Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/jsxc.nextcloud.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'build/js/jsxc/lib/strophe.jinglejs/strophe.jinglejs-bundle.js')
-rw-r--r--build/js/jsxc/lib/strophe.jinglejs/strophe.jinglejs-bundle.js35234
1 files changed, 21483 insertions, 13751 deletions
diff --git a/build/js/jsxc/lib/strophe.jinglejs/strophe.jinglejs-bundle.js b/build/js/jsxc/lib/strophe.jinglejs/strophe.jinglejs-bundle.js
index a6d2512..94c8766 100644
--- a/build/js/jsxc/lib/strophe.jinglejs/strophe.jinglejs-bundle.js
+++ b/build/js/jsxc/lib/strophe.jinglejs/strophe.jinglejs-bundle.js
@@ -1,19 +1,259 @@
/*!
- * strophe.jinglejs v0.1.1 - 2015-11-27
+ * strophe.jinglejs v0.1.2 - 2017-01-12
*
- * Copyright (c) 2015 Klaus Herberth <klaus@jsxc.org> <br>
+ * Copyright (c) 2017 Klaus Herberth <klaus@jsxc.org> <br>
* Released under the MIT license
*
* Please see https://github.com/sualko/strophe.jinglejs/
*
* @author Klaus Herberth <klaus@jsxc.org>
- * @version 0.1.1
+ * @version 0.1.2
* @license MIT
*/
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/object/assign"), __esModule: true };
+},{"core-js/library/fn/object/assign":8}],2:[function(require,module,exports){
+"use strict";
+
+exports["default"] = function (obj) {
+ return obj && obj.__esModule ? obj : {
+ "default": obj
+ };
+};
+
+exports.__esModule = true;
+},{}],3:[function(require,module,exports){
+'use strict'
+
+exports.byteLength = byteLength
+exports.toByteArray = toByteArray
+exports.fromByteArray = fromByteArray
+
+var lookup = []
+var revLookup = []
+var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
+
+var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+for (var i = 0, len = code.length; i < len; ++i) {
+ lookup[i] = code[i]
+ revLookup[code.charCodeAt(i)] = i
+}
+
+revLookup['-'.charCodeAt(0)] = 62
+revLookup['_'.charCodeAt(0)] = 63
+
+function placeHoldersCount (b64) {
+ var len = b64.length
+ if (len % 4 > 0) {
+ throw new Error('Invalid string. Length must be a multiple of 4')
+ }
+
+ // the number of equal signs (place holders)
+ // if there are two placeholders, than the two characters before it
+ // represent one byte
+ // if there is only one, then the three characters before it represent 2 bytes
+ // this is just a cheap hack to not do indexOf twice
+ return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0
+}
+
+function byteLength (b64) {
+ // base64 is 4/3 + up to two characters of the original data
+ return b64.length * 3 / 4 - placeHoldersCount(b64)
+}
+
+function toByteArray (b64) {
+ var i, j, l, tmp, placeHolders, arr
+ var len = b64.length
+ placeHolders = placeHoldersCount(b64)
+
+ arr = new Arr(len * 3 / 4 - placeHolders)
+
+ // if there are placeholders, only get up to the last complete 4 chars
+ l = placeHolders > 0 ? len - 4 : len
+
+ var L = 0
+
+ for (i = 0, j = 0; i < l; i += 4, j += 3) {
+ tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]
+ arr[L++] = (tmp >> 16) & 0xFF
+ arr[L++] = (tmp >> 8) & 0xFF
+ arr[L++] = tmp & 0xFF
+ }
+
+ if (placeHolders === 2) {
+ tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)
+ arr[L++] = tmp & 0xFF
+ } else if (placeHolders === 1) {
+ tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)
+ arr[L++] = (tmp >> 8) & 0xFF
+ arr[L++] = tmp & 0xFF
+ }
+
+ return arr
+}
+
+function tripletToBase64 (num) {
+ return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]
+}
+
+function encodeChunk (uint8, start, end) {
+ var tmp
+ var output = []
+ for (var i = start; i < end; i += 3) {
+ tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
+ output.push(tripletToBase64(tmp))
+ }
+ return output.join('')
+}
+
+function fromByteArray (uint8) {
+ var tmp
+ var len = uint8.length
+ var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
+ var output = ''
+ var parts = []
+ var maxChunkLength = 16383 // must be multiple of 3
+
+ // go through the array every three bytes, we'll deal with trailing stuff later
+ for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
+ parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
+ }
+
+ // pad the end with zeros, but make sure to not forget the extra bytes
+ if (extraBytes === 1) {
+ tmp = uint8[len - 1]
+ output += lookup[tmp >> 2]
+ output += lookup[(tmp << 4) & 0x3F]
+ output += '=='
+ } else if (extraBytes === 2) {
+ tmp = (uint8[len - 2] << 8) + (uint8[len - 1])
+ output += lookup[tmp >> 10]
+ output += lookup[(tmp >> 4) & 0x3F]
+ output += lookup[(tmp << 2) & 0x3F]
+ output += '='
+ }
+
+ parts.push(output)
+
+ return parts.join('')
+}
+
+},{}],4:[function(require,module,exports){
-},{}],2:[function(require,module,exports){
+},{}],5:[function(require,module,exports){
+(function (global){
+'use strict';
+
+var buffer = require('buffer');
+var Buffer = buffer.Buffer;
+var SlowBuffer = buffer.SlowBuffer;
+var MAX_LEN = buffer.kMaxLength || 2147483647;
+exports.alloc = function alloc(size, fill, encoding) {
+ if (typeof Buffer.alloc === 'function') {
+ return Buffer.alloc(size, fill, encoding);
+ }
+ if (typeof encoding === 'number') {
+ throw new TypeError('encoding must not be number');
+ }
+ if (typeof size !== 'number') {
+ throw new TypeError('size must be a number');
+ }
+ if (size > MAX_LEN) {
+ throw new RangeError('size is too large');
+ }
+ var enc = encoding;
+ var _fill = fill;
+ if (_fill === undefined) {
+ enc = undefined;
+ _fill = 0;
+ }
+ var buf = new Buffer(size);
+ if (typeof _fill === 'string') {
+ var fillBuf = new Buffer(_fill, enc);
+ var flen = fillBuf.length;
+ var i = -1;
+ while (++i < size) {
+ buf[i] = fillBuf[i % flen];
+ }
+ } else {
+ buf.fill(_fill);
+ }
+ return buf;
+}
+exports.allocUnsafe = function allocUnsafe(size) {
+ if (typeof Buffer.allocUnsafe === 'function') {
+ return Buffer.allocUnsafe(size);
+ }
+ if (typeof size !== 'number') {
+ throw new TypeError('size must be a number');
+ }
+ if (size > MAX_LEN) {
+ throw new RangeError('size is too large');
+ }
+ return new Buffer(size);
+}
+exports.from = function from(value, encodingOrOffset, length) {
+ if (typeof Buffer.from === 'function' && (!global.Uint8Array || Uint8Array.from !== Buffer.from)) {
+ return Buffer.from(value, encodingOrOffset, length);
+ }
+ if (typeof value === 'number') {
+ throw new TypeError('"value" argument must not be a number');
+ }
+ if (typeof value === 'string') {
+ return new Buffer(value, encodingOrOffset);
+ }
+ if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
+ var offset = encodingOrOffset;
+ if (arguments.length === 1) {
+ return new Buffer(value);
+ }
+ if (typeof offset === 'undefined') {
+ offset = 0;
+ }
+ var len = length;
+ if (typeof len === 'undefined') {
+ len = value.byteLength - offset;
+ }
+ if (offset >= value.byteLength) {
+ throw new RangeError('\'offset\' is out of bounds');
+ }
+ if (len > value.byteLength - offset) {
+ throw new RangeError('\'length\' is out of bounds');
+ }
+ return new Buffer(value.slice(offset, offset + len));
+ }
+ if (Buffer.isBuffer(value)) {
+ var out = new Buffer(value.length);
+ value.copy(out, 0, 0, value.length);
+ return out;
+ }
+ if (value) {
+ if (Array.isArray(value) || (typeof ArrayBuffer !== 'undefined' && value.buffer instanceof ArrayBuffer) || 'length' in value) {
+ return new Buffer(value);
+ }
+ if (value.type === 'Buffer' && Array.isArray(value.data)) {
+ return new Buffer(value.data);
+ }
+ }
+
+ throw new TypeError('First argument must be a string, Buffer, ' + 'ArrayBuffer, Array, or array-like object.');
+}
+exports.allocUnsafeSlow = function allocUnsafeSlow(size) {
+ if (typeof Buffer.allocUnsafeSlow === 'function') {
+ return Buffer.allocUnsafeSlow(size);
+ }
+ if (typeof size !== 'number') {
+ throw new TypeError('size must be a number');
+ }
+ if (size >= MAX_LEN) {
+ throw new RangeError('size is too large');
+ }
+ return new SlowBuffer(size);
+}
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"buffer":6}],6:[function(require,module,exports){
(function (global){
/*!
* The buffer module from node.js, for the browser.
@@ -23,16 +263,15 @@
*/
/* eslint-disable no-proto */
+'use strict'
+
var base64 = require('base64-js')
var ieee754 = require('ieee754')
-var isArray = require('is-array')
+var isArray = require('isarray')
exports.Buffer = Buffer
exports.SlowBuffer = SlowBuffer
exports.INSPECT_MAX_BYTES = 50
-Buffer.poolSize = 8192 // not used by this implementation
-
-var rootParent = {}
/**
* If `Buffer.TYPED_ARRAY_SUPPORT`:
@@ -50,9 +289,6 @@ var rootParent = {}
* - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
* See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
*
- * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property
- * on objects.
- *
* - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
*
* - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
@@ -65,14 +301,16 @@ Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined
? global.TYPED_ARRAY_SUPPORT
: typedArraySupport()
+/*
+ * Export kMaxLength after typed array support is determined.
+ */
+exports.kMaxLength = kMaxLength()
+
function typedArraySupport () {
- function Bar () {}
try {
var arr = new Uint8Array(1)
- arr.foo = function () { return 42 }
- arr.constructor = Bar
+ arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}
return arr.foo() === 42 && // typed array instances can be augmented
- arr.constructor === Bar && // constructor can be set
typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
} catch (e) {
@@ -86,178 +324,252 @@ function kMaxLength () {
: 0x3fffffff
}
+function createBuffer (that, length) {
+ if (kMaxLength() < length) {
+ throw new RangeError('Invalid typed array length')
+ }
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ // Return an augmented `Uint8Array` instance, for best performance
+ that = new Uint8Array(length)
+ that.__proto__ = Buffer.prototype
+ } else {
+ // Fallback: Return an object instance of the Buffer class
+ if (that === null) {
+ that = new Buffer(length)
+ }
+ that.length = length
+ }
+
+ return that
+}
+
/**
- * Class: Buffer
- * =============
- *
- * The Buffer constructor returns instances of `Uint8Array` that are augmented
- * with function properties for all the node `Buffer` API functions. We use
- * `Uint8Array` so that square bracket notation works as expected -- it returns
- * a single octet.
+ * The Buffer constructor returns instances of `Uint8Array` that have their
+ * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
+ * `Uint8Array`, so the returned instances will have all the node `Buffer` methods
+ * and the `Uint8Array` methods. Square bracket notation works as expected -- it
+ * returns a single octet.
*
- * By augmenting the instances, we can avoid modifying the `Uint8Array`
- * prototype.
+ * The `Uint8Array` prototype remains unmodified.
*/
-function Buffer (arg) {
- if (!(this instanceof Buffer)) {
- // Avoid going through an ArgumentsAdaptorTrampoline in the common case.
- if (arguments.length > 1) return new Buffer(arg, arguments[1])
- return new Buffer(arg)
- }
- this.length = 0
- this.parent = undefined
+function Buffer (arg, encodingOrOffset, length) {
+ if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {
+ return new Buffer(arg, encodingOrOffset, length)
+ }
// Common case.
if (typeof arg === 'number') {
- return fromNumber(this, arg)
+ if (typeof encodingOrOffset === 'string') {
+ throw new Error(
+ 'If encoding is specified then the first argument must be a string'
+ )
+ }
+ return allocUnsafe(this, arg)
}
+ return from(this, arg, encodingOrOffset, length)
+}
- // Slightly less common case.
- if (typeof arg === 'string') {
- return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')
- }
+Buffer.poolSize = 8192 // not used by this implementation
- // Unusual.
- return fromObject(this, arg)
+// TODO: Legacy, not needed anymore. Remove in next major version.
+Buffer._augment = function (arr) {
+ arr.__proto__ = Buffer.prototype
+ return arr
}
-function fromNumber (that, length) {
- that = allocate(that, length < 0 ? 0 : checked(length) | 0)
- if (!Buffer.TYPED_ARRAY_SUPPORT) {
- for (var i = 0; i < length; i++) {
- that[i] = 0
- }
+function from (that, value, encodingOrOffset, length) {
+ if (typeof value === 'number') {
+ throw new TypeError('"value" argument must not be a number')
}
- return that
-}
-function fromString (that, string, encoding) {
- if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'
+ if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
+ return fromArrayBuffer(that, value, encodingOrOffset, length)
+ }
- // Assumption: byteLength() return value is always < kMaxLength.
- var length = byteLength(string, encoding) | 0
- that = allocate(that, length)
+ if (typeof value === 'string') {
+ return fromString(that, value, encodingOrOffset)
+ }
- that.write(string, encoding)
- return that
+ return fromObject(that, value)
}
-function fromObject (that, object) {
- if (Buffer.isBuffer(object)) return fromBuffer(that, object)
-
- if (isArray(object)) return fromArray(that, object)
+/**
+ * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
+ * if value is a number.
+ * Buffer.from(str[, encoding])
+ * Buffer.from(array)
+ * Buffer.from(buffer)
+ * Buffer.from(arrayBuffer[, byteOffset[, length]])
+ **/
+Buffer.from = function (value, encodingOrOffset, length) {
+ return from(null, value, encodingOrOffset, length)
+}
- if (object == null) {
- throw new TypeError('must start with number, buffer, array or string')
+if (Buffer.TYPED_ARRAY_SUPPORT) {
+ Buffer.prototype.__proto__ = Uint8Array.prototype
+ Buffer.__proto__ = Uint8Array
+ if (typeof Symbol !== 'undefined' && Symbol.species &&
+ Buffer[Symbol.species] === Buffer) {
+ // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
+ Object.defineProperty(Buffer, Symbol.species, {
+ value: null,
+ configurable: true
+ })
}
+}
- if (typeof ArrayBuffer !== 'undefined') {
- if (object.buffer instanceof ArrayBuffer) {
- return fromTypedArray(that, object)
- }
- if (object instanceof ArrayBuffer) {
- return fromArrayBuffer(that, object)
- }
+function assertSize (size) {
+ if (typeof size !== 'number') {
+ throw new TypeError('"size" argument must be a number')
+ } else if (size < 0) {
+ throw new RangeError('"size" argument must not be negative')
}
+}
- if (object.length) return fromArrayLike(that, object)
-
- return fromJsonObject(that, object)
+function alloc (that, size, fill, encoding) {
+ assertSize(size)
+ if (size <= 0) {
+ return createBuffer(that, size)
+ }
+ if (fill !== undefined) {
+ // Only pay attention to encoding if it's a string. This
+ // prevents accidentally sending in a number that would
+ // be interpretted as a start offset.
+ return typeof encoding === 'string'
+ ? createBuffer(that, size).fill(fill, encoding)
+ : createBuffer(that, size).fill(fill)
+ }
+ return createBuffer(that, size)
}
-function fromBuffer (that, buffer) {
- var length = checked(buffer.length) | 0
- that = allocate(that, length)
- buffer.copy(that, 0, 0, length)
- return that
+/**
+ * Creates a new filled Buffer instance.
+ * alloc(size[, fill[, encoding]])
+ **/
+Buffer.alloc = function (size, fill, encoding) {
+ return alloc(null, size, fill, encoding)
}
-function fromArray (that, array) {
- var length = checked(array.length) | 0
- that = allocate(that, length)
- for (var i = 0; i < length; i += 1) {
- that[i] = array[i] & 255
+function allocUnsafe (that, size) {
+ assertSize(size)
+ that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)
+ if (!Buffer.TYPED_ARRAY_SUPPORT) {
+ for (var i = 0; i < size; ++i) {
+ that[i] = 0
+ }
}
return that
}
-// Duplicate of fromArray() to keep fromArray() monomorphic.
-function fromTypedArray (that, array) {
- var length = checked(array.length) | 0
- that = allocate(that, length)
- // Truncating the elements is probably not what people expect from typed
- // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior
- // of the old Buffer constructor.
- for (var i = 0; i < length; i += 1) {
- that[i] = array[i] & 255
- }
- return that
+/**
+ * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
+ * */
+Buffer.allocUnsafe = function (size) {
+ return allocUnsafe(null, size)
+}
+/**
+ * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
+ */
+Buffer.allocUnsafeSlow = function (size) {
+ return allocUnsafe(null, size)
}
-function fromArrayBuffer (that, array) {
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- // Return an augmented `Uint8Array` instance, for best performance
- array.byteLength
- that = Buffer._augment(new Uint8Array(array))
- } else {
- // Fallback: Return an object instance of the Buffer class
- that = fromTypedArray(that, new Uint8Array(array))
+function fromString (that, string, encoding) {
+ if (typeof encoding !== 'string' || encoding === '') {
+ encoding = 'utf8'
+ }
+
+ if (!Buffer.isEncoding(encoding)) {
+ throw new TypeError('"encoding" must be a valid string encoding')
+ }
+
+ var length = byteLength(string, encoding) | 0
+ that = createBuffer(that, length)
+
+ var actual = that.write(string, encoding)
+
+ if (actual !== length) {
+ // Writing a hex string, for example, that contains invalid characters will
+ // cause everything after the first invalid character to be ignored. (e.g.
+ // 'abxxcd' will be treated as 'ab')
+ that = that.slice(0, actual)
}
+
return that
}
function fromArrayLike (that, array) {
- var length = checked(array.length) | 0
- that = allocate(that, length)
+ var length = array.length < 0 ? 0 : checked(array.length) | 0
+ that = createBuffer(that, length)
for (var i = 0; i < length; i += 1) {
that[i] = array[i] & 255
}
return that
}
-// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.
-// Returns a zero-length buffer for inputs that don't conform to the spec.
-function fromJsonObject (that, object) {
- var array
- var length = 0
+function fromArrayBuffer (that, array, byteOffset, length) {
+ array.byteLength // this throws if `array` is not a valid ArrayBuffer
- if (object.type === 'Buffer' && isArray(object.data)) {
- array = object.data
- length = checked(array.length) | 0
+ if (byteOffset < 0 || array.byteLength < byteOffset) {
+ throw new RangeError('\'offset\' is out of bounds')
}
- that = allocate(that, length)
- for (var i = 0; i < length; i += 1) {
- that[i] = array[i] & 255
+ if (array.byteLength < byteOffset + (length || 0)) {
+ throw new RangeError('\'length\' is out of bounds')
}
- return that
-}
-if (Buffer.TYPED_ARRAY_SUPPORT) {
- Buffer.prototype.__proto__ = Uint8Array.prototype
- Buffer.__proto__ = Uint8Array
-}
+ if (byteOffset === undefined && length === undefined) {
+ array = new Uint8Array(array)
+ } else if (length === undefined) {
+ array = new Uint8Array(array, byteOffset)
+ } else {
+ array = new Uint8Array(array, byteOffset, length)
+ }
-function allocate (that, length) {
if (Buffer.TYPED_ARRAY_SUPPORT) {
// Return an augmented `Uint8Array` instance, for best performance
- that = Buffer._augment(new Uint8Array(length))
+ that = array
that.__proto__ = Buffer.prototype
} else {
// Fallback: Return an object instance of the Buffer class
- that.length = length
- that._isBuffer = true
+ that = fromArrayLike(that, array)
}
+ return that
+}
- var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1
- if (fromPool) that.parent = rootParent
+function fromObject (that, obj) {
+ if (Buffer.isBuffer(obj)) {
+ var len = checked(obj.length) | 0
+ that = createBuffer(that, len)
- return that
+ if (that.length === 0) {
+ return that
+ }
+
+ obj.copy(that, 0, 0, len)
+ return that
+ }
+
+ if (obj) {
+ if ((typeof ArrayBuffer !== 'undefined' &&
+ obj.buffer instanceof ArrayBuffer) || 'length' in obj) {
+ if (typeof obj.length !== 'number' || isnan(obj.length)) {
+ return createBuffer(that, 0)
+ }
+ return fromArrayLike(that, obj)
+ }
+
+ if (obj.type === 'Buffer' && isArray(obj.data)) {
+ return fromArrayLike(that, obj.data)
+ }
+ }
+
+ throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
}
function checked (length) {
- // Note: cannot use `length < kMaxLength` here because that fails when
+ // Note: cannot use `length < kMaxLength()` here because that fails when
// length is NaN (which is otherwise coerced to zero.)
if (length >= kMaxLength()) {
throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
@@ -266,12 +578,11 @@ function checked (length) {
return length | 0
}
-function SlowBuffer (subject, encoding) {
- if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)
-
- var buf = new Buffer(subject, encoding)
- delete buf.parent
- return buf
+function SlowBuffer (length) {
+ if (+length != length) { // eslint-disable-line eqeqeq
+ length = 0
+ }
+ return Buffer.alloc(+length)
}
Buffer.isBuffer = function isBuffer (b) {
@@ -288,17 +599,12 @@ Buffer.compare = function compare (a, b) {
var x = a.length
var y = b.length
- var i = 0
- var len = Math.min(x, y)
- while (i < len) {
- if (a[i] !== b[i]) break
-
- ++i
- }
-
- if (i !== len) {
- x = a[i]
- y = b[i]
+ for (var i = 0, len = Math.min(x, y); i < len; ++i) {
+ if (a[i] !== b[i]) {
+ x = a[i]
+ y = b[i]
+ break
+ }
}
if (x < y) return -1
@@ -312,9 +618,9 @@ Buffer.isEncoding = function isEncoding (encoding) {
case 'utf8':
case 'utf-8':
case 'ascii':
+ case 'latin1':
case 'binary':
case 'base64':
- case 'raw':
case 'ucs2':
case 'ucs-2':
case 'utf16le':
@@ -326,32 +632,46 @@ Buffer.isEncoding = function isEncoding (encoding) {
}
Buffer.concat = function concat (list, length) {
- if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')
+ if (!isArray(list)) {
+ throw new TypeError('"list" argument must be an Array of Buffers')
+ }
if (list.length === 0) {
- return new Buffer(0)
+ return Buffer.alloc(0)
}
var i
if (length === undefined) {
length = 0
- for (i = 0; i < list.length; i++) {
+ for (i = 0; i < list.length; ++i) {
length += list[i].length
}
}
- var buf = new Buffer(length)
+ var buffer = Buffer.allocUnsafe(length)
var pos = 0
- for (i = 0; i < list.length; i++) {
- var item = list[i]
- item.copy(buf, pos)
- pos += item.length
+ for (i = 0; i < list.length; ++i) {
+ var buf = list[i]
+ if (!Buffer.isBuffer(buf)) {
+ throw new TypeError('"list" argument must be an Array of Buffers')
+ }
+ buf.copy(buffer, pos)
+ pos += buf.length
}
- return buf
+ return buffer
}
function byteLength (string, encoding) {
- if (typeof string !== 'string') string = '' + string
+ if (Buffer.isBuffer(string)) {
+ return string.length
+ }
+ if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&
+ (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {
+ return string.byteLength
+ }
+ if (typeof string !== 'string') {
+ string = '' + string
+ }
var len = string.length
if (len === 0) return 0
@@ -361,13 +681,12 @@ function byteLength (string, encoding) {
for (;;) {
switch (encoding) {
case 'ascii':
+ case 'latin1':
case 'binary':
- // Deprecated
- case 'raw':
- case 'raws':
return len
case 'utf8':
case 'utf-8':
+ case undefined:
return utf8ToBytes(string).length
case 'ucs2':
case 'ucs-2':
@@ -387,20 +706,42 @@ function byteLength (string, encoding) {
}
Buffer.byteLength = byteLength
-// pre-set for values that may exist in the future
-Buffer.prototype.length = undefined
-Buffer.prototype.parent = undefined
-
function slowToString (encoding, start, end) {
var loweredCase = false
- start = start | 0
- end = end === undefined || end === Infinity ? this.length : end | 0
+ // No need to verify that "this.length <= MAX_UINT32" since it's a read-only
+ // property of a typed array.
+
+ // This behaves neither like String nor Uint8Array in that we set start/end
+ // to their upper/lower bounds if the value passed is out of range.
+ // undefined is handled specially as per ECMA-262 6th Edition,
+ // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
+ if (start === undefined || start < 0) {
+ start = 0
+ }
+ // Return early if start > this.length. Done here to prevent potential uint32
+ // coercion fail below.
+ if (start > this.length) {
+ return ''
+ }
+
+ if (end === undefined || end > this.length) {
+ end = this.length
+ }
+
+ if (end <= 0) {
+ return ''
+ }
+
+ // Force coersion to uint32. This will also coerce falsey/NaN values to 0.
+ end >>>= 0
+ start >>>= 0
+
+ if (end <= start) {
+ return ''
+ }
if (!encoding) encoding = 'utf8'
- if (start < 0) start = 0
- if (end > this.length) end = this.length
- if (end <= start) return ''
while (true) {
switch (encoding) {
@@ -414,8 +755,9 @@ function slowToString (encoding, start, end) {
case 'ascii':
return asciiSlice(this, start, end)
+ case 'latin1':
case 'binary':
- return binarySlice(this, start, end)
+ return latin1Slice(this, start, end)
case 'base64':
return base64Slice(this, start, end)
@@ -434,6 +776,53 @@ function slowToString (encoding, start, end) {
}
}
+// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect
+// Buffer instances.
+Buffer.prototype._isBuffer = true
+
+function swap (b, n, m) {
+ var i = b[n]
+ b[n] = b[m]
+ b[m] = i
+}
+
+Buffer.prototype.swap16 = function swap16 () {
+ var len = this.length
+ if (len % 2 !== 0) {
+ throw new RangeError('Buffer size must be a multiple of 16-bits')
+ }
+ for (var i = 0; i < len; i += 2) {
+ swap(this, i, i + 1)
+ }
+ return this
+}
+
+Buffer.prototype.swap32 = function swap32 () {
+ var len = this.length
+ if (len % 4 !== 0) {
+ throw new RangeError('Buffer size must be a multiple of 32-bits')
+ }
+ for (var i = 0; i < len; i += 4) {
+ swap(this, i, i + 3)
+ swap(this, i + 1, i + 2)
+ }
+ return this
+}
+
+Buffer.prototype.swap64 = function swap64 () {
+ var len = this.length
+ if (len % 8 !== 0) {
+ throw new RangeError('Buffer size must be a multiple of 64-bits')
+ }
+ for (var i = 0; i < len; i += 8) {
+ swap(this, i, i + 7)
+ swap(this, i + 1, i + 6)
+ swap(this, i + 2, i + 5)
+ swap(this, i + 3, i + 4)
+ }
+ return this
+}
+
Buffer.prototype.toString = function toString () {
var length = this.length | 0
if (length === 0) return ''
@@ -457,63 +846,197 @@ Buffer.prototype.inspect = function inspect () {
return '<Buffer ' + str + '>'
}
-Buffer.prototype.compare = function compare (b) {
- if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
- if (this === b) return 0
- return Buffer.compare(this, b)
-}
+Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
+ if (!Buffer.isBuffer(target)) {
+ throw new TypeError('Argument must be a Buffer')
+ }
+
+ if (start === undefined) {
+ start = 0
+ }
+ if (end === undefined) {
+ end = target ? target.length : 0
+ }
+ if (thisStart === undefined) {
+ thisStart = 0
+ }
+ if (thisEnd === undefined) {
+ thisEnd = this.length
+ }
-Buffer.prototype.indexOf = function indexOf (val, byteOffset) {
- if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff
- else if (byteOffset < -0x80000000) byteOffset = -0x80000000
- byteOffset >>= 0
+ if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
+ throw new RangeError('out of range index')
+ }
- if (this.length === 0) return -1
- if (byteOffset >= this.length) return -1
+ if (thisStart >= thisEnd && start >= end) {
+ return 0
+ }
+ if (thisStart >= thisEnd) {
+ return -1
+ }
+ if (start >= end) {
+ return 1
+ }
- // Negative offsets start from the end of the buffer
- if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)
+ start >>>= 0
+ end >>>= 0
+ thisStart >>>= 0
+ thisEnd >>>= 0
+ if (this === target) return 0
+
+ var x = thisEnd - thisStart
+ var y = end - start
+ var len = Math.min(x, y)
+
+ var thisCopy = this.slice(thisStart, thisEnd)
+ var targetCopy = target.slice(start, end)
+
+ for (var i = 0; i < len; ++i) {
+ if (thisCopy[i] !== targetCopy[i]) {
+ x = thisCopy[i]
+ y = targetCopy[i]
+ break
+ }
+ }
+
+ if (x < y) return -1
+ if (y < x) return 1
+ return 0
+}
+
+// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
+// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
+//
+// Arguments:
+// - buffer - a Buffer to search
+// - val - a string, Buffer, or number
+// - byteOffset - an index into `buffer`; will be clamped to an int32
+// - encoding - an optional encoding, relevant is val is a string
+// - dir - true for indexOf, false for lastIndexOf
+function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
+ // Empty buffer means no match
+ if (buffer.length === 0) return -1
+
+ // Normalize byteOffset
+ if (typeof byteOffset === 'string') {
+ encoding = byteOffset
+ byteOffset = 0
+ } else if (byteOffset > 0x7fffffff) {
+ byteOffset = 0x7fffffff
+ } else if (byteOffset < -0x80000000) {
+ byteOffset = -0x80000000
+ }
+ byteOffset = +byteOffset // Coerce to Number.
+ if (isNaN(byteOffset)) {
+ // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
+ byteOffset = dir ? 0 : (buffer.length - 1)
+ }
+
+ // Normalize byteOffset: negative offsets start from the end of the buffer
+ if (byteOffset < 0) byteOffset = buffer.length + byteOffset
+ if (byteOffset >= buffer.length) {
+ if (dir) return -1
+ else byteOffset = buffer.length - 1
+ } else if (byteOffset < 0) {
+ if (dir) byteOffset = 0
+ else return -1
+ }
+
+ // Normalize val
if (typeof val === 'string') {
- if (val.length === 0) return -1 // special case: looking for empty string always fails
- return String.prototype.indexOf.call(this, val, byteOffset)
+ val = Buffer.from(val, encoding)
}
+
+ // Finally, search either indexOf (if dir is true) or lastIndexOf
if (Buffer.isBuffer(val)) {
- return arrayIndexOf(this, val, byteOffset)
+ // Special case: looking for empty string/buffer always fails
+ if (val.length === 0) {
+ return -1
+ }
+ return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
+ } else if (typeof val === 'number') {
+ val = val & 0xFF // Search for a byte value [0-255]
+ if (Buffer.TYPED_ARRAY_SUPPORT &&
+ typeof Uint8Array.prototype.indexOf === 'function') {
+ if (dir) {
+ return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
+ } else {
+ return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
+ }
+ }
+ return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)
}
- if (typeof val === 'number') {
- if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {
- return Uint8Array.prototype.indexOf.call(this, val, byteOffset)
+
+ throw new TypeError('val must be string, number or Buffer')
+}
+
+function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
+ var indexSize = 1
+ var arrLength = arr.length
+ var valLength = val.length
+
+ if (encoding !== undefined) {
+ encoding = String(encoding).toLowerCase()
+ if (encoding === 'ucs2' || encoding === 'ucs-2' ||
+ encoding === 'utf16le' || encoding === 'utf-16le') {
+ if (arr.length < 2 || val.length < 2) {
+ return -1
+ }
+ indexSize = 2
+ arrLength /= 2
+ valLength /= 2
+ byteOffset /= 2
+ }
+ }
+
+ function read (buf, i) {
+ if (indexSize === 1) {
+ return buf[i]
+ } else {
+ return buf.readUInt16BE(i * indexSize)
}
- return arrayIndexOf(this, [ val ], byteOffset)
}
- function arrayIndexOf (arr, val, byteOffset) {
+ var i
+ if (dir) {
var foundIndex = -1
- for (var i = 0; byteOffset + i < arr.length; i++) {
- if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {
+ for (i = byteOffset; i < arrLength; i++) {
+ if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
if (foundIndex === -1) foundIndex = i
- if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex
+ if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
} else {
+ if (foundIndex !== -1) i -= i - foundIndex
foundIndex = -1
}
}
- return -1
+ } else {
+ if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
+ for (i = byteOffset; i >= 0; i--) {
+ var found = true
+ for (var j = 0; j < valLength; j++) {
+ if (read(arr, i + j) !== read(val, j)) {
+ found = false
+ break
+ }
+ }
+ if (found) return i
+ }
}
- throw new TypeError('val must be string, number or Buffer')
+ return -1
+}
+
+Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
+ return this.indexOf(val, byteOffset, encoding) !== -1
}
-// `get` is deprecated
-Buffer.prototype.get = function get (offset) {
- console.log('.get() is deprecated. Access using array indexes instead.')
- return this.readUInt8(offset)
+Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
+ return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
}
-// `set` is deprecated
-Buffer.prototype.set = function set (v, offset) {
- console.log('.set() is deprecated. Access using array indexes instead.')
- return this.writeUInt8(v, offset)
+Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
+ return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
}
function hexWrite (buf, string, offset, length) {
@@ -530,14 +1053,14 @@ function hexWrite (buf, string, offset, length) {
// must be an even number of digits
var strLen = string.length
- if (strLen % 2 !== 0) throw new Error('Invalid hex string')
+ if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')
if (length > strLen / 2) {
length = strLen / 2
}
- for (var i = 0; i < length; i++) {
+ for (var i = 0; i < length; ++i) {
var parsed = parseInt(string.substr(i * 2, 2), 16)
- if (isNaN(parsed)) throw new Error('Invalid hex string')
+ if (isNaN(parsed)) return i
buf[offset + i] = parsed
}
return i
@@ -551,7 +1074,7 @@ function asciiWrite (buf, string, offset, length) {
return blitBuffer(asciiToBytes(string), buf, offset, length)
}
-function binaryWrite (buf, string, offset, length) {
+function latin1Write (buf, string, offset, length) {
return asciiWrite(buf, string, offset, length)
}
@@ -586,17 +1109,16 @@ Buffer.prototype.write = function write (string, offset, length, encoding) {
}
// legacy write(string, encoding, offset, length) - remove in v0.13
} else {
- var swap = encoding
- encoding = offset
- offset = length | 0
- length = swap
+ throw new Error(
+ 'Buffer.write(string, encoding, offset[, length]) is no longer supported'
+ )
}
var remaining = this.length - offset
if (length === undefined || length > remaining) length = remaining
if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
- throw new RangeError('attempt to write outside buffer bounds')
+ throw new RangeError('Attempt to write outside buffer bounds')
}
if (!encoding) encoding = 'utf8'
@@ -614,8 +1136,9 @@ Buffer.prototype.write = function write (string, offset, length, encoding) {
case 'ascii':
return asciiWrite(this, string, offset, length)
+ case 'latin1':
case 'binary':
- return binaryWrite(this, string, offset, length)
+ return latin1Write(this, string, offset, length)
case 'base64':
// Warning: maxLength not taken into account in base64Write
@@ -750,17 +1273,17 @@ function asciiSlice (buf, start, end) {
var ret = ''
end = Math.min(buf.length, end)
- for (var i = start; i < end; i++) {
+ for (var i = start; i < end; ++i) {
ret += String.fromCharCode(buf[i] & 0x7F)
}
return ret
}
-function binarySlice (buf, start, end) {
+function latin1Slice (buf, start, end) {
var ret = ''
end = Math.min(buf.length, end)
- for (var i = start; i < end; i++) {
+ for (var i = start; i < end; ++i) {
ret += String.fromCharCode(buf[i])
}
return ret
@@ -773,7 +1296,7 @@ function hexSlice (buf, start, end) {
if (!end || end < 0 || end > len) end = len
var out = ''
- for (var i = start; i < end; i++) {
+ for (var i = start; i < end; ++i) {
out += toHex(buf[i])
}
return out
@@ -811,17 +1334,16 @@ Buffer.prototype.slice = function slice (start, end) {
var newBuf
if (Buffer.TYPED_ARRAY_SUPPORT) {
- newBuf = Buffer._augment(this.subarray(start, end))
+ newBuf = this.subarray(start, end)
+ newBuf.__proto__ = Buffer.prototype
} else {
var sliceLen = end - start
newBuf = new Buffer(sliceLen, undefined)
- for (var i = 0; i < sliceLen; i++) {
+ for (var i = 0; i < sliceLen; ++i) {
newBuf[i] = this[i + start]
}
}
- if (newBuf.length) newBuf.parent = this.parent || this
-
return newBuf
}
@@ -990,16 +1512,19 @@ Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
}
function checkInt (buf, value, offset, ext, max, min) {
- if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')
- if (value > max || value < min) throw new RangeError('value is out of bounds')
- if (offset + ext > buf.length) throw new RangeError('index out of range')
+ if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
+ if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
+ if (offset + ext > buf.length) throw new RangeError('Index out of range')
}
Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
value = +value
offset = offset | 0
byteLength = byteLength | 0
- if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)
+ if (!noAssert) {
+ var maxBytes = Math.pow(2, 8 * byteLength) - 1
+ checkInt(this, value, offset, byteLength, maxBytes, 0)
+ }
var mul = 1
var i = 0
@@ -1015,7 +1540,10 @@ Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength,
value = +value
offset = offset | 0
byteLength = byteLength | 0
- if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)
+ if (!noAssert) {
+ var maxBytes = Math.pow(2, 8 * byteLength) - 1
+ checkInt(this, value, offset, byteLength, maxBytes, 0)
+ }
var i = byteLength - 1
var mul = 1
@@ -1038,7 +1566,7 @@ Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
function objectWriteUInt16 (buf, value, offset, littleEndian) {
if (value < 0) value = 0xffff + value + 1
- for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {
+ for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {
buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
(littleEndian ? i : 1 - i) * 8
}
@@ -1072,7 +1600,7 @@ Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert
function objectWriteUInt32 (buf, value, offset, littleEndian) {
if (value < 0) value = 0xffffffff + value + 1
- for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {
+ for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {
buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
}
}
@@ -1118,9 +1646,12 @@ Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, no
var i = 0
var mul = 1
- var sub = value < 0 ? 1 : 0
+ var sub = 0
this[offset] = value & 0xFF
while (++i < byteLength && (mul *= 0x100)) {
+ if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
+ sub = 1
+ }
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
}
@@ -1138,9 +1669,12 @@ Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, no
var i = byteLength - 1
var mul = 1
- var sub = value < 0 ? 1 : 0
+ var sub = 0
this[offset + i] = value & 0xFF
while (--i >= 0 && (mul *= 0x100)) {
+ if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
+ sub = 1
+ }
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
}
@@ -1215,9 +1749,8 @@ Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert)
}
function checkIEEE754 (buf, value, offset, ext, max, min) {
- if (value > max || value < min) throw new RangeError('value is out of bounds')
- if (offset + ext > buf.length) throw new RangeError('index out of range')
- if (offset < 0) throw new RangeError('index out of range')
+ if (offset + ext > buf.length) throw new RangeError('Index out of range')
+ if (offset < 0) throw new RangeError('Index out of range')
}
function writeFloat (buf, value, offset, littleEndian, noAssert) {
@@ -1282,143 +1815,91 @@ Buffer.prototype.copy = function copy (target, targetStart, start, end) {
if (this === target && start < targetStart && targetStart < end) {
// descending copy from end
- for (i = len - 1; i >= 0; i--) {
+ for (i = len - 1; i >= 0; --i) {
target[i + targetStart] = this[i + start]
}
} else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
// ascending copy from start
- for (i = 0; i < len; i++) {
+ for (i = 0; i < len; ++i) {
target[i + targetStart] = this[i + start]
}
} else {
- target._set(this.subarray(start, start + len), targetStart)
+ Uint8Array.prototype.set.call(
+ target,
+ this.subarray(start, start + len),
+ targetStart
+ )
}
return len
}
-// fill(value, start=0, end=buffer.length)
-Buffer.prototype.fill = function fill (value, start, end) {
- if (!value) value = 0
- if (!start) start = 0
- if (!end) end = this.length
+// Usage:
+// buffer.fill(number[, offset[, end]])
+// buffer.fill(buffer[, offset[, end]])
+// buffer.fill(string[, offset[, end]][, encoding])
+Buffer.prototype.fill = function fill (val, start, end, encoding) {
+ // Handle string cases:
+ if (typeof val === 'string') {
+ if (typeof start === 'string') {
+ encoding = start
+ start = 0
+ end = this.length
+ } else if (typeof end === 'string') {
+ encoding = end
+ end = this.length
+ }
+ if (val.length === 1) {
+ var code = val.charCodeAt(0)
+ if (code < 256) {
+ val = code
+ }
+ }
+ if (encoding !== undefined && typeof encoding !== 'string') {
+ throw new TypeError('encoding must be a string')
+ }
+ if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
+ throw new TypeError('Unknown encoding: ' + encoding)
+ }
+ } else if (typeof val === 'number') {
+ val = val & 255
+ }
+
+ // Invalid ranges are not set to a default, so can range check early.
+ if (start < 0 || this.length < start || this.length < end) {
+ throw new RangeError('Out of range index')
+ }
- if (end < start) throw new RangeError('end < start')
+ if (end <= start) {
+ return this
+ }
- // Fill 0 bytes; we're done
- if (end === start) return
- if (this.length === 0) return
+ start = start >>> 0
+ end = end === undefined ? this.length : end >>> 0
- if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')
- if (end < 0 || end > this.length) throw new RangeError('end out of bounds')
+ if (!val) val = 0
var i
- if (typeof value === 'number') {
- for (i = start; i < end; i++) {
- this[i] = value
+ if (typeof val === 'number') {
+ for (i = start; i < end; ++i) {
+ this[i] = val
}
} else {
- var bytes = utf8ToBytes(value.toString())
+ var bytes = Buffer.isBuffer(val)
+ ? val
+ : utf8ToBytes(new Buffer(val, encoding).toString())
var len = bytes.length
- for (i = start; i < end; i++) {
- this[i] = bytes[i % len]
+ for (i = 0; i < end - start; ++i) {
+ this[i + start] = bytes[i % len]
}
}
return this
}
-/**
- * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.
- * Added in Node 0.12. Only available in browsers that support ArrayBuffer.
- */
-Buffer.prototype.toArrayBuffer = function toArrayBuffer () {
- if (typeof Uint8Array !== 'undefined') {
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- return (new Buffer(this)).buffer
- } else {
- var buf = new Uint8Array(this.length)
- for (var i = 0, len = buf.length; i < len; i += 1) {
- buf[i] = this[i]
- }
- return buf.buffer
- }
- } else {
- throw new TypeError('Buffer.toArrayBuffer not supported in this browser')
- }
-}
-
// HELPER FUNCTIONS
// ================
-var BP = Buffer.prototype
-
-/**
- * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods
- */
-Buffer._augment = function _augment (arr) {
- arr.constructor = Buffer
- arr._isBuffer = true
-
- // save reference to original Uint8Array set method before overwriting
- arr._set = arr.set
-
- // deprecated
- arr.get = BP.get
- arr.set = BP.set
-
- arr.write = BP.write
- arr.toString = BP.toString
- arr.toLocaleString = BP.toString
- arr.toJSON = BP.toJSON
- arr.equals = BP.equals
- arr.compare = BP.compare
- arr.indexOf = BP.indexOf
- arr.copy = BP.copy
- arr.slice = BP.slice
- arr.readUIntLE = BP.readUIntLE
- arr.readUIntBE = BP.readUIntBE
- arr.readUInt8 = BP.readUInt8
- arr.readUInt16LE = BP.readUInt16LE
- arr.readUInt16BE = BP.readUInt16BE
- arr.readUInt32LE = BP.readUInt32LE
- arr.readUInt32BE = BP.readUInt32BE
- arr.readIntLE = BP.readIntLE
- arr.readIntBE = BP.readIntBE
- arr.readInt8 = BP.readInt8
- arr.readInt16LE = BP.readInt16LE
- arr.readInt16BE = BP.readInt16BE
- arr.readInt32LE = BP.readInt32LE
- arr.readInt32BE = BP.readInt32BE
- arr.readFloatLE = BP.readFloatLE
- arr.readFloatBE = BP.readFloatBE
- arr.readDoubleLE = BP.readDoubleLE
- arr.readDoubleBE = BP.readDoubleBE
- arr.writeUInt8 = BP.writeUInt8
- arr.writeUIntLE = BP.writeUIntLE
- arr.writeUIntBE = BP.writeUIntBE
- arr.writeUInt16LE = BP.writeUInt16LE
- arr.writeUInt16BE = BP.writeUInt16BE
- arr.writeUInt32LE = BP.writeUInt32LE
- arr.writeUInt32BE = BP.writeUInt32BE
- arr.writeIntLE = BP.writeIntLE
- arr.writeIntBE = BP.writeIntBE
- arr.writeInt8 = BP.writeInt8
- arr.writeInt16LE = BP.writeInt16LE
- arr.writeInt16BE = BP.writeInt16BE
- arr.writeInt32LE = BP.writeInt32LE
- arr.writeInt32BE = BP.writeInt32BE
- arr.writeFloatLE = BP.writeFloatLE
- arr.writeFloatBE = BP.writeFloatBE
- arr.writeDoubleLE = BP.writeDoubleLE
- arr.writeDoubleBE = BP.writeDoubleBE
- arr.fill = BP.fill
- arr.inspect = BP.inspect
- arr.toArrayBuffer = BP.toArrayBuffer
-
- return arr
-}
-
var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g
function base64clean (str) {
@@ -1450,7 +1931,7 @@ function utf8ToBytes (string, units) {
var leadSurrogate = null
var bytes = []
- for (var i = 0; i < length; i++) {
+ for (var i = 0; i < length; ++i) {
codePoint = string.charCodeAt(i)
// is surrogate component
@@ -1482,7 +1963,7 @@ function utf8ToBytes (string, units) {
}
// valid surrogate pair
- codePoint = leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 | 0x10000
+ codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
} else if (leadSurrogate) {
// valid bmp char, but last char was a lead
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
@@ -1525,7 +2006,7 @@ function utf8ToBytes (string, units) {
function asciiToBytes (str) {
var byteArray = []
- for (var i = 0; i < str.length; i++) {
+ for (var i = 0; i < str.length; ++i) {
// Node's code seems to be doing this and not & 0x7F..
byteArray.push(str.charCodeAt(i) & 0xFF)
}
@@ -1535,7 +2016,7 @@ function asciiToBytes (str) {
function utf16leToBytes (str, units) {
var c, hi, lo
var byteArray = []
- for (var i = 0; i < str.length; i++) {
+ for (var i = 0; i < str.length; ++i) {
if ((units -= 2) < 0) break
c = str.charCodeAt(i)
@@ -1553,3062 +2034,282 @@ function base64ToBytes (str) {
}
function blitBuffer (src, dst, offset, length) {
- for (var i = 0; i < length; i++) {
+ for (var i = 0; i < length; ++i) {
if ((i + offset >= dst.length) || (i >= src.length)) break
dst[i + offset] = src[i]
}
return i
}
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"base64-js":3,"ieee754":4,"is-array":5}],3:[function(require,module,exports){
-var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
-
-;(function (exports) {
- 'use strict';
-
- var Arr = (typeof Uint8Array !== 'undefined')
- ? Uint8Array
- : Array
-
- var PLUS = '+'.charCodeAt(0)
- var SLASH = '/'.charCodeAt(0)
- var NUMBER = '0'.charCodeAt(0)
- var LOWER = 'a'.charCodeAt(0)
- var UPPER = 'A'.charCodeAt(0)
- var PLUS_URL_SAFE = '-'.charCodeAt(0)
- var SLASH_URL_SAFE = '_'.charCodeAt(0)
-
- function decode (elt) {
- var code = elt.charCodeAt(0)
- if (code === PLUS ||
- code === PLUS_URL_SAFE)
- return 62 // '+'
- if (code === SLASH ||
- code === SLASH_URL_SAFE)
- return 63 // '/'
- if (code < NUMBER)
- return -1 //no match
- if (code < NUMBER + 10)
- return code - NUMBER + 26 + 26
- if (code < UPPER + 26)
- return code - UPPER
- if (code < LOWER + 26)
- return code - LOWER + 26
- }
-
- function b64ToByteArray (b64) {
- var i, j, l, tmp, placeHolders, arr
-
- if (b64.length % 4 > 0) {
- throw new Error('Invalid string. Length must be a multiple of 4')
- }
-
- // the number of equal signs (place holders)
- // if there are two placeholders, than the two characters before it
- // represent one byte
- // if there is only one, then the three characters before it represent 2 bytes
- // this is just a cheap hack to not do indexOf twice
- var len = b64.length
- placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0
-
- // base64 is 4/3 + up to two characters of the original data
- arr = new Arr(b64.length * 3 / 4 - placeHolders)
-
- // if there are placeholders, only get up to the last complete 4 chars
- l = placeHolders > 0 ? b64.length - 4 : b64.length
-
- var L = 0
-
- function push (v) {
- arr[L++] = v
- }
-
- for (i = 0, j = 0; i < l; i += 4, j += 3) {
- tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
- push((tmp & 0xFF0000) >> 16)
- push((tmp & 0xFF00) >> 8)
- push(tmp & 0xFF)
- }
-
- if (placeHolders === 2) {
- tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
- push(tmp & 0xFF)
- } else if (placeHolders === 1) {
- tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
- push((tmp >> 8) & 0xFF)
- push(tmp & 0xFF)
- }
-
- return arr
- }
-
- function uint8ToBase64 (uint8) {
- var i,
- extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
- output = "",
- temp, length
-
- function encode (num) {
- return lookup.charAt(num)
- }
-
- function tripletToBase64 (num) {
- return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
- }
-
- // go through the array every three bytes, we'll deal with trailing stuff later
- for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
- temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
- output += tripletToBase64(temp)
- }
-
- // pad the end with zeros, but make sure to not forget the extra bytes
- switch (extraBytes) {
- case 1:
- temp = uint8[uint8.length - 1]
- output += encode(temp >> 2)
- output += encode((temp << 4) & 0x3F)
- output += '=='
- break
- case 2:
- temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
- output += encode(temp >> 10)
- output += encode((temp >> 4) & 0x3F)
- output += encode((temp << 2) & 0x3F)
- output += '='
- break
- }
-
- return output
- }
-
- exports.toByteArray = b64ToByteArray
- exports.fromByteArray = uint8ToBase64
-}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))
-
-},{}],4:[function(require,module,exports){
-exports.read = function (buffer, offset, isLE, mLen, nBytes) {
- var e, m
- var eLen = nBytes * 8 - mLen - 1
- var eMax = (1 << eLen) - 1
- var eBias = eMax >> 1
- var nBits = -7
- var i = isLE ? (nBytes - 1) : 0
- var d = isLE ? -1 : 1
- var s = buffer[offset + i]
-
- i += d
-
- e = s & ((1 << (-nBits)) - 1)
- s >>= (-nBits)
- nBits += eLen
- for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
-
- m = e & ((1 << (-nBits)) - 1)
- e >>= (-nBits)
- nBits += mLen
- for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
-
- if (e === 0) {
- e = 1 - eBias
- } else if (e === eMax) {
- return m ? NaN : ((s ? -1 : 1) * Infinity)
- } else {
- m = m + Math.pow(2, mLen)
- e = e - eBias
- }
- return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
-}
-
-exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
- var e, m, c
- var eLen = nBytes * 8 - mLen - 1
- var eMax = (1 << eLen) - 1
- var eBias = eMax >> 1
- var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
- var i = isLE ? 0 : (nBytes - 1)
- var d = isLE ? 1 : -1
- var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
-
- value = Math.abs(value)
-
- if (isNaN(value) || value === Infinity) {
- m = isNaN(value) ? 1 : 0
- e = eMax
- } else {
- e = Math.floor(Math.log(value) / Math.LN2)
- if (value * (c = Math.pow(2, -e)) < 1) {
- e--
- c *= 2
- }
- if (e + eBias >= 1) {
- value += rt / c
- } else {
- value += rt * Math.pow(2, 1 - eBias)
- }
- if (value * c >= 2) {
- e++
- c /= 2
- }
-
- if (e + eBias >= eMax) {
- m = 0
- e = eMax
- } else if (e + eBias >= 1) {
- m = (value * c - 1) * Math.pow(2, mLen)
- e = e + eBias
- } else {
- m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
- e = 0
- }
- }
-
- for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
-
- e = (e << mLen) | m
- eLen += mLen
- for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
-
- buffer[offset + i - d] |= s * 128
-}
-
-},{}],5:[function(require,module,exports){
-
-/**
- * isArray
- */
-
-var isArray = Array.isArray;
-
-/**
- * toString
- */
-
-var str = Object.prototype.toString;
-
-/**
- * Whether or not the given `val`
- * is an array.
- *
- * example:
- *
- * isArray([]);
- * // > true
- * isArray(arguments);
- * // > false
- * isArray('');
- * // > false
- *
- * @param {mixed} val
- * @return {bool}
- */
-
-module.exports = isArray || function (val) {
- return !! val && '[object Array]' == str.call(val);
-};
-
-},{}],6:[function(require,module,exports){
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-function EventEmitter() {
- this._events = this._events || {};
- this._maxListeners = this._maxListeners || undefined;
-}
-module.exports = EventEmitter;
-
-// Backwards-compat with node 0.10.x
-EventEmitter.EventEmitter = EventEmitter;
-
-EventEmitter.prototype._events = undefined;
-EventEmitter.prototype._maxListeners = undefined;
-
-// By default EventEmitters will print a warning if more than 10 listeners are
-// added to it. This is a useful default which helps finding memory leaks.
-EventEmitter.defaultMaxListeners = 10;
-
-// Obviously not all Emitters should be limited to 10. This function allows
-// that to be increased. Set to zero for unlimited.
-EventEmitter.prototype.setMaxListeners = function(n) {
- if (!isNumber(n) || n < 0 || isNaN(n))
- throw TypeError('n must be a positive number');
- this._maxListeners = n;
- return this;
-};
-
-EventEmitter.prototype.emit = function(type) {
- var er, handler, len, args, i, listeners;
-
- if (!this._events)
- this._events = {};
-
- // If there is no 'error' event listener then throw.
- if (type === 'error') {
- if (!this._events.error ||
- (isObject(this._events.error) && !this._events.error.length)) {
- er = arguments[1];
- if (er instanceof Error) {
- throw er; // Unhandled 'error' event
- }
- throw TypeError('Uncaught, unspecified "error" event.');
- }
- }
-
- handler = this._events[type];
-
- if (isUndefined(handler))
- return false;
-
- if (isFunction(handler)) {
- switch (arguments.length) {
- // fast cases
- case 1:
- handler.call(this);
- break;
- case 2:
- handler.call(this, arguments[1]);
- break;
- case 3:
- handler.call(this, arguments[1], arguments[2]);
- break;
- // slower
- default:
- len = arguments.length;
- args = new Array(len - 1);
- for (i = 1; i < len; i++)
- args[i - 1] = arguments[i];
- handler.apply(this, args);
- }
- } else if (isObject(handler)) {
- len = arguments.length;
- args = new Array(len - 1);
- for (i = 1; i < len; i++)
- args[i - 1] = arguments[i];
-
- listeners = handler.slice();
- len = listeners.length;
- for (i = 0; i < len; i++)
- listeners[i].apply(this, args);
- }
-
- return true;
-};
-
-EventEmitter.prototype.addListener = function(type, listener) {
- var m;
-
- if (!isFunction(listener))
- throw TypeError('listener must be a function');
-
- if (!this._events)
- this._events = {};
-
- // To avoid recursion in the case that type === "newListener"! Before
- // adding it to the listeners, first emit "newListener".
- if (this._events.newListener)
- this.emit('newListener', type,
- isFunction(listener.listener) ?
- listener.listener : listener);
-
- if (!this._events[type])
- // Optimize the case of one listener. Don't need the extra array object.
- this._events[type] = listener;
- else if (isObject(this._events[type]))
- // If we've already got an array, just append.
- this._events[type].push(listener);
- else
- // Adding the second element, need to change to array.
- this._events[type] = [this._events[type], listener];
-
- // Check for listener leak
- if (isObject(this._events[type]) && !this._events[type].warned) {
- var m;
- if (!isUndefined(this._maxListeners)) {
- m = this._maxListeners;
- } else {
- m = EventEmitter.defaultMaxListeners;
- }
-
- if (m && m > 0 && this._events[type].length > m) {
- this._events[type].warned = true;
- console.error('(node) warning: possible EventEmitter memory ' +
- 'leak detected. %d listeners added. ' +
- 'Use emitter.setMaxListeners() to increase limit.',
- this._events[type].length);
- if (typeof console.trace === 'function') {
- // not supported in IE 10
- console.trace();
- }
- }
- }
-
- return this;
-};
-
-EventEmitter.prototype.on = EventEmitter.prototype.addListener;
-
-EventEmitter.prototype.once = function(type, listener) {
- if (!isFunction(listener))
- throw TypeError('listener must be a function');
-
- var fired = false;
-
- function g() {
- this.removeListener(type, g);
-
- if (!fired) {
- fired = true;
- listener.apply(this, arguments);
- }
- }
-
- g.listener = listener;
- this.on(type, g);
-
- return this;
-};
-
-// emits a 'removeListener' event iff the listener was removed
-EventEmitter.prototype.removeListener = function(type, listener) {
- var list, position, length, i;
-
- if (!isFunction(listener))
- throw TypeError('listener must be a function');
-
- if (!this._events || !this._events[type])
- return this;
-
- list = this._events[type];
- length = list.length;
- position = -1;
-
- if (list === listener ||
- (isFunction(list.listener) && list.listener === listener)) {
- delete this._events[type];
- if (this._events.removeListener)
- this.emit('removeListener', type, listener);
-
- } else if (isObject(list)) {
- for (i = length; i-- > 0;) {
- if (list[i] === listener ||
- (list[i].listener && list[i].listener === listener)) {
- position = i;
- break;
- }
- }
-
- if (position < 0)
- return this;
-
- if (list.length === 1) {
- list.length = 0;
- delete this._events[type];
- } else {
- list.splice(position, 1);
- }
-
- if (this._events.removeListener)
- this.emit('removeListener', type, listener);
- }
-
- return this;
-};
-
-EventEmitter.prototype.removeAllListeners = function(type) {
- var key, listeners;
-
- if (!this._events)
- return this;
-
- // not listening for removeListener, no need to emit
- if (!this._events.removeListener) {
- if (arguments.length === 0)
- this._events = {};
- else if (this._events[type])
- delete this._events[type];
- return this;
- }
-
- // emit removeListener for all listeners on all events
- if (arguments.length === 0) {
- for (key in this._events) {
- if (key === 'removeListener') continue;
- this.removeAllListeners(key);
- }
- this.removeAllListeners('removeListener');
- this._events = {};
- return this;
- }
-
- listeners = this._events[type];
-
- if (isFunction(listeners)) {
- this.removeListener(type, listeners);
- } else {
- // LIFO order
- while (listeners.length)
- this.removeListener(type, listeners[listeners.length - 1]);
- }
- delete this._events[type];
-
- return this;
-};
-
-EventEmitter.prototype.listeners = function(type) {
- var ret;
- if (!this._events || !this._events[type])
- ret = [];
- else if (isFunction(this._events[type]))
- ret = [this._events[type]];
- else
- ret = this._events[type].slice();
- return ret;
-};
-
-EventEmitter.listenerCount = function(emitter, type) {
- var ret;
- if (!emitter._events || !emitter._events[type])
- ret = 0;
- else if (isFunction(emitter._events[type]))
- ret = 1;
- else
- ret = emitter._events[type].length;
- return ret;
-};
-
-function isFunction(arg) {
- return typeof arg === 'function';
-}
-
-function isNumber(arg) {
- return typeof arg === 'number';
-}
-
-function isObject(arg) {
- return typeof arg === 'object' && arg !== null;
-}
-
-function isUndefined(arg) {
- return arg === void 0;
-}
-
-},{}],7:[function(require,module,exports){
-if (typeof Object.create === 'function') {
- // implementation from standard node.js 'util' module
- module.exports = function inherits(ctor, superCtor) {
- ctor.super_ = superCtor
- ctor.prototype = Object.create(superCtor.prototype, {
- constructor: {
- value: ctor,
- enumerable: false,
- writable: true,
- configurable: true
- }
- });
- };
-} else {
- // old school shim for old browsers
- module.exports = function inherits(ctor, superCtor) {
- ctor.super_ = superCtor
- var TempCtor = function () {}
- TempCtor.prototype = superCtor.prototype
- ctor.prototype = new TempCtor()
- ctor.prototype.constructor = ctor
- }
-}
-
-},{}],8:[function(require,module,exports){
-/**
- * Determine if an object is Buffer
- *
- * Author: Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
- * License: MIT
- *
- * `npm install is-buffer`
- */
-
-module.exports = function (obj) {
- return !!(obj != null &&
- (obj._isBuffer || // For Safari 5-7 (missing Object.prototype.constructor)
- (obj.constructor &&
- typeof obj.constructor.isBuffer === 'function' &&
- obj.constructor.isBuffer(obj))
- ))
-}
-
-},{}],9:[function(require,module,exports){
-module.exports = Array.isArray || function (arr) {
- return Object.prototype.toString.call(arr) == '[object Array]';
-};
-
-},{}],10:[function(require,module,exports){
-// shim for using process in browser
-
-var process = module.exports = {};
-var queue = [];
-var draining = false;
-var currentQueue;
-var queueIndex = -1;
-
-function cleanUpNextTick() {
- draining = false;
- if (currentQueue.length) {
- queue = currentQueue.concat(queue);
- } else {
- queueIndex = -1;
- }
- if (queue.length) {
- drainQueue();
- }
-}
-
-function drainQueue() {
- if (draining) {
- return;
- }
- var timeout = setTimeout(cleanUpNextTick);
- draining = true;
-
- var len = queue.length;
- while(len) {
- currentQueue = queue;
- queue = [];
- while (++queueIndex < len) {
- if (currentQueue) {
- currentQueue[queueIndex].run();
- }
- }
- queueIndex = -1;
- len = queue.length;
- }
- currentQueue = null;
- draining = false;
- clearTimeout(timeout);
-}
-
-process.nextTick = function (fun) {
- var args = new Array(arguments.length - 1);
- if (arguments.length > 1) {
- for (var i = 1; i < arguments.length; i++) {
- args[i - 1] = arguments[i];
- }
- }
- queue.push(new Item(fun, args));
- if (queue.length === 1 && !draining) {
- setTimeout(drainQueue, 0);
- }
-};
-
-// v8 likes predictible objects
-function Item(fun, array) {
- this.fun = fun;
- this.array = array;
+function isnan (val) {
+ return val !== val // eslint-disable-line no-self-compare
}
-Item.prototype.run = function () {
- this.fun.apply(null, this.array);
-};
-process.title = 'browser';
-process.browser = true;
-process.env = {};
-process.argv = [];
-process.version = ''; // empty string to avoid regexp issues
-process.versions = {};
-
-function noop() {}
-
-process.on = noop;
-process.addListener = noop;
-process.once = noop;
-process.off = noop;
-process.removeListener = noop;
-process.removeAllListeners = noop;
-process.emit = noop;
-
-process.binding = function (name) {
- throw new Error('process.binding is not supported');
-};
-
-process.cwd = function () { return '/' };
-process.chdir = function (dir) {
- throw new Error('process.chdir is not supported');
-};
-process.umask = function() { return 0; };
-
-},{}],11:[function(require,module,exports){
-(function (global){
-/*! https://mths.be/punycode v1.3.2 by @mathias */
-;(function(root) {
-
- /** Detect free variables */
- var freeExports = typeof exports == 'object' && exports &&
- !exports.nodeType && exports;
- var freeModule = typeof module == 'object' && module &&
- !module.nodeType && module;
- var freeGlobal = typeof global == 'object' && global;
- if (
- freeGlobal.global === freeGlobal ||
- freeGlobal.window === freeGlobal ||
- freeGlobal.self === freeGlobal
- ) {
- root = freeGlobal;
- }
-
- /**
- * The `punycode` object.
- * @name punycode
- * @type Object
- */
- var punycode,
-
- /** Highest positive signed 32-bit float value */
- maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
-
- /** Bootstring parameters */
- base = 36,
- tMin = 1,
- tMax = 26,
- skew = 38,
- damp = 700,
- initialBias = 72,
- initialN = 128, // 0x80
- delimiter = '-', // '\x2D'
-
- /** Regular expressions */
- regexPunycode = /^xn--/,
- regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
- regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
-
- /** Error messages */
- errors = {
- 'overflow': 'Overflow: input needs wider integers to process',
- 'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
- 'invalid-input': 'Invalid input'
- },
-
- /** Convenience shortcuts */
- baseMinusTMin = base - tMin,
- floor = Math.floor,
- stringFromCharCode = String.fromCharCode,
-
- /** Temporary variable */
- key;
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * A generic error utility function.
- * @private
- * @param {String} type The error type.
- * @returns {Error} Throws a `RangeError` with the applicable error message.
- */
- function error(type) {
- throw RangeError(errors[type]);
- }
-
- /**
- * A generic `Array#map` utility function.
- * @private
- * @param {Array} array The array to iterate over.
- * @param {Function} callback The function that gets called for every array
- * item.
- * @returns {Array} A new array of values returned by the callback function.
- */
- function map(array, fn) {
- var length = array.length;
- var result = [];
- while (length--) {
- result[length] = fn(array[length]);
- }
- return result;
- }
-
- /**
- * A simple `Array#map`-like wrapper to work with domain name strings or email
- * addresses.
- * @private
- * @param {String} domain The domain name or email address.
- * @param {Function} callback The function that gets called for every
- * character.
- * @returns {Array} A new string of characters returned by the callback
- * function.
- */
- function mapDomain(string, fn) {
- var parts = string.split('@');
- var result = '';
- if (parts.length > 1) {
- // In email addresses, only the domain name should be punycoded. Leave
- // the local part (i.e. everything up to `@`) intact.
- result = parts[0] + '@';
- string = parts[1];
- }
- // Avoid `split(regex)` for IE8 compatibility. See #17.
- string = string.replace(regexSeparators, '\x2E');
- var labels = string.split('.');
- var encoded = map(labels, fn).join('.');
- return result + encoded;
- }
-
- /**
- * Creates an array containing the numeric code points of each Unicode
- * character in the string. While JavaScript uses UCS-2 internally,
- * this function will convert a pair of surrogate halves (each of which
- * UCS-2 exposes as separate characters) into a single code point,
- * matching UTF-16.
- * @see `punycode.ucs2.encode`
- * @see <https://mathiasbynens.be/notes/javascript-encoding>
- * @memberOf punycode.ucs2
- * @name decode
- * @param {String} string The Unicode input string (UCS-2).
- * @returns {Array} The new array of code points.
- */
- function ucs2decode(string) {
- var output = [],
- counter = 0,
- length = string.length,
- value,
- extra;
- while (counter < length) {
- value = string.charCodeAt(counter++);
- if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
- // high surrogate, and there is a next character
- extra = string.charCodeAt(counter++);
- if ((extra & 0xFC00) == 0xDC00) { // low surrogate
- output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
- } else {
- // unmatched surrogate; only append this code unit, in case the next
- // code unit is the high surrogate of a surrogate pair
- output.push(value);
- counter--;
- }
- } else {
- output.push(value);
- }
- }
- return output;
- }
-
- /**
- * Creates a string based on an array of numeric code points.
- * @see `punycode.ucs2.decode`
- * @memberOf punycode.ucs2
- * @name encode
- * @param {Array} codePoints The array of numeric code points.
- * @returns {String} The new Unicode string (UCS-2).
- */
- function ucs2encode(array) {
- return map(array, function(value) {
- var output = '';
- if (value > 0xFFFF) {
- value -= 0x10000;
- output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
- value = 0xDC00 | value & 0x3FF;
- }
- output += stringFromCharCode(value);
- return output;
- }).join('');
- }
-
- /**
- * Converts a basic code point into a digit/integer.
- * @see `digitToBasic()`
- * @private
- * @param {Number} codePoint The basic numeric code point value.
- * @returns {Number} The numeric value of a basic code point (for use in
- * representing integers) in the range `0` to `base - 1`, or `base` if
- * the code point does not represent a value.
- */
- function basicToDigit(codePoint) {
- if (codePoint - 48 < 10) {
- return codePoint - 22;
- }
- if (codePoint - 65 < 26) {
- return codePoint - 65;
- }
- if (codePoint - 97 < 26) {
- return codePoint - 97;
- }
- return base;
- }
-
- /**
- * Converts a digit/integer into a basic code point.
- * @see `basicToDigit()`
- * @private
- * @param {Number} digit The numeric value of a basic code point.
- * @returns {Number} The basic code point whose value (when used for
- * representing integers) is `digit`, which needs to be in the range
- * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
- * used; else, the lowercase form is used. The behavior is undefined
- * if `flag` is non-zero and `digit` has no uppercase form.
- */
- function digitToBasic(digit, flag) {
- // 0..25 map to ASCII a..z or A..Z
- // 26..35 map to ASCII 0..9
- return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
- }
-
- /**
- * Bias adaptation function as per section 3.4 of RFC 3492.
- * http://tools.ietf.org/html/rfc3492#section-3.4
- * @private
- */
- function adapt(delta, numPoints, firstTime) {
- var k = 0;
- delta = firstTime ? floor(delta / damp) : delta >> 1;
- delta += floor(delta / numPoints);
- for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
- delta = floor(delta / baseMinusTMin);
- }
- return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
- }
-
- /**
- * Converts a Punycode string of ASCII-only symbols to a string of Unicode
- * symbols.
- * @memberOf punycode
- * @param {String} input The Punycode string of ASCII-only symbols.
- * @returns {String} The resulting string of Unicode symbols.
- */
- function decode(input) {
- // Don't use UCS-2
- var output = [],
- inputLength = input.length,
- out,
- i = 0,
- n = initialN,
- bias = initialBias,
- basic,
- j,
- index,
- oldi,
- w,
- k,
- digit,
- t,
- /** Cached calculation results */
- baseMinusT;
-
- // Handle the basic code points: let `basic` be the number of input code
- // points before the last delimiter, or `0` if there is none, then copy
- // the first basic code points to the output.
-
- basic = input.lastIndexOf(delimiter);
- if (basic < 0) {
- basic = 0;
- }
-
- for (j = 0; j < basic; ++j) {
- // if it's not a basic code point
- if (input.charCodeAt(j) >= 0x80) {
- error('not-basic');
- }
- output.push(input.charCodeAt(j));
- }
-
- // Main decoding loop: start just after the last delimiter if any basic code
- // points were copied; start at the beginning otherwise.
-
- for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
-
- // `index` is the index of the next character to be consumed.
- // Decode a generalized variable-length integer into `delta`,
- // which gets added to `i`. The overflow checking is easier
- // if we increase `i` as we go, then subtract off its starting
- // value at the end to obtain `delta`.
- for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
-
- if (index >= inputLength) {
- error('invalid-input');
- }
-
- digit = basicToDigit(input.charCodeAt(index++));
-
- if (digit >= base || digit > floor((maxInt - i) / w)) {
- error('overflow');
- }
-
- i += digit * w;
- t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
-
- if (digit < t) {
- break;
- }
-
- baseMinusT = base - t;
- if (w > floor(maxInt / baseMinusT)) {
- error('overflow');
- }
-
- w *= baseMinusT;
-
- }
-
- out = output.length + 1;
- bias = adapt(i - oldi, out, oldi == 0);
-
- // `i` was supposed to wrap around from `out` to `0`,
- // incrementing `n` each time, so we'll fix that now:
- if (floor(i / out) > maxInt - n) {
- error('overflow');
- }
-
- n += floor(i / out);
- i %= out;
-
- // Insert `n` at position `i` of the output
- output.splice(i++, 0, n);
-
- }
-
- return ucs2encode(output);
- }
-
- /**
- * Converts a string of Unicode symbols (e.g. a domain name label) to a
- * Punycode string of ASCII-only symbols.
- * @memberOf punycode
- * @param {String} input The string of Unicode symbols.
- * @returns {String} The resulting Punycode string of ASCII-only symbols.
- */
- function encode(input) {
- var n,
- delta,
- handledCPCount,
- basicLength,
- bias,
- j,
- m,
- q,
- k,
- t,
- currentValue,
- output = [],
- /** `inputLength` will hold the number of code points in `input`. */
- inputLength,
- /** Cached calculation results */
- handledCPCountPlusOne,
- baseMinusT,
- qMinusT;
-
- // Convert the input in UCS-2 to Unicode
- input = ucs2decode(input);
-
- // Cache the length
- inputLength = input.length;
-
- // Initialize the state
- n = initialN;
- delta = 0;
- bias = initialBias;
-
- // Handle the basic code points
- for (j = 0; j < inputLength; ++j) {
- currentValue = input[j];
- if (currentValue < 0x80) {
- output.push(stringFromCharCode(currentValue));
- }
- }
-
- handledCPCount = basicLength = output.length;
-
- // `handledCPCount` is the number of code points that have been handled;
- // `basicLength` is the number of basic code points.
-
- // Finish the basic string - if it is not empty - with a delimiter
- if (basicLength) {
- output.push(delimiter);
- }
-
- // Main encoding loop:
- while (handledCPCount < inputLength) {
-
- // All non-basic code points < n have been handled already. Find the next
- // larger one:
- for (m = maxInt, j = 0; j < inputLength; ++j) {
- currentValue = input[j];
- if (currentValue >= n && currentValue < m) {
- m = currentValue;
- }
- }
-
- // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
- // but guard against overflow
- handledCPCountPlusOne = handledCPCount + 1;
- if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
- error('overflow');
- }
-
- delta += (m - n) * handledCPCountPlusOne;
- n = m;
-
- for (j = 0; j < inputLength; ++j) {
- currentValue = input[j];
-
- if (currentValue < n && ++delta > maxInt) {
- error('overflow');
- }
-
- if (currentValue == n) {
- // Represent delta as a generalized variable-length integer
- for (q = delta, k = base; /* no condition */; k += base) {
- t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
- if (q < t) {
- break;
- }
- qMinusT = q - t;
- baseMinusT = base - t;
- output.push(
- stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
- );
- q = floor(qMinusT / baseMinusT);
- }
-
- output.push(stringFromCharCode(digitToBasic(q, 0)));
- bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
- delta = 0;
- ++handledCPCount;
- }
- }
-
- ++delta;
- ++n;
-
- }
- return output.join('');
- }
-
- /**
- * Converts a Punycode string representing a domain name or an email address
- * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
- * it doesn't matter if you call it on a string that has already been
- * converted to Unicode.
- * @memberOf punycode
- * @param {String} input The Punycoded domain name or email address to
- * convert to Unicode.
- * @returns {String} The Unicode representation of the given Punycode
- * string.
- */
- function toUnicode(input) {
- return mapDomain(input, function(string) {
- return regexPunycode.test(string)
- ? decode(string.slice(4).toLowerCase())
- : string;
- });
- }
-
- /**
- * Converts a Unicode string representing a domain name or an email address to
- * Punycode. Only the non-ASCII parts of the domain name will be converted,
- * i.e. it doesn't matter if you call it with a domain that's already in
- * ASCII.
- * @memberOf punycode
- * @param {String} input The domain name or email address to convert, as a
- * Unicode string.
- * @returns {String} The Punycode representation of the given domain name or
- * email address.
- */
- function toASCII(input) {
- return mapDomain(input, function(string) {
- return regexNonASCII.test(string)
- ? 'xn--' + encode(string)
- : string;
- });
- }
-
- /*--------------------------------------------------------------------------*/
-
- /** Define the public API */
- punycode = {
- /**
- * A string representing the current Punycode.js version number.
- * @memberOf punycode
- * @type String
- */
- 'version': '1.3.2',
- /**
- * An object of methods to convert from JavaScript's internal character
- * representation (UCS-2) to Unicode code points, and back.
- * @see <https://mathiasbynens.be/notes/javascript-encoding>
- * @memberOf punycode
- * @type Object
- */
- 'ucs2': {
- 'decode': ucs2decode,
- 'encode': ucs2encode
- },
- 'decode': decode,
- 'encode': encode,
- 'toASCII': toASCII,
- 'toUnicode': toUnicode
- };
-
- /** Expose `punycode` */
- // Some AMD build optimizers, like r.js, check for specific condition patterns
- // like the following:
- if (
- typeof define == 'function' &&
- typeof define.amd == 'object' &&
- define.amd
- ) {
- define('punycode', function() {
- return punycode;
- });
- } else if (freeExports && freeModule) {
- if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+
- freeModule.exports = punycode;
- } else { // in Narwhal or RingoJS v0.7.0-
- for (key in punycode) {
- punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
- }
- }
- } else { // in Rhino or a web browser
- root.punycode = punycode;
- }
-
-}(this));
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],12:[function(require,module,exports){
-module.exports = require("./lib/_stream_duplex.js")
-
-},{"./lib/_stream_duplex.js":13}],13:[function(require,module,exports){
-// a duplex stream is just a stream that is both readable and writable.
-// Since JS doesn't have multiple prototypal inheritance, this class
-// prototypally inherits from Readable, and then parasitically from
-// Writable.
-
-'use strict';
-
-/*<replacement>*/
-var objectKeys = Object.keys || function (obj) {
- var keys = [];
- for (var key in obj) keys.push(key);
- return keys;
-}
-/*</replacement>*/
-
-
-module.exports = Duplex;
-
-/*<replacement>*/
-var processNextTick = require('process-nextick-args');
-/*</replacement>*/
-
-
-
-/*<replacement>*/
-var util = require('core-util-is');
-util.inherits = require('inherits');
-/*</replacement>*/
-
-var Readable = require('./_stream_readable');
-var Writable = require('./_stream_writable');
-
-util.inherits(Duplex, Readable);
-
-var keys = objectKeys(Writable.prototype);
-for (var v = 0; v < keys.length; v++) {
- var method = keys[v];
- if (!Duplex.prototype[method])
- Duplex.prototype[method] = Writable.prototype[method];
-}
-
-function Duplex(options) {
- if (!(this instanceof Duplex))
- return new Duplex(options);
-
- Readable.call(this, options);
- Writable.call(this, options);
-
- if (options && options.readable === false)
- this.readable = false;
-
- if (options && options.writable === false)
- this.writable = false;
-
- this.allowHalfOpen = true;
- if (options && options.allowHalfOpen === false)
- this.allowHalfOpen = false;
-
- this.once('end', onend);
-}
-
-// the no-half-open enforcer
-function onend() {
- // if we allow half-open state, or if the writable side ended,
- // then we're ok.
- if (this.allowHalfOpen || this._writableState.ended)
- return;
-
- // no more data can be written.
- // But allow more writes to happen in this tick.
- processNextTick(onEndNT, this);
-}
-
-function onEndNT(self) {
- self.end();
-}
-
-function forEach (xs, f) {
- for (var i = 0, l = xs.length; i < l; i++) {
- f(xs[i], i);
- }
-}
-
-},{"./_stream_readable":15,"./_stream_writable":17,"core-util-is":18,"inherits":7,"process-nextick-args":19}],14:[function(require,module,exports){
-// a passthrough stream.
-// basically just the most minimal sort of Transform stream.
-// Every written chunk gets output as-is.
-
-'use strict';
-
-module.exports = PassThrough;
-
-var Transform = require('./_stream_transform');
-
-/*<replacement>*/
-var util = require('core-util-is');
-util.inherits = require('inherits');
-/*</replacement>*/
-
-util.inherits(PassThrough, Transform);
-
-function PassThrough(options) {
- if (!(this instanceof PassThrough))
- return new PassThrough(options);
-
- Transform.call(this, options);
-}
-
-PassThrough.prototype._transform = function(chunk, encoding, cb) {
- cb(null, chunk);
-};
-
-},{"./_stream_transform":16,"core-util-is":18,"inherits":7}],15:[function(require,module,exports){
-(function (process){
-'use strict';
-
-module.exports = Readable;
-
-/*<replacement>*/
-var processNextTick = require('process-nextick-args');
-/*</replacement>*/
-
-
-/*<replacement>*/
-var isArray = require('isarray');
-/*</replacement>*/
-
-
-/*<replacement>*/
-var Buffer = require('buffer').Buffer;
-/*</replacement>*/
-
-Readable.ReadableState = ReadableState;
-
-var EE = require('events');
-
-/*<replacement>*/
-var EElistenerCount = function(emitter, type) {
- return emitter.listeners(type).length;
-};
-/*</replacement>*/
-
-
-
-/*<replacement>*/
-var Stream;
-(function (){try{
- Stream = require('st' + 'ream');
-}catch(_){}finally{
- if (!Stream)
- Stream = require('events').EventEmitter;
-}}())
-/*</replacement>*/
-
-var Buffer = require('buffer').Buffer;
-
-/*<replacement>*/
-var util = require('core-util-is');
-util.inherits = require('inherits');
-/*</replacement>*/
-
-
-
-/*<replacement>*/
-var debugUtil = require('util');
-var debug;
-if (debugUtil && debugUtil.debuglog) {
- debug = debugUtil.debuglog('stream');
-} else {
- debug = function () {};
-}
-/*</replacement>*/
-
-var StringDecoder;
-
-util.inherits(Readable, Stream);
-
-function ReadableState(options, stream) {
- var Duplex = require('./_stream_duplex');
-
- options = options || {};
-
- // object stream flag. Used to make read(n) ignore n and to
- // make all the buffer merging and length checks go away
- this.objectMode = !!options.objectMode;
-
- if (stream instanceof Duplex)
- this.objectMode = this.objectMode || !!options.readableObjectMode;
-
- // the point at which it stops calling _read() to fill the buffer
- // Note: 0 is a valid value, means "don't call _read preemptively ever"
- var hwm = options.highWaterMark;
- var defaultHwm = this.objectMode ? 16 : 16 * 1024;
- this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm;
-
- // cast to ints.
- this.highWaterMark = ~~this.highWaterMark;
-
- this.buffer = [];
- this.length = 0;
- this.pipes = null;
- this.pipesCount = 0;
- this.flowing = null;
- this.ended = false;
- this.endEmitted = false;
- this.reading = false;
-
- // a flag to be able to tell if the onwrite cb is called immediately,
- // or on a later tick. We set this to true at first, because any
- // actions that shouldn't happen until "later" should generally also
- // not happen before the first write call.
- this.sync = true;
-
- // whenever we return null, then we set a flag to say
- // that we're awaiting a 'readable' event emission.
- this.needReadable = false;
- this.emittedReadable = false;
- this.readableListening = false;
-
- // Crypto is kind of old and crusty. Historically, its default string
- // encoding is 'binary' so we have to make this configurable.
- // Everything else in the universe uses 'utf8', though.
- this.defaultEncoding = options.defaultEncoding || 'utf8';
-
- // when piping, we only care about 'readable' events that happen
- // after read()ing all the bytes and not getting any pushback.
- this.ranOut = false;
-
- // the number of writers that are awaiting a drain event in .pipe()s
- this.awaitDrain = 0;
-
- // if true, a maybeReadMore has been scheduled
- this.readingMore = false;
-
- this.decoder = null;
- this.encoding = null;
- if (options.encoding) {
- if (!StringDecoder)
- StringDecoder = require('string_decoder/').StringDecoder;
- this.decoder = new StringDecoder(options.encoding);
- this.encoding = options.encoding;
- }
-}
-
-function Readable(options) {
- var Duplex = require('./_stream_duplex');
-
- if (!(this instanceof Readable))
- return new Readable(options);
-
- this._readableState = new ReadableState(options, this);
-
- // legacy
- this.readable = true;
-
- if (options && typeof options.read === 'function')
- this._read = options.read;
-
- Stream.call(this);
-}
-
-// Manually shove something into the read() buffer.
-// This returns true if the highWaterMark has not been hit yet,
-// similar to how Writable.write() returns true if you should
-// write() some more.
-Readable.prototype.push = function(chunk, encoding) {
- var state = this._readableState;
-
- if (!state.objectMode && typeof chunk === 'string') {
- encoding = encoding || state.defaultEncoding;
- if (encoding !== state.encoding) {
- chunk = new Buffer(chunk, encoding);
- encoding = '';
- }
- }
-
- return readableAddChunk(this, state, chunk, encoding, false);
-};
-
-// Unshift should *always* be something directly out of read()
-Readable.prototype.unshift = function(chunk) {
- var state = this._readableState;
- return readableAddChunk(this, state, chunk, '', true);
-};
-
-Readable.prototype.isPaused = function() {
- return this._readableState.flowing === false;
-};
-
-function readableAddChunk(stream, state, chunk, encoding, addToFront) {
- var er = chunkInvalid(state, chunk);
- if (er) {
- stream.emit('error', er);
- } else if (chunk === null) {
- state.reading = false;
- onEofChunk(stream, state);
- } else if (state.objectMode || chunk && chunk.length > 0) {
- if (state.ended && !addToFront) {
- var e = new Error('stream.push() after EOF');
- stream.emit('error', e);
- } else if (state.endEmitted && addToFront) {
- var e = new Error('stream.unshift() after end event');
- stream.emit('error', e);
- } else {
- if (state.decoder && !addToFront && !encoding)
- chunk = state.decoder.write(chunk);
-
- if (!addToFront)
- state.reading = false;
-
- // if we want the data now, just emit it.
- if (state.flowing && state.length === 0 && !state.sync) {
- stream.emit('data', chunk);
- stream.read(0);
- } else {
- // update the buffer info.
- state.length += state.objectMode ? 1 : chunk.length;
- if (addToFront)
- state.buffer.unshift(chunk);
- else
- state.buffer.push(chunk);
-
- if (state.needReadable)
- emitReadable(stream);
- }
-
- maybeReadMore(stream, state);
- }
- } else if (!addToFront) {
- state.reading = false;
- }
-
- return needMoreData(state);
-}
-
-
-// if it's past the high water mark, we can push in some more.
-// Also, if we have no data yet, we can stand some
-// more bytes. This is to work around cases where hwm=0,
-// such as the repl. Also, if the push() triggered a
-// readable event, and the user called read(largeNumber) such that
-// needReadable was set, then we ought to push more, so that another
-// 'readable' event will be triggered.
-function needMoreData(state) {
- return !state.ended &&
- (state.needReadable ||
- state.length < state.highWaterMark ||
- state.length === 0);
-}
-
-// backwards compatibility.
-Readable.prototype.setEncoding = function(enc) {
- if (!StringDecoder)
- StringDecoder = require('string_decoder/').StringDecoder;
- this._readableState.decoder = new StringDecoder(enc);
- this._readableState.encoding = enc;
- return this;
-};
-
-// Don't raise the hwm > 8MB
-var MAX_HWM = 0x800000;
-function computeNewHighWaterMark(n) {
- if (n >= MAX_HWM) {
- n = MAX_HWM;
+},{"base64-js":3,"ieee754":44,"isarray":48}],7:[function(require,module,exports){
+(function (Buffer){
+var Transform = require('stream').Transform
+var inherits = require('inherits')
+var StringDecoder = require('string_decoder').StringDecoder
+module.exports = CipherBase
+inherits(CipherBase, Transform)
+function CipherBase (hashMode) {
+ Transform.call(this)
+ this.hashMode = typeof hashMode === 'string'
+ if (this.hashMode) {
+ this[hashMode] = this._finalOrDigest
} else {
- // Get the next highest power of 2
- n--;
- n |= n >>> 1;
- n |= n >>> 2;
- n |= n >>> 4;
- n |= n >>> 8;
- n |= n >>> 16;
- n++;
- }
- return n;
-}
-
-function howMuchToRead(n, state) {
- if (state.length === 0 && state.ended)
- return 0;
-
- if (state.objectMode)
- return n === 0 ? 0 : 1;
-
- if (n === null || isNaN(n)) {
- // only flow one buffer at a time
- if (state.flowing && state.buffer.length)
- return state.buffer[0].length;
- else
- return state.length;
- }
-
- if (n <= 0)
- return 0;
-
- // If we're asking for more than the target buffer level,
- // then raise the water mark. Bump up to the next highest
- // power of 2, to prevent increasing it excessively in tiny
- // amounts.
- if (n > state.highWaterMark)
- state.highWaterMark = computeNewHighWaterMark(n);
-
- // don't have that much. return null, unless we've ended.
- if (n > state.length) {
- if (!state.ended) {
- state.needReadable = true;
- return 0;
- } else {
- return state.length;
- }
- }
-
- return n;
-}
-
-// you can override either this method, or the async _read(n) below.
-Readable.prototype.read = function(n) {
- debug('read', n);
- var state = this._readableState;
- var nOrig = n;
-
- if (typeof n !== 'number' || n > 0)
- state.emittedReadable = false;
-
- // if we're doing read(0) to trigger a readable event, but we
- // already have a bunch of data in the buffer, then just trigger
- // the 'readable' event and move on.
- if (n === 0 &&
- state.needReadable &&
- (state.length >= state.highWaterMark || state.ended)) {
- debug('read: emitReadable', state.length, state.ended);
- if (state.length === 0 && state.ended)
- endReadable(this);
- else
- emitReadable(this);
- return null;
- }
-
- n = howMuchToRead(n, state);
-
- // if we've ended, and we're now clear, then finish it up.
- if (n === 0 && state.ended) {
- if (state.length === 0)
- endReadable(this);
- return null;
- }
-
- // All the actual chunk generation logic needs to be
- // *below* the call to _read. The reason is that in certain
- // synthetic stream cases, such as passthrough streams, _read
- // may be a completely synchronous operation which may change
- // the state of the read buffer, providing enough data when
- // before there was *not* enough.
- //
- // So, the steps are:
- // 1. Figure out what the state of things will be after we do
- // a read from the buffer.
- //
- // 2. If that resulting state will trigger a _read, then call _read.
- // Note that this may be asynchronous, or synchronous. Yes, it is
- // deeply ugly to write APIs this way, but that still doesn't mean
- // that the Readable class should behave improperly, as streams are
- // designed to be sync/async agnostic.
- // Take note if the _read call is sync or async (ie, if the read call
- // has returned yet), so that we know whether or not it's safe to emit
- // 'readable' etc.
- //
- // 3. Actually pull the requested chunks out of the buffer and return.
-
- // if we need a readable event, then we need to do some reading.
- var doRead = state.needReadable;
- debug('need readable', doRead);
-
- // if we currently have less than the highWaterMark, then also read some
- if (state.length === 0 || state.length - n < state.highWaterMark) {
- doRead = true;
- debug('length less than watermark', doRead);
- }
-
- // however, if we've ended, then there's no point, and if we're already
- // reading, then it's unnecessary.
- if (state.ended || state.reading) {
- doRead = false;
- debug('reading or ended', doRead);
- }
-
- if (doRead) {
- debug('do read');
- state.reading = true;
- state.sync = true;
- // if the length is currently zero, then we *need* a readable event.
- if (state.length === 0)
- state.needReadable = true;
- // call internal read method
- this._read(state.highWaterMark);
- state.sync = false;
- }
-
- // If _read pushed data synchronously, then `reading` will be false,
- // and we need to re-evaluate how much data we can return to the user.
- if (doRead && !state.reading)
- n = howMuchToRead(nOrig, state);
-
- var ret;
- if (n > 0)
- ret = fromList(n, state);
- else
- ret = null;
-
- if (ret === null) {
- state.needReadable = true;
- n = 0;
- }
-
- state.length -= n;
-
- // If we have nothing in the buffer, then we want to know
- // as soon as we *do* get something into the buffer.
- if (state.length === 0 && !state.ended)
- state.needReadable = true;
-
- // If we tried to read() past the EOF, then emit end on the next tick.
- if (nOrig !== n && state.ended && state.length === 0)
- endReadable(this);
-
- if (ret !== null)
- this.emit('data', ret);
-
- return ret;
-};
-
-function chunkInvalid(state, chunk) {
- var er = null;
- if (!(Buffer.isBuffer(chunk)) &&
- typeof chunk !== 'string' &&
- chunk !== null &&
- chunk !== undefined &&
- !state.objectMode) {
- er = new TypeError('Invalid non-string/buffer chunk');
- }
- return er;
-}
-
-
-function onEofChunk(stream, state) {
- if (state.ended) return;
- if (state.decoder) {
- var chunk = state.decoder.end();
- if (chunk && chunk.length) {
- state.buffer.push(chunk);
- state.length += state.objectMode ? 1 : chunk.length;
- }
- }
- state.ended = true;
-
- // emit 'readable' now to make sure it gets picked up.
- emitReadable(stream);
-}
-
-// Don't emit readable right away in sync mode, because this can trigger
-// another read() call => stack overflow. This way, it might trigger
-// a nextTick recursion warning, but that's not so bad.
-function emitReadable(stream) {
- var state = stream._readableState;
- state.needReadable = false;
- if (!state.emittedReadable) {
- debug('emitReadable', state.flowing);
- state.emittedReadable = true;
- if (state.sync)
- processNextTick(emitReadable_, stream);
- else
- emitReadable_(stream);
- }
-}
-
-function emitReadable_(stream) {
- debug('emit readable');
- stream.emit('readable');
- flow(stream);
-}
-
-
-// at this point, the user has presumably seen the 'readable' event,
-// and called read() to consume some data. that may have triggered
-// in turn another _read(n) call, in which case reading = true if
-// it's in progress.
-// However, if we're not ended, or reading, and the length < hwm,
-// then go ahead and try to read some more preemptively.
-function maybeReadMore(stream, state) {
- if (!state.readingMore) {
- state.readingMore = true;
- processNextTick(maybeReadMore_, stream, state);
- }
-}
-
-function maybeReadMore_(stream, state) {
- var len = state.length;
- while (!state.reading && !state.flowing && !state.ended &&
- state.length < state.highWaterMark) {
- debug('maybeReadMore read 0');
- stream.read(0);
- if (len === state.length)
- // didn't get any data, stop spinning.
- break;
- else
- len = state.length;
- }
- state.readingMore = false;
-}
-
-// abstract method. to be overridden in specific implementation classes.
-// call cb(er, data) where data is <= n in length.
-// for virtual (non-string, non-buffer) streams, "length" is somewhat
-// arbitrary, and perhaps not very meaningful.
-Readable.prototype._read = function(n) {
- this.emit('error', new Error('not implemented'));
-};
-
-Readable.prototype.pipe = function(dest, pipeOpts) {
- var src = this;
- var state = this._readableState;
-
- switch (state.pipesCount) {
- case 0:
- state.pipes = dest;
- break;
- case 1:
- state.pipes = [state.pipes, dest];
- break;
- default:
- state.pipes.push(dest);
- break;
- }
- state.pipesCount += 1;
- debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);
-
- var doEnd = (!pipeOpts || pipeOpts.end !== false) &&
- dest !== process.stdout &&
- dest !== process.stderr;
-
- var endFn = doEnd ? onend : cleanup;
- if (state.endEmitted)
- processNextTick(endFn);
- else
- src.once('end', endFn);
-
- dest.on('unpipe', onunpipe);
- function onunpipe(readable) {
- debug('onunpipe');
- if (readable === src) {
- cleanup();
- }
- }
-
- function onend() {
- debug('onend');
- dest.end();
- }
-
- // when the dest drains, it reduces the awaitDrain counter
- // on the source. This would be more elegant with a .once()
- // handler in flow(), but adding and removing repeatedly is
- // too slow.
- var ondrain = pipeOnDrain(src);
- dest.on('drain', ondrain);
-
- var cleanedUp = false;
- function cleanup() {
- debug('cleanup');
- // cleanup event handlers once the pipe is broken
- dest.removeListener('close', onclose);
- dest.removeListener('finish', onfinish);
- dest.removeListener('drain', ondrain);
- dest.removeListener('error', onerror);
- dest.removeListener('unpipe', onunpipe);
- src.removeListener('end', onend);
- src.removeListener('end', cleanup);
- src.removeListener('data', ondata);
-
- cleanedUp = true;
-
- // if the reader is waiting for a drain event from this
- // specific writer, then it would cause it to never start
- // flowing again.
- // So, if this is awaiting a drain, then we just call it now.
- // If we don't know, then assume that we are waiting for one.
- if (state.awaitDrain &&
- (!dest._writableState || dest._writableState.needDrain))
- ondrain();
- }
-
- src.on('data', ondata);
- function ondata(chunk) {
- debug('ondata');
- var ret = dest.write(chunk);
- if (false === ret) {
- // If the user unpiped during `dest.write()`, it is possible
- // to get stuck in a permanently paused state if that write
- // also returned false.
- if (state.pipesCount === 1 &&
- state.pipes[0] === dest &&
- src.listenerCount('data') === 1 &&
- !cleanedUp) {
- debug('false write response, pause', src._readableState.awaitDrain);
- src._readableState.awaitDrain++;
- }
- src.pause();
- }
- }
-
- // if the dest has an error, then stop piping into it.
- // however, don't suppress the throwing behavior for this.
- function onerror(er) {
- debug('onerror', er);
- unpipe();
- dest.removeListener('error', onerror);
- if (EElistenerCount(dest, 'error') === 0)
- dest.emit('error', er);
- }
- // This is a brutally ugly hack to make sure that our error handler
- // is attached before any userland ones. NEVER DO THIS.
- if (!dest._events || !dest._events.error)
- dest.on('error', onerror);
- else if (isArray(dest._events.error))
- dest._events.error.unshift(onerror);
- else
- dest._events.error = [onerror, dest._events.error];
-
-
- // Both close and finish should trigger unpipe, but only once.
- function onclose() {
- dest.removeListener('finish', onfinish);
- unpipe();
- }
- dest.once('close', onclose);
- function onfinish() {
- debug('onfinish');
- dest.removeListener('close', onclose);
- unpipe();
- }
- dest.once('finish', onfinish);
-
- function unpipe() {
- debug('unpipe');
- src.unpipe(dest);
- }
-
- // tell the dest that it's being piped to
- dest.emit('pipe', src);
-
- // start the flow if it hasn't been started already.
- if (!state.flowing) {
- debug('pipe resume');
- src.resume();
+ this.final = this._finalOrDigest
}
-
- return dest;
-};
-
-function pipeOnDrain(src) {
- return function() {
- var state = src._readableState;
- debug('pipeOnDrain', state.awaitDrain);
- if (state.awaitDrain)
- state.awaitDrain--;
- if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {
- state.flowing = true;
- flow(src);
- }
- };
+ this._decoder = null
+ this._encoding = null
}
-
-
-Readable.prototype.unpipe = function(dest) {
- var state = this._readableState;
-
- // if we're not piping anywhere, then do nothing.
- if (state.pipesCount === 0)
- return this;
-
- // just one destination. most common case.
- if (state.pipesCount === 1) {
- // passed in one, but it's not the right one.
- if (dest && dest !== state.pipes)
- return this;
-
- if (!dest)
- dest = state.pipes;
-
- // got a match.
- state.pipes = null;
- state.pipesCount = 0;
- state.flowing = false;
- if (dest)
- dest.emit('unpipe', this);
- return this;
- }
-
- // slow case. multiple pipe destinations.
-
- if (!dest) {
- // remove all.
- var dests = state.pipes;
- var len = state.pipesCount;
- state.pipes = null;
- state.pipesCount = 0;
- state.flowing = false;
-
- for (var i = 0; i < len; i++)
- dests[i].emit('unpipe', this);
- return this;
+CipherBase.prototype.update = function (data, inputEnc, outputEnc) {
+ if (typeof data === 'string') {
+ data = new Buffer(data, inputEnc)
}
-
- // try to find the right one.
- var i = indexOf(state.pipes, dest);
- if (i === -1)
- return this;
-
- state.pipes.splice(i, 1);
- state.pipesCount -= 1;
- if (state.pipesCount === 1)
- state.pipes = state.pipes[0];
-
- dest.emit('unpipe', this);
-
- return this;
-};
-
-// set up data events if they are asked for
-// Ensure readable listeners eventually get something
-Readable.prototype.on = function(ev, fn) {
- var res = Stream.prototype.on.call(this, ev, fn);
-
- // If listening to data, and it has not explicitly been paused,
- // then call resume to start the flow of data on the next tick.
- if (ev === 'data' && false !== this._readableState.flowing) {
- this.resume();
+ var outData = this._update(data)
+ if (this.hashMode) {
+ return this
}
-
- if (ev === 'readable' && this.readable) {
- var state = this._readableState;
- if (!state.readableListening) {
- state.readableListening = true;
- state.emittedReadable = false;
- state.needReadable = true;
- if (!state.reading) {
- processNextTick(nReadingNextTick, this);
- } else if (state.length) {
- emitReadable(this, state);
- }
- }
+ if (outputEnc) {
+ outData = this._toString(outData, outputEnc)
}
-
- return res;
-};
-Readable.prototype.addListener = Readable.prototype.on;
-
-function nReadingNextTick(self) {
- debug('readable nexttick read 0');
- self.read(0);
+ return outData
}
-// pause() and resume() are remnants of the legacy readable stream API
-// If the user uses them, then switch into old mode.
-Readable.prototype.resume = function() {
- var state = this._readableState;
- if (!state.flowing) {
- debug('resume');
- state.flowing = true;
- resume(this, state);
- }
- return this;
-};
+CipherBase.prototype.setAutoPadding = function () {}
-function resume(stream, state) {
- if (!state.resumeScheduled) {
- state.resumeScheduled = true;
- processNextTick(resume_, stream, state);
- }
+CipherBase.prototype.getAuthTag = function () {
+ throw new Error('trying to get auth tag in unsupported state')
}
-function resume_(stream, state) {
- if (!state.reading) {
- debug('resume read 0');
- stream.read(0);
- }
-
- state.resumeScheduled = false;
- stream.emit('resume');
- flow(stream);
- if (state.flowing && !state.reading)
- stream.read(0);
+CipherBase.prototype.setAuthTag = function () {
+ throw new Error('trying to set auth tag in unsupported state')
}
-Readable.prototype.pause = function() {
- debug('call pause flowing=%j', this._readableState.flowing);
- if (false !== this._readableState.flowing) {
- debug('pause');
- this._readableState.flowing = false;
- this.emit('pause');
- }
- return this;
-};
-
-function flow(stream) {
- var state = stream._readableState;
- debug('flow', state.flowing);
- if (state.flowing) {
- do {
- var chunk = stream.read();
- } while (null !== chunk && state.flowing);
- }
+CipherBase.prototype.setAAD = function () {
+ throw new Error('trying to set aad in unsupported state')
}
-// wrap an old-style stream as the async data source.
-// This is *not* part of the readable stream interface.
-// It is an ugly unfortunate mess of history.
-Readable.prototype.wrap = function(stream) {
- var state = this._readableState;
- var paused = false;
-
- var self = this;
- stream.on('end', function() {
- debug('wrapped end');
- if (state.decoder && !state.ended) {
- var chunk = state.decoder.end();
- if (chunk && chunk.length)
- self.push(chunk);
- }
-
- self.push(null);
- });
-
- stream.on('data', function(chunk) {
- debug('wrapped data');
- if (state.decoder)
- chunk = state.decoder.write(chunk);
-
- // don't skip over falsy values in objectMode
- if (state.objectMode && (chunk === null || chunk === undefined))
- return;
- else if (!state.objectMode && (!chunk || !chunk.length))
- return;
-
- var ret = self.push(chunk);
- if (!ret) {
- paused = true;
- stream.pause();
- }
- });
-
- // proxy all the other methods.
- // important when wrapping filters and duplexes.
- for (var i in stream) {
- if (this[i] === undefined && typeof stream[i] === 'function') {
- this[i] = function(method) { return function() {
- return stream[method].apply(stream, arguments);
- }; }(i);
- }
- }
-
- // proxy certain important events.
- var events = ['error', 'close', 'destroy', 'pause', 'resume'];
- forEach(events, function(ev) {
- stream.on(ev, self.emit.bind(self, ev));
- });
-
- // when we try to consume some more bytes, simply unpause the
- // underlying stream.
- self._read = function(n) {
- debug('wrapped _read', n);
- if (paused) {
- paused = false;
- stream.resume();
- }
- };
-
- return self;
-};
-
-
-// exposed for testing purposes only.
-Readable._fromList = fromList;
-
-// Pluck off n bytes from an array of buffers.
-// Length is the combined lengths of all the buffers in the list.
-function fromList(n, state) {
- var list = state.buffer;
- var length = state.length;
- var stringMode = !!state.decoder;
- var objectMode = !!state.objectMode;
- var ret;
-
- // nothing in the list, definitely empty.
- if (list.length === 0)
- return null;
-
- if (length === 0)
- ret = null;
- else if (objectMode)
- ret = list.shift();
- else if (!n || n >= length) {
- // read it all, truncate the array.
- if (stringMode)
- ret = list.join('');
- else if (list.length === 1)
- ret = list[0];
- else
- ret = Buffer.concat(list, length);
- list.length = 0;
- } else {
- // read just some of it.
- if (n < list[0].length) {
- // just take a part of the first list item.
- // slice is the same for buffers and strings.
- var buf = list[0];
- ret = buf.slice(0, n);
- list[0] = buf.slice(n);
- } else if (n === list[0].length) {
- // first list is a perfect match
- ret = list.shift();
+CipherBase.prototype._transform = function (data, _, next) {
+ var err
+ try {
+ if (this.hashMode) {
+ this._update(data)
} else {
- // complex case.
- // we have enough to cover it, but it spans past the first buffer.
- if (stringMode)
- ret = '';
- else
- ret = new Buffer(n);
-
- var c = 0;
- for (var i = 0, l = list.length; i < l && c < n; i++) {
- var buf = list[0];
- var cpy = Math.min(n - c, buf.length);
-
- if (stringMode)
- ret += buf.slice(0, cpy);
- else
- buf.copy(ret, c, 0, cpy);
-
- if (cpy < buf.length)
- list[0] = buf.slice(cpy);
- else
- list.shift();
-
- c += cpy;
- }
+ this.push(this._update(data))
}
- }
-
- return ret;
-}
-
-function endReadable(stream) {
- var state = stream._readableState;
-
- // If we get here before consuming all the bytes, then that is a
- // bug in node. Should never happen.
- if (state.length > 0)
- throw new Error('endReadable called on non-empty stream');
-
- if (!state.endEmitted) {
- state.ended = true;
- processNextTick(endReadableNT, state, stream);
+ } catch (e) {
+ err = e
+ } finally {
+ next(err)
}
}
-
-function endReadableNT(state, stream) {
- // Check that we didn't get one last unshift.
- if (!state.endEmitted && state.length === 0) {
- state.endEmitted = true;
- stream.readable = false;
- stream.emit('end');
+CipherBase.prototype._flush = function (done) {
+ var err
+ try {
+ this.push(this._final())
+ } catch (e) {
+ err = e
+ } finally {
+ done(err)
}
}
-
-function forEach (xs, f) {
- for (var i = 0, l = xs.length; i < l; i++) {
- f(xs[i], i);
+CipherBase.prototype._finalOrDigest = function (outputEnc) {
+ var outData = this._final() || new Buffer('')
+ if (outputEnc) {
+ outData = this._toString(outData, outputEnc, true)
}
+ return outData
}
-function indexOf (xs, x) {
- for (var i = 0, l = xs.length; i < l; i++) {
- if (xs[i] === x) return i;
+CipherBase.prototype._toString = function (value, enc, fin) {
+ if (!this._decoder) {
+ this._decoder = new StringDecoder(enc)
+ this._encoding = enc
}
- return -1;
-}
-
-}).call(this,require('_process'))
-},{"./_stream_duplex":13,"_process":10,"buffer":2,"core-util-is":18,"events":6,"inherits":7,"isarray":9,"process-nextick-args":19,"string_decoder/":26,"util":1}],16:[function(require,module,exports){
-// a transform stream is a readable/writable stream where you do
-// something with the data. Sometimes it's called a "filter",
-// but that's not a great name for it, since that implies a thing where
-// some bits pass through, and others are simply ignored. (That would
-// be a valid example of a transform, of course.)
-//
-// While the output is causally related to the input, it's not a
-// necessarily symmetric or synchronous transformation. For example,
-// a zlib stream might take multiple plain-text writes(), and then
-// emit a single compressed chunk some time in the future.
-//
-// Here's how this works:
-//
-// The Transform stream has all the aspects of the readable and writable
-// stream classes. When you write(chunk), that calls _write(chunk,cb)
-// internally, and returns false if there's a lot of pending writes
-// buffered up. When you call read(), that calls _read(n) until
-// there's enough pending readable data buffered up.
-//
-// In a transform stream, the written data is placed in a buffer. When
-// _read(n) is called, it transforms the queued up data, calling the
-// buffered _write cb's as it consumes chunks. If consuming a single
-// written chunk would result in multiple output chunks, then the first
-// outputted bit calls the readcb, and subsequent chunks just go into
-// the read buffer, and will cause it to emit 'readable' if necessary.
-//
-// This way, back-pressure is actually determined by the reading side,
-// since _read has to be called to start processing a new chunk. However,
-// a pathological inflate type of transform can cause excessive buffering
-// here. For example, imagine a stream where every byte of input is
-// interpreted as an integer from 0-255, and then results in that many
-// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in
-// 1kb of data being output. In this case, you could write a very small
-// amount of input, and end up with a very large amount of output. In
-// such a pathological inflating mechanism, there'd be no way to tell
-// the system to stop doing the transform. A single 4MB write could
-// cause the system to run out of memory.
-//
-// However, even in such a pathological case, only a single written chunk
-// would be consumed, and then the rest would wait (un-transformed) until
-// the results of the previous transformed chunk were consumed.
-
-'use strict';
-
-module.exports = Transform;
-
-var Duplex = require('./_stream_duplex');
-
-/*<replacement>*/
-var util = require('core-util-is');
-util.inherits = require('inherits');
-/*</replacement>*/
-
-util.inherits(Transform, Duplex);
-
-
-function TransformState(stream) {
- this.afterTransform = function(er, data) {
- return afterTransform(stream, er, data);
- };
-
- this.needTransform = false;
- this.transforming = false;
- this.writecb = null;
- this.writechunk = null;
-}
-
-function afterTransform(stream, er, data) {
- var ts = stream._transformState;
- ts.transforming = false;
-
- var cb = ts.writecb;
-
- if (!cb)
- return stream.emit('error', new Error('no writecb in Transform class'));
-
- ts.writechunk = null;
- ts.writecb = null;
-
- if (data !== null && data !== undefined)
- stream.push(data);
-
- if (cb)
- cb(er);
-
- var rs = stream._readableState;
- rs.reading = false;
- if (rs.needReadable || rs.length < rs.highWaterMark) {
- stream._read(rs.highWaterMark);
+ if (this._encoding !== enc) {
+ throw new Error('can\'t switch encodings')
}
-}
-
-
-function Transform(options) {
- if (!(this instanceof Transform))
- return new Transform(options);
-
- Duplex.call(this, options);
-
- this._transformState = new TransformState(this);
-
- // when the writable side finishes, then flush out anything remaining.
- var stream = this;
-
- // start out asking for a readable event once data is transformed.
- this._readableState.needReadable = true;
-
- // we have implemented the _read method, and done the other things
- // that Readable wants before the first _read call, so unset the
- // sync guard flag.
- this._readableState.sync = false;
-
- if (options) {
- if (typeof options.transform === 'function')
- this._transform = options.transform;
-
- if (typeof options.flush === 'function')
- this._flush = options.flush;
+ var out = this._decoder.write(value)
+ if (fin) {
+ out += this._decoder.end()
}
-
- this.once('prefinish', function() {
- if (typeof this._flush === 'function')
- this._flush(function(er) {
- done(stream, er);
- });
- else
- done(stream);
- });
+ return out
}
-Transform.prototype.push = function(chunk, encoding) {
- this._transformState.needTransform = false;
- return Duplex.prototype.push.call(this, chunk, encoding);
-};
-
-// This is the part where you do stuff!
-// override this function in implementation classes.
-// 'chunk' is an input chunk.
-//
-// Call `push(newChunk)` to pass along transformed output
-// to the readable side. You may call 'push' zero or more times.
-//
-// Call `cb(err)` when you are done with this chunk. If you pass
-// an error, then that'll put the hurt on the whole operation. If you
-// never call cb(), then you'll never get another chunk.
-Transform.prototype._transform = function(chunk, encoding, cb) {
- throw new Error('not implemented');
+}).call(this,require("buffer").Buffer)
+},{"buffer":6,"inherits":45,"stream":182,"string_decoder":183}],8:[function(require,module,exports){
+require('../../modules/es6.object.assign');
+module.exports = require('../../modules/$.core').Object.assign;
+},{"../../modules/$.core":11,"../../modules/es6.object.assign":21}],9:[function(require,module,exports){
+module.exports = function(it){
+ if(typeof it != 'function')throw TypeError(it + ' is not a function!');
+ return it;
};
+},{}],10:[function(require,module,exports){
+var toString = {}.toString;
-Transform.prototype._write = function(chunk, encoding, cb) {
- var ts = this._transformState;
- ts.writecb = cb;
- ts.writechunk = chunk;
- ts.writeencoding = encoding;
- if (!ts.transforming) {
- var rs = this._readableState;
- if (ts.needTransform ||
- rs.needReadable ||
- rs.length < rs.highWaterMark)
- this._read(rs.highWaterMark);
- }
+module.exports = function(it){
+ return toString.call(it).slice(8, -1);
};
-
-// Doesn't matter what the args are here.
-// _transform does all the work.
-// That we got here means that the readable side wants more data.
-Transform.prototype._read = function(n) {
- var ts = this._transformState;
-
- if (ts.writechunk !== null && ts.writecb && !ts.transforming) {
- ts.transforming = true;
- this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);
- } else {
- // mark that we need a transform, so that any data that comes in
- // will get processed, now that we've asked for it.
- ts.needTransform = true;
+},{}],11:[function(require,module,exports){
+var core = module.exports = {version: '1.2.6'};
+if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef
+},{}],12:[function(require,module,exports){
+// optional / simple context binding
+var aFunction = require('./$.a-function');
+module.exports = function(fn, that, length){
+ aFunction(fn);
+ if(that === undefined)return fn;
+ switch(length){
+ case 1: return function(a){
+ return fn.call(that, a);
+ };
+ case 2: return function(a, b){
+ return fn.call(that, a, b);
+ };
+ case 3: return function(a, b, c){
+ return fn.call(that, a, b, c);
+ };
}
-};
-
-
-function done(stream, er) {
- if (er)
- return stream.emit('error', er);
-
- // if there's nothing in the write buffer, then that means
- // that nothing more will ever be provided
- var ws = stream._writableState;
- var ts = stream._transformState;
-
- if (ws.length)
- throw new Error('calling transform done when ws.length != 0');
-
- if (ts.transforming)
- throw new Error('calling transform done when still transforming');
-
- return stream.push(null);
-}
-
-},{"./_stream_duplex":13,"core-util-is":18,"inherits":7}],17:[function(require,module,exports){
-// A bit simpler than readable streams.
-// Implement an async ._write(chunk, encoding, cb), and it'll handle all
-// the drain event emission and buffering.
-
-'use strict';
-
-module.exports = Writable;
-
-/*<replacement>*/
-var processNextTick = require('process-nextick-args');
-/*</replacement>*/
-
-
-/*<replacement>*/
-var Buffer = require('buffer').Buffer;
-/*</replacement>*/
-
-Writable.WritableState = WritableState;
-
-
-/*<replacement>*/
-var util = require('core-util-is');
-util.inherits = require('inherits');
-/*</replacement>*/
-
-
-/*<replacement>*/
-var internalUtil = {
- deprecate: require('util-deprecate')
-};
-/*</replacement>*/
-
-
-
-/*<replacement>*/
-var Stream;
-(function (){try{
- Stream = require('st' + 'ream');
-}catch(_){}finally{
- if (!Stream)
- Stream = require('events').EventEmitter;
-}}())
-/*</replacement>*/
-
-var Buffer = require('buffer').Buffer;
-
-util.inherits(Writable, Stream);
-
-function nop() {}
-
-function WriteReq(chunk, encoding, cb) {
- this.chunk = chunk;
- this.encoding = encoding;
- this.callback = cb;
- this.next = null;
-}
-
-function WritableState(options, stream) {
- var Duplex = require('./_stream_duplex');
-
- options = options || {};
-
- // object stream flag to indicate whether or not this stream
- // contains buffers or objects.
- this.objectMode = !!options.objectMode;
-
- if (stream instanceof Duplex)
- this.objectMode = this.objectMode || !!options.writableObjectMode;
-
- // the point at which write() starts returning false
- // Note: 0 is a valid value, means that we always return false if
- // the entire buffer is not flushed immediately on write()
- var hwm = options.highWaterMark;
- var defaultHwm = this.objectMode ? 16 : 16 * 1024;
- this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm;
-
- // cast to ints.
- this.highWaterMark = ~~this.highWaterMark;
-
- this.needDrain = false;
- // at the start of calling end()
- this.ending = false;
- // when end() has been called, and returned
- this.ended = false;
- // when 'finish' is emitted
- this.finished = false;
-
- // should we decode strings into buffers before passing to _write?
- // this is here so that some node-core streams can optimize string
- // handling at a lower level.
- var noDecode = options.decodeStrings === false;
- this.decodeStrings = !noDecode;
-
- // Crypto is kind of old and crusty. Historically, its default string
- // encoding is 'binary' so we have to make this configurable.
- // Everything else in the universe uses 'utf8', though.
- this.defaultEncoding = options.defaultEncoding || 'utf8';
-
- // not an actual buffer we keep track of, but a measurement
- // of how much we're waiting to get pushed to some underlying
- // socket or file.
- this.length = 0;
-
- // a flag to see when we're in the middle of a write.
- this.writing = false;
-
- // when true all writes will be buffered until .uncork() call
- this.corked = 0;
-
- // a flag to be able to tell if the onwrite cb is called immediately,
- // or on a later tick. We set this to true at first, because any
- // actions that shouldn't happen until "later" should generally also
- // not happen before the first write call.
- this.sync = true;
-
- // a flag to know if we're processing previously buffered items, which
- // may call the _write() callback in the same tick, so that we don't
- // end up in an overlapped onwrite situation.
- this.bufferProcessing = false;
-
- // the callback that's passed to _write(chunk,cb)
- this.onwrite = function(er) {
- onwrite(stream, er);
+ return function(/* ...args */){
+ return fn.apply(that, arguments);
};
-
- // the callback that the user supplies to write(chunk,encoding,cb)
- this.writecb = null;
-
- // the amount that is being written when _write is called.
- this.writelen = 0;
-
- this.bufferedRequest = null;
- this.lastBufferedRequest = null;
-
- // number of pending user-supplied write callbacks
- // this must be 0 before 'finish' can be emitted
- this.pendingcb = 0;
-
- // emit prefinish if the only thing we're waiting for is _write cbs
- // This is relevant for synchronous Transform streams
- this.prefinished = false;
-
- // True if the error was already emitted and should not be thrown again
- this.errorEmitted = false;
-}
-
-WritableState.prototype.getBuffer = function writableStateGetBuffer() {
- var current = this.bufferedRequest;
- var out = [];
- while (current) {
- out.push(current);
- current = current.next;
- }
- return out;
};
-
-(function (){try {
-Object.defineProperty(WritableState.prototype, 'buffer', {
- get: internalUtil.deprecate(function() {
- return this.getBuffer();
- }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' +
- 'instead.')
-});
-}catch(_){}}());
-
-
-function Writable(options) {
- var Duplex = require('./_stream_duplex');
-
- // Writable ctor is applied to Duplexes, though they're not
- // instanceof Writable, they're instanceof Readable.
- if (!(this instanceof Writable) && !(this instanceof Duplex))
- return new Writable(options);
-
- this._writableState = new WritableState(options, this);
-
- // legacy.
- this.writable = true;
-
- if (options) {
- if (typeof options.write === 'function')
- this._write = options.write;
-
- if (typeof options.writev === 'function')
- this._writev = options.writev;
- }
-
- Stream.call(this);
-}
-
-// Otherwise people can pipe Writable streams, which is just wrong.
-Writable.prototype.pipe = function() {
- this.emit('error', new Error('Cannot pipe. Not readable.'));
+},{"./$.a-function":9}],13:[function(require,module,exports){
+// 7.2.1 RequireObjectCoercible(argument)
+module.exports = function(it){
+ if(it == undefined)throw TypeError("Can't call method on " + it);
+ return it;
};
+},{}],14:[function(require,module,exports){
+var global = require('./$.global')
+ , core = require('./$.core')
+ , ctx = require('./$.ctx')
+ , PROTOTYPE = 'prototype';
-
-function writeAfterEnd(stream, cb) {
- var er = new Error('write after end');
- // TODO: defer error events consistently everywhere, not just the cb
- stream.emit('error', er);
- processNextTick(cb, er);
-}
-
-// If we get something that is not a buffer, string, null, or undefined,
-// and we're not in objectMode, then that's an error.
-// Otherwise stream chunks are all considered to be of length=1, and the
-// watermarks determine how many objects to keep in the buffer, rather than
-// how many bytes or characters.
-function validChunk(stream, state, chunk, cb) {
- var valid = true;
-
- if (!(Buffer.isBuffer(chunk)) &&
- typeof chunk !== 'string' &&
- chunk !== null &&
- chunk !== undefined &&
- !state.objectMode) {
- var er = new TypeError('Invalid non-string/buffer chunk');
- stream.emit('error', er);
- processNextTick(cb, er);
- valid = false;
- }
- return valid;
-}
-
-Writable.prototype.write = function(chunk, encoding, cb) {
- var state = this._writableState;
- var ret = false;
-
- if (typeof encoding === 'function') {
- cb = encoding;
- encoding = null;
- }
-
- if (Buffer.isBuffer(chunk))
- encoding = 'buffer';
- else if (!encoding)
- encoding = state.defaultEncoding;
-
- if (typeof cb !== 'function')
- cb = nop;
-
- if (state.ended)
- writeAfterEnd(this, cb);
- else if (validChunk(this, state, chunk, cb)) {
- state.pendingcb++;
- ret = writeOrBuffer(this, state, chunk, encoding, cb);
+var $export = function(type, name, source){
+ var IS_FORCED = type & $export.F
+ , IS_GLOBAL = type & $export.G
+ , IS_STATIC = type & $export.S
+ , IS_PROTO = type & $export.P
+ , IS_BIND = type & $export.B
+ , IS_WRAP = type & $export.W
+ , exports = IS_GLOBAL ? core : core[name] || (core[name] = {})
+ , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE]
+ , key, own, out;
+ if(IS_GLOBAL)source = name;
+ for(key in source){
+ // contains in native
+ own = !IS_FORCED && target && key in target;
+ if(own && key in exports)continue;
+ // export native or passed
+ out = own ? target[key] : source[key];
+ // prevent global pollution for namespaces
+ exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key]
+ // bind timers to global for call from export context
+ : IS_BIND && own ? ctx(out, global)
+ // wrap global constructors for prevent change them in library
+ : IS_WRAP && target[key] == out ? (function(C){
+ var F = function(param){
+ return this instanceof C ? new C(param) : C(param);
+ };
+ F[PROTOTYPE] = C[PROTOTYPE];
+ return F;
+ // make static versions for prototype methods
+ })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;
+ if(IS_PROTO)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out;
}
-
- return ret;
};
-
-Writable.prototype.cork = function() {
- var state = this._writableState;
-
- state.corked++;
-};
-
-Writable.prototype.uncork = function() {
- var state = this._writableState;
-
- if (state.corked) {
- state.corked--;
-
- if (!state.writing &&
- !state.corked &&
- !state.finished &&
- !state.bufferProcessing &&
- state.bufferedRequest)
- clearBuffer(this, state);
+// type bitmap
+$export.F = 1; // forced
+$export.G = 2; // global
+$export.S = 4; // static
+$export.P = 8; // proto
+$export.B = 16; // bind
+$export.W = 32; // wrap
+module.exports = $export;
+},{"./$.core":11,"./$.ctx":12,"./$.global":16}],15:[function(require,module,exports){
+module.exports = function(exec){
+ try {
+ return !!exec();
+ } catch(e){
+ return true;
}
};
-
-Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
- // node::ParseEncoding() requires lower case.
- if (typeof encoding === 'string')
- encoding = encoding.toLowerCase();
- if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64',
-'ucs2', 'ucs-2','utf16le', 'utf-16le', 'raw']
-.indexOf((encoding + '').toLowerCase()) > -1))
- throw new TypeError('Unknown encoding: ' + encoding);
- this._writableState.defaultEncoding = encoding;
+},{}],16:[function(require,module,exports){
+// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
+var global = module.exports = typeof window != 'undefined' && window.Math == Math
+ ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')();
+if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef
+},{}],17:[function(require,module,exports){
+// fallback for non-array-like ES3 and non-enumerable old V8 strings
+var cof = require('./$.cof');
+module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){
+ return cof(it) == 'String' ? it.split('') : Object(it);
};
-
-function decodeChunk(state, chunk, encoding) {
- if (!state.objectMode &&
- state.decodeStrings !== false &&
- typeof chunk === 'string') {
- chunk = new Buffer(chunk, encoding);
- }
- return chunk;
-}
-
-// if we're already writing something, then just put this
-// in the queue, and wait our turn. Otherwise, call _write
-// If we return false, then we need a drain event, so set that flag.
-function writeOrBuffer(stream, state, chunk, encoding, cb) {
- chunk = decodeChunk(state, chunk, encoding);
-
- if (Buffer.isBuffer(chunk))
- encoding = 'buffer';
- var len = state.objectMode ? 1 : chunk.length;
-
- state.length += len;
-
- var ret = state.length < state.highWaterMark;
- // we must ensure that previous needDrain will not be reset to false.
- if (!ret)
- state.needDrain = true;
-
- if (state.writing || state.corked) {
- var last = state.lastBufferedRequest;
- state.lastBufferedRequest = new WriteReq(chunk, encoding, cb);
- if (last) {
- last.next = state.lastBufferedRequest;
- } else {
- state.bufferedRequest = state.lastBufferedRequest;
- }
- } else {
- doWrite(stream, state, false, len, chunk, encoding, cb);
- }
-
- return ret;
-}
-
-function doWrite(stream, state, writev, len, chunk, encoding, cb) {
- state.writelen = len;
- state.writecb = cb;
- state.writing = true;
- state.sync = true;
- if (writev)
- stream._writev(chunk, state.onwrite);
- else
- stream._write(chunk, encoding, state.onwrite);
- state.sync = false;
-}
-
-function onwriteError(stream, state, sync, er, cb) {
- --state.pendingcb;
- if (sync)
- processNextTick(cb, er);
- else
- cb(er);
-
- stream._writableState.errorEmitted = true;
- stream.emit('error', er);
-}
-
-function onwriteStateUpdate(state) {
- state.writing = false;
- state.writecb = null;
- state.length -= state.writelen;
- state.writelen = 0;
-}
-
-function onwrite(stream, er) {
- var state = stream._writableState;
- var sync = state.sync;
- var cb = state.writecb;
-
- onwriteStateUpdate(state);
-
- if (er)
- onwriteError(stream, state, sync, er, cb);
- else {
- // Check if we're actually ready to finish, but don't emit yet
- var finished = needFinish(state);
-
- if (!finished &&
- !state.corked &&
- !state.bufferProcessing &&
- state.bufferedRequest) {
- clearBuffer(stream, state);
- }
-
- if (sync) {
- processNextTick(afterWrite, stream, state, finished, cb);
- } else {
- afterWrite(stream, state, finished, cb);
- }
- }
-}
-
-function afterWrite(stream, state, finished, cb) {
- if (!finished)
- onwriteDrain(stream, state);
- state.pendingcb--;
- cb();
- finishMaybe(stream, state);
-}
-
-// Must force callback to be called on nextTick, so that we don't
-// emit 'drain' before the write() consumer gets the 'false' return
-// value, and has a chance to attach a 'drain' listener.
-function onwriteDrain(stream, state) {
- if (state.length === 0 && state.needDrain) {
- state.needDrain = false;
- stream.emit('drain');
- }
-}
-
-
-// if there's something in the buffer waiting, then process it
-function clearBuffer(stream, state) {
- state.bufferProcessing = true;
- var entry = state.bufferedRequest;
-
- if (stream._writev && entry && entry.next) {
- // Fast case, write everything using _writev()
- var buffer = [];
- var cbs = [];
- while (entry) {
- cbs.push(entry.callback);
- buffer.push(entry);
- entry = entry.next;
- }
-
- // count the one we are adding, as well.
- // TODO(isaacs) clean this up
- state.pendingcb++;
- state.lastBufferedRequest = null;
- doWrite(stream, state, true, state.length, buffer, '', function(err) {
- for (var i = 0; i < cbs.length; i++) {
- state.pendingcb--;
- cbs[i](err);
- }
- });
-
- // Clear buffer
- } else {
- // Slow case, write chunks one-by-one
- while (entry) {
- var chunk = entry.chunk;
- var encoding = entry.encoding;
- var cb = entry.callback;
- var len = state.objectMode ? 1 : chunk.length;
-
- doWrite(stream, state, false, len, chunk, encoding, cb);
- entry = entry.next;
- // if we didn't call the onwrite immediately, then
- // it means that we need to wait until it does.
- // also, that means that the chunk and cb are currently
- // being processed, so move the buffer counter past them.
- if (state.writing) {
- break;
- }
- }
-
- if (entry === null)
- state.lastBufferedRequest = null;
- }
- state.bufferedRequest = entry;
- state.bufferProcessing = false;
-}
-
-Writable.prototype._write = function(chunk, encoding, cb) {
- cb(new Error('not implemented'));
+},{"./$.cof":10}],18:[function(require,module,exports){
+var $Object = Object;
+module.exports = {
+ create: $Object.create,
+ getProto: $Object.getPrototypeOf,
+ isEnum: {}.propertyIsEnumerable,
+ getDesc: $Object.getOwnPropertyDescriptor,
+ setDesc: $Object.defineProperty,
+ setDescs: $Object.defineProperties,
+ getKeys: $Object.keys,
+ getNames: $Object.getOwnPropertyNames,
+ getSymbols: $Object.getOwnPropertySymbols,
+ each: [].forEach
};
+},{}],19:[function(require,module,exports){
+// 19.1.2.1 Object.assign(target, source, ...)
+var $ = require('./$')
+ , toObject = require('./$.to-object')
+ , IObject = require('./$.iobject');
-Writable.prototype._writev = null;
-
-Writable.prototype.end = function(chunk, encoding, cb) {
- var state = this._writableState;
-
- if (typeof chunk === 'function') {
- cb = chunk;
- chunk = null;
- encoding = null;
- } else if (typeof encoding === 'function') {
- cb = encoding;
- encoding = null;
- }
-
- if (chunk !== null && chunk !== undefined)
- this.write(chunk, encoding);
-
- // .end() fully uncorks
- if (state.corked) {
- state.corked = 1;
- this.uncork();
+// should work with symbols and should have deterministic property order (V8 bug)
+module.exports = require('./$.fails')(function(){
+ var a = Object.assign
+ , A = {}
+ , B = {}
+ , S = Symbol()
+ , K = 'abcdefghijklmnopqrst';
+ A[S] = 7;
+ K.split('').forEach(function(k){ B[k] = k; });
+ return a({}, A)[S] != 7 || Object.keys(a({}, B)).join('') != K;
+}) ? function assign(target, source){ // eslint-disable-line no-unused-vars
+ var T = toObject(target)
+ , $$ = arguments
+ , $$len = $$.length
+ , index = 1
+ , getKeys = $.getKeys
+ , getSymbols = $.getSymbols
+ , isEnum = $.isEnum;
+ while($$len > index){
+ var S = IObject($$[index++])
+ , keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S)
+ , length = keys.length
+ , j = 0
+ , key;
+ while(length > j)if(isEnum.call(S, key = keys[j++]))T[key] = S[key];
}
-
- // ignore unnecessary end() calls.
- if (!state.ending && !state.finished)
- endWritable(this, state, cb);
+ return T;
+} : Object.assign;
+},{"./$":18,"./$.fails":15,"./$.iobject":17,"./$.to-object":20}],20:[function(require,module,exports){
+// 7.1.13 ToObject(argument)
+var defined = require('./$.defined');
+module.exports = function(it){
+ return Object(defined(it));
};
+},{"./$.defined":13}],21:[function(require,module,exports){
+// 19.1.3.1 Object.assign(target, source)
+var $export = require('./$.export');
-
-function needFinish(state) {
- return (state.ending &&
- state.length === 0 &&
- state.bufferedRequest === null &&
- !state.finished &&
- !state.writing);
-}
-
-function prefinish(stream, state) {
- if (!state.prefinished) {
- state.prefinished = true;
- stream.emit('prefinish');
- }
-}
-
-function finishMaybe(stream, state) {
- var need = needFinish(state);
- if (need) {
- if (state.pendingcb === 0) {
- prefinish(stream, state);
- state.finished = true;
- stream.emit('finish');
- } else {
- prefinish(stream, state);
- }
- }
- return need;
-}
-
-function endWritable(stream, state, cb) {
- state.ending = true;
- finishMaybe(stream, state);
- if (cb) {
- if (state.finished)
- processNextTick(cb);
- else
- stream.once('finish', cb);
- }
- state.ended = true;
-}
-
-},{"./_stream_duplex":13,"buffer":2,"core-util-is":18,"events":6,"inherits":7,"process-nextick-args":19,"util-deprecate":20}],18:[function(require,module,exports){
+$export($export.S + $export.F, 'Object', {assign: require('./$.object-assign')});
+},{"./$.export":14,"./$.object-assign":19}],22:[function(require,module,exports){
(function (Buffer){
// Copyright Joyent, Inc. and other Node contributors.
//
@@ -4633,1014 +2334,12 @@ function endWritable(stream, state, cb) {
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
-function isArray(ar) {
- return Array.isArray(ar);
-}
-exports.isArray = isArray;
-
-function isBoolean(arg) {
- return typeof arg === 'boolean';
-}
-exports.isBoolean = isBoolean;
-
-function isNull(arg) {
- return arg === null;
-}
-exports.isNull = isNull;
-
-function isNullOrUndefined(arg) {
- return arg == null;
-}
-exports.isNullOrUndefined = isNullOrUndefined;
-
-function isNumber(arg) {
- return typeof arg === 'number';
-}
-exports.isNumber = isNumber;
-
-function isString(arg) {
- return typeof arg === 'string';
-}
-exports.isString = isString;
-
-function isSymbol(arg) {
- return typeof arg === 'symbol';
-}
-exports.isSymbol = isSymbol;
-function isUndefined(arg) {
- return arg === void 0;
-}
-exports.isUndefined = isUndefined;
-
-function isRegExp(re) {
- return isObject(re) && objectToString(re) === '[object RegExp]';
-}
-exports.isRegExp = isRegExp;
-
-function isObject(arg) {
- return typeof arg === 'object' && arg !== null;
-}
-exports.isObject = isObject;
-
-function isDate(d) {
- return isObject(d) && objectToString(d) === '[object Date]';
-}
-exports.isDate = isDate;
-
-function isError(e) {
- return isObject(e) &&
- (objectToString(e) === '[object Error]' || e instanceof Error);
-}
-exports.isError = isError;
-
-function isFunction(arg) {
- return typeof arg === 'function';
-}
-exports.isFunction = isFunction;
-
-function isPrimitive(arg) {
- return arg === null ||
- typeof arg === 'boolean' ||
- typeof arg === 'number' ||
- typeof arg === 'string' ||
- typeof arg === 'symbol' || // ES6 symbol
- typeof arg === 'undefined';
-}
-exports.isPrimitive = isPrimitive;
-
-function isBuffer(arg) {
- return Buffer.isBuffer(arg);
-}
-exports.isBuffer = isBuffer;
-
-function objectToString(o) {
- return Object.prototype.toString.call(o);
-}
-}).call(this,{"isBuffer":require("../../../../insert-module-globals/node_modules/is-buffer/index.js")})
-},{"../../../../insert-module-globals/node_modules/is-buffer/index.js":8}],19:[function(require,module,exports){
-(function (process){
-'use strict';
-module.exports = nextTick;
-
-function nextTick(fn) {
- var args = new Array(arguments.length - 1);
- var i = 0;
- while (i < args.length) {
- args[i++] = arguments[i];
- }
- process.nextTick(function afterTick() {
- fn.apply(null, args);
- });
-}
-
-}).call(this,require('_process'))
-},{"_process":10}],20:[function(require,module,exports){
-(function (global){
-
-/**
- * Module exports.
- */
-
-module.exports = deprecate;
-
-/**
- * Mark that a method should not be used.
- * Returns a modified function which warns once by default.
- *
- * If `localStorage.noDeprecation = true` is set, then it is a no-op.
- *
- * If `localStorage.throwDeprecation = true` is set, then deprecated functions
- * will throw an Error when invoked.
- *
- * If `localStorage.traceDeprecation = true` is set, then deprecated functions
- * will invoke `console.trace()` instead of `console.error()`.
- *
- * @param {Function} fn - the function to deprecate
- * @param {String} msg - the string to print to the console when `fn` is invoked
- * @returns {Function} a new "deprecated" version of `fn`
- * @api public
- */
-
-function deprecate (fn, msg) {
- if (config('noDeprecation')) {
- return fn;
- }
-
- var warned = false;
- function deprecated() {
- if (!warned) {
- if (config('throwDeprecation')) {
- throw new Error(msg);
- } else if (config('traceDeprecation')) {
- console.trace(msg);
- } else {
- console.warn(msg);
- }
- warned = true;
- }
- return fn.apply(this, arguments);
- }
-
- return deprecated;
-}
-
-/**
- * Checks `localStorage` for boolean values for the given `name`.
- *
- * @param {String} name
- * @returns {Boolean}
- * @api private
- */
-
-function config (name) {
- // accessing global.localStorage can trigger a DOMException in sandboxed iframes
- try {
- if (!global.localStorage) return false;
- } catch (_) {
- return false;
- }
- var val = global.localStorage[name];
- if (null == val) return false;
- return String(val).toLowerCase() === 'true';
-}
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],21:[function(require,module,exports){
-module.exports = require("./lib/_stream_passthrough.js")
-
-},{"./lib/_stream_passthrough.js":14}],22:[function(require,module,exports){
-var Stream = (function (){
- try {
- return require('st' + 'ream'); // hack to fix a circular dependency issue when used with browserify
- } catch(_){}
-}());
-exports = module.exports = require('./lib/_stream_readable.js');
-exports.Stream = Stream || exports;
-exports.Readable = exports;
-exports.Writable = require('./lib/_stream_writable.js');
-exports.Duplex = require('./lib/_stream_duplex.js');
-exports.Transform = require('./lib/_stream_transform.js');
-exports.PassThrough = require('./lib/_stream_passthrough.js');
-
-},{"./lib/_stream_duplex.js":13,"./lib/_stream_passthrough.js":14,"./lib/_stream_readable.js":15,"./lib/_stream_transform.js":16,"./lib/_stream_writable.js":17}],23:[function(require,module,exports){
-module.exports = require("./lib/_stream_transform.js")
-
-},{"./lib/_stream_transform.js":16}],24:[function(require,module,exports){
-module.exports = require("./lib/_stream_writable.js")
-
-},{"./lib/_stream_writable.js":17}],25:[function(require,module,exports){
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-module.exports = Stream;
-
-var EE = require('events').EventEmitter;
-var inherits = require('inherits');
-
-inherits(Stream, EE);
-Stream.Readable = require('readable-stream/readable.js');
-Stream.Writable = require('readable-stream/writable.js');
-Stream.Duplex = require('readable-stream/duplex.js');
-Stream.Transform = require('readable-stream/transform.js');
-Stream.PassThrough = require('readable-stream/passthrough.js');
-
-// Backwards-compat with node 0.4.x
-Stream.Stream = Stream;
-
-
-
-// old-style streams. Note that the pipe method (the only relevant
-// part of this class) is overridden in the Readable class.
-
-function Stream() {
- EE.call(this);
-}
-
-Stream.prototype.pipe = function(dest, options) {
- var source = this;
-
- function ondata(chunk) {
- if (dest.writable) {
- if (false === dest.write(chunk) && source.pause) {
- source.pause();
- }
- }
- }
-
- source.on('data', ondata);
-
- function ondrain() {
- if (source.readable && source.resume) {
- source.resume();
- }
- }
-
- dest.on('drain', ondrain);
-
- // If the 'end' option is not supplied, dest.end() will be called when
- // source gets the 'end' or 'close' events. Only dest.end() once.
- if (!dest._isStdio && (!options || options.end !== false)) {
- source.on('end', onend);
- source.on('close', onclose);
- }
-
- var didOnEnd = false;
- function onend() {
- if (didOnEnd) return;
- didOnEnd = true;
-
- dest.end();
- }
-
-
- function onclose() {
- if (didOnEnd) return;
- didOnEnd = true;
-
- if (typeof dest.destroy === 'function') dest.destroy();
- }
-
- // don't leave dangling pipes when there are errors.
- function onerror(er) {
- cleanup();
- if (EE.listenerCount(this, 'error') === 0) {
- throw er; // Unhandled stream error in pipe.
- }
- }
-
- source.on('error', onerror);
- dest.on('error', onerror);
-
- // remove all the event listeners that were added.
- function cleanup() {
- source.removeListener('data', ondata);
- dest.removeListener('drain', ondrain);
-
- source.removeListener('end', onend);
- source.removeListener('close', onclose);
-
- source.removeListener('error', onerror);
- dest.removeListener('error', onerror);
-
- source.removeListener('end', cleanup);
- source.removeListener('close', cleanup);
-
- dest.removeListener('close', cleanup);
- }
-
- source.on('end', cleanup);
- source.on('close', cleanup);
-
- dest.on('close', cleanup);
-
- dest.emit('pipe', source);
-
- // Allow for unix-like usage: A.pipe(B).pipe(C)
- return dest;
-};
-
-},{"events":6,"inherits":7,"readable-stream/duplex.js":12,"readable-stream/passthrough.js":21,"readable-stream/readable.js":22,"readable-stream/transform.js":23,"readable-stream/writable.js":24}],26:[function(require,module,exports){
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var Buffer = require('buffer').Buffer;
-
-var isBufferEncoding = Buffer.isEncoding
- || function(encoding) {
- switch (encoding && encoding.toLowerCase()) {
- case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true;
- default: return false;
- }
- }
-
-
-function assertEncoding(encoding) {
- if (encoding && !isBufferEncoding(encoding)) {
- throw new Error('Unknown encoding: ' + encoding);
- }
-}
-
-// StringDecoder provides an interface for efficiently splitting a series of
-// buffers into a series of JS strings without breaking apart multi-byte
-// characters. CESU-8 is handled as part of the UTF-8 encoding.
-//
-// @TODO Handling all encodings inside a single object makes it very difficult
-// to reason about this code, so it should be split up in the future.
-// @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code
-// points as used by CESU-8.
-var StringDecoder = exports.StringDecoder = function(encoding) {
- this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, '');
- assertEncoding(encoding);
- switch (this.encoding) {
- case 'utf8':
- // CESU-8 represents each of Surrogate Pair by 3-bytes
- this.surrogateSize = 3;
- break;
- case 'ucs2':
- case 'utf16le':
- // UTF-16 represents each of Surrogate Pair by 2-bytes
- this.surrogateSize = 2;
- this.detectIncompleteChar = utf16DetectIncompleteChar;
- break;
- case 'base64':
- // Base-64 stores 3 bytes in 4 chars, and pads the remainder.
- this.surrogateSize = 3;
- this.detectIncompleteChar = base64DetectIncompleteChar;
- break;
- default:
- this.write = passThroughWrite;
- return;
- }
-
- // Enough space to store all bytes of a single character. UTF-8 needs 4
- // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate).
- this.charBuffer = new Buffer(6);
- // Number of bytes received for the current incomplete multi-byte character.
- this.charReceived = 0;
- // Number of bytes expected for the current incomplete multi-byte character.
- this.charLength = 0;
-};
-
-
-// write decodes the given buffer and returns it as JS string that is
-// guaranteed to not contain any partial multi-byte characters. Any partial
-// character found at the end of the buffer is buffered up, and will be
-// returned when calling write again with the remaining bytes.
-//
-// Note: Converting a Buffer containing an orphan surrogate to a String
-// currently works, but converting a String to a Buffer (via `new Buffer`, or
-// Buffer#write) will replace incomplete surrogates with the unicode
-// replacement character. See https://codereview.chromium.org/121173009/ .
-StringDecoder.prototype.write = function(buffer) {
- var charStr = '';
- // if our last write ended with an incomplete multibyte character
- while (this.charLength) {
- // determine how many remaining bytes this buffer has to offer for this char
- var available = (buffer.length >= this.charLength - this.charReceived) ?
- this.charLength - this.charReceived :
- buffer.length;
-
- // add the new bytes to the char buffer
- buffer.copy(this.charBuffer, this.charReceived, 0, available);
- this.charReceived += available;
-
- if (this.charReceived < this.charLength) {
- // still not enough chars in this buffer? wait for more ...
- return '';
- }
-
- // remove bytes belonging to the current character from the buffer
- buffer = buffer.slice(available, buffer.length);
-
- // get the character that was split
- charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding);
-
- // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character
- var charCode = charStr.charCodeAt(charStr.length - 1);
- if (charCode >= 0xD800 && charCode <= 0xDBFF) {
- this.charLength += this.surrogateSize;
- charStr = '';
- continue;
- }
- this.charReceived = this.charLength = 0;
-
- // if there are no more bytes in this buffer, just emit our char
- if (buffer.length === 0) {
- return charStr;
- }
- break;
- }
-
- // determine and set charLength / charReceived
- this.detectIncompleteChar(buffer);
-
- var end = buffer.length;
- if (this.charLength) {
- // buffer the incomplete character bytes we got
- buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end);
- end -= this.charReceived;
- }
-
- charStr += buffer.toString(this.encoding, 0, end);
-
- var end = charStr.length - 1;
- var charCode = charStr.charCodeAt(end);
- // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character
- if (charCode >= 0xD800 && charCode <= 0xDBFF) {
- var size = this.surrogateSize;
- this.charLength += size;
- this.charReceived += size;
- this.charBuffer.copy(this.charBuffer, size, 0, size);
- buffer.copy(this.charBuffer, 0, 0, size);
- return charStr.substring(0, end);
- }
-
- // or just emit the charStr
- return charStr;
-};
-
-// detectIncompleteChar determines if there is an incomplete UTF-8 character at
-// the end of the given buffer. If so, it sets this.charLength to the byte
-// length that character, and sets this.charReceived to the number of bytes
-// that are available for this character.
-StringDecoder.prototype.detectIncompleteChar = function(buffer) {
- // determine how many bytes we have to check at the end of this buffer
- var i = (buffer.length >= 3) ? 3 : buffer.length;
-
- // Figure out if one of the last i bytes of our buffer announces an
- // incomplete char.
- for (; i > 0; i--) {
- var c = buffer[buffer.length - i];
-
- // See http://en.wikipedia.org/wiki/UTF-8#Description
-
- // 110XXXXX
- if (i == 1 && c >> 5 == 0x06) {
- this.charLength = 2;
- break;
- }
-
- // 1110XXXX
- if (i <= 2 && c >> 4 == 0x0E) {
- this.charLength = 3;
- break;
- }
-
- // 11110XXX
- if (i <= 3 && c >> 3 == 0x1E) {
- this.charLength = 4;
- break;
- }
- }
- this.charReceived = i;
-};
-
-StringDecoder.prototype.end = function(buffer) {
- var res = '';
- if (buffer && buffer.length)
- res = this.write(buffer);
-
- if (this.charReceived) {
- var cr = this.charReceived;
- var buf = this.charBuffer;
- var enc = this.encoding;
- res += buf.slice(0, cr).toString(enc);
- }
-
- return res;
-};
-
-function passThroughWrite(buffer) {
- return buffer.toString(this.encoding);
-}
-
-function utf16DetectIncompleteChar(buffer) {
- this.charReceived = buffer.length % 2;
- this.charLength = this.charReceived ? 2 : 0;
-}
-
-function base64DetectIncompleteChar(buffer) {
- this.charReceived = buffer.length % 3;
- this.charLength = this.charReceived ? 3 : 0;
-}
-
-},{"buffer":2}],27:[function(require,module,exports){
-module.exports = function isBuffer(arg) {
- return arg && typeof arg === 'object'
- && typeof arg.copy === 'function'
- && typeof arg.fill === 'function'
- && typeof arg.readUInt8 === 'function';
-}
-},{}],28:[function(require,module,exports){
-(function (process,global){
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var formatRegExp = /%[sdj%]/g;
-exports.format = function(f) {
- if (!isString(f)) {
- var objects = [];
- for (var i = 0; i < arguments.length; i++) {
- objects.push(inspect(arguments[i]));
- }
- return objects.join(' ');
- }
-
- var i = 1;
- var args = arguments;
- var len = args.length;
- var str = String(f).replace(formatRegExp, function(x) {
- if (x === '%%') return '%';
- if (i >= len) return x;
- switch (x) {
- case '%s': return String(args[i++]);
- case '%d': return Number(args[i++]);
- case '%j':
- try {
- return JSON.stringify(args[i++]);
- } catch (_) {
- return '[Circular]';
- }
- default:
- return x;
- }
- });
- for (var x = args[i]; i < len; x = args[++i]) {
- if (isNull(x) || !isObject(x)) {
- str += ' ' + x;
- } else {
- str += ' ' + inspect(x);
- }
- }
- return str;
-};
-
-
-// Mark that a method should not be used.
-// Returns a modified function which warns once by default.
-// If --no-deprecation is set, then it is a no-op.
-exports.deprecate = function(fn, msg) {
- // Allow for deprecating things in the process of starting up.
- if (isUndefined(global.process)) {
- return function() {
- return exports.deprecate(fn, msg).apply(this, arguments);
- };
- }
-
- if (process.noDeprecation === true) {
- return fn;
- }
-
- var warned = false;
- function deprecated() {
- if (!warned) {
- if (process.throwDeprecation) {
- throw new Error(msg);
- } else if (process.traceDeprecation) {
- console.trace(msg);
- } else {
- console.error(msg);
- }
- warned = true;
- }
- return fn.apply(this, arguments);
- }
-
- return deprecated;
-};
-
-
-var debugs = {};
-var debugEnviron;
-exports.debuglog = function(set) {
- if (isUndefined(debugEnviron))
- debugEnviron = process.env.NODE_DEBUG || '';
- set = set.toUpperCase();
- if (!debugs[set]) {
- if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
- var pid = process.pid;
- debugs[set] = function() {
- var msg = exports.format.apply(exports, arguments);
- console.error('%s %d: %s', set, pid, msg);
- };
- } else {
- debugs[set] = function() {};
- }
- }
- return debugs[set];
-};
-
-
-/**
- * Echos the value of a value. Trys to print the value out
- * in the best way possible given the different types.
- *
- * @param {Object} obj The object to print out.
- * @param {Object} opts Optional options object that alters the output.
- */
-/* legacy: obj, showHidden, depth, colors*/
-function inspect(obj, opts) {
- // default options
- var ctx = {
- seen: [],
- stylize: stylizeNoColor
- };
- // legacy...
- if (arguments.length >= 3) ctx.depth = arguments[2];
- if (arguments.length >= 4) ctx.colors = arguments[3];
- if (isBoolean(opts)) {
- // legacy...
- ctx.showHidden = opts;
- } else if (opts) {
- // got an "options" object
- exports._extend(ctx, opts);
- }
- // set default options
- if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
- if (isUndefined(ctx.depth)) ctx.depth = 2;
- if (isUndefined(ctx.colors)) ctx.colors = false;
- if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
- if (ctx.colors) ctx.stylize = stylizeWithColor;
- return formatValue(ctx, obj, ctx.depth);
-}
-exports.inspect = inspect;
-
-
-// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
-inspect.colors = {
- 'bold' : [1, 22],
- 'italic' : [3, 23],
- 'underline' : [4, 24],
- 'inverse' : [7, 27],
- 'white' : [37, 39],
- 'grey' : [90, 39],
- 'black' : [30, 39],
- 'blue' : [34, 39],
- 'cyan' : [36, 39],
- 'green' : [32, 39],
- 'magenta' : [35, 39],
- 'red' : [31, 39],
- 'yellow' : [33, 39]
-};
-
-// Don't use 'blue' not visible on cmd.exe
-inspect.styles = {
- 'special': 'cyan',
- 'number': 'yellow',
- 'boolean': 'yellow',
- 'undefined': 'grey',
- 'null': 'bold',
- 'string': 'green',
- 'date': 'magenta',
- // "name": intentionally not styling
- 'regexp': 'red'
-};
-
-
-function stylizeWithColor(str, styleType) {
- var style = inspect.styles[styleType];
-
- if (style) {
- return '\u001b[' + inspect.colors[style][0] + 'm' + str +
- '\u001b[' + inspect.colors[style][1] + 'm';
- } else {
- return str;
- }
-}
-
-
-function stylizeNoColor(str, styleType) {
- return str;
-}
-
-
-function arrayToHash(array) {
- var hash = {};
-
- array.forEach(function(val, idx) {
- hash[val] = true;
- });
-
- return hash;
-}
-
-
-function formatValue(ctx, value, recurseTimes) {
- // Provide a hook for user-specified inspect functions.
- // Check that value is an object with an inspect function on it
- if (ctx.customInspect &&
- value &&
- isFunction(value.inspect) &&
- // Filter out the util module, it's inspect function is special
- value.inspect !== exports.inspect &&
- // Also filter out any prototype objects using the circular check.
- !(value.constructor && value.constructor.prototype === value)) {
- var ret = value.inspect(recurseTimes, ctx);
- if (!isString(ret)) {
- ret = formatValue(ctx, ret, recurseTimes);
- }
- return ret;
- }
-
- // Primitive types cannot have properties
- var primitive = formatPrimitive(ctx, value);
- if (primitive) {
- return primitive;
- }
-
- // Look up the keys of the object.
- var keys = Object.keys(value);
- var visibleKeys = arrayToHash(keys);
-
- if (ctx.showHidden) {
- keys = Object.getOwnPropertyNames(value);
- }
-
- // IE doesn't make error fields non-enumerable
- // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
- if (isError(value)
- && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
- return formatError(value);
- }
-
- // Some type of object without properties can be shortcutted.
- if (keys.length === 0) {
- if (isFunction(value)) {
- var name = value.name ? ': ' + value.name : '';
- return ctx.stylize('[Function' + name + ']', 'special');
- }
- if (isRegExp(value)) {
- return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
- }
- if (isDate(value)) {
- return ctx.stylize(Date.prototype.toString.call(value), 'date');
- }
- if (isError(value)) {
- return formatError(value);
- }
- }
-
- var base = '', array = false, braces = ['{', '}'];
-
- // Make Array say that they are Array
- if (isArray(value)) {
- array = true;
- braces = ['[', ']'];
- }
-
- // Make functions say that they are functions
- if (isFunction(value)) {
- var n = value.name ? ': ' + value.name : '';
- base = ' [Function' + n + ']';
- }
-
- // Make RegExps say that they are RegExps
- if (isRegExp(value)) {
- base = ' ' + RegExp.prototype.toString.call(value);
- }
-
- // Make dates with properties first say the date
- if (isDate(value)) {
- base = ' ' + Date.prototype.toUTCString.call(value);
- }
-
- // Make error with message first say the error
- if (isError(value)) {
- base = ' ' + formatError(value);
- }
-
- if (keys.length === 0 && (!array || value.length == 0)) {
- return braces[0] + base + braces[1];
- }
-
- if (recurseTimes < 0) {
- if (isRegExp(value)) {
- return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
- } else {
- return ctx.stylize('[Object]', 'special');
- }
- }
-
- ctx.seen.push(value);
-
- var output;
- if (array) {
- output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
- } else {
- output = keys.map(function(key) {
- return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
- });
- }
-
- ctx.seen.pop();
-
- return reduceToSingleString(output, base, braces);
-}
-
-
-function formatPrimitive(ctx, value) {
- if (isUndefined(value))
- return ctx.stylize('undefined', 'undefined');
- if (isString(value)) {
- var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
- .replace(/'/g, "\\'")
- .replace(/\\"/g, '"') + '\'';
- return ctx.stylize(simple, 'string');
- }
- if (isNumber(value))
- return ctx.stylize('' + value, 'number');
- if (isBoolean(value))
- return ctx.stylize('' + value, 'boolean');
- // For some reason typeof null is "object", so special case here.
- if (isNull(value))
- return ctx.stylize('null', 'null');
-}
-
-
-function formatError(value) {
- return '[' + Error.prototype.toString.call(value) + ']';
-}
-
-
-function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
- var output = [];
- for (var i = 0, l = value.length; i < l; ++i) {
- if (hasOwnProperty(value, String(i))) {
- output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
- String(i), true));
- } else {
- output.push('');
- }
- }
- keys.forEach(function(key) {
- if (!key.match(/^\d+$/)) {
- output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
- key, true));
- }
- });
- return output;
-}
-
-
-function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
- var name, str, desc;
- desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
- if (desc.get) {
- if (desc.set) {
- str = ctx.stylize('[Getter/Setter]', 'special');
- } else {
- str = ctx.stylize('[Getter]', 'special');
- }
- } else {
- if (desc.set) {
- str = ctx.stylize('[Setter]', 'special');
- }
- }
- if (!hasOwnProperty(visibleKeys, key)) {
- name = '[' + key + ']';
- }
- if (!str) {
- if (ctx.seen.indexOf(desc.value) < 0) {
- if (isNull(recurseTimes)) {
- str = formatValue(ctx, desc.value, null);
- } else {
- str = formatValue(ctx, desc.value, recurseTimes - 1);
- }
- if (str.indexOf('\n') > -1) {
- if (array) {
- str = str.split('\n').map(function(line) {
- return ' ' + line;
- }).join('\n').substr(2);
- } else {
- str = '\n' + str.split('\n').map(function(line) {
- return ' ' + line;
- }).join('\n');
- }
- }
- } else {
- str = ctx.stylize('[Circular]', 'special');
- }
- }
- if (isUndefined(name)) {
- if (array && key.match(/^\d+$/)) {
- return str;
- }
- name = JSON.stringify('' + key);
- if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
- name = name.substr(1, name.length - 2);
- name = ctx.stylize(name, 'name');
- } else {
- name = name.replace(/'/g, "\\'")
- .replace(/\\"/g, '"')
- .replace(/(^"|"$)/g, "'");
- name = ctx.stylize(name, 'string');
- }
- }
-
- return name + ': ' + str;
-}
-
-
-function reduceToSingleString(output, base, braces) {
- var numLinesEst = 0;
- var length = output.reduce(function(prev, cur) {
- numLinesEst++;
- if (cur.indexOf('\n') >= 0) numLinesEst++;
- return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
- }, 0);
-
- if (length > 60) {
- return braces[0] +
- (base === '' ? '' : base + '\n ') +
- ' ' +
- output.join(',\n ') +
- ' ' +
- braces[1];
+function isArray(arg) {
+ if (Array.isArray) {
+ return Array.isArray(arg);
}
-
- return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
-}
-
-
-// NOTE: These type checking functions intentionally don't use `instanceof`
-// because it is fragile and can be easily faked with `Object.create()`.
-function isArray(ar) {
- return Array.isArray(ar);
+ return objectToString(arg) === '[object Array]';
}
exports.isArray = isArray;
@@ -5680,7 +2379,7 @@ function isUndefined(arg) {
exports.isUndefined = isUndefined;
function isRegExp(re) {
- return isObject(re) && objectToString(re) === '[object RegExp]';
+ return objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
@@ -5690,13 +2389,12 @@ function isObject(arg) {
exports.isObject = isObject;
function isDate(d) {
- return isObject(d) && objectToString(d) === '[object Date]';
+ return objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
- return isObject(e) &&
- (objectToString(e) === '[object Error]' || e instanceof Error);
+ return (objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
@@ -5715,1008 +2413,14 @@ function isPrimitive(arg) {
}
exports.isPrimitive = isPrimitive;
-exports.isBuffer = require('./support/isBuffer');
+exports.isBuffer = Buffer.isBuffer;
function objectToString(o) {
return Object.prototype.toString.call(o);
}
-
-function pad(n) {
- return n < 10 ? '0' + n.toString(10) : n.toString(10);
-}
-
-
-var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
- 'Oct', 'Nov', 'Dec'];
-
-// 26 Feb 16:19:34
-function timestamp() {
- var d = new Date();
- var time = [pad(d.getHours()),
- pad(d.getMinutes()),
- pad(d.getSeconds())].join(':');
- return [d.getDate(), months[d.getMonth()], time].join(' ');
-}
-
-
-// log is just a thin wrapper to console.log that prepends a timestamp
-exports.log = function() {
- console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
-};
-
-
-/**
- * Inherit the prototype methods from one constructor into another.
- *
- * The Function.prototype.inherits from lang.js rewritten as a standalone
- * function (not on Function.prototype). NOTE: If this file is to be loaded
- * during bootstrapping this function needs to be rewritten using some native
- * functions as prototype setup using normal JavaScript does not work as
- * expected during bootstrapping (see mirror.js in r114903).
- *
- * @param {function} ctor Constructor function which needs to inherit the
- * prototype.
- * @param {function} superCtor Constructor function to inherit prototype from.
- */
-exports.inherits = require('inherits');
-
-exports._extend = function(origin, add) {
- // Don't do anything if add isn't an object
- if (!add || !isObject(add)) return origin;
-
- var keys = Object.keys(add);
- var i = keys.length;
- while (i--) {
- origin[keys[i]] = add[keys[i]];
- }
- return origin;
-};
-
-function hasOwnProperty(obj, prop) {
- return Object.prototype.hasOwnProperty.call(obj, prop);
-}
-
-}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./support/isBuffer":27,"_process":10,"inherits":7}],29:[function(require,module,exports){
-var util = require('util');
-var intersect = require('intersect');
-var WildEmitter = require('wildemitter');
-var webrtc = require('webrtcsupport');
-
-var BaseSession = require('jingle-session');
-var MediaSession = require('jingle-media-session');
-var FileSession = require('jingle-filetransfer-session');
-
-
-function SessionManager(conf) {
- WildEmitter.call(this);
-
- conf = conf || {};
-
- this.jid = conf.jid;
- this.selfID = conf.selfID || (this.jid && this.jid.full) || this.jid || '';
-
- this.sessions = {};
- this.peers = {};
-
- this.prepareSession = conf.prepareSession || function (opts) {
- if (opts.descriptionTypes.indexOf('rtp') >= 0) {
- return new MediaSession(opts);
- }
- if (opts.descriptionTypes.indexOf('filetransfer') >= 0) {
- return new FileSession(opts);
- }
- };
-
- this.performTieBreak = conf.performTieBreak || function (sess, req) {
- var descriptionTypes = req.jingle.contents.map(function (content) {
- if (content.description) {
- return content.description.descType;
- }
- });
-
- var matching = intersect(sess.pendingDescriptionTypes, descriptionTypes);
-
- return matching.length > 0;
- };
-
- this.screenSharingSupport = webrtc.screenSharing;
-
- this.capabilities = [
- 'urn:xmpp:jingle:1'
- ];
- if (webrtc.support) {
- this.capabilities = [
- 'urn:xmpp:jingle:1',
- 'urn:xmpp:jingle:apps:rtp:1',
- 'urn:xmpp:jingle:apps:rtp:audio',
- 'urn:xmpp:jingle:apps:rtp:video',
- 'urn:xmpp:jingle:apps:rtp:rtcb-fb:0',
- 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0',
- 'urn:xmpp:jingle:apps:rtp:ssma:0',
- 'urn:xmpp:jingle:apps:dtls:0',
- 'urn:xmpp:jingle:apps:grouping:0',
- 'urn:xmpp:jingle:apps:file-transfer:3',
- 'urn:xmpp:jingle:transports:ice-udp:1',
- 'urn:xmpp:jingle:transports.dtls-sctp:1',
- 'urn:ietf:rfc:3264',
- 'urn:ietf:rfc:5576',
- 'urn:ietf:rfc:5888'
- ];
- }
-
- this.config = {
- debug: false,
- peerConnectionConfig: {
- iceServers: conf.iceServers || [{'url': 'stun:stun.l.google.com:19302'}]
- },
- peerConnectionConstraints: {
- optional: [
- {DtlsSrtpKeyAgreement: true},
- {RtpDataChannels: false}
- ]
- },
- media: {
- audio: true,
- video: true
- }
- };
-
- for (var item in conf) {
- this.config[item] = conf[item];
- }
-
- this.iceServers = this.config.peerConnectionConfig.iceServers;
-}
-
-
-util.inherits(SessionManager, WildEmitter);
-
-
-SessionManager.prototype.addICEServer = function (server) {
- // server == {
- // url: '',
- // [username: '',]
- // [credential: '']
- // }
- if (typeof server === 'string') {
- server = {url: server};
- }
- this.iceServers.push(server);
-};
-
-SessionManager.prototype.addSession = function (session) {
- var self = this;
-
- var sid = session.sid;
- var peer = session.peerID;
-
- this.sessions[sid] = session;
- if (!this.peers[peer]) {
- this.peers[peer] = [];
- }
-
- this.peers[peer].push(session);
-
- // Automatically clean up tracked sessions
- session.on('terminated', function () {
- var peers = self.peers[peer] || [];
- if (peers.length) {
- peers.splice(peers.indexOf(session), 1);
- }
- delete self.sessions[sid];
- });
-
- // Proxy session events
- session.on('*', function (name, data, extraData, extraData2) {
- // Listen for when we actually try to start a session to
- // trigger the outgoing event.
- if (name === 'send') {
- var action = data.jingle && data.jingle.action;
- if (session.isInitiator && action === 'session-initiate') {
- self.emit('outgoing', session);
- }
- }
-
- if (self.config.debug && (name === 'log:debug' || name === 'log:error')) {
- console.log('Jingle:', data, extraData, extraData2);
- }
-
- // Don't proxy change:* events, since those don't apply to
- // the session manager itself.
- if (name.indexOf('change') === 0) {
- return;
- }
-
- self.emit(name, data, extraData, extraData2);
- });
-
- this.emit('createdSession', session);
-
- return session;
-};
-
-SessionManager.prototype.createMediaSession = function (peer, sid, stream) {
- var session = new MediaSession({
- sid: sid,
- peer: peer,
- initiator: true,
- stream: stream,
- parent: this,
- iceServers: this.iceServers,
- constraints: this.config.peerConnectionConstraints
- });
-
- this.addSession(session);
-
- return session;
-};
-
-SessionManager.prototype.createFileTransferSession = function (peer, sid) {
- var session = new FileSession({
- sid: sid,
- peer: peer,
- initiator: true,
- parent: this
- });
-
- this.addSession(session);
-
- return session;
-};
-
-SessionManager.prototype.endPeerSessions = function (peer, reason, silent) {
- peer = peer.full || peer;
-
- var sessions = this.peers[peer] || [];
- delete this.peers[peer];
-
- sessions.forEach(function (session) {
- session.end(reason || 'gone', silent);
- });
-};
-
-SessionManager.prototype.endAllSessions = function (reason, silent) {
- var self = this;
- Object.keys(this.peers).forEach(function (peer) {
- self.endPeerSessions(peer, reason, silent);
- });
-};
-
-SessionManager.prototype._createIncomingSession = function (meta, req) {
- var session;
-
- if (this.prepareSession) {
- session = this.prepareSession(meta, req);
- }
-
- // Fallback to a generic session type, which can
- // only be used to end the session.
-
- if (!session) {
- session = new BaseSession(meta);
- }
-
- this.addSession(session);
-
- return session;
-};
-
-SessionManager.prototype._sendError = function (to, id, data) {
- if (!data.type) {
- data.type = 'cancel';
- }
- this.emit('send', {
- to: to,
- id: id,
- type: 'error',
- error: data
- });
-};
-
-SessionManager.prototype._log = function (level, message) {
- this.emit('log:' + level, message);
-};
-
-SessionManager.prototype.process = function (req) {
- var self = this;
-
- // Extract the request metadata that we need to verify
- var sid = !!req.jingle ? req.jingle.sid : null;
- var session = this.sessions[sid] || null;
- var rid = req.id;
- var sender = req.from.full || req.from;
-
-
- if (req.type === 'error') {
- var isTieBreak = req.error && req.error.jingleCondition === 'tie-break';
- if (session && session.pending && isTieBreak) {
- return session.end('alternative-session', true);
- } else {
- if (session) {
- session.pendingAction = false;
- }
- return this.emit('error', req);
- }
- }
-
- if (req.type === 'result') {
- if (session) {
- session.pendingAction = false;
- }
- return;
- }
-
- var action = req.jingle.action;
- var contents = req.jingle.contents || [];
-
- var descriptionTypes = contents.map(function (content) {
- if (content.description) {
- return content.description.descType;
- }
- });
- var transportTypes = contents.map(function (content) {
- if (content.transport) {
- return content.transport.transType;
- }
- });
-
-
- // Now verify that we are allowed to actually process the
- // requested action
-
- if (action !== 'session-initiate') {
- // Can't modify a session that we don't have.
- if (!session) {
- this._log('error', 'Unknown session', sid);
- return this._sendError(sender, rid, {
- condition: 'item-not-found',
- jingleCondition: 'unknown-session'
- });
- }
-
- // Check if someone is trying to hijack a session.
- if (session.peerID !== sender || session.ended) {
- this._log('error', 'Session has ended, or action has wrong sender');
- return this._sendError(sender, rid, {
- condition: 'item-not-found',
- jingleCondition: 'unknown-session'
- });
- }
-
- // Can't accept a session twice
- if (action === 'session-accept' && !session.pending) {
- this._log('error', 'Tried to accept session twice', sid);
- return this._sendError(sender, rid, {
- condition: 'unexpected-request',
- jingleCondition: 'out-of-order'
- });
- }
-
- // Can't process two requests at once, need to tie break
- if (action !== 'session-terminate' && action === session.pendingAction) {
- this._log('error', 'Tie break during pending request');
- if (session.isInitiator) {
- return this._sendError(sender, rid, {
- condition: 'conflict',
- jingleCondition: 'tie-break'
- });
- }
- }
- } else if (session) {
- // Don't accept a new session if we already have one.
- if (session.peerID !== sender) {
- this._log('error', 'Duplicate sid from new sender');
- return this._sendError(sender, rid, {
- condition: 'service-unavailable'
- });
- }
-
- // Check if we need to have a tie breaker because both parties
- // happened to pick the same random sid.
- if (session.pending) {
- if (this.selfID > session.peerID && this.performTieBreak(session, req)) {
- this._log('error', 'Tie break new session because of duplicate sids');
- return this._sendError(sender, rid, {
- condition: 'conflict',
- jingleCondition: 'tie-break'
- });
- }
- } else {
- // The other side is just doing it wrong.
- this._log('error', 'Someone is doing this wrong');
- return this._sendError(sender, rid, {
- condition: 'unexpected-request',
- jingleCondition: 'out-of-order'
- });
- }
- } else if (this.peers[sender] && this.peers[sender].length) {
- // Check if we need to have a tie breaker because we already have
- // a different session with this peer that is using the requested
- // content description types.
- for (var i = 0, len = this.peers[sender].length; i < len; i++) {
- var sess = this.peers[sender][i];
- if (sess && sess.pending && sess.sid > sid && this.performTieBreak(sess, req)) {
- this._log('info', 'Tie break session-initiate');
- return this._sendError(sender, rid, {
- condition: 'conflict',
- jingleCondition: 'tie-break'
- });
- }
- }
- }
-
- // We've now weeded out invalid requests, so we can process the action now.
-
- if (action === 'session-initiate') {
- if (!contents.length) {
- return self._sendError(sender, rid, {
- condition: 'bad-request'
- });
- }
-
- session = this._createIncomingSession({
- sid: sid,
- peer: req.from,
- peerID: sender,
- initiator: false,
- parent: this,
- descriptionTypes: descriptionTypes,
- transportTypes: transportTypes,
- iceServers: this.iceServers,
- constraints: this.config.peerConnectionConstraints
- }, req);
- }
-
- session.process(action, req.jingle, function (err) {
- if (err) {
- self._log('error', 'Could not process request', req, err);
- self._sendError(sender, rid, err);
- } else {
- self.emit('send', {
- to: sender,
- id: rid,
- type: 'result',
- });
-
- // Wait for the initial action to be processed before emitting
- // the session for the user to accept/reject.
- if (action === 'session-initiate') {
- self.emit('incoming', session);
- }
- }
- });
-};
-
-
-module.exports = SessionManager;
-
-},{"intersect":31,"jingle-filetransfer-session":32,"jingle-media-session":86,"jingle-session":118,"util":28,"webrtcsupport":123,"wildemitter":124}],30:[function(require,module,exports){
-var arr = [];
-var each = arr.forEach;
-var slice = arr.slice;
-
-
-module.exports = function(obj) {
- each.call(slice.call(arguments, 1), function(source) {
- if (source) {
- for (var prop in source) {
- obj[prop] = source[prop];
- }
- }
- });
- return obj;
-};
-
-},{}],31:[function(require,module,exports){
-module.exports = intersect;
-
-function intersect (a, b) {
- var res = [];
- for (var i = 0; i < a.length; i++) {
- if (indexOf(b, a[i]) > -1) res.push(a[i]);
- }
- return res;
-}
-
-intersect.big = function(a, b) {
- var ret = [];
- var temp = {};
-
- for (var i = 0; i < b.length; i++) {
- temp[b[i]] = true;
- }
- for (var i = 0; i < a.length; i++) {
- if (temp[a[i]]) ret.push(a[i]);
- }
-
- return ret;
-}
-
-function indexOf(arr, el) {
- for (var i = 0; i < arr.length; i++) {
- if (arr[i] === el) return i;
- }
- return -1;
-}
-
-},{}],32:[function(require,module,exports){
-var util = require('util');
-var extend = require('extend-object');
-var BaseSession = require('jingle-session');
-var RTCPeerConnection = require('rtcpeerconnection');
-var FileTransfer = require('filetransfer/hashed');
-
-
-function FileTransferSession(opts) {
- BaseSession.call(this, opts);
-
- this.pc = new RTCPeerConnection({
- iceServers: opts.iceServers || [],
- useJingle: true
- }, opts.constraints || {});
-
- this.pc.on('ice', this.onIceCandidate.bind(this));
- this.pc.on('iceConnectionStateChange', this.onIceStateChange.bind(this));
- this.pc.on('addChannel', this.onChannelAdded.bind(this));
-
- this.sender = null;
- this.receiver = null;
-}
-
-
-util.inherits(FileTransferSession, BaseSession);
-
-
-FileTransferSession.prototype = extend(FileTransferSession.prototype, {
-
- // ----------------------------------------------------------------
- // Session control methods
- // ----------------------------------------------------------------
-
- start: function (file) {
- var self = this;
- this.state = 'pending';
-
- this.pc.isInitiator = true;
-
- this.sender = new FileTransfer.Sender();
- this.sender.on('progress', function (sent, size) {
- self._log('info', 'Send progress ' + sent + '/' + size);
- });
- this.sender.on('sentFile', function (meta) {
- self._log('info', 'Sent file', meta.name);
-
- var content = self.pc.localDescription.contents[0];
- delete content.transport;
-
- content.description = {
- descType: 'filetransfer',
- offer: {
- hash: {
- algo: meta.algo,
- value: meta.hash
- }
- }
- };
-
- self.send('description-info', {
- contents: [content]
- });
- self.emit('sentFile', self, meta);
- });
-
- var sendChannel = this.pc.createDataChannel('filetransfer');
- sendChannel.onopen = function () {
- self.sender.send(file, sendChannel);
- };
-
- var constraints = {
- mandatory: {
- OfferToReceiveAudio: false,
- OfferToReceiveVideo: false
- }
- };
-
- this.pc.offer(constraints, function (err, offer) {
- if (err) {
- self._log('error', 'Could not create WebRTC offer', err);
- return self.end('failed-application', true);
- }
-
- offer.jingle.contents[0].description = {
- descType: 'filetransfer',
- offer: {
- date: file.lastModifiedDate,
- name: file.name,
- size: file.size,
- hash: {
- algo: 'sha-1',
- value: ''
- }
- }
- };
-
- self.send('session-initiate', offer.jingle);
- });
- },
-
- accept: function () {
- var self = this;
-
- this._log('info', 'Accepted incoming session');
-
- this.state = 'active';
-
- this.pc.answer(function (err, answer) {
- if (err) {
- self._log('error', 'Could not create WebRTC answer', err);
- return self.end('failed-application');
- }
- self.send('session-accept', answer.jingle);
- });
- },
-
- end: function (reason, silent) {
- this.pc.close();
- BaseSession.prototype.end.call(this, reason, silent);
- },
-
- maybeReceivedFile: function () {
- if (!this.receiver.metadata.hash.value) {
- // unknown hash, file transfer not completed
- } else if (this.receiver.metadata.hash.value === this.receiver.metadata.actualhash) {
- this._log('info', 'File hash matches');
- this.emit('receivedFile', this, this.receivedFile, this.receiver.metadata);
- this.end('success');
- } else {
- this._log('error', 'File hash does not match');
- this.end('media-error');
- }
- },
-
- // ----------------------------------------------------------------
- // ICE action handers
- // ----------------------------------------------------------------
-
- onIceCandidate: function (candidate) {
- this._log('info', 'Discovered new ICE candidate', candidate.jingle);
- this.send('transport-info', candidate.jingle);
- },
-
- onIceStateChange: function () {
- switch (this.pc.iceConnectionState) {
- case 'checking':
- this.connectionState = 'connecting';
- break;
- case 'completed':
- case 'connected':
- this.connectionState = 'connected';
- break;
- case 'disconnected':
- if (this.pc.signalingState === 'stable') {
- this.connectionState = 'interrupted';
- } else {
- this.connectionState = 'disconnected';
- }
- break;
- case 'failed':
- this.connectionState = 'failed';
- this.end('failed-transport');
- break;
- case 'closed':
- this.connectionState = 'disconnected';
- break;
- }
- },
-
- onChannelAdded: function (channel) {
- this.receiver.receive(null, channel);
- },
-
- // ----------------------------------------------------------------
- // Jingle action handers
- // ----------------------------------------------------------------
-
- onSessionInitiate: function (changes, cb) {
- var self = this;
-
- this._log('info', 'Initiating incoming session');
-
- this.state = 'pending';
-
- this.pc.isInitiator = false;
-
- var desc = changes.contents[0].description;
-
-
- this.receiver = new FileTransfer.Receiver({hash: desc.offer.hash.algo});
- this.receiver.on('progress', function (received, size) {
- self._log('info', 'Receive progress ' + received + '/' + size);
- });
- this.receiver.on('receivedFile', function (file) {
- self.receivedFile = file;
- self.maybeReceivedFile();
- });
- this.receiver.metadata = desc.offer;
-
- changes.contents[0].description = {
- descType: 'datachannel'
- };
-
- this.pc.handleOffer({
- type: 'offer',
- jingle: changes
- }, function (err) {
- if (err) {
- self._log('error', 'Could not create WebRTC answer');
- return cb({condition: 'general-error'});
- }
- cb();
- });
- },
-
- onSessionAccept: function (changes, cb) {
- var self = this;
-
- this.state = 'active';
-
- changes.contents[0].description = {
- descType: 'datachannel'
- };
-
- this.pc.handleAnswer({
- type: 'answer',
- jingle: changes
- }, function (err) {
- if (err) {
- self._log('error', 'Could not process WebRTC answer');
- return cb({condition: 'general-error'});
- }
- self.emit('accepted', self);
- cb();
- });
- },
-
- onSessionTerminate: function (changes, cb) {
- this._log('info', 'Terminating session');
- this.pc.close();
- BaseSession.prototype.end.call(this, changes.reason, true);
- cb();
- },
-
- onDescriptionInfo: function (info, cb) {
- var hash = info.contents[0].description.offer.hash;
- this.receiver.metadata.hash = hash;
- if (this.receiver.metadata.actualhash) {
- this.maybeReceivedFile();
- }
- cb();
- },
-
- onTransportInfo: function (changes, cb) {
- this.pc.processIce(changes, function () {
- cb();
- });
- }
-});
-
-
-module.exports = FileTransferSession;
-
-},{"extend-object":30,"filetransfer/hashed":34,"jingle-session":118,"rtcpeerconnection":85,"util":28}],33:[function(require,module,exports){
-var WildEmitter = require('wildemitter');
-var util = require('util');
-
-function Sender(opts) {
- WildEmitter.call(this);
- var options = opts || {};
- this.config = {
- chunksize: 16384,
- pacing: 0
- };
- // set our config from options
- var item;
- for (item in options) {
- this.config[item] = options[item];
- }
-
- this.file = null;
- this.channel = null;
-}
-util.inherits(Sender, WildEmitter);
-
-Sender.prototype.send = function (file, channel) {
- var self = this;
- this.file = file;
- this.channel = channel;
- var sliceFile = function(offset) {
- var reader = new window.FileReader();
- reader.onload = (function() {
- return function(e) {
- self.channel.send(e.target.result);
- self.emit('progress', offset, file.size, e.target.result);
- if (file.size > offset + e.target.result.byteLength) {
- window.setTimeout(sliceFile, self.config.pacing, offset + self.config.chunksize);
- } else {
- self.emit('progress', file.size, file.size, null);
- self.emit('sentFile');
- }
- };
- })(file);
- var slice = file.slice(offset, offset + self.config.chunksize);
- reader.readAsArrayBuffer(slice);
- };
- window.setTimeout(sliceFile, 0, 0);
-};
-
-function Receiver() {
- WildEmitter.call(this);
-
- this.receiveBuffer = [];
- this.received = 0;
- this.metadata = {};
- this.channel = null;
-}
-util.inherits(Receiver, WildEmitter);
-
-Receiver.prototype.receive = function (metadata, channel) {
- var self = this;
-
- if (metadata) {
- this.metadata = metadata;
- }
- this.channel = channel;
- // chrome only supports arraybuffers and those make it easier to calc the hash
- channel.binaryType = 'arraybuffer';
- this.channel.onmessage = function (event) {
- var len = event.data.byteLength;
- self.received += len;
- self.receiveBuffer.push(event.data);
-
- self.emit('progress', self.received, self.metadata.size, event.data);
- if (self.received === self.metadata.size) {
- self.emit('receivedFile', new window.Blob(self.receiveBuffer), self.metadata);
- self.receiveBuffer = []; // discard receivebuffer
- } else if (self.received > self.metadata.size) {
- // FIXME
- console.error('received more than expected, discarding...');
- self.receiveBuffer = []; // just discard...
-
- }
- };
-};
-
-module.exports = {};
-module.exports.support = typeof window !== 'undefined' && window && window.File && window.FileReader && window.Blob;
-module.exports.Sender = Sender;
-module.exports.Receiver = Receiver;
-
-},{"util":28,"wildemitter":53}],34:[function(require,module,exports){
-var WildEmitter = require('wildemitter');
-var util = require('util');
-var hashes = require('iana-hashes');
-var base = require('./filetransfer');
-
-// drop-in replacement for filetransfer which also calculates hashes
-function Sender(opts) {
- WildEmitter.call(this);
- var self = this;
- this.base = new base.Sender(opts);
-
- var options = opts || {};
- if (!options.hash) {
- options.hash = 'sha-1';
- }
- this.hash = hashes.createHash(options.hash);
-
- this.base.on('progress', function (start, size, data) {
- self.emit('progress', start, size, data);
- if (data) {
- self.hash.update(new Uint8Array(data));
- }
- });
- this.base.on('sentFile', function () {
- self.emit('sentFile', {hash: self.hash.digest('hex'), algo: options.hash });
- });
-}
-util.inherits(Sender, WildEmitter);
-Sender.prototype.send = function () {
- this.base.send.apply(this.base, arguments);
-};
-
-function Receiver(opts) {
- WildEmitter.call(this);
- var self = this;
- this.base = new base.Receiver(opts);
-
- var options = opts || {};
- if (!options.hash) {
- options.hash = 'sha-1';
- }
- this.hash = hashes.createHash(options.hash);
-
- this.base.on('progress', function (start, size, data) {
- self.emit('progress', start, size, data);
- if (data) {
- self.hash.update(new Uint8Array(data));
- }
- });
- this.base.on('receivedFile', function (file, metadata) {
- metadata.actualhash = self.hash.digest('hex');
- self.emit('receivedFile', file, metadata);
- });
-}
-util.inherits(Receiver, WildEmitter);
-Receiver.prototype.receive = function () {
- this.base.receive.apply(this.base, arguments);
-};
-Object.defineProperty(Receiver.prototype, 'metadata', {
- get: function () {
- return this.base.metadata;
- },
- set: function (value) {
- this.base.metadata = value;
- }
-});
-
-module.exports = {};
-module.exports.support = base.support;
-module.exports.Sender = Sender;
-module.exports.Receiver = Receiver;
-
-},{"./filetransfer":33,"iana-hashes":35,"util":28,"wildemitter":53}],35:[function(require,module,exports){
-var createHash = require('create-hash');
-var createHmac = require('create-hmac');
-var getHashes = require('./lib/get-hashes');
-
-var mapping = {
- md2: 'md2',
- md5: 'md5',
- 'sha-1': 'sha1',
- 'sha-224': 'sha224',
- 'sha-256': 'sha256',
- 'sha-384': 'sha384',
- 'sha-512': 'sha512'
-};
-
-var names = Object.keys(mapping);
-
-
-exports.getHashes = function () {
- var result = [];
- var available = getHashes();
- for (var i = 0, len = names.length; i < len; i++) {
- if (available.indexOf(mapping[names[i]]) >= 0) {
- result.push(names[i]);
- }
- }
- return result;
-};
-
-exports.createHash = function (algorithm) {
- algorithm = algorithm.toLowerCase();
- if (mapping[algorithm]) {
- algorithm = mapping[algorithm];
- }
- return createHash(algorithm);
-};
-
-exports.createHmac = function (algorithm, key) {
- algorithm = algorithm.toLowerCase();
- if (mapping[algorithm]) {
- algorithm = mapping[algorithm];
- }
- return createHmac(algorithm, key);
-};
-
-},{"./lib/get-hashes":36,"create-hash":37,"create-hmac":51}],36:[function(require,module,exports){
-module.exports = function () {
- return ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'md5', 'rmd160'];
-};
-
-},{}],37:[function(require,module,exports){
+}).call(this,{"isBuffer":require("../../is-buffer/index.js")})
+},{"../../is-buffer/index.js":47}],23:[function(require,module,exports){
(function (Buffer){
'use strict';
var inherits = require('inherits')
@@ -6772,7 +2476,7 @@ module.exports = function createHash (alg) {
}
}).call(this,require("buffer").Buffer)
-},{"./md5":39,"buffer":2,"cipher-base":40,"inherits":41,"ripemd160":42,"sha.js":44}],38:[function(require,module,exports){
+},{"./md5":25,"buffer":6,"cipher-base":7,"inherits":45,"ripemd160":166,"sha.js":175}],24:[function(require,module,exports){
(function (Buffer){
'use strict';
var intSize = 4;
@@ -6809,7 +2513,7 @@ function hash(buf, fn, hashSize, bigEndian) {
}
exports.hash = hash;
}).call(this,require("buffer").Buffer)
-},{"buffer":2}],39:[function(require,module,exports){
+},{"buffer":6}],25:[function(require,module,exports){
'use strict';
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
@@ -6966,1142 +2670,7 @@ function bit_rol(num, cnt)
module.exports = function md5(buf) {
return helpers.hash(buf, core_md5, 16);
};
-},{"./helpers":38}],40:[function(require,module,exports){
-(function (Buffer){
-var Transform = require('stream').Transform
-var inherits = require('inherits')
-var StringDecoder = require('string_decoder').StringDecoder
-module.exports = CipherBase
-inherits(CipherBase, Transform)
-function CipherBase (hashMode) {
- Transform.call(this)
- this.hashMode = typeof hashMode === 'string'
- if (this.hashMode) {
- this[hashMode] = this._finalOrDigest
- } else {
- this.final = this._finalOrDigest
- }
- this._decoder = null
- this._encoding = null
-}
-CipherBase.prototype.update = function (data, inputEnc, outputEnc) {
- if (typeof data === 'string') {
- data = new Buffer(data, inputEnc)
- }
- var outData = this._update(data)
- if (this.hashMode) {
- return this
- }
- if (outputEnc) {
- outData = this._toString(outData, outputEnc)
- }
- return outData
-}
-
-CipherBase.prototype.setAutoPadding = function () {}
-
-CipherBase.prototype.getAuthTag = function () {
- throw new Error('trying to get auth tag in unsupported state')
-}
-
-CipherBase.prototype.setAuthTag = function () {
- throw new Error('trying to set auth tag in unsupported state')
-}
-
-CipherBase.prototype.setAAD = function () {
- throw new Error('trying to set aad in unsupported state')
-}
-
-CipherBase.prototype._transform = function (data, _, next) {
- var err
- try {
- if (this.hashMode) {
- this._update(data)
- } else {
- this.push(this._update(data))
- }
- } catch (e) {
- err = e
- } finally {
- next(err)
- }
-}
-CipherBase.prototype._flush = function (done) {
- var err
- try {
- this.push(this._final())
- } catch (e) {
- err = e
- } finally {
- done(err)
- }
-}
-CipherBase.prototype._finalOrDigest = function (outputEnc) {
- var outData = this._final() || new Buffer('')
- if (outputEnc) {
- outData = this._toString(outData, outputEnc, true)
- }
- return outData
-}
-
-CipherBase.prototype._toString = function (value, enc, final) {
- if (!this._decoder) {
- this._decoder = new StringDecoder(enc)
- this._encoding = enc
- }
- if (this._encoding !== enc) {
- throw new Error('can\'t switch encodings')
- }
- var out = this._decoder.write(value)
- if (final) {
- out += this._decoder.end()
- }
- return out
-}
-
-}).call(this,require("buffer").Buffer)
-},{"buffer":2,"inherits":41,"stream":25,"string_decoder":26}],41:[function(require,module,exports){
-arguments[4][7][0].apply(exports,arguments)
-},{"dup":7}],42:[function(require,module,exports){
-(function (Buffer){
-/*
-CryptoJS v3.1.2
-code.google.com/p/crypto-js
-(c) 2009-2013 by Jeff Mott. All rights reserved.
-code.google.com/p/crypto-js/wiki/License
-*/
-/** @preserve
-(c) 2012 by Cédric Mesnil. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
- - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-// constants table
-var zl = [
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
- 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
- 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
- 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
-]
-
-var zr = [
- 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
- 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
- 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
- 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
- 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
-]
-
-var sl = [
- 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
- 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
- 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
- 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
- 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
-]
-
-var sr = [
- 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
- 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
- 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
- 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
- 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
-]
-
-var hl = [0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]
-var hr = [0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]
-
-function bytesToWords (bytes) {
- var words = []
- for (var i = 0, b = 0; i < bytes.length; i++, b += 8) {
- words[b >>> 5] |= bytes[i] << (24 - b % 32)
- }
- return words
-}
-
-function wordsToBytes (words) {
- var bytes = []
- for (var b = 0; b < words.length * 32; b += 8) {
- bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF)
- }
- return bytes
-}
-
-function processBlock (H, M, offset) {
- // swap endian
- for (var i = 0; i < 16; i++) {
- var offset_i = offset + i
- var M_offset_i = M[offset_i]
-
- // Swap
- M[offset_i] = (
- (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) |
- (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00)
- )
- }
-
- // Working variables
- var al, bl, cl, dl, el
- var ar, br, cr, dr, er
-
- ar = al = H[0]
- br = bl = H[1]
- cr = cl = H[2]
- dr = dl = H[3]
- er = el = H[4]
-
- // computation
- var t
- for (i = 0; i < 80; i += 1) {
- t = (al + M[offset + zl[i]]) | 0
- if (i < 16) {
- t += f1(bl, cl, dl) + hl[0]
- } else if (i < 32) {
- t += f2(bl, cl, dl) + hl[1]
- } else if (i < 48) {
- t += f3(bl, cl, dl) + hl[2]
- } else if (i < 64) {
- t += f4(bl, cl, dl) + hl[3]
- } else {// if (i<80) {
- t += f5(bl, cl, dl) + hl[4]
- }
- t = t | 0
- t = rotl(t, sl[i])
- t = (t + el) | 0
- al = el
- el = dl
- dl = rotl(cl, 10)
- cl = bl
- bl = t
-
- t = (ar + M[offset + zr[i]]) | 0
- if (i < 16) {
- t += f5(br, cr, dr) + hr[0]
- } else if (i < 32) {
- t += f4(br, cr, dr) + hr[1]
- } else if (i < 48) {
- t += f3(br, cr, dr) + hr[2]
- } else if (i < 64) {
- t += f2(br, cr, dr) + hr[3]
- } else {// if (i<80) {
- t += f1(br, cr, dr) + hr[4]
- }
-
- t = t | 0
- t = rotl(t, sr[i])
- t = (t + er) | 0
- ar = er
- er = dr
- dr = rotl(cr, 10)
- cr = br
- br = t
- }
-
- // intermediate hash value
- t = (H[1] + cl + dr) | 0
- H[1] = (H[2] + dl + er) | 0
- H[2] = (H[3] + el + ar) | 0
- H[3] = (H[4] + al + br) | 0
- H[4] = (H[0] + bl + cr) | 0
- H[0] = t
-}
-
-function f1 (x, y, z) {
- return ((x) ^ (y) ^ (z))
-}
-
-function f2 (x, y, z) {
- return (((x) & (y)) | ((~x) & (z)))
-}
-
-function f3 (x, y, z) {
- return (((x) | (~(y))) ^ (z))
-}
-
-function f4 (x, y, z) {
- return (((x) & (z)) | ((y) & (~(z))))
-}
-
-function f5 (x, y, z) {
- return ((x) ^ ((y) | (~(z))))
-}
-
-function rotl (x, n) {
- return (x << n) | (x >>> (32 - n))
-}
-
-function ripemd160 (message) {
- var H = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]
-
- if (typeof message === 'string') {
- message = new Buffer(message, 'utf8')
- }
-
- var m = bytesToWords(message)
-
- var nBitsLeft = message.length * 8
- var nBitsTotal = message.length * 8
-
- // Add padding
- m[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32)
- m[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
- (((nBitsTotal << 8) | (nBitsTotal >>> 24)) & 0x00ff00ff) |
- (((nBitsTotal << 24) | (nBitsTotal >>> 8)) & 0xff00ff00)
- )
-
- for (var i = 0; i < m.length; i += 16) {
- processBlock(H, m, i)
- }
-
- // swap endian
- for (i = 0; i < 5; i++) {
- // shortcut
- var H_i = H[i]
-
- // Swap
- H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) |
- (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00)
- }
-
- var digestbytes = wordsToBytes(H)
- return new Buffer(digestbytes)
-}
-
-module.exports = ripemd160
-
-}).call(this,require("buffer").Buffer)
-},{"buffer":2}],43:[function(require,module,exports){
-(function (Buffer){
-// prototype class for hash functions
-function Hash (blockSize, finalSize) {
- this._block = new Buffer(blockSize)
- this._finalSize = finalSize
- this._blockSize = blockSize
- this._len = 0
- this._s = 0
-}
-
-Hash.prototype.update = function (data, enc) {
- if (typeof data === 'string') {
- enc = enc || 'utf8'
- data = new Buffer(data, enc)
- }
-
- var l = this._len += data.length
- var s = this._s || 0
- var f = 0
- var buffer = this._block
-
- while (s < l) {
- var t = Math.min(data.length, f + this._blockSize - (s % this._blockSize))
- var ch = (t - f)
-
- for (var i = 0; i < ch; i++) {
- buffer[(s % this._blockSize) + i] = data[i + f]
- }
-
- s += ch
- f += ch
-
- if ((s % this._blockSize) === 0) {
- this._update(buffer)
- }
- }
- this._s = s
-
- return this
-}
-
-Hash.prototype.digest = function (enc) {
- // Suppose the length of the message M, in bits, is l
- var l = this._len * 8
-
- // Append the bit 1 to the end of the message
- this._block[this._len % this._blockSize] = 0x80
-
- // and then k zero bits, where k is the smallest non-negative solution to the equation (l + 1 + k) === finalSize mod blockSize
- this._block.fill(0, this._len % this._blockSize + 1)
-
- if (l % (this._blockSize * 8) >= this._finalSize * 8) {
- this._update(this._block)
- this._block.fill(0)
- }
-
- // to this append the block which is equal to the number l written in binary
- // TODO: handle case where l is > Math.pow(2, 29)
- this._block.writeInt32BE(l, this._blockSize - 4)
-
- var hash = this._update(this._block) || this._hash()
-
- return enc ? hash.toString(enc) : hash
-}
-
-Hash.prototype._update = function () {
- throw new Error('_update must be implemented by subclass')
-}
-
-module.exports = Hash
-
-}).call(this,require("buffer").Buffer)
-},{"buffer":2}],44:[function(require,module,exports){
-var exports = module.exports = function SHA (algorithm) {
- algorithm = algorithm.toLowerCase()
-
- var Algorithm = exports[algorithm]
- if (!Algorithm) throw new Error(algorithm + ' is not supported (we accept pull requests)')
-
- return new Algorithm()
-}
-
-exports.sha = require('./sha')
-exports.sha1 = require('./sha1')
-exports.sha224 = require('./sha224')
-exports.sha256 = require('./sha256')
-exports.sha384 = require('./sha384')
-exports.sha512 = require('./sha512')
-
-},{"./sha":45,"./sha1":46,"./sha224":47,"./sha256":48,"./sha384":49,"./sha512":50}],45:[function(require,module,exports){
-(function (Buffer){
-/*
- * A JavaScript implementation of the Secure Hash Algorithm, SHA-0, as defined
- * in FIPS PUB 180-1
- * This source code is derived from sha1.js of the same repository.
- * The difference between SHA-0 and SHA-1 is just a bitwise rotate left
- * operation was added.
- */
-
-var inherits = require('inherits')
-var Hash = require('./hash')
-
-var W = new Array(80)
-
-function Sha () {
- this.init()
- this._w = W
-
- Hash.call(this, 64, 56)
-}
-
-inherits(Sha, Hash)
-
-Sha.prototype.init = function () {
- this._a = 0x67452301 | 0
- this._b = 0xefcdab89 | 0
- this._c = 0x98badcfe | 0
- this._d = 0x10325476 | 0
- this._e = 0xc3d2e1f0 | 0
-
- return this
-}
-
-/*
- * Bitwise rotate a 32-bit number to the left.
- */
-function rol (num, cnt) {
- return (num << cnt) | (num >>> (32 - cnt))
-}
-
-Sha.prototype._update = function (M) {
- var W = this._w
-
- var a = this._a
- var b = this._b
- var c = this._c
- var d = this._d
- var e = this._e
-
- var j = 0
- var k
-
- /*
- * SHA-1 has a bitwise rotate left operation. But, SHA is not
- * function calcW() { return rol(W[j - 3] ^ W[j - 8] ^ W[j - 14] ^ W[j - 16], 1) }
- */
- function calcW () { return W[j - 3] ^ W[j - 8] ^ W[j - 14] ^ W[j - 16] }
- function loop (w, f) {
- W[j] = w
-
- var t = rol(a, 5) + f + e + w + k
-
- e = d
- d = c
- c = rol(b, 30)
- b = a
- a = t
- j++
- }
-
- k = 1518500249
- while (j < 16) loop(M.readInt32BE(j * 4), (b & c) | ((~b) & d))
- while (j < 20) loop(calcW(), (b & c) | ((~b) & d))
- k = 1859775393
- while (j < 40) loop(calcW(), b ^ c ^ d)
- k = -1894007588
- while (j < 60) loop(calcW(), (b & c) | (b & d) | (c & d))
- k = -899497514
- while (j < 80) loop(calcW(), b ^ c ^ d)
-
- this._a = (a + this._a) | 0
- this._b = (b + this._b) | 0
- this._c = (c + this._c) | 0
- this._d = (d + this._d) | 0
- this._e = (e + this._e) | 0
-}
-
-Sha.prototype._hash = function () {
- var H = new Buffer(20)
-
- H.writeInt32BE(this._a | 0, 0)
- H.writeInt32BE(this._b | 0, 4)
- H.writeInt32BE(this._c | 0, 8)
- H.writeInt32BE(this._d | 0, 12)
- H.writeInt32BE(this._e | 0, 16)
-
- return H
-}
-
-module.exports = Sha
-
-
-}).call(this,require("buffer").Buffer)
-},{"./hash":43,"buffer":2,"inherits":41}],46:[function(require,module,exports){
-(function (Buffer){
-/*
- * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
- * in FIPS PUB 180-1
- * Version 2.1a Copyright Paul Johnston 2000 - 2002.
- * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
- * Distributed under the BSD License
- * See http://pajhome.org.uk/crypt/md5 for details.
- */
-
-var inherits = require('inherits')
-var Hash = require('./hash')
-
-var W = new Array(80)
-
-function Sha1 () {
- this.init()
- this._w = W
-
- Hash.call(this, 64, 56)
-}
-
-inherits(Sha1, Hash)
-
-Sha1.prototype.init = function () {
- this._a = 0x67452301 | 0
- this._b = 0xefcdab89 | 0
- this._c = 0x98badcfe | 0
- this._d = 0x10325476 | 0
- this._e = 0xc3d2e1f0 | 0
-
- return this
-}
-
-/*
- * Bitwise rotate a 32-bit number to the left.
- */
-function rol (num, cnt) {
- return (num << cnt) | (num >>> (32 - cnt))
-}
-
-Sha1.prototype._update = function (M) {
- var W = this._w
-
- var a = this._a
- var b = this._b
- var c = this._c
- var d = this._d
- var e = this._e
-
- var j = 0
- var k
-
- function calcW () { return rol(W[j - 3] ^ W[j - 8] ^ W[j - 14] ^ W[j - 16], 1) }
- function loop (w, f) {
- W[j] = w
-
- var t = rol(a, 5) + f + e + w + k
-
- e = d
- d = c
- c = rol(b, 30)
- b = a
- a = t
- j++
- }
-
- k = 1518500249
- while (j < 16) loop(M.readInt32BE(j * 4), (b & c) | ((~b) & d))
- while (j < 20) loop(calcW(), (b & c) | ((~b) & d))
- k = 1859775393
- while (j < 40) loop(calcW(), b ^ c ^ d)
- k = -1894007588
- while (j < 60) loop(calcW(), (b & c) | (b & d) | (c & d))
- k = -899497514
- while (j < 80) loop(calcW(), b ^ c ^ d)
-
- this._a = (a + this._a) | 0
- this._b = (b + this._b) | 0
- this._c = (c + this._c) | 0
- this._d = (d + this._d) | 0
- this._e = (e + this._e) | 0
-}
-
-Sha1.prototype._hash = function () {
- var H = new Buffer(20)
-
- H.writeInt32BE(this._a | 0, 0)
- H.writeInt32BE(this._b | 0, 4)
- H.writeInt32BE(this._c | 0, 8)
- H.writeInt32BE(this._d | 0, 12)
- H.writeInt32BE(this._e | 0, 16)
-
- return H
-}
-
-module.exports = Sha1
-
-}).call(this,require("buffer").Buffer)
-},{"./hash":43,"buffer":2,"inherits":41}],47:[function(require,module,exports){
-(function (Buffer){
-/**
- * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
- * in FIPS 180-2
- * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009.
- * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
- *
- */
-
-var inherits = require('inherits')
-var Sha256 = require('./sha256')
-var Hash = require('./hash')
-
-var W = new Array(64)
-
-function Sha224 () {
- this.init()
-
- this._w = W // new Array(64)
-
- Hash.call(this, 64, 56)
-}
-
-inherits(Sha224, Sha256)
-
-Sha224.prototype.init = function () {
- this._a = 0xc1059ed8 | 0
- this._b = 0x367cd507 | 0
- this._c = 0x3070dd17 | 0
- this._d = 0xf70e5939 | 0
- this._e = 0xffc00b31 | 0
- this._f = 0x68581511 | 0
- this._g = 0x64f98fa7 | 0
- this._h = 0xbefa4fa4 | 0
-
- return this
-}
-
-Sha224.prototype._hash = function () {
- var H = new Buffer(28)
-
- H.writeInt32BE(this._a, 0)
- H.writeInt32BE(this._b, 4)
- H.writeInt32BE(this._c, 8)
- H.writeInt32BE(this._d, 12)
- H.writeInt32BE(this._e, 16)
- H.writeInt32BE(this._f, 20)
- H.writeInt32BE(this._g, 24)
-
- return H
-}
-
-module.exports = Sha224
-
-}).call(this,require("buffer").Buffer)
-},{"./hash":43,"./sha256":48,"buffer":2,"inherits":41}],48:[function(require,module,exports){
-(function (Buffer){
-/**
- * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
- * in FIPS 180-2
- * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009.
- * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
- *
- */
-
-var inherits = require('inherits')
-var Hash = require('./hash')
-
-var K = [
- 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
- 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
- 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
- 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
- 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
- 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
- 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
- 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
- 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
- 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
- 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
- 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
- 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
- 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
- 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
- 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
-]
-
-var W = new Array(64)
-
-function Sha256 () {
- this.init()
-
- this._w = W // new Array(64)
-
- Hash.call(this, 64, 56)
-}
-
-inherits(Sha256, Hash)
-
-Sha256.prototype.init = function () {
- this._a = 0x6a09e667 | 0
- this._b = 0xbb67ae85 | 0
- this._c = 0x3c6ef372 | 0
- this._d = 0xa54ff53a | 0
- this._e = 0x510e527f | 0
- this._f = 0x9b05688c | 0
- this._g = 0x1f83d9ab | 0
- this._h = 0x5be0cd19 | 0
-
- return this
-}
-
-function Ch (x, y, z) {
- return z ^ (x & (y ^ z))
-}
-
-function Maj (x, y, z) {
- return (x & y) | (z & (x | y))
-}
-
-function Sigma0 (x) {
- return (x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10)
-}
-
-function Sigma1 (x) {
- return (x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7)
-}
-
-function Gamma0 (x) {
- return (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ (x >>> 3)
-}
-
-function Gamma1 (x) {
- return (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ (x >>> 10)
-}
-
-Sha256.prototype._update = function (M) {
- var W = this._w
-
- var a = this._a | 0
- var b = this._b | 0
- var c = this._c | 0
- var d = this._d | 0
- var e = this._e | 0
- var f = this._f | 0
- var g = this._g | 0
- var h = this._h | 0
-
- var j = 0
-
- function calcW () { return Gamma1(W[j - 2]) + W[j - 7] + Gamma0(W[j - 15]) + W[j - 16] }
- function loop (w) {
- W[j] = w
-
- var T1 = h + Sigma1(e) + Ch(e, f, g) + K[j] + w
- var T2 = Sigma0(a) + Maj(a, b, c)
-
- h = g
- g = f
- f = e
- e = d + T1
- d = c
- c = b
- b = a
- a = T1 + T2
-
- j++
- }
-
- while (j < 16) loop(M.readInt32BE(j * 4))
- while (j < 64) loop(calcW())
-
- this._a = (a + this._a) | 0
- this._b = (b + this._b) | 0
- this._c = (c + this._c) | 0
- this._d = (d + this._d) | 0
- this._e = (e + this._e) | 0
- this._f = (f + this._f) | 0
- this._g = (g + this._g) | 0
- this._h = (h + this._h) | 0
-}
-
-Sha256.prototype._hash = function () {
- var H = new Buffer(32)
-
- H.writeInt32BE(this._a, 0)
- H.writeInt32BE(this._b, 4)
- H.writeInt32BE(this._c, 8)
- H.writeInt32BE(this._d, 12)
- H.writeInt32BE(this._e, 16)
- H.writeInt32BE(this._f, 20)
- H.writeInt32BE(this._g, 24)
- H.writeInt32BE(this._h, 28)
-
- return H
-}
-
-module.exports = Sha256
-
-}).call(this,require("buffer").Buffer)
-},{"./hash":43,"buffer":2,"inherits":41}],49:[function(require,module,exports){
-(function (Buffer){
-var inherits = require('inherits')
-var SHA512 = require('./sha512')
-var Hash = require('./hash')
-
-var W = new Array(160)
-
-function Sha384 () {
- this.init()
- this._w = W
-
- Hash.call(this, 128, 112)
-}
-
-inherits(Sha384, SHA512)
-
-Sha384.prototype.init = function () {
- this._a = 0xcbbb9d5d | 0
- this._b = 0x629a292a | 0
- this._c = 0x9159015a | 0
- this._d = 0x152fecd8 | 0
- this._e = 0x67332667 | 0
- this._f = 0x8eb44a87 | 0
- this._g = 0xdb0c2e0d | 0
- this._h = 0x47b5481d | 0
-
- this._al = 0xc1059ed8 | 0
- this._bl = 0x367cd507 | 0
- this._cl = 0x3070dd17 | 0
- this._dl = 0xf70e5939 | 0
- this._el = 0xffc00b31 | 0
- this._fl = 0x68581511 | 0
- this._gl = 0x64f98fa7 | 0
- this._hl = 0xbefa4fa4 | 0
-
- return this
-}
-
-Sha384.prototype._hash = function () {
- var H = new Buffer(48)
-
- function writeInt64BE (h, l, offset) {
- H.writeInt32BE(h, offset)
- H.writeInt32BE(l, offset + 4)
- }
-
- writeInt64BE(this._a, this._al, 0)
- writeInt64BE(this._b, this._bl, 8)
- writeInt64BE(this._c, this._cl, 16)
- writeInt64BE(this._d, this._dl, 24)
- writeInt64BE(this._e, this._el, 32)
- writeInt64BE(this._f, this._fl, 40)
-
- return H
-}
-
-module.exports = Sha384
-
-}).call(this,require("buffer").Buffer)
-},{"./hash":43,"./sha512":50,"buffer":2,"inherits":41}],50:[function(require,module,exports){
-(function (Buffer){
-var inherits = require('inherits')
-var Hash = require('./hash')
-
-var K = [
- 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,
- 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
- 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,
- 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
- 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,
- 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
- 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,
- 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
- 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,
- 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
- 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,
- 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
- 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,
- 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
- 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,
- 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
- 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,
- 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
- 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,
- 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
- 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,
- 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
- 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,
- 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
- 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,
- 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
- 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,
- 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
- 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,
- 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
- 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,
- 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
- 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,
- 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
- 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,
- 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
- 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,
- 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
- 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,
- 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817
-]
-
-var W = new Array(160)
-
-function Sha512 () {
- this.init()
- this._w = W
-
- Hash.call(this, 128, 112)
-}
-
-inherits(Sha512, Hash)
-
-Sha512.prototype.init = function () {
- this._a = 0x6a09e667 | 0
- this._b = 0xbb67ae85 | 0
- this._c = 0x3c6ef372 | 0
- this._d = 0xa54ff53a | 0
- this._e = 0x510e527f | 0
- this._f = 0x9b05688c | 0
- this._g = 0x1f83d9ab | 0
- this._h = 0x5be0cd19 | 0
-
- this._al = 0xf3bcc908 | 0
- this._bl = 0x84caa73b | 0
- this._cl = 0xfe94f82b | 0
- this._dl = 0x5f1d36f1 | 0
- this._el = 0xade682d1 | 0
- this._fl = 0x2b3e6c1f | 0
- this._gl = 0xfb41bd6b | 0
- this._hl = 0x137e2179 | 0
-
- return this
-}
-
-function Ch (x, y, z) {
- return z ^ (x & (y ^ z))
-}
-
-function Maj (x, y, z) {
- return (x & y) | (z & (x | y))
-}
-
-function Sigma0 (x, xl) {
- return (x >>> 28 | xl << 4) ^ (xl >>> 2 | x << 30) ^ (xl >>> 7 | x << 25)
-}
-
-function Sigma1 (x, xl) {
- return (x >>> 14 | xl << 18) ^ (x >>> 18 | xl << 14) ^ (xl >>> 9 | x << 23)
-}
-
-function Gamma0 (x, xl) {
- return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7)
-}
-
-function Gamma0l (x, xl) {
- return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7 | xl << 25)
-}
-
-function Gamma1 (x, xl) {
- return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6)
-}
-
-function Gamma1l (x, xl) {
- return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6 | xl << 26)
-}
-
-Sha512.prototype._update = function (M) {
- var W = this._w
-
- var a = this._a | 0
- var b = this._b | 0
- var c = this._c | 0
- var d = this._d | 0
- var e = this._e | 0
- var f = this._f | 0
- var g = this._g | 0
- var h = this._h | 0
-
- var al = this._al | 0
- var bl = this._bl | 0
- var cl = this._cl | 0
- var dl = this._dl | 0
- var el = this._el | 0
- var fl = this._fl | 0
- var gl = this._gl | 0
- var hl = this._hl | 0
-
- var i = 0
- var j = 0
- var Wi, Wil
- function calcW () {
- var x = W[j - 15 * 2]
- var xl = W[j - 15 * 2 + 1]
- var gamma0 = Gamma0(x, xl)
- var gamma0l = Gamma0l(xl, x)
-
- x = W[j - 2 * 2]
- xl = W[j - 2 * 2 + 1]
- var gamma1 = Gamma1(x, xl)
- var gamma1l = Gamma1l(xl, x)
-
- // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]
- var Wi7 = W[j - 7 * 2]
- var Wi7l = W[j - 7 * 2 + 1]
-
- var Wi16 = W[j - 16 * 2]
- var Wi16l = W[j - 16 * 2 + 1]
-
- Wil = gamma0l + Wi7l
- Wi = gamma0 + Wi7 + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0)
- Wil = Wil + gamma1l
- Wi = Wi + gamma1 + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0)
- Wil = Wil + Wi16l
- Wi = Wi + Wi16 + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0)
- }
-
- function loop () {
- W[j] = Wi
- W[j + 1] = Wil
-
- var maj = Maj(a, b, c)
- var majl = Maj(al, bl, cl)
-
- var sigma0h = Sigma0(a, al)
- var sigma0l = Sigma0(al, a)
- var sigma1h = Sigma1(e, el)
- var sigma1l = Sigma1(el, e)
-
- // t1 = h + sigma1 + ch + K[i] + W[i]
- var Ki = K[j]
- var Kil = K[j + 1]
-
- var ch = Ch(e, f, g)
- var chl = Ch(el, fl, gl)
-
- var t1l = hl + sigma1l
- var t1 = h + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0)
- t1l = t1l + chl
- t1 = t1 + ch + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0)
- t1l = t1l + Kil
- t1 = t1 + Ki + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0)
- t1l = t1l + Wil
- t1 = t1 + Wi + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0)
-
- // t2 = sigma0 + maj
- var t2l = sigma0l + majl
- var t2 = sigma0h + maj + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0)
-
- h = g
- hl = gl
- g = f
- gl = fl
- f = e
- fl = el
- el = (dl + t1l) | 0
- e = (d + t1 + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0
- d = c
- dl = cl
- c = b
- cl = bl
- b = a
- bl = al
- al = (t1l + t2l) | 0
- a = (t1 + t2 + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0
-
- i++
- j += 2
- }
-
- while (i < 16) {
- Wi = M.readInt32BE(j * 4)
- Wil = M.readInt32BE(j * 4 + 4)
-
- loop()
- }
-
- while (i < 80) {
- calcW()
- loop()
- }
-
- this._al = (this._al + al) | 0
- this._bl = (this._bl + bl) | 0
- this._cl = (this._cl + cl) | 0
- this._dl = (this._dl + dl) | 0
- this._el = (this._el + el) | 0
- this._fl = (this._fl + fl) | 0
- this._gl = (this._gl + gl) | 0
- this._hl = (this._hl + hl) | 0
-
- this._a = (this._a + a + ((this._al >>> 0) < (al >>> 0) ? 1 : 0)) | 0
- this._b = (this._b + b + ((this._bl >>> 0) < (bl >>> 0) ? 1 : 0)) | 0
- this._c = (this._c + c + ((this._cl >>> 0) < (cl >>> 0) ? 1 : 0)) | 0
- this._d = (this._d + d + ((this._dl >>> 0) < (dl >>> 0) ? 1 : 0)) | 0
- this._e = (this._e + e + ((this._el >>> 0) < (el >>> 0) ? 1 : 0)) | 0
- this._f = (this._f + f + ((this._fl >>> 0) < (fl >>> 0) ? 1 : 0)) | 0
- this._g = (this._g + g + ((this._gl >>> 0) < (gl >>> 0) ? 1 : 0)) | 0
- this._h = (this._h + h + ((this._hl >>> 0) < (hl >>> 0) ? 1 : 0)) | 0
-}
-
-Sha512.prototype._hash = function () {
- var H = new Buffer(64)
-
- function writeInt64BE (h, l, offset) {
- H.writeInt32BE(h, offset)
- H.writeInt32BE(l, offset + 4)
- }
-
- writeInt64BE(this._a, this._al, 0)
- writeInt64BE(this._b, this._bl, 8)
- writeInt64BE(this._c, this._cl, 16)
- writeInt64BE(this._d, this._dl, 24)
- writeInt64BE(this._e, this._el, 32)
- writeInt64BE(this._f, this._fl, 40)
- writeInt64BE(this._g, this._gl, 48)
- writeInt64BE(this._h, this._hl, 56)
-
- return H
-}
-
-module.exports = Sha512
-
-}).call(this,require("buffer").Buffer)
-},{"./hash":43,"buffer":2,"inherits":41}],51:[function(require,module,exports){
+},{"./helpers":24}],26:[function(require,module,exports){
(function (Buffer){
'use strict';
var createHash = require('create-hash/browser');
@@ -8173,3866 +2742,2595 @@ module.exports = function createHmac(alg, key) {
}
}).call(this,require("buffer").Buffer)
-},{"buffer":2,"create-hash/browser":37,"inherits":52,"stream":25}],52:[function(require,module,exports){
-arguments[4][7][0].apply(exports,arguments)
-},{"dup":7}],53:[function(require,module,exports){
-/*
-WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based
-on @visionmedia's Emitter from UI Kit.
-
-Why? I wanted it standalone.
-
-I also wanted support for wildcard emitters like this:
-
-emitter.on('*', function (eventName, other, event, payloads) {
-
-});
-
-emitter.on('somenamespace*', function (eventName, payloads) {
-
-});
-
-Please note that callbacks triggered by wildcard registered events also get
-the event name as the first argument.
-*/
-
-module.exports = WildEmitter;
-
-function WildEmitter() { }
-
-WildEmitter.mixin = function (constructor) {
- var prototype = constructor.prototype || constructor;
-
- prototype.isWildEmitter= true;
-
- // Listen on the given `event` with `fn`. Store a group name if present.
- prototype.on = function (event, groupName, fn) {
- this.callbacks = this.callbacks || {};
- var hasGroup = (arguments.length === 3),
- group = hasGroup ? arguments[1] : undefined,
- func = hasGroup ? arguments[2] : arguments[1];
- func._groupName = group;
- (this.callbacks[event] = this.callbacks[event] || []).push(func);
- return this;
- };
-
- // Adds an `event` listener that will be invoked a single
- // time then automatically removed.
- prototype.once = function (event, groupName, fn) {
- var self = this,
- hasGroup = (arguments.length === 3),
- group = hasGroup ? arguments[1] : undefined,
- func = hasGroup ? arguments[2] : arguments[1];
- function on() {
- self.off(event, on);
- func.apply(this, arguments);
- }
- this.on(event, group, on);
- return this;
- };
-
- // Unbinds an entire group
- prototype.releaseGroup = function (groupName) {
- this.callbacks = this.callbacks || {};
- var item, i, len, handlers;
- for (item in this.callbacks) {
- handlers = this.callbacks[item];
- for (i = 0, len = handlers.length; i < len; i++) {
- if (handlers[i]._groupName === groupName) {
- //console.log('removing');
- // remove it and shorten the array we're looping through
- handlers.splice(i, 1);
- i--;
- len--;
- }
- }
- }
- return this;
- };
-
- // Remove the given callback for `event` or all
- // registered callbacks.
- prototype.off = function (event, fn) {
- this.callbacks = this.callbacks || {};
- var callbacks = this.callbacks[event],
- i;
-
- if (!callbacks) return this;
-
- // remove all handlers
- if (arguments.length === 1) {
- delete this.callbacks[event];
- return this;
- }
-
- // remove specific handler
- i = callbacks.indexOf(fn);
- callbacks.splice(i, 1);
- if (callbacks.length === 0) {
- delete this.callbacks[event];
- }
- return this;
- };
-
- /// Emit `event` with the given args.
- // also calls any `*` handlers
- prototype.emit = function (event) {
- this.callbacks = this.callbacks || {};
- var args = [].slice.call(arguments, 1),
- callbacks = this.callbacks[event],
- specialCallbacks = this.getWildcardCallbacks(event),
- i,
- len,
- item,
- listeners;
-
- if (callbacks) {
- listeners = callbacks.slice();
- for (i = 0, len = listeners.length; i < len; ++i) {
- if (!listeners[i]) {
- break;
- }
- listeners[i].apply(this, args);
- }
- }
-
- if (specialCallbacks) {
- len = specialCallbacks.length;
- listeners = specialCallbacks.slice();
- for (i = 0, len = listeners.length; i < len; ++i) {
- if (!listeners[i]) {
- break;
- }
- listeners[i].apply(this, [event].concat(args));
- }
- }
-
- return this;
- };
-
- // Helper for for finding special wildcard event handlers that match the event
- prototype.getWildcardCallbacks = function (eventName) {
- this.callbacks = this.callbacks || {};
- var item,
- split,
- result = [];
-
- for (item in this.callbacks) {
- split = item.split('*');
- if (item === '*' || (split.length === 2 && eventName.slice(0, split[0].length) === split[0])) {
- result = result.concat(this.callbacks[item]);
- }
- }
- return result;
- };
-
-};
-
-WildEmitter.mixin(WildEmitter);
-
-},{}],54:[function(require,module,exports){
-/**
- * lodash 3.0.3 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-var arrayEach = require('lodash._arrayeach'),
- baseEach = require('lodash._baseeach'),
- bindCallback = require('lodash._bindcallback'),
- isArray = require('lodash.isarray');
+},{"buffer":6,"create-hash/browser":23,"inherits":45,"stream":182}],27:[function(require,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
-/**
- * Creates a function for `_.forEach` or `_.forEachRight`.
- *
- * @private
- * @param {Function} arrayFunc The function to iterate over an array.
- * @param {Function} eachFunc The function to iterate over a collection.
- * @returns {Function} Returns the new each function.
- */
-function createForEach(arrayFunc, eachFunc) {
- return function(collection, iteratee, thisArg) {
- return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection))
- ? arrayFunc(collection, iteratee)
- : eachFunc(collection, bindCallback(iteratee, thisArg, 3));
- };
+function EventEmitter() {
+ this._events = this._events || {};
+ this._maxListeners = this._maxListeners || undefined;
}
+module.exports = EventEmitter;
-/**
- * Iterates over elements of `collection` invoking `iteratee` for each element.
- * The `iteratee` is bound to `thisArg` and invoked with three arguments:
- * (value, index|key, collection). Iteratee functions may exit iteration early
- * by explicitly returning `false`.
- *
- * **Note:** As with other "Collections" methods, objects with a "length" property
- * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
- * may be used for object iteration.
- *
- * @static
- * @memberOf _
- * @alias each
- * @category Collection
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} [iteratee=_.identity] The function invoked per iteration.
- * @param {*} [thisArg] The `this` binding of `iteratee`.
- * @returns {Array|Object|string} Returns `collection`.
- * @example
- *
- * _([1, 2]).forEach(function(n) {
- * console.log(n);
- * }).value();
- * // => logs each value from left to right and returns the array
- *
- * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) {
- * console.log(n, key);
- * });
- * // => logs each value-key pair and returns the object (iteration order is not guaranteed)
- */
-var forEach = createForEach(arrayEach, baseEach);
+// Backwards-compat with node 0.10.x
+EventEmitter.EventEmitter = EventEmitter;
-module.exports = forEach;
+EventEmitter.prototype._events = undefined;
+EventEmitter.prototype._maxListeners = undefined;
-},{"lodash._arrayeach":55,"lodash._baseeach":56,"lodash._bindcallback":60,"lodash.isarray":61}],55:[function(require,module,exports){
-/**
- * lodash 3.0.0 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
+// By default EventEmitters will print a warning if more than 10 listeners are
+// added to it. This is a useful default which helps finding memory leaks.
+EventEmitter.defaultMaxListeners = 10;
-/**
- * A specialized version of `_.forEach` for arrays without support for callback
- * shorthands or `this` binding.
- *
- * @private
- * @param {Array} array The array to iterate over.
- * @param {Function} iteratee The function invoked per iteration.
- * @returns {Array} Returns `array`.
- */
-function arrayEach(array, iteratee) {
- var index = -1,
- length = array.length;
+// Obviously not all Emitters should be limited to 10. This function allows
+// that to be increased. Set to zero for unlimited.
+EventEmitter.prototype.setMaxListeners = function(n) {
+ if (!isNumber(n) || n < 0 || isNaN(n))
+ throw TypeError('n must be a positive number');
+ this._maxListeners = n;
+ return this;
+};
- while (++index < length) {
- if (iteratee(array[index], index, array) === false) {
- break;
+EventEmitter.prototype.emit = function(type) {
+ var er, handler, len, args, i, listeners;
+
+ if (!this._events)
+ this._events = {};
+
+ // If there is no 'error' event listener then throw.
+ if (type === 'error') {
+ if (!this._events.error ||
+ (isObject(this._events.error) && !this._events.error.length)) {
+ er = arguments[1];
+ if (er instanceof Error) {
+ throw er; // Unhandled 'error' event
+ } else {
+ // At least give some kind of context to the user
+ var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
+ err.context = er;
+ throw err;
+ }
}
}
- return array;
-}
-module.exports = arrayEach;
+ handler = this._events[type];
-},{}],56:[function(require,module,exports){
-/**
- * lodash 3.0.4 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-var keys = require('lodash.keys');
+ if (isUndefined(handler))
+ return false;
-/**
- * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer)
- * of an array-like value.
- */
-var MAX_SAFE_INTEGER = 9007199254740991;
+ if (isFunction(handler)) {
+ switch (arguments.length) {
+ // fast cases
+ case 1:
+ handler.call(this);
+ break;
+ case 2:
+ handler.call(this, arguments[1]);
+ break;
+ case 3:
+ handler.call(this, arguments[1], arguments[2]);
+ break;
+ // slower
+ default:
+ args = Array.prototype.slice.call(arguments, 1);
+ handler.apply(this, args);
+ }
+ } else if (isObject(handler)) {
+ args = Array.prototype.slice.call(arguments, 1);
+ listeners = handler.slice();
+ len = listeners.length;
+ for (i = 0; i < len; i++)
+ listeners[i].apply(this, args);
+ }
-/**
- * The base implementation of `_.forEach` without support for callback
- * shorthands and `this` binding.
- *
- * @private
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} iteratee The function invoked per iteration.
- * @returns {Array|Object|string} Returns `collection`.
- */
-var baseEach = createBaseEach(baseForOwn);
+ return true;
+};
-/**
- * The base implementation of `baseForIn` and `baseForOwn` which iterates
- * over `object` properties returned by `keysFunc` invoking `iteratee` for
- * each property. Iteratee functions may exit iteration early by explicitly
- * returning `false`.
- *
- * @private
- * @param {Object} object The object to iterate over.
- * @param {Function} iteratee The function invoked per iteration.
- * @param {Function} keysFunc The function to get the keys of `object`.
- * @returns {Object} Returns `object`.
- */
-var baseFor = createBaseFor();
+EventEmitter.prototype.addListener = function(type, listener) {
+ var m;
-/**
- * The base implementation of `_.forOwn` without support for callback
- * shorthands and `this` binding.
- *
- * @private
- * @param {Object} object The object to iterate over.
- * @param {Function} iteratee The function invoked per iteration.
- * @returns {Object} Returns `object`.
- */
-function baseForOwn(object, iteratee) {
- return baseFor(object, iteratee, keys);
-}
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
-/**
- * The base implementation of `_.property` without support for deep paths.
- *
- * @private
- * @param {string} key The key of the property to get.
- * @returns {Function} Returns the new function.
- */
-function baseProperty(key) {
- return function(object) {
- return object == null ? undefined : object[key];
- };
-}
+ if (!this._events)
+ this._events = {};
-/**
- * Creates a `baseEach` or `baseEachRight` function.
- *
- * @private
- * @param {Function} eachFunc The function to iterate over a collection.
- * @param {boolean} [fromRight] Specify iterating from right to left.
- * @returns {Function} Returns the new base function.
- */
-function createBaseEach(eachFunc, fromRight) {
- return function(collection, iteratee) {
- var length = collection ? getLength(collection) : 0;
- if (!isLength(length)) {
- return eachFunc(collection, iteratee);
- }
- var index = fromRight ? length : -1,
- iterable = toObject(collection);
+ // To avoid recursion in the case that type === "newListener"! Before
+ // adding it to the listeners, first emit "newListener".
+ if (this._events.newListener)
+ this.emit('newListener', type,
+ isFunction(listener.listener) ?
+ listener.listener : listener);
- while ((fromRight ? index-- : ++index < length)) {
- if (iteratee(iterable[index], index, iterable) === false) {
- break;
- }
- }
- return collection;
- };
-}
+ if (!this._events[type])
+ // Optimize the case of one listener. Don't need the extra array object.
+ this._events[type] = listener;
+ else if (isObject(this._events[type]))
+ // If we've already got an array, just append.
+ this._events[type].push(listener);
+ else
+ // Adding the second element, need to change to array.
+ this._events[type] = [this._events[type], listener];
-/**
- * Creates a base function for `_.forIn` or `_.forInRight`.
- *
- * @private
- * @param {boolean} [fromRight] Specify iterating from right to left.
- * @returns {Function} Returns the new base function.
- */
-function createBaseFor(fromRight) {
- return function(object, iteratee, keysFunc) {
- var iterable = toObject(object),
- props = keysFunc(object),
- length = props.length,
- index = fromRight ? length : -1;
+ // Check for listener leak
+ if (isObject(this._events[type]) && !this._events[type].warned) {
+ if (!isUndefined(this._maxListeners)) {
+ m = this._maxListeners;
+ } else {
+ m = EventEmitter.defaultMaxListeners;
+ }
- while ((fromRight ? index-- : ++index < length)) {
- var key = props[index];
- if (iteratee(iterable[key], key, iterable) === false) {
- break;
+ if (m && m > 0 && this._events[type].length > m) {
+ this._events[type].warned = true;
+ console.error('(node) warning: possible EventEmitter memory ' +
+ 'leak detected. %d listeners added. ' +
+ 'Use emitter.setMaxListeners() to increase limit.',
+ this._events[type].length);
+ if (typeof console.trace === 'function') {
+ // not supported in IE 10
+ console.trace();
}
}
- return object;
- };
-}
-
-/**
- * Gets the "length" property value of `object`.
- *
- * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
- * that affects Safari on at least iOS 8.1-8.3 ARM64.
- *
- * @private
- * @param {Object} object The object to query.
- * @returns {*} Returns the "length" value.
- */
-var getLength = baseProperty('length');
-
-/**
- * Checks if `value` is a valid array-like length.
- *
- * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength).
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
- */
-function isLength(value) {
- return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
-}
-
-/**
- * Converts `value` to an object if it's not one.
- *
- * @private
- * @param {*} value The value to process.
- * @returns {Object} Returns the object.
- */
-function toObject(value) {
- return isObject(value) ? value : Object(value);
-}
-
-/**
- * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
- * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an object, else `false`.
- * @example
- *
- * _.isObject({});
- * // => true
- *
- * _.isObject([1, 2, 3]);
- * // => true
- *
- * _.isObject(1);
- * // => false
- */
-function isObject(value) {
- // Avoid a V8 JIT bug in Chrome 19-20.
- // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
- var type = typeof value;
- return !!value && (type == 'object' || type == 'function');
-}
+ }
-module.exports = baseEach;
+ return this;
+};
-},{"lodash.keys":57}],57:[function(require,module,exports){
-/**
- * lodash 3.1.2 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-var getNative = require('lodash._getnative'),
- isArguments = require('lodash.isarguments'),
- isArray = require('lodash.isarray');
+EventEmitter.prototype.on = EventEmitter.prototype.addListener;
-/** Used to detect unsigned integer values. */
-var reIsUint = /^\d+$/;
+EventEmitter.prototype.once = function(type, listener) {
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
-/** Used for native method references. */
-var objectProto = Object.prototype;
+ var fired = false;
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
+ function g() {
+ this.removeListener(type, g);
-/* Native method references for those with the same name as other `lodash` methods. */
-var nativeKeys = getNative(Object, 'keys');
+ if (!fired) {
+ fired = true;
+ listener.apply(this, arguments);
+ }
+ }
-/**
- * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
- * of an array-like value.
- */
-var MAX_SAFE_INTEGER = 9007199254740991;
+ g.listener = listener;
+ this.on(type, g);
-/**
- * The base implementation of `_.property` without support for deep paths.
- *
- * @private
- * @param {string} key The key of the property to get.
- * @returns {Function} Returns the new function.
- */
-function baseProperty(key) {
- return function(object) {
- return object == null ? undefined : object[key];
- };
-}
+ return this;
+};
-/**
- * Gets the "length" property value of `object`.
- *
- * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
- * that affects Safari on at least iOS 8.1-8.3 ARM64.
- *
- * @private
- * @param {Object} object The object to query.
- * @returns {*} Returns the "length" value.
- */
-var getLength = baseProperty('length');
+// emits a 'removeListener' event iff the listener was removed
+EventEmitter.prototype.removeListener = function(type, listener) {
+ var list, position, length, i;
-/**
- * Checks if `value` is array-like.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
- */
-function isArrayLike(value) {
- return value != null && isLength(getLength(value));
-}
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
-/**
- * Checks if `value` is a valid array-like index.
- *
- * @private
- * @param {*} value The value to check.
- * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
- * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
- */
-function isIndex(value, length) {
- value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
- length = length == null ? MAX_SAFE_INTEGER : length;
- return value > -1 && value % 1 == 0 && value < length;
-}
+ if (!this._events || !this._events[type])
+ return this;
-/**
- * Checks if `value` is a valid array-like length.
- *
- * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
- */
-function isLength(value) {
- return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
-}
+ list = this._events[type];
+ length = list.length;
+ position = -1;
-/**
- * A fallback implementation of `Object.keys` which creates an array of the
- * own enumerable property names of `object`.
- *
- * @private
- * @param {Object} object The object to query.
- * @returns {Array} Returns the array of property names.
- */
-function shimKeys(object) {
- var props = keysIn(object),
- propsLength = props.length,
- length = propsLength && object.length;
+ if (list === listener ||
+ (isFunction(list.listener) && list.listener === listener)) {
+ delete this._events[type];
+ if (this._events.removeListener)
+ this.emit('removeListener', type, listener);
- var allowIndexes = !!length && isLength(length) &&
- (isArray(object) || isArguments(object));
+ } else if (isObject(list)) {
+ for (i = length; i-- > 0;) {
+ if (list[i] === listener ||
+ (list[i].listener && list[i].listener === listener)) {
+ position = i;
+ break;
+ }
+ }
- var index = -1,
- result = [];
+ if (position < 0)
+ return this;
- while (++index < propsLength) {
- var key = props[index];
- if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
- result.push(key);
+ if (list.length === 1) {
+ list.length = 0;
+ delete this._events[type];
+ } else {
+ list.splice(position, 1);
}
- }
- return result;
-}
-
-/**
- * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
- * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an object, else `false`.
- * @example
- *
- * _.isObject({});
- * // => true
- *
- * _.isObject([1, 2, 3]);
- * // => true
- *
- * _.isObject(1);
- * // => false
- */
-function isObject(value) {
- // Avoid a V8 JIT bug in Chrome 19-20.
- // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
- var type = typeof value;
- return !!value && (type == 'object' || type == 'function');
-}
-/**
- * Creates an array of the own enumerable property names of `object`.
- *
- * **Note:** Non-object values are coerced to objects. See the
- * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
- * for more details.
- *
- * @static
- * @memberOf _
- * @category Object
- * @param {Object} object The object to query.
- * @returns {Array} Returns the array of property names.
- * @example
- *
- * function Foo() {
- * this.a = 1;
- * this.b = 2;
- * }
- *
- * Foo.prototype.c = 3;
- *
- * _.keys(new Foo);
- * // => ['a', 'b'] (iteration order is not guaranteed)
- *
- * _.keys('hi');
- * // => ['0', '1']
- */
-var keys = !nativeKeys ? shimKeys : function(object) {
- var Ctor = object == null ? undefined : object.constructor;
- if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
- (typeof object != 'function' && isArrayLike(object))) {
- return shimKeys(object);
+ if (this._events.removeListener)
+ this.emit('removeListener', type, listener);
}
- return isObject(object) ? nativeKeys(object) : [];
+
+ return this;
};
-/**
- * Creates an array of the own and inherited enumerable property names of `object`.
- *
- * **Note:** Non-object values are coerced to objects.
- *
- * @static
- * @memberOf _
- * @category Object
- * @param {Object} object The object to query.
- * @returns {Array} Returns the array of property names.
- * @example
- *
- * function Foo() {
- * this.a = 1;
- * this.b = 2;
- * }
- *
- * Foo.prototype.c = 3;
- *
- * _.keysIn(new Foo);
- * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
- */
-function keysIn(object) {
- if (object == null) {
- return [];
- }
- if (!isObject(object)) {
- object = Object(object);
- }
- var length = object.length;
- length = (length && isLength(length) &&
- (isArray(object) || isArguments(object)) && length) || 0;
+EventEmitter.prototype.removeAllListeners = function(type) {
+ var key, listeners;
- var Ctor = object.constructor,
- index = -1,
- isProto = typeof Ctor == 'function' && Ctor.prototype === object,
- result = Array(length),
- skipIndexes = length > 0;
+ if (!this._events)
+ return this;
- while (++index < length) {
- result[index] = (index + '');
+ // not listening for removeListener, no need to emit
+ if (!this._events.removeListener) {
+ if (arguments.length === 0)
+ this._events = {};
+ else if (this._events[type])
+ delete this._events[type];
+ return this;
}
- for (var key in object) {
- if (!(skipIndexes && isIndex(key, length)) &&
- !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
- result.push(key);
+
+ // emit removeListener for all listeners on all events
+ if (arguments.length === 0) {
+ for (key in this._events) {
+ if (key === 'removeListener') continue;
+ this.removeAllListeners(key);
}
+ this.removeAllListeners('removeListener');
+ this._events = {};
+ return this;
}
- return result;
-}
-
-module.exports = keys;
-
-},{"lodash._getnative":58,"lodash.isarguments":59,"lodash.isarray":61}],58:[function(require,module,exports){
-/**
- * lodash 3.9.1 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-
-/** `Object#toString` result references. */
-var funcTag = '[object Function]';
-
-/** Used to detect host constructors (Safari > 5). */
-var reIsHostCtor = /^\[object .+?Constructor\]$/;
-
-/**
- * Checks if `value` is object-like.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
- */
-function isObjectLike(value) {
- return !!value && typeof value == 'object';
-}
-
-/** Used for native method references. */
-var objectProto = Object.prototype;
-
-/** Used to resolve the decompiled source of functions. */
-var fnToString = Function.prototype.toString;
-
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
-/**
- * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
- * of values.
- */
-var objToString = objectProto.toString;
+ listeners = this._events[type];
-/** Used to detect if a method is native. */
-var reIsNative = RegExp('^' +
- fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
- .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
-);
+ if (isFunction(listeners)) {
+ this.removeListener(type, listeners);
+ } else if (listeners) {
+ // LIFO order
+ while (listeners.length)
+ this.removeListener(type, listeners[listeners.length - 1]);
+ }
+ delete this._events[type];
-/**
- * Gets the native function at `key` of `object`.
- *
- * @private
- * @param {Object} object The object to query.
- * @param {string} key The key of the method to get.
- * @returns {*} Returns the function if it's native, else `undefined`.
- */
-function getNative(object, key) {
- var value = object == null ? undefined : object[key];
- return isNative(value) ? value : undefined;
-}
+ return this;
+};
-/**
- * Checks if `value` is classified as a `Function` object.
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
- * @example
- *
- * _.isFunction(_);
- * // => true
- *
- * _.isFunction(/abc/);
- * // => false
- */
-function isFunction(value) {
- // The use of `Object#toString` avoids issues with the `typeof` operator
- // in older versions of Chrome and Safari which return 'function' for regexes
- // and Safari 8 equivalents which return 'object' for typed array constructors.
- return isObject(value) && objToString.call(value) == funcTag;
-}
+EventEmitter.prototype.listeners = function(type) {
+ var ret;
+ if (!this._events || !this._events[type])
+ ret = [];
+ else if (isFunction(this._events[type]))
+ ret = [this._events[type]];
+ else
+ ret = this._events[type].slice();
+ return ret;
+};
-/**
- * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
- * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an object, else `false`.
- * @example
- *
- * _.isObject({});
- * // => true
- *
- * _.isObject([1, 2, 3]);
- * // => true
- *
- * _.isObject(1);
- * // => false
- */
-function isObject(value) {
- // Avoid a V8 JIT bug in Chrome 19-20.
- // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
- var type = typeof value;
- return !!value && (type == 'object' || type == 'function');
-}
+EventEmitter.prototype.listenerCount = function(type) {
+ if (this._events) {
+ var evlistener = this._events[type];
-/**
- * Checks if `value` is a native function.
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
- * @example
- *
- * _.isNative(Array.prototype.push);
- * // => true
- *
- * _.isNative(_);
- * // => false
- */
-function isNative(value) {
- if (value == null) {
- return false;
- }
- if (isFunction(value)) {
- return reIsNative.test(fnToString.call(value));
+ if (isFunction(evlistener))
+ return 1;
+ else if (evlistener)
+ return evlistener.length;
}
- return isObjectLike(value) && reIsHostCtor.test(value);
-}
-
-module.exports = getNative;
+ return 0;
+};
-},{}],59:[function(require,module,exports){
-/**
- * lodash 3.0.4 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
+EventEmitter.listenerCount = function(emitter, type) {
+ return emitter.listenerCount(type);
+};
-/**
- * Checks if `value` is object-like.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
- */
-function isObjectLike(value) {
- return !!value && typeof value == 'object';
+function isFunction(arg) {
+ return typeof arg === 'function';
}
-/** Used for native method references. */
-var objectProto = Object.prototype;
-
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
-
-/** Native method references. */
-var propertyIsEnumerable = objectProto.propertyIsEnumerable;
-
-/**
- * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
- * of an array-like value.
- */
-var MAX_SAFE_INTEGER = 9007199254740991;
-
-/**
- * The base implementation of `_.property` without support for deep paths.
- *
- * @private
- * @param {string} key The key of the property to get.
- * @returns {Function} Returns the new function.
- */
-function baseProperty(key) {
- return function(object) {
- return object == null ? undefined : object[key];
- };
+function isNumber(arg) {
+ return typeof arg === 'number';
}
-/**
- * Gets the "length" property value of `object`.
- *
- * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
- * that affects Safari on at least iOS 8.1-8.3 ARM64.
- *
- * @private
- * @param {Object} object The object to query.
- * @returns {*} Returns the "length" value.
- */
-var getLength = baseProperty('length');
-
-/**
- * Checks if `value` is array-like.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
- */
-function isArrayLike(value) {
- return value != null && isLength(getLength(value));
+function isObject(arg) {
+ return typeof arg === 'object' && arg !== null;
}
-/**
- * Checks if `value` is a valid array-like length.
- *
- * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
- */
-function isLength(value) {
- return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+function isUndefined(arg) {
+ return arg === void 0;
}
-/**
- * Checks if `value` is classified as an `arguments` object.
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
- * @example
- *
- * _.isArguments(function() { return arguments; }());
- * // => true
- *
- * _.isArguments([1, 2, 3]);
- * // => false
- */
-function isArguments(value) {
- return isObjectLike(value) && isArrayLike(value) &&
- hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee');
-}
+},{}],28:[function(require,module,exports){
+var arr = [];
+var each = arr.forEach;
+var slice = arr.slice;
-module.exports = isArguments;
-},{}],60:[function(require,module,exports){
-/**
- * lodash 3.0.1 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
+module.exports = function(obj) {
+ each.call(slice.call(arguments, 1), function(source) {
+ if (source) {
+ for (var prop in source) {
+ obj[prop] = source[prop];
+ }
+ }
+ });
+ return obj;
+};
-/**
- * A specialized version of `baseCallback` which only supports `this` binding
- * and specifying the number of arguments to provide to `func`.
- *
- * @private
- * @param {Function} func The function to bind.
- * @param {*} thisArg The `this` binding of `func`.
- * @param {number} [argCount] The number of arguments to provide to `func`.
- * @returns {Function} Returns the callback.
- */
-function bindCallback(func, thisArg, argCount) {
- if (typeof func != 'function') {
- return identity;
- }
- if (thisArg === undefined) {
- return func;
- }
- switch (argCount) {
- case 1: return function(value) {
- return func.call(thisArg, value);
- };
- case 3: return function(value, index, collection) {
- return func.call(thisArg, value, index, collection);
- };
- case 4: return function(accumulator, value, index, collection) {
- return func.call(thisArg, accumulator, value, index, collection);
- };
- case 5: return function(value, other, key, object, source) {
- return func.call(thisArg, value, other, key, object, source);
+},{}],29:[function(require,module,exports){
+var WildEmitter = require('wildemitter');
+var util = require('util');
+
+function Sender(opts) {
+ WildEmitter.call(this);
+ var options = opts || {};
+ this.config = {
+ chunksize: 16384,
+ pacing: 0
};
- }
- return function() {
- return func.apply(thisArg, arguments);
- };
-}
+ // set our config from options
+ var item;
+ for (item in options) {
+ this.config[item] = options[item];
+ }
-/**
- * This method returns the first argument provided to it.
- *
- * @static
- * @memberOf _
- * @category Utility
- * @param {*} value Any value.
- * @returns {*} Returns `value`.
- * @example
- *
- * var object = { 'user': 'fred' };
- *
- * _.identity(object) === object;
- * // => true
- */
-function identity(value) {
- return value;
+ this.file = null;
+ this.channel = null;
}
+util.inherits(Sender, WildEmitter);
-module.exports = bindCallback;
-
-},{}],61:[function(require,module,exports){
-/**
- * lodash 3.0.4 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-
-/** `Object#toString` result references. */
-var arrayTag = '[object Array]',
- funcTag = '[object Function]';
+Sender.prototype.send = function (file, channel) {
+ var self = this;
+ this.file = file;
+ this.channel = channel;
+ var sliceFile = function(offset) {
+ var reader = new window.FileReader();
+ reader.onload = (function() {
+ return function(e) {
+ self.channel.send(e.target.result);
+ self.emit('progress', offset, file.size, e.target.result);
+ if (file.size > offset + e.target.result.byteLength) {
+ window.setTimeout(sliceFile, self.config.pacing, offset + self.config.chunksize);
+ } else {
+ self.emit('progress', file.size, file.size, null);
+ self.emit('sentFile');
+ }
+ };
+ })(file);
+ var slice = file.slice(offset, offset + self.config.chunksize);
+ reader.readAsArrayBuffer(slice);
+ };
+ window.setTimeout(sliceFile, 0, 0);
+};
-/** Used to detect host constructors (Safari > 5). */
-var reIsHostCtor = /^\[object .+?Constructor\]$/;
+function Receiver() {
+ WildEmitter.call(this);
-/**
- * Checks if `value` is object-like.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
- */
-function isObjectLike(value) {
- return !!value && typeof value == 'object';
+ this.receiveBuffer = [];
+ this.received = 0;
+ this.metadata = {};
+ this.channel = null;
}
+util.inherits(Receiver, WildEmitter);
-/** Used for native method references. */
-var objectProto = Object.prototype;
+Receiver.prototype.receive = function (metadata, channel) {
+ var self = this;
-/** Used to resolve the decompiled source of functions. */
-var fnToString = Function.prototype.toString;
+ if (metadata) {
+ this.metadata = metadata;
+ }
+ this.channel = channel;
+ // chrome only supports arraybuffers and those make it easier to calc the hash
+ channel.binaryType = 'arraybuffer';
+ this.channel.onmessage = function (event) {
+ var len = event.data.byteLength;
+ self.received += len;
+ self.receiveBuffer.push(event.data);
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
+ self.emit('progress', self.received, self.metadata.size, event.data);
+ if (self.received === self.metadata.size) {
+ self.emit('receivedFile', new window.Blob(self.receiveBuffer), self.metadata);
+ self.receiveBuffer = []; // discard receivebuffer
+ } else if (self.received > self.metadata.size) {
+ // FIXME
+ console.error('received more than expected, discarding...');
+ self.receiveBuffer = []; // just discard...
-/**
- * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
- * of values.
- */
-var objToString = objectProto.toString;
+ }
+ };
+};
-/** Used to detect if a method is native. */
-var reIsNative = RegExp('^' +
- fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
- .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
-);
+module.exports = {};
+module.exports.support = typeof window !== 'undefined' && window && window.File && window.FileReader && window.Blob;
+module.exports.Sender = Sender;
+module.exports.Receiver = Receiver;
-/* Native method references for those with the same name as other `lodash` methods. */
-var nativeIsArray = getNative(Array, 'isArray');
+},{"util":197,"wildemitter":211}],30:[function(require,module,exports){
+var WildEmitter = require('wildemitter');
+var util = require('util');
+var hashes = require('iana-hashes');
+var base = require('./filetransfer');
-/**
- * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
- * of an array-like value.
- */
-var MAX_SAFE_INTEGER = 9007199254740991;
+// drop-in replacement for filetransfer which also calculates hashes
+function Sender(opts) {
+ WildEmitter.call(this);
+ var self = this;
+ this.base = new base.Sender(opts);
-/**
- * Gets the native function at `key` of `object`.
- *
- * @private
- * @param {Object} object The object to query.
- * @param {string} key The key of the method to get.
- * @returns {*} Returns the function if it's native, else `undefined`.
- */
-function getNative(object, key) {
- var value = object == null ? undefined : object[key];
- return isNative(value) ? value : undefined;
-}
+ var options = opts || {};
+ if (!options.hash) {
+ options.hash = 'sha-1';
+ }
+ this.hash = hashes.createHash(options.hash);
-/**
- * Checks if `value` is a valid array-like length.
- *
- * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
- */
-function isLength(value) {
- return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ this.base.on('progress', function (start, size, data) {
+ self.emit('progress', start, size, data);
+ if (data) {
+ self.hash.update(new Uint8Array(data));
+ }
+ });
+ this.base.on('sentFile', function () {
+ self.emit('sentFile', {hash: self.hash.digest('hex'), algo: options.hash });
+ });
}
-
-/**
- * Checks if `value` is classified as an `Array` object.
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
- * @example
- *
- * _.isArray([1, 2, 3]);
- * // => true
- *
- * _.isArray(function() { return arguments; }());
- * // => false
- */
-var isArray = nativeIsArray || function(value) {
- return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
+util.inherits(Sender, WildEmitter);
+Sender.prototype.send = function () {
+ this.base.send.apply(this.base, arguments);
};
-/**
- * Checks if `value` is classified as a `Function` object.
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
- * @example
- *
- * _.isFunction(_);
- * // => true
- *
- * _.isFunction(/abc/);
- * // => false
- */
-function isFunction(value) {
- // The use of `Object#toString` avoids issues with the `typeof` operator
- // in older versions of Chrome and Safari which return 'function' for regexes
- // and Safari 8 equivalents which return 'object' for typed array constructors.
- return isObject(value) && objToString.call(value) == funcTag;
-}
+function Receiver(opts) {
+ WildEmitter.call(this);
+ var self = this;
+ this.base = new base.Receiver(opts);
-/**
- * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
- * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an object, else `false`.
- * @example
- *
- * _.isObject({});
- * // => true
- *
- * _.isObject([1, 2, 3]);
- * // => true
- *
- * _.isObject(1);
- * // => false
- */
-function isObject(value) {
- // Avoid a V8 JIT bug in Chrome 19-20.
- // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
- var type = typeof value;
- return !!value && (type == 'object' || type == 'function');
-}
+ var options = opts || {};
+ if (!options.hash) {
+ options.hash = 'sha-1';
+ }
+ this.hash = hashes.createHash(options.hash);
-/**
- * Checks if `value` is a native function.
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
- * @example
- *
- * _.isNative(Array.prototype.push);
- * // => true
- *
- * _.isNative(_);
- * // => false
- */
-function isNative(value) {
- if (value == null) {
- return false;
- }
- if (isFunction(value)) {
- return reIsNative.test(fnToString.call(value));
- }
- return isObjectLike(value) && reIsHostCtor.test(value);
+ this.base.on('progress', function (start, size, data) {
+ self.emit('progress', start, size, data);
+ if (data) {
+ self.hash.update(new Uint8Array(data));
+ }
+ });
+ this.base.on('receivedFile', function (file, metadata) {
+ metadata.actualhash = self.hash.digest('hex');
+ self.emit('receivedFile', file, metadata);
+ });
}
+util.inherits(Receiver, WildEmitter);
+Receiver.prototype.receive = function () {
+ this.base.receive.apply(this.base, arguments);
+};
+Object.defineProperty(Receiver.prototype, 'metadata', {
+ get: function () {
+ return this.base.metadata;
+ },
+ set: function (value) {
+ this.base.metadata = value;
+ }
+});
-module.exports = isArray;
-
-},{}],62:[function(require,module,exports){
-/**
- * lodash 3.1.2 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-var baseGet = require('lodash._baseget'),
- toPath = require('lodash._topath'),
- isArray = require('lodash.isarray'),
- map = require('lodash.map');
+module.exports = {};
+module.exports.support = base.support;
+module.exports.Sender = Sender;
+module.exports.Receiver = Receiver;
-/** Used to match property names within property paths. */
-var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/,
- reIsPlainProp = /^\w*$/;
+},{"./filetransfer":29,"iana-hashes":42,"util":197,"wildemitter":211}],31:[function(require,module,exports){
+// getScreenMedia helper by @HenrikJoreteg
+var getUserMedia = require('getusermedia');
-/**
- * The base implementation of `_.property` without support for deep paths.
- *
- * @private
- * @param {string} key The key of the property to get.
- * @returns {Function} Returns the new function.
- */
-function baseProperty(key) {
- return function(object) {
- return object == null ? undefined : object[key];
- };
-}
+// cache for constraints and callback
+var cache = {};
-/**
- * A specialized version of `baseProperty` which supports deep paths.
- *
- * @private
- * @param {Array|string} path The path of the property to get.
- * @returns {Function} Returns the new function.
- */
-function basePropertyDeep(path) {
- var pathKey = (path + '');
- path = toPath(path);
- return function(object) {
- return baseGet(object, path, pathKey);
- };
-}
+module.exports = function (constraints, cb) {
+ var hasConstraints = arguments.length === 2;
+ var callback = hasConstraints ? cb : constraints;
+ var error;
+
+ if (typeof window === 'undefined' || window.location.protocol === 'http:') {
+ error = new Error('NavigatorUserMediaError');
+ error.name = 'HTTPS_REQUIRED';
+ return callback(error);
+ }
+
+ if (window.navigator.userAgent.match('Chrome')) {
+ var chromever = parseInt(window.navigator.userAgent.match(/Chrome\/(.*) /)[1], 10);
+ var maxver = 33;
+ var isCef = !window.chrome.webstore;
+ // "known" crash in chrome 34 and 35 on linux
+ if (window.navigator.userAgent.match('Linux')) maxver = 35;
+
+ // check that the extension is installed by looking for a
+ // sessionStorage variable that contains the extension id
+ // this has to be set after installation unless the contest
+ // script does that
+ if (sessionStorage.getScreenMediaJSExtensionId) {
+ chrome.runtime.sendMessage(sessionStorage.getScreenMediaJSExtensionId,
+ {type:'getScreen', id: 1}, null,
+ function (data) {
+ if (!data || data.sourceId === '') { // user canceled
+ var error = new Error('NavigatorUserMediaError');
+ error.name = 'PERMISSION_DENIED';
+ callback(error);
+ } else {
+ constraints = (hasConstraints && constraints) || {audio: false, video: {
+ mandatory: {
+ chromeMediaSource: 'desktop',
+ maxWidth: window.screen.width,
+ maxHeight: window.screen.height,
+ maxFrameRate: 3
+ }
+ }};
+ constraints.video.mandatory.chromeMediaSourceId = data.sourceId;
+ getUserMedia(constraints, callback);
+ }
+ }
+ );
+ } else if (window.cefGetScreenMedia) {
+ //window.cefGetScreenMedia is experimental - may be removed without notice
+ window.cefGetScreenMedia(function(sourceId) {
+ if (!sourceId) {
+ var error = new Error('cefGetScreenMediaError');
+ error.name = 'CEF_GETSCREENMEDIA_CANCELED';
+ callback(error);
+ } else {
+ constraints = (hasConstraints && constraints) || {audio: false, video: {
+ mandatory: {
+ chromeMediaSource: 'desktop',
+ maxWidth: window.screen.width,
+ maxHeight: window.screen.height,
+ maxFrameRate: 3
+ },
+ optional: [
+ {googLeakyBucket: true},
+ {googTemporalLayeredScreencast: true}
+ ]
+ }};
+ constraints.video.mandatory.chromeMediaSourceId = sourceId;
+ getUserMedia(constraints, callback);
+ }
+ });
+ } else if (isCef || (chromever >= 26 && chromever <= maxver)) {
+ // chrome 26 - chrome 33 way to do it -- requires bad chrome://flags
+ // note: this is basically in maintenance mode and will go away soon
+ constraints = (hasConstraints && constraints) || {
+ video: {
+ mandatory: {
+ googLeakyBucket: true,
+ maxWidth: window.screen.width,
+ maxHeight: window.screen.height,
+ maxFrameRate: 3,
+ chromeMediaSource: 'screen'
+ }
+ }
+ };
+ getUserMedia(constraints, callback);
+ } else {
+ // chrome 34+ way requiring an extension
+ var pending = window.setTimeout(function () {
+ error = new Error('NavigatorUserMediaError');
+ error.name = 'EXTENSION_UNAVAILABLE';
+ return callback(error);
+ }, 1000);
+ cache[pending] = [callback, hasConstraints ? constraints : null];
+ window.postMessage({ type: 'getScreen', id: pending }, '*');
+ }
+ } else if (window.navigator.userAgent.match('Firefox')) {
+ var ffver = parseInt(window.navigator.userAgent.match(/Firefox\/(.*)/)[1], 10);
+ if (ffver >= 33) {
+ constraints = (hasConstraints && constraints) || {
+ video: {
+ mozMediaSource: 'window',
+ mediaSource: 'window'
+ }
+ };
+ getUserMedia(constraints, function (err, stream) {
+ callback(err, stream);
+ // workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1045810
+ if (!err) {
+ var lastTime = stream.currentTime;
+ var polly = window.setInterval(function () {
+ if (!stream) window.clearInterval(polly);
+ if (stream.currentTime == lastTime) {
+ window.clearInterval(polly);
+ if (stream.onended) {
+ stream.onended();
+ }
+ }
+ lastTime = stream.currentTime;
+ }, 500);
+ }
+ });
+ } else {
+ error = new Error('NavigatorUserMediaError');
+ error.name = 'EXTENSION_UNAVAILABLE'; // does not make much sense but...
+ }
+ }
+};
-/**
- * Checks if `value` is a property name and not a property path.
- *
- * @private
- * @param {*} value The value to check.
- * @param {Object} [object] The object to query keys on.
- * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
- */
-function isKey(value, object) {
- var type = typeof value;
- if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') {
- return true;
- }
- if (isArray(value)) {
- return false;
- }
- var result = !reIsDeepProp.test(value);
- return result || (object != null && value in toObject(object));
-}
+window.addEventListener('message', function (event) {
+ if (event.origin != window.location.origin) {
+ return;
+ }
+ if (event.data.type == 'gotScreen' && cache[event.data.id]) {
+ var data = cache[event.data.id];
+ var constraints = data[1];
+ var callback = data[0];
+ delete cache[event.data.id];
-/**
- * Converts `value` to an object if it's not one.
- *
- * @private
- * @param {*} value The value to process.
- * @returns {Object} Returns the object.
- */
-function toObject(value) {
- return isObject(value) ? value : Object(value);
-}
+ if (event.data.sourceId === '') { // user canceled
+ var error = new Error('NavigatorUserMediaError');
+ error.name = 'PERMISSION_DENIED';
+ callback(error);
+ } else {
+ constraints = constraints || {audio: false, video: {
+ mandatory: {
+ chromeMediaSource: 'desktop',
+ maxWidth: window.screen.width,
+ maxHeight: window.screen.height,
+ maxFrameRate: 3
+ },
+ optional: [
+ {googLeakyBucket: true},
+ {googTemporalLayeredScreencast: true}
+ ]
+ }};
+ constraints.video.mandatory.chromeMediaSourceId = event.data.sourceId;
+ getUserMedia(constraints, callback);
+ }
+ } else if (event.data.type == 'getScreenPending') {
+ window.clearTimeout(event.data.id);
+ }
+});
-/**
- * Gets the property value of `path` from all elements in `collection`.
- *
- * @static
- * @memberOf _
- * @category Collection
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Array|string} path The path of the property to pluck.
- * @returns {Array} Returns the property values.
- * @example
- *
- * var users = [
- * { 'user': 'barney', 'age': 36 },
- * { 'user': 'fred', 'age': 40 }
- * ];
- *
- * _.pluck(users, 'user');
- * // => ['barney', 'fred']
- *
- * var userIndex = _.indexBy(users, 'user');
- * _.pluck(userIndex, 'age');
- * // => [36, 40] (iteration order is not guaranteed)
- */
-function pluck(collection, path) {
- return map(collection, property(path));
-}
+},{"getusermedia":32}],32:[function(require,module,exports){
+// getUserMedia helper by @HenrikJoreteg used for navigator.getUserMedia shim
+var adapter = require('webrtc-adapter');
+
+module.exports = function (constraints, cb) {
+ var error;
+ var haveOpts = arguments.length === 2;
+ var defaultOpts = {video: true, audio: true};
+
+ var denied = 'PermissionDeniedError';
+ var altDenied = 'PERMISSION_DENIED';
+ var notSatisfied = 'ConstraintNotSatisfiedError';
+
+ // make constraints optional
+ if (!haveOpts) {
+ cb = constraints;
+ constraints = defaultOpts;
+ }
+
+ // treat lack of browser support like an error
+ if (typeof navigator === 'undefined' || !navigator.getUserMedia) {
+ // throw proper error per spec
+ error = new Error('MediaStreamError');
+ error.name = 'NotSupportedError';
+
+ // keep all callbacks async
+ return setTimeout(function () {
+ cb(error);
+ }, 0);
+ }
+
+ // normalize error handling when no media types are requested
+ if (!constraints.audio && !constraints.video) {
+ error = new Error('MediaStreamError');
+ error.name = 'NoMediaRequestedError';
+
+ // keep all callbacks async
+ return setTimeout(function () {
+ cb(error);
+ }, 0);
+ }
+
+ navigator.mediaDevices.getUserMedia(constraints)
+ .then(function (stream) {
+ cb(null, stream);
+ }).catch(function (err) {
+ var error;
+ // coerce into an error object since FF gives us a string
+ // there are only two valid names according to the spec
+ // we coerce all non-denied to "constraint not satisfied".
+ if (typeof err === 'string') {
+ error = new Error('MediaStreamError');
+ if (err === denied || err === altDenied) {
+ error.name = denied;
+ } else {
+ error.name = notSatisfied;
+ }
+ } else {
+ // if we get an error object make sure '.name' property is set
+ // according to spec: http://dev.w3.org/2011/webrtc/editor/getusermedia.html#navigatorusermediaerror-and-navigatorusermediaerrorcallback
+ error = err;
+ if (!error.name) {
+ // this is likely chrome which
+ // sets a property called "ERROR_DENIED" on the error object
+ // if so we make sure to set a name
+ if (error[denied]) {
+ err.name = denied;
+ } else {
+ err.name = notSatisfied;
+ }
+ }
+ }
-/**
- * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
- * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an object, else `false`.
- * @example
- *
- * _.isObject({});
- * // => true
- *
- * _.isObject([1, 2, 3]);
- * // => true
- *
- * _.isObject(1);
- * // => false
- */
-function isObject(value) {
- // Avoid a V8 JIT bug in Chrome 19-20.
- // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
- var type = typeof value;
- return !!value && (type == 'object' || type == 'function');
-}
+ cb(error);
+ });
+};
-/**
- * Creates a function which returns the property value at `path` on a
- * given object.
- *
- * @static
- * @memberOf _
- * @category Utility
- * @param {Array|string} path The path of the property to get.
- * @returns {Function} Returns the new function.
- * @example
- *
- * var objects = [
- * { 'a': { 'b': { 'c': 2 } } },
- * { 'a': { 'b': { 'c': 1 } } }
- * ];
- *
- * _.map(objects, _.property('a.b.c'));
- * // => [2, 1]
+},{"webrtc-adapter":33}],33:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
- * _.pluck(_.sortBy(objects, _.property(['a', 'b', 'c'])), 'a.b.c');
- * // => [1, 2]
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
*/
-function property(path) {
- return isKey(path) ? baseProperty(path) : basePropertyDeep(path);
-}
+ /* eslint-env node */
-module.exports = pluck;
+'use strict';
-},{"lodash._baseget":63,"lodash._topath":64,"lodash.isarray":65,"lodash.map":66}],63:[function(require,module,exports){
-/**
- * lodash 3.7.2 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
+// Shimming starts here.
+(function() {
+ // Utils.
+ var logging = require('./utils').log;
+ var browserDetails = require('./utils').browserDetails;
+ // Export to the adapter global object visible in the browser.
+ module.exports.browserDetails = browserDetails;
+ module.exports.extractVersion = require('./utils').extractVersion;
+ module.exports.disableLog = require('./utils').disableLog;
+
+ // Uncomment the line below if you want logging to occur, including logging
+ // for the switch statement below. Can also be turned on in the browser via
+ // adapter.disableLog(false), but then logging from the switch statement below
+ // will not appear.
+ // require('./utils').disableLog(false);
+
+ // Browser shims.
+ var chromeShim = require('./chrome/chrome_shim') || null;
+ var edgeShim = require('./edge/edge_shim') || null;
+ var firefoxShim = require('./firefox/firefox_shim') || null;
+ var safariShim = require('./safari/safari_shim') || null;
+
+ // Shim browser if found.
+ switch (browserDetails.browser) {
+ case 'opera': // fallthrough as it uses chrome shims
+ case 'chrome':
+ if (!chromeShim || !chromeShim.shimPeerConnection) {
+ logging('Chrome shim is not included in this adapter release.');
+ return;
+ }
+ logging('adapter.js shimming chrome.');
+ // Export to the adapter global object visible in the browser.
+ module.exports.browserShim = chromeShim;
+
+ chromeShim.shimGetUserMedia();
+ chromeShim.shimMediaStream();
+ chromeShim.shimSourceObject();
+ chromeShim.shimPeerConnection();
+ chromeShim.shimOnTrack();
+ break;
+ case 'firefox':
+ if (!firefoxShim || !firefoxShim.shimPeerConnection) {
+ logging('Firefox shim is not included in this adapter release.');
+ return;
+ }
+ logging('adapter.js shimming firefox.');
+ // Export to the adapter global object visible in the browser.
+ module.exports.browserShim = firefoxShim;
+
+ firefoxShim.shimGetUserMedia();
+ firefoxShim.shimSourceObject();
+ firefoxShim.shimPeerConnection();
+ firefoxShim.shimOnTrack();
+ break;
+ case 'edge':
+ if (!edgeShim || !edgeShim.shimPeerConnection) {
+ logging('MS edge shim is not included in this adapter release.');
+ return;
+ }
+ logging('adapter.js shimming edge.');
+ // Export to the adapter global object visible in the browser.
+ module.exports.browserShim = edgeShim;
-/**
- * The base implementation of `get` without support for string paths
- * and default values.
- *
- * @private
- * @param {Object} object The object to query.
- * @param {Array} path The path of the property to get.
- * @param {string} [pathKey] The key representation of path.
- * @returns {*} Returns the resolved value.
- */
-function baseGet(object, path, pathKey) {
- if (object == null) {
- return;
- }
- if (pathKey !== undefined && pathKey in toObject(object)) {
- path = [pathKey];
- }
- var index = 0,
- length = path.length;
+ edgeShim.shimGetUserMedia();
+ edgeShim.shimPeerConnection();
+ break;
+ case 'safari':
+ if (!safariShim) {
+ logging('Safari shim is not included in this adapter release.');
+ return;
+ }
+ logging('adapter.js shimming safari.');
+ // Export to the adapter global object visible in the browser.
+ module.exports.browserShim = safariShim;
- while (object != null && index < length) {
- object = object[path[index++]];
+ safariShim.shimGetUserMedia();
+ break;
+ default:
+ logging('Unsupported browser!');
}
- return (index && index == length) ? object : undefined;
-}
-
-/**
- * Converts `value` to an object if it's not one.
- *
- * @private
- * @param {*} value The value to process.
- * @returns {Object} Returns the object.
- */
-function toObject(value) {
- return isObject(value) ? value : Object(value);
-}
-
-/**
- * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
- * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an object, else `false`.
- * @example
- *
- * _.isObject({});
- * // => true
- *
- * _.isObject([1, 2, 3]);
- * // => true
- *
- * _.isObject(1);
- * // => false
- */
-function isObject(value) {
- // Avoid a V8 JIT bug in Chrome 19-20.
- // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
- var type = typeof value;
- return !!value && (type == 'object' || type == 'function');
-}
+})();
-module.exports = baseGet;
+},{"./chrome/chrome_shim":34,"./edge/edge_shim":36,"./firefox/firefox_shim":38,"./safari/safari_shim":40,"./utils":41}],34:[function(require,module,exports){
-},{}],64:[function(require,module,exports){
-/**
- * lodash 3.8.1 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-var isArray = require('lodash.isarray');
-
-/** Used to match property names within property paths. */
-var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g;
-
-/** Used to match backslashes in property paths. */
-var reEscapeChar = /\\(\\)?/g;
-
-/**
- * Converts `value` to a string if it's not one. An empty string is returned
- * for `null` or `undefined` values.
- *
- * @private
- * @param {*} value The value to process.
- * @returns {string} Returns the string.
- */
-function baseToString(value) {
- return value == null ? '' : (value + '');
-}
-
-/**
- * Converts `value` to property path array if it's not one.
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
- * @private
- * @param {*} value The value to process.
- * @returns {Array} Returns the property path array.
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
*/
-function toPath(value) {
- if (isArray(value)) {
- return value;
- }
- var result = [];
- baseToString(value).replace(rePropName, function(match, number, quote, string) {
- result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
- });
- return result;
-}
-
-module.exports = toPath;
+ /* eslint-env node */
+'use strict';
+var logging = require('../utils.js').log;
+var browserDetails = require('../utils.js').browserDetails;
-},{"lodash.isarray":65}],65:[function(require,module,exports){
-arguments[4][61][0].apply(exports,arguments)
-},{"dup":61}],66:[function(require,module,exports){
-/**
- * lodash 3.1.4 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-var arrayMap = require('lodash._arraymap'),
- baseCallback = require('lodash._basecallback'),
- baseEach = require('lodash._baseeach'),
- isArray = require('lodash.isarray');
+var chromeShim = {
+ shimMediaStream: function() {
+ window.MediaStream = window.MediaStream || window.webkitMediaStream;
+ },
-/**
- * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer)
- * of an array-like value.
- */
-var MAX_SAFE_INTEGER = 9007199254740991;
+ shimOnTrack: function() {
+ if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in
+ window.RTCPeerConnection.prototype)) {
+ Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
+ get: function() {
+ return this._ontrack;
+ },
+ set: function(f) {
+ var self = this;
+ if (this._ontrack) {
+ this.removeEventListener('track', this._ontrack);
+ this.removeEventListener('addstream', this._ontrackpoly);
+ }
+ this.addEventListener('track', this._ontrack = f);
+ this.addEventListener('addstream', this._ontrackpoly = function(e) {
+ // onaddstream does not fire when a track is added to an existing
+ // stream. But stream.onaddtrack is implemented so we use that.
+ e.stream.addEventListener('addtrack', function(te) {
+ var event = new Event('track');
+ event.track = te.track;
+ event.receiver = {track: te.track};
+ event.streams = [e.stream];
+ self.dispatchEvent(event);
+ });
+ e.stream.getTracks().forEach(function(track) {
+ var event = new Event('track');
+ event.track = track;
+ event.receiver = {track: track};
+ event.streams = [e.stream];
+ this.dispatchEvent(event);
+ }.bind(this));
+ }.bind(this));
+ }
+ });
+ }
+ },
-/**
- * The base implementation of `_.map` without support for callback shorthands
- * and `this` binding.
- *
- * @private
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} iteratee The function invoked per iteration.
- * @returns {Array} Returns the new mapped array.
- */
-function baseMap(collection, iteratee) {
- var index = -1,
- result = isArrayLike(collection) ? Array(collection.length) : [];
+ shimSourceObject: function() {
+ if (typeof window === 'object') {
+ if (window.HTMLMediaElement &&
+ !('srcObject' in window.HTMLMediaElement.prototype)) {
+ // Shim the srcObject property, once, when HTMLMediaElement is found.
+ Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
+ get: function() {
+ return this._srcObject;
+ },
+ set: function(stream) {
+ var self = this;
+ // Use _srcObject as a private property for this shim
+ this._srcObject = stream;
+ if (this.src) {
+ URL.revokeObjectURL(this.src);
+ }
- baseEach(collection, function(value, key, collection) {
- result[++index] = iteratee(value, key, collection);
- });
- return result;
-}
+ if (!stream) {
+ this.src = '';
+ return;
+ }
+ this.src = URL.createObjectURL(stream);
+ // We need to recreate the blob url when a track is added or
+ // removed. Doing it manually since we want to avoid a recursion.
+ stream.addEventListener('addtrack', function() {
+ if (self.src) {
+ URL.revokeObjectURL(self.src);
+ }
+ self.src = URL.createObjectURL(stream);
+ });
+ stream.addEventListener('removetrack', function() {
+ if (self.src) {
+ URL.revokeObjectURL(self.src);
+ }
+ self.src = URL.createObjectURL(stream);
+ });
+ }
+ });
+ }
+ }
+ },
-/**
- * The base implementation of `_.property` without support for deep paths.
- *
- * @private
- * @param {string} key The key of the property to get.
- * @returns {Function} Returns the new function.
- */
-function baseProperty(key) {
- return function(object) {
- return object == null ? undefined : object[key];
- };
-}
+ shimPeerConnection: function() {
+ // The RTCPeerConnection object.
+ window.RTCPeerConnection = function(pcConfig, pcConstraints) {
+ // Translate iceTransportPolicy to iceTransports,
+ // see https://code.google.com/p/webrtc/issues/detail?id=4869
+ logging('PeerConnection');
+ if (pcConfig && pcConfig.iceTransportPolicy) {
+ pcConfig.iceTransports = pcConfig.iceTransportPolicy;
+ }
-/**
- * Gets the "length" property value of `object`.
- *
- * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
- * that affects Safari on at least iOS 8.1-8.3 ARM64.
- *
- * @private
- * @param {Object} object The object to query.
- * @returns {*} Returns the "length" value.
- */
-var getLength = baseProperty('length');
+ var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints);
+ var origGetStats = pc.getStats.bind(pc);
+ pc.getStats = function(selector, successCallback, errorCallback) {
+ var self = this;
+ var args = arguments;
+
+ // If selector is a function then we are in the old style stats so just
+ // pass back the original getStats format to avoid breaking old users.
+ if (arguments.length > 0 && typeof selector === 'function') {
+ return origGetStats(selector, successCallback);
+ }
+
+ var fixChromeStats_ = function(response) {
+ var standardReport = {};
+ var reports = response.result();
+ reports.forEach(function(report) {
+ var standardStats = {
+ id: report.id,
+ timestamp: report.timestamp,
+ type: report.type
+ };
+ report.names().forEach(function(name) {
+ standardStats[name] = report.stat(name);
+ });
+ standardReport[standardStats.id] = standardStats;
+ });
-/**
- * Checks if `value` is array-like.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
- */
-function isArrayLike(value) {
- return value != null && isLength(getLength(value));
-}
+ return standardReport;
+ };
-/**
- * Checks if `value` is a valid array-like length.
- *
- * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength).
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
- */
-function isLength(value) {
- return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
-}
+ // shim getStats with maplike support
+ var makeMapStats = function(stats, legacyStats) {
+ var map = new Map(Object.keys(stats).map(function(key) {
+ return[key, stats[key]];
+ }));
+ legacyStats = legacyStats || stats;
+ Object.keys(legacyStats).forEach(function(key) {
+ map[key] = legacyStats[key];
+ });
+ return map;
+ };
-/**
- * Creates an array of values by running each element in `collection` through
- * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three
- * arguments: (value, index|key, collection).
- *
- * If a property name is provided for `iteratee` the created `_.property`
- * style callback returns the property value of the given element.
- *
- * If a value is also provided for `thisArg` the created `_.matchesProperty`
- * style callback returns `true` for elements that have a matching property
- * value, else `false`.
- *
- * If an object is provided for `iteratee` the created `_.matches` style
- * callback returns `true` for elements that have the properties of the given
- * object, else `false`.
- *
- * Many lodash methods are guarded to work as iteratees for methods like
- * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
- *
- * The guarded methods are:
- * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`,
- * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`,
- * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`,
- * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`,
- * `sum`, `uniq`, and `words`
- *
- * @static
- * @memberOf _
- * @alias collect
- * @category Collection
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [iteratee=_.identity] The function invoked
- * per iteration.
- * @param {*} [thisArg] The `this` binding of `iteratee`.
- * @returns {Array} Returns the new mapped array.
- * @example
- *
- * function timesThree(n) {
- * return n * 3;
- * }
- *
- * _.map([1, 2], timesThree);
- * // => [3, 6]
- *
- * _.map({ 'a': 1, 'b': 2 }, timesThree);
- * // => [3, 6] (iteration order is not guaranteed)
- *
- * var users = [
- * { 'user': 'barney' },
- * { 'user': 'fred' }
- * ];
- *
- * // using the `_.property` callback shorthand
- * _.map(users, 'user');
- * // => ['barney', 'fred']
- */
-function map(collection, iteratee, thisArg) {
- var func = isArray(collection) ? arrayMap : baseMap;
- iteratee = baseCallback(iteratee, thisArg, 3);
- return func(collection, iteratee);
-}
+ if (arguments.length >= 2) {
+ var successCallbackWrapper_ = function(response) {
+ args[1](makeMapStats(fixChromeStats_(response)));
+ };
-module.exports = map;
+ return origGetStats.apply(this, [successCallbackWrapper_,
+ arguments[0]]);
+ }
-},{"lodash._arraymap":67,"lodash._basecallback":68,"lodash._baseeach":73,"lodash.isarray":65}],67:[function(require,module,exports){
-/**
- * lodash 3.0.0 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
+ // promise-support
+ return new Promise(function(resolve, reject) {
+ if (args.length === 1 && typeof selector === 'object') {
+ origGetStats.apply(self, [
+ function(response) {
+ resolve(makeMapStats(fixChromeStats_(response)));
+ }, reject]);
+ } else {
+ // Preserve legacy chrome stats only on legacy access of stats obj
+ origGetStats.apply(self, [
+ function(response) {
+ resolve(makeMapStats(fixChromeStats_(response),
+ response.result()));
+ }, reject]);
+ }
+ }).then(successCallback, errorCallback);
+ };
-/**
- * A specialized version of `_.map` for arrays without support for callback
- * shorthands or `this` binding.
- *
- * @private
- * @param {Array} array The array to iterate over.
- * @param {Function} iteratee The function invoked per iteration.
- * @returns {Array} Returns the new mapped array.
- */
-function arrayMap(array, iteratee) {
- var index = -1,
- length = array.length,
- result = Array(length);
+ return pc;
+ };
+ window.RTCPeerConnection.prototype = webkitRTCPeerConnection.prototype;
- while (++index < length) {
- result[index] = iteratee(array[index], index, array);
- }
- return result;
-}
+ // wrap static methods. Currently just generateCertificate.
+ if (webkitRTCPeerConnection.generateCertificate) {
+ Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
+ get: function() {
+ return webkitRTCPeerConnection.generateCertificate;
+ }
+ });
+ }
-module.exports = arrayMap;
+ ['createOffer', 'createAnswer'].forEach(function(method) {
+ var nativeMethod = webkitRTCPeerConnection.prototype[method];
+ webkitRTCPeerConnection.prototype[method] = function() {
+ var self = this;
+ if (arguments.length < 1 || (arguments.length === 1 &&
+ typeof arguments[0] === 'object')) {
+ var opts = arguments.length === 1 ? arguments[0] : undefined;
+ return new Promise(function(resolve, reject) {
+ nativeMethod.apply(self, [resolve, reject, opts]);
+ });
+ }
+ return nativeMethod.apply(this, arguments);
+ };
+ });
-},{}],68:[function(require,module,exports){
-/**
- * lodash 3.3.1 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-var baseIsEqual = require('lodash._baseisequal'),
- bindCallback = require('lodash._bindcallback'),
- isArray = require('lodash.isarray'),
- pairs = require('lodash.pairs');
+ // add promise support -- natively available in Chrome 51
+ if (browserDetails.version < 51) {
+ ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
+ .forEach(function(method) {
+ var nativeMethod = webkitRTCPeerConnection.prototype[method];
+ webkitRTCPeerConnection.prototype[method] = function() {
+ var args = arguments;
+ var self = this;
+ var promise = new Promise(function(resolve, reject) {
+ nativeMethod.apply(self, [args[0], resolve, reject]);
+ });
+ if (args.length < 2) {
+ return promise;
+ }
+ return promise.then(function() {
+ args[1].apply(null, []);
+ },
+ function(err) {
+ if (args.length >= 3) {
+ args[2].apply(null, [err]);
+ }
+ });
+ };
+ });
+ }
-/** Used to match property names within property paths. */
-var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/,
- reIsPlainProp = /^\w*$/,
- rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g;
+ // support for addIceCandidate(null)
+ var nativeAddIceCandidate =
+ RTCPeerConnection.prototype.addIceCandidate;
+ RTCPeerConnection.prototype.addIceCandidate = function() {
+ return arguments[0] === null ? Promise.resolve()
+ : nativeAddIceCandidate.apply(this, arguments);
+ };
-/** Used to match backslashes in property paths. */
-var reEscapeChar = /\\(\\)?/g;
+ // shim implicit creation of RTCSessionDescription/RTCIceCandidate
+ ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
+ .forEach(function(method) {
+ var nativeMethod = webkitRTCPeerConnection.prototype[method];
+ webkitRTCPeerConnection.prototype[method] = function() {
+ arguments[0] = new ((method === 'addIceCandidate') ?
+ RTCIceCandidate : RTCSessionDescription)(arguments[0]);
+ return nativeMethod.apply(this, arguments);
+ };
+ });
+ },
-/**
- * Converts `value` to a string if it's not one. An empty string is returned
- * for `null` or `undefined` values.
- *
- * @private
- * @param {*} value The value to process.
- * @returns {string} Returns the string.
- */
-function baseToString(value) {
- return value == null ? '' : (value + '');
-}
+ // Attach a media stream to an element.
+ attachMediaStream: function(element, stream) {
+ logging('DEPRECATED, attachMediaStream will soon be removed.');
+ if (browserDetails.version >= 43) {
+ element.srcObject = stream;
+ } else if (typeof element.src !== 'undefined') {
+ element.src = URL.createObjectURL(stream);
+ } else {
+ logging('Error attaching stream to element.');
+ }
+ },
-/**
- * The base implementation of `_.callback` which supports specifying the
- * number of arguments to provide to `func`.
- *
- * @private
- * @param {*} [func=_.identity] The value to convert to a callback.
- * @param {*} [thisArg] The `this` binding of `func`.
- * @param {number} [argCount] The number of arguments to provide to `func`.
- * @returns {Function} Returns the callback.
- */
-function baseCallback(func, thisArg, argCount) {
- var type = typeof func;
- if (type == 'function') {
- return thisArg === undefined
- ? func
- : bindCallback(func, thisArg, argCount);
- }
- if (func == null) {
- return identity;
- }
- if (type == 'object') {
- return baseMatches(func);
+ reattachMediaStream: function(to, from) {
+ logging('DEPRECATED, reattachMediaStream will soon be removed.');
+ if (browserDetails.version >= 43) {
+ to.srcObject = from.srcObject;
+ } else {
+ to.src = from.src;
+ }
}
- return thisArg === undefined
- ? property(func)
- : baseMatchesProperty(func, thisArg);
-}
+};
-/**
- * The base implementation of `get` without support for string paths
- * and default values.
- *
- * @private
- * @param {Object} object The object to query.
- * @param {Array} path The path of the property to get.
- * @param {string} [pathKey] The key representation of path.
- * @returns {*} Returns the resolved value.
- */
-function baseGet(object, path, pathKey) {
- if (object == null) {
- return;
- }
- if (pathKey !== undefined && pathKey in toObject(object)) {
- path = [pathKey];
- }
- var index = 0,
- length = path.length;
- while (object != null && index < length) {
- object = object[path[index++]];
- }
- return (index && index == length) ? object : undefined;
-}
+// Expose public methods.
+module.exports = {
+ shimMediaStream: chromeShim.shimMediaStream,
+ shimOnTrack: chromeShim.shimOnTrack,
+ shimSourceObject: chromeShim.shimSourceObject,
+ shimPeerConnection: chromeShim.shimPeerConnection,
+ shimGetUserMedia: require('./getusermedia'),
+ attachMediaStream: chromeShim.attachMediaStream,
+ reattachMediaStream: chromeShim.reattachMediaStream
+};
-/**
- * The base implementation of `_.isMatch` without support for callback
- * shorthands and `this` binding.
+},{"../utils.js":41,"./getusermedia":35}],35:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
- * @private
- * @param {Object} object The object to inspect.
- * @param {Array} matchData The propery names, values, and compare flags to match.
- * @param {Function} [customizer] The function to customize comparing objects.
- * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
*/
-function baseIsMatch(object, matchData, customizer) {
- var index = matchData.length,
- length = index,
- noCustomizer = !customizer;
+ /* eslint-env node */
+'use strict';
+var logging = require('../utils.js').log;
- if (object == null) {
- return !length;
- }
- object = toObject(object);
- while (index--) {
- var data = matchData[index];
- if ((noCustomizer && data[2])
- ? data[1] !== object[data[0]]
- : !(data[0] in object)
- ) {
- return false;
+// Expose public methods.
+module.exports = function() {
+ var constraintsToChrome_ = function(c) {
+ if (typeof c !== 'object' || c.mandatory || c.optional) {
+ return c;
}
- }
- while (++index < length) {
- data = matchData[index];
- var key = data[0],
- objValue = object[key],
- srcValue = data[1];
-
- if (noCustomizer && data[2]) {
- if (objValue === undefined && !(key in object)) {
- return false;
+ var cc = {};
+ Object.keys(c).forEach(function(key) {
+ if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
+ return;
}
- } else {
- var result = customizer ? customizer(objValue, srcValue, key) : undefined;
- if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, true) : result)) {
- return false;
+ var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]};
+ if (r.exact !== undefined && typeof r.exact === 'number') {
+ r.min = r.max = r.exact;
}
- }
- }
- return true;
-}
-
-/**
- * The base implementation of `_.matches` which does not clone `source`.
- *
- * @private
- * @param {Object} source The object of property values to match.
- * @returns {Function} Returns the new function.
- */
-function baseMatches(source) {
- var matchData = getMatchData(source);
- if (matchData.length == 1 && matchData[0][2]) {
- var key = matchData[0][0],
- value = matchData[0][1];
-
- return function(object) {
- if (object == null) {
- return false;
+ var oldname_ = function(prefix, name) {
+ if (prefix) {
+ return prefix + name.charAt(0).toUpperCase() + name.slice(1);
+ }
+ return (name === 'deviceId') ? 'sourceId' : name;
+ };
+ if (r.ideal !== undefined) {
+ cc.optional = cc.optional || [];
+ var oc = {};
+ if (typeof r.ideal === 'number') {
+ oc[oldname_('min', key)] = r.ideal;
+ cc.optional.push(oc);
+ oc = {};
+ oc[oldname_('max', key)] = r.ideal;
+ cc.optional.push(oc);
+ } else {
+ oc[oldname_('', key)] = r.ideal;
+ cc.optional.push(oc);
+ }
}
- return object[key] === value && (value !== undefined || (key in toObject(object)));
- };
- }
- return function(object) {
- return baseIsMatch(object, matchData);
+ if (r.exact !== undefined && typeof r.exact !== 'number') {
+ cc.mandatory = cc.mandatory || {};
+ cc.mandatory[oldname_('', key)] = r.exact;
+ } else {
+ ['min', 'max'].forEach(function(mix) {
+ if (r[mix] !== undefined) {
+ cc.mandatory = cc.mandatory || {};
+ cc.mandatory[oldname_(mix, key)] = r[mix];
+ }
+ });
+ }
+ });
+ if (c.advanced) {
+ cc.optional = (cc.optional || []).concat(c.advanced);
+ }
+ return cc;
};
-}
-
-/**
- * The base implementation of `_.matchesProperty` which does not clone `srcValue`.
- *
- * @private
- * @param {string} path The path of the property to get.
- * @param {*} srcValue The value to compare.
- * @returns {Function} Returns the new function.
- */
-function baseMatchesProperty(path, srcValue) {
- var isArr = isArray(path),
- isCommon = isKey(path) && isStrictComparable(srcValue),
- pathKey = (path + '');
- path = toPath(path);
- return function(object) {
- if (object == null) {
- return false;
- }
- var key = pathKey;
- object = toObject(object);
- if ((isArr || !isCommon) && !(key in object)) {
- object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
- if (object == null) {
- return false;
+ var shimConstraints_ = function(constraints, func) {
+ constraints = JSON.parse(JSON.stringify(constraints));
+ if (constraints && constraints.audio) {
+ constraints.audio = constraintsToChrome_(constraints.audio);
+ }
+ if (constraints && typeof constraints.video === 'object') {
+ // Shim facingMode for mobile, where it defaults to "user".
+ var face = constraints.video.facingMode;
+ face = face && ((typeof face === 'object') ? face : {ideal: face});
+
+ if ((face && (face.exact === 'user' || face.exact === 'environment' ||
+ face.ideal === 'user' || face.ideal === 'environment')) &&
+ !(navigator.mediaDevices.getSupportedConstraints &&
+ navigator.mediaDevices.getSupportedConstraints().facingMode)) {
+ delete constraints.video.facingMode;
+ if (face.exact === 'environment' || face.ideal === 'environment') {
+ // Look for "back" in label, or use last cam (typically back cam).
+ return navigator.mediaDevices.enumerateDevices()
+ .then(function(devices) {
+ devices = devices.filter(function(d) {
+ return d.kind === 'videoinput';
+ });
+ var back = devices.find(function(d) {
+ return d.label.toLowerCase().indexOf('back') !== -1;
+ }) || (devices.length && devices[devices.length - 1]);
+ if (back) {
+ constraints.video.deviceId = face.exact ? {exact: back.deviceId} :
+ {ideal: back.deviceId};
+ }
+ constraints.video = constraintsToChrome_(constraints.video);
+ logging('chrome: ' + JSON.stringify(constraints));
+ return func(constraints);
+ });
+ }
}
- key = last(path);
- object = toObject(object);
+ constraints.video = constraintsToChrome_(constraints.video);
}
- return object[key] === srcValue
- ? (srcValue !== undefined || (key in object))
- : baseIsEqual(srcValue, object[key], undefined, true);
+ logging('chrome: ' + JSON.stringify(constraints));
+ return func(constraints);
};
-}
-/**
- * The base implementation of `_.property` without support for deep paths.
- *
- * @private
- * @param {string} key The key of the property to get.
- * @returns {Function} Returns the new function.
- */
-function baseProperty(key) {
- return function(object) {
- return object == null ? undefined : object[key];
+ var shimError_ = function(e) {
+ return {
+ name: {
+ PermissionDeniedError: 'NotAllowedError',
+ ConstraintNotSatisfiedError: 'OverconstrainedError'
+ }[e.name] || e.name,
+ message: e.message,
+ constraint: e.constraintName,
+ toString: function() {
+ return this.name + (this.message && ': ') + this.message;
+ }
+ };
};
-}
-/**
- * A specialized version of `baseProperty` which supports deep paths.
- *
- * @private
- * @param {Array|string} path The path of the property to get.
- * @returns {Function} Returns the new function.
- */
-function basePropertyDeep(path) {
- var pathKey = (path + '');
- path = toPath(path);
- return function(object) {
- return baseGet(object, path, pathKey);
+ var getUserMedia_ = function(constraints, onSuccess, onError) {
+ shimConstraints_(constraints, function(c) {
+ navigator.webkitGetUserMedia(c, onSuccess, function(e) {
+ onError(shimError_(e));
+ });
+ });
};
-}
-
-/**
- * The base implementation of `_.slice` without an iteratee call guard.
- *
- * @private
- * @param {Array} array The array to slice.
- * @param {number} [start=0] The start position.
- * @param {number} [end=array.length] The end position.
- * @returns {Array} Returns the slice of `array`.
- */
-function baseSlice(array, start, end) {
- var index = -1,
- length = array.length;
-
- start = start == null ? 0 : (+start || 0);
- if (start < 0) {
- start = -start > length ? 0 : (length + start);
- }
- end = (end === undefined || end > length) ? length : (+end || 0);
- if (end < 0) {
- end += length;
- }
- length = start > end ? 0 : ((end - start) >>> 0);
- start >>>= 0;
-
- var result = Array(length);
- while (++index < length) {
- result[index] = array[index + start];
- }
- return result;
-}
-/**
- * Gets the propery names, values, and compare flags of `object`.
- *
- * @private
- * @param {Object} object The object to query.
- * @returns {Array} Returns the match data of `object`.
- */
-function getMatchData(object) {
- var result = pairs(object),
- length = result.length;
+ navigator.getUserMedia = getUserMedia_;
- while (length--) {
- result[length][2] = isStrictComparable(result[length][1]);
- }
- return result;
-}
-
-/**
- * Checks if `value` is a property name and not a property path.
- *
- * @private
- * @param {*} value The value to check.
- * @param {Object} [object] The object to query keys on.
- * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
- */
-function isKey(value, object) {
- var type = typeof value;
- if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') {
- return true;
- }
- if (isArray(value)) {
- return false;
- }
- var result = !reIsDeepProp.test(value);
- return result || (object != null && value in toObject(object));
-}
-
-/**
- * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` if suitable for strict
- * equality comparisons, else `false`.
- */
-function isStrictComparable(value) {
- return value === value && !isObject(value);
-}
-
-/**
- * Converts `value` to an object if it's not one.
- *
- * @private
- * @param {*} value The value to process.
- * @returns {Object} Returns the object.
- */
-function toObject(value) {
- return isObject(value) ? value : Object(value);
-}
+ // Returns the result of getUserMedia as a Promise.
+ var getUserMediaPromise_ = function(constraints) {
+ return new Promise(function(resolve, reject) {
+ navigator.getUserMedia(constraints, resolve, reject);
+ });
+ };
-/**
- * Converts `value` to property path array if it's not one.
- *
- * @private
- * @param {*} value The value to process.
- * @returns {Array} Returns the property path array.
- */
-function toPath(value) {
- if (isArray(value)) {
- return value;
+ if (!navigator.mediaDevices) {
+ navigator.mediaDevices = {
+ getUserMedia: getUserMediaPromise_,
+ enumerateDevices: function() {
+ return new Promise(function(resolve) {
+ var kinds = {audio: 'audioinput', video: 'videoinput'};
+ return MediaStreamTrack.getSources(function(devices) {
+ resolve(devices.map(function(device) {
+ return {label: device.label,
+ kind: kinds[device.kind],
+ deviceId: device.id,
+ groupId: ''};
+ }));
+ });
+ });
+ }
+ };
}
- var result = [];
- baseToString(value).replace(rePropName, function(match, number, quote, string) {
- result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
- });
- return result;
-}
-
-/**
- * Gets the last element of `array`.
- *
- * @static
- * @memberOf _
- * @category Array
- * @param {Array} array The array to query.
- * @returns {*} Returns the last element of `array`.
- * @example
- *
- * _.last([1, 2, 3]);
- * // => 3
- */
-function last(array) {
- var length = array ? array.length : 0;
- return length ? array[length - 1] : undefined;
-}
-
-/**
- * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
- * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an object, else `false`.
- * @example
- *
- * _.isObject({});
- * // => true
- *
- * _.isObject([1, 2, 3]);
- * // => true
- *
- * _.isObject(1);
- * // => false
- */
-function isObject(value) {
- // Avoid a V8 JIT bug in Chrome 19-20.
- // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
- var type = typeof value;
- return !!value && (type == 'object' || type == 'function');
-}
-
-/**
- * This method returns the first argument provided to it.
- *
- * @static
- * @memberOf _
- * @category Utility
- * @param {*} value Any value.
- * @returns {*} Returns `value`.
- * @example
- *
- * var object = { 'user': 'fred' };
- *
- * _.identity(object) === object;
- * // => true
- */
-function identity(value) {
- return value;
-}
-
-/**
- * Creates a function that returns the property value at `path` on a
- * given object.
- *
- * @static
- * @memberOf _
- * @category Utility
- * @param {Array|string} path The path of the property to get.
- * @returns {Function} Returns the new function.
- * @example
- *
- * var objects = [
- * { 'a': { 'b': { 'c': 2 } } },
- * { 'a': { 'b': { 'c': 1 } } }
- * ];
- *
- * _.map(objects, _.property('a.b.c'));
- * // => [2, 1]
- *
- * _.pluck(_.sortBy(objects, _.property(['a', 'b', 'c'])), 'a.b.c');
- * // => [1, 2]
- */
-function property(path) {
- return isKey(path) ? baseProperty(path) : basePropertyDeep(path);
-}
-
-module.exports = baseCallback;
-
-},{"lodash._baseisequal":69,"lodash._bindcallback":71,"lodash.isarray":65,"lodash.pairs":72}],69:[function(require,module,exports){
-/**
- * lodash 3.0.7 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-var isArray = require('lodash.isarray'),
- isTypedArray = require('lodash.istypedarray'),
- keys = require('lodash.keys');
-
-/** `Object#toString` result references. */
-var argsTag = '[object Arguments]',
- arrayTag = '[object Array]',
- boolTag = '[object Boolean]',
- dateTag = '[object Date]',
- errorTag = '[object Error]',
- numberTag = '[object Number]',
- objectTag = '[object Object]',
- regexpTag = '[object RegExp]',
- stringTag = '[object String]';
-
-/**
- * Checks if `value` is object-like.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
- */
-function isObjectLike(value) {
- return !!value && typeof value == 'object';
-}
-
-/** Used for native method references. */
-var objectProto = Object.prototype;
-
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
-
-/**
- * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
- * of values.
- */
-var objToString = objectProto.toString;
-
-/**
- * A specialized version of `_.some` for arrays without support for callback
- * shorthands and `this` binding.
- *
- * @private
- * @param {Array} array The array to iterate over.
- * @param {Function} predicate The function invoked per iteration.
- * @returns {boolean} Returns `true` if any element passes the predicate check,
- * else `false`.
- */
-function arraySome(array, predicate) {
- var index = -1,
- length = array.length;
- while (++index < length) {
- if (predicate(array[index], index, array)) {
- return true;
- }
+ // A shim for getUserMedia method on the mediaDevices object.
+ // TODO(KaptenJansson) remove once implemented in Chrome stable.
+ if (!navigator.mediaDevices.getUserMedia) {
+ navigator.mediaDevices.getUserMedia = function(constraints) {
+ return getUserMediaPromise_(constraints);
+ };
+ } else {
+ // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia
+ // function which returns a Promise, it does not accept spec-style
+ // constraints.
+ var origGetUserMedia = navigator.mediaDevices.getUserMedia.
+ bind(navigator.mediaDevices);
+ navigator.mediaDevices.getUserMedia = function(cs) {
+ return shimConstraints_(cs, function(c) {
+ return origGetUserMedia(c).catch(function(e) {
+ return Promise.reject(shimError_(e));
+ });
+ });
+ };
}
- return false;
-}
-/**
- * The base implementation of `_.isEqual` without support for `this` binding
- * `customizer` functions.
- *
- * @private
- * @param {*} value The value to compare.
- * @param {*} other The other value to compare.
- * @param {Function} [customizer] The function to customize comparing values.
- * @param {boolean} [isLoose] Specify performing partial comparisons.
- * @param {Array} [stackA] Tracks traversed `value` objects.
- * @param {Array} [stackB] Tracks traversed `other` objects.
- * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
- */
-function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) {
- if (value === other) {
- return true;
+ // Dummy devicechange event methods.
+ // TODO(KaptenJansson) remove once implemented in Chrome stable.
+ if (typeof navigator.mediaDevices.addEventListener === 'undefined') {
+ navigator.mediaDevices.addEventListener = function() {
+ logging('Dummy mediaDevices.addEventListener called.');
+ };
}
- if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
- return value !== value && other !== other;
+ if (typeof navigator.mediaDevices.removeEventListener === 'undefined') {
+ navigator.mediaDevices.removeEventListener = function() {
+ logging('Dummy mediaDevices.removeEventListener called.');
+ };
}
- return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB);
-}
+};
-/**
- * A specialized version of `baseIsEqual` for arrays and objects which performs
- * deep comparisons and tracks traversed objects enabling objects with circular
- * references to be compared.
+},{"../utils.js":41}],36:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
- * @private
- * @param {Object} object The object to compare.
- * @param {Object} other The other object to compare.
- * @param {Function} equalFunc The function to determine equivalents of values.
- * @param {Function} [customizer] The function to customize comparing objects.
- * @param {boolean} [isLoose] Specify performing partial comparisons.
- * @param {Array} [stackA=[]] Tracks traversed `value` objects.
- * @param {Array} [stackB=[]] Tracks traversed `other` objects.
- * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
*/
-function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
- var objIsArr = isArray(object),
- othIsArr = isArray(other),
- objTag = arrayTag,
- othTag = arrayTag;
-
- if (!objIsArr) {
- objTag = objToString.call(object);
- if (objTag == argsTag) {
- objTag = objectTag;
- } else if (objTag != objectTag) {
- objIsArr = isTypedArray(object);
- }
- }
- if (!othIsArr) {
- othTag = objToString.call(other);
- if (othTag == argsTag) {
- othTag = objectTag;
- } else if (othTag != objectTag) {
- othIsArr = isTypedArray(other);
- }
- }
- var objIsObj = objTag == objectTag,
- othIsObj = othTag == objectTag,
- isSameTag = objTag == othTag;
-
- if (isSameTag && !(objIsArr || objIsObj)) {
- return equalByTag(object, other, objTag);
- }
- if (!isLoose) {
- var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
- othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
-
- if (objIsWrapped || othIsWrapped) {
- return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB);
- }
- }
- if (!isSameTag) {
- return false;
- }
- // Assume cyclic values are equal.
- // For more information on detecting circular references see https://es5.github.io/#JO.
- stackA || (stackA = []);
- stackB || (stackB = []);
+ /* eslint-env node */
+'use strict';
- var length = stackA.length;
- while (length--) {
- if (stackA[length] == object) {
- return stackB[length] == other;
+var SDPUtils = require('sdp');
+var logging = require('../utils').log;
+
+var edgeShim = {
+ shimPeerConnection: function() {
+ if (window.RTCIceGatherer) {
+ // ORTC defines an RTCIceCandidate object but no constructor.
+ // Not implemented in Edge.
+ if (!window.RTCIceCandidate) {
+ window.RTCIceCandidate = function(args) {
+ return args;
+ };
+ }
+ // ORTC does not have a session description object but
+ // other browsers (i.e. Chrome) that will support both PC and ORTC
+ // in the future might have this defined already.
+ if (!window.RTCSessionDescription) {
+ window.RTCSessionDescription = function(args) {
+ return args;
+ };
+ }
}
- }
- // Add `object` and `other` to the stack of traversed objects.
- stackA.push(object);
- stackB.push(other);
-
- var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB);
- stackA.pop();
- stackB.pop();
+ window.RTCPeerConnection = function(config) {
+ var self = this;
- return result;
-}
+ var _eventTarget = document.createDocumentFragment();
+ ['addEventListener', 'removeEventListener', 'dispatchEvent']
+ .forEach(function(method) {
+ self[method] = _eventTarget[method].bind(_eventTarget);
+ });
-/**
- * A specialized version of `baseIsEqualDeep` for arrays with support for
- * partial deep comparisons.
- *
- * @private
- * @param {Array} array The array to compare.
- * @param {Array} other The other array to compare.
- * @param {Function} equalFunc The function to determine equivalents of values.
- * @param {Function} [customizer] The function to customize comparing arrays.
- * @param {boolean} [isLoose] Specify performing partial comparisons.
- * @param {Array} [stackA] Tracks traversed `value` objects.
- * @param {Array} [stackB] Tracks traversed `other` objects.
- * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
- */
-function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) {
- var index = -1,
- arrLength = array.length,
- othLength = other.length;
+ this.onicecandidate = null;
+ this.onaddstream = null;
+ this.ontrack = null;
+ this.onremovestream = null;
+ this.onsignalingstatechange = null;
+ this.oniceconnectionstatechange = null;
+ this.onnegotiationneeded = null;
+ this.ondatachannel = null;
+
+ this.localStreams = [];
+ this.remoteStreams = [];
+ this.getLocalStreams = function() {
+ return self.localStreams;
+ };
+ this.getRemoteStreams = function() {
+ return self.remoteStreams;
+ };
- if (arrLength != othLength && !(isLoose && othLength > arrLength)) {
- return false;
- }
- // Ignore non-index properties.
- while (++index < arrLength) {
- var arrValue = array[index],
- othValue = other[index],
- result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined;
+ this.localDescription = new RTCSessionDescription({
+ type: '',
+ sdp: ''
+ });
+ this.remoteDescription = new RTCSessionDescription({
+ type: '',
+ sdp: ''
+ });
+ this.signalingState = 'stable';
+ this.iceConnectionState = 'new';
+ this.iceGatheringState = 'new';
- if (result !== undefined) {
- if (result) {
- continue;
+ this.iceOptions = {
+ gatherPolicy: 'all',
+ iceServers: []
+ };
+ if (config && config.iceTransportPolicy) {
+ switch (config.iceTransportPolicy) {
+ case 'all':
+ case 'relay':
+ this.iceOptions.gatherPolicy = config.iceTransportPolicy;
+ break;
+ case 'none':
+ // FIXME: remove once implementation and spec have added this.
+ throw new TypeError('iceTransportPolicy "none" not supported');
+ default:
+ // don't set iceTransportPolicy.
+ break;
+ }
}
- return false;
- }
- // Recursively compare arrays (susceptible to call stack limits).
- if (isLoose) {
- if (!arraySome(other, function(othValue) {
- return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB);
- })) {
- return false;
+ this.usingBundle = config && config.bundlePolicy === 'max-bundle';
+
+ if (config && config.iceServers) {
+ // Edge does not like
+ // 1) stun:
+ // 2) turn: that does not have all of turn:host:port?transport=udp
+ var iceServers = JSON.parse(JSON.stringify(config.iceServers));
+ this.iceOptions.iceServers = iceServers.filter(function(server) {
+ if (server && server.urls) {
+ var urls = server.urls;
+ if (typeof urls === 'string') {
+ urls = [urls];
+ }
+ urls = urls.filter(function(url) {
+ return url.indexOf('turn:') === 0 &&
+ url.indexOf('transport=udp') !== -1;
+ })[0];
+ return !!urls;
+ }
+ return false;
+ });
}
- } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) {
- return false;
- }
- }
- return true;
-}
-/**
- * A specialized version of `baseIsEqualDeep` for comparing objects of
- * the same `toStringTag`.
- *
- * **Note:** This function only supports comparing values with tags of
- * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
- *
- * @private
- * @param {Object} value The object to compare.
- * @param {Object} other The other object to compare.
- * @param {string} tag The `toStringTag` of the objects to compare.
- * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
- */
-function equalByTag(object, other, tag) {
- switch (tag) {
- case boolTag:
- case dateTag:
- // Coerce dates and booleans to numbers, dates to milliseconds and booleans
- // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
- return +object == +other;
-
- case errorTag:
- return object.name == other.name && object.message == other.message;
-
- case numberTag:
- // Treat `NaN` vs. `NaN` as equal.
- return (object != +object)
- ? other != +other
- : object == +other;
+ // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ...
+ // everything that is needed to describe a SDP m-line.
+ this.transceivers = [];
- case regexpTag:
- case stringTag:
- // Coerce regexes to strings and treat strings primitives and string
- // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details.
- return object == (other + '');
- }
- return false;
-}
+ // since the iceGatherer is currently created in createOffer but we
+ // must not emit candidates until after setLocalDescription we buffer
+ // them in this array.
+ this._localIceCandidatesBuffer = [];
+ };
-/**
- * A specialized version of `baseIsEqualDeep` for objects with support for
- * partial deep comparisons.
- *
- * @private
- * @param {Object} object The object to compare.
- * @param {Object} other The other object to compare.
- * @param {Function} equalFunc The function to determine equivalents of values.
- * @param {Function} [customizer] The function to customize comparing values.
- * @param {boolean} [isLoose] Specify performing partial comparisons.
- * @param {Array} [stackA] Tracks traversed `value` objects.
- * @param {Array} [stackB] Tracks traversed `other` objects.
- * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
- */
-function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
- var objProps = keys(object),
- objLength = objProps.length,
- othProps = keys(other),
- othLength = othProps.length;
+ window.RTCPeerConnection.prototype._emitBufferedCandidates = function() {
+ var self = this;
+ var sections = SDPUtils.splitSections(self.localDescription.sdp);
+ // FIXME: need to apply ice candidates in a way which is async but
+ // in-order
+ this._localIceCandidatesBuffer.forEach(function(event) {
+ var end = !event.candidate || Object.keys(event.candidate).length === 0;
+ if (end) {
+ for (var j = 1; j < sections.length; j++) {
+ if (sections[j].indexOf('\r\na=end-of-candidates\r\n') === -1) {
+ sections[j] += 'a=end-of-candidates\r\n';
+ }
+ }
+ } else if (event.candidate.candidate.indexOf('typ endOfCandidates')
+ === -1) {
+ sections[event.candidate.sdpMLineIndex + 1] +=
+ 'a=' + event.candidate.candidate + '\r\n';
+ }
+ self.localDescription.sdp = sections.join('');
+ self.dispatchEvent(event);
+ if (self.onicecandidate !== null) {
+ self.onicecandidate(event);
+ }
+ if (!event.candidate && self.iceGatheringState !== 'complete') {
+ var complete = self.transceivers.every(function(transceiver) {
+ return transceiver.iceGatherer &&
+ transceiver.iceGatherer.state === 'completed';
+ });
+ if (complete) {
+ self.iceGatheringState = 'complete';
+ }
+ }
+ });
+ this._localIceCandidatesBuffer = [];
+ };
- if (objLength != othLength && !isLoose) {
- return false;
- }
- var index = objLength;
- while (index--) {
- var key = objProps[index];
- if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) {
- return false;
- }
- }
- var skipCtor = isLoose;
- while (++index < objLength) {
- key = objProps[index];
- var objValue = object[key],
- othValue = other[key],
- result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined;
+ window.RTCPeerConnection.prototype.addStream = function(stream) {
+ // Clone is necessary for local demos mostly, attaching directly
+ // to two different senders does not work (build 10547).
+ this.localStreams.push(stream.clone());
+ this._maybeFireNegotiationNeeded();
+ };
- // Recursively compare objects (susceptible to call stack limits).
- if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) {
- return false;
- }
- skipCtor || (skipCtor = key == 'constructor');
- }
- if (!skipCtor) {
- var objCtor = object.constructor,
- othCtor = other.constructor;
+ window.RTCPeerConnection.prototype.removeStream = function(stream) {
+ var idx = this.localStreams.indexOf(stream);
+ if (idx > -1) {
+ this.localStreams.splice(idx, 1);
+ this._maybeFireNegotiationNeeded();
+ }
+ };
- // Non `Object` object instances with different constructors are not equal.
- if (objCtor != othCtor &&
- ('constructor' in object && 'constructor' in other) &&
- !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
- typeof othCtor == 'function' && othCtor instanceof othCtor)) {
- return false;
- }
- }
- return true;
-}
+ window.RTCPeerConnection.prototype.getSenders = function() {
+ return this.transceivers.filter(function(transceiver) {
+ return !!transceiver.rtpSender;
+ })
+ .map(function(transceiver) {
+ return transceiver.rtpSender;
+ });
+ };
-/**
- * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
- * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an object, else `false`.
- * @example
- *
- * _.isObject({});
- * // => true
- *
- * _.isObject([1, 2, 3]);
- * // => true
- *
- * _.isObject(1);
- * // => false
- */
-function isObject(value) {
- // Avoid a V8 JIT bug in Chrome 19-20.
- // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
- var type = typeof value;
- return !!value && (type == 'object' || type == 'function');
-}
+ window.RTCPeerConnection.prototype.getReceivers = function() {
+ return this.transceivers.filter(function(transceiver) {
+ return !!transceiver.rtpReceiver;
+ })
+ .map(function(transceiver) {
+ return transceiver.rtpReceiver;
+ });
+ };
-module.exports = baseIsEqual;
+ // Determines the intersection of local and remote capabilities.
+ window.RTCPeerConnection.prototype._getCommonCapabilities =
+ function(localCapabilities, remoteCapabilities) {
+ var commonCapabilities = {
+ codecs: [],
+ headerExtensions: [],
+ fecMechanisms: []
+ };
+ localCapabilities.codecs.forEach(function(lCodec) {
+ for (var i = 0; i < remoteCapabilities.codecs.length; i++) {
+ var rCodec = remoteCapabilities.codecs[i];
+ if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() &&
+ lCodec.clockRate === rCodec.clockRate &&
+ lCodec.numChannels === rCodec.numChannels) {
+ // push rCodec so we reply with offerer payload type
+ commonCapabilities.codecs.push(rCodec);
+
+ // FIXME: also need to determine intersection between
+ // .rtcpFeedback and .parameters
+ break;
+ }
+ }
+ });
-},{"lodash.isarray":65,"lodash.istypedarray":70,"lodash.keys":74}],70:[function(require,module,exports){
-/**
- * lodash 3.0.2 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
+ localCapabilities.headerExtensions
+ .forEach(function(lHeaderExtension) {
+ for (var i = 0; i < remoteCapabilities.headerExtensions.length;
+ i++) {
+ var rHeaderExtension = remoteCapabilities.headerExtensions[i];
+ if (lHeaderExtension.uri === rHeaderExtension.uri) {
+ commonCapabilities.headerExtensions.push(rHeaderExtension);
+ break;
+ }
+ }
+ });
-/** `Object#toString` result references. */
-var argsTag = '[object Arguments]',
- arrayTag = '[object Array]',
- boolTag = '[object Boolean]',
- dateTag = '[object Date]',
- errorTag = '[object Error]',
- funcTag = '[object Function]',
- mapTag = '[object Map]',
- numberTag = '[object Number]',
- objectTag = '[object Object]',
- regexpTag = '[object RegExp]',
- setTag = '[object Set]',
- stringTag = '[object String]',
- weakMapTag = '[object WeakMap]';
+ // FIXME: fecMechanisms
+ return commonCapabilities;
+ };
-var arrayBufferTag = '[object ArrayBuffer]',
- float32Tag = '[object Float32Array]',
- float64Tag = '[object Float64Array]',
- int8Tag = '[object Int8Array]',
- int16Tag = '[object Int16Array]',
- int32Tag = '[object Int32Array]',
- uint8Tag = '[object Uint8Array]',
- uint8ClampedTag = '[object Uint8ClampedArray]',
- uint16Tag = '[object Uint16Array]',
- uint32Tag = '[object Uint32Array]';
+ // Create ICE gatherer, ICE transport and DTLS transport.
+ window.RTCPeerConnection.prototype._createIceAndDtlsTransports =
+ function(mid, sdpMLineIndex) {
+ var self = this;
+ var iceGatherer = new RTCIceGatherer(self.iceOptions);
+ var iceTransport = new RTCIceTransport(iceGatherer);
+ iceGatherer.onlocalcandidate = function(evt) {
+ var event = new Event('icecandidate');
+ event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex};
+
+ var cand = evt.candidate;
+ var end = !cand || Object.keys(cand).length === 0;
+ // Edge emits an empty object for RTCIceCandidateComplete‥
+ if (end) {
+ // polyfill since RTCIceGatherer.state is not implemented in
+ // Edge 10547 yet.
+ if (iceGatherer.state === undefined) {
+ iceGatherer.state = 'completed';
+ }
-/** Used to identify `toStringTag` values of typed arrays. */
-var typedArrayTags = {};
-typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
-typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
-typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
-typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
-typedArrayTags[uint32Tag] = true;
-typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
-typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
-typedArrayTags[dateTag] = typedArrayTags[errorTag] =
-typedArrayTags[funcTag] = typedArrayTags[mapTag] =
-typedArrayTags[numberTag] = typedArrayTags[objectTag] =
-typedArrayTags[regexpTag] = typedArrayTags[setTag] =
-typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
+ // Emit a candidate with type endOfCandidates to make the samples
+ // work. Edge requires addIceCandidate with this empty candidate
+ // to start checking. The real solution is to signal
+ // end-of-candidates to the other side when getting the null
+ // candidate but some apps (like the samples) don't do that.
+ event.candidate.candidate =
+ 'candidate:1 1 udp 1 0.0.0.0 9 typ endOfCandidates';
+ } else {
+ // RTCIceCandidate doesn't have a component, needs to be added
+ cand.component = iceTransport.component === 'RTCP' ? 2 : 1;
+ event.candidate.candidate = SDPUtils.writeCandidate(cand);
+ }
-/**
- * Checks if `value` is object-like.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
- */
-function isObjectLike(value) {
- return !!value && typeof value == 'object';
-}
+ // update local description.
+ var sections = SDPUtils.splitSections(self.localDescription.sdp);
+ if (event.candidate.candidate.indexOf('typ endOfCandidates')
+ === -1) {
+ sections[event.candidate.sdpMLineIndex + 1] +=
+ 'a=' + event.candidate.candidate + '\r\n';
+ } else {
+ sections[event.candidate.sdpMLineIndex + 1] +=
+ 'a=end-of-candidates\r\n';
+ }
+ self.localDescription.sdp = sections.join('');
-/** Used for native method references. */
-var objectProto = Object.prototype;
+ var complete = self.transceivers.every(function(transceiver) {
+ return transceiver.iceGatherer &&
+ transceiver.iceGatherer.state === 'completed';
+ });
-/**
- * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
- * of values.
- */
-var objToString = objectProto.toString;
+ // Emit candidate if localDescription is set.
+ // Also emits null candidate when all gatherers are complete.
+ switch (self.iceGatheringState) {
+ case 'new':
+ self._localIceCandidatesBuffer.push(event);
+ if (end && complete) {
+ self._localIceCandidatesBuffer.push(
+ new Event('icecandidate'));
+ }
+ break;
+ case 'gathering':
+ self._emitBufferedCandidates();
+ self.dispatchEvent(event);
+ if (self.onicecandidate !== null) {
+ self.onicecandidate(event);
+ }
+ if (complete) {
+ self.dispatchEvent(new Event('icecandidate'));
+ if (self.onicecandidate !== null) {
+ self.onicecandidate(new Event('icecandidate'));
+ }
+ self.iceGatheringState = 'complete';
+ }
+ break;
+ case 'complete':
+ // should not happen... currently!
+ break;
+ default: // no-op.
+ break;
+ }
+ };
+ iceTransport.onicestatechange = function() {
+ self._updateConnectionState();
+ };
-/**
- * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer)
- * of an array-like value.
- */
-var MAX_SAFE_INTEGER = 9007199254740991;
+ var dtlsTransport = new RTCDtlsTransport(iceTransport);
+ dtlsTransport.ondtlsstatechange = function() {
+ self._updateConnectionState();
+ };
+ dtlsTransport.onerror = function() {
+ // onerror does not set state to failed by itself.
+ dtlsTransport.state = 'failed';
+ self._updateConnectionState();
+ };
-/**
- * Checks if `value` is a valid array-like length.
- *
- * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength).
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
- */
-function isLength(value) {
- return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
-}
+ return {
+ iceGatherer: iceGatherer,
+ iceTransport: iceTransport,
+ dtlsTransport: dtlsTransport
+ };
+ };
-/**
- * Checks if `value` is classified as a typed array.
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
- * @example
- *
- * _.isTypedArray(new Uint8Array);
- * // => true
- *
- * _.isTypedArray([]);
- * // => false
- */
-function isTypedArray(value) {
- return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)];
-}
+ // Start the RTP Sender and Receiver for a transceiver.
+ window.RTCPeerConnection.prototype._transceive = function(transceiver,
+ send, recv) {
+ var params = this._getCommonCapabilities(transceiver.localCapabilities,
+ transceiver.remoteCapabilities);
+ if (send && transceiver.rtpSender) {
+ params.encodings = transceiver.sendEncodingParameters;
+ params.rtcp = {
+ cname: SDPUtils.localCName
+ };
+ if (transceiver.recvEncodingParameters.length) {
+ params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc;
+ }
+ transceiver.rtpSender.send(params);
+ }
+ if (recv && transceiver.rtpReceiver) {
+ params.encodings = transceiver.recvEncodingParameters;
+ params.rtcp = {
+ cname: transceiver.cname
+ };
+ if (transceiver.sendEncodingParameters.length) {
+ params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc;
+ }
+ transceiver.rtpReceiver.receive(params);
+ }
+ };
-module.exports = isTypedArray;
+ window.RTCPeerConnection.prototype.setLocalDescription =
+ function(description) {
+ var self = this;
+ var sections;
+ var sessionpart;
+ if (description.type === 'offer') {
+ // FIXME: What was the purpose of this empty if statement?
+ // if (!this._pendingOffer) {
+ // } else {
+ if (this._pendingOffer) {
+ // VERY limited support for SDP munging. Limited to:
+ // * changing the order of codecs
+ sections = SDPUtils.splitSections(description.sdp);
+ sessionpart = sections.shift();
+ sections.forEach(function(mediaSection, sdpMLineIndex) {
+ var caps = SDPUtils.parseRtpParameters(mediaSection);
+ self._pendingOffer[sdpMLineIndex].localCapabilities = caps;
+ });
+ this.transceivers = this._pendingOffer;
+ delete this._pendingOffer;
+ }
+ } else if (description.type === 'answer') {
+ sections = SDPUtils.splitSections(self.remoteDescription.sdp);
+ sessionpart = sections.shift();
+ var isIceLite = SDPUtils.matchPrefix(sessionpart,
+ 'a=ice-lite').length > 0;
+ sections.forEach(function(mediaSection, sdpMLineIndex) {
+ var transceiver = self.transceivers[sdpMLineIndex];
+ var iceGatherer = transceiver.iceGatherer;
+ var iceTransport = transceiver.iceTransport;
+ var dtlsTransport = transceiver.dtlsTransport;
+ var localCapabilities = transceiver.localCapabilities;
+ var remoteCapabilities = transceiver.remoteCapabilities;
+ var rejected = mediaSection.split('\n', 1)[0]
+ .split(' ', 2)[1] === '0';
+
+ if (!rejected) {
+ var remoteIceParameters = SDPUtils.getIceParameters(
+ mediaSection, sessionpart);
+ if (isIceLite) {
+ var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:')
+ .map(function(cand) {
+ return SDPUtils.parseCandidate(cand);
+ })
+ .filter(function(cand) {
+ return cand.component === '1';
+ });
+ // ice-lite only includes host candidates in the SDP so we can
+ // use setRemoteCandidates (which implies an
+ // RTCIceCandidateComplete)
+ if (cands.length) {
+ iceTransport.setRemoteCandidates(cands);
+ }
+ }
+ var remoteDtlsParameters = SDPUtils.getDtlsParameters(
+ mediaSection, sessionpart);
+ if (isIceLite) {
+ remoteDtlsParameters.role = 'server';
+ }
-},{}],71:[function(require,module,exports){
-arguments[4][60][0].apply(exports,arguments)
-},{"dup":60}],72:[function(require,module,exports){
-/**
- * lodash 3.0.1 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern modularize exports="npm" -o ./`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-var keys = require('lodash.keys');
+ if (!self.usingBundle || sdpMLineIndex === 0) {
+ iceTransport.start(iceGatherer, remoteIceParameters,
+ isIceLite ? 'controlling' : 'controlled');
+ dtlsTransport.start(remoteDtlsParameters);
+ }
-/**
- * Converts `value` to an object if it's not one.
- *
- * @private
- * @param {*} value The value to process.
- * @returns {Object} Returns the object.
- */
-function toObject(value) {
- return isObject(value) ? value : Object(value);
-}
+ // Calculate intersection of capabilities.
+ var params = self._getCommonCapabilities(localCapabilities,
+ remoteCapabilities);
-/**
- * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
- * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an object, else `false`.
- * @example
- *
- * _.isObject({});
- * // => true
- *
- * _.isObject([1, 2, 3]);
- * // => true
- *
- * _.isObject(1);
- * // => false
- */
-function isObject(value) {
- // Avoid a V8 JIT bug in Chrome 19-20.
- // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
- var type = typeof value;
- return !!value && (type == 'object' || type == 'function');
-}
+ // Start the RTCRtpSender. The RTCRtpReceiver for this
+ // transceiver has already been started in setRemoteDescription.
+ self._transceive(transceiver,
+ params.codecs.length > 0,
+ false);
+ }
+ });
+ }
-/**
- * Creates a two dimensional array of the key-value pairs for `object`,
- * e.g. `[[key1, value1], [key2, value2]]`.
- *
- * @static
- * @memberOf _
- * @category Object
- * @param {Object} object The object to query.
- * @returns {Array} Returns the new array of key-value pairs.
- * @example
- *
- * _.pairs({ 'barney': 36, 'fred': 40 });
- * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed)
- */
-function pairs(object) {
- object = toObject(object);
+ this.localDescription = {
+ type: description.type,
+ sdp: description.sdp
+ };
+ switch (description.type) {
+ case 'offer':
+ this._updateSignalingState('have-local-offer');
+ break;
+ case 'answer':
+ this._updateSignalingState('stable');
+ break;
+ default:
+ throw new TypeError('unsupported type "' + description.type +
+ '"');
+ }
- var index = -1,
- props = keys(object),
- length = props.length,
- result = Array(length);
+ // If a success callback was provided, emit ICE candidates after it
+ // has been executed. Otherwise, emit callback after the Promise is
+ // resolved.
+ var hasCallback = arguments.length > 1 &&
+ typeof arguments[1] === 'function';
+ if (hasCallback) {
+ var cb = arguments[1];
+ window.setTimeout(function() {
+ cb();
+ if (self.iceGatheringState === 'new') {
+ self.iceGatheringState = 'gathering';
+ }
+ self._emitBufferedCandidates();
+ }, 0);
+ }
+ var p = Promise.resolve();
+ p.then(function() {
+ if (!hasCallback) {
+ if (self.iceGatheringState === 'new') {
+ self.iceGatheringState = 'gathering';
+ }
+ // Usually candidates will be emitted earlier.
+ window.setTimeout(self._emitBufferedCandidates.bind(self), 500);
+ }
+ });
+ return p;
+ };
- while (++index < length) {
- var key = props[index];
- result[index] = [key, object[key]];
- }
- return result;
-}
+ window.RTCPeerConnection.prototype.setRemoteDescription =
+ function(description) {
+ var self = this;
+ var stream = new MediaStream();
+ var receiverList = [];
+ var sections = SDPUtils.splitSections(description.sdp);
+ var sessionpart = sections.shift();
+ var isIceLite = SDPUtils.matchPrefix(sessionpart,
+ 'a=ice-lite').length > 0;
+ this.usingBundle = SDPUtils.matchPrefix(sessionpart,
+ 'a=group:BUNDLE ').length > 0;
+ sections.forEach(function(mediaSection, sdpMLineIndex) {
+ var lines = SDPUtils.splitLines(mediaSection);
+ var mline = lines[0].substr(2).split(' ');
+ var kind = mline[0];
+ var rejected = mline[1] === '0';
+ var direction = SDPUtils.getDirection(mediaSection, sessionpart);
+
+ var transceiver;
+ var iceGatherer;
+ var iceTransport;
+ var dtlsTransport;
+ var rtpSender;
+ var rtpReceiver;
+ var sendEncodingParameters;
+ var recvEncodingParameters;
+ var localCapabilities;
+
+ var track;
+ // FIXME: ensure the mediaSection has rtcp-mux set.
+ var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection);
+ var remoteIceParameters;
+ var remoteDtlsParameters;
+ if (!rejected) {
+ remoteIceParameters = SDPUtils.getIceParameters(mediaSection,
+ sessionpart);
+ remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection,
+ sessionpart);
+ remoteDtlsParameters.role = 'client';
+ }
+ recvEncodingParameters =
+ SDPUtils.parseRtpEncodingParameters(mediaSection);
-module.exports = pairs;
+ var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:');
+ if (mid.length) {
+ mid = mid[0].substr(6);
+ } else {
+ mid = SDPUtils.generateIdentifier();
+ }
-},{"lodash.keys":74}],73:[function(require,module,exports){
-arguments[4][56][0].apply(exports,arguments)
-},{"dup":56,"lodash.keys":74}],74:[function(require,module,exports){
-arguments[4][57][0].apply(exports,arguments)
-},{"dup":57,"lodash._getnative":75,"lodash.isarguments":76,"lodash.isarray":65}],75:[function(require,module,exports){
-arguments[4][58][0].apply(exports,arguments)
-},{"dup":58}],76:[function(require,module,exports){
-arguments[4][59][0].apply(exports,arguments)
-},{"dup":59}],77:[function(require,module,exports){
-var toSDP = require('./lib/tosdp');
-var toJSON = require('./lib/tojson');
+ var cname;
+ // Gets the first SSRC. Note that with RTX there might be multiple
+ // SSRCs.
+ var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
+ .map(function(line) {
+ return SDPUtils.parseSsrcMedia(line);
+ })
+ .filter(function(obj) {
+ return obj.attribute === 'cname';
+ })[0];
+ if (remoteSsrc) {
+ cname = remoteSsrc.value;
+ }
+ var isComplete = SDPUtils.matchPrefix(mediaSection,
+ 'a=end-of-candidates').length > 0;
+ var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:')
+ .map(function(cand) {
+ return SDPUtils.parseCandidate(cand);
+ })
+ .filter(function(cand) {
+ return cand.component === '1';
+ });
+ if (description.type === 'offer' && !rejected) {
+ var transports = self.usingBundle && sdpMLineIndex > 0 ? {
+ iceGatherer: self.transceivers[0].iceGatherer,
+ iceTransport: self.transceivers[0].iceTransport,
+ dtlsTransport: self.transceivers[0].dtlsTransport
+ } : self._createIceAndDtlsTransports(mid, sdpMLineIndex);
+
+ if (isComplete) {
+ transports.iceTransport.setRemoteCandidates(cands);
+ }
-// Converstion from JSON to SDP
+ localCapabilities = RTCRtpReceiver.getCapabilities(kind);
+ sendEncodingParameters = [{
+ ssrc: (2 * sdpMLineIndex + 2) * 1001
+ }];
+
+ rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind);
+
+ track = rtpReceiver.track;
+ receiverList.push([track, rtpReceiver]);
+ // FIXME: not correct when there are multiple streams but that is
+ // not currently supported in this shim.
+ stream.addTrack(track);
+
+ // FIXME: look at direction.
+ if (self.localStreams.length > 0 &&
+ self.localStreams[0].getTracks().length >= sdpMLineIndex) {
+ // FIXME: actually more complicated, needs to match types etc
+ var localtrack = self.localStreams[0]
+ .getTracks()[sdpMLineIndex];
+ rtpSender = new RTCRtpSender(localtrack,
+ transports.dtlsTransport);
+ }
-exports.toIncomingSDPOffer = function (session) {
- return toSDP.toSessionSDP(session, {
- role: 'responder',
- direction: 'incoming'
- });
-};
-exports.toOutgoingSDPOffer = function (session) {
- return toSDP.toSessionSDP(session, {
- role: 'initiator',
- direction: 'outgoing'
- });
-};
-exports.toIncomingSDPAnswer = function (session) {
- return toSDP.toSessionSDP(session, {
- role: 'initiator',
- direction: 'incoming'
- });
-};
-exports.toOutgoingSDPAnswer = function (session) {
- return toSDP.toSessionSDP(session, {
- role: 'responder',
- direction: 'outgoing'
- });
-};
-exports.toIncomingMediaSDPOffer = function (media) {
- return toSDP.toMediaSDP(media, {
- role: 'responder',
- direction: 'incoming'
- });
-};
-exports.toOutgoingMediaSDPOffer = function (media) {
- return toSDP.toMediaSDP(media, {
- role: 'initiator',
- direction: 'outgoing'
- });
-};
-exports.toIncomingMediaSDPAnswer = function (media) {
- return toSDP.toMediaSDP(media, {
- role: 'initiator',
- direction: 'incoming'
- });
-};
-exports.toOutgoingMediaSDPAnswer = function (media) {
- return toSDP.toMediaSDP(media, {
- role: 'responder',
- direction: 'outgoing'
- });
-};
-exports.toCandidateSDP = toSDP.toCandidateSDP;
-exports.toMediaSDP = toSDP.toMediaSDP;
-exports.toSessionSDP = toSDP.toSessionSDP;
+ self.transceivers[sdpMLineIndex] = {
+ iceGatherer: transports.iceGatherer,
+ iceTransport: transports.iceTransport,
+ dtlsTransport: transports.dtlsTransport,
+ localCapabilities: localCapabilities,
+ remoteCapabilities: remoteCapabilities,
+ rtpSender: rtpSender,
+ rtpReceiver: rtpReceiver,
+ kind: kind,
+ mid: mid,
+ cname: cname,
+ sendEncodingParameters: sendEncodingParameters,
+ recvEncodingParameters: recvEncodingParameters
+ };
+ // Start the RTCRtpReceiver now. The RTPSender is started in
+ // setLocalDescription.
+ self._transceive(self.transceivers[sdpMLineIndex],
+ false,
+ direction === 'sendrecv' || direction === 'sendonly');
+ } else if (description.type === 'answer' && !rejected) {
+ transceiver = self.transceivers[sdpMLineIndex];
+ iceGatherer = transceiver.iceGatherer;
+ iceTransport = transceiver.iceTransport;
+ dtlsTransport = transceiver.dtlsTransport;
+ rtpSender = transceiver.rtpSender;
+ rtpReceiver = transceiver.rtpReceiver;
+ sendEncodingParameters = transceiver.sendEncodingParameters;
+ localCapabilities = transceiver.localCapabilities;
+
+ self.transceivers[sdpMLineIndex].recvEncodingParameters =
+ recvEncodingParameters;
+ self.transceivers[sdpMLineIndex].remoteCapabilities =
+ remoteCapabilities;
+ self.transceivers[sdpMLineIndex].cname = cname;
+
+ if ((isIceLite || isComplete) && cands.length) {
+ iceTransport.setRemoteCandidates(cands);
+ }
+ if (!self.usingBundle || sdpMLineIndex === 0) {
+ iceTransport.start(iceGatherer, remoteIceParameters,
+ 'controlling');
+ dtlsTransport.start(remoteDtlsParameters);
+ }
+ self._transceive(transceiver,
+ direction === 'sendrecv' || direction === 'recvonly',
+ direction === 'sendrecv' || direction === 'sendonly');
-// Conversion from SDP to JSON
+ if (rtpReceiver &&
+ (direction === 'sendrecv' || direction === 'sendonly')) {
+ track = rtpReceiver.track;
+ receiverList.push([track, rtpReceiver]);
+ stream.addTrack(track);
+ } else {
+ // FIXME: actually the receiver should be created later.
+ delete transceiver.rtpReceiver;
+ }
+ }
+ });
-exports.toIncomingJSONOffer = function (sdp, creators) {
- return toJSON.toSessionJSON(sdp, {
- role: 'responder',
- direction: 'incoming',
- creators: creators
- });
-};
-exports.toOutgoingJSONOffer = function (sdp, creators) {
- return toJSON.toSessionJSON(sdp, {
- role: 'initiator',
- direction: 'outgoing',
- creators: creators
- });
-};
-exports.toIncomingJSONAnswer = function (sdp, creators) {
- return toJSON.toSessionJSON(sdp, {
- role: 'initiator',
- direction: 'incoming',
- creators: creators
- });
-};
-exports.toOutgoingJSONAnswer = function (sdp, creators) {
- return toJSON.toSessionJSON(sdp, {
- role: 'responder',
- direction: 'outgoing',
- creators: creators
- });
-};
-exports.toIncomingMediaJSONOffer = function (sdp, creator) {
- return toJSON.toMediaJSON(sdp, {
- role: 'responder',
- direction: 'incoming',
- creator: creator
- });
-};
-exports.toOutgoingMediaJSONOffer = function (sdp, creator) {
- return toJSON.toMediaJSON(sdp, {
- role: 'initiator',
- direction: 'outgoing',
- creator: creator
- });
-};
-exports.toIncomingMediaJSONAnswer = function (sdp, creator) {
- return toJSON.toMediaJSON(sdp, {
- role: 'initiator',
- direction: 'incoming',
- creator: creator
- });
-};
-exports.toOutgoingMediaJSONAnswer = function (sdp, creator) {
- return toJSON.toMediaJSON(sdp, {
- role: 'responder',
- direction: 'outgoing',
- creator: creator
- });
-};
-exports.toCandidateJSON = toJSON.toCandidateJSON;
-exports.toMediaJSON = toJSON.toMediaJSON;
-exports.toSessionJSON = toJSON.toSessionJSON;
+ this.remoteDescription = {
+ type: description.type,
+ sdp: description.sdp
+ };
+ switch (description.type) {
+ case 'offer':
+ this._updateSignalingState('have-remote-offer');
+ break;
+ case 'answer':
+ this._updateSignalingState('stable');
+ break;
+ default:
+ throw new TypeError('unsupported type "' + description.type +
+ '"');
+ }
+ if (stream.getTracks().length) {
+ self.remoteStreams.push(stream);
+ window.setTimeout(function() {
+ var event = new Event('addstream');
+ event.stream = stream;
+ self.dispatchEvent(event);
+ if (self.onaddstream !== null) {
+ window.setTimeout(function() {
+ self.onaddstream(event);
+ }, 0);
+ }
-},{"./lib/tojson":80,"./lib/tosdp":81}],78:[function(require,module,exports){
-exports.lines = function (sdp) {
- return sdp.split('\r\n').filter(function (line) {
- return line.length > 0;
- });
-};
+ receiverList.forEach(function(item) {
+ var track = item[0];
+ var receiver = item[1];
+ var trackEvent = new Event('track');
+ trackEvent.track = track;
+ trackEvent.receiver = receiver;
+ trackEvent.streams = [stream];
+ self.dispatchEvent(event);
+ if (self.ontrack !== null) {
+ window.setTimeout(function() {
+ self.ontrack(trackEvent);
+ }, 0);
+ }
+ });
+ }, 0);
+ }
+ if (arguments.length > 1 && typeof arguments[1] === 'function') {
+ window.setTimeout(arguments[1], 0);
+ }
+ return Promise.resolve();
+ };
-exports.findLine = function (prefix, mediaLines, sessionLines) {
- var prefixLength = prefix.length;
- for (var i = 0; i < mediaLines.length; i++) {
- if (mediaLines[i].substr(0, prefixLength) === prefix) {
- return mediaLines[i];
+ window.RTCPeerConnection.prototype.close = function() {
+ this.transceivers.forEach(function(transceiver) {
+ /* not yet
+ if (transceiver.iceGatherer) {
+ transceiver.iceGatherer.close();
}
- }
- // Continue searching in parent session section
- if (!sessionLines) {
- return false;
- }
-
- for (var j = 0; j < sessionLines.length; j++) {
- if (sessionLines[j].substr(0, prefixLength) === prefix) {
- return sessionLines[j];
+ */
+ if (transceiver.iceTransport) {
+ transceiver.iceTransport.stop();
}
- }
-
- return false;
-};
-
-exports.findLines = function (prefix, mediaLines, sessionLines) {
- var results = [];
- var prefixLength = prefix.length;
- for (var i = 0; i < mediaLines.length; i++) {
- if (mediaLines[i].substr(0, prefixLength) === prefix) {
- results.push(mediaLines[i]);
+ if (transceiver.dtlsTransport) {
+ transceiver.dtlsTransport.stop();
}
- }
- if (results.length || !sessionLines) {
- return results;
- }
- for (var j = 0; j < sessionLines.length; j++) {
- if (sessionLines[j].substr(0, prefixLength) === prefix) {
- results.push(sessionLines[j]);
+ if (transceiver.rtpSender) {
+ transceiver.rtpSender.stop();
}
- }
- return results;
-};
-
-exports.mline = function (line) {
- var parts = line.substr(2).split(' ');
- var parsed = {
- media: parts[0],
- port: parts[1],
- proto: parts[2],
- formats: []
- };
- for (var i = 3; i < parts.length; i++) {
- if (parts[i]) {
- parsed.formats.push(parts[i]);
+ if (transceiver.rtpReceiver) {
+ transceiver.rtpReceiver.stop();
}
- }
- return parsed;
-};
-
-exports.rtpmap = function (line) {
- var parts = line.substr(9).split(' ');
- var parsed = {
- id: parts.shift()
+ });
+ // FIXME: clean up tracks, local streams, remote streams, etc
+ this._updateSignalingState('closed');
};
- parts = parts[0].split('/');
-
- parsed.name = parts[0];
- parsed.clockrate = parts[1];
- parsed.channels = parts.length == 3 ? parts[2] : '1';
- return parsed;
-};
+ // Update the signaling state.
+ window.RTCPeerConnection.prototype._updateSignalingState =
+ function(newState) {
+ this.signalingState = newState;
+ var event = new Event('signalingstatechange');
+ this.dispatchEvent(event);
+ if (this.onsignalingstatechange !== null) {
+ this.onsignalingstatechange(event);
+ }
+ };
-exports.sctpmap = function (line) {
- // based on -05 draft
- var parts = line.substr(10).split(' ');
- var parsed = {
- number: parts.shift(),
- protocol: parts.shift(),
- streams: parts.shift()
- };
- return parsed;
-};
+ // Determine whether to fire the negotiationneeded event.
+ window.RTCPeerConnection.prototype._maybeFireNegotiationNeeded =
+ function() {
+ // Fire away (for now).
+ var event = new Event('negotiationneeded');
+ this.dispatchEvent(event);
+ if (this.onnegotiationneeded !== null) {
+ this.onnegotiationneeded(event);
+ }
+ };
+ // Update the connection state.
+ window.RTCPeerConnection.prototype._updateConnectionState = function() {
+ var self = this;
+ var newState;
+ var states = {
+ 'new': 0,
+ closed: 0,
+ connecting: 0,
+ checking: 0,
+ connected: 0,
+ completed: 0,
+ failed: 0
+ };
+ this.transceivers.forEach(function(transceiver) {
+ states[transceiver.iceTransport.state]++;
+ states[transceiver.dtlsTransport.state]++;
+ });
+ // ICETransport.completed and connected are the same for this purpose.
+ states.connected += states.completed;
+
+ newState = 'new';
+ if (states.failed > 0) {
+ newState = 'failed';
+ } else if (states.connecting > 0 || states.checking > 0) {
+ newState = 'connecting';
+ } else if (states.disconnected > 0) {
+ newState = 'disconnected';
+ } else if (states.new > 0) {
+ newState = 'new';
+ } else if (states.connected > 0 || states.completed > 0) {
+ newState = 'connected';
+ }
-exports.fmtp = function (line) {
- var kv, key, value;
- var parts = line.substr(line.indexOf(' ') + 1).split(';');
- var parsed = [];
- for (var i = 0; i < parts.length; i++) {
- kv = parts[i].split('=');
- key = kv[0].trim();
- value = kv[1];
- if (key && value) {
- parsed.push({key: key, value: value});
- } else if (key) {
- parsed.push({key: '', value: key});
+ if (newState !== self.iceConnectionState) {
+ self.iceConnectionState = newState;
+ var event = new Event('iceconnectionstatechange');
+ this.dispatchEvent(event);
+ if (this.oniceconnectionstatechange !== null) {
+ this.oniceconnectionstatechange(event);
}
- }
- return parsed;
-};
-
-exports.crypto = function (line) {
- var parts = line.substr(9).split(' ');
- var parsed = {
- tag: parts[0],
- cipherSuite: parts[1],
- keyParams: parts[2],
- sessionParams: parts.slice(3).join(' ')
- };
- return parsed;
-};
-
-exports.fingerprint = function (line) {
- var parts = line.substr(14).split(' ');
- return {
- hash: parts[0],
- value: parts[1]
+ }
};
-};
-
-exports.extmap = function (line) {
- var parts = line.substr(9).split(' ');
- var parsed = {};
-
- var idpart = parts.shift();
- var sp = idpart.indexOf('/');
- if (sp >= 0) {
- parsed.id = idpart.substr(0, sp);
- parsed.senders = idpart.substr(sp + 1);
- } else {
- parsed.id = idpart;
- parsed.senders = 'sendrecv';
- }
-
- parsed.uri = parts.shift() || '';
- return parsed;
-};
-
-exports.rtcpfb = function (line) {
- var parts = line.substr(10).split(' ');
- var parsed = {};
- parsed.id = parts.shift();
- parsed.type = parts.shift();
- if (parsed.type === 'trr-int') {
- parsed.value = parts.shift();
- } else {
- parsed.subtype = parts.shift() || '';
- }
- parsed.parameters = parts;
- return parsed;
-};
-
-exports.candidate = function (line) {
- var parts;
- if (line.indexOf('a=candidate:') === 0) {
- parts = line.substring(12).split(' ');
- } else { // no a=candidate
- parts = line.substring(10).split(' ');
- }
-
- var candidate = {
- foundation: parts[0],
- component: parts[1],
- protocol: parts[2].toLowerCase(),
- priority: parts[3],
- ip: parts[4],
- port: parts[5],
- // skip parts[6] == 'typ'
- type: parts[7],
- generation: '0'
- };
+ window.RTCPeerConnection.prototype.createOffer = function() {
+ var self = this;
+ if (this._pendingOffer) {
+ throw new Error('createOffer called while there is a pending offer.');
+ }
+ var offerOptions;
+ if (arguments.length === 1 && typeof arguments[0] !== 'function') {
+ offerOptions = arguments[0];
+ } else if (arguments.length === 3) {
+ offerOptions = arguments[2];
+ }
- for (var i = 8; i < parts.length; i += 2) {
- if (parts[i] === 'raddr') {
- candidate.relAddr = parts[i + 1];
- } else if (parts[i] === 'rport') {
- candidate.relPort = parts[i + 1];
- } else if (parts[i] === 'generation') {
- candidate.generation = parts[i + 1];
- } else if (parts[i] === 'tcptype') {
- candidate.tcpType = parts[i + 1];
+ var tracks = [];
+ var numAudioTracks = 0;
+ var numVideoTracks = 0;
+ // Default to sendrecv.
+ if (this.localStreams.length) {
+ numAudioTracks = this.localStreams[0].getAudioTracks().length;
+ numVideoTracks = this.localStreams[0].getVideoTracks().length;
+ }
+ // Determine number of audio and video tracks we need to send/recv.
+ if (offerOptions) {
+ // Reject Chrome legacy constraints.
+ if (offerOptions.mandatory || offerOptions.optional) {
+ throw new TypeError(
+ 'Legacy mandatory/optional constraints not supported.');
}
- }
-
- candidate.network = '1';
-
- return candidate;
-};
-
-exports.sourceGroups = function (lines) {
- var parsed = [];
- for (var i = 0; i < lines.length; i++) {
- var parts = lines[i].substr(13).split(' ');
- parsed.push({
- semantics: parts.shift(),
- sources: parts
- });
- }
- return parsed;
-};
-
-exports.sources = function (lines) {
- // http://tools.ietf.org/html/rfc5576
- var parsed = [];
- var sources = {};
- for (var i = 0; i < lines.length; i++) {
- var parts = lines[i].substr(7).split(' ');
- var ssrc = parts.shift();
-
- if (!sources[ssrc]) {
- var source = {
- ssrc: ssrc,
- parameters: []
- };
- parsed.push(source);
-
- // Keep an index
- sources[ssrc] = source;
+ if (offerOptions.offerToReceiveAudio !== undefined) {
+ numAudioTracks = offerOptions.offerToReceiveAudio;
}
-
- parts = parts.join(' ').split(':');
- var attribute = parts.shift();
- var value = parts.join(':') || null;
-
- sources[ssrc].parameters.push({
- key: attribute,
- value: value
- });
- }
-
- return parsed;
-};
-
-exports.groups = function (lines) {
- // http://tools.ietf.org/html/rfc5888
- var parsed = [];
- var parts;
- for (var i = 0; i < lines.length; i++) {
- parts = lines[i].substr(8).split(' ');
- parsed.push({
- semantics: parts.shift(),
- contents: parts
- });
- }
- return parsed;
-};
-
-exports.bandwidth = function (line) {
- var parts = line.substr(2).split(':');
- var parsed = {};
- parsed.type = parts.shift();
- parsed.bandwidth = parts.shift();
- return parsed;
-};
-
-exports.msid = function (line) {
- var data = line.substr(7);
- var parts = data.split(' ');
- return {
- msid: data,
- mslabel: parts[0],
- label: parts[1]
- };
-};
-
-},{}],79:[function(require,module,exports){
-module.exports = {
- initiator: {
- incoming: {
- initiator: 'recvonly',
- responder: 'sendonly',
- both: 'sendrecv',
- none: 'inactive',
- recvonly: 'initiator',
- sendonly: 'responder',
- sendrecv: 'both',
- inactive: 'none'
- },
- outgoing: {
- initiator: 'sendonly',
- responder: 'recvonly',
- both: 'sendrecv',
- none: 'inactive',
- recvonly: 'responder',
- sendonly: 'initiator',
- sendrecv: 'both',
- inactive: 'none'
+ if (offerOptions.offerToReceiveVideo !== undefined) {
+ numVideoTracks = offerOptions.offerToReceiveVideo;
}
- },
- responder: {
- incoming: {
- initiator: 'sendonly',
- responder: 'recvonly',
- both: 'sendrecv',
- none: 'inactive',
- recvonly: 'responder',
- sendonly: 'initiator',
- sendrecv: 'both',
- inactive: 'none'
- },
- outgoing: {
- initiator: 'recvonly',
- responder: 'sendonly',
- both: 'sendrecv',
- none: 'inactive',
- recvonly: 'initiator',
- sendonly: 'responder',
- sendrecv: 'both',
- inactive: 'none'
+ }
+ if (this.localStreams.length) {
+ // Push local streams.
+ this.localStreams[0].getTracks().forEach(function(track) {
+ tracks.push({
+ kind: track.kind,
+ track: track,
+ wantReceive: track.kind === 'audio' ?
+ numAudioTracks > 0 : numVideoTracks > 0
+ });
+ if (track.kind === 'audio') {
+ numAudioTracks--;
+ } else if (track.kind === 'video') {
+ numVideoTracks--;
+ }
+ });
+ }
+ // Create M-lines for recvonly streams.
+ while (numAudioTracks > 0 || numVideoTracks > 0) {
+ if (numAudioTracks > 0) {
+ tracks.push({
+ kind: 'audio',
+ wantReceive: true
+ });
+ numAudioTracks--;
}
- }
-};
-
-},{}],80:[function(require,module,exports){
-var SENDERS = require('./senders');
-var parsers = require('./parsers');
-var idCounter = Math.random();
-
-
-exports._setIdCounter = function (counter) {
- idCounter = counter;
-};
-
-exports.toSessionJSON = function (sdp, opts) {
- var i;
- var creators = opts.creators || [];
- var role = opts.role || 'initiator';
- var direction = opts.direction || 'outgoing';
-
-
- // Divide the SDP into session and media sections.
- var media = sdp.split('\r\nm=');
- for (i = 1; i < media.length; i++) {
- media[i] = 'm=' + media[i];
- if (i !== media.length - 1) {
- media[i] += '\r\n';
+ if (numVideoTracks > 0) {
+ tracks.push({
+ kind: 'video',
+ wantReceive: true
+ });
+ numVideoTracks--;
}
- }
- var session = media.shift() + '\r\n';
- var sessionLines = parsers.lines(session);
- var parsed = {};
-
- var contents = [];
- for (i = 0; i < media.length; i++) {
- contents.push(exports.toMediaJSON(media[i], session, {
- role: role,
- direction: direction,
- creator: creators[i] || 'initiator'
- }));
- }
- parsed.contents = contents;
+ }
- var groupLines = parsers.findLines('a=group:', sessionLines);
- if (groupLines.length) {
- parsed.groups = parsers.groups(groupLines);
- }
+ var sdp = SDPUtils.writeSessionBoilerplate();
+ var transceivers = [];
+ tracks.forEach(function(mline, sdpMLineIndex) {
+ // For each track, create an ice gatherer, ice transport,
+ // dtls transport, potentially rtpsender and rtpreceiver.
+ var track = mline.track;
+ var kind = mline.kind;
+ var mid = SDPUtils.generateIdentifier();
+
+ var transports = self.usingBundle && sdpMLineIndex > 0 ? {
+ iceGatherer: transceivers[0].iceGatherer,
+ iceTransport: transceivers[0].iceTransport,
+ dtlsTransport: transceivers[0].dtlsTransport
+ } : self._createIceAndDtlsTransports(mid, sdpMLineIndex);
+
+ var localCapabilities = RTCRtpSender.getCapabilities(kind);
+ var rtpSender;
+ var rtpReceiver;
+
+ // generate an ssrc now, to be used later in rtpSender.send
+ var sendEncodingParameters = [{
+ ssrc: (2 * sdpMLineIndex + 1) * 1001
+ }];
+ if (track) {
+ rtpSender = new RTCRtpSender(track, transports.dtlsTransport);
+ }
+
+ if (mline.wantReceive) {
+ rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind);
+ }
+
+ transceivers[sdpMLineIndex] = {
+ iceGatherer: transports.iceGatherer,
+ iceTransport: transports.iceTransport,
+ dtlsTransport: transports.dtlsTransport,
+ localCapabilities: localCapabilities,
+ remoteCapabilities: null,
+ rtpSender: rtpSender,
+ rtpReceiver: rtpReceiver,
+ kind: kind,
+ mid: mid,
+ sendEncodingParameters: sendEncodingParameters,
+ recvEncodingParameters: null
+ };
+ });
+ if (this.usingBundle) {
+ sdp += 'a=group:BUNDLE ' + transceivers.map(function(t) {
+ return t.mid;
+ }).join(' ') + '\r\n';
+ }
+ tracks.forEach(function(mline, sdpMLineIndex) {
+ var transceiver = transceivers[sdpMLineIndex];
+ sdp += SDPUtils.writeMediaSection(transceiver,
+ transceiver.localCapabilities, 'offer', self.localStreams[0]);
+ });
- return parsed;
-};
+ this._pendingOffer = transceivers;
+ var desc = new RTCSessionDescription({
+ type: 'offer',
+ sdp: sdp
+ });
+ if (arguments.length && typeof arguments[0] === 'function') {
+ window.setTimeout(arguments[0], 0, desc);
+ }
+ return Promise.resolve(desc);
+ };
-exports.toMediaJSON = function (media, session, opts) {
- var creator = opts.creator || 'initiator';
- var role = opts.role || 'initiator';
- var direction = opts.direction || 'outgoing';
+ window.RTCPeerConnection.prototype.createAnswer = function() {
+ var self = this;
- var lines = parsers.lines(media);
- var sessionLines = parsers.lines(session);
- var mline = parsers.mline(lines[0]);
+ var sdp = SDPUtils.writeSessionBoilerplate();
+ if (this.usingBundle) {
+ sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) {
+ return t.mid;
+ }).join(' ') + '\r\n';
+ }
+ this.transceivers.forEach(function(transceiver) {
+ // Calculate intersection of capabilities.
+ var commonCapabilities = self._getCommonCapabilities(
+ transceiver.localCapabilities,
+ transceiver.remoteCapabilities);
+
+ sdp += SDPUtils.writeMediaSection(transceiver, commonCapabilities,
+ 'answer', self.localStreams[0]);
+ });
- var content = {
- creator: creator,
- name: mline.media,
- description: {
- descType: 'rtp',
- media: mline.media,
- payloads: [],
- encryption: [],
- feedback: [],
- headerExtensions: []
- },
- transport: {
- transType: 'iceUdp',
- candidates: [],
- fingerprints: []
- }
+ var desc = new RTCSessionDescription({
+ type: 'answer',
+ sdp: sdp
+ });
+ if (arguments.length && typeof arguments[0] === 'function') {
+ window.setTimeout(arguments[0], 0, desc);
+ }
+ return Promise.resolve(desc);
};
- if (mline.media == 'application') {
- // FIXME: the description is most likely to be independent
- // of the SDP and should be processed by other parts of the library
- content.description = {
- descType: 'datachannel'
- };
- content.transport.sctp = [];
- }
- var desc = content.description;
- var trans = content.transport;
-
- // If we have a mid, use that for the content name instead.
- var mid = parsers.findLine('a=mid:', lines);
- if (mid) {
- content.name = mid.substr(6);
- }
-
- if (parsers.findLine('a=sendrecv', lines, sessionLines)) {
- content.senders = 'both';
- } else if (parsers.findLine('a=sendonly', lines, sessionLines)) {
- content.senders = SENDERS[role][direction].sendonly;
- } else if (parsers.findLine('a=recvonly', lines, sessionLines)) {
- content.senders = SENDERS[role][direction].recvonly;
- } else if (parsers.findLine('a=inactive', lines, sessionLines)) {
- content.senders = 'none';
- }
- if (desc.descType == 'rtp') {
- var bandwidth = parsers.findLine('b=', lines);
- if (bandwidth) {
- desc.bandwidth = parsers.bandwidth(bandwidth);
+ window.RTCPeerConnection.prototype.addIceCandidate = function(candidate) {
+ if (candidate === null) {
+ this.transceivers.forEach(function(transceiver) {
+ transceiver.iceTransport.addRemoteCandidate({});
+ });
+ } else {
+ var mLineIndex = candidate.sdpMLineIndex;
+ if (candidate.sdpMid) {
+ for (var i = 0; i < this.transceivers.length; i++) {
+ if (this.transceivers[i].mid === candidate.sdpMid) {
+ mLineIndex = i;
+ break;
+ }
+ }
}
+ var transceiver = this.transceivers[mLineIndex];
+ if (transceiver) {
+ var cand = Object.keys(candidate.candidate).length > 0 ?
+ SDPUtils.parseCandidate(candidate.candidate) : {};
+ // Ignore Chrome's invalid candidates since Edge does not like them.
+ if (cand.protocol === 'tcp' && cand.port === 0) {
+ return;
+ }
+ // Ignore RTCP candidates, we assume RTCP-MUX.
+ if (cand.component !== '1') {
+ return;
+ }
+ // A dirty hack to make samples work.
+ if (cand.type === 'endOfCandidates') {
+ cand = {};
+ }
+ transceiver.iceTransport.addRemoteCandidate(cand);
- var ssrc = parsers.findLine('a=ssrc:', lines);
- if (ssrc) {
- desc.ssrc = ssrc.substr(7).split(' ')[0];
+ // update the remoteDescription.
+ var sections = SDPUtils.splitSections(this.remoteDescription.sdp);
+ sections[mLineIndex + 1] += (cand.type ? candidate.candidate.trim()
+ : 'a=end-of-candidates') + '\r\n';
+ this.remoteDescription.sdp = sections.join('');
}
+ }
+ if (arguments.length > 1 && typeof arguments[1] === 'function') {
+ window.setTimeout(arguments[1], 0);
+ }
+ return Promise.resolve();
+ };
- var rtpmapLines = parsers.findLines('a=rtpmap:', lines);
- rtpmapLines.forEach(function (line) {
- var payload = parsers.rtpmap(line);
- payload.parameters = [];
- payload.feedback = [];
-
- var fmtpLines = parsers.findLines('a=fmtp:' + payload.id, lines);
- // There should only be one fmtp line per payload
- fmtpLines.forEach(function (line) {
- payload.parameters = parsers.fmtp(line);
- });
-
- var fbLines = parsers.findLines('a=rtcp-fb:' + payload.id, lines);
- fbLines.forEach(function (line) {
- payload.feedback.push(parsers.rtcpfb(line));
+ window.RTCPeerConnection.prototype.getStats = function() {
+ var promises = [];
+ this.transceivers.forEach(function(transceiver) {
+ ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport',
+ 'dtlsTransport'].forEach(function(method) {
+ if (transceiver[method]) {
+ promises.push(transceiver[method].getStats());
+ }
});
-
- desc.payloads.push(payload);
- });
-
- var cryptoLines = parsers.findLines('a=crypto:', lines, sessionLines);
- cryptoLines.forEach(function (line) {
- desc.encryption.push(parsers.crypto(line));
- });
-
- if (parsers.findLine('a=rtcp-mux', lines)) {
- desc.mux = true;
- }
-
- var fbLines = parsers.findLines('a=rtcp-fb:*', lines);
- fbLines.forEach(function (line) {
- desc.feedback.push(parsers.rtcpfb(line));
- });
-
- var extLines = parsers.findLines('a=extmap:', lines);
- extLines.forEach(function (line) {
- var ext = parsers.extmap(line);
-
- ext.senders = SENDERS[role][direction][ext.senders];
-
- desc.headerExtensions.push(ext);
- });
-
- var ssrcGroupLines = parsers.findLines('a=ssrc-group:', lines);
- desc.sourceGroups = parsers.sourceGroups(ssrcGroupLines || []);
-
- var ssrcLines = parsers.findLines('a=ssrc:', lines);
- var sources = desc.sources = parsers.sources(ssrcLines || []);
-
- var msidLine = parsers.findLine('a=msid:', lines);
- if (msidLine) {
- var msid = parsers.msid(msidLine);
- ['msid', 'mslabel', 'label'].forEach(function (key) {
- for (var i = 0; i < sources.length; i++) {
- var found = false;
- for (var j = 0; j < sources[i].parameters.length; j++) {
- if (sources[i].parameters[j].key === key) {
- found = true;
- }
- }
- if (!found) {
- sources[i].parameters.push({ key: key, value: msid[key] });
- }
- }
+ });
+ var cb = arguments.length > 1 && typeof arguments[1] === 'function' &&
+ arguments[1];
+ return new Promise(function(resolve) {
+ // shim getStats with maplike support
+ var results = new Map();
+ Promise.all(promises).then(function(res) {
+ res.forEach(function(result) {
+ Object.keys(result).forEach(function(id) {
+ results.set(id, result[id]);
+ results[id] = result[id];
});
- }
-
- if (parsers.findLine('a=x-google-flag:conference', lines, sessionLines)) {
- desc.googConferenceFlag = true;
- }
- }
-
- // transport specific attributes
- var fingerprintLines = parsers.findLines('a=fingerprint:', lines, sessionLines);
- var setup = parsers.findLine('a=setup:', lines, sessionLines);
- fingerprintLines.forEach(function (line) {
- var fp = parsers.fingerprint(line);
- if (setup) {
- fp.setup = setup.substr(8);
- }
- trans.fingerprints.push(fp);
- });
-
- var ufragLine = parsers.findLine('a=ice-ufrag:', lines, sessionLines);
- var pwdLine = parsers.findLine('a=ice-pwd:', lines, sessionLines);
- if (ufragLine && pwdLine) {
- trans.ufrag = ufragLine.substr(12);
- trans.pwd = pwdLine.substr(10);
- trans.candidates = [];
-
- var candidateLines = parsers.findLines('a=candidate:', lines, sessionLines);
- candidateLines.forEach(function (line) {
- trans.candidates.push(exports.toCandidateJSON(line));
+ });
+ if (cb) {
+ window.setTimeout(cb, 0, results);
+ }
+ resolve(results);
});
- }
+ });
+ };
+ },
- if (desc.descType == 'datachannel') {
- var sctpmapLines = parsers.findLines('a=sctpmap:', lines);
- sctpmapLines.forEach(function (line) {
- var sctp = parsers.sctpmap(line);
- trans.sctp.push(sctp);
- });
- }
+ // Attach a media stream to an element.
+ attachMediaStream: function(element, stream) {
+ logging('DEPRECATED, attachMediaStream will soon be removed.');
+ element.srcObject = stream;
+ },
- return content;
+ reattachMediaStream: function(to, from) {
+ logging('DEPRECATED, reattachMediaStream will soon be removed.');
+ to.srcObject = from.srcObject;
+ }
};
-exports.toCandidateJSON = function (line) {
- var candidate = parsers.candidate(line.split('\r\n')[0]);
- candidate.id = (idCounter++).toString(36).substr(0, 12);
- return candidate;
+// Expose public methods.
+module.exports = {
+ shimPeerConnection: edgeShim.shimPeerConnection,
+ shimGetUserMedia: require('./getusermedia'),
+ attachMediaStream: edgeShim.attachMediaStream,
+ reattachMediaStream: edgeShim.reattachMediaStream
};
-},{"./parsers":78,"./senders":79}],81:[function(require,module,exports){
-var SENDERS = require('./senders');
-
-
-exports.toSessionSDP = function (session, opts) {
- var role = opts.role || 'initiator';
- var direction = opts.direction || 'outgoing';
- var sid = opts.sid || session.sid || Date.now();
- var time = opts.time || Date.now();
-
- var sdp = [
- 'v=0',
- 'o=- ' + sid + ' ' + time + ' IN IP4 0.0.0.0',
- 's=-',
- 't=0 0',
- 'a=msid-semantic: WMS *'
- ];
+},{"../utils":41,"./getusermedia":37,"sdp":173}],37:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+ /* eslint-env node */
+'use strict';
- var groups = session.groups || [];
- groups.forEach(function (group) {
- sdp.push('a=group:' + group.semantics + ' ' + group.contents.join(' '));
- });
+// Expose public methods.
+module.exports = function() {
+ var shimError_ = function(e) {
+ return {
+ name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name,
+ message: e.message,
+ constraint: e.constraint,
+ toString: function() {
+ return this.name;
+ }
+ };
+ };
- var contents = session.contents || [];
- contents.forEach(function (content) {
- sdp.push(exports.toMediaSDP(content, opts));
+ // getUserMedia error shim.
+ var origGetUserMedia = navigator.mediaDevices.getUserMedia.
+ bind(navigator.mediaDevices);
+ navigator.mediaDevices.getUserMedia = function(c) {
+ return origGetUserMedia(c).catch(function(e) {
+ return Promise.reject(shimError_(e));
});
-
- return sdp.join('\r\n') + '\r\n';
+ };
};
-exports.toMediaSDP = function (content, opts) {
- var sdp = [];
-
- var role = opts.role || 'initiator';
- var direction = opts.direction || 'outgoing';
-
- var desc = content.description;
- var transport = content.transport;
- var payloads = desc.payloads || [];
- var fingerprints = (transport && transport.fingerprints) || [];
-
- var mline = [];
- if (desc.descType == 'datachannel') {
- mline.push('application');
- mline.push('1');
- mline.push('DTLS/SCTP');
- if (transport.sctp) {
- transport.sctp.forEach(function (map) {
- mline.push(map.number);
- });
- }
- } else {
- mline.push(desc.media);
- mline.push('1');
- if ((desc.encryption && desc.encryption.length > 0) || (fingerprints.length > 0)) {
- mline.push('RTP/SAVPF');
- } else {
- mline.push('RTP/AVPF');
- }
- payloads.forEach(function (payload) {
- mline.push(payload.id);
- });
- }
-
-
- sdp.push('m=' + mline.join(' '));
-
- sdp.push('c=IN IP4 0.0.0.0');
- if (desc.bandwidth && desc.bandwidth.type && desc.bandwidth.bandwidth) {
- sdp.push('b=' + desc.bandwidth.type + ':' + desc.bandwidth.bandwidth);
- }
- if (desc.descType == 'rtp') {
- sdp.push('a=rtcp:1 IN IP4 0.0.0.0');
- }
-
- if (transport) {
- if (transport.ufrag) {
- sdp.push('a=ice-ufrag:' + transport.ufrag);
- }
- if (transport.pwd) {
- sdp.push('a=ice-pwd:' + transport.pwd);
- }
+},{}],38:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+ /* eslint-env node */
+'use strict';
- var pushedSetup = false;
- fingerprints.forEach(function (fingerprint) {
- sdp.push('a=fingerprint:' + fingerprint.hash + ' ' + fingerprint.value);
- if (fingerprint.setup && !pushedSetup) {
- sdp.push('a=setup:' + fingerprint.setup);
- }
- });
+var logging = require('../utils').log;
+var browserDetails = require('../utils').browserDetails;
- if (transport.sctp) {
- transport.sctp.forEach(function (map) {
- sdp.push('a=sctpmap:' + map.number + ' ' + map.protocol + ' ' + map.streams);
- });
+var firefoxShim = {
+ shimOnTrack: function() {
+ if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in
+ window.RTCPeerConnection.prototype)) {
+ Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
+ get: function() {
+ return this._ontrack;
+ },
+ set: function(f) {
+ if (this._ontrack) {
+ this.removeEventListener('track', this._ontrack);
+ this.removeEventListener('addstream', this._ontrackpoly);
+ }
+ this.addEventListener('track', this._ontrack = f);
+ this.addEventListener('addstream', this._ontrackpoly = function(e) {
+ e.stream.getTracks().forEach(function(track) {
+ var event = new Event('track');
+ event.track = track;
+ event.receiver = {track: track};
+ event.streams = [e.stream];
+ this.dispatchEvent(event);
+ }.bind(this));
+ }.bind(this));
}
+ });
}
+ },
- if (desc.descType == 'rtp') {
- sdp.push('a=' + (SENDERS[role][direction][content.senders] || 'sendrecv'));
- }
- sdp.push('a=mid:' + content.name);
-
- if (desc.sources && desc.sources.length) {
- (desc.sources[0].parameters || []).forEach(function (param) {
- if (param.key === 'msid') {
- sdp.push('a=msid:' + param.value);
- }
+ shimSourceObject: function() {
+ // Firefox has supported mozSrcObject since FF22, unprefixed in 42.
+ if (typeof window === 'object') {
+ if (window.HTMLMediaElement &&
+ !('srcObject' in window.HTMLMediaElement.prototype)) {
+ // Shim the srcObject property, once, when HTMLMediaElement is found.
+ Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
+ get: function() {
+ return this.mozSrcObject;
+ },
+ set: function(stream) {
+ this.mozSrcObject = stream;
+ }
});
+ }
}
+ },
- if (desc.mux) {
- sdp.push('a=rtcp-mux');
- }
-
- var encryption = desc.encryption || [];
- encryption.forEach(function (crypto) {
- sdp.push('a=crypto:' + crypto.tag + ' ' + crypto.cipherSuite + ' ' + crypto.keyParams + (crypto.sessionParams ? ' ' + crypto.sessionParams : ''));
- });
- if (desc.googConferenceFlag) {
- sdp.push('a=x-google-flag:conference');
- }
-
- payloads.forEach(function (payload) {
- var rtpmap = 'a=rtpmap:' + payload.id + ' ' + payload.name + '/' + payload.clockrate;
- if (payload.channels && payload.channels != '1') {
- rtpmap += '/' + payload.channels;
- }
- sdp.push(rtpmap);
-
- if (payload.parameters && payload.parameters.length) {
- var fmtp = ['a=fmtp:' + payload.id];
- var parameters = [];
- payload.parameters.forEach(function (param) {
- parameters.push((param.key ? param.key + '=' : '') + param.value);
- });
- fmtp.push(parameters.join(';'));
- sdp.push(fmtp.join(' '));
- }
-
- if (payload.feedback) {
- payload.feedback.forEach(function (fb) {
- if (fb.type === 'trr-int') {
- sdp.push('a=rtcp-fb:' + payload.id + ' trr-int ' + (fb.value ? fb.value : '0'));
- } else {
- sdp.push('a=rtcp-fb:' + payload.id + ' ' + fb.type + (fb.subtype ? ' ' + fb.subtype : ''));
+ shimPeerConnection: function() {
+ if (typeof window !== 'object' || !(window.RTCPeerConnection ||
+ window.mozRTCPeerConnection)) {
+ return; // probably media.peerconnection.enabled=false in about:config
+ }
+ // The RTCPeerConnection object.
+ if (!window.RTCPeerConnection) {
+ window.RTCPeerConnection = function(pcConfig, pcConstraints) {
+ if (browserDetails.version < 38) {
+ // .urls is not supported in FF < 38.
+ // create RTCIceServers with a single url.
+ if (pcConfig && pcConfig.iceServers) {
+ var newIceServers = [];
+ for (var i = 0; i < pcConfig.iceServers.length; i++) {
+ var server = pcConfig.iceServers[i];
+ if (server.hasOwnProperty('urls')) {
+ for (var j = 0; j < server.urls.length; j++) {
+ var newServer = {
+ url: server.urls[j]
+ };
+ if (server.urls[j].indexOf('turn') === 0) {
+ newServer.username = server.username;
+ newServer.credential = server.credential;
+ }
+ newIceServers.push(newServer);
}
- });
- }
- });
-
- if (desc.feedback) {
- desc.feedback.forEach(function (fb) {
- if (fb.type === 'trr-int') {
- sdp.push('a=rtcp-fb:* trr-int ' + (fb.value ? fb.value : '0'));
- } else {
- sdp.push('a=rtcp-fb:* ' + fb.type + (fb.subtype ? ' ' + fb.subtype : ''));
+ } else {
+ newIceServers.push(pcConfig.iceServers[i]);
+ }
}
- });
- }
-
- var hdrExts = desc.headerExtensions || [];
- hdrExts.forEach(function (hdr) {
- sdp.push('a=extmap:' + hdr.id + (hdr.senders ? '/' + SENDERS[role][direction][hdr.senders] : '') + ' ' + hdr.uri);
- });
-
- var ssrcGroups = desc.sourceGroups || [];
- ssrcGroups.forEach(function (ssrcGroup) {
- sdp.push('a=ssrc-group:' + ssrcGroup.semantics + ' ' + ssrcGroup.sources.join(' '));
- });
-
- var ssrcs = desc.sources || [];
- ssrcs.forEach(function (ssrc) {
- for (var i = 0; i < ssrc.parameters.length; i++) {
- var param = ssrc.parameters[i];
- sdp.push('a=ssrc:' + (ssrc.ssrc || desc.ssrc) + ' ' + param.key + (param.value ? (':' + param.value) : ''));
+ pcConfig.iceServers = newIceServers;
+ }
}
- });
-
- var candidates = transport.candidates || [];
- candidates.forEach(function (candidate) {
- sdp.push(exports.toCandidateSDP(candidate));
- });
-
- return sdp.join('\r\n');
-};
-
-exports.toCandidateSDP = function (candidate) {
- var sdp = [];
+ return new mozRTCPeerConnection(pcConfig, pcConstraints);
+ };
+ window.RTCPeerConnection.prototype = mozRTCPeerConnection.prototype;
- sdp.push(candidate.foundation);
- sdp.push(candidate.component);
- sdp.push(candidate.protocol.toUpperCase());
- sdp.push(candidate.priority);
- sdp.push(candidate.ip);
- sdp.push(candidate.port);
+ // wrap static methods. Currently just generateCertificate.
+ if (mozRTCPeerConnection.generateCertificate) {
+ Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
+ get: function() {
+ return mozRTCPeerConnection.generateCertificate;
+ }
+ });
+ }
- var type = candidate.type;
- sdp.push('typ');
- sdp.push(type);
- if (type === 'srflx' || type === 'prflx' || type === 'relay') {
- if (candidate.relAddr && candidate.relPort) {
- sdp.push('raddr');
- sdp.push(candidate.relAddr);
- sdp.push('rport');
- sdp.push(candidate.relPort);
- }
- }
- if (candidate.tcpType && candidate.protocol.toUpperCase() == 'TCP') {
- sdp.push('tcptype');
- sdp.push(candidate.tcpType);
+ window.RTCSessionDescription = mozRTCSessionDescription;
+ window.RTCIceCandidate = mozRTCIceCandidate;
}
- sdp.push('generation');
- sdp.push(candidate.generation || '0');
-
- // FIXME: apparently this is wrong per spec
- // but then, we need this when actually putting this into
- // SDP so it's going to stay.
- // decision needs to be revisited when browsers dont
- // accept this any longer
- return 'a=candidate:' + sdp.join(' ');
-};
-
-},{"./senders":79}],82:[function(require,module,exports){
-// based on https://github.com/ESTOS/strophe.jingle/
-// adds wildemitter support
-var util = require('util');
-var adapter = require('webrtc-adapter-test');
-var WildEmitter = require('wildemitter');
-
-function dumpSDP(description) {
- return {
- type: description.type,
- sdp: description.sdp
- };
-}
-
-function dumpStream(stream) {
- var info = {
- label: stream.id,
- };
- if (stream.getAudioTracks().length) {
- info.audio = stream.getAudioTracks().map(function (track) {
- return track.id;
- });
- }
- if (stream.getVideoTracks().length) {
- info.video = stream.getVideoTracks().map(function (track) {
- return track.id;
+ // shim away need for obsolete RTCIceCandidate/RTCSessionDescription.
+ ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
+ .forEach(function(method) {
+ var nativeMethod = RTCPeerConnection.prototype[method];
+ RTCPeerConnection.prototype[method] = function() {
+ arguments[0] = new ((method === 'addIceCandidate') ?
+ RTCIceCandidate : RTCSessionDescription)(arguments[0]);
+ return nativeMethod.apply(this, arguments);
+ };
});
- }
- return info;
-}
-function TraceablePeerConnection(config, constraints) {
- var self = this;
- WildEmitter.call(this);
-
- this.peerconnection = new window.RTCPeerConnection(config, constraints);
-
- this.trace = function (what, info) {
- self.emit('PeerConnectionTrace', {
- time: new Date(),
- type: what,
- value: info || ""
- });
+ // support for addIceCandidate(null)
+ var nativeAddIceCandidate =
+ RTCPeerConnection.prototype.addIceCandidate;
+ RTCPeerConnection.prototype.addIceCandidate = function() {
+ return arguments[0] === null ? Promise.resolve()
+ : nativeAddIceCandidate.apply(this, arguments);
};
- this.onicecandidate = null;
- this.peerconnection.onicecandidate = function (event) {
- self.trace('onicecandidate', event.candidate);
- if (self.onicecandidate !== null) {
- self.onicecandidate(event);
- }
- };
- this.onaddstream = null;
- this.peerconnection.onaddstream = function (event) {
- self.trace('onaddstream', dumpStream(event.stream));
- if (self.onaddstream !== null) {
- self.onaddstream(event);
- }
- };
- this.onremovestream = null;
- this.peerconnection.onremovestream = function (event) {
- self.trace('onremovestream', dumpStream(event.stream));
- if (self.onremovestream !== null) {
- self.onremovestream(event);
- }
- };
- this.onsignalingstatechange = null;
- this.peerconnection.onsignalingstatechange = function (event) {
- self.trace('onsignalingstatechange', self.signalingState);
- if (self.onsignalingstatechange !== null) {
- self.onsignalingstatechange(event);
- }
- };
- this.oniceconnectionstatechange = null;
- this.peerconnection.oniceconnectionstatechange = function (event) {
- self.trace('oniceconnectionstatechange', self.iceConnectionState);
- if (self.oniceconnectionstatechange !== null) {
- self.oniceconnectionstatechange(event);
- }
- };
- this.onnegotiationneeded = null;
- this.peerconnection.onnegotiationneeded = function (event) {
- self.trace('onnegotiationneeded');
- if (self.onnegotiationneeded !== null) {
- self.onnegotiationneeded(event);
- }
- };
- self.ondatachannel = null;
- this.peerconnection.ondatachannel = function (event) {
- self.trace('ondatachannel', event);
- if (self.ondatachannel !== null) {
- self.ondatachannel(event);
- }
+ // shim getStats with maplike support
+ var makeMapStats = function(stats) {
+ var map = new Map();
+ Object.keys(stats).forEach(function(key) {
+ map.set(key, stats[key]);
+ map[key] = stats[key];
+ });
+ return map;
};
- this.getLocalStreams = this.peerconnection.getLocalStreams.bind(this.peerconnection);
- this.getRemoteStreams = this.peerconnection.getRemoteStreams.bind(this.peerconnection);
-}
-
-util.inherits(TraceablePeerConnection, WildEmitter);
-
-['signalingState', 'iceConnectionState', 'localDescription', 'remoteDescription'].forEach(function (prop) {
- Object.defineProperty(TraceablePeerConnection.prototype, prop, {
- get: function () {
- return this.peerconnection[prop];
- }
- });
-});
-
-TraceablePeerConnection.prototype.addStream = function (stream) {
- this.trace('addStream', dumpStream(stream));
- this.peerconnection.addStream(stream);
-};
-
-TraceablePeerConnection.prototype.removeStream = function (stream) {
- this.trace('removeStream', dumpStream(stream));
- this.peerconnection.removeStream(stream);
-};
-
-TraceablePeerConnection.prototype.createDataChannel = function (label, opts) {
- this.trace('createDataChannel', label, opts);
- return this.peerconnection.createDataChannel(label, opts);
-};
-
-TraceablePeerConnection.prototype.setLocalDescription = function (description, successCallback, failureCallback) {
- var self = this;
- this.trace('setLocalDescription', dumpSDP(description));
- this.peerconnection.setLocalDescription(description,
- function () {
- self.trace('setLocalDescriptionOnSuccess');
- if (successCallback) successCallback();
- },
- function (err) {
- self.trace('setLocalDescriptionOnFailure', err);
- if (failureCallback) failureCallback(err);
- }
- );
-};
-
-TraceablePeerConnection.prototype.setRemoteDescription = function (description, successCallback, failureCallback) {
- var self = this;
- this.trace('setRemoteDescription', dumpSDP(description));
- this.peerconnection.setRemoteDescription(description,
- function () {
- self.trace('setRemoteDescriptionOnSuccess');
- if (successCallback) successCallback();
- },
- function (err) {
- self.trace('setRemoteDescriptionOnFailure', err);
- if (failureCallback) failureCallback(err);
- }
- );
-};
-
-TraceablePeerConnection.prototype.close = function () {
- this.trace('stop');
- if (this.peerconnection.signalingState != 'closed') {
- this.peerconnection.close();
- }
-};
-TraceablePeerConnection.prototype.createOffer = function (successCallback, failureCallback, constraints) {
- var self = this;
- this.trace('createOffer', constraints);
- this.peerconnection.createOffer(
- function (offer) {
- self.trace('createOfferOnSuccess', dumpSDP(offer));
- if (successCallback) successCallback(offer);
- },
- function (err) {
- self.trace('createOfferOnFailure', err);
- if (failureCallback) failureCallback(err);
- },
- constraints
- );
-};
+ var nativeGetStats = RTCPeerConnection.prototype.getStats;
+ RTCPeerConnection.prototype.getStats = function(selector, onSucc, onErr) {
+ return nativeGetStats.apply(this, [selector || null])
+ .then(function(stats) {
+ return makeMapStats(stats);
+ })
+ .then(onSucc, onErr);
+ };
+ },
-TraceablePeerConnection.prototype.createAnswer = function (successCallback, failureCallback, constraints) {
- var self = this;
- this.trace('createAnswer', constraints);
- this.peerconnection.createAnswer(
- function (answer) {
- self.trace('createAnswerOnSuccess', dumpSDP(answer));
- if (successCallback) successCallback(answer);
- },
- function (err) {
- self.trace('createAnswerOnFailure', err);
- if (failureCallback) failureCallback(err);
- },
- constraints
- );
-};
+ // Attach a media stream to an element.
+ attachMediaStream: function(element, stream) {
+ logging('DEPRECATED, attachMediaStream will soon be removed.');
+ element.srcObject = stream;
+ },
-TraceablePeerConnection.prototype.addIceCandidate = function (candidate, successCallback, failureCallback) {
- var self = this;
- this.trace('addIceCandidate', candidate);
- this.peerconnection.addIceCandidate(candidate,
- function () {
- //self.trace('addIceCandidateOnSuccess');
- if (successCallback) successCallback();
- },
- function (err) {
- self.trace('addIceCandidateOnFailure', err);
- if (failureCallback) failureCallback(err);
- }
- );
+ reattachMediaStream: function(to, from) {
+ logging('DEPRECATED, reattachMediaStream will soon be removed.');
+ to.srcObject = from.srcObject;
+ }
};
-TraceablePeerConnection.prototype.getStats = function () {
- this.peerconnection.getStats.apply(this.peerconnection, arguments);
+// Expose public methods.
+module.exports = {
+ shimOnTrack: firefoxShim.shimOnTrack,
+ shimSourceObject: firefoxShim.shimSourceObject,
+ shimPeerConnection: firefoxShim.shimPeerConnection,
+ shimGetUserMedia: require('./getusermedia'),
+ attachMediaStream: firefoxShim.attachMediaStream,
+ reattachMediaStream: firefoxShim.reattachMediaStream
};
-module.exports = TraceablePeerConnection;
-
-},{"util":28,"webrtc-adapter-test":83,"wildemitter":84}],83:[function(require,module,exports){
+},{"../utils":41,"./getusermedia":39}],39:[function(require,module,exports){
/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
-
-/* More information about these options at jshint.com/docs/options */
-/* jshint browser: true, camelcase: true, curly: true, devel: true,
- eqeqeq: true, forin: false, globalstrict: true, node: true,
- quotmark: single, undef: true, unused: strict */
-/* global mozRTCIceCandidate, mozRTCPeerConnection, Promise,
-mozRTCSessionDescription, webkitRTCPeerConnection, MediaStreamTrack */
-/* exported trace,requestUserMedia */
-
+ /* eslint-env node */
'use strict';
-var getUserMedia = null;
-var attachMediaStream = null;
-var reattachMediaStream = null;
-var webrtcDetectedBrowser = null;
-var webrtcDetectedVersion = null;
-var webrtcMinimumVersion = null;
-var webrtcUtils = {
- log: function() {
- // suppress console.log output when being included as a module.
- if (typeof module !== 'undefined' ||
- typeof require === 'function' && typeof define === 'function') {
- return;
- }
- console.log.apply(console, arguments);
- },
- extractVersion: function(uastring, expr, pos) {
- var match = uastring.match(expr);
- return match && match.length >= pos && parseInt(match[pos]);
- }
-};
-
-function trace(text) {
- // This function is used for logging.
- if (text[text.length - 1] === '\n') {
- text = text.substring(0, text.length - 1);
- }
- if (window.performance) {
- var now = (window.performance.now() / 1000).toFixed(3);
- webrtcUtils.log(now + ': ' + text);
- } else {
- webrtcUtils.log(text);
- }
-}
-
-if (typeof window === 'object') {
- if (window.HTMLMediaElement &&
- !('srcObject' in window.HTMLMediaElement.prototype)) {
- // Shim the srcObject property, once, when HTMLMediaElement is found.
- Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
- get: function() {
- // If prefixed srcObject property exists, return it.
- // Otherwise use the shimmed property, _srcObject
- return 'mozSrcObject' in this ? this.mozSrcObject : this._srcObject;
- },
- set: function(stream) {
- if ('mozSrcObject' in this) {
- this.mozSrcObject = stream;
- } else {
- // Use _srcObject as a private property for this shim
- this._srcObject = stream;
- // TODO: revokeObjectUrl(this.src) when !stream to release resources?
- this.src = URL.createObjectURL(stream);
- }
- }
- });
- }
- // Proxy existing globals
- getUserMedia = window.navigator && window.navigator.getUserMedia;
-}
-
-// Attach a media stream to an element.
-attachMediaStream = function(element, stream) {
- element.srcObject = stream;
-};
-
-reattachMediaStream = function(to, from) {
- to.srcObject = from.srcObject;
-};
-
-if (typeof window === 'undefined' || !window.navigator) {
- webrtcUtils.log('This does not appear to be a browser');
- webrtcDetectedBrowser = 'not a browser';
-} else if (navigator.mozGetUserMedia && window.mozRTCPeerConnection) {
- webrtcUtils.log('This appears to be Firefox');
-
- webrtcDetectedBrowser = 'firefox';
-
- // the detected firefox version.
- webrtcDetectedVersion = webrtcUtils.extractVersion(navigator.userAgent,
- /Firefox\/([0-9]+)\./, 1);
-
- // the minimum firefox version still supported by adapter.
- webrtcMinimumVersion = 31;
+var logging = require('../utils').log;
+var browserDetails = require('../utils').browserDetails;
- // The RTCPeerConnection object.
- window.RTCPeerConnection = function(pcConfig, pcConstraints) {
- if (webrtcDetectedVersion < 38) {
- // .urls is not supported in FF < 38.
- // create RTCIceServers with a single url.
- if (pcConfig && pcConfig.iceServers) {
- var newIceServers = [];
- for (var i = 0; i < pcConfig.iceServers.length; i++) {
- var server = pcConfig.iceServers[i];
- if (server.hasOwnProperty('urls')) {
- for (var j = 0; j < server.urls.length; j++) {
- var newServer = {
- url: server.urls[j]
- };
- if (server.urls[j].indexOf('turn') === 0) {
- newServer.username = server.username;
- newServer.credential = server.credential;
- }
- newIceServers.push(newServer);
- }
- } else {
- newIceServers.push(pcConfig.iceServers[i]);
- }
- }
- pcConfig.iceServers = newIceServers;
+// Expose public methods.
+module.exports = function() {
+ var shimError_ = function(e) {
+ return {
+ name: {
+ SecurityError: 'NotAllowedError',
+ PermissionDeniedError: 'NotAllowedError'
+ }[e.name] || e.name,
+ message: {
+ 'The operation is insecure.': 'The request is not allowed by the ' +
+ 'user agent or the platform in the current context.'
+ }[e.message] || e.message,
+ constraint: e.constraint,
+ toString: function() {
+ return this.name + (this.message && ': ') + this.message;
}
- }
- return new mozRTCPeerConnection(pcConfig, pcConstraints); // jscs:ignore requireCapitalizedConstructors
+ };
};
- // The RTCSessionDescription object.
- if (!window.RTCSessionDescription) {
- window.RTCSessionDescription = mozRTCSessionDescription;
- }
-
- // The RTCIceCandidate object.
- if (!window.RTCIceCandidate) {
- window.RTCIceCandidate = mozRTCIceCandidate;
- }
-
// getUserMedia constraints shim.
- getUserMedia = function(constraints, onSuccess, onError) {
- var constraintsToFF37 = function(c) {
+ var getUserMedia_ = function(constraints, onSuccess, onError) {
+ var constraintsToFF37_ = function(c) {
if (typeof c !== 'object' || c.require) {
return c;
}
@@ -12049,7 +5347,7 @@ if (typeof window === 'undefined' || !window.navigator) {
}
if (r.exact !== undefined) {
if (typeof r.exact === 'number') {
- r.min = r.max = r.exact;
+ r. min = r.max = r.exact;
} else {
c[key] = r.exact;
}
@@ -12075,40 +5373,48 @@ if (typeof window === 'undefined' || !window.navigator) {
}
return c;
};
- if (webrtcDetectedVersion < 38) {
- webrtcUtils.log('spec: ' + JSON.stringify(constraints));
+ constraints = JSON.parse(JSON.stringify(constraints));
+ if (browserDetails.version < 38) {
+ logging('spec: ' + JSON.stringify(constraints));
if (constraints.audio) {
- constraints.audio = constraintsToFF37(constraints.audio);
+ constraints.audio = constraintsToFF37_(constraints.audio);
}
if (constraints.video) {
- constraints.video = constraintsToFF37(constraints.video);
+ constraints.video = constraintsToFF37_(constraints.video);
}
- webrtcUtils.log('ff37: ' + JSON.stringify(constraints));
+ logging('ff37: ' + JSON.stringify(constraints));
}
- return navigator.mozGetUserMedia(constraints, onSuccess, onError);
+ return navigator.mozGetUserMedia(constraints, onSuccess, function(e) {
+ onError(shimError_(e));
+ });
};
- navigator.getUserMedia = getUserMedia;
+ // Returns the result of getUserMedia as a Promise.
+ var getUserMediaPromise_ = function(constraints) {
+ return new Promise(function(resolve, reject) {
+ getUserMedia_(constraints, resolve, reject);
+ });
+ };
// Shim for mediaDevices on older versions.
if (!navigator.mediaDevices) {
- navigator.mediaDevices = {getUserMedia: requestUserMedia,
+ navigator.mediaDevices = {getUserMedia: getUserMediaPromise_,
addEventListener: function() { },
removeEventListener: function() { }
};
}
navigator.mediaDevices.enumerateDevices =
navigator.mediaDevices.enumerateDevices || function() {
- return new Promise(function(resolve) {
- var infos = [
- {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''},
- {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''}
- ];
- resolve(infos);
- });
- };
+ return new Promise(function(resolve) {
+ var infos = [
+ {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''},
+ {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''}
+ ];
+ resolve(infos);
+ });
+ };
- if (webrtcDetectedVersion < 41) {
+ if (browserDetails.version < 41) {
// Work around http://bugzil.la/1169665
var orgEnumerateDevices =
navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices);
@@ -12121,1177 +5427,695 @@ if (typeof window === 'undefined' || !window.navigator) {
});
};
}
-} else if (navigator.webkitGetUserMedia && window.webkitRTCPeerConnection) {
- webrtcUtils.log('This appears to be Chrome');
-
- webrtcDetectedBrowser = 'chrome';
-
- // the detected chrome version.
- webrtcDetectedVersion = webrtcUtils.extractVersion(navigator.userAgent,
- /Chrom(e|ium)\/([0-9]+)\./, 2);
-
- // the minimum chrome version still supported by adapter.
- webrtcMinimumVersion = 38;
-
- // The RTCPeerConnection object.
- window.RTCPeerConnection = function(pcConfig, pcConstraints) {
- // Translate iceTransportPolicy to iceTransports,
- // see https://code.google.com/p/webrtc/issues/detail?id=4869
- if (pcConfig && pcConfig.iceTransportPolicy) {
- pcConfig.iceTransports = pcConfig.iceTransportPolicy;
+ if (browserDetails.version < 49) {
+ var origGetUserMedia = navigator.mediaDevices.getUserMedia.
+ bind(navigator.mediaDevices);
+ navigator.mediaDevices.getUserMedia = function(c) {
+ return origGetUserMedia(c).catch(function(e) {
+ return Promise.reject(shimError_(e));
+ });
+ };
+ }
+ navigator.getUserMedia = function(constraints, onSuccess, onError) {
+ if (browserDetails.version < 44) {
+ return getUserMedia_(constraints, onSuccess, onError);
}
+ // Replace Firefox 44+'s deprecation warning with unprefixed version.
+ console.warn('navigator.getUserMedia has been replaced by ' +
+ 'navigator.mediaDevices.getUserMedia');
+ navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);
+ };
+};
- var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints); // jscs:ignore requireCapitalizedConstructors
- var origGetStats = pc.getStats.bind(pc);
- pc.getStats = function(selector, successCallback, errorCallback) { // jshint ignore: line
- var self = this;
- var args = arguments;
-
- // If selector is a function then we are in the old style stats so just
- // pass back the original getStats format to avoid breaking old users.
- if (arguments.length > 0 && typeof selector === 'function') {
- return origGetStats(selector, successCallback);
- }
-
- var fixChromeStats = function(response) {
- var standardReport = {};
- var reports = response.result();
- reports.forEach(function(report) {
- var standardStats = {
- id: report.id,
- timestamp: report.timestamp,
- type: report.type
- };
- report.names().forEach(function(name) {
- standardStats[name] = report.stat(name);
- });
- standardReport[standardStats.id] = standardStats;
- });
-
- return standardReport;
- };
+},{"../utils":41}],40:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+'use strict';
+var safariShim = {
+ // TODO: DrAlex, should be here, double check against LayoutTests
+ // shimOnTrack: function() { },
- if (arguments.length >= 2) {
- var successCallbackWrapper = function(response) {
- args[1](fixChromeStats(response));
- };
+ // TODO: DrAlex
+ // attachMediaStream: function(element, stream) { },
+ // reattachMediaStream: function(to, from) { },
- return origGetStats.apply(this, [successCallbackWrapper, arguments[0]]);
- }
+ // TODO: once the back-end for the mac port is done, add.
+ // TODO: check for webkitGTK+
+ // shimPeerConnection: function() { },
- // promise-support
- return new Promise(function(resolve, reject) {
- if (args.length === 1 && selector === null) {
- origGetStats.apply(self, [
- function(response) {
- resolve.apply(null, [fixChromeStats(response)]);
- }, reject]);
- } else {
- origGetStats.apply(self, [resolve, reject]);
- }
- });
- };
+ shimGetUserMedia: function() {
+ navigator.getUserMedia = navigator.webkitGetUserMedia;
+ }
+};
- return pc;
- };
+// Expose public methods.
+module.exports = {
+ shimGetUserMedia: safariShim.shimGetUserMedia
+ // TODO
+ // shimOnTrack: safariShim.shimOnTrack,
+ // shimPeerConnection: safariShim.shimPeerConnection,
+ // attachMediaStream: safariShim.attachMediaStream,
+ // reattachMediaStream: safariShim.reattachMediaStream
+};
- // add promise support
- ['createOffer', 'createAnswer'].forEach(function(method) {
- var nativeMethod = webkitRTCPeerConnection.prototype[method];
- webkitRTCPeerConnection.prototype[method] = function() {
- var self = this;
- if (arguments.length < 1 || (arguments.length === 1 &&
- typeof(arguments[0]) === 'object')) {
- var opts = arguments.length === 1 ? arguments[0] : undefined;
- return new Promise(function(resolve, reject) {
- nativeMethod.apply(self, [resolve, reject, opts]);
- });
- } else {
- return nativeMethod.apply(this, arguments);
- }
- };
- });
+},{}],41:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+ /* eslint-env node */
+'use strict';
- ['setLocalDescription', 'setRemoteDescription',
- 'addIceCandidate'].forEach(function(method) {
- var nativeMethod = webkitRTCPeerConnection.prototype[method];
- webkitRTCPeerConnection.prototype[method] = function() {
- var args = arguments;
- var self = this;
- return new Promise(function(resolve, reject) {
- nativeMethod.apply(self, [args[0],
- function() {
- resolve();
- if (args.length >= 2) {
- args[1].apply(null, []);
- }
- },
- function(err) {
- reject(err);
- if (args.length >= 3) {
- args[2].apply(null, [err]);
- }
- }]
- );
- });
- };
- });
+var logDisabled_ = true;
- // getUserMedia constraints shim.
- var constraintsToChrome = function(c) {
- if (typeof c !== 'object' || c.mandatory || c.optional) {
- return c;
+// Utility methods.
+var utils = {
+ disableLog: function(bool) {
+ if (typeof bool !== 'boolean') {
+ return new Error('Argument type: ' + typeof bool +
+ '. Please use a boolean.');
}
- var cc = {};
- Object.keys(c).forEach(function(key) {
- if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
+ logDisabled_ = bool;
+ return (bool) ? 'adapter.js logging disabled' :
+ 'adapter.js logging enabled';
+ },
+
+ log: function() {
+ if (typeof window === 'object') {
+ if (logDisabled_) {
return;
}
- var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]};
- if (r.exact !== undefined && typeof r.exact === 'number') {
- r.min = r.max = r.exact;
+ if (typeof console !== 'undefined' && typeof console.log === 'function') {
+ console.log.apply(console, arguments);
}
- var oldname = function(prefix, name) {
- if (prefix) {
- return prefix + name.charAt(0).toUpperCase() + name.slice(1);
- }
- return (name === 'deviceId') ? 'sourceId' : name;
- };
- if (r.ideal !== undefined) {
- cc.optional = cc.optional || [];
- var oc = {};
- if (typeof r.ideal === 'number') {
- oc[oldname('min', key)] = r.ideal;
- cc.optional.push(oc);
- oc = {};
- oc[oldname('max', key)] = r.ideal;
- cc.optional.push(oc);
+ }
+ },
+
+ /**
+ * Extract browser version out of the provided user agent string.
+ *
+ * @param {!string} uastring userAgent string.
+ * @param {!string} expr Regular expression used as match criteria.
+ * @param {!number} pos position in the version string to be returned.
+ * @return {!number} browser version.
+ */
+ extractVersion: function(uastring, expr, pos) {
+ var match = uastring.match(expr);
+ return match && match.length >= pos && parseInt(match[pos], 10);
+ },
+
+ /**
+ * Browser detector.
+ *
+ * @return {object} result containing browser, version and minVersion
+ * properties.
+ */
+ detectBrowser: function() {
+ // Returned result object.
+ var result = {};
+ result.browser = null;
+ result.version = null;
+ result.minVersion = null;
+
+ // Fail early if it's not a browser
+ if (typeof window === 'undefined' || !window.navigator) {
+ result.browser = 'Not a browser.';
+ return result;
+ }
+
+ // Firefox.
+ if (navigator.mozGetUserMedia) {
+ result.browser = 'firefox';
+ result.version = this.extractVersion(navigator.userAgent,
+ /Firefox\/([0-9]+)\./, 1);
+ result.minVersion = 31;
+
+ // all webkit-based browsers
+ } else if (navigator.webkitGetUserMedia) {
+ // Chrome, Chromium, Webview, Opera, all use the chrome shim for now
+ if (window.webkitRTCPeerConnection) {
+ result.browser = 'chrome';
+ result.version = this.extractVersion(navigator.userAgent,
+ /Chrom(e|ium)\/([0-9]+)\./, 2);
+ result.minVersion = 38;
+
+ // Safari or unknown webkit-based
+ // for the time being Safari has support for MediaStreams but not webRTC
+ } else {
+ // Safari UA substrings of interest for reference:
+ // - webkit version: AppleWebKit/602.1.25 (also used in Op,Cr)
+ // - safari UI version: Version/9.0.3 (unique to Safari)
+ // - safari UI webkit version: Safari/601.4.4 (also used in Op,Cr)
+ //
+ // if the webkit version and safari UI webkit versions are equals,
+ // ... this is a stable version.
+ //
+ // only the internal webkit version is important today to know if
+ // media streams are supported
+ //
+ if (navigator.userAgent.match(/Version\/(\d+).(\d+)/)) {
+ result.browser = 'safari';
+ result.version = this.extractVersion(navigator.userAgent,
+ /AppleWebKit\/([0-9]+)\./, 1);
+ result.minVersion = 602;
+
+ // unknown webkit-based browser
} else {
- oc[oldname('', key)] = r.ideal;
- cc.optional.push(oc);
+ result.browser = 'Unsupported webkit-based browser ' +
+ 'with GUM support but no WebRTC support.';
+ return result;
}
}
- if (r.exact !== undefined && typeof r.exact !== 'number') {
- cc.mandatory = cc.mandatory || {};
- cc.mandatory[oldname('', key)] = r.exact;
- } else {
- ['min', 'max'].forEach(function(mix) {
- if (r[mix] !== undefined) {
- cc.mandatory = cc.mandatory || {};
- cc.mandatory[oldname(mix, key)] = r[mix];
- }
- });
- }
- });
- if (c.advanced) {
- cc.optional = (cc.optional || []).concat(c.advanced);
- }
- return cc;
- };
- getUserMedia = function(constraints, onSuccess, onError) {
- if (constraints.audio) {
- constraints.audio = constraintsToChrome(constraints.audio);
+ // Edge.
+ } else if (navigator.mediaDevices &&
+ navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) {
+ result.browser = 'edge';
+ result.version = this.extractVersion(navigator.userAgent,
+ /Edge\/(\d+).(\d+)$/, 2);
+ result.minVersion = 10547;
+
+ // Default fallthrough: not supported.
+ } else {
+ result.browser = 'Not a supported browser.';
+ return result;
}
- if (constraints.video) {
- constraints.video = constraintsToChrome(constraints.video);
+
+ // Warn if version is less than minVersion.
+ if (result.version < result.minVersion) {
+ utils.log('Browser: ' + result.browser + ' Version: ' + result.version +
+ ' < minimum supported version: ' + result.minVersion +
+ '\n some things might not work!');
}
- webrtcUtils.log('chrome: ' + JSON.stringify(constraints));
- return navigator.webkitGetUserMedia(constraints, onSuccess, onError);
- };
- navigator.getUserMedia = getUserMedia;
- if (!navigator.mediaDevices) {
- navigator.mediaDevices = {getUserMedia: requestUserMedia,
- enumerateDevices: function() {
- return new Promise(function(resolve) {
- var kinds = {audio: 'audioinput', video: 'videoinput'};
- return MediaStreamTrack.getSources(function(devices) {
- resolve(devices.map(function(device) {
- return {label: device.label,
- kind: kinds[device.kind],
- deviceId: device.id,
- groupId: ''};
- }));
- });
- });
- }};
+ return result;
}
+};
- // A shim for getUserMedia method on the mediaDevices object.
- // TODO(KaptenJansson) remove once implemented in Chrome stable.
- if (!navigator.mediaDevices.getUserMedia) {
- navigator.mediaDevices.getUserMedia = function(constraints) {
- return requestUserMedia(constraints);
- };
- } else {
- // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia
- // function which returns a Promise, it does not accept spec-style
- // constraints.
- var origGetUserMedia = navigator.mediaDevices.getUserMedia.
- bind(navigator.mediaDevices);
- navigator.mediaDevices.getUserMedia = function(c) {
- webrtcUtils.log('spec: ' + JSON.stringify(c)); // whitespace for alignment
- c.audio = constraintsToChrome(c.audio);
- c.video = constraintsToChrome(c.video);
- webrtcUtils.log('chrome: ' + JSON.stringify(c));
- return origGetUserMedia(c);
- };
- }
+// Export.
+module.exports = {
+ log: utils.log,
+ disableLog: utils.disableLog,
+ browserDetails: utils.detectBrowser(),
+ extractVersion: utils.extractVersion
+};
- // Dummy devicechange event methods.
- // TODO(KaptenJansson) remove once implemented in Chrome stable.
- if (typeof navigator.mediaDevices.addEventListener === 'undefined') {
- navigator.mediaDevices.addEventListener = function() {
- webrtcUtils.log('Dummy mediaDevices.addEventListener called.');
- };
- }
- if (typeof navigator.mediaDevices.removeEventListener === 'undefined') {
- navigator.mediaDevices.removeEventListener = function() {
- webrtcUtils.log('Dummy mediaDevices.removeEventListener called.');
- };
- }
+},{}],42:[function(require,module,exports){
+var createHash = require('create-hash');
+var createHmac = require('create-hmac');
+var getHashes = require('./lib/get-hashes');
- // Attach a media stream to an element.
- attachMediaStream = function(element, stream) {
- if (webrtcDetectedVersion >= 43) {
- element.srcObject = stream;
- } else if (typeof element.src !== 'undefined') {
- element.src = URL.createObjectURL(stream);
- } else {
- webrtcUtils.log('Error attaching stream to element.');
- }
- };
- reattachMediaStream = function(to, from) {
- if (webrtcDetectedVersion >= 43) {
- to.srcObject = from.srcObject;
- } else {
- to.src = from.src;
- }
- };
+var mapping = {
+ md2: 'md2',
+ md5: 'md5',
+ 'sha-1': 'sha1',
+ 'sha-224': 'sha224',
+ 'sha-256': 'sha256',
+ 'sha-384': 'sha384',
+ 'sha-512': 'sha512'
+};
-} else if (navigator.mediaDevices && navigator.userAgent.match(
- /Edge\/(\d+).(\d+)$/)) {
- webrtcUtils.log('This appears to be Edge');
- webrtcDetectedBrowser = 'edge';
+var names = Object.keys(mapping);
- webrtcDetectedVersion = webrtcUtils.extractVersion(navigator.userAgent,
- /Edge\/(\d+).(\d+)$/, 2);
- // the minimum version still supported by adapter.
- webrtcMinimumVersion = 12;
-} else {
- webrtcUtils.log('Browser does not appear to be WebRTC-capable');
-}
+exports.getHashes = function () {
+ var result = [];
+ var available = getHashes();
+ for (var i = 0, len = names.length; i < len; i++) {
+ if (available.indexOf(mapping[names[i]]) >= 0) {
+ result.push(names[i]);
+ }
+ }
+ return result;
+};
-// Returns the result of getUserMedia as a Promise.
-function requestUserMedia(constraints) {
- return new Promise(function(resolve, reject) {
- getUserMedia(constraints, resolve, reject);
- });
-}
+exports.createHash = function (algorithm) {
+ algorithm = algorithm.toLowerCase();
+ if (mapping[algorithm]) {
+ algorithm = mapping[algorithm];
+ }
+ return createHash(algorithm);
+};
-var webrtcTesting = {};
-try {
- Object.defineProperty(webrtcTesting, 'version', {
- set: function(version) {
- webrtcDetectedVersion = version;
+exports.createHmac = function (algorithm, key) {
+ algorithm = algorithm.toLowerCase();
+ if (mapping[algorithm]) {
+ algorithm = mapping[algorithm];
}
- });
-} catch (e) {}
+ return createHmac(algorithm, key);
+};
-if (typeof module !== 'undefined') {
- var RTCPeerConnection;
- if (typeof window !== 'undefined') {
- RTCPeerConnection = window.RTCPeerConnection;
- }
- module.exports = {
- RTCPeerConnection: RTCPeerConnection,
- getUserMedia: getUserMedia,
- attachMediaStream: attachMediaStream,
- reattachMediaStream: reattachMediaStream,
- webrtcDetectedBrowser: webrtcDetectedBrowser,
- webrtcDetectedVersion: webrtcDetectedVersion,
- webrtcMinimumVersion: webrtcMinimumVersion,
- webrtcTesting: webrtcTesting,
- webrtcUtils: webrtcUtils
- //requestUserMedia: not exposed on purpose.
- //trace: not exposed on purpose.
- };
-} else if ((typeof require === 'function') && (typeof define === 'function')) {
- // Expose objects and functions when RequireJS is doing the loading.
- define([], function() {
- return {
- RTCPeerConnection: window.RTCPeerConnection,
- getUserMedia: getUserMedia,
- attachMediaStream: attachMediaStream,
- reattachMediaStream: reattachMediaStream,
- webrtcDetectedBrowser: webrtcDetectedBrowser,
- webrtcDetectedVersion: webrtcDetectedVersion,
- webrtcMinimumVersion: webrtcMinimumVersion,
- webrtcTesting: webrtcTesting,
- webrtcUtils: webrtcUtils
- //requestUserMedia: not exposed on purpose.
- //trace: not exposed on purpose.
- };
- });
-}
+},{"./lib/get-hashes":43,"create-hash":23,"create-hmac":26}],43:[function(require,module,exports){
+module.exports = function () {
+ return ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'md5', 'rmd160'];
+};
-},{}],84:[function(require,module,exports){
-arguments[4][53][0].apply(exports,arguments)
-},{"dup":53}],85:[function(require,module,exports){
-var util = require('util');
-var each = require('lodash.foreach');
-var pluck = require('lodash.pluck');
-var SJJ = require('sdp-jingle-json');
-var WildEmitter = require('wildemitter');
-var peerconn = require('traceablepeerconnection');
-var adapter = require('webrtc-adapter-test');
+},{}],44:[function(require,module,exports){
+exports.read = function (buffer, offset, isLE, mLen, nBytes) {
+ var e, m
+ var eLen = nBytes * 8 - mLen - 1
+ var eMax = (1 << eLen) - 1
+ var eBias = eMax >> 1
+ var nBits = -7
+ var i = isLE ? (nBytes - 1) : 0
+ var d = isLE ? -1 : 1
+ var s = buffer[offset + i]
-function PeerConnection(config, constraints) {
- var self = this;
- var item;
- WildEmitter.call(this);
+ i += d
- config = config || {};
- config.iceServers = config.iceServers || [];
+ e = s & ((1 << (-nBits)) - 1)
+ s >>= (-nBits)
+ nBits += eLen
+ for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
- // make sure this only gets enabled in Google Chrome
- // EXPERIMENTAL FLAG, might get removed without notice
- this.enableChromeNativeSimulcast = false;
- if (constraints && constraints.optional &&
- adapter.webrtcDetectedBrowser === 'chrome' &&
- navigator.appVersion.match(/Chromium\//) === null) {
- constraints.optional.forEach(function (constraint) {
- if (constraint.enableChromeNativeSimulcast) {
- self.enableChromeNativeSimulcast = true;
- }
- });
- }
+ m = e & ((1 << (-nBits)) - 1)
+ e >>= (-nBits)
+ nBits += mLen
+ for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
- // EXPERIMENTAL FLAG, might get removed without notice
- this.enableMultiStreamHacks = false;
- if (constraints && constraints.optional &&
- adapter.webrtcDetectedBrowser === 'chrome') {
- constraints.optional.forEach(function (constraint) {
- if (constraint.enableMultiStreamHacks) {
- self.enableMultiStreamHacks = true;
- }
- });
- }
- // EXPERIMENTAL FLAG, might get removed without notice
- this.restrictBandwidth = 0;
- if (constraints && constraints.optional) {
- constraints.optional.forEach(function (constraint) {
- if (constraint.andyetRestrictBandwidth) {
- self.restrictBandwidth = constraint.andyetRestrictBandwidth;
- }
- });
- }
+ if (e === 0) {
+ e = 1 - eBias
+ } else if (e === eMax) {
+ return m ? NaN : ((s ? -1 : 1) * Infinity)
+ } else {
+ m = m + Math.pow(2, mLen)
+ e = e - eBias
+ }
+ return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
+}
- // EXPERIMENTAL FLAG, might get removed without notice
- // bundle up ice candidates, only works for jingle mode
- // number > 0 is the delay to wait for additional candidates
- // ~20ms seems good
- this.batchIceCandidates = 0;
- if (constraints && constraints.optional) {
- constraints.optional.forEach(function (constraint) {
- if (constraint.andyetBatchIce) {
- self.batchIceCandidates = constraint.andyetBatchIce;
- }
- });
- }
- this.batchedIceCandidates = [];
+exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
+ var e, m, c
+ var eLen = nBytes * 8 - mLen - 1
+ var eMax = (1 << eLen) - 1
+ var eBias = eMax >> 1
+ var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
+ var i = isLE ? 0 : (nBytes - 1)
+ var d = isLE ? 1 : -1
+ var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
- // EXPERIMENTAL FLAG, might get removed without notice
- // this attemps to strip out candidates with an already known foundation
- // and type -- i.e. those which are gathered via the same TURN server
- // but different transports (TURN udp, tcp and tls respectively)
- if (constraints && constraints.optional && adapter.webrtcDetectedBrowser === 'chrome') {
- constraints.optional.forEach(function (constraint) {
- if (constraint.andyetFasterICE) {
- self.eliminateDuplicateCandidates = constraint.andyetFasterICE;
- }
- });
+ value = Math.abs(value)
+
+ if (isNaN(value) || value === Infinity) {
+ m = isNaN(value) ? 1 : 0
+ e = eMax
+ } else {
+ e = Math.floor(Math.log(value) / Math.LN2)
+ if (value * (c = Math.pow(2, -e)) < 1) {
+ e--
+ c *= 2
}
- // EXPERIMENTAL FLAG, might get removed without notice
- // when using a server such as the jitsi videobridge we don't need to signal
- // our candidates
- if (constraints && constraints.optional) {
- constraints.optional.forEach(function (constraint) {
- if (constraint.andyetDontSignalCandidates) {
- self.dontSignalCandidates = constraint.andyetDontSignalCandidates;
- }
- });
+ if (e + eBias >= 1) {
+ value += rt / c
+ } else {
+ value += rt * Math.pow(2, 1 - eBias)
}
-
-
- // EXPERIMENTAL FLAG, might get removed without notice
- this.assumeSetLocalSuccess = false;
- if (constraints && constraints.optional) {
- constraints.optional.forEach(function (constraint) {
- if (constraint.andyetAssumeSetLocalSuccess) {
- self.assumeSetLocalSuccess = constraint.andyetAssumeSetLocalSuccess;
- }
- });
+ if (value * c >= 2) {
+ e++
+ c /= 2
}
- // EXPERIMENTAL FLAG, might get removed without notice
- // working around https://bugzilla.mozilla.org/show_bug.cgi?id=1087551
- // pass in a timeout for this
- if (adapter.webrtcDetectedBrowser === 'firefox') {
- if (constraints && constraints.optional) {
- this.wtFirefox = 0;
- constraints.optional.forEach(function (constraint) {
- if (constraint.andyetFirefoxMakesMeSad) {
- self.wtFirefox = constraint.andyetFirefoxMakesMeSad;
- if (self.wtFirefox > 0) {
- self.firefoxcandidatebuffer = [];
- }
- }
- });
- }
+ if (e + eBias >= eMax) {
+ m = 0
+ e = eMax
+ } else if (e + eBias >= 1) {
+ m = (value * c - 1) * Math.pow(2, mLen)
+ e = e + eBias
+ } else {
+ m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
+ e = 0
}
+ }
+ for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
- this.pc = new peerconn(config, constraints);
+ e = (e << mLen) | m
+ eLen += mLen
+ for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
- this.getLocalStreams = this.pc.getLocalStreams.bind(this.pc);
- this.getRemoteStreams = this.pc.getRemoteStreams.bind(this.pc);
- this.addStream = this.pc.addStream.bind(this.pc);
- this.removeStream = this.pc.removeStream.bind(this.pc);
+ buffer[offset + i - d] |= s * 128
+}
- // proxy events
- this.pc.on('*', function () {
- self.emit.apply(self, arguments);
+},{}],45:[function(require,module,exports){
+if (typeof Object.create === 'function') {
+ // implementation from standard node.js 'util' module
+ module.exports = function inherits(ctor, superCtor) {
+ ctor.super_ = superCtor
+ ctor.prototype = Object.create(superCtor.prototype, {
+ constructor: {
+ value: ctor,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
});
+ };
+} else {
+ // old school shim for old browsers
+ module.exports = function inherits(ctor, superCtor) {
+ ctor.super_ = superCtor
+ var TempCtor = function () {}
+ TempCtor.prototype = superCtor.prototype
+ ctor.prototype = new TempCtor()
+ ctor.prototype.constructor = ctor
+ }
+}
- // proxy some events directly
- this.pc.onremovestream = this.emit.bind(this, 'removeStream');
- this.pc.onaddstream = this.emit.bind(this, 'addStream');
- this.pc.onnegotiationneeded = this.emit.bind(this, 'negotiationNeeded');
- this.pc.oniceconnectionstatechange = this.emit.bind(this, 'iceConnectionStateChange');
- this.pc.onsignalingstatechange = this.emit.bind(this, 'signalingStateChange');
-
- // handle ice candidate and data channel events
- this.pc.onicecandidate = this._onIce.bind(this);
- this.pc.ondatachannel = this._onDataChannel.bind(this);
-
- this.localDescription = {
- contents: []
- };
- this.remoteDescription = {
- contents: []
- };
-
- this.config = {
- debug: false,
- ice: {},
- sid: '',
- isInitiator: true,
- sdpSessionID: Date.now(),
- useJingle: false
- };
+},{}],46:[function(require,module,exports){
+module.exports = intersect;
- // apply our config
- for (item in config) {
- this.config[item] = config[item];
- }
+function intersect (a, b) {
+ var res = [];
+ for (var i = 0; i < a.length; i++) {
+ if (indexOf(b, a[i]) > -1) res.push(a[i]);
+ }
+ return res;
+}
- if (this.config.debug) {
- this.on('*', function () {
- var logger = config.logger || console;
- logger.log('PeerConnection event:', arguments);
- });
- }
- this.hadLocalStunCandidate = false;
- this.hadRemoteStunCandidate = false;
- this.hadLocalRelayCandidate = false;
- this.hadRemoteRelayCandidate = false;
+intersect.big = function(a, b) {
+ var ret = [];
+ var temp = {};
+
+ for (var i = 0; i < b.length; i++) {
+ temp[b[i]] = true;
+ }
+ for (var i = 0; i < a.length; i++) {
+ if (temp[a[i]]) ret.push(a[i]);
+ }
+
+ return ret;
+}
- this.hadLocalIPv6Candidate = false;
- this.hadRemoteIPv6Candidate = false;
+function indexOf(arr, el) {
+ for (var i = 0; i < arr.length; i++) {
+ if (arr[i] === el) return i;
+ }
+ return -1;
+}
- // keeping references for all our data channels
- // so they dont get garbage collected
- // can be removed once the following bugs have been fixed
- // https://crbug.com/405545
- // https://bugzilla.mozilla.org/show_bug.cgi?id=964092
- // to be filed for opera
- this._remoteDataChannels = [];
- this._localDataChannels = [];
+},{}],47:[function(require,module,exports){
+/*!
+ * Determine if an object is a Buffer
+ *
+ * @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
+ * @license MIT
+ */
- this._candidateBuffer = [];
+// The _isBuffer check is for Safari 5-7 support, because it's missing
+// Object.prototype.constructor. Remove this eventually
+module.exports = function (obj) {
+ return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
-util.inherits(PeerConnection, WildEmitter);
+function isBuffer (obj) {
+ return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
+}
-Object.defineProperty(PeerConnection.prototype, 'signalingState', {
- get: function () {
- return this.pc.signalingState;
- }
-});
-Object.defineProperty(PeerConnection.prototype, 'iceConnectionState', {
- get: function () {
- return this.pc.iceConnectionState;
- }
-});
+// For Node v0.10 support. Remove this eventually.
+function isSlowBuffer (obj) {
+ return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
+}
-PeerConnection.prototype._role = function () {
- return this.isInitiator ? 'initiator' : 'responder';
-};
+},{}],48:[function(require,module,exports){
+var toString = {}.toString;
-// Add a stream to the peer connection object
-PeerConnection.prototype.addStream = function (stream) {
- this.localStream = stream;
- this.pc.addStream(stream);
+module.exports = Array.isArray || function (arr) {
+ return toString.call(arr) == '[object Array]';
};
-// helper function to check if a remote candidate is a stun/relay
-// candidate or an ipv6 candidate
-PeerConnection.prototype._checkLocalCandidate = function (candidate) {
- var cand = SJJ.toCandidateJSON(candidate);
- if (cand.type == 'srflx') {
- this.hadLocalStunCandidate = true;
- } else if (cand.type == 'relay') {
- this.hadLocalRelayCandidate = true;
- }
- if (cand.ip.indexOf(':') != -1) {
- this.hadLocalIPv6Candidate = true;
- }
-};
+},{}],49:[function(require,module,exports){
+var util = require('util');
+var extend = require('extend-object');
+var BaseSession = require('jingle-session');
+var RTCPeerConnection = require('rtcpeerconnection');
+var FileTransfer = require('filetransfer/hashed');
-// helper function to check if a remote candidate is a stun/relay
-// candidate or an ipv6 candidate
-PeerConnection.prototype._checkRemoteCandidate = function (candidate) {
- var cand = SJJ.toCandidateJSON(candidate);
- if (cand.type == 'srflx') {
- this.hadRemoteStunCandidate = true;
- } else if (cand.type == 'relay') {
- this.hadRemoteRelayCandidate = true;
- }
- if (cand.ip.indexOf(':') != -1) {
- this.hadRemoteIPv6Candidate = true;
- }
-};
+function FileTransferSession(opts) {
+ BaseSession.call(this, opts);
-// Init and add ice candidate object with correct constructor
-PeerConnection.prototype.processIce = function (update, cb) {
- cb = cb || function () {};
- var self = this;
+ this.pc = new RTCPeerConnection({
+ iceServers: opts.iceServers || [],
+ useJingle: true
+ }, opts.constraints || {});
- // ignore any added ice candidates to avoid errors. why does the
- // spec not do this?
- if (this.pc.signalingState === 'closed') return cb();
+ this.pc.on('ice', this.onIceCandidate.bind(this));
+ this.pc.on('iceConnectionStateChange', this.onIceStateChange.bind(this));
+ this.pc.on('addChannel', this.onChannelAdded.bind(this));
- if (update.contents || (update.jingle && update.jingle.contents)) {
- var contentNames = pluck(this.remoteDescription.contents, 'name');
- var contents = update.contents || update.jingle.contents;
+ this.sender = null;
+ this.receiver = null;
+}
- contents.forEach(function (content) {
- var transport = content.transport || {};
- var candidates = transport.candidates || [];
- var mline = contentNames.indexOf(content.name);
- var mid = content.name;
- candidates.forEach(
- function (candidate) {
- var iceCandidate = SJJ.toCandidateSDP(candidate) + '\r\n';
- self.pc.addIceCandidate(
- new RTCIceCandidate({
- candidate: iceCandidate,
- sdpMLineIndex: mline,
- sdpMid: mid
- }), function () {
- // well, this success callback is pretty meaningless
- },
- function (err) {
- self.emit('error', err);
- }
- );
- self._checkRemoteCandidate(iceCandidate);
- });
- });
- } else {
- // working around https://code.google.com/p/webrtc/issues/detail?id=3669
- if (update.candidate && update.candidate.candidate.indexOf('a=') !== 0) {
- update.candidate.candidate = 'a=' + update.candidate.candidate;
- }
+util.inherits(FileTransferSession, BaseSession);
- if (this.wtFirefox && this.firefoxcandidatebuffer !== null) {
- // we cant add this yet due to https://bugzilla.mozilla.org/show_bug.cgi?id=1087551
- if (this.pc.localDescription && this.pc.localDescription.type === 'offer') {
- this.firefoxcandidatebuffer.push(update.candidate);
- return cb();
- }
- }
- self.pc.addIceCandidate(
- new RTCIceCandidate(update.candidate),
- function () { },
- function (err) {
- self.emit('error', err);
- }
- );
- self._checkRemoteCandidate(update.candidate.candidate);
- }
- cb();
-};
+FileTransferSession.prototype = extend(FileTransferSession.prototype, {
-// Generate and emit an offer with the given constraints
-PeerConnection.prototype.offer = function (constraints, cb) {
- var self = this;
- var hasConstraints = arguments.length === 2;
- var mediaConstraints = hasConstraints && constraints ? constraints : {
- mandatory: {
- OfferToReceiveAudio: true,
- OfferToReceiveVideo: true
- }
- };
- cb = hasConstraints ? cb : constraints;
- cb = cb || function () {};
+ // ----------------------------------------------------------------
+ // Session control methods
+ // ----------------------------------------------------------------
- if (this.pc.signalingState === 'closed') return cb('Already closed');
+ start: function (file) {
+ var self = this;
+ this.state = 'pending';
- // Actually generate the offer
- this.pc.createOffer(
- function (offer) {
- // does not work for jingle, but jingle.js doesn't need
- // this hack...
- var expandedOffer = {
- type: 'offer',
- sdp: offer.sdp
- };
- if (self.assumeSetLocalSuccess) {
- self.emit('offer', expandedOffer);
- cb(null, expandedOffer);
- }
- self._candidateBuffer = [];
- self.pc.setLocalDescription(offer,
- function () {
- var jingle;
- if (self.config.useJingle) {
- jingle = SJJ.toSessionJSON(offer.sdp, {
- role: self._role(),
- direction: 'outgoing'
- });
- jingle.sid = self.config.sid;
- self.localDescription = jingle;
+ this.pc.isInitiator = true;
- // Save ICE credentials
- each(jingle.contents, function (content) {
- var transport = content.transport || {};
- if (transport.ufrag) {
- self.config.ice[content.name] = {
- ufrag: transport.ufrag,
- pwd: transport.pwd
- };
- }
- });
+ this.sender = new FileTransfer.Sender();
+ this.sender.on('progress', function (sent, size) {
+ self._log('info', 'Send progress ' + sent + '/' + size);
+ });
+ this.sender.on('sentFile', function (meta) {
+ self._log('info', 'Sent file', meta.name);
- expandedOffer.jingle = jingle;
- }
- expandedOffer.sdp.split('\r\n').forEach(function (line) {
- if (line.indexOf('a=candidate:') === 0) {
- self._checkLocalCandidate(line);
- }
- });
+ var content = self.pc.localDescription.contents[0];
+ delete content.transport;
- if (!self.assumeSetLocalSuccess) {
- self.emit('offer', expandedOffer);
- cb(null, expandedOffer);
+ content.application = {
+ applicationType: 'filetransfer',
+ offer: {
+ hash: {
+ algo: meta.algo,
+ value: meta.hash
}
- },
- function (err) {
- self.emit('error', err);
- cb(err);
}
- );
- },
- function (err) {
- self.emit('error', err);
- cb(err);
- },
- mediaConstraints
- );
-};
-
+ };
-// Process an incoming offer so that ICE may proceed before deciding
-// to answer the request.
-PeerConnection.prototype.handleOffer = function (offer, cb) {
- cb = cb || function () {};
- var self = this;
- offer.type = 'offer';
- if (offer.jingle) {
- if (this.enableChromeNativeSimulcast) {
- offer.jingle.contents.forEach(function (content) {
- if (content.name === 'video') {
- content.description.googConferenceFlag = true;
- }
- });
- }
- if (this.enableMultiStreamHacks) {
- // add a mixed video stream as first stream
- offer.jingle.contents.forEach(function (content) {
- if (content.name === 'video') {
- var sources = content.description.sources || [];
- if (sources.length === 0 || sources[0].ssrc !== "3735928559") {
- sources.unshift({
- ssrc: "3735928559", // 0xdeadbeef
- parameters: [
- {
- key: "cname",
- value: "deadbeef"
- },
- {
- key: "msid",
- value: "mixyourfecintothis please"
- }
- ]
- });
- content.description.sources = sources;
- }
- }
+ self.send('description-info', {
+ contents: [content]
});
- }
- if (self.restrictBandwidth > 0) {
- if (offer.jingle.contents.length >= 2 && offer.jingle.contents[1].name === 'video') {
- var content = offer.jingle.contents[1];
- var hasBw = content.description && content.description.bandwidth;
- if (!hasBw) {
- offer.jingle.contents[1].description.bandwidth = { type: 'AS', bandwidth: self.restrictBandwidth.toString() };
- offer.sdp = SJJ.toSessionSDP(offer.jingle, {
- sid: self.config.sdpSessionID,
- role: self._role(),
- direction: 'outgoing'
- });
- }
- }
- }
- offer.sdp = SJJ.toSessionSDP(offer.jingle, {
- sid: self.config.sdpSessionID,
- role: self._role(),
- direction: 'incoming'
+ self.emit('sentFile', self, meta);
});
- self.remoteDescription = offer.jingle;
- }
- offer.sdp.split('\r\n').forEach(function (line) {
- if (line.indexOf('a=candidate:') === 0) {
- self._checkRemoteCandidate(line);
- }
- });
- self.pc.setRemoteDescription(new RTCSessionDescription(offer),
- function () {
- cb();
- },
- cb
- );
-};
-// Answer an offer with audio only
-PeerConnection.prototype.answerAudioOnly = function (cb) {
- var mediaConstraints = {
- mandatory: {
- OfferToReceiveAudio: true,
- OfferToReceiveVideo: false
- }
+ var sendChannel = this.pc.createDataChannel('filetransfer');
+ sendChannel.onopen = function () {
+ self.sender.send(file, sendChannel);
};
- this._answer(mediaConstraints, cb);
-};
-// Answer an offer without offering to recieve
-PeerConnection.prototype.answerBroadcastOnly = function (cb) {
- var mediaConstraints = {
+ var constraints = {
mandatory: {
OfferToReceiveAudio: false,
OfferToReceiveVideo: false
}
};
- this._answer(mediaConstraints, cb);
-};
-// Answer an offer with given constraints default is audio/video
-PeerConnection.prototype.answer = function (constraints, cb) {
- var hasConstraints = arguments.length === 2;
- var callback = hasConstraints ? cb : constraints;
- var mediaConstraints = hasConstraints && constraints ? constraints : {
- mandatory: {
- OfferToReceiveAudio: true,
- OfferToReceiveVideo: true
+ this.pc.offer(constraints, function (err, offer) {
+ if (err) {
+ self._log('error', 'Could not create WebRTC offer', err);
+ return self.end('failed-application', true);
}
- };
- this._answer(mediaConstraints, callback);
-};
+ offer.jingle.contents[0].application = {
+ applicationType: 'filetransfer',
+ offer: {
+ date: file.lastModifiedDate,
+ name: file.name,
+ size: file.size,
+ hash: {
+ algo: 'sha-1',
+ value: ''
+ }
+ }
+ };
-// Process an answer
-PeerConnection.prototype.handleAnswer = function (answer, cb) {
- cb = cb || function () {};
- var self = this;
- if (answer.jingle) {
- answer.sdp = SJJ.toSessionSDP(answer.jingle, {
- sid: self.config.sdpSessionID,
- role: self._role(),
- direction: 'incoming'
+ self.send('session-initiate', offer.jingle);
});
- self.remoteDescription = answer.jingle;
- }
- answer.sdp.split('\r\n').forEach(function (line) {
- if (line.indexOf('a=candidate:') === 0) {
- self._checkRemoteCandidate(line);
- }
- });
- self.pc.setRemoteDescription(
- new RTCSessionDescription(answer),
- function () {
- if (self.wtFirefox) {
- window.setTimeout(function () {
- self.firefoxcandidatebuffer.forEach(function (candidate) {
- // add candidates later
- self.pc.addIceCandidate(
- new RTCIceCandidate(candidate),
- function () { },
- function (err) {
- self.emit('error', err);
- }
- );
- self._checkRemoteCandidate(candidate.candidate);
- });
- self.firefoxcandidatebuffer = null;
- }, self.wtFirefox);
- }
- cb(null);
- },
- cb
- );
-};
+ },
-// Close the peer connection
-PeerConnection.prototype.close = function () {
- this.pc.close();
+ accept: function () {
+ var self = this;
- this._localDataChannels = [];
- this._remoteDataChannels = [];
+ this._log('info', 'Accepted incoming session');
- this.emit('close');
-};
+ this.state = 'active';
-// Internal code sharing for various types of answer methods
-PeerConnection.prototype._answer = function (constraints, cb) {
- cb = cb || function () {};
- var self = this;
- if (!this.pc.remoteDescription) {
- // the old API is used, call handleOffer
- throw new Error('remoteDescription not set');
- }
+ this.pc.answer(function (err, answer) {
+ if (err) {
+ self._log('error', 'Could not create WebRTC answer', err);
+ return self.end('failed-application');
+ }
+ self.send('session-accept', answer.jingle);
+ });
+ },
- if (this.pc.signalingState === 'closed') return cb('Already closed');
+ end: function (reason, silent) {
+ this.pc.close();
+ BaseSession.prototype.end.call(this, reason, silent);
+ },
- self.pc.createAnswer(
- function (answer) {
- var sim = [];
- if (self.enableChromeNativeSimulcast) {
- // native simulcast part 1: add another SSRC
- answer.jingle = SJJ.toSessionJSON(answer.sdp, {
- role: self._role(),
- direction: 'outgoing'
- });
- if (answer.jingle.contents.length >= 2 && answer.jingle.contents[1].name === 'video') {
- var groups = answer.jingle.contents[1].description.sourceGroups || [];
- var hasSim = false;
- groups.forEach(function (group) {
- if (group.semantics == 'SIM') hasSim = true;
- });
- if (!hasSim &&
- answer.jingle.contents[1].description.sources.length) {
- var newssrc = JSON.parse(JSON.stringify(answer.jingle.contents[1].description.sources[0]));
- newssrc.ssrc = '' + Math.floor(Math.random() * 0xffffffff); // FIXME: look for conflicts
- answer.jingle.contents[1].description.sources.push(newssrc);
+ maybeReceivedFile: function () {
+ if (!this.receiver.metadata.hash.value) {
+ // unknown hash, file transfer not completed
+ } else if (this.receiver.metadata.hash.value === this.receiver.metadata.actualhash) {
+ this._log('info', 'File hash matches');
+ this.emit('receivedFile', this, this.receivedFile, this.receiver.metadata);
+ this.end('success');
+ } else {
+ this._log('error', 'File hash does not match');
+ this.end('media-error');
+ }
+ },
- sim.push(answer.jingle.contents[1].description.sources[0].ssrc);
- sim.push(newssrc.ssrc);
- groups.push({
- semantics: 'SIM',
- sources: sim
- });
+ // ----------------------------------------------------------------
+ // ICE action handers
+ // ----------------------------------------------------------------
- // also create an RTX one for the SIM one
- var rtxssrc = JSON.parse(JSON.stringify(newssrc));
- rtxssrc.ssrc = '' + Math.floor(Math.random() * 0xffffffff); // FIXME: look for conflicts
- answer.jingle.contents[1].description.sources.push(rtxssrc);
- groups.push({
- semantics: 'FID',
- sources: [newssrc.ssrc, rtxssrc.ssrc]
- });
+ onIceCandidate: function (candidate) {
+ this._log('info', 'Discovered new ICE candidate', candidate.jingle);
+ this.send('transport-info', candidate.jingle);
+ },
- answer.jingle.contents[1].description.sourceGroups = groups;
- answer.sdp = SJJ.toSessionSDP(answer.jingle, {
- sid: self.config.sdpSessionID,
- role: self._role(),
- direction: 'outgoing'
- });
- }
- }
- }
- var expandedAnswer = {
- type: 'answer',
- sdp: answer.sdp
- };
- if (self.assumeSetLocalSuccess) {
- // not safe to do when doing simulcast mangling
- self.emit('answer', expandedAnswer);
- cb(null, expandedAnswer);
- }
- self._candidateBuffer = [];
- self.pc.setLocalDescription(answer,
- function () {
- if (self.config.useJingle) {
- var jingle = SJJ.toSessionJSON(answer.sdp, {
- role: self._role(),
- direction: 'outgoing'
- });
- jingle.sid = self.config.sid;
- self.localDescription = jingle;
- expandedAnswer.jingle = jingle;
- }
- if (self.enableChromeNativeSimulcast) {
- // native simulcast part 2:
- // signal multiple tracks to the receiver
- // for anything in the SIM group
- if (!expandedAnswer.jingle) {
- expandedAnswer.jingle = SJJ.toSessionJSON(answer.sdp, {
- role: self._role(),
- direction: 'outgoing'
- });
- }
- expandedAnswer.jingle.contents[1].description.sources.forEach(function (source, idx) {
- // the floor idx/2 is a hack that relies on a particular order
- // of groups, alternating between sim and rtx
- source.parameters = source.parameters.map(function (parameter) {
- if (parameter.key === 'msid') {
- parameter.value += '-' + Math.floor(idx / 2);
- }
- return parameter;
- });
- });
- expandedAnswer.sdp = SJJ.toSessionSDP(expandedAnswer.jingle, {
- sid: self.sdpSessionID,
- role: self._role(),
- direction: 'outgoing'
- });
- }
- expandedAnswer.sdp.split('\r\n').forEach(function (line) {
- if (line.indexOf('a=candidate:') === 0) {
- self._checkLocalCandidate(line);
- }
- });
- if (!self.assumeSetLocalSuccess) {
- self.emit('answer', expandedAnswer);
- cb(null, expandedAnswer);
- }
- },
- function (err) {
- self.emit('error', err);
- cb(err);
+ onIceStateChange: function () {
+ switch (this.pc.iceConnectionState) {
+ case 'checking':
+ this.connectionState = 'connecting';
+ break;
+ case 'completed':
+ case 'connected':
+ this.connectionState = 'connected';
+ break;
+ case 'disconnected':
+ if (this.pc.signalingState === 'stable') {
+ this.connectionState = 'interrupted';
+ } else {
+ this.connectionState = 'disconnected';
}
- );
- },
- function (err) {
- self.emit('error', err);
- cb(err);
- },
- constraints
- );
-};
+ break;
+ case 'failed':
+ this.connectionState = 'failed';
+ this.end('failed-transport');
+ break;
+ case 'closed':
+ this.connectionState = 'disconnected';
+ break;
+ }
+ },
-// Internal method for emitting ice candidates on our peer object
-PeerConnection.prototype._onIce = function (event) {
- var self = this;
- if (event.candidate) {
- if (this.dontSignalCandidates) return;
- var ice = event.candidate;
+ onChannelAdded: function (channel) {
+ this.receiver.receive(null, channel);
+ },
- var expandedCandidate = {
- candidate: {
- candidate: ice.candidate,
- sdpMid: ice.sdpMid,
- sdpMLineIndex: ice.sdpMLineIndex
- }
- };
- this._checkLocalCandidate(ice.candidate);
+ // ----------------------------------------------------------------
+ // Jingle action handers
+ // ----------------------------------------------------------------
- var cand = SJJ.toCandidateJSON(ice.candidate);
+ onSessionInitiate: function (changes, cb) {
+ var self = this;
- var already;
- var idx;
- if (this.eliminateDuplicateCandidates && cand.type === 'relay') {
- // drop candidates with same foundation, component
- // take local type pref into account so we don't ignore udp
- // ones when we know about a TCP one. unlikely but...
- already = this._candidateBuffer.filter(
- function (c) {
- return c.type === 'relay';
- }).map(function (c) {
- return c.foundation + ':' + c.component;
- }
- );
- idx = already.indexOf(cand.foundation + ':' + cand.component);
- // remember: local type pref of udp is 0, tcp 1, tls 2
- if (idx > -1 && ((cand.priority >> 24) >= (already[idx].priority >> 24))) {
- // drop it, same foundation with higher (worse) type pref
- return;
- }
- }
- if (this.config.bundlePolicy === 'max-bundle') {
- // drop candidates which are duplicate for audio/video/data
- // duplicate means same host/port but different sdpMid
- already = this._candidateBuffer.filter(
- function (c) {
- return cand.type === c.type;
- }).map(function (cand) {
- return cand.address + ':' + cand.port;
- }
- );
- idx = already.indexOf(cand.address + ':' + cand.port);
- if (idx > -1) return;
- }
- // also drop rtcp candidates since we know the peer supports RTCP-MUX
- // this is a workaround until browsers implement this natively
- if (this.config.rtcpMuxPolicy === 'require' && cand.component === '2') {
- return;
- }
- this._candidateBuffer.push(cand);
+ this._log('info', 'Initiating incoming session');
- if (self.config.useJingle) {
- if (!ice.sdpMid) { // firefox doesn't set this
- if (self.pc.remoteDescription && self.pc.remoteDescription.type === 'offer') {
- // preserve name from remote
- ice.sdpMid = self.remoteDescription.contents[ice.sdpMLineIndex].name;
- } else {
- ice.sdpMid = self.localDescription.contents[ice.sdpMLineIndex].name;
- }
- }
- if (!self.config.ice[ice.sdpMid]) {
- var jingle = SJJ.toSessionJSON(self.pc.localDescription.sdp, {
- role: self._role(),
- direction: 'outgoing'
- });
- each(jingle.contents, function (content) {
- var transport = content.transport || {};
- if (transport.ufrag) {
- self.config.ice[content.name] = {
- ufrag: transport.ufrag,
- pwd: transport.pwd
- };
- }
- });
- }
- expandedCandidate.jingle = {
- contents: [{
- name: ice.sdpMid,
- creator: self._role(),
- transport: {
- transType: 'iceUdp',
- ufrag: self.config.ice[ice.sdpMid].ufrag,
- pwd: self.config.ice[ice.sdpMid].pwd,
- candidates: [
- cand
- ]
- }
- }]
- };
- if (self.batchIceCandidates > 0) {
- if (self.batchedIceCandidates.length === 0) {
- window.setTimeout(function () {
- var contents = {};
- self.batchedIceCandidates.forEach(function (content) {
- content = content.contents[0];
- if (!contents[content.name]) contents[content.name] = content;
- contents[content.name].transport.candidates.push(content.transport.candidates[0]);
- });
- var newCand = {
- jingle: {
- contents: []
- }
- };
- Object.keys(contents).forEach(function (name) {
- newCand.jingle.contents.push(contents[name]);
- });
- self.batchedIceCandidates = [];
- self.emit('ice', newCand);
- }, self.batchIceCandidates);
- }
- self.batchedIceCandidates.push(expandedCandidate.jingle);
- return;
- }
+ this.state = 'pending';
- }
- this.emit('ice', expandedCandidate);
- } else {
- this.emit('endOfCandidates');
- }
-};
+ this.pc.isInitiator = false;
-// Internal method for processing a new data channel being added by the
-// other peer.
-PeerConnection.prototype._onDataChannel = function (event) {
- // make sure we keep a reference so this doesn't get garbage collected
- var channel = event.channel;
- this._remoteDataChannels.push(channel);
+ var desc = changes.contents[0].application;
- this.emit('addChannel', channel);
-};
-// Create a data channel spec reference:
-// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannelInit
-PeerConnection.prototype.createDataChannel = function (name, opts) {
- var channel = this.pc.createDataChannel(name, opts);
+ this.receiver = new FileTransfer.Receiver({hash: desc.offer.hash.algo});
+ this.receiver.on('progress', function (received, size) {
+ self._log('info', 'Receive progress ' + received + '/' + size);
+ });
+ this.receiver.on('receivedFile', function (file) {
+ self.receivedFile = file;
+ self.maybeReceivedFile();
+ });
+ this.receiver.metadata = desc.offer;
- // make sure we keep a reference so this doesn't get garbage collected
- this._localDataChannels.push(channel);
+ changes.contents[0].application = {
+ applicationType: 'datachannel'
+ };
- return channel;
-};
+ this.pc.handleOffer({
+ type: 'offer',
+ jingle: changes
+ }, function (err) {
+ if (err) {
+ self._log('error', 'Could not create WebRTC answer');
+ return cb({condition: 'general-error'});
+ }
+ cb();
+ });
+ },
-// a wrapper around getStats which hides the differences (where possible)
-// TODO: remove in favor of adapter.js shim
-PeerConnection.prototype.getStats = function (cb) {
- if (adapter.webrtcDetectedBrowser === 'firefox') {
- this.pc.getStats(
- function (res) {
- var items = [];
- for (var result in res) {
- if (typeof res[result] === 'object') {
- items.push(res[result]);
- }
- }
- cb(null, items);
- },
- cb
- );
- } else {
- this.pc.getStats(function (res) {
- var items = [];
- res.result().forEach(function (result) {
- var item = {};
- result.names().forEach(function (name) {
- item[name] = result.stat(name);
- });
- item.id = result.id;
- item.type = result.type;
- item.timestamp = result.timestamp;
- items.push(item);
- });
- cb(null, items);
+ onSessionAccept: function (changes, cb) {
+ var self = this;
+
+ this.state = 'active';
+
+ changes.contents[0].application = {
+ applicationType: 'datachannel'
+ };
+
+ this.pc.handleAnswer({
+ type: 'answer',
+ jingle: changes
+ }, function (err) {
+ if (err) {
+ self._log('error', 'Could not process WebRTC answer');
+ return cb({condition: 'general-error'});
+ }
+ self.emit('accepted', self);
+ cb();
+ });
+ },
+
+ onSessionTerminate: function (changes, cb) {
+ this._log('info', 'Terminating session');
+ this.pc.close();
+ BaseSession.prototype.end.call(this, changes.reason, true);
+ cb();
+ },
+
+ onDescriptionInfo: function (info, cb) {
+ var hash = info.contents[0].application.offer.hash;
+ this.receiver.metadata.hash = hash;
+ if (this.receiver.metadata.actualhash) {
+ this.maybeReceivedFile();
+ }
+ cb();
+ },
+
+ onTransportInfo: function (changes, cb) {
+ this.pc.processIce(changes, function () {
+ cb();
});
}
-};
+});
-module.exports = PeerConnection;
-},{"lodash.foreach":54,"lodash.pluck":62,"sdp-jingle-json":77,"traceablepeerconnection":82,"util":28,"webrtc-adapter-test":83,"wildemitter":84}],86:[function(require,module,exports){
+module.exports = FileTransferSession;
+
+},{"extend-object":28,"filetransfer/hashed":30,"jingle-session":51,"rtcpeerconnection":167,"util":197}],50:[function(require,module,exports){
var util = require('util');
var extend = require('extend-object');
var BaseSession = require('jingle-session');
@@ -13299,25 +6123,25 @@ var RTCPeerConnection = require('rtcpeerconnection');
function filterContentSources(content, stream) {
- if (content.description.descType !== 'rtp') {
+ if (content.application.applicationType !== 'rtp') {
return;
}
delete content.transport;
- delete content.description.payloads;
- delete content.description.headerExtensions;
- content.description.mux = false;
+ delete content.application.payloads;
+ delete content.application.headerExtensions;
+ content.application.mux = false;
- if (content.description.sources) {
- content.description.sources = content.description.sources.filter(function (source) {
+ if (content.application.sources) {
+ content.application.sources = content.application.sources.filter(function (source) {
return stream.id === source.parameters[1].value.split(' ')[0];
});
}
// remove source groups not related to this stream
- if (content.description.sourceGroups) {
- content.description.sourceGroups = content.description.sourceGroups.filter(function (group) {
+ if (content.application.sourceGroups) {
+ content.application.sourceGroups = content.application.sourceGroups.filter(function (group) {
var found = false;
- for (var i = 0; i < content.description.sources.length; i++) {
- if (content.description.sources[i].ssrc === group.sources[0]) {
+ for (var i = 0; i < content.application.sources.length; i++) {
+ if (content.application.sources[i].ssrc === group.sources[0]) {
found = true;
break;
}
@@ -13329,7 +6153,7 @@ function filterContentSources(content, stream) {
function filterUnusedLabels(content) {
// Remove mslabel and label ssrc-specific attributes
- var sources = content.description.sources || [];
+ var sources = content.application.sources || [];
sources.forEach(function (source) {
source.parameters = source.parameters.filter(function (parameter) {
return !(parameter.key === 'mslabel' || parameter.key === 'label');
@@ -13346,11 +6170,12 @@ function MediaSession(opts) {
useJingle: true
}, opts.constraints || {});
- this.pc.on('ice', this.onIceCandidate.bind(this));
- this.pc.on('endOfCandidates', this.onIceEndOfCandidates.bind(this));
+ this.pc.on('ice', this.onIceCandidate.bind(this, opts));
+ this.pc.on('endOfCandidates', this.onIceEndOfCandidates.bind(this, opts));
this.pc.on('iceConnectionStateChange', this.onIceStateChange.bind(this));
this.pc.on('addStream', this.onAddStream.bind(this));
this.pc.on('removeStream', this.onRemoveStream.bind(this));
+ this.pc.on('addChannel', this.onAddChannel.bind(this));
if (opts.stream) {
this.addStream(opts.stream);
@@ -13409,9 +6234,9 @@ MediaSession.prototype = extend(MediaSession.prototype, {
// https://code.google.com/p/webrtc/issues/detail?id=1553
if (offerOptions && offerOptions.mandatory) {
offer.jingle.contents.forEach(function (content) {
- var mediaType = content.description.media;
+ var mediaType = content.application.media;
- if (!content.description || content.description.descType !== 'rtp') {
+ if (!content.description || content.application.applicationType !== 'rtp') {
return;
}
@@ -13433,16 +6258,29 @@ MediaSession.prototype = extend(MediaSession.prototype, {
});
},
- accept: function (next) {
+ accept: function (opts, next) {
var self = this;
+ // support calling with accept(next) or accept(opts, next)
+ if (arguments.length === 1 && typeof opts === 'function') {
+ next = opts;
+ opts = {};
+ }
next = next || function () {};
+ opts = opts || {};
+
+ var constraints = opts.constraints || {
+ mandatory: {
+ OfferToReceiveAudio: true,
+ OfferToReceiveVideo: true
+ }
+ };
this._log('info', 'Accepted incoming session');
this.state = 'active';
- this.pc.answer(function (err, answer) {
+ this.pc.answer(constraints, function (err, answer) {
if (err) {
self._log('error', 'Could not create WebRTC answer', err);
return self.end('failed-application');
@@ -13534,7 +6372,7 @@ MediaSession.prototype = extend(MediaSession.prototype, {
filterContentSources(content, stream);
});
answer.jingle.contents = answer.jingle.contents.filter(function (content) {
- return content.description.descType === 'rtp' && content.description.sources && content.description.sources.length;
+ return content.application.applicationType === 'rtp' && content.application.sources && content.application.sources.length;
});
delete answer.jingle.groups;
@@ -13563,7 +6401,7 @@ MediaSession.prototype = extend(MediaSession.prototype, {
filterContentSources(content, stream);
});
desc.contents = desc.contents.filter(function (content) {
- return content.description.descType === 'rtp' && content.description.sources && content.description.sources.length;
+ return content.application.applicationType === 'rtp' && content.application.sources && content.application.sources.length;
});
delete desc.groups;
@@ -13600,17 +6438,12 @@ MediaSession.prototype = extend(MediaSession.prototype, {
var desc = this.pc.localDescription;
desc.contents.forEach(function (content) {
delete content.transport;
- delete content.description.payloads;
+ delete content.application.payloads;
});
this.pc.removeStream(oldStream);
this.send('source-remove', desc);
- var audioTracks = oldStream.getAudioTracks();
- if (audioTracks.length) {
- newStream.addTrack(audioTracks[0]);
- }
-
this.pc.addStream(newStream);
this.pc.handleOffer({
type: 'offer',
@@ -13627,7 +6460,7 @@ MediaSession.prototype = extend(MediaSession.prototype, {
}
answer.jingle.contents.forEach(function (content) {
delete content.transport;
- delete content.description.payloads;
+ delete content.application.payloads;
});
self.send('source-add', answer.jingle);
cb();
@@ -13639,13 +6472,25 @@ MediaSession.prototype = extend(MediaSession.prototype, {
// ICE action handers
// ----------------------------------------------------------------
- onIceCandidate: function (candidate) {
+ onIceCandidate: function (opts, candidate) {
this._log('info', 'Discovered new ICE candidate', candidate.jingle);
this.send('transport-info', candidate.jingle);
+ if (opts.signalEndOfCandidates) {
+ this.lastCandidate = candidate;
+ }
},
- onIceEndOfCandidates: function () {
+ onIceEndOfCandidates: function (opts) {
this._log('info', 'ICE end of candidates');
+ if (opts.signalEndOfCandidates) {
+ var endOfCandidates = this.lastCandidate.jingle;
+ endOfCandidates.contents[0].transport = {
+ transportType: endOfCandidates.contents[0].transport.transportType,
+ gatheringComplete: true
+ };
+ this.lastCandidate = null;
+ this.send('transport-info', endOfCandidates);
+ }
},
onIceStateChange: function () {
@@ -13789,7 +6634,7 @@ MediaSession.prototype = extend(MediaSession.prototype, {
var newDesc = this.pc.remoteDescription;
this.pc.remoteDescription.contents.forEach(function (content, idx) {
- var desc = content.description;
+ var desc = content.application;
var ssrcs = desc.sources || [];
var groups = desc.sourceGroups || [];
@@ -13798,15 +6643,15 @@ MediaSession.prototype = extend(MediaSession.prototype, {
return;
}
- var newContentDesc = newContent.description;
+ var newContentDesc = newContent.application;
var newSSRCs = newContentDesc.sources || [];
ssrcs = ssrcs.concat(newSSRCs);
- newDesc.contents[idx].description.sources = JSON.parse(JSON.stringify(ssrcs));
+ newDesc.contents[idx].application.sources = JSON.parse(JSON.stringify(ssrcs));
var newGroups = newContentDesc.sourceGroups || [];
groups = groups.concat(newGroups);
- newDesc.contents[idx].description.sourceGroups = JSON.parse(JSON.stringify(groups));
+ newDesc.contents[idx].application.sourceGroups = JSON.parse(JSON.stringify(groups));
});
});
@@ -13839,7 +6684,7 @@ MediaSession.prototype = extend(MediaSession.prototype, {
var newDesc = this.pc.remoteDescription;
this.pc.remoteDescription.contents.forEach(function (content, idx) {
- var desc = content.description;
+ var desc = content.application;
var ssrcs = desc.sources || [];
var groups = desc.sourceGroups || [];
@@ -13848,7 +6693,7 @@ MediaSession.prototype = extend(MediaSession.prototype, {
return;
}
- var newContentDesc = newContent.description;
+ var newContentDesc = newContent.application;
var newSSRCs = newContentDesc.sources || [];
var newGroups = newContentDesc.sourceGroups || [];
@@ -13865,7 +6710,7 @@ MediaSession.prototype = extend(MediaSession.prototype, {
}
if (found > -1) {
ssrcs.splice(found, 1);
- newDesc.contents[idx].description.sources = JSON.parse(JSON.stringify(ssrcs));
+ newDesc.contents[idx].application.sources = JSON.parse(JSON.stringify(ssrcs));
}
}
@@ -13890,7 +6735,7 @@ MediaSession.prototype = extend(MediaSession.prototype, {
}
if (found > -1) {
groups.splice(found, 1);
- newDesc.contents[idx].description.sourceGroups = JSON.parse(JSON.stringify(groups));
+ newDesc.contents[idx].application.sourceGroups = JSON.parse(JSON.stringify(groups));
}
}
});
@@ -13916,75 +6761,20 @@ MediaSession.prototype = extend(MediaSession.prototype, {
cb();
});
});
+ },
+
+ // ----------------------------------------------------------------
+ // DataChannels
+ // ----------------------------------------------------------------
+ onAddChannel: function (channel) {
+ this.emit('addChannel', channel);
}
});
module.exports = MediaSession;
-},{"extend-object":30,"jingle-session":118,"rtcpeerconnection":117,"util":28}],87:[function(require,module,exports){
-arguments[4][54][0].apply(exports,arguments)
-},{"dup":54,"lodash._arrayeach":88,"lodash._baseeach":89,"lodash._bindcallback":93,"lodash.isarray":94}],88:[function(require,module,exports){
-arguments[4][55][0].apply(exports,arguments)
-},{"dup":55}],89:[function(require,module,exports){
-arguments[4][56][0].apply(exports,arguments)
-},{"dup":56,"lodash.keys":90}],90:[function(require,module,exports){
-arguments[4][57][0].apply(exports,arguments)
-},{"dup":57,"lodash._getnative":91,"lodash.isarguments":92,"lodash.isarray":94}],91:[function(require,module,exports){
-arguments[4][58][0].apply(exports,arguments)
-},{"dup":58}],92:[function(require,module,exports){
-arguments[4][59][0].apply(exports,arguments)
-},{"dup":59}],93:[function(require,module,exports){
-arguments[4][60][0].apply(exports,arguments)
-},{"dup":60}],94:[function(require,module,exports){
-arguments[4][61][0].apply(exports,arguments)
-},{"dup":61}],95:[function(require,module,exports){
-arguments[4][62][0].apply(exports,arguments)
-},{"dup":62,"lodash._baseget":96,"lodash._topath":97,"lodash.isarray":98,"lodash.map":99}],96:[function(require,module,exports){
-arguments[4][63][0].apply(exports,arguments)
-},{"dup":63}],97:[function(require,module,exports){
-arguments[4][64][0].apply(exports,arguments)
-},{"dup":64,"lodash.isarray":98}],98:[function(require,module,exports){
-arguments[4][61][0].apply(exports,arguments)
-},{"dup":61}],99:[function(require,module,exports){
-arguments[4][66][0].apply(exports,arguments)
-},{"dup":66,"lodash._arraymap":100,"lodash._basecallback":101,"lodash._baseeach":106,"lodash.isarray":98}],100:[function(require,module,exports){
-arguments[4][67][0].apply(exports,arguments)
-},{"dup":67}],101:[function(require,module,exports){
-arguments[4][68][0].apply(exports,arguments)
-},{"dup":68,"lodash._baseisequal":102,"lodash._bindcallback":104,"lodash.isarray":98,"lodash.pairs":105}],102:[function(require,module,exports){
-arguments[4][69][0].apply(exports,arguments)
-},{"dup":69,"lodash.isarray":98,"lodash.istypedarray":103,"lodash.keys":107}],103:[function(require,module,exports){
-arguments[4][70][0].apply(exports,arguments)
-},{"dup":70}],104:[function(require,module,exports){
-arguments[4][60][0].apply(exports,arguments)
-},{"dup":60}],105:[function(require,module,exports){
-arguments[4][72][0].apply(exports,arguments)
-},{"dup":72,"lodash.keys":107}],106:[function(require,module,exports){
-arguments[4][56][0].apply(exports,arguments)
-},{"dup":56,"lodash.keys":107}],107:[function(require,module,exports){
-arguments[4][57][0].apply(exports,arguments)
-},{"dup":57,"lodash._getnative":108,"lodash.isarguments":109,"lodash.isarray":98}],108:[function(require,module,exports){
-arguments[4][58][0].apply(exports,arguments)
-},{"dup":58}],109:[function(require,module,exports){
-arguments[4][59][0].apply(exports,arguments)
-},{"dup":59}],110:[function(require,module,exports){
-arguments[4][77][0].apply(exports,arguments)
-},{"./lib/tojson":113,"./lib/tosdp":114,"dup":77}],111:[function(require,module,exports){
-arguments[4][78][0].apply(exports,arguments)
-},{"dup":78}],112:[function(require,module,exports){
-arguments[4][79][0].apply(exports,arguments)
-},{"dup":79}],113:[function(require,module,exports){
-arguments[4][80][0].apply(exports,arguments)
-},{"./parsers":111,"./senders":112,"dup":80}],114:[function(require,module,exports){
-arguments[4][81][0].apply(exports,arguments)
-},{"./senders":112,"dup":81}],115:[function(require,module,exports){
-arguments[4][82][0].apply(exports,arguments)
-},{"dup":82,"util":28,"webrtc-adapter-test":116,"wildemitter":124}],116:[function(require,module,exports){
-arguments[4][83][0].apply(exports,arguments)
-},{"dup":83}],117:[function(require,module,exports){
-arguments[4][85][0].apply(exports,arguments)
-},{"dup":85,"lodash.foreach":87,"lodash.pluck":95,"sdp-jingle-json":110,"traceablepeerconnection":115,"util":28,"webrtc-adapter-test":116,"wildemitter":124}],118:[function(require,module,exports){
+},{"extend-object":28,"jingle-session":51,"rtcpeerconnection":167,"util":197}],51:[function(require,module,exports){
var util = require('util');
var uuid = require('uuid');
var async = require('async');
@@ -14030,7 +6820,7 @@ function JingleSession(opts) {
// We track the intial pending description types in case
// of the need for a tie-breaker.
- this.pendingDescriptionTypes = opts.descriptionTypes || [];
+ this.pendingApplicationTypes = opts.applicationTypes || [];
this.pendingAction = false;
@@ -14330,8 +7120,8 @@ JingleSession.prototype = extend(JingleSession.prototype, {
module.exports = JingleSession;
-},{"async":119,"extend-object":30,"util":28,"uuid":121,"wildemitter":122}],119:[function(require,module,exports){
-(function (process){
+},{"async":52,"extend-object":28,"util":197,"uuid":199,"wildemitter":211}],52:[function(require,module,exports){
+(function (process,global){
/*!
* async
* https://github.com/caolan/async
@@ -14339,18 +7129,32 @@ module.exports = JingleSession;
* Copyright 2010-2014 Caolan McMahon
* Released under the MIT license
*/
-/*jshint onevar: false, indent:4 */
-/*global setImmediate: false, setTimeout: false, console: false */
(function () {
var async = {};
+ function noop() {}
+ function identity(v) {
+ return v;
+ }
+ function toBool(v) {
+ return !!v;
+ }
+ function notId(v) {
+ return !v;
+ }
// global on the server, window in the browser
- var root, previous_async;
+ var previous_async;
+
+ // Establish the root object, `window` (`self`) in the browser, `global`
+ // on the server, or `this` in some virtual machines. We use `self`
+ // instead of `window` for `WebWorker` support.
+ var root = typeof self === 'object' && self.self === self && self ||
+ typeof global === 'object' && global.global === global && global ||
+ this;
- root = this;
if (root != null) {
- previous_async = root.async;
+ previous_async = root.async;
}
async.noConflict = function () {
@@ -14359,12 +7163,19 @@ module.exports = JingleSession;
};
function only_once(fn) {
- var called = false;
return function() {
- if (called) throw new Error("Callback was already called.");
- called = true;
- fn.apply(root, arguments);
- }
+ if (fn === null) throw new Error("Callback was already called.");
+ fn.apply(this, arguments);
+ fn = null;
+ };
+ }
+
+ function _once(fn) {
+ return function() {
+ if (fn === null) return;
+ fn.apply(this, arguments);
+ fn = null;
+ };
}
//// cross-browser compatiblity functions ////
@@ -14375,37 +7186,66 @@ module.exports = JingleSession;
return _toString.call(obj) === '[object Array]';
};
- var _each = function (arr, iterator) {
- for (var i = 0; i < arr.length; i += 1) {
- iterator(arr[i], i, arr);
- }
+ // Ported from underscore.js isObject
+ var _isObject = function(obj) {
+ var type = typeof obj;
+ return type === 'function' || type === 'object' && !!obj;
};
- var _map = function (arr, iterator) {
- if (arr.map) {
- return arr.map(iterator);
+ function _isArrayLike(arr) {
+ return _isArray(arr) || (
+ // has a positive integer length property
+ typeof arr.length === "number" &&
+ arr.length >= 0 &&
+ arr.length % 1 === 0
+ );
+ }
+
+ function _arrayEach(arr, iterator) {
+ var index = -1,
+ length = arr.length;
+
+ while (++index < length) {
+ iterator(arr[index], index, arr);
}
- var results = [];
- _each(arr, function (x, i, a) {
- results.push(iterator(x, i, a));
- });
- return results;
- };
+ }
- var _reduce = function (arr, iterator, memo) {
- if (arr.reduce) {
- return arr.reduce(iterator, memo);
+ function _map(arr, iterator) {
+ var index = -1,
+ length = arr.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = iterator(arr[index], index, arr);
}
- _each(arr, function (x, i, a) {
+ return result;
+ }
+
+ function _range(count) {
+ return _map(Array(count), function (v, i) { return i; });
+ }
+
+ function _reduce(arr, iterator, memo) {
+ _arrayEach(arr, function (x, i, a) {
memo = iterator(memo, x, i, a);
});
return memo;
- };
+ }
+
+ function _forEachOf(object, iterator) {
+ _arrayEach(_keys(object), function (key) {
+ iterator(object[key], key);
+ });
+ }
- var _keys = function (obj) {
- if (Object.keys) {
- return Object.keys(obj);
+ function _indexOf(arr, item) {
+ for (var i = 0; i < arr.length; i++) {
+ if (arr[i] === item) return i;
}
+ return -1;
+ }
+
+ var _keys = Object.keys || function (obj) {
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
@@ -14415,191 +7255,247 @@ module.exports = JingleSession;
return keys;
};
- //// exported async module functions ////
-
- //// nextTick implementation with browser-compatible fallback ////
- if (typeof process === 'undefined' || !(process.nextTick)) {
- if (typeof setImmediate === 'function') {
- async.nextTick = function (fn) {
- // not a direct alias for IE10 compatibility
- setImmediate(fn);
+ function _keyIterator(coll) {
+ var i = -1;
+ var len;
+ var keys;
+ if (_isArrayLike(coll)) {
+ len = coll.length;
+ return function next() {
+ i++;
+ return i < len ? i : null;
};
- async.setImmediate = async.nextTick;
- }
- else {
- async.nextTick = function (fn) {
- setTimeout(fn, 0);
+ } else {
+ keys = _keys(coll);
+ len = keys.length;
+ return function next() {
+ i++;
+ return i < len ? keys[i] : null;
};
- async.setImmediate = async.nextTick;
}
}
- else {
+
+ // Similar to ES6's rest param (http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html)
+ // This accumulates the arguments passed into an array, after a given index.
+ // From underscore.js (https://github.com/jashkenas/underscore/pull/2140).
+ function _restParam(func, startIndex) {
+ startIndex = startIndex == null ? func.length - 1 : +startIndex;
+ return function() {
+ var length = Math.max(arguments.length - startIndex, 0);
+ var rest = Array(length);
+ for (var index = 0; index < length; index++) {
+ rest[index] = arguments[index + startIndex];
+ }
+ switch (startIndex) {
+ case 0: return func.call(this, rest);
+ case 1: return func.call(this, arguments[0], rest);
+ }
+ // Currently unused but handle cases outside of the switch statement:
+ // var args = Array(startIndex + 1);
+ // for (index = 0; index < startIndex; index++) {
+ // args[index] = arguments[index];
+ // }
+ // args[startIndex] = rest;
+ // return func.apply(this, args);
+ };
+ }
+
+ function _withoutIndex(iterator) {
+ return function (value, index, callback) {
+ return iterator(value, callback);
+ };
+ }
+
+ //// exported async module functions ////
+
+ //// nextTick implementation with browser-compatible fallback ////
+
+ // capture the global reference to guard against fakeTimer mocks
+ var _setImmediate = typeof setImmediate === 'function' && setImmediate;
+
+ var _delay = _setImmediate ? function(fn) {
+ // not a direct alias for IE10 compatibility
+ _setImmediate(fn);
+ } : function(fn) {
+ setTimeout(fn, 0);
+ };
+
+ if (typeof process === 'object' && typeof process.nextTick === 'function') {
async.nextTick = process.nextTick;
- if (typeof setImmediate !== 'undefined') {
- async.setImmediate = function (fn) {
- // not a direct alias for IE10 compatibility
- setImmediate(fn);
- };
- }
- else {
- async.setImmediate = async.nextTick;
- }
+ } else {
+ async.nextTick = _delay;
}
+ async.setImmediate = _setImmediate ? _delay : async.nextTick;
+
+ async.forEach =
async.each = function (arr, iterator, callback) {
- callback = callback || function () {};
- if (!arr.length) {
- return callback();
+ return async.eachOf(arr, _withoutIndex(iterator), callback);
+ };
+
+ async.forEachSeries =
+ async.eachSeries = function (arr, iterator, callback) {
+ return async.eachOfSeries(arr, _withoutIndex(iterator), callback);
+ };
+
+
+ async.forEachLimit =
+ async.eachLimit = function (arr, limit, iterator, callback) {
+ return _eachOfLimit(limit)(arr, _withoutIndex(iterator), callback);
+ };
+
+ async.forEachOf =
+ async.eachOf = function (object, iterator, callback) {
+ callback = _once(callback || noop);
+ object = object || [];
+
+ var iter = _keyIterator(object);
+ var key, completed = 0;
+
+ while ((key = iter()) != null) {
+ completed += 1;
+ iterator(object[key], key, only_once(done));
}
- var completed = 0;
- _each(arr, function (x) {
- iterator(x, only_once(done) );
- });
+
+ if (completed === 0) callback(null);
+
function done(err) {
- if (err) {
- callback(err);
- callback = function () {};
- }
- else {
- completed += 1;
- if (completed >= arr.length) {
- callback();
- }
- }
+ completed--;
+ if (err) {
+ callback(err);
+ }
+ // Check key is null in case iterator isn't exhausted
+ // and done resolved synchronously.
+ else if (key === null && completed <= 0) {
+ callback(null);
+ }
}
};
- async.forEach = async.each;
- async.eachSeries = function (arr, iterator, callback) {
- callback = callback || function () {};
- if (!arr.length) {
- return callback();
- }
- var completed = 0;
- var iterate = function () {
- iterator(arr[completed], function (err) {
+ async.forEachOfSeries =
+ async.eachOfSeries = function (obj, iterator, callback) {
+ callback = _once(callback || noop);
+ obj = obj || [];
+ var nextKey = _keyIterator(obj);
+ var key = nextKey();
+ function iterate() {
+ var sync = true;
+ if (key === null) {
+ return callback(null);
+ }
+ iterator(obj[key], key, only_once(function (err) {
if (err) {
callback(err);
- callback = function () {};
}
else {
- completed += 1;
- if (completed >= arr.length) {
- callback();
- }
- else {
- iterate();
+ key = nextKey();
+ if (key === null) {
+ return callback(null);
+ } else {
+ if (sync) {
+ async.setImmediate(iterate);
+ } else {
+ iterate();
+ }
}
}
- });
- };
+ }));
+ sync = false;
+ }
iterate();
};
- async.forEachSeries = async.eachSeries;
- async.eachLimit = function (arr, limit, iterator, callback) {
- var fn = _eachLimit(limit);
- fn.apply(null, [arr, iterator, callback]);
+
+
+ async.forEachOfLimit =
+ async.eachOfLimit = function (obj, limit, iterator, callback) {
+ _eachOfLimit(limit)(obj, iterator, callback);
};
- async.forEachLimit = async.eachLimit;
- var _eachLimit = function (limit) {
+ function _eachOfLimit(limit) {
- return function (arr, iterator, callback) {
- callback = callback || function () {};
- if (!arr.length || limit <= 0) {
- return callback();
+ return function (obj, iterator, callback) {
+ callback = _once(callback || noop);
+ obj = obj || [];
+ var nextKey = _keyIterator(obj);
+ if (limit <= 0) {
+ return callback(null);
}
- var completed = 0;
- var started = 0;
+ var done = false;
var running = 0;
+ var errored = false;
(function replenish () {
- if (completed >= arr.length) {
- return callback();
+ if (done && running <= 0) {
+ return callback(null);
}
- while (running < limit && started < arr.length) {
- started += 1;
+ while (running < limit && !errored) {
+ var key = nextKey();
+ if (key === null) {
+ done = true;
+ if (running <= 0) {
+ callback(null);
+ }
+ return;
+ }
running += 1;
- iterator(arr[started - 1], function (err) {
+ iterator(obj[key], key, only_once(function (err) {
+ running -= 1;
if (err) {
callback(err);
- callback = function () {};
+ errored = true;
}
else {
- completed += 1;
- running -= 1;
- if (completed >= arr.length) {
- callback();
- }
- else {
- replenish();
- }
+ replenish();
}
- });
+ }));
}
})();
};
- };
+ }
- var doParallel = function (fn) {
- return function () {
- var args = Array.prototype.slice.call(arguments);
- return fn.apply(null, [async.each].concat(args));
+ function doParallel(fn) {
+ return function (obj, iterator, callback) {
+ return fn(async.eachOf, obj, iterator, callback);
};
- };
- var doParallelLimit = function(limit, fn) {
- return function () {
- var args = Array.prototype.slice.call(arguments);
- return fn.apply(null, [_eachLimit(limit)].concat(args));
+ }
+ function doParallelLimit(fn) {
+ return function (obj, limit, iterator, callback) {
+ return fn(_eachOfLimit(limit), obj, iterator, callback);
};
- };
- var doSeries = function (fn) {
- return function () {
- var args = Array.prototype.slice.call(arguments);
- return fn.apply(null, [async.eachSeries].concat(args));
+ }
+ function doSeries(fn) {
+ return function (obj, iterator, callback) {
+ return fn(async.eachOfSeries, obj, iterator, callback);
};
- };
-
+ }
- var _asyncMap = function (eachfn, arr, iterator, callback) {
- arr = _map(arr, function (x, i) {
- return {index: i, value: x};
- });
- if (!callback) {
- eachfn(arr, function (x, callback) {
- iterator(x.value, function (err) {
- callback(err);
- });
- });
- } else {
- var results = [];
- eachfn(arr, function (x, callback) {
- iterator(x.value, function (err, v) {
- results[x.index] = v;
- callback(err);
- });
- }, function (err) {
- callback(err, results);
+ function _asyncMap(eachfn, arr, iterator, callback) {
+ callback = _once(callback || noop);
+ arr = arr || [];
+ var results = _isArrayLike(arr) ? [] : {};
+ eachfn(arr, function (value, index, callback) {
+ iterator(value, function (err, v) {
+ results[index] = v;
+ callback(err);
});
- }
- };
+ }, function (err) {
+ callback(err, results);
+ });
+ }
+
async.map = doParallel(_asyncMap);
async.mapSeries = doSeries(_asyncMap);
- async.mapLimit = function (arr, limit, iterator, callback) {
- return _mapLimit(limit)(arr, iterator, callback);
- };
-
- var _mapLimit = function(limit) {
- return doParallelLimit(limit, _asyncMap);
- };
+ async.mapLimit = doParallelLimit(_asyncMap);
// reduce only has a series version, as doing reduce in parallel won't
// work in many situations.
+ async.inject =
+ async.foldl =
async.reduce = function (arr, memo, iterator, callback) {
- async.eachSeries(arr, function (x, callback) {
+ async.eachOfSeries(arr, function (x, i, callback) {
iterator(memo, x, function (err, v) {
memo = v;
callback(err);
@@ -14608,118 +7504,106 @@ module.exports = JingleSession;
callback(err, memo);
});
};
- // inject alias
- async.inject = async.reduce;
- // foldl alias
- async.foldl = async.reduce;
+ async.foldr =
async.reduceRight = function (arr, memo, iterator, callback) {
- var reversed = _map(arr, function (x) {
- return x;
- }).reverse();
+ var reversed = _map(arr, identity).reverse();
async.reduce(reversed, memo, iterator, callback);
};
- // foldr alias
- async.foldr = async.reduceRight;
- var _filter = function (eachfn, arr, iterator, callback) {
- var results = [];
- arr = _map(arr, function (x, i) {
- return {index: i, value: x};
+ async.transform = function (arr, memo, iterator, callback) {
+ if (arguments.length === 3) {
+ callback = iterator;
+ iterator = memo;
+ memo = _isArray(arr) ? [] : {};
+ }
+
+ async.eachOf(arr, function(v, k, cb) {
+ iterator(memo, v, k, cb);
+ }, function(err) {
+ callback(err, memo);
});
- eachfn(arr, function (x, callback) {
- iterator(x.value, function (v) {
+ };
+
+ function _filter(eachfn, arr, iterator, callback) {
+ var results = [];
+ eachfn(arr, function (x, index, callback) {
+ iterator(x, function (v) {
if (v) {
- results.push(x);
+ results.push({index: index, value: x});
}
callback();
});
- }, function (err) {
+ }, function () {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
- };
+ }
+
+ async.select =
async.filter = doParallel(_filter);
+
+ async.selectLimit =
+ async.filterLimit = doParallelLimit(_filter);
+
+ async.selectSeries =
async.filterSeries = doSeries(_filter);
- // select alias
- async.select = async.filter;
- async.selectSeries = async.filterSeries;
- var _reject = function (eachfn, arr, iterator, callback) {
- var results = [];
- arr = _map(arr, function (x, i) {
- return {index: i, value: x};
- });
- eachfn(arr, function (x, callback) {
- iterator(x.value, function (v) {
- if (!v) {
- results.push(x);
- }
- callback();
+ function _reject(eachfn, arr, iterator, callback) {
+ _filter(eachfn, arr, function(value, cb) {
+ iterator(value, function(v) {
+ cb(!v);
});
- }, function (err) {
- callback(_map(results.sort(function (a, b) {
- return a.index - b.index;
- }), function (x) {
- return x.value;
- }));
- });
- };
+ }, callback);
+ }
async.reject = doParallel(_reject);
+ async.rejectLimit = doParallelLimit(_reject);
async.rejectSeries = doSeries(_reject);
- var _detect = function (eachfn, arr, iterator, main_callback) {
- eachfn(arr, function (x, callback) {
- iterator(x, function (result) {
- if (result) {
- main_callback(x);
- main_callback = function () {};
- }
- else {
+ function _createTester(eachfn, check, getResult) {
+ return function(arr, limit, iterator, cb) {
+ function done() {
+ if (cb) cb(getResult(false, void 0));
+ }
+ function iteratee(x, _, callback) {
+ if (!cb) return callback();
+ iterator(x, function (v) {
+ if (cb && check(v)) {
+ cb(getResult(true, x));
+ cb = iterator = false;
+ }
callback();
- }
- });
- }, function (err) {
- main_callback();
- });
- };
- async.detect = doParallel(_detect);
- async.detectSeries = doSeries(_detect);
+ });
+ }
+ if (arguments.length > 3) {
+ eachfn(arr, limit, iteratee, done);
+ } else {
+ cb = iterator;
+ iterator = limit;
+ eachfn(arr, iteratee, done);
+ }
+ };
+ }
- async.some = function (arr, iterator, main_callback) {
- async.each(arr, function (x, callback) {
- iterator(x, function (v) {
- if (v) {
- main_callback(true);
- main_callback = function () {};
- }
- callback();
- });
- }, function (err) {
- main_callback(false);
- });
- };
- // any alias
- async.any = async.some;
+ async.any =
+ async.some = _createTester(async.eachOf, toBool, identity);
- async.every = function (arr, iterator, main_callback) {
- async.each(arr, function (x, callback) {
- iterator(x, function (v) {
- if (!v) {
- main_callback(false);
- main_callback = function () {};
- }
- callback();
- });
- }, function (err) {
- main_callback(true);
- });
- };
- // all alias
- async.all = async.every;
+ async.someLimit = _createTester(async.eachOfLimit, toBool, identity);
+
+ async.all =
+ async.every = _createTester(async.eachOf, notId, notId);
+
+ async.everyLimit = _createTester(async.eachOfLimit, notId, notId);
+
+ function _findGetResult(v, x) {
+ return x;
+ }
+ async.detect = _createTester(async.eachOf, identity, _findGetResult);
+ async.detectSeries = _createTester(async.eachOfSeries, identity, _findGetResult);
+ async.detectLimit = _createTester(async.eachOfLimit, identity, _findGetResult);
async.sortBy = function (arr, iterator, callback) {
async.map(arr, function (x, callback) {
@@ -14736,147 +7620,206 @@ module.exports = JingleSession;
return callback(err);
}
else {
- var fn = function (left, right) {
- var a = left.criteria, b = right.criteria;
- return a < b ? -1 : a > b ? 1 : 0;
- };
- callback(null, _map(results.sort(fn), function (x) {
+ callback(null, _map(results.sort(comparator), function (x) {
return x.value;
}));
}
+
});
+
+ function comparator(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }
};
- async.auto = function (tasks, callback) {
- callback = callback || function () {};
+ async.auto = function (tasks, concurrency, callback) {
+ if (typeof arguments[1] === 'function') {
+ // concurrency is optional, shift the args.
+ callback = concurrency;
+ concurrency = null;
+ }
+ callback = _once(callback || noop);
var keys = _keys(tasks);
- var remainingTasks = keys.length
+ var remainingTasks = keys.length;
if (!remainingTasks) {
- return callback();
+ return callback(null);
+ }
+ if (!concurrency) {
+ concurrency = remainingTasks;
}
var results = {};
+ var runningTasks = 0;
+
+ var hasError = false;
var listeners = [];
- var addListener = function (fn) {
+ function addListener(fn) {
listeners.unshift(fn);
- };
- var removeListener = function (fn) {
- for (var i = 0; i < listeners.length; i += 1) {
- if (listeners[i] === fn) {
- listeners.splice(i, 1);
- return;
- }
- }
- };
- var taskComplete = function () {
- remainingTasks--
- _each(listeners.slice(0), function (fn) {
+ }
+ function removeListener(fn) {
+ var idx = _indexOf(listeners, fn);
+ if (idx >= 0) listeners.splice(idx, 1);
+ }
+ function taskComplete() {
+ remainingTasks--;
+ _arrayEach(listeners.slice(0), function (fn) {
fn();
});
- };
+ }
addListener(function () {
if (!remainingTasks) {
- var theCallback = callback;
- // prevent final callback from calling itself if it errors
- callback = function () {};
-
- theCallback(null, results);
+ callback(null, results);
}
});
- _each(keys, function (k) {
+ _arrayEach(keys, function (k) {
+ if (hasError) return;
var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
- var taskCallback = function (err) {
- var args = Array.prototype.slice.call(arguments, 1);
+ var taskCallback = _restParam(function(err, args) {
+ runningTasks--;
if (args.length <= 1) {
args = args[0];
}
if (err) {
var safeResults = {};
- _each(_keys(results), function(rkey) {
- safeResults[rkey] = results[rkey];
+ _forEachOf(results, function(val, rkey) {
+ safeResults[rkey] = val;
});
safeResults[k] = args;
+ hasError = true;
+
callback(err, safeResults);
- // stop subsequent errors hitting callback multiple times
- callback = function () {};
}
else {
results[k] = args;
async.setImmediate(taskComplete);
}
- };
- var requires = task.slice(0, Math.abs(task.length - 1)) || [];
- var ready = function () {
- return _reduce(requires, function (a, x) {
+ });
+ var requires = task.slice(0, task.length - 1);
+ // prevent dead-locks
+ var len = requires.length;
+ var dep;
+ while (len--) {
+ if (!(dep = tasks[requires[len]])) {
+ throw new Error('Has nonexistent dependency in ' + requires.join(', '));
+ }
+ if (_isArray(dep) && _indexOf(dep, k) >= 0) {
+ throw new Error('Has cyclic dependencies');
+ }
+ }
+ function ready() {
+ return runningTasks < concurrency && _reduce(requires, function (a, x) {
return (a && results.hasOwnProperty(x));
}, true) && !results.hasOwnProperty(k);
- };
+ }
if (ready()) {
+ runningTasks++;
task[task.length - 1](taskCallback, results);
}
else {
- var listener = function () {
- if (ready()) {
- removeListener(listener);
- task[task.length - 1](taskCallback, results);
- }
- };
addListener(listener);
}
+ function listener() {
+ if (ready()) {
+ runningTasks++;
+ removeListener(listener);
+ task[task.length - 1](taskCallback, results);
+ }
+ }
});
};
+
+
async.retry = function(times, task, callback) {
var DEFAULT_TIMES = 5;
+ var DEFAULT_INTERVAL = 0;
+
var attempts = [];
- // Use defaults if times not passed
- if (typeof times === 'function') {
+
+ var opts = {
+ times: DEFAULT_TIMES,
+ interval: DEFAULT_INTERVAL
+ };
+
+ function parseTimes(acc, t){
+ if(typeof t === 'number'){
+ acc.times = parseInt(t, 10) || DEFAULT_TIMES;
+ } else if(typeof t === 'object'){
+ acc.times = parseInt(t.times, 10) || DEFAULT_TIMES;
+ acc.interval = parseInt(t.interval, 10) || DEFAULT_INTERVAL;
+ } else {
+ throw new Error('Unsupported argument type for \'times\': ' + typeof t);
+ }
+ }
+
+ var length = arguments.length;
+ if (length < 1 || length > 3) {
+ throw new Error('Invalid arguments - must be either (task), (task, callback), (times, task) or (times, task, callback)');
+ } else if (length <= 2 && typeof times === 'function') {
callback = task;
task = times;
- times = DEFAULT_TIMES;
}
- // Make sure times is a number
- times = parseInt(times, 10) || DEFAULT_TIMES;
- var wrappedTask = function(wrappedCallback, wrappedResults) {
- var retryAttempt = function(task, finalAttempt) {
+ if (typeof times !== 'function') {
+ parseTimes(opts, times);
+ }
+ opts.callback = callback;
+ opts.task = task;
+
+ function wrappedTask(wrappedCallback, wrappedResults) {
+ function retryAttempt(task, finalAttempt) {
return function(seriesCallback) {
task(function(err, result){
seriesCallback(!err || finalAttempt, {err: err, result: result});
}, wrappedResults);
};
- };
- while (times) {
- attempts.push(retryAttempt(task, !(times-=1)));
}
+
+ function retryInterval(interval){
+ return function(seriesCallback){
+ setTimeout(function(){
+ seriesCallback(null);
+ }, interval);
+ };
+ }
+
+ while (opts.times) {
+
+ var finalAttempt = !(opts.times-=1);
+ attempts.push(retryAttempt(opts.task, finalAttempt));
+ if(!finalAttempt && opts.interval > 0){
+ attempts.push(retryInterval(opts.interval));
+ }
+ }
+
async.series(attempts, function(done, data){
data = data[data.length - 1];
- (wrappedCallback || callback)(data.err, data.result);
+ (wrappedCallback || opts.callback)(data.err, data.result);
});
}
+
// If a callback is passed, run this as a controll flow
- return callback ? wrappedTask() : wrappedTask
+ return opts.callback ? wrappedTask() : wrappedTask;
};
async.waterfall = function (tasks, callback) {
- callback = callback || function () {};
+ callback = _once(callback || noop);
if (!_isArray(tasks)) {
- var err = new Error('First argument to waterfall must be an array of functions');
- return callback(err);
+ var err = new Error('First argument to waterfall must be an array of functions');
+ return callback(err);
}
if (!tasks.length) {
return callback();
}
- var wrapIterator = function (iterator) {
- return function (err) {
+ function wrapIterator(iterator) {
+ return _restParam(function (err, args) {
if (err) {
- callback.apply(null, arguments);
- callback = function () {};
+ callback.apply(null, [err].concat(args));
}
else {
- var args = Array.prototype.slice.call(arguments, 1);
var next = iterator.next();
if (next) {
args.push(wrapIterator(next));
@@ -14884,260 +7827,254 @@ module.exports = JingleSession;
else {
args.push(callback);
}
- async.setImmediate(function () {
- iterator.apply(null, args);
- });
+ ensureAsync(iterator).apply(null, args);
}
- };
- };
+ });
+ }
wrapIterator(async.iterator(tasks))();
};
- var _parallel = function(eachfn, tasks, callback) {
- callback = callback || function () {};
- if (_isArray(tasks)) {
- eachfn.map(tasks, function (fn, callback) {
- if (fn) {
- fn(function (err) {
- var args = Array.prototype.slice.call(arguments, 1);
- if (args.length <= 1) {
- args = args[0];
- }
- callback.call(null, err, args);
- });
+ function _parallel(eachfn, tasks, callback) {
+ callback = callback || noop;
+ var results = _isArrayLike(tasks) ? [] : {};
+
+ eachfn(tasks, function (task, key, callback) {
+ task(_restParam(function (err, args) {
+ if (args.length <= 1) {
+ args = args[0];
}
- }, callback);
- }
- else {
- var results = {};
- eachfn.each(_keys(tasks), function (k, callback) {
- tasks[k](function (err) {
- var args = Array.prototype.slice.call(arguments, 1);
- if (args.length <= 1) {
- args = args[0];
- }
- results[k] = args;
- callback(err);
- });
- }, function (err) {
- callback(err, results);
- });
- }
- };
+ results[key] = args;
+ callback(err);
+ }));
+ }, function (err) {
+ callback(err, results);
+ });
+ }
async.parallel = function (tasks, callback) {
- _parallel({ map: async.map, each: async.each }, tasks, callback);
+ _parallel(async.eachOf, tasks, callback);
};
async.parallelLimit = function(tasks, limit, callback) {
- _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
+ _parallel(_eachOfLimit(limit), tasks, callback);
};
- async.series = function (tasks, callback) {
- callback = callback || function () {};
- if (_isArray(tasks)) {
- async.mapSeries(tasks, function (fn, callback) {
- if (fn) {
- fn(function (err) {
- var args = Array.prototype.slice.call(arguments, 1);
- if (args.length <= 1) {
- args = args[0];
- }
- callback.call(null, err, args);
- });
- }
- }, callback);
- }
- else {
- var results = {};
- async.eachSeries(_keys(tasks), function (k, callback) {
- tasks[k](function (err) {
- var args = Array.prototype.slice.call(arguments, 1);
- if (args.length <= 1) {
- args = args[0];
- }
- results[k] = args;
- callback(err);
- });
- }, function (err) {
- callback(err, results);
- });
- }
+ async.series = function(tasks, callback) {
+ _parallel(async.eachOfSeries, tasks, callback);
};
async.iterator = function (tasks) {
- var makeCallback = function (index) {
- var fn = function () {
+ function makeCallback(index) {
+ function fn() {
if (tasks.length) {
tasks[index].apply(null, arguments);
}
return fn.next();
- };
+ }
fn.next = function () {
return (index < tasks.length - 1) ? makeCallback(index + 1): null;
};
return fn;
- };
+ }
return makeCallback(0);
};
- async.apply = function (fn) {
- var args = Array.prototype.slice.call(arguments, 1);
- return function () {
+ async.apply = _restParam(function (fn, args) {
+ return _restParam(function (callArgs) {
return fn.apply(
- null, args.concat(Array.prototype.slice.call(arguments))
+ null, args.concat(callArgs)
);
- };
- };
+ });
+ });
- var _concat = function (eachfn, arr, fn, callback) {
- var r = [];
- eachfn(arr, function (x, cb) {
+ function _concat(eachfn, arr, fn, callback) {
+ var result = [];
+ eachfn(arr, function (x, index, cb) {
fn(x, function (err, y) {
- r = r.concat(y || []);
+ result = result.concat(y || []);
cb(err);
});
}, function (err) {
- callback(err, r);
+ callback(err, result);
});
- };
+ }
async.concat = doParallel(_concat);
async.concatSeries = doSeries(_concat);
async.whilst = function (test, iterator, callback) {
+ callback = callback || noop;
if (test()) {
- iterator(function (err) {
+ var next = _restParam(function(err, args) {
if (err) {
- return callback(err);
+ callback(err);
+ } else if (test.apply(this, args)) {
+ iterator(next);
+ } else {
+ callback.apply(null, [null].concat(args));
}
- async.whilst(test, iterator, callback);
});
- }
- else {
- callback();
+ iterator(next);
+ } else {
+ callback(null);
}
};
async.doWhilst = function (iterator, test, callback) {
- iterator(function (err) {
- if (err) {
- return callback(err);
- }
- var args = Array.prototype.slice.call(arguments, 1);
- if (test.apply(null, args)) {
- async.doWhilst(iterator, test, callback);
- }
- else {
- callback();
- }
- });
+ var calls = 0;
+ return async.whilst(function() {
+ return ++calls <= 1 || test.apply(this, arguments);
+ }, iterator, callback);
};
async.until = function (test, iterator, callback) {
- if (!test()) {
- iterator(function (err) {
- if (err) {
- return callback(err);
- }
- async.until(test, iterator, callback);
- });
- }
- else {
- callback();
- }
+ return async.whilst(function() {
+ return !test.apply(this, arguments);
+ }, iterator, callback);
};
async.doUntil = function (iterator, test, callback) {
- iterator(function (err) {
+ return async.doWhilst(iterator, function() {
+ return !test.apply(this, arguments);
+ }, callback);
+ };
+
+ async.during = function (test, iterator, callback) {
+ callback = callback || noop;
+
+ var next = _restParam(function(err, args) {
if (err) {
- return callback(err);
+ callback(err);
+ } else {
+ args.push(check);
+ test.apply(this, args);
}
- var args = Array.prototype.slice.call(arguments, 1);
- if (!test.apply(null, args)) {
- async.doUntil(iterator, test, callback);
+ });
+
+ var check = function(err, truth) {
+ if (err) {
+ callback(err);
+ } else if (truth) {
+ iterator(next);
+ } else {
+ callback(null);
}
- else {
- callback();
+ };
+
+ test(check);
+ };
+
+ async.doDuring = function (iterator, test, callback) {
+ var calls = 0;
+ async.during(function(next) {
+ if (calls++ < 1) {
+ next(null, true);
+ } else {
+ test.apply(this, arguments);
}
- });
+ }, iterator, callback);
};
- async.queue = function (worker, concurrency) {
- if (concurrency === undefined) {
+ function _queue(worker, concurrency, payload) {
+ if (concurrency == null) {
concurrency = 1;
}
+ else if(concurrency === 0) {
+ throw new Error('Concurrency must not be zero');
+ }
function _insert(q, data, pos, callback) {
- if (!q.started){
+ if (callback != null && typeof callback !== "function") {
+ throw new Error("task callback must be a function");
+ }
q.started = true;
- }
- if (!_isArray(data)) {
- data = [data];
- }
- if(data.length == 0) {
- // call drain immediately if there are no tasks
- return async.setImmediate(function() {
- if (q.drain) {
- q.drain();
- }
- });
- }
- _each(data, function(task) {
- var item = {
- data: task,
- callback: typeof callback === 'function' ? callback : null
- };
+ if (!_isArray(data)) {
+ data = [data];
+ }
+ if(data.length === 0 && q.idle()) {
+ // call drain immediately if there are no tasks
+ return async.setImmediate(function() {
+ q.drain();
+ });
+ }
+ _arrayEach(data, function(task) {
+ var item = {
+ data: task,
+ callback: callback || noop
+ };
- if (pos) {
- q.tasks.unshift(item);
- } else {
- q.tasks.push(item);
- }
+ if (pos) {
+ q.tasks.unshift(item);
+ } else {
+ q.tasks.push(item);
+ }
- if (q.saturated && q.tasks.length === q.concurrency) {
- q.saturated();
- }
- async.setImmediate(q.process);
- });
+ if (q.tasks.length === q.concurrency) {
+ q.saturated();
+ }
+ });
+ async.setImmediate(q.process);
+ }
+ function _next(q, tasks) {
+ return function(){
+ workers -= 1;
+
+ var removed = false;
+ var args = arguments;
+ _arrayEach(tasks, function (task) {
+ _arrayEach(workersList, function (worker, index) {
+ if (worker === task && !removed) {
+ workersList.splice(index, 1);
+ removed = true;
+ }
+ });
+
+ task.callback.apply(task, args);
+ });
+ if (q.tasks.length + workers === 0) {
+ q.drain();
+ }
+ q.process();
+ };
}
var workers = 0;
+ var workersList = [];
var q = {
tasks: [],
concurrency: concurrency,
- saturated: null,
- empty: null,
- drain: null,
+ payload: payload,
+ saturated: noop,
+ empty: noop,
+ drain: noop,
started: false,
paused: false,
push: function (data, callback) {
- _insert(q, data, false, callback);
+ _insert(q, data, false, callback);
},
kill: function () {
- q.drain = null;
- q.tasks = [];
+ q.drain = noop;
+ q.tasks = [];
},
unshift: function (data, callback) {
- _insert(q, data, true, callback);
+ _insert(q, data, true, callback);
},
process: function () {
- if (!q.paused && workers < q.concurrency && q.tasks.length) {
- var task = q.tasks.shift();
- if (q.empty && q.tasks.length === 0) {
+ while(!q.paused && workers < q.concurrency && q.tasks.length){
+
+ var tasks = q.payload ?
+ q.tasks.splice(0, q.payload) :
+ q.tasks.splice(0, q.tasks.length);
+
+ var data = _map(tasks, function (task) {
+ return task.data;
+ });
+
+ if (q.tasks.length === 0) {
q.empty();
}
workers += 1;
- var next = function () {
- workers -= 1;
- if (task.callback) {
- task.callback.apply(task, arguments);
- }
- if (q.drain && q.tasks.length + workers === 0) {
- q.drain();
- }
- q.process();
- };
- var cb = only_once(next);
- worker(task.data, cb);
+ workersList.push(tasks[0]);
+ var cb = only_once(_next(q, tasks));
+ worker(data, cb);
}
},
length: function () {
@@ -15146,75 +8083,85 @@ module.exports = JingleSession;
running: function () {
return workers;
},
+ workersList: function () {
+ return workersList;
+ },
idle: function() {
return q.tasks.length + workers === 0;
},
pause: function () {
- if (q.paused === true) { return; }
q.paused = true;
},
resume: function () {
if (q.paused === false) { return; }
q.paused = false;
+ var resumeCount = Math.min(q.concurrency, q.tasks.length);
// Need to call q.process once per concurrent
// worker to preserve full concurrency after pause
- for (var w = 1; w <= q.concurrency; w++) {
+ for (var w = 1; w <= resumeCount; w++) {
async.setImmediate(q.process);
}
}
};
return q;
+ }
+
+ async.queue = function (worker, concurrency) {
+ var q = _queue(function (items, cb) {
+ worker(items[0], cb);
+ }, concurrency, 1);
+
+ return q;
};
async.priorityQueue = function (worker, concurrency) {
function _compareTasks(a, b){
- return a.priority - b.priority;
- };
+ return a.priority - b.priority;
+ }
function _binarySearch(sequence, item, compare) {
- var beg = -1,
- end = sequence.length - 1;
- while (beg < end) {
- var mid = beg + ((end - beg + 1) >>> 1);
- if (compare(item, sequence[mid]) >= 0) {
- beg = mid;
- } else {
- end = mid - 1;
+ var beg = -1,
+ end = sequence.length - 1;
+ while (beg < end) {
+ var mid = beg + ((end - beg + 1) >>> 1);
+ if (compare(item, sequence[mid]) >= 0) {
+ beg = mid;
+ } else {
+ end = mid - 1;
+ }
}
- }
- return beg;
+ return beg;
}
function _insert(q, data, priority, callback) {
- if (!q.started){
+ if (callback != null && typeof callback !== "function") {
+ throw new Error("task callback must be a function");
+ }
q.started = true;
- }
- if (!_isArray(data)) {
- data = [data];
- }
- if(data.length == 0) {
- // call drain immediately if there are no tasks
- return async.setImmediate(function() {
- if (q.drain) {
- q.drain();
- }
- });
- }
- _each(data, function(task) {
- var item = {
- data: task,
- priority: priority,
- callback: typeof callback === 'function' ? callback : null
- };
+ if (!_isArray(data)) {
+ data = [data];
+ }
+ if(data.length === 0) {
+ // call drain immediately if there are no tasks
+ return async.setImmediate(function() {
+ q.drain();
+ });
+ }
+ _arrayEach(data, function(task) {
+ var item = {
+ data: task,
+ priority: priority,
+ callback: typeof callback === 'function' ? callback : noop
+ };
- q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);
+ q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);
- if (q.saturated && q.tasks.length === q.concurrency) {
- q.saturated();
- }
- async.setImmediate(q.process);
- });
+ if (q.tasks.length === q.concurrency) {
+ q.saturated();
+ }
+ async.setImmediate(q.process);
+ });
}
// Start with a normal queue
@@ -15222,7 +8169,7 @@ module.exports = JingleSession;
// Override push to accept second parameter representing priority
q.push = function (data, priority, callback) {
- _insert(q, data, priority, callback);
+ _insert(q, data, priority, callback);
};
// Remove unshift function
@@ -15232,93 +8179,27 @@ module.exports = JingleSession;
};
async.cargo = function (worker, payload) {
- var working = false,
- tasks = [];
-
- var cargo = {
- tasks: tasks,
- payload: payload,
- saturated: null,
- empty: null,
- drain: null,
- drained: true,
- push: function (data, callback) {
- if (!_isArray(data)) {
- data = [data];
- }
- _each(data, function(task) {
- tasks.push({
- data: task,
- callback: typeof callback === 'function' ? callback : null
- });
- cargo.drained = false;
- if (cargo.saturated && tasks.length === payload) {
- cargo.saturated();
- }
- });
- async.setImmediate(cargo.process);
- },
- process: function process() {
- if (working) return;
- if (tasks.length === 0) {
- if(cargo.drain && !cargo.drained) cargo.drain();
- cargo.drained = true;
- return;
- }
-
- var ts = typeof payload === 'number'
- ? tasks.splice(0, payload)
- : tasks.splice(0, tasks.length);
-
- var ds = _map(ts, function (task) {
- return task.data;
- });
-
- if(cargo.empty) cargo.empty();
- working = true;
- worker(ds, function () {
- working = false;
-
- var args = arguments;
- _each(ts, function (data) {
- if (data.callback) {
- data.callback.apply(null, args);
- }
- });
-
- process();
- });
- },
- length: function () {
- return tasks.length;
- },
- running: function () {
- return working;
- }
- };
- return cargo;
+ return _queue(worker, 1, payload);
};
- var _console_fn = function (name) {
- return function (fn) {
- var args = Array.prototype.slice.call(arguments, 1);
- fn.apply(null, args.concat([function (err) {
- var args = Array.prototype.slice.call(arguments, 1);
- if (typeof console !== 'undefined') {
+ function _console_fn(name) {
+ return _restParam(function (fn, args) {
+ fn.apply(null, args.concat([_restParam(function (err, args) {
+ if (typeof console === 'object') {
if (err) {
if (console.error) {
console.error(err);
}
}
else if (console[name]) {
- _each(args, function (x) {
+ _arrayEach(args, function (x) {
console[name](x);
});
}
}
- }]));
- };
- };
+ })]));
+ });
+ }
async.log = _console_fn('log');
async.dir = _console_fn('dir');
/*async.info = _console_fn('info');
@@ -15328,123 +8209,174 @@ module.exports = JingleSession;
async.memoize = function (fn, hasher) {
var memo = {};
var queues = {};
- hasher = hasher || function (x) {
- return x;
- };
- var memoized = function () {
- var args = Array.prototype.slice.call(arguments);
+ var has = Object.prototype.hasOwnProperty;
+ hasher = hasher || identity;
+ var memoized = _restParam(function memoized(args) {
var callback = args.pop();
var key = hasher.apply(null, args);
- if (key in memo) {
- async.nextTick(function () {
+ if (has.call(memo, key)) {
+ async.setImmediate(function () {
callback.apply(null, memo[key]);
});
}
- else if (key in queues) {
+ else if (has.call(queues, key)) {
queues[key].push(callback);
}
else {
queues[key] = [callback];
- fn.apply(null, args.concat([function () {
- memo[key] = arguments;
+ fn.apply(null, args.concat([_restParam(function (args) {
+ memo[key] = args;
var q = queues[key];
delete queues[key];
for (var i = 0, l = q.length; i < l; i++) {
- q[i].apply(null, arguments);
+ q[i].apply(null, args);
}
- }]));
+ })]));
}
- };
+ });
memoized.memo = memo;
memoized.unmemoized = fn;
return memoized;
};
async.unmemoize = function (fn) {
- return function () {
- return (fn.unmemoized || fn).apply(null, arguments);
- };
+ return function () {
+ return (fn.unmemoized || fn).apply(null, arguments);
+ };
};
- async.times = function (count, iterator, callback) {
- var counter = [];
- for (var i = 0; i < count; i++) {
- counter.push(i);
- }
- return async.map(counter, iterator, callback);
- };
+ function _times(mapper) {
+ return function (count, iterator, callback) {
+ mapper(_range(count), iterator, callback);
+ };
+ }
- async.timesSeries = function (count, iterator, callback) {
- var counter = [];
- for (var i = 0; i < count; i++) {
- counter.push(i);
- }
- return async.mapSeries(counter, iterator, callback);
+ async.times = _times(async.map);
+ async.timesSeries = _times(async.mapSeries);
+ async.timesLimit = function (count, limit, iterator, callback) {
+ return async.mapLimit(_range(count), limit, iterator, callback);
};
async.seq = function (/* functions... */) {
var fns = arguments;
- return function () {
+ return _restParam(function (args) {
var that = this;
- var args = Array.prototype.slice.call(arguments);
- var callback = args.pop();
+
+ var callback = args[args.length - 1];
+ if (typeof callback == 'function') {
+ args.pop();
+ } else {
+ callback = noop;
+ }
+
async.reduce(fns, args, function (newargs, fn, cb) {
- fn.apply(that, newargs.concat([function () {
- var err = arguments[0];
- var nextargs = Array.prototype.slice.call(arguments, 1);
+ fn.apply(that, newargs.concat([_restParam(function (err, nextargs) {
cb(err, nextargs);
- }]))
+ })]));
},
function (err, results) {
callback.apply(that, [err].concat(results));
});
- };
+ });
};
async.compose = function (/* functions... */) {
- return async.seq.apply(null, Array.prototype.reverse.call(arguments));
+ return async.seq.apply(null, Array.prototype.reverse.call(arguments));
};
- var _applyEach = function (eachfn, fns /*args...*/) {
- var go = function () {
- var that = this;
- var args = Array.prototype.slice.call(arguments);
- var callback = args.pop();
- return eachfn(fns, function (fn, cb) {
- fn.apply(that, args.concat([cb]));
- },
- callback);
- };
- if (arguments.length > 2) {
- var args = Array.prototype.slice.call(arguments, 2);
- return go.apply(this, args);
- }
- else {
- return go;
- }
- };
- async.applyEach = doParallel(_applyEach);
- async.applyEachSeries = doSeries(_applyEach);
+
+ function _applyEach(eachfn) {
+ return _restParam(function(fns, args) {
+ var go = _restParam(function(args) {
+ var that = this;
+ var callback = args.pop();
+ return eachfn(fns, function (fn, _, cb) {
+ fn.apply(that, args.concat([cb]));
+ },
+ callback);
+ });
+ if (args.length) {
+ return go.apply(this, args);
+ }
+ else {
+ return go;
+ }
+ });
+ }
+
+ async.applyEach = _applyEach(async.eachOf);
+ async.applyEachSeries = _applyEach(async.eachOfSeries);
+
async.forever = function (fn, callback) {
+ var done = only_once(callback || noop);
+ var task = ensureAsync(fn);
function next(err) {
if (err) {
- if (callback) {
- return callback(err);
- }
- throw err;
+ return done(err);
}
- fn(next);
+ task(next);
}
next();
};
+ function ensureAsync(fn) {
+ return _restParam(function (args) {
+ var callback = args.pop();
+ args.push(function () {
+ var innerArgs = arguments;
+ if (sync) {
+ async.setImmediate(function () {
+ callback.apply(null, innerArgs);
+ });
+ } else {
+ callback.apply(null, innerArgs);
+ }
+ });
+ var sync = true;
+ fn.apply(this, args);
+ sync = false;
+ });
+ }
+
+ async.ensureAsync = ensureAsync;
+
+ async.constant = _restParam(function(values) {
+ var args = [null].concat(values);
+ return function (callback) {
+ return callback.apply(this, args);
+ };
+ });
+
+ async.wrapSync =
+ async.asyncify = function asyncify(func) {
+ return _restParam(function (args) {
+ var callback = args.pop();
+ var result;
+ try {
+ result = func.apply(this, args);
+ } catch (e) {
+ return callback(e);
+ }
+ // if result is Promise object
+ if (_isObject(result) && typeof result.then === "function") {
+ result.then(function(value) {
+ callback(null, value);
+ })["catch"](function(err) {
+ callback(err.message ? err : new Error(err));
+ });
+ } else {
+ callback(null, result);
+ }
+ });
+ };
+
// Node.js
- if (typeof module !== 'undefined' && module.exports) {
+ if (typeof module === 'object' && module.exports) {
module.exports = async;
}
// AMD / RequireJS
- else if (typeof define !== 'undefined' && define.amd) {
+ else if (typeof define === 'function' && define.amd) {
define([], function () {
return async;
});
@@ -15456,284 +8388,422 @@ module.exports = JingleSession;
}());
-}).call(this,require('_process'))
-},{"_process":10}],120:[function(require,module,exports){
-(function (global){
+}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"_process":153}],53:[function(require,module,exports){
+var util = require('util');
+var intersect = require('intersect');
+var WildEmitter = require('wildemitter');
+var webrtc = require('webrtcsupport');
-var rng;
+var BaseSession = require('jingle-session');
+var MediaSession = require('jingle-media-session');
+var FileSession = require('jingle-filetransfer-session');
-if (global.crypto && crypto.getRandomValues) {
- // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
- // Moderately fast, high quality
- var _rnds8 = new Uint8Array(16);
- rng = function whatwgRNG() {
- crypto.getRandomValues(_rnds8);
- return _rnds8;
- };
-}
-if (!rng) {
- // Math.random()-based (RNG)
- //
- // If all else fails, use Math.random(). It's fast, but is of unspecified
- // quality.
- var _rnds = new Array(16);
- rng = function() {
- for (var i = 0, r; i < 16; i++) {
- if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
- _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
- }
+function SessionManager(conf) {
+ WildEmitter.call(this);
- return _rnds;
- };
-}
+ conf = conf || {};
-module.exports = rng;
+ this.jid = conf.jid;
+ this.selfID = conf.selfID || (this.jid && this.jid.full) || this.jid || '';
+ this.sessions = {};
+ this.peers = {};
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],121:[function(require,module,exports){
-// uuid.js
-//
-// Copyright (c) 2010-2012 Robert Kieffer
-// MIT License - http://opensource.org/licenses/mit-license.php
+ this.prepareSession = conf.prepareSession || function (opts) {
+ if (opts.applicationTypes.indexOf('rtp') >= 0) {
+ return new MediaSession(opts);
+ }
+ if (opts.applicationTypes.indexOf('filetransfer') >= 0) {
+ return new FileSession(opts);
+ }
+ };
-// Unique ID creation requires a high quality random # generator. We feature
-// detect to determine the best RNG source, normalizing to a function that
-// returns 128-bits of randomness, since that's what's usually required
-var _rng = require('./rng');
+ this.performTieBreak = conf.performTieBreak || function (sess, req) {
+ var applicationTypes= req.jingle.contents.map(function (content) {
+ if (content.application) {
+ return content.application.applicationType;
+ }
+ });
-// Maps for number <-> hex string conversion
-var _byteToHex = [];
-var _hexToByte = {};
-for (var i = 0; i < 256; i++) {
- _byteToHex[i] = (i + 0x100).toString(16).substr(1);
- _hexToByte[_byteToHex[i]] = i;
-}
+ var matching = intersect(sess.pendingApplicationTypes, applicationTypes);
-// **`parse()` - Parse a UUID into it's component bytes**
-function parse(s, buf, offset) {
- var i = (buf && offset) || 0, ii = 0;
+ return matching.length > 0;
+ };
- buf = buf || [];
- s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
- if (ii < 16) { // Don't overflow!
- buf[i + ii++] = _hexToByte[oct];
+ this.screenSharingSupport = webrtc.screenSharing;
+
+ this.capabilities = [
+ 'urn:xmpp:jingle:1'
+ ];
+ if (webrtc.support) {
+ this.capabilities = [
+ 'urn:xmpp:jingle:1',
+ 'urn:xmpp:jingle:apps:rtp:1',
+ 'urn:xmpp:jingle:apps:rtp:audio',
+ 'urn:xmpp:jingle:apps:rtp:video',
+ 'urn:xmpp:jingle:apps:rtp:rtcb-fb:0',
+ 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0',
+ 'urn:xmpp:jingle:apps:rtp:ssma:0',
+ 'urn:xmpp:jingle:apps:dtls:0',
+ 'urn:xmpp:jingle:apps:grouping:0',
+ 'urn:xmpp:jingle:apps:file-transfer:3',
+ 'urn:xmpp:jingle:transports:ice-udp:1',
+ 'urn:xmpp:jingle:transports.dtls-sctp:1',
+ 'urn:ietf:rfc:3264',
+ 'urn:ietf:rfc:5576',
+ 'urn:ietf:rfc:5888'
+ ];
}
- });
- // Zero out remaining bytes if string was short
- while (ii < 16) {
- buf[i + ii++] = 0;
- }
+ this.config = {
+ debug: false,
+ peerConnectionConfig: {
+ iceServers: conf.iceServers || [{'url': 'stun:stun.l.google.com:19302'}]
+ },
+ peerConnectionConstraints: {
+ optional: [
+ {DtlsSrtpKeyAgreement: true},
+ {RtpDataChannels: false}
+ ]
+ },
+ media: {
+ audio: true,
+ video: true
+ }
+ };
- return buf;
-}
+ for (var item in conf) {
+ this.config[item] = conf[item];
+ }
-// **`unparse()` - Convert UUID byte array (ala parse()) into a string**
-function unparse(buf, offset) {
- var i = offset || 0, bth = _byteToHex;
- return bth[buf[i++]] + bth[buf[i++]] +
- bth[buf[i++]] + bth[buf[i++]] + '-' +
- bth[buf[i++]] + bth[buf[i++]] + '-' +
- bth[buf[i++]] + bth[buf[i++]] + '-' +
- bth[buf[i++]] + bth[buf[i++]] + '-' +
- bth[buf[i++]] + bth[buf[i++]] +
- bth[buf[i++]] + bth[buf[i++]] +
- bth[buf[i++]] + bth[buf[i++]];
+ this.iceServers = this.config.peerConnectionConfig.iceServers;
}
-// **`v1()` - Generate time-based UUID**
-//
-// Inspired by https://github.com/LiosK/UUID.js
-// and http://docs.python.org/library/uuid.html
-// random #'s we need to init node and clockseq
-var _seedBytes = _rng();
+util.inherits(SessionManager, WildEmitter);
-// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
-var _nodeId = [
- _seedBytes[0] | 0x01,
- _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
-];
-// Per 4.2.2, randomize (14 bit) clockseq
-var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
+SessionManager.prototype.addICEServer = function (server) {
+ // server == {
+ // url: '',
+ // [username: '',]
+ // [credential: '']
+ // }
+ if (typeof server === 'string') {
+ server = {url: server};
+ }
+ this.iceServers.push(server);
+};
-// Previous uuid creation time
-var _lastMSecs = 0, _lastNSecs = 0;
+SessionManager.prototype.addSession = function (session) {
+ var self = this;
-// See https://github.com/broofa/node-uuid for API details
-function v1(options, buf, offset) {
- var i = buf && offset || 0;
- var b = buf || [];
+ var sid = session.sid;
+ var peer = session.peerID;
- options = options || {};
+ this.sessions[sid] = session;
+ if (!this.peers[peer]) {
+ this.peers[peer] = [];
+ }
- var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq;
+ this.peers[peer].push(session);
- // UUID timestamps are 100 nano-second units since the Gregorian epoch,
- // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
- // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
- // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
- var msecs = options.msecs !== undefined ? options.msecs : new Date().getTime();
+ // Automatically clean up tracked sessions
+ session.on('terminated', function () {
+ var peers = self.peers[peer] || [];
+ if (peers.length) {
+ peers.splice(peers.indexOf(session), 1);
+ }
+ delete self.sessions[sid];
+ });
- // Per 4.2.1.2, use count of uuid's generated during the current clock
- // cycle to simulate higher resolution clock
- var nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1;
+ // Proxy session events
+ session.on('*', function (name, data, extraData, extraData2) {
+ // Listen for when we actually try to start a session to
+ // trigger the outgoing event.
+ if (name === 'send') {
+ var action = data.jingle && data.jingle.action;
+ if (session.isInitiator && action === 'session-initiate') {
+ self.emit('outgoing', session);
+ }
+ }
- // Time since last uuid creation (in msecs)
- var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
+ if (self.config.debug && (name === 'log:debug' || name === 'log:error')) {
+ console.log('Jingle:', data, extraData, extraData2);
+ }
- // Per 4.2.1.2, Bump clockseq on clock regression
- if (dt < 0 && options.clockseq === undefined) {
- clockseq = clockseq + 1 & 0x3fff;
- }
+ // Don't proxy change:* events, since those don't apply to
+ // the session manager itself.
+ if (name.indexOf('change') === 0) {
+ return;
+ }
- // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
- // time interval
- if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {
- nsecs = 0;
- }
+ self.emit(name, data, extraData, extraData2);
+ });
- // Per 4.2.1.2 Throw error if too many uuids are requested
- if (nsecs >= 10000) {
- throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
- }
+ this.emit('createdSession', session);
- _lastMSecs = msecs;
- _lastNSecs = nsecs;
- _clockseq = clockseq;
+ return session;
+};
- // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
- msecs += 12219292800000;
+SessionManager.prototype.createMediaSession = function (peer, sid, stream) {
+ var session = new MediaSession({
+ sid: sid,
+ peer: peer,
+ initiator: true,
+ stream: stream,
+ parent: this,
+ iceServers: this.iceServers,
+ constraints: this.config.peerConnectionConstraints
+ });
- // `time_low`
- var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
- b[i++] = tl >>> 24 & 0xff;
- b[i++] = tl >>> 16 & 0xff;
- b[i++] = tl >>> 8 & 0xff;
- b[i++] = tl & 0xff;
+ this.addSession(session);
- // `time_mid`
- var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
- b[i++] = tmh >>> 8 & 0xff;
- b[i++] = tmh & 0xff;
+ return session;
+};
- // `time_high_and_version`
- b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
- b[i++] = tmh >>> 16 & 0xff;
+SessionManager.prototype.createFileTransferSession = function (peer, sid) {
+ var session = new FileSession({
+ sid: sid,
+ peer: peer,
+ initiator: true,
+ parent: this
+ });
- // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
- b[i++] = clockseq >>> 8 | 0x80;
+ this.addSession(session);
- // `clock_seq_low`
- b[i++] = clockseq & 0xff;
+ return session;
+};
- // `node`
- var node = options.node || _nodeId;
- for (var n = 0; n < 6; n++) {
- b[i + n] = node[n];
- }
+SessionManager.prototype.endPeerSessions = function (peer, reason, silent) {
+ peer = peer.full || peer;
- return buf ? buf : unparse(b);
-}
+ var sessions = this.peers[peer] || [];
+ delete this.peers[peer];
-// **`v4()` - Generate random UUID**
+ sessions.forEach(function (session) {
+ session.end(reason || 'gone', silent);
+ });
+};
-// See https://github.com/broofa/node-uuid for API details
-function v4(options, buf, offset) {
- // Deprecated - 'format' argument, as supported in v1.2
- var i = buf && offset || 0;
+SessionManager.prototype.endAllSessions = function (reason, silent) {
+ var self = this;
+ Object.keys(this.peers).forEach(function (peer) {
+ self.endPeerSessions(peer, reason, silent);
+ });
+};
- if (typeof(options) == 'string') {
- buf = options == 'binary' ? new Array(16) : null;
- options = null;
- }
- options = options || {};
+SessionManager.prototype._createIncomingSession = function (meta, req) {
+ var session;
- var rnds = options.random || (options.rng || _rng)();
+ if (this.prepareSession) {
+ session = this.prepareSession(meta, req);
+ }
- // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
- rnds[6] = (rnds[6] & 0x0f) | 0x40;
- rnds[8] = (rnds[8] & 0x3f) | 0x80;
+ // Fallback to a generic session type, which can
+ // only be used to end the session.
- // Copy bytes to buffer, if provided
- if (buf) {
- for (var ii = 0; ii < 16; ii++) {
- buf[i + ii] = rnds[ii];
+ if (!session) {
+ session = new BaseSession(meta);
}
- }
- return buf || unparse(rnds);
-}
+ this.addSession(session);
-// Export public API
-var uuid = v4;
-uuid.v1 = v1;
-uuid.v4 = v4;
-uuid.parse = parse;
-uuid.unparse = unparse;
+ return session;
+};
-module.exports = uuid;
+SessionManager.prototype._sendError = function (to, id, data) {
+ if (!data.type) {
+ data.type = 'cancel';
+ }
+ this.emit('send', {
+ to: to,
+ id: id,
+ type: 'error',
+ error: data
+ });
+};
-},{"./rng":120}],122:[function(require,module,exports){
-arguments[4][53][0].apply(exports,arguments)
-},{"dup":53}],123:[function(require,module,exports){
-// created by @HenrikJoreteg
-var prefix;
-var version;
+SessionManager.prototype._log = function (level, message) {
+ this.emit('log:' + level, message);
+};
-if (window.mozRTCPeerConnection || navigator.mozGetUserMedia) {
- prefix = 'moz';
- version = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
-} else if (window.webkitRTCPeerConnection || navigator.webkitGetUserMedia) {
- prefix = 'webkit';
- version = navigator.userAgent.match(/Chrom(e|ium)/) && parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10);
-}
+SessionManager.prototype.process = function (req) {
+ var self = this;
-var PC = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
-var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
-var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;
-var MediaStream = window.webkitMediaStream || window.MediaStream;
-var screenSharing = window.location.protocol === 'https:' &&
- ((prefix === 'webkit' && version >= 26) ||
- (prefix === 'moz' && version >= 33))
-var AudioContext = window.AudioContext || window.webkitAudioContext;
-var videoEl = document.createElement('video');
-var supportVp8 = videoEl && videoEl.canPlayType && videoEl.canPlayType('video/webm; codecs="vp8", vorbis') === "probably";
-var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia || navigator.mozGetUserMedia;
+ // Extract the request metadata that we need to verify
+ var sid = !!req.jingle ? req.jingle.sid : null;
+ var session = this.sessions[sid] || null;
+ var rid = req.id;
+ var sender = req.from.full || req.from;
-// export support flags and constructors.prototype && PC
-module.exports = {
- prefix: prefix,
- browserVersion: version,
- support: !!PC && supportVp8 && !!getUserMedia,
- // new support style
- supportRTCPeerConnection: !!PC,
- supportVp8: supportVp8,
- supportGetUserMedia: !!getUserMedia,
- supportDataChannel: !!(PC && PC.prototype && PC.prototype.createDataChannel),
- supportWebAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource),
- supportMediaStream: !!(MediaStream && MediaStream.prototype.removeTrack),
- supportScreenSharing: !!screenSharing,
- // old deprecated style. Dont use this anymore
- dataChannel: !!(PC && PC.prototype && PC.prototype.createDataChannel),
- webAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource),
- mediaStream: !!(MediaStream && MediaStream.prototype.removeTrack),
- screenSharing: !!screenSharing,
- // constructors
- AudioContext: AudioContext,
- PeerConnection: PC,
- SessionDescription: SessionDescription,
- IceCandidate: IceCandidate,
- MediaStream: MediaStream,
- getUserMedia: getUserMedia
+
+ if (req.type === 'error') {
+ var isTieBreak = req.error && req.error.jingleCondition === 'tie-break';
+ if (session && session.pending && isTieBreak) {
+ return session.end('alternative-session', true);
+ } else {
+ if (session) {
+ session.pendingAction = false;
+ }
+ return this.emit('error', req);
+ }
+ }
+
+ if (req.type === 'result') {
+ if (session) {
+ session.pendingAction = false;
+ }
+ return;
+ }
+
+ var action = req.jingle.action;
+ var contents = req.jingle.contents || [];
+
+ var applicationTypes = contents.map(function (content) {
+ if (content.application) {
+ return content.application.applicationType;
+ }
+ });
+ var transportTypes = contents.map(function (content) {
+ if (content.transport) {
+ return content.transport.transportType;
+ }
+ });
+
+
+ // Now verify that we are allowed to actually process the
+ // requested action
+
+ if (action !== 'session-initiate') {
+ // Can't modify a session that we don't have.
+ if (!session) {
+ this._log('error', 'Unknown session', sid);
+ return this._sendError(sender, rid, {
+ condition: 'item-not-found',
+ jingleCondition: 'unknown-session'
+ });
+ }
+
+ // Check if someone is trying to hijack a session.
+ if (session.peerID !== sender || session.ended) {
+ this._log('error', 'Session has ended, or action has wrong sender');
+ return this._sendError(sender, rid, {
+ condition: 'item-not-found',
+ jingleCondition: 'unknown-session'
+ });
+ }
+
+ // Can't accept a session twice
+ if (action === 'session-accept' && !session.pending) {
+ this._log('error', 'Tried to accept session twice', sid);
+ return this._sendError(sender, rid, {
+ condition: 'unexpected-request',
+ jingleCondition: 'out-of-order'
+ });
+ }
+
+ // Can't process two requests at once, need to tie break
+ if (action !== 'session-terminate' && action === session.pendingAction) {
+ this._log('error', 'Tie break during pending request');
+ if (session.isInitiator) {
+ return this._sendError(sender, rid, {
+ condition: 'conflict',
+ jingleCondition: 'tie-break'
+ });
+ }
+ }
+ } else if (session) {
+ // Don't accept a new session if we already have one.
+ if (session.peerID !== sender) {
+ this._log('error', 'Duplicate sid from new sender');
+ return this._sendError(sender, rid, {
+ condition: 'service-unavailable'
+ });
+ }
+
+ // Check if we need to have a tie breaker because both parties
+ // happened to pick the same random sid.
+ if (session.pending) {
+ if (this.selfID > session.peerID && this.performTieBreak(session, req)) {
+ this._log('error', 'Tie break new session because of duplicate sids');
+ return this._sendError(sender, rid, {
+ condition: 'conflict',
+ jingleCondition: 'tie-break'
+ });
+ }
+ } else {
+ // The other side is just doing it wrong.
+ this._log('error', 'Someone is doing this wrong');
+ return this._sendError(sender, rid, {
+ condition: 'unexpected-request',
+ jingleCondition: 'out-of-order'
+ });
+ }
+ } else if (this.peers[sender] && this.peers[sender].length) {
+ // Check if we need to have a tie breaker because we already have
+ // a different session with this peer that is using the requested
+ // content application types.
+ for (var i = 0, len = this.peers[sender].length; i < len; i++) {
+ var sess = this.peers[sender][i];
+ if (sess && sess.pending && sess.sid > sid && this.performTieBreak(sess, req)) {
+ this._log('info', 'Tie break session-initiate');
+ return this._sendError(sender, rid, {
+ condition: 'conflict',
+ jingleCondition: 'tie-break'
+ });
+ }
+ }
+ }
+
+ // We've now weeded out invalid requests, so we can process the action now.
+
+ if (action === 'session-initiate') {
+ if (!contents.length) {
+ return self._sendError(sender, rid, {
+ condition: 'bad-request'
+ });
+ }
+
+ session = this._createIncomingSession({
+ sid: sid,
+ peer: req.from,
+ peerID: sender,
+ initiator: false,
+ parent: this,
+ applicationTypes: applicationTypes,
+ transportTypes: transportTypes,
+ iceServers: this.iceServers,
+ constraints: this.config.peerConnectionConstraints
+ }, req);
+ }
+
+ session.process(action, req.jingle, function (err) {
+ if (err) {
+ self._log('error', 'Could not process request', req, err);
+ self._sendError(sender, rid, err);
+ } else {
+ self.emit('send', {
+ to: sender,
+ id: rid,
+ type: 'result',
+ });
+
+ // Wait for the initial action to be processed before emitting
+ // the session for the user to accept/reject.
+ if (action === 'session-initiate') {
+ self.emit('incoming', session);
+ }
+ }
+ });
};
-},{}],124:[function(require,module,exports){
-arguments[4][53][0].apply(exports,arguments)
-},{"dup":53}],125:[function(require,module,exports){
+
+module.exports = SessionManager;
+
+},{"intersect":46,"jingle-filetransfer-session":49,"jingle-media-session":50,"jingle-session":51,"util":197,"webrtcsupport":210,"wildemitter":211}],54:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -15758,7 +8828,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"./shortcuts":126,"./types":127}],126:[function(require,module,exports){
+},{"./shortcuts":55,"./types":56}],55:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -15902,7 +8972,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":128}],127:[function(require,module,exports){
+},{"xmpp-constants":212}],56:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -15994,712 +9064,47 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-jid":134}],128:[function(require,module,exports){
-module.exports = {
- Namespace: require('./lib/namespaces'),
- MUC: require('./lib/muc'),
- PubSub: require('./lib/pubsub'),
- Jingle: require('./lib/jingle'),
- Presence: require('./lib/presence')
-};
-
-},{"./lib/jingle":129,"./lib/muc":130,"./lib/namespaces":131,"./lib/presence":132,"./lib/pubsub":133}],129:[function(require,module,exports){
-module.exports = {
- Action: {
- CONTENT_ACCEPT: 'content-accept',
- CONTENT_ADD: 'content-add',
- CONTENT_MODIFY: 'content-modify',
- CONTENT_REJECT: 'content-reject',
- CONTENT_REMOVE: 'content-remove',
- DESCRIPTION_INFO: 'description-info',
- SECURITY_INFO: 'security-info',
- SESSION_ACCEPT: 'session-accept',
- SESSION_INFO: 'session-info',
- SESSION_INITIATE: 'session-initiate',
- SESSION_TERMINATE: 'session-terminate',
- TRANSPORT_ACCEPT: 'transport-accept',
- TRANSPORT_INFO: 'transport-info',
- TRANSPORT_REJECT: 'transport-reject',
- TRANSPORT_REPLACE: 'transport-replace'
- },
- Reason: {
- ALTERNATIVE_SESSION: 'alernative-session',
- BUSY: 'busy',
- CANCEL: 'cancel',
- CONNECTIVITY_ERROR: 'connectivity-error',
- DECLINE: 'decline',
- EXPIRED: 'expired',
- FAILED_APPLICATION: 'failed-application',
- FAILED_TRANSPORT: 'failed-transport',
- GENERAL_ERROR: 'general-error',
- GONE: 'gone',
- INCOMPATIBLE_PARAMETERS: 'incompatible-parameters',
- MEDIA_ERROR: 'media-error',
- SECURITY_ERROR: 'security-error',
- SUCCESS: 'success',
- TIMEOUT: 'timeout',
- UNSUPPORTED_APPLICATIONS: 'unsupported-applications',
- UNSUPPORTED_TRANSPORTS: 'unsupported-transports'
- },
- Condition: {
- OUT_OF_ORDER: 'out-of-order',
- TIE_BREAK: 'tie-break',
- UNKNOWN_SESSION: 'unknown-session',
- UNSUPPORTED_INFO: 'unsupported-info'
- }
-};
-
-},{}],130:[function(require,module,exports){
-module.exports = {
- Status: {
- REALJID_PUBLIC: '100',
- AFFILIATION_CHANGED: '101',
- UNAVAILABLE_SHOWN: '102',
- UNAVAILABLE_NOT_SHOWN: '103',
- CONFIGURATION_CHANGED: '104',
- SELF_PRESENCE: '110',
- LOGGING_ENABLED: '170',
- LOGGING_DISABLED: '171',
- NON_ANONYMOUS: '172',
- SEMI_ANONYMOUS: '173',
- FULLY_ANONYMOUS: '174',
- ROOM_CREATED: '201',
- NICK_ASSIGNED: '210',
- BANNED: '301',
- NEW_NICK: '303',
- KICKED: '307',
- REMOVED_AFFILIATION: '321',
- REMOVED_MEMBERSHIP: '322',
- REMOVED_SHUTDOWN: '332'
- },
- Affiliation: {
- ADMIN: 'admin',
- MEMBER: 'member',
- NONE: 'none',
- OUTCAST: 'outcast',
- OWNER: 'owner'
- },
- Role: {
- MODERATOR: 'moderator',
- NONE: 'none',
- PARTICIPANT: 'participant',
- VISITOR: 'visitor'
- }
-};
-
-},{}],131:[function(require,module,exports){
-module.exports = {
-// ================================================================
-// RFCS
-// ================================================================
-
-// RFC 6120
- BIND: 'urn:ietf:params:xml:ns:xmpp-bind',
- CLIENT: 'jabber:client',
- SASL: 'urn:ietf:params:xml:ns:xmpp-sasl',
- SERVER: 'jabber:server',
- SESSION: 'urn:ietf:params:xml:ns:xmpp-session',
- STANZA_ERROR: 'urn:ietf:params:xml:ns:xmpp-stanzas',
- STREAM: 'http://etherx.jabber.org/streams',
- STREAM_ERROR: 'urn:ietf:params:xml:ns:xmpp-streams',
-
-// RFC 6121
- ROSTER: 'jabber:iq:roster',
- ROSTER_VERSIONING: 'urn:xmpp:features:rosterver',
- SUBSCRIPTION_PREAPPROVAL: 'urn:xmpp:features:pre-approval',
-
-// RFC 7395
- FRAMING: 'urn:ietf:params:xml:ns:xmpp-framing',
-
-// ================================================================
-// XEPS
-// ================================================================
-
-// XEP-0004
- DATAFORM: 'jabber:x:data',
-
-// XEP-0009
- RPC: 'jabber:iq:rpc',
-
-// XEP-0012
- LAST_ACTIVITY: 'jabber:iq:last',
-
-// XEP-0016
- PRIVACY: 'jabber:iq:privacy',
-
-// XEP-0030
- DISCO_INFO: 'http://jabber.org/protocol/disco#info',
- DISCO_ITEMS: 'http://jabber.org/protocol/disco#items',
-
-// XEP-0033
- ADDRESS: 'http://jabber.org/protocol/address',
-
-// XEP-0045
- MUC: 'http://jabber.org/protocol/muc',
- MUC_ADMIN: 'http://jabber.org/protocol/muc#admin',
- MUC_OWNER: 'http://jabber.org/protocol/muc#owner',
- MUC_USER: 'http://jabber.org/protocol/muc#user',
-
-// XEP-0047
- IBB: 'http://jabber.org/protocol/ibb',
-
-// XEP-0048
- BOOKMARKS: 'storage:bookmarks',
-
-// XEP-0049
- PRIVATE: 'jabber:iq:private',
-
-// XEP-0050
- ADHOC_COMMANDS: 'http://jabber.org/protocol/commands',
-
-// XEP-0054
- VCARD_TEMP: 'vcard-temp',
-
-// XEP-0055
- SEARCH: 'jabber:iq:search',
-
-// XEP-0059
- RSM: 'http://jabber.org/protocol/rsm',
-
-// XEP-0060
- PUBSUB: 'http://jabber.org/protocol/pubsub',
- PUBSUB_ERRORS: 'http://jabber.org/protocol/pubsub#errors',
- PUBSUB_EVENT: 'http://jabber.org/protocol/pubsub#event',
- PUBSUB_OWNER: 'http://jabber.org/protocol/pubsub#owner',
-
-// XEP-0065
- SOCKS5: 'http://jabber.org/protocol/bytestreams',
-
-// XEP-0066
- OOB: 'jabber:x:oob',
-
-// XEP-0070
- HTTP_AUTH: 'http://jabber.org/protocol/http-auth',
-
-// XEP-0071
- XHTML_IM: 'http://jabber.org/protocol/xhtml-im',
-
-// XEP-0077
- REGISTER: 'jabber:iq:register',
-
-// XEP-0079
- AMP: 'http://jabber.org/protocol/amp',
-
-// XEP-0080
- GEOLOC: 'http://jabber.org/protocol/geoloc',
-
-// XEP-0083
- ROSTER_DELIMITER: 'roster:delimiter',
-
-// XEP-0084
- AVATAR_DATA: 'urn:xmpp:avatar:data',
- AVATAR_METADATA: 'urn:xmpp:avatar:metadata',
-
-// XEP-0085
- CHAT_STATES: 'http://jabber.org/protocol/chatstates',
-
-// XEP-0092
- VERSION: 'jabber:iq:version',
-
-// XEP-0107
- MOOD: 'http://jabber.org/protocol/mood',
-
-// XEP-0108
- ACTIVITY: 'http://jabber.org/protocol/activity',
-
-// XEP-0114
- COMPONENT: 'jabber:component:accept',
-
-// XEP-0115
- CAPS: 'http://jabber.org/protocol/caps',
-
-// XEP-0118
- TUNE: 'http://jabber.org/protocol/tune',
-
-// XEP-0122
- DATAFORM_VALIDATION: 'http://jabber.org/protocol/xdata-validate',
-
-// XEP-0124
- BOSH: 'http://jabber.org/protocol/httpbind',
-
-// XEP-0131
- SHIM: 'http://jabber.org/protocol/shim',
-
-// XEP-0138
- COMPRESSION: 'http://jabber.org/features/compress',
-
-// XEP-0141
- DATAFORM_LAYOUT: 'http://jabber.org/protocol/xdata-layout',
-
-// XEP-0144
- ROSTER_EXCHANGE: 'http://jabber.org/protocol/rosterx',
-
-// XEP-0145
- ROSTER_NOTES: 'storage:rosternotes',
-
-// XEP-0152
- REACH_0: 'urn:xmpp:reach:0',
-
-// XEP-0153
- VCARD_TEMP_UPDATE: 'vcard-temp:x:update',
-
-// XEP-0158
- CAPTCHA: 'urn:xmpp:captcha',
-
-// XEP-0166
- JINGLE_1: 'urn:xmpp:jingle:1',
- JINGLE_ERRORS_1: 'urn:xmpp:jingle:errors:1',
-
-// XEP-0167
- JINGLE_RTP_1: 'urn:xmpp:jingle:apps:rtp:1',
- JINGLE_RTP_ERRORS_1: 'urn:xmpp:jingle:apps:rtp:errors:1',
- JINGLE_RTP_INFO_1: 'urn:xmpp:jingle:apps:rtp:info:1',
-
-// XEP-0171
- LANG_TRANS: 'urn:xmpp:langtrans',
- LANG_TRANS_ITEMS: 'urn:xmpp:langtrans:items',
-
-// XEP-0172
- NICK: 'http://jabber.org/protocol/nick',
-
-// XEP-0176
- JINGLE_ICE_UDP_1: 'urn:xmpp:jingle:transports:ice-udp:1',
-
-// XEP-0177
- JINGLE_RAW_UDP_1: 'urn:xmpp:jingle:transports:raw-udp:1',
-
-// XEP-0184
- RECEIPTS: 'urn:xmpp:receipts',
-
-// XEP-0186
- INVISIBLE_0: 'urn:xmpp:invisible:0',
-
-// XEP-0191
- BLOCKING: 'urn:xmpp:blocking',
-
-// XEP-0198
- SMACKS_3: 'urn:xmpp:sm:3',
-
-// XEP-0199
- PING: 'urn:xmpp:ping',
-
-// XEP-0202
- TIME: 'urn:xmpp:time',
-
-// XEP-0203
- DELAY: 'urn:xmpp:delay',
-
-// XEP-0206
- BOSH_XMPP: 'urn:xmpp:xbosh',
-
-// XEP-0215
- DISCO_EXTERNAL_1: 'urn:xmpp:extdisco:1',
-
-// XEP-0221
- DATAFORM_MEDIA: 'urn:xmpp:media-element',
-
-// XEP-0224
- ATTENTION_0: 'urn:xmpp:attention:0',
-
-// XEP-0231
- BOB: 'urn:xmpp:bob',
-
-// XEP-0234
- FILE_TRANSFER_3: 'urn:xmpp:jingle:apps:file-transfer:3',
- FILE_TRANSFER_4: 'urn:xmpp:jingle:apps:file-transfer:4',
-
-// XEP-0249
- MUC_DIRECT_INVITE: 'jabber:x:conference',
-
-// XEP-0258
- SEC_LABEL_0: 'urn:xmpp:sec-label:0',
- SEC_LABEL_CATALOG_2: 'urn:xmpp:sec-label:catalog:2',
- SEC_LABEL_ESS_0: 'urn:xmpp:sec-label:ess:0',
-
-// XEP-0260
- JINGLE_SOCKS5_1: 'urn:xmpp:jingle:transports:s5b:1',
-
-// XEP-0261
- JINGLE_IBB_1: 'urn:xmpp:jingle:transports:ibb:1',
-
-// XEP-0262
- JINGLE_RTP_ZRTP_1: 'urn:xmpp:jingle:apps:rtp:zrtp:1',
-
-// XEP-0264
- THUMBS_0: 'urn:xmpp:thumbs:0',
- THUMBS_1: 'urn:xmpp:thumbs:1',
-
-// XEP-0276
- DECLOAKING_0: 'urn:xmpp:decloaking:0',
-
-// XEP-0280
- CARBONS_2: 'urn:xmpp:carbons:2',
-
-// XEP-0293
- JINGLE_RTP_RTCP_FB_0: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0',
-
-// XEP-0294
- JINGLE_RTP_HDREXT_0: 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0',
-
-// XEP-0297
- FORWARD_0: 'urn:xmpp:forward:0',
-
-// XEP-0300
- HASHES_1: 'urn:xmpp:hashes:1',
-
-// XEP-0301
- RTT_0: 'urn:xmpp:rtt:0',
-
-// XEP-0307
- MUC_UNIQUE: 'http://jabber.org/protocol/muc#unique',
-
-// XEP-308
- CORRECTION_0: 'urn:xmpp:message-correct:0',
-
-// XEP-0310
- PSA: 'urn:xmpp:psa',
-
-// XEP-0313
- MAM_TMP: 'urn:xmpp:mam:tmp',
- MAM_0: 'urn:xmpp:mam:0',
-
-// XEP-0317
- HATS_0: 'urn:xmpp:hats:0',
-
-// XEP-0319
- IDLE_1: 'urn:xmpp:idle:1',
-
-// XEP-0320
- JINGLE_DTLS_0: 'urn:xmpp:jingle:apps:dtls:0',
-
-// XEP-0328
- JID_PREP_0: 'urn:xmpp:jidprep:0',
-
-// XEP-0334
- HINTS: 'urn:xmpp:hints',
-
-// XEP-0335
- JSON_0: 'urn:xmpp:json:0',
-
-// XEP-0337
- EVENTLOG: 'urn:xmpp:eventlog',
-
-// XEP-0338
- JINGLE_GROUPING_0: 'urn:xmpp:jingle:apps:grouping:0',
-
-// XEP-0339
- JINGLE_RTP_SSMA_0: 'urn:xmpp:jingle:apps:rtp:ssma:0',
-
-// XEP-0340
- COLIBRI: 'http://jitsi.org/protocol/colibri',
-
-// XEP-0343
- DTLS_SCTP_1: 'urn:xmpp:jingle:transports:dtls-sctp:1',
-
-// XEP-0352
- CSI: 'urn:xmpp:csi',
-
-// XEP-0353
- JINGLE_MSG_INITIATE_0: 'urn:xmpp:jingle:jingle-message:0',
-
-// XEP-0357
- PUSH_0: 'urn:xmpp:push:0',
-
-// XEP-0358
- JINGLE_PUB_1: 'urn:xmpp:jinglepub:1'
-};
-
-},{}],132:[function(require,module,exports){
-module.exports = {
- Type: {
- SUBSCRIBE: 'subscribe',
- SUBSCRIBED: 'subscribed',
- UNSUBSCRIBE: 'unsubscribe',
- UNSUBSCRIBED: 'unsubscribed',
- PROBE: 'probe',
- UNAVAILABLE: 'unavailable'
- },
- Show: {
- CHAT: 'chat',
- AWAY: 'away',
- DO_NOT_DISTURB: 'dnd',
- EXTENDED_AWAY: 'xa'
- }
-};
-
-},{}],133:[function(require,module,exports){
-module.exports = {
- Affiliation: {
- MEMBER: 'member',
- NONE: 'none',
- OUTCAST: 'outcast',
- OWNER: 'owner',
- PUBLISHER: 'publisher',
- PUBLISH_ONLY: 'publish-only'
- },
- Subscription: {
- NONE: 'none',
- PENDING: 'pending',
- UNCONFIGURED: 'unconfigured',
- SUBSCRIBED: 'subscribed'
- },
- AccessModel: {
- OPEN: 'open',
- PRESENCE: 'presence',
- ROSTER: 'roster',
- AUTHORIZE: 'authorize',
- WHITELIST: 'whitelist'
- },
- Condition: {
- CONFLICT: 'conflict'
- }
-};
-
-},{}],134:[function(require,module,exports){
+},{"xmpp-jid":218}],57:[function(require,module,exports){
'use strict';
-var StringPrep = require('./lib/stringprep');
-
-// All of our StringPrep fallbacks work correctly
-// in the ASCII range, so we can reliably mark
-// ASCII-only JIDs as prepped.
-var ASCII = /^[\x00-\x7F]*$/;
-
-
-
-function bareJID(local, domain) {
- if (local) {
- return local + '@' + domain;
- }
- return domain;
-}
-
-function fullJID(local, domain, resource) {
- if (resource) {
- return bareJID(local, domain) + '/' + resource;
- }
- return bareJID(local, domain);
-}
-
-
-exports.prep = function (data) {
- var local = data.local;
- var domain = data.domain;
- var resource = data.resource;
- var unescapedLocal = local;
-
- if (local) {
- local = StringPrep.nodeprep(local);
- unescapedLocal = exports.unescape(local);
- }
-
- if (resource) {
- resource = StringPrep.resourceprep(resource);
- }
-
- if (domain[domain.length - 1] === '.') {
- domain = domain.slice(0, domain.length - 1);
- }
-
- domain = StringPrep.nameprep(domain.split('.').map(StringPrep.toUnicode).join('.'));
-
- return {
- prepped: data.prepped || StringPrep.available,
- local: local,
- domain: domain,
- resource: resource,
- bare: bareJID(local, domain),
- full: fullJID(local, domain, resource),
- unescapedLocal: unescapedLocal,
- unescapedBare: bareJID(unescapedLocal, domain),
- unescapedFull: fullJID(unescapedLocal, domain, resource)
- };
-};
-
-exports.parse = function (jid, trusted) {
- var local = '';
- var domain = '';
- var resource = '';
-
- trusted = trusted || ASCII.test(jid);
-
- var resourceStart = jid.indexOf('/');
- if (resourceStart > 0) {
- resource = jid.slice(resourceStart + 1);
- jid = jid.slice(0, resourceStart);
- }
-
- var localEnd = jid.indexOf('@');
- if (localEnd > 0) {
- local = jid.slice(0, localEnd);
- jid = jid.slice(localEnd + 1);
- }
-
- domain = jid;
-
- var preppedJID = exports.prep({
- local: local,
- domain: domain,
- resource: resource,
- });
-
- preppedJID.prepped = preppedJID.prepped || trusted;
-
- return preppedJID;
-};
-
-exports.equal = function (jid1, jid2, requirePrep) {
- jid1 = new exports.JID(jid1);
- jid2 = new exports.JID(jid2);
- if (arguments.length === 2) {
- requirePrep = true;
- }
- return jid1.local === jid2.local &&
- jid1.domain === jid2.domain &&
- jid1.resource === jid2.resource &&
- (requirePrep ? jid1.prepped && jid2.prepped : true);
-};
-
-exports.equalBare = function (jid1, jid2, requirePrep) {
- jid1 = new exports.JID(jid1);
- jid2 = new exports.JID(jid2);
- if (arguments.length === 2) {
- requirePrep = true;
- }
- return jid1.local === jid2.local &&
- jid1.domain === jid2.domain &&
- (requirePrep ? jid1.prepped && jid2.prepped : true);
-};
-
-exports.isBare = function (jid) {
- jid = new exports.JID(jid);
-
- var hasResource = !!jid.resource;
-
- return !hasResource;
-};
-
-exports.isFull = function (jid) {
- jid = new exports.JID(jid);
-
- var hasResource = !!jid.resource;
-
- return hasResource;
-};
-
-exports.escape = function (val) {
- return val.replace(/^\s+|\s+$/g, '')
- .replace(/\\5c/g, '\\5c5c')
- .replace(/\\20/g, '\\5c20')
- .replace(/\\22/g, '\\5c22')
- .replace(/\\26/g, '\\5c26')
- .replace(/\\27/g, '\\5c27')
- .replace(/\\2f/g, '\\5c2f')
- .replace(/\\3a/g, '\\5c3a')
- .replace(/\\3c/g, '\\5c3c')
- .replace(/\\3e/g, '\\5c3e')
- .replace(/\\40/g, '\\5c40')
- .replace(/ /g, '\\20')
- .replace(/\"/g, '\\22')
- .replace(/\&/g, '\\26')
- .replace(/\'/g, '\\27')
- .replace(/\//g, '\\2f')
- .replace(/:/g, '\\3a')
- .replace(/</g, '\\3c')
- .replace(/>/g, '\\3e')
- .replace(/@/g, '\\40');
-};
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
-exports.unescape = function (val) {
- return val.replace(/\\20/g, ' ')
- .replace(/\\22/g, '"')
- .replace(/\\26/g, '&')
- .replace(/\\27/g, '\'')
- .replace(/\\2f/g, '/')
- .replace(/\\3a/g, ':')
- .replace(/\\3c/g, '<')
- .replace(/\\3e/g, '>')
- .replace(/\\40/g, '@')
- .replace(/\\5c/g, '\\');
-};
+var _xmppConstants = require('xmpp-constants');
+exports['default'] = function (JXT) {
-exports.create = function (local, domain, resource) {
- return new exports.JID(local, domain, resource);
-};
+ var Utils = JXT.utils;
-exports.JID = function JID(localOrJID, domain, resource) {
- var parsed = {};
- if (localOrJID && !domain && !resource) {
- if (typeof localOrJID === 'string') {
- parsed = exports.parse(localOrJID);
- } else if (localOrJID._isJID || localOrJID instanceof exports.JID) {
- parsed = localOrJID;
- } else {
- throw new Error('Invalid argument type');
- }
- } else if (domain) {
- var trusted = ASCII.test(localOrJID) && ASCII.test(domain);
- if (resource) {
- trusted = trusted && ASCII.test(resource);
+ var Address = JXT.define({
+ name: '_address',
+ namespace: _xmppConstants.Namespace.ADDRESS,
+ element: 'address',
+ fields: {
+ jid: Utils.jidAttribute('jid'),
+ uri: Utils.attribute('uri'),
+ node: Utils.attribute('node'),
+ description: Utils.attribute('desc'),
+ delivered: Utils.boolAttribute('delivered'),
+ type: Utils.attribute('type')
}
+ });
- parsed = exports.prep({
- local: exports.escape(localOrJID),
- domain: domain,
- resource: resource,
- prepped: trusted
- });
- } else {
- parsed = {};
- }
-
- this._isJID = true;
-
- this.local = parsed.local || '';
- this.domain = parsed.domain || '';
- this.resource = parsed.resource || '';
- this.bare = parsed.bare || '';
- this.full = parsed.full || '';
-
- this.unescapedLocal = parsed.unescapedLocal || '';
- this.unescapedBare = parsed.unescapedBare || '';
- this.unescapedFull = parsed.unescapedFull || '';
-
- this.prepped = parsed.prepped;
-};
-
-exports.JID.prototype.toString = function () {
- return this.full;
-};
-
-exports.JID.prototype.toJSON = function () {
- return this.full;
-};
-
-},{"./lib/stringprep":135}],135:[function(require,module,exports){
-'use strict';
-
-var punycode = require('punycode');
-
-
-exports.available = false;
+ var Addresses = Utils.subMultiExtension(_xmppConstants.Namespace.ADDRESS, 'addresses', Address);
-exports.toUnicode = punycode.toUnicode;
-
-exports.nameprep = function (str) {
- return str.toLowerCase();
-};
+ JXT.withMessage(function (Message) {
+ JXT.add(Message, 'addresses', Addresses);
+ });
-exports.nodeprep = function (str) {
- return str.toLowerCase();
+ JXT.withPresence(function (Presence) {
+ JXT.add(Presence, 'addresses', Addresses);
+ });
};
-exports.resourceprep = function (str) {
- return str;
-};
+module.exports = exports['default'];
-},{"punycode":11}],136:[function(require,module,exports){
+},{"xmpp-constants":212}],58:[function(require,module,exports){
'use strict';
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
@@ -16767,7 +9172,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"babel-runtime/helpers/interop-require-default":197,"lodash.foreach":212,"xmpp-constants":220}],137:[function(require,module,exports){
+},{"babel-runtime/helpers/interop-require-default":2,"lodash.foreach":134,"xmpp-constants":212}],59:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -16796,7 +9201,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],138:[function(require,module,exports){
+},{"xmpp-constants":212}],60:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -16815,14 +9220,14 @@ exports['default'] = function (JXT) {
get: function get() {
var result = [];
- var items = types.find(this.xml, _xmppConstants.Namespace.BLOCKING, 'item');
+ var items = Utils.find(this.xml, _xmppConstants.Namespace.BLOCKING, 'item');
if (!items.length) {
return result;
}
items.forEach(function (item) {
- result.push(new _xmppJid.JID(types.getAttribute(item, 'jid', '')));
+ result.push(new _xmppJid.JID(Utils.getAttribute(item, 'jid', '')));
});
return result;
@@ -16832,8 +9237,8 @@ exports['default'] = function (JXT) {
var self = this;
values.forEach(function (value) {
- var item = types.createElement(_xmppConstants.Namespace.BLOCKING, 'item', _xmppConstants.Namespace.BLOCKING);
- types.setAttribute(item, 'jid', value.toString());
+ var item = Utils.createElement(_xmppConstants.Namespace.BLOCKING, 'item', _xmppConstants.Namespace.BLOCKING);
+ Utils.setAttribute(item, 'jid', value.toString());
self.xml.appendChild(item);
});
}
@@ -16873,7 +9278,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220,"xmpp-jid":226}],139:[function(require,module,exports){
+},{"xmpp-constants":212,"xmpp-jid":218}],61:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -16905,7 +9310,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],140:[function(require,module,exports){
+},{"xmpp-constants":212}],62:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -16946,7 +9351,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],141:[function(require,module,exports){
+},{"xmpp-constants":212}],63:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17025,7 +9430,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],142:[function(require,module,exports){
+},{"xmpp-constants":212}],64:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17084,7 +9489,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],143:[function(require,module,exports){
+},{"xmpp-constants":212}],65:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17170,7 +9575,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],144:[function(require,module,exports){
+},{"xmpp-constants":212}],66:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17208,7 +9613,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],145:[function(require,module,exports){
+},{"xmpp-constants":212}],67:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17507,7 +9912,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220,"xmpp-jid":226}],146:[function(require,module,exports){
+},{"xmpp-constants":212,"xmpp-jid":218}],68:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17537,7 +9942,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],147:[function(require,module,exports){
+},{"xmpp-constants":212}],69:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17625,7 +10030,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],148:[function(require,module,exports){
+},{"xmpp-constants":212}],70:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17704,7 +10109,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],149:[function(require,module,exports){
+},{"xmpp-constants":212}],71:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17760,7 +10165,103 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],150:[function(require,module,exports){
+},{"xmpp-constants":212}],72:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _xmppConstants = require('xmpp-constants');
+
+var FT_NS = _xmppConstants.Namespace.FILE_TRANSFER_4;
+
+exports['default'] = function (JXT) {
+
+ var Utils = JXT.utils;
+
+ var File = JXT.define({
+ name: 'file',
+ namespace: FT_NS,
+ element: 'file',
+ fields: {
+ name: Utils.textSub(FT_NS, 'name'),
+ description: Utils.textSub(FT_NS, 'desc'),
+ mediaType: Utils.textSub(FT_NS, 'media-type'),
+ size: Utils.numberSub(FT_NS, 'size'),
+ date: Utils.dateSub(FT_NS, 'date')
+ }
+ });
+
+ var Range = JXT.define({
+ name: 'range',
+ namespace: FT_NS,
+ element: 'range',
+ fields: {
+ offset: Utils.numberAttribute('offset'),
+ length: Utils.numberAttribute('length')
+ }
+ });
+
+ var FileTransfer = JXT.define({
+ name: '_' + FT_NS,
+ namespace: FT_NS,
+ element: 'description',
+ tags: ['jingle-application'],
+ fields: {
+ applicationType: { value: FT_NS }
+ }
+ });
+
+ var Received = JXT.define({
+ name: '_{' + FT_NS + '}received',
+ namespace: FT_NS,
+ element: 'received',
+ tags: ['jingle-info'],
+ fields: {
+ infoType: { value: '{' + FT_NS + '}received' },
+ creator: Utils.attribute('creator'),
+ name: Utils.attribute('name')
+ }
+ });
+
+ var Checksum = JXT.define({
+ name: '_{' + FT_NS + '}checksum',
+ namespace: FT_NS,
+ element: 'checksum',
+ tags: ['jingle-info'],
+ fields: {
+ infoType: { value: '{' + FT_NS + '}checksum' },
+ creator: Utils.attribute('creator'),
+ name: Utils.attribute('name')
+ }
+ });
+
+ JXT.extend(File, Range);
+ JXT.extend(Checksum, File);
+ JXT.extend(FileTransfer, File);
+
+ JXT.withDefinition('hash', _xmppConstants.Namespace.HASHES_1, function (Hash) {
+
+ JXT.extend(File, Hash, 'hashes');
+ JXT.extend(Range, Hash, 'hashes');
+ });
+
+ JXT.withDefinition('content', _xmppConstants.Namespace.JINGLE_1, function (Content) {
+
+ JXT.extend(Content, FileTransfer);
+ });
+
+ JXT.withDefinition('jingle', _xmppConstants.Namespace.JINGLE_1, function (Jingle) {
+
+ JXT.extend(Jingle, Received);
+ JXT.extend(Jingle, Checksum);
+ });
+};
+
+module.exports = exports['default'];
+
+},{"xmpp-constants":212}],73:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17812,9 +10313,9 @@ exports['default'] = function (JXT) {
name: '_filetransfer',
namespace: FT_NS,
element: 'description',
- tags: ['jingle-description'],
+ tags: ['jingle-application'],
fields: {
- descType: { value: 'filetransfer' },
+ applicationType: { value: 'filetransfer' },
offer: Utils.subExtension('offer', FT_NS, 'offer', File),
request: Utils.subExtension('request', FT_NS, 'request', File)
}
@@ -17836,7 +10337,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],151:[function(require,module,exports){
+},{"xmpp-constants":212}],74:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17853,15 +10354,24 @@ exports['default'] = function (JXT) {
element: 'forwarded'
});
- JXT.extendIQ(Forwarded);
- JXT.extendPresence(Forwarded);
-
JXT.withMessage(function (Message) {
JXT.extend(Message, Forwarded);
JXT.extend(Forwarded, Message);
});
+ JXT.withPresence(function (Presence) {
+
+ JXT.extend(Presence, Forwarded);
+ JXT.extend(Forwarded, Presence);
+ });
+
+ JXT.withIQ(function (IQ) {
+
+ JXT.extend(IQ, Forwarded);
+ JXT.extend(Forwarded, IQ);
+ });
+
JXT.withDefinition('delay', _xmppConstants.Namespace.DELAY, function (Delayed) {
JXT.extend(Forwarded, Delayed);
@@ -17870,7 +10380,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],152:[function(require,module,exports){
+},{"xmpp-constants":212}],75:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17910,7 +10420,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],153:[function(require,module,exports){
+},{"xmpp-constants":212}],76:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17960,7 +10470,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],154:[function(require,module,exports){
+},{"xmpp-constants":212}],77:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -17984,7 +10494,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],155:[function(require,module,exports){
+},{"xmpp-constants":212}],78:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -18014,7 +10524,143 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],156:[function(require,module,exports){
+},{"xmpp-constants":212}],79:[function(require,module,exports){
+(function (Buffer){
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _xmppConstants = require('xmpp-constants');
+
+var NS_IBB = 'http://jabber.org/protocol/ibb';
+var NS_JIBB = 'urn:xmpp:jingle:transports:ibb:1';
+
+exports['default'] = function (JXT) {
+
+ var Utils = JXT.utils;
+
+ var IBB = {
+ get: function get() {
+
+ var data = Utils.find(this.xml, NS_IBB, 'data');
+ if (data.length) {
+ data = data[0];
+ return {
+ action: 'data',
+ sid: Utils.getAttribute(data, 'sid'),
+ seq: parseInt(Utils.getAttribute(data, 'seq') || '0', 10),
+ data: new Buffer(Utils.getText(data), 'base64')
+ };
+ }
+
+ var open = Utils.find(this.xml, NS_IBB, 'open');
+ if (open.length) {
+ open = open[0];
+ var ack = Utils.getAttribute(open, 'stanza');
+ if (ack === 'message') {
+ ack = false;
+ } else {
+ ack = true;
+ }
+
+ return {
+ action: 'open',
+ sid: Utils.getAttribute(open, 'sid'),
+ blockSize: Utils.getAttribute(open, 'block-size'),
+ ack: ack
+ };
+ }
+
+ var close = Utils.find(this.xml, NS_IBB, 'close');
+ if (close.length) {
+ return {
+ action: 'close',
+ sid: Utils.getAttribute(close[0], 'sid')
+ };
+ }
+ },
+ set: function set(value) {
+
+ if (value.action === 'data') {
+ var data = Utils.createElement(NS_IBB, 'data');
+ Utils.setAttribute(data, 'sid', value.sid);
+ Utils.setAttribute(data, 'seq', value.seq.toString());
+ Utils.setText(data, value.data.toString('base64'));
+ this.xml.appendChild(data);
+ }
+
+ if (value.action === 'open') {
+ var _open = Utils.createElement(NS_IBB, 'open');
+ Utils.setAttribute(_open, 'sid', value.sid);
+ Utils.setAttribute(_open, 'block-size', (value.blockSize || '4096').toString());
+ if (value.ack === false) {
+ Utils.setAttribute(_open, 'stanza', 'message');
+ } else {
+ Utils.setAttribute(_open, 'stanza', 'iq');
+ }
+ this.xml.appendChild(_open);
+ }
+
+ if (value.action === 'close') {
+ var _close = Utils.createElement(NS_IBB, 'close');
+ Utils.setAttribute(_close, 'sid', value.sid);
+ this.xml.appendChild(_close);
+ }
+ }
+ };
+
+ var JingleIBB = JXT.define({
+ name: '_' + NS_JIBB,
+ namespace: NS_JIBB,
+ element: 'transport',
+ tags: ['jingle-transport'],
+ fields: {
+ transportType: {
+ value: NS_JIBB
+ },
+ sid: Utils.attribute('sid'),
+ blockSize: Utils.numberAttribute('block-size'),
+ ack: {
+ get: function get() {
+ var value = Utils.getAttribute(this.xml, 'stanza');
+ if (value === 'message') {
+ return false;
+ }
+ return true;
+ },
+ set: function set(value) {
+ if (value.ack === false) {
+ Utils.setAttribute(this.xml, 'stanza', 'message');
+ } else {
+ Utils.setAttribute(this.xml, 'stanza', 'iq');
+ }
+ }
+ }
+ }
+ });
+
+ JXT.withDefinition('content', _xmppConstants.Namespace.JINGLE_1, function (Content) {
+
+ JXT.extend(Content, JingleIBB);
+ });
+
+ JXT.withIQ(function (IQ) {
+
+ JXT.add(IQ, 'ibb', IBB);
+ });
+
+ JXT.withMessage(function (Message) {
+
+ JXT.add(Message, 'ibb', IBB);
+ });
+};
+
+module.exports = exports['default'];
+
+}).call(this,require("buffer").Buffer)
+},{"buffer":6,"xmpp-constants":212}],80:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -18033,7 +10679,7 @@ exports['default'] = function (JXT) {
element: 'transport',
tags: ['jingle-transport'],
fields: {
- transType: { value: 'iceUdp' },
+ transportType: { value: 'iceUdp' },
pwd: Utils.attribute('pwd'),
ufrag: Utils.attribute('ufrag')
}
@@ -18107,7 +10753,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],157:[function(require,module,exports){
+},{"xmpp-constants":212}],81:[function(require,module,exports){
'use strict';
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
@@ -18116,6 +10762,10 @@ Object.defineProperty(exports, '__esModule', {
value: true
});
+var _addresses = require('./addresses');
+
+var _addresses2 = _interopRequireDefault(_addresses);
+
var _avatar = require('./avatar');
var _avatar2 = _interopRequireDefault(_avatar);
@@ -18176,6 +10826,10 @@ var _file = require('./file');
var _file2 = _interopRequireDefault(_file);
+var _file3 = require('./file3');
+
+var _file32 = _interopRequireDefault(_file3);
+
var _forwarded = require('./forwarded');
var _forwarded2 = _interopRequireDefault(_forwarded);
@@ -18200,6 +10854,10 @@ var _iceUdp = require('./iceUdp');
var _iceUdp2 = _interopRequireDefault(_iceUdp);
+var _ibb = require('./ibb');
+
+var _ibb2 = _interopRequireDefault(_ibb);
+
var _iq = require('./iq');
var _iq2 = _interopRequireDefault(_iq);
@@ -18354,6 +11012,7 @@ var _visibility2 = _interopRequireDefault(_visibility);
exports['default'] = function (JXT) {
+ JXT.use(_addresses2['default']);
JXT.use(_avatar2['default']);
JXT.use(_bind2['default']);
JXT.use(_blocking2['default']);
@@ -18369,12 +11028,14 @@ exports['default'] = function (JXT) {
JXT.use(_error2['default']);
JXT.use(_extdisco2['default']);
JXT.use(_file2['default']);
+ JXT.use(_file32['default']);
JXT.use(_forwarded2['default']);
JXT.use(_framing2['default']);
JXT.use(_geoloc2['default']);
JXT.use(_hash2['default']);
JXT.use(_hats2['default']);
JXT.use(_iceUdp2['default']);
+ JXT.use(_ibb2['default']);
JXT.use(_iq2['default']);
JXT.use(_jidprep2['default']);
JXT.use(_jingle2['default']);
@@ -18417,7 +11078,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"./avatar":136,"./bind":137,"./blocking":138,"./bob":139,"./bookmarks":140,"./bosh":141,"./carbons":142,"./command":143,"./csi":144,"./dataforms":145,"./delayed":146,"./disco":147,"./error":148,"./extdisco":149,"./file":150,"./forwarded":151,"./framing":152,"./geoloc":153,"./hash":154,"./hats":155,"./iceUdp":156,"./iq":158,"./jidprep":159,"./jingle":160,"./json":161,"./logging":162,"./mam":163,"./message":164,"./mood":165,"./muc":166,"./nick":167,"./oob":168,"./ping":169,"./presence":170,"./private":171,"./psa":172,"./pubsub":173,"./pubsubError":174,"./pubsubEvents":175,"./pubsubOwner":176,"./push":177,"./reach":178,"./register":179,"./roster":180,"./rsm":181,"./rtp":182,"./rtt":183,"./sasl":184,"./session":185,"./shim":186,"./sm":187,"./stream":188,"./streamError":189,"./streamFeatures":190,"./time":191,"./tune":192,"./vcard":193,"./version":194,"./visibility":195,"babel-runtime/helpers/interop-require-default":197}],158:[function(require,module,exports){
+},{"./addresses":57,"./avatar":58,"./bind":59,"./blocking":60,"./bob":61,"./bookmarks":62,"./bosh":63,"./carbons":64,"./command":65,"./csi":66,"./dataforms":67,"./delayed":68,"./disco":69,"./error":70,"./extdisco":71,"./file":72,"./file3":73,"./forwarded":74,"./framing":75,"./geoloc":76,"./hash":77,"./hats":78,"./ibb":79,"./iceUdp":80,"./iq":82,"./jidprep":83,"./jingle":84,"./json":85,"./logging":86,"./mam":87,"./message":88,"./mood":89,"./muc":90,"./nick":91,"./oob":92,"./ping":93,"./presence":94,"./private":95,"./psa":96,"./pubsub":97,"./pubsubError":98,"./pubsubEvents":99,"./pubsubOwner":100,"./push":101,"./reach":102,"./register":103,"./roster":104,"./rsm":105,"./rtp":106,"./rtt":107,"./sasl":108,"./session":109,"./shim":110,"./sm":111,"./stream":112,"./streamError":113,"./streamFeatures":114,"./time":115,"./tune":116,"./vcard":117,"./version":118,"./visibility":119,"babel-runtime/helpers/interop-require-default":2}],82:[function(require,module,exports){
'use strict';
var _Object$assign = require('babel-runtime/core-js/object/assign')['default'];
@@ -18488,7 +11149,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"babel-runtime/core-js/object/assign":196,"xmpp-constants":220}],159:[function(require,module,exports){
+},{"babel-runtime/core-js/object/assign":1,"xmpp-constants":212}],83:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -18523,7 +11184,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220,"xmpp-jid":226}],160:[function(require,module,exports){
+},{"xmpp-constants":212,"xmpp-jid":218}],84:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -18547,7 +11208,40 @@ exports['default'] = function (JXT) {
action: Utils.attribute('action'),
initiator: Utils.attribute('initiator'),
responder: Utils.attribute('responder'),
- sid: Utils.attribute('sid')
+ sid: Utils.attribute('sid'),
+ info: {
+ get: function get() {
+
+ var opts = JXT.tagged('jingle-info').map(function (Info) {
+
+ return Info.prototype._name;
+ });
+ for (var i = 0, len = opts.length; i < len; i++) {
+ if (this._extensions[opts[i]]) {
+ return this._extensions[opts[i]];
+ }
+ }
+ if (Utils.getAttribute(this.xml, 'action') === 'session-info') {
+ if (this.xml.children.length === 0) {
+ return {
+ infoType: 'ping'
+ };
+ }
+ return {
+ infoType: 'unknown'
+ };
+ }
+ },
+ set: function set(value) {
+
+ if (value.infoType === 'ping') {
+ return;
+ }
+
+ var ext = '_' + value.infoType;
+ this[ext] = value;
+ }
+ }
}
});
@@ -18560,10 +11254,10 @@ exports['default'] = function (JXT) {
disposition: Utils.attribute('disposition', 'session'),
name: Utils.attribute('name'),
senders: Utils.attribute('senders', 'both'),
- description: {
+ application: {
get: function get() {
- var opts = JXT.tagged('jingle-description').map(function (Description) {
+ var opts = JXT.tagged('jingle-application').map(function (Description) {
return Description.prototype._name;
});
@@ -18575,7 +11269,7 @@ exports['default'] = function (JXT) {
},
set: function set(value) {
- var ext = '_' + value.descType;
+ var ext = '_' + value.applicationType;
this[ext] = value;
}
},
@@ -18594,7 +11288,26 @@ exports['default'] = function (JXT) {
},
set: function set(value) {
- var ext = '_' + value.transType;
+ var ext = '_' + value.transportType;
+ this[ext] = value;
+ }
+ },
+ security: {
+ get: function get() {
+
+ var opts = JXT.tagged('jingle-security').map(function (Info) {
+
+ return Security.prototype._name;
+ });
+ for (var i = 0, len = opts.length; i < len; i++) {
+ if (this._extensions[opts[i]]) {
+ return this._extensions[opts[i]];
+ }
+ }
+ },
+ set: function set(value) {
+
+ var ext = '_' + value.securityType;
this[ext] = value;
}
}
@@ -18635,7 +11348,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],161:[function(require,module,exports){
+},{"xmpp-constants":212}],85:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -18676,7 +11389,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],162:[function(require,module,exports){
+},{"xmpp-constants":212}],86:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -18726,7 +11439,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],163:[function(require,module,exports){
+},{"xmpp-constants":212}],87:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -18853,7 +11566,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220,"xmpp-jid":226}],164:[function(require,module,exports){
+},{"xmpp-constants":212,"xmpp-jid":218}],88:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -18917,7 +11630,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],165:[function(require,module,exports){
+},{"xmpp-constants":212}],89:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -18946,7 +11659,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],166:[function(require,module,exports){
+},{"xmpp-constants":212}],90:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -19227,7 +11940,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],167:[function(require,module,exports){
+},{"xmpp-constants":212}],91:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -19258,7 +11971,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],168:[function(require,module,exports){
+},{"xmpp-constants":212}],92:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -19284,7 +11997,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],169:[function(require,module,exports){
+},{"xmpp-constants":212}],93:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -19306,7 +12019,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],170:[function(require,module,exports){
+},{"xmpp-constants":212}],94:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -19402,7 +12115,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],171:[function(require,module,exports){
+},{"xmpp-constants":212}],95:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -19424,7 +12137,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],172:[function(require,module,exports){
+},{"xmpp-constants":212}],96:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -19453,7 +12166,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],173:[function(require,module,exports){
+},{"xmpp-constants":212}],97:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -19594,6 +12307,7 @@ exports['default'] = function (JXT) {
element: 'unsubscribe',
fields: {
node: Utils.attribute('node'),
+ subid: Utils.attribute('subid'),
jid: Utils.jidAttribute('jid')
}
});
@@ -19671,7 +12385,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],174:[function(require,module,exports){
+},{"xmpp-constants":212}],98:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -19703,7 +12417,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],175:[function(require,module,exports){
+},{"xmpp-constants":212}],99:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -19846,7 +12560,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],176:[function(require,module,exports){
+},{"xmpp-constants":212}],100:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -19961,7 +12675,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],177:[function(require,module,exports){
+},{"xmpp-constants":212}],101:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -20011,7 +12725,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],178:[function(require,module,exports){
+},{"xmpp-constants":212}],102:[function(require,module,exports){
'use strict';
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
@@ -20095,7 +12809,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"babel-runtime/helpers/interop-require-default":197,"lodash.foreach":212,"xmpp-constants":220}],179:[function(require,module,exports){
+},{"babel-runtime/helpers/interop-require-default":2,"lodash.foreach":134,"xmpp-constants":212}],103:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -20151,7 +12865,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],180:[function(require,module,exports){
+},{"xmpp-constants":212}],104:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -20210,7 +12924,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],181:[function(require,module,exports){
+},{"xmpp-constants":212}],105:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -20255,7 +12969,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],182:[function(require,module,exports){
+},{"xmpp-constants":212}],106:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -20335,9 +13049,9 @@ exports['default'] = function (JXT) {
name: '_rtp',
namespace: _xmppConstants.Namespace.JINGLE_RTP_1,
element: 'description',
- tags: ['jingle-description'],
+ tags: ['jingle-application'],
fields: {
- descType: { value: 'rtp' },
+ applicationType: { value: 'rtp' },
media: Utils.attribute('media'),
ssrc: Utils.attribute('ssrc'),
mux: Utils.boolSub(_xmppConstants.Namespace.JINGLE_RTP_1, 'rtcp-mux'),
@@ -20571,7 +13285,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],183:[function(require,module,exports){
+},{"xmpp-constants":212}],107:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -20683,7 +13397,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],184:[function(require,module,exports){
+},{"xmpp-constants":212}],108:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -20803,7 +13517,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],185:[function(require,module,exports){
+},{"xmpp-constants":212}],109:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -20830,7 +13544,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],186:[function(require,module,exports){
+},{"xmpp-constants":212}],110:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -20887,7 +13601,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],187:[function(require,module,exports){
+},{"xmpp-constants":212}],111:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -20985,7 +13699,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],188:[function(require,module,exports){
+},{"xmpp-constants":212}],112:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -21014,7 +13728,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],189:[function(require,module,exports){
+},{"xmpp-constants":212}],113:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -21080,7 +13794,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],190:[function(require,module,exports){
+},{"xmpp-constants":212}],114:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -21116,7 +13830,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],191:[function(require,module,exports){
+},{"xmpp-constants":212}],115:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -21142,7 +13856,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],192:[function(require,module,exports){
+},{"xmpp-constants":212}],116:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -21176,7 +13890,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],193:[function(require,module,exports){
+},{"xmpp-constants":212}],117:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -21294,7 +14008,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],194:[function(require,module,exports){
+},{"xmpp-constants":212}],118:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -21321,7 +14035,7 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],195:[function(require,module,exports){
+},{"xmpp-constants":212}],119:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
@@ -21341,225 +14055,11 @@ exports['default'] = function (JXT) {
module.exports = exports['default'];
-},{"xmpp-constants":220}],196:[function(require,module,exports){
-module.exports = { "default": require("core-js/library/fn/object/assign"), __esModule: true };
-},{"core-js/library/fn/object/assign":198}],197:[function(require,module,exports){
-"use strict";
-
-exports["default"] = function (obj) {
- return obj && obj.__esModule ? obj : {
- "default": obj
- };
-};
-
-exports.__esModule = true;
-},{}],198:[function(require,module,exports){
-require('../../modules/es6.object.assign');
-module.exports = require('../../modules/$.core').Object.assign;
-},{"../../modules/$.core":201,"../../modules/es6.object.assign":211}],199:[function(require,module,exports){
-module.exports = function(it){
- if(typeof it != 'function')throw TypeError(it + ' is not a function!');
- return it;
-};
-},{}],200:[function(require,module,exports){
-var toString = {}.toString;
-
-module.exports = function(it){
- return toString.call(it).slice(8, -1);
-};
-},{}],201:[function(require,module,exports){
-var core = module.exports = {version: '1.2.6'};
-if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef
-},{}],202:[function(require,module,exports){
-// optional / simple context binding
-var aFunction = require('./$.a-function');
-module.exports = function(fn, that, length){
- aFunction(fn);
- if(that === undefined)return fn;
- switch(length){
- case 1: return function(a){
- return fn.call(that, a);
- };
- case 2: return function(a, b){
- return fn.call(that, a, b);
- };
- case 3: return function(a, b, c){
- return fn.call(that, a, b, c);
- };
- }
- return function(/* ...args */){
- return fn.apply(that, arguments);
- };
-};
-},{"./$.a-function":199}],203:[function(require,module,exports){
-// 7.2.1 RequireObjectCoercible(argument)
-module.exports = function(it){
- if(it == undefined)throw TypeError("Can't call method on " + it);
- return it;
-};
-},{}],204:[function(require,module,exports){
-var global = require('./$.global')
- , core = require('./$.core')
- , ctx = require('./$.ctx')
- , PROTOTYPE = 'prototype';
-
-var $export = function(type, name, source){
- var IS_FORCED = type & $export.F
- , IS_GLOBAL = type & $export.G
- , IS_STATIC = type & $export.S
- , IS_PROTO = type & $export.P
- , IS_BIND = type & $export.B
- , IS_WRAP = type & $export.W
- , exports = IS_GLOBAL ? core : core[name] || (core[name] = {})
- , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE]
- , key, own, out;
- if(IS_GLOBAL)source = name;
- for(key in source){
- // contains in native
- own = !IS_FORCED && target && key in target;
- if(own && key in exports)continue;
- // export native or passed
- out = own ? target[key] : source[key];
- // prevent global pollution for namespaces
- exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key]
- // bind timers to global for call from export context
- : IS_BIND && own ? ctx(out, global)
- // wrap global constructors for prevent change them in library
- : IS_WRAP && target[key] == out ? (function(C){
- var F = function(param){
- return this instanceof C ? new C(param) : C(param);
- };
- F[PROTOTYPE] = C[PROTOTYPE];
- return F;
- // make static versions for prototype methods
- })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;
- if(IS_PROTO)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out;
- }
-};
-// type bitmap
-$export.F = 1; // forced
-$export.G = 2; // global
-$export.S = 4; // static
-$export.P = 8; // proto
-$export.B = 16; // bind
-$export.W = 32; // wrap
-module.exports = $export;
-},{"./$.core":201,"./$.ctx":202,"./$.global":206}],205:[function(require,module,exports){
-module.exports = function(exec){
- try {
- return !!exec();
- } catch(e){
- return true;
- }
-};
-},{}],206:[function(require,module,exports){
-// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
-var global = module.exports = typeof window != 'undefined' && window.Math == Math
- ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')();
-if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef
-},{}],207:[function(require,module,exports){
-// fallback for non-array-like ES3 and non-enumerable old V8 strings
-var cof = require('./$.cof');
-module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){
- return cof(it) == 'String' ? it.split('') : Object(it);
-};
-},{"./$.cof":200}],208:[function(require,module,exports){
-var $Object = Object;
-module.exports = {
- create: $Object.create,
- getProto: $Object.getPrototypeOf,
- isEnum: {}.propertyIsEnumerable,
- getDesc: $Object.getOwnPropertyDescriptor,
- setDesc: $Object.defineProperty,
- setDescs: $Object.defineProperties,
- getKeys: $Object.keys,
- getNames: $Object.getOwnPropertyNames,
- getSymbols: $Object.getOwnPropertySymbols,
- each: [].forEach
-};
-},{}],209:[function(require,module,exports){
-// 19.1.2.1 Object.assign(target, source, ...)
-var $ = require('./$')
- , toObject = require('./$.to-object')
- , IObject = require('./$.iobject');
-
-// should work with symbols and should have deterministic property order (V8 bug)
-module.exports = require('./$.fails')(function(){
- var a = Object.assign
- , A = {}
- , B = {}
- , S = Symbol()
- , K = 'abcdefghijklmnopqrst';
- A[S] = 7;
- K.split('').forEach(function(k){ B[k] = k; });
- return a({}, A)[S] != 7 || Object.keys(a({}, B)).join('') != K;
-}) ? function assign(target, source){ // eslint-disable-line no-unused-vars
- var T = toObject(target)
- , $$ = arguments
- , $$len = $$.length
- , index = 1
- , getKeys = $.getKeys
- , getSymbols = $.getSymbols
- , isEnum = $.isEnum;
- while($$len > index){
- var S = IObject($$[index++])
- , keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S)
- , length = keys.length
- , j = 0
- , key;
- while(length > j)if(isEnum.call(S, key = keys[j++]))T[key] = S[key];
- }
- return T;
-} : Object.assign;
-},{"./$":208,"./$.fails":205,"./$.iobject":207,"./$.to-object":210}],210:[function(require,module,exports){
-// 7.1.13 ToObject(argument)
-var defined = require('./$.defined');
-module.exports = function(it){
- return Object(defined(it));
-};
-},{"./$.defined":203}],211:[function(require,module,exports){
-// 19.1.3.1 Object.assign(target, source)
-var $export = require('./$.export');
-
-$export($export.S + $export.F, 'Object', {assign: require('./$.object-assign')});
-},{"./$.export":204,"./$.object-assign":209}],212:[function(require,module,exports){
-arguments[4][54][0].apply(exports,arguments)
-},{"dup":54,"lodash._arrayeach":213,"lodash._baseeach":214,"lodash._bindcallback":218,"lodash.isarray":219}],213:[function(require,module,exports){
-arguments[4][55][0].apply(exports,arguments)
-},{"dup":55}],214:[function(require,module,exports){
-arguments[4][56][0].apply(exports,arguments)
-},{"dup":56,"lodash.keys":215}],215:[function(require,module,exports){
-arguments[4][57][0].apply(exports,arguments)
-},{"dup":57,"lodash._getnative":216,"lodash.isarguments":217,"lodash.isarray":219}],216:[function(require,module,exports){
-arguments[4][58][0].apply(exports,arguments)
-},{"dup":58}],217:[function(require,module,exports){
-arguments[4][59][0].apply(exports,arguments)
-},{"dup":59}],218:[function(require,module,exports){
-arguments[4][60][0].apply(exports,arguments)
-},{"dup":60}],219:[function(require,module,exports){
-arguments[4][61][0].apply(exports,arguments)
-},{"dup":61}],220:[function(require,module,exports){
-arguments[4][128][0].apply(exports,arguments)
-},{"./lib/jingle":221,"./lib/muc":222,"./lib/namespaces":223,"./lib/presence":224,"./lib/pubsub":225,"dup":128}],221:[function(require,module,exports){
-arguments[4][129][0].apply(exports,arguments)
-},{"dup":129}],222:[function(require,module,exports){
-arguments[4][130][0].apply(exports,arguments)
-},{"dup":130}],223:[function(require,module,exports){
-arguments[4][131][0].apply(exports,arguments)
-},{"dup":131}],224:[function(require,module,exports){
-arguments[4][132][0].apply(exports,arguments)
-},{"dup":132}],225:[function(require,module,exports){
-arguments[4][133][0].apply(exports,arguments)
-},{"dup":133}],226:[function(require,module,exports){
-arguments[4][134][0].apply(exports,arguments)
-},{"./lib/stringprep":227,"dup":134}],227:[function(require,module,exports){
-arguments[4][135][0].apply(exports,arguments)
-},{"dup":135,"punycode":11}],228:[function(require,module,exports){
+},{"xmpp-constants":212}],120:[function(require,module,exports){
'use strict';
var extend = require('lodash.assign');
var uuid = require('uuid');
-var ltx = require('ltx');
var types = require('./lib/types');
var helpers = require('./lib/helpers');
@@ -21631,11 +14131,10 @@ JXT.prototype.build = function (xml) {
};
JXT.prototype.parse = function (str) {
- var xml = ltx.parse(str);
- if (xml.nodeType !== 1) {
+ var xml = helpers.parse(str);
+ if (!xml) {
return;
}
-
return this.build(xml);
};
@@ -21739,16 +14238,27 @@ JXT.getGlobalJXT = function () {
module.exports = JXT;
-},{"./lib/helpers":229,"./lib/stanza":230,"./lib/types":231,"lodash.assign":232,"ltx":245,"uuid":250}],229:[function(require,module,exports){
+},{"./lib/helpers":121,"./lib/stanza":122,"./lib/types":123,"lodash.assign":132,"uuid":199}],121:[function(require,module,exports){
'use strict';
var ltx = require('ltx');
+var DOMElement = require('ltx/lib/DOMElement');
var XML_NS = exports.XML_NS = 'http://www.w3.org/XML/1998/namespace';
+exports.parse = function (str) {
+ var xml = ltx.parse(str, {
+ Element: DOMElement
+ });
+ if (xml.nodeType !== 1) {
+ return;
+ }
+ return xml;
+};
+
exports.createElement = function (NS, name, parentNS) {
- var el = new ltx.Element(name);
+ var el = new DOMElement(name);
if (!parentNS || parentNS !== NS) {
exports.setAttribute(el, 'xmlns', NS);
}
@@ -22020,7 +14530,7 @@ exports.setBoolSub = function (xml, NS, element, value) {
}
};
-},{"ltx":245}],230:[function(require,module,exports){
+},{"ltx":139,"ltx/lib/DOMElement":140}],122:[function(require,module,exports){
'use strict';
var helpers = require('./helpers');
@@ -22072,7 +14582,7 @@ module.exports = function (JXT, opts) {
return self;
}
-
+ Stanza.prototype._isJXT = true;
Stanza.prototype._name = opts.name;
Stanza.prototype._eventname = opts.eventName;
Stanza.prototype._NS = opts.namespace;
@@ -22106,7 +14616,11 @@ module.exports = function (JXT, opts) {
var type = Object.prototype.toString.call(val);
if (type.indexOf('Object') >= 0) {
if (Object.keys(val).length > 0) {
- result[prop] = val;
+ if (val._isJXT) {
+ result[prop] = val.toJSON();
+ } else {
+ result[prop] = val;
+ }
}
} else if (type.indexOf('Array') >= 0) {
if (val.length > 0) {
@@ -22115,7 +14629,7 @@ module.exports = function (JXT, opts) {
for (var n = 0; n < len; n++) {
var nval = val[n];
if (typeof nval !== 'undefined') {
- if (nval.toJSON !== undefined) {
+ if (nval._isJXT) {
vals.push(nval.toJSON());
} else {
vals.push(nval);
@@ -22136,7 +14650,7 @@ module.exports = function (JXT, opts) {
return Stanza;
};
-},{"./helpers":229,"lodash.assign":232}],231:[function(require,module,exports){
+},{"./helpers":121,"lodash.assign":132}],123:[function(require,module,exports){
(function (Buffer){
'use strict';
@@ -22525,7 +15039,9 @@ exports.subMultiExtension = function (NS, sub, ChildJXT) {
existing = createElement(NS, sub, this._NS);
values.forEach(function (value) {
- var content = new ChildJXT(value, null, self);
+ var content = new ChildJXT(value, null, {
+ xml: { namespaceURI: NS }
+ });
existing.appendChild(content.xml);
});
@@ -22535,89 +15051,40 @@ exports.subMultiExtension = function (NS, sub, ChildJXT) {
};
}).call(this,require("buffer").Buffer)
-},{"./helpers":229,"buffer":2,"lodash.assign":232}],232:[function(require,module,exports){
+},{"./helpers":121,"buffer":6,"lodash.assign":132}],124:[function(require,module,exports){
/**
- * lodash 3.2.0 (Custom Build) <https://lodash.com/>
+ * lodash 3.0.0 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
-var baseAssign = require('lodash._baseassign'),
- createAssigner = require('lodash._createassigner'),
- keys = require('lodash.keys');
/**
- * A specialized version of `_.assign` for customizing assigned values without
- * support for argument juggling, multiple sources, and `this` binding `customizer`
- * functions.
+ * A specialized version of `_.forEach` for arrays without support for callback
+ * shorthands or `this` binding.
*
* @private
- * @param {Object} object The destination object.
- * @param {Object} source The source object.
- * @param {Function} customizer The function to customize assigned values.
- * @returns {Object} Returns `object`.
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
*/
-function assignWith(object, source, customizer) {
+function arrayEach(array, iteratee) {
var index = -1,
- props = keys(source),
- length = props.length;
+ length = array.length;
while (++index < length) {
- var key = props[index],
- value = object[key],
- result = customizer(value, source[key], key, object, source);
-
- if ((result === result ? (result !== value) : (value === value)) ||
- (value === undefined && !(key in object))) {
- object[key] = result;
+ if (iteratee(array[index], index, array) === false) {
+ break;
}
}
- return object;
+ return array;
}
-/**
- * Assigns own enumerable properties of source object(s) to the destination
- * object. Subsequent sources overwrite property assignments of previous sources.
- * If `customizer` is provided it is invoked to produce the assigned values.
- * The `customizer` is bound to `thisArg` and invoked with five arguments:
- * (objectValue, sourceValue, key, object, source).
- *
- * **Note:** This method mutates `object` and is based on
- * [`Object.assign`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign).
- *
- * @static
- * @memberOf _
- * @alias extend
- * @category Object
- * @param {Object} object The destination object.
- * @param {...Object} [sources] The source objects.
- * @param {Function} [customizer] The function to customize assigned values.
- * @param {*} [thisArg] The `this` binding of `customizer`.
- * @returns {Object} Returns `object`.
- * @example
- *
- * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
- * // => { 'user': 'fred', 'age': 40 }
- *
- * // using a customizer callback
- * var defaults = _.partialRight(_.assign, function(value, other) {
- * return _.isUndefined(value) ? other : value;
- * });
- *
- * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
- * // => { 'user': 'barney', 'age': 36 }
- */
-var assign = createAssigner(function(object, source, customizer) {
- return customizer
- ? assignWith(object, source, customizer)
- : baseAssign(object, source);
-});
-
-module.exports = assign;
+module.exports = arrayEach;
-},{"lodash._baseassign":233,"lodash._createassigner":235,"lodash.keys":239}],233:[function(require,module,exports){
+},{}],125:[function(require,module,exports){
/**
* lodash 3.2.0 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
@@ -22646,7 +15113,7 @@ function baseAssign(object, source) {
module.exports = baseAssign;
-},{"lodash._basecopy":234,"lodash.keys":239}],234:[function(require,module,exports){
+},{"lodash._basecopy":126,"lodash.keys":137}],126:[function(require,module,exports){
/**
* lodash 3.0.1 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
@@ -22680,7 +15147,257 @@ function baseCopy(source, props, object) {
module.exports = baseCopy;
-},{}],235:[function(require,module,exports){
+},{}],127:[function(require,module,exports){
+/**
+ * lodash 3.0.4 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern modularize exports="npm" -o ./`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+var keys = require('lodash.keys');
+
+/**
+ * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer)
+ * of an array-like value.
+ */
+var MAX_SAFE_INTEGER = 9007199254740991;
+
+/**
+ * The base implementation of `_.forEach` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+var baseEach = createBaseEach(baseForOwn);
+
+/**
+ * The base implementation of `baseForIn` and `baseForOwn` which iterates
+ * over `object` properties returned by `keysFunc` invoking `iteratee` for
+ * each property. Iteratee functions may exit iteration early by explicitly
+ * returning `false`.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+var baseFor = createBaseFor();
+
+/**
+ * The base implementation of `_.forOwn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+function baseForOwn(object, iteratee) {
+ return baseFor(object, iteratee, keys);
+}
+
+/**
+ * The base implementation of `_.property` without support for deep paths.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ */
+function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+}
+
+/**
+ * Creates a `baseEach` or `baseEachRight` function.
+ *
+ * @private
+ * @param {Function} eachFunc The function to iterate over a collection.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new base function.
+ */
+function createBaseEach(eachFunc, fromRight) {
+ return function(collection, iteratee) {
+ var length = collection ? getLength(collection) : 0;
+ if (!isLength(length)) {
+ return eachFunc(collection, iteratee);
+ }
+ var index = fromRight ? length : -1,
+ iterable = toObject(collection);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ if (iteratee(iterable[index], index, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ };
+}
+
+/**
+ * Creates a base function for `_.forIn` or `_.forInRight`.
+ *
+ * @private
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new base function.
+ */
+function createBaseFor(fromRight) {
+ return function(object, iteratee, keysFunc) {
+ var iterable = toObject(object),
+ props = keysFunc(object),
+ length = props.length,
+ index = fromRight ? length : -1;
+
+ while ((fromRight ? index-- : ++index < length)) {
+ var key = props[index];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ };
+}
+
+/**
+ * Gets the "length" property value of `object`.
+ *
+ * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
+ * that affects Safari on at least iOS 8.1-8.3 ARM64.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {*} Returns the "length" value.
+ */
+var getLength = baseProperty('length');
+
+/**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength).
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ */
+function isLength(value) {
+ return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+}
+
+/**
+ * Converts `value` to an object if it's not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Object} Returns the object.
+ */
+function toObject(value) {
+ return isObject(value) ? value : Object(value);
+}
+
+/**
+ * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(1);
+ * // => false
+ */
+function isObject(value) {
+ // Avoid a V8 JIT bug in Chrome 19-20.
+ // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+}
+
+module.exports = baseEach;
+
+},{"lodash.keys":137}],128:[function(require,module,exports){
+/**
+ * lodash 3.0.1 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern modularize exports="npm" -o ./`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+
+/**
+ * A specialized version of `baseCallback` which only supports `this` binding
+ * and specifying the number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+function bindCallback(func, thisArg, argCount) {
+ if (typeof func != 'function') {
+ return identity;
+ }
+ if (thisArg === undefined) {
+ return func;
+ }
+ switch (argCount) {
+ case 1: return function(value) {
+ return func.call(thisArg, value);
+ };
+ case 3: return function(value, index, collection) {
+ return func.call(thisArg, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(thisArg, accumulator, value, index, collection);
+ };
+ case 5: return function(value, other, key, object, source) {
+ return func.call(thisArg, value, other, key, object, source);
+ };
+ }
+ return function() {
+ return func.apply(thisArg, arguments);
+ };
+}
+
+/**
+ * This method returns the first argument provided to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value Any value.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ *
+ * _.identity(object) === object;
+ * // => true
+ */
+function identity(value) {
+ return value;
+}
+
+module.exports = bindCallback;
+
+},{}],129:[function(require,module,exports){
/**
* lodash 3.1.1 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
@@ -22734,9 +15451,146 @@ function createAssigner(assigner) {
module.exports = createAssigner;
-},{"lodash._bindcallback":236,"lodash._isiterateecall":237,"lodash.restparam":238}],236:[function(require,module,exports){
-arguments[4][60][0].apply(exports,arguments)
-},{"dup":60}],237:[function(require,module,exports){
+},{"lodash._bindcallback":128,"lodash._isiterateecall":131,"lodash.restparam":138}],130:[function(require,module,exports){
+/**
+ * lodash 3.9.1 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern modularize exports="npm" -o ./`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+
+/** `Object#toString` result references. */
+var funcTag = '[object Function]';
+
+/** Used to detect host constructors (Safari > 5). */
+var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+/**
+ * Checks if `value` is object-like.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ */
+function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+}
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/** Used to resolve the decompiled source of functions. */
+var fnToString = Function.prototype.toString;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objToString = objectProto.toString;
+
+/** Used to detect if a method is native. */
+var reIsNative = RegExp('^' +
+ fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
+ .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+);
+
+/**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+function getNative(object, key) {
+ var value = object == null ? undefined : object[key];
+ return isNative(value) ? value : undefined;
+}
+
+/**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in older versions of Chrome and Safari which return 'function' for regexes
+ // and Safari 8 equivalents which return 'object' for typed array constructors.
+ return isObject(value) && objToString.call(value) == funcTag;
+}
+
+/**
+ * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(1);
+ * // => false
+ */
+function isObject(value) {
+ // Avoid a V8 JIT bug in Chrome 19-20.
+ // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+}
+
+/**
+ * Checks if `value` is a native function.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
+ * @example
+ *
+ * _.isNative(Array.prototype.push);
+ * // => true
+ *
+ * _.isNative(_);
+ * // => false
+ */
+function isNative(value) {
+ if (value == null) {
+ return false;
+ }
+ if (isFunction(value)) {
+ return reIsNative.test(fnToString.call(value));
+ }
+ return isObjectLike(value) && reIsHostCtor.test(value);
+}
+
+module.exports = getNative;
+
+},{}],131:[function(require,module,exports){
/**
* lodash 3.0.9 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
@@ -22870,7 +15724,2556 @@ function isObject(value) {
module.exports = isIterateeCall;
-},{}],238:[function(require,module,exports){
+},{}],132:[function(require,module,exports){
+/**
+ * lodash 3.2.0 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern modularize exports="npm" -o ./`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+var baseAssign = require('lodash._baseassign'),
+ createAssigner = require('lodash._createassigner'),
+ keys = require('lodash.keys');
+
+/**
+ * A specialized version of `_.assign` for customizing assigned values without
+ * support for argument juggling, multiple sources, and `this` binding `customizer`
+ * functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} customizer The function to customize assigned values.
+ * @returns {Object} Returns `object`.
+ */
+function assignWith(object, source, customizer) {
+ var index = -1,
+ props = keys(source),
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key],
+ result = customizer(value, source[key], key, object, source);
+
+ if ((result === result ? (result !== value) : (value === value)) ||
+ (value === undefined && !(key in object))) {
+ object[key] = result;
+ }
+ }
+ return object;
+}
+
+/**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object. Subsequent sources overwrite property assignments of previous sources.
+ * If `customizer` is provided it is invoked to produce the assigned values.
+ * The `customizer` is bound to `thisArg` and invoked with five arguments:
+ * (objectValue, sourceValue, key, object, source).
+ *
+ * **Note:** This method mutates `object` and is based on
+ * [`Object.assign`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign).
+ *
+ * @static
+ * @memberOf _
+ * @alias extend
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize assigned values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
+ * // => { 'user': 'fred', 'age': 40 }
+ *
+ * // using a customizer callback
+ * var defaults = _.partialRight(_.assign, function(value, other) {
+ * return _.isUndefined(value) ? other : value;
+ * });
+ *
+ * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+var assign = createAssigner(function(object, source, customizer) {
+ return customizer
+ ? assignWith(object, source, customizer)
+ : baseAssign(object, source);
+});
+
+module.exports = assign;
+
+},{"lodash._baseassign":125,"lodash._createassigner":129,"lodash.keys":137}],133:[function(require,module,exports){
+(function (global){
+/**
+ * lodash (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+/** Used as the size to enable large array optimizations. */
+var LARGE_ARRAY_SIZE = 200;
+
+/** Used to stand-in for `undefined` hash values. */
+var HASH_UNDEFINED = '__lodash_hash_undefined__';
+
+/** Used as references for various `Number` constants. */
+var MAX_SAFE_INTEGER = 9007199254740991;
+
+/** `Object#toString` result references. */
+var argsTag = '[object Arguments]',
+ arrayTag = '[object Array]',
+ boolTag = '[object Boolean]',
+ dateTag = '[object Date]',
+ errorTag = '[object Error]',
+ funcTag = '[object Function]',
+ genTag = '[object GeneratorFunction]',
+ mapTag = '[object Map]',
+ numberTag = '[object Number]',
+ objectTag = '[object Object]',
+ promiseTag = '[object Promise]',
+ regexpTag = '[object RegExp]',
+ setTag = '[object Set]',
+ stringTag = '[object String]',
+ symbolTag = '[object Symbol]',
+ weakMapTag = '[object WeakMap]';
+
+var arrayBufferTag = '[object ArrayBuffer]',
+ dataViewTag = '[object DataView]',
+ float32Tag = '[object Float32Array]',
+ float64Tag = '[object Float64Array]',
+ int8Tag = '[object Int8Array]',
+ int16Tag = '[object Int16Array]',
+ int32Tag = '[object Int32Array]',
+ uint8Tag = '[object Uint8Array]',
+ uint8ClampedTag = '[object Uint8ClampedArray]',
+ uint16Tag = '[object Uint16Array]',
+ uint32Tag = '[object Uint32Array]';
+
+/**
+ * Used to match `RegExp`
+ * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
+ */
+var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
+
+/** Used to match `RegExp` flags from their coerced string values. */
+var reFlags = /\w*$/;
+
+/** Used to detect host constructors (Safari). */
+var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+/** Used to detect unsigned integer values. */
+var reIsUint = /^(?:0|[1-9]\d*)$/;
+
+/** Used to identify `toStringTag` values supported by `_.clone`. */
+var cloneableTags = {};
+cloneableTags[argsTag] = cloneableTags[arrayTag] =
+cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
+cloneableTags[boolTag] = cloneableTags[dateTag] =
+cloneableTags[float32Tag] = cloneableTags[float64Tag] =
+cloneableTags[int8Tag] = cloneableTags[int16Tag] =
+cloneableTags[int32Tag] = cloneableTags[mapTag] =
+cloneableTags[numberTag] = cloneableTags[objectTag] =
+cloneableTags[regexpTag] = cloneableTags[setTag] =
+cloneableTags[stringTag] = cloneableTags[symbolTag] =
+cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
+cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
+cloneableTags[errorTag] = cloneableTags[funcTag] =
+cloneableTags[weakMapTag] = false;
+
+/** Detect free variable `global` from Node.js. */
+var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
+
+/** Detect free variable `self`. */
+var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
+
+/** Used as a reference to the global object. */
+var root = freeGlobal || freeSelf || Function('return this')();
+
+/** Detect free variable `exports`. */
+var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
+
+/** Detect free variable `module`. */
+var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
+
+/** Detect the popular CommonJS extension `module.exports`. */
+var moduleExports = freeModule && freeModule.exports === freeExports;
+
+/**
+ * Adds the key-value `pair` to `map`.
+ *
+ * @private
+ * @param {Object} map The map to modify.
+ * @param {Array} pair The key-value pair to add.
+ * @returns {Object} Returns `map`.
+ */
+function addMapEntry(map, pair) {
+ // Don't return `map.set` because it's not chainable in IE 11.
+ map.set(pair[0], pair[1]);
+ return map;
+}
+
+/**
+ * Adds `value` to `set`.
+ *
+ * @private
+ * @param {Object} set The set to modify.
+ * @param {*} value The value to add.
+ * @returns {Object} Returns `set`.
+ */
+function addSetEntry(set, value) {
+ // Don't return `set.add` because it's not chainable in IE 11.
+ set.add(value);
+ return set;
+}
+
+/**
+ * A specialized version of `_.forEach` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+function arrayEach(array, iteratee) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ while (++index < length) {
+ if (iteratee(array[index], index, array) === false) {
+ break;
+ }
+ }
+ return array;
+}
+
+/**
+ * Appends the elements of `values` to `array`.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {Array} values The values to append.
+ * @returns {Array} Returns `array`.
+ */
+function arrayPush(array, values) {
+ var index = -1,
+ length = values.length,
+ offset = array.length;
+
+ while (++index < length) {
+ array[offset + index] = values[index];
+ }
+ return array;
+}
+
+/**
+ * A specialized version of `_.reduce` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initAccum] Specify using the first element of `array` as
+ * the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+function arrayReduce(array, iteratee, accumulator, initAccum) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ if (initAccum && length) {
+ accumulator = array[++index];
+ }
+ while (++index < length) {
+ accumulator = iteratee(accumulator, array[index], index, array);
+ }
+ return accumulator;
+}
+
+/**
+ * The base implementation of `_.times` without support for iteratee shorthands
+ * or max array length checks.
+ *
+ * @private
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the array of results.
+ */
+function baseTimes(n, iteratee) {
+ var index = -1,
+ result = Array(n);
+
+ while (++index < n) {
+ result[index] = iteratee(index);
+ }
+ return result;
+}
+
+/**
+ * Gets the value at `key` of `object`.
+ *
+ * @private
+ * @param {Object} [object] The object to query.
+ * @param {string} key The key of the property to get.
+ * @returns {*} Returns the property value.
+ */
+function getValue(object, key) {
+ return object == null ? undefined : object[key];
+}
+
+/**
+ * Checks if `value` is a host object in IE < 9.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
+ */
+function isHostObject(value) {
+ // Many host objects are `Object` objects that can coerce to strings
+ // despite having improperly defined `toString` methods.
+ var result = false;
+ if (value != null && typeof value.toString != 'function') {
+ try {
+ result = !!(value + '');
+ } catch (e) {}
+ }
+ return result;
+}
+
+/**
+ * Converts `map` to its key-value pairs.
+ *
+ * @private
+ * @param {Object} map The map to convert.
+ * @returns {Array} Returns the key-value pairs.
+ */
+function mapToArray(map) {
+ var index = -1,
+ result = Array(map.size);
+
+ map.forEach(function(value, key) {
+ result[++index] = [key, value];
+ });
+ return result;
+}
+
+/**
+ * Creates a unary function that invokes `func` with its argument transformed.
+ *
+ * @private
+ * @param {Function} func The function to wrap.
+ * @param {Function} transform The argument transform.
+ * @returns {Function} Returns the new function.
+ */
+function overArg(func, transform) {
+ return function(arg) {
+ return func(transform(arg));
+ };
+}
+
+/**
+ * Converts `set` to an array of its values.
+ *
+ * @private
+ * @param {Object} set The set to convert.
+ * @returns {Array} Returns the values.
+ */
+function setToArray(set) {
+ var index = -1,
+ result = Array(set.size);
+
+ set.forEach(function(value) {
+ result[++index] = value;
+ });
+ return result;
+}
+
+/** Used for built-in method references. */
+var arrayProto = Array.prototype,
+ funcProto = Function.prototype,
+ objectProto = Object.prototype;
+
+/** Used to detect overreaching core-js shims. */
+var coreJsData = root['__core-js_shared__'];
+
+/** Used to detect methods masquerading as native. */
+var maskSrcKey = (function() {
+ var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
+ return uid ? ('Symbol(src)_1.' + uid) : '';
+}());
+
+/** Used to resolve the decompiled source of functions. */
+var funcToString = funcProto.toString;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objectToString = objectProto.toString;
+
+/** Used to detect if a method is native. */
+var reIsNative = RegExp('^' +
+ funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
+ .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+);
+
+/** Built-in value references. */
+var Buffer = moduleExports ? root.Buffer : undefined,
+ Symbol = root.Symbol,
+ Uint8Array = root.Uint8Array,
+ getPrototype = overArg(Object.getPrototypeOf, Object),
+ objectCreate = Object.create,
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ splice = arrayProto.splice;
+
+/* Built-in method references for those with the same name as other `lodash` methods. */
+var nativeGetSymbols = Object.getOwnPropertySymbols,
+ nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
+ nativeKeys = overArg(Object.keys, Object);
+
+/* Built-in method references that are verified to be native. */
+var DataView = getNative(root, 'DataView'),
+ Map = getNative(root, 'Map'),
+ Promise = getNative(root, 'Promise'),
+ Set = getNative(root, 'Set'),
+ WeakMap = getNative(root, 'WeakMap'),
+ nativeCreate = getNative(Object, 'create');
+
+/** Used to detect maps, sets, and weakmaps. */
+var dataViewCtorString = toSource(DataView),
+ mapCtorString = toSource(Map),
+ promiseCtorString = toSource(Promise),
+ setCtorString = toSource(Set),
+ weakMapCtorString = toSource(WeakMap);
+
+/** Used to convert symbols to primitives and strings. */
+var symbolProto = Symbol ? Symbol.prototype : undefined,
+ symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;
+
+/**
+ * Creates a hash object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+function Hash(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+}
+
+/**
+ * Removes all key-value entries from the hash.
+ *
+ * @private
+ * @name clear
+ * @memberOf Hash
+ */
+function hashClear() {
+ this.__data__ = nativeCreate ? nativeCreate(null) : {};
+}
+
+/**
+ * Removes `key` and its value from the hash.
+ *
+ * @private
+ * @name delete
+ * @memberOf Hash
+ * @param {Object} hash The hash to modify.
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+function hashDelete(key) {
+ return this.has(key) && delete this.__data__[key];
+}
+
+/**
+ * Gets the hash value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Hash
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+function hashGet(key) {
+ var data = this.__data__;
+ if (nativeCreate) {
+ var result = data[key];
+ return result === HASH_UNDEFINED ? undefined : result;
+ }
+ return hasOwnProperty.call(data, key) ? data[key] : undefined;
+}
+
+/**
+ * Checks if a hash value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Hash
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+function hashHas(key) {
+ var data = this.__data__;
+ return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
+}
+
+/**
+ * Sets the hash `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Hash
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the hash instance.
+ */
+function hashSet(key, value) {
+ var data = this.__data__;
+ data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
+ return this;
+}
+
+// Add methods to `Hash`.
+Hash.prototype.clear = hashClear;
+Hash.prototype['delete'] = hashDelete;
+Hash.prototype.get = hashGet;
+Hash.prototype.has = hashHas;
+Hash.prototype.set = hashSet;
+
+/**
+ * Creates an list cache object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+function ListCache(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+}
+
+/**
+ * Removes all key-value entries from the list cache.
+ *
+ * @private
+ * @name clear
+ * @memberOf ListCache
+ */
+function listCacheClear() {
+ this.__data__ = [];
+}
+
+/**
+ * Removes `key` and its value from the list cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf ListCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+function listCacheDelete(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ return false;
+ }
+ var lastIndex = data.length - 1;
+ if (index == lastIndex) {
+ data.pop();
+ } else {
+ splice.call(data, index, 1);
+ }
+ return true;
+}
+
+/**
+ * Gets the list cache value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf ListCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+function listCacheGet(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ return index < 0 ? undefined : data[index][1];
+}
+
+/**
+ * Checks if a list cache value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf ListCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+function listCacheHas(key) {
+ return assocIndexOf(this.__data__, key) > -1;
+}
+
+/**
+ * Sets the list cache `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf ListCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the list cache instance.
+ */
+function listCacheSet(key, value) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ data.push([key, value]);
+ } else {
+ data[index][1] = value;
+ }
+ return this;
+}
+
+// Add methods to `ListCache`.
+ListCache.prototype.clear = listCacheClear;
+ListCache.prototype['delete'] = listCacheDelete;
+ListCache.prototype.get = listCacheGet;
+ListCache.prototype.has = listCacheHas;
+ListCache.prototype.set = listCacheSet;
+
+/**
+ * Creates a map cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+function MapCache(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+}
+
+/**
+ * Removes all key-value entries from the map.
+ *
+ * @private
+ * @name clear
+ * @memberOf MapCache
+ */
+function mapCacheClear() {
+ this.__data__ = {
+ 'hash': new Hash,
+ 'map': new (Map || ListCache),
+ 'string': new Hash
+ };
+}
+
+/**
+ * Removes `key` and its value from the map.
+ *
+ * @private
+ * @name delete
+ * @memberOf MapCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+function mapCacheDelete(key) {
+ return getMapData(this, key)['delete'](key);
+}
+
+/**
+ * Gets the map value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf MapCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+function mapCacheGet(key) {
+ return getMapData(this, key).get(key);
+}
+
+/**
+ * Checks if a map value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf MapCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+function mapCacheHas(key) {
+ return getMapData(this, key).has(key);
+}
+
+/**
+ * Sets the map `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf MapCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the map cache instance.
+ */
+function mapCacheSet(key, value) {
+ getMapData(this, key).set(key, value);
+ return this;
+}
+
+// Add methods to `MapCache`.
+MapCache.prototype.clear = mapCacheClear;
+MapCache.prototype['delete'] = mapCacheDelete;
+MapCache.prototype.get = mapCacheGet;
+MapCache.prototype.has = mapCacheHas;
+MapCache.prototype.set = mapCacheSet;
+
+/**
+ * Creates a stack cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+function Stack(entries) {
+ this.__data__ = new ListCache(entries);
+}
+
+/**
+ * Removes all key-value entries from the stack.
+ *
+ * @private
+ * @name clear
+ * @memberOf Stack
+ */
+function stackClear() {
+ this.__data__ = new ListCache;
+}
+
+/**
+ * Removes `key` and its value from the stack.
+ *
+ * @private
+ * @name delete
+ * @memberOf Stack
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+function stackDelete(key) {
+ return this.__data__['delete'](key);
+}
+
+/**
+ * Gets the stack value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Stack
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+function stackGet(key) {
+ return this.__data__.get(key);
+}
+
+/**
+ * Checks if a stack value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Stack
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+function stackHas(key) {
+ return this.__data__.has(key);
+}
+
+/**
+ * Sets the stack `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Stack
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the stack cache instance.
+ */
+function stackSet(key, value) {
+ var cache = this.__data__;
+ if (cache instanceof ListCache) {
+ var pairs = cache.__data__;
+ if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
+ pairs.push([key, value]);
+ return this;
+ }
+ cache = this.__data__ = new MapCache(pairs);
+ }
+ cache.set(key, value);
+ return this;
+}
+
+// Add methods to `Stack`.
+Stack.prototype.clear = stackClear;
+Stack.prototype['delete'] = stackDelete;
+Stack.prototype.get = stackGet;
+Stack.prototype.has = stackHas;
+Stack.prototype.set = stackSet;
+
+/**
+ * Creates an array of the enumerable property names of the array-like `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @param {boolean} inherited Specify returning inherited property names.
+ * @returns {Array} Returns the array of property names.
+ */
+function arrayLikeKeys(value, inherited) {
+ // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
+ // Safari 9 makes `arguments.length` enumerable in strict mode.
+ var result = (isArray(value) || isArguments(value))
+ ? baseTimes(value.length, String)
+ : [];
+
+ var length = result.length,
+ skipIndexes = !!length;
+
+ for (var key in value) {
+ if ((inherited || hasOwnProperty.call(value, key)) &&
+ !(skipIndexes && (key == 'length' || isIndex(key, length)))) {
+ result.push(key);
+ }
+ }
+ return result;
+}
+
+/**
+ * Assigns `value` to `key` of `object` if the existing value is not equivalent
+ * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * @private
+ * @param {Object} object The object to modify.
+ * @param {string} key The key of the property to assign.
+ * @param {*} value The value to assign.
+ */
+function assignValue(object, key, value) {
+ var objValue = object[key];
+ if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
+ (value === undefined && !(key in object))) {
+ object[key] = value;
+ }
+}
+
+/**
+ * Gets the index at which the `key` is found in `array` of key-value pairs.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} key The key to search for.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+function assocIndexOf(array, key) {
+ var length = array.length;
+ while (length--) {
+ if (eq(array[length][0], key)) {
+ return length;
+ }
+ }
+ return -1;
+}
+
+/**
+ * The base implementation of `_.assign` without support for multiple sources
+ * or `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @returns {Object} Returns `object`.
+ */
+function baseAssign(object, source) {
+ return object && copyObject(source, keys(source), object);
+}
+
+/**
+ * The base implementation of `_.clone` and `_.cloneDeep` which tracks
+ * traversed objects.
+ *
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {boolean} [isFull] Specify a clone including symbols.
+ * @param {Function} [customizer] The function to customize cloning.
+ * @param {string} [key] The key of `value`.
+ * @param {Object} [object] The parent object of `value`.
+ * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
+ * @returns {*} Returns the cloned value.
+ */
+function baseClone(value, isDeep, isFull, customizer, key, object, stack) {
+ var result;
+ if (customizer) {
+ result = object ? customizer(value, key, object, stack) : customizer(value);
+ }
+ if (result !== undefined) {
+ return result;
+ }
+ if (!isObject(value)) {
+ return value;
+ }
+ var isArr = isArray(value);
+ if (isArr) {
+ result = initCloneArray(value);
+ if (!isDeep) {
+ return copyArray(value, result);
+ }
+ } else {
+ var tag = getTag(value),
+ isFunc = tag == funcTag || tag == genTag;
+
+ if (isBuffer(value)) {
+ return cloneBuffer(value, isDeep);
+ }
+ if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+ if (isHostObject(value)) {
+ return object ? value : {};
+ }
+ result = initCloneObject(isFunc ? {} : value);
+ if (!isDeep) {
+ return copySymbols(value, baseAssign(result, value));
+ }
+ } else {
+ if (!cloneableTags[tag]) {
+ return object ? value : {};
+ }
+ result = initCloneByTag(value, tag, baseClone, isDeep);
+ }
+ }
+ // Check for circular references and return its corresponding clone.
+ stack || (stack = new Stack);
+ var stacked = stack.get(value);
+ if (stacked) {
+ return stacked;
+ }
+ stack.set(value, result);
+
+ if (!isArr) {
+ var props = isFull ? getAllKeys(value) : keys(value);
+ }
+ arrayEach(props || value, function(subValue, key) {
+ if (props) {
+ key = subValue;
+ subValue = value[key];
+ }
+ // Recursively populate clone (susceptible to call stack limits).
+ assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack));
+ });
+ return result;
+}
+
+/**
+ * The base implementation of `_.create` without support for assigning
+ * properties to the created object.
+ *
+ * @private
+ * @param {Object} prototype The object to inherit from.
+ * @returns {Object} Returns the new object.
+ */
+function baseCreate(proto) {
+ return isObject(proto) ? objectCreate(proto) : {};
+}
+
+/**
+ * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
+ * `keysFunc` and `symbolsFunc` to get the enumerable property names and
+ * symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @param {Function} symbolsFunc The function to get the symbols of `object`.
+ * @returns {Array} Returns the array of property names and symbols.
+ */
+function baseGetAllKeys(object, keysFunc, symbolsFunc) {
+ var result = keysFunc(object);
+ return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
+}
+
+/**
+ * The base implementation of `getTag`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+function baseGetTag(value) {
+ return objectToString.call(value);
+}
+
+/**
+ * The base implementation of `_.isNative` without bad shim checks.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function,
+ * else `false`.
+ */
+function baseIsNative(value) {
+ if (!isObject(value) || isMasked(value)) {
+ return false;
+ }
+ var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
+ return pattern.test(toSource(value));
+}
+
+/**
+ * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+function baseKeys(object) {
+ if (!isPrototype(object)) {
+ return nativeKeys(object);
+ }
+ var result = [];
+ for (var key in Object(object)) {
+ if (hasOwnProperty.call(object, key) && key != 'constructor') {
+ result.push(key);
+ }
+ }
+ return result;
+}
+
+/**
+ * Creates a clone of `buffer`.
+ *
+ * @private
+ * @param {Buffer} buffer The buffer to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Buffer} Returns the cloned buffer.
+ */
+function cloneBuffer(buffer, isDeep) {
+ if (isDeep) {
+ return buffer.slice();
+ }
+ var result = new buffer.constructor(buffer.length);
+ buffer.copy(result);
+ return result;
+}
+
+/**
+ * Creates a clone of `arrayBuffer`.
+ *
+ * @private
+ * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
+ * @returns {ArrayBuffer} Returns the cloned array buffer.
+ */
+function cloneArrayBuffer(arrayBuffer) {
+ var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
+ new Uint8Array(result).set(new Uint8Array(arrayBuffer));
+ return result;
+}
+
+/**
+ * Creates a clone of `dataView`.
+ *
+ * @private
+ * @param {Object} dataView The data view to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the cloned data view.
+ */
+function cloneDataView(dataView, isDeep) {
+ var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
+ return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
+}
+
+/**
+ * Creates a clone of `map`.
+ *
+ * @private
+ * @param {Object} map The map to clone.
+ * @param {Function} cloneFunc The function to clone values.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the cloned map.
+ */
+function cloneMap(map, isDeep, cloneFunc) {
+ var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map);
+ return arrayReduce(array, addMapEntry, new map.constructor);
+}
+
+/**
+ * Creates a clone of `regexp`.
+ *
+ * @private
+ * @param {Object} regexp The regexp to clone.
+ * @returns {Object} Returns the cloned regexp.
+ */
+function cloneRegExp(regexp) {
+ var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
+ result.lastIndex = regexp.lastIndex;
+ return result;
+}
+
+/**
+ * Creates a clone of `set`.
+ *
+ * @private
+ * @param {Object} set The set to clone.
+ * @param {Function} cloneFunc The function to clone values.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the cloned set.
+ */
+function cloneSet(set, isDeep, cloneFunc) {
+ var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set);
+ return arrayReduce(array, addSetEntry, new set.constructor);
+}
+
+/**
+ * Creates a clone of the `symbol` object.
+ *
+ * @private
+ * @param {Object} symbol The symbol object to clone.
+ * @returns {Object} Returns the cloned symbol object.
+ */
+function cloneSymbol(symbol) {
+ return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
+}
+
+/**
+ * Creates a clone of `typedArray`.
+ *
+ * @private
+ * @param {Object} typedArray The typed array to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the cloned typed array.
+ */
+function cloneTypedArray(typedArray, isDeep) {
+ var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
+ return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
+}
+
+/**
+ * Copies the values of `source` to `array`.
+ *
+ * @private
+ * @param {Array} source The array to copy values from.
+ * @param {Array} [array=[]] The array to copy values to.
+ * @returns {Array} Returns `array`.
+ */
+function copyArray(source, array) {
+ var index = -1,
+ length = source.length;
+
+ array || (array = Array(length));
+ while (++index < length) {
+ array[index] = source[index];
+ }
+ return array;
+}
+
+/**
+ * Copies properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy properties from.
+ * @param {Array} props The property identifiers to copy.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @param {Function} [customizer] The function to customize copied values.
+ * @returns {Object} Returns `object`.
+ */
+function copyObject(source, props, object, customizer) {
+ object || (object = {});
+
+ var index = -1,
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+
+ var newValue = customizer
+ ? customizer(object[key], source[key], key, object, source)
+ : undefined;
+
+ assignValue(object, key, newValue === undefined ? source[key] : newValue);
+ }
+ return object;
+}
+
+/**
+ * Copies own symbol properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy symbols from.
+ * @param {Object} [object={}] The object to copy symbols to.
+ * @returns {Object} Returns `object`.
+ */
+function copySymbols(source, object) {
+ return copyObject(source, getSymbols(source), object);
+}
+
+/**
+ * Creates an array of own enumerable property names and symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names and symbols.
+ */
+function getAllKeys(object) {
+ return baseGetAllKeys(object, keys, getSymbols);
+}
+
+/**
+ * Gets the data for `map`.
+ *
+ * @private
+ * @param {Object} map The map to query.
+ * @param {string} key The reference key.
+ * @returns {*} Returns the map data.
+ */
+function getMapData(map, key) {
+ var data = map.__data__;
+ return isKeyable(key)
+ ? data[typeof key == 'string' ? 'string' : 'hash']
+ : data.map;
+}
+
+/**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+function getNative(object, key) {
+ var value = getValue(object, key);
+ return baseIsNative(value) ? value : undefined;
+}
+
+/**
+ * Creates an array of the own enumerable symbol properties of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of symbols.
+ */
+var getSymbols = nativeGetSymbols ? overArg(nativeGetSymbols, Object) : stubArray;
+
+/**
+ * Gets the `toStringTag` of `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+var getTag = baseGetTag;
+
+// Fallback for data views, maps, sets, and weak maps in IE 11,
+// for data views in Edge < 14, and promises in Node.js.
+if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
+ (Map && getTag(new Map) != mapTag) ||
+ (Promise && getTag(Promise.resolve()) != promiseTag) ||
+ (Set && getTag(new Set) != setTag) ||
+ (WeakMap && getTag(new WeakMap) != weakMapTag)) {
+ getTag = function(value) {
+ var result = objectToString.call(value),
+ Ctor = result == objectTag ? value.constructor : undefined,
+ ctorString = Ctor ? toSource(Ctor) : undefined;
+
+ if (ctorString) {
+ switch (ctorString) {
+ case dataViewCtorString: return dataViewTag;
+ case mapCtorString: return mapTag;
+ case promiseCtorString: return promiseTag;
+ case setCtorString: return setTag;
+ case weakMapCtorString: return weakMapTag;
+ }
+ }
+ return result;
+ };
+}
+
+/**
+ * Initializes an array clone.
+ *
+ * @private
+ * @param {Array} array The array to clone.
+ * @returns {Array} Returns the initialized clone.
+ */
+function initCloneArray(array) {
+ var length = array.length,
+ result = array.constructor(length);
+
+ // Add properties assigned by `RegExp#exec`.
+ if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
+ result.index = array.index;
+ result.input = array.input;
+ }
+ return result;
+}
+
+/**
+ * Initializes an object clone.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+function initCloneObject(object) {
+ return (typeof object.constructor == 'function' && !isPrototype(object))
+ ? baseCreate(getPrototype(object))
+ : {};
+}
+
+/**
+ * Initializes an object clone based on its `toStringTag`.
+ *
+ * **Note:** This function only supports cloning values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @param {string} tag The `toStringTag` of the object to clone.
+ * @param {Function} cloneFunc The function to clone values.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+function initCloneByTag(object, tag, cloneFunc, isDeep) {
+ var Ctor = object.constructor;
+ switch (tag) {
+ case arrayBufferTag:
+ return cloneArrayBuffer(object);
+
+ case boolTag:
+ case dateTag:
+ return new Ctor(+object);
+
+ case dataViewTag:
+ return cloneDataView(object, isDeep);
+
+ case float32Tag: case float64Tag:
+ case int8Tag: case int16Tag: case int32Tag:
+ case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
+ return cloneTypedArray(object, isDeep);
+
+ case mapTag:
+ return cloneMap(object, isDeep, cloneFunc);
+
+ case numberTag:
+ case stringTag:
+ return new Ctor(object);
+
+ case regexpTag:
+ return cloneRegExp(object);
+
+ case setTag:
+ return cloneSet(object, isDeep, cloneFunc);
+
+ case symbolTag:
+ return cloneSymbol(object);
+ }
+}
+
+/**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+function isIndex(value, length) {
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return !!length &&
+ (typeof value == 'number' || reIsUint.test(value)) &&
+ (value > -1 && value % 1 == 0 && value < length);
+}
+
+/**
+ * Checks if `value` is suitable for use as unique object key.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
+ */
+function isKeyable(value) {
+ var type = typeof value;
+ return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
+ ? (value !== '__proto__')
+ : (value === null);
+}
+
+/**
+ * Checks if `func` has its source masked.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is masked, else `false`.
+ */
+function isMasked(func) {
+ return !!maskSrcKey && (maskSrcKey in func);
+}
+
+/**
+ * Checks if `value` is likely a prototype object.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
+ */
+function isPrototype(value) {
+ var Ctor = value && value.constructor,
+ proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
+
+ return value === proto;
+}
+
+/**
+ * Converts `func` to its source code.
+ *
+ * @private
+ * @param {Function} func The function to process.
+ * @returns {string} Returns the source code.
+ */
+function toSource(func) {
+ if (func != null) {
+ try {
+ return funcToString.call(func);
+ } catch (e) {}
+ try {
+ return (func + '');
+ } catch (e) {}
+ }
+ return '';
+}
+
+/**
+ * This method is like `_.clone` except that it recursively clones `value`.
+ *
+ * @static
+ * @memberOf _
+ * @since 1.0.0
+ * @category Lang
+ * @param {*} value The value to recursively clone.
+ * @returns {*} Returns the deep cloned value.
+ * @see _.clone
+ * @example
+ *
+ * var objects = [{ 'a': 1 }, { 'b': 2 }];
+ *
+ * var deep = _.cloneDeep(objects);
+ * console.log(deep[0] === objects[0]);
+ * // => false
+ */
+function cloneDeep(value) {
+ return baseClone(value, true, true);
+}
+
+/**
+ * Performs a
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * comparison between two values to determine if they are equivalent.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'a': 1 };
+ * var other = { 'a': 1 };
+ *
+ * _.eq(object, object);
+ * // => true
+ *
+ * _.eq(object, other);
+ * // => false
+ *
+ * _.eq('a', 'a');
+ * // => true
+ *
+ * _.eq('a', Object('a'));
+ * // => false
+ *
+ * _.eq(NaN, NaN);
+ * // => true
+ */
+function eq(value, other) {
+ return value === other || (value !== value && other !== other);
+}
+
+/**
+ * Checks if `value` is likely an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+ * else `false`.
+ * @example
+ *
+ * _.isArguments(function() { return arguments; }());
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+function isArguments(value) {
+ // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
+ return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
+ (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
+}
+
+/**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * _.isArray(document.body.children);
+ * // => false
+ *
+ * _.isArray('abc');
+ * // => false
+ *
+ * _.isArray(_.noop);
+ * // => false
+ */
+var isArray = Array.isArray;
+
+/**
+ * Checks if `value` is array-like. A value is considered array-like if it's
+ * not a function and has a `value.length` that's an integer greater than or
+ * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ * @example
+ *
+ * _.isArrayLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLike(document.body.children);
+ * // => true
+ *
+ * _.isArrayLike('abc');
+ * // => true
+ *
+ * _.isArrayLike(_.noop);
+ * // => false
+ */
+function isArrayLike(value) {
+ return value != null && isLength(value.length) && !isFunction(value);
+}
+
+/**
+ * This method is like `_.isArrayLike` except that it also checks if `value`
+ * is an object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array-like object,
+ * else `false`.
+ * @example
+ *
+ * _.isArrayLikeObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLikeObject(document.body.children);
+ * // => true
+ *
+ * _.isArrayLikeObject('abc');
+ * // => false
+ *
+ * _.isArrayLikeObject(_.noop);
+ * // => false
+ */
+function isArrayLikeObject(value) {
+ return isObjectLike(value) && isArrayLike(value);
+}
+
+/**
+ * Checks if `value` is a buffer.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.3.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
+ * @example
+ *
+ * _.isBuffer(new Buffer(2));
+ * // => true
+ *
+ * _.isBuffer(new Uint8Array(2));
+ * // => false
+ */
+var isBuffer = nativeIsBuffer || stubFalse;
+
+/**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a function, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in Safari 8-9 which returns 'object' for typed array and other constructors.
+ var tag = isObject(value) ? objectToString.call(value) : '';
+ return tag == funcTag || tag == genTag;
+}
+
+/**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This method is loosely based on
+ * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ * @example
+ *
+ * _.isLength(3);
+ * // => true
+ *
+ * _.isLength(Number.MIN_VALUE);
+ * // => false
+ *
+ * _.isLength(Infinity);
+ * // => false
+ *
+ * _.isLength('3');
+ * // => false
+ */
+function isLength(value) {
+ return typeof value == 'number' &&
+ value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+}
+
+/**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+function isObject(value) {
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+}
+
+/**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+}
+
+/**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @since 0.1.0
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+function keys(object) {
+ return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
+}
+
+/**
+ * This method returns a new empty array.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.13.0
+ * @category Util
+ * @returns {Array} Returns the new empty array.
+ * @example
+ *
+ * var arrays = _.times(2, _.stubArray);
+ *
+ * console.log(arrays);
+ * // => [[], []]
+ *
+ * console.log(arrays[0] === arrays[1]);
+ * // => false
+ */
+function stubArray() {
+ return [];
+}
+
+/**
+ * This method returns `false`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.13.0
+ * @category Util
+ * @returns {boolean} Returns `false`.
+ * @example
+ *
+ * _.times(2, _.stubFalse);
+ * // => [false, false]
+ */
+function stubFalse() {
+ return false;
+}
+
+module.exports = cloneDeep;
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}],134:[function(require,module,exports){
+/**
+ * lodash 3.0.3 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern modularize exports="npm" -o ./`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+var arrayEach = require('lodash._arrayeach'),
+ baseEach = require('lodash._baseeach'),
+ bindCallback = require('lodash._bindcallback'),
+ isArray = require('lodash.isarray');
+
+/**
+ * Creates a function for `_.forEach` or `_.forEachRight`.
+ *
+ * @private
+ * @param {Function} arrayFunc The function to iterate over an array.
+ * @param {Function} eachFunc The function to iterate over a collection.
+ * @returns {Function} Returns the new each function.
+ */
+function createForEach(arrayFunc, eachFunc) {
+ return function(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection))
+ ? arrayFunc(collection, iteratee)
+ : eachFunc(collection, bindCallback(iteratee, thisArg, 3));
+ };
+}
+
+/**
+ * Iterates over elements of `collection` invoking `iteratee` for each element.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments:
+ * (value, index|key, collection). Iteratee functions may exit iteration early
+ * by explicitly returning `false`.
+ *
+ * **Note:** As with other "Collections" methods, objects with a "length" property
+ * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
+ * may be used for object iteration.
+ *
+ * @static
+ * @memberOf _
+ * @alias each
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2]).forEach(function(n) {
+ * console.log(n);
+ * }).value();
+ * // => logs each value from left to right and returns the array
+ *
+ * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) {
+ * console.log(n, key);
+ * });
+ * // => logs each value-key pair and returns the object (iteration order is not guaranteed)
+ */
+var forEach = createForEach(arrayEach, baseEach);
+
+module.exports = forEach;
+
+},{"lodash._arrayeach":124,"lodash._baseeach":127,"lodash._bindcallback":128,"lodash.isarray":136}],135:[function(require,module,exports){
+/**
+ * lodash (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+/** Used as references for various `Number` constants. */
+var MAX_SAFE_INTEGER = 9007199254740991;
+
+/** `Object#toString` result references. */
+var argsTag = '[object Arguments]',
+ funcTag = '[object Function]',
+ genTag = '[object GeneratorFunction]';
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objectToString = objectProto.toString;
+
+/** Built-in value references. */
+var propertyIsEnumerable = objectProto.propertyIsEnumerable;
+
+/**
+ * Checks if `value` is likely an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+ * else `false`.
+ * @example
+ *
+ * _.isArguments(function() { return arguments; }());
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+function isArguments(value) {
+ // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
+ return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
+ (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
+}
+
+/**
+ * Checks if `value` is array-like. A value is considered array-like if it's
+ * not a function and has a `value.length` that's an integer greater than or
+ * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ * @example
+ *
+ * _.isArrayLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLike(document.body.children);
+ * // => true
+ *
+ * _.isArrayLike('abc');
+ * // => true
+ *
+ * _.isArrayLike(_.noop);
+ * // => false
+ */
+function isArrayLike(value) {
+ return value != null && isLength(value.length) && !isFunction(value);
+}
+
+/**
+ * This method is like `_.isArrayLike` except that it also checks if `value`
+ * is an object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array-like object,
+ * else `false`.
+ * @example
+ *
+ * _.isArrayLikeObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLikeObject(document.body.children);
+ * // => true
+ *
+ * _.isArrayLikeObject('abc');
+ * // => false
+ *
+ * _.isArrayLikeObject(_.noop);
+ * // => false
+ */
+function isArrayLikeObject(value) {
+ return isObjectLike(value) && isArrayLike(value);
+}
+
+/**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a function, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in Safari 8-9 which returns 'object' for typed array and other constructors.
+ var tag = isObject(value) ? objectToString.call(value) : '';
+ return tag == funcTag || tag == genTag;
+}
+
+/**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This method is loosely based on
+ * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ * @example
+ *
+ * _.isLength(3);
+ * // => true
+ *
+ * _.isLength(Number.MIN_VALUE);
+ * // => false
+ *
+ * _.isLength(Infinity);
+ * // => false
+ *
+ * _.isLength('3');
+ * // => false
+ */
+function isLength(value) {
+ return typeof value == 'number' &&
+ value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+}
+
+/**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+function isObject(value) {
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+}
+
+/**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+}
+
+module.exports = isArguments;
+
+},{}],136:[function(require,module,exports){
+/**
+ * lodash 3.0.4 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern modularize exports="npm" -o ./`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+
+/** `Object#toString` result references. */
+var arrayTag = '[object Array]',
+ funcTag = '[object Function]';
+
+/** Used to detect host constructors (Safari > 5). */
+var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+/**
+ * Checks if `value` is object-like.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ */
+function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+}
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/** Used to resolve the decompiled source of functions. */
+var fnToString = Function.prototype.toString;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objToString = objectProto.toString;
+
+/** Used to detect if a method is native. */
+var reIsNative = RegExp('^' +
+ fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
+ .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+);
+
+/* Native method references for those with the same name as other `lodash` methods. */
+var nativeIsArray = getNative(Array, 'isArray');
+
+/**
+ * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
+ * of an array-like value.
+ */
+var MAX_SAFE_INTEGER = 9007199254740991;
+
+/**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+function getNative(object, key) {
+ var value = object == null ? undefined : object[key];
+ return isNative(value) ? value : undefined;
+}
+
+/**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ */
+function isLength(value) {
+ return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+}
+
+/**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * _.isArray(function() { return arguments; }());
+ * // => false
+ */
+var isArray = nativeIsArray || function(value) {
+ return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
+};
+
+/**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in older versions of Chrome and Safari which return 'function' for regexes
+ // and Safari 8 equivalents which return 'object' for typed array constructors.
+ return isObject(value) && objToString.call(value) == funcTag;
+}
+
+/**
+ * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(1);
+ * // => false
+ */
+function isObject(value) {
+ // Avoid a V8 JIT bug in Chrome 19-20.
+ // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+}
+
+/**
+ * Checks if `value` is a native function.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
+ * @example
+ *
+ * _.isNative(Array.prototype.push);
+ * // => true
+ *
+ * _.isNative(_);
+ * // => false
+ */
+function isNative(value) {
+ if (value == null) {
+ return false;
+ }
+ if (isFunction(value)) {
+ return reIsNative.test(fnToString.call(value));
+ }
+ return isObjectLike(value) && reIsHostCtor.test(value);
+}
+
+module.exports = isArray;
+
+},{}],137:[function(require,module,exports){
+/**
+ * lodash 3.1.2 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern modularize exports="npm" -o ./`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+var getNative = require('lodash._getnative'),
+ isArguments = require('lodash.isarguments'),
+ isArray = require('lodash.isarray');
+
+/** Used to detect unsigned integer values. */
+var reIsUint = /^\d+$/;
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/* Native method references for those with the same name as other `lodash` methods. */
+var nativeKeys = getNative(Object, 'keys');
+
+/**
+ * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
+ * of an array-like value.
+ */
+var MAX_SAFE_INTEGER = 9007199254740991;
+
+/**
+ * The base implementation of `_.property` without support for deep paths.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ */
+function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+}
+
+/**
+ * Gets the "length" property value of `object`.
+ *
+ * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
+ * that affects Safari on at least iOS 8.1-8.3 ARM64.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {*} Returns the "length" value.
+ */
+var getLength = baseProperty('length');
+
+/**
+ * Checks if `value` is array-like.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ */
+function isArrayLike(value) {
+ return value != null && isLength(getLength(value));
+}
+
+/**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+function isIndex(value, length) {
+ value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return value > -1 && value % 1 == 0 && value < length;
+}
+
+/**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ */
+function isLength(value) {
+ return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+}
+
+/**
+ * A fallback implementation of `Object.keys` which creates an array of the
+ * own enumerable property names of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+function shimKeys(object) {
+ var props = keysIn(object),
+ propsLength = props.length,
+ length = propsLength && object.length;
+
+ var allowIndexes = !!length && isLength(length) &&
+ (isArray(object) || isArguments(object));
+
+ var index = -1,
+ result = [];
+
+ while (++index < propsLength) {
+ var key = props[index];
+ if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
+ result.push(key);
+ }
+ }
+ return result;
+}
+
+/**
+ * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(1);
+ * // => false
+ */
+function isObject(value) {
+ // Avoid a V8 JIT bug in Chrome 19-20.
+ // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+}
+
+/**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+var keys = !nativeKeys ? shimKeys : function(object) {
+ var Ctor = object == null ? undefined : object.constructor;
+ if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
+ (typeof object != 'function' && isArrayLike(object))) {
+ return shimKeys(object);
+ }
+ return isObject(object) ? nativeKeys(object) : [];
+};
+
+/**
+ * Creates an array of the own and inherited enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keysIn(new Foo);
+ * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
+ */
+function keysIn(object) {
+ if (object == null) {
+ return [];
+ }
+ if (!isObject(object)) {
+ object = Object(object);
+ }
+ var length = object.length;
+ length = (length && isLength(length) &&
+ (isArray(object) || isArguments(object)) && length) || 0;
+
+ var Ctor = object.constructor,
+ index = -1,
+ isProto = typeof Ctor == 'function' && Ctor.prototype === object,
+ result = Array(length),
+ skipIndexes = length > 0;
+
+ while (++index < length) {
+ result[index] = (index + '');
+ }
+ for (var key in object) {
+ if (!(skipIndexes && isIndex(key, length)) &&
+ !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+ result.push(key);
+ }
+ }
+ return result;
+}
+
+module.exports = keys;
+
+},{"lodash._getnative":130,"lodash.isarguments":135,"lodash.isarray":136}],138:[function(require,module,exports){
/**
* lodash 3.6.1 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
@@ -22939,322 +18342,378 @@ function restParam(func, start) {
module.exports = restParam;
-},{}],239:[function(require,module,exports){
-arguments[4][57][0].apply(exports,arguments)
-},{"dup":57,"lodash._getnative":240,"lodash.isarguments":241,"lodash.isarray":242}],240:[function(require,module,exports){
-arguments[4][58][0].apply(exports,arguments)
-},{"dup":58}],241:[function(require,module,exports){
-arguments[4][59][0].apply(exports,arguments)
-},{"dup":59}],242:[function(require,module,exports){
-arguments[4][61][0].apply(exports,arguments)
-},{"dup":61}],243:[function(require,module,exports){
-'use strict';
+},{}],139:[function(require,module,exports){
+'use strict'
+
+var parse = require('./lib/parse')
+var Parser = require('./lib/Parser')
+var escape = require('./lib/escape')
+var Element = require('./lib/Element')
+var equal = require('./lib/equal')
+var createElement = require('./lib/createElement')
+var tag = require('./lib/tag')
+var tagString = require('./lib/tagString')
+var is = require('./lib/is')
+
+exports = module.exports = tag
+
+exports.Element = Element
+
+exports.equal = equal.equal
+exports.nameEqual = equal.name
+exports.attrsEqual = equal.attrs
+exports.childrenEqual = equal.children
+
+exports.isNode = is.isNode
+exports.isElement = is.isElement
+exports.isText = is.isText
-var util = require('util')
- , Element = require('./element').Element
+exports.createElement = createElement
-function DOMElement(name, attrs) {
- Element.call(this, name, attrs)
+exports.escapeXML = escape.escapeXML
+exports.unescapeXML = escape.unescapeXML
+exports.escapeXMLText = escape.escapeXMLText
+exports.unescapeXMLText = escape.unescapeXMLText
- this.nodeType = 1
- this.nodeName = this.localName
+exports.Parser = Parser
+exports.parse = parse
+
+exports.tag = tag
+exports.tagString = tagString
+
+},{"./lib/Element":141,"./lib/Parser":142,"./lib/createElement":144,"./lib/equal":145,"./lib/escape":146,"./lib/is":147,"./lib/parse":148,"./lib/tag":150,"./lib/tagString":151}],140:[function(require,module,exports){
+'use strict'
+
+var inherits = require('inherits')
+var Element = require('./Element')
+
+function DOMElement (name, attrs) {
+ Element.call(this, name, attrs)
+
+ this.nodeType = 1
+ this.nodeName = this.localName
}
-util.inherits(DOMElement, Element)
+inherits(DOMElement, Element)
-DOMElement.prototype._getElement = function(name, attrs) {
- var element = new DOMElement(name, attrs)
- return element
+DOMElement.prototype._getElement = function (name, attrs) {
+ var element = new DOMElement(name, attrs)
+ return element
}
Object.defineProperty(DOMElement.prototype, 'localName', {
- get: function () {
- return this.getName()
- }
+ get: function () {
+ return this.getName()
+ }
})
Object.defineProperty(DOMElement.prototype, 'namespaceURI', {
- get: function () {
- return this.getNS()
- }
+ get: function () {
+ return this.getNS()
+ }
})
Object.defineProperty(DOMElement.prototype, 'parentNode', {
- get: function () {
- return this.parent
- }
+ get: function () {
+ return this.parent
+ }
})
Object.defineProperty(DOMElement.prototype, 'childNodes', {
- get: function () {
- return this.children
- }
+ get: function () {
+ return this.children
+ }
})
Object.defineProperty(DOMElement.prototype, 'textContent', {
- get: function () {
- return this.getText()
- },
- set: function (value) {
- this.children.push(value)
- }
+ get: function () {
+ return this.getText()
+ },
+ set: function (value) {
+ this.children.push(value)
+ }
})
DOMElement.prototype.getElementsByTagName = function (name) {
- return this.getChildren(name)
+ return this.getChildren(name)
}
DOMElement.prototype.getAttribute = function (name) {
- return this.getAttr(name)
+ return this.getAttr(name)
}
DOMElement.prototype.setAttribute = function (name, value) {
- this.attr(name, value)
+ this.attr(name, value)
}
DOMElement.prototype.getAttributeNS = function (ns, name) {
- if (ns === 'http://www.w3.org/XML/1998/namespace') {
- return this.getAttr(['xml', name].join(':'))
- }
- return this.getAttr(name, ns)
+ if (ns === 'http://www.w3.org/XML/1998/namespace') {
+ return this.getAttr(['xml', name].join(':'))
+ }
+ return this.getAttr(name, ns)
}
DOMElement.prototype.setAttributeNS = function (ns, name, value) {
- var prefix
- if (ns === 'http://www.w3.org/XML/1998/namespace') {
- prefix = 'xml'
- } else {
- var nss = this.getXmlns()
- prefix = nss[ns] || ''
- }
- if (prefix) {
- this.attr([prefix, name].join(':'), value)
- }
+ var prefix
+ if (ns === 'http://www.w3.org/XML/1998/namespace') {
+ prefix = 'xml'
+ } else {
+ var nss = this.getXmlns()
+ prefix = nss[ns] || ''
+ }
+ if (prefix) {
+ this.attr([prefix, name].join(':'), value)
+ }
}
DOMElement.prototype.removeAttribute = function (name) {
- this.attr(name, null)
+ this.attr(name, null)
}
DOMElement.prototype.removeAttributeNS = function (ns, name) {
- var prefix
- if (ns === 'http://www.w3.org/XML/1998/namespace') {
- prefix = 'xml'
- } else {
- var nss = this.getXmlns()
- prefix = nss[ns] || ''
- }
- if (prefix) {
- this.attr([prefix, name].join(':'), null)
- }
+ var prefix
+ if (ns === 'http://www.w3.org/XML/1998/namespace') {
+ prefix = 'xml'
+ } else {
+ var nss = this.getXmlns()
+ prefix = nss[ns] || ''
+ }
+ if (prefix) {
+ this.attr([prefix, name].join(':'), null)
+ }
}
DOMElement.prototype.appendChild = function (el) {
- this.cnode(el)
+ this.cnode(el)
}
DOMElement.prototype.removeChild = function (el) {
- this.remove(el)
+ this.remove(el)
+}
+
+DOMElement.createElement = function (name, attrs /*, child1, child2, ...*/) {
+ var el = new DOMElement(name, attrs)
+
+ var children = Array.prototype.slice.call(arguments, 2)
+
+ children.forEach(function (child) {
+ el.appendChild(child)
+ })
+ return el
}
module.exports = DOMElement
-},{"./element":244,"util":28}],244:[function(require,module,exports){
-'use strict';
+},{"./Element":141,"inherits":45}],141:[function(require,module,exports){
+'use strict'
+
+var escape = require('./escape')
+var escapeXML = escape.escapeXML
+var escapeXMLText = escape.escapeXMLText
+
+var equality = require('./equal')
+var equal = equality.equal
+var nameEqual = equality.name
+var attrsEqual = equality.attrs
+var childrenEqual = equality.children
+
+var clone = require('./clone')
/**
- * This cheap replica of DOM/Builder puts me to shame :-)
+ * Element
*
* Attributes are in the element.attrs object. Children is a list of
* either other Elements or Strings for text content.
**/
-function Element(name, attrs) {
- this.name = name
- this.parent = null
- this.children = []
- this.setAttrs(attrs)
+function Element (name, attrs) {
+ this.name = name
+ this.parent = null
+ this.children = []
+ this.attrs = {}
+ this.setAttrs(attrs)
}
-/*** Accessors ***/
+/* Accessors */
/**
* if (element.is('message', 'jabber:client')) ...
**/
-Element.prototype.is = function(name, xmlns) {
- return (this.getName() === name) &&
- (!xmlns || (this.getNS() === xmlns))
+Element.prototype.is = function (name, xmlns) {
+ return (this.getName() === name) &&
+ (!xmlns || (this.getNS() === xmlns))
}
/* without prefix */
-Element.prototype.getName = function() {
- if (this.name.indexOf(':') >= 0) {
- return this.name.substr(this.name.indexOf(':') + 1)
- } else {
- return this.name
- }
+Element.prototype.getName = function () {
+ if (this.name.indexOf(':') >= 0) {
+ return this.name.substr(this.name.indexOf(':') + 1)
+ } else {
+ return this.name
+ }
}
/**
* retrieves the namespace of the current element, upwards recursively
**/
-Element.prototype.getNS = function() {
- if (this.name.indexOf(':') >= 0) {
- var prefix = this.name.substr(0, this.name.indexOf(':'))
- return this.findNS(prefix)
- }
- return this.findNS()
+Element.prototype.getNS = function () {
+ if (this.name.indexOf(':') >= 0) {
+ var prefix = this.name.substr(0, this.name.indexOf(':'))
+ return this.findNS(prefix)
+ }
+ return this.findNS()
}
/**
* find the namespace to the given prefix, upwards recursively
**/
-Element.prototype.findNS = function(prefix) {
- if (!prefix) {
- /* default namespace */
- if (this.attrs.xmlns) {
- return this.attrs.xmlns
- } else if (this.parent) {
- return this.parent.findNS()
- }
- } else {
- /* prefixed namespace */
- var attr = 'xmlns:' + prefix
- if (this.attrs[attr]) {
- return this.attrs[attr]
- } else if (this.parent) {
- return this.parent.findNS(prefix)
- }
+Element.prototype.findNS = function (prefix) {
+ if (!prefix) {
+ /* default namespace */
+ if (this.attrs.xmlns) {
+ return this.attrs.xmlns
+ } else if (this.parent) {
+ return this.parent.findNS()
}
+ } else {
+ /* prefixed namespace */
+ var attr = 'xmlns:' + prefix
+ if (this.attrs[attr]) {
+ return this.attrs[attr]
+ } else if (this.parent) {
+ return this.parent.findNS(prefix)
+ }
+ }
}
/**
* Recursiverly gets all xmlns defined, in the form of {url:prefix}
**/
-Element.prototype.getXmlns = function() {
- var namespaces = {}
+Element.prototype.getXmlns = function () {
+ var namespaces = {}
- if (this.parent) {
- namespaces = this.parent.getXmlns()
- }
+ if (this.parent) {
+ namespaces = this.parent.getXmlns()
+ }
- for (var attr in this.attrs) {
- var m = attr.match('xmlns:?(.*)')
- if (this.attrs.hasOwnProperty(attr) && m) {
- namespaces[this.attrs[attr]] = m[1]
- }
+ for (var attr in this.attrs) {
+ var m = attr.match('xmlns:?(.*)')
+ if (this.attrs.hasOwnProperty(attr) && m) {
+ namespaces[this.attrs[attr]] = m[1]
}
- return namespaces
+ }
+ return namespaces
}
-Element.prototype.setAttrs = function(attrs) {
- this.attrs = {}
-
- if (typeof attrs === 'string')
- this.attrs.xmlns = attrs
- else if (attrs) {
- Object.keys(attrs).forEach(function(key) {
- this.attrs[key] = attrs[key]
- }, this)
- }
+Element.prototype.setAttrs = function (attrs) {
+ if (typeof attrs === 'string') {
+ this.attrs.xmlns = attrs
+ } else if (attrs) {
+ Object.keys(attrs).forEach(function (key) {
+ this.attrs[key] = attrs[key]
+ }, this)
+ }
}
/**
* xmlns can be null, returns the matching attribute.
**/
-Element.prototype.getAttr = function(name, xmlns) {
- if (!xmlns) {
- return this.attrs[name]
- }
+Element.prototype.getAttr = function (name, xmlns) {
+ if (!xmlns) {
+ return this.attrs[name]
+ }
- var namespaces = this.getXmlns()
+ var namespaces = this.getXmlns()
- if (!namespaces[xmlns]) {
- return null
- }
+ if (!namespaces[xmlns]) {
+ return null
+ }
- return this.attrs[[namespaces[xmlns], name].join(':')]
+ return this.attrs[[namespaces[xmlns], name].join(':')]
}
/**
* xmlns can be null
**/
-Element.prototype.getChild = function(name, xmlns) {
- return this.getChildren(name, xmlns)[0]
+Element.prototype.getChild = function (name, xmlns) {
+ return this.getChildren(name, xmlns)[0]
}
/**
* xmlns can be null
**/
-Element.prototype.getChildren = function(name, xmlns) {
- var result = []
- for (var i = 0; i < this.children.length; i++) {
- var child = this.children[i]
- if (child.getName &&
- (child.getName() === name) &&
- (!xmlns || (child.getNS() === xmlns)))
- result.push(child)
+Element.prototype.getChildren = function (name, xmlns) {
+ var result = []
+ for (var i = 0; i < this.children.length; i++) {
+ var child = this.children[i]
+ if (child.getName &&
+ (child.getName() === name) &&
+ (!xmlns || (child.getNS() === xmlns))) {
+ result.push(child)
}
- return result
+ }
+ return result
}
/**
* xmlns and recursive can be null
**/
-Element.prototype.getChildByAttr = function(attr, val, xmlns, recursive) {
- return this.getChildrenByAttr(attr, val, xmlns, recursive)[0]
+Element.prototype.getChildByAttr = function (attr, val, xmlns, recursive) {
+ return this.getChildrenByAttr(attr, val, xmlns, recursive)[0]
}
/**
* xmlns and recursive can be null
**/
-Element.prototype.getChildrenByAttr = function(attr, val, xmlns, recursive) {
- var result = []
- for (var i = 0; i < this.children.length; i++) {
- var child = this.children[i]
- if (child.attrs &&
- (child.attrs[attr] === val) &&
- (!xmlns || (child.getNS() === xmlns)))
- result.push(child)
- if (recursive && child.getChildrenByAttr) {
- result.push(child.getChildrenByAttr(attr, val, xmlns, true))
- }
+Element.prototype.getChildrenByAttr = function (attr, val, xmlns, recursive) {
+ var result = []
+ for (var i = 0; i < this.children.length; i++) {
+ var child = this.children[i]
+ if (child.attrs &&
+ (child.attrs[attr] === val) &&
+ (!xmlns || (child.getNS() === xmlns))) {
+ result.push(child)
}
- if (recursive) {
- result = [].concat.apply([], result)
+ if (recursive && child.getChildrenByAttr) {
+ result.push(child.getChildrenByAttr(attr, val, xmlns, true))
}
- return result
+ }
+ if (recursive) {
+ result = [].concat.apply([], result)
+ }
+ return result
}
-Element.prototype.getChildrenByFilter = function(filter, recursive) {
- var result = []
- for (var i = 0; i < this.children.length; i++) {
- var child = this.children[i]
- if (filter(child))
- result.push(child)
- if (recursive && child.getChildrenByFilter){
- result.push(child.getChildrenByFilter(filter, true))
- }
+Element.prototype.getChildrenByFilter = function (filter, recursive) {
+ var result = []
+ for (var i = 0; i < this.children.length; i++) {
+ var child = this.children[i]
+ if (filter(child)) {
+ result.push(child)
}
- if (recursive) {
- result = [].concat.apply([], result)
+ if (recursive && child.getChildrenByFilter) {
+ result.push(child.getChildrenByFilter(filter, true))
}
- return result
+ }
+ if (recursive) {
+ result = [].concat.apply([], result)
+ }
+ return result
}
-Element.prototype.getText = function() {
- var text = ''
- for (var i = 0; i < this.children.length; i++) {
- var child = this.children[i]
- if ((typeof child === 'string') || (typeof child === 'number')) {
- text += child
- }
+Element.prototype.getText = function () {
+ var text = ''
+ for (var i = 0; i < this.children.length; i++) {
+ var child = this.children[i]
+ if ((typeof child === 'string') || (typeof child === 'number')) {
+ text += child
}
- return text
+ }
+ return text
}
-Element.prototype.getChildText = function(name, xmlns) {
- var child = this.getChild(name, xmlns)
- return child ? child.getText() : null
+Element.prototype.getChildText = function (name, xmlns) {
+ var child = this.getChild(name, xmlns)
+ return child ? child.getText() : null
}
/**
@@ -23262,537 +18721,12807 @@ Element.prototype.getChildText = function(name, xmlns) {
* This differs from `getChildren` in that it will exclude text nodes,
* processing instructions, etc.
*/
-Element.prototype.getChildElements = function() {
- return this.getChildrenByFilter(function(child) {
- return child instanceof Element
- })
+Element.prototype.getChildElements = function () {
+ return this.getChildrenByFilter(function (child) {
+ return child instanceof Element
+ })
}
-/*** Builder ***/
+/* Builder */
/** returns uppermost parent */
-Element.prototype.root = function() {
- if (this.parent) {
- return this.parent.root()
- }
- return this
+Element.prototype.root = function () {
+ if (this.parent) {
+ return this.parent.root()
+ }
+ return this
}
Element.prototype.tree = Element.prototype.root
/** just parent or itself */
-Element.prototype.up = function() {
- if (this.parent) {
- return this.parent
- }
- return this
-}
-
-Element.prototype._getElement = function(name, attrs) {
- var element = new Element(name, attrs)
- return element
+Element.prototype.up = function () {
+ if (this.parent) {
+ return this.parent
+ }
+ return this
}
/** create child node and return it */
-Element.prototype.c = function(name, attrs) {
- return this.cnode(this._getElement(name, attrs))
+Element.prototype.c = function (name, attrs) {
+ return this.cnode(new Element(name, attrs))
}
-Element.prototype.cnode = function(child) {
- this.children.push(child)
- if (typeof child === 'object') {
- child.parent = this
- }
- return child
+Element.prototype.cnode = function (child) {
+ this.children.push(child)
+ if (typeof child === 'object') {
+ child.parent = this
+ }
+ return child
}
/** add text node and return element */
-Element.prototype.t = function(text) {
- this.children.push(text)
- return this
+Element.prototype.t = function (text) {
+ this.children.push(text)
+ return this
}
-/*** Manipulation ***/
+/* Manipulation */
/**
* Either:
* el.remove(childEl)
* el.remove('author', 'urn:...')
*/
-Element.prototype.remove = function(el, xmlns) {
- var filter
- if (typeof el === 'string') {
- /* 1st parameter is tag name */
- filter = function(child) {
- return !(child.is &&
- child.is(el, xmlns))
- }
- } else {
- /* 1st parameter is element */
- filter = function(child) {
- return child !== el
- }
+Element.prototype.remove = function (el, xmlns) {
+ var filter
+ if (typeof el === 'string') {
+ /* 1st parameter is tag name */
+ filter = function (child) {
+ return !(child.is &&
+ child.is(el, xmlns))
}
+ } else {
+ /* 1st parameter is element */
+ filter = function (child) {
+ return child !== el
+ }
+ }
- this.children = this.children.filter(filter)
+ this.children = this.children.filter(filter)
+
+ return this
+}
+Element.prototype.clone = function () {
+ return clone(this)
+}
+
+Element.prototype.text = function (val) {
+ if (val && this.children.length === 1) {
+ this.children[0] = val
return this
+ }
+ return this.getText()
+}
+
+Element.prototype.attr = function (attr, val) {
+ if (typeof val !== 'undefined' || val === null) {
+ if (!this.attrs) {
+ this.attrs = {}
+ }
+ this.attrs[attr] = val
+ return this
+ }
+ return this.attrs[attr]
+}
+
+/* Serialization */
+
+Element.prototype.toString = function () {
+ var s = ''
+ this.write(function (c) {
+ s += c
+ })
+ return s
}
+Element.prototype.toJSON = function () {
+ return {
+ name: this.name,
+ attrs: this.attrs,
+ children: this.children.map(function (child) {
+ return child && child.toJSON ? child.toJSON() : child
+ })
+ }
+}
+
+Element.prototype._addChildren = function (writer) {
+ writer('>')
+ for (var i = 0; i < this.children.length; i++) {
+ var child = this.children[i]
+ /* Skip null/undefined */
+ if (child || (child === 0)) {
+ if (child.write) {
+ child.write(writer)
+ } else if (typeof child === 'string') {
+ writer(escapeXMLText(child))
+ } else if (child.toString) {
+ writer(escapeXMLText(child.toString(10)))
+ }
+ }
+ }
+ writer('</')
+ writer(this.name)
+ writer('>')
+}
+
+Element.prototype.write = function (writer) {
+ writer('<')
+ writer(this.name)
+ for (var k in this.attrs) {
+ var v = this.attrs[k]
+ if (v != null) { // === null || undefined
+ writer(' ')
+ writer(k)
+ writer('="')
+ if (typeof v !== 'string') {
+ v = v.toString()
+ }
+ writer(escapeXML(v))
+ writer('"')
+ }
+ }
+ if (this.children.length === 0) {
+ writer('/>')
+ } else {
+ this._addChildren(writer)
+ }
+}
+
+Element.prototype.nameEquals = function (el) {
+ return nameEqual(this, el)
+}
+
+Element.prototype.attrsEquals = function (el) {
+ return attrsEqual(this, el)
+}
+
+Element.prototype.childrenEquals = function (el) {
+ return childrenEqual(this, el)
+}
+
+Element.prototype.equals = function (el) {
+ return equal(this, el)
+}
+
+module.exports = Element
+
+},{"./clone":143,"./equal":145,"./escape":146}],142:[function(require,module,exports){
+'use strict'
+
+var EventEmitter = require('events').EventEmitter
+var inherits = require('inherits')
+var Element = require('./Element')
+var LtxParser = require('./parsers/ltx')
+
+var Parser = function (options) {
+ EventEmitter.call(this)
+
+ var ParserInterface = this.Parser = (options && options.Parser) || this.DefaultParser
+ var ElementInterface = this.Element = (options && options.Element) || this.DefaultElement
+
+ this.parser = new ParserInterface()
+
+ var el
+ var self = this
+ this.parser.on('startElement', function (name, attrs) {
+ var child = new ElementInterface(name, attrs)
+ if (!el) {
+ el = child
+ } else {
+ el = el.cnode(child)
+ }
+ })
+ this.parser.on('endElement', function (name) {
+ if (!el) {
+ /* Err */
+ } else if (name === el.name) {
+ if (el.parent) {
+ el = el.parent
+ } else if (!self.tree) {
+ self.tree = el
+ el = undefined
+ }
+ }
+ })
+ this.parser.on('text', function (str) {
+ if (el) {
+ el.t(str)
+ }
+ })
+ this.parser.on('error', function (e) {
+ self.error = e
+ self.emit('error', e)
+ })
+}
+
+inherits(Parser, EventEmitter)
+
+Parser.prototype.DefaultParser = LtxParser
+
+Parser.prototype.DefaultElement = Element
+
+Parser.prototype.write = function (data) {
+ this.parser.write(data)
+}
+
+Parser.prototype.end = function (data) {
+ this.parser.end(data)
+
+ if (!this.error) {
+ if (this.tree) {
+ this.emit('tree', this.tree)
+ } else {
+ this.emit('error', new Error('Incomplete document'))
+ }
+ }
+}
+
+module.exports = Parser
+
+},{"./Element":141,"./parsers/ltx":149,"events":27,"inherits":45}],143:[function(require,module,exports){
+'use strict'
+
+module.exports = function clone (el) {
+ var clone = new el.constructor(el.name, el.attrs)
+ for (var i = 0; i < el.children.length; i++) {
+ var child = el.children[i]
+ clone.cnode(child.clone ? child.clone() : child)
+ }
+ return clone
+}
+
+},{}],144:[function(require,module,exports){
+'use strict'
+
+var Element = require('./Element')
+
/**
- * To use in case you want the same XML data for separate uses.
- * Please refrain from this practise unless you know what you are
- * doing. Building XML with ltx is easy!
+ * JSX compatible API, use this function as pragma
+ * https://facebook.github.io/jsx/
+ *
+ * @param {string} name name of the element
+ * @param {object} attrs object of attribute key/value pairs
+ * @return {Element} Element
*/
-Element.prototype.clone = function() {
- var clone = this._getElement(this.name, this.attrs)
- for (var i = 0; i < this.children.length; i++) {
- var child = this.children[i]
- clone.cnode(child.clone ? child.clone() : child)
+module.exports = function createElement (name, attrs /*, child1, child2, ...*/) {
+ var el = new Element(name, attrs)
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i]
+ if (child) el.cnode(child)
+ }
+
+ return el
+}
+
+},{"./Element":141}],145:[function(require,module,exports){
+'use strict'
+
+function nameEqual (a, b) {
+ return a.name === b.name
+}
+
+function attrsEqual (a, b) {
+ var attrs = a.attrs
+ var keys = Object.keys(attrs)
+ var length = keys.length
+ if (length !== Object.keys(b.attrs).length) return false
+ for (var i = 0, l = length; i < l; i++) {
+ var key = keys[i]
+ var value = attrs[key]
+ if (value == null || b.attrs[key] == null) { // === null || undefined
+ if (value !== b.attrs[key]) return false
+ } else if (value.toString() !== b.attrs[key].toString()) {
+ return false
}
- return clone
+ }
+ return true
}
-Element.prototype.text = function(val) {
- if (val && this.children.length === 1) {
- this.children[0] = val
- return this
+function childrenEqual (a, b) {
+ var children = a.children
+ var length = children.length
+ if (length !== b.children.length) return false
+ for (var i = 0, l = length; i < l; i++) {
+ var child = children[i]
+ if (typeof child === 'string') {
+ if (child !== b.children[i]) return false
+ } else {
+ if (!child.equals(b.children[i])) return false
}
- return this.getText()
+ }
+ return true
+}
+
+function equal (a, b) {
+ if (!nameEqual(a, b)) return false
+ if (!attrsEqual(a, b)) return false
+ if (!childrenEqual(a, b)) return false
+ return true
+}
+
+module.exports.name = nameEqual
+module.exports.attrs = attrsEqual
+module.exports.children = childrenEqual
+module.exports.equal = equal
+
+},{}],146:[function(require,module,exports){
+'use strict'
+
+var escapeXMLTable = {
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&quot;',
+ '\'': '&apos;'
+}
+
+function escapeXMLReplace (match) {
+ return escapeXMLTable[match]
+}
+
+var unescapeXMLTable = {
+ '&amp;': '&',
+ '&#38;': '&',
+ '&lt;': '<',
+ '&#60;': '<',
+ '&gt;': '>',
+ '&#62;': '>',
+ '&quot;': '"',
+ '&#34;': '"',
+ '&apos;': "'",
+ '&#39;': "'"
+}
+
+function unescapeXMLReplace (match) {
+ return unescapeXMLTable[match]
+}
+
+exports.escapeXML = function escapeXML (s) {
+ return s.replace(/&|<|>|"|'/g, escapeXMLReplace)
+}
+
+exports.unescapeXML = function unescapeXML (s) {
+ return s.replace(/&(amp|#38|lt|#60|gt|#62|quot|#34|apos|#39);/g, unescapeXMLReplace)
+}
+
+exports.escapeXMLText = function escapeXMLText (s) {
+ return s.replace(/&|<|>/g, escapeXMLReplace)
+}
+
+exports.unescapeXMLText = function unescapeXMLText (s) {
+ return s.replace(/&(amp|#38|lt|#60|gt|#62);/g, unescapeXMLReplace)
+}
+
+},{}],147:[function(require,module,exports){
+'use strict'
+
+var Element = require('./Element')
+
+module.exports.isNode = function is (el) {
+ return el instanceof Element || typeof el === 'string'
+}
+
+module.exports.isElement = function isElement (el) {
+ return el instanceof Element
+}
+
+module.exports.isText = function isText (el) {
+ return typeof el === 'string'
+}
+
+},{"./Element":141}],148:[function(require,module,exports){
+'use strict'
+
+var Parser = require('./Parser')
+
+module.exports = function parse (data, options) {
+ var p
+ if (typeof options === 'function') {
+ p = new options() // eslint-disable-line
+ } else {
+ p = new Parser(options)
+ }
+
+ var result = null
+ var error = null
+
+ p.on('tree', function (tree) {
+ result = tree
+ })
+ p.on('error', function (e) {
+ error = e
+ })
+
+ p.write(data)
+ p.end()
+
+ if (error) {
+ throw error
+ } else {
+ return result
+ }
+}
+
+},{"./Parser":142}],149:[function(require,module,exports){
+'use strict'
+
+var inherits = require('inherits')
+var EventEmitter = require('events').EventEmitter
+var unescapeXML = require('../escape').unescapeXML
+
+var STATE_TEXT = 0
+var STATE_IGNORE_TAG = 1
+var STATE_TAG_NAME = 2
+var STATE_TAG = 3
+var STATE_ATTR_NAME = 4
+var STATE_ATTR_EQ = 5
+var STATE_ATTR_QUOT = 6
+var STATE_ATTR_VALUE = 7
+
+var SaxLtx = module.exports = function SaxLtx () {
+ EventEmitter.call(this)
+
+ var state = STATE_TEXT
+ var remainder
+ var tagName
+ var attrs
+ var endTag
+ var selfClosing
+ var attrQuote
+ var recordStart = 0
+ var attrName
+
+ this._handleTagOpening = function (endTag, tagName, attrs) {
+ if (!endTag) {
+ this.emit('startElement', tagName, attrs)
+ if (selfClosing) {
+ this.emit('endElement', tagName)
+ }
+ } else {
+ this.emit('endElement', tagName)
+ }
+ }
+
+ this.write = function (data) {
+ if (typeof data !== 'string') {
+ data = data.toString()
+ }
+ var pos = 0
+
+ /* Anything from previous write()? */
+ if (remainder) {
+ data = remainder + data
+ pos += remainder.length
+ remainder = null
+ }
+
+ function endRecording () {
+ if (typeof recordStart === 'number') {
+ var recorded = data.slice(recordStart, pos)
+ recordStart = undefined
+ return recorded
+ }
+ }
+
+ for (; pos < data.length; pos++) {
+ var c = data.charCodeAt(pos)
+ // console.log("state", state, "c", c, data[pos])
+ switch (state) {
+ case STATE_TEXT:
+ if (c === 60 /* < */) {
+ var text = endRecording()
+ if (text) {
+ this.emit('text', unescapeXML(text))
+ }
+ state = STATE_TAG_NAME
+ recordStart = pos + 1
+ attrs = {}
+ }
+ break
+ case STATE_TAG_NAME:
+ if (c === 47 /* / */ && recordStart === pos) {
+ recordStart = pos + 1
+ endTag = true
+ } else if (c === 33 /* ! */ || c === 63 /* ? */) {
+ recordStart = undefined
+ state = STATE_IGNORE_TAG
+ } else if (c <= 32 || c === 47 /* / */ || c === 62 /* > */) {
+ tagName = endRecording()
+ pos--
+ state = STATE_TAG
+ }
+ break
+ case STATE_IGNORE_TAG:
+ if (c === 62 /* > */) {
+ state = STATE_TEXT
+ }
+ break
+ case STATE_TAG:
+ if (c === 62 /* > */) {
+ this._handleTagOpening(endTag, tagName, attrs)
+ tagName = undefined
+ attrs = undefined
+ endTag = undefined
+ selfClosing = undefined
+ state = STATE_TEXT
+ recordStart = pos + 1
+ } else if (c === 47 /* / */) {
+ selfClosing = true
+ } else if (c > 32) {
+ recordStart = pos
+ state = STATE_ATTR_NAME
+ }
+ break
+ case STATE_ATTR_NAME:
+ if (c <= 32 || c === 61 /* = */) {
+ attrName = endRecording()
+ pos--
+ state = STATE_ATTR_EQ
+ }
+ break
+ case STATE_ATTR_EQ:
+ if (c === 61 /* = */) {
+ state = STATE_ATTR_QUOT
+ }
+ break
+ case STATE_ATTR_QUOT:
+ if (c === 34 /* " */ || c === 39 /* ' */) {
+ attrQuote = c
+ state = STATE_ATTR_VALUE
+ recordStart = pos + 1
+ }
+ break
+ case STATE_ATTR_VALUE:
+ if (c === attrQuote) {
+ var value = unescapeXML(endRecording())
+ attrs[attrName] = value
+ attrName = undefined
+ state = STATE_TAG
+ }
+ break
+ }
+ }
+
+ if (typeof recordStart === 'number' &&
+ recordStart <= data.length) {
+ remainder = data.slice(recordStart)
+ recordStart = 0
+ }
+ }
+ /*
+ var origEmit = this.emit
+ this.emit = function() {
+ console.log('ltx', arguments)
+ origEmit.apply(this, arguments)
+ }
+ */
+}
+inherits(SaxLtx, EventEmitter)
+
+SaxLtx.prototype.end = function (data) {
+ if (data) {
+ this.write(data)
+ }
+
+ /* Uh, yeah */
+ this.write = function () {}
+}
+
+},{"../escape":146,"events":27,"inherits":45}],150:[function(require,module,exports){
+'use strict'
+
+var tagString = require('./tagString')
+var parse = require('./parse')
+
+module.exports = function tag (/* [literals], ...substitutions */) {
+ return parse(tagString.apply(null, arguments))
+}
+
+},{"./parse":148,"./tagString":151}],151:[function(require,module,exports){
+'use strict'
+
+var escape = require('./escape').escapeXML
+
+module.exports = function tagString (/* [literals], ...substitutions */) {
+ var literals = arguments[0]
+
+ var str = ''
+
+ for (var i = 1; i < arguments.length; i++) {
+ str += literals[i - 1]
+ str += escape(arguments[i])
+ }
+ str += literals[literals.length - 1]
+
+ return str
+}
+
+},{"./escape":146}],152:[function(require,module,exports){
+(function (process){
+'use strict';
+
+if (!process.version ||
+ process.version.indexOf('v0.') === 0 ||
+ process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) {
+ module.exports = nextTick;
+} else {
+ module.exports = process.nextTick;
+}
+
+function nextTick(fn, arg1, arg2, arg3) {
+ if (typeof fn !== 'function') {
+ throw new TypeError('"callback" argument must be a function');
+ }
+ var len = arguments.length;
+ var args, i;
+ switch (len) {
+ case 0:
+ case 1:
+ return process.nextTick(fn);
+ case 2:
+ return process.nextTick(function afterTickOne() {
+ fn.call(null, arg1);
+ });
+ case 3:
+ return process.nextTick(function afterTickTwo() {
+ fn.call(null, arg1, arg2);
+ });
+ case 4:
+ return process.nextTick(function afterTickThree() {
+ fn.call(null, arg1, arg2, arg3);
+ });
+ default:
+ args = new Array(len - 1);
+ i = 0;
+ while (i < args.length) {
+ args[i++] = arguments[i];
+ }
+ return process.nextTick(function afterTick() {
+ fn.apply(null, args);
+ });
+ }
}
-Element.prototype.attr = function(attr, val) {
- if (((typeof val !== 'undefined') || (val === null))) {
- if (!this.attrs) {
- this.attrs = {}
+}).call(this,require('_process'))
+},{"_process":153}],153:[function(require,module,exports){
+// shim for using process in browser
+var process = module.exports = {};
+
+// cached from whatever global is present so that test runners that stub it
+// don't break things. But we need to wrap it in a try catch in case it is
+// wrapped in strict mode code which doesn't define any globals. It's inside a
+// function because try/catches deoptimize in certain engines.
+
+var cachedSetTimeout;
+var cachedClearTimeout;
+
+function defaultSetTimout() {
+ throw new Error('setTimeout has not been defined');
+}
+function defaultClearTimeout () {
+ throw new Error('clearTimeout has not been defined');
+}
+(function () {
+ try {
+ if (typeof setTimeout === 'function') {
+ cachedSetTimeout = setTimeout;
+ } else {
+ cachedSetTimeout = defaultSetTimout;
+ }
+ } catch (e) {
+ cachedSetTimeout = defaultSetTimout;
+ }
+ try {
+ if (typeof clearTimeout === 'function') {
+ cachedClearTimeout = clearTimeout;
+ } else {
+ cachedClearTimeout = defaultClearTimeout;
+ }
+ } catch (e) {
+ cachedClearTimeout = defaultClearTimeout;
+ }
+} ())
+function runTimeout(fun) {
+ if (cachedSetTimeout === setTimeout) {
+ //normal enviroments in sane situations
+ return setTimeout(fun, 0);
+ }
+ // if setTimeout wasn't available but was latter defined
+ if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
+ cachedSetTimeout = setTimeout;
+ return setTimeout(fun, 0);
+ }
+ try {
+ // when when somebody has screwed with setTimeout but no I.E. maddness
+ return cachedSetTimeout(fun, 0);
+ } catch(e){
+ try {
+ // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+ return cachedSetTimeout.call(null, fun, 0);
+ } catch(e){
+ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
+ return cachedSetTimeout.call(this, fun, 0);
}
- this.attrs[attr] = val
- return this
}
- return this.attrs[attr]
+
+
}
+function runClearTimeout(marker) {
+ if (cachedClearTimeout === clearTimeout) {
+ //normal enviroments in sane situations
+ return clearTimeout(marker);
+ }
+ // if clearTimeout wasn't available but was latter defined
+ if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
+ cachedClearTimeout = clearTimeout;
+ return clearTimeout(marker);
+ }
+ try {
+ // when when somebody has screwed with setTimeout but no I.E. maddness
+ return cachedClearTimeout(marker);
+ } catch (e){
+ try {
+ // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+ return cachedClearTimeout.call(null, marker);
+ } catch (e){
+ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
+ // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+ return cachedClearTimeout.call(this, marker);
+ }
+ }
+
-/*** Serialization ***/
-Element.prototype.toString = function() {
- var s = ''
- this.write(function(c) {
- s += c
- })
- return s
}
+var queue = [];
+var draining = false;
+var currentQueue;
+var queueIndex = -1;
-Element.prototype.toJSON = function() {
- return {
- name: this.name,
- attrs: this.attrs,
- children: this.children.map(function(child) {
- return child && child.toJSON ? child.toJSON() : child
- })
+function cleanUpNextTick() {
+ if (!draining || !currentQueue) {
+ return;
+ }
+ draining = false;
+ if (currentQueue.length) {
+ queue = currentQueue.concat(queue);
+ } else {
+ queueIndex = -1;
+ }
+ if (queue.length) {
+ drainQueue();
}
}
-Element.prototype._addChildren = function(writer) {
- writer('>')
- for (var i = 0; i < this.children.length; i++) {
- var child = this.children[i]
- /* Skip null/undefined */
- if (child || (child === 0)) {
- if (child.write) {
- child.write(writer)
- } else if (typeof child === 'string') {
- writer(escapeXmlText(child))
- } else if (child.toString) {
- writer(escapeXmlText(child.toString(10)))
+function drainQueue() {
+ if (draining) {
+ return;
+ }
+ var timeout = runTimeout(cleanUpNextTick);
+ draining = true;
+
+ var len = queue.length;
+ while(len) {
+ currentQueue = queue;
+ queue = [];
+ while (++queueIndex < len) {
+ if (currentQueue) {
+ currentQueue[queueIndex].run();
}
}
+ queueIndex = -1;
+ len = queue.length;
}
- writer('</')
- writer(this.name)
- writer('>')
+ currentQueue = null;
+ draining = false;
+ runClearTimeout(timeout);
}
-Element.prototype.write = function(writer) {
- writer('<')
- writer(this.name)
- for (var k in this.attrs) {
- var v = this.attrs[k]
- if (v || (v === '') || (v === 0)) {
- writer(' ')
- writer(k)
- writer('="')
- if (typeof v !== 'string') {
- v = v.toString(10)
- }
- writer(escapeXml(v))
- writer('"')
+process.nextTick = function (fun) {
+ var args = new Array(arguments.length - 1);
+ if (arguments.length > 1) {
+ for (var i = 1; i < arguments.length; i++) {
+ args[i - 1] = arguments[i];
}
}
- if (this.children.length === 0) {
- writer('/>')
+ queue.push(new Item(fun, args));
+ if (queue.length === 1 && !draining) {
+ runTimeout(drainQueue);
+ }
+};
+
+// v8 likes predictible objects
+function Item(fun, array) {
+ this.fun = fun;
+ this.array = array;
+}
+Item.prototype.run = function () {
+ this.fun.apply(null, this.array);
+};
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+process.version = ''; // empty string to avoid regexp issues
+process.versions = {};
+
+function noop() {}
+
+process.on = noop;
+process.addListener = noop;
+process.once = noop;
+process.off = noop;
+process.removeListener = noop;
+process.removeAllListeners = noop;
+process.emit = noop;
+
+process.binding = function (name) {
+ throw new Error('process.binding is not supported');
+};
+
+process.cwd = function () { return '/' };
+process.chdir = function (dir) {
+ throw new Error('process.chdir is not supported');
+};
+process.umask = function() { return 0; };
+
+},{}],154:[function(require,module,exports){
+(function (global){
+/*! https://mths.be/punycode v1.4.1 by @mathias */
+;(function(root) {
+
+ /** Detect free variables */
+ var freeExports = typeof exports == 'object' && exports &&
+ !exports.nodeType && exports;
+ var freeModule = typeof module == 'object' && module &&
+ !module.nodeType && module;
+ var freeGlobal = typeof global == 'object' && global;
+ if (
+ freeGlobal.global === freeGlobal ||
+ freeGlobal.window === freeGlobal ||
+ freeGlobal.self === freeGlobal
+ ) {
+ root = freeGlobal;
+ }
+
+ /**
+ * The `punycode` object.
+ * @name punycode
+ * @type Object
+ */
+ var punycode,
+
+ /** Highest positive signed 32-bit float value */
+ maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+ /** Bootstring parameters */
+ base = 36,
+ tMin = 1,
+ tMax = 26,
+ skew = 38,
+ damp = 700,
+ initialBias = 72,
+ initialN = 128, // 0x80
+ delimiter = '-', // '\x2D'
+
+ /** Regular expressions */
+ regexPunycode = /^xn--/,
+ regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
+ regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
+
+ /** Error messages */
+ errors = {
+ 'overflow': 'Overflow: input needs wider integers to process',
+ 'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+ 'invalid-input': 'Invalid input'
+ },
+
+ /** Convenience shortcuts */
+ baseMinusTMin = base - tMin,
+ floor = Math.floor,
+ stringFromCharCode = String.fromCharCode,
+
+ /** Temporary variable */
+ key;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * A generic error utility function.
+ * @private
+ * @param {String} type The error type.
+ * @returns {Error} Throws a `RangeError` with the applicable error message.
+ */
+ function error(type) {
+ throw new RangeError(errors[type]);
+ }
+
+ /**
+ * A generic `Array#map` utility function.
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} callback The function that gets called for every array
+ * item.
+ * @returns {Array} A new array of values returned by the callback function.
+ */
+ function map(array, fn) {
+ var length = array.length;
+ var result = [];
+ while (length--) {
+ result[length] = fn(array[length]);
+ }
+ return result;
+ }
+
+ /**
+ * A simple `Array#map`-like wrapper to work with domain name strings or email
+ * addresses.
+ * @private
+ * @param {String} domain The domain name or email address.
+ * @param {Function} callback The function that gets called for every
+ * character.
+ * @returns {Array} A new string of characters returned by the callback
+ * function.
+ */
+ function mapDomain(string, fn) {
+ var parts = string.split('@');
+ var result = '';
+ if (parts.length > 1) {
+ // In email addresses, only the domain name should be punycoded. Leave
+ // the local part (i.e. everything up to `@`) intact.
+ result = parts[0] + '@';
+ string = parts[1];
+ }
+ // Avoid `split(regex)` for IE8 compatibility. See #17.
+ string = string.replace(regexSeparators, '\x2E');
+ var labels = string.split('.');
+ var encoded = map(labels, fn).join('.');
+ return result + encoded;
+ }
+
+ /**
+ * Creates an array containing the numeric code points of each Unicode
+ * character in the string. While JavaScript uses UCS-2 internally,
+ * this function will convert a pair of surrogate halves (each of which
+ * UCS-2 exposes as separate characters) into a single code point,
+ * matching UTF-16.
+ * @see `punycode.ucs2.encode`
+ * @see <https://mathiasbynens.be/notes/javascript-encoding>
+ * @memberOf punycode.ucs2
+ * @name decode
+ * @param {String} string The Unicode input string (UCS-2).
+ * @returns {Array} The new array of code points.
+ */
+ function ucs2decode(string) {
+ var output = [],
+ counter = 0,
+ length = string.length,
+ value,
+ extra;
+ while (counter < length) {
+ value = string.charCodeAt(counter++);
+ if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+ // high surrogate, and there is a next character
+ extra = string.charCodeAt(counter++);
+ if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+ output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+ } else {
+ // unmatched surrogate; only append this code unit, in case the next
+ // code unit is the high surrogate of a surrogate pair
+ output.push(value);
+ counter--;
+ }
+ } else {
+ output.push(value);
+ }
+ }
+ return output;
+ }
+
+ /**
+ * Creates a string based on an array of numeric code points.
+ * @see `punycode.ucs2.decode`
+ * @memberOf punycode.ucs2
+ * @name encode
+ * @param {Array} codePoints The array of numeric code points.
+ * @returns {String} The new Unicode string (UCS-2).
+ */
+ function ucs2encode(array) {
+ return map(array, function(value) {
+ var output = '';
+ if (value > 0xFFFF) {
+ value -= 0x10000;
+ output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+ value = 0xDC00 | value & 0x3FF;
+ }
+ output += stringFromCharCode(value);
+ return output;
+ }).join('');
+ }
+
+ /**
+ * Converts a basic code point into a digit/integer.
+ * @see `digitToBasic()`
+ * @private
+ * @param {Number} codePoint The basic numeric code point value.
+ * @returns {Number} The numeric value of a basic code point (for use in
+ * representing integers) in the range `0` to `base - 1`, or `base` if
+ * the code point does not represent a value.
+ */
+ function basicToDigit(codePoint) {
+ if (codePoint - 48 < 10) {
+ return codePoint - 22;
+ }
+ if (codePoint - 65 < 26) {
+ return codePoint - 65;
+ }
+ if (codePoint - 97 < 26) {
+ return codePoint - 97;
+ }
+ return base;
+ }
+
+ /**
+ * Converts a digit/integer into a basic code point.
+ * @see `basicToDigit()`
+ * @private
+ * @param {Number} digit The numeric value of a basic code point.
+ * @returns {Number} The basic code point whose value (when used for
+ * representing integers) is `digit`, which needs to be in the range
+ * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+ * used; else, the lowercase form is used. The behavior is undefined
+ * if `flag` is non-zero and `digit` has no uppercase form.
+ */
+ function digitToBasic(digit, flag) {
+ // 0..25 map to ASCII a..z or A..Z
+ // 26..35 map to ASCII 0..9
+ return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+ }
+
+ /**
+ * Bias adaptation function as per section 3.4 of RFC 3492.
+ * https://tools.ietf.org/html/rfc3492#section-3.4
+ * @private
+ */
+ function adapt(delta, numPoints, firstTime) {
+ var k = 0;
+ delta = firstTime ? floor(delta / damp) : delta >> 1;
+ delta += floor(delta / numPoints);
+ for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+ delta = floor(delta / baseMinusTMin);
+ }
+ return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+ }
+
+ /**
+ * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+ * symbols.
+ * @memberOf punycode
+ * @param {String} input The Punycode string of ASCII-only symbols.
+ * @returns {String} The resulting string of Unicode symbols.
+ */
+ function decode(input) {
+ // Don't use UCS-2
+ var output = [],
+ inputLength = input.length,
+ out,
+ i = 0,
+ n = initialN,
+ bias = initialBias,
+ basic,
+ j,
+ index,
+ oldi,
+ w,
+ k,
+ digit,
+ t,
+ /** Cached calculation results */
+ baseMinusT;
+
+ // Handle the basic code points: let `basic` be the number of input code
+ // points before the last delimiter, or `0` if there is none, then copy
+ // the first basic code points to the output.
+
+ basic = input.lastIndexOf(delimiter);
+ if (basic < 0) {
+ basic = 0;
+ }
+
+ for (j = 0; j < basic; ++j) {
+ // if it's not a basic code point
+ if (input.charCodeAt(j) >= 0x80) {
+ error('not-basic');
+ }
+ output.push(input.charCodeAt(j));
+ }
+
+ // Main decoding loop: start just after the last delimiter if any basic code
+ // points were copied; start at the beginning otherwise.
+
+ for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+ // `index` is the index of the next character to be consumed.
+ // Decode a generalized variable-length integer into `delta`,
+ // which gets added to `i`. The overflow checking is easier
+ // if we increase `i` as we go, then subtract off its starting
+ // value at the end to obtain `delta`.
+ for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+ if (index >= inputLength) {
+ error('invalid-input');
+ }
+
+ digit = basicToDigit(input.charCodeAt(index++));
+
+ if (digit >= base || digit > floor((maxInt - i) / w)) {
+ error('overflow');
+ }
+
+ i += digit * w;
+ t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+ if (digit < t) {
+ break;
+ }
+
+ baseMinusT = base - t;
+ if (w > floor(maxInt / baseMinusT)) {
+ error('overflow');
+ }
+
+ w *= baseMinusT;
+
+ }
+
+ out = output.length + 1;
+ bias = adapt(i - oldi, out, oldi == 0);
+
+ // `i` was supposed to wrap around from `out` to `0`,
+ // incrementing `n` each time, so we'll fix that now:
+ if (floor(i / out) > maxInt - n) {
+ error('overflow');
+ }
+
+ n += floor(i / out);
+ i %= out;
+
+ // Insert `n` at position `i` of the output
+ output.splice(i++, 0, n);
+
+ }
+
+ return ucs2encode(output);
+ }
+
+ /**
+ * Converts a string of Unicode symbols (e.g. a domain name label) to a
+ * Punycode string of ASCII-only symbols.
+ * @memberOf punycode
+ * @param {String} input The string of Unicode symbols.
+ * @returns {String} The resulting Punycode string of ASCII-only symbols.
+ */
+ function encode(input) {
+ var n,
+ delta,
+ handledCPCount,
+ basicLength,
+ bias,
+ j,
+ m,
+ q,
+ k,
+ t,
+ currentValue,
+ output = [],
+ /** `inputLength` will hold the number of code points in `input`. */
+ inputLength,
+ /** Cached calculation results */
+ handledCPCountPlusOne,
+ baseMinusT,
+ qMinusT;
+
+ // Convert the input in UCS-2 to Unicode
+ input = ucs2decode(input);
+
+ // Cache the length
+ inputLength = input.length;
+
+ // Initialize the state
+ n = initialN;
+ delta = 0;
+ bias = initialBias;
+
+ // Handle the basic code points
+ for (j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+ if (currentValue < 0x80) {
+ output.push(stringFromCharCode(currentValue));
+ }
+ }
+
+ handledCPCount = basicLength = output.length;
+
+ // `handledCPCount` is the number of code points that have been handled;
+ // `basicLength` is the number of basic code points.
+
+ // Finish the basic string - if it is not empty - with a delimiter
+ if (basicLength) {
+ output.push(delimiter);
+ }
+
+ // Main encoding loop:
+ while (handledCPCount < inputLength) {
+
+ // All non-basic code points < n have been handled already. Find the next
+ // larger one:
+ for (m = maxInt, j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+ if (currentValue >= n && currentValue < m) {
+ m = currentValue;
+ }
+ }
+
+ // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+ // but guard against overflow
+ handledCPCountPlusOne = handledCPCount + 1;
+ if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+ error('overflow');
+ }
+
+ delta += (m - n) * handledCPCountPlusOne;
+ n = m;
+
+ for (j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+
+ if (currentValue < n && ++delta > maxInt) {
+ error('overflow');
+ }
+
+ if (currentValue == n) {
+ // Represent delta as a generalized variable-length integer
+ for (q = delta, k = base; /* no condition */; k += base) {
+ t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+ if (q < t) {
+ break;
+ }
+ qMinusT = q - t;
+ baseMinusT = base - t;
+ output.push(
+ stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+ );
+ q = floor(qMinusT / baseMinusT);
+ }
+
+ output.push(stringFromCharCode(digitToBasic(q, 0)));
+ bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+ delta = 0;
+ ++handledCPCount;
+ }
+ }
+
+ ++delta;
+ ++n;
+
+ }
+ return output.join('');
+ }
+
+ /**
+ * Converts a Punycode string representing a domain name or an email address
+ * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
+ * it doesn't matter if you call it on a string that has already been
+ * converted to Unicode.
+ * @memberOf punycode
+ * @param {String} input The Punycoded domain name or email address to
+ * convert to Unicode.
+ * @returns {String} The Unicode representation of the given Punycode
+ * string.
+ */
+ function toUnicode(input) {
+ return mapDomain(input, function(string) {
+ return regexPunycode.test(string)
+ ? decode(string.slice(4).toLowerCase())
+ : string;
+ });
+ }
+
+ /**
+ * Converts a Unicode string representing a domain name or an email address to
+ * Punycode. Only the non-ASCII parts of the domain name will be converted,
+ * i.e. it doesn't matter if you call it with a domain that's already in
+ * ASCII.
+ * @memberOf punycode
+ * @param {String} input The domain name or email address to convert, as a
+ * Unicode string.
+ * @returns {String} The Punycode representation of the given domain name or
+ * email address.
+ */
+ function toASCII(input) {
+ return mapDomain(input, function(string) {
+ return regexNonASCII.test(string)
+ ? 'xn--' + encode(string)
+ : string;
+ });
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /** Define the public API */
+ punycode = {
+ /**
+ * A string representing the current Punycode.js version number.
+ * @memberOf punycode
+ * @type String
+ */
+ 'version': '1.4.1',
+ /**
+ * An object of methods to convert from JavaScript's internal character
+ * representation (UCS-2) to Unicode code points, and back.
+ * @see <https://mathiasbynens.be/notes/javascript-encoding>
+ * @memberOf punycode
+ * @type Object
+ */
+ 'ucs2': {
+ 'decode': ucs2decode,
+ 'encode': ucs2encode
+ },
+ 'decode': decode,
+ 'encode': encode,
+ 'toASCII': toASCII,
+ 'toUnicode': toUnicode
+ };
+
+ /** Expose `punycode` */
+ // Some AMD build optimizers, like r.js, check for specific condition patterns
+ // like the following:
+ if (
+ typeof define == 'function' &&
+ typeof define.amd == 'object' &&
+ define.amd
+ ) {
+ define('punycode', function() {
+ return punycode;
+ });
+ } else if (freeExports && freeModule) {
+ if (module.exports == freeExports) {
+ // in Node.js, io.js, or RingoJS v0.8.0+
+ freeModule.exports = punycode;
+ } else {
+ // in Narwhal or RingoJS v0.7.0-
+ for (key in punycode) {
+ punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+ }
+ }
+ } else {
+ // in Rhino or a web browser
+ root.punycode = punycode;
+ }
+
+}(this));
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}],155:[function(require,module,exports){
+module.exports = require("./lib/_stream_duplex.js")
+
+},{"./lib/_stream_duplex.js":156}],156:[function(require,module,exports){
+// a duplex stream is just a stream that is both readable and writable.
+// Since JS doesn't have multiple prototypal inheritance, this class
+// prototypally inherits from Readable, and then parasitically from
+// Writable.
+
+'use strict';
+
+/*<replacement>*/
+
+var objectKeys = Object.keys || function (obj) {
+ var keys = [];
+ for (var key in obj) {
+ keys.push(key);
+ }return keys;
+};
+/*</replacement>*/
+
+module.exports = Duplex;
+
+/*<replacement>*/
+var processNextTick = require('process-nextick-args');
+/*</replacement>*/
+
+/*<replacement>*/
+var util = require('core-util-is');
+util.inherits = require('inherits');
+/*</replacement>*/
+
+var Readable = require('./_stream_readable');
+var Writable = require('./_stream_writable');
+
+util.inherits(Duplex, Readable);
+
+var keys = objectKeys(Writable.prototype);
+for (var v = 0; v < keys.length; v++) {
+ var method = keys[v];
+ if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
+}
+
+function Duplex(options) {
+ if (!(this instanceof Duplex)) return new Duplex(options);
+
+ Readable.call(this, options);
+ Writable.call(this, options);
+
+ if (options && options.readable === false) this.readable = false;
+
+ if (options && options.writable === false) this.writable = false;
+
+ this.allowHalfOpen = true;
+ if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;
+
+ this.once('end', onend);
+}
+
+// the no-half-open enforcer
+function onend() {
+ // if we allow half-open state, or if the writable side ended,
+ // then we're ok.
+ if (this.allowHalfOpen || this._writableState.ended) return;
+
+ // no more data can be written.
+ // But allow more writes to happen in this tick.
+ processNextTick(onEndNT, this);
+}
+
+function onEndNT(self) {
+ self.end();
+}
+
+function forEach(xs, f) {
+ for (var i = 0, l = xs.length; i < l; i++) {
+ f(xs[i], i);
+ }
+}
+},{"./_stream_readable":158,"./_stream_writable":160,"core-util-is":22,"inherits":45,"process-nextick-args":152}],157:[function(require,module,exports){
+// a passthrough stream.
+// basically just the most minimal sort of Transform stream.
+// Every written chunk gets output as-is.
+
+'use strict';
+
+module.exports = PassThrough;
+
+var Transform = require('./_stream_transform');
+
+/*<replacement>*/
+var util = require('core-util-is');
+util.inherits = require('inherits');
+/*</replacement>*/
+
+util.inherits(PassThrough, Transform);
+
+function PassThrough(options) {
+ if (!(this instanceof PassThrough)) return new PassThrough(options);
+
+ Transform.call(this, options);
+}
+
+PassThrough.prototype._transform = function (chunk, encoding, cb) {
+ cb(null, chunk);
+};
+},{"./_stream_transform":159,"core-util-is":22,"inherits":45}],158:[function(require,module,exports){
+(function (process){
+'use strict';
+
+module.exports = Readable;
+
+/*<replacement>*/
+var processNextTick = require('process-nextick-args');
+/*</replacement>*/
+
+/*<replacement>*/
+var isArray = require('isarray');
+/*</replacement>*/
+
+Readable.ReadableState = ReadableState;
+
+/*<replacement>*/
+var EE = require('events').EventEmitter;
+
+var EElistenerCount = function (emitter, type) {
+ return emitter.listeners(type).length;
+};
+/*</replacement>*/
+
+/*<replacement>*/
+var Stream;
+(function () {
+ try {
+ Stream = require('st' + 'ream');
+ } catch (_) {} finally {
+ if (!Stream) Stream = require('events').EventEmitter;
+ }
+})();
+/*</replacement>*/
+
+var Buffer = require('buffer').Buffer;
+/*<replacement>*/
+var bufferShim = require('buffer-shims');
+/*</replacement>*/
+
+/*<replacement>*/
+var util = require('core-util-is');
+util.inherits = require('inherits');
+/*</replacement>*/
+
+/*<replacement>*/
+var debugUtil = require('util');
+var debug = void 0;
+if (debugUtil && debugUtil.debuglog) {
+ debug = debugUtil.debuglog('stream');
+} else {
+ debug = function () {};
+}
+/*</replacement>*/
+
+var BufferList = require('./internal/streams/BufferList');
+var StringDecoder;
+
+util.inherits(Readable, Stream);
+
+function prependListener(emitter, event, fn) {
+ if (typeof emitter.prependListener === 'function') {
+ return emitter.prependListener(event, fn);
+ } else {
+ // This is a hack to make sure that our error handler is attached before any
+ // userland ones. NEVER DO THIS. This is here only because this code needs
+ // to continue to work with older versions of Node.js that do not include
+ // the prependListener() method. The goal is to eventually remove this hack.
+ if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];
+ }
+}
+
+var Duplex;
+function ReadableState(options, stream) {
+ Duplex = Duplex || require('./_stream_duplex');
+
+ options = options || {};
+
+ // object stream flag. Used to make read(n) ignore n and to
+ // make all the buffer merging and length checks go away
+ this.objectMode = !!options.objectMode;
+
+ if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode;
+
+ // the point at which it stops calling _read() to fill the buffer
+ // Note: 0 is a valid value, means "don't call _read preemptively ever"
+ var hwm = options.highWaterMark;
+ var defaultHwm = this.objectMode ? 16 : 16 * 1024;
+ this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm;
+
+ // cast to ints.
+ this.highWaterMark = ~ ~this.highWaterMark;
+
+ // A linked list is used to store data chunks instead of an array because the
+ // linked list can remove elements from the beginning faster than
+ // array.shift()
+ this.buffer = new BufferList();
+ this.length = 0;
+ this.pipes = null;
+ this.pipesCount = 0;
+ this.flowing = null;
+ this.ended = false;
+ this.endEmitted = false;
+ this.reading = false;
+
+ // a flag to be able to tell if the onwrite cb is called immediately,
+ // or on a later tick. We set this to true at first, because any
+ // actions that shouldn't happen until "later" should generally also
+ // not happen before the first write call.
+ this.sync = true;
+
+ // whenever we return null, then we set a flag to say
+ // that we're awaiting a 'readable' event emission.
+ this.needReadable = false;
+ this.emittedReadable = false;
+ this.readableListening = false;
+ this.resumeScheduled = false;
+
+ // Crypto is kind of old and crusty. Historically, its default string
+ // encoding is 'binary' so we have to make this configurable.
+ // Everything else in the universe uses 'utf8', though.
+ this.defaultEncoding = options.defaultEncoding || 'utf8';
+
+ // when piping, we only care about 'readable' events that happen
+ // after read()ing all the bytes and not getting any pushback.
+ this.ranOut = false;
+
+ // the number of writers that are awaiting a drain event in .pipe()s
+ this.awaitDrain = 0;
+
+ // if true, a maybeReadMore has been scheduled
+ this.readingMore = false;
+
+ this.decoder = null;
+ this.encoding = null;
+ if (options.encoding) {
+ if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;
+ this.decoder = new StringDecoder(options.encoding);
+ this.encoding = options.encoding;
+ }
+}
+
+var Duplex;
+function Readable(options) {
+ Duplex = Duplex || require('./_stream_duplex');
+
+ if (!(this instanceof Readable)) return new Readable(options);
+
+ this._readableState = new ReadableState(options, this);
+
+ // legacy
+ this.readable = true;
+
+ if (options && typeof options.read === 'function') this._read = options.read;
+
+ Stream.call(this);
+}
+
+// Manually shove something into the read() buffer.
+// This returns true if the highWaterMark has not been hit yet,
+// similar to how Writable.write() returns true if you should
+// write() some more.
+Readable.prototype.push = function (chunk, encoding) {
+ var state = this._readableState;
+
+ if (!state.objectMode && typeof chunk === 'string') {
+ encoding = encoding || state.defaultEncoding;
+ if (encoding !== state.encoding) {
+ chunk = bufferShim.from(chunk, encoding);
+ encoding = '';
+ }
+ }
+
+ return readableAddChunk(this, state, chunk, encoding, false);
+};
+
+// Unshift should *always* be something directly out of read()
+Readable.prototype.unshift = function (chunk) {
+ var state = this._readableState;
+ return readableAddChunk(this, state, chunk, '', true);
+};
+
+Readable.prototype.isPaused = function () {
+ return this._readableState.flowing === false;
+};
+
+function readableAddChunk(stream, state, chunk, encoding, addToFront) {
+ var er = chunkInvalid(state, chunk);
+ if (er) {
+ stream.emit('error', er);
+ } else if (chunk === null) {
+ state.reading = false;
+ onEofChunk(stream, state);
+ } else if (state.objectMode || chunk && chunk.length > 0) {
+ if (state.ended && !addToFront) {
+ var e = new Error('stream.push() after EOF');
+ stream.emit('error', e);
+ } else if (state.endEmitted && addToFront) {
+ var _e = new Error('stream.unshift() after end event');
+ stream.emit('error', _e);
} else {
- this._addChildren(writer)
+ var skipAdd;
+ if (state.decoder && !addToFront && !encoding) {
+ chunk = state.decoder.write(chunk);
+ skipAdd = !state.objectMode && chunk.length === 0;
+ }
+
+ if (!addToFront) state.reading = false;
+
+ // Don't add to the buffer if we've decoded to an empty string chunk and
+ // we're not in object mode
+ if (!skipAdd) {
+ // if we want the data now, just emit it.
+ if (state.flowing && state.length === 0 && !state.sync) {
+ stream.emit('data', chunk);
+ stream.read(0);
+ } else {
+ // update the buffer info.
+ state.length += state.objectMode ? 1 : chunk.length;
+ if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);
+
+ if (state.needReadable) emitReadable(stream);
+ }
+ }
+
+ maybeReadMore(stream, state);
}
+ } else if (!addToFront) {
+ state.reading = false;
+ }
+
+ return needMoreData(state);
}
-function escapeXml(s) {
- return s.
- replace(/\&/g, '&amp;').
- replace(/</g, '&lt;').
- replace(/>/g, '&gt;').
- replace(/"/g, '&quot;').
- replace(/"/g, '&apos;')
+// if it's past the high water mark, we can push in some more.
+// Also, if we have no data yet, we can stand some
+// more bytes. This is to work around cases where hwm=0,
+// such as the repl. Also, if the push() triggered a
+// readable event, and the user called read(largeNumber) such that
+// needReadable was set, then we ought to push more, so that another
+// 'readable' event will be triggered.
+function needMoreData(state) {
+ return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0);
}
-function escapeXmlText(s) {
- return s.
- replace(/\&/g, '&amp;').
- replace(/</g, '&lt;').
- replace(/>/g, '&gt;')
+// backwards compatibility.
+Readable.prototype.setEncoding = function (enc) {
+ if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;
+ this._readableState.decoder = new StringDecoder(enc);
+ this._readableState.encoding = enc;
+ return this;
+};
+
+// Don't raise the hwm > 8MB
+var MAX_HWM = 0x800000;
+function computeNewHighWaterMark(n) {
+ if (n >= MAX_HWM) {
+ n = MAX_HWM;
+ } else {
+ // Get the next highest power of 2 to prevent increasing hwm excessively in
+ // tiny amounts
+ n--;
+ n |= n >>> 1;
+ n |= n >>> 2;
+ n |= n >>> 4;
+ n |= n >>> 8;
+ n |= n >>> 16;
+ n++;
+ }
+ return n;
}
-exports.Element = Element
-exports.escapeXml = escapeXml
+// This function is designed to be inlinable, so please take care when making
+// changes to the function body.
+function howMuchToRead(n, state) {
+ if (n <= 0 || state.length === 0 && state.ended) return 0;
+ if (state.objectMode) return 1;
+ if (n !== n) {
+ // Only flow one buffer at a time
+ if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;
+ }
+ // If we're asking for more than the current hwm, then raise the hwm.
+ if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);
+ if (n <= state.length) return n;
+ // Don't have enough
+ if (!state.ended) {
+ state.needReadable = true;
+ return 0;
+ }
+ return state.length;
+}
+
+// you can override either this method, or the async _read(n) below.
+Readable.prototype.read = function (n) {
+ debug('read', n);
+ n = parseInt(n, 10);
+ var state = this._readableState;
+ var nOrig = n;
+
+ if (n !== 0) state.emittedReadable = false;
+
+ // if we're doing read(0) to trigger a readable event, but we
+ // already have a bunch of data in the buffer, then just trigger
+ // the 'readable' event and move on.
+ if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) {
+ debug('read: emitReadable', state.length, state.ended);
+ if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);
+ return null;
+ }
+
+ n = howMuchToRead(n, state);
+
+ // if we've ended, and we're now clear, then finish it up.
+ if (n === 0 && state.ended) {
+ if (state.length === 0) endReadable(this);
+ return null;
+ }
+
+ // All the actual chunk generation logic needs to be
+ // *below* the call to _read. The reason is that in certain
+ // synthetic stream cases, such as passthrough streams, _read
+ // may be a completely synchronous operation which may change
+ // the state of the read buffer, providing enough data when
+ // before there was *not* enough.
+ //
+ // So, the steps are:
+ // 1. Figure out what the state of things will be after we do
+ // a read from the buffer.
+ //
+ // 2. If that resulting state will trigger a _read, then call _read.
+ // Note that this may be asynchronous, or synchronous. Yes, it is
+ // deeply ugly to write APIs this way, but that still doesn't mean
+ // that the Readable class should behave improperly, as streams are
+ // designed to be sync/async agnostic.
+ // Take note if the _read call is sync or async (ie, if the read call
+ // has returned yet), so that we know whether or not it's safe to emit
+ // 'readable' etc.
+ //
+ // 3. Actually pull the requested chunks out of the buffer and return.
+
+ // if we need a readable event, then we need to do some reading.
+ var doRead = state.needReadable;
+ debug('need readable', doRead);
+
+ // if we currently have less than the highWaterMark, then also read some
+ if (state.length === 0 || state.length - n < state.highWaterMark) {
+ doRead = true;
+ debug('length less than watermark', doRead);
+ }
+
+ // however, if we've ended, then there's no point, and if we're already
+ // reading, then it's unnecessary.
+ if (state.ended || state.reading) {
+ doRead = false;
+ debug('reading or ended', doRead);
+ } else if (doRead) {
+ debug('do read');
+ state.reading = true;
+ state.sync = true;
+ // if the length is currently zero, then we *need* a readable event.
+ if (state.length === 0) state.needReadable = true;
+ // call internal read method
+ this._read(state.highWaterMark);
+ state.sync = false;
+ // If _read pushed data synchronously, then `reading` will be false,
+ // and we need to re-evaluate how much data we can return to the user.
+ if (!state.reading) n = howMuchToRead(nOrig, state);
+ }
+
+ var ret;
+ if (n > 0) ret = fromList(n, state);else ret = null;
+
+ if (ret === null) {
+ state.needReadable = true;
+ n = 0;
+ } else {
+ state.length -= n;
+ }
+
+ if (state.length === 0) {
+ // If we have nothing in the buffer, then we want to know
+ // as soon as we *do* get something into the buffer.
+ if (!state.ended) state.needReadable = true;
+
+ // If we tried to read() past the EOF, then emit end on the next tick.
+ if (nOrig !== n && state.ended) endReadable(this);
+ }
+
+ if (ret !== null) this.emit('data', ret);
+
+ return ret;
+};
+
+function chunkInvalid(state, chunk) {
+ var er = null;
+ if (!Buffer.isBuffer(chunk) && typeof chunk !== 'string' && chunk !== null && chunk !== undefined && !state.objectMode) {
+ er = new TypeError('Invalid non-string/buffer chunk');
+ }
+ return er;
+}
+
+function onEofChunk(stream, state) {
+ if (state.ended) return;
+ if (state.decoder) {
+ var chunk = state.decoder.end();
+ if (chunk && chunk.length) {
+ state.buffer.push(chunk);
+ state.length += state.objectMode ? 1 : chunk.length;
+ }
+ }
+ state.ended = true;
+
+ // emit 'readable' now to make sure it gets picked up.
+ emitReadable(stream);
+}
+
+// Don't emit readable right away in sync mode, because this can trigger
+// another read() call => stack overflow. This way, it might trigger
+// a nextTick recursion warning, but that's not so bad.
+function emitReadable(stream) {
+ var state = stream._readableState;
+ state.needReadable = false;
+ if (!state.emittedReadable) {
+ debug('emitReadable', state.flowing);
+ state.emittedReadable = true;
+ if (state.sync) processNextTick(emitReadable_, stream);else emitReadable_(stream);
+ }
+}
+
+function emitReadable_(stream) {
+ debug('emit readable');
+ stream.emit('readable');
+ flow(stream);
+}
+
+// at this point, the user has presumably seen the 'readable' event,
+// and called read() to consume some data. that may have triggered
+// in turn another _read(n) call, in which case reading = true if
+// it's in progress.
+// However, if we're not ended, or reading, and the length < hwm,
+// then go ahead and try to read some more preemptively.
+function maybeReadMore(stream, state) {
+ if (!state.readingMore) {
+ state.readingMore = true;
+ processNextTick(maybeReadMore_, stream, state);
+ }
+}
+
+function maybeReadMore_(stream, state) {
+ var len = state.length;
+ while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) {
+ debug('maybeReadMore read 0');
+ stream.read(0);
+ if (len === state.length)
+ // didn't get any data, stop spinning.
+ break;else len = state.length;
+ }
+ state.readingMore = false;
+}
+
+// abstract method. to be overridden in specific implementation classes.
+// call cb(er, data) where data is <= n in length.
+// for virtual (non-string, non-buffer) streams, "length" is somewhat
+// arbitrary, and perhaps not very meaningful.
+Readable.prototype._read = function (n) {
+ this.emit('error', new Error('not implemented'));
+};
+
+Readable.prototype.pipe = function (dest, pipeOpts) {
+ var src = this;
+ var state = this._readableState;
+
+ switch (state.pipesCount) {
+ case 0:
+ state.pipes = dest;
+ break;
+ case 1:
+ state.pipes = [state.pipes, dest];
+ break;
+ default:
+ state.pipes.push(dest);
+ break;
+ }
+ state.pipesCount += 1;
+ debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);
+
+ var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr;
+
+ var endFn = doEnd ? onend : cleanup;
+ if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn);
+
+ dest.on('unpipe', onunpipe);
+ function onunpipe(readable) {
+ debug('onunpipe');
+ if (readable === src) {
+ cleanup();
+ }
+ }
+
+ function onend() {
+ debug('onend');
+ dest.end();
+ }
+
+ // when the dest drains, it reduces the awaitDrain counter
+ // on the source. This would be more elegant with a .once()
+ // handler in flow(), but adding and removing repeatedly is
+ // too slow.
+ var ondrain = pipeOnDrain(src);
+ dest.on('drain', ondrain);
+
+ var cleanedUp = false;
+ function cleanup() {
+ debug('cleanup');
+ // cleanup event handlers once the pipe is broken
+ dest.removeListener('close', onclose);
+ dest.removeListener('finish', onfinish);
+ dest.removeListener('drain', ondrain);
+ dest.removeListener('error', onerror);
+ dest.removeListener('unpipe', onunpipe);
+ src.removeListener('end', onend);
+ src.removeListener('end', cleanup);
+ src.removeListener('data', ondata);
+
+ cleanedUp = true;
+
+ // if the reader is waiting for a drain event from this
+ // specific writer, then it would cause it to never start
+ // flowing again.
+ // So, if this is awaiting a drain, then we just call it now.
+ // If we don't know, then assume that we are waiting for one.
+ if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();
+ }
+
+ // If the user pushes more data while we're writing to dest then we'll end up
+ // in ondata again. However, we only want to increase awaitDrain once because
+ // dest will only emit one 'drain' event for the multiple writes.
+ // => Introduce a guard on increasing awaitDrain.
+ var increasedAwaitDrain = false;
+ src.on('data', ondata);
+ function ondata(chunk) {
+ debug('ondata');
+ increasedAwaitDrain = false;
+ var ret = dest.write(chunk);
+ if (false === ret && !increasedAwaitDrain) {
+ // If the user unpiped during `dest.write()`, it is possible
+ // to get stuck in a permanently paused state if that write
+ // also returned false.
+ // => Check whether `dest` is still a piping destination.
+ if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {
+ debug('false write response, pause', src._readableState.awaitDrain);
+ src._readableState.awaitDrain++;
+ increasedAwaitDrain = true;
+ }
+ src.pause();
+ }
+ }
+
+ // if the dest has an error, then stop piping into it.
+ // however, don't suppress the throwing behavior for this.
+ function onerror(er) {
+ debug('onerror', er);
+ unpipe();
+ dest.removeListener('error', onerror);
+ if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er);
+ }
+
+ // Make sure our error handler is attached before userland ones.
+ prependListener(dest, 'error', onerror);
+
+ // Both close and finish should trigger unpipe, but only once.
+ function onclose() {
+ dest.removeListener('finish', onfinish);
+ unpipe();
+ }
+ dest.once('close', onclose);
+ function onfinish() {
+ debug('onfinish');
+ dest.removeListener('close', onclose);
+ unpipe();
+ }
+ dest.once('finish', onfinish);
+
+ function unpipe() {
+ debug('unpipe');
+ src.unpipe(dest);
+ }
+
+ // tell the dest that it's being piped to
+ dest.emit('pipe', src);
+
+ // start the flow if it hasn't been started already.
+ if (!state.flowing) {
+ debug('pipe resume');
+ src.resume();
+ }
+
+ return dest;
+};
+
+function pipeOnDrain(src) {
+ return function () {
+ var state = src._readableState;
+ debug('pipeOnDrain', state.awaitDrain);
+ if (state.awaitDrain) state.awaitDrain--;
+ if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {
+ state.flowing = true;
+ flow(src);
+ }
+ };
+}
+
+Readable.prototype.unpipe = function (dest) {
+ var state = this._readableState;
+
+ // if we're not piping anywhere, then do nothing.
+ if (state.pipesCount === 0) return this;
+
+ // just one destination. most common case.
+ if (state.pipesCount === 1) {
+ // passed in one, but it's not the right one.
+ if (dest && dest !== state.pipes) return this;
+
+ if (!dest) dest = state.pipes;
+
+ // got a match.
+ state.pipes = null;
+ state.pipesCount = 0;
+ state.flowing = false;
+ if (dest) dest.emit('unpipe', this);
+ return this;
+ }
+
+ // slow case. multiple pipe destinations.
+
+ if (!dest) {
+ // remove all.
+ var dests = state.pipes;
+ var len = state.pipesCount;
+ state.pipes = null;
+ state.pipesCount = 0;
+ state.flowing = false;
+
+ for (var _i = 0; _i < len; _i++) {
+ dests[_i].emit('unpipe', this);
+ }return this;
+ }
+
+ // try to find the right one.
+ var i = indexOf(state.pipes, dest);
+ if (i === -1) return this;
+
+ state.pipes.splice(i, 1);
+ state.pipesCount -= 1;
+ if (state.pipesCount === 1) state.pipes = state.pipes[0];
+
+ dest.emit('unpipe', this);
+
+ return this;
+};
+
+// set up data events if they are asked for
+// Ensure readable listeners eventually get something
+Readable.prototype.on = function (ev, fn) {
+ var res = Stream.prototype.on.call(this, ev, fn);
+
+ if (ev === 'data') {
+ // Start flowing on next tick if stream isn't explicitly paused
+ if (this._readableState.flowing !== false) this.resume();
+ } else if (ev === 'readable') {
+ var state = this._readableState;
+ if (!state.endEmitted && !state.readableListening) {
+ state.readableListening = state.needReadable = true;
+ state.emittedReadable = false;
+ if (!state.reading) {
+ processNextTick(nReadingNextTick, this);
+ } else if (state.length) {
+ emitReadable(this, state);
+ }
+ }
+ }
+
+ return res;
+};
+Readable.prototype.addListener = Readable.prototype.on;
+
+function nReadingNextTick(self) {
+ debug('readable nexttick read 0');
+ self.read(0);
+}
+
+// pause() and resume() are remnants of the legacy readable stream API
+// If the user uses them, then switch into old mode.
+Readable.prototype.resume = function () {
+ var state = this._readableState;
+ if (!state.flowing) {
+ debug('resume');
+ state.flowing = true;
+ resume(this, state);
+ }
+ return this;
+};
+
+function resume(stream, state) {
+ if (!state.resumeScheduled) {
+ state.resumeScheduled = true;
+ processNextTick(resume_, stream, state);
+ }
+}
+
+function resume_(stream, state) {
+ if (!state.reading) {
+ debug('resume read 0');
+ stream.read(0);
+ }
+
+ state.resumeScheduled = false;
+ state.awaitDrain = 0;
+ stream.emit('resume');
+ flow(stream);
+ if (state.flowing && !state.reading) stream.read(0);
+}
+
+Readable.prototype.pause = function () {
+ debug('call pause flowing=%j', this._readableState.flowing);
+ if (false !== this._readableState.flowing) {
+ debug('pause');
+ this._readableState.flowing = false;
+ this.emit('pause');
+ }
+ return this;
+};
+
+function flow(stream) {
+ var state = stream._readableState;
+ debug('flow', state.flowing);
+ while (state.flowing && stream.read() !== null) {}
+}
+
+// wrap an old-style stream as the async data source.
+// This is *not* part of the readable stream interface.
+// It is an ugly unfortunate mess of history.
+Readable.prototype.wrap = function (stream) {
+ var state = this._readableState;
+ var paused = false;
+
+ var self = this;
+ stream.on('end', function () {
+ debug('wrapped end');
+ if (state.decoder && !state.ended) {
+ var chunk = state.decoder.end();
+ if (chunk && chunk.length) self.push(chunk);
+ }
+
+ self.push(null);
+ });
+
+ stream.on('data', function (chunk) {
+ debug('wrapped data');
+ if (state.decoder) chunk = state.decoder.write(chunk);
+
+ // don't skip over falsy values in objectMode
+ if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;
+
+ var ret = self.push(chunk);
+ if (!ret) {
+ paused = true;
+ stream.pause();
+ }
+ });
+
+ // proxy all the other methods.
+ // important when wrapping filters and duplexes.
+ for (var i in stream) {
+ if (this[i] === undefined && typeof stream[i] === 'function') {
+ this[i] = function (method) {
+ return function () {
+ return stream[method].apply(stream, arguments);
+ };
+ }(i);
+ }
+ }
+
+ // proxy certain important events.
+ var events = ['error', 'close', 'destroy', 'pause', 'resume'];
+ forEach(events, function (ev) {
+ stream.on(ev, self.emit.bind(self, ev));
+ });
+
+ // when we try to consume some more bytes, simply unpause the
+ // underlying stream.
+ self._read = function (n) {
+ debug('wrapped _read', n);
+ if (paused) {
+ paused = false;
+ stream.resume();
+ }
+ };
+
+ return self;
+};
+
+// exposed for testing purposes only.
+Readable._fromList = fromList;
+
+// Pluck off n bytes from an array of buffers.
+// Length is the combined lengths of all the buffers in the list.
+// This function is designed to be inlinable, so please take care when making
+// changes to the function body.
+function fromList(n, state) {
+ // nothing buffered
+ if (state.length === 0) return null;
+
+ var ret;
+ if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {
+ // read it all, truncate the list
+ if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length);
+ state.buffer.clear();
+ } else {
+ // read part of list
+ ret = fromListPartial(n, state.buffer, state.decoder);
+ }
+
+ return ret;
+}
+
+// Extracts only enough buffered data to satisfy the amount requested.
+// This function is designed to be inlinable, so please take care when making
+// changes to the function body.
+function fromListPartial(n, list, hasStrings) {
+ var ret;
+ if (n < list.head.data.length) {
+ // slice is the same for buffers and strings
+ ret = list.head.data.slice(0, n);
+ list.head.data = list.head.data.slice(n);
+ } else if (n === list.head.data.length) {
+ // first chunk is a perfect match
+ ret = list.shift();
+ } else {
+ // result spans more than one buffer
+ ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list);
+ }
+ return ret;
+}
+
+// Copies a specified amount of characters from the list of buffered data
+// chunks.
+// This function is designed to be inlinable, so please take care when making
+// changes to the function body.
+function copyFromBufferString(n, list) {
+ var p = list.head;
+ var c = 1;
+ var ret = p.data;
+ n -= ret.length;
+ while (p = p.next) {
+ var str = p.data;
+ var nb = n > str.length ? str.length : n;
+ if (nb === str.length) ret += str;else ret += str.slice(0, n);
+ n -= nb;
+ if (n === 0) {
+ if (nb === str.length) {
+ ++c;
+ if (p.next) list.head = p.next;else list.head = list.tail = null;
+ } else {
+ list.head = p;
+ p.data = str.slice(nb);
+ }
+ break;
+ }
+ ++c;
+ }
+ list.length -= c;
+ return ret;
+}
+
+// Copies a specified amount of bytes from the list of buffered data chunks.
+// This function is designed to be inlinable, so please take care when making
+// changes to the function body.
+function copyFromBuffer(n, list) {
+ var ret = bufferShim.allocUnsafe(n);
+ var p = list.head;
+ var c = 1;
+ p.data.copy(ret);
+ n -= p.data.length;
+ while (p = p.next) {
+ var buf = p.data;
+ var nb = n > buf.length ? buf.length : n;
+ buf.copy(ret, ret.length - n, 0, nb);
+ n -= nb;
+ if (n === 0) {
+ if (nb === buf.length) {
+ ++c;
+ if (p.next) list.head = p.next;else list.head = list.tail = null;
+ } else {
+ list.head = p;
+ p.data = buf.slice(nb);
+ }
+ break;
+ }
+ ++c;
+ }
+ list.length -= c;
+ return ret;
+}
+
+function endReadable(stream) {
+ var state = stream._readableState;
+
+ // If we get here before consuming all the bytes, then that is a
+ // bug in node. Should never happen.
+ if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream');
+
+ if (!state.endEmitted) {
+ state.ended = true;
+ processNextTick(endReadableNT, state, stream);
+ }
+}
+
+function endReadableNT(state, stream) {
+ // Check that we didn't get one last unshift.
+ if (!state.endEmitted && state.length === 0) {
+ state.endEmitted = true;
+ stream.readable = false;
+ stream.emit('end');
+ }
+}
+
+function forEach(xs, f) {
+ for (var i = 0, l = xs.length; i < l; i++) {
+ f(xs[i], i);
+ }
+}
+
+function indexOf(xs, x) {
+ for (var i = 0, l = xs.length; i < l; i++) {
+ if (xs[i] === x) return i;
+ }
+ return -1;
+}
+}).call(this,require('_process'))
+},{"./_stream_duplex":156,"./internal/streams/BufferList":161,"_process":153,"buffer":6,"buffer-shims":5,"core-util-is":22,"events":27,"inherits":45,"isarray":48,"process-nextick-args":152,"string_decoder/":183,"util":4}],159:[function(require,module,exports){
+// a transform stream is a readable/writable stream where you do
+// something with the data. Sometimes it's called a "filter",
+// but that's not a great name for it, since that implies a thing where
+// some bits pass through, and others are simply ignored. (That would
+// be a valid example of a transform, of course.)
+//
+// While the output is causally related to the input, it's not a
+// necessarily symmetric or synchronous transformation. For example,
+// a zlib stream might take multiple plain-text writes(), and then
+// emit a single compressed chunk some time in the future.
+//
+// Here's how this works:
+//
+// The Transform stream has all the aspects of the readable and writable
+// stream classes. When you write(chunk), that calls _write(chunk,cb)
+// internally, and returns false if there's a lot of pending writes
+// buffered up. When you call read(), that calls _read(n) until
+// there's enough pending readable data buffered up.
+//
+// In a transform stream, the written data is placed in a buffer. When
+// _read(n) is called, it transforms the queued up data, calling the
+// buffered _write cb's as it consumes chunks. If consuming a single
+// written chunk would result in multiple output chunks, then the first
+// outputted bit calls the readcb, and subsequent chunks just go into
+// the read buffer, and will cause it to emit 'readable' if necessary.
+//
+// This way, back-pressure is actually determined by the reading side,
+// since _read has to be called to start processing a new chunk. However,
+// a pathological inflate type of transform can cause excessive buffering
+// here. For example, imagine a stream where every byte of input is
+// interpreted as an integer from 0-255, and then results in that many
+// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in
+// 1kb of data being output. In this case, you could write a very small
+// amount of input, and end up with a very large amount of output. In
+// such a pathological inflating mechanism, there'd be no way to tell
+// the system to stop doing the transform. A single 4MB write could
+// cause the system to run out of memory.
+//
+// However, even in such a pathological case, only a single written chunk
+// would be consumed, and then the rest would wait (un-transformed) until
+// the results of the previous transformed chunk were consumed.
-},{}],245:[function(require,module,exports){
'use strict';
-/* Cause browserify to bundle SAX parsers: */
-var parse = require('./parse')
+module.exports = Transform;
+
+var Duplex = require('./_stream_duplex');
+
+/*<replacement>*/
+var util = require('core-util-is');
+util.inherits = require('inherits');
+/*</replacement>*/
+
+util.inherits(Transform, Duplex);
+
+function TransformState(stream) {
+ this.afterTransform = function (er, data) {
+ return afterTransform(stream, er, data);
+ };
+
+ this.needTransform = false;
+ this.transforming = false;
+ this.writecb = null;
+ this.writechunk = null;
+ this.writeencoding = null;
+}
+
+function afterTransform(stream, er, data) {
+ var ts = stream._transformState;
+ ts.transforming = false;
+
+ var cb = ts.writecb;
+
+ if (!cb) return stream.emit('error', new Error('no writecb in Transform class'));
+
+ ts.writechunk = null;
+ ts.writecb = null;
+
+ if (data !== null && data !== undefined) stream.push(data);
+
+ cb(er);
+
+ var rs = stream._readableState;
+ rs.reading = false;
+ if (rs.needReadable || rs.length < rs.highWaterMark) {
+ stream._read(rs.highWaterMark);
+ }
+}
+
+function Transform(options) {
+ if (!(this instanceof Transform)) return new Transform(options);
+
+ Duplex.call(this, options);
+
+ this._transformState = new TransformState(this);
+
+ // when the writable side finishes, then flush out anything remaining.
+ var stream = this;
+
+ // start out asking for a readable event once data is transformed.
+ this._readableState.needReadable = true;
+
+ // we have implemented the _read method, and done the other things
+ // that Readable wants before the first _read call, so unset the
+ // sync guard flag.
+ this._readableState.sync = false;
+
+ if (options) {
+ if (typeof options.transform === 'function') this._transform = options.transform;
+
+ if (typeof options.flush === 'function') this._flush = options.flush;
+ }
+
+ this.once('prefinish', function () {
+ if (typeof this._flush === 'function') this._flush(function (er) {
+ done(stream, er);
+ });else done(stream);
+ });
+}
+
+Transform.prototype.push = function (chunk, encoding) {
+ this._transformState.needTransform = false;
+ return Duplex.prototype.push.call(this, chunk, encoding);
+};
+
+// This is the part where you do stuff!
+// override this function in implementation classes.
+// 'chunk' is an input chunk.
+//
+// Call `push(newChunk)` to pass along transformed output
+// to the readable side. You may call 'push' zero or more times.
+//
+// Call `cb(err)` when you are done with this chunk. If you pass
+// an error, then that'll put the hurt on the whole operation. If you
+// never call cb(), then you'll never get another chunk.
+Transform.prototype._transform = function (chunk, encoding, cb) {
+ throw new Error('Not implemented');
+};
+
+Transform.prototype._write = function (chunk, encoding, cb) {
+ var ts = this._transformState;
+ ts.writecb = cb;
+ ts.writechunk = chunk;
+ ts.writeencoding = encoding;
+ if (!ts.transforming) {
+ var rs = this._readableState;
+ if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);
+ }
+};
+
+// Doesn't matter what the args are here.
+// _transform does all the work.
+// That we got here means that the readable side wants more data.
+Transform.prototype._read = function (n) {
+ var ts = this._transformState;
+
+ if (ts.writechunk !== null && ts.writecb && !ts.transforming) {
+ ts.transforming = true;
+ this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);
+ } else {
+ // mark that we need a transform, so that any data that comes in
+ // will get processed, now that we've asked for it.
+ ts.needTransform = true;
+ }
+};
+
+function done(stream, er) {
+ if (er) return stream.emit('error', er);
+
+ // if there's nothing in the write buffer, then that means
+ // that nothing more will ever be provided
+ var ws = stream._writableState;
+ var ts = stream._transformState;
+
+ if (ws.length) throw new Error('Calling transform done when ws.length != 0');
-parse.availableSaxParsers.push(parse.bestSaxParser = require('./sax/sax_ltx'))
+ if (ts.transforming) throw new Error('Calling transform done when still transforming');
+
+ return stream.push(null);
+}
+},{"./_stream_duplex":156,"core-util-is":22,"inherits":45}],160:[function(require,module,exports){
+(function (process){
+// A bit simpler than readable streams.
+// Implement an async ._write(chunk, encoding, cb), and it'll handle all
+// the drain event emission and buffering.
-/* SHIM */
-module.exports = require('./index')
-},{"./index":246,"./parse":247,"./sax/sax_ltx":248}],246:[function(require,module,exports){
'use strict';
-var parse = require('./parse')
+module.exports = Writable;
+
+/*<replacement>*/
+var processNextTick = require('process-nextick-args');
+/*</replacement>*/
+
+/*<replacement>*/
+var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick;
+/*</replacement>*/
+
+Writable.WritableState = WritableState;
+
+/*<replacement>*/
+var util = require('core-util-is');
+util.inherits = require('inherits');
+/*</replacement>*/
+
+/*<replacement>*/
+var internalUtil = {
+ deprecate: require('util-deprecate')
+};
+/*</replacement>*/
+
+/*<replacement>*/
+var Stream;
+(function () {
+ try {
+ Stream = require('st' + 'ream');
+ } catch (_) {} finally {
+ if (!Stream) Stream = require('events').EventEmitter;
+ }
+})();
+/*</replacement>*/
+
+var Buffer = require('buffer').Buffer;
+/*<replacement>*/
+var bufferShim = require('buffer-shims');
+/*</replacement>*/
+
+util.inherits(Writable, Stream);
+
+function nop() {}
+
+function WriteReq(chunk, encoding, cb) {
+ this.chunk = chunk;
+ this.encoding = encoding;
+ this.callback = cb;
+ this.next = null;
+}
+
+var Duplex;
+function WritableState(options, stream) {
+ Duplex = Duplex || require('./_stream_duplex');
+
+ options = options || {};
+
+ // object stream flag to indicate whether or not this stream
+ // contains buffers or objects.
+ this.objectMode = !!options.objectMode;
+
+ if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode;
+
+ // the point at which write() starts returning false
+ // Note: 0 is a valid value, means that we always return false if
+ // the entire buffer is not flushed immediately on write()
+ var hwm = options.highWaterMark;
+ var defaultHwm = this.objectMode ? 16 : 16 * 1024;
+ this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm;
+
+ // cast to ints.
+ this.highWaterMark = ~ ~this.highWaterMark;
+
+ this.needDrain = false;
+ // at the start of calling end()
+ this.ending = false;
+ // when end() has been called, and returned
+ this.ended = false;
+ // when 'finish' is emitted
+ this.finished = false;
+
+ // should we decode strings into buffers before passing to _write?
+ // this is here so that some node-core streams can optimize string
+ // handling at a lower level.
+ var noDecode = options.decodeStrings === false;
+ this.decodeStrings = !noDecode;
+
+ // Crypto is kind of old and crusty. Historically, its default string
+ // encoding is 'binary' so we have to make this configurable.
+ // Everything else in the universe uses 'utf8', though.
+ this.defaultEncoding = options.defaultEncoding || 'utf8';
+
+ // not an actual buffer we keep track of, but a measurement
+ // of how much we're waiting to get pushed to some underlying
+ // socket or file.
+ this.length = 0;
+
+ // a flag to see when we're in the middle of a write.
+ this.writing = false;
+
+ // when true all writes will be buffered until .uncork() call
+ this.corked = 0;
+
+ // a flag to be able to tell if the onwrite cb is called immediately,
+ // or on a later tick. We set this to true at first, because any
+ // actions that shouldn't happen until "later" should generally also
+ // not happen before the first write call.
+ this.sync = true;
+
+ // a flag to know if we're processing previously buffered items, which
+ // may call the _write() callback in the same tick, so that we don't
+ // end up in an overlapped onwrite situation.
+ this.bufferProcessing = false;
+
+ // the callback that's passed to _write(chunk,cb)
+ this.onwrite = function (er) {
+ onwrite(stream, er);
+ };
+
+ // the callback that the user supplies to write(chunk,encoding,cb)
+ this.writecb = null;
+
+ // the amount that is being written when _write is called.
+ this.writelen = 0;
+
+ this.bufferedRequest = null;
+ this.lastBufferedRequest = null;
+
+ // number of pending user-supplied write callbacks
+ // this must be 0 before 'finish' can be emitted
+ this.pendingcb = 0;
+
+ // emit prefinish if the only thing we're waiting for is _write cbs
+ // This is relevant for synchronous Transform streams
+ this.prefinished = false;
+
+ // True if the error was already emitted and should not be thrown again
+ this.errorEmitted = false;
+
+ // count buffered requests
+ this.bufferedRequestCount = 0;
+
+ // allocate the first CorkedRequest, there is always
+ // one allocated and free to use, and we maintain at most two
+ this.corkedRequestsFree = new CorkedRequest(this);
+}
+
+WritableState.prototype.getBuffer = function writableStateGetBuffer() {
+ var current = this.bufferedRequest;
+ var out = [];
+ while (current) {
+ out.push(current);
+ current = current.next;
+ }
+ return out;
+};
+
+(function () {
+ try {
+ Object.defineProperty(WritableState.prototype, 'buffer', {
+ get: internalUtil.deprecate(function () {
+ return this.getBuffer();
+ }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.')
+ });
+ } catch (_) {}
+})();
+
+var Duplex;
+function Writable(options) {
+ Duplex = Duplex || require('./_stream_duplex');
+
+ // Writable ctor is applied to Duplexes, though they're not
+ // instanceof Writable, they're instanceof Readable.
+ if (!(this instanceof Writable) && !(this instanceof Duplex)) return new Writable(options);
+
+ this._writableState = new WritableState(options, this);
+
+ // legacy.
+ this.writable = true;
+
+ if (options) {
+ if (typeof options.write === 'function') this._write = options.write;
+
+ if (typeof options.writev === 'function') this._writev = options.writev;
+ }
+
+ Stream.call(this);
+}
+
+// Otherwise people can pipe Writable streams, which is just wrong.
+Writable.prototype.pipe = function () {
+ this.emit('error', new Error('Cannot pipe, not readable'));
+};
+
+function writeAfterEnd(stream, cb) {
+ var er = new Error('write after end');
+ // TODO: defer error events consistently everywhere, not just the cb
+ stream.emit('error', er);
+ processNextTick(cb, er);
+}
+
+// If we get something that is not a buffer, string, null, or undefined,
+// and we're not in objectMode, then that's an error.
+// Otherwise stream chunks are all considered to be of length=1, and the
+// watermarks determine how many objects to keep in the buffer, rather than
+// how many bytes or characters.
+function validChunk(stream, state, chunk, cb) {
+ var valid = true;
+ var er = false;
+ // Always throw error if a null is written
+ // if we are not in object mode then throw
+ // if it is not a buffer, string, or undefined.
+ if (chunk === null) {
+ er = new TypeError('May not write null values to stream');
+ } else if (!Buffer.isBuffer(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {
+ er = new TypeError('Invalid non-string/buffer chunk');
+ }
+ if (er) {
+ stream.emit('error', er);
+ processNextTick(cb, er);
+ valid = false;
+ }
+ return valid;
+}
+
+Writable.prototype.write = function (chunk, encoding, cb) {
+ var state = this._writableState;
+ var ret = false;
+
+ if (typeof encoding === 'function') {
+ cb = encoding;
+ encoding = null;
+ }
+
+ if (Buffer.isBuffer(chunk)) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;
+
+ if (typeof cb !== 'function') cb = nop;
+
+ if (state.ended) writeAfterEnd(this, cb);else if (validChunk(this, state, chunk, cb)) {
+ state.pendingcb++;
+ ret = writeOrBuffer(this, state, chunk, encoding, cb);
+ }
+
+ return ret;
+};
+
+Writable.prototype.cork = function () {
+ var state = this._writableState;
+
+ state.corked++;
+};
+
+Writable.prototype.uncork = function () {
+ var state = this._writableState;
+
+ if (state.corked) {
+ state.corked--;
+
+ if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);
+ }
+};
+
+Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
+ // node::ParseEncoding() requires lower case.
+ if (typeof encoding === 'string') encoding = encoding.toLowerCase();
+ if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding);
+ this._writableState.defaultEncoding = encoding;
+ return this;
+};
+
+function decodeChunk(state, chunk, encoding) {
+ if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {
+ chunk = bufferShim.from(chunk, encoding);
+ }
+ return chunk;
+}
+
+// if we're already writing something, then just put this
+// in the queue, and wait our turn. Otherwise, call _write
+// If we return false, then we need a drain event, so set that flag.
+function writeOrBuffer(stream, state, chunk, encoding, cb) {
+ chunk = decodeChunk(state, chunk, encoding);
+
+ if (Buffer.isBuffer(chunk)) encoding = 'buffer';
+ var len = state.objectMode ? 1 : chunk.length;
+
+ state.length += len;
+
+ var ret = state.length < state.highWaterMark;
+ // we must ensure that previous needDrain will not be reset to false.
+ if (!ret) state.needDrain = true;
+
+ if (state.writing || state.corked) {
+ var last = state.lastBufferedRequest;
+ state.lastBufferedRequest = new WriteReq(chunk, encoding, cb);
+ if (last) {
+ last.next = state.lastBufferedRequest;
+ } else {
+ state.bufferedRequest = state.lastBufferedRequest;
+ }
+ state.bufferedRequestCount += 1;
+ } else {
+ doWrite(stream, state, false, len, chunk, encoding, cb);
+ }
+
+ return ret;
+}
+
+function doWrite(stream, state, writev, len, chunk, encoding, cb) {
+ state.writelen = len;
+ state.writecb = cb;
+ state.writing = true;
+ state.sync = true;
+ if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);
+ state.sync = false;
+}
+
+function onwriteError(stream, state, sync, er, cb) {
+ --state.pendingcb;
+ if (sync) processNextTick(cb, er);else cb(er);
+
+ stream._writableState.errorEmitted = true;
+ stream.emit('error', er);
+}
+
+function onwriteStateUpdate(state) {
+ state.writing = false;
+ state.writecb = null;
+ state.length -= state.writelen;
+ state.writelen = 0;
+}
+
+function onwrite(stream, er) {
+ var state = stream._writableState;
+ var sync = state.sync;
+ var cb = state.writecb;
+
+ onwriteStateUpdate(state);
+
+ if (er) onwriteError(stream, state, sync, er, cb);else {
+ // Check if we're actually ready to finish, but don't emit yet
+ var finished = needFinish(state);
+
+ if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {
+ clearBuffer(stream, state);
+ }
+
+ if (sync) {
+ /*<replacement>*/
+ asyncWrite(afterWrite, stream, state, finished, cb);
+ /*</replacement>*/
+ } else {
+ afterWrite(stream, state, finished, cb);
+ }
+ }
+}
+
+function afterWrite(stream, state, finished, cb) {
+ if (!finished) onwriteDrain(stream, state);
+ state.pendingcb--;
+ cb();
+ finishMaybe(stream, state);
+}
+
+// Must force callback to be called on nextTick, so that we don't
+// emit 'drain' before the write() consumer gets the 'false' return
+// value, and has a chance to attach a 'drain' listener.
+function onwriteDrain(stream, state) {
+ if (state.length === 0 && state.needDrain) {
+ state.needDrain = false;
+ stream.emit('drain');
+ }
+}
+
+// if there's something in the buffer waiting, then process it
+function clearBuffer(stream, state) {
+ state.bufferProcessing = true;
+ var entry = state.bufferedRequest;
+
+ if (stream._writev && entry && entry.next) {
+ // Fast case, write everything using _writev()
+ var l = state.bufferedRequestCount;
+ var buffer = new Array(l);
+ var holder = state.corkedRequestsFree;
+ holder.entry = entry;
+
+ var count = 0;
+ while (entry) {
+ buffer[count] = entry;
+ entry = entry.next;
+ count += 1;
+ }
+
+ doWrite(stream, state, true, state.length, buffer, '', holder.finish);
+
+ // doWrite is almost always async, defer these to save a bit of time
+ // as the hot path ends with doWrite
+ state.pendingcb++;
+ state.lastBufferedRequest = null;
+ if (holder.next) {
+ state.corkedRequestsFree = holder.next;
+ holder.next = null;
+ } else {
+ state.corkedRequestsFree = new CorkedRequest(state);
+ }
+ } else {
+ // Slow case, write chunks one-by-one
+ while (entry) {
+ var chunk = entry.chunk;
+ var encoding = entry.encoding;
+ var cb = entry.callback;
+ var len = state.objectMode ? 1 : chunk.length;
+
+ doWrite(stream, state, false, len, chunk, encoding, cb);
+ entry = entry.next;
+ // if we didn't call the onwrite immediately, then
+ // it means that we need to wait until it does.
+ // also, that means that the chunk and cb are currently
+ // being processed, so move the buffer counter past them.
+ if (state.writing) {
+ break;
+ }
+ }
+
+ if (entry === null) state.lastBufferedRequest = null;
+ }
+
+ state.bufferedRequestCount = 0;
+ state.bufferedRequest = entry;
+ state.bufferProcessing = false;
+}
+
+Writable.prototype._write = function (chunk, encoding, cb) {
+ cb(new Error('not implemented'));
+};
+
+Writable.prototype._writev = null;
+
+Writable.prototype.end = function (chunk, encoding, cb) {
+ var state = this._writableState;
+
+ if (typeof chunk === 'function') {
+ cb = chunk;
+ chunk = null;
+ encoding = null;
+ } else if (typeof encoding === 'function') {
+ cb = encoding;
+ encoding = null;
+ }
+
+ if (chunk !== null && chunk !== undefined) this.write(chunk, encoding);
+
+ // .end() fully uncorks
+ if (state.corked) {
+ state.corked = 1;
+ this.uncork();
+ }
+
+ // ignore unnecessary end() calls.
+ if (!state.ending && !state.finished) endWritable(this, state, cb);
+};
+
+function needFinish(state) {
+ return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;
+}
+
+function prefinish(stream, state) {
+ if (!state.prefinished) {
+ state.prefinished = true;
+ stream.emit('prefinish');
+ }
+}
+
+function finishMaybe(stream, state) {
+ var need = needFinish(state);
+ if (need) {
+ if (state.pendingcb === 0) {
+ prefinish(stream, state);
+ state.finished = true;
+ stream.emit('finish');
+ } else {
+ prefinish(stream, state);
+ }
+ }
+ return need;
+}
+
+function endWritable(stream, state, cb) {
+ state.ending = true;
+ finishMaybe(stream, state);
+ if (cb) {
+ if (state.finished) processNextTick(cb);else stream.once('finish', cb);
+ }
+ state.ended = true;
+ stream.writable = false;
+}
+
+// It seems a linked list but it is not
+// there will be only 2 of these for each stream
+function CorkedRequest(state) {
+ var _this = this;
+
+ this.next = null;
+ this.entry = null;
+
+ this.finish = function (err) {
+ var entry = _this.entry;
+ _this.entry = null;
+ while (entry) {
+ var cb = entry.callback;
+ state.pendingcb--;
+ cb(err);
+ entry = entry.next;
+ }
+ if (state.corkedRequestsFree) {
+ state.corkedRequestsFree.next = _this;
+ } else {
+ state.corkedRequestsFree = _this;
+ }
+ };
+}
+}).call(this,require('_process'))
+},{"./_stream_duplex":156,"_process":153,"buffer":6,"buffer-shims":5,"core-util-is":22,"events":27,"inherits":45,"process-nextick-args":152,"util-deprecate":194}],161:[function(require,module,exports){
+'use strict';
+
+var Buffer = require('buffer').Buffer;
+/*<replacement>*/
+var bufferShim = require('buffer-shims');
+/*</replacement>*/
+
+module.exports = BufferList;
+
+function BufferList() {
+ this.head = null;
+ this.tail = null;
+ this.length = 0;
+}
+
+BufferList.prototype.push = function (v) {
+ var entry = { data: v, next: null };
+ if (this.length > 0) this.tail.next = entry;else this.head = entry;
+ this.tail = entry;
+ ++this.length;
+};
+
+BufferList.prototype.unshift = function (v) {
+ var entry = { data: v, next: this.head };
+ if (this.length === 0) this.tail = entry;
+ this.head = entry;
+ ++this.length;
+};
+
+BufferList.prototype.shift = function () {
+ if (this.length === 0) return;
+ var ret = this.head.data;
+ if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next;
+ --this.length;
+ return ret;
+};
+
+BufferList.prototype.clear = function () {
+ this.head = this.tail = null;
+ this.length = 0;
+};
+
+BufferList.prototype.join = function (s) {
+ if (this.length === 0) return '';
+ var p = this.head;
+ var ret = '' + p.data;
+ while (p = p.next) {
+ ret += s + p.data;
+ }return ret;
+};
+
+BufferList.prototype.concat = function (n) {
+ if (this.length === 0) return bufferShim.alloc(0);
+ if (this.length === 1) return this.head.data;
+ var ret = bufferShim.allocUnsafe(n >>> 0);
+ var p = this.head;
+ var i = 0;
+ while (p) {
+ p.data.copy(ret, i);
+ i += p.data.length;
+ p = p.next;
+ }
+ return ret;
+};
+},{"buffer":6,"buffer-shims":5}],162:[function(require,module,exports){
+module.exports = require("./lib/_stream_passthrough.js")
+
+},{"./lib/_stream_passthrough.js":157}],163:[function(require,module,exports){
+(function (process){
+var Stream = (function (){
+ try {
+ return require('st' + 'ream'); // hack to fix a circular dependency issue when used with browserify
+ } catch(_){}
+}());
+exports = module.exports = require('./lib/_stream_readable.js');
+exports.Stream = Stream || exports;
+exports.Readable = exports;
+exports.Writable = require('./lib/_stream_writable.js');
+exports.Duplex = require('./lib/_stream_duplex.js');
+exports.Transform = require('./lib/_stream_transform.js');
+exports.PassThrough = require('./lib/_stream_passthrough.js');
+
+if (!process.browser && process.env.READABLE_STREAM === 'disable' && Stream) {
+ module.exports = Stream;
+}
+
+}).call(this,require('_process'))
+},{"./lib/_stream_duplex.js":156,"./lib/_stream_passthrough.js":157,"./lib/_stream_readable.js":158,"./lib/_stream_transform.js":159,"./lib/_stream_writable.js":160,"_process":153}],164:[function(require,module,exports){
+module.exports = require("./lib/_stream_transform.js")
+
+},{"./lib/_stream_transform.js":159}],165:[function(require,module,exports){
+module.exports = require("./lib/_stream_writable.js")
+
+},{"./lib/_stream_writable.js":160}],166:[function(require,module,exports){
+(function (Buffer){
+/*
+CryptoJS v3.1.2
+code.google.com/p/crypto-js
+(c) 2009-2013 by Jeff Mott. All rights reserved.
+code.google.com/p/crypto-js/wiki/License
+*/
+/** @preserve
+(c) 2012 by Cédric Mesnil. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// constants table
+var zl = [
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
+ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
+ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
+ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
+]
+
+var zr = [
+ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
+ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
+ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
+ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
+ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
+]
+
+var sl = [
+ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
+ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
+ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
+ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
+ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
+]
+
+var sr = [
+ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
+ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
+ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
+ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
+ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
+]
+
+var hl = [0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]
+var hr = [0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]
+
+function bytesToWords (bytes) {
+ var words = []
+ for (var i = 0, b = 0; i < bytes.length; i++, b += 8) {
+ words[b >>> 5] |= bytes[i] << (24 - b % 32)
+ }
+ return words
+}
+
+function wordsToBytes (words) {
+ var bytes = []
+ for (var b = 0; b < words.length * 32; b += 8) {
+ bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF)
+ }
+ return bytes
+}
+
+function processBlock (H, M, offset) {
+ // swap endian
+ for (var i = 0; i < 16; i++) {
+ var offset_i = offset + i
+ var M_offset_i = M[offset_i]
+
+ // Swap
+ M[offset_i] = (
+ (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) |
+ (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00)
+ )
+ }
+
+ // Working variables
+ var al, bl, cl, dl, el
+ var ar, br, cr, dr, er
+
+ ar = al = H[0]
+ br = bl = H[1]
+ cr = cl = H[2]
+ dr = dl = H[3]
+ er = el = H[4]
+
+ // computation
+ var t
+ for (i = 0; i < 80; i += 1) {
+ t = (al + M[offset + zl[i]]) | 0
+ if (i < 16) {
+ t += f1(bl, cl, dl) + hl[0]
+ } else if (i < 32) {
+ t += f2(bl, cl, dl) + hl[1]
+ } else if (i < 48) {
+ t += f3(bl, cl, dl) + hl[2]
+ } else if (i < 64) {
+ t += f4(bl, cl, dl) + hl[3]
+ } else {// if (i<80) {
+ t += f5(bl, cl, dl) + hl[4]
+ }
+ t = t | 0
+ t = rotl(t, sl[i])
+ t = (t + el) | 0
+ al = el
+ el = dl
+ dl = rotl(cl, 10)
+ cl = bl
+ bl = t
+
+ t = (ar + M[offset + zr[i]]) | 0
+ if (i < 16) {
+ t += f5(br, cr, dr) + hr[0]
+ } else if (i < 32) {
+ t += f4(br, cr, dr) + hr[1]
+ } else if (i < 48) {
+ t += f3(br, cr, dr) + hr[2]
+ } else if (i < 64) {
+ t += f2(br, cr, dr) + hr[3]
+ } else {// if (i<80) {
+ t += f1(br, cr, dr) + hr[4]
+ }
+
+ t = t | 0
+ t = rotl(t, sr[i])
+ t = (t + er) | 0
+ ar = er
+ er = dr
+ dr = rotl(cr, 10)
+ cr = br
+ br = t
+ }
+
+ // intermediate hash value
+ t = (H[1] + cl + dr) | 0
+ H[1] = (H[2] + dl + er) | 0
+ H[2] = (H[3] + el + ar) | 0
+ H[3] = (H[4] + al + br) | 0
+ H[4] = (H[0] + bl + cr) | 0
+ H[0] = t
+}
+
+function f1 (x, y, z) {
+ return ((x) ^ (y) ^ (z))
+}
+
+function f2 (x, y, z) {
+ return (((x) & (y)) | ((~x) & (z)))
+}
+
+function f3 (x, y, z) {
+ return (((x) | (~(y))) ^ (z))
+}
+
+function f4 (x, y, z) {
+ return (((x) & (z)) | ((y) & (~(z))))
+}
+
+function f5 (x, y, z) {
+ return ((x) ^ ((y) | (~(z))))
+}
+
+function rotl (x, n) {
+ return (x << n) | (x >>> (32 - n))
+}
+
+function ripemd160 (message) {
+ var H = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]
+
+ if (typeof message === 'string') {
+ message = new Buffer(message, 'utf8')
+ }
+
+ var m = bytesToWords(message)
+
+ var nBitsLeft = message.length * 8
+ var nBitsTotal = message.length * 8
+
+ // Add padding
+ m[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32)
+ m[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
+ (((nBitsTotal << 8) | (nBitsTotal >>> 24)) & 0x00ff00ff) |
+ (((nBitsTotal << 24) | (nBitsTotal >>> 8)) & 0xff00ff00)
+ )
+
+ for (var i = 0; i < m.length; i += 16) {
+ processBlock(H, m, i)
+ }
+
+ // swap endian
+ for (i = 0; i < 5; i++) {
+ // shortcut
+ var H_i = H[i]
+
+ // Swap
+ H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) |
+ (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00)
+ }
+
+ var digestbytes = wordsToBytes(H)
+ return new Buffer(digestbytes)
+}
+
+module.exports = ripemd160
+
+}).call(this,require("buffer").Buffer)
+},{"buffer":6}],167:[function(require,module,exports){
+var util = require('util');
+var SJJ = require('sdp-jingle-json');
+var WildEmitter = require('wildemitter');
+var Peerconn = require('traceablepeerconnection');
+var adapter = require('webrtc-adapter');
+var cloneDeep = require('lodash.clonedeep');
+
+function PeerConnection(config, constraints) {
+ var self = this;
+ var item;
+ WildEmitter.call(this);
+
+ config = config || {};
+ config.iceServers = config.iceServers || [];
+
+ var detectedBrowser = adapter.browserDetails.browser;
+
+ // make sure this only gets enabled in Google Chrome
+ // EXPERIMENTAL FLAG, might get removed without notice
+ this.enableChromeNativeSimulcast = false;
+ if (constraints && constraints.optional &&
+ detectedBrowser === 'chrome' &&
+ navigator.appVersion.match(/Chromium\//) === null) {
+ constraints.optional.forEach(function (constraint) {
+ if (constraint.enableChromeNativeSimulcast) {
+ self.enableChromeNativeSimulcast = true;
+ }
+ });
+ }
+
+ // EXPERIMENTAL FLAG, might get removed without notice
+ this.enableMultiStreamHacks = false;
+ if (constraints && constraints.optional &&
+ detectedBrowser === 'chrome') {
+ constraints.optional.forEach(function (constraint) {
+ if (constraint.enableMultiStreamHacks) {
+ self.enableMultiStreamHacks = true;
+ }
+ });
+ }
+ // EXPERIMENTAL FLAG, might get removed without notice
+ this.restrictBandwidth = 0;
+ if (constraints && constraints.optional) {
+ constraints.optional.forEach(function (constraint) {
+ if (constraint.andyetRestrictBandwidth) {
+ self.restrictBandwidth = constraint.andyetRestrictBandwidth;
+ }
+ });
+ }
+
+ // EXPERIMENTAL FLAG, might get removed without notice
+ // bundle up ice candidates, only works for jingle mode
+ // number > 0 is the delay to wait for additional candidates
+ // ~20ms seems good
+ this.batchIceCandidates = 0;
+ if (constraints && constraints.optional) {
+ constraints.optional.forEach(function (constraint) {
+ if (constraint.andyetBatchIce) {
+ self.batchIceCandidates = constraint.andyetBatchIce;
+ }
+ });
+ }
+ this.batchedIceCandidates = [];
+
+ // EXPERIMENTAL FLAG, might get removed without notice
+ // this attemps to strip out candidates with an already known foundation
+ // and type -- i.e. those which are gathered via the same TURN server
+ // but different transports (TURN udp, tcp and tls respectively)
+ if (constraints && constraints.optional && detectedBrowser === 'chrome') {
+ constraints.optional.forEach(function (constraint) {
+ if (constraint.andyetFasterICE) {
+ self.eliminateDuplicateCandidates = constraint.andyetFasterICE;
+ }
+ });
+ }
+ // EXPERIMENTAL FLAG, might get removed without notice
+ // when using a server such as the jitsi videobridge we don't need to signal
+ // our candidates
+ if (constraints && constraints.optional) {
+ constraints.optional.forEach(function (constraint) {
+ if (constraint.andyetDontSignalCandidates) {
+ self.dontSignalCandidates = constraint.andyetDontSignalCandidates;
+ }
+ });
+ }
+
+
+ // EXPERIMENTAL FLAG, might get removed without notice
+ this.assumeSetLocalSuccess = false;
+ if (constraints && constraints.optional) {
+ constraints.optional.forEach(function (constraint) {
+ if (constraint.andyetAssumeSetLocalSuccess) {
+ self.assumeSetLocalSuccess = constraint.andyetAssumeSetLocalSuccess;
+ }
+ });
+ }
+
+ // EXPERIMENTAL FLAG, might get removed without notice
+ // working around https://bugzilla.mozilla.org/show_bug.cgi?id=1087551
+ // pass in a timeout for this
+ if (detectedBrowser === 'firefox') {
+ if (constraints && constraints.optional) {
+ this.wtFirefox = 0;
+ constraints.optional.forEach(function (constraint) {
+ if (constraint.andyetFirefoxMakesMeSad) {
+ self.wtFirefox = constraint.andyetFirefoxMakesMeSad;
+ if (self.wtFirefox > 0) {
+ self.firefoxcandidatebuffer = [];
+ }
+ }
+ });
+ }
+ }
+
+
+ this.pc = new Peerconn(config, constraints);
+
+ this.getLocalStreams = this.pc.getLocalStreams.bind(this.pc);
+ this.getRemoteStreams = this.pc.getRemoteStreams.bind(this.pc);
+ this.addStream = this.pc.addStream.bind(this.pc);
+ this.removeStream = this.pc.removeStream.bind(this.pc);
+
+ // proxy events
+ this.pc.on('*', function () {
+ self.emit.apply(self, arguments);
+ });
+
+ // proxy some events directly
+ this.pc.onremovestream = this.emit.bind(this, 'removeStream');
+ this.pc.onaddstream = this.emit.bind(this, 'addStream');
+ this.pc.onnegotiationneeded = this.emit.bind(this, 'negotiationNeeded');
+ this.pc.oniceconnectionstatechange = this.emit.bind(this, 'iceConnectionStateChange');
+ this.pc.onsignalingstatechange = this.emit.bind(this, 'signalingStateChange');
+
+ // handle ice candidate and data channel events
+ this.pc.onicecandidate = this._onIce.bind(this);
+ this.pc.ondatachannel = this._onDataChannel.bind(this);
+
+ this.localDescription = {
+ contents: []
+ };
+ this.remoteDescription = {
+ contents: []
+ };
+
+ this.config = {
+ debug: false,
+ sid: '',
+ isInitiator: true,
+ sdpSessionID: Date.now(),
+ useJingle: false
+ };
+
+ this.iceCredentials = {
+ local: {},
+ remote: {}
+ };
+
+ // apply our config
+ for (item in config) {
+ this.config[item] = config[item];
+ }
+ if (this.config.debug) {
+ this.on('*', function () {
+ var logger = config.logger || console;
+ logger.log('PeerConnection event:', arguments);
+ });
+ }
+ this.hadLocalStunCandidate = false;
+ this.hadRemoteStunCandidate = false;
+ this.hadLocalRelayCandidate = false;
+ this.hadRemoteRelayCandidate = false;
+
+ this.hadLocalIPv6Candidate = false;
+ this.hadRemoteIPv6Candidate = false;
+
+ // keeping references for all our data channels
+ // so they dont get garbage collected
+ // can be removed once the following bugs have been fixed
+ // https://crbug.com/405545
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=964092
+ // to be filed for opera
+ this._remoteDataChannels = [];
+ this._localDataChannels = [];
+
+ this._candidateBuffer = [];
+}
+
+util.inherits(PeerConnection, WildEmitter);
+
+Object.defineProperty(PeerConnection.prototype, 'signalingState', {
+ get: function () {
+ return this.pc.signalingState;
+ }
+});
+Object.defineProperty(PeerConnection.prototype, 'iceConnectionState', {
+ get: function () {
+ return this.pc.iceConnectionState;
+ }
+});
+
+PeerConnection.prototype._role = function () {
+ return this.isInitiator ? 'initiator' : 'responder';
+};
+
+// Add a stream to the peer connection object
+PeerConnection.prototype.addStream = function (stream) {
+ this.localStream = stream;
+ this.pc.addStream(stream);
+};
+
+// helper function to check if a remote candidate is a stun/relay
+// candidate or an ipv6 candidate
+PeerConnection.prototype._checkLocalCandidate = function (candidate) {
+ var cand = SJJ.toCandidateJSON(candidate);
+ if (cand.type == 'srflx') {
+ this.hadLocalStunCandidate = true;
+ } else if (cand.type == 'relay') {
+ this.hadLocalRelayCandidate = true;
+ }
+ if (cand.ip.indexOf(':') != -1) {
+ this.hadLocalIPv6Candidate = true;
+ }
+};
+
+// helper function to check if a remote candidate is a stun/relay
+// candidate or an ipv6 candidate
+PeerConnection.prototype._checkRemoteCandidate = function (candidate) {
+ var cand = SJJ.toCandidateJSON(candidate);
+ if (cand.type == 'srflx') {
+ this.hadRemoteStunCandidate = true;
+ } else if (cand.type == 'relay') {
+ this.hadRemoteRelayCandidate = true;
+ }
+ if (cand.ip.indexOf(':') != -1) {
+ this.hadRemoteIPv6Candidate = true;
+ }
+};
+
+
+// Init and add ice candidate object with correct constructor
+PeerConnection.prototype.processIce = function (update, cb) {
+ cb = cb || function () {};
+ var self = this;
+
+ // ignore any added ice candidates to avoid errors. why does the
+ // spec not do this?
+ if (this.pc.signalingState === 'closed') return cb();
+
+ if (update.contents || (update.jingle && update.jingle.contents)) {
+ var contentNames = this.remoteDescription.contents.map(function (c) { return c.name; });
+ var contents = update.contents || update.jingle.contents;
+
+ contents.forEach(function (content) {
+ var transport = content.transport || {};
+ var candidates = transport.candidates || [];
+ var mline = contentNames.indexOf(content.name);
+ var mid = content.name;
+ var remoteContent = self.remoteDescription.contents.find(function (c) {
+ return c.name === content.name;
+ });
+
+ // process candidates as a callback, in case we need to
+ // update ufrag and pwd with offer/answer
+ var processCandidates = function () {
+ candidates.forEach(
+ function (candidate) {
+ var iceCandidate = SJJ.toCandidateSDP(candidate) + '\r\n';
+ self.pc.addIceCandidate(
+ new RTCIceCandidate({
+ candidate: iceCandidate,
+ sdpMLineIndex: mline,
+ sdpMid: mid
+ }), function () {
+ // well, this success callback is pretty meaningless
+ },
+ function (err) {
+ self.emit('error', err);
+ }
+ );
+ self._checkRemoteCandidate(iceCandidate);
+ });
+ cb();
+ };
+
+ if (self.iceCredentials.remote[content.name] && transport.ufrag &&
+ self.iceCredentials.remote[content.name].ufrag !== transport.ufrag) {
+ if (remoteContent) {
+ remoteContent.transport.ufrag = transport.ufrag;
+ remoteContent.transport.pwd = transport.pwd;
+ var offer = {
+ type: 'offer',
+ jingle: self.remoteDescription
+ };
+ offer.sdp = SJJ.toSessionSDP(offer.jingle, {
+ sid: self.config.sdpSessionID,
+ role: self._role(),
+ direction: 'incoming'
+ });
+ self.pc.setRemoteDescription(new RTCSessionDescription(offer),
+ function () {
+ processCandidates();
+ },
+ function (err) {
+ self.emit('error', err);
+ }
+ );
+ } else {
+ self.emit('error', 'ice restart failed to find matching content');
+ }
+ } else {
+ processCandidates();
+ }
+ });
+ } else {
+ // working around https://code.google.com/p/webrtc/issues/detail?id=3669
+ if (update.candidate && update.candidate.candidate.indexOf('a=') !== 0) {
+ update.candidate.candidate = 'a=' + update.candidate.candidate;
+ }
+
+ if (this.wtFirefox && this.firefoxcandidatebuffer !== null) {
+ // we cant add this yet due to https://bugzilla.mozilla.org/show_bug.cgi?id=1087551
+ if (this.pc.localDescription && this.pc.localDescription.type === 'offer') {
+ this.firefoxcandidatebuffer.push(update.candidate);
+ return cb();
+ }
+ }
+
+ self.pc.addIceCandidate(
+ new RTCIceCandidate(update.candidate),
+ function () { },
+ function (err) {
+ self.emit('error', err);
+ }
+ );
+ self._checkRemoteCandidate(update.candidate.candidate);
+ cb();
+ }
+};
+
+// Generate and emit an offer with the given constraints
+PeerConnection.prototype.offer = function (constraints, cb) {
+ var self = this;
+ var hasConstraints = arguments.length === 2;
+ var mediaConstraints = hasConstraints && constraints ? constraints : {
+ offerToReceiveAudio: 1,
+ offerToReceiveVideo: 1
+ };
+ cb = hasConstraints ? cb : constraints;
+ cb = cb || function () {};
+
+ if (this.pc.signalingState === 'closed') return cb('Already closed');
+
+ // Actually generate the offer
+ this.pc.createOffer(
+ function (offer) {
+ // does not work for jingle, but jingle.js doesn't need
+ // this hack...
+ var expandedOffer = {
+ type: 'offer',
+ sdp: offer.sdp
+ };
+ if (self.assumeSetLocalSuccess) {
+ self.emit('offer', expandedOffer);
+ cb(null, expandedOffer);
+ }
+ self._candidateBuffer = [];
+ self.pc.setLocalDescription(offer,
+ function () {
+ var jingle;
+ if (self.config.useJingle) {
+ jingle = SJJ.toSessionJSON(offer.sdp, {
+ role: self._role(),
+ direction: 'outgoing'
+ });
+ jingle.sid = self.config.sid;
+ self.localDescription = jingle;
+
+ // Save ICE credentials
+ jingle.contents.forEach(function (content) {
+ var transport = content.transport || {};
+ if (transport.ufrag) {
+ self.iceCredentials.local[content.name] = {
+ ufrag: transport.ufrag,
+ pwd: transport.pwd
+ };
+ }
+ });
+
+ expandedOffer.jingle = jingle;
+ }
+ expandedOffer.sdp.split('\r\n').forEach(function (line) {
+ if (line.indexOf('a=candidate:') === 0) {
+ self._checkLocalCandidate(line);
+ }
+ });
+
+ if (!self.assumeSetLocalSuccess) {
+ self.emit('offer', expandedOffer);
+ cb(null, expandedOffer);
+ }
+ },
+ function (err) {
+ self.emit('error', err);
+ cb(err);
+ }
+ );
+ },
+ function (err) {
+ self.emit('error', err);
+ cb(err);
+ },
+ mediaConstraints
+ );
+};
+
+
+// Process an incoming offer so that ICE may proceed before deciding
+// to answer the request.
+PeerConnection.prototype.handleOffer = function (offer, cb) {
+ cb = cb || function () {};
+ var self = this;
+ offer.type = 'offer';
+ if (offer.jingle) {
+ if (this.enableChromeNativeSimulcast) {
+ offer.jingle.contents.forEach(function (content) {
+ if (content.name === 'video') {
+ content.application.googConferenceFlag = true;
+ }
+
+ });
+ }
+ if (this.enableMultiStreamHacks) {
+ // add a mixed video stream as first stream
+ offer.jingle.contents.forEach(function (content) {
+ if (content.name === 'video') {
+ var sources = content.application.sources || [];
+ if (sources.length === 0 || sources[0].ssrc !== "3735928559") {
+ sources.unshift({
+ ssrc: "3735928559", // 0xdeadbeef
+ parameters: [
+ {
+ key: "cname",
+ value: "deadbeef"
+ },
+ {
+ key: "msid",
+ value: "mixyourfecintothis please"
+ }
+ ]
+ });
+ content.application.sources = sources;
+ }
+ }
+ });
+ }
+ if (self.restrictBandwidth > 0) {
+ if (offer.jingle.contents.length >= 2 && offer.jingle.contents[1].name === 'video') {
+ var content = offer.jingle.contents[1];
+ var hasBw = content.application && content.application.bandwidth && content.application.bandwidth.bandwidth;
+ if (!hasBw) {
+ offer.jingle.contents[1].application.bandwidth = { type: 'AS', bandwidth: self.restrictBandwidth.toString() };
+ offer.sdp = SJJ.toSessionSDP(offer.jingle, {
+ sid: self.config.sdpSessionID,
+ role: self._role(),
+ direction: 'outgoing'
+ });
+ }
+ }
+ }
+ // Save ICE credentials
+ offer.jingle.contents.forEach(function (content) {
+ var transport = content.transport || {};
+ if (transport.ufrag) {
+ self.iceCredentials.remote[content.name] = {
+ ufrag: transport.ufrag,
+ pwd: transport.pwd
+ };
+ }
+ });
+ offer.sdp = SJJ.toSessionSDP(offer.jingle, {
+ sid: self.config.sdpSessionID,
+ role: self._role(),
+ direction: 'incoming'
+ });
+ self.remoteDescription = offer.jingle;
+ }
+ offer.sdp.split('\r\n').forEach(function (line) {
+ if (line.indexOf('a=candidate:') === 0) {
+ self._checkRemoteCandidate(line);
+ }
+ });
+ self.pc.setRemoteDescription(new RTCSessionDescription(offer),
+ function () {
+ cb();
+ },
+ cb
+ );
+};
+
+// Answer an offer with audio only
+PeerConnection.prototype.answerAudioOnly = function (cb) {
+ var mediaConstraints = {
+ mandatory: {
+ OfferToReceiveAudio: true,
+ OfferToReceiveVideo: false
+ }
+ };
+ this._answer(mediaConstraints, cb);
+};
+
+// Answer an offer without offering to recieve
+PeerConnection.prototype.answerBroadcastOnly = function (cb) {
+ var mediaConstraints = {
+ mandatory: {
+ OfferToReceiveAudio: false,
+ OfferToReceiveVideo: false
+ }
+ };
+ this._answer(mediaConstraints, cb);
+};
+
+// Answer an offer with given constraints default is audio/video
+PeerConnection.prototype.answer = function (constraints, cb) {
+ var hasConstraints = arguments.length === 2;
+ var callback = hasConstraints ? cb : constraints;
+ var mediaConstraints = hasConstraints && constraints ? constraints : {
+ mandatory: {
+ OfferToReceiveAudio: true,
+ OfferToReceiveVideo: true
+ }
+ };
+
+ this._answer(mediaConstraints, callback);
+};
+
+// Process an answer
+PeerConnection.prototype.handleAnswer = function (answer, cb) {
+ cb = cb || function () {};
+ var self = this;
+ if (answer.jingle) {
+ answer.sdp = SJJ.toSessionSDP(answer.jingle, {
+ sid: self.config.sdpSessionID,
+ role: self._role(),
+ direction: 'incoming'
+ });
+ self.remoteDescription = answer.jingle;
+
+ // Save ICE credentials
+ answer.jingle.contents.forEach(function (content) {
+ var transport = content.transport || {};
+ if (transport.ufrag) {
+ self.iceCredentials.remote[content.name] = {
+ ufrag: transport.ufrag,
+ pwd: transport.pwd
+ };
+ }
+ });
+ }
+ answer.sdp.split('\r\n').forEach(function (line) {
+ if (line.indexOf('a=candidate:') === 0) {
+ self._checkRemoteCandidate(line);
+ }
+ });
+ self.pc.setRemoteDescription(
+ new RTCSessionDescription(answer),
+ function () {
+ if (self.wtFirefox) {
+ window.setTimeout(function () {
+ self.firefoxcandidatebuffer.forEach(function (candidate) {
+ // add candidates later
+ self.pc.addIceCandidate(
+ new RTCIceCandidate(candidate),
+ function () { },
+ function (err) {
+ self.emit('error', err);
+ }
+ );
+ self._checkRemoteCandidate(candidate.candidate);
+ });
+ self.firefoxcandidatebuffer = null;
+ }, self.wtFirefox);
+ }
+ cb(null);
+ },
+ cb
+ );
+};
+
+// Close the peer connection
+PeerConnection.prototype.close = function () {
+ this.pc.close();
+
+ this._localDataChannels = [];
+ this._remoteDataChannels = [];
+
+ this.emit('close');
+};
+
+// Internal code sharing for various types of answer methods
+PeerConnection.prototype._answer = function (constraints, cb) {
+ cb = cb || function () {};
+ var self = this;
+ if (!this.pc.remoteDescription) {
+ // the old API is used, call handleOffer
+ throw new Error('remoteDescription not set');
+ }
+
+ if (this.pc.signalingState === 'closed') return cb('Already closed');
+
+ self.pc.createAnswer(
+ function (answer) {
+ var sim = [];
+ if (self.enableChromeNativeSimulcast) {
+ // native simulcast part 1: add another SSRC
+ answer.jingle = SJJ.toSessionJSON(answer.sdp, {
+ role: self._role(),
+ direction: 'outgoing'
+ });
+ if (answer.jingle.contents.length >= 2 && answer.jingle.contents[1].name === 'video') {
+ var groups = answer.jingle.contents[1].application.sourceGroups || [];
+ var hasSim = false;
+ groups.forEach(function (group) {
+ if (group.semantics == 'SIM') hasSim = true;
+ });
+ if (!hasSim &&
+ answer.jingle.contents[1].application.sources.length) {
+ var newssrc = JSON.parse(JSON.stringify(answer.jingle.contents[1].application.sources[0]));
+ newssrc.ssrc = '' + Math.floor(Math.random() * 0xffffffff); // FIXME: look for conflicts
+ answer.jingle.contents[1].application.sources.push(newssrc);
+
+ sim.push(answer.jingle.contents[1].application.sources[0].ssrc);
+ sim.push(newssrc.ssrc);
+ groups.push({
+ semantics: 'SIM',
+ sources: sim
+ });
+
+ // also create an RTX one for the SIM one
+ var rtxssrc = JSON.parse(JSON.stringify(newssrc));
+ rtxssrc.ssrc = '' + Math.floor(Math.random() * 0xffffffff); // FIXME: look for conflicts
+ answer.jingle.contents[1].application.sources.push(rtxssrc);
+ groups.push({
+ semantics: 'FID',
+ sources: [newssrc.ssrc, rtxssrc.ssrc]
+ });
+
+ answer.jingle.contents[1].application.sourceGroups = groups;
+ answer.sdp = SJJ.toSessionSDP(answer.jingle, {
+ sid: self.config.sdpSessionID,
+ role: self._role(),
+ direction: 'outgoing'
+ });
+ }
+ }
+ }
+ var expandedAnswer = {
+ type: 'answer',
+ sdp: answer.sdp
+ };
+ if (self.assumeSetLocalSuccess) {
+ // not safe to do when doing simulcast mangling
+ var copy = cloneDeep(expandedAnswer);
+ self.emit('answer', copy);
+ cb(null, copy);
+ }
+ self._candidateBuffer = [];
+ self.pc.setLocalDescription(answer,
+ function () {
+ if (self.config.useJingle) {
+ var jingle = SJJ.toSessionJSON(answer.sdp, {
+ role: self._role(),
+ direction: 'outgoing'
+ });
+ jingle.sid = self.config.sid;
+ self.localDescription = jingle;
+ expandedAnswer.jingle = jingle;
+ }
+ if (self.enableChromeNativeSimulcast) {
+ // native simulcast part 2:
+ // signal multiple tracks to the receiver
+ // for anything in the SIM group
+ if (!expandedAnswer.jingle) {
+ expandedAnswer.jingle = SJJ.toSessionJSON(answer.sdp, {
+ role: self._role(),
+ direction: 'outgoing'
+ });
+ }
+ expandedAnswer.jingle.contents[1].application.sources.forEach(function (source, idx) {
+ // the floor idx/2 is a hack that relies on a particular order
+ // of groups, alternating between sim and rtx
+ source.parameters = source.parameters.map(function (parameter) {
+ if (parameter.key === 'msid') {
+ parameter.value += '-' + Math.floor(idx / 2);
+ }
+ return parameter;
+ });
+ });
+ expandedAnswer.sdp = SJJ.toSessionSDP(expandedAnswer.jingle, {
+ sid: self.sdpSessionID,
+ role: self._role(),
+ direction: 'outgoing'
+ });
+ }
+ expandedAnswer.sdp.split('\r\n').forEach(function (line) {
+ if (line.indexOf('a=candidate:') === 0) {
+ self._checkLocalCandidate(line);
+ }
+ });
+ if (!self.assumeSetLocalSuccess) {
+ var copy = cloneDeep(expandedAnswer);
+ self.emit('answer', copy);
+ cb(null, copy);
+ }
+ },
+ function (err) {
+ self.emit('error', err);
+ cb(err);
+ }
+ );
+ },
+ function (err) {
+ self.emit('error', err);
+ cb(err);
+ },
+ constraints
+ );
+};
+
+// Internal method for emitting ice candidates on our peer object
+PeerConnection.prototype._onIce = function (event) {
+ var self = this;
+ if (event.candidate) {
+ if (this.dontSignalCandidates) return;
+ var ice = event.candidate;
+
+ var expandedCandidate = {
+ candidate: {
+ candidate: ice.candidate,
+ sdpMid: ice.sdpMid,
+ sdpMLineIndex: ice.sdpMLineIndex
+ }
+ };
+ this._checkLocalCandidate(ice.candidate);
+
+ var cand = SJJ.toCandidateJSON(ice.candidate);
+
+ var already;
+ var idx;
+ if (this.eliminateDuplicateCandidates && cand.type === 'relay') {
+ // drop candidates with same foundation, component
+ // take local type pref into account so we don't ignore udp
+ // ones when we know about a TCP one. unlikely but...
+ already = this._candidateBuffer.filter(
+ function (c) {
+ return c.type === 'relay';
+ }).map(function (c) {
+ return c.foundation + ':' + c.component;
+ }
+ );
+ idx = already.indexOf(cand.foundation + ':' + cand.component);
+ // remember: local type pref of udp is 0, tcp 1, tls 2
+ if (idx > -1 && ((cand.priority >> 24) >= (already[idx].priority >> 24))) {
+ // drop it, same foundation with higher (worse) type pref
+ return;
+ }
+ }
+ if (this.config.bundlePolicy === 'max-bundle') {
+ // drop candidates which are duplicate for audio/video/data
+ // duplicate means same host/port but different sdpMid
+ already = this._candidateBuffer.filter(
+ function (c) {
+ return cand.type === c.type;
+ }).map(function (cand) {
+ return cand.address + ':' + cand.port;
+ }
+ );
+ idx = already.indexOf(cand.address + ':' + cand.port);
+ if (idx > -1) return;
+ }
+ // also drop rtcp candidates since we know the peer supports RTCP-MUX
+ // this is a workaround until browsers implement this natively
+ if (this.config.rtcpMuxPolicy === 'require' && cand.component === '2') {
+ return;
+ }
+ this._candidateBuffer.push(cand);
+
+ if (self.config.useJingle) {
+ if (!ice.sdpMid) { // firefox doesn't set this
+ if (self.pc.remoteDescription && self.pc.remoteDescription.type === 'offer') {
+ // preserve name from remote
+ ice.sdpMid = self.remoteDescription.contents[ice.sdpMLineIndex].name;
+ } else {
+ ice.sdpMid = self.localDescription.contents[ice.sdpMLineIndex].name;
+ }
+ }
+ if (!self.iceCredentials.local[ice.sdpMid]) {
+ var jingle = SJJ.toSessionJSON(self.pc.localDescription.sdp, {
+ role: self._role(),
+ direction: 'outgoing'
+ });
+ jingle.contents.forEach(function (content) {
+ var transport = content.transport || {};
+ if (transport.ufrag) {
+ self.iceCredentials.local[content.name] = {
+ ufrag: transport.ufrag,
+ pwd: transport.pwd
+ };
+ }
+ });
+ }
+ expandedCandidate.jingle = {
+ contents: [{
+ name: ice.sdpMid,
+ creator: self._role(),
+ transport: {
+ transportType: 'iceUdp',
+ ufrag: self.iceCredentials.local[ice.sdpMid].ufrag,
+ pwd: self.iceCredentials.local[ice.sdpMid].pwd,
+ candidates: [
+ cand
+ ]
+ }
+ }]
+ };
+ if (self.batchIceCandidates > 0) {
+ if (self.batchedIceCandidates.length === 0) {
+ window.setTimeout(function () {
+ var contents = {};
+ self.batchedIceCandidates.forEach(function (content) {
+ content = content.contents[0];
+ if (!contents[content.name]) contents[content.name] = content;
+ contents[content.name].transport.candidates.push(content.transport.candidates[0]);
+ });
+ var newCand = {
+ jingle: {
+ contents: []
+ }
+ };
+ Object.keys(contents).forEach(function (name) {
+ newCand.jingle.contents.push(contents[name]);
+ });
+ self.batchedIceCandidates = [];
+ self.emit('ice', newCand);
+ }, self.batchIceCandidates);
+ }
+ self.batchedIceCandidates.push(expandedCandidate.jingle);
+ return;
+ }
+
+ }
+ this.emit('ice', expandedCandidate);
+ } else {
+ this.emit('endOfCandidates');
+ }
+};
+
+// Internal method for processing a new data channel being added by the
+// other peer.
+PeerConnection.prototype._onDataChannel = function (event) {
+ // make sure we keep a reference so this doesn't get garbage collected
+ var channel = event.channel;
+ this._remoteDataChannels.push(channel);
+
+ this.emit('addChannel', channel);
+};
+
+// Create a data channel spec reference:
+// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannelInit
+PeerConnection.prototype.createDataChannel = function (name, opts) {
+ var channel = this.pc.createDataChannel(name, opts);
+
+ // make sure we keep a reference so this doesn't get garbage collected
+ this._localDataChannels.push(channel);
+
+ return channel;
+};
+
+PeerConnection.prototype.getStats = function (cb) {
+ this.pc.getStats(null,
+ function (res) {
+ cb(null, res);
+ },
+ function (err) {
+ cb(err);
+ }
+ );
+};
+
+module.exports = PeerConnection;
+
+},{"lodash.clonedeep":133,"sdp-jingle-json":168,"traceablepeerconnection":184,"util":197,"webrtc-adapter":201,"wildemitter":211}],168:[function(require,module,exports){
+var toSDP = require('./lib/tosdp');
+var toJSON = require('./lib/tojson');
+
+
+// Converstion from JSON to SDP
+
+exports.toIncomingSDPOffer = function (session) {
+ return toSDP.toSessionSDP(session, {
+ role: 'responder',
+ direction: 'incoming'
+ });
+};
+exports.toOutgoingSDPOffer = function (session) {
+ return toSDP.toSessionSDP(session, {
+ role: 'initiator',
+ direction: 'outgoing'
+ });
+};
+exports.toIncomingSDPAnswer = function (session) {
+ return toSDP.toSessionSDP(session, {
+ role: 'initiator',
+ direction: 'incoming'
+ });
+};
+exports.toOutgoingSDPAnswer = function (session) {
+ return toSDP.toSessionSDP(session, {
+ role: 'responder',
+ direction: 'outgoing'
+ });
+};
+exports.toIncomingMediaSDPOffer = function (media) {
+ return toSDP.toMediaSDP(media, {
+ role: 'responder',
+ direction: 'incoming'
+ });
+};
+exports.toOutgoingMediaSDPOffer = function (media) {
+ return toSDP.toMediaSDP(media, {
+ role: 'initiator',
+ direction: 'outgoing'
+ });
+};
+exports.toIncomingMediaSDPAnswer = function (media) {
+ return toSDP.toMediaSDP(media, {
+ role: 'initiator',
+ direction: 'incoming'
+ });
+};
+exports.toOutgoingMediaSDPAnswer = function (media) {
+ return toSDP.toMediaSDP(media, {
+ role: 'responder',
+ direction: 'outgoing'
+ });
+};
+exports.toCandidateSDP = toSDP.toCandidateSDP;
+exports.toMediaSDP = toSDP.toMediaSDP;
+exports.toSessionSDP = toSDP.toSessionSDP;
+
+
+// Conversion from SDP to JSON
+
+exports.toIncomingJSONOffer = function (sdp, creators) {
+ return toJSON.toSessionJSON(sdp, {
+ role: 'responder',
+ direction: 'incoming',
+ creators: creators
+ });
+};
+exports.toOutgoingJSONOffer = function (sdp, creators) {
+ return toJSON.toSessionJSON(sdp, {
+ role: 'initiator',
+ direction: 'outgoing',
+ creators: creators
+ });
+};
+exports.toIncomingJSONAnswer = function (sdp, creators) {
+ return toJSON.toSessionJSON(sdp, {
+ role: 'initiator',
+ direction: 'incoming',
+ creators: creators
+ });
+};
+exports.toOutgoingJSONAnswer = function (sdp, creators) {
+ return toJSON.toSessionJSON(sdp, {
+ role: 'responder',
+ direction: 'outgoing',
+ creators: creators
+ });
+};
+exports.toIncomingMediaJSONOffer = function (sdp, creator) {
+ return toJSON.toMediaJSON(sdp, {
+ role: 'responder',
+ direction: 'incoming',
+ creator: creator
+ });
+};
+exports.toOutgoingMediaJSONOffer = function (sdp, creator) {
+ return toJSON.toMediaJSON(sdp, {
+ role: 'initiator',
+ direction: 'outgoing',
+ creator: creator
+ });
+};
+exports.toIncomingMediaJSONAnswer = function (sdp, creator) {
+ return toJSON.toMediaJSON(sdp, {
+ role: 'initiator',
+ direction: 'incoming',
+ creator: creator
+ });
+};
+exports.toOutgoingMediaJSONAnswer = function (sdp, creator) {
+ return toJSON.toMediaJSON(sdp, {
+ role: 'responder',
+ direction: 'outgoing',
+ creator: creator
+ });
+};
+exports.toCandidateJSON = toJSON.toCandidateJSON;
+exports.toMediaJSON = toJSON.toMediaJSON;
+exports.toSessionJSON = toJSON.toSessionJSON;
+
+},{"./lib/tojson":171,"./lib/tosdp":172}],169:[function(require,module,exports){
+exports.lines = function (sdp) {
+ return sdp.split('\r\n').filter(function (line) {
+ return line.length > 0;
+ });
+};
+
+exports.findLine = function (prefix, mediaLines, sessionLines) {
+ var prefixLength = prefix.length;
+ for (var i = 0; i < mediaLines.length; i++) {
+ if (mediaLines[i].substr(0, prefixLength) === prefix) {
+ return mediaLines[i];
+ }
+ }
+ // Continue searching in parent session section
+ if (!sessionLines) {
+ return false;
+ }
+
+ for (var j = 0; j < sessionLines.length; j++) {
+ if (sessionLines[j].substr(0, prefixLength) === prefix) {
+ return sessionLines[j];
+ }
+ }
+
+ return false;
+};
+
+exports.findLines = function (prefix, mediaLines, sessionLines) {
+ var results = [];
+ var prefixLength = prefix.length;
+ for (var i = 0; i < mediaLines.length; i++) {
+ if (mediaLines[i].substr(0, prefixLength) === prefix) {
+ results.push(mediaLines[i]);
+ }
+ }
+ if (results.length || !sessionLines) {
+ return results;
+ }
+ for (var j = 0; j < sessionLines.length; j++) {
+ if (sessionLines[j].substr(0, prefixLength) === prefix) {
+ results.push(sessionLines[j]);
+ }
+ }
+ return results;
+};
+
+exports.mline = function (line) {
+ var parts = line.substr(2).split(' ');
+ var parsed = {
+ media: parts[0],
+ port: parts[1],
+ proto: parts[2],
+ formats: []
+ };
+ for (var i = 3; i < parts.length; i++) {
+ if (parts[i]) {
+ parsed.formats.push(parts[i]);
+ }
+ }
+ return parsed;
+};
+
+exports.rtpmap = function (line) {
+ var parts = line.substr(9).split(' ');
+ var parsed = {
+ id: parts.shift()
+ };
+
+ parts = parts[0].split('/');
+
+ parsed.name = parts[0];
+ parsed.clockrate = parts[1];
+ parsed.channels = parts.length == 3 ? parts[2] : '1';
+ return parsed;
+};
+
+exports.sctpmap = function (line) {
+ // based on -05 draft
+ var parts = line.substr(10).split(' ');
+ var parsed = {
+ number: parts.shift(),
+ protocol: parts.shift(),
+ streams: parts.shift()
+ };
+ return parsed;
+};
+
+
+exports.fmtp = function (line) {
+ var kv, key, value;
+ var parts = line.substr(line.indexOf(' ') + 1).split(';');
+ var parsed = [];
+ for (var i = 0; i < parts.length; i++) {
+ kv = parts[i].split('=');
+ key = kv[0].trim();
+ value = kv[1];
+ if (key && value) {
+ parsed.push({key: key, value: value});
+ } else if (key) {
+ parsed.push({key: '', value: key});
+ }
+ }
+ return parsed;
+};
+
+exports.crypto = function (line) {
+ var parts = line.substr(9).split(' ');
+ var parsed = {
+ tag: parts[0],
+ cipherSuite: parts[1],
+ keyParams: parts[2],
+ sessionParams: parts.slice(3).join(' ')
+ };
+ return parsed;
+};
+
+exports.fingerprint = function (line) {
+ var parts = line.substr(14).split(' ');
+ return {
+ hash: parts[0],
+ value: parts[1]
+ };
+};
+
+exports.extmap = function (line) {
+ var parts = line.substr(9).split(' ');
+ var parsed = {};
+
+ var idpart = parts.shift();
+ var sp = idpart.indexOf('/');
+ if (sp >= 0) {
+ parsed.id = idpart.substr(0, sp);
+ parsed.senders = idpart.substr(sp + 1);
+ } else {
+ parsed.id = idpart;
+ parsed.senders = 'sendrecv';
+ }
+
+ parsed.uri = parts.shift() || '';
+
+ return parsed;
+};
+
+exports.rtcpfb = function (line) {
+ var parts = line.substr(10).split(' ');
+ var parsed = {};
+ parsed.id = parts.shift();
+ parsed.type = parts.shift();
+ if (parsed.type === 'trr-int') {
+ parsed.value = parts.shift();
+ } else {
+ parsed.subtype = parts.shift() || '';
+ }
+ parsed.parameters = parts;
+ return parsed;
+};
+
+exports.candidate = function (line) {
+ var parts;
+ if (line.indexOf('a=candidate:') === 0) {
+ parts = line.substring(12).split(' ');
+ } else { // no a=candidate
+ parts = line.substring(10).split(' ');
+ }
+
+ var candidate = {
+ foundation: parts[0],
+ component: parts[1],
+ protocol: parts[2].toLowerCase(),
+ priority: parts[3],
+ ip: parts[4],
+ port: parts[5],
+ // skip parts[6] == 'typ'
+ type: parts[7],
+ generation: '0'
+ };
+
+ for (var i = 8; i < parts.length; i += 2) {
+ if (parts[i] === 'raddr') {
+ candidate.relAddr = parts[i + 1];
+ } else if (parts[i] === 'rport') {
+ candidate.relPort = parts[i + 1];
+ } else if (parts[i] === 'generation') {
+ candidate.generation = parts[i + 1];
+ } else if (parts[i] === 'tcptype') {
+ candidate.tcpType = parts[i + 1];
+ }
+ }
+
+ candidate.network = '1';
+
+ return candidate;
+};
+
+exports.sourceGroups = function (lines) {
+ var parsed = [];
+ for (var i = 0; i < lines.length; i++) {
+ var parts = lines[i].substr(13).split(' ');
+ parsed.push({
+ semantics: parts.shift(),
+ sources: parts
+ });
+ }
+ return parsed;
+};
+
+exports.sources = function (lines) {
+ // http://tools.ietf.org/html/rfc5576
+ var parsed = [];
+ var sources = {};
+ for (var i = 0; i < lines.length; i++) {
+ var parts = lines[i].substr(7).split(' ');
+ var ssrc = parts.shift();
+
+ if (!sources[ssrc]) {
+ var source = {
+ ssrc: ssrc,
+ parameters: []
+ };
+ parsed.push(source);
+
+ // Keep an index
+ sources[ssrc] = source;
+ }
+
+ parts = parts.join(' ').split(':');
+ var attribute = parts.shift();
+ var value = parts.join(':') || null;
+
+ sources[ssrc].parameters.push({
+ key: attribute,
+ value: value
+ });
+ }
+
+ return parsed;
+};
+
+exports.groups = function (lines) {
+ // http://tools.ietf.org/html/rfc5888
+ var parsed = [];
+ var parts;
+ for (var i = 0; i < lines.length; i++) {
+ parts = lines[i].substr(8).split(' ');
+ parsed.push({
+ semantics: parts.shift(),
+ contents: parts
+ });
+ }
+ return parsed;
+};
+
+exports.bandwidth = function (line) {
+ var parts = line.substr(2).split(':');
+ var parsed = {};
+ parsed.type = parts.shift();
+ parsed.bandwidth = parts.shift();
+ return parsed;
+};
+
+exports.msid = function (line) {
+ var data = line.substr(7);
+ var parts = data.split(' ');
+ return {
+ msid: data,
+ mslabel: parts[0],
+ label: parts[1]
+ };
+};
+
+},{}],170:[function(require,module,exports){
+module.exports = {
+ initiator: {
+ incoming: {
+ initiator: 'recvonly',
+ responder: 'sendonly',
+ both: 'sendrecv',
+ none: 'inactive',
+ recvonly: 'initiator',
+ sendonly: 'responder',
+ sendrecv: 'both',
+ inactive: 'none'
+ },
+ outgoing: {
+ initiator: 'sendonly',
+ responder: 'recvonly',
+ both: 'sendrecv',
+ none: 'inactive',
+ recvonly: 'responder',
+ sendonly: 'initiator',
+ sendrecv: 'both',
+ inactive: 'none'
+ }
+ },
+ responder: {
+ incoming: {
+ initiator: 'sendonly',
+ responder: 'recvonly',
+ both: 'sendrecv',
+ none: 'inactive',
+ recvonly: 'responder',
+ sendonly: 'initiator',
+ sendrecv: 'both',
+ inactive: 'none'
+ },
+ outgoing: {
+ initiator: 'recvonly',
+ responder: 'sendonly',
+ both: 'sendrecv',
+ none: 'inactive',
+ recvonly: 'initiator',
+ sendonly: 'responder',
+ sendrecv: 'both',
+ inactive: 'none'
+ }
+ }
+};
+
+},{}],171:[function(require,module,exports){
+var SENDERS = require('./senders');
+var parsers = require('./parsers');
+var idCounter = Math.random();
+
+
+exports._setIdCounter = function (counter) {
+ idCounter = counter;
+};
+
+exports.toSessionJSON = function (sdp, opts) {
+ var i;
+ var creators = opts.creators || [];
+ var role = opts.role || 'initiator';
+ var direction = opts.direction || 'outgoing';
+
+
+ // Divide the SDP into session and media sections.
+ var media = sdp.split('\r\nm=');
+ for (i = 1; i < media.length; i++) {
+ media[i] = 'm=' + media[i];
+ if (i !== media.length - 1) {
+ media[i] += '\r\n';
+ }
+ }
+ var session = media.shift() + '\r\n';
+ var sessionLines = parsers.lines(session);
+ var parsed = {};
+
+ var contents = [];
+ for (i = 0; i < media.length; i++) {
+ contents.push(exports.toMediaJSON(media[i], session, {
+ role: role,
+ direction: direction,
+ creator: creators[i] || 'initiator'
+ }));
+ }
+ parsed.contents = contents;
+
+ var groupLines = parsers.findLines('a=group:', sessionLines);
+ if (groupLines.length) {
+ parsed.groups = parsers.groups(groupLines);
+ }
+
+ return parsed;
+};
+
+exports.toMediaJSON = function (media, session, opts) {
+ var creator = opts.creator || 'initiator';
+ var role = opts.role || 'initiator';
+ var direction = opts.direction || 'outgoing';
+
+ var lines = parsers.lines(media);
+ var sessionLines = parsers.lines(session);
+ var mline = parsers.mline(lines[0]);
+
+ var content = {
+ creator: creator,
+ name: mline.media,
+ application: {
+ applicationType: 'rtp',
+ media: mline.media,
+ payloads: [],
+ encryption: [],
+ feedback: [],
+ headerExtensions: []
+ },
+ transport: {
+ transportType: 'iceUdp',
+ candidates: [],
+ fingerprints: []
+ }
+ };
+ if (mline.media == 'application') {
+ // FIXME: the description is most likely to be independent
+ // of the SDP and should be processed by other parts of the library
+ content.application = {
+ applicationType: 'datachannel'
+ };
+ content.transport.sctp = [];
+ }
+ var desc = content.application;
+ var trans = content.transport;
+
+ // If we have a mid, use that for the content name instead.
+ var mid = parsers.findLine('a=mid:', lines);
+ if (mid) {
+ content.name = mid.substr(6);
+ }
+
+ if (parsers.findLine('a=sendrecv', lines, sessionLines)) {
+ content.senders = 'both';
+ } else if (parsers.findLine('a=sendonly', lines, sessionLines)) {
+ content.senders = SENDERS[role][direction].sendonly;
+ } else if (parsers.findLine('a=recvonly', lines, sessionLines)) {
+ content.senders = SENDERS[role][direction].recvonly;
+ } else if (parsers.findLine('a=inactive', lines, sessionLines)) {
+ content.senders = 'none';
+ }
+
+ if (desc.applicationType == 'rtp') {
+ var bandwidth = parsers.findLine('b=', lines);
+ if (bandwidth) {
+ desc.bandwidth = parsers.bandwidth(bandwidth);
+ }
+
+ var ssrc = parsers.findLine('a=ssrc:', lines);
+ if (ssrc) {
+ desc.ssrc = ssrc.substr(7).split(' ')[0];
+ }
+
+ var rtpmapLines = parsers.findLines('a=rtpmap:', lines);
+ rtpmapLines.forEach(function (line) {
+ var payload = parsers.rtpmap(line);
+ payload.parameters = [];
+ payload.feedback = [];
+
+ var fmtpLines = parsers.findLines('a=fmtp:' + payload.id, lines);
+ // There should only be one fmtp line per payload
+ fmtpLines.forEach(function (line) {
+ payload.parameters = parsers.fmtp(line);
+ });
+
+ var fbLines = parsers.findLines('a=rtcp-fb:' + payload.id, lines);
+ fbLines.forEach(function (line) {
+ payload.feedback.push(parsers.rtcpfb(line));
+ });
+
+ desc.payloads.push(payload);
+ });
+
+ var cryptoLines = parsers.findLines('a=crypto:', lines, sessionLines);
+ cryptoLines.forEach(function (line) {
+ desc.encryption.push(parsers.crypto(line));
+ });
+
+ if (parsers.findLine('a=rtcp-mux', lines)) {
+ desc.mux = true;
+ }
+
+ var fbLines = parsers.findLines('a=rtcp-fb:*', lines);
+ fbLines.forEach(function (line) {
+ desc.feedback.push(parsers.rtcpfb(line));
+ });
+
+ var extLines = parsers.findLines('a=extmap:', lines);
+ extLines.forEach(function (line) {
+ var ext = parsers.extmap(line);
+
+ ext.senders = SENDERS[role][direction][ext.senders];
+
+ desc.headerExtensions.push(ext);
+ });
+
+ var ssrcGroupLines = parsers.findLines('a=ssrc-group:', lines);
+ desc.sourceGroups = parsers.sourceGroups(ssrcGroupLines || []);
+
+ var ssrcLines = parsers.findLines('a=ssrc:', lines);
+ var sources = desc.sources = parsers.sources(ssrcLines || []);
+
+ var msidLine = parsers.findLine('a=msid:', lines);
+ if (msidLine) {
+ var msid = parsers.msid(msidLine);
+ ['msid', 'mslabel', 'label'].forEach(function (key) {
+ for (var i = 0; i < sources.length; i++) {
+ var found = false;
+ for (var j = 0; j < sources[i].parameters.length; j++) {
+ if (sources[i].parameters[j].key === key) {
+ found = true;
+ }
+ }
+ if (!found) {
+ sources[i].parameters.push({ key: key, value: msid[key] });
+ }
+ }
+ });
+ }
+
+ if (parsers.findLine('a=x-google-flag:conference', lines, sessionLines)) {
+ desc.googConferenceFlag = true;
+ }
+ }
+
+ // transport specific attributes
+ var fingerprintLines = parsers.findLines('a=fingerprint:', lines, sessionLines);
+ var setup = parsers.findLine('a=setup:', lines, sessionLines);
+ fingerprintLines.forEach(function (line) {
+ var fp = parsers.fingerprint(line);
+ if (setup) {
+ fp.setup = setup.substr(8);
+ }
+ trans.fingerprints.push(fp);
+ });
+
+ var ufragLine = parsers.findLine('a=ice-ufrag:', lines, sessionLines);
+ var pwdLine = parsers.findLine('a=ice-pwd:', lines, sessionLines);
+ if (ufragLine && pwdLine) {
+ trans.ufrag = ufragLine.substr(12);
+ trans.pwd = pwdLine.substr(10);
+ trans.candidates = [];
+
+ var candidateLines = parsers.findLines('a=candidate:', lines, sessionLines);
+ candidateLines.forEach(function (line) {
+ trans.candidates.push(exports.toCandidateJSON(line));
+ });
+ }
+
+ if (desc.applicationType == 'datachannel') {
+ var sctpmapLines = parsers.findLines('a=sctpmap:', lines);
+ sctpmapLines.forEach(function (line) {
+ var sctp = parsers.sctpmap(line);
+ trans.sctp.push(sctp);
+ });
+ }
+
+ return content;
+};
+
+exports.toCandidateJSON = function (line) {
+ var candidate = parsers.candidate(line.split('\r\n')[0]);
+ candidate.id = (idCounter++).toString(36).substr(0, 12);
+ return candidate;
+};
+
+},{"./parsers":169,"./senders":170}],172:[function(require,module,exports){
+var SENDERS = require('./senders');
+
+
+exports.toSessionSDP = function (session, opts) {
+ var role = opts.role || 'initiator';
+ var direction = opts.direction || 'outgoing';
+ var sid = opts.sid || session.sid || Date.now();
+ var time = opts.time || Date.now();
+
+ var sdp = [
+ 'v=0',
+ 'o=- ' + sid + ' ' + time + ' IN IP4 0.0.0.0',
+ 's=-',
+ 't=0 0'
+ ];
+
+ var contents = session.contents || [];
+ var hasSources = false;
+ contents.forEach(function (content) {
+ if (content.application.sources &&
+ content.application.sources.length) {
+ hasSources = true;
+ }
+ });
+
+ if (hasSources) {
+ sdp.push('a=msid-semantic: WMS *');
+ }
+
+ var groups = session.groups || [];
+ groups.forEach(function (group) {
+ sdp.push('a=group:' + group.semantics + ' ' + group.contents.join(' '));
+ });
+
+
+ contents.forEach(function (content) {
+ sdp.push(exports.toMediaSDP(content, opts));
+ });
+
+ return sdp.join('\r\n') + '\r\n';
+};
+
+exports.toMediaSDP = function (content, opts) {
+ var sdp = [];
+
+ var role = opts.role || 'initiator';
+ var direction = opts.direction || 'outgoing';
+
+ var desc = content.application;
+ var transport = content.transport;
+ var payloads = desc.payloads || [];
+ var fingerprints = (transport && transport.fingerprints) || [];
+
+ var mline = [];
+ if (desc.applicationType == 'datachannel') {
+ mline.push('application');
+ mline.push('1');
+ mline.push('DTLS/SCTP');
+ if (transport.sctp) {
+ transport.sctp.forEach(function (map) {
+ mline.push(map.number);
+ });
+ }
+ } else {
+ mline.push(desc.media);
+ mline.push('1');
+ if (fingerprints.length > 0) {
+ mline.push('UDP/TLS/RTP/SAVPF');
+ } else if (desc.encryption && desc.encryption.length > 0) {
+ mline.push('RTP/SAVPF');
+ } else {
+ mline.push('RTP/AVPF');
+ }
+ payloads.forEach(function (payload) {
+ mline.push(payload.id);
+ });
+ }
+
+
+ sdp.push('m=' + mline.join(' '));
+
+ sdp.push('c=IN IP4 0.0.0.0');
+ if (desc.bandwidth && desc.bandwidth.type && desc.bandwidth.bandwidth) {
+ sdp.push('b=' + desc.bandwidth.type + ':' + desc.bandwidth.bandwidth);
+ }
+ if (desc.applicationType == 'rtp') {
+ sdp.push('a=rtcp:1 IN IP4 0.0.0.0');
+ }
+
+ if (transport) {
+ if (transport.ufrag) {
+ sdp.push('a=ice-ufrag:' + transport.ufrag);
+ }
+ if (transport.pwd) {
+ sdp.push('a=ice-pwd:' + transport.pwd);
+ }
+
+ var pushedSetup = false;
+ fingerprints.forEach(function (fingerprint) {
+ sdp.push('a=fingerprint:' + fingerprint.hash + ' ' + fingerprint.value);
+ if (fingerprint.setup && !pushedSetup) {
+ sdp.push('a=setup:' + fingerprint.setup);
+ }
+ });
+
+ if (transport.sctp) {
+ transport.sctp.forEach(function (map) {
+ sdp.push('a=sctpmap:' + map.number + ' ' + map.protocol + ' ' + map.streams);
+ });
+ }
+ }
+
+ if (desc.applicationType == 'rtp') {
+ sdp.push('a=' + (SENDERS[role][direction][content.senders] || 'sendrecv'));
+ }
+ sdp.push('a=mid:' + content.name);
+
+ if (desc.sources && desc.sources.length) {
+ (desc.sources[0].parameters || []).forEach(function (param) {
+ if (param.key === 'msid') {
+ sdp.push('a=msid:' + param.value);
+ }
+ });
+ }
+
+ if (desc.mux) {
+ sdp.push('a=rtcp-mux');
+ }
+
+ var encryption = desc.encryption || [];
+ encryption.forEach(function (crypto) {
+ sdp.push('a=crypto:' + crypto.tag + ' ' + crypto.cipherSuite + ' ' + crypto.keyParams + (crypto.sessionParams ? ' ' + crypto.sessionParams : ''));
+ });
+ if (desc.googConferenceFlag) {
+ sdp.push('a=x-google-flag:conference');
+ }
+
+ payloads.forEach(function (payload) {
+ var rtpmap = 'a=rtpmap:' + payload.id + ' ' + payload.name + '/' + payload.clockrate;
+ if (payload.channels && payload.channels != '1') {
+ rtpmap += '/' + payload.channels;
+ }
+ sdp.push(rtpmap);
+
+ if (payload.parameters && payload.parameters.length) {
+ var fmtp = ['a=fmtp:' + payload.id];
+ var parameters = [];
+ payload.parameters.forEach(function (param) {
+ parameters.push((param.key ? param.key + '=' : '') + param.value);
+ });
+ fmtp.push(parameters.join(';'));
+ sdp.push(fmtp.join(' '));
+ }
+
+ if (payload.feedback) {
+ payload.feedback.forEach(function (fb) {
+ if (fb.type === 'trr-int') {
+ sdp.push('a=rtcp-fb:' + payload.id + ' trr-int ' + (fb.value ? fb.value : '0'));
+ } else {
+ sdp.push('a=rtcp-fb:' + payload.id + ' ' + fb.type + (fb.subtype ? ' ' + fb.subtype : ''));
+ }
+ });
+ }
+ });
+
+ if (desc.feedback) {
+ desc.feedback.forEach(function (fb) {
+ if (fb.type === 'trr-int') {
+ sdp.push('a=rtcp-fb:* trr-int ' + (fb.value ? fb.value : '0'));
+ } else {
+ sdp.push('a=rtcp-fb:* ' + fb.type + (fb.subtype ? ' ' + fb.subtype : ''));
+ }
+ });
+ }
+
+ var hdrExts = desc.headerExtensions || [];
+ hdrExts.forEach(function (hdr) {
+ sdp.push('a=extmap:' + hdr.id + (hdr.senders ? '/' + SENDERS[role][direction][hdr.senders] : '') + ' ' + hdr.uri);
+ });
+
+ var ssrcGroups = desc.sourceGroups || [];
+ ssrcGroups.forEach(function (ssrcGroup) {
+ sdp.push('a=ssrc-group:' + ssrcGroup.semantics + ' ' + ssrcGroup.sources.join(' '));
+ });
+
+ var ssrcs = desc.sources || [];
+ ssrcs.forEach(function (ssrc) {
+ for (var i = 0; i < ssrc.parameters.length; i++) {
+ var param = ssrc.parameters[i];
+ sdp.push('a=ssrc:' + (ssrc.ssrc || desc.ssrc) + ' ' + param.key + (param.value ? (':' + param.value) : ''));
+ }
+ });
+
+ var candidates = transport.candidates || [];
+ candidates.forEach(function (candidate) {
+ sdp.push(exports.toCandidateSDP(candidate));
+ });
+
+ return sdp.join('\r\n');
+};
+
+exports.toCandidateSDP = function (candidate) {
+ var sdp = [];
+
+ sdp.push(candidate.foundation);
+ sdp.push(candidate.component);
+ sdp.push(candidate.protocol.toUpperCase());
+ sdp.push(candidate.priority);
+ sdp.push(candidate.ip);
+ sdp.push(candidate.port);
+
+ var type = candidate.type;
+ sdp.push('typ');
+ sdp.push(type);
+ if (type === 'srflx' || type === 'prflx' || type === 'relay') {
+ if (candidate.relAddr && candidate.relPort) {
+ sdp.push('raddr');
+ sdp.push(candidate.relAddr);
+ sdp.push('rport');
+ sdp.push(candidate.relPort);
+ }
+ }
+ if (candidate.tcpType && candidate.protocol.toUpperCase() == 'TCP') {
+ sdp.push('tcptype');
+ sdp.push(candidate.tcpType);
+ }
+
+ sdp.push('generation');
+ sdp.push(candidate.generation || '0');
+
+ // FIXME: apparently this is wrong per spec
+ // but then, we need this when actually putting this into
+ // SDP so it's going to stay.
+ // decision needs to be revisited when browsers dont
+ // accept this any longer
+ return 'a=candidate:' + sdp.join(' ');
+};
+
+},{"./senders":170}],173:[function(require,module,exports){
+ /* eslint-env node */
+'use strict';
+
+// SDP helpers.
+var SDPUtils = {};
+
+// Generate an alphanumeric identifier for cname or mids.
+// TODO: use UUIDs instead? https://gist.github.com/jed/982883
+SDPUtils.generateIdentifier = function() {
+ return Math.random().toString(36).substr(2, 10);
+};
+
+// The RTCP CNAME used by all peerconnections from the same JS.
+SDPUtils.localCName = SDPUtils.generateIdentifier();
+
+// Splits SDP into lines, dealing with both CRLF and LF.
+SDPUtils.splitLines = function(blob) {
+ return blob.trim().split('\n').map(function(line) {
+ return line.trim();
+ });
+};
+// Splits SDP into sessionpart and mediasections. Ensures CRLF.
+SDPUtils.splitSections = function(blob) {
+ var parts = blob.split('\nm=');
+ return parts.map(function(part, index) {
+ return (index > 0 ? 'm=' + part : part).trim() + '\r\n';
+ });
+};
+
+// Returns lines that start with a certain prefix.
+SDPUtils.matchPrefix = function(blob, prefix) {
+ return SDPUtils.splitLines(blob).filter(function(line) {
+ return line.indexOf(prefix) === 0;
+ });
+};
+
+// Parses an ICE candidate line. Sample input:
+// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8
+// rport 55996"
+SDPUtils.parseCandidate = function(line) {
+ var parts;
+ // Parse both variants.
+ if (line.indexOf('a=candidate:') === 0) {
+ parts = line.substring(12).split(' ');
+ } else {
+ parts = line.substring(10).split(' ');
+ }
+
+ var candidate = {
+ foundation: parts[0],
+ component: parts[1],
+ protocol: parts[2].toLowerCase(),
+ priority: parseInt(parts[3], 10),
+ ip: parts[4],
+ port: parseInt(parts[5], 10),
+ // skip parts[6] == 'typ'
+ type: parts[7]
+ };
+
+ for (var i = 8; i < parts.length; i += 2) {
+ switch (parts[i]) {
+ case 'raddr':
+ candidate.relatedAddress = parts[i + 1];
+ break;
+ case 'rport':
+ candidate.relatedPort = parseInt(parts[i + 1], 10);
+ break;
+ case 'tcptype':
+ candidate.tcpType = parts[i + 1];
+ break;
+ default: // Unknown extensions are silently ignored.
+ break;
+ }
+ }
+ return candidate;
+};
+
+// Translates a candidate object into SDP candidate attribute.
+SDPUtils.writeCandidate = function(candidate) {
+ var sdp = [];
+ sdp.push(candidate.foundation);
+ sdp.push(candidate.component);
+ sdp.push(candidate.protocol.toUpperCase());
+ sdp.push(candidate.priority);
+ sdp.push(candidate.ip);
+ sdp.push(candidate.port);
+
+ var type = candidate.type;
+ sdp.push('typ');
+ sdp.push(type);
+ if (type !== 'host' && candidate.relatedAddress &&
+ candidate.relatedPort) {
+ sdp.push('raddr');
+ sdp.push(candidate.relatedAddress); // was: relAddr
+ sdp.push('rport');
+ sdp.push(candidate.relatedPort); // was: relPort
+ }
+ if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {
+ sdp.push('tcptype');
+ sdp.push(candidate.tcpType);
+ }
+ return 'candidate:' + sdp.join(' ');
+};
+
+// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input:
+// a=rtpmap:111 opus/48000/2
+SDPUtils.parseRtpMap = function(line) {
+ var parts = line.substr(9).split(' ');
+ var parsed = {
+ payloadType: parseInt(parts.shift(), 10) // was: id
+ };
+
+ parts = parts[0].split('/');
+
+ parsed.name = parts[0];
+ parsed.clockRate = parseInt(parts[1], 10); // was: clockrate
+ // was: channels
+ parsed.numChannels = parts.length === 3 ? parseInt(parts[2], 10) : 1;
+ return parsed;
+};
+
+// Generate an a=rtpmap line from RTCRtpCodecCapability or
+// RTCRtpCodecParameters.
+SDPUtils.writeRtpMap = function(codec) {
+ var pt = codec.payloadType;
+ if (codec.preferredPayloadType !== undefined) {
+ pt = codec.preferredPayloadType;
+ }
+ return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate +
+ (codec.numChannels !== 1 ? '/' + codec.numChannels : '') + '\r\n';
+};
+
+// Parses an a=extmap line (headerextension from RFC 5285). Sample input:
+// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
+SDPUtils.parseExtmap = function(line) {
+ var parts = line.substr(9).split(' ');
+ return {
+ id: parseInt(parts[0], 10),
+ uri: parts[1]
+ };
+};
+
+// Generates a=extmap line from RTCRtpHeaderExtensionParameters or
+// RTCRtpHeaderExtension.
+SDPUtils.writeExtmap = function(headerExtension) {
+ return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) +
+ ' ' + headerExtension.uri + '\r\n';
+};
+
+// Parses an ftmp line, returns dictionary. Sample input:
+// a=fmtp:96 vbr=on;cng=on
+// Also deals with vbr=on; cng=on
+SDPUtils.parseFmtp = function(line) {
+ var parsed = {};
+ var kv;
+ var parts = line.substr(line.indexOf(' ') + 1).split(';');
+ for (var j = 0; j < parts.length; j++) {
+ kv = parts[j].trim().split('=');
+ parsed[kv[0].trim()] = kv[1];
+ }
+ return parsed;
+};
+
+// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters.
+SDPUtils.writeFmtp = function(codec) {
+ var line = '';
+ var pt = codec.payloadType;
+ if (codec.preferredPayloadType !== undefined) {
+ pt = codec.preferredPayloadType;
+ }
+ if (codec.parameters && Object.keys(codec.parameters).length) {
+ var params = [];
+ Object.keys(codec.parameters).forEach(function(param) {
+ params.push(param + '=' + codec.parameters[param]);
+ });
+ line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n';
+ }
+ return line;
+};
+
+// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:
+// a=rtcp-fb:98 nack rpsi
+SDPUtils.parseRtcpFb = function(line) {
+ var parts = line.substr(line.indexOf(' ') + 1).split(' ');
+ return {
+ type: parts.shift(),
+ parameter: parts.join(' ')
+ };
+};
+// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.
+SDPUtils.writeRtcpFb = function(codec) {
+ var lines = '';
+ var pt = codec.payloadType;
+ if (codec.preferredPayloadType !== undefined) {
+ pt = codec.preferredPayloadType;
+ }
+ if (codec.rtcpFeedback && codec.rtcpFeedback.length) {
+ // FIXME: special handling for trr-int?
+ codec.rtcpFeedback.forEach(function(fb) {
+ lines += 'a=rtcp-fb:' + pt + ' ' + fb.type +
+ (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') +
+ '\r\n';
+ });
+ }
+ return lines;
+};
+
+// Parses an RFC 5576 ssrc media attribute. Sample input:
+// a=ssrc:3735928559 cname:something
+SDPUtils.parseSsrcMedia = function(line) {
+ var sp = line.indexOf(' ');
+ var parts = {
+ ssrc: parseInt(line.substr(7, sp - 7), 10)
+ };
+ var colon = line.indexOf(':', sp);
+ if (colon > -1) {
+ parts.attribute = line.substr(sp + 1, colon - sp - 1);
+ parts.value = line.substr(colon + 1);
+ } else {
+ parts.attribute = line.substr(sp + 1);
+ }
+ return parts;
+};
+
+// Extracts DTLS parameters from SDP media section or sessionpart.
+// FIXME: for consistency with other functions this should only
+// get the fingerprint line as input. See also getIceParameters.
+SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) {
+ var lines = SDPUtils.splitLines(mediaSection);
+ // Search in session part, too.
+ lines = lines.concat(SDPUtils.splitLines(sessionpart));
+ var fpLine = lines.filter(function(line) {
+ return line.indexOf('a=fingerprint:') === 0;
+ })[0].substr(14);
+ // Note: a=setup line is ignored since we use the 'auto' role.
+ var dtlsParameters = {
+ role: 'auto',
+ fingerprints: [{
+ algorithm: fpLine.split(' ')[0],
+ value: fpLine.split(' ')[1]
+ }]
+ };
+ return dtlsParameters;
+};
+
+// Serializes DTLS parameters to SDP.
+SDPUtils.writeDtlsParameters = function(params, setupType) {
+ var sdp = 'a=setup:' + setupType + '\r\n';
+ params.fingerprints.forEach(function(fp) {
+ sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n';
+ });
+ return sdp;
+};
+// Parses ICE information from SDP media section or sessionpart.
+// FIXME: for consistency with other functions this should only
+// get the ice-ufrag and ice-pwd lines as input.
+SDPUtils.getIceParameters = function(mediaSection, sessionpart) {
+ var lines = SDPUtils.splitLines(mediaSection);
+ // Search in session part, too.
+ lines = lines.concat(SDPUtils.splitLines(sessionpart));
+ var iceParameters = {
+ usernameFragment: lines.filter(function(line) {
+ return line.indexOf('a=ice-ufrag:') === 0;
+ })[0].substr(12),
+ password: lines.filter(function(line) {
+ return line.indexOf('a=ice-pwd:') === 0;
+ })[0].substr(10)
+ };
+ return iceParameters;
+};
+
+// Serializes ICE parameters to SDP.
+SDPUtils.writeIceParameters = function(params) {
+ return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' +
+ 'a=ice-pwd:' + params.password + '\r\n';
+};
+
+// Parses the SDP media section and returns RTCRtpParameters.
+SDPUtils.parseRtpParameters = function(mediaSection) {
+ var description = {
+ codecs: [],
+ headerExtensions: [],
+ fecMechanisms: [],
+ rtcp: []
+ };
+ var lines = SDPUtils.splitLines(mediaSection);
+ var mline = lines[0].split(' ');
+ for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..]
+ var pt = mline[i];
+ var rtpmapline = SDPUtils.matchPrefix(
+ mediaSection, 'a=rtpmap:' + pt + ' ')[0];
+ if (rtpmapline) {
+ var codec = SDPUtils.parseRtpMap(rtpmapline);
+ var fmtps = SDPUtils.matchPrefix(
+ mediaSection, 'a=fmtp:' + pt + ' ');
+ // Only the first a=fmtp:<pt> is considered.
+ codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};
+ codec.rtcpFeedback = SDPUtils.matchPrefix(
+ mediaSection, 'a=rtcp-fb:' + pt + ' ')
+ .map(SDPUtils.parseRtcpFb);
+ description.codecs.push(codec);
+ // parse FEC mechanisms from rtpmap lines.
+ switch (codec.name.toUpperCase()) {
+ case 'RED':
+ case 'ULPFEC':
+ description.fecMechanisms.push(codec.name.toUpperCase());
+ break;
+ default: // only RED and ULPFEC are recognized as FEC mechanisms.
+ break;
+ }
+ }
+ }
+ SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) {
+ description.headerExtensions.push(SDPUtils.parseExtmap(line));
+ });
+ // FIXME: parse rtcp.
+ return description;
+};
+
+// Generates parts of the SDP media section describing the capabilities /
+// parameters.
+SDPUtils.writeRtpDescription = function(kind, caps) {
+ var sdp = '';
+
+ // Build the mline.
+ sdp += 'm=' + kind + ' ';
+ sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.
+ sdp += ' UDP/TLS/RTP/SAVPF ';
+ sdp += caps.codecs.map(function(codec) {
+ if (codec.preferredPayloadType !== undefined) {
+ return codec.preferredPayloadType;
+ }
+ return codec.payloadType;
+ }).join(' ') + '\r\n';
+
+ sdp += 'c=IN IP4 0.0.0.0\r\n';
+ sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n';
+
+ // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.
+ caps.codecs.forEach(function(codec) {
+ sdp += SDPUtils.writeRtpMap(codec);
+ sdp += SDPUtils.writeFmtp(codec);
+ sdp += SDPUtils.writeRtcpFb(codec);
+ });
+ // FIXME: add headerExtensions, fecMechanismş and rtcp.
+ sdp += 'a=rtcp-mux\r\n';
+ return sdp;
+};
+
+// Parses the SDP media section and returns an array of
+// RTCRtpEncodingParameters.
+SDPUtils.parseRtpEncodingParameters = function(mediaSection) {
+ var encodingParameters = [];
+ var description = SDPUtils.parseRtpParameters(mediaSection);
+ var hasRed = description.fecMechanisms.indexOf('RED') !== -1;
+ var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;
+
+ // filter a=ssrc:... cname:, ignore PlanB-msid
+ var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
+ .map(function(line) {
+ return SDPUtils.parseSsrcMedia(line);
+ })
+ .filter(function(parts) {
+ return parts.attribute === 'cname';
+ });
+ var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;
+ var secondarySsrc;
+
+ var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID')
+ .map(function(line) {
+ var parts = line.split(' ');
+ parts.shift();
+ return parts.map(function(part) {
+ return parseInt(part, 10);
+ });
+ });
+ if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {
+ secondarySsrc = flows[0][1];
+ }
+
+ description.codecs.forEach(function(codec) {
+ if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {
+ var encParam = {
+ ssrc: primarySsrc,
+ codecPayloadType: parseInt(codec.parameters.apt, 10),
+ rtx: {
+ payloadType: codec.payloadType,
+ ssrc: secondarySsrc
+ }
+ };
+ encodingParameters.push(encParam);
+ if (hasRed) {
+ encParam = JSON.parse(JSON.stringify(encParam));
+ encParam.fec = {
+ ssrc: secondarySsrc,
+ mechanism: hasUlpfec ? 'red+ulpfec' : 'red'
+ };
+ encodingParameters.push(encParam);
+ }
+ }
+ });
+ if (encodingParameters.length === 0 && primarySsrc) {
+ encodingParameters.push({
+ ssrc: primarySsrc
+ });
+ }
+
+ // we support both b=AS and b=TIAS but interpret AS as TIAS.
+ var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');
+ if (bandwidth.length) {
+ if (bandwidth[0].indexOf('b=TIAS:') === 0) {
+ bandwidth = parseInt(bandwidth[0].substr(7), 10);
+ } else if (bandwidth[0].indexOf('b=AS:') === 0) {
+ bandwidth = parseInt(bandwidth[0].substr(5), 10);
+ }
+ encodingParameters.forEach(function(params) {
+ params.maxBitrate = bandwidth;
+ });
+ }
+ return encodingParameters;
+};
+
+SDPUtils.writeSessionBoilerplate = function() {
+ // FIXME: sess-id should be an NTP timestamp.
+ return 'v=0\r\n' +
+ 'o=thisisadapterortc 8169639915646943137 2 IN IP4 127.0.0.1\r\n' +
+ 's=-\r\n' +
+ 't=0 0\r\n';
+};
+
+SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) {
+ var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps);
+
+ // Map ICE parameters (ufrag, pwd) to SDP.
+ sdp += SDPUtils.writeIceParameters(
+ transceiver.iceGatherer.getLocalParameters());
+
+ // Map DTLS parameters to SDP.
+ sdp += SDPUtils.writeDtlsParameters(
+ transceiver.dtlsTransport.getLocalParameters(),
+ type === 'offer' ? 'actpass' : 'active');
+
+ sdp += 'a=mid:' + transceiver.mid + '\r\n';
+
+ if (transceiver.rtpSender && transceiver.rtpReceiver) {
+ sdp += 'a=sendrecv\r\n';
+ } else if (transceiver.rtpSender) {
+ sdp += 'a=sendonly\r\n';
+ } else if (transceiver.rtpReceiver) {
+ sdp += 'a=recvonly\r\n';
+ } else {
+ sdp += 'a=inactive\r\n';
+ }
+
+ // FIXME: for RTX there might be multiple SSRCs. Not implemented in Edge yet.
+ if (transceiver.rtpSender) {
+ var msid = 'msid:' + stream.id + ' ' +
+ transceiver.rtpSender.track.id + '\r\n';
+ sdp += 'a=' + msid;
+ sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
+ ' ' + msid;
+ }
+ // FIXME: this should be written by writeRtpDescription.
+ sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
+ ' cname:' + SDPUtils.localCName + '\r\n';
+ return sdp;
+};
+
+// Gets the direction from the mediaSection or the sessionpart.
+SDPUtils.getDirection = function(mediaSection, sessionpart) {
+ // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.
+ var lines = SDPUtils.splitLines(mediaSection);
+ for (var i = 0; i < lines.length; i++) {
+ switch (lines[i]) {
+ case 'a=sendrecv':
+ case 'a=sendonly':
+ case 'a=recvonly':
+ case 'a=inactive':
+ return lines[i].substr(2);
+ default:
+ // FIXME: What should happen here?
+ }
+ }
+ if (sessionpart) {
+ return SDPUtils.getDirection(sessionpart);
+ }
+ return 'sendrecv';
+};
+
+// Expose public methods.
+module.exports = SDPUtils;
+
+},{}],174:[function(require,module,exports){
+(function (Buffer){
+// prototype class for hash functions
+function Hash (blockSize, finalSize) {
+ this._block = new Buffer(blockSize)
+ this._finalSize = finalSize
+ this._blockSize = blockSize
+ this._len = 0
+ this._s = 0
+}
+
+Hash.prototype.update = function (data, enc) {
+ if (typeof data === 'string') {
+ enc = enc || 'utf8'
+ data = new Buffer(data, enc)
+ }
+
+ var l = this._len += data.length
+ var s = this._s || 0
+ var f = 0
+ var buffer = this._block
+
+ while (s < l) {
+ var t = Math.min(data.length, f + this._blockSize - (s % this._blockSize))
+ var ch = (t - f)
+
+ for (var i = 0; i < ch; i++) {
+ buffer[(s % this._blockSize) + i] = data[i + f]
+ }
+
+ s += ch
+ f += ch
+
+ if ((s % this._blockSize) === 0) {
+ this._update(buffer)
+ }
+ }
+ this._s = s
+
+ return this
+}
+
+Hash.prototype.digest = function (enc) {
+ // Suppose the length of the message M, in bits, is l
+ var l = this._len * 8
+
+ // Append the bit 1 to the end of the message
+ this._block[this._len % this._blockSize] = 0x80
+
+ // and then k zero bits, where k is the smallest non-negative solution to the equation (l + 1 + k) === finalSize mod blockSize
+ this._block.fill(0, this._len % this._blockSize + 1)
+
+ if (l % (this._blockSize * 8) >= this._finalSize * 8) {
+ this._update(this._block)
+ this._block.fill(0)
+ }
+
+ // to this append the block which is equal to the number l written in binary
+ // TODO: handle case where l is > Math.pow(2, 29)
+ this._block.writeInt32BE(l, this._blockSize - 4)
+
+ var hash = this._update(this._block) || this._hash()
+
+ return enc ? hash.toString(enc) : hash
+}
+
+Hash.prototype._update = function () {
+ throw new Error('_update must be implemented by subclass')
+}
+
+module.exports = Hash
+
+}).call(this,require("buffer").Buffer)
+},{"buffer":6}],175:[function(require,module,exports){
+var exports = module.exports = function SHA (algorithm) {
+ algorithm = algorithm.toLowerCase()
+
+ var Algorithm = exports[algorithm]
+ if (!Algorithm) throw new Error(algorithm + ' is not supported (we accept pull requests)')
+
+ return new Algorithm()
+}
+
+exports.sha = require('./sha')
+exports.sha1 = require('./sha1')
+exports.sha224 = require('./sha224')
+exports.sha256 = require('./sha256')
+exports.sha384 = require('./sha384')
+exports.sha512 = require('./sha512')
+
+},{"./sha":176,"./sha1":177,"./sha224":178,"./sha256":179,"./sha384":180,"./sha512":181}],176:[function(require,module,exports){
+(function (Buffer){
+/*
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-0, as defined
+ * in FIPS PUB 180-1
+ * This source code is derived from sha1.js of the same repository.
+ * The difference between SHA-0 and SHA-1 is just a bitwise rotate left
+ * operation was added.
+ */
+
+var inherits = require('inherits')
+var Hash = require('./hash')
+
+var K = [
+ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc | 0, 0xca62c1d6 | 0
+]
+
+var W = new Array(80)
+
+function Sha () {
+ this.init()
+ this._w = W
+
+ Hash.call(this, 64, 56)
+}
+
+inherits(Sha, Hash)
+
+Sha.prototype.init = function () {
+ this._a = 0x67452301
+ this._b = 0xefcdab89
+ this._c = 0x98badcfe
+ this._d = 0x10325476
+ this._e = 0xc3d2e1f0
+
+ return this
+}
+
+function rotl5 (num) {
+ return (num << 5) | (num >>> 27)
+}
+
+function rotl30 (num) {
+ return (num << 30) | (num >>> 2)
+}
+
+function ft (s, b, c, d) {
+ if (s === 0) return (b & c) | ((~b) & d)
+ if (s === 2) return (b & c) | (b & d) | (c & d)
+ return b ^ c ^ d
+}
+
+Sha.prototype._update = function (M) {
+ var W = this._w
+
+ var a = this._a | 0
+ var b = this._b | 0
+ var c = this._c | 0
+ var d = this._d | 0
+ var e = this._e | 0
+
+ for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4)
+ for (; i < 80; ++i) W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]
+
+ for (var j = 0; j < 80; ++j) {
+ var s = ~~(j / 20)
+ var t = (rotl5(a) + ft(s, b, c, d) + e + W[j] + K[s]) | 0
+
+ e = d
+ d = c
+ c = rotl30(b)
+ b = a
+ a = t
+ }
+
+ this._a = (a + this._a) | 0
+ this._b = (b + this._b) | 0
+ this._c = (c + this._c) | 0
+ this._d = (d + this._d) | 0
+ this._e = (e + this._e) | 0
+}
+
+Sha.prototype._hash = function () {
+ var H = new Buffer(20)
+
+ H.writeInt32BE(this._a | 0, 0)
+ H.writeInt32BE(this._b | 0, 4)
+ H.writeInt32BE(this._c | 0, 8)
+ H.writeInt32BE(this._d | 0, 12)
+ H.writeInt32BE(this._e | 0, 16)
+
+ return H
+}
+
+module.exports = Sha
+
+}).call(this,require("buffer").Buffer)
+},{"./hash":174,"buffer":6,"inherits":45}],177:[function(require,module,exports){
+(function (Buffer){
+/*
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
+ * in FIPS PUB 180-1
+ * Version 2.1a Copyright Paul Johnston 2000 - 2002.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for details.
+ */
+
+var inherits = require('inherits')
+var Hash = require('./hash')
+
+var K = [
+ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc | 0, 0xca62c1d6 | 0
+]
+
+var W = new Array(80)
+
+function Sha1 () {
+ this.init()
+ this._w = W
+
+ Hash.call(this, 64, 56)
+}
+
+inherits(Sha1, Hash)
+
+Sha1.prototype.init = function () {
+ this._a = 0x67452301
+ this._b = 0xefcdab89
+ this._c = 0x98badcfe
+ this._d = 0x10325476
+ this._e = 0xc3d2e1f0
+
+ return this
+}
+
+function rotl1 (num) {
+ return (num << 1) | (num >>> 31)
+}
+
+function rotl5 (num) {
+ return (num << 5) | (num >>> 27)
+}
+
+function rotl30 (num) {
+ return (num << 30) | (num >>> 2)
+}
+
+function ft (s, b, c, d) {
+ if (s === 0) return (b & c) | ((~b) & d)
+ if (s === 2) return (b & c) | (b & d) | (c & d)
+ return b ^ c ^ d
+}
+
+Sha1.prototype._update = function (M) {
+ var W = this._w
+
+ var a = this._a | 0
+ var b = this._b | 0
+ var c = this._c | 0
+ var d = this._d | 0
+ var e = this._e | 0
+
+ for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4)
+ for (; i < 80; ++i) W[i] = rotl1(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16])
+
+ for (var j = 0; j < 80; ++j) {
+ var s = ~~(j / 20)
+ var t = (rotl5(a) + ft(s, b, c, d) + e + W[j] + K[s]) | 0
+
+ e = d
+ d = c
+ c = rotl30(b)
+ b = a
+ a = t
+ }
+
+ this._a = (a + this._a) | 0
+ this._b = (b + this._b) | 0
+ this._c = (c + this._c) | 0
+ this._d = (d + this._d) | 0
+ this._e = (e + this._e) | 0
+}
+
+Sha1.prototype._hash = function () {
+ var H = new Buffer(20)
+
+ H.writeInt32BE(this._a | 0, 0)
+ H.writeInt32BE(this._b | 0, 4)
+ H.writeInt32BE(this._c | 0, 8)
+ H.writeInt32BE(this._d | 0, 12)
+ H.writeInt32BE(this._e | 0, 16)
+
+ return H
+}
+
+module.exports = Sha1
+
+}).call(this,require("buffer").Buffer)
+},{"./hash":174,"buffer":6,"inherits":45}],178:[function(require,module,exports){
+(function (Buffer){
/**
- * The only (relevant) data structure
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
+ * in FIPS 180-2
+ * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ *
*/
-exports.Element = require('./dom-element')
+var inherits = require('inherits')
+var Sha256 = require('./sha256')
+var Hash = require('./hash')
+
+var W = new Array(64)
+
+function Sha224 () {
+ this.init()
+
+ this._w = W // new Array(64)
+
+ Hash.call(this, 64, 56)
+}
+
+inherits(Sha224, Sha256)
+
+Sha224.prototype.init = function () {
+ this._a = 0xc1059ed8
+ this._b = 0x367cd507
+ this._c = 0x3070dd17
+ this._d = 0xf70e5939
+ this._e = 0xffc00b31
+ this._f = 0x68581511
+ this._g = 0x64f98fa7
+ this._h = 0xbefa4fa4
+
+ return this
+}
+
+Sha224.prototype._hash = function () {
+ var H = new Buffer(28)
+
+ H.writeInt32BE(this._a, 0)
+ H.writeInt32BE(this._b, 4)
+ H.writeInt32BE(this._c, 8)
+ H.writeInt32BE(this._d, 12)
+ H.writeInt32BE(this._e, 16)
+ H.writeInt32BE(this._f, 20)
+ H.writeInt32BE(this._g, 24)
+
+ return H
+}
+
+module.exports = Sha224
+
+}).call(this,require("buffer").Buffer)
+},{"./hash":174,"./sha256":179,"buffer":6,"inherits":45}],179:[function(require,module,exports){
+(function (Buffer){
/**
- * Helper
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
+ * in FIPS 180-2
+ * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ *
*/
-exports.escapeXml = require('./element').escapeXml
+
+var inherits = require('inherits')
+var Hash = require('./hash')
+
+var K = [
+ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+ 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+ 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+ 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+ 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+ 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+ 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+ 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+ 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+ 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+ 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+ 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+ 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+ 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+ 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+ 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
+]
+
+var W = new Array(64)
+
+function Sha256 () {
+ this.init()
+
+ this._w = W // new Array(64)
+
+ Hash.call(this, 64, 56)
+}
+
+inherits(Sha256, Hash)
+
+Sha256.prototype.init = function () {
+ this._a = 0x6a09e667
+ this._b = 0xbb67ae85
+ this._c = 0x3c6ef372
+ this._d = 0xa54ff53a
+ this._e = 0x510e527f
+ this._f = 0x9b05688c
+ this._g = 0x1f83d9ab
+ this._h = 0x5be0cd19
+
+ return this
+}
+
+function ch (x, y, z) {
+ return z ^ (x & (y ^ z))
+}
+
+function maj (x, y, z) {
+ return (x & y) | (z & (x | y))
+}
+
+function sigma0 (x) {
+ return (x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10)
+}
+
+function sigma1 (x) {
+ return (x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7)
+}
+
+function gamma0 (x) {
+ return (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ (x >>> 3)
+}
+
+function gamma1 (x) {
+ return (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ (x >>> 10)
+}
+
+Sha256.prototype._update = function (M) {
+ var W = this._w
+
+ var a = this._a | 0
+ var b = this._b | 0
+ var c = this._c | 0
+ var d = this._d | 0
+ var e = this._e | 0
+ var f = this._f | 0
+ var g = this._g | 0
+ var h = this._h | 0
+
+ for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4)
+ for (; i < 64; ++i) W[i] = (gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16]) | 0
+
+ for (var j = 0; j < 64; ++j) {
+ var T1 = (h + sigma1(e) + ch(e, f, g) + K[j] + W[j]) | 0
+ var T2 = (sigma0(a) + maj(a, b, c)) | 0
+
+ h = g
+ g = f
+ f = e
+ e = (d + T1) | 0
+ d = c
+ c = b
+ b = a
+ a = (T1 + T2) | 0
+ }
+
+ this._a = (a + this._a) | 0
+ this._b = (b + this._b) | 0
+ this._c = (c + this._c) | 0
+ this._d = (d + this._d) | 0
+ this._e = (e + this._e) | 0
+ this._f = (f + this._f) | 0
+ this._g = (g + this._g) | 0
+ this._h = (h + this._h) | 0
+}
+
+Sha256.prototype._hash = function () {
+ var H = new Buffer(32)
+
+ H.writeInt32BE(this._a, 0)
+ H.writeInt32BE(this._b, 4)
+ H.writeInt32BE(this._c, 8)
+ H.writeInt32BE(this._d, 12)
+ H.writeInt32BE(this._e, 16)
+ H.writeInt32BE(this._f, 20)
+ H.writeInt32BE(this._g, 24)
+ H.writeInt32BE(this._h, 28)
+
+ return H
+}
+
+module.exports = Sha256
+
+}).call(this,require("buffer").Buffer)
+},{"./hash":174,"buffer":6,"inherits":45}],180:[function(require,module,exports){
+(function (Buffer){
+var inherits = require('inherits')
+var SHA512 = require('./sha512')
+var Hash = require('./hash')
+
+var W = new Array(160)
+
+function Sha384 () {
+ this.init()
+ this._w = W
+
+ Hash.call(this, 128, 112)
+}
+
+inherits(Sha384, SHA512)
+
+Sha384.prototype.init = function () {
+ this._ah = 0xcbbb9d5d
+ this._bh = 0x629a292a
+ this._ch = 0x9159015a
+ this._dh = 0x152fecd8
+ this._eh = 0x67332667
+ this._fh = 0x8eb44a87
+ this._gh = 0xdb0c2e0d
+ this._hh = 0x47b5481d
+
+ this._al = 0xc1059ed8
+ this._bl = 0x367cd507
+ this._cl = 0x3070dd17
+ this._dl = 0xf70e5939
+ this._el = 0xffc00b31
+ this._fl = 0x68581511
+ this._gl = 0x64f98fa7
+ this._hl = 0xbefa4fa4
+
+ return this
+}
+
+Sha384.prototype._hash = function () {
+ var H = new Buffer(48)
+
+ function writeInt64BE (h, l, offset) {
+ H.writeInt32BE(h, offset)
+ H.writeInt32BE(l, offset + 4)
+ }
+
+ writeInt64BE(this._ah, this._al, 0)
+ writeInt64BE(this._bh, this._bl, 8)
+ writeInt64BE(this._ch, this._cl, 16)
+ writeInt64BE(this._dh, this._dl, 24)
+ writeInt64BE(this._eh, this._el, 32)
+ writeInt64BE(this._fh, this._fl, 40)
+
+ return H
+}
+
+module.exports = Sha384
+
+}).call(this,require("buffer").Buffer)
+},{"./hash":174,"./sha512":181,"buffer":6,"inherits":45}],181:[function(require,module,exports){
+(function (Buffer){
+var inherits = require('inherits')
+var Hash = require('./hash')
+
+var K = [
+ 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,
+ 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
+ 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,
+ 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
+ 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,
+ 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
+ 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,
+ 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
+ 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,
+ 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
+ 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,
+ 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
+ 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,
+ 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
+ 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,
+ 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
+ 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,
+ 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
+ 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,
+ 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
+ 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,
+ 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
+ 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,
+ 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
+ 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,
+ 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
+ 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,
+ 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
+ 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,
+ 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
+ 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,
+ 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
+ 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,
+ 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
+ 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,
+ 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
+ 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,
+ 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
+ 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,
+ 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817
+]
+
+var W = new Array(160)
+
+function Sha512 () {
+ this.init()
+ this._w = W
+
+ Hash.call(this, 128, 112)
+}
+
+inherits(Sha512, Hash)
+
+Sha512.prototype.init = function () {
+ this._ah = 0x6a09e667
+ this._bh = 0xbb67ae85
+ this._ch = 0x3c6ef372
+ this._dh = 0xa54ff53a
+ this._eh = 0x510e527f
+ this._fh = 0x9b05688c
+ this._gh = 0x1f83d9ab
+ this._hh = 0x5be0cd19
+
+ this._al = 0xf3bcc908
+ this._bl = 0x84caa73b
+ this._cl = 0xfe94f82b
+ this._dl = 0x5f1d36f1
+ this._el = 0xade682d1
+ this._fl = 0x2b3e6c1f
+ this._gl = 0xfb41bd6b
+ this._hl = 0x137e2179
+
+ return this
+}
+
+function Ch (x, y, z) {
+ return z ^ (x & (y ^ z))
+}
+
+function maj (x, y, z) {
+ return (x & y) | (z & (x | y))
+}
+
+function sigma0 (x, xl) {
+ return (x >>> 28 | xl << 4) ^ (xl >>> 2 | x << 30) ^ (xl >>> 7 | x << 25)
+}
+
+function sigma1 (x, xl) {
+ return (x >>> 14 | xl << 18) ^ (x >>> 18 | xl << 14) ^ (xl >>> 9 | x << 23)
+}
+
+function Gamma0 (x, xl) {
+ return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7)
+}
+
+function Gamma0l (x, xl) {
+ return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7 | xl << 25)
+}
+
+function Gamma1 (x, xl) {
+ return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6)
+}
+
+function Gamma1l (x, xl) {
+ return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6 | xl << 26)
+}
+
+function getCarry (a, b) {
+ return (a >>> 0) < (b >>> 0) ? 1 : 0
+}
+
+Sha512.prototype._update = function (M) {
+ var W = this._w
+
+ var ah = this._ah | 0
+ var bh = this._bh | 0
+ var ch = this._ch | 0
+ var dh = this._dh | 0
+ var eh = this._eh | 0
+ var fh = this._fh | 0
+ var gh = this._gh | 0
+ var hh = this._hh | 0
+
+ var al = this._al | 0
+ var bl = this._bl | 0
+ var cl = this._cl | 0
+ var dl = this._dl | 0
+ var el = this._el | 0
+ var fl = this._fl | 0
+ var gl = this._gl | 0
+ var hl = this._hl | 0
+
+ for (var i = 0; i < 32; i += 2) {
+ W[i] = M.readInt32BE(i * 4)
+ W[i + 1] = M.readInt32BE(i * 4 + 4)
+ }
+ for (; i < 160; i += 2) {
+ var xh = W[i - 15 * 2]
+ var xl = W[i - 15 * 2 + 1]
+ var gamma0 = Gamma0(xh, xl)
+ var gamma0l = Gamma0l(xl, xh)
+
+ xh = W[i - 2 * 2]
+ xl = W[i - 2 * 2 + 1]
+ var gamma1 = Gamma1(xh, xl)
+ var gamma1l = Gamma1l(xl, xh)
+
+ // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]
+ var Wi7h = W[i - 7 * 2]
+ var Wi7l = W[i - 7 * 2 + 1]
+
+ var Wi16h = W[i - 16 * 2]
+ var Wi16l = W[i - 16 * 2 + 1]
+
+ var Wil = (gamma0l + Wi7l) | 0
+ var Wih = (gamma0 + Wi7h + getCarry(Wil, gamma0l)) | 0
+ Wil = (Wil + gamma1l) | 0
+ Wih = (Wih + gamma1 + getCarry(Wil, gamma1l)) | 0
+ Wil = (Wil + Wi16l) | 0
+ Wih = (Wih + Wi16h + getCarry(Wil, Wi16l)) | 0
+
+ W[i] = Wih
+ W[i + 1] = Wil
+ }
+
+ for (var j = 0; j < 160; j += 2) {
+ Wih = W[j]
+ Wil = W[j + 1]
+
+ var majh = maj(ah, bh, ch)
+ var majl = maj(al, bl, cl)
+
+ var sigma0h = sigma0(ah, al)
+ var sigma0l = sigma0(al, ah)
+ var sigma1h = sigma1(eh, el)
+ var sigma1l = sigma1(el, eh)
+
+ // t1 = h + sigma1 + ch + K[j] + W[j]
+ var Kih = K[j]
+ var Kil = K[j + 1]
+
+ var chh = Ch(eh, fh, gh)
+ var chl = Ch(el, fl, gl)
+
+ var t1l = (hl + sigma1l) | 0
+ var t1h = (hh + sigma1h + getCarry(t1l, hl)) | 0
+ t1l = (t1l + chl) | 0
+ t1h = (t1h + chh + getCarry(t1l, chl)) | 0
+ t1l = (t1l + Kil) | 0
+ t1h = (t1h + Kih + getCarry(t1l, Kil)) | 0
+ t1l = (t1l + Wil) | 0
+ t1h = (t1h + Wih + getCarry(t1l, Wil)) | 0
+
+ // t2 = sigma0 + maj
+ var t2l = (sigma0l + majl) | 0
+ var t2h = (sigma0h + majh + getCarry(t2l, sigma0l)) | 0
+
+ hh = gh
+ hl = gl
+ gh = fh
+ gl = fl
+ fh = eh
+ fl = el
+ el = (dl + t1l) | 0
+ eh = (dh + t1h + getCarry(el, dl)) | 0
+ dh = ch
+ dl = cl
+ ch = bh
+ cl = bl
+ bh = ah
+ bl = al
+ al = (t1l + t2l) | 0
+ ah = (t1h + t2h + getCarry(al, t1l)) | 0
+ }
+
+ this._al = (this._al + al) | 0
+ this._bl = (this._bl + bl) | 0
+ this._cl = (this._cl + cl) | 0
+ this._dl = (this._dl + dl) | 0
+ this._el = (this._el + el) | 0
+ this._fl = (this._fl + fl) | 0
+ this._gl = (this._gl + gl) | 0
+ this._hl = (this._hl + hl) | 0
+
+ this._ah = (this._ah + ah + getCarry(this._al, al)) | 0
+ this._bh = (this._bh + bh + getCarry(this._bl, bl)) | 0
+ this._ch = (this._ch + ch + getCarry(this._cl, cl)) | 0
+ this._dh = (this._dh + dh + getCarry(this._dl, dl)) | 0
+ this._eh = (this._eh + eh + getCarry(this._el, el)) | 0
+ this._fh = (this._fh + fh + getCarry(this._fl, fl)) | 0
+ this._gh = (this._gh + gh + getCarry(this._gl, gl)) | 0
+ this._hh = (this._hh + hh + getCarry(this._hl, hl)) | 0
+}
+
+Sha512.prototype._hash = function () {
+ var H = new Buffer(64)
+
+ function writeInt64BE (h, l, offset) {
+ H.writeInt32BE(h, offset)
+ H.writeInt32BE(l, offset + 4)
+ }
+
+ writeInt64BE(this._ah, this._al, 0)
+ writeInt64BE(this._bh, this._bl, 8)
+ writeInt64BE(this._ch, this._cl, 16)
+ writeInt64BE(this._dh, this._dl, 24)
+ writeInt64BE(this._eh, this._el, 32)
+ writeInt64BE(this._fh, this._fl, 40)
+ writeInt64BE(this._gh, this._gl, 48)
+ writeInt64BE(this._hh, this._hl, 56)
+
+ return H
+}
+
+module.exports = Sha512
+
+}).call(this,require("buffer").Buffer)
+},{"./hash":174,"buffer":6,"inherits":45}],182:[function(require,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+module.exports = Stream;
+
+var EE = require('events').EventEmitter;
+var inherits = require('inherits');
+
+inherits(Stream, EE);
+Stream.Readable = require('readable-stream/readable.js');
+Stream.Writable = require('readable-stream/writable.js');
+Stream.Duplex = require('readable-stream/duplex.js');
+Stream.Transform = require('readable-stream/transform.js');
+Stream.PassThrough = require('readable-stream/passthrough.js');
+
+// Backwards-compat with node 0.4.x
+Stream.Stream = Stream;
+
+
+
+// old-style streams. Note that the pipe method (the only relevant
+// part of this class) is overridden in the Readable class.
+
+function Stream() {
+ EE.call(this);
+}
+
+Stream.prototype.pipe = function(dest, options) {
+ var source = this;
+
+ function ondata(chunk) {
+ if (dest.writable) {
+ if (false === dest.write(chunk) && source.pause) {
+ source.pause();
+ }
+ }
+ }
+
+ source.on('data', ondata);
+
+ function ondrain() {
+ if (source.readable && source.resume) {
+ source.resume();
+ }
+ }
+
+ dest.on('drain', ondrain);
+
+ // If the 'end' option is not supplied, dest.end() will be called when
+ // source gets the 'end' or 'close' events. Only dest.end() once.
+ if (!dest._isStdio && (!options || options.end !== false)) {
+ source.on('end', onend);
+ source.on('close', onclose);
+ }
+
+ var didOnEnd = false;
+ function onend() {
+ if (didOnEnd) return;
+ didOnEnd = true;
+
+ dest.end();
+ }
+
+
+ function onclose() {
+ if (didOnEnd) return;
+ didOnEnd = true;
+
+ if (typeof dest.destroy === 'function') dest.destroy();
+ }
+
+ // don't leave dangling pipes when there are errors.
+ function onerror(er) {
+ cleanup();
+ if (EE.listenerCount(this, 'error') === 0) {
+ throw er; // Unhandled stream error in pipe.
+ }
+ }
+
+ source.on('error', onerror);
+ dest.on('error', onerror);
+
+ // remove all the event listeners that were added.
+ function cleanup() {
+ source.removeListener('data', ondata);
+ dest.removeListener('drain', ondrain);
+
+ source.removeListener('end', onend);
+ source.removeListener('close', onclose);
+
+ source.removeListener('error', onerror);
+ dest.removeListener('error', onerror);
+
+ source.removeListener('end', cleanup);
+ source.removeListener('close', cleanup);
+
+ dest.removeListener('close', cleanup);
+ }
+
+ source.on('end', cleanup);
+ source.on('close', cleanup);
+
+ dest.on('close', cleanup);
+
+ dest.emit('pipe', source);
+
+ // Allow for unix-like usage: A.pipe(B).pipe(C)
+ return dest;
+};
+
+},{"events":27,"inherits":45,"readable-stream/duplex.js":155,"readable-stream/passthrough.js":162,"readable-stream/readable.js":163,"readable-stream/transform.js":164,"readable-stream/writable.js":165}],183:[function(require,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var Buffer = require('buffer').Buffer;
+
+var isBufferEncoding = Buffer.isEncoding
+ || function(encoding) {
+ switch (encoding && encoding.toLowerCase()) {
+ case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true;
+ default: return false;
+ }
+ }
+
+
+function assertEncoding(encoding) {
+ if (encoding && !isBufferEncoding(encoding)) {
+ throw new Error('Unknown encoding: ' + encoding);
+ }
+}
+
+// StringDecoder provides an interface for efficiently splitting a series of
+// buffers into a series of JS strings without breaking apart multi-byte
+// characters. CESU-8 is handled as part of the UTF-8 encoding.
+//
+// @TODO Handling all encodings inside a single object makes it very difficult
+// to reason about this code, so it should be split up in the future.
+// @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code
+// points as used by CESU-8.
+var StringDecoder = exports.StringDecoder = function(encoding) {
+ this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, '');
+ assertEncoding(encoding);
+ switch (this.encoding) {
+ case 'utf8':
+ // CESU-8 represents each of Surrogate Pair by 3-bytes
+ this.surrogateSize = 3;
+ break;
+ case 'ucs2':
+ case 'utf16le':
+ // UTF-16 represents each of Surrogate Pair by 2-bytes
+ this.surrogateSize = 2;
+ this.detectIncompleteChar = utf16DetectIncompleteChar;
+ break;
+ case 'base64':
+ // Base-64 stores 3 bytes in 4 chars, and pads the remainder.
+ this.surrogateSize = 3;
+ this.detectIncompleteChar = base64DetectIncompleteChar;
+ break;
+ default:
+ this.write = passThroughWrite;
+ return;
+ }
+
+ // Enough space to store all bytes of a single character. UTF-8 needs 4
+ // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate).
+ this.charBuffer = new Buffer(6);
+ // Number of bytes received for the current incomplete multi-byte character.
+ this.charReceived = 0;
+ // Number of bytes expected for the current incomplete multi-byte character.
+ this.charLength = 0;
+};
+
+
+// write decodes the given buffer and returns it as JS string that is
+// guaranteed to not contain any partial multi-byte characters. Any partial
+// character found at the end of the buffer is buffered up, and will be
+// returned when calling write again with the remaining bytes.
+//
+// Note: Converting a Buffer containing an orphan surrogate to a String
+// currently works, but converting a String to a Buffer (via `new Buffer`, or
+// Buffer#write) will replace incomplete surrogates with the unicode
+// replacement character. See https://codereview.chromium.org/121173009/ .
+StringDecoder.prototype.write = function(buffer) {
+ var charStr = '';
+ // if our last write ended with an incomplete multibyte character
+ while (this.charLength) {
+ // determine how many remaining bytes this buffer has to offer for this char
+ var available = (buffer.length >= this.charLength - this.charReceived) ?
+ this.charLength - this.charReceived :
+ buffer.length;
+
+ // add the new bytes to the char buffer
+ buffer.copy(this.charBuffer, this.charReceived, 0, available);
+ this.charReceived += available;
+
+ if (this.charReceived < this.charLength) {
+ // still not enough chars in this buffer? wait for more ...
+ return '';
+ }
+
+ // remove bytes belonging to the current character from the buffer
+ buffer = buffer.slice(available, buffer.length);
+
+ // get the character that was split
+ charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding);
+
+ // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character
+ var charCode = charStr.charCodeAt(charStr.length - 1);
+ if (charCode >= 0xD800 && charCode <= 0xDBFF) {
+ this.charLength += this.surrogateSize;
+ charStr = '';
+ continue;
+ }
+ this.charReceived = this.charLength = 0;
+
+ // if there are no more bytes in this buffer, just emit our char
+ if (buffer.length === 0) {
+ return charStr;
+ }
+ break;
+ }
+
+ // determine and set charLength / charReceived
+ this.detectIncompleteChar(buffer);
+
+ var end = buffer.length;
+ if (this.charLength) {
+ // buffer the incomplete character bytes we got
+ buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end);
+ end -= this.charReceived;
+ }
+
+ charStr += buffer.toString(this.encoding, 0, end);
+
+ var end = charStr.length - 1;
+ var charCode = charStr.charCodeAt(end);
+ // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character
+ if (charCode >= 0xD800 && charCode <= 0xDBFF) {
+ var size = this.surrogateSize;
+ this.charLength += size;
+ this.charReceived += size;
+ this.charBuffer.copy(this.charBuffer, size, 0, size);
+ buffer.copy(this.charBuffer, 0, 0, size);
+ return charStr.substring(0, end);
+ }
+
+ // or just emit the charStr
+ return charStr;
+};
+
+// detectIncompleteChar determines if there is an incomplete UTF-8 character at
+// the end of the given buffer. If so, it sets this.charLength to the byte
+// length that character, and sets this.charReceived to the number of bytes
+// that are available for this character.
+StringDecoder.prototype.detectIncompleteChar = function(buffer) {
+ // determine how many bytes we have to check at the end of this buffer
+ var i = (buffer.length >= 3) ? 3 : buffer.length;
+
+ // Figure out if one of the last i bytes of our buffer announces an
+ // incomplete char.
+ for (; i > 0; i--) {
+ var c = buffer[buffer.length - i];
+
+ // See http://en.wikipedia.org/wiki/UTF-8#Description
+
+ // 110XXXXX
+ if (i == 1 && c >> 5 == 0x06) {
+ this.charLength = 2;
+ break;
+ }
+
+ // 1110XXXX
+ if (i <= 2 && c >> 4 == 0x0E) {
+ this.charLength = 3;
+ break;
+ }
+
+ // 11110XXX
+ if (i <= 3 && c >> 3 == 0x1E) {
+ this.charLength = 4;
+ break;
+ }
+ }
+ this.charReceived = i;
+};
+
+StringDecoder.prototype.end = function(buffer) {
+ var res = '';
+ if (buffer && buffer.length)
+ res = this.write(buffer);
+
+ if (this.charReceived) {
+ var cr = this.charReceived;
+ var buf = this.charBuffer;
+ var enc = this.encoding;
+ res += buf.slice(0, cr).toString(enc);
+ }
+
+ return res;
+};
+
+function passThroughWrite(buffer) {
+ return buffer.toString(this.encoding);
+}
+
+function utf16DetectIncompleteChar(buffer) {
+ this.charReceived = buffer.length % 2;
+ this.charLength = this.charReceived ? 2 : 0;
+}
+
+function base64DetectIncompleteChar(buffer) {
+ this.charReceived = buffer.length % 3;
+ this.charLength = this.charReceived ? 3 : 0;
+}
+
+},{"buffer":6}],184:[function(require,module,exports){
+// based on https://github.com/ESTOS/strophe.jingle/
+// adds wildemitter support
+var util = require('util');
+var adapter = require('webrtc-adapter'); // jshint ignore:line
+var WildEmitter = require('wildemitter');
+
+function dumpSDP(description) {
+ return {
+ type: description.type,
+ sdp: description.sdp
+ };
+}
+
+function dumpStream(stream) {
+ var info = {
+ label: stream.id,
+ };
+ if (stream.getAudioTracks().length) {
+ info.audio = stream.getAudioTracks().map(function (track) {
+ return track.id;
+ });
+ }
+ if (stream.getVideoTracks().length) {
+ info.video = stream.getVideoTracks().map(function (track) {
+ return track.id;
+ });
+ }
+ return info;
+}
+
+function TraceablePeerConnection(config, constraints) {
+ var self = this;
+ WildEmitter.call(this);
+
+ this.peerconnection = new window.RTCPeerConnection(config, constraints);
+
+ this.trace = function (what, info) {
+ self.emit('PeerConnectionTrace', {
+ time: new Date(),
+ type: what,
+ value: info || ""
+ });
+ };
+
+ this.onicecandidate = null;
+ this.peerconnection.onicecandidate = function (event) {
+ self.trace('onicecandidate', event.candidate);
+ if (self.onicecandidate !== null) {
+ self.onicecandidate(event);
+ }
+ };
+ this.onaddstream = null;
+ this.peerconnection.onaddstream = function (event) {
+ self.trace('onaddstream', dumpStream(event.stream));
+ if (self.onaddstream !== null) {
+ self.onaddstream(event);
+ }
+ };
+ this.onremovestream = null;
+ this.peerconnection.onremovestream = function (event) {
+ self.trace('onremovestream', dumpStream(event.stream));
+ if (self.onremovestream !== null) {
+ self.onremovestream(event);
+ }
+ };
+ this.onsignalingstatechange = null;
+ this.peerconnection.onsignalingstatechange = function (event) {
+ self.trace('onsignalingstatechange', self.signalingState);
+ if (self.onsignalingstatechange !== null) {
+ self.onsignalingstatechange(event);
+ }
+ };
+ this.oniceconnectionstatechange = null;
+ this.peerconnection.oniceconnectionstatechange = function (event) {
+ self.trace('oniceconnectionstatechange', self.iceConnectionState);
+ if (self.oniceconnectionstatechange !== null) {
+ self.oniceconnectionstatechange(event);
+ }
+ };
+ this.onnegotiationneeded = null;
+ this.peerconnection.onnegotiationneeded = function (event) {
+ self.trace('onnegotiationneeded');
+ if (self.onnegotiationneeded !== null) {
+ self.onnegotiationneeded(event);
+ }
+ };
+ self.ondatachannel = null;
+ this.peerconnection.ondatachannel = function (event) {
+ self.trace('ondatachannel', event);
+ if (self.ondatachannel !== null) {
+ self.ondatachannel(event);
+ }
+ };
+ this.getLocalStreams = this.peerconnection.getLocalStreams.bind(this.peerconnection);
+ this.getRemoteStreams = this.peerconnection.getRemoteStreams.bind(this.peerconnection);
+}
+
+util.inherits(TraceablePeerConnection, WildEmitter);
+
+['signalingState', 'iceConnectionState', 'localDescription', 'remoteDescription'].forEach(function (prop) {
+ Object.defineProperty(TraceablePeerConnection.prototype, prop, {
+ get: function () {
+ return this.peerconnection[prop];
+ }
+ });
+});
+
+TraceablePeerConnection.prototype.addStream = function (stream) {
+ this.trace('addStream', dumpStream(stream));
+ this.peerconnection.addStream(stream);
+};
+
+TraceablePeerConnection.prototype.removeStream = function (stream) {
+ this.trace('removeStream', dumpStream(stream));
+ this.peerconnection.removeStream(stream);
+};
+
+TraceablePeerConnection.prototype.createDataChannel = function (label, opts) {
+ this.trace('createDataChannel', label, opts);
+ return this.peerconnection.createDataChannel(label, opts);
+};
+
+TraceablePeerConnection.prototype.setLocalDescription = function (description, successCallback, failureCallback) {
+ var self = this;
+ this.trace('setLocalDescription', dumpSDP(description));
+ return this.peerconnection.setLocalDescription(
+ description
+ ).then(
+ function () {
+ self.trace('setLocalDescriptionOnSuccess');
+ if (successCallback) successCallback();
+ },
+ function (err) {
+ self.trace('setLocalDescriptionOnFailure', err);
+ if (failureCallback) failureCallback(err);
+ }
+ );
+};
+
+TraceablePeerConnection.prototype.setRemoteDescription = function (description, successCallback, failureCallback) {
+ var self = this;
+ this.trace('setRemoteDescription', dumpSDP(description));
+ return this.peerconnection.setRemoteDescription(
+ description
+ ).then(
+ function () {
+ self.trace('setRemoteDescriptionOnSuccess');
+ if (successCallback) successCallback();
+ },
+ function (err) {
+ self.trace('setRemoteDescriptionOnFailure', err);
+ if (failureCallback) failureCallback(err);
+ }
+ );
+};
+
+TraceablePeerConnection.prototype.close = function () {
+ this.trace('stop');
+ if (this.peerconnection.signalingState != 'closed') {
+ this.peerconnection.close();
+ }
+};
+
+TraceablePeerConnection.prototype.createOffer = function (successCallback, failureCallback, constraints) {
+ var self = this;
+ this.trace('createOffer', constraints);
+ return this.peerconnection.createOffer(
+ constraints
+ ).then(
+ function (offer) {
+ self.trace('createOfferOnSuccess', dumpSDP(offer));
+ if (successCallback) successCallback(offer);
+ },
+ function (err) {
+ self.trace('createOfferOnFailure', err);
+ if (failureCallback) failureCallback(err);
+ }
+ );
+};
+
+TraceablePeerConnection.prototype.createAnswer = function (successCallback, failureCallback, constraints) {
+ var self = this;
+ this.trace('createAnswer', constraints);
+ return this.peerconnection.createAnswer(
+ constraints
+ ).then(
+ function (answer) {
+ self.trace('createAnswerOnSuccess', dumpSDP(answer));
+ if (successCallback) successCallback(answer);
+ },
+ function (err) {
+ self.trace('createAnswerOnFailure', err);
+ if (failureCallback) failureCallback(err);
+ }
+ );
+};
+
+TraceablePeerConnection.prototype.addIceCandidate = function (candidate, successCallback, failureCallback) {
+ var self = this;
+ this.trace('addIceCandidate', candidate);
+ return this.peerconnection.addIceCandidate(
+ candidate
+ ).then(
+ function () {
+ //self.trace('addIceCandidateOnSuccess');
+ if (successCallback) successCallback();
+ },
+ function (err) {
+ self.trace('addIceCandidateOnFailure', err);
+ if (failureCallback) failureCallback(err);
+ }
+ );
+};
+
+TraceablePeerConnection.prototype.getStats = function () {
+ this.peerconnection.getStats.apply(this.peerconnection, arguments);
+};
+
+module.exports = TraceablePeerConnection;
+
+},{"util":197,"webrtc-adapter":185,"wildemitter":211}],185:[function(require,module,exports){
+arguments[4][33][0].apply(exports,arguments)
+},{"./chrome/chrome_shim":186,"./edge/edge_shim":188,"./firefox/firefox_shim":190,"./safari/safari_shim":192,"./utils":193,"dup":33}],186:[function(require,module,exports){
+arguments[4][34][0].apply(exports,arguments)
+},{"../utils.js":193,"./getusermedia":187,"dup":34}],187:[function(require,module,exports){
+arguments[4][35][0].apply(exports,arguments)
+},{"../utils.js":193,"dup":35}],188:[function(require,module,exports){
+arguments[4][36][0].apply(exports,arguments)
+},{"../utils":193,"./getusermedia":189,"dup":36,"sdp":173}],189:[function(require,module,exports){
+arguments[4][37][0].apply(exports,arguments)
+},{"dup":37}],190:[function(require,module,exports){
+arguments[4][38][0].apply(exports,arguments)
+},{"../utils":193,"./getusermedia":191,"dup":38}],191:[function(require,module,exports){
+arguments[4][39][0].apply(exports,arguments)
+},{"../utils":193,"dup":39}],192:[function(require,module,exports){
+arguments[4][40][0].apply(exports,arguments)
+},{"dup":40}],193:[function(require,module,exports){
+arguments[4][41][0].apply(exports,arguments)
+},{"dup":41}],194:[function(require,module,exports){
+(function (global){
/**
- * DOM parser interface
+ * Module exports.
*/
-exports.parse = parse.parse
-exports.Parser = parse.Parser
+
+module.exports = deprecate;
/**
- * SAX parser interface
+ * Mark that a method should not be used.
+ * Returns a modified function which warns once by default.
+ *
+ * If `localStorage.noDeprecation = true` is set, then it is a no-op.
+ *
+ * If `localStorage.throwDeprecation = true` is set, then deprecated functions
+ * will throw an Error when invoked.
+ *
+ * If `localStorage.traceDeprecation = true` is set, then deprecated functions
+ * will invoke `console.trace()` instead of `console.error()`.
+ *
+ * @param {Function} fn - the function to deprecate
+ * @param {String} msg - the string to print to the console when `fn` is invoked
+ * @returns {Function} a new "deprecated" version of `fn`
+ * @api public
*/
-exports.availableSaxParsers = parse.availableSaxParsers
-exports.bestSaxParser = parse.bestSaxParser
-},{"./dom-element":243,"./element":244,"./parse":247}],247:[function(require,module,exports){
-'use strict';
+function deprecate (fn, msg) {
+ if (config('noDeprecation')) {
+ return fn;
+ }
-var events = require('events')
- , util = require('util')
- , DOMElement = require('./dom-element')
+ var warned = false;
+ function deprecated() {
+ if (!warned) {
+ if (config('throwDeprecation')) {
+ throw new Error(msg);
+ } else if (config('traceDeprecation')) {
+ console.trace(msg);
+ } else {
+ console.warn(msg);
+ }
+ warned = true;
+ }
+ return fn.apply(this, arguments);
+ }
+ return deprecated;
+}
-exports.availableSaxParsers = []
-exports.bestSaxParser = null
+/**
+ * Checks `localStorage` for boolean values for the given `name`.
+ *
+ * @param {String} name
+ * @returns {Boolean}
+ * @api private
+ */
-var saxParsers = [
- './sax/sax_expat.js',
- './sax/sax_ltx.js',
- /*'./sax_easysax.js', './sax_node-xml.js',*/
- './sax/sax_saxjs.js'
-]
+function config (name) {
+ // accessing global.localStorage can trigger a DOMException in sandboxed iframes
+ try {
+ if (!global.localStorage) return false;
+ } catch (_) {
+ return false;
+ }
+ var val = global.localStorage[name];
+ if (null == val) return false;
+ return String(val).toLowerCase() === 'true';
+}
-saxParsers.forEach(function(modName) {
- var mod
- try {
- mod = require(modName)
- } catch (e) {
- /* Silently missing libraries drop for debug:
- console.error(e.stack || e)
- */
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}],195:[function(require,module,exports){
+arguments[4][45][0].apply(exports,arguments)
+},{"dup":45}],196:[function(require,module,exports){
+module.exports = function isBuffer(arg) {
+ return arg && typeof arg === 'object'
+ && typeof arg.copy === 'function'
+ && typeof arg.fill === 'function'
+ && typeof arg.readUInt8 === 'function';
+}
+},{}],197:[function(require,module,exports){
+(function (process,global){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var formatRegExp = /%[sdj%]/g;
+exports.format = function(f) {
+ if (!isString(f)) {
+ var objects = [];
+ for (var i = 0; i < arguments.length; i++) {
+ objects.push(inspect(arguments[i]));
}
- if (mod) {
- exports.availableSaxParsers.push(mod)
- if (!exports.bestSaxParser) {
- exports.bestSaxParser = mod
+ return objects.join(' ');
+ }
+
+ var i = 1;
+ var args = arguments;
+ var len = args.length;
+ var str = String(f).replace(formatRegExp, function(x) {
+ if (x === '%%') return '%';
+ if (i >= len) return x;
+ switch (x) {
+ case '%s': return String(args[i++]);
+ case '%d': return Number(args[i++]);
+ case '%j':
+ try {
+ return JSON.stringify(args[i++]);
+ } catch (_) {
+ return '[Circular]';
}
+ default:
+ return x;
}
-})
+ });
+ for (var x = args[i]; i < len; x = args[++i]) {
+ if (isNull(x) || !isObject(x)) {
+ str += ' ' + x;
+ } else {
+ str += ' ' + inspect(x);
+ }
+ }
+ return str;
+};
+
+
+// Mark that a method should not be used.
+// Returns a modified function which warns once by default.
+// If --no-deprecation is set, then it is a no-op.
+exports.deprecate = function(fn, msg) {
+ // Allow for deprecating things in the process of starting up.
+ if (isUndefined(global.process)) {
+ return function() {
+ return exports.deprecate(fn, msg).apply(this, arguments);
+ };
+ }
+
+ if (process.noDeprecation === true) {
+ return fn;
+ }
+
+ var warned = false;
+ function deprecated() {
+ if (!warned) {
+ if (process.throwDeprecation) {
+ throw new Error(msg);
+ } else if (process.traceDeprecation) {
+ console.trace(msg);
+ } else {
+ console.error(msg);
+ }
+ warned = true;
+ }
+ return fn.apply(this, arguments);
+ }
+
+ return deprecated;
+};
+
+
+var debugs = {};
+var debugEnviron;
+exports.debuglog = function(set) {
+ if (isUndefined(debugEnviron))
+ debugEnviron = process.env.NODE_DEBUG || '';
+ set = set.toUpperCase();
+ if (!debugs[set]) {
+ if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
+ var pid = process.pid;
+ debugs[set] = function() {
+ var msg = exports.format.apply(exports, arguments);
+ console.error('%s %d: %s', set, pid, msg);
+ };
+ } else {
+ debugs[set] = function() {};
+ }
+ }
+ return debugs[set];
+};
+
+
+/**
+ * Echos the value of a value. Trys to print the value out
+ * in the best way possible given the different types.
+ *
+ * @param {Object} obj The object to print out.
+ * @param {Object} opts Optional options object that alters the output.
+ */
+/* legacy: obj, showHidden, depth, colors*/
+function inspect(obj, opts) {
+ // default options
+ var ctx = {
+ seen: [],
+ stylize: stylizeNoColor
+ };
+ // legacy...
+ if (arguments.length >= 3) ctx.depth = arguments[2];
+ if (arguments.length >= 4) ctx.colors = arguments[3];
+ if (isBoolean(opts)) {
+ // legacy...
+ ctx.showHidden = opts;
+ } else if (opts) {
+ // got an "options" object
+ exports._extend(ctx, opts);
+ }
+ // set default options
+ if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
+ if (isUndefined(ctx.depth)) ctx.depth = 2;
+ if (isUndefined(ctx.colors)) ctx.colors = false;
+ if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
+ if (ctx.colors) ctx.stylize = stylizeWithColor;
+ return formatValue(ctx, obj, ctx.depth);
+}
+exports.inspect = inspect;
+
+
+// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
+inspect.colors = {
+ 'bold' : [1, 22],
+ 'italic' : [3, 23],
+ 'underline' : [4, 24],
+ 'inverse' : [7, 27],
+ 'white' : [37, 39],
+ 'grey' : [90, 39],
+ 'black' : [30, 39],
+ 'blue' : [34, 39],
+ 'cyan' : [36, 39],
+ 'green' : [32, 39],
+ 'magenta' : [35, 39],
+ 'red' : [31, 39],
+ 'yellow' : [33, 39]
+};
+
+// Don't use 'blue' not visible on cmd.exe
+inspect.styles = {
+ 'special': 'cyan',
+ 'number': 'yellow',
+ 'boolean': 'yellow',
+ 'undefined': 'grey',
+ 'null': 'bold',
+ 'string': 'green',
+ 'date': 'magenta',
+ // "name": intentionally not styling
+ 'regexp': 'red'
+};
+
+
+function stylizeWithColor(str, styleType) {
+ var style = inspect.styles[styleType];
+
+ if (style) {
+ return '\u001b[' + inspect.colors[style][0] + 'm' + str +
+ '\u001b[' + inspect.colors[style][1] + 'm';
+ } else {
+ return str;
+ }
+}
+
+
+function stylizeNoColor(str, styleType) {
+ return str;
+}
+
+
+function arrayToHash(array) {
+ var hash = {};
+
+ array.forEach(function(val, idx) {
+ hash[val] = true;
+ });
+
+ return hash;
+}
+
+
+function formatValue(ctx, value, recurseTimes) {
+ // Provide a hook for user-specified inspect functions.
+ // Check that value is an object with an inspect function on it
+ if (ctx.customInspect &&
+ value &&
+ isFunction(value.inspect) &&
+ // Filter out the util module, it's inspect function is special
+ value.inspect !== exports.inspect &&
+ // Also filter out any prototype objects using the circular check.
+ !(value.constructor && value.constructor.prototype === value)) {
+ var ret = value.inspect(recurseTimes, ctx);
+ if (!isString(ret)) {
+ ret = formatValue(ctx, ret, recurseTimes);
+ }
+ return ret;
+ }
+
+ // Primitive types cannot have properties
+ var primitive = formatPrimitive(ctx, value);
+ if (primitive) {
+ return primitive;
+ }
+
+ // Look up the keys of the object.
+ var keys = Object.keys(value);
+ var visibleKeys = arrayToHash(keys);
+
+ if (ctx.showHidden) {
+ keys = Object.getOwnPropertyNames(value);
+ }
+
+ // IE doesn't make error fields non-enumerable
+ // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
+ if (isError(value)
+ && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
+ return formatError(value);
+ }
+
+ // Some type of object without properties can be shortcutted.
+ if (keys.length === 0) {
+ if (isFunction(value)) {
+ var name = value.name ? ': ' + value.name : '';
+ return ctx.stylize('[Function' + name + ']', 'special');
+ }
+ if (isRegExp(value)) {
+ return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+ }
+ if (isDate(value)) {
+ return ctx.stylize(Date.prototype.toString.call(value), 'date');
+ }
+ if (isError(value)) {
+ return formatError(value);
+ }
+ }
+
+ var base = '', array = false, braces = ['{', '}'];
+
+ // Make Array say that they are Array
+ if (isArray(value)) {
+ array = true;
+ braces = ['[', ']'];
+ }
+
+ // Make functions say that they are functions
+ if (isFunction(value)) {
+ var n = value.name ? ': ' + value.name : '';
+ base = ' [Function' + n + ']';
+ }
+
+ // Make RegExps say that they are RegExps
+ if (isRegExp(value)) {
+ base = ' ' + RegExp.prototype.toString.call(value);
+ }
+
+ // Make dates with properties first say the date
+ if (isDate(value)) {
+ base = ' ' + Date.prototype.toUTCString.call(value);
+ }
+
+ // Make error with message first say the error
+ if (isError(value)) {
+ base = ' ' + formatError(value);
+ }
+
+ if (keys.length === 0 && (!array || value.length == 0)) {
+ return braces[0] + base + braces[1];
+ }
+
+ if (recurseTimes < 0) {
+ if (isRegExp(value)) {
+ return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+ } else {
+ return ctx.stylize('[Object]', 'special');
+ }
+ }
+
+ ctx.seen.push(value);
+
+ var output;
+ if (array) {
+ output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
+ } else {
+ output = keys.map(function(key) {
+ return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
+ });
+ }
+
+ ctx.seen.pop();
+
+ return reduceToSingleString(output, base, braces);
+}
+
+
+function formatPrimitive(ctx, value) {
+ if (isUndefined(value))
+ return ctx.stylize('undefined', 'undefined');
+ if (isString(value)) {
+ var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
+ .replace(/'/g, "\\'")
+ .replace(/\\"/g, '"') + '\'';
+ return ctx.stylize(simple, 'string');
+ }
+ if (isNumber(value))
+ return ctx.stylize('' + value, 'number');
+ if (isBoolean(value))
+ return ctx.stylize('' + value, 'boolean');
+ // For some reason typeof null is "object", so special case here.
+ if (isNull(value))
+ return ctx.stylize('null', 'null');
+}
+
+
+function formatError(value) {
+ return '[' + Error.prototype.toString.call(value) + ']';
+}
-exports.Parser = function(saxParser) {
- events.EventEmitter.call(this)
- var self = this
- var ParserMod = saxParser || exports.bestSaxParser
- if (!ParserMod) {
- throw new Error('No SAX parser available')
+function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
+ var output = [];
+ for (var i = 0, l = value.length; i < l; ++i) {
+ if (hasOwnProperty(value, String(i))) {
+ output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+ String(i), true));
+ } else {
+ output.push('');
+ }
+ }
+ keys.forEach(function(key) {
+ if (!key.match(/^\d+$/)) {
+ output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+ key, true));
}
- this.parser = new ParserMod()
+ });
+ return output;
+}
+
- var el
- this.parser.addListener('startElement', function(name, attrs) {
- var child = new DOMElement(name, attrs)
- if (!el) {
- el = child
+function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
+ var name, str, desc;
+ desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
+ if (desc.get) {
+ if (desc.set) {
+ str = ctx.stylize('[Getter/Setter]', 'special');
+ } else {
+ str = ctx.stylize('[Getter]', 'special');
+ }
+ } else {
+ if (desc.set) {
+ str = ctx.stylize('[Setter]', 'special');
+ }
+ }
+ if (!hasOwnProperty(visibleKeys, key)) {
+ name = '[' + key + ']';
+ }
+ if (!str) {
+ if (ctx.seen.indexOf(desc.value) < 0) {
+ if (isNull(recurseTimes)) {
+ str = formatValue(ctx, desc.value, null);
+ } else {
+ str = formatValue(ctx, desc.value, recurseTimes - 1);
+ }
+ if (str.indexOf('\n') > -1) {
+ if (array) {
+ str = str.split('\n').map(function(line) {
+ return ' ' + line;
+ }).join('\n').substr(2);
} else {
- el = el.cnode(child)
+ str = '\n' + str.split('\n').map(function(line) {
+ return ' ' + line;
+ }).join('\n');
}
- })
- this.parser.addListener('endElement', function(name) {
- /* jshint -W035 */
- if (!el) {
- /* Err */
- } else if (name === el.name) {
- if (el.parent) {
- el = el.parent
- } else if (!self.tree) {
- self.tree = el
- el = undefined
+ }
+ } else {
+ str = ctx.stylize('[Circular]', 'special');
+ }
+ }
+ if (isUndefined(name)) {
+ if (array && key.match(/^\d+$/)) {
+ return str;
+ }
+ name = JSON.stringify('' + key);
+ if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
+ name = name.substr(1, name.length - 2);
+ name = ctx.stylize(name, 'name');
+ } else {
+ name = name.replace(/'/g, "\\'")
+ .replace(/\\"/g, '"')
+ .replace(/(^"|"$)/g, "'");
+ name = ctx.stylize(name, 'string');
+ }
+ }
+
+ return name + ': ' + str;
+}
+
+
+function reduceToSingleString(output, base, braces) {
+ var numLinesEst = 0;
+ var length = output.reduce(function(prev, cur) {
+ numLinesEst++;
+ if (cur.indexOf('\n') >= 0) numLinesEst++;
+ return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
+ }, 0);
+
+ if (length > 60) {
+ return braces[0] +
+ (base === '' ? '' : base + '\n ') +
+ ' ' +
+ output.join(',\n ') +
+ ' ' +
+ braces[1];
+ }
+
+ return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
+}
+
+
+// NOTE: These type checking functions intentionally don't use `instanceof`
+// because it is fragile and can be easily faked with `Object.create()`.
+function isArray(ar) {
+ return Array.isArray(ar);
+}
+exports.isArray = isArray;
+
+function isBoolean(arg) {
+ return typeof arg === 'boolean';
+}
+exports.isBoolean = isBoolean;
+
+function isNull(arg) {
+ return arg === null;
+}
+exports.isNull = isNull;
+
+function isNullOrUndefined(arg) {
+ return arg == null;
+}
+exports.isNullOrUndefined = isNullOrUndefined;
+
+function isNumber(arg) {
+ return typeof arg === 'number';
+}
+exports.isNumber = isNumber;
+
+function isString(arg) {
+ return typeof arg === 'string';
+}
+exports.isString = isString;
+
+function isSymbol(arg) {
+ return typeof arg === 'symbol';
+}
+exports.isSymbol = isSymbol;
+
+function isUndefined(arg) {
+ return arg === void 0;
+}
+exports.isUndefined = isUndefined;
+
+function isRegExp(re) {
+ return isObject(re) && objectToString(re) === '[object RegExp]';
+}
+exports.isRegExp = isRegExp;
+
+function isObject(arg) {
+ return typeof arg === 'object' && arg !== null;
+}
+exports.isObject = isObject;
+
+function isDate(d) {
+ return isObject(d) && objectToString(d) === '[object Date]';
+}
+exports.isDate = isDate;
+
+function isError(e) {
+ return isObject(e) &&
+ (objectToString(e) === '[object Error]' || e instanceof Error);
+}
+exports.isError = isError;
+
+function isFunction(arg) {
+ return typeof arg === 'function';
+}
+exports.isFunction = isFunction;
+
+function isPrimitive(arg) {
+ return arg === null ||
+ typeof arg === 'boolean' ||
+ typeof arg === 'number' ||
+ typeof arg === 'string' ||
+ typeof arg === 'symbol' || // ES6 symbol
+ typeof arg === 'undefined';
+}
+exports.isPrimitive = isPrimitive;
+
+exports.isBuffer = require('./support/isBuffer');
+
+function objectToString(o) {
+ return Object.prototype.toString.call(o);
+}
+
+
+function pad(n) {
+ return n < 10 ? '0' + n.toString(10) : n.toString(10);
+}
+
+
+var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
+ 'Oct', 'Nov', 'Dec'];
+
+// 26 Feb 16:19:34
+function timestamp() {
+ var d = new Date();
+ var time = [pad(d.getHours()),
+ pad(d.getMinutes()),
+ pad(d.getSeconds())].join(':');
+ return [d.getDate(), months[d.getMonth()], time].join(' ');
+}
+
+
+// log is just a thin wrapper to console.log that prepends a timestamp
+exports.log = function() {
+ console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
+};
+
+
+/**
+ * Inherit the prototype methods from one constructor into another.
+ *
+ * The Function.prototype.inherits from lang.js rewritten as a standalone
+ * function (not on Function.prototype). NOTE: If this file is to be loaded
+ * during bootstrapping this function needs to be rewritten using some native
+ * functions as prototype setup using normal JavaScript does not work as
+ * expected during bootstrapping (see mirror.js in r114903).
+ *
+ * @param {function} ctor Constructor function which needs to inherit the
+ * prototype.
+ * @param {function} superCtor Constructor function to inherit prototype from.
+ */
+exports.inherits = require('inherits');
+
+exports._extend = function(origin, add) {
+ // Don't do anything if add isn't an object
+ if (!add || !isObject(add)) return origin;
+
+ var keys = Object.keys(add);
+ var i = keys.length;
+ while (i--) {
+ origin[keys[i]] = add[keys[i]];
+ }
+ return origin;
+};
+
+function hasOwnProperty(obj, prop) {
+ return Object.prototype.hasOwnProperty.call(obj, prop);
+}
+
+}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"./support/isBuffer":196,"_process":153,"inherits":195}],198:[function(require,module,exports){
+(function (global){
+
+var rng;
+
+var crypto = global.crypto || global.msCrypto; // for IE 11
+if (crypto && crypto.getRandomValues) {
+ // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
+ // Moderately fast, high quality
+ var _rnds8 = new Uint8Array(16);
+ rng = function whatwgRNG() {
+ crypto.getRandomValues(_rnds8);
+ return _rnds8;
+ };
+}
+
+if (!rng) {
+ // Math.random()-based (RNG)
+ //
+ // If all else fails, use Math.random(). It's fast, but is of unspecified
+ // quality.
+ var _rnds = new Array(16);
+ rng = function() {
+ for (var i = 0, r; i < 16; i++) {
+ if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
+ _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
+ }
+
+ return _rnds;
+ };
+}
+
+module.exports = rng;
+
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}],199:[function(require,module,exports){
+// uuid.js
+//
+// Copyright (c) 2010-2012 Robert Kieffer
+// MIT License - http://opensource.org/licenses/mit-license.php
+
+// Unique ID creation requires a high quality random # generator. We feature
+// detect to determine the best RNG source, normalizing to a function that
+// returns 128-bits of randomness, since that's what's usually required
+var _rng = require('./rng');
+
+// Maps for number <-> hex string conversion
+var _byteToHex = [];
+var _hexToByte = {};
+for (var i = 0; i < 256; i++) {
+ _byteToHex[i] = (i + 0x100).toString(16).substr(1);
+ _hexToByte[_byteToHex[i]] = i;
+}
+
+// **`parse()` - Parse a UUID into it's component bytes**
+function parse(s, buf, offset) {
+ var i = (buf && offset) || 0, ii = 0;
+
+ buf = buf || [];
+ s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
+ if (ii < 16) { // Don't overflow!
+ buf[i + ii++] = _hexToByte[oct];
+ }
+ });
+
+ // Zero out remaining bytes if string was short
+ while (ii < 16) {
+ buf[i + ii++] = 0;
+ }
+
+ return buf;
+}
+
+// **`unparse()` - Convert UUID byte array (ala parse()) into a string**
+function unparse(buf, offset) {
+ var i = offset || 0, bth = _byteToHex;
+ return bth[buf[i++]] + bth[buf[i++]] +
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
+ bth[buf[i++]] + bth[buf[i++]] +
+ bth[buf[i++]] + bth[buf[i++]] +
+ bth[buf[i++]] + bth[buf[i++]];
+}
+
+// **`v1()` - Generate time-based UUID**
+//
+// Inspired by https://github.com/LiosK/UUID.js
+// and http://docs.python.org/library/uuid.html
+
+// random #'s we need to init node and clockseq
+var _seedBytes = _rng();
+
+// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
+var _nodeId = [
+ _seedBytes[0] | 0x01,
+ _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
+];
+
+// Per 4.2.2, randomize (14 bit) clockseq
+var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
+
+// Previous uuid creation time
+var _lastMSecs = 0, _lastNSecs = 0;
+
+// See https://github.com/broofa/node-uuid for API details
+function v1(options, buf, offset) {
+ var i = buf && offset || 0;
+ var b = buf || [];
+
+ options = options || {};
+
+ var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq;
+
+ // UUID timestamps are 100 nano-second units since the Gregorian epoch,
+ // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
+ // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
+ // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
+ var msecs = options.msecs !== undefined ? options.msecs : new Date().getTime();
+
+ // Per 4.2.1.2, use count of uuid's generated during the current clock
+ // cycle to simulate higher resolution clock
+ var nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1;
+
+ // Time since last uuid creation (in msecs)
+ var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
+
+ // Per 4.2.1.2, Bump clockseq on clock regression
+ if (dt < 0 && options.clockseq === undefined) {
+ clockseq = clockseq + 1 & 0x3fff;
+ }
+
+ // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
+ // time interval
+ if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {
+ nsecs = 0;
+ }
+
+ // Per 4.2.1.2 Throw error if too many uuids are requested
+ if (nsecs >= 10000) {
+ throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
+ }
+
+ _lastMSecs = msecs;
+ _lastNSecs = nsecs;
+ _clockseq = clockseq;
+
+ // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
+ msecs += 12219292800000;
+
+ // `time_low`
+ var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
+ b[i++] = tl >>> 24 & 0xff;
+ b[i++] = tl >>> 16 & 0xff;
+ b[i++] = tl >>> 8 & 0xff;
+ b[i++] = tl & 0xff;
+
+ // `time_mid`
+ var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
+ b[i++] = tmh >>> 8 & 0xff;
+ b[i++] = tmh & 0xff;
+
+ // `time_high_and_version`
+ b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
+ b[i++] = tmh >>> 16 & 0xff;
+
+ // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
+ b[i++] = clockseq >>> 8 | 0x80;
+
+ // `clock_seq_low`
+ b[i++] = clockseq & 0xff;
+
+ // `node`
+ var node = options.node || _nodeId;
+ for (var n = 0; n < 6; n++) {
+ b[i + n] = node[n];
+ }
+
+ return buf ? buf : unparse(b);
+}
+
+// **`v4()` - Generate random UUID**
+
+// See https://github.com/broofa/node-uuid for API details
+function v4(options, buf, offset) {
+ // Deprecated - 'format' argument, as supported in v1.2
+ var i = buf && offset || 0;
+
+ if (typeof(options) == 'string') {
+ buf = options == 'binary' ? new Array(16) : null;
+ options = null;
+ }
+ options = options || {};
+
+ var rnds = options.random || (options.rng || _rng)();
+
+ // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
+ rnds[6] = (rnds[6] & 0x0f) | 0x40;
+ rnds[8] = (rnds[8] & 0x3f) | 0x80;
+
+ // Copy bytes to buffer, if provided
+ if (buf) {
+ for (var ii = 0; ii < 16; ii++) {
+ buf[i + ii] = rnds[ii];
+ }
+ }
+
+ return buf || unparse(rnds);
+}
+
+// Export public API
+var uuid = v4;
+uuid.v1 = v1;
+uuid.v4 = v4;
+uuid.parse = parse;
+uuid.unparse = unparse;
+
+module.exports = uuid;
+
+},{"./rng":198}],200:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+
+/* More information about these options at jshint.com/docs/options */
+/* jshint browser: true, camelcase: true, curly: true, devel: true,
+ eqeqeq: true, forin: false, globalstrict: true, node: true,
+ quotmark: single, undef: true, unused: strict */
+/* global mozRTCIceCandidate, mozRTCPeerConnection, Promise,
+mozRTCSessionDescription, webkitRTCPeerConnection, MediaStreamTrack,
+MediaStream, RTCIceGatherer, RTCIceTransport, RTCDtlsTransport,
+RTCRtpSender, RTCRtpReceiver*/
+/* exported trace,requestUserMedia */
+
+'use strict';
+
+var getUserMedia = null;
+var attachMediaStream = null;
+var reattachMediaStream = null;
+var webrtcDetectedBrowser = null;
+var webrtcDetectedVersion = null;
+var webrtcMinimumVersion = null;
+var webrtcUtils = {
+ log: function() {
+ // suppress console.log output when being included as a module.
+ if (typeof module !== 'undefined' ||
+ typeof require === 'function' && typeof define === 'function') {
+ return;
+ }
+ console.log.apply(console, arguments);
+ },
+ extractVersion: function(uastring, expr, pos) {
+ var match = uastring.match(expr);
+ return match && match.length >= pos && parseInt(match[pos], 10);
+ }
+};
+
+function trace(text) {
+ // This function is used for logging.
+ if (text[text.length - 1] === '\n') {
+ text = text.substring(0, text.length - 1);
+ }
+ if (window.performance) {
+ var now = (window.performance.now() / 1000).toFixed(3);
+ webrtcUtils.log(now + ': ' + text);
+ } else {
+ webrtcUtils.log(text);
+ }
+}
+
+if (typeof window === 'object') {
+ if (window.HTMLMediaElement &&
+ !('srcObject' in window.HTMLMediaElement.prototype)) {
+ // Shim the srcObject property, once, when HTMLMediaElement is found.
+ Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
+ get: function() {
+ // If prefixed srcObject property exists, return it.
+ // Otherwise use the shimmed property, _srcObject
+ return 'mozSrcObject' in this ? this.mozSrcObject : this._srcObject;
+ },
+ set: function(stream) {
+ if ('mozSrcObject' in this) {
+ this.mozSrcObject = stream;
+ } else {
+ // Use _srcObject as a private property for this shim
+ this._srcObject = stream;
+ // TODO: revokeObjectUrl(this.src) when !stream to release resources?
+ this.src = URL.createObjectURL(stream);
+ }
+ }
+ });
+ }
+ // Proxy existing globals
+ getUserMedia = window.navigator && window.navigator.getUserMedia;
+}
+
+// Attach a media stream to an element.
+attachMediaStream = function(element, stream) {
+ element.srcObject = stream;
+};
+
+reattachMediaStream = function(to, from) {
+ to.srcObject = from.srcObject;
+};
+
+if (typeof window === 'undefined' || !window.navigator) {
+ webrtcUtils.log('This does not appear to be a browser');
+ webrtcDetectedBrowser = 'not a browser';
+} else if (navigator.mozGetUserMedia) {
+ webrtcUtils.log('This appears to be Firefox');
+
+ webrtcDetectedBrowser = 'firefox';
+
+ // the detected firefox version.
+ webrtcDetectedVersion = webrtcUtils.extractVersion(navigator.userAgent,
+ /Firefox\/([0-9]+)\./, 1);
+
+ // the minimum firefox version still supported by adapter.
+ webrtcMinimumVersion = 31;
+
+ // Shim for RTCPeerConnection on older versions.
+ if (!window.RTCPeerConnection) {
+ window.RTCPeerConnection = function(pcConfig, pcConstraints) {
+ if (webrtcDetectedVersion < 38) {
+ // .urls is not supported in FF < 38.
+ // create RTCIceServers with a single url.
+ if (pcConfig && pcConfig.iceServers) {
+ var newIceServers = [];
+ for (var i = 0; i < pcConfig.iceServers.length; i++) {
+ var server = pcConfig.iceServers[i];
+ if (server.hasOwnProperty('urls')) {
+ for (var j = 0; j < server.urls.length; j++) {
+ var newServer = {
+ url: server.urls[j]
+ };
+ if (server.urls[j].indexOf('turn') === 0) {
+ newServer.username = server.username;
+ newServer.credential = server.credential;
+ }
+ newIceServers.push(newServer);
+ }
+ } else {
+ newIceServers.push(pcConfig.iceServers[i]);
}
+ }
+ pcConfig.iceServers = newIceServers;
}
- /* jshint +W035 */
- })
- this.parser.addListener('text', function(str) {
- if (el) {
- el.t(str)
+ }
+ return new mozRTCPeerConnection(pcConfig, pcConstraints); // jscs:ignore requireCapitalizedConstructors
+ };
+ window.RTCPeerConnection.prototype = mozRTCPeerConnection.prototype;
+
+ // wrap static methods. Currently just generateCertificate.
+ if (mozRTCPeerConnection.generateCertificate) {
+ Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
+ get: function() {
+ if (arguments.length) {
+ return mozRTCPeerConnection.generateCertificate.apply(null,
+ arguments);
+ } else {
+ return mozRTCPeerConnection.generateCertificate;
+ }
}
- })
- this.parser.addListener('error', function(e) {
- self.error = e
- self.emit('error', e)
- })
-}
+ });
+ }
-util.inherits(exports.Parser, events.EventEmitter)
+ window.RTCSessionDescription = mozRTCSessionDescription;
+ window.RTCIceCandidate = mozRTCIceCandidate;
+ }
-exports.Parser.prototype.write = function(data) {
- this.parser.write(data)
-}
+ // getUserMedia constraints shim.
+ getUserMedia = function(constraints, onSuccess, onError) {
+ var constraintsToFF37 = function(c) {
+ if (typeof c !== 'object' || c.require) {
+ return c;
+ }
+ var require = [];
+ Object.keys(c).forEach(function(key) {
+ if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
+ return;
+ }
+ var r = c[key] = (typeof c[key] === 'object') ?
+ c[key] : {ideal: c[key]};
+ if (r.min !== undefined ||
+ r.max !== undefined || r.exact !== undefined) {
+ require.push(key);
+ }
+ if (r.exact !== undefined) {
+ if (typeof r.exact === 'number') {
+ r.min = r.max = r.exact;
+ } else {
+ c[key] = r.exact;
+ }
+ delete r.exact;
+ }
+ if (r.ideal !== undefined) {
+ c.advanced = c.advanced || [];
+ var oc = {};
+ if (typeof r.ideal === 'number') {
+ oc[key] = {min: r.ideal, max: r.ideal};
+ } else {
+ oc[key] = r.ideal;
+ }
+ c.advanced.push(oc);
+ delete r.ideal;
+ if (!Object.keys(r).length) {
+ delete c[key];
+ }
+ }
+ });
+ if (require.length) {
+ c.require = require;
+ }
+ return c;
+ };
+ if (webrtcDetectedVersion < 38) {
+ webrtcUtils.log('spec: ' + JSON.stringify(constraints));
+ if (constraints.audio) {
+ constraints.audio = constraintsToFF37(constraints.audio);
+ }
+ if (constraints.video) {
+ constraints.video = constraintsToFF37(constraints.video);
+ }
+ webrtcUtils.log('ff37: ' + JSON.stringify(constraints));
+ }
+ return navigator.mozGetUserMedia(constraints, onSuccess, onError);
+ };
+
+ navigator.getUserMedia = getUserMedia;
+
+ // Shim for mediaDevices on older versions.
+ if (!navigator.mediaDevices) {
+ navigator.mediaDevices = {getUserMedia: requestUserMedia,
+ addEventListener: function() { },
+ removeEventListener: function() { }
+ };
+ }
+ navigator.mediaDevices.enumerateDevices =
+ navigator.mediaDevices.enumerateDevices || function() {
+ return new Promise(function(resolve) {
+ var infos = [
+ {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''},
+ {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''}
+ ];
+ resolve(infos);
+ });
+ };
+
+ if (webrtcDetectedVersion < 41) {
+ // Work around http://bugzil.la/1169665
+ var orgEnumerateDevices =
+ navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices);
+ navigator.mediaDevices.enumerateDevices = function() {
+ return orgEnumerateDevices().then(undefined, function(e) {
+ if (e.name === 'NotFoundError') {
+ return [];
+ }
+ throw e;
+ });
+ };
+ }
+} else if (navigator.webkitGetUserMedia && window.webkitRTCPeerConnection) {
+ webrtcUtils.log('This appears to be Chrome');
+
+ webrtcDetectedBrowser = 'chrome';
+
+ // the detected chrome version.
+ webrtcDetectedVersion = webrtcUtils.extractVersion(navigator.userAgent,
+ /Chrom(e|ium)\/([0-9]+)\./, 2);
+
+ // the minimum chrome version still supported by adapter.
+ webrtcMinimumVersion = 38;
+
+ // The RTCPeerConnection object.
+ window.RTCPeerConnection = function(pcConfig, pcConstraints) {
+ // Translate iceTransportPolicy to iceTransports,
+ // see https://code.google.com/p/webrtc/issues/detail?id=4869
+ if (pcConfig && pcConfig.iceTransportPolicy) {
+ pcConfig.iceTransports = pcConfig.iceTransportPolicy;
+ }
+
+ var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints); // jscs:ignore requireCapitalizedConstructors
+ var origGetStats = pc.getStats.bind(pc);
+ pc.getStats = function(selector, successCallback, errorCallback) { // jshint ignore: line
+ var self = this;
+ var args = arguments;
+
+ // If selector is a function then we are in the old style stats so just
+ // pass back the original getStats format to avoid breaking old users.
+ if (arguments.length > 0 && typeof selector === 'function') {
+ return origGetStats(selector, successCallback);
+ }
+
+ var fixChromeStats = function(response) {
+ var standardReport = {};
+ var reports = response.result();
+ reports.forEach(function(report) {
+ var standardStats = {
+ id: report.id,
+ timestamp: report.timestamp,
+ type: report.type
+ };
+ report.names().forEach(function(name) {
+ standardStats[name] = report.stat(name);
+ });
+ standardReport[standardStats.id] = standardStats;
+ });
+
+ return standardReport;
+ };
+
+ if (arguments.length >= 2) {
+ var successCallbackWrapper = function(response) {
+ args[1](fixChromeStats(response));
+ };
+
+ return origGetStats.apply(this, [successCallbackWrapper, arguments[0]]);
+ }
+
+ // promise-support
+ return new Promise(function(resolve, reject) {
+ if (args.length === 1 && selector === null) {
+ origGetStats.apply(self, [
+ function(response) {
+ resolve.apply(null, [fixChromeStats(response)]);
+ }, reject]);
+ } else {
+ origGetStats.apply(self, [resolve, reject]);
+ }
+ });
+ };
+
+ return pc;
+ };
+ window.RTCPeerConnection.prototype = webkitRTCPeerConnection.prototype;
+
+ // wrap static methods. Currently just generateCertificate.
+ if (webkitRTCPeerConnection.generateCertificate) {
+ Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
+ get: function() {
+ if (arguments.length) {
+ return webkitRTCPeerConnection.generateCertificate.apply(null,
+ arguments);
+ } else {
+ return webkitRTCPeerConnection.generateCertificate;
+ }
+ }
+ });
+ }
+
+ // add promise support
+ ['createOffer', 'createAnswer'].forEach(function(method) {
+ var nativeMethod = webkitRTCPeerConnection.prototype[method];
+ webkitRTCPeerConnection.prototype[method] = function() {
+ var self = this;
+ if (arguments.length < 1 || (arguments.length === 1 &&
+ typeof(arguments[0]) === 'object')) {
+ var opts = arguments.length === 1 ? arguments[0] : undefined;
+ return new Promise(function(resolve, reject) {
+ nativeMethod.apply(self, [resolve, reject, opts]);
+ });
+ } else {
+ return nativeMethod.apply(this, arguments);
+ }
+ };
+ });
-exports.Parser.prototype.end = function(data) {
- this.parser.end(data)
+ ['setLocalDescription', 'setRemoteDescription',
+ 'addIceCandidate'].forEach(function(method) {
+ var nativeMethod = webkitRTCPeerConnection.prototype[method];
+ webkitRTCPeerConnection.prototype[method] = function() {
+ var args = arguments;
+ var self = this;
+ return new Promise(function(resolve, reject) {
+ nativeMethod.apply(self, [args[0],
+ function() {
+ resolve();
+ if (args.length >= 2) {
+ args[1].apply(null, []);
+ }
+ },
+ function(err) {
+ reject(err);
+ if (args.length >= 3) {
+ args[2].apply(null, [err]);
+ }
+ }]
+ );
+ });
+ };
+ });
- if (!this.error) {
- if (this.tree) {
- this.emit('tree', this.tree)
+ // getUserMedia constraints shim.
+ var constraintsToChrome = function(c) {
+ if (typeof c !== 'object' || c.mandatory || c.optional) {
+ return c;
+ }
+ var cc = {};
+ Object.keys(c).forEach(function(key) {
+ if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
+ return;
+ }
+ var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]};
+ if (r.exact !== undefined && typeof r.exact === 'number') {
+ r.min = r.max = r.exact;
+ }
+ var oldname = function(prefix, name) {
+ if (prefix) {
+ return prefix + name.charAt(0).toUpperCase() + name.slice(1);
+ }
+ return (name === 'deviceId') ? 'sourceId' : name;
+ };
+ if (r.ideal !== undefined) {
+ cc.optional = cc.optional || [];
+ var oc = {};
+ if (typeof r.ideal === 'number') {
+ oc[oldname('min', key)] = r.ideal;
+ cc.optional.push(oc);
+ oc = {};
+ oc[oldname('max', key)] = r.ideal;
+ cc.optional.push(oc);
} else {
- this.emit('error', new Error('Incomplete document'))
+ oc[oldname('', key)] = r.ideal;
+ cc.optional.push(oc);
}
+ }
+ if (r.exact !== undefined && typeof r.exact !== 'number') {
+ cc.mandatory = cc.mandatory || {};
+ cc.mandatory[oldname('', key)] = r.exact;
+ } else {
+ ['min', 'max'].forEach(function(mix) {
+ if (r[mix] !== undefined) {
+ cc.mandatory = cc.mandatory || {};
+ cc.mandatory[oldname(mix, key)] = r[mix];
+ }
+ });
+ }
+ });
+ if (c.advanced) {
+ cc.optional = (cc.optional || []).concat(c.advanced);
}
-}
+ return cc;
+ };
+
+ getUserMedia = function(constraints, onSuccess, onError) {
+ if (constraints.audio) {
+ constraints.audio = constraintsToChrome(constraints.audio);
+ }
+ if (constraints.video) {
+ constraints.video = constraintsToChrome(constraints.video);
+ }
+ webrtcUtils.log('chrome: ' + JSON.stringify(constraints));
+ return navigator.webkitGetUserMedia(constraints, onSuccess, onError);
+ };
+ navigator.getUserMedia = getUserMedia;
-exports.parse = function(data, saxParser) {
- var p = new exports.Parser(saxParser)
- var result = null
- , error = null
+ if (!navigator.mediaDevices) {
+ navigator.mediaDevices = {getUserMedia: requestUserMedia,
+ enumerateDevices: function() {
+ return new Promise(function(resolve) {
+ var kinds = {audio: 'audioinput', video: 'videoinput'};
+ return MediaStreamTrack.getSources(function(devices) {
+ resolve(devices.map(function(device) {
+ return {label: device.label,
+ kind: kinds[device.kind],
+ deviceId: device.id,
+ groupId: ''};
+ }));
+ });
+ });
+ }};
+ }
- p.on('tree', function(tree) {
- result = tree
- })
- p.on('error', function(e) {
- error = e
- })
+ // A shim for getUserMedia method on the mediaDevices object.
+ // TODO(KaptenJansson) remove once implemented in Chrome stable.
+ if (!navigator.mediaDevices.getUserMedia) {
+ navigator.mediaDevices.getUserMedia = function(constraints) {
+ return requestUserMedia(constraints);
+ };
+ } else {
+ // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia
+ // function which returns a Promise, it does not accept spec-style
+ // constraints.
+ var origGetUserMedia = navigator.mediaDevices.getUserMedia.
+ bind(navigator.mediaDevices);
+ navigator.mediaDevices.getUserMedia = function(c) {
+ webrtcUtils.log('spec: ' + JSON.stringify(c)); // whitespace for alignment
+ c.audio = constraintsToChrome(c.audio);
+ c.video = constraintsToChrome(c.video);
+ webrtcUtils.log('chrome: ' + JSON.stringify(c));
+ return origGetUserMedia(c);
+ };
+ }
- p.write(data)
- p.end()
+ // Dummy devicechange event methods.
+ // TODO(KaptenJansson) remove once implemented in Chrome stable.
+ if (typeof navigator.mediaDevices.addEventListener === 'undefined') {
+ navigator.mediaDevices.addEventListener = function() {
+ webrtcUtils.log('Dummy mediaDevices.addEventListener called.');
+ };
+ }
+ if (typeof navigator.mediaDevices.removeEventListener === 'undefined') {
+ navigator.mediaDevices.removeEventListener = function() {
+ webrtcUtils.log('Dummy mediaDevices.removeEventListener called.');
+ };
+ }
- if (error) {
- throw error
+ // Attach a media stream to an element.
+ attachMediaStream = function(element, stream) {
+ if (webrtcDetectedVersion >= 43) {
+ element.srcObject = stream;
+ } else if (typeof element.src !== 'undefined') {
+ element.src = URL.createObjectURL(stream);
+ } else {
+ webrtcUtils.log('Error attaching stream to element.');
+ }
+ };
+ reattachMediaStream = function(to, from) {
+ if (webrtcDetectedVersion >= 43) {
+ to.srcObject = from.srcObject;
} else {
- return result
+ to.src = from.src;
+ }
+ };
+
+} else if (navigator.mediaDevices && navigator.userAgent.match(
+ /Edge\/(\d+).(\d+)$/)) {
+ webrtcUtils.log('This appears to be Edge');
+ webrtcDetectedBrowser = 'edge';
+
+ webrtcDetectedVersion = webrtcUtils.extractVersion(navigator.userAgent,
+ /Edge\/(\d+).(\d+)$/, 2);
+
+ // The minimum version still supported by adapter.
+ // This is the build number for Edge.
+ webrtcMinimumVersion = 10547;
+
+ if (window.RTCIceGatherer) {
+ // Generate an alphanumeric identifier for cname or mids.
+ // TODO: use UUIDs instead? https://gist.github.com/jed/982883
+ var generateIdentifier = function() {
+ return Math.random().toString(36).substr(2, 10);
+ };
+
+ // The RTCP CNAME used by all peerconnections from the same JS.
+ var localCName = generateIdentifier();
+
+ // SDP helpers - to be moved into separate module.
+ var SDPUtils = {};
+
+ // Splits SDP into lines, dealing with both CRLF and LF.
+ SDPUtils.splitLines = function(blob) {
+ return blob.trim().split('\n').map(function(line) {
+ return line.trim();
+ });
+ };
+
+ // Splits SDP into sessionpart and mediasections. Ensures CRLF.
+ SDPUtils.splitSections = function(blob) {
+ var parts = blob.split('\r\nm=');
+ return parts.map(function(part, index) {
+ return (index > 0 ? 'm=' + part : part).trim() + '\r\n';
+ });
+ };
+
+ // Returns lines that start with a certain prefix.
+ SDPUtils.matchPrefix = function(blob, prefix) {
+ return SDPUtils.splitLines(blob).filter(function(line) {
+ return line.indexOf(prefix) === 0;
+ });
+ };
+
+ // Parses an ICE candidate line. Sample input:
+ // candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 rport 55996"
+ SDPUtils.parseCandidate = function(line) {
+ var parts;
+ // Parse both variants.
+ if (line.indexOf('a=candidate:') === 0) {
+ parts = line.substring(12).split(' ');
+ } else {
+ parts = line.substring(10).split(' ');
+ }
+
+ var candidate = {
+ foundation: parts[0],
+ component: parts[1],
+ protocol: parts[2].toLowerCase(),
+ priority: parseInt(parts[3], 10),
+ ip: parts[4],
+ port: parseInt(parts[5], 10),
+ // skip parts[6] == 'typ'
+ type: parts[7]
+ };
+
+ for (var i = 8; i < parts.length; i += 2) {
+ switch (parts[i]) {
+ case 'raddr':
+ candidate.relatedAddress = parts[i + 1];
+ break;
+ case 'rport':
+ candidate.relatedPort = parseInt(parts[i + 1], 10);
+ break;
+ case 'tcptype':
+ candidate.tcpType = parts[i + 1];
+ break;
+ default: // Unknown extensions are silently ignored.
+ break;
+ }
+ }
+ return candidate;
+ };
+
+ // Translates a candidate object into SDP candidate attribute.
+ SDPUtils.writeCandidate = function(candidate) {
+ var sdp = [];
+ sdp.push(candidate.foundation);
+ sdp.push(candidate.component);
+ sdp.push(candidate.protocol.toUpperCase());
+ sdp.push(candidate.priority);
+ sdp.push(candidate.ip);
+ sdp.push(candidate.port);
+
+ var type = candidate.type;
+ sdp.push('typ');
+ sdp.push(type);
+ if (type !== 'host' && candidate.relatedAddress &&
+ candidate.relatedPort) {
+ sdp.push('raddr');
+ sdp.push(candidate.relatedAddress); // was: relAddr
+ sdp.push('rport');
+ sdp.push(candidate.relatedPort); // was: relPort
+ }
+ if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {
+ sdp.push('tcptype');
+ sdp.push(candidate.tcpType);
+ }
+ return 'candidate:' + sdp.join(' ');
+ };
+
+ // Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input:
+ // a=rtpmap:111 opus/48000/2
+ SDPUtils.parseRtpMap = function(line) {
+ var parts = line.substr(9).split(' ');
+ var parsed = {
+ payloadType: parseInt(parts.shift(), 10) // was: id
+ };
+
+ parts = parts[0].split('/');
+
+ parsed.name = parts[0];
+ parsed.clockRate = parseInt(parts[1], 10); // was: clockrate
+ parsed.numChannels = parts.length === 3 ? parseInt(parts[2], 10) : 1; // was: channels
+ return parsed;
+ };
+
+ // Generate an a=rtpmap line from RTCRtpCodecCapability or RTCRtpCodecParameters.
+ SDPUtils.writeRtpMap = function(codec) {
+ var pt = codec.payloadType;
+ if (codec.preferredPayloadType !== undefined) {
+ pt = codec.preferredPayloadType;
+ }
+ return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate +
+ (codec.numChannels !== 1 ? '/' + codec.numChannels : '') + '\r\n';
+ };
+
+ // Parses an ftmp line, returns dictionary. Sample input:
+ // a=fmtp:96 vbr=on;cng=on
+ // Also deals with vbr=on; cng=on
+ SDPUtils.parseFmtp = function(line) {
+ var parsed = {};
+ var kv;
+ var parts = line.substr(line.indexOf(' ') + 1).split(';');
+ for (var j = 0; j < parts.length; j++) {
+ kv = parts[j].trim().split('=');
+ parsed[kv[0].trim()] = kv[1];
+ }
+ return parsed;
+ };
+
+ // Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters.
+ SDPUtils.writeFtmp = function(codec) {
+ var line = '';
+ var pt = codec.payloadType;
+ if (codec.preferredPayloadType !== undefined) {
+ pt = codec.preferredPayloadType;
+ }
+ if (codec.parameters && codec.parameters.length) {
+ var params = [];
+ Object.keys(codec.parameters).forEach(function(param) {
+ params.push(param + '=' + codec.parameters[param]);
+ });
+ line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n';
+ }
+ return line;
+ };
+
+ // Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:
+ // a=rtcp-fb:98 nack rpsi
+ SDPUtils.parseRtcpFb = function(line) {
+ var parts = line.substr(line.indexOf(' ') + 1).split(' ');
+ return {
+ type: parts.shift(),
+ parameter: parts.join(' ')
+ };
+ };
+ // Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.
+ SDPUtils.writeRtcpFb = function(codec) {
+ var lines = '';
+ var pt = codec.payloadType;
+ if (codec.preferredPayloadType !== undefined) {
+ pt = codec.preferredPayloadType;
+ }
+ if (codec.rtcpFeedback && codec.rtcpFeedback.length) {
+ // FIXME: special handling for trr-int?
+ codec.rtcpFeedback.forEach(function(fb) {
+ lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + ' ' + fb.parameter +
+ '\r\n';
+ });
+ }
+ return lines;
+ };
+
+ // Parses an RFC 5576 ssrc media attribute. Sample input:
+ // a=ssrc:3735928559 cname:something
+ SDPUtils.parseSsrcMedia = function(line) {
+ var sp = line.indexOf(' ');
+ var parts = {
+ ssrc: line.substr(7, sp - 7),
+ };
+ var colon = line.indexOf(':', sp);
+ if (colon > -1) {
+ parts.attribute = line.substr(sp + 1, colon - sp - 1);
+ parts.value = line.substr(colon + 1);
+ } else {
+ parts.attribute = line.substr(sp + 1);
+ }
+ return parts;
+ };
+
+ // Extracts DTLS parameters from SDP media section or sessionpart.
+ // FIXME: for consistency with other functions this should only
+ // get the fingerprint line as input. See also getIceParameters.
+ SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) {
+ var lines = SDPUtils.splitLines(mediaSection);
+ lines = lines.concat(SDPUtils.splitLines(sessionpart)); // Search in session part, too.
+ var fpLine = lines.filter(function(line) {
+ return line.indexOf('a=fingerprint:') === 0;
+ })[0].substr(14);
+ // Note: a=setup line is ignored since we use the 'auto' role.
+ var dtlsParameters = {
+ role: 'auto',
+ fingerprints: [{
+ algorithm: fpLine.split(' ')[0],
+ value: fpLine.split(' ')[1]
+ }]
+ };
+ return dtlsParameters;
+ };
+
+ // Serializes DTLS parameters to SDP.
+ SDPUtils.writeDtlsParameters = function(params, setupType) {
+ var sdp = 'a=setup:' + setupType + '\r\n';
+ params.fingerprints.forEach(function(fp) {
+ sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n';
+ });
+ return sdp;
+ };
+ // Parses ICE information from SDP media section or sessionpart.
+ // FIXME: for consistency with other functions this should only
+ // get the ice-ufrag and ice-pwd lines as input.
+ SDPUtils.getIceParameters = function(mediaSection, sessionpart) {
+ var lines = SDPUtils.splitLines(mediaSection);
+ lines = lines.concat(SDPUtils.splitLines(sessionpart)); // Search in session part, too.
+ var iceParameters = {
+ usernameFragment: lines.filter(function(line) {
+ return line.indexOf('a=ice-ufrag:') === 0;
+ })[0].substr(12),
+ password: lines.filter(function(line) {
+ return line.indexOf('a=ice-pwd:') === 0;
+ })[0].substr(10)
+ };
+ return iceParameters;
+ };
+
+ // Serializes ICE parameters to SDP.
+ SDPUtils.writeIceParameters = function(params) {
+ return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' +
+ 'a=ice-pwd:' + params.password + '\r\n';
+ };
+
+ // Parses the SDP media section and returns RTCRtpParameters.
+ SDPUtils.parseRtpParameters = function(mediaSection) {
+ var description = {
+ codecs: [],
+ headerExtensions: [],
+ fecMechanisms: [],
+ rtcp: []
+ };
+ var lines = SDPUtils.splitLines(mediaSection);
+ var mline = lines[0].split(' ');
+ for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..]
+ var pt = mline[i];
+ var rtpmapline = SDPUtils.matchPrefix(
+ mediaSection, 'a=rtpmap:' + pt + ' ')[0];
+ if (rtpmapline) {
+ var codec = SDPUtils.parseRtpMap(rtpmapline);
+ var fmtps = SDPUtils.matchPrefix(
+ mediaSection, 'a=fmtp:' + pt + ' ');
+ // Only the first a=fmtp:<pt> is considered.
+ codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};
+ codec.rtcpFeedback = SDPUtils.matchPrefix(
+ mediaSection, 'a=rtcp-fb:' + pt + ' ')
+ .map(SDPUtils.parseRtcpFb);
+ description.codecs.push(codec);
+ }
+ }
+ // FIXME: parse headerExtensions, fecMechanisms and rtcp.
+ return description;
+ };
+
+ // Generates parts of the SDP media section describing the capabilities / parameters.
+ SDPUtils.writeRtpDescription = function(kind, caps) {
+ var sdp = '';
+
+ // Build the mline.
+ sdp += 'm=' + kind + ' ';
+ sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.
+ sdp += ' UDP/TLS/RTP/SAVPF ';
+ sdp += caps.codecs.map(function(codec) {
+ if (codec.preferredPayloadType !== undefined) {
+ return codec.preferredPayloadType;
+ }
+ return codec.payloadType;
+ }).join(' ') + '\r\n';
+
+ sdp += 'c=IN IP4 0.0.0.0\r\n';
+ sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n';
+
+ // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.
+ caps.codecs.forEach(function(codec) {
+ sdp += SDPUtils.writeRtpMap(codec);
+ sdp += SDPUtils.writeFtmp(codec);
+ sdp += SDPUtils.writeRtcpFb(codec);
+ });
+ // FIXME: add headerExtensions, fecMechanismş and rtcp.
+ sdp += 'a=rtcp-mux\r\n';
+ return sdp;
+ };
+
+ SDPUtils.writeSessionBoilerplate = function() {
+ // FIXME: sess-id should be an NTP timestamp.
+ return 'v=0\r\n' +
+ 'o=thisisadapterortc 8169639915646943137 2 IN IP4 127.0.0.1\r\n' +
+ 's=-\r\n' +
+ 't=0 0\r\n';
+ };
+
+ SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) {
+ var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps);
+
+ // Map ICE parameters (ufrag, pwd) to SDP.
+ sdp += SDPUtils.writeIceParameters(
+ transceiver.iceGatherer.getLocalParameters());
+
+ // Map DTLS parameters to SDP.
+ sdp += SDPUtils.writeDtlsParameters(
+ transceiver.dtlsTransport.getLocalParameters(),
+ type === 'offer' ? 'actpass' : 'active');
+
+ sdp += 'a=mid:' + transceiver.mid + '\r\n';
+
+ if (transceiver.rtpSender && transceiver.rtpReceiver) {
+ sdp += 'a=sendrecv\r\n';
+ } else if (transceiver.rtpSender) {
+ sdp += 'a=sendonly\r\n';
+ } else if (transceiver.rtpReceiver) {
+ sdp += 'a=recvonly\r\n';
+ } else {
+ sdp += 'a=inactive\r\n';
+ }
+
+ // FIXME: for RTX there might be multiple SSRCs. Not implemented in Edge yet.
+ if (transceiver.rtpSender) {
+ var msid = 'msid:' + stream.id + ' ' +
+ transceiver.rtpSender.track.id + '\r\n';
+ sdp += 'a=' + msid;
+ sdp += 'a=ssrc:' + transceiver.sendSsrc + ' ' + msid;
+ }
+ // FIXME: this should be written by writeRtpDescription.
+ sdp += 'a=ssrc:' + transceiver.sendSsrc + ' cname:' +
+ localCName + '\r\n';
+ return sdp;
+ };
+
+ // Gets the direction from the mediaSection or the sessionpart.
+ SDPUtils.getDirection = function(mediaSection, sessionpart) {
+ // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.
+ var lines = SDPUtils.splitLines(mediaSection);
+ for (var i = 0; i < lines.length; i++) {
+ switch (lines[i]) {
+ case 'a=sendrecv':
+ case 'a=sendonly':
+ case 'a=recvonly':
+ case 'a=inactive':
+ return lines[i].substr(2);
+ }
+ }
+ if (sessionpart) {
+ return SDPUtils.getDirection(sessionpart);
+ }
+ return 'sendrecv';
+ };
+
+ // ORTC defines an RTCIceCandidate object but no constructor.
+ // Not implemented in Edge.
+ if (!window.RTCIceCandidate) {
+ window.RTCIceCandidate = function(args) {
+ return args;
+ };
+ }
+ // ORTC does not have a session description object but
+ // other browsers (i.e. Chrome) that will support both PC and ORTC
+ // in the future might have this defined already.
+ if (!window.RTCSessionDescription) {
+ window.RTCSessionDescription = function(args) {
+ return args;
+ };
+ }
+
+ window.RTCPeerConnection = function(config) {
+ var self = this;
+
+ this.onicecandidate = null;
+ this.onaddstream = null;
+ this.onremovestream = null;
+ this.onsignalingstatechange = null;
+ this.oniceconnectionstatechange = null;
+ this.onnegotiationneeded = null;
+ this.ondatachannel = null;
+
+ this.localStreams = [];
+ this.remoteStreams = [];
+ this.getLocalStreams = function() { return self.localStreams; };
+ this.getRemoteStreams = function() { return self.remoteStreams; };
+
+ this.localDescription = new RTCSessionDescription({
+ type: '',
+ sdp: ''
+ });
+ this.remoteDescription = new RTCSessionDescription({
+ type: '',
+ sdp: ''
+ });
+ this.signalingState = 'stable';
+ this.iceConnectionState = 'new';
+
+ this.iceOptions = {
+ gatherPolicy: 'all',
+ iceServers: []
+ };
+ if (config && config.iceTransportPolicy) {
+ switch (config.iceTransportPolicy) {
+ case 'all':
+ case 'relay':
+ this.iceOptions.gatherPolicy = config.iceTransportPolicy;
+ break;
+ case 'none':
+ // FIXME: remove once implementation and spec have added this.
+ throw new TypeError('iceTransportPolicy "none" not supported');
+ }
+ }
+ if (config && config.iceServers) {
+ // Edge does not like
+ // 1) stun:
+ // 2) turn: that does not have all of turn:host:port?transport=udp
+ // 3) an array of urls
+ config.iceServers.forEach(function(server) {
+ if (server.urls) {
+ var url;
+ if (typeof(server.urls) === 'string') {
+ url = server.urls;
+ } else {
+ url = server.urls[0];
+ }
+ if (url.indexOf('transport=udp') !== -1) {
+ self.iceServers.push({
+ username: server.username,
+ credential: server.credential,
+ urls: url
+ });
+ }
+ }
+ });
+ }
+
+ // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ...
+ // everything that is needed to describe a SDP m-line.
+ this.transceivers = [];
+
+ // since the iceGatherer is currently created in createOffer but we
+ // must not emit candidates until after setLocalDescription we buffer
+ // them in this array.
+ this._localIceCandidatesBuffer = [];
+ };
+
+ window.RTCPeerConnection.prototype._emitBufferedCandidates = function() {
+ var self = this;
+ // FIXME: need to apply ice candidates in a way which is async but in-order
+ this._localIceCandidatesBuffer.forEach(function(event) {
+ if (self.onicecandidate !== null) {
+ self.onicecandidate(event);
+ }
+ });
+ this._localIceCandidatesBuffer = [];
+ };
+
+ window.RTCPeerConnection.prototype.addStream = function(stream) {
+ // Clone is necessary for local demos mostly, attaching directly
+ // to two different senders does not work (build 10547).
+ this.localStreams.push(stream.clone());
+ this._maybeFireNegotiationNeeded();
+ };
+
+ window.RTCPeerConnection.prototype.removeStream = function(stream) {
+ var idx = this.localStreams.indexOf(stream);
+ if (idx > -1) {
+ this.localStreams.splice(idx, 1);
+ this._maybeFireNegotiationNeeded();
+ }
+ };
+
+ // Determines the intersection of local and remote capabilities.
+ window.RTCPeerConnection.prototype._getCommonCapabilities =
+ function(localCapabilities, remoteCapabilities) {
+ var commonCapabilities = {
+ codecs: [],
+ headerExtensions: [],
+ fecMechanisms: []
+ };
+ localCapabilities.codecs.forEach(function(lCodec) {
+ for (var i = 0; i < remoteCapabilities.codecs.length; i++) {
+ var rCodec = remoteCapabilities.codecs[i];
+ if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() &&
+ lCodec.clockRate === rCodec.clockRate &&
+ lCodec.numChannels === rCodec.numChannels) {
+ // push rCodec so we reply with offerer payload type
+ commonCapabilities.codecs.push(rCodec);
+
+ // FIXME: also need to determine intersection between
+ // .rtcpFeedback and .parameters
+ break;
+ }
+ }
+ });
+
+ localCapabilities.headerExtensions.forEach(function(lHeaderExtension) {
+ for (var i = 0; i < remoteCapabilities.headerExtensions.length; i++) {
+ var rHeaderExtension = remoteCapabilities.headerExtensions[i];
+ if (lHeaderExtension.uri === rHeaderExtension.uri) {
+ commonCapabilities.headerExtensions.push(rHeaderExtension);
+ break;
+ }
+ }
+ });
+
+ // FIXME: fecMechanisms
+ return commonCapabilities;
+ };
+
+ // Create ICE gatherer, ICE transport and DTLS transport.
+ window.RTCPeerConnection.prototype._createIceAndDtlsTransports =
+ function(mid, sdpMLineIndex) {
+ var self = this;
+ var iceGatherer = new RTCIceGatherer(self.iceOptions);
+ var iceTransport = new RTCIceTransport(iceGatherer);
+ iceGatherer.onlocalcandidate = function(evt) {
+ var event = {};
+ event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex};
+
+ var cand = evt.candidate;
+ // Edge emits an empty object for RTCIceCandidateComplete‥
+ if (!cand || Object.keys(cand).length === 0) {
+ // polyfill since RTCIceGatherer.state is not implemented in Edge 10547 yet.
+ if (iceGatherer.state === undefined) {
+ iceGatherer.state = 'completed';
+ }
+
+ // Emit a candidate with type endOfCandidates to make the samples work.
+ // Edge requires addIceCandidate with this empty candidate to start checking.
+ // The real solution is to signal end-of-candidates to the other side when
+ // getting the null candidate but some apps (like the samples) don't do that.
+ event.candidate.candidate =
+ 'candidate:1 1 udp 1 0.0.0.0 9 typ endOfCandidates';
+ } else {
+ // RTCIceCandidate doesn't have a component, needs to be added
+ cand.component = iceTransport.component === 'RTCP' ? 2 : 1;
+ event.candidate.candidate = SDPUtils.writeCandidate(cand);
+ }
+
+ var complete = self.transceivers.every(function(transceiver) {
+ return transceiver.iceGatherer &&
+ transceiver.iceGatherer.state === 'completed';
+ });
+ // FIXME: update .localDescription with candidate and (potentially) end-of-candidates.
+ // To make this harder, the gatherer might emit candidates before localdescription
+ // is set. To make things worse, gather.getLocalCandidates still errors in
+ // Edge 10547 when no candidates have been gathered yet.
+
+ if (self.onicecandidate !== null) {
+ // Emit candidate if localDescription is set.
+ // Also emits null candidate when all gatherers are complete.
+ if (self.localDescription && self.localDescription.type === '') {
+ self._localIceCandidatesBuffer.push(event);
+ if (complete) {
+ self._localIceCandidatesBuffer.push({});
+ }
+ } else {
+ self.onicecandidate(event);
+ if (complete) {
+ self.onicecandidate({});
+ }
+ }
+ }
+ };
+ iceTransport.onicestatechange = function() {
+ self._updateConnectionState();
+ };
+
+ var dtlsTransport = new RTCDtlsTransport(iceTransport);
+ dtlsTransport.ondtlsstatechange = function() {
+ self._updateConnectionState();
+ };
+ dtlsTransport.onerror = function() {
+ // onerror does not set state to failed by itself.
+ dtlsTransport.state = 'failed';
+ self._updateConnectionState();
+ };
+
+ return {
+ iceGatherer: iceGatherer,
+ iceTransport: iceTransport,
+ dtlsTransport: dtlsTransport
+ };
+ };
+
+ // Start the RTP Sender and Receiver for a transceiver.
+ window.RTCPeerConnection.prototype._transceive = function(transceiver,
+ send, recv) {
+ var params = this._getCommonCapabilities(transceiver.localCapabilities,
+ transceiver.remoteCapabilities);
+ if (send && transceiver.rtpSender) {
+ params.encodings = [{
+ ssrc: transceiver.sendSsrc
+ }];
+ params.rtcp = {
+ cname: localCName,
+ ssrc: transceiver.recvSsrc
+ };
+ transceiver.rtpSender.send(params);
+ }
+ if (recv && transceiver.rtpReceiver) {
+ params.encodings = [{
+ ssrc: transceiver.recvSsrc
+ }];
+ params.rtcp = {
+ cname: transceiver.cname,
+ ssrc: transceiver.sendSsrc
+ };
+ transceiver.rtpReceiver.receive(params);
+ }
+ };
+
+ window.RTCPeerConnection.prototype.setLocalDescription =
+ function(description) {
+ var self = this;
+ if (description.type === 'offer') {
+ if (!this._pendingOffer) {
+ } else {
+ this.transceivers = this._pendingOffer;
+ delete this._pendingOffer;
+ }
+ } else if (description.type === 'answer') {
+ var sections = SDPUtils.splitSections(self.remoteDescription.sdp);
+ var sessionpart = sections.shift();
+ sections.forEach(function(mediaSection, sdpMLineIndex) {
+ var transceiver = self.transceivers[sdpMLineIndex];
+ var iceGatherer = transceiver.iceGatherer;
+ var iceTransport = transceiver.iceTransport;
+ var dtlsTransport = transceiver.dtlsTransport;
+ var localCapabilities = transceiver.localCapabilities;
+ var remoteCapabilities = transceiver.remoteCapabilities;
+ var rejected = mediaSection.split('\n', 1)[0]
+ .split(' ', 2)[1] === '0';
+
+ if (!rejected) {
+ var remoteIceParameters = SDPUtils.getIceParameters(mediaSection,
+ sessionpart);
+ iceTransport.start(iceGatherer, remoteIceParameters, 'controlled');
+
+ var remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection,
+ sessionpart);
+ dtlsTransport.start(remoteDtlsParameters);
+
+ // Calculate intersection of capabilities.
+ var params = self._getCommonCapabilities(localCapabilities,
+ remoteCapabilities);
+
+ // Start the RTCRtpSender. The RTCRtpReceiver for this transceiver
+ // has already been started in setRemoteDescription.
+ self._transceive(transceiver,
+ params.codecs.length > 0,
+ false);
+ }
+ });
+ }
+
+ this.localDescription = description;
+ switch (description.type) {
+ case 'offer':
+ this._updateSignalingState('have-local-offer');
+ break;
+ case 'answer':
+ this._updateSignalingState('stable');
+ break;
+ default:
+ throw new TypeError('unsupported type "' + description.type + '"');
+ }
+
+ // If a success callback was provided, emit ICE candidates after it has been
+ // executed. Otherwise, emit callback after the Promise is resolved.
+ var hasCallback = arguments.length > 1 &&
+ typeof arguments[1] === 'function';
+ if (hasCallback) {
+ var cb = arguments[1];
+ window.setTimeout(function() {
+ cb();
+ self._emitBufferedCandidates();
+ }, 0);
+ }
+ var p = Promise.resolve();
+ p.then(function() {
+ if (!hasCallback) {
+ window.setTimeout(self._emitBufferedCandidates.bind(self), 0);
+ }
+ });
+ return p;
+ };
+
+ window.RTCPeerConnection.prototype.setRemoteDescription =
+ function(description) {
+ var self = this;
+ var stream = new MediaStream();
+ var sections = SDPUtils.splitSections(description.sdp);
+ var sessionpart = sections.shift();
+ sections.forEach(function(mediaSection, sdpMLineIndex) {
+ var lines = SDPUtils.splitLines(mediaSection);
+ var mline = lines[0].substr(2).split(' ');
+ var kind = mline[0];
+ var rejected = mline[1] === '0';
+ var direction = SDPUtils.getDirection(mediaSection, sessionpart);
+
+ var transceiver;
+ var iceGatherer;
+ var iceTransport;
+ var dtlsTransport;
+ var rtpSender;
+ var rtpReceiver;
+ var sendSsrc;
+ var recvSsrc;
+ var localCapabilities;
+
+ // FIXME: ensure the mediaSection has rtcp-mux set.
+ var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection);
+ var remoteIceParameters;
+ var remoteDtlsParameters;
+ if (!rejected) {
+ remoteIceParameters = SDPUtils.getIceParameters(mediaSection,
+ sessionpart);
+ remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection,
+ sessionpart);
+ }
+ var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0].substr(6);
+
+ var cname;
+ // Gets the first SSRC. Note that with RTX there might be multiple SSRCs.
+ var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
+ .map(function(line) {
+ return SDPUtils.parseSsrcMedia(line);
+ })
+ .filter(function(obj) {
+ return obj.attribute === 'cname';
+ })[0];
+ if (remoteSsrc) {
+ recvSsrc = parseInt(remoteSsrc.ssrc, 10);
+ cname = remoteSsrc.value;
+ }
+
+ if (description.type === 'offer') {
+ var transports = self._createIceAndDtlsTransports(mid, sdpMLineIndex);
+
+ localCapabilities = RTCRtpReceiver.getCapabilities(kind);
+ sendSsrc = (2 * sdpMLineIndex + 2) * 1001;
+
+ rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind);
+
+ // FIXME: not correct when there are multiple streams but that is
+ // not currently supported in this shim.
+ stream.addTrack(rtpReceiver.track);
+
+ // FIXME: look at direction.
+ if (self.localStreams.length > 0 &&
+ self.localStreams[0].getTracks().length >= sdpMLineIndex) {
+ // FIXME: actually more complicated, needs to match types etc
+ var localtrack = self.localStreams[0].getTracks()[sdpMLineIndex];
+ rtpSender = new RTCRtpSender(localtrack, transports.dtlsTransport);
+ }
+
+ self.transceivers[sdpMLineIndex] = {
+ iceGatherer: transports.iceGatherer,
+ iceTransport: transports.iceTransport,
+ dtlsTransport: transports.dtlsTransport,
+ localCapabilities: localCapabilities,
+ remoteCapabilities: remoteCapabilities,
+ rtpSender: rtpSender,
+ rtpReceiver: rtpReceiver,
+ kind: kind,
+ mid: mid,
+ cname: cname,
+ sendSsrc: sendSsrc,
+ recvSsrc: recvSsrc
+ };
+ // Start the RTCRtpReceiver now. The RTPSender is started in setLocalDescription.
+ self._transceive(self.transceivers[sdpMLineIndex],
+ false,
+ direction === 'sendrecv' || direction === 'sendonly');
+ } else if (description.type === 'answer' && !rejected) {
+ transceiver = self.transceivers[sdpMLineIndex];
+ iceGatherer = transceiver.iceGatherer;
+ iceTransport = transceiver.iceTransport;
+ dtlsTransport = transceiver.dtlsTransport;
+ rtpSender = transceiver.rtpSender;
+ rtpReceiver = transceiver.rtpReceiver;
+ sendSsrc = transceiver.sendSsrc;
+ //recvSsrc = transceiver.recvSsrc;
+ localCapabilities = transceiver.localCapabilities;
+
+ self.transceivers[sdpMLineIndex].recvSsrc = recvSsrc;
+ self.transceivers[sdpMLineIndex].remoteCapabilities =
+ remoteCapabilities;
+ self.transceivers[sdpMLineIndex].cname = cname;
+
+ iceTransport.start(iceGatherer, remoteIceParameters, 'controlling');
+ dtlsTransport.start(remoteDtlsParameters);
+
+ self._transceive(transceiver,
+ direction === 'sendrecv' || direction === 'recvonly',
+ direction === 'sendrecv' || direction === 'sendonly');
+
+ if (rtpReceiver &&
+ (direction === 'sendrecv' || direction === 'sendonly')) {
+ stream.addTrack(rtpReceiver.track);
+ } else {
+ // FIXME: actually the receiver should be created later.
+ delete transceiver.rtpReceiver;
+ }
+ }
+ });
+
+ this.remoteDescription = description;
+ switch (description.type) {
+ case 'offer':
+ this._updateSignalingState('have-remote-offer');
+ break;
+ case 'answer':
+ this._updateSignalingState('stable');
+ break;
+ default:
+ throw new TypeError('unsupported type "' + description.type + '"');
+ }
+ window.setTimeout(function() {
+ if (self.onaddstream !== null && stream.getTracks().length) {
+ self.remoteStreams.push(stream);
+ window.setTimeout(function() {
+ self.onaddstream({stream: stream});
+ }, 0);
+ }
+ }, 0);
+ if (arguments.length > 1 && typeof arguments[1] === 'function') {
+ window.setTimeout(arguments[1], 0);
+ }
+ return Promise.resolve();
+ };
+
+ window.RTCPeerConnection.prototype.close = function() {
+ this.transceivers.forEach(function(transceiver) {
+ /* not yet
+ if (transceiver.iceGatherer) {
+ transceiver.iceGatherer.close();
+ }
+ */
+ if (transceiver.iceTransport) {
+ transceiver.iceTransport.stop();
+ }
+ if (transceiver.dtlsTransport) {
+ transceiver.dtlsTransport.stop();
+ }
+ if (transceiver.rtpSender) {
+ transceiver.rtpSender.stop();
+ }
+ if (transceiver.rtpReceiver) {
+ transceiver.rtpReceiver.stop();
+ }
+ });
+ // FIXME: clean up tracks, local streams, remote streams, etc
+ this._updateSignalingState('closed');
+ };
+
+ // Update the signaling state.
+ window.RTCPeerConnection.prototype._updateSignalingState =
+ function(newState) {
+ this.signalingState = newState;
+ if (this.onsignalingstatechange !== null) {
+ this.onsignalingstatechange();
+ }
+ };
+
+ // Determine whether to fire the negotiationneeded event.
+ window.RTCPeerConnection.prototype._maybeFireNegotiationNeeded =
+ function() {
+ // Fire away (for now).
+ if (this.onnegotiationneeded !== null) {
+ this.onnegotiationneeded();
+ }
+ };
+
+ // Update the connection state.
+ window.RTCPeerConnection.prototype._updateConnectionState =
+ function() {
+ var self = this;
+ var newState;
+ var states = {
+ 'new': 0,
+ closed: 0,
+ connecting: 0,
+ checking: 0,
+ connected: 0,
+ completed: 0,
+ failed: 0
+ };
+ this.transceivers.forEach(function(transceiver) {
+ states[transceiver.iceTransport.state]++;
+ states[transceiver.dtlsTransport.state]++;
+ });
+ // ICETransport.completed and connected are the same for this purpose.
+ states.connected += states.completed;
+
+ newState = 'new';
+ if (states.failed > 0) {
+ newState = 'failed';
+ } else if (states.connecting > 0 || states.checking > 0) {
+ newState = 'connecting';
+ } else if (states.disconnected > 0) {
+ newState = 'disconnected';
+ } else if (states.new > 0) {
+ newState = 'new';
+ } else if (states.connecting > 0 || states.completed > 0) {
+ newState = 'connected';
+ }
+
+ if (newState !== self.iceConnectionState) {
+ self.iceConnectionState = newState;
+ if (this.oniceconnectionstatechange !== null) {
+ this.oniceconnectionstatechange();
+ }
+ }
+ };
+
+ window.RTCPeerConnection.prototype.createOffer = function() {
+ var self = this;
+ if (this._pendingOffer) {
+ throw new Error('createOffer called while there is a pending offer.');
+ }
+ var offerOptions;
+ if (arguments.length === 1 && typeof arguments[0] !== 'function') {
+ offerOptions = arguments[0];
+ } else if (arguments.length === 3) {
+ offerOptions = arguments[2];
+ }
+
+ var tracks = [];
+ var numAudioTracks = 0;
+ var numVideoTracks = 0;
+ // Default to sendrecv.
+ if (this.localStreams.length) {
+ numAudioTracks = this.localStreams[0].getAudioTracks().length;
+ numVideoTracks = this.localStreams[0].getVideoTracks().length;
+ }
+ // Determine number of audio and video tracks we need to send/recv.
+ if (offerOptions) {
+ // Reject Chrome legacy constraints.
+ if (offerOptions.mandatory || offerOptions.optional) {
+ throw new TypeError(
+ 'Legacy mandatory/optional constraints not supported.');
+ }
+ if (offerOptions.offerToReceiveAudio !== undefined) {
+ numAudioTracks = offerOptions.offerToReceiveAudio;
+ }
+ if (offerOptions.offerToReceiveVideo !== undefined) {
+ numVideoTracks = offerOptions.offerToReceiveVideo;
+ }
+ }
+ if (this.localStreams.length) {
+ // Push local streams.
+ this.localStreams[0].getTracks().forEach(function(track) {
+ tracks.push({
+ kind: track.kind,
+ track: track,
+ wantReceive: track.kind === 'audio' ?
+ numAudioTracks > 0 : numVideoTracks > 0
+ });
+ if (track.kind === 'audio') {
+ numAudioTracks--;
+ } else if (track.kind === 'video') {
+ numVideoTracks--;
+ }
+ });
+ }
+ // Create M-lines for recvonly streams.
+ while (numAudioTracks > 0 || numVideoTracks > 0) {
+ if (numAudioTracks > 0) {
+ tracks.push({
+ kind: 'audio',
+ wantReceive: true
+ });
+ numAudioTracks--;
+ }
+ if (numVideoTracks > 0) {
+ tracks.push({
+ kind: 'video',
+ wantReceive: true
+ });
+ numVideoTracks--;
+ }
+ }
+
+ var sdp = SDPUtils.writeSessionBoilerplate();
+ var transceivers = [];
+ tracks.forEach(function(mline, sdpMLineIndex) {
+ // For each track, create an ice gatherer, ice transport, dtls transport,
+ // potentially rtpsender and rtpreceiver.
+ var track = mline.track;
+ var kind = mline.kind;
+ var mid = generateIdentifier();
+
+ var transports = self._createIceAndDtlsTransports(mid, sdpMLineIndex);
+
+ var localCapabilities = RTCRtpSender.getCapabilities(kind);
+ var rtpSender;
+ var rtpReceiver;
+
+ // generate an ssrc now, to be used later in rtpSender.send
+ var sendSsrc = (2 * sdpMLineIndex + 1) * 1001;
+ if (track) {
+ rtpSender = new RTCRtpSender(track, transports.dtlsTransport);
+ }
+
+ if (mline.wantReceive) {
+ rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind);
+ }
+
+ transceivers[sdpMLineIndex] = {
+ iceGatherer: transports.iceGatherer,
+ iceTransport: transports.iceTransport,
+ dtlsTransport: transports.dtlsTransport,
+ localCapabilities: localCapabilities,
+ remoteCapabilities: null,
+ rtpSender: rtpSender,
+ rtpReceiver: rtpReceiver,
+ kind: kind,
+ mid: mid,
+ sendSsrc: sendSsrc,
+ recvSsrc: null
+ };
+ var transceiver = transceivers[sdpMLineIndex];
+ sdp += SDPUtils.writeMediaSection(transceiver,
+ transceiver.localCapabilities, 'offer', self.localStreams[0]);
+ });
+
+ this._pendingOffer = transceivers;
+ var desc = new RTCSessionDescription({
+ type: 'offer',
+ sdp: sdp
+ });
+ if (arguments.length && typeof arguments[0] === 'function') {
+ window.setTimeout(arguments[0], 0, desc);
+ }
+ return Promise.resolve(desc);
+ };
+
+ window.RTCPeerConnection.prototype.createAnswer = function() {
+ var self = this;
+ var answerOptions;
+ if (arguments.length === 1 && typeof arguments[0] !== 'function') {
+ answerOptions = arguments[0];
+ } else if (arguments.length === 3) {
+ answerOptions = arguments[2];
+ }
+
+ var sdp = SDPUtils.writeSessionBoilerplate();
+ this.transceivers.forEach(function(transceiver) {
+ // Calculate intersection of capabilities.
+ var commonCapabilities = self._getCommonCapabilities(
+ transceiver.localCapabilities,
+ transceiver.remoteCapabilities);
+
+ sdp += SDPUtils.writeMediaSection(transceiver, commonCapabilities,
+ 'answer', self.localStreams[0]);
+ });
+
+ var desc = new RTCSessionDescription({
+ type: 'answer',
+ sdp: sdp
+ });
+ if (arguments.length && typeof arguments[0] === 'function') {
+ window.setTimeout(arguments[0], 0, desc);
+ }
+ return Promise.resolve(desc);
+ };
+
+ window.RTCPeerConnection.prototype.addIceCandidate = function(candidate) {
+ var mLineIndex = candidate.sdpMLineIndex;
+ if (candidate.sdpMid) {
+ for (var i = 0; i < this.transceivers.length; i++) {
+ if (this.transceivers[i].mid === candidate.sdpMid) {
+ mLineIndex = i;
+ break;
+ }
+ }
+ }
+ var transceiver = this.transceivers[mLineIndex];
+ if (transceiver) {
+ var cand = Object.keys(candidate.candidate).length > 0 ?
+ SDPUtils.parseCandidate(candidate.candidate) : {};
+ // Ignore Chrome's invalid candidates since Edge does not like them.
+ if (cand.protocol === 'tcp' && cand.port === 0) {
+ return;
+ }
+ // Ignore RTCP candidates, we assume RTCP-MUX.
+ if (cand.component !== '1') {
+ return;
+ }
+ // A dirty hack to make samples work.
+ if (cand.type === 'endOfCandidates') {
+ cand = {};
+ }
+ transceiver.iceTransport.addRemoteCandidate(cand);
+ }
+ if (arguments.length > 1 && typeof arguments[1] === 'function') {
+ window.setTimeout(arguments[1], 0);
+ }
+ return Promise.resolve();
+ };
+
+ window.RTCPeerConnection.prototype.getStats = function() {
+ var promises = [];
+ this.transceivers.forEach(function(transceiver) {
+ ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport',
+ 'dtlsTransport'].forEach(function(method) {
+ if (transceiver[method]) {
+ promises.push(transceiver[method].getStats());
+ }
+ });
+ });
+ var cb = arguments.length > 1 && typeof arguments[1] === 'function' &&
+ arguments[1];
+ return new Promise(function(resolve) {
+ var results = {};
+ Promise.all(promises).then(function(res) {
+ res.forEach(function(result) {
+ Object.keys(result).forEach(function(id) {
+ results[id] = result[id];
+ });
+ });
+ if (cb) {
+ window.setTimeout(cb, 0, results);
+ }
+ resolve(results);
+ });
+ });
+ };
+ }
+} else {
+ webrtcUtils.log('Browser does not appear to be WebRTC-capable');
+}
+
+// Polyfill ontrack on browsers that don't yet have it
+if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in
+ window.RTCPeerConnection.prototype)) {
+ Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
+ get: function() { return this._ontrack; },
+ set: function(f) {
+ var self = this;
+ if (this._ontrack) {
+ this.removeEventListener('track', this._ontrack);
+ this.removeEventListener('addstream', this._ontrackpoly);
+ }
+ this.addEventListener('track', this._ontrack = f);
+ this.addEventListener('addstream', this._ontrackpoly = function(e) {
+ if (webrtcDetectedBrowser === 'chrome') {
+ // onaddstream does not fire when a track is added to an existing stream.
+ // but stream.onaddtrack is implemented so we use thたt
+ e.stream.addEventListener('addtrack', function(te) {
+ var event = new Event('track');
+ event.track = te.track;
+ event.receiver = {track: te.track};
+ event.streams = [e.stream];
+ self.dispatchEvent(event);
+ });
+ }
+ e.stream.getTracks().forEach(function(track) {
+ var event = new Event('track');
+ event.track = track;
+ event.receiver = {track: track};
+ event.streams = [e.stream];
+ this.dispatchEvent(event);
+ }.bind(this));
+ }.bind(this));
+ }
+ });
+}
+
+// Returns the result of getUserMedia as a Promise.
+function requestUserMedia(constraints) {
+ return new Promise(function(resolve, reject) {
+ getUserMedia(constraints, resolve, reject);
+ });
+}
+
+var webrtcTesting = {};
+try {
+ Object.defineProperty(webrtcTesting, 'version', {
+ set: function(version) {
+ webrtcDetectedVersion = version;
}
+ });
+} catch (e) {}
+
+if (typeof module !== 'undefined') {
+ var RTCPeerConnection;
+ var RTCIceCandidate;
+ var RTCSessionDescription;
+ if (typeof window !== 'undefined') {
+ RTCPeerConnection = window.RTCPeerConnection;
+ RTCIceCandidate = window.RTCIceCandidate;
+ RTCSessionDescription = window.RTCSessionDescription;
+ }
+ module.exports = {
+ RTCPeerConnection: RTCPeerConnection,
+ RTCIceCandidate: RTCIceCandidate,
+ RTCSessionDescription: RTCSessionDescription,
+ getUserMedia: getUserMedia,
+ attachMediaStream: attachMediaStream,
+ reattachMediaStream: reattachMediaStream,
+ webrtcDetectedBrowser: webrtcDetectedBrowser,
+ webrtcDetectedVersion: webrtcDetectedVersion,
+ webrtcMinimumVersion: webrtcMinimumVersion,
+ webrtcTesting: webrtcTesting,
+ webrtcUtils: webrtcUtils
+ //requestUserMedia: not exposed on purpose.
+ //trace: not exposed on purpose.
+ };
+} else if ((typeof require === 'function') && (typeof define === 'function')) {
+ // Expose objects and functions when RequireJS is doing the loading.
+ define([], function() {
+ return {
+ RTCPeerConnection: window.RTCPeerConnection,
+ RTCIceCandidate: window.RTCIceCandidate,
+ RTCSessionDescription: window.RTCSessionDescription,
+ getUserMedia: getUserMedia,
+ attachMediaStream: attachMediaStream,
+ reattachMediaStream: reattachMediaStream,
+ webrtcDetectedBrowser: webrtcDetectedBrowser,
+ webrtcDetectedVersion: webrtcDetectedVersion,
+ webrtcMinimumVersion: webrtcMinimumVersion,
+ webrtcTesting: webrtcTesting,
+ webrtcUtils: webrtcUtils
+ //requestUserMedia: not exposed on purpose.
+ //trace: not exposed on purpose.
+ };
+ });
}
-},{"./dom-element":243,"events":6,"util":28}],248:[function(require,module,exports){
+},{}],201:[function(require,module,exports){
+arguments[4][33][0].apply(exports,arguments)
+},{"./chrome/chrome_shim":202,"./edge/edge_shim":204,"./firefox/firefox_shim":206,"./safari/safari_shim":208,"./utils":209,"dup":33}],202:[function(require,module,exports){
+
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+ /* eslint-env node */
'use strict';
+var logging = require('../utils.js').log;
+var browserDetails = require('../utils.js').browserDetails;
+
+var chromeShim = {
+ shimMediaStream: function() {
+ window.MediaStream = window.MediaStream || window.webkitMediaStream;
+ },
+
+ shimOnTrack: function() {
+ if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in
+ window.RTCPeerConnection.prototype)) {
+ Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
+ get: function() {
+ return this._ontrack;
+ },
+ set: function(f) {
+ var self = this;
+ if (this._ontrack) {
+ this.removeEventListener('track', this._ontrack);
+ this.removeEventListener('addstream', this._ontrackpoly);
+ }
+ this.addEventListener('track', this._ontrack = f);
+ this.addEventListener('addstream', this._ontrackpoly = function(e) {
+ // onaddstream does not fire when a track is added to an existing
+ // stream. But stream.onaddtrack is implemented so we use that.
+ e.stream.addEventListener('addtrack', function(te) {
+ var event = new Event('track');
+ event.track = te.track;
+ event.receiver = {track: te.track};
+ event.streams = [e.stream];
+ self.dispatchEvent(event);
+ });
+ e.stream.getTracks().forEach(function(track) {
+ var event = new Event('track');
+ event.track = track;
+ event.receiver = {track: track};
+ event.streams = [e.stream];
+ this.dispatchEvent(event);
+ }.bind(this));
+ }.bind(this));
+ }
+ });
+ }
+ },
+
+ shimSourceObject: function() {
+ if (typeof window === 'object') {
+ if (window.HTMLMediaElement &&
+ !('srcObject' in window.HTMLMediaElement.prototype)) {
+ // Shim the srcObject property, once, when HTMLMediaElement is found.
+ Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
+ get: function() {
+ return this._srcObject;
+ },
+ set: function(stream) {
+ var self = this;
+ // Use _srcObject as a private property for this shim
+ this._srcObject = stream;
+ if (this.src) {
+ URL.revokeObjectURL(this.src);
+ }
-var util = require('util')
- , events = require('events')
-
-var STATE_TEXT = 0,
- STATE_IGNORE_TAG = 1,
- STATE_TAG_NAME = 2,
- STATE_TAG = 3,
- STATE_ATTR_NAME = 4,
- STATE_ATTR_EQ = 5,
- STATE_ATTR_QUOT = 6,
- STATE_ATTR_VALUE = 7
-
-var SaxLtx = module.exports = function SaxLtx() {
- events.EventEmitter.call(this)
-
- var state = STATE_TEXT, remainder
- var tagName, attrs, endTag, selfClosing, attrQuote
- var recordStart = 0
- var attrName
-
- this._handleTagOpening = function(endTag, tagName, attrs) {
- if (!endTag) {
- this.emit('startElement', tagName, attrs)
- if (selfClosing) {
- this.emit('endElement', tagName)
+ if (!stream) {
+ this.src = '';
+ return;
}
+ this.src = URL.createObjectURL(stream);
+ // We need to recreate the blob url when a track is added or
+ // removed. Doing it manually since we want to avoid a recursion.
+ stream.addEventListener('addtrack', function() {
+ if (self.src) {
+ URL.revokeObjectURL(self.src);
+ }
+ self.src = URL.createObjectURL(stream);
+ });
+ stream.addEventListener('removetrack', function() {
+ if (self.src) {
+ URL.revokeObjectURL(self.src);
+ }
+ self.src = URL.createObjectURL(stream);
+ });
+ }
+ });
+ }
+ }
+ },
+
+ shimPeerConnection: function() {
+ // The RTCPeerConnection object.
+ window.RTCPeerConnection = function(pcConfig, pcConstraints) {
+ // Translate iceTransportPolicy to iceTransports,
+ // see https://code.google.com/p/webrtc/issues/detail?id=4869
+ logging('PeerConnection');
+ if (pcConfig && pcConfig.iceTransportPolicy) {
+ pcConfig.iceTransports = pcConfig.iceTransportPolicy;
+ }
+
+ var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints);
+ var origGetStats = pc.getStats.bind(pc);
+ pc.getStats = function(selector, successCallback, errorCallback) {
+ var self = this;
+ var args = arguments;
+
+ // If selector is a function then we are in the old style stats so just
+ // pass back the original getStats format to avoid breaking old users.
+ if (arguments.length > 0 && typeof selector === 'function') {
+ return origGetStats(selector, successCallback);
+ }
+
+ var fixChromeStats_ = function(response) {
+ var standardReport = {};
+ var reports = response.result();
+ reports.forEach(function(report) {
+ var standardStats = {
+ id: report.id,
+ timestamp: report.timestamp,
+ type: report.type
+ };
+ report.names().forEach(function(name) {
+ standardStats[name] = report.stat(name);
+ });
+ standardReport[standardStats.id] = standardStats;
+ });
+
+ return standardReport;
+ };
+
+ // shim getStats with maplike support
+ var makeMapStats = function(stats, legacyStats) {
+ var map = new Map(Object.keys(stats).map(function(key) {
+ return[key, stats[key]];
+ }));
+ legacyStats = legacyStats || stats;
+ Object.keys(legacyStats).forEach(function(key) {
+ map[key] = legacyStats[key];
+ });
+ return map;
+ };
+
+ if (arguments.length >= 2) {
+ var successCallbackWrapper_ = function(response) {
+ args[1](makeMapStats(fixChromeStats_(response)));
+ };
+
+ return origGetStats.apply(this, [successCallbackWrapper_,
+ arguments[0]]);
+ }
+
+ // promise-support
+ return new Promise(function(resolve, reject) {
+ if (args.length === 1 && typeof selector === 'object') {
+ origGetStats.apply(self, [
+ function(response) {
+ resolve(makeMapStats(fixChromeStats_(response)));
+ }, reject]);
+ } else {
+ // Preserve legacy chrome stats only on legacy access of stats obj
+ origGetStats.apply(self, [
+ function(response) {
+ resolve(makeMapStats(fixChromeStats_(response),
+ response.result()));
+ }, reject]);
+ }
+ }).then(successCallback, errorCallback);
+ };
+
+ return pc;
+ };
+ window.RTCPeerConnection.prototype = webkitRTCPeerConnection.prototype;
+
+ // wrap static methods. Currently just generateCertificate.
+ if (webkitRTCPeerConnection.generateCertificate) {
+ Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
+ get: function() {
+ return webkitRTCPeerConnection.generateCertificate;
+ }
+ });
+ }
+
+ ['createOffer', 'createAnswer'].forEach(function(method) {
+ var nativeMethod = webkitRTCPeerConnection.prototype[method];
+ webkitRTCPeerConnection.prototype[method] = function() {
+ var self = this;
+ if (arguments.length < 1 || (arguments.length === 1 &&
+ typeof arguments[0] === 'object')) {
+ var opts = arguments.length === 1 ? arguments[0] : undefined;
+ return new Promise(function(resolve, reject) {
+ nativeMethod.apply(self, [resolve, reject, opts]);
+ });
+ }
+ return nativeMethod.apply(this, arguments);
+ };
+ });
+
+ // add promise support -- natively available in Chrome 51
+ if (browserDetails.version < 51) {
+ ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
+ .forEach(function(method) {
+ var nativeMethod = webkitRTCPeerConnection.prototype[method];
+ webkitRTCPeerConnection.prototype[method] = function() {
+ var args = arguments;
+ var self = this;
+ var promise = new Promise(function(resolve, reject) {
+ nativeMethod.apply(self, [args[0], resolve, reject]);
+ });
+ if (args.length < 2) {
+ return promise;
+ }
+ return promise.then(function() {
+ args[1].apply(null, []);
+ },
+ function(err) {
+ if (args.length >= 3) {
+ args[2].apply(null, [err]);
+ }
+ });
+ };
+ });
+ }
+
+ // shim implicit creation of RTCSessionDescription/RTCIceCandidate
+ ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
+ .forEach(function(method) {
+ var nativeMethod = webkitRTCPeerConnection.prototype[method];
+ webkitRTCPeerConnection.prototype[method] = function() {
+ arguments[0] = new ((method === 'addIceCandidate') ?
+ RTCIceCandidate : RTCSessionDescription)(arguments[0]);
+ return nativeMethod.apply(this, arguments);
+ };
+ });
+
+ // support for addIceCandidate(null)
+ var nativeAddIceCandidate =
+ RTCPeerConnection.prototype.addIceCandidate;
+ RTCPeerConnection.prototype.addIceCandidate = function() {
+ if (arguments[0] === null) {
+ if (arguments[1]) {
+ arguments[1].apply(null);
+ }
+ return Promise.resolve();
+ }
+ return nativeAddIceCandidate.apply(this, arguments);
+ };
+ }
+};
+
+
+// Expose public methods.
+module.exports = {
+ shimMediaStream: chromeShim.shimMediaStream,
+ shimOnTrack: chromeShim.shimOnTrack,
+ shimSourceObject: chromeShim.shimSourceObject,
+ shimPeerConnection: chromeShim.shimPeerConnection,
+ shimGetUserMedia: require('./getusermedia')
+};
+
+},{"../utils.js":209,"./getusermedia":203}],203:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+ /* eslint-env node */
+'use strict';
+var logging = require('../utils.js').log;
+
+// Expose public methods.
+module.exports = function() {
+ var constraintsToChrome_ = function(c) {
+ if (typeof c !== 'object' || c.mandatory || c.optional) {
+ return c;
+ }
+ var cc = {};
+ Object.keys(c).forEach(function(key) {
+ if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
+ return;
+ }
+ var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]};
+ if (r.exact !== undefined && typeof r.exact === 'number') {
+ r.min = r.max = r.exact;
+ }
+ var oldname_ = function(prefix, name) {
+ if (prefix) {
+ return prefix + name.charAt(0).toUpperCase() + name.slice(1);
+ }
+ return (name === 'deviceId') ? 'sourceId' : name;
+ };
+ if (r.ideal !== undefined) {
+ cc.optional = cc.optional || [];
+ var oc = {};
+ if (typeof r.ideal === 'number') {
+ oc[oldname_('min', key)] = r.ideal;
+ cc.optional.push(oc);
+ oc = {};
+ oc[oldname_('max', key)] = r.ideal;
+ cc.optional.push(oc);
} else {
- this.emit('endElement', tagName)
+ oc[oldname_('', key)] = r.ideal;
+ cc.optional.push(oc);
}
+ }
+ if (r.exact !== undefined && typeof r.exact !== 'number') {
+ cc.mandatory = cc.mandatory || {};
+ cc.mandatory[oldname_('', key)] = r.exact;
+ } else {
+ ['min', 'max'].forEach(function(mix) {
+ if (r[mix] !== undefined) {
+ cc.mandatory = cc.mandatory || {};
+ cc.mandatory[oldname_(mix, key)] = r[mix];
+ }
+ });
+ }
+ });
+ if (c.advanced) {
+ cc.optional = (cc.optional || []).concat(c.advanced);
}
+ return cc;
+ };
- this.write = function(data) {
- /* jshint -W071 */
- /* jshint -W074 */
- if (typeof data !== 'string') {
- data = data.toString()
+ var shimConstraints_ = function(constraints, func) {
+ constraints = JSON.parse(JSON.stringify(constraints));
+ if (constraints && constraints.audio) {
+ constraints.audio = constraintsToChrome_(constraints.audio);
+ }
+ if (constraints && typeof constraints.video === 'object') {
+ // Shim facingMode for mobile, where it defaults to "user".
+ var face = constraints.video.facingMode;
+ face = face && ((typeof face === 'object') ? face : {ideal: face});
+
+ if ((face && (face.exact === 'user' || face.exact === 'environment' ||
+ face.ideal === 'user' || face.ideal === 'environment')) &&
+ !(navigator.mediaDevices.getSupportedConstraints &&
+ navigator.mediaDevices.getSupportedConstraints().facingMode)) {
+ delete constraints.video.facingMode;
+ if (face.exact === 'environment' || face.ideal === 'environment') {
+ // Look for "back" in label, or use last cam (typically back cam).
+ return navigator.mediaDevices.enumerateDevices()
+ .then(function(devices) {
+ devices = devices.filter(function(d) {
+ return d.kind === 'videoinput';
+ });
+ var back = devices.find(function(d) {
+ return d.label.toLowerCase().indexOf('back') !== -1;
+ }) || (devices.length && devices[devices.length - 1]);
+ if (back) {
+ constraints.video.deviceId = face.exact ? {exact: back.deviceId} :
+ {ideal: back.deviceId};
+ }
+ constraints.video = constraintsToChrome_(constraints.video);
+ logging('chrome: ' + JSON.stringify(constraints));
+ return func(constraints);
+ });
}
- var pos = 0
+ }
+ constraints.video = constraintsToChrome_(constraints.video);
+ }
+ logging('chrome: ' + JSON.stringify(constraints));
+ return func(constraints);
+ };
+
+ var shimError_ = function(e) {
+ return {
+ name: {
+ PermissionDeniedError: 'NotAllowedError',
+ ConstraintNotSatisfiedError: 'OverconstrainedError'
+ }[e.name] || e.name,
+ message: e.message,
+ constraint: e.constraintName,
+ toString: function() {
+ return this.name + (this.message && ': ') + this.message;
+ }
+ };
+ };
+
+ var getUserMedia_ = function(constraints, onSuccess, onError) {
+ shimConstraints_(constraints, function(c) {
+ navigator.webkitGetUserMedia(c, onSuccess, function(e) {
+ onError(shimError_(e));
+ });
+ });
+ };
+
+ navigator.getUserMedia = getUserMedia_;
+
+ // Returns the result of getUserMedia as a Promise.
+ var getUserMediaPromise_ = function(constraints) {
+ return new Promise(function(resolve, reject) {
+ navigator.getUserMedia(constraints, resolve, reject);
+ });
+ };
+
+ if (!navigator.mediaDevices) {
+ navigator.mediaDevices = {
+ getUserMedia: getUserMediaPromise_,
+ enumerateDevices: function() {
+ return new Promise(function(resolve) {
+ var kinds = {audio: 'audioinput', video: 'videoinput'};
+ return MediaStreamTrack.getSources(function(devices) {
+ resolve(devices.map(function(device) {
+ return {label: device.label,
+ kind: kinds[device.kind],
+ deviceId: device.id,
+ groupId: ''};
+ }));
+ });
+ });
+ }
+ };
+ }
+
+ // A shim for getUserMedia method on the mediaDevices object.
+ // TODO(KaptenJansson) remove once implemented in Chrome stable.
+ if (!navigator.mediaDevices.getUserMedia) {
+ navigator.mediaDevices.getUserMedia = function(constraints) {
+ return getUserMediaPromise_(constraints);
+ };
+ } else {
+ // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia
+ // function which returns a Promise, it does not accept spec-style
+ // constraints.
+ var origGetUserMedia = navigator.mediaDevices.getUserMedia.
+ bind(navigator.mediaDevices);
+ navigator.mediaDevices.getUserMedia = function(cs) {
+ return shimConstraints_(cs, function(c) {
+ return origGetUserMedia(c).then(function(stream) {
+ if (c.audio && !stream.getAudioTracks().length ||
+ c.video && !stream.getVideoTracks().length) {
+ stream.getTracks().forEach(function(track) {
+ track.stop();
+ });
+ throw new DOMException('', 'NotFoundError');
+ }
+ return stream;
+ }, function(e) {
+ return Promise.reject(shimError_(e));
+ });
+ });
+ };
+ }
+
+ // Dummy devicechange event methods.
+ // TODO(KaptenJansson) remove once implemented in Chrome stable.
+ if (typeof navigator.mediaDevices.addEventListener === 'undefined') {
+ navigator.mediaDevices.addEventListener = function() {
+ logging('Dummy mediaDevices.addEventListener called.');
+ };
+ }
+ if (typeof navigator.mediaDevices.removeEventListener === 'undefined') {
+ navigator.mediaDevices.removeEventListener = function() {
+ logging('Dummy mediaDevices.removeEventListener called.');
+ };
+ }
+};
+
+},{"../utils.js":209}],204:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+ /* eslint-env node */
+'use strict';
+
+var SDPUtils = require('sdp');
+var browserDetails = require('../utils').browserDetails;
+
+var edgeShim = {
+ shimPeerConnection: function() {
+ if (window.RTCIceGatherer) {
+ // ORTC defines an RTCIceCandidate object but no constructor.
+ // Not implemented in Edge.
+ if (!window.RTCIceCandidate) {
+ window.RTCIceCandidate = function(args) {
+ return args;
+ };
+ }
+ // ORTC does not have a session description object but
+ // other browsers (i.e. Chrome) that will support both PC and ORTC
+ // in the future might have this defined already.
+ if (!window.RTCSessionDescription) {
+ window.RTCSessionDescription = function(args) {
+ return args;
+ };
+ }
+ }
- /* Anything from previous write()? */
- if (remainder) {
- data = remainder + data
- pos += remainder.length
- remainder = null
+ window.RTCPeerConnection = function(config) {
+ var self = this;
+
+ var _eventTarget = document.createDocumentFragment();
+ ['addEventListener', 'removeEventListener', 'dispatchEvent']
+ .forEach(function(method) {
+ self[method] = _eventTarget[method].bind(_eventTarget);
+ });
+
+ this.onicecandidate = null;
+ this.onaddstream = null;
+ this.ontrack = null;
+ this.onremovestream = null;
+ this.onsignalingstatechange = null;
+ this.oniceconnectionstatechange = null;
+ this.onnegotiationneeded = null;
+ this.ondatachannel = null;
+
+ this.localStreams = [];
+ this.remoteStreams = [];
+ this.getLocalStreams = function() {
+ return self.localStreams;
+ };
+ this.getRemoteStreams = function() {
+ return self.remoteStreams;
+ };
+
+ this.localDescription = new RTCSessionDescription({
+ type: '',
+ sdp: ''
+ });
+ this.remoteDescription = new RTCSessionDescription({
+ type: '',
+ sdp: ''
+ });
+ this.signalingState = 'stable';
+ this.iceConnectionState = 'new';
+ this.iceGatheringState = 'new';
+
+ this.iceOptions = {
+ gatherPolicy: 'all',
+ iceServers: []
+ };
+ if (config && config.iceTransportPolicy) {
+ switch (config.iceTransportPolicy) {
+ case 'all':
+ case 'relay':
+ this.iceOptions.gatherPolicy = config.iceTransportPolicy;
+ break;
+ case 'none':
+ // FIXME: remove once implementation and spec have added this.
+ throw new TypeError('iceTransportPolicy "none" not supported');
+ default:
+ // don't set iceTransportPolicy.
+ break;
}
+ }
+ this.usingBundle = config && config.bundlePolicy === 'max-bundle';
+
+ if (config && config.iceServers) {
+ // Edge does not like
+ // 1) stun:
+ // 2) turn: that does not have all of turn:host:port?transport=udp
+ // 3) turn: with ipv6 addresses
+ var iceServers = JSON.parse(JSON.stringify(config.iceServers));
+ this.iceOptions.iceServers = iceServers.filter(function(server) {
+ if (server && server.urls) {
+ var urls = server.urls;
+ if (typeof urls === 'string') {
+ urls = [urls];
+ }
+ urls = urls.filter(function(url) {
+ return (url.indexOf('turn:') === 0 &&
+ url.indexOf('transport=udp') !== -1 &&
+ url.indexOf('turn:[') === -1) ||
+ (url.indexOf('stun:') === 0 &&
+ browserDetails.version >= 14393);
+ })[0];
+ return !!urls;
+ }
+ return false;
+ });
+ }
+ this._config = config;
+
+ // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ...
+ // everything that is needed to describe a SDP m-line.
+ this.transceivers = [];
- function endRecording() {
- if (typeof recordStart === 'number') {
- var recorded = data.slice(recordStart, pos)
- recordStart = undefined
- return recorded
+ // since the iceGatherer is currently created in createOffer but we
+ // must not emit candidates until after setLocalDescription we buffer
+ // them in this array.
+ this._localIceCandidatesBuffer = [];
+ };
+
+ window.RTCPeerConnection.prototype._emitBufferedCandidates = function() {
+ var self = this;
+ var sections = SDPUtils.splitSections(self.localDescription.sdp);
+ // FIXME: need to apply ice candidates in a way which is async but
+ // in-order
+ this._localIceCandidatesBuffer.forEach(function(event) {
+ var end = !event.candidate || Object.keys(event.candidate).length === 0;
+ if (end) {
+ for (var j = 1; j < sections.length; j++) {
+ if (sections[j].indexOf('\r\na=end-of-candidates\r\n') === -1) {
+ sections[j] += 'a=end-of-candidates\r\n';
}
+ }
+ } else if (event.candidate.candidate.indexOf('typ endOfCandidates')
+ === -1) {
+ sections[event.candidate.sdpMLineIndex + 1] +=
+ 'a=' + event.candidate.candidate + '\r\n';
+ }
+ self.localDescription.sdp = sections.join('');
+ self.dispatchEvent(event);
+ if (self.onicecandidate !== null) {
+ self.onicecandidate(event);
}
+ if (!event.candidate && self.iceGatheringState !== 'complete') {
+ var complete = self.transceivers.every(function(transceiver) {
+ return transceiver.iceGatherer &&
+ transceiver.iceGatherer.state === 'completed';
+ });
+ if (complete) {
+ self.iceGatheringState = 'complete';
+ }
+ }
+ });
+ this._localIceCandidatesBuffer = [];
+ };
+
+ window.RTCPeerConnection.prototype.getConfiguration = function() {
+ return this._config;
+ };
+
+ window.RTCPeerConnection.prototype.addStream = function(stream) {
+ // Clone is necessary for local demos mostly, attaching directly
+ // to two different senders does not work (build 10547).
+ this.localStreams.push(stream.clone());
+ this._maybeFireNegotiationNeeded();
+ };
+
+ window.RTCPeerConnection.prototype.removeStream = function(stream) {
+ var idx = this.localStreams.indexOf(stream);
+ if (idx > -1) {
+ this.localStreams.splice(idx, 1);
+ this._maybeFireNegotiationNeeded();
+ }
+ };
- for(; pos < data.length; pos++) {
- var c = data.charCodeAt(pos)
- //console.log("state", state, "c", c, data[pos])
- switch(state) {
- case STATE_TEXT:
- if (c === 60 /* < */) {
- var text = endRecording()
- if (text) {
- this.emit('text', unescapeXml(text))
+ window.RTCPeerConnection.prototype.getSenders = function() {
+ return this.transceivers.filter(function(transceiver) {
+ return !!transceiver.rtpSender;
+ })
+ .map(function(transceiver) {
+ return transceiver.rtpSender;
+ });
+ };
+
+ window.RTCPeerConnection.prototype.getReceivers = function() {
+ return this.transceivers.filter(function(transceiver) {
+ return !!transceiver.rtpReceiver;
+ })
+ .map(function(transceiver) {
+ return transceiver.rtpReceiver;
+ });
+ };
+
+ // Determines the intersection of local and remote capabilities.
+ window.RTCPeerConnection.prototype._getCommonCapabilities =
+ function(localCapabilities, remoteCapabilities) {
+ var commonCapabilities = {
+ codecs: [],
+ headerExtensions: [],
+ fecMechanisms: []
+ };
+ localCapabilities.codecs.forEach(function(lCodec) {
+ for (var i = 0; i < remoteCapabilities.codecs.length; i++) {
+ var rCodec = remoteCapabilities.codecs[i];
+ if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() &&
+ lCodec.clockRate === rCodec.clockRate) {
+ // number of channels is the highest common number of channels
+ rCodec.numChannels = Math.min(lCodec.numChannels,
+ rCodec.numChannels);
+ // push rCodec so we reply with offerer payload type
+ commonCapabilities.codecs.push(rCodec);
+
+ // determine common feedback mechanisms
+ rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) {
+ for (var j = 0; j < lCodec.rtcpFeedback.length; j++) {
+ if (lCodec.rtcpFeedback[j].type === fb.type &&
+ lCodec.rtcpFeedback[j].parameter === fb.parameter) {
+ return true;
}
- state = STATE_TAG_NAME
- recordStart = pos + 1
- attrs = {}
+ }
+ return false;
+ });
+ // FIXME: also need to determine .parameters
+ // see https://github.com/openpeer/ortc/issues/569
+ break;
+ }
+ }
+ });
+
+ localCapabilities.headerExtensions
+ .forEach(function(lHeaderExtension) {
+ for (var i = 0; i < remoteCapabilities.headerExtensions.length;
+ i++) {
+ var rHeaderExtension = remoteCapabilities.headerExtensions[i];
+ if (lHeaderExtension.uri === rHeaderExtension.uri) {
+ commonCapabilities.headerExtensions.push(rHeaderExtension);
+ break;
+ }
}
- break
- case STATE_TAG_NAME:
- if (c === 47 /* / */ && recordStart === pos) {
- recordStart = pos + 1
- endTag = true
- } else if (c === 33 /* ! */ || c === 63 /* ? */) {
- recordStart = undefined
- state = STATE_IGNORE_TAG
- } else if (c <= 32 || c === 47 /* / */ || c === 62 /* > */) {
- tagName = endRecording()
- pos--
- state = STATE_TAG
+ });
+
+ // FIXME: fecMechanisms
+ return commonCapabilities;
+ };
+
+ // Create ICE gatherer, ICE transport and DTLS transport.
+ window.RTCPeerConnection.prototype._createIceAndDtlsTransports =
+ function(mid, sdpMLineIndex) {
+ var self = this;
+ var iceGatherer = new RTCIceGatherer(self.iceOptions);
+ var iceTransport = new RTCIceTransport(iceGatherer);
+ iceGatherer.onlocalcandidate = function(evt) {
+ var event = new Event('icecandidate');
+ event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex};
+
+ var cand = evt.candidate;
+ var end = !cand || Object.keys(cand).length === 0;
+ // Edge emits an empty object for RTCIceCandidateComplete‥
+ if (end) {
+ // polyfill since RTCIceGatherer.state is not implemented in
+ // Edge 10547 yet.
+ if (iceGatherer.state === undefined) {
+ iceGatherer.state = 'completed';
+ }
+
+ // Emit a candidate with type endOfCandidates to make the samples
+ // work. Edge requires addIceCandidate with this empty candidate
+ // to start checking. The real solution is to signal
+ // end-of-candidates to the other side when getting the null
+ // candidate but some apps (like the samples) don't do that.
+ event.candidate.candidate =
+ 'candidate:1 1 udp 1 0.0.0.0 9 typ endOfCandidates';
+ } else {
+ // RTCIceCandidate doesn't have a component, needs to be added
+ cand.component = iceTransport.component === 'RTCP' ? 2 : 1;
+ event.candidate.candidate = SDPUtils.writeCandidate(cand);
+ }
+
+ // update local description.
+ var sections = SDPUtils.splitSections(self.localDescription.sdp);
+ if (event.candidate.candidate.indexOf('typ endOfCandidates')
+ === -1) {
+ sections[event.candidate.sdpMLineIndex + 1] +=
+ 'a=' + event.candidate.candidate + '\r\n';
+ } else {
+ sections[event.candidate.sdpMLineIndex + 1] +=
+ 'a=end-of-candidates\r\n';
+ }
+ self.localDescription.sdp = sections.join('');
+
+ var complete = self.transceivers.every(function(transceiver) {
+ return transceiver.iceGatherer &&
+ transceiver.iceGatherer.state === 'completed';
+ });
+
+ // Emit candidate if localDescription is set.
+ // Also emits null candidate when all gatherers are complete.
+ switch (self.iceGatheringState) {
+ case 'new':
+ self._localIceCandidatesBuffer.push(event);
+ if (end && complete) {
+ self._localIceCandidatesBuffer.push(
+ new Event('icecandidate'));
+ }
+ break;
+ case 'gathering':
+ self._emitBufferedCandidates();
+ self.dispatchEvent(event);
+ if (self.onicecandidate !== null) {
+ self.onicecandidate(event);
+ }
+ if (complete) {
+ self.dispatchEvent(new Event('icecandidate'));
+ if (self.onicecandidate !== null) {
+ self.onicecandidate(new Event('icecandidate'));
+ }
+ self.iceGatheringState = 'complete';
+ }
+ break;
+ case 'complete':
+ // should not happen... currently!
+ break;
+ default: // no-op.
+ break;
+ }
+ };
+ iceTransport.onicestatechange = function() {
+ self._updateConnectionState();
+ };
+
+ var dtlsTransport = new RTCDtlsTransport(iceTransport);
+ dtlsTransport.ondtlsstatechange = function() {
+ self._updateConnectionState();
+ };
+ dtlsTransport.onerror = function() {
+ // onerror does not set state to failed by itself.
+ dtlsTransport.state = 'failed';
+ self._updateConnectionState();
+ };
+
+ return {
+ iceGatherer: iceGatherer,
+ iceTransport: iceTransport,
+ dtlsTransport: dtlsTransport
+ };
+ };
+
+ // Start the RTP Sender and Receiver for a transceiver.
+ window.RTCPeerConnection.prototype._transceive = function(transceiver,
+ send, recv) {
+ var params = this._getCommonCapabilities(transceiver.localCapabilities,
+ transceiver.remoteCapabilities);
+ if (send && transceiver.rtpSender) {
+ params.encodings = transceiver.sendEncodingParameters;
+ params.rtcp = {
+ cname: SDPUtils.localCName
+ };
+ if (transceiver.recvEncodingParameters.length) {
+ params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc;
+ }
+ transceiver.rtpSender.send(params);
+ }
+ if (recv && transceiver.rtpReceiver) {
+ // remove RTX field in Edge 14942
+ if (transceiver.kind === 'video'
+ && transceiver.recvEncodingParameters) {
+ transceiver.recvEncodingParameters.forEach(function(p) {
+ delete p.rtx;
+ });
+ }
+ params.encodings = transceiver.recvEncodingParameters;
+ params.rtcp = {
+ cname: transceiver.cname
+ };
+ if (transceiver.sendEncodingParameters.length) {
+ params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc;
+ }
+ transceiver.rtpReceiver.receive(params);
+ }
+ };
+
+ window.RTCPeerConnection.prototype.setLocalDescription =
+ function(description) {
+ var self = this;
+ var sections;
+ var sessionpart;
+ if (description.type === 'offer') {
+ // FIXME: What was the purpose of this empty if statement?
+ // if (!this._pendingOffer) {
+ // } else {
+ if (this._pendingOffer) {
+ // VERY limited support for SDP munging. Limited to:
+ // * changing the order of codecs
+ sections = SDPUtils.splitSections(description.sdp);
+ sessionpart = sections.shift();
+ sections.forEach(function(mediaSection, sdpMLineIndex) {
+ var caps = SDPUtils.parseRtpParameters(mediaSection);
+ self._pendingOffer[sdpMLineIndex].localCapabilities = caps;
+ });
+ this.transceivers = this._pendingOffer;
+ delete this._pendingOffer;
+ }
+ } else if (description.type === 'answer') {
+ sections = SDPUtils.splitSections(self.remoteDescription.sdp);
+ sessionpart = sections.shift();
+ var isIceLite = SDPUtils.matchPrefix(sessionpart,
+ 'a=ice-lite').length > 0;
+ sections.forEach(function(mediaSection, sdpMLineIndex) {
+ var transceiver = self.transceivers[sdpMLineIndex];
+ var iceGatherer = transceiver.iceGatherer;
+ var iceTransport = transceiver.iceTransport;
+ var dtlsTransport = transceiver.dtlsTransport;
+ var localCapabilities = transceiver.localCapabilities;
+ var remoteCapabilities = transceiver.remoteCapabilities;
+
+ var rejected = mediaSection.split('\n', 1)[0]
+ .split(' ', 2)[1] === '0';
+
+ if (!rejected && !transceiver.isDatachannel) {
+ var remoteIceParameters = SDPUtils.getIceParameters(
+ mediaSection, sessionpart);
+ if (isIceLite) {
+ var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:')
+ .map(function(cand) {
+ return SDPUtils.parseCandidate(cand);
+ })
+ .filter(function(cand) {
+ return cand.component === '1';
+ });
+ // ice-lite only includes host candidates in the SDP so we can
+ // use setRemoteCandidates (which implies an
+ // RTCIceCandidateComplete)
+ if (cands.length) {
+ iceTransport.setRemoteCandidates(cands);
+ }
}
- break
- case STATE_IGNORE_TAG:
- if (c === 62 /* > */) {
- state = STATE_TEXT
+ var remoteDtlsParameters = SDPUtils.getDtlsParameters(
+ mediaSection, sessionpart);
+ if (isIceLite) {
+ remoteDtlsParameters.role = 'server';
}
- break
- case STATE_TAG:
- if (c === 62 /* > */) {
- this._handleTagOpening(endTag, tagName, attrs)
- tagName = undefined
- attrs = undefined
- endTag = undefined
- selfClosing = undefined
- state = STATE_TEXT
- recordStart = pos + 1
- } else if (c === 47 /* / */) {
- selfClosing = true
- } else if (c > 32) {
- recordStart = pos
- state = STATE_ATTR_NAME
+
+ if (!self.usingBundle || sdpMLineIndex === 0) {
+ iceTransport.start(iceGatherer, remoteIceParameters,
+ isIceLite ? 'controlling' : 'controlled');
+ dtlsTransport.start(remoteDtlsParameters);
}
- break
- case STATE_ATTR_NAME:
- if (c <= 32 || c === 61 /* = */) {
- attrName = endRecording()
- pos--
- state = STATE_ATTR_EQ
+
+ // Calculate intersection of capabilities.
+ var params = self._getCommonCapabilities(localCapabilities,
+ remoteCapabilities);
+
+ // Start the RTCRtpSender. The RTCRtpReceiver for this
+ // transceiver has already been started in setRemoteDescription.
+ self._transceive(transceiver,
+ params.codecs.length > 0,
+ false);
+ }
+ });
+ }
+
+ this.localDescription = {
+ type: description.type,
+ sdp: description.sdp
+ };
+ switch (description.type) {
+ case 'offer':
+ this._updateSignalingState('have-local-offer');
+ break;
+ case 'answer':
+ this._updateSignalingState('stable');
+ break;
+ default:
+ throw new TypeError('unsupported type "' + description.type +
+ '"');
+ }
+
+ // If a success callback was provided, emit ICE candidates after it
+ // has been executed. Otherwise, emit callback after the Promise is
+ // resolved.
+ var hasCallback = arguments.length > 1 &&
+ typeof arguments[1] === 'function';
+ if (hasCallback) {
+ var cb = arguments[1];
+ window.setTimeout(function() {
+ cb();
+ if (self.iceGatheringState === 'new') {
+ self.iceGatheringState = 'gathering';
+ }
+ self._emitBufferedCandidates();
+ }, 0);
+ }
+ var p = Promise.resolve();
+ p.then(function() {
+ if (!hasCallback) {
+ if (self.iceGatheringState === 'new') {
+ self.iceGatheringState = 'gathering';
+ }
+ // Usually candidates will be emitted earlier.
+ window.setTimeout(self._emitBufferedCandidates.bind(self), 500);
+ }
+ });
+ return p;
+ };
+
+ window.RTCPeerConnection.prototype.setRemoteDescription =
+ function(description) {
+ var self = this;
+ var stream = new MediaStream();
+ var receiverList = [];
+ var sections = SDPUtils.splitSections(description.sdp);
+ var sessionpart = sections.shift();
+ var isIceLite = SDPUtils.matchPrefix(sessionpart,
+ 'a=ice-lite').length > 0;
+ this.usingBundle = SDPUtils.matchPrefix(sessionpart,
+ 'a=group:BUNDLE ').length > 0;
+ sections.forEach(function(mediaSection, sdpMLineIndex) {
+ var lines = SDPUtils.splitLines(mediaSection);
+ var mline = lines[0].substr(2).split(' ');
+ var kind = mline[0];
+ var rejected = mline[1] === '0';
+ var direction = SDPUtils.getDirection(mediaSection, sessionpart);
+
+ var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:');
+ if (mid.length) {
+ mid = mid[0].substr(6);
+ } else {
+ mid = SDPUtils.generateIdentifier();
+ }
+
+ // Reject datachannels which are not implemented yet.
+ if (kind === 'application' && mline[2] === 'DTLS/SCTP') {
+ self.transceivers[sdpMLineIndex] = {
+ mid: mid,
+ isDatachannel: true
+ };
+ return;
+ }
+
+ var transceiver;
+ var iceGatherer;
+ var iceTransport;
+ var dtlsTransport;
+ var rtpSender;
+ var rtpReceiver;
+ var sendEncodingParameters;
+ var recvEncodingParameters;
+ var localCapabilities;
+
+ var track;
+ // FIXME: ensure the mediaSection has rtcp-mux set.
+ var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection);
+ var remoteIceParameters;
+ var remoteDtlsParameters;
+ if (!rejected) {
+ remoteIceParameters = SDPUtils.getIceParameters(mediaSection,
+ sessionpart);
+ remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection,
+ sessionpart);
+ remoteDtlsParameters.role = 'client';
+ }
+ recvEncodingParameters =
+ SDPUtils.parseRtpEncodingParameters(mediaSection);
+
+ var cname;
+ // Gets the first SSRC. Note that with RTX there might be multiple
+ // SSRCs.
+ var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
+ .map(function(line) {
+ return SDPUtils.parseSsrcMedia(line);
+ })
+ .filter(function(obj) {
+ return obj.attribute === 'cname';
+ })[0];
+ if (remoteSsrc) {
+ cname = remoteSsrc.value;
+ }
+
+ var isComplete = SDPUtils.matchPrefix(mediaSection,
+ 'a=end-of-candidates', sessionpart).length > 0;
+ var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:')
+ .map(function(cand) {
+ return SDPUtils.parseCandidate(cand);
+ })
+ .filter(function(cand) {
+ return cand.component === '1';
+ });
+ if (description.type === 'offer' && !rejected) {
+ var transports = self.usingBundle && sdpMLineIndex > 0 ? {
+ iceGatherer: self.transceivers[0].iceGatherer,
+ iceTransport: self.transceivers[0].iceTransport,
+ dtlsTransport: self.transceivers[0].dtlsTransport
+ } : self._createIceAndDtlsTransports(mid, sdpMLineIndex);
+
+ if (isComplete) {
+ transports.iceTransport.setRemoteCandidates(cands);
+ }
+
+ localCapabilities = RTCRtpReceiver.getCapabilities(kind);
+
+ // filter RTX until additional stuff needed for RTX is implemented
+ // in adapter.js
+ localCapabilities.codecs = localCapabilities.codecs.filter(
+ function(codec) {
+ return codec.name !== 'rtx';
+ });
+
+ sendEncodingParameters = [{
+ ssrc: (2 * sdpMLineIndex + 2) * 1001
+ }];
+
+ rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind);
+
+ track = rtpReceiver.track;
+ receiverList.push([track, rtpReceiver]);
+ // FIXME: not correct when there are multiple streams but that is
+ // not currently supported in this shim.
+ stream.addTrack(track);
+
+ // FIXME: look at direction.
+ if (self.localStreams.length > 0 &&
+ self.localStreams[0].getTracks().length >= sdpMLineIndex) {
+ var localTrack;
+ if (kind === 'audio') {
+ localTrack = self.localStreams[0].getAudioTracks()[0];
+ } else if (kind === 'video') {
+ localTrack = self.localStreams[0].getVideoTracks()[0];
}
- break
- case STATE_ATTR_EQ:
- if (c === 61 /* = */) {
- state = STATE_ATTR_QUOT
+ if (localTrack) {
+ rtpSender = new RTCRtpSender(localTrack,
+ transports.dtlsTransport);
}
- break
- case STATE_ATTR_QUOT:
- if (c === 34 /* " */ || c === 39 /* ' */) {
- attrQuote = c
- state = STATE_ATTR_VALUE
- recordStart = pos + 1
+ }
+
+ self.transceivers[sdpMLineIndex] = {
+ iceGatherer: transports.iceGatherer,
+ iceTransport: transports.iceTransport,
+ dtlsTransport: transports.dtlsTransport,
+ localCapabilities: localCapabilities,
+ remoteCapabilities: remoteCapabilities,
+ rtpSender: rtpSender,
+ rtpReceiver: rtpReceiver,
+ kind: kind,
+ mid: mid,
+ cname: cname,
+ sendEncodingParameters: sendEncodingParameters,
+ recvEncodingParameters: recvEncodingParameters
+ };
+ // Start the RTCRtpReceiver now. The RTPSender is started in
+ // setLocalDescription.
+ self._transceive(self.transceivers[sdpMLineIndex],
+ false,
+ direction === 'sendrecv' || direction === 'sendonly');
+ } else if (description.type === 'answer' && !rejected) {
+ transceiver = self.transceivers[sdpMLineIndex];
+ iceGatherer = transceiver.iceGatherer;
+ iceTransport = transceiver.iceTransport;
+ dtlsTransport = transceiver.dtlsTransport;
+ rtpSender = transceiver.rtpSender;
+ rtpReceiver = transceiver.rtpReceiver;
+ sendEncodingParameters = transceiver.sendEncodingParameters;
+ localCapabilities = transceiver.localCapabilities;
+
+ self.transceivers[sdpMLineIndex].recvEncodingParameters =
+ recvEncodingParameters;
+ self.transceivers[sdpMLineIndex].remoteCapabilities =
+ remoteCapabilities;
+ self.transceivers[sdpMLineIndex].cname = cname;
+
+ if ((isIceLite || isComplete) && cands.length) {
+ iceTransport.setRemoteCandidates(cands);
+ }
+ if (!self.usingBundle || sdpMLineIndex === 0) {
+ iceTransport.start(iceGatherer, remoteIceParameters,
+ 'controlling');
+ dtlsTransport.start(remoteDtlsParameters);
+ }
+
+ self._transceive(transceiver,
+ direction === 'sendrecv' || direction === 'recvonly',
+ direction === 'sendrecv' || direction === 'sendonly');
+
+ if (rtpReceiver &&
+ (direction === 'sendrecv' || direction === 'sendonly')) {
+ track = rtpReceiver.track;
+ receiverList.push([track, rtpReceiver]);
+ stream.addTrack(track);
+ } else {
+ // FIXME: actually the receiver should be created later.
+ delete transceiver.rtpReceiver;
+ }
+ }
+ });
+
+ this.remoteDescription = {
+ type: description.type,
+ sdp: description.sdp
+ };
+ switch (description.type) {
+ case 'offer':
+ this._updateSignalingState('have-remote-offer');
+ break;
+ case 'answer':
+ this._updateSignalingState('stable');
+ break;
+ default:
+ throw new TypeError('unsupported type "' + description.type +
+ '"');
+ }
+ if (stream.getTracks().length) {
+ self.remoteStreams.push(stream);
+ window.setTimeout(function() {
+ var event = new Event('addstream');
+ event.stream = stream;
+ self.dispatchEvent(event);
+ if (self.onaddstream !== null) {
+ window.setTimeout(function() {
+ self.onaddstream(event);
+ }, 0);
+ }
+
+ receiverList.forEach(function(item) {
+ var track = item[0];
+ var receiver = item[1];
+ var trackEvent = new Event('track');
+ trackEvent.track = track;
+ trackEvent.receiver = receiver;
+ trackEvent.streams = [stream];
+ self.dispatchEvent(event);
+ if (self.ontrack !== null) {
+ window.setTimeout(function() {
+ self.ontrack(trackEvent);
+ }, 0);
}
- break
- case STATE_ATTR_VALUE:
- if (c === attrQuote) {
- var value = unescapeXml(endRecording())
- attrs[attrName] = value
- attrName = undefined
- state = STATE_TAG
+ });
+ }, 0);
+ }
+ if (arguments.length > 1 && typeof arguments[1] === 'function') {
+ window.setTimeout(arguments[1], 0);
+ }
+ return Promise.resolve();
+ };
+
+ window.RTCPeerConnection.prototype.close = function() {
+ this.transceivers.forEach(function(transceiver) {
+ /* not yet
+ if (transceiver.iceGatherer) {
+ transceiver.iceGatherer.close();
+ }
+ */
+ if (transceiver.iceTransport) {
+ transceiver.iceTransport.stop();
+ }
+ if (transceiver.dtlsTransport) {
+ transceiver.dtlsTransport.stop();
+ }
+ if (transceiver.rtpSender) {
+ transceiver.rtpSender.stop();
+ }
+ if (transceiver.rtpReceiver) {
+ transceiver.rtpReceiver.stop();
+ }
+ });
+ // FIXME: clean up tracks, local streams, remote streams, etc
+ this._updateSignalingState('closed');
+ };
+
+ // Update the signaling state.
+ window.RTCPeerConnection.prototype._updateSignalingState =
+ function(newState) {
+ this.signalingState = newState;
+ var event = new Event('signalingstatechange');
+ this.dispatchEvent(event);
+ if (this.onsignalingstatechange !== null) {
+ this.onsignalingstatechange(event);
+ }
+ };
+
+ // Determine whether to fire the negotiationneeded event.
+ window.RTCPeerConnection.prototype._maybeFireNegotiationNeeded =
+ function() {
+ // Fire away (for now).
+ var event = new Event('negotiationneeded');
+ this.dispatchEvent(event);
+ if (this.onnegotiationneeded !== null) {
+ this.onnegotiationneeded(event);
+ }
+ };
+
+ // Update the connection state.
+ window.RTCPeerConnection.prototype._updateConnectionState = function() {
+ var self = this;
+ var newState;
+ var states = {
+ 'new': 0,
+ closed: 0,
+ connecting: 0,
+ checking: 0,
+ connected: 0,
+ completed: 0,
+ failed: 0
+ };
+ this.transceivers.forEach(function(transceiver) {
+ states[transceiver.iceTransport.state]++;
+ states[transceiver.dtlsTransport.state]++;
+ });
+ // ICETransport.completed and connected are the same for this purpose.
+ states.connected += states.completed;
+
+ newState = 'new';
+ if (states.failed > 0) {
+ newState = 'failed';
+ } else if (states.connecting > 0 || states.checking > 0) {
+ newState = 'connecting';
+ } else if (states.disconnected > 0) {
+ newState = 'disconnected';
+ } else if (states.new > 0) {
+ newState = 'new';
+ } else if (states.connected > 0 || states.completed > 0) {
+ newState = 'connected';
+ }
+
+ if (newState !== self.iceConnectionState) {
+ self.iceConnectionState = newState;
+ var event = new Event('iceconnectionstatechange');
+ this.dispatchEvent(event);
+ if (this.oniceconnectionstatechange !== null) {
+ this.oniceconnectionstatechange(event);
+ }
+ }
+ };
+
+ window.RTCPeerConnection.prototype.createOffer = function() {
+ var self = this;
+ if (this._pendingOffer) {
+ throw new Error('createOffer called while there is a pending offer.');
+ }
+ var offerOptions;
+ if (arguments.length === 1 && typeof arguments[0] !== 'function') {
+ offerOptions = arguments[0];
+ } else if (arguments.length === 3) {
+ offerOptions = arguments[2];
+ }
+
+ var tracks = [];
+ var numAudioTracks = 0;
+ var numVideoTracks = 0;
+ // Default to sendrecv.
+ if (this.localStreams.length) {
+ numAudioTracks = this.localStreams[0].getAudioTracks().length;
+ numVideoTracks = this.localStreams[0].getVideoTracks().length;
+ }
+ // Determine number of audio and video tracks we need to send/recv.
+ if (offerOptions) {
+ // Reject Chrome legacy constraints.
+ if (offerOptions.mandatory || offerOptions.optional) {
+ throw new TypeError(
+ 'Legacy mandatory/optional constraints not supported.');
+ }
+ if (offerOptions.offerToReceiveAudio !== undefined) {
+ numAudioTracks = offerOptions.offerToReceiveAudio;
+ }
+ if (offerOptions.offerToReceiveVideo !== undefined) {
+ numVideoTracks = offerOptions.offerToReceiveVideo;
+ }
+ }
+ if (this.localStreams.length) {
+ // Push local streams.
+ this.localStreams[0].getTracks().forEach(function(track) {
+ tracks.push({
+ kind: track.kind,
+ track: track,
+ wantReceive: track.kind === 'audio' ?
+ numAudioTracks > 0 : numVideoTracks > 0
+ });
+ if (track.kind === 'audio') {
+ numAudioTracks--;
+ } else if (track.kind === 'video') {
+ numVideoTracks--;
+ }
+ });
+ }
+ // Create M-lines for recvonly streams.
+ while (numAudioTracks > 0 || numVideoTracks > 0) {
+ if (numAudioTracks > 0) {
+ tracks.push({
+ kind: 'audio',
+ wantReceive: true
+ });
+ numAudioTracks--;
+ }
+ if (numVideoTracks > 0) {
+ tracks.push({
+ kind: 'video',
+ wantReceive: true
+ });
+ numVideoTracks--;
+ }
+ }
+
+ var sdp = SDPUtils.writeSessionBoilerplate();
+ var transceivers = [];
+ tracks.forEach(function(mline, sdpMLineIndex) {
+ // For each track, create an ice gatherer, ice transport,
+ // dtls transport, potentially rtpsender and rtpreceiver.
+ var track = mline.track;
+ var kind = mline.kind;
+ var mid = SDPUtils.generateIdentifier();
+
+ var transports = self.usingBundle && sdpMLineIndex > 0 ? {
+ iceGatherer: transceivers[0].iceGatherer,
+ iceTransport: transceivers[0].iceTransport,
+ dtlsTransport: transceivers[0].dtlsTransport
+ } : self._createIceAndDtlsTransports(mid, sdpMLineIndex);
+
+ var localCapabilities = RTCRtpSender.getCapabilities(kind);
+ // filter RTX until additional stuff needed for RTX is implemented
+ // in adapter.js
+ localCapabilities.codecs = localCapabilities.codecs.filter(
+ function(codec) {
+ return codec.name !== 'rtx';
+ });
+ localCapabilities.codecs.forEach(function(codec) {
+ // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552
+ // by adding level-asymmetry-allowed=1
+ if (codec.name === 'H264' &&
+ codec.parameters['level-asymmetry-allowed'] === undefined) {
+ codec.parameters['level-asymmetry-allowed'] = '1';
+ }
+ });
+
+ var rtpSender;
+ var rtpReceiver;
+
+ // generate an ssrc now, to be used later in rtpSender.send
+ var sendEncodingParameters = [{
+ ssrc: (2 * sdpMLineIndex + 1) * 1001
+ }];
+ if (track) {
+ rtpSender = new RTCRtpSender(track, transports.dtlsTransport);
+ }
+
+ if (mline.wantReceive) {
+ rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind);
+ }
+
+ transceivers[sdpMLineIndex] = {
+ iceGatherer: transports.iceGatherer,
+ iceTransport: transports.iceTransport,
+ dtlsTransport: transports.dtlsTransport,
+ localCapabilities: localCapabilities,
+ remoteCapabilities: null,
+ rtpSender: rtpSender,
+ rtpReceiver: rtpReceiver,
+ kind: kind,
+ mid: mid,
+ sendEncodingParameters: sendEncodingParameters,
+ recvEncodingParameters: null
+ };
+ });
+ if (this.usingBundle) {
+ sdp += 'a=group:BUNDLE ' + transceivers.map(function(t) {
+ return t.mid;
+ }).join(' ') + '\r\n';
+ }
+ tracks.forEach(function(mline, sdpMLineIndex) {
+ var transceiver = transceivers[sdpMLineIndex];
+ sdp += SDPUtils.writeMediaSection(transceiver,
+ transceiver.localCapabilities, 'offer', self.localStreams[0]);
+ });
+
+ this._pendingOffer = transceivers;
+ var desc = new RTCSessionDescription({
+ type: 'offer',
+ sdp: sdp
+ });
+ if (arguments.length && typeof arguments[0] === 'function') {
+ window.setTimeout(arguments[0], 0, desc);
+ }
+ return Promise.resolve(desc);
+ };
+
+ window.RTCPeerConnection.prototype.createAnswer = function() {
+ var self = this;
+
+ var sdp = SDPUtils.writeSessionBoilerplate();
+ if (this.usingBundle) {
+ sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) {
+ return t.mid;
+ }).join(' ') + '\r\n';
+ }
+ this.transceivers.forEach(function(transceiver) {
+ if (transceiver.isDatachannel) {
+ sdp += 'm=application 0 DTLS/SCTP 5000\r\n' +
+ 'c=IN IP4 0.0.0.0\r\n' +
+ 'a=mid:' + transceiver.mid + '\r\n';
+ return;
+ }
+ // Calculate intersection of capabilities.
+ var commonCapabilities = self._getCommonCapabilities(
+ transceiver.localCapabilities,
+ transceiver.remoteCapabilities);
+
+ sdp += SDPUtils.writeMediaSection(transceiver, commonCapabilities,
+ 'answer', self.localStreams[0]);
+ });
+
+ var desc = new RTCSessionDescription({
+ type: 'answer',
+ sdp: sdp
+ });
+ if (arguments.length && typeof arguments[0] === 'function') {
+ window.setTimeout(arguments[0], 0, desc);
+ }
+ return Promise.resolve(desc);
+ };
+
+ window.RTCPeerConnection.prototype.addIceCandidate = function(candidate) {
+ if (candidate === null) {
+ this.transceivers.forEach(function(transceiver) {
+ transceiver.iceTransport.addRemoteCandidate({});
+ });
+ } else {
+ var mLineIndex = candidate.sdpMLineIndex;
+ if (candidate.sdpMid) {
+ for (var i = 0; i < this.transceivers.length; i++) {
+ if (this.transceivers[i].mid === candidate.sdpMid) {
+ mLineIndex = i;
+ break;
+ }
+ }
+ }
+ var transceiver = this.transceivers[mLineIndex];
+ if (transceiver) {
+ var cand = Object.keys(candidate.candidate).length > 0 ?
+ SDPUtils.parseCandidate(candidate.candidate) : {};
+ // Ignore Chrome's invalid candidates since Edge does not like them.
+ if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) {
+ return;
+ }
+ // Ignore RTCP candidates, we assume RTCP-MUX.
+ if (cand.component !== '1') {
+ return;
+ }
+ // A dirty hack to make samples work.
+ if (cand.type === 'endOfCandidates') {
+ cand = {};
+ }
+ transceiver.iceTransport.addRemoteCandidate(cand);
+
+ // update the remoteDescription.
+ var sections = SDPUtils.splitSections(this.remoteDescription.sdp);
+ sections[mLineIndex + 1] += (cand.type ? candidate.candidate.trim()
+ : 'a=end-of-candidates') + '\r\n';
+ this.remoteDescription.sdp = sections.join('');
+ }
+ }
+ if (arguments.length > 1 && typeof arguments[1] === 'function') {
+ window.setTimeout(arguments[1], 0);
+ }
+ return Promise.resolve();
+ };
+
+ window.RTCPeerConnection.prototype.getStats = function() {
+ var promises = [];
+ this.transceivers.forEach(function(transceiver) {
+ ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport',
+ 'dtlsTransport'].forEach(function(method) {
+ if (transceiver[method]) {
+ promises.push(transceiver[method].getStats());
+ }
+ });
+ });
+ var cb = arguments.length > 1 && typeof arguments[1] === 'function' &&
+ arguments[1];
+ return new Promise(function(resolve) {
+ // shim getStats with maplike support
+ var results = new Map();
+ Promise.all(promises).then(function(res) {
+ res.forEach(function(result) {
+ Object.keys(result).forEach(function(id) {
+ results.set(id, result[id]);
+ results[id] = result[id];
+ });
+ });
+ if (cb) {
+ window.setTimeout(cb, 0, results);
+ }
+ resolve(results);
+ });
+ });
+ };
+ }
+};
+
+// Expose public methods.
+module.exports = {
+ shimPeerConnection: edgeShim.shimPeerConnection,
+ shimGetUserMedia: require('./getusermedia')
+};
+
+},{"../utils":209,"./getusermedia":205,"sdp":173}],205:[function(require,module,exports){
+arguments[4][37][0].apply(exports,arguments)
+},{"dup":37}],206:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+ /* eslint-env node */
+'use strict';
+
+var browserDetails = require('../utils').browserDetails;
+
+var firefoxShim = {
+ shimOnTrack: function() {
+ if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in
+ window.RTCPeerConnection.prototype)) {
+ Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
+ get: function() {
+ return this._ontrack;
+ },
+ set: function(f) {
+ if (this._ontrack) {
+ this.removeEventListener('track', this._ontrack);
+ this.removeEventListener('addstream', this._ontrackpoly);
+ }
+ this.addEventListener('track', this._ontrack = f);
+ this.addEventListener('addstream', this._ontrackpoly = function(e) {
+ e.stream.getTracks().forEach(function(track) {
+ var event = new Event('track');
+ event.track = track;
+ event.receiver = {track: track};
+ event.streams = [e.stream];
+ this.dispatchEvent(event);
+ }.bind(this));
+ }.bind(this));
+ }
+ });
+ }
+ },
+
+ shimSourceObject: function() {
+ // Firefox has supported mozSrcObject since FF22, unprefixed in 42.
+ if (typeof window === 'object') {
+ if (window.HTMLMediaElement &&
+ !('srcObject' in window.HTMLMediaElement.prototype)) {
+ // Shim the srcObject property, once, when HTMLMediaElement is found.
+ Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
+ get: function() {
+ return this.mozSrcObject;
+ },
+ set: function(stream) {
+ this.mozSrcObject = stream;
+ }
+ });
+ }
+ }
+ },
+
+ shimPeerConnection: function() {
+ if (typeof window !== 'object' || !(window.RTCPeerConnection ||
+ window.mozRTCPeerConnection)) {
+ return; // probably media.peerconnection.enabled=false in about:config
+ }
+ // The RTCPeerConnection object.
+ if (!window.RTCPeerConnection) {
+ window.RTCPeerConnection = function(pcConfig, pcConstraints) {
+ if (browserDetails.version < 38) {
+ // .urls is not supported in FF < 38.
+ // create RTCIceServers with a single url.
+ if (pcConfig && pcConfig.iceServers) {
+ var newIceServers = [];
+ for (var i = 0; i < pcConfig.iceServers.length; i++) {
+ var server = pcConfig.iceServers[i];
+ if (server.hasOwnProperty('urls')) {
+ for (var j = 0; j < server.urls.length; j++) {
+ var newServer = {
+ url: server.urls[j]
+ };
+ if (server.urls[j].indexOf('turn') === 0) {
+ newServer.username = server.username;
+ newServer.credential = server.credential;
+ }
+ newIceServers.push(newServer);
}
- break
+ } else {
+ newIceServers.push(pcConfig.iceServers[i]);
+ }
}
+ pcConfig.iceServers = newIceServers;
+ }
+ }
+ return new mozRTCPeerConnection(pcConfig, pcConstraints);
+ };
+ window.RTCPeerConnection.prototype = mozRTCPeerConnection.prototype;
+
+ // wrap static methods. Currently just generateCertificate.
+ if (mozRTCPeerConnection.generateCertificate) {
+ Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
+ get: function() {
+ return mozRTCPeerConnection.generateCertificate;
+ }
+ });
+ }
+
+ window.RTCSessionDescription = mozRTCSessionDescription;
+ window.RTCIceCandidate = mozRTCIceCandidate;
+ }
+
+ // shim away need for obsolete RTCIceCandidate/RTCSessionDescription.
+ ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
+ .forEach(function(method) {
+ var nativeMethod = RTCPeerConnection.prototype[method];
+ RTCPeerConnection.prototype[method] = function() {
+ arguments[0] = new ((method === 'addIceCandidate') ?
+ RTCIceCandidate : RTCSessionDescription)(arguments[0]);
+ return nativeMethod.apply(this, arguments);
+ };
+ });
+
+ // support for addIceCandidate(null)
+ var nativeAddIceCandidate =
+ RTCPeerConnection.prototype.addIceCandidate;
+ RTCPeerConnection.prototype.addIceCandidate = function() {
+ if (arguments[0] === null) {
+ if (arguments[1]) {
+ arguments[1].apply(null);
+ }
+ return Promise.resolve();
+ }
+ return nativeAddIceCandidate.apply(this, arguments);
+ };
+
+ // shim getStats with maplike support
+ var makeMapStats = function(stats) {
+ var map = new Map();
+ Object.keys(stats).forEach(function(key) {
+ map.set(key, stats[key]);
+ map[key] = stats[key];
+ });
+ return map;
+ };
+
+ var nativeGetStats = RTCPeerConnection.prototype.getStats;
+ RTCPeerConnection.prototype.getStats = function(selector, onSucc, onErr) {
+ return nativeGetStats.apply(this, [selector || null])
+ .then(function(stats) {
+ return makeMapStats(stats);
+ })
+ .then(onSucc, onErr);
+ };
+ }
+};
+
+// Expose public methods.
+module.exports = {
+ shimOnTrack: firefoxShim.shimOnTrack,
+ shimSourceObject: firefoxShim.shimSourceObject,
+ shimPeerConnection: firefoxShim.shimPeerConnection,
+ shimGetUserMedia: require('./getusermedia')
+};
+
+},{"../utils":209,"./getusermedia":207}],207:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+ /* eslint-env node */
+'use strict';
+
+var logging = require('../utils').log;
+var browserDetails = require('../utils').browserDetails;
+
+// Expose public methods.
+module.exports = function() {
+ var shimError_ = function(e) {
+ return {
+ name: {
+ SecurityError: 'NotAllowedError',
+ PermissionDeniedError: 'NotAllowedError'
+ }[e.name] || e.name,
+ message: {
+ 'The operation is insecure.': 'The request is not allowed by the ' +
+ 'user agent or the platform in the current context.'
+ }[e.message] || e.message,
+ constraint: e.constraint,
+ toString: function() {
+ return this.name + (this.message && ': ') + this.message;
+ }
+ };
+ };
+
+ // getUserMedia constraints shim.
+ var getUserMedia_ = function(constraints, onSuccess, onError) {
+ var constraintsToFF37_ = function(c) {
+ if (typeof c !== 'object' || c.require) {
+ return c;
+ }
+ var require = [];
+ Object.keys(c).forEach(function(key) {
+ if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
+ return;
+ }
+ var r = c[key] = (typeof c[key] === 'object') ?
+ c[key] : {ideal: c[key]};
+ if (r.min !== undefined ||
+ r.max !== undefined || r.exact !== undefined) {
+ require.push(key);
+ }
+ if (r.exact !== undefined) {
+ if (typeof r.exact === 'number') {
+ r. min = r.max = r.exact;
+ } else {
+ c[key] = r.exact;
+ }
+ delete r.exact;
}
+ if (r.ideal !== undefined) {
+ c.advanced = c.advanced || [];
+ var oc = {};
+ if (typeof r.ideal === 'number') {
+ oc[key] = {min: r.ideal, max: r.ideal};
+ } else {
+ oc[key] = r.ideal;
+ }
+ c.advanced.push(oc);
+ delete r.ideal;
+ if (!Object.keys(r).length) {
+ delete c[key];
+ }
+ }
+ });
+ if (require.length) {
+ c.require = require;
+ }
+ return c;
+ };
+ constraints = JSON.parse(JSON.stringify(constraints));
+ if (browserDetails.version < 38) {
+ logging('spec: ' + JSON.stringify(constraints));
+ if (constraints.audio) {
+ constraints.audio = constraintsToFF37_(constraints.audio);
+ }
+ if (constraints.video) {
+ constraints.video = constraintsToFF37_(constraints.video);
+ }
+ logging('ff37: ' + JSON.stringify(constraints));
+ }
+ return navigator.mozGetUserMedia(constraints, onSuccess, function(e) {
+ onError(shimError_(e));
+ });
+ };
- if (typeof recordStart === 'number' &&
- recordStart <= data.length) {
+ // Returns the result of getUserMedia as a Promise.
+ var getUserMediaPromise_ = function(constraints) {
+ return new Promise(function(resolve, reject) {
+ getUserMedia_(constraints, resolve, reject);
+ });
+ };
+
+ // Shim for mediaDevices on older versions.
+ if (!navigator.mediaDevices) {
+ navigator.mediaDevices = {getUserMedia: getUserMediaPromise_,
+ addEventListener: function() { },
+ removeEventListener: function() { }
+ };
+ }
+ navigator.mediaDevices.enumerateDevices =
+ navigator.mediaDevices.enumerateDevices || function() {
+ return new Promise(function(resolve) {
+ var infos = [
+ {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''},
+ {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''}
+ ];
+ resolve(infos);
+ });
+ };
- remainder = data.slice(recordStart)
- recordStart = 0
+ if (browserDetails.version < 41) {
+ // Work around http://bugzil.la/1169665
+ var orgEnumerateDevices =
+ navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices);
+ navigator.mediaDevices.enumerateDevices = function() {
+ return orgEnumerateDevices().then(undefined, function(e) {
+ if (e.name === 'NotFoundError') {
+ return [];
}
+ throw e;
+ });
+ };
+ }
+ if (browserDetails.version < 49) {
+ var origGetUserMedia = navigator.mediaDevices.getUserMedia.
+ bind(navigator.mediaDevices);
+ navigator.mediaDevices.getUserMedia = function(c) {
+ return origGetUserMedia(c).then(function(stream) {
+ // Work around https://bugzil.la/802326
+ if (c.audio && !stream.getAudioTracks().length ||
+ c.video && !stream.getVideoTracks().length) {
+ stream.getTracks().forEach(function(track) {
+ track.stop();
+ });
+ throw new DOMException('The object can not be found here.',
+ 'NotFoundError');
+ }
+ return stream;
+ }, function(e) {
+ return Promise.reject(shimError_(e));
+ });
+ };
+ }
+ navigator.getUserMedia = function(constraints, onSuccess, onError) {
+ if (browserDetails.version < 44) {
+ return getUserMedia_(constraints, onSuccess, onError);
}
+ // Replace Firefox 44+'s deprecation warning with unprefixed version.
+ console.warn('navigator.getUserMedia has been replaced by ' +
+ 'navigator.mediaDevices.getUserMedia');
+ navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);
+ };
+};
- /*var origEmit = this.emit
- this.emit = function() {
- console.log('ltx', arguments)
- origEmit.apply(this, arguments)
- }*/
+},{"../utils":209}],208:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+'use strict';
+var safariShim = {
+ // TODO: DrAlex, should be here, double check against LayoutTests
+ // shimOnTrack: function() { },
+
+ // TODO: once the back-end for the mac port is done, add.
+ // TODO: check for webkitGTK+
+ // shimPeerConnection: function() { },
+
+ shimGetUserMedia: function() {
+ navigator.getUserMedia = navigator.webkitGetUserMedia;
+ }
+};
+
+// Expose public methods.
+module.exports = {
+ shimGetUserMedia: safariShim.shimGetUserMedia
+ // TODO
+ // shimOnTrack: safariShim.shimOnTrack,
+ // shimPeerConnection: safariShim.shimPeerConnection
+};
+
+},{}],209:[function(require,module,exports){
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+ /* eslint-env node */
+'use strict';
+
+var logDisabled_ = true;
+
+// Utility methods.
+var utils = {
+ disableLog: function(bool) {
+ if (typeof bool !== 'boolean') {
+ return new Error('Argument type: ' + typeof bool +
+ '. Please use a boolean.');
+ }
+ logDisabled_ = bool;
+ return (bool) ? 'adapter.js logging disabled' :
+ 'adapter.js logging enabled';
+ },
+
+ log: function() {
+ if (typeof window === 'object') {
+ if (logDisabled_) {
+ return;
+ }
+ if (typeof console !== 'undefined' && typeof console.log === 'function') {
+ console.log.apply(console, arguments);
+ }
+ }
+ },
+
+ /**
+ * Extract browser version out of the provided user agent string.
+ *
+ * @param {!string} uastring userAgent string.
+ * @param {!string} expr Regular expression used as match criteria.
+ * @param {!number} pos position in the version string to be returned.
+ * @return {!number} browser version.
+ */
+ extractVersion: function(uastring, expr, pos) {
+ var match = uastring.match(expr);
+ return match && match.length >= pos && parseInt(match[pos], 10);
+ },
+
+ /**
+ * Browser detector.
+ *
+ * @return {object} result containing browser and version
+ * properties.
+ */
+ detectBrowser: function() {
+ // Returned result object.
+ var result = {};
+ result.browser = null;
+ result.version = null;
+
+ // Fail early if it's not a browser
+ if (typeof window === 'undefined' || !window.navigator) {
+ result.browser = 'Not a browser.';
+ return result;
+ }
+
+ // Firefox.
+ if (navigator.mozGetUserMedia) {
+ result.browser = 'firefox';
+ result.version = this.extractVersion(navigator.userAgent,
+ /Firefox\/([0-9]+)\./, 1);
+
+ // all webkit-based browsers
+ } else if (navigator.webkitGetUserMedia) {
+ // Chrome, Chromium, Webview, Opera, all use the chrome shim for now
+ if (window.webkitRTCPeerConnection) {
+ result.browser = 'chrome';
+ result.version = this.extractVersion(navigator.userAgent,
+ /Chrom(e|ium)\/([0-9]+)\./, 2);
+
+ // Safari or unknown webkit-based
+ // for the time being Safari has support for MediaStreams but not webRTC
+ } else {
+ // Safari UA substrings of interest for reference:
+ // - webkit version: AppleWebKit/602.1.25 (also used in Op,Cr)
+ // - safari UI version: Version/9.0.3 (unique to Safari)
+ // - safari UI webkit version: Safari/601.4.4 (also used in Op,Cr)
+ //
+ // if the webkit version and safari UI webkit versions are equals,
+ // ... this is a stable version.
+ //
+ // only the internal webkit version is important today to know if
+ // media streams are supported
+ //
+ if (navigator.userAgent.match(/Version\/(\d+).(\d+)/)) {
+ result.browser = 'safari';
+ result.version = this.extractVersion(navigator.userAgent,
+ /AppleWebKit\/([0-9]+)\./, 1);
+
+ // unknown webkit-based browser
+ } else {
+ result.browser = 'Unsupported webkit-based browser ' +
+ 'with GUM support but no WebRTC support.';
+ return result;
+ }
+ }
+
+ // Edge.
+ } else if (navigator.mediaDevices &&
+ navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) {
+ result.browser = 'edge';
+ result.version = this.extractVersion(navigator.userAgent,
+ /Edge\/(\d+).(\d+)$/, 2);
+
+ // Default fallthrough: not supported.
+ } else {
+ result.browser = 'Not a supported browser.';
+ return result;
+ }
+
+ return result;
+ }
+};
+
+// Export.
+module.exports = {
+ log: utils.log,
+ disableLog: utils.disableLog,
+ browserDetails: utils.detectBrowser(),
+ extractVersion: utils.extractVersion
+};
+
+},{}],210:[function(require,module,exports){
+// created by @HenrikJoreteg
+var prefix;
+var version;
+
+if (window.mozRTCPeerConnection || navigator.mozGetUserMedia) {
+ prefix = 'moz';
+ version = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
+} else if (window.webkitRTCPeerConnection || navigator.webkitGetUserMedia) {
+ prefix = 'webkit';
+ version = navigator.userAgent.match(/Chrom(e|ium)/) && parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10);
}
-util.inherits(SaxLtx, events.EventEmitter)
+var PC = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
+var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
+var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;
+var MediaStream = window.webkitMediaStream || window.MediaStream;
+var screenSharing = window.location.protocol === 'https:' &&
+ ((prefix === 'webkit' && version >= 26) ||
+ (prefix === 'moz' && version >= 33))
+var AudioContext = window.AudioContext || window.webkitAudioContext;
+var videoEl = document.createElement('video');
+var supportVp8 = videoEl && videoEl.canPlayType && videoEl.canPlayType('video/webm; codecs="vp8", vorbis') === "probably";
+var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia || navigator.mozGetUserMedia;
+
+// export support flags and constructors.prototype && PC
+module.exports = {
+ prefix: prefix,
+ browserVersion: version,
+ support: !!PC && supportVp8 && !!getUserMedia,
+ // new support style
+ supportRTCPeerConnection: !!PC,
+ supportVp8: supportVp8,
+ supportGetUserMedia: !!getUserMedia,
+ supportDataChannel: !!(PC && PC.prototype && PC.prototype.createDataChannel),
+ supportWebAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource),
+ supportMediaStream: !!(MediaStream && MediaStream.prototype.removeTrack),
+ supportScreenSharing: !!screenSharing,
+ // old deprecated style. Dont use this anymore
+ dataChannel: !!(PC && PC.prototype && PC.prototype.createDataChannel),
+ webAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource),
+ mediaStream: !!(MediaStream && MediaStream.prototype.removeTrack),
+ screenSharing: !!screenSharing,
+ // constructors
+ AudioContext: AudioContext,
+ PeerConnection: PC,
+ SessionDescription: SessionDescription,
+ IceCandidate: IceCandidate,
+ MediaStream: MediaStream,
+ getUserMedia: getUserMedia
+};
-SaxLtx.prototype.end = function(data) {
- if (data) {
- this.write(data)
+},{}],211:[function(require,module,exports){
+/*
+WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based
+on @visionmedia's Emitter from UI Kit.
+
+Why? I wanted it standalone.
+
+I also wanted support for wildcard emitters like this:
+
+emitter.on('*', function (eventName, other, event, payloads) {
+
+});
+
+emitter.on('somenamespace*', function (eventName, payloads) {
+
+});
+
+Please note that callbacks triggered by wildcard registered events also get
+the event name as the first argument.
+*/
+
+module.exports = WildEmitter;
+
+function WildEmitter() { }
+
+WildEmitter.mixin = function (constructor) {
+ var prototype = constructor.prototype || constructor;
+
+ prototype.isWildEmitter= true;
+
+ // Listen on the given `event` with `fn`. Store a group name if present.
+ prototype.on = function (event, groupName, fn) {
+ this.callbacks = this.callbacks || {};
+ var hasGroup = (arguments.length === 3),
+ group = hasGroup ? arguments[1] : undefined,
+ func = hasGroup ? arguments[2] : arguments[1];
+ func._groupName = group;
+ (this.callbacks[event] = this.callbacks[event] || []).push(func);
+ return this;
+ };
+
+ // Adds an `event` listener that will be invoked a single
+ // time then automatically removed.
+ prototype.once = function (event, groupName, fn) {
+ var self = this,
+ hasGroup = (arguments.length === 3),
+ group = hasGroup ? arguments[1] : undefined,
+ func = hasGroup ? arguments[2] : arguments[1];
+ function on() {
+ self.off(event, on);
+ func.apply(this, arguments);
+ }
+ this.on(event, group, on);
+ return this;
+ };
+
+ // Unbinds an entire group
+ prototype.releaseGroup = function (groupName) {
+ this.callbacks = this.callbacks || {};
+ var item, i, len, handlers;
+ for (item in this.callbacks) {
+ handlers = this.callbacks[item];
+ for (i = 0, len = handlers.length; i < len; i++) {
+ if (handlers[i]._groupName === groupName) {
+ //console.log('removing');
+ // remove it and shorten the array we're looping through
+ handlers.splice(i, 1);
+ i--;
+ len--;
+ }
+ }
+ }
+ return this;
+ };
+
+ // Remove the given callback for `event` or all
+ // registered callbacks.
+ prototype.off = function (event, fn) {
+ this.callbacks = this.callbacks || {};
+ var callbacks = this.callbacks[event],
+ i;
+
+ if (!callbacks) return this;
+
+ // remove all handlers
+ if (arguments.length === 1) {
+ delete this.callbacks[event];
+ return this;
+ }
+
+ // remove specific handler
+ i = callbacks.indexOf(fn);
+ callbacks.splice(i, 1);
+ if (callbacks.length === 0) {
+ delete this.callbacks[event];
+ }
+ return this;
+ };
+
+ /// Emit `event` with the given args.
+ // also calls any `*` handlers
+ prototype.emit = function (event) {
+ this.callbacks = this.callbacks || {};
+ var args = [].slice.call(arguments, 1),
+ callbacks = this.callbacks[event],
+ specialCallbacks = this.getWildcardCallbacks(event),
+ i,
+ len,
+ item,
+ listeners;
+
+ if (callbacks) {
+ listeners = callbacks.slice();
+ for (i = 0, len = listeners.length; i < len; ++i) {
+ if (!listeners[i]) {
+ break;
+ }
+ listeners[i].apply(this, args);
+ }
+ }
+
+ if (specialCallbacks) {
+ len = specialCallbacks.length;
+ listeners = specialCallbacks.slice();
+ for (i = 0, len = listeners.length; i < len; ++i) {
+ if (!listeners[i]) {
+ break;
+ }
+ listeners[i].apply(this, [event].concat(args));
+ }
+ }
+
+ return this;
+ };
+
+ // Helper for for finding special wildcard event handlers that match the event
+ prototype.getWildcardCallbacks = function (eventName) {
+ this.callbacks = this.callbacks || {};
+ var item,
+ split,
+ result = [];
+
+ for (item in this.callbacks) {
+ split = item.split('*');
+ if (item === '*' || (split.length === 2 && eventName.slice(0, split[0].length) === split[0])) {
+ result = result.concat(this.callbacks[item]);
+ }
+ }
+ return result;
+ };
+
+};
+
+WildEmitter.mixin(WildEmitter);
+
+},{}],212:[function(require,module,exports){
+module.exports = {
+ Namespace: require('./lib/namespaces'),
+ MUC: require('./lib/muc'),
+ PubSub: require('./lib/pubsub'),
+ Jingle: require('./lib/jingle'),
+ Presence: require('./lib/presence')
+};
+
+},{"./lib/jingle":213,"./lib/muc":214,"./lib/namespaces":215,"./lib/presence":216,"./lib/pubsub":217}],213:[function(require,module,exports){
+module.exports = {
+ Action: {
+ CONTENT_ACCEPT: 'content-accept',
+ CONTENT_ADD: 'content-add',
+ CONTENT_MODIFY: 'content-modify',
+ CONTENT_REJECT: 'content-reject',
+ CONTENT_REMOVE: 'content-remove',
+ DESCRIPTION_INFO: 'description-info',
+ SECURITY_INFO: 'security-info',
+ SESSION_ACCEPT: 'session-accept',
+ SESSION_INFO: 'session-info',
+ SESSION_INITIATE: 'session-initiate',
+ SESSION_TERMINATE: 'session-terminate',
+ TRANSPORT_ACCEPT: 'transport-accept',
+ TRANSPORT_INFO: 'transport-info',
+ TRANSPORT_REJECT: 'transport-reject',
+ TRANSPORT_REPLACE: 'transport-replace'
+ },
+ Reason: {
+ ALTERNATIVE_SESSION: 'alernative-session',
+ BUSY: 'busy',
+ CANCEL: 'cancel',
+ CONNECTIVITY_ERROR: 'connectivity-error',
+ DECLINE: 'decline',
+ EXPIRED: 'expired',
+ FAILED_APPLICATION: 'failed-application',
+ FAILED_TRANSPORT: 'failed-transport',
+ GENERAL_ERROR: 'general-error',
+ GONE: 'gone',
+ INCOMPATIBLE_PARAMETERS: 'incompatible-parameters',
+ MEDIA_ERROR: 'media-error',
+ SECURITY_ERROR: 'security-error',
+ SUCCESS: 'success',
+ TIMEOUT: 'timeout',
+ UNSUPPORTED_APPLICATIONS: 'unsupported-applications',
+ UNSUPPORTED_TRANSPORTS: 'unsupported-transports'
+ },
+ Condition: {
+ OUT_OF_ORDER: 'out-of-order',
+ TIE_BREAK: 'tie-break',
+ UNKNOWN_SESSION: 'unknown-session',
+ UNSUPPORTED_INFO: 'unsupported-info'
+ }
+};
+
+},{}],214:[function(require,module,exports){
+module.exports = {
+ Status: {
+ REALJID_PUBLIC: '100',
+ AFFILIATION_CHANGED: '101',
+ UNAVAILABLE_SHOWN: '102',
+ UNAVAILABLE_NOT_SHOWN: '103',
+ CONFIGURATION_CHANGED: '104',
+ SELF_PRESENCE: '110',
+ LOGGING_ENABLED: '170',
+ LOGGING_DISABLED: '171',
+ NON_ANONYMOUS: '172',
+ SEMI_ANONYMOUS: '173',
+ FULLY_ANONYMOUS: '174',
+ ROOM_CREATED: '201',
+ NICK_ASSIGNED: '210',
+ BANNED: '301',
+ NEW_NICK: '303',
+ KICKED: '307',
+ REMOVED_AFFILIATION: '321',
+ REMOVED_MEMBERSHIP: '322',
+ REMOVED_SHUTDOWN: '332'
+ },
+ Affiliation: {
+ ADMIN: 'admin',
+ MEMBER: 'member',
+ NONE: 'none',
+ OUTCAST: 'outcast',
+ OWNER: 'owner'
+ },
+ Role: {
+ MODERATOR: 'moderator',
+ NONE: 'none',
+ PARTICIPANT: 'participant',
+ VISITOR: 'visitor'
}
+};
+
+},{}],215:[function(require,module,exports){
+module.exports = {
+// ================================================================
+// RFCS
+// ================================================================
+
+// RFC 6120
+ BIND: 'urn:ietf:params:xml:ns:xmpp-bind',
+ CLIENT: 'jabber:client',
+ SASL: 'urn:ietf:params:xml:ns:xmpp-sasl',
+ SERVER: 'jabber:server',
+ SESSION: 'urn:ietf:params:xml:ns:xmpp-session',
+ STANZA_ERROR: 'urn:ietf:params:xml:ns:xmpp-stanzas',
+ STREAM: 'http://etherx.jabber.org/streams',
+ STREAM_ERROR: 'urn:ietf:params:xml:ns:xmpp-streams',
+
+// RFC 6121
+ ROSTER: 'jabber:iq:roster',
+ ROSTER_VERSIONING: 'urn:xmpp:features:rosterver',
+ SUBSCRIPTION_PREAPPROVAL: 'urn:xmpp:features:pre-approval',
+
+// RFC 7395
+ FRAMING: 'urn:ietf:params:xml:ns:xmpp-framing',
+
+// ================================================================
+// XEPS
+// ================================================================
+
+// XEP-0004
+ DATAFORM: 'jabber:x:data',
+
+// XEP-0009
+ RPC: 'jabber:iq:rpc',
+
+// XEP-0012
+ LAST_ACTIVITY: 'jabber:iq:last',
+
+// XEP-0016
+ PRIVACY: 'jabber:iq:privacy',
+
+// XEP-0030
+ DISCO_INFO: 'http://jabber.org/protocol/disco#info',
+ DISCO_ITEMS: 'http://jabber.org/protocol/disco#items',
+
+// XEP-0033
+ ADDRESS: 'http://jabber.org/protocol/address',
+
+// XEP-0045
+ MUC: 'http://jabber.org/protocol/muc',
+ MUC_ADMIN: 'http://jabber.org/protocol/muc#admin',
+ MUC_OWNER: 'http://jabber.org/protocol/muc#owner',
+ MUC_USER: 'http://jabber.org/protocol/muc#user',
+
+// XEP-0047
+ IBB: 'http://jabber.org/protocol/ibb',
+
+// XEP-0048
+ BOOKMARKS: 'storage:bookmarks',
+
+// XEP-0049
+ PRIVATE: 'jabber:iq:private',
+
+// XEP-0050
+ ADHOC_COMMANDS: 'http://jabber.org/protocol/commands',
+
+// XEP-0054
+ VCARD_TEMP: 'vcard-temp',
+
+// XEP-0055
+ SEARCH: 'jabber:iq:search',
+
+// XEP-0059
+ RSM: 'http://jabber.org/protocol/rsm',
+
+// XEP-0060
+ PUBSUB: 'http://jabber.org/protocol/pubsub',
+ PUBSUB_ERRORS: 'http://jabber.org/protocol/pubsub#errors',
+ PUBSUB_EVENT: 'http://jabber.org/protocol/pubsub#event',
+ PUBSUB_OWNER: 'http://jabber.org/protocol/pubsub#owner',
+
+// XEP-0065
+ SOCKS5: 'http://jabber.org/protocol/bytestreams',
+
+// XEP-0066
+ OOB: 'jabber:x:oob',
+
+// XEP-0070
+ HTTP_AUTH: 'http://jabber.org/protocol/http-auth',
+
+// XEP-0071
+ XHTML_IM: 'http://jabber.org/protocol/xhtml-im',
+
+// XEP-0077
+ REGISTER: 'jabber:iq:register',
+
+// XEP-0079
+ AMP: 'http://jabber.org/protocol/amp',
+
+// XEP-0080
+ GEOLOC: 'http://jabber.org/protocol/geoloc',
+
+// XEP-0083
+ ROSTER_DELIMITER: 'roster:delimiter',
+
+// XEP-0084
+ AVATAR_DATA: 'urn:xmpp:avatar:data',
+ AVATAR_METADATA: 'urn:xmpp:avatar:metadata',
+
+// XEP-0085
+ CHAT_STATES: 'http://jabber.org/protocol/chatstates',
+
+// XEP-0092
+ VERSION: 'jabber:iq:version',
+
+// XEP-0107
+ MOOD: 'http://jabber.org/protocol/mood',
+
+// XEP-0108
+ ACTIVITY: 'http://jabber.org/protocol/activity',
+
+// XEP-0114
+ COMPONENT: 'jabber:component:accept',
+
+// XEP-0115
+ CAPS: 'http://jabber.org/protocol/caps',
+
+// XEP-0118
+ TUNE: 'http://jabber.org/protocol/tune',
+
+// XEP-0122
+ DATAFORM_VALIDATION: 'http://jabber.org/protocol/xdata-validate',
+
+// XEP-0124
+ BOSH: 'http://jabber.org/protocol/httpbind',
+
+// XEP-0131
+ SHIM: 'http://jabber.org/protocol/shim',
+
+// XEP-0138
+ COMPRESSION: 'http://jabber.org/features/compress',
+
+// XEP-0141
+ DATAFORM_LAYOUT: 'http://jabber.org/protocol/xdata-layout',
+
+// XEP-0144
+ ROSTER_EXCHANGE: 'http://jabber.org/protocol/rosterx',
+
+// XEP-0145
+ ROSTER_NOTES: 'storage:rosternotes',
+
+// XEP-0152
+ REACH_0: 'urn:xmpp:reach:0',
+
+// XEP-0153
+ VCARD_TEMP_UPDATE: 'vcard-temp:x:update',
+
+// XEP-0158
+ CAPTCHA: 'urn:xmpp:captcha',
+
+// XEP-0166
+ JINGLE_1: 'urn:xmpp:jingle:1',
+ JINGLE_ERRORS_1: 'urn:xmpp:jingle:errors:1',
+
+// XEP-0167
+ JINGLE_RTP_1: 'urn:xmpp:jingle:apps:rtp:1',
+ JINGLE_RTP_ERRORS_1: 'urn:xmpp:jingle:apps:rtp:errors:1',
+ JINGLE_RTP_INFO_1: 'urn:xmpp:jingle:apps:rtp:info:1',
+
+// XEP-0171
+ LANG_TRANS: 'urn:xmpp:langtrans',
+ LANG_TRANS_ITEMS: 'urn:xmpp:langtrans:items',
+
+// XEP-0172
+ NICK: 'http://jabber.org/protocol/nick',
+
+// XEP-0176
+ JINGLE_ICE_UDP_1: 'urn:xmpp:jingle:transports:ice-udp:1',
+
+// XEP-0177
+ JINGLE_RAW_UDP_1: 'urn:xmpp:jingle:transports:raw-udp:1',
+
+// XEP-0184
+ RECEIPTS: 'urn:xmpp:receipts',
+
+// XEP-0186
+ INVISIBLE_0: 'urn:xmpp:invisible:0',
+
+// XEP-0191
+ BLOCKING: 'urn:xmpp:blocking',
+
+// XEP-0198
+ SMACKS_3: 'urn:xmpp:sm:3',
+
+// XEP-0199
+ PING: 'urn:xmpp:ping',
+
+// XEP-0202
+ TIME: 'urn:xmpp:time',
+
+// XEP-0203
+ DELAY: 'urn:xmpp:delay',
+
+// XEP-0206
+ BOSH_XMPP: 'urn:xmpp:xbosh',
+
+// XEP-0215
+ DISCO_EXTERNAL_1: 'urn:xmpp:extdisco:1',
+
+// XEP-0221
+ DATAFORM_MEDIA: 'urn:xmpp:media-element',
+
+// XEP-0224
+ ATTENTION_0: 'urn:xmpp:attention:0',
+
+// XEP-0231
+ BOB: 'urn:xmpp:bob',
+
+// XEP-0234
+ FILE_TRANSFER_3: 'urn:xmpp:jingle:apps:file-transfer:3',
+ FILE_TRANSFER_4: 'urn:xmpp:jingle:apps:file-transfer:4',
+
+// XEP-0249
+ MUC_DIRECT_INVITE: 'jabber:x:conference',
+
+// XEP-0258
+ SEC_LABEL_0: 'urn:xmpp:sec-label:0',
+ SEC_LABEL_CATALOG_2: 'urn:xmpp:sec-label:catalog:2',
+ SEC_LABEL_ESS_0: 'urn:xmpp:sec-label:ess:0',
- /* Uh, yeah */
- this.write = function() {}
+// XEP-0260
+ JINGLE_SOCKS5_1: 'urn:xmpp:jingle:transports:s5b:1',
+
+// XEP-0261
+ JINGLE_IBB_1: 'urn:xmpp:jingle:transports:ibb:1',
+
+// XEP-0262
+ JINGLE_RTP_ZRTP_1: 'urn:xmpp:jingle:apps:rtp:zrtp:1',
+
+// XEP-0264
+ THUMBS_0: 'urn:xmpp:thumbs:0',
+ THUMBS_1: 'urn:xmpp:thumbs:1',
+
+// XEP-0276
+ DECLOAKING_0: 'urn:xmpp:decloaking:0',
+
+// XEP-0280
+ CARBONS_2: 'urn:xmpp:carbons:2',
+
+// XEP-0293
+ JINGLE_RTP_RTCP_FB_0: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0',
+
+// XEP-0294
+ JINGLE_RTP_HDREXT_0: 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0',
+
+// XEP-0297
+ FORWARD_0: 'urn:xmpp:forward:0',
+
+// XEP-0300
+ HASHES_1: 'urn:xmpp:hashes:1',
+
+// XEP-0301
+ RTT_0: 'urn:xmpp:rtt:0',
+
+// XEP-0307
+ MUC_UNIQUE: 'http://jabber.org/protocol/muc#unique',
+
+// XEP-308
+ CORRECTION_0: 'urn:xmpp:message-correct:0',
+
+// XEP-0310
+ PSA: 'urn:xmpp:psa',
+
+// XEP-0313
+ MAM_TMP: 'urn:xmpp:mam:tmp',
+ MAM_0: 'urn:xmpp:mam:0',
+
+// XEP-0317
+ HATS_0: 'urn:xmpp:hats:0',
+
+// XEP-0319
+ IDLE_1: 'urn:xmpp:idle:1',
+
+// XEP-0320
+ JINGLE_DTLS_0: 'urn:xmpp:jingle:apps:dtls:0',
+
+// XEP-0328
+ JID_PREP_0: 'urn:xmpp:jidprep:0',
+
+// XEP-0334
+ HINTS: 'urn:xmpp:hints',
+
+// XEP-0335
+ JSON_0: 'urn:xmpp:json:0',
+
+// XEP-0337
+ EVENTLOG: 'urn:xmpp:eventlog',
+
+// XEP-0338
+ JINGLE_GROUPING_0: 'urn:xmpp:jingle:apps:grouping:0',
+
+// XEP-0339
+ JINGLE_RTP_SSMA_0: 'urn:xmpp:jingle:apps:rtp:ssma:0',
+
+// XEP-0340
+ COLIBRI: 'http://jitsi.org/protocol/colibri',
+
+// XEP-0343
+ DTLS_SCTP_1: 'urn:xmpp:jingle:transports:dtls-sctp:1',
+
+// XEP-0352
+ CSI: 'urn:xmpp:csi',
+
+// XEP-0353
+ JINGLE_MSG_INITIATE_0: 'urn:xmpp:jingle:jingle-message:0',
+
+// XEP-0357
+ PUSH_0: 'urn:xmpp:push:0',
+
+// XEP-0358
+ JINGLE_PUB_1: 'urn:xmpp:jinglepub:1'
+};
+
+},{}],216:[function(require,module,exports){
+module.exports = {
+ Type: {
+ SUBSCRIBE: 'subscribe',
+ SUBSCRIBED: 'subscribed',
+ UNSUBSCRIBE: 'unsubscribe',
+ UNSUBSCRIBED: 'unsubscribed',
+ PROBE: 'probe',
+ UNAVAILABLE: 'unavailable'
+ },
+ Show: {
+ CHAT: 'chat',
+ AWAY: 'away',
+ DO_NOT_DISTURB: 'dnd',
+ EXTENDED_AWAY: 'xa'
+ }
+};
+
+},{}],217:[function(require,module,exports){
+module.exports = {
+ Affiliation: {
+ MEMBER: 'member',
+ NONE: 'none',
+ OUTCAST: 'outcast',
+ OWNER: 'owner',
+ PUBLISHER: 'publisher',
+ PUBLISH_ONLY: 'publish-only'
+ },
+ Subscription: {
+ NONE: 'none',
+ PENDING: 'pending',
+ UNCONFIGURED: 'unconfigured',
+ SUBSCRIBED: 'subscribed'
+ },
+ AccessModel: {
+ OPEN: 'open',
+ PRESENCE: 'presence',
+ ROSTER: 'roster',
+ AUTHORIZE: 'authorize',
+ WHITELIST: 'whitelist'
+ },
+ Condition: {
+ CONFLICT: 'conflict'
+ }
+};
+
+},{}],218:[function(require,module,exports){
+'use strict';
+
+var StringPrep = require('./lib/stringprep');
+
+// All of our StringPrep fallbacks work correctly
+// in the ASCII range, so we can reliably mark
+// ASCII-only JIDs as prepped.
+var ASCII = /^[\x00-\x7F]*$/;
+
+
+
+function bareJID(local, domain) {
+ if (local) {
+ return local + '@' + domain;
+ }
+ return domain;
}
-function unescapeXml(s) {
- return s.
- replace(/\&(amp|#38);/g, '&').
- replace(/\&(lt|#60);/g, '<').
- replace(/\&(gt|#62);/g, '>').
- replace(/\&(quot|#34);/g, '"').
- replace(/\&(apos|#39);/g, '\'').
- replace(/\&(nbsp|#160);/g, '\n')
+function fullJID(local, domain, resource) {
+ if (resource) {
+ return bareJID(local, domain) + '/' + resource;
+ }
+ return bareJID(local, domain);
}
-},{"events":6,"util":28}],249:[function(require,module,exports){
-arguments[4][120][0].apply(exports,arguments)
-},{"dup":120}],250:[function(require,module,exports){
-arguments[4][121][0].apply(exports,arguments)
-},{"./rng":249,"dup":121}],251:[function(require,module,exports){
-arguments[4][83][0].apply(exports,arguments)
-},{"dup":83}],252:[function(require,module,exports){
+
+exports.prep = function (data) {
+ var local = data.local;
+ var domain = data.domain;
+ var resource = data.resource;
+ var unescapedLocal = local;
+
+ if (local) {
+ local = StringPrep.nodeprep(local);
+ unescapedLocal = exports.unescape(local);
+ }
+
+ if (resource) {
+ resource = StringPrep.resourceprep(resource);
+ }
+
+ if (domain[domain.length - 1] === '.') {
+ domain = domain.slice(0, domain.length - 1);
+ }
+
+ domain = StringPrep.nameprep(domain.split('.').map(StringPrep.toUnicode).join('.'));
+
+ return {
+ prepped: data.prepped || StringPrep.available,
+ local: local,
+ domain: domain,
+ resource: resource,
+ bare: bareJID(local, domain),
+ full: fullJID(local, domain, resource),
+ unescapedLocal: unescapedLocal,
+ unescapedBare: bareJID(unescapedLocal, domain),
+ unescapedFull: fullJID(unescapedLocal, domain, resource)
+ };
+};
+
+exports.parse = function (jid, trusted) {
+ var local = '';
+ var domain = '';
+ var resource = '';
+
+ trusted = trusted || ASCII.test(jid);
+
+ var resourceStart = jid.indexOf('/');
+ if (resourceStart > 0) {
+ resource = jid.slice(resourceStart + 1);
+ jid = jid.slice(0, resourceStart);
+ }
+
+ var localEnd = jid.indexOf('@');
+ if (localEnd > 0) {
+ local = jid.slice(0, localEnd);
+ jid = jid.slice(localEnd + 1);
+ }
+
+ domain = jid;
+
+ var preppedJID = exports.prep({
+ local: local,
+ domain: domain,
+ resource: resource,
+ });
+
+ preppedJID.prepped = preppedJID.prepped || trusted;
+
+ return preppedJID;
+};
+
+exports.equal = function (jid1, jid2, requirePrep) {
+ jid1 = new exports.JID(jid1);
+ jid2 = new exports.JID(jid2);
+ if (arguments.length === 2) {
+ requirePrep = true;
+ }
+ return jid1.local === jid2.local &&
+ jid1.domain === jid2.domain &&
+ jid1.resource === jid2.resource &&
+ (requirePrep ? jid1.prepped && jid2.prepped : true);
+};
+
+exports.equalBare = function (jid1, jid2, requirePrep) {
+ jid1 = new exports.JID(jid1);
+ jid2 = new exports.JID(jid2);
+ if (arguments.length === 2) {
+ requirePrep = true;
+ }
+ return jid1.local === jid2.local &&
+ jid1.domain === jid2.domain &&
+ (requirePrep ? jid1.prepped && jid2.prepped : true);
+};
+
+exports.isBare = function (jid) {
+ jid = new exports.JID(jid);
+
+ var hasResource = !!jid.resource;
+
+ return !hasResource;
+};
+
+exports.isFull = function (jid) {
+ jid = new exports.JID(jid);
+
+ var hasResource = !!jid.resource;
+
+ return hasResource;
+};
+
+exports.escape = function (val) {
+ return val.replace(/^\s+|\s+$/g, '')
+ .replace(/\\5c/g, '\\5c5c')
+ .replace(/\\20/g, '\\5c20')
+ .replace(/\\22/g, '\\5c22')
+ .replace(/\\26/g, '\\5c26')
+ .replace(/\\27/g, '\\5c27')
+ .replace(/\\2f/g, '\\5c2f')
+ .replace(/\\3a/g, '\\5c3a')
+ .replace(/\\3c/g, '\\5c3c')
+ .replace(/\\3e/g, '\\5c3e')
+ .replace(/\\40/g, '\\5c40')
+ .replace(/ /g, '\\20')
+ .replace(/\"/g, '\\22')
+ .replace(/\&/g, '\\26')
+ .replace(/\'/g, '\\27')
+ .replace(/\//g, '\\2f')
+ .replace(/:/g, '\\3a')
+ .replace(/</g, '\\3c')
+ .replace(/>/g, '\\3e')
+ .replace(/@/g, '\\40');
+};
+
+exports.unescape = function (val) {
+ return val.replace(/\\20/g, ' ')
+ .replace(/\\22/g, '"')
+ .replace(/\\26/g, '&')
+ .replace(/\\27/g, '\'')
+ .replace(/\\2f/g, '/')
+ .replace(/\\3a/g, ':')
+ .replace(/\\3c/g, '<')
+ .replace(/\\3e/g, '>')
+ .replace(/\\40/g, '@')
+ .replace(/\\5c/g, '\\');
+};
+
+
+exports.create = function (local, domain, resource) {
+ return new exports.JID(local, domain, resource);
+};
+
+exports.JID = function JID(localOrJID, domain, resource) {
+ var parsed = {};
+ if (localOrJID && !domain && !resource) {
+ if (typeof localOrJID === 'string') {
+ parsed = exports.parse(localOrJID);
+ } else if (localOrJID._isJID || localOrJID instanceof exports.JID) {
+ parsed = localOrJID;
+ } else {
+ throw new Error('Invalid argument type');
+ }
+ } else if (domain) {
+ var trusted = ASCII.test(localOrJID) && ASCII.test(domain);
+ if (resource) {
+ trusted = trusted && ASCII.test(resource);
+ }
+
+ parsed = exports.prep({
+ local: exports.escape(localOrJID),
+ domain: domain,
+ resource: resource,
+ prepped: trusted
+ });
+ } else {
+ parsed = {};
+ }
+
+ this._isJID = true;
+
+ this.local = parsed.local || '';
+ this.domain = parsed.domain || '';
+ this.resource = parsed.resource || '';
+ this.bare = parsed.bare || '';
+ this.full = parsed.full || '';
+
+ this.unescapedLocal = parsed.unescapedLocal || '';
+ this.unescapedBare = parsed.unescapedBare || '';
+ this.unescapedFull = parsed.unescapedFull || '';
+
+ this.prepped = parsed.prepped;
+};
+
+exports.JID.prototype.toString = function () {
+ return this.full;
+};
+
+exports.JID.prototype.toJSON = function () {
+ return this.full;
+};
+
+},{"./lib/stringprep":219}],219:[function(require,module,exports){
+'use strict';
+
+var punycode = require('punycode');
+
+
+exports.available = false;
+
+exports.toUnicode = punycode.toUnicode;
+
+exports.nameprep = function (str) {
+ return str.toLowerCase();
+};
+
+exports.nodeprep = function (str) {
+ return str.toLowerCase();
+};
+
+exports.resourceprep = function (str) {
+ return str;
+};
+
+},{"punycode":154}],220:[function(require,module,exports){
/* jshint -W117 */
'use strict';
var JSM = require('jingle');
var RTC = require('webrtc-adapter-test');
+var GUM = require('getusermedia');
+var GSM = require('getscreenmedia');
var jxt = require('jxt').createRegistry();
jxt.use(require('jxt-xmpp-types'));
@@ -23808,11 +31537,15 @@ var IqStanza = jxt.getDefinition('iq', 'jabber:client');
localStream: null,
manager: null,
RTC: null,
+ getUserMedia: null,
+ getScreenMedia: null,
init: function(conn) {
var self = this;
self.RTC = RTC;
+ self.getUserMedia = GUM;
+ self.getScreenMedia = GSM;
self.connection = conn;
@@ -23889,7 +31622,7 @@ var IqStanza = jxt.getDefinition('iq', 'jabber:client');
return true;
},
- initiate: function(peerjid, stream) { // initiate a new jinglesession to peerjid
+ initiate: function(peerjid, stream, offerOptions) { // initiate a new jinglesession to peerjid
var session = this.manager.createMediaSession(peerjid);
session.on('change:connectionState', function(session, state) {
@@ -23903,8 +31636,7 @@ var IqStanza = jxt.getDefinition('iq', 'jabber:client');
// configure session
if (this.localStream) {
session.addStream(this.localStream);
- //TODO: add offer options here, instead of above in the init
- session.start();
+ session.start(offerOptions);
return session;
}
@@ -23933,4 +31665,4 @@ var IqStanza = jxt.getDefinition('iq', 'jabber:client');
});
}(jQuery));
-},{"jingle":29,"jxt":228,"jxt-xmpp":157,"jxt-xmpp-types":125,"webrtc-adapter-test":251}]},{},[252]);
+},{"getscreenmedia":31,"getusermedia":32,"jingle":53,"jxt":120,"jxt-xmpp":81,"jxt-xmpp-types":54,"webrtc-adapter-test":200}]},{},[220]);