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/jsxc.dep.js')
-rw-r--r--build/js/jsxc/lib/jsxc.dep.js37243
1 files changed, 22702 insertions, 14541 deletions
diff --git a/build/js/jsxc/lib/jsxc.dep.js b/build/js/jsxc/lib/jsxc.dep.js
index 7e11153..5c1cd81 100644
--- a/build/js/jsxc/lib/jsxc.dep.js
+++ b/build/js/jsxc/lib/jsxc.dep.js
@@ -1,5 +1,5 @@
/*!
- * jsxc v3.0.1 - 2016-10-28
+ * jsxc v3.1.0-beta - 2017-01-23
*
* This file concatenates all dependencies of jsxc.
*
@@ -10,15 +10,13 @@
* Source: lib/strophe.js/strophe.js, license: multiple, url: http://strophe.im/strophejs/
*/
/** File: strophe.js
- * A JavaScript library for XMPP BOSH/XMPP over Websocket.
+ * A JavaScript library for writing XMPP clients.
*
- * This is the JavaScript version of the Strophe library. Since JavaScript
- * had no facilities for persistent TCP connections, this library uses
- * Bidirectional-streams Over Synchronous HTTP (BOSH) to emulate
- * a persistent, stateful, two-way connection to an XMPP server. More
- * information on BOSH can be found in XEP 124.
+ * This library uses either Bidirectional-streams Over Synchronous HTTP (BOSH)
+ * to emulate a persistent, stateful, two-way connection to an XMPP server or
+ * alternatively WebSockets.
*
- * This version of Strophe also works with WebSockets.
+ * More information on BOSH can be found in XEP 124.
* For more information on XMPP-over WebSocket see this RFC:
* http://tools.ietf.org/html/rfc7395
*/
@@ -132,7 +130,7 @@
* See http://pajhome.org.uk/crypt/md5 for details.
*/
-/* jshint undef: true, unused: true:, noarg: true, latedef: true */
+/* jshint undef: true, unused: true:, noarg: true, latedef: false */
/* global define */
/* Some functions and variables have been stripped for use with Strophe */
@@ -534,6 +532,80 @@ return {
return obj;
}));
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define('strophe-utils', function () {
+ return factory();
+ });
+ } else {
+ // Browser globals
+ root.stropheUtils = factory();
+ }
+}(this, function () {
+
+ var utils = {
+
+ utf16to8: function (str) {
+ var i, c;
+ var out = "";
+ var len = str.length;
+ for (i = 0; i < len; i++) {
+ c = str.charCodeAt(i);
+ if ((c >= 0x0000) && (c <= 0x007F)) {
+ out += str.charAt(i);
+ } else if (c > 0x07FF) {
+ out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
+ out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
+ out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
+ } else {
+ out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
+ out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
+ }
+ }
+ return out;
+ },
+
+ addCookies: function (cookies) {
+ /* Parameters:
+ * (Object) cookies - either a map of cookie names
+ * to string values or to maps of cookie values.
+ *
+ * For example:
+ * { "myCookie": "1234" }
+ *
+ * or:
+ * { "myCookie": {
+ * "value": "1234",
+ * "domain": ".example.org",
+ * "path": "/",
+ * "expires": expirationDate
+ * }
+ * }
+ *
+ * These values get passed to Strophe.Connection via
+ * options.cookies
+ */
+ var cookieName, cookieObj, isObj, cookieValue, expires, domain, path;
+ for (cookieName in (cookies || {})) {
+ expires = '';
+ domain = '';
+ path = '';
+ cookieObj = cookies[cookieName];
+ isObj = typeof cookieObj == "object";
+ cookieValue = escape(unescape(isObj ? cookieObj.value : cookieObj));
+ if (isObj) {
+ expires = cookieObj.expires ? ";expires="+cookieObj.expires : '';
+ domain = cookieObj.domain ? ";domain="+cookieObj.domain : '';
+ path = cookieObj.path ? ";path="+cookieObj.path : '';
+ }
+ document.cookie =
+ cookieName+'='+cookieValue + expires + domain + path;
+ }
+ }
+ };
+ return utils;
+}));
+
/*
This program is distributed under the terms of the MIT license.
Please see the LICENSE file for details.
@@ -542,8 +614,20 @@ return {
*/
/* jshint undef: true, unused: true:, noarg: true, latedef: true */
+/* global define */
-/** PrivateFunction: Function.prototype.bind
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define('strophe-polyfill', [], function () {
+ return factory();
+ });
+ } else {
+ // Browser globals
+ return factory();
+ }
+}(this, function () {
+
+/** Function: Function.prototype.bind
* Bind a function to an instance.
*
* This Function object extension method creates a bound method similar
@@ -565,22 +649,18 @@ return {
* The bound function.
*/
if (!Function.prototype.bind) {
- Function.prototype.bind = function (obj /*, arg1, arg2, ... */)
- {
+ Function.prototype.bind = function (obj /*, arg1, arg2, ... */) {
var func = this;
var _slice = Array.prototype.slice;
var _concat = Array.prototype.concat;
var _args = _slice.call(arguments, 1);
-
return function () {
- return func.apply(obj ? obj : this,
- _concat.call(_args,
- _slice.call(arguments, 0)));
+ return func.apply(obj ? obj : this, _concat.call(_args, _slice.call(arguments, 0)));
};
};
}
-/** PrivateFunction: Array.isArray
+/** Function: Array.isArray
* This is a polyfill for the ES5 Array.isArray method.
*/
if (!Array.isArray) {
@@ -589,7 +669,7 @@ if (!Array.isArray) {
};
}
-/** PrivateFunction: Array.prototype.indexOf
+/** Function: Array.prototype.indexOf
* Return the index of an object in an array.
*
* This function is not supplied by some JavaScript implementations, so
@@ -603,12 +683,9 @@ if (!Array.isArray) {
* Returns:
* The index of elt in the array or -1 if not found.
*/
-if (!Array.prototype.indexOf)
- {
- Array.prototype.indexOf = function(elt /*, from*/)
- {
+if (!Array.prototype.indexOf) {
+ Array.prototype.indexOf = function(elt /*, from*/) {
var len = this.length;
-
var from = Number(arguments[1]) || 0;
from = (from < 0) ? Math.ceil(from) : Math.floor(from);
if (from < 0) {
@@ -620,10 +697,66 @@ if (!Array.prototype.indexOf)
return from;
}
}
-
return -1;
};
}
+}));
+
+
+/** Function: Array.prototype.forEach
+ *
+ * This function is not available in IE < 9
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
+ */
+if (!Array.prototype.forEach) {
+ Array.prototype.forEach = function(callback, thisArg) {
+ var T, k;
+ if (this === null) {
+ throw new TypeError(' this is null or not defined');
+ }
+
+ // 1. Let O be the result of calling toObject() passing the
+ // |this| value as the argument.
+ var O = Object(this);
+ // 2. Let lenValue be the result of calling the Get() internal
+ // method of O with the argument "length".
+ // 3. Let len be toUint32(lenValue).
+ var len = O.length >>> 0;
+ // 4. If isCallable(callback) is false, throw a TypeError exception.
+ // See: http://es5.github.com/#x9.11
+ if (typeof callback !== "function") {
+ throw new TypeError(callback + ' is not a function');
+ }
+ // 5. If thisArg was supplied, let T be thisArg; else let
+ // T be undefined.
+ if (arguments.length > 1) {
+ T = thisArg;
+ }
+ // 6. Let k be 0
+ k = 0;
+ // 7. Repeat, while k < len
+ while (k < len) {
+ var kValue;
+ // a. Let Pk be ToString(k).
+ // This is implicit for LHS operands of the in operator
+ // b. Let kPresent be the result of calling the HasProperty
+ // internal method of O with argument Pk.
+ // This step can be combined with c
+ // c. If kPresent is true, then
+ if (k in O) {
+ // i. Let kValue be the result of calling the Get internal
+ // method of O with argument Pk.
+ kValue = O[k];
+ // ii. Call the Call internal method of callback with T as
+ // the this value and argument list containing kValue, k, and O.
+ callback.call(T, kValue, k, O);
+ }
+ // d. Increase k by 1.
+ k++;
+ }
+ // 8. return undefined
+ };
+}
/*
This program is distributed under the terms of the MIT license.
@@ -633,7 +766,7 @@ if (!Array.prototype.indexOf)
*/
/* jshint undef: true, unused: true:, noarg: true, latedef: true */
-/*global define, document, window, setTimeout, clearTimeout, console, ActiveXObject, DOMParser */
+/*global define, document, window, setTimeout, clearTimeout, ActiveXObject, DOMParser */
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
@@ -641,13 +774,14 @@ if (!Array.prototype.indexOf)
'strophe-sha1',
'strophe-base64',
'strophe-md5',
+ 'strophe-utils',
"strophe-polyfill"
], function () {
return factory.apply(this, arguments);
});
} else {
// Browser globals
- var o = factory(root.SHA1, root.Base64, root.MD5);
+ var o = factory(root.SHA1, root.Base64, root.MD5, root.stropheUtils);
window.Strophe = o.Strophe;
window.$build = o.$build;
window.$iq = o.$iq;
@@ -661,7 +795,7 @@ if (!Array.prototype.indexOf)
window.str_hmac_sha1 = o.SHA1.str_hmac_sha1;
window.str_sha1 = o.SHA1.str_sha1;
}
-}(this, function (SHA1, Base64, MD5) {
+}(this, function (SHA1, Base64, MD5, utils) {
var Strophe;
@@ -723,7 +857,7 @@ Strophe = {
* The version of the Strophe library. Unreleased builds will have
* a version of head-HASH where HASH is a partial revision.
*/
- VERSION: "1.2.3",
+ VERSION: "1.2.9",
/** Constants: XMPP Namespace Constants
* Common namespace constants from the XMPP RFCs and XEPs.
@@ -765,7 +899,6 @@ Strophe = {
XHTML: "http://www.w3.org/1999/xhtml"
},
-
/** Constants: XHTML_IM Namespace
* contains allowed tags, tag attributes, and css properties.
* Used in the createHtml function to filter incoming html into the allowed XHTML-IM subset.
@@ -773,64 +906,63 @@ Strophe = {
* allowed tags and their attributes.
*/
XHTML: {
- tags: ['a','blockquote','br','cite','em','img','li','ol','p','span','strong','ul','body'],
- attributes: {
- 'a': ['href'],
- 'blockquote': ['style'],
- 'br': [],
- 'cite': ['style'],
- 'em': [],
- 'img': ['src', 'alt', 'style', 'height', 'width'],
- 'li': ['style'],
- 'ol': ['style'],
- 'p': ['style'],
- 'span': ['style'],
- 'strong': [],
- 'ul': ['style'],
- 'body': []
- },
- css: ['background-color','color','font-family','font-size','font-style','font-weight','margin-left','margin-right','text-align','text-decoration'],
- /** Function: XHTML.validTag
- *
- * Utility method to determine whether a tag is allowed
- * in the XHTML_IM namespace.
- *
- * XHTML tag names are case sensitive and must be lower case.
- */
- validTag: function(tag) {
- for (var i = 0; i < Strophe.XHTML.tags.length; i++) {
- if (tag == Strophe.XHTML.tags[i]) {
- return true;
- }
- }
- return false;
- },
- /** Function: XHTML.validAttribute
- *
- * Utility method to determine whether an attribute is allowed
- * as recommended per XEP-0071
- *
- * XHTML attribute names are case sensitive and must be lower case.
- */
- validAttribute: function(tag, attribute) {
- if(typeof Strophe.XHTML.attributes[tag] !== 'undefined' && Strophe.XHTML.attributes[tag].length > 0) {
- for(var i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {
- if(attribute == Strophe.XHTML.attributes[tag][i]) {
- return true;
- }
- }
- }
- return false;
- },
- validCSS: function(style)
- {
- for(var i = 0; i < Strophe.XHTML.css.length; i++) {
- if(style == Strophe.XHTML.css[i]) {
- return true;
- }
- }
- return false;
+ tags: ['a','blockquote','br','cite','em','img','li','ol','p','span','strong','ul','body'],
+ attributes: {
+ 'a': ['href'],
+ 'blockquote': ['style'],
+ 'br': [],
+ 'cite': ['style'],
+ 'em': [],
+ 'img': ['src', 'alt', 'style', 'height', 'width'],
+ 'li': ['style'],
+ 'ol': ['style'],
+ 'p': ['style'],
+ 'span': ['style'],
+ 'strong': [],
+ 'ul': ['style'],
+ 'body': []
+ },
+ css: ['background-color','color','font-family','font-size','font-style','font-weight','margin-left','margin-right','text-align','text-decoration'],
+ /** Function: XHTML.validTag
+ *
+ * Utility method to determine whether a tag is allowed
+ * in the XHTML_IM namespace.
+ *
+ * XHTML tag names are case sensitive and must be lower case.
+ */
+ validTag: function(tag) {
+ for (var i = 0; i < Strophe.XHTML.tags.length; i++) {
+ if (tag == Strophe.XHTML.tags[i]) {
+ return true;
+ }
+ }
+ return false;
+ },
+ /** Function: XHTML.validAttribute
+ *
+ * Utility method to determine whether an attribute is allowed
+ * as recommended per XEP-0071
+ *
+ * XHTML attribute names are case sensitive and must be lower case.
+ */
+ validAttribute: function(tag, attribute) {
+ if (typeof Strophe.XHTML.attributes[tag] !== 'undefined' && Strophe.XHTML.attributes[tag].length > 0) {
+ for (var i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {
+ if (attribute == Strophe.XHTML.attributes[tag][i]) {
+ return true;
+ }
+ }
+ }
+ return false;
+ },
+ validCSS: function(style) {
+ for (var i = 0; i < Strophe.XHTML.css.length; i++) {
+ if (style == Strophe.XHTML.css[i]) {
+ return true;
}
+ }
+ return false;
+ }
},
/** Constants: Connection Status Constants
@@ -846,6 +978,7 @@ Strophe = {
* Status.DISCONNECTED - The connection has been terminated
* Status.DISCONNECTING - The connection is currently being terminated
* Status.ATTACHED - The connection has been attached
+ * Status.CONNTIMEOUT - The connection has timed out
*/
Status: {
ERROR: 0,
@@ -857,7 +990,8 @@ Strophe = {
DISCONNECTED: 6,
DISCONNECTING: 7,
ATTACHED: 8,
- REDIRECT: 9
+ REDIRECT: 9,
+ CONNTIMEOUT: 10
},
/** Constants: Log Level Constants
@@ -920,9 +1054,8 @@ Strophe = {
* referenced under Strophe.NS
* (String) value - The actual namespace.
*/
- addNamespace: function (name, value)
- {
- Strophe.NS[name] = value;
+ addNamespace: function (name, value) {
+ Strophe.NS[name] = value;
},
/** Function: forEachChild
@@ -939,10 +1072,8 @@ Strophe = {
* (Function) func - The function to apply to each child. This
* function should take a single argument, a DOM element.
*/
- forEachChild: function (elem, elemName, func)
- {
+ forEachChild: function (elem, elemName, func) {
var i, childNode;
-
for (i = 0; i < elem.childNodes.length; i++) {
childNode = elem.childNodes[i];
if (childNode.nodeType == Strophe.ElementType.NORMAL &&
@@ -965,8 +1096,7 @@ Strophe = {
* true if the element's tag name matches _el_, and false
* otherwise.
*/
- isTagEqual: function (el, name)
- {
+ isTagEqual: function (el, name) {
return el.tagName == name;
},
@@ -982,7 +1112,6 @@ Strophe = {
*/
_makeGenerator: function () {
var doc;
-
// IE9 does implement createDocument(); however, using it will cause the browser to leak memory on page unload.
// Here, we test for presence of createDocument() plus IE's proprietary documentMode attribute, which would be
// less than 10 in the case of IE9 and below.
@@ -994,7 +1123,6 @@ Strophe = {
doc = document.implementation
.createDocument('jabber:client', 'strophe', null);
}
-
return doc;
},
@@ -1042,7 +1170,6 @@ Strophe = {
break;
}
}
-
return doc;
},
@@ -1064,12 +1191,10 @@ Strophe = {
* Returns:
* A new XML DOM element.
*/
- xmlElement: function (name)
- {
+ xmlElement: function (name) {
if (!name) { return null; }
var node = Strophe.xmlGenerator().createElement(name);
-
// FIXME: this should throw errors if args are the wrong type or
// there are more than two optional args
var a, i, k;
@@ -1114,8 +1239,7 @@ Strophe = {
* Returns:
* Escaped text.
*/
- xmlescape: function(text)
- {
+ xmlescape: function(text) {
text = text.replace(/\&/g, "&amp;");
text = text.replace(/</g, "&lt;");
text = text.replace(/>/g, "&gt;");
@@ -1133,8 +1257,7 @@ Strophe = {
* Returns:
* Unescaped text.
*/
- xmlunescape: function(text)
- {
+ xmlunescape: function(text) {
text = text.replace(/\&amp;/g, "&");
text = text.replace(/&lt;/g, "<");
text = text.replace(/&gt;/g, ">");
@@ -1154,8 +1277,7 @@ Strophe = {
* Returns:
* A new XML DOM text node.
*/
- xmlTextNode: function (text)
- {
+ xmlTextNode: function (text) {
return Strophe.xmlGenerator().createTextNode(text);
},
@@ -1168,8 +1290,7 @@ Strophe = {
* Returns:
* A new XML DOM text node.
*/
- xmlHtmlNode: function (html)
- {
+ xmlHtmlNode: function (html) {
var node;
//ensure text is escaped
if (window.DOMParser) {
@@ -1192,8 +1313,7 @@ Strophe = {
* Returns:
* A String with the concatenated text of all text element children.
*/
- getText: function (elem)
- {
+ getText: function (elem) {
if (!elem) { return null; }
var str = "";
@@ -1223,8 +1343,7 @@ Strophe = {
* Returns:
* A new, copied DOM element tree.
*/
- copyElement: function (elem)
- {
+ copyElement: function (elem) {
var i, el;
if (elem.nodeType == Strophe.ElementType.NORMAL) {
el = Strophe.xmlElement(elem.tagName);
@@ -1240,7 +1359,6 @@ Strophe = {
} else if (elem.nodeType == Strophe.ElementType.TEXT) {
el = Strophe.xmlGenerator().createTextNode(elem.nodeValue);
}
-
return el;
},
@@ -1257,8 +1375,7 @@ Strophe = {
* Returns:
* A new, copied DOM element tree.
*/
- createHtml: function (elem)
- {
+ createHtml: function (elem) {
var i, el, j, tag, attribute, value, css, cssAttrs, attr, cssName, cssValue;
if (elem.nodeType == Strophe.ElementType.NORMAL) {
tag = elem.nodeName.toLowerCase(); // XHTML tags must be lower case.
@@ -1317,7 +1434,6 @@ Strophe = {
} else if (elem.nodeType == Strophe.ElementType.TEXT) {
el = Strophe.xmlTextNode(elem.nodeValue);
}
-
return el;
},
@@ -1330,8 +1446,7 @@ Strophe = {
* Returns:
* An escaped node (or local part).
*/
- escapeNode: function (node)
- {
+ escapeNode: function (node) {
if (typeof node !== "string") { return node; }
return node.replace(/^\s+|\s+$/g, '')
.replace(/\\/g, "\\5c")
@@ -1355,8 +1470,7 @@ Strophe = {
* Returns:
* An unescaped node (or local part).
*/
- unescapeNode: function (node)
- {
+ unescapeNode: function (node) {
if (typeof node !== "string") { return node; }
return node.replace(/\\20/g, " ")
.replace(/\\22/g, '"')
@@ -1379,8 +1493,7 @@ Strophe = {
* Returns:
* A String containing the node.
*/
- getNodeFromJid: function (jid)
- {
+ getNodeFromJid: function (jid) {
if (jid.indexOf("@") < 0) { return null; }
return jid.split("@")[0];
},
@@ -1394,8 +1507,7 @@ Strophe = {
* Returns:
* A String containing the domain.
*/
- getDomainFromJid: function (jid)
- {
+ getDomainFromJid: function (jid) {
var bare = Strophe.getBareJidFromJid(jid);
if (bare.indexOf("@") < 0) {
return bare;
@@ -1415,8 +1527,7 @@ Strophe = {
* Returns:
* A String containing the resource.
*/
- getResourceFromJid: function (jid)
- {
+ getResourceFromJid: function (jid) {
var s = jid.split("/");
if (s.length < 2) { return null; }
s.splice(0, 1);
@@ -1432,11 +1543,29 @@ Strophe = {
* Returns:
* A String containing the bare JID.
*/
- getBareJidFromJid: function (jid)
- {
+ getBareJidFromJid: function (jid) {
return jid ? jid.split("/")[0] : null;
},
+ /** PrivateFunction: _handleError
+ * _Private_ function that properly logs an error to the console
+ */
+ _handleError: function (e) {
+ if (typeof e.stack !== "undefined") {
+ Strophe.fatal(e.stack);
+ }
+ if (e.sourceURL) {
+ Strophe.fatal("error: " + this.handler + " " + e.sourceURL + ":" +
+ e.line + " - " + e.name + ": " + e.message);
+ } else if (e.fileName) {
+ Strophe.fatal("error: " + this.handler + " " +
+ e.fileName + ":" + e.lineNumber + " - " +
+ e.name + ": " + e.message);
+ } else {
+ Strophe.fatal("error: " + e.message);
+ }
+ },
+
/** Function: log
* User overrideable logging function.
*
@@ -1467,8 +1596,7 @@ Strophe = {
* (String) msg - The log message.
*/
/* jshint ignore:start */
- log: function (level, msg)
- {
+ log: function (level, msg) {
return;
},
/* jshint ignore:end */
@@ -1479,8 +1607,7 @@ Strophe = {
* Parameters:
* (String) msg - The log message.
*/
- debug: function(msg)
- {
+ debug: function(msg) {
this.log(this.LogLevel.DEBUG, msg);
},
@@ -1490,8 +1617,7 @@ Strophe = {
* Parameters:
* (String) msg - The log message.
*/
- info: function (msg)
- {
+ info: function (msg) {
this.log(this.LogLevel.INFO, msg);
},
@@ -1501,8 +1627,7 @@ Strophe = {
* Parameters:
* (String) msg - The log message.
*/
- warn: function (msg)
- {
+ warn: function (msg) {
this.log(this.LogLevel.WARN, msg);
},
@@ -1512,8 +1637,7 @@ Strophe = {
* Parameters:
* (String) msg - The log message.
*/
- error: function (msg)
- {
+ error: function (msg) {
this.log(this.LogLevel.ERROR, msg);
},
@@ -1523,8 +1647,7 @@ Strophe = {
* Parameters:
* (String) msg - The log message.
*/
- fatal: function (msg)
- {
+ fatal: function (msg) {
this.log(this.LogLevel.FATAL, msg);
},
@@ -1537,8 +1660,7 @@ Strophe = {
* Returns:
* The serialized element tree as a String.
*/
- serialize: function (elem)
- {
+ serialize: function (elem) {
var result;
if (!elem) { return null; }
@@ -1556,14 +1678,10 @@ Strophe = {
result = "<" + nodeName;
for (i = 0; i < elem.attributes.length; i++) {
- if(elem.attributes[i].nodeName != "_realname") {
- result += " " + elem.attributes[i].nodeName +
- "='" + elem.attributes[i].value
- .replace(/&/g, "&amp;")
- .replace(/\'/g, "&apos;")
- .replace(/>/g, "&gt;")
- .replace(/</g, "&lt;") + "'";
- }
+ if(elem.attributes[i].nodeName != "_realname") {
+ result += " " + elem.attributes[i].nodeName +
+ "='" + Strophe.xmlescape(elem.attributes[i].value) + "'";
+ }
}
if (elem.childNodes.length > 0) {
@@ -1611,8 +1729,7 @@ Strophe = {
* (String) name - The name of the extension.
* (Object) ptype - The plugin's prototype.
*/
- addConnectionPlugin: function (name, ptype)
- {
+ addConnectionPlugin: function (name, ptype) {
Strophe._connectionPlugins[name] = ptype;
}
};
@@ -1628,6 +1745,7 @@ Strophe = {
* > .c('query', {xmlns: 'strophe:example'})
* > .c('example')
* > .toString()
+ *
* The above generates this XML fragment
* > <iq to='you' from='me' type='get' id='1'>
* > <query xmlns='strophe:example'>
@@ -1658,8 +1776,7 @@ Strophe = {
* Returns:
* A new Strophe.Builder.
*/
-Strophe.Builder = function (name, attrs)
-{
+Strophe.Builder = function (name, attrs) {
// Set correct namespace for jabber:client elements
if (name == "presence" || name == "message" || name == "iq") {
if (attrs && !attrs.xmlns) {
@@ -1686,8 +1803,7 @@ Strophe.Builder.prototype = {
* Returns:
* The DOM tree as a element object.
*/
- tree: function ()
- {
+ tree: function () {
return this.nodeTree;
},
@@ -1701,8 +1817,7 @@ Strophe.Builder.prototype = {
* Returns:
* The serialized DOM tree in a String.
*/
- toString: function ()
- {
+ toString: function () {
return Strophe.serialize(this.nodeTree);
},
@@ -1716,12 +1831,26 @@ Strophe.Builder.prototype = {
* Returns:
* The Stophe.Builder object.
*/
- up: function ()
- {
+ up: function () {
this.node = this.node.parentNode;
return this;
},
+ /** Function: root
+ * Make the root element the new current element.
+ *
+ * When at a deeply nested element in the tree, this function can be used
+ * to jump back to the root of the tree, instead of having to repeatedly
+ * call up().
+ *
+ * Returns:
+ * The Stophe.Builder object.
+ */
+ root: function () {
+ this.node = this.nodeTree;
+ return this;
+ },
+
/** Function: attrs
* Add or modify attributes of the current element.
*
@@ -1734,8 +1863,7 @@ Strophe.Builder.prototype = {
* Returns:
* The Strophe.Builder object.
*/
- attrs: function (moreattrs)
- {
+ attrs: function (moreattrs) {
for (var k in moreattrs) {
if (moreattrs.hasOwnProperty(k)) {
if (moreattrs[k] === undefined) {
@@ -1764,11 +1892,10 @@ Strophe.Builder.prototype = {
* Returns:
* The Strophe.Builder object.
*/
- c: function (name, attrs, text)
- {
+ c: function (name, attrs, text) {
var child = Strophe.xmlElement(name, attrs, text);
this.node.appendChild(child);
- if (typeof text !== "string") {
+ if (typeof text !== "string" && typeof text !=="number") {
this.node = child;
}
return this;
@@ -1788,14 +1915,12 @@ Strophe.Builder.prototype = {
* Returns:
* The Strophe.Builder object.
*/
- cnode: function (elem)
- {
+ cnode: function (elem) {
var impNode;
var xmlGen = Strophe.xmlGenerator();
try {
impNode = (xmlGen.importNode !== undefined);
- }
- catch (e) {
+ } catch (e) {
impNode = false;
}
var newElem = impNode ?
@@ -1818,8 +1943,7 @@ Strophe.Builder.prototype = {
* Returns:
* The Strophe.Builder object.
*/
- t: function (text)
- {
+ t: function (text) {
var child = Strophe.xmlTextNode(text);
this.node.appendChild(child);
return this;
@@ -1836,8 +1960,7 @@ Strophe.Builder.prototype = {
* Returns:
* The Strophe.Builder object.
*/
- h: function (html)
- {
+ h: function (html) {
var fragment = document.createElement('body');
// force the browser to try and fix any invalid HTML tags
@@ -1882,74 +2005,96 @@ Strophe.Builder.prototype = {
* Returns:
* A new Strophe.Handler object.
*/
-Strophe.Handler = function (handler, ns, name, type, id, from, options)
-{
+Strophe.Handler = function (handler, ns, name, type, id, from, options) {
this.handler = handler;
this.ns = ns;
this.name = name;
this.type = type;
this.id = id;
- this.options = options || {matchBare: false};
-
- // default matchBare to false if undefined
- if (!this.options.matchBare) {
- this.options.matchBare = false;
+ this.options = options || {'matchBareFromJid': false, 'ignoreNamespaceFragment': false};
+ // BBB: Maintain backward compatibility with old `matchBare` option
+ if (this.options.matchBare) {
+ Strophe.warn('The "matchBare" option is deprecated, use "matchBareFromJid" instead.');
+ this.options.matchBareFromJid = this.options.matchBare;
+ delete this.options.matchBare;
}
- if (this.options.matchBare) {
+ if (this.options.matchBareFromJid) {
this.from = from ? Strophe.getBareJidFromJid(from) : null;
} else {
this.from = from;
}
-
// whether the handler is a user handler or a system handler
this.user = true;
};
Strophe.Handler.prototype = {
- /** PrivateFunction: isMatch
- * Tests if a stanza matches the Strophe.Handler.
+ /** PrivateFunction: getNamespace
+ * Returns the XML namespace attribute on an element.
+ * If `ignoreNamespaceFragment` was passed in for this handler, then the
+ * URL fragment will be stripped.
*
* Parameters:
- * (XMLElement) elem - The XML element to test.
+ * (XMLElement) elem - The XML element with the namespace.
*
* Returns:
- * true if the stanza matches and false otherwise.
+ * The namespace, with optionally the fragment stripped.
*/
- isMatch: function (elem)
- {
- var nsMatch;
- var from = null;
-
- if (this.options.matchBare) {
- from = Strophe.getBareJidFromJid(elem.getAttribute('from'));
- } else {
- from = elem.getAttribute('from');
+ getNamespace: function (elem) {
+ var elNamespace = elem.getAttribute("xmlns");
+ if (elNamespace && this.options.ignoreNamespaceFragment) {
+ elNamespace = elNamespace.split('#')[0];
}
+ return elNamespace;
+ },
- nsMatch = false;
+ /** PrivateFunction: namespaceMatch
+ * Tests if a stanza matches the namespace set for this Strophe.Handler.
+ *
+ * Parameters:
+ * (XMLElement) elem - The XML element to test.
+ *
+ * Returns:
+ * true if the stanza matches and false otherwise.
+ */
+ namespaceMatch: function (elem) {
+ var nsMatch = false;
if (!this.ns) {
- nsMatch = true;
+ return true;
} else {
var that = this;
Strophe.forEachChild(elem, null, function (elem) {
- if (elem.getAttribute("xmlns") == that.ns) {
+ if (that.getNamespace(elem) === that.ns) {
nsMatch = true;
}
});
-
- nsMatch = nsMatch || elem.getAttribute("xmlns") == this.ns;
+ nsMatch = nsMatch || this.getNamespace(elem) === this.ns;
}
+ return nsMatch;
+ },
+ /** PrivateFunction: isMatch
+ * Tests if a stanza matches the Strophe.Handler.
+ *
+ * Parameters:
+ * (XMLElement) elem - The XML element to test.
+ *
+ * Returns:
+ * true if the stanza matches and false otherwise.
+ */
+ isMatch: function (elem) {
+ var from = elem.getAttribute('from');
+ if (this.options.matchBareFromJid) {
+ from = Strophe.getBareJidFromJid(from);
+ }
var elem_type = elem.getAttribute("type");
- if (nsMatch &&
+ if (this.namespaceMatch(elem) &&
(!this.name || Strophe.isTagEqual(elem, this.name)) &&
(!this.type || (Array.isArray(this.type) ? this.type.indexOf(elem_type) != -1 : elem_type == this.type)) &&
(!this.id || elem.getAttribute("id") == this.id) &&
(!this.from || from == this.from)) {
return true;
}
-
return false;
},
@@ -1963,31 +2108,14 @@ Strophe.Handler.prototype = {
* Returns:
* A boolean indicating if the handler should remain active.
*/
- run: function (elem)
- {
+ run: function (elem) {
var result = null;
try {
result = this.handler(elem);
} catch (e) {
- if (e.sourceURL) {
- Strophe.fatal("error: " + this.handler +
- " " + e.sourceURL + ":" +
- e.line + " - " + e.name + ": " + e.message);
- } else if (e.fileName) {
- if (typeof(console) != "undefined") {
- console.trace();
- console.error(this.handler, " - error - ", e, e.message);
- }
- Strophe.fatal("error: " + this.handler + " " +
- e.fileName + ":" + e.lineNumber + " - " +
- e.name + ": " + e.message);
- } else {
- Strophe.fatal("error: " + e.message + "\n" + e.stack);
- }
-
+ Strophe._handleError(e);
throw e;
}
-
return result;
},
@@ -1997,8 +2125,7 @@ Strophe.Handler.prototype = {
* Returns:
* A String.
*/
- toString: function ()
- {
+ toString: function () {
return "{Handler: " + this.handler + "(" + this.name + "," +
this.id + "," + this.ns + ")}";
}
@@ -2029,11 +2156,9 @@ Strophe.Handler.prototype = {
* Returns:
* A new Strophe.TimedHandler object.
*/
-Strophe.TimedHandler = function (period, handler)
-{
+Strophe.TimedHandler = function (period, handler) {
this.period = period;
this.handler = handler;
-
this.lastCalled = new Date().getTime();
this.user = true;
};
@@ -2046,8 +2171,7 @@ Strophe.TimedHandler.prototype = {
* true if the Strophe.TimedHandler should be called again, and false
* otherwise.
*/
- run: function ()
- {
+ run: function () {
this.lastCalled = new Date().getTime();
return this.handler();
},
@@ -2055,8 +2179,7 @@ Strophe.TimedHandler.prototype = {
/** PrivateFunction: reset
* Reset the last called time for the Strophe.TimedHandler.
*/
- reset: function ()
- {
+ reset: function () {
this.lastCalled = new Date().getTime();
},
@@ -2066,8 +2189,7 @@ Strophe.TimedHandler.prototype = {
* Returns:
* The string representation.
*/
- toString: function ()
- {
+ toString: function () {
return "{TimedHandler: " + this.handler + "(" + this.period +")}";
}
};
@@ -2107,7 +2229,53 @@ Strophe.TimedHandler.prototype = {
*
* > var conn = new Strophe.Connection("/http-bind/");
*
+ * Options common to both Websocket and BOSH:
+ * ------------------------------------------
+ *
+ * cookies
+ * ~~~~~~~
+ *
+ * The "cookies" option allows you to pass in cookies to be added to the
+ * document. These cookies will then be included in the BOSH XMLHttpRequest
+ * or in the websocket connection.
+ *
+ * The passed in value must be a map of cookie names and string values:
+ *
+ * > { "myCookie": {
+ * > "value": "1234",
+ * > "domain": ".example.org",
+ * > "path": "/",
+ * > "expires": expirationDate
+ * > }
+ * > }
+ *
+ * Note that cookies can't be set in this way for other domains (i.e. cross-domain).
+ * Those cookies need to be set under those domains, for example they can be
+ * set server-side by making a XHR call to that domain to ask it to set any
+ * necessary cookies.
+ *
+ * mechanisms
+ * ~~~~~~~~~~
+ *
+ * The "mechanisms" option allows you to specify the SASL mechanisms that this
+ * instance of Strophe.Connection (and therefore your XMPP client) will
+ * support.
+ *
+ * The value must be an array of objects with Strophe.SASLMechanism
+ * prototypes.
+ *
+ * If nothing is specified, then the following mechanisms (and their
+ * priorities) are registered:
+ *
+ * EXTERNAL - 60
+ * OAUTHBEARER - 50
+ * SCRAM-SHA1 - 40
+ * DIGEST-MD5 - 30
+ * PLAIN - 20
+ * ANONYMOUS - 10
+ *
* WebSocket options:
+ * ------------------
*
* If you want to connect to the current host with a WebSocket connection you
* can tell Strophe to use WebSockets through a "protocol" attribute in the
@@ -2125,6 +2293,7 @@ Strophe.TimedHandler.prototype = {
* variants if the current connection to the site is also secure (https).
*
* BOSH options:
+ * -------------
*
* By adding "sync" to the options, you can control if requests will
* be made synchronously or not. The default behaviour is asynchronous.
@@ -2144,6 +2313,23 @@ Strophe.TimedHandler.prototype = {
* "restore" is called it will check whether there are cached tokens with
* which it can resume an existing session.
*
+ * The "withCredentials" option should receive a Boolean value and is used to
+ * indicate wether cookies should be included in ajax requests (by default
+ * they're not).
+ * Set this value to true if you are connecting to a BOSH service
+ * and for some reason need to send cookies to it.
+ * In order for this to work cross-domain, the server must also enable
+ * credentials by setting the Access-Control-Allow-Credentials response header
+ * to "true". For most usecases however this setting should be false (which
+ * is the default).
+ * Additionally, when using Access-Control-Allow-Credentials, the
+ * Access-Control-Allow-Origin header can't be set to the wildcard "*", but
+ * instead must be restricted to actual domains.
+ *
+ * The "contentType" option can be set to change the default Content-Type
+ * of "text/xml; charset=utf-8", which can be useful to reduce the amount of
+ * CORS preflight requests that are sent to the server.
+ *
* Parameters:
* (String) service - The BOSH or WebSocket service URL.
* (Object) options - A hash of configuration options
@@ -2151,11 +2337,9 @@ Strophe.TimedHandler.prototype = {
* Returns:
* A new Strophe.Connection object.
*/
-Strophe.Connection = function (service, options)
-{
+Strophe.Connection = function (service, options) {
// The service URL
this.service = service;
-
// Configuration options
this.options = options || {};
var proto = this.options.protocol || "";
@@ -2187,8 +2371,11 @@ Strophe.Connection = function (service, options)
this.removeHandlers = [];
this.addTimeds = [];
this.addHandlers = [];
+ this.protocolErrorHandlers = {
+ 'HTTP': {},
+ 'websocket': {}
+ };
- this._authentication = {};
this._idleTimeout = null;
this._disconnectTimeout = null;
@@ -2209,8 +2396,14 @@ Strophe.Connection = function (service, options)
// Max retries before disconnecting
this.maxRetries = 5;
- // setup onIdle callback every 1/10th of a second
- this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
+ // Call onIdle callback every 1/10th of a second
+ // XXX: setTimeout should be called only with function expressions (23974bc1)
+ this._idleTimeout = setTimeout(function() {
+ this._onIdle();
+ }.bind(this), 100);
+
+ utils.addCookies(this.options.cookies);
+ this.registerSASLMechanisms(this.options.mechanisms);
// initialize plugins
for (var k in Strophe._connectionPlugins) {
@@ -2232,8 +2425,7 @@ Strophe.Connection.prototype = {
* This function should be called after a connection is disconnected
* before that connection is reused.
*/
- reset: function ()
- {
+ reset: function () {
this._proto._reset();
// SASL
@@ -2247,7 +2439,6 @@ Strophe.Connection.prototype = {
this.removeHandlers = [];
this.addTimeds = [];
this.addHandlers = [];
- this._authentication = {};
this.authenticated = false;
this.connected = false;
@@ -2268,8 +2459,7 @@ Strophe.Connection.prototype = {
* This causes Strophe to send the data in a single request, saving
* many request trips.
*/
- pause: function ()
- {
+ pause: function () {
this.paused = true;
},
@@ -2278,8 +2468,7 @@ Strophe.Connection.prototype = {
*
* This resumes after pause() has been called.
*/
- resume: function ()
- {
+ resume: function () {
this.paused = false;
},
@@ -2318,6 +2507,33 @@ Strophe.Connection.prototype = {
}
},
+ /** Function: addProtocolErrorHandler
+ * Register a handler function for when a protocol (websocker or HTTP)
+ * error occurs.
+ *
+ * NOTE: Currently only HTTP errors for BOSH requests are handled.
+ * Patches that handle websocket errors would be very welcome.
+ *
+ * Parameters:
+ * (String) protocol - 'HTTP' or 'websocket'
+ * (Integer) status_code - Error status code (e.g 500, 400 or 404)
+ * (Function) callback - Function that will fire on Http error
+ *
+ * Example:
+ * function onError(err_code){
+ * //do stuff
+ * }
+ *
+ * var conn = Strophe.connect('http://example.com/http-bind');
+ * conn.addProtocolErrorHandler('HTTP', 500, onError);
+ * // Triggers HTTP 500 error and onError handler will be called
+ * conn.connect('user_jid@incorrect_jabber_host', 'secret', onConnect);
+ */
+ addProtocolErrorHandler: function(protocol, status_code, callback){
+ this.protocolErrorHandlers[protocol][status_code] = callback;
+ },
+
+
/** Function: connect
* Starts the connection process.
*
@@ -2348,26 +2564,37 @@ Strophe.Connection.prototype = {
* (String) route - The optional route value.
* (String) authcid - The optional alternative authentication identity
* (username) if intending to impersonate another user.
+ * When using the SASL-EXTERNAL authentication mechanism, for example
+ * with client certificates, then the authcid value is used to
+ * determine whether an authorization JID (authzid) should be sent to
+ * the server. The authzid should not be sent to the server if the
+ * authzid and authcid are the same. So to prevent it from being sent
+ * (for example when the JID is already contained in the client
+ * certificate), set authcid to that same JID. See XEP-178 for more
+ * details.
*/
- connect: function (jid, pass, callback, wait, hold, route, authcid)
- {
+ connect: function (jid, pass, callback, wait, hold, route, authcid) {
this.jid = jid;
/** Variable: authzid
* Authorization identity.
*/
this.authzid = Strophe.getBareJidFromJid(this.jid);
+
/** Variable: authcid
* Authentication identity (User name).
*/
this.authcid = authcid || Strophe.getNodeFromJid(this.jid);
+
/** Variable: pass
* Authentication identity (User password).
*/
this.pass = pass;
+
/** Variable: servtype
* Digest MD5 compatibility.
*/
this.servtype = "xmpp";
+
this.connect_callback = callback;
this.disconnecting = false;
this.connected = false;
@@ -2406,8 +2633,7 @@ Strophe.Connection.prototype = {
* (Integer) wind - The optional HTTBIND window value. This is the
* allowed range of request ids that are valid. The default is 5.
*/
- attach: function (jid, sid, rid, callback, wait, hold, wind)
- {
+ attach: function (jid, sid, rid, callback, wait, hold, wind) {
if (this._proto instanceof Strophe.Bosh) {
this._proto._attach(jid, sid, rid, callback, wait, hold, wind);
} else {
@@ -2445,8 +2671,7 @@ Strophe.Connection.prototype = {
* (Integer) wind - The optional HTTBIND window value. This is the
* allowed range of request ids that are valid. The default is 5.
*/
- restore: function (jid, callback, wait, hold, wind)
- {
+ restore: function (jid, callback, wait, hold, wind) {
if (this._sessionCachingSupported()) {
this._proto._restore(jid, callback, wait, hold, wind);
} else {
@@ -2461,8 +2686,7 @@ Strophe.Connection.prototype = {
* Checks whether sessionStorage and JSON are supported and whether we're
* using BOSH.
*/
- _sessionCachingSupported: function ()
- {
+ _sessionCachingSupported: function () {
if (this._proto instanceof Strophe.Bosh) {
if (!JSON) { return false; }
try {
@@ -2495,8 +2719,7 @@ Strophe.Connection.prototype = {
* (XMLElement) elem - The XML data received by the connection.
*/
/* jshint unused:false */
- xmlInput: function (elem)
- {
+ xmlInput: function (elem) {
return;
},
/* jshint unused:true */
@@ -2520,8 +2743,7 @@ Strophe.Connection.prototype = {
* (XMLElement) elem - The XMLdata sent by the connection.
*/
/* jshint unused:false */
- xmlOutput: function (elem)
- {
+ xmlOutput: function (elem) {
return;
},
/* jshint unused:true */
@@ -2539,8 +2761,7 @@ Strophe.Connection.prototype = {
* (String) data - The data received by the connection.
*/
/* jshint unused:false */
- rawInput: function (data)
- {
+ rawInput: function (data) {
return;
},
/* jshint unused:true */
@@ -2558,8 +2779,7 @@ Strophe.Connection.prototype = {
* (String) data - The data sent by the connection.
*/
/* jshint unused:false */
- rawOutput: function (data)
- {
+ rawOutput: function (data) {
return;
},
/* jshint unused:true */
@@ -2576,8 +2796,7 @@ Strophe.Connection.prototype = {
* (Number) rid - The next valid rid
*/
/* jshint unused:false */
- nextValidRid: function (rid)
- {
+ nextValidRid: function (rid) {
return;
},
/* jshint unused:true */
@@ -2594,8 +2813,7 @@ Strophe.Connection.prototype = {
* [XMLElement] |
* Strophe.Builder) elem - The stanza to send.
*/
- send: function (elem)
- {
+ send: function (elem) {
if (elem === null) { return ; }
if (typeof(elem.sort) === "function") {
for (var i = 0; i < elem.length; i++) {
@@ -2618,8 +2836,7 @@ Strophe.Connection.prototype = {
* several send()s are called in succession. flush() can be used to
* immediately send all pending data.
*/
- flush: function ()
- {
+ flush: function () {
// cancel the pending idle period and run the idle function
// immediately
clearTimeout(this._idleTimeout);
@@ -2648,40 +2865,16 @@ Strophe.Connection.prototype = {
elem = elem.tree();
}
var id = elem.getAttribute('id');
-
- // inject id if not found
- if (!id) {
+ if (!id) { // inject id if not found
id = this.getUniqueId("sendIQ");
elem.setAttribute("id", id);
}
- var expectedFrom = elem.getAttribute("to");
- var fulljid = this.jid;
-
var handler = this.addHandler(function (stanza) {
// remove timeout handler if there is one
if (timeoutHandler) {
that.deleteTimedHandler(timeoutHandler);
}
-
- var acceptable = false;
- var from = stanza.getAttribute("from");
- if (from === expectedFrom ||
- (expectedFrom === null &&
- (from === Strophe.getBareJidFromJid(fulljid) ||
- from === Strophe.getDomainFromJid(fulljid) ||
- from === fulljid))) {
- acceptable = true;
- }
-
- if (!acceptable) {
- throw {
- name: "StropheError",
- message: "Got answer to IQ from wrong jid:" + from +
- "\nExpected jid: " + expectedFrom
- };
- }
-
var iqtype = stanza.getAttribute('type');
if (iqtype == 'result') {
if (callback) {
@@ -2699,7 +2892,7 @@ Strophe.Connection.prototype = {
}
}, null, 'iq', ['error', 'result'], id);
- // if timeout specified, setup timeout handler.
+ // if timeout specified, set up a timeout handler.
if (timeout) {
timeoutHandler = this.addTimedHandler(timeout, function () {
// get rid of normal handler
@@ -2728,20 +2921,19 @@ Strophe.Connection.prototype = {
message: "Cannot queue non-DOMElement."
};
}
-
this._data.push(element);
},
/** PrivateFunction: _sendRestart
* Send an xmpp:restart stanza.
*/
- _sendRestart: function ()
- {
+ _sendRestart: function () {
this._data.push("restart");
-
this._proto._sendRestart();
-
- this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
+ // XXX: setTimeout should be called only with function expressions (23974bc1)
+ this._idleTimeout = setTimeout(function() {
+ this._onIdle();
+ }.bind(this), 100);
},
/** Function: addTimedHandler
@@ -2766,8 +2958,7 @@ Strophe.Connection.prototype = {
* Returns:
* A reference to the handler that can be used to remove it.
*/
- addTimedHandler: function (period, handler)
- {
+ addTimedHandler: function (period, handler) {
var thand = new Strophe.TimedHandler(period, handler);
this.addTimeds.push(thand);
return thand;
@@ -2783,8 +2974,7 @@ Strophe.Connection.prototype = {
* Parameters:
* (Strophe.TimedHandler) handRef - The handler reference.
*/
- deleteTimedHandler: function (handRef)
- {
+ deleteTimedHandler: function (handRef) {
// this must be done in the Idle loop so that we don't change
// the handlers during iteration
this.removeTimeds.push(handRef);
@@ -2806,13 +2996,39 @@ Strophe.Connection.prototype = {
* and also any of its immediate children. This is primarily to make
* matching /iq/query elements easy.
*
- * The options argument contains handler matching flags that affect how
- * matches are determined. Currently the only flag is matchBare (a
- * boolean). When matchBare is true, the from parameter and the from
- * attribute on the stanza will be matched as bare JIDs instead of
- * full JIDs. To use this, pass {matchBare: true} as the value of
- * options. The default value for matchBare is false.
+ * Options
+ * ~~~~~~~
+ * With the options argument, you can specify boolean flags that affect how
+ * matches are being done.
+ *
+ * Currently two flags exist:
+ *
+ * - matchBareFromJid:
+ * When set to true, the from parameter and the
+ * from attribute on the stanza will be matched as bare JIDs instead
+ * of full JIDs. To use this, pass {matchBareFromJid: true} as the
+ * value of options. The default value for matchBareFromJid is false.
+ *
+ * - ignoreNamespaceFragment:
+ * When set to true, a fragment specified on the stanza's namespace
+ * URL will be ignored when it's matched with the one configured for
+ * the handler.
+ *
+ * This means that if you register like this:
+ * > connection.addHandler(
+ * > handler,
+ * > 'http://jabber.org/protocol/muc',
+ * > null, null, null, null,
+ * > {'ignoreNamespaceFragment': true}
+ * > );
+ *
+ * Then a stanza with XML namespace of
+ * 'http://jabber.org/protocol/muc#user' will also be matched. If
+ * 'ignoreNamespaceFragment' is false, then only stanzas with
+ * 'http://jabber.org/protocol/muc' will be matched.
*
+ * Deleting the handler
+ * ~~~~~~~~~~~~~~~~~~~~
* The return value should be saved if you wish to remove the handler
* with deleteHandler().
*
@@ -2820,7 +3036,7 @@ Strophe.Connection.prototype = {
* (Function) handler - The user callback.
* (String) ns - The namespace to match.
* (String) name - The stanza name to match.
- * (String) type - The stanza type attribute to match.
+ * (String|Array) type - The stanza type (or types if an array) to match.
* (String) id - The stanza id attribute to match.
* (String) from - The stanza from attribute to match.
* (String) options - The handler options
@@ -2828,8 +3044,7 @@ Strophe.Connection.prototype = {
* Returns:
* A reference to the handler that can be used to remove it.
*/
- addHandler: function (handler, ns, name, type, id, from, options)
- {
+ addHandler: function (handler, ns, name, type, id, from, options) {
var hand = new Strophe.Handler(handler, ns, name, type, id, from, options);
this.addHandlers.push(hand);
return hand;
@@ -2845,8 +3060,7 @@ Strophe.Connection.prototype = {
* Parameters:
* (Strophe.Handler) handRef - The handler reference.
*/
- deleteHandler: function (handRef)
- {
+ deleteHandler: function (handRef) {
// this must be done in the Idle loop so that we don't change
// the handlers during iteration
this.removeHandlers.push(handRef);
@@ -2858,6 +3072,40 @@ Strophe.Connection.prototype = {
}
},
+ /** Function: registerSASLMechanisms
+ *
+ * Register the SASL mechanisms which will be supported by this instance of
+ * Strophe.Connection (i.e. which this XMPP client will support).
+ *
+ * Parameters:
+ * (Array) mechanisms - Array of objects with Strophe.SASLMechanism prototypes
+ *
+ */
+ registerSASLMechanisms: function (mechanisms) {
+ this.mechanisms = {};
+ mechanisms = mechanisms || [
+ Strophe.SASLAnonymous,
+ Strophe.SASLExternal,
+ Strophe.SASLMD5,
+ Strophe.SASLOAuthBearer,
+ Strophe.SASLPlain,
+ Strophe.SASLSHA1
+ ];
+ mechanisms.forEach(this.registerSASLMechanism.bind(this));
+ },
+
+ /** Function: registerSASLMechanism
+ *
+ * Register a single SASL mechanism, to be supported by this client.
+ *
+ * Parameters:
+ * (Object) mechanism - Object with a Strophe.SASLMechanism prototype
+ *
+ */
+ registerSASLMechanism: function (mechanism) {
+ this.mechanisms[mechanism.prototype.name] = mechanism;
+ },
+
/** Function: disconnect
* Start the graceful disconnection process.
*
@@ -2874,8 +3122,7 @@ Strophe.Connection.prototype = {
* Parameters:
* (String) reason - The reason the disconnect is occuring.
*/
- disconnect: function (reason)
- {
+ disconnect: function (reason) {
this._changeConnectStatus(Strophe.Status.DISCONNECTING, reason);
Strophe.info("Disconnect was called because: " + reason);
@@ -2907,8 +3154,7 @@ Strophe.Connection.prototype = {
* in Strophe.Status
* (String) condition - the error condition or null
*/
- _changeConnectStatus: function (status, condition)
- {
+ _changeConnectStatus: function (status, condition) {
// notify all plugins listening for status changes
for (var k in Strophe._connectionPlugins) {
if (Strophe._connectionPlugins.hasOwnProperty(k)) {
@@ -2929,8 +3175,9 @@ Strophe.Connection.prototype = {
try {
this.connect_callback(status, condition);
} catch (e) {
- Strophe.error("User connection callback caused an " +
- "exception: " + e);
+ Strophe._handleError(e);
+ Strophe.error(
+ "User connection callback caused an "+"exception: "+e);
}
}
},
@@ -2941,8 +3188,7 @@ Strophe.Connection.prototype = {
* This is the last piece of the disconnection logic. This resets the
* connection and alerts the user's connection callback.
*/
- _doDisconnect: function (condition)
- {
+ _doDisconnect: function (condition) {
if (typeof this._idleTimeout == "number") {
clearTimeout(this._idleTimeout);
}
@@ -2985,8 +3231,7 @@ Strophe.Connection.prototype = {
* (Strophe.Request) req - The request that has data ready.
* (string) req - The stanza a raw string (optiona).
*/
- _dataRecv: function (req, raw)
- {
+ _dataRecv: function (req, raw) {
Strophe.info("_dataRecv called");
var elem = this._proto._reqToData(req);
if (elem === null) { return; }
@@ -3072,7 +3317,7 @@ Strophe.Connection.prototype = {
}
} catch(e) {
// if the handler throws an exception, we consider it as false
- Strophe.warn('Removing Strophe handlers due to uncaught exception: ' + e.message);
+ Strophe.warn('Removing Strophe handlers due to uncaught exception: '+e.message);
}
}
});
@@ -3080,7 +3325,7 @@ Strophe.Connection.prototype = {
/** Attribute: mechanisms
- * SASL Mechanisms available for Conncection.
+ * SASL Mechanisms available for Connection.
*/
mechanisms: {},
@@ -3100,13 +3345,18 @@ Strophe.Connection.prototype = {
* Useful for plugins with their own xmpp connect callback (when their)
* want to do something special).
*/
- _connect_cb: function (req, _callback, raw)
- {
+ _connect_cb: function (req, _callback, raw) {
Strophe.info("_connect_cb was called");
-
this.connected = true;
- var bodyWrap = this._proto._reqToData(req);
+ var bodyWrap;
+ try {
+ bodyWrap = this._proto._reqToData(req);
+ } catch (e) {
+ if (e != "badformat") { throw e; }
+ this._changeConnectStatus(Strophe.Status.CONNFAIL, 'bad-format');
+ this._doDisconnect('bad-format');
+ }
if (!bodyWrap) { return; }
if (this.xmlInput !== Strophe.Connection.prototype.xmlInput) {
@@ -3129,145 +3379,180 @@ Strophe.Connection.prototype = {
return;
}
- this._authentication.sasl_scram_sha1 = false;
- this._authentication.sasl_plain = false;
- this._authentication.sasl_digest_md5 = false;
- this._authentication.sasl_anonymous = false;
-
- this._authentication.legacy_auth = false;
-
// Check for the stream:features tag
var hasFeatures;
if (bodyWrap.getElementsByTagNameNS) {
hasFeatures = bodyWrap.getElementsByTagNameNS(Strophe.NS.STREAM, "features").length > 0;
} else {
- hasFeatures = bodyWrap.getElementsByTagName("stream:features").length > 0 || bodyWrap.getElementsByTagName("features").length > 0;
+ hasFeatures = bodyWrap.getElementsByTagName("stream:features").length > 0 ||
+ bodyWrap.getElementsByTagName("features").length > 0;
}
- var mechanisms = bodyWrap.getElementsByTagName("mechanism");
- var matched = [];
- var i, mech, found_authentication = false;
if (!hasFeatures) {
this._proto._no_auth_received(_callback);
return;
}
+
+ var matched = [], i, mech;
+ var mechanisms = bodyWrap.getElementsByTagName("mechanism");
if (mechanisms.length > 0) {
for (i = 0; i < mechanisms.length; i++) {
mech = Strophe.getText(mechanisms[i]);
if (this.mechanisms[mech]) matched.push(this.mechanisms[mech]);
}
}
- this._authentication.legacy_auth =
- bodyWrap.getElementsByTagName("auth").length > 0;
- found_authentication = this._authentication.legacy_auth ||
- matched.length > 0;
- if (!found_authentication) {
- this._proto._no_auth_received(_callback);
- return;
+ if (matched.length === 0) {
+ if (bodyWrap.getElementsByTagName("auth").length === 0) {
+ // There are no matching SASL mechanisms and also no legacy
+ // auth available.
+ this._proto._no_auth_received(_callback);
+ return;
+ }
}
- if (this.do_authentication !== false)
+ if (this.do_authentication !== false) {
this.authenticate(matched);
+ }
},
- /** Function: authenticate
- * Set up authentication
+ /** Function: sortMechanismsByPriority
*
- * Contiunues the initial connection request by setting up authentication
- * handlers and start the authentication process.
+ * Sorts an array of objects with prototype SASLMechanism according to
+ * their priorities.
*
- * SASL authentication will be attempted if available, otherwise
- * the code will fall back to legacy authentication.
+ * Parameters:
+ * (Array) mechanisms - Array of SASL mechanisms.
*
*/
- authenticate: function (matched)
- {
- var i;
- // Sorting matched mechanisms according to priority.
- for (i = 0; i < matched.length - 1; ++i) {
- var higher = i;
- for (var j = i + 1; j < matched.length; ++j) {
- if (matched[j].prototype.priority > matched[higher].prototype.priority) {
- higher = j;
- }
- }
- if (higher != i) {
- var swap = matched[i];
- matched[i] = matched[higher];
- matched[higher] = swap;
+ sortMechanismsByPriority: function (mechanisms) {
+ // Sorting mechanisms according to priority.
+ var i, j, higher, swap;
+ for (i = 0; i < mechanisms.length - 1; ++i) {
+ higher = i;
+ for (j = i + 1; j < mechanisms.length; ++j) {
+ if (mechanisms[j].prototype.priority > mechanisms[higher].prototype.priority) {
+ higher = j;
+ }
+ }
+ if (higher != i) {
+ swap = mechanisms[i];
+ mechanisms[i] = mechanisms[higher];
+ mechanisms[higher] = swap;
+ }
}
- }
-
- // run each mechanism
- var mechanism_found = false;
- for (i = 0; i < matched.length; ++i) {
- if (!matched[i].test(this)) continue;
-
- this._sasl_success_handler = this._addSysHandler(
- this._sasl_success_cb.bind(this), null,
- "success", null, null);
- this._sasl_failure_handler = this._addSysHandler(
- this._sasl_failure_cb.bind(this), null,
- "failure", null, null);
- this._sasl_challenge_handler = this._addSysHandler(
- this._sasl_challenge_cb.bind(this), null,
- "challenge", null, null);
-
- this._sasl_mechanism = new matched[i]();
- this._sasl_mechanism.onStart(this);
-
- var request_auth_exchange = $build("auth", {
- xmlns: Strophe.NS.SASL,
- mechanism: this._sasl_mechanism.name
- });
+ return mechanisms;
+ },
- if (this._sasl_mechanism.isClientFirst) {
- var response = this._sasl_mechanism.onChallenge(this, null);
- request_auth_exchange.t(Base64.encode(response));
+ /** PrivateFunction: _attemptSASLAuth
+ *
+ * Iterate through an array of SASL mechanisms and attempt authentication
+ * with the highest priority (enabled) mechanism.
+ *
+ * Parameters:
+ * (Array) mechanisms - Array of SASL mechanisms.
+ *
+ * Returns:
+ * (Boolean) mechanism_found - true or false, depending on whether a
+ * valid SASL mechanism was found with which authentication could be
+ * started.
+ */
+ _attemptSASLAuth: function (mechanisms) {
+ mechanisms = this.sortMechanismsByPriority(mechanisms || []);
+ var i = 0, mechanism_found = false;
+ for (i = 0; i < mechanisms.length; ++i) {
+ if (!mechanisms[i].prototype.test(this)) {
+ continue;
+ }
+ this._sasl_success_handler = this._addSysHandler(
+ this._sasl_success_cb.bind(this), null,
+ "success", null, null);
+ this._sasl_failure_handler = this._addSysHandler(
+ this._sasl_failure_cb.bind(this), null,
+ "failure", null, null);
+ this._sasl_challenge_handler = this._addSysHandler(
+ this._sasl_challenge_cb.bind(this), null,
+ "challenge", null, null);
+
+ this._sasl_mechanism = new mechanisms[i]();
+ this._sasl_mechanism.onStart(this);
+
+ var request_auth_exchange = $build("auth", {
+ xmlns: Strophe.NS.SASL,
+ mechanism: this._sasl_mechanism.name
+ });
+ if (this._sasl_mechanism.isClientFirst) {
+ var response = this._sasl_mechanism.onChallenge(this, null);
+ request_auth_exchange.t(Base64.encode(response));
+ }
+ this.send(request_auth_exchange.tree());
+ mechanism_found = true;
+ break;
}
+ return mechanism_found;
+ },
- this.send(request_auth_exchange.tree());
-
- mechanism_found = true;
- break;
- }
-
- if (!mechanism_found) {
- // if none of the mechanism worked
+ /** PrivateFunction: _attemptLegacyAuth
+ *
+ * Attempt legacy (i.e. non-SASL) authentication.
+ *
+ */
+ _attemptLegacyAuth: function () {
if (Strophe.getNodeFromJid(this.jid) === null) {
// we don't have a node, which is required for non-anonymous
// client connections
- this._changeConnectStatus(Strophe.Status.CONNFAIL,
- 'x-strophe-bad-non-anon-jid');
+ this._changeConnectStatus(
+ Strophe.Status.CONNFAIL,
+ 'x-strophe-bad-non-anon-jid'
+ );
this.disconnect('x-strophe-bad-non-anon-jid');
} else {
- // fall back to legacy authentication
- this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);
- this._addSysHandler(this._auth1_cb.bind(this), null, null,
- null, "_auth_1");
-
- this.send($iq({
- type: "get",
- to: this.domain,
- id: "_auth_1"
- }).c("query", {
- xmlns: Strophe.NS.AUTH
- }).c("username", {}).t(Strophe.getNodeFromJid(this.jid)).tree());
+ // Fall back to legacy authentication
+ this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);
+ this._addSysHandler(
+ this._auth1_cb.bind(this),
+ null, null, null, "_auth_1"
+ );
+ this.send($iq({
+ 'type': "get",
+ 'to': this.domain,
+ 'id': "_auth_1"
+ }).c("query", {xmlns: Strophe.NS.AUTH})
+ .c("username", {}).t(Strophe.getNodeFromJid(this.jid))
+ .tree());
}
- }
+ },
+ /** Function: authenticate
+ * Set up authentication
+ *
+ * Continues the initial connection request by setting up authentication
+ * handlers and starting the authentication process.
+ *
+ * SASL authentication will be attempted if available, otherwise
+ * the code will fall back to legacy authentication.
+ *
+ * Parameters:
+ * (Array) matched - Array of SASL mechanisms supported.
+ *
+ */
+ authenticate: function (matched) {
+ if (!this._attemptSASLAuth(matched)) {
+ this._attemptLegacyAuth();
+ }
},
+ /** PrivateFunction: _sasl_challenge_cb
+ * _Private_ handler for the SASL challenge
+ *
+ */
_sasl_challenge_cb: function(elem) {
var challenge = Base64.decode(Strophe.getText(elem));
var response = this._sasl_mechanism.onChallenge(this, challenge);
-
var stanza = $build('response', {
- xmlns: Strophe.NS.SASL
+ 'xmlns': Strophe.NS.SASL
});
if (response !== "") {
stanza.t(Base64.encode(response));
}
this.send(stanza.tree());
-
return true;
},
@@ -3286,8 +3571,7 @@ Strophe.Connection.prototype = {
* false to remove the handler.
*/
/* jshint unused:false */
- _auth1_cb: function (elem)
- {
+ _auth1_cb: function (elem) {
// build plaintext auth iq
var iq = $iq({type: "set", id: "_auth_2"})
.c('query', {xmlns: Strophe.NS.AUTH})
@@ -3305,9 +3589,7 @@ Strophe.Connection.prototype = {
this._addSysHandler(this._auth2_cb.bind(this), null,
null, null, "_auth_2");
-
this.send(iq.tree());
-
return false;
},
/* jshint unused:true */
@@ -3321,8 +3603,7 @@ Strophe.Connection.prototype = {
* Returns:
* false to remove the handler.
*/
- _sasl_success_cb: function (elem)
- {
+ _sasl_success_cb: function (elem) {
if (this._sasl_data["server-signature"]) {
var serverSignature;
var success = Base64.decode(Strophe.getText(elem));
@@ -3345,11 +3626,11 @@ Strophe.Connection.prototype = {
return this._sasl_failure_cb(null);
}
}
-
Strophe.info("SASL authentication succeeded.");
- if(this._sasl_mechanism)
+ if (this._sasl_mechanism) {
this._sasl_mechanism.onSuccess();
+ }
// remove old handlers
this.deleteHandler(this._sasl_failure_handler);
@@ -3389,13 +3670,10 @@ Strophe.Connection.prototype = {
* Returns:
* false to remove the handler.
*/
- _sasl_auth1_cb: function (elem)
- {
+ _sasl_auth1_cb: function (elem) {
// save stream:features for future usage
this.features = elem;
-
var i, child;
-
for (i = 0; i < elem.childNodes.length; i++) {
child = elem.childNodes[i];
if (child.nodeName == 'bind') {
@@ -3425,7 +3703,6 @@ Strophe.Connection.prototype = {
.tree());
}
}
-
return false;
},
@@ -3438,8 +3715,7 @@ Strophe.Connection.prototype = {
* Returns:
* false to remove the handler.
*/
- _sasl_bind_cb: function (elem)
- {
+ _sasl_bind_cb: function (elem) {
if (elem.getAttribute("type") == "error") {
Strophe.info("SASL binding failed.");
var conflict = elem.getElementsByTagName("conflict"), condition;
@@ -3490,8 +3766,7 @@ Strophe.Connection.prototype = {
* Returns:
* false to remove the handler.
*/
- _sasl_session_cb: function (elem)
- {
+ _sasl_session_cb: function (elem) {
if (elem.getAttribute("type") == "result") {
this.authenticated = true;
this._changeConnectStatus(Strophe.Status.CONNECTED, null);
@@ -3500,7 +3775,6 @@ Strophe.Connection.prototype = {
this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
return false;
}
-
return false;
},
@@ -3514,8 +3788,7 @@ Strophe.Connection.prototype = {
* false to remove the handler.
*/
/* jshint unused:false */
- _sasl_failure_cb: function (elem)
- {
+ _sasl_failure_cb: function (elem) {
// delete unneeded handlers
if (this._sasl_success_handler) {
this.deleteHandler(this._sasl_success_handler);
@@ -3545,8 +3818,7 @@ Strophe.Connection.prototype = {
* Returns:
* false to remove the handler.
*/
- _auth2_cb: function (elem)
- {
+ _auth2_cb: function (elem) {
if (elem.getAttribute("type") == "result") {
this.authenticated = true;
this._changeConnectStatus(Strophe.Status.CONNECTED, null);
@@ -3554,7 +3826,6 @@ Strophe.Connection.prototype = {
this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
this.disconnect('authentication failed');
}
-
return false;
},
@@ -3569,8 +3840,7 @@ Strophe.Connection.prototype = {
* (Integer) period - The period of the handler.
* (Function) handler - The callback function.
*/
- _addSysTimedHandler: function (period, handler)
- {
+ _addSysTimedHandler: function (period, handler) {
var thand = new Strophe.TimedHandler(period, handler);
thand.user = false;
this.addTimeds.push(thand);
@@ -3591,8 +3861,7 @@ Strophe.Connection.prototype = {
* (String) type - The stanza type attribute to match.
* (String) id - The stanza id attribute to match.
*/
- _addSysHandler: function (handler, ns, name, type, id)
- {
+ _addSysHandler: function (handler, ns, name, type, id) {
var hand = new Strophe.Handler(handler, ns, name, type, id);
hand.user = false;
this.addHandlers.push(hand);
@@ -3608,15 +3877,12 @@ Strophe.Connection.prototype = {
* Returns:
* false to remove the handler.
*/
- _onDisconnectTimeout: function ()
- {
+ _onDisconnectTimeout: function () {
Strophe.info("_onDisconnectTimeout was called");
-
+ this._changeConnectStatus(Strophe.Status.CONNTIMEOUT, null);
this._proto._onDisconnectTimeout();
-
// actually disconnect
this._doDisconnect();
-
return false;
},
@@ -3626,8 +3892,7 @@ Strophe.Connection.prototype = {
* This handler is called every 100ms to fire timed handlers that
* are ready and keep poll requests going.
*/
- _onIdle: function ()
- {
+ _onIdle: function () {
var i, thand, since, newList;
// add timed handlers scheduled for addition
@@ -3670,7 +3935,10 @@ Strophe.Connection.prototype = {
// reactivate the timer only if connected
if (this.connected) {
- this._idleTimeout = setTimeout(this._onIdle.bind(this), 100);
+ // XXX: setTimeout should be called only with function expressions (23974bc1)
+ this._idleTimeout = setTimeout(function() {
+ this._onIdle();
+ }.bind(this), 100);
}
}
};
@@ -3685,9 +3953,14 @@ Strophe.Connection.prototype = {
*
* By default, all mechanisms are enabled and the priorities are
*
+ * EXTERNAL - 60
+ * OAUTHBEARER - 50
* SCRAM-SHA1 - 40
* DIGEST-MD5 - 30
- * Plain - 20
+ * PLAIN - 20
+ * ANONYMOUS - 10
+ *
+ * See: Strophe.Connection.addSupportedSASLMechanisms
*/
/**
@@ -3762,8 +4035,7 @@ Strophe.SASLMechanism.prototype = {
* Parameters:
* (Strophe.Connection) connection - Target Connection.
*/
- onStart: function(connection)
- {
+ onStart: function(connection) {
this._connection = connection;
},
@@ -3802,89 +4074,69 @@ Strophe.SASLMechanism.prototype = {
/** Constants: SASL mechanisms
* Available authentication mechanisms
*
- * Strophe.SASLAnonymous - SASL Anonymous authentication.
- * Strophe.SASLPlain - SASL Plain authentication.
- * Strophe.SASLMD5 - SASL Digest-MD5 authentication
+ * Strophe.SASLAnonymous - SASL ANONYMOUS authentication.
+ * Strophe.SASLPlain - SASL PLAIN authentication.
+ * Strophe.SASLMD5 - SASL DIGEST-MD5 authentication
* Strophe.SASLSHA1 - SASL SCRAM-SHA1 authentication
+ * Strophe.SASLOAuthBearer - SASL OAuth Bearer authentication
+ * Strophe.SASLExternal - SASL EXTERNAL authentication
*/
// Building SASL callbacks
/** PrivateConstructor: SASLAnonymous
- * SASL Anonymous authentication.
+ * SASL ANONYMOUS authentication.
*/
Strophe.SASLAnonymous = function() {};
-
Strophe.SASLAnonymous.prototype = new Strophe.SASLMechanism("ANONYMOUS", false, 10);
-Strophe.SASLAnonymous.test = function(connection) {
- return connection.authcid === null;
+Strophe.SASLAnonymous.prototype.test = function(connection) {
+ return connection.authcid === null;
};
-Strophe.Connection.prototype.mechanisms[Strophe.SASLAnonymous.prototype.name] = Strophe.SASLAnonymous;
/** PrivateConstructor: SASLPlain
- * SASL Plain authentication.
+ * SASL PLAIN authentication.
*/
Strophe.SASLPlain = function() {};
-
Strophe.SASLPlain.prototype = new Strophe.SASLMechanism("PLAIN", true, 20);
-Strophe.SASLPlain.test = function(connection) {
- return connection.authcid !== null;
+Strophe.SASLPlain.prototype.test = function(connection) {
+ return connection.authcid !== null;
};
Strophe.SASLPlain.prototype.onChallenge = function(connection) {
- var auth_str = connection.authzid;
- auth_str = auth_str + "\u0000";
- auth_str = auth_str + connection.authcid;
- auth_str = auth_str + "\u0000";
- auth_str = auth_str + connection.pass;
- return auth_str;
+ var auth_str = connection.authzid;
+ auth_str = auth_str + "\u0000";
+ auth_str = auth_str + connection.authcid;
+ auth_str = auth_str + "\u0000";
+ auth_str = auth_str + connection.pass;
+ return utils.utf16to8(auth_str);
};
-Strophe.Connection.prototype.mechanisms[Strophe.SASLPlain.prototype.name] = Strophe.SASLPlain;
/** PrivateConstructor: SASLSHA1
* SASL SCRAM SHA 1 authentication.
*/
Strophe.SASLSHA1 = function() {};
-
-/* TEST:
- * This is a simple example of a SCRAM-SHA-1 authentication exchange
- * when the client doesn't support channel bindings (username 'user' and
- * password 'pencil' are used):
- *
- * C: n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
- * S: r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,
- * i=4096
- * C: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,
- * p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=
- * S: v=rmF9pqV8S7suAoZWja4dJRkFsKQ=
- *
- */
-
Strophe.SASLSHA1.prototype = new Strophe.SASLMechanism("SCRAM-SHA-1", true, 40);
-Strophe.SASLSHA1.test = function(connection) {
- return connection.authcid !== null;
+Strophe.SASLSHA1.prototype.test = function(connection) {
+ return connection.authcid !== null;
};
Strophe.SASLSHA1.prototype.onChallenge = function(connection, challenge, test_cnonce) {
var cnonce = test_cnonce || MD5.hexdigest(Math.random() * 1234567890);
-
- var auth_str = "n=" + connection.authcid;
+ var auth_str = "n=" + utils.utf16to8(connection.authcid);
auth_str += ",r=";
auth_str += cnonce;
-
connection._sasl_data.cnonce = cnonce;
connection._sasl_data["client-first-message-bare"] = auth_str;
auth_str = "n,," + auth_str;
- this.onChallenge = function (connection, challenge)
- {
- var nonce, salt, iter, Hi, U, U_old, i, k;
+ this.onChallenge = function (connection, challenge) {
+ var nonce, salt, iter, Hi, U, U_old, i, k, pass;
var clientKey, serverKey, clientSignature;
var responseText = "c=biws,";
var authMessage = connection._sasl_data["client-first-message-bare"] + "," +
@@ -3919,9 +4171,10 @@ Strophe.SASLSHA1.prototype.onChallenge = function(connection, challenge, test_cn
salt = Base64.decode(salt);
salt += "\x00\x00\x00\x01";
- Hi = U_old = SHA1.core_hmac_sha1(connection.pass, salt);
+ pass = utils.utf16to8(connection.pass);
+ Hi = U_old = SHA1.core_hmac_sha1(pass, salt);
for (i = 1; i < iter; i++) {
- U = SHA1.core_hmac_sha1(connection.pass, SHA1.binb2str(U_old));
+ U = SHA1.core_hmac_sha1(pass, SHA1.binb2str(U_old));
for (k = 0; k < 5; k++) {
Hi[k] ^= U[k];
}
@@ -3939,24 +4192,21 @@ Strophe.SASLSHA1.prototype.onChallenge = function(connection, challenge, test_cn
}
responseText += ",p=" + Base64.encode(SHA1.binb2str(clientKey));
-
return responseText;
}.bind(this);
return auth_str;
};
-Strophe.Connection.prototype.mechanisms[Strophe.SASLSHA1.prototype.name] = Strophe.SASLSHA1;
/** PrivateConstructor: SASLMD5
* SASL DIGEST MD5 authentication.
*/
Strophe.SASLMD5 = function() {};
-
Strophe.SASLMD5.prototype = new Strophe.SASLMechanism("DIGEST-MD5", false, 30);
-Strophe.SASLMD5.test = function(connection) {
- return connection.authcid !== null;
+Strophe.SASLMD5.prototype.test = function(connection) {
+ return connection.authcid !== null;
};
/** PrivateFunction: _quote
@@ -3968,12 +4218,10 @@ Strophe.SASLMD5.test = function(connection) {
* Returns:
* quoted string
*/
-Strophe.SASLMD5.prototype._quote = function (str)
- {
+Strophe.SASLMD5.prototype._quote = function (str) {
return '"' + str.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
//" end string workaround for emacs
- };
-
+};
Strophe.SASLMD5.prototype.onChallenge = function(connection, challenge, test_cnonce) {
var attribMatch = /([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/;
@@ -4009,15 +4257,13 @@ Strophe.SASLMD5.prototype.onChallenge = function(connection, challenge, test_cno
digest_uri = digest_uri + "/" + host;
}
- var A1 = MD5.hash(connection.authcid +
- ":" + realm + ":" + this._connection.pass) +
- ":" + nonce + ":" + cnonce;
+ var cred = utils.utf16to8(connection.authcid + ":" + realm + ":" + this._connection.pass);
+ var A1 = MD5.hash(cred) + ":" + nonce + ":" + cnonce;
var A2 = 'AUTHENTICATE:' + digest_uri;
var responseText = "";
responseText += 'charset=utf-8,';
- responseText += 'username=' +
- this._quote(connection.authcid) + ',';
+ responseText += 'username=' + this._quote(utils.utf16to8(connection.authcid)) + ',';
responseText += 'realm=' + this._quote(realm) + ',';
responseText += 'nonce=' + this._quote(nonce) + ',';
responseText += 'nc=00000001,';
@@ -4029,15 +4275,57 @@ Strophe.SASLMD5.prototype.onChallenge = function(connection, challenge, test_cno
MD5.hexdigest(A2)) + ",";
responseText += 'qop=auth';
- this.onChallenge = function ()
- {
+ this.onChallenge = function () {
return "";
- }.bind(this);
-
+ };
return responseText;
};
-Strophe.Connection.prototype.mechanisms[Strophe.SASLMD5.prototype.name] = Strophe.SASLMD5;
+
+/** PrivateConstructor: SASLOAuthBearer
+ * SASL OAuth Bearer authentication.
+ */
+Strophe.SASLOAuthBearer = function() {};
+Strophe.SASLOAuthBearer.prototype = new Strophe.SASLMechanism("OAUTHBEARER", true, 50);
+
+Strophe.SASLOAuthBearer.prototype.test = function(connection) {
+ return connection.authcid !== null;
+};
+
+Strophe.SASLOAuthBearer.prototype.onChallenge = function(connection) {
+ var auth_str = 'n,a=';
+ auth_str = auth_str + connection.authzid;
+ auth_str = auth_str + ',';
+ auth_str = auth_str + "\u0001";
+ auth_str = auth_str + 'auth=Bearer ';
+ auth_str = auth_str + connection.pass;
+ auth_str = auth_str + "\u0001";
+ auth_str = auth_str + "\u0001";
+ return utils.utf16to8(auth_str);
+};
+
+
+/** PrivateConstructor: SASLExternal
+ * SASL EXTERNAL authentication.
+ *
+ * The EXTERNAL mechanism allows a client to request the server to use
+ * credentials established by means external to the mechanism to
+ * authenticate the client. The external means may be, for instance,
+ * TLS services.
+ */
+Strophe.SASLExternal = function() {};
+Strophe.SASLExternal.prototype = new Strophe.SASLMechanism("EXTERNAL", true, 60);
+
+Strophe.SASLExternal.prototype.onChallenge = function(connection) {
+ /** According to XEP-178, an authzid SHOULD NOT be presented when the
+ * authcid contained or implied in the client certificate is the JID (i.e.
+ * authzid) with which the user wants to log in as.
+ *
+ * To NOT send the authzid, the user should therefore set the authcid equal
+ * to the JID when instantiating a new Strophe.Connection object.
+ */
+ return connection.authcid === connection.authzid ? '' : connection.authzid;
+};
return {
Strophe: Strophe,
@@ -4091,11 +4379,9 @@ return {
* (Function) func - The function that will be called when the
* XMLHttpRequest readyState changes.
* (Integer) rid - The BOSH rid attribute associated with this request.
- * (Integer) sends - The number of times this same request has been
- * sent.
+ * (Integer) sends - The number of times this same request has been sent.
*/
-Strophe.Request = function (elem, func, rid, sends)
-{
+Strophe.Request = function (elem, func, rid, sends) {
this.id = ++Strophe._requestId;
this.xmlData = elem;
this.data = Strophe.serialize(elem);
@@ -4131,12 +4417,12 @@ Strophe.Request.prototype = {
*
* Throws:
* "parsererror" - A parser error occured.
+ * "badformat" - The entity has sent XML that cannot be processed.
*
* Returns:
* The DOM element tree of the response.
*/
- getResponse: function ()
- {
+ getResponse: function () {
var node = null;
if (this.xhr.responseXML && this.xhr.responseXML.documentElement) {
node = this.xhr.responseXML.documentElement;
@@ -4150,8 +4436,7 @@ Strophe.Request.prototype = {
} else if (this.xhr.responseText) {
Strophe.error("invalid response received");
Strophe.error("responseText: " + this.xhr.responseText);
- Strophe.error("responseXML: " +
- Strophe.serialize(this.xhr.responseXML));
+ throw "badformat";
}
return node;
@@ -4165,8 +4450,7 @@ Strophe.Request.prototype = {
* Returns:
* A new XMLHttpRequest.
*/
- _newXHR: function ()
- {
+ _newXHR: function () {
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
@@ -4176,10 +4460,8 @@ Strophe.Request.prototype = {
} else if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
-
// use Function.bind() to prepend ourselves as an argument
xhr.onreadystatechange = this.func.bind(null, this);
-
return xhr;
}
};
@@ -4220,6 +4502,7 @@ Strophe.Bosh = function(connection) {
this.wait = 60;
this.window = 5;
this.errors = 0;
+ this.inactivity = null;
this._requests = [];
};
@@ -4244,8 +4527,7 @@ Strophe.Bosh.prototype = {
* Returns:
* A Strophe.Builder with a <body/> element.
*/
- _buildBody: function ()
- {
+ _buildBody: function () {
var bodyWrap = $build('body', {
rid: this.rid++,
xmlns: Strophe.NS.HTTPBIND
@@ -4253,7 +4535,7 @@ Strophe.Bosh.prototype = {
if (this.sid !== null) {
bodyWrap.attrs({sid: this.sid});
}
- if (this._conn.options.keepalive) {
+ if (this._conn.options.keepalive && this._conn._sessionCachingSupported()) {
this._cacheSession();
}
return bodyWrap;
@@ -4264,12 +4546,13 @@ Strophe.Bosh.prototype = {
*
* This function is called by the reset function of the Strophe Connection
*/
- _reset: function ()
- {
+ _reset: function () {
this.rid = Math.floor(Math.random() * 4294967295);
this.sid = null;
this.errors = 0;
- window.sessionStorage.removeItem('strophe-bosh-session');
+ if (this._conn._sessionCachingSupported()) {
+ window.sessionStorage.removeItem('strophe-bosh-session');
+ }
this._conn.nextValidRid(this.rid);
},
@@ -4279,8 +4562,7 @@ Strophe.Bosh.prototype = {
*
* Creates and sends the Request that initializes the BOSH connection.
*/
- _connect: function (wait, hold, route)
- {
+ _connect: function (wait, hold, route) {
this.wait = wait || this.wait;
this.hold = hold || this.hold;
this.errors = 0;
@@ -4337,8 +4619,7 @@ Strophe.Bosh.prototype = {
* (Integer) wind - The optional HTTBIND window value. This is the
* allowed range of request ids that are valid. The default is 5.
*/
- _attach: function (jid, sid, rid, callback, wait, hold, wind)
- {
+ _attach: function (jid, sid, rid, callback, wait, hold, wind) {
this._conn.jid = jid;
this.sid = sid;
this.rid = rid;
@@ -4376,15 +4657,14 @@ Strophe.Bosh.prototype = {
* (Integer) wind - The optional HTTBIND window value. This is the
* allowed range of request ids that are valid. The default is 5.
*/
- _restore: function (jid, callback, wait, hold, wind)
- {
+ _restore: function (jid, callback, wait, hold, wind) {
var session = JSON.parse(window.sessionStorage.getItem('strophe-bosh-session'));
if (typeof session !== "undefined" &&
session !== null &&
session.rid &&
session.sid &&
session.jid &&
- (typeof jid === "undefined" || jid === "null" || Strophe.getBareJidFromJid(session.jid) == Strophe.getBareJidFromJid(jid)))
+ (typeof jid === "undefined" || jid === null || Strophe.getBareJidFromJid(session.jid) == Strophe.getBareJidFromJid(jid)))
{
this._conn.restored = true;
this._attach(session.jid, session.sid, session.rid, callback, wait, hold, wind);
@@ -4400,8 +4680,7 @@ Strophe.Bosh.prototype = {
* Parameters:
* (Strophe.Request) bodyWrap - The received stanza.
*/
- _cacheSession: function ()
- {
+ _cacheSession: function () {
if (this._conn.authenticated) {
if (this._conn.jid && this.rid && this.sid) {
window.sessionStorage.setItem('strophe-bosh-session', JSON.stringify({
@@ -4422,8 +4701,7 @@ Strophe.Bosh.prototype = {
* Parameters:
* (Strophe.Request) bodyWrap - The received stanza.
*/
- _connect_cb: function (bodyWrap)
- {
+ _connect_cb: function (bodyWrap) {
var typ = bodyWrap.getAttribute("type");
var cond, conflict;
if (typ !== null && typ == "terminate") {
@@ -4454,6 +4732,8 @@ Strophe.Bosh.prototype = {
if (hold) { this.hold = parseInt(hold, 10); }
var wait = bodyWrap.getAttribute('wait');
if (wait) { this.wait = parseInt(wait, 10); }
+ var inactivity = bodyWrap.getAttribute('inactivity');
+ if (inactivity) { this.inactivity = parseInt(inactivity, 10); }
},
/** PrivateFunction: _disconnect
@@ -4462,8 +4742,7 @@ Strophe.Bosh.prototype = {
* Parameters:
* (Request) pres - This stanza will be sent before disconnecting.
*/
- _disconnect: function (pres)
- {
+ _disconnect: function (pres) {
this._sendTerminate(pres);
},
@@ -4472,11 +4751,12 @@ Strophe.Bosh.prototype = {
*
* Resets the SID and RID.
*/
- _doDisconnect: function ()
- {
+ _doDisconnect: function () {
this.sid = null;
this.rid = Math.floor(Math.random() * 4294967295);
- window.sessionStorage.removeItem('strophe-bosh-session');
+ if (this._conn._sessionCachingSupported()) {
+ window.sessionStorage.removeItem('strophe-bosh-session');
+ }
this._conn.nextValidRid(this.rid);
},
@@ -4487,11 +4767,25 @@ Strophe.Bosh.prototype = {
* Returns:
* True, if there are no Requests queued, False otherwise.
*/
- _emptyQueue: function ()
- {
+ _emptyQueue: function () {
return this._requests.length === 0;
},
+ /** PrivateFunction: _callProtocolErrorHandlers
+ * _Private_ function to call error handlers registered for HTTP errors.
+ *
+ * Parameters:
+ * (Strophe.Request) req - The request that is changing readyState.
+ */
+ _callProtocolErrorHandlers: function (req) {
+ var reqStatus = this._getRequestStatus(req),
+ err_callback;
+ err_callback = this._conn.protocolErrorHandlers.HTTP[reqStatus];
+ if (err_callback) {
+ err_callback.call(this, reqStatus);
+ }
+ },
+
/** PrivateFunction: _hitError
* _Private_ function to handle the error count.
*
@@ -4502,8 +4796,7 @@ Strophe.Bosh.prototype = {
* Parameters:
* (Integer) reqStatus - The request status.
*/
- _hitError: function (reqStatus)
- {
+ _hitError: function (reqStatus) {
this.errors++;
Strophe.warn("request errored, status: " + reqStatus +
", number of errors: " + this.errors);
@@ -4517,8 +4810,7 @@ Strophe.Bosh.prototype = {
* Called on stream start/restart when no stream:features
* has been received and sends a blank poll request.
*/
- _no_auth_received: function (_callback)
- {
+ _no_auth_received: function (_callback) {
if (_callback) {
_callback = _callback.bind(this._conn);
} else {
@@ -4564,7 +4856,6 @@ Strophe.Bosh.prototype = {
*/
_onIdle: function () {
var data = this._conn._data;
-
// if no requests are in progress, poll
if (this._conn.authenticated && this._requests.length === 0 &&
data.length === 0 && !this._conn.disconnecting) {
@@ -4622,6 +4913,34 @@ Strophe.Bosh.prototype = {
}
},
+ /** PrivateFunction: _getRequestStatus
+ *
+ * Returns the HTTP status code from a Strophe.Request
+ *
+ * Parameters:
+ * (Strophe.Request) req - The Strophe.Request instance.
+ * (Integer) def - The default value that should be returned if no
+ * status value was found.
+ */
+ _getRequestStatus: function (req, def) {
+ var reqStatus;
+ if (req.xhr.readyState == 4) {
+ try {
+ reqStatus = req.xhr.status;
+ } catch (e) {
+ // ignore errors from undefined status attribute. Works
+ // around a browser bug
+ Strophe.error(
+ "Caught an error while retrieving a request's status, " +
+ "reqStatus: " + reqStatus);
+ }
+ }
+ if (typeof(reqStatus) == "undefined") {
+ reqStatus = typeof def === 'number' ? def : 0;
+ }
+ return reqStatus;
+ },
+
/** PrivateFunction: _onRequestStateChange
* _Private_ handler for Strophe.Request state changes.
*
@@ -4634,90 +4953,63 @@ Strophe.Bosh.prototype = {
* (Function) func - The handler for the request.
* (Strophe.Request) req - The request that is changing readyState.
*/
- _onRequestStateChange: function (func, req)
- {
- Strophe.debug("request id " + req.id +
- "." + req.sends + " state changed to " +
- req.xhr.readyState);
-
+ _onRequestStateChange: function (func, req) {
+ Strophe.debug("request id "+req.id+"."+req.sends+
+ " state changed to "+req.xhr.readyState);
if (req.abort) {
req.abort = false;
return;
}
+ if (req.xhr.readyState !== 4) {
+ // The request is not yet complete
+ return;
+ }
+ var reqStatus = this._getRequestStatus(req);
+ if (this.disconnecting && reqStatus >= 400) {
+ this._hitError(reqStatus);
+ this._callProtocolErrorHandlers(req);
+ return;
+ }
- // request complete
- var reqStatus;
- if (req.xhr.readyState == 4) {
- reqStatus = 0;
- try {
- reqStatus = req.xhr.status;
- } catch (e) {
- // ignore errors from undefined status attribute. works
- // around a browser bug
- }
-
- if (typeof(reqStatus) == "undefined") {
- reqStatus = 0;
- }
-
- if (this.disconnecting) {
- if (reqStatus >= 400) {
- this._hitError(reqStatus);
- return;
- }
- }
+ if ((reqStatus > 0 && reqStatus < 500) || req.sends > 5) {
+ // remove from internal queue
+ this._removeRequest(req);
+ Strophe.debug("request id "+req.id+" should now be removed");
+ }
+ if (reqStatus == 200) {
+ // request succeeded
var reqIs0 = (this._requests[0] == req);
var reqIs1 = (this._requests[1] == req);
-
- if ((reqStatus > 0 && reqStatus < 500) || req.sends > 5) {
- // remove from internal queue
- this._removeRequest(req);
- Strophe.debug("request id " +
- req.id +
- " should now be removed");
- }
-
- // request succeeded
- if (reqStatus == 200) {
- // if request 1 finished, or request 0 finished and request
- // 1 is over Strophe.SECONDARY_TIMEOUT seconds old, we need to
- // restart the other - both will be in the first spot, as the
- // completed request has been removed from the queue already
- if (reqIs1 ||
- (reqIs0 && this._requests.length > 0 &&
- this._requests[0].age() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait))) {
- this._restartRequest(0);
- }
-
- this._conn.nextValidRid(Number(req.rid) + 1);
-
- // call handler
- Strophe.debug("request id " +
- req.id + "." +
- req.sends + " got 200");
- func(req);
- this.errors = 0;
- } else {
- Strophe.error("request id " +
- req.id + "." +
- req.sends + " error " + reqStatus +
- " happened");
- if (reqStatus === 0 ||
- (reqStatus >= 400 && reqStatus < 600) ||
- reqStatus >= 12000) {
- this._hitError(reqStatus);
- if (reqStatus >= 400 && reqStatus < 500) {
- this._conn._changeConnectStatus(Strophe.Status.DISCONNECTING, null);
- this._conn._doDisconnect();
- }
- }
- }
-
- if (!((reqStatus > 0 && reqStatus < 500) ||
- req.sends > 5)) {
- this._throttledRequestHandler();
+ // if request 1 finished, or request 0 finished and request
+ // 1 is over Strophe.SECONDARY_TIMEOUT seconds old, we need to
+ // restart the other - both will be in the first spot, as the
+ // completed request has been removed from the queue already
+ if (reqIs1 ||
+ (reqIs0 && this._requests.length > 0 &&
+ this._requests[0].age() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait))) {
+ this._restartRequest(0);
+ }
+ this._conn.nextValidRid(Number(req.rid) + 1);
+ Strophe.debug("request id "+req.id+"."+req.sends+" got 200");
+ func(req); // call handler
+ this.errors = 0;
+ } else if (reqStatus === 0 ||
+ (reqStatus >= 400 && reqStatus < 600) ||
+ reqStatus >= 12000) {
+ // request failed
+ Strophe.error("request id "+req.id+"."+req.sends+" error "+reqStatus+" happened");
+ this._hitError(reqStatus);
+ this._callProtocolErrorHandlers(req);
+ if (reqStatus >= 400 && reqStatus < 500) {
+ this._conn._changeConnectStatus(Strophe.Status.DISCONNECTING, null);
+ this._conn._doDisconnect();
}
+ } else {
+ Strophe.error("request id "+req.id+"."+req.sends+" error "+reqStatus+" happened");
+ }
+ if (!(reqStatus > 0 && reqStatus < 500) || req.sends > 5) {
+ this._throttledRequestHandler();
}
},
@@ -4730,24 +5022,10 @@ Strophe.Bosh.prototype = {
* Parameters:
* (Integer) i - The index of the request in the queue.
*/
- _processRequest: function (i)
- {
+ _processRequest: function (i) {
var self = this;
var req = this._requests[i];
- var reqStatus = -1;
-
- try {
- if (req.xhr.readyState == 4) {
- reqStatus = req.xhr.status;
- }
- } catch (e) {
- Strophe.error("caught an error in _requests[" + i +
- "], reqStatus: " + reqStatus);
- }
-
- if (typeof(reqStatus) == "undefined") {
- reqStatus = -1;
- }
+ var reqStatus = this._getRequestStatus(req, -1);
// make sure we limit the number of retries
if (req.sends > this._conn.maxRetries) {
@@ -4761,13 +5039,11 @@ Strophe.Bosh.prototype = {
var secondaryTimeout = (req.dead !== null &&
req.timeDead() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait));
var requestCompletedWithServerError = (req.xhr.readyState == 4 &&
- (reqStatus < 1 ||
- reqStatus >= 500));
+ (reqStatus < 1 || reqStatus >= 500));
if (primaryTimeout || secondaryTimeout ||
requestCompletedWithServerError) {
if (secondaryTimeout) {
- Strophe.error("Request " +
- this._requests[i].id +
+ Strophe.error("Request " + this._requests[i].id +
" timed out (secondary), restarting");
}
req.abort = true;
@@ -4782,17 +5058,23 @@ Strophe.Bosh.prototype = {
}
if (req.xhr.readyState === 0) {
- Strophe.debug("request id " + req.id +
- "." + req.sends + " posting");
+ Strophe.debug("request id "+req.id+"."+req.sends+" posting");
try {
+ var contentType = this._conn.options.contentType || "text/xml; charset=utf-8";
req.xhr.open("POST", this._conn.service, this._conn.options.sync ? false : true);
- req.xhr.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
+ if (typeof req.xhr.setRequestHeader !== 'undefined') {
+ // IE9 doesn't have setRequestHeader
+ req.xhr.setRequestHeader("Content-Type", contentType);
+ }
+ if (this._conn.options.withCredentials) {
+ req.xhr.withCredentials = true;
+ }
} catch (e2) {
Strophe.error("XHR open failed.");
if (!this._conn.connected) {
- this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,
- "bad-service");
+ this._conn._changeConnectStatus(
+ Strophe.Status.CONNFAIL, "bad-service");
}
this._conn.disconnect();
return;
@@ -4820,7 +5102,10 @@ Strophe.Bosh.prototype = {
// expanding retry window
var backoff = Math.min(Math.floor(Strophe.TIMEOUT * this.wait),
Math.pow(req.sends, 3)) * 1000;
- setTimeout(sendFunc, backoff);
+ setTimeout(function() {
+ // XXX: setTimeout should be called only with function expressions (23974bc1)
+ sendFunc();
+ }, backoff);
} else {
sendFunc();
}
@@ -4851,20 +5136,16 @@ Strophe.Bosh.prototype = {
* Parameters:
* (Strophe.Request) req - The request to remove.
*/
- _removeRequest: function (req)
- {
+ _removeRequest: function (req) {
Strophe.debug("removing request");
-
var i;
for (i = this._requests.length - 1; i >= 0; i--) {
if (req == this._requests[i]) {
this._requests.splice(i, 1);
}
}
-
// IE6 fails on setting to null, so set to empty function
req.xhr.onreadystatechange = function () {};
-
this._throttledRequestHandler();
},
@@ -4874,8 +5155,7 @@ Strophe.Bosh.prototype = {
* Parameters:
* (Integer) i - The index of the request in the queue.
*/
- _restartRequest: function (i)
- {
+ _restartRequest: function (i) {
var req = this._requests[i];
if (req.dead === null) {
req.dead = new Date();
@@ -4896,8 +5176,7 @@ Strophe.Bosh.prototype = {
* Returns:
* The stanza that was passed.
*/
- _reqToData: function (req)
- {
+ _reqToData: function (req) {
try {
return req.getResponse();
} catch (e) {
@@ -4913,20 +5192,18 @@ Strophe.Bosh.prototype = {
* the BOSH server a terminate body and includes an unavailable
* presence if authentication has completed.
*/
- _sendTerminate: function (pres)
- {
+ _sendTerminate: function (pres) {
Strophe.info("_sendTerminate was called");
var body = this._buildBody().attrs({type: "terminate"});
-
if (pres) {
body.cnode(pres.tree());
}
-
- var req = new Strophe.Request(body.tree(),
- this._onRequestStateChange.bind(
- this, this._conn._dataRecv.bind(this._conn)),
- body.tree().getAttribute("rid"));
-
+ var req = new Strophe.Request(
+ body.tree(),
+ this._onRequestStateChange.bind(
+ this, this._conn._dataRecv.bind(this._conn)),
+ body.tree().getAttribute("rid")
+ );
this._requests.push(req);
this._throttledRequestHandler();
},
@@ -4939,15 +5216,18 @@ Strophe.Bosh.prototype = {
_send: function () {
clearTimeout(this._conn._idleTimeout);
this._throttledRequestHandler();
- this._conn._idleTimeout = setTimeout(this._conn._onIdle.bind(this._conn), 100);
+
+ // XXX: setTimeout should be called only with function expressions (23974bc1)
+ this._conn._idleTimeout = setTimeout(function() {
+ this._onIdle();
+ }.bind(this._conn), 100);
},
/** PrivateFunction: _sendRestart
*
* Send an xmpp:restart stanza.
*/
- _sendRestart: function ()
- {
+ _sendRestart: function () {
this._throttledRequestHandler();
clearTimeout(this._conn._idleTimeout);
},
@@ -4959,8 +5239,7 @@ Strophe.Bosh.prototype = {
* request ids overflow the connection window in the case that one
* request died.
*/
- _throttledRequestHandler: function ()
- {
+ _throttledRequestHandler: function () {
if (!this._requests) {
Strophe.debug("_throttledRequestHandler called with " +
"undefined requests");
@@ -5075,8 +5354,7 @@ Strophe.Websocket.prototype = {
* Returns:
* A Strophe.Builder with a <stream> element.
*/
- _buildStream: function ()
- {
+ _buildStream: function () {
return $build("open", {
"xmlns": Strophe.NS.FRAMING,
"to": this._conn.domain,
@@ -5146,8 +5424,7 @@ Strophe.Websocket.prototype = {
* This function is called by the reset function of the Strophe Connection.
* Is not needed by WebSockets.
*/
- _reset: function ()
- {
+ _reset: function () {
return;
},
@@ -5269,8 +5546,7 @@ Strophe.Websocket.prototype = {
* Parameters:
* (Request) pres - This stanza will be sent before disconnecting.
*/
- _disconnect: function (pres)
- {
+ _disconnect: function (pres) {
if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {
if (pres) {
this._conn.send(pres);
@@ -5293,8 +5569,7 @@ Strophe.Websocket.prototype = {
*
* Just closes the Socket for WebSockets
*/
- _doDisconnect: function ()
- {
+ _doDisconnect: function () {
Strophe.info("WebSockets _doDisconnect was called");
this._closeSocket();
},
@@ -5303,8 +5578,7 @@ Strophe.Websocket.prototype = {
* _Private_ helper function to wrap a stanza in a <stream> tag.
* This is used so Strophe can process stanzas from WebSockets like BOSH
*/
- _streamWrap: function (stanza)
- {
+ _streamWrap: function (stanza) {
return "<wrapper>" + stanza + '</wrapper>';
},
@@ -5314,8 +5588,7 @@ Strophe.Websocket.prototype = {
*
* Closes the socket if it is still open and deletes it
*/
- _closeSocket: function ()
- {
+ _closeSocket: function () {
if (this.socket) { try {
this.socket.close();
} catch (e) {} }
@@ -5328,8 +5601,7 @@ Strophe.Websocket.prototype = {
* Returns:
* True, because WebSocket messages are send immediately after queueing.
*/
- _emptyQueue: function ()
- {
+ _emptyQueue: function () {
return true;
},
@@ -5340,7 +5612,7 @@ Strophe.Websocket.prototype = {
*/
_onClose: function() {
if(this._conn.connected && !this._conn.disconnecting) {
- Strophe.error("Websocket closed unexcectedly");
+ Strophe.error("Websocket closed unexpectedly");
this._conn._doDisconnect();
} else {
Strophe.info("Websocket closed");
@@ -5352,8 +5624,7 @@ Strophe.Websocket.prototype = {
* Called on stream start/restart when no stream:features
* has been received.
*/
- _no_auth_received: function (_callback)
- {
+ _no_auth_received: function (_callback) {
Strophe.error("Server did not send any auth methods");
this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "Server did not send any auth methods");
if (_callback) {
@@ -5383,7 +5654,7 @@ Strophe.Websocket.prototype = {
*/
_onError: function(error) {
Strophe.error("Websocket error " + error);
- this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "The WebSocket connection could not be established was disconnected.");
+ this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, "The WebSocket connection could not be established or was disconnected.");
this._disconnect();
},
@@ -5416,11 +5687,22 @@ Strophe.Websocket.prototype = {
/** PrivateFunction: _onMessage
* _Private_ function to handle websockets messages.
*
- * This function parses each of the messages as if they are full documents. [TODO : We may actually want to use a SAX Push parser].
+ * This function parses each of the messages as if they are full documents.
+ * [TODO : We may actually want to use a SAX Push parser].
+ *
+ * Since all XMPP traffic starts with
+ * <stream:stream version='1.0'
+ * xml:lang='en'
+ * xmlns='jabber:client'
+ * xmlns:stream='http://etherx.jabber.org/streams'
+ * id='3697395463'
+ * from='SERVER'>
+ *
+ * The first stanza will always fail to be parsed.
*
- * Since all XMPP traffic starts with "<stream:stream version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='3697395463' from='SERVER'>"
- * The first stanza will always fail to be parsed...
- * Addtionnaly, the seconds stanza will always be a <stream:features> with the stream NS defined in the previous stanza... so we need to 'force' the inclusion of the NS in this stanza!
+ * Additionally, the seconds stanza will always be <stream:features> with
+ * the stream NS defined in the previous stanza, so we need to 'force'
+ * the inclusion of the NS in this stanza.
*
* Parameters:
* (string) message - The websocket message.
@@ -5439,7 +5721,6 @@ Strophe.Websocket.prototype = {
} else if (message.data.search("<open ") === 0) {
// This handles stream restarts
elem = new DOMParser().parseFromString(message.data, "text/xml").documentElement;
-
if (!this._handleStreamStart(elem)) {
return;
}
@@ -5491,8 +5772,7 @@ Strophe.Websocket.prototype = {
* Returns:
* The stanza that was passed.
*/
- _reqToData: function (stanza)
- {
+ _reqToData: function (stanza) {
return stanza;
},
@@ -5509,8 +5789,7 @@ Strophe.Websocket.prototype = {
*
* Send an xmpp:restart stanza.
*/
- _sendRestart: function ()
- {
+ _sendRestart: function () {
clearTimeout(this._conn._idleTimeout);
this._conn._onIdle.bind(this._conn)();
}
@@ -5518,9 +5797,35 @@ Strophe.Websocket.prototype = {
return Strophe;
}));
+(function(root){
+ if(typeof define === 'function' && define.amd){
+ define("strophe", [
+ "strophe-core",
+ "strophe-bosh",
+ "strophe-websocket"
+ ], function (wrapper) {
+ return wrapper;
+ });
+ }
+})(this);
+
/* jshint ignore:start */
if (callback) {
- return callback(Strophe, $build, $msg, $iq, $pres);
+ if(typeof define === 'function' && define.amd){
+ //For backwards compatability
+ var n_callback = callback;
+ if (typeof requirejs === 'function') {
+ requirejs(["strophe"], function(o){
+ n_callback(o.Strophe,o.$build,o.$msg,o.$iq,o.$pres);
+ });
+ } else {
+ require(["strophe"], function(o){
+ n_callback(o.Strophe,o.$build,o.$msg,o.$iq,o.$pres);
+ });
+ }
+ }else{
+ return callback(Strophe, $build, $msg, $iq, $pres);
+ }
}
@@ -8129,24 +8434,349 @@ Strophe.addConnectionPlugin('bookmarks', {
/*!
+ * Source: lib/strophe.chatstates/index.js, license: MIT, url: https://github.com/strophe/strophejs-plugins/tree/master/chatstates
+ */
+/**
+ * Chat state notifications (XEP 0085) plugin
+ * @see http://xmpp.org/extensions/xep-0085.html
+ */
+Strophe.addConnectionPlugin('chatstates',
+{
+ init: function (connection)
+ {
+ this._connection = connection;
+
+ Strophe.addNamespace('CHATSTATES', 'http://jabber.org/protocol/chatstates');
+ },
+
+ statusChanged: function (status)
+ {
+ if (status === Strophe.Status.CONNECTED
+ || status === Strophe.Status.ATTACHED)
+ {
+ this._connection.addHandler(this._notificationReceived.bind(this),
+ Strophe.NS.CHATSTATES, "message");
+ }
+ },
+
+ addActive: function(message)
+ {
+ return message.c('active', {xmlns: Strophe.NS.CHATSTATES}).up();
+ },
+
+ _notificationReceived: function(message)
+ {
+ var composing = $(message).find('composing'),
+ paused = $(message).find('paused'),
+ active = $(message).find('active'),
+ jid = $(message).attr('from');
+
+ if (composing.length > 0)
+ {
+ $(document).trigger('composing.chatstates', jid);
+ }
+
+ if (paused.length > 0)
+ {
+ $(document).trigger('paused.chatstates', jid);
+ }
+
+ if (active.length > 0)
+ {
+ $(document).trigger('active.chatstates', jid);
+ }
+
+ return true;
+ },
+
+ sendActive: function(jid, type)
+ {
+ this._sendNotification(jid, type, 'active');
+ },
+
+ sendComposing: function(jid, type)
+ {
+ this._sendNotification(jid, type, 'composing');
+ },
+
+ sendPaused: function(jid, type)
+ {
+ this._sendNotification(jid, type, 'paused');
+ },
+
+ _sendNotification: function(jid, type, notification)
+ {
+ if (!type) type = 'chat';
+
+ this._connection.send($msg(
+ {
+ to: jid,
+ type: type
+ })
+ .c(notification, {xmlns: Strophe.NS.CHATSTATES}));
+ }
+});
+
+
+/*!
* Source: lib/strophe.jinglejs/strophe.jinglejs-bundle.js, license: MIT, url: https://github.com/sualko/strophe.jinglejs
*/
/*!
- * 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
+ };
+};
-},{}],2:[function(require,module,exports){
+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){
+
+},{}],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.
@@ -8156,16 +8786,15 @@ Strophe.addConnectionPlugin('bookmarks', {
*/
/* 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`:
@@ -8183,9 +8812,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
@@ -8198,14 +8824,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) {
@@ -8219,178 +8847,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 ' +
@@ -8399,12 +9101,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) {
@@ -8421,17 +9122,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
@@ -8445,9 +9141,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':
@@ -8459,32 +9155,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
@@ -8494,13 +9204,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':
@@ -8520,20 +9229,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) {
@@ -8547,8 +9278,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)
@@ -8567,6 +9299,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 ''
@@ -8590,63 +9369,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')
+ }
-Buffer.prototype.indexOf = function indexOf (val, byteOffset) {
- if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff
- else if (byteOffset < -0x80000000) byteOffset = -0x80000000
- byteOffset >>= 0
+ if (start === undefined) {
+ start = 0
+ }
+ if (end === undefined) {
+ end = target ? target.length : 0
+ }
+ if (thisStart === undefined) {
+ thisStart = 0
+ }
+ if (thisEnd === undefined) {
+ thisEnd = this.length
+ }
+
+ if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
+ throw new RangeError('out of range index')
+ }
+
+ if (thisStart >= thisEnd && start >= end) {
+ return 0
+ }
+ if (thisStart >= thisEnd) {
+ return -1
+ }
+ if (start >= end) {
+ return 1
+ }
+
+ start >>>= 0
+ end >>>= 0
+ thisStart >>>= 0
+ thisEnd >>>= 0
+
+ if (this === target) return 0
- if (this.length === 0) return -1
- if (byteOffset >= this.length) return -1
+ 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
+ }
+ }
- // Negative offsets start from the end of the buffer
- if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)
+ 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
}
-// `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.includes = function includes (val, byteOffset, encoding) {
+ return this.indexOf(val, byteOffset, encoding) !== -1
}
-// `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.indexOf = function indexOf (val, byteOffset, encoding) {
+ return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
+}
+
+Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
+ return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
}
function hexWrite (buf, string, offset, length) {
@@ -8663,14 +9576,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
@@ -8684,7 +9597,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)
}
@@ -8719,17 +9632,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'
@@ -8747,8 +9659,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
@@ -8883,17 +9796,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
@@ -8906,7 +9819,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
@@ -8944,17 +9857,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
}
@@ -9123,16 +10035,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
@@ -9148,7 +10063,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
@@ -9171,7 +10089,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
}
@@ -9205,7 +10123,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
}
}
@@ -9251,9 +10169,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
}
@@ -9271,9 +10192,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
}
@@ -9348,9 +10272,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) {
@@ -9415,143 +10338,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
+ }
- if (end < start) throw new RangeError('end < start')
+ // 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) {
+ 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) {
@@ -9583,7 +10454,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
@@ -9615,7 +10486,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)
@@ -9658,7 +10529,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)
}
@@ -9668,7 +10539,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)
@@ -9686,3062 +10557,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)
+function isnan (val) {
+ return val !== val // eslint-disable-line no-self-compare
}
-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;
-}
-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.
//
@@ -12766,1014 +10857,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];
+function isArray(arg) {
+ if (Array.isArray) {
+ return Array.isArray(arg);
}
- 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];
- }
-
- 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;
@@ -13813,7 +10902,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;
@@ -13823,13 +10912,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;
@@ -13848,1008 +10936,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')
@@ -14905,7 +10999,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;
@@ -14942,7 +11036,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
@@ -15099,1142 +11193,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');
@@ -16306,3866 +11265,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;
+ listeners = this._events[type];
-/**
- * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
- * of values.
- */
-var objToString = objectProto.toString;
+ 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];
-/** Used to detect if a method is native. */
-var reIsNative = RegExp('^' +
- fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
- .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
-);
+ return this;
+};
-/**
- * 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;
-}
+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 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.listenerCount = function(type) {
+ if (this._events) {
+ var evlistener = this._events[type];
-/**
- * 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(evlistener))
+ return 1;
+ else if (evlistener)
+ return evlistener.length;
}
- if (isFunction(value)) {
- return reIsNative.test(fnToString.call(value));
- }
- 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;
-
-},{}],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 + '');
-}
+},{"./chrome/chrome_shim":34,"./edge/edge_shim":36,"./firefox/firefox_shim":38,"./safari/safari_shim":40,"./utils":41}],34:[function(require,module,exports){
-/**
- * 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.
- */
-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;
-
-},{"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>
+ * 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.
*/
-var arrayMap = require('lodash._arraymap'),
- baseCallback = require('lodash._basecallback'),
- baseEach = require('lodash._baseeach'),
- isArray = require('lodash.isarray');
+ /* eslint-env node */
+'use strict';
+var logging = require('../utils.js').log;
+var browserDetails = require('../utils.js').browserDetails;
-/**
- * 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 chromeShim = {
+ shimMediaStream: function() {
+ window.MediaStream = window.MediaStream || window.webkitMediaStream;
+ },
-/**
- * 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) : [];
+ 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));
+ }
+ });
+ }
+ },
- baseEach(collection, function(value, key, collection) {
- result[++index] = iteratee(value, key, collection);
- });
- return result;
-}
+ 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);
+ }
+
+ 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;
-
- 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);
-}
+ navigator.getUserMedia = getUserMedia_;
-/**
- * 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 = []);
-
- var length = stackA.length;
- while (length--) {
- if (stackA[length] == object) {
- return stackB[length] == other;
- }
- }
- // 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();
-
- return result;
-}
-
-/**
- * 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;
-
- 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;
+ /* eslint-env node */
+'use strict';
- if (result !== undefined) {
- if (result) {
- continue;
+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;
+ };
}
- 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;
+ // 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;
+ };
}
- } 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;
-
- 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;
-}
-
-/**
- * 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;
-
- 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;
-
- // 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;
-
- // 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;
-}
-
-/**
- * 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 = baseIsEqual;
-
-},{"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>
- */
-
-/** `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]';
-
-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]';
-
-/** 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;
-
-/**
- * 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 [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
- * of values.
- */
-var objToString = objectProto.toString;
-
-/**
- * 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;
-
-/**
- * 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;
-}
-
-/**
- * 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)];
-}
-
-module.exports = isTypedArray;
-
-},{}],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');
-
-/**
- * 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');
-}
-
-/**
- * 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);
-
- var index = -1,
- props = keys(object),
- length = props.length,
- result = Array(length);
-
- while (++index < length) {
- var key = props[index];
- result[index] = [key, object[key]];
- }
- return result;
-}
-
-module.exports = pairs;
-
-},{"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');
-
-
-// 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;
+ window.RTCPeerConnection = function(config) {
+ var self = this;
-// Conversion from SDP to JSON
+ var _eventTarget = document.createDocumentFragment();
+ ['addEventListener', 'removeEventListener', 'dispatchEvent']
+ .forEach(function(method) {
+ self[method] = _eventTarget[method].bind(_eventTarget);
+ });
-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.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;
+ };
-},{"./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;
- });
-};
+ this.localDescription = new RTCSessionDescription({
+ type: '',
+ sdp: ''
+ });
+ this.remoteDescription = new RTCSessionDescription({
+ type: '',
+ sdp: ''
+ });
+ this.signalingState = 'stable';
+ this.iceConnectionState = 'new';
+ this.iceGatheringState = 'new';
-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];
+ 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;
}
- }
- // Continue searching in parent session section
- if (!sessionLines) {
- 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;
+ });
+ }
- for (var j = 0; j < sessionLines.length; j++) {
- if (sessionLines[j].substr(0, prefixLength) === prefix) {
- return sessionLines[j];
- }
- }
+ // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ...
+ // everything that is needed to describe a SDP m-line.
+ this.transceivers = [];
- 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 = [];
+ };
-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]);
+ 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';
}
- }
- 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]);
+ self.localDescription.sdp = sections.join('');
+ self.dispatchEvent(event);
+ if (self.onicecandidate !== null) {
+ self.onicecandidate(event);
}
- }
- 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 (!event.candidate && self.iceGatheringState !== 'complete') {
+ var complete = self.transceivers.every(function(transceiver) {
+ return transceiver.iceGatherer &&
+ transceiver.iceGatherer.state === 'completed';
+ });
+ if (complete) {
+ self.iceGatheringState = 'complete';
+ }
}
- }
- return parsed;
-};
+ });
+ this._localIceCandidatesBuffer = [];
+ };
-exports.rtpmap = function (line) {
- var parts = line.substr(9).split(' ');
- var parsed = {
- id: parts.shift()
+ 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();
};
- parts = parts[0].split('/');
+ window.RTCPeerConnection.prototype.removeStream = function(stream) {
+ var idx = this.localStreams.indexOf(stream);
+ if (idx > -1) {
+ this.localStreams.splice(idx, 1);
+ this._maybeFireNegotiationNeeded();
+ }
+ };
- parsed.name = parts[0];
- parsed.clockrate = parts[1];
- parsed.channels = parts.length == 3 ? parts[2] : '1';
- return parsed;
-};
+ window.RTCPeerConnection.prototype.getSenders = function() {
+ return this.transceivers.filter(function(transceiver) {
+ return !!transceiver.rtpSender;
+ })
+ .map(function(transceiver) {
+ return transceiver.rtpSender;
+ });
+ };
-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()
+ window.RTCPeerConnection.prototype.getReceivers = function() {
+ return this.transceivers.filter(function(transceiver) {
+ return !!transceiver.rtpReceiver;
+ })
+ .map(function(transceiver) {
+ return transceiver.rtpReceiver;
+ });
};
- return parsed;
-};
+ // 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;
+ }
+ }
+ });
-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;
-};
+ 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;
+ }
+ }
+ });
-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;
-};
+ // FIXME: fecMechanisms
+ return commonCapabilities;
+ };
-exports.fingerprint = function (line) {
- var parts = line.substr(14).split(' ');
- return {
- hash: parts[0],
- value: parts[1]
- };
-};
+ // 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';
+ }
-exports.extmap = function (line) {
- var parts = line.substr(9).split(' ');
- var parsed = {};
+ // 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 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';
- }
+ // 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('');
- parsed.uri = parts.shift() || '';
+ var complete = self.transceivers.every(function(transceiver) {
+ return transceiver.iceGatherer &&
+ transceiver.iceGatherer.state === 'completed';
+ });
- return parsed;
-};
+ // 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();
+ };
-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;
-};
+ 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();
+ };
-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(' ');
- }
+ return {
+ iceGatherer: iceGatherer,
+ iceTransport: iceTransport,
+ dtlsTransport: dtlsTransport
+ };
+ };
- 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'
+ // 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);
+ }
};
- 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];
- }
- }
+ 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';
+ }
- candidate.network = '1';
+ if (!self.usingBundle || sdpMLineIndex === 0) {
+ iceTransport.start(iceGatherer, remoteIceParameters,
+ isIceLite ? 'controlling' : 'controlled');
+ dtlsTransport.start(remoteDtlsParameters);
+ }
- return candidate;
-};
+ // Calculate intersection of capabilities.
+ var params = self._getCommonCapabilities(localCapabilities,
+ remoteCapabilities);
-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;
-};
+ // Start the RTCRtpSender. The RTCRtpReceiver for this
+ // transceiver has already been started in setRemoteDescription.
+ self._transceive(transceiver,
+ params.codecs.length > 0,
+ false);
+ }
+ });
+ }
-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();
+ 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 (!sources[ssrc]) {
- var source = {
- ssrc: ssrc,
- parameters: []
- };
- parsed.push(source);
+ // 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;
+ };
- // Keep an index
- sources[ssrc] = source;
- }
+ 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);
+
+ var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:');
+ if (mid.length) {
+ mid = mid[0].substr(6);
+ } else {
+ mid = SDPUtils.generateIdentifier();
+ }
+
+ 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);
+ }
- parts = parts.join(' ').split(':');
- var attribute = parts.shift();
- var value = parts.join(':') || null;
+ 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);
+ }
- sources[ssrc].parameters.push({
- key: attribute,
- value: value
- });
- }
+ 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);
+ }
- return parsed;
-};
+ self._transceive(transceiver,
+ direction === 'sendrecv' || direction === 'recvonly',
+ direction === 'sendrecv' || direction === 'sendonly');
-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;
-};
+ 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.bandwidth = function (line) {
- var parts = line.substr(2).split(':');
- var parsed = {};
- parsed.type = parts.shift();
- parsed.bandwidth = parts.shift();
- return parsed;
-};
+ 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);
+ }
-exports.msid = function (line) {
- var data = line.substr(7);
- var parts = data.split(' ');
- return {
- msid: data,
- mslabel: parts[0],
- label: parts[1]
- };
-};
+ 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();
+ };
-},{}],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'
+ window.RTCPeerConnection.prototype.close = function() {
+ this.transceivers.forEach(function(transceiver) {
+ /* not yet
+ if (transceiver.iceGatherer) {
+ transceiver.iceGatherer.close();
}
- },
- 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 (transceiver.iceTransport) {
+ transceiver.iceTransport.stop();
}
- }
-};
-
-},{}],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 (transceiver.dtlsTransport) {
+ transceiver.dtlsTransport.stop();
}
- }
- 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);
- }
+ if (transceiver.rtpSender) {
+ transceiver.rtpSender.stop();
+ }
+ if (transceiver.rtpReceiver) {
+ transceiver.rtpReceiver.stop();
+ }
+ });
+ // FIXME: clean up tracks, local streams, remote streams, etc
+ this._updateSignalingState('closed');
+ };
- 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.toMediaJSON = function (media, session, opts) {
- var creator = opts.creator || 'initiator';
- var role = opts.role || 'initiator';
- var direction = opts.direction || 'outgoing';
+ // 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);
+ }
+ };
- var lines = parsers.lines(media);
- var sessionLines = parsers.lines(session);
- var mline = parsers.mline(lines[0]);
+ // 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';
+ }
- var content = {
- creator: creator,
- name: mline.media,
- description: {
- descType: 'rtp',
- media: mline.media,
- payloads: [],
- encryption: [],
- feedback: [],
- headerExtensions: []
- },
- transport: {
- transType: 'iceUdp',
- candidates: [],
- fingerprints: []
+ if (newState !== self.iceConnectionState) {
+ self.iceConnectionState = newState;
+ var event = new Event('iceconnectionstatechange');
+ this.dispatchEvent(event);
+ if (this.oniceconnectionstatechange !== null) {
+ this.oniceconnectionstatechange(event);
}
+ }
};
- 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';
- }
+ 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];
+ }
- if (desc.descType == 'rtp') {
- var bandwidth = parsers.findLine('b=', lines);
- if (bandwidth) {
- desc.bandwidth = parsers.bandwidth(bandwidth);
+ 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.');
}
-
- var ssrc = parsers.findLine('a=ssrc:', lines);
- if (ssrc) {
- desc.ssrc = ssrc.substr(7).split(' ')[0];
+ if (offerOptions.offerToReceiveAudio !== undefined) {
+ numAudioTracks = offerOptions.offerToReceiveAudio;
}
-
- 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;
+ if (offerOptions.offerToReceiveVideo !== undefined) {
+ numVideoTracks = offerOptions.offerToReceiveVideo;
}
-
- var fbLines = parsers.findLines('a=rtcp-fb:*', lines);
- fbLines.forEach(function (line) {
- desc.feedback.push(parsers.rtcpfb(line));
+ }
+ 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 extLines = parsers.findLines('a=extmap:', lines);
- extLines.forEach(function (line) {
- var ext = parsers.extmap(line);
-
- ext.senders = SENDERS[role][direction][ext.senders];
+ 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]);
+ });
- desc.headerExtensions.push(ext);
- });
+ 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);
+ };
- var ssrcGroupLines = parsers.findLines('a=ssrc-group:', lines);
- desc.sourceGroups = parsers.sourceGroups(ssrcGroupLines || []);
+ window.RTCPeerConnection.prototype.createAnswer = function() {
+ var self = this;
- var ssrcLines = parsers.findLines('a=ssrc:', lines);
- var sources = desc.sources = parsers.sources(ssrcLines || []);
+ 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 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 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 (parsers.findLine('a=x-google-flag:conference', lines, sessionLines)) {
- desc.googConferenceFlag = true;
+ 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);
- // 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);
+ // 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('');
}
- 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 = [];
+ }
+ if (arguments.length > 1 && typeof arguments[1] === 'function') {
+ window.setTimeout(arguments[1], 0);
+ }
+ return Promise.resolve();
+ };
- var candidateLines = parsers.findLines('a=candidate:', lines, sessionLines);
- candidateLines.forEach(function (line) {
- trans.candidates.push(exports.toCandidateJSON(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());
+ }
+ });
+ });
+ 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);
});
- }
+ });
+ };
+ },
- 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';
+var logging = require('../utils').log;
+var browserDetails = require('../utils').browserDetails;
- // the detected firefox version.
- webrtcDetectedVersion = webrtcUtils.extractVersion(navigator.userAgent,
- /Firefox\/([0-9]+)\./, 1);
-
- // the minimum firefox version still supported by adapter.
- webrtcMinimumVersion = 31;
-
- // 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;
}
@@ -20182,7 +13870,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;
}
@@ -20208,40 +13896,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);
@@ -20254,1177 +13950,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');
@@ -21432,25 +14646,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;
}
@@ -21462,7 +14676,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');
@@ -21479,11 +14693,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);
@@ -21542,9 +14757,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;
}
@@ -21566,16 +14781,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');
@@ -21667,7 +14895,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;
@@ -21696,7 +14924,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;
@@ -21733,17 +14961,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',
@@ -21760,7 +14983,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();
@@ -21772,13 +14995,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 () {
@@ -21922,7 +15157,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 || [];
@@ -21931,15 +15166,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));
});
});
@@ -21972,7 +15207,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 || [];
@@ -21981,7 +15216,7 @@ MediaSession.prototype = extend(MediaSession.prototype, {
return;
}
- var newContentDesc = newContent.description;
+ var newContentDesc = newContent.application;
var newSSRCs = newContentDesc.sources || [];
var newGroups = newContentDesc.sourceGroups || [];
@@ -21998,7 +15233,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));
}
}
@@ -22023,7 +15258,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));
}
}
});
@@ -22049,75 +15284,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');
@@ -22163,7 +15343,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;
@@ -22463,8 +15643,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
@@ -22472,18 +15652,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 () {
@@ -22492,12 +15686,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 ////
@@ -22508,37 +15709,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;
- };
+ }
+
+ function _map(arr, iterator) {
+ var index = -1,
+ length = arr.length,
+ result = Array(length);
- var _reduce = function (arr, iterator, memo) {
- if (arr.reduce) {
- return arr.reduce(iterator, memo);
+ 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)) {
@@ -22548,191 +15778,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);
@@ -22741,118 +16027,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) {
@@ -22869,147 +16143,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));
@@ -23017,260 +16350,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);
- };
-
- 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);
- });
- }
+ _parallel(_eachOfLimit(limit), tasks, callback);
+ };
+
+ 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 () {
@@ -23279,75 +16606,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
@@ -23355,7 +16692,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
@@ -23365,93 +16702,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');
@@ -23461,123 +16732,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;
});
@@ -23589,284 +16911,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', {
@@ -23891,7 +17351,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', {
@@ -24035,7 +17495,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', {
@@ -24127,712 +17587,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;
-
-exports.toUnicode = punycode.toUnicode;
+ var Addresses = Utils.subMultiExtension(_xmppConstants.Namespace.ADDRESS, 'addresses', Address);
-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'];
@@ -24900,7 +17695,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', {
@@ -24929,7 +17724,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', {
@@ -24948,14 +17743,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;
@@ -24965,8 +17760,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);
});
}
@@ -25006,7 +17801,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', {
@@ -25038,7 +17833,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', {
@@ -25079,7 +17874,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', {
@@ -25158,7 +17953,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', {
@@ -25217,7 +18012,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', {
@@ -25303,7 +18098,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', {
@@ -25341,7 +18136,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', {
@@ -25640,7 +18435,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', {
@@ -25670,7 +18465,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', {
@@ -25758,7 +18553,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', {
@@ -25837,7 +18632,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', {
@@ -25893,7 +18688,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', {
@@ -25945,9 +18836,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)
}
@@ -25969,7 +18860,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', {
@@ -25986,15 +18877,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);
@@ -26003,7 +18903,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', {
@@ -26043,7 +18943,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', {
@@ -26093,7 +18993,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', {
@@ -26117,7 +19017,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', {
@@ -26147,7 +19047,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', {
@@ -26166,7 +19202,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')
}
@@ -26240,7 +19276,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'];
@@ -26249,6 +19285,10 @@ Object.defineProperty(exports, '__esModule', {
value: true
});
+var _addresses = require('./addresses');
+
+var _addresses2 = _interopRequireDefault(_addresses);
+
var _avatar = require('./avatar');
var _avatar2 = _interopRequireDefault(_avatar);
@@ -26309,6 +19349,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);
@@ -26333,6 +19377,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);
@@ -26487,6 +19535,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']);
@@ -26502,12 +19551,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']);
@@ -26550,7 +19601,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'];
@@ -26621,7 +19672,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', {
@@ -26656,7 +19707,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', {
@@ -26680,7 +19731,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;
+ }
+ }
}
});
@@ -26693,10 +19777,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;
});
@@ -26708,7 +19792,7 @@ exports['default'] = function (JXT) {
},
set: function set(value) {
- var ext = '_' + value.descType;
+ var ext = '_' + value.applicationType;
this[ext] = value;
}
},
@@ -26727,7 +19811,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;
}
}
@@ -26768,7 +19871,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', {
@@ -26809,7 +19912,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', {
@@ -26859,7 +19962,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', {
@@ -26986,7 +20089,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', {
@@ -27050,7 +20153,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', {
@@ -27079,7 +20182,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', {
@@ -27360,7 +20463,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', {
@@ -27391,7 +20494,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', {
@@ -27417,7 +20520,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', {
@@ -27439,7 +20542,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', {
@@ -27535,7 +20638,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', {
@@ -27557,7 +20660,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', {
@@ -27586,7 +20689,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', {
@@ -27727,6 +20830,7 @@ exports['default'] = function (JXT) {
element: 'unsubscribe',
fields: {
node: Utils.attribute('node'),
+ subid: Utils.attribute('subid'),
jid: Utils.jidAttribute('jid')
}
});
@@ -27804,7 +20908,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', {
@@ -27836,7 +20940,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', {
@@ -27979,7 +21083,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', {
@@ -28094,7 +21198,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', {
@@ -28144,7 +21248,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'];
@@ -28228,7 +21332,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', {
@@ -28284,7 +21388,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', {
@@ -28343,7 +21447,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', {
@@ -28388,7 +21492,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', {
@@ -28468,9 +21572,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'),
@@ -28704,7 +21808,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', {
@@ -28816,7 +21920,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', {
@@ -28936,7 +22040,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', {
@@ -28963,7 +22067,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', {
@@ -29020,7 +22124,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', {
@@ -29118,7 +22222,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', {
@@ -29147,7 +22251,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', {
@@ -29213,7 +22317,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', {
@@ -29249,7 +22353,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', {
@@ -29275,7 +22379,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', {
@@ -29309,7 +22413,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', {
@@ -29427,7 +22531,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', {
@@ -29454,7 +22558,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', {
@@ -29474,225 +22578,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');
@@ -29764,11 +22654,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);
};
@@ -29872,16 +22761,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);
}
@@ -30153,7 +23053,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');
@@ -30205,7 +23105,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;
@@ -30239,7 +23139,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) {
@@ -30248,7 +23152,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);
@@ -30269,7 +23173,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';
@@ -30658,7 +23562,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);
});
@@ -30668,89 +23574,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 ./`
@@ -30779,7 +23636,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 ./`
@@ -30813,7 +23670,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 ./`
@@ -30867,9 +23974,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 ./`
@@ -31003,7 +24247,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 ./`
@@ -31072,322 +26865,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
+
+exports.createElement = createElement
-var util = require('util')
- , Element = require('./element').Element
+exports.escapeXML = escape.escapeXML
+exports.unescapeXML = escape.unescapeXML
+exports.escapeXMLText = escape.escapeXMLText
+exports.unescapeXMLText = escape.unescapeXMLText
-function DOMElement(name, attrs) {
- Element.call(this, name, attrs)
+exports.Parser = Parser
+exports.parse = parse
- this.nodeType = 1
- this.nodeName = this.localName
+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
}
/**
@@ -31395,537 +27244,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)
+
+ return this
+}
+
+Element.prototype.clone = function () {
+ return clone(this)
+}
- this.children = this.children.filter(filter)
+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]
}
-Element.prototype.attr = function(attr, val) {
- if (((typeof val !== 'undefined') || (val === null))) {
- if (!this.attrs) {
- this.attrs = {}
+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);
+ });
+ }
+}
+
+}).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;
}
- this.attrs[attr] = val
- return this
+ } 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);
}
- return this.attrs[attr]
+ // if setTimeout wasn't available but was latter defined
+ if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
+ cachedSetTimeout = setTimeout;
+ return setTimeout(fun, 0);
+ }
+ try {
+ // when when somebody has screwed with setTimeout but no I.E. maddness
+ return cachedSetTimeout(fun, 0);
+ } catch(e){
+ try {
+ // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+ return cachedSetTimeout.call(null, fun, 0);
+ } catch(e){
+ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
+ return cachedSetTimeout.call(this, fun, 0);
+ }
+ }
+
+
}
+function runClearTimeout(marker) {
+ if (cachedClearTimeout === clearTimeout) {
+ //normal enviroments in sane situations
+ return clearTimeout(marker);
+ }
+ // if clearTimeout wasn't available but was latter defined
+ if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
+ cachedClearTimeout = clearTimeout;
+ return clearTimeout(marker);
+ }
+ try {
+ // when when somebody has screwed with setTimeout but no I.E. maddness
+ return cachedClearTimeout(marker);
+ } catch (e){
+ try {
+ // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+ return cachedClearTimeout.call(null, marker);
+ } catch (e){
+ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
+ // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+ return cachedClearTimeout.call(this, marker);
+ }
+ }
+
-/*** 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');
+};
-parse.availableSaxParsers.push(parse.bestSaxParser = require('./sax/sax_ltx'))
+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');
+
+ 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;
+};
-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')
+// 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);
}
- this.parser = new ParserMod()
+ }
- var el
- this.parser.addListener('startElement', function(name, attrs) {
- var child = new DOMElement(name, attrs)
- if (!el) {
- el = child
+ 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 {
- el = el.cnode(child)
- }
- })
- 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
- }
- }
- /* jshint +W035 */
- })
- this.parser.addListener('text', function(str) {
- if (el) {
- el.t(str)
+ str = '\n' + str.split('\n').map(function(line) {
+ return ' ' + line;
+ }).join('\n');
}
- })
- this.parser.addListener('error', function(e) {
- self.error = e
- self.emit('error', e)
- })
+ }
+ } 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;
+ };
}
-util.inherits(exports.Parser, events.EventEmitter)
+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
-exports.Parser.prototype.write = function(data) {
- this.parser.write(data)
+// 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;
}
-exports.Parser.prototype.end = function(data) {
- this.parser.end(data)
+// **`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];
+ }
+ });
- if (!this.error) {
- if (this.tree) {
- this.emit('tree', this.tree)
+ // 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 {
- this.emit('error', new Error('Incomplete document'))
+ // 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;
}
-exports.parse = function(data, saxParser) {
- var p = new exports.Parser(saxParser)
- var result = null
- , error = null
+// Attach a media stream to an element.
+attachMediaStream = function(element, stream) {
+ element.srcObject = stream;
+};
- p.on('tree', function(tree) {
- result = tree
- })
- p.on('error', function(e) {
- error = e
- })
+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');
- p.write(data)
- p.end()
+ webrtcDetectedBrowser = 'firefox';
+
+ // the detected firefox version.
+ webrtcDetectedVersion = webrtcUtils.extractVersion(navigator.userAgent,
+ /Firefox\/([0-9]+)\./, 1);
- if (error) {
- throw error
+ // 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;
+ }
+ }
+ 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;
+ }
+ }
+ });
+ }
+
+ window.RTCSessionDescription = mozRTCSessionDescription;
+ window.RTCIceCandidate = mozRTCIceCandidate;
+ }
+
+ // 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);
+ }
+ };
+ });
+
+ ['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]);
+ }
+ }]
+ );
+ });
+ };
+ });
+
+ // 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 {
+ 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;
+
+ 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: ''};
+ }));
+ });
+ });
+ }};
+ }
+
+ // 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);
+ };
+ }
+
+ // 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.');
+ };
+ }
+
+ // 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');
}
-},{"./dom-element":243,"events":6,"util":28}],248:[function(require,module,exports){
+// 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.
+ };
+ });
+}
+
+},{}],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));
+ }
+ });
+ }
+ },
-var util = require('util')
- , events = require('events')
+ 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);
+ }
+
+ 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);
+ });
+ }
+ });
+ }
+ }
+ },
-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
+ 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 SaxLtx = module.exports = function SaxLtx() {
- events.EventEmitter.call(this)
+ 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;
+ });
- var state = STATE_TEXT, remainder
- var tagName, attrs, endTag, selfClosing, attrQuote
- var recordStart = 0
- var attrName
+ return standardReport;
+ };
- this._handleTagOpening = function(endTag, tagName, attrs) {
- if (!endTag) {
- this.emit('startElement', tagName, attrs)
- if (selfClosing) {
- this.emit('endElement', tagName)
- }
+ // 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);
+ };
- /* Anything from previous write()? */
- if (remainder) {
- data = remainder + data
- pos += remainder.length
- remainder = null
+ 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;
+ };
+ }
+ }
+
+ 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();
+ }
+ };
+
+ window.RTCPeerConnection.prototype.getSenders = function() {
+ return this.transceivers.filter(function(transceiver) {
+ return !!transceiver.rtpSender;
+ })
+ .map(function(transceiver) {
+ return transceiver.rtpSender;
+ });
+ };
- 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.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 STATE_IGNORE_TAG:
- if (c === 62 /* > */) {
- state = STATE_TEXT
+ break;
+ case 'gathering':
+ self._emitBufferedCandidates();
+ self.dispatchEvent(event);
+ if (self.onicecandidate !== null) {
+ self.onicecandidate(event);
}
- 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 (complete) {
+ self.dispatchEvent(new Event('icecandidate'));
+ if (self.onicecandidate !== null) {
+ self.onicecandidate(new Event('icecandidate'));
+ }
+ self.iceGatheringState = 'complete';
}
- break
- case STATE_ATTR_NAME:
- if (c <= 32 || c === 61 /* = */) {
- attrName = endRecording()
- pos--
- state = STATE_ATTR_EQ
+ 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_ATTR_EQ:
- if (c === 61 /* = */) {
- state = STATE_ATTR_QUOT
+ var remoteDtlsParameters = SDPUtils.getDtlsParameters(
+ mediaSection, sessionpart);
+ if (isIceLite) {
+ remoteDtlsParameters.role = 'server';
}
- break
- case STATE_ATTR_QUOT:
- if (c === 34 /* " */ || c === 39 /* ' */) {
- attrQuote = c
- state = STATE_ATTR_VALUE
- recordStart = pos + 1
+
+ if (!self.usingBundle || sdpMLineIndex === 0) {
+ iceTransport.start(iceGatherer, remoteIceParameters,
+ isIceLite ? 'controlling' : 'controlled');
+ 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 = {
+ 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_VALUE:
- if (c === attrQuote) {
- var value = unescapeXml(endRecording())
- attrs[attrName] = value
- attrName = undefined
- state = STATE_TAG
+ if (localTrack) {
+ rtpSender = new RTCRtpSender(localTrack,
+ transports.dtlsTransport);
}
- break
+ }
+
+ 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);
+ }
+ });
+ }, 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);
+ };
- if (typeof recordStart === 'number' &&
- recordStart <= data.length) {
+ 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);
- remainder = data.slice(recordStart)
- recordStart = 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();
+ };
+
+ 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));
+ }
+ });
}
+ },
- /*var origEmit = this.emit
- this.emit = function() {
- console.log('ltx', arguments)
- origEmit.apply(this, arguments)
- }*/
+ 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);
+ }
+ } 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));
+ });
+ };
+
+ // 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);
+ });
+ };
+
+ 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);
+ };
+};
+
+},{"../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
+};
+
+},{}],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'
+ }
+};
-SaxLtx.prototype.end = function(data) {
- if (data) {
- this.write(data)
+},{}],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
+// ================================================================
- /* Uh, yeah */
- this.write = function() {}
+// 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'
+};
+
+},{}],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'));
@@ -31941,11 +40060,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;
@@ -32022,7 +40145,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) {
@@ -32036,8 +40159,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;
}
@@ -32066,7 +40188,7 @@ 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]);
/*!
@@ -39585,26 +47707,29 @@ CryptoJS.mode.CTR = (function () {
}))
/*!
- * Source: lib/i18next/release/i18next-latest.min.js, license: MIT, url: http://i18next.com/
+ * Source: lib/i18next/i18next.min.js, license: MIT, url: http://i18next.com/
+ */
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.i18next=e()}(this,function(){"use strict";function t(t){return null==t?"":""+t}function e(t,e,n){t.forEach(function(t){e[t]&&(n[t]=e[t])})}function n(t,e,n){function o(t){return t&&t.indexOf("###")>-1?t.replace(/###/g,"."):t}for(var r="string"!=typeof e?[].concat(e):e.split(".");r.length>1;){if(!t)return{};var i=o(r.shift());!t[i]&&n&&(t[i]=new n),t=t[i]}return t?{obj:t,k:o(r.shift())}:{}}function o(t,e,o){var r=n(t,e,Object),i=r.obj,a=r.k;i[a]=o}function r(t,e,o,r){var i=n(t,e,Object),a=i.obj,s=i.k;a[s]=a[s]||[],r&&(a[s]=a[s].concat(o)),r||a[s].push(o)}function i(t,e){var o=n(t,e),r=o.obj,i=o.k;if(r)return r[i]}function a(t,e,n){for(var o in e)o in t?"string"==typeof t[o]||t[o]instanceof String||"string"==typeof e[o]||e[o]instanceof String?n&&(t[o]=e[o]):a(t[o],e[o],n):t[o]=e[o];return t}function s(t){return t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function u(t){return"string"==typeof t?t.replace(/[&<>"'\/]/g,function(t){return R[t]}):t}function l(t){return t.interpolation={unescapeSuffix:"HTML"},t.interpolation.prefix=t.interpolationPrefix||"__",t.interpolation.suffix=t.interpolationSuffix||"__",t.interpolation.escapeValue=t.escapeInterpolation||!1,t.interpolation.nestingPrefix=t.reusePrefix||"$t(",t.interpolation.nestingSuffix=t.reuseSuffix||")",t}function c(t){return t.resStore&&(t.resources=t.resStore),t.ns&&t.ns.defaultNs?(t.defaultNS=t.ns.defaultNs,t.ns=t.ns.namespaces):t.defaultNS=t.ns||"translation",t.fallbackToDefaultNS&&t.defaultNS&&(t.fallbackNS=t.defaultNS),t.saveMissing=t.sendMissing,t.saveMissingTo=t.sendMissingTo||"current",t.returnNull=!t.fallbackOnNull,t.returnEmptyString=!t.fallbackOnEmpty,t.returnObjects=t.returnObjectTrees,t.joinArrays="\n",t.returnedObjectHandler=t.objectTreeKeyHandler,t.parseMissingKeyHandler=t.parseMissingKey,t.appendNamespaceToMissingKey=!0,t.nsSeparator=t.nsseparator,t.keySeparator=t.keyseparator,"sprintf"===t.shortcutFunction&&(t.overloadTranslationOptionHandler=function(t){for(var e=[],n=1;n<t.length;n++)e.push(t[n]);return{postProcess:"sprintf",sprintf:e}}),t.whitelist=t.lngWhitelist,t.preload=t.preload,"current"===t.load&&(t.load="currentOnly"),"unspecific"===t.load&&(t.load="languageOnly"),t.backend=t.backend||{},t.backend.loadPath=t.resGetPath||"locales/__lng__/__ns__.json",t.backend.addPath=t.resPostPath||"locales/add/__lng__/__ns__",t.backend.allowMultiLoading=t.dynamicLoad,t.cache=t.cache||{},t.cache.prefix="res_",t.cache.expirationTime=6048e5,t.cache.enabled=!!t.useLocalStorage,t=l(t),t.defaultVariables&&(t.interpolation.defaultVariables=t.defaultVariables),t}function p(t){return t=l(t),t.joinArrays="\n",t}function f(t){return(t.interpolationPrefix||t.interpolationSuffix||t.escapeInterpolation)&&(t=l(t)),t.nsSeparator=t.nsseparator,t.keySeparator=t.keyseparator,t.returnObjects=t.returnObjectTrees,t}function g(t){t.lng=function(){return C.deprecate("i18next.lng() can be replaced by i18next.language for detected language or i18next.languages for languages ordered by translation lookup."),t.services.languageUtils.toResolveHierarchy(t.language)[0]},t.preload=function(e,n){C.deprecate("i18next.preload() can be replaced with i18next.loadLanguages()"),t.loadLanguages(e,n)},t.setLng=function(e,n,o){return C.deprecate("i18next.setLng() can be replaced with i18next.changeLanguage() or i18next.getFixedT() to get a translation function with fixed language or namespace."),"function"==typeof n&&(o=n,n={}),n||(n={}),n.fixLng===!0&&o?o(null,t.getFixedT(e)):void t.changeLanguage(e,o)},t.addPostProcessor=function(e,n){C.deprecate("i18next.addPostProcessor() can be replaced by i18next.use({ type: 'postProcessor', name: 'name', process: fc })"),t.use({type:"postProcessor",name:e,process:n})}}function h(t){return t.charAt(0).toUpperCase()+t.slice(1)}function d(){var t={};return T.forEach(function(e){e.lngs.forEach(function(n){return t[n]={numbers:e.nr,plurals:H[e.fc]}})}),t}function v(t,e){for(var n=t.indexOf(e);n!==-1;)t.splice(n,1),n=t.indexOf(e)}function y(){return{debug:!1,initImmediate:!0,ns:["translation"],defaultNS:["translation"],fallbackLng:["dev"],fallbackNS:!1,whitelist:!1,nonExplicitWhitelist:!1,load:"all",preload:!1,keySeparator:".",nsSeparator:":",pluralSeparator:"_",contextSeparator:"_",saveMissing:!1,saveMissingTo:"fallback",missingKeyHandler:!1,postProcess:!1,returnNull:!0,returnEmptyString:!0,returnObjects:!1,joinArrays:!1,returnedObjectHandler:function(){},parseMissingKeyHandler:!1,appendNamespaceToMissingKey:!1,overloadTranslationOptionHandler:function(t){return{defaultValue:t[1]}},interpolation:{escapeValue:!0,format:function(t,e,n){return t},prefix:"{{",suffix:"}}",formatSeparator:",",unescapePrefix:"-",nestingPrefix:"$t(",nestingSuffix:")",defaultVariables:void 0}}}function b(t){return"string"==typeof t.ns&&(t.ns=[t.ns]),"string"==typeof t.fallbackLng&&(t.fallbackLng=[t.fallbackLng]),"string"==typeof t.fallbackNS&&(t.fallbackNS=[t.fallbackNS]),t.whitelist&&t.whitelist.indexOf("cimode")<0&&t.whitelist.push("cimode"),t}function m(){}var x="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},k=(function(){function t(t){this.value=t}function e(e){function n(t,e){return new Promise(function(n,r){var s={key:t,arg:e,resolve:n,reject:r,next:null};a?a=a.next=s:(i=a=s,o(t,e))})}function o(n,i){try{var a=e[n](i),s=a.value;s instanceof t?Promise.resolve(s.value).then(function(t){o("next",t)},function(t){o("throw",t)}):r(a.done?"return":"normal",a.value)}catch(t){r("throw",t)}}function r(t,e){switch(t){case"return":i.resolve({value:e,done:!0});break;case"throw":i.reject(e);break;default:i.resolve({value:e,done:!1})}i=i.next,i?o(i.key,i.arg):a=null}var i,a;this._invoke=n,"function"!=typeof e.return&&(this.return=void 0)}return"function"==typeof Symbol&&Symbol.asyncIterator&&(e.prototype[Symbol.asyncIterator]=function(){return this}),e.prototype.next=function(t){return this._invoke("next",t)},e.prototype.throw=function(t){return this._invoke("throw",t)},e.prototype.return=function(t){return this._invoke("return",t)},{wrap:function(t){return function(){return new e(t.apply(this,arguments))}},await:function(e){return new t(e)}}}(),function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}),S=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(t[o]=n[o])}return t},w=function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)},O=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e},N=function(){function t(t,e){var n=[],o=!0,r=!1,i=void 0;try{for(var a,s=t[Symbol.iterator]();!(o=(a=s.next()).done)&&(n.push(a.value),!e||n.length!==e);o=!0);}catch(t){r=!0,i=t}finally{try{!o&&s.return&&s.return()}finally{if(r)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),L={type:"logger",log:function(t){this._output("log",t)},warn:function(t){this._output("warn",t)},error:function(t){this._output("error",t)},_output:function(t,e){console&&console[t]&&console[t].apply(console,Array.prototype.slice.call(e))}},j=function(){function t(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};k(this,t),this.init(e,n)}return t.prototype.init=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};this.prefix=e.prefix||"i18next:",this.logger=t||L,this.options=e,this.debug=e.debug!==!1},t.prototype.setDebug=function(t){this.debug=t},t.prototype.log=function(){this.forward(arguments,"log","",!0)},t.prototype.warn=function(){this.forward(arguments,"warn","",!0)},t.prototype.error=function(){this.forward(arguments,"error","")},t.prototype.deprecate=function(){this.forward(arguments,"warn","WARNING DEPRECATED: ",!0)},t.prototype.forward=function(t,e,n,o){o&&!this.debug||("string"==typeof t[0]&&(t[0]=n+this.prefix+" "+t[0]),this.logger[e](t))},t.prototype.create=function(e){var n=new t(this.logger,S({prefix:this.prefix+":"+e+":"},this.options));return n},t}(),C=new j,P=function(){function t(){k(this,t),this.observers={}}return t.prototype.on=function(t,e){var n=this;t.split(" ").forEach(function(t){n.observers[t]=n.observers[t]||[],n.observers[t].push(e)})},t.prototype.off=function(t,e){var n=this;this.observers[t]&&this.observers[t].forEach(function(){if(e){var o=n.observers[t].indexOf(e);o>-1&&n.observers[t].splice(o,1)}else delete n.observers[t]})},t.prototype.emit=function(t){for(var e=arguments.length,n=Array(e>1?e-1:0),o=1;o<e;o++)n[o-1]=arguments[o];this.observers[t]&&this.observers[t].forEach(function(t){t.apply(void 0,n)}),this.observers["*"]&&this.observers["*"].forEach(function(e){var o;e.apply(e,(o=[t]).concat.apply(o,n))})},t}(),R={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;"},E=function(t){function e(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{ns:["translation"],defaultNS:"translation"};k(this,e);var r=O(this,t.call(this));return r.data=n,r.options=o,r}return w(e,t),e.prototype.addNamespaces=function(t){this.options.ns.indexOf(t)<0&&this.options.ns.push(t)},e.prototype.removeNamespaces=function(t){var e=this.options.ns.indexOf(t);e>-1&&this.options.ns.splice(e,1)},e.prototype.getResource=function(t,e,n){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},r=o.keySeparator||this.options.keySeparator;void 0===r&&(r=".");var a=[t,e];return n&&"string"!=typeof n&&(a=a.concat(n)),n&&"string"==typeof n&&(a=a.concat(r?n.split(r):n)),t.indexOf(".")>-1&&(a=t.split(".")),i(this.data,a)},e.prototype.addResource=function(t,e,n,r){var i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{silent:!1},a=this.options.keySeparator;void 0===a&&(a=".");var s=[t,e];n&&(s=s.concat(a?n.split(a):n)),t.indexOf(".")>-1&&(s=t.split("."),r=e,e=s[1]),this.addNamespaces(e),o(this.data,s,r),i.silent||this.emit("added",t,e,n,r)},e.prototype.addResources=function(t,e,n){for(var o in n)"string"==typeof n[o]&&this.addResource(t,e,o,n[o],{silent:!0});this.emit("added",t,e,n)},e.prototype.addResourceBundle=function(t,e,n,r,s){var u=[t,e];t.indexOf(".")>-1&&(u=t.split("."),r=n,n=e,e=u[1]),this.addNamespaces(e);var l=i(this.data,u)||{};r?a(l,n,s):l=S({},l,n),o(this.data,u,l),this.emit("added",t,e,n)},e.prototype.removeResourceBundle=function(t,e){this.hasResourceBundle(t,e)&&delete this.data[t][e],this.removeNamespaces(e),this.emit("removed",t,e)},e.prototype.hasResourceBundle=function(t,e){return void 0!==this.getResource(t,e)},e.prototype.getResourceBundle=function(t,e){return e||(e=this.options.defaultNS),"v1"===this.options.compatibilityAPI?S({},this.getResource(t,e)):this.getResource(t,e)},e.prototype.toJSON=function(){return this.data},e}(P),_={processors:{},addPostProcessor:function(t){this.processors[t.name]=t},handle:function(t,e,n,o,r){var i=this;return t.forEach(function(t){i.processors[t]&&(e=i.processors[t].process(e,n,o,r))}),e}},A=function(t){function n(o){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};k(this,n);var i=O(this,t.call(this));return e(["resourceStore","languageUtils","pluralResolver","interpolator","backendConnector"],o,i),i.options=r,i.logger=C.create("translator"),i}return w(n,t),n.prototype.changeLanguage=function(t){t&&(this.language=t)},n.prototype.exists=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{interpolation:{}};return"v1"===this.options.compatibilityAPI&&(e=f(e)),void 0!==this.resolve(t,e)},n.prototype.extractFromKey=function(t,e){var n=e.nsSeparator||this.options.nsSeparator;void 0===n&&(n=":");var o=e.ns||this.options.defaultNS;if(n&&t.indexOf(n)>-1){var r=t.split(n);o=r[0],t=r[1]}return"string"==typeof o&&(o=[o]),{key:t,namespaces:o}},n.prototype.translate=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if("object"!==("undefined"==typeof e?"undefined":x(e))?e=this.options.overloadTranslationOptionHandler(arguments):"v1"===this.options.compatibilityAPI&&(e=f(e)),void 0===t||null===t||""===t)return"";"number"==typeof t&&(t=String(t)),"string"==typeof t&&(t=[t]);var n=e.lng||this.language;if(n&&"cimode"===n.toLowerCase())return t[t.length-1];var o=e.keySeparator||this.options.keySeparator||".",r=this.extractFromKey(t[t.length-1],e),i=r.key,a=r.namespaces,s=a[a.length-1],u=this.resolve(t,e),l=Object.prototype.toString.apply(u),c=["[object Number]","[object Function]","[object RegExp]"],p=void 0!==e.joinArrays?e.joinArrays:this.options.joinArrays;if(u&&"string"!=typeof u&&c.indexOf(l)<0&&(!p||"[object Array]"!==l)){if(!e.returnObjects&&!this.options.returnObjects)return this.logger.warn("accessing an object - but returnObjects options is not enabled!"),this.options.returnedObjectHandler?this.options.returnedObjectHandler(i,u,e):"key '"+i+" ("+this.language+")' returned an object instead of string.";var g="[object Array]"===l?[]:{};for(var h in u)g[h]=this.translate(""+i+o+h,S({joinArrays:!1,ns:a},e));u=g}else if(p&&"[object Array]"===l)u=u.join(p),u&&(u=this.extendTranslation(u,i,e));else{var d=!1,v=!1;if(this.isValidLookup(u)||void 0===e.defaultValue||(d=!0,u=e.defaultValue),this.isValidLookup(u)||(v=!0,u=i),v||d){this.logger.log("missingKey",n,s,i,u);var y=[],b=this.languageUtils.getFallbackCodes(this.options.fallbackLng,e.lng||this.language);if("fallback"===this.options.saveMissingTo&&b&&b[0])for(var m=0;m<b.length;m++)y.push(b[m]);else"all"===this.options.saveMissingTo?y=this.languageUtils.toResolveHierarchy(e.lng||this.language):y.push(e.lng||this.language);this.options.saveMissing&&(this.options.missingKeyHandler?this.options.missingKeyHandler(y,s,i,u):this.backendConnector&&this.backendConnector.saveMissing&&this.backendConnector.saveMissing(y,s,i,u)),this.emit("missingKey",y,s,i,u)}u=this.extendTranslation(u,i,e),v&&u===i&&this.options.appendNamespaceToMissingKey&&(u=s+":"+i),v&&this.options.parseMissingKeyHandler&&(u=this.options.parseMissingKeyHandler(u))}return u},n.prototype.extendTranslation=function(t,e,n){var o=this;n.interpolation&&this.interpolator.init(S({},n,{interpolation:S({},this.options.interpolation,n.interpolation)}));var r=n.replace&&"string"!=typeof n.replace?n.replace:n;this.options.interpolation.defaultVariables&&(r=S({},this.options.interpolation.defaultVariables,r)),t=this.interpolator.interpolate(t,r,this.language),t=this.interpolator.nest(t,function(){for(var t=arguments.length,e=Array(t),n=0;n<t;n++)e[n]=arguments[n];return o.translate.apply(o,e)},n),n.interpolation&&this.interpolator.reset();var i=n.postProcess||this.options.postProcess,a="string"==typeof i?[i]:i;return void 0!==t&&a&&a.length&&n.applyPostProcessor!==!1&&(t=_.handle(a,t,e,n,this)),t},n.prototype.resolve=function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=void 0;return"string"==typeof t&&(t=[t]),t.forEach(function(t){if(!e.isValidLookup(o)){var r=e.extractFromKey(t,n),i=r.key,a=r.namespaces;e.options.fallbackNS&&(a=a.concat(e.options.fallbackNS));var s=void 0!==n.count&&"string"!=typeof n.count,u=void 0!==n.context&&"string"==typeof n.context&&""!==n.context,l=n.lngs?n.lngs:e.languageUtils.toResolveHierarchy(n.lng||e.language);a.forEach(function(t){e.isValidLookup(o)||l.forEach(function(r){if(!e.isValidLookup(o)){var a=i,l=[a],c=void 0;s&&(c=e.pluralResolver.getSuffix(r,n.count)),s&&u&&l.push(a+c),u&&l.push(a+=""+e.options.contextSeparator+n.context),s&&l.push(a+=c);for(var p=void 0;p=l.pop();)e.isValidLookup(o)||(o=e.getResource(r,t,p,n))}})})}}),o},n.prototype.isValidLookup=function(t){return!(void 0===t||!this.options.returnNull&&null===t||!this.options.returnEmptyString&&""===t)},n.prototype.getResource=function(t,e,n){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};return this.resourceStore.getResource(t,e,n,o)},n}(P),M=function(){function t(e){k(this,t),this.options=e,this.whitelist=this.options.whitelist||!1,this.logger=C.create("languageUtils")}return t.prototype.getLanguagePartFromCode=function(t){if(t.indexOf("-")<0)return t;var e=["NB-NO","NN-NO","nb-NO","nn-NO","nb-no","nn-no"],n=t.split("-");return this.formatLanguageCode(e.indexOf(t)>-1?n[1].toLowerCase():n[0])},t.prototype.getScriptPartFromCode=function(t){if(t.indexOf("-")<0)return null;var e=t.split("-");return 2===e.length?null:(e.pop(),this.formatLanguageCode(e.join("-")))},t.prototype.getLanguagePartFromCode=function(t){if(t.indexOf("-")<0)return t;var e=["NB-NO","NN-NO","nb-NO","nn-NO","nb-no","nn-no"],n=t.split("-");return this.formatLanguageCode(e.indexOf(t)>-1?n[1].toLowerCase():n[0])},t.prototype.formatLanguageCode=function(t){if("string"==typeof t&&t.indexOf("-")>-1){var e=["hans","hant","latn","cyrl","cans","mong","arab"],n=t.split("-");return this.options.lowerCaseLng?n=n.map(function(t){return t.toLowerCase()}):2===n.length?(n[0]=n[0].toLowerCase(),n[1]=n[1].toUpperCase(),e.indexOf(n[1].toLowerCase())>-1&&(n[1]=h(n[1].toLowerCase()))):3===n.length&&(n[0]=n[0].toLowerCase(),2===n[1].length&&(n[1]=n[1].toUpperCase()),"sgn"!==n[0]&&2===n[2].length&&(n[2]=n[2].toUpperCase()),e.indexOf(n[1].toLowerCase())>-1&&(n[1]=h(n[1].toLowerCase())),e.indexOf(n[2].toLowerCase())>-1&&(n[2]=h(n[2].toLowerCase()))),n.join("-")}return this.options.cleanCode||this.options.lowerCaseLng?t.toLowerCase():t},t.prototype.isWhitelisted=function(t,e){return("languageOnly"===this.options.load||this.options.nonExplicitWhitelist&&!e)&&(t=this.getLanguagePartFromCode(t)),!this.whitelist||!this.whitelist.length||this.whitelist.indexOf(t)>-1},t.prototype.getFallbackCodes=function(t,e){if(!t)return[];if("string"==typeof t&&(t=[t]),"[object Array]"===Object.prototype.toString.apply(t))return t;var n=t[e];return n||(n=t[this.getScriptPartFromCode(e)]),n||(n=t[this.formatLanguageCode(e)]),n||(n=t.default),n||[]},t.prototype.toResolveHierarchy=function(t,e){var n=this,o=this.getFallbackCodes(e||this.options.fallbackLng||[],t),r=[],i=function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];t&&(n.isWhitelisted(t,e)?r.push(t):n.logger.warn("rejecting non-whitelisted language code: "+t))};return"string"==typeof t&&t.indexOf("-")>-1?("languageOnly"!==this.options.load&&i(this.formatLanguageCode(t),!0),"languageOnly"!==this.options.load&&"currentOnly"!==this.options.load&&i(this.getScriptPartFromCode(t),!0),"currentOnly"!==this.options.load&&i(this.getLanguagePartFromCode(t))):"string"==typeof t&&i(this.formatLanguageCode(t)),o.forEach(function(t){r.indexOf(t)<0&&i(n.formatLanguageCode(t))}),r},t}(),T=[{lngs:["ach","ak","am","arn","br","fil","gun","ln","mfe","mg","mi","oc","tg","ti","tr","uz","wa"],nr:[1,2],fc:1},{lngs:["af","an","ast","az","bg","bn","ca","da","de","dev","el","en","eo","es","es_ar","et","eu","fi","fo","fur","fy","gl","gu","ha","he","hi","hu","hy","ia","it","kn","ku","lb","mai","ml","mn","mr","nah","nap","nb","ne","nl","nn","no","nso","pa","pap","pms","ps","pt","pt_br","rm","sco","se","si","so","son","sq","sv","sw","ta","te","tk","ur","yo"],nr:[1,2],fc:2},{lngs:["ay","bo","cgg","fa","id","ja","jbo","ka","kk","km","ko","ky","lo","ms","sah","su","th","tt","ug","vi","wo","zh"],nr:[1],fc:3},{lngs:["be","bs","dz","hr","ru","sr","uk"],nr:[1,2,5],fc:4},{lngs:["ar"],nr:[0,1,2,3,11,100],fc:5},{lngs:["cs","sk"],nr:[1,2,5],fc:6},{lngs:["csb","pl"],nr:[1,2,5],fc:7},{lngs:["cy"],nr:[1,2,3,8],fc:8},{lngs:["fr"],nr:[1,2],fc:9},{lngs:["ga"],nr:[1,2,3,7,11],fc:10},{lngs:["gd"],nr:[1,2,3,20],fc:11},{lngs:["is"],nr:[1,2],fc:12},{lngs:["jv"],nr:[0,1],fc:13},{lngs:["kw"],nr:[1,2,3,4],fc:14},{lngs:["lt"],nr:[1,2,10],fc:15},{lngs:["lv"],nr:[1,2,0],fc:16},{lngs:["mk"],nr:[1,2],fc:17},{lngs:["mnk"],nr:[0,1,2],fc:18},{lngs:["mt"],nr:[1,2,11,20],fc:19},{lngs:["or"],nr:[2,1],fc:2},{lngs:["ro"],nr:[1,2,20],fc:20},{lngs:["sl"],nr:[5,1,2,3],fc:21}],H={1:function(t){return Number(t>1)},2:function(t){return Number(1!=t)},3:function(t){return 0},4:function(t){return Number(t%10==1&&t%100!=11?0:t%10>=2&&t%10<=4&&(t%100<10||t%100>=20)?1:2)},5:function(t){return Number(0===t?0:1==t?1:2==t?2:t%100>=3&&t%100<=10?3:t%100>=11?4:5)},6:function(t){return Number(1==t?0:t>=2&&t<=4?1:2)},7:function(t){return Number(1==t?0:t%10>=2&&t%10<=4&&(t%100<10||t%100>=20)?1:2)},8:function(t){return Number(1==t?0:2==t?1:8!=t&&11!=t?2:3)},9:function(t){return Number(t>=2)},10:function(t){return Number(1==t?0:2==t?1:t<7?2:t<11?3:4)},11:function(t){return Number(1==t||11==t?0:2==t||12==t?1:t>2&&t<20?2:3)},12:function(t){return Number(t%10!=1||t%100==11)},13:function(t){return Number(0!==t)},14:function(t){return Number(1==t?0:2==t?1:3==t?2:3)},15:function(t){return Number(t%10==1&&t%100!=11?0:t%10>=2&&(t%100<10||t%100>=20)?1:2)},16:function(t){return Number(t%10==1&&t%100!=11?0:0!==t?1:2)},17:function(t){return Number(1==t||t%10==1?0:1)},18:function(t){return Number(0==t?0:1==t?1:2)},19:function(t){return Number(1==t?0:0===t||t%100>1&&t%100<11?1:t%100>10&&t%100<20?2:3)},20:function(t){return Number(1==t?0:0===t||t%100>0&&t%100<20?1:2)},21:function(t){return Number(t%100==1?1:t%100==2?2:t%100==3||t%100==4?3:0)}},U=function(){function t(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};k(this,t),this.languageUtils=e,this.options=n,this.logger=C.create("pluralResolver"),this.rules=d()}return t.prototype.addRule=function(t,e){this.rules[t]=e},t.prototype.getRule=function(t){return this.rules[this.languageUtils.getLanguagePartFromCode(t)]},t.prototype.needsPlural=function(t){var e=this.getRule(t);return!(e&&e.numbers.length<=1)},t.prototype.getSuffix=function(t,e){var n=this,o=this.getRule(t);if(!o)return this.logger.warn("no plural rule found for: "+t),"";var r=function(){if(1===o.numbers.length)return{v:""};var t=o.noAbs?o.plurals(e):o.plurals(Math.abs(e)),r=o.numbers[t];2===o.numbers.length&&1===o.numbers[0]&&(2===r?r="plural":1===r&&(r=""));var i=function(){return n.options.prepend&&r.toString()?n.options.prepend+r.toString():r.toString()};return"v1"===n.options.compatibilityJSON?1===r?{v:""}:"number"==typeof r?{v:"_plural_"+r.toString()}:{v:i()}:"v2"===n.options.compatibilityJSON||2===o.numbers.length&&1===o.numbers[0]?{v:i()}:2===o.numbers.length&&1===o.numbers[0]?{v:i()}:{v:n.options.prepend&&t.toString()?n.options.prepend+t.toString():t.toString()}}();return"object"===("undefined"==typeof r?"undefined":x(r))?r.v:void 0},t}(),V=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};k(this,e),this.logger=C.create("interpolator"),this.init(t,!0)}return e.prototype.init=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=arguments[1];e&&(this.options=t,this.format=t.interpolation&&t.interpolation.format||function(t){return t},this.escape=t.interpolation&&t.interpolation.escape||u),t.interpolation||(t.interpolation={escapeValue:!0});var n=t.interpolation;this.escapeValue=void 0===n.escapeValue||n.escapeValue,this.prefix=n.prefix?s(n.prefix):n.prefixEscaped||"{{",this.suffix=n.suffix?s(n.suffix):n.suffixEscaped||"}}",this.formatSeparator=n.formatSeparator?s(n.formatSeparator):n.formatSeparator||",",this.unescapePrefix=n.unescapeSuffix?"":n.unescapePrefix||"-",this.unescapeSuffix=this.unescapePrefix?"":n.unescapeSuffix||"",this.nestingPrefix=n.nestingPrefix?s(n.nestingPrefix):n.nestingPrefixEscaped||s("$t("),this.nestingSuffix=n.nestingSuffix?s(n.nestingSuffix):n.nestingSuffixEscaped||s(")"),this.resetRegExp()},e.prototype.reset=function(){this.options&&this.init(this.options)},e.prototype.resetRegExp=function(){var t=this.prefix+"(.+?)"+this.suffix;this.regexp=new RegExp(t,"g");var e=this.prefix+this.unescapePrefix+"(.+?)"+this.unescapeSuffix+this.suffix;this.regexpUnescape=new RegExp(e,"g");var n=this.nestingPrefix+"(.+?)"+this.nestingSuffix;this.nestingRegexp=new RegExp(n,"g")},e.prototype.interpolate=function(e,n,o){function r(t){return t.replace(/\$/g,"$$$$")}var a=this,s=void 0,u=void 0,l=function(t){if(t.indexOf(a.formatSeparator)<0)return i(n,t);var e=t.split(a.formatSeparator),r=e.shift().trim(),s=e.join(a.formatSeparator).trim();return a.format(i(n,r),s,o)};for(this.resetRegExp();s=this.regexpUnescape.exec(e);){var c=l(s[1].trim());e=e.replace(s[0],c),this.regexpUnescape.lastIndex=0}for(;s=this.regexp.exec(e);)u=l(s[1].trim()),"string"!=typeof u&&(u=t(u)),u||(this.logger.warn("missed to pass in variable "+s[1]+" for interpolating "+e),u=""),u=r(this.escapeValue?this.escape(u):u),e=e.replace(s[0],u),this.regexp.lastIndex=0;return e},e.prototype.nest=function(e,n){function o(t){if(t.indexOf(",")<0)return t;var e=t.split(",");t=e.shift();var n=e.join(",");n=this.interpolate(n,s),n=n.replace(/'/g,'"');try{s=JSON.parse(n)}catch(e){this.logger.error("failed parsing options string in nesting for key "+t,e)}return t}var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},i=void 0,a=void 0,s=JSON.parse(JSON.stringify(r));for(s.applyPostProcessor=!1;i=this.nestingRegexp.exec(e);)a=n(o.call(this,i[1].trim()),s),"string"!=typeof a&&(a=t(a)),a||(this.logger.warn("missed to pass in variable "+i[1]+" for interpolating "+e),a=""),e=e.replace(i[0],a),this.regexp.lastIndex=0;return e},e}(),F=function(t){function e(n,o,r){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};k(this,e);var a=O(this,t.call(this));return a.backend=n,a.store=o,a.services=r,a.options=i,a.logger=C.create("backendConnector"),a.state={},a.queue=[],a.backend&&a.backend.init&&a.backend.init(r,i.backend,i),a}return w(e,t),e.prototype.queueLoad=function(t,e,n){var o=this,r=[],i=[],a=[],s=[];return t.forEach(function(t){var n=!0;e.forEach(function(e){var a=t+"|"+e;o.store.hasResourceBundle(t,e)?o.state[a]=2:o.state[a]<0||(1===o.state[a]?i.indexOf(a)<0&&i.push(a):(o.state[a]=1,n=!1,i.indexOf(a)<0&&i.push(a),r.indexOf(a)<0&&r.push(a),s.indexOf(e)<0&&s.push(e)))}),n||a.push(t)}),(r.length||i.length)&&this.queue.push({pending:i,loaded:{},errors:[],callback:n}),{toLoad:r,pending:i,toLoadLanguages:a,toLoadNamespaces:s}},e.prototype.loaded=function(t,e,n){var o=this,i=t.split("|"),a=N(i,2),s=a[0],u=a[1];e&&this.emit("failedLoading",s,u,e),n&&this.store.addResourceBundle(s,u,n),this.state[t]=e?-1:2,this.queue.forEach(function(n){r(n.loaded,[s],u),v(n.pending,t),e&&n.errors.push(e),0!==n.pending.length||n.done||(o.emit("loaded",n.loaded),n.errors.length?n.callback(n.errors):n.callback(),n.done=!0)}),this.queue=this.queue.filter(function(t){return!t.done})},e.prototype.read=function(t,e,n,o,r,i){var a=this;return o||(o=0),r||(r=250),t.length?void this.backend[n](t,e,function(s,u){return s&&u&&o<5?void setTimeout(function(){a.read.call(a,t,e,n,++o,2*r,i)},r):void i(s,u)}):i(null,{})},e.prototype.load=function(t,e,n){var o=this;if(!this.backend)return this.logger.warn("No backend was added via i18next.use. Will not load resources."),n&&n();var r=S({},this.backend.options,this.options.backend);"string"==typeof t&&(t=this.services.languageUtils.toResolveHierarchy(t)),"string"==typeof e&&(e=[e]);var a=this.queueLoad(t,e,n);return a.toLoad.length?void(r.allowMultiLoading&&this.backend.readMulti?this.read(a.toLoadLanguages,a.toLoadNamespaces,"readMulti",null,null,function(t,e){t&&o.logger.warn("loading namespaces "+a.toLoadNamespaces.join(", ")+" for languages "+a.toLoadLanguages.join(", ")+" via multiloading failed",t),!t&&e&&o.logger.log("loaded namespaces "+a.toLoadNamespaces.join(", ")+" for languages "+a.toLoadLanguages.join(", ")+" via multiloading",e),a.toLoad.forEach(function(n){var r=n.split("|"),a=N(r,2),s=a[0],u=a[1],l=i(e,[s,u]);if(l)o.loaded(n,t,l);else{var c="loading namespace "+u+" for language "+s+" via multiloading failed";o.loaded(n,c),o.logger.error(c)}})}):!function(){var t=function(t){var e=this,n=t.split("|"),o=N(n,2),r=o[0],i=o[1];this.read(r,i,"read",null,null,function(n,o){n&&e.logger.warn("loading namespace "+i+" for language "+r+" failed",n),!n&&o&&e.logger.log("loaded namespace "+i+" for language "+r,o),e.loaded(t,n,o)})};a.toLoad.forEach(function(e){t.call(o,e)})}()):void(a.pending.length||n())},e.prototype.reload=function(t,e){var n=this;this.backend||this.logger.warn("No backend was added via i18next.use. Will not load resources.");var o=S({},this.backend.options,this.options.backend);"string"==typeof t&&(t=this.services.languageUtils.toResolveHierarchy(t)),"string"==typeof e&&(e=[e]),o.allowMultiLoading&&this.backend.readMulti?this.read(t,e,"readMulti",null,null,function(o,r){o&&n.logger.warn("reloading namespaces "+e.join(", ")+" for languages "+t.join(", ")+" via multiloading failed",o),!o&&r&&n.logger.log("reloaded namespaces "+e.join(", ")+" for languages "+t.join(", ")+" via multiloading",r),t.forEach(function(t){e.forEach(function(e){var a=i(r,[t,e]);if(a)n.loaded(t+"|"+e,o,a);else{var s="reloading namespace "+e+" for language "+t+" via multiloading failed";n.loaded(t+"|"+e,s),n.logger.error(s)}})})}):!function(){var o=function(t){var e=this,n=t.split("|"),o=N(n,2),r=o[0],i=o[1];this.read(r,i,"read",null,null,function(n,o){n&&e.logger.warn("reloading namespace "+i+" for language "+r+" failed",n),!n&&o&&e.logger.log("reloaded namespace "+i+" for language "+r,o),e.loaded(t,n,o)})};t.forEach(function(t){e.forEach(function(e){o.call(n,t+"|"+e)})})}()},e.prototype.saveMissing=function(t,e,n,o){this.backend&&this.backend.create&&this.backend.create(t,e,n,o),t&&t[0]&&this.store.addResource(t[0],e,n,o)},e}(P),I=function(t){function e(n,o,r){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};k(this,e);var a=O(this,t.call(this));return a.cache=n,a.store=o,a.services=r,a.options=i,a.logger=C.create("cacheConnector"),a.cache&&a.cache.init&&a.cache.init(r,i.cache,i),a}return w(e,t),e.prototype.load=function(t,e,n){var o=this;if(!this.cache)return n&&n();var r=S({},this.cache.options,this.options.cache);"string"==typeof t&&(t=this.services.languageUtils.toResolveHierarchy(t)),"string"==typeof e&&(e=[e]),r.enabled?this.cache.load(t,function(e,r){if(e&&o.logger.error("loading languages "+t.join(", ")+" from cache failed",e),r)for(var i in r)for(var a in r[i])if("i18nStamp"!==a){var s=r[i][a];s&&o.store.addResourceBundle(i,a,s)}n&&n()}):n&&n()},e.prototype.save=function(){this.cache&&this.options.cache&&this.options.cache.enabled&&this.cache.save(this.store.data)},e}(P),K=function(t){function e(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},o=arguments[1];k(this,e);var r=O(this,t.call(this));return r.options=b(n),r.services={},r.logger=C,r.modules={},o&&!r.isInitialized&&r.init(n,o),r}return w(e,t),e.prototype.init=function(t,e){function n(t){if(t)return"function"==typeof t?new t:t}var o=this;if("function"==typeof t&&(e=t,t={}),t||(t={}),"v1"===t.compatibilityAPI?this.options=S({},y(),b(c(t)),{}):"v1"===t.compatibilityJSON?this.options=S({},y(),b(p(t)),{}):this.options=S({},y(),this.options,b(t)),e||(e=m),!this.options.isClone){this.modules.logger?C.init(n(this.modules.logger),this.options):C.init(null,this.options);var r=new M(this.options);this.store=new E(this.options.resources,this.options);var i=this.services;i.logger=C,i.resourceStore=this.store,i.resourceStore.on("added removed",function(t,e){i.cacheConnector.save()}),i.languageUtils=r,i.pluralResolver=new U(r,{prepend:this.options.pluralSeparator,compatibilityJSON:this.options.compatibilityJSON}),i.interpolator=new V(this.options),i.backendConnector=new F(n(this.modules.backend),i.resourceStore,i,this.options),i.backendConnector.on("*",function(t){for(var e=arguments.length,n=Array(e>1?e-1:0),r=1;r<e;r++)n[r-1]=arguments[r];o.emit.apply(o,[t].concat(n));
+}),i.backendConnector.on("loaded",function(t){i.cacheConnector.save()}),i.cacheConnector=new I(n(this.modules.cache),i.resourceStore,i,this.options),i.cacheConnector.on("*",function(t){for(var e=arguments.length,n=Array(e>1?e-1:0),r=1;r<e;r++)n[r-1]=arguments[r];o.emit.apply(o,[t].concat(n))}),this.modules.languageDetector&&(i.languageDetector=n(this.modules.languageDetector),i.languageDetector.init(i,this.options.detection,this.options)),this.translator=new A(this.services,this.options),this.translator.on("*",function(t){for(var e=arguments.length,n=Array(e>1?e-1:0),r=1;r<e;r++)n[r-1]=arguments[r];o.emit.apply(o,[t].concat(n))})}var a=["getResource","addResource","addResources","addResourceBundle","removeResourceBundle","hasResourceBundle","getResourceBundle"];a.forEach(function(t){o[t]=function(){return this.store[t].apply(this.store,arguments)}}),"v1"===this.options.compatibilityAPI&&g(this);var s=function(){o.changeLanguage(o.options.lng,function(t,n){o.isInitialized=!0,o.emit("initialized",o.options),o.logger.log("initialized",o.options),e(t,n)})};return this.options.resources||!this.options.initImmediate?s():setTimeout(s,0),this},e.prototype.loadResources=function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:m;if(this.options.resources)e(null);else{var n=function(){if(t.language&&"cimode"===t.language.toLowerCase())return{v:e()};var n=[],o=function(e){var o=t.services.languageUtils.toResolveHierarchy(e);o.forEach(function(t){n.indexOf(t)<0&&n.push(t)})};o(t.language),t.options.preload&&t.options.preload.forEach(function(t){o(t)}),t.services.cacheConnector.load(n,t.options.ns,function(){t.services.backendConnector.load(n,t.options.ns,e)})}();if("object"===("undefined"==typeof n?"undefined":x(n)))return n.v}},e.prototype.reloadResources=function(t,e){t||(t=this.languages),e||(e=this.options.ns),this.services.backendConnector.reload(t,e)},e.prototype.use=function(t){return"backend"===t.type&&(this.modules.backend=t),"cache"===t.type&&(this.modules.cache=t),("logger"===t.type||t.log&&t.warn&&t.warn)&&(this.modules.logger=t),"languageDetector"===t.type&&(this.modules.languageDetector=t),"postProcessor"===t.type&&_.addPostProcessor(t),this},e.prototype.changeLanguage=function(t,e){var n=this,o=function(o){t&&(n.emit("languageChanged",t),n.logger.log("languageChanged",t)),e&&e(o,function(){for(var t=arguments.length,e=Array(t),o=0;o<t;o++)e[o]=arguments[o];return n.t.apply(n,e)})};!t&&this.services.languageDetector&&(t=this.services.languageDetector.detect()),t&&(this.language=t,this.languages=this.services.languageUtils.toResolveHierarchy(t),this.translator.changeLanguage(t),this.services.languageDetector&&this.services.languageDetector.cacheUserLanguage(t)),this.loadResources(function(t){o(t)})},e.prototype.getFixedT=function(t,e){var n=this,o=function t(e){var o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=S({},o);return r.lng=r.lng||t.lng,r.ns=r.ns||t.ns,n.t(e,r)};return o.lng=t,o.ns=e,o},e.prototype.t=function(){return this.translator&&this.translator.translate.apply(this.translator,arguments)},e.prototype.exists=function(){return this.translator&&this.translator.exists.apply(this.translator,arguments)},e.prototype.setDefaultNamespace=function(t){this.options.defaultNS=t},e.prototype.loadNamespaces=function(t,e){var n=this;return this.options.ns?("string"==typeof t&&(t=[t]),t.forEach(function(t){n.options.ns.indexOf(t)<0&&n.options.ns.push(t)}),void this.loadResources(e)):e&&e()},e.prototype.loadLanguages=function(t,e){"string"==typeof t&&(t=[t]);var n=this.options.preload||[],o=t.filter(function(t){return n.indexOf(t)<0});return o.length?(this.options.preload=n.concat(o),void this.loadResources(e)):e()},e.prototype.dir=function(t){if(t||(t=this.language),!t)return"rtl";var e=["ar","shu","sqr","ssh","xaa","yhd","yud","aao","abh","abv","acm","acq","acw","acx","acy","adf","ads","aeb","aec","afb","ajp","apc","apd","arb","arq","ars","ary","arz","auz","avl","ayh","ayl","ayn","ayp","bbz","pga","he","iw","ps","pbt","pbu","pst","prp","prd","ur","ydd","yds","yih","ji","yi","hbo","men","xmn","fa","jpr","peo","pes","prs","dv","sam"];return e.indexOf(this.services.languageUtils.getLanguagePartFromCode(t))>=0?"rtl":"ltr"},e.prototype.createInstance=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments[1];return new e(t,n)},e.prototype.cloneInstance=function(){var t=this,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:m,r=new e(S({},n,this.options,{isClone:!0}),o),i=["store","services","language"];return i.forEach(function(e){r[e]=t[e]}),r.translator=new A(r.services,r.options),r.translator.on("*",function(t){for(var e=arguments.length,n=Array(e>1?e-1:0),o=1;o<e;o++)n[o-1]=arguments[o];r.emit.apply(r,[t].concat(n))}),r},e}(P),D=new K;return D});
+
+
+/*!
+ * Source: lib/jquery-i18next/jquery-i18next.min.js, license: MIT, url: http://i18next.com/
*/
-// i18next, v1.7.7
-// Copyright (c)2014 Jan Mühlemann (jamuhl).
-// Distributed under MIT license
-// http://i18next.com
-!function(){function a(a,b){if(!b||"function"==typeof b)return a;for(var c in b)a[c]=b[c];return a}function b(a,c){for(var d in c)d in a?b(a[d],c[d]):a[d]=c[d];return a}function c(a,b,c){var d,e=0,f=a.length,g=void 0===f||"[object Array]"!==Object.prototype.toString.apply(a)||"function"==typeof a;if(c)if(g){for(d in a)if(b.apply(a[d],c)===!1)break}else for(;f>e&&b.apply(a[e++],c)!==!1;);else if(g){for(d in a)if(b.call(a[d],d,a[d])===!1)break}else for(;f>e&&b.call(a[e],e,a[e++])!==!1;);return a}function d(a){return"string"==typeof a?a.replace(/[&<>"'\/]/g,function(a){return Q[a]}):a}function e(a){var b=function(a){if(window.XMLHttpRequest)return a(null,new XMLHttpRequest);if(window.ActiveXObject)try{return a(null,new ActiveXObject("Msxml2.XMLHTTP"))}catch(b){return a(null,new ActiveXObject("Microsoft.XMLHTTP"))}return a(new Error)},c=function(a){if("string"==typeof a)return a;var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(encodeURIComponent(c)+"="+encodeURIComponent(a[c]));return b.join("&")},d=function(a){a=a.replace(/\r\n/g,"\n");for(var b="",c=0;c<a.length;c++){var d=a.charCodeAt(c);128>d?b+=String.fromCharCode(d):d>127&&2048>d?(b+=String.fromCharCode(192|d>>6),b+=String.fromCharCode(128|63&d)):(b+=String.fromCharCode(224|d>>12),b+=String.fromCharCode(128|63&d>>6),b+=String.fromCharCode(128|63&d))}return b},e=function(a){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";a=d(a);var c,e,f,g,h,i,j,k="",l=0;do c=a.charCodeAt(l++),e=a.charCodeAt(l++),f=a.charCodeAt(l++),g=c>>2,h=(3&c)<<4|e>>4,i=(15&e)<<2|f>>6,j=63&f,isNaN(e)?i=j=64:isNaN(f)&&(j=64),k+=b.charAt(g)+b.charAt(h)+b.charAt(i)+b.charAt(j),c=e=f="",g=h=i=j="";while(l<a.length);return k},f=function(){for(var a=arguments[0],b=1;b<arguments.length;b++){var c=arguments[b];for(var d in c)c.hasOwnProperty(d)&&(a[d]=c[d])}return a},g=function(a,d,e,h){"function"==typeof e&&(h=e,e={}),e.cache=e.cache||!1,e.data=e.data||{},e.headers=e.headers||{},e.jsonp=e.jsonp||!1,e.async=void 0===e.async?!0:e.async;var i,j=f({accept:"*/*","content-type":"application/x-www-form-urlencoded;charset=UTF-8"},g.headers,e.headers);if(i="application/json"===j["content-type"]?JSON.stringify(e.data):c(e.data),"GET"===a){var k=[];if(i&&(k.push(i),i=null),e.cache||k.push("_="+(new Date).getTime()),e.jsonp&&(k.push("callback="+e.jsonp),k.push("jsonp="+e.jsonp)),k=k.join("&"),k.length>1&&(d+=d.indexOf("?")>-1?"&"+k:"?"+k),e.jsonp){var l=document.getElementsByTagName("head")[0],m=document.createElement("script");return m.type="text/javascript",m.src=d,l.appendChild(m),void 0}}b(function(b,c){if(b)return h(b);c.open(a,d,e.async);for(var f in j)j.hasOwnProperty(f)&&c.setRequestHeader(f,j[f]);c.onreadystatechange=function(){if(4===c.readyState){var a=c.responseText||"";if(!h)return;h(c.status,{text:function(){return a},json:function(){try{return JSON.parse(a)}catch(b){return T.error("Can not parse JSON. URL: "+d),{}}}})}},c.send(i)})},h={authBasic:function(a,b){g.headers.Authorization="Basic "+e(a+":"+b)},connect:function(a,b,c){return g("CONNECT",a,b,c)},del:function(a,b,c){return g("DELETE",a,b,c)},get:function(a,b,c){return g("GET",a,b,c)},head:function(a,b,c){return g("HEAD",a,b,c)},headers:function(a){g.headers=a||{}},isAllowed:function(a,b,c){this.options(a,function(a,d){c(-1!==d.text().indexOf(b))})},options:function(a,b,c){return g("OPTIONS",a,b,c)},patch:function(a,b,c){return g("PATCH",a,b,c)},post:function(a,b,c){return g("POST",a,b,c)},put:function(a,b,c){return g("PUT",a,b,c)},trace:function(a,b,c){return g("TRACE",a,b,c)}},i=a.type?a.type.toLowerCase():"get";h[i](a.url,a,function(b,c){200===b||0===b&&c.text()?a.success(c.json(),b,null):a.error(c.text(),b,null)})}function f(a,b){"function"==typeof a&&(b=a,a={}),a=a||{},T.extend(P,a),delete P.fixLng,P.functions&&(delete P.functions,T.extend(T,a.functions)),"string"==typeof P.ns&&(P.ns={namespaces:[P.ns],defaultNs:P.ns}),"string"==typeof P.fallbackNS&&(P.fallbackNS=[P.fallbackNS]),("string"==typeof P.fallbackLng||"boolean"==typeof P.fallbackLng)&&(P.fallbackLng=[P.fallbackLng]),P.interpolationPrefixEscaped=T.regexEscape(P.interpolationPrefix),P.interpolationSuffixEscaped=T.regexEscape(P.interpolationSuffix),P.lng||(P.lng=T.detectLanguage()),L=T.toLanguages(P.lng),F=L[0],T.log("currentLng set to: "+F),P.useCookie&&T.cookie.read(P.cookieName)!==F&&T.cookie.create(P.cookieName,F,P.cookieExpirationTime,P.cookieDomain),P.detectLngFromLocalStorage&&"undefined"!=typeof document&&window.localStorage&&T.localStorage.setItem("i18next_lng",F);var c=z;a.fixLng&&(c=function(a,b){return b=b||{},b.lng=b.lng||c.lng,z(a,b)},c.lng=F),W.setCurrentLng(F),H&&P.setJqueryExt&&s();var d;if(H&&H.Deferred&&(d=H.Deferred()),!P.resStore){var e=T.toLanguages(P.lng);"string"==typeof P.preload&&(P.preload=[P.preload]);for(var f=0,g=P.preload.length;g>f;f++)for(var h=T.toLanguages(P.preload[f]),i=0,j=h.length;j>i;i++)e.indexOf(h[i])<0&&e.push(h[i]);return I.sync.load(e,P,function(a,e){J=e,M=!0,b&&b(c),d&&d.resolve(c)}),d?d.promise():void 0}return J=P.resStore,M=!0,b&&b(c),d&&d.resolve(c),d?d.promise():void 0}function g(a,b){"string"==typeof a&&(a=[a]);for(var c=0,d=a.length;d>c;c++)P.preload.indexOf(a[c])<0&&P.preload.push(a[c]);return f(b)}function h(a,b,c,d){"string"!=typeof b?(c=b,b=P.ns.defaultNs):P.ns.namespaces.indexOf(b)<0&&P.ns.namespaces.push(b),J[a]=J[a]||{},J[a][b]=J[a][b]||{},d?T.deepExtend(J[a][b],c):T.extend(J[a][b],c)}function i(a,b){"string"!=typeof b&&(b=P.ns.defaultNs),J[a]=J[a]||{};var c=J[a][b]||{},d=!1;for(var e in c)c.hasOwnProperty(e)&&(d=!0);return d}function j(a,b){"string"!=typeof b&&(b=P.ns.defaultNs),J[a]=J[a]||{},J[a][b]={}}function k(a,b,c,d){"string"!=typeof b?(resource=b,b=P.ns.defaultNs):P.ns.namespaces.indexOf(b)<0&&P.ns.namespaces.push(b),J[a]=J[a]||{},J[a][b]=J[a][b]||{};for(var e=c.split(P.keyseparator),f=0,g=J[a][b];e[f];)f==e.length-1?g[e[f]]=d:(null==g[e[f]]&&(g[e[f]]={}),g=g[e[f]]),f++}function l(a,b,c){"string"!=typeof b?(resource=b,b=P.ns.defaultNs):P.ns.namespaces.indexOf(b)<0&&P.ns.namespaces.push(b);for(var d in c)"string"==typeof c[d]&&k(a,b,d,c[d])}function m(a){P.ns.defaultNs=a}function n(a,b){o([a],b)}function o(a,b){var c={dynamicLoad:P.dynamicLoad,resGetPath:P.resGetPath,getAsync:P.getAsync,customLoad:P.customLoad,ns:{namespaces:a,defaultNs:""}},d=T.toLanguages(P.lng);"string"==typeof P.preload&&(P.preload=[P.preload]);for(var e=0,f=P.preload.length;f>e;e++)for(var g=T.toLanguages(P.preload[e]),h=0,i=g.length;i>h;h++)d.indexOf(g[h])<0&&d.push(g[h]);for(var j=[],k=0,l=d.length;l>k;k++){var m=!1,n=J[d[k]];if(n)for(var o=0,p=a.length;p>o;o++)n[a[o]]||(m=!0);else m=!0;m&&j.push(d[k])}j.length?I.sync._fetch(j,c,function(c,d){var e=a.length*j.length;T.each(a,function(a,c){P.ns.namespaces.indexOf(c)<0&&P.ns.namespaces.push(c),T.each(j,function(a,f){J[f]=J[f]||{},J[f][c]=d[f][c],e--,0===e&&b&&(P.useLocalStorage&&I.sync._storeLocal(J),b())})})}):b&&b()}function p(a,b,c){return"function"==typeof b?(c=b,b={}):b||(b={}),b.lng=a,f(b,c)}function q(){return F}function r(a){J={},p(F,a)}function s(){function a(a,b,c){if(0!==b.length){var d="text";if(0===b.indexOf("[")){var e=b.split("]");b=e[1],d=e[0].substr(1,e[0].length-1)}b.indexOf(";")===b.length-1&&(b=b.substr(0,b.length-2));var f;if("html"===d)f=P.defaultValueFromContent?H.extend({defaultValue:a.html()},c):c,a.html(H.t(b,f));else if("text"===d)f=P.defaultValueFromContent?H.extend({defaultValue:a.text()},c):c,a.text(H.t(b,f));else if("prepend"===d)f=P.defaultValueFromContent?H.extend({defaultValue:a.html()},c):c,a.prepend(H.t(b,f));else if("append"===d)f=P.defaultValueFromContent?H.extend({defaultValue:a.html()},c):c,a.append(H.t(b,f));else if(0===d.indexOf("data-")){var g=d.substr("data-".length);f=P.defaultValueFromContent?H.extend({defaultValue:a.data(g)},c):c;var h=H.t(b,f);a.data(g,h),a.attr(d,h)}else f=P.defaultValueFromContent?H.extend({defaultValue:a.attr(d)},c):c,a.attr(d,H.t(b,f))}}function b(b,c){var d=b.attr(P.selectorAttr);if(d||"undefined"==typeof d||d===!1||(d=b.text()||b.val()),d){var e=b,f=b.data("i18n-target");if(f&&(e=b.find(f)||b),c||P.useDataAttrOptions!==!0||(c=b.data("i18n-options")),c=c||{},d.indexOf(";")>=0){var g=d.split(";");H.each(g,function(b,d){""!==d&&a(e,d,c)})}else a(e,d,c);P.useDataAttrOptions===!0&&b.data("i18n-options",c)}}H.t=H.t||z,H.fn.i18n=function(a){return this.each(function(){b(H(this),a);var c=H(this).find("["+P.selectorAttr+"]");c.each(function(){b(H(this),a)})})}}function t(a,b,c,d){if(!a)return a;if(d=d||b,a.indexOf(d.interpolationPrefix||P.interpolationPrefix)<0)return a;var e=d.interpolationPrefix?T.regexEscape(d.interpolationPrefix):P.interpolationPrefixEscaped,f=d.interpolationSuffix?T.regexEscape(d.interpolationSuffix):P.interpolationSuffixEscaped,g="HTML"+f,h=b.replace&&"object"==typeof b.replace?b.replace:b;return T.each(h,function(b,h){var i=c?c+P.keyseparator+b:b;"object"==typeof h&&null!==h?a=t(a,h,i,d):d.escapeInterpolation||P.escapeInterpolation?(a=a.replace(new RegExp([e,i,g].join(""),"g"),T.regexReplacementEscape(h)),a=a.replace(new RegExp([e,i,f].join(""),"g"),T.regexReplacementEscape(T.escape(h)))):a=a.replace(new RegExp([e,i,f].join(""),"g"),T.regexReplacementEscape(h))}),a}function u(a,b){var c=",",d="{",e="}",f=T.extend({},b);for(delete f.postProcess;-1!=a.indexOf(P.reusePrefix)&&(K++,!(K>P.maxRecursion));){var g=a.lastIndexOf(P.reusePrefix),h=a.indexOf(P.reuseSuffix,g)+P.reuseSuffix.length,i=a.substring(g,h),j=i.replace(P.reusePrefix,"").replace(P.reuseSuffix,"");if(g>=h)return T.error("there is an missing closing in following translation value",a),"";if(-1!=j.indexOf(c)){var k=j.indexOf(c);if(-1!=j.indexOf(d,k)&&-1!=j.indexOf(e,k)){var l=j.indexOf(d,k),m=j.indexOf(e,l)+e.length;try{f=T.extend(f,JSON.parse(j.substring(l,m))),j=j.substring(0,k)}catch(n){}}}var o=C(j,f);a=a.replace(i,T.regexReplacementEscape(o))}return a}function v(a){return a.context&&("string"==typeof a.context||"number"==typeof a.context)}function w(a){return void 0!==a.count&&"string"!=typeof a.count}function x(a){return void 0!==a.indefinite_article&&"string"!=typeof a.indefinite_article&&a.indefinite_article}function y(a,b){b=b||{};var c=A(a,b),d=D(a,b);return void 0!==d||d===c}function z(a,b){return b=b||{},M?(K=0,C.apply(null,arguments)):(T.log("i18next not finished initialization. you might have called t function before loading resources finished."),b.defaultValue||"")}function A(a,b){return void 0!==b.defaultValue?b.defaultValue:a}function B(){for(var a=[],b=1;b<arguments.length;b++)a.push(arguments[b]);return{postProcess:"sprintf",sprintf:a}}function C(a,b){if(b&&"object"!=typeof b?"sprintf"===P.shortcutFunction?b=B.apply(null,arguments):"defaultValue"===P.shortcutFunction&&(b={defaultValue:b}):b=b||{},"object"==typeof P.defaultVariables&&(b=T.extend({},P.defaultVariables,b)),void 0===a||null===a||""===a)return"";"string"==typeof a&&(a=[a]);var c=a[0];if(a.length>1)for(var d=0;d<a.length&&(c=a[d],!y(c,b));d++);var e,f=A(c,b),g=D(c,b),h=b.lng?T.toLanguages(b.lng,b.fallbackLng):L,i=b.ns||P.ns.defaultNs;c.indexOf(P.nsseparator)>-1&&(e=c.split(P.nsseparator),i=e[0],c=e[1]),void 0===g&&P.sendMissing&&"function"==typeof P.missingKeyHandler&&(b.lng?P.missingKeyHandler(h[0],i,c,f,h):P.missingKeyHandler(P.lng,i,c,f,h));var j=b.postProcess||P.postProcess;void 0!==g&&j&&X[j]&&(g=X[j](g,c,b));var k=f;if(f.indexOf(P.nsseparator)>-1&&(e=f.split(P.nsseparator),k=e[1]),k===c&&P.parseMissingKey&&(f=P.parseMissingKey(f)),void 0===g&&(f=t(f,b),f=u(f,b),j&&X[j])){var l=A(c,b);g=X[j](l,c,b)}return void 0!==g?g:f}function D(a,b){b=b||{};var c,d,e=A(a,b),f=L;if(!J)return e;if("cimode"===f[0].toLowerCase())return e;if(b.lngs&&(f=b.lngs),b.lng&&(f=T.toLanguages(b.lng,b.fallbackLng),!J[f[0]])){var g=P.getAsync;P.getAsync=!1,I.sync.load(f,P,function(a,b){T.extend(J,b),P.getAsync=g})}var h=b.ns||P.ns.defaultNs;if(a.indexOf(P.nsseparator)>-1){var i=a.split(P.nsseparator);h=i[0],a=i[1]}if(v(b)){c=T.extend({},b),delete c.context,c.defaultValue=P.contextNotFound;var j=h+P.nsseparator+a+"_"+b.context;if(d=z(j,c),d!=P.contextNotFound)return t(d,{context:b.context})}if(w(b,f[0])){c=T.extend({lngs:[f[0]]},b),delete c.count,delete c.lng,c.defaultValue=P.pluralNotFound;var k;if(W.needsPlural(f[0],b.count)){k=h+P.nsseparator+a+P.pluralSuffix;var l=W.get(f[0],b.count);l>=0?k=k+"_"+l:1===l&&(k=h+P.nsseparator+a)}else k=h+P.nsseparator+a;if(d=z(k,c),d!=P.pluralNotFound)return t(d,{count:b.count,interpolationPrefix:b.interpolationPrefix,interpolationSuffix:b.interpolationSuffix});if(!(f.length>1))return d;var m=f.slice();if(m.shift(),b=T.extend(b,{lngs:m}),delete b.lng,d=z(h+P.nsseparator+a,b),d!=P.pluralNotFound)return d}if(x(b)){var n=T.extend({},b);delete n.indefinite_article,n.defaultValue=P.indefiniteNotFound;var o=h+P.nsseparator+a+(b.count&&!w(b,f[0])||!b.count?P.indefiniteSuffix:"");if(d=z(o,n),d!=P.indefiniteNotFound)return d}for(var p,q=a.split(P.keyseparator),r=0,s=f.length;s>r&&void 0===p;r++){for(var y=f[r],B=0,E=J[y]&&J[y][h];q[B];)E=E&&E[q[B]],B++;if(void 0!==E){var F=Object.prototype.toString.apply(E);if("string"==typeof E)E=t(E,b),E=u(E,b);else if("[object Array]"!==F||P.returnObjectTrees||b.returnObjectTrees){if(null===E&&P.fallbackOnNull===!0)E=void 0;else if(null!==E)if(P.returnObjectTrees||b.returnObjectTrees){if("[object Number]"!==F&&"[object Function]"!==F&&"[object RegExp]"!==F){var G="[object Array]"===F?[]:{};T.each(E,function(c){G[c]=C(h+P.nsseparator+a+P.keyseparator+c,b)}),E=G}}else P.objectTreeKeyHandler&&"function"==typeof P.objectTreeKeyHandler?E=P.objectTreeKeyHandler(a,E,y,h,b):(E="key '"+h+":"+a+" ("+y+")' "+"returned an object instead of string.",T.log(E))}else E=E.join("\n"),E=t(E,b),E=u(E,b);"string"==typeof E&&""===E.trim()&&P.fallbackOnEmpty===!0&&(E=void 0),p=E}}if(void 0===p&&!b.isFallbackLookup&&(P.fallbackToDefaultNS===!0||P.fallbackNS&&P.fallbackNS.length>0)){if(b.isFallbackLookup=!0,P.fallbackNS.length){for(var H=0,K=P.fallbackNS.length;K>H;H++)if(p=D(P.fallbackNS[H]+P.nsseparator+a,b),p||""===p&&P.fallbackOnEmpty===!1){var M=p.indexOf(P.nsseparator)>-1?p.split(P.nsseparator)[1]:p,N=e.indexOf(P.nsseparator)>-1?e.split(P.nsseparator)[1]:e;if(M!==N)break}}else p=D(a,b);b.isFallbackLookup=!1}return p}function E(){var a,b=P.lngWhitelist||[],c=[];if("undefined"!=typeof window&&!function(){for(var a=window.location.search.substring(1),b=a.split("&"),d=0;d<b.length;d++){var e=b[d].indexOf("=");if(e>0){var f=b[d].substring(0,e);f==P.detectLngQS&&c.push(b[d].substring(e+1))}}}(),P.useCookie&&"undefined"!=typeof document){var d=T.cookie.read(P.cookieName);d&&c.push(d)}if(P.detectLngFromLocalStorage&&"undefined"!=typeof window&&window.localStorage&&c.push(window.localStorage.getItem("i18next_lng")),"undefined"!=typeof navigator){if(navigator.languages)for(var e=0;e<navigator.languages.length;e++)c.push(navigator.languages[e]);navigator.userLanguage&&c.push(navigator.userLanguage),navigator.language&&c.push(navigator.language)}return function(){for(var d=0;d<c.length;d++){var e=c[d];if(e.indexOf("-")>-1){var f=e.split("-");e=P.lowerCaseLng?f[0].toLowerCase()+"-"+f[1].toLowerCase():f[0].toLowerCase()+"-"+f[1].toUpperCase()}if(0===b.length||b.indexOf(e)>-1){a=e;break}}}(),a||(a=P.fallbackLng[0]),a}Array.prototype.indexOf||(Array.prototype.indexOf=function(a){"use strict";if(null==this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=0;if(arguments.length>0&&(d=Number(arguments[1]),d!=d?d=0:0!=d&&1/0!=d&&d!=-1/0&&(d=(d>0||-1)*Math.floor(Math.abs(d)))),d>=c)return-1;for(var e=d>=0?d:Math.max(c-Math.abs(d),0);c>e;e++)if(e in b&&b[e]===a)return e;return-1}),Array.prototype.lastIndexOf||(Array.prototype.lastIndexOf=function(a){"use strict";if(null==this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=c;arguments.length>1&&(d=Number(arguments[1]),d!=d?d=0:0!=d&&d!=1/0&&d!=-(1/0)&&(d=(d>0||-1)*Math.floor(Math.abs(d))));for(var e=d>=0?Math.min(d,c-1):c-Math.abs(d);e>=0;e--)if(e in b&&b[e]===a)return e;return-1}),"function"!=typeof String.prototype.trim&&(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")});var F,G=this,H=G.jQuery||G.Zepto,I={},J={},K=0,L=[],M=!1,N={};if("undefined"!=typeof module&&module.exports){if(!H)try{H=require("jquery")}catch(O){}H&&(H.i18n=H.i18n||I),module.exports=I}else H&&(H.i18n=H.i18n||I),G.i18n=G.i18n||I;N={load:function(a,b,c){b.useLocalStorage?N._loadLocal(a,b,function(d,e){for(var f=[],g=0,h=a.length;h>g;g++)e[a[g]]||f.push(a[g]);f.length>0?N._fetch(f,b,function(a,b){T.extend(e,b),N._storeLocal(b),c(null,e)}):c(null,e)}):N._fetch(a,b,function(a,b){c(null,b)})},_loadLocal:function(a,b,c){var d={},e=(new Date).getTime();if(window.localStorage){var f=a.length;T.each(a,function(a,g){var h=window.localStorage.getItem("res_"+g);h&&(h=JSON.parse(h),h.i18nStamp&&h.i18nStamp+b.localStorageExpirationTime>e&&(d[g]=h)),f--,0===f&&c(null,d)})}},_storeLocal:function(a){if(window.localStorage)for(var b in a)a[b].i18nStamp=(new Date).getTime(),T.localStorage.setItem("res_"+b,JSON.stringify(a[b]))},_fetch:function(a,b,c){var d=b.ns,e={};if(b.dynamicLoad){var f=function(a,b){c(null,b)};if("function"==typeof b.customLoad)b.customLoad(a,d.namespaces,b,f);else{var g=t(b.resGetPath,{lng:a.join("+"),ns:d.namespaces.join("+")});T.ajax({url:g,success:function(a){T.log("loaded: "+g),f(null,a)},error:function(a,b,c){T.log("failed loading: "+g),f("failed loading resource.json error: "+c)},dataType:"json",async:b.getAsync})}}else{var h,i=d.namespaces.length*a.length;T.each(d.namespaces,function(d,f){T.each(a,function(a,d){var g=function(a,b){a&&(h=h||[],h.push(a)),e[d]=e[d]||{},e[d][f]=b,i--,0===i&&c(h,e)};"function"==typeof b.customLoad?b.customLoad(d,f,b,g):N._fetchOne(d,f,b,g)})})}},_fetchOne:function(a,b,c,d){var e=t(c.resGetPath,{lng:a,ns:b});T.ajax({url:e,success:function(a){T.log("loaded: "+e),d(null,a)},error:function(a,b,c){if(b&&200==b||a&&a.status&&200==a.status)T.error("There is a typo in: "+e);else if(b&&404==b||a&&a.status&&404==a.status)T.log("Does not exist: "+e);else{var f=b?b:a&&a.status?a.status:null;T.log(f+" when loading "+e)}d(c,{})},dataType:"json",async:c.getAsync})},postMissing:function(a,b,c,d,e){var f={};f[c]=d;var g=[];if("fallback"===P.sendMissingTo&&P.fallbackLng[0]!==!1)for(var h=0;h<P.fallbackLng.length;h++)g.push({lng:P.fallbackLng[h],url:t(P.resPostPath,{lng:P.fallbackLng[h],ns:b})});else if("current"===P.sendMissingTo||"fallback"===P.sendMissingTo&&P.fallbackLng[0]===!1)g.push({lng:a,url:t(P.resPostPath,{lng:a,ns:b})});else if("all"===P.sendMissingTo)for(var h=0,i=e.length;i>h;h++)g.push({lng:e[h],url:t(P.resPostPath,{lng:e[h],ns:b})});for(var j=0,k=g.length;k>j;j++){var l=g[j];T.ajax({url:l.url,type:P.sendType,data:f,success:function(){T.log("posted missing key '"+c+"' to: "+l.url);for(var a=c.split("."),e=0,f=J[l.lng][b];a[e];)f=f[a[e]]=e===a.length-1?d:f[a[e]]||{},e++},error:function(){T.log("failed posting missing key '"+c+"' to: "+l.url)},dataType:"json",async:P.postAsync})}},reload:r};var P={lng:void 0,load:"all",preload:[],lowerCaseLng:!1,returnObjectTrees:!1,fallbackLng:["dev"],fallbackNS:[],detectLngQS:"setLng",detectLngFromLocalStorage:!1,ns:"translation",fallbackOnNull:!0,fallbackOnEmpty:!1,fallbackToDefaultNS:!1,nsseparator:":",keyseparator:".",selectorAttr:"data-i18n",debug:!1,resGetPath:"locales/__lng__/__ns__.json",resPostPath:"locales/add/__lng__/__ns__",getAsync:!0,postAsync:!0,resStore:void 0,useLocalStorage:!1,localStorageExpirationTime:6048e5,dynamicLoad:!1,sendMissing:!1,sendMissingTo:"fallback",sendType:"POST",interpolationPrefix:"__",interpolationSuffix:"__",defaultVariables:!1,reusePrefix:"$t(",reuseSuffix:")",pluralSuffix:"_plural",pluralNotFound:["plural_not_found",Math.random()].join(""),contextNotFound:["context_not_found",Math.random()].join(""),escapeInterpolation:!1,indefiniteSuffix:"_indefinite",indefiniteNotFound:["indefinite_not_found",Math.random()].join(""),setJqueryExt:!0,defaultValueFromContent:!0,useDataAttrOptions:!1,cookieExpirationTime:void 0,useCookie:!0,cookieName:"i18next",cookieDomain:void 0,objectTreeKeyHandler:void 0,postProcess:void 0,parseMissingKey:void 0,missingKeyHandler:N.postMissing,shortcutFunction:"sprintf"},Q={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;"},R={create:function(a,b,c,d){var e;if(c){var f=new Date;f.setTime(f.getTime()+1e3*60*c),e="; expires="+f.toGMTString()}else e="";d=d?"domain="+d+";":"",document.cookie=a+"="+b+e+";"+d+"path=/"},read:function(a){for(var b=a+"=",c=document.cookie.split(";"),d=0;d<c.length;d++){for(var e=c[d];" "==e.charAt(0);)e=e.substring(1,e.length);if(0===e.indexOf(b))return e.substring(b.length,e.length)}return null},remove:function(a){this.create(a,"",-1)}},S={create:function(){},read:function(){return null},remove:function(){}},T={extend:H?H.extend:a,deepExtend:b,each:H?H.each:c,ajax:H?H.ajax:"undefined"!=typeof document?e:function(){},cookie:"undefined"!=typeof document?R:S,detectLanguage:E,escape:d,log:function(a){P.debug&&"undefined"!=typeof console&&console.log(a)},error:function(a){"undefined"!=typeof console&&console.error(a)},getCountyIndexOfLng:function(a){var b=0;return("nb-NO"===a||"nn-NO"===a||"nb-no"===a||"nn-no"===a)&&(b=1),b},toLanguages:function(a){function b(a){var b=a;if("string"==typeof a&&a.indexOf("-")>-1){var c=a.split("-");b=P.lowerCaseLng?c[0].toLowerCase()+"-"+c[1].toLowerCase():c[0].toLowerCase()+"-"+c[1].toUpperCase()}else b=P.lowerCaseLng?a.toLowerCase():a;return b}var c=this.log,d=[],e=P.lngWhitelist||!1,f=function(a){!e||e.indexOf(a)>-1?d.push(a):c("rejecting non-whitelisted language: "+a)};if("string"==typeof a&&a.indexOf("-")>-1){var g=a.split("-");"unspecific"!==P.load&&f(b(a)),"current"!==P.load&&f(b(g[this.getCountyIndexOfLng(a)]))}else f(b(a));for(var h=0;h<P.fallbackLng.length;h++)-1===d.indexOf(P.fallbackLng[h])&&P.fallbackLng[h]&&d.push(b(P.fallbackLng[h]));return d},regexEscape:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},regexReplacementEscape:function(a){return"string"==typeof a?a.replace(/\$/g,"$$$$"):a},localStorage:{setItem:function(a,b){if(window.localStorage)try{window.localStorage.setItem(a,b)}catch(c){T.log('failed to set value for key "'+a+'" to localStorage.')}}}};T.applyReplacement=t;var U=[["ach","Acholi",[1,2],1],["af","Afrikaans",[1,2],2],["ak","Akan",[1,2],1],["am","Amharic",[1,2],1],["an","Aragonese",[1,2],2],["ar","Arabic",[0,1,2,3,11,100],5],["arn","Mapudungun",[1,2],1],["ast","Asturian",[1,2],2],["ay","Aymará",[1],3],["az","Azerbaijani",[1,2],2],["be","Belarusian",[1,2,5],4],["bg","Bulgarian",[1,2],2],["bn","Bengali",[1,2],2],["bo","Tibetan",[1],3],["br","Breton",[1,2],1],["bs","Bosnian",[1,2,5],4],["ca","Catalan",[1,2],2],["cgg","Chiga",[1],3],["cs","Czech",[1,2,5],6],["csb","Kashubian",[1,2,5],7],["cy","Welsh",[1,2,3,8],8],["da","Danish",[1,2],2],["de","German",[1,2],2],["dev","Development Fallback",[1,2],2],["dz","Dzongkha",[1],3],["el","Greek",[1,2],2],["en","English",[1,2],2],["eo","Esperanto",[1,2],2],["es","Spanish",[1,2],2],["es_ar","Argentinean Spanish",[1,2],2],["et","Estonian",[1,2],2],["eu","Basque",[1,2],2],["fa","Persian",[1],3],["fi","Finnish",[1,2],2],["fil","Filipino",[1,2],1],["fo","Faroese",[1,2],2],["fr","French",[1,2],9],["fur","Friulian",[1,2],2],["fy","Frisian",[1,2],2],["ga","Irish",[1,2,3,7,11],10],["gd","Scottish Gaelic",[1,2,3,20],11],["gl","Galician",[1,2],2],["gu","Gujarati",[1,2],2],["gun","Gun",[1,2],1],["ha","Hausa",[1,2],2],["he","Hebrew",[1,2],2],["hi","Hindi",[1,2],2],["hr","Croatian",[1,2,5],4],["hu","Hungarian",[1,2],2],["hy","Armenian",[1,2],2],["ia","Interlingua",[1,2],2],["id","Indonesian",[1],3],["is","Icelandic",[1,2],12],["it","Italian",[1,2],2],["ja","Japanese",[1],3],["jbo","Lojban",[1],3],["jv","Javanese",[0,1],13],["ka","Georgian",[1],3],["kk","Kazakh",[1],3],["km","Khmer",[1],3],["kn","Kannada",[1,2],2],["ko","Korean",[1],3],["ku","Kurdish",[1,2],2],["kw","Cornish",[1,2,3,4],14],["ky","Kyrgyz",[1],3],["lb","Letzeburgesch",[1,2],2],["ln","Lingala",[1,2],1],["lo","Lao",[1],3],["lt","Lithuanian",[1,2,10],15],["lv","Latvian",[1,2,0],16],["mai","Maithili",[1,2],2],["mfe","Mauritian Creole",[1,2],1],["mg","Malagasy",[1,2],1],["mi","Maori",[1,2],1],["mk","Macedonian",[1,2],17],["ml","Malayalam",[1,2],2],["mn","Mongolian",[1,2],2],["mnk","Mandinka",[0,1,2],18],["mr","Marathi",[1,2],2],["ms","Malay",[1],3],["mt","Maltese",[1,2,11,20],19],["nah","Nahuatl",[1,2],2],["nap","Neapolitan",[1,2],2],["nb","Norwegian Bokmal",[1,2],2],["ne","Nepali",[1,2],2],["nl","Dutch",[1,2],2],["nn","Norwegian Nynorsk",[1,2],2],["no","Norwegian",[1,2],2],["nso","Northern Sotho",[1,2],2],["oc","Occitan",[1,2],1],["or","Oriya",[2,1],2],["pa","Punjabi",[1,2],2],["pap","Papiamento",[1,2],2],["pl","Polish",[1,2,5],7],["pms","Piemontese",[1,2],2],["ps","Pashto",[1,2],2],["pt","Portuguese",[1,2],2],["pt_br","Brazilian Portuguese",[1,2],2],["rm","Romansh",[1,2],2],["ro","Romanian",[1,2,20],20],["ru","Russian",[1,2,5],4],["sah","Yakut",[1],3],["sco","Scots",[1,2],2],["se","Northern Sami",[1,2],2],["si","Sinhala",[1,2],2],["sk","Slovak",[1,2,5],6],["sl","Slovenian",[5,1,2,3],21],["so","Somali",[1,2],2],["son","Songhay",[1,2],2],["sq","Albanian",[1,2],2],["sr","Serbian",[1,2,5],4],["su","Sundanese",[1],3],["sv","Swedish",[1,2],2],["sw","Swahili",[1,2],2],["ta","Tamil",[1,2],2],["te","Telugu",[1,2],2],["tg","Tajik",[1,2],1],["th","Thai",[1],3],["ti","Tigrinya",[1,2],1],["tk","Turkmen",[1,2],2],["tr","Turkish",[1,2],1],["tt","Tatar",[1],3],["ug","Uyghur",[1],3],["uk","Ukrainian",[1,2,5],4],["ur","Urdu",[1,2],2],["uz","Uzbek",[1,2],1],["vi","Vietnamese",[1],3],["wa","Walloon",[1,2],1],["wo","Wolof",[1],3],["yo","Yoruba",[1,2],2],["zh","Chinese",[1],3]],V={1:function(a){return Number(a>1)},2:function(a){return Number(1!=a)},3:function(){return 0},4:function(a){return Number(1==a%10&&11!=a%100?0:a%10>=2&&4>=a%10&&(10>a%100||a%100>=20)?1:2)},5:function(a){return Number(0===a?0:1==a?1:2==a?2:a%100>=3&&10>=a%100?3:a%100>=11?4:5)},6:function(a){return Number(1==a?0:a>=2&&4>=a?1:2)},7:function(a){return Number(1==a?0:a%10>=2&&4>=a%10&&(10>a%100||a%100>=20)?1:2)},8:function(a){return Number(1==a?0:2==a?1:8!=a&&11!=a?2:3)},9:function(a){return Number(a>=2)},10:function(a){return Number(1==a?0:2==a?1:7>a?2:11>a?3:4)},11:function(a){return Number(1==a||11==a?0:2==a||12==a?1:a>2&&20>a?2:3)},12:function(a){return Number(1!=a%10||11==a%100)},13:function(a){return Number(0!==a)},14:function(a){return Number(1==a?0:2==a?1:3==a?2:3)},15:function(a){return Number(1==a%10&&11!=a%100?0:a%10>=2&&(10>a%100||a%100>=20)?1:2)},16:function(a){return Number(1==a%10&&11!=a%100?0:0!==a?1:2)},17:function(a){return Number(1==a||1==a%10?0:1)},18:function(a){return Number(1==a?1:2)},19:function(a){return Number(1==a?0:0===a||a%100>1&&11>a%100?1:a%100>10&&20>a%100?2:3)},20:function(a){return Number(1==a?0:0===a||a%100>0&&20>a%100?1:2)},21:function(a){return Number(1==a%100?1:2==a%100?2:3==a%100||4==a%100?3:0)}},W={rules:function(){var a,b={};for(a=U.length;a--;)b[U[a][0]]={name:U[a][1],numbers:U[a][2],plurals:V[U[a][3]]};return b}(),addRule:function(a,b){W.rules[a]=b},setCurrentLng:function(a){if(!W.currentRule||W.currentRule.lng!==a){var b=a.split("-");W.currentRule={lng:a,rule:W.rules[b[0]]}}},needsPlural:function(a,b){var c,d=a.split("-");return c=W.currentRule&&W.currentRule.lng===a?W.currentRule.rule:W.rules[d[T.getCountyIndexOfLng(a)]],c&&c.numbers.length<=1?!1:1!==this.get(a,b)},get:function(a,b){function c(b,c){var d;if(d=W.currentRule&&W.currentRule.lng===a?W.currentRule.rule:W.rules[b]){var e;e=d.noAbs?d.plurals(c):d.plurals(Math.abs(c));var f=d.numbers[e];return 2===d.numbers.length&&1===d.numbers[0]&&(2===f?f=-1:1===f&&(f=1)),f}return 1===c?"1":"-1"}var d=a.split("-");return c(d[T.getCountyIndexOfLng(a)],b)}},X={},Y=function(a,b){X[a]=b},Z=function(){function a(a){return Object.prototype.toString.call(a).slice(8,-1).toLowerCase()}function b(a,b){for(var c=[];b>0;c[--b]=a);return c.join("")}var c=function(){return c.cache.hasOwnProperty(arguments[0])||(c.cache[arguments[0]]=c.parse(arguments[0])),c.format.call(null,c.cache[arguments[0]],arguments)};return c.format=function(c,d){var e,f,g,h,i,j,k,l=1,m=c.length,n="",o=[];for(f=0;m>f;f++)if(n=a(c[f]),"string"===n)o.push(c[f]);else if("array"===n){if(h=c[f],h[2])for(e=d[l],g=0;g<h[2].length;g++){if(!e.hasOwnProperty(h[2][g]))throw Z('[sprintf] property "%s" does not exist',h[2][g]);e=e[h[2][g]]}else e=h[1]?d[h[1]]:d[l++];if(/[^s]/.test(h[8])&&"number"!=a(e))throw Z("[sprintf] expecting number but found %s",a(e));switch(h[8]){case"b":e=e.toString(2);break;case"c":e=String.fromCharCode(e);break;case"d":e=parseInt(e,10);break;case"e":e=h[7]?e.toExponential(h[7]):e.toExponential();break;case"f":e=h[7]?parseFloat(e).toFixed(h[7]):parseFloat(e);break;case"o":e=e.toString(8);break;case"s":e=(e=String(e))&&h[7]?e.substring(0,h[7]):e;break;case"u":e=Math.abs(e);break;case"x":e=e.toString(16);break;case"X":e=e.toString(16).toUpperCase()}e=/[def]/.test(h[8])&&h[3]&&e>=0?"+"+e:e,j=h[4]?"0"==h[4]?"0":h[4].charAt(1):" ",k=h[6]-String(e).length,i=h[6]?b(j,k):"",o.push(h[5]?e+i:i+e)}return o.join("")},c.cache={},c.parse=function(a){for(var b=a,c=[],d=[],e=0;b;){if(null!==(c=/^[^\x25]+/.exec(b)))d.push(c[0]);else if(null!==(c=/^\x25{2}/.exec(b)))d.push("%");else{if(null===(c=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(b)))throw"[sprintf] huh?";if(c[2]){e|=1;var f=[],g=c[2],h=[];if(null===(h=/^([a-z_][a-z_\d]*)/i.exec(g)))throw"[sprintf] huh?";for(f.push(h[1]);""!==(g=g.substring(h[0].length));)if(null!==(h=/^\.([a-z_][a-z_\d]*)/i.exec(g)))f.push(h[1]);else{if(null===(h=/^\[(\d+)\]/.exec(g)))throw"[sprintf] huh?";f.push(h[1])}c[2]=f}else e|=2;if(3===e)throw"[sprintf] mixing positional and named placeholders is not (yet) supported";d.push(c)}b=b.substring(c[0].length)}return d},c}(),$=function(a,b){return b.unshift(a),Z.apply(null,b)};Y("sprintf",function(a,b,c){return c.sprintf?"[object Array]"===Object.prototype.toString.apply(c.sprintf)?$(a,c.sprintf):"object"==typeof c.sprintf?Z(a,c.sprintf):a:a}),I.init=f,I.setLng=p,I.preload=g,I.addResourceBundle=h,I.hasResourceBundle=i,I.addResource=k,I.addResources=l,I.removeResourceBundle=j,I.loadNamespace=n,I.loadNamespaces=o,I.setDefaultNamespace=m,I.t=z,I.translate=z,I.exists=y,I.detectLanguage=T.detectLanguage,I.pluralExtensions=W,I.sync=N,I.functions=T,I.lng=q,I.addPostProcessor=Y,I.options=P}();
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.jqueryI18next=e()}(this,function(){"use strict";function t(t,a){function i(n,a,i){function r(t,n){return f.parseDefaultValueFromContent?e({},t,{defaultValue:n}):t}if(0!==a.length){var o="text";if(0===a.indexOf("[")){var l=a.split("]");a=l[1],o=l[0].substr(1,l[0].length-1)}if(a.indexOf(";")===a.length-1&&(a=a.substr(0,a.length-2)),"html"===o)n.html(t.t(a,r(i,n.html())));else if("text"===o)n.text(t.t(a,r(i,n.text())));else if("prepend"===o)n.prepend(t.t(a,r(i,n.html())));else if("append"===o)n.append(t.t(a,r(i,n.html())));else if(0===o.indexOf("data-")){var s=o.substr("data-".length),d=t.t(a,r(i,n.data(s)));n.data(s,d),n.attr(o,d)}else n.attr(o,t.t(a,r(i,n.attr(o))))}}function r(t,n){var r=t.attr(f.selectorAttr);if(r||"undefined"==typeof r||r===!1||(r=t.text()||t.val()),r){var o=t,l=t.data(f.targetAttr);if(l&&(o=t.find(l)||t),n||f.useOptionsAttr!==!0||(n=t.data(f.optionsAttr)),n=n||{},r.indexOf(";")>=0){var s=r.split(";");a.each(s,function(t,e){""!==e&&i(o,e,n)})}else i(o,r,n);if(f.useOptionsAttr===!0){var d={};d=e({clone:d},n),delete d.lng,t.data(f.optionsAttr,d)}}}function o(t){return this.each(function(){r(a(this),t);var e=a(this).find("["+f.selectorAttr+"]");e.each(function(){r(a(this),t)})})}var f=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};f=e({},n,f),a[f.tName]=t.t.bind(t),a[f.i18nName]=t,a.fn[f.handleName]=o}var e=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var a in n)Object.prototype.hasOwnProperty.call(n,a)&&(t[a]=n[a])}return t},n={tName:"t",i18nName:"i18n",handleName:"localize",selectorAttr:"data-i18n",targetAttr:"i18n-target",optionsAttr:"i18n-options",useOptionsAttr:!1,parseDefaultValueFromContent:!0},a={init:t};return a});
/*!
* Source: lib/magnific-popup/dist/jquery.magnific-popup.min.js, license: MIT, url: http://dimsemenov.com/plugins/magnific-popup/
*/
-/*! Magnific Popup - v1.0.0 - 2015-01-03
+/*! Magnific Popup - v1.1.0 - 2016-02-20
* http://dimsemenov.com/plugins/magnific-popup/
-* Copyright (c) 2015 Dmitry Semenov; */
-!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):window.jQuery||window.Zepto)}(function(a){var b,c,d,e,f,g,h="Close",i="BeforeClose",j="AfterClose",k="BeforeAppend",l="MarkupParse",m="Open",n="Change",o="mfp",p="."+o,q="mfp-ready",r="mfp-removing",s="mfp-prevent-close",t=function(){},u=!!window.jQuery,v=a(window),w=function(a,c){b.ev.on(o+a+p,c)},x=function(b,c,d,e){var f=document.createElement("div");return f.className="mfp-"+b,d&&(f.innerHTML=d),e?c&&c.appendChild(f):(f=a(f),c&&f.appendTo(c)),f},y=function(c,d){b.ev.triggerHandler(o+c,d),b.st.callbacks&&(c=c.charAt(0).toLowerCase()+c.slice(1),b.st.callbacks[c]&&b.st.callbacks[c].apply(b,a.isArray(d)?d:[d]))},z=function(c){return c===g&&b.currTemplate.closeBtn||(b.currTemplate.closeBtn=a(b.st.closeMarkup.replace("%title%",b.st.tClose)),g=c),b.currTemplate.closeBtn},A=function(){a.magnificPopup.instance||(b=new t,b.init(),a.magnificPopup.instance=b)},B=function(){var a=document.createElement("p").style,b=["ms","O","Moz","Webkit"];if(void 0!==a.transition)return!0;for(;b.length;)if(b.pop()+"Transition"in a)return!0;return!1};t.prototype={constructor:t,init:function(){var c=navigator.appVersion;b.isIE7=-1!==c.indexOf("MSIE 7."),b.isIE8=-1!==c.indexOf("MSIE 8."),b.isLowIE=b.isIE7||b.isIE8,b.isAndroid=/android/gi.test(c),b.isIOS=/iphone|ipad|ipod/gi.test(c),b.supportsTransition=B(),b.probablyMobile=b.isAndroid||b.isIOS||/(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent),d=a(document),b.popupsCache={}},open:function(c){var e;if(c.isObj===!1){b.items=c.items.toArray(),b.index=0;var g,h=c.items;for(e=0;e<h.length;e++)if(g=h[e],g.parsed&&(g=g.el[0]),g===c.el[0]){b.index=e;break}}else b.items=a.isArray(c.items)?c.items:[c.items],b.index=c.index||0;if(b.isOpen)return void b.updateItemHTML();b.types=[],f="",b.ev=c.mainEl&&c.mainEl.length?c.mainEl.eq(0):d,c.key?(b.popupsCache[c.key]||(b.popupsCache[c.key]={}),b.currTemplate=b.popupsCache[c.key]):b.currTemplate={},b.st=a.extend(!0,{},a.magnificPopup.defaults,c),b.fixedContentPos="auto"===b.st.fixedContentPos?!b.probablyMobile:b.st.fixedContentPos,b.st.modal&&(b.st.closeOnContentClick=!1,b.st.closeOnBgClick=!1,b.st.showCloseBtn=!1,b.st.enableEscapeKey=!1),b.bgOverlay||(b.bgOverlay=x("bg").on("click"+p,function(){b.close()}),b.wrap=x("wrap").attr("tabindex",-1).on("click"+p,function(a){b._checkIfClose(a.target)&&b.close()}),b.container=x("container",b.wrap)),b.contentContainer=x("content"),b.st.preloader&&(b.preloader=x("preloader",b.container,b.st.tLoading));var i=a.magnificPopup.modules;for(e=0;e<i.length;e++){var j=i[e];j=j.charAt(0).toUpperCase()+j.slice(1),b["init"+j].call(b)}y("BeforeOpen"),b.st.showCloseBtn&&(b.st.closeBtnInside?(w(l,function(a,b,c,d){c.close_replaceWith=z(d.type)}),f+=" mfp-close-btn-in"):b.wrap.append(z())),b.st.alignTop&&(f+=" mfp-align-top"),b.wrap.css(b.fixedContentPos?{overflow:b.st.overflowY,overflowX:"hidden",overflowY:b.st.overflowY}:{top:v.scrollTop(),position:"absolute"}),(b.st.fixedBgPos===!1||"auto"===b.st.fixedBgPos&&!b.fixedContentPos)&&b.bgOverlay.css({height:d.height(),position:"absolute"}),b.st.enableEscapeKey&&d.on("keyup"+p,function(a){27===a.keyCode&&b.close()}),v.on("resize"+p,function(){b.updateSize()}),b.st.closeOnContentClick||(f+=" mfp-auto-cursor"),f&&b.wrap.addClass(f);var k=b.wH=v.height(),n={};if(b.fixedContentPos&&b._hasScrollBar(k)){var o=b._getScrollbarSize();o&&(n.marginRight=o)}b.fixedContentPos&&(b.isIE7?a("body, html").css("overflow","hidden"):n.overflow="hidden");var r=b.st.mainClass;return b.isIE7&&(r+=" mfp-ie7"),r&&b._addClassToMFP(r),b.updateItemHTML(),y("BuildControls"),a("html").css(n),b.bgOverlay.add(b.wrap).prependTo(b.st.prependTo||a(document.body)),b._lastFocusedEl=document.activeElement,setTimeout(function(){b.content?(b._addClassToMFP(q),b._setFocus()):b.bgOverlay.addClass(q),d.on("focusin"+p,b._onFocusIn)},16),b.isOpen=!0,b.updateSize(k),y(m),c},close:function(){b.isOpen&&(y(i),b.isOpen=!1,b.st.removalDelay&&!b.isLowIE&&b.supportsTransition?(b._addClassToMFP(r),setTimeout(function(){b._close()},b.st.removalDelay)):b._close())},_close:function(){y(h);var c=r+" "+q+" ";if(b.bgOverlay.detach(),b.wrap.detach(),b.container.empty(),b.st.mainClass&&(c+=b.st.mainClass+" "),b._removeClassFromMFP(c),b.fixedContentPos){var e={marginRight:""};b.isIE7?a("body, html").css("overflow",""):e.overflow="",a("html").css(e)}d.off("keyup"+p+" focusin"+p),b.ev.off(p),b.wrap.attr("class","mfp-wrap").removeAttr("style"),b.bgOverlay.attr("class","mfp-bg"),b.container.attr("class","mfp-container"),!b.st.showCloseBtn||b.st.closeBtnInside&&b.currTemplate[b.currItem.type]!==!0||b.currTemplate.closeBtn&&b.currTemplate.closeBtn.detach(),b._lastFocusedEl&&a(b._lastFocusedEl).focus(),b.currItem=null,b.content=null,b.currTemplate=null,b.prevHeight=0,y(j)},updateSize:function(a){if(b.isIOS){var c=document.documentElement.clientWidth/window.innerWidth,d=window.innerHeight*c;b.wrap.css("height",d),b.wH=d}else b.wH=a||v.height();b.fixedContentPos||b.wrap.css("height",b.wH),y("Resize")},updateItemHTML:function(){var c=b.items[b.index];b.contentContainer.detach(),b.content&&b.content.detach(),c.parsed||(c=b.parseEl(b.index));var d=c.type;if(y("BeforeChange",[b.currItem?b.currItem.type:"",d]),b.currItem=c,!b.currTemplate[d]){var f=b.st[d]?b.st[d].markup:!1;y("FirstMarkupParse",f),b.currTemplate[d]=f?a(f):!0}e&&e!==c.type&&b.container.removeClass("mfp-"+e+"-holder");var g=b["get"+d.charAt(0).toUpperCase()+d.slice(1)](c,b.currTemplate[d]);b.appendContent(g,d),c.preloaded=!0,y(n,c),e=c.type,b.container.prepend(b.contentContainer),y("AfterChange")},appendContent:function(a,c){b.content=a,a?b.st.showCloseBtn&&b.st.closeBtnInside&&b.currTemplate[c]===!0?b.content.find(".mfp-close").length||b.content.append(z()):b.content=a:b.content="",y(k),b.container.addClass("mfp-"+c+"-holder"),b.contentContainer.append(b.content)},parseEl:function(c){var d,e=b.items[c];if(e.tagName?e={el:a(e)}:(d=e.type,e={data:e,src:e.src}),e.el){for(var f=b.types,g=0;g<f.length;g++)if(e.el.hasClass("mfp-"+f[g])){d=f[g];break}e.src=e.el.attr("data-mfp-src"),e.src||(e.src=e.el.attr("href"))}return e.type=d||b.st.type||"inline",e.index=c,e.parsed=!0,b.items[c]=e,y("ElementParse",e),b.items[c]},addGroup:function(a,c){var d=function(d){d.mfpEl=this,b._openClick(d,a,c)};c||(c={});var e="click.magnificPopup";c.mainEl=a,c.items?(c.isObj=!0,a.off(e).on(e,d)):(c.isObj=!1,c.delegate?a.off(e).on(e,c.delegate,d):(c.items=a,a.off(e).on(e,d)))},_openClick:function(c,d,e){var f=void 0!==e.midClick?e.midClick:a.magnificPopup.defaults.midClick;if(f||2!==c.which&&!c.ctrlKey&&!c.metaKey){var g=void 0!==e.disableOn?e.disableOn:a.magnificPopup.defaults.disableOn;if(g)if(a.isFunction(g)){if(!g.call(b))return!0}else if(v.width()<g)return!0;c.type&&(c.preventDefault(),b.isOpen&&c.stopPropagation()),e.el=a(c.mfpEl),e.delegate&&(e.items=d.find(e.delegate)),b.open(e)}},updateStatus:function(a,d){if(b.preloader){c!==a&&b.container.removeClass("mfp-s-"+c),d||"loading"!==a||(d=b.st.tLoading);var e={status:a,text:d};y("UpdateStatus",e),a=e.status,d=e.text,b.preloader.html(d),b.preloader.find("a").on("click",function(a){a.stopImmediatePropagation()}),b.container.addClass("mfp-s-"+a),c=a}},_checkIfClose:function(c){if(!a(c).hasClass(s)){var d=b.st.closeOnContentClick,e=b.st.closeOnBgClick;if(d&&e)return!0;if(!b.content||a(c).hasClass("mfp-close")||b.preloader&&c===b.preloader[0])return!0;if(c===b.content[0]||a.contains(b.content[0],c)){if(d)return!0}else if(e&&a.contains(document,c))return!0;return!1}},_addClassToMFP:function(a){b.bgOverlay.addClass(a),b.wrap.addClass(a)},_removeClassFromMFP:function(a){this.bgOverlay.removeClass(a),b.wrap.removeClass(a)},_hasScrollBar:function(a){return(b.isIE7?d.height():document.body.scrollHeight)>(a||v.height())},_setFocus:function(){(b.st.focus?b.content.find(b.st.focus).eq(0):b.wrap).focus()},_onFocusIn:function(c){return c.target===b.wrap[0]||a.contains(b.wrap[0],c.target)?void 0:(b._setFocus(),!1)},_parseMarkup:function(b,c,d){var e;d.data&&(c=a.extend(d.data,c)),y(l,[b,c,d]),a.each(c,function(a,c){if(void 0===c||c===!1)return!0;if(e=a.split("_"),e.length>1){var d=b.find(p+"-"+e[0]);if(d.length>0){var f=e[1];"replaceWith"===f?d[0]!==c[0]&&d.replaceWith(c):"img"===f?d.is("img")?d.attr("src",c):d.replaceWith('<img src="'+c+'" class="'+d.attr("class")+'" />'):d.attr(e[1],c)}}else b.find(p+"-"+a).html(c)})},_getScrollbarSize:function(){if(void 0===b.scrollbarSize){var a=document.createElement("div");a.style.cssText="width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;",document.body.appendChild(a),b.scrollbarSize=a.offsetWidth-a.clientWidth,document.body.removeChild(a)}return b.scrollbarSize}},a.magnificPopup={instance:null,proto:t.prototype,modules:[],open:function(b,c){return A(),b=b?a.extend(!0,{},b):{},b.isObj=!0,b.index=c||0,this.instance.open(b)},close:function(){return a.magnificPopup.instance&&a.magnificPopup.instance.close()},registerModule:function(b,c){c.options&&(a.magnificPopup.defaults[b]=c.options),a.extend(this.proto,c.proto),this.modules.push(b)},defaults:{disableOn:0,key:null,midClick:!1,mainClass:"",preloader:!0,focus:"",closeOnContentClick:!1,closeOnBgClick:!0,closeBtnInside:!0,showCloseBtn:!0,enableEscapeKey:!0,modal:!1,alignTop:!1,removalDelay:0,prependTo:null,fixedContentPos:"auto",fixedBgPos:"auto",overflowY:"auto",closeMarkup:'<button title="%title%" type="button" class="mfp-close">&times;</button>',tClose:"Close (Esc)",tLoading:"Loading..."}},a.fn.magnificPopup=function(c){A();var d=a(this);if("string"==typeof c)if("open"===c){var e,f=u?d.data("magnificPopup"):d[0].magnificPopup,g=parseInt(arguments[1],10)||0;f.items?e=f.items[g]:(e=d,f.delegate&&(e=e.find(f.delegate)),e=e.eq(g)),b._openClick({mfpEl:e},d,f)}else b.isOpen&&b[c].apply(b,Array.prototype.slice.call(arguments,1));else c=a.extend(!0,{},c),u?d.data("magnificPopup",c):d[0].magnificPopup=c,b.addGroup(d,c);return d};var C,D,E,F="inline",G=function(){E&&(D.after(E.addClass(C)).detach(),E=null)};a.magnificPopup.registerModule(F,{options:{hiddenClass:"hide",markup:"",tNotFound:"Content not found"},proto:{initInline:function(){b.types.push(F),w(h+"."+F,function(){G()})},getInline:function(c,d){if(G(),c.src){var e=b.st.inline,f=a(c.src);if(f.length){var g=f[0].parentNode;g&&g.tagName&&(D||(C=e.hiddenClass,D=x(C),C="mfp-"+C),E=f.after(D).detach().removeClass(C)),b.updateStatus("ready")}else b.updateStatus("error",e.tNotFound),f=a("<div>");return c.inlineElement=f,f}return b.updateStatus("ready"),b._parseMarkup(d,{},c),d}}});var H,I="ajax",J=function(){H&&a(document.body).removeClass(H)},K=function(){J(),b.req&&b.req.abort()};a.magnificPopup.registerModule(I,{options:{settings:null,cursor:"mfp-ajax-cur",tError:'<a href="%url%">The content</a> could not be loaded.'},proto:{initAjax:function(){b.types.push(I),H=b.st.ajax.cursor,w(h+"."+I,K),w("BeforeChange."+I,K)},getAjax:function(c){H&&a(document.body).addClass(H),b.updateStatus("loading");var d=a.extend({url:c.src,success:function(d,e,f){var g={data:d,xhr:f};y("ParseAjax",g),b.appendContent(a(g.data),I),c.finished=!0,J(),b._setFocus(),setTimeout(function(){b.wrap.addClass(q)},16),b.updateStatus("ready"),y("AjaxContentAdded")},error:function(){J(),c.finished=c.loadError=!0,b.updateStatus("error",b.st.ajax.tError.replace("%url%",c.src))}},b.st.ajax.settings);return b.req=a.ajax(d),""}}});var L,M=function(c){if(c.data&&void 0!==c.data.title)return c.data.title;var d=b.st.image.titleSrc;if(d){if(a.isFunction(d))return d.call(b,c);if(c.el)return c.el.attr(d)||""}return""};a.magnificPopup.registerModule("image",{options:{markup:'<div class="mfp-figure"><div class="mfp-close"></div><figure><div class="mfp-img"></div><figcaption><div class="mfp-bottom-bar"><div class="mfp-title"></div><div class="mfp-counter"></div></div></figcaption></figure></div>',cursor:"mfp-zoom-out-cur",titleSrc:"title",verticalFit:!0,tError:'<a href="%url%">The image</a> could not be loaded.'},proto:{initImage:function(){var c=b.st.image,d=".image";b.types.push("image"),w(m+d,function(){"image"===b.currItem.type&&c.cursor&&a(document.body).addClass(c.cursor)}),w(h+d,function(){c.cursor&&a(document.body).removeClass(c.cursor),v.off("resize"+p)}),w("Resize"+d,b.resizeImage),b.isLowIE&&w("AfterChange",b.resizeImage)},resizeImage:function(){var a=b.currItem;if(a&&a.img&&b.st.image.verticalFit){var c=0;b.isLowIE&&(c=parseInt(a.img.css("padding-top"),10)+parseInt(a.img.css("padding-bottom"),10)),a.img.css("max-height",b.wH-c)}},_onImageHasSize:function(a){a.img&&(a.hasSize=!0,L&&clearInterval(L),a.isCheckingImgSize=!1,y("ImageHasSize",a),a.imgHidden&&(b.content&&b.content.removeClass("mfp-loading"),a.imgHidden=!1))},findImageSize:function(a){var c=0,d=a.img[0],e=function(f){L&&clearInterval(L),L=setInterval(function(){return d.naturalWidth>0?void b._onImageHasSize(a):(c>200&&clearInterval(L),c++,void(3===c?e(10):40===c?e(50):100===c&&e(500)))},f)};e(1)},getImage:function(c,d){var e=0,f=function(){c&&(c.img[0].complete?(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("ready")),c.hasSize=!0,c.loaded=!0,y("ImageLoadComplete")):(e++,200>e?setTimeout(f,100):g()))},g=function(){c&&(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("error",h.tError.replace("%url%",c.src))),c.hasSize=!0,c.loaded=!0,c.loadError=!0)},h=b.st.image,i=d.find(".mfp-img");if(i.length){var j=document.createElement("img");j.className="mfp-img",c.el&&c.el.find("img").length&&(j.alt=c.el.find("img").attr("alt")),c.img=a(j).on("load.mfploader",f).on("error.mfploader",g),j.src=c.src,i.is("img")&&(c.img=c.img.clone()),j=c.img[0],j.naturalWidth>0?c.hasSize=!0:j.width||(c.hasSize=!1)}return b._parseMarkup(d,{title:M(c),img_replaceWith:c.img},c),b.resizeImage(),c.hasSize?(L&&clearInterval(L),c.loadError?(d.addClass("mfp-loading"),b.updateStatus("error",h.tError.replace("%url%",c.src))):(d.removeClass("mfp-loading"),b.updateStatus("ready")),d):(b.updateStatus("loading"),c.loading=!0,c.hasSize||(c.imgHidden=!0,d.addClass("mfp-loading"),b.findImageSize(c)),d)}}});var N,O=function(){return void 0===N&&(N=void 0!==document.createElement("p").style.MozTransform),N};a.magnificPopup.registerModule("zoom",{options:{enabled:!1,easing:"ease-in-out",duration:300,opener:function(a){return a.is("img")?a:a.find("img")}},proto:{initZoom:function(){var a,c=b.st.zoom,d=".zoom";if(c.enabled&&b.supportsTransition){var e,f,g=c.duration,j=function(a){var b=a.clone().removeAttr("style").removeAttr("class").addClass("mfp-animated-image"),d="all "+c.duration/1e3+"s "+c.easing,e={position:"fixed",zIndex:9999,left:0,top:0,"-webkit-backface-visibility":"hidden"},f="transition";return e["-webkit-"+f]=e["-moz-"+f]=e["-o-"+f]=e[f]=d,b.css(e),b},k=function(){b.content.css("visibility","visible")};w("BuildControls"+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.content.css("visibility","hidden"),a=b._getItemToZoom(),!a)return void k();f=j(a),f.css(b._getOffset()),b.wrap.append(f),e=setTimeout(function(){f.css(b._getOffset(!0)),e=setTimeout(function(){k(),setTimeout(function(){f.remove(),a=f=null,y("ZoomAnimationEnded")},16)},g)},16)}}),w(i+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.st.removalDelay=g,!a){if(a=b._getItemToZoom(),!a)return;f=j(a)}f.css(b._getOffset(!0)),b.wrap.append(f),b.content.css("visibility","hidden"),setTimeout(function(){f.css(b._getOffset())},16)}}),w(h+d,function(){b._allowZoom()&&(k(),f&&f.remove(),a=null)})}},_allowZoom:function(){return"image"===b.currItem.type},_getItemToZoom:function(){return b.currItem.hasSize?b.currItem.img:!1},_getOffset:function(c){var d;d=c?b.currItem.img:b.st.zoom.opener(b.currItem.el||b.currItem);var e=d.offset(),f=parseInt(d.css("padding-top"),10),g=parseInt(d.css("padding-bottom"),10);e.top-=a(window).scrollTop()-f;var h={width:d.width(),height:(u?d.innerHeight():d[0].offsetHeight)-g-f};return O()?h["-moz-transform"]=h.transform="translate("+e.left+"px,"+e.top+"px)":(h.left=e.left,h.top=e.top),h}}});var P="iframe",Q="//about:blank",R=function(a){if(b.currTemplate[P]){var c=b.currTemplate[P].find("iframe");c.length&&(a||(c[0].src=Q),b.isIE8&&c.css("display",a?"block":"none"))}};a.magnificPopup.registerModule(P,{options:{markup:'<div class="mfp-iframe-scaler"><div class="mfp-close"></div><iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe></div>',srcAction:"iframe_src",patterns:{youtube:{index:"youtube.com",id:"v=",src:"//www.youtube.com/embed/%id%?autoplay=1"},vimeo:{index:"vimeo.com/",id:"/",src:"//player.vimeo.com/video/%id%?autoplay=1"},gmaps:{index:"//maps.google.",src:"%id%&output=embed"}}},proto:{initIframe:function(){b.types.push(P),w("BeforeChange",function(a,b,c){b!==c&&(b===P?R():c===P&&R(!0))}),w(h+"."+P,function(){R()})},getIframe:function(c,d){var e=c.src,f=b.st.iframe;a.each(f.patterns,function(){return e.indexOf(this.index)>-1?(this.id&&(e="string"==typeof this.id?e.substr(e.lastIndexOf(this.id)+this.id.length,e.length):this.id.call(this,e)),e=this.src.replace("%id%",e),!1):void 0});var g={};return f.srcAction&&(g[f.srcAction]=e),b._parseMarkup(d,g,c),b.updateStatus("ready"),d}}});var S=function(a){var c=b.items.length;return a>c-1?a-c:0>a?c+a:a},T=function(a,b,c){return a.replace(/%curr%/gi,b+1).replace(/%total%/gi,c)};a.magnificPopup.registerModule("gallery",{options:{enabled:!1,arrowMarkup:'<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',preload:[0,2],navigateByImgClick:!0,arrows:!0,tPrev:"Previous (Left arrow key)",tNext:"Next (Right arrow key)",tCounter:"%curr% of %total%"},proto:{initGallery:function(){var c=b.st.gallery,e=".mfp-gallery",g=Boolean(a.fn.mfpFastClick);return b.direction=!0,c&&c.enabled?(f+=" mfp-gallery",w(m+e,function(){c.navigateByImgClick&&b.wrap.on("click"+e,".mfp-img",function(){return b.items.length>1?(b.next(),!1):void 0}),d.on("keydown"+e,function(a){37===a.keyCode?b.prev():39===a.keyCode&&b.next()})}),w("UpdateStatus"+e,function(a,c){c.text&&(c.text=T(c.text,b.currItem.index,b.items.length))}),w(l+e,function(a,d,e,f){var g=b.items.length;e.counter=g>1?T(c.tCounter,f.index,g):""}),w("BuildControls"+e,function(){if(b.items.length>1&&c.arrows&&!b.arrowLeft){var d=c.arrowMarkup,e=b.arrowLeft=a(d.replace(/%title%/gi,c.tPrev).replace(/%dir%/gi,"left")).addClass(s),f=b.arrowRight=a(d.replace(/%title%/gi,c.tNext).replace(/%dir%/gi,"right")).addClass(s),h=g?"mfpFastClick":"click";e[h](function(){b.prev()}),f[h](function(){b.next()}),b.isIE7&&(x("b",e[0],!1,!0),x("a",e[0],!1,!0),x("b",f[0],!1,!0),x("a",f[0],!1,!0)),b.container.append(e.add(f))}}),w(n+e,function(){b._preloadTimeout&&clearTimeout(b._preloadTimeout),b._preloadTimeout=setTimeout(function(){b.preloadNearbyImages(),b._preloadTimeout=null},16)}),void w(h+e,function(){d.off(e),b.wrap.off("click"+e),b.arrowLeft&&g&&b.arrowLeft.add(b.arrowRight).destroyMfpFastClick(),b.arrowRight=b.arrowLeft=null})):!1},next:function(){b.direction=!0,b.index=S(b.index+1),b.updateItemHTML()},prev:function(){b.direction=!1,b.index=S(b.index-1),b.updateItemHTML()},goTo:function(a){b.direction=a>=b.index,b.index=a,b.updateItemHTML()},preloadNearbyImages:function(){var a,c=b.st.gallery.preload,d=Math.min(c[0],b.items.length),e=Math.min(c[1],b.items.length);for(a=1;a<=(b.direction?e:d);a++)b._preloadItem(b.index+a);for(a=1;a<=(b.direction?d:e);a++)b._preloadItem(b.index-a)},_preloadItem:function(c){if(c=S(c),!b.items[c].preloaded){var d=b.items[c];d.parsed||(d=b.parseEl(c)),y("LazyLoad",d),"image"===d.type&&(d.img=a('<img class="mfp-img" />').on("load.mfploader",function(){d.hasSize=!0}).on("error.mfploader",function(){d.hasSize=!0,d.loadError=!0,y("LazyLoadError",d)}).attr("src",d.src)),d.preloaded=!0}}}});var U="retina";a.magnificPopup.registerModule(U,{options:{replaceSrc:function(a){return a.src.replace(/\.\w+$/,function(a){return"@2x"+a})},ratio:1},proto:{initRetina:function(){if(window.devicePixelRatio>1){var a=b.st.retina,c=a.ratio;c=isNaN(c)?c():c,c>1&&(w("ImageHasSize."+U,function(a,b){b.img.css({"max-width":b.img[0].naturalWidth/c,width:"100%"})}),w("ElementParse."+U,function(b,d){d.src=a.replaceSrc(d,c)}))}}}}),function(){var b=1e3,c="ontouchstart"in window,d=function(){v.off("touchmove"+f+" touchend"+f)},e="mfpFastClick",f="."+e;a.fn.mfpFastClick=function(e){return a(this).each(function(){var g,h=a(this);if(c){var i,j,k,l,m,n;h.on("touchstart"+f,function(a){l=!1,n=1,m=a.originalEvent?a.originalEvent.touches[0]:a.touches[0],j=m.clientX,k=m.clientY,v.on("touchmove"+f,function(a){m=a.originalEvent?a.originalEvent.touches:a.touches,n=m.length,m=m[0],(Math.abs(m.clientX-j)>10||Math.abs(m.clientY-k)>10)&&(l=!0,d())}).on("touchend"+f,function(a){d(),l||n>1||(g=!0,a.preventDefault(),clearTimeout(i),i=setTimeout(function(){g=!1},b),e())})})}h.on("click"+f,function(){g||e()})})},a.fn.destroyMfpFastClick=function(){a(this).off("touchstart"+f+" click"+f),c&&v.off("touchmove"+f+" touchend"+f)}}(),A()});
+* Copyright (c) 2016 Dmitry Semenov; */
+!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):window.jQuery||window.Zepto)}(function(a){var b,c,d,e,f,g,h="Close",i="BeforeClose",j="AfterClose",k="BeforeAppend",l="MarkupParse",m="Open",n="Change",o="mfp",p="."+o,q="mfp-ready",r="mfp-removing",s="mfp-prevent-close",t=function(){},u=!!window.jQuery,v=a(window),w=function(a,c){b.ev.on(o+a+p,c)},x=function(b,c,d,e){var f=document.createElement("div");return f.className="mfp-"+b,d&&(f.innerHTML=d),e?c&&c.appendChild(f):(f=a(f),c&&f.appendTo(c)),f},y=function(c,d){b.ev.triggerHandler(o+c,d),b.st.callbacks&&(c=c.charAt(0).toLowerCase()+c.slice(1),b.st.callbacks[c]&&b.st.callbacks[c].apply(b,a.isArray(d)?d:[d]))},z=function(c){return c===g&&b.currTemplate.closeBtn||(b.currTemplate.closeBtn=a(b.st.closeMarkup.replace("%title%",b.st.tClose)),g=c),b.currTemplate.closeBtn},A=function(){a.magnificPopup.instance||(b=new t,b.init(),a.magnificPopup.instance=b)},B=function(){var a=document.createElement("p").style,b=["ms","O","Moz","Webkit"];if(void 0!==a.transition)return!0;for(;b.length;)if(b.pop()+"Transition"in a)return!0;return!1};t.prototype={constructor:t,init:function(){var c=navigator.appVersion;b.isLowIE=b.isIE8=document.all&&!document.addEventListener,b.isAndroid=/android/gi.test(c),b.isIOS=/iphone|ipad|ipod/gi.test(c),b.supportsTransition=B(),b.probablyMobile=b.isAndroid||b.isIOS||/(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent),d=a(document),b.popupsCache={}},open:function(c){var e;if(c.isObj===!1){b.items=c.items.toArray(),b.index=0;var g,h=c.items;for(e=0;e<h.length;e++)if(g=h[e],g.parsed&&(g=g.el[0]),g===c.el[0]){b.index=e;break}}else b.items=a.isArray(c.items)?c.items:[c.items],b.index=c.index||0;if(b.isOpen)return void b.updateItemHTML();b.types=[],f="",c.mainEl&&c.mainEl.length?b.ev=c.mainEl.eq(0):b.ev=d,c.key?(b.popupsCache[c.key]||(b.popupsCache[c.key]={}),b.currTemplate=b.popupsCache[c.key]):b.currTemplate={},b.st=a.extend(!0,{},a.magnificPopup.defaults,c),b.fixedContentPos="auto"===b.st.fixedContentPos?!b.probablyMobile:b.st.fixedContentPos,b.st.modal&&(b.st.closeOnContentClick=!1,b.st.closeOnBgClick=!1,b.st.showCloseBtn=!1,b.st.enableEscapeKey=!1),b.bgOverlay||(b.bgOverlay=x("bg").on("click"+p,function(){b.close()}),b.wrap=x("wrap").attr("tabindex",-1).on("click"+p,function(a){b._checkIfClose(a.target)&&b.close()}),b.container=x("container",b.wrap)),b.contentContainer=x("content"),b.st.preloader&&(b.preloader=x("preloader",b.container,b.st.tLoading));var i=a.magnificPopup.modules;for(e=0;e<i.length;e++){var j=i[e];j=j.charAt(0).toUpperCase()+j.slice(1),b["init"+j].call(b)}y("BeforeOpen"),b.st.showCloseBtn&&(b.st.closeBtnInside?(w(l,function(a,b,c,d){c.close_replaceWith=z(d.type)}),f+=" mfp-close-btn-in"):b.wrap.append(z())),b.st.alignTop&&(f+=" mfp-align-top"),b.fixedContentPos?b.wrap.css({overflow:b.st.overflowY,overflowX:"hidden",overflowY:b.st.overflowY}):b.wrap.css({top:v.scrollTop(),position:"absolute"}),(b.st.fixedBgPos===!1||"auto"===b.st.fixedBgPos&&!b.fixedContentPos)&&b.bgOverlay.css({height:d.height(),position:"absolute"}),b.st.enableEscapeKey&&d.on("keyup"+p,function(a){27===a.keyCode&&b.close()}),v.on("resize"+p,function(){b.updateSize()}),b.st.closeOnContentClick||(f+=" mfp-auto-cursor"),f&&b.wrap.addClass(f);var k=b.wH=v.height(),n={};if(b.fixedContentPos&&b._hasScrollBar(k)){var o=b._getScrollbarSize();o&&(n.marginRight=o)}b.fixedContentPos&&(b.isIE7?a("body, html").css("overflow","hidden"):n.overflow="hidden");var r=b.st.mainClass;return b.isIE7&&(r+=" mfp-ie7"),r&&b._addClassToMFP(r),b.updateItemHTML(),y("BuildControls"),a("html").css(n),b.bgOverlay.add(b.wrap).prependTo(b.st.prependTo||a(document.body)),b._lastFocusedEl=document.activeElement,setTimeout(function(){b.content?(b._addClassToMFP(q),b._setFocus()):b.bgOverlay.addClass(q),d.on("focusin"+p,b._onFocusIn)},16),b.isOpen=!0,b.updateSize(k),y(m),c},close:function(){b.isOpen&&(y(i),b.isOpen=!1,b.st.removalDelay&&!b.isLowIE&&b.supportsTransition?(b._addClassToMFP(r),setTimeout(function(){b._close()},b.st.removalDelay)):b._close())},_close:function(){y(h);var c=r+" "+q+" ";if(b.bgOverlay.detach(),b.wrap.detach(),b.container.empty(),b.st.mainClass&&(c+=b.st.mainClass+" "),b._removeClassFromMFP(c),b.fixedContentPos){var e={marginRight:""};b.isIE7?a("body, html").css("overflow",""):e.overflow="",a("html").css(e)}d.off("keyup"+p+" focusin"+p),b.ev.off(p),b.wrap.attr("class","mfp-wrap").removeAttr("style"),b.bgOverlay.attr("class","mfp-bg"),b.container.attr("class","mfp-container"),!b.st.showCloseBtn||b.st.closeBtnInside&&b.currTemplate[b.currItem.type]!==!0||b.currTemplate.closeBtn&&b.currTemplate.closeBtn.detach(),b.st.autoFocusLast&&b._lastFocusedEl&&a(b._lastFocusedEl).focus(),b.currItem=null,b.content=null,b.currTemplate=null,b.prevHeight=0,y(j)},updateSize:function(a){if(b.isIOS){var c=document.documentElement.clientWidth/window.innerWidth,d=window.innerHeight*c;b.wrap.css("height",d),b.wH=d}else b.wH=a||v.height();b.fixedContentPos||b.wrap.css("height",b.wH),y("Resize")},updateItemHTML:function(){var c=b.items[b.index];b.contentContainer.detach(),b.content&&b.content.detach(),c.parsed||(c=b.parseEl(b.index));var d=c.type;if(y("BeforeChange",[b.currItem?b.currItem.type:"",d]),b.currItem=c,!b.currTemplate[d]){var f=b.st[d]?b.st[d].markup:!1;y("FirstMarkupParse",f),f?b.currTemplate[d]=a(f):b.currTemplate[d]=!0}e&&e!==c.type&&b.container.removeClass("mfp-"+e+"-holder");var g=b["get"+d.charAt(0).toUpperCase()+d.slice(1)](c,b.currTemplate[d]);b.appendContent(g,d),c.preloaded=!0,y(n,c),e=c.type,b.container.prepend(b.contentContainer),y("AfterChange")},appendContent:function(a,c){b.content=a,a?b.st.showCloseBtn&&b.st.closeBtnInside&&b.currTemplate[c]===!0?b.content.find(".mfp-close").length||b.content.append(z()):b.content=a:b.content="",y(k),b.container.addClass("mfp-"+c+"-holder"),b.contentContainer.append(b.content)},parseEl:function(c){var d,e=b.items[c];if(e.tagName?e={el:a(e)}:(d=e.type,e={data:e,src:e.src}),e.el){for(var f=b.types,g=0;g<f.length;g++)if(e.el.hasClass("mfp-"+f[g])){d=f[g];break}e.src=e.el.attr("data-mfp-src"),e.src||(e.src=e.el.attr("href"))}return e.type=d||b.st.type||"inline",e.index=c,e.parsed=!0,b.items[c]=e,y("ElementParse",e),b.items[c]},addGroup:function(a,c){var d=function(d){d.mfpEl=this,b._openClick(d,a,c)};c||(c={});var e="click.magnificPopup";c.mainEl=a,c.items?(c.isObj=!0,a.off(e).on(e,d)):(c.isObj=!1,c.delegate?a.off(e).on(e,c.delegate,d):(c.items=a,a.off(e).on(e,d)))},_openClick:function(c,d,e){var f=void 0!==e.midClick?e.midClick:a.magnificPopup.defaults.midClick;if(f||!(2===c.which||c.ctrlKey||c.metaKey||c.altKey||c.shiftKey)){var g=void 0!==e.disableOn?e.disableOn:a.magnificPopup.defaults.disableOn;if(g)if(a.isFunction(g)){if(!g.call(b))return!0}else if(v.width()<g)return!0;c.type&&(c.preventDefault(),b.isOpen&&c.stopPropagation()),e.el=a(c.mfpEl),e.delegate&&(e.items=d.find(e.delegate)),b.open(e)}},updateStatus:function(a,d){if(b.preloader){c!==a&&b.container.removeClass("mfp-s-"+c),d||"loading"!==a||(d=b.st.tLoading);var e={status:a,text:d};y("UpdateStatus",e),a=e.status,d=e.text,b.preloader.html(d),b.preloader.find("a").on("click",function(a){a.stopImmediatePropagation()}),b.container.addClass("mfp-s-"+a),c=a}},_checkIfClose:function(c){if(!a(c).hasClass(s)){var d=b.st.closeOnContentClick,e=b.st.closeOnBgClick;if(d&&e)return!0;if(!b.content||a(c).hasClass("mfp-close")||b.preloader&&c===b.preloader[0])return!0;if(c===b.content[0]||a.contains(b.content[0],c)){if(d)return!0}else if(e&&a.contains(document,c))return!0;return!1}},_addClassToMFP:function(a){b.bgOverlay.addClass(a),b.wrap.addClass(a)},_removeClassFromMFP:function(a){this.bgOverlay.removeClass(a),b.wrap.removeClass(a)},_hasScrollBar:function(a){return(b.isIE7?d.height():document.body.scrollHeight)>(a||v.height())},_setFocus:function(){(b.st.focus?b.content.find(b.st.focus).eq(0):b.wrap).focus()},_onFocusIn:function(c){return c.target===b.wrap[0]||a.contains(b.wrap[0],c.target)?void 0:(b._setFocus(),!1)},_parseMarkup:function(b,c,d){var e;d.data&&(c=a.extend(d.data,c)),y(l,[b,c,d]),a.each(c,function(c,d){if(void 0===d||d===!1)return!0;if(e=c.split("_"),e.length>1){var f=b.find(p+"-"+e[0]);if(f.length>0){var g=e[1];"replaceWith"===g?f[0]!==d[0]&&f.replaceWith(d):"img"===g?f.is("img")?f.attr("src",d):f.replaceWith(a("<img>").attr("src",d).attr("class",f.attr("class"))):f.attr(e[1],d)}}else b.find(p+"-"+c).html(d)})},_getScrollbarSize:function(){if(void 0===b.scrollbarSize){var a=document.createElement("div");a.style.cssText="width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;",document.body.appendChild(a),b.scrollbarSize=a.offsetWidth-a.clientWidth,document.body.removeChild(a)}return b.scrollbarSize}},a.magnificPopup={instance:null,proto:t.prototype,modules:[],open:function(b,c){return A(),b=b?a.extend(!0,{},b):{},b.isObj=!0,b.index=c||0,this.instance.open(b)},close:function(){return a.magnificPopup.instance&&a.magnificPopup.instance.close()},registerModule:function(b,c){c.options&&(a.magnificPopup.defaults[b]=c.options),a.extend(this.proto,c.proto),this.modules.push(b)},defaults:{disableOn:0,key:null,midClick:!1,mainClass:"",preloader:!0,focus:"",closeOnContentClick:!1,closeOnBgClick:!0,closeBtnInside:!0,showCloseBtn:!0,enableEscapeKey:!0,modal:!1,alignTop:!1,removalDelay:0,prependTo:null,fixedContentPos:"auto",fixedBgPos:"auto",overflowY:"auto",closeMarkup:'<button title="%title%" type="button" class="mfp-close">&#215;</button>',tClose:"Close (Esc)",tLoading:"Loading...",autoFocusLast:!0}},a.fn.magnificPopup=function(c){A();var d=a(this);if("string"==typeof c)if("open"===c){var e,f=u?d.data("magnificPopup"):d[0].magnificPopup,g=parseInt(arguments[1],10)||0;f.items?e=f.items[g]:(e=d,f.delegate&&(e=e.find(f.delegate)),e=e.eq(g)),b._openClick({mfpEl:e},d,f)}else b.isOpen&&b[c].apply(b,Array.prototype.slice.call(arguments,1));else c=a.extend(!0,{},c),u?d.data("magnificPopup",c):d[0].magnificPopup=c,b.addGroup(d,c);return d};var C,D,E,F="inline",G=function(){E&&(D.after(E.addClass(C)).detach(),E=null)};a.magnificPopup.registerModule(F,{options:{hiddenClass:"hide",markup:"",tNotFound:"Content not found"},proto:{initInline:function(){b.types.push(F),w(h+"."+F,function(){G()})},getInline:function(c,d){if(G(),c.src){var e=b.st.inline,f=a(c.src);if(f.length){var g=f[0].parentNode;g&&g.tagName&&(D||(C=e.hiddenClass,D=x(C),C="mfp-"+C),E=f.after(D).detach().removeClass(C)),b.updateStatus("ready")}else b.updateStatus("error",e.tNotFound),f=a("<div>");return c.inlineElement=f,f}return b.updateStatus("ready"),b._parseMarkup(d,{},c),d}}});var H,I="ajax",J=function(){H&&a(document.body).removeClass(H)},K=function(){J(),b.req&&b.req.abort()};a.magnificPopup.registerModule(I,{options:{settings:null,cursor:"mfp-ajax-cur",tError:'<a href="%url%">The content</a> could not be loaded.'},proto:{initAjax:function(){b.types.push(I),H=b.st.ajax.cursor,w(h+"."+I,K),w("BeforeChange."+I,K)},getAjax:function(c){H&&a(document.body).addClass(H),b.updateStatus("loading");var d=a.extend({url:c.src,success:function(d,e,f){var g={data:d,xhr:f};y("ParseAjax",g),b.appendContent(a(g.data),I),c.finished=!0,J(),b._setFocus(),setTimeout(function(){b.wrap.addClass(q)},16),b.updateStatus("ready"),y("AjaxContentAdded")},error:function(){J(),c.finished=c.loadError=!0,b.updateStatus("error",b.st.ajax.tError.replace("%url%",c.src))}},b.st.ajax.settings);return b.req=a.ajax(d),""}}});var L,M=function(c){if(c.data&&void 0!==c.data.title)return c.data.title;var d=b.st.image.titleSrc;if(d){if(a.isFunction(d))return d.call(b,c);if(c.el)return c.el.attr(d)||""}return""};a.magnificPopup.registerModule("image",{options:{markup:'<div class="mfp-figure"><div class="mfp-close"></div><figure><div class="mfp-img"></div><figcaption><div class="mfp-bottom-bar"><div class="mfp-title"></div><div class="mfp-counter"></div></div></figcaption></figure></div>',cursor:"mfp-zoom-out-cur",titleSrc:"title",verticalFit:!0,tError:'<a href="%url%">The image</a> could not be loaded.'},proto:{initImage:function(){var c=b.st.image,d=".image";b.types.push("image"),w(m+d,function(){"image"===b.currItem.type&&c.cursor&&a(document.body).addClass(c.cursor)}),w(h+d,function(){c.cursor&&a(document.body).removeClass(c.cursor),v.off("resize"+p)}),w("Resize"+d,b.resizeImage),b.isLowIE&&w("AfterChange",b.resizeImage)},resizeImage:function(){var a=b.currItem;if(a&&a.img&&b.st.image.verticalFit){var c=0;b.isLowIE&&(c=parseInt(a.img.css("padding-top"),10)+parseInt(a.img.css("padding-bottom"),10)),a.img.css("max-height",b.wH-c)}},_onImageHasSize:function(a){a.img&&(a.hasSize=!0,L&&clearInterval(L),a.isCheckingImgSize=!1,y("ImageHasSize",a),a.imgHidden&&(b.content&&b.content.removeClass("mfp-loading"),a.imgHidden=!1))},findImageSize:function(a){var c=0,d=a.img[0],e=function(f){L&&clearInterval(L),L=setInterval(function(){return d.naturalWidth>0?void b._onImageHasSize(a):(c>200&&clearInterval(L),c++,void(3===c?e(10):40===c?e(50):100===c&&e(500)))},f)};e(1)},getImage:function(c,d){var e=0,f=function(){c&&(c.img[0].complete?(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("ready")),c.hasSize=!0,c.loaded=!0,y("ImageLoadComplete")):(e++,200>e?setTimeout(f,100):g()))},g=function(){c&&(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("error",h.tError.replace("%url%",c.src))),c.hasSize=!0,c.loaded=!0,c.loadError=!0)},h=b.st.image,i=d.find(".mfp-img");if(i.length){var j=document.createElement("img");j.className="mfp-img",c.el&&c.el.find("img").length&&(j.alt=c.el.find("img").attr("alt")),c.img=a(j).on("load.mfploader",f).on("error.mfploader",g),j.src=c.src,i.is("img")&&(c.img=c.img.clone()),j=c.img[0],j.naturalWidth>0?c.hasSize=!0:j.width||(c.hasSize=!1)}return b._parseMarkup(d,{title:M(c),img_replaceWith:c.img},c),b.resizeImage(),c.hasSize?(L&&clearInterval(L),c.loadError?(d.addClass("mfp-loading"),b.updateStatus("error",h.tError.replace("%url%",c.src))):(d.removeClass("mfp-loading"),b.updateStatus("ready")),d):(b.updateStatus("loading"),c.loading=!0,c.hasSize||(c.imgHidden=!0,d.addClass("mfp-loading"),b.findImageSize(c)),d)}}});var N,O=function(){return void 0===N&&(N=void 0!==document.createElement("p").style.MozTransform),N};a.magnificPopup.registerModule("zoom",{options:{enabled:!1,easing:"ease-in-out",duration:300,opener:function(a){return a.is("img")?a:a.find("img")}},proto:{initZoom:function(){var a,c=b.st.zoom,d=".zoom";if(c.enabled&&b.supportsTransition){var e,f,g=c.duration,j=function(a){var b=a.clone().removeAttr("style").removeAttr("class").addClass("mfp-animated-image"),d="all "+c.duration/1e3+"s "+c.easing,e={position:"fixed",zIndex:9999,left:0,top:0,"-webkit-backface-visibility":"hidden"},f="transition";return e["-webkit-"+f]=e["-moz-"+f]=e["-o-"+f]=e[f]=d,b.css(e),b},k=function(){b.content.css("visibility","visible")};w("BuildControls"+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.content.css("visibility","hidden"),a=b._getItemToZoom(),!a)return void k();f=j(a),f.css(b._getOffset()),b.wrap.append(f),e=setTimeout(function(){f.css(b._getOffset(!0)),e=setTimeout(function(){k(),setTimeout(function(){f.remove(),a=f=null,y("ZoomAnimationEnded")},16)},g)},16)}}),w(i+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.st.removalDelay=g,!a){if(a=b._getItemToZoom(),!a)return;f=j(a)}f.css(b._getOffset(!0)),b.wrap.append(f),b.content.css("visibility","hidden"),setTimeout(function(){f.css(b._getOffset())},16)}}),w(h+d,function(){b._allowZoom()&&(k(),f&&f.remove(),a=null)})}},_allowZoom:function(){return"image"===b.currItem.type},_getItemToZoom:function(){return b.currItem.hasSize?b.currItem.img:!1},_getOffset:function(c){var d;d=c?b.currItem.img:b.st.zoom.opener(b.currItem.el||b.currItem);var e=d.offset(),f=parseInt(d.css("padding-top"),10),g=parseInt(d.css("padding-bottom"),10);e.top-=a(window).scrollTop()-f;var h={width:d.width(),height:(u?d.innerHeight():d[0].offsetHeight)-g-f};return O()?h["-moz-transform"]=h.transform="translate("+e.left+"px,"+e.top+"px)":(h.left=e.left,h.top=e.top),h}}});var P="iframe",Q="//about:blank",R=function(a){if(b.currTemplate[P]){var c=b.currTemplate[P].find("iframe");c.length&&(a||(c[0].src=Q),b.isIE8&&c.css("display",a?"block":"none"))}};a.magnificPopup.registerModule(P,{options:{markup:'<div class="mfp-iframe-scaler"><div class="mfp-close"></div><iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe></div>',srcAction:"iframe_src",patterns:{youtube:{index:"youtube.com",id:"v=",src:"//www.youtube.com/embed/%id%?autoplay=1"},vimeo:{index:"vimeo.com/",id:"/",src:"//player.vimeo.com/video/%id%?autoplay=1"},gmaps:{index:"//maps.google.",src:"%id%&output=embed"}}},proto:{initIframe:function(){b.types.push(P),w("BeforeChange",function(a,b,c){b!==c&&(b===P?R():c===P&&R(!0))}),w(h+"."+P,function(){R()})},getIframe:function(c,d){var e=c.src,f=b.st.iframe;a.each(f.patterns,function(){return e.indexOf(this.index)>-1?(this.id&&(e="string"==typeof this.id?e.substr(e.lastIndexOf(this.id)+this.id.length,e.length):this.id.call(this,e)),e=this.src.replace("%id%",e),!1):void 0});var g={};return f.srcAction&&(g[f.srcAction]=e),b._parseMarkup(d,g,c),b.updateStatus("ready"),d}}});var S=function(a){var c=b.items.length;return a>c-1?a-c:0>a?c+a:a},T=function(a,b,c){return a.replace(/%curr%/gi,b+1).replace(/%total%/gi,c)};a.magnificPopup.registerModule("gallery",{options:{enabled:!1,arrowMarkup:'<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',preload:[0,2],navigateByImgClick:!0,arrows:!0,tPrev:"Previous (Left arrow key)",tNext:"Next (Right arrow key)",tCounter:"%curr% of %total%"},proto:{initGallery:function(){var c=b.st.gallery,e=".mfp-gallery";return b.direction=!0,c&&c.enabled?(f+=" mfp-gallery",w(m+e,function(){c.navigateByImgClick&&b.wrap.on("click"+e,".mfp-img",function(){return b.items.length>1?(b.next(),!1):void 0}),d.on("keydown"+e,function(a){37===a.keyCode?b.prev():39===a.keyCode&&b.next()})}),w("UpdateStatus"+e,function(a,c){c.text&&(c.text=T(c.text,b.currItem.index,b.items.length))}),w(l+e,function(a,d,e,f){var g=b.items.length;e.counter=g>1?T(c.tCounter,f.index,g):""}),w("BuildControls"+e,function(){if(b.items.length>1&&c.arrows&&!b.arrowLeft){var d=c.arrowMarkup,e=b.arrowLeft=a(d.replace(/%title%/gi,c.tPrev).replace(/%dir%/gi,"left")).addClass(s),f=b.arrowRight=a(d.replace(/%title%/gi,c.tNext).replace(/%dir%/gi,"right")).addClass(s);e.click(function(){b.prev()}),f.click(function(){b.next()}),b.container.append(e.add(f))}}),w(n+e,function(){b._preloadTimeout&&clearTimeout(b._preloadTimeout),b._preloadTimeout=setTimeout(function(){b.preloadNearbyImages(),b._preloadTimeout=null},16)}),void w(h+e,function(){d.off(e),b.wrap.off("click"+e),b.arrowRight=b.arrowLeft=null})):!1},next:function(){b.direction=!0,b.index=S(b.index+1),b.updateItemHTML()},prev:function(){b.direction=!1,b.index=S(b.index-1),b.updateItemHTML()},goTo:function(a){b.direction=a>=b.index,b.index=a,b.updateItemHTML()},preloadNearbyImages:function(){var a,c=b.st.gallery.preload,d=Math.min(c[0],b.items.length),e=Math.min(c[1],b.items.length);for(a=1;a<=(b.direction?e:d);a++)b._preloadItem(b.index+a);for(a=1;a<=(b.direction?d:e);a++)b._preloadItem(b.index-a)},_preloadItem:function(c){if(c=S(c),!b.items[c].preloaded){var d=b.items[c];d.parsed||(d=b.parseEl(c)),y("LazyLoad",d),"image"===d.type&&(d.img=a('<img class="mfp-img" />').on("load.mfploader",function(){d.hasSize=!0}).on("error.mfploader",function(){d.hasSize=!0,d.loadError=!0,y("LazyLoadError",d)}).attr("src",d.src)),d.preloaded=!0}}}});var U="retina";a.magnificPopup.registerModule(U,{options:{replaceSrc:function(a){return a.src.replace(/\.\w+$/,function(a){return"@2x"+a})},ratio:1},proto:{initRetina:function(){if(window.devicePixelRatio>1){var a=b.st.retina,c=a.ratio;c=isNaN(c)?c():c,c>1&&(w("ImageHasSize."+U,function(a,b){b.img.css({"max-width":b.img[0].naturalWidth/c,width:"100%"})}),w("ElementParse."+U,function(b,d){d.src=a.replaceSrc(d,c)}))}}}}),A()});
/*!
* Source: lib/translation.js, license: MIT, url: https://webtranslateit.com/en/projects/10365-JSXC
*/
-var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null}},"de":{"translation":{"Logging_in":"Login läuft…","your_connection_is_unencrypted":"Deine Verbindung ist unverschlüsselt.","your_connection_is_encrypted":"Deine Verbindung ist verschlüsselt.","your_buddy_closed_the_private_connection":"Dein Kontakt hat die private Verbindung getrennt.","start_private":"Privat starten","close_private":"Privat abbrechen","your_buddy_is_verificated":"Dein Kontakt ist verifiziert.","you_have_only_a_subscription_in_one_way":"Der Kontaktstatus ist einseitig.","authentication_query_sent":"Authentifizierungsanfrage gesendet.","your_message_wasnt_send_please_end_your_private_conversation":"Deine Nachricht wurde nicht gesendet. Bitte beende die private Konversation.","unencrypted_message_received":"Unverschlüsselte Nachricht erhalten.","not_available":"Nicht verfügbar.","no_connection":"Keine Verbindung.","relogin":"Neu anmelden.","trying_to_start_private_conversation":"Versuche private Konversation zu starten.","Verified":"Verifiziert","Unverified":"Unverifiziert","private_conversation_aborted":"Private Konversation abgebrochen.","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Dein Kontakt hat die private Konversation beendet. Das solltest du auch tun!","conversation_is_now_verified":"Konversation ist jetzt verifiziert","authentication_failed":"Authentifizierung fehlgeschlagen.","Creating_your_private_key_":"Wir werden jetzt deinen privaten Schlüssel generieren. Das kann einige Zeit in Anspruch nehmen.","Authenticating_a_buddy_helps_":"Einen Kontakt zu authentifizieren hilft sicherzustellen, dass die Person mit der du sprichst auch die ist die sie sagt.","How_do_you_want_to_authenticate_your_buddy":"Wie willst du {{bid_name}} (<b>{{bid_jid}}</b>) authentifizieren?","Select_method":"Wähle...","Manual":"Manual","Question":"Frage","Secret":"Geheimnis","To_verify_the_fingerprint_":"Um den Fingerprint zu verifizieren kontaktiere dein Kontakt über einen anderen Kommunikationsweg. Zum Beispiel per Telefonanruf.","Your_fingerprint":"Dein Fingerprint","Buddy_fingerprint":"Sein/Ihr Fingerprint","Close":"Schließen","Compared":"Verglichen","To_authenticate_using_a_question_":"Um die Authentifizierung per Frage durchzuführen, wähle eine Frage bei welcher nur dein Kontakt die Antwort kennt.","Ask":"Frage","To_authenticate_pick_a_secret_":"Um deinen Kontakt zu authentifizieren, wähle ein Geheimnis welches nur deinem Kontakt und dir bekannt ist.","Compare":"Vergleiche","Fingerprints":"Fingerprints","Authentication":"Authentifizierung","Message":"Nachricht","Add_buddy":"Kontakt hinzufügen","rename_buddy":"Kontakt umbenennen","delete_buddy":"Kontakt löschen","Login":"Anmeldung","Username":"Benutzername","Password":"Passwort","Cancel":"Abbrechen","Connect":"Verbinden","Type_in_the_full_username_":"Gib bitte den vollen Benutzernamen und optional ein Alias an.","Alias":"Alias","Add":"Hinzufügen","Subscription_request":"Kontaktanfrage","You_have_a_request_from":"Du hast eine Anfrage von","Deny":"Ablehnen","Approve":"Bestätigen","Remove_buddy":"Kontakt entfernen","You_are_about_to_remove_":"Du bist gerade dabei {{bid_name}} (<b>{{bid_jid}}</b>) von deiner Kontaktliste zu entfernen. Alle Chats werden geschlossen.","Continue_without_chat":"Weiter ohne Chat","Please_wait":"Bitte warten","Login_failed":"Chat-Anmeldung fehlgeschlagen","Sorry_we_cant_authentikate_":"Der Chatserver hat die Anmeldung abgelehnt. Falsches Passwort?","Retry":"Zurück","clear_history":"Lösche Verlauf","New_message_from":"Neue Nachricht von __name__","Should_we_notify_you_":"Sollen wir dich in Zukunft über eingehende Nachrichten informieren, auch wenn dieser Tab nicht im Vordergrund ist?","Please_accept_":"Bitte klick auf den \"Zulassen\" Button oben.","Hide_offline":"Offline ausblenden","Show_offline":"Offline einblenden","About":"Über","dnd":"Beschäftigt","Mute":"Ton aus","Unmute":"Ton an","Subscription":"Bezug","both":"beidseitig","Status":"Status","online":"online","chat":"chat","away":"abwesend","xa":"länger abwesend","offline":"offline","none":"keine","Unknown_instance_tag":"Unbekannter instance tag.","Not_one_of_our_latest_keys":"Nicht einer unserer letzten Schlüssel.","Received_an_unreadable_encrypted_message":"Eine unlesbare verschlüsselte Nachricht erhalten.","Online":"Online","Chatty":"Gesprächig","Away":"Abwesend","Extended_away":"Länger abwesend","Offline":"Offline","Friendship_request":"Kontaktanfrage","Confirm":"Bestätigen","Dismiss":"Ablehnen","Remove":"Löschen","Online_help":"Online Hilfe","FN":"Name","N":" ","FAMILY":"Familienname","GIVEN":"Vorname","NICKNAME":"Spitzname","URL":"URL","ADR":"Adresse","STREET":"Straße","EXTADD":"Zusätzliche Adresse","LOCALITY":"Ortschaft","REGION":"Region","PCODE":"Postleitzahl","CTRY":"Land","TEL":"Telefon","NUMBER":"Nummer","EMAIL":"E-Mail","USERID":" ","ORG":"Organisation","ORGNAME":"Name","ORGUNIT":"Abteilung","TITLE":"Titel","ROLE":"Rolle","BDAY":"Geburtstag","DESC":"Beschreibung","PHOTO":" ","send_message":"Sende Nachricht","get_info":"Benutzerinformationen","Settings":"Einstellungen","Priority":"Priorität","Save":"Speichern","User_settings":"Benutzereinstellungen","A_fingerprint_":"Ein Fingerabdruck wird dazu benutzt deinen Gesprächspartner zu identifizieren.","is":"ist","Login_options":"Anmeldeoptionen","BOSH_url":"BOSH url","Domain":"Domain","Resource":"Ressource","On_login":"Beim Anmelden","Received_an_unencrypted_message":"Unverschlüsselte Nachricht empfangen","Sorry_your_buddy_doesnt_provide_any_information":"Dein Kontakt stellt leider keine Informationen bereit.","Info_about":"Info über","Authentication_aborted":"Authentifizierung abgebrochen.","Authentication_request_received":"Authentifizierungsanfrage empfangen.","Log_in_without_chat":"Anmelden ohne Chat","has_come_online":"ist online gekommen","Unknown_sender":"Unbekannter Sender","Please_allow_access_to_microphone_and_camera":"Bitte klick auf den \"Zulassen\" Button oben, um den Zugriff auf Kamera und Mikrofon zu erlauben.","Incoming_call":"Eingehender Anruf","from":"von","Do_you_want_to_accept_the_call_from":"Möchtest Du den Anruf annehmen von","Reject":"Ablehnen","Accept":"Annehmen","hang_up":"Auflegen","snapshot":"Schnappschuss","mute_my_audio":"Mein Ton aus","pause_my_video":"Mein Video pausieren","fullscreen":"Vollbild","Info":"Info","Local_IP":"Lokale IP","Remote_IP":"Remote IP","Local_Fingerprint":"Lokaler Fingerprint","Remote_Fingerprint":"Remote Fingerprint","Video_call_not_possible":"Videoanruf nicht verfügbar. Dein Gesprächspartner unterstützt keine Videotelefonie.","Start_video_call":"Starte Videoanruf","Join_chat":"Gruppe beitreten","Join":"Betreten","Room":"Gruppe","Nickname":"Nickname","left_the_building":"__nickname__ hat die Gruppe verlassen","entered_the_room":"__nickname__ ist der Gruppe beigetreten","is_now_known_as":"__oldNickname__ ist nun unter __newNickname__ bekannt","This_room_is":"Diese Gruppe ist","muc_hidden":{"keyword":"versteckt","description":"kann durch die Suche nicht gefunden werden"},"muc_membersonly":{"keyword":"nur für Mitglieder","description":"du musst auf der Mitgliederliste stehen"},"muc_moderated":{"keyword":"moderiert","description":"Nur Personen die \"Mitspracherecht\" haben dürfen Nachrichten senden"},"muc_nonanonymous":{"keyword":"nicht anonym","description":"deine Jabber ID wird für alle Mitglieder sichtbar sein"},"muc_open":{"keyword":"offen","description":"jeder darf dieser Gruppe beitreten"},"muc_passwordprotected":{"keyword":"passwortgeschützt","description":"du benötigst das korrekte Passwort"},"muc_persistent":{"keyword":"permanent","description":"wird nicht geschlossen, wenn das letzte Mitglied die Gruppe verlässt"},"muc_public":{"keyword":"öffentlich","description":"kann durch die Suche gefunden werden"},"muc_semianonymous":{"keyword":"teilweise anonym","description":"deine Jabber ID wird nur für die Gruppen Administratoren sichtbar sein"},"muc_temporary":{"keyword":"temporär","description":"wird geschlossen, wenn das letzte Mitglied die Gruppe verlässt"},"muc_unmoderated":{"keyword":"nicht moderiert","description":"jeder darf Nachrichten senden"},"muc_unsecured":{"keyword":"ungesichert","description":"es wird kein Passwort benötigt"},"Continue":"Weiter","Server":"Server","Rooms_are_loaded":"Gruppen werden geladen","Could_load_only":"Es konnten nur __count__ Gruppen für die Autovervollständigung geladen werden","muc_explanation":"Bitte trage den Gruppennamen und optional ein Nickname und Passwort ein um einer Gruppe beizutreten","You_already_joined_this_room":"Du bist dieser Gruppe bereits beigetreten","This_room_will_be_closed":"Diese Gruppe wird geschlossen","Room_not_found_":"Es wird eine neue Gruppe erstellt","Loading_room_information":"Informationen über Gruppe werden geladen","Destroy":"Auflösen","Leave":"Verlassen","changed_subject_to":"__nickname__ hat das Thema auf __subject__ geändert","muc_removed_kicked":"Du wurdest aus der Gruppe entfernt","muc_removed_info_kicked":"__nickname__ wurde aus der Gruppe entfernt","muc_removed_banned":"Du wurdest aus der Gruppe ausgeschlossen","muc_removed_info_banned":"__nickname__ wurde aus der Gruppe ausgeschlossen","muc_removed_affiliation":"Du wurdest aus der Gruppe entfernt wegen einer Änderung deines Mitgliedstatus","muc_removed_info_affiliation":"__nickname__ wurde aus der Gruppe entfernt wegen einer Änderung seines Mitgliedstatus","muc_removed_membersonly":"Diese Gruppe erlaubt jetzt nur noch eingetragene Mitglieder und da du nicht dazugehörst, wurdest du aus der Gruppen entfernt","muc_removed_info_membersonly":"Diese Gruppe erlaubt jetzt nur noch eingetragene Mitglieder und __nickname__ gehört nicht dazu, daher wurde er aus der Gruppe entfernt","muc_removed_shutdown":"Du wurdest aus der Gruppe entfernt, da der MUC Server heruntergefahren wird","Reason":"Grund","message_not_send":"Deine Nachricht wurde aufgrund eines Fehlers nicht versandt","message_not_send_item-not-found":"Deine Nachricht wurde nicht versandt, da der Raum nicht mehr existiert","message_not_send_forbidden":"Deine Nachricht wurde nicht versandt, da du kein \"Mitspracherecht\" hast","message_not_send_not-acceptable":"Deine Nachricht wurde nicht versandt, da du kein Mitglied dieser Gruppe bist","This_room_has_been_closed":"Diese Gruppe wurde geschlossen","Room_logging_is_enabled":"Gesprächsverlauf kann öffentlich einsehbar sein","A_password_is_required":"Es wird ein Passwort benötigt","You_are_not_on_the_member_list":"Du bist kein eingetragenes Mitglied","You_are_banned_from_this_room":"Du wurdest von dieser Gruppe ausgeschlossen","Your_desired_nickname_":"Dein gewünschter Nickname wird bereits verwendet. Bitte wähle einen anderen.","The_maximum_number_":"Die maximale Anzahl der Mitglieder wurde erreicht.","This_room_is_locked_":"Diese Gruppe ist gesperrt","You_are_not_allowed_to_create_":"Du darfst keine neue Gruppe erstellen","Alert":"Alarm","Call_started":"Anruf gestarted","Call_terminated":"Anruf beendet","Carbon_copy":"Kopie","Enable":"Aktivieren","jingle_reason_busy":"beschäftigt","jingle_reason_decline":"abgelehnt","jingle_reason_success":"aufgelegt","Media_failure":"Gerätefehler","No_local_audio_device":"Kein eigenes Audio Gerät","No_local_video_device":"Keine eigene Webcam","Ok":"Ok","PermissionDeniedError":"Du oder dein Browser haben die Audio/Video Berechtigung verweigert","Use_local_audio_device":"Nutze eigenes Audio Gerät","Use_local_video_device":"Benutze eigene Webcam","is_":"ist __status__","You_received_a_message_from_an_unknown_sender_":"Du hast eine Nachricht von einem unbekannten Sender erhalten (__sender__) Möchtest du sie sehen?","Your_roster_is_empty_add_":"Deine Kontaktliste ist leer, füge einen neuen Kontakt <a>hinzu</a>","onsmp_explanation_question":"Dein Kontakt versucht herauszufinden ob er wirklich mit dir redet. Um dich gegenüber deinem Kontakt zu verifizieren gib die Antwort ein und klick auf Antworten.","onsmp_explanation_secret":"Dein Kontakt versucht herauszufinden ob er wirklich mit dir redet. Um dich gegenüber deinem Kontakt zu verifizieren gib das Geheimnis ein.","from_sender":"von __sender__","Verified_private_conversation_started":"Verifizierte private Konversation gestartet.","Unverified_private_conversation_started":"Unverifizierte private Konversation gestartet.","Bookmark":"Lesezeichen","Auto-join":"Automatisch beitreten","Edit_bookmark":"Lesezeichen bearbeiten","Room_logging_is_disabled":"Gruppen Log ist deaktiviert","Room_is_now_non-anoymous":"Gruppe ist jetzt nicht anonym","Room_is_now_semi-anonymous":"Gruppe ist jetzt semi-anonym","Do_you_want_to_change_the_default_room_configuration":"Möchtest du die Gruppenkonfiguration ändern?","Default":"Standard","Change":"Ändern","Send_file":"Datei senden","setting-explanation-carbon":"Wenn Kopien aktiviert sind, werden alle eingehenden Nachrichten zu allen angemeldeten Clients gesendet.","setting-explanation-login":"Wenn diese Option aktiviert ist, wird der Chat beim anmelden automatisch gestartet.","setting-explanation-priority":"Wenn du mit deinem XMPP Konto mehrfach angemeldet bist, werden Nachrichten zu dem Client mit der höchsten Priorität zugestellt.","setting-explanation-xmpp":"Diese Optionen werden für die Verbindung zum XMPP server genutzt."}},"el":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null}},"en":{"translation":{"Logging_in":"Logging in…","your_connection_is_unencrypted":"Your connection is unencrypted.","your_connection_is_encrypted":"Your connection is encrypted.","your_buddy_closed_the_private_connection":"Your contact closed the private connection.","start_private":"Start private","close_private":"Close private","your_buddy_is_verificated":"Your contact is verified.","you_have_only_a_subscription_in_one_way":"You only have a one-way subscription.","authentication_query_sent":"Authentication query sent.","your_message_wasnt_send_please_end_your_private_conversation":"Your message was not sent. Please end your private conversation.","unencrypted_message_received":"Unencrypted message received","not_available":"Not available","no_connection":"No connection!","relogin":"relogin","trying_to_start_private_conversation":"Trying to start private conversation!","Verified":"Verified","Unverified":"Unverified","private_conversation_aborted":"Private conversation aborted!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Your contact closed the private conversation! You should do the same.","conversation_is_now_verified":"Conversation is now verified.","authentication_failed":"Authentication failed.","Creating_your_private_key_":"Creating your private key; this may take a while.","Authenticating_a_buddy_helps_":"Authenticating a contact helps ensure that the person you are talking to is really the one they claim to be.","How_do_you_want_to_authenticate_your_buddy":"How do you want to authenticate {{bid_name}} (<b>{{bid_jid}}</b>)?","Select_method":"Select method...","Manual":"Manual","Question":"Question","Secret":"Secret","To_verify_the_fingerprint_":"To verify the fingerprint, contact your contact via some other trustworthy channel, such as the telephone.","Your_fingerprint":"Your fingerprint","Buddy_fingerprint":"Contact fingerprint","Close":"Close","Compared":"Compared","To_authenticate_using_a_question_":"To authenticate using a question, pick a question whose answer is known only you and your contact.","Ask":"Ask","To_authenticate_pick_a_secret_":"To authenticate, pick a secret known only to you and your contact.","Compare":"Compare","Fingerprints":"Fingerprints","Authentication":"Authentication","Message":"Message","Add_buddy":"Add contact","rename_buddy":"rename contact","delete_buddy":"delete contact","Login":"Login","Username":"Username","Password":"Password","Cancel":"Cancel","Connect":"Connect","Type_in_the_full_username_":"Type in the full username and an optional alias.","Alias":"Alias","Add":"Add","Subscription_request":"Subscription request","You_have_a_request_from":"You have a request from","Deny":"Deny","Approve":"Approve","Remove_buddy":"Remove contact","You_are_about_to_remove_":"You are about to remove {{bid_name}} (<b>{{bid_jid}}</b>) from your contact list. All related chats will be closed.","Continue_without_chat":"Continue without chat","Please_wait":"Please wait","Login_failed":"Chat login failed","Sorry_we_cant_authentikate_":"Authentication failed with the chat server. Maybe the password is wrong?","Retry":"Back","clear_history":"Clear history","New_message_from":"New message from __name__","Should_we_notify_you_":"Should we notify you about new messages in the future?","Please_accept_":"Please click the \"Allow\" button at the top.","Hide_offline":"Hide offline contacts","Show_offline":"Show offline contacts","About":"About","dnd":"Do Not Disturb","Mute":"Mute","Unmute":"Unmute","Subscription":"Subscription","both":"both","Status":"Status","online":"online","chat":"chat","away":"away","xa":"extended away","offline":"offline","none":"none","Unknown_instance_tag":"Unknown instance tag.","Not_one_of_our_latest_keys":"Not one of our latest keys.","Received_an_unreadable_encrypted_message":"Received an unreadable encrypted message.","Online":"Online","Chatty":"Chatty","Away":"Away","Extended_away":"Extended away","Offline":"Offline","Friendship_request":"Contact request","Confirm":"Confirm","Dismiss":"Dismiss","Remove":"Remove","Online_help":"Online help","FN":"Full name","N":" ","FAMILY":"Family name","GIVEN":"Given name","NICKNAME":"Nickname","URL":"URL","ADR":"Address","STREET":"Street Address","EXTADD":"Extended Address","LOCALITY":"Locality","REGION":"Region","PCODE":"Postal Code","CTRY":"Country","TEL":"Telephone","NUMBER":"Number","EMAIL":"Email","USERID":" ","ORG":"Organization","ORGNAME":"Name","ORGUNIT":"Unit","TITLE":"Job title","ROLE":"Role","BDAY":"Birthday","DESC":"Description","PHOTO":" ","send_message":"Send message","get_info":"Show information","Settings":"Settings","Priority":"Priority","Save":"Save","User_settings":"User settings","A_fingerprint_":"A fingerprint is used to make sure that the person you are talking to is who he or she is saying.","is":"is","Login_options":"Login options","BOSH_url":"BOSH URL","Domain":"Domain","Resource":"Resource","On_login":"On login","Received_an_unencrypted_message":"Received an unencrypted message","Sorry_your_buddy_doesnt_provide_any_information":"Sorry, your contact does not provide any information.","Info_about":"Info about","Authentication_aborted":"Authentication aborted.","Authentication_request_received":"Authentication request received.","Log_in_without_chat":"Log in without chat","has_come_online":"has come online","Unknown_sender":"Unknown sender","Please_allow_access_to_microphone_and_camera":"Please click the \"Allow\" button at the top, to allow access to microphone and camera.","Incoming_call":"Incoming call","from":"from","Do_you_want_to_accept_the_call_from":"Do you want to accept the call from","Reject":"Reject","Accept":"Accept","hang_up":"hang up","snapshot":"snapshot","mute_my_audio":"mute my audio","pause_my_video":"pause my video","fullscreen":"fullscreen","Info":"Info","Local_IP":"Local IP","Remote_IP":"Remote IP","Local_Fingerprint":"Local fingerprint","Remote_Fingerprint":"Remote fingerprint","Video_call_not_possible":"Video call not possible. Your contact does not support video calls.","Start_video_call":"Start video call","Join_chat":"Join chat","Join":"Join","Room":"Room","Nickname":"Nickname","left_the_building":"__nickname__ left the building","entered_the_room":"__nickname__ entered the room","is_now_known_as":"__oldNickname__ is now known as __newNickname__","This_room_is":"This room is","muc_hidden":{"keyword":"hidden","description":"can not be found through search"},"muc_membersonly":{"keyword":"members-only","description":"you need to be on the member list"},"muc_moderated":{"keyword":"moderated","description":"only persons with \"voice\" are allowed to send messages"},"muc_nonanonymous":{"keyword":"non-anonymous","description":"your jabber id is exposed to all other occupants"},"muc_open":{"keyword":"open","description":"everyone is allowed to join"},"muc_passwordprotected":{"keyword":"password-protected","description":"you need to provide the correct password"},"muc_persistent":{"keyword":"persistent","description":"will not be destroyed if the last occupant left"},"muc_public":{"keyword":"public","description":"can be found through search"},"muc_semianonymous":{"keyword":"semi-anonymous","description":"your jabber id is only exposed to room admins"},"muc_temporary":{"keyword":"temporary","description":"will be destroyed if the last occupant left"},"muc_unmoderated":{"keyword":"unmoderated","description":"everyone is allowed to send messages"},"muc_unsecured":{"keyword":"unsecured","description":"you need no password to enter"},"Continue":"Continue","Server":"Server","Rooms_are_loaded":"Rooms are loaded","Could_load_only":"Could load only __count__ rooms for autocomplete","muc_explanation":"Please enter room name and optional a nickname and password to join a chat","You_already_joined_this_room":"You already joined this room","This_room_will_be_closed":"This room will be closed","Room_not_found_":"A new room will be created","Loading_room_information":"Loading room information","Destroy":"Destroy","Leave":"Leave","changed_subject_to":"__nickname__ changed the room subject to \"__subject__\"","muc_removed_kicked":"You have been kicked from the room","muc_removed_info_kicked":"__nickname__ has been kicked from the room","muc_removed_banned":"You have been banned from the room","muc_removed_info_banned":"__nickname__ has been banned from the room","muc_removed_affiliation":"You have been removed from the room, because of an affiliation change","muc_removed_info_affiliation":"__nickname__ has been removed from the room, because of an affiliation change","muc_removed_membersonly":"You have been removed from the room, because the room has been changed to members-only and you are no member","muc_removed_info_membersonly":"__nickname__ has been removed from the room, because the room has been changed to members-only and you are no member","muc_removed_shutdown":"You have been removed from the room, because the MUC service is being shut down","Reason":"Reason","message_not_send":"Your message was not send because of an error","message_not_send_item-not-found":"Your message was not send because this room does not exist","message_not_send_forbidden":"Your message was not send because you have no voice in this room","message_not_send_not-acceptable":"Your message was not send because you are no occupant of this room","This_room_has_been_closed":"This room has been closed","Room_logging_is_enabled":"Room logging is enabled","A_password_is_required":"A password is required","You_are_not_on_the_member_list":"You are not on the member list","You_are_banned_from_this_room":"You are banned from this room","Your_desired_nickname_":"Your desired nickname is already in use. Please choose another","The_maximum_number_":"The maximum number of user is reached in this room","This_room_is_locked_":"This room is locked","You_are_not_allowed_to_create_":"You are not allowed to create a room","Alert":"Alert","Call_started":"Call started","Call_terminated":"Call terminated","Carbon_copy":"Carbon copy","Enable":"Enable","jingle_reason_busy":"busy","jingle_reason_decline":"decline","jingle_reason_success":"hung up","Media_failure":"Media failure","No_local_audio_device":"No local audio device.","No_local_video_device":"No local video device.","Ok":"Ok","PermissionDeniedError":"You or your browser denied audio/video permission","Use_local_audio_device":"Use local audio device.","Use_local_video_device":"Use local video device.","is_":"is __status__","You_received_a_message_from_an_unknown_sender_":"You received a message from an unknown sender (__sender__) Do you want to display them?","Your_roster_is_empty_add_":"Your roster is empty, add a <a>new contact</a>","onsmp_explanation_question":"You contact is attempting to determine if they are really talking to you. To authenticate to your contact, enter the answer and click Answer.","onsmp_explanation_secret":"You contact is attempting to determine if they are really talking to you. To authenticate to your contact, enter the secret.","from_sender":"from __sender__","Verified_private_conversation_started":"Verified Private conversation started.","Unverified_private_conversation_started":"Unverified Private conversation started.","Bookmark":"Bookmark","Auto-join":"Auto-join","Edit_bookmark":"Edit bookmark","Room_logging_is_disabled":"Room logging is disabled","Room_is_now_non-anoymous":"Room is now non-anonymous","Room_is_now_semi-anonymous":"Room is now semi-anonymous","Do_you_want_to_change_the_default_room_configuration":"Do you want to change the default room configuration?","Default":"Default","Change":"Change","Send_file":"Send file","setting-explanation-carbon":"With enabled carbon copy your XMPP server will send a copy of every incoming message for you to this client even if it was not addressed to it.","setting-explanation-login":"If this option is enabled, the chat will start on login.","setting-explanation-priority":"If you are logged in multiple times with the same account, your XMPP server will deliver messages to the client with the highest priority.","setting-explanation-xmpp":"These options are used to connect to the XMPP server."}},"es":{"translation":{"Logging_in":"Por favor, espere...","your_connection_is_unencrypted":"Su conexión no está cifrada.","your_connection_is_encrypted":"Su conexión está cifrada.","your_buddy_closed_the_private_connection":"Su amigo ha cerrado la conexión privada.","start_private":"Iniciar privado","close_private":"Cerrar privado","your_buddy_is_verificated":"Tu amigo está verificado.","you_have_only_a_subscription_in_one_way":"Solo tienes una suscripción de un modo.","authentication_query_sent":"Consulta de verificación enviada.","your_message_wasnt_send_please_end_your_private_conversation":"Su mensaje no fue enviado. Por favor, termine su conversación privada.","unencrypted_message_received":"Mensaje no cifrado recibido:","not_available":"No disponible","no_connection":"¡Sin conexión!","relogin":"iniciar sesión nuevamente","trying_to_start_private_conversation":"¡Intentando iniciar una conversación privada!","Verified":"Verificado","Unverified":"No verificado","private_conversation_aborted":"¡Conversación privada abortada!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"¡Su amigo cerró la conversación privada! Usted debería hacer lo mismo.","conversation_is_now_verified":"La conversación es ahora verificada.","authentication_failed":"Falló la verificación.","Creating_your_private_key_":"Ahora vamos a crear su clave privada. Esto puede tomar algún tiempo.","Authenticating_a_buddy_helps_":"Autenticación de un amigo ayuda a garantizar que la persona que está hablando es quien él o ella está diciendo.","How_do_you_want_to_authenticate_your_buddy":"¿Cómo desea autenticar {{bid_name}} (<b>{{bid_jid}}</b>)?","Select_method":"Escoja un método...","Manual":"Manual","Question":"Pregunta","Secret":"Secreto","To_verify_the_fingerprint_":"Para verificar la firma digital, póngase en contacto con su amigo a través de algún otro canal autenticado, como el teléfono.","Your_fingerprint":"Tu firma digital","Buddy_fingerprint":"firma digital de tu amigo","Close":"Cerrar","Compared":"Comparado","To_authenticate_using_a_question_":"Para autenticar mediante una pregunta, elegid una pregunta cuya respuesta se conoce solo usted y su amigo.","Ask":"Preguntar","To_authenticate_pick_a_secret_":"Para autenticar, elija un secreto conocido solo por usted y su amigo.","Compare":"Comparar","Fingerprints":"Firmas digitales","Authentication":"Autenticación","Message":"Mensaje","Add_buddy":"Añadir amigo","rename_buddy":"renombrar amigo","delete_buddy":"eliminar amigo","Login":"Iniciar Sesión","Username":"Usuario","Password":"Contraseña","Cancel":"Cancelar","Connect":"Conectar","Type_in_the_full_username_":"Escriba el usuario completo y un alias opcional.","Alias":"Alias","Add":"Añadir","Subscription_request":"Solicitud de suscripción","You_have_a_request_from":"Tienes una petición de","Deny":"Rechazar","Approve":"Aprobar","Remove_buddy":"Eliminar amigo","You_are_about_to_remove_":"Vas a eliminar a {{bid_name}} (<b>{{bid_jid}}</b>) de tu lista de amigos. Todas las conversaciones relacionadas serán cerradas.","Continue_without_chat":"Continuar","Please_wait":"Espere por favor","Login_failed":"Fallo el inicio de sesión","Sorry_we_cant_authentikate_":"Lo sentimos, no podemos autentificarlo en nuestro servidor de chat. ¿Tal vez la contraseña es incorrecta?","Retry":"Reintentar","clear_history":"Borrar el historial","New_message_from":"Nuevo mensaje de __name__","Should_we_notify_you_":"¿Debemos notificarle sobre nuevos mensajes en el futuro?","Please_accept_":"Por favor, haga clic en el botón \"Permitir\" en la parte superior.","Hide_offline":"Ocultar contactos desconectados","Show_offline":"Mostrar contactos desconectados","About":"Acerca de","dnd":"No Molestar","Mute":"Desactivar sonido","Unmute":"Activar sonido","Subscription":"Suscripción","both":"ambos","Status":"Estado","online":"en línea","chat":"chat","away":"ausente","xa":"más ausente","offline":"desconectado","none":"nadie","Unknown_instance_tag":"Etiqueta de instancia desconocida.","Not_one_of_our_latest_keys":"No una de nuestras última claves.","Received_an_unreadable_encrypted_message":"Se recibió un mensaje cifrado ilegible.","Online":"En linea","Chatty":"Hablador","Away":"Ausente","Extended_away":"Más ausente","Offline":"Desconectado","Friendship_request":"Solicitud de amistad","Confirm":"Confirmar","Dismiss":"Rechazar","Remove":"Eliminar","Online_help":"Ayuda en línea","FN":"Nombre completo ","N":" ","FAMILY":"Apellido","GIVEN":"Nombre","NICKNAME":"Apodo","URL":"URL","ADR":"Dirección","STREET":"Calle","EXTADD":"Dirección extendida","LOCALITY":"Población","REGION":"Región","PCODE":"Código postal","CTRY":"País","TEL":"Teléfono","NUMBER":"Número","EMAIL":"Correo electrónico","USERID":" ","ORG":"Organización","ORGNAME":"Nombre","ORGUNIT":"Departamento","TITLE":"Título","ROLE":"Rol","BDAY":"Cumpleaños","DESC":"Descripción","PHOTO":" ","send_message":"mandar un texto","get_info":"obtener información","Settings":"Ajustes","Priority":"Prioridad","Save":"Guardar","User_settings":"Configuración de usuario","A_fingerprint_":"La huella digital se utiliza para que puedas estar seguro que la persona con la que estas hablando es quien realmente dice ser","is":"es","Login_options":"Opciones de login","BOSH_url":"BOSH url","Domain":"Dominio","Resource":"Recurso","On_login":"Iniciar sesión","Received_an_unencrypted_message":"Recibe un mensaje no cifrado","Sorry_your_buddy_doesnt_provide_any_information":"Lo sentimos, su amigo no provee ninguna información.","Info_about":"Info acerca de","Authentication_aborted":"Autenticación abortada","Authentication_request_received":"Pedido de autenticación recibido.","Log_in_without_chat":"Ingresar sin chat","has_come_online":"se ha conectado","Unknown_sender":"Remitente desconocido","Please_allow_access_to_microphone_and_camera":"Por favor, permitir el acceso al micrófono y la cámara.","Incoming_call":"Llamada entrante","from":"de","Do_you_want_to_accept_the_call_from":"Desea aceptar la llamada de","Reject":"Rechazar","Accept":"Aceptar","hang_up":"colgar","snapshot":"instantánea","mute_my_audio":"silenciar mi audio","pause_my_video":"pausar mi vídeo","fullscreen":"pantalla completa","Info":"Info","Local_IP":"IP local","Remote_IP":"IP remota","Local_Fingerprint":"Firma digital local","Remote_Fingerprint":"Firma digital remota","Video_call_not_possible":"Llamada de vídeo no es posible","Start_video_call":"Iniciar llamada de vídeo","Join_chat":"Unirse al chat","Join":"Unirse","Room":"Sala","Nickname":"Alias","left_the_building":"__nickname__ dejó el edificio","entered_the_room":"__nickname__ entró en la sala","is_now_known_as":"__oldNickname__ ahora es conocido como __newNickname__","This_room_is":"Esta sala es","muc_hidden":{"keyword":"oculta","description":"no se encontró mediante la búsqueda"},"muc_membersonly":{"keyword":"miembros solo","description":"necesitas estar en la lista de miembros"},"muc_moderated":{"keyword":"moderada","description":"solo personas con \"voice\" están permitidas para mandar mensajes"},"muc_nonanonymous":{"keyword":"no anónima","description":"tu id de jabber es expuesta al resto de ocupantes"},"muc_open":{"keyword":"abierta","description":"todo el mundo puede unirse"},"muc_passwordprotected":{"keyword":"protegida por contraseña","description":"necesitas dar la contraseña correcta"},"muc_persistent":{"keyword":"persistente","description":"no será destruida si el último ocupante sale"},"muc_public":{"keyword":"pública","description":"puede ser encontrada mediante la búsqueda"},"muc_semianonymous":{"keyword":"semi-anónima","description":"tu id de jabber es expuesta a los administradores de la sala"},"muc_temporary":{"keyword":"temporal","description":"será destruida si el último ocupante sale"},"muc_unmoderated":{"keyword":"no moderada","description":"todo el mundo puede enviar mensajes"},"muc_unsecured":{"keyword":"sin asegurar","description":"no necesitas contraseña para entrar"},"Continue":"Continuar","Server":"Servidor","Rooms_are_loaded":"Las salas han sido cargadas","Could_load_only":"Se cargaron solo __count__ salas para el autocompletado","muc_explanation":"Por favor introduce el nombre de la sala, un alias opcional y una contraseña para unirse al chat","You_already_joined_this_room":"Ya te has unido a esta sala","This_room_will_be_closed":"Esta sale será cerrada","Room_not_found_":"Sala no encontrada","Loading_room_information":"Cargando información de la sala","Destroy":"Destruir","Leave":"Abandonar","changed_subject_to":"__nickname__ cambió el asunto de la sala a \"__subject__\"","muc_removed_kicked":"Has sido echado de la sala","muc_removed_info_kicked":"__nickname__ ha sido echado de la sala","muc_removed_banned":"Has sido expulsado de la sala","muc_removed_info_banned":"__nickname__ ha sido expulsado","muc_removed_affiliation":"Has sido eliminado de la sala debido a un cambio en la afiliación","muc_removed_info_affiliation":"__nickname__ ha sido eliminado de la sala debido a un cambio en la afiliación","muc_removed_membersonly":"Has sido eliminado de la sala debido a que la sala ha sido cambiada a miembros solo y tú no eres un miembro","muc_removed_info_membersonly":"__nickname__ ha sido eliminado de la sala debido a que la sala ha sido cambiada a miembros solo y tú no eres un miembro","muc_removed_shutdown":"Has sido eliminado de la sala debido a que el servicio MUC está siendo apagado","Reason":"Razón","message_not_send":"Tu mensaje no fue enviado debido a un error","message_not_send_item-not-found":"Tu mensaje no fue enviado debido a que esta sala no existe","message_not_send_forbidden":"Tu mensaje no fue enviado debido a que no tienes voz en esta sala","message_not_send_not-acceptable":"Tu mensaje no fue enviado debido a que no eres un ocupante de esta sala ","This_room_has_been_closed":"Esta sala ha sido cerrada","Room_logging_is_enabled":"Log de sala está habilitado","A_password_is_required":"Se requiere una contraseña","You_are_not_on_the_member_list":"No estás en la lista de miembros","You_are_banned_from_this_room":"Estás expulsado de esta sala","Your_desired_nickname_":"Tu alias ya está en uso. Por favor elige otro","The_maximum_number_":"El máximo número de usuarios ha sido alcanzado en esta sala","This_room_is_locked_":"Esta sala está bloqueada","You_are_not_allowed_to_create_":"No tienes permiso para crear una sala","Alert":"Alerta","Call_started":"Llamada empezada","Call_terminated":"Llamada terminada","Carbon_copy":"Calco","Enable":"Activar","jingle_reason_busy":"ocupado","jingle_reason_decline":"rechazar","jingle_reason_success":"colgar","Media_failure":"Fallo multimedia","No_local_audio_device":"No hay dispositivo de audio local","No_local_video_device":"No hay dispositivo de vídeo local","Ok":"Ok","PermissionDeniedError":"Tú o tu navegador denegaron el permiso de audio/vídeo","Use_local_audio_device":"Usar dispositivo de audio local","Use_local_video_device":"Usar dispositivo de vídeo","is_":"es __status__","You_received_a_message_from_an_unknown_sender_":"Ha recibido un mensaje de un remitente desconocido (__sender__) ¿Quiere mostrarlos?","Your_roster_is_empty_add_":"Tu lista de amigos esta vacía, añadir un <a>nuevo amigo</a>","onsmp_explanation_question":"Tu amigo está tratando de determinar si él o ella está realmente hablando con usted. Para autenticar a su amigo, introduce la respuesta y haga clic en Contestar.","onsmp_explanation_secret":"Tu amigo está tratando de determinar si él o ella está realmente hablando con usted. Para autenticar a su amigo, especifique el secreto.","from_sender":"de __sender__","Verified_private_conversation_started":"Verificado se inició una conversación privada.","Unverified_private_conversation_started":"No verificado se inició una conversación privada.","Bookmark":"Favorito","Auto-join":"Auto-unir","Edit_bookmark":"Editar favorito","Room_logging_is_disabled":"Log de sala está deshabilitado","Room_is_now_non-anoymous":"La sala es ahora no anónima","Room_is_now_semi-anonymous":"La sale es ahora semi-anónima","Do_you_want_to_change_the_default_room_configuration":"¿Quieres cambiar la configuración por defecto de la sala?","Default":"Por defecto","Change":"Cambiar","Send_file":"Enviar archivo","setting-explanation-carbon":"Con el Calco habilitado tu servidor XMPP enviará una copia de cada mensaje entrante dirigido a ti a este cliente incluso si no estaba siendo enviado a él","setting-explanation-login":"Si esta opción está habilitada, el chat empezará al inicio de sesión","setting-explanation-priority":"Si tú has iniciado sesión varias veces con la misma cuenta, tu servidor XMPP enviará los mensajes al cliente con la mayor prioridad","setting-explanation-xmpp":"Estas opciones son usadas para conectar con el servidor XMPP"}},"fi":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null}},"fr":{"translation":{"Logging_in":"Connexion...","your_connection_is_unencrypted":"Connexion non chiffrée.","your_connection_is_encrypted":"Connexion chiffrée.","your_buddy_closed_the_private_connection":"Votre contact a fermé la connexion privée.","start_private":"Démarrer une conversation privée","close_private":"Clôturer une conversation privée","your_buddy_is_verificated":"Votre contact est vérifié.","you_have_only_a_subscription_in_one_way":"Vous ne pouvez souscrire qu'une fois.","authentication_query_sent":"Requête d’authentification envoyée.","your_message_wasnt_send_please_end_your_private_conversation":"Votre message n'a pas été envoyé. Veuillez terminer votre conversation privée.","unencrypted_message_received":"Message non chiffré reçu","not_available":"Non disponible","no_connection":"Pas de connexion !","relogin":"Re-connexion","trying_to_start_private_conversation":"Essai de démarrage d'une conversation privée !","Verified":"Vérifié","Unverified":"Non vérifié","private_conversation_aborted":"Conversation privée interrompue !","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Votre contact a fermé la conversation privée ! Vous devriez faire de même.","conversation_is_now_verified":"La conversation est maintenant vérifiée.","authentication_failed":"L'authentification a échoué.","Creating_your_private_key_":"Création de votre clé privée; cela peut prendre un moment.","Authenticating_a_buddy_helps_":"L'authentification d'un contact permet de s'assurer que la personne à qui vous parlez est vraiment celui qu'il ou elle prétend être.","How_do_you_want_to_authenticate_your_buddy":"Comment voulez-vous vous authentifier {{bid_name}} (<b>{{bid_jid}}</b>)?","Select_method":"Sélection de la méthode...","Manual":"Manuel","Question":"Question","Secret":"Sécurité","To_verify_the_fingerprint_":"Pour vérifier l'empreinte, joignez votre contact via un autre canal digne de confiance, tel que le téléphone.","Your_fingerprint":"Votre empreinte","Buddy_fingerprint":"Empreinte du contact","Close":"Fermer","Compared":"Comparé","To_authenticate_using_a_question_":"Pour s'authentifier à l'aide d'une question, choisissez une question dont la réponse n'est connue que vous et de votre contact.","Ask":"Demander","To_authenticate_pick_a_secret_":"Pour vous authentifier, choisissez un secret connu seulement de vous et de votre contact.","Compare":"Comparer","Fingerprints":"Empreintes","Authentication":"Authentification","Message":"Message","Add_buddy":"Ajouter un contact","rename_buddy":"Renommer le contact","delete_buddy":"Supprimer le contact","Login":"Connexion","Username":"Nom d'utilisateur","Password":"Mot de passe","Cancel":"Annuler","Connect":"Connecter","Type_in_the_full_username_":"Tapez un nom d'utilisateur complet et un alias(optionnel).","Alias":"Alias","Add":"Ajouter","Subscription_request":"Demande d'abonnement","You_have_a_request_from":"Vous avez une requête de ","Deny":"Refuser","Approve":"Approuver","Remove_buddy":"Supprimer le contact","You_are_about_to_remove_":"Vous allez retirer {{bid_name}} (<b>{{bid_jid}}</b>) de votre liste de contacts. Toutes les fenêtres de discussion en lien avec celui-ci seront fermées.","Continue_without_chat":"Continuer sans tchat","Please_wait":"Merci de patienter","Login_failed":"Authentification échouée","Sorry_we_cant_authentikate_":"La connexion avec le serveur de tchat a échoué. Vérifiez le mot de passe.","Retry":"Retour","clear_history":"Effacer l’historique","New_message_from":"Nouveau message de __name__","Should_we_notify_you_":"Dans le futur, devrons-nous vous notifier les nouveaux messages ?","Please_accept_":"Merci de cliquer sur le bouton \"autoriser\" en haut de page","Hide_offline":"Masquer les contacts non connectés","Show_offline":"Afficher les contacts non connectés","About":"À propos","dnd":"Ne pas déranger","Mute":"Muet","Unmute":"Son actif","Subscription":"Abonnement","both":"Les deux","Status":"Statut","online":"En ligne","chat":"tchat","away":"Absent","xa":"Longue absence","offline":"Hors ligne","none":"Aucun","Unknown_instance_tag":"Tag inconnu","Not_one_of_our_latest_keys":"Ce n'est pas l'une des dernières touches","Received_an_unreadable_encrypted_message":"Message chiffré non lisible","Online":"En ligne","Chatty":"Libre pour discuter","Away":"Absent","Extended_away":"Longue absence","Offline":"Hors ligne","Friendship_request":"Demande de contact","Confirm":"Valider","Dismiss":"Rejeter","Remove":"Supprimer","Online_help":"Aide en ligne","FN":"Nom","N":" N ","FAMILY":"Nom de famille","GIVEN":"prénom","NICKNAME":"Pseudo","URL":"URL","ADR":"Adresse","STREET":"Rue","EXTADD":"Adresse (suite)","LOCALITY":"Localité","REGION":"Région","PCODE":"Code Postal","CTRY":"Pays","TEL":"Téléphone","NUMBER":"Numéro","EMAIL":"Courriel","USERID":" USERID ","ORG":"Organisation","ORGNAME":"Nom","ORGUNIT":"Unité","TITLE":"Qualité:","ROLE":"Rôle","BDAY":"Date de naissance","DESC":"Description","PHOTO":"Photo","send_message":"Envoyer un message","get_info":"Montrer les informations","Settings":"Réglages","Priority":"Priorité","Save":"Enregistrer","User_settings":"Paramètres utilisateur","A_fingerprint_":"Une empreinte est utilisée pour s'assurer de l'identité de la personne à qui vous parlez","is":"est","Login_options":"Options d'identification","BOSH_url":"URL BOSH","Domain":"Domaine","Resource":"Ressource","On_login":"Après authentification","Received_an_unencrypted_message":"Reçu un message non chiffré","Sorry_your_buddy_doesnt_provide_any_information":"Désolé, votre contact n'a pas fourni d'informations","Info_about":"À propos de","Authentication_aborted":"Authentification interrompue.","Authentication_request_received":"Requête d'authentification reçue.","Log_in_without_chat":"S'identifier sans tchat","has_come_online":"vient d'arriver","Unknown_sender":"Expéditeur inconnu","Please_allow_access_to_microphone_and_camera":"Veuillez cliquez sur le bouton \"Autoriser\" en haut, pour permettre l'accès au micro et à la caméra.","Incoming_call":"Appel entrant","from":"de","Do_you_want_to_accept_the_call_from":"Voulez-vous accepter l'appel de","Reject":"Rejeté","Accept":"Accepté","hang_up":"raccrocher","snapshot":"Capture d’écran","mute_my_audio":"Couper l'audio","pause_my_video":"Mettre ma vidéo en pause","fullscreen":"Plein écran","Info":"Info","Local_IP":"IP locale","Remote_IP":"IP distante","Local_Fingerprint":"Empreinte locale","Remote_Fingerprint":"Empreinte distante","Video_call_not_possible":"L'appel vidéo n'est possible. Votre contact ne supporte pas les appels vidéo.","Start_video_call":"Démarrer l'appel vidéo","Join_chat":"Joindre la discussion","Join":"Joindre","Room":"Salon","Nickname":"Pseudo","left_the_building":"__nickname__ a quitté l'immeuble","entered_the_room":"__nickname__ entre dans le salon","is_now_known_as":"__oldNickname__ est maintenant connu comme __newNickname__","This_room_is":"Ce salon est","muc_hidden":{"keyword":"caché","description":"ne peut être trouvé avec une recherche"},"muc_membersonly":{"keyword":"pour les membres seulement","description":"Vous devez être sur la liste des membres"},"muc_moderated":{"keyword":"modéré","description":"Seulement les personnes avec la \"voix\" sont autorisés à envoyer des messages"},"muc_nonanonymous":{"keyword":"non anonyme","description":"Votre identifiant Jabber est visible de tous les autres occupants"},"muc_open":{"keyword":"ouvert","description":"Tout le monde est autorisé à se connecter"},"muc_passwordprotected":{"keyword":"protégé par un mot de passe","description":"Vous devez fournir un mot de passe correct"},"muc_persistent":{"keyword":"persistent","description":"ne sera pas détruit si le dernier occupant part"},"muc_public":{"keyword":"public","description":"peut être touvé avec une recherche"},"muc_semianonymous":{"keyword":"semi-anonyme","description":"Votre identifiant Jabber est seulement visible aux administrateurs de ce salon"},"muc_temporary":{"keyword":"temporaire","description":"sera détruit au départ de son dernier occupant"},"muc_unmoderated":{"keyword":"non modéré","description":"Tout le monde est autorisé à envoyer des messages"},"muc_unsecured":{"keyword":"non sécurisé","description":"un mot de passe n'est pas nécessaire pour entrer"},"Continue":"Continuer","Server":"Serveur","Rooms_are_loaded":"Les salons sont chargés","Could_load_only":"Ne peut charger que __count__ salons pour l'autocomplétion","muc_explanation":"Veuillez saisir le nom du salon, un surnom (optionnel) et un mot de passe pour joindre la conversation","You_already_joined_this_room":"Vous avez déjà rejoint ce salon","This_room_will_be_closed":"Ce salon va être fermé","Room_not_found_":"Un nouveau salon va être créé","Loading_room_information":"Chargement des informations du salon","Destroy":"Détruire","Leave":"Quitter","changed_subject_to":"__nickname__ a changé le sujet du salon à \"__subject__\"","muc_removed_kicked":"Vous avez été éjecté de ce salon","muc_removed_info_kicked":"__nickname__ a été éjecté de ce salon","muc_removed_banned":"Vous avez été banni de ce salon","muc_removed_info_banned":"__nickname__ a été banni de ce salon","muc_removed_affiliation":"Vous avez été retiré du salon en raison d'un changement d'affiliation","muc_removed_info_affiliation":"__nickname__ a été retiré du salon en raison d'un changement d'affiliation","muc_removed_membersonly":"Vous avez été retiré du salon parce que celui-ci est maintenant réservé aux membres et vous n'en faites pas partie","muc_removed_info_membersonly":"__nickname__ a été retiré du salon parce que celui-ci est maintenant réservé aux membres","muc_removed_shutdown":"Vous avez été retiré du salon parce que le service de salon de discussion est en train de s'éteindre","Reason":"Raison","message_not_send":"Votre message n'a pu être envoyé a cause d'une erreur","message_not_send_item-not-found":"Votre message n'a pu être envoyé parce que ce salon n'existe pas","message_not_send_forbidden":"Votre message n'a pas été envoyé parce que vous n'avez pas le droit de parler dans ce salon","message_not_send_not-acceptable":"Votre message n'a pas été envoyé car il n'y a personne dans ce salon","This_room_has_been_closed":"Ce salon a été fermé","Room_logging_is_enabled":"L'historique du salon est conservé","A_password_is_required":"Un mot de passe est requis","You_are_not_on_the_member_list":"Vous n'êtes pas sur la liste des membres","You_are_banned_from_this_room":"Vous avez été banni de ce salon","Your_desired_nickname_":"Votre pseudo souhaité est déjà utilisé. Veuillez en choisir un autre","The_maximum_number_":"Le nombre maximum d'utilisateurs est atteint dans ce salon","This_room_is_locked_":"Ce salon est verrouillé","You_are_not_allowed_to_create_":"Vous n'êtes pas autorisé à créer un salon","Alert":"Alerte","Call_started":"Appel démarré","Call_terminated":"Appel terminé","Carbon_copy":"Copie carbone","Enable":"Activé","jingle_reason_busy":"occupé","jingle_reason_decline":"refusé","jingle_reason_success":"raccroché","Media_failure":"échec du média","No_local_audio_device":"Pas de périphérique audio local","No_local_video_device":"Pas de périphérique vidéo local","Ok":"Ok","PermissionDeniedError":"Vous ou votre navigateur à refusé de donner les permissions audio/vidéo","Use_local_audio_device":"Utiliser un périphérique audio local.","Use_local_video_device":"Utiliser un périphérique vidéo local.","is_":"est __status__","You_received_a_message_from_an_unknown_sender_":"Vous avez reçu un message d'un expéditeur inconnu (__sender__) Voulez-vous les afficher ?","Your_roster_is_empty_add_":"Votre liste est vide, ajouter <a>Nouveau contact</a>","onsmp_explanation_question":"Votre contact tente de déterminer si il ou elle parle vraiment à vous. Pour vous authentifier auprès de votre contact, saisissez une réponse et cliquez sur Répondre.","onsmp_explanation_secret":"Votre contact tente de déterminer si il ou elle parle vraiment à vous. Pour vous authentifier auprès de votre contact, entrez le mot secret","from_sender":"de __sender__","Verified_private_conversation_started":"La conversation privée vérifiée a démarré.","Unverified_private_conversation_started":"La conversation privée non vérifiée a démarré.","Bookmark":"Marque-page","Auto-join":"Joindre automatiquement","Edit_bookmark":"Éditer le marque-page","Room_logging_is_disabled":"La connexion au salon est désactivée","Room_is_now_non-anoymous":"Ce salon n'est désormais plus anonyme","Room_is_now_semi-anonymous":"Ce salon est désormais semi-anonyme","Do_you_want_to_change_the_default_room_configuration":"Voulez-vous changer la configuration par défaut du salon ?","Default":"Par défaut","Change":"Changer","Send_file":"Envoyer un fichier","setting-explanation-carbon":"Avec la copie carbone activé, votre serveur XMPP envera une copie de tous les messages entrant qui vous sont destiné à ce client, même s'il ne lui sont pas directement addressés.","setting-explanation-login":"Si cette option est activé, le chat commencera lorsque vous vos connectez.","setting-explanation-priority":"Si vous êtes connecté plusieurs fois avec le même compte, votre serveur XMPP enverra les messages au client ayant le plus haute priorité.","setting-explanation-xmpp":"Ces options sont utilisées pour se connecter au serveur XMPP."}},"hu-HU":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":"Az Ön kapcsolata titkosítatlan.","your_connection_is_encrypted":"Az Ön kapcsolata titkosított.","your_buddy_closed_the_private_connection":"Partnere megszakította a privát kapcsolatot.","start_private":"Privát beszélgetés indítása","close_private":"Privát beszélgetés bezárása","your_buddy_is_verificated":"Az Ön partnere megerősítve.","you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":"Azonosítási kérelem elküldve.","your_message_wasnt_send_please_end_your_private_conversation":"Az üzenetet nem sikerült elküldeni. Kérem fejezze be a privát beszélgetést.","unencrypted_message_received":"Titkosítatlan üzenet fogadva","not_available":"Nem elérhető","no_connection":"Nincs kapcsolat!","relogin":"relogin","trying_to_start_private_conversation":"Privát beszélgetés indítása!","Verified":"Megerősítve","Unverified":"Nem megerősített","private_conversation_aborted":"Privát beszélgetés megszakítva!","your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":"Azonosítás sikertelen.","Creating_your_private_key_":"Privát kulcs generálása. Egy kis időbe telhet...","Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":"Kérdés","Secret":"Kulcs","To_verify_the_fingerprint_":null,"Your_fingerprint":"Az Ön lenyomata","Buddy_fingerprint":"Partnere lenyomata","Close":"Bezárás","Compared":"Összehasonlítva","To_authenticate_using_a_question_":"Az azonosításhoz adjon meg egy kérdést, amelyre a választ csak Ön és Partnere ismerhetik.","Ask":"Kérdez","To_authenticate_pick_a_secret_":"Az azonosításhoz adjon meg egy titkot, amelyet csak Ön és Partnere ismerhetnek.","Compare":"Összehasonlítás","Fingerprints":"Lenyomatok","Authentication":"Azonosítás","Message":"Üzenet","Add_buddy":"Partner hozzáadása","rename_buddy":"Partner átnevezése","delete_buddy":"Partner törlése","Login":"Belépés","Username":"Felhasználónév","Password":"Jelszó","Cancel":"Mégsem","Connect":"Csatlakozás","Type_in_the_full_username_":"Adjon meg egy teljes felhasználónevet, és egy opcionális becenevet.","Alias":"Becenév","Add":"Hozzáadás","Subscription_request":"Feliratkozási kérelem","You_have_a_request_from":"Ön felkérést kapott a következőtől","Deny":"Elutasít","Approve":"Jóváhagy","Remove_buddy":"Partner eltávolítása","You_are_about_to_remove_":null,"Continue_without_chat":"Folytatás chat nélkül","Please_wait":"Kérem várjon","Login_failed":"Chat bejelentkezés sikertelen","Sorry_we_cant_authentikate_":null,"Retry":"Vissza","clear_history":"Előzmények törlése","New_message_from":"Új üzenet __name__ partnerétől","Should_we_notify_you_":"Kívánja hogy értesítsük a jövőben új üzeneteiről?","Please_accept_":"Kérem kattintson a fent megjelenő \"Engedélyez\" gombra.","Hide_offline":"Offline partnerek elrejtése","Show_offline":"Offline partnerek mutatása","About":null,"dnd":"Ne zavarj","Mute":"Némítás","Unmute":"Hangok engedélyezése","Subscription":null,"both":"mindkettő","Status":"Állapot","online":"elérhető","chat":null,"away":"távol","xa":"huzamosabban távol","offline":"offline","none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":"Teljes név","N":null,"FAMILY":"Családi név","GIVEN":"Keresztnév","NICKNAME":"Becenév","URL":"URL","ADR":"Cím","STREET":"Utcanév","EXTADD":"Cím","LOCALITY":"Helység","REGION":"Régió","PCODE":"Irányítószám","CTRY":"Ország","TEL":"Telefonszám","NUMBER":"Házszám","EMAIL":"E-mail cím","USERID":null,"ORG":"Vállalat","ORGNAME":"Név","ORGUNIT":"Osztály","TITLE":"Beosztás","ROLE":"Részleg","BDAY":"Születésnap","DESC":"Leírás","PHOTO":null,"send_message":"Üzenet küldése","get_info":"Info mutatása","Settings":"Beállítások","Priority":"Prioritás","Save":"Mentés","User_settings":"Felhasználó beállítások","A_fingerprint_":null,"is":null,"Login_options":"Bejelentkezési lehetőségek","BOSH_url":"BOSH URL","Domain":"Domain","Resource":"Erőforrás","On_login":"Bejelentkezéskor","Received_an_unencrypted_message":"Titkosítatlan üzenetet fogadott","Sorry_your_buddy_doesnt_provide_any_information":"Sajnos az Ön partnere nem adott meg semmilyen információt.","Info_about":null,"Authentication_aborted":"Azonosítás megszakítva.","Authentication_request_received":"Azonosítási kérelem fogadva.","Log_in_without_chat":"Bejelentkezés chat nélkül","has_come_online":"bejelentkezett","Unknown_sender":"Ismeretlen küldő","Please_allow_access_to_microphone_and_camera":"Kérem kattintson a fent megjelenő \"Engedélyez/Allow\" gombra hogy hozzáférést biztosítson mikrofonjához és kamerájához.","Incoming_call":"Bejövő hívás","from":"tőle","Do_you_want_to_accept_the_call_from":"Szeretné fogadni következő partnere hívását:","Reject":"Elutasít","Accept":"Fogadás","hang_up":"tartás","snapshot":"képernyőfotó","mute_my_audio":"hangom némítása","pause_my_video":"videóképem megállítása","fullscreen":"teljes képernyő","Info":"Info","Local_IP":"Helyi IP","Remote_IP":"Távoli IP","Local_Fingerprint":"Helyi lenyomat","Remote_Fingerprint":"Távoli lenyomat","Video_call_not_possible":"Videóhívás nem lehetséges. Az Ön partnerének készüléke nem támogatja a videóhívásokat.","Start_video_call":"Videóhívás indítása","Join_chat":"Belépés a chatbe","Join":"Belépés","Room":"Szoba","Nickname":"Becenév","left_the_building":"__nickname__ elhagyta az épületet.","entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null}},"it":{"translation":{"Logging_in":"login…","your_connection_is_unencrypted":"La sua connessione è non cifrata.","your_connection_is_encrypted":"La sua connessione è cifrata.","your_buddy_closed_the_private_connection":"La sua connessione privata è stato chiuso dal suo compagno.","start_private":"Inizia privata","close_private":"Chiude privata","your_buddy_is_verificated":"Il tuo compagno è stato verificato","you_have_only_a_subscription_in_one_way":"Hai solo una one-way inscrizione.","authentication_query_sent":"Domanda d'autenticità inviata.","your_message_wasnt_send_please_end_your_private_conversation":"Il tuo messaggio non è stato inviato. Si prega di finire la sua conversazione privata.","unencrypted_message_received":"Messaggio non cifrato ricevuto","not_available":"non disponibile","no_connection":"nessun collegamento!","relogin":"nuovo login","trying_to_start_private_conversation":"Cercando di avviare una conversazione privata!","Verified":"verificato","Unverified":"non verificato","private_conversation_aborted":"Conversazione privata abortito!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Il tuo compagno ha chiuso la conversazione privata! Si dovrebbe fare lo stesso.","conversation_is_now_verified":"Conversazione è ora verificato.","authentication_failed":"autenticazione fallita.","Creating_your_private_key_":"Creare la propria chiave privata; questo potrebbe richiedere un po'.","Authenticating_a_buddy_helps_":"Autenticazione un compagno aiuta a garantire che la persona si sta parlando è davvero quello che lui o lei sostiene di essere.","How_do_you_want_to_authenticate_your_buddy":"Come si desidera autenticare {{bid_name}} (<b>{{bid_jid}}</b>)?","Select_method":"Seleziona metodo ..","Manual":"manuale","Question":"domanda","Secret":"segreto","To_verify_the_fingerprint_":"Per verificare l'impronta digitale, contattare il proprio compagno attraverso qualche altro canale affidabile, come il telefono.","Your_fingerprint":"il tuo impronta digitale","Buddy_fingerprint":"impronta digitale da compagno","Close":"chiude","Compared":"comparato","To_authenticate_using_a_question_":"Per autenticare tramite una questione, scegli una questione la cui risposta è nota solo voi e il tuo compagno","Ask":"chiedi","To_authenticate_pick_a_secret_":"Per autenticare, scegli un segreto noto solo a te e il tuo compagno.","Compare":"Comparare","Fingerprints":"Impronta digitale","Authentication":"Autenticazione","Message":"Messagio","Add_buddy":"Aggiungi un compagno","rename_buddy":"rinomina compagno","delete_buddy":"elimina compagno","Login":"Login","Username":"Identificazione dell'utente","Password":"Password","Cancel":"Cancella","Connect":"Collega","Type_in_the_full_username_":"Digita l'identificazione utente completo e un alias opzionale.","Alias":"Alias","Add":"Aggiungi","Subscription_request":"Rrichiesta di sottoscrizione","You_have_a_request_from":"Hai una richiesta da","Deny":"Refiuta","Approve":"Approva","Remove_buddy":"Rimuova il compagno","You_are_about_to_remove_":"Stai rimovendo {{bid_name}} (<b>{{bid_jid}}</b>) del suo lista di compagni. Tutte le chat appartenente saranno chiuse.","Continue_without_chat":"Continua senza chat","Please_wait":"Si prega d'attendere","Login_failed":"Chat login è fallito","Sorry_we_cant_authentikate_":"Autenticazione non riuscita con il server di chat. Forse la password è sbagliata?","Retry":"Indietro","clear_history":"Cancella la cronologia","New_message_from":"Nuovo messaggio da __name__","Should_we_notify_you_":"Vuoi ricevere una notifica di nuovi messaggi in futuro?","Please_accept_":"Si prega di fare clic sul bottone \"Autorizzazione\" sopra.","Hide_offline":"Nascondere i contatti non in linea","Show_offline":"Mostra i contatti non in linea","About":"Informazione legale","dnd":"Non disturbare","Mute":"Muto attivo","Unmute":"Muto inattivo","Subscription":"Sottoscrizione","both":"etrambi","Status":"Status","online":"In linea","chat":"chat","away":"via","xa":"via estensivo","offline":"non in linea","none":"nessuno","Unknown_instance_tag":"Instance tag sconosciuta.","Not_one_of_our_latest_keys":"Non è una delle nostre ultime chiavi.","Received_an_unreadable_encrypted_message":"Ricevuto un messaggio crittografato illeggibile.","Online":"In linea","Chatty":"Chiacchierino","Away":"Via","Extended_away":"Via estensivo","Offline":"Non in linea","Friendship_request":"Amicizia richiesto","Confirm":"Conferma","Dismiss":"Rifiuta","Remove":"Rimuovi","Online_help":"Guida in linea","FN":"Nome e cognome","N":null,"FAMILY":"Cognome","GIVEN":"Nome","NICKNAME":"Soprannome","URL":"URL","ADR":"Indirizzo","STREET":"Via","EXTADD":"Esteso Indirizzo","LOCALITY":"Località","REGION":"Regione","PCODE":"Codice Postale","CTRY":"Paese","TEL":"Telefono","NUMBER":"Numero","EMAIL":"E-mail","USERID":null,"ORG":"Organizzazione","ORGNAME":"Nome","ORGUNIT":"Unità","TITLE":"Titolo di lavoro","ROLE":"Funzione","BDAY":"Compleanno","DESC":"Descrizione","PHOTO":null,"send_message":"Messagio inviato","get_info":"Mostra informazioni","Settings":"Impostazione","Priority":"Priorità","Save":"Salva","User_settings":"Impostazione dell'utente","A_fingerprint_":"Una impronta digitale è usato per assicurarsi che la persona con cui stai parlando è lui o lei che sta dicendo.","is":"è","Login_options":"Opzioni di login","BOSH_url":"BOSH URL","Domain":"Domain","Resource":"Risorsa","On_login":"Login on","Received_an_unencrypted_message":"Ricevuto un messaggio non crittografato","Sorry_your_buddy_doesnt_provide_any_information":"Spiace, il tuo compagno non fornisce alcuna informazione.","Info_about":"Informazioni","Authentication_aborted":"Autenticazione interrotta","Authentication_request_received":"Richiesta di autenticazione ricevuto.","Log_in_without_chat":"Log in senza chat","has_come_online":"È venuto in linea","Unknown_sender":"Mittente sconosciuto","Please_allow_access_to_microphone_and_camera":"Si prega di fare clic sul bottone \"Autorizzazione\" sopra per autorizzazione del l'accesso al microfono e fotocamera.","Incoming_call":"Chiamata in arrivo","from":"di","Do_you_want_to_accept_the_call_from":"Vuoi accettare la chiamata di","Reject":"Rifiuta","Accept":"Accetta","hang_up":"Riattacca","snapshot":"istantanea","mute_my_audio":"disattiva il mio audio","pause_my_video":"pausa il mio audio","fullscreen":"schermo intero","Info":"Informazione","Local_IP":"IP locale","Remote_IP":"IP remoto","Local_Fingerprint":"Impronta digitale locale","Remote_Fingerprint":"Impronta digitale remoto","Video_call_not_possible":"Videochiamata non è possibile. Il tuo compagno non può effettuare videochiamate.","Start_video_call":"Inizia videochiamata","Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":"è __status__","You_received_a_message_from_an_unknown_sender_":"Hai ricevuto un messaggio da un mittente sconosciuto (__sender__) Vuoi che venga visualizzato?","Your_roster_is_empty_add_":"Il suo elenco è vuoto, aggiungi un <a>compagno nuovo</a>","onsmp_explanation_question":"Il tuo compagno sta cercando di determinare se lui o lei sta davvero parlando con te. Per autenticare a il tuo compagno. inserisci la risposta e fare click su risposta.","onsmp_explanation_secret":"Il tuo compagno sta cercando di determinare se lui o lei sta davvero parlando con te. Per autenticare a il tuo compagno. inserire il segreto.","from_sender":"di __sender__","Verified_private_conversation_started":"verificato Conversazione privata iniziato.","Unverified_private_conversation_started":"non verificato Conversazione privata iniziato.","Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null}},"nds":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null}},"pl":{"translation":{"Logging_in":"Logowanie...","your_connection_is_unencrypted":"Twoje połączenie nie jest szyfrowane.","your_connection_is_encrypted":"Twoje połączenie jest szyfrowane.","your_buddy_closed_the_private_connection":"Twój rozmówca zamknął połączenie.","start_private":"Rozpocznij rozmowę.","close_private":"Zakończ rozmowę.","your_buddy_is_verificated":"Twój rozmówca został zweryfikowany.","you_have_only_a_subscription_in_one_way":"Posiadasz tylko jednostronną subskrypcję.","authentication_query_sent":"Wysłano proźbę o autentykację.","your_message_wasnt_send_please_end_your_private_conversation":"Twoja wiadomość nie została wysłana. Proszę, zamknij rozmowę.","unencrypted_message_received":"Otrzymano niezaszyfrowaną wiadomość.","not_available":"Niedostępny.","no_connection":"Brak połączenia!","relogin":"Połącz ponownie","trying_to_start_private_conversation":"Rozpocznij rozmowę!","Verified":"Zweryfikowano","Unverified":"Niezweryfikowano","private_conversation_aborted":"Anulowano rozmowę!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Rozmówca przerwał połączenie! Powinieneś zrobić to samo.","conversation_is_now_verified":"Zweryfikowano połączenie.","authentication_failed":"Weryfikacja się nie powiodła.","Creating_your_private_key_":"Tworzenie klucza prywatnego; może to chwilę potrwać","Authenticating_a_buddy_helps_":"Autoryzacja pomoże w ustaleniu faktycznej tożsamości rozmówcy ;).","How_do_you_want_to_authenticate_your_buddy":"Jakiej autoryzacji chcesz użyć {{bid_name}} (<b>{{bid_jid}}</b>)?","Select_method":"Wybierz sposób...","Manual":"Ręcznie","Question":"Pytanie","Secret":"Hasło","To_verify_the_fingerprint_":"Aby zweryfikować kod, najpierw skontaktuj się z rozmówcą za pomocą zaufanego sposobu, np telefonu.","Your_fingerprint":"Twój kod:","Buddy_fingerprint":"Kod kontaktu","Close":"Zamknij","Compared":"Porównano","To_authenticate_using_a_question_":"Aby autoryzować za pomocą pytania, wybierz pytanie na które tylko ty i twój rozmówca zna odpowiedź.","Ask":"Zadaj pytanie","To_authenticate_pick_a_secret_":"Aby autoryzować za pomocą hasła, wybierz hasło na które znasz tylko Ty i twój rozmówca.","Compare":"Dopasuj","Fingerprints":"Kody autoryzacyjne","Authentication":"Autoryzacja","Message":"Wiadomość","Add_buddy":"Dodaj kontakt","rename_buddy":"Zmień nazwę kontaktu","delete_buddy":"Usuń kontakt","Login":"Login","Username":"Nazwa Użytkownika","Password":"Hasło","Cancel":"Anuluj","Connect":"Połączenie","Type_in_the_full_username_":"Wpisz pełną nazwę użytkownika (np. <B>imię.nazwisko@zajezdnia.local</B>) oraz jego nazwę wyświetlaną (Alias).","Alias":"Alias","Add":"Dodaj","Subscription_request":"Potwierdzenie subskrypcji","You_have_a_request_from":"Masz potwierdzenie od","Deny":"Odmów","Approve":"Zatwierdź","Remove_buddy":"Usuń kontakt","You_are_about_to_remove_":"Chcesz usunąć {{bid_name}} (<b>{{bid_jid}}</b>) z twojej listy kontaktów. Wszystkie powiązane rozmowy zostaną zamknięte.","Continue_without_chat":"Kontynuuj bez komunikatora","Please_wait":"Proszę czekać","Login_failed":"Błędne logowanie","Sorry_we_cant_authentikate_":"Błędna autoryzacja z serwerem. Może hasło jest nieprawidłowe?","Retry":"Powrót","clear_history":"Wyczyść historię","New_message_from":"Nowa wiadomość od __name__","Should_we_notify_you_":"Czy chcesz otrzymywać powiadomienia o nowych wiadomościach w przyszłości?","Please_accept_":"Kliknij \"Zezwól\" na górze.","Hide_offline":"Schowaj niedostępne kontakty","Show_offline":"Pokaż niedostępne kontakty","About":"Info","dnd":"Nie przeszkadzać","Mute":"Wycisz","Unmute":"Włącz dźwięk","Subscription":"Subskrybcja","both":"obustronna","Status":"Status","online":"Dostępny","chat":"czat","away":"z dala od kompa","xa":"hen hen...","offline":"niedostępny","none":"brak","Unknown_instance_tag":"Nieznany przypadek.","Not_one_of_our_latest_keys":"Not one of our latest keys.","Received_an_unreadable_encrypted_message":"Otrzymano nieczytelną, zaszyfrowaną wiadomość.","Online":"Połączony","Chatty":"Pogawędzimy?","Away":"Daleko","Extended_away":"Hen Hen...","Offline":"Niedostępny","Friendship_request":"Prośba o kontakt","Confirm":"Potwierdzenie","Dismiss":"Odwołaj","Remove":"Usuń","Online_help":"Pomoc Online","FN":"Pełna nazwa","N":" ","FAMILY":"Nazwisko","GIVEN":"Imię","NICKNAME":"Pseudonim","URL":"Strona WWW","ADR":"Adres","STREET":"Ulica","EXTADD":"Pełny adres","LOCALITY":"Lokalizacja","REGION":"Region","PCODE":"Kod pocztowy","CTRY":"Kraj","TEL":"Telefon","NUMBER":"Numer","EMAIL":"Email","USERID":" ","ORG":"Organizacja","ORGNAME":"Nazwa","ORGUNIT":"Jednostka","TITLE":"Stanowisko","ROLE":"Rola","BDAY":"Data urodzin","DESC":"Opis","PHOTO":" ","send_message":"Wyślij wiadomość","get_info":"Pokaż informację","Settings":"Ustawienia","Priority":"Priorytet","Save":"Zapisz","User_settings":"Ustawienia Użytkownika","A_fingerprint_":"Kod służy do autoryzacji Twojego rozmówcy aby potwierdzić jego tożsamość.","is":"jest","Login_options":"opcje logowania","BOSH_url":"Adres BOSH","Domain":"Domena","Resource":"Źródło","On_login":"Na login","Received_an_unencrypted_message":"Zatwierdzono nieszyfrowaną wiadomość.","Sorry_your_buddy_doesnt_provide_any_information":"Wybacz, twój rozmówca nie posiada żadnych informacji.","Info_about":"Informacja o...","Authentication_aborted":"Autoryzacja anulowana.","Authentication_request_received":"Prośba o autoryzację została przyjęta.","Log_in_without_chat":"Zaloguj bez komunikatora","has_come_online":"jest teraz dostępny","Unknown_sender":"Nieznany nadawca","Please_allow_access_to_microphone_and_camera":"Kliknij \"Potwierdź\" na górze, aby móc korzystać z mikrofonu oraz kamery.","Incoming_call":"Przychodzące połączenie","from":"z","Do_you_want_to_accept_the_call_from":"Akceptujesz połączenie od","Reject":"Odrzuć","Accept":"Zaakceptuj","hang_up":"odbierz","snapshot":"zrób zdjęcie","mute_my_audio":"wycisz dźwięk","pause_my_video":"zatrzymaj moje wideo","fullscreen":"Pełny ekran","Info":"Informacja","Local_IP":"Adres IP","Remote_IP":"Zdalny adres IP","Local_Fingerprint":"Kod lokalny","Remote_Fingerprint":"Zdalny kod","Video_call_not_possible":"Rozmowa wideo jest niemożliwa. Twój rozmówca nie ma możliwości prowadzenia takich rozmów.","Start_video_call":"Rozpocznij rozmowę wideo","Join_chat":"Dołącz do czata","Join":"Dołącz","Room":"Pokój","Nickname":"Nazwa użytkownika","left_the_building":"__nickname__ wyszedł","entered_the_room":"__nickname__ wszedł do pokoju","is_now_known_as":"__oldNickname__ zmienił nazwę na __newNickname__","This_room_is":"Ten pokój jest","muc_hidden":{"keyword":"ukryty","description":"nie można odnaleźć elementów wyszukiwania"},"muc_membersonly":{"keyword":"tylko zalogowani","description":"musisz być członkiem listy"},"muc_moderated":{"keyword":"moderowano","description":"tylko osoby z opcją \"głos\" mogą wysyłać wiadomość"},"muc_nonanonymous":{"keyword":"nie-anonimowy","description":"Twój identyfikator jabber jest widoczny dla wszystkich innych osób"},"muc_open":{"keyword":"otwarty","description":"wszyscy mają pozwolenie aby dołączyć"},"muc_passwordprotected":{"keyword":"ograniczone hasłem","description":"musisz wpisać prawidłowe hasło"},"muc_persistent":{"keyword":"trwale","description":"nie zostaną zniszczone, jeśli ostatnia osoba wyszła"},"muc_public":{"keyword":"publiczny","description":"wyszukawno"},"muc_semianonymous":{"keyword":"pół-anonimowy","description":"Twój identyfikator jabber jest widoczny w pokoju adminów"},"muc_temporary":{"keyword":"tymczasowy","description":"zostanie usunięty jeżeli ostatnia osoba wyjdzie"},"muc_unmoderated":{"keyword":"niemoderowany","description":"wszyscy są uprawnieni do pisania wiadomości"},"muc_unsecured":{"keyword":"niezabezpieczone","description":"nie musisz wpisywać hasła"},"Continue":"Kontynuuj","Server":"Serwer","Rooms_are_loaded":"Pokoje zostały załadowane","Could_load_only":"Nie załadowano __count__ pokoi","muc_explanation":"Aby się zalogować, wpisz nazwę pokoju oraz opcjonalnie nazwę użytkownika i hasło","You_already_joined_this_room":"Już dołączyłeś do tego pokoju","This_room_will_be_closed":"Ten pokój będzie zamknięty","Room_not_found_":"Nowy pokój będzie stworzony","Loading_room_information":"Ładowani informacji o pokoju","Destroy":"Zniszczony","Leave":"Opuść","changed_subject_to":"__nickname__ zmienił temat pokoju na \"__subject__\"","muc_removed_kicked":"Zostałeś wyrzucony z pokoju","muc_removed_info_kicked":"__nickname__ został wyrzucony z pokoju","muc_removed_banned":"Zostałeś zbanowany","muc_removed_info_banned":"__nickname__ został zbanowany","muc_removed_affiliation":"Zostałeś usunięty z pokoju ze względu na zmianę przynależnosci","muc_removed_info_affiliation":"__nickname__ został usunięty z pokoju ze względu na zmianę przynależnosci","muc_removed_membersonly":"Zostałeś usunięty z pokoju ze względu na zmianę pokoju tylko dla członków, a Ty nie jesteś członkiem...","muc_removed_info_membersonly":"__nickname__ został usunięty z pokoju ze względu na zmianę pokoju na tylko dla członków","muc_removed_shutdown":"Zostałeś usunięty z pokoju ze względu na zamknięcie usługi","Reason":"Powód","message_not_send":"Wystąpił błąd i twoja wiadomość nie została wysłana.","message_not_send_item-not-found":"Twoja wiadomość nie została wysłana ponieważ ten pokój nie istnieje","message_not_send_forbidden":"Twoja wiadomość nie została wysłana ponieważ nie masz głosu w tym pokoju","message_not_send_not-acceptable":"Twoja wiadomość nie została wysłana ponieważ nie jesteś właścicielem tego pokoju","This_room_has_been_closed":"Ten pokój został zamknięty","Room_logging_is_enabled":"Logowanie do pokoju jest włączone","A_password_is_required":"Hasło jest wymagane","You_are_not_on_the_member_list":"Nie jesteś na liście członków","You_are_banned_from_this_room":"Zostałeś zbanowany w tym pokoju","Your_desired_nickname_":"Twoja nazwa użytkownika jest już użyta. Spróbuj wybrać inną","The_maximum_number_":"Została osiągnięta maksymalna liczba użytkowników w tym pokoju","This_room_is_locked_":"Ten pokój jest zablokowany","You_are_not_allowed_to_create_":"Nie masz uprawnień do tworzenia pokoju","Alert":"Alarm","Call_started":"Rozmowa rozpoczęta","Call_terminated":"Rozmowa zakończona","Carbon_copy":"Do wiadomości","Enable":"Włączone","jingle_reason_busy":"zajęte","jingle_reason_decline":"odmów","jingle_reason_success":"zakończono","Media_failure":"Błąd mediów","No_local_audio_device":"Brak lokalnego urządzenia audio.","No_local_video_device":"Brak lokalnego urządzenia wideo.","Ok":"Ok","PermissionDeniedError":"Ty lub twoja przeglądarka odmówiła dostępu do audio/video","Use_local_audio_device":"Użyj lokalnego urządzenia audio.","Use_local_video_device":"Użyj lokalnego urządzenia wideo.","is_":"jest __status__","You_received_a_message_from_an_unknown_sender_":"Masz wiadomość od nieznanego nadawcy. (__sender__) Chcesz to wyświetlić?","Your_roster_is_empty_add_":"Twoja lista jest pusta, dodaj kontakty <a>Nowy kontakt</a>","onsmp_explanation_question":"Twój rozmówca próbuje się z Tobą połączyć. Autoryzacja z rozmówcą, napisz odpowiedź.","onsmp_explanation_secret":"Twój rozmówca próbuje się z Tobą połączyć. Autoryzacja z rozmówcą, wpisz hasło.","from_sender":"z __sender__","Verified_private_conversation_started":"Zweryfikowano Rozmowa prywatna rozpoczęta.","Unverified_private_conversation_started":"Niezweryfikowano Rozmowa prywatna rozpoczęta.","Bookmark":"Zakładka","Auto-join":"Auto-połączenie","Edit_bookmark":"Edytuj zakładkę","Room_logging_is_disabled":"Logowanie pokoju jest wyłączone","Room_is_now_non-anoymous":"Pokój jest teraz nie-anonimowy","Room_is_now_semi-anonymous":"Pokój jest teraz pół-anonimowy","Do_you_want_to_change_the_default_room_configuration":"Chcesz zmienić domyślną konfigurację pokoju?","Default":"Domyślny","Change":"Zmień","Send_file":"Wyślij plik","setting-explanation-carbon":null,"setting-explanation-login":"Jeżeli ta opcja jest włączona, czat uruchomi się przy zalogowaniu.","setting-explanation-priority":"Jeżeli jesteś zalogowany wiele razy na to samo konto twój serwer XMPP dostarczy wiadomości do klienta z najwyższym priorytetem.","setting-explanation-xmpp":"Te ustawienia używane są do połączenia z serwerem XMPP."}},"pt-BR":{"translation":{"Logging_in":"Entrando...","your_connection_is_unencrypted":"Sua conexão não é encriptada","your_connection_is_encrypted":"Sua conexão é encriptada","your_buddy_closed_the_private_connection":"Seu contato fechou a conexão privada","start_private":"Iniciar conversa privada","close_private":"Fechar conversa privada","your_buddy_is_verificated":"Seu contato está verificado","you_have_only_a_subscription_in_one_way":"Você só tem a inscrição one-way","authentication_query_sent":"Pergunta de autenticação enviada","your_message_wasnt_send_please_end_your_private_conversation":"Sua mensagem não foi enviada. Por favor finalize sua conversa privada","unencrypted_message_received":"Mensagem não encriptada recebida","not_available":"Indisponível","no_connection":"Sem conexão!","relogin":"reentrar","trying_to_start_private_conversation":"Tentando iniciar conversa privada","Verified":"Verificado","Unverified":"Não verificado","private_conversation_aborted":"Conversa privada abortada!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Seu contato encerrou a conversa privada! Você deveria fazer o mesmo.","conversation_is_now_verified":"Conversa verificada.","authentication_failed":"Autenticação falhou.","Creating_your_private_key_":"Criando sua chave privada: isso pode demorar um pouco.","Authenticating_a_buddy_helps_":"Autenticar seu contato ajuda a garantir que a pessoa com a qual você está falando é realmente a pessoa que ela alega ser.","How_do_you_want_to_authenticate_your_buddy":"Como você gostaria de se autenticar {{bid_name}} (<b>{{bid_jid}}</b>)?","Select_method":"Selecione o método...","Manual":"Manual","Question":"Pergunta","Secret":"Senha","To_verify_the_fingerprint_":"Para verificar o fingerprint, entre em contato com seu contato usando outro meio, de preferência seguro, como o telefone.","Your_fingerprint":"Sua impressão digital","Buddy_fingerprint":"Impressão digital do contato","Close":"Fechar","Compared":"Comparado","To_authenticate_using_a_question_":"Para autenticar seu contato faça uma pergunta, mas escolha que só ele saiba a resposta.","Ask":"Pergunta","To_authenticate_pick_a_secret_":"Para autenticar, escolha um segredo que somente você e seu contato saibam.","Compare":"Compare","Fingerprints":"Impressões digitais","Authentication":"Autenticação","Message":"Mensagem","Add_buddy":"Adicionar contato","rename_buddy":"renomear contato","delete_buddy":"remover contato","Login":"Entrar","Username":"Usuário","Password":"Senha","Cancel":"Cancelar","Connect":"Conectar","Type_in_the_full_username_":"Digite seu nome completo e um apelido opcional.","Alias":"Apelido","Add":"Adicionar","Subscription_request":"Pedido de inscrição","You_have_a_request_from":"Você tem um pedido de","Deny":"Negar","Approve":"Aprovar","Remove_buddy":"Remover contato","You_are_about_to_remove_":"Você está prestes a remover {{bid_name}} (<b>{{bid_jid}}</b>) de sua lista de contatos. Todas as conversas serão fechadas.","Continue_without_chat":"Continue sem converar","Please_wait":"Por favor aguarde","Login_failed":"Autenticação da conversa falhou","Sorry_we_cant_authentikate_":"A autenticação com o servidor falhou. Talvez seja a senha errada?","Retry":"Voltar","clear_history":"Limpar histórico","New_message_from":"Nova mensagem de __name__","Should_we_notify_you_":"Devemos continuar notificando sobre novas mensagens no futuro?","Please_accept_":"Por favor clique no botão \"Permitir\" na parte superior.","Hide_offline":"Esconder contatos desconectados","Show_offline":"Mostrar contatos desconectados","About":"Sobre","dnd":"Não perturbe","Mute":"Mudo","Unmute":"Ligar","Subscription":"Inscrição","both":"ambos","Status":"Status","online":"online","chat":"conversa","away":"ausente","xa":"ausente por mais tempo","offline":"desativado","none":"nenhum","Unknown_instance_tag":"Marcação desconhecida da instância","Not_one_of_our_latest_keys":"Nenhuma de nossas ultimas chaves.","Received_an_unreadable_encrypted_message":"Mensagem encriptada ilegível foi recebida.","Online":"Online","Chatty":"Tagarela","Away":"Ausente","Extended_away":"Ausente por mais tempo","Offline":"Desativado","Friendship_request":"Pedido de amizade","Confirm":"Confirmar","Dismiss":"Ignorar","Remove":"Remover","Online_help":"Ajuda online","FN":"Nome completo","N":" ","FAMILY":"Sobrenome","GIVEN":"Nome","NICKNAME":"Apelido","URL":"URL","ADR":"Endereço","STREET":"Rua, Av, etc","EXTADD":"Complemento","LOCALITY":"Localidade","REGION":"Região","PCODE":"CEP","CTRY":"País","TEL":"Telefone","NUMBER":"Número","EMAIL":"Email","USERID":" IDUsuário","ORG":"Empresa","ORGNAME":"Nome","ORGUNIT":"Unidade","TITLE":"Cargo","ROLE":"Função","BDAY":"Data de nascimento","DESC":"Descrição","PHOTO":"Foto","send_message":"Enviar mensagem","get_info":"Exibir informações","Settings":"Configurações","Priority":"Prioridade","Save":"Salvar","User_settings":"Configurações do usuário","A_fingerprint_":"O fingerprint é usado para certificar que a pessoa com a qual se está falando é que ela diz ser.","is":"é","Login_options":"Opções de login","BOSH_url":"BOSH URL","Domain":"Domínio","Resource":"Recurso","On_login":"Ao autenticar","Received_an_unencrypted_message":"Mensagem não encriptada recebida","Sorry_your_buddy_doesnt_provide_any_information":"Desculpe, seu contato não forneceu nenhuma informação","Info_about":"Informações sobre","Authentication_aborted":"Autenticação encerrada.","Authentication_request_received":"Pedido de autenticação recebido","Log_in_without_chat":"Entrar sem conversar","has_come_online":"ficou online","Unknown_sender":"Emissor desconhecido","Please_allow_access_to_microphone_and_camera":"Por favor clique no botão \"Permitir\" no topo, para conceder acesso ao seu microfone e câmera.","Incoming_call":"Recebendo chamada","from":"de","Do_you_want_to_accept_the_call_from":"Você aceita a chamada de","Reject":"Negar","Accept":"Aceitar","hang_up":"desligar","snapshot":"registrar imagem","mute_my_audio":"mudo","pause_my_video":"pausar vídeo","fullscreen":"tela cheia","Info":"Informações","Local_IP":"IP local","Remote_IP":"IP remoto","Local_Fingerprint":"Fingerprint local","Remote_Fingerprint":"Fingerprint remoto","Video_call_not_possible":"Chamada de vídeo impossível. Seu contato não suporta chamadas desse tipo.","Start_video_call":"Iniciar chamada de vídeo","Join_chat":"Entrar no chat","Join":"Entrar","Room":"Sala","Nickname":"Apelido","left_the_building":"__nickname__ deixou o prédio","entered_the_room":"__nickname__ entrou na sala","is_now_known_as":"__oldNickname__ agora é conhecido como __newNickname__","This_room_is":"Esta sala é","muc_hidden":{"keyword":"oculto","description":"Não pode ser encontrado através de pesquisa"},"muc_membersonly":{"keyword":"apenas para membros","description":"você precisa estar na lista de membros"},"muc_moderated":{"keyword":"moderado","description":"Somente pessoas com \"voice\" podem enviar mensagens"},"muc_nonanonymous":{"keyword":"não-anônimo","description":"Seu id jabber esta esposto para todos os outros ocupantes"},"muc_open":{"keyword":"abrir","description":"Todos podem entrar"},"muc_passwordprotected":{"keyword":"protegido por senha","description":"você precisa fornecer a senha correta"},"muc_persistent":{"keyword":"persistente","description":"Não será destruída se o último ocupante tiver saído"},"muc_public":{"keyword":"público","description":"pode ser localizado pela busca"},"muc_semianonymous":{"keyword":"semi-anônimos","description":"Sua identificação jabber só é exposta para administradores da sala"},"muc_temporary":{"keyword":"temporário","description":"Será destruída se o último ocupante tiver saído"},"muc_unmoderated":{"keyword":"sem moderação","description":"Todos tem permissão de enviar mensagens"},"muc_unsecured":{"keyword":"inseguro","description":"Você não precisa de senha para entrar"},"Continue":"Avançar","Server":"Servidor","Rooms_are_loaded":"Sala carregada","Could_load_only":"Pode carregar somente __count__ salas para autocompletar","muc_explanation":"Por favor entre um nome de sala e um nickname opcional e uma senha para entrar no chat","You_already_joined_this_room":"Você já entrou nesta sala","This_room_will_be_closed":"Esta sala será fechada","Room_not_found_":"Uma nova sala será criada","Loading_room_information":"Carregar informação da sala","Destroy":"Destruir","Leave":"Sair","changed_subject_to":"__nickname__ alterar o assunto da sala para \"__subject__\"","muc_removed_kicked":"Você foi removido da sala","muc_removed_info_kicked":"__nickname__ foi removido da sala","muc_removed_banned":"Você foi banido da sala","muc_removed_info_banned":"__nickname__ foi banido da sala","muc_removed_affiliation":"Você foi removido da sala pois a sala, por que a afiliação mudou","muc_removed_info_affiliation":"__nickname__ foi removido da sala, por que a afiliação mudou","muc_removed_membersonly":"Você foi removido da sala pois a sala foi alterada somente para membros e você não é um membro","muc_removed_info_membersonly":"__nickname__ foi removido da sala porque a sala foi alterada para somente membros e você não é um membro","muc_removed_shutdown":"Você foi removido da sala, por que o serviço MUC esta sendo desligado","Reason":"Motivo","message_not_send":"Sua mensagem não foi enviada devido a um erro","message_not_send_item-not-found":"Sua mensagem não foi enviada por que essa sala nao existe mais","message_not_send_forbidden":"Sua mensagem não foi enviada por que não tem 'voz' para essa sala","message_not_send_not-acceptable":"Sua mensagem não foi enviada por que você nao é ocupante desta sala","This_room_has_been_closed":"Essa sala foi fechada","Room_logging_is_enabled":"O Logging esta habilitado","A_password_is_required":"Senha é obrigatória","You_are_not_on_the_member_list":"Você não esta na lista de usuarios","You_are_banned_from_this_room":"Você foi banido desta sala","Your_desired_nickname_":"O nickname escolhido já esta em uso. Por favor escolha outro","The_maximum_number_":"O número máximo de usuarios já foi antigido para essa sala","This_room_is_locked_":"A sala esta trancada","You_are_not_allowed_to_create_":"Você não esta autorizado para criar uma sala","Alert":"Alerta","Call_started":"Chamada iniciada","Call_terminated":"Chamada finalizada","Carbon_copy":"Copia carbono","Enable":"Habilitado","jingle_reason_busy":"ocupado","jingle_reason_decline":"recusado","jingle_reason_success":"sucesso","Media_failure":"Media falhou","No_local_audio_device":"sem dispositivo local de audio","No_local_video_device":"sem dispositivo local de video","Ok":"Ok","PermissionDeniedError":"Você ou seu navegador negou permissão para acessar audio/video","Use_local_audio_device":"Usar dispositivo local de audio","Use_local_video_device":"Usar dispositivo local de video","is_":"é __status__","You_received_a_message_from_an_unknown_sender_":"Você recebeu uma mensagem de um emissor desconhecido (__sender__) Você quer mostrá-los?","Your_roster_is_empty_add_":"Sua lista está vazia, adicione um <a>novo contato</a>","onsmp_explanation_question":"Seu contato está tentando determinar se ele realmente está falando contigo. Para autenticar seu contato, entre com a resposta e clique em Responder.","onsmp_explanation_secret":"Seu contato está tentando determinar se ele realmente está falando contigo. Para autenticar seu contato, escreva a senha.","from_sender":"de __sender__","Verified_private_conversation_started":"Verificado Conversa privada iniciada.","Unverified_private_conversation_started":"Não verificado Conversa privada iniciada.","Bookmark":"Favoritos","Auto-join":"Entrar Automaticamente","Edit_bookmark":"Editar favoritos","Room_logging_is_disabled":"Registro de log na sala está desativado","Room_is_now_non-anoymous":"A sala é não anônima agora","Room_is_now_semi-anonymous":"A sala é semi anônima agora","Do_you_want_to_change_the_default_room_configuration":"Você quer alterar as configurações da sala?","Default":"Padrão","Change":"Alterar","Send_file":"Enviar arquivo","setting-explanation-carbon":"Com carbon copy ativado seu servidor XMPP vai enviar uma copia de cada mensagem para você neste cliente mesmo que não tenha endereço","setting-explanation-login":"Se essa opção esta habilitada, o chat vai começar ao logar.","setting-explanation-priority":"Você esta logado varias vezes com a mesma conta, seu servidor XMPP vai entregar as mensagens para o cliente com a prioridade mais alta.","setting-explanation-xmpp":"Essas opções são usadas para conectar no Servidor XMPP"}},"ro":{"translation":{"Logging_in":"Autentificare...","your_connection_is_unencrypted":"Conexiunea nu este criptată.","your_connection_is_encrypted":"Conexiunea este criptată.","your_buddy_closed_the_private_connection":"Interlocutorul a închis conexiunea privată.","start_private":"Pornește în privat","close_private":"Închide privat","your_buddy_is_verificated":"Interlocutorul este verificat.","you_have_only_a_subscription_in_one_way":"Subscrierea este într-o singură direcție.","authentication_query_sent":"Cererea de autentificare a fost trimisă.","your_message_wasnt_send_please_end_your_private_conversation":"Mesajul nu a fost trimis. Te rog închide conversația în privat.","unencrypted_message_received":"A fost primit un mesaj necriptat","not_available":"Indisponibil","no_connection":"Fără conexiune!","relogin":"Re-autentificare","trying_to_start_private_conversation":"Se încearcă deschiderea conversației în privat!","Verified":"Verificat","Unverified":"Neverificat","private_conversation_aborted":"Conversație în privat eșuată!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Interlocutorul a închis conversația în privat! Ar trebui să faci la fel și tu.","conversation_is_now_verified":"Conversația este acum verificată.","authentication_failed":"Autentificarea a eşuat.","Creating_your_private_key_":"Se crează cheia privată; ar putea să dureze ceva timp.","Authenticating_a_buddy_helps_":"Autentificând un contact ne asigură că persoana cu care vorbești este într-adevăr cine pretinde că este.","How_do_you_want_to_authenticate_your_buddy":"Cum vrei să te autentifici {{bid_name}} (<b>{{bid_jid}}</b>)","Select_method":"Alege metoda...","Manual":"Manual","Question":"Întrebare","Secret":"Secret","To_verify_the_fingerprint_":"Pentru a verifica amprenta, contactează interlocutorul printr-un canal de încredere, cum ar fi telefonul.","Your_fingerprint":"Amprenta ta","Buddy_fingerprint":"Amprenta interlocutorului","Close":"Închide","Compared":"Prin comparație","To_authenticate_using_a_question_":"Pentru autentificarea folosind o întrebare, alege o întrebare cu un răspuns cunoscut doar de tine și de interlocutor.","Ask":"Întreabă","To_authenticate_pick_a_secret_":"Pentru autentificare, alege un secret cunoscut doar de tine și de interlocutor.","Compare":"Compară","Fingerprints":"Amprente","Authentication":"Autentificare","Message":"Mesaj","Add_buddy":"Adaugă contact","rename_buddy":"redenumește contact","delete_buddy":"șterge contact","Login":"Logare","Username":"Utilizator","Password":"Parolă","Cancel":"Renunță","Connect":"Conectare","Type_in_the_full_username_":"Scrie numele complet al utilizatorului și un alias opțional.","Alias":"Alias","Add":"Adaugă","Subscription_request":"Cerere de subscriere","You_have_a_request_from":"Ai o cerere de la","Deny":"Refuză","Approve":"Aprobă","Remove_buddy":"Șterge contact","You_are_about_to_remove_":"Urmează să ștergi {{bid_name}} (<b>{{bid_jid}}</b>) din lista de contacte. Toate chat-urile asociate vor fi închise.","Continue_without_chat":"Continuă fără chat","Please_wait":"Te rog așteaptă","Login_failed":"Logarea pe chat a eșuat","Sorry_we_cant_authentikate_":"Autentificarea cu serverul de chat a eșuat. Poate parola este greșită ?","Retry":"Înapoi","clear_history":"Curăță istoria","New_message_from":"Un nou mesaj de la __name__","Should_we_notify_you_":"Vrei să fi notificat despre mesajele noi în viitor ?","Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null}},"ru":{"translation":{"Logging_in":"Вход в систему...","your_connection_is_unencrypted":"Ваше соединение не зашифровано.","your_connection_is_encrypted":"Ваше соединение зашифровано.","your_buddy_closed_the_private_connection":"Ваш собеседник закончил зашифрованное соединение.","start_private":"Начать зашифрованный чат","close_private":"Закончить зашифрованный чат","your_buddy_is_verificated":"Собеседник подтвержден.","you_have_only_a_subscription_in_one_way":"У вас только односторонняя подписка.","authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":"Сообщение не отправлено. Завершите зашифрованный чат, пожалуйста.","unencrypted_message_received":"Получено незашифрованное сообщение","not_available":"Не доступен","no_connection":"Нет соединения!","relogin":"переподключиться","trying_to_start_private_conversation":"Попытка начать зашифрованный чат!","Verified":"Подтверждено","Unverified":"Не подтверждено","private_conversation_aborted":"Зашифрованный чат отклонен!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Ваш собеседник завершил зашифрованный чат! Вы должны сделать тоже самое.","conversation_is_now_verified":"Чат теперь утвержден.","authentication_failed":"Ошибка авторизации.","Creating_your_private_key_":"Создается приватный ключ. Это может занять некоторое время","Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":"Выберите метод...","Manual":"Вручную","Question":"Вопрос","Secret":"Пароль","To_verify_the_fingerprint_":null,"Your_fingerprint":"Ваш отпечаток","Buddy_fingerprint":"Отпечаток собеседника","Close":"Закрыть","Compared":"Сравнение завершено","To_authenticate_using_a_question_":"Для авторизации с помощью вопроса выберите вопрос, ответ на который знаете только Вы и собеседник.","Ask":null,"To_authenticate_pick_a_secret_":"Для авторизации выберите пароль, который знаете только Вы и собеседник.","Compare":"Сравнить","Fingerprints":"Отпечатки","Authentication":"Авторизация","Message":"Сообщение","Add_buddy":"Добавить контакт","rename_buddy":"переименовать контакт","delete_buddy":"удалить контакт","Login":"Вход","Username":"Логин","Password":"Пароль","Cancel":"Отмена","Connect":"Подключить","Type_in_the_full_username_":"Введите полное имя пользователя и дополнительный псевдоним","Alias":"Псевдоним","Add":"Добавить","Subscription_request":"Запрос подписки","You_have_a_request_from":"Получен запрос от","Deny":"Отказ","Approve":"Подтвердить","Remove_buddy":"Удалить контакт","You_are_about_to_remove_":"Вы собираетесь удалить {{bid_name}} (<b>{{bid_jid}}</b>) из списка контактов. Все связанные с чаты будут закрыты.","Continue_without_chat":"Продолжить без чата","Please_wait":"Подождите…","Login_failed":"Неудачный вход в чат","Sorry_we_cant_authentikate_":"Неудачная попытка входа","Retry":"Назад","clear_history":"Очистить историю","New_message_from":"Новое сообщение от __name__","Should_we_notify_you_":"Уведомлять о новых сообщениях в будущем?","Please_accept_":"Нажмите кнопку \"Разрешить\" вверху страницы, пожалуйста","Hide_offline":"Спрятать отключенных","Show_offline":"Показать отключенных","About":"О проекте","dnd":"Не беспокоить","Mute":"Выкл. уведомления","Unmute":"Вкл. уведомления","Subscription":"Подписка","both":"оба","Status":"Статус","online":"в сети","chat":"готов общаться","away":"отошел","xa":"отсутствую","offline":"не в сети","none":"нет","Unknown_instance_tag":"Неизвестный тег.","Not_one_of_our_latest_keys":"Ни один из наших последних ключей","Received_an_unreadable_encrypted_message":"Получено нечитаемое зашифрованное сообщение","Online":"В сети","Chatty":"Готов общаться","Away":"Отошел","Extended_away":"Отсутствую","Offline":"Не в сети","Friendship_request":"Запрос на добавление в контакты","Confirm":"Подтвердить","Dismiss":"Отклонить","Remove":"Удалить","Online_help":"Онлайн помощь","FN":"Полное имя","N":null,"FAMILY":"Фамилия","GIVEN":"Имя","NICKNAME":"Ник","URL":"URL","ADR":"Адрес","STREET":"Улица","EXTADD":"Дополнительный адрес","LOCALITY":"Город","REGION":"Область","PCODE":"Индекс","CTRY":"Страна","TEL":"Телефон","NUMBER":"Номер","EMAIL":"Почта","USERID":null,"ORG":"Организация","ORGNAME":"Название","ORGUNIT":"Отдел","TITLE":"Должность","ROLE":"Обязанности","BDAY":"День рождения","DESC":"Описание","PHOTO":" Фото ","send_message":"Отправить сообщение","get_info":"Показать информацию","Settings":"Настройки","Priority":"Приоритет","Save":"Сохранить","User_settings":"Пользовательские настройки","A_fingerprint_":null,"is":" ","Login_options":"Параметры входа","BOSH_url":"BOSH URL","Domain":"Домен","Resource":"Ресурс","On_login":"Автоматически подключаться","Received_an_unencrypted_message":"Получено незашифрованное сообщение","Sorry_your_buddy_doesnt_provide_any_information":"К сожалению, контакт не предоставил какой-либо информации.","Info_about":"Информация о","Authentication_aborted":"Аутентификация прервана.","Authentication_request_received":"Получен запрос проверки подлинности.","Log_in_without_chat":"Вход без чата","has_come_online":"появился в сети","Unknown_sender":"Неизвестный отправитель","Please_allow_access_to_microphone_and_camera":"Нажмите кнопку \"Разрешить\" вверху страницы, чтобы предоставить доступ к микрофону и камере.","Incoming_call":"Входящий вызов","from":"от","Do_you_want_to_accept_the_call_from":"Вы хотите принять вызов от","Reject":"Отклонить","Accept":"Принять","hang_up":"Завершить","snapshot":"Снимок","mute_my_audio":"Без звука","pause_my_video":"Остановить моё видео","fullscreen":"На весь экран","Info":"Инфо","Local_IP":"Мой IP","Remote_IP":"Удаленный IP","Local_Fingerprint":"Мой отпечаток","Remote_Fingerprint":"Удаленный отпечаток","Video_call_not_possible":"Видео-вызов невозможен. Ваш собеседник не поддерживает видео-вызовы.","Start_video_call":"Видео-вызов","Join_chat":"Присоединиться к комнате","Join":"Присоедениться","Room":"Комната","Nickname":"Ник","left_the_building":"__nickname__ выходит из комнаты","entered_the_room":"__nickname__ заходит в комнату","is_now_known_as":"__oldNickname__ теперь известен как __newNickname__","This_room_is":"Эта комната","muc_hidden":{"keyword":"скрыта","description":"не может быть найдена через поиск"},"muc_membersonly":{"keyword":"только для участников","description":"Вы должны быть в списке участников"},"muc_moderated":{"keyword":"модерируется","description":"Только пользователи с правом голоса могут отправлять сообщения"},"muc_nonanonymous":{"keyword":"неанонимная","description":"Ваш JID будет показан всем посетителям"},"muc_open":{"keyword":"открытая","description":"Любой пользователь может присоедениться"},"muc_passwordprotected":{"keyword":"защищена паролем","description":"Необходимо ввести правильный пароль"},"muc_persistent":{"keyword":"постоянная","description":"Не будет уничтожена, когда ее покинут все участники"},"muc_public":{"keyword":"публичная","description":"Может быть найдена через поиск"},"muc_semianonymous":{"keyword":"полу-анонимная","description":"Ваш JID могут увидеть только администраторы"},"muc_temporary":{"keyword":"временная","description":"Будет уничтожена как только не останется ни одного участника"},"muc_unmoderated":{"keyword":"не модерируется","description":"Любой посетитель может отправлять сообщения"},"muc_unsecured":{"keyword":"без пароля","description":"Не нужно вводить пароль для входа"},"Continue":"Далее","Server":"Сервер","Rooms_are_loaded":"Комнаты загружены","Could_load_only":"Подгрузка только __count__ комнат в автодополнении","muc_explanation":"Введите название комнаты, свой ник и пароль для входа в комнату","You_already_joined_this_room":"Вы уже в этой комнате","This_room_will_be_closed":"Эта комната была закрыта","Room_not_found_":"Новая комната будет создана","Loading_room_information":"Загрузка информации о комнате","Destroy":"Уничтожить","Leave":"Покинуть","changed_subject_to":"__nickname__ изменил тему комнаты на \"__subject__\"","muc_removed_kicked":"Вас выкинули из комнаты","muc_removed_info_kicked":"__nickname__ был удален из комнаты","muc_removed_banned":"Вас забанили в комнате","muc_removed_info_banned":"__nickname__ был забанен в комнате","muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":"Вы были исключены из комнаты, т.к. комната стала доступна только для членов комнаты, а Вы им не являетесь","muc_removed_info_membersonly":"__nickname__ исключен(а) из комнаты, т.к. комната стала доступна только для членов комнаты, а он(она) им не является","muc_removed_shutdown":"Вы были удалены из комнаты, т.к. сервис чат-комнат недоступен","Reason":"Причина","message_not_send":"Ваше сообщение не было отправлено из-за ошибки","message_not_send_item-not-found":"Ваше сообщение не было отправлено, т.к. этой комнаты не существует","message_not_send_forbidden":"Ваше сообщение не было отправлено, т.к. у Вас нет права голоса в этой комнате","message_not_send_not-acceptable":"Ваше сообщение не было отправлено, т.к. Вы не являетесь участником этой комнаты","This_room_has_been_closed":"Эта комната была закрыта","Room_logging_is_enabled":"Журналирование комнаты включено","A_password_is_required":"Необходим пароль","You_are_not_on_the_member_list":"Вы не в списке участников","You_are_banned_from_this_room":"Вас забанили в этой комнате","Your_desired_nickname_":"Данное имя пользователя уже занято, пожалуйста, выберите другое имя пользователя","The_maximum_number_":"Достигнут лимит максимального количества посетителей этой комнаты","This_room_is_locked_":"Эта комната заблокирована","You_are_not_allowed_to_create_":"Вы не можете создавать комнаты","Alert":"Внимание","Call_started":"Вызов начался","Call_terminated":"Вызов завершен","Carbon_copy":"Копировать сообщения","Enable":"Включить","jingle_reason_busy":"занято","jingle_reason_decline":"запрещено","jingle_reason_success":"сбросили","Media_failure":"Ошибка передачи медиа","No_local_audio_device":"Нет локального аудио-устройства.","No_local_video_device":"Нет локального видео-устройства.","Ok":"Ок","PermissionDeniedError":"Вы или Ваш браузер запретили использовать микрофон/камеру","Use_local_audio_device":"Использовать локальное аудио-устройство.","Use_local_video_device":"Использовать локальное видео-устройство.","is_":"__status__","You_received_a_message_from_an_unknown_sender_":"Вы получили сообщение от неизвестного отправителя (__sender__)","Your_roster_is_empty_add_":"Ваш список контактов пуст, добавить <a>новый контакт</a>","onsmp_explanation_question":"Собеседник пытается определить, что общается действительно с Вами.","onsmp_explanation_secret":"Собеседник пытается определить, что общается действительно с Вами. введите пароль.","from_sender":"от __sender__","Verified_private_conversation_started":"Подтверждено Зашифрованный чат начат.","Unverified_private_conversation_started":"Не подтверждено Зашифрованный чат начат.","Bookmark":"Закладка","Auto-join":"Автоматически входить","Edit_bookmark":"Редактировать закладку","Room_logging_is_disabled":"Журналирование комнаты отключено","Room_is_now_non-anoymous":"Комната теперь не анонимная","Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":"Вы хотите изменить стандартную конфигурацию комнаты?","Default":"Станд.","Change":"Изменить","Send_file":"Отправить файл","setting-explanation-carbon":"С включенным Carbon Copy Ваш XMPP сервер будет отправлять копию каждого входящего сообщения на все подключенные устройства.","setting-explanation-login":"Если эта опция включена, то чат будет начинаться сразу после аутентификации.","setting-explanation-priority":"Если вы подключены к одному аккаунту с нескольких устройств, то XMPP сервер будет доставлять сообщения на клиент с наивысшим приоритетом.","setting-explanation-xmpp":"Эти настройки используются для подключения к XMPP серверу."}},"tr-TR":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null}},"vi-VN":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null}},"zh-TW":{"translation":{"Logging_in":"正在登入…","your_connection_is_unencrypted":"連線沒加密。","your_connection_is_encrypted":"連線有加密。","your_buddy_closed_the_private_connection":"聯絡人關閉了加密連線。","start_private":"開始加密","close_private":"結束加密","your_buddy_is_verificated":"聯絡人已校驗。","you_have_only_a_subscription_in_one_way":"只有單向訂閱。","authentication_query_sent":"驗證要求送出了。","your_message_wasnt_send_please_end_your_private_conversation":"訊息沒送出去。請結束加密的對話。","unencrypted_message_received":"收到沒加密的訊息","not_available":"不存在","no_connection":"沒有連線!","relogin":"重新登入","trying_to_start_private_conversation":"正在試著開始加密的對話!","Verified":"已校驗","Unverified":"未校驗","private_conversation_aborted":"加密的對話中斷了!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"聯絡人把這場加密的對話關掉了!你也應該同樣關掉。","conversation_is_now_verified":"對話現在校驗過了。","authentication_failed":"驗證失敗。","Creating_your_private_key_":"正在產生你的私人金鑰,會花一段時間。","Authenticating_a_buddy_helps_":"聯絡人驗證可以確保跟你說話的是真的那個人。","How_do_you_want_to_authenticate_your_buddy":"你想要怎樣驗證{{bid_name}} ({{bid_jid}})?","Select_method":"選個方式...","Manual":"手動","Question":"問答","Secret":"祕密","To_verify_the_fingerprint_":"要校驗聯絡人的電子指紋,請透過其他可靠的管道跟她/他聯絡,比如說電話。","Your_fingerprint":"你的電子指紋","Buddy_fingerprint":"聯絡人的電子指紋","Close":"關閉","Compared":"比對正確","To_authenticate_using_a_question_":"要用問答來驗證的話,請找一個只有你和聯絡人才知道答案的問題。","Ask":"問題","To_authenticate_pick_a_secret_":"要驗證的話,請找一個只有你和聯絡人知道的祕密。","Compare":"比對","Fingerprints":"電子指紋","Authentication":"驗證","Message":"訊息","Add_buddy":"加聯絡人","rename_buddy":"重新命名聯絡人","delete_buddy":"刪掉聯絡人","Login":"登入","Username":"使用者名稱","Password":"密碼","Cancel":"取消","Connect":"連線","Type_in_the_full_username_":"請打全名,別名可有可無","Alias":"別名","Add":"加入","Subscription_request":"訂閱請求","You_have_a_request_from":"收到聯絡人的請求:","Deny":"拒絕","Approve":"同意","Remove_buddy":"刪除聯絡人","You_are_about_to_remove_":"你就要把{{bid_name}} ({{bid_jid}})從聯絡簿刪掉了。所有相關的對話也都會關掉。","Continue_without_chat":"繼續不聊天","Please_wait":"請等一下","Login_failed":"登入聊天失敗","Sorry_we_cant_authentikate_":"跟聊天伺服器驗證失敗,會不會是密碼打錯了?","Retry":"上一步","clear_history":"清除歷史紀錄","New_message_from":"有新訊息:__name__","Should_we_notify_you_":"以後若有新訊息要通知你嗎?","Please_accept_":"請點上方的「允許」按鈕。","Hide_offline":"隱藏離線聯絡人","Show_offline":"顯示離線聯絡人","About":"關於我","dnd":"別打擾","Mute":"開靜音","Unmute":"關靜音","Subscription":"訂閱狀態","both":"雙向","Status":"狀態","online":"上線","chat":"聊天","away":"離開","xa":"離開很久","offline":"離線","none":"沒有","Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":"收到了一則加密但無法辨認的訊息。","Online":"上線","Chatty":"想聊天","Away":"離開","Extended_away":"離開很久","Offline":"離線","Friendship_request":"聯絡請求","Confirm":"確定","Dismiss":"取消","Remove":"刪掉","Online_help":"線上說明","FN":"全名","N":" ","FAMILY":"姓氏","GIVEN":"名字","NICKNAME":"綽號","URL":"網址","ADR":"位址","STREET":"地址","EXTADD":"更多位址","LOCALITY":"所在地","REGION":"區域","PCODE":"郵遞區號","CTRY":"國家","TEL":"電話","NUMBER":"編號","EMAIL":"電子郵件","USERID":" ","ORG":"團體","ORGNAME":"名稱","ORGUNIT":"單位","TITLE":"職稱","ROLE":"職位","BDAY":"生日","DESC":"簡介","PHOTO":" ","send_message":"發送訊息","get_info":"顯示帳號資訊","Settings":"設定","Priority":"優先度","Save":"儲存","User_settings":"使用者設定","A_fingerprint_":"電子指紋是用來確認跟你說話的是真的那個人。","is":"狀態:","Login_options":"登入選項","BOSH_url":"BOSH 網址","Domain":"網域","Resource":"資源","On_login":"登入啟動","Received_an_unencrypted_message":"收到了一則沒加密的訊息","Sorry_your_buddy_doesnt_provide_any_information":"抱歉,聯絡人沒有提供任何資訊。","Info_about":"帳號資訊:","Authentication_aborted":"驗證中斷。","Authentication_request_received":"驗證請求收到了。","Log_in_without_chat":"登入但不啟用聊天","has_come_online":"上線了","Unknown_sender":"不明傳訊人","Please_allow_access_to_microphone_and_camera":"請點上方的「接受」按鈕來允許我們使用麥克風和相機。","Incoming_call":"來電","from":"只出","Do_you_want_to_accept_the_call_from":"是否要接聽來電:","Reject":"拒絕","Accept":"接受","hang_up":"掛斷","snapshot":"截圖","mute_my_audio":"關掉我的聲音","pause_my_video":"暫停我的影像","fullscreen":"全螢幕","Info":"資料","Local_IP":"本機網路位址","Remote_IP":"遠端網路位址","Local_Fingerprint":"本機電子指紋","Remote_Fingerprint":"遠端電子指紋","Video_call_not_possible":"無法視訊通話。聯絡人不支援視訊。","Start_video_call":"開始視訊通話","Join_chat":"參加聊天","Join":"參加","Room":"聊天室","Nickname":"綽號","left_the_building":"__nickname__離開了大樓","entered_the_room":"__nickname__進入了聊天室","is_now_known_as":"__oldNickname__改名叫做__newNickname__","This_room_is":"聊天室屬性:","muc_hidden":{"keyword":"隱藏","description":"搜尋也找不到"},"muc_membersonly":{"keyword":"限會員","description":"會員才會加入"},"muc_moderated":{"keyword":"有管制","description":"沒被消音的人才能送訊息"},"muc_nonanonymous":{"keyword":"禁匿名","description":"每個參與人都能看到你的 jabber 代碼"},"muc_open":{"keyword":"開放","description":"任何人都能參加"},"muc_passwordprotected":{"keyword":"密碼鎖","description":"要輸入正確的密碼才能加入"},"muc_persistent":{"keyword":"永久性","description":"最後一個參與人都離開了也不會結束"},"muc_public":{"keyword":"公開","description":"搜尋得到"},"muc_semianonymous":{"keyword":"半匿名","description":"只有聊天室管理員才看得到你的 jabber 代碼"},"muc_temporary":{"keyword":"暫時性","description":"最後一個參與人離開了就會結束"},"muc_unmoderated":{"keyword":"沒管制","description":"每個人都可以送訊息"},"muc_unsecured":{"keyword":"沒保護","description":"不需要密碼就能加入"},"Continue":"繼續","Server":"伺服器","Rooms_are_loaded":"聊天室載入完成","Could_load_only":"只能載入__count__間聊天室供輸入自動完成使用","muc_explanation":"請輸入要參加的聊天室名稱,綽號和密碼非必要","You_already_joined_this_room":"你已經參加這間聊天室了","This_room_will_be_closed":"聊天室即將關閉","Room_not_found_":"新聊天室即將開啟","Loading_room_information":"正在載入聊天室資訊","Destroy":"關閉","Leave":"離開","changed_subject_to":"__nickname__把聊天室的標題改成了\"__subject__\"","muc_removed_kicked":"你被踢出聊天室了","muc_removed_info_kicked":"__nickname__被踢出聊天室了","muc_removed_banned":"你被禁止進入聊天室了","muc_removed_info_banned":"__nickname__被禁止進入聊天室了","muc_removed_affiliation":"你因為身份改變而離開聊天室了","muc_removed_info_affiliation":"__nickname__因為身份改變而離開聊天室了","muc_removed_membersonly":"你離開聊天室了,因為聊天室改為只限會員,但你不是會員","muc_removed_info_membersonly":"__nickname__離開聊天室了,因為聊天室改為只限會員,但她/他不是會員","muc_removed_shutdown":"你離開聊天室了,因為多人聊天服務正在關閉中。","Reason":"原因","message_not_send":"訊息因為發生錯誤沒送出去","message_not_send_item-not-found":"訊息沒送出去,因為聊天室不存在了","message_not_send_forbidden":"訊息沒送出去,因為你被消音了","message_not_send_not-acceptable":"訊息沒送出去,因為你不是聊天室的參與人了","This_room_has_been_closed":"聊天室已經關閉了","Room_logging_is_enabled":"聊天室紀錄打開了","A_password_is_required":"需要密碼","You_are_not_on_the_member_list":"你不是會員","You_are_banned_from_this_room":"你被禁止進入聊天室了","Your_desired_nickname_":"這個綽號被用掉了,請換一個","The_maximum_number_":"這間聊天室已經到達使用者數目的上限","This_room_is_locked_":"聊天室上鎖了","You_are_not_allowed_to_create_":"不允許你開新的聊天室","Alert":"警告","Call_started":"通話開始","Call_terminated":"通話結束","Carbon_copy":"副本","Enable":"打開","jingle_reason_busy":"忙線中","jingle_reason_decline":"被拒絕","jingle_reason_success":"被掛斷","Media_failure":"媒體錯誤","No_local_audio_device":"本機沒有音訊設備。","No_local_video_device":"本機沒有視訊設備。","Ok":"好","PermissionDeniedError":"你或你的瀏覽器拒絕了音視訊的權限","Use_local_audio_device":"使用本機音訊設備。","Use_local_video_device":"使用本機視訊設備。","is_":"狀態: __status__","You_received_a_message_from_an_unknown_sender_":"收到了不明人士(__sender__)傳來的訊息。你要打開來看嗎?","Your_roster_is_empty_add_":"好友清單是空的,請加<a>新的聯絡人</a>","onsmp_explanation_question":"聯絡人想要確定她/他是在跟真的你說話。要完成你的驗證,請輸入問題的答案,然後按\"回答\"。","onsmp_explanation_secret":"聯絡人想要確定她/他是在跟真的你說話。要完成你的驗證,請輸入你們之間的祕密。","from_sender":"來自:__sender__","Verified_private_conversation_started":"加密且已校驗的對話開始了。","Unverified_private_conversation_started":"加密但未校驗的對話開始了。","Bookmark":"書籤","Auto-join":"自動參加","Edit_bookmark":"編輯書籤","Room_logging_is_disabled":"聊天室紀錄關掉了","Room_is_now_non-anoymous":"現在聊天室禁止匿名了","Room_is_now_semi-anonymous":"現在聊天室變半匿名了","Do_you_want_to_change_the_default_room_configuration":"你想要改變聊天室的預設配置嗎?","Default":"預設值","Change":"修改","Send_file":"傳送檔案","setting-explanation-carbon":"如果打開副本選項的話,XMPP 伺服器會把每一個收到的訊息,都送一份到這個用戶端程式,即使它不是訊息發送的對象。","setting-explanation-login":"打開這個選項會在登入時同時開啟聊天。","setting-explanation-priority":"如果你用同一個帳號同時登入好幾次的話,XMPP 伺服器會把訊息送給優先度最高的那個用戶端程式。","setting-explanation-xmpp":"這些是用在 XMPP 伺服器連線的選項。"}},"zh":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null}}};
+var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null,"_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"bn-BD":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null,"_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"de":{"translation":{"Logging_in":"Login läuft…","your_connection_is_unencrypted":"Deine Verbindung ist unverschlüsselt.","your_connection_is_encrypted":"Deine Verbindung ist verschlüsselt.","your_buddy_closed_the_private_connection":"Dein Kontakt hat die private Verbindung getrennt.","start_private":"Privat starten","close_private":"Privat abbrechen","your_buddy_is_verificated":"Dein Kontakt ist verifiziert.","you_have_only_a_subscription_in_one_way":"Der Kontaktstatus ist einseitig.","authentication_query_sent":"Authentifizierungsanfrage gesendet.","your_message_wasnt_send_please_end_your_private_conversation":"Deine Nachricht wurde nicht gesendet. Bitte beende die private Konversation.","unencrypted_message_received":"Unverschlüsselte Nachricht erhalten.","not_available":"Nicht verfügbar.","no_connection":"Keine Verbindung.","relogin":"Neu anmelden.","trying_to_start_private_conversation":"Versuche private Konversation zu starten.","Verified":"Verifiziert","Unverified":"Unverifiziert","private_conversation_aborted":"Private Konversation abgebrochen.","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Dein Kontakt hat die private Konversation beendet. Das solltest du auch tun!","conversation_is_now_verified":"Konversation ist jetzt verifiziert","authentication_failed":"Authentifizierung fehlgeschlagen.","Creating_your_private_key_":"Wir werden jetzt deinen privaten Schlüssel generieren. Das kann einige Zeit in Anspruch nehmen.","Authenticating_a_buddy_helps_":"Einen Kontakt zu authentifizieren hilft sicherzustellen, dass die Person mit der du sprichst auch die ist die sie sagt.","How_do_you_want_to_authenticate_your_buddy":"Wie willst du __bid_name__ (<b>__bid_jid__</b>) authentifizieren?","Select_method":"Wähle...","Manual":"Manual","Question":"Frage","Secret":"Geheimnis","To_verify_the_fingerprint_":"Um den Fingerprint zu verifizieren kontaktiere dein Kontakt über einen anderen Kommunikationsweg. Zum Beispiel per Telefonanruf.","Your_fingerprint":"Dein Fingerprint","Buddy_fingerprint":"Sein/Ihr Fingerprint","Close":"Schließen","Compared":"Verglichen","To_authenticate_using_a_question_":"Um die Authentifizierung per Frage durchzuführen, wähle eine Frage bei welcher nur dein Kontakt die Antwort kennt.","Ask":"Frage","To_authenticate_pick_a_secret_":"Um deinen Kontakt zu authentifizieren, wähle ein Geheimnis welches nur deinem Kontakt und dir bekannt ist.","Compare":"Vergleiche","Fingerprints":"Fingerprints","Authentication":"Authentifizierung","Message":"Nachricht","Add_buddy":"Kontakt hinzufügen","rename_buddy":"Kontakt umbenennen","delete_buddy":"Kontakt löschen","Login":"Anmeldung","Username":"Benutzername","Password":"Passwort","Cancel":"Abbrechen","Connect":"Verbinden","Type_in_the_full_username_":"Gib bitte den vollen Benutzernamen und optional ein Alias an.","Alias":"Alias","Add":"Hinzufügen","Subscription_request":"Kontaktanfrage","You_have_a_request_from":"Du hast eine Anfrage von","Deny":"Ablehnen","Approve":"Bestätigen","Remove_buddy":"Kontakt entfernen","You_are_about_to_remove_":"Du bist gerade dabei __bid_name__ (<b>__bid_jid__</b>) von deiner Kontaktliste zu entfernen. Alle Chats werden geschlossen.","Continue_without_chat":"Weiter ohne Chat","Please_wait":"Bitte warten","Login_failed":"Chat-Anmeldung fehlgeschlagen","Sorry_we_cant_authentikate_":"Der Chatserver hat die Anmeldung abgelehnt. Falsches Passwort?","Retry":"Zurück","clear_history":"Lösche Verlauf","New_message_from":"Neue Nachricht von __name__","Should_we_notify_you_":"Sollen wir dich in Zukunft über eingehende Nachrichten informieren, auch wenn dieser Tab nicht im Vordergrund ist?","Please_accept_":"Bitte klick auf den \"Zulassen\" Button oben.","Hide_offline":"Offline ausblenden","Show_offline":"Offline einblenden","About":"Über","dnd":"Beschäftigt","Mute":"Ton aus","Unmute":"Ton an","Subscription":"Bezug","both":"beidseitig","Status":"Status","online":"online","chat":"chat","away":"abwesend","xa":"länger abwesend","offline":"offline","none":"keine","Unknown_instance_tag":"Unbekannter instance tag.","Not_one_of_our_latest_keys":"Nicht einer unserer letzten Schlüssel.","Received_an_unreadable_encrypted_message":"Eine unlesbare verschlüsselte Nachricht erhalten.","Online":"Online","Chatty":"Gesprächig","Away":"Abwesend","Extended_away":"Länger abwesend","Offline":"Offline","Friendship_request":"Kontaktanfrage","Confirm":"Bestätigen","Dismiss":"Ablehnen","Remove":"Löschen","Online_help":"Online Hilfe","FN":"Name","N":" ","FAMILY":"Familienname","GIVEN":"Vorname","NICKNAME":"Spitzname","URL":"URL","ADR":"Adresse","STREET":"Straße","EXTADD":"Zusätzliche Adresse","LOCALITY":"Ortschaft","REGION":"Region","PCODE":"Postleitzahl","CTRY":"Land","TEL":"Telefon","NUMBER":"Nummer","EMAIL":"E-Mail","USERID":" ","ORG":"Organisation","ORGNAME":"Name","ORGUNIT":"Abteilung","TITLE":"Titel","ROLE":"Rolle","BDAY":"Geburtstag","DESC":"Beschreibung","PHOTO":" ","send_message":"Sende Nachricht","get_info":"Benutzerinformationen","Settings":"Einstellungen","Priority":"Priorität","Save":"Speichern","User_settings":"Benutzereinstellungen","A_fingerprint_":"Ein Fingerabdruck wird dazu benutzt deinen Gesprächspartner zu identifizieren.","is":"ist","Login_options":"Anmeldeoptionen","BOSH_url":"BOSH url","Domain":"Domain","Resource":"Ressource","On_login":"Beim Anmelden","Received_an_unencrypted_message":"Unverschlüsselte Nachricht empfangen","Sorry_your_buddy_doesnt_provide_any_information":"Dein Kontakt stellt leider keine Informationen bereit.","Info_about":"Info über","Authentication_aborted":"Authentifizierung abgebrochen.","Authentication_request_received":"Authentifizierungsanfrage empfangen.","Log_in_without_chat":"Anmelden ohne Chat","has_come_online":"ist online gekommen","Unknown_sender":"Unbekannter Sender","Please_allow_access_to_microphone_and_camera":"Bitte klick auf den \"Zulassen\" Button oben, um den Zugriff auf Kamera und Mikrofon zu erlauben.","Incoming_call":"Eingehender Anruf","from":"von","Do_you_want_to_accept_the_call_from":"Möchtest Du den Anruf annehmen von","Reject":"Ablehnen","Accept":"Annehmen","hang_up":"Auflegen","snapshot":"Schnappschuss","mute_my_audio":"Mein Ton aus","pause_my_video":"Mein Video pausieren","fullscreen":"Vollbild","Info":"Info","Local_IP":"Lokale IP","Remote_IP":"Remote IP","Local_Fingerprint":"Lokaler Fingerprint","Remote_Fingerprint":"Remote Fingerprint","Video_call_not_possible":"Videoanruf nicht verfügbar. Dein Gesprächspartner unterstützt keine Videotelefonie.","Start_video_call":"Starte Videoanruf","Join_chat":"Gruppe beitreten","Join":"Betreten","Room":"Gruppe","Nickname":"Nickname","left_the_building":"__nickname__ hat die Gruppe verlassen","entered_the_room":"__nickname__ ist der Gruppe beigetreten","is_now_known_as":"__oldNickname__ ist nun unter __newNickname__ bekannt","This_room_is":"Diese Gruppe ist","muc_hidden":{"keyword":"versteckt","description":"kann durch die Suche nicht gefunden werden"},"muc_membersonly":{"keyword":"nur für Mitglieder","description":"du musst auf der Mitgliederliste stehen"},"muc_moderated":{"keyword":"moderiert","description":"Nur Personen die \"Mitspracherecht\" haben dürfen Nachrichten senden"},"muc_nonanonymous":{"keyword":"nicht anonym","description":"deine Jabber ID wird für alle Mitglieder sichtbar sein"},"muc_open":{"keyword":"offen","description":"jeder darf dieser Gruppe beitreten"},"muc_passwordprotected":{"keyword":"passwortgeschützt","description":"du benötigst das korrekte Passwort"},"muc_persistent":{"keyword":"permanent","description":"wird nicht geschlossen, wenn das letzte Mitglied die Gruppe verlässt"},"muc_public":{"keyword":"öffentlich","description":"kann durch die Suche gefunden werden"},"muc_semianonymous":{"keyword":"teilweise anonym","description":"deine Jabber ID wird nur für die Gruppen Administratoren sichtbar sein"},"muc_temporary":{"keyword":"temporär","description":"wird geschlossen, wenn das letzte Mitglied die Gruppe verlässt"},"muc_unmoderated":{"keyword":"nicht moderiert","description":"jeder darf Nachrichten senden"},"muc_unsecured":{"keyword":"ungesichert","description":"es wird kein Passwort benötigt"},"Continue":"Weiter","Server":"Server","Rooms_are_loaded":"Gruppen werden geladen","Could_load_only":"Es konnten nur __count__ Gruppen für die Autovervollständigung geladen werden","muc_explanation":"Bitte trage den Gruppennamen und optional ein Nickname und Passwort ein um einer Gruppe beizutreten","You_already_joined_this_room":"Du bist dieser Gruppe bereits beigetreten","This_room_will_be_closed":"Diese Gruppe wird geschlossen","Room_not_found_":"Es wird eine neue Gruppe erstellt","Loading_room_information":"Informationen über Gruppe werden geladen","Destroy":"Auflösen","Leave":"Verlassen","changed_subject_to":"__nickname__ hat das Thema auf __subject__ geändert","muc_removed_kicked":"Du wurdest aus der Gruppe entfernt","muc_removed_info_kicked":"__nickname__ wurde aus der Gruppe entfernt","muc_removed_banned":"Du wurdest aus der Gruppe ausgeschlossen","muc_removed_info_banned":"__nickname__ wurde aus der Gruppe ausgeschlossen","muc_removed_affiliation":"Du wurdest aus der Gruppe entfernt wegen einer Änderung deines Mitgliedstatus","muc_removed_info_affiliation":"__nickname__ wurde aus der Gruppe entfernt wegen einer Änderung seines Mitgliedstatus","muc_removed_membersonly":"Diese Gruppe erlaubt jetzt nur noch eingetragene Mitglieder und da du nicht dazugehörst, wurdest du aus der Gruppen entfernt","muc_removed_info_membersonly":"Diese Gruppe erlaubt jetzt nur noch eingetragene Mitglieder und __nickname__ gehört nicht dazu, daher wurde er aus der Gruppe entfernt","muc_removed_shutdown":"Du wurdest aus der Gruppe entfernt, da der MUC Server heruntergefahren wird","Reason":"Grund","message_not_send":"Deine Nachricht wurde aufgrund eines Fehlers nicht versandt","message_not_send_item-not-found":"Deine Nachricht wurde nicht versandt, da der Raum nicht mehr existiert","message_not_send_forbidden":"Deine Nachricht wurde nicht versandt, da du kein \"Mitspracherecht\" hast","message_not_send_not-acceptable":"Deine Nachricht wurde nicht versandt, da du kein Mitglied dieser Gruppe bist","This_room_has_been_closed":"Diese Gruppe wurde geschlossen","Room_logging_is_enabled":"Gesprächsverlauf kann öffentlich einsehbar sein","A_password_is_required":"Es wird ein Passwort benötigt","You_are_not_on_the_member_list":"Du bist kein eingetragenes Mitglied","You_are_banned_from_this_room":"Du wurdest von dieser Gruppe ausgeschlossen","Your_desired_nickname_":"Dein gewünschter Nickname wird bereits verwendet. Bitte wähle einen anderen.","The_maximum_number_":"Die maximale Anzahl der Mitglieder wurde erreicht.","This_room_is_locked_":"Diese Gruppe ist gesperrt","You_are_not_allowed_to_create_":"Du darfst keine neue Gruppe erstellen","Alert":"Alarm","Call_started":"Anruf gestarted","Call_terminated":"Anruf beendet","Carbon_copy":"Kopie","Enable":"Aktivieren","jingle_reason_busy":"beschäftigt","jingle_reason_decline":"abgelehnt","jingle_reason_success":"aufgelegt","Media_failure":"Gerätefehler","No_local_audio_device":"Kein eigenes Audio Gerät","No_local_video_device":"Keine eigene Webcam","Ok":"Ok","PermissionDeniedError":"Du oder dein Browser haben die Audio/Video Berechtigung verweigert","Use_local_audio_device":"Nutze eigenes Audio Gerät","Use_local_video_device":"Benutze eigene Webcam","is_":"ist __status__","You_received_a_message_from_an_unknown_sender_":"Du hast eine Nachricht von einem unbekannten Sender erhalten (__sender__) Möchtest du sie sehen?","Your_roster_is_empty_add_":"Deine Kontaktliste ist leer, füge einen neuen Kontakt <a>hinzu</a>","onsmp_explanation_question":"Dein Kontakt versucht herauszufinden ob er wirklich mit dir redet. Um dich gegenüber deinem Kontakt zu verifizieren gib die Antwort ein und klick auf Antworten.","onsmp_explanation_secret":"Dein Kontakt versucht herauszufinden ob er wirklich mit dir redet. Um dich gegenüber deinem Kontakt zu verifizieren gib das Geheimnis ein.","from_sender":"von __sender__","Verified_private_conversation_started":"Verifizierte private Konversation gestartet.","Unverified_private_conversation_started":"Unverifizierte private Konversation gestartet.","Bookmark":"Lesezeichen","Auto-join":"Automatisch beitreten","Edit_bookmark":"Lesezeichen bearbeiten","Room_logging_is_disabled":"Gruppen Log ist deaktiviert","Room_is_now_non-anoymous":"Gruppe ist jetzt nicht anonym","Room_is_now_semi-anonymous":"Gruppe ist jetzt semi-anonym","Do_you_want_to_change_the_default_room_configuration":"Möchtest du die Gruppenkonfiguration ändern?","Default":"Standard","Change":"Ändern","Send_file":"Datei senden","setting-explanation-carbon":"Wenn Kopien aktiviert sind, werden alle eingehenden Nachrichten zu allen angemeldeten Clients gesendet.","setting-explanation-login":"Wenn diese Option aktiviert ist, wird der Chat beim anmelden automatisch gestartet.","setting-explanation-priority":"Wenn du mit deinem XMPP Konto mehrfach angemeldet bist, werden Nachrichten zu dem Client mit der höchsten Priorität zugestellt.","setting-explanation-xmpp":"Diese Optionen werden für die Verbindung zum XMPP server genutzt.","_is_composing":" tippt gerade...","_are_composing":" tippen gerade...","Chat_state_notifications":"Statusbenachrichtigungen","setting-explanation-chat-state":"Möchtest Benachrichtigungen senden und erhalten wenn du oder dein Kontakt Nachrichten tippt?","Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":"Schließe alle"}},"el":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null,"_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"en":{"translation":{"Logging_in":"Logging in…","your_connection_is_unencrypted":"Your connection is unencrypted.","your_connection_is_encrypted":"Your connection is encrypted.","your_buddy_closed_the_private_connection":"Your contact closed the private connection.","start_private":"Start private","close_private":"Close private","your_buddy_is_verificated":"Your contact is verified.","you_have_only_a_subscription_in_one_way":"You only have a one-way subscription.","authentication_query_sent":"Authentication query sent.","your_message_wasnt_send_please_end_your_private_conversation":"Your message was not sent. Please end your private conversation.","unencrypted_message_received":"Unencrypted message received","not_available":"Not available","no_connection":"No connection!","relogin":"relogin","trying_to_start_private_conversation":"Trying to start private conversation!","Verified":"Verified","Unverified":"Unverified","private_conversation_aborted":"Private conversation aborted!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Your contact closed the private conversation! You should do the same.","conversation_is_now_verified":"Conversation is now verified.","authentication_failed":"Authentication failed.","Creating_your_private_key_":"Creating your private key; this may take a while.","Authenticating_a_buddy_helps_":"Authenticating a contact helps ensure that the person you are talking to is really the one they claim to be.","How_do_you_want_to_authenticate_your_buddy":"How do you want to authenticate __bid_name__ (<b>__bid_jid__</b>)?","Select_method":"Select method...","Manual":"Manual","Question":"Question","Secret":"Secret","To_verify_the_fingerprint_":"To verify the fingerprint, contact your contact via some other trustworthy channel, such as the telephone.","Your_fingerprint":"Your fingerprint","Buddy_fingerprint":"Contact fingerprint","Close":"Close","Compared":"Compared","To_authenticate_using_a_question_":"To authenticate using a question, pick a question whose answer is known only you and your contact.","Ask":"Ask","To_authenticate_pick_a_secret_":"To authenticate, pick a secret known only to you and your contact.","Compare":"Compare","Fingerprints":"Fingerprints","Authentication":"Authentication","Message":"Message","Add_buddy":"Add contact","rename_buddy":"rename contact","delete_buddy":"delete contact","Login":"Login","Username":"Username","Password":"Password","Cancel":"Cancel","Connect":"Connect","Type_in_the_full_username_":"Type in the full username and an optional alias.","Alias":"Alias","Add":"Add","Subscription_request":"Subscription request","You_have_a_request_from":"You have a request from","Deny":"Deny","Approve":"Approve","Remove_buddy":"Remove contact","You_are_about_to_remove_":"You are about to remove __bid_name__ (<b>__bid_jid__</b>) from your contact list. All related chats will be closed.","Continue_without_chat":"Continue without chat","Please_wait":"Please wait","Login_failed":"Chat login failed","Sorry_we_cant_authentikate_":"Authentication failed with the chat server. Maybe the password is wrong?","Retry":"Back","clear_history":"Clear history","New_message_from":"New message from __name__","Should_we_notify_you_":"Should we notify you about new messages in the future?","Please_accept_":"Please click the \"Allow\" button at the top.","Hide_offline":"Hide offline contacts","Show_offline":"Show offline contacts","About":"About","dnd":"Do Not Disturb","Mute":"Mute","Unmute":"Unmute","Subscription":"Subscription","both":"both","Status":"Status","online":"online","chat":"chat","away":"away","xa":"extended away","offline":"offline","none":"none","Unknown_instance_tag":"Unknown instance tag.","Not_one_of_our_latest_keys":"Not one of our latest keys.","Received_an_unreadable_encrypted_message":"Received an unreadable encrypted message.","Online":"Online","Chatty":"Chatty","Away":"Away","Extended_away":"Extended away","Offline":"Offline","Friendship_request":"Contact request","Confirm":"Confirm","Dismiss":"Dismiss","Remove":"Remove","Online_help":"Online help","FN":"Full name","N":" ","FAMILY":"Family name","GIVEN":"Given name","NICKNAME":"Nickname","URL":"URL","ADR":"Address","STREET":"Street Address","EXTADD":"Extended Address","LOCALITY":"Locality","REGION":"Region","PCODE":"Postal Code","CTRY":"Country","TEL":"Telephone","NUMBER":"Number","EMAIL":"Email","USERID":" ","ORG":"Organization","ORGNAME":"Name","ORGUNIT":"Unit","TITLE":"Job title","ROLE":"Role","BDAY":"Birthday","DESC":"Description","PHOTO":" ","send_message":"Send message","get_info":"Show information","Settings":"Settings","Priority":"Priority","Save":"Save","User_settings":"User settings","A_fingerprint_":"A fingerprint is used to make sure that the person you are talking to is who he or she is saying.","is":"is","Login_options":"Login options","BOSH_url":"BOSH URL","Domain":"Domain","Resource":"Resource","On_login":"On login","Received_an_unencrypted_message":"Received an unencrypted message","Sorry_your_buddy_doesnt_provide_any_information":"Sorry, your contact does not provide any information.","Info_about":"Info about","Authentication_aborted":"Authentication aborted.","Authentication_request_received":"Authentication request received.","Log_in_without_chat":"Log in without chat","has_come_online":"has come online","Unknown_sender":"Unknown sender","Please_allow_access_to_microphone_and_camera":"Please click the \"Allow\" button at the top, to allow access to microphone and camera.","Incoming_call":"Incoming call","from":"from","Do_you_want_to_accept_the_call_from":"Do you want to accept the call from","Reject":"Reject","Accept":"Accept","hang_up":"hang up","snapshot":"snapshot","mute_my_audio":"mute my audio","pause_my_video":"pause my video","fullscreen":"fullscreen","Info":"Info","Local_IP":"Local IP","Remote_IP":"Remote IP","Local_Fingerprint":"Local fingerprint","Remote_Fingerprint":"Remote fingerprint","Video_call_not_possible":"Video call not possible. Your contact does not support video calls.","Start_video_call":"Start video call","Join_chat":"Join chat","Join":"Join","Room":"Room","Nickname":"Nickname","left_the_building":"__nickname__ left the building","entered_the_room":"__nickname__ entered the room","is_now_known_as":"__oldNickname__ is now known as __newNickname__","This_room_is":"This room is","muc_hidden":{"keyword":"hidden","description":"can not be found through search"},"muc_membersonly":{"keyword":"members-only","description":"you need to be on the member list"},"muc_moderated":{"keyword":"moderated","description":"only persons with \"voice\" are allowed to send messages"},"muc_nonanonymous":{"keyword":"non-anonymous","description":"your jabber id is exposed to all other occupants"},"muc_open":{"keyword":"open","description":"everyone is allowed to join"},"muc_passwordprotected":{"keyword":"password-protected","description":"you need to provide the correct password"},"muc_persistent":{"keyword":"persistent","description":"will not be destroyed if the last occupant left"},"muc_public":{"keyword":"public","description":"can be found through search"},"muc_semianonymous":{"keyword":"semi-anonymous","description":"your jabber id is only exposed to room admins"},"muc_temporary":{"keyword":"temporary","description":"will be destroyed if the last occupant left"},"muc_unmoderated":{"keyword":"unmoderated","description":"everyone is allowed to send messages"},"muc_unsecured":{"keyword":"unsecured","description":"you need no password to enter"},"Continue":"Continue","Server":"Server","Rooms_are_loaded":"Rooms are loaded","Could_load_only":"Could load only __count__ rooms for autocomplete","muc_explanation":"Please enter room name and optional a nickname and password to join a chat","You_already_joined_this_room":"You already joined this room","This_room_will_be_closed":"This room will be closed","Room_not_found_":"A new room will be created","Loading_room_information":"Loading room information","Destroy":"Destroy","Leave":"Leave","changed_subject_to":"__nickname__ changed the room subject to \"__subject__\"","muc_removed_kicked":"You have been kicked from the room","muc_removed_info_kicked":"__nickname__ has been kicked from the room","muc_removed_banned":"You have been banned from the room","muc_removed_info_banned":"__nickname__ has been banned from the room","muc_removed_affiliation":"You have been removed from the room, because of an affiliation change","muc_removed_info_affiliation":"__nickname__ has been removed from the room, because of an affiliation change","muc_removed_membersonly":"You have been removed from the room, because the room has been changed to members-only and you are no member","muc_removed_info_membersonly":"__nickname__ has been removed from the room, because the room has been changed to members-only and you are no member","muc_removed_shutdown":"You have been removed from the room, because the MUC service is being shut down","Reason":"Reason","message_not_send":"Your message was not send because of an error","message_not_send_item-not-found":"Your message was not send because this room does not exist","message_not_send_forbidden":"Your message was not send because you have no voice in this room","message_not_send_not-acceptable":"Your message was not send because you are no occupant of this room","This_room_has_been_closed":"This room has been closed","Room_logging_is_enabled":"Room logging is enabled","A_password_is_required":"A password is required","You_are_not_on_the_member_list":"You are not on the member list","You_are_banned_from_this_room":"You are banned from this room","Your_desired_nickname_":"Your desired nickname is already in use. Please choose another","The_maximum_number_":"The maximum number of user is reached in this room","This_room_is_locked_":"This room is locked","You_are_not_allowed_to_create_":"You are not allowed to create a room","Alert":"Alert","Call_started":"Call started","Call_terminated":"Call terminated","Carbon_copy":"Carbon copy","Enable":"Enable","jingle_reason_busy":"busy","jingle_reason_decline":"decline","jingle_reason_success":"hung up","Media_failure":"Media failure","No_local_audio_device":"No local audio device.","No_local_video_device":"No local video device.","Ok":"Ok","PermissionDeniedError":"You or your browser denied media permission","Use_local_audio_device":"Use local audio device.","Use_local_video_device":"Use local video device.","is_":"is __status__","You_received_a_message_from_an_unknown_sender_":"You received a message from an unknown sender (__sender__) Do you want to display them?","Your_roster_is_empty_add_":"Your roster is empty, add a <a>new contact</a>","onsmp_explanation_question":"You contact is attempting to determine if they are really talking to you. To authenticate to your contact, enter the answer and click Answer.","onsmp_explanation_secret":"You contact is attempting to determine if they are really talking to you. To authenticate to your contact, enter the secret.","from_sender":"from __sender__","Verified_private_conversation_started":"Verified Private conversation started.","Unverified_private_conversation_started":"Unverified Private conversation started.","Bookmark":"Bookmark","Auto-join":"Auto-join","Edit_bookmark":"Edit bookmark","Room_logging_is_disabled":"Room logging is disabled","Room_is_now_non-anoymous":"Room is now non-anonymous","Room_is_now_semi-anonymous":"Room is now semi-anonymous","Do_you_want_to_change_the_default_room_configuration":"Do you want to change the default room configuration?","Default":"Default","Change":"Change","Send_file":"Send file","setting-explanation-carbon":"With enabled carbon copy your XMPP server will send a copy of every incoming message for you to this client even if it was not addressed to it.","setting-explanation-login":"If this option is enabled, the chat will start on login.","setting-explanation-priority":"If you are logged in multiple times with the same account, your XMPP server will deliver messages to the client with the highest priority.","setting-explanation-xmpp":"These options are used to connect to the XMPP server.","_is_composing":" is composing...","_are_composing":" are composing...","Chat_state_notifications":"Chat state notifications","setting-explanation-chat-state":"Do you want to send and receive chat state notifications, like someone starts or stops composing a message?","Share_screen":"Share screen","Incoming_stream":"Incoming stream","Stream_started":"Stream started","HTTPS_REQUIRED":"This action requires an encrypted connection.","EXTENSION_UNAVAILABLE":"You need a browser extension/addon.","UNKNOWN_ERROR":"An unknown error occured.","Install_extension":"Please install the extension in order to use screen sharing: ","Connection_accepted":"Connection accepted","Stream_terminated":"Stream terminated","Close_all":"Close all","Notification":"Notification"}},"es":{"translation":{"Logging_in":"Por favor, espere...","your_connection_is_unencrypted":"Su conexión no está cifrada.","your_connection_is_encrypted":"Su conexión está cifrada.","your_buddy_closed_the_private_connection":"Su amigo ha cerrado la conexión privada.","start_private":"Iniciar privado","close_private":"Cerrar privado","your_buddy_is_verificated":"Tu amigo está verificado.","you_have_only_a_subscription_in_one_way":"Solo tienes una suscripción de un modo.","authentication_query_sent":"Consulta de verificación enviada.","your_message_wasnt_send_please_end_your_private_conversation":"Su mensaje no fue enviado. Por favor, termine su conversación privada.","unencrypted_message_received":"Mensaje no cifrado recibido:","not_available":"No disponible","no_connection":"¡Sin conexión!","relogin":"iniciar sesión nuevamente","trying_to_start_private_conversation":"¡Intentando iniciar una conversación privada!","Verified":"Verificado","Unverified":"No verificado","private_conversation_aborted":"¡Conversación privada abortada!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"¡Su amigo cerró la conversación privada! Usted debería hacer lo mismo.","conversation_is_now_verified":"La conversación es ahora verificada.","authentication_failed":"Falló la verificación.","Creating_your_private_key_":"Ahora vamos a crear su clave privada. Esto puede tomar algún tiempo.","Authenticating_a_buddy_helps_":"Autenticación de un amigo ayuda a garantizar que la persona que está hablando es quien él o ella está diciendo.","How_do_you_want_to_authenticate_your_buddy":"¿Cómo desea autenticar __bid_name__ (<b>__bid_jid__</b>)?","Select_method":"Escoja un método...","Manual":"Manual","Question":"Pregunta","Secret":"Secreto","To_verify_the_fingerprint_":"Para verificar la firma digital, póngase en contacto con su amigo a través de algún otro canal autenticado, como el teléfono.","Your_fingerprint":"Tu firma digital","Buddy_fingerprint":"firma digital de tu amigo","Close":"Cerrar","Compared":"Comparado","To_authenticate_using_a_question_":"Para autenticar mediante una pregunta, elegid una pregunta cuya respuesta se conoce solo usted y su amigo.","Ask":"Preguntar","To_authenticate_pick_a_secret_":"Para autenticar, elija un secreto conocido solo por usted y su amigo.","Compare":"Comparar","Fingerprints":"Firmas digitales","Authentication":"Autenticación","Message":"Mensaje","Add_buddy":"Añadir amigo","rename_buddy":"renombrar amigo","delete_buddy":"eliminar amigo","Login":"Iniciar Sesión","Username":"Usuario","Password":"Contraseña","Cancel":"Cancelar","Connect":"Conectar","Type_in_the_full_username_":"Escriba el usuario completo y un alias opcional.","Alias":"Alias","Add":"Añadir","Subscription_request":"Solicitud de suscripción","You_have_a_request_from":"Tienes una petición de","Deny":"Rechazar","Approve":"Aprobar","Remove_buddy":"Eliminar amigo","You_are_about_to_remove_":"Vas a eliminar a __bid_name__ (<b>__bid_jid__</b>) de tu lista de amigos. Todas las conversaciones relacionadas serán cerradas.","Continue_without_chat":"Continuar","Please_wait":"Espere por favor","Login_failed":"Fallo el inicio de sesión","Sorry_we_cant_authentikate_":"Lo sentimos, no podemos autentificarlo en nuestro servidor de chat. ¿Tal vez la contraseña es incorrecta?","Retry":"Reintentar","clear_history":"Borrar el historial","New_message_from":"Nuevo mensaje de __name__","Should_we_notify_you_":"¿Debemos notificarle sobre nuevos mensajes en el futuro?","Please_accept_":"Por favor, haga clic en el botón \"Permitir\" en la parte superior.","Hide_offline":"Ocultar contactos desconectados","Show_offline":"Mostrar contactos desconectados","About":"Acerca de","dnd":"No Molestar","Mute":"Desactivar sonido","Unmute":"Activar sonido","Subscription":"Suscripción","both":"ambos","Status":"Estado","online":"en línea","chat":"chat","away":"ausente","xa":"más ausente","offline":"desconectado","none":"nadie","Unknown_instance_tag":"Etiqueta de instancia desconocida.","Not_one_of_our_latest_keys":"No una de nuestras última claves.","Received_an_unreadable_encrypted_message":"Se recibió un mensaje cifrado ilegible.","Online":"En linea","Chatty":"Hablador","Away":"Ausente","Extended_away":"Más ausente","Offline":"Desconectado","Friendship_request":"Solicitud de amistad","Confirm":"Confirmar","Dismiss":"Rechazar","Remove":"Eliminar","Online_help":"Ayuda en línea","FN":"Nombre completo ","N":" ","FAMILY":"Apellido","GIVEN":"Nombre","NICKNAME":"Apodo","URL":"URL","ADR":"Dirección","STREET":"Calle","EXTADD":"Dirección extendida","LOCALITY":"Población","REGION":"Región","PCODE":"Código postal","CTRY":"País","TEL":"Teléfono","NUMBER":"Número","EMAIL":"Correo electrónico","USERID":" ","ORG":"Organización","ORGNAME":"Nombre","ORGUNIT":"Departamento","TITLE":"Título","ROLE":"Rol","BDAY":"Cumpleaños","DESC":"Descripción","PHOTO":" ","send_message":"mandar un texto","get_info":"obtener información","Settings":"Ajustes","Priority":"Prioridad","Save":"Guardar","User_settings":"Configuración de usuario","A_fingerprint_":"La huella digital se utiliza para que puedas estar seguro que la persona con la que estas hablando es quien realmente dice ser","is":"es","Login_options":"Opciones de login","BOSH_url":"BOSH url","Domain":"Dominio","Resource":"Recurso","On_login":"Iniciar sesión","Received_an_unencrypted_message":"Recibe un mensaje no cifrado","Sorry_your_buddy_doesnt_provide_any_information":"Lo sentimos, su amigo no provee ninguna información.","Info_about":"Info acerca de","Authentication_aborted":"Autenticación abortada","Authentication_request_received":"Pedido de autenticación recibido.","Log_in_without_chat":"Ingresar sin chat","has_come_online":"se ha conectado","Unknown_sender":"Remitente desconocido","Please_allow_access_to_microphone_and_camera":"Por favor, permitir el acceso al micrófono y la cámara.","Incoming_call":"Llamada entrante","from":"de","Do_you_want_to_accept_the_call_from":"Desea aceptar la llamada de","Reject":"Rechazar","Accept":"Aceptar","hang_up":"colgar","snapshot":"instantánea","mute_my_audio":"silenciar mi audio","pause_my_video":"pausar mi vídeo","fullscreen":"pantalla completa","Info":"Info","Local_IP":"IP local","Remote_IP":"IP remota","Local_Fingerprint":"Firma digital local","Remote_Fingerprint":"Firma digital remota","Video_call_not_possible":"Llamada de vídeo no es posible","Start_video_call":"Iniciar llamada de vídeo","Join_chat":"Unirse al chat","Join":"Unirse","Room":"Sala","Nickname":"Alias","left_the_building":"__nickname__ dejó el edificio","entered_the_room":"__nickname__ entró en la sala","is_now_known_as":"__oldNickname__ ahora es conocido como __newNickname__","This_room_is":"Esta sala es","muc_hidden":{"keyword":"oculta","description":"no se encontró mediante la búsqueda"},"muc_membersonly":{"keyword":"miembros solo","description":"necesitas estar en la lista de miembros"},"muc_moderated":{"keyword":"moderada","description":"solo personas con \"voice\" están permitidas para mandar mensajes"},"muc_nonanonymous":{"keyword":"no anónima","description":"tu id de jabber es expuesta al resto de ocupantes"},"muc_open":{"keyword":"abierta","description":"todo el mundo puede unirse"},"muc_passwordprotected":{"keyword":"protegida por contraseña","description":"necesitas dar la contraseña correcta"},"muc_persistent":{"keyword":"persistente","description":"no será destruida si el último ocupante sale"},"muc_public":{"keyword":"pública","description":"puede ser encontrada mediante la búsqueda"},"muc_semianonymous":{"keyword":"semi-anónima","description":"tu id de jabber es expuesta a los administradores de la sala"},"muc_temporary":{"keyword":"temporal","description":"será destruida si el último ocupante sale"},"muc_unmoderated":{"keyword":"no moderada","description":"todo el mundo puede enviar mensajes"},"muc_unsecured":{"keyword":"sin asegurar","description":"no necesitas contraseña para entrar"},"Continue":"Continuar","Server":"Servidor","Rooms_are_loaded":"Las salas han sido cargadas","Could_load_only":"Se cargaron solo __count__ salas para el autocompletado","muc_explanation":"Por favor introduce el nombre de la sala, un alias opcional y una contraseña para unirse al chat","You_already_joined_this_room":"Ya te has unido a esta sala","This_room_will_be_closed":"Esta sale será cerrada","Room_not_found_":"Sala no encontrada","Loading_room_information":"Cargando información de la sala","Destroy":"Destruir","Leave":"Abandonar","changed_subject_to":"__nickname__ cambió el asunto de la sala a \"__subject__\"","muc_removed_kicked":"Has sido echado de la sala","muc_removed_info_kicked":"__nickname__ ha sido echado de la sala","muc_removed_banned":"Has sido expulsado de la sala","muc_removed_info_banned":"__nickname__ ha sido expulsado","muc_removed_affiliation":"Has sido eliminado de la sala debido a un cambio en la afiliación","muc_removed_info_affiliation":"__nickname__ ha sido eliminado de la sala debido a un cambio en la afiliación","muc_removed_membersonly":"Has sido eliminado de la sala debido a que la sala ha sido cambiada a miembros solo y tú no eres un miembro","muc_removed_info_membersonly":"__nickname__ ha sido eliminado de la sala debido a que la sala ha sido cambiada a miembros solo y tú no eres un miembro","muc_removed_shutdown":"Has sido eliminado de la sala debido a que el servicio MUC está siendo apagado","Reason":"Razón","message_not_send":"Tu mensaje no fue enviado debido a un error","message_not_send_item-not-found":"Tu mensaje no fue enviado debido a que esta sala no existe","message_not_send_forbidden":"Tu mensaje no fue enviado debido a que no tienes voz en esta sala","message_not_send_not-acceptable":"Tu mensaje no fue enviado debido a que no eres un ocupante de esta sala ","This_room_has_been_closed":"Esta sala ha sido cerrada","Room_logging_is_enabled":"Log de sala está habilitado","A_password_is_required":"Se requiere una contraseña","You_are_not_on_the_member_list":"No estás en la lista de miembros","You_are_banned_from_this_room":"Estás expulsado de esta sala","Your_desired_nickname_":"Tu alias ya está en uso. Por favor elige otro","The_maximum_number_":"El máximo número de usuarios ha sido alcanzado en esta sala","This_room_is_locked_":"Esta sala está bloqueada","You_are_not_allowed_to_create_":"No tienes permiso para crear una sala","Alert":"Alerta","Call_started":"Llamada empezada","Call_terminated":"Llamada terminada","Carbon_copy":"Calco","Enable":"Activar","jingle_reason_busy":"ocupado","jingle_reason_decline":"rechazar","jingle_reason_success":"colgar","Media_failure":"Fallo multimedia","No_local_audio_device":"No hay dispositivo de audio local","No_local_video_device":"No hay dispositivo de vídeo local","Ok":"Ok","PermissionDeniedError":"Tú o tu navegador denegaron el permiso de audio/vídeo","Use_local_audio_device":"Usar dispositivo de audio local","Use_local_video_device":"Usar dispositivo de vídeo","is_":"es __status__","You_received_a_message_from_an_unknown_sender_":"Ha recibido un mensaje de un remitente desconocido (__sender__) ¿Quiere mostrarlos?","Your_roster_is_empty_add_":"Tu lista de amigos esta vacía, añadir un <a>nuevo amigo</a>","onsmp_explanation_question":"Tu amigo está tratando de determinar si él o ella está realmente hablando con usted. Para autenticar a su amigo, introduce la respuesta y haga clic en Contestar.","onsmp_explanation_secret":"Tu amigo está tratando de determinar si él o ella está realmente hablando con usted. Para autenticar a su amigo, especifique el secreto.","from_sender":"de __sender__","Verified_private_conversation_started":"Verificado se inició una conversación privada.","Unverified_private_conversation_started":"No verificado se inició una conversación privada.","Bookmark":"Favorito","Auto-join":"Auto-unir","Edit_bookmark":"Editar favorito","Room_logging_is_disabled":"Log de sala está deshabilitado","Room_is_now_non-anoymous":"La sala es ahora no anónima","Room_is_now_semi-anonymous":"La sale es ahora semi-anónima","Do_you_want_to_change_the_default_room_configuration":"¿Quieres cambiar la configuración por defecto de la sala?","Default":"Por defecto","Change":"Cambiar","Send_file":"Enviar archivo","setting-explanation-carbon":"Con el Calco habilitado tu servidor XMPP enviará una copia de cada mensaje entrante dirigido a ti a este cliente incluso si no estaba siendo enviado a él","setting-explanation-login":"Si esta opción está habilitada, el chat empezará al inicio de sesión","setting-explanation-priority":"Si tú has iniciado sesión varias veces con la misma cuenta, tu servidor XMPP enviará los mensajes al cliente con la mayor prioridad","setting-explanation-xmpp":"Estas opciones son usadas para conectar con el servidor XMPP","_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"fi":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null,"_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"fr":{"translation":{"Logging_in":"Connexion...","your_connection_is_unencrypted":"Connexion non chiffrée.","your_connection_is_encrypted":"Connexion chiffrée.","your_buddy_closed_the_private_connection":"Votre contact a fermé la connexion privée.","start_private":"Démarrer une conversation privée","close_private":"Clôturer une conversation privée","your_buddy_is_verificated":"Votre contact est vérifié.","you_have_only_a_subscription_in_one_way":"Vous ne pouvez souscrire qu'une fois.","authentication_query_sent":"Requête d’authentification envoyée.","your_message_wasnt_send_please_end_your_private_conversation":"Votre message n'a pas été envoyé. Veuillez terminer votre conversation privée.","unencrypted_message_received":"Message non chiffré reçu","not_available":"Non disponible","no_connection":"Pas de connexion !","relogin":"Re-connexion","trying_to_start_private_conversation":"Essai de démarrage d'une conversation privée !","Verified":"Vérifié","Unverified":"Non vérifié","private_conversation_aborted":"Conversation privée interrompue !","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Votre contact a fermé la conversation privée ! Vous devriez faire de même.","conversation_is_now_verified":"La conversation est maintenant vérifiée.","authentication_failed":"L'authentification a échoué.","Creating_your_private_key_":"Création de votre clé privée; cela peut prendre un moment.","Authenticating_a_buddy_helps_":"L'authentification d'un contact permet de s'assurer que la personne à qui vous parlez est vraiment celui qu'il ou elle prétend être.","How_do_you_want_to_authenticate_your_buddy":"Comment voulez-vous vous authentifier __bid_name__ (<b>__bid_jid__</b>)?","Select_method":"Sélection de la méthode...","Manual":"Manuel","Question":"Question","Secret":"Sécurité","To_verify_the_fingerprint_":"Pour vérifier l'empreinte, joignez votre contact via un autre canal digne de confiance, tel que le téléphone.","Your_fingerprint":"Votre empreinte","Buddy_fingerprint":"Empreinte du contact","Close":"Fermer","Compared":"Comparé","To_authenticate_using_a_question_":"Pour s'authentifier à l'aide d'une question, choisissez une question dont la réponse n'est connue que vous et de votre contact.","Ask":"Demander","To_authenticate_pick_a_secret_":"Pour vous authentifier, choisissez un secret connu seulement de vous et de votre contact.","Compare":"Comparer","Fingerprints":"Empreintes","Authentication":"Authentification","Message":"Message","Add_buddy":"Ajouter un contact","rename_buddy":"Renommer le contact","delete_buddy":"Supprimer le contact","Login":"Connexion","Username":"Nom d'utilisateur","Password":"Mot de passe","Cancel":"Annuler","Connect":"Connecter","Type_in_the_full_username_":"Tapez un nom d'utilisateur complet et un alias(optionnel).","Alias":"Alias","Add":"Ajouter","Subscription_request":"Demande d'abonnement","You_have_a_request_from":"Vous avez une requête de ","Deny":"Refuser","Approve":"Approuver","Remove_buddy":"Supprimer le contact","You_are_about_to_remove_":"Vous allez retirer __bid_name__ (<b>__bid_jid__</b>) de votre liste de contacts. Toutes les fenêtres de discussion en lien avec celui-ci seront fermées.","Continue_without_chat":"Continuer sans tchat","Please_wait":"Merci de patienter","Login_failed":"Authentification échouée","Sorry_we_cant_authentikate_":"La connexion avec le serveur de tchat a échoué. Vérifiez le mot de passe.","Retry":"Retour","clear_history":"Effacer l’historique","New_message_from":"Nouveau message de __name__","Should_we_notify_you_":"Dans le futur, devrons-nous vous notifier les nouveaux messages ?","Please_accept_":"Merci de cliquer sur le bouton \"autoriser\" en haut de page","Hide_offline":"Masquer les contacts non connectés","Show_offline":"Afficher les contacts non connectés","About":"À propos","dnd":"Ne pas déranger","Mute":"Muet","Unmute":"Son actif","Subscription":"Abonnement","both":"Les deux","Status":"Statut","online":"En ligne","chat":"tchat","away":"Absent","xa":"Longue absence","offline":"Hors ligne","none":"Aucun","Unknown_instance_tag":"Tag inconnu","Not_one_of_our_latest_keys":"Ce n'est pas l'une des dernières touches","Received_an_unreadable_encrypted_message":"Message chiffré non lisible","Online":"En ligne","Chatty":"Libre pour discuter","Away":"Absent","Extended_away":"Longue absence","Offline":"Hors ligne","Friendship_request":"Demande de contact","Confirm":"Valider","Dismiss":"Rejeter","Remove":"Supprimer","Online_help":"Aide en ligne","FN":"Nom","N":" N ","FAMILY":"Nom de famille","GIVEN":"prénom","NICKNAME":"Pseudo","URL":"URL","ADR":"Adresse","STREET":"Rue","EXTADD":"Adresse (suite)","LOCALITY":"Localité","REGION":"Région","PCODE":"Code Postal","CTRY":"Pays","TEL":"Téléphone","NUMBER":"Numéro","EMAIL":"Courriel","USERID":" USERID ","ORG":"Organisation","ORGNAME":"Nom","ORGUNIT":"Unité","TITLE":"Qualité:","ROLE":"Rôle","BDAY":"Date de naissance","DESC":"Description","PHOTO":"Photo","send_message":"Envoyer un message","get_info":"Montrer les informations","Settings":"Réglages","Priority":"Priorité","Save":"Enregistrer","User_settings":"Paramètres utilisateur","A_fingerprint_":"Une empreinte est utilisée pour s'assurer de l'identité de la personne à qui vous parlez","is":"est","Login_options":"Options d'identification","BOSH_url":"URL BOSH","Domain":"Domaine","Resource":"Ressource","On_login":"Après authentification","Received_an_unencrypted_message":"Reçu un message non chiffré","Sorry_your_buddy_doesnt_provide_any_information":"Désolé, votre contact n'a pas fourni d'informations","Info_about":"À propos de","Authentication_aborted":"Authentification interrompue.","Authentication_request_received":"Requête d'authentification reçue.","Log_in_without_chat":"S'identifier sans tchat","has_come_online":"vient d'arriver","Unknown_sender":"Expéditeur inconnu","Please_allow_access_to_microphone_and_camera":"Veuillez cliquez sur le bouton \"Autoriser\" en haut, pour permettre l'accès au micro et à la caméra.","Incoming_call":"Appel entrant","from":"de","Do_you_want_to_accept_the_call_from":"Voulez-vous accepter l'appel de","Reject":"Rejeté","Accept":"Accepté","hang_up":"raccrocher","snapshot":"Capture d’écran","mute_my_audio":"Couper l'audio","pause_my_video":"Mettre ma vidéo en pause","fullscreen":"Plein écran","Info":"Info","Local_IP":"IP locale","Remote_IP":"IP distante","Local_Fingerprint":"Empreinte locale","Remote_Fingerprint":"Empreinte distante","Video_call_not_possible":"L'appel vidéo n'est possible. Votre contact ne supporte pas les appels vidéo.","Start_video_call":"Démarrer l'appel vidéo","Join_chat":"Joindre la discussion","Join":"Joindre","Room":"Salon","Nickname":"Pseudo","left_the_building":"__nickname__ a quitté l'immeuble","entered_the_room":"__nickname__ entre dans le salon","is_now_known_as":"__oldNickname__ est maintenant connu comme __newNickname__","This_room_is":"Ce salon est","muc_hidden":{"keyword":"caché","description":"ne peut être trouvé avec une recherche"},"muc_membersonly":{"keyword":"pour les membres seulement","description":"Vous devez être sur la liste des membres"},"muc_moderated":{"keyword":"modéré","description":"Seulement les personnes avec la \"voix\" sont autorisés à envoyer des messages"},"muc_nonanonymous":{"keyword":"non anonyme","description":"Votre identifiant Jabber est visible de tous les autres occupants"},"muc_open":{"keyword":"ouvert","description":"Tout le monde est autorisé à se connecter"},"muc_passwordprotected":{"keyword":"protégé par un mot de passe","description":"Vous devez fournir un mot de passe correct"},"muc_persistent":{"keyword":"persistent","description":"ne sera pas détruit si le dernier occupant part"},"muc_public":{"keyword":"public","description":"peut être touvé avec une recherche"},"muc_semianonymous":{"keyword":"semi-anonyme","description":"Votre identifiant Jabber est seulement visible aux administrateurs de ce salon"},"muc_temporary":{"keyword":"temporaire","description":"sera détruit au départ de son dernier occupant"},"muc_unmoderated":{"keyword":"non modéré","description":"Tout le monde est autorisé à envoyer des messages"},"muc_unsecured":{"keyword":"non sécurisé","description":"un mot de passe n'est pas nécessaire pour entrer"},"Continue":"Continuer","Server":"Serveur","Rooms_are_loaded":"Les salons sont chargés","Could_load_only":"Ne peut charger que __count__ salons pour l'autocomplétion","muc_explanation":"Veuillez saisir le nom du salon, un surnom (optionnel) et un mot de passe pour joindre la conversation","You_already_joined_this_room":"Vous avez déjà rejoint ce salon","This_room_will_be_closed":"Ce salon va être fermé","Room_not_found_":"Un nouveau salon va être créé","Loading_room_information":"Chargement des informations du salon","Destroy":"Détruire","Leave":"Quitter","changed_subject_to":"__nickname__ a changé le sujet du salon à \"__subject__\"","muc_removed_kicked":"Vous avez été éjecté de ce salon","muc_removed_info_kicked":"__nickname__ a été éjecté de ce salon","muc_removed_banned":"Vous avez été banni de ce salon","muc_removed_info_banned":"__nickname__ a été banni de ce salon","muc_removed_affiliation":"Vous avez été retiré du salon en raison d'un changement d'affiliation","muc_removed_info_affiliation":"__nickname__ a été retiré du salon en raison d'un changement d'affiliation","muc_removed_membersonly":"Vous avez été retiré du salon parce que celui-ci est maintenant réservé aux membres et vous n'en faites pas partie","muc_removed_info_membersonly":"__nickname__ a été retiré du salon parce que celui-ci est maintenant réservé aux membres","muc_removed_shutdown":"Vous avez été retiré du salon parce que le service de salon de discussion est en train de s'éteindre","Reason":"Raison","message_not_send":"Votre message n'a pu être envoyé a cause d'une erreur","message_not_send_item-not-found":"Votre message n'a pu être envoyé parce que ce salon n'existe pas","message_not_send_forbidden":"Votre message n'a pas été envoyé parce que vous n'avez pas le droit de parler dans ce salon","message_not_send_not-acceptable":"Votre message n'a pas été envoyé car il n'y a personne dans ce salon","This_room_has_been_closed":"Ce salon a été fermé","Room_logging_is_enabled":"L'historique du salon est conservé","A_password_is_required":"Un mot de passe est requis","You_are_not_on_the_member_list":"Vous n'êtes pas sur la liste des membres","You_are_banned_from_this_room":"Vous avez été banni de ce salon","Your_desired_nickname_":"Votre pseudo souhaité est déjà utilisé. Veuillez en choisir un autre","The_maximum_number_":"Le nombre maximum d'utilisateurs est atteint dans ce salon","This_room_is_locked_":"Ce salon est verrouillé","You_are_not_allowed_to_create_":"Vous n'êtes pas autorisé à créer un salon","Alert":"Alerte","Call_started":"Appel démarré","Call_terminated":"Appel terminé","Carbon_copy":"Copie carbone","Enable":"Activé","jingle_reason_busy":"occupé","jingle_reason_decline":"refusé","jingle_reason_success":"raccroché","Media_failure":"échec du média","No_local_audio_device":"Pas de périphérique audio local","No_local_video_device":"Pas de périphérique vidéo local","Ok":"Ok","PermissionDeniedError":"Vous ou votre navigateur avez refusé de donner des permissions audio/vidéo","Use_local_audio_device":"Utiliser un périphérique audio local.","Use_local_video_device":"Utiliser un périphérique vidéo local.","is_":"est __status__","You_received_a_message_from_an_unknown_sender_":"Vous avez reçu un message d'un expéditeur inconnu (__sender__) Voulez-vous les afficher ?","Your_roster_is_empty_add_":"Votre liste est vide, ajouter <a>Nouveau contact</a>","onsmp_explanation_question":"Votre contact tente de déterminer si il ou elle parle vraiment à vous. Pour vous authentifier auprès de votre contact, saisissez une réponse et cliquez sur Répondre.","onsmp_explanation_secret":"Votre contact tente de déterminer si il ou elle parle vraiment à vous. Pour vous authentifier auprès de votre contact, entrez le mot secret","from_sender":"de __sender__","Verified_private_conversation_started":"La conversation privée vérifiée a démarré.","Unverified_private_conversation_started":"La conversation privée non vérifiée a démarré.","Bookmark":"Marque-page","Auto-join":"Joindre automatiquement","Edit_bookmark":"Éditer le marque-page","Room_logging_is_disabled":"La connexion au salon est désactivée","Room_is_now_non-anoymous":"Ce salon n'est désormais plus anonyme","Room_is_now_semi-anonymous":"Ce salon est désormais semi-anonyme","Do_you_want_to_change_the_default_room_configuration":"Voulez-vous changer la configuration par défaut du salon ?","Default":"Par défaut","Change":"Changer","Send_file":"Envoyer un fichier","setting-explanation-carbon":"Avec la copie carbone activé, votre serveur XMPP envera une copie de tous les messages entrant qui vous sont destiné à ce client, même s'il ne lui sont pas directement addressés.","setting-explanation-login":"Si cette option est activé, le chat commencera lorsque vous vos connectez.","setting-explanation-priority":"Si vous êtes connecté plusieurs fois avec le même compte, votre serveur XMPP enverra les messages au client ayant le plus haute priorité.","setting-explanation-xmpp":"Ces options sont utilisées pour se connecter au serveur XMPP.","_is_composing":" est en train d'écrire...","_are_composing":" sont en train d'écrire...","Chat_state_notifications":"Notifications de composition","setting-explanation-chat-state":"Voulez-vous envoyer et recevoir les notifications de composition, comme lorsque quelqu'un commence ou arrête d'écrire un message ?","Share_screen":"Ecran partagé","Incoming_stream":"Flux entrant","Stream_started":"flux démarré","HTTPS_REQUIRED":"Cette action nécessite une connexion cryptée.","EXTENSION_UNAVAILABLE":"Vous avez besoin d'une extension / d'un addon pour votre navigateur.","UNKNOWN_ERROR":"Une erreur inconnue s'est produite.","Install_extension":"Veuillez installer l'extension afin d'utiliser le partage d'écran: ","Connection_accepted":"Connexion acceptée","Stream_terminated":"Flux terminé","Close_all":null}},"hu-HU":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":"Az Ön kapcsolata titkosítatlan.","your_connection_is_encrypted":"Az Ön kapcsolata titkosított.","your_buddy_closed_the_private_connection":"Partnere megszakította a privát kapcsolatot.","start_private":"Privát beszélgetés indítása","close_private":"Privát beszélgetés bezárása","your_buddy_is_verificated":"Az Ön partnere megerősítve.","you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":"Azonosítási kérelem elküldve.","your_message_wasnt_send_please_end_your_private_conversation":"Az üzenetet nem sikerült elküldeni. Kérem fejezze be a privát beszélgetést.","unencrypted_message_received":"Titkosítatlan üzenet fogadva","not_available":"Nem elérhető","no_connection":"Nincs kapcsolat!","relogin":"relogin","trying_to_start_private_conversation":"Privát beszélgetés indítása!","Verified":"Megerősítve","Unverified":"Nem megerősített","private_conversation_aborted":"Privát beszélgetés megszakítva!","your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":"Azonosítás sikertelen.","Creating_your_private_key_":"Privát kulcs generálása. Egy kis időbe telhet...","Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":"Kérdés","Secret":"Kulcs","To_verify_the_fingerprint_":null,"Your_fingerprint":"Az Ön lenyomata","Buddy_fingerprint":"Partnere lenyomata","Close":"Bezárás","Compared":"Összehasonlítva","To_authenticate_using_a_question_":"Az azonosításhoz adjon meg egy kérdést, amelyre a választ csak Ön és Partnere ismerhetik.","Ask":"Kérdez","To_authenticate_pick_a_secret_":"Az azonosításhoz adjon meg egy titkot, amelyet csak Ön és Partnere ismerhetnek.","Compare":"Összehasonlítás","Fingerprints":"Lenyomatok","Authentication":"Azonosítás","Message":"Üzenet","Add_buddy":"Partner hozzáadása","rename_buddy":"Partner átnevezése","delete_buddy":"Partner törlése","Login":"Belépés","Username":"Felhasználónév","Password":"Jelszó","Cancel":"Mégsem","Connect":"Csatlakozás","Type_in_the_full_username_":"Adjon meg egy teljes felhasználónevet, és egy opcionális becenevet.","Alias":"Becenév","Add":"Hozzáadás","Subscription_request":"Feliratkozási kérelem","You_have_a_request_from":"Ön felkérést kapott a következőtől","Deny":"Elutasít","Approve":"Jóváhagy","Remove_buddy":"Partner eltávolítása","You_are_about_to_remove_":null,"Continue_without_chat":"Folytatás chat nélkül","Please_wait":"Kérem várjon","Login_failed":"Chat bejelentkezés sikertelen","Sorry_we_cant_authentikate_":null,"Retry":"Vissza","clear_history":"Előzmények törlése","New_message_from":"Új üzenet __name__ partnerétől","Should_we_notify_you_":"Kívánja hogy értesítsük a jövőben új üzeneteiről?","Please_accept_":"Kérem kattintson a fent megjelenő \"Engedélyez\" gombra.","Hide_offline":"Offline partnerek elrejtése","Show_offline":"Offline partnerek mutatása","About":null,"dnd":"Ne zavarj","Mute":"Némítás","Unmute":"Hangok engedélyezése","Subscription":null,"both":"mindkettő","Status":"Állapot","online":"elérhető","chat":null,"away":"távol","xa":"huzamosabban távol","offline":"offline","none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":"Teljes név","N":null,"FAMILY":"Családi név","GIVEN":"Keresztnév","NICKNAME":"Becenév","URL":"URL","ADR":"Cím","STREET":"Utcanév","EXTADD":"Cím","LOCALITY":"Helység","REGION":"Régió","PCODE":"Irányítószám","CTRY":"Ország","TEL":"Telefonszám","NUMBER":"Házszám","EMAIL":"E-mail cím","USERID":null,"ORG":"Vállalat","ORGNAME":"Név","ORGUNIT":"Osztály","TITLE":"Beosztás","ROLE":"Részleg","BDAY":"Születésnap","DESC":"Leírás","PHOTO":null,"send_message":"Üzenet küldése","get_info":"Info mutatása","Settings":"Beállítások","Priority":"Prioritás","Save":"Mentés","User_settings":"Felhasználó beállítások","A_fingerprint_":null,"is":null,"Login_options":"Bejelentkezési lehetőségek","BOSH_url":"BOSH URL","Domain":"Domain","Resource":"Erőforrás","On_login":"Bejelentkezéskor","Received_an_unencrypted_message":"Titkosítatlan üzenetet fogadott","Sorry_your_buddy_doesnt_provide_any_information":"Sajnos az Ön partnere nem adott meg semmilyen információt.","Info_about":null,"Authentication_aborted":"Azonosítás megszakítva.","Authentication_request_received":"Azonosítási kérelem fogadva.","Log_in_without_chat":"Bejelentkezés chat nélkül","has_come_online":"bejelentkezett","Unknown_sender":"Ismeretlen küldő","Please_allow_access_to_microphone_and_camera":"Kérem kattintson a fent megjelenő \"Engedélyez/Allow\" gombra hogy hozzáférést biztosítson mikrofonjához és kamerájához.","Incoming_call":"Bejövő hívás","from":"tőle","Do_you_want_to_accept_the_call_from":"Szeretné fogadni következő partnere hívását:","Reject":"Elutasít","Accept":"Fogadás","hang_up":"tartás","snapshot":"képernyőfotó","mute_my_audio":"hangom némítása","pause_my_video":"videóképem megállítása","fullscreen":"teljes képernyő","Info":"Info","Local_IP":"Helyi IP","Remote_IP":"Távoli IP","Local_Fingerprint":"Helyi lenyomat","Remote_Fingerprint":"Távoli lenyomat","Video_call_not_possible":"Videóhívás nem lehetséges. Az Ön partnerének készüléke nem támogatja a videóhívásokat.","Start_video_call":"Videóhívás indítása","Join_chat":"Belépés a chatbe","Join":"Belépés","Room":"Szoba","Nickname":"Becenév","left_the_building":"__nickname__ elhagyta az épületet.","entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null,"_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"it":{"translation":{"Logging_in":"login…","your_connection_is_unencrypted":"La sua connessione è non cifrata.","your_connection_is_encrypted":"La sua connessione è cifrata.","your_buddy_closed_the_private_connection":"La sua connessione privata è stato chiuso dal suo compagno.","start_private":"Inizia privata","close_private":"Chiude privata","your_buddy_is_verificated":"Il tuo compagno è stato verificato","you_have_only_a_subscription_in_one_way":"Hai solo una one-way inscrizione.","authentication_query_sent":"Domanda d'autenticità inviata.","your_message_wasnt_send_please_end_your_private_conversation":"Il tuo messaggio non è stato inviato. Si prega di finire la sua conversazione privata.","unencrypted_message_received":"Messaggio non cifrato ricevuto","not_available":"non disponibile","no_connection":"nessun collegamento!","relogin":"nuovo login","trying_to_start_private_conversation":"Cercando di avviare una conversazione privata!","Verified":"verificato","Unverified":"non verificato","private_conversation_aborted":"Conversazione privata abortito!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Il tuo compagno ha chiuso la conversazione privata! Si dovrebbe fare lo stesso.","conversation_is_now_verified":"Conversazione è ora verificato.","authentication_failed":"autenticazione fallita.","Creating_your_private_key_":"Creare la propria chiave privata; questo potrebbe richiedere un po'.","Authenticating_a_buddy_helps_":"Autenticazione un compagno aiuta a garantire che la persona si sta parlando è davvero quello che lui o lei sostiene di essere.","How_do_you_want_to_authenticate_your_buddy":"Come si desidera autenticare __bid_name__ (<b>__bid_jid__</b>)?","Select_method":"Seleziona metodo ..","Manual":"manuale","Question":"domanda","Secret":"segreto","To_verify_the_fingerprint_":"Per verificare l'impronta digitale, contattare il proprio compagno attraverso qualche altro canale affidabile, come il telefono.","Your_fingerprint":"il tuo impronta digitale","Buddy_fingerprint":"impronta digitale da compagno","Close":"chiude","Compared":"comparato","To_authenticate_using_a_question_":"Per autenticare tramite una questione, scegli una questione la cui risposta è nota solo voi e il tuo compagno","Ask":"chiedi","To_authenticate_pick_a_secret_":"Per autenticare, scegli un segreto noto solo a te e il tuo compagno.","Compare":"Comparare","Fingerprints":"Impronta digitale","Authentication":"Autenticazione","Message":"Messagio","Add_buddy":"Aggiungi un compagno","rename_buddy":"rinomina compagno","delete_buddy":"elimina compagno","Login":"Login","Username":"Identificazione dell'utente","Password":"Password","Cancel":"Cancella","Connect":"Collega","Type_in_the_full_username_":"Digita l'identificazione utente completo e un alias opzionale.","Alias":"Alias","Add":"Aggiungi","Subscription_request":"Rrichiesta di sottoscrizione","You_have_a_request_from":"Hai una richiesta da","Deny":"Refiuta","Approve":"Approva","Remove_buddy":"Rimuova il compagno","You_are_about_to_remove_":"Stai rimovendo __bid_name__ (<b>__bid_jid__</b>) del suo lista di compagni. Tutte le chat appartenente saranno chiuse.","Continue_without_chat":"Continua senza chat","Please_wait":"Si prega d'attendere","Login_failed":"Chat login è fallito","Sorry_we_cant_authentikate_":"Autenticazione non riuscita con il server di chat. Forse la password è sbagliata?","Retry":"Indietro","clear_history":"Cancella la cronologia","New_message_from":"Nuovo messaggio da __name__","Should_we_notify_you_":"Vuoi ricevere una notifica di nuovi messaggi in futuro?","Please_accept_":"Si prega di fare clic sul bottone \"Autorizzazione\" sopra.","Hide_offline":"Nascondere i contatti non in linea","Show_offline":"Mostra i contatti non in linea","About":"Informazione legale","dnd":"Non disturbare","Mute":"Muto attivo","Unmute":"Muto inattivo","Subscription":"Sottoscrizione","both":"etrambi","Status":"Status","online":"In linea","chat":"chat","away":"via","xa":"via estensivo","offline":"non in linea","none":"nessuno","Unknown_instance_tag":"Instance tag sconosciuta.","Not_one_of_our_latest_keys":"Non è una delle nostre ultime chiavi.","Received_an_unreadable_encrypted_message":"Ricevuto un messaggio crittografato illeggibile.","Online":"In linea","Chatty":"Chiacchierino","Away":"Via","Extended_away":"Via estensivo","Offline":"Non in linea","Friendship_request":"Amicizia richiesto","Confirm":"Conferma","Dismiss":"Rifiuta","Remove":"Rimuovi","Online_help":"Guida in linea","FN":"Nome e cognome","N":null,"FAMILY":"Cognome","GIVEN":"Nome","NICKNAME":"Soprannome","URL":"URL","ADR":"Indirizzo","STREET":"Via","EXTADD":"Esteso Indirizzo","LOCALITY":"Località","REGION":"Regione","PCODE":"Codice Postale","CTRY":"Paese","TEL":"Telefono","NUMBER":"Numero","EMAIL":"E-mail","USERID":null,"ORG":"Organizzazione","ORGNAME":"Nome","ORGUNIT":"Unità","TITLE":"Titolo di lavoro","ROLE":"Funzione","BDAY":"Compleanno","DESC":"Descrizione","PHOTO":null,"send_message":"Messagio inviato","get_info":"Mostra informazioni","Settings":"Impostazione","Priority":"Priorità","Save":"Salva","User_settings":"Impostazione dell'utente","A_fingerprint_":"Una impronta digitale è usato per assicurarsi che la persona con cui stai parlando è lui o lei che sta dicendo.","is":"è","Login_options":"Opzioni di login","BOSH_url":"BOSH URL","Domain":"Domain","Resource":"Risorsa","On_login":"Login on","Received_an_unencrypted_message":"Ricevuto un messaggio non crittografato","Sorry_your_buddy_doesnt_provide_any_information":"Spiace, il tuo compagno non fornisce alcuna informazione.","Info_about":"Informazioni","Authentication_aborted":"Autenticazione interrotta","Authentication_request_received":"Richiesta di autenticazione ricevuto.","Log_in_without_chat":"Log in senza chat","has_come_online":"È venuto in linea","Unknown_sender":"Mittente sconosciuto","Please_allow_access_to_microphone_and_camera":"Si prega di fare clic sul bottone \"Autorizzazione\" sopra per autorizzazione del l'accesso al microfono e fotocamera.","Incoming_call":"Chiamata in arrivo","from":"di","Do_you_want_to_accept_the_call_from":"Vuoi accettare la chiamata di","Reject":"Rifiuta","Accept":"Accetta","hang_up":"Riattacca","snapshot":"istantanea","mute_my_audio":"disattiva il mio audio","pause_my_video":"pausa il mio audio","fullscreen":"schermo intero","Info":"Informazione","Local_IP":"IP locale","Remote_IP":"IP remoto","Local_Fingerprint":"Impronta digitale locale","Remote_Fingerprint":"Impronta digitale remoto","Video_call_not_possible":"Videochiamata non è possibile. Il tuo compagno non può effettuare videochiamate.","Start_video_call":"Inizia videochiamata","Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":"è __status__","You_received_a_message_from_an_unknown_sender_":"Hai ricevuto un messaggio da un mittente sconosciuto (__sender__) Vuoi che venga visualizzato?","Your_roster_is_empty_add_":"Il suo elenco è vuoto, aggiungi un <a>compagno nuovo</a>","onsmp_explanation_question":"Il tuo compagno sta cercando di determinare se lui o lei sta davvero parlando con te. Per autenticare a il tuo compagno. inserisci la risposta e fare click su risposta.","onsmp_explanation_secret":"Il tuo compagno sta cercando di determinare se lui o lei sta davvero parlando con te. Per autenticare a il tuo compagno. inserire il segreto.","from_sender":"di __sender__","Verified_private_conversation_started":"verificato Conversazione privata iniziato.","Unverified_private_conversation_started":"non verificato Conversazione privata iniziato.","Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null,"_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"nds":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null,"_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"pl":{"translation":{"Logging_in":"Logowanie...","your_connection_is_unencrypted":"Twoje połączenie nie jest szyfrowane.","your_connection_is_encrypted":"Twoje połączenie jest szyfrowane.","your_buddy_closed_the_private_connection":"Twój rozmówca zamknął połączenie.","start_private":"Rozpocznij rozmowę.","close_private":"Zakończ rozmowę.","your_buddy_is_verificated":"Twój rozmówca został zweryfikowany.","you_have_only_a_subscription_in_one_way":"Posiadasz tylko jednostronną subskrypcję.","authentication_query_sent":"Wysłano proźbę o autentykację.","your_message_wasnt_send_please_end_your_private_conversation":"Twoja wiadomość nie została wysłana. Proszę, zamknij rozmowę.","unencrypted_message_received":"Otrzymano niezaszyfrowaną wiadomość.","not_available":"Niedostępny.","no_connection":"Brak połączenia!","relogin":"Połącz ponownie","trying_to_start_private_conversation":"Rozpocznij rozmowę!","Verified":"Zweryfikowano","Unverified":"Niezweryfikowano","private_conversation_aborted":"Anulowano rozmowę!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Rozmówca przerwał połączenie! Powinieneś zrobić to samo.","conversation_is_now_verified":"Zweryfikowano połączenie.","authentication_failed":"Weryfikacja się nie powiodła.","Creating_your_private_key_":"Tworzenie klucza prywatnego; może to chwilę potrwać","Authenticating_a_buddy_helps_":"Autoryzacja pomoże w ustaleniu faktycznej tożsamości rozmówcy ;).","How_do_you_want_to_authenticate_your_buddy":"Jakiej autoryzacji chcesz użyć __bid_name__ (<b>__bid_jid__</b>)?","Select_method":"Wybierz sposób...","Manual":"Ręcznie","Question":"Pytanie","Secret":"Hasło","To_verify_the_fingerprint_":"Aby zweryfikować kod, najpierw skontaktuj się z rozmówcą za pomocą zaufanego sposobu, np telefonu.","Your_fingerprint":"Twój kod:","Buddy_fingerprint":"Kod kontaktu","Close":"Zamknij","Compared":"Porównano","To_authenticate_using_a_question_":"Aby autoryzować za pomocą pytania, wybierz pytanie na które tylko ty i twój rozmówca zna odpowiedź.","Ask":"Zadaj pytanie","To_authenticate_pick_a_secret_":"Aby autoryzować za pomocą hasła, wybierz hasło na które znasz tylko Ty i twój rozmówca.","Compare":"Dopasuj","Fingerprints":"Kody autoryzacyjne","Authentication":"Autoryzacja","Message":"Wiadomość","Add_buddy":"Dodaj kontakt","rename_buddy":"Zmień nazwę kontaktu","delete_buddy":"Usuń kontakt","Login":"Login","Username":"Nazwa Użytkownika","Password":"Hasło","Cancel":"Anuluj","Connect":"Połączenie","Type_in_the_full_username_":"Wpisz pełną nazwę użytkownika (np. <B>imię.nazwisko@zajezdnia.local</B>) oraz jego nazwę wyświetlaną (Alias).","Alias":"Alias","Add":"Dodaj","Subscription_request":"Potwierdzenie subskrypcji","You_have_a_request_from":"Masz potwierdzenie od","Deny":"Odmów","Approve":"Zatwierdź","Remove_buddy":"Usuń kontakt","You_are_about_to_remove_":"Chcesz usunąć __bid_name__ (<b>__bid_jid__</b>) z twojej listy kontaktów. Wszystkie powiązane rozmowy zostaną zamknięte.","Continue_without_chat":"Kontynuuj bez komunikatora","Please_wait":"Proszę czekać","Login_failed":"Błędne logowanie","Sorry_we_cant_authentikate_":"Błędna autoryzacja z serwerem. Może hasło jest nieprawidłowe?","Retry":"Powrót","clear_history":"Wyczyść historię","New_message_from":"Nowa wiadomość od __name__","Should_we_notify_you_":"Czy chcesz otrzymywać powiadomienia o nowych wiadomościach w przyszłości?","Please_accept_":"Kliknij \"Zezwól\" na górze.","Hide_offline":"Schowaj niedostępne kontakty","Show_offline":"Pokaż niedostępne kontakty","About":"Info","dnd":"Nie przeszkadzać","Mute":"Wycisz","Unmute":"Włącz dźwięk","Subscription":"Subskrybcja","both":"obustronna","Status":"Status","online":"Dostępny","chat":"czat","away":"z dala od kompa","xa":"hen hen...","offline":"niedostępny","none":"brak","Unknown_instance_tag":"Nieznany przypadek.","Not_one_of_our_latest_keys":"Not one of our latest keys.","Received_an_unreadable_encrypted_message":"Otrzymano nieczytelną, zaszyfrowaną wiadomość.","Online":"Połączony","Chatty":"Pogawędzimy?","Away":"Daleko","Extended_away":"Hen Hen...","Offline":"Niedostępny","Friendship_request":"Prośba o kontakt","Confirm":"Potwierdzenie","Dismiss":"Odwołaj","Remove":"Usuń","Online_help":"Pomoc Online","FN":"Pełna nazwa","N":" ","FAMILY":"Nazwisko","GIVEN":"Imię","NICKNAME":"Pseudonim","URL":"Strona WWW","ADR":"Adres","STREET":"Ulica","EXTADD":"Pełny adres","LOCALITY":"Lokalizacja","REGION":"Region","PCODE":"Kod pocztowy","CTRY":"Kraj","TEL":"Telefon","NUMBER":"Numer","EMAIL":"Email","USERID":" ","ORG":"Organizacja","ORGNAME":"Nazwa","ORGUNIT":"Jednostka","TITLE":"Stanowisko","ROLE":"Rola","BDAY":"Data urodzin","DESC":"Opis","PHOTO":" ","send_message":"Wyślij wiadomość","get_info":"Pokaż informację","Settings":"Ustawienia","Priority":"Priorytet","Save":"Zapisz","User_settings":"Ustawienia Użytkownika","A_fingerprint_":"Kod służy do autoryzacji Twojego rozmówcy aby potwierdzić jego tożsamość.","is":"jest","Login_options":"opcje logowania","BOSH_url":"Adres BOSH","Domain":"Domena","Resource":"Źródło","On_login":"Na login","Received_an_unencrypted_message":"Zatwierdzono nieszyfrowaną wiadomość.","Sorry_your_buddy_doesnt_provide_any_information":"Wybacz, twój rozmówca nie posiada żadnych informacji.","Info_about":"Informacja o...","Authentication_aborted":"Autoryzacja anulowana.","Authentication_request_received":"Prośba o autoryzację została przyjęta.","Log_in_without_chat":"Zaloguj bez komunikatora","has_come_online":"jest teraz dostępny","Unknown_sender":"Nieznany nadawca","Please_allow_access_to_microphone_and_camera":"Kliknij \"Potwierdź\" na górze, aby móc korzystać z mikrofonu oraz kamery.","Incoming_call":"Przychodzące połączenie","from":"z","Do_you_want_to_accept_the_call_from":"Akceptujesz połączenie od","Reject":"Odrzuć","Accept":"Zaakceptuj","hang_up":"odbierz","snapshot":"zrób zdjęcie","mute_my_audio":"wycisz dźwięk","pause_my_video":"zatrzymaj moje wideo","fullscreen":"Pełny ekran","Info":"Informacja","Local_IP":"Adres IP","Remote_IP":"Zdalny adres IP","Local_Fingerprint":"Kod lokalny","Remote_Fingerprint":"Zdalny kod","Video_call_not_possible":"Rozmowa wideo jest niemożliwa. Twój rozmówca nie ma możliwości prowadzenia takich rozmów.","Start_video_call":"Rozpocznij rozmowę wideo","Join_chat":"Dołącz do czata","Join":"Dołącz","Room":"Pokój","Nickname":"Nazwa użytkownika","left_the_building":"__nickname__ wyszedł","entered_the_room":"__nickname__ wszedł do pokoju","is_now_known_as":"__oldNickname__ zmienił nazwę na __newNickname__","This_room_is":"Ten pokój jest","muc_hidden":{"keyword":"ukryty","description":"nie można odnaleźć elementów wyszukiwania"},"muc_membersonly":{"keyword":"tylko zalogowani","description":"musisz być członkiem listy"},"muc_moderated":{"keyword":"moderowano","description":"tylko osoby z opcją \"głos\" mogą wysyłać wiadomość"},"muc_nonanonymous":{"keyword":"nie-anonimowy","description":"Twój identyfikator jabber jest widoczny dla wszystkich innych osób"},"muc_open":{"keyword":"otwarty","description":"wszyscy mają pozwolenie aby dołączyć"},"muc_passwordprotected":{"keyword":"ograniczone hasłem","description":"musisz wpisać prawidłowe hasło"},"muc_persistent":{"keyword":"trwale","description":"nie zostaną zniszczone, jeśli ostatnia osoba wyszła"},"muc_public":{"keyword":"publiczny","description":"wyszukawno"},"muc_semianonymous":{"keyword":"pół-anonimowy","description":"Twój identyfikator jabber jest widoczny w pokoju adminów"},"muc_temporary":{"keyword":"tymczasowy","description":"zostanie usunięty jeżeli ostatnia osoba wyjdzie"},"muc_unmoderated":{"keyword":"niemoderowany","description":"wszyscy są uprawnieni do pisania wiadomości"},"muc_unsecured":{"keyword":"niezabezpieczone","description":"nie musisz wpisywać hasła"},"Continue":"Kontynuuj","Server":"Serwer","Rooms_are_loaded":"Pokoje zostały załadowane","Could_load_only":"Nie załadowano __count__ pokoi","muc_explanation":"Aby się zalogować, wpisz nazwę pokoju oraz opcjonalnie nazwę użytkownika i hasło","You_already_joined_this_room":"Już dołączyłeś do tego pokoju","This_room_will_be_closed":"Ten pokój będzie zamknięty","Room_not_found_":"Nowy pokój będzie stworzony","Loading_room_information":"Ładowani informacji o pokoju","Destroy":"Zniszczony","Leave":"Opuść","changed_subject_to":"__nickname__ zmienił temat pokoju na \"__subject__\"","muc_removed_kicked":"Zostałeś wyrzucony z pokoju","muc_removed_info_kicked":"__nickname__ został wyrzucony z pokoju","muc_removed_banned":"Zostałeś zbanowany","muc_removed_info_banned":"__nickname__ został zbanowany","muc_removed_affiliation":"Zostałeś usunięty z pokoju ze względu na zmianę przynależnosci","muc_removed_info_affiliation":"__nickname__ został usunięty z pokoju ze względu na zmianę przynależnosci","muc_removed_membersonly":"Zostałeś usunięty z pokoju ze względu na zmianę pokoju tylko dla członków, a Ty nie jesteś członkiem...","muc_removed_info_membersonly":"__nickname__ został usunięty z pokoju ze względu na zmianę pokoju na tylko dla członków","muc_removed_shutdown":"Zostałeś usunięty z pokoju ze względu na zamknięcie usługi","Reason":"Powód","message_not_send":"Wystąpił błąd i twoja wiadomość nie została wysłana.","message_not_send_item-not-found":"Twoja wiadomość nie została wysłana ponieważ ten pokój nie istnieje","message_not_send_forbidden":"Twoja wiadomość nie została wysłana ponieważ nie masz głosu w tym pokoju","message_not_send_not-acceptable":"Twoja wiadomość nie została wysłana ponieważ nie jesteś właścicielem tego pokoju","This_room_has_been_closed":"Ten pokój został zamknięty","Room_logging_is_enabled":"Logowanie do pokoju jest włączone","A_password_is_required":"Hasło jest wymagane","You_are_not_on_the_member_list":"Nie jesteś na liście członków","You_are_banned_from_this_room":"Zostałeś zbanowany w tym pokoju","Your_desired_nickname_":"Twoja nazwa użytkownika jest już użyta. Spróbuj wybrać inną","The_maximum_number_":"Została osiągnięta maksymalna liczba użytkowników w tym pokoju","This_room_is_locked_":"Ten pokój jest zablokowany","You_are_not_allowed_to_create_":"Nie masz uprawnień do tworzenia pokoju","Alert":"Alarm","Call_started":"Rozmowa rozpoczęta","Call_terminated":"Rozmowa zakończona","Carbon_copy":"Do wiadomości","Enable":"Włączone","jingle_reason_busy":"zajęte","jingle_reason_decline":"odmów","jingle_reason_success":"zakończono","Media_failure":"Błąd mediów","No_local_audio_device":"Brak lokalnego urządzenia audio.","No_local_video_device":"Brak lokalnego urządzenia wideo.","Ok":"Ok","PermissionDeniedError":"Ty lub twoja przeglądarka odmówiła dostępu do audio/video","Use_local_audio_device":"Użyj lokalnego urządzenia audio.","Use_local_video_device":"Użyj lokalnego urządzenia wideo.","is_":"jest __status__","You_received_a_message_from_an_unknown_sender_":"Masz wiadomość od nieznanego nadawcy. (__sender__) Chcesz to wyświetlić?","Your_roster_is_empty_add_":"Twoja lista jest pusta, dodaj kontakty <a>Nowy kontakt</a>","onsmp_explanation_question":"Twój rozmówca próbuje się z Tobą połączyć. Autoryzacja z rozmówcą, napisz odpowiedź.","onsmp_explanation_secret":"Twój rozmówca próbuje się z Tobą połączyć. Autoryzacja z rozmówcą, wpisz hasło.","from_sender":"z __sender__","Verified_private_conversation_started":"Zweryfikowano Rozmowa prywatna rozpoczęta.","Unverified_private_conversation_started":"Niezweryfikowano Rozmowa prywatna rozpoczęta.","Bookmark":"Zakładka","Auto-join":"Auto-połączenie","Edit_bookmark":"Edytuj zakładkę","Room_logging_is_disabled":"Logowanie pokoju jest wyłączone","Room_is_now_non-anoymous":"Pokój jest teraz nie-anonimowy","Room_is_now_semi-anonymous":"Pokój jest teraz pół-anonimowy","Do_you_want_to_change_the_default_room_configuration":"Chcesz zmienić domyślną konfigurację pokoju?","Default":"Domyślny","Change":"Zmień","Send_file":"Wyślij plik","setting-explanation-carbon":null,"setting-explanation-login":"Jeżeli ta opcja jest włączona, czat uruchomi się przy zalogowaniu.","setting-explanation-priority":"Jeżeli jesteś zalogowany wiele razy na to samo konto twój serwer XMPP dostarczy wiadomości do klienta z najwyższym priorytetem.","setting-explanation-xmpp":"Te ustawienia używane są do połączenia z serwerem XMPP.","_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"pt-BR":{"translation":{"Logging_in":"Entrando...","your_connection_is_unencrypted":"Sua conexão não é encriptada","your_connection_is_encrypted":"Sua conexão é encriptada","your_buddy_closed_the_private_connection":"Seu contato fechou a conexão privada","start_private":"Iniciar conversa privada","close_private":"Fechar conversa privada","your_buddy_is_verificated":"Seu contato está verificado","you_have_only_a_subscription_in_one_way":"Você só tem a inscrição one-way","authentication_query_sent":"Pergunta de autenticação enviada","your_message_wasnt_send_please_end_your_private_conversation":"Sua mensagem não foi enviada. Por favor finalize sua conversa privada","unencrypted_message_received":"Mensagem não encriptada recebida","not_available":"Indisponível","no_connection":"Sem conexão!","relogin":"reentrar","trying_to_start_private_conversation":"Tentando iniciar conversa privada","Verified":"Verificado","Unverified":"Não verificado","private_conversation_aborted":"Conversa privada abortada!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Seu contato encerrou a conversa privada! Você deveria fazer o mesmo.","conversation_is_now_verified":"Conversa verificada.","authentication_failed":"Autenticação falhou.","Creating_your_private_key_":"Criando sua chave privada: isso pode demorar um pouco.","Authenticating_a_buddy_helps_":"Autenticar seu contato ajuda a garantir que a pessoa com a qual você está falando é realmente a pessoa que ela alega ser.","How_do_you_want_to_authenticate_your_buddy":"Como você gostaria de se autenticar __bid_name__ (<b>__bid_jid__</b>)?","Select_method":"Selecione o método...","Manual":"Manual","Question":"Pergunta","Secret":"Senha","To_verify_the_fingerprint_":"Para verificar o fingerprint, entre em contato com seu contato usando outro meio, de preferência seguro, como o telefone.","Your_fingerprint":"Sua impressão digital","Buddy_fingerprint":"Impressão digital do contato","Close":"Fechar","Compared":"Comparado","To_authenticate_using_a_question_":"Para autenticar seu contato faça uma pergunta, mas escolha que só ele saiba a resposta.","Ask":"Pergunta","To_authenticate_pick_a_secret_":"Para autenticar, escolha um segredo que somente você e seu contato saibam.","Compare":"Compare","Fingerprints":"Impressões digitais","Authentication":"Autenticação","Message":"Mensagem","Add_buddy":"Adicionar contato","rename_buddy":"renomear contato","delete_buddy":"remover contato","Login":"Entrar","Username":"Usuário","Password":"Senha","Cancel":"Cancelar","Connect":"Conectar","Type_in_the_full_username_":"Digite seu nome completo e um apelido opcional.","Alias":"Apelido","Add":"Adicionar","Subscription_request":"Pedido de inscrição","You_have_a_request_from":"Você tem um pedido de","Deny":"Negar","Approve":"Aprovar","Remove_buddy":"Remover contato","You_are_about_to_remove_":"Você está prestes a remover __bid_name__ (<b>__bid_jid__</b>) de sua lista de contatos. Todas as conversas serão fechadas.","Continue_without_chat":"Continue sem converar","Please_wait":"Por favor aguarde","Login_failed":"Autenticação da conversa falhou","Sorry_we_cant_authentikate_":"A autenticação com o servidor falhou. Talvez seja a senha errada?","Retry":"Voltar","clear_history":"Limpar histórico","New_message_from":"Nova mensagem de __name__","Should_we_notify_you_":"Devemos continuar notificando sobre novas mensagens no futuro?","Please_accept_":"Por favor clique no botão \"Permitir\" na parte superior.","Hide_offline":"Esconder contatos desconectados","Show_offline":"Mostrar contatos desconectados","About":"Sobre","dnd":"Não perturbe","Mute":"Mudo","Unmute":"Ligar","Subscription":"Inscrição","both":"ambos","Status":"Status","online":"online","chat":"conversa","away":"ausente","xa":"ausente por mais tempo","offline":"desativado","none":"nenhum","Unknown_instance_tag":"Marcação desconhecida da instância","Not_one_of_our_latest_keys":"Nenhuma de nossas ultimas chaves.","Received_an_unreadable_encrypted_message":"Mensagem encriptada ilegível foi recebida.","Online":"Online","Chatty":"Tagarela","Away":"Ausente","Extended_away":"Ausente por mais tempo","Offline":"Desativado","Friendship_request":"Pedido de amizade","Confirm":"Confirmar","Dismiss":"Ignorar","Remove":"Remover","Online_help":"Ajuda online","FN":"Nome completo","N":" ","FAMILY":"Sobrenome","GIVEN":"Nome","NICKNAME":"Apelido","URL":"URL","ADR":"Endereço","STREET":"Rua, Av, etc","EXTADD":"Complemento","LOCALITY":"Localidade","REGION":"Região","PCODE":"CEP","CTRY":"País","TEL":"Telefone","NUMBER":"Número","EMAIL":"Email","USERID":" IDUsuário","ORG":"Empresa","ORGNAME":"Nome","ORGUNIT":"Unidade","TITLE":"Cargo","ROLE":"Função","BDAY":"Data de nascimento","DESC":"Descrição","PHOTO":"Foto","send_message":"Enviar mensagem","get_info":"Exibir informações","Settings":"Configurações","Priority":"Prioridade","Save":"Salvar","User_settings":"Configurações do usuário","A_fingerprint_":"O fingerprint é usado para certificar que a pessoa com a qual se está falando é que ela diz ser.","is":"é","Login_options":"Opções de login","BOSH_url":"BOSH URL","Domain":"Domínio","Resource":"Recurso","On_login":"Ao autenticar","Received_an_unencrypted_message":"Mensagem não encriptada recebida","Sorry_your_buddy_doesnt_provide_any_information":"Desculpe, seu contato não forneceu nenhuma informação","Info_about":"Informações sobre","Authentication_aborted":"Autenticação encerrada.","Authentication_request_received":"Pedido de autenticação recebido","Log_in_without_chat":"Entrar sem conversar","has_come_online":"ficou online","Unknown_sender":"Emissor desconhecido","Please_allow_access_to_microphone_and_camera":"Por favor clique no botão \"Permitir\" no topo, para conceder acesso ao seu microfone e câmera.","Incoming_call":"Recebendo chamada","from":"de","Do_you_want_to_accept_the_call_from":"Você aceita a chamada de","Reject":"Negar","Accept":"Aceitar","hang_up":"desligar","snapshot":"registrar imagem","mute_my_audio":"mudo","pause_my_video":"pausar vídeo","fullscreen":"tela cheia","Info":"Informações","Local_IP":"IP local","Remote_IP":"IP remoto","Local_Fingerprint":"Fingerprint local","Remote_Fingerprint":"Fingerprint remoto","Video_call_not_possible":"Chamada de vídeo impossível. Seu contato não suporta chamadas desse tipo.","Start_video_call":"Iniciar chamada de vídeo","Join_chat":"Entrar no chat","Join":"Entrar","Room":"Sala","Nickname":"Apelido","left_the_building":"__nickname__ deixou o prédio","entered_the_room":"__nickname__ entrou na sala","is_now_known_as":"__oldNickname__ agora é conhecido como __newNickname__","This_room_is":"Esta sala é","muc_hidden":{"keyword":"oculto","description":"Não pode ser encontrado através de pesquisa"},"muc_membersonly":{"keyword":"apenas para membros","description":"você precisa estar na lista de membros"},"muc_moderated":{"keyword":"moderado","description":"Somente pessoas com \"voice\" podem enviar mensagens"},"muc_nonanonymous":{"keyword":"não-anônimo","description":"Seu id jabber esta esposto para todos os outros ocupantes"},"muc_open":{"keyword":"abrir","description":"Todos podem entrar"},"muc_passwordprotected":{"keyword":"protegido por senha","description":"você precisa fornecer a senha correta"},"muc_persistent":{"keyword":"persistente","description":"Não será destruída se o último ocupante tiver saído"},"muc_public":{"keyword":"público","description":"pode ser localizado pela busca"},"muc_semianonymous":{"keyword":"semi-anônimos","description":"Sua identificação jabber só é exposta para administradores da sala"},"muc_temporary":{"keyword":"temporário","description":"Será destruída se o último ocupante tiver saído"},"muc_unmoderated":{"keyword":"sem moderação","description":"Todos tem permissão de enviar mensagens"},"muc_unsecured":{"keyword":"inseguro","description":"Você não precisa de senha para entrar"},"Continue":"Avançar","Server":"Servidor","Rooms_are_loaded":"Sala carregada","Could_load_only":"Pode carregar somente __count__ salas para autocompletar","muc_explanation":"Por favor entre um nome de sala e um nickname opcional e uma senha para entrar no chat","You_already_joined_this_room":"Você já entrou nesta sala","This_room_will_be_closed":"Esta sala será fechada","Room_not_found_":"Uma nova sala será criada","Loading_room_information":"Carregar informação da sala","Destroy":"Destruir","Leave":"Sair","changed_subject_to":"__nickname__ alterar o assunto da sala para \"__subject__\"","muc_removed_kicked":"Você foi removido da sala","muc_removed_info_kicked":"__nickname__ foi removido da sala","muc_removed_banned":"Você foi banido da sala","muc_removed_info_banned":"__nickname__ foi banido da sala","muc_removed_affiliation":"Você foi removido da sala pois a sala, por que a afiliação mudou","muc_removed_info_affiliation":"__nickname__ foi removido da sala, por que a afiliação mudou","muc_removed_membersonly":"Você foi removido da sala pois a sala foi alterada somente para membros e você não é um membro","muc_removed_info_membersonly":"__nickname__ foi removido da sala porque a sala foi alterada para somente membros e você não é um membro","muc_removed_shutdown":"Você foi removido da sala, por que o serviço MUC esta sendo desligado","Reason":"Motivo","message_not_send":"Sua mensagem não foi enviada devido a um erro","message_not_send_item-not-found":"Sua mensagem não foi enviada por que essa sala nao existe mais","message_not_send_forbidden":"Sua mensagem não foi enviada por que não tem 'voz' para essa sala","message_not_send_not-acceptable":"Sua mensagem não foi enviada por que você nao é ocupante desta sala","This_room_has_been_closed":"Essa sala foi fechada","Room_logging_is_enabled":"O Logging esta habilitado","A_password_is_required":"Senha é obrigatória","You_are_not_on_the_member_list":"Você não esta na lista de usuarios","You_are_banned_from_this_room":"Você foi banido desta sala","Your_desired_nickname_":"O nickname escolhido já esta em uso. Por favor escolha outro","The_maximum_number_":"O número máximo de usuarios já foi antigido para essa sala","This_room_is_locked_":"A sala esta trancada","You_are_not_allowed_to_create_":"Você não esta autorizado para criar uma sala","Alert":"Alerta","Call_started":"Chamada iniciada","Call_terminated":"Chamada finalizada","Carbon_copy":"Copia carbono","Enable":"Habilitado","jingle_reason_busy":"ocupado","jingle_reason_decline":"recusado","jingle_reason_success":"sucesso","Media_failure":"Media falhou","No_local_audio_device":"sem dispositivo local de audio","No_local_video_device":"sem dispositivo local de video","Ok":"Ok","PermissionDeniedError":"Você ou seu navegador negou permissão para acessar audio/video","Use_local_audio_device":"Usar dispositivo local de audio","Use_local_video_device":"Usar dispositivo local de video","is_":"é __status__","You_received_a_message_from_an_unknown_sender_":"Você recebeu uma mensagem de um emissor desconhecido (__sender__) Você quer mostrá-los?","Your_roster_is_empty_add_":"Sua lista está vazia, adicione um <a>novo contato</a>","onsmp_explanation_question":"Seu contato está tentando determinar se ele realmente está falando contigo. Para autenticar seu contato, entre com a resposta e clique em Responder.","onsmp_explanation_secret":"Seu contato está tentando determinar se ele realmente está falando contigo. Para autenticar seu contato, escreva a senha.","from_sender":"de __sender__","Verified_private_conversation_started":"Verificado Conversa privada iniciada.","Unverified_private_conversation_started":"Não verificado Conversa privada iniciada.","Bookmark":"Favoritos","Auto-join":"Entrar Automaticamente","Edit_bookmark":"Editar favoritos","Room_logging_is_disabled":"Registro de log na sala está desativado","Room_is_now_non-anoymous":"A sala é não anônima agora","Room_is_now_semi-anonymous":"A sala é semi anônima agora","Do_you_want_to_change_the_default_room_configuration":"Você quer alterar as configurações da sala?","Default":"Padrão","Change":"Alterar","Send_file":"Enviar arquivo","setting-explanation-carbon":"Com carbon copy ativado seu servidor XMPP vai enviar uma copia de cada mensagem para você neste cliente mesmo que não tenha endereço","setting-explanation-login":"Se essa opção esta habilitada, o chat vai começar ao logar.","setting-explanation-priority":"Você esta logado varias vezes com a mesma conta, seu servidor XMPP vai entregar as mensagens para o cliente com a prioridade mais alta.","setting-explanation-xmpp":"Essas opções são usadas para conectar no Servidor XMPP","_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"ro":{"translation":{"Logging_in":"Autentificare...","your_connection_is_unencrypted":"Conexiunea nu este criptată.","your_connection_is_encrypted":"Conexiunea este criptată.","your_buddy_closed_the_private_connection":"Interlocutorul a închis conexiunea privată.","start_private":"Pornește în privat","close_private":"Închide privat","your_buddy_is_verificated":"Interlocutorul este verificat.","you_have_only_a_subscription_in_one_way":"Subscrierea este într-o singură direcție.","authentication_query_sent":"Cererea de autentificare a fost trimisă.","your_message_wasnt_send_please_end_your_private_conversation":"Mesajul nu a fost trimis. Te rog închide conversația în privat.","unencrypted_message_received":"A fost primit un mesaj necriptat","not_available":"Indisponibil","no_connection":"Fără conexiune!","relogin":"Re-autentificare","trying_to_start_private_conversation":"Se încearcă deschiderea conversației în privat!","Verified":"Verificat","Unverified":"Neverificat","private_conversation_aborted":"Conversație în privat eșuată!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Interlocutorul a închis conversația în privat! Ar trebui să faci la fel și tu.","conversation_is_now_verified":"Conversația este acum verificată.","authentication_failed":"Autentificarea a eşuat.","Creating_your_private_key_":"Se crează cheia privată; ar putea să dureze ceva timp.","Authenticating_a_buddy_helps_":"Autentificând un contact ne asigură că persoana cu care vorbești este într-adevăr cine pretinde că este.","How_do_you_want_to_authenticate_your_buddy":"Cum vrei să te autentifici __bid_name__ (<b>__bid_jid__</b>)","Select_method":"Alege metoda...","Manual":"Manual","Question":"Întrebare","Secret":"Secret","To_verify_the_fingerprint_":"Pentru a verifica amprenta, contactează interlocutorul printr-un canal de încredere, cum ar fi telefonul.","Your_fingerprint":"Amprenta ta","Buddy_fingerprint":"Amprenta interlocutorului","Close":"Închide","Compared":"Prin comparație","To_authenticate_using_a_question_":"Pentru autentificarea folosind o întrebare, alege o întrebare cu un răspuns cunoscut doar de tine și de interlocutor.","Ask":"Întreabă","To_authenticate_pick_a_secret_":"Pentru autentificare, alege un secret cunoscut doar de tine și de interlocutor.","Compare":"Compară","Fingerprints":"Amprente","Authentication":"Autentificare","Message":"Mesaj","Add_buddy":"Adaugă contact","rename_buddy":"redenumește contact","delete_buddy":"șterge contact","Login":"Logare","Username":"Utilizator","Password":"Parolă","Cancel":"Renunță","Connect":"Conectare","Type_in_the_full_username_":"Scrie numele complet al utilizatorului și un alias opțional.","Alias":"Alias","Add":"Adaugă","Subscription_request":"Cerere de subscriere","You_have_a_request_from":"Ai o cerere de la","Deny":"Refuză","Approve":"Aprobă","Remove_buddy":"Șterge contact","You_are_about_to_remove_":"Urmează să ștergi __bid_name__ (<b>__bid_jid__</b>) din lista de contacte. Toate chat-urile asociate vor fi închise.","Continue_without_chat":"Continuă fără chat","Please_wait":"Te rog așteaptă","Login_failed":"Logarea pe chat a eșuat","Sorry_we_cant_authentikate_":"Autentificarea cu serverul de chat a eșuat. Poate parola este greșită ?","Retry":"Înapoi","clear_history":"Curăță istoria","New_message_from":"Un nou mesaj de la __name__","Should_we_notify_you_":"Vrei să fi notificat despre mesajele noi în viitor ?","Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null,"_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"ru":{"translation":{"Logging_in":"Вход в систему...","your_connection_is_unencrypted":"Ваше соединение не зашифровано.","your_connection_is_encrypted":"Ваше соединение зашифровано.","your_buddy_closed_the_private_connection":"Ваш собеседник закончил зашифрованное соединение.","start_private":"Начать зашифрованный чат","close_private":"Закончить зашифрованный чат","your_buddy_is_verificated":"Собеседник подтвержден.","you_have_only_a_subscription_in_one_way":"У вас только односторонняя подписка.","authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":"Сообщение не отправлено. Завершите зашифрованный чат, пожалуйста.","unencrypted_message_received":"Получено незашифрованное сообщение","not_available":"Не доступен","no_connection":"Нет соединения!","relogin":"переподключиться","trying_to_start_private_conversation":"Попытка начать зашифрованный чат!","Verified":"Подтверждено","Unverified":"Не подтверждено","private_conversation_aborted":"Зашифрованный чат отклонен!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Ваш собеседник завершил зашифрованный чат! Вы должны сделать тоже самое.","conversation_is_now_verified":"Чат теперь утвержден.","authentication_failed":"Ошибка авторизации.","Creating_your_private_key_":"Создается приватный ключ. Это может занять некоторое время","Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":"Выберите метод...","Manual":"Вручную","Question":"Вопрос","Secret":"Пароль","To_verify_the_fingerprint_":null,"Your_fingerprint":"Ваш отпечаток","Buddy_fingerprint":"Отпечаток собеседника","Close":"Закрыть","Compared":"Сравнение завершено","To_authenticate_using_a_question_":"Для авторизации с помощью вопроса выберите вопрос, ответ на который знаете только Вы и собеседник.","Ask":null,"To_authenticate_pick_a_secret_":"Для авторизации выберите пароль, который знаете только Вы и собеседник.","Compare":"Сравнить","Fingerprints":"Отпечатки","Authentication":"Авторизация","Message":"Сообщение","Add_buddy":"Добавить контакт","rename_buddy":"переименовать контакт","delete_buddy":"удалить контакт","Login":"Вход","Username":"Логин","Password":"Пароль","Cancel":"Отмена","Connect":"Подключить","Type_in_the_full_username_":"Введите полное имя пользователя и дополнительный псевдоним","Alias":"Псевдоним","Add":"Добавить","Subscription_request":"Запрос подписки","You_have_a_request_from":"Получен запрос от","Deny":"Отказ","Approve":"Подтвердить","Remove_buddy":"Удалить контакт","You_are_about_to_remove_":"Вы собираетесь удалить __bid_name__ (<b>__bid_jid__</b>) из списка контактов. Все связанные с чаты будут закрыты.","Continue_without_chat":"Продолжить без чата","Please_wait":"Подождите…","Login_failed":"Неудачный вход в чат","Sorry_we_cant_authentikate_":"Неудачная попытка входа","Retry":"Назад","clear_history":"Очистить историю","New_message_from":"Новое сообщение от __name__","Should_we_notify_you_":"Уведомлять о новых сообщениях в будущем?","Please_accept_":"Нажмите кнопку \"Разрешить\" вверху страницы, пожалуйста","Hide_offline":"Спрятать отключенных","Show_offline":"Показать отключенных","About":"О проекте","dnd":"Не беспокоить","Mute":"Выкл. уведомления","Unmute":"Вкл. уведомления","Subscription":"Подписка","both":"оба","Status":"Статус","online":"в сети","chat":"готов общаться","away":"отошел","xa":"отсутствую","offline":"не в сети","none":"нет","Unknown_instance_tag":"Неизвестный тег.","Not_one_of_our_latest_keys":"Ни один из наших последних ключей","Received_an_unreadable_encrypted_message":"Получено нечитаемое зашифрованное сообщение","Online":"В сети","Chatty":"Готов общаться","Away":"Отошел","Extended_away":"Отсутствую","Offline":"Не в сети","Friendship_request":"Запрос на добавление в контакты","Confirm":"Подтвердить","Dismiss":"Отклонить","Remove":"Удалить","Online_help":"Онлайн помощь","FN":"Полное имя","N":null,"FAMILY":"Фамилия","GIVEN":"Имя","NICKNAME":"Ник","URL":"URL","ADR":"Адрес","STREET":"Улица","EXTADD":"Дополнительный адрес","LOCALITY":"Город","REGION":"Область","PCODE":"Индекс","CTRY":"Страна","TEL":"Телефон","NUMBER":"Номер","EMAIL":"Почта","USERID":null,"ORG":"Организация","ORGNAME":"Название","ORGUNIT":"Отдел","TITLE":"Должность","ROLE":"Обязанности","BDAY":"День рождения","DESC":"Описание","PHOTO":" Фото ","send_message":"Отправить сообщение","get_info":"Показать информацию","Settings":"Настройки","Priority":"Приоритет","Save":"Сохранить","User_settings":"Пользовательские настройки","A_fingerprint_":null,"is":" ","Login_options":"Параметры входа","BOSH_url":"BOSH URL","Domain":"Домен","Resource":"Ресурс","On_login":"Автоматически подключаться","Received_an_unencrypted_message":"Получено незашифрованное сообщение","Sorry_your_buddy_doesnt_provide_any_information":"К сожалению, контакт не предоставил какой-либо информации.","Info_about":"Информация о","Authentication_aborted":"Аутентификация прервана.","Authentication_request_received":"Получен запрос проверки подлинности.","Log_in_without_chat":"Вход без чата","has_come_online":"появился в сети","Unknown_sender":"Неизвестный отправитель","Please_allow_access_to_microphone_and_camera":"Нажмите кнопку \"Разрешить\" вверху страницы, чтобы предоставить доступ к микрофону и камере.","Incoming_call":"Входящий вызов","from":"от","Do_you_want_to_accept_the_call_from":"Вы хотите принять вызов от","Reject":"Отклонить","Accept":"Принять","hang_up":"Завершить","snapshot":"Снимок","mute_my_audio":"Без звука","pause_my_video":"Остановить моё видео","fullscreen":"На весь экран","Info":"Инфо","Local_IP":"Мой IP","Remote_IP":"Удаленный IP","Local_Fingerprint":"Мой отпечаток","Remote_Fingerprint":"Удаленный отпечаток","Video_call_not_possible":"Видео-вызов невозможен. Ваш собеседник не поддерживает видео-вызовы.","Start_video_call":"Видео-вызов","Join_chat":"Присоединиться к комнате","Join":"Присоедениться","Room":"Комната","Nickname":"Ник","left_the_building":"__nickname__ выходит из комнаты","entered_the_room":"__nickname__ заходит в комнату","is_now_known_as":"__oldNickname__ теперь известен как __newNickname__","This_room_is":"Эта комната","muc_hidden":{"keyword":"скрыта","description":"не может быть найдена через поиск"},"muc_membersonly":{"keyword":"только для участников","description":"Вы должны быть в списке участников"},"muc_moderated":{"keyword":"модерируется","description":"Только пользователи с правом голоса могут отправлять сообщения"},"muc_nonanonymous":{"keyword":"неанонимная","description":"Ваш JID будет показан всем посетителям"},"muc_open":{"keyword":"открытая","description":"Любой пользователь может присоедениться"},"muc_passwordprotected":{"keyword":"защищена паролем","description":"Необходимо ввести правильный пароль"},"muc_persistent":{"keyword":"постоянная","description":"Не будет уничтожена, когда ее покинут все участники"},"muc_public":{"keyword":"публичная","description":"Может быть найдена через поиск"},"muc_semianonymous":{"keyword":"полу-анонимная","description":"Ваш JID могут увидеть только администраторы"},"muc_temporary":{"keyword":"временная","description":"Будет уничтожена как только не останется ни одного участника"},"muc_unmoderated":{"keyword":"не модерируется","description":"Любой посетитель может отправлять сообщения"},"muc_unsecured":{"keyword":"без пароля","description":"Не нужно вводить пароль для входа"},"Continue":"Далее","Server":"Сервер","Rooms_are_loaded":"Комнаты загружены","Could_load_only":"Подгрузка только __count__ комнат в автодополнении","muc_explanation":"Введите название комнаты, свой ник и пароль для входа в комнату","You_already_joined_this_room":"Вы уже в этой комнате","This_room_will_be_closed":"Эта комната была закрыта","Room_not_found_":"Новая комната будет создана","Loading_room_information":"Загрузка информации о комнате","Destroy":"Уничтожить","Leave":"Покинуть","changed_subject_to":"__nickname__ изменил тему комнаты на \"__subject__\"","muc_removed_kicked":"Вас выкинули из комнаты","muc_removed_info_kicked":"__nickname__ был удален из комнаты","muc_removed_banned":"Вас забанили в комнате","muc_removed_info_banned":"__nickname__ был забанен в комнате","muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":"Вы были исключены из комнаты, т.к. комната стала доступна только для членов комнаты, а Вы им не являетесь","muc_removed_info_membersonly":"__nickname__ исключен(а) из комнаты, т.к. комната стала доступна только для членов комнаты, а он(она) им не является","muc_removed_shutdown":"Вы были удалены из комнаты, т.к. сервис чат-комнат недоступен","Reason":"Причина","message_not_send":"Ваше сообщение не было отправлено из-за ошибки","message_not_send_item-not-found":"Ваше сообщение не было отправлено, т.к. этой комнаты не существует","message_not_send_forbidden":"Ваше сообщение не было отправлено, т.к. у Вас нет права голоса в этой комнате","message_not_send_not-acceptable":"Ваше сообщение не было отправлено, т.к. Вы не являетесь участником этой комнаты","This_room_has_been_closed":"Эта комната была закрыта","Room_logging_is_enabled":"Журналирование комнаты включено","A_password_is_required":"Необходим пароль","You_are_not_on_the_member_list":"Вы не в списке участников","You_are_banned_from_this_room":"Вас забанили в этой комнате","Your_desired_nickname_":"Данное имя пользователя уже занято, пожалуйста, выберите другое имя пользователя","The_maximum_number_":"Достигнут лимит максимального количества посетителей этой комнаты","This_room_is_locked_":"Эта комната заблокирована","You_are_not_allowed_to_create_":"Вы не можете создавать комнаты","Alert":"Внимание","Call_started":"Вызов начался","Call_terminated":"Вызов завершен","Carbon_copy":"Копировать сообщения","Enable":"Включить","jingle_reason_busy":"занято","jingle_reason_decline":"запрещено","jingle_reason_success":"сбросили","Media_failure":"Ошибка передачи медиа","No_local_audio_device":"Нет локального аудио-устройства.","No_local_video_device":"Нет локального видео-устройства.","Ok":"Ок","PermissionDeniedError":"Вы или Ваш браузер запретили использовать микрофон/камеру","Use_local_audio_device":"Использовать локальное аудио-устройство.","Use_local_video_device":"Использовать локальное видео-устройство.","is_":"__status__","You_received_a_message_from_an_unknown_sender_":"Вы получили сообщение от неизвестного отправителя (__sender__)","Your_roster_is_empty_add_":"Ваш список контактов пуст, добавить <a>новый контакт</a>","onsmp_explanation_question":"Собеседник пытается определить, что общается действительно с Вами.","onsmp_explanation_secret":"Собеседник пытается определить, что общается действительно с Вами. введите пароль.","from_sender":"от __sender__","Verified_private_conversation_started":"Подтверждено Зашифрованный чат начат.","Unverified_private_conversation_started":"Не подтверждено Зашифрованный чат начат.","Bookmark":"Закладка","Auto-join":"Автоматически входить","Edit_bookmark":"Редактировать закладку","Room_logging_is_disabled":"Журналирование комнаты отключено","Room_is_now_non-anoymous":"Комната теперь не анонимная","Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":"Вы хотите изменить стандартную конфигурацию комнаты?","Default":"Станд.","Change":"Изменить","Send_file":"Отправить файл","setting-explanation-carbon":"С включенным Carbon Copy Ваш XMPP сервер будет отправлять копию каждого входящего сообщения на все подключенные устройства.","setting-explanation-login":"Если эта опция включена, то чат будет начинаться сразу после аутентификации.","setting-explanation-priority":"Если вы подключены к одному аккаунту с нескольких устройств, то XMPP сервер будет доставлять сообщения на клиент с наивысшим приоритетом.","setting-explanation-xmpp":"Эти настройки используются для подключения к XMPP серверу.","_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"sv-SE":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null,"_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"tr-TR":{"translation":{"Logging_in":"Giriş yapılıyor…","your_connection_is_unencrypted":"Bağlantınız şifrelenmemiş.","your_connection_is_encrypted":"Bağlantınız şifrelenmiş.","your_buddy_closed_the_private_connection":"Sohbet ettiğiniz kişi özel bağlantı kapatıldı.","start_private":"Özel bağlantı başlat.","close_private":"Özel bağlantıyı kapat.","your_buddy_is_verificated":"Kişi doğrulandı.","you_have_only_a_subscription_in_one_way":"Sadece tek yönlü bir aboneliğiniz var.","authentication_query_sent":"Kimlik doğrulama sorgusu gönderildi.","your_message_wasnt_send_please_end_your_private_conversation":"Mesajınız gönderilmedi. Lütfen özel görüşmelerinizi bitirin.","unencrypted_message_received":"Şifrelenmemiş mesaj alındı","not_available":"Müsait değil","no_connection":"Bağlantı yok!","relogin":"Yeniden gir","trying_to_start_private_conversation":"Özel sohbet başlatılmaya çalışılıyor!","Verified":"Doğrulandı","Unverified":"Doğrulanamadı","private_conversation_aborted":"Özel sohbet iptal edildi!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"Sohbet ettiğiniz kişi özel görüşmeyi kapattı! Siz de aynı şeyi yapmalısınız.","conversation_is_now_verified":"Sohbet doğrulandı.","authentication_failed":"Kimlik doğrulama başarısız.","Creating_your_private_key_":"Özel anahtarınız oluşturuluyor; bu işlem biraz sürebilir.","Authenticating_a_buddy_helps_":"Kimlik doğrulaması, konuşmakta olduğunuz kişinin gerçekten o kişi olduğundan emin olmanıza yardımcı olur.","How_do_you_want_to_authenticate_your_buddy":"Kimlik doğrulasını nasıl yapmak istersiniz __bid_name__ (<b>__bid_jid__</b>)?","Select_method":"Yöntemi seçin...","Manual":"Elle","Question":"Soru","Secret":"Gizli anahtar","To_verify_the_fingerprint_":"Parmakizini doğrulamak için, telefon gibi başka bir güvenilir kanalı kullanın.","Your_fingerprint":"Parmakiziniz","Buddy_fingerprint":"Kişinin parmakizi","Close":"Kapat","Compared":"Kıyaslandı","To_authenticate_using_a_question_":"Bir soru ile kimlik doğrulaması için, yanıtını yalnızca siz ve karşınızdaki kişinin bildiği bir soru seçin.","Ask":"Sor","To_authenticate_pick_a_secret_":"Kimlik doğrulaması için, yalnızca siz ve karşınızdaki kişinin bildiği bir parola seçin.","Compare":"Karşılaştır","Fingerprints":"Parmakizleri","Authentication":"Kimlik doğrulama","Message":"İleti","Add_buddy":"Kişi ekle","rename_buddy":"Kişiyi yeniden adlandır","delete_buddy":"Kişiyi sil","Login":"Giriş","Username":"Kullanıcı adı","Password":"Şifre","Cancel":"iptal","Connect":"Bağlan","Type_in_the_full_username_":"Tam kullanıcı adını ve isteğe bağlı bir takma ad yazın.","Alias":"Takma ad","Add":"Ekle","Subscription_request":"Abonelik isteği","You_have_a_request_from":"Size gelen bir istek var","Deny":"Reddet","Approve":"Onayla","Remove_buddy":"Kişiyi çıkar","You_are_about_to_remove_":"__bid_name__ (<b>__bid_jid__</b>) adlı kişiyi listenizden çıkarmak üzeresiniz. Tüm ilişkili sohbetler kapanacak.","Continue_without_chat":"Sohbet etmeden devam et","Please_wait":"Lütfen bekleyin","Login_failed":"Sohbet girişi başarısız oldu","Sorry_we_cant_authentikate_":"Kimlik doğrulaması başarısız oldu. Şifreniz yanlış olabilir.","Retry":"Geri","clear_history":"Geçmişi sil","New_message_from":"__name__ adlı kişiden yeni bir mesaj aldınız","Should_we_notify_you_":"İleride aldığınız yeni mesajları size bildirelim mi?","Please_accept_":"Lütfen üstteki \"İzin ver\" düğmesini tıklayın.","Hide_offline":"Çevrimdışı kişileri gizle","Show_offline":"Çevrimdışı kişileri göster","About":"hakkında","dnd":"Rahatsız etmeyin","Mute":"Sessiz","Unmute":"Sesli","Subscription":"Üyelik","both":"her ikisi de","Status":"Durum","online":"çevrimiçi","chat":"sohbet","away":"uzakta","xa":"çok uzakta","offline":"çevrimdışı","none":"hiç biri","Unknown_instance_tag":"Bilinmeyen örnek etiketi.","Not_one_of_our_latest_keys":"En son anahtarlarımızdan biri değil.","Received_an_unreadable_encrypted_message":"Okunamayan şifrelenmiş bir mesaj alındı.","Online":"Çevrimiçi","Chatty":"Konuşkan","Away":"Uzakta","Extended_away":"Çok uzakta","Offline":"Çevrimdışı","Friendship_request":"İrtibat isteği","Confirm":"Onayla","Dismiss":"Reddet","Remove":"Çıkar","Online_help":"Çevrimiçi yardım","FN":"Tam adı","N":" ","FAMILY":"Soyadı","GIVEN":"Adı","NICKNAME":"Takma ad","URL":"URL","ADR":"Adres","STREET":"Sokak","EXTADD":"Genişletilmiş Adres","LOCALITY":"Yer","REGION":"Bölge","PCODE":"Posta Kodu","CTRY":"Ülke","TEL":"Telefon","NUMBER":"Numara","EMAIL":"Eposta","USERID":" ","ORG":"Organizasyon","ORGNAME":"İsim","ORGUNIT":"Birim","TITLE":"İş tenımı","ROLE":"Görevi","BDAY":"Doğum günü","DESC":"Tanım","PHOTO":" ","send_message":"İletiyi gönder","get_info":"Bilgileri göster","Settings":"Ayarlar","Priority":"Öncelik","Save":"Kaydet","User_settings":"Kullanıcı tercihleri","A_fingerprint_":"Parmak izi konuştuğunuz kişinin söylediği kişi olduğundan emin olmak için kullanılır.","is":"Eşit","Login_options":"Giriş seçenekleri","BOSH_url":"BOSH URL","Domain":"Alan adı","Resource":"Kaynak","On_login":"Girişte","Received_an_unencrypted_message":"Şifrelenmemiş bir mesaj alındı","Sorry_your_buddy_doesnt_provide_any_information":"Maalesef kişi her hangi bir bilgi sunmamış.","Info_about":"Bilinen özellikleri","Authentication_aborted":"Kimlik doğrulama iptal edildi.","Authentication_request_received":"Kimlik doğrulama isteği alındı.","Log_in_without_chat":"Sohbetsiz giriş yap","has_come_online":"Çevrimiçi oldu","Unknown_sender":"Bilinmeyen gönderen","Please_allow_access_to_microphone_and_camera":"Mikrofona ve kameraya erişime izin vermek için lütfen üstteki \"İzin Ver\" düğmesini tıklayın.","Incoming_call":"Gelen çağrı","from":"gönderen","Do_you_want_to_accept_the_call_from":"Gelen aramayı kabul etmek istiyor musunuz","Reject":"Reddet","Accept":"Kabul et","hang_up":"aramayı sonlandır","snapshot":"anlık fotoğraf","mute_my_audio":"Sesi kapat","pause_my_video":"videoyu duraklat","fullscreen":"tam ekran","Info":"bilgi","Local_IP":"Yerel IP","Remote_IP":"Uzak IP","Local_Fingerprint":"Yerel parmakizi","Remote_Fingerprint":"Uzak parmakizi","Video_call_not_possible":"Video çağrısı yapılamıyor. Aranan kişi video görüşmelerini desteklemiyor.","Start_video_call":"Video görüşmesini başlat","Join_chat":"Sohbete katıl","Join":"Katıl","Room":"Oda","Nickname":"Takma ad","left_the_building":"__nickname__ binadan ayrıldı","entered_the_room":"__nickname__ odaya girdi","is_now_known_as":"__oldNickname__ şimdi __newNickname__ olarak biliniyor","This_room_is":"Bu oda","muc_hidden":{"keyword":"gizli","description":"Arama yoluyla bulunamıyor"},"muc_membersonly":{"keyword":"sadece-üye-olanlar","description":"üye listenizde olmanız gerekiyor"},"muc_moderated":{"keyword":"yöneticili","description":"Yalnızca \"sesli\" kişilerin mesaj göndermesine izin verilir"},"muc_nonanonymous":{"keyword":"Anonim-değil","description":"Sohbet kimliğiniz diğer tüm oturanlara görünüyor"},"muc_open":{"keyword":"açık","description":"herkes katılabilir"},"muc_passwordprotected":{"keyword":"şifre-korumalı","description":"Doğru şifreyi girmeniz gerekiyor"},"muc_persistent":{"keyword":"kalıcı","description":"Son oturan ayrıldığında kapanmaz"},"muc_public":{"keyword":"herkese açık","description":"Arama yoluyla bulunabilir"},"muc_semianonymous":{"keyword":"yarı-anonim","description":"Sohbet kimliğiniz sadece oda yöneticilerine görünüyor"},"muc_temporary":{"keyword":"geçici","description":"Son oturan ayrıldığında kapanır"},"muc_unmoderated":{"keyword":"yöneticisiz","description":"herkes ileti gönderebilir"},"muc_unsecured":{"keyword":"güvensiz","description":"şifre girmenize gerek yok"},"Continue":"Devam","Server":"Sunucu","Rooms_are_loaded":"Oda yüklendi","Could_load_only":"Sadece __count__ oda otomatik tamamlamayla yüklenebilir","muc_explanation":"Bir sohbete katılmak için, lütfen oda adını ve isteniyorsa takma adınız ve parolanızı girin","You_already_joined_this_room":"Zaten bu odaya katılmış durumdasınız","This_room_will_be_closed":"Bu oda kapanacak","Room_not_found_":"Yeni oda oluşturulacak","Loading_room_information":"Oda bilgileri yükleniyor","Destroy":"Sil","Leave":"Ayrıl","changed_subject_to":"__nickname__ bu odanın konusunu \"__subject__\" olarak değiştirdi","muc_removed_kicked":"Bu odadan atıldınız","muc_removed_info_kicked":"__nickname__ bu odadan atıldı","muc_removed_banned":"Odadan yasaklandınız","muc_removed_info_banned":"__nickname__ odadan yasaklandınız","muc_removed_affiliation":"Üyelik değişikliği nedeniyle odadan çıkarıldınız","muc_removed_info_affiliation":"__nickname__ üyelik değişikliği nedeniyle odadan çıkarıldı","muc_removed_membersonly":"Odanın durumu sadece-üyeler olarak değiştirildiği ve siz üye olmadığınız için odadan çıkarıldınız","muc_removed_info_membersonly":"Odanın durumu sadece-üyeler olarak değiştirildiği ve __nickname__ üye olmadığı için odadan çıkarıldı","muc_removed_shutdown":"Odadan çıkarıldınız çünkü, MUC sunucusu kapandı","Reason":"Sebep","message_not_send":"Mesajınız bir hata nedeniyle gönderilmedi","message_not_send_item-not-found":"Mesajınız gönderilmedi, çünkü bu oda mevcut değil","message_not_send_forbidden":"Mesajınız gönderilmedi çünkü bu odada sesiniz yok","message_not_send_not-acceptable":"Mesajınız gönderilmedi çünkü bu odaya bulunmuyorsunuz","This_room_has_been_closed":"Bu oda kapatıldı","Room_logging_is_enabled":"Oda günlüğü etkinleştirildi","A_password_is_required":"Şifre gerekli","You_are_not_on_the_member_list":"Üye listesinde değilsiniz","You_are_banned_from_this_room":"Bu odadan yasaklandınız","Your_desired_nickname_":"İstediğiniz takma ad başkası tarafından kullanılıyor. Lütfen başka bir takma ad","The_maximum_number_":"Bu odada maksimum kullanıcı sayısına ulaşıldı","This_room_is_locked_":"Bu oda kilitli","You_are_not_allowed_to_create_":"Oda açma izniniz yok","Alert":"Uyarı","Call_started":"Arama başlatıldı","Call_terminated":"Arama bitirildi","Carbon_copy":"Karbon kopya","Enable":"Etkinleştir","jingle_reason_busy":"meşgul","jingle_reason_decline":"kabul etme","jingle_reason_success":"kapatıldı","Media_failure":"Medya istek hatası","No_local_audio_device":"Yerel ses cihazı bulunamadı.","No_local_video_device":"Yerel video cihazı bulunamadı.","Ok":"Tamam","PermissionDeniedError":"Siz veya tarayıcınız sesli/görüntülü izni reddetti","Use_local_audio_device":"Yerel video cihazını kullan.","Use_local_video_device":"Yerel video cihazını kullanın.","is_":"__status__","You_received_a_message_from_an_unknown_sender_":"Bilinmeyen bir gönderenden bir ileti aldınız (__sender__) İletiyi görüntülemek istiyor musunuz?","Your_roster_is_empty_add_":"Listeniz boş, yeni bir <a>kişi ekleyin</a>","onsmp_explanation_question":"Karşınızdaki kişi, konuştuğu kişinin gerçekten siz olduğunuzu belirlemeye çalışıyor. Karşınızdaki kişiye kimliğinizi kanıtlamak için, yanıtı girin ve Yanıtla'yı tıklayın.","onsmp_explanation_secret":"Karşınızdaki kişi, konuştuğu kişinin gerçekten siz olduğunuzu belirlemeye çalışıyor. Karşınızdaki kişiye kimliğinizi kanıtlamak için, parolayı girin.","from_sender":"__sender__'den","Verified_private_conversation_started":"Doğrulanmış Özel görüşme başladı.","Unverified_private_conversation_started":"Doğrulanmamış Özel görüşme başladı.","Bookmark":"Yer imi","Auto-join":"Otomatik katıl","Edit_bookmark":"yer imini düzenle","Room_logging_is_disabled":"Oda günlüğü devre dışı","Room_is_now_non-anoymous":"Oda artık anonim değil","Room_is_now_semi-anonymous":"Oda yarı-anonim","Do_you_want_to_change_the_default_room_configuration":"Öntanımlı oda yapılandırmasını değiştirmek istiyor musunuz?","Default":"Öntanımlı","Change":"Değiştir","Send_file":"Dosya gönder","setting-explanation-carbon":"Etkinleştirilmiş karbon kopya ile, XMPP sunucusu kendisine gönderilen her iletinin bir kopyasını, bu adrese gönderilmemiş olsa bile sizin için bu istemciye gönderir.","setting-explanation-login":"Bu seçenek etkinleştirilirse, sohbet girişle beraber başlayacaktır.","setting-explanation-priority":"Aynı hesapla bir çok kez oturum açtıysanız, XMPP sunucusu, istemciye iletileri en yüksek öncelikle gönderecektir.","setting-explanation-xmpp":"Bu seçenekler XMPP sunucusuna bağlanmak için kullanılır.","_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"vi-VN":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null,"_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}},"zh-TW":{"translation":{"Logging_in":"正在登入…","your_connection_is_unencrypted":"連線沒加密。","your_connection_is_encrypted":"連線有加密。","your_buddy_closed_the_private_connection":"聯絡人關閉了加密連線。","start_private":"開始加密","close_private":"結束加密","your_buddy_is_verificated":"聯絡人已校驗。","you_have_only_a_subscription_in_one_way":"只有單向訂閱。","authentication_query_sent":"驗證要求送出了。","your_message_wasnt_send_please_end_your_private_conversation":"訊息沒送出去。請結束加密的對話。","unencrypted_message_received":"收到沒加密的訊息","not_available":"不存在","no_connection":"沒有連線!","relogin":"重新登入","trying_to_start_private_conversation":"正在試著開始加密的對話!","Verified":"已校驗","Unverified":"未校驗","private_conversation_aborted":"加密的對話中斷了!","your_buddy_closed_the_private_conversation_you_should_do_the_same":"聯絡人把這場加密的對話關掉了!你也應該同樣關掉。","conversation_is_now_verified":"對話現在校驗過了。","authentication_failed":"驗證失敗。","Creating_your_private_key_":"正在產生你的私人金鑰,會花一段時間。","Authenticating_a_buddy_helps_":"聯絡人驗證可以確保跟你說話的是真的那個人。","How_do_you_want_to_authenticate_your_buddy":"想要怎樣驗證__bid_name__ (<b>__bid_jid__</b>)?","Select_method":"選個方式...","Manual":"手動","Question":"問答","Secret":"祕密","To_verify_the_fingerprint_":"要校驗聯絡人的電子指紋,請透過其他可靠的管道跟她/他聯絡,比如說電話。","Your_fingerprint":"你的電子指紋","Buddy_fingerprint":"聯絡人的電子指紋","Close":"關閉","Compared":"比對正確","To_authenticate_using_a_question_":"要用問答來驗證的話,請找一個只有你和聯絡人才知道答案的問題。","Ask":"問題","To_authenticate_pick_a_secret_":"要驗證的話,請找一個只有你和聯絡人知道的祕密。","Compare":"比對","Fingerprints":"電子指紋","Authentication":"驗證","Message":"訊息","Add_buddy":"加聯絡人","rename_buddy":"重新命名聯絡人","delete_buddy":"刪掉聯絡人","Login":"登入","Username":"使用者名稱","Password":"密碼","Cancel":"取消","Connect":"連線","Type_in_the_full_username_":"請打全名,別名可有可無","Alias":"別名","Add":"加入","Subscription_request":"訂閱請求","You_have_a_request_from":"收到聯絡人的請求:","Deny":"拒絕","Approve":"同意","Remove_buddy":"刪除聯絡人","You_are_about_to_remove_":"要把__bid_name__ (<b>__bid_jid__</b>)從聯絡簿裡刪掉了。所有相關的對話也都會關掉。","Continue_without_chat":"繼續不聊天","Please_wait":"請等一下","Login_failed":"登入聊天失敗","Sorry_we_cant_authentikate_":"跟聊天伺服器驗證失敗,會不會是密碼打錯了?","Retry":"上一步","clear_history":"清除歷史紀錄","New_message_from":"有新訊息:__name__","Should_we_notify_you_":"以後若有新訊息要通知你嗎?","Please_accept_":"請點上方的「允許」按鈕。","Hide_offline":"隱藏離線聯絡人","Show_offline":"顯示離線聯絡人","About":"關於我","dnd":"別打擾","Mute":"開靜音","Unmute":"關靜音","Subscription":"訂閱狀態","both":"雙向","Status":"狀態","online":"上線","chat":"聊天","away":"離開","xa":"離開很久","offline":"離線","none":"沒有","Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":"收到了一則加密但無法辨認的訊息。","Online":"上線","Chatty":"想聊天","Away":"離開","Extended_away":"離開很久","Offline":"離線","Friendship_request":"聯絡請求","Confirm":"確定","Dismiss":"取消","Remove":"刪掉","Online_help":"線上說明","FN":"全名","N":" ","FAMILY":"姓氏","GIVEN":"名字","NICKNAME":"綽號","URL":"網址","ADR":"位址","STREET":"地址","EXTADD":"更多位址","LOCALITY":"所在地","REGION":"區域","PCODE":"郵遞區號","CTRY":"國家","TEL":"電話","NUMBER":"編號","EMAIL":"電子郵件","USERID":" ","ORG":"團體","ORGNAME":"名稱","ORGUNIT":"單位","TITLE":"職稱","ROLE":"職位","BDAY":"生日","DESC":"簡介","PHOTO":" ","send_message":"發送訊息","get_info":"顯示帳號資訊","Settings":"設定","Priority":"優先度","Save":"儲存","User_settings":"使用者設定","A_fingerprint_":"電子指紋是用來確認跟你說話的是真的那個人。","is":"狀態:","Login_options":"登入選項","BOSH_url":"BOSH 網址","Domain":"網域","Resource":"資源","On_login":"登入啟動","Received_an_unencrypted_message":"收到了一則沒加密的訊息","Sorry_your_buddy_doesnt_provide_any_information":"抱歉,聯絡人沒有提供任何資訊。","Info_about":"帳號資訊:","Authentication_aborted":"驗證中斷。","Authentication_request_received":"驗證請求收到了。","Log_in_without_chat":"登入但不啟用聊天","has_come_online":"上線了","Unknown_sender":"不明傳訊人","Please_allow_access_to_microphone_and_camera":"請點上方的「接受」按鈕來允許我們使用麥克風和相機。","Incoming_call":"來電","from":"只出","Do_you_want_to_accept_the_call_from":"是否要接聽來電:","Reject":"拒絕","Accept":"接受","hang_up":"掛斷","snapshot":"截圖","mute_my_audio":"關掉我的聲音","pause_my_video":"暫停我的影像","fullscreen":"全螢幕","Info":"資料","Local_IP":"本機網路位址","Remote_IP":"遠端網路位址","Local_Fingerprint":"本機電子指紋","Remote_Fingerprint":"遠端電子指紋","Video_call_not_possible":"無法視訊通話。聯絡人不支援視訊。","Start_video_call":"開始視訊通話","Join_chat":"參加聊天","Join":"參加","Room":"聊天室","Nickname":"綽號","left_the_building":"__nickname__離開了大樓","entered_the_room":"__nickname__進入了聊天室","is_now_known_as":"__oldNickname__改名叫做__newNickname__","This_room_is":"聊天室屬性:","muc_hidden":{"keyword":"隱藏","description":"搜尋也找不到"},"muc_membersonly":{"keyword":"限會員","description":"會員才會加入"},"muc_moderated":{"keyword":"有管制","description":"沒被消音的人才能送訊息"},"muc_nonanonymous":{"keyword":"禁匿名","description":"每個參與人都能看到你的 jabber 代碼"},"muc_open":{"keyword":"開放","description":"任何人都能參加"},"muc_passwordprotected":{"keyword":"密碼鎖","description":"要輸入正確的密碼才能加入"},"muc_persistent":{"keyword":"永久性","description":"最後一個參與人都離開了也不會結束"},"muc_public":{"keyword":"公開","description":"搜尋得到"},"muc_semianonymous":{"keyword":"半匿名","description":"只有聊天室管理員才看得到你的 jabber 代碼"},"muc_temporary":{"keyword":"暫時性","description":"最後一個參與人離開了就會結束"},"muc_unmoderated":{"keyword":"沒管制","description":"每個人都可以送訊息"},"muc_unsecured":{"keyword":"沒保護","description":"不需要密碼就能加入"},"Continue":"繼續","Server":"伺服器","Rooms_are_loaded":"聊天室載入完成","Could_load_only":"只能載入__count__間聊天室供輸入自動完成使用","muc_explanation":"請輸入要參加的聊天室名稱,綽號和密碼非必要","You_already_joined_this_room":"你已經參加這間聊天室了","This_room_will_be_closed":"聊天室即將關閉","Room_not_found_":"新聊天室即將開啟","Loading_room_information":"正在載入聊天室資訊","Destroy":"關閉","Leave":"離開","changed_subject_to":"__nickname__把聊天室的標題改成了\"__subject__\"","muc_removed_kicked":"你被踢出聊天室了","muc_removed_info_kicked":"__nickname__被踢出聊天室了","muc_removed_banned":"你被禁止進入聊天室了","muc_removed_info_banned":"__nickname__被禁止進入聊天室了","muc_removed_affiliation":"你因為身份改變而離開聊天室了","muc_removed_info_affiliation":"__nickname__因為身份改變而離開聊天室了","muc_removed_membersonly":"你離開聊天室了,因為聊天室改為只限會員,但你不是會員","muc_removed_info_membersonly":"__nickname__離開聊天室了,因為聊天室改為只限會員,但她/他不是會員","muc_removed_shutdown":"你離開聊天室了,因為多人聊天服務正在關閉中。","Reason":"原因","message_not_send":"訊息因為發生錯誤沒送出去","message_not_send_item-not-found":"訊息沒送出去,因為聊天室不存在了","message_not_send_forbidden":"訊息沒送出去,因為你被消音了","message_not_send_not-acceptable":"訊息沒送出去,因為你不是聊天室的參與人了","This_room_has_been_closed":"聊天室已經關閉了","Room_logging_is_enabled":"聊天室紀錄打開了","A_password_is_required":"需要密碼","You_are_not_on_the_member_list":"你不是會員","You_are_banned_from_this_room":"你被禁止進入聊天室了","Your_desired_nickname_":"這個綽號被用掉了,請換一個","The_maximum_number_":"這間聊天室已經到達使用者數目的上限","This_room_is_locked_":"聊天室上鎖了","You_are_not_allowed_to_create_":"不允許你開新的聊天室","Alert":"警告","Call_started":"通話開始","Call_terminated":"通話結束","Carbon_copy":"副本","Enable":"打開","jingle_reason_busy":"忙線中","jingle_reason_decline":"被拒絕","jingle_reason_success":"被掛斷","Media_failure":"媒體錯誤","No_local_audio_device":"本機沒有音訊設備。","No_local_video_device":"本機沒有視訊設備。","Ok":"好","PermissionDeniedError":"你或你的瀏覽器拒絕了媒體使用權限","Use_local_audio_device":"使用本機音訊設備。","Use_local_video_device":"使用本機視訊設備。","is_":"狀態: __status__","You_received_a_message_from_an_unknown_sender_":"收到了不明人士(__sender__)傳來的訊息。你要打開來看嗎?","Your_roster_is_empty_add_":"好友清單是空的,請加<a>新的聯絡人</a>","onsmp_explanation_question":"聯絡人想要確定她/他是在跟真的你說話。要完成你的驗證,請輸入問題的答案,然後按\"回答\"。","onsmp_explanation_secret":"聯絡人想要確定她/他是在跟真的你說話。要完成你的驗證,請輸入你們之間的祕密。","from_sender":"來自:__sender__","Verified_private_conversation_started":"加密且已校驗的對話開始了。","Unverified_private_conversation_started":"加密但未校驗的對話開始了。","Bookmark":"書籤","Auto-join":"自動參加","Edit_bookmark":"編輯書籤","Room_logging_is_disabled":"聊天室紀錄關掉了","Room_is_now_non-anoymous":"現在聊天室禁止匿名了","Room_is_now_semi-anonymous":"現在聊天室變半匿名了","Do_you_want_to_change_the_default_room_configuration":"你想要改變聊天室的預設配置嗎?","Default":"預設值","Change":"修改","Send_file":"傳送檔案","setting-explanation-carbon":"如果打開副本選項的話,XMPP 伺服器會把每一個收到的訊息,都送一份到這個用戶端程式,即使它不是訊息發送的對象。","setting-explanation-login":"打開這個選項會在登入時同時開啟聊天。","setting-explanation-priority":"如果你用同一個帳號同時登入好幾次的話,XMPP 伺服器會把訊息送給優先度最高的那個用戶端程式。","setting-explanation-xmpp":"這些是用在 XMPP 伺服器連線的選項。","_is_composing":"正在打字中...","_are_composing":"正在打字中...","Chat_state_notifications":"聊天狀態通知","setting-explanation-chat-state":"想要傳送以及接收聊天狀態的通知嗎?也就是有人開始或停止寫訊息之類?","Share_screen":"分享螢幕","Incoming_stream":"有串流來","Stream_started":"串流開始了","HTTPS_REQUIRED":"這個動作需要連線有加密。","EXTENSION_UNAVAILABLE":"瀏覽器必須要安裝擴充套件或是附加元件。","UNKNOWN_ERROR":"發生了不明錯誤。","Install_extension":"要使用螢幕分享功能請安裝這個擴充套件: ","Connection_accepted":"連線接受了","Stream_terminated":"串流結束了","Close_all":null}},"zh":{"translation":{"Logging_in":null,"your_connection_is_unencrypted":null,"your_connection_is_encrypted":null,"your_buddy_closed_the_private_connection":null,"start_private":null,"close_private":null,"your_buddy_is_verificated":null,"you_have_only_a_subscription_in_one_way":null,"authentication_query_sent":null,"your_message_wasnt_send_please_end_your_private_conversation":null,"unencrypted_message_received":null,"not_available":null,"no_connection":null,"relogin":null,"trying_to_start_private_conversation":null,"Verified":null,"Unverified":null,"private_conversation_aborted":null,"your_buddy_closed_the_private_conversation_you_should_do_the_same":null,"conversation_is_now_verified":null,"authentication_failed":null,"Creating_your_private_key_":null,"Authenticating_a_buddy_helps_":null,"How_do_you_want_to_authenticate_your_buddy":null,"Select_method":null,"Manual":null,"Question":null,"Secret":null,"To_verify_the_fingerprint_":null,"Your_fingerprint":null,"Buddy_fingerprint":null,"Close":null,"Compared":null,"To_authenticate_using_a_question_":null,"Ask":null,"To_authenticate_pick_a_secret_":null,"Compare":null,"Fingerprints":null,"Authentication":null,"Message":null,"Add_buddy":null,"rename_buddy":null,"delete_buddy":null,"Login":null,"Username":null,"Password":null,"Cancel":null,"Connect":null,"Type_in_the_full_username_":null,"Alias":null,"Add":null,"Subscription_request":null,"You_have_a_request_from":null,"Deny":null,"Approve":null,"Remove_buddy":null,"You_are_about_to_remove_":null,"Continue_without_chat":null,"Please_wait":null,"Login_failed":null,"Sorry_we_cant_authentikate_":null,"Retry":null,"clear_history":null,"New_message_from":null,"Should_we_notify_you_":null,"Please_accept_":null,"Hide_offline":null,"Show_offline":null,"About":null,"dnd":null,"Mute":null,"Unmute":null,"Subscription":null,"both":null,"Status":null,"online":null,"chat":null,"away":null,"xa":null,"offline":null,"none":null,"Unknown_instance_tag":null,"Not_one_of_our_latest_keys":null,"Received_an_unreadable_encrypted_message":null,"Online":null,"Chatty":null,"Away":null,"Extended_away":null,"Offline":null,"Friendship_request":null,"Confirm":null,"Dismiss":null,"Remove":null,"Online_help":null,"FN":null,"N":null,"FAMILY":null,"GIVEN":null,"NICKNAME":null,"URL":null,"ADR":null,"STREET":null,"EXTADD":null,"LOCALITY":null,"REGION":null,"PCODE":null,"CTRY":null,"TEL":null,"NUMBER":null,"EMAIL":null,"USERID":null,"ORG":null,"ORGNAME":null,"ORGUNIT":null,"TITLE":null,"ROLE":null,"BDAY":null,"DESC":null,"PHOTO":null,"send_message":null,"get_info":null,"Settings":null,"Priority":null,"Save":null,"User_settings":null,"A_fingerprint_":null,"is":null,"Login_options":null,"BOSH_url":null,"Domain":null,"Resource":null,"On_login":null,"Received_an_unencrypted_message":null,"Sorry_your_buddy_doesnt_provide_any_information":null,"Info_about":null,"Authentication_aborted":null,"Authentication_request_received":null,"Log_in_without_chat":null,"has_come_online":null,"Unknown_sender":null,"Please_allow_access_to_microphone_and_camera":null,"Incoming_call":null,"from":null,"Do_you_want_to_accept_the_call_from":null,"Reject":null,"Accept":null,"hang_up":null,"snapshot":null,"mute_my_audio":null,"pause_my_video":null,"fullscreen":null,"Info":null,"Local_IP":null,"Remote_IP":null,"Local_Fingerprint":null,"Remote_Fingerprint":null,"Video_call_not_possible":null,"Start_video_call":null,"Join_chat":null,"Join":null,"Room":null,"Nickname":null,"left_the_building":null,"entered_the_room":null,"is_now_known_as":null,"This_room_is":null,"muc_hidden":{"keyword":null,"description":null},"muc_membersonly":{"keyword":null,"description":null},"muc_moderated":{"keyword":null,"description":null},"muc_nonanonymous":{"keyword":null,"description":null},"muc_open":{"keyword":null,"description":null},"muc_passwordprotected":{"keyword":null,"description":null},"muc_persistent":{"keyword":null,"description":null},"muc_public":{"keyword":null,"description":null},"muc_semianonymous":{"keyword":null,"description":null},"muc_temporary":{"keyword":null,"description":null},"muc_unmoderated":{"keyword":null,"description":null},"muc_unsecured":{"keyword":null,"description":null},"Continue":null,"Server":null,"Rooms_are_loaded":null,"Could_load_only":null,"muc_explanation":null,"You_already_joined_this_room":null,"This_room_will_be_closed":null,"Room_not_found_":null,"Loading_room_information":null,"Destroy":null,"Leave":null,"changed_subject_to":null,"muc_removed_kicked":null,"muc_removed_info_kicked":null,"muc_removed_banned":null,"muc_removed_info_banned":null,"muc_removed_affiliation":null,"muc_removed_info_affiliation":null,"muc_removed_membersonly":null,"muc_removed_info_membersonly":null,"muc_removed_shutdown":null,"Reason":null,"message_not_send":null,"message_not_send_item-not-found":null,"message_not_send_forbidden":null,"message_not_send_not-acceptable":null,"This_room_has_been_closed":null,"Room_logging_is_enabled":null,"A_password_is_required":null,"You_are_not_on_the_member_list":null,"You_are_banned_from_this_room":null,"Your_desired_nickname_":null,"The_maximum_number_":null,"This_room_is_locked_":null,"You_are_not_allowed_to_create_":null,"Alert":null,"Call_started":null,"Call_terminated":null,"Carbon_copy":null,"Enable":null,"jingle_reason_busy":null,"jingle_reason_decline":null,"jingle_reason_success":null,"Media_failure":null,"No_local_audio_device":null,"No_local_video_device":null,"Ok":null,"PermissionDeniedError":null,"Use_local_audio_device":null,"Use_local_video_device":null,"is_":null,"You_received_a_message_from_an_unknown_sender_":null,"Your_roster_is_empty_add_":null,"onsmp_explanation_question":null,"onsmp_explanation_secret":null,"from_sender":null,"Verified_private_conversation_started":null,"Unverified_private_conversation_started":null,"Bookmark":null,"Auto-join":null,"Edit_bookmark":null,"Room_logging_is_disabled":null,"Room_is_now_non-anoymous":null,"Room_is_now_semi-anonymous":null,"Do_you_want_to_change_the_default_room_configuration":null,"Default":null,"Change":null,"Send_file":null,"setting-explanation-carbon":null,"setting-explanation-login":null,"setting-explanation-priority":null,"setting-explanation-xmpp":null,"_is_composing":null,"_are_composing":null,"Chat_state_notifications":null,"setting-explanation-chat-state":null,"Share_screen":null,"Incoming_stream":null,"Stream_started":null,"HTTPS_REQUIRED":null,"EXTENSION_UNAVAILABLE":null,"UNKNOWN_ERROR":null,"Install_extension":null,"Connection_accepted":null,"Stream_terminated":null,"Close_all":null}}};
/*!
* Source: lib/favico.js/favico.js, license: MIT, url: https://github.com/ejci/favico.js
@@ -40477,7 +48602,7 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
/* jshint -W075 */
(function(ns){
// this list must be ordered from largest length of the value array, index 0, to the shortest
- ns.emojioneList = {':kiss_ww:':["1f469-200d-2764-fe0f-200d-1f48b-200d-1f469","1f469-2764-1f48b-1f469"],':couplekiss_ww:':["1f469-200d-2764-fe0f-200d-1f48b-200d-1f469","1f469-2764-1f48b-1f469"],':kiss_mm:':["1f468-200d-2764-fe0f-200d-1f48b-200d-1f468","1f468-2764-1f48b-1f468"],':couplekiss_mm:':["1f468-200d-2764-fe0f-200d-1f48b-200d-1f468","1f468-2764-1f48b-1f468"],':family_mmbb:':["1f468-200d-1f468-200d-1f466-200d-1f466","1f468-1f468-1f466-1f466"],':family_mmgb:':["1f468-200d-1f468-200d-1f467-200d-1f466","1f468-1f468-1f467-1f466"],':family_mmgg:':["1f468-200d-1f468-200d-1f467-200d-1f467","1f468-1f468-1f467-1f467"],':family_mwbb:':["1f468-200d-1f469-200d-1f466-200d-1f466","1f468-1f469-1f466-1f466"],':family_mwgb:':["1f468-200d-1f469-200d-1f467-200d-1f466","1f468-1f469-1f467-1f466"],':family_mwgg:':["1f468-200d-1f469-200d-1f467-200d-1f467","1f468-1f469-1f467-1f467"],':family_wwbb:':["1f469-200d-1f469-200d-1f466-200d-1f466","1f469-1f469-1f466-1f466"],':family_wwgb:':["1f469-200d-1f469-200d-1f467-200d-1f466","1f469-1f469-1f467-1f466"],':family_wwgg:':["1f469-200d-1f469-200d-1f467-200d-1f467","1f469-1f469-1f467-1f467"],':couple_ww:':["1f469-200d-2764-fe0f-200d-1f469","1f469-2764-1f469"],':couple_with_heart_ww:':["1f469-200d-2764-fe0f-200d-1f469","1f469-2764-1f469"],':couple_mm:':["1f468-200d-2764-fe0f-200d-1f468","1f468-2764-1f468"],':couple_with_heart_mm:':["1f468-200d-2764-fe0f-200d-1f468","1f468-2764-1f468"],':family_mmb:':["1f468-200d-1f468-200d-1f466","1f468-1f468-1f466"],':family_mmg:':["1f468-200d-1f468-200d-1f467","1f468-1f468-1f467"],':family_mwg:':["1f468-200d-1f469-200d-1f467","1f468-1f469-1f467"],':family_wwb:':["1f469-200d-1f469-200d-1f466","1f469-1f469-1f466"],':family_wwg:':["1f469-200d-1f469-200d-1f467","1f469-1f469-1f467"],':eye_in_speech_bubble:':["1f441-200d-1f5e8","1f441-1f5e8"],':hash:':["0023-fe0f-20e3","0023-20e3"],':zero:':["0030-fe0f-20e3","0030-20e3"],':one:':["0031-fe0f-20e3","0031-20e3"],':two:':["0032-fe0f-20e3","0032-20e3"],':three:':["0033-fe0f-20e3","0033-20e3"],':four:':["0034-fe0f-20e3","0034-20e3"],':five:':["0035-fe0f-20e3","0035-20e3"],':six:':["0036-fe0f-20e3","0036-20e3"],':seven:':["0037-fe0f-20e3","0037-20e3"],':eight:':["0038-fe0f-20e3","0038-20e3"],':nine:':["0039-fe0f-20e3","0039-20e3"],':asterisk:':["002a-fe0f-20e3","002a-20e3"],':keycap_asterisk:':["002a-fe0f-20e3","002a-20e3"],':metal_tone5:':["1f918-1f3ff"],':sign_of_the_horns_tone5:':["1f918-1f3ff"],':metal_tone4:':["1f918-1f3fe"],':sign_of_the_horns_tone4:':["1f918-1f3fe"],':metal_tone3:':["1f918-1f3fd"],':sign_of_the_horns_tone3:':["1f918-1f3fd"],':metal_tone2:':["1f918-1f3fc"],':sign_of_the_horns_tone2:':["1f918-1f3fc"],':metal_tone1:':["1f918-1f3fb"],':sign_of_the_horns_tone1:':["1f918-1f3fb"],':bath_tone5:':["1f6c0-1f3ff"],':bath_tone4:':["1f6c0-1f3fe"],':bath_tone3:':["1f6c0-1f3fd"],':bath_tone2:':["1f6c0-1f3fc"],':bath_tone1:':["1f6c0-1f3fb"],':walking_tone5:':["1f6b6-1f3ff"],':walking_tone4:':["1f6b6-1f3fe"],':walking_tone3:':["1f6b6-1f3fd"],':walking_tone2:':["1f6b6-1f3fc"],':walking_tone1:':["1f6b6-1f3fb"],':mountain_bicyclist_tone5:':["1f6b5-1f3ff"],':mountain_bicyclist_tone4:':["1f6b5-1f3fe"],':mountain_bicyclist_tone3:':["1f6b5-1f3fd"],':mountain_bicyclist_tone2:':["1f6b5-1f3fc"],':mountain_bicyclist_tone1:':["1f6b5-1f3fb"],':bicyclist_tone5:':["1f6b4-1f3ff"],':bicyclist_tone4:':["1f6b4-1f3fe"],':bicyclist_tone3:':["1f6b4-1f3fd"],':bicyclist_tone2:':["1f6b4-1f3fc"],':bicyclist_tone1:':["1f6b4-1f3fb"],':rowboat_tone5:':["1f6a3-1f3ff"],':rowboat_tone4:':["1f6a3-1f3fe"],':rowboat_tone3:':["1f6a3-1f3fd"],':rowboat_tone2:':["1f6a3-1f3fc"],':rowboat_tone1:':["1f6a3-1f3fb"],':pray_tone5:':["1f64f-1f3ff"],':pray_tone4:':["1f64f-1f3fe"],':pray_tone3:':["1f64f-1f3fd"],':pray_tone2:':["1f64f-1f3fc"],':pray_tone1:':["1f64f-1f3fb"],':person_with_pouting_face_tone5:':["1f64e-1f3ff"],':person_with_pouting_face_tone4:':["1f64e-1f3fe"],':person_with_pouting_face_tone3:':["1f64e-1f3fd"],':person_with_pouting_face_tone2:':["1f64e-1f3fc"],':person_with_pouting_face_tone1:':["1f64e-1f3fb"],':person_frowning_tone5:':["1f64d-1f3ff"],':person_frowning_tone4:':["1f64d-1f3fe"],':person_frowning_tone3:':["1f64d-1f3fd"],':person_frowning_tone2:':["1f64d-1f3fc"],':person_frowning_tone1:':["1f64d-1f3fb"],':raised_hands_tone5:':["1f64c-1f3ff"],':raised_hands_tone4:':["1f64c-1f3fe"],':raised_hands_tone3:':["1f64c-1f3fd"],':raised_hands_tone2:':["1f64c-1f3fc"],':raised_hands_tone1:':["1f64c-1f3fb"],':raising_hand_tone5:':["1f64b-1f3ff"],':raising_hand_tone4:':["1f64b-1f3fe"],':raising_hand_tone3:':["1f64b-1f3fd"],':raising_hand_tone2:':["1f64b-1f3fc"],':raising_hand_tone1:':["1f64b-1f3fb"],':bow_tone5:':["1f647-1f3ff"],':bow_tone4:':["1f647-1f3fe"],':bow_tone3:':["1f647-1f3fd"],':bow_tone2:':["1f647-1f3fc"],':bow_tone1:':["1f647-1f3fb"],':ok_woman_tone5:':["1f646-1f3ff"],':ok_woman_tone4:':["1f646-1f3fe"],':ok_woman_tone3:':["1f646-1f3fd"],':ok_woman_tone2:':["1f646-1f3fc"],':ok_woman_tone1:':["1f646-1f3fb"],':no_good_tone5:':["1f645-1f3ff"],':no_good_tone4:':["1f645-1f3fe"],':no_good_tone3:':["1f645-1f3fd"],':no_good_tone2:':["1f645-1f3fc"],':no_good_tone1:':["1f645-1f3fb"],':vulcan_tone5:':["1f596-1f3ff"],':raised_hand_with_part_between_middle_and_ring_fingers_tone5:':["1f596-1f3ff"],':vulcan_tone4:':["1f596-1f3fe"],':raised_hand_with_part_between_middle_and_ring_fingers_tone4:':["1f596-1f3fe"],':vulcan_tone3:':["1f596-1f3fd"],':raised_hand_with_part_between_middle_and_ring_fingers_tone3:':["1f596-1f3fd"],':vulcan_tone2:':["1f596-1f3fc"],':raised_hand_with_part_between_middle_and_ring_fingers_tone2:':["1f596-1f3fc"],':vulcan_tone1:':["1f596-1f3fb"],':raised_hand_with_part_between_middle_and_ring_fingers_tone1:':["1f596-1f3fb"],':middle_finger_tone5:':["1f595-1f3ff"],':reversed_hand_with_middle_finger_extended_tone5:':["1f595-1f3ff"],':middle_finger_tone4:':["1f595-1f3fe"],':reversed_hand_with_middle_finger_extended_tone4:':["1f595-1f3fe"],':middle_finger_tone3:':["1f595-1f3fd"],':reversed_hand_with_middle_finger_extended_tone3:':["1f595-1f3fd"],':middle_finger_tone2:':["1f595-1f3fc"],':reversed_hand_with_middle_finger_extended_tone2:':["1f595-1f3fc"],':middle_finger_tone1:':["1f595-1f3fb"],':reversed_hand_with_middle_finger_extended_tone1:':["1f595-1f3fb"],':hand_splayed_tone5:':["1f590-1f3ff"],':raised_hand_with_fingers_splayed_tone5:':["1f590-1f3ff"],':hand_splayed_tone4:':["1f590-1f3fe"],':raised_hand_with_fingers_splayed_tone4:':["1f590-1f3fe"],':hand_splayed_tone3:':["1f590-1f3fd"],':raised_hand_with_fingers_splayed_tone3:':["1f590-1f3fd"],':hand_splayed_tone2:':["1f590-1f3fc"],':raised_hand_with_fingers_splayed_tone2:':["1f590-1f3fc"],':hand_splayed_tone1:':["1f590-1f3fb"],':raised_hand_with_fingers_splayed_tone1:':["1f590-1f3fb"],':spy_tone5:':["1f575-1f3ff"],':sleuth_or_spy_tone5:':["1f575-1f3ff"],':spy_tone4:':["1f575-1f3fe"],':sleuth_or_spy_tone4:':["1f575-1f3fe"],':spy_tone3:':["1f575-1f3fd"],':sleuth_or_spy_tone3:':["1f575-1f3fd"],':spy_tone2:':["1f575-1f3fc"],':sleuth_or_spy_tone2:':["1f575-1f3fc"],':spy_tone1:':["1f575-1f3fb"],':sleuth_or_spy_tone1:':["1f575-1f3fb"],':muscle_tone5:':["1f4aa-1f3ff"],':muscle_tone4:':["1f4aa-1f3fe"],':muscle_tone3:':["1f4aa-1f3fd"],':muscle_tone2:':["1f4aa-1f3fc"],':muscle_tone1:':["1f4aa-1f3fb"],':haircut_tone5:':["1f487-1f3ff"],':haircut_tone4:':["1f487-1f3fe"],':haircut_tone3:':["1f487-1f3fd"],':haircut_tone2:':["1f487-1f3fc"],':haircut_tone1:':["1f487-1f3fb"],':massage_tone5:':["1f486-1f3ff"],':massage_tone4:':["1f486-1f3fe"],':massage_tone3:':["1f486-1f3fd"],':massage_tone2:':["1f486-1f3fc"],':massage_tone1:':["1f486-1f3fb"],':nail_care_tone5:':["1f485-1f3ff"],':nail_care_tone4:':["1f485-1f3fe"],':nail_care_tone3:':["1f485-1f3fd"],':nail_care_tone2:':["1f485-1f3fc"],':nail_care_tone1:':["1f485-1f3fb"],':dancer_tone5:':["1f483-1f3ff"],':dancer_tone4:':["1f483-1f3fe"],':dancer_tone3:':["1f483-1f3fd"],':dancer_tone2:':["1f483-1f3fc"],':dancer_tone1:':["1f483-1f3fb"],':guardsman_tone5:':["1f482-1f3ff"],':guardsman_tone4:':["1f482-1f3fe"],':guardsman_tone3:':["1f482-1f3fd"],':guardsman_tone2:':["1f482-1f3fc"],':guardsman_tone1:':["1f482-1f3fb"],':information_desk_person_tone5:':["1f481-1f3ff"],':information_desk_person_tone4:':["1f481-1f3fe"],':information_desk_person_tone3:':["1f481-1f3fd"],':information_desk_person_tone2:':["1f481-1f3fc"],':information_desk_person_tone1:':["1f481-1f3fb"],':angel_tone5:':["1f47c-1f3ff"],':angel_tone4:':["1f47c-1f3fe"],':angel_tone3:':["1f47c-1f3fd"],':angel_tone2:':["1f47c-1f3fc"],':angel_tone1:':["1f47c-1f3fb"],':princess_tone5:':["1f478-1f3ff"],':princess_tone4:':["1f478-1f3fe"],':princess_tone3:':["1f478-1f3fd"],':princess_tone2:':["1f478-1f3fc"],':princess_tone1:':["1f478-1f3fb"],':construction_worker_tone5:':["1f477-1f3ff"],':construction_worker_tone4:':["1f477-1f3fe"],':construction_worker_tone3:':["1f477-1f3fd"],':construction_worker_tone2:':["1f477-1f3fc"],':construction_worker_tone1:':["1f477-1f3fb"],':baby_tone5:':["1f476-1f3ff"],':baby_tone4:':["1f476-1f3fe"],':baby_tone3:':["1f476-1f3fd"],':baby_tone2:':["1f476-1f3fc"],':baby_tone1:':["1f476-1f3fb"],':older_woman_tone5:':["1f475-1f3ff"],':grandma_tone5:':["1f475-1f3ff"],':older_woman_tone4:':["1f475-1f3fe"],':grandma_tone4:':["1f475-1f3fe"],':older_woman_tone3:':["1f475-1f3fd"],':grandma_tone3:':["1f475-1f3fd"],':older_woman_tone2:':["1f475-1f3fc"],':grandma_tone2:':["1f475-1f3fc"],':older_woman_tone1:':["1f475-1f3fb"],':grandma_tone1:':["1f475-1f3fb"],':older_man_tone5:':["1f474-1f3ff"],':older_man_tone4:':["1f474-1f3fe"],':older_man_tone3:':["1f474-1f3fd"],':older_man_tone2:':["1f474-1f3fc"],':older_man_tone1:':["1f474-1f3fb"],':man_with_turban_tone5:':["1f473-1f3ff"],':man_with_turban_tone4:':["1f473-1f3fe"],':man_with_turban_tone3:':["1f473-1f3fd"],':man_with_turban_tone2:':["1f473-1f3fc"],':man_with_turban_tone1:':["1f473-1f3fb"],':man_with_gua_pi_mao_tone5:':["1f472-1f3ff"],':man_with_gua_pi_mao_tone4:':["1f472-1f3fe"],':man_with_gua_pi_mao_tone3:':["1f472-1f3fd"],':man_with_gua_pi_mao_tone2:':["1f472-1f3fc"],':man_with_gua_pi_mao_tone1:':["1f472-1f3fb"],':person_with_blond_hair_tone5:':["1f471-1f3ff"],':person_with_blond_hair_tone4:':["1f471-1f3fe"],':person_with_blond_hair_tone3:':["1f471-1f3fd"],':person_with_blond_hair_tone2:':["1f471-1f3fc"],':person_with_blond_hair_tone1:':["1f471-1f3fb"],':bride_with_veil_tone5:':["1f470-1f3ff"],':bride_with_veil_tone4:':["1f470-1f3fe"],':bride_with_veil_tone3:':["1f470-1f3fd"],':bride_with_veil_tone2:':["1f470-1f3fc"],':bride_with_veil_tone1:':["1f470-1f3fb"],':cop_tone5:':["1f46e-1f3ff"],':cop_tone4:':["1f46e-1f3fe"],':cop_tone3:':["1f46e-1f3fd"],':cop_tone2:':["1f46e-1f3fc"],':cop_tone1:':["1f46e-1f3fb"],':woman_tone5:':["1f469-1f3ff"],':woman_tone4:':["1f469-1f3fe"],':woman_tone3:':["1f469-1f3fd"],':woman_tone2:':["1f469-1f3fc"],':woman_tone1:':["1f469-1f3fb"],':man_tone5:':["1f468-1f3ff"],':man_tone4:':["1f468-1f3fe"],':man_tone3:':["1f468-1f3fd"],':man_tone2:':["1f468-1f3fc"],':man_tone1:':["1f468-1f3fb"],':girl_tone5:':["1f467-1f3ff"],':girl_tone4:':["1f467-1f3fe"],':girl_tone3:':["1f467-1f3fd"],':girl_tone2:':["1f467-1f3fc"],':girl_tone1:':["1f467-1f3fb"],':boy_tone5:':["1f466-1f3ff"],':boy_tone4:':["1f466-1f3fe"],':boy_tone3:':["1f466-1f3fd"],':boy_tone2:':["1f466-1f3fc"],':boy_tone1:':["1f466-1f3fb"],':open_hands_tone5:':["1f450-1f3ff"],':open_hands_tone4:':["1f450-1f3fe"],':open_hands_tone3:':["1f450-1f3fd"],':open_hands_tone2:':["1f450-1f3fc"],':open_hands_tone1:':["1f450-1f3fb"],':clap_tone5:':["1f44f-1f3ff"],':clap_tone4:':["1f44f-1f3fe"],':clap_tone3:':["1f44f-1f3fd"],':clap_tone2:':["1f44f-1f3fc"],':clap_tone1:':["1f44f-1f3fb"],':thumbsdown_tone5:':["1f44e-1f3ff"],':-1_tone5:':["1f44e-1f3ff"],':thumbsdown_tone4:':["1f44e-1f3fe"],':-1_tone4:':["1f44e-1f3fe"],':thumbsdown_tone3:':["1f44e-1f3fd"],':-1_tone3:':["1f44e-1f3fd"],':thumbsdown_tone2:':["1f44e-1f3fc"],':-1_tone2:':["1f44e-1f3fc"],':thumbsdown_tone1:':["1f44e-1f3fb"],':-1_tone1:':["1f44e-1f3fb"],':thumbsup_tone5:':["1f44d-1f3ff"],':+1_tone5:':["1f44d-1f3ff"],':thumbsup_tone4:':["1f44d-1f3fe"],':+1_tone4:':["1f44d-1f3fe"],':thumbsup_tone3:':["1f44d-1f3fd"],':+1_tone3:':["1f44d-1f3fd"],':thumbsup_tone2:':["1f44d-1f3fc"],':+1_tone2:':["1f44d-1f3fc"],':thumbsup_tone1:':["1f44d-1f3fb"],':+1_tone1:':["1f44d-1f3fb"],':ok_hand_tone5:':["1f44c-1f3ff"],':ok_hand_tone4:':["1f44c-1f3fe"],':ok_hand_tone3:':["1f44c-1f3fd"],':ok_hand_tone2:':["1f44c-1f3fc"],':ok_hand_tone1:':["1f44c-1f3fb"],':wave_tone5:':["1f44b-1f3ff"],':wave_tone4:':["1f44b-1f3fe"],':wave_tone3:':["1f44b-1f3fd"],':wave_tone2:':["1f44b-1f3fc"],':wave_tone1:':["1f44b-1f3fb"],':punch_tone5:':["1f44a-1f3ff"],':punch_tone4:':["1f44a-1f3fe"],':punch_tone3:':["1f44a-1f3fd"],':punch_tone2:':["1f44a-1f3fc"],':punch_tone1:':["1f44a-1f3fb"],':point_right_tone5:':["1f449-1f3ff"],':point_right_tone4:':["1f449-1f3fe"],':point_right_tone3:':["1f449-1f3fd"],':point_right_tone2:':["1f449-1f3fc"],':point_right_tone1:':["1f449-1f3fb"],':point_left_tone5:':["1f448-1f3ff"],':point_left_tone4:':["1f448-1f3fe"],':point_left_tone3:':["1f448-1f3fd"],':point_left_tone2:':["1f448-1f3fc"],':point_left_tone1:':["1f448-1f3fb"],':point_down_tone5:':["1f447-1f3ff"],':point_down_tone4:':["1f447-1f3fe"],':point_down_tone3:':["1f447-1f3fd"],':point_down_tone2:':["1f447-1f3fc"],':point_down_tone1:':["1f447-1f3fb"],':point_up_2_tone5:':["1f446-1f3ff"],':point_up_2_tone4:':["1f446-1f3fe"],':point_up_2_tone3:':["1f446-1f3fd"],':point_up_2_tone2:':["1f446-1f3fc"],':point_up_2_tone1:':["1f446-1f3fb"],':nose_tone5:':["1f443-1f3ff"],':nose_tone4:':["1f443-1f3fe"],':nose_tone3:':["1f443-1f3fd"],':nose_tone2:':["1f443-1f3fc"],':nose_tone1:':["1f443-1f3fb"],':ear_tone5:':["1f442-1f3ff"],':ear_tone4:':["1f442-1f3fe"],':ear_tone3:':["1f442-1f3fd"],':ear_tone2:':["1f442-1f3fc"],':ear_tone1:':["1f442-1f3fb"],':lifter_tone5:':["1f3cb-1f3ff"],':weight_lifter_tone5:':["1f3cb-1f3ff"],':lifter_tone4:':["1f3cb-1f3fe"],':weight_lifter_tone4:':["1f3cb-1f3fe"],':lifter_tone3:':["1f3cb-1f3fd"],':weight_lifter_tone3:':["1f3cb-1f3fd"],':lifter_tone2:':["1f3cb-1f3fc"],':weight_lifter_tone2:':["1f3cb-1f3fc"],':lifter_tone1:':["1f3cb-1f3fb"],':weight_lifter_tone1:':["1f3cb-1f3fb"],':swimmer_tone5:':["1f3ca-1f3ff"],':swimmer_tone4:':["1f3ca-1f3fe"],':swimmer_tone3:':["1f3ca-1f3fd"],':swimmer_tone2:':["1f3ca-1f3fc"],':swimmer_tone1:':["1f3ca-1f3fb"],':horse_racing_tone5:':["1f3c7-1f3ff"],':horse_racing_tone4:':["1f3c7-1f3fe"],':horse_racing_tone3:':["1f3c7-1f3fd"],':horse_racing_tone2:':["1f3c7-1f3fc"],':horse_racing_tone1:':["1f3c7-1f3fb"],':surfer_tone5:':["1f3c4-1f3ff"],':surfer_tone4:':["1f3c4-1f3fe"],':surfer_tone3:':["1f3c4-1f3fd"],':surfer_tone2:':["1f3c4-1f3fc"],':surfer_tone1:':["1f3c4-1f3fb"],':runner_tone5:':["1f3c3-1f3ff"],':runner_tone4:':["1f3c3-1f3fe"],':runner_tone3:':["1f3c3-1f3fd"],':runner_tone2:':["1f3c3-1f3fc"],':runner_tone1:':["1f3c3-1f3fb"],':santa_tone5:':["1f385-1f3ff"],':santa_tone4:':["1f385-1f3fe"],':santa_tone3:':["1f385-1f3fd"],':santa_tone2:':["1f385-1f3fc"],':santa_tone1:':["1f385-1f3fb"],':flag_zw:':["1f1ff-1f1fc"],':zw:':["1f1ff-1f1fc"],':flag_zm:':["1f1ff-1f1f2"],':zm:':["1f1ff-1f1f2"],':flag_za:':["1f1ff-1f1e6"],':za:':["1f1ff-1f1e6"],':flag_yt:':["1f1fe-1f1f9"],':yt:':["1f1fe-1f1f9"],':flag_ye:':["1f1fe-1f1ea"],':ye:':["1f1fe-1f1ea"],':flag_xk:':["1f1fd-1f1f0"],':xk:':["1f1fd-1f1f0"],':flag_ws:':["1f1fc-1f1f8"],':ws:':["1f1fc-1f1f8"],':flag_wf:':["1f1fc-1f1eb"],':wf:':["1f1fc-1f1eb"],':flag_vu:':["1f1fb-1f1fa"],':vu:':["1f1fb-1f1fa"],':flag_vn:':["1f1fb-1f1f3"],':vn:':["1f1fb-1f1f3"],':flag_vi:':["1f1fb-1f1ee"],':vi:':["1f1fb-1f1ee"],':flag_vg:':["1f1fb-1f1ec"],':vg:':["1f1fb-1f1ec"],':flag_ve:':["1f1fb-1f1ea"],':ve:':["1f1fb-1f1ea"],':flag_vc:':["1f1fb-1f1e8"],':vc:':["1f1fb-1f1e8"],':flag_va:':["1f1fb-1f1e6"],':va:':["1f1fb-1f1e6"],':flag_uz:':["1f1fa-1f1ff"],':uz:':["1f1fa-1f1ff"],':flag_uy:':["1f1fa-1f1fe"],':uy:':["1f1fa-1f1fe"],':flag_us:':["1f1fa-1f1f8"],':us:':["1f1fa-1f1f8"],':flag_um:':["1f1fa-1f1f2"],':um:':["1f1fa-1f1f2"],':flag_ug:':["1f1fa-1f1ec"],':ug:':["1f1fa-1f1ec"],':flag_ua:':["1f1fa-1f1e6"],':ua:':["1f1fa-1f1e6"],':flag_tz:':["1f1f9-1f1ff"],':tz:':["1f1f9-1f1ff"],':flag_tw:':["1f1f9-1f1fc"],':tw:':["1f1f9-1f1fc"],':flag_tv:':["1f1f9-1f1fb"],':tuvalu:':["1f1f9-1f1fb"],':flag_tt:':["1f1f9-1f1f9"],':tt:':["1f1f9-1f1f9"],':flag_tr:':["1f1f9-1f1f7"],':tr:':["1f1f9-1f1f7"],':flag_to:':["1f1f9-1f1f4"],':to:':["1f1f9-1f1f4"],':flag_tn:':["1f1f9-1f1f3"],':tn:':["1f1f9-1f1f3"],':flag_tm:':["1f1f9-1f1f2"],':turkmenistan:':["1f1f9-1f1f2"],':flag_tl:':["1f1f9-1f1f1"],':tl:':["1f1f9-1f1f1"],':flag_tk:':["1f1f9-1f1f0"],':tk:':["1f1f9-1f1f0"],':flag_tj:':["1f1f9-1f1ef"],':tj:':["1f1f9-1f1ef"],':flag_th:':["1f1f9-1f1ed"],':th:':["1f1f9-1f1ed"],':flag_tg:':["1f1f9-1f1ec"],':tg:':["1f1f9-1f1ec"],':flag_tf:':["1f1f9-1f1eb"],':tf:':["1f1f9-1f1eb"],':flag_td:':["1f1f9-1f1e9"],':td:':["1f1f9-1f1e9"],':flag_tc:':["1f1f9-1f1e8"],':tc:':["1f1f9-1f1e8"],':flag_ta:':["1f1f9-1f1e6"],':ta:':["1f1f9-1f1e6"],':flag_sz:':["1f1f8-1f1ff"],':sz:':["1f1f8-1f1ff"],':flag_sy:':["1f1f8-1f1fe"],':sy:':["1f1f8-1f1fe"],':flag_sx:':["1f1f8-1f1fd"],':sx:':["1f1f8-1f1fd"],':flag_sv:':["1f1f8-1f1fb"],':sv:':["1f1f8-1f1fb"],':flag_st:':["1f1f8-1f1f9"],':st:':["1f1f8-1f1f9"],':flag_ss:':["1f1f8-1f1f8"],':ss:':["1f1f8-1f1f8"],':flag_sr:':["1f1f8-1f1f7"],':sr:':["1f1f8-1f1f7"],':flag_so:':["1f1f8-1f1f4"],':so:':["1f1f8-1f1f4"],':flag_sn:':["1f1f8-1f1f3"],':sn:':["1f1f8-1f1f3"],':flag_sm:':["1f1f8-1f1f2"],':sm:':["1f1f8-1f1f2"],':flag_sl:':["1f1f8-1f1f1"],':sl:':["1f1f8-1f1f1"],':flag_sk:':["1f1f8-1f1f0"],':sk:':["1f1f8-1f1f0"],':flag_sj:':["1f1f8-1f1ef"],':sj:':["1f1f8-1f1ef"],':flag_si:':["1f1f8-1f1ee"],':si:':["1f1f8-1f1ee"],':flag_sh:':["1f1f8-1f1ed"],':sh:':["1f1f8-1f1ed"],':flag_sg:':["1f1f8-1f1ec"],':sg:':["1f1f8-1f1ec"],':flag_se:':["1f1f8-1f1ea"],':se:':["1f1f8-1f1ea"],':flag_sd:':["1f1f8-1f1e9"],':sd:':["1f1f8-1f1e9"],':flag_sc:':["1f1f8-1f1e8"],':sc:':["1f1f8-1f1e8"],':flag_sb:':["1f1f8-1f1e7"],':sb:':["1f1f8-1f1e7"],':flag_sa:':["1f1f8-1f1e6"],':saudiarabia:':["1f1f8-1f1e6"],':saudi:':["1f1f8-1f1e6"],':flag_rw:':["1f1f7-1f1fc"],':rw:':["1f1f7-1f1fc"],':flag_ru:':["1f1f7-1f1fa"],':ru:':["1f1f7-1f1fa"],':flag_rs:':["1f1f7-1f1f8"],':rs:':["1f1f7-1f1f8"],':flag_ro:':["1f1f7-1f1f4"],':ro:':["1f1f7-1f1f4"],':flag_re:':["1f1f7-1f1ea"],':re:':["1f1f7-1f1ea"],':flag_qa:':["1f1f6-1f1e6"],':qa:':["1f1f6-1f1e6"],':flag_py:':["1f1f5-1f1fe"],':py:':["1f1f5-1f1fe"],':flag_pw:':["1f1f5-1f1fc"],':pw:':["1f1f5-1f1fc"],':flag_pt:':["1f1f5-1f1f9"],':pt:':["1f1f5-1f1f9"],':flag_ps:':["1f1f5-1f1f8"],':ps:':["1f1f5-1f1f8"],':flag_pr:':["1f1f5-1f1f7"],':pr:':["1f1f5-1f1f7"],':flag_pn:':["1f1f5-1f1f3"],':pn:':["1f1f5-1f1f3"],':flag_pm:':["1f1f5-1f1f2"],':pm:':["1f1f5-1f1f2"],':flag_pl:':["1f1f5-1f1f1"],':pl:':["1f1f5-1f1f1"],':flag_pk:':["1f1f5-1f1f0"],':pk:':["1f1f5-1f1f0"],':flag_ph:':["1f1f5-1f1ed"],':ph:':["1f1f5-1f1ed"],':flag_pg:':["1f1f5-1f1ec"],':pg:':["1f1f5-1f1ec"],':flag_pf:':["1f1f5-1f1eb"],':pf:':["1f1f5-1f1eb"],':flag_pe:':["1f1f5-1f1ea"],':pe:':["1f1f5-1f1ea"],':flag_pa:':["1f1f5-1f1e6"],':pa:':["1f1f5-1f1e6"],':flag_om:':["1f1f4-1f1f2"],':om:':["1f1f4-1f1f2"],':flag_nz:':["1f1f3-1f1ff"],':nz:':["1f1f3-1f1ff"],':flag_nu:':["1f1f3-1f1fa"],':nu:':["1f1f3-1f1fa"],':flag_nr:':["1f1f3-1f1f7"],':nr:':["1f1f3-1f1f7"],':flag_np:':["1f1f3-1f1f5"],':np:':["1f1f3-1f1f5"],':flag_no:':["1f1f3-1f1f4"],':no:':["1f1f3-1f1f4"],':flag_nl:':["1f1f3-1f1f1"],':nl:':["1f1f3-1f1f1"],':flag_ni:':["1f1f3-1f1ee"],':ni:':["1f1f3-1f1ee"],':flag_ng:':["1f1f3-1f1ec"],':nigeria:':["1f1f3-1f1ec"],':flag_nf:':["1f1f3-1f1eb"],':nf:':["1f1f3-1f1eb"],':flag_ne:':["1f1f3-1f1ea"],':ne:':["1f1f3-1f1ea"],':flag_nc:':["1f1f3-1f1e8"],':nc:':["1f1f3-1f1e8"],':flag_na:':["1f1f3-1f1e6"],':na:':["1f1f3-1f1e6"],':flag_mz:':["1f1f2-1f1ff"],':mz:':["1f1f2-1f1ff"],':flag_my:':["1f1f2-1f1fe"],':my:':["1f1f2-1f1fe"],':flag_mx:':["1f1f2-1f1fd"],':mx:':["1f1f2-1f1fd"],':flag_mw:':["1f1f2-1f1fc"],':mw:':["1f1f2-1f1fc"],':flag_mv:':["1f1f2-1f1fb"],':mv:':["1f1f2-1f1fb"],':flag_mu:':["1f1f2-1f1fa"],':mu:':["1f1f2-1f1fa"],':flag_mt:':["1f1f2-1f1f9"],':mt:':["1f1f2-1f1f9"],':flag_ms:':["1f1f2-1f1f8"],':ms:':["1f1f2-1f1f8"],':flag_mr:':["1f1f2-1f1f7"],':mr:':["1f1f2-1f1f7"],':flag_mq:':["1f1f2-1f1f6"],':mq:':["1f1f2-1f1f6"],':flag_mp:':["1f1f2-1f1f5"],':mp:':["1f1f2-1f1f5"],':flag_mo:':["1f1f2-1f1f4"],':mo:':["1f1f2-1f1f4"],':flag_mn:':["1f1f2-1f1f3"],':mn:':["1f1f2-1f1f3"],':flag_mm:':["1f1f2-1f1f2"],':mm:':["1f1f2-1f1f2"],':flag_ml:':["1f1f2-1f1f1"],':ml:':["1f1f2-1f1f1"],':flag_mk:':["1f1f2-1f1f0"],':mk:':["1f1f2-1f1f0"],':flag_mh:':["1f1f2-1f1ed"],':mh:':["1f1f2-1f1ed"],':flag_mg:':["1f1f2-1f1ec"],':mg:':["1f1f2-1f1ec"],':flag_mf:':["1f1f2-1f1eb"],':mf:':["1f1f2-1f1eb"],':flag_me:':["1f1f2-1f1ea"],':me:':["1f1f2-1f1ea"],':flag_md:':["1f1f2-1f1e9"],':md:':["1f1f2-1f1e9"],':flag_mc:':["1f1f2-1f1e8"],':mc:':["1f1f2-1f1e8"],':flag_ma:':["1f1f2-1f1e6"],':ma:':["1f1f2-1f1e6"],':flag_ly:':["1f1f1-1f1fe"],':ly:':["1f1f1-1f1fe"],':flag_lv:':["1f1f1-1f1fb"],':lv:':["1f1f1-1f1fb"],':flag_lu:':["1f1f1-1f1fa"],':lu:':["1f1f1-1f1fa"],':flag_lt:':["1f1f1-1f1f9"],':lt:':["1f1f1-1f1f9"],':flag_ls:':["1f1f1-1f1f8"],':ls:':["1f1f1-1f1f8"],':flag_lr:':["1f1f1-1f1f7"],':lr:':["1f1f1-1f1f7"],':flag_lk:':["1f1f1-1f1f0"],':lk:':["1f1f1-1f1f0"],':flag_li:':["1f1f1-1f1ee"],':li:':["1f1f1-1f1ee"],':flag_lc:':["1f1f1-1f1e8"],':lc:':["1f1f1-1f1e8"],':flag_lb:':["1f1f1-1f1e7"],':lb:':["1f1f1-1f1e7"],':flag_la:':["1f1f1-1f1e6"],':la:':["1f1f1-1f1e6"],':flag_kz:':["1f1f0-1f1ff"],':kz:':["1f1f0-1f1ff"],':flag_ky:':["1f1f0-1f1fe"],':ky:':["1f1f0-1f1fe"],':flag_kw:':["1f1f0-1f1fc"],':kw:':["1f1f0-1f1fc"],':flag_kr:':["1f1f0-1f1f7"],':kr:':["1f1f0-1f1f7"],':flag_kp:':["1f1f0-1f1f5"],':kp:':["1f1f0-1f1f5"],':flag_kn:':["1f1f0-1f1f3"],':kn:':["1f1f0-1f1f3"],':flag_km:':["1f1f0-1f1f2"],':km:':["1f1f0-1f1f2"],':flag_ki:':["1f1f0-1f1ee"],':ki:':["1f1f0-1f1ee"],':flag_kh:':["1f1f0-1f1ed"],':kh:':["1f1f0-1f1ed"],':flag_kg:':["1f1f0-1f1ec"],':kg:':["1f1f0-1f1ec"],':flag_ke:':["1f1f0-1f1ea"],':ke:':["1f1f0-1f1ea"],':flag_jp:':["1f1ef-1f1f5"],':jp:':["1f1ef-1f1f5"],':flag_jo:':["1f1ef-1f1f4"],':jo:':["1f1ef-1f1f4"],':flag_jm:':["1f1ef-1f1f2"],':jm:':["1f1ef-1f1f2"],':flag_je:':["1f1ef-1f1ea"],':je:':["1f1ef-1f1ea"],':flag_it:':["1f1ee-1f1f9"],':it:':["1f1ee-1f1f9"],':flag_is:':["1f1ee-1f1f8"],':is:':["1f1ee-1f1f8"],':flag_ir:':["1f1ee-1f1f7"],':ir:':["1f1ee-1f1f7"],':flag_iq:':["1f1ee-1f1f6"],':iq:':["1f1ee-1f1f6"],':flag_io:':["1f1ee-1f1f4"],':io:':["1f1ee-1f1f4"],':flag_in:':["1f1ee-1f1f3"],':in:':["1f1ee-1f1f3"],':flag_im:':["1f1ee-1f1f2"],':im:':["1f1ee-1f1f2"],':flag_il:':["1f1ee-1f1f1"],':il:':["1f1ee-1f1f1"],':flag_ie:':["1f1ee-1f1ea"],':ie:':["1f1ee-1f1ea"],':flag_id:':["1f1ee-1f1e9"],':indonesia:':["1f1ee-1f1e9"],':flag_ic:':["1f1ee-1f1e8"],':ic:':["1f1ee-1f1e8"],':flag_hu:':["1f1ed-1f1fa"],':hu:':["1f1ed-1f1fa"],':flag_ht:':["1f1ed-1f1f9"],':ht:':["1f1ed-1f1f9"],':flag_hr:':["1f1ed-1f1f7"],':hr:':["1f1ed-1f1f7"],':flag_hn:':["1f1ed-1f1f3"],':hn:':["1f1ed-1f1f3"],':flag_hm:':["1f1ed-1f1f2"],':hm:':["1f1ed-1f1f2"],':flag_hk:':["1f1ed-1f1f0"],':hk:':["1f1ed-1f1f0"],':flag_gy:':["1f1ec-1f1fe"],':gy:':["1f1ec-1f1fe"],':flag_gw:':["1f1ec-1f1fc"],':gw:':["1f1ec-1f1fc"],':flag_gu:':["1f1ec-1f1fa"],':gu:':["1f1ec-1f1fa"],':flag_gt:':["1f1ec-1f1f9"],':gt:':["1f1ec-1f1f9"],':flag_gs:':["1f1ec-1f1f8"],':gs:':["1f1ec-1f1f8"],':flag_gr:':["1f1ec-1f1f7"],':gr:':["1f1ec-1f1f7"],':flag_gq:':["1f1ec-1f1f6"],':gq:':["1f1ec-1f1f6"],':flag_gp:':["1f1ec-1f1f5"],':gp:':["1f1ec-1f1f5"],':flag_gn:':["1f1ec-1f1f3"],':gn:':["1f1ec-1f1f3"],':flag_gm:':["1f1ec-1f1f2"],':gm:':["1f1ec-1f1f2"],':flag_gl:':["1f1ec-1f1f1"],':gl:':["1f1ec-1f1f1"],':flag_gi:':["1f1ec-1f1ee"],':gi:':["1f1ec-1f1ee"],':flag_gh:':["1f1ec-1f1ed"],':gh:':["1f1ec-1f1ed"],':flag_gg:':["1f1ec-1f1ec"],':gg:':["1f1ec-1f1ec"],':flag_gf:':["1f1ec-1f1eb"],':gf:':["1f1ec-1f1eb"],':flag_ge:':["1f1ec-1f1ea"],':ge:':["1f1ec-1f1ea"],':flag_gd:':["1f1ec-1f1e9"],':gd:':["1f1ec-1f1e9"],':flag_gb:':["1f1ec-1f1e7"],':gb:':["1f1ec-1f1e7"],':flag_ga:':["1f1ec-1f1e6"],':ga:':["1f1ec-1f1e6"],':flag_fr:':["1f1eb-1f1f7"],':fr:':["1f1eb-1f1f7"],':flag_fo:':["1f1eb-1f1f4"],':fo:':["1f1eb-1f1f4"],':flag_fm:':["1f1eb-1f1f2"],':fm:':["1f1eb-1f1f2"],':flag_fk:':["1f1eb-1f1f0"],':fk:':["1f1eb-1f1f0"],':flag_fj:':["1f1eb-1f1ef"],':fj:':["1f1eb-1f1ef"],':flag_fi:':["1f1eb-1f1ee"],':fi:':["1f1eb-1f1ee"],':flag_eu:':["1f1ea-1f1fa"],':eu:':["1f1ea-1f1fa"],':flag_et:':["1f1ea-1f1f9"],':et:':["1f1ea-1f1f9"],':flag_es:':["1f1ea-1f1f8"],':es:':["1f1ea-1f1f8"],':flag_er:':["1f1ea-1f1f7"],':er:':["1f1ea-1f1f7"],':flag_eh:':["1f1ea-1f1ed"],':eh:':["1f1ea-1f1ed"],':flag_eg:':["1f1ea-1f1ec"],':eg:':["1f1ea-1f1ec"],':flag_ee:':["1f1ea-1f1ea"],':ee:':["1f1ea-1f1ea"],':flag_ec:':["1f1ea-1f1e8"],':ec:':["1f1ea-1f1e8"],':flag_ea:':["1f1ea-1f1e6"],':ea:':["1f1ea-1f1e6"],':flag_dz:':["1f1e9-1f1ff"],':dz:':["1f1e9-1f1ff"],':flag_do:':["1f1e9-1f1f4"],':do:':["1f1e9-1f1f4"],':flag_dm:':["1f1e9-1f1f2"],':dm:':["1f1e9-1f1f2"],':flag_dk:':["1f1e9-1f1f0"],':dk:':["1f1e9-1f1f0"],':flag_dj:':["1f1e9-1f1ef"],':dj:':["1f1e9-1f1ef"],':flag_dg:':["1f1e9-1f1ec"],':dg:':["1f1e9-1f1ec"],':flag_de:':["1f1e9-1f1ea"],':de:':["1f1e9-1f1ea"],':flag_cz:':["1f1e8-1f1ff"],':cz:':["1f1e8-1f1ff"],':flag_cy:':["1f1e8-1f1fe"],':cy:':["1f1e8-1f1fe"],':flag_cx:':["1f1e8-1f1fd"],':cx:':["1f1e8-1f1fd"],':flag_cw:':["1f1e8-1f1fc"],':cw:':["1f1e8-1f1fc"],':flag_cv:':["1f1e8-1f1fb"],':cv:':["1f1e8-1f1fb"],':flag_cu:':["1f1e8-1f1fa"],':cu:':["1f1e8-1f1fa"],':flag_cr:':["1f1e8-1f1f7"],':cr:':["1f1e8-1f1f7"],':flag_cp:':["1f1e8-1f1f5"],':cp:':["1f1e8-1f1f5"],':flag_co:':["1f1e8-1f1f4"],':co:':["1f1e8-1f1f4"],':flag_cn:':["1f1e8-1f1f3"],':cn:':["1f1e8-1f1f3"],':flag_cm:':["1f1e8-1f1f2"],':cm:':["1f1e8-1f1f2"],':flag_cl:':["1f1e8-1f1f1"],':chile:':["1f1e8-1f1f1"],':flag_ck:':["1f1e8-1f1f0"],':ck:':["1f1e8-1f1f0"],':flag_ci:':["1f1e8-1f1ee"],':ci:':["1f1e8-1f1ee"],':flag_ch:':["1f1e8-1f1ed"],':ch:':["1f1e8-1f1ed"],':flag_cg:':["1f1e8-1f1ec"],':cg:':["1f1e8-1f1ec"],':flag_cf:':["1f1e8-1f1eb"],':cf:':["1f1e8-1f1eb"],':flag_cd:':["1f1e8-1f1e9"],':congo:':["1f1e8-1f1e9"],':flag_cc:':["1f1e8-1f1e8"],':cc:':["1f1e8-1f1e8"],':flag_ca:':["1f1e8-1f1e6"],':ca:':["1f1e8-1f1e6"],':flag_bz:':["1f1e7-1f1ff"],':bz:':["1f1e7-1f1ff"],':flag_by:':["1f1e7-1f1fe"],':by:':["1f1e7-1f1fe"],':flag_bw:':["1f1e7-1f1fc"],':bw:':["1f1e7-1f1fc"],':flag_bv:':["1f1e7-1f1fb"],':bv:':["1f1e7-1f1fb"],':flag_bt:':["1f1e7-1f1f9"],':bt:':["1f1e7-1f1f9"],':flag_bs:':["1f1e7-1f1f8"],':bs:':["1f1e7-1f1f8"],':flag_br:':["1f1e7-1f1f7"],':br:':["1f1e7-1f1f7"],':flag_bq:':["1f1e7-1f1f6"],':bq:':["1f1e7-1f1f6"],':flag_bo:':["1f1e7-1f1f4"],':bo:':["1f1e7-1f1f4"],':flag_bn:':["1f1e7-1f1f3"],':bn:':["1f1e7-1f1f3"],':flag_bm:':["1f1e7-1f1f2"],':bm:':["1f1e7-1f1f2"],':flag_bl:':["1f1e7-1f1f1"],':bl:':["1f1e7-1f1f1"],':flag_bj:':["1f1e7-1f1ef"],':bj:':["1f1e7-1f1ef"],':flag_bi:':["1f1e7-1f1ee"],':bi:':["1f1e7-1f1ee"],':flag_bh:':["1f1e7-1f1ed"],':bh:':["1f1e7-1f1ed"],':flag_bg:':["1f1e7-1f1ec"],':bg:':["1f1e7-1f1ec"],':flag_bf:':["1f1e7-1f1eb"],':bf:':["1f1e7-1f1eb"],':flag_be:':["1f1e7-1f1ea"],':be:':["1f1e7-1f1ea"],':flag_bd:':["1f1e7-1f1e9"],':bd:':["1f1e7-1f1e9"],':flag_bb:':["1f1e7-1f1e7"],':bb:':["1f1e7-1f1e7"],':flag_ba:':["1f1e7-1f1e6"],':ba:':["1f1e7-1f1e6"],':flag_az:':["1f1e6-1f1ff"],':az:':["1f1e6-1f1ff"],':flag_ax:':["1f1e6-1f1fd"],':ax:':["1f1e6-1f1fd"],':flag_aw:':["1f1e6-1f1fc"],':aw:':["1f1e6-1f1fc"],':flag_au:':["1f1e6-1f1fa"],':au:':["1f1e6-1f1fa"],':flag_at:':["1f1e6-1f1f9"],':at:':["1f1e6-1f1f9"],':flag_as:':["1f1e6-1f1f8"],':as:':["1f1e6-1f1f8"],':flag_ar:':["1f1e6-1f1f7"],':ar:':["1f1e6-1f1f7"],':flag_aq:':["1f1e6-1f1f6"],':aq:':["1f1e6-1f1f6"],':flag_ao:':["1f1e6-1f1f4"],':ao:':["1f1e6-1f1f4"],':flag_am:':["1f1e6-1f1f2"],':am:':["1f1e6-1f1f2"],':flag_al:':["1f1e6-1f1f1"],':al:':["1f1e6-1f1f1"],':flag_ai:':["1f1e6-1f1ee"],':ai:':["1f1e6-1f1ee"],':flag_ag:':["1f1e6-1f1ec"],':ag:':["1f1e6-1f1ec"],':flag_af:':["1f1e6-1f1eb"],':af:':["1f1e6-1f1eb"],':flag_ae:':["1f1e6-1f1ea"],':ae:':["1f1e6-1f1ea"],':flag_ad:':["1f1e6-1f1e9"],':ad:':["1f1e6-1f1e9"],':flag_ac:':["1f1e6-1f1e8"],':ac:':["1f1e6-1f1e8"],':mahjong:':["1f004-fe0f","1f004"],':parking:':["1f17f-fe0f","1f17f"],':u7121:':["1f21a-fe0f","1f21a"],':u6307:':["1f22f-fe0f","1f22f"],':u6708:':["1f237-fe0f","1f237"],':point_up_tone1:':["261d-1f3fb"],':point_up_tone2:':["261d-1f3fc"],':point_up_tone3:':["261d-1f3fd"],':point_up_tone4:':["261d-1f3fe"],':point_up_tone5:':["261d-1f3ff"],':v_tone1:':["270c-1f3fb"],':v_tone2:':["270c-1f3fc"],':v_tone3:':["270c-1f3fd"],':v_tone4:':["270c-1f3fe"],':v_tone5:':["270c-1f3ff"],':fist_tone1:':["270a-1f3fb"],':fist_tone2:':["270a-1f3fc"],':fist_tone3:':["270a-1f3fd"],':fist_tone4:':["270a-1f3fe"],':fist_tone5:':["270a-1f3ff"],':raised_hand_tone1:':["270b-1f3fb"],':raised_hand_tone2:':["270b-1f3fc"],':raised_hand_tone3:':["270b-1f3fd"],':raised_hand_tone4:':["270b-1f3fe"],':raised_hand_tone5:':["270b-1f3ff"],':writing_hand_tone1:':["270d-1f3fb"],':writing_hand_tone2:':["270d-1f3fc"],':writing_hand_tone3:':["270d-1f3fd"],':writing_hand_tone4:':["270d-1f3fe"],':writing_hand_tone5:':["270d-1f3ff"],':basketball_player_tone1:':["26f9-1f3fb"],':person_with_ball_tone1:':["26f9-1f3fb"],':basketball_player_tone2:':["26f9-1f3fc"],':person_with_ball_tone2:':["26f9-1f3fc"],':basketball_player_tone3:':["26f9-1f3fd"],':person_with_ball_tone3:':["26f9-1f3fd"],':basketball_player_tone4:':["26f9-1f3fe"],':person_with_ball_tone4:':["26f9-1f3fe"],':basketball_player_tone5:':["26f9-1f3ff"],':person_with_ball_tone5:':["26f9-1f3ff"],':copyright:':["00a9-fe0f","00a9"],':registered:':["00ae-fe0f","00ae"],':bangbang:':["203c-fe0f","203c"],':interrobang:':["2049-fe0f","2049"],':tm:':["2122-fe0f","2122"],':information_source:':["2139-fe0f","2139"],':left_right_arrow:':["2194-fe0f","2194"],':arrow_up_down:':["2195-fe0f","2195"],':arrow_upper_left:':["2196-fe0f","2196"],':arrow_upper_right:':["2197-fe0f","2197"],':arrow_lower_right:':["2198-fe0f","2198"],':arrow_lower_left:':["2199-fe0f","2199"],':leftwards_arrow_with_hook:':["21a9-fe0f","21a9"],':arrow_right_hook:':["21aa-fe0f","21aa"],':watch:':["231a-fe0f","231a"],':hourglass:':["231b-fe0f","231b"],':m:':["24c2-fe0f","24c2"],':black_small_square:':["25aa-fe0f","25aa"],':white_small_square:':["25ab-fe0f","25ab"],':arrow_forward:':["25b6-fe0f","25b6"],':arrow_backward:':["25c0-fe0f","25c0"],':white_medium_square:':["25fb-fe0f","25fb"],':black_medium_square:':["25fc-fe0f","25fc"],':white_medium_small_square:':["25fd-fe0f","25fd"],':black_medium_small_square:':["25fe-fe0f","25fe"],':sunny:':["2600-fe0f","2600"],':cloud:':["2601-fe0f","2601"],':telephone:':["260e-fe0f","260e"],':ballot_box_with_check:':["2611-fe0f","2611"],':umbrella:':["2614-fe0f","2614"],':coffee:':["2615-fe0f","2615"],':point_up:':["261d-fe0f","261d"],':relaxed:':["263a-fe0f","263a"],':aries:':["2648-fe0f","2648"],':taurus:':["2649-fe0f","2649"],':gemini:':["264a-fe0f","264a"],':cancer:':["264b-fe0f","264b"],':leo:':["264c-fe0f","264c"],':virgo:':["264d-fe0f","264d"],':libra:':["264e-fe0f","264e"],':scorpius:':["264f-fe0f","264f"],':sagittarius:':["2650-fe0f","2650"],':capricorn:':["2651-fe0f","2651"],':aquarius:':["2652-fe0f","2652"],':pisces:':["2653-fe0f","2653"],':spades:':["2660-fe0f","2660"],':clubs:':["2663-fe0f","2663"],':hearts:':["2665-fe0f","2665"],':diamonds:':["2666-fe0f","2666"],':hotsprings:':["2668-fe0f","2668"],':recycle:':["267b-fe0f","267b"],':wheelchair:':["267f-fe0f","267f"],':anchor:':["2693-fe0f","2693"],':warning:':["26a0-fe0f","26a0"],':zap:':["26a1-fe0f","26a1"],':white_circle:':["26aa-fe0f","26aa"],':black_circle:':["26ab-fe0f","26ab"],':soccer:':["26bd-fe0f","26bd"],':baseball:':["26be-fe0f","26be"],':snowman:':["26c4-fe0f","26c4"],':partly_sunny:':["26c5-fe0f","26c5"],':no_entry:':["26d4-fe0f","26d4"],':church:':["26ea-fe0f","26ea"],':fountain:':["26f2-fe0f","26f2"],':golf:':["26f3-fe0f","26f3"],':sailboat:':["26f5-fe0f","26f5"],':tent:':["26fa-fe0f","26fa"],':fuelpump:':["26fd-fe0f","26fd"],':scissors:':["2702-fe0f","2702"],':airplane:':["2708-fe0f","2708"],':envelope:':["2709-fe0f","2709"],':v:':["270c-fe0f","270c"],':pencil2:':["270f-fe0f","270f"],':black_nib:':["2712-fe0f","2712"],':heavy_check_mark:':["2714-fe0f","2714"],':heavy_multiplication_x:':["2716-fe0f","2716"],':eight_spoked_asterisk:':["2733-fe0f","2733"],':eight_pointed_black_star:':["2734-fe0f","2734"],':snowflake:':["2744-fe0f","2744"],':sparkle:':["2747-fe0f","2747"],':exclamation:':["2757-fe0f","2757"],':heart:':["2764-fe0f","2764"],':arrow_right:':["27a1-fe0f","27a1"],':arrow_heading_up:':["2934-fe0f","2934"],':arrow_heading_down:':["2935-fe0f","2935"],':arrow_left:':["2b05-fe0f","2b05"],':arrow_up:':["2b06-fe0f","2b06"],':arrow_down:':["2b07-fe0f","2b07"],':black_large_square:':["2b1b-fe0f","2b1b"],':white_large_square:':["2b1c-fe0f","2b1c"],':star:':["2b50-fe0f","2b50"],':o:':["2b55-fe0f","2b55"],':part_alternation_mark:':["303d-fe0f","303d"],':congratulations:':["3297-fe0f","3297"],':secret:':["3299-fe0f","3299"],':black_joker:':["1f0cf"],':a:':["1f170"],':b:':["1f171"],':o2:':["1f17e"],':ab:':["1f18e"],':cl:':["1f191"],':cool:':["1f192"],':free:':["1f193"],':id:':["1f194"],':new:':["1f195"],':ng:':["1f196"],':ok:':["1f197"],':sos:':["1f198"],':up:':["1f199"],':vs:':["1f19a"],':koko:':["1f201"],':sa:':["1f202"],':u7981:':["1f232"],':u7a7a:':["1f233"],':u5408:':["1f234"],':u6e80:':["1f235"],':u6709:':["1f236"],':u7533:':["1f238"],':u5272:':["1f239"],':u55b6:':["1f23a"],':ideograph_advantage:':["1f250"],':accept:':["1f251"],':cyclone:':["1f300"],':foggy:':["1f301"],':closed_umbrella:':["1f302"],':night_with_stars:':["1f303"],':sunrise_over_mountains:':["1f304"],':sunrise:':["1f305"],':city_dusk:':["1f306"],':city_sunset:':["1f307"],':city_sunrise:':["1f307"],':rainbow:':["1f308"],':bridge_at_night:':["1f309"],':ocean:':["1f30a"],':volcano:':["1f30b"],':milky_way:':["1f30c"],':earth_asia:':["1f30f"],':new_moon:':["1f311"],':first_quarter_moon:':["1f313"],':waxing_gibbous_moon:':["1f314"],':full_moon:':["1f315"],':crescent_moon:':["1f319"],':first_quarter_moon_with_face:':["1f31b"],':star2:':["1f31f"],':stars:':["1f320"],':chestnut:':["1f330"],':seedling:':["1f331"],':palm_tree:':["1f334"],':cactus:':["1f335"],':tulip:':["1f337"],':cherry_blossom:':["1f338"],':rose:':["1f339"],':hibiscus:':["1f33a"],':sunflower:':["1f33b"],':blossom:':["1f33c"],':corn:':["1f33d"],':ear_of_rice:':["1f33e"],':herb:':["1f33f"],':four_leaf_clover:':["1f340"],':maple_leaf:':["1f341"],':fallen_leaf:':["1f342"],':leaves:':["1f343"],':mushroom:':["1f344"],':tomato:':["1f345"],':eggplant:':["1f346"],':grapes:':["1f347"],':melon:':["1f348"],':watermelon:':["1f349"],':tangerine:':["1f34a"],':banana:':["1f34c"],':pineapple:':["1f34d"],':apple:':["1f34e"],':green_apple:':["1f34f"],':peach:':["1f351"],':cherries:':["1f352"],':strawberry:':["1f353"],':hamburger:':["1f354"],':pizza:':["1f355"],':meat_on_bone:':["1f356"],':poultry_leg:':["1f357"],':rice_cracker:':["1f358"],':rice_ball:':["1f359"],':rice:':["1f35a"],':curry:':["1f35b"],':ramen:':["1f35c"],':spaghetti:':["1f35d"],':bread:':["1f35e"],':fries:':["1f35f"],':sweet_potato:':["1f360"],':dango:':["1f361"],':oden:':["1f362"],':sushi:':["1f363"],':fried_shrimp:':["1f364"],':fish_cake:':["1f365"],':icecream:':["1f366"],':shaved_ice:':["1f367"],':ice_cream:':["1f368"],':doughnut:':["1f369"],':cookie:':["1f36a"],':chocolate_bar:':["1f36b"],':candy:':["1f36c"],':lollipop:':["1f36d"],':custard:':["1f36e"],':honey_pot:':["1f36f"],':cake:':["1f370"],':bento:':["1f371"],':stew:':["1f372"],':egg:':["1f373"],':fork_and_knife:':["1f374"],':tea:':["1f375"],':sake:':["1f376"],':wine_glass:':["1f377"],':cocktail:':["1f378"],':tropical_drink:':["1f379"],':beer:':["1f37a"],':beers:':["1f37b"],':ribbon:':["1f380"],':gift:':["1f381"],':birthday:':["1f382"],':jack_o_lantern:':["1f383"],':christmas_tree:':["1f384"],':santa:':["1f385"],':fireworks:':["1f386"],':sparkler:':["1f387"],':balloon:':["1f388"],':tada:':["1f389"],':confetti_ball:':["1f38a"],':tanabata_tree:':["1f38b"],':crossed_flags:':["1f38c"],':bamboo:':["1f38d"],':dolls:':["1f38e"],':flags:':["1f38f"],':wind_chime:':["1f390"],':rice_scene:':["1f391"],':school_satchel:':["1f392"],':mortar_board:':["1f393"],':carousel_horse:':["1f3a0"],':ferris_wheel:':["1f3a1"],':roller_coaster:':["1f3a2"],':fishing_pole_and_fish:':["1f3a3"],':microphone:':["1f3a4"],':movie_camera:':["1f3a5"],':cinema:':["1f3a6"],':headphones:':["1f3a7"],':art:':["1f3a8"],':tophat:':["1f3a9"],':circus_tent:':["1f3aa"],':ticket:':["1f3ab"],':clapper:':["1f3ac"],':performing_arts:':["1f3ad"],':video_game:':["1f3ae"],':dart:':["1f3af"],':slot_machine:':["1f3b0"],':8ball:':["1f3b1"],':game_die:':["1f3b2"],':bowling:':["1f3b3"],':flower_playing_cards:':["1f3b4"],':musical_note:':["1f3b5"],':notes:':["1f3b6"],':saxophone:':["1f3b7"],':guitar:':["1f3b8"],':musical_keyboard:':["1f3b9"],':trumpet:':["1f3ba"],':violin:':["1f3bb"],':musical_score:':["1f3bc"],':running_shirt_with_sash:':["1f3bd"],':tennis:':["1f3be"],':ski:':["1f3bf"],':basketball:':["1f3c0"],':checkered_flag:':["1f3c1"],':snowboarder:':["1f3c2"],':runner:':["1f3c3"],':surfer:':["1f3c4"],':trophy:':["1f3c6"],':football:':["1f3c8"],':swimmer:':["1f3ca"],':house:':["1f3e0"],':house_with_garden:':["1f3e1"],':office:':["1f3e2"],':post_office:':["1f3e3"],':hospital:':["1f3e5"],':bank:':["1f3e6"],':atm:':["1f3e7"],':hotel:':["1f3e8"],':love_hotel:':["1f3e9"],':convenience_store:':["1f3ea"],':school:':["1f3eb"],':department_store:':["1f3ec"],':factory:':["1f3ed"],':izakaya_lantern:':["1f3ee"],':japanese_castle:':["1f3ef"],':european_castle:':["1f3f0"],':snail:':["1f40c"],':snake:':["1f40d"],':racehorse:':["1f40e"],':sheep:':["1f411"],':monkey:':["1f412"],':chicken:':["1f414"],':boar:':["1f417"],':elephant:':["1f418"],':octopus:':["1f419"],':shell:':["1f41a"],':bug:':["1f41b"],':ant:':["1f41c"],':bee:':["1f41d"],':beetle:':["1f41e"],':fish:':["1f41f"],':tropical_fish:':["1f420"],':blowfish:':["1f421"],':turtle:':["1f422"],':hatching_chick:':["1f423"],':baby_chick:':["1f424"],':hatched_chick:':["1f425"],':bird:':["1f426"],':penguin:':["1f427"],':koala:':["1f428"],':poodle:':["1f429"],':camel:':["1f42b"],':dolphin:':["1f42c"],':mouse:':["1f42d"],':cow:':["1f42e"],':tiger:':["1f42f"],':rabbit:':["1f430"],':cat:':["1f431"],':dragon_face:':["1f432"],':whale:':["1f433"],':horse:':["1f434"],':monkey_face:':["1f435"],':dog:':["1f436"],':pig:':["1f437"],':frog:':["1f438"],':hamster:':["1f439"],':wolf:':["1f43a"],':bear:':["1f43b"],':panda_face:':["1f43c"],':pig_nose:':["1f43d"],':feet:':["1f43e"],':paw_prints:':["1f43e"],':eyes:':["1f440"],':ear:':["1f442"],':nose:':["1f443"],':lips:':["1f444"],':tongue:':["1f445"],':point_up_2:':["1f446"],':point_down:':["1f447"],':point_left:':["1f448"],':point_right:':["1f449"],':punch:':["1f44a"],':wave:':["1f44b"],':ok_hand:':["1f44c"],':thumbsup:':["1f44d"],':+1:':["1f44d"],':thumbsdown:':["1f44e"],':-1:':["1f44e"],':clap:':["1f44f"],':open_hands:':["1f450"],':crown:':["1f451"],':womans_hat:':["1f452"],':eyeglasses:':["1f453"],':necktie:':["1f454"],':shirt:':["1f455"],':jeans:':["1f456"],':dress:':["1f457"],':kimono:':["1f458"],':bikini:':["1f459"],':womans_clothes:':["1f45a"],':purse:':["1f45b"],':handbag:':["1f45c"],':pouch:':["1f45d"],':mans_shoe:':["1f45e"],':athletic_shoe:':["1f45f"],':high_heel:':["1f460"],':sandal:':["1f461"],':boot:':["1f462"],':footprints:':["1f463"],':bust_in_silhouette:':["1f464"],':boy:':["1f466"],':girl:':["1f467"],':man:':["1f468"],':woman:':["1f469"],':family:':["1f46a"],':couple:':["1f46b"],':cop:':["1f46e"],':dancers:':["1f46f"],':bride_with_veil:':["1f470"],':person_with_blond_hair:':["1f471"],':man_with_gua_pi_mao:':["1f472"],':man_with_turban:':["1f473"],':older_man:':["1f474"],':older_woman:':["1f475"],':grandma:':["1f475"],':baby:':["1f476"],':construction_worker:':["1f477"],':princess:':["1f478"],':japanese_ogre:':["1f479"],':japanese_goblin:':["1f47a"],':ghost:':["1f47b"],':angel:':["1f47c"],':alien:':["1f47d"],':space_invader:':["1f47e"],':imp:':["1f47f"],':skull:':["1f480"],':skeleton:':["1f480"],':card_index:':["1f4c7"],':information_desk_person:':["1f481"],':guardsman:':["1f482"],':dancer:':["1f483"],':lipstick:':["1f484"],':nail_care:':["1f485"],':ledger:':["1f4d2"],':massage:':["1f486"],':notebook:':["1f4d3"],':haircut:':["1f487"],':notebook_with_decorative_cover:':["1f4d4"],':barber:':["1f488"],':closed_book:':["1f4d5"],':syringe:':["1f489"],':book:':["1f4d6"],':pill:':["1f48a"],':green_book:':["1f4d7"],':kiss:':["1f48b"],':blue_book:':["1f4d8"],':love_letter:':["1f48c"],':orange_book:':["1f4d9"],':ring:':["1f48d"],':books:':["1f4da"],':gem:':["1f48e"],':name_badge:':["1f4db"],':couplekiss:':["1f48f"],':scroll:':["1f4dc"],':bouquet:':["1f490"],':pencil:':["1f4dd"],':couple_with_heart:':["1f491"],':telephone_receiver:':["1f4de"],':wedding:':["1f492"],':pager:':["1f4df"],':fax:':["1f4e0"],':heartbeat:':["1f493"],':satellite:':["1f4e1"],':loudspeaker:':["1f4e2"],':broken_heart:':["1f494"],':mega:':["1f4e3"],':outbox_tray:':["1f4e4"],':two_hearts:':["1f495"],':inbox_tray:':["1f4e5"],':package:':["1f4e6"],':sparkling_heart:':["1f496"],':e-mail:':["1f4e7"],':email:':["1f4e7"],':incoming_envelope:':["1f4e8"],':heartpulse:':["1f497"],':envelope_with_arrow:':["1f4e9"],':mailbox_closed:':["1f4ea"],':cupid:':["1f498"],':mailbox:':["1f4eb"],':postbox:':["1f4ee"],':blue_heart:':["1f499"],':newspaper:':["1f4f0"],':iphone:':["1f4f1"],':green_heart:':["1f49a"],':calling:':["1f4f2"],':vibration_mode:':["1f4f3"],':yellow_heart:':["1f49b"],':mobile_phone_off:':["1f4f4"],':signal_strength:':["1f4f6"],':purple_heart:':["1f49c"],':camera:':["1f4f7"],':video_camera:':["1f4f9"],':gift_heart:':["1f49d"],':tv:':["1f4fa"],':radio:':["1f4fb"],':revolving_hearts:':["1f49e"],':vhs:':["1f4fc"],':arrows_clockwise:':["1f503"],':heart_decoration:':["1f49f"],':loud_sound:':["1f50a"],':battery:':["1f50b"],':diamond_shape_with_a_dot_inside:':["1f4a0"],':electric_plug:':["1f50c"],':mag:':["1f50d"],':bulb:':["1f4a1"],':mag_right:':["1f50e"],':lock_with_ink_pen:':["1f50f"],':anger:':["1f4a2"],':closed_lock_with_key:':["1f510"],':key:':["1f511"],':bomb:':["1f4a3"],':lock:':["1f512"],':unlock:':["1f513"],':zzz:':["1f4a4"],':bell:':["1f514"],':bookmark:':["1f516"],':boom:':["1f4a5"],':link:':["1f517"],':radio_button:':["1f518"],':sweat_drops:':["1f4a6"],':back:':["1f519"],':end:':["1f51a"],':droplet:':["1f4a7"],':on:':["1f51b"],':soon:':["1f51c"],':dash:':["1f4a8"],':top:':["1f51d"],':underage:':["1f51e"],':poop:':["1f4a9"],':shit:':["1f4a9"],':hankey:':["1f4a9"],':poo:':["1f4a9"],':ten:':["1f51f"],':muscle:':["1f4aa"],':capital_abcd:':["1f520"],':abcd:':["1f521"],':dizzy:':["1f4ab"],':1234:':["1f522"],':symbols:':["1f523"],':speech_balloon:':["1f4ac"],':abc:':["1f524"],':fire:':["1f525"],':flame:':["1f525"],':white_flower:':["1f4ae"],':flashlight:':["1f526"],':wrench:':["1f527"],':100:':["1f4af"],':hammer:':["1f528"],':nut_and_bolt:':["1f529"],':moneybag:':["1f4b0"],':knife:':["1f52a"],':gun:':["1f52b"],':currency_exchange:':["1f4b1"],':crystal_ball:':["1f52e"],':heavy_dollar_sign:':["1f4b2"],':six_pointed_star:':["1f52f"],':credit_card:':["1f4b3"],':beginner:':["1f530"],':trident:':["1f531"],':yen:':["1f4b4"],':black_square_button:':["1f532"],':white_square_button:':["1f533"],':dollar:':["1f4b5"],':red_circle:':["1f534"],':large_blue_circle:':["1f535"],':money_with_wings:':["1f4b8"],':large_orange_diamond:':["1f536"],':large_blue_diamond:':["1f537"],':chart:':["1f4b9"],':small_orange_diamond:':["1f538"],':small_blue_diamond:':["1f539"],':seat:':["1f4ba"],':small_red_triangle:':["1f53a"],':small_red_triangle_down:':["1f53b"],':computer:':["1f4bb"],':arrow_up_small:':["1f53c"],':briefcase:':["1f4bc"],':arrow_down_small:':["1f53d"],':clock1:':["1f550"],':minidisc:':["1f4bd"],':clock2:':["1f551"],':floppy_disk:':["1f4be"],':clock3:':["1f552"],':cd:':["1f4bf"],':clock4:':["1f553"],':dvd:':["1f4c0"],':clock5:':["1f554"],':clock6:':["1f555"],':file_folder:':["1f4c1"],':clock7:':["1f556"],':clock8:':["1f557"],':open_file_folder:':["1f4c2"],':clock9:':["1f558"],':clock10:':["1f559"],':page_with_curl:':["1f4c3"],':clock11:':["1f55a"],':clock12:':["1f55b"],':page_facing_up:':["1f4c4"],':mount_fuji:':["1f5fb"],':tokyo_tower:':["1f5fc"],':date:':["1f4c5"],':statue_of_liberty:':["1f5fd"],':japan:':["1f5fe"],':calendar:':["1f4c6"],':moyai:':["1f5ff"],':grin:':["1f601"],':joy:':["1f602"],':smiley:':["1f603"],':chart_with_upwards_trend:':["1f4c8"],':smile:':["1f604"],':sweat_smile:':["1f605"],':chart_with_downwards_trend:':["1f4c9"],':laughing:':["1f606"],':satisfied:':["1f606"],':wink:':["1f609"],':bar_chart:':["1f4ca"],':blush:':["1f60a"],':yum:':["1f60b"],':clipboard:':["1f4cb"],':relieved:':["1f60c"],':heart_eyes:':["1f60d"],':pushpin:':["1f4cc"],':smirk:':["1f60f"],':unamused:':["1f612"],':round_pushpin:':["1f4cd"],':sweat:':["1f613"],':pensive:':["1f614"],':paperclip:':["1f4ce"],':confounded:':["1f616"],':kissing_heart:':["1f618"],':straight_ruler:':["1f4cf"],':kissing_closed_eyes:':["1f61a"],':stuck_out_tongue_winking_eye:':["1f61c"],':triangular_ruler:':["1f4d0"],':stuck_out_tongue_closed_eyes:':["1f61d"],':disappointed:':["1f61e"],':bookmark_tabs:':["1f4d1"],':angry:':["1f620"],':rage:':["1f621"],':cry:':["1f622"],':persevere:':["1f623"],':triumph:':["1f624"],':disappointed_relieved:':["1f625"],':fearful:':["1f628"],':weary:':["1f629"],':sleepy:':["1f62a"],':tired_face:':["1f62b"],':sob:':["1f62d"],':cold_sweat:':["1f630"],':scream:':["1f631"],':astonished:':["1f632"],':flushed:':["1f633"],':dizzy_face:':["1f635"],':mask:':["1f637"],':smile_cat:':["1f638"],':joy_cat:':["1f639"],':smiley_cat:':["1f63a"],':heart_eyes_cat:':["1f63b"],':smirk_cat:':["1f63c"],':kissing_cat:':["1f63d"],':pouting_cat:':["1f63e"],':crying_cat_face:':["1f63f"],':scream_cat:':["1f640"],':no_good:':["1f645"],':ok_woman:':["1f646"],':bow:':["1f647"],':see_no_evil:':["1f648"],':hear_no_evil:':["1f649"],':speak_no_evil:':["1f64a"],':raising_hand:':["1f64b"],':raised_hands:':["1f64c"],':person_frowning:':["1f64d"],':person_with_pouting_face:':["1f64e"],':pray:':["1f64f"],':rocket:':["1f680"],':railway_car:':["1f683"],':bullettrain_side:':["1f684"],':bullettrain_front:':["1f685"],':metro:':["1f687"],':station:':["1f689"],':bus:':["1f68c"],':busstop:':["1f68f"],':ambulance:':["1f691"],':fire_engine:':["1f692"],':police_car:':["1f693"],':taxi:':["1f695"],':red_car:':["1f697"],':blue_car:':["1f699"],':truck:':["1f69a"],':ship:':["1f6a2"],':speedboat:':["1f6a4"],':traffic_light:':["1f6a5"],':construction:':["1f6a7"],':rotating_light:':["1f6a8"],':triangular_flag_on_post:':["1f6a9"],':door:':["1f6aa"],':no_entry_sign:':["1f6ab"],':smoking:':["1f6ac"],':no_smoking:':["1f6ad"],':bike:':["1f6b2"],':walking:':["1f6b6"],':mens:':["1f6b9"],':womens:':["1f6ba"],':restroom:':["1f6bb"],':baby_symbol:':["1f6bc"],':toilet:':["1f6bd"],':wc:':["1f6be"],':bath:':["1f6c0"],':metal:':["1f918"],':sign_of_the_horns:':["1f918"],':grinning:':["1f600"],':innocent:':["1f607"],':smiling_imp:':["1f608"],':sunglasses:':["1f60e"],':neutral_face:':["1f610"],':expressionless:':["1f611"],':confused:':["1f615"],':kissing:':["1f617"],':kissing_smiling_eyes:':["1f619"],':stuck_out_tongue:':["1f61b"],':worried:':["1f61f"],':frowning:':["1f626"],':anguished:':["1f627"],':grimacing:':["1f62c"],':open_mouth:':["1f62e"],':hushed:':["1f62f"],':sleeping:':["1f634"],':no_mouth:':["1f636"],':helicopter:':["1f681"],':steam_locomotive:':["1f682"],':train2:':["1f686"],':light_rail:':["1f688"],':tram:':["1f68a"],':oncoming_bus:':["1f68d"],':trolleybus:':["1f68e"],':minibus:':["1f690"],':oncoming_police_car:':["1f694"],':oncoming_taxi:':["1f696"],':oncoming_automobile:':["1f698"],':articulated_lorry:':["1f69b"],':tractor:':["1f69c"],':monorail:':["1f69d"],':mountain_railway:':["1f69e"],':suspension_railway:':["1f69f"],':mountain_cableway:':["1f6a0"],':aerial_tramway:':["1f6a1"],':rowboat:':["1f6a3"],':vertical_traffic_light:':["1f6a6"],':put_litter_in_its_place:':["1f6ae"],':do_not_litter:':["1f6af"],':potable_water:':["1f6b0"],':non-potable_water:':["1f6b1"],':no_bicycles:':["1f6b3"],':bicyclist:':["1f6b4"],':mountain_bicyclist:':["1f6b5"],':no_pedestrians:':["1f6b7"],':children_crossing:':["1f6b8"],':shower:':["1f6bf"],':bathtub:':["1f6c1"],':passport_control:':["1f6c2"],':customs:':["1f6c3"],':baggage_claim:':["1f6c4"],':left_luggage:':["1f6c5"],':earth_africa:':["1f30d"],':earth_americas:':["1f30e"],':globe_with_meridians:':["1f310"],':waxing_crescent_moon:':["1f312"],':waning_gibbous_moon:':["1f316"],':last_quarter_moon:':["1f317"],':waning_crescent_moon:':["1f318"],':new_moon_with_face:':["1f31a"],':last_quarter_moon_with_face:':["1f31c"],':full_moon_with_face:':["1f31d"],':sun_with_face:':["1f31e"],':evergreen_tree:':["1f332"],':deciduous_tree:':["1f333"],':lemon:':["1f34b"],':pear:':["1f350"],':baby_bottle:':["1f37c"],':horse_racing:':["1f3c7"],':rugby_football:':["1f3c9"],':european_post_office:':["1f3e4"],':rat:':["1f400"],':mouse2:':["1f401"],':ox:':["1f402"],':water_buffalo:':["1f403"],':cow2:':["1f404"],':tiger2:':["1f405"],':leopard:':["1f406"],':rabbit2:':["1f407"],':cat2:':["1f408"],':dragon:':["1f409"],':crocodile:':["1f40a"],':whale2:':["1f40b"],':ram:':["1f40f"],':goat:':["1f410"],':rooster:':["1f413"],':dog2:':["1f415"],':pig2:':["1f416"],':dromedary_camel:':["1f42a"],':busts_in_silhouette:':["1f465"],':two_men_holding_hands:':["1f46c"],':two_women_holding_hands:':["1f46d"],':thought_balloon:':["1f4ad"],':euro:':["1f4b6"],':pound:':["1f4b7"],':mailbox_with_mail:':["1f4ec"],':mailbox_with_no_mail:':["1f4ed"],':postal_horn:':["1f4ef"],':no_mobile_phones:':["1f4f5"],':twisted_rightwards_arrows:':["1f500"],':repeat:':["1f501"],':repeat_one:':["1f502"],':arrows_counterclockwise:':["1f504"],':low_brightness:':["1f505"],':high_brightness:':["1f506"],':mute:':["1f507"],':sound:':["1f509"],':no_bell:':["1f515"],':microscope:':["1f52c"],':telescope:':["1f52d"],':clock130:':["1f55c"],':clock230:':["1f55d"],':clock330:':["1f55e"],':clock430:':["1f55f"],':clock530:':["1f560"],':clock630:':["1f561"],':clock730:':["1f562"],':clock830:':["1f563"],':clock930:':["1f564"],':clock1030:':["1f565"],':clock1130:':["1f566"],':clock1230:':["1f567"],':speaker:':["1f508"],':train:':["1f68b"],':film_frames:':["1f39e"],':tickets:':["1f39f"],':admission_tickets:':["1f39f"],':medal:':["1f3c5"],':sports_medal:':["1f3c5"],':lifter:':["1f3cb"],':weight_lifter:':["1f3cb"],':golfer:':["1f3cc"],':motorcycle:':["1f3cd"],':racing_motorcycle:':["1f3cd"],':race_car:':["1f3ce"],':racing_car:':["1f3ce"],':military_medal:':["1f396"],':reminder_ribbon:':["1f397"],':hot_pepper:':["1f336"],':cloud_rain:':["1f327"],':cloud_with_rain:':["1f327"],':cloud_snow:':["1f328"],':cloud_with_snow:':["1f328"],':cloud_lightning:':["1f329"],':cloud_with_lightning:':["1f329"],':cloud_tornado:':["1f32a"],':cloud_with_tornado:':["1f32a"],':fog:':["1f32b"],':wind_blowing_face:':["1f32c"],':chipmunk:':["1f43f"],':spider:':["1f577"],':spider_web:':["1f578"],':thermometer:':["1f321"],':microphone2:':["1f399"],':studio_microphone:':["1f399"],':level_slider:':["1f39a"],':control_knobs:':["1f39b"],':flag_white:':["1f3f3"],':waving_white_flag:':["1f3f3"],':flag_black:':["1f3f4"],':waving_black_flag:':["1f3f4"],':rosette:':["1f3f5"],':label:':["1f3f7"],':camera_with_flash:':["1f4f8"],':projector:':["1f4fd"],':film_projector:':["1f4fd"],':om_symbol:':["1f549"],':dove:':["1f54a"],':dove_of_peace:':["1f54a"],':candle:':["1f56f"],':clock:':["1f570"],':mantlepiece_clock:':["1f570"],':hole:':["1f573"],':dark_sunglasses:':["1f576"],':joystick:':["1f579"],':paperclips:':["1f587"],':linked_paperclips:':["1f587"],':pen_ballpoint:':["1f58a"],':lower_left_ballpoint_pen:':["1f58a"],':pen_fountain:':["1f58b"],':lower_left_fountain_pen:':["1f58b"],':paintbrush:':["1f58c"],':lower_left_paintbrush:':["1f58c"],':crayon:':["1f58d"],':lower_left_crayon:':["1f58d"],':desktop:':["1f5a5"],':desktop_computer:':["1f5a5"],':printer:':["1f5a8"],':trackball:':["1f5b2"],':frame_photo:':["1f5bc"],':frame_with_picture:':["1f5bc"],':dividers:':["1f5c2"],':card_index_dividers:':["1f5c2"],':card_box:':["1f5c3"],':card_file_box:':["1f5c3"],':file_cabinet:':["1f5c4"],':wastebasket:':["1f5d1"],':notepad_spiral:':["1f5d2"],':spiral_note_pad:':["1f5d2"],':calendar_spiral:':["1f5d3"],':spiral_calendar_pad:':["1f5d3"],':compression:':["1f5dc"],':key2:':["1f5dd"],':old_key:':["1f5dd"],':newspaper2:':["1f5de"],':rolled_up_newspaper:':["1f5de"],':dagger:':["1f5e1"],':dagger_knife:':["1f5e1"],':speaking_head:':["1f5e3"],':speaking_head_in_silhouette:':["1f5e3"],':anger_right:':["1f5ef"],':right_anger_bubble:':["1f5ef"],':ballot_box:':["1f5f3"],':ballot_box_with_ballot:':["1f5f3"],':map:':["1f5fa"],':world_map:':["1f5fa"],':sleeping_accommodation:':["1f6cc"],':tools:':["1f6e0"],':hammer_and_wrench:':["1f6e0"],':shield:':["1f6e1"],':oil:':["1f6e2"],':oil_drum:':["1f6e2"],':satellite_orbital:':["1f6f0"],':fork_knife_plate:':["1f37d"],':fork_and_knife_with_plate:':["1f37d"],':eye:':["1f441"],':levitate:':["1f574"],':man_in_business_suit_levitating:':["1f574"],':spy:':["1f575"],':sleuth_or_spy:':["1f575"],':hand_splayed:':["1f590"],':raised_hand_with_fingers_splayed:':["1f590"],':middle_finger:':["1f595"],':reversed_hand_with_middle_finger_extended:':["1f595"],':vulcan:':["1f596"],':raised_hand_with_part_between_middle_and_ring_fingers:':["1f596"],':slight_frown:':["1f641"],':slightly_frowning_face:':["1f641"],':slight_smile:':["1f642"],':slightly_smiling_face:':["1f642"],':mountain_snow:':["1f3d4"],':snow_capped_mountain:':["1f3d4"],':camping:':["1f3d5"],':beach:':["1f3d6"],':beach_with_umbrella:':["1f3d6"],':construction_site:':["1f3d7"],':building_construction:':["1f3d7"],':homes:':["1f3d8"],':house_buildings:':["1f3d8"],':cityscape:':["1f3d9"],':house_abandoned:':["1f3da"],':derelict_house_building:':["1f3da"],':classical_building:':["1f3db"],':desert:':["1f3dc"],':island:':["1f3dd"],':desert_island:':["1f3dd"],':park:':["1f3de"],':national_park:':["1f3de"],':stadium:':["1f3df"],':couch:':["1f6cb"],':couch_and_lamp:':["1f6cb"],':shopping_bags:':["1f6cd"],':bellhop:':["1f6ce"],':bellhop_bell:':["1f6ce"],':bed:':["1f6cf"],':motorway:':["1f6e3"],':railway_track:':["1f6e4"],':railroad_track:':["1f6e4"],':motorboat:':["1f6e5"],':airplane_small:':["1f6e9"],':small_airplane:':["1f6e9"],':airplane_departure:':["1f6eb"],':airplane_arriving:':["1f6ec"],':cruise_ship:':["1f6f3"],':passenger_ship:':["1f6f3"],':tone1:':["1f3fb"],':tone2:':["1f3fc"],':tone3:':["1f3fd"],':tone4:':["1f3fe"],':tone5:':["1f3ff"],':white_sun_small_cloud:':["1f324"],':white_sun_with_small_cloud:':["1f324"],':white_sun_cloud:':["1f325"],':white_sun_behind_cloud:':["1f325"],':white_sun_rain_cloud:':["1f326"],':white_sun_behind_cloud_with_rain:':["1f326"],':mouse_three_button:':["1f5b1"],':three_button_mouse:':["1f5b1"],':upside_down:':["1f643"],':upside_down_face:':["1f643"],':money_mouth:':["1f911"],':money_mouth_face:':["1f911"],':nerd:':["1f913"],':nerd_face:':["1f913"],':hugging:':["1f917"],':hugging_face:':["1f917"],':rolling_eyes:':["1f644"],':face_with_rolling_eyes:':["1f644"],':thinking:':["1f914"],':thinking_face:':["1f914"],':zipper_mouth:':["1f910"],':zipper_mouth_face:':["1f910"],':thermometer_face:':["1f912"],':face_with_thermometer:':["1f912"],':head_bandage:':["1f915"],':face_with_head_bandage:':["1f915"],':robot:':["1f916"],':robot_face:':["1f916"],':lion_face:':["1f981"],':lion:':["1f981"],':unicorn:':["1f984"],':unicorn_face:':["1f984"],':scorpion:':["1f982"],':crab:':["1f980"],':turkey:':["1f983"],':cheese:':["1f9c0"],':cheese_wedge:':["1f9c0"],':hotdog:':["1f32d"],':hot_dog:':["1f32d"],':taco:':["1f32e"],':burrito:':["1f32f"],':popcorn:':["1f37f"],':champagne:':["1f37e"],':bottle_with_popping_cork:':["1f37e"],':bow_and_arrow:':["1f3f9"],':archery:':["1f3f9"],':amphora:':["1f3fa"],':place_of_worship:':["1f6d0"],':worship_symbol:':["1f6d0"],':kaaba:':["1f54b"],':mosque:':["1f54c"],':synagogue:':["1f54d"],':menorah:':["1f54e"],':prayer_beads:':["1f4ff"],':cricket:':["1f3cf"],':cricket_bat_ball:':["1f3cf"],':volleyball:':["1f3d0"],':field_hockey:':["1f3d1"],':hockey:':["1f3d2"],':ping_pong:':["1f3d3"],':table_tennis:':["1f3d3"],':badminton:':["1f3f8"],':fast_forward:':["23e9"],':rewind:':["23ea"],':arrow_double_up:':["23eb"],':arrow_double_down:':["23ec"],':alarm_clock:':["23f0"],':hourglass_flowing_sand:':["23f3"],':ophiuchus:':["26ce"],':white_check_mark:':["2705"],':fist:':["270a"],':raised_hand:':["270b"],':sparkles:':["2728"],':x:':["274c"],':negative_squared_cross_mark:':["274e"],':question:':["2753"],':grey_question:':["2754"],':grey_exclamation:':["2755"],':heavy_plus_sign:':["2795"],':heavy_minus_sign:':["2796"],':heavy_division_sign:':["2797"],':curly_loop:':["27b0"],':wavy_dash:':["3030"],':loop:':["27bf"],':cross:':["271d"],':latin_cross:':["271d"],':keyboard:':["2328"],':writing_hand:':["270d"],':track_next:':["23ed"],':next_track:':["23ed"],':track_previous:':["23ee"],':previous_track:':["23ee"],':play_pause:':["23ef"],':stopwatch:':["23f1"],':timer:':["23f2"],':timer_clock:':["23f2"],':pause_button:':["23f8"],':double_vertical_bar:':["23f8"],':stop_button:':["23f9"],':record_button:':["23fa"],':umbrella2:':["2602"],':snowman2:':["2603"],':comet:':["2604"],':shamrock:':["2618"],':skull_crossbones:':["2620"],':skull_and_crossbones:':["2620"],':radioactive:':["2622"],':radioactive_sign:':["2622"],':biohazard:':["2623"],':biohazard_sign:':["2623"],':orthodox_cross:':["2626"],':star_and_crescent:':["262a"],':peace:':["262e"],':peace_symbol:':["262e"],':yin_yang:':["262f"],':wheel_of_dharma:':["2638"],':frowning2:':["2639"],':white_frowning_face:':["2639"],':hammer_pick:':["2692"],':hammer_and_pick:':["2692"],':crossed_swords:':["2694"],':scales:':["2696"],':alembic:':["2697"],':gear:':["2699"],':atom:':["269b"],':atom_symbol:':["269b"],':fleur-de-lis:':["269c"],':coffin:':["26b0"],':urn:':["26b1"],':funeral_urn:':["26b1"],':thunder_cloud_rain:':["26c8"],':thunder_cloud_and_rain:':["26c8"],':pick:':["26cf"],':helmet_with_cross:':["26d1"],':helmet_with_white_cross:':["26d1"],':chains:':["26d3"],':shinto_shrine:':["26e9"],':mountain:':["26f0"],':beach_umbrella:':["26f1"],':umbrella_on_ground:':["26f1"],':ferry:':["26f4"],':skier:':["26f7"],':ice_skate:':["26f8"],':basketball_player:':["26f9"],':person_with_ball:':["26f9"],':star_of_david:':["2721"],':heart_exclamation:':["2763"],':heavy_heart_exclamation_mark_ornament:':["2763"]};
+ ns.emojioneList = {":kiss_ww:":{"unicode":["1f469-200d-2764-fe0f-200d-1f48b-200d-1f469","1f469-2764-1f48b-1f469"],"fname":"1f469-2764-1f48b-1f469","uc":"1f469-200d-2764-fe0f-200d-1f48b-200d-1f469","isCanonical": true},":couplekiss_ww:":{"unicode":["1f469-200d-2764-fe0f-200d-1f48b-200d-1f469","1f469-2764-1f48b-1f469"],"fname":"1f469-2764-1f48b-1f469","uc":"1f469-200d-2764-fe0f-200d-1f48b-200d-1f469","isCanonical": false},":kiss_mm:":{"unicode":["1f468-200d-2764-fe0f-200d-1f48b-200d-1f468","1f468-2764-1f48b-1f468"],"fname":"1f468-2764-1f48b-1f468","uc":"1f468-200d-2764-fe0f-200d-1f48b-200d-1f468","isCanonical": true},":couplekiss_mm:":{"unicode":["1f468-200d-2764-fe0f-200d-1f48b-200d-1f468","1f468-2764-1f48b-1f468"],"fname":"1f468-2764-1f48b-1f468","uc":"1f468-200d-2764-fe0f-200d-1f48b-200d-1f468","isCanonical": false},":family_mmbb:":{"unicode":["1f468-200d-1f468-200d-1f466-200d-1f466","1f468-1f468-1f466-1f466"],"fname":"1f468-1f468-1f466-1f466","uc":"1f468-200d-1f468-200d-1f466-200d-1f466","isCanonical": true},":family_mmgb:":{"unicode":["1f468-200d-1f468-200d-1f467-200d-1f466","1f468-1f468-1f467-1f466"],"fname":"1f468-1f468-1f467-1f466","uc":"1f468-200d-1f468-200d-1f467-200d-1f466","isCanonical": true},":family_mmgg:":{"unicode":["1f468-200d-1f468-200d-1f467-200d-1f467","1f468-1f468-1f467-1f467"],"fname":"1f468-1f468-1f467-1f467","uc":"1f468-200d-1f468-200d-1f467-200d-1f467","isCanonical": true},":family_mwbb:":{"unicode":["1f468-200d-1f469-200d-1f466-200d-1f466","1f468-1f469-1f466-1f466"],"fname":"1f468-1f469-1f466-1f466","uc":"1f468-200d-1f469-200d-1f466-200d-1f466","isCanonical": true},":family_mwgb:":{"unicode":["1f468-200d-1f469-200d-1f467-200d-1f466","1f468-1f469-1f467-1f466"],"fname":"1f468-1f469-1f467-1f466","uc":"1f468-200d-1f469-200d-1f467-200d-1f466","isCanonical": true},":family_mwgg:":{"unicode":["1f468-200d-1f469-200d-1f467-200d-1f467","1f468-1f469-1f467-1f467"],"fname":"1f468-1f469-1f467-1f467","uc":"1f468-200d-1f469-200d-1f467-200d-1f467","isCanonical": true},":family_wwbb:":{"unicode":["1f469-200d-1f469-200d-1f466-200d-1f466","1f469-1f469-1f466-1f466"],"fname":"1f469-1f469-1f466-1f466","uc":"1f469-200d-1f469-200d-1f466-200d-1f466","isCanonical": true},":family_wwgb:":{"unicode":["1f469-200d-1f469-200d-1f467-200d-1f466","1f469-1f469-1f467-1f466"],"fname":"1f469-1f469-1f467-1f466","uc":"1f469-200d-1f469-200d-1f467-200d-1f466","isCanonical": true},":family_wwgg:":{"unicode":["1f469-200d-1f469-200d-1f467-200d-1f467","1f469-1f469-1f467-1f467"],"fname":"1f469-1f469-1f467-1f467","uc":"1f469-200d-1f469-200d-1f467-200d-1f467","isCanonical": true},":couple_ww:":{"unicode":["1f469-200d-2764-fe0f-200d-1f469","1f469-2764-1f469"],"fname":"1f469-2764-1f469","uc":"1f469-200d-2764-fe0f-200d-1f469","isCanonical": true},":couple_with_heart_ww:":{"unicode":["1f469-200d-2764-fe0f-200d-1f469","1f469-2764-1f469"],"fname":"1f469-2764-1f469","uc":"1f469-200d-2764-fe0f-200d-1f469","isCanonical": false},":couple_mm:":{"unicode":["1f468-200d-2764-fe0f-200d-1f468","1f468-2764-1f468"],"fname":"1f468-2764-1f468","uc":"1f468-200d-2764-fe0f-200d-1f468","isCanonical": true},":couple_with_heart_mm:":{"unicode":["1f468-200d-2764-fe0f-200d-1f468","1f468-2764-1f468"],"fname":"1f468-2764-1f468","uc":"1f468-200d-2764-fe0f-200d-1f468","isCanonical": false},":family_mmb:":{"unicode":["1f468-200d-1f468-200d-1f466","1f468-1f468-1f466"],"fname":"1f468-1f468-1f466","uc":"1f468-200d-1f468-200d-1f466","isCanonical": true},":family_mmg:":{"unicode":["1f468-200d-1f468-200d-1f467","1f468-1f468-1f467"],"fname":"1f468-1f468-1f467","uc":"1f468-200d-1f468-200d-1f467","isCanonical": true},":family_mwg:":{"unicode":["1f468-200d-1f469-200d-1f467","1f468-1f469-1f467"],"fname":"1f468-1f469-1f467","uc":"1f468-200d-1f469-200d-1f467","isCanonical": true},":family_wwb:":{"unicode":["1f469-200d-1f469-200d-1f466","1f469-1f469-1f466"],"fname":"1f469-1f469-1f466","uc":"1f469-200d-1f469-200d-1f466","isCanonical": true},":family_wwg:":{"unicode":["1f469-200d-1f469-200d-1f467","1f469-1f469-1f467"],"fname":"1f469-1f469-1f467","uc":"1f469-200d-1f469-200d-1f467","isCanonical": true},":rainbow_flag:":{"unicode":["1f3f3-fe0f-200d-1f308","1f3f3-1f308"],"fname":"1f3f3-1f308","uc":"1f3f3-fe0f-200d-1f308","isCanonical": true},":gay_pride_flag:":{"unicode":["1f3f3-fe0f-200d-1f308","1f3f3-1f308"],"fname":"1f3f3-1f308","uc":"1f3f3-fe0f-200d-1f308","isCanonical": false},":eye_in_speech_bubble:":{"unicode":["1f441-200d-1f5e8","1f441-1f5e8"],"fname":"1f441-1f5e8","uc":"1f441-200d-1f5e8","isCanonical": true},":hash:":{"unicode":["0023-fe0f-20e3","0023-20e3"],"fname":"0023-20e3","uc":"0023-20e3","isCanonical": true},":zero:":{"unicode":["0030-fe0f-20e3","0030-20e3"],"fname":"0030-20e3","uc":"0030-20e3","isCanonical": true},":one:":{"unicode":["0031-fe0f-20e3","0031-20e3"],"fname":"0031-20e3","uc":"0031-20e3","isCanonical": true},":two:":{"unicode":["0032-fe0f-20e3","0032-20e3"],"fname":"0032-20e3","uc":"0032-20e3","isCanonical": true},":three:":{"unicode":["0033-fe0f-20e3","0033-20e3"],"fname":"0033-20e3","uc":"0033-20e3","isCanonical": true},":four:":{"unicode":["0034-fe0f-20e3","0034-20e3"],"fname":"0034-20e3","uc":"0034-20e3","isCanonical": true},":five:":{"unicode":["0035-fe0f-20e3","0035-20e3"],"fname":"0035-20e3","uc":"0035-20e3","isCanonical": true},":six:":{"unicode":["0036-fe0f-20e3","0036-20e3"],"fname":"0036-20e3","uc":"0036-20e3","isCanonical": true},":seven:":{"unicode":["0037-fe0f-20e3","0037-20e3"],"fname":"0037-20e3","uc":"0037-20e3","isCanonical": true},":eight:":{"unicode":["0038-fe0f-20e3","0038-20e3"],"fname":"0038-20e3","uc":"0038-20e3","isCanonical": true},":nine:":{"unicode":["0039-fe0f-20e3","0039-20e3"],"fname":"0039-20e3","uc":"0039-20e3","isCanonical": true},":asterisk:":{"unicode":["002a-fe0f-20e3","002a-20e3"],"fname":"002a-20e3","uc":"002a-20e3","isCanonical": true},":keycap_asterisk:":{"unicode":["002a-fe0f-20e3","002a-20e3"],"fname":"002a-20e3","uc":"002a-20e3","isCanonical": false},":handball_tone5:":{"unicode":["1f93e-1f3ff"],"fname":"1f93e-1f3ff","uc":"1f93e-1f3ff","isCanonical": true},":handball_tone4:":{"unicode":["1f93e-1f3fe"],"fname":"1f93e-1f3fe","uc":"1f93e-1f3fe","isCanonical": true},":handball_tone3:":{"unicode":["1f93e-1f3fd"],"fname":"1f93e-1f3fd","uc":"1f93e-1f3fd","isCanonical": true},":handball_tone2:":{"unicode":["1f93e-1f3fc"],"fname":"1f93e-1f3fc","uc":"1f93e-1f3fc","isCanonical": true},":handball_tone1:":{"unicode":["1f93e-1f3fb"],"fname":"1f93e-1f3fb","uc":"1f93e-1f3fb","isCanonical": true},":water_polo_tone5:":{"unicode":["1f93d-1f3ff"],"fname":"1f93d-1f3ff","uc":"1f93d-1f3ff","isCanonical": true},":water_polo_tone4:":{"unicode":["1f93d-1f3fe"],"fname":"1f93d-1f3fe","uc":"1f93d-1f3fe","isCanonical": true},":water_polo_tone3:":{"unicode":["1f93d-1f3fd"],"fname":"1f93d-1f3fd","uc":"1f93d-1f3fd","isCanonical": true},":water_polo_tone2:":{"unicode":["1f93d-1f3fc"],"fname":"1f93d-1f3fc","uc":"1f93d-1f3fc","isCanonical": true},":water_polo_tone1:":{"unicode":["1f93d-1f3fb"],"fname":"1f93d-1f3fb","uc":"1f93d-1f3fb","isCanonical": true},":wrestlers_tone5:":{"unicode":["1f93c-1f3ff"],"fname":"1f93c-1f3ff","uc":"1f93c-1f3ff","isCanonical": true},":wrestling_tone5:":{"unicode":["1f93c-1f3ff"],"fname":"1f93c-1f3ff","uc":"1f93c-1f3ff","isCanonical": false},":wrestlers_tone4:":{"unicode":["1f93c-1f3fe"],"fname":"1f93c-1f3fe","uc":"1f93c-1f3fe","isCanonical": true},":wrestling_tone4:":{"unicode":["1f93c-1f3fe"],"fname":"1f93c-1f3fe","uc":"1f93c-1f3fe","isCanonical": false},":wrestlers_tone3:":{"unicode":["1f93c-1f3fd"],"fname":"1f93c-1f3fd","uc":"1f93c-1f3fd","isCanonical": true},":wrestling_tone3:":{"unicode":["1f93c-1f3fd"],"fname":"1f93c-1f3fd","uc":"1f93c-1f3fd","isCanonical": false},":wrestlers_tone2:":{"unicode":["1f93c-1f3fc"],"fname":"1f93c-1f3fc","uc":"1f93c-1f3fc","isCanonical": true},":wrestling_tone2:":{"unicode":["1f93c-1f3fc"],"fname":"1f93c-1f3fc","uc":"1f93c-1f3fc","isCanonical": false},":wrestlers_tone1:":{"unicode":["1f93c-1f3fb"],"fname":"1f93c-1f3fb","uc":"1f93c-1f3fb","isCanonical": true},":wrestling_tone1:":{"unicode":["1f93c-1f3fb"],"fname":"1f93c-1f3fb","uc":"1f93c-1f3fb","isCanonical": false},":juggling_tone5:":{"unicode":["1f939-1f3ff"],"fname":"1f939-1f3ff","uc":"1f939-1f3ff","isCanonical": true},":juggler_tone5:":{"unicode":["1f939-1f3ff"],"fname":"1f939-1f3ff","uc":"1f939-1f3ff","isCanonical": false},":juggling_tone4:":{"unicode":["1f939-1f3fe"],"fname":"1f939-1f3fe","uc":"1f939-1f3fe","isCanonical": true},":juggler_tone4:":{"unicode":["1f939-1f3fe"],"fname":"1f939-1f3fe","uc":"1f939-1f3fe","isCanonical": false},":juggling_tone3:":{"unicode":["1f939-1f3fd"],"fname":"1f939-1f3fd","uc":"1f939-1f3fd","isCanonical": true},":juggler_tone3:":{"unicode":["1f939-1f3fd"],"fname":"1f939-1f3fd","uc":"1f939-1f3fd","isCanonical": false},":juggling_tone2:":{"unicode":["1f939-1f3fc"],"fname":"1f939-1f3fc","uc":"1f939-1f3fc","isCanonical": true},":juggler_tone2:":{"unicode":["1f939-1f3fc"],"fname":"1f939-1f3fc","uc":"1f939-1f3fc","isCanonical": false},":juggling_tone1:":{"unicode":["1f939-1f3fb"],"fname":"1f939-1f3fb","uc":"1f939-1f3fb","isCanonical": true},":juggler_tone1:":{"unicode":["1f939-1f3fb"],"fname":"1f939-1f3fb","uc":"1f939-1f3fb","isCanonical": false},":cartwheel_tone5:":{"unicode":["1f938-1f3ff"],"fname":"1f938-1f3ff","uc":"1f938-1f3ff","isCanonical": true},":person_doing_cartwheel_tone5:":{"unicode":["1f938-1f3ff"],"fname":"1f938-1f3ff","uc":"1f938-1f3ff","isCanonical": false},":cartwheel_tone4:":{"unicode":["1f938-1f3fe"],"fname":"1f938-1f3fe","uc":"1f938-1f3fe","isCanonical": true},":person_doing_cartwheel_tone4:":{"unicode":["1f938-1f3fe"],"fname":"1f938-1f3fe","uc":"1f938-1f3fe","isCanonical": false},":cartwheel_tone3:":{"unicode":["1f938-1f3fd"],"fname":"1f938-1f3fd","uc":"1f938-1f3fd","isCanonical": true},":person_doing_cartwheel_tone3:":{"unicode":["1f938-1f3fd"],"fname":"1f938-1f3fd","uc":"1f938-1f3fd","isCanonical": false},":cartwheel_tone2:":{"unicode":["1f938-1f3fc"],"fname":"1f938-1f3fc","uc":"1f938-1f3fc","isCanonical": true},":person_doing_cartwheel_tone2:":{"unicode":["1f938-1f3fc"],"fname":"1f938-1f3fc","uc":"1f938-1f3fc","isCanonical": false},":cartwheel_tone1:":{"unicode":["1f938-1f3fb"],"fname":"1f938-1f3fb","uc":"1f938-1f3fb","isCanonical": true},":person_doing_cartwheel_tone1:":{"unicode":["1f938-1f3fb"],"fname":"1f938-1f3fb","uc":"1f938-1f3fb","isCanonical": false},":shrug_tone5:":{"unicode":["1f937-1f3ff"],"fname":"1f937-1f3ff","uc":"1f937-1f3ff","isCanonical": true},":shrug_tone4:":{"unicode":["1f937-1f3fe"],"fname":"1f937-1f3fe","uc":"1f937-1f3fe","isCanonical": true},":shrug_tone3:":{"unicode":["1f937-1f3fd"],"fname":"1f937-1f3fd","uc":"1f937-1f3fd","isCanonical": true},":shrug_tone2:":{"unicode":["1f937-1f3fc"],"fname":"1f937-1f3fc","uc":"1f937-1f3fc","isCanonical": true},":shrug_tone1:":{"unicode":["1f937-1f3fb"],"fname":"1f937-1f3fb","uc":"1f937-1f3fb","isCanonical": true},":mrs_claus_tone5:":{"unicode":["1f936-1f3ff"],"fname":"1f936-1f3ff","uc":"1f936-1f3ff","isCanonical": true},":mother_christmas_tone5:":{"unicode":["1f936-1f3ff"],"fname":"1f936-1f3ff","uc":"1f936-1f3ff","isCanonical": false},":mrs_claus_tone4:":{"unicode":["1f936-1f3fe"],"fname":"1f936-1f3fe","uc":"1f936-1f3fe","isCanonical": true},":mother_christmas_tone4:":{"unicode":["1f936-1f3fe"],"fname":"1f936-1f3fe","uc":"1f936-1f3fe","isCanonical": false},":mrs_claus_tone3:":{"unicode":["1f936-1f3fd"],"fname":"1f936-1f3fd","uc":"1f936-1f3fd","isCanonical": true},":mother_christmas_tone3:":{"unicode":["1f936-1f3fd"],"fname":"1f936-1f3fd","uc":"1f936-1f3fd","isCanonical": false},":mrs_claus_tone2:":{"unicode":["1f936-1f3fc"],"fname":"1f936-1f3fc","uc":"1f936-1f3fc","isCanonical": true},":mother_christmas_tone2:":{"unicode":["1f936-1f3fc"],"fname":"1f936-1f3fc","uc":"1f936-1f3fc","isCanonical": false},":mrs_claus_tone1:":{"unicode":["1f936-1f3fb"],"fname":"1f936-1f3fb","uc":"1f936-1f3fb","isCanonical": true},":mother_christmas_tone1:":{"unicode":["1f936-1f3fb"],"fname":"1f936-1f3fb","uc":"1f936-1f3fb","isCanonical": false},":man_in_tuxedo_tone5:":{"unicode":["1f935-1f3ff"],"fname":"1f935-1f3ff","uc":"1f935-1f3ff","isCanonical": true},":tuxedo_tone5:":{"unicode":["1f935-1f3ff"],"fname":"1f935-1f3ff","uc":"1f935-1f3ff","isCanonical": false},":man_in_tuxedo_tone4:":{"unicode":["1f935-1f3fe"],"fname":"1f935-1f3fe","uc":"1f935-1f3fe","isCanonical": true},":tuxedo_tone4:":{"unicode":["1f935-1f3fe"],"fname":"1f935-1f3fe","uc":"1f935-1f3fe","isCanonical": false},":man_in_tuxedo_tone3:":{"unicode":["1f935-1f3fd"],"fname":"1f935-1f3fd","uc":"1f935-1f3fd","isCanonical": true},":tuxedo_tone3:":{"unicode":["1f935-1f3fd"],"fname":"1f935-1f3fd","uc":"1f935-1f3fd","isCanonical": false},":man_in_tuxedo_tone2:":{"unicode":["1f935-1f3fc"],"fname":"1f935-1f3fc","uc":"1f935-1f3fc","isCanonical": true},":tuxedo_tone2:":{"unicode":["1f935-1f3fc"],"fname":"1f935-1f3fc","uc":"1f935-1f3fc","isCanonical": false},":man_in_tuxedo_tone1:":{"unicode":["1f935-1f3fb"],"fname":"1f935-1f3fb","uc":"1f935-1f3fb","isCanonical": true},":tuxedo_tone1:":{"unicode":["1f935-1f3fb"],"fname":"1f935-1f3fb","uc":"1f935-1f3fb","isCanonical": false},":prince_tone5:":{"unicode":["1f934-1f3ff"],"fname":"1f934-1f3ff","uc":"1f934-1f3ff","isCanonical": true},":prince_tone4:":{"unicode":["1f934-1f3fe"],"fname":"1f934-1f3fe","uc":"1f934-1f3fe","isCanonical": true},":prince_tone3:":{"unicode":["1f934-1f3fd"],"fname":"1f934-1f3fd","uc":"1f934-1f3fd","isCanonical": true},":prince_tone2:":{"unicode":["1f934-1f3fc"],"fname":"1f934-1f3fc","uc":"1f934-1f3fc","isCanonical": true},":prince_tone1:":{"unicode":["1f934-1f3fb"],"fname":"1f934-1f3fb","uc":"1f934-1f3fb","isCanonical": true},":selfie_tone5:":{"unicode":["1f933-1f3ff"],"fname":"1f933-1f3ff","uc":"1f933-1f3ff","isCanonical": true},":selfie_tone4:":{"unicode":["1f933-1f3fe"],"fname":"1f933-1f3fe","uc":"1f933-1f3fe","isCanonical": true},":selfie_tone3:":{"unicode":["1f933-1f3fd"],"fname":"1f933-1f3fd","uc":"1f933-1f3fd","isCanonical": true},":selfie_tone2:":{"unicode":["1f933-1f3fc"],"fname":"1f933-1f3fc","uc":"1f933-1f3fc","isCanonical": true},":selfie_tone1:":{"unicode":["1f933-1f3fb"],"fname":"1f933-1f3fb","uc":"1f933-1f3fb","isCanonical": true},":pregnant_woman_tone5:":{"unicode":["1f930-1f3ff"],"fname":"1f930-1f3ff","uc":"1f930-1f3ff","isCanonical": true},":expecting_woman_tone5:":{"unicode":["1f930-1f3ff"],"fname":"1f930-1f3ff","uc":"1f930-1f3ff","isCanonical": false},":pregnant_woman_tone4:":{"unicode":["1f930-1f3fe"],"fname":"1f930-1f3fe","uc":"1f930-1f3fe","isCanonical": true},":expecting_woman_tone4:":{"unicode":["1f930-1f3fe"],"fname":"1f930-1f3fe","uc":"1f930-1f3fe","isCanonical": false},":pregnant_woman_tone3:":{"unicode":["1f930-1f3fd"],"fname":"1f930-1f3fd","uc":"1f930-1f3fd","isCanonical": true},":expecting_woman_tone3:":{"unicode":["1f930-1f3fd"],"fname":"1f930-1f3fd","uc":"1f930-1f3fd","isCanonical": false},":pregnant_woman_tone2:":{"unicode":["1f930-1f3fc"],"fname":"1f930-1f3fc","uc":"1f930-1f3fc","isCanonical": true},":expecting_woman_tone2:":{"unicode":["1f930-1f3fc"],"fname":"1f930-1f3fc","uc":"1f930-1f3fc","isCanonical": false},":pregnant_woman_tone1:":{"unicode":["1f930-1f3fb"],"fname":"1f930-1f3fb","uc":"1f930-1f3fb","isCanonical": true},":expecting_woman_tone1:":{"unicode":["1f930-1f3fb"],"fname":"1f930-1f3fb","uc":"1f930-1f3fb","isCanonical": false},":face_palm_tone5:":{"unicode":["1f926-1f3ff"],"fname":"1f926-1f3ff","uc":"1f926-1f3ff","isCanonical": true},":facepalm_tone5:":{"unicode":["1f926-1f3ff"],"fname":"1f926-1f3ff","uc":"1f926-1f3ff","isCanonical": false},":face_palm_tone4:":{"unicode":["1f926-1f3fe"],"fname":"1f926-1f3fe","uc":"1f926-1f3fe","isCanonical": true},":facepalm_tone4:":{"unicode":["1f926-1f3fe"],"fname":"1f926-1f3fe","uc":"1f926-1f3fe","isCanonical": false},":face_palm_tone3:":{"unicode":["1f926-1f3fd"],"fname":"1f926-1f3fd","uc":"1f926-1f3fd","isCanonical": true},":facepalm_tone3:":{"unicode":["1f926-1f3fd"],"fname":"1f926-1f3fd","uc":"1f926-1f3fd","isCanonical": false},":face_palm_tone2:":{"unicode":["1f926-1f3fc"],"fname":"1f926-1f3fc","uc":"1f926-1f3fc","isCanonical": true},":facepalm_tone2:":{"unicode":["1f926-1f3fc"],"fname":"1f926-1f3fc","uc":"1f926-1f3fc","isCanonical": false},":face_palm_tone1:":{"unicode":["1f926-1f3fb"],"fname":"1f926-1f3fb","uc":"1f926-1f3fb","isCanonical": true},":facepalm_tone1:":{"unicode":["1f926-1f3fb"],"fname":"1f926-1f3fb","uc":"1f926-1f3fb","isCanonical": false},":fingers_crossed_tone5:":{"unicode":["1f91e-1f3ff"],"fname":"1f91e-1f3ff","uc":"1f91e-1f3ff","isCanonical": true},":hand_with_index_and_middle_fingers_crossed_tone5:":{"unicode":["1f91e-1f3ff"],"fname":"1f91e-1f3ff","uc":"1f91e-1f3ff","isCanonical": false},":fingers_crossed_tone4:":{"unicode":["1f91e-1f3fe"],"fname":"1f91e-1f3fe","uc":"1f91e-1f3fe","isCanonical": true},":hand_with_index_and_middle_fingers_crossed_tone4:":{"unicode":["1f91e-1f3fe"],"fname":"1f91e-1f3fe","uc":"1f91e-1f3fe","isCanonical": false},":fingers_crossed_tone3:":{"unicode":["1f91e-1f3fd"],"fname":"1f91e-1f3fd","uc":"1f91e-1f3fd","isCanonical": true},":hand_with_index_and_middle_fingers_crossed_tone3:":{"unicode":["1f91e-1f3fd"],"fname":"1f91e-1f3fd","uc":"1f91e-1f3fd","isCanonical": false},":fingers_crossed_tone2:":{"unicode":["1f91e-1f3fc"],"fname":"1f91e-1f3fc","uc":"1f91e-1f3fc","isCanonical": true},":hand_with_index_and_middle_fingers_crossed_tone2:":{"unicode":["1f91e-1f3fc"],"fname":"1f91e-1f3fc","uc":"1f91e-1f3fc","isCanonical": false},":fingers_crossed_tone1:":{"unicode":["1f91e-1f3fb"],"fname":"1f91e-1f3fb","uc":"1f91e-1f3fb","isCanonical": true},":hand_with_index_and_middle_fingers_crossed_tone1:":{"unicode":["1f91e-1f3fb"],"fname":"1f91e-1f3fb","uc":"1f91e-1f3fb","isCanonical": false},":handshake_tone5:":{"unicode":["1f91d-1f3ff"],"fname":"1f91d-1f3ff","uc":"1f91d-1f3ff","isCanonical": true},":shaking_hands_tone5:":{"unicode":["1f91d-1f3ff"],"fname":"1f91d-1f3ff","uc":"1f91d-1f3ff","isCanonical": false},":handshake_tone4:":{"unicode":["1f91d-1f3fe"],"fname":"1f91d-1f3fe","uc":"1f91d-1f3fe","isCanonical": true},":shaking_hands_tone4:":{"unicode":["1f91d-1f3fe"],"fname":"1f91d-1f3fe","uc":"1f91d-1f3fe","isCanonical": false},":handshake_tone3:":{"unicode":["1f91d-1f3fd"],"fname":"1f91d-1f3fd","uc":"1f91d-1f3fd","isCanonical": true},":shaking_hands_tone3:":{"unicode":["1f91d-1f3fd"],"fname":"1f91d-1f3fd","uc":"1f91d-1f3fd","isCanonical": false},":handshake_tone2:":{"unicode":["1f91d-1f3fc"],"fname":"1f91d-1f3fc","uc":"1f91d-1f3fc","isCanonical": true},":shaking_hands_tone2:":{"unicode":["1f91d-1f3fc"],"fname":"1f91d-1f3fc","uc":"1f91d-1f3fc","isCanonical": false},":handshake_tone1:":{"unicode":["1f91d-1f3fb"],"fname":"1f91d-1f3fb","uc":"1f91d-1f3fb","isCanonical": true},":shaking_hands_tone1:":{"unicode":["1f91d-1f3fb"],"fname":"1f91d-1f3fb","uc":"1f91d-1f3fb","isCanonical": false},":right_facing_fist_tone5:":{"unicode":["1f91c-1f3ff"],"fname":"1f91c-1f3ff","uc":"1f91c-1f3ff","isCanonical": true},":right_fist_tone5:":{"unicode":["1f91c-1f3ff"],"fname":"1f91c-1f3ff","uc":"1f91c-1f3ff","isCanonical": false},":right_facing_fist_tone4:":{"unicode":["1f91c-1f3fe"],"fname":"1f91c-1f3fe","uc":"1f91c-1f3fe","isCanonical": true},":right_fist_tone4:":{"unicode":["1f91c-1f3fe"],"fname":"1f91c-1f3fe","uc":"1f91c-1f3fe","isCanonical": false},":right_facing_fist_tone3:":{"unicode":["1f91c-1f3fd"],"fname":"1f91c-1f3fd","uc":"1f91c-1f3fd","isCanonical": true},":right_fist_tone3:":{"unicode":["1f91c-1f3fd"],"fname":"1f91c-1f3fd","uc":"1f91c-1f3fd","isCanonical": false},":right_facing_fist_tone2:":{"unicode":["1f91c-1f3fc"],"fname":"1f91c-1f3fc","uc":"1f91c-1f3fc","isCanonical": true},":right_fist_tone2:":{"unicode":["1f91c-1f3fc"],"fname":"1f91c-1f3fc","uc":"1f91c-1f3fc","isCanonical": false},":right_facing_fist_tone1:":{"unicode":["1f91c-1f3fb"],"fname":"1f91c-1f3fb","uc":"1f91c-1f3fb","isCanonical": true},":right_fist_tone1:":{"unicode":["1f91c-1f3fb"],"fname":"1f91c-1f3fb","uc":"1f91c-1f3fb","isCanonical": false},":left_facing_fist_tone5:":{"unicode":["1f91b-1f3ff"],"fname":"1f91b-1f3ff","uc":"1f91b-1f3ff","isCanonical": true},":left_fist_tone5:":{"unicode":["1f91b-1f3ff"],"fname":"1f91b-1f3ff","uc":"1f91b-1f3ff","isCanonical": false},":left_facing_fist_tone4:":{"unicode":["1f91b-1f3fe"],"fname":"1f91b-1f3fe","uc":"1f91b-1f3fe","isCanonical": true},":left_fist_tone4:":{"unicode":["1f91b-1f3fe"],"fname":"1f91b-1f3fe","uc":"1f91b-1f3fe","isCanonical": false},":left_facing_fist_tone3:":{"unicode":["1f91b-1f3fd"],"fname":"1f91b-1f3fd","uc":"1f91b-1f3fd","isCanonical": true},":left_fist_tone3:":{"unicode":["1f91b-1f3fd"],"fname":"1f91b-1f3fd","uc":"1f91b-1f3fd","isCanonical": false},":left_facing_fist_tone2:":{"unicode":["1f91b-1f3fc"],"fname":"1f91b-1f3fc","uc":"1f91b-1f3fc","isCanonical": true},":left_fist_tone2:":{"unicode":["1f91b-1f3fc"],"fname":"1f91b-1f3fc","uc":"1f91b-1f3fc","isCanonical": false},":left_facing_fist_tone1:":{"unicode":["1f91b-1f3fb"],"fname":"1f91b-1f3fb","uc":"1f91b-1f3fb","isCanonical": true},":left_fist_tone1:":{"unicode":["1f91b-1f3fb"],"fname":"1f91b-1f3fb","uc":"1f91b-1f3fb","isCanonical": false},":raised_back_of_hand_tone5:":{"unicode":["1f91a-1f3ff"],"fname":"1f91a-1f3ff","uc":"1f91a-1f3ff","isCanonical": true},":back_of_hand_tone5:":{"unicode":["1f91a-1f3ff"],"fname":"1f91a-1f3ff","uc":"1f91a-1f3ff","isCanonical": false},":raised_back_of_hand_tone4:":{"unicode":["1f91a-1f3fe"],"fname":"1f91a-1f3fe","uc":"1f91a-1f3fe","isCanonical": true},":back_of_hand_tone4:":{"unicode":["1f91a-1f3fe"],"fname":"1f91a-1f3fe","uc":"1f91a-1f3fe","isCanonical": false},":raised_back_of_hand_tone3:":{"unicode":["1f91a-1f3fd"],"fname":"1f91a-1f3fd","uc":"1f91a-1f3fd","isCanonical": true},":back_of_hand_tone3:":{"unicode":["1f91a-1f3fd"],"fname":"1f91a-1f3fd","uc":"1f91a-1f3fd","isCanonical": false},":raised_back_of_hand_tone2:":{"unicode":["1f91a-1f3fc"],"fname":"1f91a-1f3fc","uc":"1f91a-1f3fc","isCanonical": true},":back_of_hand_tone2:":{"unicode":["1f91a-1f3fc"],"fname":"1f91a-1f3fc","uc":"1f91a-1f3fc","isCanonical": false},":raised_back_of_hand_tone1:":{"unicode":["1f91a-1f3fb"],"fname":"1f91a-1f3fb","uc":"1f91a-1f3fb","isCanonical": true},":back_of_hand_tone1:":{"unicode":["1f91a-1f3fb"],"fname":"1f91a-1f3fb","uc":"1f91a-1f3fb","isCanonical": false},":call_me_tone5:":{"unicode":["1f919-1f3ff"],"fname":"1f919-1f3ff","uc":"1f919-1f3ff","isCanonical": true},":call_me_hand_tone5:":{"unicode":["1f919-1f3ff"],"fname":"1f919-1f3ff","uc":"1f919-1f3ff","isCanonical": false},":call_me_tone4:":{"unicode":["1f919-1f3fe"],"fname":"1f919-1f3fe","uc":"1f919-1f3fe","isCanonical": true},":call_me_hand_tone4:":{"unicode":["1f919-1f3fe"],"fname":"1f919-1f3fe","uc":"1f919-1f3fe","isCanonical": false},":call_me_tone3:":{"unicode":["1f919-1f3fd"],"fname":"1f919-1f3fd","uc":"1f919-1f3fd","isCanonical": true},":call_me_hand_tone3:":{"unicode":["1f919-1f3fd"],"fname":"1f919-1f3fd","uc":"1f919-1f3fd","isCanonical": false},":call_me_tone2:":{"unicode":["1f919-1f3fc"],"fname":"1f919-1f3fc","uc":"1f919-1f3fc","isCanonical": true},":call_me_hand_tone2:":{"unicode":["1f919-1f3fc"],"fname":"1f919-1f3fc","uc":"1f919-1f3fc","isCanonical": false},":call_me_tone1:":{"unicode":["1f919-1f3fb"],"fname":"1f919-1f3fb","uc":"1f919-1f3fb","isCanonical": true},":call_me_hand_tone1:":{"unicode":["1f919-1f3fb"],"fname":"1f919-1f3fb","uc":"1f919-1f3fb","isCanonical": false},":metal_tone5:":{"unicode":["1f918-1f3ff"],"fname":"1f918-1f3ff","uc":"1f918-1f3ff","isCanonical": true},":sign_of_the_horns_tone5:":{"unicode":["1f918-1f3ff"],"fname":"1f918-1f3ff","uc":"1f918-1f3ff","isCanonical": false},":metal_tone4:":{"unicode":["1f918-1f3fe"],"fname":"1f918-1f3fe","uc":"1f918-1f3fe","isCanonical": true},":sign_of_the_horns_tone4:":{"unicode":["1f918-1f3fe"],"fname":"1f918-1f3fe","uc":"1f918-1f3fe","isCanonical": false},":metal_tone3:":{"unicode":["1f918-1f3fd"],"fname":"1f918-1f3fd","uc":"1f918-1f3fd","isCanonical": true},":sign_of_the_horns_tone3:":{"unicode":["1f918-1f3fd"],"fname":"1f918-1f3fd","uc":"1f918-1f3fd","isCanonical": false},":metal_tone2:":{"unicode":["1f918-1f3fc"],"fname":"1f918-1f3fc","uc":"1f918-1f3fc","isCanonical": true},":sign_of_the_horns_tone2:":{"unicode":["1f918-1f3fc"],"fname":"1f918-1f3fc","uc":"1f918-1f3fc","isCanonical": false},":metal_tone1:":{"unicode":["1f918-1f3fb"],"fname":"1f918-1f3fb","uc":"1f918-1f3fb","isCanonical": true},":sign_of_the_horns_tone1:":{"unicode":["1f918-1f3fb"],"fname":"1f918-1f3fb","uc":"1f918-1f3fb","isCanonical": false},":bath_tone5:":{"unicode":["1f6c0-1f3ff"],"fname":"1f6c0-1f3ff","uc":"1f6c0-1f3ff","isCanonical": true},":bath_tone4:":{"unicode":["1f6c0-1f3fe"],"fname":"1f6c0-1f3fe","uc":"1f6c0-1f3fe","isCanonical": true},":bath_tone3:":{"unicode":["1f6c0-1f3fd"],"fname":"1f6c0-1f3fd","uc":"1f6c0-1f3fd","isCanonical": true},":bath_tone2:":{"unicode":["1f6c0-1f3fc"],"fname":"1f6c0-1f3fc","uc":"1f6c0-1f3fc","isCanonical": true},":bath_tone1:":{"unicode":["1f6c0-1f3fb"],"fname":"1f6c0-1f3fb","uc":"1f6c0-1f3fb","isCanonical": true},":walking_tone5:":{"unicode":["1f6b6-1f3ff"],"fname":"1f6b6-1f3ff","uc":"1f6b6-1f3ff","isCanonical": true},":walking_tone4:":{"unicode":["1f6b6-1f3fe"],"fname":"1f6b6-1f3fe","uc":"1f6b6-1f3fe","isCanonical": true},":walking_tone3:":{"unicode":["1f6b6-1f3fd"],"fname":"1f6b6-1f3fd","uc":"1f6b6-1f3fd","isCanonical": true},":walking_tone2:":{"unicode":["1f6b6-1f3fc"],"fname":"1f6b6-1f3fc","uc":"1f6b6-1f3fc","isCanonical": true},":walking_tone1:":{"unicode":["1f6b6-1f3fb"],"fname":"1f6b6-1f3fb","uc":"1f6b6-1f3fb","isCanonical": true},":mountain_bicyclist_tone5:":{"unicode":["1f6b5-1f3ff"],"fname":"1f6b5-1f3ff","uc":"1f6b5-1f3ff","isCanonical": true},":mountain_bicyclist_tone4:":{"unicode":["1f6b5-1f3fe"],"fname":"1f6b5-1f3fe","uc":"1f6b5-1f3fe","isCanonical": true},":mountain_bicyclist_tone3:":{"unicode":["1f6b5-1f3fd"],"fname":"1f6b5-1f3fd","uc":"1f6b5-1f3fd","isCanonical": true},":mountain_bicyclist_tone2:":{"unicode":["1f6b5-1f3fc"],"fname":"1f6b5-1f3fc","uc":"1f6b5-1f3fc","isCanonical": true},":mountain_bicyclist_tone1:":{"unicode":["1f6b5-1f3fb"],"fname":"1f6b5-1f3fb","uc":"1f6b5-1f3fb","isCanonical": true},":bicyclist_tone5:":{"unicode":["1f6b4-1f3ff"],"fname":"1f6b4-1f3ff","uc":"1f6b4-1f3ff","isCanonical": true},":bicyclist_tone4:":{"unicode":["1f6b4-1f3fe"],"fname":"1f6b4-1f3fe","uc":"1f6b4-1f3fe","isCanonical": true},":bicyclist_tone3:":{"unicode":["1f6b4-1f3fd"],"fname":"1f6b4-1f3fd","uc":"1f6b4-1f3fd","isCanonical": true},":bicyclist_tone2:":{"unicode":["1f6b4-1f3fc"],"fname":"1f6b4-1f3fc","uc":"1f6b4-1f3fc","isCanonical": true},":bicyclist_tone1:":{"unicode":["1f6b4-1f3fb"],"fname":"1f6b4-1f3fb","uc":"1f6b4-1f3fb","isCanonical": true},":rowboat_tone5:":{"unicode":["1f6a3-1f3ff"],"fname":"1f6a3-1f3ff","uc":"1f6a3-1f3ff","isCanonical": true},":rowboat_tone4:":{"unicode":["1f6a3-1f3fe"],"fname":"1f6a3-1f3fe","uc":"1f6a3-1f3fe","isCanonical": true},":rowboat_tone3:":{"unicode":["1f6a3-1f3fd"],"fname":"1f6a3-1f3fd","uc":"1f6a3-1f3fd","isCanonical": true},":rowboat_tone2:":{"unicode":["1f6a3-1f3fc"],"fname":"1f6a3-1f3fc","uc":"1f6a3-1f3fc","isCanonical": true},":rowboat_tone1:":{"unicode":["1f6a3-1f3fb"],"fname":"1f6a3-1f3fb","uc":"1f6a3-1f3fb","isCanonical": true},":pray_tone5:":{"unicode":["1f64f-1f3ff"],"fname":"1f64f-1f3ff","uc":"1f64f-1f3ff","isCanonical": true},":pray_tone4:":{"unicode":["1f64f-1f3fe"],"fname":"1f64f-1f3fe","uc":"1f64f-1f3fe","isCanonical": true},":pray_tone3:":{"unicode":["1f64f-1f3fd"],"fname":"1f64f-1f3fd","uc":"1f64f-1f3fd","isCanonical": true},":pray_tone2:":{"unicode":["1f64f-1f3fc"],"fname":"1f64f-1f3fc","uc":"1f64f-1f3fc","isCanonical": true},":pray_tone1:":{"unicode":["1f64f-1f3fb"],"fname":"1f64f-1f3fb","uc":"1f64f-1f3fb","isCanonical": true},":person_with_pouting_face_tone5:":{"unicode":["1f64e-1f3ff"],"fname":"1f64e-1f3ff","uc":"1f64e-1f3ff","isCanonical": true},":person_with_pouting_face_tone4:":{"unicode":["1f64e-1f3fe"],"fname":"1f64e-1f3fe","uc":"1f64e-1f3fe","isCanonical": true},":person_with_pouting_face_tone3:":{"unicode":["1f64e-1f3fd"],"fname":"1f64e-1f3fd","uc":"1f64e-1f3fd","isCanonical": true},":person_with_pouting_face_tone2:":{"unicode":["1f64e-1f3fc"],"fname":"1f64e-1f3fc","uc":"1f64e-1f3fc","isCanonical": true},":person_with_pouting_face_tone1:":{"unicode":["1f64e-1f3fb"],"fname":"1f64e-1f3fb","uc":"1f64e-1f3fb","isCanonical": true},":person_frowning_tone5:":{"unicode":["1f64d-1f3ff"],"fname":"1f64d-1f3ff","uc":"1f64d-1f3ff","isCanonical": true},":person_frowning_tone4:":{"unicode":["1f64d-1f3fe"],"fname":"1f64d-1f3fe","uc":"1f64d-1f3fe","isCanonical": true},":person_frowning_tone3:":{"unicode":["1f64d-1f3fd"],"fname":"1f64d-1f3fd","uc":"1f64d-1f3fd","isCanonical": true},":person_frowning_tone2:":{"unicode":["1f64d-1f3fc"],"fname":"1f64d-1f3fc","uc":"1f64d-1f3fc","isCanonical": true},":person_frowning_tone1:":{"unicode":["1f64d-1f3fb"],"fname":"1f64d-1f3fb","uc":"1f64d-1f3fb","isCanonical": true},":raised_hands_tone5:":{"unicode":["1f64c-1f3ff"],"fname":"1f64c-1f3ff","uc":"1f64c-1f3ff","isCanonical": true},":raised_hands_tone4:":{"unicode":["1f64c-1f3fe"],"fname":"1f64c-1f3fe","uc":"1f64c-1f3fe","isCanonical": true},":raised_hands_tone3:":{"unicode":["1f64c-1f3fd"],"fname":"1f64c-1f3fd","uc":"1f64c-1f3fd","isCanonical": true},":raised_hands_tone2:":{"unicode":["1f64c-1f3fc"],"fname":"1f64c-1f3fc","uc":"1f64c-1f3fc","isCanonical": true},":raised_hands_tone1:":{"unicode":["1f64c-1f3fb"],"fname":"1f64c-1f3fb","uc":"1f64c-1f3fb","isCanonical": true},":raising_hand_tone5:":{"unicode":["1f64b-1f3ff"],"fname":"1f64b-1f3ff","uc":"1f64b-1f3ff","isCanonical": true},":raising_hand_tone4:":{"unicode":["1f64b-1f3fe"],"fname":"1f64b-1f3fe","uc":"1f64b-1f3fe","isCanonical": true},":raising_hand_tone3:":{"unicode":["1f64b-1f3fd"],"fname":"1f64b-1f3fd","uc":"1f64b-1f3fd","isCanonical": true},":raising_hand_tone2:":{"unicode":["1f64b-1f3fc"],"fname":"1f64b-1f3fc","uc":"1f64b-1f3fc","isCanonical": true},":raising_hand_tone1:":{"unicode":["1f64b-1f3fb"],"fname":"1f64b-1f3fb","uc":"1f64b-1f3fb","isCanonical": true},":bow_tone5:":{"unicode":["1f647-1f3ff"],"fname":"1f647-1f3ff","uc":"1f647-1f3ff","isCanonical": true},":bow_tone4:":{"unicode":["1f647-1f3fe"],"fname":"1f647-1f3fe","uc":"1f647-1f3fe","isCanonical": true},":bow_tone3:":{"unicode":["1f647-1f3fd"],"fname":"1f647-1f3fd","uc":"1f647-1f3fd","isCanonical": true},":bow_tone2:":{"unicode":["1f647-1f3fc"],"fname":"1f647-1f3fc","uc":"1f647-1f3fc","isCanonical": true},":bow_tone1:":{"unicode":["1f647-1f3fb"],"fname":"1f647-1f3fb","uc":"1f647-1f3fb","isCanonical": true},":ok_woman_tone5:":{"unicode":["1f646-1f3ff"],"fname":"1f646-1f3ff","uc":"1f646-1f3ff","isCanonical": true},":ok_woman_tone4:":{"unicode":["1f646-1f3fe"],"fname":"1f646-1f3fe","uc":"1f646-1f3fe","isCanonical": true},":ok_woman_tone3:":{"unicode":["1f646-1f3fd"],"fname":"1f646-1f3fd","uc":"1f646-1f3fd","isCanonical": true},":ok_woman_tone2:":{"unicode":["1f646-1f3fc"],"fname":"1f646-1f3fc","uc":"1f646-1f3fc","isCanonical": true},":ok_woman_tone1:":{"unicode":["1f646-1f3fb"],"fname":"1f646-1f3fb","uc":"1f646-1f3fb","isCanonical": true},":no_good_tone5:":{"unicode":["1f645-1f3ff"],"fname":"1f645-1f3ff","uc":"1f645-1f3ff","isCanonical": true},":no_good_tone4:":{"unicode":["1f645-1f3fe"],"fname":"1f645-1f3fe","uc":"1f645-1f3fe","isCanonical": true},":no_good_tone3:":{"unicode":["1f645-1f3fd"],"fname":"1f645-1f3fd","uc":"1f645-1f3fd","isCanonical": true},":no_good_tone2:":{"unicode":["1f645-1f3fc"],"fname":"1f645-1f3fc","uc":"1f645-1f3fc","isCanonical": true},":no_good_tone1:":{"unicode":["1f645-1f3fb"],"fname":"1f645-1f3fb","uc":"1f645-1f3fb","isCanonical": true},":vulcan_tone5:":{"unicode":["1f596-1f3ff"],"fname":"1f596-1f3ff","uc":"1f596-1f3ff","isCanonical": true},":raised_hand_with_part_between_middle_and_ring_fingers_tone5:":{"unicode":["1f596-1f3ff"],"fname":"1f596-1f3ff","uc":"1f596-1f3ff","isCanonical": false},":vulcan_tone4:":{"unicode":["1f596-1f3fe"],"fname":"1f596-1f3fe","uc":"1f596-1f3fe","isCanonical": true},":raised_hand_with_part_between_middle_and_ring_fingers_tone4:":{"unicode":["1f596-1f3fe"],"fname":"1f596-1f3fe","uc":"1f596-1f3fe","isCanonical": false},":vulcan_tone3:":{"unicode":["1f596-1f3fd"],"fname":"1f596-1f3fd","uc":"1f596-1f3fd","isCanonical": true},":raised_hand_with_part_between_middle_and_ring_fingers_tone3:":{"unicode":["1f596-1f3fd"],"fname":"1f596-1f3fd","uc":"1f596-1f3fd","isCanonical": false},":vulcan_tone2:":{"unicode":["1f596-1f3fc"],"fname":"1f596-1f3fc","uc":"1f596-1f3fc","isCanonical": true},":raised_hand_with_part_between_middle_and_ring_fingers_tone2:":{"unicode":["1f596-1f3fc"],"fname":"1f596-1f3fc","uc":"1f596-1f3fc","isCanonical": false},":vulcan_tone1:":{"unicode":["1f596-1f3fb"],"fname":"1f596-1f3fb","uc":"1f596-1f3fb","isCanonical": true},":raised_hand_with_part_between_middle_and_ring_fingers_tone1:":{"unicode":["1f596-1f3fb"],"fname":"1f596-1f3fb","uc":"1f596-1f3fb","isCanonical": false},":middle_finger_tone5:":{"unicode":["1f595-1f3ff"],"fname":"1f595-1f3ff","uc":"1f595-1f3ff","isCanonical": true},":reversed_hand_with_middle_finger_extended_tone5:":{"unicode":["1f595-1f3ff"],"fname":"1f595-1f3ff","uc":"1f595-1f3ff","isCanonical": false},":middle_finger_tone4:":{"unicode":["1f595-1f3fe"],"fname":"1f595-1f3fe","uc":"1f595-1f3fe","isCanonical": true},":reversed_hand_with_middle_finger_extended_tone4:":{"unicode":["1f595-1f3fe"],"fname":"1f595-1f3fe","uc":"1f595-1f3fe","isCanonical": false},":middle_finger_tone3:":{"unicode":["1f595-1f3fd"],"fname":"1f595-1f3fd","uc":"1f595-1f3fd","isCanonical": true},":reversed_hand_with_middle_finger_extended_tone3:":{"unicode":["1f595-1f3fd"],"fname":"1f595-1f3fd","uc":"1f595-1f3fd","isCanonical": false},":middle_finger_tone2:":{"unicode":["1f595-1f3fc"],"fname":"1f595-1f3fc","uc":"1f595-1f3fc","isCanonical": true},":reversed_hand_with_middle_finger_extended_tone2:":{"unicode":["1f595-1f3fc"],"fname":"1f595-1f3fc","uc":"1f595-1f3fc","isCanonical": false},":middle_finger_tone1:":{"unicode":["1f595-1f3fb"],"fname":"1f595-1f3fb","uc":"1f595-1f3fb","isCanonical": true},":reversed_hand_with_middle_finger_extended_tone1:":{"unicode":["1f595-1f3fb"],"fname":"1f595-1f3fb","uc":"1f595-1f3fb","isCanonical": false},":hand_splayed_tone5:":{"unicode":["1f590-1f3ff"],"fname":"1f590-1f3ff","uc":"1f590-1f3ff","isCanonical": true},":raised_hand_with_fingers_splayed_tone5:":{"unicode":["1f590-1f3ff"],"fname":"1f590-1f3ff","uc":"1f590-1f3ff","isCanonical": false},":hand_splayed_tone4:":{"unicode":["1f590-1f3fe"],"fname":"1f590-1f3fe","uc":"1f590-1f3fe","isCanonical": true},":raised_hand_with_fingers_splayed_tone4:":{"unicode":["1f590-1f3fe"],"fname":"1f590-1f3fe","uc":"1f590-1f3fe","isCanonical": false},":hand_splayed_tone3:":{"unicode":["1f590-1f3fd"],"fname":"1f590-1f3fd","uc":"1f590-1f3fd","isCanonical": true},":raised_hand_with_fingers_splayed_tone3:":{"unicode":["1f590-1f3fd"],"fname":"1f590-1f3fd","uc":"1f590-1f3fd","isCanonical": false},":hand_splayed_tone2:":{"unicode":["1f590-1f3fc"],"fname":"1f590-1f3fc","uc":"1f590-1f3fc","isCanonical": true},":raised_hand_with_fingers_splayed_tone2:":{"unicode":["1f590-1f3fc"],"fname":"1f590-1f3fc","uc":"1f590-1f3fc","isCanonical": false},":hand_splayed_tone1:":{"unicode":["1f590-1f3fb"],"fname":"1f590-1f3fb","uc":"1f590-1f3fb","isCanonical": true},":raised_hand_with_fingers_splayed_tone1:":{"unicode":["1f590-1f3fb"],"fname":"1f590-1f3fb","uc":"1f590-1f3fb","isCanonical": false},":man_dancing_tone5:":{"unicode":["1f57a-1f3ff"],"fname":"1f57a-1f3ff","uc":"1f57a-1f3ff","isCanonical": true},":male_dancer_tone5:":{"unicode":["1f57a-1f3ff"],"fname":"1f57a-1f3ff","uc":"1f57a-1f3ff","isCanonical": false},":man_dancing_tone4:":{"unicode":["1f57a-1f3fe"],"fname":"1f57a-1f3fe","uc":"1f57a-1f3fe","isCanonical": true},":male_dancer_tone4:":{"unicode":["1f57a-1f3fe"],"fname":"1f57a-1f3fe","uc":"1f57a-1f3fe","isCanonical": false},":man_dancing_tone3:":{"unicode":["1f57a-1f3fd"],"fname":"1f57a-1f3fd","uc":"1f57a-1f3fd","isCanonical": true},":male_dancer_tone3:":{"unicode":["1f57a-1f3fd"],"fname":"1f57a-1f3fd","uc":"1f57a-1f3fd","isCanonical": false},":man_dancing_tone2:":{"unicode":["1f57a-1f3fc"],"fname":"1f57a-1f3fc","uc":"1f57a-1f3fc","isCanonical": true},":male_dancer_tone2:":{"unicode":["1f57a-1f3fc"],"fname":"1f57a-1f3fc","uc":"1f57a-1f3fc","isCanonical": false},":man_dancing_tone1:":{"unicode":["1f57a-1f3fb"],"fname":"1f57a-1f3fb","uc":"1f57a-1f3fb","isCanonical": true},":male_dancer_tone1:":{"unicode":["1f57a-1f3fb"],"fname":"1f57a-1f3fb","uc":"1f57a-1f3fb","isCanonical": false},":spy_tone5:":{"unicode":["1f575-1f3ff"],"fname":"1f575-1f3ff","uc":"1f575-1f3ff","isCanonical": true},":sleuth_or_spy_tone5:":{"unicode":["1f575-1f3ff"],"fname":"1f575-1f3ff","uc":"1f575-1f3ff","isCanonical": false},":spy_tone4:":{"unicode":["1f575-1f3fe"],"fname":"1f575-1f3fe","uc":"1f575-1f3fe","isCanonical": true},":sleuth_or_spy_tone4:":{"unicode":["1f575-1f3fe"],"fname":"1f575-1f3fe","uc":"1f575-1f3fe","isCanonical": false},":spy_tone3:":{"unicode":["1f575-1f3fd"],"fname":"1f575-1f3fd","uc":"1f575-1f3fd","isCanonical": true},":sleuth_or_spy_tone3:":{"unicode":["1f575-1f3fd"],"fname":"1f575-1f3fd","uc":"1f575-1f3fd","isCanonical": false},":spy_tone2:":{"unicode":["1f575-1f3fc"],"fname":"1f575-1f3fc","uc":"1f575-1f3fc","isCanonical": true},":sleuth_or_spy_tone2:":{"unicode":["1f575-1f3fc"],"fname":"1f575-1f3fc","uc":"1f575-1f3fc","isCanonical": false},":spy_tone1:":{"unicode":["1f575-1f3fb"],"fname":"1f575-1f3fb","uc":"1f575-1f3fb","isCanonical": true},":sleuth_or_spy_tone1:":{"unicode":["1f575-1f3fb"],"fname":"1f575-1f3fb","uc":"1f575-1f3fb","isCanonical": false},":muscle_tone5:":{"unicode":["1f4aa-1f3ff"],"fname":"1f4aa-1f3ff","uc":"1f4aa-1f3ff","isCanonical": true},":muscle_tone4:":{"unicode":["1f4aa-1f3fe"],"fname":"1f4aa-1f3fe","uc":"1f4aa-1f3fe","isCanonical": true},":muscle_tone3:":{"unicode":["1f4aa-1f3fd"],"fname":"1f4aa-1f3fd","uc":"1f4aa-1f3fd","isCanonical": true},":muscle_tone2:":{"unicode":["1f4aa-1f3fc"],"fname":"1f4aa-1f3fc","uc":"1f4aa-1f3fc","isCanonical": true},":muscle_tone1:":{"unicode":["1f4aa-1f3fb"],"fname":"1f4aa-1f3fb","uc":"1f4aa-1f3fb","isCanonical": true},":haircut_tone5:":{"unicode":["1f487-1f3ff"],"fname":"1f487-1f3ff","uc":"1f487-1f3ff","isCanonical": true},":haircut_tone4:":{"unicode":["1f487-1f3fe"],"fname":"1f487-1f3fe","uc":"1f487-1f3fe","isCanonical": true},":haircut_tone3:":{"unicode":["1f487-1f3fd"],"fname":"1f487-1f3fd","uc":"1f487-1f3fd","isCanonical": true},":haircut_tone2:":{"unicode":["1f487-1f3fc"],"fname":"1f487-1f3fc","uc":"1f487-1f3fc","isCanonical": true},":haircut_tone1:":{"unicode":["1f487-1f3fb"],"fname":"1f487-1f3fb","uc":"1f487-1f3fb","isCanonical": true},":massage_tone5:":{"unicode":["1f486-1f3ff"],"fname":"1f486-1f3ff","uc":"1f486-1f3ff","isCanonical": true},":massage_tone4:":{"unicode":["1f486-1f3fe"],"fname":"1f486-1f3fe","uc":"1f486-1f3fe","isCanonical": true},":massage_tone3:":{"unicode":["1f486-1f3fd"],"fname":"1f486-1f3fd","uc":"1f486-1f3fd","isCanonical": true},":massage_tone2:":{"unicode":["1f486-1f3fc"],"fname":"1f486-1f3fc","uc":"1f486-1f3fc","isCanonical": true},":massage_tone1:":{"unicode":["1f486-1f3fb"],"fname":"1f486-1f3fb","uc":"1f486-1f3fb","isCanonical": true},":nail_care_tone5:":{"unicode":["1f485-1f3ff"],"fname":"1f485-1f3ff","uc":"1f485-1f3ff","isCanonical": true},":nail_care_tone4:":{"unicode":["1f485-1f3fe"],"fname":"1f485-1f3fe","uc":"1f485-1f3fe","isCanonical": true},":nail_care_tone3:":{"unicode":["1f485-1f3fd"],"fname":"1f485-1f3fd","uc":"1f485-1f3fd","isCanonical": true},":nail_care_tone2:":{"unicode":["1f485-1f3fc"],"fname":"1f485-1f3fc","uc":"1f485-1f3fc","isCanonical": true},":nail_care_tone1:":{"unicode":["1f485-1f3fb"],"fname":"1f485-1f3fb","uc":"1f485-1f3fb","isCanonical": true},":dancer_tone5:":{"unicode":["1f483-1f3ff"],"fname":"1f483-1f3ff","uc":"1f483-1f3ff","isCanonical": true},":dancer_tone4:":{"unicode":["1f483-1f3fe"],"fname":"1f483-1f3fe","uc":"1f483-1f3fe","isCanonical": true},":dancer_tone3:":{"unicode":["1f483-1f3fd"],"fname":"1f483-1f3fd","uc":"1f483-1f3fd","isCanonical": true},":dancer_tone2:":{"unicode":["1f483-1f3fc"],"fname":"1f483-1f3fc","uc":"1f483-1f3fc","isCanonical": true},":dancer_tone1:":{"unicode":["1f483-1f3fb"],"fname":"1f483-1f3fb","uc":"1f483-1f3fb","isCanonical": true},":guardsman_tone5:":{"unicode":["1f482-1f3ff"],"fname":"1f482-1f3ff","uc":"1f482-1f3ff","isCanonical": true},":guardsman_tone4:":{"unicode":["1f482-1f3fe"],"fname":"1f482-1f3fe","uc":"1f482-1f3fe","isCanonical": true},":guardsman_tone3:":{"unicode":["1f482-1f3fd"],"fname":"1f482-1f3fd","uc":"1f482-1f3fd","isCanonical": true},":guardsman_tone2:":{"unicode":["1f482-1f3fc"],"fname":"1f482-1f3fc","uc":"1f482-1f3fc","isCanonical": true},":guardsman_tone1:":{"unicode":["1f482-1f3fb"],"fname":"1f482-1f3fb","uc":"1f482-1f3fb","isCanonical": true},":information_desk_person_tone5:":{"unicode":["1f481-1f3ff"],"fname":"1f481-1f3ff","uc":"1f481-1f3ff","isCanonical": true},":information_desk_person_tone4:":{"unicode":["1f481-1f3fe"],"fname":"1f481-1f3fe","uc":"1f481-1f3fe","isCanonical": true},":information_desk_person_tone3:":{"unicode":["1f481-1f3fd"],"fname":"1f481-1f3fd","uc":"1f481-1f3fd","isCanonical": true},":information_desk_person_tone2:":{"unicode":["1f481-1f3fc"],"fname":"1f481-1f3fc","uc":"1f481-1f3fc","isCanonical": true},":information_desk_person_tone1:":{"unicode":["1f481-1f3fb"],"fname":"1f481-1f3fb","uc":"1f481-1f3fb","isCanonical": true},":angel_tone5:":{"unicode":["1f47c-1f3ff"],"fname":"1f47c-1f3ff","uc":"1f47c-1f3ff","isCanonical": true},":angel_tone4:":{"unicode":["1f47c-1f3fe"],"fname":"1f47c-1f3fe","uc":"1f47c-1f3fe","isCanonical": true},":angel_tone3:":{"unicode":["1f47c-1f3fd"],"fname":"1f47c-1f3fd","uc":"1f47c-1f3fd","isCanonical": true},":angel_tone2:":{"unicode":["1f47c-1f3fc"],"fname":"1f47c-1f3fc","uc":"1f47c-1f3fc","isCanonical": true},":angel_tone1:":{"unicode":["1f47c-1f3fb"],"fname":"1f47c-1f3fb","uc":"1f47c-1f3fb","isCanonical": true},":princess_tone5:":{"unicode":["1f478-1f3ff"],"fname":"1f478-1f3ff","uc":"1f478-1f3ff","isCanonical": true},":princess_tone4:":{"unicode":["1f478-1f3fe"],"fname":"1f478-1f3fe","uc":"1f478-1f3fe","isCanonical": true},":princess_tone3:":{"unicode":["1f478-1f3fd"],"fname":"1f478-1f3fd","uc":"1f478-1f3fd","isCanonical": true},":princess_tone2:":{"unicode":["1f478-1f3fc"],"fname":"1f478-1f3fc","uc":"1f478-1f3fc","isCanonical": true},":princess_tone1:":{"unicode":["1f478-1f3fb"],"fname":"1f478-1f3fb","uc":"1f478-1f3fb","isCanonical": true},":construction_worker_tone5:":{"unicode":["1f477-1f3ff"],"fname":"1f477-1f3ff","uc":"1f477-1f3ff","isCanonical": true},":construction_worker_tone4:":{"unicode":["1f477-1f3fe"],"fname":"1f477-1f3fe","uc":"1f477-1f3fe","isCanonical": true},":construction_worker_tone3:":{"unicode":["1f477-1f3fd"],"fname":"1f477-1f3fd","uc":"1f477-1f3fd","isCanonical": true},":construction_worker_tone2:":{"unicode":["1f477-1f3fc"],"fname":"1f477-1f3fc","uc":"1f477-1f3fc","isCanonical": true},":construction_worker_tone1:":{"unicode":["1f477-1f3fb"],"fname":"1f477-1f3fb","uc":"1f477-1f3fb","isCanonical": true},":baby_tone5:":{"unicode":["1f476-1f3ff"],"fname":"1f476-1f3ff","uc":"1f476-1f3ff","isCanonical": true},":baby_tone4:":{"unicode":["1f476-1f3fe"],"fname":"1f476-1f3fe","uc":"1f476-1f3fe","isCanonical": true},":baby_tone3:":{"unicode":["1f476-1f3fd"],"fname":"1f476-1f3fd","uc":"1f476-1f3fd","isCanonical": true},":baby_tone2:":{"unicode":["1f476-1f3fc"],"fname":"1f476-1f3fc","uc":"1f476-1f3fc","isCanonical": true},":baby_tone1:":{"unicode":["1f476-1f3fb"],"fname":"1f476-1f3fb","uc":"1f476-1f3fb","isCanonical": true},":older_woman_tone5:":{"unicode":["1f475-1f3ff"],"fname":"1f475-1f3ff","uc":"1f475-1f3ff","isCanonical": true},":grandma_tone5:":{"unicode":["1f475-1f3ff"],"fname":"1f475-1f3ff","uc":"1f475-1f3ff","isCanonical": false},":older_woman_tone4:":{"unicode":["1f475-1f3fe"],"fname":"1f475-1f3fe","uc":"1f475-1f3fe","isCanonical": true},":grandma_tone4:":{"unicode":["1f475-1f3fe"],"fname":"1f475-1f3fe","uc":"1f475-1f3fe","isCanonical": false},":older_woman_tone3:":{"unicode":["1f475-1f3fd"],"fname":"1f475-1f3fd","uc":"1f475-1f3fd","isCanonical": true},":grandma_tone3:":{"unicode":["1f475-1f3fd"],"fname":"1f475-1f3fd","uc":"1f475-1f3fd","isCanonical": false},":older_woman_tone2:":{"unicode":["1f475-1f3fc"],"fname":"1f475-1f3fc","uc":"1f475-1f3fc","isCanonical": true},":grandma_tone2:":{"unicode":["1f475-1f3fc"],"fname":"1f475-1f3fc","uc":"1f475-1f3fc","isCanonical": false},":older_woman_tone1:":{"unicode":["1f475-1f3fb"],"fname":"1f475-1f3fb","uc":"1f475-1f3fb","isCanonical": true},":grandma_tone1:":{"unicode":["1f475-1f3fb"],"fname":"1f475-1f3fb","uc":"1f475-1f3fb","isCanonical": false},":older_man_tone5:":{"unicode":["1f474-1f3ff"],"fname":"1f474-1f3ff","uc":"1f474-1f3ff","isCanonical": true},":older_man_tone4:":{"unicode":["1f474-1f3fe"],"fname":"1f474-1f3fe","uc":"1f474-1f3fe","isCanonical": true},":older_man_tone3:":{"unicode":["1f474-1f3fd"],"fname":"1f474-1f3fd","uc":"1f474-1f3fd","isCanonical": true},":older_man_tone2:":{"unicode":["1f474-1f3fc"],"fname":"1f474-1f3fc","uc":"1f474-1f3fc","isCanonical": true},":older_man_tone1:":{"unicode":["1f474-1f3fb"],"fname":"1f474-1f3fb","uc":"1f474-1f3fb","isCanonical": true},":man_with_turban_tone5:":{"unicode":["1f473-1f3ff"],"fname":"1f473-1f3ff","uc":"1f473-1f3ff","isCanonical": true},":man_with_turban_tone4:":{"unicode":["1f473-1f3fe"],"fname":"1f473-1f3fe","uc":"1f473-1f3fe","isCanonical": true},":man_with_turban_tone3:":{"unicode":["1f473-1f3fd"],"fname":"1f473-1f3fd","uc":"1f473-1f3fd","isCanonical": true},":man_with_turban_tone2:":{"unicode":["1f473-1f3fc"],"fname":"1f473-1f3fc","uc":"1f473-1f3fc","isCanonical": true},":man_with_turban_tone1:":{"unicode":["1f473-1f3fb"],"fname":"1f473-1f3fb","uc":"1f473-1f3fb","isCanonical": true},":man_with_gua_pi_mao_tone5:":{"unicode":["1f472-1f3ff"],"fname":"1f472-1f3ff","uc":"1f472-1f3ff","isCanonical": true},":man_with_gua_pi_mao_tone4:":{"unicode":["1f472-1f3fe"],"fname":"1f472-1f3fe","uc":"1f472-1f3fe","isCanonical": true},":man_with_gua_pi_mao_tone3:":{"unicode":["1f472-1f3fd"],"fname":"1f472-1f3fd","uc":"1f472-1f3fd","isCanonical": true},":man_with_gua_pi_mao_tone2:":{"unicode":["1f472-1f3fc"],"fname":"1f472-1f3fc","uc":"1f472-1f3fc","isCanonical": true},":man_with_gua_pi_mao_tone1:":{"unicode":["1f472-1f3fb"],"fname":"1f472-1f3fb","uc":"1f472-1f3fb","isCanonical": true},":person_with_blond_hair_tone5:":{"unicode":["1f471-1f3ff"],"fname":"1f471-1f3ff","uc":"1f471-1f3ff","isCanonical": true},":person_with_blond_hair_tone4:":{"unicode":["1f471-1f3fe"],"fname":"1f471-1f3fe","uc":"1f471-1f3fe","isCanonical": true},":person_with_blond_hair_tone3:":{"unicode":["1f471-1f3fd"],"fname":"1f471-1f3fd","uc":"1f471-1f3fd","isCanonical": true},":person_with_blond_hair_tone2:":{"unicode":["1f471-1f3fc"],"fname":"1f471-1f3fc","uc":"1f471-1f3fc","isCanonical": true},":person_with_blond_hair_tone1:":{"unicode":["1f471-1f3fb"],"fname":"1f471-1f3fb","uc":"1f471-1f3fb","isCanonical": true},":bride_with_veil_tone5:":{"unicode":["1f470-1f3ff"],"fname":"1f470-1f3ff","uc":"1f470-1f3ff","isCanonical": true},":bride_with_veil_tone4:":{"unicode":["1f470-1f3fe"],"fname":"1f470-1f3fe","uc":"1f470-1f3fe","isCanonical": true},":bride_with_veil_tone3:":{"unicode":["1f470-1f3fd"],"fname":"1f470-1f3fd","uc":"1f470-1f3fd","isCanonical": true},":bride_with_veil_tone2:":{"unicode":["1f470-1f3fc"],"fname":"1f470-1f3fc","uc":"1f470-1f3fc","isCanonical": true},":bride_with_veil_tone1:":{"unicode":["1f470-1f3fb"],"fname":"1f470-1f3fb","uc":"1f470-1f3fb","isCanonical": true},":cop_tone5:":{"unicode":["1f46e-1f3ff"],"fname":"1f46e-1f3ff","uc":"1f46e-1f3ff","isCanonical": true},":cop_tone4:":{"unicode":["1f46e-1f3fe"],"fname":"1f46e-1f3fe","uc":"1f46e-1f3fe","isCanonical": true},":cop_tone3:":{"unicode":["1f46e-1f3fd"],"fname":"1f46e-1f3fd","uc":"1f46e-1f3fd","isCanonical": true},":cop_tone2:":{"unicode":["1f46e-1f3fc"],"fname":"1f46e-1f3fc","uc":"1f46e-1f3fc","isCanonical": true},":cop_tone1:":{"unicode":["1f46e-1f3fb"],"fname":"1f46e-1f3fb","uc":"1f46e-1f3fb","isCanonical": true},":woman_tone5:":{"unicode":["1f469-1f3ff"],"fname":"1f469-1f3ff","uc":"1f469-1f3ff","isCanonical": true},":woman_tone4:":{"unicode":["1f469-1f3fe"],"fname":"1f469-1f3fe","uc":"1f469-1f3fe","isCanonical": true},":woman_tone3:":{"unicode":["1f469-1f3fd"],"fname":"1f469-1f3fd","uc":"1f469-1f3fd","isCanonical": true},":woman_tone2:":{"unicode":["1f469-1f3fc"],"fname":"1f469-1f3fc","uc":"1f469-1f3fc","isCanonical": true},":woman_tone1:":{"unicode":["1f469-1f3fb"],"fname":"1f469-1f3fb","uc":"1f469-1f3fb","isCanonical": true},":man_tone5:":{"unicode":["1f468-1f3ff"],"fname":"1f468-1f3ff","uc":"1f468-1f3ff","isCanonical": true},":man_tone4:":{"unicode":["1f468-1f3fe"],"fname":"1f468-1f3fe","uc":"1f468-1f3fe","isCanonical": true},":man_tone3:":{"unicode":["1f468-1f3fd"],"fname":"1f468-1f3fd","uc":"1f468-1f3fd","isCanonical": true},":man_tone2:":{"unicode":["1f468-1f3fc"],"fname":"1f468-1f3fc","uc":"1f468-1f3fc","isCanonical": true},":man_tone1:":{"unicode":["1f468-1f3fb"],"fname":"1f468-1f3fb","uc":"1f468-1f3fb","isCanonical": true},":girl_tone5:":{"unicode":["1f467-1f3ff"],"fname":"1f467-1f3ff","uc":"1f467-1f3ff","isCanonical": true},":girl_tone4:":{"unicode":["1f467-1f3fe"],"fname":"1f467-1f3fe","uc":"1f467-1f3fe","isCanonical": true},":girl_tone3:":{"unicode":["1f467-1f3fd"],"fname":"1f467-1f3fd","uc":"1f467-1f3fd","isCanonical": true},":girl_tone2:":{"unicode":["1f467-1f3fc"],"fname":"1f467-1f3fc","uc":"1f467-1f3fc","isCanonical": true},":girl_tone1:":{"unicode":["1f467-1f3fb"],"fname":"1f467-1f3fb","uc":"1f467-1f3fb","isCanonical": true},":boy_tone5:":{"unicode":["1f466-1f3ff"],"fname":"1f466-1f3ff","uc":"1f466-1f3ff","isCanonical": true},":boy_tone4:":{"unicode":["1f466-1f3fe"],"fname":"1f466-1f3fe","uc":"1f466-1f3fe","isCanonical": true},":boy_tone3:":{"unicode":["1f466-1f3fd"],"fname":"1f466-1f3fd","uc":"1f466-1f3fd","isCanonical": true},":boy_tone2:":{"unicode":["1f466-1f3fc"],"fname":"1f466-1f3fc","uc":"1f466-1f3fc","isCanonical": true},":boy_tone1:":{"unicode":["1f466-1f3fb"],"fname":"1f466-1f3fb","uc":"1f466-1f3fb","isCanonical": true},":open_hands_tone5:":{"unicode":["1f450-1f3ff"],"fname":"1f450-1f3ff","uc":"1f450-1f3ff","isCanonical": true},":open_hands_tone4:":{"unicode":["1f450-1f3fe"],"fname":"1f450-1f3fe","uc":"1f450-1f3fe","isCanonical": true},":open_hands_tone3:":{"unicode":["1f450-1f3fd"],"fname":"1f450-1f3fd","uc":"1f450-1f3fd","isCanonical": true},":open_hands_tone2:":{"unicode":["1f450-1f3fc"],"fname":"1f450-1f3fc","uc":"1f450-1f3fc","isCanonical": true},":open_hands_tone1:":{"unicode":["1f450-1f3fb"],"fname":"1f450-1f3fb","uc":"1f450-1f3fb","isCanonical": true},":clap_tone5:":{"unicode":["1f44f-1f3ff"],"fname":"1f44f-1f3ff","uc":"1f44f-1f3ff","isCanonical": true},":clap_tone4:":{"unicode":["1f44f-1f3fe"],"fname":"1f44f-1f3fe","uc":"1f44f-1f3fe","isCanonical": true},":clap_tone3:":{"unicode":["1f44f-1f3fd"],"fname":"1f44f-1f3fd","uc":"1f44f-1f3fd","isCanonical": true},":clap_tone2:":{"unicode":["1f44f-1f3fc"],"fname":"1f44f-1f3fc","uc":"1f44f-1f3fc","isCanonical": true},":clap_tone1:":{"unicode":["1f44f-1f3fb"],"fname":"1f44f-1f3fb","uc":"1f44f-1f3fb","isCanonical": true},":thumbsdown_tone5:":{"unicode":["1f44e-1f3ff"],"fname":"1f44e-1f3ff","uc":"1f44e-1f3ff","isCanonical": true},":-1_tone5:":{"unicode":["1f44e-1f3ff"],"fname":"1f44e-1f3ff","uc":"1f44e-1f3ff","isCanonical": false},":thumbdown_tone5:":{"unicode":["1f44e-1f3ff"],"fname":"1f44e-1f3ff","uc":"1f44e-1f3ff","isCanonical": false},":thumbsdown_tone4:":{"unicode":["1f44e-1f3fe"],"fname":"1f44e-1f3fe","uc":"1f44e-1f3fe","isCanonical": true},":-1_tone4:":{"unicode":["1f44e-1f3fe"],"fname":"1f44e-1f3fe","uc":"1f44e-1f3fe","isCanonical": false},":thumbdown_tone4:":{"unicode":["1f44e-1f3fe"],"fname":"1f44e-1f3fe","uc":"1f44e-1f3fe","isCanonical": false},":thumbsdown_tone3:":{"unicode":["1f44e-1f3fd"],"fname":"1f44e-1f3fd","uc":"1f44e-1f3fd","isCanonical": true},":-1_tone3:":{"unicode":["1f44e-1f3fd"],"fname":"1f44e-1f3fd","uc":"1f44e-1f3fd","isCanonical": false},":thumbdown_tone3:":{"unicode":["1f44e-1f3fd"],"fname":"1f44e-1f3fd","uc":"1f44e-1f3fd","isCanonical": false},":thumbsdown_tone2:":{"unicode":["1f44e-1f3fc"],"fname":"1f44e-1f3fc","uc":"1f44e-1f3fc","isCanonical": true},":-1_tone2:":{"unicode":["1f44e-1f3fc"],"fname":"1f44e-1f3fc","uc":"1f44e-1f3fc","isCanonical": false},":thumbdown_tone2:":{"unicode":["1f44e-1f3fc"],"fname":"1f44e-1f3fc","uc":"1f44e-1f3fc","isCanonical": false},":thumbsdown_tone1:":{"unicode":["1f44e-1f3fb"],"fname":"1f44e-1f3fb","uc":"1f44e-1f3fb","isCanonical": true},":-1_tone1:":{"unicode":["1f44e-1f3fb"],"fname":"1f44e-1f3fb","uc":"1f44e-1f3fb","isCanonical": false},":thumbdown_tone1:":{"unicode":["1f44e-1f3fb"],"fname":"1f44e-1f3fb","uc":"1f44e-1f3fb","isCanonical": false},":thumbsup_tone5:":{"unicode":["1f44d-1f3ff"],"fname":"1f44d-1f3ff","uc":"1f44d-1f3ff","isCanonical": true},":+1_tone5:":{"unicode":["1f44d-1f3ff"],"fname":"1f44d-1f3ff","uc":"1f44d-1f3ff","isCanonical": false},":thumbup_tone5:":{"unicode":["1f44d-1f3ff"],"fname":"1f44d-1f3ff","uc":"1f44d-1f3ff","isCanonical": false},":thumbsup_tone4:":{"unicode":["1f44d-1f3fe"],"fname":"1f44d-1f3fe","uc":"1f44d-1f3fe","isCanonical": true},":+1_tone4:":{"unicode":["1f44d-1f3fe"],"fname":"1f44d-1f3fe","uc":"1f44d-1f3fe","isCanonical": false},":thumbup_tone4:":{"unicode":["1f44d-1f3fe"],"fname":"1f44d-1f3fe","uc":"1f44d-1f3fe","isCanonical": false},":thumbsup_tone3:":{"unicode":["1f44d-1f3fd"],"fname":"1f44d-1f3fd","uc":"1f44d-1f3fd","isCanonical": true},":+1_tone3:":{"unicode":["1f44d-1f3fd"],"fname":"1f44d-1f3fd","uc":"1f44d-1f3fd","isCanonical": false},":thumbup_tone3:":{"unicode":["1f44d-1f3fd"],"fname":"1f44d-1f3fd","uc":"1f44d-1f3fd","isCanonical": false},":thumbsup_tone2:":{"unicode":["1f44d-1f3fc"],"fname":"1f44d-1f3fc","uc":"1f44d-1f3fc","isCanonical": true},":+1_tone2:":{"unicode":["1f44d-1f3fc"],"fname":"1f44d-1f3fc","uc":"1f44d-1f3fc","isCanonical": false},":thumbup_tone2:":{"unicode":["1f44d-1f3fc"],"fname":"1f44d-1f3fc","uc":"1f44d-1f3fc","isCanonical": false},":thumbsup_tone1:":{"unicode":["1f44d-1f3fb"],"fname":"1f44d-1f3fb","uc":"1f44d-1f3fb","isCanonical": true},":+1_tone1:":{"unicode":["1f44d-1f3fb"],"fname":"1f44d-1f3fb","uc":"1f44d-1f3fb","isCanonical": false},":thumbup_tone1:":{"unicode":["1f44d-1f3fb"],"fname":"1f44d-1f3fb","uc":"1f44d-1f3fb","isCanonical": false},":ok_hand_tone5:":{"unicode":["1f44c-1f3ff"],"fname":"1f44c-1f3ff","uc":"1f44c-1f3ff","isCanonical": true},":ok_hand_tone4:":{"unicode":["1f44c-1f3fe"],"fname":"1f44c-1f3fe","uc":"1f44c-1f3fe","isCanonical": true},":ok_hand_tone3:":{"unicode":["1f44c-1f3fd"],"fname":"1f44c-1f3fd","uc":"1f44c-1f3fd","isCanonical": true},":ok_hand_tone2:":{"unicode":["1f44c-1f3fc"],"fname":"1f44c-1f3fc","uc":"1f44c-1f3fc","isCanonical": true},":ok_hand_tone1:":{"unicode":["1f44c-1f3fb"],"fname":"1f44c-1f3fb","uc":"1f44c-1f3fb","isCanonical": true},":wave_tone5:":{"unicode":["1f44b-1f3ff"],"fname":"1f44b-1f3ff","uc":"1f44b-1f3ff","isCanonical": true},":wave_tone4:":{"unicode":["1f44b-1f3fe"],"fname":"1f44b-1f3fe","uc":"1f44b-1f3fe","isCanonical": true},":wave_tone3:":{"unicode":["1f44b-1f3fd"],"fname":"1f44b-1f3fd","uc":"1f44b-1f3fd","isCanonical": true},":wave_tone2:":{"unicode":["1f44b-1f3fc"],"fname":"1f44b-1f3fc","uc":"1f44b-1f3fc","isCanonical": true},":wave_tone1:":{"unicode":["1f44b-1f3fb"],"fname":"1f44b-1f3fb","uc":"1f44b-1f3fb","isCanonical": true},":punch_tone5:":{"unicode":["1f44a-1f3ff"],"fname":"1f44a-1f3ff","uc":"1f44a-1f3ff","isCanonical": true},":punch_tone4:":{"unicode":["1f44a-1f3fe"],"fname":"1f44a-1f3fe","uc":"1f44a-1f3fe","isCanonical": true},":punch_tone3:":{"unicode":["1f44a-1f3fd"],"fname":"1f44a-1f3fd","uc":"1f44a-1f3fd","isCanonical": true},":punch_tone2:":{"unicode":["1f44a-1f3fc"],"fname":"1f44a-1f3fc","uc":"1f44a-1f3fc","isCanonical": true},":punch_tone1:":{"unicode":["1f44a-1f3fb"],"fname":"1f44a-1f3fb","uc":"1f44a-1f3fb","isCanonical": true},":point_right_tone5:":{"unicode":["1f449-1f3ff"],"fname":"1f449-1f3ff","uc":"1f449-1f3ff","isCanonical": true},":point_right_tone4:":{"unicode":["1f449-1f3fe"],"fname":"1f449-1f3fe","uc":"1f449-1f3fe","isCanonical": true},":point_right_tone3:":{"unicode":["1f449-1f3fd"],"fname":"1f449-1f3fd","uc":"1f449-1f3fd","isCanonical": true},":point_right_tone2:":{"unicode":["1f449-1f3fc"],"fname":"1f449-1f3fc","uc":"1f449-1f3fc","isCanonical": true},":point_right_tone1:":{"unicode":["1f449-1f3fb"],"fname":"1f449-1f3fb","uc":"1f449-1f3fb","isCanonical": true},":point_left_tone5:":{"unicode":["1f448-1f3ff"],"fname":"1f448-1f3ff","uc":"1f448-1f3ff","isCanonical": true},":point_left_tone4:":{"unicode":["1f448-1f3fe"],"fname":"1f448-1f3fe","uc":"1f448-1f3fe","isCanonical": true},":point_left_tone3:":{"unicode":["1f448-1f3fd"],"fname":"1f448-1f3fd","uc":"1f448-1f3fd","isCanonical": true},":point_left_tone2:":{"unicode":["1f448-1f3fc"],"fname":"1f448-1f3fc","uc":"1f448-1f3fc","isCanonical": true},":point_left_tone1:":{"unicode":["1f448-1f3fb"],"fname":"1f448-1f3fb","uc":"1f448-1f3fb","isCanonical": true},":point_down_tone5:":{"unicode":["1f447-1f3ff"],"fname":"1f447-1f3ff","uc":"1f447-1f3ff","isCanonical": true},":point_down_tone4:":{"unicode":["1f447-1f3fe"],"fname":"1f447-1f3fe","uc":"1f447-1f3fe","isCanonical": true},":point_down_tone3:":{"unicode":["1f447-1f3fd"],"fname":"1f447-1f3fd","uc":"1f447-1f3fd","isCanonical": true},":point_down_tone2:":{"unicode":["1f447-1f3fc"],"fname":"1f447-1f3fc","uc":"1f447-1f3fc","isCanonical": true},":point_down_tone1:":{"unicode":["1f447-1f3fb"],"fname":"1f447-1f3fb","uc":"1f447-1f3fb","isCanonical": true},":point_up_2_tone5:":{"unicode":["1f446-1f3ff"],"fname":"1f446-1f3ff","uc":"1f446-1f3ff","isCanonical": true},":point_up_2_tone4:":{"unicode":["1f446-1f3fe"],"fname":"1f446-1f3fe","uc":"1f446-1f3fe","isCanonical": true},":point_up_2_tone3:":{"unicode":["1f446-1f3fd"],"fname":"1f446-1f3fd","uc":"1f446-1f3fd","isCanonical": true},":point_up_2_tone2:":{"unicode":["1f446-1f3fc"],"fname":"1f446-1f3fc","uc":"1f446-1f3fc","isCanonical": true},":point_up_2_tone1:":{"unicode":["1f446-1f3fb"],"fname":"1f446-1f3fb","uc":"1f446-1f3fb","isCanonical": true},":nose_tone5:":{"unicode":["1f443-1f3ff"],"fname":"1f443-1f3ff","uc":"1f443-1f3ff","isCanonical": true},":nose_tone4:":{"unicode":["1f443-1f3fe"],"fname":"1f443-1f3fe","uc":"1f443-1f3fe","isCanonical": true},":nose_tone3:":{"unicode":["1f443-1f3fd"],"fname":"1f443-1f3fd","uc":"1f443-1f3fd","isCanonical": true},":nose_tone2:":{"unicode":["1f443-1f3fc"],"fname":"1f443-1f3fc","uc":"1f443-1f3fc","isCanonical": true},":nose_tone1:":{"unicode":["1f443-1f3fb"],"fname":"1f443-1f3fb","uc":"1f443-1f3fb","isCanonical": true},":ear_tone5:":{"unicode":["1f442-1f3ff"],"fname":"1f442-1f3ff","uc":"1f442-1f3ff","isCanonical": true},":ear_tone4:":{"unicode":["1f442-1f3fe"],"fname":"1f442-1f3fe","uc":"1f442-1f3fe","isCanonical": true},":ear_tone3:":{"unicode":["1f442-1f3fd"],"fname":"1f442-1f3fd","uc":"1f442-1f3fd","isCanonical": true},":ear_tone2:":{"unicode":["1f442-1f3fc"],"fname":"1f442-1f3fc","uc":"1f442-1f3fc","isCanonical": true},":ear_tone1:":{"unicode":["1f442-1f3fb"],"fname":"1f442-1f3fb","uc":"1f442-1f3fb","isCanonical": true},":lifter_tone5:":{"unicode":["1f3cb-1f3ff"],"fname":"1f3cb-1f3ff","uc":"1f3cb-1f3ff","isCanonical": true},":weight_lifter_tone5:":{"unicode":["1f3cb-1f3ff"],"fname":"1f3cb-1f3ff","uc":"1f3cb-1f3ff","isCanonical": false},":lifter_tone4:":{"unicode":["1f3cb-1f3fe"],"fname":"1f3cb-1f3fe","uc":"1f3cb-1f3fe","isCanonical": true},":weight_lifter_tone4:":{"unicode":["1f3cb-1f3fe"],"fname":"1f3cb-1f3fe","uc":"1f3cb-1f3fe","isCanonical": false},":lifter_tone3:":{"unicode":["1f3cb-1f3fd"],"fname":"1f3cb-1f3fd","uc":"1f3cb-1f3fd","isCanonical": true},":weight_lifter_tone3:":{"unicode":["1f3cb-1f3fd"],"fname":"1f3cb-1f3fd","uc":"1f3cb-1f3fd","isCanonical": false},":lifter_tone2:":{"unicode":["1f3cb-1f3fc"],"fname":"1f3cb-1f3fc","uc":"1f3cb-1f3fc","isCanonical": true},":weight_lifter_tone2:":{"unicode":["1f3cb-1f3fc"],"fname":"1f3cb-1f3fc","uc":"1f3cb-1f3fc","isCanonical": false},":lifter_tone1:":{"unicode":["1f3cb-1f3fb"],"fname":"1f3cb-1f3fb","uc":"1f3cb-1f3fb","isCanonical": true},":weight_lifter_tone1:":{"unicode":["1f3cb-1f3fb"],"fname":"1f3cb-1f3fb","uc":"1f3cb-1f3fb","isCanonical": false},":swimmer_tone5:":{"unicode":["1f3ca-1f3ff"],"fname":"1f3ca-1f3ff","uc":"1f3ca-1f3ff","isCanonical": true},":swimmer_tone4:":{"unicode":["1f3ca-1f3fe"],"fname":"1f3ca-1f3fe","uc":"1f3ca-1f3fe","isCanonical": true},":swimmer_tone3:":{"unicode":["1f3ca-1f3fd"],"fname":"1f3ca-1f3fd","uc":"1f3ca-1f3fd","isCanonical": true},":swimmer_tone2:":{"unicode":["1f3ca-1f3fc"],"fname":"1f3ca-1f3fc","uc":"1f3ca-1f3fc","isCanonical": true},":swimmer_tone1:":{"unicode":["1f3ca-1f3fb"],"fname":"1f3ca-1f3fb","uc":"1f3ca-1f3fb","isCanonical": true},":horse_racing_tone5:":{"unicode":["1f3c7-1f3ff"],"fname":"1f3c7-1f3ff","uc":"1f3c7-1f3ff","isCanonical": true},":horse_racing_tone4:":{"unicode":["1f3c7-1f3fe"],"fname":"1f3c7-1f3fe","uc":"1f3c7-1f3fe","isCanonical": true},":horse_racing_tone3:":{"unicode":["1f3c7-1f3fd"],"fname":"1f3c7-1f3fd","uc":"1f3c7-1f3fd","isCanonical": true},":horse_racing_tone2:":{"unicode":["1f3c7-1f3fc"],"fname":"1f3c7-1f3fc","uc":"1f3c7-1f3fc","isCanonical": true},":horse_racing_tone1:":{"unicode":["1f3c7-1f3fb"],"fname":"1f3c7-1f3fb","uc":"1f3c7-1f3fb","isCanonical": true},":surfer_tone5:":{"unicode":["1f3c4-1f3ff"],"fname":"1f3c4-1f3ff","uc":"1f3c4-1f3ff","isCanonical": true},":surfer_tone4:":{"unicode":["1f3c4-1f3fe"],"fname":"1f3c4-1f3fe","uc":"1f3c4-1f3fe","isCanonical": true},":surfer_tone3:":{"unicode":["1f3c4-1f3fd"],"fname":"1f3c4-1f3fd","uc":"1f3c4-1f3fd","isCanonical": true},":surfer_tone2:":{"unicode":["1f3c4-1f3fc"],"fname":"1f3c4-1f3fc","uc":"1f3c4-1f3fc","isCanonical": true},":surfer_tone1:":{"unicode":["1f3c4-1f3fb"],"fname":"1f3c4-1f3fb","uc":"1f3c4-1f3fb","isCanonical": true},":runner_tone5:":{"unicode":["1f3c3-1f3ff"],"fname":"1f3c3-1f3ff","uc":"1f3c3-1f3ff","isCanonical": true},":runner_tone4:":{"unicode":["1f3c3-1f3fe"],"fname":"1f3c3-1f3fe","uc":"1f3c3-1f3fe","isCanonical": true},":runner_tone3:":{"unicode":["1f3c3-1f3fd"],"fname":"1f3c3-1f3fd","uc":"1f3c3-1f3fd","isCanonical": true},":runner_tone2:":{"unicode":["1f3c3-1f3fc"],"fname":"1f3c3-1f3fc","uc":"1f3c3-1f3fc","isCanonical": true},":runner_tone1:":{"unicode":["1f3c3-1f3fb"],"fname":"1f3c3-1f3fb","uc":"1f3c3-1f3fb","isCanonical": true},":santa_tone5:":{"unicode":["1f385-1f3ff"],"fname":"1f385-1f3ff","uc":"1f385-1f3ff","isCanonical": true},":santa_tone4:":{"unicode":["1f385-1f3fe"],"fname":"1f385-1f3fe","uc":"1f385-1f3fe","isCanonical": true},":santa_tone3:":{"unicode":["1f385-1f3fd"],"fname":"1f385-1f3fd","uc":"1f385-1f3fd","isCanonical": true},":santa_tone2:":{"unicode":["1f385-1f3fc"],"fname":"1f385-1f3fc","uc":"1f385-1f3fc","isCanonical": true},":santa_tone1:":{"unicode":["1f385-1f3fb"],"fname":"1f385-1f3fb","uc":"1f385-1f3fb","isCanonical": true},":flag_zw:":{"unicode":["1f1ff-1f1fc"],"fname":"1f1ff-1f1fc","uc":"1f1ff-1f1fc","isCanonical": true},":zw:":{"unicode":["1f1ff-1f1fc"],"fname":"1f1ff-1f1fc","uc":"1f1ff-1f1fc","isCanonical": false},":flag_zm:":{"unicode":["1f1ff-1f1f2"],"fname":"1f1ff-1f1f2","uc":"1f1ff-1f1f2","isCanonical": true},":zm:":{"unicode":["1f1ff-1f1f2"],"fname":"1f1ff-1f1f2","uc":"1f1ff-1f1f2","isCanonical": false},":flag_za:":{"unicode":["1f1ff-1f1e6"],"fname":"1f1ff-1f1e6","uc":"1f1ff-1f1e6","isCanonical": true},":za:":{"unicode":["1f1ff-1f1e6"],"fname":"1f1ff-1f1e6","uc":"1f1ff-1f1e6","isCanonical": false},":flag_yt:":{"unicode":["1f1fe-1f1f9"],"fname":"1f1fe-1f1f9","uc":"1f1fe-1f1f9","isCanonical": true},":yt:":{"unicode":["1f1fe-1f1f9"],"fname":"1f1fe-1f1f9","uc":"1f1fe-1f1f9","isCanonical": false},":flag_ye:":{"unicode":["1f1fe-1f1ea"],"fname":"1f1fe-1f1ea","uc":"1f1fe-1f1ea","isCanonical": true},":ye:":{"unicode":["1f1fe-1f1ea"],"fname":"1f1fe-1f1ea","uc":"1f1fe-1f1ea","isCanonical": false},":flag_xk:":{"unicode":["1f1fd-1f1f0"],"fname":"1f1fd-1f1f0","uc":"1f1fd-1f1f0","isCanonical": true},":xk:":{"unicode":["1f1fd-1f1f0"],"fname":"1f1fd-1f1f0","uc":"1f1fd-1f1f0","isCanonical": false},":flag_ws:":{"unicode":["1f1fc-1f1f8"],"fname":"1f1fc-1f1f8","uc":"1f1fc-1f1f8","isCanonical": true},":ws:":{"unicode":["1f1fc-1f1f8"],"fname":"1f1fc-1f1f8","uc":"1f1fc-1f1f8","isCanonical": false},":flag_wf:":{"unicode":["1f1fc-1f1eb"],"fname":"1f1fc-1f1eb","uc":"1f1fc-1f1eb","isCanonical": true},":wf:":{"unicode":["1f1fc-1f1eb"],"fname":"1f1fc-1f1eb","uc":"1f1fc-1f1eb","isCanonical": false},":flag_vu:":{"unicode":["1f1fb-1f1fa"],"fname":"1f1fb-1f1fa","uc":"1f1fb-1f1fa","isCanonical": true},":vu:":{"unicode":["1f1fb-1f1fa"],"fname":"1f1fb-1f1fa","uc":"1f1fb-1f1fa","isCanonical": false},":flag_vn:":{"unicode":["1f1fb-1f1f3"],"fname":"1f1fb-1f1f3","uc":"1f1fb-1f1f3","isCanonical": true},":vn:":{"unicode":["1f1fb-1f1f3"],"fname":"1f1fb-1f1f3","uc":"1f1fb-1f1f3","isCanonical": false},":flag_vi:":{"unicode":["1f1fb-1f1ee"],"fname":"1f1fb-1f1ee","uc":"1f1fb-1f1ee","isCanonical": true},":vi:":{"unicode":["1f1fb-1f1ee"],"fname":"1f1fb-1f1ee","uc":"1f1fb-1f1ee","isCanonical": false},":flag_vg:":{"unicode":["1f1fb-1f1ec"],"fname":"1f1fb-1f1ec","uc":"1f1fb-1f1ec","isCanonical": true},":vg:":{"unicode":["1f1fb-1f1ec"],"fname":"1f1fb-1f1ec","uc":"1f1fb-1f1ec","isCanonical": false},":flag_ve:":{"unicode":["1f1fb-1f1ea"],"fname":"1f1fb-1f1ea","uc":"1f1fb-1f1ea","isCanonical": true},":ve:":{"unicode":["1f1fb-1f1ea"],"fname":"1f1fb-1f1ea","uc":"1f1fb-1f1ea","isCanonical": false},":flag_vc:":{"unicode":["1f1fb-1f1e8"],"fname":"1f1fb-1f1e8","uc":"1f1fb-1f1e8","isCanonical": true},":vc:":{"unicode":["1f1fb-1f1e8"],"fname":"1f1fb-1f1e8","uc":"1f1fb-1f1e8","isCanonical": false},":flag_va:":{"unicode":["1f1fb-1f1e6"],"fname":"1f1fb-1f1e6","uc":"1f1fb-1f1e6","isCanonical": true},":va:":{"unicode":["1f1fb-1f1e6"],"fname":"1f1fb-1f1e6","uc":"1f1fb-1f1e6","isCanonical": false},":flag_uz:":{"unicode":["1f1fa-1f1ff"],"fname":"1f1fa-1f1ff","uc":"1f1fa-1f1ff","isCanonical": true},":uz:":{"unicode":["1f1fa-1f1ff"],"fname":"1f1fa-1f1ff","uc":"1f1fa-1f1ff","isCanonical": false},":flag_uy:":{"unicode":["1f1fa-1f1fe"],"fname":"1f1fa-1f1fe","uc":"1f1fa-1f1fe","isCanonical": true},":uy:":{"unicode":["1f1fa-1f1fe"],"fname":"1f1fa-1f1fe","uc":"1f1fa-1f1fe","isCanonical": false},":flag_us:":{"unicode":["1f1fa-1f1f8"],"fname":"1f1fa-1f1f8","uc":"1f1fa-1f1f8","isCanonical": true},":us:":{"unicode":["1f1fa-1f1f8"],"fname":"1f1fa-1f1f8","uc":"1f1fa-1f1f8","isCanonical": false},":flag_um:":{"unicode":["1f1fa-1f1f2"],"fname":"1f1fa-1f1f2","uc":"1f1fa-1f1f2","isCanonical": true},":um:":{"unicode":["1f1fa-1f1f2"],"fname":"1f1fa-1f1f2","uc":"1f1fa-1f1f2","isCanonical": false},":flag_ug:":{"unicode":["1f1fa-1f1ec"],"fname":"1f1fa-1f1ec","uc":"1f1fa-1f1ec","isCanonical": true},":ug:":{"unicode":["1f1fa-1f1ec"],"fname":"1f1fa-1f1ec","uc":"1f1fa-1f1ec","isCanonical": false},":flag_ua:":{"unicode":["1f1fa-1f1e6"],"fname":"1f1fa-1f1e6","uc":"1f1fa-1f1e6","isCanonical": true},":ua:":{"unicode":["1f1fa-1f1e6"],"fname":"1f1fa-1f1e6","uc":"1f1fa-1f1e6","isCanonical": false},":flag_tz:":{"unicode":["1f1f9-1f1ff"],"fname":"1f1f9-1f1ff","uc":"1f1f9-1f1ff","isCanonical": true},":tz:":{"unicode":["1f1f9-1f1ff"],"fname":"1f1f9-1f1ff","uc":"1f1f9-1f1ff","isCanonical": false},":flag_tw:":{"unicode":["1f1f9-1f1fc"],"fname":"1f1f9-1f1fc","uc":"1f1f9-1f1fc","isCanonical": true},":tw:":{"unicode":["1f1f9-1f1fc"],"fname":"1f1f9-1f1fc","uc":"1f1f9-1f1fc","isCanonical": false},":flag_tv:":{"unicode":["1f1f9-1f1fb"],"fname":"1f1f9-1f1fb","uc":"1f1f9-1f1fb","isCanonical": true},":tuvalu:":{"unicode":["1f1f9-1f1fb"],"fname":"1f1f9-1f1fb","uc":"1f1f9-1f1fb","isCanonical": false},":flag_tt:":{"unicode":["1f1f9-1f1f9"],"fname":"1f1f9-1f1f9","uc":"1f1f9-1f1f9","isCanonical": true},":tt:":{"unicode":["1f1f9-1f1f9"],"fname":"1f1f9-1f1f9","uc":"1f1f9-1f1f9","isCanonical": false},":flag_tr:":{"unicode":["1f1f9-1f1f7"],"fname":"1f1f9-1f1f7","uc":"1f1f9-1f1f7","isCanonical": true},":tr:":{"unicode":["1f1f9-1f1f7"],"fname":"1f1f9-1f1f7","uc":"1f1f9-1f1f7","isCanonical": false},":flag_to:":{"unicode":["1f1f9-1f1f4"],"fname":"1f1f9-1f1f4","uc":"1f1f9-1f1f4","isCanonical": true},":to:":{"unicode":["1f1f9-1f1f4"],"fname":"1f1f9-1f1f4","uc":"1f1f9-1f1f4","isCanonical": false},":flag_tn:":{"unicode":["1f1f9-1f1f3"],"fname":"1f1f9-1f1f3","uc":"1f1f9-1f1f3","isCanonical": true},":tn:":{"unicode":["1f1f9-1f1f3"],"fname":"1f1f9-1f1f3","uc":"1f1f9-1f1f3","isCanonical": false},":flag_tm:":{"unicode":["1f1f9-1f1f2"],"fname":"1f1f9-1f1f2","uc":"1f1f9-1f1f2","isCanonical": true},":turkmenistan:":{"unicode":["1f1f9-1f1f2"],"fname":"1f1f9-1f1f2","uc":"1f1f9-1f1f2","isCanonical": false},":flag_tl:":{"unicode":["1f1f9-1f1f1"],"fname":"1f1f9-1f1f1","uc":"1f1f9-1f1f1","isCanonical": true},":tl:":{"unicode":["1f1f9-1f1f1"],"fname":"1f1f9-1f1f1","uc":"1f1f9-1f1f1","isCanonical": false},":flag_tk:":{"unicode":["1f1f9-1f1f0"],"fname":"1f1f9-1f1f0","uc":"1f1f9-1f1f0","isCanonical": true},":tk:":{"unicode":["1f1f9-1f1f0"],"fname":"1f1f9-1f1f0","uc":"1f1f9-1f1f0","isCanonical": false},":flag_tj:":{"unicode":["1f1f9-1f1ef"],"fname":"1f1f9-1f1ef","uc":"1f1f9-1f1ef","isCanonical": true},":tj:":{"unicode":["1f1f9-1f1ef"],"fname":"1f1f9-1f1ef","uc":"1f1f9-1f1ef","isCanonical": false},":flag_th:":{"unicode":["1f1f9-1f1ed"],"fname":"1f1f9-1f1ed","uc":"1f1f9-1f1ed","isCanonical": true},":th:":{"unicode":["1f1f9-1f1ed"],"fname":"1f1f9-1f1ed","uc":"1f1f9-1f1ed","isCanonical": false},":flag_tg:":{"unicode":["1f1f9-1f1ec"],"fname":"1f1f9-1f1ec","uc":"1f1f9-1f1ec","isCanonical": true},":tg:":{"unicode":["1f1f9-1f1ec"],"fname":"1f1f9-1f1ec","uc":"1f1f9-1f1ec","isCanonical": false},":flag_tf:":{"unicode":["1f1f9-1f1eb"],"fname":"1f1f9-1f1eb","uc":"1f1f9-1f1eb","isCanonical": true},":tf:":{"unicode":["1f1f9-1f1eb"],"fname":"1f1f9-1f1eb","uc":"1f1f9-1f1eb","isCanonical": false},":flag_td:":{"unicode":["1f1f9-1f1e9"],"fname":"1f1f9-1f1e9","uc":"1f1f9-1f1e9","isCanonical": true},":td:":{"unicode":["1f1f9-1f1e9"],"fname":"1f1f9-1f1e9","uc":"1f1f9-1f1e9","isCanonical": false},":flag_tc:":{"unicode":["1f1f9-1f1e8"],"fname":"1f1f9-1f1e8","uc":"1f1f9-1f1e8","isCanonical": true},":tc:":{"unicode":["1f1f9-1f1e8"],"fname":"1f1f9-1f1e8","uc":"1f1f9-1f1e8","isCanonical": false},":flag_ta:":{"unicode":["1f1f9-1f1e6"],"fname":"1f1f9-1f1e6","uc":"1f1f9-1f1e6","isCanonical": true},":ta:":{"unicode":["1f1f9-1f1e6"],"fname":"1f1f9-1f1e6","uc":"1f1f9-1f1e6","isCanonical": false},":flag_sz:":{"unicode":["1f1f8-1f1ff"],"fname":"1f1f8-1f1ff","uc":"1f1f8-1f1ff","isCanonical": true},":sz:":{"unicode":["1f1f8-1f1ff"],"fname":"1f1f8-1f1ff","uc":"1f1f8-1f1ff","isCanonical": false},":flag_sy:":{"unicode":["1f1f8-1f1fe"],"fname":"1f1f8-1f1fe","uc":"1f1f8-1f1fe","isCanonical": true},":sy:":{"unicode":["1f1f8-1f1fe"],"fname":"1f1f8-1f1fe","uc":"1f1f8-1f1fe","isCanonical": false},":flag_sx:":{"unicode":["1f1f8-1f1fd"],"fname":"1f1f8-1f1fd","uc":"1f1f8-1f1fd","isCanonical": true},":sx:":{"unicode":["1f1f8-1f1fd"],"fname":"1f1f8-1f1fd","uc":"1f1f8-1f1fd","isCanonical": false},":flag_sv:":{"unicode":["1f1f8-1f1fb"],"fname":"1f1f8-1f1fb","uc":"1f1f8-1f1fb","isCanonical": true},":sv:":{"unicode":["1f1f8-1f1fb"],"fname":"1f1f8-1f1fb","uc":"1f1f8-1f1fb","isCanonical": false},":flag_st:":{"unicode":["1f1f8-1f1f9"],"fname":"1f1f8-1f1f9","uc":"1f1f8-1f1f9","isCanonical": true},":st:":{"unicode":["1f1f8-1f1f9"],"fname":"1f1f8-1f1f9","uc":"1f1f8-1f1f9","isCanonical": false},":flag_ss:":{"unicode":["1f1f8-1f1f8"],"fname":"1f1f8-1f1f8","uc":"1f1f8-1f1f8","isCanonical": true},":ss:":{"unicode":["1f1f8-1f1f8"],"fname":"1f1f8-1f1f8","uc":"1f1f8-1f1f8","isCanonical": false},":flag_sr:":{"unicode":["1f1f8-1f1f7"],"fname":"1f1f8-1f1f7","uc":"1f1f8-1f1f7","isCanonical": true},":sr:":{"unicode":["1f1f8-1f1f7"],"fname":"1f1f8-1f1f7","uc":"1f1f8-1f1f7","isCanonical": false},":flag_so:":{"unicode":["1f1f8-1f1f4"],"fname":"1f1f8-1f1f4","uc":"1f1f8-1f1f4","isCanonical": true},":so:":{"unicode":["1f1f8-1f1f4"],"fname":"1f1f8-1f1f4","uc":"1f1f8-1f1f4","isCanonical": false},":flag_sn:":{"unicode":["1f1f8-1f1f3"],"fname":"1f1f8-1f1f3","uc":"1f1f8-1f1f3","isCanonical": true},":sn:":{"unicode":["1f1f8-1f1f3"],"fname":"1f1f8-1f1f3","uc":"1f1f8-1f1f3","isCanonical": false},":flag_sm:":{"unicode":["1f1f8-1f1f2"],"fname":"1f1f8-1f1f2","uc":"1f1f8-1f1f2","isCanonical": true},":sm:":{"unicode":["1f1f8-1f1f2"],"fname":"1f1f8-1f1f2","uc":"1f1f8-1f1f2","isCanonical": false},":flag_sl:":{"unicode":["1f1f8-1f1f1"],"fname":"1f1f8-1f1f1","uc":"1f1f8-1f1f1","isCanonical": true},":sl:":{"unicode":["1f1f8-1f1f1"],"fname":"1f1f8-1f1f1","uc":"1f1f8-1f1f1","isCanonical": false},":flag_sk:":{"unicode":["1f1f8-1f1f0"],"fname":"1f1f8-1f1f0","uc":"1f1f8-1f1f0","isCanonical": true},":sk:":{"unicode":["1f1f8-1f1f0"],"fname":"1f1f8-1f1f0","uc":"1f1f8-1f1f0","isCanonical": false},":flag_sj:":{"unicode":["1f1f8-1f1ef"],"fname":"1f1f8-1f1ef","uc":"1f1f8-1f1ef","isCanonical": true},":sj:":{"unicode":["1f1f8-1f1ef"],"fname":"1f1f8-1f1ef","uc":"1f1f8-1f1ef","isCanonical": false},":flag_si:":{"unicode":["1f1f8-1f1ee"],"fname":"1f1f8-1f1ee","uc":"1f1f8-1f1ee","isCanonical": true},":si:":{"unicode":["1f1f8-1f1ee"],"fname":"1f1f8-1f1ee","uc":"1f1f8-1f1ee","isCanonical": false},":flag_sh:":{"unicode":["1f1f8-1f1ed"],"fname":"1f1f8-1f1ed","uc":"1f1f8-1f1ed","isCanonical": true},":sh:":{"unicode":["1f1f8-1f1ed"],"fname":"1f1f8-1f1ed","uc":"1f1f8-1f1ed","isCanonical": false},":flag_sg:":{"unicode":["1f1f8-1f1ec"],"fname":"1f1f8-1f1ec","uc":"1f1f8-1f1ec","isCanonical": true},":sg:":{"unicode":["1f1f8-1f1ec"],"fname":"1f1f8-1f1ec","uc":"1f1f8-1f1ec","isCanonical": false},":flag_se:":{"unicode":["1f1f8-1f1ea"],"fname":"1f1f8-1f1ea","uc":"1f1f8-1f1ea","isCanonical": true},":se:":{"unicode":["1f1f8-1f1ea"],"fname":"1f1f8-1f1ea","uc":"1f1f8-1f1ea","isCanonical": false},":flag_sd:":{"unicode":["1f1f8-1f1e9"],"fname":"1f1f8-1f1e9","uc":"1f1f8-1f1e9","isCanonical": true},":sd:":{"unicode":["1f1f8-1f1e9"],"fname":"1f1f8-1f1e9","uc":"1f1f8-1f1e9","isCanonical": false},":flag_sc:":{"unicode":["1f1f8-1f1e8"],"fname":"1f1f8-1f1e8","uc":"1f1f8-1f1e8","isCanonical": true},":sc:":{"unicode":["1f1f8-1f1e8"],"fname":"1f1f8-1f1e8","uc":"1f1f8-1f1e8","isCanonical": false},":flag_sb:":{"unicode":["1f1f8-1f1e7"],"fname":"1f1f8-1f1e7","uc":"1f1f8-1f1e7","isCanonical": true},":sb:":{"unicode":["1f1f8-1f1e7"],"fname":"1f1f8-1f1e7","uc":"1f1f8-1f1e7","isCanonical": false},":flag_sa:":{"unicode":["1f1f8-1f1e6"],"fname":"1f1f8-1f1e6","uc":"1f1f8-1f1e6","isCanonical": true},":saudiarabia:":{"unicode":["1f1f8-1f1e6"],"fname":"1f1f8-1f1e6","uc":"1f1f8-1f1e6","isCanonical": false},":saudi:":{"unicode":["1f1f8-1f1e6"],"fname":"1f1f8-1f1e6","uc":"1f1f8-1f1e6","isCanonical": false},":flag_rw:":{"unicode":["1f1f7-1f1fc"],"fname":"1f1f7-1f1fc","uc":"1f1f7-1f1fc","isCanonical": true},":rw:":{"unicode":["1f1f7-1f1fc"],"fname":"1f1f7-1f1fc","uc":"1f1f7-1f1fc","isCanonical": false},":flag_ru:":{"unicode":["1f1f7-1f1fa"],"fname":"1f1f7-1f1fa","uc":"1f1f7-1f1fa","isCanonical": true},":ru:":{"unicode":["1f1f7-1f1fa"],"fname":"1f1f7-1f1fa","uc":"1f1f7-1f1fa","isCanonical": false},":flag_rs:":{"unicode":["1f1f7-1f1f8"],"fname":"1f1f7-1f1f8","uc":"1f1f7-1f1f8","isCanonical": true},":rs:":{"unicode":["1f1f7-1f1f8"],"fname":"1f1f7-1f1f8","uc":"1f1f7-1f1f8","isCanonical": false},":flag_ro:":{"unicode":["1f1f7-1f1f4"],"fname":"1f1f7-1f1f4","uc":"1f1f7-1f1f4","isCanonical": true},":ro:":{"unicode":["1f1f7-1f1f4"],"fname":"1f1f7-1f1f4","uc":"1f1f7-1f1f4","isCanonical": false},":flag_re:":{"unicode":["1f1f7-1f1ea"],"fname":"1f1f7-1f1ea","uc":"1f1f7-1f1ea","isCanonical": true},":re:":{"unicode":["1f1f7-1f1ea"],"fname":"1f1f7-1f1ea","uc":"1f1f7-1f1ea","isCanonical": false},":flag_qa:":{"unicode":["1f1f6-1f1e6"],"fname":"1f1f6-1f1e6","uc":"1f1f6-1f1e6","isCanonical": true},":qa:":{"unicode":["1f1f6-1f1e6"],"fname":"1f1f6-1f1e6","uc":"1f1f6-1f1e6","isCanonical": false},":flag_py:":{"unicode":["1f1f5-1f1fe"],"fname":"1f1f5-1f1fe","uc":"1f1f5-1f1fe","isCanonical": true},":py:":{"unicode":["1f1f5-1f1fe"],"fname":"1f1f5-1f1fe","uc":"1f1f5-1f1fe","isCanonical": false},":flag_pw:":{"unicode":["1f1f5-1f1fc"],"fname":"1f1f5-1f1fc","uc":"1f1f5-1f1fc","isCanonical": true},":pw:":{"unicode":["1f1f5-1f1fc"],"fname":"1f1f5-1f1fc","uc":"1f1f5-1f1fc","isCanonical": false},":flag_pt:":{"unicode":["1f1f5-1f1f9"],"fname":"1f1f5-1f1f9","uc":"1f1f5-1f1f9","isCanonical": true},":pt:":{"unicode":["1f1f5-1f1f9"],"fname":"1f1f5-1f1f9","uc":"1f1f5-1f1f9","isCanonical": false},":flag_ps:":{"unicode":["1f1f5-1f1f8"],"fname":"1f1f5-1f1f8","uc":"1f1f5-1f1f8","isCanonical": true},":ps:":{"unicode":["1f1f5-1f1f8"],"fname":"1f1f5-1f1f8","uc":"1f1f5-1f1f8","isCanonical": false},":flag_pr:":{"unicode":["1f1f5-1f1f7"],"fname":"1f1f5-1f1f7","uc":"1f1f5-1f1f7","isCanonical": true},":pr:":{"unicode":["1f1f5-1f1f7"],"fname":"1f1f5-1f1f7","uc":"1f1f5-1f1f7","isCanonical": false},":flag_pn:":{"unicode":["1f1f5-1f1f3"],"fname":"1f1f5-1f1f3","uc":"1f1f5-1f1f3","isCanonical": true},":pn:":{"unicode":["1f1f5-1f1f3"],"fname":"1f1f5-1f1f3","uc":"1f1f5-1f1f3","isCanonical": false},":flag_pm:":{"unicode":["1f1f5-1f1f2"],"fname":"1f1f5-1f1f2","uc":"1f1f5-1f1f2","isCanonical": true},":pm:":{"unicode":["1f1f5-1f1f2"],"fname":"1f1f5-1f1f2","uc":"1f1f5-1f1f2","isCanonical": false},":flag_pl:":{"unicode":["1f1f5-1f1f1"],"fname":"1f1f5-1f1f1","uc":"1f1f5-1f1f1","isCanonical": true},":pl:":{"unicode":["1f1f5-1f1f1"],"fname":"1f1f5-1f1f1","uc":"1f1f5-1f1f1","isCanonical": false},":flag_pk:":{"unicode":["1f1f5-1f1f0"],"fname":"1f1f5-1f1f0","uc":"1f1f5-1f1f0","isCanonical": true},":pk:":{"unicode":["1f1f5-1f1f0"],"fname":"1f1f5-1f1f0","uc":"1f1f5-1f1f0","isCanonical": false},":flag_ph:":{"unicode":["1f1f5-1f1ed"],"fname":"1f1f5-1f1ed","uc":"1f1f5-1f1ed","isCanonical": true},":ph:":{"unicode":["1f1f5-1f1ed"],"fname":"1f1f5-1f1ed","uc":"1f1f5-1f1ed","isCanonical": false},":flag_pg:":{"unicode":["1f1f5-1f1ec"],"fname":"1f1f5-1f1ec","uc":"1f1f5-1f1ec","isCanonical": true},":pg:":{"unicode":["1f1f5-1f1ec"],"fname":"1f1f5-1f1ec","uc":"1f1f5-1f1ec","isCanonical": false},":flag_pf:":{"unicode":["1f1f5-1f1eb"],"fname":"1f1f5-1f1eb","uc":"1f1f5-1f1eb","isCanonical": true},":pf:":{"unicode":["1f1f5-1f1eb"],"fname":"1f1f5-1f1eb","uc":"1f1f5-1f1eb","isCanonical": false},":flag_pe:":{"unicode":["1f1f5-1f1ea"],"fname":"1f1f5-1f1ea","uc":"1f1f5-1f1ea","isCanonical": true},":pe:":{"unicode":["1f1f5-1f1ea"],"fname":"1f1f5-1f1ea","uc":"1f1f5-1f1ea","isCanonical": false},":flag_pa:":{"unicode":["1f1f5-1f1e6"],"fname":"1f1f5-1f1e6","uc":"1f1f5-1f1e6","isCanonical": true},":pa:":{"unicode":["1f1f5-1f1e6"],"fname":"1f1f5-1f1e6","uc":"1f1f5-1f1e6","isCanonical": false},":flag_om:":{"unicode":["1f1f4-1f1f2"],"fname":"1f1f4-1f1f2","uc":"1f1f4-1f1f2","isCanonical": true},":om:":{"unicode":["1f1f4-1f1f2"],"fname":"1f1f4-1f1f2","uc":"1f1f4-1f1f2","isCanonical": false},":flag_nz:":{"unicode":["1f1f3-1f1ff"],"fname":"1f1f3-1f1ff","uc":"1f1f3-1f1ff","isCanonical": true},":nz:":{"unicode":["1f1f3-1f1ff"],"fname":"1f1f3-1f1ff","uc":"1f1f3-1f1ff","isCanonical": false},":flag_nu:":{"unicode":["1f1f3-1f1fa"],"fname":"1f1f3-1f1fa","uc":"1f1f3-1f1fa","isCanonical": true},":nu:":{"unicode":["1f1f3-1f1fa"],"fname":"1f1f3-1f1fa","uc":"1f1f3-1f1fa","isCanonical": false},":flag_nr:":{"unicode":["1f1f3-1f1f7"],"fname":"1f1f3-1f1f7","uc":"1f1f3-1f1f7","isCanonical": true},":nr:":{"unicode":["1f1f3-1f1f7"],"fname":"1f1f3-1f1f7","uc":"1f1f3-1f1f7","isCanonical": false},":flag_np:":{"unicode":["1f1f3-1f1f5"],"fname":"1f1f3-1f1f5","uc":"1f1f3-1f1f5","isCanonical": true},":np:":{"unicode":["1f1f3-1f1f5"],"fname":"1f1f3-1f1f5","uc":"1f1f3-1f1f5","isCanonical": false},":flag_no:":{"unicode":["1f1f3-1f1f4"],"fname":"1f1f3-1f1f4","uc":"1f1f3-1f1f4","isCanonical": true},":no:":{"unicode":["1f1f3-1f1f4"],"fname":"1f1f3-1f1f4","uc":"1f1f3-1f1f4","isCanonical": false},":flag_nl:":{"unicode":["1f1f3-1f1f1"],"fname":"1f1f3-1f1f1","uc":"1f1f3-1f1f1","isCanonical": true},":nl:":{"unicode":["1f1f3-1f1f1"],"fname":"1f1f3-1f1f1","uc":"1f1f3-1f1f1","isCanonical": false},":flag_ni:":{"unicode":["1f1f3-1f1ee"],"fname":"1f1f3-1f1ee","uc":"1f1f3-1f1ee","isCanonical": true},":ni:":{"unicode":["1f1f3-1f1ee"],"fname":"1f1f3-1f1ee","uc":"1f1f3-1f1ee","isCanonical": false},":flag_ng:":{"unicode":["1f1f3-1f1ec"],"fname":"1f1f3-1f1ec","uc":"1f1f3-1f1ec","isCanonical": true},":nigeria:":{"unicode":["1f1f3-1f1ec"],"fname":"1f1f3-1f1ec","uc":"1f1f3-1f1ec","isCanonical": false},":flag_nf:":{"unicode":["1f1f3-1f1eb"],"fname":"1f1f3-1f1eb","uc":"1f1f3-1f1eb","isCanonical": true},":nf:":{"unicode":["1f1f3-1f1eb"],"fname":"1f1f3-1f1eb","uc":"1f1f3-1f1eb","isCanonical": false},":flag_ne:":{"unicode":["1f1f3-1f1ea"],"fname":"1f1f3-1f1ea","uc":"1f1f3-1f1ea","isCanonical": true},":ne:":{"unicode":["1f1f3-1f1ea"],"fname":"1f1f3-1f1ea","uc":"1f1f3-1f1ea","isCanonical": false},":flag_nc:":{"unicode":["1f1f3-1f1e8"],"fname":"1f1f3-1f1e8","uc":"1f1f3-1f1e8","isCanonical": true},":nc:":{"unicode":["1f1f3-1f1e8"],"fname":"1f1f3-1f1e8","uc":"1f1f3-1f1e8","isCanonical": false},":flag_na:":{"unicode":["1f1f3-1f1e6"],"fname":"1f1f3-1f1e6","uc":"1f1f3-1f1e6","isCanonical": true},":na:":{"unicode":["1f1f3-1f1e6"],"fname":"1f1f3-1f1e6","uc":"1f1f3-1f1e6","isCanonical": false},":flag_mz:":{"unicode":["1f1f2-1f1ff"],"fname":"1f1f2-1f1ff","uc":"1f1f2-1f1ff","isCanonical": true},":mz:":{"unicode":["1f1f2-1f1ff"],"fname":"1f1f2-1f1ff","uc":"1f1f2-1f1ff","isCanonical": false},":flag_my:":{"unicode":["1f1f2-1f1fe"],"fname":"1f1f2-1f1fe","uc":"1f1f2-1f1fe","isCanonical": true},":my:":{"unicode":["1f1f2-1f1fe"],"fname":"1f1f2-1f1fe","uc":"1f1f2-1f1fe","isCanonical": false},":flag_mx:":{"unicode":["1f1f2-1f1fd"],"fname":"1f1f2-1f1fd","uc":"1f1f2-1f1fd","isCanonical": true},":mx:":{"unicode":["1f1f2-1f1fd"],"fname":"1f1f2-1f1fd","uc":"1f1f2-1f1fd","isCanonical": false},":flag_mw:":{"unicode":["1f1f2-1f1fc"],"fname":"1f1f2-1f1fc","uc":"1f1f2-1f1fc","isCanonical": true},":mw:":{"unicode":["1f1f2-1f1fc"],"fname":"1f1f2-1f1fc","uc":"1f1f2-1f1fc","isCanonical": false},":flag_mv:":{"unicode":["1f1f2-1f1fb"],"fname":"1f1f2-1f1fb","uc":"1f1f2-1f1fb","isCanonical": true},":mv:":{"unicode":["1f1f2-1f1fb"],"fname":"1f1f2-1f1fb","uc":"1f1f2-1f1fb","isCanonical": false},":flag_mu:":{"unicode":["1f1f2-1f1fa"],"fname":"1f1f2-1f1fa","uc":"1f1f2-1f1fa","isCanonical": true},":mu:":{"unicode":["1f1f2-1f1fa"],"fname":"1f1f2-1f1fa","uc":"1f1f2-1f1fa","isCanonical": false},":flag_mt:":{"unicode":["1f1f2-1f1f9"],"fname":"1f1f2-1f1f9","uc":"1f1f2-1f1f9","isCanonical": true},":mt:":{"unicode":["1f1f2-1f1f9"],"fname":"1f1f2-1f1f9","uc":"1f1f2-1f1f9","isCanonical": false},":flag_ms:":{"unicode":["1f1f2-1f1f8"],"fname":"1f1f2-1f1f8","uc":"1f1f2-1f1f8","isCanonical": true},":ms:":{"unicode":["1f1f2-1f1f8"],"fname":"1f1f2-1f1f8","uc":"1f1f2-1f1f8","isCanonical": false},":flag_mr:":{"unicode":["1f1f2-1f1f7"],"fname":"1f1f2-1f1f7","uc":"1f1f2-1f1f7","isCanonical": true},":mr:":{"unicode":["1f1f2-1f1f7"],"fname":"1f1f2-1f1f7","uc":"1f1f2-1f1f7","isCanonical": false},":flag_mq:":{"unicode":["1f1f2-1f1f6"],"fname":"1f1f2-1f1f6","uc":"1f1f2-1f1f6","isCanonical": true},":mq:":{"unicode":["1f1f2-1f1f6"],"fname":"1f1f2-1f1f6","uc":"1f1f2-1f1f6","isCanonical": false},":flag_mp:":{"unicode":["1f1f2-1f1f5"],"fname":"1f1f2-1f1f5","uc":"1f1f2-1f1f5","isCanonical": true},":mp:":{"unicode":["1f1f2-1f1f5"],"fname":"1f1f2-1f1f5","uc":"1f1f2-1f1f5","isCanonical": false},":flag_mo:":{"unicode":["1f1f2-1f1f4"],"fname":"1f1f2-1f1f4","uc":"1f1f2-1f1f4","isCanonical": true},":mo:":{"unicode":["1f1f2-1f1f4"],"fname":"1f1f2-1f1f4","uc":"1f1f2-1f1f4","isCanonical": false},":flag_mn:":{"unicode":["1f1f2-1f1f3"],"fname":"1f1f2-1f1f3","uc":"1f1f2-1f1f3","isCanonical": true},":mn:":{"unicode":["1f1f2-1f1f3"],"fname":"1f1f2-1f1f3","uc":"1f1f2-1f1f3","isCanonical": false},":flag_mm:":{"unicode":["1f1f2-1f1f2"],"fname":"1f1f2-1f1f2","uc":"1f1f2-1f1f2","isCanonical": true},":mm:":{"unicode":["1f1f2-1f1f2"],"fname":"1f1f2-1f1f2","uc":"1f1f2-1f1f2","isCanonical": false},":flag_ml:":{"unicode":["1f1f2-1f1f1"],"fname":"1f1f2-1f1f1","uc":"1f1f2-1f1f1","isCanonical": true},":ml:":{"unicode":["1f1f2-1f1f1"],"fname":"1f1f2-1f1f1","uc":"1f1f2-1f1f1","isCanonical": false},":flag_mk:":{"unicode":["1f1f2-1f1f0"],"fname":"1f1f2-1f1f0","uc":"1f1f2-1f1f0","isCanonical": true},":mk:":{"unicode":["1f1f2-1f1f0"],"fname":"1f1f2-1f1f0","uc":"1f1f2-1f1f0","isCanonical": false},":flag_mh:":{"unicode":["1f1f2-1f1ed"],"fname":"1f1f2-1f1ed","uc":"1f1f2-1f1ed","isCanonical": true},":mh:":{"unicode":["1f1f2-1f1ed"],"fname":"1f1f2-1f1ed","uc":"1f1f2-1f1ed","isCanonical": false},":flag_mg:":{"unicode":["1f1f2-1f1ec"],"fname":"1f1f2-1f1ec","uc":"1f1f2-1f1ec","isCanonical": true},":mg:":{"unicode":["1f1f2-1f1ec"],"fname":"1f1f2-1f1ec","uc":"1f1f2-1f1ec","isCanonical": false},":flag_mf:":{"unicode":["1f1f2-1f1eb"],"fname":"1f1f2-1f1eb","uc":"1f1f2-1f1eb","isCanonical": true},":mf:":{"unicode":["1f1f2-1f1eb"],"fname":"1f1f2-1f1eb","uc":"1f1f2-1f1eb","isCanonical": false},":flag_me:":{"unicode":["1f1f2-1f1ea"],"fname":"1f1f2-1f1ea","uc":"1f1f2-1f1ea","isCanonical": true},":me:":{"unicode":["1f1f2-1f1ea"],"fname":"1f1f2-1f1ea","uc":"1f1f2-1f1ea","isCanonical": false},":flag_md:":{"unicode":["1f1f2-1f1e9"],"fname":"1f1f2-1f1e9","uc":"1f1f2-1f1e9","isCanonical": true},":md:":{"unicode":["1f1f2-1f1e9"],"fname":"1f1f2-1f1e9","uc":"1f1f2-1f1e9","isCanonical": false},":flag_mc:":{"unicode":["1f1f2-1f1e8"],"fname":"1f1f2-1f1e8","uc":"1f1f2-1f1e8","isCanonical": true},":mc:":{"unicode":["1f1f2-1f1e8"],"fname":"1f1f2-1f1e8","uc":"1f1f2-1f1e8","isCanonical": false},":flag_ma:":{"unicode":["1f1f2-1f1e6"],"fname":"1f1f2-1f1e6","uc":"1f1f2-1f1e6","isCanonical": true},":ma:":{"unicode":["1f1f2-1f1e6"],"fname":"1f1f2-1f1e6","uc":"1f1f2-1f1e6","isCanonical": false},":flag_ly:":{"unicode":["1f1f1-1f1fe"],"fname":"1f1f1-1f1fe","uc":"1f1f1-1f1fe","isCanonical": true},":ly:":{"unicode":["1f1f1-1f1fe"],"fname":"1f1f1-1f1fe","uc":"1f1f1-1f1fe","isCanonical": false},":flag_lv:":{"unicode":["1f1f1-1f1fb"],"fname":"1f1f1-1f1fb","uc":"1f1f1-1f1fb","isCanonical": true},":lv:":{"unicode":["1f1f1-1f1fb"],"fname":"1f1f1-1f1fb","uc":"1f1f1-1f1fb","isCanonical": false},":flag_lu:":{"unicode":["1f1f1-1f1fa"],"fname":"1f1f1-1f1fa","uc":"1f1f1-1f1fa","isCanonical": true},":lu:":{"unicode":["1f1f1-1f1fa"],"fname":"1f1f1-1f1fa","uc":"1f1f1-1f1fa","isCanonical": false},":flag_lt:":{"unicode":["1f1f1-1f1f9"],"fname":"1f1f1-1f1f9","uc":"1f1f1-1f1f9","isCanonical": true},":lt:":{"unicode":["1f1f1-1f1f9"],"fname":"1f1f1-1f1f9","uc":"1f1f1-1f1f9","isCanonical": false},":flag_ls:":{"unicode":["1f1f1-1f1f8"],"fname":"1f1f1-1f1f8","uc":"1f1f1-1f1f8","isCanonical": true},":ls:":{"unicode":["1f1f1-1f1f8"],"fname":"1f1f1-1f1f8","uc":"1f1f1-1f1f8","isCanonical": false},":flag_lr:":{"unicode":["1f1f1-1f1f7"],"fname":"1f1f1-1f1f7","uc":"1f1f1-1f1f7","isCanonical": true},":lr:":{"unicode":["1f1f1-1f1f7"],"fname":"1f1f1-1f1f7","uc":"1f1f1-1f1f7","isCanonical": false},":flag_lk:":{"unicode":["1f1f1-1f1f0"],"fname":"1f1f1-1f1f0","uc":"1f1f1-1f1f0","isCanonical": true},":lk:":{"unicode":["1f1f1-1f1f0"],"fname":"1f1f1-1f1f0","uc":"1f1f1-1f1f0","isCanonical": false},":flag_li:":{"unicode":["1f1f1-1f1ee"],"fname":"1f1f1-1f1ee","uc":"1f1f1-1f1ee","isCanonical": true},":li:":{"unicode":["1f1f1-1f1ee"],"fname":"1f1f1-1f1ee","uc":"1f1f1-1f1ee","isCanonical": false},":flag_lc:":{"unicode":["1f1f1-1f1e8"],"fname":"1f1f1-1f1e8","uc":"1f1f1-1f1e8","isCanonical": true},":lc:":{"unicode":["1f1f1-1f1e8"],"fname":"1f1f1-1f1e8","uc":"1f1f1-1f1e8","isCanonical": false},":flag_lb:":{"unicode":["1f1f1-1f1e7"],"fname":"1f1f1-1f1e7","uc":"1f1f1-1f1e7","isCanonical": true},":lb:":{"unicode":["1f1f1-1f1e7"],"fname":"1f1f1-1f1e7","uc":"1f1f1-1f1e7","isCanonical": false},":flag_la:":{"unicode":["1f1f1-1f1e6"],"fname":"1f1f1-1f1e6","uc":"1f1f1-1f1e6","isCanonical": true},":la:":{"unicode":["1f1f1-1f1e6"],"fname":"1f1f1-1f1e6","uc":"1f1f1-1f1e6","isCanonical": false},":flag_kz:":{"unicode":["1f1f0-1f1ff"],"fname":"1f1f0-1f1ff","uc":"1f1f0-1f1ff","isCanonical": true},":kz:":{"unicode":["1f1f0-1f1ff"],"fname":"1f1f0-1f1ff","uc":"1f1f0-1f1ff","isCanonical": false},":flag_ky:":{"unicode":["1f1f0-1f1fe"],"fname":"1f1f0-1f1fe","uc":"1f1f0-1f1fe","isCanonical": true},":ky:":{"unicode":["1f1f0-1f1fe"],"fname":"1f1f0-1f1fe","uc":"1f1f0-1f1fe","isCanonical": false},":flag_kw:":{"unicode":["1f1f0-1f1fc"],"fname":"1f1f0-1f1fc","uc":"1f1f0-1f1fc","isCanonical": true},":kw:":{"unicode":["1f1f0-1f1fc"],"fname":"1f1f0-1f1fc","uc":"1f1f0-1f1fc","isCanonical": false},":flag_kr:":{"unicode":["1f1f0-1f1f7"],"fname":"1f1f0-1f1f7","uc":"1f1f0-1f1f7","isCanonical": true},":kr:":{"unicode":["1f1f0-1f1f7"],"fname":"1f1f0-1f1f7","uc":"1f1f0-1f1f7","isCanonical": false},":flag_kp:":{"unicode":["1f1f0-1f1f5"],"fname":"1f1f0-1f1f5","uc":"1f1f0-1f1f5","isCanonical": true},":kp:":{"unicode":["1f1f0-1f1f5"],"fname":"1f1f0-1f1f5","uc":"1f1f0-1f1f5","isCanonical": false},":flag_kn:":{"unicode":["1f1f0-1f1f3"],"fname":"1f1f0-1f1f3","uc":"1f1f0-1f1f3","isCanonical": true},":kn:":{"unicode":["1f1f0-1f1f3"],"fname":"1f1f0-1f1f3","uc":"1f1f0-1f1f3","isCanonical": false},":flag_km:":{"unicode":["1f1f0-1f1f2"],"fname":"1f1f0-1f1f2","uc":"1f1f0-1f1f2","isCanonical": true},":km:":{"unicode":["1f1f0-1f1f2"],"fname":"1f1f0-1f1f2","uc":"1f1f0-1f1f2","isCanonical": false},":flag_ki:":{"unicode":["1f1f0-1f1ee"],"fname":"1f1f0-1f1ee","uc":"1f1f0-1f1ee","isCanonical": true},":ki:":{"unicode":["1f1f0-1f1ee"],"fname":"1f1f0-1f1ee","uc":"1f1f0-1f1ee","isCanonical": false},":flag_kh:":{"unicode":["1f1f0-1f1ed"],"fname":"1f1f0-1f1ed","uc":"1f1f0-1f1ed","isCanonical": true},":kh:":{"unicode":["1f1f0-1f1ed"],"fname":"1f1f0-1f1ed","uc":"1f1f0-1f1ed","isCanonical": false},":flag_kg:":{"unicode":["1f1f0-1f1ec"],"fname":"1f1f0-1f1ec","uc":"1f1f0-1f1ec","isCanonical": true},":kg:":{"unicode":["1f1f0-1f1ec"],"fname":"1f1f0-1f1ec","uc":"1f1f0-1f1ec","isCanonical": false},":flag_ke:":{"unicode":["1f1f0-1f1ea"],"fname":"1f1f0-1f1ea","uc":"1f1f0-1f1ea","isCanonical": true},":ke:":{"unicode":["1f1f0-1f1ea"],"fname":"1f1f0-1f1ea","uc":"1f1f0-1f1ea","isCanonical": false},":flag_jp:":{"unicode":["1f1ef-1f1f5"],"fname":"1f1ef-1f1f5","uc":"1f1ef-1f1f5","isCanonical": true},":jp:":{"unicode":["1f1ef-1f1f5"],"fname":"1f1ef-1f1f5","uc":"1f1ef-1f1f5","isCanonical": false},":flag_jo:":{"unicode":["1f1ef-1f1f4"],"fname":"1f1ef-1f1f4","uc":"1f1ef-1f1f4","isCanonical": true},":jo:":{"unicode":["1f1ef-1f1f4"],"fname":"1f1ef-1f1f4","uc":"1f1ef-1f1f4","isCanonical": false},":flag_jm:":{"unicode":["1f1ef-1f1f2"],"fname":"1f1ef-1f1f2","uc":"1f1ef-1f1f2","isCanonical": true},":jm:":{"unicode":["1f1ef-1f1f2"],"fname":"1f1ef-1f1f2","uc":"1f1ef-1f1f2","isCanonical": false},":flag_je:":{"unicode":["1f1ef-1f1ea"],"fname":"1f1ef-1f1ea","uc":"1f1ef-1f1ea","isCanonical": true},":je:":{"unicode":["1f1ef-1f1ea"],"fname":"1f1ef-1f1ea","uc":"1f1ef-1f1ea","isCanonical": false},":flag_it:":{"unicode":["1f1ee-1f1f9"],"fname":"1f1ee-1f1f9","uc":"1f1ee-1f1f9","isCanonical": true},":it:":{"unicode":["1f1ee-1f1f9"],"fname":"1f1ee-1f1f9","uc":"1f1ee-1f1f9","isCanonical": false},":flag_is:":{"unicode":["1f1ee-1f1f8"],"fname":"1f1ee-1f1f8","uc":"1f1ee-1f1f8","isCanonical": true},":is:":{"unicode":["1f1ee-1f1f8"],"fname":"1f1ee-1f1f8","uc":"1f1ee-1f1f8","isCanonical": false},":flag_ir:":{"unicode":["1f1ee-1f1f7"],"fname":"1f1ee-1f1f7","uc":"1f1ee-1f1f7","isCanonical": true},":ir:":{"unicode":["1f1ee-1f1f7"],"fname":"1f1ee-1f1f7","uc":"1f1ee-1f1f7","isCanonical": false},":flag_iq:":{"unicode":["1f1ee-1f1f6"],"fname":"1f1ee-1f1f6","uc":"1f1ee-1f1f6","isCanonical": true},":iq:":{"unicode":["1f1ee-1f1f6"],"fname":"1f1ee-1f1f6","uc":"1f1ee-1f1f6","isCanonical": false},":flag_io:":{"unicode":["1f1ee-1f1f4"],"fname":"1f1ee-1f1f4","uc":"1f1ee-1f1f4","isCanonical": true},":io:":{"unicode":["1f1ee-1f1f4"],"fname":"1f1ee-1f1f4","uc":"1f1ee-1f1f4","isCanonical": false},":flag_in:":{"unicode":["1f1ee-1f1f3"],"fname":"1f1ee-1f1f3","uc":"1f1ee-1f1f3","isCanonical": true},":in:":{"unicode":["1f1ee-1f1f3"],"fname":"1f1ee-1f1f3","uc":"1f1ee-1f1f3","isCanonical": false},":flag_im:":{"unicode":["1f1ee-1f1f2"],"fname":"1f1ee-1f1f2","uc":"1f1ee-1f1f2","isCanonical": true},":im:":{"unicode":["1f1ee-1f1f2"],"fname":"1f1ee-1f1f2","uc":"1f1ee-1f1f2","isCanonical": false},":flag_il:":{"unicode":["1f1ee-1f1f1"],"fname":"1f1ee-1f1f1","uc":"1f1ee-1f1f1","isCanonical": true},":il:":{"unicode":["1f1ee-1f1f1"],"fname":"1f1ee-1f1f1","uc":"1f1ee-1f1f1","isCanonical": false},":flag_ie:":{"unicode":["1f1ee-1f1ea"],"fname":"1f1ee-1f1ea","uc":"1f1ee-1f1ea","isCanonical": true},":ie:":{"unicode":["1f1ee-1f1ea"],"fname":"1f1ee-1f1ea","uc":"1f1ee-1f1ea","isCanonical": false},":flag_id:":{"unicode":["1f1ee-1f1e9"],"fname":"1f1ee-1f1e9","uc":"1f1ee-1f1e9","isCanonical": true},":indonesia:":{"unicode":["1f1ee-1f1e9"],"fname":"1f1ee-1f1e9","uc":"1f1ee-1f1e9","isCanonical": false},":flag_ic:":{"unicode":["1f1ee-1f1e8"],"fname":"1f1ee-1f1e8","uc":"1f1ee-1f1e8","isCanonical": true},":ic:":{"unicode":["1f1ee-1f1e8"],"fname":"1f1ee-1f1e8","uc":"1f1ee-1f1e8","isCanonical": false},":flag_hu:":{"unicode":["1f1ed-1f1fa"],"fname":"1f1ed-1f1fa","uc":"1f1ed-1f1fa","isCanonical": true},":hu:":{"unicode":["1f1ed-1f1fa"],"fname":"1f1ed-1f1fa","uc":"1f1ed-1f1fa","isCanonical": false},":flag_ht:":{"unicode":["1f1ed-1f1f9"],"fname":"1f1ed-1f1f9","uc":"1f1ed-1f1f9","isCanonical": true},":ht:":{"unicode":["1f1ed-1f1f9"],"fname":"1f1ed-1f1f9","uc":"1f1ed-1f1f9","isCanonical": false},":flag_hr:":{"unicode":["1f1ed-1f1f7"],"fname":"1f1ed-1f1f7","uc":"1f1ed-1f1f7","isCanonical": true},":hr:":{"unicode":["1f1ed-1f1f7"],"fname":"1f1ed-1f1f7","uc":"1f1ed-1f1f7","isCanonical": false},":flag_hn:":{"unicode":["1f1ed-1f1f3"],"fname":"1f1ed-1f1f3","uc":"1f1ed-1f1f3","isCanonical": true},":hn:":{"unicode":["1f1ed-1f1f3"],"fname":"1f1ed-1f1f3","uc":"1f1ed-1f1f3","isCanonical": false},":flag_hm:":{"unicode":["1f1ed-1f1f2"],"fname":"1f1ed-1f1f2","uc":"1f1ed-1f1f2","isCanonical": true},":hm:":{"unicode":["1f1ed-1f1f2"],"fname":"1f1ed-1f1f2","uc":"1f1ed-1f1f2","isCanonical": false},":flag_hk:":{"unicode":["1f1ed-1f1f0"],"fname":"1f1ed-1f1f0","uc":"1f1ed-1f1f0","isCanonical": true},":hk:":{"unicode":["1f1ed-1f1f0"],"fname":"1f1ed-1f1f0","uc":"1f1ed-1f1f0","isCanonical": false},":flag_gy:":{"unicode":["1f1ec-1f1fe"],"fname":"1f1ec-1f1fe","uc":"1f1ec-1f1fe","isCanonical": true},":gy:":{"unicode":["1f1ec-1f1fe"],"fname":"1f1ec-1f1fe","uc":"1f1ec-1f1fe","isCanonical": false},":flag_gw:":{"unicode":["1f1ec-1f1fc"],"fname":"1f1ec-1f1fc","uc":"1f1ec-1f1fc","isCanonical": true},":gw:":{"unicode":["1f1ec-1f1fc"],"fname":"1f1ec-1f1fc","uc":"1f1ec-1f1fc","isCanonical": false},":flag_gu:":{"unicode":["1f1ec-1f1fa"],"fname":"1f1ec-1f1fa","uc":"1f1ec-1f1fa","isCanonical": true},":gu:":{"unicode":["1f1ec-1f1fa"],"fname":"1f1ec-1f1fa","uc":"1f1ec-1f1fa","isCanonical": false},":flag_gt:":{"unicode":["1f1ec-1f1f9"],"fname":"1f1ec-1f1f9","uc":"1f1ec-1f1f9","isCanonical": true},":gt:":{"unicode":["1f1ec-1f1f9"],"fname":"1f1ec-1f1f9","uc":"1f1ec-1f1f9","isCanonical": false},":flag_gs:":{"unicode":["1f1ec-1f1f8"],"fname":"1f1ec-1f1f8","uc":"1f1ec-1f1f8","isCanonical": true},":gs:":{"unicode":["1f1ec-1f1f8"],"fname":"1f1ec-1f1f8","uc":"1f1ec-1f1f8","isCanonical": false},":flag_gr:":{"unicode":["1f1ec-1f1f7"],"fname":"1f1ec-1f1f7","uc":"1f1ec-1f1f7","isCanonical": true},":gr:":{"unicode":["1f1ec-1f1f7"],"fname":"1f1ec-1f1f7","uc":"1f1ec-1f1f7","isCanonical": false},":flag_gq:":{"unicode":["1f1ec-1f1f6"],"fname":"1f1ec-1f1f6","uc":"1f1ec-1f1f6","isCanonical": true},":gq:":{"unicode":["1f1ec-1f1f6"],"fname":"1f1ec-1f1f6","uc":"1f1ec-1f1f6","isCanonical": false},":flag_gp:":{"unicode":["1f1ec-1f1f5"],"fname":"1f1ec-1f1f5","uc":"1f1ec-1f1f5","isCanonical": true},":gp:":{"unicode":["1f1ec-1f1f5"],"fname":"1f1ec-1f1f5","uc":"1f1ec-1f1f5","isCanonical": false},":flag_gn:":{"unicode":["1f1ec-1f1f3"],"fname":"1f1ec-1f1f3","uc":"1f1ec-1f1f3","isCanonical": true},":gn:":{"unicode":["1f1ec-1f1f3"],"fname":"1f1ec-1f1f3","uc":"1f1ec-1f1f3","isCanonical": false},":flag_gm:":{"unicode":["1f1ec-1f1f2"],"fname":"1f1ec-1f1f2","uc":"1f1ec-1f1f2","isCanonical": true},":gm:":{"unicode":["1f1ec-1f1f2"],"fname":"1f1ec-1f1f2","uc":"1f1ec-1f1f2","isCanonical": false},":flag_gl:":{"unicode":["1f1ec-1f1f1"],"fname":"1f1ec-1f1f1","uc":"1f1ec-1f1f1","isCanonical": true},":gl:":{"unicode":["1f1ec-1f1f1"],"fname":"1f1ec-1f1f1","uc":"1f1ec-1f1f1","isCanonical": false},":flag_gi:":{"unicode":["1f1ec-1f1ee"],"fname":"1f1ec-1f1ee","uc":"1f1ec-1f1ee","isCanonical": true},":gi:":{"unicode":["1f1ec-1f1ee"],"fname":"1f1ec-1f1ee","uc":"1f1ec-1f1ee","isCanonical": false},":flag_gh:":{"unicode":["1f1ec-1f1ed"],"fname":"1f1ec-1f1ed","uc":"1f1ec-1f1ed","isCanonical": true},":gh:":{"unicode":["1f1ec-1f1ed"],"fname":"1f1ec-1f1ed","uc":"1f1ec-1f1ed","isCanonical": false},":flag_gg:":{"unicode":["1f1ec-1f1ec"],"fname":"1f1ec-1f1ec","uc":"1f1ec-1f1ec","isCanonical": true},":gg:":{"unicode":["1f1ec-1f1ec"],"fname":"1f1ec-1f1ec","uc":"1f1ec-1f1ec","isCanonical": false},":flag_gf:":{"unicode":["1f1ec-1f1eb"],"fname":"1f1ec-1f1eb","uc":"1f1ec-1f1eb","isCanonical": true},":gf:":{"unicode":["1f1ec-1f1eb"],"fname":"1f1ec-1f1eb","uc":"1f1ec-1f1eb","isCanonical": false},":flag_ge:":{"unicode":["1f1ec-1f1ea"],"fname":"1f1ec-1f1ea","uc":"1f1ec-1f1ea","isCanonical": true},":ge:":{"unicode":["1f1ec-1f1ea"],"fname":"1f1ec-1f1ea","uc":"1f1ec-1f1ea","isCanonical": false},":flag_gd:":{"unicode":["1f1ec-1f1e9"],"fname":"1f1ec-1f1e9","uc":"1f1ec-1f1e9","isCanonical": true},":gd:":{"unicode":["1f1ec-1f1e9"],"fname":"1f1ec-1f1e9","uc":"1f1ec-1f1e9","isCanonical": false},":flag_gb:":{"unicode":["1f1ec-1f1e7"],"fname":"1f1ec-1f1e7","uc":"1f1ec-1f1e7","isCanonical": true},":gb:":{"unicode":["1f1ec-1f1e7"],"fname":"1f1ec-1f1e7","uc":"1f1ec-1f1e7","isCanonical": false},":flag_ga:":{"unicode":["1f1ec-1f1e6"],"fname":"1f1ec-1f1e6","uc":"1f1ec-1f1e6","isCanonical": true},":ga:":{"unicode":["1f1ec-1f1e6"],"fname":"1f1ec-1f1e6","uc":"1f1ec-1f1e6","isCanonical": false},":flag_fr:":{"unicode":["1f1eb-1f1f7"],"fname":"1f1eb-1f1f7","uc":"1f1eb-1f1f7","isCanonical": true},":fr:":{"unicode":["1f1eb-1f1f7"],"fname":"1f1eb-1f1f7","uc":"1f1eb-1f1f7","isCanonical": false},":flag_fo:":{"unicode":["1f1eb-1f1f4"],"fname":"1f1eb-1f1f4","uc":"1f1eb-1f1f4","isCanonical": true},":fo:":{"unicode":["1f1eb-1f1f4"],"fname":"1f1eb-1f1f4","uc":"1f1eb-1f1f4","isCanonical": false},":flag_fm:":{"unicode":["1f1eb-1f1f2"],"fname":"1f1eb-1f1f2","uc":"1f1eb-1f1f2","isCanonical": true},":fm:":{"unicode":["1f1eb-1f1f2"],"fname":"1f1eb-1f1f2","uc":"1f1eb-1f1f2","isCanonical": false},":flag_fk:":{"unicode":["1f1eb-1f1f0"],"fname":"1f1eb-1f1f0","uc":"1f1eb-1f1f0","isCanonical": true},":fk:":{"unicode":["1f1eb-1f1f0"],"fname":"1f1eb-1f1f0","uc":"1f1eb-1f1f0","isCanonical": false},":flag_fj:":{"unicode":["1f1eb-1f1ef"],"fname":"1f1eb-1f1ef","uc":"1f1eb-1f1ef","isCanonical": true},":fj:":{"unicode":["1f1eb-1f1ef"],"fname":"1f1eb-1f1ef","uc":"1f1eb-1f1ef","isCanonical": false},":flag_fi:":{"unicode":["1f1eb-1f1ee"],"fname":"1f1eb-1f1ee","uc":"1f1eb-1f1ee","isCanonical": true},":fi:":{"unicode":["1f1eb-1f1ee"],"fname":"1f1eb-1f1ee","uc":"1f1eb-1f1ee","isCanonical": false},":flag_eu:":{"unicode":["1f1ea-1f1fa"],"fname":"1f1ea-1f1fa","uc":"1f1ea-1f1fa","isCanonical": true},":eu:":{"unicode":["1f1ea-1f1fa"],"fname":"1f1ea-1f1fa","uc":"1f1ea-1f1fa","isCanonical": false},":flag_et:":{"unicode":["1f1ea-1f1f9"],"fname":"1f1ea-1f1f9","uc":"1f1ea-1f1f9","isCanonical": true},":et:":{"unicode":["1f1ea-1f1f9"],"fname":"1f1ea-1f1f9","uc":"1f1ea-1f1f9","isCanonical": false},":flag_es:":{"unicode":["1f1ea-1f1f8"],"fname":"1f1ea-1f1f8","uc":"1f1ea-1f1f8","isCanonical": true},":es:":{"unicode":["1f1ea-1f1f8"],"fname":"1f1ea-1f1f8","uc":"1f1ea-1f1f8","isCanonical": false},":flag_er:":{"unicode":["1f1ea-1f1f7"],"fname":"1f1ea-1f1f7","uc":"1f1ea-1f1f7","isCanonical": true},":er:":{"unicode":["1f1ea-1f1f7"],"fname":"1f1ea-1f1f7","uc":"1f1ea-1f1f7","isCanonical": false},":flag_eh:":{"unicode":["1f1ea-1f1ed"],"fname":"1f1ea-1f1ed","uc":"1f1ea-1f1ed","isCanonical": true},":eh:":{"unicode":["1f1ea-1f1ed"],"fname":"1f1ea-1f1ed","uc":"1f1ea-1f1ed","isCanonical": false},":flag_eg:":{"unicode":["1f1ea-1f1ec"],"fname":"1f1ea-1f1ec","uc":"1f1ea-1f1ec","isCanonical": true},":eg:":{"unicode":["1f1ea-1f1ec"],"fname":"1f1ea-1f1ec","uc":"1f1ea-1f1ec","isCanonical": false},":flag_ee:":{"unicode":["1f1ea-1f1ea"],"fname":"1f1ea-1f1ea","uc":"1f1ea-1f1ea","isCanonical": true},":ee:":{"unicode":["1f1ea-1f1ea"],"fname":"1f1ea-1f1ea","uc":"1f1ea-1f1ea","isCanonical": false},":flag_ec:":{"unicode":["1f1ea-1f1e8"],"fname":"1f1ea-1f1e8","uc":"1f1ea-1f1e8","isCanonical": true},":ec:":{"unicode":["1f1ea-1f1e8"],"fname":"1f1ea-1f1e8","uc":"1f1ea-1f1e8","isCanonical": false},":flag_ea:":{"unicode":["1f1ea-1f1e6"],"fname":"1f1ea-1f1e6","uc":"1f1ea-1f1e6","isCanonical": true},":ea:":{"unicode":["1f1ea-1f1e6"],"fname":"1f1ea-1f1e6","uc":"1f1ea-1f1e6","isCanonical": false},":flag_dz:":{"unicode":["1f1e9-1f1ff"],"fname":"1f1e9-1f1ff","uc":"1f1e9-1f1ff","isCanonical": true},":dz:":{"unicode":["1f1e9-1f1ff"],"fname":"1f1e9-1f1ff","uc":"1f1e9-1f1ff","isCanonical": false},":flag_do:":{"unicode":["1f1e9-1f1f4"],"fname":"1f1e9-1f1f4","uc":"1f1e9-1f1f4","isCanonical": true},":do:":{"unicode":["1f1e9-1f1f4"],"fname":"1f1e9-1f1f4","uc":"1f1e9-1f1f4","isCanonical": false},":flag_dm:":{"unicode":["1f1e9-1f1f2"],"fname":"1f1e9-1f1f2","uc":"1f1e9-1f1f2","isCanonical": true},":dm:":{"unicode":["1f1e9-1f1f2"],"fname":"1f1e9-1f1f2","uc":"1f1e9-1f1f2","isCanonical": false},":flag_dk:":{"unicode":["1f1e9-1f1f0"],"fname":"1f1e9-1f1f0","uc":"1f1e9-1f1f0","isCanonical": true},":dk:":{"unicode":["1f1e9-1f1f0"],"fname":"1f1e9-1f1f0","uc":"1f1e9-1f1f0","isCanonical": false},":flag_dj:":{"unicode":["1f1e9-1f1ef"],"fname":"1f1e9-1f1ef","uc":"1f1e9-1f1ef","isCanonical": true},":dj:":{"unicode":["1f1e9-1f1ef"],"fname":"1f1e9-1f1ef","uc":"1f1e9-1f1ef","isCanonical": false},":flag_dg:":{"unicode":["1f1e9-1f1ec"],"fname":"1f1e9-1f1ec","uc":"1f1e9-1f1ec","isCanonical": true},":dg:":{"unicode":["1f1e9-1f1ec"],"fname":"1f1e9-1f1ec","uc":"1f1e9-1f1ec","isCanonical": false},":flag_de:":{"unicode":["1f1e9-1f1ea"],"fname":"1f1e9-1f1ea","uc":"1f1e9-1f1ea","isCanonical": true},":de:":{"unicode":["1f1e9-1f1ea"],"fname":"1f1e9-1f1ea","uc":"1f1e9-1f1ea","isCanonical": false},":flag_cz:":{"unicode":["1f1e8-1f1ff"],"fname":"1f1e8-1f1ff","uc":"1f1e8-1f1ff","isCanonical": true},":cz:":{"unicode":["1f1e8-1f1ff"],"fname":"1f1e8-1f1ff","uc":"1f1e8-1f1ff","isCanonical": false},":flag_cy:":{"unicode":["1f1e8-1f1fe"],"fname":"1f1e8-1f1fe","uc":"1f1e8-1f1fe","isCanonical": true},":cy:":{"unicode":["1f1e8-1f1fe"],"fname":"1f1e8-1f1fe","uc":"1f1e8-1f1fe","isCanonical": false},":flag_cx:":{"unicode":["1f1e8-1f1fd"],"fname":"1f1e8-1f1fd","uc":"1f1e8-1f1fd","isCanonical": true},":cx:":{"unicode":["1f1e8-1f1fd"],"fname":"1f1e8-1f1fd","uc":"1f1e8-1f1fd","isCanonical": false},":flag_cw:":{"unicode":["1f1e8-1f1fc"],"fname":"1f1e8-1f1fc","uc":"1f1e8-1f1fc","isCanonical": true},":cw:":{"unicode":["1f1e8-1f1fc"],"fname":"1f1e8-1f1fc","uc":"1f1e8-1f1fc","isCanonical": false},":flag_cv:":{"unicode":["1f1e8-1f1fb"],"fname":"1f1e8-1f1fb","uc":"1f1e8-1f1fb","isCanonical": true},":cv:":{"unicode":["1f1e8-1f1fb"],"fname":"1f1e8-1f1fb","uc":"1f1e8-1f1fb","isCanonical": false},":flag_cu:":{"unicode":["1f1e8-1f1fa"],"fname":"1f1e8-1f1fa","uc":"1f1e8-1f1fa","isCanonical": true},":cu:":{"unicode":["1f1e8-1f1fa"],"fname":"1f1e8-1f1fa","uc":"1f1e8-1f1fa","isCanonical": false},":flag_cr:":{"unicode":["1f1e8-1f1f7"],"fname":"1f1e8-1f1f7","uc":"1f1e8-1f1f7","isCanonical": true},":cr:":{"unicode":["1f1e8-1f1f7"],"fname":"1f1e8-1f1f7","uc":"1f1e8-1f1f7","isCanonical": false},":flag_cp:":{"unicode":["1f1e8-1f1f5"],"fname":"1f1e8-1f1f5","uc":"1f1e8-1f1f5","isCanonical": true},":cp:":{"unicode":["1f1e8-1f1f5"],"fname":"1f1e8-1f1f5","uc":"1f1e8-1f1f5","isCanonical": false},":flag_co:":{"unicode":["1f1e8-1f1f4"],"fname":"1f1e8-1f1f4","uc":"1f1e8-1f1f4","isCanonical": true},":co:":{"unicode":["1f1e8-1f1f4"],"fname":"1f1e8-1f1f4","uc":"1f1e8-1f1f4","isCanonical": false},":flag_cn:":{"unicode":["1f1e8-1f1f3"],"fname":"1f1e8-1f1f3","uc":"1f1e8-1f1f3","isCanonical": true},":cn:":{"unicode":["1f1e8-1f1f3"],"fname":"1f1e8-1f1f3","uc":"1f1e8-1f1f3","isCanonical": false},":flag_cm:":{"unicode":["1f1e8-1f1f2"],"fname":"1f1e8-1f1f2","uc":"1f1e8-1f1f2","isCanonical": true},":cm:":{"unicode":["1f1e8-1f1f2"],"fname":"1f1e8-1f1f2","uc":"1f1e8-1f1f2","isCanonical": false},":flag_cl:":{"unicode":["1f1e8-1f1f1"],"fname":"1f1e8-1f1f1","uc":"1f1e8-1f1f1","isCanonical": true},":chile:":{"unicode":["1f1e8-1f1f1"],"fname":"1f1e8-1f1f1","uc":"1f1e8-1f1f1","isCanonical": false},":flag_ck:":{"unicode":["1f1e8-1f1f0"],"fname":"1f1e8-1f1f0","uc":"1f1e8-1f1f0","isCanonical": true},":ck:":{"unicode":["1f1e8-1f1f0"],"fname":"1f1e8-1f1f0","uc":"1f1e8-1f1f0","isCanonical": false},":flag_ci:":{"unicode":["1f1e8-1f1ee"],"fname":"1f1e8-1f1ee","uc":"1f1e8-1f1ee","isCanonical": true},":ci:":{"unicode":["1f1e8-1f1ee"],"fname":"1f1e8-1f1ee","uc":"1f1e8-1f1ee","isCanonical": false},":flag_ch:":{"unicode":["1f1e8-1f1ed"],"fname":"1f1e8-1f1ed","uc":"1f1e8-1f1ed","isCanonical": true},":ch:":{"unicode":["1f1e8-1f1ed"],"fname":"1f1e8-1f1ed","uc":"1f1e8-1f1ed","isCanonical": false},":flag_cg:":{"unicode":["1f1e8-1f1ec"],"fname":"1f1e8-1f1ec","uc":"1f1e8-1f1ec","isCanonical": true},":cg:":{"unicode":["1f1e8-1f1ec"],"fname":"1f1e8-1f1ec","uc":"1f1e8-1f1ec","isCanonical": false},":flag_cf:":{"unicode":["1f1e8-1f1eb"],"fname":"1f1e8-1f1eb","uc":"1f1e8-1f1eb","isCanonical": true},":cf:":{"unicode":["1f1e8-1f1eb"],"fname":"1f1e8-1f1eb","uc":"1f1e8-1f1eb","isCanonical": false},":flag_cd:":{"unicode":["1f1e8-1f1e9"],"fname":"1f1e8-1f1e9","uc":"1f1e8-1f1e9","isCanonical": true},":congo:":{"unicode":["1f1e8-1f1e9"],"fname":"1f1e8-1f1e9","uc":"1f1e8-1f1e9","isCanonical": false},":flag_cc:":{"unicode":["1f1e8-1f1e8"],"fname":"1f1e8-1f1e8","uc":"1f1e8-1f1e8","isCanonical": true},":cc:":{"unicode":["1f1e8-1f1e8"],"fname":"1f1e8-1f1e8","uc":"1f1e8-1f1e8","isCanonical": false},":flag_ca:":{"unicode":["1f1e8-1f1e6"],"fname":"1f1e8-1f1e6","uc":"1f1e8-1f1e6","isCanonical": true},":ca:":{"unicode":["1f1e8-1f1e6"],"fname":"1f1e8-1f1e6","uc":"1f1e8-1f1e6","isCanonical": false},":flag_bz:":{"unicode":["1f1e7-1f1ff"],"fname":"1f1e7-1f1ff","uc":"1f1e7-1f1ff","isCanonical": true},":bz:":{"unicode":["1f1e7-1f1ff"],"fname":"1f1e7-1f1ff","uc":"1f1e7-1f1ff","isCanonical": false},":flag_by:":{"unicode":["1f1e7-1f1fe"],"fname":"1f1e7-1f1fe","uc":"1f1e7-1f1fe","isCanonical": true},":by:":{"unicode":["1f1e7-1f1fe"],"fname":"1f1e7-1f1fe","uc":"1f1e7-1f1fe","isCanonical": false},":flag_bw:":{"unicode":["1f1e7-1f1fc"],"fname":"1f1e7-1f1fc","uc":"1f1e7-1f1fc","isCanonical": true},":bw:":{"unicode":["1f1e7-1f1fc"],"fname":"1f1e7-1f1fc","uc":"1f1e7-1f1fc","isCanonical": false},":flag_bv:":{"unicode":["1f1e7-1f1fb"],"fname":"1f1e7-1f1fb","uc":"1f1e7-1f1fb","isCanonical": true},":bv:":{"unicode":["1f1e7-1f1fb"],"fname":"1f1e7-1f1fb","uc":"1f1e7-1f1fb","isCanonical": false},":flag_bt:":{"unicode":["1f1e7-1f1f9"],"fname":"1f1e7-1f1f9","uc":"1f1e7-1f1f9","isCanonical": true},":bt:":{"unicode":["1f1e7-1f1f9"],"fname":"1f1e7-1f1f9","uc":"1f1e7-1f1f9","isCanonical": false},":flag_bs:":{"unicode":["1f1e7-1f1f8"],"fname":"1f1e7-1f1f8","uc":"1f1e7-1f1f8","isCanonical": true},":bs:":{"unicode":["1f1e7-1f1f8"],"fname":"1f1e7-1f1f8","uc":"1f1e7-1f1f8","isCanonical": false},":flag_br:":{"unicode":["1f1e7-1f1f7"],"fname":"1f1e7-1f1f7","uc":"1f1e7-1f1f7","isCanonical": true},":br:":{"unicode":["1f1e7-1f1f7"],"fname":"1f1e7-1f1f7","uc":"1f1e7-1f1f7","isCanonical": false},":flag_bq:":{"unicode":["1f1e7-1f1f6"],"fname":"1f1e7-1f1f6","uc":"1f1e7-1f1f6","isCanonical": true},":bq:":{"unicode":["1f1e7-1f1f6"],"fname":"1f1e7-1f1f6","uc":"1f1e7-1f1f6","isCanonical": false},":flag_bo:":{"unicode":["1f1e7-1f1f4"],"fname":"1f1e7-1f1f4","uc":"1f1e7-1f1f4","isCanonical": true},":bo:":{"unicode":["1f1e7-1f1f4"],"fname":"1f1e7-1f1f4","uc":"1f1e7-1f1f4","isCanonical": false},":flag_bn:":{"unicode":["1f1e7-1f1f3"],"fname":"1f1e7-1f1f3","uc":"1f1e7-1f1f3","isCanonical": true},":bn:":{"unicode":["1f1e7-1f1f3"],"fname":"1f1e7-1f1f3","uc":"1f1e7-1f1f3","isCanonical": false},":flag_bm:":{"unicode":["1f1e7-1f1f2"],"fname":"1f1e7-1f1f2","uc":"1f1e7-1f1f2","isCanonical": true},":bm:":{"unicode":["1f1e7-1f1f2"],"fname":"1f1e7-1f1f2","uc":"1f1e7-1f1f2","isCanonical": false},":flag_bl:":{"unicode":["1f1e7-1f1f1"],"fname":"1f1e7-1f1f1","uc":"1f1e7-1f1f1","isCanonical": true},":bl:":{"unicode":["1f1e7-1f1f1"],"fname":"1f1e7-1f1f1","uc":"1f1e7-1f1f1","isCanonical": false},":flag_bj:":{"unicode":["1f1e7-1f1ef"],"fname":"1f1e7-1f1ef","uc":"1f1e7-1f1ef","isCanonical": true},":bj:":{"unicode":["1f1e7-1f1ef"],"fname":"1f1e7-1f1ef","uc":"1f1e7-1f1ef","isCanonical": false},":flag_bi:":{"unicode":["1f1e7-1f1ee"],"fname":"1f1e7-1f1ee","uc":"1f1e7-1f1ee","isCanonical": true},":bi:":{"unicode":["1f1e7-1f1ee"],"fname":"1f1e7-1f1ee","uc":"1f1e7-1f1ee","isCanonical": false},":flag_bh:":{"unicode":["1f1e7-1f1ed"],"fname":"1f1e7-1f1ed","uc":"1f1e7-1f1ed","isCanonical": true},":bh:":{"unicode":["1f1e7-1f1ed"],"fname":"1f1e7-1f1ed","uc":"1f1e7-1f1ed","isCanonical": false},":flag_bg:":{"unicode":["1f1e7-1f1ec"],"fname":"1f1e7-1f1ec","uc":"1f1e7-1f1ec","isCanonical": true},":bg:":{"unicode":["1f1e7-1f1ec"],"fname":"1f1e7-1f1ec","uc":"1f1e7-1f1ec","isCanonical": false},":flag_bf:":{"unicode":["1f1e7-1f1eb"],"fname":"1f1e7-1f1eb","uc":"1f1e7-1f1eb","isCanonical": true},":bf:":{"unicode":["1f1e7-1f1eb"],"fname":"1f1e7-1f1eb","uc":"1f1e7-1f1eb","isCanonical": false},":flag_be:":{"unicode":["1f1e7-1f1ea"],"fname":"1f1e7-1f1ea","uc":"1f1e7-1f1ea","isCanonical": true},":be:":{"unicode":["1f1e7-1f1ea"],"fname":"1f1e7-1f1ea","uc":"1f1e7-1f1ea","isCanonical": false},":flag_bd:":{"unicode":["1f1e7-1f1e9"],"fname":"1f1e7-1f1e9","uc":"1f1e7-1f1e9","isCanonical": true},":bd:":{"unicode":["1f1e7-1f1e9"],"fname":"1f1e7-1f1e9","uc":"1f1e7-1f1e9","isCanonical": false},":flag_bb:":{"unicode":["1f1e7-1f1e7"],"fname":"1f1e7-1f1e7","uc":"1f1e7-1f1e7","isCanonical": true},":bb:":{"unicode":["1f1e7-1f1e7"],"fname":"1f1e7-1f1e7","uc":"1f1e7-1f1e7","isCanonical": false},":flag_ba:":{"unicode":["1f1e7-1f1e6"],"fname":"1f1e7-1f1e6","uc":"1f1e7-1f1e6","isCanonical": true},":ba:":{"unicode":["1f1e7-1f1e6"],"fname":"1f1e7-1f1e6","uc":"1f1e7-1f1e6","isCanonical": false},":flag_az:":{"unicode":["1f1e6-1f1ff"],"fname":"1f1e6-1f1ff","uc":"1f1e6-1f1ff","isCanonical": true},":az:":{"unicode":["1f1e6-1f1ff"],"fname":"1f1e6-1f1ff","uc":"1f1e6-1f1ff","isCanonical": false},":flag_ax:":{"unicode":["1f1e6-1f1fd"],"fname":"1f1e6-1f1fd","uc":"1f1e6-1f1fd","isCanonical": true},":ax:":{"unicode":["1f1e6-1f1fd"],"fname":"1f1e6-1f1fd","uc":"1f1e6-1f1fd","isCanonical": false},":flag_aw:":{"unicode":["1f1e6-1f1fc"],"fname":"1f1e6-1f1fc","uc":"1f1e6-1f1fc","isCanonical": true},":aw:":{"unicode":["1f1e6-1f1fc"],"fname":"1f1e6-1f1fc","uc":"1f1e6-1f1fc","isCanonical": false},":flag_au:":{"unicode":["1f1e6-1f1fa"],"fname":"1f1e6-1f1fa","uc":"1f1e6-1f1fa","isCanonical": true},":au:":{"unicode":["1f1e6-1f1fa"],"fname":"1f1e6-1f1fa","uc":"1f1e6-1f1fa","isCanonical": false},":flag_at:":{"unicode":["1f1e6-1f1f9"],"fname":"1f1e6-1f1f9","uc":"1f1e6-1f1f9","isCanonical": true},":at:":{"unicode":["1f1e6-1f1f9"],"fname":"1f1e6-1f1f9","uc":"1f1e6-1f1f9","isCanonical": false},":flag_as:":{"unicode":["1f1e6-1f1f8"],"fname":"1f1e6-1f1f8","uc":"1f1e6-1f1f8","isCanonical": true},":as:":{"unicode":["1f1e6-1f1f8"],"fname":"1f1e6-1f1f8","uc":"1f1e6-1f1f8","isCanonical": false},":flag_ar:":{"unicode":["1f1e6-1f1f7"],"fname":"1f1e6-1f1f7","uc":"1f1e6-1f1f7","isCanonical": true},":ar:":{"unicode":["1f1e6-1f1f7"],"fname":"1f1e6-1f1f7","uc":"1f1e6-1f1f7","isCanonical": false},":flag_aq:":{"unicode":["1f1e6-1f1f6"],"fname":"1f1e6-1f1f6","uc":"1f1e6-1f1f6","isCanonical": true},":aq:":{"unicode":["1f1e6-1f1f6"],"fname":"1f1e6-1f1f6","uc":"1f1e6-1f1f6","isCanonical": false},":flag_ao:":{"unicode":["1f1e6-1f1f4"],"fname":"1f1e6-1f1f4","uc":"1f1e6-1f1f4","isCanonical": true},":ao:":{"unicode":["1f1e6-1f1f4"],"fname":"1f1e6-1f1f4","uc":"1f1e6-1f1f4","isCanonical": false},":flag_am:":{"unicode":["1f1e6-1f1f2"],"fname":"1f1e6-1f1f2","uc":"1f1e6-1f1f2","isCanonical": true},":am:":{"unicode":["1f1e6-1f1f2"],"fname":"1f1e6-1f1f2","uc":"1f1e6-1f1f2","isCanonical": false},":flag_al:":{"unicode":["1f1e6-1f1f1"],"fname":"1f1e6-1f1f1","uc":"1f1e6-1f1f1","isCanonical": true},":al:":{"unicode":["1f1e6-1f1f1"],"fname":"1f1e6-1f1f1","uc":"1f1e6-1f1f1","isCanonical": false},":flag_ai:":{"unicode":["1f1e6-1f1ee"],"fname":"1f1e6-1f1ee","uc":"1f1e6-1f1ee","isCanonical": true},":ai:":{"unicode":["1f1e6-1f1ee"],"fname":"1f1e6-1f1ee","uc":"1f1e6-1f1ee","isCanonical": false},":flag_ag:":{"unicode":["1f1e6-1f1ec"],"fname":"1f1e6-1f1ec","uc":"1f1e6-1f1ec","isCanonical": true},":ag:":{"unicode":["1f1e6-1f1ec"],"fname":"1f1e6-1f1ec","uc":"1f1e6-1f1ec","isCanonical": false},":flag_af:":{"unicode":["1f1e6-1f1eb"],"fname":"1f1e6-1f1eb","uc":"1f1e6-1f1eb","isCanonical": true},":af:":{"unicode":["1f1e6-1f1eb"],"fname":"1f1e6-1f1eb","uc":"1f1e6-1f1eb","isCanonical": false},":flag_ae:":{"unicode":["1f1e6-1f1ea"],"fname":"1f1e6-1f1ea","uc":"1f1e6-1f1ea","isCanonical": true},":ae:":{"unicode":["1f1e6-1f1ea"],"fname":"1f1e6-1f1ea","uc":"1f1e6-1f1ea","isCanonical": false},":flag_ad:":{"unicode":["1f1e6-1f1e9"],"fname":"1f1e6-1f1e9","uc":"1f1e6-1f1e9","isCanonical": true},":ad:":{"unicode":["1f1e6-1f1e9"],"fname":"1f1e6-1f1e9","uc":"1f1e6-1f1e9","isCanonical": false},":flag_ac:":{"unicode":["1f1e6-1f1e8"],"fname":"1f1e6-1f1e8","uc":"1f1e6-1f1e8","isCanonical": true},":ac:":{"unicode":["1f1e6-1f1e8"],"fname":"1f1e6-1f1e8","uc":"1f1e6-1f1e8","isCanonical": false},":mahjong:":{"unicode":["1f004-fe0f","1f004"],"fname":"1f004","uc":"1f004","isCanonical": true},":parking:":{"unicode":["1f17f-fe0f","1f17f"],"fname":"1f17f","uc":"1f17f","isCanonical": true},":sa:":{"unicode":["1f202-fe0f","1f202"],"fname":"1f202","uc":"1f202","isCanonical": true},":u7121:":{"unicode":["1f21a-fe0f","1f21a"],"fname":"1f21a","uc":"1f21a","isCanonical": true},":u6307:":{"unicode":["1f22f-fe0f","1f22f"],"fname":"1f22f","uc":"1f22f","isCanonical": true},":u6708:":{"unicode":["1f237-fe0f","1f237"],"fname":"1f237","uc":"1f237","isCanonical": true},":film_frames:":{"unicode":["1f39e-fe0f","1f39e"],"fname":"1f39e","uc":"1f39e","isCanonical": true},":tickets:":{"unicode":["1f39f-fe0f","1f39f"],"fname":"1f39f","uc":"1f39f","isCanonical": true},":admission_tickets:":{"unicode":["1f39f-fe0f","1f39f"],"fname":"1f39f","uc":"1f39f","isCanonical": false},":lifter:":{"unicode":["1f3cb-fe0f","1f3cb"],"fname":"1f3cb","uc":"1f3cb","isCanonical": true},":weight_lifter:":{"unicode":["1f3cb-fe0f","1f3cb"],"fname":"1f3cb","uc":"1f3cb","isCanonical": false},":golfer:":{"unicode":["1f3cc-fe0f","1f3cc"],"fname":"1f3cc","uc":"1f3cc","isCanonical": true},":motorcycle:":{"unicode":["1f3cd-fe0f","1f3cd"],"fname":"1f3cd","uc":"1f3cd","isCanonical": true},":racing_motorcycle:":{"unicode":["1f3cd-fe0f","1f3cd"],"fname":"1f3cd","uc":"1f3cd","isCanonical": false},":race_car:":{"unicode":["1f3ce-fe0f","1f3ce"],"fname":"1f3ce","uc":"1f3ce","isCanonical": true},":racing_car:":{"unicode":["1f3ce-fe0f","1f3ce"],"fname":"1f3ce","uc":"1f3ce","isCanonical": false},":military_medal:":{"unicode":["1f396-fe0f","1f396"],"fname":"1f396","uc":"1f396","isCanonical": true},":reminder_ribbon:":{"unicode":["1f397-fe0f","1f397"],"fname":"1f397","uc":"1f397","isCanonical": true},":hot_pepper:":{"unicode":["1f336-fe0f","1f336"],"fname":"1f336","uc":"1f336","isCanonical": true},":cloud_rain:":{"unicode":["1f327-fe0f","1f327"],"fname":"1f327","uc":"1f327","isCanonical": true},":cloud_with_rain:":{"unicode":["1f327-fe0f","1f327"],"fname":"1f327","uc":"1f327","isCanonical": false},":cloud_snow:":{"unicode":["1f328-fe0f","1f328"],"fname":"1f328","uc":"1f328","isCanonical": true},":cloud_with_snow:":{"unicode":["1f328-fe0f","1f328"],"fname":"1f328","uc":"1f328","isCanonical": false},":cloud_lightning:":{"unicode":["1f329-fe0f","1f329"],"fname":"1f329","uc":"1f329","isCanonical": true},":cloud_with_lightning:":{"unicode":["1f329-fe0f","1f329"],"fname":"1f329","uc":"1f329","isCanonical": false},":cloud_tornado:":{"unicode":["1f32a-fe0f","1f32a"],"fname":"1f32a","uc":"1f32a","isCanonical": true},":cloud_with_tornado:":{"unicode":["1f32a-fe0f","1f32a"],"fname":"1f32a","uc":"1f32a","isCanonical": false},":fog:":{"unicode":["1f32b-fe0f","1f32b"],"fname":"1f32b","uc":"1f32b","isCanonical": true},":wind_blowing_face:":{"unicode":["1f32c-fe0f","1f32c"],"fname":"1f32c","uc":"1f32c","isCanonical": true},":chipmunk:":{"unicode":["1f43f-fe0f","1f43f"],"fname":"1f43f","uc":"1f43f","isCanonical": true},":spider:":{"unicode":["1f577-fe0f","1f577"],"fname":"1f577","uc":"1f577","isCanonical": true},":spider_web:":{"unicode":["1f578-fe0f","1f578"],"fname":"1f578","uc":"1f578","isCanonical": true},":thermometer:":{"unicode":["1f321-fe0f","1f321"],"fname":"1f321","uc":"1f321","isCanonical": true},":microphone2:":{"unicode":["1f399-fe0f","1f399"],"fname":"1f399","uc":"1f399","isCanonical": true},":studio_microphone:":{"unicode":["1f399-fe0f","1f399"],"fname":"1f399","uc":"1f399","isCanonical": false},":level_slider:":{"unicode":["1f39a-fe0f","1f39a"],"fname":"1f39a","uc":"1f39a","isCanonical": true},":control_knobs:":{"unicode":["1f39b-fe0f","1f39b"],"fname":"1f39b","uc":"1f39b","isCanonical": true},":flag_white:":{"unicode":["1f3f3-fe0f","1f3f3"],"fname":"1f3f3","uc":"1f3f3","isCanonical": true},":waving_white_flag:":{"unicode":["1f3f3-fe0f","1f3f3"],"fname":"1f3f3","uc":"1f3f3","isCanonical": false},":rosette:":{"unicode":["1f3f5-fe0f","1f3f5"],"fname":"1f3f5","uc":"1f3f5","isCanonical": true},":label:":{"unicode":["1f3f7-fe0f","1f3f7"],"fname":"1f3f7","uc":"1f3f7","isCanonical": true},":projector:":{"unicode":["1f4fd-fe0f","1f4fd"],"fname":"1f4fd","uc":"1f4fd","isCanonical": true},":film_projector:":{"unicode":["1f4fd-fe0f","1f4fd"],"fname":"1f4fd","uc":"1f4fd","isCanonical": false},":om_symbol:":{"unicode":["1f549-fe0f","1f549"],"fname":"1f549","uc":"1f549","isCanonical": true},":dove:":{"unicode":["1f54a-fe0f","1f54a"],"fname":"1f54a","uc":"1f54a","isCanonical": true},":dove_of_peace:":{"unicode":["1f54a-fe0f","1f54a"],"fname":"1f54a","uc":"1f54a","isCanonical": false},":candle:":{"unicode":["1f56f-fe0f","1f56f"],"fname":"1f56f","uc":"1f56f","isCanonical": true},":clock:":{"unicode":["1f570-fe0f","1f570"],"fname":"1f570","uc":"1f570","isCanonical": true},":mantlepiece_clock:":{"unicode":["1f570-fe0f","1f570"],"fname":"1f570","uc":"1f570","isCanonical": false},":hole:":{"unicode":["1f573-fe0f","1f573"],"fname":"1f573","uc":"1f573","isCanonical": true},":dark_sunglasses:":{"unicode":["1f576-fe0f","1f576"],"fname":"1f576","uc":"1f576","isCanonical": true},":joystick:":{"unicode":["1f579-fe0f","1f579"],"fname":"1f579","uc":"1f579","isCanonical": true},":paperclips:":{"unicode":["1f587-fe0f","1f587"],"fname":"1f587","uc":"1f587","isCanonical": true},":linked_paperclips:":{"unicode":["1f587-fe0f","1f587"],"fname":"1f587","uc":"1f587","isCanonical": false},":pen_ballpoint:":{"unicode":["1f58a-fe0f","1f58a"],"fname":"1f58a","uc":"1f58a","isCanonical": true},":lower_left_ballpoint_pen:":{"unicode":["1f58a-fe0f","1f58a"],"fname":"1f58a","uc":"1f58a","isCanonical": false},":pen_fountain:":{"unicode":["1f58b-fe0f","1f58b"],"fname":"1f58b","uc":"1f58b","isCanonical": true},":lower_left_fountain_pen:":{"unicode":["1f58b-fe0f","1f58b"],"fname":"1f58b","uc":"1f58b","isCanonical": false},":paintbrush:":{"unicode":["1f58c-fe0f","1f58c"],"fname":"1f58c","uc":"1f58c","isCanonical": true},":lower_left_paintbrush:":{"unicode":["1f58c-fe0f","1f58c"],"fname":"1f58c","uc":"1f58c","isCanonical": false},":crayon:":{"unicode":["1f58d-fe0f","1f58d"],"fname":"1f58d","uc":"1f58d","isCanonical": true},":lower_left_crayon:":{"unicode":["1f58d-fe0f","1f58d"],"fname":"1f58d","uc":"1f58d","isCanonical": false},":desktop:":{"unicode":["1f5a5-fe0f","1f5a5"],"fname":"1f5a5","uc":"1f5a5","isCanonical": true},":desktop_computer:":{"unicode":["1f5a5-fe0f","1f5a5"],"fname":"1f5a5","uc":"1f5a5","isCanonical": false},":printer:":{"unicode":["1f5a8-fe0f","1f5a8"],"fname":"1f5a8","uc":"1f5a8","isCanonical": true},":trackball:":{"unicode":["1f5b2-fe0f","1f5b2"],"fname":"1f5b2","uc":"1f5b2","isCanonical": true},":frame_photo:":{"unicode":["1f5bc-fe0f","1f5bc"],"fname":"1f5bc","uc":"1f5bc","isCanonical": true},":frame_with_picture:":{"unicode":["1f5bc-fe0f","1f5bc"],"fname":"1f5bc","uc":"1f5bc","isCanonical": false},":dividers:":{"unicode":["1f5c2-fe0f","1f5c2"],"fname":"1f5c2","uc":"1f5c2","isCanonical": true},":card_index_dividers:":{"unicode":["1f5c2-fe0f","1f5c2"],"fname":"1f5c2","uc":"1f5c2","isCanonical": false},":card_box:":{"unicode":["1f5c3-fe0f","1f5c3"],"fname":"1f5c3","uc":"1f5c3","isCanonical": true},":card_file_box:":{"unicode":["1f5c3-fe0f","1f5c3"],"fname":"1f5c3","uc":"1f5c3","isCanonical": false},":file_cabinet:":{"unicode":["1f5c4-fe0f","1f5c4"],"fname":"1f5c4","uc":"1f5c4","isCanonical": true},":wastebasket:":{"unicode":["1f5d1-fe0f","1f5d1"],"fname":"1f5d1","uc":"1f5d1","isCanonical": true},":notepad_spiral:":{"unicode":["1f5d2-fe0f","1f5d2"],"fname":"1f5d2","uc":"1f5d2","isCanonical": true},":spiral_note_pad:":{"unicode":["1f5d2-fe0f","1f5d2"],"fname":"1f5d2","uc":"1f5d2","isCanonical": false},":calendar_spiral:":{"unicode":["1f5d3-fe0f","1f5d3"],"fname":"1f5d3","uc":"1f5d3","isCanonical": true},":spiral_calendar_pad:":{"unicode":["1f5d3-fe0f","1f5d3"],"fname":"1f5d3","uc":"1f5d3","isCanonical": false},":compression:":{"unicode":["1f5dc-fe0f","1f5dc"],"fname":"1f5dc","uc":"1f5dc","isCanonical": true},":key2:":{"unicode":["1f5dd-fe0f","1f5dd"],"fname":"1f5dd","uc":"1f5dd","isCanonical": true},":old_key:":{"unicode":["1f5dd-fe0f","1f5dd"],"fname":"1f5dd","uc":"1f5dd","isCanonical": false},":newspaper2:":{"unicode":["1f5de-fe0f","1f5de"],"fname":"1f5de","uc":"1f5de","isCanonical": true},":rolled_up_newspaper:":{"unicode":["1f5de-fe0f","1f5de"],"fname":"1f5de","uc":"1f5de","isCanonical": false},":dagger:":{"unicode":["1f5e1-fe0f","1f5e1"],"fname":"1f5e1","uc":"1f5e1","isCanonical": true},":dagger_knife:":{"unicode":["1f5e1-fe0f","1f5e1"],"fname":"1f5e1","uc":"1f5e1","isCanonical": false},":speaking_head:":{"unicode":["1f5e3-fe0f","1f5e3"],"fname":"1f5e3","uc":"1f5e3","isCanonical": true},":speaking_head_in_silhouette:":{"unicode":["1f5e3-fe0f","1f5e3"],"fname":"1f5e3","uc":"1f5e3","isCanonical": false},":speech_left:":{"unicode":["1f5e8-fe0f","1f5e8"],"fname":"1f5e8","uc":"1f5e8","isCanonical": true},":left_speech_bubble:":{"unicode":["1f5e8-fe0f","1f5e8"],"fname":"1f5e8","uc":"1f5e8","isCanonical": false},":anger_right:":{"unicode":["1f5ef-fe0f","1f5ef"],"fname":"1f5ef","uc":"1f5ef","isCanonical": true},":right_anger_bubble:":{"unicode":["1f5ef-fe0f","1f5ef"],"fname":"1f5ef","uc":"1f5ef","isCanonical": false},":ballot_box:":{"unicode":["1f5f3-fe0f","1f5f3"],"fname":"1f5f3","uc":"1f5f3","isCanonical": true},":ballot_box_with_ballot:":{"unicode":["1f5f3-fe0f","1f5f3"],"fname":"1f5f3","uc":"1f5f3","isCanonical": false},":map:":{"unicode":["1f5fa-fe0f","1f5fa"],"fname":"1f5fa","uc":"1f5fa","isCanonical": true},":world_map:":{"unicode":["1f5fa-fe0f","1f5fa"],"fname":"1f5fa","uc":"1f5fa","isCanonical": false},":tools:":{"unicode":["1f6e0-fe0f","1f6e0"],"fname":"1f6e0","uc":"1f6e0","isCanonical": true},":hammer_and_wrench:":{"unicode":["1f6e0-fe0f","1f6e0"],"fname":"1f6e0","uc":"1f6e0","isCanonical": false},":shield:":{"unicode":["1f6e1-fe0f","1f6e1"],"fname":"1f6e1","uc":"1f6e1","isCanonical": true},":oil:":{"unicode":["1f6e2-fe0f","1f6e2"],"fname":"1f6e2","uc":"1f6e2","isCanonical": true},":oil_drum:":{"unicode":["1f6e2-fe0f","1f6e2"],"fname":"1f6e2","uc":"1f6e2","isCanonical": false},":satellite_orbital:":{"unicode":["1f6f0-fe0f","1f6f0"],"fname":"1f6f0","uc":"1f6f0","isCanonical": true},":fork_knife_plate:":{"unicode":["1f37d-fe0f","1f37d"],"fname":"1f37d","uc":"1f37d","isCanonical": true},":fork_and_knife_with_plate:":{"unicode":["1f37d-fe0f","1f37d"],"fname":"1f37d","uc":"1f37d","isCanonical": false},":eye:":{"unicode":["1f441-fe0f","1f441"],"fname":"1f441","uc":"1f441","isCanonical": true},":levitate:":{"unicode":["1f574-fe0f","1f574"],"fname":"1f574","uc":"1f574","isCanonical": true},":man_in_business_suit_levitating:":{"unicode":["1f574-fe0f","1f574"],"fname":"1f574","uc":"1f574","isCanonical": false},":spy:":{"unicode":["1f575-fe0f","1f575"],"fname":"1f575","uc":"1f575","isCanonical": true},":sleuth_or_spy:":{"unicode":["1f575-fe0f","1f575"],"fname":"1f575","uc":"1f575","isCanonical": false},":hand_splayed:":{"unicode":["1f590-fe0f","1f590"],"fname":"1f590","uc":"1f590","isCanonical": true},":raised_hand_with_fingers_splayed:":{"unicode":["1f590-fe0f","1f590"],"fname":"1f590","uc":"1f590","isCanonical": false},":mountain_snow:":{"unicode":["1f3d4-fe0f","1f3d4"],"fname":"1f3d4","uc":"1f3d4","isCanonical": true},":snow_capped_mountain:":{"unicode":["1f3d4-fe0f","1f3d4"],"fname":"1f3d4","uc":"1f3d4","isCanonical": false},":camping:":{"unicode":["1f3d5-fe0f","1f3d5"],"fname":"1f3d5","uc":"1f3d5","isCanonical": true},":beach:":{"unicode":["1f3d6-fe0f","1f3d6"],"fname":"1f3d6","uc":"1f3d6","isCanonical": true},":beach_with_umbrella:":{"unicode":["1f3d6-fe0f","1f3d6"],"fname":"1f3d6","uc":"1f3d6","isCanonical": false},":construction_site:":{"unicode":["1f3d7-fe0f","1f3d7"],"fname":"1f3d7","uc":"1f3d7","isCanonical": true},":building_construction:":{"unicode":["1f3d7-fe0f","1f3d7"],"fname":"1f3d7","uc":"1f3d7","isCanonical": false},":homes:":{"unicode":["1f3d8-fe0f","1f3d8"],"fname":"1f3d8","uc":"1f3d8","isCanonical": true},":house_buildings:":{"unicode":["1f3d8-fe0f","1f3d8"],"fname":"1f3d8","uc":"1f3d8","isCanonical": false},":cityscape:":{"unicode":["1f3d9-fe0f","1f3d9"],"fname":"1f3d9","uc":"1f3d9","isCanonical": true},":house_abandoned:":{"unicode":["1f3da-fe0f","1f3da"],"fname":"1f3da","uc":"1f3da","isCanonical": true},":derelict_house_building:":{"unicode":["1f3da-fe0f","1f3da"],"fname":"1f3da","uc":"1f3da","isCanonical": false},":classical_building:":{"unicode":["1f3db-fe0f","1f3db"],"fname":"1f3db","uc":"1f3db","isCanonical": true},":desert:":{"unicode":["1f3dc-fe0f","1f3dc"],"fname":"1f3dc","uc":"1f3dc","isCanonical": true},":island:":{"unicode":["1f3dd-fe0f","1f3dd"],"fname":"1f3dd","uc":"1f3dd","isCanonical": true},":desert_island:":{"unicode":["1f3dd-fe0f","1f3dd"],"fname":"1f3dd","uc":"1f3dd","isCanonical": false},":park:":{"unicode":["1f3de-fe0f","1f3de"],"fname":"1f3de","uc":"1f3de","isCanonical": true},":national_park:":{"unicode":["1f3de-fe0f","1f3de"],"fname":"1f3de","uc":"1f3de","isCanonical": false},":stadium:":{"unicode":["1f3df-fe0f","1f3df"],"fname":"1f3df","uc":"1f3df","isCanonical": true},":couch:":{"unicode":["1f6cb-fe0f","1f6cb"],"fname":"1f6cb","uc":"1f6cb","isCanonical": true},":couch_and_lamp:":{"unicode":["1f6cb-fe0f","1f6cb"],"fname":"1f6cb","uc":"1f6cb","isCanonical": false},":shopping_bags:":{"unicode":["1f6cd-fe0f","1f6cd"],"fname":"1f6cd","uc":"1f6cd","isCanonical": true},":bellhop:":{"unicode":["1f6ce-fe0f","1f6ce"],"fname":"1f6ce","uc":"1f6ce","isCanonical": true},":bellhop_bell:":{"unicode":["1f6ce-fe0f","1f6ce"],"fname":"1f6ce","uc":"1f6ce","isCanonical": false},":bed:":{"unicode":["1f6cf-fe0f","1f6cf"],"fname":"1f6cf","uc":"1f6cf","isCanonical": true},":motorway:":{"unicode":["1f6e3-fe0f","1f6e3"],"fname":"1f6e3","uc":"1f6e3","isCanonical": true},":railway_track:":{"unicode":["1f6e4-fe0f","1f6e4"],"fname":"1f6e4","uc":"1f6e4","isCanonical": true},":railroad_track:":{"unicode":["1f6e4-fe0f","1f6e4"],"fname":"1f6e4","uc":"1f6e4","isCanonical": false},":motorboat:":{"unicode":["1f6e5-fe0f","1f6e5"],"fname":"1f6e5","uc":"1f6e5","isCanonical": true},":airplane_small:":{"unicode":["1f6e9-fe0f","1f6e9"],"fname":"1f6e9","uc":"1f6e9","isCanonical": true},":small_airplane:":{"unicode":["1f6e9-fe0f","1f6e9"],"fname":"1f6e9","uc":"1f6e9","isCanonical": false},":cruise_ship:":{"unicode":["1f6f3-fe0f","1f6f3"],"fname":"1f6f3","uc":"1f6f3","isCanonical": true},":passenger_ship:":{"unicode":["1f6f3-fe0f","1f6f3"],"fname":"1f6f3","uc":"1f6f3","isCanonical": false},":white_sun_small_cloud:":{"unicode":["1f324-fe0f","1f324"],"fname":"1f324","uc":"1f324","isCanonical": true},":white_sun_with_small_cloud:":{"unicode":["1f324-fe0f","1f324"],"fname":"1f324","uc":"1f324","isCanonical": false},":white_sun_cloud:":{"unicode":["1f325-fe0f","1f325"],"fname":"1f325","uc":"1f325","isCanonical": true},":white_sun_behind_cloud:":{"unicode":["1f325-fe0f","1f325"],"fname":"1f325","uc":"1f325","isCanonical": false},":white_sun_rain_cloud:":{"unicode":["1f326-fe0f","1f326"],"fname":"1f326","uc":"1f326","isCanonical": true},":white_sun_behind_cloud_with_rain:":{"unicode":["1f326-fe0f","1f326"],"fname":"1f326","uc":"1f326","isCanonical": false},":mouse_three_button:":{"unicode":["1f5b1-fe0f","1f5b1"],"fname":"1f5b1","uc":"1f5b1","isCanonical": true},":three_button_mouse:":{"unicode":["1f5b1-fe0f","1f5b1"],"fname":"1f5b1","uc":"1f5b1","isCanonical": false},":point_up_tone1:":{"unicode":["261d-1f3fb"],"fname":"261d-1f3fb","uc":"261d-1f3fb","isCanonical": true},":point_up_tone2:":{"unicode":["261d-1f3fc"],"fname":"261d-1f3fc","uc":"261d-1f3fc","isCanonical": true},":point_up_tone3:":{"unicode":["261d-1f3fd"],"fname":"261d-1f3fd","uc":"261d-1f3fd","isCanonical": true},":point_up_tone4:":{"unicode":["261d-1f3fe"],"fname":"261d-1f3fe","uc":"261d-1f3fe","isCanonical": true},":point_up_tone5:":{"unicode":["261d-1f3ff"],"fname":"261d-1f3ff","uc":"261d-1f3ff","isCanonical": true},":v_tone1:":{"unicode":["270c-1f3fb"],"fname":"270c-1f3fb","uc":"270c-1f3fb","isCanonical": true},":v_tone2:":{"unicode":["270c-1f3fc"],"fname":"270c-1f3fc","uc":"270c-1f3fc","isCanonical": true},":v_tone3:":{"unicode":["270c-1f3fd"],"fname":"270c-1f3fd","uc":"270c-1f3fd","isCanonical": true},":v_tone4:":{"unicode":["270c-1f3fe"],"fname":"270c-1f3fe","uc":"270c-1f3fe","isCanonical": true},":v_tone5:":{"unicode":["270c-1f3ff"],"fname":"270c-1f3ff","uc":"270c-1f3ff","isCanonical": true},":fist_tone1:":{"unicode":["270a-1f3fb"],"fname":"270a-1f3fb","uc":"270a-1f3fb","isCanonical": true},":fist_tone2:":{"unicode":["270a-1f3fc"],"fname":"270a-1f3fc","uc":"270a-1f3fc","isCanonical": true},":fist_tone3:":{"unicode":["270a-1f3fd"],"fname":"270a-1f3fd","uc":"270a-1f3fd","isCanonical": true},":fist_tone4:":{"unicode":["270a-1f3fe"],"fname":"270a-1f3fe","uc":"270a-1f3fe","isCanonical": true},":fist_tone5:":{"unicode":["270a-1f3ff"],"fname":"270a-1f3ff","uc":"270a-1f3ff","isCanonical": true},":raised_hand_tone1:":{"unicode":["270b-1f3fb"],"fname":"270b-1f3fb","uc":"270b-1f3fb","isCanonical": true},":raised_hand_tone2:":{"unicode":["270b-1f3fc"],"fname":"270b-1f3fc","uc":"270b-1f3fc","isCanonical": true},":raised_hand_tone3:":{"unicode":["270b-1f3fd"],"fname":"270b-1f3fd","uc":"270b-1f3fd","isCanonical": true},":raised_hand_tone4:":{"unicode":["270b-1f3fe"],"fname":"270b-1f3fe","uc":"270b-1f3fe","isCanonical": true},":raised_hand_tone5:":{"unicode":["270b-1f3ff"],"fname":"270b-1f3ff","uc":"270b-1f3ff","isCanonical": true},":writing_hand_tone1:":{"unicode":["270d-1f3fb"],"fname":"270d-1f3fb","uc":"270d-1f3fb","isCanonical": true},":writing_hand_tone2:":{"unicode":["270d-1f3fc"],"fname":"270d-1f3fc","uc":"270d-1f3fc","isCanonical": true},":writing_hand_tone3:":{"unicode":["270d-1f3fd"],"fname":"270d-1f3fd","uc":"270d-1f3fd","isCanonical": true},":writing_hand_tone4:":{"unicode":["270d-1f3fe"],"fname":"270d-1f3fe","uc":"270d-1f3fe","isCanonical": true},":writing_hand_tone5:":{"unicode":["270d-1f3ff"],"fname":"270d-1f3ff","uc":"270d-1f3ff","isCanonical": true},":basketball_player_tone1:":{"unicode":["26f9-1f3fb"],"fname":"26f9-1f3fb","uc":"26f9-1f3fb","isCanonical": true},":person_with_ball_tone1:":{"unicode":["26f9-1f3fb"],"fname":"26f9-1f3fb","uc":"26f9-1f3fb","isCanonical": false},":basketball_player_tone2:":{"unicode":["26f9-1f3fc"],"fname":"26f9-1f3fc","uc":"26f9-1f3fc","isCanonical": true},":person_with_ball_tone2:":{"unicode":["26f9-1f3fc"],"fname":"26f9-1f3fc","uc":"26f9-1f3fc","isCanonical": false},":basketball_player_tone3:":{"unicode":["26f9-1f3fd"],"fname":"26f9-1f3fd","uc":"26f9-1f3fd","isCanonical": true},":person_with_ball_tone3:":{"unicode":["26f9-1f3fd"],"fname":"26f9-1f3fd","uc":"26f9-1f3fd","isCanonical": false},":basketball_player_tone4:":{"unicode":["26f9-1f3fe"],"fname":"26f9-1f3fe","uc":"26f9-1f3fe","isCanonical": true},":person_with_ball_tone4:":{"unicode":["26f9-1f3fe"],"fname":"26f9-1f3fe","uc":"26f9-1f3fe","isCanonical": false},":basketball_player_tone5:":{"unicode":["26f9-1f3ff"],"fname":"26f9-1f3ff","uc":"26f9-1f3ff","isCanonical": true},":person_with_ball_tone5:":{"unicode":["26f9-1f3ff"],"fname":"26f9-1f3ff","uc":"26f9-1f3ff","isCanonical": false},":copyright:":{"unicode":["00a9-fe0f","00a9"],"fname":"00a9","uc":"00a9","isCanonical": true},":registered:":{"unicode":["00ae-fe0f","00ae"],"fname":"00ae","uc":"00ae","isCanonical": true},":bangbang:":{"unicode":["203c-fe0f","203c"],"fname":"203c","uc":"203c","isCanonical": true},":interrobang:":{"unicode":["2049-fe0f","2049"],"fname":"2049","uc":"2049","isCanonical": true},":tm:":{"unicode":["2122-fe0f","2122"],"fname":"2122","uc":"2122","isCanonical": true},":information_source:":{"unicode":["2139-fe0f","2139"],"fname":"2139","uc":"2139","isCanonical": true},":left_right_arrow:":{"unicode":["2194-fe0f","2194"],"fname":"2194","uc":"2194","isCanonical": true},":arrow_up_down:":{"unicode":["2195-fe0f","2195"],"fname":"2195","uc":"2195","isCanonical": true},":arrow_upper_left:":{"unicode":["2196-fe0f","2196"],"fname":"2196","uc":"2196","isCanonical": true},":arrow_upper_right:":{"unicode":["2197-fe0f","2197"],"fname":"2197","uc":"2197","isCanonical": true},":arrow_lower_right:":{"unicode":["2198-fe0f","2198"],"fname":"2198","uc":"2198","isCanonical": true},":arrow_lower_left:":{"unicode":["2199-fe0f","2199"],"fname":"2199","uc":"2199","isCanonical": true},":leftwards_arrow_with_hook:":{"unicode":["21a9-fe0f","21a9"],"fname":"21a9","uc":"21a9","isCanonical": true},":arrow_right_hook:":{"unicode":["21aa-fe0f","21aa"],"fname":"21aa","uc":"21aa","isCanonical": true},":watch:":{"unicode":["231a-fe0f","231a"],"fname":"231a","uc":"231a","isCanonical": true},":hourglass:":{"unicode":["231b-fe0f","231b"],"fname":"231b","uc":"231b","isCanonical": true},":m:":{"unicode":["24c2-fe0f","24c2"],"fname":"24c2","uc":"24c2","isCanonical": true},":black_small_square:":{"unicode":["25aa-fe0f","25aa"],"fname":"25aa","uc":"25aa","isCanonical": true},":white_small_square:":{"unicode":["25ab-fe0f","25ab"],"fname":"25ab","uc":"25ab","isCanonical": true},":arrow_forward:":{"unicode":["25b6-fe0f","25b6"],"fname":"25b6","uc":"25b6","isCanonical": true},":arrow_backward:":{"unicode":["25c0-fe0f","25c0"],"fname":"25c0","uc":"25c0","isCanonical": true},":white_medium_square:":{"unicode":["25fb-fe0f","25fb"],"fname":"25fb","uc":"25fb","isCanonical": true},":black_medium_square:":{"unicode":["25fc-fe0f","25fc"],"fname":"25fc","uc":"25fc","isCanonical": true},":white_medium_small_square:":{"unicode":["25fd-fe0f","25fd"],"fname":"25fd","uc":"25fd","isCanonical": true},":black_medium_small_square:":{"unicode":["25fe-fe0f","25fe"],"fname":"25fe","uc":"25fe","isCanonical": true},":sunny:":{"unicode":["2600-fe0f","2600"],"fname":"2600","uc":"2600","isCanonical": true},":cloud:":{"unicode":["2601-fe0f","2601"],"fname":"2601","uc":"2601","isCanonical": true},":telephone:":{"unicode":["260e-fe0f","260e"],"fname":"260e","uc":"260e","isCanonical": true},":ballot_box_with_check:":{"unicode":["2611-fe0f","2611"],"fname":"2611","uc":"2611","isCanonical": true},":umbrella:":{"unicode":["2614-fe0f","2614"],"fname":"2614","uc":"2614","isCanonical": true},":coffee:":{"unicode":["2615-fe0f","2615"],"fname":"2615","uc":"2615","isCanonical": true},":point_up:":{"unicode":["261d-fe0f","261d"],"fname":"261d","uc":"261d","isCanonical": true},":relaxed:":{"unicode":["263a-fe0f","263a"],"fname":"263a","uc":"263a","isCanonical": true},":aries:":{"unicode":["2648-fe0f","2648"],"fname":"2648","uc":"2648","isCanonical": true},":taurus:":{"unicode":["2649-fe0f","2649"],"fname":"2649","uc":"2649","isCanonical": true},":gemini:":{"unicode":["264a-fe0f","264a"],"fname":"264a","uc":"264a","isCanonical": true},":cancer:":{"unicode":["264b-fe0f","264b"],"fname":"264b","uc":"264b","isCanonical": true},":leo:":{"unicode":["264c-fe0f","264c"],"fname":"264c","uc":"264c","isCanonical": true},":virgo:":{"unicode":["264d-fe0f","264d"],"fname":"264d","uc":"264d","isCanonical": true},":libra:":{"unicode":["264e-fe0f","264e"],"fname":"264e","uc":"264e","isCanonical": true},":scorpius:":{"unicode":["264f-fe0f","264f"],"fname":"264f","uc":"264f","isCanonical": true},":sagittarius:":{"unicode":["2650-fe0f","2650"],"fname":"2650","uc":"2650","isCanonical": true},":capricorn:":{"unicode":["2651-fe0f","2651"],"fname":"2651","uc":"2651","isCanonical": true},":aquarius:":{"unicode":["2652-fe0f","2652"],"fname":"2652","uc":"2652","isCanonical": true},":pisces:":{"unicode":["2653-fe0f","2653"],"fname":"2653","uc":"2653","isCanonical": true},":spades:":{"unicode":["2660-fe0f","2660"],"fname":"2660","uc":"2660","isCanonical": true},":clubs:":{"unicode":["2663-fe0f","2663"],"fname":"2663","uc":"2663","isCanonical": true},":hearts:":{"unicode":["2665-fe0f","2665"],"fname":"2665","uc":"2665","isCanonical": true},":diamonds:":{"unicode":["2666-fe0f","2666"],"fname":"2666","uc":"2666","isCanonical": true},":hotsprings:":{"unicode":["2668-fe0f","2668"],"fname":"2668","uc":"2668","isCanonical": true},":recycle:":{"unicode":["267b-fe0f","267b"],"fname":"267b","uc":"267b","isCanonical": true},":wheelchair:":{"unicode":["267f-fe0f","267f"],"fname":"267f","uc":"267f","isCanonical": true},":anchor:":{"unicode":["2693-fe0f","2693"],"fname":"2693","uc":"2693","isCanonical": true},":warning:":{"unicode":["26a0-fe0f","26a0"],"fname":"26a0","uc":"26a0","isCanonical": true},":zap:":{"unicode":["26a1-fe0f","26a1"],"fname":"26a1","uc":"26a1","isCanonical": true},":white_circle:":{"unicode":["26aa-fe0f","26aa"],"fname":"26aa","uc":"26aa","isCanonical": true},":black_circle:":{"unicode":["26ab-fe0f","26ab"],"fname":"26ab","uc":"26ab","isCanonical": true},":soccer:":{"unicode":["26bd-fe0f","26bd"],"fname":"26bd","uc":"26bd","isCanonical": true},":baseball:":{"unicode":["26be-fe0f","26be"],"fname":"26be","uc":"26be","isCanonical": true},":snowman:":{"unicode":["26c4-fe0f","26c4"],"fname":"26c4","uc":"26c4","isCanonical": true},":partly_sunny:":{"unicode":["26c5-fe0f","26c5"],"fname":"26c5","uc":"26c5","isCanonical": true},":no_entry:":{"unicode":["26d4-fe0f","26d4"],"fname":"26d4","uc":"26d4","isCanonical": true},":church:":{"unicode":["26ea-fe0f","26ea"],"fname":"26ea","uc":"26ea","isCanonical": true},":fountain:":{"unicode":["26f2-fe0f","26f2"],"fname":"26f2","uc":"26f2","isCanonical": true},":golf:":{"unicode":["26f3-fe0f","26f3"],"fname":"26f3","uc":"26f3","isCanonical": true},":sailboat:":{"unicode":["26f5-fe0f","26f5"],"fname":"26f5","uc":"26f5","isCanonical": true},":tent:":{"unicode":["26fa-fe0f","26fa"],"fname":"26fa","uc":"26fa","isCanonical": true},":fuelpump:":{"unicode":["26fd-fe0f","26fd"],"fname":"26fd","uc":"26fd","isCanonical": true},":scissors:":{"unicode":["2702-fe0f","2702"],"fname":"2702","uc":"2702","isCanonical": true},":airplane:":{"unicode":["2708-fe0f","2708"],"fname":"2708","uc":"2708","isCanonical": true},":envelope:":{"unicode":["2709-fe0f","2709"],"fname":"2709","uc":"2709","isCanonical": true},":v:":{"unicode":["270c-fe0f","270c"],"fname":"270c","uc":"270c","isCanonical": true},":pencil2:":{"unicode":["270f-fe0f","270f"],"fname":"270f","uc":"270f","isCanonical": true},":black_nib:":{"unicode":["2712-fe0f","2712"],"fname":"2712","uc":"2712","isCanonical": true},":heavy_check_mark:":{"unicode":["2714-fe0f","2714"],"fname":"2714","uc":"2714","isCanonical": true},":heavy_multiplication_x:":{"unicode":["2716-fe0f","2716"],"fname":"2716","uc":"2716","isCanonical": true},":eight_spoked_asterisk:":{"unicode":["2733-fe0f","2733"],"fname":"2733","uc":"2733","isCanonical": true},":eight_pointed_black_star:":{"unicode":["2734-fe0f","2734"],"fname":"2734","uc":"2734","isCanonical": true},":snowflake:":{"unicode":["2744-fe0f","2744"],"fname":"2744","uc":"2744","isCanonical": true},":sparkle:":{"unicode":["2747-fe0f","2747"],"fname":"2747","uc":"2747","isCanonical": true},":exclamation:":{"unicode":["2757-fe0f","2757"],"fname":"2757","uc":"2757","isCanonical": true},":heart:":{"unicode":["2764-fe0f","2764"],"fname":"2764","uc":"2764","isCanonical": true},":arrow_right:":{"unicode":["27a1-fe0f","27a1"],"fname":"27a1","uc":"27a1","isCanonical": true},":arrow_heading_up:":{"unicode":["2934-fe0f","2934"],"fname":"2934","uc":"2934","isCanonical": true},":arrow_heading_down:":{"unicode":["2935-fe0f","2935"],"fname":"2935","uc":"2935","isCanonical": true},":arrow_left:":{"unicode":["2b05-fe0f","2b05"],"fname":"2b05","uc":"2b05","isCanonical": true},":arrow_up:":{"unicode":["2b06-fe0f","2b06"],"fname":"2b06","uc":"2b06","isCanonical": true},":arrow_down:":{"unicode":["2b07-fe0f","2b07"],"fname":"2b07","uc":"2b07","isCanonical": true},":black_large_square:":{"unicode":["2b1b-fe0f","2b1b"],"fname":"2b1b","uc":"2b1b","isCanonical": true},":white_large_square:":{"unicode":["2b1c-fe0f","2b1c"],"fname":"2b1c","uc":"2b1c","isCanonical": true},":star:":{"unicode":["2b50-fe0f","2b50"],"fname":"2b50","uc":"2b50","isCanonical": true},":o:":{"unicode":["2b55-fe0f","2b55"],"fname":"2b55","uc":"2b55","isCanonical": true},":wavy_dash:":{"unicode":["3030-fe0f","3030"],"fname":"3030","uc":"3030","isCanonical": true},":part_alternation_mark:":{"unicode":["303d-fe0f","303d"],"fname":"303d","uc":"303d","isCanonical": true},":congratulations:":{"unicode":["3297-fe0f","3297"],"fname":"3297","uc":"3297","isCanonical": true},":secret:":{"unicode":["3299-fe0f","3299"],"fname":"3299","uc":"3299","isCanonical": true},":cross:":{"unicode":["271d-fe0f","271d"],"fname":"271d","uc":"271d","isCanonical": true},":latin_cross:":{"unicode":["271d-fe0f","271d"],"fname":"271d","uc":"271d","isCanonical": false},":keyboard:":{"unicode":["2328-fe0f","2328"],"fname":"2328","uc":"2328","isCanonical": true},":writing_hand:":{"unicode":["270d-fe0f","270d"],"fname":"270d","uc":"270d","isCanonical": true},":eject:":{"unicode":["23cf-fe0f","23cf"],"fname":"23cf","uc":"23cf","isCanonical": true},":eject_symbol:":{"unicode":["23cf-fe0f","23cf"],"fname":"23cf","uc":"23cf","isCanonical": false},":track_next:":{"unicode":["23ed-fe0f","23ed"],"fname":"23ed","uc":"23ed","isCanonical": true},":next_track:":{"unicode":["23ed-fe0f","23ed"],"fname":"23ed","uc":"23ed","isCanonical": false},":track_previous:":{"unicode":["23ee-fe0f","23ee"],"fname":"23ee","uc":"23ee","isCanonical": true},":previous_track:":{"unicode":["23ee-fe0f","23ee"],"fname":"23ee","uc":"23ee","isCanonical": false},":play_pause:":{"unicode":["23ef-fe0f","23ef"],"fname":"23ef","uc":"23ef","isCanonical": true},":stopwatch:":{"unicode":["23f1-fe0f","23f1"],"fname":"23f1","uc":"23f1","isCanonical": true},":timer:":{"unicode":["23f2-fe0f","23f2"],"fname":"23f2","uc":"23f2","isCanonical": true},":timer_clock:":{"unicode":["23f2-fe0f","23f2"],"fname":"23f2","uc":"23f2","isCanonical": false},":pause_button:":{"unicode":["23f8-fe0f","23f8"],"fname":"23f8","uc":"23f8","isCanonical": true},":double_vertical_bar:":{"unicode":["23f8-fe0f","23f8"],"fname":"23f8","uc":"23f8","isCanonical": false},":stop_button:":{"unicode":["23f9-fe0f","23f9"],"fname":"23f9","uc":"23f9","isCanonical": true},":record_button:":{"unicode":["23fa-fe0f","23fa"],"fname":"23fa","uc":"23fa","isCanonical": true},":umbrella2:":{"unicode":["2602-fe0f","2602"],"fname":"2602","uc":"2602","isCanonical": true},":snowman2:":{"unicode":["2603-fe0f","2603"],"fname":"2603","uc":"2603","isCanonical": true},":comet:":{"unicode":["2604-fe0f","2604"],"fname":"2604","uc":"2604","isCanonical": true},":shamrock:":{"unicode":["2618-fe0f","2618"],"fname":"2618","uc":"2618","isCanonical": true},":skull_crossbones:":{"unicode":["2620-fe0f","2620"],"fname":"2620","uc":"2620","isCanonical": true},":skull_and_crossbones:":{"unicode":["2620-fe0f","2620"],"fname":"2620","uc":"2620","isCanonical": false},":radioactive:":{"unicode":["2622-fe0f","2622"],"fname":"2622","uc":"2622","isCanonical": true},":radioactive_sign:":{"unicode":["2622-fe0f","2622"],"fname":"2622","uc":"2622","isCanonical": false},":biohazard:":{"unicode":["2623-fe0f","2623"],"fname":"2623","uc":"2623","isCanonical": true},":biohazard_sign:":{"unicode":["2623-fe0f","2623"],"fname":"2623","uc":"2623","isCanonical": false},":orthodox_cross:":{"unicode":["2626-fe0f","2626"],"fname":"2626","uc":"2626","isCanonical": true},":star_and_crescent:":{"unicode":["262a-fe0f","262a"],"fname":"262a","uc":"262a","isCanonical": true},":peace:":{"unicode":["262e-fe0f","262e"],"fname":"262e","uc":"262e","isCanonical": true},":peace_symbol:":{"unicode":["262e-fe0f","262e"],"fname":"262e","uc":"262e","isCanonical": false},":yin_yang:":{"unicode":["262f-fe0f","262f"],"fname":"262f","uc":"262f","isCanonical": true},":wheel_of_dharma:":{"unicode":["2638-fe0f","2638"],"fname":"2638","uc":"2638","isCanonical": true},":frowning2:":{"unicode":["2639-fe0f","2639"],"fname":"2639","uc":"2639","isCanonical": true},":white_frowning_face:":{"unicode":["2639-fe0f","2639"],"fname":"2639","uc":"2639","isCanonical": false},":hammer_pick:":{"unicode":["2692-fe0f","2692"],"fname":"2692","uc":"2692","isCanonical": true},":hammer_and_pick:":{"unicode":["2692-fe0f","2692"],"fname":"2692","uc":"2692","isCanonical": false},":crossed_swords:":{"unicode":["2694-fe0f","2694"],"fname":"2694","uc":"2694","isCanonical": true},":scales:":{"unicode":["2696-fe0f","2696"],"fname":"2696","uc":"2696","isCanonical": true},":alembic:":{"unicode":["2697-fe0f","2697"],"fname":"2697","uc":"2697","isCanonical": true},":gear:":{"unicode":["2699-fe0f","2699"],"fname":"2699","uc":"2699","isCanonical": true},":atom:":{"unicode":["269b-fe0f","269b"],"fname":"269b","uc":"269b","isCanonical": true},":atom_symbol:":{"unicode":["269b-fe0f","269b"],"fname":"269b","uc":"269b","isCanonical": false},":fleur-de-lis:":{"unicode":["269c-fe0f","269c"],"fname":"269c","uc":"269c","isCanonical": true},":coffin:":{"unicode":["26b0-fe0f","26b0"],"fname":"26b0","uc":"26b0","isCanonical": true},":urn:":{"unicode":["26b1-fe0f","26b1"],"fname":"26b1","uc":"26b1","isCanonical": true},":funeral_urn:":{"unicode":["26b1-fe0f","26b1"],"fname":"26b1","uc":"26b1","isCanonical": false},":thunder_cloud_rain:":{"unicode":["26c8-fe0f","26c8"],"fname":"26c8","uc":"26c8","isCanonical": true},":thunder_cloud_and_rain:":{"unicode":["26c8-fe0f","26c8"],"fname":"26c8","uc":"26c8","isCanonical": false},":pick:":{"unicode":["26cf-fe0f","26cf"],"fname":"26cf","uc":"26cf","isCanonical": true},":helmet_with_cross:":{"unicode":["26d1-fe0f","26d1"],"fname":"26d1","uc":"26d1","isCanonical": true},":helmet_with_white_cross:":{"unicode":["26d1-fe0f","26d1"],"fname":"26d1","uc":"26d1","isCanonical": false},":chains:":{"unicode":["26d3-fe0f","26d3"],"fname":"26d3","uc":"26d3","isCanonical": true},":shinto_shrine:":{"unicode":["26e9-fe0f","26e9"],"fname":"26e9","uc":"26e9","isCanonical": true},":mountain:":{"unicode":["26f0-fe0f","26f0"],"fname":"26f0","uc":"26f0","isCanonical": true},":beach_umbrella:":{"unicode":["26f1-fe0f","26f1"],"fname":"26f1","uc":"26f1","isCanonical": true},":umbrella_on_ground:":{"unicode":["26f1-fe0f","26f1"],"fname":"26f1","uc":"26f1","isCanonical": false},":ferry:":{"unicode":["26f4-fe0f","26f4"],"fname":"26f4","uc":"26f4","isCanonical": true},":skier:":{"unicode":["26f7-fe0f","26f7"],"fname":"26f7","uc":"26f7","isCanonical": true},":ice_skate:":{"unicode":["26f8-fe0f","26f8"],"fname":"26f8","uc":"26f8","isCanonical": true},":basketball_player:":{"unicode":["26f9-fe0f","26f9"],"fname":"26f9","uc":"26f9","isCanonical": true},":person_with_ball:":{"unicode":["26f9-fe0f","26f9"],"fname":"26f9","uc":"26f9","isCanonical": false},":star_of_david:":{"unicode":["2721-fe0f","2721"],"fname":"2721","uc":"2721","isCanonical": true},":heart_exclamation:":{"unicode":["2763-fe0f","2763"],"fname":"2763","uc":"2763","isCanonical": true},":heavy_heart_exclamation_mark_ornament:":{"unicode":["2763-fe0f","2763"],"fname":"2763","uc":"2763","isCanonical": false},":third_place:":{"unicode":["1f949"],"fname":"1f949","uc":"1f949","isCanonical": true},":third_place_medal:":{"unicode":["1f949"],"fname":"1f949","uc":"1f949","isCanonical": false},":second_place:":{"unicode":["1f948"],"fname":"1f948","uc":"1f948","isCanonical": true},":second_place_medal:":{"unicode":["1f948"],"fname":"1f948","uc":"1f948","isCanonical": false},":first_place:":{"unicode":["1f947"],"fname":"1f947","uc":"1f947","isCanonical": true},":first_place_medal:":{"unicode":["1f947"],"fname":"1f947","uc":"1f947","isCanonical": false},":fencer:":{"unicode":["1f93a"],"fname":"1f93a","uc":"1f93a","isCanonical": true},":fencing:":{"unicode":["1f93a"],"fname":"1f93a","uc":"1f93a","isCanonical": false},":goal:":{"unicode":["1f945"],"fname":"1f945","uc":"1f945","isCanonical": true},":goal_net:":{"unicode":["1f945"],"fname":"1f945","uc":"1f945","isCanonical": false},":handball:":{"unicode":["1f93e"],"fname":"1f93e","uc":"1f93e","isCanonical": true},":regional_indicator_z:":{"unicode":["1f1ff"],"fname":"1f1ff","uc":"1f1ff","isCanonical": true},":water_polo:":{"unicode":["1f93d"],"fname":"1f93d","uc":"1f93d","isCanonical": true},":martial_arts_uniform:":{"unicode":["1f94b"],"fname":"1f94b","uc":"1f94b","isCanonical": true},":karate_uniform:":{"unicode":["1f94b"],"fname":"1f94b","uc":"1f94b","isCanonical": false},":boxing_glove:":{"unicode":["1f94a"],"fname":"1f94a","uc":"1f94a","isCanonical": true},":boxing_gloves:":{"unicode":["1f94a"],"fname":"1f94a","uc":"1f94a","isCanonical": false},":wrestlers:":{"unicode":["1f93c"],"fname":"1f93c","uc":"1f93c","isCanonical": true},":wrestling:":{"unicode":["1f93c"],"fname":"1f93c","uc":"1f93c","isCanonical": false},":juggling:":{"unicode":["1f939"],"fname":"1f939","uc":"1f939","isCanonical": true},":juggler:":{"unicode":["1f939"],"fname":"1f939","uc":"1f939","isCanonical": false},":cartwheel:":{"unicode":["1f938"],"fname":"1f938","uc":"1f938","isCanonical": true},":person_doing_cartwheel:":{"unicode":["1f938"],"fname":"1f938","uc":"1f938","isCanonical": false},":canoe:":{"unicode":["1f6f6"],"fname":"1f6f6","uc":"1f6f6","isCanonical": true},":kayak:":{"unicode":["1f6f6"],"fname":"1f6f6","uc":"1f6f6","isCanonical": false},":motor_scooter:":{"unicode":["1f6f5"],"fname":"1f6f5","uc":"1f6f5","isCanonical": true},":motorbike:":{"unicode":["1f6f5"],"fname":"1f6f5","uc":"1f6f5","isCanonical": false},":scooter:":{"unicode":["1f6f4"],"fname":"1f6f4","uc":"1f6f4","isCanonical": true},":shopping_cart:":{"unicode":["1f6d2"],"fname":"1f6d2","uc":"1f6d2","isCanonical": true},":shopping_trolley:":{"unicode":["1f6d2"],"fname":"1f6d2","uc":"1f6d2","isCanonical": false},":black_joker:":{"unicode":["1f0cf"],"fname":"1f0cf","uc":"1f0cf","isCanonical": true},":a:":{"unicode":["1f170"],"fname":"1f170","uc":"1f170","isCanonical": true},":b:":{"unicode":["1f171"],"fname":"1f171","uc":"1f171","isCanonical": true},":o2:":{"unicode":["1f17e"],"fname":"1f17e","uc":"1f17e","isCanonical": true},":octagonal_sign:":{"unicode":["1f6d1"],"fname":"1f6d1","uc":"1f6d1","isCanonical": true},":stop_sign:":{"unicode":["1f6d1"],"fname":"1f6d1","uc":"1f6d1","isCanonical": false},":ab:":{"unicode":["1f18e"],"fname":"1f18e","uc":"1f18e","isCanonical": true},":cl:":{"unicode":["1f191"],"fname":"1f191","uc":"1f191","isCanonical": true},":regional_indicator_y:":{"unicode":["1f1fe"],"fname":"1f1fe","uc":"1f1fe","isCanonical": true},":cool:":{"unicode":["1f192"],"fname":"1f192","uc":"1f192","isCanonical": true},":free:":{"unicode":["1f193"],"fname":"1f193","uc":"1f193","isCanonical": true},":id:":{"unicode":["1f194"],"fname":"1f194","uc":"1f194","isCanonical": true},":new:":{"unicode":["1f195"],"fname":"1f195","uc":"1f195","isCanonical": true},":ng:":{"unicode":["1f196"],"fname":"1f196","uc":"1f196","isCanonical": true},":ok:":{"unicode":["1f197"],"fname":"1f197","uc":"1f197","isCanonical": true},":sos:":{"unicode":["1f198"],"fname":"1f198","uc":"1f198","isCanonical": true},":spoon:":{"unicode":["1f944"],"fname":"1f944","uc":"1f944","isCanonical": true},":up:":{"unicode":["1f199"],"fname":"1f199","uc":"1f199","isCanonical": true},":vs:":{"unicode":["1f19a"],"fname":"1f19a","uc":"1f19a","isCanonical": true},":champagne_glass:":{"unicode":["1f942"],"fname":"1f942","uc":"1f942","isCanonical": true},":clinking_glass:":{"unicode":["1f942"],"fname":"1f942","uc":"1f942","isCanonical": false},":tumbler_glass:":{"unicode":["1f943"],"fname":"1f943","uc":"1f943","isCanonical": true},":whisky:":{"unicode":["1f943"],"fname":"1f943","uc":"1f943","isCanonical": false},":koko:":{"unicode":["1f201"],"fname":"1f201","uc":"1f201","isCanonical": true},":stuffed_flatbread:":{"unicode":["1f959"],"fname":"1f959","uc":"1f959","isCanonical": true},":stuffed_pita:":{"unicode":["1f959"],"fname":"1f959","uc":"1f959","isCanonical": false},":u7981:":{"unicode":["1f232"],"fname":"1f232","uc":"1f232","isCanonical": true},":u7a7a:":{"unicode":["1f233"],"fname":"1f233","uc":"1f233","isCanonical": true},":u5408:":{"unicode":["1f234"],"fname":"1f234","uc":"1f234","isCanonical": true},":u6e80:":{"unicode":["1f235"],"fname":"1f235","uc":"1f235","isCanonical": true},":u6709:":{"unicode":["1f236"],"fname":"1f236","uc":"1f236","isCanonical": true},":shallow_pan_of_food:":{"unicode":["1f958"],"fname":"1f958","uc":"1f958","isCanonical": true},":paella:":{"unicode":["1f958"],"fname":"1f958","uc":"1f958","isCanonical": false},":u7533:":{"unicode":["1f238"],"fname":"1f238","uc":"1f238","isCanonical": true},":u5272:":{"unicode":["1f239"],"fname":"1f239","uc":"1f239","isCanonical": true},":salad:":{"unicode":["1f957"],"fname":"1f957","uc":"1f957","isCanonical": true},":green_salad:":{"unicode":["1f957"],"fname":"1f957","uc":"1f957","isCanonical": false},":u55b6:":{"unicode":["1f23a"],"fname":"1f23a","uc":"1f23a","isCanonical": true},":ideograph_advantage:":{"unicode":["1f250"],"fname":"1f250","uc":"1f250","isCanonical": true},":accept:":{"unicode":["1f251"],"fname":"1f251","uc":"1f251","isCanonical": true},":cyclone:":{"unicode":["1f300"],"fname":"1f300","uc":"1f300","isCanonical": true},":french_bread:":{"unicode":["1f956"],"fname":"1f956","uc":"1f956","isCanonical": true},":baguette_bread:":{"unicode":["1f956"],"fname":"1f956","uc":"1f956","isCanonical": false},":foggy:":{"unicode":["1f301"],"fname":"1f301","uc":"1f301","isCanonical": true},":closed_umbrella:":{"unicode":["1f302"],"fname":"1f302","uc":"1f302","isCanonical": true},":night_with_stars:":{"unicode":["1f303"],"fname":"1f303","uc":"1f303","isCanonical": true},":sunrise_over_mountains:":{"unicode":["1f304"],"fname":"1f304","uc":"1f304","isCanonical": true},":sunrise:":{"unicode":["1f305"],"fname":"1f305","uc":"1f305","isCanonical": true},":city_dusk:":{"unicode":["1f306"],"fname":"1f306","uc":"1f306","isCanonical": true},":carrot:":{"unicode":["1f955"],"fname":"1f955","uc":"1f955","isCanonical": true},":city_sunset:":{"unicode":["1f307"],"fname":"1f307","uc":"1f307","isCanonical": true},":city_sunrise:":{"unicode":["1f307"],"fname":"1f307","uc":"1f307","isCanonical": false},":rainbow:":{"unicode":["1f308"],"fname":"1f308","uc":"1f308","isCanonical": true},":potato:":{"unicode":["1f954"],"fname":"1f954","uc":"1f954","isCanonical": true},":bridge_at_night:":{"unicode":["1f309"],"fname":"1f309","uc":"1f309","isCanonical": true},":ocean:":{"unicode":["1f30a"],"fname":"1f30a","uc":"1f30a","isCanonical": true},":volcano:":{"unicode":["1f30b"],"fname":"1f30b","uc":"1f30b","isCanonical": true},":milky_way:":{"unicode":["1f30c"],"fname":"1f30c","uc":"1f30c","isCanonical": true},":earth_asia:":{"unicode":["1f30f"],"fname":"1f30f","uc":"1f30f","isCanonical": true},":new_moon:":{"unicode":["1f311"],"fname":"1f311","uc":"1f311","isCanonical": true},":bacon:":{"unicode":["1f953"],"fname":"1f953","uc":"1f953","isCanonical": true},":first_quarter_moon:":{"unicode":["1f313"],"fname":"1f313","uc":"1f313","isCanonical": true},":waxing_gibbous_moon:":{"unicode":["1f314"],"fname":"1f314","uc":"1f314","isCanonical": true},":full_moon:":{"unicode":["1f315"],"fname":"1f315","uc":"1f315","isCanonical": true},":crescent_moon:":{"unicode":["1f319"],"fname":"1f319","uc":"1f319","isCanonical": true},":first_quarter_moon_with_face:":{"unicode":["1f31b"],"fname":"1f31b","uc":"1f31b","isCanonical": true},":star2:":{"unicode":["1f31f"],"fname":"1f31f","uc":"1f31f","isCanonical": true},":cucumber:":{"unicode":["1f952"],"fname":"1f952","uc":"1f952","isCanonical": true},":stars:":{"unicode":["1f320"],"fname":"1f320","uc":"1f320","isCanonical": true},":chestnut:":{"unicode":["1f330"],"fname":"1f330","uc":"1f330","isCanonical": true},":avocado:":{"unicode":["1f951"],"fname":"1f951","uc":"1f951","isCanonical": true},":seedling:":{"unicode":["1f331"],"fname":"1f331","uc":"1f331","isCanonical": true},":palm_tree:":{"unicode":["1f334"],"fname":"1f334","uc":"1f334","isCanonical": true},":cactus:":{"unicode":["1f335"],"fname":"1f335","uc":"1f335","isCanonical": true},":tulip:":{"unicode":["1f337"],"fname":"1f337","uc":"1f337","isCanonical": true},":cherry_blossom:":{"unicode":["1f338"],"fname":"1f338","uc":"1f338","isCanonical": true},":rose:":{"unicode":["1f339"],"fname":"1f339","uc":"1f339","isCanonical": true},":hibiscus:":{"unicode":["1f33a"],"fname":"1f33a","uc":"1f33a","isCanonical": true},":sunflower:":{"unicode":["1f33b"],"fname":"1f33b","uc":"1f33b","isCanonical": true},":blossom:":{"unicode":["1f33c"],"fname":"1f33c","uc":"1f33c","isCanonical": true},":corn:":{"unicode":["1f33d"],"fname":"1f33d","uc":"1f33d","isCanonical": true},":croissant:":{"unicode":["1f950"],"fname":"1f950","uc":"1f950","isCanonical": true},":ear_of_rice:":{"unicode":["1f33e"],"fname":"1f33e","uc":"1f33e","isCanonical": true},":herb:":{"unicode":["1f33f"],"fname":"1f33f","uc":"1f33f","isCanonical": true},":four_leaf_clover:":{"unicode":["1f340"],"fname":"1f340","uc":"1f340","isCanonical": true},":maple_leaf:":{"unicode":["1f341"],"fname":"1f341","uc":"1f341","isCanonical": true},":fallen_leaf:":{"unicode":["1f342"],"fname":"1f342","uc":"1f342","isCanonical": true},":leaves:":{"unicode":["1f343"],"fname":"1f343","uc":"1f343","isCanonical": true},":mushroom:":{"unicode":["1f344"],"fname":"1f344","uc":"1f344","isCanonical": true},":tomato:":{"unicode":["1f345"],"fname":"1f345","uc":"1f345","isCanonical": true},":eggplant:":{"unicode":["1f346"],"fname":"1f346","uc":"1f346","isCanonical": true},":grapes:":{"unicode":["1f347"],"fname":"1f347","uc":"1f347","isCanonical": true},":melon:":{"unicode":["1f348"],"fname":"1f348","uc":"1f348","isCanonical": true},":watermelon:":{"unicode":["1f349"],"fname":"1f349","uc":"1f349","isCanonical": true},":tangerine:":{"unicode":["1f34a"],"fname":"1f34a","uc":"1f34a","isCanonical": true},":wilted_rose:":{"unicode":["1f940"],"fname":"1f940","uc":"1f940","isCanonical": true},":wilted_flower:":{"unicode":["1f940"],"fname":"1f940","uc":"1f940","isCanonical": false},":banana:":{"unicode":["1f34c"],"fname":"1f34c","uc":"1f34c","isCanonical": true},":pineapple:":{"unicode":["1f34d"],"fname":"1f34d","uc":"1f34d","isCanonical": true},":apple:":{"unicode":["1f34e"],"fname":"1f34e","uc":"1f34e","isCanonical": true},":green_apple:":{"unicode":["1f34f"],"fname":"1f34f","uc":"1f34f","isCanonical": true},":peach:":{"unicode":["1f351"],"fname":"1f351","uc":"1f351","isCanonical": true},":cherries:":{"unicode":["1f352"],"fname":"1f352","uc":"1f352","isCanonical": true},":strawberry:":{"unicode":["1f353"],"fname":"1f353","uc":"1f353","isCanonical": true},":rhino:":{"unicode":["1f98f"],"fname":"1f98f","uc":"1f98f","isCanonical": true},":rhinoceros:":{"unicode":["1f98f"],"fname":"1f98f","uc":"1f98f","isCanonical": false},":hamburger:":{"unicode":["1f354"],"fname":"1f354","uc":"1f354","isCanonical": true},":pizza:":{"unicode":["1f355"],"fname":"1f355","uc":"1f355","isCanonical": true},":meat_on_bone:":{"unicode":["1f356"],"fname":"1f356","uc":"1f356","isCanonical": true},":lizard:":{"unicode":["1f98e"],"fname":"1f98e","uc":"1f98e","isCanonical": true},":poultry_leg:":{"unicode":["1f357"],"fname":"1f357","uc":"1f357","isCanonical": true},":rice_cracker:":{"unicode":["1f358"],"fname":"1f358","uc":"1f358","isCanonical": true},":rice_ball:":{"unicode":["1f359"],"fname":"1f359","uc":"1f359","isCanonical": true},":gorilla:":{"unicode":["1f98d"],"fname":"1f98d","uc":"1f98d","isCanonical": true},":rice:":{"unicode":["1f35a"],"fname":"1f35a","uc":"1f35a","isCanonical": true},":curry:":{"unicode":["1f35b"],"fname":"1f35b","uc":"1f35b","isCanonical": true},":deer:":{"unicode":["1f98c"],"fname":"1f98c","uc":"1f98c","isCanonical": true},":ramen:":{"unicode":["1f35c"],"fname":"1f35c","uc":"1f35c","isCanonical": true},":spaghetti:":{"unicode":["1f35d"],"fname":"1f35d","uc":"1f35d","isCanonical": true},":bread:":{"unicode":["1f35e"],"fname":"1f35e","uc":"1f35e","isCanonical": true},":fries:":{"unicode":["1f35f"],"fname":"1f35f","uc":"1f35f","isCanonical": true},":butterfly:":{"unicode":["1f98b"],"fname":"1f98b","uc":"1f98b","isCanonical": true},":sweet_potato:":{"unicode":["1f360"],"fname":"1f360","uc":"1f360","isCanonical": true},":dango:":{"unicode":["1f361"],"fname":"1f361","uc":"1f361","isCanonical": true},":fox:":{"unicode":["1f98a"],"fname":"1f98a","uc":"1f98a","isCanonical": true},":fox_face:":{"unicode":["1f98a"],"fname":"1f98a","uc":"1f98a","isCanonical": false},":oden:":{"unicode":["1f362"],"fname":"1f362","uc":"1f362","isCanonical": true},":sushi:":{"unicode":["1f363"],"fname":"1f363","uc":"1f363","isCanonical": true},":owl:":{"unicode":["1f989"],"fname":"1f989","uc":"1f989","isCanonical": true},":fried_shrimp:":{"unicode":["1f364"],"fname":"1f364","uc":"1f364","isCanonical": true},":fish_cake:":{"unicode":["1f365"],"fname":"1f365","uc":"1f365","isCanonical": true},":shark:":{"unicode":["1f988"],"fname":"1f988","uc":"1f988","isCanonical": true},":icecream:":{"unicode":["1f366"],"fname":"1f366","uc":"1f366","isCanonical": true},":bat:":{"unicode":["1f987"],"fname":"1f987","uc":"1f987","isCanonical": true},":shaved_ice:":{"unicode":["1f367"],"fname":"1f367","uc":"1f367","isCanonical": true},":regional_indicator_x:":{"unicode":["1f1fd"],"fname":"1f1fd","uc":"1f1fd","isCanonical": true},":ice_cream:":{"unicode":["1f368"],"fname":"1f368","uc":"1f368","isCanonical": true},":duck:":{"unicode":["1f986"],"fname":"1f986","uc":"1f986","isCanonical": true},":doughnut:":{"unicode":["1f369"],"fname":"1f369","uc":"1f369","isCanonical": true},":eagle:":{"unicode":["1f985"],"fname":"1f985","uc":"1f985","isCanonical": true},":cookie:":{"unicode":["1f36a"],"fname":"1f36a","uc":"1f36a","isCanonical": true},":black_heart:":{"unicode":["1f5a4"],"fname":"1f5a4","uc":"1f5a4","isCanonical": true},":chocolate_bar:":{"unicode":["1f36b"],"fname":"1f36b","uc":"1f36b","isCanonical": true},":candy:":{"unicode":["1f36c"],"fname":"1f36c","uc":"1f36c","isCanonical": true},":lollipop:":{"unicode":["1f36d"],"fname":"1f36d","uc":"1f36d","isCanonical": true},":custard:":{"unicode":["1f36e"],"fname":"1f36e","uc":"1f36e","isCanonical": true},":pudding:":{"unicode":["1f36e"],"fname":"1f36e","uc":"1f36e","isCanonical": false},":flan:":{"unicode":["1f36e"],"fname":"1f36e","uc":"1f36e","isCanonical": false},":honey_pot:":{"unicode":["1f36f"],"fname":"1f36f","uc":"1f36f","isCanonical": true},":fingers_crossed:":{"unicode":["1f91e"],"fname":"1f91e","uc":"1f91e","isCanonical": true},":hand_with_index_and_middle_finger_crossed:":{"unicode":["1f91e"],"fname":"1f91e","uc":"1f91e","isCanonical": false},":cake:":{"unicode":["1f370"],"fname":"1f370","uc":"1f370","isCanonical": true},":bento:":{"unicode":["1f371"],"fname":"1f371","uc":"1f371","isCanonical": true},":stew:":{"unicode":["1f372"],"fname":"1f372","uc":"1f372","isCanonical": true},":handshake:":{"unicode":["1f91d"],"fname":"1f91d","uc":"1f91d","isCanonical": true},":shaking_hands:":{"unicode":["1f91d"],"fname":"1f91d","uc":"1f91d","isCanonical": false},":cooking:":{"unicode":["1f373"],"fname":"1f373","uc":"1f373","isCanonical": true},":fork_and_knife:":{"unicode":["1f374"],"fname":"1f374","uc":"1f374","isCanonical": true},":tea:":{"unicode":["1f375"],"fname":"1f375","uc":"1f375","isCanonical": true},":sake:":{"unicode":["1f376"],"fname":"1f376","uc":"1f376","isCanonical": true},":wine_glass:":{"unicode":["1f377"],"fname":"1f377","uc":"1f377","isCanonical": true},":cocktail:":{"unicode":["1f378"],"fname":"1f378","uc":"1f378","isCanonical": true},":tropical_drink:":{"unicode":["1f379"],"fname":"1f379","uc":"1f379","isCanonical": true},":beer:":{"unicode":["1f37a"],"fname":"1f37a","uc":"1f37a","isCanonical": true},":beers:":{"unicode":["1f37b"],"fname":"1f37b","uc":"1f37b","isCanonical": true},":ribbon:":{"unicode":["1f380"],"fname":"1f380","uc":"1f380","isCanonical": true},":gift:":{"unicode":["1f381"],"fname":"1f381","uc":"1f381","isCanonical": true},":birthday:":{"unicode":["1f382"],"fname":"1f382","uc":"1f382","isCanonical": true},":jack_o_lantern:":{"unicode":["1f383"],"fname":"1f383","uc":"1f383","isCanonical": true},":left_facing_fist:":{"unicode":["1f91b"],"fname":"1f91b","uc":"1f91b","isCanonical": true},":left_fist:":{"unicode":["1f91b"],"fname":"1f91b","uc":"1f91b","isCanonical": false},":right_facing_fist:":{"unicode":["1f91c"],"fname":"1f91c","uc":"1f91c","isCanonical": true},":right_fist:":{"unicode":["1f91c"],"fname":"1f91c","uc":"1f91c","isCanonical": false},":christmas_tree:":{"unicode":["1f384"],"fname":"1f384","uc":"1f384","isCanonical": true},":santa:":{"unicode":["1f385"],"fname":"1f385","uc":"1f385","isCanonical": true},":fireworks:":{"unicode":["1f386"],"fname":"1f386","uc":"1f386","isCanonical": true},":raised_back_of_hand:":{"unicode":["1f91a"],"fname":"1f91a","uc":"1f91a","isCanonical": true},":back_of_hand:":{"unicode":["1f91a"],"fname":"1f91a","uc":"1f91a","isCanonical": false},":sparkler:":{"unicode":["1f387"],"fname":"1f387","uc":"1f387","isCanonical": true},":balloon:":{"unicode":["1f388"],"fname":"1f388","uc":"1f388","isCanonical": true},":tada:":{"unicode":["1f389"],"fname":"1f389","uc":"1f389","isCanonical": true},":confetti_ball:":{"unicode":["1f38a"],"fname":"1f38a","uc":"1f38a","isCanonical": true},":tanabata_tree:":{"unicode":["1f38b"],"fname":"1f38b","uc":"1f38b","isCanonical": true},":crossed_flags:":{"unicode":["1f38c"],"fname":"1f38c","uc":"1f38c","isCanonical": true},":call_me:":{"unicode":["1f919"],"fname":"1f919","uc":"1f919","isCanonical": true},":call_me_hand:":{"unicode":["1f919"],"fname":"1f919","uc":"1f919","isCanonical": false},":bamboo:":{"unicode":["1f38d"],"fname":"1f38d","uc":"1f38d","isCanonical": true},":man_dancing:":{"unicode":["1f57a"],"fname":"1f57a","uc":"1f57a","isCanonical": true},":male_dancer:":{"unicode":["1f57a"],"fname":"1f57a","uc":"1f57a","isCanonical": false},":dolls:":{"unicode":["1f38e"],"fname":"1f38e","uc":"1f38e","isCanonical": true},":selfie:":{"unicode":["1f933"],"fname":"1f933","uc":"1f933","isCanonical": true},":flags:":{"unicode":["1f38f"],"fname":"1f38f","uc":"1f38f","isCanonical": true},":pregnant_woman:":{"unicode":["1f930"],"fname":"1f930","uc":"1f930","isCanonical": true},":expecting_woman:":{"unicode":["1f930"],"fname":"1f930","uc":"1f930","isCanonical": false},":wind_chime:":{"unicode":["1f390"],"fname":"1f390","uc":"1f390","isCanonical": true},":face_palm:":{"unicode":["1f926"],"fname":"1f926","uc":"1f926","isCanonical": true},":facepalm:":{"unicode":["1f926"],"fname":"1f926","uc":"1f926","isCanonical": false},":shrug:":{"unicode":["1f937"],"fname":"1f937","uc":"1f937","isCanonical": true},":rice_scene:":{"unicode":["1f391"],"fname":"1f391","uc":"1f391","isCanonical": true},":school_satchel:":{"unicode":["1f392"],"fname":"1f392","uc":"1f392","isCanonical": true},":mortar_board:":{"unicode":["1f393"],"fname":"1f393","uc":"1f393","isCanonical": true},":carousel_horse:":{"unicode":["1f3a0"],"fname":"1f3a0","uc":"1f3a0","isCanonical": true},":ferris_wheel:":{"unicode":["1f3a1"],"fname":"1f3a1","uc":"1f3a1","isCanonical": true},":roller_coaster:":{"unicode":["1f3a2"],"fname":"1f3a2","uc":"1f3a2","isCanonical": true},":fishing_pole_and_fish:":{"unicode":["1f3a3"],"fname":"1f3a3","uc":"1f3a3","isCanonical": true},":microphone:":{"unicode":["1f3a4"],"fname":"1f3a4","uc":"1f3a4","isCanonical": true},":movie_camera:":{"unicode":["1f3a5"],"fname":"1f3a5","uc":"1f3a5","isCanonical": true},":cinema:":{"unicode":["1f3a6"],"fname":"1f3a6","uc":"1f3a6","isCanonical": true},":headphones:":{"unicode":["1f3a7"],"fname":"1f3a7","uc":"1f3a7","isCanonical": true},":mrs_claus:":{"unicode":["1f936"],"fname":"1f936","uc":"1f936","isCanonical": true},":mother_christmas:":{"unicode":["1f936"],"fname":"1f936","uc":"1f936","isCanonical": false},":art:":{"unicode":["1f3a8"],"fname":"1f3a8","uc":"1f3a8","isCanonical": true},":man_in_tuxedo:":{"unicode":["1f935"],"fname":"1f935","uc":"1f935","isCanonical": true},":tophat:":{"unicode":["1f3a9"],"fname":"1f3a9","uc":"1f3a9","isCanonical": true},":circus_tent:":{"unicode":["1f3aa"],"fname":"1f3aa","uc":"1f3aa","isCanonical": true},":prince:":{"unicode":["1f934"],"fname":"1f934","uc":"1f934","isCanonical": true},":ticket:":{"unicode":["1f3ab"],"fname":"1f3ab","uc":"1f3ab","isCanonical": true},":clapper:":{"unicode":["1f3ac"],"fname":"1f3ac","uc":"1f3ac","isCanonical": true},":performing_arts:":{"unicode":["1f3ad"],"fname":"1f3ad","uc":"1f3ad","isCanonical": true},":sneezing_face:":{"unicode":["1f927"],"fname":"1f927","uc":"1f927","isCanonical": true},":sneeze:":{"unicode":["1f927"],"fname":"1f927","uc":"1f927","isCanonical": false},":video_game:":{"unicode":["1f3ae"],"fname":"1f3ae","uc":"1f3ae","isCanonical": true},":dart:":{"unicode":["1f3af"],"fname":"1f3af","uc":"1f3af","isCanonical": true},":slot_machine:":{"unicode":["1f3b0"],"fname":"1f3b0","uc":"1f3b0","isCanonical": true},":8ball:":{"unicode":["1f3b1"],"fname":"1f3b1","uc":"1f3b1","isCanonical": true},":game_die:":{"unicode":["1f3b2"],"fname":"1f3b2","uc":"1f3b2","isCanonical": true},":bowling:":{"unicode":["1f3b3"],"fname":"1f3b3","uc":"1f3b3","isCanonical": true},":flower_playing_cards:":{"unicode":["1f3b4"],"fname":"1f3b4","uc":"1f3b4","isCanonical": true},":lying_face:":{"unicode":["1f925"],"fname":"1f925","uc":"1f925","isCanonical": true},":liar:":{"unicode":["1f925"],"fname":"1f925","uc":"1f925","isCanonical": false},":musical_note:":{"unicode":["1f3b5"],"fname":"1f3b5","uc":"1f3b5","isCanonical": true},":notes:":{"unicode":["1f3b6"],"fname":"1f3b6","uc":"1f3b6","isCanonical": true},":saxophone:":{"unicode":["1f3b7"],"fname":"1f3b7","uc":"1f3b7","isCanonical": true},":drooling_face:":{"unicode":["1f924"],"fname":"1f924","uc":"1f924","isCanonical": true},":drool:":{"unicode":["1f924"],"fname":"1f924","uc":"1f924","isCanonical": false},":guitar:":{"unicode":["1f3b8"],"fname":"1f3b8","uc":"1f3b8","isCanonical": true},":musical_keyboard:":{"unicode":["1f3b9"],"fname":"1f3b9","uc":"1f3b9","isCanonical": true},":trumpet:":{"unicode":["1f3ba"],"fname":"1f3ba","uc":"1f3ba","isCanonical": true},":rofl:":{"unicode":["1f923"],"fname":"1f923","uc":"1f923","isCanonical": true},":rolling_on_the_floor_laughing:":{"unicode":["1f923"],"fname":"1f923","uc":"1f923","isCanonical": false},":violin:":{"unicode":["1f3bb"],"fname":"1f3bb","uc":"1f3bb","isCanonical": true},":musical_score:":{"unicode":["1f3bc"],"fname":"1f3bc","uc":"1f3bc","isCanonical": true},":running_shirt_with_sash:":{"unicode":["1f3bd"],"fname":"1f3bd","uc":"1f3bd","isCanonical": true},":nauseated_face:":{"unicode":["1f922"],"fname":"1f922","uc":"1f922","isCanonical": true},":sick:":{"unicode":["1f922"],"fname":"1f922","uc":"1f922","isCanonical": false},":tennis:":{"unicode":["1f3be"],"fname":"1f3be","uc":"1f3be","isCanonical": true},":ski:":{"unicode":["1f3bf"],"fname":"1f3bf","uc":"1f3bf","isCanonical": true},":basketball:":{"unicode":["1f3c0"],"fname":"1f3c0","uc":"1f3c0","isCanonical": true},":checkered_flag:":{"unicode":["1f3c1"],"fname":"1f3c1","uc":"1f3c1","isCanonical": true},":clown:":{"unicode":["1f921"],"fname":"1f921","uc":"1f921","isCanonical": true},":clown_face:":{"unicode":["1f921"],"fname":"1f921","uc":"1f921","isCanonical": false},":snowboarder:":{"unicode":["1f3c2"],"fname":"1f3c2","uc":"1f3c2","isCanonical": true},":runner:":{"unicode":["1f3c3"],"fname":"1f3c3","uc":"1f3c3","isCanonical": true},":surfer:":{"unicode":["1f3c4"],"fname":"1f3c4","uc":"1f3c4","isCanonical": true},":trophy:":{"unicode":["1f3c6"],"fname":"1f3c6","uc":"1f3c6","isCanonical": true},":football:":{"unicode":["1f3c8"],"fname":"1f3c8","uc":"1f3c8","isCanonical": true},":swimmer:":{"unicode":["1f3ca"],"fname":"1f3ca","uc":"1f3ca","isCanonical": true},":house:":{"unicode":["1f3e0"],"fname":"1f3e0","uc":"1f3e0","isCanonical": true},":house_with_garden:":{"unicode":["1f3e1"],"fname":"1f3e1","uc":"1f3e1","isCanonical": true},":office:":{"unicode":["1f3e2"],"fname":"1f3e2","uc":"1f3e2","isCanonical": true},":post_office:":{"unicode":["1f3e3"],"fname":"1f3e3","uc":"1f3e3","isCanonical": true},":hospital:":{"unicode":["1f3e5"],"fname":"1f3e5","uc":"1f3e5","isCanonical": true},":bank:":{"unicode":["1f3e6"],"fname":"1f3e6","uc":"1f3e6","isCanonical": true},":atm:":{"unicode":["1f3e7"],"fname":"1f3e7","uc":"1f3e7","isCanonical": true},":hotel:":{"unicode":["1f3e8"],"fname":"1f3e8","uc":"1f3e8","isCanonical": true},":love_hotel:":{"unicode":["1f3e9"],"fname":"1f3e9","uc":"1f3e9","isCanonical": true},":convenience_store:":{"unicode":["1f3ea"],"fname":"1f3ea","uc":"1f3ea","isCanonical": true},":school:":{"unicode":["1f3eb"],"fname":"1f3eb","uc":"1f3eb","isCanonical": true},":department_store:":{"unicode":["1f3ec"],"fname":"1f3ec","uc":"1f3ec","isCanonical": true},":cowboy:":{"unicode":["1f920"],"fname":"1f920","uc":"1f920","isCanonical": true},":face_with_cowboy_hat:":{"unicode":["1f920"],"fname":"1f920","uc":"1f920","isCanonical": false},":factory:":{"unicode":["1f3ed"],"fname":"1f3ed","uc":"1f3ed","isCanonical": true},":izakaya_lantern:":{"unicode":["1f3ee"],"fname":"1f3ee","uc":"1f3ee","isCanonical": true},":japanese_castle:":{"unicode":["1f3ef"],"fname":"1f3ef","uc":"1f3ef","isCanonical": true},":european_castle:":{"unicode":["1f3f0"],"fname":"1f3f0","uc":"1f3f0","isCanonical": true},":snail:":{"unicode":["1f40c"],"fname":"1f40c","uc":"1f40c","isCanonical": true},":snake:":{"unicode":["1f40d"],"fname":"1f40d","uc":"1f40d","isCanonical": true},":racehorse:":{"unicode":["1f40e"],"fname":"1f40e","uc":"1f40e","isCanonical": true},":sheep:":{"unicode":["1f411"],"fname":"1f411","uc":"1f411","isCanonical": true},":monkey:":{"unicode":["1f412"],"fname":"1f412","uc":"1f412","isCanonical": true},":chicken:":{"unicode":["1f414"],"fname":"1f414","uc":"1f414","isCanonical": true},":boar:":{"unicode":["1f417"],"fname":"1f417","uc":"1f417","isCanonical": true},":elephant:":{"unicode":["1f418"],"fname":"1f418","uc":"1f418","isCanonical": true},":octopus:":{"unicode":["1f419"],"fname":"1f419","uc":"1f419","isCanonical": true},":shell:":{"unicode":["1f41a"],"fname":"1f41a","uc":"1f41a","isCanonical": true},":bug:":{"unicode":["1f41b"],"fname":"1f41b","uc":"1f41b","isCanonical": true},":ant:":{"unicode":["1f41c"],"fname":"1f41c","uc":"1f41c","isCanonical": true},":bee:":{"unicode":["1f41d"],"fname":"1f41d","uc":"1f41d","isCanonical": true},":beetle:":{"unicode":["1f41e"],"fname":"1f41e","uc":"1f41e","isCanonical": true},":fish:":{"unicode":["1f41f"],"fname":"1f41f","uc":"1f41f","isCanonical": true},":tropical_fish:":{"unicode":["1f420"],"fname":"1f420","uc":"1f420","isCanonical": true},":blowfish:":{"unicode":["1f421"],"fname":"1f421","uc":"1f421","isCanonical": true},":turtle:":{"unicode":["1f422"],"fname":"1f422","uc":"1f422","isCanonical": true},":hatching_chick:":{"unicode":["1f423"],"fname":"1f423","uc":"1f423","isCanonical": true},":baby_chick:":{"unicode":["1f424"],"fname":"1f424","uc":"1f424","isCanonical": true},":hatched_chick:":{"unicode":["1f425"],"fname":"1f425","uc":"1f425","isCanonical": true},":bird:":{"unicode":["1f426"],"fname":"1f426","uc":"1f426","isCanonical": true},":penguin:":{"unicode":["1f427"],"fname":"1f427","uc":"1f427","isCanonical": true},":koala:":{"unicode":["1f428"],"fname":"1f428","uc":"1f428","isCanonical": true},":poodle:":{"unicode":["1f429"],"fname":"1f429","uc":"1f429","isCanonical": true},":camel:":{"unicode":["1f42b"],"fname":"1f42b","uc":"1f42b","isCanonical": true},":dolphin:":{"unicode":["1f42c"],"fname":"1f42c","uc":"1f42c","isCanonical": true},":mouse:":{"unicode":["1f42d"],"fname":"1f42d","uc":"1f42d","isCanonical": true},":cow:":{"unicode":["1f42e"],"fname":"1f42e","uc":"1f42e","isCanonical": true},":tiger:":{"unicode":["1f42f"],"fname":"1f42f","uc":"1f42f","isCanonical": true},":rabbit:":{"unicode":["1f430"],"fname":"1f430","uc":"1f430","isCanonical": true},":cat:":{"unicode":["1f431"],"fname":"1f431","uc":"1f431","isCanonical": true},":dragon_face:":{"unicode":["1f432"],"fname":"1f432","uc":"1f432","isCanonical": true},":whale:":{"unicode":["1f433"],"fname":"1f433","uc":"1f433","isCanonical": true},":horse:":{"unicode":["1f434"],"fname":"1f434","uc":"1f434","isCanonical": true},":monkey_face:":{"unicode":["1f435"],"fname":"1f435","uc":"1f435","isCanonical": true},":dog:":{"unicode":["1f436"],"fname":"1f436","uc":"1f436","isCanonical": true},":pig:":{"unicode":["1f437"],"fname":"1f437","uc":"1f437","isCanonical": true},":frog:":{"unicode":["1f438"],"fname":"1f438","uc":"1f438","isCanonical": true},":hamster:":{"unicode":["1f439"],"fname":"1f439","uc":"1f439","isCanonical": true},":wolf:":{"unicode":["1f43a"],"fname":"1f43a","uc":"1f43a","isCanonical": true},":bear:":{"unicode":["1f43b"],"fname":"1f43b","uc":"1f43b","isCanonical": true},":panda_face:":{"unicode":["1f43c"],"fname":"1f43c","uc":"1f43c","isCanonical": true},":pig_nose:":{"unicode":["1f43d"],"fname":"1f43d","uc":"1f43d","isCanonical": true},":feet:":{"unicode":["1f43e"],"fname":"1f43e","uc":"1f43e","isCanonical": true},":paw_prints:":{"unicode":["1f43e"],"fname":"1f43e","uc":"1f43e","isCanonical": false},":eyes:":{"unicode":["1f440"],"fname":"1f440","uc":"1f440","isCanonical": true},":ear:":{"unicode":["1f442"],"fname":"1f442","uc":"1f442","isCanonical": true},":nose:":{"unicode":["1f443"],"fname":"1f443","uc":"1f443","isCanonical": true},":lips:":{"unicode":["1f444"],"fname":"1f444","uc":"1f444","isCanonical": true},":tongue:":{"unicode":["1f445"],"fname":"1f445","uc":"1f445","isCanonical": true},":point_up_2:":{"unicode":["1f446"],"fname":"1f446","uc":"1f446","isCanonical": true},":point_down:":{"unicode":["1f447"],"fname":"1f447","uc":"1f447","isCanonical": true},":point_left:":{"unicode":["1f448"],"fname":"1f448","uc":"1f448","isCanonical": true},":point_right:":{"unicode":["1f449"],"fname":"1f449","uc":"1f449","isCanonical": true},":punch:":{"unicode":["1f44a"],"fname":"1f44a","uc":"1f44a","isCanonical": true},":wave:":{"unicode":["1f44b"],"fname":"1f44b","uc":"1f44b","isCanonical": true},":ok_hand:":{"unicode":["1f44c"],"fname":"1f44c","uc":"1f44c","isCanonical": true},":thumbsup:":{"unicode":["1f44d"],"fname":"1f44d","uc":"1f44d","isCanonical": true},":+1:":{"unicode":["1f44d"],"fname":"1f44d","uc":"1f44d","isCanonical": false},":thumbup:":{"unicode":["1f44d"],"fname":"1f44d","uc":"1f44d","isCanonical": false},":thumbsdown:":{"unicode":["1f44e"],"fname":"1f44e","uc":"1f44e","isCanonical": true},":-1:":{"unicode":["1f44e"],"fname":"1f44e","uc":"1f44e","isCanonical": false},":thumbdown:":{"unicode":["1f44e"],"fname":"1f44e","uc":"1f44e","isCanonical": false},":clap:":{"unicode":["1f44f"],"fname":"1f44f","uc":"1f44f","isCanonical": true},":open_hands:":{"unicode":["1f450"],"fname":"1f450","uc":"1f450","isCanonical": true},":crown:":{"unicode":["1f451"],"fname":"1f451","uc":"1f451","isCanonical": true},":womans_hat:":{"unicode":["1f452"],"fname":"1f452","uc":"1f452","isCanonical": true},":eyeglasses:":{"unicode":["1f453"],"fname":"1f453","uc":"1f453","isCanonical": true},":necktie:":{"unicode":["1f454"],"fname":"1f454","uc":"1f454","isCanonical": true},":shirt:":{"unicode":["1f455"],"fname":"1f455","uc":"1f455","isCanonical": true},":jeans:":{"unicode":["1f456"],"fname":"1f456","uc":"1f456","isCanonical": true},":dress:":{"unicode":["1f457"],"fname":"1f457","uc":"1f457","isCanonical": true},":kimono:":{"unicode":["1f458"],"fname":"1f458","uc":"1f458","isCanonical": true},":bikini:":{"unicode":["1f459"],"fname":"1f459","uc":"1f459","isCanonical": true},":womans_clothes:":{"unicode":["1f45a"],"fname":"1f45a","uc":"1f45a","isCanonical": true},":purse:":{"unicode":["1f45b"],"fname":"1f45b","uc":"1f45b","isCanonical": true},":handbag:":{"unicode":["1f45c"],"fname":"1f45c","uc":"1f45c","isCanonical": true},":pouch:":{"unicode":["1f45d"],"fname":"1f45d","uc":"1f45d","isCanonical": true},":mans_shoe:":{"unicode":["1f45e"],"fname":"1f45e","uc":"1f45e","isCanonical": true},":athletic_shoe:":{"unicode":["1f45f"],"fname":"1f45f","uc":"1f45f","isCanonical": true},":high_heel:":{"unicode":["1f460"],"fname":"1f460","uc":"1f460","isCanonical": true},":sandal:":{"unicode":["1f461"],"fname":"1f461","uc":"1f461","isCanonical": true},":boot:":{"unicode":["1f462"],"fname":"1f462","uc":"1f462","isCanonical": true},":footprints:":{"unicode":["1f463"],"fname":"1f463","uc":"1f463","isCanonical": true},":bust_in_silhouette:":{"unicode":["1f464"],"fname":"1f464","uc":"1f464","isCanonical": true},":boy:":{"unicode":["1f466"],"fname":"1f466","uc":"1f466","isCanonical": true},":girl:":{"unicode":["1f467"],"fname":"1f467","uc":"1f467","isCanonical": true},":man:":{"unicode":["1f468"],"fname":"1f468","uc":"1f468","isCanonical": true},":woman:":{"unicode":["1f469"],"fname":"1f469","uc":"1f469","isCanonical": true},":family:":{"unicode":["1f46a"],"fname":"1f46a","uc":"1f46a","isCanonical": true},":couple:":{"unicode":["1f46b"],"fname":"1f46b","uc":"1f46b","isCanonical": true},":cop:":{"unicode":["1f46e"],"fname":"1f46e","uc":"1f46e","isCanonical": true},":dancers:":{"unicode":["1f46f"],"fname":"1f46f","uc":"1f46f","isCanonical": true},":bride_with_veil:":{"unicode":["1f470"],"fname":"1f470","uc":"1f470","isCanonical": true},":person_with_blond_hair:":{"unicode":["1f471"],"fname":"1f471","uc":"1f471","isCanonical": true},":man_with_gua_pi_mao:":{"unicode":["1f472"],"fname":"1f472","uc":"1f472","isCanonical": true},":man_with_turban:":{"unicode":["1f473"],"fname":"1f473","uc":"1f473","isCanonical": true},":older_man:":{"unicode":["1f474"],"fname":"1f474","uc":"1f474","isCanonical": true},":older_woman:":{"unicode":["1f475"],"fname":"1f475","uc":"1f475","isCanonical": true},":grandma:":{"unicode":["1f475"],"fname":"1f475","uc":"1f475","isCanonical": false},":baby:":{"unicode":["1f476"],"fname":"1f476","uc":"1f476","isCanonical": true},":construction_worker:":{"unicode":["1f477"],"fname":"1f477","uc":"1f477","isCanonical": true},":princess:":{"unicode":["1f478"],"fname":"1f478","uc":"1f478","isCanonical": true},":japanese_ogre:":{"unicode":["1f479"],"fname":"1f479","uc":"1f479","isCanonical": true},":japanese_goblin:":{"unicode":["1f47a"],"fname":"1f47a","uc":"1f47a","isCanonical": true},":ghost:":{"unicode":["1f47b"],"fname":"1f47b","uc":"1f47b","isCanonical": true},":angel:":{"unicode":["1f47c"],"fname":"1f47c","uc":"1f47c","isCanonical": true},":alien:":{"unicode":["1f47d"],"fname":"1f47d","uc":"1f47d","isCanonical": true},":space_invader:":{"unicode":["1f47e"],"fname":"1f47e","uc":"1f47e","isCanonical": true},":imp:":{"unicode":["1f47f"],"fname":"1f47f","uc":"1f47f","isCanonical": true},":skull:":{"unicode":["1f480"],"fname":"1f480","uc":"1f480","isCanonical": true},":skeleton:":{"unicode":["1f480"],"fname":"1f480","uc":"1f480","isCanonical": false},":card_index:":{"unicode":["1f4c7"],"fname":"1f4c7","uc":"1f4c7","isCanonical": true},":information_desk_person:":{"unicode":["1f481"],"fname":"1f481","uc":"1f481","isCanonical": true},":guardsman:":{"unicode":["1f482"],"fname":"1f482","uc":"1f482","isCanonical": true},":dancer:":{"unicode":["1f483"],"fname":"1f483","uc":"1f483","isCanonical": true},":lipstick:":{"unicode":["1f484"],"fname":"1f484","uc":"1f484","isCanonical": true},":nail_care:":{"unicode":["1f485"],"fname":"1f485","uc":"1f485","isCanonical": true},":ledger:":{"unicode":["1f4d2"],"fname":"1f4d2","uc":"1f4d2","isCanonical": true},":massage:":{"unicode":["1f486"],"fname":"1f486","uc":"1f486","isCanonical": true},":notebook:":{"unicode":["1f4d3"],"fname":"1f4d3","uc":"1f4d3","isCanonical": true},":haircut:":{"unicode":["1f487"],"fname":"1f487","uc":"1f487","isCanonical": true},":notebook_with_decorative_cover:":{"unicode":["1f4d4"],"fname":"1f4d4","uc":"1f4d4","isCanonical": true},":barber:":{"unicode":["1f488"],"fname":"1f488","uc":"1f488","isCanonical": true},":closed_book:":{"unicode":["1f4d5"],"fname":"1f4d5","uc":"1f4d5","isCanonical": true},":syringe:":{"unicode":["1f489"],"fname":"1f489","uc":"1f489","isCanonical": true},":book:":{"unicode":["1f4d6"],"fname":"1f4d6","uc":"1f4d6","isCanonical": true},":pill:":{"unicode":["1f48a"],"fname":"1f48a","uc":"1f48a","isCanonical": true},":green_book:":{"unicode":["1f4d7"],"fname":"1f4d7","uc":"1f4d7","isCanonical": true},":kiss:":{"unicode":["1f48b"],"fname":"1f48b","uc":"1f48b","isCanonical": true},":blue_book:":{"unicode":["1f4d8"],"fname":"1f4d8","uc":"1f4d8","isCanonical": true},":love_letter:":{"unicode":["1f48c"],"fname":"1f48c","uc":"1f48c","isCanonical": true},":orange_book:":{"unicode":["1f4d9"],"fname":"1f4d9","uc":"1f4d9","isCanonical": true},":ring:":{"unicode":["1f48d"],"fname":"1f48d","uc":"1f48d","isCanonical": true},":books:":{"unicode":["1f4da"],"fname":"1f4da","uc":"1f4da","isCanonical": true},":gem:":{"unicode":["1f48e"],"fname":"1f48e","uc":"1f48e","isCanonical": true},":name_badge:":{"unicode":["1f4db"],"fname":"1f4db","uc":"1f4db","isCanonical": true},":couplekiss:":{"unicode":["1f48f"],"fname":"1f48f","uc":"1f48f","isCanonical": true},":scroll:":{"unicode":["1f4dc"],"fname":"1f4dc","uc":"1f4dc","isCanonical": true},":bouquet:":{"unicode":["1f490"],"fname":"1f490","uc":"1f490","isCanonical": true},":pencil:":{"unicode":["1f4dd"],"fname":"1f4dd","uc":"1f4dd","isCanonical": true},":couple_with_heart:":{"unicode":["1f491"],"fname":"1f491","uc":"1f491","isCanonical": true},":telephone_receiver:":{"unicode":["1f4de"],"fname":"1f4de","uc":"1f4de","isCanonical": true},":wedding:":{"unicode":["1f492"],"fname":"1f492","uc":"1f492","isCanonical": true},":pager:":{"unicode":["1f4df"],"fname":"1f4df","uc":"1f4df","isCanonical": true},":fax:":{"unicode":["1f4e0"],"fname":"1f4e0","uc":"1f4e0","isCanonical": true},":heartbeat:":{"unicode":["1f493"],"fname":"1f493","uc":"1f493","isCanonical": true},":satellite:":{"unicode":["1f4e1"],"fname":"1f4e1","uc":"1f4e1","isCanonical": true},":loudspeaker:":{"unicode":["1f4e2"],"fname":"1f4e2","uc":"1f4e2","isCanonical": true},":broken_heart:":{"unicode":["1f494"],"fname":"1f494","uc":"1f494","isCanonical": true},":mega:":{"unicode":["1f4e3"],"fname":"1f4e3","uc":"1f4e3","isCanonical": true},":outbox_tray:":{"unicode":["1f4e4"],"fname":"1f4e4","uc":"1f4e4","isCanonical": true},":two_hearts:":{"unicode":["1f495"],"fname":"1f495","uc":"1f495","isCanonical": true},":inbox_tray:":{"unicode":["1f4e5"],"fname":"1f4e5","uc":"1f4e5","isCanonical": true},":package:":{"unicode":["1f4e6"],"fname":"1f4e6","uc":"1f4e6","isCanonical": true},":sparkling_heart:":{"unicode":["1f496"],"fname":"1f496","uc":"1f496","isCanonical": true},":e-mail:":{"unicode":["1f4e7"],"fname":"1f4e7","uc":"1f4e7","isCanonical": true},":email:":{"unicode":["1f4e7"],"fname":"1f4e7","uc":"1f4e7","isCanonical": false},":incoming_envelope:":{"unicode":["1f4e8"],"fname":"1f4e8","uc":"1f4e8","isCanonical": true},":heartpulse:":{"unicode":["1f497"],"fname":"1f497","uc":"1f497","isCanonical": true},":envelope_with_arrow:":{"unicode":["1f4e9"],"fname":"1f4e9","uc":"1f4e9","isCanonical": true},":mailbox_closed:":{"unicode":["1f4ea"],"fname":"1f4ea","uc":"1f4ea","isCanonical": true},":cupid:":{"unicode":["1f498"],"fname":"1f498","uc":"1f498","isCanonical": true},":mailbox:":{"unicode":["1f4eb"],"fname":"1f4eb","uc":"1f4eb","isCanonical": true},":postbox:":{"unicode":["1f4ee"],"fname":"1f4ee","uc":"1f4ee","isCanonical": true},":blue_heart:":{"unicode":["1f499"],"fname":"1f499","uc":"1f499","isCanonical": true},":newspaper:":{"unicode":["1f4f0"],"fname":"1f4f0","uc":"1f4f0","isCanonical": true},":iphone:":{"unicode":["1f4f1"],"fname":"1f4f1","uc":"1f4f1","isCanonical": true},":green_heart:":{"unicode":["1f49a"],"fname":"1f49a","uc":"1f49a","isCanonical": true},":calling:":{"unicode":["1f4f2"],"fname":"1f4f2","uc":"1f4f2","isCanonical": true},":vibration_mode:":{"unicode":["1f4f3"],"fname":"1f4f3","uc":"1f4f3","isCanonical": true},":yellow_heart:":{"unicode":["1f49b"],"fname":"1f49b","uc":"1f49b","isCanonical": true},":mobile_phone_off:":{"unicode":["1f4f4"],"fname":"1f4f4","uc":"1f4f4","isCanonical": true},":signal_strength:":{"unicode":["1f4f6"],"fname":"1f4f6","uc":"1f4f6","isCanonical": true},":purple_heart:":{"unicode":["1f49c"],"fname":"1f49c","uc":"1f49c","isCanonical": true},":camera:":{"unicode":["1f4f7"],"fname":"1f4f7","uc":"1f4f7","isCanonical": true},":video_camera:":{"unicode":["1f4f9"],"fname":"1f4f9","uc":"1f4f9","isCanonical": true},":gift_heart:":{"unicode":["1f49d"],"fname":"1f49d","uc":"1f49d","isCanonical": true},":tv:":{"unicode":["1f4fa"],"fname":"1f4fa","uc":"1f4fa","isCanonical": true},":radio:":{"unicode":["1f4fb"],"fname":"1f4fb","uc":"1f4fb","isCanonical": true},":revolving_hearts:":{"unicode":["1f49e"],"fname":"1f49e","uc":"1f49e","isCanonical": true},":vhs:":{"unicode":["1f4fc"],"fname":"1f4fc","uc":"1f4fc","isCanonical": true},":arrows_clockwise:":{"unicode":["1f503"],"fname":"1f503","uc":"1f503","isCanonical": true},":heart_decoration:":{"unicode":["1f49f"],"fname":"1f49f","uc":"1f49f","isCanonical": true},":loud_sound:":{"unicode":["1f50a"],"fname":"1f50a","uc":"1f50a","isCanonical": true},":battery:":{"unicode":["1f50b"],"fname":"1f50b","uc":"1f50b","isCanonical": true},":diamond_shape_with_a_dot_inside:":{"unicode":["1f4a0"],"fname":"1f4a0","uc":"1f4a0","isCanonical": true},":electric_plug:":{"unicode":["1f50c"],"fname":"1f50c","uc":"1f50c","isCanonical": true},":mag:":{"unicode":["1f50d"],"fname":"1f50d","uc":"1f50d","isCanonical": true},":bulb:":{"unicode":["1f4a1"],"fname":"1f4a1","uc":"1f4a1","isCanonical": true},":mag_right:":{"unicode":["1f50e"],"fname":"1f50e","uc":"1f50e","isCanonical": true},":lock_with_ink_pen:":{"unicode":["1f50f"],"fname":"1f50f","uc":"1f50f","isCanonical": true},":anger:":{"unicode":["1f4a2"],"fname":"1f4a2","uc":"1f4a2","isCanonical": true},":closed_lock_with_key:":{"unicode":["1f510"],"fname":"1f510","uc":"1f510","isCanonical": true},":key:":{"unicode":["1f511"],"fname":"1f511","uc":"1f511","isCanonical": true},":bomb:":{"unicode":["1f4a3"],"fname":"1f4a3","uc":"1f4a3","isCanonical": true},":lock:":{"unicode":["1f512"],"fname":"1f512","uc":"1f512","isCanonical": true},":unlock:":{"unicode":["1f513"],"fname":"1f513","uc":"1f513","isCanonical": true},":zzz:":{"unicode":["1f4a4"],"fname":"1f4a4","uc":"1f4a4","isCanonical": true},":bell:":{"unicode":["1f514"],"fname":"1f514","uc":"1f514","isCanonical": true},":bookmark:":{"unicode":["1f516"],"fname":"1f516","uc":"1f516","isCanonical": true},":boom:":{"unicode":["1f4a5"],"fname":"1f4a5","uc":"1f4a5","isCanonical": true},":link:":{"unicode":["1f517"],"fname":"1f517","uc":"1f517","isCanonical": true},":radio_button:":{"unicode":["1f518"],"fname":"1f518","uc":"1f518","isCanonical": true},":sweat_drops:":{"unicode":["1f4a6"],"fname":"1f4a6","uc":"1f4a6","isCanonical": true},":back:":{"unicode":["1f519"],"fname":"1f519","uc":"1f519","isCanonical": true},":end:":{"unicode":["1f51a"],"fname":"1f51a","uc":"1f51a","isCanonical": true},":droplet:":{"unicode":["1f4a7"],"fname":"1f4a7","uc":"1f4a7","isCanonical": true},":on:":{"unicode":["1f51b"],"fname":"1f51b","uc":"1f51b","isCanonical": true},":soon:":{"unicode":["1f51c"],"fname":"1f51c","uc":"1f51c","isCanonical": true},":dash:":{"unicode":["1f4a8"],"fname":"1f4a8","uc":"1f4a8","isCanonical": true},":top:":{"unicode":["1f51d"],"fname":"1f51d","uc":"1f51d","isCanonical": true},":underage:":{"unicode":["1f51e"],"fname":"1f51e","uc":"1f51e","isCanonical": true},":poop:":{"unicode":["1f4a9"],"fname":"1f4a9","uc":"1f4a9","isCanonical": true},":shit:":{"unicode":["1f4a9"],"fname":"1f4a9","uc":"1f4a9","isCanonical": false},":hankey:":{"unicode":["1f4a9"],"fname":"1f4a9","uc":"1f4a9","isCanonical": false},":poo:":{"unicode":["1f4a9"],"fname":"1f4a9","uc":"1f4a9","isCanonical": false},":keycap_ten:":{"unicode":["1f51f"],"fname":"1f51f","uc":"1f51f","isCanonical": true},":muscle:":{"unicode":["1f4aa"],"fname":"1f4aa","uc":"1f4aa","isCanonical": true},":capital_abcd:":{"unicode":["1f520"],"fname":"1f520","uc":"1f520","isCanonical": true},":abcd:":{"unicode":["1f521"],"fname":"1f521","uc":"1f521","isCanonical": true},":dizzy:":{"unicode":["1f4ab"],"fname":"1f4ab","uc":"1f4ab","isCanonical": true},":1234:":{"unicode":["1f522"],"fname":"1f522","uc":"1f522","isCanonical": true},":symbols:":{"unicode":["1f523"],"fname":"1f523","uc":"1f523","isCanonical": true},":speech_balloon:":{"unicode":["1f4ac"],"fname":"1f4ac","uc":"1f4ac","isCanonical": true},":abc:":{"unicode":["1f524"],"fname":"1f524","uc":"1f524","isCanonical": true},":fire:":{"unicode":["1f525"],"fname":"1f525","uc":"1f525","isCanonical": true},":flame:":{"unicode":["1f525"],"fname":"1f525","uc":"1f525","isCanonical": false},":white_flower:":{"unicode":["1f4ae"],"fname":"1f4ae","uc":"1f4ae","isCanonical": true},":flashlight:":{"unicode":["1f526"],"fname":"1f526","uc":"1f526","isCanonical": true},":wrench:":{"unicode":["1f527"],"fname":"1f527","uc":"1f527","isCanonical": true},":100:":{"unicode":["1f4af"],"fname":"1f4af","uc":"1f4af","isCanonical": true},":hammer:":{"unicode":["1f528"],"fname":"1f528","uc":"1f528","isCanonical": true},":nut_and_bolt:":{"unicode":["1f529"],"fname":"1f529","uc":"1f529","isCanonical": true},":moneybag:":{"unicode":["1f4b0"],"fname":"1f4b0","uc":"1f4b0","isCanonical": true},":knife:":{"unicode":["1f52a"],"fname":"1f52a","uc":"1f52a","isCanonical": true},":gun:":{"unicode":["1f52b"],"fname":"1f52b","uc":"1f52b","isCanonical": true},":currency_exchange:":{"unicode":["1f4b1"],"fname":"1f4b1","uc":"1f4b1","isCanonical": true},":crystal_ball:":{"unicode":["1f52e"],"fname":"1f52e","uc":"1f52e","isCanonical": true},":heavy_dollar_sign:":{"unicode":["1f4b2"],"fname":"1f4b2","uc":"1f4b2","isCanonical": true},":six_pointed_star:":{"unicode":["1f52f"],"fname":"1f52f","uc":"1f52f","isCanonical": true},":credit_card:":{"unicode":["1f4b3"],"fname":"1f4b3","uc":"1f4b3","isCanonical": true},":beginner:":{"unicode":["1f530"],"fname":"1f530","uc":"1f530","isCanonical": true},":trident:":{"unicode":["1f531"],"fname":"1f531","uc":"1f531","isCanonical": true},":yen:":{"unicode":["1f4b4"],"fname":"1f4b4","uc":"1f4b4","isCanonical": true},":black_square_button:":{"unicode":["1f532"],"fname":"1f532","uc":"1f532","isCanonical": true},":white_square_button:":{"unicode":["1f533"],"fname":"1f533","uc":"1f533","isCanonical": true},":dollar:":{"unicode":["1f4b5"],"fname":"1f4b5","uc":"1f4b5","isCanonical": true},":red_circle:":{"unicode":["1f534"],"fname":"1f534","uc":"1f534","isCanonical": true},":blue_circle:":{"unicode":["1f535"],"fname":"1f535","uc":"1f535","isCanonical": true},":money_with_wings:":{"unicode":["1f4b8"],"fname":"1f4b8","uc":"1f4b8","isCanonical": true},":large_orange_diamond:":{"unicode":["1f536"],"fname":"1f536","uc":"1f536","isCanonical": true},":large_blue_diamond:":{"unicode":["1f537"],"fname":"1f537","uc":"1f537","isCanonical": true},":chart:":{"unicode":["1f4b9"],"fname":"1f4b9","uc":"1f4b9","isCanonical": true},":small_orange_diamond:":{"unicode":["1f538"],"fname":"1f538","uc":"1f538","isCanonical": true},":small_blue_diamond:":{"unicode":["1f539"],"fname":"1f539","uc":"1f539","isCanonical": true},":seat:":{"unicode":["1f4ba"],"fname":"1f4ba","uc":"1f4ba","isCanonical": true},":small_red_triangle:":{"unicode":["1f53a"],"fname":"1f53a","uc":"1f53a","isCanonical": true},":small_red_triangle_down:":{"unicode":["1f53b"],"fname":"1f53b","uc":"1f53b","isCanonical": true},":computer:":{"unicode":["1f4bb"],"fname":"1f4bb","uc":"1f4bb","isCanonical": true},":arrow_up_small:":{"unicode":["1f53c"],"fname":"1f53c","uc":"1f53c","isCanonical": true},":briefcase:":{"unicode":["1f4bc"],"fname":"1f4bc","uc":"1f4bc","isCanonical": true},":arrow_down_small:":{"unicode":["1f53d"],"fname":"1f53d","uc":"1f53d","isCanonical": true},":clock1:":{"unicode":["1f550"],"fname":"1f550","uc":"1f550","isCanonical": true},":minidisc:":{"unicode":["1f4bd"],"fname":"1f4bd","uc":"1f4bd","isCanonical": true},":clock2:":{"unicode":["1f551"],"fname":"1f551","uc":"1f551","isCanonical": true},":floppy_disk:":{"unicode":["1f4be"],"fname":"1f4be","uc":"1f4be","isCanonical": true},":clock3:":{"unicode":["1f552"],"fname":"1f552","uc":"1f552","isCanonical": true},":cd:":{"unicode":["1f4bf"],"fname":"1f4bf","uc":"1f4bf","isCanonical": true},":clock4:":{"unicode":["1f553"],"fname":"1f553","uc":"1f553","isCanonical": true},":dvd:":{"unicode":["1f4c0"],"fname":"1f4c0","uc":"1f4c0","isCanonical": true},":clock5:":{"unicode":["1f554"],"fname":"1f554","uc":"1f554","isCanonical": true},":clock6:":{"unicode":["1f555"],"fname":"1f555","uc":"1f555","isCanonical": true},":file_folder:":{"unicode":["1f4c1"],"fname":"1f4c1","uc":"1f4c1","isCanonical": true},":clock7:":{"unicode":["1f556"],"fname":"1f556","uc":"1f556","isCanonical": true},":clock8:":{"unicode":["1f557"],"fname":"1f557","uc":"1f557","isCanonical": true},":open_file_folder:":{"unicode":["1f4c2"],"fname":"1f4c2","uc":"1f4c2","isCanonical": true},":clock9:":{"unicode":["1f558"],"fname":"1f558","uc":"1f558","isCanonical": true},":clock10:":{"unicode":["1f559"],"fname":"1f559","uc":"1f559","isCanonical": true},":page_with_curl:":{"unicode":["1f4c3"],"fname":"1f4c3","uc":"1f4c3","isCanonical": true},":clock11:":{"unicode":["1f55a"],"fname":"1f55a","uc":"1f55a","isCanonical": true},":clock12:":{"unicode":["1f55b"],"fname":"1f55b","uc":"1f55b","isCanonical": true},":page_facing_up:":{"unicode":["1f4c4"],"fname":"1f4c4","uc":"1f4c4","isCanonical": true},":mount_fuji:":{"unicode":["1f5fb"],"fname":"1f5fb","uc":"1f5fb","isCanonical": true},":tokyo_tower:":{"unicode":["1f5fc"],"fname":"1f5fc","uc":"1f5fc","isCanonical": true},":date:":{"unicode":["1f4c5"],"fname":"1f4c5","uc":"1f4c5","isCanonical": true},":statue_of_liberty:":{"unicode":["1f5fd"],"fname":"1f5fd","uc":"1f5fd","isCanonical": true},":japan:":{"unicode":["1f5fe"],"fname":"1f5fe","uc":"1f5fe","isCanonical": true},":calendar:":{"unicode":["1f4c6"],"fname":"1f4c6","uc":"1f4c6","isCanonical": true},":moyai:":{"unicode":["1f5ff"],"fname":"1f5ff","uc":"1f5ff","isCanonical": true},":grin:":{"unicode":["1f601"],"fname":"1f601","uc":"1f601","isCanonical": true},":joy:":{"unicode":["1f602"],"fname":"1f602","uc":"1f602","isCanonical": true},":smiley:":{"unicode":["1f603"],"fname":"1f603","uc":"1f603","isCanonical": true},":chart_with_upwards_trend:":{"unicode":["1f4c8"],"fname":"1f4c8","uc":"1f4c8","isCanonical": true},":smile:":{"unicode":["1f604"],"fname":"1f604","uc":"1f604","isCanonical": true},":sweat_smile:":{"unicode":["1f605"],"fname":"1f605","uc":"1f605","isCanonical": true},":chart_with_downwards_trend:":{"unicode":["1f4c9"],"fname":"1f4c9","uc":"1f4c9","isCanonical": true},":laughing:":{"unicode":["1f606"],"fname":"1f606","uc":"1f606","isCanonical": true},":satisfied:":{"unicode":["1f606"],"fname":"1f606","uc":"1f606","isCanonical": false},":wink:":{"unicode":["1f609"],"fname":"1f609","uc":"1f609","isCanonical": true},":bar_chart:":{"unicode":["1f4ca"],"fname":"1f4ca","uc":"1f4ca","isCanonical": true},":blush:":{"unicode":["1f60a"],"fname":"1f60a","uc":"1f60a","isCanonical": true},":yum:":{"unicode":["1f60b"],"fname":"1f60b","uc":"1f60b","isCanonical": true},":clipboard:":{"unicode":["1f4cb"],"fname":"1f4cb","uc":"1f4cb","isCanonical": true},":relieved:":{"unicode":["1f60c"],"fname":"1f60c","uc":"1f60c","isCanonical": true},":heart_eyes:":{"unicode":["1f60d"],"fname":"1f60d","uc":"1f60d","isCanonical": true},":pushpin:":{"unicode":["1f4cc"],"fname":"1f4cc","uc":"1f4cc","isCanonical": true},":smirk:":{"unicode":["1f60f"],"fname":"1f60f","uc":"1f60f","isCanonical": true},":unamused:":{"unicode":["1f612"],"fname":"1f612","uc":"1f612","isCanonical": true},":round_pushpin:":{"unicode":["1f4cd"],"fname":"1f4cd","uc":"1f4cd","isCanonical": true},":sweat:":{"unicode":["1f613"],"fname":"1f613","uc":"1f613","isCanonical": true},":pensive:":{"unicode":["1f614"],"fname":"1f614","uc":"1f614","isCanonical": true},":paperclip:":{"unicode":["1f4ce"],"fname":"1f4ce","uc":"1f4ce","isCanonical": true},":confounded:":{"unicode":["1f616"],"fname":"1f616","uc":"1f616","isCanonical": true},":kissing_heart:":{"unicode":["1f618"],"fname":"1f618","uc":"1f618","isCanonical": true},":straight_ruler:":{"unicode":["1f4cf"],"fname":"1f4cf","uc":"1f4cf","isCanonical": true},":kissing_closed_eyes:":{"unicode":["1f61a"],"fname":"1f61a","uc":"1f61a","isCanonical": true},":stuck_out_tongue_winking_eye:":{"unicode":["1f61c"],"fname":"1f61c","uc":"1f61c","isCanonical": true},":triangular_ruler:":{"unicode":["1f4d0"],"fname":"1f4d0","uc":"1f4d0","isCanonical": true},":stuck_out_tongue_closed_eyes:":{"unicode":["1f61d"],"fname":"1f61d","uc":"1f61d","isCanonical": true},":disappointed:":{"unicode":["1f61e"],"fname":"1f61e","uc":"1f61e","isCanonical": true},":bookmark_tabs:":{"unicode":["1f4d1"],"fname":"1f4d1","uc":"1f4d1","isCanonical": true},":angry:":{"unicode":["1f620"],"fname":"1f620","uc":"1f620","isCanonical": true},":rage:":{"unicode":["1f621"],"fname":"1f621","uc":"1f621","isCanonical": true},":cry:":{"unicode":["1f622"],"fname":"1f622","uc":"1f622","isCanonical": true},":persevere:":{"unicode":["1f623"],"fname":"1f623","uc":"1f623","isCanonical": true},":triumph:":{"unicode":["1f624"],"fname":"1f624","uc":"1f624","isCanonical": true},":disappointed_relieved:":{"unicode":["1f625"],"fname":"1f625","uc":"1f625","isCanonical": true},":fearful:":{"unicode":["1f628"],"fname":"1f628","uc":"1f628","isCanonical": true},":weary:":{"unicode":["1f629"],"fname":"1f629","uc":"1f629","isCanonical": true},":sleepy:":{"unicode":["1f62a"],"fname":"1f62a","uc":"1f62a","isCanonical": true},":tired_face:":{"unicode":["1f62b"],"fname":"1f62b","uc":"1f62b","isCanonical": true},":sob:":{"unicode":["1f62d"],"fname":"1f62d","uc":"1f62d","isCanonical": true},":cold_sweat:":{"unicode":["1f630"],"fname":"1f630","uc":"1f630","isCanonical": true},":scream:":{"unicode":["1f631"],"fname":"1f631","uc":"1f631","isCanonical": true},":astonished:":{"unicode":["1f632"],"fname":"1f632","uc":"1f632","isCanonical": true},":flushed:":{"unicode":["1f633"],"fname":"1f633","uc":"1f633","isCanonical": true},":dizzy_face:":{"unicode":["1f635"],"fname":"1f635","uc":"1f635","isCanonical": true},":mask:":{"unicode":["1f637"],"fname":"1f637","uc":"1f637","isCanonical": true},":smile_cat:":{"unicode":["1f638"],"fname":"1f638","uc":"1f638","isCanonical": true},":joy_cat:":{"unicode":["1f639"],"fname":"1f639","uc":"1f639","isCanonical": true},":smiley_cat:":{"unicode":["1f63a"],"fname":"1f63a","uc":"1f63a","isCanonical": true},":heart_eyes_cat:":{"unicode":["1f63b"],"fname":"1f63b","uc":"1f63b","isCanonical": true},":smirk_cat:":{"unicode":["1f63c"],"fname":"1f63c","uc":"1f63c","isCanonical": true},":kissing_cat:":{"unicode":["1f63d"],"fname":"1f63d","uc":"1f63d","isCanonical": true},":pouting_cat:":{"unicode":["1f63e"],"fname":"1f63e","uc":"1f63e","isCanonical": true},":crying_cat_face:":{"unicode":["1f63f"],"fname":"1f63f","uc":"1f63f","isCanonical": true},":scream_cat:":{"unicode":["1f640"],"fname":"1f640","uc":"1f640","isCanonical": true},":no_good:":{"unicode":["1f645"],"fname":"1f645","uc":"1f645","isCanonical": true},":ok_woman:":{"unicode":["1f646"],"fname":"1f646","uc":"1f646","isCanonical": true},":bow:":{"unicode":["1f647"],"fname":"1f647","uc":"1f647","isCanonical": true},":see_no_evil:":{"unicode":["1f648"],"fname":"1f648","uc":"1f648","isCanonical": true},":hear_no_evil:":{"unicode":["1f649"],"fname":"1f649","uc":"1f649","isCanonical": true},":speak_no_evil:":{"unicode":["1f64a"],"fname":"1f64a","uc":"1f64a","isCanonical": true},":raising_hand:":{"unicode":["1f64b"],"fname":"1f64b","uc":"1f64b","isCanonical": true},":raised_hands:":{"unicode":["1f64c"],"fname":"1f64c","uc":"1f64c","isCanonical": true},":person_frowning:":{"unicode":["1f64d"],"fname":"1f64d","uc":"1f64d","isCanonical": true},":person_with_pouting_face:":{"unicode":["1f64e"],"fname":"1f64e","uc":"1f64e","isCanonical": true},":pray:":{"unicode":["1f64f"],"fname":"1f64f","uc":"1f64f","isCanonical": true},":rocket:":{"unicode":["1f680"],"fname":"1f680","uc":"1f680","isCanonical": true},":railway_car:":{"unicode":["1f683"],"fname":"1f683","uc":"1f683","isCanonical": true},":bullettrain_side:":{"unicode":["1f684"],"fname":"1f684","uc":"1f684","isCanonical": true},":bullettrain_front:":{"unicode":["1f685"],"fname":"1f685","uc":"1f685","isCanonical": true},":metro:":{"unicode":["1f687"],"fname":"1f687","uc":"1f687","isCanonical": true},":station:":{"unicode":["1f689"],"fname":"1f689","uc":"1f689","isCanonical": true},":bus:":{"unicode":["1f68c"],"fname":"1f68c","uc":"1f68c","isCanonical": true},":busstop:":{"unicode":["1f68f"],"fname":"1f68f","uc":"1f68f","isCanonical": true},":ambulance:":{"unicode":["1f691"],"fname":"1f691","uc":"1f691","isCanonical": true},":fire_engine:":{"unicode":["1f692"],"fname":"1f692","uc":"1f692","isCanonical": true},":police_car:":{"unicode":["1f693"],"fname":"1f693","uc":"1f693","isCanonical": true},":taxi:":{"unicode":["1f695"],"fname":"1f695","uc":"1f695","isCanonical": true},":red_car:":{"unicode":["1f697"],"fname":"1f697","uc":"1f697","isCanonical": true},":blue_car:":{"unicode":["1f699"],"fname":"1f699","uc":"1f699","isCanonical": true},":truck:":{"unicode":["1f69a"],"fname":"1f69a","uc":"1f69a","isCanonical": true},":ship:":{"unicode":["1f6a2"],"fname":"1f6a2","uc":"1f6a2","isCanonical": true},":speedboat:":{"unicode":["1f6a4"],"fname":"1f6a4","uc":"1f6a4","isCanonical": true},":traffic_light:":{"unicode":["1f6a5"],"fname":"1f6a5","uc":"1f6a5","isCanonical": true},":construction:":{"unicode":["1f6a7"],"fname":"1f6a7","uc":"1f6a7","isCanonical": true},":rotating_light:":{"unicode":["1f6a8"],"fname":"1f6a8","uc":"1f6a8","isCanonical": true},":triangular_flag_on_post:":{"unicode":["1f6a9"],"fname":"1f6a9","uc":"1f6a9","isCanonical": true},":door:":{"unicode":["1f6aa"],"fname":"1f6aa","uc":"1f6aa","isCanonical": true},":no_entry_sign:":{"unicode":["1f6ab"],"fname":"1f6ab","uc":"1f6ab","isCanonical": true},":smoking:":{"unicode":["1f6ac"],"fname":"1f6ac","uc":"1f6ac","isCanonical": true},":no_smoking:":{"unicode":["1f6ad"],"fname":"1f6ad","uc":"1f6ad","isCanonical": true},":bike:":{"unicode":["1f6b2"],"fname":"1f6b2","uc":"1f6b2","isCanonical": true},":walking:":{"unicode":["1f6b6"],"fname":"1f6b6","uc":"1f6b6","isCanonical": true},":mens:":{"unicode":["1f6b9"],"fname":"1f6b9","uc":"1f6b9","isCanonical": true},":womens:":{"unicode":["1f6ba"],"fname":"1f6ba","uc":"1f6ba","isCanonical": true},":restroom:":{"unicode":["1f6bb"],"fname":"1f6bb","uc":"1f6bb","isCanonical": true},":baby_symbol:":{"unicode":["1f6bc"],"fname":"1f6bc","uc":"1f6bc","isCanonical": true},":toilet:":{"unicode":["1f6bd"],"fname":"1f6bd","uc":"1f6bd","isCanonical": true},":wc:":{"unicode":["1f6be"],"fname":"1f6be","uc":"1f6be","isCanonical": true},":bath:":{"unicode":["1f6c0"],"fname":"1f6c0","uc":"1f6c0","isCanonical": true},":metal:":{"unicode":["1f918"],"fname":"1f918","uc":"1f918","isCanonical": true},":sign_of_the_horns:":{"unicode":["1f918"],"fname":"1f918","uc":"1f918","isCanonical": false},":grinning:":{"unicode":["1f600"],"fname":"1f600","uc":"1f600","isCanonical": true},":innocent:":{"unicode":["1f607"],"fname":"1f607","uc":"1f607","isCanonical": true},":smiling_imp:":{"unicode":["1f608"],"fname":"1f608","uc":"1f608","isCanonical": true},":sunglasses:":{"unicode":["1f60e"],"fname":"1f60e","uc":"1f60e","isCanonical": true},":neutral_face:":{"unicode":["1f610"],"fname":"1f610","uc":"1f610","isCanonical": true},":expressionless:":{"unicode":["1f611"],"fname":"1f611","uc":"1f611","isCanonical": true},":confused:":{"unicode":["1f615"],"fname":"1f615","uc":"1f615","isCanonical": true},":kissing:":{"unicode":["1f617"],"fname":"1f617","uc":"1f617","isCanonical": true},":kissing_smiling_eyes:":{"unicode":["1f619"],"fname":"1f619","uc":"1f619","isCanonical": true},":stuck_out_tongue:":{"unicode":["1f61b"],"fname":"1f61b","uc":"1f61b","isCanonical": true},":worried:":{"unicode":["1f61f"],"fname":"1f61f","uc":"1f61f","isCanonical": true},":frowning:":{"unicode":["1f626"],"fname":"1f626","uc":"1f626","isCanonical": true},":anguished:":{"unicode":["1f627"],"fname":"1f627","uc":"1f627","isCanonical": true},":grimacing:":{"unicode":["1f62c"],"fname":"1f62c","uc":"1f62c","isCanonical": true},":open_mouth:":{"unicode":["1f62e"],"fname":"1f62e","uc":"1f62e","isCanonical": true},":hushed:":{"unicode":["1f62f"],"fname":"1f62f","uc":"1f62f","isCanonical": true},":sleeping:":{"unicode":["1f634"],"fname":"1f634","uc":"1f634","isCanonical": true},":no_mouth:":{"unicode":["1f636"],"fname":"1f636","uc":"1f636","isCanonical": true},":helicopter:":{"unicode":["1f681"],"fname":"1f681","uc":"1f681","isCanonical": true},":steam_locomotive:":{"unicode":["1f682"],"fname":"1f682","uc":"1f682","isCanonical": true},":train2:":{"unicode":["1f686"],"fname":"1f686","uc":"1f686","isCanonical": true},":light_rail:":{"unicode":["1f688"],"fname":"1f688","uc":"1f688","isCanonical": true},":tram:":{"unicode":["1f68a"],"fname":"1f68a","uc":"1f68a","isCanonical": true},":oncoming_bus:":{"unicode":["1f68d"],"fname":"1f68d","uc":"1f68d","isCanonical": true},":trolleybus:":{"unicode":["1f68e"],"fname":"1f68e","uc":"1f68e","isCanonical": true},":minibus:":{"unicode":["1f690"],"fname":"1f690","uc":"1f690","isCanonical": true},":oncoming_police_car:":{"unicode":["1f694"],"fname":"1f694","uc":"1f694","isCanonical": true},":oncoming_taxi:":{"unicode":["1f696"],"fname":"1f696","uc":"1f696","isCanonical": true},":oncoming_automobile:":{"unicode":["1f698"],"fname":"1f698","uc":"1f698","isCanonical": true},":articulated_lorry:":{"unicode":["1f69b"],"fname":"1f69b","uc":"1f69b","isCanonical": true},":tractor:":{"unicode":["1f69c"],"fname":"1f69c","uc":"1f69c","isCanonical": true},":monorail:":{"unicode":["1f69d"],"fname":"1f69d","uc":"1f69d","isCanonical": true},":mountain_railway:":{"unicode":["1f69e"],"fname":"1f69e","uc":"1f69e","isCanonical": true},":suspension_railway:":{"unicode":["1f69f"],"fname":"1f69f","uc":"1f69f","isCanonical": true},":mountain_cableway:":{"unicode":["1f6a0"],"fname":"1f6a0","uc":"1f6a0","isCanonical": true},":aerial_tramway:":{"unicode":["1f6a1"],"fname":"1f6a1","uc":"1f6a1","isCanonical": true},":rowboat:":{"unicode":["1f6a3"],"fname":"1f6a3","uc":"1f6a3","isCanonical": true},":vertical_traffic_light:":{"unicode":["1f6a6"],"fname":"1f6a6","uc":"1f6a6","isCanonical": true},":put_litter_in_its_place:":{"unicode":["1f6ae"],"fname":"1f6ae","uc":"1f6ae","isCanonical": true},":do_not_litter:":{"unicode":["1f6af"],"fname":"1f6af","uc":"1f6af","isCanonical": true},":potable_water:":{"unicode":["1f6b0"],"fname":"1f6b0","uc":"1f6b0","isCanonical": true},":non-potable_water:":{"unicode":["1f6b1"],"fname":"1f6b1","uc":"1f6b1","isCanonical": true},":no_bicycles:":{"unicode":["1f6b3"],"fname":"1f6b3","uc":"1f6b3","isCanonical": true},":bicyclist:":{"unicode":["1f6b4"],"fname":"1f6b4","uc":"1f6b4","isCanonical": true},":mountain_bicyclist:":{"unicode":["1f6b5"],"fname":"1f6b5","uc":"1f6b5","isCanonical": true},":no_pedestrians:":{"unicode":["1f6b7"],"fname":"1f6b7","uc":"1f6b7","isCanonical": true},":children_crossing:":{"unicode":["1f6b8"],"fname":"1f6b8","uc":"1f6b8","isCanonical": true},":shower:":{"unicode":["1f6bf"],"fname":"1f6bf","uc":"1f6bf","isCanonical": true},":bathtub:":{"unicode":["1f6c1"],"fname":"1f6c1","uc":"1f6c1","isCanonical": true},":passport_control:":{"unicode":["1f6c2"],"fname":"1f6c2","uc":"1f6c2","isCanonical": true},":customs:":{"unicode":["1f6c3"],"fname":"1f6c3","uc":"1f6c3","isCanonical": true},":baggage_claim:":{"unicode":["1f6c4"],"fname":"1f6c4","uc":"1f6c4","isCanonical": true},":left_luggage:":{"unicode":["1f6c5"],"fname":"1f6c5","uc":"1f6c5","isCanonical": true},":earth_africa:":{"unicode":["1f30d"],"fname":"1f30d","uc":"1f30d","isCanonical": true},":earth_americas:":{"unicode":["1f30e"],"fname":"1f30e","uc":"1f30e","isCanonical": true},":globe_with_meridians:":{"unicode":["1f310"],"fname":"1f310","uc":"1f310","isCanonical": true},":waxing_crescent_moon:":{"unicode":["1f312"],"fname":"1f312","uc":"1f312","isCanonical": true},":waning_gibbous_moon:":{"unicode":["1f316"],"fname":"1f316","uc":"1f316","isCanonical": true},":last_quarter_moon:":{"unicode":["1f317"],"fname":"1f317","uc":"1f317","isCanonical": true},":waning_crescent_moon:":{"unicode":["1f318"],"fname":"1f318","uc":"1f318","isCanonical": true},":new_moon_with_face:":{"unicode":["1f31a"],"fname":"1f31a","uc":"1f31a","isCanonical": true},":last_quarter_moon_with_face:":{"unicode":["1f31c"],"fname":"1f31c","uc":"1f31c","isCanonical": true},":full_moon_with_face:":{"unicode":["1f31d"],"fname":"1f31d","uc":"1f31d","isCanonical": true},":sun_with_face:":{"unicode":["1f31e"],"fname":"1f31e","uc":"1f31e","isCanonical": true},":evergreen_tree:":{"unicode":["1f332"],"fname":"1f332","uc":"1f332","isCanonical": true},":deciduous_tree:":{"unicode":["1f333"],"fname":"1f333","uc":"1f333","isCanonical": true},":lemon:":{"unicode":["1f34b"],"fname":"1f34b","uc":"1f34b","isCanonical": true},":pear:":{"unicode":["1f350"],"fname":"1f350","uc":"1f350","isCanonical": true},":baby_bottle:":{"unicode":["1f37c"],"fname":"1f37c","uc":"1f37c","isCanonical": true},":horse_racing:":{"unicode":["1f3c7"],"fname":"1f3c7","uc":"1f3c7","isCanonical": true},":rugby_football:":{"unicode":["1f3c9"],"fname":"1f3c9","uc":"1f3c9","isCanonical": true},":european_post_office:":{"unicode":["1f3e4"],"fname":"1f3e4","uc":"1f3e4","isCanonical": true},":rat:":{"unicode":["1f400"],"fname":"1f400","uc":"1f400","isCanonical": true},":mouse2:":{"unicode":["1f401"],"fname":"1f401","uc":"1f401","isCanonical": true},":ox:":{"unicode":["1f402"],"fname":"1f402","uc":"1f402","isCanonical": true},":water_buffalo:":{"unicode":["1f403"],"fname":"1f403","uc":"1f403","isCanonical": true},":cow2:":{"unicode":["1f404"],"fname":"1f404","uc":"1f404","isCanonical": true},":tiger2:":{"unicode":["1f405"],"fname":"1f405","uc":"1f405","isCanonical": true},":leopard:":{"unicode":["1f406"],"fname":"1f406","uc":"1f406","isCanonical": true},":rabbit2:":{"unicode":["1f407"],"fname":"1f407","uc":"1f407","isCanonical": true},":cat2:":{"unicode":["1f408"],"fname":"1f408","uc":"1f408","isCanonical": true},":dragon:":{"unicode":["1f409"],"fname":"1f409","uc":"1f409","isCanonical": true},":crocodile:":{"unicode":["1f40a"],"fname":"1f40a","uc":"1f40a","isCanonical": true},":whale2:":{"unicode":["1f40b"],"fname":"1f40b","uc":"1f40b","isCanonical": true},":ram:":{"unicode":["1f40f"],"fname":"1f40f","uc":"1f40f","isCanonical": true},":goat:":{"unicode":["1f410"],"fname":"1f410","uc":"1f410","isCanonical": true},":rooster:":{"unicode":["1f413"],"fname":"1f413","uc":"1f413","isCanonical": true},":dog2:":{"unicode":["1f415"],"fname":"1f415","uc":"1f415","isCanonical": true},":pig2:":{"unicode":["1f416"],"fname":"1f416","uc":"1f416","isCanonical": true},":dromedary_camel:":{"unicode":["1f42a"],"fname":"1f42a","uc":"1f42a","isCanonical": true},":busts_in_silhouette:":{"unicode":["1f465"],"fname":"1f465","uc":"1f465","isCanonical": true},":two_men_holding_hands:":{"unicode":["1f46c"],"fname":"1f46c","uc":"1f46c","isCanonical": true},":two_women_holding_hands:":{"unicode":["1f46d"],"fname":"1f46d","uc":"1f46d","isCanonical": true},":thought_balloon:":{"unicode":["1f4ad"],"fname":"1f4ad","uc":"1f4ad","isCanonical": true},":euro:":{"unicode":["1f4b6"],"fname":"1f4b6","uc":"1f4b6","isCanonical": true},":pound:":{"unicode":["1f4b7"],"fname":"1f4b7","uc":"1f4b7","isCanonical": true},":mailbox_with_mail:":{"unicode":["1f4ec"],"fname":"1f4ec","uc":"1f4ec","isCanonical": true},":mailbox_with_no_mail:":{"unicode":["1f4ed"],"fname":"1f4ed","uc":"1f4ed","isCanonical": true},":postal_horn:":{"unicode":["1f4ef"],"fname":"1f4ef","uc":"1f4ef","isCanonical": true},":no_mobile_phones:":{"unicode":["1f4f5"],"fname":"1f4f5","uc":"1f4f5","isCanonical": true},":twisted_rightwards_arrows:":{"unicode":["1f500"],"fname":"1f500","uc":"1f500","isCanonical": true},":repeat:":{"unicode":["1f501"],"fname":"1f501","uc":"1f501","isCanonical": true},":repeat_one:":{"unicode":["1f502"],"fname":"1f502","uc":"1f502","isCanonical": true},":arrows_counterclockwise:":{"unicode":["1f504"],"fname":"1f504","uc":"1f504","isCanonical": true},":low_brightness:":{"unicode":["1f505"],"fname":"1f505","uc":"1f505","isCanonical": true},":high_brightness:":{"unicode":["1f506"],"fname":"1f506","uc":"1f506","isCanonical": true},":mute:":{"unicode":["1f507"],"fname":"1f507","uc":"1f507","isCanonical": true},":sound:":{"unicode":["1f509"],"fname":"1f509","uc":"1f509","isCanonical": true},":no_bell:":{"unicode":["1f515"],"fname":"1f515","uc":"1f515","isCanonical": true},":microscope:":{"unicode":["1f52c"],"fname":"1f52c","uc":"1f52c","isCanonical": true},":telescope:":{"unicode":["1f52d"],"fname":"1f52d","uc":"1f52d","isCanonical": true},":clock130:":{"unicode":["1f55c"],"fname":"1f55c","uc":"1f55c","isCanonical": true},":clock230:":{"unicode":["1f55d"],"fname":"1f55d","uc":"1f55d","isCanonical": true},":clock330:":{"unicode":["1f55e"],"fname":"1f55e","uc":"1f55e","isCanonical": true},":clock430:":{"unicode":["1f55f"],"fname":"1f55f","uc":"1f55f","isCanonical": true},":clock530:":{"unicode":["1f560"],"fname":"1f560","uc":"1f560","isCanonical": true},":clock630:":{"unicode":["1f561"],"fname":"1f561","uc":"1f561","isCanonical": true},":clock730:":{"unicode":["1f562"],"fname":"1f562","uc":"1f562","isCanonical": true},":clock830:":{"unicode":["1f563"],"fname":"1f563","uc":"1f563","isCanonical": true},":clock930:":{"unicode":["1f564"],"fname":"1f564","uc":"1f564","isCanonical": true},":clock1030:":{"unicode":["1f565"],"fname":"1f565","uc":"1f565","isCanonical": true},":clock1130:":{"unicode":["1f566"],"fname":"1f566","uc":"1f566","isCanonical": true},":clock1230:":{"unicode":["1f567"],"fname":"1f567","uc":"1f567","isCanonical": true},":speaker:":{"unicode":["1f508"],"fname":"1f508","uc":"1f508","isCanonical": true},":train:":{"unicode":["1f68b"],"fname":"1f68b","uc":"1f68b","isCanonical": true},":medal:":{"unicode":["1f3c5"],"fname":"1f3c5","uc":"1f3c5","isCanonical": true},":sports_medal:":{"unicode":["1f3c5"],"fname":"1f3c5","uc":"1f3c5","isCanonical": false},":flag_black:":{"unicode":["1f3f4"],"fname":"1f3f4","uc":"1f3f4","isCanonical": true},":waving_black_flag:":{"unicode":["1f3f4"],"fname":"1f3f4","uc":"1f3f4","isCanonical": false},":camera_with_flash:":{"unicode":["1f4f8"],"fname":"1f4f8","uc":"1f4f8","isCanonical": true},":sleeping_accommodation:":{"unicode":["1f6cc"],"fname":"1f6cc","uc":"1f6cc","isCanonical": true},":middle_finger:":{"unicode":["1f595"],"fname":"1f595","uc":"1f595","isCanonical": true},":reversed_hand_with_middle_finger_extended:":{"unicode":["1f595"],"fname":"1f595","uc":"1f595","isCanonical": false},":vulcan:":{"unicode":["1f596"],"fname":"1f596","uc":"1f596","isCanonical": true},":raised_hand_with_part_between_middle_and_ring_fingers:":{"unicode":["1f596"],"fname":"1f596","uc":"1f596","isCanonical": false},":slight_frown:":{"unicode":["1f641"],"fname":"1f641","uc":"1f641","isCanonical": true},":slightly_frowning_face:":{"unicode":["1f641"],"fname":"1f641","uc":"1f641","isCanonical": false},":slight_smile:":{"unicode":["1f642"],"fname":"1f642","uc":"1f642","isCanonical": true},":slightly_smiling_face:":{"unicode":["1f642"],"fname":"1f642","uc":"1f642","isCanonical": false},":airplane_departure:":{"unicode":["1f6eb"],"fname":"1f6eb","uc":"1f6eb","isCanonical": true},":airplane_arriving:":{"unicode":["1f6ec"],"fname":"1f6ec","uc":"1f6ec","isCanonical": true},":tone1:":{"unicode":["1f3fb"],"fname":"1f3fb","uc":"1f3fb","isCanonical": true},":tone2:":{"unicode":["1f3fc"],"fname":"1f3fc","uc":"1f3fc","isCanonical": true},":tone3:":{"unicode":["1f3fd"],"fname":"1f3fd","uc":"1f3fd","isCanonical": true},":tone4:":{"unicode":["1f3fe"],"fname":"1f3fe","uc":"1f3fe","isCanonical": true},":tone5:":{"unicode":["1f3ff"],"fname":"1f3ff","uc":"1f3ff","isCanonical": true},":upside_down:":{"unicode":["1f643"],"fname":"1f643","uc":"1f643","isCanonical": true},":upside_down_face:":{"unicode":["1f643"],"fname":"1f643","uc":"1f643","isCanonical": false},":money_mouth:":{"unicode":["1f911"],"fname":"1f911","uc":"1f911","isCanonical": true},":money_mouth_face:":{"unicode":["1f911"],"fname":"1f911","uc":"1f911","isCanonical": false},":nerd:":{"unicode":["1f913"],"fname":"1f913","uc":"1f913","isCanonical": true},":nerd_face:":{"unicode":["1f913"],"fname":"1f913","uc":"1f913","isCanonical": false},":hugging:":{"unicode":["1f917"],"fname":"1f917","uc":"1f917","isCanonical": true},":hugging_face:":{"unicode":["1f917"],"fname":"1f917","uc":"1f917","isCanonical": false},":rolling_eyes:":{"unicode":["1f644"],"fname":"1f644","uc":"1f644","isCanonical": true},":face_with_rolling_eyes:":{"unicode":["1f644"],"fname":"1f644","uc":"1f644","isCanonical": false},":thinking:":{"unicode":["1f914"],"fname":"1f914","uc":"1f914","isCanonical": true},":thinking_face:":{"unicode":["1f914"],"fname":"1f914","uc":"1f914","isCanonical": false},":zipper_mouth:":{"unicode":["1f910"],"fname":"1f910","uc":"1f910","isCanonical": true},":zipper_mouth_face:":{"unicode":["1f910"],"fname":"1f910","uc":"1f910","isCanonical": false},":thermometer_face:":{"unicode":["1f912"],"fname":"1f912","uc":"1f912","isCanonical": true},":face_with_thermometer:":{"unicode":["1f912"],"fname":"1f912","uc":"1f912","isCanonical": false},":head_bandage:":{"unicode":["1f915"],"fname":"1f915","uc":"1f915","isCanonical": true},":face_with_head_bandage:":{"unicode":["1f915"],"fname":"1f915","uc":"1f915","isCanonical": false},":robot:":{"unicode":["1f916"],"fname":"1f916","uc":"1f916","isCanonical": true},":robot_face:":{"unicode":["1f916"],"fname":"1f916","uc":"1f916","isCanonical": false},":lion_face:":{"unicode":["1f981"],"fname":"1f981","uc":"1f981","isCanonical": true},":lion:":{"unicode":["1f981"],"fname":"1f981","uc":"1f981","isCanonical": false},":unicorn:":{"unicode":["1f984"],"fname":"1f984","uc":"1f984","isCanonical": true},":unicorn_face:":{"unicode":["1f984"],"fname":"1f984","uc":"1f984","isCanonical": false},":scorpion:":{"unicode":["1f982"],"fname":"1f982","uc":"1f982","isCanonical": true},":crab:":{"unicode":["1f980"],"fname":"1f980","uc":"1f980","isCanonical": true},":turkey:":{"unicode":["1f983"],"fname":"1f983","uc":"1f983","isCanonical": true},":cheese:":{"unicode":["1f9c0"],"fname":"1f9c0","uc":"1f9c0","isCanonical": true},":cheese_wedge:":{"unicode":["1f9c0"],"fname":"1f9c0","uc":"1f9c0","isCanonical": false},":hotdog:":{"unicode":["1f32d"],"fname":"1f32d","uc":"1f32d","isCanonical": true},":hot_dog:":{"unicode":["1f32d"],"fname":"1f32d","uc":"1f32d","isCanonical": false},":taco:":{"unicode":["1f32e"],"fname":"1f32e","uc":"1f32e","isCanonical": true},":burrito:":{"unicode":["1f32f"],"fname":"1f32f","uc":"1f32f","isCanonical": true},":popcorn:":{"unicode":["1f37f"],"fname":"1f37f","uc":"1f37f","isCanonical": true},":champagne:":{"unicode":["1f37e"],"fname":"1f37e","uc":"1f37e","isCanonical": true},":bottle_with_popping_cork:":{"unicode":["1f37e"],"fname":"1f37e","uc":"1f37e","isCanonical": false},":bow_and_arrow:":{"unicode":["1f3f9"],"fname":"1f3f9","uc":"1f3f9","isCanonical": true},":archery:":{"unicode":["1f3f9"],"fname":"1f3f9","uc":"1f3f9","isCanonical": false},":amphora:":{"unicode":["1f3fa"],"fname":"1f3fa","uc":"1f3fa","isCanonical": true},":place_of_worship:":{"unicode":["1f6d0"],"fname":"1f6d0","uc":"1f6d0","isCanonical": true},":worship_symbol:":{"unicode":["1f6d0"],"fname":"1f6d0","uc":"1f6d0","isCanonical": false},":kaaba:":{"unicode":["1f54b"],"fname":"1f54b","uc":"1f54b","isCanonical": true},":mosque:":{"unicode":["1f54c"],"fname":"1f54c","uc":"1f54c","isCanonical": true},":synagogue:":{"unicode":["1f54d"],"fname":"1f54d","uc":"1f54d","isCanonical": true},":menorah:":{"unicode":["1f54e"],"fname":"1f54e","uc":"1f54e","isCanonical": true},":prayer_beads:":{"unicode":["1f4ff"],"fname":"1f4ff","uc":"1f4ff","isCanonical": true},":cricket:":{"unicode":["1f3cf"],"fname":"1f3cf","uc":"1f3cf","isCanonical": true},":cricket_bat_ball:":{"unicode":["1f3cf"],"fname":"1f3cf","uc":"1f3cf","isCanonical": false},":volleyball:":{"unicode":["1f3d0"],"fname":"1f3d0","uc":"1f3d0","isCanonical": true},":field_hockey:":{"unicode":["1f3d1"],"fname":"1f3d1","uc":"1f3d1","isCanonical": true},":hockey:":{"unicode":["1f3d2"],"fname":"1f3d2","uc":"1f3d2","isCanonical": true},":ping_pong:":{"unicode":["1f3d3"],"fname":"1f3d3","uc":"1f3d3","isCanonical": true},":table_tennis:":{"unicode":["1f3d3"],"fname":"1f3d3","uc":"1f3d3","isCanonical": false},":badminton:":{"unicode":["1f3f8"],"fname":"1f3f8","uc":"1f3f8","isCanonical": true},":drum:":{"unicode":["1f941"],"fname":"1f941","uc":"1f941","isCanonical": true},":drum_with_drumsticks:":{"unicode":["1f941"],"fname":"1f941","uc":"1f941","isCanonical": false},":shrimp:":{"unicode":["1f990"],"fname":"1f990","uc":"1f990","isCanonical": true},":squid:":{"unicode":["1f991"],"fname":"1f991","uc":"1f991","isCanonical": true},":egg:":{"unicode":["1f95a"],"fname":"1f95a","uc":"1f95a","isCanonical": true},":milk:":{"unicode":["1f95b"],"fname":"1f95b","uc":"1f95b","isCanonical": true},":glass_of_milk:":{"unicode":["1f95b"],"fname":"1f95b","uc":"1f95b","isCanonical": false},":peanuts:":{"unicode":["1f95c"],"fname":"1f95c","uc":"1f95c","isCanonical": true},":shelled_peanut:":{"unicode":["1f95c"],"fname":"1f95c","uc":"1f95c","isCanonical": false},":kiwi:":{"unicode":["1f95d"],"fname":"1f95d","uc":"1f95d","isCanonical": true},":kiwifruit:":{"unicode":["1f95d"],"fname":"1f95d","uc":"1f95d","isCanonical": false},":pancakes:":{"unicode":["1f95e"],"fname":"1f95e","uc":"1f95e","isCanonical": true},":regional_indicator_w:":{"unicode":["1f1fc"],"fname":"1f1fc","uc":"1f1fc","isCanonical": true},":regional_indicator_v:":{"unicode":["1f1fb"],"fname":"1f1fb","uc":"1f1fb","isCanonical": true},":regional_indicator_u:":{"unicode":["1f1fa"],"fname":"1f1fa","uc":"1f1fa","isCanonical": true},":regional_indicator_t:":{"unicode":["1f1f9"],"fname":"1f1f9","uc":"1f1f9","isCanonical": true},":regional_indicator_s:":{"unicode":["1f1f8"],"fname":"1f1f8","uc":"1f1f8","isCanonical": true},":regional_indicator_r:":{"unicode":["1f1f7"],"fname":"1f1f7","uc":"1f1f7","isCanonical": true},":regional_indicator_q:":{"unicode":["1f1f6"],"fname":"1f1f6","uc":"1f1f6","isCanonical": true},":regional_indicator_p:":{"unicode":["1f1f5"],"fname":"1f1f5","uc":"1f1f5","isCanonical": true},":regional_indicator_o:":{"unicode":["1f1f4"],"fname":"1f1f4","uc":"1f1f4","isCanonical": true},":regional_indicator_n:":{"unicode":["1f1f3"],"fname":"1f1f3","uc":"1f1f3","isCanonical": true},":regional_indicator_m:":{"unicode":["1f1f2"],"fname":"1f1f2","uc":"1f1f2","isCanonical": true},":regional_indicator_l:":{"unicode":["1f1f1"],"fname":"1f1f1","uc":"1f1f1","isCanonical": true},":regional_indicator_k:":{"unicode":["1f1f0"],"fname":"1f1f0","uc":"1f1f0","isCanonical": true},":regional_indicator_j:":{"unicode":["1f1ef"],"fname":"1f1ef","uc":"1f1ef","isCanonical": true},":regional_indicator_i:":{"unicode":["1f1ee"],"fname":"1f1ee","uc":"1f1ee","isCanonical": true},":regional_indicator_h:":{"unicode":["1f1ed"],"fname":"1f1ed","uc":"1f1ed","isCanonical": true},":regional_indicator_g:":{"unicode":["1f1ec"],"fname":"1f1ec","uc":"1f1ec","isCanonical": true},":regional_indicator_f:":{"unicode":["1f1eb"],"fname":"1f1eb","uc":"1f1eb","isCanonical": true},":regional_indicator_e:":{"unicode":["1f1ea"],"fname":"1f1ea","uc":"1f1ea","isCanonical": true},":regional_indicator_d:":{"unicode":["1f1e9"],"fname":"1f1e9","uc":"1f1e9","isCanonical": true},":regional_indicator_c:":{"unicode":["1f1e8"],"fname":"1f1e8","uc":"1f1e8","isCanonical": true},":regional_indicator_b:":{"unicode":["1f1e7"],"fname":"1f1e7","uc":"1f1e7","isCanonical": true},":regional_indicator_a:":{"unicode":["1f1e6"],"fname":"1f1e6","uc":"1f1e6","isCanonical": true},":fast_forward:":{"unicode":["23e9"],"fname":"23e9","uc":"23e9","isCanonical": true},":rewind:":{"unicode":["23ea"],"fname":"23ea","uc":"23ea","isCanonical": true},":arrow_double_up:":{"unicode":["23eb"],"fname":"23eb","uc":"23eb","isCanonical": true},":arrow_double_down:":{"unicode":["23ec"],"fname":"23ec","uc":"23ec","isCanonical": true},":alarm_clock:":{"unicode":["23f0"],"fname":"23f0","uc":"23f0","isCanonical": true},":hourglass_flowing_sand:":{"unicode":["23f3"],"fname":"23f3","uc":"23f3","isCanonical": true},":ophiuchus:":{"unicode":["26ce"],"fname":"26ce","uc":"26ce","isCanonical": true},":white_check_mark:":{"unicode":["2705"],"fname":"2705","uc":"2705","isCanonical": true},":fist:":{"unicode":["270a"],"fname":"270a","uc":"270a","isCanonical": true},":raised_hand:":{"unicode":["270b"],"fname":"270b","uc":"270b","isCanonical": true},":sparkles:":{"unicode":["2728"],"fname":"2728","uc":"2728","isCanonical": true},":x:":{"unicode":["274c"],"fname":"274c","uc":"274c","isCanonical": true},":negative_squared_cross_mark:":{"unicode":["274e"],"fname":"274e","uc":"274e","isCanonical": true},":question:":{"unicode":["2753"],"fname":"2753","uc":"2753","isCanonical": true},":grey_question:":{"unicode":["2754"],"fname":"2754","uc":"2754","isCanonical": true},":grey_exclamation:":{"unicode":["2755"],"fname":"2755","uc":"2755","isCanonical": true},":heavy_plus_sign:":{"unicode":["2795"],"fname":"2795","uc":"2795","isCanonical": true},":heavy_minus_sign:":{"unicode":["2796"],"fname":"2796","uc":"2796","isCanonical": true},":heavy_division_sign:":{"unicode":["2797"],"fname":"2797","uc":"2797","isCanonical": true},":curly_loop:":{"unicode":["27b0"],"fname":"27b0","uc":"27b0","isCanonical": true},":loop:":{"unicode":["27bf"],"fname":"27bf","uc":"27bf","isCanonical": true}};
// ns.shortnames = Object.keys(ns.emojioneList).map(function(emoji) {
// return emoji.replace(/[+]/g, "\\$&");
// }).join('|');
@@ -40496,11 +48621,11 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
':D':'1f603',
':-D':'1f603',
'=D':'1f603',
- ':)':'1f604',
- ':-)':'1f604',
- '=]':'1f604',
- '=)':'1f604',
- ':]':'1f604',
+ ':)':'1f642',
+ ':-)':'1f642',
+ '=]':'1f642',
+ '=)':'1f642',
+ ':]':'1f642',
'\':)':'1f605',
'\':-)':'1f605',
'\'=)':'1f605',
@@ -40618,21 +48743,22 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
};
ns.asciiRegexp = '(\\<3|&lt;3|\\<\\/3|&lt;\\/3|\\:\'\\)|\\:\'\\-\\)|\\:D|\\:\\-D|\\=D|\\:\\)|\\:\\-\\)|\\=\\]|\\=\\)|\\:\\]|\'\\:\\)|\'\\:\\-\\)|\'\\=\\)|\'\\:D|\'\\:\\-D|\'\\=D|\\>\\:\\)|&gt;\\:\\)|\\>;\\)|&gt;;\\)|\\>\\:\\-\\)|&gt;\\:\\-\\)|\\>\\=\\)|&gt;\\=\\)|;\\)|;\\-\\)|\\*\\-\\)|\\*\\)|;\\-\\]|;\\]|;D|;\\^\\)|\'\\:\\(|\'\\:\\-\\(|\'\\=\\(|\\:\\*|\\:\\-\\*|\\=\\*|\\:\\^\\*|\\>\\:P|&gt;\\:P|X\\-P|x\\-p|\\>\\:\\[|&gt;\\:\\[|\\:\\-\\(|\\:\\(|\\:\\-\\[|\\:\\[|\\=\\(|\\>\\:\\(|&gt;\\:\\(|\\>\\:\\-\\(|&gt;\\:\\-\\(|\\:@|\\:\'\\(|\\:\'\\-\\(|;\\(|;\\-\\(|\\>\\.\\<|&gt;\\.&lt;|D\\:|\\:\\$|\\=\\$|#\\-\\)|#\\)|%\\-\\)|%\\)|X\\)|X\\-\\)|\\*\\\\0\\/\\*|\\\\0\\/|\\*\\\\O\\/\\*|\\\\O\\/|O\\:\\-\\)|0\\:\\-3|0\\:3|0\\:\\-\\)|0\\:\\)|0;\\^\\)|O\\:\\-\\)|O\\:\\)|O;\\-\\)|O\\=\\)|0;\\-\\)|O\\:\\-3|O\\:3|B\\-\\)|B\\)|8\\)|8\\-\\)|B\\-D|8\\-D|\\-_\\-|\\-__\\-|\\-___\\-|\\>\\:\\\\|&gt;\\:\\\\|\\>\\:\\/|&gt;\\:\\/|\\:\\-\\/|\\:\\-\\.|\\:\\/|\\:\\\\|\\=\\/|\\=\\\\|\\:L|\\=L|\\:P|\\:\\-P|\\=P|\\:\\-p|\\:p|\\=p|\\:\\-Þ|\\:\\-&THORN;|\\:Þ|\\:&THORN;|\\:þ|\\:&thorn;|\\:\\-þ|\\:\\-&thorn;|\\:\\-b|\\:b|d\\:|\\:\\-O|\\:O|\\:\\-o|\\:o|O_O|\\>\\:O|&gt;\\:O|\\:\\-X|\\:X|\\:\\-#|\\:#|\\=X|\\=x|\\:x|\\:\\-x|\\=#)';
// javascript escapes here must be ordered from largest length to shortest
- ns.unicodeRegexp = '(\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC67|\\uD83D\\uDC69\\u200D\\u2764\\uFE0F\\u200D\\uD83D\\uDC8B\\u200D\\uD83D\\uDC69|\\uD83D\\uDC68\\u200D\\uD83D\\uDC68\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC67|\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC66|\\uD83D\\uDC68\\u200D\\uD83D\\uDC68\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC67|\\uD83D\\uDC68\\u200D\\uD83D\\uDC68\\u200D\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC68\\u200D\\u2764\\uFE0F\\u200D\\uD83D\\uDC8B\\u200D\\uD83D\\uDC68|\\uD83D\\uDC68\\u200D\\u2764\\uFE0F\\u200D\\uD83D\\uDC68|\\uD83D\\uDC68\\u200D\\uD83D\\uDC68\\u200D\\uD83D\\uDC66|\\uD83D\\uDC68\\u200D\\uD83D\\uDC68\\u200D\\uD83D\\uDC67|\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67|\\uD83D\\uDC69\\u200D\\u2764\\uFE0F\\u200D\\uD83D\\uDC69|\\uD83D\\uDC41\\u200D\\uD83D\\uDDE8|\\uD83C\\uDFCB\\uD83C\\uDFFE|\\uD83E\\uDD18\\uD83C\\uDFFE|\\uD83E\\uDD18\\uD83C\\uDFFD|\\uD83E\\uDD18\\uD83C\\uDFFC|\\uD83E\\uDD18\\uD83C\\uDFFB|\\uD83D\\uDEC0\\uD83C\\uDFFF|\\uD83D\\uDEC0\\uD83C\\uDFFE|\\uD83D\\uDEC0\\uD83C\\uDFFD|\\uD83D\\uDEC0\\uD83C\\uDFFC|\\uD83D\\uDEC0\\uD83C\\uDFFB|\\uD83D\\uDEB6\\uD83C\\uDFFF|\\uD83D\\uDEB6\\uD83C\\uDFFE|\\uD83D\\uDEB6\\uD83C\\uDFFD|\\uD83D\\uDEB6\\uD83C\\uDFFC|\\uD83D\\uDEB6\\uD83C\\uDFFB|\\uD83D\\uDEB5\\uD83C\\uDFFF|\\uD83D\\uDEB5\\uD83C\\uDFFE|\\uD83D\\uDEB5\\uD83C\\uDFFD|\\uD83D\\uDEB5\\uD83C\\uDFFC|\\uD83D\\uDEB5\\uD83C\\uDFFB|\\uD83D\\uDEB4\\uD83C\\uDFFF|\\uD83D\\uDEB4\\uD83C\\uDFFE|\\uD83D\\uDEB4\\uD83C\\uDFFD|\\uD83D\\uDEB4\\uD83C\\uDFFC|\\uD83D\\uDEB4\\uD83C\\uDFFB|\\uD83D\\uDEA3\\uD83C\\uDFFF|\\uD83D\\uDEA3\\uD83C\\uDFFE|\\uD83D\\uDEA3\\uD83C\\uDFFD|\\uD83D\\uDEA3\\uD83C\\uDFFC|\\uD83D\\uDEA3\\uD83C\\uDFFB|\\uD83D\\uDE4F\\uD83C\\uDFFF|\\uD83D\\uDE4F\\uD83C\\uDFFE|\\uD83D\\uDE4F\\uD83C\\uDFFD|\\uD83D\\uDE4F\\uD83C\\uDFFC|\\uD83D\\uDE4F\\uD83C\\uDFFB|\\uD83D\\uDE4E\\uD83C\\uDFFF|\\uD83D\\uDE4E\\uD83C\\uDFFE|\\uD83D\\uDE4E\\uD83C\\uDFFD|\\uD83D\\uDE4E\\uD83C\\uDFFC|\\uD83D\\uDE4E\\uD83C\\uDFFB|\\uD83D\\uDE4D\\uD83C\\uDFFF|\\uD83D\\uDE4D\\uD83C\\uDFFE|\\uD83D\\uDE4D\\uD83C\\uDFFD|\\uD83D\\uDE4D\\uD83C\\uDFFC|\\uD83D\\uDE4D\\uD83C\\uDFFB|\\uD83D\\uDE4C\\uD83C\\uDFFF|\\uD83D\\uDE4C\\uD83C\\uDFFE|\\uD83D\\uDE4C\\uD83C\\uDFFD|\\uD83D\\uDE4C\\uD83C\\uDFFC|\\uD83D\\uDE4C\\uD83C\\uDFFB|\\uD83D\\uDE4B\\uD83C\\uDFFF|\\uD83D\\uDE4B\\uD83C\\uDFFE|\\uD83D\\uDE4B\\uD83C\\uDFFD|\\uD83D\\uDE4B\\uD83C\\uDFFC|\\uD83D\\uDE4B\\uD83C\\uDFFB|\\uD83D\\uDE47\\uD83C\\uDFFF|\\uD83D\\uDE47\\uD83C\\uDFFE|\\uD83D\\uDE47\\uD83C\\uDFFD|\\uD83D\\uDE47\\uD83C\\uDFFC|\\uD83D\\uDE47\\uD83C\\uDFFB|\\uD83D\\uDE46\\uD83C\\uDFFF|\\uD83D\\uDE46\\uD83C\\uDFFE|\\uD83D\\uDE46\\uD83C\\uDFFD|\\uD83D\\uDE46\\uD83C\\uDFFC|\\uD83D\\uDE46\\uD83C\\uDFFB|\\uD83D\\uDE45\\uD83C\\uDFFF|\\uD83D\\uDE45\\uD83C\\uDFFE|\\uD83D\\uDE45\\uD83C\\uDFFD|\\uD83D\\uDE45\\uD83C\\uDFFC|\\uD83D\\uDE45\\uD83C\\uDFFB|\\uD83D\\uDD96\\uD83C\\uDFFF|\\uD83D\\uDD96\\uD83C\\uDFFE|\\uD83D\\uDD96\\uD83C\\uDFFD|\\uD83D\\uDD96\\uD83C\\uDFFC|\\uD83D\\uDD96\\uD83C\\uDFFB|\\uD83D\\uDD95\\uD83C\\uDFFF|\\uD83D\\uDD95\\uD83C\\uDFFE|\\uD83D\\uDD95\\uD83C\\uDFFD|\\uD83D\\uDD95\\uD83C\\uDFFC|\\uD83D\\uDD95\\uD83C\\uDFFB|\\uD83D\\uDD90\\uD83C\\uDFFF|\\uD83D\\uDD90\\uD83C\\uDFFE|\\uD83D\\uDD90\\uD83C\\uDFFD|\\uD83D\\uDD90\\uD83C\\uDFFC|\\uD83D\\uDD90\\uD83C\\uDFFB|\\uD83D\\uDD75\\uD83C\\uDFFF|\\uD83D\\uDD75\\uD83C\\uDFFE|\\uD83D\\uDD75\\uD83C\\uDFFD|\\uD83D\\uDD75\\uD83C\\uDFFC|\\uD83D\\uDD75\\uD83C\\uDFFB|\\uD83D\\uDCAA\\uD83C\\uDFFF|\\uD83D\\uDCAA\\uD83C\\uDFFE|\\uD83D\\uDCAA\\uD83C\\uDFFD|\\uD83D\\uDCAA\\uD83C\\uDFFC|\\uD83D\\uDCAA\\uD83C\\uDFFB|\\uD83D\\uDC87\\uD83C\\uDFFF|\\uD83D\\uDC87\\uD83C\\uDFFE|\\uD83D\\uDC87\\uD83C\\uDFFD|\\uD83D\\uDC87\\uD83C\\uDFFC|\\uD83D\\uDC87\\uD83C\\uDFFB|\\uD83D\\uDC86\\uD83C\\uDFFF|\\uD83D\\uDC86\\uD83C\\uDFFE|\\uD83D\\uDC86\\uD83C\\uDFFD|\\uD83D\\uDC86\\uD83C\\uDFFC|\\uD83D\\uDC86\\uD83C\\uDFFB|\\uD83D\\uDC85\\uD83C\\uDFFF|\\uD83D\\uDC85\\uD83C\\uDFFE|\\uD83D\\uDC85\\uD83C\\uDFFD|\\uD83D\\uDC85\\uD83C\\uDFFC|\\uD83D\\uDC85\\uD83C\\uDFFB|\\uD83D\\uDC83\\uD83C\\uDFFF|\\uD83D\\uDC83\\uD83C\\uDFFE|\\uD83D\\uDC83\\uD83C\\uDFFD|\\uD83D\\uDC83\\uD83C\\uDFFC|\\uD83D\\uDC83\\uD83C\\uDFFB|\\uD83D\\uDC82\\uD83C\\uDFFF|\\uD83D\\uDC82\\uD83C\\uDFFE|\\uD83D\\uDC82\\uD83C\\uDFFD|\\uD83D\\uDC82\\uD83C\\uDFFC|\\uD83D\\uDC82\\uD83C\\uDFFB|\\uD83D\\uDC81\\uD83C\\uDFFF|\\uD83D\\uDC81\\uD83C\\uDFFE|\\uD83D\\uDC81\\uD83C\\uDFFD|\\uD83D\\uDC81\\uD83C\\uDFFC|\\uD83D\\uDC81\\uD83C\\uDFFB|\\uD83D\\uDC7C\\uD83C\\uDFFF|\\uD83D\\uDC7C\\uD83C\\uDFFE|\\uD83D\\uDC7C\\uD83C\\uDFFD|\\uD83D\\uDC7C\\uD83C\\uDFFC|\\uD83D\\uDC7C\\uD83C\\uDFFB|\\uD83D\\uDC78\\uD83C\\uDFFF|\\uD83D\\uDC78\\uD83C\\uDFFE|\\uD83D\\uDC78\\uD83C\\uDFFD|\\uD83D\\uDC78\\uD83C\\uDFFC|\\uD83D\\uDC78\\uD83C\\uDFFB|\\uD83D\\uDC77\\uD83C\\uDFFF|\\uD83D\\uDC77\\uD83C\\uDFFE|\\uD83D\\uDC77\\uD83C\\uDFFD|\\uD83D\\uDC77\\uD83C\\uDFFC|\\uD83D\\uDC77\\uD83C\\uDFFB|\\uD83D\\uDC76\\uD83C\\uDFFF|\\uD83D\\uDC76\\uD83C\\uDFFE|\\uD83D\\uDC76\\uD83C\\uDFFD|\\uD83D\\uDC76\\uD83C\\uDFFC|\\uD83D\\uDC76\\uD83C\\uDFFB|\\uD83D\\uDC75\\uD83C\\uDFFF|\\uD83D\\uDC75\\uD83C\\uDFFE|\\uD83D\\uDC75\\uD83C\\uDFFD|\\uD83D\\uDC75\\uD83C\\uDFFC|\\uD83D\\uDC75\\uD83C\\uDFFB|\\uD83D\\uDC74\\uD83C\\uDFFF|\\uD83D\\uDC74\\uD83C\\uDFFE|\\uD83D\\uDC74\\uD83C\\uDFFD|\\uD83D\\uDC74\\uD83C\\uDFFC|\\uD83D\\uDC74\\uD83C\\uDFFB|\\uD83D\\uDC73\\uD83C\\uDFFF|\\uD83D\\uDC73\\uD83C\\uDFFE|\\uD83D\\uDC73\\uD83C\\uDFFD|\\uD83D\\uDC73\\uD83C\\uDFFC|\\uD83D\\uDC73\\uD83C\\uDFFB|\\uD83D\\uDC72\\uD83C\\uDFFF|\\uD83D\\uDC72\\uD83C\\uDFFE|\\uD83D\\uDC72\\uD83C\\uDFFD|\\uD83D\\uDC72\\uD83C\\uDFFC|\\uD83D\\uDC72\\uD83C\\uDFFB|\\uD83D\\uDC71\\uD83C\\uDFFF|\\uD83D\\uDC71\\uD83C\\uDFFE|\\uD83D\\uDC71\\uD83C\\uDFFD|\\uD83D\\uDC71\\uD83C\\uDFFC|\\uD83D\\uDC71\\uD83C\\uDFFB|\\uD83D\\uDC70\\uD83C\\uDFFF|\\uD83D\\uDC70\\uD83C\\uDFFE|\\uD83D\\uDC70\\uD83C\\uDFFD|\\uD83D\\uDC70\\uD83C\\uDFFC|\\uD83D\\uDC70\\uD83C\\uDFFB|\\uD83D\\uDC6E\\uD83C\\uDFFF|\\uD83D\\uDC6E\\uD83C\\uDFFE|\\uD83D\\uDC6E\\uD83C\\uDFFD|\\uD83D\\uDC6E\\uD83C\\uDFFC|\\uD83D\\uDC6E\\uD83C\\uDFFB|\\uD83D\\uDC69\\uD83C\\uDFFF|\\uD83D\\uDC69\\uD83C\\uDFFE|\\uD83D\\uDC69\\uD83C\\uDFFD|\\uD83D\\uDC69\\uD83C\\uDFFC|\\uD83D\\uDC69\\uD83C\\uDFFB|\\uD83D\\uDC68\\uD83C\\uDFFF|\\uD83D\\uDC68\\uD83C\\uDFFE|\\uD83D\\uDC68\\uD83C\\uDFFD|\\uD83D\\uDC68\\uD83C\\uDFFC|\\uD83D\\uDC68\\uD83C\\uDFFB|\\uD83D\\uDC67\\uD83C\\uDFFF|\\uD83D\\uDC67\\uD83C\\uDFFE|\\uD83D\\uDC67\\uD83C\\uDFFD|\\uD83D\\uDC67\\uD83C\\uDFFC|\\uD83D\\uDC67\\uD83C\\uDFFB|\\uD83D\\uDC66\\uD83C\\uDFFF|\\uD83D\\uDC66\\uD83C\\uDFFE|\\uD83D\\uDC66\\uD83C\\uDFFD|\\uD83D\\uDC66\\uD83C\\uDFFC|\\uD83D\\uDC66\\uD83C\\uDFFB|\\uD83D\\uDC50\\uD83C\\uDFFF|\\uD83D\\uDC50\\uD83C\\uDFFE|\\uD83D\\uDC50\\uD83C\\uDFFD|\\uD83D\\uDC50\\uD83C\\uDFFC|\\uD83D\\uDC50\\uD83C\\uDFFB|\\uD83D\\uDC4F\\uD83C\\uDFFF|\\uD83D\\uDC4F\\uD83C\\uDFFE|\\uD83D\\uDC4F\\uD83C\\uDFFD|\\uD83D\\uDC4F\\uD83C\\uDFFC|\\uD83D\\uDC4F\\uD83C\\uDFFB|\\uD83D\\uDC4E\\uD83C\\uDFFF|\\uD83D\\uDC4E\\uD83C\\uDFFE|\\uD83D\\uDC4E\\uD83C\\uDFFD|\\uD83D\\uDC4E\\uD83C\\uDFFC|\\uD83D\\uDC4E\\uD83C\\uDFFB|\\uD83D\\uDC4D\\uD83C\\uDFFF|\\uD83D\\uDC4D\\uD83C\\uDFFE|\\uD83D\\uDC4D\\uD83C\\uDFFD|\\uD83D\\uDC4D\\uD83C\\uDFFC|\\uD83D\\uDC4D\\uD83C\\uDFFB|\\uD83D\\uDC4C\\uD83C\\uDFFF|\\uD83D\\uDC4C\\uD83C\\uDFFE|\\uD83D\\uDC4C\\uD83C\\uDFFD|\\uD83D\\uDC4C\\uD83C\\uDFFC|\\uD83D\\uDC4C\\uD83C\\uDFFB|\\uD83D\\uDC4B\\uD83C\\uDFFF|\\uD83D\\uDC4B\\uD83C\\uDFFE|\\uD83D\\uDC4B\\uD83C\\uDFFD|\\uD83D\\uDC4B\\uD83C\\uDFFC|\\uD83D\\uDC4B\\uD83C\\uDFFB|\\uD83D\\uDC4A\\uD83C\\uDFFF|\\uD83D\\uDC4A\\uD83C\\uDFFE|\\uD83D\\uDC4A\\uD83C\\uDFFD|\\uD83D\\uDC4A\\uD83C\\uDFFC|\\uD83D\\uDC4A\\uD83C\\uDFFB|\\uD83D\\uDC49\\uD83C\\uDFFF|\\uD83D\\uDC49\\uD83C\\uDFFE|\\uD83D\\uDC49\\uD83C\\uDFFD|\\uD83D\\uDC49\\uD83C\\uDFFC|\\uD83D\\uDC49\\uD83C\\uDFFB|\\uD83D\\uDC48\\uD83C\\uDFFF|\\uD83D\\uDC48\\uD83C\\uDFFE|\\uD83D\\uDC48\\uD83C\\uDFFD|\\uD83D\\uDC48\\uD83C\\uDFFC|\\uD83D\\uDC48\\uD83C\\uDFFB|\\uD83D\\uDC47\\uD83C\\uDFFF|\\uD83D\\uDC47\\uD83C\\uDFFE|\\uD83D\\uDC47\\uD83C\\uDFFD|\\uD83D\\uDC47\\uD83C\\uDFFC|\\uD83D\\uDC47\\uD83C\\uDFFB|\\uD83D\\uDC46\\uD83C\\uDFFF|\\uD83D\\uDC46\\uD83C\\uDFFE|\\uD83D\\uDC46\\uD83C\\uDFFD|\\uD83D\\uDC46\\uD83C\\uDFFC|\\uD83D\\uDC46\\uD83C\\uDFFB|\\uD83D\\uDC43\\uD83C\\uDFFF|\\uD83D\\uDC43\\uD83C\\uDFFE|\\uD83D\\uDC43\\uD83C\\uDFFD|\\uD83D\\uDC43\\uD83C\\uDFFC|\\uD83D\\uDC43\\uD83C\\uDFFB|\\uD83D\\uDC42\\uD83C\\uDFFF|\\uD83D\\uDC42\\uD83C\\uDFFE|\\uD83D\\uDC42\\uD83C\\uDFFD|\\uD83D\\uDC42\\uD83C\\uDFFC|\\uD83D\\uDC42\\uD83C\\uDFFB|\\uD83C\\uDFCB\\uD83C\\uDFFF|\\uD83C\\uDFC7\\uD83C\\uDFFD|\\uD83C\\uDFCB\\uD83C\\uDFFD|\\uD83C\\uDFCB\\uD83C\\uDFFC|\\uD83C\\uDFCB\\uD83C\\uDFFB|\\uD83C\\uDFCA\\uD83C\\uDFFF|\\uD83C\\uDFCA\\uD83C\\uDFFE|\\uD83C\\uDFCA\\uD83C\\uDFFD|\\uD83C\\uDFCA\\uD83C\\uDFFC|\\uD83C\\uDFCA\\uD83C\\uDFFB|\\uD83C\\uDFC7\\uD83C\\uDFFF|\\uD83C\\uDFC7\\uD83C\\uDFFE|\\uD83E\\uDD18\\uD83C\\uDFFF|\\uD83C\\uDFC7\\uD83C\\uDFFC|\\uD83C\\uDFC7\\uD83C\\uDFFB|\\uD83C\\uDFC4\\uD83C\\uDFFF|\\uD83C\\uDFC4\\uD83C\\uDFFE|\\uD83C\\uDFC4\\uD83C\\uDFFD|\\uD83C\\uDFC4\\uD83C\\uDFFC|\\uD83C\\uDFC4\\uD83C\\uDFFB|\\uD83C\\uDFC3\\uD83C\\uDFFF|\\uD83C\\uDFC3\\uD83C\\uDFFE|\\uD83C\\uDFC3\\uD83C\\uDFFD|\\uD83C\\uDFC3\\uD83C\\uDFFC|\\uD83C\\uDFC3\\uD83C\\uDFFB|\\uD83C\\uDF85\\uD83C\\uDFFF|\\uD83C\\uDF85\\uD83C\\uDFFE|\\uD83C\\uDF85\\uD83C\\uDFFD|\\uD83C\\uDF85\\uD83C\\uDFFC|\\uD83C\\uDF85\\uD83C\\uDFFB|\\uD83C\\uDDFF\\uD83C\\uDDFC|\\uD83C\\uDDFF\\uD83C\\uDDF2|\\uD83C\\uDDFF\\uD83C\\uDDE6|\\uD83C\\uDDFE\\uD83C\\uDDF9|\\uD83C\\uDDFE\\uD83C\\uDDEA|\\uD83C\\uDDFD\\uD83C\\uDDF0|\\uD83C\\uDDFC\\uD83C\\uDDF8|\\uD83C\\uDDFC\\uD83C\\uDDEB|\\uD83C\\uDDFB\\uD83C\\uDDFA|\\uD83C\\uDDFB\\uD83C\\uDDF3|\\uD83C\\uDDFB\\uD83C\\uDDEE|\\uD83C\\uDDFB\\uD83C\\uDDEC|\\uD83C\\uDDFB\\uD83C\\uDDEA|\\uD83C\\uDDFB\\uD83C\\uDDE8|\\uD83C\\uDDFB\\uD83C\\uDDE6|\\uD83C\\uDDFA\\uD83C\\uDDFF|\\uD83C\\uDDFA\\uD83C\\uDDFE|\\uD83C\\uDDFA\\uD83C\\uDDF8|\\uD83C\\uDDFA\\uD83C\\uDDF2|\\uD83C\\uDDFA\\uD83C\\uDDEC|\\uD83C\\uDDFA\\uD83C\\uDDE6|\\uD83C\\uDDF9\\uD83C\\uDDFF|\\uD83C\\uDDF9\\uD83C\\uDDFC|\\uD83C\\uDDF9\\uD83C\\uDDFB|\\uD83C\\uDDF9\\uD83C\\uDDF9|\\uD83C\\uDDF9\\uD83C\\uDDF7|\\uD83C\\uDDF9\\uD83C\\uDDF4|\\uD83C\\uDDF9\\uD83C\\uDDF3|\\uD83C\\uDDF9\\uD83C\\uDDF2|\\uD83C\\uDDF9\\uD83C\\uDDF1|\\uD83C\\uDDF9\\uD83C\\uDDF0|\\uD83C\\uDDF9\\uD83C\\uDDEF|\\uD83C\\uDDF9\\uD83C\\uDDED|\\uD83C\\uDDF9\\uD83C\\uDDEC|\\uD83C\\uDDF9\\uD83C\\uDDEB|\\uD83C\\uDDF9\\uD83C\\uDDE9|\\uD83C\\uDDF9\\uD83C\\uDDE8|\\uD83C\\uDDF9\\uD83C\\uDDE6|\\uD83C\\uDDF8\\uD83C\\uDDFF|\\uD83C\\uDDF8\\uD83C\\uDDFE|\\uD83C\\uDDF8\\uD83C\\uDDFD|\\uD83C\\uDDF8\\uD83C\\uDDFB|\\uD83C\\uDDF8\\uD83C\\uDDF9|\\uD83C\\uDDF8\\uD83C\\uDDF8|\\uD83C\\uDDF8\\uD83C\\uDDF7|\\uD83C\\uDDF8\\uD83C\\uDDF4|\\uD83C\\uDDF8\\uD83C\\uDDF3|\\uD83C\\uDDF8\\uD83C\\uDDF2|\\uD83C\\uDDF8\\uD83C\\uDDF1|\\uD83C\\uDDF8\\uD83C\\uDDF0|\\uD83C\\uDDF8\\uD83C\\uDDEF|\\uD83C\\uDDF8\\uD83C\\uDDEE|\\uD83C\\uDDF8\\uD83C\\uDDED|\\uD83C\\uDDF8\\uD83C\\uDDEC|\\uD83C\\uDDF8\\uD83C\\uDDEA|\\uD83C\\uDDF8\\uD83C\\uDDE9|\\uD83C\\uDDF8\\uD83C\\uDDE8|\\uD83C\\uDDF8\\uD83C\\uDDE7|\\uD83C\\uDDF8\\uD83C\\uDDE6|\\uD83C\\uDDF7\\uD83C\\uDDFC|\\uD83C\\uDDF7\\uD83C\\uDDFA|\\uD83C\\uDDF7\\uD83C\\uDDF8|\\uD83C\\uDDF7\\uD83C\\uDDF4|\\uD83C\\uDDF7\\uD83C\\uDDEA|\\uD83C\\uDDF6\\uD83C\\uDDE6|\\uD83C\\uDDF5\\uD83C\\uDDFE|\\uD83C\\uDDF5\\uD83C\\uDDFC|\\uD83C\\uDDF5\\uD83C\\uDDF9|\\uD83C\\uDDF5\\uD83C\\uDDF8|\\uD83C\\uDDF5\\uD83C\\uDDF7|\\uD83C\\uDDF5\\uD83C\\uDDF3|\\uD83C\\uDDF5\\uD83C\\uDDF2|\\uD83C\\uDDF5\\uD83C\\uDDF1|\\uD83C\\uDDF5\\uD83C\\uDDF0|\\uD83C\\uDDF5\\uD83C\\uDDED|\\uD83C\\uDDF5\\uD83C\\uDDEC|\\uD83C\\uDDF5\\uD83C\\uDDEB|\\uD83C\\uDDF5\\uD83C\\uDDEA|\\uD83C\\uDDF5\\uD83C\\uDDE6|\\uD83C\\uDDF4\\uD83C\\uDDF2|\\uD83C\\uDDF3\\uD83C\\uDDFF|\\uD83C\\uDDF3\\uD83C\\uDDFA|\\uD83C\\uDDF3\\uD83C\\uDDF7|\\uD83C\\uDDF3\\uD83C\\uDDF5|\\uD83C\\uDDF3\\uD83C\\uDDF4|\\uD83C\\uDDF3\\uD83C\\uDDF1|\\uD83C\\uDDF3\\uD83C\\uDDEE|\\uD83C\\uDDF3\\uD83C\\uDDEC|\\uD83C\\uDDF3\\uD83C\\uDDEB|\\uD83C\\uDDF3\\uD83C\\uDDEA|\\uD83C\\uDDF3\\uD83C\\uDDE8|\\uD83C\\uDDF3\\uD83C\\uDDE6|\\uD83C\\uDDF2\\uD83C\\uDDFF|\\uD83C\\uDDF2\\uD83C\\uDDFE|\\uD83C\\uDDF2\\uD83C\\uDDFD|\\uD83C\\uDDF2\\uD83C\\uDDFC|\\uD83C\\uDDF2\\uD83C\\uDDFB|\\uD83C\\uDDF2\\uD83C\\uDDFA|\\uD83C\\uDDF2\\uD83C\\uDDF9|\\uD83C\\uDDF2\\uD83C\\uDDF8|\\uD83C\\uDDF2\\uD83C\\uDDF7|\\uD83C\\uDDF2\\uD83C\\uDDF6|\\uD83C\\uDDF2\\uD83C\\uDDF5|\\uD83C\\uDDF2\\uD83C\\uDDF4|\\uD83C\\uDDF2\\uD83C\\uDDF3|\\uD83C\\uDDF2\\uD83C\\uDDF2|\\uD83C\\uDDF2\\uD83C\\uDDF1|\\uD83C\\uDDF2\\uD83C\\uDDF0|\\uD83C\\uDDF2\\uD83C\\uDDED|\\uD83C\\uDDF2\\uD83C\\uDDEC|\\uD83C\\uDDF2\\uD83C\\uDDEB|\\uD83C\\uDDF2\\uD83C\\uDDEA|\\uD83C\\uDDF2\\uD83C\\uDDE9|\\uD83C\\uDDF2\\uD83C\\uDDE8|\\uD83C\\uDDF2\\uD83C\\uDDE6|\\uD83C\\uDDF1\\uD83C\\uDDFE|\\uD83C\\uDDF1\\uD83C\\uDDFB|\\uD83C\\uDDF1\\uD83C\\uDDFA|\\uD83C\\uDDF1\\uD83C\\uDDF9|\\uD83C\\uDDF1\\uD83C\\uDDF8|\\uD83C\\uDDF1\\uD83C\\uDDF7|\\uD83C\\uDDF1\\uD83C\\uDDF0|\\uD83C\\uDDF1\\uD83C\\uDDEE|\\uD83C\\uDDF1\\uD83C\\uDDE8|\\uD83C\\uDDF1\\uD83C\\uDDE7|\\uD83C\\uDDF1\\uD83C\\uDDE6|\\uD83C\\uDDF0\\uD83C\\uDDFF|\\uD83C\\uDDF0\\uD83C\\uDDFE|\\uD83C\\uDDF0\\uD83C\\uDDFC|\\uD83C\\uDDF0\\uD83C\\uDDF7|\\uD83C\\uDDF0\\uD83C\\uDDF5|\\uD83C\\uDDF0\\uD83C\\uDDF3|\\uD83C\\uDDF0\\uD83C\\uDDF2|\\uD83C\\uDDF0\\uD83C\\uDDEE|\\uD83C\\uDDF0\\uD83C\\uDDED|\\uD83C\\uDDF0\\uD83C\\uDDEC|\\uD83C\\uDDF0\\uD83C\\uDDEA|\\uD83C\\uDDEF\\uD83C\\uDDF5|\\uD83C\\uDDEF\\uD83C\\uDDF4|\\uD83C\\uDDEF\\uD83C\\uDDF2|\\uD83C\\uDDEF\\uD83C\\uDDEA|\\uD83C\\uDDEE\\uD83C\\uDDF9|\\uD83C\\uDDEE\\uD83C\\uDDF8|\\uD83C\\uDDEE\\uD83C\\uDDF7|\\uD83C\\uDDEE\\uD83C\\uDDF6|\\uD83C\\uDDEE\\uD83C\\uDDF4|\\uD83C\\uDDEE\\uD83C\\uDDF3|\\uD83C\\uDDEE\\uD83C\\uDDF2|\\uD83C\\uDDEE\\uD83C\\uDDF1|\\uD83C\\uDDEE\\uD83C\\uDDEA|\\uD83C\\uDDEE\\uD83C\\uDDE9|\\uD83C\\uDDEE\\uD83C\\uDDE8|\\uD83C\\uDDED\\uD83C\\uDDFA|\\uD83C\\uDDED\\uD83C\\uDDF9|\\uD83C\\uDDED\\uD83C\\uDDF7|\\uD83C\\uDDED\\uD83C\\uDDF3|\\uD83C\\uDDED\\uD83C\\uDDF2|\\uD83C\\uDDED\\uD83C\\uDDF0|\\uD83C\\uDDEC\\uD83C\\uDDFE|\\uD83C\\uDDEC\\uD83C\\uDDFC|\\uD83C\\uDDEC\\uD83C\\uDDFA|\\uD83C\\uDDEC\\uD83C\\uDDF9|\\uD83C\\uDDEC\\uD83C\\uDDF8|\\uD83C\\uDDEC\\uD83C\\uDDF7|\\uD83C\\uDDEC\\uD83C\\uDDF6|\\uD83C\\uDDEC\\uD83C\\uDDF5|\\uD83C\\uDDEC\\uD83C\\uDDF3|\\uD83C\\uDDEC\\uD83C\\uDDF2|\\uD83C\\uDDEC\\uD83C\\uDDF1|\\uD83C\\uDDEC\\uD83C\\uDDEE|\\uD83C\\uDDEC\\uD83C\\uDDED|\\uD83C\\uDDEC\\uD83C\\uDDEC|\\uD83C\\uDDEC\\uD83C\\uDDEB|\\uD83C\\uDDEC\\uD83C\\uDDEA|\\uD83C\\uDDEC\\uD83C\\uDDE9|\\uD83C\\uDDEC\\uD83C\\uDDE7|\\uD83C\\uDDEC\\uD83C\\uDDE6|\\uD83C\\uDDEB\\uD83C\\uDDF7|\\uD83C\\uDDEB\\uD83C\\uDDF4|\\uD83C\\uDDEB\\uD83C\\uDDF2|\\uD83C\\uDDEB\\uD83C\\uDDF0|\\uD83C\\uDDEB\\uD83C\\uDDEF|\\uD83C\\uDDEB\\uD83C\\uDDEE|\\uD83C\\uDDEA\\uD83C\\uDDFA|\\uD83C\\uDDEA\\uD83C\\uDDF9|\\uD83C\\uDDEA\\uD83C\\uDDF8|\\uD83C\\uDDEA\\uD83C\\uDDF7|\\uD83C\\uDDEA\\uD83C\\uDDED|\\uD83C\\uDDEA\\uD83C\\uDDEC|\\uD83C\\uDDEA\\uD83C\\uDDEA|\\uD83C\\uDDEA\\uD83C\\uDDE8|\\uD83C\\uDDEA\\uD83C\\uDDE6|\\uD83C\\uDDE9\\uD83C\\uDDFF|\\uD83C\\uDDE9\\uD83C\\uDDF4|\\uD83C\\uDDE9\\uD83C\\uDDF2|\\uD83C\\uDDE9\\uD83C\\uDDF0|\\uD83C\\uDDE9\\uD83C\\uDDEF|\\uD83C\\uDDE9\\uD83C\\uDDEC|\\uD83C\\uDDE9\\uD83C\\uDDEA|\\uD83C\\uDDE8\\uD83C\\uDDFF|\\uD83C\\uDDE8\\uD83C\\uDDFE|\\uD83C\\uDDE8\\uD83C\\uDDFD|\\uD83C\\uDDE8\\uD83C\\uDDFC|\\uD83C\\uDDE8\\uD83C\\uDDFB|\\uD83C\\uDDE8\\uD83C\\uDDFA|\\uD83C\\uDDE8\\uD83C\\uDDF7|\\uD83C\\uDDE8\\uD83C\\uDDF5|\\uD83C\\uDDE8\\uD83C\\uDDF4|\\uD83C\\uDDE8\\uD83C\\uDDF3|\\uD83C\\uDDE8\\uD83C\\uDDF2|\\uD83C\\uDDE8\\uD83C\\uDDF1|\\uD83C\\uDDE8\\uD83C\\uDDF0|\\uD83C\\uDDE8\\uD83C\\uDDEE|\\uD83C\\uDDE8\\uD83C\\uDDED|\\uD83C\\uDDE8\\uD83C\\uDDEC|\\uD83C\\uDDE8\\uD83C\\uDDEB|\\uD83C\\uDDE8\\uD83C\\uDDE9|\\uD83C\\uDDE8\\uD83C\\uDDE8|\\uD83C\\uDDE8\\uD83C\\uDDE6|\\uD83C\\uDDE7\\uD83C\\uDDFF|\\uD83C\\uDDE7\\uD83C\\uDDFE|\\uD83C\\uDDE7\\uD83C\\uDDFC|\\uD83C\\uDDE7\\uD83C\\uDDFB|\\uD83C\\uDDE7\\uD83C\\uDDF9|\\uD83C\\uDDE7\\uD83C\\uDDF8|\\uD83C\\uDDE7\\uD83C\\uDDF7|\\uD83C\\uDDE7\\uD83C\\uDDF6|\\uD83C\\uDDE7\\uD83C\\uDDF4|\\uD83C\\uDDE7\\uD83C\\uDDF3|\\uD83C\\uDDE7\\uD83C\\uDDF2|\\uD83C\\uDDE7\\uD83C\\uDDF1|\\uD83C\\uDDE7\\uD83C\\uDDEF|\\uD83C\\uDDE7\\uD83C\\uDDEE|\\uD83C\\uDDE7\\uD83C\\uDDED|\\uD83C\\uDDE7\\uD83C\\uDDEC|\\uD83C\\uDDE7\\uD83C\\uDDEB|\\uD83C\\uDDE7\\uD83C\\uDDEA|\\uD83C\\uDDE7\\uD83C\\uDDE9|\\uD83C\\uDDE7\\uD83C\\uDDE7|\\uD83C\\uDDE7\\uD83C\\uDDE6|\\uD83C\\uDDE6\\uD83C\\uDDFF|\\uD83C\\uDDE6\\uD83C\\uDDFD|\\uD83C\\uDDE6\\uD83C\\uDDFC|\\uD83C\\uDDE6\\uD83C\\uDDFA|\\uD83C\\uDDE6\\uD83C\\uDDF9|\\uD83C\\uDDE6\\uD83C\\uDDF8|\\uD83C\\uDDE6\\uD83C\\uDDF7|\\uD83C\\uDDE6\\uD83C\\uDDF6|\\uD83C\\uDDE6\\uD83C\\uDDF4|\\uD83C\\uDDE6\\uD83C\\uDDF2|\\uD83C\\uDDE6\\uD83C\\uDDF1|\\uD83C\\uDDE6\\uD83C\\uDDEE|\\uD83C\\uDDE6\\uD83C\\uDDEC|\\uD83C\\uDDE6\\uD83C\\uDDEB|\\uD83C\\uDDE6\\uD83C\\uDDEA|\\uD83C\\uDDE6\\uD83C\\uDDE9|\\uD83C\\uDDE6\\uD83C\\uDDE8|\\u270D\\uD83C\\uDFFE|\\u270D\\uD83C\\uDFFD|\\u270D\\uD83C\\uDFFC|\\u270D\\uD83C\\uDFFB|\\u270B\\uD83C\\uDFFF|\\u270B\\uD83C\\uDFFE|\\u270B\\uD83C\\uDFFD|\\u26F9\\uD83C\\uDFFF|\\u26F9\\uD83C\\uDFFE|\\u26F9\\uD83C\\uDFFD|\\u26F9\\uD83C\\uDFFC|\\u26F9\\uD83C\\uDFFB|\\u270D\\uD83C\\uDFFF|\\uD83C\\uDC04\\uFE0F|\\uD83C\\uDD7F\\uFE0F|\\uD83C\\uDE1A\\uFE0F|\\uD83C\\uDE2F\\uFE0F|\\uD83C\\uDE37\\uFE0F|\\u261D\\uD83C\\uDFFB|\\u261D\\uD83C\\uDFFC|\\u261D\\uD83C\\uDFFD|\\u261D\\uD83C\\uDFFE|\\u261D\\uD83C\\uDFFF|\\u270C\\uD83C\\uDFFB|\\u270C\\uD83C\\uDFFC|\\u270C\\uD83C\\uDFFD|\\u270C\\uD83C\\uDFFE|\\u270C\\uD83C\\uDFFF|\\u270A\\uD83C\\uDFFB|\\u270A\\uD83C\\uDFFC|\\u270A\\uD83C\\uDFFD|\\u270A\\uD83C\\uDFFE|\\u270A\\uD83C\\uDFFF|\\u270B\\uD83C\\uDFFB|\\u270B\\uD83C\\uDFFC|4\\uFE0F\\u20E3|\\*\\uFE0F\\u20E3|8\\uFE0F\\u20E3|7\\uFE0F\\u20E3|6\\uFE0F\\u20E3|5\\uFE0F\\u20E3|9\\uFE0F\\u20E3|3\\uFE0F\\u20E3|2\\uFE0F\\u20E3|1\\uFE0F\\u20E3|0\\uFE0F\\u20E3|#\\uFE0F\\u20E3|\\uD83C\\uDF61|\\u2198\\uFE0F|\\u2199\\uFE0F|\\uD83C\\uDFF8|\\u2600\\uFE0F|\\u2601\\uFE0F|\\uD83C\\uDFD3|\\uD83C\\uDFD2|\\uD83C\\uDFD1|\\u2611\\uFE0F|\\u2614\\uFE0F|\\u2615\\uFE0F|\\uD83C\\uDFD0|\\uD83C\\uDFCF|\\uD83D\\uDCFF|\\uD83D\\uDD4E|\\uD83D\\uDD4D|\\uD83D\\uDD4C|\\uD83D\\uDD4B|\\u2648\\uFE0F|\\u2649\\uFE0F|\\u2650\\uFE0F|\\u2651\\uFE0F|\\u2652\\uFE0F|\\u2653\\uFE0F|\\u2660\\uFE0F|\\u2663\\uFE0F|\\u2665\\uFE0F|\\u2666\\uFE0F|\\u2668\\uFE0F|\\uD83D\\uDED0|\\u2693\\uFE0F|\\uD83C\\uDFFA|\\uD83C\\uDFF9|\\uD83C\\uDF7E|\\uD83C\\uDF7F|\\u2702\\uFE0F|\\uD83C\\uDF2F|\\u2708\\uFE0F|\\u2709\\uFE0F|\\u2712\\uFE0F|\\u2714\\uFE0F|\\u2716\\uFE0F|\\uD83C\\uDF2E|\\uD83C\\uDF2D|\\u2733\\uFE0F|\\u2734\\uFE0F|\\u2744\\uFE0F|\\u2747\\uFE0F|\\uD83E\\uDDC0|\\uD83E\\uDD83|\\uD83E\\uDD80|\\u2757\\uFE0F|\\uD83E\\uDD82|\\u2764\\uFE0F|\\uD83E\\uDD84|\\uD83E\\uDD81|\\uD83E\\uDD16|\\u2934\\uFE0F|\\u2935\\uFE0F|\\uD83E\\uDD15|\\u3297\\uFE0F|\\u3299\\uFE0F|\\u2049\\uFE0F|\\u2139\\uFE0F|\\u2194\\uFE0F|\\u2195\\uFE0F|\\u2196\\uFE0F|\\u2197\\uFE0F|\\u00A9\\uFE0F|\\u00AE\\uFE0F|\\u203C\\uFE0F|\\u21A9\\uFE0F|\\u21AA\\uFE0F|\\u231A\\uFE0F|\\u231B\\uFE0F|\\u24C2\\uFE0F|\\u25AA\\uFE0F|\\u25AB\\uFE0F|\\u25B6\\uFE0F|\\u25C0\\uFE0F|\\u25FB\\uFE0F|\\u25FC\\uFE0F|\\u25FD\\uFE0F|\\u25FE\\uFE0F|\\u260E\\uFE0F|\\u261D\\uFE0F|\\u263A\\uFE0F|\\u264A\\uFE0F|\\u264B\\uFE0F|\\u264C\\uFE0F|\\u264D\\uFE0F|\\u264E\\uFE0F|\\u264F\\uFE0F|\\u267B\\uFE0F|\\u267F\\uFE0F|\\u26A0\\uFE0F|\\u26A1\\uFE0F|\\u26AA\\uFE0F|\\u26AB\\uFE0F|\\u26BD\\uFE0F|\\u26BE\\uFE0F|\\u26C4\\uFE0F|\\u26C5\\uFE0F|\\u26D4\\uFE0F|\\u26EA\\uFE0F|\\u26F2\\uFE0F|\\u26F3\\uFE0F|\\u26F5\\uFE0F|\\u26FA\\uFE0F|\\u26FD\\uFE0F|\\u270C\\uFE0F|\\u270F\\uFE0F|\\u27A1\\uFE0F|\\u2B05\\uFE0F|\\u2B06\\uFE0F|\\u2B07\\uFE0F|\\u2B1B\\uFE0F|\\u2B1C\\uFE0F|\\u2B50\\uFE0F|\\u2B55\\uFE0F|\\u303D\\uFE0F|\\uD83C\\uDCCF|\\uD83C\\uDD70|\\uD83C\\uDD71|\\uD83C\\uDD7E|\\uD83C\\uDD8E|\\uD83C\\uDD91|\\uD83C\\uDD92|\\uD83C\\uDD93|\\uD83C\\uDD94|\\uD83C\\uDD95|\\uD83C\\uDD96|\\uD83C\\uDD97|\\uD83C\\uDD98|\\uD83C\\uDD99|\\uD83C\\uDD9A|\\uD83C\\uDE01|\\uD83C\\uDE02|\\uD83C\\uDE32|\\uD83C\\uDE33|\\uD83C\\uDE34|\\uD83C\\uDE35|\\uD83C\\uDE36|\\uD83C\\uDE38|\\uD83C\\uDE39|\\uD83C\\uDE3A|\\uD83C\\uDE50|\\uD83C\\uDE51|\\uD83C\\uDF00|\\uD83C\\uDF01|\\uD83C\\uDF02|\\uD83C\\uDF03|\\uD83C\\uDF04|\\uD83C\\uDF05|\\uD83C\\uDF06|\\uD83C\\uDF07|\\uD83C\\uDF08|\\uD83C\\uDF09|\\uD83C\\uDF0A|\\uD83C\\uDF0B|\\uD83C\\uDF0C|\\uD83C\\uDF0F|\\uD83C\\uDF11|\\uD83C\\uDF13|\\uD83C\\uDF14|\\uD83C\\uDF15|\\uD83C\\uDF19|\\uD83C\\uDF1B|\\uD83C\\uDF1F|\\uD83C\\uDF20|\\uD83C\\uDF30|\\uD83C\\uDF31|\\uD83C\\uDF34|\\uD83C\\uDF35|\\uD83C\\uDF37|\\uD83C\\uDF38|\\uD83C\\uDF39|\\uD83C\\uDF3A|\\uD83C\\uDF3B|\\uD83C\\uDF3C|\\uD83C\\uDF3D|\\uD83C\\uDF3E|\\uD83C\\uDF3F|\\uD83C\\uDF40|\\uD83C\\uDF41|\\uD83C\\uDF42|\\uD83C\\uDF43|\\uD83C\\uDF44|\\uD83C\\uDF45|\\uD83C\\uDF46|\\uD83C\\uDF47|\\uD83C\\uDF48|\\uD83C\\uDF49|\\uD83C\\uDF4A|\\uD83C\\uDF4C|\\uD83C\\uDF4D|\\uD83C\\uDF4E|\\uD83C\\uDF4F|\\uD83C\\uDF51|\\uD83C\\uDF52|\\uD83C\\uDF53|\\uD83C\\uDF54|\\uD83C\\uDF55|\\uD83C\\uDF56|\\uD83C\\uDF57|\\uD83C\\uDF58|\\uD83C\\uDF59|\\uD83C\\uDF5A|\\uD83C\\uDF5B|\\uD83C\\uDF5C|\\uD83C\\uDF5D|\\uD83C\\uDF5E|\\uD83C\\uDF5F|\\uD83C\\uDF60|\\u2122\\uFE0F|\\uD83C\\uDF62|\\uD83C\\uDF63|\\uD83C\\uDF64|\\uD83C\\uDF65|\\uD83C\\uDF66|\\uD83C\\uDF67|\\uD83C\\uDF68|\\uD83C\\uDF69|\\uD83C\\uDF6A|\\uD83C\\uDF6B|\\uD83C\\uDF6C|\\uD83C\\uDF6D|\\uD83C\\uDF6E|\\uD83C\\uDF6F|\\uD83C\\uDF70|\\uD83C\\uDF71|\\uD83C\\uDF72|\\uD83C\\uDF73|\\uD83C\\uDF74|\\uD83C\\uDF75|\\uD83C\\uDF76|\\uD83C\\uDF77|\\uD83C\\uDF78|\\uD83C\\uDF79|\\uD83C\\uDF7A|\\uD83C\\uDF7B|\\uD83C\\uDF80|\\uD83C\\uDF81|\\uD83C\\uDF82|\\uD83C\\uDF83|\\uD83C\\uDF84|\\uD83C\\uDF85|\\uD83C\\uDF86|\\uD83C\\uDF87|\\uD83C\\uDF88|\\uD83C\\uDF89|\\uD83C\\uDF8A|\\uD83C\\uDF8B|\\uD83C\\uDF8C|\\uD83C\\uDF8D|\\uD83C\\uDF8E|\\uD83C\\uDF8F|\\uD83C\\uDF90|\\uD83C\\uDF91|\\uD83C\\uDF92|\\uD83C\\uDF93|\\uD83C\\uDFA0|\\uD83C\\uDFA1|\\uD83C\\uDFA2|\\uD83C\\uDFA3|\\uD83C\\uDFA4|\\uD83C\\uDFA5|\\uD83C\\uDFA6|\\uD83C\\uDFA7|\\uD83C\\uDFA8|\\uD83C\\uDFA9|\\uD83C\\uDFAA|\\uD83C\\uDFAB|\\uD83C\\uDFAC|\\uD83C\\uDFAD|\\uD83C\\uDFAE|\\uD83C\\uDFAF|\\uD83C\\uDFB0|\\uD83C\\uDFB1|\\uD83C\\uDFB2|\\uD83C\\uDFB3|\\uD83C\\uDFB4|\\uD83C\\uDFB5|\\uD83C\\uDFB6|\\uD83C\\uDFB7|\\uD83C\\uDFB8|\\uD83C\\uDFB9|\\uD83C\\uDFBA|\\uD83C\\uDFBB|\\uD83C\\uDFBC|\\uD83C\\uDFBD|\\uD83C\\uDFBE|\\uD83C\\uDFBF|\\uD83C\\uDFC0|\\uD83C\\uDFC1|\\uD83C\\uDFC2|\\uD83C\\uDFC3|\\uD83C\\uDFC4|\\uD83C\\uDFC6|\\uD83C\\uDFC8|\\uD83C\\uDFCA|\\uD83C\\uDFE0|\\uD83C\\uDFE1|\\uD83C\\uDFE2|\\uD83C\\uDFE3|\\uD83C\\uDFE5|\\uD83C\\uDFE6|\\uD83C\\uDFE7|\\uD83C\\uDFE8|\\uD83C\\uDFE9|\\uD83C\\uDFEA|\\uD83C\\uDFEB|\\uD83C\\uDFEC|\\uD83C\\uDFED|\\uD83C\\uDFEE|\\uD83C\\uDFEF|\\uD83C\\uDFF0|\\uD83D\\uDC0C|\\uD83D\\uDC0D|\\uD83D\\uDC0E|\\uD83D\\uDC11|\\uD83D\\uDC12|\\uD83D\\uDC14|\\uD83D\\uDC17|\\uD83D\\uDC18|\\uD83D\\uDC19|\\uD83D\\uDC1A|\\uD83D\\uDC1B|\\uD83D\\uDC1C|\\uD83D\\uDC1D|\\uD83D\\uDC1E|\\uD83D\\uDC1F|\\uD83D\\uDC20|\\uD83D\\uDC21|\\uD83D\\uDC22|\\uD83D\\uDC23|\\uD83D\\uDC24|\\uD83D\\uDC25|\\uD83D\\uDC26|\\uD83D\\uDC27|\\uD83D\\uDC28|\\uD83D\\uDC29|\\uD83D\\uDC2B|\\uD83D\\uDC2C|\\uD83D\\uDC2D|\\uD83D\\uDC2E|\\uD83D\\uDC2F|\\uD83D\\uDC30|\\uD83D\\uDC31|\\uD83D\\uDC32|\\uD83D\\uDC33|\\uD83D\\uDC34|\\uD83D\\uDC35|\\uD83D\\uDC36|\\uD83D\\uDC37|\\uD83D\\uDC38|\\uD83D\\uDC39|\\uD83D\\uDC3A|\\uD83D\\uDC3B|\\uD83D\\uDC3C|\\uD83D\\uDC3D|\\uD83D\\uDC3E|\\uD83D\\uDC40|\\uD83D\\uDC42|\\uD83D\\uDC43|\\uD83D\\uDC44|\\uD83D\\uDC45|\\uD83D\\uDC46|\\uD83D\\uDC47|\\uD83D\\uDC48|\\uD83D\\uDC49|\\uD83D\\uDC4A|\\uD83D\\uDC4B|\\uD83D\\uDC4C|\\uD83D\\uDC4D|\\uD83D\\uDC4E|\\uD83D\\uDC4F|\\uD83D\\uDC50|\\uD83D\\uDC51|\\uD83D\\uDC52|\\uD83D\\uDC53|\\uD83D\\uDC54|\\uD83D\\uDC55|\\uD83D\\uDC56|\\uD83D\\uDC57|\\uD83D\\uDC58|\\uD83D\\uDC59|\\uD83D\\uDC5A|\\uD83D\\uDC5B|\\uD83D\\uDC5C|\\uD83D\\uDC5D|\\uD83D\\uDC5E|\\uD83D\\uDC5F|\\uD83D\\uDC60|\\uD83D\\uDC61|\\uD83D\\uDC62|\\uD83D\\uDC63|\\uD83D\\uDC64|\\uD83D\\uDC66|\\uD83D\\uDC67|\\uD83D\\uDC68|\\uD83D\\uDC69|\\uD83D\\uDC6A|\\uD83D\\uDC6B|\\uD83D\\uDC6E|\\uD83D\\uDC6F|\\uD83D\\uDC70|\\uD83D\\uDC71|\\uD83D\\uDC72|\\uD83D\\uDC73|\\uD83D\\uDC74|\\uD83D\\uDC75|\\uD83D\\uDC76|\\uD83D\\uDC77|\\uD83D\\uDC78|\\uD83D\\uDC79|\\uD83D\\uDC7A|\\uD83D\\uDC7B|\\uD83D\\uDC7C|\\uD83D\\uDC7D|\\uD83D\\uDC7E|\\uD83D\\uDC7F|\\uD83D\\uDC80|\\uD83D\\uDCC7|\\uD83D\\uDC81|\\uD83D\\uDC82|\\uD83D\\uDC83|\\uD83D\\uDC84|\\uD83D\\uDC85|\\uD83D\\uDCD2|\\uD83D\\uDC86|\\uD83D\\uDCD3|\\uD83D\\uDC87|\\uD83D\\uDCD4|\\uD83D\\uDC88|\\uD83D\\uDCD5|\\uD83D\\uDC89|\\uD83D\\uDCD6|\\uD83D\\uDC8A|\\uD83D\\uDCD7|\\uD83D\\uDC8B|\\uD83D\\uDCD8|\\uD83D\\uDC8C|\\uD83D\\uDCD9|\\uD83D\\uDC8D|\\uD83D\\uDCDA|\\uD83D\\uDC8E|\\uD83D\\uDCDB|\\uD83D\\uDC8F|\\uD83D\\uDCDC|\\uD83D\\uDC90|\\uD83D\\uDCDD|\\uD83D\\uDC91|\\uD83D\\uDCDE|\\uD83D\\uDC92|\\uD83D\\uDCDF|\\uD83D\\uDCE0|\\uD83D\\uDC93|\\uD83D\\uDCE1|\\uD83D\\uDCE2|\\uD83D\\uDC94|\\uD83D\\uDCE3|\\uD83D\\uDCE4|\\uD83D\\uDC95|\\uD83D\\uDCE5|\\uD83D\\uDCE6|\\uD83D\\uDC96|\\uD83D\\uDCE7|\\uD83D\\uDCE8|\\uD83D\\uDC97|\\uD83D\\uDCE9|\\uD83D\\uDCEA|\\uD83D\\uDC98|\\uD83D\\uDCEB|\\uD83D\\uDCEE|\\uD83D\\uDC99|\\uD83D\\uDCF0|\\uD83D\\uDCF1|\\uD83D\\uDC9A|\\uD83D\\uDCF2|\\uD83D\\uDCF3|\\uD83D\\uDC9B|\\uD83D\\uDCF4|\\uD83D\\uDCF6|\\uD83D\\uDC9C|\\uD83D\\uDCF7|\\uD83D\\uDCF9|\\uD83D\\uDC9D|\\uD83D\\uDCFA|\\uD83D\\uDCFB|\\uD83D\\uDC9E|\\uD83D\\uDCFC|\\uD83D\\uDD03|\\uD83D\\uDC9F|\\uD83D\\uDD0A|\\uD83D\\uDD0B|\\uD83D\\uDCA0|\\uD83D\\uDD0C|\\uD83D\\uDD0D|\\uD83D\\uDCA1|\\uD83D\\uDD0E|\\uD83D\\uDD0F|\\uD83D\\uDCA2|\\uD83D\\uDD10|\\uD83D\\uDD11|\\uD83D\\uDCA3|\\uD83D\\uDD12|\\uD83D\\uDD13|\\uD83D\\uDCA4|\\uD83D\\uDD14|\\uD83D\\uDD16|\\uD83D\\uDCA5|\\uD83D\\uDD17|\\uD83D\\uDD18|\\uD83D\\uDCA6|\\uD83D\\uDD19|\\uD83D\\uDD1A|\\uD83D\\uDCA7|\\uD83D\\uDD1B|\\uD83D\\uDD1C|\\uD83D\\uDCA8|\\uD83D\\uDD1D|\\uD83D\\uDD1E|\\uD83D\\uDCA9|\\uD83D\\uDD1F|\\uD83D\\uDCAA|\\uD83D\\uDD20|\\uD83D\\uDD21|\\uD83D\\uDCAB|\\uD83D\\uDD22|\\uD83D\\uDD23|\\uD83D\\uDCAC|\\uD83D\\uDD24|\\uD83D\\uDD25|\\uD83D\\uDCAE|\\uD83D\\uDD26|\\uD83D\\uDD27|\\uD83D\\uDCAF|\\uD83D\\uDD28|\\uD83D\\uDD29|\\uD83D\\uDCB0|\\uD83D\\uDD2A|\\uD83D\\uDD2B|\\uD83D\\uDCB1|\\uD83D\\uDD2E|\\uD83D\\uDCB2|\\uD83D\\uDD2F|\\uD83D\\uDCB3|\\uD83D\\uDD30|\\uD83D\\uDD31|\\uD83D\\uDCB4|\\uD83D\\uDD32|\\uD83D\\uDD33|\\uD83D\\uDCB5|\\uD83D\\uDD34|\\uD83D\\uDD35|\\uD83D\\uDCB8|\\uD83D\\uDD36|\\uD83D\\uDD37|\\uD83D\\uDCB9|\\uD83D\\uDD38|\\uD83D\\uDD39|\\uD83D\\uDCBA|\\uD83D\\uDD3A|\\uD83D\\uDD3B|\\uD83D\\uDCBB|\\uD83D\\uDD3C|\\uD83D\\uDCBC|\\uD83D\\uDD3D|\\uD83D\\uDD50|\\uD83D\\uDCBD|\\uD83D\\uDD51|\\uD83D\\uDCBE|\\uD83D\\uDD52|\\uD83D\\uDCBF|\\uD83D\\uDD53|\\uD83D\\uDCC0|\\uD83D\\uDD54|\\uD83D\\uDD55|\\uD83D\\uDCC1|\\uD83D\\uDD56|\\uD83D\\uDD57|\\uD83D\\uDCC2|\\uD83D\\uDD58|\\uD83D\\uDD59|\\uD83D\\uDCC3|\\uD83D\\uDD5A|\\uD83D\\uDD5B|\\uD83D\\uDCC4|\\uD83D\\uDDFB|\\uD83D\\uDDFC|\\uD83D\\uDCC5|\\uD83D\\uDDFD|\\uD83D\\uDDFE|\\uD83D\\uDCC6|\\uD83D\\uDDFF|\\uD83D\\uDE01|\\uD83D\\uDE02|\\uD83D\\uDE03|\\uD83D\\uDCC8|\\uD83D\\uDE04|\\uD83D\\uDE05|\\uD83D\\uDCC9|\\uD83D\\uDE06|\\uD83D\\uDE09|\\uD83D\\uDCCA|\\uD83D\\uDE0A|\\uD83D\\uDE0B|\\uD83D\\uDCCB|\\uD83D\\uDE0C|\\uD83D\\uDE0D|\\uD83D\\uDCCC|\\uD83D\\uDE0F|\\uD83D\\uDE12|\\uD83D\\uDCCD|\\uD83D\\uDE13|\\uD83D\\uDE14|\\uD83D\\uDCCE|\\uD83D\\uDE16|\\uD83D\\uDE18|\\uD83D\\uDCCF|\\uD83D\\uDE1A|\\uD83D\\uDE1C|\\uD83D\\uDCD0|\\uD83D\\uDE1D|\\uD83D\\uDE1E|\\uD83D\\uDCD1|\\uD83D\\uDE20|\\uD83D\\uDE21|\\uD83D\\uDE22|\\uD83D\\uDE23|\\uD83D\\uDE24|\\uD83D\\uDE25|\\uD83D\\uDE28|\\uD83D\\uDE29|\\uD83D\\uDE2A|\\uD83D\\uDE2B|\\uD83D\\uDE2D|\\uD83D\\uDE30|\\uD83D\\uDE31|\\uD83D\\uDE32|\\uD83D\\uDE33|\\uD83D\\uDE35|\\uD83D\\uDE37|\\uD83D\\uDE38|\\uD83D\\uDE39|\\uD83D\\uDE3A|\\uD83D\\uDE3B|\\uD83D\\uDE3C|\\uD83D\\uDE3D|\\uD83D\\uDE3E|\\uD83D\\uDE3F|\\uD83D\\uDE40|\\uD83D\\uDE45|\\uD83D\\uDE46|\\uD83D\\uDE47|\\uD83D\\uDE48|\\uD83D\\uDE49|\\uD83D\\uDE4A|\\uD83D\\uDE4B|\\uD83D\\uDE4C|\\uD83D\\uDE4D|\\uD83D\\uDE4E|\\uD83D\\uDE4F|\\uD83D\\uDE80|\\uD83D\\uDE83|\\uD83D\\uDE84|\\uD83D\\uDE85|\\uD83D\\uDE87|\\uD83D\\uDE89|\\uD83D\\uDE8C|\\uD83D\\uDE8F|\\uD83D\\uDE91|\\uD83D\\uDE92|\\uD83D\\uDE93|\\uD83D\\uDE95|\\uD83D\\uDE97|\\uD83D\\uDE99|\\uD83D\\uDE9A|\\uD83D\\uDEA2|\\uD83D\\uDEA4|\\uD83D\\uDEA5|\\uD83D\\uDEA7|\\uD83D\\uDEA8|\\uD83D\\uDEA9|\\uD83D\\uDEAA|\\uD83D\\uDEAB|\\uD83D\\uDEAC|\\uD83D\\uDEAD|\\uD83D\\uDEB2|\\uD83D\\uDEB6|\\uD83D\\uDEB9|\\uD83D\\uDEBA|\\uD83D\\uDEBB|\\uD83D\\uDEBC|\\uD83D\\uDEBD|\\uD83D\\uDEBE|\\uD83D\\uDEC0|\\uD83E\\uDD18|\\uD83D\\uDE00|\\uD83D\\uDE07|\\uD83D\\uDE08|\\uD83D\\uDE0E|\\uD83D\\uDE10|\\uD83D\\uDE11|\\uD83D\\uDE15|\\uD83D\\uDE17|\\uD83D\\uDE19|\\uD83D\\uDE1B|\\uD83D\\uDE1F|\\uD83D\\uDE26|\\uD83D\\uDE27|\\uD83D\\uDE2C|\\uD83D\\uDE2E|\\uD83D\\uDE2F|\\uD83D\\uDE34|\\uD83D\\uDE36|\\uD83D\\uDE81|\\uD83D\\uDE82|\\uD83D\\uDE86|\\uD83D\\uDE88|\\uD83D\\uDE8A|\\uD83D\\uDE8D|\\uD83D\\uDE8E|\\uD83D\\uDE90|\\uD83D\\uDE94|\\uD83D\\uDE96|\\uD83D\\uDE98|\\uD83D\\uDE9B|\\uD83D\\uDE9C|\\uD83D\\uDE9D|\\uD83D\\uDE9E|\\uD83D\\uDE9F|\\uD83D\\uDEA0|\\uD83D\\uDEA1|\\uD83D\\uDEA3|\\uD83D\\uDEA6|\\uD83D\\uDEAE|\\uD83D\\uDEAF|\\uD83D\\uDEB0|\\uD83D\\uDEB1|\\uD83D\\uDEB3|\\uD83D\\uDEB4|\\uD83D\\uDEB5|\\uD83D\\uDEB7|\\uD83D\\uDEB8|\\uD83D\\uDEBF|\\uD83D\\uDEC1|\\uD83D\\uDEC2|\\uD83D\\uDEC3|\\uD83D\\uDEC4|\\uD83D\\uDEC5|\\uD83C\\uDF0D|\\uD83C\\uDF0E|\\uD83C\\uDF10|\\uD83C\\uDF12|\\uD83C\\uDF16|\\uD83C\\uDF17|\\uD83C\\uDF18|\\uD83C\\uDF1A|\\uD83C\\uDF1C|\\uD83C\\uDF1D|\\uD83C\\uDF1E|\\uD83C\\uDF32|\\uD83C\\uDF33|\\uD83C\\uDF4B|\\uD83C\\uDF50|\\uD83C\\uDF7C|\\uD83C\\uDFC7|\\uD83C\\uDFC9|\\uD83C\\uDFE4|\\uD83D\\uDC00|\\uD83D\\uDC01|\\uD83D\\uDC02|\\uD83D\\uDC03|\\uD83D\\uDC04|\\uD83D\\uDC05|\\uD83D\\uDC06|\\uD83D\\uDC07|\\uD83D\\uDC08|\\uD83D\\uDC09|\\uD83D\\uDC0A|\\uD83D\\uDC0B|\\uD83D\\uDC0F|\\uD83D\\uDC10|\\uD83D\\uDC13|\\uD83D\\uDC15|\\uD83D\\uDC16|\\uD83D\\uDC2A|\\uD83D\\uDC65|\\uD83D\\uDC6C|\\uD83D\\uDC6D|\\uD83D\\uDCAD|\\uD83D\\uDCB6|\\uD83D\\uDCB7|\\uD83D\\uDCEC|\\uD83D\\uDCED|\\uD83D\\uDCEF|\\uD83D\\uDCF5|\\uD83D\\uDD00|\\uD83D\\uDD01|\\uD83D\\uDD02|\\uD83D\\uDD04|\\uD83D\\uDD05|\\uD83D\\uDD06|\\uD83D\\uDD07|\\uD83D\\uDD09|\\uD83D\\uDD15|\\uD83D\\uDD2C|\\uD83D\\uDD2D|\\uD83D\\uDD5C|\\uD83D\\uDD5D|\\uD83D\\uDD5E|\\uD83D\\uDD5F|\\uD83D\\uDD60|\\uD83D\\uDD61|\\uD83D\\uDD62|\\uD83D\\uDD63|\\uD83D\\uDD64|\\uD83D\\uDD65|\\uD83D\\uDD66|\\uD83D\\uDD67|\\uD83D\\uDD08|\\uD83D\\uDE8B|\\uD83C\\uDF9E|\\uD83C\\uDF9F|\\uD83C\\uDFC5|\\uD83C\\uDFCB|\\uD83C\\uDFCC|\\uD83C\\uDFCD|\\uD83C\\uDFCE|\\uD83C\\uDF96|\\uD83C\\uDF97|\\uD83C\\uDF36|\\uD83C\\uDF27|\\uD83C\\uDF28|\\uD83C\\uDF29|\\uD83C\\uDF2A|\\uD83C\\uDF2B|\\uD83C\\uDF2C|\\uD83D\\uDC3F|\\uD83D\\uDD77|\\uD83D\\uDD78|\\uD83C\\uDF21|\\uD83C\\uDF99|\\uD83C\\uDF9A|\\uD83C\\uDF9B|\\uD83C\\uDFF3|\\uD83C\\uDFF4|\\uD83C\\uDFF5|\\uD83C\\uDFF7|\\uD83D\\uDCF8|\\uD83D\\uDCFD|\\uD83D\\uDD49|\\uD83D\\uDD4A|\\uD83D\\uDD6F|\\uD83D\\uDD70|\\uD83D\\uDD73|\\uD83D\\uDD76|\\uD83D\\uDD79|\\uD83D\\uDD87|\\uD83D\\uDD8A|\\uD83D\\uDD8B|\\uD83D\\uDD8C|\\uD83D\\uDD8D|\\uD83D\\uDDA5|\\uD83D\\uDDA8|\\uD83D\\uDDB2|\\uD83D\\uDDBC|\\uD83D\\uDDC2|\\uD83D\\uDDC3|\\uD83D\\uDDC4|\\uD83D\\uDDD1|\\uD83D\\uDDD2|\\uD83D\\uDDD3|\\uD83D\\uDDDC|\\uD83D\\uDDDD|\\uD83D\\uDDDE|\\uD83D\\uDDE1|\\uD83D\\uDDE3|\\uD83D\\uDDEF|\\uD83D\\uDDF3|\\uD83D\\uDDFA|\\uD83D\\uDECC|\\uD83D\\uDEE0|\\uD83D\\uDEE1|\\uD83D\\uDEE2|\\uD83D\\uDEF0|\\uD83C\\uDF7D|\\uD83D\\uDC41|\\uD83D\\uDD74|\\uD83D\\uDD75|\\uD83D\\uDD90|\\uD83D\\uDD95|\\uD83D\\uDD96|\\uD83D\\uDE41|\\uD83D\\uDE42|\\uD83C\\uDFD4|\\uD83C\\uDFD5|\\uD83C\\uDFD6|\\uD83C\\uDFD7|\\uD83C\\uDFD8|\\uD83C\\uDFD9|\\uD83C\\uDFDA|\\uD83C\\uDFDB|\\uD83C\\uDFDC|\\uD83C\\uDFDD|\\uD83C\\uDFDE|\\uD83C\\uDFDF|\\uD83D\\uDECB|\\uD83D\\uDECD|\\uD83D\\uDECE|\\uD83D\\uDECF|\\uD83D\\uDEE3|\\uD83D\\uDEE4|\\uD83D\\uDEE5|\\uD83D\\uDEE9|\\uD83D\\uDEEB|\\uD83D\\uDEEC|\\uD83D\\uDEF3|\\uD83C\\uDFFB|\\uD83C\\uDFFC|\\uD83C\\uDFFD|\\uD83C\\uDFFE|\\uD83C\\uDFFF|\\uD83C\\uDF24|\\uD83C\\uDF25|\\uD83C\\uDF26|\\uD83D\\uDDB1|\\uD83D\\uDE43|\\uD83E\\uDD11|\\uD83E\\uDD13|\\uD83E\\uDD17|\\uD83D\\uDE44|\\uD83E\\uDD14|\\uD83E\\uDD10|\\uD83E\\uDD12|\\u270A|\\u3030|\\u2796|\\u2795|\\u2763|\\u2755|\\u2754|\\u2753|\\u2728|\\u2721|\\u2705|\\u2699|\\u2697|\\u2696|\\u2694|\\u2692|\\u2639|\\u2638|\\u2626|\\u2623|\\u2622|\\u2620|\\u2618|\\u2604|\\u2603|\\u2602|\\u2328|\\u23E9|\\u23EA|\\u23EB|\\u23EC|\\u23F0|\\u23F3|\\u26CE|\\u2797|\\u270B|\\u274C|\\u274E|\\u27B0|\\u27BF|\\u271D|\\u270D|\\u23ED|\\u23EE|\\u23EF|\\u23F1|\\u23F2|\\u23F8|\\u23F9|\\u23FA|\\u262A|\\u262E|\\u262F|\\u269B|\\u269C|\\u26B0|\\u26B1|\\u26C8|\\u26CF|\\u26D1|\\u26D3|\\u26E9|\\u26F0|\\u26F1|\\u26F4|\\u26F7|\\u26F8|\\u26F9)';
- ns.jsEscapeMap = {"\u2049\uFE0F":"2049","\u2122\uFE0F":"2122","\u2139\uFE0F":"2139","\u2194\uFE0F":"2194","\u2195\uFE0F":"2195","\u2196\uFE0F":"2196","\u2197\uFE0F":"2197","\u2198\uFE0F":"2198","\u2199\uFE0F":"2199","\u2328":"2328","\u2600\uFE0F":"2600","\u2601\uFE0F":"2601","\u2602":"2602","\u2603":"2603","\u2604":"2604","\u2611\uFE0F":"2611","\u2614\uFE0F":"2614","\u2615\uFE0F":"2615","\u2618":"2618","\u2620":"2620","\u2622":"2622","\u2623":"2623","\u2626":"2626","\u2638":"2638","\u2639":"2639","\u2648\uFE0F":"2648","\u2649\uFE0F":"2649","\u2650\uFE0F":"2650","\u2651\uFE0F":"2651","\u2652\uFE0F":"2652","\u2653\uFE0F":"2653","\u2660\uFE0F":"2660","\u2663\uFE0F":"2663","\u2665\uFE0F":"2665","\u2666\uFE0F":"2666","\u2668\uFE0F":"2668","\u2692":"2692","\u2693\uFE0F":"2693","\u2694":"2694","\u2696":"2696","\u2697":"2697","\u2699":"2699","\u2702\uFE0F":"2702","\u2705":"2705","\u2708\uFE0F":"2708","\u2709\uFE0F":"2709","\u2712\uFE0F":"2712","\u2714\uFE0F":"2714","\u2716\uFE0F":"2716","\u2721":"2721","\u2728":"2728","\u2733\uFE0F":"2733","\u2734\uFE0F":"2734","\u2744\uFE0F":"2744","\u2747\uFE0F":"2747","\u2753":"2753","\u2754":"2754","\u2755":"2755","\u2757\uFE0F":"2757","\u2763":"2763","\u2764\uFE0F":"2764","\u2795":"2795","\u2796":"2796","\u2797":"2797","\u2934\uFE0F":"2934","\u2935\uFE0F":"2935","\u3030":"3030","\u3297\uFE0F":"3297","\u3299\uFE0F":"3299","\uD83D\uDC69\u200D\u2764\uFE0F\u200D\uD83D\uDC8B\u200D\uD83D\uDC69":"1f469-2764-1f48b-1f469","\uD83D\uDC68\u200D\u2764\uFE0F\u200D\uD83D\uDC8B\u200D\uD83D\uDC68":"1f468-2764-1f48b-1f468","\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC66\u200D\uD83D\uDC66":"1f468-1f468-1f466-1f466","\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC67\u200D\uD83D\uDC66":"1f468-1f468-1f467-1f466","\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC67\u200D\uD83D\uDC67":"1f468-1f468-1f467-1f467","\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66":"1f468-1f469-1f466-1f466","\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66":"1f468-1f469-1f467-1f466","\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC67":"1f468-1f469-1f467-1f467","\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66":"1f469-1f469-1f466-1f466","\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66":"1f469-1f469-1f467-1f466","\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC67":"1f469-1f469-1f467-1f467","\uD83D\uDC69\u200D\u2764\uFE0F\u200D\uD83D\uDC69":"1f469-2764-1f469","\uD83D\uDC68\u200D\u2764\uFE0F\u200D\uD83D\uDC68":"1f468-2764-1f468","\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC66":"1f468-1f468-1f466","\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC67":"1f468-1f468-1f467","\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67":"1f468-1f469-1f467","\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66":"1f469-1f469-1f466","\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC67":"1f469-1f469-1f467","\uD83D\uDC41\u200D\uD83D\uDDE8":"1f441-1f5e8","#\uFE0F\u20E3":"0023-20e3","0\uFE0F\u20E3":"0030-20e3","1\uFE0F\u20E3":"0031-20e3","2\uFE0F\u20E3":"0032-20e3","3\uFE0F\u20E3":"0033-20e3","4\uFE0F\u20E3":"0034-20e3","5\uFE0F\u20E3":"0035-20e3","6\uFE0F\u20E3":"0036-20e3","7\uFE0F\u20E3":"0037-20e3","8\uFE0F\u20E3":"0038-20e3","9\uFE0F\u20E3":"0039-20e3","*\uFE0F\u20E3":"002a-20e3","\uD83E\uDD18\uD83C\uDFFF":"1f918-1f3ff","\uD83E\uDD18\uD83C\uDFFE":"1f918-1f3fe","\uD83E\uDD18\uD83C\uDFFD":"1f918-1f3fd","\uD83E\uDD18\uD83C\uDFFC":"1f918-1f3fc","\uD83E\uDD18\uD83C\uDFFB":"1f918-1f3fb","\uD83D\uDEC0\uD83C\uDFFF":"1f6c0-1f3ff","\uD83D\uDEC0\uD83C\uDFFE":"1f6c0-1f3fe","\uD83D\uDEC0\uD83C\uDFFD":"1f6c0-1f3fd","\uD83D\uDEC0\uD83C\uDFFC":"1f6c0-1f3fc","\uD83D\uDEC0\uD83C\uDFFB":"1f6c0-1f3fb","\uD83D\uDEB6\uD83C\uDFFF":"1f6b6-1f3ff","\uD83D\uDEB6\uD83C\uDFFE":"1f6b6-1f3fe","\uD83D\uDEB6\uD83C\uDFFD":"1f6b6-1f3fd","\uD83D\uDEB6\uD83C\uDFFC":"1f6b6-1f3fc","\uD83D\uDEB6\uD83C\uDFFB":"1f6b6-1f3fb","\uD83D\uDEB5\uD83C\uDFFF":"1f6b5-1f3ff","\uD83D\uDEB5\uD83C\uDFFE":"1f6b5-1f3fe","\uD83D\uDEB5\uD83C\uDFFD":"1f6b5-1f3fd","\uD83D\uDEB5\uD83C\uDFFC":"1f6b5-1f3fc","\uD83D\uDEB5\uD83C\uDFFB":"1f6b5-1f3fb","\uD83D\uDEB4\uD83C\uDFFF":"1f6b4-1f3ff","\uD83D\uDEB4\uD83C\uDFFE":"1f6b4-1f3fe","\uD83D\uDEB4\uD83C\uDFFD":"1f6b4-1f3fd","\uD83D\uDEB4\uD83C\uDFFC":"1f6b4-1f3fc","\uD83D\uDEB4\uD83C\uDFFB":"1f6b4-1f3fb","\uD83D\uDEA3\uD83C\uDFFF":"1f6a3-1f3ff","\uD83D\uDEA3\uD83C\uDFFE":"1f6a3-1f3fe","\uD83D\uDEA3\uD83C\uDFFD":"1f6a3-1f3fd","\uD83D\uDEA3\uD83C\uDFFC":"1f6a3-1f3fc","\uD83D\uDEA3\uD83C\uDFFB":"1f6a3-1f3fb","\uD83D\uDE4F\uD83C\uDFFF":"1f64f-1f3ff","\uD83D\uDE4F\uD83C\uDFFE":"1f64f-1f3fe","\uD83D\uDE4F\uD83C\uDFFD":"1f64f-1f3fd","\uD83D\uDE4F\uD83C\uDFFC":"1f64f-1f3fc","\uD83D\uDE4F\uD83C\uDFFB":"1f64f-1f3fb","\uD83D\uDE4E\uD83C\uDFFF":"1f64e-1f3ff","\uD83D\uDE4E\uD83C\uDFFE":"1f64e-1f3fe","\uD83D\uDE4E\uD83C\uDFFD":"1f64e-1f3fd","\uD83D\uDE4E\uD83C\uDFFC":"1f64e-1f3fc","\uD83D\uDE4E\uD83C\uDFFB":"1f64e-1f3fb","\uD83D\uDE4D\uD83C\uDFFF":"1f64d-1f3ff","\uD83D\uDE4D\uD83C\uDFFE":"1f64d-1f3fe","\uD83D\uDE4D\uD83C\uDFFD":"1f64d-1f3fd","\uD83D\uDE4D\uD83C\uDFFC":"1f64d-1f3fc","\uD83D\uDE4D\uD83C\uDFFB":"1f64d-1f3fb","\uD83D\uDE4C\uD83C\uDFFF":"1f64c-1f3ff","\uD83D\uDE4C\uD83C\uDFFE":"1f64c-1f3fe","\uD83D\uDE4C\uD83C\uDFFD":"1f64c-1f3fd","\uD83D\uDE4C\uD83C\uDFFC":"1f64c-1f3fc","\uD83D\uDE4C\uD83C\uDFFB":"1f64c-1f3fb","\uD83D\uDE4B\uD83C\uDFFF":"1f64b-1f3ff","\uD83D\uDE4B\uD83C\uDFFE":"1f64b-1f3fe","\uD83D\uDE4B\uD83C\uDFFD":"1f64b-1f3fd","\uD83D\uDE4B\uD83C\uDFFC":"1f64b-1f3fc","\uD83D\uDE4B\uD83C\uDFFB":"1f64b-1f3fb","\uD83D\uDE47\uD83C\uDFFF":"1f647-1f3ff","\uD83D\uDE47\uD83C\uDFFE":"1f647-1f3fe","\uD83D\uDE47\uD83C\uDFFD":"1f647-1f3fd","\uD83D\uDE47\uD83C\uDFFC":"1f647-1f3fc","\uD83D\uDE47\uD83C\uDFFB":"1f647-1f3fb","\uD83D\uDE46\uD83C\uDFFF":"1f646-1f3ff","\uD83D\uDE46\uD83C\uDFFE":"1f646-1f3fe","\uD83D\uDE46\uD83C\uDFFD":"1f646-1f3fd","\uD83D\uDE46\uD83C\uDFFC":"1f646-1f3fc","\uD83D\uDE46\uD83C\uDFFB":"1f646-1f3fb","\uD83D\uDE45\uD83C\uDFFF":"1f645-1f3ff","\uD83D\uDE45\uD83C\uDFFE":"1f645-1f3fe","\uD83D\uDE45\uD83C\uDFFD":"1f645-1f3fd","\uD83D\uDE45\uD83C\uDFFC":"1f645-1f3fc","\uD83D\uDE45\uD83C\uDFFB":"1f645-1f3fb","\uD83D\uDD96\uD83C\uDFFF":"1f596-1f3ff","\uD83D\uDD96\uD83C\uDFFE":"1f596-1f3fe","\uD83D\uDD96\uD83C\uDFFD":"1f596-1f3fd","\uD83D\uDD96\uD83C\uDFFC":"1f596-1f3fc","\uD83D\uDD96\uD83C\uDFFB":"1f596-1f3fb","\uD83D\uDD95\uD83C\uDFFF":"1f595-1f3ff","\uD83D\uDD95\uD83C\uDFFE":"1f595-1f3fe","\uD83D\uDD95\uD83C\uDFFD":"1f595-1f3fd","\uD83D\uDD95\uD83C\uDFFC":"1f595-1f3fc","\uD83D\uDD95\uD83C\uDFFB":"1f595-1f3fb","\uD83D\uDD90\uD83C\uDFFF":"1f590-1f3ff","\uD83D\uDD90\uD83C\uDFFE":"1f590-1f3fe","\uD83D\uDD90\uD83C\uDFFD":"1f590-1f3fd","\uD83D\uDD90\uD83C\uDFFC":"1f590-1f3fc","\uD83D\uDD90\uD83C\uDFFB":"1f590-1f3fb","\uD83D\uDD75\uD83C\uDFFF":"1f575-1f3ff","\uD83D\uDD75\uD83C\uDFFE":"1f575-1f3fe","\uD83D\uDD75\uD83C\uDFFD":"1f575-1f3fd","\uD83D\uDD75\uD83C\uDFFC":"1f575-1f3fc","\uD83D\uDD75\uD83C\uDFFB":"1f575-1f3fb","\uD83D\uDCAA\uD83C\uDFFF":"1f4aa-1f3ff","\uD83D\uDCAA\uD83C\uDFFE":"1f4aa-1f3fe","\uD83D\uDCAA\uD83C\uDFFD":"1f4aa-1f3fd","\uD83D\uDCAA\uD83C\uDFFC":"1f4aa-1f3fc","\uD83D\uDCAA\uD83C\uDFFB":"1f4aa-1f3fb","\uD83D\uDC87\uD83C\uDFFF":"1f487-1f3ff","\uD83D\uDC87\uD83C\uDFFE":"1f487-1f3fe","\uD83D\uDC87\uD83C\uDFFD":"1f487-1f3fd","\uD83D\uDC87\uD83C\uDFFC":"1f487-1f3fc","\uD83D\uDC87\uD83C\uDFFB":"1f487-1f3fb","\uD83D\uDC86\uD83C\uDFFF":"1f486-1f3ff","\uD83D\uDC86\uD83C\uDFFE":"1f486-1f3fe","\uD83D\uDC86\uD83C\uDFFD":"1f486-1f3fd","\uD83D\uDC86\uD83C\uDFFC":"1f486-1f3fc","\uD83D\uDC86\uD83C\uDFFB":"1f486-1f3fb","\uD83D\uDC85\uD83C\uDFFF":"1f485-1f3ff","\uD83D\uDC85\uD83C\uDFFE":"1f485-1f3fe","\uD83D\uDC85\uD83C\uDFFD":"1f485-1f3fd","\uD83D\uDC85\uD83C\uDFFC":"1f485-1f3fc","\uD83D\uDC85\uD83C\uDFFB":"1f485-1f3fb","\uD83D\uDC83\uD83C\uDFFF":"1f483-1f3ff","\uD83D\uDC83\uD83C\uDFFE":"1f483-1f3fe","\uD83D\uDC83\uD83C\uDFFD":"1f483-1f3fd","\uD83D\uDC83\uD83C\uDFFC":"1f483-1f3fc","\uD83D\uDC83\uD83C\uDFFB":"1f483-1f3fb","\uD83D\uDC82\uD83C\uDFFF":"1f482-1f3ff","\uD83D\uDC82\uD83C\uDFFE":"1f482-1f3fe","\uD83D\uDC82\uD83C\uDFFD":"1f482-1f3fd","\uD83D\uDC82\uD83C\uDFFC":"1f482-1f3fc","\uD83D\uDC82\uD83C\uDFFB":"1f482-1f3fb","\uD83D\uDC81\uD83C\uDFFF":"1f481-1f3ff","\uD83D\uDC81\uD83C\uDFFE":"1f481-1f3fe","\uD83D\uDC81\uD83C\uDFFD":"1f481-1f3fd","\uD83D\uDC81\uD83C\uDFFC":"1f481-1f3fc","\uD83D\uDC81\uD83C\uDFFB":"1f481-1f3fb","\uD83D\uDC7C\uD83C\uDFFF":"1f47c-1f3ff","\uD83D\uDC7C\uD83C\uDFFE":"1f47c-1f3fe","\uD83D\uDC7C\uD83C\uDFFD":"1f47c-1f3fd","\uD83D\uDC7C\uD83C\uDFFC":"1f47c-1f3fc","\uD83D\uDC7C\uD83C\uDFFB":"1f47c-1f3fb","\uD83D\uDC78\uD83C\uDFFF":"1f478-1f3ff","\uD83D\uDC78\uD83C\uDFFE":"1f478-1f3fe","\uD83D\uDC78\uD83C\uDFFD":"1f478-1f3fd","\uD83D\uDC78\uD83C\uDFFC":"1f478-1f3fc","\uD83D\uDC78\uD83C\uDFFB":"1f478-1f3fb","\uD83D\uDC77\uD83C\uDFFF":"1f477-1f3ff","\uD83D\uDC77\uD83C\uDFFE":"1f477-1f3fe","\uD83D\uDC77\uD83C\uDFFD":"1f477-1f3fd","\uD83D\uDC77\uD83C\uDFFC":"1f477-1f3fc","\uD83D\uDC77\uD83C\uDFFB":"1f477-1f3fb","\uD83D\uDC76\uD83C\uDFFF":"1f476-1f3ff","\uD83D\uDC76\uD83C\uDFFE":"1f476-1f3fe","\uD83D\uDC76\uD83C\uDFFD":"1f476-1f3fd","\uD83D\uDC76\uD83C\uDFFC":"1f476-1f3fc","\uD83D\uDC76\uD83C\uDFFB":"1f476-1f3fb","\uD83D\uDC75\uD83C\uDFFF":"1f475-1f3ff","\uD83D\uDC75\uD83C\uDFFE":"1f475-1f3fe","\uD83D\uDC75\uD83C\uDFFD":"1f475-1f3fd","\uD83D\uDC75\uD83C\uDFFC":"1f475-1f3fc","\uD83D\uDC75\uD83C\uDFFB":"1f475-1f3fb","\uD83D\uDC74\uD83C\uDFFF":"1f474-1f3ff","\uD83D\uDC74\uD83C\uDFFE":"1f474-1f3fe","\uD83D\uDC74\uD83C\uDFFD":"1f474-1f3fd","\uD83D\uDC74\uD83C\uDFFC":"1f474-1f3fc","\uD83D\uDC74\uD83C\uDFFB":"1f474-1f3fb","\uD83D\uDC73\uD83C\uDFFF":"1f473-1f3ff","\uD83D\uDC73\uD83C\uDFFE":"1f473-1f3fe","\uD83D\uDC73\uD83C\uDFFD":"1f473-1f3fd","\uD83D\uDC73\uD83C\uDFFC":"1f473-1f3fc","\uD83D\uDC73\uD83C\uDFFB":"1f473-1f3fb","\uD83D\uDC72\uD83C\uDFFF":"1f472-1f3ff","\uD83D\uDC72\uD83C\uDFFE":"1f472-1f3fe","\uD83D\uDC72\uD83C\uDFFD":"1f472-1f3fd","\uD83D\uDC72\uD83C\uDFFC":"1f472-1f3fc","\uD83D\uDC72\uD83C\uDFFB":"1f472-1f3fb","\uD83D\uDC71\uD83C\uDFFF":"1f471-1f3ff","\uD83D\uDC71\uD83C\uDFFE":"1f471-1f3fe","\uD83D\uDC71\uD83C\uDFFD":"1f471-1f3fd","\uD83D\uDC71\uD83C\uDFFC":"1f471-1f3fc","\uD83D\uDC71\uD83C\uDFFB":"1f471-1f3fb","\uD83D\uDC70\uD83C\uDFFF":"1f470-1f3ff","\uD83D\uDC70\uD83C\uDFFE":"1f470-1f3fe","\uD83D\uDC70\uD83C\uDFFD":"1f470-1f3fd","\uD83D\uDC70\uD83C\uDFFC":"1f470-1f3fc","\uD83D\uDC70\uD83C\uDFFB":"1f470-1f3fb","\uD83D\uDC6E\uD83C\uDFFF":"1f46e-1f3ff","\uD83D\uDC6E\uD83C\uDFFE":"1f46e-1f3fe","\uD83D\uDC6E\uD83C\uDFFD":"1f46e-1f3fd","\uD83D\uDC6E\uD83C\uDFFC":"1f46e-1f3fc","\uD83D\uDC6E\uD83C\uDFFB":"1f46e-1f3fb","\uD83D\uDC69\uD83C\uDFFF":"1f469-1f3ff","\uD83D\uDC69\uD83C\uDFFE":"1f469-1f3fe","\uD83D\uDC69\uD83C\uDFFD":"1f469-1f3fd","\uD83D\uDC69\uD83C\uDFFC":"1f469-1f3fc","\uD83D\uDC69\uD83C\uDFFB":"1f469-1f3fb","\uD83D\uDC68\uD83C\uDFFF":"1f468-1f3ff","\uD83D\uDC68\uD83C\uDFFE":"1f468-1f3fe","\uD83D\uDC68\uD83C\uDFFD":"1f468-1f3fd","\uD83D\uDC68\uD83C\uDFFC":"1f468-1f3fc","\uD83D\uDC68\uD83C\uDFFB":"1f468-1f3fb","\uD83D\uDC67\uD83C\uDFFF":"1f467-1f3ff","\uD83D\uDC67\uD83C\uDFFE":"1f467-1f3fe","\uD83D\uDC67\uD83C\uDFFD":"1f467-1f3fd","\uD83D\uDC67\uD83C\uDFFC":"1f467-1f3fc","\uD83D\uDC67\uD83C\uDFFB":"1f467-1f3fb","\uD83D\uDC66\uD83C\uDFFF":"1f466-1f3ff","\uD83D\uDC66\uD83C\uDFFE":"1f466-1f3fe","\uD83D\uDC66\uD83C\uDFFD":"1f466-1f3fd","\uD83D\uDC66\uD83C\uDFFC":"1f466-1f3fc","\uD83D\uDC66\uD83C\uDFFB":"1f466-1f3fb","\uD83D\uDC50\uD83C\uDFFF":"1f450-1f3ff","\uD83D\uDC50\uD83C\uDFFE":"1f450-1f3fe","\uD83D\uDC50\uD83C\uDFFD":"1f450-1f3fd","\uD83D\uDC50\uD83C\uDFFC":"1f450-1f3fc","\uD83D\uDC50\uD83C\uDFFB":"1f450-1f3fb","\uD83D\uDC4F\uD83C\uDFFF":"1f44f-1f3ff","\uD83D\uDC4F\uD83C\uDFFE":"1f44f-1f3fe","\uD83D\uDC4F\uD83C\uDFFD":"1f44f-1f3fd","\uD83D\uDC4F\uD83C\uDFFC":"1f44f-1f3fc","\uD83D\uDC4F\uD83C\uDFFB":"1f44f-1f3fb","\uD83D\uDC4E\uD83C\uDFFF":"1f44e-1f3ff","\uD83D\uDC4E\uD83C\uDFFE":"1f44e-1f3fe","\uD83D\uDC4E\uD83C\uDFFD":"1f44e-1f3fd","\uD83D\uDC4E\uD83C\uDFFC":"1f44e-1f3fc","\uD83D\uDC4E\uD83C\uDFFB":"1f44e-1f3fb","\uD83D\uDC4D\uD83C\uDFFF":"1f44d-1f3ff","\uD83D\uDC4D\uD83C\uDFFE":"1f44d-1f3fe","\uD83D\uDC4D\uD83C\uDFFD":"1f44d-1f3fd","\uD83D\uDC4D\uD83C\uDFFC":"1f44d-1f3fc","\uD83D\uDC4D\uD83C\uDFFB":"1f44d-1f3fb","\uD83D\uDC4C\uD83C\uDFFF":"1f44c-1f3ff","\uD83D\uDC4C\uD83C\uDFFE":"1f44c-1f3fe","\uD83D\uDC4C\uD83C\uDFFD":"1f44c-1f3fd","\uD83D\uDC4C\uD83C\uDFFC":"1f44c-1f3fc","\uD83D\uDC4C\uD83C\uDFFB":"1f44c-1f3fb","\uD83D\uDC4B\uD83C\uDFFF":"1f44b-1f3ff","\uD83D\uDC4B\uD83C\uDFFE":"1f44b-1f3fe","\uD83D\uDC4B\uD83C\uDFFD":"1f44b-1f3fd","\uD83D\uDC4B\uD83C\uDFFC":"1f44b-1f3fc","\uD83D\uDC4B\uD83C\uDFFB":"1f44b-1f3fb","\uD83D\uDC4A\uD83C\uDFFF":"1f44a-1f3ff","\uD83D\uDC4A\uD83C\uDFFE":"1f44a-1f3fe","\uD83D\uDC4A\uD83C\uDFFD":"1f44a-1f3fd","\uD83D\uDC4A\uD83C\uDFFC":"1f44a-1f3fc","\uD83D\uDC4A\uD83C\uDFFB":"1f44a-1f3fb","\uD83D\uDC49\uD83C\uDFFF":"1f449-1f3ff","\uD83D\uDC49\uD83C\uDFFE":"1f449-1f3fe","\uD83D\uDC49\uD83C\uDFFD":"1f449-1f3fd","\uD83D\uDC49\uD83C\uDFFC":"1f449-1f3fc","\uD83D\uDC49\uD83C\uDFFB":"1f449-1f3fb","\uD83D\uDC48\uD83C\uDFFF":"1f448-1f3ff","\uD83D\uDC48\uD83C\uDFFE":"1f448-1f3fe","\uD83D\uDC48\uD83C\uDFFD":"1f448-1f3fd","\uD83D\uDC48\uD83C\uDFFC":"1f448-1f3fc","\uD83D\uDC48\uD83C\uDFFB":"1f448-1f3fb","\uD83D\uDC47\uD83C\uDFFF":"1f447-1f3ff","\uD83D\uDC47\uD83C\uDFFE":"1f447-1f3fe","\uD83D\uDC47\uD83C\uDFFD":"1f447-1f3fd","\uD83D\uDC47\uD83C\uDFFC":"1f447-1f3fc","\uD83D\uDC47\uD83C\uDFFB":"1f447-1f3fb","\uD83D\uDC46\uD83C\uDFFF":"1f446-1f3ff","\uD83D\uDC46\uD83C\uDFFE":"1f446-1f3fe","\uD83D\uDC46\uD83C\uDFFD":"1f446-1f3fd","\uD83D\uDC46\uD83C\uDFFC":"1f446-1f3fc","\uD83D\uDC46\uD83C\uDFFB":"1f446-1f3fb","\uD83D\uDC43\uD83C\uDFFF":"1f443-1f3ff","\uD83D\uDC43\uD83C\uDFFE":"1f443-1f3fe","\uD83D\uDC43\uD83C\uDFFD":"1f443-1f3fd","\uD83D\uDC43\uD83C\uDFFC":"1f443-1f3fc","\uD83D\uDC43\uD83C\uDFFB":"1f443-1f3fb","\uD83D\uDC42\uD83C\uDFFF":"1f442-1f3ff","\uD83D\uDC42\uD83C\uDFFE":"1f442-1f3fe","\uD83D\uDC42\uD83C\uDFFD":"1f442-1f3fd","\uD83D\uDC42\uD83C\uDFFC":"1f442-1f3fc","\uD83D\uDC42\uD83C\uDFFB":"1f442-1f3fb","\uD83C\uDFCB\uD83C\uDFFF":"1f3cb-1f3ff","\uD83C\uDFCB\uD83C\uDFFE":"1f3cb-1f3fe","\uD83C\uDFCB\uD83C\uDFFD":"1f3cb-1f3fd","\uD83C\uDFCB\uD83C\uDFFC":"1f3cb-1f3fc","\uD83C\uDFCB\uD83C\uDFFB":"1f3cb-1f3fb","\uD83C\uDFCA\uD83C\uDFFF":"1f3ca-1f3ff","\uD83C\uDFCA\uD83C\uDFFE":"1f3ca-1f3fe","\uD83C\uDFCA\uD83C\uDFFD":"1f3ca-1f3fd","\uD83C\uDFCA\uD83C\uDFFC":"1f3ca-1f3fc","\uD83C\uDFCA\uD83C\uDFFB":"1f3ca-1f3fb","\uD83C\uDFC7\uD83C\uDFFF":"1f3c7-1f3ff","\uD83C\uDFC7\uD83C\uDFFE":"1f3c7-1f3fe","\uD83C\uDFC7\uD83C\uDFFD":"1f3c7-1f3fd","\uD83C\uDFC7\uD83C\uDFFC":"1f3c7-1f3fc","\uD83C\uDFC7\uD83C\uDFFB":"1f3c7-1f3fb","\uD83C\uDFC4\uD83C\uDFFF":"1f3c4-1f3ff","\uD83C\uDFC4\uD83C\uDFFE":"1f3c4-1f3fe","\uD83C\uDFC4\uD83C\uDFFD":"1f3c4-1f3fd","\uD83C\uDFC4\uD83C\uDFFC":"1f3c4-1f3fc","\uD83C\uDFC4\uD83C\uDFFB":"1f3c4-1f3fb","\uD83C\uDFC3\uD83C\uDFFF":"1f3c3-1f3ff","\uD83C\uDFC3\uD83C\uDFFE":"1f3c3-1f3fe","\uD83C\uDFC3\uD83C\uDFFD":"1f3c3-1f3fd","\uD83C\uDFC3\uD83C\uDFFC":"1f3c3-1f3fc","\uD83C\uDFC3\uD83C\uDFFB":"1f3c3-1f3fb","\uD83C\uDF85\uD83C\uDFFF":"1f385-1f3ff","\uD83C\uDF85\uD83C\uDFFE":"1f385-1f3fe","\uD83C\uDF85\uD83C\uDFFD":"1f385-1f3fd","\uD83C\uDF85\uD83C\uDFFC":"1f385-1f3fc","\uD83C\uDF85\uD83C\uDFFB":"1f385-1f3fb","\uD83C\uDDFF\uD83C\uDDFC":"1f1ff-1f1fc","\uD83C\uDDFF\uD83C\uDDF2":"1f1ff-1f1f2","\uD83C\uDDFF\uD83C\uDDE6":"1f1ff-1f1e6","\uD83C\uDDFE\uD83C\uDDF9":"1f1fe-1f1f9","\uD83C\uDDFE\uD83C\uDDEA":"1f1fe-1f1ea","\uD83C\uDDFD\uD83C\uDDF0":"1f1fd-1f1f0","\uD83C\uDDFC\uD83C\uDDF8":"1f1fc-1f1f8","\uD83C\uDDFC\uD83C\uDDEB":"1f1fc-1f1eb","\uD83C\uDDFB\uD83C\uDDFA":"1f1fb-1f1fa","\uD83C\uDDFB\uD83C\uDDF3":"1f1fb-1f1f3","\uD83C\uDDFB\uD83C\uDDEE":"1f1fb-1f1ee","\uD83C\uDDFB\uD83C\uDDEC":"1f1fb-1f1ec","\uD83C\uDDFB\uD83C\uDDEA":"1f1fb-1f1ea","\uD83C\uDDFB\uD83C\uDDE8":"1f1fb-1f1e8","\uD83C\uDDFB\uD83C\uDDE6":"1f1fb-1f1e6","\uD83C\uDDFA\uD83C\uDDFF":"1f1fa-1f1ff","\uD83C\uDDFA\uD83C\uDDFE":"1f1fa-1f1fe","\uD83C\uDDFA\uD83C\uDDF8":"1f1fa-1f1f8","\uD83C\uDDFA\uD83C\uDDF2":"1f1fa-1f1f2","\uD83C\uDDFA\uD83C\uDDEC":"1f1fa-1f1ec","\uD83C\uDDFA\uD83C\uDDE6":"1f1fa-1f1e6","\uD83C\uDDF9\uD83C\uDDFF":"1f1f9-1f1ff","\uD83C\uDDF9\uD83C\uDDFC":"1f1f9-1f1fc","\uD83C\uDDF9\uD83C\uDDFB":"1f1f9-1f1fb","\uD83C\uDDF9\uD83C\uDDF9":"1f1f9-1f1f9","\uD83C\uDDF9\uD83C\uDDF7":"1f1f9-1f1f7","\uD83C\uDDF9\uD83C\uDDF4":"1f1f9-1f1f4","\uD83C\uDDF9\uD83C\uDDF3":"1f1f9-1f1f3","\uD83C\uDDF9\uD83C\uDDF2":"1f1f9-1f1f2","\uD83C\uDDF9\uD83C\uDDF1":"1f1f9-1f1f1","\uD83C\uDDF9\uD83C\uDDF0":"1f1f9-1f1f0","\uD83C\uDDF9\uD83C\uDDEF":"1f1f9-1f1ef","\uD83C\uDDF9\uD83C\uDDED":"1f1f9-1f1ed","\uD83C\uDDF9\uD83C\uDDEC":"1f1f9-1f1ec","\uD83C\uDDF9\uD83C\uDDEB":"1f1f9-1f1eb","\uD83C\uDDF9\uD83C\uDDE9":"1f1f9-1f1e9","\uD83C\uDDF9\uD83C\uDDE8":"1f1f9-1f1e8","\uD83C\uDDF9\uD83C\uDDE6":"1f1f9-1f1e6","\uD83C\uDDF8\uD83C\uDDFF":"1f1f8-1f1ff","\uD83C\uDDF8\uD83C\uDDFE":"1f1f8-1f1fe","\uD83C\uDDF8\uD83C\uDDFD":"1f1f8-1f1fd","\uD83C\uDDF8\uD83C\uDDFB":"1f1f8-1f1fb","\uD83C\uDDF8\uD83C\uDDF9":"1f1f8-1f1f9","\uD83C\uDDF8\uD83C\uDDF8":"1f1f8-1f1f8","\uD83C\uDDF8\uD83C\uDDF7":"1f1f8-1f1f7","\uD83C\uDDF8\uD83C\uDDF4":"1f1f8-1f1f4","\uD83C\uDDF8\uD83C\uDDF3":"1f1f8-1f1f3","\uD83C\uDDF8\uD83C\uDDF2":"1f1f8-1f1f2","\uD83C\uDDF8\uD83C\uDDF1":"1f1f8-1f1f1","\uD83C\uDDF8\uD83C\uDDF0":"1f1f8-1f1f0","\uD83C\uDDF8\uD83C\uDDEF":"1f1f8-1f1ef","\uD83C\uDDF8\uD83C\uDDEE":"1f1f8-1f1ee","\uD83C\uDDF8\uD83C\uDDED":"1f1f8-1f1ed","\uD83C\uDDF8\uD83C\uDDEC":"1f1f8-1f1ec","\uD83C\uDDF8\uD83C\uDDEA":"1f1f8-1f1ea","\uD83C\uDDF8\uD83C\uDDE9":"1f1f8-1f1e9","\uD83C\uDDF8\uD83C\uDDE8":"1f1f8-1f1e8","\uD83C\uDDF8\uD83C\uDDE7":"1f1f8-1f1e7","\uD83C\uDDF8\uD83C\uDDE6":"1f1f8-1f1e6","\uD83C\uDDF7\uD83C\uDDFC":"1f1f7-1f1fc","\uD83C\uDDF7\uD83C\uDDFA":"1f1f7-1f1fa","\uD83C\uDDF7\uD83C\uDDF8":"1f1f7-1f1f8","\uD83C\uDDF7\uD83C\uDDF4":"1f1f7-1f1f4","\uD83C\uDDF7\uD83C\uDDEA":"1f1f7-1f1ea","\uD83C\uDDF6\uD83C\uDDE6":"1f1f6-1f1e6","\uD83C\uDDF5\uD83C\uDDFE":"1f1f5-1f1fe","\uD83C\uDDF5\uD83C\uDDFC":"1f1f5-1f1fc","\uD83C\uDDF5\uD83C\uDDF9":"1f1f5-1f1f9","\uD83C\uDDF5\uD83C\uDDF8":"1f1f5-1f1f8","\uD83C\uDDF5\uD83C\uDDF7":"1f1f5-1f1f7","\uD83C\uDDF5\uD83C\uDDF3":"1f1f5-1f1f3","\uD83C\uDDF5\uD83C\uDDF2":"1f1f5-1f1f2","\uD83C\uDDF5\uD83C\uDDF1":"1f1f5-1f1f1","\uD83C\uDDF5\uD83C\uDDF0":"1f1f5-1f1f0","\uD83C\uDDF5\uD83C\uDDED":"1f1f5-1f1ed","\uD83C\uDDF5\uD83C\uDDEC":"1f1f5-1f1ec","\uD83C\uDDF5\uD83C\uDDEB":"1f1f5-1f1eb","\uD83C\uDDF5\uD83C\uDDEA":"1f1f5-1f1ea","\uD83C\uDDF5\uD83C\uDDE6":"1f1f5-1f1e6","\uD83C\uDDF4\uD83C\uDDF2":"1f1f4-1f1f2","\uD83C\uDDF3\uD83C\uDDFF":"1f1f3-1f1ff","\uD83C\uDDF3\uD83C\uDDFA":"1f1f3-1f1fa","\uD83C\uDDF3\uD83C\uDDF7":"1f1f3-1f1f7","\uD83C\uDDF3\uD83C\uDDF5":"1f1f3-1f1f5","\uD83C\uDDF3\uD83C\uDDF4":"1f1f3-1f1f4","\uD83C\uDDF3\uD83C\uDDF1":"1f1f3-1f1f1","\uD83C\uDDF3\uD83C\uDDEE":"1f1f3-1f1ee","\uD83C\uDDF3\uD83C\uDDEC":"1f1f3-1f1ec","\uD83C\uDDF3\uD83C\uDDEB":"1f1f3-1f1eb","\uD83C\uDDF3\uD83C\uDDEA":"1f1f3-1f1ea","\uD83C\uDDF3\uD83C\uDDE8":"1f1f3-1f1e8","\uD83C\uDDF3\uD83C\uDDE6":"1f1f3-1f1e6","\uD83C\uDDF2\uD83C\uDDFF":"1f1f2-1f1ff","\uD83C\uDDF2\uD83C\uDDFE":"1f1f2-1f1fe","\uD83C\uDDF2\uD83C\uDDFD":"1f1f2-1f1fd","\uD83C\uDDF2\uD83C\uDDFC":"1f1f2-1f1fc","\uD83C\uDDF2\uD83C\uDDFB":"1f1f2-1f1fb","\uD83C\uDDF2\uD83C\uDDFA":"1f1f2-1f1fa","\uD83C\uDDF2\uD83C\uDDF9":"1f1f2-1f1f9","\uD83C\uDDF2\uD83C\uDDF8":"1f1f2-1f1f8","\uD83C\uDDF2\uD83C\uDDF7":"1f1f2-1f1f7","\uD83C\uDDF2\uD83C\uDDF6":"1f1f2-1f1f6","\uD83C\uDDF2\uD83C\uDDF5":"1f1f2-1f1f5","\uD83C\uDDF2\uD83C\uDDF4":"1f1f2-1f1f4","\uD83C\uDDF2\uD83C\uDDF3":"1f1f2-1f1f3","\uD83C\uDDF2\uD83C\uDDF2":"1f1f2-1f1f2","\uD83C\uDDF2\uD83C\uDDF1":"1f1f2-1f1f1","\uD83C\uDDF2\uD83C\uDDF0":"1f1f2-1f1f0","\uD83C\uDDF2\uD83C\uDDED":"1f1f2-1f1ed","\uD83C\uDDF2\uD83C\uDDEC":"1f1f2-1f1ec","\uD83C\uDDF2\uD83C\uDDEB":"1f1f2-1f1eb","\uD83C\uDDF2\uD83C\uDDEA":"1f1f2-1f1ea","\uD83C\uDDF2\uD83C\uDDE9":"1f1f2-1f1e9","\uD83C\uDDF2\uD83C\uDDE8":"1f1f2-1f1e8","\uD83C\uDDF2\uD83C\uDDE6":"1f1f2-1f1e6","\uD83C\uDDF1\uD83C\uDDFE":"1f1f1-1f1fe","\uD83C\uDDF1\uD83C\uDDFB":"1f1f1-1f1fb","\uD83C\uDDF1\uD83C\uDDFA":"1f1f1-1f1fa","\uD83C\uDDF1\uD83C\uDDF9":"1f1f1-1f1f9","\uD83C\uDDF1\uD83C\uDDF8":"1f1f1-1f1f8","\uD83C\uDDF1\uD83C\uDDF7":"1f1f1-1f1f7","\uD83C\uDDF1\uD83C\uDDF0":"1f1f1-1f1f0","\uD83C\uDDF1\uD83C\uDDEE":"1f1f1-1f1ee","\uD83C\uDDF1\uD83C\uDDE8":"1f1f1-1f1e8","\uD83C\uDDF1\uD83C\uDDE7":"1f1f1-1f1e7","\uD83C\uDDF1\uD83C\uDDE6":"1f1f1-1f1e6","\uD83C\uDDF0\uD83C\uDDFF":"1f1f0-1f1ff","\uD83C\uDDF0\uD83C\uDDFE":"1f1f0-1f1fe","\uD83C\uDDF0\uD83C\uDDFC":"1f1f0-1f1fc","\uD83C\uDDF0\uD83C\uDDF7":"1f1f0-1f1f7","\uD83C\uDDF0\uD83C\uDDF5":"1f1f0-1f1f5","\uD83C\uDDF0\uD83C\uDDF3":"1f1f0-1f1f3","\uD83C\uDDF0\uD83C\uDDF2":"1f1f0-1f1f2","\uD83C\uDDF0\uD83C\uDDEE":"1f1f0-1f1ee","\uD83C\uDDF0\uD83C\uDDED":"1f1f0-1f1ed","\uD83C\uDDF0\uD83C\uDDEC":"1f1f0-1f1ec","\uD83C\uDDF0\uD83C\uDDEA":"1f1f0-1f1ea","\uD83C\uDDEF\uD83C\uDDF5":"1f1ef-1f1f5","\uD83C\uDDEF\uD83C\uDDF4":"1f1ef-1f1f4","\uD83C\uDDEF\uD83C\uDDF2":"1f1ef-1f1f2","\uD83C\uDDEF\uD83C\uDDEA":"1f1ef-1f1ea","\uD83C\uDDEE\uD83C\uDDF9":"1f1ee-1f1f9","\uD83C\uDDEE\uD83C\uDDF8":"1f1ee-1f1f8","\uD83C\uDDEE\uD83C\uDDF7":"1f1ee-1f1f7","\uD83C\uDDEE\uD83C\uDDF6":"1f1ee-1f1f6","\uD83C\uDDEE\uD83C\uDDF4":"1f1ee-1f1f4","\uD83C\uDDEE\uD83C\uDDF3":"1f1ee-1f1f3","\uD83C\uDDEE\uD83C\uDDF2":"1f1ee-1f1f2","\uD83C\uDDEE\uD83C\uDDF1":"1f1ee-1f1f1","\uD83C\uDDEE\uD83C\uDDEA":"1f1ee-1f1ea","\uD83C\uDDEE\uD83C\uDDE9":"1f1ee-1f1e9","\uD83C\uDDEE\uD83C\uDDE8":"1f1ee-1f1e8","\uD83C\uDDED\uD83C\uDDFA":"1f1ed-1f1fa","\uD83C\uDDED\uD83C\uDDF9":"1f1ed-1f1f9","\uD83C\uDDED\uD83C\uDDF7":"1f1ed-1f1f7","\uD83C\uDDED\uD83C\uDDF3":"1f1ed-1f1f3","\uD83C\uDDED\uD83C\uDDF2":"1f1ed-1f1f2","\uD83C\uDDED\uD83C\uDDF0":"1f1ed-1f1f0","\uD83C\uDDEC\uD83C\uDDFE":"1f1ec-1f1fe","\uD83C\uDDEC\uD83C\uDDFC":"1f1ec-1f1fc","\uD83C\uDDEC\uD83C\uDDFA":"1f1ec-1f1fa","\uD83C\uDDEC\uD83C\uDDF9":"1f1ec-1f1f9","\uD83C\uDDEC\uD83C\uDDF8":"1f1ec-1f1f8","\uD83C\uDDEC\uD83C\uDDF7":"1f1ec-1f1f7","\uD83C\uDDEC\uD83C\uDDF6":"1f1ec-1f1f6","\uD83C\uDDEC\uD83C\uDDF5":"1f1ec-1f1f5","\uD83C\uDDEC\uD83C\uDDF3":"1f1ec-1f1f3","\uD83C\uDDEC\uD83C\uDDF2":"1f1ec-1f1f2","\uD83C\uDDEC\uD83C\uDDF1":"1f1ec-1f1f1","\uD83C\uDDEC\uD83C\uDDEE":"1f1ec-1f1ee","\uD83C\uDDEC\uD83C\uDDED":"1f1ec-1f1ed","\uD83C\uDDEC\uD83C\uDDEC":"1f1ec-1f1ec","\uD83C\uDDEC\uD83C\uDDEB":"1f1ec-1f1eb","\uD83C\uDDEC\uD83C\uDDEA":"1f1ec-1f1ea","\uD83C\uDDEC\uD83C\uDDE9":"1f1ec-1f1e9","\uD83C\uDDEC\uD83C\uDDE7":"1f1ec-1f1e7","\uD83C\uDDEC\uD83C\uDDE6":"1f1ec-1f1e6","\uD83C\uDDEB\uD83C\uDDF7":"1f1eb-1f1f7","\uD83C\uDDEB\uD83C\uDDF4":"1f1eb-1f1f4","\uD83C\uDDEB\uD83C\uDDF2":"1f1eb-1f1f2","\uD83C\uDDEB\uD83C\uDDF0":"1f1eb-1f1f0","\uD83C\uDDEB\uD83C\uDDEF":"1f1eb-1f1ef","\uD83C\uDDEB\uD83C\uDDEE":"1f1eb-1f1ee","\uD83C\uDDEA\uD83C\uDDFA":"1f1ea-1f1fa","\uD83C\uDDEA\uD83C\uDDF9":"1f1ea-1f1f9","\uD83C\uDDEA\uD83C\uDDF8":"1f1ea-1f1f8","\uD83C\uDDEA\uD83C\uDDF7":"1f1ea-1f1f7","\uD83C\uDDEA\uD83C\uDDED":"1f1ea-1f1ed","\uD83C\uDDEA\uD83C\uDDEC":"1f1ea-1f1ec","\uD83C\uDDEA\uD83C\uDDEA":"1f1ea-1f1ea","\uD83C\uDDEA\uD83C\uDDE8":"1f1ea-1f1e8","\uD83C\uDDEA\uD83C\uDDE6":"1f1ea-1f1e6","\uD83C\uDDE9\uD83C\uDDFF":"1f1e9-1f1ff","\uD83C\uDDE9\uD83C\uDDF4":"1f1e9-1f1f4","\uD83C\uDDE9\uD83C\uDDF2":"1f1e9-1f1f2","\uD83C\uDDE9\uD83C\uDDF0":"1f1e9-1f1f0","\uD83C\uDDE9\uD83C\uDDEF":"1f1e9-1f1ef","\uD83C\uDDE9\uD83C\uDDEC":"1f1e9-1f1ec","\uD83C\uDDE9\uD83C\uDDEA":"1f1e9-1f1ea","\uD83C\uDDE8\uD83C\uDDFF":"1f1e8-1f1ff","\uD83C\uDDE8\uD83C\uDDFE":"1f1e8-1f1fe","\uD83C\uDDE8\uD83C\uDDFD":"1f1e8-1f1fd","\uD83C\uDDE8\uD83C\uDDFC":"1f1e8-1f1fc","\uD83C\uDDE8\uD83C\uDDFB":"1f1e8-1f1fb","\uD83C\uDDE8\uD83C\uDDFA":"1f1e8-1f1fa","\uD83C\uDDE8\uD83C\uDDF7":"1f1e8-1f1f7","\uD83C\uDDE8\uD83C\uDDF5":"1f1e8-1f1f5","\uD83C\uDDE8\uD83C\uDDF4":"1f1e8-1f1f4","\uD83C\uDDE8\uD83C\uDDF3":"1f1e8-1f1f3","\uD83C\uDDE8\uD83C\uDDF2":"1f1e8-1f1f2","\uD83C\uDDE8\uD83C\uDDF1":"1f1e8-1f1f1","\uD83C\uDDE8\uD83C\uDDF0":"1f1e8-1f1f0","\uD83C\uDDE8\uD83C\uDDEE":"1f1e8-1f1ee","\uD83C\uDDE8\uD83C\uDDED":"1f1e8-1f1ed","\uD83C\uDDE8\uD83C\uDDEC":"1f1e8-1f1ec","\uD83C\uDDE8\uD83C\uDDEB":"1f1e8-1f1eb","\uD83C\uDDE8\uD83C\uDDE9":"1f1e8-1f1e9","\uD83C\uDDE8\uD83C\uDDE8":"1f1e8-1f1e8","\uD83C\uDDE8\uD83C\uDDE6":"1f1e8-1f1e6","\uD83C\uDDE7\uD83C\uDDFF":"1f1e7-1f1ff","\uD83C\uDDE7\uD83C\uDDFE":"1f1e7-1f1fe","\uD83C\uDDE7\uD83C\uDDFC":"1f1e7-1f1fc","\uD83C\uDDE7\uD83C\uDDFB":"1f1e7-1f1fb","\uD83C\uDDE7\uD83C\uDDF9":"1f1e7-1f1f9","\uD83C\uDDE7\uD83C\uDDF8":"1f1e7-1f1f8","\uD83C\uDDE7\uD83C\uDDF7":"1f1e7-1f1f7","\uD83C\uDDE7\uD83C\uDDF6":"1f1e7-1f1f6","\uD83C\uDDE7\uD83C\uDDF4":"1f1e7-1f1f4","\uD83C\uDDE7\uD83C\uDDF3":"1f1e7-1f1f3","\uD83C\uDDE7\uD83C\uDDF2":"1f1e7-1f1f2","\uD83C\uDDE7\uD83C\uDDF1":"1f1e7-1f1f1","\uD83C\uDDE7\uD83C\uDDEF":"1f1e7-1f1ef","\uD83C\uDDE7\uD83C\uDDEE":"1f1e7-1f1ee","\uD83C\uDDE7\uD83C\uDDED":"1f1e7-1f1ed","\uD83C\uDDE7\uD83C\uDDEC":"1f1e7-1f1ec","\uD83C\uDDE7\uD83C\uDDEB":"1f1e7-1f1eb","\uD83C\uDDE7\uD83C\uDDEA":"1f1e7-1f1ea","\uD83C\uDDE7\uD83C\uDDE9":"1f1e7-1f1e9","\uD83C\uDDE7\uD83C\uDDE7":"1f1e7-1f1e7","\uD83C\uDDE7\uD83C\uDDE6":"1f1e7-1f1e6","\uD83C\uDDE6\uD83C\uDDFF":"1f1e6-1f1ff","\uD83C\uDDE6\uD83C\uDDFD":"1f1e6-1f1fd","\uD83C\uDDE6\uD83C\uDDFC":"1f1e6-1f1fc","\uD83C\uDDE6\uD83C\uDDFA":"1f1e6-1f1fa","\uD83C\uDDE6\uD83C\uDDF9":"1f1e6-1f1f9","\uD83C\uDDE6\uD83C\uDDF8":"1f1e6-1f1f8","\uD83C\uDDE6\uD83C\uDDF7":"1f1e6-1f1f7","\uD83C\uDDE6\uD83C\uDDF6":"1f1e6-1f1f6","\uD83C\uDDE6\uD83C\uDDF4":"1f1e6-1f1f4","\uD83C\uDDE6\uD83C\uDDF2":"1f1e6-1f1f2","\uD83C\uDDE6\uD83C\uDDF1":"1f1e6-1f1f1","\uD83C\uDDE6\uD83C\uDDEE":"1f1e6-1f1ee","\uD83C\uDDE6\uD83C\uDDEC":"1f1e6-1f1ec","\uD83C\uDDE6\uD83C\uDDEB":"1f1e6-1f1eb","\uD83C\uDDE6\uD83C\uDDEA":"1f1e6-1f1ea","\uD83C\uDDE6\uD83C\uDDE9":"1f1e6-1f1e9","\uD83C\uDDE6\uD83C\uDDE8":"1f1e6-1f1e8","\uD83C\uDC04\uFE0F":"1f004","\uD83C\uDD7F\uFE0F":"1f17f","\uD83C\uDE1A\uFE0F":"1f21a","\uD83C\uDE2F\uFE0F":"1f22f","\uD83C\uDE37\uFE0F":"1f237","\u261D\uD83C\uDFFB":"261d-1f3fb","\u261D\uD83C\uDFFC":"261d-1f3fc","\u261D\uD83C\uDFFD":"261d-1f3fd","\u261D\uD83C\uDFFE":"261d-1f3fe","\u261D\uD83C\uDFFF":"261d-1f3ff","\u270C\uD83C\uDFFB":"270c-1f3fb","\u270C\uD83C\uDFFC":"270c-1f3fc","\u270C\uD83C\uDFFD":"270c-1f3fd","\u270C\uD83C\uDFFE":"270c-1f3fe","\u270C\uD83C\uDFFF":"270c-1f3ff","\u270A\uD83C\uDFFB":"270a-1f3fb","\u270A\uD83C\uDFFC":"270a-1f3fc","\u270A\uD83C\uDFFD":"270a-1f3fd","\u270A\uD83C\uDFFE":"270a-1f3fe","\u270A\uD83C\uDFFF":"270a-1f3ff","\u270B\uD83C\uDFFB":"270b-1f3fb","\u270B\uD83C\uDFFC":"270b-1f3fc","\u270B\uD83C\uDFFD":"270b-1f3fd","\u270B\uD83C\uDFFE":"270b-1f3fe","\u270B\uD83C\uDFFF":"270b-1f3ff","\u270D\uD83C\uDFFB":"270d-1f3fb","\u270D\uD83C\uDFFC":"270d-1f3fc","\u270D\uD83C\uDFFD":"270d-1f3fd","\u270D\uD83C\uDFFE":"270d-1f3fe","\u270D\uD83C\uDFFF":"270d-1f3ff","\u26F9\uD83C\uDFFB":"26f9-1f3fb","\u26F9\uD83C\uDFFC":"26f9-1f3fc","\u26F9\uD83C\uDFFD":"26f9-1f3fd","\u26F9\uD83C\uDFFE":"26f9-1f3fe","\u26F9\uD83C\uDFFF":"26f9-1f3ff","\u00A9\uFE0F":"00a9","\u00AE\uFE0F":"00ae","\u203C\uFE0F":"203c","\u21A9\uFE0F":"21a9","\u21AA\uFE0F":"21aa","\u231A\uFE0F":"231a","\u231B\uFE0F":"231b","\u24C2\uFE0F":"24c2","\u25AA\uFE0F":"25aa","\u25AB\uFE0F":"25ab","\u25B6\uFE0F":"25b6","\u25C0\uFE0F":"25c0","\u25FB\uFE0F":"25fb","\u25FC\uFE0F":"25fc","\u25FD\uFE0F":"25fd","\u25FE\uFE0F":"25fe","\u260E\uFE0F":"260e","\u261D\uFE0F":"261d","\u263A\uFE0F":"263a","\u264A\uFE0F":"264a","\u264B\uFE0F":"264b","\u264C\uFE0F":"264c","\u264D\uFE0F":"264d","\u264E\uFE0F":"264e","\u264F\uFE0F":"264f","\u267B\uFE0F":"267b","\u267F\uFE0F":"267f","\u26A0\uFE0F":"26a0","\u26A1\uFE0F":"26a1","\u26AA\uFE0F":"26aa","\u26AB\uFE0F":"26ab","\u26BD\uFE0F":"26bd","\u26BE\uFE0F":"26be","\u26C4\uFE0F":"26c4","\u26C5\uFE0F":"26c5","\u26D4\uFE0F":"26d4","\u26EA\uFE0F":"26ea","\u26F2\uFE0F":"26f2","\u26F3\uFE0F":"26f3","\u26F5\uFE0F":"26f5","\u26FA\uFE0F":"26fa","\u26FD\uFE0F":"26fd","\u270C\uFE0F":"270c","\u270F\uFE0F":"270f","\u27A1\uFE0F":"27a1","\u2B05\uFE0F":"2b05","\u2B06\uFE0F":"2b06","\u2B07\uFE0F":"2b07","\u2B1B\uFE0F":"2b1b","\u2B1C\uFE0F":"2b1c","\u2B50\uFE0F":"2b50","\u2B55\uFE0F":"2b55","\u303D\uFE0F":"303d","\uD83C\uDCCF":"1f0cf","\uD83C\uDD70":"1f170","\uD83C\uDD71":"1f171","\uD83C\uDD7E":"1f17e","\uD83C\uDD8E":"1f18e","\uD83C\uDD91":"1f191","\uD83C\uDD92":"1f192","\uD83C\uDD93":"1f193","\uD83C\uDD94":"1f194","\uD83C\uDD95":"1f195","\uD83C\uDD96":"1f196","\uD83C\uDD97":"1f197","\uD83C\uDD98":"1f198","\uD83C\uDD99":"1f199","\uD83C\uDD9A":"1f19a","\uD83C\uDE01":"1f201","\uD83C\uDE02":"1f202","\uD83C\uDE32":"1f232","\uD83C\uDE33":"1f233","\uD83C\uDE34":"1f234","\uD83C\uDE35":"1f235","\uD83C\uDE36":"1f236","\uD83C\uDE38":"1f238","\uD83C\uDE39":"1f239","\uD83C\uDE3A":"1f23a","\uD83C\uDE50":"1f250","\uD83C\uDE51":"1f251","\uD83C\uDF00":"1f300","\uD83C\uDF01":"1f301","\uD83C\uDF02":"1f302","\uD83C\uDF03":"1f303","\uD83C\uDF04":"1f304","\uD83C\uDF05":"1f305","\uD83C\uDF06":"1f306","\uD83C\uDF07":"1f307","\uD83C\uDF08":"1f308","\uD83C\uDF09":"1f309","\uD83C\uDF0A":"1f30a","\uD83C\uDF0B":"1f30b","\uD83C\uDF0C":"1f30c","\uD83C\uDF0F":"1f30f","\uD83C\uDF11":"1f311","\uD83C\uDF13":"1f313","\uD83C\uDF14":"1f314","\uD83C\uDF15":"1f315","\uD83C\uDF19":"1f319","\uD83C\uDF1B":"1f31b","\uD83C\uDF1F":"1f31f","\uD83C\uDF20":"1f320","\uD83C\uDF30":"1f330","\uD83C\uDF31":"1f331","\uD83C\uDF34":"1f334","\uD83C\uDF35":"1f335","\uD83C\uDF37":"1f337","\uD83C\uDF38":"1f338","\uD83C\uDF39":"1f339","\uD83C\uDF3A":"1f33a","\uD83C\uDF3B":"1f33b","\uD83C\uDF3C":"1f33c","\uD83C\uDF3D":"1f33d","\uD83C\uDF3E":"1f33e","\uD83C\uDF3F":"1f33f","\uD83C\uDF40":"1f340","\uD83C\uDF41":"1f341","\uD83C\uDF42":"1f342","\uD83C\uDF43":"1f343","\uD83C\uDF44":"1f344","\uD83C\uDF45":"1f345","\uD83C\uDF46":"1f346","\uD83C\uDF47":"1f347","\uD83C\uDF48":"1f348","\uD83C\uDF49":"1f349","\uD83C\uDF4A":"1f34a","\uD83C\uDF4C":"1f34c","\uD83C\uDF4D":"1f34d","\uD83C\uDF4E":"1f34e","\uD83C\uDF4F":"1f34f","\uD83C\uDF51":"1f351","\uD83C\uDF52":"1f352","\uD83C\uDF53":"1f353","\uD83C\uDF54":"1f354","\uD83C\uDF55":"1f355","\uD83C\uDF56":"1f356","\uD83C\uDF57":"1f357","\uD83C\uDF58":"1f358","\uD83C\uDF59":"1f359","\uD83C\uDF5A":"1f35a","\uD83C\uDF5B":"1f35b","\uD83C\uDF5C":"1f35c","\uD83C\uDF5D":"1f35d","\uD83C\uDF5E":"1f35e","\uD83C\uDF5F":"1f35f","\uD83C\uDF60":"1f360","\uD83C\uDF61":"1f361","\uD83C\uDF62":"1f362","\uD83C\uDF63":"1f363","\uD83C\uDF64":"1f364","\uD83C\uDF65":"1f365","\uD83C\uDF66":"1f366","\uD83C\uDF67":"1f367","\uD83C\uDF68":"1f368","\uD83C\uDF69":"1f369","\uD83C\uDF6A":"1f36a","\uD83C\uDF6B":"1f36b","\uD83C\uDF6C":"1f36c","\uD83C\uDF6D":"1f36d","\uD83C\uDF6E":"1f36e","\uD83C\uDF6F":"1f36f","\uD83C\uDF70":"1f370","\uD83C\uDF71":"1f371","\uD83C\uDF72":"1f372","\uD83C\uDF73":"1f373","\uD83C\uDF74":"1f374","\uD83C\uDF75":"1f375","\uD83C\uDF76":"1f376","\uD83C\uDF77":"1f377","\uD83C\uDF78":"1f378","\uD83C\uDF79":"1f379","\uD83C\uDF7A":"1f37a","\uD83C\uDF7B":"1f37b","\uD83C\uDF80":"1f380","\uD83C\uDF81":"1f381","\uD83C\uDF82":"1f382","\uD83C\uDF83":"1f383","\uD83C\uDF84":"1f384","\uD83C\uDF85":"1f385","\uD83C\uDF86":"1f386","\uD83C\uDF87":"1f387","\uD83C\uDF88":"1f388","\uD83C\uDF89":"1f389","\uD83C\uDF8A":"1f38a","\uD83C\uDF8B":"1f38b","\uD83C\uDF8C":"1f38c","\uD83C\uDF8D":"1f38d","\uD83C\uDF8E":"1f38e","\uD83C\uDF8F":"1f38f","\uD83C\uDF90":"1f390","\uD83C\uDF91":"1f391","\uD83C\uDF92":"1f392","\uD83C\uDF93":"1f393","\uD83C\uDFA0":"1f3a0","\uD83C\uDFA1":"1f3a1","\uD83C\uDFA2":"1f3a2","\uD83C\uDFA3":"1f3a3","\uD83C\uDFA4":"1f3a4","\uD83C\uDFA5":"1f3a5","\uD83C\uDFA6":"1f3a6","\uD83C\uDFA7":"1f3a7","\uD83C\uDFA8":"1f3a8","\uD83C\uDFA9":"1f3a9","\uD83C\uDFAA":"1f3aa","\uD83C\uDFAB":"1f3ab","\uD83C\uDFAC":"1f3ac","\uD83C\uDFAD":"1f3ad","\uD83C\uDFAE":"1f3ae","\uD83C\uDFAF":"1f3af","\uD83C\uDFB0":"1f3b0","\uD83C\uDFB1":"1f3b1","\uD83C\uDFB2":"1f3b2","\uD83C\uDFB3":"1f3b3","\uD83C\uDFB4":"1f3b4","\uD83C\uDFB5":"1f3b5","\uD83C\uDFB6":"1f3b6","\uD83C\uDFB7":"1f3b7","\uD83C\uDFB8":"1f3b8","\uD83C\uDFB9":"1f3b9","\uD83C\uDFBA":"1f3ba","\uD83C\uDFBB":"1f3bb","\uD83C\uDFBC":"1f3bc","\uD83C\uDFBD":"1f3bd","\uD83C\uDFBE":"1f3be","\uD83C\uDFBF":"1f3bf","\uD83C\uDFC0":"1f3c0","\uD83C\uDFC1":"1f3c1","\uD83C\uDFC2":"1f3c2","\uD83C\uDFC3":"1f3c3","\uD83C\uDFC4":"1f3c4","\uD83C\uDFC6":"1f3c6","\uD83C\uDFC8":"1f3c8","\uD83C\uDFCA":"1f3ca","\uD83C\uDFE0":"1f3e0","\uD83C\uDFE1":"1f3e1","\uD83C\uDFE2":"1f3e2","\uD83C\uDFE3":"1f3e3","\uD83C\uDFE5":"1f3e5","\uD83C\uDFE6":"1f3e6","\uD83C\uDFE7":"1f3e7","\uD83C\uDFE8":"1f3e8","\uD83C\uDFE9":"1f3e9","\uD83C\uDFEA":"1f3ea","\uD83C\uDFEB":"1f3eb","\uD83C\uDFEC":"1f3ec","\uD83C\uDFED":"1f3ed","\uD83C\uDFEE":"1f3ee","\uD83C\uDFEF":"1f3ef","\uD83C\uDFF0":"1f3f0","\uD83D\uDC0C":"1f40c","\uD83D\uDC0D":"1f40d","\uD83D\uDC0E":"1f40e","\uD83D\uDC11":"1f411","\uD83D\uDC12":"1f412","\uD83D\uDC14":"1f414","\uD83D\uDC17":"1f417","\uD83D\uDC18":"1f418","\uD83D\uDC19":"1f419","\uD83D\uDC1A":"1f41a","\uD83D\uDC1B":"1f41b","\uD83D\uDC1C":"1f41c","\uD83D\uDC1D":"1f41d","\uD83D\uDC1E":"1f41e","\uD83D\uDC1F":"1f41f","\uD83D\uDC20":"1f420","\uD83D\uDC21":"1f421","\uD83D\uDC22":"1f422","\uD83D\uDC23":"1f423","\uD83D\uDC24":"1f424","\uD83D\uDC25":"1f425","\uD83D\uDC26":"1f426","\uD83D\uDC27":"1f427","\uD83D\uDC28":"1f428","\uD83D\uDC29":"1f429","\uD83D\uDC2B":"1f42b","\uD83D\uDC2C":"1f42c","\uD83D\uDC2D":"1f42d","\uD83D\uDC2E":"1f42e","\uD83D\uDC2F":"1f42f","\uD83D\uDC30":"1f430","\uD83D\uDC31":"1f431","\uD83D\uDC32":"1f432","\uD83D\uDC33":"1f433","\uD83D\uDC34":"1f434","\uD83D\uDC35":"1f435","\uD83D\uDC36":"1f436","\uD83D\uDC37":"1f437","\uD83D\uDC38":"1f438","\uD83D\uDC39":"1f439","\uD83D\uDC3A":"1f43a","\uD83D\uDC3B":"1f43b","\uD83D\uDC3C":"1f43c","\uD83D\uDC3D":"1f43d","\uD83D\uDC3E":"1f43e","\uD83D\uDC40":"1f440","\uD83D\uDC42":"1f442","\uD83D\uDC43":"1f443","\uD83D\uDC44":"1f444","\uD83D\uDC45":"1f445","\uD83D\uDC46":"1f446","\uD83D\uDC47":"1f447","\uD83D\uDC48":"1f448","\uD83D\uDC49":"1f449","\uD83D\uDC4A":"1f44a","\uD83D\uDC4B":"1f44b","\uD83D\uDC4C":"1f44c","\uD83D\uDC4D":"1f44d","\uD83D\uDC4E":"1f44e","\uD83D\uDC4F":"1f44f","\uD83D\uDC50":"1f450","\uD83D\uDC51":"1f451","\uD83D\uDC52":"1f452","\uD83D\uDC53":"1f453","\uD83D\uDC54":"1f454","\uD83D\uDC55":"1f455","\uD83D\uDC56":"1f456","\uD83D\uDC57":"1f457","\uD83D\uDC58":"1f458","\uD83D\uDC59":"1f459","\uD83D\uDC5A":"1f45a","\uD83D\uDC5B":"1f45b","\uD83D\uDC5C":"1f45c","\uD83D\uDC5D":"1f45d","\uD83D\uDC5E":"1f45e","\uD83D\uDC5F":"1f45f","\uD83D\uDC60":"1f460","\uD83D\uDC61":"1f461","\uD83D\uDC62":"1f462","\uD83D\uDC63":"1f463","\uD83D\uDC64":"1f464","\uD83D\uDC66":"1f466","\uD83D\uDC67":"1f467","\uD83D\uDC68":"1f468","\uD83D\uDC69":"1f469","\uD83D\uDC6A":"1f46a","\uD83D\uDC6B":"1f46b","\uD83D\uDC6E":"1f46e","\uD83D\uDC6F":"1f46f","\uD83D\uDC70":"1f470","\uD83D\uDC71":"1f471","\uD83D\uDC72":"1f472","\uD83D\uDC73":"1f473","\uD83D\uDC74":"1f474","\uD83D\uDC75":"1f475","\uD83D\uDC76":"1f476","\uD83D\uDC77":"1f477","\uD83D\uDC78":"1f478","\uD83D\uDC79":"1f479","\uD83D\uDC7A":"1f47a","\uD83D\uDC7B":"1f47b","\uD83D\uDC7C":"1f47c","\uD83D\uDC7D":"1f47d","\uD83D\uDC7E":"1f47e","\uD83D\uDC7F":"1f47f","\uD83D\uDC80":"1f480","\uD83D\uDCC7":"1f4c7","\uD83D\uDC81":"1f481","\uD83D\uDC82":"1f482","\uD83D\uDC83":"1f483","\uD83D\uDC84":"1f484","\uD83D\uDC85":"1f485","\uD83D\uDCD2":"1f4d2","\uD83D\uDC86":"1f486","\uD83D\uDCD3":"1f4d3","\uD83D\uDC87":"1f487","\uD83D\uDCD4":"1f4d4","\uD83D\uDC88":"1f488","\uD83D\uDCD5":"1f4d5","\uD83D\uDC89":"1f489","\uD83D\uDCD6":"1f4d6","\uD83D\uDC8A":"1f48a","\uD83D\uDCD7":"1f4d7","\uD83D\uDC8B":"1f48b","\uD83D\uDCD8":"1f4d8","\uD83D\uDC8C":"1f48c","\uD83D\uDCD9":"1f4d9","\uD83D\uDC8D":"1f48d","\uD83D\uDCDA":"1f4da","\uD83D\uDC8E":"1f48e","\uD83D\uDCDB":"1f4db","\uD83D\uDC8F":"1f48f","\uD83D\uDCDC":"1f4dc","\uD83D\uDC90":"1f490","\uD83D\uDCDD":"1f4dd","\uD83D\uDC91":"1f491","\uD83D\uDCDE":"1f4de","\uD83D\uDC92":"1f492","\uD83D\uDCDF":"1f4df","\uD83D\uDCE0":"1f4e0","\uD83D\uDC93":"1f493","\uD83D\uDCE1":"1f4e1","\uD83D\uDCE2":"1f4e2","\uD83D\uDC94":"1f494","\uD83D\uDCE3":"1f4e3","\uD83D\uDCE4":"1f4e4","\uD83D\uDC95":"1f495","\uD83D\uDCE5":"1f4e5","\uD83D\uDCE6":"1f4e6","\uD83D\uDC96":"1f496","\uD83D\uDCE7":"1f4e7","\uD83D\uDCE8":"1f4e8","\uD83D\uDC97":"1f497","\uD83D\uDCE9":"1f4e9","\uD83D\uDCEA":"1f4ea","\uD83D\uDC98":"1f498","\uD83D\uDCEB":"1f4eb","\uD83D\uDCEE":"1f4ee","\uD83D\uDC99":"1f499","\uD83D\uDCF0":"1f4f0","\uD83D\uDCF1":"1f4f1","\uD83D\uDC9A":"1f49a","\uD83D\uDCF2":"1f4f2","\uD83D\uDCF3":"1f4f3","\uD83D\uDC9B":"1f49b","\uD83D\uDCF4":"1f4f4","\uD83D\uDCF6":"1f4f6","\uD83D\uDC9C":"1f49c","\uD83D\uDCF7":"1f4f7","\uD83D\uDCF9":"1f4f9","\uD83D\uDC9D":"1f49d","\uD83D\uDCFA":"1f4fa","\uD83D\uDCFB":"1f4fb","\uD83D\uDC9E":"1f49e","\uD83D\uDCFC":"1f4fc","\uD83D\uDD03":"1f503","\uD83D\uDC9F":"1f49f","\uD83D\uDD0A":"1f50a","\uD83D\uDD0B":"1f50b","\uD83D\uDCA0":"1f4a0","\uD83D\uDD0C":"1f50c","\uD83D\uDD0D":"1f50d","\uD83D\uDCA1":"1f4a1","\uD83D\uDD0E":"1f50e","\uD83D\uDD0F":"1f50f","\uD83D\uDCA2":"1f4a2","\uD83D\uDD10":"1f510","\uD83D\uDD11":"1f511","\uD83D\uDCA3":"1f4a3","\uD83D\uDD12":"1f512","\uD83D\uDD13":"1f513","\uD83D\uDCA4":"1f4a4","\uD83D\uDD14":"1f514","\uD83D\uDD16":"1f516","\uD83D\uDCA5":"1f4a5","\uD83D\uDD17":"1f517","\uD83D\uDD18":"1f518","\uD83D\uDCA6":"1f4a6","\uD83D\uDD19":"1f519","\uD83D\uDD1A":"1f51a","\uD83D\uDCA7":"1f4a7","\uD83D\uDD1B":"1f51b","\uD83D\uDD1C":"1f51c","\uD83D\uDCA8":"1f4a8","\uD83D\uDD1D":"1f51d","\uD83D\uDD1E":"1f51e","\uD83D\uDCA9":"1f4a9","\uD83D\uDD1F":"1f51f","\uD83D\uDCAA":"1f4aa","\uD83D\uDD20":"1f520","\uD83D\uDD21":"1f521","\uD83D\uDCAB":"1f4ab","\uD83D\uDD22":"1f522","\uD83D\uDD23":"1f523","\uD83D\uDCAC":"1f4ac","\uD83D\uDD24":"1f524","\uD83D\uDD25":"1f525","\uD83D\uDCAE":"1f4ae","\uD83D\uDD26":"1f526","\uD83D\uDD27":"1f527","\uD83D\uDCAF":"1f4af","\uD83D\uDD28":"1f528","\uD83D\uDD29":"1f529","\uD83D\uDCB0":"1f4b0","\uD83D\uDD2A":"1f52a","\uD83D\uDD2B":"1f52b","\uD83D\uDCB1":"1f4b1","\uD83D\uDD2E":"1f52e","\uD83D\uDCB2":"1f4b2","\uD83D\uDD2F":"1f52f","\uD83D\uDCB3":"1f4b3","\uD83D\uDD30":"1f530","\uD83D\uDD31":"1f531","\uD83D\uDCB4":"1f4b4","\uD83D\uDD32":"1f532","\uD83D\uDD33":"1f533","\uD83D\uDCB5":"1f4b5","\uD83D\uDD34":"1f534","\uD83D\uDD35":"1f535","\uD83D\uDCB8":"1f4b8","\uD83D\uDD36":"1f536","\uD83D\uDD37":"1f537","\uD83D\uDCB9":"1f4b9","\uD83D\uDD38":"1f538","\uD83D\uDD39":"1f539","\uD83D\uDCBA":"1f4ba","\uD83D\uDD3A":"1f53a","\uD83D\uDD3B":"1f53b","\uD83D\uDCBB":"1f4bb","\uD83D\uDD3C":"1f53c","\uD83D\uDCBC":"1f4bc","\uD83D\uDD3D":"1f53d","\uD83D\uDD50":"1f550","\uD83D\uDCBD":"1f4bd","\uD83D\uDD51":"1f551","\uD83D\uDCBE":"1f4be","\uD83D\uDD52":"1f552","\uD83D\uDCBF":"1f4bf","\uD83D\uDD53":"1f553","\uD83D\uDCC0":"1f4c0","\uD83D\uDD54":"1f554","\uD83D\uDD55":"1f555","\uD83D\uDCC1":"1f4c1","\uD83D\uDD56":"1f556","\uD83D\uDD57":"1f557","\uD83D\uDCC2":"1f4c2","\uD83D\uDD58":"1f558","\uD83D\uDD59":"1f559","\uD83D\uDCC3":"1f4c3","\uD83D\uDD5A":"1f55a","\uD83D\uDD5B":"1f55b","\uD83D\uDCC4":"1f4c4","\uD83D\uDDFB":"1f5fb","\uD83D\uDDFC":"1f5fc","\uD83D\uDCC5":"1f4c5","\uD83D\uDDFD":"1f5fd","\uD83D\uDDFE":"1f5fe","\uD83D\uDCC6":"1f4c6","\uD83D\uDDFF":"1f5ff","\uD83D\uDE01":"1f601","\uD83D\uDE02":"1f602","\uD83D\uDE03":"1f603","\uD83D\uDCC8":"1f4c8","\uD83D\uDE04":"1f604","\uD83D\uDE05":"1f605","\uD83D\uDCC9":"1f4c9","\uD83D\uDE06":"1f606","\uD83D\uDE09":"1f609","\uD83D\uDCCA":"1f4ca","\uD83D\uDE0A":"1f60a","\uD83D\uDE0B":"1f60b","\uD83D\uDCCB":"1f4cb","\uD83D\uDE0C":"1f60c","\uD83D\uDE0D":"1f60d","\uD83D\uDCCC":"1f4cc","\uD83D\uDE0F":"1f60f","\uD83D\uDE12":"1f612","\uD83D\uDCCD":"1f4cd","\uD83D\uDE13":"1f613","\uD83D\uDE14":"1f614","\uD83D\uDCCE":"1f4ce","\uD83D\uDE16":"1f616","\uD83D\uDE18":"1f618","\uD83D\uDCCF":"1f4cf","\uD83D\uDE1A":"1f61a","\uD83D\uDE1C":"1f61c","\uD83D\uDCD0":"1f4d0","\uD83D\uDE1D":"1f61d","\uD83D\uDE1E":"1f61e","\uD83D\uDCD1":"1f4d1","\uD83D\uDE20":"1f620","\uD83D\uDE21":"1f621","\uD83D\uDE22":"1f622","\uD83D\uDE23":"1f623","\uD83D\uDE24":"1f624","\uD83D\uDE25":"1f625","\uD83D\uDE28":"1f628","\uD83D\uDE29":"1f629","\uD83D\uDE2A":"1f62a","\uD83D\uDE2B":"1f62b","\uD83D\uDE2D":"1f62d","\uD83D\uDE30":"1f630","\uD83D\uDE31":"1f631","\uD83D\uDE32":"1f632","\uD83D\uDE33":"1f633","\uD83D\uDE35":"1f635","\uD83D\uDE37":"1f637","\uD83D\uDE38":"1f638","\uD83D\uDE39":"1f639","\uD83D\uDE3A":"1f63a","\uD83D\uDE3B":"1f63b","\uD83D\uDE3C":"1f63c","\uD83D\uDE3D":"1f63d","\uD83D\uDE3E":"1f63e","\uD83D\uDE3F":"1f63f","\uD83D\uDE40":"1f640","\uD83D\uDE45":"1f645","\uD83D\uDE46":"1f646","\uD83D\uDE47":"1f647","\uD83D\uDE48":"1f648","\uD83D\uDE49":"1f649","\uD83D\uDE4A":"1f64a","\uD83D\uDE4B":"1f64b","\uD83D\uDE4C":"1f64c","\uD83D\uDE4D":"1f64d","\uD83D\uDE4E":"1f64e","\uD83D\uDE4F":"1f64f","\uD83D\uDE80":"1f680","\uD83D\uDE83":"1f683","\uD83D\uDE84":"1f684","\uD83D\uDE85":"1f685","\uD83D\uDE87":"1f687","\uD83D\uDE89":"1f689","\uD83D\uDE8C":"1f68c","\uD83D\uDE8F":"1f68f","\uD83D\uDE91":"1f691","\uD83D\uDE92":"1f692","\uD83D\uDE93":"1f693","\uD83D\uDE95":"1f695","\uD83D\uDE97":"1f697","\uD83D\uDE99":"1f699","\uD83D\uDE9A":"1f69a","\uD83D\uDEA2":"1f6a2","\uD83D\uDEA4":"1f6a4","\uD83D\uDEA5":"1f6a5","\uD83D\uDEA7":"1f6a7","\uD83D\uDEA8":"1f6a8","\uD83D\uDEA9":"1f6a9","\uD83D\uDEAA":"1f6aa","\uD83D\uDEAB":"1f6ab","\uD83D\uDEAC":"1f6ac","\uD83D\uDEAD":"1f6ad","\uD83D\uDEB2":"1f6b2","\uD83D\uDEB6":"1f6b6","\uD83D\uDEB9":"1f6b9","\uD83D\uDEBA":"1f6ba","\uD83D\uDEBB":"1f6bb","\uD83D\uDEBC":"1f6bc","\uD83D\uDEBD":"1f6bd","\uD83D\uDEBE":"1f6be","\uD83D\uDEC0":"1f6c0","\uD83E\uDD18":"1f918","\uD83D\uDE00":"1f600","\uD83D\uDE07":"1f607","\uD83D\uDE08":"1f608","\uD83D\uDE0E":"1f60e","\uD83D\uDE10":"1f610","\uD83D\uDE11":"1f611","\uD83D\uDE15":"1f615","\uD83D\uDE17":"1f617","\uD83D\uDE19":"1f619","\uD83D\uDE1B":"1f61b","\uD83D\uDE1F":"1f61f","\uD83D\uDE26":"1f626","\uD83D\uDE27":"1f627","\uD83D\uDE2C":"1f62c","\uD83D\uDE2E":"1f62e","\uD83D\uDE2F":"1f62f","\uD83D\uDE34":"1f634","\uD83D\uDE36":"1f636","\uD83D\uDE81":"1f681","\uD83D\uDE82":"1f682","\uD83D\uDE86":"1f686","\uD83D\uDE88":"1f688","\uD83D\uDE8A":"1f68a","\uD83D\uDE8D":"1f68d","\uD83D\uDE8E":"1f68e","\uD83D\uDE90":"1f690","\uD83D\uDE94":"1f694","\uD83D\uDE96":"1f696","\uD83D\uDE98":"1f698","\uD83D\uDE9B":"1f69b","\uD83D\uDE9C":"1f69c","\uD83D\uDE9D":"1f69d","\uD83D\uDE9E":"1f69e","\uD83D\uDE9F":"1f69f","\uD83D\uDEA0":"1f6a0","\uD83D\uDEA1":"1f6a1","\uD83D\uDEA3":"1f6a3","\uD83D\uDEA6":"1f6a6","\uD83D\uDEAE":"1f6ae","\uD83D\uDEAF":"1f6af","\uD83D\uDEB0":"1f6b0","\uD83D\uDEB1":"1f6b1","\uD83D\uDEB3":"1f6b3","\uD83D\uDEB4":"1f6b4","\uD83D\uDEB5":"1f6b5","\uD83D\uDEB7":"1f6b7","\uD83D\uDEB8":"1f6b8","\uD83D\uDEBF":"1f6bf","\uD83D\uDEC1":"1f6c1","\uD83D\uDEC2":"1f6c2","\uD83D\uDEC3":"1f6c3","\uD83D\uDEC4":"1f6c4","\uD83D\uDEC5":"1f6c5","\uD83C\uDF0D":"1f30d","\uD83C\uDF0E":"1f30e","\uD83C\uDF10":"1f310","\uD83C\uDF12":"1f312","\uD83C\uDF16":"1f316","\uD83C\uDF17":"1f317","\uD83C\uDF18":"1f318","\uD83C\uDF1A":"1f31a","\uD83C\uDF1C":"1f31c","\uD83C\uDF1D":"1f31d","\uD83C\uDF1E":"1f31e","\uD83C\uDF32":"1f332","\uD83C\uDF33":"1f333","\uD83C\uDF4B":"1f34b","\uD83C\uDF50":"1f350","\uD83C\uDF7C":"1f37c","\uD83C\uDFC7":"1f3c7","\uD83C\uDFC9":"1f3c9","\uD83C\uDFE4":"1f3e4","\uD83D\uDC00":"1f400","\uD83D\uDC01":"1f401","\uD83D\uDC02":"1f402","\uD83D\uDC03":"1f403","\uD83D\uDC04":"1f404","\uD83D\uDC05":"1f405","\uD83D\uDC06":"1f406","\uD83D\uDC07":"1f407","\uD83D\uDC08":"1f408","\uD83D\uDC09":"1f409","\uD83D\uDC0A":"1f40a","\uD83D\uDC0B":"1f40b","\uD83D\uDC0F":"1f40f","\uD83D\uDC10":"1f410","\uD83D\uDC13":"1f413","\uD83D\uDC15":"1f415","\uD83D\uDC16":"1f416","\uD83D\uDC2A":"1f42a","\uD83D\uDC65":"1f465","\uD83D\uDC6C":"1f46c","\uD83D\uDC6D":"1f46d","\uD83D\uDCAD":"1f4ad","\uD83D\uDCB6":"1f4b6","\uD83D\uDCB7":"1f4b7","\uD83D\uDCEC":"1f4ec","\uD83D\uDCED":"1f4ed","\uD83D\uDCEF":"1f4ef","\uD83D\uDCF5":"1f4f5","\uD83D\uDD00":"1f500","\uD83D\uDD01":"1f501","\uD83D\uDD02":"1f502","\uD83D\uDD04":"1f504","\uD83D\uDD05":"1f505","\uD83D\uDD06":"1f506","\uD83D\uDD07":"1f507","\uD83D\uDD09":"1f509","\uD83D\uDD15":"1f515","\uD83D\uDD2C":"1f52c","\uD83D\uDD2D":"1f52d","\uD83D\uDD5C":"1f55c","\uD83D\uDD5D":"1f55d","\uD83D\uDD5E":"1f55e","\uD83D\uDD5F":"1f55f","\uD83D\uDD60":"1f560","\uD83D\uDD61":"1f561","\uD83D\uDD62":"1f562","\uD83D\uDD63":"1f563","\uD83D\uDD64":"1f564","\uD83D\uDD65":"1f565","\uD83D\uDD66":"1f566","\uD83D\uDD67":"1f567","\uD83D\uDD08":"1f508","\uD83D\uDE8B":"1f68b","\uD83C\uDF9E":"1f39e","\uD83C\uDF9F":"1f39f","\uD83C\uDFC5":"1f3c5","\uD83C\uDFCB":"1f3cb","\uD83C\uDFCC":"1f3cc","\uD83C\uDFCD":"1f3cd","\uD83C\uDFCE":"1f3ce","\uD83C\uDF96":"1f396","\uD83C\uDF97":"1f397","\uD83C\uDF36":"1f336","\uD83C\uDF27":"1f327","\uD83C\uDF28":"1f328","\uD83C\uDF29":"1f329","\uD83C\uDF2A":"1f32a","\uD83C\uDF2B":"1f32b","\uD83C\uDF2C":"1f32c","\uD83D\uDC3F":"1f43f","\uD83D\uDD77":"1f577","\uD83D\uDD78":"1f578","\uD83C\uDF21":"1f321","\uD83C\uDF99":"1f399","\uD83C\uDF9A":"1f39a","\uD83C\uDF9B":"1f39b","\uD83C\uDFF3":"1f3f3","\uD83C\uDFF4":"1f3f4","\uD83C\uDFF5":"1f3f5","\uD83C\uDFF7":"1f3f7","\uD83D\uDCF8":"1f4f8","\uD83D\uDCFD":"1f4fd","\uD83D\uDD49":"1f549","\uD83D\uDD4A":"1f54a","\uD83D\uDD6F":"1f56f","\uD83D\uDD70":"1f570","\uD83D\uDD73":"1f573","\uD83D\uDD76":"1f576","\uD83D\uDD79":"1f579","\uD83D\uDD87":"1f587","\uD83D\uDD8A":"1f58a","\uD83D\uDD8B":"1f58b","\uD83D\uDD8C":"1f58c","\uD83D\uDD8D":"1f58d","\uD83D\uDDA5":"1f5a5","\uD83D\uDDA8":"1f5a8","\uD83D\uDDB2":"1f5b2","\uD83D\uDDBC":"1f5bc","\uD83D\uDDC2":"1f5c2","\uD83D\uDDC3":"1f5c3","\uD83D\uDDC4":"1f5c4","\uD83D\uDDD1":"1f5d1","\uD83D\uDDD2":"1f5d2","\uD83D\uDDD3":"1f5d3","\uD83D\uDDDC":"1f5dc","\uD83D\uDDDD":"1f5dd","\uD83D\uDDDE":"1f5de","\uD83D\uDDE1":"1f5e1","\uD83D\uDDE3":"1f5e3","\uD83D\uDDEF":"1f5ef","\uD83D\uDDF3":"1f5f3","\uD83D\uDDFA":"1f5fa","\uD83D\uDECC":"1f6cc","\uD83D\uDEE0":"1f6e0","\uD83D\uDEE1":"1f6e1","\uD83D\uDEE2":"1f6e2","\uD83D\uDEF0":"1f6f0","\uD83C\uDF7D":"1f37d","\uD83D\uDC41":"1f441","\uD83D\uDD74":"1f574","\uD83D\uDD75":"1f575","\uD83D\uDD90":"1f590","\uD83D\uDD95":"1f595","\uD83D\uDD96":"1f596","\uD83D\uDE41":"1f641","\uD83D\uDE42":"1f642","\uD83C\uDFD4":"1f3d4","\uD83C\uDFD5":"1f3d5","\uD83C\uDFD6":"1f3d6","\uD83C\uDFD7":"1f3d7","\uD83C\uDFD8":"1f3d8","\uD83C\uDFD9":"1f3d9","\uD83C\uDFDA":"1f3da","\uD83C\uDFDB":"1f3db","\uD83C\uDFDC":"1f3dc","\uD83C\uDFDD":"1f3dd","\uD83C\uDFDE":"1f3de","\uD83C\uDFDF":"1f3df","\uD83D\uDECB":"1f6cb","\uD83D\uDECD":"1f6cd","\uD83D\uDECE":"1f6ce","\uD83D\uDECF":"1f6cf","\uD83D\uDEE3":"1f6e3","\uD83D\uDEE4":"1f6e4","\uD83D\uDEE5":"1f6e5","\uD83D\uDEE9":"1f6e9","\uD83D\uDEEB":"1f6eb","\uD83D\uDEEC":"1f6ec","\uD83D\uDEF3":"1f6f3","\uD83C\uDFFB":"1f3fb","\uD83C\uDFFC":"1f3fc","\uD83C\uDFFD":"1f3fd","\uD83C\uDFFE":"1f3fe","\uD83C\uDFFF":"1f3ff","\uD83C\uDF24":"1f324","\uD83C\uDF25":"1f325","\uD83C\uDF26":"1f326","\uD83D\uDDB1":"1f5b1","\uD83D\uDE43":"1f643","\uD83E\uDD11":"1f911","\uD83E\uDD13":"1f913","\uD83E\uDD17":"1f917","\uD83D\uDE44":"1f644","\uD83E\uDD14":"1f914","\uD83E\uDD10":"1f910","\uD83E\uDD12":"1f912","\uD83E\uDD15":"1f915","\uD83E\uDD16":"1f916","\uD83E\uDD81":"1f981","\uD83E\uDD84":"1f984","\uD83E\uDD82":"1f982","\uD83E\uDD80":"1f980","\uD83E\uDD83":"1f983","\uD83E\uDDC0":"1f9c0","\uD83C\uDF2D":"1f32d","\uD83C\uDF2E":"1f32e","\uD83C\uDF2F":"1f32f","\uD83C\uDF7F":"1f37f","\uD83C\uDF7E":"1f37e","\uD83C\uDFF9":"1f3f9","\uD83C\uDFFA":"1f3fa","\uD83D\uDED0":"1f6d0","\uD83D\uDD4B":"1f54b","\uD83D\uDD4C":"1f54c","\uD83D\uDD4D":"1f54d","\uD83D\uDD4E":"1f54e","\uD83D\uDCFF":"1f4ff","\uD83C\uDFCF":"1f3cf","\uD83C\uDFD0":"1f3d0","\uD83C\uDFD1":"1f3d1","\uD83C\uDFD2":"1f3d2","\uD83C\uDFD3":"1f3d3","\uD83C\uDFF8":"1f3f8","\u23E9":"23e9","\u23EA":"23ea","\u23EB":"23eb","\u23EC":"23ec","\u23F0":"23f0","\u23F3":"23f3","\u26CE":"26ce","\u270A":"270a","\u270B":"270b","\u274C":"274c","\u274E":"274e","\u27B0":"27b0","\u27BF":"27bf","\u271D":"271d","\u270D":"270d","\u23ED":"23ed","\u23EE":"23ee","\u23EF":"23ef","\u23F1":"23f1","\u23F2":"23f2","\u23F8":"23f8","\u23F9":"23f9","\u23FA":"23fa","\u262A":"262a","\u262E":"262e","\u262F":"262f","\u269B":"269b","\u269C":"269c","\u26B0":"26b0","\u26B1":"26b1","\u26C8":"26c8","\u26CF":"26cf","\u26D1":"26d1","\u26D3":"26d3","\u26E9":"26e9","\u26F0":"26f0","\u26F1":"26f1","\u26F4":"26f4","\u26F7":"26f7","\u26F8":"26f8","\u26F9":"26f9"};
- ns.imagePathPNG = '//cdn.jsdelivr.net/emojione/assets/png/';
- ns.imagePathSVG = '//cdn.jsdelivr.net/emojione/assets/svg/';
+ ns.unicodeRegexp = '(\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\u2764\\uFE0F\\u200D\\uD83D\\uDC8B\\u200D\\uD83D\\uDC69|\\uD83D\\uDC68\\u200D\\u2764\\uFE0F\\u200D\\uD83D\\uDC8B\\u200D\\uD83D\\uDC68|\\uD83D\\uDC68\\u200D\\uD83D\\uDC68\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC67|\\uD83D\\uDC68\\u200D\\uD83D\\uDC68\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC67|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC66|\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC68\\u200D\\uD83D\\uDC68\\u200D\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC66|\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D\\uD83D\\uDC67|\\uD83D\\uDC69\\u200D\\u2764\\uFE0F\\u200D\\uD83D\\uDC69|\\uD83D\\uDC68\\uD83D\\uDC69\\uD83D\\uDC67\\uD83D\\uDC66|\\uD83D\\uDC68\\uD83D\\uDC69\\uD83D\\uDC66\\uD83D\\uDC66|\\uD83D\\uDC69\\uD83D\\uDC69\\uD83D\\uDC66\\uD83D\\uDC66|\\uD83D\\uDC68\\uD83D\\uDC68\\uD83D\\uDC67\\uD83D\\uDC67|\\uD83D\\uDC69\\uD83D\\uDC69\\uD83D\\uDC67\\uD83D\\uDC66|\\uD83D\\uDC68\\uD83D\\uDC68\\uD83D\\uDC67\\uD83D\\uDC66|\\uD83D\\uDC69\\uD83D\\uDC69\\uD83D\\uDC67\\uD83D\\uDC67|\\uD83D\\uDC68\\uD83D\\uDC69\\uD83D\\uDC67\\uD83D\\uDC67|\\uD83D\\uDC68\\uD83D\\uDC68\\uD83D\\uDC66\\uD83D\\uDC66|\\uD83D\\uDC68\\u200D\\u2764\\uFE0F\\u200D\\uD83D\\uDC68|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67|\\uD83D\\uDC68\\u200D\\uD83D\\uDC68\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66|\\uD83D\\uDC68\\u200D\\uD83D\\uDC68\\u200D\\uD83D\\uDC67|\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC67|\\uD83D\\uDC69\\u2764\\uD83D\\uDC8B\\uD83D\\uDC69|\\uD83D\\uDC68\\u2764\\uD83D\\uDC8B\\uD83D\\uDC68|\\uD83D\\uDC68\\uD83D\\uDC68\\uD83D\\uDC67|\\uD83D\\uDC68\\uD83D\\uDC68\\uD83D\\uDC66|\\uD83D\\uDC69\\uD83D\\uDC69\\uD83D\\uDC66|\\uD83D\\uDC69\\uD83D\\uDC69\\uD83D\\uDC67|\\uD83C\\uDFF3\\uFE0F\\u200D\\uD83C\\uDF08|\\uD83D\\uDC68\\uD83D\\uDC69\\uD83D\\uDC67|\\uD83D\\uDC68\\u2764\\uD83D\\uDC68|\\uD83D\\uDC41\\u200D\\uD83D\\uDDE8|\\uD83D\\uDC69\\u2764\\uD83D\\uDC69|\\uD83D\\uDC41\\uD83D\\uDDE8|\\uD83C\\uDDE6\\uD83C\\uDDE8|\\uD83C\\uDDE6\\uD83C\\uDDE9|\\uD83C\\uDDE6\\uD83C\\uDDEA|\\uD83C\\uDDE6\\uD83C\\uDDEB|\\uD83C\\uDDE6\\uD83C\\uDDEC|\\uD83C\\uDDE6\\uD83C\\uDDEE|\\uD83C\\uDDE6\\uD83C\\uDDF1|\\uD83C\\uDDE6\\uD83C\\uDDF2|\\uD83C\\uDDE6\\uD83C\\uDDF4|\\uD83C\\uDDE6\\uD83C\\uDDF6|\\uD83C\\uDDE6\\uD83C\\uDDF7|\\uD83C\\uDDE6\\uD83C\\uDDF8|\\uD83E\\uDD3E\\uD83C\\uDFFF|\\uD83E\\uDD3E\\uD83C\\uDFFE|\\uD83E\\uDD3E\\uD83C\\uDFFD|\\uD83E\\uDD3E\\uD83C\\uDFFC|\\uD83E\\uDD3E\\uD83C\\uDFFB|\\uD83E\\uDD3D\\uD83C\\uDFFF|\\uD83E\\uDD3D\\uD83C\\uDFFE|\\uD83E\\uDD3D\\uD83C\\uDFFD|\\uD83E\\uDD3D\\uD83C\\uDFFC|\\uD83E\\uDD3D\\uD83C\\uDFFB|\\uD83E\\uDD3C\\uD83C\\uDFFF|\\uD83E\\uDD3C\\uD83C\\uDFFE|\\uD83E\\uDD3C\\uD83C\\uDFFD|\\uD83E\\uDD3C\\uD83C\\uDFFC|\\uD83E\\uDD3C\\uD83C\\uDFFB|\\uD83E\\uDD39\\uD83C\\uDFFF|\\uD83E\\uDD39\\uD83C\\uDFFE|\\uD83E\\uDD39\\uD83C\\uDFFD|\\uD83E\\uDD39\\uD83C\\uDFFC|\\uD83E\\uDD39\\uD83C\\uDFFB|\\uD83E\\uDD38\\uD83C\\uDFFF|\\uD83E\\uDD38\\uD83C\\uDFFE|\\uD83E\\uDD38\\uD83C\\uDFFD|\\uD83E\\uDD38\\uD83C\\uDFFC|\\uD83E\\uDD38\\uD83C\\uDFFB|\\uD83E\\uDD37\\uD83C\\uDFFF|\\uD83E\\uDD37\\uD83C\\uDFFE|\\uD83E\\uDD37\\uD83C\\uDFFD|\\uD83E\\uDD37\\uD83C\\uDFFC|\\uD83E\\uDD37\\uD83C\\uDFFB|\\uD83E\\uDD36\\uD83C\\uDFFF|\\uD83E\\uDD36\\uD83C\\uDFFE|\\uD83E\\uDD36\\uD83C\\uDFFD|\\uD83E\\uDD36\\uD83C\\uDFFC|\\uD83E\\uDD36\\uD83C\\uDFFB|\\uD83E\\uDD35\\uD83C\\uDFFF|\\uD83E\\uDD35\\uD83C\\uDFFE|\\uD83E\\uDD35\\uD83C\\uDFFD|\\uD83E\\uDD35\\uD83C\\uDFFC|\\uD83E\\uDD35\\uD83C\\uDFFB|\\uD83E\\uDD34\\uD83C\\uDFFF|\\uD83E\\uDD34\\uD83C\\uDFFE|\\uD83E\\uDD34\\uD83C\\uDFFD|\\uD83E\\uDD34\\uD83C\\uDFFC|\\uD83E\\uDD34\\uD83C\\uDFFB|\\uD83E\\uDD33\\uD83C\\uDFFF|\\uD83E\\uDD33\\uD83C\\uDFFE|\\uD83E\\uDD33\\uD83C\\uDFFD|\\uD83E\\uDD33\\uD83C\\uDFFC|\\uD83E\\uDD33\\uD83C\\uDFFB|\\uD83E\\uDD30\\uD83C\\uDFFF|\\uD83E\\uDD30\\uD83C\\uDFFE|\\uD83E\\uDD30\\uD83C\\uDFFD|\\uD83E\\uDD30\\uD83C\\uDFFC|\\uD83E\\uDD30\\uD83C\\uDFFB|\\uD83E\\uDD26\\uD83C\\uDFFF|\\uD83E\\uDD26\\uD83C\\uDFFE|\\uD83E\\uDD26\\uD83C\\uDFFD|\\uD83E\\uDD26\\uD83C\\uDFFC|\\uD83E\\uDD26\\uD83C\\uDFFB|\\uD83E\\uDD1E\\uD83C\\uDFFF|\\uD83E\\uDD1E\\uD83C\\uDFFE|\\uD83E\\uDD1E\\uD83C\\uDFFD|\\uD83E\\uDD1E\\uD83C\\uDFFC|\\uD83E\\uDD1E\\uD83C\\uDFFB|\\uD83E\\uDD1D\\uD83C\\uDFFF|\\uD83E\\uDD1D\\uD83C\\uDFFE|\\uD83E\\uDD1D\\uD83C\\uDFFD|\\uD83E\\uDD1D\\uD83C\\uDFFC|\\uD83E\\uDD1D\\uD83C\\uDFFB|\\uD83E\\uDD1C\\uD83C\\uDFFF|\\uD83E\\uDD1C\\uD83C\\uDFFE|\\uD83E\\uDD1C\\uD83C\\uDFFD|\\uD83E\\uDD1C\\uD83C\\uDFFC|\\uD83E\\uDD1C\\uD83C\\uDFFB|\\uD83E\\uDD1B\\uD83C\\uDFFF|\\uD83E\\uDD1B\\uD83C\\uDFFE|\\uD83E\\uDD1B\\uD83C\\uDFFD|\\uD83E\\uDD1B\\uD83C\\uDFFC|\\uD83E\\uDD1B\\uD83C\\uDFFB|\\uD83E\\uDD1A\\uD83C\\uDFFF|\\uD83E\\uDD1A\\uD83C\\uDFFE|\\uD83E\\uDD1A\\uD83C\\uDFFD|\\uD83E\\uDD1A\\uD83C\\uDFFC|\\uD83E\\uDD1A\\uD83C\\uDFFB|\\uD83E\\uDD19\\uD83C\\uDFFF|\\uD83E\\uDD19\\uD83C\\uDFFE|\\uD83E\\uDD19\\uD83C\\uDFFD|\\uD83E\\uDD19\\uD83C\\uDFFC|\\uD83E\\uDD19\\uD83C\\uDFFB|\\uD83E\\uDD18\\uD83C\\uDFFF|\\uD83E\\uDD18\\uD83C\\uDFFE|\\uD83E\\uDD18\\uD83C\\uDFFD|\\uD83E\\uDD18\\uD83C\\uDFFC|\\uD83E\\uDD18\\uD83C\\uDFFB|\\uD83D\\uDEC0\\uD83C\\uDFFF|\\uD83D\\uDEC0\\uD83C\\uDFFE|\\uD83D\\uDEC0\\uD83C\\uDFFD|\\uD83D\\uDEC0\\uD83C\\uDFFC|\\uD83D\\uDEC0\\uD83C\\uDFFB|\\uD83D\\uDEB6\\uD83C\\uDFFF|\\uD83D\\uDEB6\\uD83C\\uDFFE|\\uD83D\\uDEB6\\uD83C\\uDFFD|\\uD83D\\uDEB6\\uD83C\\uDFFC|\\uD83D\\uDEB6\\uD83C\\uDFFB|\\uD83D\\uDEB5\\uD83C\\uDFFF|\\uD83D\\uDEB5\\uD83C\\uDFFE|\\uD83D\\uDEB5\\uD83C\\uDFFD|\\uD83D\\uDEB5\\uD83C\\uDFFC|\\uD83D\\uDEB5\\uD83C\\uDFFB|\\uD83D\\uDEB4\\uD83C\\uDFFF|\\uD83D\\uDEB4\\uD83C\\uDFFE|\\uD83D\\uDEB4\\uD83C\\uDFFD|\\uD83D\\uDEB4\\uD83C\\uDFFC|\\uD83D\\uDEB4\\uD83C\\uDFFB|\\uD83D\\uDEA3\\uD83C\\uDFFF|\\uD83D\\uDEA3\\uD83C\\uDFFE|\\uD83D\\uDEA3\\uD83C\\uDFFD|\\uD83D\\uDEA3\\uD83C\\uDFFC|\\uD83D\\uDEA3\\uD83C\\uDFFB|\\uD83D\\uDE4F\\uD83C\\uDFFF|\\uD83D\\uDE4F\\uD83C\\uDFFE|\\uD83D\\uDE4F\\uD83C\\uDFFD|\\uD83D\\uDE4F\\uD83C\\uDFFC|\\uD83D\\uDE4F\\uD83C\\uDFFB|\\uD83D\\uDE4E\\uD83C\\uDFFF|\\uD83D\\uDE4E\\uD83C\\uDFFE|\\uD83D\\uDE4E\\uD83C\\uDFFD|\\uD83D\\uDE4E\\uD83C\\uDFFC|\\uD83D\\uDE4E\\uD83C\\uDFFB|\\uD83D\\uDE4D\\uD83C\\uDFFF|\\uD83D\\uDE4D\\uD83C\\uDFFE|\\uD83D\\uDE4D\\uD83C\\uDFFD|\\uD83D\\uDE4D\\uD83C\\uDFFC|\\uD83D\\uDE4D\\uD83C\\uDFFB|\\uD83D\\uDE4C\\uD83C\\uDFFF|\\uD83D\\uDE4C\\uD83C\\uDFFE|\\uD83D\\uDE4C\\uD83C\\uDFFD|\\uD83D\\uDE4C\\uD83C\\uDFFC|\\uD83D\\uDE4C\\uD83C\\uDFFB|\\uD83D\\uDE4B\\uD83C\\uDFFF|\\uD83D\\uDE4B\\uD83C\\uDFFE|\\uD83D\\uDE4B\\uD83C\\uDFFD|\\uD83D\\uDE4B\\uD83C\\uDFFC|\\uD83D\\uDE4B\\uD83C\\uDFFB|\\uD83D\\uDE47\\uD83C\\uDFFF|\\uD83D\\uDE47\\uD83C\\uDFFE|\\uD83D\\uDE47\\uD83C\\uDFFD|\\uD83D\\uDE47\\uD83C\\uDFFC|\\uD83D\\uDE47\\uD83C\\uDFFB|\\uD83D\\uDE46\\uD83C\\uDFFF|\\uD83D\\uDE46\\uD83C\\uDFFE|\\uD83D\\uDE46\\uD83C\\uDFFD|\\uD83D\\uDE46\\uD83C\\uDFFC|\\uD83D\\uDE46\\uD83C\\uDFFB|\\uD83D\\uDE45\\uD83C\\uDFFF|\\uD83D\\uDE45\\uD83C\\uDFFE|\\uD83D\\uDE45\\uD83C\\uDFFD|\\uD83D\\uDE45\\uD83C\\uDFFC|\\uD83D\\uDE45\\uD83C\\uDFFB|\\uD83D\\uDD96\\uD83C\\uDFFF|\\uD83D\\uDD96\\uD83C\\uDFFE|\\uD83D\\uDD96\\uD83C\\uDFFD|\\uD83D\\uDD96\\uD83C\\uDFFC|\\uD83D\\uDD96\\uD83C\\uDFFB|\\uD83D\\uDD95\\uD83C\\uDFFF|\\uD83D\\uDD95\\uD83C\\uDFFE|\\uD83D\\uDD95\\uD83C\\uDFFD|\\uD83D\\uDD95\\uD83C\\uDFFC|\\uD83D\\uDD95\\uD83C\\uDFFB|\\uD83D\\uDD90\\uD83C\\uDFFF|\\uD83D\\uDD90\\uD83C\\uDFFE|\\uD83D\\uDD90\\uD83C\\uDFFD|\\uD83D\\uDD90\\uD83C\\uDFFC|\\uD83D\\uDD90\\uD83C\\uDFFB|\\uD83D\\uDD7A\\uD83C\\uDFFF|\\uD83D\\uDD7A\\uD83C\\uDFFE|\\uD83D\\uDD7A\\uD83C\\uDFFD|\\uD83D\\uDD7A\\uD83C\\uDFFC|\\uD83D\\uDD7A\\uD83C\\uDFFB|\\uD83D\\uDD75\\uD83C\\uDFFF|\\uD83D\\uDD75\\uD83C\\uDFFE|\\uD83D\\uDD75\\uD83C\\uDFFD|\\uD83D\\uDD75\\uD83C\\uDFFC|\\uD83D\\uDD75\\uD83C\\uDFFB|\\uD83D\\uDCAA\\uD83C\\uDFFF|\\uD83D\\uDCAA\\uD83C\\uDFFE|\\uD83D\\uDCAA\\uD83C\\uDFFD|\\uD83D\\uDCAA\\uD83C\\uDFFC|\\uD83D\\uDCAA\\uD83C\\uDFFB|\\uD83D\\uDC87\\uD83C\\uDFFF|\\uD83D\\uDC87\\uD83C\\uDFFE|\\uD83D\\uDC87\\uD83C\\uDFFD|\\uD83D\\uDC87\\uD83C\\uDFFC|\\uD83D\\uDC87\\uD83C\\uDFFB|\\uD83D\\uDC86\\uD83C\\uDFFF|\\uD83D\\uDC86\\uD83C\\uDFFE|\\uD83D\\uDC86\\uD83C\\uDFFD|\\uD83D\\uDC86\\uD83C\\uDFFC|\\uD83D\\uDC86\\uD83C\\uDFFB|\\uD83D\\uDC85\\uD83C\\uDFFF|\\uD83D\\uDC85\\uD83C\\uDFFE|\\uD83D\\uDC85\\uD83C\\uDFFD|\\uD83D\\uDC85\\uD83C\\uDFFC|\\uD83D\\uDC85\\uD83C\\uDFFB|\\uD83D\\uDC83\\uD83C\\uDFFF|\\uD83D\\uDC83\\uD83C\\uDFFE|\\uD83D\\uDC83\\uD83C\\uDFFD|\\uD83D\\uDC83\\uD83C\\uDFFC|\\uD83D\\uDC83\\uD83C\\uDFFB|\\uD83D\\uDC82\\uD83C\\uDFFF|\\uD83D\\uDC82\\uD83C\\uDFFE|\\uD83D\\uDC82\\uD83C\\uDFFD|\\uD83D\\uDC82\\uD83C\\uDFFC|\\uD83D\\uDC82\\uD83C\\uDFFB|\\uD83D\\uDC81\\uD83C\\uDFFF|\\uD83D\\uDC81\\uD83C\\uDFFE|\\uD83D\\uDC81\\uD83C\\uDFFD|\\uD83D\\uDC81\\uD83C\\uDFFC|\\uD83D\\uDC81\\uD83C\\uDFFB|\\uD83D\\uDC7C\\uD83C\\uDFFF|\\uD83D\\uDC7C\\uD83C\\uDFFE|\\uD83D\\uDC7C\\uD83C\\uDFFD|\\uD83D\\uDC7C\\uD83C\\uDFFC|\\uD83D\\uDC7C\\uD83C\\uDFFB|\\uD83D\\uDC78\\uD83C\\uDFFF|\\uD83D\\uDC78\\uD83C\\uDFFE|\\uD83D\\uDC78\\uD83C\\uDFFD|\\uD83D\\uDC78\\uD83C\\uDFFC|\\uD83D\\uDC78\\uD83C\\uDFFB|\\uD83D\\uDC77\\uD83C\\uDFFF|\\uD83D\\uDC77\\uD83C\\uDFFE|\\uD83D\\uDC77\\uD83C\\uDFFD|\\uD83D\\uDC77\\uD83C\\uDFFC|\\uD83D\\uDC77\\uD83C\\uDFFB|\\uD83D\\uDC76\\uD83C\\uDFFF|\\uD83D\\uDC76\\uD83C\\uDFFE|\\uD83D\\uDC76\\uD83C\\uDFFD|\\uD83D\\uDC76\\uD83C\\uDFFC|\\uD83D\\uDC76\\uD83C\\uDFFB|\\uD83D\\uDC75\\uD83C\\uDFFF|\\uD83D\\uDC75\\uD83C\\uDFFE|\\uD83D\\uDC75\\uD83C\\uDFFD|\\uD83D\\uDC75\\uD83C\\uDFFC|\\uD83D\\uDC75\\uD83C\\uDFFB|\\uD83D\\uDC74\\uD83C\\uDFFF|\\uD83D\\uDC74\\uD83C\\uDFFE|\\uD83D\\uDC74\\uD83C\\uDFFD|\\uD83D\\uDC74\\uD83C\\uDFFC|\\uD83D\\uDC74\\uD83C\\uDFFB|\\uD83D\\uDC73\\uD83C\\uDFFF|\\uD83D\\uDC73\\uD83C\\uDFFE|\\uD83D\\uDC73\\uD83C\\uDFFD|\\uD83D\\uDC73\\uD83C\\uDFFC|\\uD83D\\uDC73\\uD83C\\uDFFB|\\uD83D\\uDC72\\uD83C\\uDFFF|\\uD83D\\uDC72\\uD83C\\uDFFE|\\uD83D\\uDC72\\uD83C\\uDFFD|\\uD83D\\uDC72\\uD83C\\uDFFC|\\uD83D\\uDC72\\uD83C\\uDFFB|\\uD83D\\uDC71\\uD83C\\uDFFF|\\uD83D\\uDC71\\uD83C\\uDFFE|\\uD83D\\uDC71\\uD83C\\uDFFD|\\uD83D\\uDC71\\uD83C\\uDFFC|\\uD83D\\uDC71\\uD83C\\uDFFB|\\uD83D\\uDC70\\uD83C\\uDFFF|\\uD83D\\uDC70\\uD83C\\uDFFE|\\uD83D\\uDC70\\uD83C\\uDFFD|\\uD83D\\uDC70\\uD83C\\uDFFC|\\uD83D\\uDC70\\uD83C\\uDFFB|\\uD83D\\uDC6E\\uD83C\\uDFFF|\\uD83D\\uDC6E\\uD83C\\uDFFE|\\uD83D\\uDC6E\\uD83C\\uDFFD|\\uD83D\\uDC6E\\uD83C\\uDFFC|\\uD83D\\uDC6E\\uD83C\\uDFFB|\\uD83D\\uDC69\\uD83C\\uDFFF|\\uD83D\\uDC69\\uD83C\\uDFFE|\\uD83D\\uDC69\\uD83C\\uDFFD|\\uD83D\\uDC69\\uD83C\\uDFFC|\\uD83D\\uDC69\\uD83C\\uDFFB|\\uD83D\\uDC68\\uD83C\\uDFFF|\\uD83D\\uDC68\\uD83C\\uDFFE|\\uD83D\\uDC68\\uD83C\\uDFFD|\\uD83D\\uDC68\\uD83C\\uDFFC|\\uD83D\\uDC68\\uD83C\\uDFFB|\\uD83D\\uDC67\\uD83C\\uDFFF|\\uD83D\\uDC67\\uD83C\\uDFFE|\\uD83D\\uDC67\\uD83C\\uDFFD|\\uD83D\\uDC67\\uD83C\\uDFFC|\\uD83D\\uDC67\\uD83C\\uDFFB|\\uD83D\\uDC66\\uD83C\\uDFFF|\\uD83D\\uDC66\\uD83C\\uDFFE|\\uD83D\\uDC66\\uD83C\\uDFFD|\\uD83D\\uDC66\\uD83C\\uDFFC|\\uD83D\\uDC66\\uD83C\\uDFFB|\\uD83D\\uDC50\\uD83C\\uDFFF|\\uD83D\\uDC50\\uD83C\\uDFFE|\\uD83D\\uDC50\\uD83C\\uDFFD|\\uD83D\\uDC50\\uD83C\\uDFFC|\\uD83D\\uDC50\\uD83C\\uDFFB|\\uD83D\\uDC4F\\uD83C\\uDFFF|\\uD83D\\uDC4F\\uD83C\\uDFFE|\\uD83D\\uDC4F\\uD83C\\uDFFD|\\uD83D\\uDC4F\\uD83C\\uDFFC|\\uD83D\\uDC4F\\uD83C\\uDFFB|\\uD83D\\uDC4E\\uD83C\\uDFFF|\\uD83D\\uDC4E\\uD83C\\uDFFE|\\uD83D\\uDC4E\\uD83C\\uDFFD|\\uD83D\\uDC4E\\uD83C\\uDFFC|\\uD83D\\uDC4E\\uD83C\\uDFFB|\\uD83D\\uDC4D\\uD83C\\uDFFF|\\uD83D\\uDC4D\\uD83C\\uDFFE|\\uD83D\\uDC4D\\uD83C\\uDFFD|\\uD83D\\uDC4D\\uD83C\\uDFFC|\\uD83D\\uDC4D\\uD83C\\uDFFB|\\uD83D\\uDC4C\\uD83C\\uDFFF|\\uD83D\\uDC4C\\uD83C\\uDFFE|\\uD83D\\uDC4C\\uD83C\\uDFFD|\\uD83D\\uDC4C\\uD83C\\uDFFC|\\uD83D\\uDC4C\\uD83C\\uDFFB|\\uD83D\\uDC4B\\uD83C\\uDFFF|\\uD83D\\uDC4B\\uD83C\\uDFFE|\\uD83D\\uDC4B\\uD83C\\uDFFD|\\uD83D\\uDC4B\\uD83C\\uDFFC|\\uD83D\\uDC4B\\uD83C\\uDFFB|\\uD83D\\uDC4A\\uD83C\\uDFFF|\\uD83D\\uDC4A\\uD83C\\uDFFE|\\uD83D\\uDC4A\\uD83C\\uDFFD|\\uD83D\\uDC4A\\uD83C\\uDFFC|\\uD83D\\uDC4A\\uD83C\\uDFFB|\\uD83D\\uDC49\\uD83C\\uDFFF|\\uD83D\\uDC49\\uD83C\\uDFFE|\\uD83D\\uDC49\\uD83C\\uDFFD|\\uD83D\\uDC49\\uD83C\\uDFFC|\\uD83D\\uDC49\\uD83C\\uDFFB|\\uD83D\\uDC48\\uD83C\\uDFFF|\\uD83D\\uDC48\\uD83C\\uDFFE|\\uD83D\\uDC48\\uD83C\\uDFFD|\\uD83D\\uDC48\\uD83C\\uDFFC|\\uD83D\\uDC48\\uD83C\\uDFFB|\\uD83D\\uDC47\\uD83C\\uDFFF|\\uD83D\\uDC47\\uD83C\\uDFFE|\\uD83D\\uDC47\\uD83C\\uDFFD|\\uD83D\\uDC47\\uD83C\\uDFFC|\\uD83D\\uDC47\\uD83C\\uDFFB|\\uD83D\\uDC46\\uD83C\\uDFFF|\\uD83D\\uDC46\\uD83C\\uDFFE|\\uD83D\\uDC46\\uD83C\\uDFFD|\\uD83D\\uDC46\\uD83C\\uDFFC|\\uD83D\\uDC46\\uD83C\\uDFFB|\\uD83D\\uDC43\\uD83C\\uDFFF|\\uD83D\\uDC43\\uD83C\\uDFFE|\\uD83D\\uDC43\\uD83C\\uDFFD|\\uD83D\\uDC43\\uD83C\\uDFFC|\\uD83D\\uDC43\\uD83C\\uDFFB|\\uD83D\\uDC42\\uD83C\\uDFFF|\\uD83D\\uDC42\\uD83C\\uDFFE|\\uD83D\\uDC42\\uD83C\\uDFFD|\\uD83D\\uDC42\\uD83C\\uDFFC|\\uD83D\\uDC42\\uD83C\\uDFFB|\\uD83C\\uDFCB\\uD83C\\uDFFF|\\uD83C\\uDFCB\\uD83C\\uDFFE|\\uD83C\\uDFF3\\uD83C\\uDF08|\\uD83C\\uDFCB\\uD83C\\uDFFC|\\uD83C\\uDFCB\\uD83C\\uDFFB|\\uD83C\\uDFCA\\uD83C\\uDFFF|\\uD83C\\uDFCA\\uD83C\\uDFFE|\\uD83C\\uDFCA\\uD83C\\uDFFD|\\uD83C\\uDFCA\\uD83C\\uDFFC|\\uD83C\\uDFCA\\uD83C\\uDFFB|\\uD83C\\uDFC7\\uD83C\\uDFFF|\\uD83C\\uDFC7\\uD83C\\uDFFE|\\uD83C\\uDFC7\\uD83C\\uDFFD|\\uD83C\\uDFC7\\uD83C\\uDFFC|\\uD83C\\uDFC7\\uD83C\\uDFFB|\\uD83C\\uDFC4\\uD83C\\uDFFF|\\uD83C\\uDFCB\\uD83C\\uDFFD|\\uD83C\\uDFC4\\uD83C\\uDFFD|\\uD83C\\uDFC4\\uD83C\\uDFFC|\\uD83C\\uDFC4\\uD83C\\uDFFB|\\uD83C\\uDFC3\\uD83C\\uDFFF|\\uD83C\\uDFC3\\uD83C\\uDFFE|\\uD83C\\uDFC3\\uD83C\\uDFFD|\\uD83C\\uDFC3\\uD83C\\uDFFC|\\uD83C\\uDFC3\\uD83C\\uDFFB|\\uD83C\\uDF85\\uD83C\\uDFFF|\\uD83C\\uDF85\\uD83C\\uDFFE|\\uD83C\\uDF85\\uD83C\\uDFFD|\\uD83C\\uDF85\\uD83C\\uDFFC|\\uD83C\\uDF85\\uD83C\\uDFFB|\\uD83C\\uDDFF\\uD83C\\uDDFC|\\uD83C\\uDDFF\\uD83C\\uDDF2|\\uD83C\\uDDFF\\uD83C\\uDDE6|\\uD83C\\uDDFE\\uD83C\\uDDF9|\\uD83C\\uDDFE\\uD83C\\uDDEA|\\uD83C\\uDDFD\\uD83C\\uDDF0|\\uD83C\\uDDFC\\uD83C\\uDDF8|\\uD83C\\uDDFC\\uD83C\\uDDEB|\\uD83C\\uDDFB\\uD83C\\uDDFA|\\uD83C\\uDDFB\\uD83C\\uDDF3|\\uD83C\\uDDFB\\uD83C\\uDDEE|\\uD83C\\uDDFB\\uD83C\\uDDEC|\\uD83C\\uDDFB\\uD83C\\uDDEA|\\uD83C\\uDDFB\\uD83C\\uDDE8|\\uD83C\\uDDFB\\uD83C\\uDDE6|\\uD83C\\uDDFA\\uD83C\\uDDFF|\\uD83C\\uDDFA\\uD83C\\uDDFE|\\uD83C\\uDDFA\\uD83C\\uDDF8|\\uD83C\\uDDFA\\uD83C\\uDDF2|\\uD83C\\uDDFA\\uD83C\\uDDEC|\\uD83C\\uDDFA\\uD83C\\uDDE6|\\uD83C\\uDDF9\\uD83C\\uDDFF|\\uD83C\\uDDF9\\uD83C\\uDDFC|\\uD83C\\uDDF9\\uD83C\\uDDFB|\\uD83C\\uDDF9\\uD83C\\uDDF9|\\uD83C\\uDDF9\\uD83C\\uDDF7|\\uD83C\\uDDF9\\uD83C\\uDDF4|\\uD83C\\uDDF9\\uD83C\\uDDF3|\\uD83C\\uDDF9\\uD83C\\uDDF2|\\uD83C\\uDDF9\\uD83C\\uDDF1|\\uD83C\\uDDF9\\uD83C\\uDDF0|\\uD83C\\uDDF9\\uD83C\\uDDEF|\\uD83C\\uDDF9\\uD83C\\uDDED|\\uD83C\\uDDF9\\uD83C\\uDDEC|\\uD83C\\uDDF9\\uD83C\\uDDEB|\\uD83C\\uDDF9\\uD83C\\uDDE9|\\uD83C\\uDDF9\\uD83C\\uDDE8|\\uD83C\\uDDF9\\uD83C\\uDDE6|\\uD83C\\uDDF8\\uD83C\\uDDFF|\\uD83C\\uDDF8\\uD83C\\uDDFE|\\uD83C\\uDDF8\\uD83C\\uDDFD|\\uD83C\\uDDF8\\uD83C\\uDDFB|\\uD83C\\uDDF8\\uD83C\\uDDF9|\\uD83C\\uDDF8\\uD83C\\uDDF8|\\uD83C\\uDDF8\\uD83C\\uDDF7|\\uD83C\\uDDF8\\uD83C\\uDDF4|\\uD83C\\uDDF8\\uD83C\\uDDF3|\\uD83C\\uDDF8\\uD83C\\uDDF2|\\uD83C\\uDDF8\\uD83C\\uDDF1|\\uD83C\\uDDF8\\uD83C\\uDDF0|\\uD83C\\uDDF8\\uD83C\\uDDEF|\\uD83C\\uDDF8\\uD83C\\uDDEE|\\uD83C\\uDDF8\\uD83C\\uDDED|\\uD83C\\uDDF8\\uD83C\\uDDEC|\\uD83C\\uDDF8\\uD83C\\uDDEA|\\uD83C\\uDDF8\\uD83C\\uDDE9|\\uD83C\\uDDF8\\uD83C\\uDDE8|\\uD83C\\uDDF8\\uD83C\\uDDE7|\\uD83C\\uDDF8\\uD83C\\uDDE6|\\uD83C\\uDDF7\\uD83C\\uDDFC|\\uD83C\\uDDF7\\uD83C\\uDDFA|\\uD83C\\uDDF7\\uD83C\\uDDF8|\\uD83C\\uDDF7\\uD83C\\uDDF4|\\uD83C\\uDDF7\\uD83C\\uDDEA|\\uD83C\\uDDF6\\uD83C\\uDDE6|\\uD83C\\uDDF5\\uD83C\\uDDFE|\\uD83C\\uDDF5\\uD83C\\uDDFC|\\uD83C\\uDDF5\\uD83C\\uDDF9|\\uD83C\\uDDF5\\uD83C\\uDDF8|\\uD83C\\uDDF5\\uD83C\\uDDF7|\\uD83C\\uDDF5\\uD83C\\uDDF3|\\uD83C\\uDDF5\\uD83C\\uDDF2|\\uD83C\\uDDF5\\uD83C\\uDDF1|\\uD83C\\uDDF5\\uD83C\\uDDF0|\\uD83C\\uDDF5\\uD83C\\uDDED|\\uD83C\\uDDF5\\uD83C\\uDDEC|\\uD83C\\uDDF5\\uD83C\\uDDEB|\\uD83C\\uDDF5\\uD83C\\uDDEA|\\uD83C\\uDDF5\\uD83C\\uDDE6|\\uD83C\\uDDF4\\uD83C\\uDDF2|\\uD83C\\uDDF3\\uD83C\\uDDFF|\\uD83C\\uDDF3\\uD83C\\uDDFA|\\uD83C\\uDDF3\\uD83C\\uDDF7|\\uD83C\\uDDF3\\uD83C\\uDDF5|\\uD83C\\uDDF3\\uD83C\\uDDF4|\\uD83C\\uDDF3\\uD83C\\uDDF1|\\uD83C\\uDDF3\\uD83C\\uDDEE|\\uD83C\\uDDF3\\uD83C\\uDDEC|\\uD83C\\uDDF3\\uD83C\\uDDEB|\\uD83C\\uDDF3\\uD83C\\uDDEA|\\uD83C\\uDDF3\\uD83C\\uDDE8|\\uD83C\\uDDF3\\uD83C\\uDDE6|\\uD83C\\uDDF2\\uD83C\\uDDFF|\\uD83C\\uDDF2\\uD83C\\uDDFE|\\uD83C\\uDDF2\\uD83C\\uDDFD|\\uD83C\\uDDF2\\uD83C\\uDDFC|\\uD83C\\uDDF2\\uD83C\\uDDFB|\\uD83C\\uDDF2\\uD83C\\uDDFA|\\uD83C\\uDDF2\\uD83C\\uDDF9|\\uD83C\\uDDF2\\uD83C\\uDDF8|\\uD83C\\uDDF2\\uD83C\\uDDF7|\\uD83C\\uDDF2\\uD83C\\uDDF6|\\uD83C\\uDDF2\\uD83C\\uDDF5|\\uD83C\\uDDF2\\uD83C\\uDDF4|\\uD83C\\uDDF2\\uD83C\\uDDF3|\\uD83C\\uDDF2\\uD83C\\uDDF2|\\uD83C\\uDDF2\\uD83C\\uDDF1|\\uD83C\\uDDF2\\uD83C\\uDDF0|\\uD83C\\uDDF2\\uD83C\\uDDED|\\uD83C\\uDDF2\\uD83C\\uDDEC|\\uD83C\\uDDF2\\uD83C\\uDDEB|\\uD83C\\uDDF2\\uD83C\\uDDEA|\\uD83C\\uDDF2\\uD83C\\uDDE9|\\uD83C\\uDDF2\\uD83C\\uDDE8|\\uD83C\\uDDF2\\uD83C\\uDDE6|\\uD83C\\uDDF1\\uD83C\\uDDFE|\\uD83C\\uDDF1\\uD83C\\uDDFB|\\uD83C\\uDDF1\\uD83C\\uDDFA|\\uD83C\\uDDF1\\uD83C\\uDDF9|\\uD83C\\uDDF1\\uD83C\\uDDF8|\\uD83C\\uDDF1\\uD83C\\uDDF7|\\uD83C\\uDDF1\\uD83C\\uDDF0|\\uD83C\\uDDF1\\uD83C\\uDDEE|\\uD83C\\uDDF1\\uD83C\\uDDE8|\\uD83C\\uDDF1\\uD83C\\uDDE7|\\uD83C\\uDDF1\\uD83C\\uDDE6|\\uD83C\\uDDF0\\uD83C\\uDDFF|\\uD83C\\uDDF0\\uD83C\\uDDFE|\\uD83C\\uDDF0\\uD83C\\uDDFC|\\uD83C\\uDDF0\\uD83C\\uDDF7|\\uD83C\\uDDF0\\uD83C\\uDDF5|\\uD83C\\uDDF0\\uD83C\\uDDF3|\\uD83C\\uDDF0\\uD83C\\uDDF2|\\uD83C\\uDDF0\\uD83C\\uDDEE|\\uD83C\\uDDF0\\uD83C\\uDDED|\\uD83C\\uDDF0\\uD83C\\uDDEC|\\uD83C\\uDDF0\\uD83C\\uDDEA|\\uD83C\\uDDEF\\uD83C\\uDDF5|\\uD83C\\uDDEF\\uD83C\\uDDF4|\\uD83C\\uDDEF\\uD83C\\uDDF2|\\uD83C\\uDDEF\\uD83C\\uDDEA|\\uD83C\\uDDEE\\uD83C\\uDDF9|\\uD83C\\uDDEE\\uD83C\\uDDF8|\\uD83C\\uDDEE\\uD83C\\uDDF7|\\uD83C\\uDDEE\\uD83C\\uDDF6|\\uD83C\\uDDEE\\uD83C\\uDDF4|\\uD83C\\uDDEE\\uD83C\\uDDF3|\\uD83C\\uDDEE\\uD83C\\uDDF2|\\uD83C\\uDDEE\\uD83C\\uDDF1|\\uD83C\\uDDEE\\uD83C\\uDDEA|\\uD83C\\uDDEE\\uD83C\\uDDE9|\\uD83C\\uDDEE\\uD83C\\uDDE8|\\uD83C\\uDDED\\uD83C\\uDDFA|\\uD83C\\uDDED\\uD83C\\uDDF9|\\uD83C\\uDDED\\uD83C\\uDDF7|\\uD83C\\uDDED\\uD83C\\uDDF3|\\uD83C\\uDDED\\uD83C\\uDDF2|\\uD83C\\uDDED\\uD83C\\uDDF0|\\uD83C\\uDDEC\\uD83C\\uDDFE|\\uD83C\\uDDEC\\uD83C\\uDDFC|\\uD83C\\uDDEC\\uD83C\\uDDFA|\\uD83C\\uDDEC\\uD83C\\uDDF9|\\uD83C\\uDDEC\\uD83C\\uDDF8|\\uD83C\\uDDEC\\uD83C\\uDDF7|\\uD83C\\uDDEC\\uD83C\\uDDF6|\\uD83C\\uDDEC\\uD83C\\uDDF5|\\uD83C\\uDDEC\\uD83C\\uDDF3|\\uD83C\\uDDEC\\uD83C\\uDDF2|\\uD83C\\uDDEC\\uD83C\\uDDF1|\\uD83C\\uDDEC\\uD83C\\uDDEE|\\uD83C\\uDDEC\\uD83C\\uDDED|\\uD83C\\uDDEC\\uD83C\\uDDEC|\\uD83C\\uDDEC\\uD83C\\uDDEB|\\uD83C\\uDDEC\\uD83C\\uDDEA|\\uD83C\\uDDEC\\uD83C\\uDDE9|\\uD83C\\uDDEC\\uD83C\\uDDE7|\\uD83C\\uDDEC\\uD83C\\uDDE6|\\uD83C\\uDDEB\\uD83C\\uDDF7|\\uD83C\\uDDEB\\uD83C\\uDDF4|\\uD83C\\uDDEB\\uD83C\\uDDF2|\\uD83C\\uDDEB\\uD83C\\uDDF0|\\uD83C\\uDDEB\\uD83C\\uDDEF|\\uD83C\\uDDEB\\uD83C\\uDDEE|\\uD83C\\uDDEA\\uD83C\\uDDFA|\\uD83C\\uDDEA\\uD83C\\uDDF9|\\uD83C\\uDDEA\\uD83C\\uDDF8|\\uD83C\\uDDEA\\uD83C\\uDDF7|\\uD83C\\uDDEA\\uD83C\\uDDED|\\uD83C\\uDDEA\\uD83C\\uDDEC|\\uD83C\\uDDEA\\uD83C\\uDDEA|\\uD83C\\uDDEA\\uD83C\\uDDE8|\\uD83C\\uDDEA\\uD83C\\uDDE6|\\uD83C\\uDDE9\\uD83C\\uDDFF|\\uD83C\\uDDE9\\uD83C\\uDDF4|\\uD83C\\uDDE9\\uD83C\\uDDF2|\\uD83C\\uDDE9\\uD83C\\uDDF0|\\uD83C\\uDDE9\\uD83C\\uDDEF|\\uD83C\\uDDE9\\uD83C\\uDDEC|\\uD83C\\uDDE9\\uD83C\\uDDEA|\\uD83C\\uDDE8\\uD83C\\uDDFF|\\uD83C\\uDDE8\\uD83C\\uDDFE|\\uD83C\\uDDE8\\uD83C\\uDDFD|\\uD83C\\uDDE8\\uD83C\\uDDFC|\\uD83C\\uDDE8\\uD83C\\uDDFB|\\uD83C\\uDDE8\\uD83C\\uDDFA|\\uD83C\\uDDE8\\uD83C\\uDDF7|\\uD83C\\uDDE8\\uD83C\\uDDF5|\\uD83C\\uDDE8\\uD83C\\uDDF4|\\uD83C\\uDDE8\\uD83C\\uDDF3|\\uD83C\\uDDE8\\uD83C\\uDDF2|\\uD83C\\uDDE8\\uD83C\\uDDF1|\\uD83C\\uDDE8\\uD83C\\uDDF0|\\uD83C\\uDDE8\\uD83C\\uDDEE|\\uD83C\\uDDE8\\uD83C\\uDDED|\\uD83C\\uDDE8\\uD83C\\uDDEC|\\uD83C\\uDDE8\\uD83C\\uDDEB|\\uD83C\\uDDE8\\uD83C\\uDDE9|\\uD83C\\uDDE8\\uD83C\\uDDE8|\\uD83C\\uDDE8\\uD83C\\uDDE6|\\uD83C\\uDDE7\\uD83C\\uDDFF|\\uD83C\\uDDE7\\uD83C\\uDDFE|\\uD83C\\uDDE7\\uD83C\\uDDFC|\\uD83C\\uDDE7\\uD83C\\uDDFB|\\uD83C\\uDDE7\\uD83C\\uDDF9|\\uD83C\\uDDE7\\uD83C\\uDDF8|\\uD83C\\uDDE7\\uD83C\\uDDF7|\\uD83C\\uDDE7\\uD83C\\uDDF6|\\uD83C\\uDDE7\\uD83C\\uDDF4|\\uD83C\\uDDE7\\uD83C\\uDDF3|\\uD83C\\uDDE7\\uD83C\\uDDF2|\\uD83C\\uDDE7\\uD83C\\uDDF1|\\uD83C\\uDDE7\\uD83C\\uDDEF|\\uD83C\\uDDE7\\uD83C\\uDDEE|\\uD83C\\uDDE7\\uD83C\\uDDED|\\uD83C\\uDDE7\\uD83C\\uDDEC|\\uD83C\\uDDE7\\uD83C\\uDDEB|\\uD83C\\uDDE7\\uD83C\\uDDEA|\\uD83C\\uDDE7\\uD83C\\uDDE9|\\uD83C\\uDDE7\\uD83C\\uDDE7|\\uD83C\\uDDE7\\uD83C\\uDDE6|\\uD83C\\uDDE6\\uD83C\\uDDFF|\\uD83C\\uDDE6\\uD83C\\uDDFD|\\uD83C\\uDDE6\\uD83C\\uDDFC|\\uD83C\\uDDE6\\uD83C\\uDDFA|\\uD83C\\uDDE6\\uD83C\\uDDF9|\\uD83C\\uDFC4\\uD83C\\uDFFE|\\uD83D\\uDDE3\\uFE0F|\\u26F9\\uD83C\\uDFFF|\\u26F9\\uD83C\\uDFFE|\\u26F9\\uD83C\\uDFFD|\\u26F9\\uD83C\\uDFFC|\\u26F9\\uD83C\\uDFFB|\\u270D\\uD83C\\uDFFF|\\u270D\\uD83C\\uDFFE|\\u270D\\uD83C\\uDFFD|\\u270D\\uD83C\\uDFFC|\\u270D\\uD83C\\uDFFB|\\uD83C\\uDC04\\uFE0F|\\uD83C\\uDD7F\\uFE0F|\\uD83C\\uDE02\\uFE0F|\\uD83C\\uDE1A\\uFE0F|\\uD83C\\uDE2F\\uFE0F|\\uD83C\\uDE37\\uFE0F|\\uD83C\\uDF9E\\uFE0F|\\uD83C\\uDF9F\\uFE0F|\\uD83C\\uDFCB\\uFE0F|\\uD83C\\uDFCC\\uFE0F|\\uD83C\\uDFCD\\uFE0F|\\uD83C\\uDFCE\\uFE0F|\\uD83C\\uDF96\\uFE0F|\\uD83C\\uDF97\\uFE0F|\\uD83C\\uDF36\\uFE0F|\\uD83C\\uDF27\\uFE0F|\\uD83C\\uDF28\\uFE0F|\\uD83C\\uDF29\\uFE0F|\\uD83C\\uDF2A\\uFE0F|\\uD83C\\uDF2B\\uFE0F|\\uD83C\\uDF2C\\uFE0F|\\uD83D\\uDC3F\\uFE0F|\\uD83D\\uDD77\\uFE0F|\\uD83D\\uDD78\\uFE0F|\\uD83C\\uDF21\\uFE0F|\\uD83C\\uDF99\\uFE0F|\\uD83C\\uDF9A\\uFE0F|\\uD83C\\uDF9B\\uFE0F|\\uD83C\\uDFF3\\uFE0F|\\uD83C\\uDFF5\\uFE0F|\\uD83C\\uDFF7\\uFE0F|\\uD83D\\uDCFD\\uFE0F|\\uD83D\\uDD49\\uFE0F|\\uD83D\\uDD4A\\uFE0F|\\uD83D\\uDD6F\\uFE0F|\\uD83D\\uDD70\\uFE0F|\\uD83D\\uDD73\\uFE0F|\\uD83D\\uDD76\\uFE0F|\\uD83D\\uDD79\\uFE0F|\\uD83D\\uDD87\\uFE0F|\\uD83D\\uDD8A\\uFE0F|\\uD83D\\uDD8B\\uFE0F|\\uD83D\\uDD8C\\uFE0F|\\uD83D\\uDD8D\\uFE0F|\\uD83D\\uDDA5\\uFE0F|\\uD83D\\uDDA8\\uFE0F|\\uD83D\\uDDB2\\uFE0F|\\uD83D\\uDDBC\\uFE0F|\\uD83D\\uDDC2\\uFE0F|\\uD83D\\uDDC3\\uFE0F|\\uD83D\\uDDC4\\uFE0F|\\uD83D\\uDDD1\\uFE0F|\\uD83D\\uDDD2\\uFE0F|\\uD83D\\uDDD3\\uFE0F|\\uD83D\\uDDDC\\uFE0F|\\uD83D\\uDDDD\\uFE0F|\\uD83D\\uDDDE\\uFE0F|\\uD83D\\uDDE1\\uFE0F|\\u270B\\uD83C\\uDFFF|\\uD83D\\uDDE8\\uFE0F|\\uD83D\\uDDEF\\uFE0F|\\uD83D\\uDDF3\\uFE0F|\\uD83D\\uDDFA\\uFE0F|\\uD83D\\uDEE0\\uFE0F|\\uD83D\\uDEE1\\uFE0F|\\uD83D\\uDEE2\\uFE0F|\\uD83D\\uDEF0\\uFE0F|\\uD83C\\uDF7D\\uFE0F|\\uD83D\\uDC41\\uFE0F|\\uD83D\\uDD74\\uFE0F|\\uD83D\\uDD75\\uFE0F|\\uD83D\\uDD90\\uFE0F|\\uD83C\\uDFD4\\uFE0F|\\uD83C\\uDFD5\\uFE0F|\\uD83C\\uDFD6\\uFE0F|\\uD83C\\uDFD7\\uFE0F|\\uD83C\\uDFD8\\uFE0F|\\uD83C\\uDFD9\\uFE0F|\\uD83C\\uDFDA\\uFE0F|\\uD83C\\uDFDB\\uFE0F|\\uD83C\\uDFDC\\uFE0F|\\uD83C\\uDFDD\\uFE0F|\\uD83C\\uDFDE\\uFE0F|\\uD83C\\uDFDF\\uFE0F|\\uD83D\\uDECB\\uFE0F|\\uD83D\\uDECD\\uFE0F|\\uD83D\\uDECE\\uFE0F|\\uD83D\\uDECF\\uFE0F|\\uD83D\\uDEE3\\uFE0F|\\uD83D\\uDEE4\\uFE0F|\\uD83D\\uDEE5\\uFE0F|\\uD83D\\uDEE9\\uFE0F|\\uD83D\\uDEF3\\uFE0F|\\uD83C\\uDF24\\uFE0F|\\uD83C\\uDF25\\uFE0F|\\uD83C\\uDF26\\uFE0F|\\uD83D\\uDDB1\\uFE0F|\\u261D\\uD83C\\uDFFB|\\u261D\\uD83C\\uDFFC|\\u261D\\uD83C\\uDFFD|\\u261D\\uD83C\\uDFFE|\\u261D\\uD83C\\uDFFF|\\u270C\\uD83C\\uDFFB|\\u270C\\uD83C\\uDFFC|\\u270C\\uD83C\\uDFFD|\\u270C\\uD83C\\uDFFE|\\u270C\\uD83C\\uDFFF|\\u270A\\uD83C\\uDFFB|\\u270A\\uD83C\\uDFFC|\\u270A\\uD83C\\uDFFD|\\u270A\\uD83C\\uDFFE|\\u270A\\uD83C\\uDFFF|\\u270B\\uD83C\\uDFFB|\\u270B\\uD83C\\uDFFC|\\u270B\\uD83C\\uDFFD|\\u270B\\uD83C\\uDFFE|\\4\\uFE0F\\u20E3|\\9\\uFE0F\\u20E3|\\0\\uFE0F\\u20E3|\\1\\uFE0F\\u20E3|\\2\\uFE0F\\u20E3|\\3\\uFE0F\\u20E3|\\#\\uFE0F\\u20E3|\\5\\uFE0F\\u20E3|\\6\\uFE0F\\u20E3|\\7\\uFE0F\\u20E3|\\8\\uFE0F\\u20E3|\\*\\uFE0F\\u20E3|\\uD83D\\uDDE1|\\uD83D\\uDD77|\\uD83D\\uDDE3|\\uD83D\\uDEE4|\\uD83D\\uDDE8|\\uD83D\\uDD78|\\uD83D\\uDDEF|\\uD83C\\uDE37|\\uD83D\\uDDF3|\\uD83C\\uDF21|\\uD83D\\uDDFA|\\uD83D\\uDDB1|\\uD83D\\uDEE0|\\uD83C\\uDF99|\\uD83D\\uDEE1|\\uD83C\\uDF9E|\\uD83D\\uDEE2|\\uD83C\\uDF9A|\\uD83D\\uDEF0|\\uD83D\\uDEE3|\\uD83C\\uDF7D|\\uD83C\\uDF9B|\\uD83D\\uDC41|\\uD83C\\uDF9F|\\uD83D\\uDD74|\\uD83C\\uDFF3|\\uD83D\\uDD75|\\uD83D\\uDEF3|\\uD83D\\uDD90|\\uD83C\\uDFF5|\\uD83C\\uDFD4|\\uD83C\\uDFCB|\\uD83C\\uDFD5|\\uD83C\\uDFF7|\\uD83C\\uDFD6|\\uD83D\\uDECF|\\uD83C\\uDFD7|\\uD83D\\uDCFD|\\uD83C\\uDFD8|\\uD83C\\uDFCC|\\uD83C\\uDFD9|\\uD83D\\uDD49|\\uD83C\\uDFDA|\\uD83C\\uDF25|\\uD83C\\uDFDB|\\uD83D\\uDD4A|\\uD83C\\uDFDC|\\uD83C\\uDFCD|\\uD83C\\uDFDD|\\uD83D\\uDD6F|\\uD83C\\uDFDE|\\uD83D\\uDECE|\\uD83C\\uDFDF|\\uD83D\\uDD70|\\uD83D\\uDECB|\\uD83C\\uDFCE|\\uD83D\\uDECD|\\uD83D\\uDD73|\\uD83D\\uDECE|\\uD83D\\uDEE9|\\uD83D\\uDECF|\\uD83D\\uDD76|\\uD83D\\uDEE3|\\uD83C\\uDF96|\\uD83D\\uDEE4|\\uD83D\\uDD79|\\uD83D\\uDEE5|\\uD83D\\uDECD|\\uD83D\\uDEE9|\\uD83D\\uDD87|\\uD83D\\uDEF3|\\uD83C\\uDF97|\\uD83C\\uDF24|\\uD83D\\uDD8A|\\uD83C\\uDF25|\\uD83C\\uDC04|\\uD83C\\uDF26|\\uD83D\\uDD8B|\\uD83D\\uDDB1|\\uD83C\\uDF36|\\uD83D\\uDD8C|\\uD83C\\uDF26|\\uD83D\\uDD8D|\\uD83C\\uDF27|\\uD83D\\uDDA5|\\uD83C\\uDD7F|\\uD83D\\uDDA8|\\uD83C\\uDF28|\\uD83D\\uDDB2|\\uD83D\\uDECB|\\uD83D\\uDDBC|\\uD83C\\uDF29|\\uD83D\\uDDC2|\\uD83C\\uDE02|\\uD83D\\uDDC3|\\uD83C\\uDF2A|\\uD83D\\uDDC4|\\uD83D\\uDEE5|\\uD83D\\uDDD1|\\uD83C\\uDF2B|\\uD83D\\uDDD2|\\uD83C\\uDE1A|\\uD83D\\uDDD3|\\uD83C\\uDF2C|\\uD83D\\uDDDC|\\uD83C\\uDF24|\\uD83D\\uDDDD|\\uD83D\\uDC3F|\\uD83D\\uDDDE|\\u00A9\\uFE0F|\\uD83C\\uDFDF|\\u00AE\\uFE0F|\\uD83C\\uDFDE|\\u203C\\uFE0F|\\uD83C\\uDFDD|\\u2049\\uFE0F|\\uD83C\\uDFDC|\\u2122\\uFE0F|\\uD83C\\uDFDB|\\u2139\\uFE0F|\\uD83C\\uDFDA|\\u2194\\uFE0F|\\uD83C\\uDFD9|\\u2195\\uFE0F|\\uD83C\\uDFD8|\\u2196\\uFE0F|\\uD83C\\uDFD7|\\u2197\\uFE0F|\\uD83C\\uDFD6|\\u2198\\uFE0F|\\uD83C\\uDFD5|\\u2199\\uFE0F|\\uD83C\\uDFD4|\\u21A9\\uFE0F|\\uD83D\\uDD90|\\u21AA\\uFE0F|\\uD83D\\uDD75|\\u231A\\uFE0F|\\uD83D\\uDD74|\\u231B\\uFE0F|\\uD83D\\uDC41|\\u24C2\\uFE0F|\\uD83C\\uDF7D|\\u25AA\\uFE0F|\\uD83D\\uDEF0|\\u25AB\\uFE0F|\\uD83D\\uDEE2|\\u25B6\\uFE0F|\\uD83D\\uDEE1|\\u25C0\\uFE0F|\\uD83D\\uDEE0|\\u25FB\\uFE0F|\\uD83D\\uDDFA|\\u25FC\\uFE0F|\\uD83D\\uDDF3|\\u25FD\\uFE0F|\\uD83D\\uDDEF|\\u25FE\\uFE0F|\\uD83D\\uDDE8|\\u2600\\uFE0F|\\uD83D\\uDDE3|\\u2601\\uFE0F|\\uD83D\\uDDE1|\\u260E\\uFE0F|\\uD83D\\uDDDE|\\u2611\\uFE0F|\\uD83D\\uDDDD|\\u2614\\uFE0F|\\uD83D\\uDDDC|\\u2615\\uFE0F|\\uD83D\\uDDD3|\\u261D\\uFE0F|\\uD83D\\uDDD2|\\u263A\\uFE0F|\\uD83D\\uDDD1|\\u2648\\uFE0F|\\uD83D\\uDDC4|\\u2649\\uFE0F|\\uD83D\\uDDC3|\\u264A\\uFE0F|\\uD83D\\uDDC2|\\u264B\\uFE0F|\\uD83D\\uDDBC|\\u264C\\uFE0F|\\uD83D\\uDDB2|\\u264D\\uFE0F|\\uD83D\\uDDA8|\\u264E\\uFE0F|\\uD83D\\uDDA5|\\u264F\\uFE0F|\\uD83D\\uDD8D|\\u2650\\uFE0F|\\uD83D\\uDD8C|\\u2651\\uFE0F|\\uD83D\\uDD8B|\\u2652\\uFE0F|\\uD83D\\uDD8A|\\u2653\\uFE0F|\\uD83D\\uDD87|\\u2660\\uFE0F|\\uD83D\\uDD79|\\u2663\\uFE0F|\\uD83D\\uDD76|\\u2665\\uFE0F|\\uD83D\\uDD73|\\u2666\\uFE0F|\\uD83D\\uDD70|\\u2668\\uFE0F|\\uD83D\\uDD6F|\\u267B\\uFE0F|\\uD83D\\uDD4A|\\u267F\\uFE0F|\\uD83D\\uDD49|\\u2693\\uFE0F|\\uD83D\\uDCFD|\\u26A0\\uFE0F|\\uD83C\\uDFF7|\\u26A1\\uFE0F|\\uD83C\\uDFF5|\\u26AA\\uFE0F|\\uD83C\\uDFF3|\\u26AB\\uFE0F|\\uD83C\\uDF9B|\\u26BD\\uFE0F|\\uD83C\\uDF9A|\\u26BE\\uFE0F|\\uD83C\\uDF99|\\u26C4\\uFE0F|\\uD83C\\uDF21|\\u26C5\\uFE0F|\\uD83D\\uDD78|\\u26D4\\uFE0F|\\uD83D\\uDD77|\\u26EA\\uFE0F|\\uD83D\\uDC3F|\\uD83C\\uDE2F|\\uD83C\\uDF2C|\\u26F3\\uFE0F|\\uD83C\\uDF2B|\\u26F5\\uFE0F|\\uD83C\\uDF2A|\\u26FA\\uFE0F|\\uD83C\\uDF29|\\u26FD\\uFE0F|\\uD83C\\uDF28|\\u2702\\uFE0F|\\uD83C\\uDF27|\\u2708\\uFE0F|\\uD83C\\uDF36|\\u2709\\uFE0F|\\uD83C\\uDF97|\\u270C\\uFE0F|\\uD83C\\uDF96|\\u270F\\uFE0F|\\uD83C\\uDFCE|\\u2712\\uFE0F|\\uD83C\\uDFCD|\\u2714\\uFE0F|\\uD83C\\uDFCC|\\u2716\\uFE0F|\\uD83C\\uDFCB|\\u2733\\uFE0F|\\uD83C\\uDF9F|\\u2734\\uFE0F|\\uD83C\\uDF9E|\\u2744\\uFE0F|\\uD83C\\uDE37|\\u2747\\uFE0F|\\uD83C\\uDE2F|\\u2757\\uFE0F|\\uD83C\\uDE1A|\\u2764\\uFE0F|\\uD83C\\uDE02|\\u27A1\\uFE0F|\\uD83C\\uDD7F|\\u2934\\uFE0F|\\uD83C\\uDC04|\\u2935\\uFE0F|\\uD83C\\uDDE6|\\u2B05\\uFE0F|\\uD83C\\uDDE7|\\u2B06\\uFE0F|\\uD83C\\uDDE8|\\u2B07\\uFE0F|\\uD83C\\uDDE9|\\u2B1B\\uFE0F|\\uD83C\\uDDEA|\\u2B1C\\uFE0F|\\uD83C\\uDDEB|\\u2B50\\uFE0F|\\uD83C\\uDDEC|\\u2B55\\uFE0F|\\uD83C\\uDDED|\\u3030\\uFE0F|\\uD83C\\uDDEE|\\u303D\\uFE0F|\\uD83C\\uDDEF|\\u3297\\uFE0F|\\uD83C\\uDDF0|\\u3299\\uFE0F|\\uD83C\\uDDF1|\\u271D\\uFE0F|\\uD83C\\uDDF2|\\u2328\\uFE0F|\\uD83C\\uDDF3|\\u270D\\uFE0F|\\uD83C\\uDDF4|\\u23CF\\uFE0F|\\uD83C\\uDDF5|\\u23ED\\uFE0F|\\uD83C\\uDDF6|\\u23EE\\uFE0F|\\uD83C\\uDDF7|\\u23EF\\uFE0F|\\uD83C\\uDDF8|\\u23F1\\uFE0F|\\uD83C\\uDDF9|\\u23F2\\uFE0F|\\uD83C\\uDDFA|\\u23F8\\uFE0F|\\uD83C\\uDDFB|\\u23F9\\uFE0F|\\uD83C\\uDDFC|\\u23FA\\uFE0F|\\uD83E\\uDD5E|\\u2602\\uFE0F|\\uD83E\\uDD5D|\\u2603\\uFE0F|\\uD83E\\uDD5C|\\u2604\\uFE0F|\\uD83E\\uDD5B|\\u2618\\uFE0F|\\uD83E\\uDD5A|\\u2620\\uFE0F|\\uD83E\\uDD91|\\u2622\\uFE0F|\\uD83E\\uDD90|\\u2623\\uFE0F|\\uD83E\\uDD41|\\u2626\\uFE0F|\\uD83C\\uDFF8|\\u262A\\uFE0F|\\uD83C\\uDFD3|\\u262E\\uFE0F|\\uD83C\\uDFD2|\\u262F\\uFE0F|\\uD83C\\uDFD1|\\u2638\\uFE0F|\\uD83C\\uDFD0|\\u2639\\uFE0F|\\uD83C\\uDFCF|\\u2692\\uFE0F|\\uD83D\\uDCFF|\\u2694\\uFE0F|\\uD83D\\uDD4E|\\u2696\\uFE0F|\\uD83D\\uDD4D|\\u2697\\uFE0F|\\uD83D\\uDD4C|\\u2699\\uFE0F|\\uD83D\\uDD4B|\\u269B\\uFE0F|\\uD83D\\uDED0|\\u269C\\uFE0F|\\uD83C\\uDFFA|\\u26B0\\uFE0F|\\uD83C\\uDFF9|\\u26B1\\uFE0F|\\uD83C\\uDF7E|\\u26C8\\uFE0F|\\uD83C\\uDF7F|\\u26CF\\uFE0F|\\uD83C\\uDF2F|\\u26D1\\uFE0F|\\uD83C\\uDF2E|\\u26D3\\uFE0F|\\uD83C\\uDF2D|\\u26E9\\uFE0F|\\uD83E\\uDDC0|\\u26F0\\uFE0F|\\uD83E\\uDD83|\\u26F1\\uFE0F|\\uD83E\\uDD80|\\u26F4\\uFE0F|\\uD83E\\uDD82|\\u26F7\\uFE0F|\\uD83E\\uDD84|\\u26F8\\uFE0F|\\uD83E\\uDD81|\\u26F9\\uFE0F|\\uD83E\\uDD16|\\u2721\\uFE0F|\\uD83E\\uDD15|\\u2763\\uFE0F|\\uD83E\\uDD12|\\uD83E\\uDD49|\\uD83E\\uDD48|\\uD83E\\uDD47|\\uD83E\\uDD3A|\\uD83E\\uDD45|\\uD83E\\uDD3E|\\uD83C\\uDDFF|\\uD83E\\uDD3D|\\uD83E\\uDD4B|\\uD83E\\uDD4A|\\uD83E\\uDD3C|\\uD83E\\uDD39|\\uD83E\\uDD38|\\uD83D\\uDEF6|\\uD83D\\uDEF5|\\uD83D\\uDEF4|\\uD83D\\uDED2|\\uD83C\\uDCCF|\\uD83C\\uDD70|\\uD83C\\uDD71|\\uD83C\\uDD7E|\\uD83D\\uDED1|\\uD83C\\uDD8E|\\uD83C\\uDD91|\\uD83C\\uDDFE|\\uD83C\\uDD92|\\uD83C\\uDD93|\\uD83C\\uDD94|\\uD83C\\uDD95|\\uD83C\\uDD96|\\uD83C\\uDD97|\\uD83C\\uDD98|\\uD83E\\uDD44|\\uD83C\\uDD99|\\uD83C\\uDD9A|\\uD83E\\uDD42|\\uD83E\\uDD43|\\uD83C\\uDE01|\\uD83E\\uDD59|\\uD83C\\uDE32|\\uD83C\\uDE33|\\uD83C\\uDE34|\\uD83C\\uDE35|\\uD83C\\uDE36|\\uD83E\\uDD58|\\uD83C\\uDE38|\\uD83C\\uDE39|\\uD83E\\uDD57|\\uD83C\\uDE3A|\\uD83C\\uDE50|\\uD83C\\uDE51|\\uD83C\\uDF00|\\uD83E\\uDD56|\\uD83C\\uDF01|\\uD83C\\uDF02|\\uD83C\\uDF03|\\uD83C\\uDF04|\\uD83C\\uDF05|\\uD83C\\uDF06|\\uD83E\\uDD55|\\uD83C\\uDF07|\\uD83C\\uDF08|\\uD83E\\uDD54|\\uD83C\\uDF09|\\uD83C\\uDF0A|\\uD83C\\uDF0B|\\uD83C\\uDF0C|\\uD83C\\uDF0F|\\uD83C\\uDF11|\\uD83E\\uDD53|\\uD83C\\uDF13|\\uD83C\\uDF14|\\uD83C\\uDF15|\\uD83C\\uDF19|\\uD83C\\uDF1B|\\uD83C\\uDF1F|\\uD83E\\uDD52|\\uD83C\\uDF20|\\uD83C\\uDF30|\\uD83E\\uDD51|\\uD83C\\uDF31|\\uD83C\\uDF34|\\uD83C\\uDF35|\\uD83C\\uDF37|\\uD83C\\uDF38|\\uD83C\\uDF39|\\uD83C\\uDF3A|\\uD83C\\uDF3B|\\uD83C\\uDF3C|\\uD83C\\uDF3D|\\uD83E\\uDD50|\\uD83C\\uDF3E|\\uD83C\\uDF3F|\\uD83C\\uDF40|\\uD83C\\uDF41|\\uD83C\\uDF42|\\uD83C\\uDF43|\\uD83C\\uDF44|\\uD83C\\uDF45|\\uD83C\\uDF46|\\uD83C\\uDF47|\\uD83C\\uDF48|\\uD83C\\uDF49|\\uD83C\\uDF4A|\\uD83E\\uDD40|\\uD83C\\uDF4C|\\uD83C\\uDF4D|\\uD83C\\uDF4E|\\uD83C\\uDF4F|\\uD83C\\uDF51|\\uD83C\\uDF52|\\uD83C\\uDF53|\\uD83E\\uDD8F|\\uD83C\\uDF54|\\uD83C\\uDF55|\\uD83C\\uDF56|\\uD83E\\uDD8E|\\uD83C\\uDF57|\\uD83C\\uDF58|\\uD83C\\uDF59|\\uD83E\\uDD8D|\\uD83C\\uDF5A|\\uD83C\\uDF5B|\\uD83E\\uDD8C|\\uD83C\\uDF5C|\\uD83C\\uDF5D|\\uD83C\\uDF5E|\\uD83C\\uDF5F|\\uD83E\\uDD8B|\\uD83C\\uDF60|\\uD83C\\uDF61|\\uD83E\\uDD8A|\\uD83C\\uDF62|\\uD83C\\uDF63|\\uD83E\\uDD89|\\uD83C\\uDF64|\\uD83C\\uDF65|\\uD83E\\uDD88|\\uD83C\\uDF66|\\uD83E\\uDD87|\\uD83C\\uDF67|\\uD83C\\uDDFD|\\uD83C\\uDF68|\\uD83E\\uDD86|\\uD83C\\uDF69|\\uD83E\\uDD85|\\uD83C\\uDF6A|\\uD83D\\uDDA4|\\uD83C\\uDF6B|\\uD83C\\uDF6C|\\uD83C\\uDF6D|\\uD83C\\uDF6E|\\uD83C\\uDF6F|\\uD83E\\uDD1E|\\uD83C\\uDF70|\\uD83C\\uDF71|\\uD83C\\uDF72|\\uD83E\\uDD1D|\\uD83C\\uDF73|\\uD83C\\uDF74|\\uD83C\\uDF75|\\uD83C\\uDF76|\\uD83C\\uDF77|\\uD83C\\uDF78|\\uD83C\\uDF79|\\uD83C\\uDF7A|\\uD83C\\uDF7B|\\uD83C\\uDF80|\\uD83C\\uDF81|\\uD83C\\uDF82|\\uD83C\\uDF83|\\uD83E\\uDD1B|\\uD83E\\uDD1C|\\uD83C\\uDF84|\\uD83C\\uDF85|\\uD83C\\uDF86|\\uD83E\\uDD1A|\\uD83C\\uDF87|\\uD83C\\uDF88|\\uD83C\\uDF89|\\uD83C\\uDF8A|\\uD83C\\uDF8B|\\uD83C\\uDF8C|\\uD83E\\uDD19|\\uD83C\\uDF8D|\\uD83D\\uDD7A|\\uD83C\\uDF8E|\\uD83E\\uDD33|\\uD83C\\uDF8F|\\uD83E\\uDD30|\\uD83C\\uDF90|\\uD83E\\uDD26|\\uD83E\\uDD37|\\uD83C\\uDF91|\\uD83C\\uDF92|\\uD83C\\uDF93|\\uD83C\\uDFA0|\\uD83C\\uDFA1|\\uD83C\\uDFA2|\\uD83C\\uDFA3|\\uD83C\\uDFA4|\\uD83C\\uDFA5|\\uD83C\\uDFA6|\\uD83C\\uDFA7|\\uD83E\\uDD36|\\uD83C\\uDFA8|\\uD83E\\uDD35|\\uD83C\\uDFA9|\\uD83C\\uDFAA|\\uD83E\\uDD34|\\uD83C\\uDFAB|\\uD83C\\uDFAC|\\uD83C\\uDFAD|\\uD83E\\uDD27|\\uD83C\\uDFAE|\\uD83C\\uDFAF|\\uD83C\\uDFB0|\\uD83C\\uDFB1|\\uD83C\\uDFB2|\\uD83C\\uDFB3|\\uD83C\\uDFB4|\\uD83E\\uDD25|\\uD83C\\uDFB5|\\uD83C\\uDFB6|\\uD83C\\uDFB7|\\uD83E\\uDD24|\\uD83C\\uDFB8|\\uD83C\\uDFB9|\\uD83C\\uDFBA|\\uD83E\\uDD23|\\uD83C\\uDFBB|\\uD83C\\uDFBC|\\uD83C\\uDFBD|\\uD83E\\uDD22|\\uD83C\\uDFBE|\\uD83C\\uDFBF|\\uD83C\\uDFC0|\\uD83C\\uDFC1|\\uD83E\\uDD21|\\uD83C\\uDFC2|\\uD83C\\uDFC3|\\uD83C\\uDFC4|\\uD83C\\uDFC6|\\uD83C\\uDFC8|\\uD83C\\uDFCA|\\uD83C\\uDFE0|\\uD83C\\uDFE1|\\uD83C\\uDFE2|\\uD83C\\uDFE3|\\uD83C\\uDFE5|\\uD83C\\uDFE6|\\uD83C\\uDFE7|\\uD83C\\uDFE8|\\uD83C\\uDFE9|\\uD83C\\uDFEA|\\uD83C\\uDFEB|\\uD83C\\uDFEC|\\uD83E\\uDD20|\\uD83C\\uDFED|\\uD83C\\uDFEE|\\uD83C\\uDFEF|\\uD83C\\uDFF0|\\uD83D\\uDC0C|\\uD83D\\uDC0D|\\uD83D\\uDC0E|\\uD83D\\uDC11|\\uD83D\\uDC12|\\uD83D\\uDC14|\\uD83D\\uDC17|\\uD83D\\uDC18|\\uD83D\\uDC19|\\uD83D\\uDC1A|\\uD83D\\uDC1B|\\uD83D\\uDC1C|\\uD83D\\uDC1D|\\uD83D\\uDC1E|\\uD83D\\uDC1F|\\uD83D\\uDC20|\\uD83D\\uDC21|\\uD83D\\uDC22|\\uD83D\\uDC23|\\uD83D\\uDC24|\\uD83D\\uDC25|\\uD83D\\uDC26|\\uD83D\\uDC27|\\uD83D\\uDC28|\\uD83D\\uDC29|\\uD83D\\uDC2B|\\uD83D\\uDC2C|\\uD83D\\uDC2D|\\uD83D\\uDC2E|\\uD83D\\uDC2F|\\uD83D\\uDC30|\\uD83D\\uDC31|\\uD83D\\uDC32|\\uD83D\\uDC33|\\uD83D\\uDC34|\\uD83D\\uDC35|\\uD83D\\uDC36|\\uD83D\\uDC37|\\uD83D\\uDC38|\\uD83D\\uDC39|\\uD83D\\uDC3A|\\uD83D\\uDC3B|\\uD83D\\uDC3C|\\uD83D\\uDC3D|\\uD83D\\uDC3E|\\uD83D\\uDC40|\\uD83D\\uDC42|\\uD83D\\uDC43|\\uD83D\\uDC44|\\uD83D\\uDC45|\\uD83D\\uDC46|\\uD83D\\uDC47|\\uD83D\\uDC48|\\uD83D\\uDC49|\\uD83D\\uDC4A|\\uD83D\\uDC4B|\\uD83D\\uDC4C|\\uD83D\\uDC4D|\\uD83D\\uDC4E|\\uD83D\\uDC4F|\\uD83D\\uDC50|\\uD83D\\uDC51|\\uD83D\\uDC52|\\uD83D\\uDC53|\\uD83D\\uDC54|\\uD83D\\uDC55|\\uD83D\\uDC56|\\uD83D\\uDC57|\\uD83D\\uDC58|\\uD83D\\uDC59|\\uD83D\\uDC5A|\\uD83D\\uDC5B|\\uD83D\\uDC5C|\\uD83D\\uDC5D|\\uD83D\\uDC5E|\\uD83D\\uDC5F|\\uD83D\\uDC60|\\uD83D\\uDC61|\\uD83D\\uDC62|\\uD83D\\uDC63|\\uD83D\\uDC64|\\uD83D\\uDC66|\\uD83D\\uDC67|\\uD83D\\uDC68|\\uD83D\\uDC69|\\uD83D\\uDC6A|\\uD83D\\uDC6B|\\uD83D\\uDC6E|\\uD83D\\uDC6F|\\uD83D\\uDC70|\\uD83D\\uDC71|\\uD83D\\uDC72|\\uD83D\\uDC73|\\uD83D\\uDC74|\\uD83D\\uDC75|\\uD83D\\uDC76|\\uD83D\\uDC77|\\uD83D\\uDC78|\\uD83D\\uDC79|\\uD83D\\uDC7A|\\uD83D\\uDC7B|\\uD83D\\uDC7C|\\uD83D\\uDC7D|\\uD83D\\uDC7E|\\uD83D\\uDC7F|\\uD83D\\uDC80|\\uD83D\\uDCC7|\\uD83D\\uDC81|\\uD83D\\uDC82|\\uD83D\\uDC83|\\uD83D\\uDC84|\\uD83D\\uDC85|\\uD83D\\uDCD2|\\uD83D\\uDC86|\\uD83D\\uDCD3|\\uD83D\\uDC87|\\uD83D\\uDCD4|\\uD83D\\uDC88|\\uD83D\\uDCD5|\\uD83D\\uDC89|\\uD83D\\uDCD6|\\uD83D\\uDC8A|\\uD83D\\uDCD7|\\uD83D\\uDC8B|\\uD83D\\uDCD8|\\uD83D\\uDC8C|\\uD83D\\uDCD9|\\uD83D\\uDC8D|\\uD83D\\uDCDA|\\uD83D\\uDC8E|\\uD83D\\uDCDB|\\uD83D\\uDC8F|\\uD83D\\uDCDC|\\uD83D\\uDC90|\\uD83D\\uDCDD|\\uD83D\\uDC91|\\uD83D\\uDCDE|\\uD83D\\uDC92|\\uD83D\\uDCDF|\\uD83D\\uDCE0|\\uD83D\\uDC93|\\uD83D\\uDCE1|\\uD83D\\uDCE2|\\uD83D\\uDC94|\\uD83D\\uDCE3|\\uD83D\\uDCE4|\\uD83D\\uDC95|\\uD83D\\uDCE5|\\uD83D\\uDCE6|\\uD83D\\uDC96|\\uD83D\\uDCE7|\\uD83D\\uDCE8|\\uD83D\\uDC97|\\uD83D\\uDCE9|\\uD83D\\uDCEA|\\uD83D\\uDC98|\\uD83D\\uDCEB|\\uD83D\\uDCEE|\\uD83D\\uDC99|\\uD83D\\uDCF0|\\uD83D\\uDCF1|\\uD83D\\uDC9A|\\uD83D\\uDCF2|\\uD83D\\uDCF3|\\uD83D\\uDC9B|\\uD83D\\uDCF4|\\uD83D\\uDCF6|\\uD83D\\uDC9C|\\uD83D\\uDCF7|\\uD83D\\uDCF9|\\uD83D\\uDC9D|\\uD83D\\uDCFA|\\uD83D\\uDCFB|\\uD83D\\uDC9E|\\uD83D\\uDCFC|\\uD83D\\uDD03|\\uD83D\\uDC9F|\\uD83D\\uDD0A|\\uD83D\\uDD0B|\\uD83D\\uDCA0|\\uD83D\\uDD0C|\\uD83D\\uDD0D|\\uD83D\\uDCA1|\\uD83D\\uDD0E|\\uD83D\\uDD0F|\\uD83D\\uDCA2|\\uD83D\\uDD10|\\uD83D\\uDD11|\\uD83D\\uDCA3|\\uD83D\\uDD12|\\uD83D\\uDD13|\\uD83D\\uDCA4|\\uD83D\\uDD14|\\uD83D\\uDD16|\\uD83D\\uDCA5|\\uD83D\\uDD17|\\uD83D\\uDD18|\\uD83D\\uDCA6|\\uD83D\\uDD19|\\uD83D\\uDD1A|\\uD83D\\uDCA7|\\uD83D\\uDD1B|\\uD83D\\uDD1C|\\uD83D\\uDCA8|\\uD83D\\uDD1D|\\uD83D\\uDD1E|\\uD83D\\uDCA9|\\uD83D\\uDD1F|\\uD83D\\uDCAA|\\uD83D\\uDD20|\\uD83D\\uDD21|\\uD83D\\uDCAB|\\uD83D\\uDD22|\\uD83D\\uDD23|\\uD83D\\uDCAC|\\uD83D\\uDD24|\\uD83D\\uDD25|\\uD83D\\uDCAE|\\uD83D\\uDD26|\\uD83D\\uDD27|\\uD83D\\uDCAF|\\uD83D\\uDD28|\\uD83D\\uDD29|\\uD83D\\uDCB0|\\uD83D\\uDD2A|\\uD83D\\uDD2B|\\uD83D\\uDCB1|\\uD83D\\uDD2E|\\uD83D\\uDCB2|\\uD83D\\uDD2F|\\uD83D\\uDCB3|\\uD83D\\uDD30|\\uD83D\\uDD31|\\uD83D\\uDCB4|\\uD83D\\uDD32|\\uD83D\\uDD33|\\uD83D\\uDCB5|\\uD83D\\uDD34|\\uD83D\\uDD35|\\uD83D\\uDCB8|\\uD83D\\uDD36|\\uD83D\\uDD37|\\uD83D\\uDCB9|\\uD83D\\uDD38|\\uD83D\\uDD39|\\uD83D\\uDCBA|\\uD83D\\uDD3A|\\uD83D\\uDD3B|\\uD83D\\uDCBB|\\uD83D\\uDD3C|\\uD83D\\uDCBC|\\uD83D\\uDD3D|\\uD83D\\uDD50|\\uD83D\\uDCBD|\\uD83D\\uDD51|\\uD83D\\uDCBE|\\uD83D\\uDD52|\\uD83D\\uDCBF|\\uD83D\\uDD53|\\uD83D\\uDCC0|\\uD83D\\uDD54|\\uD83D\\uDD55|\\uD83D\\uDCC1|\\uD83D\\uDD56|\\uD83D\\uDD57|\\uD83D\\uDCC2|\\uD83D\\uDD58|\\uD83D\\uDD59|\\uD83D\\uDCC3|\\uD83D\\uDD5A|\\uD83D\\uDD5B|\\uD83D\\uDCC4|\\uD83D\\uDDFB|\\uD83D\\uDDFC|\\uD83D\\uDCC5|\\uD83D\\uDDFD|\\uD83D\\uDDFE|\\uD83D\\uDCC6|\\uD83D\\uDDFF|\\uD83D\\uDE01|\\uD83D\\uDE02|\\uD83D\\uDE03|\\uD83D\\uDCC8|\\uD83D\\uDE04|\\uD83D\\uDE05|\\uD83D\\uDCC9|\\uD83D\\uDE06|\\uD83D\\uDE09|\\uD83D\\uDCCA|\\uD83D\\uDE0A|\\uD83D\\uDE0B|\\uD83D\\uDCCB|\\uD83D\\uDE0C|\\uD83D\\uDE0D|\\uD83D\\uDCCC|\\uD83D\\uDE0F|\\uD83D\\uDE12|\\uD83D\\uDCCD|\\uD83D\\uDE13|\\uD83D\\uDE14|\\uD83D\\uDCCE|\\uD83D\\uDE16|\\uD83D\\uDE18|\\uD83D\\uDCCF|\\uD83D\\uDE1A|\\uD83D\\uDE1C|\\uD83D\\uDCD0|\\uD83D\\uDE1D|\\uD83D\\uDE1E|\\uD83D\\uDCD1|\\uD83D\\uDE20|\\uD83D\\uDE21|\\uD83D\\uDE22|\\uD83D\\uDE23|\\uD83D\\uDE24|\\uD83D\\uDE25|\\uD83D\\uDE28|\\uD83D\\uDE29|\\uD83D\\uDE2A|\\uD83D\\uDE2B|\\uD83D\\uDE2D|\\uD83D\\uDE30|\\uD83D\\uDE31|\\uD83D\\uDE32|\\uD83D\\uDE33|\\uD83D\\uDE35|\\uD83D\\uDE37|\\uD83D\\uDE38|\\uD83D\\uDE39|\\uD83D\\uDE3A|\\uD83D\\uDE3B|\\uD83D\\uDE3C|\\uD83D\\uDE3D|\\uD83D\\uDE3E|\\uD83D\\uDE3F|\\uD83D\\uDE40|\\uD83D\\uDE45|\\uD83D\\uDE46|\\uD83D\\uDE47|\\uD83D\\uDE48|\\uD83D\\uDE49|\\uD83D\\uDE4A|\\uD83D\\uDE4B|\\uD83D\\uDE4C|\\uD83D\\uDE4D|\\uD83D\\uDE4E|\\uD83D\\uDE4F|\\uD83D\\uDE80|\\uD83D\\uDE83|\\uD83D\\uDE84|\\uD83D\\uDE85|\\uD83D\\uDE87|\\uD83D\\uDE89|\\uD83D\\uDE8C|\\uD83D\\uDE8F|\\uD83D\\uDE91|\\uD83D\\uDE92|\\uD83D\\uDE93|\\uD83D\\uDE95|\\uD83D\\uDE97|\\uD83D\\uDE99|\\uD83D\\uDE9A|\\uD83D\\uDEA2|\\uD83D\\uDEA4|\\uD83D\\uDEA5|\\uD83D\\uDEA7|\\uD83D\\uDEA8|\\uD83D\\uDEA9|\\uD83D\\uDEAA|\\uD83D\\uDEAB|\\uD83D\\uDEAC|\\uD83D\\uDEAD|\\uD83D\\uDEB2|\\uD83D\\uDEB6|\\uD83D\\uDEB9|\\uD83D\\uDEBA|\\uD83D\\uDEBB|\\uD83D\\uDEBC|\\uD83D\\uDEBD|\\uD83D\\uDEBE|\\uD83D\\uDEC0|\\uD83E\\uDD18|\\uD83D\\uDE00|\\uD83D\\uDE07|\\uD83D\\uDE08|\\uD83D\\uDE0E|\\uD83D\\uDE10|\\uD83D\\uDE11|\\uD83D\\uDE15|\\uD83D\\uDE17|\\uD83D\\uDE19|\\uD83D\\uDE1B|\\uD83D\\uDE1F|\\uD83D\\uDE26|\\uD83D\\uDE27|\\uD83D\\uDE2C|\\uD83D\\uDE2E|\\uD83D\\uDE2F|\\uD83D\\uDE34|\\uD83D\\uDE36|\\uD83D\\uDE81|\\uD83D\\uDE82|\\uD83D\\uDE86|\\uD83D\\uDE88|\\uD83D\\uDE8A|\\uD83D\\uDE8D|\\uD83D\\uDE8E|\\uD83D\\uDE90|\\uD83D\\uDE94|\\uD83D\\uDE96|\\uD83D\\uDE98|\\uD83D\\uDE9B|\\uD83D\\uDE9C|\\uD83D\\uDE9D|\\uD83D\\uDE9E|\\uD83D\\uDE9F|\\uD83D\\uDEA0|\\uD83D\\uDEA1|\\uD83D\\uDEA3|\\uD83D\\uDEA6|\\uD83D\\uDEAE|\\uD83D\\uDEAF|\\uD83D\\uDEB0|\\uD83D\\uDEB1|\\uD83D\\uDEB3|\\uD83D\\uDEB4|\\uD83D\\uDEB5|\\uD83D\\uDEB7|\\uD83D\\uDEB8|\\uD83D\\uDEBF|\\uD83D\\uDEC1|\\uD83D\\uDEC2|\\uD83D\\uDEC3|\\uD83D\\uDEC4|\\uD83D\\uDEC5|\\uD83C\\uDF0D|\\uD83C\\uDF0E|\\uD83C\\uDF10|\\uD83C\\uDF12|\\uD83C\\uDF16|\\uD83C\\uDF17|\\uD83C\\uDF18|\\uD83C\\uDF1A|\\uD83C\\uDF1C|\\uD83C\\uDF1D|\\uD83C\\uDF1E|\\uD83C\\uDF32|\\uD83C\\uDF33|\\uD83C\\uDF4B|\\uD83C\\uDF50|\\uD83C\\uDF7C|\\uD83C\\uDFC7|\\uD83C\\uDFC9|\\uD83C\\uDFE4|\\uD83D\\uDC00|\\uD83D\\uDC01|\\uD83D\\uDC02|\\uD83D\\uDC03|\\uD83D\\uDC04|\\uD83D\\uDC05|\\uD83D\\uDC06|\\uD83D\\uDC07|\\uD83D\\uDC08|\\uD83D\\uDC09|\\uD83D\\uDC0A|\\uD83D\\uDC0B|\\uD83D\\uDC0F|\\uD83D\\uDC10|\\uD83D\\uDC13|\\uD83D\\uDC15|\\uD83D\\uDC16|\\uD83D\\uDC2A|\\uD83D\\uDC65|\\uD83D\\uDC6C|\\uD83D\\uDC6D|\\uD83D\\uDCAD|\\uD83D\\uDCB6|\\uD83D\\uDCB7|\\uD83D\\uDCEC|\\uD83D\\uDCED|\\uD83D\\uDCEF|\\uD83D\\uDCF5|\\uD83D\\uDD00|\\uD83D\\uDD01|\\uD83D\\uDD02|\\uD83D\\uDD04|\\uD83D\\uDD05|\\uD83D\\uDD06|\\uD83D\\uDD07|\\uD83D\\uDD09|\\uD83D\\uDD15|\\uD83D\\uDD2C|\\uD83D\\uDD2D|\\uD83D\\uDD5C|\\uD83D\\uDD5D|\\uD83D\\uDD5E|\\uD83D\\uDD5F|\\uD83D\\uDD60|\\uD83D\\uDD61|\\uD83D\\uDD62|\\uD83D\\uDD63|\\uD83D\\uDD64|\\uD83D\\uDD65|\\uD83D\\uDD66|\\uD83D\\uDD67|\\uD83D\\uDD08|\\uD83D\\uDE8B|\\uD83C\\uDFC5|\\uD83C\\uDFF4|\\uD83D\\uDCF8|\\uD83D\\uDECC|\\uD83D\\uDD95|\\uD83D\\uDD96|\\uD83D\\uDE41|\\uD83D\\uDE42|\\uD83D\\uDEEB|\\uD83D\\uDEEC|\\uD83C\\uDFFB|\\uD83C\\uDFFC|\\uD83C\\uDFFD|\\uD83C\\uDFFE|\\uD83C\\uDFFF|\\uD83D\\uDE43|\\uD83E\\uDD11|\\uD83E\\uDD13|\\uD83E\\uDD17|\\uD83D\\uDE44|\\uD83E\\uDD14|\\uD83E\\uDD10|\\u26F2\\uFE0F|\\#\\u20E3|\\9\\u20E3|\\8\\u20E3|\\7\\u20E3|\\6\\u20E3|\\*\\u20E3|\\4\\u20E3|\\3\\u20E3|\\2\\u20E3|\\1\\u20E3|\\0\\u20E3|\\5\\u20E3|\\u26B1|\\u26B0|\\u269C|\\u269B|\\u2699|\\u2697|\\u2696|\\u2694|\\u2692|\\u2639|\\u2638|\\u262F|\\u262E|\\u262A|\\u2626|\\u2623|\\u2622|\\u2620|\\u2618|\\u2604|\\u2603|\\u2602|\\u23FA|\\u23F9|\\u23F8|\\u23F2|\\u23F1|\\u23EF|\\u23EE|\\u23ED|\\u23CF|\\u270D|\\u2328|\\u271D|\\u3299|\\u3297|\\u303D|\\u3030|\\u2B55|\\u2B50|\\u2B1C|\\u2B1B|\\u2B07|\\u2B06|\\u2B05|\\u2935|\\u23E9|\\u23EA|\\u23EB|\\u23EC|\\u23F0|\\u23F3|\\u26CE|\\u2705|\\u270A|\\u270B|\\u2728|\\u274C|\\u274E|\\u2753|\\u2754|\\u2755|\\u2795|\\u2796|\\u2797|\\u27B0|\\u27BF|\\u00A9|\\u00AE|\\u203C|\\u2049|\\u2122|\\u2139|\\u2194|\\u2195|\\u2196|\\u2197|\\u2198|\\u2199|\\u21A9|\\u21AA|\\u231A|\\u231B|\\u24C2|\\u25AA|\\u25AB|\\u25B6|\\u25C0|\\u25FB|\\u25FC|\\u25FD|\\u25FE|\\u2600|\\u2601|\\u260E|\\u2611|\\u2614|\\u2615|\\u261D|\\u263A|\\u2648|\\u2649|\\u264A|\\u264B|\\u264C|\\u264D|\\u264E|\\u264F|\\u2650|\\u2651|\\u2652|\\u2653|\\u2660|\\u2663|\\u2665|\\u2666|\\u2668|\\u267B|\\u267F|\\u2693|\\u26A0|\\u26A1|\\u26AA|\\u26AB|\\u26BD|\\u26BE|\\u26C4|\\u26C5|\\u26D4|\\u26EA|\\u26F2|\\u26F3|\\u26F5|\\u26FA|\\u26FD|\\u2702|\\u2708|\\u2709|\\u270C|\\u270F|\\u2712|\\u2714|\\u2716|\\u2733|\\u2734|\\u2744|\\u2747|\\u2721|\\u2764|\\u27A1|\\u2934|\\u2935|\\u2B05|\\u2B06|\\u2B07|\\u2B1B|\\u2B1C|\\u2B50|\\u2B55|\\u3030|\\u303D|\\u3297|\\u3299|\\u2934|\\u27A1|\\u2764|\\u2757|\\u2747|\\u2744|\\u2734|\\u2733|\\u2716|\\u2714|\\u2712|\\u270F|\\u270C|\\u2709|\\u2708|\\u2702|\\u26FD|\\u26FA|\\u26F5|\\u26F3|\\u26F2|\\u26EA|\\u26D4|\\u26C5|\\u26C4|\\u26BE|\\u26BD|\\u26AB|\\u26AA|\\u26A1|\\u26A0|\\u2693|\\u271D|\\u267F|\\u267B|\\u2668|\\u2666|\\u2665|\\u2663|\\u2660|\\u2653|\\u2652|\\u2651|\\u2650|\\u264F|\\u264E|\\u264D|\\u2328|\\u264C|\\u264B|\\u264A|\\u2649|\\u2648|\\u263A|\\u261D|\\u2615|\\u2614|\\u2611|\\u260E|\\u2601|\\u2600|\\u25FE|\\u25FD|\\u25FC|\\u25FB|\\u25C0|\\u25B6|\\u25AB|\\u25AA|\\u24C2|\\u231B|\\u231A|\\u21AA|\\u270D|\\u21A9|\\u2199|\\u2198|\\u2197|\\u2196|\\u2195|\\u2194|\\u2139|\\u2122|\\u2049|\\u203C|\\u00AE|\\u00A9|\\u2763|\\u26F9|\\u26F8|\\u26F7|\\u26F4|\\u26F1|\\u26F0|\\u26E9|\\u26D3|\\u23CF|\\u23ED|\\u23EE|\\u23EF|\\u23F1|\\u23F2|\\u23F8|\\u23F9|\\u23FA|\\u2602|\\u2603|\\u2604|\\u2618|\\u2620|\\u2622|\\u2623|\\u2626|\\u262A|\\u262E|\\u262F|\\u2638|\\u2639|\\u2692|\\u2694|\\u2696|\\u2697|\\u2699|\\u269B|\\u269C|\\u26B0|\\u26B1|\\u26C8|\\u26CF|\\u26D1|\\u26D3|\\u26E9|\\u26F0|\\u26F1|\\u26F4|\\u26F7|\\u26F8|\\u26F9|\\u2721|\\u2763|\\u26D1|\\u26CF|\\u26C8|\\u2757)';
+ ns.jsEscapeMap = {"\uD83D\uDC69\u200D\u2764\uFE0F\u200D\uD83D\uDC8B\u200D\uD83D\uDC69":"1f469-200d-2764-fe0f-200d-1f48b-200d-1f469","\uD83D\uDC69\u2764\uD83D\uDC8B\uD83D\uDC69":"1f469-2764-1f48b-1f469","\uD83D\uDC68\u200D\u2764\uFE0F\u200D\uD83D\uDC8B\u200D\uD83D\uDC68":"1f468-200d-2764-fe0f-200d-1f48b-200d-1f468","\uD83D\uDC68\u2764\uD83D\uDC8B\uD83D\uDC68":"1f468-2764-1f48b-1f468","\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC66\u200D\uD83D\uDC66":"1f468-200d-1f468-200d-1f466-200d-1f466","\uD83D\uDC68\uD83D\uDC68\uD83D\uDC66\uD83D\uDC66":"1f468-1f468-1f466-1f466","\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC67\u200D\uD83D\uDC66":"1f468-200d-1f468-200d-1f467-200d-1f466","\uD83D\uDC68\uD83D\uDC68\uD83D\uDC67\uD83D\uDC66":"1f468-1f468-1f467-1f466","\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC67\u200D\uD83D\uDC67":"1f468-200d-1f468-200d-1f467-200d-1f467","\uD83D\uDC68\uD83D\uDC68\uD83D\uDC67\uD83D\uDC67":"1f468-1f468-1f467-1f467","\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66":"1f468-200d-1f469-200d-1f466-200d-1f466","\uD83D\uDC68\uD83D\uDC69\uD83D\uDC66\uD83D\uDC66":"1f468-1f469-1f466-1f466","\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66":"1f468-200d-1f469-200d-1f467-200d-1f466","\uD83D\uDC68\uD83D\uDC69\uD83D\uDC67\uD83D\uDC66":"1f468-1f469-1f467-1f466","\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC67":"1f468-200d-1f469-200d-1f467-200d-1f467","\uD83D\uDC68\uD83D\uDC69\uD83D\uDC67\uD83D\uDC67":"1f468-1f469-1f467-1f467","\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66":"1f469-200d-1f469-200d-1f466-200d-1f466","\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66\uD83D\uDC66":"1f469-1f469-1f466-1f466","\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66":"1f469-200d-1f469-200d-1f467-200d-1f466","\uD83D\uDC69\uD83D\uDC69\uD83D\uDC67\uD83D\uDC66":"1f469-1f469-1f467-1f466","\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC67":"1f469-200d-1f469-200d-1f467-200d-1f467","\uD83D\uDC69\uD83D\uDC69\uD83D\uDC67\uD83D\uDC67":"1f469-1f469-1f467-1f467","\uD83D\uDC69\u200D\u2764\uFE0F\u200D\uD83D\uDC69":"1f469-200d-2764-fe0f-200d-1f469","\uD83D\uDC69\u2764\uD83D\uDC69":"1f469-2764-1f469","\uD83D\uDC68\u200D\u2764\uFE0F\u200D\uD83D\uDC68":"1f468-200d-2764-fe0f-200d-1f468","\uD83D\uDC68\u2764\uD83D\uDC68":"1f468-2764-1f468","\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC66":"1f468-200d-1f468-200d-1f466","\uD83D\uDC68\uD83D\uDC68\uD83D\uDC66":"1f468-1f468-1f466","\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC67":"1f468-200d-1f468-200d-1f467","\uD83D\uDC68\uD83D\uDC68\uD83D\uDC67":"1f468-1f468-1f467","\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67":"1f468-200d-1f469-200d-1f467","\uD83D\uDC68\uD83D\uDC69\uD83D\uDC67":"1f468-1f469-1f467","\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66":"1f469-200d-1f469-200d-1f466","\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66":"1f469-1f469-1f466","\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC67":"1f469-200d-1f469-200d-1f467","\uD83D\uDC69\uD83D\uDC69\uD83D\uDC67":"1f469-1f469-1f467","\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08":"1f3f3-fe0f-200d-1f308","\uD83C\uDFF3\uD83C\uDF08":"1f3f3-1f308","\uD83D\uDC41\u200D\uD83D\uDDE8":"1f441-200d-1f5e8","\uD83D\uDC41\uD83D\uDDE8":"1f441-1f5e8","#\uFE0F\u20E3":"0023-fe0f-20e3","#\u20E3":"0023-20e3","0\uFE0F\u20E3":"0030-fe0f-20e3","0\u20E3":"0030-20e3","1\uFE0F\u20E3":"0031-fe0f-20e3","1\u20E3":"0031-20e3","2\uFE0F\u20E3":"0032-fe0f-20e3","2\u20E3":"0032-20e3","3\uFE0F\u20E3":"0033-fe0f-20e3","3\u20E3":"0033-20e3","4\uFE0F\u20E3":"0034-fe0f-20e3","4\u20E3":"0034-20e3","5\uFE0F\u20E3":"0035-fe0f-20e3","5\u20E3":"0035-20e3","6\uFE0F\u20E3":"0036-fe0f-20e3","6\u20E3":"0036-20e3","7\uFE0F\u20E3":"0037-fe0f-20e3","7\u20E3":"0037-20e3","8\uFE0F\u20E3":"0038-fe0f-20e3","8\u20E3":"0038-20e3","9\uFE0F\u20E3":"0039-fe0f-20e3","9\u20E3":"0039-20e3","*\uFE0F\u20E3":"002a-fe0f-20e3","*\u20E3":"002a-20e3","\uD83E\uDD3E\uD83C\uDFFF":"1f93e-1f3ff","\uD83E\uDD3E\uD83C\uDFFE":"1f93e-1f3fe","\uD83E\uDD3E\uD83C\uDFFD":"1f93e-1f3fd","\uD83E\uDD3E\uD83C\uDFFC":"1f93e-1f3fc","\uD83E\uDD3E\uD83C\uDFFB":"1f93e-1f3fb","\uD83E\uDD3D\uD83C\uDFFF":"1f93d-1f3ff","\uD83E\uDD3D\uD83C\uDFFE":"1f93d-1f3fe","\uD83E\uDD3D\uD83C\uDFFD":"1f93d-1f3fd","\uD83E\uDD3D\uD83C\uDFFC":"1f93d-1f3fc","\uD83E\uDD3D\uD83C\uDFFB":"1f93d-1f3fb","\uD83E\uDD3C\uD83C\uDFFF":"1f93c-1f3ff","\uD83E\uDD3C\uD83C\uDFFE":"1f93c-1f3fe","\uD83E\uDD3C\uD83C\uDFFD":"1f93c-1f3fd","\uD83E\uDD3C\uD83C\uDFFC":"1f93c-1f3fc","\uD83E\uDD3C\uD83C\uDFFB":"1f93c-1f3fb","\uD83E\uDD39\uD83C\uDFFF":"1f939-1f3ff","\uD83E\uDD39\uD83C\uDFFE":"1f939-1f3fe","\uD83E\uDD39\uD83C\uDFFD":"1f939-1f3fd","\uD83E\uDD39\uD83C\uDFFC":"1f939-1f3fc","\uD83E\uDD39\uD83C\uDFFB":"1f939-1f3fb","\uD83E\uDD38\uD83C\uDFFF":"1f938-1f3ff","\uD83E\uDD38\uD83C\uDFFE":"1f938-1f3fe","\uD83E\uDD38\uD83C\uDFFD":"1f938-1f3fd","\uD83E\uDD38\uD83C\uDFFC":"1f938-1f3fc","\uD83E\uDD38\uD83C\uDFFB":"1f938-1f3fb","\uD83E\uDD37\uD83C\uDFFF":"1f937-1f3ff","\uD83E\uDD37\uD83C\uDFFE":"1f937-1f3fe","\uD83E\uDD37\uD83C\uDFFD":"1f937-1f3fd","\uD83E\uDD37\uD83C\uDFFC":"1f937-1f3fc","\uD83E\uDD37\uD83C\uDFFB":"1f937-1f3fb","\uD83E\uDD36\uD83C\uDFFF":"1f936-1f3ff","\uD83E\uDD36\uD83C\uDFFE":"1f936-1f3fe","\uD83E\uDD36\uD83C\uDFFD":"1f936-1f3fd","\uD83E\uDD36\uD83C\uDFFC":"1f936-1f3fc","\uD83E\uDD36\uD83C\uDFFB":"1f936-1f3fb","\uD83E\uDD35\uD83C\uDFFF":"1f935-1f3ff","\uD83E\uDD35\uD83C\uDFFE":"1f935-1f3fe","\uD83E\uDD35\uD83C\uDFFD":"1f935-1f3fd","\uD83E\uDD35\uD83C\uDFFC":"1f935-1f3fc","\uD83E\uDD35\uD83C\uDFFB":"1f935-1f3fb","\uD83E\uDD34\uD83C\uDFFF":"1f934-1f3ff","\uD83E\uDD34\uD83C\uDFFE":"1f934-1f3fe","\uD83E\uDD34\uD83C\uDFFD":"1f934-1f3fd","\uD83E\uDD34\uD83C\uDFFC":"1f934-1f3fc","\uD83E\uDD34\uD83C\uDFFB":"1f934-1f3fb","\uD83E\uDD33\uD83C\uDFFF":"1f933-1f3ff","\uD83E\uDD33\uD83C\uDFFE":"1f933-1f3fe","\uD83E\uDD33\uD83C\uDFFD":"1f933-1f3fd","\uD83E\uDD33\uD83C\uDFFC":"1f933-1f3fc","\uD83E\uDD33\uD83C\uDFFB":"1f933-1f3fb","\uD83E\uDD30\uD83C\uDFFF":"1f930-1f3ff","\uD83E\uDD30\uD83C\uDFFE":"1f930-1f3fe","\uD83E\uDD30\uD83C\uDFFD":"1f930-1f3fd","\uD83E\uDD30\uD83C\uDFFC":"1f930-1f3fc","\uD83E\uDD30\uD83C\uDFFB":"1f930-1f3fb","\uD83E\uDD26\uD83C\uDFFF":"1f926-1f3ff","\uD83E\uDD26\uD83C\uDFFE":"1f926-1f3fe","\uD83E\uDD26\uD83C\uDFFD":"1f926-1f3fd","\uD83E\uDD26\uD83C\uDFFC":"1f926-1f3fc","\uD83E\uDD26\uD83C\uDFFB":"1f926-1f3fb","\uD83E\uDD1E\uD83C\uDFFF":"1f91e-1f3ff","\uD83E\uDD1E\uD83C\uDFFE":"1f91e-1f3fe","\uD83E\uDD1E\uD83C\uDFFD":"1f91e-1f3fd","\uD83E\uDD1E\uD83C\uDFFC":"1f91e-1f3fc","\uD83E\uDD1E\uD83C\uDFFB":"1f91e-1f3fb","\uD83E\uDD1D\uD83C\uDFFF":"1f91d-1f3ff","\uD83E\uDD1D\uD83C\uDFFE":"1f91d-1f3fe","\uD83E\uDD1D\uD83C\uDFFD":"1f91d-1f3fd","\uD83E\uDD1D\uD83C\uDFFC":"1f91d-1f3fc","\uD83E\uDD1D\uD83C\uDFFB":"1f91d-1f3fb","\uD83E\uDD1C\uD83C\uDFFF":"1f91c-1f3ff","\uD83E\uDD1C\uD83C\uDFFE":"1f91c-1f3fe","\uD83E\uDD1C\uD83C\uDFFD":"1f91c-1f3fd","\uD83E\uDD1C\uD83C\uDFFC":"1f91c-1f3fc","\uD83E\uDD1C\uD83C\uDFFB":"1f91c-1f3fb","\uD83E\uDD1B\uD83C\uDFFF":"1f91b-1f3ff","\uD83E\uDD1B\uD83C\uDFFE":"1f91b-1f3fe","\uD83E\uDD1B\uD83C\uDFFD":"1f91b-1f3fd","\uD83E\uDD1B\uD83C\uDFFC":"1f91b-1f3fc","\uD83E\uDD1B\uD83C\uDFFB":"1f91b-1f3fb","\uD83E\uDD1A\uD83C\uDFFF":"1f91a-1f3ff","\uD83E\uDD1A\uD83C\uDFFE":"1f91a-1f3fe","\uD83E\uDD1A\uD83C\uDFFD":"1f91a-1f3fd","\uD83E\uDD1A\uD83C\uDFFC":"1f91a-1f3fc","\uD83E\uDD1A\uD83C\uDFFB":"1f91a-1f3fb","\uD83E\uDD19\uD83C\uDFFF":"1f919-1f3ff","\uD83E\uDD19\uD83C\uDFFE":"1f919-1f3fe","\uD83E\uDD19\uD83C\uDFFD":"1f919-1f3fd","\uD83E\uDD19\uD83C\uDFFC":"1f919-1f3fc","\uD83E\uDD19\uD83C\uDFFB":"1f919-1f3fb","\uD83E\uDD18\uD83C\uDFFF":"1f918-1f3ff","\uD83E\uDD18\uD83C\uDFFE":"1f918-1f3fe","\uD83E\uDD18\uD83C\uDFFD":"1f918-1f3fd","\uD83E\uDD18\uD83C\uDFFC":"1f918-1f3fc","\uD83E\uDD18\uD83C\uDFFB":"1f918-1f3fb","\uD83D\uDEC0\uD83C\uDFFF":"1f6c0-1f3ff","\uD83D\uDEC0\uD83C\uDFFE":"1f6c0-1f3fe","\uD83D\uDEC0\uD83C\uDFFD":"1f6c0-1f3fd","\uD83D\uDEC0\uD83C\uDFFC":"1f6c0-1f3fc","\uD83D\uDEC0\uD83C\uDFFB":"1f6c0-1f3fb","\uD83D\uDEB6\uD83C\uDFFF":"1f6b6-1f3ff","\uD83D\uDEB6\uD83C\uDFFE":"1f6b6-1f3fe","\uD83D\uDEB6\uD83C\uDFFD":"1f6b6-1f3fd","\uD83D\uDEB6\uD83C\uDFFC":"1f6b6-1f3fc","\uD83D\uDEB6\uD83C\uDFFB":"1f6b6-1f3fb","\uD83D\uDEB5\uD83C\uDFFF":"1f6b5-1f3ff","\uD83D\uDEB5\uD83C\uDFFE":"1f6b5-1f3fe","\uD83D\uDEB5\uD83C\uDFFD":"1f6b5-1f3fd","\uD83D\uDEB5\uD83C\uDFFC":"1f6b5-1f3fc","\uD83D\uDEB5\uD83C\uDFFB":"1f6b5-1f3fb","\uD83D\uDEB4\uD83C\uDFFF":"1f6b4-1f3ff","\uD83D\uDEB4\uD83C\uDFFE":"1f6b4-1f3fe","\uD83D\uDEB4\uD83C\uDFFD":"1f6b4-1f3fd","\uD83D\uDEB4\uD83C\uDFFC":"1f6b4-1f3fc","\uD83D\uDEB4\uD83C\uDFFB":"1f6b4-1f3fb","\uD83D\uDEA3\uD83C\uDFFF":"1f6a3-1f3ff","\uD83D\uDEA3\uD83C\uDFFE":"1f6a3-1f3fe","\uD83D\uDEA3\uD83C\uDFFD":"1f6a3-1f3fd","\uD83D\uDEA3\uD83C\uDFFC":"1f6a3-1f3fc","\uD83D\uDEA3\uD83C\uDFFB":"1f6a3-1f3fb","\uD83D\uDE4F\uD83C\uDFFF":"1f64f-1f3ff","\uD83D\uDE4F\uD83C\uDFFE":"1f64f-1f3fe","\uD83D\uDE4F\uD83C\uDFFD":"1f64f-1f3fd","\uD83D\uDE4F\uD83C\uDFFC":"1f64f-1f3fc","\uD83D\uDE4F\uD83C\uDFFB":"1f64f-1f3fb","\uD83D\uDE4E\uD83C\uDFFF":"1f64e-1f3ff","\uD83D\uDE4E\uD83C\uDFFE":"1f64e-1f3fe","\uD83D\uDE4E\uD83C\uDFFD":"1f64e-1f3fd","\uD83D\uDE4E\uD83C\uDFFC":"1f64e-1f3fc","\uD83D\uDE4E\uD83C\uDFFB":"1f64e-1f3fb","\uD83D\uDE4D\uD83C\uDFFF":"1f64d-1f3ff","\uD83D\uDE4D\uD83C\uDFFE":"1f64d-1f3fe","\uD83D\uDE4D\uD83C\uDFFD":"1f64d-1f3fd","\uD83D\uDE4D\uD83C\uDFFC":"1f64d-1f3fc","\uD83D\uDE4D\uD83C\uDFFB":"1f64d-1f3fb","\uD83D\uDE4C\uD83C\uDFFF":"1f64c-1f3ff","\uD83D\uDE4C\uD83C\uDFFE":"1f64c-1f3fe","\uD83D\uDE4C\uD83C\uDFFD":"1f64c-1f3fd","\uD83D\uDE4C\uD83C\uDFFC":"1f64c-1f3fc","\uD83D\uDE4C\uD83C\uDFFB":"1f64c-1f3fb","\uD83D\uDE4B\uD83C\uDFFF":"1f64b-1f3ff","\uD83D\uDE4B\uD83C\uDFFE":"1f64b-1f3fe","\uD83D\uDE4B\uD83C\uDFFD":"1f64b-1f3fd","\uD83D\uDE4B\uD83C\uDFFC":"1f64b-1f3fc","\uD83D\uDE4B\uD83C\uDFFB":"1f64b-1f3fb","\uD83D\uDE47\uD83C\uDFFF":"1f647-1f3ff","\uD83D\uDE47\uD83C\uDFFE":"1f647-1f3fe","\uD83D\uDE47\uD83C\uDFFD":"1f647-1f3fd","\uD83D\uDE47\uD83C\uDFFC":"1f647-1f3fc","\uD83D\uDE47\uD83C\uDFFB":"1f647-1f3fb","\uD83D\uDE46\uD83C\uDFFF":"1f646-1f3ff","\uD83D\uDE46\uD83C\uDFFE":"1f646-1f3fe","\uD83D\uDE46\uD83C\uDFFD":"1f646-1f3fd","\uD83D\uDE46\uD83C\uDFFC":"1f646-1f3fc","\uD83D\uDE46\uD83C\uDFFB":"1f646-1f3fb","\uD83D\uDE45\uD83C\uDFFF":"1f645-1f3ff","\uD83D\uDE45\uD83C\uDFFE":"1f645-1f3fe","\uD83D\uDE45\uD83C\uDFFD":"1f645-1f3fd","\uD83D\uDE45\uD83C\uDFFC":"1f645-1f3fc","\uD83D\uDE45\uD83C\uDFFB":"1f645-1f3fb","\uD83D\uDD96\uD83C\uDFFF":"1f596-1f3ff","\uD83D\uDD96\uD83C\uDFFE":"1f596-1f3fe","\uD83D\uDD96\uD83C\uDFFD":"1f596-1f3fd","\uD83D\uDD96\uD83C\uDFFC":"1f596-1f3fc","\uD83D\uDD96\uD83C\uDFFB":"1f596-1f3fb","\uD83D\uDD95\uD83C\uDFFF":"1f595-1f3ff","\uD83D\uDD95\uD83C\uDFFE":"1f595-1f3fe","\uD83D\uDD95\uD83C\uDFFD":"1f595-1f3fd","\uD83D\uDD95\uD83C\uDFFC":"1f595-1f3fc","\uD83D\uDD95\uD83C\uDFFB":"1f595-1f3fb","\uD83D\uDD90\uD83C\uDFFF":"1f590-1f3ff","\uD83D\uDD90\uD83C\uDFFE":"1f590-1f3fe","\uD83D\uDD90\uD83C\uDFFD":"1f590-1f3fd","\uD83D\uDD90\uD83C\uDFFC":"1f590-1f3fc","\uD83D\uDD90\uD83C\uDFFB":"1f590-1f3fb","\uD83D\uDD7A\uD83C\uDFFF":"1f57a-1f3ff","\uD83D\uDD7A\uD83C\uDFFE":"1f57a-1f3fe","\uD83D\uDD7A\uD83C\uDFFD":"1f57a-1f3fd","\uD83D\uDD7A\uD83C\uDFFC":"1f57a-1f3fc","\uD83D\uDD7A\uD83C\uDFFB":"1f57a-1f3fb","\uD83D\uDD75\uD83C\uDFFF":"1f575-1f3ff","\uD83D\uDD75\uD83C\uDFFE":"1f575-1f3fe","\uD83D\uDD75\uD83C\uDFFD":"1f575-1f3fd","\uD83D\uDD75\uD83C\uDFFC":"1f575-1f3fc","\uD83D\uDD75\uD83C\uDFFB":"1f575-1f3fb","\uD83D\uDCAA\uD83C\uDFFF":"1f4aa-1f3ff","\uD83D\uDCAA\uD83C\uDFFE":"1f4aa-1f3fe","\uD83D\uDCAA\uD83C\uDFFD":"1f4aa-1f3fd","\uD83D\uDCAA\uD83C\uDFFC":"1f4aa-1f3fc","\uD83D\uDCAA\uD83C\uDFFB":"1f4aa-1f3fb","\uD83D\uDC87\uD83C\uDFFF":"1f487-1f3ff","\uD83D\uDC87\uD83C\uDFFE":"1f487-1f3fe","\uD83D\uDC87\uD83C\uDFFD":"1f487-1f3fd","\uD83D\uDC87\uD83C\uDFFC":"1f487-1f3fc","\uD83D\uDC87\uD83C\uDFFB":"1f487-1f3fb","\uD83D\uDC86\uD83C\uDFFF":"1f486-1f3ff","\uD83D\uDC86\uD83C\uDFFE":"1f486-1f3fe","\uD83D\uDC86\uD83C\uDFFD":"1f486-1f3fd","\uD83D\uDC86\uD83C\uDFFC":"1f486-1f3fc","\uD83D\uDC86\uD83C\uDFFB":"1f486-1f3fb","\uD83D\uDC85\uD83C\uDFFF":"1f485-1f3ff","\uD83D\uDC85\uD83C\uDFFE":"1f485-1f3fe","\uD83D\uDC85\uD83C\uDFFD":"1f485-1f3fd","\uD83D\uDC85\uD83C\uDFFC":"1f485-1f3fc","\uD83D\uDC85\uD83C\uDFFB":"1f485-1f3fb","\uD83D\uDC83\uD83C\uDFFF":"1f483-1f3ff","\uD83D\uDC83\uD83C\uDFFE":"1f483-1f3fe","\uD83D\uDC83\uD83C\uDFFD":"1f483-1f3fd","\uD83D\uDC83\uD83C\uDFFC":"1f483-1f3fc","\uD83D\uDC83\uD83C\uDFFB":"1f483-1f3fb","\uD83D\uDC82\uD83C\uDFFF":"1f482-1f3ff","\uD83D\uDC82\uD83C\uDFFE":"1f482-1f3fe","\uD83D\uDC82\uD83C\uDFFD":"1f482-1f3fd","\uD83D\uDC82\uD83C\uDFFC":"1f482-1f3fc","\uD83D\uDC82\uD83C\uDFFB":"1f482-1f3fb","\uD83D\uDC81\uD83C\uDFFF":"1f481-1f3ff","\uD83D\uDC81\uD83C\uDFFE":"1f481-1f3fe","\uD83D\uDC81\uD83C\uDFFD":"1f481-1f3fd","\uD83D\uDC81\uD83C\uDFFC":"1f481-1f3fc","\uD83D\uDC81\uD83C\uDFFB":"1f481-1f3fb","\uD83D\uDC7C\uD83C\uDFFF":"1f47c-1f3ff","\uD83D\uDC7C\uD83C\uDFFE":"1f47c-1f3fe","\uD83D\uDC7C\uD83C\uDFFD":"1f47c-1f3fd","\uD83D\uDC7C\uD83C\uDFFC":"1f47c-1f3fc","\uD83D\uDC7C\uD83C\uDFFB":"1f47c-1f3fb","\uD83D\uDC78\uD83C\uDFFF":"1f478-1f3ff","\uD83D\uDC78\uD83C\uDFFE":"1f478-1f3fe","\uD83D\uDC78\uD83C\uDFFD":"1f478-1f3fd","\uD83D\uDC78\uD83C\uDFFC":"1f478-1f3fc","\uD83D\uDC78\uD83C\uDFFB":"1f478-1f3fb","\uD83D\uDC77\uD83C\uDFFF":"1f477-1f3ff","\uD83D\uDC77\uD83C\uDFFE":"1f477-1f3fe","\uD83D\uDC77\uD83C\uDFFD":"1f477-1f3fd","\uD83D\uDC77\uD83C\uDFFC":"1f477-1f3fc","\uD83D\uDC77\uD83C\uDFFB":"1f477-1f3fb","\uD83D\uDC76\uD83C\uDFFF":"1f476-1f3ff","\uD83D\uDC76\uD83C\uDFFE":"1f476-1f3fe","\uD83D\uDC76\uD83C\uDFFD":"1f476-1f3fd","\uD83D\uDC76\uD83C\uDFFC":"1f476-1f3fc","\uD83D\uDC76\uD83C\uDFFB":"1f476-1f3fb","\uD83D\uDC75\uD83C\uDFFF":"1f475-1f3ff","\uD83D\uDC75\uD83C\uDFFE":"1f475-1f3fe","\uD83D\uDC75\uD83C\uDFFD":"1f475-1f3fd","\uD83D\uDC75\uD83C\uDFFC":"1f475-1f3fc","\uD83D\uDC75\uD83C\uDFFB":"1f475-1f3fb","\uD83D\uDC74\uD83C\uDFFF":"1f474-1f3ff","\uD83D\uDC74\uD83C\uDFFE":"1f474-1f3fe","\uD83D\uDC74\uD83C\uDFFD":"1f474-1f3fd","\uD83D\uDC74\uD83C\uDFFC":"1f474-1f3fc","\uD83D\uDC74\uD83C\uDFFB":"1f474-1f3fb","\uD83D\uDC73\uD83C\uDFFF":"1f473-1f3ff","\uD83D\uDC73\uD83C\uDFFE":"1f473-1f3fe","\uD83D\uDC73\uD83C\uDFFD":"1f473-1f3fd","\uD83D\uDC73\uD83C\uDFFC":"1f473-1f3fc","\uD83D\uDC73\uD83C\uDFFB":"1f473-1f3fb","\uD83D\uDC72\uD83C\uDFFF":"1f472-1f3ff","\uD83D\uDC72\uD83C\uDFFE":"1f472-1f3fe","\uD83D\uDC72\uD83C\uDFFD":"1f472-1f3fd","\uD83D\uDC72\uD83C\uDFFC":"1f472-1f3fc","\uD83D\uDC72\uD83C\uDFFB":"1f472-1f3fb","\uD83D\uDC71\uD83C\uDFFF":"1f471-1f3ff","\uD83D\uDC71\uD83C\uDFFE":"1f471-1f3fe","\uD83D\uDC71\uD83C\uDFFD":"1f471-1f3fd","\uD83D\uDC71\uD83C\uDFFC":"1f471-1f3fc","\uD83D\uDC71\uD83C\uDFFB":"1f471-1f3fb","\uD83D\uDC70\uD83C\uDFFF":"1f470-1f3ff","\uD83D\uDC70\uD83C\uDFFE":"1f470-1f3fe","\uD83D\uDC70\uD83C\uDFFD":"1f470-1f3fd","\uD83D\uDC70\uD83C\uDFFC":"1f470-1f3fc","\uD83D\uDC70\uD83C\uDFFB":"1f470-1f3fb","\uD83D\uDC6E\uD83C\uDFFF":"1f46e-1f3ff","\uD83D\uDC6E\uD83C\uDFFE":"1f46e-1f3fe","\uD83D\uDC6E\uD83C\uDFFD":"1f46e-1f3fd","\uD83D\uDC6E\uD83C\uDFFC":"1f46e-1f3fc","\uD83D\uDC6E\uD83C\uDFFB":"1f46e-1f3fb","\uD83D\uDC69\uD83C\uDFFF":"1f469-1f3ff","\uD83D\uDC69\uD83C\uDFFE":"1f469-1f3fe","\uD83D\uDC69\uD83C\uDFFD":"1f469-1f3fd","\uD83D\uDC69\uD83C\uDFFC":"1f469-1f3fc","\uD83D\uDC69\uD83C\uDFFB":"1f469-1f3fb","\uD83D\uDC68\uD83C\uDFFF":"1f468-1f3ff","\uD83D\uDC68\uD83C\uDFFE":"1f468-1f3fe","\uD83D\uDC68\uD83C\uDFFD":"1f468-1f3fd","\uD83D\uDC68\uD83C\uDFFC":"1f468-1f3fc","\uD83D\uDC68\uD83C\uDFFB":"1f468-1f3fb","\uD83D\uDC67\uD83C\uDFFF":"1f467-1f3ff","\uD83D\uDC67\uD83C\uDFFE":"1f467-1f3fe","\uD83D\uDC67\uD83C\uDFFD":"1f467-1f3fd","\uD83D\uDC67\uD83C\uDFFC":"1f467-1f3fc","\uD83D\uDC67\uD83C\uDFFB":"1f467-1f3fb","\uD83D\uDC66\uD83C\uDFFF":"1f466-1f3ff","\uD83D\uDC66\uD83C\uDFFE":"1f466-1f3fe","\uD83D\uDC66\uD83C\uDFFD":"1f466-1f3fd","\uD83D\uDC66\uD83C\uDFFC":"1f466-1f3fc","\uD83D\uDC66\uD83C\uDFFB":"1f466-1f3fb","\uD83D\uDC50\uD83C\uDFFF":"1f450-1f3ff","\uD83D\uDC50\uD83C\uDFFE":"1f450-1f3fe","\uD83D\uDC50\uD83C\uDFFD":"1f450-1f3fd","\uD83D\uDC50\uD83C\uDFFC":"1f450-1f3fc","\uD83D\uDC50\uD83C\uDFFB":"1f450-1f3fb","\uD83D\uDC4F\uD83C\uDFFF":"1f44f-1f3ff","\uD83D\uDC4F\uD83C\uDFFE":"1f44f-1f3fe","\uD83D\uDC4F\uD83C\uDFFD":"1f44f-1f3fd","\uD83D\uDC4F\uD83C\uDFFC":"1f44f-1f3fc","\uD83D\uDC4F\uD83C\uDFFB":"1f44f-1f3fb","\uD83D\uDC4E\uD83C\uDFFF":"1f44e-1f3ff","\uD83D\uDC4E\uD83C\uDFFE":"1f44e-1f3fe","\uD83D\uDC4E\uD83C\uDFFD":"1f44e-1f3fd","\uD83D\uDC4E\uD83C\uDFFC":"1f44e-1f3fc","\uD83D\uDC4E\uD83C\uDFFB":"1f44e-1f3fb","\uD83D\uDC4D\uD83C\uDFFF":"1f44d-1f3ff","\uD83D\uDC4D\uD83C\uDFFE":"1f44d-1f3fe","\uD83D\uDC4D\uD83C\uDFFD":"1f44d-1f3fd","\uD83D\uDC4D\uD83C\uDFFC":"1f44d-1f3fc","\uD83D\uDC4D\uD83C\uDFFB":"1f44d-1f3fb","\uD83D\uDC4C\uD83C\uDFFF":"1f44c-1f3ff","\uD83D\uDC4C\uD83C\uDFFE":"1f44c-1f3fe","\uD83D\uDC4C\uD83C\uDFFD":"1f44c-1f3fd","\uD83D\uDC4C\uD83C\uDFFC":"1f44c-1f3fc","\uD83D\uDC4C\uD83C\uDFFB":"1f44c-1f3fb","\uD83D\uDC4B\uD83C\uDFFF":"1f44b-1f3ff","\uD83D\uDC4B\uD83C\uDFFE":"1f44b-1f3fe","\uD83D\uDC4B\uD83C\uDFFD":"1f44b-1f3fd","\uD83D\uDC4B\uD83C\uDFFC":"1f44b-1f3fc","\uD83D\uDC4B\uD83C\uDFFB":"1f44b-1f3fb","\uD83D\uDC4A\uD83C\uDFFF":"1f44a-1f3ff","\uD83D\uDC4A\uD83C\uDFFE":"1f44a-1f3fe","\uD83D\uDC4A\uD83C\uDFFD":"1f44a-1f3fd","\uD83D\uDC4A\uD83C\uDFFC":"1f44a-1f3fc","\uD83D\uDC4A\uD83C\uDFFB":"1f44a-1f3fb","\uD83D\uDC49\uD83C\uDFFF":"1f449-1f3ff","\uD83D\uDC49\uD83C\uDFFE":"1f449-1f3fe","\uD83D\uDC49\uD83C\uDFFD":"1f449-1f3fd","\uD83D\uDC49\uD83C\uDFFC":"1f449-1f3fc","\uD83D\uDC49\uD83C\uDFFB":"1f449-1f3fb","\uD83D\uDC48\uD83C\uDFFF":"1f448-1f3ff","\uD83D\uDC48\uD83C\uDFFE":"1f448-1f3fe","\uD83D\uDC48\uD83C\uDFFD":"1f448-1f3fd","\uD83D\uDC48\uD83C\uDFFC":"1f448-1f3fc","\uD83D\uDC48\uD83C\uDFFB":"1f448-1f3fb","\uD83D\uDC47\uD83C\uDFFF":"1f447-1f3ff","\uD83D\uDC47\uD83C\uDFFE":"1f447-1f3fe","\uD83D\uDC47\uD83C\uDFFD":"1f447-1f3fd","\uD83D\uDC47\uD83C\uDFFC":"1f447-1f3fc","\uD83D\uDC47\uD83C\uDFFB":"1f447-1f3fb","\uD83D\uDC46\uD83C\uDFFF":"1f446-1f3ff","\uD83D\uDC46\uD83C\uDFFE":"1f446-1f3fe","\uD83D\uDC46\uD83C\uDFFD":"1f446-1f3fd","\uD83D\uDC46\uD83C\uDFFC":"1f446-1f3fc","\uD83D\uDC46\uD83C\uDFFB":"1f446-1f3fb","\uD83D\uDC43\uD83C\uDFFF":"1f443-1f3ff","\uD83D\uDC43\uD83C\uDFFE":"1f443-1f3fe","\uD83D\uDC43\uD83C\uDFFD":"1f443-1f3fd","\uD83D\uDC43\uD83C\uDFFC":"1f443-1f3fc","\uD83D\uDC43\uD83C\uDFFB":"1f443-1f3fb","\uD83D\uDC42\uD83C\uDFFF":"1f442-1f3ff","\uD83D\uDC42\uD83C\uDFFE":"1f442-1f3fe","\uD83D\uDC42\uD83C\uDFFD":"1f442-1f3fd","\uD83D\uDC42\uD83C\uDFFC":"1f442-1f3fc","\uD83D\uDC42\uD83C\uDFFB":"1f442-1f3fb","\uD83C\uDFCB\uD83C\uDFFF":"1f3cb-1f3ff","\uD83C\uDFCB\uD83C\uDFFE":"1f3cb-1f3fe","\uD83C\uDFCB\uD83C\uDFFD":"1f3cb-1f3fd","\uD83C\uDFCB\uD83C\uDFFC":"1f3cb-1f3fc","\uD83C\uDFCB\uD83C\uDFFB":"1f3cb-1f3fb","\uD83C\uDFCA\uD83C\uDFFF":"1f3ca-1f3ff","\uD83C\uDFCA\uD83C\uDFFE":"1f3ca-1f3fe","\uD83C\uDFCA\uD83C\uDFFD":"1f3ca-1f3fd","\uD83C\uDFCA\uD83C\uDFFC":"1f3ca-1f3fc","\uD83C\uDFCA\uD83C\uDFFB":"1f3ca-1f3fb","\uD83C\uDFC7\uD83C\uDFFF":"1f3c7-1f3ff","\uD83C\uDFC7\uD83C\uDFFE":"1f3c7-1f3fe","\uD83C\uDFC7\uD83C\uDFFD":"1f3c7-1f3fd","\uD83C\uDFC7\uD83C\uDFFC":"1f3c7-1f3fc","\uD83C\uDFC7\uD83C\uDFFB":"1f3c7-1f3fb","\uD83C\uDFC4\uD83C\uDFFF":"1f3c4-1f3ff","\uD83C\uDFC4\uD83C\uDFFE":"1f3c4-1f3fe","\uD83C\uDFC4\uD83C\uDFFD":"1f3c4-1f3fd","\uD83C\uDFC4\uD83C\uDFFC":"1f3c4-1f3fc","\uD83C\uDFC4\uD83C\uDFFB":"1f3c4-1f3fb","\uD83C\uDFC3\uD83C\uDFFF":"1f3c3-1f3ff","\uD83C\uDFC3\uD83C\uDFFE":"1f3c3-1f3fe","\uD83C\uDFC3\uD83C\uDFFD":"1f3c3-1f3fd","\uD83C\uDFC3\uD83C\uDFFC":"1f3c3-1f3fc","\uD83C\uDFC3\uD83C\uDFFB":"1f3c3-1f3fb","\uD83C\uDF85\uD83C\uDFFF":"1f385-1f3ff","\uD83C\uDF85\uD83C\uDFFE":"1f385-1f3fe","\uD83C\uDF85\uD83C\uDFFD":"1f385-1f3fd","\uD83C\uDF85\uD83C\uDFFC":"1f385-1f3fc","\uD83C\uDF85\uD83C\uDFFB":"1f385-1f3fb","\uD83C\uDDFF\uD83C\uDDFC":"1f1ff-1f1fc","\uD83C\uDDFF\uD83C\uDDF2":"1f1ff-1f1f2","\uD83C\uDDFF\uD83C\uDDE6":"1f1ff-1f1e6","\uD83C\uDDFE\uD83C\uDDF9":"1f1fe-1f1f9","\uD83C\uDDFE\uD83C\uDDEA":"1f1fe-1f1ea","\uD83C\uDDFD\uD83C\uDDF0":"1f1fd-1f1f0","\uD83C\uDDFC\uD83C\uDDF8":"1f1fc-1f1f8","\uD83C\uDDFC\uD83C\uDDEB":"1f1fc-1f1eb","\uD83C\uDDFB\uD83C\uDDFA":"1f1fb-1f1fa","\uD83C\uDDFB\uD83C\uDDF3":"1f1fb-1f1f3","\uD83C\uDDFB\uD83C\uDDEE":"1f1fb-1f1ee","\uD83C\uDDFB\uD83C\uDDEC":"1f1fb-1f1ec","\uD83C\uDDFB\uD83C\uDDEA":"1f1fb-1f1ea","\uD83C\uDDFB\uD83C\uDDE8":"1f1fb-1f1e8","\uD83C\uDDFB\uD83C\uDDE6":"1f1fb-1f1e6","\uD83C\uDDFA\uD83C\uDDFF":"1f1fa-1f1ff","\uD83C\uDDFA\uD83C\uDDFE":"1f1fa-1f1fe","\uD83C\uDDFA\uD83C\uDDF8":"1f1fa-1f1f8","\uD83C\uDDFA\uD83C\uDDF2":"1f1fa-1f1f2","\uD83C\uDDFA\uD83C\uDDEC":"1f1fa-1f1ec","\uD83C\uDDFA\uD83C\uDDE6":"1f1fa-1f1e6","\uD83C\uDDF9\uD83C\uDDFF":"1f1f9-1f1ff","\uD83C\uDDF9\uD83C\uDDFC":"1f1f9-1f1fc","\uD83C\uDDF9\uD83C\uDDFB":"1f1f9-1f1fb","\uD83C\uDDF9\uD83C\uDDF9":"1f1f9-1f1f9","\uD83C\uDDF9\uD83C\uDDF7":"1f1f9-1f1f7","\uD83C\uDDF9\uD83C\uDDF4":"1f1f9-1f1f4","\uD83C\uDDF9\uD83C\uDDF3":"1f1f9-1f1f3","\uD83C\uDDF9\uD83C\uDDF2":"1f1f9-1f1f2","\uD83C\uDDF9\uD83C\uDDF1":"1f1f9-1f1f1","\uD83C\uDDF9\uD83C\uDDF0":"1f1f9-1f1f0","\uD83C\uDDF9\uD83C\uDDEF":"1f1f9-1f1ef","\uD83C\uDDF9\uD83C\uDDED":"1f1f9-1f1ed","\uD83C\uDDF9\uD83C\uDDEC":"1f1f9-1f1ec","\uD83C\uDDF9\uD83C\uDDEB":"1f1f9-1f1eb","\uD83C\uDDF9\uD83C\uDDE9":"1f1f9-1f1e9","\uD83C\uDDF9\uD83C\uDDE8":"1f1f9-1f1e8","\uD83C\uDDF9\uD83C\uDDE6":"1f1f9-1f1e6","\uD83C\uDDF8\uD83C\uDDFF":"1f1f8-1f1ff","\uD83C\uDDF8\uD83C\uDDFE":"1f1f8-1f1fe","\uD83C\uDDF8\uD83C\uDDFD":"1f1f8-1f1fd","\uD83C\uDDF8\uD83C\uDDFB":"1f1f8-1f1fb","\uD83C\uDDF8\uD83C\uDDF9":"1f1f8-1f1f9","\uD83C\uDDF8\uD83C\uDDF8":"1f1f8-1f1f8","\uD83C\uDDF8\uD83C\uDDF7":"1f1f8-1f1f7","\uD83C\uDDF8\uD83C\uDDF4":"1f1f8-1f1f4","\uD83C\uDDF8\uD83C\uDDF3":"1f1f8-1f1f3","\uD83C\uDDF8\uD83C\uDDF2":"1f1f8-1f1f2","\uD83C\uDDF8\uD83C\uDDF1":"1f1f8-1f1f1","\uD83C\uDDF8\uD83C\uDDF0":"1f1f8-1f1f0","\uD83C\uDDF8\uD83C\uDDEF":"1f1f8-1f1ef","\uD83C\uDDF8\uD83C\uDDEE":"1f1f8-1f1ee","\uD83C\uDDF8\uD83C\uDDED":"1f1f8-1f1ed","\uD83C\uDDF8\uD83C\uDDEC":"1f1f8-1f1ec","\uD83C\uDDF8\uD83C\uDDEA":"1f1f8-1f1ea","\uD83C\uDDF8\uD83C\uDDE9":"1f1f8-1f1e9","\uD83C\uDDF8\uD83C\uDDE8":"1f1f8-1f1e8","\uD83C\uDDF8\uD83C\uDDE7":"1f1f8-1f1e7","\uD83C\uDDF8\uD83C\uDDE6":"1f1f8-1f1e6","\uD83C\uDDF7\uD83C\uDDFC":"1f1f7-1f1fc","\uD83C\uDDF7\uD83C\uDDFA":"1f1f7-1f1fa","\uD83C\uDDF7\uD83C\uDDF8":"1f1f7-1f1f8","\uD83C\uDDF7\uD83C\uDDF4":"1f1f7-1f1f4","\uD83C\uDDF7\uD83C\uDDEA":"1f1f7-1f1ea","\uD83C\uDDF6\uD83C\uDDE6":"1f1f6-1f1e6","\uD83C\uDDF5\uD83C\uDDFE":"1f1f5-1f1fe","\uD83C\uDDF5\uD83C\uDDFC":"1f1f5-1f1fc","\uD83C\uDDF5\uD83C\uDDF9":"1f1f5-1f1f9","\uD83C\uDDF5\uD83C\uDDF8":"1f1f5-1f1f8","\uD83C\uDDF5\uD83C\uDDF7":"1f1f5-1f1f7","\uD83C\uDDF5\uD83C\uDDF3":"1f1f5-1f1f3","\uD83C\uDDF5\uD83C\uDDF2":"1f1f5-1f1f2","\uD83C\uDDF5\uD83C\uDDF1":"1f1f5-1f1f1","\uD83C\uDDF5\uD83C\uDDF0":"1f1f5-1f1f0","\uD83C\uDDF5\uD83C\uDDED":"1f1f5-1f1ed","\uD83C\uDDF5\uD83C\uDDEC":"1f1f5-1f1ec","\uD83C\uDDF5\uD83C\uDDEB":"1f1f5-1f1eb","\uD83C\uDDF5\uD83C\uDDEA":"1f1f5-1f1ea","\uD83C\uDDF5\uD83C\uDDE6":"1f1f5-1f1e6","\uD83C\uDDF4\uD83C\uDDF2":"1f1f4-1f1f2","\uD83C\uDDF3\uD83C\uDDFF":"1f1f3-1f1ff","\uD83C\uDDF3\uD83C\uDDFA":"1f1f3-1f1fa","\uD83C\uDDF3\uD83C\uDDF7":"1f1f3-1f1f7","\uD83C\uDDF3\uD83C\uDDF5":"1f1f3-1f1f5","\uD83C\uDDF3\uD83C\uDDF4":"1f1f3-1f1f4","\uD83C\uDDF3\uD83C\uDDF1":"1f1f3-1f1f1","\uD83C\uDDF3\uD83C\uDDEE":"1f1f3-1f1ee","\uD83C\uDDF3\uD83C\uDDEC":"1f1f3-1f1ec","\uD83C\uDDF3\uD83C\uDDEB":"1f1f3-1f1eb","\uD83C\uDDF3\uD83C\uDDEA":"1f1f3-1f1ea","\uD83C\uDDF3\uD83C\uDDE8":"1f1f3-1f1e8","\uD83C\uDDF3\uD83C\uDDE6":"1f1f3-1f1e6","\uD83C\uDDF2\uD83C\uDDFF":"1f1f2-1f1ff","\uD83C\uDDF2\uD83C\uDDFE":"1f1f2-1f1fe","\uD83C\uDDF2\uD83C\uDDFD":"1f1f2-1f1fd","\uD83C\uDDF2\uD83C\uDDFC":"1f1f2-1f1fc","\uD83C\uDDF2\uD83C\uDDFB":"1f1f2-1f1fb","\uD83C\uDDF2\uD83C\uDDFA":"1f1f2-1f1fa","\uD83C\uDDF2\uD83C\uDDF9":"1f1f2-1f1f9","\uD83C\uDDF2\uD83C\uDDF8":"1f1f2-1f1f8","\uD83C\uDDF2\uD83C\uDDF7":"1f1f2-1f1f7","\uD83C\uDDF2\uD83C\uDDF6":"1f1f2-1f1f6","\uD83C\uDDF2\uD83C\uDDF5":"1f1f2-1f1f5","\uD83C\uDDF2\uD83C\uDDF4":"1f1f2-1f1f4","\uD83C\uDDF2\uD83C\uDDF3":"1f1f2-1f1f3","\uD83C\uDDF2\uD83C\uDDF2":"1f1f2-1f1f2","\uD83C\uDDF2\uD83C\uDDF1":"1f1f2-1f1f1","\uD83C\uDDF2\uD83C\uDDF0":"1f1f2-1f1f0","\uD83C\uDDF2\uD83C\uDDED":"1f1f2-1f1ed","\uD83C\uDDF2\uD83C\uDDEC":"1f1f2-1f1ec","\uD83C\uDDF2\uD83C\uDDEB":"1f1f2-1f1eb","\uD83C\uDDF2\uD83C\uDDEA":"1f1f2-1f1ea","\uD83C\uDDF2\uD83C\uDDE9":"1f1f2-1f1e9","\uD83C\uDDF2\uD83C\uDDE8":"1f1f2-1f1e8","\uD83C\uDDF2\uD83C\uDDE6":"1f1f2-1f1e6","\uD83C\uDDF1\uD83C\uDDFE":"1f1f1-1f1fe","\uD83C\uDDF1\uD83C\uDDFB":"1f1f1-1f1fb","\uD83C\uDDF1\uD83C\uDDFA":"1f1f1-1f1fa","\uD83C\uDDF1\uD83C\uDDF9":"1f1f1-1f1f9","\uD83C\uDDF1\uD83C\uDDF8":"1f1f1-1f1f8","\uD83C\uDDF1\uD83C\uDDF7":"1f1f1-1f1f7","\uD83C\uDDF1\uD83C\uDDF0":"1f1f1-1f1f0","\uD83C\uDDF1\uD83C\uDDEE":"1f1f1-1f1ee","\uD83C\uDDF1\uD83C\uDDE8":"1f1f1-1f1e8","\uD83C\uDDF1\uD83C\uDDE7":"1f1f1-1f1e7","\uD83C\uDDF1\uD83C\uDDE6":"1f1f1-1f1e6","\uD83C\uDDF0\uD83C\uDDFF":"1f1f0-1f1ff","\uD83C\uDDF0\uD83C\uDDFE":"1f1f0-1f1fe","\uD83C\uDDF0\uD83C\uDDFC":"1f1f0-1f1fc","\uD83C\uDDF0\uD83C\uDDF7":"1f1f0-1f1f7","\uD83C\uDDF0\uD83C\uDDF5":"1f1f0-1f1f5","\uD83C\uDDF0\uD83C\uDDF3":"1f1f0-1f1f3","\uD83C\uDDF0\uD83C\uDDF2":"1f1f0-1f1f2","\uD83C\uDDF0\uD83C\uDDEE":"1f1f0-1f1ee","\uD83C\uDDF0\uD83C\uDDED":"1f1f0-1f1ed","\uD83C\uDDF0\uD83C\uDDEC":"1f1f0-1f1ec","\uD83C\uDDF0\uD83C\uDDEA":"1f1f0-1f1ea","\uD83C\uDDEF\uD83C\uDDF5":"1f1ef-1f1f5","\uD83C\uDDEF\uD83C\uDDF4":"1f1ef-1f1f4","\uD83C\uDDEF\uD83C\uDDF2":"1f1ef-1f1f2","\uD83C\uDDEF\uD83C\uDDEA":"1f1ef-1f1ea","\uD83C\uDDEE\uD83C\uDDF9":"1f1ee-1f1f9","\uD83C\uDDEE\uD83C\uDDF8":"1f1ee-1f1f8","\uD83C\uDDEE\uD83C\uDDF7":"1f1ee-1f1f7","\uD83C\uDDEE\uD83C\uDDF6":"1f1ee-1f1f6","\uD83C\uDDEE\uD83C\uDDF4":"1f1ee-1f1f4","\uD83C\uDDEE\uD83C\uDDF3":"1f1ee-1f1f3","\uD83C\uDDEE\uD83C\uDDF2":"1f1ee-1f1f2","\uD83C\uDDEE\uD83C\uDDF1":"1f1ee-1f1f1","\uD83C\uDDEE\uD83C\uDDEA":"1f1ee-1f1ea","\uD83C\uDDEE\uD83C\uDDE9":"1f1ee-1f1e9","\uD83C\uDDEE\uD83C\uDDE8":"1f1ee-1f1e8","\uD83C\uDDED\uD83C\uDDFA":"1f1ed-1f1fa","\uD83C\uDDED\uD83C\uDDF9":"1f1ed-1f1f9","\uD83C\uDDED\uD83C\uDDF7":"1f1ed-1f1f7","\uD83C\uDDED\uD83C\uDDF3":"1f1ed-1f1f3","\uD83C\uDDED\uD83C\uDDF2":"1f1ed-1f1f2","\uD83C\uDDED\uD83C\uDDF0":"1f1ed-1f1f0","\uD83C\uDDEC\uD83C\uDDFE":"1f1ec-1f1fe","\uD83C\uDDEC\uD83C\uDDFC":"1f1ec-1f1fc","\uD83C\uDDEC\uD83C\uDDFA":"1f1ec-1f1fa","\uD83C\uDDEC\uD83C\uDDF9":"1f1ec-1f1f9","\uD83C\uDDEC\uD83C\uDDF8":"1f1ec-1f1f8","\uD83C\uDDEC\uD83C\uDDF7":"1f1ec-1f1f7","\uD83C\uDDEC\uD83C\uDDF6":"1f1ec-1f1f6","\uD83C\uDDEC\uD83C\uDDF5":"1f1ec-1f1f5","\uD83C\uDDEC\uD83C\uDDF3":"1f1ec-1f1f3","\uD83C\uDDEC\uD83C\uDDF2":"1f1ec-1f1f2","\uD83C\uDDEC\uD83C\uDDF1":"1f1ec-1f1f1","\uD83C\uDDEC\uD83C\uDDEE":"1f1ec-1f1ee","\uD83C\uDDEC\uD83C\uDDED":"1f1ec-1f1ed","\uD83C\uDDEC\uD83C\uDDEC":"1f1ec-1f1ec","\uD83C\uDDEC\uD83C\uDDEB":"1f1ec-1f1eb","\uD83C\uDDEC\uD83C\uDDEA":"1f1ec-1f1ea","\uD83C\uDDEC\uD83C\uDDE9":"1f1ec-1f1e9","\uD83C\uDDEC\uD83C\uDDE7":"1f1ec-1f1e7","\uD83C\uDDEC\uD83C\uDDE6":"1f1ec-1f1e6","\uD83C\uDDEB\uD83C\uDDF7":"1f1eb-1f1f7","\uD83C\uDDEB\uD83C\uDDF4":"1f1eb-1f1f4","\uD83C\uDDEB\uD83C\uDDF2":"1f1eb-1f1f2","\uD83C\uDDEB\uD83C\uDDF0":"1f1eb-1f1f0","\uD83C\uDDEB\uD83C\uDDEF":"1f1eb-1f1ef","\uD83C\uDDEB\uD83C\uDDEE":"1f1eb-1f1ee","\uD83C\uDDEA\uD83C\uDDFA":"1f1ea-1f1fa","\uD83C\uDDEA\uD83C\uDDF9":"1f1ea-1f1f9","\uD83C\uDDEA\uD83C\uDDF8":"1f1ea-1f1f8","\uD83C\uDDEA\uD83C\uDDF7":"1f1ea-1f1f7","\uD83C\uDDEA\uD83C\uDDED":"1f1ea-1f1ed","\uD83C\uDDEA\uD83C\uDDEC":"1f1ea-1f1ec","\uD83C\uDDEA\uD83C\uDDEA":"1f1ea-1f1ea","\uD83C\uDDEA\uD83C\uDDE8":"1f1ea-1f1e8","\uD83C\uDDEA\uD83C\uDDE6":"1f1ea-1f1e6","\uD83C\uDDE9\uD83C\uDDFF":"1f1e9-1f1ff","\uD83C\uDDE9\uD83C\uDDF4":"1f1e9-1f1f4","\uD83C\uDDE9\uD83C\uDDF2":"1f1e9-1f1f2","\uD83C\uDDE9\uD83C\uDDF0":"1f1e9-1f1f0","\uD83C\uDDE9\uD83C\uDDEF":"1f1e9-1f1ef","\uD83C\uDDE9\uD83C\uDDEC":"1f1e9-1f1ec","\uD83C\uDDE9\uD83C\uDDEA":"1f1e9-1f1ea","\uD83C\uDDE8\uD83C\uDDFF":"1f1e8-1f1ff","\uD83C\uDDE8\uD83C\uDDFE":"1f1e8-1f1fe","\uD83C\uDDE8\uD83C\uDDFD":"1f1e8-1f1fd","\uD83C\uDDE8\uD83C\uDDFC":"1f1e8-1f1fc","\uD83C\uDDE8\uD83C\uDDFB":"1f1e8-1f1fb","\uD83C\uDDE8\uD83C\uDDFA":"1f1e8-1f1fa","\uD83C\uDDE8\uD83C\uDDF7":"1f1e8-1f1f7","\uD83C\uDDE8\uD83C\uDDF5":"1f1e8-1f1f5","\uD83C\uDDE8\uD83C\uDDF4":"1f1e8-1f1f4","\uD83C\uDDE8\uD83C\uDDF3":"1f1e8-1f1f3","\uD83C\uDDE8\uD83C\uDDF2":"1f1e8-1f1f2","\uD83C\uDDE8\uD83C\uDDF1":"1f1e8-1f1f1","\uD83C\uDDE8\uD83C\uDDF0":"1f1e8-1f1f0","\uD83C\uDDE8\uD83C\uDDEE":"1f1e8-1f1ee","\uD83C\uDDE8\uD83C\uDDED":"1f1e8-1f1ed","\uD83C\uDDE8\uD83C\uDDEC":"1f1e8-1f1ec","\uD83C\uDDE8\uD83C\uDDEB":"1f1e8-1f1eb","\uD83C\uDDE8\uD83C\uDDE9":"1f1e8-1f1e9","\uD83C\uDDE8\uD83C\uDDE8":"1f1e8-1f1e8","\uD83C\uDDE8\uD83C\uDDE6":"1f1e8-1f1e6","\uD83C\uDDE7\uD83C\uDDFF":"1f1e7-1f1ff","\uD83C\uDDE7\uD83C\uDDFE":"1f1e7-1f1fe","\uD83C\uDDE7\uD83C\uDDFC":"1f1e7-1f1fc","\uD83C\uDDE7\uD83C\uDDFB":"1f1e7-1f1fb","\uD83C\uDDE7\uD83C\uDDF9":"1f1e7-1f1f9","\uD83C\uDDE7\uD83C\uDDF8":"1f1e7-1f1f8","\uD83C\uDDE7\uD83C\uDDF7":"1f1e7-1f1f7","\uD83C\uDDE7\uD83C\uDDF6":"1f1e7-1f1f6","\uD83C\uDDE7\uD83C\uDDF4":"1f1e7-1f1f4","\uD83C\uDDE7\uD83C\uDDF3":"1f1e7-1f1f3","\uD83C\uDDE7\uD83C\uDDF2":"1f1e7-1f1f2","\uD83C\uDDE7\uD83C\uDDF1":"1f1e7-1f1f1","\uD83C\uDDE7\uD83C\uDDEF":"1f1e7-1f1ef","\uD83C\uDDE7\uD83C\uDDEE":"1f1e7-1f1ee","\uD83C\uDDE7\uD83C\uDDED":"1f1e7-1f1ed","\uD83C\uDDE7\uD83C\uDDEC":"1f1e7-1f1ec","\uD83C\uDDE7\uD83C\uDDEB":"1f1e7-1f1eb","\uD83C\uDDE7\uD83C\uDDEA":"1f1e7-1f1ea","\uD83C\uDDE7\uD83C\uDDE9":"1f1e7-1f1e9","\uD83C\uDDE7\uD83C\uDDE7":"1f1e7-1f1e7","\uD83C\uDDE7\uD83C\uDDE6":"1f1e7-1f1e6","\uD83C\uDDE6\uD83C\uDDFF":"1f1e6-1f1ff","\uD83C\uDDE6\uD83C\uDDFD":"1f1e6-1f1fd","\uD83C\uDDE6\uD83C\uDDFC":"1f1e6-1f1fc","\uD83C\uDDE6\uD83C\uDDFA":"1f1e6-1f1fa","\uD83C\uDDE6\uD83C\uDDF9":"1f1e6-1f1f9","\uD83C\uDDE6\uD83C\uDDF8":"1f1e6-1f1f8","\uD83C\uDDE6\uD83C\uDDF7":"1f1e6-1f1f7","\uD83C\uDDE6\uD83C\uDDF6":"1f1e6-1f1f6","\uD83C\uDDE6\uD83C\uDDF4":"1f1e6-1f1f4","\uD83C\uDDE6\uD83C\uDDF2":"1f1e6-1f1f2","\uD83C\uDDE6\uD83C\uDDF1":"1f1e6-1f1f1","\uD83C\uDDE6\uD83C\uDDEE":"1f1e6-1f1ee","\uD83C\uDDE6\uD83C\uDDEC":"1f1e6-1f1ec","\uD83C\uDDE6\uD83C\uDDEB":"1f1e6-1f1eb","\uD83C\uDDE6\uD83C\uDDEA":"1f1e6-1f1ea","\uD83C\uDDE6\uD83C\uDDE9":"1f1e6-1f1e9","\uD83C\uDDE6\uD83C\uDDE8":"1f1e6-1f1e8","\uD83C\uDC04\uFE0F":"1f004-fe0f","\uD83C\uDC04":"1f004","\uD83C\uDD7F\uFE0F":"1f17f-fe0f","\uD83C\uDD7F":"1f17f","\uD83C\uDE02\uFE0F":"1f202-fe0f","\uD83C\uDE02":"1f202","\uD83C\uDE1A\uFE0F":"1f21a-fe0f","\uD83C\uDE1A":"1f21a","\uD83C\uDE2F\uFE0F":"1f22f-fe0f","\uD83C\uDE2F":"1f22f","\uD83C\uDE37\uFE0F":"1f237-fe0f","\uD83C\uDE37":"1f237","\uD83C\uDF9E\uFE0F":"1f39e-fe0f","\uD83C\uDF9E":"1f39e","\uD83C\uDF9F\uFE0F":"1f39f-fe0f","\uD83C\uDF9F":"1f39f","\uD83C\uDFCB\uFE0F":"1f3cb-fe0f","\uD83C\uDFCB":"1f3cb","\uD83C\uDFCC\uFE0F":"1f3cc-fe0f","\uD83C\uDFCC":"1f3cc","\uD83C\uDFCD\uFE0F":"1f3cd-fe0f","\uD83C\uDFCD":"1f3cd","\uD83C\uDFCE\uFE0F":"1f3ce-fe0f","\uD83C\uDFCE":"1f3ce","\uD83C\uDF96\uFE0F":"1f396-fe0f","\uD83C\uDF96":"1f396","\uD83C\uDF97\uFE0F":"1f397-fe0f","\uD83C\uDF97":"1f397","\uD83C\uDF36\uFE0F":"1f336-fe0f","\uD83C\uDF36":"1f336","\uD83C\uDF27\uFE0F":"1f327-fe0f","\uD83C\uDF27":"1f327","\uD83C\uDF28\uFE0F":"1f328-fe0f","\uD83C\uDF28":"1f328","\uD83C\uDF29\uFE0F":"1f329-fe0f","\uD83C\uDF29":"1f329","\uD83C\uDF2A\uFE0F":"1f32a-fe0f","\uD83C\uDF2A":"1f32a","\uD83C\uDF2B\uFE0F":"1f32b-fe0f","\uD83C\uDF2B":"1f32b","\uD83C\uDF2C\uFE0F":"1f32c-fe0f","\uD83C\uDF2C":"1f32c","\uD83D\uDC3F\uFE0F":"1f43f-fe0f","\uD83D\uDC3F":"1f43f","\uD83D\uDD77\uFE0F":"1f577-fe0f","\uD83D\uDD77":"1f577","\uD83D\uDD78\uFE0F":"1f578-fe0f","\uD83D\uDD78":"1f578","\uD83C\uDF21\uFE0F":"1f321-fe0f","\uD83C\uDF21":"1f321","\uD83C\uDF99\uFE0F":"1f399-fe0f","\uD83C\uDF99":"1f399","\uD83C\uDF9A\uFE0F":"1f39a-fe0f","\uD83C\uDF9A":"1f39a","\uD83C\uDF9B\uFE0F":"1f39b-fe0f","\uD83C\uDF9B":"1f39b","\uD83C\uDFF3\uFE0F":"1f3f3-fe0f","\uD83C\uDFF3":"1f3f3","\uD83C\uDFF5\uFE0F":"1f3f5-fe0f","\uD83C\uDFF5":"1f3f5","\uD83C\uDFF7\uFE0F":"1f3f7-fe0f","\uD83C\uDFF7":"1f3f7","\uD83D\uDCFD\uFE0F":"1f4fd-fe0f","\uD83D\uDCFD":"1f4fd","\uD83D\uDD49\uFE0F":"1f549-fe0f","\uD83D\uDD49":"1f549","\uD83D\uDD4A\uFE0F":"1f54a-fe0f","\uD83D\uDD4A":"1f54a","\uD83D\uDD6F\uFE0F":"1f56f-fe0f","\uD83D\uDD6F":"1f56f","\uD83D\uDD70\uFE0F":"1f570-fe0f","\uD83D\uDD70":"1f570","\uD83D\uDD73\uFE0F":"1f573-fe0f","\uD83D\uDD73":"1f573","\uD83D\uDD76\uFE0F":"1f576-fe0f","\uD83D\uDD76":"1f576","\uD83D\uDD79\uFE0F":"1f579-fe0f","\uD83D\uDD79":"1f579","\uD83D\uDD87\uFE0F":"1f587-fe0f","\uD83D\uDD87":"1f587","\uD83D\uDD8A\uFE0F":"1f58a-fe0f","\uD83D\uDD8A":"1f58a","\uD83D\uDD8B\uFE0F":"1f58b-fe0f","\uD83D\uDD8B":"1f58b","\uD83D\uDD8C\uFE0F":"1f58c-fe0f","\uD83D\uDD8C":"1f58c","\uD83D\uDD8D\uFE0F":"1f58d-fe0f","\uD83D\uDD8D":"1f58d","\uD83D\uDDA5\uFE0F":"1f5a5-fe0f","\uD83D\uDDA5":"1f5a5","\uD83D\uDDA8\uFE0F":"1f5a8-fe0f","\uD83D\uDDA8":"1f5a8","\uD83D\uDDB2\uFE0F":"1f5b2-fe0f","\uD83D\uDDB2":"1f5b2","\uD83D\uDDBC\uFE0F":"1f5bc-fe0f","\uD83D\uDDBC":"1f5bc","\uD83D\uDDC2\uFE0F":"1f5c2-fe0f","\uD83D\uDDC2":"1f5c2","\uD83D\uDDC3\uFE0F":"1f5c3-fe0f","\uD83D\uDDC3":"1f5c3","\uD83D\uDDC4\uFE0F":"1f5c4-fe0f","\uD83D\uDDC4":"1f5c4","\uD83D\uDDD1\uFE0F":"1f5d1-fe0f","\uD83D\uDDD1":"1f5d1","\uD83D\uDDD2\uFE0F":"1f5d2-fe0f","\uD83D\uDDD2":"1f5d2","\uD83D\uDDD3\uFE0F":"1f5d3-fe0f","\uD83D\uDDD3":"1f5d3","\uD83D\uDDDC\uFE0F":"1f5dc-fe0f","\uD83D\uDDDC":"1f5dc","\uD83D\uDDDD\uFE0F":"1f5dd-fe0f","\uD83D\uDDDD":"1f5dd","\uD83D\uDDDE\uFE0F":"1f5de-fe0f","\uD83D\uDDDE":"1f5de","\uD83D\uDDE1\uFE0F":"1f5e1-fe0f","\uD83D\uDDE1":"1f5e1","\uD83D\uDDE3\uFE0F":"1f5e3-fe0f","\uD83D\uDDE3":"1f5e3","\uD83D\uDDE8\uFE0F":"1f5e8-fe0f","\uD83D\uDDE8":"1f5e8","\uD83D\uDDEF\uFE0F":"1f5ef-fe0f","\uD83D\uDDEF":"1f5ef","\uD83D\uDDF3\uFE0F":"1f5f3-fe0f","\uD83D\uDDF3":"1f5f3","\uD83D\uDDFA\uFE0F":"1f5fa-fe0f","\uD83D\uDDFA":"1f5fa","\uD83D\uDEE0\uFE0F":"1f6e0-fe0f","\uD83D\uDEE0":"1f6e0","\uD83D\uDEE1\uFE0F":"1f6e1-fe0f","\uD83D\uDEE1":"1f6e1","\uD83D\uDEE2\uFE0F":"1f6e2-fe0f","\uD83D\uDEE2":"1f6e2","\uD83D\uDEF0\uFE0F":"1f6f0-fe0f","\uD83D\uDEF0":"1f6f0","\uD83C\uDF7D\uFE0F":"1f37d-fe0f","\uD83C\uDF7D":"1f37d","\uD83D\uDC41\uFE0F":"1f441-fe0f","\uD83D\uDC41":"1f441","\uD83D\uDD74\uFE0F":"1f574-fe0f","\uD83D\uDD74":"1f574","\uD83D\uDD75\uFE0F":"1f575-fe0f","\uD83D\uDD75":"1f575","\uD83D\uDD90\uFE0F":"1f590-fe0f","\uD83D\uDD90":"1f590","\uD83C\uDFD4\uFE0F":"1f3d4-fe0f","\uD83C\uDFD4":"1f3d4","\uD83C\uDFD5\uFE0F":"1f3d5-fe0f","\uD83C\uDFD5":"1f3d5","\uD83C\uDFD6\uFE0F":"1f3d6-fe0f","\uD83C\uDFD6":"1f3d6","\uD83C\uDFD7\uFE0F":"1f3d7-fe0f","\uD83C\uDFD7":"1f3d7","\uD83C\uDFD8\uFE0F":"1f3d8-fe0f","\uD83C\uDFD8":"1f3d8","\uD83C\uDFD9\uFE0F":"1f3d9-fe0f","\uD83C\uDFD9":"1f3d9","\uD83C\uDFDA\uFE0F":"1f3da-fe0f","\uD83C\uDFDA":"1f3da","\uD83C\uDFDB\uFE0F":"1f3db-fe0f","\uD83C\uDFDB":"1f3db","\uD83C\uDFDC\uFE0F":"1f3dc-fe0f","\uD83C\uDFDC":"1f3dc","\uD83C\uDFDD\uFE0F":"1f3dd-fe0f","\uD83C\uDFDD":"1f3dd","\uD83C\uDFDE\uFE0F":"1f3de-fe0f","\uD83C\uDFDE":"1f3de","\uD83C\uDFDF\uFE0F":"1f3df-fe0f","\uD83C\uDFDF":"1f3df","\uD83D\uDECB\uFE0F":"1f6cb-fe0f","\uD83D\uDECB":"1f6cb","\uD83D\uDECD\uFE0F":"1f6cd-fe0f","\uD83D\uDECD":"1f6cd","\uD83D\uDECE\uFE0F":"1f6ce-fe0f","\uD83D\uDECE":"1f6ce","\uD83D\uDECF\uFE0F":"1f6cf-fe0f","\uD83D\uDECF":"1f6cf","\uD83D\uDEE3\uFE0F":"1f6e3-fe0f","\uD83D\uDEE3":"1f6e3","\uD83D\uDEE4\uFE0F":"1f6e4-fe0f","\uD83D\uDEE4":"1f6e4","\uD83D\uDEE5\uFE0F":"1f6e5-fe0f","\uD83D\uDEE5":"1f6e5","\uD83D\uDEE9\uFE0F":"1f6e9-fe0f","\uD83D\uDEE9":"1f6e9","\uD83D\uDEF3\uFE0F":"1f6f3-fe0f","\uD83D\uDEF3":"1f6f3","\uD83C\uDF24\uFE0F":"1f324-fe0f","\uD83C\uDF24":"1f324","\uD83C\uDF25\uFE0F":"1f325-fe0f","\uD83C\uDF25":"1f325","\uD83C\uDF26\uFE0F":"1f326-fe0f","\uD83C\uDF26":"1f326","\uD83D\uDDB1\uFE0F":"1f5b1-fe0f","\uD83D\uDDB1":"1f5b1","\u261D\uD83C\uDFFB":"261d-1f3fb","\u261D\uD83C\uDFFC":"261d-1f3fc","\u261D\uD83C\uDFFD":"261d-1f3fd","\u261D\uD83C\uDFFE":"261d-1f3fe","\u261D\uD83C\uDFFF":"261d-1f3ff","\u270C\uD83C\uDFFB":"270c-1f3fb","\u270C\uD83C\uDFFC":"270c-1f3fc","\u270C\uD83C\uDFFD":"270c-1f3fd","\u270C\uD83C\uDFFE":"270c-1f3fe","\u270C\uD83C\uDFFF":"270c-1f3ff","\u270A\uD83C\uDFFB":"270a-1f3fb","\u270A\uD83C\uDFFC":"270a-1f3fc","\u270A\uD83C\uDFFD":"270a-1f3fd","\u270A\uD83C\uDFFE":"270a-1f3fe","\u270A\uD83C\uDFFF":"270a-1f3ff","\u270B\uD83C\uDFFB":"270b-1f3fb","\u270B\uD83C\uDFFC":"270b-1f3fc","\u270B\uD83C\uDFFD":"270b-1f3fd","\u270B\uD83C\uDFFE":"270b-1f3fe","\u270B\uD83C\uDFFF":"270b-1f3ff","\u270D\uD83C\uDFFB":"270d-1f3fb","\u270D\uD83C\uDFFC":"270d-1f3fc","\u270D\uD83C\uDFFD":"270d-1f3fd","\u270D\uD83C\uDFFE":"270d-1f3fe","\u270D\uD83C\uDFFF":"270d-1f3ff","\u26F9\uD83C\uDFFB":"26f9-1f3fb","\u26F9\uD83C\uDFFC":"26f9-1f3fc","\u26F9\uD83C\uDFFD":"26f9-1f3fd","\u26F9\uD83C\uDFFE":"26f9-1f3fe","\u26F9\uD83C\uDFFF":"26f9-1f3ff","\u00A9\uFE0F":"00a9-fe0f","\u00A9":"00a9","\u00AE\uFE0F":"00ae-fe0f","\u00AE":"00ae","\u203C\uFE0F":"203c-fe0f","\u203C":"203c","\u2049\uFE0F":"2049-fe0f","\u2049":"2049","\u2122\uFE0F":"2122-fe0f","\u2122":"2122","\u2139\uFE0F":"2139-fe0f","\u2139":"2139","\u2194\uFE0F":"2194-fe0f","\u2194":"2194","\u2195\uFE0F":"2195-fe0f","\u2195":"2195","\u2196\uFE0F":"2196-fe0f","\u2196":"2196","\u2197\uFE0F":"2197-fe0f","\u2197":"2197","\u2198\uFE0F":"2198-fe0f","\u2198":"2198","\u2199\uFE0F":"2199-fe0f","\u2199":"2199","\u21A9\uFE0F":"21a9-fe0f","\u21A9":"21a9","\u21AA\uFE0F":"21aa-fe0f","\u21AA":"21aa","\u231A\uFE0F":"231a-fe0f","\u231A":"231a","\u231B\uFE0F":"231b-fe0f","\u231B":"231b","\u24C2\uFE0F":"24c2-fe0f","\u24C2":"24c2","\u25AA\uFE0F":"25aa-fe0f","\u25AA":"25aa","\u25AB\uFE0F":"25ab-fe0f","\u25AB":"25ab","\u25B6\uFE0F":"25b6-fe0f","\u25B6":"25b6","\u25C0\uFE0F":"25c0-fe0f","\u25C0":"25c0","\u25FB\uFE0F":"25fb-fe0f","\u25FB":"25fb","\u25FC\uFE0F":"25fc-fe0f","\u25FC":"25fc","\u25FD\uFE0F":"25fd-fe0f","\u25FD":"25fd","\u25FE\uFE0F":"25fe-fe0f","\u25FE":"25fe","\u2600\uFE0F":"2600-fe0f","\u2600":"2600","\u2601\uFE0F":"2601-fe0f","\u2601":"2601","\u260E\uFE0F":"260e-fe0f","\u260E":"260e","\u2611\uFE0F":"2611-fe0f","\u2611":"2611","\u2614\uFE0F":"2614-fe0f","\u2614":"2614","\u2615\uFE0F":"2615-fe0f","\u2615":"2615","\u261D\uFE0F":"261d-fe0f","\u261D":"261d","\u263A\uFE0F":"263a-fe0f","\u263A":"263a","\u2648\uFE0F":"2648-fe0f","\u2648":"2648","\u2649\uFE0F":"2649-fe0f","\u2649":"2649","\u264A\uFE0F":"264a-fe0f","\u264A":"264a","\u264B\uFE0F":"264b-fe0f","\u264B":"264b","\u264C\uFE0F":"264c-fe0f","\u264C":"264c","\u264D\uFE0F":"264d-fe0f","\u264D":"264d","\u264E\uFE0F":"264e-fe0f","\u264E":"264e","\u264F\uFE0F":"264f-fe0f","\u264F":"264f","\u2650\uFE0F":"2650-fe0f","\u2650":"2650","\u2651\uFE0F":"2651-fe0f","\u2651":"2651","\u2652\uFE0F":"2652-fe0f","\u2652":"2652","\u2653\uFE0F":"2653-fe0f","\u2653":"2653","\u2660\uFE0F":"2660-fe0f","\u2660":"2660","\u2663\uFE0F":"2663-fe0f","\u2663":"2663","\u2665\uFE0F":"2665-fe0f","\u2665":"2665","\u2666\uFE0F":"2666-fe0f","\u2666":"2666","\u2668\uFE0F":"2668-fe0f","\u2668":"2668","\u267B\uFE0F":"267b-fe0f","\u267B":"267b","\u267F\uFE0F":"267f-fe0f","\u267F":"267f","\u2693\uFE0F":"2693-fe0f","\u2693":"2693","\u26A0\uFE0F":"26a0-fe0f","\u26A0":"26a0","\u26A1\uFE0F":"26a1-fe0f","\u26A1":"26a1","\u26AA\uFE0F":"26aa-fe0f","\u26AA":"26aa","\u26AB\uFE0F":"26ab-fe0f","\u26AB":"26ab","\u26BD\uFE0F":"26bd-fe0f","\u26BD":"26bd","\u26BE\uFE0F":"26be-fe0f","\u26BE":"26be","\u26C4\uFE0F":"26c4-fe0f","\u26C4":"26c4","\u26C5\uFE0F":"26c5-fe0f","\u26C5":"26c5","\u26D4\uFE0F":"26d4-fe0f","\u26D4":"26d4","\u26EA\uFE0F":"26ea-fe0f","\u26EA":"26ea","\u26F2\uFE0F":"26f2-fe0f","\u26F2":"26f2","\u26F3\uFE0F":"26f3-fe0f","\u26F3":"26f3","\u26F5\uFE0F":"26f5-fe0f","\u26F5":"26f5","\u26FA\uFE0F":"26fa-fe0f","\u26FA":"26fa","\u26FD\uFE0F":"26fd-fe0f","\u26FD":"26fd","\u2702\uFE0F":"2702-fe0f","\u2702":"2702","\u2708\uFE0F":"2708-fe0f","\u2708":"2708","\u2709\uFE0F":"2709-fe0f","\u2709":"2709","\u270C\uFE0F":"270c-fe0f","\u270C":"270c","\u270F\uFE0F":"270f-fe0f","\u270F":"270f","\u2712\uFE0F":"2712-fe0f","\u2712":"2712","\u2714\uFE0F":"2714-fe0f","\u2714":"2714","\u2716\uFE0F":"2716-fe0f","\u2716":"2716","\u2733\uFE0F":"2733-fe0f","\u2733":"2733","\u2734\uFE0F":"2734-fe0f","\u2734":"2734","\u2744\uFE0F":"2744-fe0f","\u2744":"2744","\u2747\uFE0F":"2747-fe0f","\u2747":"2747","\u2757\uFE0F":"2757-fe0f","\u2757":"2757","\u2764\uFE0F":"2764-fe0f","\u2764":"2764","\u27A1\uFE0F":"27a1-fe0f","\u27A1":"27a1","\u2934\uFE0F":"2934-fe0f","\u2934":"2934","\u2935\uFE0F":"2935-fe0f","\u2935":"2935","\u2B05\uFE0F":"2b05-fe0f","\u2B05":"2b05","\u2B06\uFE0F":"2b06-fe0f","\u2B06":"2b06","\u2B07\uFE0F":"2b07-fe0f","\u2B07":"2b07","\u2B1B\uFE0F":"2b1b-fe0f","\u2B1B":"2b1b","\u2B1C\uFE0F":"2b1c-fe0f","\u2B1C":"2b1c","\u2B50\uFE0F":"2b50-fe0f","\u2B50":"2b50","\u2B55\uFE0F":"2b55-fe0f","\u2B55":"2b55","\u3030\uFE0F":"3030-fe0f","\u3030":"3030","\u303D\uFE0F":"303d-fe0f","\u303D":"303d","\u3297\uFE0F":"3297-fe0f","\u3297":"3297","\u3299\uFE0F":"3299-fe0f","\u3299":"3299","\u271D\uFE0F":"271d-fe0f","\u271D":"271d","\u2328\uFE0F":"2328-fe0f","\u2328":"2328","\u270D\uFE0F":"270d-fe0f","\u270D":"270d","\u23CF\uFE0F":"23cf-fe0f","\u23CF":"23cf","\u23ED\uFE0F":"23ed-fe0f","\u23ED":"23ed","\u23EE\uFE0F":"23ee-fe0f","\u23EE":"23ee","\u23EF\uFE0F":"23ef-fe0f","\u23EF":"23ef","\u23F1\uFE0F":"23f1-fe0f","\u23F1":"23f1","\u23F2\uFE0F":"23f2-fe0f","\u23F2":"23f2","\u23F8\uFE0F":"23f8-fe0f","\u23F8":"23f8","\u23F9\uFE0F":"23f9-fe0f","\u23F9":"23f9","\u23FA\uFE0F":"23fa-fe0f","\u23FA":"23fa","\u2602\uFE0F":"2602-fe0f","\u2602":"2602","\u2603\uFE0F":"2603-fe0f","\u2603":"2603","\u2604\uFE0F":"2604-fe0f","\u2604":"2604","\u2618\uFE0F":"2618-fe0f","\u2618":"2618","\u2620\uFE0F":"2620-fe0f","\u2620":"2620","\u2622\uFE0F":"2622-fe0f","\u2622":"2622","\u2623\uFE0F":"2623-fe0f","\u2623":"2623","\u2626\uFE0F":"2626-fe0f","\u2626":"2626","\u262A\uFE0F":"262a-fe0f","\u262A":"262a","\u262E\uFE0F":"262e-fe0f","\u262E":"262e","\u262F\uFE0F":"262f-fe0f","\u262F":"262f","\u2638\uFE0F":"2638-fe0f","\u2638":"2638","\u2639\uFE0F":"2639-fe0f","\u2639":"2639","\u2692\uFE0F":"2692-fe0f","\u2692":"2692","\u2694\uFE0F":"2694-fe0f","\u2694":"2694","\u2696\uFE0F":"2696-fe0f","\u2696":"2696","\u2697\uFE0F":"2697-fe0f","\u2697":"2697","\u2699\uFE0F":"2699-fe0f","\u2699":"2699","\u269B\uFE0F":"269b-fe0f","\u269B":"269b","\u269C\uFE0F":"269c-fe0f","\u269C":"269c","\u26B0\uFE0F":"26b0-fe0f","\u26B0":"26b0","\u26B1\uFE0F":"26b1-fe0f","\u26B1":"26b1","\u26C8\uFE0F":"26c8-fe0f","\u26C8":"26c8","\u26CF\uFE0F":"26cf-fe0f","\u26CF":"26cf","\u26D1\uFE0F":"26d1-fe0f","\u26D1":"26d1","\u26D3\uFE0F":"26d3-fe0f","\u26D3":"26d3","\u26E9\uFE0F":"26e9-fe0f","\u26E9":"26e9","\u26F0\uFE0F":"26f0-fe0f","\u26F0":"26f0","\u26F1\uFE0F":"26f1-fe0f","\u26F1":"26f1","\u26F4\uFE0F":"26f4-fe0f","\u26F4":"26f4","\u26F7\uFE0F":"26f7-fe0f","\u26F7":"26f7","\u26F8\uFE0F":"26f8-fe0f","\u26F8":"26f8","\u26F9\uFE0F":"26f9-fe0f","\u26F9":"26f9","\u2721\uFE0F":"2721-fe0f","\u2721":"2721","\u2763\uFE0F":"2763-fe0f","\u2763":"2763","\uD83E\uDD49":"1f949","\uD83E\uDD48":"1f948","\uD83E\uDD47":"1f947","\uD83E\uDD3A":"1f93a","\uD83E\uDD45":"1f945","\uD83E\uDD3E":"1f93e","\uD83C\uDDFF":"1f1ff","\uD83E\uDD3D":"1f93d","\uD83E\uDD4B":"1f94b","\uD83E\uDD4A":"1f94a","\uD83E\uDD3C":"1f93c","\uD83E\uDD39":"1f939","\uD83E\uDD38":"1f938","\uD83D\uDEF6":"1f6f6","\uD83D\uDEF5":"1f6f5","\uD83D\uDEF4":"1f6f4","\uD83D\uDED2":"1f6d2","\uD83C\uDCCF":"1f0cf","\uD83C\uDD70":"1f170","\uD83C\uDD71":"1f171","\uD83C\uDD7E":"1f17e","\uD83D\uDED1":"1f6d1","\uD83C\uDD8E":"1f18e","\uD83C\uDD91":"1f191","\uD83C\uDDFE":"1f1fe","\uD83C\uDD92":"1f192","\uD83C\uDD93":"1f193","\uD83C\uDD94":"1f194","\uD83C\uDD95":"1f195","\uD83C\uDD96":"1f196","\uD83C\uDD97":"1f197","\uD83C\uDD98":"1f198","\uD83E\uDD44":"1f944","\uD83C\uDD99":"1f199","\uD83C\uDD9A":"1f19a","\uD83E\uDD42":"1f942","\uD83E\uDD43":"1f943","\uD83C\uDE01":"1f201","\uD83E\uDD59":"1f959","\uD83C\uDE32":"1f232","\uD83C\uDE33":"1f233","\uD83C\uDE34":"1f234","\uD83C\uDE35":"1f235","\uD83C\uDE36":"1f236","\uD83E\uDD58":"1f958","\uD83C\uDE38":"1f238","\uD83C\uDE39":"1f239","\uD83E\uDD57":"1f957","\uD83C\uDE3A":"1f23a","\uD83C\uDE50":"1f250","\uD83C\uDE51":"1f251","\uD83C\uDF00":"1f300","\uD83E\uDD56":"1f956","\uD83C\uDF01":"1f301","\uD83C\uDF02":"1f302","\uD83C\uDF03":"1f303","\uD83C\uDF04":"1f304","\uD83C\uDF05":"1f305","\uD83C\uDF06":"1f306","\uD83E\uDD55":"1f955","\uD83C\uDF07":"1f307","\uD83C\uDF08":"1f308","\uD83E\uDD54":"1f954","\uD83C\uDF09":"1f309","\uD83C\uDF0A":"1f30a","\uD83C\uDF0B":"1f30b","\uD83C\uDF0C":"1f30c","\uD83C\uDF0F":"1f30f","\uD83C\uDF11":"1f311","\uD83E\uDD53":"1f953","\uD83C\uDF13":"1f313","\uD83C\uDF14":"1f314","\uD83C\uDF15":"1f315","\uD83C\uDF19":"1f319","\uD83C\uDF1B":"1f31b","\uD83C\uDF1F":"1f31f","\uD83E\uDD52":"1f952","\uD83C\uDF20":"1f320","\uD83C\uDF30":"1f330","\uD83E\uDD51":"1f951","\uD83C\uDF31":"1f331","\uD83C\uDF34":"1f334","\uD83C\uDF35":"1f335","\uD83C\uDF37":"1f337","\uD83C\uDF38":"1f338","\uD83C\uDF39":"1f339","\uD83C\uDF3A":"1f33a","\uD83C\uDF3B":"1f33b","\uD83C\uDF3C":"1f33c","\uD83C\uDF3D":"1f33d","\uD83E\uDD50":"1f950","\uD83C\uDF3E":"1f33e","\uD83C\uDF3F":"1f33f","\uD83C\uDF40":"1f340","\uD83C\uDF41":"1f341","\uD83C\uDF42":"1f342","\uD83C\uDF43":"1f343","\uD83C\uDF44":"1f344","\uD83C\uDF45":"1f345","\uD83C\uDF46":"1f346","\uD83C\uDF47":"1f347","\uD83C\uDF48":"1f348","\uD83C\uDF49":"1f349","\uD83C\uDF4A":"1f34a","\uD83E\uDD40":"1f940","\uD83C\uDF4C":"1f34c","\uD83C\uDF4D":"1f34d","\uD83C\uDF4E":"1f34e","\uD83C\uDF4F":"1f34f","\uD83C\uDF51":"1f351","\uD83C\uDF52":"1f352","\uD83C\uDF53":"1f353","\uD83E\uDD8F":"1f98f","\uD83C\uDF54":"1f354","\uD83C\uDF55":"1f355","\uD83C\uDF56":"1f356","\uD83E\uDD8E":"1f98e","\uD83C\uDF57":"1f357","\uD83C\uDF58":"1f358","\uD83C\uDF59":"1f359","\uD83E\uDD8D":"1f98d","\uD83C\uDF5A":"1f35a","\uD83C\uDF5B":"1f35b","\uD83E\uDD8C":"1f98c","\uD83C\uDF5C":"1f35c","\uD83C\uDF5D":"1f35d","\uD83C\uDF5E":"1f35e","\uD83C\uDF5F":"1f35f","\uD83E\uDD8B":"1f98b","\uD83C\uDF60":"1f360","\uD83C\uDF61":"1f361","\uD83E\uDD8A":"1f98a","\uD83C\uDF62":"1f362","\uD83C\uDF63":"1f363","\uD83E\uDD89":"1f989","\uD83C\uDF64":"1f364","\uD83C\uDF65":"1f365","\uD83E\uDD88":"1f988","\uD83C\uDF66":"1f366","\uD83E\uDD87":"1f987","\uD83C\uDF67":"1f367","\uD83C\uDDFD":"1f1fd","\uD83C\uDF68":"1f368","\uD83E\uDD86":"1f986","\uD83C\uDF69":"1f369","\uD83E\uDD85":"1f985","\uD83C\uDF6A":"1f36a","\uD83D\uDDA4":"1f5a4","\uD83C\uDF6B":"1f36b","\uD83C\uDF6C":"1f36c","\uD83C\uDF6D":"1f36d","\uD83C\uDF6E":"1f36e","\uD83C\uDF6F":"1f36f","\uD83E\uDD1E":"1f91e","\uD83C\uDF70":"1f370","\uD83C\uDF71":"1f371","\uD83C\uDF72":"1f372","\uD83E\uDD1D":"1f91d","\uD83C\uDF73":"1f373","\uD83C\uDF74":"1f374","\uD83C\uDF75":"1f375","\uD83C\uDF76":"1f376","\uD83C\uDF77":"1f377","\uD83C\uDF78":"1f378","\uD83C\uDF79":"1f379","\uD83C\uDF7A":"1f37a","\uD83C\uDF7B":"1f37b","\uD83C\uDF80":"1f380","\uD83C\uDF81":"1f381","\uD83C\uDF82":"1f382","\uD83C\uDF83":"1f383","\uD83E\uDD1B":"1f91b","\uD83E\uDD1C":"1f91c","\uD83C\uDF84":"1f384","\uD83C\uDF85":"1f385","\uD83C\uDF86":"1f386","\uD83E\uDD1A":"1f91a","\uD83C\uDF87":"1f387","\uD83C\uDF88":"1f388","\uD83C\uDF89":"1f389","\uD83C\uDF8A":"1f38a","\uD83C\uDF8B":"1f38b","\uD83C\uDF8C":"1f38c","\uD83E\uDD19":"1f919","\uD83C\uDF8D":"1f38d","\uD83D\uDD7A":"1f57a","\uD83C\uDF8E":"1f38e","\uD83E\uDD33":"1f933","\uD83C\uDF8F":"1f38f","\uD83E\uDD30":"1f930","\uD83C\uDF90":"1f390","\uD83E\uDD26":"1f926","\uD83E\uDD37":"1f937","\uD83C\uDF91":"1f391","\uD83C\uDF92":"1f392","\uD83C\uDF93":"1f393","\uD83C\uDFA0":"1f3a0","\uD83C\uDFA1":"1f3a1","\uD83C\uDFA2":"1f3a2","\uD83C\uDFA3":"1f3a3","\uD83C\uDFA4":"1f3a4","\uD83C\uDFA5":"1f3a5","\uD83C\uDFA6":"1f3a6","\uD83C\uDFA7":"1f3a7","\uD83E\uDD36":"1f936","\uD83C\uDFA8":"1f3a8","\uD83E\uDD35":"1f935","\uD83C\uDFA9":"1f3a9","\uD83C\uDFAA":"1f3aa","\uD83E\uDD34":"1f934","\uD83C\uDFAB":"1f3ab","\uD83C\uDFAC":"1f3ac","\uD83C\uDFAD":"1f3ad","\uD83E\uDD27":"1f927","\uD83C\uDFAE":"1f3ae","\uD83C\uDFAF":"1f3af","\uD83C\uDFB0":"1f3b0","\uD83C\uDFB1":"1f3b1","\uD83C\uDFB2":"1f3b2","\uD83C\uDFB3":"1f3b3","\uD83C\uDFB4":"1f3b4","\uD83E\uDD25":"1f925","\uD83C\uDFB5":"1f3b5","\uD83C\uDFB6":"1f3b6","\uD83C\uDFB7":"1f3b7","\uD83E\uDD24":"1f924","\uD83C\uDFB8":"1f3b8","\uD83C\uDFB9":"1f3b9","\uD83C\uDFBA":"1f3ba","\uD83E\uDD23":"1f923","\uD83C\uDFBB":"1f3bb","\uD83C\uDFBC":"1f3bc","\uD83C\uDFBD":"1f3bd","\uD83E\uDD22":"1f922","\uD83C\uDFBE":"1f3be","\uD83C\uDFBF":"1f3bf","\uD83C\uDFC0":"1f3c0","\uD83C\uDFC1":"1f3c1","\uD83E\uDD21":"1f921","\uD83C\uDFC2":"1f3c2","\uD83C\uDFC3":"1f3c3","\uD83C\uDFC4":"1f3c4","\uD83C\uDFC6":"1f3c6","\uD83C\uDFC8":"1f3c8","\uD83C\uDFCA":"1f3ca","\uD83C\uDFE0":"1f3e0","\uD83C\uDFE1":"1f3e1","\uD83C\uDFE2":"1f3e2","\uD83C\uDFE3":"1f3e3","\uD83C\uDFE5":"1f3e5","\uD83C\uDFE6":"1f3e6","\uD83C\uDFE7":"1f3e7","\uD83C\uDFE8":"1f3e8","\uD83C\uDFE9":"1f3e9","\uD83C\uDFEA":"1f3ea","\uD83C\uDFEB":"1f3eb","\uD83C\uDFEC":"1f3ec","\uD83E\uDD20":"1f920","\uD83C\uDFED":"1f3ed","\uD83C\uDFEE":"1f3ee","\uD83C\uDFEF":"1f3ef","\uD83C\uDFF0":"1f3f0","\uD83D\uDC0C":"1f40c","\uD83D\uDC0D":"1f40d","\uD83D\uDC0E":"1f40e","\uD83D\uDC11":"1f411","\uD83D\uDC12":"1f412","\uD83D\uDC14":"1f414","\uD83D\uDC17":"1f417","\uD83D\uDC18":"1f418","\uD83D\uDC19":"1f419","\uD83D\uDC1A":"1f41a","\uD83D\uDC1B":"1f41b","\uD83D\uDC1C":"1f41c","\uD83D\uDC1D":"1f41d","\uD83D\uDC1E":"1f41e","\uD83D\uDC1F":"1f41f","\uD83D\uDC20":"1f420","\uD83D\uDC21":"1f421","\uD83D\uDC22":"1f422","\uD83D\uDC23":"1f423","\uD83D\uDC24":"1f424","\uD83D\uDC25":"1f425","\uD83D\uDC26":"1f426","\uD83D\uDC27":"1f427","\uD83D\uDC28":"1f428","\uD83D\uDC29":"1f429","\uD83D\uDC2B":"1f42b","\uD83D\uDC2C":"1f42c","\uD83D\uDC2D":"1f42d","\uD83D\uDC2E":"1f42e","\uD83D\uDC2F":"1f42f","\uD83D\uDC30":"1f430","\uD83D\uDC31":"1f431","\uD83D\uDC32":"1f432","\uD83D\uDC33":"1f433","\uD83D\uDC34":"1f434","\uD83D\uDC35":"1f435","\uD83D\uDC36":"1f436","\uD83D\uDC37":"1f437","\uD83D\uDC38":"1f438","\uD83D\uDC39":"1f439","\uD83D\uDC3A":"1f43a","\uD83D\uDC3B":"1f43b","\uD83D\uDC3C":"1f43c","\uD83D\uDC3D":"1f43d","\uD83D\uDC3E":"1f43e","\uD83D\uDC40":"1f440","\uD83D\uDC42":"1f442","\uD83D\uDC43":"1f443","\uD83D\uDC44":"1f444","\uD83D\uDC45":"1f445","\uD83D\uDC46":"1f446","\uD83D\uDC47":"1f447","\uD83D\uDC48":"1f448","\uD83D\uDC49":"1f449","\uD83D\uDC4A":"1f44a","\uD83D\uDC4B":"1f44b","\uD83D\uDC4C":"1f44c","\uD83D\uDC4D":"1f44d","\uD83D\uDC4E":"1f44e","\uD83D\uDC4F":"1f44f","\uD83D\uDC50":"1f450","\uD83D\uDC51":"1f451","\uD83D\uDC52":"1f452","\uD83D\uDC53":"1f453","\uD83D\uDC54":"1f454","\uD83D\uDC55":"1f455","\uD83D\uDC56":"1f456","\uD83D\uDC57":"1f457","\uD83D\uDC58":"1f458","\uD83D\uDC59":"1f459","\uD83D\uDC5A":"1f45a","\uD83D\uDC5B":"1f45b","\uD83D\uDC5C":"1f45c","\uD83D\uDC5D":"1f45d","\uD83D\uDC5E":"1f45e","\uD83D\uDC5F":"1f45f","\uD83D\uDC60":"1f460","\uD83D\uDC61":"1f461","\uD83D\uDC62":"1f462","\uD83D\uDC63":"1f463","\uD83D\uDC64":"1f464","\uD83D\uDC66":"1f466","\uD83D\uDC67":"1f467","\uD83D\uDC68":"1f468","\uD83D\uDC69":"1f469","\uD83D\uDC6A":"1f46a","\uD83D\uDC6B":"1f46b","\uD83D\uDC6E":"1f46e","\uD83D\uDC6F":"1f46f","\uD83D\uDC70":"1f470","\uD83D\uDC71":"1f471","\uD83D\uDC72":"1f472","\uD83D\uDC73":"1f473","\uD83D\uDC74":"1f474","\uD83D\uDC75":"1f475","\uD83D\uDC76":"1f476","\uD83D\uDC77":"1f477","\uD83D\uDC78":"1f478","\uD83D\uDC79":"1f479","\uD83D\uDC7A":"1f47a","\uD83D\uDC7B":"1f47b","\uD83D\uDC7C":"1f47c","\uD83D\uDC7D":"1f47d","\uD83D\uDC7E":"1f47e","\uD83D\uDC7F":"1f47f","\uD83D\uDC80":"1f480","\uD83D\uDCC7":"1f4c7","\uD83D\uDC81":"1f481","\uD83D\uDC82":"1f482","\uD83D\uDC83":"1f483","\uD83D\uDC84":"1f484","\uD83D\uDC85":"1f485","\uD83D\uDCD2":"1f4d2","\uD83D\uDC86":"1f486","\uD83D\uDCD3":"1f4d3","\uD83D\uDC87":"1f487","\uD83D\uDCD4":"1f4d4","\uD83D\uDC88":"1f488","\uD83D\uDCD5":"1f4d5","\uD83D\uDC89":"1f489","\uD83D\uDCD6":"1f4d6","\uD83D\uDC8A":"1f48a","\uD83D\uDCD7":"1f4d7","\uD83D\uDC8B":"1f48b","\uD83D\uDCD8":"1f4d8","\uD83D\uDC8C":"1f48c","\uD83D\uDCD9":"1f4d9","\uD83D\uDC8D":"1f48d","\uD83D\uDCDA":"1f4da","\uD83D\uDC8E":"1f48e","\uD83D\uDCDB":"1f4db","\uD83D\uDC8F":"1f48f","\uD83D\uDCDC":"1f4dc","\uD83D\uDC90":"1f490","\uD83D\uDCDD":"1f4dd","\uD83D\uDC91":"1f491","\uD83D\uDCDE":"1f4de","\uD83D\uDC92":"1f492","\uD83D\uDCDF":"1f4df","\uD83D\uDCE0":"1f4e0","\uD83D\uDC93":"1f493","\uD83D\uDCE1":"1f4e1","\uD83D\uDCE2":"1f4e2","\uD83D\uDC94":"1f494","\uD83D\uDCE3":"1f4e3","\uD83D\uDCE4":"1f4e4","\uD83D\uDC95":"1f495","\uD83D\uDCE5":"1f4e5","\uD83D\uDCE6":"1f4e6","\uD83D\uDC96":"1f496","\uD83D\uDCE7":"1f4e7","\uD83D\uDCE8":"1f4e8","\uD83D\uDC97":"1f497","\uD83D\uDCE9":"1f4e9","\uD83D\uDCEA":"1f4ea","\uD83D\uDC98":"1f498","\uD83D\uDCEB":"1f4eb","\uD83D\uDCEE":"1f4ee","\uD83D\uDC99":"1f499","\uD83D\uDCF0":"1f4f0","\uD83D\uDCF1":"1f4f1","\uD83D\uDC9A":"1f49a","\uD83D\uDCF2":"1f4f2","\uD83D\uDCF3":"1f4f3","\uD83D\uDC9B":"1f49b","\uD83D\uDCF4":"1f4f4","\uD83D\uDCF6":"1f4f6","\uD83D\uDC9C":"1f49c","\uD83D\uDCF7":"1f4f7","\uD83D\uDCF9":"1f4f9","\uD83D\uDC9D":"1f49d","\uD83D\uDCFA":"1f4fa","\uD83D\uDCFB":"1f4fb","\uD83D\uDC9E":"1f49e","\uD83D\uDCFC":"1f4fc","\uD83D\uDD03":"1f503","\uD83D\uDC9F":"1f49f","\uD83D\uDD0A":"1f50a","\uD83D\uDD0B":"1f50b","\uD83D\uDCA0":"1f4a0","\uD83D\uDD0C":"1f50c","\uD83D\uDD0D":"1f50d","\uD83D\uDCA1":"1f4a1","\uD83D\uDD0E":"1f50e","\uD83D\uDD0F":"1f50f","\uD83D\uDCA2":"1f4a2","\uD83D\uDD10":"1f510","\uD83D\uDD11":"1f511","\uD83D\uDCA3":"1f4a3","\uD83D\uDD12":"1f512","\uD83D\uDD13":"1f513","\uD83D\uDCA4":"1f4a4","\uD83D\uDD14":"1f514","\uD83D\uDD16":"1f516","\uD83D\uDCA5":"1f4a5","\uD83D\uDD17":"1f517","\uD83D\uDD18":"1f518","\uD83D\uDCA6":"1f4a6","\uD83D\uDD19":"1f519","\uD83D\uDD1A":"1f51a","\uD83D\uDCA7":"1f4a7","\uD83D\uDD1B":"1f51b","\uD83D\uDD1C":"1f51c","\uD83D\uDCA8":"1f4a8","\uD83D\uDD1D":"1f51d","\uD83D\uDD1E":"1f51e","\uD83D\uDCA9":"1f4a9","\uD83D\uDD1F":"1f51f","\uD83D\uDCAA":"1f4aa","\uD83D\uDD20":"1f520","\uD83D\uDD21":"1f521","\uD83D\uDCAB":"1f4ab","\uD83D\uDD22":"1f522","\uD83D\uDD23":"1f523","\uD83D\uDCAC":"1f4ac","\uD83D\uDD24":"1f524","\uD83D\uDD25":"1f525","\uD83D\uDCAE":"1f4ae","\uD83D\uDD26":"1f526","\uD83D\uDD27":"1f527","\uD83D\uDCAF":"1f4af","\uD83D\uDD28":"1f528","\uD83D\uDD29":"1f529","\uD83D\uDCB0":"1f4b0","\uD83D\uDD2A":"1f52a","\uD83D\uDD2B":"1f52b","\uD83D\uDCB1":"1f4b1","\uD83D\uDD2E":"1f52e","\uD83D\uDCB2":"1f4b2","\uD83D\uDD2F":"1f52f","\uD83D\uDCB3":"1f4b3","\uD83D\uDD30":"1f530","\uD83D\uDD31":"1f531","\uD83D\uDCB4":"1f4b4","\uD83D\uDD32":"1f532","\uD83D\uDD33":"1f533","\uD83D\uDCB5":"1f4b5","\uD83D\uDD34":"1f534","\uD83D\uDD35":"1f535","\uD83D\uDCB8":"1f4b8","\uD83D\uDD36":"1f536","\uD83D\uDD37":"1f537","\uD83D\uDCB9":"1f4b9","\uD83D\uDD38":"1f538","\uD83D\uDD39":"1f539","\uD83D\uDCBA":"1f4ba","\uD83D\uDD3A":"1f53a","\uD83D\uDD3B":"1f53b","\uD83D\uDCBB":"1f4bb","\uD83D\uDD3C":"1f53c","\uD83D\uDCBC":"1f4bc","\uD83D\uDD3D":"1f53d","\uD83D\uDD50":"1f550","\uD83D\uDCBD":"1f4bd","\uD83D\uDD51":"1f551","\uD83D\uDCBE":"1f4be","\uD83D\uDD52":"1f552","\uD83D\uDCBF":"1f4bf","\uD83D\uDD53":"1f553","\uD83D\uDCC0":"1f4c0","\uD83D\uDD54":"1f554","\uD83D\uDD55":"1f555","\uD83D\uDCC1":"1f4c1","\uD83D\uDD56":"1f556","\uD83D\uDD57":"1f557","\uD83D\uDCC2":"1f4c2","\uD83D\uDD58":"1f558","\uD83D\uDD59":"1f559","\uD83D\uDCC3":"1f4c3","\uD83D\uDD5A":"1f55a","\uD83D\uDD5B":"1f55b","\uD83D\uDCC4":"1f4c4","\uD83D\uDDFB":"1f5fb","\uD83D\uDDFC":"1f5fc","\uD83D\uDCC5":"1f4c5","\uD83D\uDDFD":"1f5fd","\uD83D\uDDFE":"1f5fe","\uD83D\uDCC6":"1f4c6","\uD83D\uDDFF":"1f5ff","\uD83D\uDE01":"1f601","\uD83D\uDE02":"1f602","\uD83D\uDE03":"1f603","\uD83D\uDCC8":"1f4c8","\uD83D\uDE04":"1f604","\uD83D\uDE05":"1f605","\uD83D\uDCC9":"1f4c9","\uD83D\uDE06":"1f606","\uD83D\uDE09":"1f609","\uD83D\uDCCA":"1f4ca","\uD83D\uDE0A":"1f60a","\uD83D\uDE0B":"1f60b","\uD83D\uDCCB":"1f4cb","\uD83D\uDE0C":"1f60c","\uD83D\uDE0D":"1f60d","\uD83D\uDCCC":"1f4cc","\uD83D\uDE0F":"1f60f","\uD83D\uDE12":"1f612","\uD83D\uDCCD":"1f4cd","\uD83D\uDE13":"1f613","\uD83D\uDE14":"1f614","\uD83D\uDCCE":"1f4ce","\uD83D\uDE16":"1f616","\uD83D\uDE18":"1f618","\uD83D\uDCCF":"1f4cf","\uD83D\uDE1A":"1f61a","\uD83D\uDE1C":"1f61c","\uD83D\uDCD0":"1f4d0","\uD83D\uDE1D":"1f61d","\uD83D\uDE1E":"1f61e","\uD83D\uDCD1":"1f4d1","\uD83D\uDE20":"1f620","\uD83D\uDE21":"1f621","\uD83D\uDE22":"1f622","\uD83D\uDE23":"1f623","\uD83D\uDE24":"1f624","\uD83D\uDE25":"1f625","\uD83D\uDE28":"1f628","\uD83D\uDE29":"1f629","\uD83D\uDE2A":"1f62a","\uD83D\uDE2B":"1f62b","\uD83D\uDE2D":"1f62d","\uD83D\uDE30":"1f630","\uD83D\uDE31":"1f631","\uD83D\uDE32":"1f632","\uD83D\uDE33":"1f633","\uD83D\uDE35":"1f635","\uD83D\uDE37":"1f637","\uD83D\uDE38":"1f638","\uD83D\uDE39":"1f639","\uD83D\uDE3A":"1f63a","\uD83D\uDE3B":"1f63b","\uD83D\uDE3C":"1f63c","\uD83D\uDE3D":"1f63d","\uD83D\uDE3E":"1f63e","\uD83D\uDE3F":"1f63f","\uD83D\uDE40":"1f640","\uD83D\uDE45":"1f645","\uD83D\uDE46":"1f646","\uD83D\uDE47":"1f647","\uD83D\uDE48":"1f648","\uD83D\uDE49":"1f649","\uD83D\uDE4A":"1f64a","\uD83D\uDE4B":"1f64b","\uD83D\uDE4C":"1f64c","\uD83D\uDE4D":"1f64d","\uD83D\uDE4E":"1f64e","\uD83D\uDE4F":"1f64f","\uD83D\uDE80":"1f680","\uD83D\uDE83":"1f683","\uD83D\uDE84":"1f684","\uD83D\uDE85":"1f685","\uD83D\uDE87":"1f687","\uD83D\uDE89":"1f689","\uD83D\uDE8C":"1f68c","\uD83D\uDE8F":"1f68f","\uD83D\uDE91":"1f691","\uD83D\uDE92":"1f692","\uD83D\uDE93":"1f693","\uD83D\uDE95":"1f695","\uD83D\uDE97":"1f697","\uD83D\uDE99":"1f699","\uD83D\uDE9A":"1f69a","\uD83D\uDEA2":"1f6a2","\uD83D\uDEA4":"1f6a4","\uD83D\uDEA5":"1f6a5","\uD83D\uDEA7":"1f6a7","\uD83D\uDEA8":"1f6a8","\uD83D\uDEA9":"1f6a9","\uD83D\uDEAA":"1f6aa","\uD83D\uDEAB":"1f6ab","\uD83D\uDEAC":"1f6ac","\uD83D\uDEAD":"1f6ad","\uD83D\uDEB2":"1f6b2","\uD83D\uDEB6":"1f6b6","\uD83D\uDEB9":"1f6b9","\uD83D\uDEBA":"1f6ba","\uD83D\uDEBB":"1f6bb","\uD83D\uDEBC":"1f6bc","\uD83D\uDEBD":"1f6bd","\uD83D\uDEBE":"1f6be","\uD83D\uDEC0":"1f6c0","\uD83E\uDD18":"1f918","\uD83D\uDE00":"1f600","\uD83D\uDE07":"1f607","\uD83D\uDE08":"1f608","\uD83D\uDE0E":"1f60e","\uD83D\uDE10":"1f610","\uD83D\uDE11":"1f611","\uD83D\uDE15":"1f615","\uD83D\uDE17":"1f617","\uD83D\uDE19":"1f619","\uD83D\uDE1B":"1f61b","\uD83D\uDE1F":"1f61f","\uD83D\uDE26":"1f626","\uD83D\uDE27":"1f627","\uD83D\uDE2C":"1f62c","\uD83D\uDE2E":"1f62e","\uD83D\uDE2F":"1f62f","\uD83D\uDE34":"1f634","\uD83D\uDE36":"1f636","\uD83D\uDE81":"1f681","\uD83D\uDE82":"1f682","\uD83D\uDE86":"1f686","\uD83D\uDE88":"1f688","\uD83D\uDE8A":"1f68a","\uD83D\uDE8D":"1f68d","\uD83D\uDE8E":"1f68e","\uD83D\uDE90":"1f690","\uD83D\uDE94":"1f694","\uD83D\uDE96":"1f696","\uD83D\uDE98":"1f698","\uD83D\uDE9B":"1f69b","\uD83D\uDE9C":"1f69c","\uD83D\uDE9D":"1f69d","\uD83D\uDE9E":"1f69e","\uD83D\uDE9F":"1f69f","\uD83D\uDEA0":"1f6a0","\uD83D\uDEA1":"1f6a1","\uD83D\uDEA3":"1f6a3","\uD83D\uDEA6":"1f6a6","\uD83D\uDEAE":"1f6ae","\uD83D\uDEAF":"1f6af","\uD83D\uDEB0":"1f6b0","\uD83D\uDEB1":"1f6b1","\uD83D\uDEB3":"1f6b3","\uD83D\uDEB4":"1f6b4","\uD83D\uDEB5":"1f6b5","\uD83D\uDEB7":"1f6b7","\uD83D\uDEB8":"1f6b8","\uD83D\uDEBF":"1f6bf","\uD83D\uDEC1":"1f6c1","\uD83D\uDEC2":"1f6c2","\uD83D\uDEC3":"1f6c3","\uD83D\uDEC4":"1f6c4","\uD83D\uDEC5":"1f6c5","\uD83C\uDF0D":"1f30d","\uD83C\uDF0E":"1f30e","\uD83C\uDF10":"1f310","\uD83C\uDF12":"1f312","\uD83C\uDF16":"1f316","\uD83C\uDF17":"1f317","\uD83C\uDF18":"1f318","\uD83C\uDF1A":"1f31a","\uD83C\uDF1C":"1f31c","\uD83C\uDF1D":"1f31d","\uD83C\uDF1E":"1f31e","\uD83C\uDF32":"1f332","\uD83C\uDF33":"1f333","\uD83C\uDF4B":"1f34b","\uD83C\uDF50":"1f350","\uD83C\uDF7C":"1f37c","\uD83C\uDFC7":"1f3c7","\uD83C\uDFC9":"1f3c9","\uD83C\uDFE4":"1f3e4","\uD83D\uDC00":"1f400","\uD83D\uDC01":"1f401","\uD83D\uDC02":"1f402","\uD83D\uDC03":"1f403","\uD83D\uDC04":"1f404","\uD83D\uDC05":"1f405","\uD83D\uDC06":"1f406","\uD83D\uDC07":"1f407","\uD83D\uDC08":"1f408","\uD83D\uDC09":"1f409","\uD83D\uDC0A":"1f40a","\uD83D\uDC0B":"1f40b","\uD83D\uDC0F":"1f40f","\uD83D\uDC10":"1f410","\uD83D\uDC13":"1f413","\uD83D\uDC15":"1f415","\uD83D\uDC16":"1f416","\uD83D\uDC2A":"1f42a","\uD83D\uDC65":"1f465","\uD83D\uDC6C":"1f46c","\uD83D\uDC6D":"1f46d","\uD83D\uDCAD":"1f4ad","\uD83D\uDCB6":"1f4b6","\uD83D\uDCB7":"1f4b7","\uD83D\uDCEC":"1f4ec","\uD83D\uDCED":"1f4ed","\uD83D\uDCEF":"1f4ef","\uD83D\uDCF5":"1f4f5","\uD83D\uDD00":"1f500","\uD83D\uDD01":"1f501","\uD83D\uDD02":"1f502","\uD83D\uDD04":"1f504","\uD83D\uDD05":"1f505","\uD83D\uDD06":"1f506","\uD83D\uDD07":"1f507","\uD83D\uDD09":"1f509","\uD83D\uDD15":"1f515","\uD83D\uDD2C":"1f52c","\uD83D\uDD2D":"1f52d","\uD83D\uDD5C":"1f55c","\uD83D\uDD5D":"1f55d","\uD83D\uDD5E":"1f55e","\uD83D\uDD5F":"1f55f","\uD83D\uDD60":"1f560","\uD83D\uDD61":"1f561","\uD83D\uDD62":"1f562","\uD83D\uDD63":"1f563","\uD83D\uDD64":"1f564","\uD83D\uDD65":"1f565","\uD83D\uDD66":"1f566","\uD83D\uDD67":"1f567","\uD83D\uDD08":"1f508","\uD83D\uDE8B":"1f68b","\uD83C\uDFC5":"1f3c5","\uD83C\uDFF4":"1f3f4","\uD83D\uDCF8":"1f4f8","\uD83D\uDECC":"1f6cc","\uD83D\uDD95":"1f595","\uD83D\uDD96":"1f596","\uD83D\uDE41":"1f641","\uD83D\uDE42":"1f642","\uD83D\uDEEB":"1f6eb","\uD83D\uDEEC":"1f6ec","\uD83C\uDFFB":"1f3fb","\uD83C\uDFFC":"1f3fc","\uD83C\uDFFD":"1f3fd","\uD83C\uDFFE":"1f3fe","\uD83C\uDFFF":"1f3ff","\uD83D\uDE43":"1f643","\uD83E\uDD11":"1f911","\uD83E\uDD13":"1f913","\uD83E\uDD17":"1f917","\uD83D\uDE44":"1f644","\uD83E\uDD14":"1f914","\uD83E\uDD10":"1f910","\uD83E\uDD12":"1f912","\uD83E\uDD15":"1f915","\uD83E\uDD16":"1f916","\uD83E\uDD81":"1f981","\uD83E\uDD84":"1f984","\uD83E\uDD82":"1f982","\uD83E\uDD80":"1f980","\uD83E\uDD83":"1f983","\uD83E\uDDC0":"1f9c0","\uD83C\uDF2D":"1f32d","\uD83C\uDF2E":"1f32e","\uD83C\uDF2F":"1f32f","\uD83C\uDF7F":"1f37f","\uD83C\uDF7E":"1f37e","\uD83C\uDFF9":"1f3f9","\uD83C\uDFFA":"1f3fa","\uD83D\uDED0":"1f6d0","\uD83D\uDD4B":"1f54b","\uD83D\uDD4C":"1f54c","\uD83D\uDD4D":"1f54d","\uD83D\uDD4E":"1f54e","\uD83D\uDCFF":"1f4ff","\uD83C\uDFCF":"1f3cf","\uD83C\uDFD0":"1f3d0","\uD83C\uDFD1":"1f3d1","\uD83C\uDFD2":"1f3d2","\uD83C\uDFD3":"1f3d3","\uD83C\uDFF8":"1f3f8","\uD83E\uDD41":"1f941","\uD83E\uDD90":"1f990","\uD83E\uDD91":"1f991","\uD83E\uDD5A":"1f95a","\uD83E\uDD5B":"1f95b","\uD83E\uDD5C":"1f95c","\uD83E\uDD5D":"1f95d","\uD83E\uDD5E":"1f95e","\uD83C\uDDFC":"1f1fc","\uD83C\uDDFB":"1f1fb","\uD83C\uDDFA":"1f1fa","\uD83C\uDDF9":"1f1f9","\uD83C\uDDF8":"1f1f8","\uD83C\uDDF7":"1f1f7","\uD83C\uDDF6":"1f1f6","\uD83C\uDDF5":"1f1f5","\uD83C\uDDF4":"1f1f4","\uD83C\uDDF3":"1f1f3","\uD83C\uDDF2":"1f1f2","\uD83C\uDDF1":"1f1f1","\uD83C\uDDF0":"1f1f0","\uD83C\uDDEF":"1f1ef","\uD83C\uDDEE":"1f1ee","\uD83C\uDDED":"1f1ed","\uD83C\uDDEC":"1f1ec","\uD83C\uDDEB":"1f1eb","\uD83C\uDDEA":"1f1ea","\uD83C\uDDE9":"1f1e9","\uD83C\uDDE8":"1f1e8","\uD83C\uDDE7":"1f1e7","\uD83C\uDDE6":"1f1e6","\u23E9":"23e9","\u23EA":"23ea","\u23EB":"23eb","\u23EC":"23ec","\u23F0":"23f0","\u23F3":"23f3","\u26CE":"26ce","\u2705":"2705","\u270A":"270a","\u270B":"270b","\u2728":"2728","\u274C":"274c","\u274E":"274e","\u2753":"2753","\u2754":"2754","\u2755":"2755","\u2795":"2795","\u2796":"2796","\u2797":"2797","\u27B0":"27b0","\u27BF":"27bf","\u00A9":"00a9","\u00AE":"00ae","\u203C":"203c","\u2049":"2049","\u2122":"2122","\u2139":"2139","\u2194":"2194","\u2195":"2195","\u2196":"2196","\u2197":"2197","\u2198":"2198","\u2199":"2199","\u21A9":"21a9","\u21AA":"21aa","\u231A":"231a","\u231B":"231b","\u24C2":"24c2","\u25AA":"25aa","\u25AB":"25ab","\u25B6":"25b6","\u25C0":"25c0","\u25FB":"25fb","\u25FC":"25fc","\u25FD":"25fd","\u25FE":"25fe","\u2600":"2600","\u2601":"2601","\u260E":"260e","\u2611":"2611","\u2614":"2614","\u2615":"2615","\u261D":"261d","\u263A":"263a","\u2648":"2648","\u2649":"2649","\u264A":"264a","\u264B":"264b","\u264C":"264c","\u264D":"264d","\u264E":"264e","\u264F":"264f","\u2650":"2650","\u2651":"2651","\u2652":"2652","\u2653":"2653","\u2660":"2660","\u2663":"2663","\u2665":"2665","\u2666":"2666","\u2668":"2668","\u267B":"267b","\u267F":"267f","\u2693":"2693","\u26A0":"26a0","\u26A1":"26a1","\u26AA":"26aa","\u26AB":"26ab","\u26BD":"26bd","\u26BE":"26be","\u26C4":"26c4","\u26C5":"26c5","\u26D4":"26d4","\u26EA":"26ea","\u26F2":"26f2","\u26F3":"26f3","\u26F5":"26f5","\u26FA":"26fa","\u26FD":"26fd","\u2702":"2702","\u2708":"2708","\u2709":"2709","\u270C":"270c","\u270F":"270f","\u2712":"2712","\u2714":"2714","\u2716":"2716","\u2733":"2733","\u2734":"2734","\u2744":"2744","\u2747":"2747","\u2757":"2757","\u2764":"2764","\u27A1":"27a1","\u2934":"2934","\u2935":"2935","\u2B05":"2b05","\u2B06":"2b06","\u2B07":"2b07","\u2B1B":"2b1b","\u2B1C":"2b1c","\u2B50":"2b50","\u2B55":"2b55","\u3030":"3030","\u303D":"303d","\u3297":"3297","\u3299":"3299","\uD83C\uDC04":"1f004","\uD83C\uDD7F":"1f17f","\uD83C\uDE02":"1f202","\uD83C\uDE1A":"1f21a","\uD83C\uDE2F":"1f22f","\uD83C\uDE37":"1f237","\uD83C\uDF9E":"1f39e","\uD83C\uDF9F":"1f39f","\uD83C\uDFCB":"1f3cb","\uD83C\uDFCC":"1f3cc","\uD83C\uDFCD":"1f3cd","\uD83C\uDFCE":"1f3ce","\uD83C\uDF96":"1f396","\uD83C\uDF97":"1f397","\uD83C\uDF36":"1f336","\uD83C\uDF27":"1f327","\uD83C\uDF28":"1f328","\uD83C\uDF29":"1f329","\uD83C\uDF2A":"1f32a","\uD83C\uDF2B":"1f32b","\uD83C\uDF2C":"1f32c","\uD83D\uDC3F":"1f43f","\uD83D\uDD77":"1f577","\uD83D\uDD78":"1f578","\uD83C\uDF21":"1f321","\uD83C\uDF99":"1f399","\uD83C\uDF9A":"1f39a","\uD83C\uDF9B":"1f39b","\uD83C\uDFF3":"1f3f3","\uD83C\uDFF5":"1f3f5","\uD83C\uDFF7":"1f3f7","\uD83D\uDCFD":"1f4fd","\u271D":"271d","\uD83D\uDD49":"1f549","\uD83D\uDD4A":"1f54a","\uD83D\uDD6F":"1f56f","\uD83D\uDD70":"1f570","\uD83D\uDD73":"1f573","\uD83D\uDD76":"1f576","\uD83D\uDD79":"1f579","\uD83D\uDD87":"1f587","\uD83D\uDD8A":"1f58a","\uD83D\uDD8B":"1f58b","\uD83D\uDD8C":"1f58c","\uD83D\uDD8D":"1f58d","\uD83D\uDDA5":"1f5a5","\uD83D\uDDA8":"1f5a8","\u2328":"2328","\uD83D\uDDB2":"1f5b2","\uD83D\uDDBC":"1f5bc","\uD83D\uDDC2":"1f5c2","\uD83D\uDDC3":"1f5c3","\uD83D\uDDC4":"1f5c4","\uD83D\uDDD1":"1f5d1","\uD83D\uDDD2":"1f5d2","\uD83D\uDDD3":"1f5d3","\uD83D\uDDDC":"1f5dc","\uD83D\uDDDD":"1f5dd","\uD83D\uDDDE":"1f5de","\uD83D\uDDE1":"1f5e1","\uD83D\uDDE3":"1f5e3","\uD83D\uDDE8":"1f5e8","\uD83D\uDDEF":"1f5ef","\uD83D\uDDF3":"1f5f3","\uD83D\uDDFA":"1f5fa","\uD83D\uDEE0":"1f6e0","\uD83D\uDEE1":"1f6e1","\uD83D\uDEE2":"1f6e2","\uD83D\uDEF0":"1f6f0","\uD83C\uDF7D":"1f37d","\uD83D\uDC41":"1f441","\uD83D\uDD74":"1f574","\uD83D\uDD75":"1f575","\u270D":"270d","\uD83D\uDD90":"1f590","\uD83C\uDFD4":"1f3d4","\uD83C\uDFD5":"1f3d5","\uD83C\uDFD6":"1f3d6","\uD83C\uDFD7":"1f3d7","\uD83C\uDFD8":"1f3d8","\uD83C\uDFD9":"1f3d9","\uD83C\uDFDA":"1f3da","\uD83C\uDFDB":"1f3db","\uD83C\uDFDC":"1f3dc","\uD83C\uDFDD":"1f3dd","\uD83C\uDFDE":"1f3de","\uD83C\uDFDF":"1f3df","\uD83D\uDECB":"1f6cb","\uD83D\uDECD":"1f6cd","\uD83D\uDECE":"1f6ce","\uD83D\uDECF":"1f6cf","\uD83D\uDEE3":"1f6e3","\uD83D\uDEE4":"1f6e4","\uD83D\uDEE5":"1f6e5","\uD83D\uDEE9":"1f6e9","\uD83D\uDEF3":"1f6f3","\u23CF":"23cf","\u23ED":"23ed","\u23EE":"23ee","\u23EF":"23ef","\u23F1":"23f1","\u23F2":"23f2","\u23F8":"23f8","\u23F9":"23f9","\u23FA":"23fa","\u2602":"2602","\u2603":"2603","\u2604":"2604","\u2618":"2618","\u2620":"2620","\u2622":"2622","\u2623":"2623","\u2626":"2626","\u262A":"262a","\u262E":"262e","\u262F":"262f","\u2638":"2638","\u2639":"2639","\u2692":"2692","\u2694":"2694","\u2696":"2696","\u2697":"2697","\u2699":"2699","\u269B":"269b","\u269C":"269c","\u26B0":"26b0","\u26B1":"26b1","\u26C8":"26c8","\u26CF":"26cf","\u26D1":"26d1","\u26D3":"26d3","\u26E9":"26e9","\u26F0":"26f0","\u26F1":"26f1","\u26F4":"26f4","\u26F7":"26f7","\u26F8":"26f8","\u26F9":"26f9","\u2721":"2721","\u2763":"2763","\uD83C\uDF24":"1f324","\uD83C\uDF25":"1f325","\uD83C\uDF26":"1f326","\uD83D\uDDB1":"1f5b1"};
+ ns.imagePathPNG = 'https://cdn.jsdelivr.net/emojione/assets/png/';
+ ns.imagePathSVG = 'https://cdn.jsdelivr.net/emojione/assets/svg/';
ns.imagePathSVGSprites = './../assets/sprites/emojione.sprites.svg';
ns.imageType = 'png'; // or svg
+ ns.imageTitleTag = true; //set to false to remove title attribute from img tag
ns.sprites = false; // if this is true then sprite markup will be used (if SVG image type is set then you must include the SVG sprite file locally)
ns.unicodeAlt = true; // use the unicode char as the alt attribute (makes copy and pasting the resulting text better)
ns.ascii = false; // change to true to convert ascii smileys
- ns.cacheBustParam = '?v=2.0.1'; // you can [optionally] modify this to force browsers to refresh their cache. it will be appended to the send of the filenames
+ ns.cacheBustParam = '?v=2.2.7'; // you can [optionally] modify this to force browsers to refresh their cache. it will be appended to the send of the filenames
ns.regShortNames = new RegExp("<object[^>]*>.*?<\/object>|<span[^>]*>.*?<\/span>|<(?:object|embed|svg|img|div|span|p|a)[^>]*>|("+ns.shortnames+")", "gi");
ns.regAscii = new RegExp("<object[^>]*>.*?<\/object>|<span[^>]*>.*?<\/span>|<(?:object|embed|svg|img|div|span|p|a)[^>]*>|((\\s|^)"+ns.asciiRegexp+"(?=\\s|$|[!,.?]))", "g");
ns.regUnicode = new RegExp("<object[^>]*>.*?<\/object>|<span[^>]*>.*?<\/span>|<(?:object|embed|svg|img|div|span|p|a)[^>]*>|("+ns.unicodeRegexp+")", "gi");
-
+
ns.toImage = function(str) {
str = ns.unicodeToImage(str);
str = ns.shortnameToImage(str);
@@ -40652,9 +48778,9 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
// Useful for systems that dont support unicode nor images
ns.shortnameToAscii = function(str) {
var unicode,
- // something to keep in mind here is that array flip will destroy
- // half of the ascii text "emojis" because the unicode numbers are duplicated
- // this is ok for what it's being used for
+ // something to keep in mind here is that array flip will destroy
+ // half of the ascii text "emojis" because the unicode numbers are duplicated
+ // this is ok for what it's being used for
unicodeToAscii = ns.objectFlip(ns.asciiList);
str = str.replace(ns.regShortNames, function(shortname) {
@@ -40663,7 +48789,7 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
return shortname;
}
else {
- unicode = ns.emojioneList[shortname][ns.emojioneList[shortname].length-1];
+ unicode = ns.emojioneList[shortname].unicode[ns.emojioneList[shortname].unicode.length-1];
if(typeof unicodeToAscii[unicode] !== 'undefined') {
return unicodeToAscii[unicode];
} else {
@@ -40678,14 +48804,17 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
// useful for sending emojis back to mobile devices
ns.shortnameToUnicode = function(str) {
// replace regular shortnames first
- var unicode;
+ var unicode,fname,uc;
str = str.replace(ns.regShortNames, function(shortname) {
if( (typeof shortname === 'undefined') || (shortname === '') || (!(shortname in ns.emojioneList)) ) {
// if the shortname doesnt exist just return the entire match
return shortname;
}
- unicode = ns.emojioneList[shortname][0].toUpperCase();
- return ns.convert(unicode);
+ unicode = ns.emojioneList[shortname].unicode[0].toUpperCase();
+ fname = ns.emojioneList[shortname].fname;
+ uc = ns.emojioneList[shortname].uc;
+ //return ns.convert(unicode);
+ return ns.convert(uc);
});
// if ascii smileys are turned on, then we'll replace them!
@@ -40703,29 +48832,30 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
});
}
- return str;
+ return str;
};
ns.shortnameToImage = function(str) {
// replace regular shortnames first
- var replaceWith,unicode,alt;
+ var replaceWith,unicode,alt,title;
str = str.replace(ns.regShortNames, function(shortname) {
if( (typeof shortname === 'undefined') || (shortname === '') || (!(shortname in ns.emojioneList)) ) {
// if the shortname doesnt exist just return the entire match
return shortname;
}
else {
- unicode = ns.emojioneList[shortname][ns.emojioneList[shortname].length-1];
+ unicode = ns.emojioneList[shortname].unicode[ns.emojioneList[shortname].unicode.length-1];
+ title = ns.imageTitleTag ? 'title="'+shortname+'"' : '';
// depending on the settings, we'll either add the native unicode as the alt tag, otherwise the shortname
alt = (ns.unicodeAlt) ? ns.convert(unicode.toUpperCase()) : shortname;
if(ns.imageType === 'png') {
if(ns.sprites) {
- replaceWith = '<span class="emojione-'+unicode+'" title="'+shortname+'">'+alt+'</span>';
+ replaceWith = '<span class="emojione emojione-'+unicode+'" ' + title + '>'+alt+'</span>';
}
else {
- replaceWith = '<img class="emojione" alt="'+alt+'" src="'+ns.imagePathPNG+unicode+'.png'+ns.cacheBustParam+'"/>';
+ replaceWith = '<img class="emojione" alt="'+alt+'" ' + title + ' src="'+ns.imagePathPNG+unicode+'.png'+ns.cacheBustParam+'"/>';
}
}
else {
@@ -40747,22 +48877,23 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
str = str.replace(ns.regAscii, function(entire, m1, m2, m3) {
if( (typeof m3 === 'undefined') || (m3 === '') || (!(ns.unescapeHTML(m3) in ns.asciiList)) ) {
- // if the shortname doesnt exist just return the entire match
+ // if the ascii doesnt exist just return the entire match
return entire;
}
m3 = ns.unescapeHTML(m3);
unicode = ns.asciiList[m3];
+ title = ns.imageTitleTag ? 'title="'+ns.escapeHTML(m3)+'"' : '';
// depending on the settings, we'll either add the native unicode as the alt tag, otherwise the shortname
alt = (ns.unicodeAlt) ? ns.convert(unicode.toUpperCase()) : ns.escapeHTML(m3);
if(ns.imageType === 'png') {
if(ns.sprites) {
- replaceWith = m2+'<span class="emojione-'+unicode+'" title="'+ns.escapeHTML(m3)+'">'+alt+'</span>';
+ replaceWith = m2+'<span class="emojione emojione-'+unicode+'" ' + title + '>'+alt+'</span>';
}
else {
- replaceWith = m2+'<img class="emojione" alt="'+alt+'" src="'+ns.imagePathPNG+unicode+'.png'+ns.cacheBustParam+'"/>';
+ replaceWith = m2+'<img class="emojione" alt="'+alt+'" ' + title + ' src="'+ns.imagePathPNG+unicode+'.png'+ns.cacheBustParam+'"/>';
}
}
else {
@@ -40784,13 +48915,8 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
ns.unicodeToImage = function(str) {
- var replaceWith,unicode,alt;
-
- if((!ns.unicodeAlt) || (ns.sprites)) {
- // if we are using the shortname as the alt tag then we need a reversed array to map unicode code point to shortnames
- var mappedUnicode = ns.mapShortToUnicode();
- }
-
+ var replaceWith,unicode,short,fname,alt,title;
+ var mappedUnicode = ns.mapUnicodeToShort();
str = str.replace(ns.regUnicode, function(unicodeChar) {
if( (typeof unicodeChar === 'undefined') || (unicodeChar === '') || (!(unicodeChar in ns.jsEscapeMap)) ) {
// if the unicodeChar doesnt exist just return the entire match
@@ -40800,15 +48926,20 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
// get the unicode codepoint from the actual char
unicode = ns.jsEscapeMap[unicodeChar];
+ //then map to shortname and locate the filename
+ short = mappedUnicode[unicode];
+ fname = ns.emojioneList[short].fname;
+
// depending on the settings, we'll either add the native unicode as the alt tag, otherwise the shortname
- alt = (ns.unicodeAlt) ? ns.convert(unicode.toUpperCase()) : mappedUnicode[unicode];
+ alt = (ns.unicodeAlt) ? ns.convert(unicode.toUpperCase()) : short;
+ title = ns.imageTitleTag ? 'title="'+short+'"' : '';
if(ns.imageType === 'png') {
if(ns.sprites) {
- replaceWith = '<span class="emojione-'+unicode+'" title="'+mappedUnicode[unicode]+'">'+alt+'</span>';
+ replaceWith = '<span class="emojione emojione-'+unicode+'" ' + title + '>'+alt+'</span>';
}
else {
- replaceWith = '<img class="emojione" alt="'+alt+'" src="'+ns.imagePathPNG+unicode+'.png'+ns.cacheBustParam+'"/>';
+ replaceWith = '<img class="emojione" alt="'+alt+'" ' + title + ' src="'+ns.imagePathPNG+fname+'.png'+ns.cacheBustParam+'"/>';
}
}
else {
@@ -40817,7 +48948,7 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
replaceWith = '<svg class="emojione"><description>'+alt+'</description><use xlink:href="'+ns.imagePathSVGSprites+'#emoji-'+unicode+'"></use></svg>';
}
else {
- replaceWith = '<img class="emojione" alt="'+alt+'" src="'+ns.imagePathSVG+unicode+'.svg'+ns.cacheBustParam+'"/>';
+ replaceWith = '<img class="emojione" alt="'+alt+'" ' + title + ' src="'+ns.imagePathSVG+fname+'.svg'+ns.cacheBustParam+'"/>';
}
}
@@ -40828,17 +48959,11 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
return str;
};
- // super simple loop to replace all unicode emoji to shortnames
- // needs to be improved into one big replacement instead, for performance reasons
- ns.toShort = function(str) { // this is really just unicodeToShortname() but I opted for the shorthand name to match toImage()
- for (var shortcode in ns.emojioneList) {
- if (!ns.emojioneList.hasOwnProperty(shortcode)) { continue; }
- for(var i = 0, len = ns.emojioneList[shortcode].length; i < len; i++){
- var unicode = ns.emojioneList[shortcode][i];
- str = ns.replaceAll(str,ns.convert(unicode.toUpperCase()),shortcode);
- }
- }
- return str;
+ // this is really just unicodeToShortname() but I opted for the shorthand name to match toImage()
+ ns.toShort = function(str) {
+ var find = ns.getUnicodeReplacementRegEx(),
+ replacementList = ns.mapUnicodeCharactersToShort();
+ return ns.replaceAll(str, find,replacementList);
};
// for converting unicode code points and code pairs to their respective characters
@@ -40909,16 +49034,52 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
return unescaped[match];
});
};
- ns.mapShortToUnicode = function() {
- var new_obj = {};
+
+ ns.mapEmojioneList = function (addToMapStorage) {
for (var shortname in ns.emojioneList) {
if (!ns.emojioneList.hasOwnProperty(shortname)) { continue; }
- for(var i = 0, len = ns.emojioneList[shortname].length; i < len; i++){
- new_obj[ns.emojioneList[shortname][i]] = shortname;
+ for (var i = 0, len = ns.emojioneList[shortname].unicode.length; i < len; i++) {
+ var unicode = ns.emojioneList[shortname].unicode[i];
+ addToMapStorage(unicode, shortname);
}
}
- return new_obj;
};
+
+ ns.mapUnicodeToShort = function() {
+ if (!ns.memMapShortToUnicode) {
+ ns.memMapShortToUnicode = {};
+ ns.mapEmojioneList(function (unicode, shortname) {
+ ns.memMapShortToUnicode[unicode] = shortname;
+ });
+ }
+ return ns.memMapShortToUnicode;
+ };
+
+ ns.memoizeReplacement = function() {
+ if (!ns.unicodeReplacementRegEx || !ns.memMapShortToUnicodeCharacters) {
+ var unicodeList = [];
+ ns.memMapShortToUnicodeCharacters = {};
+ ns.mapEmojioneList(function (unicode, shortname) {
+ var emojiCharacter = ns.convert(unicode);
+ if(ns.emojioneList[shortname].isCanonical) {
+ ns.memMapShortToUnicodeCharacters[emojiCharacter] = shortname;
+ }
+ unicodeList.push(emojiCharacter);
+ });
+ ns.unicodeReplacementRegEx = unicodeList.join('|');
+ }
+ };
+
+ ns.mapUnicodeCharactersToShort = function() {
+ ns.memoizeReplacement();
+ return ns.memMapShortToUnicodeCharacters;
+ };
+
+ ns.getUnicodeReplacementRegEx = function() {
+ ns.memoizeReplacement();
+ return ns.unicodeReplacementRegEx;
+ };
+
//reverse an object
ns.objectFlip = function (obj) {
var key, tmp_obj = {};
@@ -40933,20 +49094,20 @@ var I18next = {"bg":{"translation":{"Logging_in":null,"your_connection_is_unencr
};
ns.escapeRegExp = function(string) {
- return string.replace(/[-[\]{}()*+?.,;:&\\^$|#\s]/g, "\\$&");
+ return string.replace(/[-[\]{}()*+?.,;:&\\^$#\s]/g, "\\$&");
};
- ns.replaceAll = function(string, find, replaceWith) {
+ ns.replaceAll = function(string, find, replacementList) {
var escapedFind = ns.escapeRegExp(find);
var search = new RegExp("<object[^>]*>.*?<\/object>|<span[^>]*>.*?<\/span>|<(?:object|embed|svg|img|div|span|p|a)[^>]*>|("+escapedFind+")", "gi");
// callback prevents replacing anything inside of these common html tags as well as between an <object></object> tag
var replace = function(entire, m1) {
- return ((typeof m1 === 'undefined') || (m1 === '')) ? entire : replaceWith;
+ return ((typeof m1 === 'undefined') || (m1 === '')) ? entire : replacementList[m1];
};
return string.replace(search,replace);
};
}(this.emojione = this.emojione || {}));
-if(typeof module === "object") module.exports = this.emojione;
+if(typeof module === "object") module.exports = this.emojione; \ No newline at end of file