diff --git a/dist/naf-janus-adapter.js b/dist/naf-janus-adapter.js index a8fd73e..ce0555e 100644 --- a/dist/naf-janus-adapter.js +++ b/dist/naf-janus-adapter.js @@ -371,6 +371,7 @@ class JanusAdapter { this.reconnectionTimeout = null; this.maxReconnectionAttempts = 10; this.reconnectionAttempts = 0; + this.isReconnecting = false; this.publisher = null; this.occupantIds = []; this.occupants = {}; @@ -434,12 +435,25 @@ class JanusAdapter { this.loops = loops; } connect() { + if (this.serverUrl === '/') { + this.serverUrl = '/janus'; + } + if (this.serverUrl === '/janus') { + if (location.protocol === 'https:') { + this.serverUrl = 'wss://' + location.host + '/janus'; + } else { + this.serverUrl = 'ws://' + location.host + '/janus'; + } + } debug(`connecting to ${this.serverUrl}`); const websocketConnection = new Promise((resolve, reject) => { this.ws = new WebSocket(this.serverUrl, "janus-protocol"); this.session = new mj.JanusSession(this.ws.send.bind(this.ws), { timeoutMs: 40000 }); + this.websocketConnectionPromise = {}; + this.websocketConnectionPromise.resolve = resolve; + this.websocketConnectionPromise.reject = reject; this.ws.addEventListener("close", this.onWebsocketClose); this.ws.addEventListener("message", this.onWebsocketMessage); this.wsOnOpen = () => { @@ -505,11 +519,15 @@ class JanusAdapter { if (event.code === WS_NORMAL_CLOSURE) { return; } - console.warn("Janus websocket closed unexpectedly."); - if (this.onReconnecting) { - this.onReconnecting(this.reconnectionDelay); + this.websocketConnectionPromise.reject(event); + if (!this.isReconnecting) { + this.isReconnecting = true; + console.warn("Janus websocket closed unexpectedly."); + if (this.onReconnecting) { + this.onReconnecting(this.reconnectionDelay); + } + this.reconnectionTimeout = setTimeout(() => this.reconnect(), this.reconnectionDelay); } - this.reconnectionTimeout = setTimeout(() => this.reconnect(), this.reconnectionDelay); } reconnect() { // Dispose of all networked entities and other resources tied to the session. @@ -517,14 +535,21 @@ class JanusAdapter { this.connect().then(() => { this.reconnectionDelay = this.initialReconnectionDelay; this.reconnectionAttempts = 0; + this.isReconnecting = false; if (this.onReconnected) { this.onReconnected(); } }).catch(error => { this.reconnectionDelay += 1000; this.reconnectionAttempts++; - if (this.reconnectionAttempts > this.maxReconnectionAttempts && this.onReconnectionError) { - return this.onReconnectionError(new Error("Connection could not be reestablished, exceeded maximum number of reconnection attempts.")); + if (this.reconnectionAttempts > this.maxReconnectionAttempts) { + const error = new Error("Connection could not be reestablished, exceeded maximum number of reconnection attempts."); + if (this.onReconnectionError) { + return this.onReconnectionError(error); + } else { + console.warn(error); + return; + } } console.warn("Error during reconnect, retrying."); console.warn(error); @@ -1464,14 +1489,17 @@ function useColors() { return false; } + let m; + // Is webkit? http://stackoverflow.com/a/16459606/376773 // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + // eslint-disable-next-line no-return-assign return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || // Is firebug? http://stackoverflow.com/a/398120/376773 (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || // Is firefox >= v31? // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + (typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31) || // Double check webkit in userAgent just in case we are in a worker (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); } @@ -1784,24 +1812,62 @@ function setup(env) { createDebug.names = []; createDebug.skips = []; - let i; - const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - const len = split.length; + const split = (typeof namespaces === 'string' ? namespaces : '') + .trim() + .replace(' ', ',') + .split(',') + .filter(Boolean); - for (i = 0; i < len; i++) { - if (!split[i]) { - // ignore empty strings - continue; + for (const ns of split) { + if (ns[0] === '-') { + createDebug.skips.push(ns.slice(1)); + } else { + createDebug.names.push(ns); } + } + } - namespaces = split[i].replace(/\*/g, '.*?'); - - if (namespaces[0] === '-') { - createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$')); + /** + * Checks if the given string matches a namespace template, honoring + * asterisks as wildcards. + * + * @param {String} search + * @param {String} template + * @return {Boolean} + */ + function matchesTemplate(search, template) { + let searchIndex = 0; + let templateIndex = 0; + let starIndex = -1; + let matchIndex = 0; + + while (searchIndex < search.length) { + if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) { + // Match character or proceed with wildcard + if (template[templateIndex] === '*') { + starIndex = templateIndex; + matchIndex = searchIndex; + templateIndex++; // Skip the '*' + } else { + searchIndex++; + templateIndex++; + } + } else if (starIndex !== -1) { // eslint-disable-line no-negated-condition + // Backtrack to the last '*' and try to match more characters + templateIndex = starIndex + 1; + matchIndex++; + searchIndex = matchIndex; } else { - createDebug.names.push(new RegExp('^' + namespaces + '$')); + return false; // No match } } + + // Handle trailing '*' in template + while (templateIndex < template.length && template[templateIndex] === '*') { + templateIndex++; + } + + return templateIndex === template.length; } /** @@ -1812,8 +1878,8 @@ function setup(env) { */ function disable() { const namespaces = [ - ...createDebug.names.map(toNamespace), - ...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace) + ...createDebug.names, + ...createDebug.skips.map(namespace => '-' + namespace) ].join(','); createDebug.enable(''); return namespaces; @@ -1827,21 +1893,14 @@ function setup(env) { * @api public */ function enabled(name) { - if (name[name.length - 1] === '*') { - return true; - } - - let i; - let len; - - for (i = 0, len = createDebug.skips.length; i < len; i++) { - if (createDebug.skips[i].test(name)) { + for (const skip of createDebug.skips) { + if (matchesTemplate(name, skip)) { return false; } } - for (i = 0, len = createDebug.names.length; i < len; i++) { - if (createDebug.names[i].test(name)) { + for (const ns of createDebug.names) { + if (matchesTemplate(name, ns)) { return true; } } @@ -1849,19 +1908,6 @@ function setup(env) { return false; } - /** - * Convert regexp to namespace - * - * @param {RegExp} regxep - * @return {String} namespace - * @api private - */ - function toNamespace(regexp) { - return regexp.toString() - .substring(2, regexp.toString().length - 2) - .replace(/\.\*\?$/, '*'); - } - /** * Coerce `val`. * @@ -1925,7 +1971,7 @@ var y = d * 365.25; * @api public */ -module.exports = function(val, options) { +module.exports = function (val, options) { options = options || {}; var type = typeof val; if (type === 'string' && val.length > 0) { @@ -2914,4 +2960,4 @@ if (true) { /******/ /******/ })() ; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,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O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyw0Q0FBNEM7O0FBRXZEO0FBQ0E7QUFDQTtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFB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Q0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsUUFBUTtBQUNuQixZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsUUFBUTtBQUNuQixZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkIsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7QUNqS0E7QUFDYTs7QUFFYjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsZ0JBQWdCLG9CQUFvQjtBQUNwQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGtCQUFrQixrQkFBa0I7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdDQUF3QztBQUN4QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLDZDQUE2QztBQUM3QztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxvQkFBb0I7QUFDcEIsMkJBQTJCO0FBQzNCO0FBQ0E7QUFDQTtBQUNBLDhEQUE4RDtBQUM5RCxrQkFBa0Isa0JBQWtCO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsaURBQWlEO0FBQ2pEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQixrQkFBa0IsT0FBTztBQUMzQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxHQUFHO0FBQ0g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSw2Q0FBNkM7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0I7QUFDeEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLGtCQUFrQjtBQUNwQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQixrQkFBa0I7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxJQUFJLElBQTBCO0FBQzlCO0FBQ0E7Ozs7Ozs7VUNqeUJBO1VBQ0E7O1VBRUE7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7O1VBRUE7VUFDQTs7VUFFQTtVQUNBO1VBQ0E7Ozs7VUV0QkE7VUFDQTtVQUNBO1VBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci8uL25vZGVfbW9kdWxlcy9AbmV0d29ya2VkLWFmcmFtZS9taW5pamFudXMvbWluaWphbnVzLmpzIiwid2VicGFjazovL0BuZXR3b3JrZWQtYWZyYW1lL25hZi1qYW51cy1hZGFwdGVyLy4vc3JjL2luZGV4LmpzIiwid2VicGFjazovL0BuZXR3b3JrZWQtYWZyYW1lL25hZi1qYW51cy1hZGFwdGVyLy4vbm9kZV9tb2R1bGVzL2RlYnVnL3NyYy9icm93c2VyLmpzIiwid2VicGFjazovL0BuZXR3b3JrZWQtYWZyYW1lL25hZi1qYW51cy1hZGFwdGVyLy4vbm9kZV9tb2R1bGVzL2RlYnVnL3NyYy9jb21tb24uanMiLCJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvLi9ub2RlX21vZHVsZXMvbXMvaW5kZXguanMiLCJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvLi9ub2RlX21vZHVsZXMvc2RwL3NkcC5qcyIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci93ZWJwYWNrL2Jvb3RzdHJhcCIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci93ZWJwYWNrL2JlZm9yZS1zdGFydHVwIiwid2VicGFjazovL0BuZXR3b3JrZWQtYWZyYW1lL25hZi1qYW51cy1hZGFwdGVyL3dlYnBhY2svc3RhcnR1cCIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci93ZWJwYWNrL2FmdGVyLXN0YXJ0dXAiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBSZXByZXNlbnRzIGEgaGFuZGxlIHRvIGEgc2luZ2xlIEphbnVzIHBsdWdpbiBvbiBhIEphbnVzIHNlc3Npb24uIEVhY2ggV2ViUlRDIGNvbm5lY3Rpb24gdG8gdGhlIEphbnVzIHNlcnZlciB3aWxsIGJlXG4gKiBhc3NvY2lhdGVkIHdpdGggYSBzaW5nbGUgaGFuZGxlLiBPbmNlIGF0dGFjaGVkIHRvIHRoZSBzZXJ2ZXIsIHRoaXMgaGFuZGxlIHdpbGwgYmUgZ2l2ZW4gYSB1bmlxdWUgSUQgd2hpY2ggc2hvdWxkIGJlXG4gKiB1c2VkIHRvIGFzc29jaWF0ZSBpdCB3aXRoIGZ1dHVyZSBzaWduYWxsaW5nIG1lc3NhZ2VzLlxuICpcbiAqIFNlZSBodHRwczovL2phbnVzLmNvbmYubWVldGVjaG8uY29tL2RvY3MvcmVzdC5odG1sI2hhbmRsZXMuXG4gKiovXG5mdW5jdGlvbiBKYW51c1BsdWdpbkhhbmRsZShzZXNzaW9uKSB7XG4gIHRoaXMuc2Vzc2lvbiA9IHNlc3Npb247XG4gIHRoaXMuaWQgPSB1bmRlZmluZWQ7XG59XG5cbi8qKiBBdHRhY2hlcyB0aGlzIGhhbmRsZSB0byB0aGUgSmFudXMgc2VydmVyIGFuZCBzZXRzIGl0cyBJRC4gKiovXG5KYW51c1BsdWdpbkhhbmRsZS5wcm90b3R5cGUuYXR0YWNoID0gZnVuY3Rpb24ocGx1Z2luLCBsb29wX2luZGV4KSB7XG4gIHZhciBwYXlsb2FkID0geyBwbHVnaW46IHBsdWdpbiwgbG9vcF9pbmRleDogbG9vcF9pbmRleCwgXCJmb3JjZS1idW5kbGVcIjogdHJ1ZSwgXCJmb3JjZS1ydGNwLW11eFwiOiB0cnVlIH07XG4gIHJldHVybiB0aGlzLnNlc3Npb24uc2VuZChcImF0dGFjaFwiLCBwYXlsb2FkKS50aGVuKHJlc3AgPT4ge1xuICAgIHRoaXMuaWQgPSByZXNwLmRhdGEuaWQ7XG4gICAgcmV0dXJuIHJlc3A7XG4gIH0pO1xufTtcblxuLyoqIERldGFjaGVzIHRoaXMgaGFuZGxlLiAqKi9cbkphbnVzUGx1Z2luSGFuZGxlLnByb3RvdHlwZS5kZXRhY2ggPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIHRoaXMuc2VuZChcImRldGFjaFwiKTtcbn07XG5cbi8qKiBSZWdpc3RlcnMgYSBjYWxsYmFjayB0byBiZSBmaXJlZCB1cG9uIHRoZSByZWNlcHRpb24gb2YgYW55IGluY29taW5nIEphbnVzIHNpZ25hbHMgZm9yIHRoaXMgcGx1Z2luIGhhbmRsZSB3aXRoIHRoZVxuICogYGphbnVzYCBhdHRyaWJ1dGUgZXF1YWwgdG8gYGV2YC5cbiAqKi9cbkphbnVzUGx1Z2luSGFuZGxlLnByb3RvdHlwZS5vbiA9IGZ1bmN0aW9uKGV2LCBjYWxsYmFjaykge1xuICByZXR1cm4gdGhpcy5zZXNzaW9uLm9uKGV2LCBzaWduYWwgPT4ge1xuICAgIGlmIChzaWduYWwuc2VuZGVyID09IHRoaXMuaWQpIHtcbiAgICAgIGNhbGxiYWNrKHNpZ25hbCk7XG4gICAgfVxuICB9KTtcbn07XG5cbi8qKlxuICogU2VuZHMgYSBzaWduYWwgYXNzb2NpYXRlZCB3aXRoIHRoaXMgaGFuZGxlLiBTaWduYWxzIHNob3VsZCBiZSBKU09OLXNlcmlhbGl6YWJsZSBvYmplY3RzLiBSZXR1cm5zIGEgcHJvbWlzZSB0aGF0IHdpbGxcbiAqIGJlIHJlc29sdmVkIG9yIHJlamVjdGVkIHdoZW4gYSByZXNwb25zZSB0byB0aGlzIHNpZ25hbCBpcyByZWNlaXZlZCwgb3Igd2hlbiBubyByZXNwb25zZSBpcyByZWNlaXZlZCB3aXRoaW4gdGhlXG4gKiBzZXNzaW9uIHRpbWVvdXQuXG4gKiovXG5KYW51c1BsdWdpbkhhbmRsZS5wcm90b3R5cGUuc2VuZCA9IGZ1bmN0aW9uKHR5cGUsIHNpZ25hbCkge1xuICByZXR1cm4gdGhpcy5zZXNzaW9uLnNlbmQodHlwZSwgT2JqZWN0LmFzc2lnbih7IGhhbmRsZV9pZDogdGhpcy5pZCB9LCBzaWduYWwpKTtcbn07XG5cbi8qKiBTZW5kcyBhIHBsdWdpbi1zcGVjaWZpYyBtZXNzYWdlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGhhbmRsZS4gKiovXG5KYW51c1BsdWdpbkhhbmRsZS5wcm90b3R5cGUuc2VuZE1lc3NhZ2UgPSBmdW5jdGlvbihib2R5KSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJtZXNzYWdlXCIsIHsgYm9keTogYm9keSB9KTtcbn07XG5cbi8qKiBTZW5kcyBhIEpTRVAgb2ZmZXIgb3IgYW5zd2VyIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGhhbmRsZS4gKiovXG5KYW51c1BsdWdpbkhhbmRsZS5wcm90b3R5cGUuc2VuZEpzZXAgPSBmdW5jdGlvbihqc2VwKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJtZXNzYWdlXCIsIHsgYm9keToge30sIGpzZXA6IGpzZXAgfSk7XG59O1xuXG4vKiogU2VuZHMgYW4gSUNFIHRyaWNrbGUgY2FuZGlkYXRlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGhhbmRsZS4gKiovXG5KYW51c1BsdWdpbkhhbmRsZS5wcm90b3R5cGUuc2VuZFRyaWNrbGUgPSBmdW5jdGlvbihjYW5kaWRhdGUpIHtcbiAgcmV0dXJuIHRoaXMuc2VuZChcInRyaWNrbGVcIiwgeyBjYW5kaWRhdGU6IGNhbmRpZGF0ZSB9KTtcbn07XG5cbi8qKlxuICogUmVwcmVzZW50cyBhIEphbnVzIHNlc3Npb24gLS0gYSBKYW51cyBjb250ZXh0IGZyb20gd2l0aGluIHdoaWNoIHlvdSBjYW4gb3BlbiBtdWx0aXBsZSBoYW5kbGVzIGFuZCBjb25uZWN0aW9ucy4gT25jZVxuICogY3JlYXRlZCwgdGhpcyBzZXNzaW9uIHdpbGwgYmUgZ2l2ZW4gYSB1bmlxdWUgSUQgd2hpY2ggc2hvdWxkIGJlIHVzZWQgdG8gYXNzb2NpYXRlIGl0IHdpdGggZnV0dXJlIHNpZ25hbGxpbmcgbWVzc2FnZXMuXG4gKlxuICogU2VlIGh0dHBzOi8vamFudXMuY29uZi5tZWV0ZWNoby5jb20vZG9jcy9yZXN0Lmh0bWwjc2Vzc2lvbnMuXG4gKiovXG5mdW5jdGlvbiBKYW51c1Nlc3Npb24ob3V0cHV0LCBvcHRpb25zKSB7XG4gIHRoaXMub3V0cHV0ID0gb3V0cHV0O1xuICB0aGlzLmlkID0gdW5kZWZpbmVkO1xuICB0aGlzLm5leHRUeElkID0gMDtcbiAgdGhpcy50eG5zID0ge307XG4gIHRoaXMuZXZlbnRIYW5kbGVycyA9IHt9O1xuICB0aGlzLm9wdGlvbnMgPSBPYmplY3QuYXNzaWduKHtcbiAgICB2ZXJib3NlOiBmYWxzZSxcbiAgICB0aW1lb3V0TXM6IDEwMDAwLFxuICAgIGtlZXBhbGl2ZU1zOiAzMDAwMFxuICB9LCBvcHRpb25zKTtcbn1cblxuLyoqIENyZWF0ZXMgdGhpcyBzZXNzaW9uIG9uIHRoZSBKYW51cyBzZXJ2ZXIgYW5kIHNldHMgaXRzIElELiAqKi9cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuY3JlYXRlID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJjcmVhdGVcIikudGhlbihyZXNwID0+IHtcbiAgICB0aGlzLmlkID0gcmVzcC5kYXRhLmlkO1xuICAgIHJldHVybiByZXNwO1xuICB9KTtcbn07XG5cbi8qKlxuICogRGVzdHJveXMgdGhpcyBzZXNzaW9uLiBOb3RlIHRoYXQgdXBvbiBkZXN0cnVjdGlvbiwgSmFudXMgd2lsbCBhbHNvIGNsb3NlIHRoZSBzaWduYWxsaW5nIHRyYW5zcG9ydCAoaWYgYXBwbGljYWJsZSkgYW5kXG4gKiBhbnkgb3BlbiBXZWJSVEMgY29ubmVjdGlvbnMuXG4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIHRoaXMuc2VuZChcImRlc3Ryb3lcIikudGhlbigocmVzcCkgPT4ge1xuICAgIHRoaXMuZGlzcG9zZSgpO1xuICAgIHJldHVybiByZXNwO1xuICB9KTtcbn07XG5cbi8qKlxuICogRGlzcG9zZXMgb2YgdGhpcyBzZXNzaW9uIGluIGEgd2F5IHN1Y2ggdGhhdCBubyBmdXJ0aGVyIGluY29taW5nIHNpZ25hbGxpbmcgbWVzc2FnZXMgd2lsbCBiZSBwcm9jZXNzZWQuXG4gKiBPdXRzdGFuZGluZyB0cmFuc2FjdGlvbnMgd2lsbCBiZSByZWplY3RlZC5cbiAqKi9cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuZGlzcG9zZSA9IGZ1bmN0aW9uKCkge1xuICB0aGlzLl9raWxsS2VlcGFsaXZlKCk7XG4gIHRoaXMuZXZlbnRIYW5kbGVycyA9IHt9O1xuICBmb3IgKHZhciB0eElkIGluIHRoaXMudHhucykge1xuICAgIGlmICh0aGlzLnR4bnMuaGFzT3duUHJvcGVydHkodHhJZCkpIHtcbiAgICAgIHZhciB0eG4gPSB0aGlzLnR4bnNbdHhJZF07XG4gICAgICBjbGVhclRpbWVvdXQodHhuLnRpbWVvdXQpO1xuICAgICAgdHhuLnJlamVjdChuZXcgRXJyb3IoXCJKYW51cyBzZXNzaW9uIHdhcyBkaXNwb3NlZC5cIikpO1xuICAgICAgZGVsZXRlIHRoaXMudHhuc1t0eElkXTtcbiAgICB9XG4gIH1cbn07XG5cbi8qKlxuICogV2hldGhlciB0aGlzIHNpZ25hbCByZXByZXNlbnRzIGFuIGVycm9yLCBhbmQgdGhlIGFzc29jaWF0ZWQgcHJvbWlzZSAoaWYgYW55KSBzaG91bGQgYmUgcmVqZWN0ZWQuXG4gKiBVc2VycyBzaG91bGQgb3ZlcnJpZGUgdGhpcyB0byBoYW5kbGUgYW55IGN1c3RvbSBwbHVnaW4tc3BlY2lmaWMgZXJyb3IgY29udmVudGlvbnMuXG4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLmlzRXJyb3IgPSBmdW5jdGlvbihzaWduYWwpIHtcbiAgcmV0dXJuIHNpZ25hbC5qYW51cyA9PT0gXCJlcnJvclwiO1xufTtcblxuLyoqIFJlZ2lzdGVycyBhIGNhbGxiYWNrIHRvIGJlIGZpcmVkIHVwb24gdGhlIHJlY2VwdGlvbiBvZiBhbnkgaW5jb21pbmcgSmFudXMgc2lnbmFscyBmb3IgdGhpcyBzZXNzaW9uIHdpdGggdGhlXG4gKiBgamFudXNgIGF0dHJpYnV0ZSBlcXVhbCB0byBgZXZgLlxuICoqL1xuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5vbiA9IGZ1bmN0aW9uKGV2LCBjYWxsYmFjaykge1xuICB2YXIgaGFuZGxlcnMgPSB0aGlzLmV2ZW50SGFuZGxlcnNbZXZdO1xuICBpZiAoaGFuZGxlcnMgPT0gbnVsbCkge1xuICAgIGhhbmRsZXJzID0gdGhpcy5ldmVudEhhbmRsZXJzW2V2XSA9IFtdO1xuICB9XG4gIGhhbmRsZXJzLnB1c2goY2FsbGJhY2spO1xufTtcblxuLyoqXG4gKiBDYWxsYmFjayBmb3IgcmVjZWl2aW5nIEpTT04gc2lnbmFsbGluZyBtZXNzYWdlcyBwZXJ0aW5lbnQgdG8gdGhpcyBzZXNzaW9uLiBJZiB0aGUgc2lnbmFscyBhcmUgcmVzcG9uc2VzIHRvIHByZXZpb3VzbHlcbiAqIHNlbnQgc2lnbmFscywgdGhlIHByb21pc2VzIGZvciB0aGUgb3V0Z29pbmcgc2lnbmFscyB3aWxsIGJlIHJlc29sdmVkIG9yIHJlamVjdGVkIGFwcHJvcHJpYXRlbHkgd2l0aCB0aGlzIHNpZ25hbCBhcyBhblxuICogYXJndW1lbnQuXG4gKlxuICogRXh0ZXJuYWwgY2FsbGVycyBzaG91bGQgY2FsbCB0aGlzIGZ1bmN0aW9uIGV2ZXJ5IHRpbWUgYSBuZXcgc2lnbmFsIGFycml2ZXMgb24gdGhlIHRyYW5zcG9ydDsgZm9yIGV4YW1wbGUsIGluIGFcbiAqIFdlYlNvY2tldCdzIGBtZXNzYWdlYCBldmVudCwgb3Igd2hlbiBhIG5ldyBkYXR1bSBzaG93cyB1cCBpbiBhbiBIVFRQIGxvbmctcG9sbGluZyByZXNwb25zZS5cbiAqKi9cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUucmVjZWl2ZSA9IGZ1bmN0aW9uKHNpZ25hbCkge1xuICBpZiAodGhpcy5vcHRpb25zLnZlcmJvc2UpIHtcbiAgICB0aGlzLl9sb2dJbmNvbWluZyhzaWduYWwpO1xuICB9XG4gIGlmIChzaWduYWwuc2Vzc2lvbl9pZCAhPSB0aGlzLmlkKSB7XG4gICAgY29uc29sZS53YXJuKFwiSW5jb3JyZWN0IHNlc3Npb24gSUQgcmVjZWl2ZWQgaW4gSmFudXMgc2lnbmFsbGluZyBtZXNzYWdlOiB3YXMgXCIgKyBzaWduYWwuc2Vzc2lvbl9pZCArIFwiLCBleHBlY3RlZCBcIiArIHRoaXMuaWQgKyBcIi5cIik7XG4gIH1cblxuICB2YXIgcmVzcG9uc2VUeXBlID0gc2lnbmFsLmphbnVzO1xuICB2YXIgaGFuZGxlcnMgPSB0aGlzLmV2ZW50SGFuZGxlcnNbcmVzcG9uc2VUeXBlXTtcbiAgaWYgKGhhbmRsZXJzICE9IG51bGwpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGhhbmRsZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBoYW5kbGVyc1tpXShzaWduYWwpO1xuICAgIH1cbiAgfVxuXG4gIGlmIChzaWduYWwudHJhbnNhY3Rpb24gIT0gbnVsbCkge1xuICAgIHZhciB0eG4gPSB0aGlzLnR4bnNbc2lnbmFsLnRyYW5zYWN0aW9uXTtcbiAgICBpZiAodHhuID09IG51bGwpIHtcbiAgICAgIC8vIHRoaXMgaXMgYSByZXNwb25zZSB0byBhIHRyYW5zYWN0aW9uIHRoYXQgd2Fzbid0IGNhdXNlZCB2aWEgSmFudXNTZXNzaW9uLnNlbmQsIG9yIGEgcGx1Z2luIHJlcGxpZWQgdHdpY2UgdG8gYVxuICAgICAgLy8gc2luZ2xlIHJlcXVlc3QsIG9yIHRoZSBzZXNzaW9uIHdhcyBkaXNwb3NlZCwgb3Igc29tZXRoaW5nIGVsc2UgdGhhdCBpc24ndCB1bmRlciBvdXIgcHVydmlldzsgdGhhdCdzIGZpbmVcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAocmVzcG9uc2VUeXBlID09PSBcImFja1wiICYmIHR4bi50eXBlID09IFwibWVzc2FnZVwiKSB7XG4gICAgICAvLyB0aGlzIGlzIGFuIGFjayBvZiBhbiBhc3luY2hyb25vdXNseS1wcm9jZXNzZWQgcGx1Z2luIHJlcXVlc3QsIHdlIHNob3VsZCB3YWl0IHRvIHJlc29sdmUgdGhlIHByb21pc2UgdW50aWwgdGhlXG4gICAgICAvLyBhY3R1YWwgcmVzcG9uc2UgY29tZXMgaW5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjbGVhclRpbWVvdXQodHhuLnRpbWVvdXQpO1xuXG4gICAgZGVsZXRlIHRoaXMudHhuc1tzaWduYWwudHJhbnNhY3Rpb25dO1xuICAgICh0aGlzLmlzRXJyb3Ioc2lnbmFsKSA/IHR4bi5yZWplY3QgOiB0eG4ucmVzb2x2ZSkoc2lnbmFsKTtcbiAgfVxufTtcblxuLyoqXG4gKiBTZW5kcyBhIHNpZ25hbCBhc3NvY2lhdGVkIHdpdGggdGhpcyBzZXNzaW9uLCBiZWdpbm5pbmcgYSBuZXcgdHJhbnNhY3Rpb24uIFJldHVybnMgYSBwcm9taXNlIHRoYXQgd2lsbCBiZSByZXNvbHZlZCBvclxuICogcmVqZWN0ZWQgd2hlbiBhIHJlc3BvbnNlIGlzIHJlY2VpdmVkIGluIHRoZSBzYW1lIHRyYW5zYWN0aW9uLCBvciB3aGVuIG5vIHJlc3BvbnNlIGlzIHJlY2VpdmVkIHdpdGhpbiB0aGUgc2Vzc2lvblxuICogdGltZW91dC5cbiAqKi9cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuc2VuZCA9IGZ1bmN0aW9uKHR5cGUsIHNpZ25hbCkge1xuICBzaWduYWwgPSBPYmplY3QuYXNzaWduKHsgdHJhbnNhY3Rpb246ICh0aGlzLm5leHRUeElkKyspLnRvU3RyaW5nKCkgfSwgc2lnbmFsKTtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICB2YXIgdGltZW91dCA9IG51bGw7XG4gICAgaWYgKHRoaXMub3B0aW9ucy50aW1lb3V0TXMpIHtcbiAgICAgIHRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgZGVsZXRlIHRoaXMudHhuc1tzaWduYWwudHJhbnNhY3Rpb25dO1xuICAgICAgICByZWplY3QobmV3IEVycm9yKFwiU2lnbmFsbGluZyB0cmFuc2FjdGlvbiB3aXRoIHR4aWQgXCIgKyBzaWduYWwudHJhbnNhY3Rpb24gKyBcIiB0aW1lZCBvdXQuXCIpKTtcbiAgICAgIH0sIHRoaXMub3B0aW9ucy50aW1lb3V0TXMpO1xuICAgIH1cbiAgICB0aGlzLnR4bnNbc2lnbmFsLnRyYW5zYWN0aW9uXSA9IHsgcmVzb2x2ZTogcmVzb2x2ZSwgcmVqZWN0OiByZWplY3QsIHRpbWVvdXQ6IHRpbWVvdXQsIHR5cGU6IHR5cGUgfTtcbiAgICB0aGlzLl90cmFuc21pdCh0eXBlLCBzaWduYWwpO1xuICB9KTtcbn07XG5cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuX3RyYW5zbWl0ID0gZnVuY3Rpb24odHlwZSwgc2lnbmFsKSB7XG4gIHNpZ25hbCA9IE9iamVjdC5hc3NpZ24oeyBqYW51czogdHlwZSB9LCBzaWduYWwpO1xuXG4gIGlmICh0aGlzLmlkICE9IG51bGwpIHsgLy8gdGhpcy5pZCBpcyB1bmRlZmluZWQgaW4gdGhlIHNwZWNpYWwgY2FzZSB3aGVuIHdlJ3JlIHNlbmRpbmcgdGhlIHNlc3Npb24gY3JlYXRlIG1lc3NhZ2VcbiAgICBzaWduYWwgPSBPYmplY3QuYXNzaWduKHsgc2Vzc2lvbl9pZDogdGhpcy5pZCB9LCBzaWduYWwpO1xuICB9XG5cbiAgaWYgKHRoaXMub3B0aW9ucy52ZXJib3NlKSB7XG4gICAgdGhpcy5fbG9nT3V0Z29pbmcoc2lnbmFsKTtcbiAgfVxuXG4gIHRoaXMub3V0cHV0KEpTT04uc3RyaW5naWZ5KHNpZ25hbCkpO1xuICB0aGlzLl9yZXNldEtlZXBhbGl2ZSgpO1xufTtcblxuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5fbG9nT3V0Z29pbmcgPSBmdW5jdGlvbihzaWduYWwpIHtcbiAgdmFyIGtpbmQgPSBzaWduYWwuamFudXM7XG4gIGlmIChraW5kID09PSBcIm1lc3NhZ2VcIiAmJiBzaWduYWwuanNlcCkge1xuICAgIGtpbmQgPSBzaWduYWwuanNlcC50eXBlO1xuICB9XG4gIHZhciBtZXNzYWdlID0gXCI+IE91dGdvaW5nIEphbnVzIFwiICsgKGtpbmQgfHwgXCJzaWduYWxcIikgKyBcIiAoI1wiICsgc2lnbmFsLnRyYW5zYWN0aW9uICsgXCIpOiBcIjtcbiAgY29uc29sZS5kZWJ1ZyhcIiVjXCIgKyBtZXNzYWdlLCBcImNvbG9yOiAjMDQwXCIsIHNpZ25hbCk7XG59O1xuXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLl9sb2dJbmNvbWluZyA9IGZ1bmN0aW9uKHNpZ25hbCkge1xuICB2YXIga2luZCA9IHNpZ25hbC5qYW51cztcbiAgdmFyIG1lc3NhZ2UgPSBzaWduYWwudHJhbnNhY3Rpb24gP1xuICAgICAgXCI8IEluY29taW5nIEphbnVzIFwiICsgKGtpbmQgfHwgXCJzaWduYWxcIikgKyBcIiAoI1wiICsgc2lnbmFsLnRyYW5zYWN0aW9uICsgXCIpOiBcIiA6XG4gICAgICBcIjwgSW5jb21pbmcgSmFudXMgXCIgKyAoa2luZCB8fCBcInNpZ25hbFwiKSArIFwiOiBcIjtcbiAgY29uc29sZS5kZWJ1ZyhcIiVjXCIgKyBtZXNzYWdlLCBcImNvbG9yOiAjMDA0XCIsIHNpZ25hbCk7XG59O1xuXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLl9zZW5kS2VlcGFsaXZlID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJrZWVwYWxpdmVcIik7XG59O1xuXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLl9raWxsS2VlcGFsaXZlID0gZnVuY3Rpb24oKSB7XG4gIGNsZWFyVGltZW91dCh0aGlzLmtlZXBhbGl2ZVRpbWVvdXQpO1xufTtcblxuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5fcmVzZXRLZWVwYWxpdmUgPSBmdW5jdGlvbigpIHtcbiAgdGhpcy5fa2lsbEtlZXBhbGl2ZSgpO1xuICBpZiAodGhpcy5vcHRpb25zLmtlZXBhbGl2ZU1zKSB7XG4gICAgdGhpcy5rZWVwYWxpdmVUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLl9zZW5kS2VlcGFsaXZlKCkuY2F0Y2goZSA9PiBjb25zb2xlLmVycm9yKFwiRXJyb3IgcmVjZWl2ZWQgZnJvbSBrZWVwYWxpdmU6IFwiLCBlKSk7XG4gICAgfSwgdGhpcy5vcHRpb25zLmtlZXBhbGl2ZU1zKTtcbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIEphbnVzUGx1Z2luSGFuZGxlLFxuICBKYW51c1Nlc3Npb25cbn07XG4iLCIvKiBnbG9iYWwgTkFGICovXG52YXIgbWogPSByZXF1aXJlKFwiQG5ldHdvcmtlZC1hZnJhbWUvbWluaWphbnVzXCIpO1xubWouSmFudXNTZXNzaW9uLnByb3RvdHlwZS5zZW5kT3JpZ2luYWwgPSBtai5KYW51c1Nlc3Npb24ucHJvdG90eXBlLnNlbmQ7XG5tai5KYW51c1Nlc3Npb24ucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbih0eXBlLCBzaWduYWwpIHtcbiAgcmV0dXJuIHRoaXMuc2VuZE9yaWdpbmFsKHR5cGUsIHNpZ25hbCkuY2F0Y2goKGUpID0+IHtcbiAgICBpZiAoZS5tZXNzYWdlICYmIGUubWVzc2FnZS5pbmRleE9mKFwidGltZWQgb3V0XCIpID4gLTEpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJ3ZWIgc29ja2V0IHRpbWVkIG91dFwiKTtcbiAgICAgIE5BRi5jb25uZWN0aW9uLmFkYXB0ZXIucmVjb25uZWN0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93KGUpO1xuICAgIH1cbiAgfSk7XG59XG5cbnZhciBzZHBVdGlscyA9IHJlcXVpcmUoXCJzZHBcIik7XG52YXIgZGVidWcgPSByZXF1aXJlKFwiZGVidWdcIikoXCJuYWYtamFudXMtYWRhcHRlcjpkZWJ1Z1wiKTtcbnZhciB3YXJuID0gcmVxdWlyZShcImRlYnVnXCIpKFwibmFmLWphbnVzLWFkYXB0ZXI6d2FyblwiKTtcbnZhciBlcnJvciA9IHJlcXVpcmUoXCJkZWJ1Z1wiKShcIm5hZi1qYW51cy1hZGFwdGVyOmVycm9yXCIpO1xudmFyIGlzU2FmYXJpID0gL14oKD8hY2hyb21lfGFuZHJvaWQpLikqc2FmYXJpL2kudGVzdChuYXZpZ2F0b3IudXNlckFnZW50KTtcblxuY29uc3QgU1VCU0NSSUJFX1RJTUVPVVRfTVMgPSAxNTAwMDtcblxuY29uc3QgQVZBSUxBQkxFX09DQ1VQQU5UU19USFJFU0hPTEQgPSA1O1xuY29uc3QgTUFYX1NVQlNDUklCRV9ERUxBWSA9IDUwMDA7XG5cbmZ1bmN0aW9uIHJhbmRvbURlbGF5KG1pbiwgbWF4KSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHtcbiAgICBjb25zdCBkZWxheSA9IE1hdGgucmFuZG9tKCkgKiAobWF4IC0gbWluKSArIG1pbjtcbiAgICBzZXRUaW1lb3V0KHJlc29sdmUsIGRlbGF5KTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGRlYm91bmNlKGZuKSB7XG4gIHZhciBjdXJyID0gUHJvbWlzZS5yZXNvbHZlKCk7XG4gIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgY3VyciA9IGN1cnIudGhlbihfID0+IGZuLmFwcGx5KHRoaXMsIGFyZ3MpKTtcbiAgfTtcbn1cblxuZnVuY3Rpb24gcmFuZG9tVWludCgpIHtcbiAgcmV0dXJuIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIE51bWJlci5NQVhfU0FGRV9JTlRFR0VSKTtcbn1cblxuZnVuY3Rpb24gdW50aWxEYXRhQ2hhbm5lbE9wZW4oZGF0YUNoYW5uZWwpIHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBpZiAoZGF0YUNoYW5uZWwucmVhZHlTdGF0ZSA9PT0gXCJvcGVuXCIpIHtcbiAgICAgIHJlc29sdmUoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbGV0IHJlc29sdmVyLCByZWplY3RvcjtcblxuICAgICAgY29uc3QgY2xlYXIgPSAoKSA9PiB7XG4gICAgICAgIGRhdGFDaGFubmVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJvcGVuXCIsIHJlc29sdmVyKTtcbiAgICAgICAgZGF0YUNoYW5uZWwucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImVycm9yXCIsIHJlamVjdG9yKTtcbiAgICAgIH07XG5cbiAgICAgIHJlc29sdmVyID0gKCkgPT4ge1xuICAgICAgICBjbGVhcigpO1xuICAgICAgICByZXNvbHZlKCk7XG4gICAgICB9O1xuICAgICAgcmVqZWN0b3IgPSAoKSA9PiB7XG4gICAgICAgIGNsZWFyKCk7XG4gICAgICAgIHJlamVjdCgpO1xuICAgICAgfTtcblxuICAgICAgZGF0YUNoYW5uZWwuYWRkRXZlbnRMaXN0ZW5lcihcIm9wZW5cIiwgcmVzb2x2ZXIpO1xuICAgICAgZGF0YUNoYW5uZWwuYWRkRXZlbnRMaXN0ZW5lcihcImVycm9yXCIsIHJlamVjdG9yKTtcbiAgICB9XG4gIH0pO1xufVxuXG5jb25zdCBpc0gyNjRWaWRlb1N1cHBvcnRlZCA9ICgoKSA9PiB7XG4gIGNvbnN0IHZpZGVvID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInZpZGVvXCIpO1xuICByZXR1cm4gdmlkZW8uY2FuUGxheVR5cGUoJ3ZpZGVvL21wNDsgY29kZWNzPVwiYXZjMS40MkUwMUUsIG1wNGEuNDAuMlwiJykgIT09IFwiXCI7XG59KSgpO1xuXG5jb25zdCBPUFVTX1BBUkFNRVRFUlMgPSB7XG4gIC8vIGluZGljYXRlcyB0aGF0IHdlIHdhbnQgdG8gZW5hYmxlIERUWCB0byBlbGlkZSBzaWxlbmNlIHBhY2tldHNcbiAgdXNlZHR4OiAxLFxuICAvLyBpbmRpY2F0ZXMgdGhhdCB3ZSBwcmVmZXIgdG8gcmVjZWl2ZSBtb25vIGF1ZGlvIChpbXBvcnRhbnQgZm9yIHZvaXAgcHJvZmlsZSlcbiAgc3RlcmVvOiAwLFxuICAvLyBpbmRpY2F0ZXMgdGhhdCB3ZSBwcmVmZXIgdG8gc2VuZCBtb25vIGF1ZGlvIChpbXBvcnRhbnQgZm9yIHZvaXAgcHJvZmlsZSlcbiAgXCJzcHJvcC1zdGVyZW9cIjogMFxufTtcblxuY29uc3QgREVGQVVMVF9QRUVSX0NPTk5FQ1RJT05fQ09ORklHID0ge1xuICBpY2VTZXJ2ZXJzOiBbeyB1cmxzOiBcInN0dW46c3R1bjEubC5nb29nbGUuY29tOjE5MzAyXCIgfSwgeyB1cmxzOiBcInN0dW46c3R1bjIubC5nb29nbGUuY29tOjE5MzAyXCIgfV1cbn07XG5cbmNvbnN0IFdTX05PUk1BTF9DTE9TVVJFID0gMTAwMDtcblxuY2xhc3MgSmFudXNBZGFwdGVyIHtcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy5yb29tID0gbnVsbDtcbiAgICAvLyBXZSBleHBlY3QgdGhlIGNvbnN1bWVyIHRvIHNldCBhIGNsaWVudCBpZCBiZWZvcmUgY29ubmVjdGluZy5cbiAgICB0aGlzLmNsaWVudElkID0gbnVsbDtcbiAgICB0aGlzLmpvaW5Ub2tlbiA9IG51bGw7XG5cbiAgICB0aGlzLnNlcnZlclVybCA9IG51bGw7XG4gICAgdGhpcy53ZWJSdGNPcHRpb25zID0ge307XG4gICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbmZpZyA9IG51bGw7XG4gICAgdGhpcy53cyA9IG51bGw7XG4gICAgdGhpcy5zZXNzaW9uID0gbnVsbDtcbiAgICB0aGlzLnJlbGlhYmxlVHJhbnNwb3J0ID0gXCJkYXRhY2hhbm5lbFwiO1xuICAgIHRoaXMudW5yZWxpYWJsZVRyYW5zcG9ydCA9IFwiZGF0YWNoYW5uZWxcIjtcblxuICAgIC8vIEluIHRoZSBldmVudCB0aGUgc2VydmVyIHJlc3RhcnRzIGFuZCBhbGwgY2xpZW50cyBsb3NlIGNvbm5lY3Rpb24sIHJlY29ubmVjdCB3aXRoXG4gICAgLy8gc29tZSByYW5kb20gaml0dGVyIGFkZGVkIHRvIHByZXZlbnQgc2ltdWx0YW5lb3VzIHJlY29ubmVjdGlvbiByZXF1ZXN0cy5cbiAgICB0aGlzLmluaXRpYWxSZWNvbm5lY3Rpb25EZWxheSA9IDEwMDAgKiBNYXRoLnJhbmRvbSgpO1xuICAgIHRoaXMucmVjb25uZWN0aW9uRGVsYXkgPSB0aGlzLmluaXRpYWxSZWNvbm5lY3Rpb25EZWxheTtcbiAgICB0aGlzLnJlY29ubmVjdGlvblRpbWVvdXQgPSBudWxsO1xuICAgIHRoaXMubWF4UmVjb25uZWN0aW9uQXR0ZW1wdHMgPSAxMDtcbiAgICB0aGlzLnJlY29ubmVjdGlvbkF0dGVtcHRzID0gMDtcblxuICAgIHRoaXMucHVibGlzaGVyID0gbnVsbDtcbiAgICB0aGlzLm9jY3VwYW50SWRzID0gW107XG4gICAgdGhpcy5vY2N1cGFudHMgPSB7fTtcbiAgICB0aGlzLm1lZGlhU3RyZWFtcyA9IHt9O1xuICAgIHRoaXMubG9jYWxNZWRpYVN0cmVhbSA9IG51bGw7XG4gICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cyA9IG5ldyBNYXAoKTtcblxuICAgIHRoaXMucGVuZGluZ09jY3VwYW50cyA9IG5ldyBTZXQoKTtcbiAgICB0aGlzLmF2YWlsYWJsZU9jY3VwYW50cyA9IFtdO1xuICAgIHRoaXMucmVxdWVzdGVkT2NjdXBhbnRzID0gbnVsbDtcblxuICAgIHRoaXMuYmxvY2tlZENsaWVudHMgPSBuZXcgTWFwKCk7XG4gICAgdGhpcy5mcm96ZW5VcGRhdGVzID0gbmV3IE1hcCgpO1xuXG4gICAgdGhpcy50aW1lT2Zmc2V0cyA9IFtdO1xuICAgIHRoaXMuc2VydmVyVGltZVJlcXVlc3RzID0gMDtcbiAgICB0aGlzLmF2Z1RpbWVPZmZzZXQgPSAwO1xuXG4gICAgdGhpcy5vbldlYnNvY2tldE9wZW4gPSB0aGlzLm9uV2Vic29ja2V0T3Blbi5iaW5kKHRoaXMpO1xuICAgIHRoaXMub25XZWJzb2NrZXRDbG9zZSA9IHRoaXMub25XZWJzb2NrZXRDbG9zZS5iaW5kKHRoaXMpO1xuICAgIHRoaXMub25XZWJzb2NrZXRNZXNzYWdlID0gdGhpcy5vbldlYnNvY2tldE1lc3NhZ2UuYmluZCh0aGlzKTtcbiAgICB0aGlzLm9uRGF0YUNoYW5uZWxNZXNzYWdlID0gdGhpcy5vbkRhdGFDaGFubmVsTWVzc2FnZS5iaW5kKHRoaXMpO1xuICAgIHRoaXMub25EYXRhID0gdGhpcy5vbkRhdGEuYmluZCh0aGlzKTtcbiAgfVxuXG4gIHNldFNlcnZlclVybCh1cmwpIHtcbiAgICB0aGlzLnNlcnZlclVybCA9IHVybDtcbiAgfVxuXG4gIHNldEFwcChhcHApIHt9XG5cbiAgc2V0Um9vbShyb29tTmFtZSkge1xuICAgIHRoaXMucm9vbSA9IHJvb21OYW1lO1xuICB9XG5cbiAgc2V0Sm9pblRva2VuKGpvaW5Ub2tlbikge1xuICAgIHRoaXMuam9pblRva2VuID0gam9pblRva2VuO1xuICB9XG5cbiAgc2V0Q2xpZW50SWQoY2xpZW50SWQpIHtcbiAgICB0aGlzLmNsaWVudElkID0gY2xpZW50SWQ7XG4gIH1cblxuICBzZXRXZWJSdGNPcHRpb25zKG9wdGlvbnMpIHtcbiAgICB0aGlzLndlYlJ0Y09wdGlvbnMgPSBvcHRpb25zO1xuICB9XG5cbiAgc2V0UGVlckNvbm5lY3Rpb25Db25maWcocGVlckNvbm5lY3Rpb25Db25maWcpIHtcbiAgICB0aGlzLnBlZXJDb25uZWN0aW9uQ29uZmlnID0gcGVlckNvbm5lY3Rpb25Db25maWc7XG4gIH1cblxuICBzZXRTZXJ2ZXJDb25uZWN0TGlzdGVuZXJzKHN1Y2Nlc3NMaXN0ZW5lciwgZmFpbHVyZUxpc3RlbmVyKSB7XG4gICAgdGhpcy5jb25uZWN0U3VjY2VzcyA9IHN1Y2Nlc3NMaXN0ZW5lcjtcbiAgICB0aGlzLmNvbm5lY3RGYWlsdXJlID0gZmFpbHVyZUxpc3RlbmVyO1xuICB9XG5cbiAgc2V0Um9vbU9jY3VwYW50TGlzdGVuZXIob2NjdXBhbnRMaXN0ZW5lcikge1xuICAgIHRoaXMub25PY2N1cGFudHNDaGFuZ2VkID0gb2NjdXBhbnRMaXN0ZW5lcjtcbiAgfVxuXG4gIHNldERhdGFDaGFubmVsTGlzdGVuZXJzKG9wZW5MaXN0ZW5lciwgY2xvc2VkTGlzdGVuZXIsIG1lc3NhZ2VMaXN0ZW5lcikge1xuICAgIHRoaXMub25PY2N1cGFudENvbm5lY3RlZCA9IG9wZW5MaXN0ZW5lcjtcbiAgICB0aGlzLm9uT2NjdXBhbnREaXNjb25uZWN0ZWQgPSBjbG9zZWRMaXN0ZW5lcjtcbiAgICB0aGlzLm9uT2NjdXBhbnRNZXNzYWdlID0gbWVzc2FnZUxpc3RlbmVyO1xuICB9XG5cbiAgc2V0UmVjb25uZWN0aW9uTGlzdGVuZXJzKHJlY29ubmVjdGluZ0xpc3RlbmVyLCByZWNvbm5lY3RlZExpc3RlbmVyLCByZWNvbm5lY3Rpb25FcnJvckxpc3RlbmVyKSB7XG4gICAgLy8gb25SZWNvbm5lY3RpbmcgaXMgY2FsbGVkIHdpdGggdGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdW50aWwgdGhlIG5leHQgcmVjb25uZWN0aW9uIGF0dGVtcHRcbiAgICB0aGlzLm9uUmVjb25uZWN0aW5nID0gcmVjb25uZWN0aW5nTGlzdGVuZXI7XG4gICAgLy8gb25SZWNvbm5lY3RlZCBpcyBjYWxsZWQgd2hlbiB0aGUgY29ubmVjdGlvbiBoYXMgYmVlbiByZWVzdGFibGlzaGVkXG4gICAgdGhpcy5vblJlY29ubmVjdGVkID0gcmVjb25uZWN0ZWRMaXN0ZW5lcjtcbiAgICAvLyBvblJlY29ubmVjdGlvbkVycm9yIGlzIGNhbGxlZCB3aXRoIGFuIGVycm9yIHdoZW4gbWF4UmVjb25uZWN0aW9uQXR0ZW1wdHMgaGFzIGJlZW4gcmVhY2hlZFxuICAgIHRoaXMub25SZWNvbm5lY3Rpb25FcnJvciA9IHJlY29ubmVjdGlvbkVycm9yTGlzdGVuZXI7XG4gIH1cblxuICBzZXRFdmVudExvb3BzKGxvb3BzKSB7XG4gICAgdGhpcy5sb29wcyA9IGxvb3BzO1xuICB9XG5cbiAgY29ubmVjdCgpIHtcbiAgICBkZWJ1ZyhgY29ubmVjdGluZyB0byAke3RoaXMuc2VydmVyVXJsfWApO1xuXG4gICAgY29uc3Qgd2Vic29ja2V0Q29ubmVjdGlvbiA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHRoaXMud3MgPSBuZXcgV2ViU29ja2V0KHRoaXMuc2VydmVyVXJsLCBcImphbnVzLXByb3RvY29sXCIpO1xuXG4gICAgICB0aGlzLnNlc3Npb24gPSBuZXcgbWouSmFudXNTZXNzaW9uKHRoaXMud3Muc2VuZC5iaW5kKHRoaXMud3MpLCB7IHRpbWVvdXRNczogNDAwMDAgfSk7XG5cbiAgICAgIHRoaXMud3MuYWRkRXZlbnRMaXN0ZW5lcihcImNsb3NlXCIsIHRoaXMub25XZWJzb2NrZXRDbG9zZSk7XG4gICAgICB0aGlzLndzLmFkZEV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIHRoaXMub25XZWJzb2NrZXRNZXNzYWdlKTtcblxuICAgICAgdGhpcy53c09uT3BlbiA9ICgpID0+IHtcbiAgICAgICAgdGhpcy53cy5yZW1vdmVFdmVudExpc3RlbmVyKFwib3BlblwiLCB0aGlzLndzT25PcGVuKTtcbiAgICAgICAgdGhpcy5vbldlYnNvY2tldE9wZW4oKVxuICAgICAgICAgIC50aGVuKHJlc29sdmUpXG4gICAgICAgICAgLmNhdGNoKHJlamVjdCk7XG4gICAgICB9O1xuXG4gICAgICB0aGlzLndzLmFkZEV2ZW50TGlzdGVuZXIoXCJvcGVuXCIsIHRoaXMud3NPbk9wZW4pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIFByb21pc2UuYWxsKFt3ZWJzb2NrZXRDb25uZWN0aW9uLCB0aGlzLnVwZGF0ZVRpbWVPZmZzZXQoKV0pO1xuICB9XG5cbiAgZGlzY29ubmVjdCgpIHtcbiAgICBkZWJ1ZyhgZGlzY29ubmVjdGluZ2ApO1xuXG4gICAgY2xlYXJUaW1lb3V0KHRoaXMucmVjb25uZWN0aW9uVGltZW91dCk7XG5cbiAgICB0aGlzLnJlbW92ZUFsbE9jY3VwYW50cygpO1xuXG4gICAgaWYgKHRoaXMucHVibGlzaGVyKSB7XG4gICAgICAvLyBDbG9zZSB0aGUgcHVibGlzaGVyIHBlZXIgY29ubmVjdGlvbi4gV2hpY2ggYWxzbyBkZXRhY2hlcyB0aGUgcGx1Z2luIGhhbmRsZS5cbiAgICAgIHRoaXMucHVibGlzaGVyLmNvbm4uY2xvc2UoKTtcbiAgICAgIHRoaXMucHVibGlzaGVyID0gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zZXNzaW9uKSB7XG4gICAgICB0aGlzLnNlc3Npb24uZGlzcG9zZSgpO1xuICAgICAgdGhpcy5zZXNzaW9uID0gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy53cykge1xuICAgICAgdGhpcy53cy5yZW1vdmVFdmVudExpc3RlbmVyKFwib3BlblwiLCB0aGlzLndzT25PcGVuKTtcbiAgICAgIHRoaXMud3MucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImNsb3NlXCIsIHRoaXMub25XZWJzb2NrZXRDbG9zZSk7XG4gICAgICB0aGlzLndzLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIHRoaXMub25XZWJzb2NrZXRNZXNzYWdlKTtcbiAgICAgIHRoaXMud3MuY2xvc2UoKTtcbiAgICAgIHRoaXMud3MgPSBudWxsO1xuICAgIH1cblxuICAgIC8vIE5vdyB0aGF0IGFsbCBSVENQZWVyQ29ubmVjdGlvbiBjbG9zZWQsIGJlIHN1cmUgdG8gbm90IGNhbGxcbiAgICAvLyByZWNvbm5lY3QoKSBhZ2FpbiB2aWEgcGVyZm9ybURlbGF5ZWRSZWNvbm5lY3QgaWYgcHJldmlvdXNcbiAgICAvLyBSVENQZWVyQ29ubmVjdGlvbiB3YXMgaW4gdGhlIGZhaWxlZCBzdGF0ZS5cbiAgICBpZiAodGhpcy5kZWxheWVkUmVjb25uZWN0VGltZW91dCkge1xuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuZGVsYXllZFJlY29ubmVjdFRpbWVvdXQpO1xuICAgICAgdGhpcy5kZWxheWVkUmVjb25uZWN0VGltZW91dCA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgaXNEaXNjb25uZWN0ZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMud3MgPT09IG51bGw7XG4gIH1cblxuICBhc3luYyBvbldlYnNvY2tldE9wZW4oKSB7XG4gICAgLy8gQ3JlYXRlIHRoZSBKYW51cyBTZXNzaW9uXG4gICAgYXdhaXQgdGhpcy5zZXNzaW9uLmNyZWF0ZSgpO1xuXG4gICAgLy8gQXR0YWNoIHRoZSBTRlUgUGx1Z2luIGFuZCBjcmVhdGUgYSBSVENQZWVyQ29ubmVjdGlvbiBmb3IgdGhlIHB1Ymxpc2hlci5cbiAgICAvLyBUaGUgcHVibGlzaGVyIHNlbmRzIGF1ZGlvIGFuZCBvcGVucyB0d28gYmlkaXJlY3Rpb25hbCBkYXRhIGNoYW5uZWxzLlxuICAgIC8vIE9uZSByZWxpYWJsZSBkYXRhY2hhbm5lbCBhbmQgb25lIHVucmVsaWFibGUuXG4gICAgdGhpcy5wdWJsaXNoZXIgPSBhd2FpdCB0aGlzLmNyZWF0ZVB1Ymxpc2hlcigpO1xuXG4gICAgLy8gQ2FsbCB0aGUgbmFmIGNvbm5lY3RTdWNjZXNzIGNhbGxiYWNrIGJlZm9yZSB3ZSBzdGFydCByZWNlaXZpbmcgV2ViUlRDIG1lc3NhZ2VzLlxuICAgIHRoaXMuY29ubmVjdFN1Y2Nlc3ModGhpcy5jbGllbnRJZCk7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMucHVibGlzaGVyLmluaXRpYWxPY2N1cGFudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IG9jY3VwYW50SWQgPSB0aGlzLnB1Ymxpc2hlci5pbml0aWFsT2NjdXBhbnRzW2ldO1xuICAgICAgaWYgKG9jY3VwYW50SWQgPT09IHRoaXMuY2xpZW50SWQpIGNvbnRpbnVlOyAvLyBIYXBwZW5zIGR1cmluZyBub24tZ3JhY2VmdWwgcmVjb25uZWN0cyBkdWUgdG8gem9tYmllIHNlc3Npb25zXG4gICAgICB0aGlzLmFkZEF2YWlsYWJsZU9jY3VwYW50KG9jY3VwYW50SWQpO1xuICAgIH1cblxuICAgIHRoaXMuc3luY09jY3VwYW50cygpO1xuICB9XG5cbiAgb25XZWJzb2NrZXRDbG9zZShldmVudCkge1xuICAgIC8vIFRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQgc3VjY2Vzc2Z1bGx5LiBEb24ndCB0cnkgdG8gcmVjb25uZWN0LlxuICAgIGlmIChldmVudC5jb2RlID09PSBXU19OT1JNQUxfQ0xPU1VSRSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnNvbGUud2FybihcIkphbnVzIHdlYnNvY2tldCBjbG9zZWQgdW5leHBlY3RlZGx5LlwiKTtcbiAgICBpZiAodGhpcy5vblJlY29ubmVjdGluZykge1xuICAgICAgdGhpcy5vblJlY29ubmVjdGluZyh0aGlzLnJlY29ubmVjdGlvbkRlbGF5KTtcbiAgICB9XG5cbiAgICB0aGlzLnJlY29ubmVjdGlvblRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHRoaXMucmVjb25uZWN0KCksIHRoaXMucmVjb25uZWN0aW9uRGVsYXkpO1xuICB9XG5cbiAgcmVjb25uZWN0KCkge1xuICAgIC8vIERpc3Bvc2Ugb2YgYWxsIG5ldHdvcmtlZCBlbnRpdGllcyBhbmQgb3RoZXIgcmVzb3VyY2VzIHRpZWQgdG8gdGhlIHNlc3Npb24uXG4gICAgdGhpcy5kaXNjb25uZWN0KCk7XG5cbiAgICB0aGlzLmNvbm5lY3QoKVxuICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICB0aGlzLnJlY29ubmVjdGlvbkRlbGF5ID0gdGhpcy5pbml0aWFsUmVjb25uZWN0aW9uRGVsYXk7XG4gICAgICAgIHRoaXMucmVjb25uZWN0aW9uQXR0ZW1wdHMgPSAwO1xuXG4gICAgICAgIGlmICh0aGlzLm9uUmVjb25uZWN0ZWQpIHtcbiAgICAgICAgICB0aGlzLm9uUmVjb25uZWN0ZWQoKTtcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICAgIC5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIHRoaXMucmVjb25uZWN0aW9uRGVsYXkgKz0gMTAwMDtcbiAgICAgICAgdGhpcy5yZWNvbm5lY3Rpb25BdHRlbXB0cysrO1xuXG4gICAgICAgIGlmICh0aGlzLnJlY29ubmVjdGlvbkF0dGVtcHRzID4gdGhpcy5tYXhSZWNvbm5lY3Rpb25BdHRlbXB0cyAmJiB0aGlzLm9uUmVjb25uZWN0aW9uRXJyb3IpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5vblJlY29ubmVjdGlvbkVycm9yKFxuICAgICAgICAgICAgbmV3IEVycm9yKFwiQ29ubmVjdGlvbiBjb3VsZCBub3QgYmUgcmVlc3RhYmxpc2hlZCwgZXhjZWVkZWQgbWF4aW11bSBudW1iZXIgb2YgcmVjb25uZWN0aW9uIGF0dGVtcHRzLlwiKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLndhcm4oXCJFcnJvciBkdXJpbmcgcmVjb25uZWN0LCByZXRyeWluZy5cIik7XG4gICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG5cbiAgICAgICAgaWYgKHRoaXMub25SZWNvbm5lY3RpbmcpIHtcbiAgICAgICAgICB0aGlzLm9uUmVjb25uZWN0aW5nKHRoaXMucmVjb25uZWN0aW9uRGVsYXkpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZWNvbm5lY3Rpb25UaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB0aGlzLnJlY29ubmVjdCgpLCB0aGlzLnJlY29ubmVjdGlvbkRlbGF5KTtcbiAgICAgIH0pO1xuICB9XG5cbiAgcGVyZm9ybURlbGF5ZWRSZWNvbm5lY3QoKSB7XG4gICAgaWYgKHRoaXMuZGVsYXllZFJlY29ubmVjdFRpbWVvdXQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLmRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0KTtcbiAgICB9XG5cbiAgICB0aGlzLmRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLmRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0ID0gbnVsbDtcbiAgICAgIHRoaXMucmVjb25uZWN0KCk7XG4gICAgfSwgMTAwMDApO1xuICB9XG5cbiAgb25XZWJzb2NrZXRNZXNzYWdlKGV2ZW50KSB7XG4gICAgdGhpcy5zZXNzaW9uLnJlY2VpdmUoSlNPTi5wYXJzZShldmVudC5kYXRhKSk7XG4gIH1cblxuICBhZGRBdmFpbGFibGVPY2N1cGFudChvY2N1cGFudElkKSB7XG4gICAgaWYgKHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmluZGV4T2Yob2NjdXBhbnRJZCkgPT09IC0xKSB7XG4gICAgICB0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5wdXNoKG9jY3VwYW50SWQpO1xuICAgIH1cbiAgfVxuXG4gIHJlbW92ZUF2YWlsYWJsZU9jY3VwYW50KG9jY3VwYW50SWQpIHtcbiAgICBjb25zdCBpZHggPSB0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpO1xuICAgIGlmIChpZHggIT09IC0xKSB7XG4gICAgICB0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5zcGxpY2UoaWR4LCAxKTtcbiAgICB9XG4gIH1cblxuICBzeW5jT2NjdXBhbnRzKHJlcXVlc3RlZE9jY3VwYW50cykge1xuICAgIGlmIChyZXF1ZXN0ZWRPY2N1cGFudHMpIHtcbiAgICAgIHRoaXMucmVxdWVzdGVkT2NjdXBhbnRzID0gcmVxdWVzdGVkT2NjdXBhbnRzO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5yZXF1ZXN0ZWRPY2N1cGFudHMpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBBZGQgYW55IHJlcXVlc3RlZCwgYXZhaWxhYmxlLCBhbmQgbm9uLXBlbmRpbmcgb2NjdXBhbnRzLlxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5yZXF1ZXN0ZWRPY2N1cGFudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IG9jY3VwYW50SWQgPSB0aGlzLnJlcXVlc3RlZE9jY3VwYW50c1tpXTtcbiAgICAgIGlmICghdGhpcy5vY2N1cGFudHNbb2NjdXBhbnRJZF0gJiYgdGhpcy5hdmFpbGFibGVPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKSAhPT0gLTEgJiYgIXRoaXMucGVuZGluZ09jY3VwYW50cy5oYXMob2NjdXBhbnRJZCkpIHtcbiAgICAgICAgdGhpcy5hZGRPY2N1cGFudChvY2N1cGFudElkKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZW1vdmUgYW55IHVucmVxdWVzdGVkIGFuZCBjdXJyZW50bHkgYWRkZWQgb2NjdXBhbnRzLlxuICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGhpcy5hdmFpbGFibGVPY2N1cGFudHMubGVuZ3RoOyBqKyspIHtcbiAgICAgIGNvbnN0IG9jY3VwYW50SWQgPSB0aGlzLmF2YWlsYWJsZU9jY3VwYW50c1tqXTtcbiAgICAgIGlmICh0aGlzLm9jY3VwYW50c1tvY2N1cGFudElkXSAmJiB0aGlzLnJlcXVlc3RlZE9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgICB0aGlzLnJlbW92ZU9jY3VwYW50KG9jY3VwYW50SWQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENhbGwgdGhlIE5ldHdvcmtlZCBBRnJhbWUgY2FsbGJhY2tzIGZvciB0aGUgdXBkYXRlZCBvY2N1cGFudHMgbGlzdC5cbiAgICB0aGlzLm9uT2NjdXBhbnRzQ2hhbmdlZCh0aGlzLm9jY3VwYW50cyk7XG4gIH1cblxuICBhc3luYyBhZGRPY2N1cGFudChvY2N1cGFudElkKSB7XG4gICAgdGhpcy5wZW5kaW5nT2NjdXBhbnRzLmFkZChvY2N1cGFudElkKTtcbiAgICBcbiAgICBjb25zdCBhdmFpbGFibGVPY2N1cGFudHNDb3VudCA9IHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmxlbmd0aDtcbiAgICBpZiAoYXZhaWxhYmxlT2NjdXBhbnRzQ291bnQgPiBBVkFJTEFCTEVfT0NDVVBBTlRTX1RIUkVTSE9MRCkge1xuICAgICAgYXdhaXQgcmFuZG9tRGVsYXkoMCwgTUFYX1NVQlNDUklCRV9ERUxBWSk7XG4gICAgfVxuICBcbiAgICBjb25zdCBzdWJzY3JpYmVyID0gYXdhaXQgdGhpcy5jcmVhdGVTdWJzY3JpYmVyKG9jY3VwYW50SWQpO1xuICAgIGlmIChzdWJzY3JpYmVyKSB7XG4gICAgICBpZighdGhpcy5wZW5kaW5nT2NjdXBhbnRzLmhhcyhvY2N1cGFudElkKSkge1xuICAgICAgICBzdWJzY3JpYmVyLmNvbm4uY2xvc2UoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMucGVuZGluZ09jY3VwYW50cy5kZWxldGUob2NjdXBhbnRJZCk7XG4gICAgICAgIHRoaXMub2NjdXBhbnRJZHMucHVzaChvY2N1cGFudElkKTtcbiAgICAgICAgdGhpcy5vY2N1cGFudHNbb2NjdXBhbnRJZF0gPSBzdWJzY3JpYmVyO1xuXG4gICAgICAgIHRoaXMuc2V0TWVkaWFTdHJlYW0ob2NjdXBhbnRJZCwgc3Vic2NyaWJlci5tZWRpYVN0cmVhbSk7XG5cbiAgICAgICAgLy8gQ2FsbCB0aGUgTmV0d29ya2VkIEFGcmFtZSBjYWxsYmFja3MgZm9yIHRoZSBuZXcgb2NjdXBhbnQuXG4gICAgICAgIHRoaXMub25PY2N1cGFudENvbm5lY3RlZChvY2N1cGFudElkKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZW1vdmVBbGxPY2N1cGFudHMoKSB7XG4gICAgdGhpcy5wZW5kaW5nT2NjdXBhbnRzLmNsZWFyKCk7XG4gICAgZm9yIChsZXQgaSA9IHRoaXMub2NjdXBhbnRJZHMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIHRoaXMucmVtb3ZlT2NjdXBhbnQodGhpcy5vY2N1cGFudElkc1tpXSk7XG4gICAgfVxuICB9XG5cbiAgcmVtb3ZlT2NjdXBhbnQob2NjdXBhbnRJZCkge1xuICAgIHRoaXMucGVuZGluZ09jY3VwYW50cy5kZWxldGUob2NjdXBhbnRJZCk7XG4gICAgXG4gICAgaWYgKHRoaXMub2NjdXBhbnRzW29jY3VwYW50SWRdKSB7XG4gICAgICAvLyBDbG9zZSB0aGUgc3Vic2NyaWJlciBwZWVyIGNvbm5lY3Rpb24uIFdoaWNoIGFsc28gZGV0YWNoZXMgdGhlIHBsdWdpbiBoYW5kbGUuXG4gICAgICB0aGlzLm9jY3VwYW50c1tvY2N1cGFudElkXS5jb25uLmNsb3NlKCk7XG4gICAgICBkZWxldGUgdGhpcy5vY2N1cGFudHNbb2NjdXBhbnRJZF07XG4gICAgICBcbiAgICAgIHRoaXMub2NjdXBhbnRJZHMuc3BsaWNlKHRoaXMub2NjdXBhbnRJZHMuaW5kZXhPZihvY2N1cGFudElkKSwgMSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMubWVkaWFTdHJlYW1zW29jY3VwYW50SWRdKSB7XG4gICAgICBkZWxldGUgdGhpcy5tZWRpYVN0cmVhbXNbb2NjdXBhbnRJZF07XG4gICAgfVxuXG4gICAgaWYgKHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuaGFzKG9jY3VwYW50SWQpKSB7XG4gICAgICBjb25zdCBtc2cgPSBcIlRoZSB1c2VyIGRpc2Nvbm5lY3RlZCBiZWZvcmUgdGhlIG1lZGlhIHN0cmVhbSB3YXMgcmVzb2x2ZWQuXCI7XG4gICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChvY2N1cGFudElkKS5hdWRpby5yZWplY3QobXNnKTtcbiAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KG9jY3VwYW50SWQpLnZpZGVvLnJlamVjdChtc2cpO1xuICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5kZWxldGUob2NjdXBhbnRJZCk7XG4gICAgfVxuXG4gICAgLy8gQ2FsbCB0aGUgTmV0d29ya2VkIEFGcmFtZSBjYWxsYmFja3MgZm9yIHRoZSByZW1vdmVkIG9jY3VwYW50LlxuICAgIHRoaXMub25PY2N1cGFudERpc2Nvbm5lY3RlZChvY2N1cGFudElkKTtcbiAgfVxuXG4gIGFzc29jaWF0ZShjb25uLCBoYW5kbGUpIHtcbiAgICBjb25uLmFkZEV2ZW50TGlzdGVuZXIoXCJpY2VjYW5kaWRhdGVcIiwgZXYgPT4ge1xuICAgICAgaGFuZGxlLnNlbmRUcmlja2xlKGV2LmNhbmRpZGF0ZSB8fCBudWxsKS5jYXRjaChlID0+IGVycm9yKFwiRXJyb3IgdHJpY2tsaW5nIElDRTogJW9cIiwgZSkpO1xuICAgIH0pO1xuICAgIGNvbm4uYWRkRXZlbnRMaXN0ZW5lcihcImljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZVwiLCBldiA9PiB7XG4gICAgICBpZiAoY29ubi5pY2VDb25uZWN0aW9uU3RhdGUgPT09IFwiY29ubmVjdGVkXCIpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJJQ0Ugc3RhdGUgY2hhbmdlZCB0byBjb25uZWN0ZWRcIik7XG4gICAgICB9XG4gICAgICBpZiAoY29ubi5pY2VDb25uZWN0aW9uU3RhdGUgPT09IFwiZGlzY29ubmVjdGVkXCIpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFwiSUNFIHN0YXRlIGNoYW5nZWQgdG8gZGlzY29ubmVjdGVkXCIpO1xuICAgICAgfVxuICAgICAgaWYgKGNvbm4uaWNlQ29ubmVjdGlvblN0YXRlID09PSBcImZhaWxlZFwiKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcIklDRSBmYWlsdXJlIGRldGVjdGVkLiBSZWNvbm5lY3RpbmcgaW4gMTBzLlwiKTtcbiAgICAgICAgdGhpcy5wZXJmb3JtRGVsYXllZFJlY29ubmVjdCgpO1xuICAgICAgfVxuICAgIH0pXG5cbiAgICAvLyB3ZSBoYXZlIHRvIGRlYm91bmNlIHRoZXNlIGJlY2F1c2UgamFudXMgZ2V0cyBhbmdyeSBpZiB5b3Ugc2VuZCBpdCBhIG5ldyBTRFAgYmVmb3JlXG4gICAgLy8gaXQncyBmaW5pc2hlZCBwcm9jZXNzaW5nIGFuIGV4aXN0aW5nIFNEUC4gaW4gYWN0dWFsaXR5LCBpdCBzZWVtcyBsaWtlIHRoaXMgaXMgbWF5YmVcbiAgICAvLyB0b28gbGliZXJhbCBhbmQgd2UgbmVlZCB0byB3YWl0IHNvbWUgYW1vdW50IG9mIHRpbWUgYWZ0ZXIgYW4gb2ZmZXIgYmVmb3JlIHNlbmRpbmcgYW5vdGhlcixcbiAgICAvLyBidXQgd2UgZG9uJ3QgY3VycmVudGx5IGtub3cgYW55IGdvb2Qgd2F5IG9mIGRldGVjdGluZyBleGFjdGx5IGhvdyBsb25nIDooXG4gICAgY29ubi5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgXCJuZWdvdGlhdGlvbm5lZWRlZFwiLFxuICAgICAgZGVib3VuY2UoZXYgPT4ge1xuICAgICAgICBkZWJ1ZyhcIlNlbmRpbmcgbmV3IG9mZmVyIGZvciBoYW5kbGU6ICVvXCIsIGhhbmRsZSk7XG4gICAgICAgIHZhciBvZmZlciA9IGNvbm4uY3JlYXRlT2ZmZXIoKS50aGVuKHRoaXMuY29uZmlndXJlUHVibGlzaGVyU2RwKS50aGVuKHRoaXMuZml4U2FmYXJpSWNlVUZyYWcpO1xuICAgICAgICB2YXIgbG9jYWwgPSBvZmZlci50aGVuKG8gPT4gY29ubi5zZXRMb2NhbERlc2NyaXB0aW9uKG8pKTtcbiAgICAgICAgdmFyIHJlbW90ZSA9IG9mZmVyO1xuXG4gICAgICAgIHJlbW90ZSA9IHJlbW90ZVxuICAgICAgICAgIC50aGVuKHRoaXMuZml4U2FmYXJpSWNlVUZyYWcpXG4gICAgICAgICAgLnRoZW4oaiA9PiBoYW5kbGUuc2VuZEpzZXAoaikpXG4gICAgICAgICAgLnRoZW4ociA9PiBjb25uLnNldFJlbW90ZURlc2NyaXB0aW9uKHIuanNlcCkpO1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwoW2xvY2FsLCByZW1vdGVdKS5jYXRjaChlID0+IGVycm9yKFwiRXJyb3IgbmVnb3RpYXRpbmcgb2ZmZXI6ICVvXCIsIGUpKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgICBoYW5kbGUub24oXG4gICAgICBcImV2ZW50XCIsXG4gICAgICBkZWJvdW5jZShldiA9PiB7XG4gICAgICAgIHZhciBqc2VwID0gZXYuanNlcDtcbiAgICAgICAgaWYgKGpzZXAgJiYganNlcC50eXBlID09IFwib2ZmZXJcIikge1xuICAgICAgICAgIGRlYnVnKFwiQWNjZXB0aW5nIG5ldyBvZmZlciBmb3IgaGFuZGxlOiAlb1wiLCBoYW5kbGUpO1xuICAgICAgICAgIHZhciBhbnN3ZXIgPSBjb25uXG4gICAgICAgICAgICAuc2V0UmVtb3RlRGVzY3JpcHRpb24odGhpcy5jb25maWd1cmVTdWJzY3JpYmVyU2RwKGpzZXApKVxuICAgICAgICAgICAgLnRoZW4oXyA9PiBjb25uLmNyZWF0ZUFuc3dlcigpKVxuICAgICAgICAgICAgLnRoZW4odGhpcy5maXhTYWZhcmlJY2VVRnJhZyk7XG4gICAgICAgICAgdmFyIGxvY2FsID0gYW5zd2VyLnRoZW4oYSA9PiBjb25uLnNldExvY2FsRGVzY3JpcHRpb24oYSkpO1xuICAgICAgICAgIHZhciByZW1vdGUgPSBhbnN3ZXIudGhlbihqID0+IGhhbmRsZS5zZW5kSnNlcChqKSk7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UuYWxsKFtsb2NhbCwgcmVtb3RlXSkuY2F0Y2goZSA9PiBlcnJvcihcIkVycm9yIG5lZ290aWF0aW5nIGFuc3dlcjogJW9cIiwgZSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIHNvbWUgb3RoZXIga2luZCBvZiBldmVudCwgbm90aGluZyB0byBkb1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBhc3luYyBjcmVhdGVQdWJsaXNoZXIoKSB7XG4gICAgdmFyIGhhbmRsZSA9IG5ldyBtai5KYW51c1BsdWdpbkhhbmRsZSh0aGlzLnNlc3Npb24pO1xuICAgIHZhciBjb25uID0gbmV3IFJUQ1BlZXJDb25uZWN0aW9uKHRoaXMucGVlckNvbm5lY3Rpb25Db25maWcgfHwgREVGQVVMVF9QRUVSX0NPTk5FQ1RJT05fQ09ORklHKTtcblxuICAgIGRlYnVnKFwicHViIHdhaXRpbmcgZm9yIHNmdVwiKTtcbiAgICBhd2FpdCBoYW5kbGUuYXR0YWNoKFwiamFudXMucGx1Z2luLnNmdVwiLCB0aGlzLmxvb3BzICYmIHRoaXMuY2xpZW50SWQgPyBwYXJzZUludCh0aGlzLmNsaWVudElkKSAlIHRoaXMubG9vcHMgOiB1bmRlZmluZWQpO1xuXG4gICAgdGhpcy5hc3NvY2lhdGUoY29ubiwgaGFuZGxlKTtcblxuICAgIGRlYnVnKFwicHViIHdhaXRpbmcgZm9yIGRhdGEgY2hhbm5lbHMgJiB3ZWJydGN1cFwiKTtcbiAgICB2YXIgd2VicnRjdXAgPSBuZXcgUHJvbWlzZShyZXNvbHZlID0+IGhhbmRsZS5vbihcIndlYnJ0Y3VwXCIsIHJlc29sdmUpKTtcblxuICAgIC8vIFVucmVsaWFibGUgZGF0YWNoYW5uZWw6IHNlbmRpbmcgYW5kIHJlY2VpdmluZyBjb21wb25lbnQgdXBkYXRlcy5cbiAgICAvLyBSZWxpYWJsZSBkYXRhY2hhbm5lbDogc2VuZGluZyBhbmQgcmVjaWV2aW5nIGVudGl0eSBpbnN0YW50aWF0aW9ucy5cbiAgICB2YXIgcmVsaWFibGVDaGFubmVsID0gY29ubi5jcmVhdGVEYXRhQ2hhbm5lbChcInJlbGlhYmxlXCIsIHsgb3JkZXJlZDogdHJ1ZSB9KTtcbiAgICB2YXIgdW5yZWxpYWJsZUNoYW5uZWwgPSBjb25uLmNyZWF0ZURhdGFDaGFubmVsKFwidW5yZWxpYWJsZVwiLCB7XG4gICAgICBvcmRlcmVkOiBmYWxzZSxcbiAgICAgIG1heFJldHJhbnNtaXRzOiAwXG4gICAgfSk7XG5cbiAgICByZWxpYWJsZUNoYW5uZWwuYWRkRXZlbnRMaXN0ZW5lcihcIm1lc3NhZ2VcIiwgZSA9PiB0aGlzLm9uRGF0YUNoYW5uZWxNZXNzYWdlKGUsIFwiamFudXMtcmVsaWFibGVcIikpO1xuICAgIHVucmVsaWFibGVDaGFubmVsLmFkZEV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIGUgPT4gdGhpcy5vbkRhdGFDaGFubmVsTWVzc2FnZShlLCBcImphbnVzLXVucmVsaWFibGVcIikpO1xuXG4gICAgYXdhaXQgd2VicnRjdXA7XG4gICAgYXdhaXQgdW50aWxEYXRhQ2hhbm5lbE9wZW4ocmVsaWFibGVDaGFubmVsKTtcbiAgICBhd2FpdCB1bnRpbERhdGFDaGFubmVsT3Blbih1bnJlbGlhYmxlQ2hhbm5lbCk7XG5cbiAgICAvLyBkb2luZyB0aGlzIGhlcmUgaXMgc29ydCBvZiBhIGhhY2sgYXJvdW5kIGNocm9tZSByZW5lZ290aWF0aW9uIHdlaXJkbmVzcyAtLVxuICAgIC8vIGlmIHdlIGRvIGl0IHByaW9yIHRvIHdlYnJ0Y3VwLCBjaHJvbWUgb24gZ2VhciBWUiB3aWxsIHNvbWV0aW1lcyBwdXQgYVxuICAgIC8vIHJlbmVnb3RpYXRpb24gb2ZmZXIgaW4gZmxpZ2h0IHdoaWxlIHRoZSBmaXJzdCBvZmZlciB3YXMgc3RpbGwgYmVpbmdcbiAgICAvLyBwcm9jZXNzZWQgYnkgamFudXMuIHdlIHNob3VsZCBmaW5kIHNvbWUgbW9yZSBwcmluY2lwbGVkIHdheSB0byBmaWd1cmUgb3V0XG4gICAgLy8gd2hlbiBqYW51cyBpcyBkb25lIGluIHRoZSBmdXR1cmUuXG4gICAgaWYgKHRoaXMubG9jYWxNZWRpYVN0cmVhbSkge1xuICAgICAgdGhpcy5sb2NhbE1lZGlhU3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2godHJhY2sgPT4ge1xuICAgICAgICBjb25uLmFkZFRyYWNrKHRyYWNrLCB0aGlzLmxvY2FsTWVkaWFTdHJlYW0pO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gSGFuZGxlIGFsbCBvZiB0aGUgam9pbiBhbmQgbGVhdmUgZXZlbnRzLlxuICAgIGhhbmRsZS5vbihcImV2ZW50XCIsIGV2ID0+IHtcbiAgICAgIHZhciBkYXRhID0gZXYucGx1Z2luZGF0YS5kYXRhO1xuICAgICAgaWYgKGRhdGEuZXZlbnQgPT0gXCJqb2luXCIgJiYgZGF0YS5yb29tX2lkID09IHRoaXMucm9vbSkge1xuICAgICAgICBpZiAodGhpcy5kZWxheWVkUmVjb25uZWN0VGltZW91dCkge1xuICAgICAgICAgIC8vIERvbid0IGNyZWF0ZSBhIG5ldyBSVENQZWVyQ29ubmVjdGlvbiwgYWxsIFJUQ1BlZXJDb25uZWN0aW9uIHdpbGwgYmUgY2xvc2VkIGluIGxlc3MgdGhhbiAxMHMuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuYWRkQXZhaWxhYmxlT2NjdXBhbnQoZGF0YS51c2VyX2lkKTtcbiAgICAgICAgdGhpcy5zeW5jT2NjdXBhbnRzKCk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnQgPT0gXCJsZWF2ZVwiICYmIGRhdGEucm9vbV9pZCA9PSB0aGlzLnJvb20pIHtcbiAgICAgICAgdGhpcy5yZW1vdmVBdmFpbGFibGVPY2N1cGFudChkYXRhLnVzZXJfaWQpO1xuICAgICAgICB0aGlzLnJlbW92ZU9jY3VwYW50KGRhdGEudXNlcl9pZCk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnQgPT0gXCJibG9ja2VkXCIpIHtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChcImJsb2NrZWRcIiwgeyBkZXRhaWw6IHsgY2xpZW50SWQ6IGRhdGEuYnkgfSB9KSk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnQgPT0gXCJ1bmJsb2NrZWRcIikge1xuICAgICAgICBkb2N1bWVudC5ib2R5LmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KFwidW5ibG9ja2VkXCIsIHsgZGV0YWlsOiB7IGNsaWVudElkOiBkYXRhLmJ5IH0gfSkpO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50ID09PSBcImRhdGFcIikge1xuICAgICAgICB0aGlzLm9uRGF0YShKU09OLnBhcnNlKGRhdGEuYm9keSksIFwiamFudXMtZXZlbnRcIik7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBkZWJ1ZyhcInB1YiB3YWl0aW5nIGZvciBqb2luXCIpO1xuXG4gICAgLy8gU2VuZCBqb2luIG1lc3NhZ2UgdG8gamFudXMuIExpc3RlbiBmb3Igam9pbi9sZWF2ZSBtZXNzYWdlcy4gQXV0b21hdGljYWxseSBzdWJzY3JpYmUgdG8gYWxsIHVzZXJzJyBXZWJSVEMgZGF0YS5cbiAgICB2YXIgbWVzc2FnZSA9IGF3YWl0IHRoaXMuc2VuZEpvaW4oaGFuZGxlLCB7XG4gICAgICBub3RpZmljYXRpb25zOiB0cnVlLFxuICAgICAgZGF0YTogdHJ1ZVxuICAgIH0pO1xuXG4gICAgaWYgKCFtZXNzYWdlLnBsdWdpbmRhdGEuZGF0YS5zdWNjZXNzKSB7XG4gICAgICBjb25zdCBlcnIgPSBtZXNzYWdlLnBsdWdpbmRhdGEuZGF0YS5lcnJvcjtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgIC8vIFdlIG1heSBnZXQgaGVyZSBiZWNhdXNlIG9mIGFuIGV4cGlyZWQgSldULlxuICAgICAgLy8gQ2xvc2UgdGhlIGNvbm5lY3Rpb24gb3Vyc2VsZiBvdGhlcndpc2UgamFudXMgd2lsbCBjbG9zZSBpdCBhZnRlclxuICAgICAgLy8gc2Vzc2lvbl90aW1lb3V0IGJlY2F1c2Ugd2UgZGlkbid0IHNlbmQgYW55IGtlZXBhbGl2ZSBhbmQgdGhpcyB3aWxsXG4gICAgICAvLyB0cmlnZ2VyIGEgZGVsYXllZCByZWNvbm5lY3QgYmVjYXVzZSBvZiB0aGUgaWNlY29ubmVjdGlvbnN0YXRlY2hhbmdlXG4gICAgICAvLyBsaXN0ZW5lciBmb3IgZmFpbHVyZSBzdGF0ZS5cbiAgICAgIC8vIEV2ZW4gaWYgdGhlIGFwcCBjb2RlIGNhbGxzIGRpc2Nvbm5lY3QgaW4gY2FzZSBvZiBlcnJvciwgZGlzY29ubmVjdFxuICAgICAgLy8gd29uJ3QgY2xvc2UgdGhlIHBlZXIgY29ubmVjdGlvbiBiZWNhdXNlIHRoaXMucHVibGlzaGVyIGlzIG5vdCBzZXQuXG4gICAgICBjb25uLmNsb3NlKCk7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuXG4gICAgdmFyIGluaXRpYWxPY2N1cGFudHMgPSBtZXNzYWdlLnBsdWdpbmRhdGEuZGF0YS5yZXNwb25zZS51c2Vyc1t0aGlzLnJvb21dIHx8IFtdO1xuXG4gICAgaWYgKGluaXRpYWxPY2N1cGFudHMuaW5jbHVkZXModGhpcy5jbGllbnRJZCkpIHtcbiAgICAgIGNvbnNvbGUud2FybihcIkphbnVzIHN0aWxsIGhhcyBwcmV2aW91cyBzZXNzaW9uIGZvciB0aGlzIGNsaWVudC4gUmVjb25uZWN0aW5nIGluIDEwcy5cIik7XG4gICAgICB0aGlzLnBlcmZvcm1EZWxheWVkUmVjb25uZWN0KCk7XG4gICAgfVxuXG4gICAgZGVidWcoXCJwdWJsaXNoZXIgcmVhZHlcIik7XG4gICAgcmV0dXJuIHtcbiAgICAgIGhhbmRsZSxcbiAgICAgIGluaXRpYWxPY2N1cGFudHMsXG4gICAgICByZWxpYWJsZUNoYW5uZWwsXG4gICAgICB1bnJlbGlhYmxlQ2hhbm5lbCxcbiAgICAgIGNvbm5cbiAgICB9O1xuICB9XG5cbiAgY29uZmlndXJlUHVibGlzaGVyU2RwKGpzZXApIHtcbiAgICBqc2VwLnNkcCA9IGpzZXAuc2RwLnJlcGxhY2UoL2E9Zm10cDooMTA5fDExMSkuKlxcclxcbi9nLCAobGluZSwgcHQpID0+IHtcbiAgICAgIGNvbnN0IHBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKHNkcFV0aWxzLnBhcnNlRm10cChsaW5lKSwgT1BVU19QQVJBTUVURVJTKTtcbiAgICAgIHJldHVybiBzZHBVdGlscy53cml0ZUZtdHAoeyBwYXlsb2FkVHlwZTogcHQsIHBhcmFtZXRlcnM6IHBhcmFtZXRlcnMgfSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIGpzZXA7XG4gIH1cblxuICBjb25maWd1cmVTdWJzY3JpYmVyU2RwKGpzZXApIHtcbiAgICAvLyB0b2RvOiBjb25zaWRlciBjbGVhbmluZyB1cCB0aGVzZSBoYWNrcyB0byB1c2Ugc2RwdXRpbHNcbiAgICBpZiAoIWlzSDI2NFZpZGVvU3VwcG9ydGVkKSB7XG4gICAgICBpZiAobmF2aWdhdG9yLnVzZXJBZ2VudC5pbmRleE9mKFwiSGVhZGxlc3NDaHJvbWVcIikgIT09IC0xKSB7XG4gICAgICAgIC8vIEhlYWRsZXNzQ2hyb21lIChlLmcuIHB1cHBldGVlcikgZG9lc24ndCBzdXBwb3J0IHdlYnJ0YyB2aWRlbyBzdHJlYW1zLCBzbyB3ZSByZW1vdmUgdGhvc2UgbGluZXMgZnJvbSB0aGUgU0RQLlxuICAgICAgICBqc2VwLnNkcCA9IGpzZXAuc2RwLnJlcGxhY2UoL209dmlkZW9bXl0qbT0vLCBcIm09XCIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFRPRE86IEhhY2sgdG8gZ2V0IHZpZGVvIHdvcmtpbmcgb24gQ2hyb21lIGZvciBBbmRyb2lkLiBodHRwczovL2dyb3Vwcy5nb29nbGUuY29tL2ZvcnVtLyMhdG9waWMvbW96aWxsYS5kZXYubWVkaWEvWWUyOXZ1TVRwbzhcbiAgICBpZiAobmF2aWdhdG9yLnVzZXJBZ2VudC5pbmRleE9mKFwiQW5kcm9pZFwiKSA9PT0gLTEpIHtcbiAgICAgIGpzZXAuc2RwID0ganNlcC5zZHAucmVwbGFjZShcbiAgICAgICAgXCJhPXJ0Y3AtZmI6MTA3IGdvb2ctcmVtYlxcclxcblwiLFxuICAgICAgICBcImE9cnRjcC1mYjoxMDcgZ29vZy1yZW1iXFxyXFxuYT1ydGNwLWZiOjEwNyB0cmFuc3BvcnQtY2NcXHJcXG5hPWZtdHA6MTA3IGxldmVsLWFzeW1tZXRyeS1hbGxvd2VkPTE7cGFja2V0aXphdGlvbi1tb2RlPTE7cHJvZmlsZS1sZXZlbC1pZD00MmUwMWZcXHJcXG5cIlxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAganNlcC5zZHAgPSBqc2VwLnNkcC5yZXBsYWNlKFxuICAgICAgICBcImE9cnRjcC1mYjoxMDcgZ29vZy1yZW1iXFxyXFxuXCIsXG4gICAgICAgIFwiYT1ydGNwLWZiOjEwNyBnb29nLXJlbWJcXHJcXG5hPXJ0Y3AtZmI6MTA3IHRyYW5zcG9ydC1jY1xcclxcbmE9Zm10cDoxMDcgbGV2ZWwtYXN5bW1ldHJ5LWFsbG93ZWQ9MTtwYWNrZXRpemF0aW9uLW1vZGU9MTtwcm9maWxlLWxldmVsLWlkPTQyMDAxZlxcclxcblwiXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4ganNlcDtcbiAgfVxuXG4gIGFzeW5jIGZpeFNhZmFyaUljZVVGcmFnKGpzZXApIHtcbiAgICAvLyBTYWZhcmkgcHJvZHVjZXMgYSBcXG4gaW5zdGVhZCBvZiBhbiBcXHJcXG4gZm9yIHRoZSBpY2UtdWZyYWcuIFNlZSBodHRwczovL2dpdGh1Yi5jb20vbWVldGVjaG8vamFudXMtZ2F0ZXdheS9pc3N1ZXMvMTgxOFxuICAgIGpzZXAuc2RwID0ganNlcC5zZHAucmVwbGFjZSgvW15cXHJdXFxuYT1pY2UtdWZyYWcvZywgXCJcXHJcXG5hPWljZS11ZnJhZ1wiKTtcbiAgICByZXR1cm4ganNlcFxuICB9XG5cbiAgYXN5bmMgY3JlYXRlU3Vic2NyaWJlcihvY2N1cGFudElkLCBtYXhSZXRyaWVzID0gNSkge1xuICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogY2FuY2VsbGVkIG9jY3VwYW50IGNvbm5lY3Rpb24sIG9jY3VwYW50IGxlZnQgYmVmb3JlIHN1YnNjcmlwdGlvbiBuZWdvdGF0aW9uLlwiKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHZhciBoYW5kbGUgPSBuZXcgbWouSmFudXNQbHVnaW5IYW5kbGUodGhpcy5zZXNzaW9uKTtcbiAgICB2YXIgY29ubiA9IG5ldyBSVENQZWVyQ29ubmVjdGlvbih0aGlzLnBlZXJDb25uZWN0aW9uQ29uZmlnIHx8IERFRkFVTFRfUEVFUl9DT05ORUNUSU9OX0NPTkZJRyk7XG5cbiAgICBkZWJ1ZyhvY2N1cGFudElkICsgXCI6IHN1YiB3YWl0aW5nIGZvciBzZnVcIik7XG4gICAgYXdhaXQgaGFuZGxlLmF0dGFjaChcImphbnVzLnBsdWdpbi5zZnVcIiwgdGhpcy5sb29wcyA/IHBhcnNlSW50KG9jY3VwYW50SWQpICUgdGhpcy5sb29wcyA6IHVuZGVmaW5lZCk7XG5cbiAgICB0aGlzLmFzc29jaWF0ZShjb25uLCBoYW5kbGUpO1xuXG4gICAgZGVidWcob2NjdXBhbnRJZCArIFwiOiBzdWIgd2FpdGluZyBmb3Igam9pblwiKTtcblxuICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgY29ubi5jbG9zZSgpO1xuICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogY2FuY2VsbGVkIG9jY3VwYW50IGNvbm5lY3Rpb24sIG9jY3VwYW50IGxlZnQgYWZ0ZXIgYXR0YWNoXCIpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgbGV0IHdlYnJ0Y0ZhaWxlZCA9IGZhbHNlO1xuXG4gICAgY29uc3Qgd2VicnRjdXAgPSBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHtcbiAgICAgIGNvbnN0IGxlZnRJbnRlcnZhbCA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgICAgaWYgKHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmluZGV4T2Yob2NjdXBhbnRJZCkgPT09IC0xKSB7XG4gICAgICAgICAgY2xlYXJJbnRlcnZhbChsZWZ0SW50ZXJ2YWwpO1xuICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgfSwgMTAwMCk7XG5cbiAgICAgIGNvbnN0IHRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgY2xlYXJJbnRlcnZhbChsZWZ0SW50ZXJ2YWwpO1xuICAgICAgICB3ZWJydGNGYWlsZWQgPSB0cnVlO1xuICAgICAgICByZXNvbHZlKCk7XG4gICAgICB9LCBTVUJTQ1JJQkVfVElNRU9VVF9NUyk7XG5cbiAgICAgIGhhbmRsZS5vbihcIndlYnJ0Y3VwXCIsICgpID0+IHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICBjbGVhckludGVydmFsKGxlZnRJbnRlcnZhbCk7XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgLy8gU2VuZCBqb2luIG1lc3NhZ2UgdG8gamFudXMuIERvbid0IGxpc3RlbiBmb3Igam9pbi9sZWF2ZSBtZXNzYWdlcy4gU3Vic2NyaWJlIHRvIHRoZSBvY2N1cGFudCdzIG1lZGlhLlxuICAgIC8vIEphbnVzIHNob3VsZCBzZW5kIHVzIGFuIG9mZmVyIGZvciB0aGlzIG9jY3VwYW50J3MgbWVkaWEgaW4gcmVzcG9uc2UgdG8gdGhpcy5cbiAgICBhd2FpdCB0aGlzLnNlbmRKb2luKGhhbmRsZSwgeyBtZWRpYTogb2NjdXBhbnRJZCB9KTtcblxuICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgY29ubi5jbG9zZSgpO1xuICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogY2FuY2VsbGVkIG9jY3VwYW50IGNvbm5lY3Rpb24sIG9jY3VwYW50IGxlZnQgYWZ0ZXIgam9pblwiKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGRlYnVnKG9jY3VwYW50SWQgKyBcIjogc3ViIHdhaXRpbmcgZm9yIHdlYnJ0Y3VwXCIpO1xuICAgIGF3YWl0IHdlYnJ0Y3VwO1xuXG4gICAgaWYgKHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmluZGV4T2Yob2NjdXBhbnRJZCkgPT09IC0xKSB7XG4gICAgICBjb25uLmNsb3NlKCk7XG4gICAgICBjb25zb2xlLndhcm4ob2NjdXBhbnRJZCArIFwiOiBjYW5jZWwgb2NjdXBhbnQgY29ubmVjdGlvbiwgb2NjdXBhbnQgbGVmdCBkdXJpbmcgb3IgYWZ0ZXIgd2VicnRjdXBcIik7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAod2VicnRjRmFpbGVkKSB7XG4gICAgICBjb25uLmNsb3NlKCk7XG4gICAgICBpZiAobWF4UmV0cmllcyA+IDApIHtcbiAgICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogd2VicnRjIHVwIHRpbWVkIG91dCwgcmV0cnlpbmdcIik7XG4gICAgICAgIHJldHVybiB0aGlzLmNyZWF0ZVN1YnNjcmliZXIob2NjdXBhbnRJZCwgbWF4UmV0cmllcyAtIDEpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogd2VicnRjIHVwIHRpbWVkIG91dFwiKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGlzU2FmYXJpICYmICF0aGlzLl9pT1NIYWNrRGVsYXllZEluaXRpYWxQZWVyKSB7XG4gICAgICAvLyBIQUNLOiB0aGUgZmlyc3QgcGVlciBvbiBTYWZhcmkgZHVyaW5nIHBhZ2UgbG9hZCBjYW4gZmFpbCB0byB3b3JrIGlmIHdlIGRvbid0XG4gICAgICAvLyB3YWl0IHNvbWUgdGltZSBiZWZvcmUgY29udGludWluZyBoZXJlLiBTZWU6IGh0dHBzOi8vZ2l0aHViLmNvbS9tb3ppbGxhL2h1YnMvcHVsbC8xNjkyXG4gICAgICBhd2FpdCAobmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgMzAwMCkpKTtcbiAgICAgIHRoaXMuX2lPU0hhY2tEZWxheWVkSW5pdGlhbFBlZXIgPSB0cnVlO1xuICAgIH1cblxuICAgIHZhciBtZWRpYVN0cmVhbSA9IG5ldyBNZWRpYVN0cmVhbSgpO1xuICAgIHZhciByZWNlaXZlcnMgPSBjb25uLmdldFJlY2VpdmVycygpO1xuICAgIHJlY2VpdmVycy5mb3JFYWNoKHJlY2VpdmVyID0+IHtcbiAgICAgIGlmIChyZWNlaXZlci50cmFjaykge1xuICAgICAgICBtZWRpYVN0cmVhbS5hZGRUcmFjayhyZWNlaXZlci50cmFjayk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgaWYgKG1lZGlhU3RyZWFtLmdldFRyYWNrcygpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgbWVkaWFTdHJlYW0gPSBudWxsO1xuICAgIH1cblxuICAgIGRlYnVnKG9jY3VwYW50SWQgKyBcIjogc3Vic2NyaWJlciByZWFkeVwiKTtcbiAgICByZXR1cm4ge1xuICAgICAgaGFuZGxlLFxuICAgICAgbWVkaWFTdHJlYW0sXG4gICAgICBjb25uXG4gICAgfTtcbiAgfVxuXG4gIHNlbmRKb2luKGhhbmRsZSwgc3Vic2NyaWJlKSB7XG4gICAgcmV0dXJuIGhhbmRsZS5zZW5kTWVzc2FnZSh7XG4gICAgICBraW5kOiBcImpvaW5cIixcbiAgICAgIHJvb21faWQ6IHRoaXMucm9vbSxcbiAgICAgIHVzZXJfaWQ6IHRoaXMuY2xpZW50SWQsXG4gICAgICBzdWJzY3JpYmUsXG4gICAgICB0b2tlbjogdGhpcy5qb2luVG9rZW5cbiAgICB9KTtcbiAgfVxuXG4gIHRvZ2dsZUZyZWV6ZSgpIHtcbiAgICBpZiAodGhpcy5mcm96ZW4pIHtcbiAgICAgIHRoaXMudW5mcmVlemUoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5mcmVlemUoKTtcbiAgICB9XG4gIH1cblxuICBmcmVlemUoKSB7XG4gICAgdGhpcy5mcm96ZW4gPSB0cnVlO1xuICB9XG5cbiAgdW5mcmVlemUoKSB7XG4gICAgdGhpcy5mcm96ZW4gPSBmYWxzZTtcbiAgICB0aGlzLmZsdXNoUGVuZGluZ1VwZGF0ZXMoKTtcbiAgfVxuXG4gIGRhdGFGb3JVcGRhdGVNdWx0aU1lc3NhZ2UobmV0d29ya0lkLCBtZXNzYWdlKSB7XG4gICAgLy8gXCJkXCIgaXMgYW4gYXJyYXkgb2YgZW50aXR5IGRhdGFzLCB3aGVyZSBlYWNoIGl0ZW0gaW4gdGhlIGFycmF5IHJlcHJlc2VudHMgYSB1bmlxdWUgZW50aXR5IGFuZCBjb250YWluc1xuICAgIC8vIG1ldGFkYXRhIGZvciB0aGUgZW50aXR5LCBhbmQgYW4gYXJyYXkgb2YgY29tcG9uZW50cyB0aGF0IGhhdmUgYmVlbiB1cGRhdGVkIG9uIHRoZSBlbnRpdHkuXG4gICAgLy8gVGhpcyBtZXRob2QgZmluZHMgdGhlIGRhdGEgY29ycmVzcG9uZGluZyB0byB0aGUgZ2l2ZW4gbmV0d29ya0lkLlxuICAgIGZvciAobGV0IGkgPSAwLCBsID0gbWVzc2FnZS5kYXRhLmQubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICBjb25zdCBkYXRhID0gbWVzc2FnZS5kYXRhLmRbaV07XG5cbiAgICAgIGlmIChkYXRhLm5ldHdvcmtJZCA9PT0gbmV0d29ya0lkKSB7XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgZ2V0UGVuZGluZ0RhdGEobmV0d29ya0lkLCBtZXNzYWdlKSB7XG4gICAgaWYgKCFtZXNzYWdlKSByZXR1cm4gbnVsbDtcblxuICAgIGxldCBkYXRhID0gbWVzc2FnZS5kYXRhVHlwZSA9PT0gXCJ1bVwiID8gdGhpcy5kYXRhRm9yVXBkYXRlTXVsdGlNZXNzYWdlKG5ldHdvcmtJZCwgbWVzc2FnZSkgOiBtZXNzYWdlLmRhdGE7XG5cbiAgICAvLyBJZ25vcmUgbWVzc2FnZXMgcmVsYXRpbmcgdG8gdXNlcnMgd2hvIGhhdmUgZGlzY29ubmVjdGVkIHNpbmNlIGZyZWV6aW5nLCB0aGVpciBlbnRpdGllc1xuICAgIC8vIHdpbGwgaGF2ZSBhbGVhZHkgYmVlbiByZW1vdmVkIGJ5IE5BRi5cbiAgICAvLyBOb3RlIHRoYXQgZGVsZXRlIG1lc3NhZ2VzIGhhdmUgbm8gXCJvd25lclwiIHNvIHdlIGhhdmUgdG8gY2hlY2sgZm9yIHRoYXQgYXMgd2VsbC5cbiAgICBpZiAoZGF0YS5vd25lciAmJiAhdGhpcy5vY2N1cGFudHNbZGF0YS5vd25lcl0pIHJldHVybiBudWxsO1xuXG4gICAgLy8gSWdub3JlIG1lc3NhZ2VzIGZyb20gdXNlcnMgdGhhdCB3ZSBtYXkgaGF2ZSBibG9ja2VkIHdoaWxlIGZyb3plbi5cbiAgICBpZiAoZGF0YS5vd25lciAmJiB0aGlzLmJsb2NrZWRDbGllbnRzLmhhcyhkYXRhLm93bmVyKSkgcmV0dXJuIG51bGw7XG5cbiAgICByZXR1cm4gZGF0YVxuICB9XG5cbiAgLy8gVXNlZCBleHRlcm5hbGx5XG4gIGdldFBlbmRpbmdEYXRhRm9yTmV0d29ya0lkKG5ldHdvcmtJZCkge1xuICAgIHJldHVybiB0aGlzLmdldFBlbmRpbmdEYXRhKG5ldHdvcmtJZCwgdGhpcy5mcm96ZW5VcGRhdGVzLmdldChuZXR3b3JrSWQpKTtcbiAgfVxuXG4gIGZsdXNoUGVuZGluZ1VwZGF0ZXMoKSB7XG4gICAgZm9yIChjb25zdCBbbmV0d29ya0lkLCBtZXNzYWdlXSBvZiB0aGlzLmZyb3plblVwZGF0ZXMpIHtcbiAgICAgIGxldCBkYXRhID0gdGhpcy5nZXRQZW5kaW5nRGF0YShuZXR3b3JrSWQsIG1lc3NhZ2UpO1xuICAgICAgaWYgKCFkYXRhKSBjb250aW51ZTtcblxuICAgICAgLy8gT3ZlcnJpZGUgdGhlIGRhdGEgdHlwZSBvbiBcInVtXCIgbWVzc2FnZXMgdHlwZXMsIHNpbmNlIHdlIGV4dHJhY3QgZW50aXR5IHVwZGF0ZXMgZnJvbSBcInVtXCIgbWVzc2FnZXMgaW50b1xuICAgICAgLy8gaW5kaXZpZHVhbCBmcm96ZW5VcGRhdGVzIGluIHN0b3JlU2luZ2xlTWVzc2FnZS5cbiAgICAgIGNvbnN0IGRhdGFUeXBlID0gbWVzc2FnZS5kYXRhVHlwZSA9PT0gXCJ1bVwiID8gXCJ1XCIgOiBtZXNzYWdlLmRhdGFUeXBlO1xuXG4gICAgICB0aGlzLm9uT2NjdXBhbnRNZXNzYWdlKG51bGwsIGRhdGFUeXBlLCBkYXRhLCBtZXNzYWdlLnNvdXJjZSk7XG4gICAgfVxuICAgIHRoaXMuZnJvemVuVXBkYXRlcy5jbGVhcigpO1xuICB9XG5cbiAgc3RvcmVNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgICBpZiAobWVzc2FnZS5kYXRhVHlwZSA9PT0gXCJ1bVwiKSB7IC8vIFVwZGF0ZU11bHRpXG4gICAgICBmb3IgKGxldCBpID0gMCwgbCA9IG1lc3NhZ2UuZGF0YS5kLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICB0aGlzLnN0b3JlU2luZ2xlTWVzc2FnZShtZXNzYWdlLCBpKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zdG9yZVNpbmdsZU1lc3NhZ2UobWVzc2FnZSk7XG4gICAgfVxuICB9XG5cbiAgc3RvcmVTaW5nbGVNZXNzYWdlKG1lc3NhZ2UsIGluZGV4KSB7XG4gICAgY29uc3QgZGF0YSA9IGluZGV4ICE9PSB1bmRlZmluZWQgPyBtZXNzYWdlLmRhdGEuZFtpbmRleF0gOiBtZXNzYWdlLmRhdGE7XG4gICAgY29uc3QgZGF0YVR5cGUgPSBtZXNzYWdlLmRhdGFUeXBlO1xuICAgIGNvbnN0IHNvdXJjZSA9IG1lc3NhZ2Uuc291cmNlO1xuXG4gICAgY29uc3QgbmV0d29ya0lkID0gZGF0YS5uZXR3b3JrSWQ7XG5cbiAgICBpZiAoIXRoaXMuZnJvemVuVXBkYXRlcy5oYXMobmV0d29ya0lkKSkge1xuICAgICAgdGhpcy5mcm96ZW5VcGRhdGVzLnNldChuZXR3b3JrSWQsIG1lc3NhZ2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBzdG9yZWRNZXNzYWdlID0gdGhpcy5mcm96ZW5VcGRhdGVzLmdldChuZXR3b3JrSWQpO1xuICAgICAgY29uc3Qgc3RvcmVkRGF0YSA9IHN0b3JlZE1lc3NhZ2UuZGF0YVR5cGUgPT09IFwidW1cIiA/IHRoaXMuZGF0YUZvclVwZGF0ZU11bHRpTWVzc2FnZShuZXR3b3JrSWQsIHN0b3JlZE1lc3NhZ2UpIDogc3RvcmVkTWVzc2FnZS5kYXRhO1xuXG4gICAgICAvLyBBdm9pZCB1cGRhdGluZyBjb21wb25lbnRzIGlmIHRoZSBlbnRpdHkgZGF0YSByZWNlaXZlZCBkaWQgbm90IGNvbWUgZnJvbSB0aGUgY3VycmVudCBvd25lci5cbiAgICAgIGNvbnN0IGlzT3V0ZGF0ZWRNZXNzYWdlID0gZGF0YS5sYXN0T3duZXJUaW1lIDwgc3RvcmVkRGF0YS5sYXN0T3duZXJUaW1lO1xuICAgICAgY29uc3QgaXNDb250ZW1wb3JhbmVvdXNNZXNzYWdlID0gZGF0YS5sYXN0T3duZXJUaW1lID09PSBzdG9yZWREYXRhLmxhc3RPd25lclRpbWU7XG4gICAgICBpZiAoaXNPdXRkYXRlZE1lc3NhZ2UgfHwgKGlzQ29udGVtcG9yYW5lb3VzTWVzc2FnZSAmJiBzdG9yZWREYXRhLm93bmVyID4gZGF0YS5vd25lcikpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZGF0YVR5cGUgPT09IFwiclwiKSB7XG4gICAgICAgIGNvbnN0IGNyZWF0ZWRXaGlsZUZyb3plbiA9IHN0b3JlZERhdGEgJiYgc3RvcmVkRGF0YS5pc0ZpcnN0U3luYztcbiAgICAgICAgaWYgKGNyZWF0ZWRXaGlsZUZyb3plbikge1xuICAgICAgICAgIC8vIElmIHRoZSBlbnRpdHkgd2FzIGNyZWF0ZWQgYW5kIGRlbGV0ZWQgd2hpbGUgZnJvemVuLCBkb24ndCBib3RoZXIgY29udmV5aW5nIGFueXRoaW5nIHRvIHRoZSBjb25zdW1lci5cbiAgICAgICAgICB0aGlzLmZyb3plblVwZGF0ZXMuZGVsZXRlKG5ldHdvcmtJZCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gRGVsZXRlIG1lc3NhZ2VzIG92ZXJyaWRlIGFueSBvdGhlciBtZXNzYWdlcyBmb3IgdGhpcyBlbnRpdHlcbiAgICAgICAgICB0aGlzLmZyb3plblVwZGF0ZXMuc2V0KG5ldHdvcmtJZCwgbWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIG1lcmdlIGluIGNvbXBvbmVudCB1cGRhdGVzXG4gICAgICAgIGlmIChzdG9yZWREYXRhLmNvbXBvbmVudHMgJiYgZGF0YS5jb21wb25lbnRzKSB7XG4gICAgICAgICAgT2JqZWN0LmFzc2lnbihzdG9yZWREYXRhLmNvbXBvbmVudHMsIGRhdGEuY29tcG9uZW50cyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBvbkRhdGFDaGFubmVsTWVzc2FnZShlLCBzb3VyY2UpIHtcbiAgICB0aGlzLm9uRGF0YShKU09OLnBhcnNlKGUuZGF0YSksIHNvdXJjZSk7XG4gIH1cblxuICBvbkRhdGEobWVzc2FnZSwgc291cmNlKSB7XG4gICAgaWYgKGRlYnVnLmVuYWJsZWQpIHtcbiAgICAgIGRlYnVnKGBEQyBpbjogJHttZXNzYWdlfWApO1xuICAgIH1cblxuICAgIGlmICghbWVzc2FnZS5kYXRhVHlwZSkgcmV0dXJuO1xuXG4gICAgbWVzc2FnZS5zb3VyY2UgPSBzb3VyY2U7XG5cbiAgICBpZiAodGhpcy5mcm96ZW4pIHtcbiAgICAgIHRoaXMuc3RvcmVNZXNzYWdlKG1lc3NhZ2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLm9uT2NjdXBhbnRNZXNzYWdlKG51bGwsIG1lc3NhZ2UuZGF0YVR5cGUsIG1lc3NhZ2UuZGF0YSwgbWVzc2FnZS5zb3VyY2UpO1xuICAgIH1cbiAgfVxuXG4gIHNob3VsZFN0YXJ0Q29ubmVjdGlvblRvKGNsaWVudCkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgc3RhcnRTdHJlYW1Db25uZWN0aW9uKGNsaWVudCkge31cblxuICBjbG9zZVN0cmVhbUNvbm5lY3Rpb24oY2xpZW50KSB7fVxuXG4gIGdldENvbm5lY3RTdGF0dXMoY2xpZW50SWQpIHtcbiAgICByZXR1cm4gdGhpcy5vY2N1cGFudHNbY2xpZW50SWRdID8gTkFGLmFkYXB0ZXJzLklTX0NPTk5FQ1RFRCA6IE5BRi5hZGFwdGVycy5OT1RfQ09OTkVDVEVEO1xuICB9XG5cbiAgYXN5bmMgdXBkYXRlVGltZU9mZnNldCgpIHtcbiAgICBpZiAodGhpcy5pc0Rpc2Nvbm5lY3RlZCgpKSByZXR1cm47XG5cbiAgICBjb25zdCBjbGllbnRTZW50VGltZSA9IERhdGUubm93KCk7XG5cbiAgICBjb25zdCByZXMgPSBhd2FpdCBmZXRjaChkb2N1bWVudC5sb2NhdGlvbi5ocmVmLCB7XG4gICAgICBtZXRob2Q6IFwiSEVBRFwiLFxuICAgICAgY2FjaGU6IFwibm8tY2FjaGVcIlxuICAgIH0pO1xuXG4gICAgY29uc3QgcHJlY2lzaW9uID0gMTAwMDtcbiAgICBjb25zdCBzZXJ2ZXJSZWNlaXZlZFRpbWUgPSBuZXcgRGF0ZShyZXMuaGVhZGVycy5nZXQoXCJEYXRlXCIpKS5nZXRUaW1lKCkgKyBwcmVjaXNpb24gLyAyO1xuICAgIGNvbnN0IGNsaWVudFJlY2VpdmVkVGltZSA9IERhdGUubm93KCk7XG4gICAgY29uc3Qgc2VydmVyVGltZSA9IHNlcnZlclJlY2VpdmVkVGltZSArIChjbGllbnRSZWNlaXZlZFRpbWUgLSBjbGllbnRTZW50VGltZSkgLyAyO1xuICAgIGNvbnN0IHRpbWVPZmZzZXQgPSBzZXJ2ZXJUaW1lIC0gY2xpZW50UmVjZWl2ZWRUaW1lO1xuXG4gICAgdGhpcy5zZXJ2ZXJUaW1lUmVxdWVzdHMrKztcblxuICAgIGlmICh0aGlzLnNlcnZlclRpbWVSZXF1ZXN0cyA8PSAxMCkge1xuICAgICAgdGhpcy50aW1lT2Zmc2V0cy5wdXNoKHRpbWVPZmZzZXQpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnRpbWVPZmZzZXRzW3RoaXMuc2VydmVyVGltZVJlcXVlc3RzICUgMTBdID0gdGltZU9mZnNldDtcbiAgICB9XG5cbiAgICB0aGlzLmF2Z1RpbWVPZmZzZXQgPSB0aGlzLnRpbWVPZmZzZXRzLnJlZHVjZSgoYWNjLCBvZmZzZXQpID0+IChhY2MgKz0gb2Zmc2V0KSwgMCkgLyB0aGlzLnRpbWVPZmZzZXRzLmxlbmd0aDtcblxuICAgIGlmICh0aGlzLnNlcnZlclRpbWVSZXF1ZXN0cyA+IDEwKSB7XG4gICAgICBkZWJ1ZyhgbmV3IHNlcnZlciB0aW1lIG9mZnNldDogJHt0aGlzLmF2Z1RpbWVPZmZzZXR9bXNgKTtcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy51cGRhdGVUaW1lT2Zmc2V0KCksIDUgKiA2MCAqIDEwMDApOyAvLyBTeW5jIGNsb2NrIGV2ZXJ5IDUgbWludXRlcy5cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy51cGRhdGVUaW1lT2Zmc2V0KCk7XG4gICAgfVxuICB9XG5cbiAgZ2V0U2VydmVyVGltZSgpIHtcbiAgICByZXR1cm4gRGF0ZS5ub3coKSArIHRoaXMuYXZnVGltZU9mZnNldDtcbiAgfVxuXG4gIGdldE1lZGlhU3RyZWFtKGNsaWVudElkLCB0eXBlID0gXCJhdWRpb1wiKSB7XG4gICAgaWYgKHRoaXMubWVkaWFTdHJlYW1zW2NsaWVudElkXSkge1xuICAgICAgZGVidWcoYEFscmVhZHkgaGFkICR7dHlwZX0gZm9yICR7Y2xpZW50SWR9YCk7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRoaXMubWVkaWFTdHJlYW1zW2NsaWVudElkXVt0eXBlXSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRlYnVnKGBXYWl0aW5nIG9uICR7dHlwZX0gZm9yICR7Y2xpZW50SWR9YCk7XG4gICAgICBpZiAoIXRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuaGFzKGNsaWVudElkKSkge1xuICAgICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLnNldChjbGllbnRJZCwge30pO1xuXG4gICAgICAgIGNvbnN0IGF1ZGlvUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChjbGllbnRJZCkuYXVkaW8gPSB7IHJlc29sdmUsIHJlamVjdCB9O1xuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgdmlkZW9Qcm9taXNlID0gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KGNsaWVudElkKS52aWRlbyA9IHsgcmVzb2x2ZSwgcmVqZWN0IH07XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KGNsaWVudElkKS5hdWRpby5wcm9taXNlID0gYXVkaW9Qcm9taXNlO1xuICAgICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChjbGllbnRJZCkudmlkZW8ucHJvbWlzZSA9IHZpZGVvUHJvbWlzZTtcblxuICAgICAgICBhdWRpb1Byb21pc2UuY2F0Y2goZSA9PiBjb25zb2xlLndhcm4oYCR7Y2xpZW50SWR9IGdldE1lZGlhU3RyZWFtIEF1ZGlvIEVycm9yYCwgZSkpO1xuICAgICAgICB2aWRlb1Byb21pc2UuY2F0Y2goZSA9PiBjb25zb2xlLndhcm4oYCR7Y2xpZW50SWR9IGdldE1lZGlhU3RyZWFtIFZpZGVvIEVycm9yYCwgZSkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KGNsaWVudElkKVt0eXBlXS5wcm9taXNlO1xuICAgIH1cbiAgfVxuXG4gIHNldE1lZGlhU3RyZWFtKGNsaWVudElkLCBzdHJlYW0pIHtcbiAgICAvLyBTYWZhcmkgZG9lc24ndCBsaWtlIGl0IHdoZW4geW91IHVzZSBzaW5nbGUgYSBtaXhlZCBtZWRpYSBzdHJlYW0gd2hlcmUgb25lIG9mIHRoZSB0cmFja3MgaXMgaW5hY3RpdmUsIHNvIHdlXG4gICAgLy8gc3BsaXQgdGhlIHRyYWNrcyBpbnRvIHR3byBzdHJlYW1zLlxuICAgIGNvbnN0IGF1ZGlvU3RyZWFtID0gbmV3IE1lZGlhU3RyZWFtKCk7XG4gICAgdHJ5IHtcbiAgICBzdHJlYW0uZ2V0QXVkaW9UcmFja3MoKS5mb3JFYWNoKHRyYWNrID0+IGF1ZGlvU3RyZWFtLmFkZFRyYWNrKHRyYWNrKSk7XG5cbiAgICB9IGNhdGNoKGUpIHtcbiAgICAgIGNvbnNvbGUud2FybihgJHtjbGllbnRJZH0gc2V0TWVkaWFTdHJlYW0gQXVkaW8gRXJyb3JgLCBlKTtcbiAgICB9XG4gICAgY29uc3QgdmlkZW9TdHJlYW0gPSBuZXcgTWVkaWFTdHJlYW0oKTtcbiAgICB0cnkge1xuICAgIHN0cmVhbS5nZXRWaWRlb1RyYWNrcygpLmZvckVhY2godHJhY2sgPT4gdmlkZW9TdHJlYW0uYWRkVHJhY2sodHJhY2spKTtcblxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnNvbGUud2FybihgJHtjbGllbnRJZH0gc2V0TWVkaWFTdHJlYW0gVmlkZW8gRXJyb3JgLCBlKTtcbiAgICB9XG5cbiAgICB0aGlzLm1lZGlhU3RyZWFtc1tjbGllbnRJZF0gPSB7IGF1ZGlvOiBhdWRpb1N0cmVhbSwgdmlkZW86IHZpZGVvU3RyZWFtIH07XG5cbiAgICAvLyBSZXNvbHZlIHRoZSBwcm9taXNlIGZvciB0aGUgdXNlcidzIG1lZGlhIHN0cmVhbSBpZiBpdCBleGlzdHMuXG4gICAgaWYgKHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuaGFzKGNsaWVudElkKSkge1xuICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5nZXQoY2xpZW50SWQpLmF1ZGlvLnJlc29sdmUoYXVkaW9TdHJlYW0pO1xuICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5nZXQoY2xpZW50SWQpLnZpZGVvLnJlc29sdmUodmlkZW9TdHJlYW0pO1xuICAgIH1cbiAgfVxuXG4gIGdldExvY2FsTWVkaWFTdHJlYW0oKSB7XG4gICAgcmV0dXJuIHRoaXMubG9jYWxNZWRpYVN0cmVhbTtcbiAgfVxuXG4gIGFzeW5jIHNldExvY2FsTWVkaWFTdHJlYW0oc3RyZWFtKSB7XG4gICAgLy8gb3VyIGpvYiBoZXJlIGlzIHRvIG1ha2Ugc3VyZSB0aGUgY29ubmVjdGlvbiB3aW5kcyB1cCB3aXRoIFJUUCBzZW5kZXJzIHNlbmRpbmcgdGhlIHN0dWZmIGluIHRoaXMgc3RyZWFtLFxuICAgIC8vIGFuZCBub3QgdGhlIHN0dWZmIHRoYXQgaXNuJ3QgaW4gdGhpcyBzdHJlYW0uIHN0cmF0ZWd5IGlzIHRvIHJlcGxhY2UgZXhpc3RpbmcgdHJhY2tzIGlmIHdlIGNhbiwgYWRkIHRyYWNrc1xuICAgIC8vIHRoYXQgd2UgY2FuJ3QgcmVwbGFjZSwgYW5kIGRpc2FibGUgdHJhY2tzIHRoYXQgZG9uJ3QgZXhpc3QgYW55bW9yZS5cblxuICAgIC8vIG5vdGUgdGhhdCB3ZSBkb24ndCBldmVyIHJlbW92ZSBhIHRyYWNrIGZyb20gdGhlIHN0cmVhbSAtLSBzaW5jZSBKYW51cyBkb2Vzbid0IHN1cHBvcnQgVW5pZmllZCBQbGFuLCB3ZSBhYnNvbHV0ZWx5XG4gICAgLy8gY2FuJ3Qgd2luZCB1cCB3aXRoIGEgU0RQIHRoYXQgaGFzID4xIGF1ZGlvIG9yID4xIHZpZGVvIHRyYWNrcywgZXZlbiBpZiBvbmUgb2YgdGhlbSBpcyBpbmFjdGl2ZSAod2hhdCB5b3UgZ2V0IGlmXG4gICAgLy8geW91IHJlbW92ZSBhIHRyYWNrIGZyb20gYW4gZXhpc3Rpbmcgc3RyZWFtLilcbiAgICBpZiAodGhpcy5wdWJsaXNoZXIgJiYgdGhpcy5wdWJsaXNoZXIuY29ubikge1xuICAgICAgY29uc3QgZXhpc3RpbmdTZW5kZXJzID0gdGhpcy5wdWJsaXNoZXIuY29ubi5nZXRTZW5kZXJzKCk7XG4gICAgICBjb25zdCBuZXdTZW5kZXJzID0gW107XG4gICAgICBjb25zdCB0cmFja3MgPSBzdHJlYW0uZ2V0VHJhY2tzKCk7XG5cbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdHJhY2tzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IHQgPSB0cmFja3NbaV07XG4gICAgICAgIGNvbnN0IHNlbmRlciA9IGV4aXN0aW5nU2VuZGVycy5maW5kKHMgPT4gcy50cmFjayAhPSBudWxsICYmIHMudHJhY2sua2luZCA9PSB0LmtpbmQpO1xuXG4gICAgICAgIGlmIChzZW5kZXIgIT0gbnVsbCkge1xuICAgICAgICAgIGlmIChzZW5kZXIucmVwbGFjZVRyYWNrKSB7XG4gICAgICAgICAgICBhd2FpdCBzZW5kZXIucmVwbGFjZVRyYWNrKHQpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBGYWxsYmFjayBmb3IgYnJvd3NlcnMgdGhhdCBkb24ndCBzdXBwb3J0IHJlcGxhY2VUcmFjay4gQXQgdGhpcyB0aW1lIG9mIHRoaXMgd3JpdGluZ1xuICAgICAgICAgICAgLy8gbW9zdCBicm93c2VycyBzdXBwb3J0IGl0LCBhbmQgdGVzdGluZyB0aGlzIGNvZGUgcGF0aCBzZWVtcyB0byBub3Qgd29yayBwcm9wZXJseVxuICAgICAgICAgICAgLy8gaW4gQ2hyb21lIGFueW1vcmUuXG4gICAgICAgICAgICBzdHJlYW0ucmVtb3ZlVHJhY2soc2VuZGVyLnRyYWNrKTtcbiAgICAgICAgICAgIHN0cmVhbS5hZGRUcmFjayh0KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgbmV3U2VuZGVycy5wdXNoKHNlbmRlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbmV3U2VuZGVycy5wdXNoKHRoaXMucHVibGlzaGVyLmNvbm4uYWRkVHJhY2sodCwgc3RyZWFtKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGV4aXN0aW5nU2VuZGVycy5mb3JFYWNoKHMgPT4ge1xuICAgICAgICBpZiAoIW5ld1NlbmRlcnMuaW5jbHVkZXMocykpIHtcbiAgICAgICAgICBzLnRyYWNrLmVuYWJsZWQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICAgIHRoaXMubG9jYWxNZWRpYVN0cmVhbSA9IHN0cmVhbTtcbiAgICB0aGlzLnNldE1lZGlhU3RyZWFtKHRoaXMuY2xpZW50SWQsIHN0cmVhbSk7XG4gIH1cblxuICBlbmFibGVNaWNyb3Bob25lKGVuYWJsZWQpIHtcbiAgICBpZiAodGhpcy5wdWJsaXNoZXIgJiYgdGhpcy5wdWJsaXNoZXIuY29ubikge1xuICAgICAgdGhpcy5wdWJsaXNoZXIuY29ubi5nZXRTZW5kZXJzKCkuZm9yRWFjaChzID0+IHtcbiAgICAgICAgaWYgKHMudHJhY2sua2luZCA9PSBcImF1ZGlvXCIpIHtcbiAgICAgICAgICBzLnRyYWNrLmVuYWJsZWQgPSBlbmFibGVkO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBzZW5kRGF0YShjbGllbnRJZCwgZGF0YVR5cGUsIGRhdGEpIHtcbiAgICBpZiAoIXRoaXMucHVibGlzaGVyKSB7XG4gICAgICBjb25zb2xlLndhcm4oXCJzZW5kRGF0YSBjYWxsZWQgd2l0aG91dCBhIHB1Ymxpc2hlclwiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3dpdGNoICh0aGlzLnVucmVsaWFibGVUcmFuc3BvcnQpIHtcbiAgICAgICAgY2FzZSBcIndlYnNvY2tldFwiOlxuICAgICAgICAgIGlmICh0aGlzLndzLnJlYWR5U3RhdGUgPT09IDEpIHsgLy8gT1BFTlxuICAgICAgICAgICAgdGhpcy5wdWJsaXNoZXIuaGFuZGxlLnNlbmRNZXNzYWdlKHsga2luZDogXCJkYXRhXCIsIGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgZGF0YVR5cGUsIGRhdGEgfSksIHdob206IGNsaWVudElkIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcImRhdGFjaGFubmVsXCI6XG4gICAgICAgICAgaWYgKHRoaXMucHVibGlzaGVyLnVucmVsaWFibGVDaGFubmVsLnJlYWR5U3RhdGUgPT09IFwib3BlblwiKSB7XG4gICAgICAgICAgICB0aGlzLnB1Ymxpc2hlci51bnJlbGlhYmxlQ2hhbm5lbC5zZW5kKEpTT04uc3RyaW5naWZ5KHsgY2xpZW50SWQsIGRhdGFUeXBlLCBkYXRhIH0pKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy51bnJlbGlhYmxlVHJhbnNwb3J0KGNsaWVudElkLCBkYXRhVHlwZSwgZGF0YSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgc2VuZERhdGFHdWFyYW50ZWVkKGNsaWVudElkLCBkYXRhVHlwZSwgZGF0YSkge1xuICAgIGlmICghdGhpcy5wdWJsaXNoZXIpIHtcbiAgICAgIGNvbnNvbGUud2FybihcInNlbmREYXRhR3VhcmFudGVlZCBjYWxsZWQgd2l0aG91dCBhIHB1Ymxpc2hlclwiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3dpdGNoICh0aGlzLnJlbGlhYmxlVHJhbnNwb3J0KSB7XG4gICAgICAgIGNhc2UgXCJ3ZWJzb2NrZXRcIjpcbiAgICAgICAgICBpZiAodGhpcy53cy5yZWFkeVN0YXRlID09PSAxKSB7IC8vIE9QRU5cbiAgICAgICAgICAgIHRoaXMucHVibGlzaGVyLmhhbmRsZS5zZW5kTWVzc2FnZSh7IGtpbmQ6IFwiZGF0YVwiLCBib2R5OiBKU09OLnN0cmluZ2lmeSh7IGRhdGFUeXBlLCBkYXRhIH0pLCB3aG9tOiBjbGllbnRJZCB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJkYXRhY2hhbm5lbFwiOlxuICAgICAgICAgIGlmICh0aGlzLnB1Ymxpc2hlci5yZWxpYWJsZUNoYW5uZWwucmVhZHlTdGF0ZSA9PT0gXCJvcGVuXCIpIHtcbiAgICAgICAgICAgIHRoaXMucHVibGlzaGVyLnJlbGlhYmxlQ2hhbm5lbC5zZW5kKEpTT04uc3RyaW5naWZ5KHsgY2xpZW50SWQsIGRhdGFUeXBlLCBkYXRhIH0pKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy5yZWxpYWJsZVRyYW5zcG9ydChjbGllbnRJZCwgZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGJyb2FkY2FzdERhdGEoZGF0YVR5cGUsIGRhdGEpIHtcbiAgICBpZiAoIXRoaXMucHVibGlzaGVyKSB7XG4gICAgICBjb25zb2xlLndhcm4oXCJicm9hZGNhc3REYXRhIGNhbGxlZCB3aXRob3V0IGEgcHVibGlzaGVyXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzd2l0Y2ggKHRoaXMudW5yZWxpYWJsZVRyYW5zcG9ydCkge1xuICAgICAgICBjYXNlIFwid2Vic29ja2V0XCI6XG4gICAgICAgICAgaWYgKHRoaXMud3MucmVhZHlTdGF0ZSA9PT0gMSkgeyAvLyBPUEVOXG4gICAgICAgICAgICB0aGlzLnB1Ymxpc2hlci5oYW5kbGUuc2VuZE1lc3NhZ2UoeyBraW5kOiBcImRhdGFcIiwgYm9keTogSlNPTi5zdHJpbmdpZnkoeyBkYXRhVHlwZSwgZGF0YSB9KSB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJkYXRhY2hhbm5lbFwiOlxuICAgICAgICAgIGlmICh0aGlzLnB1Ymxpc2hlci51bnJlbGlhYmxlQ2hhbm5lbC5yZWFkeVN0YXRlID09PSBcIm9wZW5cIikge1xuICAgICAgICAgICAgdGhpcy5wdWJsaXNoZXIudW5yZWxpYWJsZUNoYW5uZWwuc2VuZChKU09OLnN0cmluZ2lmeSh7IGRhdGFUeXBlLCBkYXRhIH0pKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy51bnJlbGlhYmxlVHJhbnNwb3J0KHVuZGVmaW5lZCwgZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGJyb2FkY2FzdERhdGFHdWFyYW50ZWVkKGRhdGFUeXBlLCBkYXRhKSB7XG4gICAgaWYgKCF0aGlzLnB1Ymxpc2hlcikge1xuICAgICAgY29uc29sZS53YXJuKFwiYnJvYWRjYXN0RGF0YUd1YXJhbnRlZWQgY2FsbGVkIHdpdGhvdXQgYSBwdWJsaXNoZXJcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXRjaCAodGhpcy5yZWxpYWJsZVRyYW5zcG9ydCkge1xuICAgICAgICBjYXNlIFwid2Vic29ja2V0XCI6XG4gICAgICAgICAgaWYgKHRoaXMud3MucmVhZHlTdGF0ZSA9PT0gMSkgeyAvLyBPUEVOXG4gICAgICAgICAgICB0aGlzLnB1Ymxpc2hlci5oYW5kbGUuc2VuZE1lc3NhZ2UoeyBraW5kOiBcImRhdGFcIiwgYm9keTogSlNPTi5zdHJpbmdpZnkoeyBkYXRhVHlwZSwgZGF0YSB9KSB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJkYXRhY2hhbm5lbFwiOlxuICAgICAgICAgIGlmICh0aGlzLnB1Ymxpc2hlci5yZWxpYWJsZUNoYW5uZWwucmVhZHlTdGF0ZSA9PT0gXCJvcGVuXCIpIHtcbiAgICAgICAgICAgIHRoaXMucHVibGlzaGVyLnJlbGlhYmxlQ2hhbm5lbC5zZW5kKEpTT04uc3RyaW5naWZ5KHsgZGF0YVR5cGUsIGRhdGEgfSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICB0aGlzLnJlbGlhYmxlVHJhbnNwb3J0KHVuZGVmaW5lZCwgZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGtpY2soY2xpZW50SWQsIHBlcm1zVG9rZW4pIHtcbiAgICByZXR1cm4gdGhpcy5wdWJsaXNoZXIuaGFuZGxlLnNlbmRNZXNzYWdlKHsga2luZDogXCJraWNrXCIsIHJvb21faWQ6IHRoaXMucm9vbSwgdXNlcl9pZDogY2xpZW50SWQsIHRva2VuOiBwZXJtc1Rva2VuIH0pLnRoZW4oKCkgPT4ge1xuICAgICAgZG9jdW1lbnQuYm9keS5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChcImtpY2tlZFwiLCB7IGRldGFpbDogeyBjbGllbnRJZDogY2xpZW50SWQgfSB9KSk7XG4gICAgfSk7XG4gIH1cblxuICBibG9jayhjbGllbnRJZCkge1xuICAgIHJldHVybiB0aGlzLnB1Ymxpc2hlci5oYW5kbGUuc2VuZE1lc3NhZ2UoeyBraW5kOiBcImJsb2NrXCIsIHdob206IGNsaWVudElkIH0pLnRoZW4oKCkgPT4ge1xuICAgICAgdGhpcy5ibG9ja2VkQ2xpZW50cy5zZXQoY2xpZW50SWQsIHRydWUpO1xuICAgICAgZG9jdW1lbnQuYm9keS5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChcImJsb2NrZWRcIiwgeyBkZXRhaWw6IHsgY2xpZW50SWQ6IGNsaWVudElkIH0gfSkpO1xuICAgIH0pO1xuICB9XG5cbiAgdW5ibG9jayhjbGllbnRJZCkge1xuICAgIHJldHVybiB0aGlzLnB1Ymxpc2hlci5oYW5kbGUuc2VuZE1lc3NhZ2UoeyBraW5kOiBcInVuYmxvY2tcIiwgd2hvbTogY2xpZW50SWQgfSkudGhlbigoKSA9PiB7XG4gICAgICB0aGlzLmJsb2NrZWRDbGllbnRzLmRlbGV0ZShjbGllbnRJZCk7XG4gICAgICBkb2N1bWVudC5ib2R5LmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KFwidW5ibG9ja2VkXCIsIHsgZGV0YWlsOiB7IGNsaWVudElkOiBjbGllbnRJZCB9IH0pKTtcbiAgICB9KTtcbiAgfVxufVxuXG5OQUYuYWRhcHRlcnMucmVnaXN0ZXIoXCJqYW51c1wiLCBKYW51c0FkYXB0ZXIpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEphbnVzQWRhcHRlcjtcbiIsIi8qIGVzbGludC1lbnYgYnJvd3NlciAqL1xuXG4vKipcbiAqIFRoaXMgaXMgdGhlIHdlYiBicm93c2VyIGltcGxlbWVudGF0aW9uIG9mIGBkZWJ1ZygpYC5cbiAqL1xuXG5leHBvcnRzLmZvcm1hdEFyZ3MgPSBmb3JtYXRBcmdzO1xuZXhwb3J0cy5zYXZlID0gc2F2ZTtcbmV4cG9ydHMubG9hZCA9IGxvYWQ7XG5leHBvcnRzLnVzZUNvbG9ycyA9IHVzZUNvbG9ycztcbmV4cG9ydHMuc3RvcmFnZSA9IGxvY2Fsc3RvcmFnZSgpO1xuZXhwb3J0cy5kZXN0cm95ID0gKCgpID0+IHtcblx0bGV0IHdhcm5lZCA9IGZhbHNlO1xuXG5cdHJldHVybiAoKSA9PiB7XG5cdFx0aWYgKCF3YXJuZWQpIHtcblx0XHRcdHdhcm5lZCA9IHRydWU7XG5cdFx0XHRjb25zb2xlLndhcm4oJ0luc3RhbmNlIG1ldGhvZCBgZGVidWcuZGVzdHJveSgpYCBpcyBkZXByZWNhdGVkIGFuZCBubyBsb25nZXIgZG9lcyBhbnl0aGluZy4gSXQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZXh0IG1ham9yIHZlcnNpb24gb2YgYGRlYnVnYC4nKTtcblx0XHR9XG5cdH07XG59KSgpO1xuXG4vKipcbiAqIENvbG9ycy5cbiAqL1xuXG5leHBvcnRzLmNvbG9ycyA9IFtcblx0JyMwMDAwQ0MnLFxuXHQnIzAwMDBGRicsXG5cdCcjMDAzM0NDJyxcblx0JyMwMDMzRkYnLFxuXHQnIzAwNjZDQycsXG5cdCcjMDA2NkZGJyxcblx0JyMwMDk5Q0MnLFxuXHQnIzAwOTlGRicsXG5cdCcjMDBDQzAwJyxcblx0JyMwMENDMzMnLFxuXHQnIzAwQ0M2NicsXG5cdCcjMDBDQzk5Jyxcblx0JyMwMENDQ0MnLFxuXHQnIzAwQ0NGRicsXG5cdCcjMzMwMENDJyxcblx0JyMzMzAwRkYnLFxuXHQnIzMzMzNDQycsXG5cdCcjMzMzM0ZGJyxcblx0JyMzMzY2Q0MnLFxuXHQnIzMzNjZGRicsXG5cdCcjMzM5OUNDJyxcblx0JyMzMzk5RkYnLFxuXHQnIzMzQ0MwMCcsXG5cdCcjMzNDQzMzJyxcblx0JyMzM0NDNjYnLFxuXHQnIzMzQ0M5OScsXG5cdCcjMzNDQ0NDJyxcblx0JyMzM0NDRkYnLFxuXHQnIzY2MDBDQycsXG5cdCcjNjYwMEZGJyxcblx0JyM2NjMzQ0MnLFxuXHQnIzY2MzNGRicsXG5cdCcjNjZDQzAwJyxcblx0JyM2NkNDMzMnLFxuXHQnIzk5MDBDQycsXG5cdCcjOTkwMEZGJyxcblx0JyM5OTMzQ0MnLFxuXHQnIzk5MzNGRicsXG5cdCcjOTlDQzAwJyxcblx0JyM5OUNDMzMnLFxuXHQnI0NDMDAwMCcsXG5cdCcjQ0MwMDMzJyxcblx0JyNDQzAwNjYnLFxuXHQnI0NDMDA5OScsXG5cdCcjQ0MwMENDJyxcblx0JyNDQzAwRkYnLFxuXHQnI0NDMzMwMCcsXG5cdCcjQ0MzMzMzJyxcblx0JyNDQzMzNjYnLFxuXHQnI0NDMzM5OScsXG5cdCcjQ0MzM0NDJyxcblx0JyNDQzMzRkYnLFxuXHQnI0NDNjYwMCcsXG5cdCcjQ0M2NjMzJyxcblx0JyNDQzk5MDAnLFxuXHQnI0NDOTkzMycsXG5cdCcjQ0NDQzAwJyxcblx0JyNDQ0NDMzMnLFxuXHQnI0ZGMDAwMCcsXG5cdCcjRkYwMDMzJyxcblx0JyNGRjAwNjYnLFxuXHQnI0ZGMDA5OScsXG5cdCcjRkYwMENDJyxcblx0JyNGRjAwRkYnLFxuXHQnI0ZGMzMwMCcsXG5cdCcjRkYzMzMzJyxcblx0JyNGRjMzNjYnLFxuXHQnI0ZGMzM5OScsXG5cdCcjRkYzM0NDJyxcblx0JyNGRjMzRkYnLFxuXHQnI0ZGNjYwMCcsXG5cdCcjRkY2NjMzJyxcblx0JyNGRjk5MDAnLFxuXHQnI0ZGOTkzMycsXG5cdCcjRkZDQzAwJyxcblx0JyNGRkNDMzMnXG5dO1xuXG4vKipcbiAqIEN1cnJlbnRseSBvbmx5IFdlYktpdC1iYXNlZCBXZWIgSW5zcGVjdG9ycywgRmlyZWZveCA+PSB2MzEsXG4gKiBhbmQgdGhlIEZpcmVidWcgZXh0ZW5zaW9uIChhbnkgRmlyZWZveCB2ZXJzaW9uKSBhcmUga25vd25cbiAqIHRvIHN1cHBvcnQgXCIlY1wiIENTUyBjdXN0b21pemF0aW9ucy5cbiAqXG4gKiBUT0RPOiBhZGQgYSBgbG9jYWxTdG9yYWdlYCB2YXJpYWJsZSB0byBleHBsaWNpdGx5IGVuYWJsZS9kaXNhYmxlIGNvbG9yc1xuICovXG5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5XG5mdW5jdGlvbiB1c2VDb2xvcnMoKSB7XG5cdC8vIE5COiBJbiBhbiBFbGVjdHJvbiBwcmVsb2FkIHNjcmlwdCwgZG9jdW1lbnQgd2lsbCBiZSBkZWZpbmVkIGJ1dCBub3QgZnVsbHlcblx0Ly8gaW5pdGlhbGl6ZWQuIFNpbmNlIHdlIGtub3cgd2UncmUgaW4gQ2hyb21lLCB3ZSdsbCBqdXN0IGRldGVjdCB0aGlzIGNhc2Vcblx0Ly8gZXhwbGljaXRseVxuXHRpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LnByb2Nlc3MgJiYgKHdpbmRvdy5wcm9jZXNzLnR5cGUgPT09ICdyZW5kZXJlcicgfHwgd2luZG93LnByb2Nlc3MuX19ud2pzKSkge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cblx0Ly8gSW50ZXJuZXQgRXhwbG9yZXIgYW5kIEVkZ2UgZG8gbm90IHN1cHBvcnQgY29sb3JzLlxuXHRpZiAodHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudCAmJiBuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCkubWF0Y2goLyhlZGdlfHRyaWRlbnQpXFwvKFxcZCspLykpIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHQvLyBJcyB3ZWJraXQ/IGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzE2NDU5NjA2LzM3Njc3M1xuXHQvLyBkb2N1bWVudCBpcyB1bmRlZmluZWQgaW4gcmVhY3QtbmF0aXZlOiBodHRwczovL2dpdGh1Yi5jb20vZmFjZWJvb2svcmVhY3QtbmF0aXZlL3B1bGwvMTYzMlxuXHRyZXR1cm4gKHR5cGVvZiBkb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50ICYmIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZSAmJiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGUuV2Via2l0QXBwZWFyYW5jZSkgfHxcblx0XHQvLyBJcyBmaXJlYnVnPyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zOTgxMjAvMzc2NzczXG5cdFx0KHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHdpbmRvdy5jb25zb2xlICYmICh3aW5kb3cuY29uc29sZS5maXJlYnVnIHx8ICh3aW5kb3cuY29uc29sZS5leGNlcHRpb24gJiYgd2luZG93LmNvbnNvbGUudGFibGUpKSkgfHxcblx0XHQvLyBJcyBmaXJlZm94ID49IHYzMT9cblx0XHQvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1Rvb2xzL1dlYl9Db25zb2xlI1N0eWxpbmdfbWVzc2FnZXNcblx0XHQodHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudCAmJiBuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCkubWF0Y2goL2ZpcmVmb3hcXC8oXFxkKykvKSAmJiBwYXJzZUludChSZWdFeHAuJDEsIDEwKSA+PSAzMSkgfHxcblx0XHQvLyBEb3VibGUgY2hlY2sgd2Via2l0IGluIHVzZXJBZ2VudCBqdXN0IGluIGNhc2Ugd2UgYXJlIGluIGEgd29ya2VyXG5cdFx0KHR5cGVvZiBuYXZpZ2F0b3IgIT09ICd1bmRlZmluZWQnICYmIG5hdmlnYXRvci51c2VyQWdlbnQgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudC50b0xvd2VyQ2FzZSgpLm1hdGNoKC9hcHBsZXdlYmtpdFxcLyhcXGQrKS8pKTtcbn1cblxuLyoqXG4gKiBDb2xvcml6ZSBsb2cgYXJndW1lbnRzIGlmIGVuYWJsZWQuXG4gKlxuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5mdW5jdGlvbiBmb3JtYXRBcmdzKGFyZ3MpIHtcblx0YXJnc1swXSA9ICh0aGlzLnVzZUNvbG9ycyA/ICclYycgOiAnJykgK1xuXHRcdHRoaXMubmFtZXNwYWNlICtcblx0XHQodGhpcy51c2VDb2xvcnMgPyAnICVjJyA6ICcgJykgK1xuXHRcdGFyZ3NbMF0gK1xuXHRcdCh0aGlzLnVzZUNvbG9ycyA/ICclYyAnIDogJyAnKSArXG5cdFx0JysnICsgbW9kdWxlLmV4cG9ydHMuaHVtYW5pemUodGhpcy5kaWZmKTtcblxuXHRpZiAoIXRoaXMudXNlQ29sb3JzKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0Y29uc3QgYyA9ICdjb2xvcjogJyArIHRoaXMuY29sb3I7XG5cdGFyZ3Muc3BsaWNlKDEsIDAsIGMsICdjb2xvcjogaW5oZXJpdCcpO1xuXG5cdC8vIFRoZSBmaW5hbCBcIiVjXCIgaXMgc29tZXdoYXQgdHJpY2t5LCBiZWNhdXNlIHRoZXJlIGNvdWxkIGJlIG90aGVyXG5cdC8vIGFyZ3VtZW50cyBwYXNzZWQgZWl0aGVyIGJlZm9yZSBvciBhZnRlciB0aGUgJWMsIHNvIHdlIG5lZWQgdG9cblx0Ly8gZmlndXJlIG91dCB0aGUgY29ycmVjdCBpbmRleCB0byBpbnNlcnQgdGhlIENTUyBpbnRvXG5cdGxldCBpbmRleCA9IDA7XG5cdGxldCBsYXN0QyA9IDA7XG5cdGFyZ3NbMF0ucmVwbGFjZSgvJVthLXpBLVolXS9nLCBtYXRjaCA9PiB7XG5cdFx0aWYgKG1hdGNoID09PSAnJSUnKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGluZGV4Kys7XG5cdFx0aWYgKG1hdGNoID09PSAnJWMnKSB7XG5cdFx0XHQvLyBXZSBvbmx5IGFyZSBpbnRlcmVzdGVkIGluIHRoZSAqbGFzdCogJWNcblx0XHRcdC8vICh0aGUgdXNlciBtYXkgaGF2ZSBwcm92aWRlZCB0aGVpciBvd24pXG5cdFx0XHRsYXN0QyA9IGluZGV4O1xuXHRcdH1cblx0fSk7XG5cblx0YXJncy5zcGxpY2UobGFzdEMsIDAsIGMpO1xufVxuXG4vKipcbiAqIEludm9rZXMgYGNvbnNvbGUuZGVidWcoKWAgd2hlbiBhdmFpbGFibGUuXG4gKiBOby1vcCB3aGVuIGBjb25zb2xlLmRlYnVnYCBpcyBub3QgYSBcImZ1bmN0aW9uXCIuXG4gKiBJZiBgY29uc29sZS5kZWJ1Z2AgaXMgbm90IGF2YWlsYWJsZSwgZmFsbHMgYmFja1xuICogdG8gYGNvbnNvbGUubG9nYC5cbiAqXG4gKiBAYXBpIHB1YmxpY1xuICovXG5leHBvcnRzLmxvZyA9IGNvbnNvbGUuZGVidWcgfHwgY29uc29sZS5sb2cgfHwgKCgpID0+IHt9KTtcblxuLyoqXG4gKiBTYXZlIGBuYW1lc3BhY2VzYC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZXNwYWNlc1xuICogQGFwaSBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIHNhdmUobmFtZXNwYWNlcykge1xuXHR0cnkge1xuXHRcdGlmIChuYW1lc3BhY2VzKSB7XG5cdFx0XHRleHBvcnRzLnN0b3JhZ2Uuc2V0SXRlbSgnZGVidWcnLCBuYW1lc3BhY2VzKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZXhwb3J0cy5zdG9yYWdlLnJlbW92ZUl0ZW0oJ2RlYnVnJyk7XG5cdFx0fVxuXHR9IGNhdGNoIChlcnJvcikge1xuXHRcdC8vIFN3YWxsb3dcblx0XHQvLyBYWFggKEBRaXgtKSBzaG91bGQgd2UgYmUgbG9nZ2luZyB0aGVzZT9cblx0fVxufVxuXG4vKipcbiAqIExvYWQgYG5hbWVzcGFjZXNgLlxuICpcbiAqIEByZXR1cm4ge1N0cmluZ30gcmV0dXJucyB0aGUgcHJldmlvdXNseSBwZXJzaXN0ZWQgZGVidWcgbW9kZXNcbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBsb2FkKCkge1xuXHRsZXQgcjtcblx0dHJ5IHtcblx0XHRyID0gZXhwb3J0cy5zdG9yYWdlLmdldEl0ZW0oJ2RlYnVnJyk7XG5cdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0Ly8gU3dhbGxvd1xuXHRcdC8vIFhYWCAoQFFpeC0pIHNob3VsZCB3ZSBiZSBsb2dnaW5nIHRoZXNlP1xuXHR9XG5cblx0Ly8gSWYgZGVidWcgaXNuJ3Qgc2V0IGluIExTLCBhbmQgd2UncmUgaW4gRWxlY3Ryb24sIHRyeSB0byBsb2FkICRERUJVR1xuXHRpZiAoIXIgJiYgdHlwZW9mIHByb2Nlc3MgIT09ICd1bmRlZmluZWQnICYmICdlbnYnIGluIHByb2Nlc3MpIHtcblx0XHRyID0gcHJvY2Vzcy5lbnYuREVCVUc7XG5cdH1cblxuXHRyZXR1cm4gcjtcbn1cblxuLyoqXG4gKiBMb2NhbHN0b3JhZ2UgYXR0ZW1wdHMgdG8gcmV0dXJuIHRoZSBsb2NhbHN0b3JhZ2UuXG4gKlxuICogVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSBzYWZhcmkgdGhyb3dzXG4gKiB3aGVuIGEgdXNlciBkaXNhYmxlcyBjb29raWVzL2xvY2Fsc3RvcmFnZVxuICogYW5kIHlvdSBhdHRlbXB0IHRvIGFjY2VzcyBpdC5cbiAqXG4gKiBAcmV0dXJuIHtMb2NhbFN0b3JhZ2V9XG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuXG5mdW5jdGlvbiBsb2NhbHN0b3JhZ2UoKSB7XG5cdHRyeSB7XG5cdFx0Ly8gVFZNTEtpdCAoQXBwbGUgVFYgSlMgUnVudGltZSkgZG9lcyBub3QgaGF2ZSBhIHdpbmRvdyBvYmplY3QsIGp1c3QgbG9jYWxTdG9yYWdlIGluIHRoZSBnbG9iYWwgY29udGV4dFxuXHRcdC8vIFRoZSBCcm93c2VyIGFsc28gaGFzIGxvY2FsU3RvcmFnZSBpbiB0aGUgZ2xvYmFsIGNvbnRleHQuXG5cdFx0cmV0dXJuIGxvY2FsU3RvcmFnZTtcblx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHQvLyBTd2FsbG93XG5cdFx0Ly8gWFhYIChAUWl4LSkgc2hvdWxkIHdlIGJlIGxvZ2dpbmcgdGhlc2U/XG5cdH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL2NvbW1vbicpKGV4cG9ydHMpO1xuXG5jb25zdCB7Zm9ybWF0dGVyc30gPSBtb2R1bGUuZXhwb3J0cztcblxuLyoqXG4gKiBNYXAgJWogdG8gYEpTT04uc3RyaW5naWZ5KClgLCBzaW5jZSBubyBXZWIgSW5zcGVjdG9ycyBkbyB0aGF0IGJ5IGRlZmF1bHQuXG4gKi9cblxuZm9ybWF0dGVycy5qID0gZnVuY3Rpb24gKHYpIHtcblx0dHJ5IHtcblx0XHRyZXR1cm4gSlNPTi5zdHJpbmdpZnkodik7XG5cdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0cmV0dXJuICdbVW5leHBlY3RlZEpTT05QYXJzZUVycm9yXTogJyArIGVycm9yLm1lc3NhZ2U7XG5cdH1cbn07XG4iLCJcbi8qKlxuICogVGhpcyBpcyB0aGUgY29tbW9uIGxvZ2ljIGZvciBib3RoIHRoZSBOb2RlLmpzIGFuZCB3ZWIgYnJvd3NlclxuICogaW1wbGVtZW50YXRpb25zIG9mIGBkZWJ1ZygpYC5cbiAqL1xuXG5mdW5jdGlvbiBzZXR1cChlbnYpIHtcblx0Y3JlYXRlRGVidWcuZGVidWcgPSBjcmVhdGVEZWJ1Zztcblx0Y3JlYXRlRGVidWcuZGVmYXVsdCA9IGNyZWF0ZURlYnVnO1xuXHRjcmVhdGVEZWJ1Zy5jb2VyY2UgPSBjb2VyY2U7XG5cdGNyZWF0ZURlYnVnLmRpc2FibGUgPSBkaXNhYmxlO1xuXHRjcmVhdGVEZWJ1Zy5lbmFibGUgPSBlbmFibGU7XG5cdGNyZWF0ZURlYnVnLmVuYWJsZWQgPSBlbmFibGVkO1xuXHRjcmVhdGVEZWJ1Zy5odW1hbml6ZSA9IHJlcXVpcmUoJ21zJyk7XG5cdGNyZWF0ZURlYnVnLmRlc3Ryb3kgPSBkZXN0cm95O1xuXG5cdE9iamVjdC5rZXlzKGVudikuZm9yRWFjaChrZXkgPT4ge1xuXHRcdGNyZWF0ZURlYnVnW2tleV0gPSBlbnZba2V5XTtcblx0fSk7XG5cblx0LyoqXG5cdCogVGhlIGN1cnJlbnRseSBhY3RpdmUgZGVidWcgbW9kZSBuYW1lcywgYW5kIG5hbWVzIHRvIHNraXAuXG5cdCovXG5cblx0Y3JlYXRlRGVidWcubmFtZXMgPSBbXTtcblx0Y3JlYXRlRGVidWcuc2tpcHMgPSBbXTtcblxuXHQvKipcblx0KiBNYXAgb2Ygc3BlY2lhbCBcIiVuXCIgaGFuZGxpbmcgZnVuY3Rpb25zLCBmb3IgdGhlIGRlYnVnIFwiZm9ybWF0XCIgYXJndW1lbnQuXG5cdCpcblx0KiBWYWxpZCBrZXkgbmFtZXMgYXJlIGEgc2luZ2xlLCBsb3dlciBvciB1cHBlci1jYXNlIGxldHRlciwgaS5lLiBcIm5cIiBhbmQgXCJOXCIuXG5cdCovXG5cdGNyZWF0ZURlYnVnLmZvcm1hdHRlcnMgPSB7fTtcblxuXHQvKipcblx0KiBTZWxlY3RzIGEgY29sb3IgZm9yIGEgZGVidWcgbmFtZXNwYWNlXG5cdCogQHBhcmFtIHtTdHJpbmd9IG5hbWVzcGFjZSBUaGUgbmFtZXNwYWNlIHN0cmluZyBmb3IgdGhlIGRlYnVnIGluc3RhbmNlIHRvIGJlIGNvbG9yZWRcblx0KiBAcmV0dXJuIHtOdW1iZXJ8U3RyaW5nfSBBbiBBTlNJIGNvbG9yIGNvZGUgZm9yIHRoZSBnaXZlbiBuYW1lc3BhY2Vcblx0KiBAYXBpIHByaXZhdGVcblx0Ki9cblx0ZnVuY3Rpb24gc2VsZWN0Q29sb3IobmFtZXNwYWNlKSB7XG5cdFx0bGV0IGhhc2ggPSAwO1xuXG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBuYW1lc3BhY2UubGVuZ3RoOyBpKyspIHtcblx0XHRcdGhhc2ggPSAoKGhhc2ggPDwgNSkgLSBoYXNoKSArIG5hbWVzcGFjZS5jaGFyQ29kZUF0KGkpO1xuXHRcdFx0aGFzaCB8PSAwOyAvLyBDb252ZXJ0IHRvIDMyYml0IGludGVnZXJcblx0XHR9XG5cblx0XHRyZXR1cm4gY3JlYXRlRGVidWcuY29sb3JzW01hdGguYWJzKGhhc2gpICUgY3JlYXRlRGVidWcuY29sb3JzLmxlbmd0aF07XG5cdH1cblx0Y3JlYXRlRGVidWcuc2VsZWN0Q29sb3IgPSBzZWxlY3RDb2xvcjtcblxuXHQvKipcblx0KiBDcmVhdGUgYSBkZWJ1Z2dlciB3aXRoIHRoZSBnaXZlbiBgbmFtZXNwYWNlYC5cblx0KlxuXHQqIEBwYXJhbSB7U3RyaW5nfSBuYW1lc3BhY2Vcblx0KiBAcmV0dXJuIHtGdW5jdGlvbn1cblx0KiBAYXBpIHB1YmxpY1xuXHQqL1xuXHRmdW5jdGlvbiBjcmVhdGVEZWJ1ZyhuYW1lc3BhY2UpIHtcblx0XHRsZXQgcHJldlRpbWU7XG5cdFx0bGV0IGVuYWJsZU92ZXJyaWRlID0gbnVsbDtcblx0XHRsZXQgbmFtZXNwYWNlc0NhY2hlO1xuXHRcdGxldCBlbmFibGVkQ2FjaGU7XG5cblx0XHRmdW5jdGlvbiBkZWJ1ZyguLi5hcmdzKSB7XG5cdFx0XHQvLyBEaXNhYmxlZD9cblx0XHRcdGlmICghZGVidWcuZW5hYmxlZCkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHNlbGYgPSBkZWJ1ZztcblxuXHRcdFx0Ly8gU2V0IGBkaWZmYCB0aW1lc3RhbXBcblx0XHRcdGNvbnN0IGN1cnIgPSBOdW1iZXIobmV3IERhdGUoKSk7XG5cdFx0XHRjb25zdCBtcyA9IGN1cnIgLSAocHJldlRpbWUgfHwgY3Vycik7XG5cdFx0XHRzZWxmLmRpZmYgPSBtcztcblx0XHRcdHNlbGYucHJldiA9IHByZXZUaW1lO1xuXHRcdFx0c2VsZi5jdXJyID0gY3Vycjtcblx0XHRcdHByZXZUaW1lID0gY3VycjtcblxuXHRcdFx0YXJnc1swXSA9IGNyZWF0ZURlYnVnLmNvZXJjZShhcmdzWzBdKTtcblxuXHRcdFx0aWYgKHR5cGVvZiBhcmdzWzBdICE9PSAnc3RyaW5nJykge1xuXHRcdFx0XHQvLyBBbnl0aGluZyBlbHNlIGxldCdzIGluc3BlY3Qgd2l0aCAlT1xuXHRcdFx0XHRhcmdzLnVuc2hpZnQoJyVPJyk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFwcGx5IGFueSBgZm9ybWF0dGVyc2AgdHJhbnNmb3JtYXRpb25zXG5cdFx0XHRsZXQgaW5kZXggPSAwO1xuXHRcdFx0YXJnc1swXSA9IGFyZ3NbMF0ucmVwbGFjZSgvJShbYS16QS1aJV0pL2csIChtYXRjaCwgZm9ybWF0KSA9PiB7XG5cdFx0XHRcdC8vIElmIHdlIGVuY291bnRlciBhbiBlc2NhcGVkICUgdGhlbiBkb24ndCBpbmNyZWFzZSB0aGUgYXJyYXkgaW5kZXhcblx0XHRcdFx0aWYgKG1hdGNoID09PSAnJSUnKSB7XG5cdFx0XHRcdFx0cmV0dXJuICclJztcblx0XHRcdFx0fVxuXHRcdFx0XHRpbmRleCsrO1xuXHRcdFx0XHRjb25zdCBmb3JtYXR0ZXIgPSBjcmVhdGVEZWJ1Zy5mb3JtYXR0ZXJzW2Zvcm1hdF07XG5cdFx0XHRcdGlmICh0eXBlb2YgZm9ybWF0dGVyID09PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRcdFx0Y29uc3QgdmFsID0gYXJnc1tpbmRleF07XG5cdFx0XHRcdFx0bWF0Y2ggPSBmb3JtYXR0ZXIuY2FsbChzZWxmLCB2YWwpO1xuXG5cdFx0XHRcdFx0Ly8gTm93IHdlIG5lZWQgdG8gcmVtb3ZlIGBhcmdzW2luZGV4XWAgc2luY2UgaXQncyBpbmxpbmVkIGluIHRoZSBgZm9ybWF0YFxuXHRcdFx0XHRcdGFyZ3Muc3BsaWNlKGluZGV4LCAxKTtcblx0XHRcdFx0XHRpbmRleC0tO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBtYXRjaDtcblx0XHRcdH0pO1xuXG5cdFx0XHQvLyBBcHBseSBlbnYtc3BlY2lmaWMgZm9ybWF0dGluZyAoY29sb3JzLCBldGMuKVxuXHRcdFx0Y3JlYXRlRGVidWcuZm9ybWF0QXJncy5jYWxsKHNlbGYsIGFyZ3MpO1xuXG5cdFx0XHRjb25zdCBsb2dGbiA9IHNlbGYubG9nIHx8IGNyZWF0ZURlYnVnLmxvZztcblx0XHRcdGxvZ0ZuLmFwcGx5KHNlbGYsIGFyZ3MpO1xuXHRcdH1cblxuXHRcdGRlYnVnLm5hbWVzcGFjZSA9IG5hbWVzcGFjZTtcblx0XHRkZWJ1Zy51c2VDb2xvcnMgPSBjcmVhdGVEZWJ1Zy51c2VDb2xvcnMoKTtcblx0XHRkZWJ1Zy5jb2xvciA9IGNyZWF0ZURlYnVnLnNlbGVjdENvbG9yKG5hbWVzcGFjZSk7XG5cdFx0ZGVidWcuZXh0ZW5kID0gZXh0ZW5kO1xuXHRcdGRlYnVnLmRlc3Ryb3kgPSBjcmVhdGVEZWJ1Zy5kZXN0cm95OyAvLyBYWFggVGVtcG9yYXJ5LiBXaWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5leHQgbWFqb3IgcmVsZWFzZS5cblxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShkZWJ1ZywgJ2VuYWJsZWQnLCB7XG5cdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuXHRcdFx0Y29uZmlndXJhYmxlOiBmYWxzZSxcblx0XHRcdGdldDogKCkgPT4ge1xuXHRcdFx0XHRpZiAoZW5hYmxlT3ZlcnJpZGUgIT09IG51bGwpIHtcblx0XHRcdFx0XHRyZXR1cm4gZW5hYmxlT3ZlcnJpZGU7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKG5hbWVzcGFjZXNDYWNoZSAhPT0gY3JlYXRlRGVidWcubmFtZXNwYWNlcykge1xuXHRcdFx0XHRcdG5hbWVzcGFjZXNDYWNoZSA9IGNyZWF0ZURlYnVnLm5hbWVzcGFjZXM7XG5cdFx0XHRcdFx0ZW5hYmxlZENhY2hlID0gY3JlYXRlRGVidWcuZW5hYmxlZChuYW1lc3BhY2UpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIGVuYWJsZWRDYWNoZTtcblx0XHRcdH0sXG5cdFx0XHRzZXQ6IHYgPT4ge1xuXHRcdFx0XHRlbmFibGVPdmVycmlkZSA9IHY7XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHQvLyBFbnYtc3BlY2lmaWMgaW5pdGlhbGl6YXRpb24gbG9naWMgZm9yIGRlYnVnIGluc3RhbmNlc1xuXHRcdGlmICh0eXBlb2YgY3JlYXRlRGVidWcuaW5pdCA9PT0gJ2Z1bmN0aW9uJykge1xuXHRcdFx0Y3JlYXRlRGVidWcuaW5pdChkZWJ1Zyk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRlYnVnO1xuXHR9XG5cblx0ZnVuY3Rpb24gZXh0ZW5kKG5hbWVzcGFjZSwgZGVsaW1pdGVyKSB7XG5cdFx0Y29uc3QgbmV3RGVidWcgPSBjcmVhdGVEZWJ1Zyh0aGlzLm5hbWVzcGFjZSArICh0eXBlb2YgZGVsaW1pdGVyID09PSAndW5kZWZpbmVkJyA/ICc6JyA6IGRlbGltaXRlcikgKyBuYW1lc3BhY2UpO1xuXHRcdG5ld0RlYnVnLmxvZyA9IHRoaXMubG9nO1xuXHRcdHJldHVybiBuZXdEZWJ1Zztcblx0fVxuXG5cdC8qKlxuXHQqIEVuYWJsZXMgYSBkZWJ1ZyBtb2RlIGJ5IG5hbWVzcGFjZXMuIFRoaXMgY2FuIGluY2x1ZGUgbW9kZXNcblx0KiBzZXBhcmF0ZWQgYnkgYSBjb2xvbiBhbmQgd2lsZGNhcmRzLlxuXHQqXG5cdCogQHBhcmFtIHtTdHJpbmd9IG5hbWVzcGFjZXNcblx0KiBAYXBpIHB1YmxpY1xuXHQqL1xuXHRmdW5jdGlvbiBlbmFibGUobmFtZXNwYWNlcykge1xuXHRcdGNyZWF0ZURlYnVnLnNhdmUobmFtZXNwYWNlcyk7XG5cdFx0Y3JlYXRlRGVidWcubmFtZXNwYWNlcyA9IG5hbWVzcGFjZXM7XG5cblx0XHRjcmVhdGVEZWJ1Zy5uYW1lcyA9IFtdO1xuXHRcdGNyZWF0ZURlYnVnLnNraXBzID0gW107XG5cblx0XHRsZXQgaTtcblx0XHRjb25zdCBzcGxpdCA9ICh0eXBlb2YgbmFtZXNwYWNlcyA9PT0gJ3N0cmluZycgPyBuYW1lc3BhY2VzIDogJycpLnNwbGl0KC9bXFxzLF0rLyk7XG5cdFx0Y29uc3QgbGVuID0gc3BsaXQubGVuZ3RoO1xuXG5cdFx0Zm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRpZiAoIXNwbGl0W2ldKSB7XG5cdFx0XHRcdC8vIGlnbm9yZSBlbXB0eSBzdHJpbmdzXG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXG5cdFx0XHRuYW1lc3BhY2VzID0gc3BsaXRbaV0ucmVwbGFjZSgvXFwqL2csICcuKj8nKTtcblxuXHRcdFx0aWYgKG5hbWVzcGFjZXNbMF0gPT09ICctJykge1xuXHRcdFx0XHRjcmVhdGVEZWJ1Zy5za2lwcy5wdXNoKG5ldyBSZWdFeHAoJ14nICsgbmFtZXNwYWNlcy5zbGljZSgxKSArICckJykpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y3JlYXRlRGVidWcubmFtZXMucHVzaChuZXcgUmVnRXhwKCdeJyArIG5hbWVzcGFjZXMgKyAnJCcpKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvKipcblx0KiBEaXNhYmxlIGRlYnVnIG91dHB1dC5cblx0KlxuXHQqIEByZXR1cm4ge1N0cmluZ30gbmFtZXNwYWNlc1xuXHQqIEBhcGkgcHVibGljXG5cdCovXG5cdGZ1bmN0aW9uIGRpc2FibGUoKSB7XG5cdFx0Y29uc3QgbmFtZXNwYWNlcyA9IFtcblx0XHRcdC4uLmNyZWF0ZURlYnVnLm5hbWVzLm1hcCh0b05hbWVzcGFjZSksXG5cdFx0XHQuLi5jcmVhdGVEZWJ1Zy5za2lwcy5tYXAodG9OYW1lc3BhY2UpLm1hcChuYW1lc3BhY2UgPT4gJy0nICsgbmFtZXNwYWNlKVxuXHRcdF0uam9pbignLCcpO1xuXHRcdGNyZWF0ZURlYnVnLmVuYWJsZSgnJyk7XG5cdFx0cmV0dXJuIG5hbWVzcGFjZXM7XG5cdH1cblxuXHQvKipcblx0KiBSZXR1cm5zIHRydWUgaWYgdGhlIGdpdmVuIG1vZGUgbmFtZSBpcyBlbmFibGVkLCBmYWxzZSBvdGhlcndpc2UuXG5cdCpcblx0KiBAcGFyYW0ge1N0cmluZ30gbmFtZVxuXHQqIEByZXR1cm4ge0Jvb2xlYW59XG5cdCogQGFwaSBwdWJsaWNcblx0Ki9cblx0ZnVuY3Rpb24gZW5hYmxlZChuYW1lKSB7XG5cdFx0aWYgKG5hbWVbbmFtZS5sZW5ndGggLSAxXSA9PT0gJyonKSB7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9XG5cblx0XHRsZXQgaTtcblx0XHRsZXQgbGVuO1xuXG5cdFx0Zm9yIChpID0gMCwgbGVuID0gY3JlYXRlRGVidWcuc2tpcHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdGlmIChjcmVhdGVEZWJ1Zy5za2lwc1tpXS50ZXN0KG5hbWUpKSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBjcmVhdGVEZWJ1Zy5uYW1lcy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuXHRcdFx0aWYgKGNyZWF0ZURlYnVnLm5hbWVzW2ldLnRlc3QobmFtZSkpIHtcblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG5cblx0LyoqXG5cdCogQ29udmVydCByZWdleHAgdG8gbmFtZXNwYWNlXG5cdCpcblx0KiBAcGFyYW0ge1JlZ0V4cH0gcmVneGVwXG5cdCogQHJldHVybiB7U3RyaW5nfSBuYW1lc3BhY2Vcblx0KiBAYXBpIHByaXZhdGVcblx0Ki9cblx0ZnVuY3Rpb24gdG9OYW1lc3BhY2UocmVnZXhwKSB7XG5cdFx0cmV0dXJuIHJlZ2V4cC50b1N0cmluZygpXG5cdFx0XHQuc3Vic3RyaW5nKDIsIHJlZ2V4cC50b1N0cmluZygpLmxlbmd0aCAtIDIpXG5cdFx0XHQucmVwbGFjZSgvXFwuXFwqXFw/JC8sICcqJyk7XG5cdH1cblxuXHQvKipcblx0KiBDb2VyY2UgYHZhbGAuXG5cdCpcblx0KiBAcGFyYW0ge01peGVkfSB2YWxcblx0KiBAcmV0dXJuIHtNaXhlZH1cblx0KiBAYXBpIHByaXZhdGVcblx0Ki9cblx0ZnVuY3Rpb24gY29lcmNlKHZhbCkge1xuXHRcdGlmICh2YWwgaW5zdGFuY2VvZiBFcnJvcikge1xuXHRcdFx0cmV0dXJuIHZhbC5zdGFjayB8fCB2YWwubWVzc2FnZTtcblx0XHR9XG5cdFx0cmV0dXJuIHZhbDtcblx0fVxuXG5cdC8qKlxuXHQqIFhYWCBETyBOT1QgVVNFLiBUaGlzIGlzIGEgdGVtcG9yYXJ5IHN0dWIgZnVuY3Rpb24uXG5cdCogWFhYIEl0IFdJTEwgYmUgcmVtb3ZlZCBpbiB0aGUgbmV4dCBtYWpvciByZWxlYXNlLlxuXHQqL1xuXHRmdW5jdGlvbiBkZXN0cm95KCkge1xuXHRcdGNvbnNvbGUud2FybignSW5zdGFuY2UgbWV0aG9kIGBkZWJ1Zy5kZXN0cm95KClgIGlzIGRlcHJlY2F0ZWQgYW5kIG5vIGxvbmdlciBkb2VzIGFueXRoaW5nLiBJdCB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5leHQgbWFqb3IgdmVyc2lvbiBvZiBgZGVidWdgLicpO1xuXHR9XG5cblx0Y3JlYXRlRGVidWcuZW5hYmxlKGNyZWF0ZURlYnVnLmxvYWQoKSk7XG5cblx0cmV0dXJuIGNyZWF0ZURlYnVnO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHNldHVwO1xuIiwiLyoqXG4gKiBIZWxwZXJzLlxuICovXG5cbnZhciBzID0gMTAwMDtcbnZhciBtID0gcyAqIDYwO1xudmFyIGggPSBtICogNjA7XG52YXIgZCA9IGggKiAyNDtcbnZhciB3ID0gZCAqIDc7XG52YXIgeSA9IGQgKiAzNjUuMjU7XG5cbi8qKlxuICogUGFyc2Ugb3IgZm9ybWF0IHRoZSBnaXZlbiBgdmFsYC5cbiAqXG4gKiBPcHRpb25zOlxuICpcbiAqICAtIGBsb25nYCB2ZXJib3NlIGZvcm1hdHRpbmcgW2ZhbHNlXVxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfE51bWJlcn0gdmFsXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnNdXG4gKiBAdGhyb3dzIHtFcnJvcn0gdGhyb3cgYW4gZXJyb3IgaWYgdmFsIGlzIG5vdCBhIG5vbi1lbXB0eSBzdHJpbmcgb3IgYSBudW1iZXJcbiAqIEByZXR1cm4ge1N0cmluZ3xOdW1iZXJ9XG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24odmFsLCBvcHRpb25zKSB7XG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICB2YXIgdHlwZSA9IHR5cGVvZiB2YWw7XG4gIGlmICh0eXBlID09PSAnc3RyaW5nJyAmJiB2YWwubGVuZ3RoID4gMCkge1xuICAgIHJldHVybiBwYXJzZSh2YWwpO1xuICB9IGVsc2UgaWYgKHR5cGUgPT09ICdudW1iZXInICYmIGlzRmluaXRlKHZhbCkpIHtcbiAgICByZXR1cm4gb3B0aW9ucy5sb25nID8gZm10TG9uZyh2YWwpIDogZm10U2hvcnQodmFsKTtcbiAgfVxuICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgJ3ZhbCBpcyBub3QgYSBub24tZW1wdHkgc3RyaW5nIG9yIGEgdmFsaWQgbnVtYmVyLiB2YWw9JyArXG4gICAgICBKU09OLnN0cmluZ2lmeSh2YWwpXG4gICk7XG59O1xuXG4vKipcbiAqIFBhcnNlIHRoZSBnaXZlbiBgc3RyYCBhbmQgcmV0dXJuIG1pbGxpc2Vjb25kcy5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gc3RyXG4gKiBAcmV0dXJuIHtOdW1iZXJ9XG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuXG5mdW5jdGlvbiBwYXJzZShzdHIpIHtcbiAgc3RyID0gU3RyaW5nKHN0cik7XG4gIGlmIChzdHIubGVuZ3RoID4gMTAwKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBtYXRjaCA9IC9eKC0/KD86XFxkKyk/XFwuP1xcZCspICoobWlsbGlzZWNvbmRzP3xtc2Vjcz98bXN8c2Vjb25kcz98c2Vjcz98c3xtaW51dGVzP3xtaW5zP3xtfGhvdXJzP3xocnM/fGh8ZGF5cz98ZHx3ZWVrcz98d3x5ZWFycz98eXJzP3x5KT8kL2kuZXhlYyhcbiAgICBzdHJcbiAgKTtcbiAgaWYgKCFtYXRjaCkge1xuICAgIHJldHVybjtcbiAgfVxuICB2YXIgbiA9IHBhcnNlRmxvYXQobWF0Y2hbMV0pO1xuICB2YXIgdHlwZSA9IChtYXRjaFsyXSB8fCAnbXMnKS50b0xvd2VyQ2FzZSgpO1xuICBzd2l0Y2ggKHR5cGUpIHtcbiAgICBjYXNlICd5ZWFycyc6XG4gICAgY2FzZSAneWVhcic6XG4gICAgY2FzZSAneXJzJzpcbiAgICBjYXNlICd5cic6XG4gICAgY2FzZSAneSc6XG4gICAgICByZXR1cm4gbiAqIHk7XG4gICAgY2FzZSAnd2Vla3MnOlxuICAgIGNhc2UgJ3dlZWsnOlxuICAgIGNhc2UgJ3cnOlxuICAgICAgcmV0dXJuIG4gKiB3O1xuICAgIGNhc2UgJ2RheXMnOlxuICAgIGNhc2UgJ2RheSc6XG4gICAgY2FzZSAnZCc6XG4gICAgICByZXR1cm4gbiAqIGQ7XG4gICAgY2FzZSAnaG91cnMnOlxuICAgIGNhc2UgJ2hvdXInOlxuICAgIGNhc2UgJ2hycyc6XG4gICAgY2FzZSAnaHInOlxuICAgIGNhc2UgJ2gnOlxuICAgICAgcmV0dXJuIG4gKiBoO1xuICAgIGNhc2UgJ21pbnV0ZXMnOlxuICAgIGNhc2UgJ21pbnV0ZSc6XG4gICAgY2FzZSAnbWlucyc6XG4gICAgY2FzZSAnbWluJzpcbiAgICBjYXNlICdtJzpcbiAgICAgIHJldHVybiBuICogbTtcbiAgICBjYXNlICdzZWNvbmRzJzpcbiAgICBjYXNlICdzZWNvbmQnOlxuICAgIGNhc2UgJ3NlY3MnOlxuICAgIGNhc2UgJ3NlYyc6XG4gICAgY2FzZSAncyc6XG4gICAgICByZXR1cm4gbiAqIHM7XG4gICAgY2FzZSAnbWlsbGlzZWNvbmRzJzpcbiAgICBjYXNlICdtaWxsaXNlY29uZCc6XG4gICAgY2FzZSAnbXNlY3MnOlxuICAgIGNhc2UgJ21zZWMnOlxuICAgIGNhc2UgJ21zJzpcbiAgICAgIHJldHVybiBuO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbi8qKlxuICogU2hvcnQgZm9ybWF0IGZvciBgbXNgLlxuICpcbiAqIEBwYXJhbSB7TnVtYmVyfSBtc1xuICogQHJldHVybiB7U3RyaW5nfVxuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gZm10U2hvcnQobXMpIHtcbiAgdmFyIG1zQWJzID0gTWF0aC5hYnMobXMpO1xuICBpZiAobXNBYnMgPj0gZCkge1xuICAgIHJldHVybiBNYXRoLnJvdW5kKG1zIC8gZCkgKyAnZCc7XG4gIH1cbiAgaWYgKG1zQWJzID49IGgpIHtcbiAgICByZXR1cm4gTWF0aC5yb3VuZChtcyAvIGgpICsgJ2gnO1xuICB9XG4gIGlmIChtc0FicyA+PSBtKSB7XG4gICAgcmV0dXJuIE1hdGgucm91bmQobXMgLyBtKSArICdtJztcbiAgfVxuICBpZiAobXNBYnMgPj0gcykge1xuICAgIHJldHVybiBNYXRoLnJvdW5kKG1zIC8gcykgKyAncyc7XG4gIH1cbiAgcmV0dXJuIG1zICsgJ21zJztcbn1cblxuLyoqXG4gKiBMb25nIGZvcm1hdCBmb3IgYG1zYC5cbiAqXG4gKiBAcGFyYW0ge051bWJlcn0gbXNcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIGZtdExvbmcobXMpIHtcbiAgdmFyIG1zQWJzID0gTWF0aC5hYnMobXMpO1xuICBpZiAobXNBYnMgPj0gZCkge1xuICAgIHJldHVybiBwbHVyYWwobXMsIG1zQWJzLCBkLCAnZGF5Jyk7XG4gIH1cbiAgaWYgKG1zQWJzID49IGgpIHtcbiAgICByZXR1cm4gcGx1cmFsKG1zLCBtc0FicywgaCwgJ2hvdXInKTtcbiAgfVxuICBpZiAobXNBYnMgPj0gbSkge1xuICAgIHJldHVybiBwbHVyYWwobXMsIG1zQWJzLCBtLCAnbWludXRlJyk7XG4gIH1cbiAgaWYgKG1zQWJzID49IHMpIHtcbiAgICByZXR1cm4gcGx1cmFsKG1zLCBtc0FicywgcywgJ3NlY29uZCcpO1xuICB9XG4gIHJldHVybiBtcyArICcgbXMnO1xufVxuXG4vKipcbiAqIFBsdXJhbGl6YXRpb24gaGVscGVyLlxuICovXG5cbmZ1bmN0aW9uIHBsdXJhbChtcywgbXNBYnMsIG4sIG5hbWUpIHtcbiAgdmFyIGlzUGx1cmFsID0gbXNBYnMgPj0gbiAqIDEuNTtcbiAgcmV0dXJuIE1hdGgucm91bmQobXMgLyBuKSArICcgJyArIG5hbWUgKyAoaXNQbHVyYWwgPyAncycgOiAnJyk7XG59XG4iLCIvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcblxuLy8gU0RQIGhlbHBlcnMuXG5jb25zdCBTRFBVdGlscyA9IHt9O1xuXG4vLyBHZW5lcmF0ZSBhbiBhbHBoYW51bWVyaWMgaWRlbnRpZmllciBmb3IgY25hbWUgb3IgbWlkcy5cbi8vIFRPRE86IHVzZSBVVUlEcyBpbnN0ZWFkPyBodHRwczovL2dpc3QuZ2l0aHViLmNvbS9qZWQvOTgyODgzXG5TRFBVdGlscy5nZW5lcmF0ZUlkZW50aWZpZXIgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cmluZygyLCAxMik7XG59O1xuXG4vLyBUaGUgUlRDUCBDTkFNRSB1c2VkIGJ5IGFsbCBwZWVyY29ubmVjdGlvbnMgZnJvbSB0aGUgc2FtZSBKUy5cblNEUFV0aWxzLmxvY2FsQ05hbWUgPSBTRFBVdGlscy5nZW5lcmF0ZUlkZW50aWZpZXIoKTtcblxuLy8gU3BsaXRzIFNEUCBpbnRvIGxpbmVzLCBkZWFsaW5nIHdpdGggYm90aCBDUkxGIGFuZCBMRi5cblNEUFV0aWxzLnNwbGl0TGluZXMgPSBmdW5jdGlvbihibG9iKSB7XG4gIHJldHVybiBibG9iLnRyaW0oKS5zcGxpdCgnXFxuJykubWFwKGxpbmUgPT4gbGluZS50cmltKCkpO1xufTtcbi8vIFNwbGl0cyBTRFAgaW50byBzZXNzaW9ucGFydCBhbmQgbWVkaWFzZWN0aW9ucy4gRW5zdXJlcyBDUkxGLlxuU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyA9IGZ1bmN0aW9uKGJsb2IpIHtcbiAgY29uc3QgcGFydHMgPSBibG9iLnNwbGl0KCdcXG5tPScpO1xuICByZXR1cm4gcGFydHMubWFwKChwYXJ0LCBpbmRleCkgPT4gKGluZGV4ID4gMCA/XG4gICAgJ209JyArIHBhcnQgOiBwYXJ0KS50cmltKCkgKyAnXFxyXFxuJyk7XG59O1xuXG4vLyBSZXR1cm5zIHRoZSBzZXNzaW9uIGRlc2NyaXB0aW9uLlxuU0RQVXRpbHMuZ2V0RGVzY3JpcHRpb24gPSBmdW5jdGlvbihibG9iKSB7XG4gIGNvbnN0IHNlY3Rpb25zID0gU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyhibG9iKTtcbiAgcmV0dXJuIHNlY3Rpb25zICYmIHNlY3Rpb25zWzBdO1xufTtcblxuLy8gUmV0dXJucyB0aGUgaW5kaXZpZHVhbCBtZWRpYSBzZWN0aW9ucy5cblNEUFV0aWxzLmdldE1lZGlhU2VjdGlvbnMgPSBmdW5jdGlvbihibG9iKSB7XG4gIGNvbnN0IHNlY3Rpb25zID0gU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyhibG9iKTtcbiAgc2VjdGlvbnMuc2hpZnQoKTtcbiAgcmV0dXJuIHNlY3Rpb25zO1xufTtcblxuLy8gUmV0dXJucyBsaW5lcyB0aGF0IHN0YXJ0IHdpdGggYSBjZXJ0YWluIHByZWZpeC5cblNEUFV0aWxzLm1hdGNoUHJlZml4ID0gZnVuY3Rpb24oYmxvYiwgcHJlZml4KSB7XG4gIHJldHVybiBTRFBVdGlscy5zcGxpdExpbmVzKGJsb2IpLmZpbHRlcihsaW5lID0+IGxpbmUuaW5kZXhPZihwcmVmaXgpID09PSAwKTtcbn07XG5cbi8vIFBhcnNlcyBhbiBJQ0UgY2FuZGlkYXRlIGxpbmUuIFNhbXBsZSBpbnB1dDpcbi8vIGNhbmRpZGF0ZTo3MDI3ODYzNTAgMiB1ZHAgNDE4MTk5MDIgOC44LjguOCA2MDc2OSB0eXAgcmVsYXkgcmFkZHIgOC44LjguOFxuLy8gcnBvcnQgNTU5OTZcIlxuLy8gSW5wdXQgY2FuIGJlIHByZWZpeGVkIHdpdGggYT0uXG5TRFBVdGlscy5wYXJzZUNhbmRpZGF0ZSA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgbGV0IHBhcnRzO1xuICAvLyBQYXJzZSBib3RoIHZhcmlhbnRzLlxuICBpZiAobGluZS5pbmRleE9mKCdhPWNhbmRpZGF0ZTonKSA9PT0gMCkge1xuICAgIHBhcnRzID0gbGluZS5zdWJzdHJpbmcoMTIpLnNwbGl0KCcgJyk7XG4gIH0gZWxzZSB7XG4gICAgcGFydHMgPSBsaW5lLnN1YnN0cmluZygxMCkuc3BsaXQoJyAnKTtcbiAgfVxuXG4gIGNvbnN0IGNhbmRpZGF0ZSA9IHtcbiAgICBmb3VuZGF0aW9uOiBwYXJ0c1swXSxcbiAgICBjb21wb25lbnQ6IHsxOiAncnRwJywgMjogJ3J0Y3AnfVtwYXJ0c1sxXV0gfHwgcGFydHNbMV0sXG4gICAgcHJvdG9jb2w6IHBhcnRzWzJdLnRvTG93ZXJDYXNlKCksXG4gICAgcHJpb3JpdHk6IHBhcnNlSW50KHBhcnRzWzNdLCAxMCksXG4gICAgaXA6IHBhcnRzWzRdLFxuICAgIGFkZHJlc3M6IHBhcnRzWzRdLCAvLyBhZGRyZXNzIGlzIGFuIGFsaWFzIGZvciBpcC5cbiAgICBwb3J0OiBwYXJzZUludChwYXJ0c1s1XSwgMTApLFxuICAgIC8vIHNraXAgcGFydHNbNl0gPT0gJ3R5cCdcbiAgICB0eXBlOiBwYXJ0c1s3XSxcbiAgfTtcblxuICBmb3IgKGxldCBpID0gODsgaSA8IHBhcnRzLmxlbmd0aDsgaSArPSAyKSB7XG4gICAgc3dpdGNoIChwYXJ0c1tpXSkge1xuICAgICAgY2FzZSAncmFkZHInOlxuICAgICAgICBjYW5kaWRhdGUucmVsYXRlZEFkZHJlc3MgPSBwYXJ0c1tpICsgMV07XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAncnBvcnQnOlxuICAgICAgICBjYW5kaWRhdGUucmVsYXRlZFBvcnQgPSBwYXJzZUludChwYXJ0c1tpICsgMV0sIDEwKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICd0Y3B0eXBlJzpcbiAgICAgICAgY2FuZGlkYXRlLnRjcFR5cGUgPSBwYXJ0c1tpICsgMV07XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAndWZyYWcnOlxuICAgICAgICBjYW5kaWRhdGUudWZyYWcgPSBwYXJ0c1tpICsgMV07IC8vIGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5LlxuICAgICAgICBjYW5kaWRhdGUudXNlcm5hbWVGcmFnbWVudCA9IHBhcnRzW2kgKyAxXTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OiAvLyBleHRlbnNpb24gaGFuZGxpbmcsIGluIHBhcnRpY3VsYXIgdWZyYWcuIERvbid0IG92ZXJ3cml0ZS5cbiAgICAgICAgaWYgKGNhbmRpZGF0ZVtwYXJ0c1tpXV0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGNhbmRpZGF0ZVtwYXJ0c1tpXV0gPSBwYXJ0c1tpICsgMV07XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG4gIHJldHVybiBjYW5kaWRhdGU7XG59O1xuXG4vLyBUcmFuc2xhdGVzIGEgY2FuZGlkYXRlIG9iamVjdCBpbnRvIFNEUCBjYW5kaWRhdGUgYXR0cmlidXRlLlxuLy8gVGhpcyBkb2VzIG5vdCBpbmNsdWRlIHRoZSBhPSBwcmVmaXghXG5TRFBVdGlscy53cml0ZUNhbmRpZGF0ZSA9IGZ1bmN0aW9uKGNhbmRpZGF0ZSkge1xuICBjb25zdCBzZHAgPSBbXTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLmZvdW5kYXRpb24pO1xuXG4gIGNvbnN0IGNvbXBvbmVudCA9IGNhbmRpZGF0ZS5jb21wb25lbnQ7XG4gIGlmIChjb21wb25lbnQgPT09ICdydHAnKSB7XG4gICAgc2RwLnB1c2goMSk7XG4gIH0gZWxzZSBpZiAoY29tcG9uZW50ID09PSAncnRjcCcpIHtcbiAgICBzZHAucHVzaCgyKTtcbiAgfSBlbHNlIHtcbiAgICBzZHAucHVzaChjb21wb25lbnQpO1xuICB9XG4gIHNkcC5wdXNoKGNhbmRpZGF0ZS5wcm90b2NvbC50b1VwcGVyQ2FzZSgpKTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLnByaW9yaXR5KTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLmFkZHJlc3MgfHwgY2FuZGlkYXRlLmlwKTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLnBvcnQpO1xuXG4gIGNvbnN0IHR5cGUgPSBjYW5kaWRhdGUudHlwZTtcbiAgc2RwLnB1c2goJ3R5cCcpO1xuICBzZHAucHVzaCh0eXBlKTtcbiAgaWYgKHR5cGUgIT09ICdob3N0JyAmJiBjYW5kaWRhdGUucmVsYXRlZEFkZHJlc3MgJiZcbiAgICAgIGNhbmRpZGF0ZS5yZWxhdGVkUG9ydCkge1xuICAgIHNkcC5wdXNoKCdyYWRkcicpO1xuICAgIHNkcC5wdXNoKGNhbmRpZGF0ZS5yZWxhdGVkQWRkcmVzcyk7XG4gICAgc2RwLnB1c2goJ3Jwb3J0Jyk7XG4gICAgc2RwLnB1c2goY2FuZGlkYXRlLnJlbGF0ZWRQb3J0KTtcbiAgfVxuICBpZiAoY2FuZGlkYXRlLnRjcFR5cGUgJiYgY2FuZGlkYXRlLnByb3RvY29sLnRvTG93ZXJDYXNlKCkgPT09ICd0Y3AnKSB7XG4gICAgc2RwLnB1c2goJ3RjcHR5cGUnKTtcbiAgICBzZHAucHVzaChjYW5kaWRhdGUudGNwVHlwZSk7XG4gIH1cbiAgaWYgKGNhbmRpZGF0ZS51c2VybmFtZUZyYWdtZW50IHx8IGNhbmRpZGF0ZS51ZnJhZykge1xuICAgIHNkcC5wdXNoKCd1ZnJhZycpO1xuICAgIHNkcC5wdXNoKGNhbmRpZGF0ZS51c2VybmFtZUZyYWdtZW50IHx8IGNhbmRpZGF0ZS51ZnJhZyk7XG4gIH1cbiAgcmV0dXJuICdjYW5kaWRhdGU6JyArIHNkcC5qb2luKCcgJyk7XG59O1xuXG4vLyBQYXJzZXMgYW4gaWNlLW9wdGlvbnMgbGluZSwgcmV0dXJucyBhbiBhcnJheSBvZiBvcHRpb24gdGFncy5cbi8vIFNhbXBsZSBpbnB1dDpcbi8vIGE9aWNlLW9wdGlvbnM6Zm9vIGJhclxuU0RQVXRpbHMucGFyc2VJY2VPcHRpb25zID0gZnVuY3Rpb24obGluZSkge1xuICByZXR1cm4gbGluZS5zdWJzdHJpbmcoMTQpLnNwbGl0KCcgJyk7XG59O1xuXG4vLyBQYXJzZXMgYSBydHBtYXAgbGluZSwgcmV0dXJucyBSVENSdHBDb2RkZWNQYXJhbWV0ZXJzLiBTYW1wbGUgaW5wdXQ6XG4vLyBhPXJ0cG1hcDoxMTEgb3B1cy80ODAwMC8yXG5TRFBVdGlscy5wYXJzZVJ0cE1hcCA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgbGV0IHBhcnRzID0gbGluZS5zdWJzdHJpbmcoOSkuc3BsaXQoJyAnKTtcbiAgY29uc3QgcGFyc2VkID0ge1xuICAgIHBheWxvYWRUeXBlOiBwYXJzZUludChwYXJ0cy5zaGlmdCgpLCAxMCksIC8vIHdhczogaWRcbiAgfTtcblxuICBwYXJ0cyA9IHBhcnRzWzBdLnNwbGl0KCcvJyk7XG5cbiAgcGFyc2VkLm5hbWUgPSBwYXJ0c1swXTtcbiAgcGFyc2VkLmNsb2NrUmF0ZSA9IHBhcnNlSW50KHBhcnRzWzFdLCAxMCk7IC8vIHdhczogY2xvY2tyYXRlXG4gIHBhcnNlZC5jaGFubmVscyA9IHBhcnRzLmxlbmd0aCA9PT0gMyA/IHBhcnNlSW50KHBhcnRzWzJdLCAxMCkgOiAxO1xuICAvLyBsZWdhY3kgYWxpYXMsIGdvdCByZW5hbWVkIGJhY2sgdG8gY2hhbm5lbHMgaW4gT1JUQy5cbiAgcGFyc2VkLm51bUNoYW5uZWxzID0gcGFyc2VkLmNoYW5uZWxzO1xuICByZXR1cm4gcGFyc2VkO1xufTtcblxuLy8gR2VuZXJhdGVzIGEgcnRwbWFwIGxpbmUgZnJvbSBSVENSdHBDb2RlY0NhcGFiaWxpdHkgb3Jcbi8vIFJUQ1J0cENvZGVjUGFyYW1ldGVycy5cblNEUFV0aWxzLndyaXRlUnRwTWFwID0gZnVuY3Rpb24oY29kZWMpIHtcbiAgbGV0IHB0ID0gY29kZWMucGF5bG9hZFR5cGU7XG4gIGlmIChjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcHQgPSBjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZTtcbiAgfVxuICBjb25zdCBjaGFubmVscyA9IGNvZGVjLmNoYW5uZWxzIHx8IGNvZGVjLm51bUNoYW5uZWxzIHx8IDE7XG4gIHJldHVybiAnYT1ydHBtYXA6JyArIHB0ICsgJyAnICsgY29kZWMubmFtZSArICcvJyArIGNvZGVjLmNsb2NrUmF0ZSArXG4gICAgICAoY2hhbm5lbHMgIT09IDEgPyAnLycgKyBjaGFubmVscyA6ICcnKSArICdcXHJcXG4nO1xufTtcblxuLy8gUGFyc2VzIGEgZXh0bWFwIGxpbmUgKGhlYWRlcmV4dGVuc2lvbiBmcm9tIFJGQyA1Mjg1KS4gU2FtcGxlIGlucHV0OlxuLy8gYT1leHRtYXA6MiB1cm46aWV0ZjpwYXJhbXM6cnRwLWhkcmV4dDp0b2Zmc2V0XG4vLyBhPWV4dG1hcDoyL3NlbmRvbmx5IHVybjppZXRmOnBhcmFtczpydHAtaGRyZXh0OnRvZmZzZXRcblNEUFV0aWxzLnBhcnNlRXh0bWFwID0gZnVuY3Rpb24obGluZSkge1xuICBjb25zdCBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDkpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAgaWQ6IHBhcnNlSW50KHBhcnRzWzBdLCAxMCksXG4gICAgZGlyZWN0aW9uOiBwYXJ0c1swXS5pbmRleE9mKCcvJykgPiAwID8gcGFydHNbMF0uc3BsaXQoJy8nKVsxXSA6ICdzZW5kcmVjdicsXG4gICAgdXJpOiBwYXJ0c1sxXSxcbiAgICBhdHRyaWJ1dGVzOiBwYXJ0cy5zbGljZSgyKS5qb2luKCcgJyksXG4gIH07XG59O1xuXG4vLyBHZW5lcmF0ZXMgYW4gZXh0bWFwIGxpbmUgZnJvbSBSVENSdHBIZWFkZXJFeHRlbnNpb25QYXJhbWV0ZXJzIG9yXG4vLyBSVENSdHBIZWFkZXJFeHRlbnNpb24uXG5TRFBVdGlscy53cml0ZUV4dG1hcCA9IGZ1bmN0aW9uKGhlYWRlckV4dGVuc2lvbikge1xuICByZXR1cm4gJ2E9ZXh0bWFwOicgKyAoaGVhZGVyRXh0ZW5zaW9uLmlkIHx8IGhlYWRlckV4dGVuc2lvbi5wcmVmZXJyZWRJZCkgK1xuICAgICAgKGhlYWRlckV4dGVuc2lvbi5kaXJlY3Rpb24gJiYgaGVhZGVyRXh0ZW5zaW9uLmRpcmVjdGlvbiAhPT0gJ3NlbmRyZWN2J1xuICAgICAgICA/ICcvJyArIGhlYWRlckV4dGVuc2lvbi5kaXJlY3Rpb25cbiAgICAgICAgOiAnJykgK1xuICAgICAgJyAnICsgaGVhZGVyRXh0ZW5zaW9uLnVyaSArXG4gICAgICAoaGVhZGVyRXh0ZW5zaW9uLmF0dHJpYnV0ZXMgPyAnICcgKyBoZWFkZXJFeHRlbnNpb24uYXR0cmlidXRlcyA6ICcnKSArXG4gICAgICAnXFxyXFxuJztcbn07XG5cbi8vIFBhcnNlcyBhIGZtdHAgbGluZSwgcmV0dXJucyBkaWN0aW9uYXJ5LiBTYW1wbGUgaW5wdXQ6XG4vLyBhPWZtdHA6OTYgdmJyPW9uO2NuZz1vblxuLy8gQWxzbyBkZWFscyB3aXRoIHZicj1vbjsgY25nPW9uXG5TRFBVdGlscy5wYXJzZUZtdHAgPSBmdW5jdGlvbihsaW5lKSB7XG4gIGNvbnN0IHBhcnNlZCA9IHt9O1xuICBsZXQga3Y7XG4gIGNvbnN0IHBhcnRzID0gbGluZS5zdWJzdHJpbmcobGluZS5pbmRleE9mKCcgJykgKyAxKS5zcGxpdCgnOycpO1xuICBmb3IgKGxldCBqID0gMDsgaiA8IHBhcnRzLmxlbmd0aDsgaisrKSB7XG4gICAga3YgPSBwYXJ0c1tqXS50cmltKCkuc3BsaXQoJz0nKTtcbiAgICBwYXJzZWRba3ZbMF0udHJpbSgpXSA9IGt2WzFdO1xuICB9XG4gIHJldHVybiBwYXJzZWQ7XG59O1xuXG4vLyBHZW5lcmF0ZXMgYSBmbXRwIGxpbmUgZnJvbSBSVENSdHBDb2RlY0NhcGFiaWxpdHkgb3IgUlRDUnRwQ29kZWNQYXJhbWV0ZXJzLlxuU0RQVXRpbHMud3JpdGVGbXRwID0gZnVuY3Rpb24oY29kZWMpIHtcbiAgbGV0IGxpbmUgPSAnJztcbiAgbGV0IHB0ID0gY29kZWMucGF5bG9hZFR5cGU7XG4gIGlmIChjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcHQgPSBjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZTtcbiAgfVxuICBpZiAoY29kZWMucGFyYW1ldGVycyAmJiBPYmplY3Qua2V5cyhjb2RlYy5wYXJhbWV0ZXJzKS5sZW5ndGgpIHtcbiAgICBjb25zdCBwYXJhbXMgPSBbXTtcbiAgICBPYmplY3Qua2V5cyhjb2RlYy5wYXJhbWV0ZXJzKS5mb3JFYWNoKHBhcmFtID0+IHtcbiAgICAgIGlmIChjb2RlYy5wYXJhbWV0ZXJzW3BhcmFtXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHBhcmFtcy5wdXNoKHBhcmFtICsgJz0nICsgY29kZWMucGFyYW1ldGVyc1twYXJhbV0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcGFyYW1zLnB1c2gocGFyYW0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGxpbmUgKz0gJ2E9Zm10cDonICsgcHQgKyAnICcgKyBwYXJhbXMuam9pbignOycpICsgJ1xcclxcbic7XG4gIH1cbiAgcmV0dXJuIGxpbmU7XG59O1xuXG4vLyBQYXJzZXMgYSBydGNwLWZiIGxpbmUsIHJldHVybnMgUlRDUFJ0Y3BGZWVkYmFjayBvYmplY3QuIFNhbXBsZSBpbnB1dDpcbi8vIGE9cnRjcC1mYjo5OCBuYWNrIHJwc2lcblNEUFV0aWxzLnBhcnNlUnRjcEZiID0gZnVuY3Rpb24obGluZSkge1xuICBjb25zdCBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKGxpbmUuaW5kZXhPZignICcpICsgMSkuc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICB0eXBlOiBwYXJ0cy5zaGlmdCgpLFxuICAgIHBhcmFtZXRlcjogcGFydHMuam9pbignICcpLFxuICB9O1xufTtcblxuLy8gR2VuZXJhdGUgYT1ydGNwLWZiIGxpbmVzIGZyb20gUlRDUnRwQ29kZWNDYXBhYmlsaXR5IG9yIFJUQ1J0cENvZGVjUGFyYW1ldGVycy5cblNEUFV0aWxzLndyaXRlUnRjcEZiID0gZnVuY3Rpb24oY29kZWMpIHtcbiAgbGV0IGxpbmVzID0gJyc7XG4gIGxldCBwdCA9IGNvZGVjLnBheWxvYWRUeXBlO1xuICBpZiAoY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGUgIT09IHVuZGVmaW5lZCkge1xuICAgIHB0ID0gY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGU7XG4gIH1cbiAgaWYgKGNvZGVjLnJ0Y3BGZWVkYmFjayAmJiBjb2RlYy5ydGNwRmVlZGJhY2subGVuZ3RoKSB7XG4gICAgLy8gRklYTUU6IHNwZWNpYWwgaGFuZGxpbmcgZm9yIHRyci1pbnQ/XG4gICAgY29kZWMucnRjcEZlZWRiYWNrLmZvckVhY2goZmIgPT4ge1xuICAgICAgbGluZXMgKz0gJ2E9cnRjcC1mYjonICsgcHQgKyAnICcgKyBmYi50eXBlICtcbiAgICAgIChmYi5wYXJhbWV0ZXIgJiYgZmIucGFyYW1ldGVyLmxlbmd0aCA/ICcgJyArIGZiLnBhcmFtZXRlciA6ICcnKSArXG4gICAgICAgICAgJ1xcclxcbic7XG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIGxpbmVzO1xufTtcblxuLy8gUGFyc2VzIGEgUkZDIDU1NzYgc3NyYyBtZWRpYSBhdHRyaWJ1dGUuIFNhbXBsZSBpbnB1dDpcbi8vIGE9c3NyYzozNzM1OTI4NTU5IGNuYW1lOnNvbWV0aGluZ1xuU0RQVXRpbHMucGFyc2VTc3JjTWVkaWEgPSBmdW5jdGlvbihsaW5lKSB7XG4gIGNvbnN0IHNwID0gbGluZS5pbmRleE9mKCcgJyk7XG4gIGNvbnN0IHBhcnRzID0ge1xuICAgIHNzcmM6IHBhcnNlSW50KGxpbmUuc3Vic3RyaW5nKDcsIHNwKSwgMTApLFxuICB9O1xuICBjb25zdCBjb2xvbiA9IGxpbmUuaW5kZXhPZignOicsIHNwKTtcbiAgaWYgKGNvbG9uID4gLTEpIHtcbiAgICBwYXJ0cy5hdHRyaWJ1dGUgPSBsaW5lLnN1YnN0cmluZyhzcCArIDEsIGNvbG9uKTtcbiAgICBwYXJ0cy52YWx1ZSA9IGxpbmUuc3Vic3RyaW5nKGNvbG9uICsgMSk7XG4gIH0gZWxzZSB7XG4gICAgcGFydHMuYXR0cmlidXRlID0gbGluZS5zdWJzdHJpbmcoc3AgKyAxKTtcbiAgfVxuICByZXR1cm4gcGFydHM7XG59O1xuXG4vLyBQYXJzZSBhIHNzcmMtZ3JvdXAgbGluZSAoc2VlIFJGQyA1NTc2KS4gU2FtcGxlIGlucHV0OlxuLy8gYT1zc3JjLWdyb3VwOnNlbWFudGljcyAxMiAzNFxuU0RQVXRpbHMucGFyc2VTc3JjR3JvdXAgPSBmdW5jdGlvbihsaW5lKSB7XG4gIGNvbnN0IHBhcnRzID0gbGluZS5zdWJzdHJpbmcoMTMpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAgc2VtYW50aWNzOiBwYXJ0cy5zaGlmdCgpLFxuICAgIHNzcmNzOiBwYXJ0cy5tYXAoc3NyYyA9PiBwYXJzZUludChzc3JjLCAxMCkpLFxuICB9O1xufTtcblxuLy8gRXh0cmFjdHMgdGhlIE1JRCAoUkZDIDU4ODgpIGZyb20gYSBtZWRpYSBzZWN0aW9uLlxuLy8gUmV0dXJucyB0aGUgTUlEIG9yIHVuZGVmaW5lZCBpZiBubyBtaWQgbGluZSB3YXMgZm91bmQuXG5TRFBVdGlscy5nZXRNaWQgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgY29uc3QgbWlkID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1taWQ6JylbMF07XG4gIGlmIChtaWQpIHtcbiAgICByZXR1cm4gbWlkLnN1YnN0cmluZyg2KTtcbiAgfVxufTtcblxuLy8gUGFyc2VzIGEgZmluZ2VycHJpbnQgbGluZSBmb3IgRFRMUy1TUlRQLlxuU0RQVXRpbHMucGFyc2VGaW5nZXJwcmludCA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgY29uc3QgcGFydHMgPSBsaW5lLnN1YnN0cmluZygxNCkuc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICBhbGdvcml0aG06IHBhcnRzWzBdLnRvTG93ZXJDYXNlKCksIC8vIGFsZ29yaXRobSBpcyBjYXNlLXNlbnNpdGl2ZSBpbiBFZGdlLlxuICAgIHZhbHVlOiBwYXJ0c1sxXS50b1VwcGVyQ2FzZSgpLCAvLyB0aGUgZGVmaW5pdGlvbiBpcyB1cHBlci1jYXNlIGluIFJGQyA0NTcyLlxuICB9O1xufTtcblxuLy8gRXh0cmFjdHMgRFRMUyBwYXJhbWV0ZXJzIGZyb20gU0RQIG1lZGlhIHNlY3Rpb24gb3Igc2Vzc2lvbnBhcnQuXG4vLyBGSVhNRTogZm9yIGNvbnNpc3RlbmN5IHdpdGggb3RoZXIgZnVuY3Rpb25zIHRoaXMgc2hvdWxkIG9ubHlcbi8vICAgZ2V0IHRoZSBmaW5nZXJwcmludCBsaW5lIGFzIGlucHV0LiBTZWUgYWxzbyBnZXRJY2VQYXJhbWV0ZXJzLlxuU0RQVXRpbHMuZ2V0RHRsc1BhcmFtZXRlcnMgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KSB7XG4gIGNvbnN0IGxpbmVzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uICsgc2Vzc2lvbnBhcnQsXG4gICAgJ2E9ZmluZ2VycHJpbnQ6Jyk7XG4gIC8vIE5vdGU6IGE9c2V0dXAgbGluZSBpcyBpZ25vcmVkIHNpbmNlIHdlIHVzZSB0aGUgJ2F1dG8nIHJvbGUgaW4gRWRnZS5cbiAgcmV0dXJuIHtcbiAgICByb2xlOiAnYXV0bycsXG4gICAgZmluZ2VycHJpbnRzOiBsaW5lcy5tYXAoU0RQVXRpbHMucGFyc2VGaW5nZXJwcmludCksXG4gIH07XG59O1xuXG4vLyBTZXJpYWxpemVzIERUTFMgcGFyYW1ldGVycyB0byBTRFAuXG5TRFBVdGlscy53cml0ZUR0bHNQYXJhbWV0ZXJzID0gZnVuY3Rpb24ocGFyYW1zLCBzZXR1cFR5cGUpIHtcbiAgbGV0IHNkcCA9ICdhPXNldHVwOicgKyBzZXR1cFR5cGUgKyAnXFxyXFxuJztcbiAgcGFyYW1zLmZpbmdlcnByaW50cy5mb3JFYWNoKGZwID0+IHtcbiAgICBzZHAgKz0gJ2E9ZmluZ2VycHJpbnQ6JyArIGZwLmFsZ29yaXRobSArICcgJyArIGZwLnZhbHVlICsgJ1xcclxcbic7XG4gIH0pO1xuICByZXR1cm4gc2RwO1xufTtcblxuLy8gUGFyc2VzIGE9Y3J5cHRvIGxpbmVzIGludG9cbi8vICAgaHR0cHM6Ly9yYXdnaXQuY29tL2Fib2JhL2VkZ2VydGMvbWFzdGVyL21zb3J0Yy1yczQuaHRtbCNkaWN0aW9uYXJ5LXJ0Y3NydHBzZGVzcGFyYW1ldGVycy1tZW1iZXJzXG5TRFBVdGlscy5wYXJzZUNyeXB0b0xpbmUgPSBmdW5jdGlvbihsaW5lKSB7XG4gIGNvbnN0IHBhcnRzID0gbGluZS5zdWJzdHJpbmcoOSkuc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICB0YWc6IHBhcnNlSW50KHBhcnRzWzBdLCAxMCksXG4gICAgY3J5cHRvU3VpdGU6IHBhcnRzWzFdLFxuICAgIGtleVBhcmFtczogcGFydHNbMl0sXG4gICAgc2Vzc2lvblBhcmFtczogcGFydHMuc2xpY2UoMyksXG4gIH07XG59O1xuXG5TRFBVdGlscy53cml0ZUNyeXB0b0xpbmUgPSBmdW5jdGlvbihwYXJhbWV0ZXJzKSB7XG4gIHJldHVybiAnYT1jcnlwdG86JyArIHBhcmFtZXRlcnMudGFnICsgJyAnICtcbiAgICBwYXJhbWV0ZXJzLmNyeXB0b1N1aXRlICsgJyAnICtcbiAgICAodHlwZW9mIHBhcmFtZXRlcnMua2V5UGFyYW1zID09PSAnb2JqZWN0J1xuICAgICAgPyBTRFBVdGlscy53cml0ZUNyeXB0b0tleVBhcmFtcyhwYXJhbWV0ZXJzLmtleVBhcmFtcylcbiAgICAgIDogcGFyYW1ldGVycy5rZXlQYXJhbXMpICtcbiAgICAocGFyYW1ldGVycy5zZXNzaW9uUGFyYW1zID8gJyAnICsgcGFyYW1ldGVycy5zZXNzaW9uUGFyYW1zLmpvaW4oJyAnKSA6ICcnKSArXG4gICAgJ1xcclxcbic7XG59O1xuXG4vLyBQYXJzZXMgdGhlIGNyeXB0byBrZXkgcGFyYW1ldGVycyBpbnRvXG4vLyAgIGh0dHBzOi8vcmF3Z2l0LmNvbS9hYm9iYS9lZGdlcnRjL21hc3Rlci9tc29ydGMtcnM0Lmh0bWwjcnRjc3J0cGtleXBhcmFtKlxuU0RQVXRpbHMucGFyc2VDcnlwdG9LZXlQYXJhbXMgPSBmdW5jdGlvbihrZXlQYXJhbXMpIHtcbiAgaWYgKGtleVBhcmFtcy5pbmRleE9mKCdpbmxpbmU6JykgIT09IDApIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBjb25zdCBwYXJ0cyA9IGtleVBhcmFtcy5zdWJzdHJpbmcoNykuc3BsaXQoJ3wnKTtcbiAgcmV0dXJuIHtcbiAgICBrZXlNZXRob2Q6ICdpbmxpbmUnLFxuICAgIGtleVNhbHQ6IHBhcnRzWzBdLFxuICAgIGxpZmVUaW1lOiBwYXJ0c1sxXSxcbiAgICBta2lWYWx1ZTogcGFydHNbMl0gPyBwYXJ0c1syXS5zcGxpdCgnOicpWzBdIDogdW5kZWZpbmVkLFxuICAgIG1raUxlbmd0aDogcGFydHNbMl0gPyBwYXJ0c1syXS5zcGxpdCgnOicpWzFdIDogdW5kZWZpbmVkLFxuICB9O1xufTtcblxuU0RQVXRpbHMud3JpdGVDcnlwdG9LZXlQYXJhbXMgPSBmdW5jdGlvbihrZXlQYXJhbXMpIHtcbiAgcmV0dXJuIGtleVBhcmFtcy5rZXlNZXRob2QgKyAnOidcbiAgICArIGtleVBhcmFtcy5rZXlTYWx0ICtcbiAgICAoa2V5UGFyYW1zLmxpZmVUaW1lID8gJ3wnICsga2V5UGFyYW1zLmxpZmVUaW1lIDogJycpICtcbiAgICAoa2V5UGFyYW1zLm1raVZhbHVlICYmIGtleVBhcmFtcy5ta2lMZW5ndGhcbiAgICAgID8gJ3wnICsga2V5UGFyYW1zLm1raVZhbHVlICsgJzonICsga2V5UGFyYW1zLm1raUxlbmd0aFxuICAgICAgOiAnJyk7XG59O1xuXG4vLyBFeHRyYWN0cyBhbGwgU0RFUyBwYXJhbWV0ZXJzLlxuU0RQVXRpbHMuZ2V0Q3J5cHRvUGFyYW1ldGVycyA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbiwgc2Vzc2lvbnBhcnQpIHtcbiAgY29uc3QgbGluZXMgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24gKyBzZXNzaW9ucGFydCxcbiAgICAnYT1jcnlwdG86Jyk7XG4gIHJldHVybiBsaW5lcy5tYXAoU0RQVXRpbHMucGFyc2VDcnlwdG9MaW5lKTtcbn07XG5cbi8vIFBhcnNlcyBJQ0UgaW5mb3JtYXRpb24gZnJvbSBTRFAgbWVkaWEgc2VjdGlvbiBvciBzZXNzaW9ucGFydC5cbi8vIEZJWE1FOiBmb3IgY29uc2lzdGVuY3kgd2l0aCBvdGhlciBmdW5jdGlvbnMgdGhpcyBzaG91bGQgb25seVxuLy8gICBnZXQgdGhlIGljZS11ZnJhZyBhbmQgaWNlLXB3ZCBsaW5lcyBhcyBpbnB1dC5cblNEUFV0aWxzLmdldEljZVBhcmFtZXRlcnMgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KSB7XG4gIGNvbnN0IHVmcmFnID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uICsgc2Vzc2lvbnBhcnQsXG4gICAgJ2E9aWNlLXVmcmFnOicpWzBdO1xuICBjb25zdCBwd2QgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24gKyBzZXNzaW9ucGFydCxcbiAgICAnYT1pY2UtcHdkOicpWzBdO1xuICBpZiAoISh1ZnJhZyAmJiBwd2QpKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgcmV0dXJuIHtcbiAgICB1c2VybmFtZUZyYWdtZW50OiB1ZnJhZy5zdWJzdHJpbmcoMTIpLFxuICAgIHBhc3N3b3JkOiBwd2Quc3Vic3RyaW5nKDEwKSxcbiAgfTtcbn07XG5cbi8vIFNlcmlhbGl6ZXMgSUNFIHBhcmFtZXRlcnMgdG8gU0RQLlxuU0RQVXRpbHMud3JpdGVJY2VQYXJhbWV0ZXJzID0gZnVuY3Rpb24ocGFyYW1zKSB7XG4gIGxldCBzZHAgPSAnYT1pY2UtdWZyYWc6JyArIHBhcmFtcy51c2VybmFtZUZyYWdtZW50ICsgJ1xcclxcbicgK1xuICAgICAgJ2E9aWNlLXB3ZDonICsgcGFyYW1zLnBhc3N3b3JkICsgJ1xcclxcbic7XG4gIGlmIChwYXJhbXMuaWNlTGl0ZSkge1xuICAgIHNkcCArPSAnYT1pY2UtbGl0ZVxcclxcbic7XG4gIH1cbiAgcmV0dXJuIHNkcDtcbn07XG5cbi8vIFBhcnNlcyB0aGUgU0RQIG1lZGlhIHNlY3Rpb24gYW5kIHJldHVybnMgUlRDUnRwUGFyYW1ldGVycy5cblNEUFV0aWxzLnBhcnNlUnRwUGFyYW1ldGVycyA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICBjb25zdCBkZXNjcmlwdGlvbiA9IHtcbiAgICBjb2RlY3M6IFtdLFxuICAgIGhlYWRlckV4dGVuc2lvbnM6IFtdLFxuICAgIGZlY01lY2hhbmlzbXM6IFtdLFxuICAgIHJ0Y3A6IFtdLFxuICB9O1xuICBjb25zdCBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMobWVkaWFTZWN0aW9uKTtcbiAgY29uc3QgbWxpbmUgPSBsaW5lc1swXS5zcGxpdCgnICcpO1xuICBkZXNjcmlwdGlvbi5wcm9maWxlID0gbWxpbmVbMl07XG4gIGZvciAobGV0IGkgPSAzOyBpIDwgbWxpbmUubGVuZ3RoOyBpKyspIHsgLy8gZmluZCBhbGwgY29kZWNzIGZyb20gbWxpbmVbMy4uXVxuICAgIGNvbnN0IHB0ID0gbWxpbmVbaV07XG4gICAgY29uc3QgcnRwbWFwbGluZSA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KFxuICAgICAgbWVkaWFTZWN0aW9uLCAnYT1ydHBtYXA6JyArIHB0ICsgJyAnKVswXTtcbiAgICBpZiAocnRwbWFwbGluZSkge1xuICAgICAgY29uc3QgY29kZWMgPSBTRFBVdGlscy5wYXJzZVJ0cE1hcChydHBtYXBsaW5lKTtcbiAgICAgIGNvbnN0IGZtdHBzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgoXG4gICAgICAgIG1lZGlhU2VjdGlvbiwgJ2E9Zm10cDonICsgcHQgKyAnICcpO1xuICAgICAgLy8gT25seSB0aGUgZmlyc3QgYT1mbXRwOjxwdD4gaXMgY29uc2lkZXJlZC5cbiAgICAgIGNvZGVjLnBhcmFtZXRlcnMgPSBmbXRwcy5sZW5ndGggPyBTRFBVdGlscy5wYXJzZUZtdHAoZm10cHNbMF0pIDoge307XG4gICAgICBjb2RlYy5ydGNwRmVlZGJhY2sgPSBTRFBVdGlscy5tYXRjaFByZWZpeChcbiAgICAgICAgbWVkaWFTZWN0aW9uLCAnYT1ydGNwLWZiOicgKyBwdCArICcgJylcbiAgICAgICAgLm1hcChTRFBVdGlscy5wYXJzZVJ0Y3BGYik7XG4gICAgICBkZXNjcmlwdGlvbi5jb2RlY3MucHVzaChjb2RlYyk7XG4gICAgICAvLyBwYXJzZSBGRUMgbWVjaGFuaXNtcyBmcm9tIHJ0cG1hcCBsaW5lcy5cbiAgICAgIHN3aXRjaCAoY29kZWMubmFtZS50b1VwcGVyQ2FzZSgpKSB7XG4gICAgICAgIGNhc2UgJ1JFRCc6XG4gICAgICAgIGNhc2UgJ1VMUEZFQyc6XG4gICAgICAgICAgZGVzY3JpcHRpb24uZmVjTWVjaGFuaXNtcy5wdXNoKGNvZGVjLm5hbWUudG9VcHBlckNhc2UoKSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6IC8vIG9ubHkgUkVEIGFuZCBVTFBGRUMgYXJlIHJlY29nbml6ZWQgYXMgRkVDIG1lY2hhbmlzbXMuXG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9ZXh0bWFwOicpLmZvckVhY2gobGluZSA9PiB7XG4gICAgZGVzY3JpcHRpb24uaGVhZGVyRXh0ZW5zaW9ucy5wdXNoKFNEUFV0aWxzLnBhcnNlRXh0bWFwKGxpbmUpKTtcbiAgfSk7XG4gIGNvbnN0IHdpbGRjYXJkUnRjcEZiID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1ydGNwLWZiOiogJylcbiAgICAubWFwKFNEUFV0aWxzLnBhcnNlUnRjcEZiKTtcbiAgZGVzY3JpcHRpb24uY29kZWNzLmZvckVhY2goY29kZWMgPT4ge1xuICAgIHdpbGRjYXJkUnRjcEZiLmZvckVhY2goZmI9PiB7XG4gICAgICBjb25zdCBkdXBsaWNhdGUgPSBjb2RlYy5ydGNwRmVlZGJhY2suZmluZChleGlzdGluZ0ZlZWRiYWNrID0+IHtcbiAgICAgICAgcmV0dXJuIGV4aXN0aW5nRmVlZGJhY2sudHlwZSA9PT0gZmIudHlwZSAmJlxuICAgICAgICAgIGV4aXN0aW5nRmVlZGJhY2sucGFyYW1ldGVyID09PSBmYi5wYXJhbWV0ZXI7XG4gICAgICB9KTtcbiAgICAgIGlmICghZHVwbGljYXRlKSB7XG4gICAgICAgIGNvZGVjLnJ0Y3BGZWVkYmFjay5wdXNoKGZiKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSk7XG4gIC8vIEZJWE1FOiBwYXJzZSBydGNwLlxuICByZXR1cm4gZGVzY3JpcHRpb247XG59O1xuXG4vLyBHZW5lcmF0ZXMgcGFydHMgb2YgdGhlIFNEUCBtZWRpYSBzZWN0aW9uIGRlc2NyaWJpbmcgdGhlIGNhcGFiaWxpdGllcyAvXG4vLyBwYXJhbWV0ZXJzLlxuU0RQVXRpbHMud3JpdGVSdHBEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uKGtpbmQsIGNhcHMpIHtcbiAgbGV0IHNkcCA9ICcnO1xuXG4gIC8vIEJ1aWxkIHRoZSBtbGluZS5cbiAgc2RwICs9ICdtPScgKyBraW5kICsgJyAnO1xuICBzZHAgKz0gY2Fwcy5jb2RlY3MubGVuZ3RoID4gMCA/ICc5JyA6ICcwJzsgLy8gcmVqZWN0IGlmIG5vIGNvZGVjcy5cbiAgc2RwICs9ICcgJyArIChjYXBzLnByb2ZpbGUgfHwgJ1VEUC9UTFMvUlRQL1NBVlBGJykgKyAnICc7XG4gIHNkcCArPSBjYXBzLmNvZGVjcy5tYXAoY29kZWMgPT4ge1xuICAgIGlmIChjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGU7XG4gICAgfVxuICAgIHJldHVybiBjb2RlYy5wYXlsb2FkVHlwZTtcbiAgfSkuam9pbignICcpICsgJ1xcclxcbic7XG5cbiAgc2RwICs9ICdjPUlOIElQNCAwLjAuMC4wXFxyXFxuJztcbiAgc2RwICs9ICdhPXJ0Y3A6OSBJTiBJUDQgMC4wLjAuMFxcclxcbic7XG5cbiAgLy8gQWRkIGE9cnRwbWFwIGxpbmVzIGZvciBlYWNoIGNvZGVjLiBBbHNvIGZtdHAgYW5kIHJ0Y3AtZmIuXG4gIGNhcHMuY29kZWNzLmZvckVhY2goY29kZWMgPT4ge1xuICAgIHNkcCArPSBTRFBVdGlscy53cml0ZVJ0cE1hcChjb2RlYyk7XG4gICAgc2RwICs9IFNEUFV0aWxzLndyaXRlRm10cChjb2RlYyk7XG4gICAgc2RwICs9IFNEUFV0aWxzLndyaXRlUnRjcEZiKGNvZGVjKTtcbiAgfSk7XG4gIGxldCBtYXhwdGltZSA9IDA7XG4gIGNhcHMuY29kZWNzLmZvckVhY2goY29kZWMgPT4ge1xuICAgIGlmIChjb2RlYy5tYXhwdGltZSA+IG1heHB0aW1lKSB7XG4gICAgICBtYXhwdGltZSA9IGNvZGVjLm1heHB0aW1lO1xuICAgIH1cbiAgfSk7XG4gIGlmIChtYXhwdGltZSA+IDApIHtcbiAgICBzZHAgKz0gJ2E9bWF4cHRpbWU6JyArIG1heHB0aW1lICsgJ1xcclxcbic7XG4gIH1cblxuICBpZiAoY2Fwcy5oZWFkZXJFeHRlbnNpb25zKSB7XG4gICAgY2Fwcy5oZWFkZXJFeHRlbnNpb25zLmZvckVhY2goZXh0ZW5zaW9uID0+IHtcbiAgICAgIHNkcCArPSBTRFBVdGlscy53cml0ZUV4dG1hcChleHRlbnNpb24pO1xuICAgIH0pO1xuICB9XG4gIC8vIEZJWE1FOiB3cml0ZSBmZWNNZWNoYW5pc21zLlxuICByZXR1cm4gc2RwO1xufTtcblxuLy8gUGFyc2VzIHRoZSBTRFAgbWVkaWEgc2VjdGlvbiBhbmQgcmV0dXJucyBhbiBhcnJheSBvZlxuLy8gUlRDUnRwRW5jb2RpbmdQYXJhbWV0ZXJzLlxuU0RQVXRpbHMucGFyc2VSdHBFbmNvZGluZ1BhcmFtZXRlcnMgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgY29uc3QgZW5jb2RpbmdQYXJhbWV0ZXJzID0gW107XG4gIGNvbnN0IGRlc2NyaXB0aW9uID0gU0RQVXRpbHMucGFyc2VSdHBQYXJhbWV0ZXJzKG1lZGlhU2VjdGlvbik7XG4gIGNvbnN0IGhhc1JlZCA9IGRlc2NyaXB0aW9uLmZlY01lY2hhbmlzbXMuaW5kZXhPZignUkVEJykgIT09IC0xO1xuICBjb25zdCBoYXNVbHBmZWMgPSBkZXNjcmlwdGlvbi5mZWNNZWNoYW5pc21zLmluZGV4T2YoJ1VMUEZFQycpICE9PSAtMTtcblxuICAvLyBmaWx0ZXIgYT1zc3JjOi4uLiBjbmFtZTosIGlnbm9yZSBQbGFuQi1tc2lkXG4gIGNvbnN0IHNzcmNzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1zc3JjOicpXG4gICAgLm1hcChsaW5lID0+IFNEUFV0aWxzLnBhcnNlU3NyY01lZGlhKGxpbmUpKVxuICAgIC5maWx0ZXIocGFydHMgPT4gcGFydHMuYXR0cmlidXRlID09PSAnY25hbWUnKTtcbiAgY29uc3QgcHJpbWFyeVNzcmMgPSBzc3Jjcy5sZW5ndGggPiAwICYmIHNzcmNzWzBdLnNzcmM7XG4gIGxldCBzZWNvbmRhcnlTc3JjO1xuXG4gIGNvbnN0IGZsb3dzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1zc3JjLWdyb3VwOkZJRCcpXG4gICAgLm1hcChsaW5lID0+IHtcbiAgICAgIGNvbnN0IHBhcnRzID0gbGluZS5zdWJzdHJpbmcoMTcpLnNwbGl0KCcgJyk7XG4gICAgICByZXR1cm4gcGFydHMubWFwKHBhcnQgPT4gcGFyc2VJbnQocGFydCwgMTApKTtcbiAgICB9KTtcbiAgaWYgKGZsb3dzLmxlbmd0aCA+IDAgJiYgZmxvd3NbMF0ubGVuZ3RoID4gMSAmJiBmbG93c1swXVswXSA9PT0gcHJpbWFyeVNzcmMpIHtcbiAgICBzZWNvbmRhcnlTc3JjID0gZmxvd3NbMF1bMV07XG4gIH1cblxuICBkZXNjcmlwdGlvbi5jb2RlY3MuZm9yRWFjaChjb2RlYyA9PiB7XG4gICAgaWYgKGNvZGVjLm5hbWUudG9VcHBlckNhc2UoKSA9PT0gJ1JUWCcgJiYgY29kZWMucGFyYW1ldGVycy5hcHQpIHtcbiAgICAgIGxldCBlbmNQYXJhbSA9IHtcbiAgICAgICAgc3NyYzogcHJpbWFyeVNzcmMsXG4gICAgICAgIGNvZGVjUGF5bG9hZFR5cGU6IHBhcnNlSW50KGNvZGVjLnBhcmFtZXRlcnMuYXB0LCAxMCksXG4gICAgICB9O1xuICAgICAgaWYgKHByaW1hcnlTc3JjICYmIHNlY29uZGFyeVNzcmMpIHtcbiAgICAgICAgZW5jUGFyYW0ucnR4ID0ge3NzcmM6IHNlY29uZGFyeVNzcmN9O1xuICAgICAgfVxuICAgICAgZW5jb2RpbmdQYXJhbWV0ZXJzLnB1c2goZW5jUGFyYW0pO1xuICAgICAgaWYgKGhhc1JlZCkge1xuICAgICAgICBlbmNQYXJhbSA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoZW5jUGFyYW0pKTtcbiAgICAgICAgZW5jUGFyYW0uZmVjID0ge1xuICAgICAgICAgIHNzcmM6IHByaW1hcnlTc3JjLFxuICAgICAgICAgIG1lY2hhbmlzbTogaGFzVWxwZmVjID8gJ3JlZCt1bHBmZWMnIDogJ3JlZCcsXG4gICAgICAgIH07XG4gICAgICAgIGVuY29kaW5nUGFyYW1ldGVycy5wdXNoKGVuY1BhcmFtKTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuICBpZiAoZW5jb2RpbmdQYXJhbWV0ZXJzLmxlbmd0aCA9PT0gMCAmJiBwcmltYXJ5U3NyYykge1xuICAgIGVuY29kaW5nUGFyYW1ldGVycy5wdXNoKHtcbiAgICAgIHNzcmM6IHByaW1hcnlTc3JjLFxuICAgIH0pO1xuICB9XG5cbiAgLy8gd2Ugc3VwcG9ydCBib3RoIGI9QVMgYW5kIGI9VElBUyBidXQgaW50ZXJwcmV0IEFTIGFzIFRJQVMuXG4gIGxldCBiYW5kd2lkdGggPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdiPScpO1xuICBpZiAoYmFuZHdpZHRoLmxlbmd0aCkge1xuICAgIGlmIChiYW5kd2lkdGhbMF0uaW5kZXhPZignYj1USUFTOicpID09PSAwKSB7XG4gICAgICBiYW5kd2lkdGggPSBwYXJzZUludChiYW5kd2lkdGhbMF0uc3Vic3RyaW5nKDcpLCAxMCk7XG4gICAgfSBlbHNlIGlmIChiYW5kd2lkdGhbMF0uaW5kZXhPZignYj1BUzonKSA9PT0gMCkge1xuICAgICAgLy8gdXNlIGZvcm11bGEgZnJvbSBKU0VQIHRvIGNvbnZlcnQgYj1BUyB0byBUSUFTIHZhbHVlLlxuICAgICAgYmFuZHdpZHRoID0gcGFyc2VJbnQoYmFuZHdpZHRoWzBdLnN1YnN0cmluZyg1KSwgMTApICogMTAwMCAqIDAuOTVcbiAgICAgICAgICAtICg1MCAqIDQwICogOCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGJhbmR3aWR0aCA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgZW5jb2RpbmdQYXJhbWV0ZXJzLmZvckVhY2gocGFyYW1zID0+IHtcbiAgICAgIHBhcmFtcy5tYXhCaXRyYXRlID0gYmFuZHdpZHRoO1xuICAgIH0pO1xuICB9XG4gIHJldHVybiBlbmNvZGluZ1BhcmFtZXRlcnM7XG59O1xuXG4vLyBwYXJzZXMgaHR0cDovL2RyYWZ0Lm9ydGMub3JnLyNydGNydGNwcGFyYW1ldGVycypcblNEUFV0aWxzLnBhcnNlUnRjcFBhcmFtZXRlcnMgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgY29uc3QgcnRjcFBhcmFtZXRlcnMgPSB7fTtcblxuICAvLyBHZXRzIHRoZSBmaXJzdCBTU1JDLiBOb3RlIHRoYXQgd2l0aCBSVFggdGhlcmUgbWlnaHQgYmUgbXVsdGlwbGVcbiAgLy8gU1NSQ3MuXG4gIGNvbnN0IHJlbW90ZVNzcmMgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXNzcmM6JylcbiAgICAubWFwKGxpbmUgPT4gU0RQVXRpbHMucGFyc2VTc3JjTWVkaWEobGluZSkpXG4gICAgLmZpbHRlcihvYmogPT4gb2JqLmF0dHJpYnV0ZSA9PT0gJ2NuYW1lJylbMF07XG4gIGlmIChyZW1vdGVTc3JjKSB7XG4gICAgcnRjcFBhcmFtZXRlcnMuY25hbWUgPSByZW1vdGVTc3JjLnZhbHVlO1xuICAgIHJ0Y3BQYXJhbWV0ZXJzLnNzcmMgPSByZW1vdGVTc3JjLnNzcmM7XG4gIH1cblxuICAvLyBFZGdlIHVzZXMgdGhlIGNvbXBvdW5kIGF0dHJpYnV0ZSBpbnN0ZWFkIG9mIHJlZHVjZWRTaXplXG4gIC8vIGNvbXBvdW5kIGlzICFyZWR1Y2VkU2l6ZVxuICBjb25zdCByc2l6ZSA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9cnRjcC1yc2l6ZScpO1xuICBydGNwUGFyYW1ldGVycy5yZWR1Y2VkU2l6ZSA9IHJzaXplLmxlbmd0aCA+IDA7XG4gIHJ0Y3BQYXJhbWV0ZXJzLmNvbXBvdW5kID0gcnNpemUubGVuZ3RoID09PSAwO1xuXG4gIC8vIHBhcnNlcyB0aGUgcnRjcC1tdXggYXR0ctGWYnV0ZS5cbiAgLy8gTm90ZSB0aGF0IEVkZ2UgZG9lcyBub3Qgc3VwcG9ydCB1bm11eGVkIFJUQ1AuXG4gIGNvbnN0IG11eCA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9cnRjcC1tdXgnKTtcbiAgcnRjcFBhcmFtZXRlcnMubXV4ID0gbXV4Lmxlbmd0aCA+IDA7XG5cbiAgcmV0dXJuIHJ0Y3BQYXJhbWV0ZXJzO1xufTtcblxuU0RQVXRpbHMud3JpdGVSdGNwUGFyYW1ldGVycyA9IGZ1bmN0aW9uKHJ0Y3BQYXJhbWV0ZXJzKSB7XG4gIGxldCBzZHAgPSAnJztcbiAgaWYgKHJ0Y3BQYXJhbWV0ZXJzLnJlZHVjZWRTaXplKSB7XG4gICAgc2RwICs9ICdhPXJ0Y3AtcnNpemVcXHJcXG4nO1xuICB9XG4gIGlmIChydGNwUGFyYW1ldGVycy5tdXgpIHtcbiAgICBzZHAgKz0gJ2E9cnRjcC1tdXhcXHJcXG4nO1xuICB9XG4gIGlmIChydGNwUGFyYW1ldGVycy5zc3JjICE9PSB1bmRlZmluZWQgJiYgcnRjcFBhcmFtZXRlcnMuY25hbWUpIHtcbiAgICBzZHAgKz0gJ2E9c3NyYzonICsgcnRjcFBhcmFtZXRlcnMuc3NyYyArXG4gICAgICAnIGNuYW1lOicgKyBydGNwUGFyYW1ldGVycy5jbmFtZSArICdcXHJcXG4nO1xuICB9XG4gIHJldHVybiBzZHA7XG59O1xuXG5cbi8vIHBhcnNlcyBlaXRoZXIgYT1tc2lkOiBvciBhPXNzcmM6Li4uIG1zaWQgbGluZXMgYW5kIHJldHVybnNcbi8vIHRoZSBpZCBvZiB0aGUgTWVkaWFTdHJlYW0gYW5kIE1lZGlhU3RyZWFtVHJhY2suXG5TRFBVdGlscy5wYXJzZU1zaWQgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgbGV0IHBhcnRzO1xuICBjb25zdCBzcGVjID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1tc2lkOicpO1xuICBpZiAoc3BlYy5sZW5ndGggPT09IDEpIHtcbiAgICBwYXJ0cyA9IHNwZWNbMF0uc3Vic3RyaW5nKDcpLnNwbGl0KCcgJyk7XG4gICAgcmV0dXJuIHtzdHJlYW06IHBhcnRzWzBdLCB0cmFjazogcGFydHNbMV19O1xuICB9XG4gIGNvbnN0IHBsYW5CID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1zc3JjOicpXG4gICAgLm1hcChsaW5lID0+IFNEUFV0aWxzLnBhcnNlU3NyY01lZGlhKGxpbmUpKVxuICAgIC5maWx0ZXIobXNpZFBhcnRzID0+IG1zaWRQYXJ0cy5hdHRyaWJ1dGUgPT09ICdtc2lkJyk7XG4gIGlmIChwbGFuQi5sZW5ndGggPiAwKSB7XG4gICAgcGFydHMgPSBwbGFuQlswXS52YWx1ZS5zcGxpdCgnICcpO1xuICAgIHJldHVybiB7c3RyZWFtOiBwYXJ0c1swXSwgdHJhY2s6IHBhcnRzWzFdfTtcbiAgfVxufTtcblxuLy8gU0NUUFxuLy8gcGFyc2VzIGRyYWZ0LWlldGYtbW11c2ljLXNjdHAtc2RwLTI2IGZpcnN0IGFuZCBmYWxscyBiYWNrXG4vLyB0byBkcmFmdC1pZXRmLW1tdXNpYy1zY3RwLXNkcC0wNVxuU0RQVXRpbHMucGFyc2VTY3RwRGVzY3JpcHRpb24gPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgY29uc3QgbWxpbmUgPSBTRFBVdGlscy5wYXJzZU1MaW5lKG1lZGlhU2VjdGlvbik7XG4gIGNvbnN0IG1heFNpemVMaW5lID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1tYXgtbWVzc2FnZS1zaXplOicpO1xuICBsZXQgbWF4TWVzc2FnZVNpemU7XG4gIGlmIChtYXhTaXplTGluZS5sZW5ndGggPiAwKSB7XG4gICAgbWF4TWVzc2FnZVNpemUgPSBwYXJzZUludChtYXhTaXplTGluZVswXS5zdWJzdHJpbmcoMTkpLCAxMCk7XG4gIH1cbiAgaWYgKGlzTmFOKG1heE1lc3NhZ2VTaXplKSkge1xuICAgIG1heE1lc3NhZ2VTaXplID0gNjU1MzY7XG4gIH1cbiAgY29uc3Qgc2N0cFBvcnQgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXNjdHAtcG9ydDonKTtcbiAgaWYgKHNjdHBQb3J0Lmxlbmd0aCA+IDApIHtcbiAgICByZXR1cm4ge1xuICAgICAgcG9ydDogcGFyc2VJbnQoc2N0cFBvcnRbMF0uc3Vic3RyaW5nKDEyKSwgMTApLFxuICAgICAgcHJvdG9jb2w6IG1saW5lLmZtdCxcbiAgICAgIG1heE1lc3NhZ2VTaXplLFxuICAgIH07XG4gIH1cbiAgY29uc3Qgc2N0cE1hcExpbmVzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1zY3RwbWFwOicpO1xuICBpZiAoc2N0cE1hcExpbmVzLmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCBwYXJ0cyA9IHNjdHBNYXBMaW5lc1swXVxuICAgICAgLnN1YnN0cmluZygxMClcbiAgICAgIC5zcGxpdCgnICcpO1xuICAgIHJldHVybiB7XG4gICAgICBwb3J0OiBwYXJzZUludChwYXJ0c1swXSwgMTApLFxuICAgICAgcHJvdG9jb2w6IHBhcnRzWzFdLFxuICAgICAgbWF4TWVzc2FnZVNpemUsXG4gICAgfTtcbiAgfVxufTtcblxuLy8gU0NUUFxuLy8gb3V0cHV0cyB0aGUgZHJhZnQtaWV0Zi1tbXVzaWMtc2N0cC1zZHAtMjYgdmVyc2lvbiB0aGF0IGFsbCBicm93c2Vyc1xuLy8gc3VwcG9ydCBieSBub3cgcmVjZWl2aW5nIGluIHRoaXMgZm9ybWF0LCB1bmxlc3Mgd2Ugb3JpZ2luYWxseSBwYXJzZWRcbi8vIGFzIHRoZSBkcmFmdC1pZXRmLW1tdXNpYy1zY3RwLXNkcC0wNSBmb3JtYXQgKGluZGljYXRlZCBieSB0aGUgbS1saW5lXG4vLyBwcm90b2NvbCBvZiBEVExTL1NDVFAgLS0gd2l0aG91dCBVRFAvIG9yIFRDUC8pXG5TRFBVdGlscy53cml0ZVNjdHBEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uKG1lZGlhLCBzY3RwKSB7XG4gIGxldCBvdXRwdXQgPSBbXTtcbiAgaWYgKG1lZGlhLnByb3RvY29sICE9PSAnRFRMUy9TQ1RQJykge1xuICAgIG91dHB1dCA9IFtcbiAgICAgICdtPScgKyBtZWRpYS5raW5kICsgJyA5ICcgKyBtZWRpYS5wcm90b2NvbCArICcgJyArIHNjdHAucHJvdG9jb2wgKyAnXFxyXFxuJyxcbiAgICAgICdjPUlOIElQNCAwLjAuMC4wXFxyXFxuJyxcbiAgICAgICdhPXNjdHAtcG9ydDonICsgc2N0cC5wb3J0ICsgJ1xcclxcbicsXG4gICAgXTtcbiAgfSBlbHNlIHtcbiAgICBvdXRwdXQgPSBbXG4gICAgICAnbT0nICsgbWVkaWEua2luZCArICcgOSAnICsgbWVkaWEucHJvdG9jb2wgKyAnICcgKyBzY3RwLnBvcnQgKyAnXFxyXFxuJyxcbiAgICAgICdjPUlOIElQNCAwLjAuMC4wXFxyXFxuJyxcbiAgICAgICdhPXNjdHBtYXA6JyArIHNjdHAucG9ydCArICcgJyArIHNjdHAucHJvdG9jb2wgKyAnIDY1NTM1XFxyXFxuJyxcbiAgICBdO1xuICB9XG4gIGlmIChzY3RwLm1heE1lc3NhZ2VTaXplICE9PSB1bmRlZmluZWQpIHtcbiAgICBvdXRwdXQucHVzaCgnYT1tYXgtbWVzc2FnZS1zaXplOicgKyBzY3RwLm1heE1lc3NhZ2VTaXplICsgJ1xcclxcbicpO1xuICB9XG4gIHJldHVybiBvdXRwdXQuam9pbignJyk7XG59O1xuXG4vLyBHZW5lcmF0ZSBhIHNlc3Npb24gSUQgZm9yIFNEUC5cbi8vIGh0dHBzOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9kcmFmdC1pZXRmLXJ0Y3dlYi1qc2VwLTIwI3NlY3Rpb24tNS4yLjFcbi8vIHJlY29tbWVuZHMgdXNpbmcgYSBjcnlwdG9ncmFwaGljYWxseSByYW5kb20gK3ZlIDY0LWJpdCB2YWx1ZVxuLy8gYnV0IHJpZ2h0IG5vdyB0aGlzIHNob3VsZCBiZSBhY2NlcHRhYmxlIGFuZCB3aXRoaW4gdGhlIHJpZ2h0IHJhbmdlXG5TRFBVdGlscy5nZW5lcmF0ZVNlc3Npb25JZCA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gTWF0aC5yYW5kb20oKS50b1N0cmluZygpLnN1YnN0cigyLCAyMik7XG59O1xuXG4vLyBXcml0ZSBib2lsZXIgcGxhdGUgZm9yIHN0YXJ0IG9mIFNEUFxuLy8gc2Vzc0lkIGFyZ3VtZW50IGlzIG9wdGlvbmFsIC0gaWYgbm90IHN1cHBsaWVkIGl0IHdpbGxcbi8vIGJlIGdlbmVyYXRlZCByYW5kb21seVxuLy8gc2Vzc1ZlcnNpb24gaXMgb3B0aW9uYWwgYW5kIGRlZmF1bHRzIHRvIDJcbi8vIHNlc3NVc2VyIGlzIG9wdGlvbmFsIGFuZCBkZWZhdWx0cyB0byAndGhpc2lzYWRhcHRlcm9ydGMnXG5TRFBVdGlscy53cml0ZVNlc3Npb25Cb2lsZXJwbGF0ZSA9IGZ1bmN0aW9uKHNlc3NJZCwgc2Vzc1Zlciwgc2Vzc1VzZXIpIHtcbiAgbGV0IHNlc3Npb25JZDtcbiAgY29uc3QgdmVyc2lvbiA9IHNlc3NWZXIgIT09IHVuZGVmaW5lZCA/IHNlc3NWZXIgOiAyO1xuICBpZiAoc2Vzc0lkKSB7XG4gICAgc2Vzc2lvbklkID0gc2Vzc0lkO1xuICB9IGVsc2Uge1xuICAgIHNlc3Npb25JZCA9IFNEUFV0aWxzLmdlbmVyYXRlU2Vzc2lvbklkKCk7XG4gIH1cbiAgY29uc3QgdXNlciA9IHNlc3NVc2VyIHx8ICd0aGlzaXNhZGFwdGVyb3J0Yyc7XG4gIC8vIEZJWE1FOiBzZXNzLWlkIHNob3VsZCBiZSBhbiBOVFAgdGltZXN0YW1wLlxuICByZXR1cm4gJ3Y9MFxcclxcbicgK1xuICAgICAgJ289JyArIHVzZXIgKyAnICcgKyBzZXNzaW9uSWQgKyAnICcgKyB2ZXJzaW9uICtcbiAgICAgICAgJyBJTiBJUDQgMTI3LjAuMC4xXFxyXFxuJyArXG4gICAgICAncz0tXFxyXFxuJyArXG4gICAgICAndD0wIDBcXHJcXG4nO1xufTtcblxuLy8gR2V0cyB0aGUgZGlyZWN0aW9uIGZyb20gdGhlIG1lZGlhU2VjdGlvbiBvciB0aGUgc2Vzc2lvbnBhcnQuXG5TRFBVdGlscy5nZXREaXJlY3Rpb24gPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KSB7XG4gIC8vIExvb2sgZm9yIHNlbmRyZWN2LCBzZW5kb25seSwgcmVjdm9ubHksIGluYWN0aXZlLCBkZWZhdWx0IHRvIHNlbmRyZWN2LlxuICBjb25zdCBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMobWVkaWFTZWN0aW9uKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKykge1xuICAgIHN3aXRjaCAobGluZXNbaV0pIHtcbiAgICAgIGNhc2UgJ2E9c2VuZHJlY3YnOlxuICAgICAgY2FzZSAnYT1zZW5kb25seSc6XG4gICAgICBjYXNlICdhPXJlY3Zvbmx5JzpcbiAgICAgIGNhc2UgJ2E9aW5hY3RpdmUnOlxuICAgICAgICByZXR1cm4gbGluZXNbaV0uc3Vic3RyaW5nKDIpO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgLy8gRklYTUU6IFdoYXQgc2hvdWxkIGhhcHBlbiBoZXJlP1xuICAgIH1cbiAgfVxuICBpZiAoc2Vzc2lvbnBhcnQpIHtcbiAgICByZXR1cm4gU0RQVXRpbHMuZ2V0RGlyZWN0aW9uKHNlc3Npb25wYXJ0KTtcbiAgfVxuICByZXR1cm4gJ3NlbmRyZWN2Jztcbn07XG5cblNEUFV0aWxzLmdldEtpbmQgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgY29uc3QgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIGNvbnN0IG1saW5lID0gbGluZXNbMF0uc3BsaXQoJyAnKTtcbiAgcmV0dXJuIG1saW5lWzBdLnN1YnN0cmluZygyKTtcbn07XG5cblNEUFV0aWxzLmlzUmVqZWN0ZWQgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgcmV0dXJuIG1lZGlhU2VjdGlvbi5zcGxpdCgnICcsIDIpWzFdID09PSAnMCc7XG59O1xuXG5TRFBVdGlscy5wYXJzZU1MaW5lID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIGNvbnN0IGxpbmVzID0gU0RQVXRpbHMuc3BsaXRMaW5lcyhtZWRpYVNlY3Rpb24pO1xuICBjb25zdCBwYXJ0cyA9IGxpbmVzWzBdLnN1YnN0cmluZygyKS5zcGxpdCgnICcpO1xuICByZXR1cm4ge1xuICAgIGtpbmQ6IHBhcnRzWzBdLFxuICAgIHBvcnQ6IHBhcnNlSW50KHBhcnRzWzFdLCAxMCksXG4gICAgcHJvdG9jb2w6IHBhcnRzWzJdLFxuICAgIGZtdDogcGFydHMuc2xpY2UoMykuam9pbignICcpLFxuICB9O1xufTtcblxuU0RQVXRpbHMucGFyc2VPTGluZSA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICBjb25zdCBsaW5lID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnbz0nKVswXTtcbiAgY29uc3QgcGFydHMgPSBsaW5lLnN1YnN0cmluZygyKS5zcGxpdCgnICcpO1xuICByZXR1cm4ge1xuICAgIHVzZXJuYW1lOiBwYXJ0c1swXSxcbiAgICBzZXNzaW9uSWQ6IHBhcnRzWzFdLFxuICAgIHNlc3Npb25WZXJzaW9uOiBwYXJzZUludChwYXJ0c1syXSwgMTApLFxuICAgIG5ldFR5cGU6IHBhcnRzWzNdLFxuICAgIGFkZHJlc3NUeXBlOiBwYXJ0c1s0XSxcbiAgICBhZGRyZXNzOiBwYXJ0c1s1XSxcbiAgfTtcbn07XG5cbi8vIGEgdmVyeSBuYWl2ZSBpbnRlcnByZXRhdGlvbiBvZiBhIHZhbGlkIFNEUC5cblNEUFV0aWxzLmlzVmFsaWRTRFAgPSBmdW5jdGlvbihibG9iKSB7XG4gIGlmICh0eXBlb2YgYmxvYiAhPT0gJ3N0cmluZycgfHwgYmxvYi5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY29uc3QgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKGJsb2IpO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKGxpbmVzW2ldLmxlbmd0aCA8IDIgfHwgbGluZXNbaV0uY2hhckF0KDEpICE9PSAnPScpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLy8gVE9ETzogY2hlY2sgdGhlIG1vZGlmaWVyIGEgYml0IG1vcmUuXG4gIH1cbiAgcmV0dXJuIHRydWU7XG59O1xuXG4vLyBFeHBvc2UgcHVibGljIG1ldGhvZHMuXG5pZiAodHlwZW9mIG1vZHVsZSA9PT0gJ29iamVjdCcpIHtcbiAgbW9kdWxlLmV4cG9ydHMgPSBTRFBVdGlscztcbn1cbiIsIi8vIFRoZSBtb2R1bGUgY2FjaGVcbnZhciBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX18gPSB7fTtcblxuLy8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbmZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG5cdHZhciBjYWNoZWRNb2R1bGUgPSBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX19bbW9kdWxlSWRdO1xuXHRpZiAoY2FjaGVkTW9kdWxlICE9PSB1bmRlZmluZWQpIHtcblx0XHRyZXR1cm4gY2FjaGVkTW9kdWxlLmV4cG9ydHM7XG5cdH1cblx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcblx0dmFyIG1vZHVsZSA9IF9fd2VicGFja19tb2R1bGVfY2FjaGVfX1ttb2R1bGVJZF0gPSB7XG5cdFx0Ly8gbm8gbW9kdWxlLmlkIG5lZWRlZFxuXHRcdC8vIG5vIG1vZHVsZS5sb2FkZWQgbmVlZGVkXG5cdFx0ZXhwb3J0czoge31cblx0fTtcblxuXHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cblx0X193ZWJwYWNrX21vZHVsZXNfX1ttb2R1bGVJZF0obW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cblx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcblx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xufVxuXG4iLCIiLCIvLyBzdGFydHVwXG4vLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbi8vIFRoaXMgZW50cnkgbW9kdWxlIGlzIHJlZmVyZW5jZWQgYnkgb3RoZXIgbW9kdWxlcyBzbyBpdCBjYW4ndCBiZSBpbmxpbmVkXG52YXIgX193ZWJwYWNrX2V4cG9ydHNfXyA9IF9fd2VicGFja19yZXF1aXJlX18oXCIuL3NyYy9pbmRleC5qc1wiKTtcbiIsIiJdLCJuYW1lcyI6WyJtaiIsInJlcXVpcmUiLCJKYW51c1Nlc3Npb24iLCJwcm90b3R5cGUiLCJzZW5kT3JpZ2luYWwiLCJzZW5kIiwidHlwZSIsInNpZ25hbCIsImNhdGNoIiwiZSIsIm1lc3NhZ2UiLCJpbmRleE9mIiwiY29uc29sZSIsImVycm9yIiwiTkFGIiwiY29ubmVjdGlvbiIsImFkYXB0ZXIiLCJyZWNvbm5lY3QiLCJzZHBVdGlscyIsImRlYnVnIiwid2FybiIsImlzU2FmYXJpIiwidGVzdCIsIm5hdmlnYXRvciIsInVzZXJBZ2VudCIsIlNVQlNDUklCRV9USU1FT1VUX01TIiwiQVZBSUxBQkxFX09DQ1VQQU5UU19USFJFU0hPTEQiLCJNQVhfU1VCU0NSSUJFX0RFTEFZIiwicmFuZG9tRGVsYXkiLCJtaW4iLCJtYXgiLCJQcm9taXNlIiwicmVzb2x2ZSIsImRlbGF5IiwiTWF0aCIsInJhbmRvbSIsInNldFRpbWVvdXQiLCJkZWJvdW5jZSIsImZuIiwiY3VyciIsImFyZ3MiLCJBcnJheSIsInNsaWNlIiwiY2FsbCIsImFyZ3VtZW50cyIsInRoZW4iLCJfIiwiYXBwbHkiLCJyYW5kb21VaW50IiwiZmxvb3IiLCJOdW1iZXIiLCJNQVhfU0FGRV9JTlRFR0VSIiwidW50aWxEYXRhQ2hhbm5lbE9wZW4iLCJkYXRhQ2hhbm5lbCIsInJlamVjdCIsInJlYWR5U3RhdGUiLCJyZXNvbHZlciIsInJlamVjdG9yIiwiY2xlYXIiLCJyZW1vdmVFdmVudExpc3RlbmVyIiwiYWRkRXZlbnRMaXN0ZW5lciIsImlzSDI2NFZpZGVvU3VwcG9ydGVkIiwidmlkZW8iLCJkb2N1bWVudCIsImNyZWF0ZUVsZW1lbnQiLCJjYW5QbGF5VHlwZSIsIk9QVVNfUEFSQU1FVEVSUyIsInVzZWR0eCIsInN0ZXJlbyIsIkRFRkFVTFRfUEVFUl9DT05ORUNUSU9OX0NPTkZJRyIsImljZVNlcnZlcnMiLCJ1cmxzIiwiV1NfTk9STUFMX0NMT1NVUkUiLCJKYW51c0FkYXB0ZXIiLCJjb25zdHJ1Y3RvciIsInJvb20iLCJjbGllbnRJZCIsImpvaW5Ub2tlbiIsInNlcnZlclVybCIsIndlYlJ0Y09wdGlvbnMiLCJwZWVyQ29ubmVjdGlvbkNvbmZpZyIsIndzIiwic2Vzc2lvbiIsInJlbGlhYmxlVHJhbnNwb3J0IiwidW5yZWxpYWJsZVRyYW5zcG9ydCIsImluaXRpYWxSZWNvbm5lY3Rpb25EZWxheSIsInJlY29ubmVjdGlvbkRlbGF5IiwicmVjb25uZWN0aW9uVGltZW91dCIsIm1heFJlY29ubmVjdGlvbkF0dGVtcHRzIiwicmVjb25uZWN0aW9uQXR0ZW1wdHMiLCJwdWJsaXNoZXIiLCJvY2N1cGFudElkcyIsIm9jY3VwYW50cyIsIm1lZGlhU3RyZWFtcyIsImxvY2FsTWVkaWFTdHJlYW0iLCJwZW5kaW5nTWVkaWFSZXF1ZXN0cyIsIk1hcCIsInBlbmRpbmdPY2N1cGFudHMiLCJTZXQiLCJhdmFpbGFibGVPY2N1cGFudHMiLCJyZXF1ZXN0ZWRPY2N1cGFudHMiLCJibG9ja2VkQ2xpZW50cyIsImZyb3plblVwZGF0ZXMiLCJ0aW1lT2Zmc2V0cyIsInNlcnZlclRpbWVSZXF1ZXN0cyIsImF2Z1RpbWVPZmZzZXQiLCJvbldlYnNvY2tldE9wZW4iLCJiaW5kIiwib25XZWJzb2NrZXRDbG9zZSIsIm9uV2Vic29ja2V0TWVzc2FnZSIsIm9uRGF0YUNoYW5uZWxNZXNzYWdlIiwib25EYXRhIiwic2V0U2VydmVyVXJsIiwidXJsIiwic2V0QXBwIiwiYXBwIiwic2V0Um9vbSIsInJvb21OYW1lIiwic2V0Sm9pblRva2VuIiwic2V0Q2xpZW50SWQiLCJzZXRXZWJSdGNPcHRpb25zIiwib3B0aW9ucyIsInNldFBlZXJDb25uZWN0aW9uQ29uZmlnIiwic2V0U2VydmVyQ29ubmVjdExpc3RlbmVycyIsInN1Y2Nlc3NMaXN0ZW5lciIsImZhaWx1cmVMaXN0ZW5lciIsImNvbm5lY3RTdWNjZXNzIiwiY29ubmVjdEZhaWx1cmUiLCJzZXRSb29tT2NjdXBhbnRMaXN0ZW5lciIsIm9jY3VwYW50TGlzdGVuZXIiLCJvbk9jY3VwYW50c0NoYW5nZWQiLCJzZXREYXRhQ2hhbm5lbExpc3RlbmVycyIsIm9wZW5MaXN0ZW5lciIsImNsb3NlZExpc3RlbmVyIiwibWVzc2FnZUxpc3RlbmVyIiwib25PY2N1cGFudENvbm5lY3RlZCIsIm9uT2NjdXBhbnREaXNjb25uZWN0ZWQiLCJvbk9jY3VwYW50TWVzc2FnZSIsInNldFJlY29ubmVjdGlvbkxpc3RlbmVycyIsInJlY29ubmVjdGluZ0xpc3RlbmVyIiwicmVjb25uZWN0ZWRMaXN0ZW5lciIsInJlY29ubmVjdGlvbkVycm9yTGlzdGVuZXIiLCJvblJlY29ubmVjdGluZyIsIm9uUmVjb25uZWN0ZWQiLCJvblJlY29ubmVjdGlvbkVycm9yIiwic2V0RXZlbnRMb29wcyIsImxvb3BzIiwiY29ubmVjdCIsIndlYnNvY2tldENvbm5lY3Rpb24iLCJXZWJTb2NrZXQiLCJ0aW1lb3V0TXMiLCJ3c09uT3BlbiIsImFsbCIsInVwZGF0ZVRpbWVPZmZzZXQiLCJkaXNjb25uZWN0IiwiY2xlYXJUaW1lb3V0IiwicmVtb3ZlQWxsT2NjdXBhbnRzIiwiY29ubiIsImNsb3NlIiwiZGlzcG9zZSIsImRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0IiwiaXNEaXNjb25uZWN0ZWQiLCJjcmVhdGUiLCJjcmVhdGVQdWJsaXNoZXIiLCJpIiwiaW5pdGlhbE9jY3VwYW50cyIsImxlbmd0aCIsIm9jY3VwYW50SWQiLCJhZGRBdmFpbGFibGVPY2N1cGFudCIsInN5bmNPY2N1cGFudHMiLCJldmVudCIsImNvZGUiLCJFcnJvciIsInBlcmZvcm1EZWxheWVkUmVjb25uZWN0IiwicmVjZWl2ZSIsIkpTT04iLCJwYXJzZSIsImRhdGEiLCJwdXNoIiwicmVtb3ZlQXZhaWxhYmxlT2NjdXBhbnQiLCJpZHgiLCJzcGxpY2UiLCJoYXMiLCJhZGRPY2N1cGFudCIsImoiLCJyZW1vdmVPY2N1cGFudCIsImFkZCIsImF2YWlsYWJsZU9jY3VwYW50c0NvdW50Iiwic3Vic2NyaWJlciIsImNyZWF0ZVN1YnNjcmliZXIiLCJkZWxldGUiLCJzZXRNZWRpYVN0cmVhbSIsIm1lZGlhU3RyZWFtIiwibXNnIiwiZ2V0IiwiYXVkaW8iLCJhc3NvY2lhdGUiLCJoYW5kbGUiLCJldiIsInNlbmRUcmlja2xlIiwiY2FuZGlkYXRlIiwiaWNlQ29ubmVjdGlvblN0YXRlIiwibG9nIiwib2ZmZXIiLCJjcmVhdGVPZmZlciIsImNvbmZpZ3VyZVB1Ymxpc2hlclNkcCIsImZpeFNhZmFyaUljZVVGcmFnIiwibG9jYWwiLCJvIiwic2V0TG9jYWxEZXNjcmlwdGlvbiIsInJlbW90ZSIsInNlbmRKc2VwIiwiciIsInNldFJlbW90ZURlc2NyaXB0aW9uIiwianNlcCIsIm9uIiwiYW5zd2VyIiwiY29uZmlndXJlU3Vic2NyaWJlclNkcCIsImNyZWF0ZUFuc3dlciIsImEiLCJKYW51c1BsdWdpbkhhbmRsZSIsIlJUQ1BlZXJDb25uZWN0aW9uIiwiYXR0YWNoIiwicGFyc2VJbnQiLCJ1bmRlZmluZWQiLCJ3ZWJydGN1cCIsInJlbGlhYmxlQ2hhbm5lbCIsImNyZWF0ZURhdGFDaGFubmVsIiwib3JkZXJlZCIsInVucmVsaWFibGVDaGFubmVsIiwibWF4UmV0cmFuc21pdHMiLCJnZXRUcmFja3MiLCJmb3JFYWNoIiwidHJhY2siLCJhZGRUcmFjayIsInBsdWdpbmRhdGEiLCJyb29tX2lkIiwidXNlcl9pZCIsImJvZHkiLCJkaXNwYXRjaEV2ZW50IiwiQ3VzdG9tRXZlbnQiLCJkZXRhaWwiLCJieSIsInNlbmRKb2luIiwibm90aWZpY2F0aW9ucyIsInN1Y2Nlc3MiLCJlcnIiLCJyZXNwb25zZSIsInVzZXJzIiwiaW5jbHVkZXMiLCJzZHAiLCJyZXBsYWNlIiwibGluZSIsInB0IiwicGFyYW1ldGVycyIsIk9iamVjdCIsImFzc2lnbiIsInBhcnNlRm10cCIsIndyaXRlRm10cCIsInBheWxvYWRUeXBlIiwibWF4UmV0cmllcyIsIndlYnJ0Y0ZhaWxlZCIsImxlZnRJbnRlcnZhbCIsInNldEludGVydmFsIiwiY2xlYXJJbnRlcnZhbCIsInRpbWVvdXQiLCJtZWRpYSIsIl9pT1NIYWNrRGVsYXllZEluaXRpYWxQZWVyIiwiTWVkaWFTdHJlYW0iLCJyZWNlaXZlcnMiLCJnZXRSZWNlaXZlcnMiLCJyZWNlaXZlciIsInN1YnNjcmliZSIsInNlbmRNZXNzYWdlIiwia2luZCIsInRva2VuIiwidG9nZ2xlRnJlZXplIiwiZnJvemVuIiwidW5mcmVlemUiLCJmcmVlemUiLCJmbHVzaFBlbmRpbmdVcGRhdGVzIiwiZGF0YUZvclVwZGF0ZU11bHRpTWVzc2FnZSIsIm5ldHdvcmtJZCIsImwiLCJkIiwiZ2V0UGVuZGluZ0RhdGEiLCJkYXRhVHlwZSIsIm93bmVyIiwiZ2V0UGVuZGluZ0RhdGFGb3JOZXR3b3JrSWQiLCJzb3VyY2UiLCJzdG9yZU1lc3NhZ2UiLCJzdG9yZVNpbmdsZU1lc3NhZ2UiLCJpbmRleCIsInNldCIsInN0b3JlZE1lc3NhZ2UiLCJzdG9yZWREYXRhIiwiaXNPdXRkYXRlZE1lc3NhZ2UiLCJsYXN0T3duZXJUaW1lIiwiaXNDb250ZW1wb3JhbmVvdXNNZXNzYWdlIiwiY3JlYXRlZFdoaWxlRnJvemVuIiwiaXNGaXJzdFN5bmMiLCJjb21wb25lbnRzIiwiZW5hYmxlZCIsInNob3VsZFN0YXJ0Q29ubmVjdGlvblRvIiwiY2xpZW50Iiwic3RhcnRTdHJlYW1Db25uZWN0aW9uIiwiY2xvc2VTdHJlYW1Db25uZWN0aW9uIiwiZ2V0Q29ubmVjdFN0YXR1cyIsImFkYXB0ZXJzIiwiSVNfQ09OTkVDVEVEIiwiTk9UX0NPTk5FQ1RFRCIsImNsaWVudFNlbnRUaW1lIiwiRGF0ZSIsIm5vdyIsInJlcyIsImZldGNoIiwibG9jYXRpb24iLCJocmVmIiwibWV0aG9kIiwiY2FjaGUiLCJwcmVjaXNpb24iLCJzZXJ2ZXJSZWNlaXZlZFRpbWUiLCJoZWFkZXJzIiwiZ2V0VGltZSIsImNsaWVudFJlY2VpdmVkVGltZSIsInNlcnZlclRpbWUiLCJ0aW1lT2Zmc2V0IiwicmVkdWNlIiwiYWNjIiwib2Zmc2V0IiwiZ2V0U2VydmVyVGltZSIsImdldE1lZGlhU3RyZWFtIiwiYXVkaW9Qcm9taXNlIiwidmlkZW9Qcm9taXNlIiwicHJvbWlzZSIsInN0cmVhbSIsImF1ZGlvU3RyZWFtIiwiZ2V0QXVkaW9UcmFja3MiLCJ2aWRlb1N0cmVhbSIsImdldFZpZGVvVHJhY2tzIiwiZ2V0TG9jYWxNZWRpYVN0cmVhbSIsInNldExvY2FsTWVkaWFTdHJlYW0iLCJleGlzdGluZ1NlbmRlcnMiLCJnZXRTZW5kZXJzIiwibmV3U2VuZGVycyIsInRyYWNrcyIsInQiLCJzZW5kZXIiLCJmaW5kIiwicyIsInJlcGxhY2VUcmFjayIsInJlbW92ZVRyYWNrIiwiZW5hYmxlTWljcm9waG9uZSIsInNlbmREYXRhIiwic3RyaW5naWZ5Iiwid2hvbSIsInNlbmREYXRhR3VhcmFudGVlZCIsImJyb2FkY2FzdERhdGEiLCJicm9hZGNhc3REYXRhR3VhcmFudGVlZCIsImtpY2siLCJwZXJtc1Rva2VuIiwiYmxvY2siLCJ1bmJsb2NrIiwicmVnaXN0ZXIiLCJtb2R1bGUiLCJleHBvcnRzIl0sInNvdXJjZVJvb3QiOiIifQ== \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,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Q0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkIsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkIsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxRQUFRO0FBQ25CLFlBQVk7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7O0FDaktBO0FBQ2E7O0FBRWI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGdCQUFnQixvQkFBb0I7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxrQkFBa0Isa0JBQWtCO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3Q0FBd0M7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSw2Q0FBNkM7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esb0JBQW9CO0FBQ3BCLDJCQUEyQjtBQUMzQjtBQUNBO0FBQ0E7QUFDQSw4REFBOEQ7QUFDOUQsa0JBQWtCLGtCQUFrQjtBQUNwQztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsS0FBSztBQUNMLGlEQUFpRDtBQUNqRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0Isa0JBQWtCLE9BQU87QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNkNBQTZDO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQixrQkFBa0I7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0Isa0JBQWtCO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsSUFBSSxJQUEwQjtBQUM5QjtBQUNBOzs7Ozs7O1VDanlCQTtVQUNBOztVQUVBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBOztVQUVBO1VBQ0E7O1VBRUE7VUFDQTtVQUNBOzs7O1VFdEJBO1VBQ0E7VUFDQTtVQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvLi9ub2RlX21vZHVsZXMvQG5ldHdvcmtlZC1hZnJhbWUvbWluaWphbnVzL21pbmlqYW51cy5qcyIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci8uL3NyYy9pbmRleC5qcyIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci8uL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvYnJvd3Nlci5qcyIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci8uL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvY29tbW9uLmpzIiwid2VicGFjazovL0BuZXR3b3JrZWQtYWZyYW1lL25hZi1qYW51cy1hZGFwdGVyLy4vbm9kZV9tb2R1bGVzL21zL2luZGV4LmpzIiwid2VicGFjazovL0BuZXR3b3JrZWQtYWZyYW1lL25hZi1qYW51cy1hZGFwdGVyLy4vbm9kZV9tb2R1bGVzL3NkcC9zZHAuanMiLCJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvd2VicGFjay9iZWZvcmUtc3RhcnR1cCIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci93ZWJwYWNrL3N0YXJ0dXAiLCJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvd2VicGFjay9hZnRlci1zdGFydHVwIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUmVwcmVzZW50cyBhIGhhbmRsZSB0byBhIHNpbmdsZSBKYW51cyBwbHVnaW4gb24gYSBKYW51cyBzZXNzaW9uLiBFYWNoIFdlYlJUQyBjb25uZWN0aW9uIHRvIHRoZSBKYW51cyBzZXJ2ZXIgd2lsbCBiZVxuICogYXNzb2NpYXRlZCB3aXRoIGEgc2luZ2xlIGhhbmRsZS4gT25jZSBhdHRhY2hlZCB0byB0aGUgc2VydmVyLCB0aGlzIGhhbmRsZSB3aWxsIGJlIGdpdmVuIGEgdW5pcXVlIElEIHdoaWNoIHNob3VsZCBiZVxuICogdXNlZCB0byBhc3NvY2lhdGUgaXQgd2l0aCBmdXR1cmUgc2lnbmFsbGluZyBtZXNzYWdlcy5cbiAqXG4gKiBTZWUgaHR0cHM6Ly9qYW51cy5jb25mLm1lZXRlY2hvLmNvbS9kb2NzL3Jlc3QuaHRtbCNoYW5kbGVzLlxuICoqL1xuZnVuY3Rpb24gSmFudXNQbHVnaW5IYW5kbGUoc2Vzc2lvbikge1xuICB0aGlzLnNlc3Npb24gPSBzZXNzaW9uO1xuICB0aGlzLmlkID0gdW5kZWZpbmVkO1xufVxuXG4vKiogQXR0YWNoZXMgdGhpcyBoYW5kbGUgdG8gdGhlIEphbnVzIHNlcnZlciBhbmQgc2V0cyBpdHMgSUQuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLmF0dGFjaCA9IGZ1bmN0aW9uKHBsdWdpbiwgbG9vcF9pbmRleCkge1xuICB2YXIgcGF5bG9hZCA9IHsgcGx1Z2luOiBwbHVnaW4sIGxvb3BfaW5kZXg6IGxvb3BfaW5kZXgsIFwiZm9yY2UtYnVuZGxlXCI6IHRydWUsIFwiZm9yY2UtcnRjcC1tdXhcIjogdHJ1ZSB9O1xuICByZXR1cm4gdGhpcy5zZXNzaW9uLnNlbmQoXCJhdHRhY2hcIiwgcGF5bG9hZCkudGhlbihyZXNwID0+IHtcbiAgICB0aGlzLmlkID0gcmVzcC5kYXRhLmlkO1xuICAgIHJldHVybiByZXNwO1xuICB9KTtcbn07XG5cbi8qKiBEZXRhY2hlcyB0aGlzIGhhbmRsZS4gKiovXG5KYW51c1BsdWdpbkhhbmRsZS5wcm90b3R5cGUuZGV0YWNoID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJkZXRhY2hcIik7XG59O1xuXG4vKiogUmVnaXN0ZXJzIGEgY2FsbGJhY2sgdG8gYmUgZmlyZWQgdXBvbiB0aGUgcmVjZXB0aW9uIG9mIGFueSBpbmNvbWluZyBKYW51cyBzaWduYWxzIGZvciB0aGlzIHBsdWdpbiBoYW5kbGUgd2l0aCB0aGVcbiAqIGBqYW51c2AgYXR0cmlidXRlIGVxdWFsIHRvIGBldmAuXG4gKiovXG5KYW51c1BsdWdpbkhhbmRsZS5wcm90b3R5cGUub24gPSBmdW5jdGlvbihldiwgY2FsbGJhY2spIHtcbiAgcmV0dXJuIHRoaXMuc2Vzc2lvbi5vbihldiwgc2lnbmFsID0+IHtcbiAgICBpZiAoc2lnbmFsLnNlbmRlciA9PSB0aGlzLmlkKSB7XG4gICAgICBjYWxsYmFjayhzaWduYWwpO1xuICAgIH1cbiAgfSk7XG59O1xuXG4vKipcbiAqIFNlbmRzIGEgc2lnbmFsIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGhhbmRsZS4gU2lnbmFscyBzaG91bGQgYmUgSlNPTi1zZXJpYWxpemFibGUgb2JqZWN0cy4gUmV0dXJucyBhIHByb21pc2UgdGhhdCB3aWxsXG4gKiBiZSByZXNvbHZlZCBvciByZWplY3RlZCB3aGVuIGEgcmVzcG9uc2UgdG8gdGhpcyBzaWduYWwgaXMgcmVjZWl2ZWQsIG9yIHdoZW4gbm8gcmVzcG9uc2UgaXMgcmVjZWl2ZWQgd2l0aGluIHRoZVxuICogc2Vzc2lvbiB0aW1lb3V0LlxuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbih0eXBlLCBzaWduYWwpIHtcbiAgcmV0dXJuIHRoaXMuc2Vzc2lvbi5zZW5kKHR5cGUsIE9iamVjdC5hc3NpZ24oeyBoYW5kbGVfaWQ6IHRoaXMuaWQgfSwgc2lnbmFsKSk7XG59O1xuXG4vKiogU2VuZHMgYSBwbHVnaW4tc3BlY2lmaWMgbWVzc2FnZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBoYW5kbGUuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmRNZXNzYWdlID0gZnVuY3Rpb24oYm9keSkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwibWVzc2FnZVwiLCB7IGJvZHk6IGJvZHkgfSk7XG59O1xuXG4vKiogU2VuZHMgYSBKU0VQIG9mZmVyIG9yIGFuc3dlciBhc3NvY2lhdGVkIHdpdGggdGhpcyBoYW5kbGUuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmRKc2VwID0gZnVuY3Rpb24oanNlcCkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwibWVzc2FnZVwiLCB7IGJvZHk6IHt9LCBqc2VwOiBqc2VwIH0pO1xufTtcblxuLyoqIFNlbmRzIGFuIElDRSB0cmlja2xlIGNhbmRpZGF0ZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBoYW5kbGUuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmRUcmlja2xlID0gZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJ0cmlja2xlXCIsIHsgY2FuZGlkYXRlOiBjYW5kaWRhdGUgfSk7XG59O1xuXG4vKipcbiAqIFJlcHJlc2VudHMgYSBKYW51cyBzZXNzaW9uIC0tIGEgSmFudXMgY29udGV4dCBmcm9tIHdpdGhpbiB3aGljaCB5b3UgY2FuIG9wZW4gbXVsdGlwbGUgaGFuZGxlcyBhbmQgY29ubmVjdGlvbnMuIE9uY2VcbiAqIGNyZWF0ZWQsIHRoaXMgc2Vzc2lvbiB3aWxsIGJlIGdpdmVuIGEgdW5pcXVlIElEIHdoaWNoIHNob3VsZCBiZSB1c2VkIHRvIGFzc29jaWF0ZSBpdCB3aXRoIGZ1dHVyZSBzaWduYWxsaW5nIG1lc3NhZ2VzLlxuICpcbiAqIFNlZSBodHRwczovL2phbnVzLmNvbmYubWVldGVjaG8uY29tL2RvY3MvcmVzdC5odG1sI3Nlc3Npb25zLlxuICoqL1xuZnVuY3Rpb24gSmFudXNTZXNzaW9uKG91dHB1dCwgb3B0aW9ucykge1xuICB0aGlzLm91dHB1dCA9IG91dHB1dDtcbiAgdGhpcy5pZCA9IHVuZGVmaW5lZDtcbiAgdGhpcy5uZXh0VHhJZCA9IDA7XG4gIHRoaXMudHhucyA9IHt9O1xuICB0aGlzLmV2ZW50SGFuZGxlcnMgPSB7fTtcbiAgdGhpcy5vcHRpb25zID0gT2JqZWN0LmFzc2lnbih7XG4gICAgdmVyYm9zZTogZmFsc2UsXG4gICAgdGltZW91dE1zOiAxMDAwMCxcbiAgICBrZWVwYWxpdmVNczogMzAwMDBcbiAgfSwgb3B0aW9ucyk7XG59XG5cbi8qKiBDcmVhdGVzIHRoaXMgc2Vzc2lvbiBvbiB0aGUgSmFudXMgc2VydmVyIGFuZCBzZXRzIGl0cyBJRC4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLmNyZWF0ZSA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwiY3JlYXRlXCIpLnRoZW4ocmVzcCA9PiB7XG4gICAgdGhpcy5pZCA9IHJlc3AuZGF0YS5pZDtcbiAgICByZXR1cm4gcmVzcDtcbiAgfSk7XG59O1xuXG4vKipcbiAqIERlc3Ryb3lzIHRoaXMgc2Vzc2lvbi4gTm90ZSB0aGF0IHVwb24gZGVzdHJ1Y3Rpb24sIEphbnVzIHdpbGwgYWxzbyBjbG9zZSB0aGUgc2lnbmFsbGluZyB0cmFuc3BvcnQgKGlmIGFwcGxpY2FibGUpIGFuZFxuICogYW55IG9wZW4gV2ViUlRDIGNvbm5lY3Rpb25zLlxuICoqL1xuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJkZXN0cm95XCIpLnRoZW4oKHJlc3ApID0+IHtcbiAgICB0aGlzLmRpc3Bvc2UoKTtcbiAgICByZXR1cm4gcmVzcDtcbiAgfSk7XG59O1xuXG4vKipcbiAqIERpc3Bvc2VzIG9mIHRoaXMgc2Vzc2lvbiBpbiBhIHdheSBzdWNoIHRoYXQgbm8gZnVydGhlciBpbmNvbWluZyBzaWduYWxsaW5nIG1lc3NhZ2VzIHdpbGwgYmUgcHJvY2Vzc2VkLlxuICogT3V0c3RhbmRpbmcgdHJhbnNhY3Rpb25zIHdpbGwgYmUgcmVqZWN0ZWQuXG4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLmRpc3Bvc2UgPSBmdW5jdGlvbigpIHtcbiAgdGhpcy5fa2lsbEtlZXBhbGl2ZSgpO1xuICB0aGlzLmV2ZW50SGFuZGxlcnMgPSB7fTtcbiAgZm9yICh2YXIgdHhJZCBpbiB0aGlzLnR4bnMpIHtcbiAgICBpZiAodGhpcy50eG5zLmhhc093blByb3BlcnR5KHR4SWQpKSB7XG4gICAgICB2YXIgdHhuID0gdGhpcy50eG5zW3R4SWRdO1xuICAgICAgY2xlYXJUaW1lb3V0KHR4bi50aW1lb3V0KTtcbiAgICAgIHR4bi5yZWplY3QobmV3IEVycm9yKFwiSmFudXMgc2Vzc2lvbiB3YXMgZGlzcG9zZWQuXCIpKTtcbiAgICAgIGRlbGV0ZSB0aGlzLnR4bnNbdHhJZF07XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIFdoZXRoZXIgdGhpcyBzaWduYWwgcmVwcmVzZW50cyBhbiBlcnJvciwgYW5kIHRoZSBhc3NvY2lhdGVkIHByb21pc2UgKGlmIGFueSkgc2hvdWxkIGJlIHJlamVjdGVkLlxuICogVXNlcnMgc2hvdWxkIG92ZXJyaWRlIHRoaXMgdG8gaGFuZGxlIGFueSBjdXN0b20gcGx1Z2luLXNwZWNpZmljIGVycm9yIGNvbnZlbnRpb25zLlxuICoqL1xuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5pc0Vycm9yID0gZnVuY3Rpb24oc2lnbmFsKSB7XG4gIHJldHVybiBzaWduYWwuamFudXMgPT09IFwiZXJyb3JcIjtcbn07XG5cbi8qKiBSZWdpc3RlcnMgYSBjYWxsYmFjayB0byBiZSBmaXJlZCB1cG9uIHRoZSByZWNlcHRpb24gb2YgYW55IGluY29taW5nIEphbnVzIHNpZ25hbHMgZm9yIHRoaXMgc2Vzc2lvbiB3aXRoIHRoZVxuICogYGphbnVzYCBhdHRyaWJ1dGUgZXF1YWwgdG8gYGV2YC5cbiAqKi9cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUub24gPSBmdW5jdGlvbihldiwgY2FsbGJhY2spIHtcbiAgdmFyIGhhbmRsZXJzID0gdGhpcy5ldmVudEhhbmRsZXJzW2V2XTtcbiAgaWYgKGhhbmRsZXJzID09IG51bGwpIHtcbiAgICBoYW5kbGVycyA9IHRoaXMuZXZlbnRIYW5kbGVyc1tldl0gPSBbXTtcbiAgfVxuICBoYW5kbGVycy5wdXNoKGNhbGxiYWNrKTtcbn07XG5cbi8qKlxuICogQ2FsbGJhY2sgZm9yIHJlY2VpdmluZyBKU09OIHNpZ25hbGxpbmcgbWVzc2FnZXMgcGVydGluZW50IHRvIHRoaXMgc2Vzc2lvbi4gSWYgdGhlIHNpZ25hbHMgYXJlIHJlc3BvbnNlcyB0byBwcmV2aW91c2x5XG4gKiBzZW50IHNpZ25hbHMsIHRoZSBwcm9taXNlcyBmb3IgdGhlIG91dGdvaW5nIHNpZ25hbHMgd2lsbCBiZSByZXNvbHZlZCBvciByZWplY3RlZCBhcHByb3ByaWF0ZWx5IHdpdGggdGhpcyBzaWduYWwgYXMgYW5cbiAqIGFyZ3VtZW50LlxuICpcbiAqIEV4dGVybmFsIGNhbGxlcnMgc2hvdWxkIGNhbGwgdGhpcyBmdW5jdGlvbiBldmVyeSB0aW1lIGEgbmV3IHNpZ25hbCBhcnJpdmVzIG9uIHRoZSB0cmFuc3BvcnQ7IGZvciBleGFtcGxlLCBpbiBhXG4gKiBXZWJTb2NrZXQncyBgbWVzc2FnZWAgZXZlbnQsIG9yIHdoZW4gYSBuZXcgZGF0dW0gc2hvd3MgdXAgaW4gYW4gSFRUUCBsb25nLXBvbGxpbmcgcmVzcG9uc2UuXG4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLnJlY2VpdmUgPSBmdW5jdGlvbihzaWduYWwpIHtcbiAgaWYgKHRoaXMub3B0aW9ucy52ZXJib3NlKSB7XG4gICAgdGhpcy5fbG9nSW5jb21pbmcoc2lnbmFsKTtcbiAgfVxuICBpZiAoc2lnbmFsLnNlc3Npb25faWQgIT0gdGhpcy5pZCkge1xuICAgIGNvbnNvbGUud2FybihcIkluY29ycmVjdCBzZXNzaW9uIElEIHJlY2VpdmVkIGluIEphbnVzIHNpZ25hbGxpbmcgbWVzc2FnZTogd2FzIFwiICsgc2lnbmFsLnNlc3Npb25faWQgKyBcIiwgZXhwZWN0ZWQgXCIgKyB0aGlzLmlkICsgXCIuXCIpO1xuICB9XG5cbiAgdmFyIHJlc3BvbnNlVHlwZSA9IHNpZ25hbC5qYW51cztcbiAgdmFyIGhhbmRsZXJzID0gdGhpcy5ldmVudEhhbmRsZXJzW3Jlc3BvbnNlVHlwZV07XG4gIGlmIChoYW5kbGVycyAhPSBudWxsKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoYW5kbGVycy5sZW5ndGg7IGkrKykge1xuICAgICAgaGFuZGxlcnNbaV0oc2lnbmFsKTtcbiAgICB9XG4gIH1cblxuICBpZiAoc2lnbmFsLnRyYW5zYWN0aW9uICE9IG51bGwpIHtcbiAgICB2YXIgdHhuID0gdGhpcy50eG5zW3NpZ25hbC50cmFuc2FjdGlvbl07XG4gICAgaWYgKHR4biA9PSBudWxsKSB7XG4gICAgICAvLyB0aGlzIGlzIGEgcmVzcG9uc2UgdG8gYSB0cmFuc2FjdGlvbiB0aGF0IHdhc24ndCBjYXVzZWQgdmlhIEphbnVzU2Vzc2lvbi5zZW5kLCBvciBhIHBsdWdpbiByZXBsaWVkIHR3aWNlIHRvIGFcbiAgICAgIC8vIHNpbmdsZSByZXF1ZXN0LCBvciB0aGUgc2Vzc2lvbiB3YXMgZGlzcG9zZWQsIG9yIHNvbWV0aGluZyBlbHNlIHRoYXQgaXNuJ3QgdW5kZXIgb3VyIHB1cnZpZXc7IHRoYXQncyBmaW5lXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHJlc3BvbnNlVHlwZSA9PT0gXCJhY2tcIiAmJiB0eG4udHlwZSA9PSBcIm1lc3NhZ2VcIikge1xuICAgICAgLy8gdGhpcyBpcyBhbiBhY2sgb2YgYW4gYXN5bmNocm9ub3VzbHktcHJvY2Vzc2VkIHBsdWdpbiByZXF1ZXN0LCB3ZSBzaG91bGQgd2FpdCB0byByZXNvbHZlIHRoZSBwcm9taXNlIHVudGlsIHRoZVxuICAgICAgLy8gYWN0dWFsIHJlc3BvbnNlIGNvbWVzIGluXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY2xlYXJUaW1lb3V0KHR4bi50aW1lb3V0KTtcblxuICAgIGRlbGV0ZSB0aGlzLnR4bnNbc2lnbmFsLnRyYW5zYWN0aW9uXTtcbiAgICAodGhpcy5pc0Vycm9yKHNpZ25hbCkgPyB0eG4ucmVqZWN0IDogdHhuLnJlc29sdmUpKHNpZ25hbCk7XG4gIH1cbn07XG5cbi8qKlxuICogU2VuZHMgYSBzaWduYWwgYXNzb2NpYXRlZCB3aXRoIHRoaXMgc2Vzc2lvbiwgYmVnaW5uaW5nIGEgbmV3IHRyYW5zYWN0aW9uLiBSZXR1cm5zIGEgcHJvbWlzZSB0aGF0IHdpbGwgYmUgcmVzb2x2ZWQgb3JcbiAqIHJlamVjdGVkIHdoZW4gYSByZXNwb25zZSBpcyByZWNlaXZlZCBpbiB0aGUgc2FtZSB0cmFuc2FjdGlvbiwgb3Igd2hlbiBubyByZXNwb25zZSBpcyByZWNlaXZlZCB3aXRoaW4gdGhlIHNlc3Npb25cbiAqIHRpbWVvdXQuXG4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbih0eXBlLCBzaWduYWwpIHtcbiAgc2lnbmFsID0gT2JqZWN0LmFzc2lnbih7IHRyYW5zYWN0aW9uOiAodGhpcy5uZXh0VHhJZCsrKS50b1N0cmluZygpIH0sIHNpZ25hbCk7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgdmFyIHRpbWVvdXQgPSBudWxsO1xuICAgIGlmICh0aGlzLm9wdGlvbnMudGltZW91dE1zKSB7XG4gICAgICB0aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGRlbGV0ZSB0aGlzLnR4bnNbc2lnbmFsLnRyYW5zYWN0aW9uXTtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihcIlNpZ25hbGxpbmcgdHJhbnNhY3Rpb24gd2l0aCB0eGlkIFwiICsgc2lnbmFsLnRyYW5zYWN0aW9uICsgXCIgdGltZWQgb3V0LlwiKSk7XG4gICAgICB9LCB0aGlzLm9wdGlvbnMudGltZW91dE1zKTtcbiAgICB9XG4gICAgdGhpcy50eG5zW3NpZ25hbC50cmFuc2FjdGlvbl0gPSB7IHJlc29sdmU6IHJlc29sdmUsIHJlamVjdDogcmVqZWN0LCB0aW1lb3V0OiB0aW1lb3V0LCB0eXBlOiB0eXBlIH07XG4gICAgdGhpcy5fdHJhbnNtaXQodHlwZSwgc2lnbmFsKTtcbiAgfSk7XG59O1xuXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLl90cmFuc21pdCA9IGZ1bmN0aW9uKHR5cGUsIHNpZ25hbCkge1xuICBzaWduYWwgPSBPYmplY3QuYXNzaWduKHsgamFudXM6IHR5cGUgfSwgc2lnbmFsKTtcblxuICBpZiAodGhpcy5pZCAhPSBudWxsKSB7IC8vIHRoaXMuaWQgaXMgdW5kZWZpbmVkIGluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlbiB3ZSdyZSBzZW5kaW5nIHRoZSBzZXNzaW9uIGNyZWF0ZSBtZXNzYWdlXG4gICAgc2lnbmFsID0gT2JqZWN0LmFzc2lnbih7IHNlc3Npb25faWQ6IHRoaXMuaWQgfSwgc2lnbmFsKTtcbiAgfVxuXG4gIGlmICh0aGlzLm9wdGlvbnMudmVyYm9zZSkge1xuICAgIHRoaXMuX2xvZ091dGdvaW5nKHNpZ25hbCk7XG4gIH1cblxuICB0aGlzLm91dHB1dChKU09OLnN0cmluZ2lmeShzaWduYWwpKTtcbiAgdGhpcy5fcmVzZXRLZWVwYWxpdmUoKTtcbn07XG5cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuX2xvZ091dGdvaW5nID0gZnVuY3Rpb24oc2lnbmFsKSB7XG4gIHZhciBraW5kID0gc2lnbmFsLmphbnVzO1xuICBpZiAoa2luZCA9PT0gXCJtZXNzYWdlXCIgJiYgc2lnbmFsLmpzZXApIHtcbiAgICBraW5kID0gc2lnbmFsLmpzZXAudHlwZTtcbiAgfVxuICB2YXIgbWVzc2FnZSA9IFwiPiBPdXRnb2luZyBKYW51cyBcIiArIChraW5kIHx8IFwic2lnbmFsXCIpICsgXCIgKCNcIiArIHNpZ25hbC50cmFuc2FjdGlvbiArIFwiKTogXCI7XG4gIGNvbnNvbGUuZGVidWcoXCIlY1wiICsgbWVzc2FnZSwgXCJjb2xvcjogIzA0MFwiLCBzaWduYWwpO1xufTtcblxuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5fbG9nSW5jb21pbmcgPSBmdW5jdGlvbihzaWduYWwpIHtcbiAgdmFyIGtpbmQgPSBzaWduYWwuamFudXM7XG4gIHZhciBtZXNzYWdlID0gc2lnbmFsLnRyYW5zYWN0aW9uID9cbiAgICAgIFwiPCBJbmNvbWluZyBKYW51cyBcIiArIChraW5kIHx8IFwic2lnbmFsXCIpICsgXCIgKCNcIiArIHNpZ25hbC50cmFuc2FjdGlvbiArIFwiKTogXCIgOlxuICAgICAgXCI8IEluY29taW5nIEphbnVzIFwiICsgKGtpbmQgfHwgXCJzaWduYWxcIikgKyBcIjogXCI7XG4gIGNvbnNvbGUuZGVidWcoXCIlY1wiICsgbWVzc2FnZSwgXCJjb2xvcjogIzAwNFwiLCBzaWduYWwpO1xufTtcblxuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5fc2VuZEtlZXBhbGl2ZSA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwia2VlcGFsaXZlXCIpO1xufTtcblxuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5fa2lsbEtlZXBhbGl2ZSA9IGZ1bmN0aW9uKCkge1xuICBjbGVhclRpbWVvdXQodGhpcy5rZWVwYWxpdmVUaW1lb3V0KTtcbn07XG5cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuX3Jlc2V0S2VlcGFsaXZlID0gZnVuY3Rpb24oKSB7XG4gIHRoaXMuX2tpbGxLZWVwYWxpdmUoKTtcbiAgaWYgKHRoaXMub3B0aW9ucy5rZWVwYWxpdmVNcykge1xuICAgIHRoaXMua2VlcGFsaXZlVGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5fc2VuZEtlZXBhbGl2ZSgpLmNhdGNoKGUgPT4gY29uc29sZS5lcnJvcihcIkVycm9yIHJlY2VpdmVkIGZyb20ga2VlcGFsaXZlOiBcIiwgZSkpO1xuICAgIH0sIHRoaXMub3B0aW9ucy5rZWVwYWxpdmVNcyk7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBKYW51c1BsdWdpbkhhbmRsZSxcbiAgSmFudXNTZXNzaW9uXG59O1xuIiwiLyogZ2xvYmFsIE5BRiAqL1xudmFyIG1qID0gcmVxdWlyZShcIkBuZXR3b3JrZWQtYWZyYW1lL21pbmlqYW51c1wiKTtcbm1qLkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuc2VuZE9yaWdpbmFsID0gbWouSmFudXNTZXNzaW9uLnByb3RvdHlwZS5zZW5kO1xubWouSmFudXNTZXNzaW9uLnByb3RvdHlwZS5zZW5kID0gZnVuY3Rpb24odHlwZSwgc2lnbmFsKSB7XG4gIHJldHVybiB0aGlzLnNlbmRPcmlnaW5hbCh0eXBlLCBzaWduYWwpLmNhdGNoKChlKSA9PiB7XG4gICAgaWYgKGUubWVzc2FnZSAmJiBlLm1lc3NhZ2UuaW5kZXhPZihcInRpbWVkIG91dFwiKSA+IC0xKSB7XG4gICAgICBjb25zb2xlLmVycm9yKFwid2ViIHNvY2tldCB0aW1lZCBvdXRcIik7XG4gICAgICBOQUYuY29ubmVjdGlvbi5hZGFwdGVyLnJlY29ubmVjdCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyhlKTtcbiAgICB9XG4gIH0pO1xufVxuXG52YXIgc2RwVXRpbHMgPSByZXF1aXJlKFwic2RwXCIpO1xudmFyIGRlYnVnID0gcmVxdWlyZShcImRlYnVnXCIpKFwibmFmLWphbnVzLWFkYXB0ZXI6ZGVidWdcIik7XG52YXIgd2FybiA9IHJlcXVpcmUoXCJkZWJ1Z1wiKShcIm5hZi1qYW51cy1hZGFwdGVyOndhcm5cIik7XG52YXIgZXJyb3IgPSByZXF1aXJlKFwiZGVidWdcIikoXCJuYWYtamFudXMtYWRhcHRlcjplcnJvclwiKTtcbnZhciBpc1NhZmFyaSA9IC9eKCg/IWNocm9tZXxhbmRyb2lkKS4pKnNhZmFyaS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCk7XG5cbmNvbnN0IFNVQlNDUklCRV9USU1FT1VUX01TID0gMTUwMDA7XG5cbmNvbnN0IEFWQUlMQUJMRV9PQ0NVUEFOVFNfVEhSRVNIT0xEID0gNTtcbmNvbnN0IE1BWF9TVUJTQ1JJQkVfREVMQVkgPSA1MDAwO1xuXG5mdW5jdGlvbiByYW5kb21EZWxheShtaW4sIG1heCkge1xuICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgY29uc3QgZGVsYXkgPSBNYXRoLnJhbmRvbSgpICogKG1heCAtIG1pbikgKyBtaW47XG4gICAgc2V0VGltZW91dChyZXNvbHZlLCBkZWxheSk7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkZWJvdW5jZShmbikge1xuICB2YXIgY3VyciA9IFByb21pc2UucmVzb2x2ZSgpO1xuICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgIGN1cnIgPSBjdXJyLnRoZW4oXyA9PiBmbi5hcHBseSh0aGlzLCBhcmdzKSk7XG4gIH07XG59XG5cbmZ1bmN0aW9uIHJhbmRvbVVpbnQoKSB7XG4gIHJldHVybiBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUik7XG59XG5cbmZ1bmN0aW9uIHVudGlsRGF0YUNoYW5uZWxPcGVuKGRhdGFDaGFubmVsKSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgaWYgKGRhdGFDaGFubmVsLnJlYWR5U3RhdGUgPT09IFwib3BlblwiKSB7XG4gICAgICByZXNvbHZlKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCByZXNvbHZlciwgcmVqZWN0b3I7XG5cbiAgICAgIGNvbnN0IGNsZWFyID0gKCkgPT4ge1xuICAgICAgICBkYXRhQ2hhbm5lbC5yZW1vdmVFdmVudExpc3RlbmVyKFwib3BlblwiLCByZXNvbHZlcik7XG4gICAgICAgIGRhdGFDaGFubmVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJlcnJvclwiLCByZWplY3Rvcik7XG4gICAgICB9O1xuXG4gICAgICByZXNvbHZlciA9ICgpID0+IHtcbiAgICAgICAgY2xlYXIoKTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfTtcbiAgICAgIHJlamVjdG9yID0gKCkgPT4ge1xuICAgICAgICBjbGVhcigpO1xuICAgICAgICByZWplY3QoKTtcbiAgICAgIH07XG5cbiAgICAgIGRhdGFDaGFubmVsLmFkZEV2ZW50TGlzdGVuZXIoXCJvcGVuXCIsIHJlc29sdmVyKTtcbiAgICAgIGRhdGFDaGFubmVsLmFkZEV2ZW50TGlzdGVuZXIoXCJlcnJvclwiLCByZWplY3Rvcik7XG4gICAgfVxuICB9KTtcbn1cblxuY29uc3QgaXNIMjY0VmlkZW9TdXBwb3J0ZWQgPSAoKCkgPT4ge1xuICBjb25zdCB2aWRlbyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJ2aWRlb1wiKTtcbiAgcmV0dXJuIHZpZGVvLmNhblBsYXlUeXBlKCd2aWRlby9tcDQ7IGNvZGVjcz1cImF2YzEuNDJFMDFFLCBtcDRhLjQwLjJcIicpICE9PSBcIlwiO1xufSkoKTtcblxuY29uc3QgT1BVU19QQVJBTUVURVJTID0ge1xuICAvLyBpbmRpY2F0ZXMgdGhhdCB3ZSB3YW50IHRvIGVuYWJsZSBEVFggdG8gZWxpZGUgc2lsZW5jZSBwYWNrZXRzXG4gIHVzZWR0eDogMSxcbiAgLy8gaW5kaWNhdGVzIHRoYXQgd2UgcHJlZmVyIHRvIHJlY2VpdmUgbW9ubyBhdWRpbyAoaW1wb3J0YW50IGZvciB2b2lwIHByb2ZpbGUpXG4gIHN0ZXJlbzogMCxcbiAgLy8gaW5kaWNhdGVzIHRoYXQgd2UgcHJlZmVyIHRvIHNlbmQgbW9ubyBhdWRpbyAoaW1wb3J0YW50IGZvciB2b2lwIHByb2ZpbGUpXG4gIFwic3Byb3Atc3RlcmVvXCI6IDBcbn07XG5cbmNvbnN0IERFRkFVTFRfUEVFUl9DT05ORUNUSU9OX0NPTkZJRyA9IHtcbiAgaWNlU2VydmVyczogW3sgdXJsczogXCJzdHVuOnN0dW4xLmwuZ29vZ2xlLmNvbToxOTMwMlwiIH0sIHsgdXJsczogXCJzdHVuOnN0dW4yLmwuZ29vZ2xlLmNvbToxOTMwMlwiIH1dXG59O1xuXG5jb25zdCBXU19OT1JNQUxfQ0xPU1VSRSA9IDEwMDA7XG5cbmNsYXNzIEphbnVzQWRhcHRlciB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMucm9vbSA9IG51bGw7XG4gICAgLy8gV2UgZXhwZWN0IHRoZSBjb25zdW1lciB0byBzZXQgYSBjbGllbnQgaWQgYmVmb3JlIGNvbm5lY3RpbmcuXG4gICAgdGhpcy5jbGllbnRJZCA9IG51bGw7XG4gICAgdGhpcy5qb2luVG9rZW4gPSBudWxsO1xuXG4gICAgdGhpcy5zZXJ2ZXJVcmwgPSBudWxsO1xuICAgIHRoaXMud2ViUnRjT3B0aW9ucyA9IHt9O1xuICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db25maWcgPSBudWxsO1xuICAgIHRoaXMud3MgPSBudWxsO1xuICAgIHRoaXMuc2Vzc2lvbiA9IG51bGw7XG4gICAgdGhpcy5yZWxpYWJsZVRyYW5zcG9ydCA9IFwiZGF0YWNoYW5uZWxcIjtcbiAgICB0aGlzLnVucmVsaWFibGVUcmFuc3BvcnQgPSBcImRhdGFjaGFubmVsXCI7XG5cbiAgICAvLyBJbiB0aGUgZXZlbnQgdGhlIHNlcnZlciByZXN0YXJ0cyBhbmQgYWxsIGNsaWVudHMgbG9zZSBjb25uZWN0aW9uLCByZWNvbm5lY3Qgd2l0aFxuICAgIC8vIHNvbWUgcmFuZG9tIGppdHRlciBhZGRlZCB0byBwcmV2ZW50IHNpbXVsdGFuZW91cyByZWNvbm5lY3Rpb24gcmVxdWVzdHMuXG4gICAgdGhpcy5pbml0aWFsUmVjb25uZWN0aW9uRGVsYXkgPSAxMDAwICogTWF0aC5yYW5kb20oKTtcbiAgICB0aGlzLnJlY29ubmVjdGlvbkRlbGF5ID0gdGhpcy5pbml0aWFsUmVjb25uZWN0aW9uRGVsYXk7XG4gICAgdGhpcy5yZWNvbm5lY3Rpb25UaW1lb3V0ID0gbnVsbDtcbiAgICB0aGlzLm1heFJlY29ubmVjdGlvbkF0dGVtcHRzID0gMTA7XG4gICAgdGhpcy5yZWNvbm5lY3Rpb25BdHRlbXB0cyA9IDA7XG4gICAgdGhpcy5pc1JlY29ubmVjdGluZyA9IGZhbHNlO1xuXG4gICAgdGhpcy5wdWJsaXNoZXIgPSBudWxsO1xuICAgIHRoaXMub2NjdXBhbnRJZHMgPSBbXTtcbiAgICB0aGlzLm9jY3VwYW50cyA9IHt9O1xuICAgIHRoaXMubWVkaWFTdHJlYW1zID0ge307XG4gICAgdGhpcy5sb2NhbE1lZGlhU3RyZWFtID0gbnVsbDtcbiAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzID0gbmV3IE1hcCgpO1xuXG4gICAgdGhpcy5wZW5kaW5nT2NjdXBhbnRzID0gbmV3IFNldCgpO1xuICAgIHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzID0gW107XG4gICAgdGhpcy5yZXF1ZXN0ZWRPY2N1cGFudHMgPSBudWxsO1xuXG4gICAgdGhpcy5ibG9ja2VkQ2xpZW50cyA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLmZyb3plblVwZGF0ZXMgPSBuZXcgTWFwKCk7XG5cbiAgICB0aGlzLnRpbWVPZmZzZXRzID0gW107XG4gICAgdGhpcy5zZXJ2ZXJUaW1lUmVxdWVzdHMgPSAwO1xuICAgIHRoaXMuYXZnVGltZU9mZnNldCA9IDA7XG5cbiAgICB0aGlzLm9uV2Vic29ja2V0T3BlbiA9IHRoaXMub25XZWJzb2NrZXRPcGVuLmJpbmQodGhpcyk7XG4gICAgdGhpcy5vbldlYnNvY2tldENsb3NlID0gdGhpcy5vbldlYnNvY2tldENsb3NlLmJpbmQodGhpcyk7XG4gICAgdGhpcy5vbldlYnNvY2tldE1lc3NhZ2UgPSB0aGlzLm9uV2Vic29ja2V0TWVzc2FnZS5iaW5kKHRoaXMpO1xuICAgIHRoaXMub25EYXRhQ2hhbm5lbE1lc3NhZ2UgPSB0aGlzLm9uRGF0YUNoYW5uZWxNZXNzYWdlLmJpbmQodGhpcyk7XG4gICAgdGhpcy5vbkRhdGEgPSB0aGlzLm9uRGF0YS5iaW5kKHRoaXMpO1xuICB9XG5cbiAgc2V0U2VydmVyVXJsKHVybCkge1xuICAgIHRoaXMuc2VydmVyVXJsID0gdXJsO1xuICB9XG5cbiAgc2V0QXBwKGFwcCkge31cblxuICBzZXRSb29tKHJvb21OYW1lKSB7XG4gICAgdGhpcy5yb29tID0gcm9vbU5hbWU7XG4gIH1cblxuICBzZXRKb2luVG9rZW4oam9pblRva2VuKSB7XG4gICAgdGhpcy5qb2luVG9rZW4gPSBqb2luVG9rZW47XG4gIH1cblxuICBzZXRDbGllbnRJZChjbGllbnRJZCkge1xuICAgIHRoaXMuY2xpZW50SWQgPSBjbGllbnRJZDtcbiAgfVxuXG4gIHNldFdlYlJ0Y09wdGlvbnMob3B0aW9ucykge1xuICAgIHRoaXMud2ViUnRjT3B0aW9ucyA9IG9wdGlvbnM7XG4gIH1cblxuICBzZXRQZWVyQ29ubmVjdGlvbkNvbmZpZyhwZWVyQ29ubmVjdGlvbkNvbmZpZykge1xuICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db25maWcgPSBwZWVyQ29ubmVjdGlvbkNvbmZpZztcbiAgfVxuXG4gIHNldFNlcnZlckNvbm5lY3RMaXN0ZW5lcnMoc3VjY2Vzc0xpc3RlbmVyLCBmYWlsdXJlTGlzdGVuZXIpIHtcbiAgICB0aGlzLmNvbm5lY3RTdWNjZXNzID0gc3VjY2Vzc0xpc3RlbmVyO1xuICAgIHRoaXMuY29ubmVjdEZhaWx1cmUgPSBmYWlsdXJlTGlzdGVuZXI7XG4gIH1cblxuICBzZXRSb29tT2NjdXBhbnRMaXN0ZW5lcihvY2N1cGFudExpc3RlbmVyKSB7XG4gICAgdGhpcy5vbk9jY3VwYW50c0NoYW5nZWQgPSBvY2N1cGFudExpc3RlbmVyO1xuICB9XG5cbiAgc2V0RGF0YUNoYW5uZWxMaXN0ZW5lcnMob3Blbkxpc3RlbmVyLCBjbG9zZWRMaXN0ZW5lciwgbWVzc2FnZUxpc3RlbmVyKSB7XG4gICAgdGhpcy5vbk9jY3VwYW50Q29ubmVjdGVkID0gb3Blbkxpc3RlbmVyO1xuICAgIHRoaXMub25PY2N1cGFudERpc2Nvbm5lY3RlZCA9IGNsb3NlZExpc3RlbmVyO1xuICAgIHRoaXMub25PY2N1cGFudE1lc3NhZ2UgPSBtZXNzYWdlTGlzdGVuZXI7XG4gIH1cblxuICBzZXRSZWNvbm5lY3Rpb25MaXN0ZW5lcnMocmVjb25uZWN0aW5nTGlzdGVuZXIsIHJlY29ubmVjdGVkTGlzdGVuZXIsIHJlY29ubmVjdGlvbkVycm9yTGlzdGVuZXIpIHtcbiAgICAvLyBvblJlY29ubmVjdGluZyBpcyBjYWxsZWQgd2l0aCB0aGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB1bnRpbCB0aGUgbmV4dCByZWNvbm5lY3Rpb24gYXR0ZW1wdFxuICAgIHRoaXMub25SZWNvbm5lY3RpbmcgPSByZWNvbm5lY3RpbmdMaXN0ZW5lcjtcbiAgICAvLyBvblJlY29ubmVjdGVkIGlzIGNhbGxlZCB3aGVuIHRoZSBjb25uZWN0aW9uIGhhcyBiZWVuIHJlZXN0YWJsaXNoZWRcbiAgICB0aGlzLm9uUmVjb25uZWN0ZWQgPSByZWNvbm5lY3RlZExpc3RlbmVyO1xuICAgIC8vIG9uUmVjb25uZWN0aW9uRXJyb3IgaXMgY2FsbGVkIHdpdGggYW4gZXJyb3Igd2hlbiBtYXhSZWNvbm5lY3Rpb25BdHRlbXB0cyBoYXMgYmVlbiByZWFjaGVkXG4gICAgdGhpcy5vblJlY29ubmVjdGlvbkVycm9yID0gcmVjb25uZWN0aW9uRXJyb3JMaXN0ZW5lcjtcbiAgfVxuXG4gIHNldEV2ZW50TG9vcHMobG9vcHMpIHtcbiAgICB0aGlzLmxvb3BzID0gbG9vcHM7XG4gIH1cblxuICBjb25uZWN0KCkge1xuICAgIGlmICh0aGlzLnNlcnZlclVybCA9PT0gJy8nKSB7XG4gICAgICB0aGlzLnNlcnZlclVybCA9ICcvamFudXMnO1xuICAgIH1cbiAgICBpZiAodGhpcy5zZXJ2ZXJVcmwgPT09ICcvamFudXMnKSB7XG4gICAgICBpZiAobG9jYXRpb24ucHJvdG9jb2wgPT09ICdodHRwczonKSB7XG4gICAgICAgIHRoaXMuc2VydmVyVXJsID0gJ3dzczovLycgKyBsb2NhdGlvbi5ob3N0ICsgJy9qYW51cyc7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnNlcnZlclVybCA9ICd3czovLycgKyBsb2NhdGlvbi5ob3N0ICsgJy9qYW51cyc7XG4gICAgICB9XG4gICAgfVxuICAgIGRlYnVnKGBjb25uZWN0aW5nIHRvICR7dGhpcy5zZXJ2ZXJVcmx9YCk7XG5cbiAgICBjb25zdCB3ZWJzb2NrZXRDb25uZWN0aW9uID0gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgdGhpcy53cyA9IG5ldyBXZWJTb2NrZXQodGhpcy5zZXJ2ZXJVcmwsIFwiamFudXMtcHJvdG9jb2xcIik7XG5cbiAgICAgIHRoaXMuc2Vzc2lvbiA9IG5ldyBtai5KYW51c1Nlc3Npb24odGhpcy53cy5zZW5kLmJpbmQodGhpcy53cyksIHsgdGltZW91dE1zOiA0MDAwMCB9KTtcblxuICAgICAgdGhpcy53ZWJzb2NrZXRDb25uZWN0aW9uUHJvbWlzZSA9IHt9O1xuICAgICAgdGhpcy53ZWJzb2NrZXRDb25uZWN0aW9uUHJvbWlzZS5yZXNvbHZlID0gcmVzb2x2ZTtcbiAgICAgIHRoaXMud2Vic29ja2V0Q29ubmVjdGlvblByb21pc2UucmVqZWN0ID0gcmVqZWN0O1xuXG4gICAgICB0aGlzLndzLmFkZEV2ZW50TGlzdGVuZXIoXCJjbG9zZVwiLCB0aGlzLm9uV2Vic29ja2V0Q2xvc2UpO1xuICAgICAgdGhpcy53cy5hZGRFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCB0aGlzLm9uV2Vic29ja2V0TWVzc2FnZSk7XG5cbiAgICAgIHRoaXMud3NPbk9wZW4gPSAoKSA9PiB7XG4gICAgICAgIHRoaXMud3MucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIm9wZW5cIiwgdGhpcy53c09uT3Blbik7XG4gICAgICAgIHRoaXMub25XZWJzb2NrZXRPcGVuKClcbiAgICAgICAgICAudGhlbihyZXNvbHZlKVxuICAgICAgICAgIC5jYXRjaChyZWplY3QpO1xuICAgICAgfTtcblxuICAgICAgdGhpcy53cy5hZGRFdmVudExpc3RlbmVyKFwib3BlblwiLCB0aGlzLndzT25PcGVuKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBQcm9taXNlLmFsbChbd2Vic29ja2V0Q29ubmVjdGlvbiwgdGhpcy51cGRhdGVUaW1lT2Zmc2V0KCldKTtcbiAgfVxuXG4gIGRpc2Nvbm5lY3QoKSB7XG4gICAgZGVidWcoYGRpc2Nvbm5lY3RpbmdgKTtcblxuICAgIGNsZWFyVGltZW91dCh0aGlzLnJlY29ubmVjdGlvblRpbWVvdXQpO1xuXG4gICAgdGhpcy5yZW1vdmVBbGxPY2N1cGFudHMoKTtcblxuICAgIGlmICh0aGlzLnB1Ymxpc2hlcikge1xuICAgICAgLy8gQ2xvc2UgdGhlIHB1Ymxpc2hlciBwZWVyIGNvbm5lY3Rpb24uIFdoaWNoIGFsc28gZGV0YWNoZXMgdGhlIHBsdWdpbiBoYW5kbGUuXG4gICAgICB0aGlzLnB1Ymxpc2hlci5jb25uLmNsb3NlKCk7XG4gICAgICB0aGlzLnB1Ymxpc2hlciA9IG51bGw7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc2Vzc2lvbikge1xuICAgICAgdGhpcy5zZXNzaW9uLmRpc3Bvc2UoKTtcbiAgICAgIHRoaXMuc2Vzc2lvbiA9IG51bGw7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMud3MpIHtcbiAgICAgIHRoaXMud3MucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIm9wZW5cIiwgdGhpcy53c09uT3Blbik7XG4gICAgICB0aGlzLndzLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJjbG9zZVwiLCB0aGlzLm9uV2Vic29ja2V0Q2xvc2UpO1xuICAgICAgdGhpcy53cy5yZW1vdmVFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCB0aGlzLm9uV2Vic29ja2V0TWVzc2FnZSk7XG4gICAgICB0aGlzLndzLmNsb3NlKCk7XG4gICAgICB0aGlzLndzID0gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBOb3cgdGhhdCBhbGwgUlRDUGVlckNvbm5lY3Rpb24gY2xvc2VkLCBiZSBzdXJlIHRvIG5vdCBjYWxsXG4gICAgLy8gcmVjb25uZWN0KCkgYWdhaW4gdmlhIHBlcmZvcm1EZWxheWVkUmVjb25uZWN0IGlmIHByZXZpb3VzXG4gICAgLy8gUlRDUGVlckNvbm5lY3Rpb24gd2FzIGluIHRoZSBmYWlsZWQgc3RhdGUuXG4gICAgaWYgKHRoaXMuZGVsYXllZFJlY29ubmVjdFRpbWVvdXQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLmRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0KTtcbiAgICAgIHRoaXMuZGVsYXllZFJlY29ubmVjdFRpbWVvdXQgPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIGlzRGlzY29ubmVjdGVkKCkge1xuICAgIHJldHVybiB0aGlzLndzID09PSBudWxsO1xuICB9XG5cbiAgYXN5bmMgb25XZWJzb2NrZXRPcGVuKCkge1xuICAgIC8vIENyZWF0ZSB0aGUgSmFudXMgU2Vzc2lvblxuICAgIGF3YWl0IHRoaXMuc2Vzc2lvbi5jcmVhdGUoKTtcblxuICAgIC8vIEF0dGFjaCB0aGUgU0ZVIFBsdWdpbiBhbmQgY3JlYXRlIGEgUlRDUGVlckNvbm5lY3Rpb24gZm9yIHRoZSBwdWJsaXNoZXIuXG4gICAgLy8gVGhlIHB1Ymxpc2hlciBzZW5kcyBhdWRpbyBhbmQgb3BlbnMgdHdvIGJpZGlyZWN0aW9uYWwgZGF0YSBjaGFubmVscy5cbiAgICAvLyBPbmUgcmVsaWFibGUgZGF0YWNoYW5uZWwgYW5kIG9uZSB1bnJlbGlhYmxlLlxuICAgIHRoaXMucHVibGlzaGVyID0gYXdhaXQgdGhpcy5jcmVhdGVQdWJsaXNoZXIoKTtcblxuICAgIC8vIENhbGwgdGhlIG5hZiBjb25uZWN0U3VjY2VzcyBjYWxsYmFjayBiZWZvcmUgd2Ugc3RhcnQgcmVjZWl2aW5nIFdlYlJUQyBtZXNzYWdlcy5cbiAgICB0aGlzLmNvbm5lY3RTdWNjZXNzKHRoaXMuY2xpZW50SWQpO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnB1Ymxpc2hlci5pbml0aWFsT2NjdXBhbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBvY2N1cGFudElkID0gdGhpcy5wdWJsaXNoZXIuaW5pdGlhbE9jY3VwYW50c1tpXTtcbiAgICAgIGlmIChvY2N1cGFudElkID09PSB0aGlzLmNsaWVudElkKSBjb250aW51ZTsgLy8gSGFwcGVucyBkdXJpbmcgbm9uLWdyYWNlZnVsIHJlY29ubmVjdHMgZHVlIHRvIHpvbWJpZSBzZXNzaW9uc1xuICAgICAgdGhpcy5hZGRBdmFpbGFibGVPY2N1cGFudChvY2N1cGFudElkKTtcbiAgICB9XG5cbiAgICB0aGlzLnN5bmNPY2N1cGFudHMoKTtcbiAgfVxuXG4gIG9uV2Vic29ja2V0Q2xvc2UoZXZlbnQpIHtcbiAgICAvLyBUaGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkIHN1Y2Nlc3NmdWxseS4gRG9uJ3QgdHJ5IHRvIHJlY29ubmVjdC5cbiAgICBpZiAoZXZlbnQuY29kZSA9PT0gV1NfTk9STUFMX0NMT1NVUkUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLndlYnNvY2tldENvbm5lY3Rpb25Qcm9taXNlLnJlamVjdChldmVudCk7XG5cbiAgICBpZiAoIXRoaXMuaXNSZWNvbm5lY3RpbmcpIHtcbiAgICAgIHRoaXMuaXNSZWNvbm5lY3RpbmcgPSB0cnVlO1xuICAgICAgY29uc29sZS53YXJuKFwiSmFudXMgd2Vic29ja2V0IGNsb3NlZCB1bmV4cGVjdGVkbHkuXCIpO1xuICAgICAgaWYgKHRoaXMub25SZWNvbm5lY3RpbmcpIHtcbiAgICAgICAgdGhpcy5vblJlY29ubmVjdGluZyh0aGlzLnJlY29ubmVjdGlvbkRlbGF5KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5yZWNvbm5lY3Rpb25UaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB0aGlzLnJlY29ubmVjdCgpLCB0aGlzLnJlY29ubmVjdGlvbkRlbGF5KTtcbiAgICB9XG4gIH1cblxuICByZWNvbm5lY3QoKSB7XG4gICAgLy8gRGlzcG9zZSBvZiBhbGwgbmV0d29ya2VkIGVudGl0aWVzIGFuZCBvdGhlciByZXNvdXJjZXMgdGllZCB0byB0aGUgc2Vzc2lvbi5cbiAgICB0aGlzLmRpc2Nvbm5lY3QoKTtcblxuICAgIHRoaXMuY29ubmVjdCgpXG4gICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgIHRoaXMucmVjb25uZWN0aW9uRGVsYXkgPSB0aGlzLmluaXRpYWxSZWNvbm5lY3Rpb25EZWxheTtcbiAgICAgICAgdGhpcy5yZWNvbm5lY3Rpb25BdHRlbXB0cyA9IDA7XG4gICAgICAgIHRoaXMuaXNSZWNvbm5lY3RpbmcgPSBmYWxzZTtcblxuICAgICAgICBpZiAodGhpcy5vblJlY29ubmVjdGVkKSB7XG4gICAgICAgICAgdGhpcy5vblJlY29ubmVjdGVkKCk7XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICB0aGlzLnJlY29ubmVjdGlvbkRlbGF5ICs9IDEwMDA7XG4gICAgICAgIHRoaXMucmVjb25uZWN0aW9uQXR0ZW1wdHMrKztcblxuICAgICAgICBpZiAodGhpcy5yZWNvbm5lY3Rpb25BdHRlbXB0cyA+IHRoaXMubWF4UmVjb25uZWN0aW9uQXR0ZW1wdHMpIHtcbiAgICAgICAgICBjb25zdCBlcnJvciA9IG5ldyBFcnJvcihcbiAgICAgICAgICAgIFwiQ29ubmVjdGlvbiBjb3VsZCBub3QgYmUgcmVlc3RhYmxpc2hlZCwgZXhjZWVkZWQgbWF4aW11bSBudW1iZXIgb2YgcmVjb25uZWN0aW9uIGF0dGVtcHRzLlwiXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAodGhpcy5vblJlY29ubmVjdGlvbkVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5vblJlY29ubmVjdGlvbkVycm9yKGVycm9yKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKGVycm9yKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLndhcm4oXCJFcnJvciBkdXJpbmcgcmVjb25uZWN0LCByZXRyeWluZy5cIik7XG4gICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG5cbiAgICAgICAgaWYgKHRoaXMub25SZWNvbm5lY3RpbmcpIHtcbiAgICAgICAgICB0aGlzLm9uUmVjb25uZWN0aW5nKHRoaXMucmVjb25uZWN0aW9uRGVsYXkpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZWNvbm5lY3Rpb25UaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB0aGlzLnJlY29ubmVjdCgpLCB0aGlzLnJlY29ubmVjdGlvbkRlbGF5KTtcbiAgICAgIH0pO1xuICB9XG5cbiAgcGVyZm9ybURlbGF5ZWRSZWNvbm5lY3QoKSB7XG4gICAgaWYgKHRoaXMuZGVsYXllZFJlY29ubmVjdFRpbWVvdXQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLmRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0KTtcbiAgICB9XG5cbiAgICB0aGlzLmRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLmRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0ID0gbnVsbDtcbiAgICAgIHRoaXMucmVjb25uZWN0KCk7XG4gICAgfSwgMTAwMDApO1xuICB9XG5cbiAgb25XZWJzb2NrZXRNZXNzYWdlKGV2ZW50KSB7XG4gICAgdGhpcy5zZXNzaW9uLnJlY2VpdmUoSlNPTi5wYXJzZShldmVudC5kYXRhKSk7XG4gIH1cblxuICBhZGRBdmFpbGFibGVPY2N1cGFudChvY2N1cGFudElkKSB7XG4gICAgaWYgKHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmluZGV4T2Yob2NjdXBhbnRJZCkgPT09IC0xKSB7XG4gICAgICB0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5wdXNoKG9jY3VwYW50SWQpO1xuICAgIH1cbiAgfVxuXG4gIHJlbW92ZUF2YWlsYWJsZU9jY3VwYW50KG9jY3VwYW50SWQpIHtcbiAgICBjb25zdCBpZHggPSB0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpO1xuICAgIGlmIChpZHggIT09IC0xKSB7XG4gICAgICB0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5zcGxpY2UoaWR4LCAxKTtcbiAgICB9XG4gIH1cblxuICBzeW5jT2NjdXBhbnRzKHJlcXVlc3RlZE9jY3VwYW50cykge1xuICAgIGlmIChyZXF1ZXN0ZWRPY2N1cGFudHMpIHtcbiAgICAgIHRoaXMucmVxdWVzdGVkT2NjdXBhbnRzID0gcmVxdWVzdGVkT2NjdXBhbnRzO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5yZXF1ZXN0ZWRPY2N1cGFudHMpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBBZGQgYW55IHJlcXVlc3RlZCwgYXZhaWxhYmxlLCBhbmQgbm9uLXBlbmRpbmcgb2NjdXBhbnRzLlxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5yZXF1ZXN0ZWRPY2N1cGFudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IG9jY3VwYW50SWQgPSB0aGlzLnJlcXVlc3RlZE9jY3VwYW50c1tpXTtcbiAgICAgIGlmICghdGhpcy5vY2N1cGFudHNbb2NjdXBhbnRJZF0gJiYgdGhpcy5hdmFpbGFibGVPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKSAhPT0gLTEgJiYgIXRoaXMucGVuZGluZ09jY3VwYW50cy5oYXMob2NjdXBhbnRJZCkpIHtcbiAgICAgICAgdGhpcy5hZGRPY2N1cGFudChvY2N1cGFudElkKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZW1vdmUgYW55IHVucmVxdWVzdGVkIGFuZCBjdXJyZW50bHkgYWRkZWQgb2NjdXBhbnRzLlxuICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGhpcy5hdmFpbGFibGVPY2N1cGFudHMubGVuZ3RoOyBqKyspIHtcbiAgICAgIGNvbnN0IG9jY3VwYW50SWQgPSB0aGlzLmF2YWlsYWJsZU9jY3VwYW50c1tqXTtcbiAgICAgIGlmICh0aGlzLm9jY3VwYW50c1tvY2N1cGFudElkXSAmJiB0aGlzLnJlcXVlc3RlZE9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgICB0aGlzLnJlbW92ZU9jY3VwYW50KG9jY3VwYW50SWQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENhbGwgdGhlIE5ldHdvcmtlZCBBRnJhbWUgY2FsbGJhY2tzIGZvciB0aGUgdXBkYXRlZCBvY2N1cGFudHMgbGlzdC5cbiAgICB0aGlzLm9uT2NjdXBhbnRzQ2hhbmdlZCh0aGlzLm9jY3VwYW50cyk7XG4gIH1cblxuICBhc3luYyBhZGRPY2N1cGFudChvY2N1cGFudElkKSB7XG4gICAgdGhpcy5wZW5kaW5nT2NjdXBhbnRzLmFkZChvY2N1cGFudElkKTtcbiAgICBcbiAgICBjb25zdCBhdmFpbGFibGVPY2N1cGFudHNDb3VudCA9IHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmxlbmd0aDtcbiAgICBpZiAoYXZhaWxhYmxlT2NjdXBhbnRzQ291bnQgPiBBVkFJTEFCTEVfT0NDVVBBTlRTX1RIUkVTSE9MRCkge1xuICAgICAgYXdhaXQgcmFuZG9tRGVsYXkoMCwgTUFYX1NVQlNDUklCRV9ERUxBWSk7XG4gICAgfVxuICBcbiAgICBjb25zdCBzdWJzY3JpYmVyID0gYXdhaXQgdGhpcy5jcmVhdGVTdWJzY3JpYmVyKG9jY3VwYW50SWQpO1xuICAgIGlmIChzdWJzY3JpYmVyKSB7XG4gICAgICBpZighdGhpcy5wZW5kaW5nT2NjdXBhbnRzLmhhcyhvY2N1cGFudElkKSkge1xuICAgICAgICBzdWJzY3JpYmVyLmNvbm4uY2xvc2UoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMucGVuZGluZ09jY3VwYW50cy5kZWxldGUob2NjdXBhbnRJZCk7XG4gICAgICAgIHRoaXMub2NjdXBhbnRJZHMucHVzaChvY2N1cGFudElkKTtcbiAgICAgICAgdGhpcy5vY2N1cGFudHNbb2NjdXBhbnRJZF0gPSBzdWJzY3JpYmVyO1xuXG4gICAgICAgIHRoaXMuc2V0TWVkaWFTdHJlYW0ob2NjdXBhbnRJZCwgc3Vic2NyaWJlci5tZWRpYVN0cmVhbSk7XG5cbiAgICAgICAgLy8gQ2FsbCB0aGUgTmV0d29ya2VkIEFGcmFtZSBjYWxsYmFja3MgZm9yIHRoZSBuZXcgb2NjdXBhbnQuXG4gICAgICAgIHRoaXMub25PY2N1cGFudENvbm5lY3RlZChvY2N1cGFudElkKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZW1vdmVBbGxPY2N1cGFudHMoKSB7XG4gICAgdGhpcy5wZW5kaW5nT2NjdXBhbnRzLmNsZWFyKCk7XG4gICAgZm9yIChsZXQgaSA9IHRoaXMub2NjdXBhbnRJZHMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIHRoaXMucmVtb3ZlT2NjdXBhbnQodGhpcy5vY2N1cGFudElkc1tpXSk7XG4gICAgfVxuICB9XG5cbiAgcmVtb3ZlT2NjdXBhbnQob2NjdXBhbnRJZCkge1xuICAgIHRoaXMucGVuZGluZ09jY3VwYW50cy5kZWxldGUob2NjdXBhbnRJZCk7XG4gICAgXG4gICAgaWYgKHRoaXMub2NjdXBhbnRzW29jY3VwYW50SWRdKSB7XG4gICAgICAvLyBDbG9zZSB0aGUgc3Vic2NyaWJlciBwZWVyIGNvbm5lY3Rpb24uIFdoaWNoIGFsc28gZGV0YWNoZXMgdGhlIHBsdWdpbiBoYW5kbGUuXG4gICAgICB0aGlzLm9jY3VwYW50c1tvY2N1cGFudElkXS5jb25uLmNsb3NlKCk7XG4gICAgICBkZWxldGUgdGhpcy5vY2N1cGFudHNbb2NjdXBhbnRJZF07XG4gICAgICBcbiAgICAgIHRoaXMub2NjdXBhbnRJZHMuc3BsaWNlKHRoaXMub2NjdXBhbnRJZHMuaW5kZXhPZihvY2N1cGFudElkKSwgMSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMubWVkaWFTdHJlYW1zW29jY3VwYW50SWRdKSB7XG4gICAgICBkZWxldGUgdGhpcy5tZWRpYVN0cmVhbXNbb2NjdXBhbnRJZF07XG4gICAgfVxuXG4gICAgaWYgKHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuaGFzKG9jY3VwYW50SWQpKSB7XG4gICAgICBjb25zdCBtc2cgPSBcIlRoZSB1c2VyIGRpc2Nvbm5lY3RlZCBiZWZvcmUgdGhlIG1lZGlhIHN0cmVhbSB3YXMgcmVzb2x2ZWQuXCI7XG4gICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChvY2N1cGFudElkKS5hdWRpby5yZWplY3QobXNnKTtcbiAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KG9jY3VwYW50SWQpLnZpZGVvLnJlamVjdChtc2cpO1xuICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5kZWxldGUob2NjdXBhbnRJZCk7XG4gICAgfVxuXG4gICAgLy8gQ2FsbCB0aGUgTmV0d29ya2VkIEFGcmFtZSBjYWxsYmFja3MgZm9yIHRoZSByZW1vdmVkIG9jY3VwYW50LlxuICAgIHRoaXMub25PY2N1cGFudERpc2Nvbm5lY3RlZChvY2N1cGFudElkKTtcbiAgfVxuXG4gIGFzc29jaWF0ZShjb25uLCBoYW5kbGUpIHtcbiAgICBjb25uLmFkZEV2ZW50TGlzdGVuZXIoXCJpY2VjYW5kaWRhdGVcIiwgZXYgPT4ge1xuICAgICAgaGFuZGxlLnNlbmRUcmlja2xlKGV2LmNhbmRpZGF0ZSB8fCBudWxsKS5jYXRjaChlID0+IGVycm9yKFwiRXJyb3IgdHJpY2tsaW5nIElDRTogJW9cIiwgZSkpO1xuICAgIH0pO1xuICAgIGNvbm4uYWRkRXZlbnRMaXN0ZW5lcihcImljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZVwiLCBldiA9PiB7XG4gICAgICBpZiAoY29ubi5pY2VDb25uZWN0aW9uU3RhdGUgPT09IFwiY29ubmVjdGVkXCIpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJJQ0Ugc3RhdGUgY2hhbmdlZCB0byBjb25uZWN0ZWRcIik7XG4gICAgICB9XG4gICAgICBpZiAoY29ubi5pY2VDb25uZWN0aW9uU3RhdGUgPT09IFwiZGlzY29ubmVjdGVkXCIpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFwiSUNFIHN0YXRlIGNoYW5nZWQgdG8gZGlzY29ubmVjdGVkXCIpO1xuICAgICAgfVxuICAgICAgaWYgKGNvbm4uaWNlQ29ubmVjdGlvblN0YXRlID09PSBcImZhaWxlZFwiKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcIklDRSBmYWlsdXJlIGRldGVjdGVkLiBSZWNvbm5lY3RpbmcgaW4gMTBzLlwiKTtcbiAgICAgICAgdGhpcy5wZXJmb3JtRGVsYXllZFJlY29ubmVjdCgpO1xuICAgICAgfVxuICAgIH0pXG5cbiAgICAvLyB3ZSBoYXZlIHRvIGRlYm91bmNlIHRoZXNlIGJlY2F1c2UgamFudXMgZ2V0cyBhbmdyeSBpZiB5b3Ugc2VuZCBpdCBhIG5ldyBTRFAgYmVmb3JlXG4gICAgLy8gaXQncyBmaW5pc2hlZCBwcm9jZXNzaW5nIGFuIGV4aXN0aW5nIFNEUC4gaW4gYWN0dWFsaXR5LCBpdCBzZWVtcyBsaWtlIHRoaXMgaXMgbWF5YmVcbiAgICAvLyB0b28gbGliZXJhbCBhbmQgd2UgbmVlZCB0byB3YWl0IHNvbWUgYW1vdW50IG9mIHRpbWUgYWZ0ZXIgYW4gb2ZmZXIgYmVmb3JlIHNlbmRpbmcgYW5vdGhlcixcbiAgICAvLyBidXQgd2UgZG9uJ3QgY3VycmVudGx5IGtub3cgYW55IGdvb2Qgd2F5IG9mIGRldGVjdGluZyBleGFjdGx5IGhvdyBsb25nIDooXG4gICAgY29ubi5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgXCJuZWdvdGlhdGlvbm5lZWRlZFwiLFxuICAgICAgZGVib3VuY2UoZXYgPT4ge1xuICAgICAgICBkZWJ1ZyhcIlNlbmRpbmcgbmV3IG9mZmVyIGZvciBoYW5kbGU6ICVvXCIsIGhhbmRsZSk7XG4gICAgICAgIHZhciBvZmZlciA9IGNvbm4uY3JlYXRlT2ZmZXIoKS50aGVuKHRoaXMuY29uZmlndXJlUHVibGlzaGVyU2RwKS50aGVuKHRoaXMuZml4U2FmYXJpSWNlVUZyYWcpO1xuICAgICAgICB2YXIgbG9jYWwgPSBvZmZlci50aGVuKG8gPT4gY29ubi5zZXRMb2NhbERlc2NyaXB0aW9uKG8pKTtcbiAgICAgICAgdmFyIHJlbW90ZSA9IG9mZmVyO1xuXG4gICAgICAgIHJlbW90ZSA9IHJlbW90ZVxuICAgICAgICAgIC50aGVuKHRoaXMuZml4U2FmYXJpSWNlVUZyYWcpXG4gICAgICAgICAgLnRoZW4oaiA9PiBoYW5kbGUuc2VuZEpzZXAoaikpXG4gICAgICAgICAgLnRoZW4ociA9PiBjb25uLnNldFJlbW90ZURlc2NyaXB0aW9uKHIuanNlcCkpO1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwoW2xvY2FsLCByZW1vdGVdKS5jYXRjaChlID0+IGVycm9yKFwiRXJyb3IgbmVnb3RpYXRpbmcgb2ZmZXI6ICVvXCIsIGUpKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgICBoYW5kbGUub24oXG4gICAgICBcImV2ZW50XCIsXG4gICAgICBkZWJvdW5jZShldiA9PiB7XG4gICAgICAgIHZhciBqc2VwID0gZXYuanNlcDtcbiAgICAgICAgaWYgKGpzZXAgJiYganNlcC50eXBlID09IFwib2ZmZXJcIikge1xuICAgICAgICAgIGRlYnVnKFwiQWNjZXB0aW5nIG5ldyBvZmZlciBmb3IgaGFuZGxlOiAlb1wiLCBoYW5kbGUpO1xuICAgICAgICAgIHZhciBhbnN3ZXIgPSBjb25uXG4gICAgICAgICAgICAuc2V0UmVtb3RlRGVzY3JpcHRpb24odGhpcy5jb25maWd1cmVTdWJzY3JpYmVyU2RwKGpzZXApKVxuICAgICAgICAgICAgLnRoZW4oXyA9PiBjb25uLmNyZWF0ZUFuc3dlcigpKVxuICAgICAgICAgICAgLnRoZW4odGhpcy5maXhTYWZhcmlJY2VVRnJhZyk7XG4gICAgICAgICAgdmFyIGxvY2FsID0gYW5zd2VyLnRoZW4oYSA9PiBjb25uLnNldExvY2FsRGVzY3JpcHRpb24oYSkpO1xuICAgICAgICAgIHZhciByZW1vdGUgPSBhbnN3ZXIudGhlbihqID0+IGhhbmRsZS5zZW5kSnNlcChqKSk7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UuYWxsKFtsb2NhbCwgcmVtb3RlXSkuY2F0Y2goZSA9PiBlcnJvcihcIkVycm9yIG5lZ290aWF0aW5nIGFuc3dlcjogJW9cIiwgZSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIHNvbWUgb3RoZXIga2luZCBvZiBldmVudCwgbm90aGluZyB0byBkb1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBhc3luYyBjcmVhdGVQdWJsaXNoZXIoKSB7XG4gICAgdmFyIGhhbmRsZSA9IG5ldyBtai5KYW51c1BsdWdpbkhhbmRsZSh0aGlzLnNlc3Npb24pO1xuICAgIHZhciBjb25uID0gbmV3IFJUQ1BlZXJDb25uZWN0aW9uKHRoaXMucGVlckNvbm5lY3Rpb25Db25maWcgfHwgREVGQVVMVF9QRUVSX0NPTk5FQ1RJT05fQ09ORklHKTtcblxuICAgIGRlYnVnKFwicHViIHdhaXRpbmcgZm9yIHNmdVwiKTtcbiAgICBhd2FpdCBoYW5kbGUuYXR0YWNoKFwiamFudXMucGx1Z2luLnNmdVwiLCB0aGlzLmxvb3BzICYmIHRoaXMuY2xpZW50SWQgPyBwYXJzZUludCh0aGlzLmNsaWVudElkKSAlIHRoaXMubG9vcHMgOiB1bmRlZmluZWQpO1xuXG4gICAgdGhpcy5hc3NvY2lhdGUoY29ubiwgaGFuZGxlKTtcblxuICAgIGRlYnVnKFwicHViIHdhaXRpbmcgZm9yIGRhdGEgY2hhbm5lbHMgJiB3ZWJydGN1cFwiKTtcbiAgICB2YXIgd2VicnRjdXAgPSBuZXcgUHJvbWlzZShyZXNvbHZlID0+IGhhbmRsZS5vbihcIndlYnJ0Y3VwXCIsIHJlc29sdmUpKTtcblxuICAgIC8vIFVucmVsaWFibGUgZGF0YWNoYW5uZWw6IHNlbmRpbmcgYW5kIHJlY2VpdmluZyBjb21wb25lbnQgdXBkYXRlcy5cbiAgICAvLyBSZWxpYWJsZSBkYXRhY2hhbm5lbDogc2VuZGluZyBhbmQgcmVjaWV2aW5nIGVudGl0eSBpbnN0YW50aWF0aW9ucy5cbiAgICB2YXIgcmVsaWFibGVDaGFubmVsID0gY29ubi5jcmVhdGVEYXRhQ2hhbm5lbChcInJlbGlhYmxlXCIsIHsgb3JkZXJlZDogdHJ1ZSB9KTtcbiAgICB2YXIgdW5yZWxpYWJsZUNoYW5uZWwgPSBjb25uLmNyZWF0ZURhdGFDaGFubmVsKFwidW5yZWxpYWJsZVwiLCB7XG4gICAgICBvcmRlcmVkOiBmYWxzZSxcbiAgICAgIG1heFJldHJhbnNtaXRzOiAwXG4gICAgfSk7XG5cbiAgICByZWxpYWJsZUNoYW5uZWwuYWRkRXZlbnRMaXN0ZW5lcihcIm1lc3NhZ2VcIiwgZSA9PiB0aGlzLm9uRGF0YUNoYW5uZWxNZXNzYWdlKGUsIFwiamFudXMtcmVsaWFibGVcIikpO1xuICAgIHVucmVsaWFibGVDaGFubmVsLmFkZEV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIGUgPT4gdGhpcy5vbkRhdGFDaGFubmVsTWVzc2FnZShlLCBcImphbnVzLXVucmVsaWFibGVcIikpO1xuXG4gICAgYXdhaXQgd2VicnRjdXA7XG4gICAgYXdhaXQgdW50aWxEYXRhQ2hhbm5lbE9wZW4ocmVsaWFibGVDaGFubmVsKTtcbiAgICBhd2FpdCB1bnRpbERhdGFDaGFubmVsT3Blbih1bnJlbGlhYmxlQ2hhbm5lbCk7XG5cbiAgICAvLyBkb2luZyB0aGlzIGhlcmUgaXMgc29ydCBvZiBhIGhhY2sgYXJvdW5kIGNocm9tZSByZW5lZ290aWF0aW9uIHdlaXJkbmVzcyAtLVxuICAgIC8vIGlmIHdlIGRvIGl0IHByaW9yIHRvIHdlYnJ0Y3VwLCBjaHJvbWUgb24gZ2VhciBWUiB3aWxsIHNvbWV0aW1lcyBwdXQgYVxuICAgIC8vIHJlbmVnb3RpYXRpb24gb2ZmZXIgaW4gZmxpZ2h0IHdoaWxlIHRoZSBmaXJzdCBvZmZlciB3YXMgc3RpbGwgYmVpbmdcbiAgICAvLyBwcm9jZXNzZWQgYnkgamFudXMuIHdlIHNob3VsZCBmaW5kIHNvbWUgbW9yZSBwcmluY2lwbGVkIHdheSB0byBmaWd1cmUgb3V0XG4gICAgLy8gd2hlbiBqYW51cyBpcyBkb25lIGluIHRoZSBmdXR1cmUuXG4gICAgaWYgKHRoaXMubG9jYWxNZWRpYVN0cmVhbSkge1xuICAgICAgdGhpcy5sb2NhbE1lZGlhU3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2godHJhY2sgPT4ge1xuICAgICAgICBjb25uLmFkZFRyYWNrKHRyYWNrLCB0aGlzLmxvY2FsTWVkaWFTdHJlYW0pO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gSGFuZGxlIGFsbCBvZiB0aGUgam9pbiBhbmQgbGVhdmUgZXZlbnRzLlxuICAgIGhhbmRsZS5vbihcImV2ZW50XCIsIGV2ID0+IHtcbiAgICAgIHZhciBkYXRhID0gZXYucGx1Z2luZGF0YS5kYXRhO1xuICAgICAgaWYgKGRhdGEuZXZlbnQgPT0gXCJqb2luXCIgJiYgZGF0YS5yb29tX2lkID09IHRoaXMucm9vbSkge1xuICAgICAgICBpZiAodGhpcy5kZWxheWVkUmVjb25uZWN0VGltZW91dCkge1xuICAgICAgICAgIC8vIERvbid0IGNyZWF0ZSBhIG5ldyBSVENQZWVyQ29ubmVjdGlvbiwgYWxsIFJUQ1BlZXJDb25uZWN0aW9uIHdpbGwgYmUgY2xvc2VkIGluIGxlc3MgdGhhbiAxMHMuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuYWRkQXZhaWxhYmxlT2NjdXBhbnQoZGF0YS51c2VyX2lkKTtcbiAgICAgICAgdGhpcy5zeW5jT2NjdXBhbnRzKCk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnQgPT0gXCJsZWF2ZVwiICYmIGRhdGEucm9vbV9pZCA9PSB0aGlzLnJvb20pIHtcbiAgICAgICAgdGhpcy5yZW1vdmVBdmFpbGFibGVPY2N1cGFudChkYXRhLnVzZXJfaWQpO1xuICAgICAgICB0aGlzLnJlbW92ZU9jY3VwYW50KGRhdGEudXNlcl9pZCk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnQgPT0gXCJibG9ja2VkXCIpIHtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChcImJsb2NrZWRcIiwgeyBkZXRhaWw6IHsgY2xpZW50SWQ6IGRhdGEuYnkgfSB9KSk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuZXZlbnQgPT0gXCJ1bmJsb2NrZWRcIikge1xuICAgICAgICBkb2N1bWVudC5ib2R5LmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KFwidW5ibG9ja2VkXCIsIHsgZGV0YWlsOiB7IGNsaWVudElkOiBkYXRhLmJ5IH0gfSkpO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50ID09PSBcImRhdGFcIikge1xuICAgICAgICB0aGlzLm9uRGF0YShKU09OLnBhcnNlKGRhdGEuYm9keSksIFwiamFudXMtZXZlbnRcIik7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBkZWJ1ZyhcInB1YiB3YWl0aW5nIGZvciBqb2luXCIpO1xuXG4gICAgLy8gU2VuZCBqb2luIG1lc3NhZ2UgdG8gamFudXMuIExpc3RlbiBmb3Igam9pbi9sZWF2ZSBtZXNzYWdlcy4gQXV0b21hdGljYWxseSBzdWJzY3JpYmUgdG8gYWxsIHVzZXJzJyBXZWJSVEMgZGF0YS5cbiAgICB2YXIgbWVzc2FnZSA9IGF3YWl0IHRoaXMuc2VuZEpvaW4oaGFuZGxlLCB7XG4gICAgICBub3RpZmljYXRpb25zOiB0cnVlLFxuICAgICAgZGF0YTogdHJ1ZVxuICAgIH0pO1xuXG4gICAgaWYgKCFtZXNzYWdlLnBsdWdpbmRhdGEuZGF0YS5zdWNjZXNzKSB7XG4gICAgICBjb25zdCBlcnIgPSBtZXNzYWdlLnBsdWdpbmRhdGEuZGF0YS5lcnJvcjtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgIC8vIFdlIG1heSBnZXQgaGVyZSBiZWNhdXNlIG9mIGFuIGV4cGlyZWQgSldULlxuICAgICAgLy8gQ2xvc2UgdGhlIGNvbm5lY3Rpb24gb3Vyc2VsZiBvdGhlcndpc2UgamFudXMgd2lsbCBjbG9zZSBpdCBhZnRlclxuICAgICAgLy8gc2Vzc2lvbl90aW1lb3V0IGJlY2F1c2Ugd2UgZGlkbid0IHNlbmQgYW55IGtlZXBhbGl2ZSBhbmQgdGhpcyB3aWxsXG4gICAgICAvLyB0cmlnZ2VyIGEgZGVsYXllZCByZWNvbm5lY3QgYmVjYXVzZSBvZiB0aGUgaWNlY29ubmVjdGlvbnN0YXRlY2hhbmdlXG4gICAgICAvLyBsaXN0ZW5lciBmb3IgZmFpbHVyZSBzdGF0ZS5cbiAgICAgIC8vIEV2ZW4gaWYgdGhlIGFwcCBjb2RlIGNhbGxzIGRpc2Nvbm5lY3QgaW4gY2FzZSBvZiBlcnJvciwgZGlzY29ubmVjdFxuICAgICAgLy8gd29uJ3QgY2xvc2UgdGhlIHBlZXIgY29ubmVjdGlvbiBiZWNhdXNlIHRoaXMucHVibGlzaGVyIGlzIG5vdCBzZXQuXG4gICAgICBjb25uLmNsb3NlKCk7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuXG4gICAgdmFyIGluaXRpYWxPY2N1cGFudHMgPSBtZXNzYWdlLnBsdWdpbmRhdGEuZGF0YS5yZXNwb25zZS51c2Vyc1t0aGlzLnJvb21dIHx8IFtdO1xuXG4gICAgaWYgKGluaXRpYWxPY2N1cGFudHMuaW5jbHVkZXModGhpcy5jbGllbnRJZCkpIHtcbiAgICAgIGNvbnNvbGUud2FybihcIkphbnVzIHN0aWxsIGhhcyBwcmV2aW91cyBzZXNzaW9uIGZvciB0aGlzIGNsaWVudC4gUmVjb25uZWN0aW5nIGluIDEwcy5cIik7XG4gICAgICB0aGlzLnBlcmZvcm1EZWxheWVkUmVjb25uZWN0KCk7XG4gICAgfVxuXG4gICAgZGVidWcoXCJwdWJsaXNoZXIgcmVhZHlcIik7XG4gICAgcmV0dXJuIHtcbiAgICAgIGhhbmRsZSxcbiAgICAgIGluaXRpYWxPY2N1cGFudHMsXG4gICAgICByZWxpYWJsZUNoYW5uZWwsXG4gICAgICB1bnJlbGlhYmxlQ2hhbm5lbCxcbiAgICAgIGNvbm5cbiAgICB9O1xuICB9XG5cbiAgY29uZmlndXJlUHVibGlzaGVyU2RwKGpzZXApIHtcbiAgICBqc2VwLnNkcCA9IGpzZXAuc2RwLnJlcGxhY2UoL2E9Zm10cDooMTA5fDExMSkuKlxcclxcbi9nLCAobGluZSwgcHQpID0+IHtcbiAgICAgIGNvbnN0IHBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKHNkcFV0aWxzLnBhcnNlRm10cChsaW5lKSwgT1BVU19QQVJBTUVURVJTKTtcbiAgICAgIHJldHVybiBzZHBVdGlscy53cml0ZUZtdHAoeyBwYXlsb2FkVHlwZTogcHQsIHBhcmFtZXRlcnM6IHBhcmFtZXRlcnMgfSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIGpzZXA7XG4gIH1cblxuICBjb25maWd1cmVTdWJzY3JpYmVyU2RwKGpzZXApIHtcbiAgICAvLyB0b2RvOiBjb25zaWRlciBjbGVhbmluZyB1cCB0aGVzZSBoYWNrcyB0byB1c2Ugc2RwdXRpbHNcbiAgICBpZiAoIWlzSDI2NFZpZGVvU3VwcG9ydGVkKSB7XG4gICAgICBpZiAobmF2aWdhdG9yLnVzZXJBZ2VudC5pbmRleE9mKFwiSGVhZGxlc3NDaHJvbWVcIikgIT09IC0xKSB7XG4gICAgICAgIC8vIEhlYWRsZXNzQ2hyb21lIChlLmcuIHB1cHBldGVlcikgZG9lc24ndCBzdXBwb3J0IHdlYnJ0YyB2aWRlbyBzdHJlYW1zLCBzbyB3ZSByZW1vdmUgdGhvc2UgbGluZXMgZnJvbSB0aGUgU0RQLlxuICAgICAgICBqc2VwLnNkcCA9IGpzZXAuc2RwLnJlcGxhY2UoL209dmlkZW9bXl0qbT0vLCBcIm09XCIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFRPRE86IEhhY2sgdG8gZ2V0IHZpZGVvIHdvcmtpbmcgb24gQ2hyb21lIGZvciBBbmRyb2lkLiBodHRwczovL2dyb3Vwcy5nb29nbGUuY29tL2ZvcnVtLyMhdG9waWMvbW96aWxsYS5kZXYubWVkaWEvWWUyOXZ1TVRwbzhcbiAgICBpZiAobmF2aWdhdG9yLnVzZXJBZ2VudC5pbmRleE9mKFwiQW5kcm9pZFwiKSA9PT0gLTEpIHtcbiAgICAgIGpzZXAuc2RwID0ganNlcC5zZHAucmVwbGFjZShcbiAgICAgICAgXCJhPXJ0Y3AtZmI6MTA3IGdvb2ctcmVtYlxcclxcblwiLFxuICAgICAgICBcImE9cnRjcC1mYjoxMDcgZ29vZy1yZW1iXFxyXFxuYT1ydGNwLWZiOjEwNyB0cmFuc3BvcnQtY2NcXHJcXG5hPWZtdHA6MTA3IGxldmVsLWFzeW1tZXRyeS1hbGxvd2VkPTE7cGFja2V0aXphdGlvbi1tb2RlPTE7cHJvZmlsZS1sZXZlbC1pZD00MmUwMWZcXHJcXG5cIlxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAganNlcC5zZHAgPSBqc2VwLnNkcC5yZXBsYWNlKFxuICAgICAgICBcImE9cnRjcC1mYjoxMDcgZ29vZy1yZW1iXFxyXFxuXCIsXG4gICAgICAgIFwiYT1ydGNwLWZiOjEwNyBnb29nLXJlbWJcXHJcXG5hPXJ0Y3AtZmI6MTA3IHRyYW5zcG9ydC1jY1xcclxcbmE9Zm10cDoxMDcgbGV2ZWwtYXN5bW1ldHJ5LWFsbG93ZWQ9MTtwYWNrZXRpemF0aW9uLW1vZGU9MTtwcm9maWxlLWxldmVsLWlkPTQyMDAxZlxcclxcblwiXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4ganNlcDtcbiAgfVxuXG4gIGFzeW5jIGZpeFNhZmFyaUljZVVGcmFnKGpzZXApIHtcbiAgICAvLyBTYWZhcmkgcHJvZHVjZXMgYSBcXG4gaW5zdGVhZCBvZiBhbiBcXHJcXG4gZm9yIHRoZSBpY2UtdWZyYWcuIFNlZSBodHRwczovL2dpdGh1Yi5jb20vbWVldGVjaG8vamFudXMtZ2F0ZXdheS9pc3N1ZXMvMTgxOFxuICAgIGpzZXAuc2RwID0ganNlcC5zZHAucmVwbGFjZSgvW15cXHJdXFxuYT1pY2UtdWZyYWcvZywgXCJcXHJcXG5hPWljZS11ZnJhZ1wiKTtcbiAgICByZXR1cm4ganNlcFxuICB9XG5cbiAgYXN5bmMgY3JlYXRlU3Vic2NyaWJlcihvY2N1cGFudElkLCBtYXhSZXRyaWVzID0gNSkge1xuICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogY2FuY2VsbGVkIG9jY3VwYW50IGNvbm5lY3Rpb24sIG9jY3VwYW50IGxlZnQgYmVmb3JlIHN1YnNjcmlwdGlvbiBuZWdvdGF0aW9uLlwiKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHZhciBoYW5kbGUgPSBuZXcgbWouSmFudXNQbHVnaW5IYW5kbGUodGhpcy5zZXNzaW9uKTtcbiAgICB2YXIgY29ubiA9IG5ldyBSVENQZWVyQ29ubmVjdGlvbih0aGlzLnBlZXJDb25uZWN0aW9uQ29uZmlnIHx8IERFRkFVTFRfUEVFUl9DT05ORUNUSU9OX0NPTkZJRyk7XG5cbiAgICBkZWJ1ZyhvY2N1cGFudElkICsgXCI6IHN1YiB3YWl0aW5nIGZvciBzZnVcIik7XG4gICAgYXdhaXQgaGFuZGxlLmF0dGFjaChcImphbnVzLnBsdWdpbi5zZnVcIiwgdGhpcy5sb29wcyA/IHBhcnNlSW50KG9jY3VwYW50SWQpICUgdGhpcy5sb29wcyA6IHVuZGVmaW5lZCk7XG5cbiAgICB0aGlzLmFzc29jaWF0ZShjb25uLCBoYW5kbGUpO1xuXG4gICAgZGVidWcob2NjdXBhbnRJZCArIFwiOiBzdWIgd2FpdGluZyBmb3Igam9pblwiKTtcblxuICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgY29ubi5jbG9zZSgpO1xuICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogY2FuY2VsbGVkIG9jY3VwYW50IGNvbm5lY3Rpb24sIG9jY3VwYW50IGxlZnQgYWZ0ZXIgYXR0YWNoXCIpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgbGV0IHdlYnJ0Y0ZhaWxlZCA9IGZhbHNlO1xuXG4gICAgY29uc3Qgd2VicnRjdXAgPSBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHtcbiAgICAgIGNvbnN0IGxlZnRJbnRlcnZhbCA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgICAgaWYgKHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmluZGV4T2Yob2NjdXBhbnRJZCkgPT09IC0xKSB7XG4gICAgICAgICAgY2xlYXJJbnRlcnZhbChsZWZ0SW50ZXJ2YWwpO1xuICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgfSwgMTAwMCk7XG5cbiAgICAgIGNvbnN0IHRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgY2xlYXJJbnRlcnZhbChsZWZ0SW50ZXJ2YWwpO1xuICAgICAgICB3ZWJydGNGYWlsZWQgPSB0cnVlO1xuICAgICAgICByZXNvbHZlKCk7XG4gICAgICB9LCBTVUJTQ1JJQkVfVElNRU9VVF9NUyk7XG5cbiAgICAgIGhhbmRsZS5vbihcIndlYnJ0Y3VwXCIsICgpID0+IHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICBjbGVhckludGVydmFsKGxlZnRJbnRlcnZhbCk7XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgLy8gU2VuZCBqb2luIG1lc3NhZ2UgdG8gamFudXMuIERvbid0IGxpc3RlbiBmb3Igam9pbi9sZWF2ZSBtZXNzYWdlcy4gU3Vic2NyaWJlIHRvIHRoZSBvY2N1cGFudCdzIG1lZGlhLlxuICAgIC8vIEphbnVzIHNob3VsZCBzZW5kIHVzIGFuIG9mZmVyIGZvciB0aGlzIG9jY3VwYW50J3MgbWVkaWEgaW4gcmVzcG9uc2UgdG8gdGhpcy5cbiAgICBhd2FpdCB0aGlzLnNlbmRKb2luKGhhbmRsZSwgeyBtZWRpYTogb2NjdXBhbnRJZCB9KTtcblxuICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgY29ubi5jbG9zZSgpO1xuICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogY2FuY2VsbGVkIG9jY3VwYW50IGNvbm5lY3Rpb24sIG9jY3VwYW50IGxlZnQgYWZ0ZXIgam9pblwiKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGRlYnVnKG9jY3VwYW50SWQgKyBcIjogc3ViIHdhaXRpbmcgZm9yIHdlYnJ0Y3VwXCIpO1xuICAgIGF3YWl0IHdlYnJ0Y3VwO1xuXG4gICAgaWYgKHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmluZGV4T2Yob2NjdXBhbnRJZCkgPT09IC0xKSB7XG4gICAgICBjb25uLmNsb3NlKCk7XG4gICAgICBjb25zb2xlLndhcm4ob2NjdXBhbnRJZCArIFwiOiBjYW5jZWwgb2NjdXBhbnQgY29ubmVjdGlvbiwgb2NjdXBhbnQgbGVmdCBkdXJpbmcgb3IgYWZ0ZXIgd2VicnRjdXBcIik7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAod2VicnRjRmFpbGVkKSB7XG4gICAgICBjb25uLmNsb3NlKCk7XG4gICAgICBpZiAobWF4UmV0cmllcyA+IDApIHtcbiAgICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogd2VicnRjIHVwIHRpbWVkIG91dCwgcmV0cnlpbmdcIik7XG4gICAgICAgIHJldHVybiB0aGlzLmNyZWF0ZVN1YnNjcmliZXIob2NjdXBhbnRJZCwgbWF4UmV0cmllcyAtIDEpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogd2VicnRjIHVwIHRpbWVkIG91dFwiKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGlzU2FmYXJpICYmICF0aGlzLl9pT1NIYWNrRGVsYXllZEluaXRpYWxQZWVyKSB7XG4gICAgICAvLyBIQUNLOiB0aGUgZmlyc3QgcGVlciBvbiBTYWZhcmkgZHVyaW5nIHBhZ2UgbG9hZCBjYW4gZmFpbCB0byB3b3JrIGlmIHdlIGRvbid0XG4gICAgICAvLyB3YWl0IHNvbWUgdGltZSBiZWZvcmUgY29udGludWluZyBoZXJlLiBTZWU6IGh0dHBzOi8vZ2l0aHViLmNvbS9tb3ppbGxhL2h1YnMvcHVsbC8xNjkyXG4gICAgICBhd2FpdCAobmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgMzAwMCkpKTtcbiAgICAgIHRoaXMuX2lPU0hhY2tEZWxheWVkSW5pdGlhbFBlZXIgPSB0cnVlO1xuICAgIH1cblxuICAgIHZhciBtZWRpYVN0cmVhbSA9IG5ldyBNZWRpYVN0cmVhbSgpO1xuICAgIHZhciByZWNlaXZlcnMgPSBjb25uLmdldFJlY2VpdmVycygpO1xuICAgIHJlY2VpdmVycy5mb3JFYWNoKHJlY2VpdmVyID0+IHtcbiAgICAgIGlmIChyZWNlaXZlci50cmFjaykge1xuICAgICAgICBtZWRpYVN0cmVhbS5hZGRUcmFjayhyZWNlaXZlci50cmFjayk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgaWYgKG1lZGlhU3RyZWFtLmdldFRyYWNrcygpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgbWVkaWFTdHJlYW0gPSBudWxsO1xuICAgIH1cblxuICAgIGRlYnVnKG9jY3VwYW50SWQgKyBcIjogc3Vic2NyaWJlciByZWFkeVwiKTtcbiAgICByZXR1cm4ge1xuICAgICAgaGFuZGxlLFxuICAgICAgbWVkaWFTdHJlYW0sXG4gICAgICBjb25uXG4gICAgfTtcbiAgfVxuXG4gIHNlbmRKb2luKGhhbmRsZSwgc3Vic2NyaWJlKSB7XG4gICAgcmV0dXJuIGhhbmRsZS5zZW5kTWVzc2FnZSh7XG4gICAgICBraW5kOiBcImpvaW5cIixcbiAgICAgIHJvb21faWQ6IHRoaXMucm9vbSxcbiAgICAgIHVzZXJfaWQ6IHRoaXMuY2xpZW50SWQsXG4gICAgICBzdWJzY3JpYmUsXG4gICAgICB0b2tlbjogdGhpcy5qb2luVG9rZW5cbiAgICB9KTtcbiAgfVxuXG4gIHRvZ2dsZUZyZWV6ZSgpIHtcbiAgICBpZiAodGhpcy5mcm96ZW4pIHtcbiAgICAgIHRoaXMudW5mcmVlemUoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5mcmVlemUoKTtcbiAgICB9XG4gIH1cblxuICBmcmVlemUoKSB7XG4gICAgdGhpcy5mcm96ZW4gPSB0cnVlO1xuICB9XG5cbiAgdW5mcmVlemUoKSB7XG4gICAgdGhpcy5mcm96ZW4gPSBmYWxzZTtcbiAgICB0aGlzLmZsdXNoUGVuZGluZ1VwZGF0ZXMoKTtcbiAgfVxuXG4gIGRhdGFGb3JVcGRhdGVNdWx0aU1lc3NhZ2UobmV0d29ya0lkLCBtZXNzYWdlKSB7XG4gICAgLy8gXCJkXCIgaXMgYW4gYXJyYXkgb2YgZW50aXR5IGRhdGFzLCB3aGVyZSBlYWNoIGl0ZW0gaW4gdGhlIGFycmF5IHJlcHJlc2VudHMgYSB1bmlxdWUgZW50aXR5IGFuZCBjb250YWluc1xuICAgIC8vIG1ldGFkYXRhIGZvciB0aGUgZW50aXR5LCBhbmQgYW4gYXJyYXkgb2YgY29tcG9uZW50cyB0aGF0IGhhdmUgYmVlbiB1cGRhdGVkIG9uIHRoZSBlbnRpdHkuXG4gICAgLy8gVGhpcyBtZXRob2QgZmluZHMgdGhlIGRhdGEgY29ycmVzcG9uZGluZyB0byB0aGUgZ2l2ZW4gbmV0d29ya0lkLlxuICAgIGZvciAobGV0IGkgPSAwLCBsID0gbWVzc2FnZS5kYXRhLmQubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICBjb25zdCBkYXRhID0gbWVzc2FnZS5kYXRhLmRbaV07XG5cbiAgICAgIGlmIChkYXRhLm5ldHdvcmtJZCA9PT0gbmV0d29ya0lkKSB7XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgZ2V0UGVuZGluZ0RhdGEobmV0d29ya0lkLCBtZXNzYWdlKSB7XG4gICAgaWYgKCFtZXNzYWdlKSByZXR1cm4gbnVsbDtcblxuICAgIGxldCBkYXRhID0gbWVzc2FnZS5kYXRhVHlwZSA9PT0gXCJ1bVwiID8gdGhpcy5kYXRhRm9yVXBkYXRlTXVsdGlNZXNzYWdlKG5ldHdvcmtJZCwgbWVzc2FnZSkgOiBtZXNzYWdlLmRhdGE7XG5cbiAgICAvLyBJZ25vcmUgbWVzc2FnZXMgcmVsYXRpbmcgdG8gdXNlcnMgd2hvIGhhdmUgZGlzY29ubmVjdGVkIHNpbmNlIGZyZWV6aW5nLCB0aGVpciBlbnRpdGllc1xuICAgIC8vIHdpbGwgaGF2ZSBhbGVhZHkgYmVlbiByZW1vdmVkIGJ5IE5BRi5cbiAgICAvLyBOb3RlIHRoYXQgZGVsZXRlIG1lc3NhZ2VzIGhhdmUgbm8gXCJvd25lclwiIHNvIHdlIGhhdmUgdG8gY2hlY2sgZm9yIHRoYXQgYXMgd2VsbC5cbiAgICBpZiAoZGF0YS5vd25lciAmJiAhdGhpcy5vY2N1cGFudHNbZGF0YS5vd25lcl0pIHJldHVybiBudWxsO1xuXG4gICAgLy8gSWdub3JlIG1lc3NhZ2VzIGZyb20gdXNlcnMgdGhhdCB3ZSBtYXkgaGF2ZSBibG9ja2VkIHdoaWxlIGZyb3plbi5cbiAgICBpZiAoZGF0YS5vd25lciAmJiB0aGlzLmJsb2NrZWRDbGllbnRzLmhhcyhkYXRhLm93bmVyKSkgcmV0dXJuIG51bGw7XG5cbiAgICByZXR1cm4gZGF0YVxuICB9XG5cbiAgLy8gVXNlZCBleHRlcm5hbGx5XG4gIGdldFBlbmRpbmdEYXRhRm9yTmV0d29ya0lkKG5ldHdvcmtJZCkge1xuICAgIHJldHVybiB0aGlzLmdldFBlbmRpbmdEYXRhKG5ldHdvcmtJZCwgdGhpcy5mcm96ZW5VcGRhdGVzLmdldChuZXR3b3JrSWQpKTtcbiAgfVxuXG4gIGZsdXNoUGVuZGluZ1VwZGF0ZXMoKSB7XG4gICAgZm9yIChjb25zdCBbbmV0d29ya0lkLCBtZXNzYWdlXSBvZiB0aGlzLmZyb3plblVwZGF0ZXMpIHtcbiAgICAgIGxldCBkYXRhID0gdGhpcy5nZXRQZW5kaW5nRGF0YShuZXR3b3JrSWQsIG1lc3NhZ2UpO1xuICAgICAgaWYgKCFkYXRhKSBjb250aW51ZTtcblxuICAgICAgLy8gT3ZlcnJpZGUgdGhlIGRhdGEgdHlwZSBvbiBcInVtXCIgbWVzc2FnZXMgdHlwZXMsIHNpbmNlIHdlIGV4dHJhY3QgZW50aXR5IHVwZGF0ZXMgZnJvbSBcInVtXCIgbWVzc2FnZXMgaW50b1xuICAgICAgLy8gaW5kaXZpZHVhbCBmcm96ZW5VcGRhdGVzIGluIHN0b3JlU2luZ2xlTWVzc2FnZS5cbiAgICAgIGNvbnN0IGRhdGFUeXBlID0gbWVzc2FnZS5kYXRhVHlwZSA9PT0gXCJ1bVwiID8gXCJ1XCIgOiBtZXNzYWdlLmRhdGFUeXBlO1xuXG4gICAgICB0aGlzLm9uT2NjdXBhbnRNZXNzYWdlKG51bGwsIGRhdGFUeXBlLCBkYXRhLCBtZXNzYWdlLnNvdXJjZSk7XG4gICAgfVxuICAgIHRoaXMuZnJvemVuVXBkYXRlcy5jbGVhcigpO1xuICB9XG5cbiAgc3RvcmVNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgICBpZiAobWVzc2FnZS5kYXRhVHlwZSA9PT0gXCJ1bVwiKSB7IC8vIFVwZGF0ZU11bHRpXG4gICAgICBmb3IgKGxldCBpID0gMCwgbCA9IG1lc3NhZ2UuZGF0YS5kLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICB0aGlzLnN0b3JlU2luZ2xlTWVzc2FnZShtZXNzYWdlLCBpKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zdG9yZVNpbmdsZU1lc3NhZ2UobWVzc2FnZSk7XG4gICAgfVxuICB9XG5cbiAgc3RvcmVTaW5nbGVNZXNzYWdlKG1lc3NhZ2UsIGluZGV4KSB7XG4gICAgY29uc3QgZGF0YSA9IGluZGV4ICE9PSB1bmRlZmluZWQgPyBtZXNzYWdlLmRhdGEuZFtpbmRleF0gOiBtZXNzYWdlLmRhdGE7XG4gICAgY29uc3QgZGF0YVR5cGUgPSBtZXNzYWdlLmRhdGFUeXBlO1xuICAgIGNvbnN0IHNvdXJjZSA9IG1lc3NhZ2Uuc291cmNlO1xuXG4gICAgY29uc3QgbmV0d29ya0lkID0gZGF0YS5uZXR3b3JrSWQ7XG5cbiAgICBpZiAoIXRoaXMuZnJvemVuVXBkYXRlcy5oYXMobmV0d29ya0lkKSkge1xuICAgICAgdGhpcy5mcm96ZW5VcGRhdGVzLnNldChuZXR3b3JrSWQsIG1lc3NhZ2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBzdG9yZWRNZXNzYWdlID0gdGhpcy5mcm96ZW5VcGRhdGVzLmdldChuZXR3b3JrSWQpO1xuICAgICAgY29uc3Qgc3RvcmVkRGF0YSA9IHN0b3JlZE1lc3NhZ2UuZGF0YVR5cGUgPT09IFwidW1cIiA/IHRoaXMuZGF0YUZvclVwZGF0ZU11bHRpTWVzc2FnZShuZXR3b3JrSWQsIHN0b3JlZE1lc3NhZ2UpIDogc3RvcmVkTWVzc2FnZS5kYXRhO1xuXG4gICAgICAvLyBBdm9pZCB1cGRhdGluZyBjb21wb25lbnRzIGlmIHRoZSBlbnRpdHkgZGF0YSByZWNlaXZlZCBkaWQgbm90IGNvbWUgZnJvbSB0aGUgY3VycmVudCBvd25lci5cbiAgICAgIGNvbnN0IGlzT3V0ZGF0ZWRNZXNzYWdlID0gZGF0YS5sYXN0T3duZXJUaW1lIDwgc3RvcmVkRGF0YS5sYXN0T3duZXJUaW1lO1xuICAgICAgY29uc3QgaXNDb250ZW1wb3JhbmVvdXNNZXNzYWdlID0gZGF0YS5sYXN0T3duZXJUaW1lID09PSBzdG9yZWREYXRhLmxhc3RPd25lclRpbWU7XG4gICAgICBpZiAoaXNPdXRkYXRlZE1lc3NhZ2UgfHwgKGlzQ29udGVtcG9yYW5lb3VzTWVzc2FnZSAmJiBzdG9yZWREYXRhLm93bmVyID4gZGF0YS5vd25lcikpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZGF0YVR5cGUgPT09IFwiclwiKSB7XG4gICAgICAgIGNvbnN0IGNyZWF0ZWRXaGlsZUZyb3plbiA9IHN0b3JlZERhdGEgJiYgc3RvcmVkRGF0YS5pc0ZpcnN0U3luYztcbiAgICAgICAgaWYgKGNyZWF0ZWRXaGlsZUZyb3plbikge1xuICAgICAgICAgIC8vIElmIHRoZSBlbnRpdHkgd2FzIGNyZWF0ZWQgYW5kIGRlbGV0ZWQgd2hpbGUgZnJvemVuLCBkb24ndCBib3RoZXIgY29udmV5aW5nIGFueXRoaW5nIHRvIHRoZSBjb25zdW1lci5cbiAgICAgICAgICB0aGlzLmZyb3plblVwZGF0ZXMuZGVsZXRlKG5ldHdvcmtJZCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gRGVsZXRlIG1lc3NhZ2VzIG92ZXJyaWRlIGFueSBvdGhlciBtZXNzYWdlcyBmb3IgdGhpcyBlbnRpdHlcbiAgICAgICAgICB0aGlzLmZyb3plblVwZGF0ZXMuc2V0KG5ldHdvcmtJZCwgbWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIG1lcmdlIGluIGNvbXBvbmVudCB1cGRhdGVzXG4gICAgICAgIGlmIChzdG9yZWREYXRhLmNvbXBvbmVudHMgJiYgZGF0YS5jb21wb25lbnRzKSB7XG4gICAgICAgICAgT2JqZWN0LmFzc2lnbihzdG9yZWREYXRhLmNvbXBvbmVudHMsIGRhdGEuY29tcG9uZW50cyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBvbkRhdGFDaGFubmVsTWVzc2FnZShlLCBzb3VyY2UpIHtcbiAgICB0aGlzLm9uRGF0YShKU09OLnBhcnNlKGUuZGF0YSksIHNvdXJjZSk7XG4gIH1cblxuICBvbkRhdGEobWVzc2FnZSwgc291cmNlKSB7XG4gICAgaWYgKGRlYnVnLmVuYWJsZWQpIHtcbiAgICAgIGRlYnVnKGBEQyBpbjogJHttZXNzYWdlfWApO1xuICAgIH1cblxuICAgIGlmICghbWVzc2FnZS5kYXRhVHlwZSkgcmV0dXJuO1xuXG4gICAgbWVzc2FnZS5zb3VyY2UgPSBzb3VyY2U7XG5cbiAgICBpZiAodGhpcy5mcm96ZW4pIHtcbiAgICAgIHRoaXMuc3RvcmVNZXNzYWdlKG1lc3NhZ2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLm9uT2NjdXBhbnRNZXNzYWdlKG51bGwsIG1lc3NhZ2UuZGF0YVR5cGUsIG1lc3NhZ2UuZGF0YSwgbWVzc2FnZS5zb3VyY2UpO1xuICAgIH1cbiAgfVxuXG4gIHNob3VsZFN0YXJ0Q29ubmVjdGlvblRvKGNsaWVudCkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgc3RhcnRTdHJlYW1Db25uZWN0aW9uKGNsaWVudCkge31cblxuICBjbG9zZVN0cmVhbUNvbm5lY3Rpb24oY2xpZW50KSB7fVxuXG4gIGdldENvbm5lY3RTdGF0dXMoY2xpZW50SWQpIHtcbiAgICByZXR1cm4gdGhpcy5vY2N1cGFudHNbY2xpZW50SWRdID8gTkFGLmFkYXB0ZXJzLklTX0NPTk5FQ1RFRCA6IE5BRi5hZGFwdGVycy5OT1RfQ09OTkVDVEVEO1xuICB9XG5cbiAgYXN5bmMgdXBkYXRlVGltZU9mZnNldCgpIHtcbiAgICBpZiAodGhpcy5pc0Rpc2Nvbm5lY3RlZCgpKSByZXR1cm47XG5cbiAgICBjb25zdCBjbGllbnRTZW50VGltZSA9IERhdGUubm93KCk7XG5cbiAgICBjb25zdCByZXMgPSBhd2FpdCBmZXRjaChkb2N1bWVudC5sb2NhdGlvbi5ocmVmLCB7XG4gICAgICBtZXRob2Q6IFwiSEVBRFwiLFxuICAgICAgY2FjaGU6IFwibm8tY2FjaGVcIlxuICAgIH0pO1xuXG4gICAgY29uc3QgcHJlY2lzaW9uID0gMTAwMDtcbiAgICBjb25zdCBzZXJ2ZXJSZWNlaXZlZFRpbWUgPSBuZXcgRGF0ZShyZXMuaGVhZGVycy5nZXQoXCJEYXRlXCIpKS5nZXRUaW1lKCkgKyBwcmVjaXNpb24gLyAyO1xuICAgIGNvbnN0IGNsaWVudFJlY2VpdmVkVGltZSA9IERhdGUubm93KCk7XG4gICAgY29uc3Qgc2VydmVyVGltZSA9IHNlcnZlclJlY2VpdmVkVGltZSArIChjbGllbnRSZWNlaXZlZFRpbWUgLSBjbGllbnRTZW50VGltZSkgLyAyO1xuICAgIGNvbnN0IHRpbWVPZmZzZXQgPSBzZXJ2ZXJUaW1lIC0gY2xpZW50UmVjZWl2ZWRUaW1lO1xuXG4gICAgdGhpcy5zZXJ2ZXJUaW1lUmVxdWVzdHMrKztcblxuICAgIGlmICh0aGlzLnNlcnZlclRpbWVSZXF1ZXN0cyA8PSAxMCkge1xuICAgICAgdGhpcy50aW1lT2Zmc2V0cy5wdXNoKHRpbWVPZmZzZXQpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnRpbWVPZmZzZXRzW3RoaXMuc2VydmVyVGltZVJlcXVlc3RzICUgMTBdID0gdGltZU9mZnNldDtcbiAgICB9XG5cbiAgICB0aGlzLmF2Z1RpbWVPZmZzZXQgPSB0aGlzLnRpbWVPZmZzZXRzLnJlZHVjZSgoYWNjLCBvZmZzZXQpID0+IChhY2MgKz0gb2Zmc2V0KSwgMCkgLyB0aGlzLnRpbWVPZmZzZXRzLmxlbmd0aDtcblxuICAgIGlmICh0aGlzLnNlcnZlclRpbWVSZXF1ZXN0cyA+IDEwKSB7XG4gICAgICBkZWJ1ZyhgbmV3IHNlcnZlciB0aW1lIG9mZnNldDogJHt0aGlzLmF2Z1RpbWVPZmZzZXR9bXNgKTtcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy51cGRhdGVUaW1lT2Zmc2V0KCksIDUgKiA2MCAqIDEwMDApOyAvLyBTeW5jIGNsb2NrIGV2ZXJ5IDUgbWludXRlcy5cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy51cGRhdGVUaW1lT2Zmc2V0KCk7XG4gICAgfVxuICB9XG5cbiAgZ2V0U2VydmVyVGltZSgpIHtcbiAgICByZXR1cm4gRGF0ZS5ub3coKSArIHRoaXMuYXZnVGltZU9mZnNldDtcbiAgfVxuXG4gIGdldE1lZGlhU3RyZWFtKGNsaWVudElkLCB0eXBlID0gXCJhdWRpb1wiKSB7XG4gICAgaWYgKHRoaXMubWVkaWFTdHJlYW1zW2NsaWVudElkXSkge1xuICAgICAgZGVidWcoYEFscmVhZHkgaGFkICR7dHlwZX0gZm9yICR7Y2xpZW50SWR9YCk7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRoaXMubWVkaWFTdHJlYW1zW2NsaWVudElkXVt0eXBlXSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRlYnVnKGBXYWl0aW5nIG9uICR7dHlwZX0gZm9yICR7Y2xpZW50SWR9YCk7XG4gICAgICBpZiAoIXRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuaGFzKGNsaWVudElkKSkge1xuICAgICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLnNldChjbGllbnRJZCwge30pO1xuXG4gICAgICAgIGNvbnN0IGF1ZGlvUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChjbGllbnRJZCkuYXVkaW8gPSB7IHJlc29sdmUsIHJlamVjdCB9O1xuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgdmlkZW9Qcm9taXNlID0gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KGNsaWVudElkKS52aWRlbyA9IHsgcmVzb2x2ZSwgcmVqZWN0IH07XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KGNsaWVudElkKS5hdWRpby5wcm9taXNlID0gYXVkaW9Qcm9taXNlO1xuICAgICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChjbGllbnRJZCkudmlkZW8ucHJvbWlzZSA9IHZpZGVvUHJvbWlzZTtcblxuICAgICAgICBhdWRpb1Byb21pc2UuY2F0Y2goZSA9PiBjb25zb2xlLndhcm4oYCR7Y2xpZW50SWR9IGdldE1lZGlhU3RyZWFtIEF1ZGlvIEVycm9yYCwgZSkpO1xuICAgICAgICB2aWRlb1Byb21pc2UuY2F0Y2goZSA9PiBjb25zb2xlLndhcm4oYCR7Y2xpZW50SWR9IGdldE1lZGlhU3RyZWFtIFZpZGVvIEVycm9yYCwgZSkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KGNsaWVudElkKVt0eXBlXS5wcm9taXNlO1xuICAgIH1cbiAgfVxuXG4gIHNldE1lZGlhU3RyZWFtKGNsaWVudElkLCBzdHJlYW0pIHtcbiAgICAvLyBTYWZhcmkgZG9lc24ndCBsaWtlIGl0IHdoZW4geW91IHVzZSBzaW5nbGUgYSBtaXhlZCBtZWRpYSBzdHJlYW0gd2hlcmUgb25lIG9mIHRoZSB0cmFja3MgaXMgaW5hY3RpdmUsIHNvIHdlXG4gICAgLy8gc3BsaXQgdGhlIHRyYWNrcyBpbnRvIHR3byBzdHJlYW1zLlxuICAgIGNvbnN0IGF1ZGlvU3RyZWFtID0gbmV3IE1lZGlhU3RyZWFtKCk7XG4gICAgdHJ5IHtcbiAgICBzdHJlYW0uZ2V0QXVkaW9UcmFja3MoKS5mb3JFYWNoKHRyYWNrID0+IGF1ZGlvU3RyZWFtLmFkZFRyYWNrKHRyYWNrKSk7XG5cbiAgICB9IGNhdGNoKGUpIHtcbiAgICAgIGNvbnNvbGUud2FybihgJHtjbGllbnRJZH0gc2V0TWVkaWFTdHJlYW0gQXVkaW8gRXJyb3JgLCBlKTtcbiAgICB9XG4gICAgY29uc3QgdmlkZW9TdHJlYW0gPSBuZXcgTWVkaWFTdHJlYW0oKTtcbiAgICB0cnkge1xuICAgIHN0cmVhbS5nZXRWaWRlb1RyYWNrcygpLmZvckVhY2godHJhY2sgPT4gdmlkZW9TdHJlYW0uYWRkVHJhY2sodHJhY2spKTtcblxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnNvbGUud2FybihgJHtjbGllbnRJZH0gc2V0TWVkaWFTdHJlYW0gVmlkZW8gRXJyb3JgLCBlKTtcbiAgICB9XG5cbiAgICB0aGlzLm1lZGlhU3RyZWFtc1tjbGllbnRJZF0gPSB7IGF1ZGlvOiBhdWRpb1N0cmVhbSwgdmlkZW86IHZpZGVvU3RyZWFtIH07XG5cbiAgICAvLyBSZXNvbHZlIHRoZSBwcm9taXNlIGZvciB0aGUgdXNlcidzIG1lZGlhIHN0cmVhbSBpZiBpdCBleGlzdHMuXG4gICAgaWYgKHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuaGFzKGNsaWVudElkKSkge1xuICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5nZXQoY2xpZW50SWQpLmF1ZGlvLnJlc29sdmUoYXVkaW9TdHJlYW0pO1xuICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5nZXQoY2xpZW50SWQpLnZpZGVvLnJlc29sdmUodmlkZW9TdHJlYW0pO1xuICAgIH1cbiAgfVxuXG4gIGdldExvY2FsTWVkaWFTdHJlYW0oKSB7XG4gICAgcmV0dXJuIHRoaXMubG9jYWxNZWRpYVN0cmVhbTtcbiAgfVxuXG4gIGFzeW5jIHNldExvY2FsTWVkaWFTdHJlYW0oc3RyZWFtKSB7XG4gICAgLy8gb3VyIGpvYiBoZXJlIGlzIHRvIG1ha2Ugc3VyZSB0aGUgY29ubmVjdGlvbiB3aW5kcyB1cCB3aXRoIFJUUCBzZW5kZXJzIHNlbmRpbmcgdGhlIHN0dWZmIGluIHRoaXMgc3RyZWFtLFxuICAgIC8vIGFuZCBub3QgdGhlIHN0dWZmIHRoYXQgaXNuJ3QgaW4gdGhpcyBzdHJlYW0uIHN0cmF0ZWd5IGlzIHRvIHJlcGxhY2UgZXhpc3RpbmcgdHJhY2tzIGlmIHdlIGNhbiwgYWRkIHRyYWNrc1xuICAgIC8vIHRoYXQgd2UgY2FuJ3QgcmVwbGFjZSwgYW5kIGRpc2FibGUgdHJhY2tzIHRoYXQgZG9uJ3QgZXhpc3QgYW55bW9yZS5cblxuICAgIC8vIG5vdGUgdGhhdCB3ZSBkb24ndCBldmVyIHJlbW92ZSBhIHRyYWNrIGZyb20gdGhlIHN0cmVhbSAtLSBzaW5jZSBKYW51cyBkb2Vzbid0IHN1cHBvcnQgVW5pZmllZCBQbGFuLCB3ZSBhYnNvbHV0ZWx5XG4gICAgLy8gY2FuJ3Qgd2luZCB1cCB3aXRoIGEgU0RQIHRoYXQgaGFzID4xIGF1ZGlvIG9yID4xIHZpZGVvIHRyYWNrcywgZXZlbiBpZiBvbmUgb2YgdGhlbSBpcyBpbmFjdGl2ZSAod2hhdCB5b3UgZ2V0IGlmXG4gICAgLy8geW91IHJlbW92ZSBhIHRyYWNrIGZyb20gYW4gZXhpc3Rpbmcgc3RyZWFtLilcbiAgICBpZiAodGhpcy5wdWJsaXNoZXIgJiYgdGhpcy5wdWJsaXNoZXIuY29ubikge1xuICAgICAgY29uc3QgZXhpc3RpbmdTZW5kZXJzID0gdGhpcy5wdWJsaXNoZXIuY29ubi5nZXRTZW5kZXJzKCk7XG4gICAgICBjb25zdCBuZXdTZW5kZXJzID0gW107XG4gICAgICBjb25zdCB0cmFja3MgPSBzdHJlYW0uZ2V0VHJhY2tzKCk7XG5cbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdHJhY2tzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IHQgPSB0cmFja3NbaV07XG4gICAgICAgIGNvbnN0IHNlbmRlciA9IGV4aXN0aW5nU2VuZGVycy5maW5kKHMgPT4gcy50cmFjayAhPSBudWxsICYmIHMudHJhY2sua2luZCA9PSB0LmtpbmQpO1xuXG4gICAgICAgIGlmIChzZW5kZXIgIT0gbnVsbCkge1xuICAgICAgICAgIGlmIChzZW5kZXIucmVwbGFjZVRyYWNrKSB7XG4gICAgICAgICAgICBhd2FpdCBzZW5kZXIucmVwbGFjZVRyYWNrKHQpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBGYWxsYmFjayBmb3IgYnJvd3NlcnMgdGhhdCBkb24ndCBzdXBwb3J0IHJlcGxhY2VUcmFjay4gQXQgdGhpcyB0aW1lIG9mIHRoaXMgd3JpdGluZ1xuICAgICAgICAgICAgLy8gbW9zdCBicm93c2VycyBzdXBwb3J0IGl0LCBhbmQgdGVzdGluZyB0aGlzIGNvZGUgcGF0aCBzZWVtcyB0byBub3Qgd29yayBwcm9wZXJseVxuICAgICAgICAgICAgLy8gaW4gQ2hyb21lIGFueW1vcmUuXG4gICAgICAgICAgICBzdHJlYW0ucmVtb3ZlVHJhY2soc2VuZGVyLnRyYWNrKTtcbiAgICAgICAgICAgIHN0cmVhbS5hZGRUcmFjayh0KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgbmV3U2VuZGVycy5wdXNoKHNlbmRlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbmV3U2VuZGVycy5wdXNoKHRoaXMucHVibGlzaGVyLmNvbm4uYWRkVHJhY2sodCwgc3RyZWFtKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGV4aXN0aW5nU2VuZGVycy5mb3JFYWNoKHMgPT4ge1xuICAgICAgICBpZiAoIW5ld1NlbmRlcnMuaW5jbHVkZXMocykpIHtcbiAgICAgICAgICBzLnRyYWNrLmVuYWJsZWQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICAgIHRoaXMubG9jYWxNZWRpYVN0cmVhbSA9IHN0cmVhbTtcbiAgICB0aGlzLnNldE1lZGlhU3RyZWFtKHRoaXMuY2xpZW50SWQsIHN0cmVhbSk7XG4gIH1cblxuICBlbmFibGVNaWNyb3Bob25lKGVuYWJsZWQpIHtcbiAgICBpZiAodGhpcy5wdWJsaXNoZXIgJiYgdGhpcy5wdWJsaXNoZXIuY29ubikge1xuICAgICAgdGhpcy5wdWJsaXNoZXIuY29ubi5nZXRTZW5kZXJzKCkuZm9yRWFjaChzID0+IHtcbiAgICAgICAgaWYgKHMudHJhY2sua2luZCA9PSBcImF1ZGlvXCIpIHtcbiAgICAgICAgICBzLnRyYWNrLmVuYWJsZWQgPSBlbmFibGVkO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBzZW5kRGF0YShjbGllbnRJZCwgZGF0YVR5cGUsIGRhdGEpIHtcbiAgICBpZiAoIXRoaXMucHVibGlzaGVyKSB7XG4gICAgICBjb25zb2xlLndhcm4oXCJzZW5kRGF0YSBjYWxsZWQgd2l0aG91dCBhIHB1Ymxpc2hlclwiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3dpdGNoICh0aGlzLnVucmVsaWFibGVUcmFuc3BvcnQpIHtcbiAgICAgICAgY2FzZSBcIndlYnNvY2tldFwiOlxuICAgICAgICAgIGlmICh0aGlzLndzLnJlYWR5U3RhdGUgPT09IDEpIHsgLy8gT1BFTlxuICAgICAgICAgICAgdGhpcy5wdWJsaXNoZXIuaGFuZGxlLnNlbmRNZXNzYWdlKHsga2luZDogXCJkYXRhXCIsIGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgZGF0YVR5cGUsIGRhdGEgfSksIHdob206IGNsaWVudElkIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcImRhdGFjaGFubmVsXCI6XG4gICAgICAgICAgaWYgKHRoaXMucHVibGlzaGVyLnVucmVsaWFibGVDaGFubmVsLnJlYWR5U3RhdGUgPT09IFwib3BlblwiKSB7XG4gICAgICAgICAgICB0aGlzLnB1Ymxpc2hlci51bnJlbGlhYmxlQ2hhbm5lbC5zZW5kKEpTT04uc3RyaW5naWZ5KHsgY2xpZW50SWQsIGRhdGFUeXBlLCBkYXRhIH0pKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy51bnJlbGlhYmxlVHJhbnNwb3J0KGNsaWVudElkLCBkYXRhVHlwZSwgZGF0YSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgc2VuZERhdGFHdWFyYW50ZWVkKGNsaWVudElkLCBkYXRhVHlwZSwgZGF0YSkge1xuICAgIGlmICghdGhpcy5wdWJsaXNoZXIpIHtcbiAgICAgIGNvbnNvbGUud2FybihcInNlbmREYXRhR3VhcmFudGVlZCBjYWxsZWQgd2l0aG91dCBhIHB1Ymxpc2hlclwiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3dpdGNoICh0aGlzLnJlbGlhYmxlVHJhbnNwb3J0KSB7XG4gICAgICAgIGNhc2UgXCJ3ZWJzb2NrZXRcIjpcbiAgICAgICAgICBpZiAodGhpcy53cy5yZWFkeVN0YXRlID09PSAxKSB7IC8vIE9QRU5cbiAgICAgICAgICAgIHRoaXMucHVibGlzaGVyLmhhbmRsZS5zZW5kTWVzc2FnZSh7IGtpbmQ6IFwiZGF0YVwiLCBib2R5OiBKU09OLnN0cmluZ2lmeSh7IGRhdGFUeXBlLCBkYXRhIH0pLCB3aG9tOiBjbGllbnRJZCB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJkYXRhY2hhbm5lbFwiOlxuICAgICAgICAgIGlmICh0aGlzLnB1Ymxpc2hlci5yZWxpYWJsZUNoYW5uZWwucmVhZHlTdGF0ZSA9PT0gXCJvcGVuXCIpIHtcbiAgICAgICAgICAgIHRoaXMucHVibGlzaGVyLnJlbGlhYmxlQ2hhbm5lbC5zZW5kKEpTT04uc3RyaW5naWZ5KHsgY2xpZW50SWQsIGRhdGFUeXBlLCBkYXRhIH0pKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy5yZWxpYWJsZVRyYW5zcG9ydChjbGllbnRJZCwgZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGJyb2FkY2FzdERhdGEoZGF0YVR5cGUsIGRhdGEpIHtcbiAgICBpZiAoIXRoaXMucHVibGlzaGVyKSB7XG4gICAgICBjb25zb2xlLndhcm4oXCJicm9hZGNhc3REYXRhIGNhbGxlZCB3aXRob3V0IGEgcHVibGlzaGVyXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzd2l0Y2ggKHRoaXMudW5yZWxpYWJsZVRyYW5zcG9ydCkge1xuICAgICAgICBjYXNlIFwid2Vic29ja2V0XCI6XG4gICAgICAgICAgaWYgKHRoaXMud3MucmVhZHlTdGF0ZSA9PT0gMSkgeyAvLyBPUEVOXG4gICAgICAgICAgICB0aGlzLnB1Ymxpc2hlci5oYW5kbGUuc2VuZE1lc3NhZ2UoeyBraW5kOiBcImRhdGFcIiwgYm9keTogSlNPTi5zdHJpbmdpZnkoeyBkYXRhVHlwZSwgZGF0YSB9KSB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJkYXRhY2hhbm5lbFwiOlxuICAgICAgICAgIGlmICh0aGlzLnB1Ymxpc2hlci51bnJlbGlhYmxlQ2hhbm5lbC5yZWFkeVN0YXRlID09PSBcIm9wZW5cIikge1xuICAgICAgICAgICAgdGhpcy5wdWJsaXNoZXIudW5yZWxpYWJsZUNoYW5uZWwuc2VuZChKU09OLnN0cmluZ2lmeSh7IGRhdGFUeXBlLCBkYXRhIH0pKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy51bnJlbGlhYmxlVHJhbnNwb3J0KHVuZGVmaW5lZCwgZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGJyb2FkY2FzdERhdGFHdWFyYW50ZWVkKGRhdGFUeXBlLCBkYXRhKSB7XG4gICAgaWYgKCF0aGlzLnB1Ymxpc2hlcikge1xuICAgICAgY29uc29sZS53YXJuKFwiYnJvYWRjYXN0RGF0YUd1YXJhbnRlZWQgY2FsbGVkIHdpdGhvdXQgYSBwdWJsaXNoZXJcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXRjaCAodGhpcy5yZWxpYWJsZVRyYW5zcG9ydCkge1xuICAgICAgICBjYXNlIFwid2Vic29ja2V0XCI6XG4gICAgICAgICAgaWYgKHRoaXMud3MucmVhZHlTdGF0ZSA9PT0gMSkgeyAvLyBPUEVOXG4gICAgICAgICAgICB0aGlzLnB1Ymxpc2hlci5oYW5kbGUuc2VuZE1lc3NhZ2UoeyBraW5kOiBcImRhdGFcIiwgYm9keTogSlNPTi5zdHJpbmdpZnkoeyBkYXRhVHlwZSwgZGF0YSB9KSB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJkYXRhY2hhbm5lbFwiOlxuICAgICAgICAgIGlmICh0aGlzLnB1Ymxpc2hlci5yZWxpYWJsZUNoYW5uZWwucmVhZHlTdGF0ZSA9PT0gXCJvcGVuXCIpIHtcbiAgICAgICAgICAgIHRoaXMucHVibGlzaGVyLnJlbGlhYmxlQ2hhbm5lbC5zZW5kKEpTT04uc3RyaW5naWZ5KHsgZGF0YVR5cGUsIGRhdGEgfSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICB0aGlzLnJlbGlhYmxlVHJhbnNwb3J0KHVuZGVmaW5lZCwgZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGtpY2soY2xpZW50SWQsIHBlcm1zVG9rZW4pIHtcbiAgICByZXR1cm4gdGhpcy5wdWJsaXNoZXIuaGFuZGxlLnNlbmRNZXNzYWdlKHsga2luZDogXCJraWNrXCIsIHJvb21faWQ6IHRoaXMucm9vbSwgdXNlcl9pZDogY2xpZW50SWQsIHRva2VuOiBwZXJtc1Rva2VuIH0pLnRoZW4oKCkgPT4ge1xuICAgICAgZG9jdW1lbnQuYm9keS5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChcImtpY2tlZFwiLCB7IGRldGFpbDogeyBjbGllbnRJZDogY2xpZW50SWQgfSB9KSk7XG4gICAgfSk7XG4gIH1cblxuICBibG9jayhjbGllbnRJZCkge1xuICAgIHJldHVybiB0aGlzLnB1Ymxpc2hlci5oYW5kbGUuc2VuZE1lc3NhZ2UoeyBraW5kOiBcImJsb2NrXCIsIHdob206IGNsaWVudElkIH0pLnRoZW4oKCkgPT4ge1xuICAgICAgdGhpcy5ibG9ja2VkQ2xpZW50cy5zZXQoY2xpZW50SWQsIHRydWUpO1xuICAgICAgZG9jdW1lbnQuYm9keS5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChcImJsb2NrZWRcIiwgeyBkZXRhaWw6IHsgY2xpZW50SWQ6IGNsaWVudElkIH0gfSkpO1xuICAgIH0pO1xuICB9XG5cbiAgdW5ibG9jayhjbGllbnRJZCkge1xuICAgIHJldHVybiB0aGlzLnB1Ymxpc2hlci5oYW5kbGUuc2VuZE1lc3NhZ2UoeyBraW5kOiBcInVuYmxvY2tcIiwgd2hvbTogY2xpZW50SWQgfSkudGhlbigoKSA9PiB7XG4gICAgICB0aGlzLmJsb2NrZWRDbGllbnRzLmRlbGV0ZShjbGllbnRJZCk7XG4gICAgICBkb2N1bWVudC5ib2R5LmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KFwidW5ibG9ja2VkXCIsIHsgZGV0YWlsOiB7IGNsaWVudElkOiBjbGllbnRJZCB9IH0pKTtcbiAgICB9KTtcbiAgfVxufVxuXG5OQUYuYWRhcHRlcnMucmVnaXN0ZXIoXCJqYW51c1wiLCBKYW51c0FkYXB0ZXIpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEphbnVzQWRhcHRlcjtcbiIsIi8qIGVzbGludC1lbnYgYnJvd3NlciAqL1xuXG4vKipcbiAqIFRoaXMgaXMgdGhlIHdlYiBicm93c2VyIGltcGxlbWVudGF0aW9uIG9mIGBkZWJ1ZygpYC5cbiAqL1xuXG5leHBvcnRzLmZvcm1hdEFyZ3MgPSBmb3JtYXRBcmdzO1xuZXhwb3J0cy5zYXZlID0gc2F2ZTtcbmV4cG9ydHMubG9hZCA9IGxvYWQ7XG5leHBvcnRzLnVzZUNvbG9ycyA9IHVzZUNvbG9ycztcbmV4cG9ydHMuc3RvcmFnZSA9IGxvY2Fsc3RvcmFnZSgpO1xuZXhwb3J0cy5kZXN0cm95ID0gKCgpID0+IHtcblx0bGV0IHdhcm5lZCA9IGZhbHNlO1xuXG5cdHJldHVybiAoKSA9PiB7XG5cdFx0aWYgKCF3YXJuZWQpIHtcblx0XHRcdHdhcm5lZCA9IHRydWU7XG5cdFx0XHRjb25zb2xlLndhcm4oJ0luc3RhbmNlIG1ldGhvZCBgZGVidWcuZGVzdHJveSgpYCBpcyBkZXByZWNhdGVkIGFuZCBubyBsb25nZXIgZG9lcyBhbnl0aGluZy4gSXQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZXh0IG1ham9yIHZlcnNpb24gb2YgYGRlYnVnYC4nKTtcblx0XHR9XG5cdH07XG59KSgpO1xuXG4vKipcbiAqIENvbG9ycy5cbiAqL1xuXG5leHBvcnRzLmNvbG9ycyA9IFtcblx0JyMwMDAwQ0MnLFxuXHQnIzAwMDBGRicsXG5cdCcjMDAzM0NDJyxcblx0JyMwMDMzRkYnLFxuXHQnIzAwNjZDQycsXG5cdCcjMDA2NkZGJyxcblx0JyMwMDk5Q0MnLFxuXHQnIzAwOTlGRicsXG5cdCcjMDBDQzAwJyxcblx0JyMwMENDMzMnLFxuXHQnIzAwQ0M2NicsXG5cdCcjMDBDQzk5Jyxcblx0JyMwMENDQ0MnLFxuXHQnIzAwQ0NGRicsXG5cdCcjMzMwMENDJyxcblx0JyMzMzAwRkYnLFxuXHQnIzMzMzNDQycsXG5cdCcjMzMzM0ZGJyxcblx0JyMzMzY2Q0MnLFxuXHQnIzMzNjZGRicsXG5cdCcjMzM5OUNDJyxcblx0JyMzMzk5RkYnLFxuXHQnIzMzQ0MwMCcsXG5cdCcjMzNDQzMzJyxcblx0JyMzM0NDNjYnLFxuXHQnIzMzQ0M5OScsXG5cdCcjMzNDQ0NDJyxcblx0JyMzM0NDRkYnLFxuXHQnIzY2MDBDQycsXG5cdCcjNjYwMEZGJyxcblx0JyM2NjMzQ0MnLFxuXHQnIzY2MzNGRicsXG5cdCcjNjZDQzAwJyxcblx0JyM2NkNDMzMnLFxuXHQnIzk5MDBDQycsXG5cdCcjOTkwMEZGJyxcblx0JyM5OTMzQ0MnLFxuXHQnIzk5MzNGRicsXG5cdCcjOTlDQzAwJyxcblx0JyM5OUNDMzMnLFxuXHQnI0NDMDAwMCcsXG5cdCcjQ0MwMDMzJyxcblx0JyNDQzAwNjYnLFxuXHQnI0NDMDA5OScsXG5cdCcjQ0MwMENDJyxcblx0JyNDQzAwRkYnLFxuXHQnI0NDMzMwMCcsXG5cdCcjQ0MzMzMzJyxcblx0JyNDQzMzNjYnLFxuXHQnI0NDMzM5OScsXG5cdCcjQ0MzM0NDJyxcblx0JyNDQzMzRkYnLFxuXHQnI0NDNjYwMCcsXG5cdCcjQ0M2NjMzJyxcblx0JyNDQzk5MDAnLFxuXHQnI0NDOTkzMycsXG5cdCcjQ0NDQzAwJyxcblx0JyNDQ0NDMzMnLFxuXHQnI0ZGMDAwMCcsXG5cdCcjRkYwMDMzJyxcblx0JyNGRjAwNjYnLFxuXHQnI0ZGMDA5OScsXG5cdCcjRkYwMENDJyxcblx0JyNGRjAwRkYnLFxuXHQnI0ZGMzMwMCcsXG5cdCcjRkYzMzMzJyxcblx0JyNGRjMzNjYnLFxuXHQnI0ZGMzM5OScsXG5cdCcjRkYzM0NDJyxcblx0JyNGRjMzRkYnLFxuXHQnI0ZGNjYwMCcsXG5cdCcjRkY2NjMzJyxcblx0JyNGRjk5MDAnLFxuXHQnI0ZGOTkzMycsXG5cdCcjRkZDQzAwJyxcblx0JyNGRkNDMzMnXG5dO1xuXG4vKipcbiAqIEN1cnJlbnRseSBvbmx5IFdlYktpdC1iYXNlZCBXZWIgSW5zcGVjdG9ycywgRmlyZWZveCA+PSB2MzEsXG4gKiBhbmQgdGhlIEZpcmVidWcgZXh0ZW5zaW9uIChhbnkgRmlyZWZveCB2ZXJzaW9uKSBhcmUga25vd25cbiAqIHRvIHN1cHBvcnQgXCIlY1wiIENTUyBjdXN0b21pemF0aW9ucy5cbiAqXG4gKiBUT0RPOiBhZGQgYSBgbG9jYWxTdG9yYWdlYCB2YXJpYWJsZSB0byBleHBsaWNpdGx5IGVuYWJsZS9kaXNhYmxlIGNvbG9yc1xuICovXG5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5XG5mdW5jdGlvbiB1c2VDb2xvcnMoKSB7XG5cdC8vIE5COiBJbiBhbiBFbGVjdHJvbiBwcmVsb2FkIHNjcmlwdCwgZG9jdW1lbnQgd2lsbCBiZSBkZWZpbmVkIGJ1dCBub3QgZnVsbHlcblx0Ly8gaW5pdGlhbGl6ZWQuIFNpbmNlIHdlIGtub3cgd2UncmUgaW4gQ2hyb21lLCB3ZSdsbCBqdXN0IGRldGVjdCB0aGlzIGNhc2Vcblx0Ly8gZXhwbGljaXRseVxuXHRpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LnByb2Nlc3MgJiYgKHdpbmRvdy5wcm9jZXNzLnR5cGUgPT09ICdyZW5kZXJlcicgfHwgd2luZG93LnByb2Nlc3MuX19ud2pzKSkge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cblx0Ly8gSW50ZXJuZXQgRXhwbG9yZXIgYW5kIEVkZ2UgZG8gbm90IHN1cHBvcnQgY29sb3JzLlxuXHRpZiAodHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudCAmJiBuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCkubWF0Y2goLyhlZGdlfHRyaWRlbnQpXFwvKFxcZCspLykpIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHRsZXQgbTtcblxuXHQvLyBJcyB3ZWJraXQ/IGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzE2NDU5NjA2LzM3Njc3M1xuXHQvLyBkb2N1bWVudCBpcyB1bmRlZmluZWQgaW4gcmVhY3QtbmF0aXZlOiBodHRwczovL2dpdGh1Yi5jb20vZmFjZWJvb2svcmVhY3QtbmF0aXZlL3B1bGwvMTYzMlxuXHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcmV0dXJuLWFzc2lnblxuXHRyZXR1cm4gKHR5cGVvZiBkb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50ICYmIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZSAmJiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGUuV2Via2l0QXBwZWFyYW5jZSkgfHxcblx0XHQvLyBJcyBmaXJlYnVnPyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zOTgxMjAvMzc2NzczXG5cdFx0KHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHdpbmRvdy5jb25zb2xlICYmICh3aW5kb3cuY29uc29sZS5maXJlYnVnIHx8ICh3aW5kb3cuY29uc29sZS5leGNlcHRpb24gJiYgd2luZG93LmNvbnNvbGUudGFibGUpKSkgfHxcblx0XHQvLyBJcyBmaXJlZm94ID49IHYzMT9cblx0XHQvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1Rvb2xzL1dlYl9Db25zb2xlI1N0eWxpbmdfbWVzc2FnZXNcblx0XHQodHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudCAmJiAobSA9IG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5tYXRjaCgvZmlyZWZveFxcLyhcXGQrKS8pKSAmJiBwYXJzZUludChtWzFdLCAxMCkgPj0gMzEpIHx8XG5cdFx0Ly8gRG91YmxlIGNoZWNrIHdlYmtpdCBpbiB1c2VyQWdlbnQganVzdCBpbiBjYXNlIHdlIGFyZSBpbiBhIHdvcmtlclxuXHRcdCh0eXBlb2YgbmF2aWdhdG9yICE9PSAndW5kZWZpbmVkJyAmJiBuYXZpZ2F0b3IudXNlckFnZW50ICYmIG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5tYXRjaCgvYXBwbGV3ZWJraXRcXC8oXFxkKykvKSk7XG59XG5cbi8qKlxuICogQ29sb3JpemUgbG9nIGFyZ3VtZW50cyBpZiBlbmFibGVkLlxuICpcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuZnVuY3Rpb24gZm9ybWF0QXJncyhhcmdzKSB7XG5cdGFyZ3NbMF0gPSAodGhpcy51c2VDb2xvcnMgPyAnJWMnIDogJycpICtcblx0XHR0aGlzLm5hbWVzcGFjZSArXG5cdFx0KHRoaXMudXNlQ29sb3JzID8gJyAlYycgOiAnICcpICtcblx0XHRhcmdzWzBdICtcblx0XHQodGhpcy51c2VDb2xvcnMgPyAnJWMgJyA6ICcgJykgK1xuXHRcdCcrJyArIG1vZHVsZS5leHBvcnRzLmh1bWFuaXplKHRoaXMuZGlmZik7XG5cblx0aWYgKCF0aGlzLnVzZUNvbG9ycykge1xuXHRcdHJldHVybjtcblx0fVxuXG5cdGNvbnN0IGMgPSAnY29sb3I6ICcgKyB0aGlzLmNvbG9yO1xuXHRhcmdzLnNwbGljZSgxLCAwLCBjLCAnY29sb3I6IGluaGVyaXQnKTtcblxuXHQvLyBUaGUgZmluYWwgXCIlY1wiIGlzIHNvbWV3aGF0IHRyaWNreSwgYmVjYXVzZSB0aGVyZSBjb3VsZCBiZSBvdGhlclxuXHQvLyBhcmd1bWVudHMgcGFzc2VkIGVpdGhlciBiZWZvcmUgb3IgYWZ0ZXIgdGhlICVjLCBzbyB3ZSBuZWVkIHRvXG5cdC8vIGZpZ3VyZSBvdXQgdGhlIGNvcnJlY3QgaW5kZXggdG8gaW5zZXJ0IHRoZSBDU1MgaW50b1xuXHRsZXQgaW5kZXggPSAwO1xuXHRsZXQgbGFzdEMgPSAwO1xuXHRhcmdzWzBdLnJlcGxhY2UoLyVbYS16QS1aJV0vZywgbWF0Y2ggPT4ge1xuXHRcdGlmIChtYXRjaCA9PT0gJyUlJykge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRpbmRleCsrO1xuXHRcdGlmIChtYXRjaCA9PT0gJyVjJykge1xuXHRcdFx0Ly8gV2Ugb25seSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgKmxhc3QqICVjXG5cdFx0XHQvLyAodGhlIHVzZXIgbWF5IGhhdmUgcHJvdmlkZWQgdGhlaXIgb3duKVxuXHRcdFx0bGFzdEMgPSBpbmRleDtcblx0XHR9XG5cdH0pO1xuXG5cdGFyZ3Muc3BsaWNlKGxhc3RDLCAwLCBjKTtcbn1cblxuLyoqXG4gKiBJbnZva2VzIGBjb25zb2xlLmRlYnVnKClgIHdoZW4gYXZhaWxhYmxlLlxuICogTm8tb3Agd2hlbiBgY29uc29sZS5kZWJ1Z2AgaXMgbm90IGEgXCJmdW5jdGlvblwiLlxuICogSWYgYGNvbnNvbGUuZGVidWdgIGlzIG5vdCBhdmFpbGFibGUsIGZhbGxzIGJhY2tcbiAqIHRvIGBjb25zb2xlLmxvZ2AuXG4gKlxuICogQGFwaSBwdWJsaWNcbiAqL1xuZXhwb3J0cy5sb2cgPSBjb25zb2xlLmRlYnVnIHx8IGNvbnNvbGUubG9nIHx8ICgoKSA9PiB7fSk7XG5cbi8qKlxuICogU2F2ZSBgbmFtZXNwYWNlc2AuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWVzcGFjZXNcbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBzYXZlKG5hbWVzcGFjZXMpIHtcblx0dHJ5IHtcblx0XHRpZiAobmFtZXNwYWNlcykge1xuXHRcdFx0ZXhwb3J0cy5zdG9yYWdlLnNldEl0ZW0oJ2RlYnVnJywgbmFtZXNwYWNlcyk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGV4cG9ydHMuc3RvcmFnZS5yZW1vdmVJdGVtKCdkZWJ1ZycpO1xuXHRcdH1cblx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHQvLyBTd2FsbG93XG5cdFx0Ly8gWFhYIChAUWl4LSkgc2hvdWxkIHdlIGJlIGxvZ2dpbmcgdGhlc2U/XG5cdH1cbn1cblxuLyoqXG4gKiBMb2FkIGBuYW1lc3BhY2VzYC5cbiAqXG4gKiBAcmV0dXJuIHtTdHJpbmd9IHJldHVybnMgdGhlIHByZXZpb3VzbHkgcGVyc2lzdGVkIGRlYnVnIG1vZGVzXG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gbG9hZCgpIHtcblx0bGV0IHI7XG5cdHRyeSB7XG5cdFx0ciA9IGV4cG9ydHMuc3RvcmFnZS5nZXRJdGVtKCdkZWJ1ZycpO1xuXHR9IGNhdGNoIChlcnJvcikge1xuXHRcdC8vIFN3YWxsb3dcblx0XHQvLyBYWFggKEBRaXgtKSBzaG91bGQgd2UgYmUgbG9nZ2luZyB0aGVzZT9cblx0fVxuXG5cdC8vIElmIGRlYnVnIGlzbid0IHNldCBpbiBMUywgYW5kIHdlJ3JlIGluIEVsZWN0cm9uLCB0cnkgdG8gbG9hZCAkREVCVUdcblx0aWYgKCFyICYmIHR5cGVvZiBwcm9jZXNzICE9PSAndW5kZWZpbmVkJyAmJiAnZW52JyBpbiBwcm9jZXNzKSB7XG5cdFx0ciA9IHByb2Nlc3MuZW52LkRFQlVHO1xuXHR9XG5cblx0cmV0dXJuIHI7XG59XG5cbi8qKlxuICogTG9jYWxzdG9yYWdlIGF0dGVtcHRzIHRvIHJldHVybiB0aGUgbG9jYWxzdG9yYWdlLlxuICpcbiAqIFRoaXMgaXMgbmVjZXNzYXJ5IGJlY2F1c2Ugc2FmYXJpIHRocm93c1xuICogd2hlbiBhIHVzZXIgZGlzYWJsZXMgY29va2llcy9sb2NhbHN0b3JhZ2VcbiAqIGFuZCB5b3UgYXR0ZW1wdCB0byBhY2Nlc3MgaXQuXG4gKlxuICogQHJldHVybiB7TG9jYWxTdG9yYWdlfVxuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gbG9jYWxzdG9yYWdlKCkge1xuXHR0cnkge1xuXHRcdC8vIFRWTUxLaXQgKEFwcGxlIFRWIEpTIFJ1bnRpbWUpIGRvZXMgbm90IGhhdmUgYSB3aW5kb3cgb2JqZWN0LCBqdXN0IGxvY2FsU3RvcmFnZSBpbiB0aGUgZ2xvYmFsIGNvbnRleHRcblx0XHQvLyBUaGUgQnJvd3NlciBhbHNvIGhhcyBsb2NhbFN0b3JhZ2UgaW4gdGhlIGdsb2JhbCBjb250ZXh0LlxuXHRcdHJldHVybiBsb2NhbFN0b3JhZ2U7XG5cdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0Ly8gU3dhbGxvd1xuXHRcdC8vIFhYWCAoQFFpeC0pIHNob3VsZCB3ZSBiZSBsb2dnaW5nIHRoZXNlP1xuXHR9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9jb21tb24nKShleHBvcnRzKTtcblxuY29uc3Qge2Zvcm1hdHRlcnN9ID0gbW9kdWxlLmV4cG9ydHM7XG5cbi8qKlxuICogTWFwICVqIHRvIGBKU09OLnN0cmluZ2lmeSgpYCwgc2luY2Ugbm8gV2ViIEluc3BlY3RvcnMgZG8gdGhhdCBieSBkZWZhdWx0LlxuICovXG5cbmZvcm1hdHRlcnMuaiA9IGZ1bmN0aW9uICh2KSB7XG5cdHRyeSB7XG5cdFx0cmV0dXJuIEpTT04uc3RyaW5naWZ5KHYpO1xuXHR9IGNhdGNoIChlcnJvcikge1xuXHRcdHJldHVybiAnW1VuZXhwZWN0ZWRKU09OUGFyc2VFcnJvcl06ICcgKyBlcnJvci5tZXNzYWdlO1xuXHR9XG59O1xuIiwiXG4vKipcbiAqIFRoaXMgaXMgdGhlIGNvbW1vbiBsb2dpYyBmb3IgYm90aCB0aGUgTm9kZS5qcyBhbmQgd2ViIGJyb3dzZXJcbiAqIGltcGxlbWVudGF0aW9ucyBvZiBgZGVidWcoKWAuXG4gKi9cblxuZnVuY3Rpb24gc2V0dXAoZW52KSB7XG5cdGNyZWF0ZURlYnVnLmRlYnVnID0gY3JlYXRlRGVidWc7XG5cdGNyZWF0ZURlYnVnLmRlZmF1bHQgPSBjcmVhdGVEZWJ1Zztcblx0Y3JlYXRlRGVidWcuY29lcmNlID0gY29lcmNlO1xuXHRjcmVhdGVEZWJ1Zy5kaXNhYmxlID0gZGlzYWJsZTtcblx0Y3JlYXRlRGVidWcuZW5hYmxlID0gZW5hYmxlO1xuXHRjcmVhdGVEZWJ1Zy5lbmFibGVkID0gZW5hYmxlZDtcblx0Y3JlYXRlRGVidWcuaHVtYW5pemUgPSByZXF1aXJlKCdtcycpO1xuXHRjcmVhdGVEZWJ1Zy5kZXN0cm95ID0gZGVzdHJveTtcblxuXHRPYmplY3Qua2V5cyhlbnYpLmZvckVhY2goa2V5ID0+IHtcblx0XHRjcmVhdGVEZWJ1Z1trZXldID0gZW52W2tleV07XG5cdH0pO1xuXG5cdC8qKlxuXHQqIFRoZSBjdXJyZW50bHkgYWN0aXZlIGRlYnVnIG1vZGUgbmFtZXMsIGFuZCBuYW1lcyB0byBza2lwLlxuXHQqL1xuXG5cdGNyZWF0ZURlYnVnLm5hbWVzID0gW107XG5cdGNyZWF0ZURlYnVnLnNraXBzID0gW107XG5cblx0LyoqXG5cdCogTWFwIG9mIHNwZWNpYWwgXCIlblwiIGhhbmRsaW5nIGZ1bmN0aW9ucywgZm9yIHRoZSBkZWJ1ZyBcImZvcm1hdFwiIGFyZ3VtZW50LlxuXHQqXG5cdCogVmFsaWQga2V5IG5hbWVzIGFyZSBhIHNpbmdsZSwgbG93ZXIgb3IgdXBwZXItY2FzZSBsZXR0ZXIsIGkuZS4gXCJuXCIgYW5kIFwiTlwiLlxuXHQqL1xuXHRjcmVhdGVEZWJ1Zy5mb3JtYXR0ZXJzID0ge307XG5cblx0LyoqXG5cdCogU2VsZWN0cyBhIGNvbG9yIGZvciBhIGRlYnVnIG5hbWVzcGFjZVxuXHQqIEBwYXJhbSB7U3RyaW5nfSBuYW1lc3BhY2UgVGhlIG5hbWVzcGFjZSBzdHJpbmcgZm9yIHRoZSBkZWJ1ZyBpbnN0YW5jZSB0byBiZSBjb2xvcmVkXG5cdCogQHJldHVybiB7TnVtYmVyfFN0cmluZ30gQW4gQU5TSSBjb2xvciBjb2RlIGZvciB0aGUgZ2l2ZW4gbmFtZXNwYWNlXG5cdCogQGFwaSBwcml2YXRlXG5cdCovXG5cdGZ1bmN0aW9uIHNlbGVjdENvbG9yKG5hbWVzcGFjZSkge1xuXHRcdGxldCBoYXNoID0gMDtcblxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgbmFtZXNwYWNlLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRoYXNoID0gKChoYXNoIDw8IDUpIC0gaGFzaCkgKyBuYW1lc3BhY2UuY2hhckNvZGVBdChpKTtcblx0XHRcdGhhc2ggfD0gMDsgLy8gQ29udmVydCB0byAzMmJpdCBpbnRlZ2VyXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNyZWF0ZURlYnVnLmNvbG9yc1tNYXRoLmFicyhoYXNoKSAlIGNyZWF0ZURlYnVnLmNvbG9ycy5sZW5ndGhdO1xuXHR9XG5cdGNyZWF0ZURlYnVnLnNlbGVjdENvbG9yID0gc2VsZWN0Q29sb3I7XG5cblx0LyoqXG5cdCogQ3JlYXRlIGEgZGVidWdnZXIgd2l0aCB0aGUgZ2l2ZW4gYG5hbWVzcGFjZWAuXG5cdCpcblx0KiBAcGFyYW0ge1N0cmluZ30gbmFtZXNwYWNlXG5cdCogQHJldHVybiB7RnVuY3Rpb259XG5cdCogQGFwaSBwdWJsaWNcblx0Ki9cblx0ZnVuY3Rpb24gY3JlYXRlRGVidWcobmFtZXNwYWNlKSB7XG5cdFx0bGV0IHByZXZUaW1lO1xuXHRcdGxldCBlbmFibGVPdmVycmlkZSA9IG51bGw7XG5cdFx0bGV0IG5hbWVzcGFjZXNDYWNoZTtcblx0XHRsZXQgZW5hYmxlZENhY2hlO1xuXG5cdFx0ZnVuY3Rpb24gZGVidWcoLi4uYXJncykge1xuXHRcdFx0Ly8gRGlzYWJsZWQ/XG5cdFx0XHRpZiAoIWRlYnVnLmVuYWJsZWQpIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBzZWxmID0gZGVidWc7XG5cblx0XHRcdC8vIFNldCBgZGlmZmAgdGltZXN0YW1wXG5cdFx0XHRjb25zdCBjdXJyID0gTnVtYmVyKG5ldyBEYXRlKCkpO1xuXHRcdFx0Y29uc3QgbXMgPSBjdXJyIC0gKHByZXZUaW1lIHx8IGN1cnIpO1xuXHRcdFx0c2VsZi5kaWZmID0gbXM7XG5cdFx0XHRzZWxmLnByZXYgPSBwcmV2VGltZTtcblx0XHRcdHNlbGYuY3VyciA9IGN1cnI7XG5cdFx0XHRwcmV2VGltZSA9IGN1cnI7XG5cblx0XHRcdGFyZ3NbMF0gPSBjcmVhdGVEZWJ1Zy5jb2VyY2UoYXJnc1swXSk7XG5cblx0XHRcdGlmICh0eXBlb2YgYXJnc1swXSAhPT0gJ3N0cmluZycpIHtcblx0XHRcdFx0Ly8gQW55dGhpbmcgZWxzZSBsZXQncyBpbnNwZWN0IHdpdGggJU9cblx0XHRcdFx0YXJncy51bnNoaWZ0KCclTycpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBBcHBseSBhbnkgYGZvcm1hdHRlcnNgIHRyYW5zZm9ybWF0aW9uc1xuXHRcdFx0bGV0IGluZGV4ID0gMDtcblx0XHRcdGFyZ3NbMF0gPSBhcmdzWzBdLnJlcGxhY2UoLyUoW2EtekEtWiVdKS9nLCAobWF0Y2gsIGZvcm1hdCkgPT4ge1xuXHRcdFx0XHQvLyBJZiB3ZSBlbmNvdW50ZXIgYW4gZXNjYXBlZCAlIHRoZW4gZG9uJ3QgaW5jcmVhc2UgdGhlIGFycmF5IGluZGV4XG5cdFx0XHRcdGlmIChtYXRjaCA9PT0gJyUlJykge1xuXHRcdFx0XHRcdHJldHVybiAnJSc7XG5cdFx0XHRcdH1cblx0XHRcdFx0aW5kZXgrKztcblx0XHRcdFx0Y29uc3QgZm9ybWF0dGVyID0gY3JlYXRlRGVidWcuZm9ybWF0dGVyc1tmb3JtYXRdO1xuXHRcdFx0XHRpZiAodHlwZW9mIGZvcm1hdHRlciA9PT0gJ2Z1bmN0aW9uJykge1xuXHRcdFx0XHRcdGNvbnN0IHZhbCA9IGFyZ3NbaW5kZXhdO1xuXHRcdFx0XHRcdG1hdGNoID0gZm9ybWF0dGVyLmNhbGwoc2VsZiwgdmFsKTtcblxuXHRcdFx0XHRcdC8vIE5vdyB3ZSBuZWVkIHRvIHJlbW92ZSBgYXJnc1tpbmRleF1gIHNpbmNlIGl0J3MgaW5saW5lZCBpbiB0aGUgYGZvcm1hdGBcblx0XHRcdFx0XHRhcmdzLnNwbGljZShpbmRleCwgMSk7XG5cdFx0XHRcdFx0aW5kZXgtLTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gbWF0Y2g7XG5cdFx0XHR9KTtcblxuXHRcdFx0Ly8gQXBwbHkgZW52LXNwZWNpZmljIGZvcm1hdHRpbmcgKGNvbG9ycywgZXRjLilcblx0XHRcdGNyZWF0ZURlYnVnLmZvcm1hdEFyZ3MuY2FsbChzZWxmLCBhcmdzKTtcblxuXHRcdFx0Y29uc3QgbG9nRm4gPSBzZWxmLmxvZyB8fCBjcmVhdGVEZWJ1Zy5sb2c7XG5cdFx0XHRsb2dGbi5hcHBseShzZWxmLCBhcmdzKTtcblx0XHR9XG5cblx0XHRkZWJ1Zy5uYW1lc3BhY2UgPSBuYW1lc3BhY2U7XG5cdFx0ZGVidWcudXNlQ29sb3JzID0gY3JlYXRlRGVidWcudXNlQ29sb3JzKCk7XG5cdFx0ZGVidWcuY29sb3IgPSBjcmVhdGVEZWJ1Zy5zZWxlY3RDb2xvcihuYW1lc3BhY2UpO1xuXHRcdGRlYnVnLmV4dGVuZCA9IGV4dGVuZDtcblx0XHRkZWJ1Zy5kZXN0cm95ID0gY3JlYXRlRGVidWcuZGVzdHJveTsgLy8gWFhYIFRlbXBvcmFyeS4gV2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZXh0IG1ham9yIHJlbGVhc2UuXG5cblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZGVidWcsICdlbmFibGVkJywge1xuXHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcblx0XHRcdGNvbmZpZ3VyYWJsZTogZmFsc2UsXG5cdFx0XHRnZXQ6ICgpID0+IHtcblx0XHRcdFx0aWYgKGVuYWJsZU92ZXJyaWRlICE9PSBudWxsKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGVuYWJsZU92ZXJyaWRlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmIChuYW1lc3BhY2VzQ2FjaGUgIT09IGNyZWF0ZURlYnVnLm5hbWVzcGFjZXMpIHtcblx0XHRcdFx0XHRuYW1lc3BhY2VzQ2FjaGUgPSBjcmVhdGVEZWJ1Zy5uYW1lc3BhY2VzO1xuXHRcdFx0XHRcdGVuYWJsZWRDYWNoZSA9IGNyZWF0ZURlYnVnLmVuYWJsZWQobmFtZXNwYWNlKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiBlbmFibGVkQ2FjaGU7XG5cdFx0XHR9LFxuXHRcdFx0c2V0OiB2ID0+IHtcblx0XHRcdFx0ZW5hYmxlT3ZlcnJpZGUgPSB2O1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0Ly8gRW52LXNwZWNpZmljIGluaXRpYWxpemF0aW9uIGxvZ2ljIGZvciBkZWJ1ZyBpbnN0YW5jZXNcblx0XHRpZiAodHlwZW9mIGNyZWF0ZURlYnVnLmluaXQgPT09ICdmdW5jdGlvbicpIHtcblx0XHRcdGNyZWF0ZURlYnVnLmluaXQoZGVidWcpO1xuXHRcdH1cblxuXHRcdHJldHVybiBkZWJ1Zztcblx0fVxuXG5cdGZ1bmN0aW9uIGV4dGVuZChuYW1lc3BhY2UsIGRlbGltaXRlcikge1xuXHRcdGNvbnN0IG5ld0RlYnVnID0gY3JlYXRlRGVidWcodGhpcy5uYW1lc3BhY2UgKyAodHlwZW9mIGRlbGltaXRlciA9PT0gJ3VuZGVmaW5lZCcgPyAnOicgOiBkZWxpbWl0ZXIpICsgbmFtZXNwYWNlKTtcblx0XHRuZXdEZWJ1Zy5sb2cgPSB0aGlzLmxvZztcblx0XHRyZXR1cm4gbmV3RGVidWc7XG5cdH1cblxuXHQvKipcblx0KiBFbmFibGVzIGEgZGVidWcgbW9kZSBieSBuYW1lc3BhY2VzLiBUaGlzIGNhbiBpbmNsdWRlIG1vZGVzXG5cdCogc2VwYXJhdGVkIGJ5IGEgY29sb24gYW5kIHdpbGRjYXJkcy5cblx0KlxuXHQqIEBwYXJhbSB7U3RyaW5nfSBuYW1lc3BhY2VzXG5cdCogQGFwaSBwdWJsaWNcblx0Ki9cblx0ZnVuY3Rpb24gZW5hYmxlKG5hbWVzcGFjZXMpIHtcblx0XHRjcmVhdGVEZWJ1Zy5zYXZlKG5hbWVzcGFjZXMpO1xuXHRcdGNyZWF0ZURlYnVnLm5hbWVzcGFjZXMgPSBuYW1lc3BhY2VzO1xuXG5cdFx0Y3JlYXRlRGVidWcubmFtZXMgPSBbXTtcblx0XHRjcmVhdGVEZWJ1Zy5za2lwcyA9IFtdO1xuXG5cdFx0Y29uc3Qgc3BsaXQgPSAodHlwZW9mIG5hbWVzcGFjZXMgPT09ICdzdHJpbmcnID8gbmFtZXNwYWNlcyA6ICcnKVxuXHRcdFx0LnRyaW0oKVxuXHRcdFx0LnJlcGxhY2UoJyAnLCAnLCcpXG5cdFx0XHQuc3BsaXQoJywnKVxuXHRcdFx0LmZpbHRlcihCb29sZWFuKTtcblxuXHRcdGZvciAoY29uc3QgbnMgb2Ygc3BsaXQpIHtcblx0XHRcdGlmIChuc1swXSA9PT0gJy0nKSB7XG5cdFx0XHRcdGNyZWF0ZURlYnVnLnNraXBzLnB1c2gobnMuc2xpY2UoMSkpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y3JlYXRlRGVidWcubmFtZXMucHVzaChucyk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gc3RyaW5nIG1hdGNoZXMgYSBuYW1lc3BhY2UgdGVtcGxhdGUsIGhvbm9yaW5nXG5cdCAqIGFzdGVyaXNrcyBhcyB3aWxkY2FyZHMuXG5cdCAqXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBzZWFyY2hcblx0ICogQHBhcmFtIHtTdHJpbmd9IHRlbXBsYXRlXG5cdCAqIEByZXR1cm4ge0Jvb2xlYW59XG5cdCAqL1xuXHRmdW5jdGlvbiBtYXRjaGVzVGVtcGxhdGUoc2VhcmNoLCB0ZW1wbGF0ZSkge1xuXHRcdGxldCBzZWFyY2hJbmRleCA9IDA7XG5cdFx0bGV0IHRlbXBsYXRlSW5kZXggPSAwO1xuXHRcdGxldCBzdGFySW5kZXggPSAtMTtcblx0XHRsZXQgbWF0Y2hJbmRleCA9IDA7XG5cblx0XHR3aGlsZSAoc2VhcmNoSW5kZXggPCBzZWFyY2gubGVuZ3RoKSB7XG5cdFx0XHRpZiAodGVtcGxhdGVJbmRleCA8IHRlbXBsYXRlLmxlbmd0aCAmJiAodGVtcGxhdGVbdGVtcGxhdGVJbmRleF0gPT09IHNlYXJjaFtzZWFyY2hJbmRleF0gfHwgdGVtcGxhdGVbdGVtcGxhdGVJbmRleF0gPT09ICcqJykpIHtcblx0XHRcdFx0Ly8gTWF0Y2ggY2hhcmFjdGVyIG9yIHByb2NlZWQgd2l0aCB3aWxkY2FyZFxuXHRcdFx0XHRpZiAodGVtcGxhdGVbdGVtcGxhdGVJbmRleF0gPT09ICcqJykge1xuXHRcdFx0XHRcdHN0YXJJbmRleCA9IHRlbXBsYXRlSW5kZXg7XG5cdFx0XHRcdFx0bWF0Y2hJbmRleCA9IHNlYXJjaEluZGV4O1xuXHRcdFx0XHRcdHRlbXBsYXRlSW5kZXgrKzsgLy8gU2tpcCB0aGUgJyonXG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0c2VhcmNoSW5kZXgrKztcblx0XHRcdFx0XHR0ZW1wbGF0ZUluZGV4Kys7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSBpZiAoc3RhckluZGV4ICE9PSAtMSkgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLW5lZ2F0ZWQtY29uZGl0aW9uXG5cdFx0XHRcdC8vIEJhY2t0cmFjayB0byB0aGUgbGFzdCAnKicgYW5kIHRyeSB0byBtYXRjaCBtb3JlIGNoYXJhY3RlcnNcblx0XHRcdFx0dGVtcGxhdGVJbmRleCA9IHN0YXJJbmRleCArIDE7XG5cdFx0XHRcdG1hdGNoSW5kZXgrKztcblx0XHRcdFx0c2VhcmNoSW5kZXggPSBtYXRjaEluZGV4O1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlOyAvLyBObyBtYXRjaFxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIEhhbmRsZSB0cmFpbGluZyAnKicgaW4gdGVtcGxhdGVcblx0XHR3aGlsZSAodGVtcGxhdGVJbmRleCA8IHRlbXBsYXRlLmxlbmd0aCAmJiB0ZW1wbGF0ZVt0ZW1wbGF0ZUluZGV4XSA9PT0gJyonKSB7XG5cdFx0XHR0ZW1wbGF0ZUluZGV4Kys7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRlbXBsYXRlSW5kZXggPT09IHRlbXBsYXRlLmxlbmd0aDtcblx0fVxuXG5cdC8qKlxuXHQqIERpc2FibGUgZGVidWcgb3V0cHV0LlxuXHQqXG5cdCogQHJldHVybiB7U3RyaW5nfSBuYW1lc3BhY2VzXG5cdCogQGFwaSBwdWJsaWNcblx0Ki9cblx0ZnVuY3Rpb24gZGlzYWJsZSgpIHtcblx0XHRjb25zdCBuYW1lc3BhY2VzID0gW1xuXHRcdFx0Li4uY3JlYXRlRGVidWcubmFtZXMsXG5cdFx0XHQuLi5jcmVhdGVEZWJ1Zy5za2lwcy5tYXAobmFtZXNwYWNlID0+ICctJyArIG5hbWVzcGFjZSlcblx0XHRdLmpvaW4oJywnKTtcblx0XHRjcmVhdGVEZWJ1Zy5lbmFibGUoJycpO1xuXHRcdHJldHVybiBuYW1lc3BhY2VzO1xuXHR9XG5cblx0LyoqXG5cdCogUmV0dXJucyB0cnVlIGlmIHRoZSBnaXZlbiBtb2RlIG5hbWUgaXMgZW5hYmxlZCwgZmFsc2Ugb3RoZXJ3aXNlLlxuXHQqXG5cdCogQHBhcmFtIHtTdHJpbmd9IG5hbWVcblx0KiBAcmV0dXJuIHtCb29sZWFufVxuXHQqIEBhcGkgcHVibGljXG5cdCovXG5cdGZ1bmN0aW9uIGVuYWJsZWQobmFtZSkge1xuXHRcdGZvciAoY29uc3Qgc2tpcCBvZiBjcmVhdGVEZWJ1Zy5za2lwcykge1xuXHRcdFx0aWYgKG1hdGNoZXNUZW1wbGF0ZShuYW1lLCBza2lwKSkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Zm9yIChjb25zdCBucyBvZiBjcmVhdGVEZWJ1Zy5uYW1lcykge1xuXHRcdFx0aWYgKG1hdGNoZXNUZW1wbGF0ZShuYW1lLCBucykpIHtcblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG5cblx0LyoqXG5cdCogQ29lcmNlIGB2YWxgLlxuXHQqXG5cdCogQHBhcmFtIHtNaXhlZH0gdmFsXG5cdCogQHJldHVybiB7TWl4ZWR9XG5cdCogQGFwaSBwcml2YXRlXG5cdCovXG5cdGZ1bmN0aW9uIGNvZXJjZSh2YWwpIHtcblx0XHRpZiAodmFsIGluc3RhbmNlb2YgRXJyb3IpIHtcblx0XHRcdHJldHVybiB2YWwuc3RhY2sgfHwgdmFsLm1lc3NhZ2U7XG5cdFx0fVxuXHRcdHJldHVybiB2YWw7XG5cdH1cblxuXHQvKipcblx0KiBYWFggRE8gTk9UIFVTRS4gVGhpcyBpcyBhIHRlbXBvcmFyeSBzdHViIGZ1bmN0aW9uLlxuXHQqIFhYWCBJdCBXSUxMIGJlIHJlbW92ZWQgaW4gdGhlIG5leHQgbWFqb3IgcmVsZWFzZS5cblx0Ki9cblx0ZnVuY3Rpb24gZGVzdHJveSgpIHtcblx0XHRjb25zb2xlLndhcm4oJ0luc3RhbmNlIG1ldGhvZCBgZGVidWcuZGVzdHJveSgpYCBpcyBkZXByZWNhdGVkIGFuZCBubyBsb25nZXIgZG9lcyBhbnl0aGluZy4gSXQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZXh0IG1ham9yIHZlcnNpb24gb2YgYGRlYnVnYC4nKTtcblx0fVxuXG5cdGNyZWF0ZURlYnVnLmVuYWJsZShjcmVhdGVEZWJ1Zy5sb2FkKCkpO1xuXG5cdHJldHVybiBjcmVhdGVEZWJ1Zztcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBzZXR1cDtcbiIsIi8qKlxuICogSGVscGVycy5cbiAqL1xuXG52YXIgcyA9IDEwMDA7XG52YXIgbSA9IHMgKiA2MDtcbnZhciBoID0gbSAqIDYwO1xudmFyIGQgPSBoICogMjQ7XG52YXIgdyA9IGQgKiA3O1xudmFyIHkgPSBkICogMzY1LjI1O1xuXG4vKipcbiAqIFBhcnNlIG9yIGZvcm1hdCB0aGUgZ2l2ZW4gYHZhbGAuXG4gKlxuICogT3B0aW9uczpcbiAqXG4gKiAgLSBgbG9uZ2AgdmVyYm9zZSBmb3JtYXR0aW5nIFtmYWxzZV1cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ3xOdW1iZXJ9IHZhbFxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zXVxuICogQHRocm93cyB7RXJyb3J9IHRocm93IGFuIGVycm9yIGlmIHZhbCBpcyBub3QgYSBub24tZW1wdHkgc3RyaW5nIG9yIGEgbnVtYmVyXG4gKiBAcmV0dXJuIHtTdHJpbmd8TnVtYmVyfVxuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICh2YWwsIG9wdGlvbnMpIHtcbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gIHZhciB0eXBlID0gdHlwZW9mIHZhbDtcbiAgaWYgKHR5cGUgPT09ICdzdHJpbmcnICYmIHZhbC5sZW5ndGggPiAwKSB7XG4gICAgcmV0dXJuIHBhcnNlKHZhbCk7XG4gIH0gZWxzZSBpZiAodHlwZSA9PT0gJ251bWJlcicgJiYgaXNGaW5pdGUodmFsKSkge1xuICAgIHJldHVybiBvcHRpb25zLmxvbmcgPyBmbXRMb25nKHZhbCkgOiBmbXRTaG9ydCh2YWwpO1xuICB9XG4gIHRocm93IG5ldyBFcnJvcihcbiAgICAndmFsIGlzIG5vdCBhIG5vbi1lbXB0eSBzdHJpbmcgb3IgYSB2YWxpZCBudW1iZXIuIHZhbD0nICtcbiAgICAgIEpTT04uc3RyaW5naWZ5KHZhbClcbiAgKTtcbn07XG5cbi8qKlxuICogUGFyc2UgdGhlIGdpdmVuIGBzdHJgIGFuZCByZXR1cm4gbWlsbGlzZWNvbmRzLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzdHJcbiAqIEByZXR1cm4ge051bWJlcn1cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIHBhcnNlKHN0cikge1xuICBzdHIgPSBTdHJpbmcoc3RyKTtcbiAgaWYgKHN0ci5sZW5ndGggPiAxMDApIHtcbiAgICByZXR1cm47XG4gIH1cbiAgdmFyIG1hdGNoID0gL14oLT8oPzpcXGQrKT9cXC4/XFxkKykgKihtaWxsaXNlY29uZHM/fG1zZWNzP3xtc3xzZWNvbmRzP3xzZWNzP3xzfG1pbnV0ZXM/fG1pbnM/fG18aG91cnM/fGhycz98aHxkYXlzP3xkfHdlZWtzP3x3fHllYXJzP3x5cnM/fHkpPyQvaS5leGVjKFxuICAgIHN0clxuICApO1xuICBpZiAoIW1hdGNoKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBuID0gcGFyc2VGbG9hdChtYXRjaFsxXSk7XG4gIHZhciB0eXBlID0gKG1hdGNoWzJdIHx8ICdtcycpLnRvTG93ZXJDYXNlKCk7XG4gIHN3aXRjaCAodHlwZSkge1xuICAgIGNhc2UgJ3llYXJzJzpcbiAgICBjYXNlICd5ZWFyJzpcbiAgICBjYXNlICd5cnMnOlxuICAgIGNhc2UgJ3lyJzpcbiAgICBjYXNlICd5JzpcbiAgICAgIHJldHVybiBuICogeTtcbiAgICBjYXNlICd3ZWVrcyc6XG4gICAgY2FzZSAnd2Vlayc6XG4gICAgY2FzZSAndyc6XG4gICAgICByZXR1cm4gbiAqIHc7XG4gICAgY2FzZSAnZGF5cyc6XG4gICAgY2FzZSAnZGF5JzpcbiAgICBjYXNlICdkJzpcbiAgICAgIHJldHVybiBuICogZDtcbiAgICBjYXNlICdob3Vycyc6XG4gICAgY2FzZSAnaG91cic6XG4gICAgY2FzZSAnaHJzJzpcbiAgICBjYXNlICdocic6XG4gICAgY2FzZSAnaCc6XG4gICAgICByZXR1cm4gbiAqIGg7XG4gICAgY2FzZSAnbWludXRlcyc6XG4gICAgY2FzZSAnbWludXRlJzpcbiAgICBjYXNlICdtaW5zJzpcbiAgICBjYXNlICdtaW4nOlxuICAgIGNhc2UgJ20nOlxuICAgICAgcmV0dXJuIG4gKiBtO1xuICAgIGNhc2UgJ3NlY29uZHMnOlxuICAgIGNhc2UgJ3NlY29uZCc6XG4gICAgY2FzZSAnc2Vjcyc6XG4gICAgY2FzZSAnc2VjJzpcbiAgICBjYXNlICdzJzpcbiAgICAgIHJldHVybiBuICogcztcbiAgICBjYXNlICdtaWxsaXNlY29uZHMnOlxuICAgIGNhc2UgJ21pbGxpc2Vjb25kJzpcbiAgICBjYXNlICdtc2Vjcyc6XG4gICAgY2FzZSAnbXNlYyc6XG4gICAgY2FzZSAnbXMnOlxuICAgICAgcmV0dXJuIG47XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuLyoqXG4gKiBTaG9ydCBmb3JtYXQgZm9yIGBtc2AuXG4gKlxuICogQHBhcmFtIHtOdW1iZXJ9IG1zXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuXG5mdW5jdGlvbiBmbXRTaG9ydChtcykge1xuICB2YXIgbXNBYnMgPSBNYXRoLmFicyhtcyk7XG4gIGlmIChtc0FicyA+PSBkKSB7XG4gICAgcmV0dXJuIE1hdGgucm91bmQobXMgLyBkKSArICdkJztcbiAgfVxuICBpZiAobXNBYnMgPj0gaCkge1xuICAgIHJldHVybiBNYXRoLnJvdW5kKG1zIC8gaCkgKyAnaCc7XG4gIH1cbiAgaWYgKG1zQWJzID49IG0pIHtcbiAgICByZXR1cm4gTWF0aC5yb3VuZChtcyAvIG0pICsgJ20nO1xuICB9XG4gIGlmIChtc0FicyA+PSBzKSB7XG4gICAgcmV0dXJuIE1hdGgucm91bmQobXMgLyBzKSArICdzJztcbiAgfVxuICByZXR1cm4gbXMgKyAnbXMnO1xufVxuXG4vKipcbiAqIExvbmcgZm9ybWF0IGZvciBgbXNgLlxuICpcbiAqIEBwYXJhbSB7TnVtYmVyfSBtc1xuICogQHJldHVybiB7U3RyaW5nfVxuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gZm10TG9uZyhtcykge1xuICB2YXIgbXNBYnMgPSBNYXRoLmFicyhtcyk7XG4gIGlmIChtc0FicyA+PSBkKSB7XG4gICAgcmV0dXJuIHBsdXJhbChtcywgbXNBYnMsIGQsICdkYXknKTtcbiAgfVxuICBpZiAobXNBYnMgPj0gaCkge1xuICAgIHJldHVybiBwbHVyYWwobXMsIG1zQWJzLCBoLCAnaG91cicpO1xuICB9XG4gIGlmIChtc0FicyA+PSBtKSB7XG4gICAgcmV0dXJuIHBsdXJhbChtcywgbXNBYnMsIG0sICdtaW51dGUnKTtcbiAgfVxuICBpZiAobXNBYnMgPj0gcykge1xuICAgIHJldHVybiBwbHVyYWwobXMsIG1zQWJzLCBzLCAnc2Vjb25kJyk7XG4gIH1cbiAgcmV0dXJuIG1zICsgJyBtcyc7XG59XG5cbi8qKlxuICogUGx1cmFsaXphdGlvbiBoZWxwZXIuXG4gKi9cblxuZnVuY3Rpb24gcGx1cmFsKG1zLCBtc0FicywgbiwgbmFtZSkge1xuICB2YXIgaXNQbHVyYWwgPSBtc0FicyA+PSBuICogMS41O1xuICByZXR1cm4gTWF0aC5yb3VuZChtcyAvIG4pICsgJyAnICsgbmFtZSArIChpc1BsdXJhbCA/ICdzJyA6ICcnKTtcbn1cbiIsIi8qIGVzbGludC1lbnYgbm9kZSAqL1xuJ3VzZSBzdHJpY3QnO1xuXG4vLyBTRFAgaGVscGVycy5cbmNvbnN0IFNEUFV0aWxzID0ge307XG5cbi8vIEdlbmVyYXRlIGFuIGFscGhhbnVtZXJpYyBpZGVudGlmaWVyIGZvciBjbmFtZSBvciBtaWRzLlxuLy8gVE9ETzogdXNlIFVVSURzIGluc3RlYWQ/IGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL2plZC85ODI4ODNcblNEUFV0aWxzLmdlbmVyYXRlSWRlbnRpZmllciA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc3Vic3RyaW5nKDIsIDEyKTtcbn07XG5cbi8vIFRoZSBSVENQIENOQU1FIHVzZWQgYnkgYWxsIHBlZXJjb25uZWN0aW9ucyBmcm9tIHRoZSBzYW1lIEpTLlxuU0RQVXRpbHMubG9jYWxDTmFtZSA9IFNEUFV0aWxzLmdlbmVyYXRlSWRlbnRpZmllcigpO1xuXG4vLyBTcGxpdHMgU0RQIGludG8gbGluZXMsIGRlYWxpbmcgd2l0aCBib3RoIENSTEYgYW5kIExGLlxuU0RQVXRpbHMuc3BsaXRMaW5lcyA9IGZ1bmN0aW9uKGJsb2IpIHtcbiAgcmV0dXJuIGJsb2IudHJpbSgpLnNwbGl0KCdcXG4nKS5tYXAobGluZSA9PiBsaW5lLnRyaW0oKSk7XG59O1xuLy8gU3BsaXRzIFNEUCBpbnRvIHNlc3Npb25wYXJ0IGFuZCBtZWRpYXNlY3Rpb25zLiBFbnN1cmVzIENSTEYuXG5TRFBVdGlscy5zcGxpdFNlY3Rpb25zID0gZnVuY3Rpb24oYmxvYikge1xuICBjb25zdCBwYXJ0cyA9IGJsb2Iuc3BsaXQoJ1xcbm09Jyk7XG4gIHJldHVybiBwYXJ0cy5tYXAoKHBhcnQsIGluZGV4KSA9PiAoaW5kZXggPiAwID9cbiAgICAnbT0nICsgcGFydCA6IHBhcnQpLnRyaW0oKSArICdcXHJcXG4nKTtcbn07XG5cbi8vIFJldHVybnMgdGhlIHNlc3Npb24gZGVzY3JpcHRpb24uXG5TRFBVdGlscy5nZXREZXNjcmlwdGlvbiA9IGZ1bmN0aW9uKGJsb2IpIHtcbiAgY29uc3Qgc2VjdGlvbnMgPSBTRFBVdGlscy5zcGxpdFNlY3Rpb25zKGJsb2IpO1xuICByZXR1cm4gc2VjdGlvbnMgJiYgc2VjdGlvbnNbMF07XG59O1xuXG4vLyBSZXR1cm5zIHRoZSBpbmRpdmlkdWFsIG1lZGlhIHNlY3Rpb25zLlxuU0RQVXRpbHMuZ2V0TWVkaWFTZWN0aW9ucyA9IGZ1bmN0aW9uKGJsb2IpIHtcbiAgY29uc3Qgc2VjdGlvbnMgPSBTRFBVdGlscy5zcGxpdFNlY3Rpb25zKGJsb2IpO1xuICBzZWN0aW9ucy5zaGlmdCgpO1xuICByZXR1cm4gc2VjdGlvbnM7XG59O1xuXG4vLyBSZXR1cm5zIGxpbmVzIHRoYXQgc3RhcnQgd2l0aCBhIGNlcnRhaW4gcHJlZml4LlxuU0RQVXRpbHMubWF0Y2hQcmVmaXggPSBmdW5jdGlvbihibG9iLCBwcmVmaXgpIHtcbiAgcmV0dXJuIFNEUFV0aWxzLnNwbGl0TGluZXMoYmxvYikuZmlsdGVyKGxpbmUgPT4gbGluZS5pbmRleE9mKHByZWZpeCkgPT09IDApO1xufTtcblxuLy8gUGFyc2VzIGFuIElDRSBjYW5kaWRhdGUgbGluZS4gU2FtcGxlIGlucHV0OlxuLy8gY2FuZGlkYXRlOjcwMjc4NjM1MCAyIHVkcCA0MTgxOTkwMiA4LjguOC44IDYwNzY5IHR5cCByZWxheSByYWRkciA4LjguOC44XG4vLyBycG9ydCA1NTk5NlwiXG4vLyBJbnB1dCBjYW4gYmUgcHJlZml4ZWQgd2l0aCBhPS5cblNEUFV0aWxzLnBhcnNlQ2FuZGlkYXRlID0gZnVuY3Rpb24obGluZSkge1xuICBsZXQgcGFydHM7XG4gIC8vIFBhcnNlIGJvdGggdmFyaWFudHMuXG4gIGlmIChsaW5lLmluZGV4T2YoJ2E9Y2FuZGlkYXRlOicpID09PSAwKSB7XG4gICAgcGFydHMgPSBsaW5lLnN1YnN0cmluZygxMikuc3BsaXQoJyAnKTtcbiAgfSBlbHNlIHtcbiAgICBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDEwKS5zcGxpdCgnICcpO1xuICB9XG5cbiAgY29uc3QgY2FuZGlkYXRlID0ge1xuICAgIGZvdW5kYXRpb246IHBhcnRzWzBdLFxuICAgIGNvbXBvbmVudDogezE6ICdydHAnLCAyOiAncnRjcCd9W3BhcnRzWzFdXSB8fCBwYXJ0c1sxXSxcbiAgICBwcm90b2NvbDogcGFydHNbMl0udG9Mb3dlckNhc2UoKSxcbiAgICBwcmlvcml0eTogcGFyc2VJbnQocGFydHNbM10sIDEwKSxcbiAgICBpcDogcGFydHNbNF0sXG4gICAgYWRkcmVzczogcGFydHNbNF0sIC8vIGFkZHJlc3MgaXMgYW4gYWxpYXMgZm9yIGlwLlxuICAgIHBvcnQ6IHBhcnNlSW50KHBhcnRzWzVdLCAxMCksXG4gICAgLy8gc2tpcCBwYXJ0c1s2XSA9PSAndHlwJ1xuICAgIHR5cGU6IHBhcnRzWzddLFxuICB9O1xuXG4gIGZvciAobGV0IGkgPSA4OyBpIDwgcGFydHMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICBzd2l0Y2ggKHBhcnRzW2ldKSB7XG4gICAgICBjYXNlICdyYWRkcic6XG4gICAgICAgIGNhbmRpZGF0ZS5yZWxhdGVkQWRkcmVzcyA9IHBhcnRzW2kgKyAxXTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdycG9ydCc6XG4gICAgICAgIGNhbmRpZGF0ZS5yZWxhdGVkUG9ydCA9IHBhcnNlSW50KHBhcnRzW2kgKyAxXSwgMTApO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3RjcHR5cGUnOlxuICAgICAgICBjYW5kaWRhdGUudGNwVHlwZSA9IHBhcnRzW2kgKyAxXTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICd1ZnJhZyc6XG4gICAgICAgIGNhbmRpZGF0ZS51ZnJhZyA9IHBhcnRzW2kgKyAxXTsgLy8gZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkuXG4gICAgICAgIGNhbmRpZGF0ZS51c2VybmFtZUZyYWdtZW50ID0gcGFydHNbaSArIDFdO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6IC8vIGV4dGVuc2lvbiBoYW5kbGluZywgaW4gcGFydGljdWxhciB1ZnJhZy4gRG9uJ3Qgb3ZlcndyaXRlLlxuICAgICAgICBpZiAoY2FuZGlkYXRlW3BhcnRzW2ldXSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgY2FuZGlkYXRlW3BhcnRzW2ldXSA9IHBhcnRzW2kgKyAxXTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNhbmRpZGF0ZTtcbn07XG5cbi8vIFRyYW5zbGF0ZXMgYSBjYW5kaWRhdGUgb2JqZWN0IGludG8gU0RQIGNhbmRpZGF0ZSBhdHRyaWJ1dGUuXG4vLyBUaGlzIGRvZXMgbm90IGluY2x1ZGUgdGhlIGE9IHByZWZpeCFcblNEUFV0aWxzLndyaXRlQ2FuZGlkYXRlID0gZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gIGNvbnN0IHNkcCA9IFtdO1xuICBzZHAucHVzaChjYW5kaWRhdGUuZm91bmRhdGlvbik7XG5cbiAgY29uc3QgY29tcG9uZW50ID0gY2FuZGlkYXRlLmNvbXBvbmVudDtcbiAgaWYgKGNvbXBvbmVudCA9PT0gJ3J0cCcpIHtcbiAgICBzZHAucHVzaCgxKTtcbiAgfSBlbHNlIGlmIChjb21wb25lbnQgPT09ICdydGNwJykge1xuICAgIHNkcC5wdXNoKDIpO1xuICB9IGVsc2Uge1xuICAgIHNkcC5wdXNoKGNvbXBvbmVudCk7XG4gIH1cbiAgc2RwLnB1c2goY2FuZGlkYXRlLnByb3RvY29sLnRvVXBwZXJDYXNlKCkpO1xuICBzZHAucHVzaChjYW5kaWRhdGUucHJpb3JpdHkpO1xuICBzZHAucHVzaChjYW5kaWRhdGUuYWRkcmVzcyB8fCBjYW5kaWRhdGUuaXApO1xuICBzZHAucHVzaChjYW5kaWRhdGUucG9ydCk7XG5cbiAgY29uc3QgdHlwZSA9IGNhbmRpZGF0ZS50eXBlO1xuICBzZHAucHVzaCgndHlwJyk7XG4gIHNkcC5wdXNoKHR5cGUpO1xuICBpZiAodHlwZSAhPT0gJ2hvc3QnICYmIGNhbmRpZGF0ZS5yZWxhdGVkQWRkcmVzcyAmJlxuICAgICAgY2FuZGlkYXRlLnJlbGF0ZWRQb3J0KSB7XG4gICAgc2RwLnB1c2goJ3JhZGRyJyk7XG4gICAgc2RwLnB1c2goY2FuZGlkYXRlLnJlbGF0ZWRBZGRyZXNzKTtcbiAgICBzZHAucHVzaCgncnBvcnQnKTtcbiAgICBzZHAucHVzaChjYW5kaWRhdGUucmVsYXRlZFBvcnQpO1xuICB9XG4gIGlmIChjYW5kaWRhdGUudGNwVHlwZSAmJiBjYW5kaWRhdGUucHJvdG9jb2wudG9Mb3dlckNhc2UoKSA9PT0gJ3RjcCcpIHtcbiAgICBzZHAucHVzaCgndGNwdHlwZScpO1xuICAgIHNkcC5wdXNoKGNhbmRpZGF0ZS50Y3BUeXBlKTtcbiAgfVxuICBpZiAoY2FuZGlkYXRlLnVzZXJuYW1lRnJhZ21lbnQgfHwgY2FuZGlkYXRlLnVmcmFnKSB7XG4gICAgc2RwLnB1c2goJ3VmcmFnJyk7XG4gICAgc2RwLnB1c2goY2FuZGlkYXRlLnVzZXJuYW1lRnJhZ21lbnQgfHwgY2FuZGlkYXRlLnVmcmFnKTtcbiAgfVxuICByZXR1cm4gJ2NhbmRpZGF0ZTonICsgc2RwLmpvaW4oJyAnKTtcbn07XG5cbi8vIFBhcnNlcyBhbiBpY2Utb3B0aW9ucyBsaW5lLCByZXR1cm5zIGFuIGFycmF5IG9mIG9wdGlvbiB0YWdzLlxuLy8gU2FtcGxlIGlucHV0OlxuLy8gYT1pY2Utb3B0aW9uczpmb28gYmFyXG5TRFBVdGlscy5wYXJzZUljZU9wdGlvbnMgPSBmdW5jdGlvbihsaW5lKSB7XG4gIHJldHVybiBsaW5lLnN1YnN0cmluZygxNCkuc3BsaXQoJyAnKTtcbn07XG5cbi8vIFBhcnNlcyBhIHJ0cG1hcCBsaW5lLCByZXR1cm5zIFJUQ1J0cENvZGRlY1BhcmFtZXRlcnMuIFNhbXBsZSBpbnB1dDpcbi8vIGE9cnRwbWFwOjExMSBvcHVzLzQ4MDAwLzJcblNEUFV0aWxzLnBhcnNlUnRwTWFwID0gZnVuY3Rpb24obGluZSkge1xuICBsZXQgcGFydHMgPSBsaW5lLnN1YnN0cmluZyg5KS5zcGxpdCgnICcpO1xuICBjb25zdCBwYXJzZWQgPSB7XG4gICAgcGF5bG9hZFR5cGU6IHBhcnNlSW50KHBhcnRzLnNoaWZ0KCksIDEwKSwgLy8gd2FzOiBpZFxuICB9O1xuXG4gIHBhcnRzID0gcGFydHNbMF0uc3BsaXQoJy8nKTtcblxuICBwYXJzZWQubmFtZSA9IHBhcnRzWzBdO1xuICBwYXJzZWQuY2xvY2tSYXRlID0gcGFyc2VJbnQocGFydHNbMV0sIDEwKTsgLy8gd2FzOiBjbG9ja3JhdGVcbiAgcGFyc2VkLmNoYW5uZWxzID0gcGFydHMubGVuZ3RoID09PSAzID8gcGFyc2VJbnQocGFydHNbMl0sIDEwKSA6IDE7XG4gIC8vIGxlZ2FjeSBhbGlhcywgZ290IHJlbmFtZWQgYmFjayB0byBjaGFubmVscyBpbiBPUlRDLlxuICBwYXJzZWQubnVtQ2hhbm5lbHMgPSBwYXJzZWQuY2hhbm5lbHM7XG4gIHJldHVybiBwYXJzZWQ7XG59O1xuXG4vLyBHZW5lcmF0ZXMgYSBydHBtYXAgbGluZSBmcm9tIFJUQ1J0cENvZGVjQ2FwYWJpbGl0eSBvclxuLy8gUlRDUnRwQ29kZWNQYXJhbWV0ZXJzLlxuU0RQVXRpbHMud3JpdGVSdHBNYXAgPSBmdW5jdGlvbihjb2RlYykge1xuICBsZXQgcHQgPSBjb2RlYy5wYXlsb2FkVHlwZTtcbiAgaWYgKGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlICE9PSB1bmRlZmluZWQpIHtcbiAgICBwdCA9IGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlO1xuICB9XG4gIGNvbnN0IGNoYW5uZWxzID0gY29kZWMuY2hhbm5lbHMgfHwgY29kZWMubnVtQ2hhbm5lbHMgfHwgMTtcbiAgcmV0dXJuICdhPXJ0cG1hcDonICsgcHQgKyAnICcgKyBjb2RlYy5uYW1lICsgJy8nICsgY29kZWMuY2xvY2tSYXRlICtcbiAgICAgIChjaGFubmVscyAhPT0gMSA/ICcvJyArIGNoYW5uZWxzIDogJycpICsgJ1xcclxcbic7XG59O1xuXG4vLyBQYXJzZXMgYSBleHRtYXAgbGluZSAoaGVhZGVyZXh0ZW5zaW9uIGZyb20gUkZDIDUyODUpLiBTYW1wbGUgaW5wdXQ6XG4vLyBhPWV4dG1hcDoyIHVybjppZXRmOnBhcmFtczpydHAtaGRyZXh0OnRvZmZzZXRcbi8vIGE9ZXh0bWFwOjIvc2VuZG9ubHkgdXJuOmlldGY6cGFyYW1zOnJ0cC1oZHJleHQ6dG9mZnNldFxuU0RQVXRpbHMucGFyc2VFeHRtYXAgPSBmdW5jdGlvbihsaW5lKSB7XG4gIGNvbnN0IHBhcnRzID0gbGluZS5zdWJzdHJpbmcoOSkuc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICBpZDogcGFyc2VJbnQocGFydHNbMF0sIDEwKSxcbiAgICBkaXJlY3Rpb246IHBhcnRzWzBdLmluZGV4T2YoJy8nKSA+IDAgPyBwYXJ0c1swXS5zcGxpdCgnLycpWzFdIDogJ3NlbmRyZWN2JyxcbiAgICB1cmk6IHBhcnRzWzFdLFxuICAgIGF0dHJpYnV0ZXM6IHBhcnRzLnNsaWNlKDIpLmpvaW4oJyAnKSxcbiAgfTtcbn07XG5cbi8vIEdlbmVyYXRlcyBhbiBleHRtYXAgbGluZSBmcm9tIFJUQ1J0cEhlYWRlckV4dGVuc2lvblBhcmFtZXRlcnMgb3Jcbi8vIFJUQ1J0cEhlYWRlckV4dGVuc2lvbi5cblNEUFV0aWxzLndyaXRlRXh0bWFwID0gZnVuY3Rpb24oaGVhZGVyRXh0ZW5zaW9uKSB7XG4gIHJldHVybiAnYT1leHRtYXA6JyArIChoZWFkZXJFeHRlbnNpb24uaWQgfHwgaGVhZGVyRXh0ZW5zaW9uLnByZWZlcnJlZElkKSArXG4gICAgICAoaGVhZGVyRXh0ZW5zaW9uLmRpcmVjdGlvbiAmJiBoZWFkZXJFeHRlbnNpb24uZGlyZWN0aW9uICE9PSAnc2VuZHJlY3YnXG4gICAgICAgID8gJy8nICsgaGVhZGVyRXh0ZW5zaW9uLmRpcmVjdGlvblxuICAgICAgICA6ICcnKSArXG4gICAgICAnICcgKyBoZWFkZXJFeHRlbnNpb24udXJpICtcbiAgICAgIChoZWFkZXJFeHRlbnNpb24uYXR0cmlidXRlcyA/ICcgJyArIGhlYWRlckV4dGVuc2lvbi5hdHRyaWJ1dGVzIDogJycpICtcbiAgICAgICdcXHJcXG4nO1xufTtcblxuLy8gUGFyc2VzIGEgZm10cCBsaW5lLCByZXR1cm5zIGRpY3Rpb25hcnkuIFNhbXBsZSBpbnB1dDpcbi8vIGE9Zm10cDo5NiB2YnI9b247Y25nPW9uXG4vLyBBbHNvIGRlYWxzIHdpdGggdmJyPW9uOyBjbmc9b25cblNEUFV0aWxzLnBhcnNlRm10cCA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgY29uc3QgcGFyc2VkID0ge307XG4gIGxldCBrdjtcbiAgY29uc3QgcGFydHMgPSBsaW5lLnN1YnN0cmluZyhsaW5lLmluZGV4T2YoJyAnKSArIDEpLnNwbGl0KCc7Jyk7XG4gIGZvciAobGV0IGogPSAwOyBqIDwgcGFydHMubGVuZ3RoOyBqKyspIHtcbiAgICBrdiA9IHBhcnRzW2pdLnRyaW0oKS5zcGxpdCgnPScpO1xuICAgIHBhcnNlZFtrdlswXS50cmltKCldID0ga3ZbMV07XG4gIH1cbiAgcmV0dXJuIHBhcnNlZDtcbn07XG5cbi8vIEdlbmVyYXRlcyBhIGZtdHAgbGluZSBmcm9tIFJUQ1J0cENvZGVjQ2FwYWJpbGl0eSBvciBSVENSdHBDb2RlY1BhcmFtZXRlcnMuXG5TRFBVdGlscy53cml0ZUZtdHAgPSBmdW5jdGlvbihjb2RlYykge1xuICBsZXQgbGluZSA9ICcnO1xuICBsZXQgcHQgPSBjb2RlYy5wYXlsb2FkVHlwZTtcbiAgaWYgKGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlICE9PSB1bmRlZmluZWQpIHtcbiAgICBwdCA9IGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlO1xuICB9XG4gIGlmIChjb2RlYy5wYXJhbWV0ZXJzICYmIE9iamVjdC5rZXlzKGNvZGVjLnBhcmFtZXRlcnMpLmxlbmd0aCkge1xuICAgIGNvbnN0IHBhcmFtcyA9IFtdO1xuICAgIE9iamVjdC5rZXlzKGNvZGVjLnBhcmFtZXRlcnMpLmZvckVhY2gocGFyYW0gPT4ge1xuICAgICAgaWYgKGNvZGVjLnBhcmFtZXRlcnNbcGFyYW1dICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcGFyYW1zLnB1c2gocGFyYW0gKyAnPScgKyBjb2RlYy5wYXJhbWV0ZXJzW3BhcmFtXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwYXJhbXMucHVzaChwYXJhbSk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgbGluZSArPSAnYT1mbXRwOicgKyBwdCArICcgJyArIHBhcmFtcy5qb2luKCc7JykgKyAnXFxyXFxuJztcbiAgfVxuICByZXR1cm4gbGluZTtcbn07XG5cbi8vIFBhcnNlcyBhIHJ0Y3AtZmIgbGluZSwgcmV0dXJucyBSVENQUnRjcEZlZWRiYWNrIG9iamVjdC4gU2FtcGxlIGlucHV0OlxuLy8gYT1ydGNwLWZiOjk4IG5hY2sgcnBzaVxuU0RQVXRpbHMucGFyc2VSdGNwRmIgPSBmdW5jdGlvbihsaW5lKSB7XG4gIGNvbnN0IHBhcnRzID0gbGluZS5zdWJzdHJpbmcobGluZS5pbmRleE9mKCcgJykgKyAxKS5zcGxpdCgnICcpO1xuICByZXR1cm4ge1xuICAgIHR5cGU6IHBhcnRzLnNoaWZ0KCksXG4gICAgcGFyYW1ldGVyOiBwYXJ0cy5qb2luKCcgJyksXG4gIH07XG59O1xuXG4vLyBHZW5lcmF0ZSBhPXJ0Y3AtZmIgbGluZXMgZnJvbSBSVENSdHBDb2RlY0NhcGFiaWxpdHkgb3IgUlRDUnRwQ29kZWNQYXJhbWV0ZXJzLlxuU0RQVXRpbHMud3JpdGVSdGNwRmIgPSBmdW5jdGlvbihjb2RlYykge1xuICBsZXQgbGluZXMgPSAnJztcbiAgbGV0IHB0ID0gY29kZWMucGF5bG9hZFR5cGU7XG4gIGlmIChjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcHQgPSBjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZTtcbiAgfVxuICBpZiAoY29kZWMucnRjcEZlZWRiYWNrICYmIGNvZGVjLnJ0Y3BGZWVkYmFjay5sZW5ndGgpIHtcbiAgICAvLyBGSVhNRTogc3BlY2lhbCBoYW5kbGluZyBmb3IgdHJyLWludD9cbiAgICBjb2RlYy5ydGNwRmVlZGJhY2suZm9yRWFjaChmYiA9PiB7XG4gICAgICBsaW5lcyArPSAnYT1ydGNwLWZiOicgKyBwdCArICcgJyArIGZiLnR5cGUgK1xuICAgICAgKGZiLnBhcmFtZXRlciAmJiBmYi5wYXJhbWV0ZXIubGVuZ3RoID8gJyAnICsgZmIucGFyYW1ldGVyIDogJycpICtcbiAgICAgICAgICAnXFxyXFxuJztcbiAgICB9KTtcbiAgfVxuICByZXR1cm4gbGluZXM7XG59O1xuXG4vLyBQYXJzZXMgYSBSRkMgNTU3NiBzc3JjIG1lZGlhIGF0dHJpYnV0ZS4gU2FtcGxlIGlucHV0OlxuLy8gYT1zc3JjOjM3MzU5Mjg1NTkgY25hbWU6c29tZXRoaW5nXG5TRFBVdGlscy5wYXJzZVNzcmNNZWRpYSA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgY29uc3Qgc3AgPSBsaW5lLmluZGV4T2YoJyAnKTtcbiAgY29uc3QgcGFydHMgPSB7XG4gICAgc3NyYzogcGFyc2VJbnQobGluZS5zdWJzdHJpbmcoNywgc3ApLCAxMCksXG4gIH07XG4gIGNvbnN0IGNvbG9uID0gbGluZS5pbmRleE9mKCc6Jywgc3ApO1xuICBpZiAoY29sb24gPiAtMSkge1xuICAgIHBhcnRzLmF0dHJpYnV0ZSA9IGxpbmUuc3Vic3RyaW5nKHNwICsgMSwgY29sb24pO1xuICAgIHBhcnRzLnZhbHVlID0gbGluZS5zdWJzdHJpbmcoY29sb24gKyAxKTtcbiAgfSBlbHNlIHtcbiAgICBwYXJ0cy5hdHRyaWJ1dGUgPSBsaW5lLnN1YnN0cmluZyhzcCArIDEpO1xuICB9XG4gIHJldHVybiBwYXJ0cztcbn07XG5cbi8vIFBhcnNlIGEgc3NyYy1ncm91cCBsaW5lIChzZWUgUkZDIDU1NzYpLiBTYW1wbGUgaW5wdXQ6XG4vLyBhPXNzcmMtZ3JvdXA6c2VtYW50aWNzIDEyIDM0XG5TRFBVdGlscy5wYXJzZVNzcmNHcm91cCA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgY29uc3QgcGFydHMgPSBsaW5lLnN1YnN0cmluZygxMykuc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICBzZW1hbnRpY3M6IHBhcnRzLnNoaWZ0KCksXG4gICAgc3NyY3M6IHBhcnRzLm1hcChzc3JjID0+IHBhcnNlSW50KHNzcmMsIDEwKSksXG4gIH07XG59O1xuXG4vLyBFeHRyYWN0cyB0aGUgTUlEIChSRkMgNTg4OCkgZnJvbSBhIG1lZGlhIHNlY3Rpb24uXG4vLyBSZXR1cm5zIHRoZSBNSUQgb3IgdW5kZWZpbmVkIGlmIG5vIG1pZCBsaW5lIHdhcyBmb3VuZC5cblNEUFV0aWxzLmdldE1pZCA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICBjb25zdCBtaWQgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPW1pZDonKVswXTtcbiAgaWYgKG1pZCkge1xuICAgIHJldHVybiBtaWQuc3Vic3RyaW5nKDYpO1xuICB9XG59O1xuXG4vLyBQYXJzZXMgYSBmaW5nZXJwcmludCBsaW5lIGZvciBEVExTLVNSVFAuXG5TRFBVdGlscy5wYXJzZUZpbmdlcnByaW50ID0gZnVuY3Rpb24obGluZSkge1xuICBjb25zdCBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDE0KS5zcGxpdCgnICcpO1xuICByZXR1cm4ge1xuICAgIGFsZ29yaXRobTogcGFydHNbMF0udG9Mb3dlckNhc2UoKSwgLy8gYWxnb3JpdGhtIGlzIGNhc2Utc2Vuc2l0aXZlIGluIEVkZ2UuXG4gICAgdmFsdWU6IHBhcnRzWzFdLnRvVXBwZXJDYXNlKCksIC8vIHRoZSBkZWZpbml0aW9uIGlzIHVwcGVyLWNhc2UgaW4gUkZDIDQ1NzIuXG4gIH07XG59O1xuXG4vLyBFeHRyYWN0cyBEVExTIHBhcmFtZXRlcnMgZnJvbSBTRFAgbWVkaWEgc2VjdGlvbiBvciBzZXNzaW9ucGFydC5cbi8vIEZJWE1FOiBmb3IgY29uc2lzdGVuY3kgd2l0aCBvdGhlciBmdW5jdGlvbnMgdGhpcyBzaG91bGQgb25seVxuLy8gICBnZXQgdGhlIGZpbmdlcnByaW50IGxpbmUgYXMgaW5wdXQuIFNlZSBhbHNvIGdldEljZVBhcmFtZXRlcnMuXG5TRFBVdGlscy5nZXREdGxzUGFyYW1ldGVycyA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbiwgc2Vzc2lvbnBhcnQpIHtcbiAgY29uc3QgbGluZXMgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24gKyBzZXNzaW9ucGFydCxcbiAgICAnYT1maW5nZXJwcmludDonKTtcbiAgLy8gTm90ZTogYT1zZXR1cCBsaW5lIGlzIGlnbm9yZWQgc2luY2Ugd2UgdXNlIHRoZSAnYXV0bycgcm9sZSBpbiBFZGdlLlxuICByZXR1cm4ge1xuICAgIHJvbGU6ICdhdXRvJyxcbiAgICBmaW5nZXJwcmludHM6IGxpbmVzLm1hcChTRFBVdGlscy5wYXJzZUZpbmdlcnByaW50KSxcbiAgfTtcbn07XG5cbi8vIFNlcmlhbGl6ZXMgRFRMUyBwYXJhbWV0ZXJzIHRvIFNEUC5cblNEUFV0aWxzLndyaXRlRHRsc1BhcmFtZXRlcnMgPSBmdW5jdGlvbihwYXJhbXMsIHNldHVwVHlwZSkge1xuICBsZXQgc2RwID0gJ2E9c2V0dXA6JyArIHNldHVwVHlwZSArICdcXHJcXG4nO1xuICBwYXJhbXMuZmluZ2VycHJpbnRzLmZvckVhY2goZnAgPT4ge1xuICAgIHNkcCArPSAnYT1maW5nZXJwcmludDonICsgZnAuYWxnb3JpdGhtICsgJyAnICsgZnAudmFsdWUgKyAnXFxyXFxuJztcbiAgfSk7XG4gIHJldHVybiBzZHA7XG59O1xuXG4vLyBQYXJzZXMgYT1jcnlwdG8gbGluZXMgaW50b1xuLy8gICBodHRwczovL3Jhd2dpdC5jb20vYWJvYmEvZWRnZXJ0Yy9tYXN0ZXIvbXNvcnRjLXJzNC5odG1sI2RpY3Rpb25hcnktcnRjc3J0cHNkZXNwYXJhbWV0ZXJzLW1lbWJlcnNcblNEUFV0aWxzLnBhcnNlQ3J5cHRvTGluZSA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgY29uc3QgcGFydHMgPSBsaW5lLnN1YnN0cmluZyg5KS5zcGxpdCgnICcpO1xuICByZXR1cm4ge1xuICAgIHRhZzogcGFyc2VJbnQocGFydHNbMF0sIDEwKSxcbiAgICBjcnlwdG9TdWl0ZTogcGFydHNbMV0sXG4gICAga2V5UGFyYW1zOiBwYXJ0c1syXSxcbiAgICBzZXNzaW9uUGFyYW1zOiBwYXJ0cy5zbGljZSgzKSxcbiAgfTtcbn07XG5cblNEUFV0aWxzLndyaXRlQ3J5cHRvTGluZSA9IGZ1bmN0aW9uKHBhcmFtZXRlcnMpIHtcbiAgcmV0dXJuICdhPWNyeXB0bzonICsgcGFyYW1ldGVycy50YWcgKyAnICcgK1xuICAgIHBhcmFtZXRlcnMuY3J5cHRvU3VpdGUgKyAnICcgK1xuICAgICh0eXBlb2YgcGFyYW1ldGVycy5rZXlQYXJhbXMgPT09ICdvYmplY3QnXG4gICAgICA/IFNEUFV0aWxzLndyaXRlQ3J5cHRvS2V5UGFyYW1zKHBhcmFtZXRlcnMua2V5UGFyYW1zKVxuICAgICAgOiBwYXJhbWV0ZXJzLmtleVBhcmFtcykgK1xuICAgIChwYXJhbWV0ZXJzLnNlc3Npb25QYXJhbXMgPyAnICcgKyBwYXJhbWV0ZXJzLnNlc3Npb25QYXJhbXMuam9pbignICcpIDogJycpICtcbiAgICAnXFxyXFxuJztcbn07XG5cbi8vIFBhcnNlcyB0aGUgY3J5cHRvIGtleSBwYXJhbWV0ZXJzIGludG9cbi8vICAgaHR0cHM6Ly9yYXdnaXQuY29tL2Fib2JhL2VkZ2VydGMvbWFzdGVyL21zb3J0Yy1yczQuaHRtbCNydGNzcnRwa2V5cGFyYW0qXG5TRFBVdGlscy5wYXJzZUNyeXB0b0tleVBhcmFtcyA9IGZ1bmN0aW9uKGtleVBhcmFtcykge1xuICBpZiAoa2V5UGFyYW1zLmluZGV4T2YoJ2lubGluZTonKSAhPT0gMCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIGNvbnN0IHBhcnRzID0ga2V5UGFyYW1zLnN1YnN0cmluZyg3KS5zcGxpdCgnfCcpO1xuICByZXR1cm4ge1xuICAgIGtleU1ldGhvZDogJ2lubGluZScsXG4gICAga2V5U2FsdDogcGFydHNbMF0sXG4gICAgbGlmZVRpbWU6IHBhcnRzWzFdLFxuICAgIG1raVZhbHVlOiBwYXJ0c1syXSA/IHBhcnRzWzJdLnNwbGl0KCc6JylbMF0gOiB1bmRlZmluZWQsXG4gICAgbWtpTGVuZ3RoOiBwYXJ0c1syXSA/IHBhcnRzWzJdLnNwbGl0KCc6JylbMV0gOiB1bmRlZmluZWQsXG4gIH07XG59O1xuXG5TRFBVdGlscy53cml0ZUNyeXB0b0tleVBhcmFtcyA9IGZ1bmN0aW9uKGtleVBhcmFtcykge1xuICByZXR1cm4ga2V5UGFyYW1zLmtleU1ldGhvZCArICc6J1xuICAgICsga2V5UGFyYW1zLmtleVNhbHQgK1xuICAgIChrZXlQYXJhbXMubGlmZVRpbWUgPyAnfCcgKyBrZXlQYXJhbXMubGlmZVRpbWUgOiAnJykgK1xuICAgIChrZXlQYXJhbXMubWtpVmFsdWUgJiYga2V5UGFyYW1zLm1raUxlbmd0aFxuICAgICAgPyAnfCcgKyBrZXlQYXJhbXMubWtpVmFsdWUgKyAnOicgKyBrZXlQYXJhbXMubWtpTGVuZ3RoXG4gICAgICA6ICcnKTtcbn07XG5cbi8vIEV4dHJhY3RzIGFsbCBTREVTIHBhcmFtZXRlcnMuXG5TRFBVdGlscy5nZXRDcnlwdG9QYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZXNzaW9ucGFydCkge1xuICBjb25zdCBsaW5lcyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiArIHNlc3Npb25wYXJ0LFxuICAgICdhPWNyeXB0bzonKTtcbiAgcmV0dXJuIGxpbmVzLm1hcChTRFBVdGlscy5wYXJzZUNyeXB0b0xpbmUpO1xufTtcblxuLy8gUGFyc2VzIElDRSBpbmZvcm1hdGlvbiBmcm9tIFNEUCBtZWRpYSBzZWN0aW9uIG9yIHNlc3Npb25wYXJ0LlxuLy8gRklYTUU6IGZvciBjb25zaXN0ZW5jeSB3aXRoIG90aGVyIGZ1bmN0aW9ucyB0aGlzIHNob3VsZCBvbmx5XG4vLyAgIGdldCB0aGUgaWNlLXVmcmFnIGFuZCBpY2UtcHdkIGxpbmVzIGFzIGlucHV0LlxuU0RQVXRpbHMuZ2V0SWNlUGFyYW1ldGVycyA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbiwgc2Vzc2lvbnBhcnQpIHtcbiAgY29uc3QgdWZyYWcgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24gKyBzZXNzaW9ucGFydCxcbiAgICAnYT1pY2UtdWZyYWc6JylbMF07XG4gIGNvbnN0IHB3ZCA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiArIHNlc3Npb25wYXJ0LFxuICAgICdhPWljZS1wd2Q6JylbMF07XG4gIGlmICghKHVmcmFnICYmIHB3ZCkpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICByZXR1cm4ge1xuICAgIHVzZXJuYW1lRnJhZ21lbnQ6IHVmcmFnLnN1YnN0cmluZygxMiksXG4gICAgcGFzc3dvcmQ6IHB3ZC5zdWJzdHJpbmcoMTApLFxuICB9O1xufTtcblxuLy8gU2VyaWFsaXplcyBJQ0UgcGFyYW1ldGVycyB0byBTRFAuXG5TRFBVdGlscy53cml0ZUljZVBhcmFtZXRlcnMgPSBmdW5jdGlvbihwYXJhbXMpIHtcbiAgbGV0IHNkcCA9ICdhPWljZS11ZnJhZzonICsgcGFyYW1zLnVzZXJuYW1lRnJhZ21lbnQgKyAnXFxyXFxuJyArXG4gICAgICAnYT1pY2UtcHdkOicgKyBwYXJhbXMucGFzc3dvcmQgKyAnXFxyXFxuJztcbiAgaWYgKHBhcmFtcy5pY2VMaXRlKSB7XG4gICAgc2RwICs9ICdhPWljZS1saXRlXFxyXFxuJztcbiAgfVxuICByZXR1cm4gc2RwO1xufTtcblxuLy8gUGFyc2VzIHRoZSBTRFAgbWVkaWEgc2VjdGlvbiBhbmQgcmV0dXJucyBSVENSdHBQYXJhbWV0ZXJzLlxuU0RQVXRpbHMucGFyc2VSdHBQYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIGNvbnN0IGRlc2NyaXB0aW9uID0ge1xuICAgIGNvZGVjczogW10sXG4gICAgaGVhZGVyRXh0ZW5zaW9uczogW10sXG4gICAgZmVjTWVjaGFuaXNtczogW10sXG4gICAgcnRjcDogW10sXG4gIH07XG4gIGNvbnN0IGxpbmVzID0gU0RQVXRpbHMuc3BsaXRMaW5lcyhtZWRpYVNlY3Rpb24pO1xuICBjb25zdCBtbGluZSA9IGxpbmVzWzBdLnNwbGl0KCcgJyk7XG4gIGRlc2NyaXB0aW9uLnByb2ZpbGUgPSBtbGluZVsyXTtcbiAgZm9yIChsZXQgaSA9IDM7IGkgPCBtbGluZS5sZW5ndGg7IGkrKykgeyAvLyBmaW5kIGFsbCBjb2RlY3MgZnJvbSBtbGluZVszLi5dXG4gICAgY29uc3QgcHQgPSBtbGluZVtpXTtcbiAgICBjb25zdCBydHBtYXBsaW5lID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgoXG4gICAgICBtZWRpYVNlY3Rpb24sICdhPXJ0cG1hcDonICsgcHQgKyAnICcpWzBdO1xuICAgIGlmIChydHBtYXBsaW5lKSB7XG4gICAgICBjb25zdCBjb2RlYyA9IFNEUFV0aWxzLnBhcnNlUnRwTWFwKHJ0cG1hcGxpbmUpO1xuICAgICAgY29uc3QgZm10cHMgPSBTRFBVdGlscy5tYXRjaFByZWZpeChcbiAgICAgICAgbWVkaWFTZWN0aW9uLCAnYT1mbXRwOicgKyBwdCArICcgJyk7XG4gICAgICAvLyBPbmx5IHRoZSBmaXJzdCBhPWZtdHA6PHB0PiBpcyBjb25zaWRlcmVkLlxuICAgICAgY29kZWMucGFyYW1ldGVycyA9IGZtdHBzLmxlbmd0aCA/IFNEUFV0aWxzLnBhcnNlRm10cChmbXRwc1swXSkgOiB7fTtcbiAgICAgIGNvZGVjLnJ0Y3BGZWVkYmFjayA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KFxuICAgICAgICBtZWRpYVNlY3Rpb24sICdhPXJ0Y3AtZmI6JyArIHB0ICsgJyAnKVxuICAgICAgICAubWFwKFNEUFV0aWxzLnBhcnNlUnRjcEZiKTtcbiAgICAgIGRlc2NyaXB0aW9uLmNvZGVjcy5wdXNoKGNvZGVjKTtcbiAgICAgIC8vIHBhcnNlIEZFQyBtZWNoYW5pc21zIGZyb20gcnRwbWFwIGxpbmVzLlxuICAgICAgc3dpdGNoIChjb2RlYy5uYW1lLnRvVXBwZXJDYXNlKCkpIHtcbiAgICAgICAgY2FzZSAnUkVEJzpcbiAgICAgICAgY2FzZSAnVUxQRkVDJzpcbiAgICAgICAgICBkZXNjcmlwdGlvbi5mZWNNZWNoYW5pc21zLnB1c2goY29kZWMubmFtZS50b1VwcGVyQ2FzZSgpKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDogLy8gb25seSBSRUQgYW5kIFVMUEZFQyBhcmUgcmVjb2duaXplZCBhcyBGRUMgbWVjaGFuaXNtcy5cbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1leHRtYXA6JykuZm9yRWFjaChsaW5lID0+IHtcbiAgICBkZXNjcmlwdGlvbi5oZWFkZXJFeHRlbnNpb25zLnB1c2goU0RQVXRpbHMucGFyc2VFeHRtYXAobGluZSkpO1xuICB9KTtcbiAgY29uc3Qgd2lsZGNhcmRSdGNwRmIgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXJ0Y3AtZmI6KiAnKVxuICAgIC5tYXAoU0RQVXRpbHMucGFyc2VSdGNwRmIpO1xuICBkZXNjcmlwdGlvbi5jb2RlY3MuZm9yRWFjaChjb2RlYyA9PiB7XG4gICAgd2lsZGNhcmRSdGNwRmIuZm9yRWFjaChmYj0+IHtcbiAgICAgIGNvbnN0IGR1cGxpY2F0ZSA9IGNvZGVjLnJ0Y3BGZWVkYmFjay5maW5kKGV4aXN0aW5nRmVlZGJhY2sgPT4ge1xuICAgICAgICByZXR1cm4gZXhpc3RpbmdGZWVkYmFjay50eXBlID09PSBmYi50eXBlICYmXG4gICAgICAgICAgZXhpc3RpbmdGZWVkYmFjay5wYXJhbWV0ZXIgPT09IGZiLnBhcmFtZXRlcjtcbiAgICAgIH0pO1xuICAgICAgaWYgKCFkdXBsaWNhdGUpIHtcbiAgICAgICAgY29kZWMucnRjcEZlZWRiYWNrLnB1c2goZmIpO1xuICAgICAgfVxuICAgIH0pO1xuICB9KTtcbiAgLy8gRklYTUU6IHBhcnNlIHJ0Y3AuXG4gIHJldHVybiBkZXNjcmlwdGlvbjtcbn07XG5cbi8vIEdlbmVyYXRlcyBwYXJ0cyBvZiB0aGUgU0RQIG1lZGlhIHNlY3Rpb24gZGVzY3JpYmluZyB0aGUgY2FwYWJpbGl0aWVzIC9cbi8vIHBhcmFtZXRlcnMuXG5TRFBVdGlscy53cml0ZVJ0cERlc2NyaXB0aW9uID0gZnVuY3Rpb24oa2luZCwgY2Fwcykge1xuICBsZXQgc2RwID0gJyc7XG5cbiAgLy8gQnVpbGQgdGhlIG1saW5lLlxuICBzZHAgKz0gJ209JyArIGtpbmQgKyAnICc7XG4gIHNkcCArPSBjYXBzLmNvZGVjcy5sZW5ndGggPiAwID8gJzknIDogJzAnOyAvLyByZWplY3QgaWYgbm8gY29kZWNzLlxuICBzZHAgKz0gJyAnICsgKGNhcHMucHJvZmlsZSB8fCAnVURQL1RMUy9SVFAvU0FWUEYnKSArICcgJztcbiAgc2RwICs9IGNhcHMuY29kZWNzLm1hcChjb2RlYyA9PiB7XG4gICAgaWYgKGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZTtcbiAgICB9XG4gICAgcmV0dXJuIGNvZGVjLnBheWxvYWRUeXBlO1xuICB9KS5qb2luKCcgJykgKyAnXFxyXFxuJztcblxuICBzZHAgKz0gJ2M9SU4gSVA0IDAuMC4wLjBcXHJcXG4nO1xuICBzZHAgKz0gJ2E9cnRjcDo5IElOIElQNCAwLjAuMC4wXFxyXFxuJztcblxuICAvLyBBZGQgYT1ydHBtYXAgbGluZXMgZm9yIGVhY2ggY29kZWMuIEFsc28gZm10cCBhbmQgcnRjcC1mYi5cbiAgY2Fwcy5jb2RlY3MuZm9yRWFjaChjb2RlYyA9PiB7XG4gICAgc2RwICs9IFNEUFV0aWxzLndyaXRlUnRwTWFwKGNvZGVjKTtcbiAgICBzZHAgKz0gU0RQVXRpbHMud3JpdGVGbXRwKGNvZGVjKTtcbiAgICBzZHAgKz0gU0RQVXRpbHMud3JpdGVSdGNwRmIoY29kZWMpO1xuICB9KTtcbiAgbGV0IG1heHB0aW1lID0gMDtcbiAgY2Fwcy5jb2RlY3MuZm9yRWFjaChjb2RlYyA9PiB7XG4gICAgaWYgKGNvZGVjLm1heHB0aW1lID4gbWF4cHRpbWUpIHtcbiAgICAgIG1heHB0aW1lID0gY29kZWMubWF4cHRpbWU7XG4gICAgfVxuICB9KTtcbiAgaWYgKG1heHB0aW1lID4gMCkge1xuICAgIHNkcCArPSAnYT1tYXhwdGltZTonICsgbWF4cHRpbWUgKyAnXFxyXFxuJztcbiAgfVxuXG4gIGlmIChjYXBzLmhlYWRlckV4dGVuc2lvbnMpIHtcbiAgICBjYXBzLmhlYWRlckV4dGVuc2lvbnMuZm9yRWFjaChleHRlbnNpb24gPT4ge1xuICAgICAgc2RwICs9IFNEUFV0aWxzLndyaXRlRXh0bWFwKGV4dGVuc2lvbik7XG4gICAgfSk7XG4gIH1cbiAgLy8gRklYTUU6IHdyaXRlIGZlY01lY2hhbmlzbXMuXG4gIHJldHVybiBzZHA7XG59O1xuXG4vLyBQYXJzZXMgdGhlIFNEUCBtZWRpYSBzZWN0aW9uIGFuZCByZXR1cm5zIGFuIGFycmF5IG9mXG4vLyBSVENSdHBFbmNvZGluZ1BhcmFtZXRlcnMuXG5TRFBVdGlscy5wYXJzZVJ0cEVuY29kaW5nUGFyYW1ldGVycyA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICBjb25zdCBlbmNvZGluZ1BhcmFtZXRlcnMgPSBbXTtcbiAgY29uc3QgZGVzY3JpcHRpb24gPSBTRFBVdGlscy5wYXJzZVJ0cFBhcmFtZXRlcnMobWVkaWFTZWN0aW9uKTtcbiAgY29uc3QgaGFzUmVkID0gZGVzY3JpcHRpb24uZmVjTWVjaGFuaXNtcy5pbmRleE9mKCdSRUQnKSAhPT0gLTE7XG4gIGNvbnN0IGhhc1VscGZlYyA9IGRlc2NyaXB0aW9uLmZlY01lY2hhbmlzbXMuaW5kZXhPZignVUxQRkVDJykgIT09IC0xO1xuXG4gIC8vIGZpbHRlciBhPXNzcmM6Li4uIGNuYW1lOiwgaWdub3JlIFBsYW5CLW1zaWRcbiAgY29uc3Qgc3NyY3MgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXNzcmM6JylcbiAgICAubWFwKGxpbmUgPT4gU0RQVXRpbHMucGFyc2VTc3JjTWVkaWEobGluZSkpXG4gICAgLmZpbHRlcihwYXJ0cyA9PiBwYXJ0cy5hdHRyaWJ1dGUgPT09ICdjbmFtZScpO1xuICBjb25zdCBwcmltYXJ5U3NyYyA9IHNzcmNzLmxlbmd0aCA+IDAgJiYgc3NyY3NbMF0uc3NyYztcbiAgbGV0IHNlY29uZGFyeVNzcmM7XG5cbiAgY29uc3QgZmxvd3MgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXNzcmMtZ3JvdXA6RklEJylcbiAgICAubWFwKGxpbmUgPT4ge1xuICAgICAgY29uc3QgcGFydHMgPSBsaW5lLnN1YnN0cmluZygxNykuc3BsaXQoJyAnKTtcbiAgICAgIHJldHVybiBwYXJ0cy5tYXAocGFydCA9PiBwYXJzZUludChwYXJ0LCAxMCkpO1xuICAgIH0pO1xuICBpZiAoZmxvd3MubGVuZ3RoID4gMCAmJiBmbG93c1swXS5sZW5ndGggPiAxICYmIGZsb3dzWzBdWzBdID09PSBwcmltYXJ5U3NyYykge1xuICAgIHNlY29uZGFyeVNzcmMgPSBmbG93c1swXVsxXTtcbiAgfVxuXG4gIGRlc2NyaXB0aW9uLmNvZGVjcy5mb3JFYWNoKGNvZGVjID0+IHtcbiAgICBpZiAoY29kZWMubmFtZS50b1VwcGVyQ2FzZSgpID09PSAnUlRYJyAmJiBjb2RlYy5wYXJhbWV0ZXJzLmFwdCkge1xuICAgICAgbGV0IGVuY1BhcmFtID0ge1xuICAgICAgICBzc3JjOiBwcmltYXJ5U3NyYyxcbiAgICAgICAgY29kZWNQYXlsb2FkVHlwZTogcGFyc2VJbnQoY29kZWMucGFyYW1ldGVycy5hcHQsIDEwKSxcbiAgICAgIH07XG4gICAgICBpZiAocHJpbWFyeVNzcmMgJiYgc2Vjb25kYXJ5U3NyYykge1xuICAgICAgICBlbmNQYXJhbS5ydHggPSB7c3NyYzogc2Vjb25kYXJ5U3NyY307XG4gICAgICB9XG4gICAgICBlbmNvZGluZ1BhcmFtZXRlcnMucHVzaChlbmNQYXJhbSk7XG4gICAgICBpZiAoaGFzUmVkKSB7XG4gICAgICAgIGVuY1BhcmFtID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShlbmNQYXJhbSkpO1xuICAgICAgICBlbmNQYXJhbS5mZWMgPSB7XG4gICAgICAgICAgc3NyYzogcHJpbWFyeVNzcmMsXG4gICAgICAgICAgbWVjaGFuaXNtOiBoYXNVbHBmZWMgPyAncmVkK3VscGZlYycgOiAncmVkJyxcbiAgICAgICAgfTtcbiAgICAgICAgZW5jb2RpbmdQYXJhbWV0ZXJzLnB1c2goZW5jUGFyYW0pO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIGlmIChlbmNvZGluZ1BhcmFtZXRlcnMubGVuZ3RoID09PSAwICYmIHByaW1hcnlTc3JjKSB7XG4gICAgZW5jb2RpbmdQYXJhbWV0ZXJzLnB1c2goe1xuICAgICAgc3NyYzogcHJpbWFyeVNzcmMsXG4gICAgfSk7XG4gIH1cblxuICAvLyB3ZSBzdXBwb3J0IGJvdGggYj1BUyBhbmQgYj1USUFTIGJ1dCBpbnRlcnByZXQgQVMgYXMgVElBUy5cbiAgbGV0IGJhbmR3aWR0aCA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2I9Jyk7XG4gIGlmIChiYW5kd2lkdGgubGVuZ3RoKSB7XG4gICAgaWYgKGJhbmR3aWR0aFswXS5pbmRleE9mKCdiPVRJQVM6JykgPT09IDApIHtcbiAgICAgIGJhbmR3aWR0aCA9IHBhcnNlSW50KGJhbmR3aWR0aFswXS5zdWJzdHJpbmcoNyksIDEwKTtcbiAgICB9IGVsc2UgaWYgKGJhbmR3aWR0aFswXS5pbmRleE9mKCdiPUFTOicpID09PSAwKSB7XG4gICAgICAvLyB1c2UgZm9ybXVsYSBmcm9tIEpTRVAgdG8gY29udmVydCBiPUFTIHRvIFRJQVMgdmFsdWUuXG4gICAgICBiYW5kd2lkdGggPSBwYXJzZUludChiYW5kd2lkdGhbMF0uc3Vic3RyaW5nKDUpLCAxMCkgKiAxMDAwICogMC45NVxuICAgICAgICAgIC0gKDUwICogNDAgKiA4KTtcbiAgICB9IGVsc2Uge1xuICAgICAgYmFuZHdpZHRoID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBlbmNvZGluZ1BhcmFtZXRlcnMuZm9yRWFjaChwYXJhbXMgPT4ge1xuICAgICAgcGFyYW1zLm1heEJpdHJhdGUgPSBiYW5kd2lkdGg7XG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIGVuY29kaW5nUGFyYW1ldGVycztcbn07XG5cbi8vIHBhcnNlcyBodHRwOi8vZHJhZnQub3J0Yy5vcmcvI3J0Y3J0Y3BwYXJhbWV0ZXJzKlxuU0RQVXRpbHMucGFyc2VSdGNwUGFyYW1ldGVycyA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICBjb25zdCBydGNwUGFyYW1ldGVycyA9IHt9O1xuXG4gIC8vIEdldHMgdGhlIGZpcnN0IFNTUkMuIE5vdGUgdGhhdCB3aXRoIFJUWCB0aGVyZSBtaWdodCBiZSBtdWx0aXBsZVxuICAvLyBTU1JDcy5cbiAgY29uc3QgcmVtb3RlU3NyYyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9c3NyYzonKVxuICAgIC5tYXAobGluZSA9PiBTRFBVdGlscy5wYXJzZVNzcmNNZWRpYShsaW5lKSlcbiAgICAuZmlsdGVyKG9iaiA9PiBvYmouYXR0cmlidXRlID09PSAnY25hbWUnKVswXTtcbiAgaWYgKHJlbW90ZVNzcmMpIHtcbiAgICBydGNwUGFyYW1ldGVycy5jbmFtZSA9IHJlbW90ZVNzcmMudmFsdWU7XG4gICAgcnRjcFBhcmFtZXRlcnMuc3NyYyA9IHJlbW90ZVNzcmMuc3NyYztcbiAgfVxuXG4gIC8vIEVkZ2UgdXNlcyB0aGUgY29tcG91bmQgYXR0cmlidXRlIGluc3RlYWQgb2YgcmVkdWNlZFNpemVcbiAgLy8gY29tcG91bmQgaXMgIXJlZHVjZWRTaXplXG4gIGNvbnN0IHJzaXplID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1ydGNwLXJzaXplJyk7XG4gIHJ0Y3BQYXJhbWV0ZXJzLnJlZHVjZWRTaXplID0gcnNpemUubGVuZ3RoID4gMDtcbiAgcnRjcFBhcmFtZXRlcnMuY29tcG91bmQgPSByc2l6ZS5sZW5ndGggPT09IDA7XG5cbiAgLy8gcGFyc2VzIHRoZSBydGNwLW11eCBhdHRy0ZZidXRlLlxuICAvLyBOb3RlIHRoYXQgRWRnZSBkb2VzIG5vdCBzdXBwb3J0IHVubXV4ZWQgUlRDUC5cbiAgY29uc3QgbXV4ID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1ydGNwLW11eCcpO1xuICBydGNwUGFyYW1ldGVycy5tdXggPSBtdXgubGVuZ3RoID4gMDtcblxuICByZXR1cm4gcnRjcFBhcmFtZXRlcnM7XG59O1xuXG5TRFBVdGlscy53cml0ZVJ0Y3BQYXJhbWV0ZXJzID0gZnVuY3Rpb24ocnRjcFBhcmFtZXRlcnMpIHtcbiAgbGV0IHNkcCA9ICcnO1xuICBpZiAocnRjcFBhcmFtZXRlcnMucmVkdWNlZFNpemUpIHtcbiAgICBzZHAgKz0gJ2E9cnRjcC1yc2l6ZVxcclxcbic7XG4gIH1cbiAgaWYgKHJ0Y3BQYXJhbWV0ZXJzLm11eCkge1xuICAgIHNkcCArPSAnYT1ydGNwLW11eFxcclxcbic7XG4gIH1cbiAgaWYgKHJ0Y3BQYXJhbWV0ZXJzLnNzcmMgIT09IHVuZGVmaW5lZCAmJiBydGNwUGFyYW1ldGVycy5jbmFtZSkge1xuICAgIHNkcCArPSAnYT1zc3JjOicgKyBydGNwUGFyYW1ldGVycy5zc3JjICtcbiAgICAgICcgY25hbWU6JyArIHJ0Y3BQYXJhbWV0ZXJzLmNuYW1lICsgJ1xcclxcbic7XG4gIH1cbiAgcmV0dXJuIHNkcDtcbn07XG5cblxuLy8gcGFyc2VzIGVpdGhlciBhPW1zaWQ6IG9yIGE9c3NyYzouLi4gbXNpZCBsaW5lcyBhbmQgcmV0dXJuc1xuLy8gdGhlIGlkIG9mIHRoZSBNZWRpYVN0cmVhbSBhbmQgTWVkaWFTdHJlYW1UcmFjay5cblNEUFV0aWxzLnBhcnNlTXNpZCA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICBsZXQgcGFydHM7XG4gIGNvbnN0IHNwZWMgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPW1zaWQ6Jyk7XG4gIGlmIChzcGVjLmxlbmd0aCA9PT0gMSkge1xuICAgIHBhcnRzID0gc3BlY1swXS5zdWJzdHJpbmcoNykuc3BsaXQoJyAnKTtcbiAgICByZXR1cm4ge3N0cmVhbTogcGFydHNbMF0sIHRyYWNrOiBwYXJ0c1sxXX07XG4gIH1cbiAgY29uc3QgcGxhbkIgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXNzcmM6JylcbiAgICAubWFwKGxpbmUgPT4gU0RQVXRpbHMucGFyc2VTc3JjTWVkaWEobGluZSkpXG4gICAgLmZpbHRlcihtc2lkUGFydHMgPT4gbXNpZFBhcnRzLmF0dHJpYnV0ZSA9PT0gJ21zaWQnKTtcbiAgaWYgKHBsYW5CLmxlbmd0aCA+IDApIHtcbiAgICBwYXJ0cyA9IHBsYW5CWzBdLnZhbHVlLnNwbGl0KCcgJyk7XG4gICAgcmV0dXJuIHtzdHJlYW06IHBhcnRzWzBdLCB0cmFjazogcGFydHNbMV19O1xuICB9XG59O1xuXG4vLyBTQ1RQXG4vLyBwYXJzZXMgZHJhZnQtaWV0Zi1tbXVzaWMtc2N0cC1zZHAtMjYgZmlyc3QgYW5kIGZhbGxzIGJhY2tcbi8vIHRvIGRyYWZ0LWlldGYtbW11c2ljLXNjdHAtc2RwLTA1XG5TRFBVdGlscy5wYXJzZVNjdHBEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICBjb25zdCBtbGluZSA9IFNEUFV0aWxzLnBhcnNlTUxpbmUobWVkaWFTZWN0aW9uKTtcbiAgY29uc3QgbWF4U2l6ZUxpbmUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPW1heC1tZXNzYWdlLXNpemU6Jyk7XG4gIGxldCBtYXhNZXNzYWdlU2l6ZTtcbiAgaWYgKG1heFNpemVMaW5lLmxlbmd0aCA+IDApIHtcbiAgICBtYXhNZXNzYWdlU2l6ZSA9IHBhcnNlSW50KG1heFNpemVMaW5lWzBdLnN1YnN0cmluZygxOSksIDEwKTtcbiAgfVxuICBpZiAoaXNOYU4obWF4TWVzc2FnZVNpemUpKSB7XG4gICAgbWF4TWVzc2FnZVNpemUgPSA2NTUzNjtcbiAgfVxuICBjb25zdCBzY3RwUG9ydCA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9c2N0cC1wb3J0OicpO1xuICBpZiAoc2N0cFBvcnQubGVuZ3RoID4gMCkge1xuICAgIHJldHVybiB7XG4gICAgICBwb3J0OiBwYXJzZUludChzY3RwUG9ydFswXS5zdWJzdHJpbmcoMTIpLCAxMCksXG4gICAgICBwcm90b2NvbDogbWxpbmUuZm10LFxuICAgICAgbWF4TWVzc2FnZVNpemUsXG4gICAgfTtcbiAgfVxuICBjb25zdCBzY3RwTWFwTGluZXMgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXNjdHBtYXA6Jyk7XG4gIGlmIChzY3RwTWFwTGluZXMubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IHBhcnRzID0gc2N0cE1hcExpbmVzWzBdXG4gICAgICAuc3Vic3RyaW5nKDEwKVxuICAgICAgLnNwbGl0KCcgJyk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHBvcnQ6IHBhcnNlSW50KHBhcnRzWzBdLCAxMCksXG4gICAgICBwcm90b2NvbDogcGFydHNbMV0sXG4gICAgICBtYXhNZXNzYWdlU2l6ZSxcbiAgICB9O1xuICB9XG59O1xuXG4vLyBTQ1RQXG4vLyBvdXRwdXRzIHRoZSBkcmFmdC1pZXRmLW1tdXNpYy1zY3RwLXNkcC0yNiB2ZXJzaW9uIHRoYXQgYWxsIGJyb3dzZXJzXG4vLyBzdXBwb3J0IGJ5IG5vdyByZWNlaXZpbmcgaW4gdGhpcyBmb3JtYXQsIHVubGVzcyB3ZSBvcmlnaW5hbGx5IHBhcnNlZFxuLy8gYXMgdGhlIGRyYWZ0LWlldGYtbW11c2ljLXNjdHAtc2RwLTA1IGZvcm1hdCAoaW5kaWNhdGVkIGJ5IHRoZSBtLWxpbmVcbi8vIHByb3RvY29sIG9mIERUTFMvU0NUUCAtLSB3aXRob3V0IFVEUC8gb3IgVENQLylcblNEUFV0aWxzLndyaXRlU2N0cERlc2NyaXB0aW9uID0gZnVuY3Rpb24obWVkaWEsIHNjdHApIHtcbiAgbGV0IG91dHB1dCA9IFtdO1xuICBpZiAobWVkaWEucHJvdG9jb2wgIT09ICdEVExTL1NDVFAnKSB7XG4gICAgb3V0cHV0ID0gW1xuICAgICAgJ209JyArIG1lZGlhLmtpbmQgKyAnIDkgJyArIG1lZGlhLnByb3RvY29sICsgJyAnICsgc2N0cC5wcm90b2NvbCArICdcXHJcXG4nLFxuICAgICAgJ2M9SU4gSVA0IDAuMC4wLjBcXHJcXG4nLFxuICAgICAgJ2E9c2N0cC1wb3J0OicgKyBzY3RwLnBvcnQgKyAnXFxyXFxuJyxcbiAgICBdO1xuICB9IGVsc2Uge1xuICAgIG91dHB1dCA9IFtcbiAgICAgICdtPScgKyBtZWRpYS5raW5kICsgJyA5ICcgKyBtZWRpYS5wcm90b2NvbCArICcgJyArIHNjdHAucG9ydCArICdcXHJcXG4nLFxuICAgICAgJ2M9SU4gSVA0IDAuMC4wLjBcXHJcXG4nLFxuICAgICAgJ2E9c2N0cG1hcDonICsgc2N0cC5wb3J0ICsgJyAnICsgc2N0cC5wcm90b2NvbCArICcgNjU1MzVcXHJcXG4nLFxuICAgIF07XG4gIH1cbiAgaWYgKHNjdHAubWF4TWVzc2FnZVNpemUgIT09IHVuZGVmaW5lZCkge1xuICAgIG91dHB1dC5wdXNoKCdhPW1heC1tZXNzYWdlLXNpemU6JyArIHNjdHAubWF4TWVzc2FnZVNpemUgKyAnXFxyXFxuJyk7XG4gIH1cbiAgcmV0dXJuIG91dHB1dC5qb2luKCcnKTtcbn07XG5cbi8vIEdlbmVyYXRlIGEgc2Vzc2lvbiBJRCBmb3IgU0RQLlxuLy8gaHR0cHM6Ly90b29scy5pZXRmLm9yZy9odG1sL2RyYWZ0LWlldGYtcnRjd2ViLWpzZXAtMjAjc2VjdGlvbi01LjIuMVxuLy8gcmVjb21tZW5kcyB1c2luZyBhIGNyeXB0b2dyYXBoaWNhbGx5IHJhbmRvbSArdmUgNjQtYml0IHZhbHVlXG4vLyBidXQgcmlnaHQgbm93IHRoaXMgc2hvdWxkIGJlIGFjY2VwdGFibGUgYW5kIHdpdGhpbiB0aGUgcmlnaHQgcmFuZ2VcblNEUFV0aWxzLmdlbmVyYXRlU2Vzc2lvbklkID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiBNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKCkuc3Vic3RyKDIsIDIyKTtcbn07XG5cbi8vIFdyaXRlIGJvaWxlciBwbGF0ZSBmb3Igc3RhcnQgb2YgU0RQXG4vLyBzZXNzSWQgYXJndW1lbnQgaXMgb3B0aW9uYWwgLSBpZiBub3Qgc3VwcGxpZWQgaXQgd2lsbFxuLy8gYmUgZ2VuZXJhdGVkIHJhbmRvbWx5XG4vLyBzZXNzVmVyc2lvbiBpcyBvcHRpb25hbCBhbmQgZGVmYXVsdHMgdG8gMlxuLy8gc2Vzc1VzZXIgaXMgb3B0aW9uYWwgYW5kIGRlZmF1bHRzIHRvICd0aGlzaXNhZGFwdGVyb3J0YydcblNEUFV0aWxzLndyaXRlU2Vzc2lvbkJvaWxlcnBsYXRlID0gZnVuY3Rpb24oc2Vzc0lkLCBzZXNzVmVyLCBzZXNzVXNlcikge1xuICBsZXQgc2Vzc2lvbklkO1xuICBjb25zdCB2ZXJzaW9uID0gc2Vzc1ZlciAhPT0gdW5kZWZpbmVkID8gc2Vzc1ZlciA6IDI7XG4gIGlmIChzZXNzSWQpIHtcbiAgICBzZXNzaW9uSWQgPSBzZXNzSWQ7XG4gIH0gZWxzZSB7XG4gICAgc2Vzc2lvbklkID0gU0RQVXRpbHMuZ2VuZXJhdGVTZXNzaW9uSWQoKTtcbiAgfVxuICBjb25zdCB1c2VyID0gc2Vzc1VzZXIgfHwgJ3RoaXNpc2FkYXB0ZXJvcnRjJztcbiAgLy8gRklYTUU6IHNlc3MtaWQgc2hvdWxkIGJlIGFuIE5UUCB0aW1lc3RhbXAuXG4gIHJldHVybiAndj0wXFxyXFxuJyArXG4gICAgICAnbz0nICsgdXNlciArICcgJyArIHNlc3Npb25JZCArICcgJyArIHZlcnNpb24gK1xuICAgICAgICAnIElOIElQNCAxMjcuMC4wLjFcXHJcXG4nICtcbiAgICAgICdzPS1cXHJcXG4nICtcbiAgICAgICd0PTAgMFxcclxcbic7XG59O1xuXG4vLyBHZXRzIHRoZSBkaXJlY3Rpb24gZnJvbSB0aGUgbWVkaWFTZWN0aW9uIG9yIHRoZSBzZXNzaW9ucGFydC5cblNEUFV0aWxzLmdldERpcmVjdGlvbiA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbiwgc2Vzc2lvbnBhcnQpIHtcbiAgLy8gTG9vayBmb3Igc2VuZHJlY3YsIHNlbmRvbmx5LCByZWN2b25seSwgaW5hY3RpdmUsIGRlZmF1bHQgdG8gc2VuZHJlY3YuXG4gIGNvbnN0IGxpbmVzID0gU0RQVXRpbHMuc3BsaXRMaW5lcyhtZWRpYVNlY3Rpb24pO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgc3dpdGNoIChsaW5lc1tpXSkge1xuICAgICAgY2FzZSAnYT1zZW5kcmVjdic6XG4gICAgICBjYXNlICdhPXNlbmRvbmx5JzpcbiAgICAgIGNhc2UgJ2E9cmVjdm9ubHknOlxuICAgICAgY2FzZSAnYT1pbmFjdGl2ZSc6XG4gICAgICAgIHJldHVybiBsaW5lc1tpXS5zdWJzdHJpbmcoMik7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICAvLyBGSVhNRTogV2hhdCBzaG91bGQgaGFwcGVuIGhlcmU/XG4gICAgfVxuICB9XG4gIGlmIChzZXNzaW9ucGFydCkge1xuICAgIHJldHVybiBTRFBVdGlscy5nZXREaXJlY3Rpb24oc2Vzc2lvbnBhcnQpO1xuICB9XG4gIHJldHVybiAnc2VuZHJlY3YnO1xufTtcblxuU0RQVXRpbHMuZ2V0S2luZCA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICBjb25zdCBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMobWVkaWFTZWN0aW9uKTtcbiAgY29uc3QgbWxpbmUgPSBsaW5lc1swXS5zcGxpdCgnICcpO1xuICByZXR1cm4gbWxpbmVbMF0uc3Vic3RyaW5nKDIpO1xufTtcblxuU0RQVXRpbHMuaXNSZWplY3RlZCA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICByZXR1cm4gbWVkaWFTZWN0aW9uLnNwbGl0KCcgJywgMilbMV0gPT09ICcwJztcbn07XG5cblNEUFV0aWxzLnBhcnNlTUxpbmUgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgY29uc3QgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIGNvbnN0IHBhcnRzID0gbGluZXNbMF0uc3Vic3RyaW5nKDIpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAga2luZDogcGFydHNbMF0sXG4gICAgcG9ydDogcGFyc2VJbnQocGFydHNbMV0sIDEwKSxcbiAgICBwcm90b2NvbDogcGFydHNbMl0sXG4gICAgZm10OiBwYXJ0cy5zbGljZSgzKS5qb2luKCcgJyksXG4gIH07XG59O1xuXG5TRFBVdGlscy5wYXJzZU9MaW5lID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIGNvbnN0IGxpbmUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdvPScpWzBdO1xuICBjb25zdCBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDIpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAgdXNlcm5hbWU6IHBhcnRzWzBdLFxuICAgIHNlc3Npb25JZDogcGFydHNbMV0sXG4gICAgc2Vzc2lvblZlcnNpb246IHBhcnNlSW50KHBhcnRzWzJdLCAxMCksXG4gICAgbmV0VHlwZTogcGFydHNbM10sXG4gICAgYWRkcmVzc1R5cGU6IHBhcnRzWzRdLFxuICAgIGFkZHJlc3M6IHBhcnRzWzVdLFxuICB9O1xufTtcblxuLy8gYSB2ZXJ5IG5haXZlIGludGVycHJldGF0aW9uIG9mIGEgdmFsaWQgU0RQLlxuU0RQVXRpbHMuaXNWYWxpZFNEUCA9IGZ1bmN0aW9uKGJsb2IpIHtcbiAgaWYgKHR5cGVvZiBibG9iICE9PSAnc3RyaW5nJyB8fCBibG9iLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBjb25zdCBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMoYmxvYik7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAobGluZXNbaV0ubGVuZ3RoIDwgMiB8fCBsaW5lc1tpXS5jaGFyQXQoMSkgIT09ICc9Jykge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICAvLyBUT0RPOiBjaGVjayB0aGUgbW9kaWZpZXIgYSBiaXQgbW9yZS5cbiAgfVxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbi8vIEV4cG9zZSBwdWJsaWMgbWV0aG9kcy5cbmlmICh0eXBlb2YgbW9kdWxlID09PSAnb2JqZWN0Jykge1xuICBtb2R1bGUuZXhwb3J0cyA9IFNEUFV0aWxzO1xufVxuIiwiLy8gVGhlIG1vZHVsZSBjYWNoZVxudmFyIF9fd2VicGFja19tb2R1bGVfY2FjaGVfXyA9IHt9O1xuXG4vLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcblx0dmFyIGNhY2hlZE1vZHVsZSA9IF9fd2VicGFja19tb2R1bGVfY2FjaGVfX1ttb2R1bGVJZF07XG5cdGlmIChjYWNoZWRNb2R1bGUgIT09IHVuZGVmaW5lZCkge1xuXHRcdHJldHVybiBjYWNoZWRNb2R1bGUuZXhwb3J0cztcblx0fVxuXHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuXHR2YXIgbW9kdWxlID0gX193ZWJwYWNrX21vZHVsZV9jYWNoZV9fW21vZHVsZUlkXSA9IHtcblx0XHQvLyBubyBtb2R1bGUuaWQgbmVlZGVkXG5cdFx0Ly8gbm8gbW9kdWxlLmxvYWRlZCBuZWVkZWRcblx0XHRleHBvcnRzOiB7fVxuXHR9O1xuXG5cdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuXHRfX3dlYnBhY2tfbW9kdWxlc19fW21vZHVsZUlkXShtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuXHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuXHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG59XG5cbiIsIiIsIi8vIHN0YXJ0dXBcbi8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuLy8gVGhpcyBlbnRyeSBtb2R1bGUgaXMgcmVmZXJlbmNlZCBieSBvdGhlciBtb2R1bGVzIHNvIGl0IGNhbid0IGJlIGlubGluZWRcbnZhciBfX3dlYnBhY2tfZXhwb3J0c19fID0gX193ZWJwYWNrX3JlcXVpcmVfXyhcIi4vc3JjL2luZGV4LmpzXCIpO1xuIiwiIl0sIm5hbWVzIjpbIm1qIiwicmVxdWlyZSIsIkphbnVzU2Vzc2lvbiIsInByb3RvdHlwZSIsInNlbmRPcmlnaW5hbCIsInNlbmQiLCJ0eXBlIiwic2lnbmFsIiwiY2F0Y2giLCJlIiwibWVzc2FnZSIsImluZGV4T2YiLCJjb25zb2xlIiwiZXJyb3IiLCJOQUYiLCJjb25uZWN0aW9uIiwiYWRhcHRlciIsInJlY29ubmVjdCIsInNkcFV0aWxzIiwiZGVidWciLCJ3YXJuIiwiaXNTYWZhcmkiLCJ0ZXN0IiwibmF2aWdhdG9yIiwidXNlckFnZW50IiwiU1VCU0NSSUJFX1RJTUVPVVRfTVMiLCJBVkFJTEFCTEVfT0NDVVBBTlRTX1RIUkVTSE9MRCIsIk1BWF9TVUJTQ1JJQkVfREVMQVkiLCJyYW5kb21EZWxheSIsIm1pbiIsIm1heCIsIlByb21pc2UiLCJyZXNvbHZlIiwiZGVsYXkiLCJNYXRoIiwicmFuZG9tIiwic2V0VGltZW91dCIsImRlYm91bmNlIiwiZm4iLCJjdXJyIiwiYXJncyIsIkFycmF5Iiwic2xpY2UiLCJjYWxsIiwiYXJndW1lbnRzIiwidGhlbiIsIl8iLCJhcHBseSIsInJhbmRvbVVpbnQiLCJmbG9vciIsIk51bWJlciIsIk1BWF9TQUZFX0lOVEVHRVIiLCJ1bnRpbERhdGFDaGFubmVsT3BlbiIsImRhdGFDaGFubmVsIiwicmVqZWN0IiwicmVhZHlTdGF0ZSIsInJlc29sdmVyIiwicmVqZWN0b3IiLCJjbGVhciIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJhZGRFdmVudExpc3RlbmVyIiwiaXNIMjY0VmlkZW9TdXBwb3J0ZWQiLCJ2aWRlbyIsImRvY3VtZW50IiwiY3JlYXRlRWxlbWVudCIsImNhblBsYXlUeXBlIiwiT1BVU19QQVJBTUVURVJTIiwidXNlZHR4Iiwic3RlcmVvIiwiREVGQVVMVF9QRUVSX0NPTk5FQ1RJT05fQ09ORklHIiwiaWNlU2VydmVycyIsInVybHMiLCJXU19OT1JNQUxfQ0xPU1VSRSIsIkphbnVzQWRhcHRlciIsImNvbnN0cnVjdG9yIiwicm9vbSIsImNsaWVudElkIiwiam9pblRva2VuIiwic2VydmVyVXJsIiwid2ViUnRjT3B0aW9ucyIsInBlZXJDb25uZWN0aW9uQ29uZmlnIiwid3MiLCJzZXNzaW9uIiwicmVsaWFibGVUcmFuc3BvcnQiLCJ1bnJlbGlhYmxlVHJhbnNwb3J0IiwiaW5pdGlhbFJlY29ubmVjdGlvbkRlbGF5IiwicmVjb25uZWN0aW9uRGVsYXkiLCJyZWNvbm5lY3Rpb25UaW1lb3V0IiwibWF4UmVjb25uZWN0aW9uQXR0ZW1wdHMiLCJyZWNvbm5lY3Rpb25BdHRlbXB0cyIsImlzUmVjb25uZWN0aW5nIiwicHVibGlzaGVyIiwib2NjdXBhbnRJZHMiLCJvY2N1cGFudHMiLCJtZWRpYVN0cmVhbXMiLCJsb2NhbE1lZGlhU3RyZWFtIiwicGVuZGluZ01lZGlhUmVxdWVzdHMiLCJNYXAiLCJwZW5kaW5nT2NjdXBhbnRzIiwiU2V0IiwiYXZhaWxhYmxlT2NjdXBhbnRzIiwicmVxdWVzdGVkT2NjdXBhbnRzIiwiYmxvY2tlZENsaWVudHMiLCJmcm96ZW5VcGRhdGVzIiwidGltZU9mZnNldHMiLCJzZXJ2ZXJUaW1lUmVxdWVzdHMiLCJhdmdUaW1lT2Zmc2V0Iiwib25XZWJzb2NrZXRPcGVuIiwiYmluZCIsIm9uV2Vic29ja2V0Q2xvc2UiLCJvbldlYnNvY2tldE1lc3NhZ2UiLCJvbkRhdGFDaGFubmVsTWVzc2FnZSIsIm9uRGF0YSIsInNldFNlcnZlclVybCIsInVybCIsInNldEFwcCIsImFwcCIsInNldFJvb20iLCJyb29tTmFtZSIsInNldEpvaW5Ub2tlbiIsInNldENsaWVudElkIiwic2V0V2ViUnRjT3B0aW9ucyIsIm9wdGlvbnMiLCJzZXRQZWVyQ29ubmVjdGlvbkNvbmZpZyIsInNldFNlcnZlckNvbm5lY3RMaXN0ZW5lcnMiLCJzdWNjZXNzTGlzdGVuZXIiLCJmYWlsdXJlTGlzdGVuZXIiLCJjb25uZWN0U3VjY2VzcyIsImNvbm5lY3RGYWlsdXJlIiwic2V0Um9vbU9jY3VwYW50TGlzdGVuZXIiLCJvY2N1cGFudExpc3RlbmVyIiwib25PY2N1cGFudHNDaGFuZ2VkIiwic2V0RGF0YUNoYW5uZWxMaXN0ZW5lcnMiLCJvcGVuTGlzdGVuZXIiLCJjbG9zZWRMaXN0ZW5lciIsIm1lc3NhZ2VMaXN0ZW5lciIsIm9uT2NjdXBhbnRDb25uZWN0ZWQiLCJvbk9jY3VwYW50RGlzY29ubmVjdGVkIiwib25PY2N1cGFudE1lc3NhZ2UiLCJzZXRSZWNvbm5lY3Rpb25MaXN0ZW5lcnMiLCJyZWNvbm5lY3RpbmdMaXN0ZW5lciIsInJlY29ubmVjdGVkTGlzdGVuZXIiLCJyZWNvbm5lY3Rpb25FcnJvckxpc3RlbmVyIiwib25SZWNvbm5lY3RpbmciLCJvblJlY29ubmVjdGVkIiwib25SZWNvbm5lY3Rpb25FcnJvciIsInNldEV2ZW50TG9vcHMiLCJsb29wcyIsImNvbm5lY3QiLCJsb2NhdGlvbiIsInByb3RvY29sIiwiaG9zdCIsIndlYnNvY2tldENvbm5lY3Rpb24iLCJXZWJTb2NrZXQiLCJ0aW1lb3V0TXMiLCJ3ZWJzb2NrZXRDb25uZWN0aW9uUHJvbWlzZSIsIndzT25PcGVuIiwiYWxsIiwidXBkYXRlVGltZU9mZnNldCIsImRpc2Nvbm5lY3QiLCJjbGVhclRpbWVvdXQiLCJyZW1vdmVBbGxPY2N1cGFudHMiLCJjb25uIiwiY2xvc2UiLCJkaXNwb3NlIiwiZGVsYXllZFJlY29ubmVjdFRpbWVvdXQiLCJpc0Rpc2Nvbm5lY3RlZCIsImNyZWF0ZSIsImNyZWF0ZVB1Ymxpc2hlciIsImkiLCJpbml0aWFsT2NjdXBhbnRzIiwibGVuZ3RoIiwib2NjdXBhbnRJZCIsImFkZEF2YWlsYWJsZU9jY3VwYW50Iiwic3luY09jY3VwYW50cyIsImV2ZW50IiwiY29kZSIsIkVycm9yIiwicGVyZm9ybURlbGF5ZWRSZWNvbm5lY3QiLCJyZWNlaXZlIiwiSlNPTiIsInBhcnNlIiwiZGF0YSIsInB1c2giLCJyZW1vdmVBdmFpbGFibGVPY2N1cGFudCIsImlkeCIsInNwbGljZSIsImhhcyIsImFkZE9jY3VwYW50IiwiaiIsInJlbW92ZU9jY3VwYW50IiwiYWRkIiwiYXZhaWxhYmxlT2NjdXBhbnRzQ291bnQiLCJzdWJzY3JpYmVyIiwiY3JlYXRlU3Vic2NyaWJlciIsImRlbGV0ZSIsInNldE1lZGlhU3RyZWFtIiwibWVkaWFTdHJlYW0iLCJtc2ciLCJnZXQiLCJhdWRpbyIsImFzc29jaWF0ZSIsImhhbmRsZSIsImV2Iiwic2VuZFRyaWNrbGUiLCJjYW5kaWRhdGUiLCJpY2VDb25uZWN0aW9uU3RhdGUiLCJsb2ciLCJvZmZlciIsImNyZWF0ZU9mZmVyIiwiY29uZmlndXJlUHVibGlzaGVyU2RwIiwiZml4U2FmYXJpSWNlVUZyYWciLCJsb2NhbCIsIm8iLCJzZXRMb2NhbERlc2NyaXB0aW9uIiwicmVtb3RlIiwic2VuZEpzZXAiLCJyIiwic2V0UmVtb3RlRGVzY3JpcHRpb24iLCJqc2VwIiwib24iLCJhbnN3ZXIiLCJjb25maWd1cmVTdWJzY3JpYmVyU2RwIiwiY3JlYXRlQW5zd2VyIiwiYSIsIkphbnVzUGx1Z2luSGFuZGxlIiwiUlRDUGVlckNvbm5lY3Rpb24iLCJhdHRhY2giLCJwYXJzZUludCIsInVuZGVmaW5lZCIsIndlYnJ0Y3VwIiwicmVsaWFibGVDaGFubmVsIiwiY3JlYXRlRGF0YUNoYW5uZWwiLCJvcmRlcmVkIiwidW5yZWxpYWJsZUNoYW5uZWwiLCJtYXhSZXRyYW5zbWl0cyIsImdldFRyYWNrcyIsImZvckVhY2giLCJ0cmFjayIsImFkZFRyYWNrIiwicGx1Z2luZGF0YSIsInJvb21faWQiLCJ1c2VyX2lkIiwiYm9keSIsImRpc3BhdGNoRXZlbnQiLCJDdXN0b21FdmVudCIsImRldGFpbCIsImJ5Iiwic2VuZEpvaW4iLCJub3RpZmljYXRpb25zIiwic3VjY2VzcyIsImVyciIsInJlc3BvbnNlIiwidXNlcnMiLCJpbmNsdWRlcyIsInNkcCIsInJlcGxhY2UiLCJsaW5lIiwicHQiLCJwYXJhbWV0ZXJzIiwiT2JqZWN0IiwiYXNzaWduIiwicGFyc2VGbXRwIiwid3JpdGVGbXRwIiwicGF5bG9hZFR5cGUiLCJtYXhSZXRyaWVzIiwid2VicnRjRmFpbGVkIiwibGVmdEludGVydmFsIiwic2V0SW50ZXJ2YWwiLCJjbGVhckludGVydmFsIiwidGltZW91dCIsIm1lZGlhIiwiX2lPU0hhY2tEZWxheWVkSW5pdGlhbFBlZXIiLCJNZWRpYVN0cmVhbSIsInJlY2VpdmVycyIsImdldFJlY2VpdmVycyIsInJlY2VpdmVyIiwic3Vic2NyaWJlIiwic2VuZE1lc3NhZ2UiLCJraW5kIiwidG9rZW4iLCJ0b2dnbGVGcmVlemUiLCJmcm96ZW4iLCJ1bmZyZWV6ZSIsImZyZWV6ZSIsImZsdXNoUGVuZGluZ1VwZGF0ZXMiLCJkYXRhRm9yVXBkYXRlTXVsdGlNZXNzYWdlIiwibmV0d29ya0lkIiwibCIsImQiLCJnZXRQZW5kaW5nRGF0YSIsImRhdGFUeXBlIiwib3duZXIiLCJnZXRQZW5kaW5nRGF0YUZvck5ldHdvcmtJZCIsInNvdXJjZSIsInN0b3JlTWVzc2FnZSIsInN0b3JlU2luZ2xlTWVzc2FnZSIsImluZGV4Iiwic2V0Iiwic3RvcmVkTWVzc2FnZSIsInN0b3JlZERhdGEiLCJpc091dGRhdGVkTWVzc2FnZSIsImxhc3RPd25lclRpbWUiLCJpc0NvbnRlbXBvcmFuZW91c01lc3NhZ2UiLCJjcmVhdGVkV2hpbGVGcm96ZW4iLCJpc0ZpcnN0U3luYyIsImNvbXBvbmVudHMiLCJlbmFibGVkIiwic2hvdWxkU3RhcnRDb25uZWN0aW9uVG8iLCJjbGllbnQiLCJzdGFydFN0cmVhbUNvbm5lY3Rpb24iLCJjbG9zZVN0cmVhbUNvbm5lY3Rpb24iLCJnZXRDb25uZWN0U3RhdHVzIiwiYWRhcHRlcnMiLCJJU19DT05ORUNURUQiLCJOT1RfQ09OTkVDVEVEIiwiY2xpZW50U2VudFRpbWUiLCJEYXRlIiwibm93IiwicmVzIiwiZmV0Y2giLCJocmVmIiwibWV0aG9kIiwiY2FjaGUiLCJwcmVjaXNpb24iLCJzZXJ2ZXJSZWNlaXZlZFRpbWUiLCJoZWFkZXJzIiwiZ2V0VGltZSIsImNsaWVudFJlY2VpdmVkVGltZSIsInNlcnZlclRpbWUiLCJ0aW1lT2Zmc2V0IiwicmVkdWNlIiwiYWNjIiwib2Zmc2V0IiwiZ2V0U2VydmVyVGltZSIsImdldE1lZGlhU3RyZWFtIiwiYXVkaW9Qcm9taXNlIiwidmlkZW9Qcm9taXNlIiwicHJvbWlzZSIsInN0cmVhbSIsImF1ZGlvU3RyZWFtIiwiZ2V0QXVkaW9UcmFja3MiLCJ2aWRlb1N0cmVhbSIsImdldFZpZGVvVHJhY2tzIiwiZ2V0TG9jYWxNZWRpYVN0cmVhbSIsInNldExvY2FsTWVkaWFTdHJlYW0iLCJleGlzdGluZ1NlbmRlcnMiLCJnZXRTZW5kZXJzIiwibmV3U2VuZGVycyIsInRyYWNrcyIsInQiLCJzZW5kZXIiLCJmaW5kIiwicyIsInJlcGxhY2VUcmFjayIsInJlbW92ZVRyYWNrIiwiZW5hYmxlTWljcm9waG9uZSIsInNlbmREYXRhIiwic3RyaW5naWZ5Iiwid2hvbSIsInNlbmREYXRhR3VhcmFudGVlZCIsImJyb2FkY2FzdERhdGEiLCJicm9hZGNhc3REYXRhR3VhcmFudGVlZCIsImtpY2siLCJwZXJtc1Rva2VuIiwiYmxvY2siLCJ1bmJsb2NrIiwicmVnaXN0ZXIiLCJtb2R1bGUiLCJleHBvcnRzIl0sInNvdXJjZVJvb3QiOiIifQ== \ No newline at end of file diff --git a/dist/naf-janus-adapter.min.js b/dist/naf-janus-adapter.min.js index 0d89a91..52ee1ea 100644 --- a/dist/naf-janus-adapter.min.js +++ b/dist/naf-janus-adapter.min.js @@ -1,2 +1,2 @@ -(()=>{var e={734:e=>{function t(e){this.session=e,this.id=void 0}function n(e,t){this.output=e,this.id=void 0,this.nextTxId=0,this.txns={},this.eventHandlers={},this.options=Object.assign({verbose:!1,timeoutMs:1e4,keepaliveMs:3e4},t)}t.prototype.attach=function(e,t){var n={plugin:e,loop_index:t,"force-bundle":!0,"force-rtcp-mux":!0};return this.session.send("attach",n).then((e=>(this.id=e.data.id,e)))},t.prototype.detach=function(){return this.send("detach")},t.prototype.on=function(e,t){return this.session.on(e,(e=>{e.sender==this.id&&t(e)}))},t.prototype.send=function(e,t){return this.session.send(e,Object.assign({handle_id:this.id},t))},t.prototype.sendMessage=function(e){return this.send("message",{body:e})},t.prototype.sendJsep=function(e){return this.send("message",{body:{},jsep:e})},t.prototype.sendTrickle=function(e){return this.send("trickle",{candidate:e})},n.prototype.create=function(){return this.send("create").then((e=>(this.id=e.data.id,e)))},n.prototype.destroy=function(){return this.send("destroy").then((e=>(this.dispose(),e)))},n.prototype.dispose=function(){for(var e in this._killKeepalive(),this.eventHandlers={},this.txns)if(this.txns.hasOwnProperty(e)){var t=this.txns[e];clearTimeout(t.timeout),t.reject(new Error("Janus session was disposed.")),delete this.txns[e]}},n.prototype.isError=function(e){return"error"===e.janus},n.prototype.on=function(e,t){var n=this.eventHandlers[e];null==n&&(n=this.eventHandlers[e]=[]),n.push(t)},n.prototype.receive=function(e){this.options.verbose&&this._logIncoming(e),e.session_id!=this.id&&console.warn("Incorrect session ID received in Janus signalling message: was "+e.session_id+", expected "+this.id+".");var t=e.janus,n=this.eventHandlers[t];if(null!=n)for(var s=0;s{var i=null;this.options.timeoutMs&&(i=setTimeout((()=>{delete this.txns[t.transaction],s(new Error("Signalling transaction with txid "+t.transaction+" timed out."))}),this.options.timeoutMs)),this.txns[t.transaction]={resolve:n,reject:s,timeout:i,type:e},this._transmit(e,t)}))},n.prototype._transmit=function(e,t){t=Object.assign({janus:e},t),null!=this.id&&(t=Object.assign({session_id:this.id},t)),this.options.verbose&&this._logOutgoing(t),this.output(JSON.stringify(t)),this._resetKeepalive()},n.prototype._logOutgoing=function(e){var t=e.janus;"message"===t&&e.jsep&&(t=e.jsep.type);var n="> Outgoing Janus "+(t||"signal")+" (#"+e.transaction+"): ";console.debug("%c"+n,"color: #040",e)},n.prototype._logIncoming=function(e){var t=e.janus,n=e.transaction?"< Incoming Janus "+(t||"signal")+" (#"+e.transaction+"): ":"< Incoming Janus "+(t||"signal")+": ";console.debug("%c"+n,"color: #004",e)},n.prototype._sendKeepalive=function(){return this.send("keepalive")},n.prototype._killKeepalive=function(){clearTimeout(this.keepaliveTimeout)},n.prototype._resetKeepalive=function(){this._killKeepalive(),this.options.keepaliveMs&&(this.keepaliveTimeout=setTimeout((()=>{this._sendKeepalive().catch((e=>console.error("Error received from keepalive: ",e)))}),this.options.keepaliveMs))},e.exports={JanusPluginHandle:t,JanusSession:n}},497:(e,t,n)=>{var s=n(734);s.JanusSession.prototype.sendOriginal=s.JanusSession.prototype.send,s.JanusSession.prototype.send=function(e,t){return this.sendOriginal(e,t).catch((e=>{if(!(e.message&&e.message.indexOf("timed out")>-1))throw e;console.error("web socket timed out"),NAF.connection.adapter.reconnect()}))};var i=n(963),r=n(833)("naf-janus-adapter:debug"),a=(n(833)("naf-janus-adapter:warn"),n(833)("naf-janus-adapter:error")),o=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function c(e){var t=Promise.resolve();return function(){var n=Array.prototype.slice.call(arguments);t=t.then((t=>e.apply(this,n)))}}function l(e){return new Promise(((t,n)=>{if("open"===e.readyState)t();else{let s,i;const r=()=>{e.removeEventListener("open",s),e.removeEventListener("error",i)};s=()=>{r(),t()},i=()=>{r(),n()},e.addEventListener("open",s),e.addEventListener("error",i)}}))}const d=""!==document.createElement("video").canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'),p={usedtx:1,stereo:0,"sprop-stereo":0},u={iceServers:[{urls:"stun:stun1.l.google.com:19302"},{urls:"stun:stun2.l.google.com:19302"}]};class h{constructor(){this.room=null,this.clientId=null,this.joinToken=null,this.serverUrl=null,this.webRtcOptions={},this.peerConnectionConfig=null,this.ws=null,this.session=null,this.reliableTransport="datachannel",this.unreliableTransport="datachannel",this.initialReconnectionDelay=1e3*Math.random(),this.reconnectionDelay=this.initialReconnectionDelay,this.reconnectionTimeout=null,this.maxReconnectionAttempts=10,this.reconnectionAttempts=0,this.publisher=null,this.occupantIds=[],this.occupants={},this.mediaStreams={},this.localMediaStream=null,this.pendingMediaRequests=new Map,this.pendingOccupants=new Set,this.availableOccupants=[],this.requestedOccupants=null,this.blockedClients=new Map,this.frozenUpdates=new Map,this.timeOffsets=[],this.serverTimeRequests=0,this.avgTimeOffset=0,this.onWebsocketOpen=this.onWebsocketOpen.bind(this),this.onWebsocketClose=this.onWebsocketClose.bind(this),this.onWebsocketMessage=this.onWebsocketMessage.bind(this),this.onDataChannelMessage=this.onDataChannelMessage.bind(this),this.onData=this.onData.bind(this)}setServerUrl(e){this.serverUrl=e}setApp(e){}setRoom(e){this.room=e}setJoinToken(e){this.joinToken=e}setClientId(e){this.clientId=e}setWebRtcOptions(e){this.webRtcOptions=e}setPeerConnectionConfig(e){this.peerConnectionConfig=e}setServerConnectListeners(e,t){this.connectSuccess=e,this.connectFailure=t}setRoomOccupantListener(e){this.onOccupantsChanged=e}setDataChannelListeners(e,t,n){this.onOccupantConnected=e,this.onOccupantDisconnected=t,this.onOccupantMessage=n}setReconnectionListeners(e,t,n){this.onReconnecting=e,this.onReconnected=t,this.onReconnectionError=n}setEventLoops(e){this.loops=e}connect(){r(`connecting to ${this.serverUrl}`);const e=new Promise(((e,t)=>{this.ws=new WebSocket(this.serverUrl,"janus-protocol"),this.session=new s.JanusSession(this.ws.send.bind(this.ws),{timeoutMs:4e4}),this.ws.addEventListener("close",this.onWebsocketClose),this.ws.addEventListener("message",this.onWebsocketMessage),this.wsOnOpen=()=>{this.ws.removeEventListener("open",this.wsOnOpen),this.onWebsocketOpen().then(e).catch(t)},this.ws.addEventListener("open",this.wsOnOpen)}));return Promise.all([e,this.updateTimeOffset()])}disconnect(){r("disconnecting"),clearTimeout(this.reconnectionTimeout),this.removeAllOccupants(),this.publisher&&(this.publisher.conn.close(),this.publisher=null),this.session&&(this.session.dispose(),this.session=null),this.ws&&(this.ws.removeEventListener("open",this.wsOnOpen),this.ws.removeEventListener("close",this.onWebsocketClose),this.ws.removeEventListener("message",this.onWebsocketMessage),this.ws.close(),this.ws=null),this.delayedReconnectTimeout&&(clearTimeout(this.delayedReconnectTimeout),this.delayedReconnectTimeout=null)}isDisconnected(){return null===this.ws}async onWebsocketOpen(){await this.session.create(),this.publisher=await this.createPublisher(),this.connectSuccess(this.clientId);for(let e=0;ethis.reconnect()),this.reconnectionDelay))}reconnect(){this.disconnect(),this.connect().then((()=>{this.reconnectionDelay=this.initialReconnectionDelay,this.reconnectionAttempts=0,this.onReconnected&&this.onReconnected()})).catch((e=>{if(this.reconnectionDelay+=1e3,this.reconnectionAttempts++,this.reconnectionAttempts>this.maxReconnectionAttempts&&this.onReconnectionError)return this.onReconnectionError(new Error("Connection could not be reestablished, exceeded maximum number of reconnection attempts."));console.warn("Error during reconnect, retrying."),console.warn(e),this.onReconnecting&&this.onReconnecting(this.reconnectionDelay),this.reconnectionTimeout=setTimeout((()=>this.reconnect()),this.reconnectionDelay)}))}performDelayedReconnect(){this.delayedReconnectTimeout&&clearTimeout(this.delayedReconnectTimeout),this.delayedReconnectTimeout=setTimeout((()=>{this.delayedReconnectTimeout=null,this.reconnect()}),1e4)}onWebsocketMessage(e){this.session.receive(JSON.parse(e.data))}addAvailableOccupant(e){-1===this.availableOccupants.indexOf(e)&&this.availableOccupants.push(e)}removeAvailableOccupant(e){const t=this.availableOccupants.indexOf(e);-1!==t&&this.availableOccupants.splice(t,1)}syncOccupants(e){if(e&&(this.requestedOccupants=e),this.requestedOccupants){for(let e=0;e5&&await(0,5e3,new Promise((e=>{const t=5e3*Math.random()+0;setTimeout(e,t)})));const t=await this.createSubscriber(e);t&&(this.pendingOccupants.has(e)?(this.pendingOccupants.delete(e),this.occupantIds.push(e),this.occupants[e]=t,this.setMediaStream(e,t.mediaStream),this.onOccupantConnected(e)):t.conn.close())}removeAllOccupants(){this.pendingOccupants.clear();for(let e=this.occupantIds.length-1;e>=0;e--)this.removeOccupant(this.occupantIds[e])}removeOccupant(e){if(this.pendingOccupants.delete(e),this.occupants[e]&&(this.occupants[e].conn.close(),delete this.occupants[e],this.occupantIds.splice(this.occupantIds.indexOf(e),1)),this.mediaStreams[e]&&delete this.mediaStreams[e],this.pendingMediaRequests.has(e)){const t="The user disconnected before the media stream was resolved.";this.pendingMediaRequests.get(e).audio.reject(t),this.pendingMediaRequests.get(e).video.reject(t),this.pendingMediaRequests.delete(e)}this.onOccupantDisconnected(e)}associate(e,t){e.addEventListener("icecandidate",(e=>{t.sendTrickle(e.candidate||null).catch((e=>a("Error trickling ICE: %o",e)))})),e.addEventListener("iceconnectionstatechange",(t=>{"connected"===e.iceConnectionState&&console.log("ICE state changed to connected"),"disconnected"===e.iceConnectionState&&console.warn("ICE state changed to disconnected"),"failed"===e.iceConnectionState&&(console.warn("ICE failure detected. Reconnecting in 10s."),this.performDelayedReconnect())})),e.addEventListener("negotiationneeded",c((n=>{r("Sending new offer for handle: %o",t);var s=e.createOffer().then(this.configurePublisherSdp).then(this.fixSafariIceUFrag),i=s.then((t=>e.setLocalDescription(t))),o=s;return o=o.then(this.fixSafariIceUFrag).then((e=>t.sendJsep(e))).then((t=>e.setRemoteDescription(t.jsep))),Promise.all([i,o]).catch((e=>a("Error negotiating offer: %o",e)))}))),t.on("event",c((n=>{var s=n.jsep;if(s&&"offer"==s.type){r("Accepting new offer for handle: %o",t);var i=e.setRemoteDescription(this.configureSubscriberSdp(s)).then((t=>e.createAnswer())).then(this.fixSafariIceUFrag),o=i.then((t=>e.setLocalDescription(t))),c=i.then((e=>t.sendJsep(e)));return Promise.all([o,c]).catch((e=>a("Error negotiating answer: %o",e)))}return null})))}async createPublisher(){var e=new s.JanusPluginHandle(this.session),t=new RTCPeerConnection(this.peerConnectionConfig||u);r("pub waiting for sfu"),await e.attach("janus.plugin.sfu",this.loops&&this.clientId?parseInt(this.clientId)%this.loops:void 0),this.associate(t,e),r("pub waiting for data channels & webrtcup");var n=new Promise((t=>e.on("webrtcup",t))),i=t.createDataChannel("reliable",{ordered:!0}),a=t.createDataChannel("unreliable",{ordered:!1,maxRetransmits:0});i.addEventListener("message",(e=>this.onDataChannelMessage(e,"janus-reliable"))),a.addEventListener("message",(e=>this.onDataChannelMessage(e,"janus-unreliable"))),await n,await l(i),await l(a),this.localMediaStream&&this.localMediaStream.getTracks().forEach((e=>{t.addTrack(e,this.localMediaStream)})),e.on("event",(e=>{var t=e.plugindata.data;if("join"==t.event&&t.room_id==this.room){if(this.delayedReconnectTimeout)return;this.addAvailableOccupant(t.user_id),this.syncOccupants()}else"leave"==t.event&&t.room_id==this.room?(this.removeAvailableOccupant(t.user_id),this.removeOccupant(t.user_id)):"blocked"==t.event?document.body.dispatchEvent(new CustomEvent("blocked",{detail:{clientId:t.by}})):"unblocked"==t.event?document.body.dispatchEvent(new CustomEvent("unblocked",{detail:{clientId:t.by}})):"data"===t.event&&this.onData(JSON.parse(t.body),"janus-event")})),r("pub waiting for join");var o=await this.sendJoin(e,{notifications:!0,data:!0});if(!o.plugindata.data.success){const e=o.plugindata.data.error;throw console.error(e),t.close(),e}var c=o.plugindata.data.response.users[this.room]||[];return c.includes(this.clientId)&&(console.warn("Janus still has previous session for this client. Reconnecting in 10s."),this.performDelayedReconnect()),r("publisher ready"),{handle:e,initialOccupants:c,reliableChannel:i,unreliableChannel:a,conn:t}}configurePublisherSdp(e){return e.sdp=e.sdp.replace(/a=fmtp:(109|111).*\r\n/g,((e,t)=>{const n=Object.assign(i.parseFmtp(e),p);return i.writeFmtp({payloadType:t,parameters:n})})),e}configureSubscriberSdp(e){return d||-1!==navigator.userAgent.indexOf("HeadlessChrome")&&(e.sdp=e.sdp.replace(/m=video[^]*m=/,"m=")),-1===navigator.userAgent.indexOf("Android")?e.sdp=e.sdp.replace("a=rtcp-fb:107 goog-remb\r\n","a=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\n"):e.sdp=e.sdp.replace("a=rtcp-fb:107 goog-remb\r\n","a=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\n"),e}async fixSafariIceUFrag(e){return e.sdp=e.sdp.replace(/[^\r]\na=ice-ufrag/g,"\r\na=ice-ufrag"),e}async createSubscriber(e,t=5){if(-1===this.availableOccupants.indexOf(e))return console.warn(e+": cancelled occupant connection, occupant left before subscription negotation."),null;var n=new s.JanusPluginHandle(this.session),i=new RTCPeerConnection(this.peerConnectionConfig||u);if(r(e+": sub waiting for sfu"),await n.attach("janus.plugin.sfu",this.loops?parseInt(e)%this.loops:void 0),this.associate(i,n),r(e+": sub waiting for join"),-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancelled occupant connection, occupant left after attach"),null;let a=!1;const c=new Promise((t=>{const s=setInterval((()=>{-1===this.availableOccupants.indexOf(e)&&(clearInterval(s),t())}),1e3),i=setTimeout((()=>{clearInterval(s),a=!0,t()}),15e3);n.on("webrtcup",(()=>{clearTimeout(i),clearInterval(s),t()}))}));if(await this.sendJoin(n,{media:e}),-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancelled occupant connection, occupant left after join"),null;if(r(e+": sub waiting for webrtcup"),await c,-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancel occupant connection, occupant left during or after webrtcup"),null;if(a)return i.close(),t>0?(console.warn(e+": webrtc up timed out, retrying"),this.createSubscriber(e,t-1)):(console.warn(e+": webrtc up timed out"),null);o&&!this._iOSHackDelayedInitialPeer&&(await new Promise((e=>setTimeout(e,3e3))),this._iOSHackDelayedInitialPeer=!0);var l=new MediaStream;return i.getReceivers().forEach((e=>{e.track&&l.addTrack(e.track)})),0===l.getTracks().length&&(l=null),r(e+": subscriber ready"),{handle:n,mediaStream:l,conn:i}}sendJoin(e,t){return e.sendMessage({kind:"join",room_id:this.room,user_id:this.clientId,subscribe:t,token:this.joinToken})}toggleFreeze(){this.frozen?this.unfreeze():this.freeze()}freeze(){this.frozen=!0}unfreeze(){this.frozen=!1,this.flushPendingUpdates()}dataForUpdateMultiMessage(e,t){for(let n=0,s=t.data.d.length;nn.owner)return;"r"===s?r&&r.isFirstSync?this.frozenUpdates.delete(i):this.frozenUpdates.set(i,e):r.components&&n.components&&Object.assign(r.components,n.components)}else this.frozenUpdates.set(i,e)}onDataChannelMessage(e,t){this.onData(JSON.parse(e.data),t)}onData(e,t){r.enabled&&r(`DC in: ${e}`),e.dataType&&(e.source=t,this.frozen?this.storeMessage(e):this.onOccupantMessage(null,e.dataType,e.data,e.source))}shouldStartConnectionTo(e){return!0}startStreamConnection(e){}closeStreamConnection(e){}getConnectStatus(e){return this.occupants[e]?NAF.adapters.IS_CONNECTED:NAF.adapters.NOT_CONNECTED}async updateTimeOffset(){if(this.isDisconnected())return;const e=Date.now(),t=await fetch(document.location.href,{method:"HEAD",cache:"no-cache"}),n=new Date(t.headers.get("Date")).getTime()+500,s=Date.now(),i=n+(s-e)/2-s;this.serverTimeRequests++,this.serverTimeRequests<=10?this.timeOffsets.push(i):this.timeOffsets[this.serverTimeRequests%10]=i,this.avgTimeOffset=this.timeOffsets.reduce(((e,t)=>e+t),0)/this.timeOffsets.length,this.serverTimeRequests>10?(r(`new server time offset: ${this.avgTimeOffset}ms`),setTimeout((()=>this.updateTimeOffset()),3e5)):this.updateTimeOffset()}getServerTime(){return Date.now()+this.avgTimeOffset}getMediaStream(e,t="audio"){if(this.mediaStreams[e])return r(`Already had ${t} for ${e}`),Promise.resolve(this.mediaStreams[e][t]);if(r(`Waiting on ${t} for ${e}`),!this.pendingMediaRequests.has(e)){this.pendingMediaRequests.set(e,{});const t=new Promise(((t,n)=>{this.pendingMediaRequests.get(e).audio={resolve:t,reject:n}})),n=new Promise(((t,n)=>{this.pendingMediaRequests.get(e).video={resolve:t,reject:n}}));this.pendingMediaRequests.get(e).audio.promise=t,this.pendingMediaRequests.get(e).video.promise=n,t.catch((t=>console.warn(`${e} getMediaStream Audio Error`,t))),n.catch((t=>console.warn(`${e} getMediaStream Video Error`,t)))}return this.pendingMediaRequests.get(e)[t].promise}setMediaStream(e,t){const n=new MediaStream;try{t.getAudioTracks().forEach((e=>n.addTrack(e)))}catch(t){console.warn(`${e} setMediaStream Audio Error`,t)}const s=new MediaStream;try{t.getVideoTracks().forEach((e=>s.addTrack(e)))}catch(t){console.warn(`${e} setMediaStream Video Error`,t)}this.mediaStreams[e]={audio:n,video:s},this.pendingMediaRequests.has(e)&&(this.pendingMediaRequests.get(e).audio.resolve(n),this.pendingMediaRequests.get(e).video.resolve(s))}getLocalMediaStream(){return this.localMediaStream}async setLocalMediaStream(e){if(this.publisher&&this.publisher.conn){const t=this.publisher.conn.getSenders(),n=[],s=e.getTracks();for(let i=0;inull!=e.track&&e.track.kind==r.kind));null!=a?(a.replaceTrack?await a.replaceTrack(r):(e.removeTrack(a.track),e.addTrack(r)),n.push(a)):n.push(this.publisher.conn.addTrack(r,e))}t.forEach((e=>{n.includes(e)||(e.track.enabled=!1)}))}this.localMediaStream=e,this.setMediaStream(this.clientId,e)}enableMicrophone(e){this.publisher&&this.publisher.conn&&this.publisher.conn.getSenders().forEach((t=>{"audio"==t.track.kind&&(t.track.enabled=e)}))}sendData(e,t,n){if(this.publisher)switch(this.unreliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:t,data:n}),whom:e});break;case"datachannel":"open"===this.publisher.unreliableChannel.readyState&&this.publisher.unreliableChannel.send(JSON.stringify({clientId:e,dataType:t,data:n}));break;default:this.unreliableTransport(e,t,n)}else console.warn("sendData called without a publisher")}sendDataGuaranteed(e,t,n){if(this.publisher)switch(this.reliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:t,data:n}),whom:e});break;case"datachannel":"open"===this.publisher.reliableChannel.readyState&&this.publisher.reliableChannel.send(JSON.stringify({clientId:e,dataType:t,data:n}));break;default:this.reliableTransport(e,t,n)}else console.warn("sendDataGuaranteed called without a publisher")}broadcastData(e,t){if(this.publisher)switch(this.unreliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:e,data:t})});break;case"datachannel":"open"===this.publisher.unreliableChannel.readyState&&this.publisher.unreliableChannel.send(JSON.stringify({dataType:e,data:t}));break;default:this.unreliableTransport(void 0,e,t)}else console.warn("broadcastData called without a publisher")}broadcastDataGuaranteed(e,t){if(this.publisher)switch(this.reliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:e,data:t})});break;case"datachannel":"open"===this.publisher.reliableChannel.readyState&&this.publisher.reliableChannel.send(JSON.stringify({dataType:e,data:t}));break;default:this.reliableTransport(void 0,e,t)}else console.warn("broadcastDataGuaranteed called without a publisher")}kick(e,t){return this.publisher.handle.sendMessage({kind:"kick",room_id:this.room,user_id:e,token:t}).then((()=>{document.body.dispatchEvent(new CustomEvent("kicked",{detail:{clientId:e}}))}))}block(e){return this.publisher.handle.sendMessage({kind:"block",whom:e}).then((()=>{this.blockedClients.set(e,!0),document.body.dispatchEvent(new CustomEvent("blocked",{detail:{clientId:e}}))}))}unblock(e){return this.publisher.handle.sendMessage({kind:"unblock",whom:e}).then((()=>{this.blockedClients.delete(e),document.body.dispatchEvent(new CustomEvent("unblocked",{detail:{clientId:e}}))}))}}NAF.adapters.register("janus",h),e.exports=h},833:(e,t,n)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;t.splice(1,0,n,"color: inherit");let s=0,i=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(s++,"%c"===e&&(i=s))})),t.splice(i,0,n)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=n(736)(t);const{formatters:s}=e.exports;s.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},736:(e,t,n)=>{e.exports=function(e){function t(e){let n,i,r,a=null;function o(...e){if(!o.enabled)return;const s=o,i=Number(new Date),r=i-(n||i);s.diff=r,s.prev=n,s.curr=i,n=i,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let a=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((n,i)=>{if("%%"===n)return"%";a++;const r=t.formatters[i];if("function"==typeof r){const t=e[a];n=r.call(s,t),e.splice(a,1),a--}return n})),t.formatArgs.call(s,e),(s.log||t.log).apply(s,e)}return o.namespace=e,o.useColors=t.useColors(),o.color=t.selectColor(e),o.extend=s,o.destroy=t.destroy,Object.defineProperty(o,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==a?a:(i!==t.namespaces&&(i=t.namespaces,r=t.enabled(e)),r),set:e=>{a=e}}),"function"==typeof t.init&&t.init(o),o}function s(e,n){const s=t(this.namespace+(void 0===n?":":n)+e);return s.log=this.log,s}function i(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(i),...t.skips.map(i).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let n;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const s=("string"==typeof e?e:"").split(/[\s,]+/),i=s.length;for(n=0;n{t[n]=e[n]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let n=0;for(let t=0;t{var t=1e3,n=60*t,s=60*n,i=24*s;function r(e,t,n,s){var i=t>=1.5*n;return Math.round(e/n)+" "+s+(i?"s":"")}e.exports=function(e,a){a=a||{};var o,c,l=typeof e;if("string"===l&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var r=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(r){var a=parseFloat(r[1]);switch((r[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*a;case"weeks":case"week":case"w":return 6048e5*a;case"days":case"day":case"d":return a*i;case"hours":case"hour":case"hrs":case"hr":case"h":return a*s;case"minutes":case"minute":case"mins":case"min":case"m":return a*n;case"seconds":case"second":case"secs":case"sec":case"s":return a*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return a;default:return}}}}(e);if("number"===l&&isFinite(e))return a.long?(o=e,(c=Math.abs(o))>=i?r(o,c,i,"day"):c>=s?r(o,c,s,"hour"):c>=n?r(o,c,n,"minute"):c>=t?r(o,c,t,"second"):o+" ms"):function(e){var r=Math.abs(e);return r>=i?Math.round(e/i)+"d":r>=s?Math.round(e/s)+"h":r>=n?Math.round(e/n)+"m":r>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},963:e=>{"use strict";const t={generateIdentifier:function(){return Math.random().toString(36).substring(2,12)}};t.localCName=t.generateIdentifier(),t.splitLines=function(e){return e.trim().split("\n").map((e=>e.trim()))},t.splitSections=function(e){return e.split("\nm=").map(((e,t)=>(t>0?"m="+e:e).trim()+"\r\n"))},t.getDescription=function(e){const n=t.splitSections(e);return n&&n[0]},t.getMediaSections=function(e){const n=t.splitSections(e);return n.shift(),n},t.matchPrefix=function(e,n){return t.splitLines(e).filter((e=>0===e.indexOf(n)))},t.parseCandidate=function(e){let t;t=0===e.indexOf("a=candidate:")?e.substring(12).split(" "):e.substring(10).split(" ");const n={foundation:t[0],component:{1:"rtp",2:"rtcp"}[t[1]]||t[1],protocol:t[2].toLowerCase(),priority:parseInt(t[3],10),ip:t[4],address:t[4],port:parseInt(t[5],10),type:t[7]};for(let e=8;e0?t[0].split("/")[1]:"sendrecv",uri:t[1],attributes:t.slice(2).join(" ")}},t.writeExtmap=function(e){return"a=extmap:"+(e.id||e.preferredId)+(e.direction&&"sendrecv"!==e.direction?"/"+e.direction:"")+" "+e.uri+(e.attributes?" "+e.attributes:"")+"\r\n"},t.parseFmtp=function(e){const t={};let n;const s=e.substring(e.indexOf(" ")+1).split(";");for(let e=0;e{void 0!==e.parameters[t]?s.push(t+"="+e.parameters[t]):s.push(t)})),t+="a=fmtp:"+n+" "+s.join(";")+"\r\n"}return t},t.parseRtcpFb=function(e){const t=e.substring(e.indexOf(" ")+1).split(" ");return{type:t.shift(),parameter:t.join(" ")}},t.writeRtcpFb=function(e){let t="",n=e.payloadType;return void 0!==e.preferredPayloadType&&(n=e.preferredPayloadType),e.rtcpFeedback&&e.rtcpFeedback.length&&e.rtcpFeedback.forEach((e=>{t+="a=rtcp-fb:"+n+" "+e.type+(e.parameter&&e.parameter.length?" "+e.parameter:"")+"\r\n"})),t},t.parseSsrcMedia=function(e){const t=e.indexOf(" "),n={ssrc:parseInt(e.substring(7,t),10)},s=e.indexOf(":",t);return s>-1?(n.attribute=e.substring(t+1,s),n.value=e.substring(s+1)):n.attribute=e.substring(t+1),n},t.parseSsrcGroup=function(e){const t=e.substring(13).split(" ");return{semantics:t.shift(),ssrcs:t.map((e=>parseInt(e,10)))}},t.getMid=function(e){const n=t.matchPrefix(e,"a=mid:")[0];if(n)return n.substring(6)},t.parseFingerprint=function(e){const t=e.substring(14).split(" ");return{algorithm:t[0].toLowerCase(),value:t[1].toUpperCase()}},t.getDtlsParameters=function(e,n){return{role:"auto",fingerprints:t.matchPrefix(e+n,"a=fingerprint:").map(t.parseFingerprint)}},t.writeDtlsParameters=function(e,t){let n="a=setup:"+t+"\r\n";return e.fingerprints.forEach((e=>{n+="a=fingerprint:"+e.algorithm+" "+e.value+"\r\n"})),n},t.parseCryptoLine=function(e){const t=e.substring(9).split(" ");return{tag:parseInt(t[0],10),cryptoSuite:t[1],keyParams:t[2],sessionParams:t.slice(3)}},t.writeCryptoLine=function(e){return"a=crypto:"+e.tag+" "+e.cryptoSuite+" "+("object"==typeof e.keyParams?t.writeCryptoKeyParams(e.keyParams):e.keyParams)+(e.sessionParams?" "+e.sessionParams.join(" "):"")+"\r\n"},t.parseCryptoKeyParams=function(e){if(0!==e.indexOf("inline:"))return null;const t=e.substring(7).split("|");return{keyMethod:"inline",keySalt:t[0],lifeTime:t[1],mkiValue:t[2]?t[2].split(":")[0]:void 0,mkiLength:t[2]?t[2].split(":")[1]:void 0}},t.writeCryptoKeyParams=function(e){return e.keyMethod+":"+e.keySalt+(e.lifeTime?"|"+e.lifeTime:"")+(e.mkiValue&&e.mkiLength?"|"+e.mkiValue+":"+e.mkiLength:"")},t.getCryptoParameters=function(e,n){return t.matchPrefix(e+n,"a=crypto:").map(t.parseCryptoLine)},t.getIceParameters=function(e,n){const s=t.matchPrefix(e+n,"a=ice-ufrag:")[0],i=t.matchPrefix(e+n,"a=ice-pwd:")[0];return s&&i?{usernameFragment:s.substring(12),password:i.substring(10)}:null},t.writeIceParameters=function(e){let t="a=ice-ufrag:"+e.usernameFragment+"\r\na=ice-pwd:"+e.password+"\r\n";return e.iceLite&&(t+="a=ice-lite\r\n"),t},t.parseRtpParameters=function(e){const n={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]},s=t.splitLines(e)[0].split(" ");n.profile=s[2];for(let i=3;i{n.headerExtensions.push(t.parseExtmap(e))}));const i=t.matchPrefix(e,"a=rtcp-fb:* ").map(t.parseRtcpFb);return n.codecs.forEach((e=>{i.forEach((t=>{e.rtcpFeedback.find((e=>e.type===t.type&&e.parameter===t.parameter))||e.rtcpFeedback.push(t)}))})),n},t.writeRtpDescription=function(e,n){let s="";s+="m="+e+" ",s+=n.codecs.length>0?"9":"0",s+=" "+(n.profile||"UDP/TLS/RTP/SAVPF")+" ",s+=n.codecs.map((e=>void 0!==e.preferredPayloadType?e.preferredPayloadType:e.payloadType)).join(" ")+"\r\n",s+="c=IN IP4 0.0.0.0\r\n",s+="a=rtcp:9 IN IP4 0.0.0.0\r\n",n.codecs.forEach((e=>{s+=t.writeRtpMap(e),s+=t.writeFmtp(e),s+=t.writeRtcpFb(e)}));let i=0;return n.codecs.forEach((e=>{e.maxptime>i&&(i=e.maxptime)})),i>0&&(s+="a=maxptime:"+i+"\r\n"),n.headerExtensions&&n.headerExtensions.forEach((e=>{s+=t.writeExtmap(e)})),s},t.parseRtpEncodingParameters=function(e){const n=[],s=t.parseRtpParameters(e),i=-1!==s.fecMechanisms.indexOf("RED"),r=-1!==s.fecMechanisms.indexOf("ULPFEC"),a=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"cname"===e.attribute)),o=a.length>0&&a[0].ssrc;let c;const l=t.matchPrefix(e,"a=ssrc-group:FID").map((e=>e.substring(17).split(" ").map((e=>parseInt(e,10)))));l.length>0&&l[0].length>1&&l[0][0]===o&&(c=l[0][1]),s.codecs.forEach((e=>{if("RTX"===e.name.toUpperCase()&&e.parameters.apt){let t={ssrc:o,codecPayloadType:parseInt(e.parameters.apt,10)};o&&c&&(t.rtx={ssrc:c}),n.push(t),i&&(t=JSON.parse(JSON.stringify(t)),t.fec={ssrc:o,mechanism:r?"red+ulpfec":"red"},n.push(t))}})),0===n.length&&o&&n.push({ssrc:o});let d=t.matchPrefix(e,"b=");return d.length&&(d=0===d[0].indexOf("b=TIAS:")?parseInt(d[0].substring(7),10):0===d[0].indexOf("b=AS:")?1e3*parseInt(d[0].substring(5),10)*.95-16e3:void 0,n.forEach((e=>{e.maxBitrate=d}))),n},t.parseRtcpParameters=function(e){const n={},s=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"cname"===e.attribute))[0];s&&(n.cname=s.value,n.ssrc=s.ssrc);const i=t.matchPrefix(e,"a=rtcp-rsize");n.reducedSize=i.length>0,n.compound=0===i.length;const r=t.matchPrefix(e,"a=rtcp-mux");return n.mux=r.length>0,n},t.writeRtcpParameters=function(e){let t="";return e.reducedSize&&(t+="a=rtcp-rsize\r\n"),e.mux&&(t+="a=rtcp-mux\r\n"),void 0!==e.ssrc&&e.cname&&(t+="a=ssrc:"+e.ssrc+" cname:"+e.cname+"\r\n"),t},t.parseMsid=function(e){let n;const s=t.matchPrefix(e,"a=msid:");if(1===s.length)return n=s[0].substring(7).split(" "),{stream:n[0],track:n[1]};const i=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"msid"===e.attribute));return i.length>0?(n=i[0].value.split(" "),{stream:n[0],track:n[1]}):void 0},t.parseSctpDescription=function(e){const n=t.parseMLine(e),s=t.matchPrefix(e,"a=max-message-size:");let i;s.length>0&&(i=parseInt(s[0].substring(19),10)),isNaN(i)&&(i=65536);const r=t.matchPrefix(e,"a=sctp-port:");if(r.length>0)return{port:parseInt(r[0].substring(12),10),protocol:n.fmt,maxMessageSize:i};const a=t.matchPrefix(e,"a=sctpmap:");if(a.length>0){const e=a[0].substring(10).split(" ");return{port:parseInt(e[0],10),protocol:e[1],maxMessageSize:i}}},t.writeSctpDescription=function(e,t){let n=[];return n="DTLS/SCTP"!==e.protocol?["m="+e.kind+" 9 "+e.protocol+" "+t.protocol+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctp-port:"+t.port+"\r\n"]:["m="+e.kind+" 9 "+e.protocol+" "+t.port+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctpmap:"+t.port+" "+t.protocol+" 65535\r\n"],void 0!==t.maxMessageSize&&n.push("a=max-message-size:"+t.maxMessageSize+"\r\n"),n.join("")},t.generateSessionId=function(){return Math.random().toString().substr(2,22)},t.writeSessionBoilerplate=function(e,n,s){let i;const r=void 0!==n?n:2;return i=e||t.generateSessionId(),"v=0\r\no="+(s||"thisisadapterortc")+" "+i+" "+r+" IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},t.getDirection=function(e,n){const s=t.splitLines(e);for(let e=0;e{var e={734:e=>{function t(e){this.session=e,this.id=void 0}function n(e,t){this.output=e,this.id=void 0,this.nextTxId=0,this.txns={},this.eventHandlers={},this.options=Object.assign({verbose:!1,timeoutMs:1e4,keepaliveMs:3e4},t)}t.prototype.attach=function(e,t){var n={plugin:e,loop_index:t,"force-bundle":!0,"force-rtcp-mux":!0};return this.session.send("attach",n).then((e=>(this.id=e.data.id,e)))},t.prototype.detach=function(){return this.send("detach")},t.prototype.on=function(e,t){return this.session.on(e,(e=>{e.sender==this.id&&t(e)}))},t.prototype.send=function(e,t){return this.session.send(e,Object.assign({handle_id:this.id},t))},t.prototype.sendMessage=function(e){return this.send("message",{body:e})},t.prototype.sendJsep=function(e){return this.send("message",{body:{},jsep:e})},t.prototype.sendTrickle=function(e){return this.send("trickle",{candidate:e})},n.prototype.create=function(){return this.send("create").then((e=>(this.id=e.data.id,e)))},n.prototype.destroy=function(){return this.send("destroy").then((e=>(this.dispose(),e)))},n.prototype.dispose=function(){for(var e in this._killKeepalive(),this.eventHandlers={},this.txns)if(this.txns.hasOwnProperty(e)){var t=this.txns[e];clearTimeout(t.timeout),t.reject(new Error("Janus session was disposed.")),delete this.txns[e]}},n.prototype.isError=function(e){return"error"===e.janus},n.prototype.on=function(e,t){var n=this.eventHandlers[e];null==n&&(n=this.eventHandlers[e]=[]),n.push(t)},n.prototype.receive=function(e){this.options.verbose&&this._logIncoming(e),e.session_id!=this.id&&console.warn("Incorrect session ID received in Janus signalling message: was "+e.session_id+", expected "+this.id+".");var t=e.janus,n=this.eventHandlers[t];if(null!=n)for(var s=0;s{var i=null;this.options.timeoutMs&&(i=setTimeout((()=>{delete this.txns[t.transaction],s(new Error("Signalling transaction with txid "+t.transaction+" timed out."))}),this.options.timeoutMs)),this.txns[t.transaction]={resolve:n,reject:s,timeout:i,type:e},this._transmit(e,t)}))},n.prototype._transmit=function(e,t){t=Object.assign({janus:e},t),null!=this.id&&(t=Object.assign({session_id:this.id},t)),this.options.verbose&&this._logOutgoing(t),this.output(JSON.stringify(t)),this._resetKeepalive()},n.prototype._logOutgoing=function(e){var t=e.janus;"message"===t&&e.jsep&&(t=e.jsep.type);var n="> Outgoing Janus "+(t||"signal")+" (#"+e.transaction+"): ";console.debug("%c"+n,"color: #040",e)},n.prototype._logIncoming=function(e){var t=e.janus,n=e.transaction?"< Incoming Janus "+(t||"signal")+" (#"+e.transaction+"): ":"< Incoming Janus "+(t||"signal")+": ";console.debug("%c"+n,"color: #004",e)},n.prototype._sendKeepalive=function(){return this.send("keepalive")},n.prototype._killKeepalive=function(){clearTimeout(this.keepaliveTimeout)},n.prototype._resetKeepalive=function(){this._killKeepalive(),this.options.keepaliveMs&&(this.keepaliveTimeout=setTimeout((()=>{this._sendKeepalive().catch((e=>console.error("Error received from keepalive: ",e)))}),this.options.keepaliveMs))},e.exports={JanusPluginHandle:t,JanusSession:n}},497:(e,t,n)=>{var s=n(734);s.JanusSession.prototype.sendOriginal=s.JanusSession.prototype.send,s.JanusSession.prototype.send=function(e,t){return this.sendOriginal(e,t).catch((e=>{if(!(e.message&&e.message.indexOf("timed out")>-1))throw e;console.error("web socket timed out"),NAF.connection.adapter.reconnect()}))};var i=n(963),r=n(833)("naf-janus-adapter:debug"),a=(n(833)("naf-janus-adapter:warn"),n(833)("naf-janus-adapter:error")),o=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function c(e){var t=Promise.resolve();return function(){var n=Array.prototype.slice.call(arguments);t=t.then((t=>e.apply(this,n)))}}function l(e){return new Promise(((t,n)=>{if("open"===e.readyState)t();else{let s,i;const r=()=>{e.removeEventListener("open",s),e.removeEventListener("error",i)};s=()=>{r(),t()},i=()=>{r(),n()},e.addEventListener("open",s),e.addEventListener("error",i)}}))}const d=""!==document.createElement("video").canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'),u={usedtx:1,stereo:0,"sprop-stereo":0},p={iceServers:[{urls:"stun:stun1.l.google.com:19302"},{urls:"stun:stun2.l.google.com:19302"}]};class h{constructor(){this.room=null,this.clientId=null,this.joinToken=null,this.serverUrl=null,this.webRtcOptions={},this.peerConnectionConfig=null,this.ws=null,this.session=null,this.reliableTransport="datachannel",this.unreliableTransport="datachannel",this.initialReconnectionDelay=1e3*Math.random(),this.reconnectionDelay=this.initialReconnectionDelay,this.reconnectionTimeout=null,this.maxReconnectionAttempts=10,this.reconnectionAttempts=0,this.isReconnecting=!1,this.publisher=null,this.occupantIds=[],this.occupants={},this.mediaStreams={},this.localMediaStream=null,this.pendingMediaRequests=new Map,this.pendingOccupants=new Set,this.availableOccupants=[],this.requestedOccupants=null,this.blockedClients=new Map,this.frozenUpdates=new Map,this.timeOffsets=[],this.serverTimeRequests=0,this.avgTimeOffset=0,this.onWebsocketOpen=this.onWebsocketOpen.bind(this),this.onWebsocketClose=this.onWebsocketClose.bind(this),this.onWebsocketMessage=this.onWebsocketMessage.bind(this),this.onDataChannelMessage=this.onDataChannelMessage.bind(this),this.onData=this.onData.bind(this)}setServerUrl(e){this.serverUrl=e}setApp(e){}setRoom(e){this.room=e}setJoinToken(e){this.joinToken=e}setClientId(e){this.clientId=e}setWebRtcOptions(e){this.webRtcOptions=e}setPeerConnectionConfig(e){this.peerConnectionConfig=e}setServerConnectListeners(e,t){this.connectSuccess=e,this.connectFailure=t}setRoomOccupantListener(e){this.onOccupantsChanged=e}setDataChannelListeners(e,t,n){this.onOccupantConnected=e,this.onOccupantDisconnected=t,this.onOccupantMessage=n}setReconnectionListeners(e,t,n){this.onReconnecting=e,this.onReconnected=t,this.onReconnectionError=n}setEventLoops(e){this.loops=e}connect(){"/"===this.serverUrl&&(this.serverUrl="/janus"),"/janus"===this.serverUrl&&("https:"===location.protocol?this.serverUrl="wss://"+location.host+"/janus":this.serverUrl="ws://"+location.host+"/janus"),r(`connecting to ${this.serverUrl}`);const e=new Promise(((e,t)=>{this.ws=new WebSocket(this.serverUrl,"janus-protocol"),this.session=new s.JanusSession(this.ws.send.bind(this.ws),{timeoutMs:4e4}),this.websocketConnectionPromise={},this.websocketConnectionPromise.resolve=e,this.websocketConnectionPromise.reject=t,this.ws.addEventListener("close",this.onWebsocketClose),this.ws.addEventListener("message",this.onWebsocketMessage),this.wsOnOpen=()=>{this.ws.removeEventListener("open",this.wsOnOpen),this.onWebsocketOpen().then(e).catch(t)},this.ws.addEventListener("open",this.wsOnOpen)}));return Promise.all([e,this.updateTimeOffset()])}disconnect(){r("disconnecting"),clearTimeout(this.reconnectionTimeout),this.removeAllOccupants(),this.publisher&&(this.publisher.conn.close(),this.publisher=null),this.session&&(this.session.dispose(),this.session=null),this.ws&&(this.ws.removeEventListener("open",this.wsOnOpen),this.ws.removeEventListener("close",this.onWebsocketClose),this.ws.removeEventListener("message",this.onWebsocketMessage),this.ws.close(),this.ws=null),this.delayedReconnectTimeout&&(clearTimeout(this.delayedReconnectTimeout),this.delayedReconnectTimeout=null)}isDisconnected(){return null===this.ws}async onWebsocketOpen(){await this.session.create(),this.publisher=await this.createPublisher(),this.connectSuccess(this.clientId);for(let e=0;ethis.reconnect()),this.reconnectionDelay)))}reconnect(){this.disconnect(),this.connect().then((()=>{this.reconnectionDelay=this.initialReconnectionDelay,this.reconnectionAttempts=0,this.isReconnecting=!1,this.onReconnected&&this.onReconnected()})).catch((e=>{if(this.reconnectionDelay+=1e3,this.reconnectionAttempts++,this.reconnectionAttempts>this.maxReconnectionAttempts){const e=new Error("Connection could not be reestablished, exceeded maximum number of reconnection attempts.");return this.onReconnectionError?this.onReconnectionError(e):void console.warn(e)}console.warn("Error during reconnect, retrying."),console.warn(e),this.onReconnecting&&this.onReconnecting(this.reconnectionDelay),this.reconnectionTimeout=setTimeout((()=>this.reconnect()),this.reconnectionDelay)}))}performDelayedReconnect(){this.delayedReconnectTimeout&&clearTimeout(this.delayedReconnectTimeout),this.delayedReconnectTimeout=setTimeout((()=>{this.delayedReconnectTimeout=null,this.reconnect()}),1e4)}onWebsocketMessage(e){this.session.receive(JSON.parse(e.data))}addAvailableOccupant(e){-1===this.availableOccupants.indexOf(e)&&this.availableOccupants.push(e)}removeAvailableOccupant(e){const t=this.availableOccupants.indexOf(e);-1!==t&&this.availableOccupants.splice(t,1)}syncOccupants(e){if(e&&(this.requestedOccupants=e),this.requestedOccupants){for(let e=0;e5&&await new Promise((e=>{const t=5e3*Math.random()+0;setTimeout(e,t)}));const t=await this.createSubscriber(e);t&&(this.pendingOccupants.has(e)?(this.pendingOccupants.delete(e),this.occupantIds.push(e),this.occupants[e]=t,this.setMediaStream(e,t.mediaStream),this.onOccupantConnected(e)):t.conn.close())}removeAllOccupants(){this.pendingOccupants.clear();for(let e=this.occupantIds.length-1;e>=0;e--)this.removeOccupant(this.occupantIds[e])}removeOccupant(e){if(this.pendingOccupants.delete(e),this.occupants[e]&&(this.occupants[e].conn.close(),delete this.occupants[e],this.occupantIds.splice(this.occupantIds.indexOf(e),1)),this.mediaStreams[e]&&delete this.mediaStreams[e],this.pendingMediaRequests.has(e)){const t="The user disconnected before the media stream was resolved.";this.pendingMediaRequests.get(e).audio.reject(t),this.pendingMediaRequests.get(e).video.reject(t),this.pendingMediaRequests.delete(e)}this.onOccupantDisconnected(e)}associate(e,t){e.addEventListener("icecandidate",(e=>{t.sendTrickle(e.candidate||null).catch((e=>a("Error trickling ICE: %o",e)))})),e.addEventListener("iceconnectionstatechange",(t=>{"connected"===e.iceConnectionState&&console.log("ICE state changed to connected"),"disconnected"===e.iceConnectionState&&console.warn("ICE state changed to disconnected"),"failed"===e.iceConnectionState&&(console.warn("ICE failure detected. Reconnecting in 10s."),this.performDelayedReconnect())})),e.addEventListener("negotiationneeded",c((n=>{r("Sending new offer for handle: %o",t);var s=e.createOffer().then(this.configurePublisherSdp).then(this.fixSafariIceUFrag),i=s.then((t=>e.setLocalDescription(t))),o=s;return o=o.then(this.fixSafariIceUFrag).then((e=>t.sendJsep(e))).then((t=>e.setRemoteDescription(t.jsep))),Promise.all([i,o]).catch((e=>a("Error negotiating offer: %o",e)))}))),t.on("event",c((n=>{var s=n.jsep;if(s&&"offer"==s.type){r("Accepting new offer for handle: %o",t);var i=e.setRemoteDescription(this.configureSubscriberSdp(s)).then((t=>e.createAnswer())).then(this.fixSafariIceUFrag),o=i.then((t=>e.setLocalDescription(t))),c=i.then((e=>t.sendJsep(e)));return Promise.all([o,c]).catch((e=>a("Error negotiating answer: %o",e)))}return null})))}async createPublisher(){var e=new s.JanusPluginHandle(this.session),t=new RTCPeerConnection(this.peerConnectionConfig||p);r("pub waiting for sfu"),await e.attach("janus.plugin.sfu",this.loops&&this.clientId?parseInt(this.clientId)%this.loops:void 0),this.associate(t,e),r("pub waiting for data channels & webrtcup");var n=new Promise((t=>e.on("webrtcup",t))),i=t.createDataChannel("reliable",{ordered:!0}),a=t.createDataChannel("unreliable",{ordered:!1,maxRetransmits:0});i.addEventListener("message",(e=>this.onDataChannelMessage(e,"janus-reliable"))),a.addEventListener("message",(e=>this.onDataChannelMessage(e,"janus-unreliable"))),await n,await l(i),await l(a),this.localMediaStream&&this.localMediaStream.getTracks().forEach((e=>{t.addTrack(e,this.localMediaStream)})),e.on("event",(e=>{var t=e.plugindata.data;if("join"==t.event&&t.room_id==this.room){if(this.delayedReconnectTimeout)return;this.addAvailableOccupant(t.user_id),this.syncOccupants()}else"leave"==t.event&&t.room_id==this.room?(this.removeAvailableOccupant(t.user_id),this.removeOccupant(t.user_id)):"blocked"==t.event?document.body.dispatchEvent(new CustomEvent("blocked",{detail:{clientId:t.by}})):"unblocked"==t.event?document.body.dispatchEvent(new CustomEvent("unblocked",{detail:{clientId:t.by}})):"data"===t.event&&this.onData(JSON.parse(t.body),"janus-event")})),r("pub waiting for join");var o=await this.sendJoin(e,{notifications:!0,data:!0});if(!o.plugindata.data.success){const e=o.plugindata.data.error;throw console.error(e),t.close(),e}var c=o.plugindata.data.response.users[this.room]||[];return c.includes(this.clientId)&&(console.warn("Janus still has previous session for this client. Reconnecting in 10s."),this.performDelayedReconnect()),r("publisher ready"),{handle:e,initialOccupants:c,reliableChannel:i,unreliableChannel:a,conn:t}}configurePublisherSdp(e){return e.sdp=e.sdp.replace(/a=fmtp:(109|111).*\r\n/g,((e,t)=>{const n=Object.assign(i.parseFmtp(e),u);return i.writeFmtp({payloadType:t,parameters:n})})),e}configureSubscriberSdp(e){return d||-1!==navigator.userAgent.indexOf("HeadlessChrome")&&(e.sdp=e.sdp.replace(/m=video[^]*m=/,"m=")),-1===navigator.userAgent.indexOf("Android")?e.sdp=e.sdp.replace("a=rtcp-fb:107 goog-remb\r\n","a=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\n"):e.sdp=e.sdp.replace("a=rtcp-fb:107 goog-remb\r\n","a=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\n"),e}async fixSafariIceUFrag(e){return e.sdp=e.sdp.replace(/[^\r]\na=ice-ufrag/g,"\r\na=ice-ufrag"),e}async createSubscriber(e,t=5){if(-1===this.availableOccupants.indexOf(e))return console.warn(e+": cancelled occupant connection, occupant left before subscription negotation."),null;var n=new s.JanusPluginHandle(this.session),i=new RTCPeerConnection(this.peerConnectionConfig||p);if(r(e+": sub waiting for sfu"),await n.attach("janus.plugin.sfu",this.loops?parseInt(e)%this.loops:void 0),this.associate(i,n),r(e+": sub waiting for join"),-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancelled occupant connection, occupant left after attach"),null;let a=!1;const c=new Promise((t=>{const s=setInterval((()=>{-1===this.availableOccupants.indexOf(e)&&(clearInterval(s),t())}),1e3),i=setTimeout((()=>{clearInterval(s),a=!0,t()}),15e3);n.on("webrtcup",(()=>{clearTimeout(i),clearInterval(s),t()}))}));if(await this.sendJoin(n,{media:e}),-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancelled occupant connection, occupant left after join"),null;if(r(e+": sub waiting for webrtcup"),await c,-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancel occupant connection, occupant left during or after webrtcup"),null;if(a)return i.close(),t>0?(console.warn(e+": webrtc up timed out, retrying"),this.createSubscriber(e,t-1)):(console.warn(e+": webrtc up timed out"),null);o&&!this._iOSHackDelayedInitialPeer&&(await new Promise((e=>setTimeout(e,3e3))),this._iOSHackDelayedInitialPeer=!0);var l=new MediaStream;return i.getReceivers().forEach((e=>{e.track&&l.addTrack(e.track)})),0===l.getTracks().length&&(l=null),r(e+": subscriber ready"),{handle:n,mediaStream:l,conn:i}}sendJoin(e,t){return e.sendMessage({kind:"join",room_id:this.room,user_id:this.clientId,subscribe:t,token:this.joinToken})}toggleFreeze(){this.frozen?this.unfreeze():this.freeze()}freeze(){this.frozen=!0}unfreeze(){this.frozen=!1,this.flushPendingUpdates()}dataForUpdateMultiMessage(e,t){for(let n=0,s=t.data.d.length;nn.owner)return;"r"===s?r&&r.isFirstSync?this.frozenUpdates.delete(i):this.frozenUpdates.set(i,e):r.components&&n.components&&Object.assign(r.components,n.components)}else this.frozenUpdates.set(i,e)}onDataChannelMessage(e,t){this.onData(JSON.parse(e.data),t)}onData(e,t){r.enabled&&r(`DC in: ${e}`),e.dataType&&(e.source=t,this.frozen?this.storeMessage(e):this.onOccupantMessage(null,e.dataType,e.data,e.source))}shouldStartConnectionTo(e){return!0}startStreamConnection(e){}closeStreamConnection(e){}getConnectStatus(e){return this.occupants[e]?NAF.adapters.IS_CONNECTED:NAF.adapters.NOT_CONNECTED}async updateTimeOffset(){if(this.isDisconnected())return;const e=Date.now(),t=await fetch(document.location.href,{method:"HEAD",cache:"no-cache"}),n=new Date(t.headers.get("Date")).getTime()+500,s=Date.now(),i=n+(s-e)/2-s;this.serverTimeRequests++,this.serverTimeRequests<=10?this.timeOffsets.push(i):this.timeOffsets[this.serverTimeRequests%10]=i,this.avgTimeOffset=this.timeOffsets.reduce(((e,t)=>e+t),0)/this.timeOffsets.length,this.serverTimeRequests>10?(r(`new server time offset: ${this.avgTimeOffset}ms`),setTimeout((()=>this.updateTimeOffset()),3e5)):this.updateTimeOffset()}getServerTime(){return Date.now()+this.avgTimeOffset}getMediaStream(e,t="audio"){if(this.mediaStreams[e])return r(`Already had ${t} for ${e}`),Promise.resolve(this.mediaStreams[e][t]);if(r(`Waiting on ${t} for ${e}`),!this.pendingMediaRequests.has(e)){this.pendingMediaRequests.set(e,{});const t=new Promise(((t,n)=>{this.pendingMediaRequests.get(e).audio={resolve:t,reject:n}})),n=new Promise(((t,n)=>{this.pendingMediaRequests.get(e).video={resolve:t,reject:n}}));this.pendingMediaRequests.get(e).audio.promise=t,this.pendingMediaRequests.get(e).video.promise=n,t.catch((t=>console.warn(`${e} getMediaStream Audio Error`,t))),n.catch((t=>console.warn(`${e} getMediaStream Video Error`,t)))}return this.pendingMediaRequests.get(e)[t].promise}setMediaStream(e,t){const n=new MediaStream;try{t.getAudioTracks().forEach((e=>n.addTrack(e)))}catch(t){console.warn(`${e} setMediaStream Audio Error`,t)}const s=new MediaStream;try{t.getVideoTracks().forEach((e=>s.addTrack(e)))}catch(t){console.warn(`${e} setMediaStream Video Error`,t)}this.mediaStreams[e]={audio:n,video:s},this.pendingMediaRequests.has(e)&&(this.pendingMediaRequests.get(e).audio.resolve(n),this.pendingMediaRequests.get(e).video.resolve(s))}getLocalMediaStream(){return this.localMediaStream}async setLocalMediaStream(e){if(this.publisher&&this.publisher.conn){const t=this.publisher.conn.getSenders(),n=[],s=e.getTracks();for(let i=0;inull!=e.track&&e.track.kind==r.kind));null!=a?(a.replaceTrack?await a.replaceTrack(r):(e.removeTrack(a.track),e.addTrack(r)),n.push(a)):n.push(this.publisher.conn.addTrack(r,e))}t.forEach((e=>{n.includes(e)||(e.track.enabled=!1)}))}this.localMediaStream=e,this.setMediaStream(this.clientId,e)}enableMicrophone(e){this.publisher&&this.publisher.conn&&this.publisher.conn.getSenders().forEach((t=>{"audio"==t.track.kind&&(t.track.enabled=e)}))}sendData(e,t,n){if(this.publisher)switch(this.unreliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:t,data:n}),whom:e});break;case"datachannel":"open"===this.publisher.unreliableChannel.readyState&&this.publisher.unreliableChannel.send(JSON.stringify({clientId:e,dataType:t,data:n}));break;default:this.unreliableTransport(e,t,n)}else console.warn("sendData called without a publisher")}sendDataGuaranteed(e,t,n){if(this.publisher)switch(this.reliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:t,data:n}),whom:e});break;case"datachannel":"open"===this.publisher.reliableChannel.readyState&&this.publisher.reliableChannel.send(JSON.stringify({clientId:e,dataType:t,data:n}));break;default:this.reliableTransport(e,t,n)}else console.warn("sendDataGuaranteed called without a publisher")}broadcastData(e,t){if(this.publisher)switch(this.unreliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:e,data:t})});break;case"datachannel":"open"===this.publisher.unreliableChannel.readyState&&this.publisher.unreliableChannel.send(JSON.stringify({dataType:e,data:t}));break;default:this.unreliableTransport(void 0,e,t)}else console.warn("broadcastData called without a publisher")}broadcastDataGuaranteed(e,t){if(this.publisher)switch(this.reliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:e,data:t})});break;case"datachannel":"open"===this.publisher.reliableChannel.readyState&&this.publisher.reliableChannel.send(JSON.stringify({dataType:e,data:t}));break;default:this.reliableTransport(void 0,e,t)}else console.warn("broadcastDataGuaranteed called without a publisher")}kick(e,t){return this.publisher.handle.sendMessage({kind:"kick",room_id:this.room,user_id:e,token:t}).then((()=>{document.body.dispatchEvent(new CustomEvent("kicked",{detail:{clientId:e}}))}))}block(e){return this.publisher.handle.sendMessage({kind:"block",whom:e}).then((()=>{this.blockedClients.set(e,!0),document.body.dispatchEvent(new CustomEvent("blocked",{detail:{clientId:e}}))}))}unblock(e){return this.publisher.handle.sendMessage({kind:"unblock",whom:e}).then((()=>{this.blockedClients.delete(e),document.body.dispatchEvent(new CustomEvent("unblocked",{detail:{clientId:e}}))}))}}NAF.adapters.register("janus",h),e.exports=h},833:(e,t,n)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;t.splice(1,0,n,"color: inherit");let s=0,i=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(s++,"%c"===e&&(i=s))})),t.splice(i,0,n)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){if("undefined"!=typeof window&&window.process&&("renderer"===window.process.type||window.process.__nwjs))return!0;if("undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;let e;return"undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&(e=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/))&&parseInt(e[1],10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=n(736)(t);const{formatters:s}=e.exports;s.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},736:(e,t,n)=>{e.exports=function(e){function t(e){let n,i,r,a=null;function o(...e){if(!o.enabled)return;const s=o,i=Number(new Date),r=i-(n||i);s.diff=r,s.prev=n,s.curr=i,n=i,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let a=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((n,i)=>{if("%%"===n)return"%";a++;const r=t.formatters[i];if("function"==typeof r){const t=e[a];n=r.call(s,t),e.splice(a,1),a--}return n})),t.formatArgs.call(s,e),(s.log||t.log).apply(s,e)}return o.namespace=e,o.useColors=t.useColors(),o.color=t.selectColor(e),o.extend=s,o.destroy=t.destroy,Object.defineProperty(o,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==a?a:(i!==t.namespaces&&(i=t.namespaces,r=t.enabled(e)),r),set:e=>{a=e}}),"function"==typeof t.init&&t.init(o),o}function s(e,n){const s=t(this.namespace+(void 0===n?":":n)+e);return s.log=this.log,s}function i(e,t){let n=0,s=0,i=-1,r=0;for(;n"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").trim().replace(" ",",").split(",").filter(Boolean);for(const e of n)"-"===e[0]?t.skips.push(e.slice(1)):t.names.push(e)},t.enabled=function(e){for(const n of t.skips)if(i(e,n))return!1;for(const n of t.names)if(i(e,n))return!0;return!1},t.humanize=n(585),t.destroy=function(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")},Object.keys(e).forEach((n=>{t[n]=e[n]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let n=0;for(let t=0;t{var t=1e3,n=60*t,s=60*n,i=24*s,r=7*i;function a(e,t,n,s){var i=t>=1.5*n;return Math.round(e/n)+" "+s+(i?"s":"")}e.exports=function(e,o){o=o||{};var c,l,d=typeof e;if("string"===d&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var a=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(a){var o=parseFloat(a[1]);switch((a[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*o;case"weeks":case"week":case"w":return o*r;case"days":case"day":case"d":return o*i;case"hours":case"hour":case"hrs":case"hr":case"h":return o*s;case"minutes":case"minute":case"mins":case"min":case"m":return o*n;case"seconds":case"second":case"secs":case"sec":case"s":return o*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return o;default:return}}}}(e);if("number"===d&&isFinite(e))return o.long?(c=e,(l=Math.abs(c))>=i?a(c,l,i,"day"):l>=s?a(c,l,s,"hour"):l>=n?a(c,l,n,"minute"):l>=t?a(c,l,t,"second"):c+" ms"):function(e){var r=Math.abs(e);return r>=i?Math.round(e/i)+"d":r>=s?Math.round(e/s)+"h":r>=n?Math.round(e/n)+"m":r>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},963:e=>{"use strict";const t={generateIdentifier:function(){return Math.random().toString(36).substring(2,12)}};t.localCName=t.generateIdentifier(),t.splitLines=function(e){return e.trim().split("\n").map((e=>e.trim()))},t.splitSections=function(e){return e.split("\nm=").map(((e,t)=>(t>0?"m="+e:e).trim()+"\r\n"))},t.getDescription=function(e){const n=t.splitSections(e);return n&&n[0]},t.getMediaSections=function(e){const n=t.splitSections(e);return n.shift(),n},t.matchPrefix=function(e,n){return t.splitLines(e).filter((e=>0===e.indexOf(n)))},t.parseCandidate=function(e){let t;t=0===e.indexOf("a=candidate:")?e.substring(12).split(" "):e.substring(10).split(" ");const n={foundation:t[0],component:{1:"rtp",2:"rtcp"}[t[1]]||t[1],protocol:t[2].toLowerCase(),priority:parseInt(t[3],10),ip:t[4],address:t[4],port:parseInt(t[5],10),type:t[7]};for(let e=8;e0?t[0].split("/")[1]:"sendrecv",uri:t[1],attributes:t.slice(2).join(" ")}},t.writeExtmap=function(e){return"a=extmap:"+(e.id||e.preferredId)+(e.direction&&"sendrecv"!==e.direction?"/"+e.direction:"")+" "+e.uri+(e.attributes?" "+e.attributes:"")+"\r\n"},t.parseFmtp=function(e){const t={};let n;const s=e.substring(e.indexOf(" ")+1).split(";");for(let e=0;e{void 0!==e.parameters[t]?s.push(t+"="+e.parameters[t]):s.push(t)})),t+="a=fmtp:"+n+" "+s.join(";")+"\r\n"}return t},t.parseRtcpFb=function(e){const t=e.substring(e.indexOf(" ")+1).split(" ");return{type:t.shift(),parameter:t.join(" ")}},t.writeRtcpFb=function(e){let t="",n=e.payloadType;return void 0!==e.preferredPayloadType&&(n=e.preferredPayloadType),e.rtcpFeedback&&e.rtcpFeedback.length&&e.rtcpFeedback.forEach((e=>{t+="a=rtcp-fb:"+n+" "+e.type+(e.parameter&&e.parameter.length?" "+e.parameter:"")+"\r\n"})),t},t.parseSsrcMedia=function(e){const t=e.indexOf(" "),n={ssrc:parseInt(e.substring(7,t),10)},s=e.indexOf(":",t);return s>-1?(n.attribute=e.substring(t+1,s),n.value=e.substring(s+1)):n.attribute=e.substring(t+1),n},t.parseSsrcGroup=function(e){const t=e.substring(13).split(" ");return{semantics:t.shift(),ssrcs:t.map((e=>parseInt(e,10)))}},t.getMid=function(e){const n=t.matchPrefix(e,"a=mid:")[0];if(n)return n.substring(6)},t.parseFingerprint=function(e){const t=e.substring(14).split(" ");return{algorithm:t[0].toLowerCase(),value:t[1].toUpperCase()}},t.getDtlsParameters=function(e,n){return{role:"auto",fingerprints:t.matchPrefix(e+n,"a=fingerprint:").map(t.parseFingerprint)}},t.writeDtlsParameters=function(e,t){let n="a=setup:"+t+"\r\n";return e.fingerprints.forEach((e=>{n+="a=fingerprint:"+e.algorithm+" "+e.value+"\r\n"})),n},t.parseCryptoLine=function(e){const t=e.substring(9).split(" ");return{tag:parseInt(t[0],10),cryptoSuite:t[1],keyParams:t[2],sessionParams:t.slice(3)}},t.writeCryptoLine=function(e){return"a=crypto:"+e.tag+" "+e.cryptoSuite+" "+("object"==typeof e.keyParams?t.writeCryptoKeyParams(e.keyParams):e.keyParams)+(e.sessionParams?" "+e.sessionParams.join(" "):"")+"\r\n"},t.parseCryptoKeyParams=function(e){if(0!==e.indexOf("inline:"))return null;const t=e.substring(7).split("|");return{keyMethod:"inline",keySalt:t[0],lifeTime:t[1],mkiValue:t[2]?t[2].split(":")[0]:void 0,mkiLength:t[2]?t[2].split(":")[1]:void 0}},t.writeCryptoKeyParams=function(e){return e.keyMethod+":"+e.keySalt+(e.lifeTime?"|"+e.lifeTime:"")+(e.mkiValue&&e.mkiLength?"|"+e.mkiValue+":"+e.mkiLength:"")},t.getCryptoParameters=function(e,n){return t.matchPrefix(e+n,"a=crypto:").map(t.parseCryptoLine)},t.getIceParameters=function(e,n){const s=t.matchPrefix(e+n,"a=ice-ufrag:")[0],i=t.matchPrefix(e+n,"a=ice-pwd:")[0];return s&&i?{usernameFragment:s.substring(12),password:i.substring(10)}:null},t.writeIceParameters=function(e){let t="a=ice-ufrag:"+e.usernameFragment+"\r\na=ice-pwd:"+e.password+"\r\n";return e.iceLite&&(t+="a=ice-lite\r\n"),t},t.parseRtpParameters=function(e){const n={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]},s=t.splitLines(e)[0].split(" ");n.profile=s[2];for(let i=3;i{n.headerExtensions.push(t.parseExtmap(e))}));const i=t.matchPrefix(e,"a=rtcp-fb:* ").map(t.parseRtcpFb);return n.codecs.forEach((e=>{i.forEach((t=>{e.rtcpFeedback.find((e=>e.type===t.type&&e.parameter===t.parameter))||e.rtcpFeedback.push(t)}))})),n},t.writeRtpDescription=function(e,n){let s="";s+="m="+e+" ",s+=n.codecs.length>0?"9":"0",s+=" "+(n.profile||"UDP/TLS/RTP/SAVPF")+" ",s+=n.codecs.map((e=>void 0!==e.preferredPayloadType?e.preferredPayloadType:e.payloadType)).join(" ")+"\r\n",s+="c=IN IP4 0.0.0.0\r\n",s+="a=rtcp:9 IN IP4 0.0.0.0\r\n",n.codecs.forEach((e=>{s+=t.writeRtpMap(e),s+=t.writeFmtp(e),s+=t.writeRtcpFb(e)}));let i=0;return n.codecs.forEach((e=>{e.maxptime>i&&(i=e.maxptime)})),i>0&&(s+="a=maxptime:"+i+"\r\n"),n.headerExtensions&&n.headerExtensions.forEach((e=>{s+=t.writeExtmap(e)})),s},t.parseRtpEncodingParameters=function(e){const n=[],s=t.parseRtpParameters(e),i=-1!==s.fecMechanisms.indexOf("RED"),r=-1!==s.fecMechanisms.indexOf("ULPFEC"),a=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"cname"===e.attribute)),o=a.length>0&&a[0].ssrc;let c;const l=t.matchPrefix(e,"a=ssrc-group:FID").map((e=>e.substring(17).split(" ").map((e=>parseInt(e,10)))));l.length>0&&l[0].length>1&&l[0][0]===o&&(c=l[0][1]),s.codecs.forEach((e=>{if("RTX"===e.name.toUpperCase()&&e.parameters.apt){let t={ssrc:o,codecPayloadType:parseInt(e.parameters.apt,10)};o&&c&&(t.rtx={ssrc:c}),n.push(t),i&&(t=JSON.parse(JSON.stringify(t)),t.fec={ssrc:o,mechanism:r?"red+ulpfec":"red"},n.push(t))}})),0===n.length&&o&&n.push({ssrc:o});let d=t.matchPrefix(e,"b=");return d.length&&(d=0===d[0].indexOf("b=TIAS:")?parseInt(d[0].substring(7),10):0===d[0].indexOf("b=AS:")?1e3*parseInt(d[0].substring(5),10)*.95-16e3:void 0,n.forEach((e=>{e.maxBitrate=d}))),n},t.parseRtcpParameters=function(e){const n={},s=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"cname"===e.attribute))[0];s&&(n.cname=s.value,n.ssrc=s.ssrc);const i=t.matchPrefix(e,"a=rtcp-rsize");n.reducedSize=i.length>0,n.compound=0===i.length;const r=t.matchPrefix(e,"a=rtcp-mux");return n.mux=r.length>0,n},t.writeRtcpParameters=function(e){let t="";return e.reducedSize&&(t+="a=rtcp-rsize\r\n"),e.mux&&(t+="a=rtcp-mux\r\n"),void 0!==e.ssrc&&e.cname&&(t+="a=ssrc:"+e.ssrc+" cname:"+e.cname+"\r\n"),t},t.parseMsid=function(e){let n;const s=t.matchPrefix(e,"a=msid:");if(1===s.length)return n=s[0].substring(7).split(" "),{stream:n[0],track:n[1]};const i=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"msid"===e.attribute));return i.length>0?(n=i[0].value.split(" "),{stream:n[0],track:n[1]}):void 0},t.parseSctpDescription=function(e){const n=t.parseMLine(e),s=t.matchPrefix(e,"a=max-message-size:");let i;s.length>0&&(i=parseInt(s[0].substring(19),10)),isNaN(i)&&(i=65536);const r=t.matchPrefix(e,"a=sctp-port:");if(r.length>0)return{port:parseInt(r[0].substring(12),10),protocol:n.fmt,maxMessageSize:i};const a=t.matchPrefix(e,"a=sctpmap:");if(a.length>0){const e=a[0].substring(10).split(" ");return{port:parseInt(e[0],10),protocol:e[1],maxMessageSize:i}}},t.writeSctpDescription=function(e,t){let n=[];return n="DTLS/SCTP"!==e.protocol?["m="+e.kind+" 9 "+e.protocol+" "+t.protocol+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctp-port:"+t.port+"\r\n"]:["m="+e.kind+" 9 "+e.protocol+" "+t.port+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctpmap:"+t.port+" "+t.protocol+" 65535\r\n"],void 0!==t.maxMessageSize&&n.push("a=max-message-size:"+t.maxMessageSize+"\r\n"),n.join("")},t.generateSessionId=function(){return Math.random().toString().substr(2,22)},t.writeSessionBoilerplate=function(e,n,s){let i;const r=void 0!==n?n:2;return i=e||t.generateSessionId(),"v=0\r\no="+(s||"thisisadapterortc")+" "+i+" "+r+" IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},t.getDirection=function(e,n){const s=t.splitLines(e);for(let e=0;e {\n this.id = resp.data.id;\n return resp;\n });\n};\n\n/** Detaches this handle. **/\nJanusPluginHandle.prototype.detach = function() {\n return this.send(\"detach\");\n};\n\n/** Registers a callback to be fired upon the reception of any incoming Janus signals for this plugin handle with the\n * `janus` attribute equal to `ev`.\n **/\nJanusPluginHandle.prototype.on = function(ev, callback) {\n return this.session.on(ev, signal => {\n if (signal.sender == this.id) {\n callback(signal);\n }\n });\n};\n\n/**\n * Sends a signal associated with this handle. Signals should be JSON-serializable objects. Returns a promise that will\n * be resolved or rejected when a response to this signal is received, or when no response is received within the\n * session timeout.\n **/\nJanusPluginHandle.prototype.send = function(type, signal) {\n return this.session.send(type, Object.assign({ handle_id: this.id }, signal));\n};\n\n/** Sends a plugin-specific message associated with this handle. **/\nJanusPluginHandle.prototype.sendMessage = function(body) {\n return this.send(\"message\", { body: body });\n};\n\n/** Sends a JSEP offer or answer associated with this handle. **/\nJanusPluginHandle.prototype.sendJsep = function(jsep) {\n return this.send(\"message\", { body: {}, jsep: jsep });\n};\n\n/** Sends an ICE trickle candidate associated with this handle. **/\nJanusPluginHandle.prototype.sendTrickle = function(candidate) {\n return this.send(\"trickle\", { candidate: candidate });\n};\n\n/**\n * Represents a Janus session -- a Janus context from within which you can open multiple handles and connections. Once\n * created, this session will be given a unique ID which should be used to associate it with future signalling messages.\n *\n * See https://janus.conf.meetecho.com/docs/rest.html#sessions.\n **/\nfunction JanusSession(output, options) {\n this.output = output;\n this.id = undefined;\n this.nextTxId = 0;\n this.txns = {};\n this.eventHandlers = {};\n this.options = Object.assign({\n verbose: false,\n timeoutMs: 10000,\n keepaliveMs: 30000\n }, options);\n}\n\n/** Creates this session on the Janus server and sets its ID. **/\nJanusSession.prototype.create = function() {\n return this.send(\"create\").then(resp => {\n this.id = resp.data.id;\n return resp;\n });\n};\n\n/**\n * Destroys this session. Note that upon destruction, Janus will also close the signalling transport (if applicable) and\n * any open WebRTC connections.\n **/\nJanusSession.prototype.destroy = function() {\n return this.send(\"destroy\").then((resp) => {\n this.dispose();\n return resp;\n });\n};\n\n/**\n * Disposes of this session in a way such that no further incoming signalling messages will be processed.\n * Outstanding transactions will be rejected.\n **/\nJanusSession.prototype.dispose = function() {\n this._killKeepalive();\n this.eventHandlers = {};\n for (var txId in this.txns) {\n if (this.txns.hasOwnProperty(txId)) {\n var txn = this.txns[txId];\n clearTimeout(txn.timeout);\n txn.reject(new Error(\"Janus session was disposed.\"));\n delete this.txns[txId];\n }\n }\n};\n\n/**\n * Whether this signal represents an error, and the associated promise (if any) should be rejected.\n * Users should override this to handle any custom plugin-specific error conventions.\n **/\nJanusSession.prototype.isError = function(signal) {\n return signal.janus === \"error\";\n};\n\n/** Registers a callback to be fired upon the reception of any incoming Janus signals for this session with the\n * `janus` attribute equal to `ev`.\n **/\nJanusSession.prototype.on = function(ev, callback) {\n var handlers = this.eventHandlers[ev];\n if (handlers == null) {\n handlers = this.eventHandlers[ev] = [];\n }\n handlers.push(callback);\n};\n\n/**\n * Callback for receiving JSON signalling messages pertinent to this session. If the signals are responses to previously\n * sent signals, the promises for the outgoing signals will be resolved or rejected appropriately with this signal as an\n * argument.\n *\n * External callers should call this function every time a new signal arrives on the transport; for example, in a\n * WebSocket's `message` event, or when a new datum shows up in an HTTP long-polling response.\n **/\nJanusSession.prototype.receive = function(signal) {\n if (this.options.verbose) {\n this._logIncoming(signal);\n }\n if (signal.session_id != this.id) {\n console.warn(\"Incorrect session ID received in Janus signalling message: was \" + signal.session_id + \", expected \" + this.id + \".\");\n }\n\n var responseType = signal.janus;\n var handlers = this.eventHandlers[responseType];\n if (handlers != null) {\n for (var i = 0; i < handlers.length; i++) {\n handlers[i](signal);\n }\n }\n\n if (signal.transaction != null) {\n var txn = this.txns[signal.transaction];\n if (txn == null) {\n // this is a response to a transaction that wasn't caused via JanusSession.send, or a plugin replied twice to a\n // single request, or the session was disposed, or something else that isn't under our purview; that's fine\n return;\n }\n\n if (responseType === \"ack\" && txn.type == \"message\") {\n // this is an ack of an asynchronously-processed plugin request, we should wait to resolve the promise until the\n // actual response comes in\n return;\n }\n\n clearTimeout(txn.timeout);\n\n delete this.txns[signal.transaction];\n (this.isError(signal) ? txn.reject : txn.resolve)(signal);\n }\n};\n\n/**\n * Sends a signal associated with this session, beginning a new transaction. Returns a promise that will be resolved or\n * rejected when a response is received in the same transaction, or when no response is received within the session\n * timeout.\n **/\nJanusSession.prototype.send = function(type, signal) {\n signal = Object.assign({ transaction: (this.nextTxId++).toString() }, signal);\n return new Promise((resolve, reject) => {\n var timeout = null;\n if (this.options.timeoutMs) {\n timeout = setTimeout(() => {\n delete this.txns[signal.transaction];\n reject(new Error(\"Signalling transaction with txid \" + signal.transaction + \" timed out.\"));\n }, this.options.timeoutMs);\n }\n this.txns[signal.transaction] = { resolve: resolve, reject: reject, timeout: timeout, type: type };\n this._transmit(type, signal);\n });\n};\n\nJanusSession.prototype._transmit = function(type, signal) {\n signal = Object.assign({ janus: type }, signal);\n\n if (this.id != null) { // this.id is undefined in the special case when we're sending the session create message\n signal = Object.assign({ session_id: this.id }, signal);\n }\n\n if (this.options.verbose) {\n this._logOutgoing(signal);\n }\n\n this.output(JSON.stringify(signal));\n this._resetKeepalive();\n};\n\nJanusSession.prototype._logOutgoing = function(signal) {\n var kind = signal.janus;\n if (kind === \"message\" && signal.jsep) {\n kind = signal.jsep.type;\n }\n var message = \"> Outgoing Janus \" + (kind || \"signal\") + \" (#\" + signal.transaction + \"): \";\n console.debug(\"%c\" + message, \"color: #040\", signal);\n};\n\nJanusSession.prototype._logIncoming = function(signal) {\n var kind = signal.janus;\n var message = signal.transaction ?\n \"< Incoming Janus \" + (kind || \"signal\") + \" (#\" + signal.transaction + \"): \" :\n \"< Incoming Janus \" + (kind || \"signal\") + \": \";\n console.debug(\"%c\" + message, \"color: #004\", signal);\n};\n\nJanusSession.prototype._sendKeepalive = function() {\n return this.send(\"keepalive\");\n};\n\nJanusSession.prototype._killKeepalive = function() {\n clearTimeout(this.keepaliveTimeout);\n};\n\nJanusSession.prototype._resetKeepalive = function() {\n this._killKeepalive();\n if (this.options.keepaliveMs) {\n this.keepaliveTimeout = setTimeout(() => {\n this._sendKeepalive().catch(e => console.error(\"Error received from keepalive: \", e));\n }, this.options.keepaliveMs);\n }\n};\n\nmodule.exports = {\n JanusPluginHandle,\n JanusSession\n};\n","/* global NAF */\nvar mj = require(\"@networked-aframe/minijanus\");\nmj.JanusSession.prototype.sendOriginal = mj.JanusSession.prototype.send;\nmj.JanusSession.prototype.send = function(type, signal) {\n return this.sendOriginal(type, signal).catch((e) => {\n if (e.message && e.message.indexOf(\"timed out\") > -1) {\n console.error(\"web socket timed out\");\n NAF.connection.adapter.reconnect();\n } else {\n throw(e);\n }\n });\n}\n\nvar sdpUtils = require(\"sdp\");\nvar debug = require(\"debug\")(\"naf-janus-adapter:debug\");\nvar warn = require(\"debug\")(\"naf-janus-adapter:warn\");\nvar error = require(\"debug\")(\"naf-janus-adapter:error\");\nvar isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\nconst SUBSCRIBE_TIMEOUT_MS = 15000;\n\nconst AVAILABLE_OCCUPANTS_THRESHOLD = 5;\nconst MAX_SUBSCRIBE_DELAY = 5000;\n\nfunction randomDelay(min, max) {\n return new Promise(resolve => {\n const delay = Math.random() * (max - min) + min;\n setTimeout(resolve, delay);\n });\n}\n\nfunction debounce(fn) {\n var curr = Promise.resolve();\n return function() {\n var args = Array.prototype.slice.call(arguments);\n curr = curr.then(_ => fn.apply(this, args));\n };\n}\n\nfunction randomUint() {\n return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);\n}\n\nfunction untilDataChannelOpen(dataChannel) {\n return new Promise((resolve, reject) => {\n if (dataChannel.readyState === \"open\") {\n resolve();\n } else {\n let resolver, rejector;\n\n const clear = () => {\n dataChannel.removeEventListener(\"open\", resolver);\n dataChannel.removeEventListener(\"error\", rejector);\n };\n\n resolver = () => {\n clear();\n resolve();\n };\n rejector = () => {\n clear();\n reject();\n };\n\n dataChannel.addEventListener(\"open\", resolver);\n dataChannel.addEventListener(\"error\", rejector);\n }\n });\n}\n\nconst isH264VideoSupported = (() => {\n const video = document.createElement(\"video\");\n return video.canPlayType('video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"') !== \"\";\n})();\n\nconst OPUS_PARAMETERS = {\n // indicates that we want to enable DTX to elide silence packets\n usedtx: 1,\n // indicates that we prefer to receive mono audio (important for voip profile)\n stereo: 0,\n // indicates that we prefer to send mono audio (important for voip profile)\n \"sprop-stereo\": 0\n};\n\nconst DEFAULT_PEER_CONNECTION_CONFIG = {\n iceServers: [{ urls: \"stun:stun1.l.google.com:19302\" }, { urls: \"stun:stun2.l.google.com:19302\" }]\n};\n\nconst WS_NORMAL_CLOSURE = 1000;\n\nclass JanusAdapter {\n constructor() {\n this.room = null;\n // We expect the consumer to set a client id before connecting.\n this.clientId = null;\n this.joinToken = null;\n\n this.serverUrl = null;\n this.webRtcOptions = {};\n this.peerConnectionConfig = null;\n this.ws = null;\n this.session = null;\n this.reliableTransport = \"datachannel\";\n this.unreliableTransport = \"datachannel\";\n\n // In the event the server restarts and all clients lose connection, reconnect with\n // some random jitter added to prevent simultaneous reconnection requests.\n this.initialReconnectionDelay = 1000 * Math.random();\n this.reconnectionDelay = this.initialReconnectionDelay;\n this.reconnectionTimeout = null;\n this.maxReconnectionAttempts = 10;\n this.reconnectionAttempts = 0;\n\n this.publisher = null;\n this.occupantIds = [];\n this.occupants = {};\n this.mediaStreams = {};\n this.localMediaStream = null;\n this.pendingMediaRequests = new Map();\n\n this.pendingOccupants = new Set();\n this.availableOccupants = [];\n this.requestedOccupants = null;\n\n this.blockedClients = new Map();\n this.frozenUpdates = new Map();\n\n this.timeOffsets = [];\n this.serverTimeRequests = 0;\n this.avgTimeOffset = 0;\n\n this.onWebsocketOpen = this.onWebsocketOpen.bind(this);\n this.onWebsocketClose = this.onWebsocketClose.bind(this);\n this.onWebsocketMessage = this.onWebsocketMessage.bind(this);\n this.onDataChannelMessage = this.onDataChannelMessage.bind(this);\n this.onData = this.onData.bind(this);\n }\n\n setServerUrl(url) {\n this.serverUrl = url;\n }\n\n setApp(app) {}\n\n setRoom(roomName) {\n this.room = roomName;\n }\n\n setJoinToken(joinToken) {\n this.joinToken = joinToken;\n }\n\n setClientId(clientId) {\n this.clientId = clientId;\n }\n\n setWebRtcOptions(options) {\n this.webRtcOptions = options;\n }\n\n setPeerConnectionConfig(peerConnectionConfig) {\n this.peerConnectionConfig = peerConnectionConfig;\n }\n\n setServerConnectListeners(successListener, failureListener) {\n this.connectSuccess = successListener;\n this.connectFailure = failureListener;\n }\n\n setRoomOccupantListener(occupantListener) {\n this.onOccupantsChanged = occupantListener;\n }\n\n setDataChannelListeners(openListener, closedListener, messageListener) {\n this.onOccupantConnected = openListener;\n this.onOccupantDisconnected = closedListener;\n this.onOccupantMessage = messageListener;\n }\n\n setReconnectionListeners(reconnectingListener, reconnectedListener, reconnectionErrorListener) {\n // onReconnecting is called with the number of milliseconds until the next reconnection attempt\n this.onReconnecting = reconnectingListener;\n // onReconnected is called when the connection has been reestablished\n this.onReconnected = reconnectedListener;\n // onReconnectionError is called with an error when maxReconnectionAttempts has been reached\n this.onReconnectionError = reconnectionErrorListener;\n }\n\n setEventLoops(loops) {\n this.loops = loops;\n }\n\n connect() {\n debug(`connecting to ${this.serverUrl}`);\n\n const websocketConnection = new Promise((resolve, reject) => {\n this.ws = new WebSocket(this.serverUrl, \"janus-protocol\");\n\n this.session = new mj.JanusSession(this.ws.send.bind(this.ws), { timeoutMs: 40000 });\n\n this.ws.addEventListener(\"close\", this.onWebsocketClose);\n this.ws.addEventListener(\"message\", this.onWebsocketMessage);\n\n this.wsOnOpen = () => {\n this.ws.removeEventListener(\"open\", this.wsOnOpen);\n this.onWebsocketOpen()\n .then(resolve)\n .catch(reject);\n };\n\n this.ws.addEventListener(\"open\", this.wsOnOpen);\n });\n\n return Promise.all([websocketConnection, this.updateTimeOffset()]);\n }\n\n disconnect() {\n debug(`disconnecting`);\n\n clearTimeout(this.reconnectionTimeout);\n\n this.removeAllOccupants();\n\n if (this.publisher) {\n // Close the publisher peer connection. Which also detaches the plugin handle.\n this.publisher.conn.close();\n this.publisher = null;\n }\n\n if (this.session) {\n this.session.dispose();\n this.session = null;\n }\n\n if (this.ws) {\n this.ws.removeEventListener(\"open\", this.wsOnOpen);\n this.ws.removeEventListener(\"close\", this.onWebsocketClose);\n this.ws.removeEventListener(\"message\", this.onWebsocketMessage);\n this.ws.close();\n this.ws = null;\n }\n\n // Now that all RTCPeerConnection closed, be sure to not call\n // reconnect() again via performDelayedReconnect if previous\n // RTCPeerConnection was in the failed state.\n if (this.delayedReconnectTimeout) {\n clearTimeout(this.delayedReconnectTimeout);\n this.delayedReconnectTimeout = null;\n }\n }\n\n isDisconnected() {\n return this.ws === null;\n }\n\n async onWebsocketOpen() {\n // Create the Janus Session\n await this.session.create();\n\n // Attach the SFU Plugin and create a RTCPeerConnection for the publisher.\n // The publisher sends audio and opens two bidirectional data channels.\n // One reliable datachannel and one unreliable.\n this.publisher = await this.createPublisher();\n\n // Call the naf connectSuccess callback before we start receiving WebRTC messages.\n this.connectSuccess(this.clientId);\n\n for (let i = 0; i < this.publisher.initialOccupants.length; i++) {\n const occupantId = this.publisher.initialOccupants[i];\n if (occupantId === this.clientId) continue; // Happens during non-graceful reconnects due to zombie sessions\n this.addAvailableOccupant(occupantId);\n }\n\n this.syncOccupants();\n }\n\n onWebsocketClose(event) {\n // The connection was closed successfully. Don't try to reconnect.\n if (event.code === WS_NORMAL_CLOSURE) {\n return;\n }\n\n console.warn(\"Janus websocket closed unexpectedly.\");\n if (this.onReconnecting) {\n this.onReconnecting(this.reconnectionDelay);\n }\n\n this.reconnectionTimeout = setTimeout(() => this.reconnect(), this.reconnectionDelay);\n }\n\n reconnect() {\n // Dispose of all networked entities and other resources tied to the session.\n this.disconnect();\n\n this.connect()\n .then(() => {\n this.reconnectionDelay = this.initialReconnectionDelay;\n this.reconnectionAttempts = 0;\n\n if (this.onReconnected) {\n this.onReconnected();\n }\n })\n .catch(error => {\n this.reconnectionDelay += 1000;\n this.reconnectionAttempts++;\n\n if (this.reconnectionAttempts > this.maxReconnectionAttempts && this.onReconnectionError) {\n return this.onReconnectionError(\n new Error(\"Connection could not be reestablished, exceeded maximum number of reconnection attempts.\")\n );\n }\n\n console.warn(\"Error during reconnect, retrying.\");\n console.warn(error);\n\n if (this.onReconnecting) {\n this.onReconnecting(this.reconnectionDelay);\n }\n\n this.reconnectionTimeout = setTimeout(() => this.reconnect(), this.reconnectionDelay);\n });\n }\n\n performDelayedReconnect() {\n if (this.delayedReconnectTimeout) {\n clearTimeout(this.delayedReconnectTimeout);\n }\n\n this.delayedReconnectTimeout = setTimeout(() => {\n this.delayedReconnectTimeout = null;\n this.reconnect();\n }, 10000);\n }\n\n onWebsocketMessage(event) {\n this.session.receive(JSON.parse(event.data));\n }\n\n addAvailableOccupant(occupantId) {\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n this.availableOccupants.push(occupantId);\n }\n }\n\n removeAvailableOccupant(occupantId) {\n const idx = this.availableOccupants.indexOf(occupantId);\n if (idx !== -1) {\n this.availableOccupants.splice(idx, 1);\n }\n }\n\n syncOccupants(requestedOccupants) {\n if (requestedOccupants) {\n this.requestedOccupants = requestedOccupants;\n }\n\n if (!this.requestedOccupants) {\n return;\n }\n\n // Add any requested, available, and non-pending occupants.\n for (let i = 0; i < this.requestedOccupants.length; i++) {\n const occupantId = this.requestedOccupants[i];\n if (!this.occupants[occupantId] && this.availableOccupants.indexOf(occupantId) !== -1 && !this.pendingOccupants.has(occupantId)) {\n this.addOccupant(occupantId);\n }\n }\n\n // Remove any unrequested and currently added occupants.\n for (let j = 0; j < this.availableOccupants.length; j++) {\n const occupantId = this.availableOccupants[j];\n if (this.occupants[occupantId] && this.requestedOccupants.indexOf(occupantId) === -1) {\n this.removeOccupant(occupantId);\n }\n }\n\n // Call the Networked AFrame callbacks for the updated occupants list.\n this.onOccupantsChanged(this.occupants);\n }\n\n async addOccupant(occupantId) {\n this.pendingOccupants.add(occupantId);\n \n const availableOccupantsCount = this.availableOccupants.length;\n if (availableOccupantsCount > AVAILABLE_OCCUPANTS_THRESHOLD) {\n await randomDelay(0, MAX_SUBSCRIBE_DELAY);\n }\n \n const subscriber = await this.createSubscriber(occupantId);\n if (subscriber) {\n if(!this.pendingOccupants.has(occupantId)) {\n subscriber.conn.close();\n } else {\n this.pendingOccupants.delete(occupantId);\n this.occupantIds.push(occupantId);\n this.occupants[occupantId] = subscriber;\n\n this.setMediaStream(occupantId, subscriber.mediaStream);\n\n // Call the Networked AFrame callbacks for the new occupant.\n this.onOccupantConnected(occupantId);\n }\n }\n }\n\n removeAllOccupants() {\n this.pendingOccupants.clear();\n for (let i = this.occupantIds.length - 1; i >= 0; i--) {\n this.removeOccupant(this.occupantIds[i]);\n }\n }\n\n removeOccupant(occupantId) {\n this.pendingOccupants.delete(occupantId);\n \n if (this.occupants[occupantId]) {\n // Close the subscriber peer connection. Which also detaches the plugin handle.\n this.occupants[occupantId].conn.close();\n delete this.occupants[occupantId];\n \n this.occupantIds.splice(this.occupantIds.indexOf(occupantId), 1);\n }\n\n if (this.mediaStreams[occupantId]) {\n delete this.mediaStreams[occupantId];\n }\n\n if (this.pendingMediaRequests.has(occupantId)) {\n const msg = \"The user disconnected before the media stream was resolved.\";\n this.pendingMediaRequests.get(occupantId).audio.reject(msg);\n this.pendingMediaRequests.get(occupantId).video.reject(msg);\n this.pendingMediaRequests.delete(occupantId);\n }\n\n // Call the Networked AFrame callbacks for the removed occupant.\n this.onOccupantDisconnected(occupantId);\n }\n\n associate(conn, handle) {\n conn.addEventListener(\"icecandidate\", ev => {\n handle.sendTrickle(ev.candidate || null).catch(e => error(\"Error trickling ICE: %o\", e));\n });\n conn.addEventListener(\"iceconnectionstatechange\", ev => {\n if (conn.iceConnectionState === \"connected\") {\n console.log(\"ICE state changed to connected\");\n }\n if (conn.iceConnectionState === \"disconnected\") {\n console.warn(\"ICE state changed to disconnected\");\n }\n if (conn.iceConnectionState === \"failed\") {\n console.warn(\"ICE failure detected. Reconnecting in 10s.\");\n this.performDelayedReconnect();\n }\n })\n\n // we have to debounce these because janus gets angry if you send it a new SDP before\n // it's finished processing an existing SDP. in actuality, it seems like this is maybe\n // too liberal and we need to wait some amount of time after an offer before sending another,\n // but we don't currently know any good way of detecting exactly how long :(\n conn.addEventListener(\n \"negotiationneeded\",\n debounce(ev => {\n debug(\"Sending new offer for handle: %o\", handle);\n var offer = conn.createOffer().then(this.configurePublisherSdp).then(this.fixSafariIceUFrag);\n var local = offer.then(o => conn.setLocalDescription(o));\n var remote = offer;\n\n remote = remote\n .then(this.fixSafariIceUFrag)\n .then(j => handle.sendJsep(j))\n .then(r => conn.setRemoteDescription(r.jsep));\n return Promise.all([local, remote]).catch(e => error(\"Error negotiating offer: %o\", e));\n })\n );\n handle.on(\n \"event\",\n debounce(ev => {\n var jsep = ev.jsep;\n if (jsep && jsep.type == \"offer\") {\n debug(\"Accepting new offer for handle: %o\", handle);\n var answer = conn\n .setRemoteDescription(this.configureSubscriberSdp(jsep))\n .then(_ => conn.createAnswer())\n .then(this.fixSafariIceUFrag);\n var local = answer.then(a => conn.setLocalDescription(a));\n var remote = answer.then(j => handle.sendJsep(j));\n return Promise.all([local, remote]).catch(e => error(\"Error negotiating answer: %o\", e));\n } else {\n // some other kind of event, nothing to do\n return null;\n }\n })\n );\n }\n\n async createPublisher() {\n var handle = new mj.JanusPluginHandle(this.session);\n var conn = new RTCPeerConnection(this.peerConnectionConfig || DEFAULT_PEER_CONNECTION_CONFIG);\n\n debug(\"pub waiting for sfu\");\n await handle.attach(\"janus.plugin.sfu\", this.loops && this.clientId ? parseInt(this.clientId) % this.loops : undefined);\n\n this.associate(conn, handle);\n\n debug(\"pub waiting for data channels & webrtcup\");\n var webrtcup = new Promise(resolve => handle.on(\"webrtcup\", resolve));\n\n // Unreliable datachannel: sending and receiving component updates.\n // Reliable datachannel: sending and recieving entity instantiations.\n var reliableChannel = conn.createDataChannel(\"reliable\", { ordered: true });\n var unreliableChannel = conn.createDataChannel(\"unreliable\", {\n ordered: false,\n maxRetransmits: 0\n });\n\n reliableChannel.addEventListener(\"message\", e => this.onDataChannelMessage(e, \"janus-reliable\"));\n unreliableChannel.addEventListener(\"message\", e => this.onDataChannelMessage(e, \"janus-unreliable\"));\n\n await webrtcup;\n await untilDataChannelOpen(reliableChannel);\n await untilDataChannelOpen(unreliableChannel);\n\n // doing this here is sort of a hack around chrome renegotiation weirdness --\n // if we do it prior to webrtcup, chrome on gear VR will sometimes put a\n // renegotiation offer in flight while the first offer was still being\n // processed by janus. we should find some more principled way to figure out\n // when janus is done in the future.\n if (this.localMediaStream) {\n this.localMediaStream.getTracks().forEach(track => {\n conn.addTrack(track, this.localMediaStream);\n });\n }\n\n // Handle all of the join and leave events.\n handle.on(\"event\", ev => {\n var data = ev.plugindata.data;\n if (data.event == \"join\" && data.room_id == this.room) {\n if (this.delayedReconnectTimeout) {\n // Don't create a new RTCPeerConnection, all RTCPeerConnection will be closed in less than 10s.\n return;\n }\n this.addAvailableOccupant(data.user_id);\n this.syncOccupants();\n } else if (data.event == \"leave\" && data.room_id == this.room) {\n this.removeAvailableOccupant(data.user_id);\n this.removeOccupant(data.user_id);\n } else if (data.event == \"blocked\") {\n document.body.dispatchEvent(new CustomEvent(\"blocked\", { detail: { clientId: data.by } }));\n } else if (data.event == \"unblocked\") {\n document.body.dispatchEvent(new CustomEvent(\"unblocked\", { detail: { clientId: data.by } }));\n } else if (data.event === \"data\") {\n this.onData(JSON.parse(data.body), \"janus-event\");\n }\n });\n\n debug(\"pub waiting for join\");\n\n // Send join message to janus. Listen for join/leave messages. Automatically subscribe to all users' WebRTC data.\n var message = await this.sendJoin(handle, {\n notifications: true,\n data: true\n });\n\n if (!message.plugindata.data.success) {\n const err = message.plugindata.data.error;\n console.error(err);\n // We may get here because of an expired JWT.\n // Close the connection ourself otherwise janus will close it after\n // session_timeout because we didn't send any keepalive and this will\n // trigger a delayed reconnect because of the iceconnectionstatechange\n // listener for failure state.\n // Even if the app code calls disconnect in case of error, disconnect\n // won't close the peer connection because this.publisher is not set.\n conn.close();\n throw err;\n }\n\n var initialOccupants = message.plugindata.data.response.users[this.room] || [];\n\n if (initialOccupants.includes(this.clientId)) {\n console.warn(\"Janus still has previous session for this client. Reconnecting in 10s.\");\n this.performDelayedReconnect();\n }\n\n debug(\"publisher ready\");\n return {\n handle,\n initialOccupants,\n reliableChannel,\n unreliableChannel,\n conn\n };\n }\n\n configurePublisherSdp(jsep) {\n jsep.sdp = jsep.sdp.replace(/a=fmtp:(109|111).*\\r\\n/g, (line, pt) => {\n const parameters = Object.assign(sdpUtils.parseFmtp(line), OPUS_PARAMETERS);\n return sdpUtils.writeFmtp({ payloadType: pt, parameters: parameters });\n });\n return jsep;\n }\n\n configureSubscriberSdp(jsep) {\n // todo: consider cleaning up these hacks to use sdputils\n if (!isH264VideoSupported) {\n if (navigator.userAgent.indexOf(\"HeadlessChrome\") !== -1) {\n // HeadlessChrome (e.g. puppeteer) doesn't support webrtc video streams, so we remove those lines from the SDP.\n jsep.sdp = jsep.sdp.replace(/m=video[^]*m=/, \"m=\");\n }\n }\n\n // TODO: Hack to get video working on Chrome for Android. https://groups.google.com/forum/#!topic/mozilla.dev.media/Ye29vuMTpo8\n if (navigator.userAgent.indexOf(\"Android\") === -1) {\n jsep.sdp = jsep.sdp.replace(\n \"a=rtcp-fb:107 goog-remb\\r\\n\",\n \"a=rtcp-fb:107 goog-remb\\r\\na=rtcp-fb:107 transport-cc\\r\\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\\r\\n\"\n );\n } else {\n jsep.sdp = jsep.sdp.replace(\n \"a=rtcp-fb:107 goog-remb\\r\\n\",\n \"a=rtcp-fb:107 goog-remb\\r\\na=rtcp-fb:107 transport-cc\\r\\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\\r\\n\"\n );\n }\n return jsep;\n }\n\n async fixSafariIceUFrag(jsep) {\n // Safari produces a \\n instead of an \\r\\n for the ice-ufrag. See https://github.com/meetecho/janus-gateway/issues/1818\n jsep.sdp = jsep.sdp.replace(/[^\\r]\\na=ice-ufrag/g, \"\\r\\na=ice-ufrag\");\n return jsep\n }\n\n async createSubscriber(occupantId, maxRetries = 5) {\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n console.warn(occupantId + \": cancelled occupant connection, occupant left before subscription negotation.\");\n return null;\n }\n\n var handle = new mj.JanusPluginHandle(this.session);\n var conn = new RTCPeerConnection(this.peerConnectionConfig || DEFAULT_PEER_CONNECTION_CONFIG);\n\n debug(occupantId + \": sub waiting for sfu\");\n await handle.attach(\"janus.plugin.sfu\", this.loops ? parseInt(occupantId) % this.loops : undefined);\n\n this.associate(conn, handle);\n\n debug(occupantId + \": sub waiting for join\");\n\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n conn.close();\n console.warn(occupantId + \": cancelled occupant connection, occupant left after attach\");\n return null;\n }\n\n let webrtcFailed = false;\n\n const webrtcup = new Promise(resolve => {\n const leftInterval = setInterval(() => {\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n clearInterval(leftInterval);\n resolve();\n }\n }, 1000);\n\n const timeout = setTimeout(() => {\n clearInterval(leftInterval);\n webrtcFailed = true;\n resolve();\n }, SUBSCRIBE_TIMEOUT_MS);\n\n handle.on(\"webrtcup\", () => {\n clearTimeout(timeout);\n clearInterval(leftInterval);\n resolve();\n });\n });\n\n // Send join message to janus. Don't listen for join/leave messages. Subscribe to the occupant's media.\n // Janus should send us an offer for this occupant's media in response to this.\n await this.sendJoin(handle, { media: occupantId });\n\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n conn.close();\n console.warn(occupantId + \": cancelled occupant connection, occupant left after join\");\n return null;\n }\n\n debug(occupantId + \": sub waiting for webrtcup\");\n await webrtcup;\n\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n conn.close();\n console.warn(occupantId + \": cancel occupant connection, occupant left during or after webrtcup\");\n return null;\n }\n\n if (webrtcFailed) {\n conn.close();\n if (maxRetries > 0) {\n console.warn(occupantId + \": webrtc up timed out, retrying\");\n return this.createSubscriber(occupantId, maxRetries - 1);\n } else {\n console.warn(occupantId + \": webrtc up timed out\");\n return null;\n }\n }\n\n if (isSafari && !this._iOSHackDelayedInitialPeer) {\n // HACK: the first peer on Safari during page load can fail to work if we don't\n // wait some time before continuing here. See: https://github.com/mozilla/hubs/pull/1692\n await (new Promise((resolve) => setTimeout(resolve, 3000)));\n this._iOSHackDelayedInitialPeer = true;\n }\n\n var mediaStream = new MediaStream();\n var receivers = conn.getReceivers();\n receivers.forEach(receiver => {\n if (receiver.track) {\n mediaStream.addTrack(receiver.track);\n }\n });\n if (mediaStream.getTracks().length === 0) {\n mediaStream = null;\n }\n\n debug(occupantId + \": subscriber ready\");\n return {\n handle,\n mediaStream,\n conn\n };\n }\n\n sendJoin(handle, subscribe) {\n return handle.sendMessage({\n kind: \"join\",\n room_id: this.room,\n user_id: this.clientId,\n subscribe,\n token: this.joinToken\n });\n }\n\n toggleFreeze() {\n if (this.frozen) {\n this.unfreeze();\n } else {\n this.freeze();\n }\n }\n\n freeze() {\n this.frozen = true;\n }\n\n unfreeze() {\n this.frozen = false;\n this.flushPendingUpdates();\n }\n\n dataForUpdateMultiMessage(networkId, message) {\n // \"d\" is an array of entity datas, where each item in the array represents a unique entity and contains\n // metadata for the entity, and an array of components that have been updated on the entity.\n // This method finds the data corresponding to the given networkId.\n for (let i = 0, l = message.data.d.length; i < l; i++) {\n const data = message.data.d[i];\n\n if (data.networkId === networkId) {\n return data;\n }\n }\n\n return null;\n }\n\n getPendingData(networkId, message) {\n if (!message) return null;\n\n let data = message.dataType === \"um\" ? this.dataForUpdateMultiMessage(networkId, message) : message.data;\n\n // Ignore messages relating to users who have disconnected since freezing, their entities\n // will have aleady been removed by NAF.\n // Note that delete messages have no \"owner\" so we have to check for that as well.\n if (data.owner && !this.occupants[data.owner]) return null;\n\n // Ignore messages from users that we may have blocked while frozen.\n if (data.owner && this.blockedClients.has(data.owner)) return null;\n\n return data\n }\n\n // Used externally\n getPendingDataForNetworkId(networkId) {\n return this.getPendingData(networkId, this.frozenUpdates.get(networkId));\n }\n\n flushPendingUpdates() {\n for (const [networkId, message] of this.frozenUpdates) {\n let data = this.getPendingData(networkId, message);\n if (!data) continue;\n\n // Override the data type on \"um\" messages types, since we extract entity updates from \"um\" messages into\n // individual frozenUpdates in storeSingleMessage.\n const dataType = message.dataType === \"um\" ? \"u\" : message.dataType;\n\n this.onOccupantMessage(null, dataType, data, message.source);\n }\n this.frozenUpdates.clear();\n }\n\n storeMessage(message) {\n if (message.dataType === \"um\") { // UpdateMulti\n for (let i = 0, l = message.data.d.length; i < l; i++) {\n this.storeSingleMessage(message, i);\n }\n } else {\n this.storeSingleMessage(message);\n }\n }\n\n storeSingleMessage(message, index) {\n const data = index !== undefined ? message.data.d[index] : message.data;\n const dataType = message.dataType;\n const source = message.source;\n\n const networkId = data.networkId;\n\n if (!this.frozenUpdates.has(networkId)) {\n this.frozenUpdates.set(networkId, message);\n } else {\n const storedMessage = this.frozenUpdates.get(networkId);\n const storedData = storedMessage.dataType === \"um\" ? this.dataForUpdateMultiMessage(networkId, storedMessage) : storedMessage.data;\n\n // Avoid updating components if the entity data received did not come from the current owner.\n const isOutdatedMessage = data.lastOwnerTime < storedData.lastOwnerTime;\n const isContemporaneousMessage = data.lastOwnerTime === storedData.lastOwnerTime;\n if (isOutdatedMessage || (isContemporaneousMessage && storedData.owner > data.owner)) {\n return;\n }\n\n if (dataType === \"r\") {\n const createdWhileFrozen = storedData && storedData.isFirstSync;\n if (createdWhileFrozen) {\n // If the entity was created and deleted while frozen, don't bother conveying anything to the consumer.\n this.frozenUpdates.delete(networkId);\n } else {\n // Delete messages override any other messages for this entity\n this.frozenUpdates.set(networkId, message);\n }\n } else {\n // merge in component updates\n if (storedData.components && data.components) {\n Object.assign(storedData.components, data.components);\n }\n }\n }\n }\n\n onDataChannelMessage(e, source) {\n this.onData(JSON.parse(e.data), source);\n }\n\n onData(message, source) {\n if (debug.enabled) {\n debug(`DC in: ${message}`);\n }\n\n if (!message.dataType) return;\n\n message.source = source;\n\n if (this.frozen) {\n this.storeMessage(message);\n } else {\n this.onOccupantMessage(null, message.dataType, message.data, message.source);\n }\n }\n\n shouldStartConnectionTo(client) {\n return true;\n }\n\n startStreamConnection(client) {}\n\n closeStreamConnection(client) {}\n\n getConnectStatus(clientId) {\n return this.occupants[clientId] ? NAF.adapters.IS_CONNECTED : NAF.adapters.NOT_CONNECTED;\n }\n\n async updateTimeOffset() {\n if (this.isDisconnected()) return;\n\n const clientSentTime = Date.now();\n\n const res = await fetch(document.location.href, {\n method: \"HEAD\",\n cache: \"no-cache\"\n });\n\n const precision = 1000;\n const serverReceivedTime = new Date(res.headers.get(\"Date\")).getTime() + precision / 2;\n const clientReceivedTime = Date.now();\n const serverTime = serverReceivedTime + (clientReceivedTime - clientSentTime) / 2;\n const timeOffset = serverTime - clientReceivedTime;\n\n this.serverTimeRequests++;\n\n if (this.serverTimeRequests <= 10) {\n this.timeOffsets.push(timeOffset);\n } else {\n this.timeOffsets[this.serverTimeRequests % 10] = timeOffset;\n }\n\n this.avgTimeOffset = this.timeOffsets.reduce((acc, offset) => (acc += offset), 0) / this.timeOffsets.length;\n\n if (this.serverTimeRequests > 10) {\n debug(`new server time offset: ${this.avgTimeOffset}ms`);\n setTimeout(() => this.updateTimeOffset(), 5 * 60 * 1000); // Sync clock every 5 minutes.\n } else {\n this.updateTimeOffset();\n }\n }\n\n getServerTime() {\n return Date.now() + this.avgTimeOffset;\n }\n\n getMediaStream(clientId, type = \"audio\") {\n if (this.mediaStreams[clientId]) {\n debug(`Already had ${type} for ${clientId}`);\n return Promise.resolve(this.mediaStreams[clientId][type]);\n } else {\n debug(`Waiting on ${type} for ${clientId}`);\n if (!this.pendingMediaRequests.has(clientId)) {\n this.pendingMediaRequests.set(clientId, {});\n\n const audioPromise = new Promise((resolve, reject) => {\n this.pendingMediaRequests.get(clientId).audio = { resolve, reject };\n });\n const videoPromise = new Promise((resolve, reject) => {\n this.pendingMediaRequests.get(clientId).video = { resolve, reject };\n });\n\n this.pendingMediaRequests.get(clientId).audio.promise = audioPromise;\n this.pendingMediaRequests.get(clientId).video.promise = videoPromise;\n\n audioPromise.catch(e => console.warn(`${clientId} getMediaStream Audio Error`, e));\n videoPromise.catch(e => console.warn(`${clientId} getMediaStream Video Error`, e));\n }\n return this.pendingMediaRequests.get(clientId)[type].promise;\n }\n }\n\n setMediaStream(clientId, stream) {\n // Safari doesn't like it when you use single a mixed media stream where one of the tracks is inactive, so we\n // split the tracks into two streams.\n const audioStream = new MediaStream();\n try {\n stream.getAudioTracks().forEach(track => audioStream.addTrack(track));\n\n } catch(e) {\n console.warn(`${clientId} setMediaStream Audio Error`, e);\n }\n const videoStream = new MediaStream();\n try {\n stream.getVideoTracks().forEach(track => videoStream.addTrack(track));\n\n } catch (e) {\n console.warn(`${clientId} setMediaStream Video Error`, e);\n }\n\n this.mediaStreams[clientId] = { audio: audioStream, video: videoStream };\n\n // Resolve the promise for the user's media stream if it exists.\n if (this.pendingMediaRequests.has(clientId)) {\n this.pendingMediaRequests.get(clientId).audio.resolve(audioStream);\n this.pendingMediaRequests.get(clientId).video.resolve(videoStream);\n }\n }\n\n getLocalMediaStream() {\n return this.localMediaStream;\n }\n\n async setLocalMediaStream(stream) {\n // our job here is to make sure the connection winds up with RTP senders sending the stuff in this stream,\n // and not the stuff that isn't in this stream. strategy is to replace existing tracks if we can, add tracks\n // that we can't replace, and disable tracks that don't exist anymore.\n\n // note that we don't ever remove a track from the stream -- since Janus doesn't support Unified Plan, we absolutely\n // can't wind up with a SDP that has >1 audio or >1 video tracks, even if one of them is inactive (what you get if\n // you remove a track from an existing stream.)\n if (this.publisher && this.publisher.conn) {\n const existingSenders = this.publisher.conn.getSenders();\n const newSenders = [];\n const tracks = stream.getTracks();\n\n for (let i = 0; i < tracks.length; i++) {\n const t = tracks[i];\n const sender = existingSenders.find(s => s.track != null && s.track.kind == t.kind);\n\n if (sender != null) {\n if (sender.replaceTrack) {\n await sender.replaceTrack(t);\n } else {\n // Fallback for browsers that don't support replaceTrack. At this time of this writing\n // most browsers support it, and testing this code path seems to not work properly\n // in Chrome anymore.\n stream.removeTrack(sender.track);\n stream.addTrack(t);\n }\n newSenders.push(sender);\n } else {\n newSenders.push(this.publisher.conn.addTrack(t, stream));\n }\n }\n existingSenders.forEach(s => {\n if (!newSenders.includes(s)) {\n s.track.enabled = false;\n }\n });\n }\n this.localMediaStream = stream;\n this.setMediaStream(this.clientId, stream);\n }\n\n enableMicrophone(enabled) {\n if (this.publisher && this.publisher.conn) {\n this.publisher.conn.getSenders().forEach(s => {\n if (s.track.kind == \"audio\") {\n s.track.enabled = enabled;\n }\n });\n }\n }\n\n sendData(clientId, dataType, data) {\n if (!this.publisher) {\n console.warn(\"sendData called without a publisher\");\n } else {\n switch (this.unreliableTransport) {\n case \"websocket\":\n if (this.ws.readyState === 1) { // OPEN\n this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }), whom: clientId });\n }\n break;\n case \"datachannel\":\n if (this.publisher.unreliableChannel.readyState === \"open\") {\n this.publisher.unreliableChannel.send(JSON.stringify({ clientId, dataType, data }));\n }\n break;\n default:\n this.unreliableTransport(clientId, dataType, data);\n break;\n }\n }\n }\n\n sendDataGuaranteed(clientId, dataType, data) {\n if (!this.publisher) {\n console.warn(\"sendDataGuaranteed called without a publisher\");\n } else {\n switch (this.reliableTransport) {\n case \"websocket\":\n if (this.ws.readyState === 1) { // OPEN\n this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }), whom: clientId });\n }\n break;\n case \"datachannel\":\n if (this.publisher.reliableChannel.readyState === \"open\") {\n this.publisher.reliableChannel.send(JSON.stringify({ clientId, dataType, data }));\n }\n break;\n default:\n this.reliableTransport(clientId, dataType, data);\n break;\n }\n }\n }\n\n broadcastData(dataType, data) {\n if (!this.publisher) {\n console.warn(\"broadcastData called without a publisher\");\n } else {\n switch (this.unreliableTransport) {\n case \"websocket\":\n if (this.ws.readyState === 1) { // OPEN\n this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }) });\n }\n break;\n case \"datachannel\":\n if (this.publisher.unreliableChannel.readyState === \"open\") {\n this.publisher.unreliableChannel.send(JSON.stringify({ dataType, data }));\n }\n break;\n default:\n this.unreliableTransport(undefined, dataType, data);\n break;\n }\n }\n }\n\n broadcastDataGuaranteed(dataType, data) {\n if (!this.publisher) {\n console.warn(\"broadcastDataGuaranteed called without a publisher\");\n } else {\n switch (this.reliableTransport) {\n case \"websocket\":\n if (this.ws.readyState === 1) { // OPEN\n this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }) });\n }\n break;\n case \"datachannel\":\n if (this.publisher.reliableChannel.readyState === \"open\") {\n this.publisher.reliableChannel.send(JSON.stringify({ dataType, data }));\n }\n break;\n default:\n this.reliableTransport(undefined, dataType, data);\n break;\n }\n }\n }\n\n kick(clientId, permsToken) {\n return this.publisher.handle.sendMessage({ kind: \"kick\", room_id: this.room, user_id: clientId, token: permsToken }).then(() => {\n document.body.dispatchEvent(new CustomEvent(\"kicked\", { detail: { clientId: clientId } }));\n });\n }\n\n block(clientId) {\n return this.publisher.handle.sendMessage({ kind: \"block\", whom: clientId }).then(() => {\n this.blockedClients.set(clientId, true);\n document.body.dispatchEvent(new CustomEvent(\"blocked\", { detail: { clientId: clientId } }));\n });\n }\n\n unblock(clientId) {\n return this.publisher.handle.sendMessage({ kind: \"unblock\", whom: clientId }).then(() => {\n this.blockedClients.delete(clientId);\n document.body.dispatchEvent(new CustomEvent(\"unblocked\", { detail: { clientId: clientId } }));\n });\n }\n}\n\nNAF.adapters.register(\"janus\", JanusAdapter);\n\nmodule.exports = JanusAdapter;\n","/* eslint-env browser */\n\n/**\n * This is the web browser implementation of `debug()`.\n */\n\nexports.formatArgs = formatArgs;\nexports.save = save;\nexports.load = load;\nexports.useColors = useColors;\nexports.storage = localstorage();\nexports.destroy = (() => {\n\tlet warned = false;\n\n\treturn () => {\n\t\tif (!warned) {\n\t\t\twarned = true;\n\t\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t\t}\n\t};\n})();\n\n/**\n * Colors.\n */\n\nexports.colors = [\n\t'#0000CC',\n\t'#0000FF',\n\t'#0033CC',\n\t'#0033FF',\n\t'#0066CC',\n\t'#0066FF',\n\t'#0099CC',\n\t'#0099FF',\n\t'#00CC00',\n\t'#00CC33',\n\t'#00CC66',\n\t'#00CC99',\n\t'#00CCCC',\n\t'#00CCFF',\n\t'#3300CC',\n\t'#3300FF',\n\t'#3333CC',\n\t'#3333FF',\n\t'#3366CC',\n\t'#3366FF',\n\t'#3399CC',\n\t'#3399FF',\n\t'#33CC00',\n\t'#33CC33',\n\t'#33CC66',\n\t'#33CC99',\n\t'#33CCCC',\n\t'#33CCFF',\n\t'#6600CC',\n\t'#6600FF',\n\t'#6633CC',\n\t'#6633FF',\n\t'#66CC00',\n\t'#66CC33',\n\t'#9900CC',\n\t'#9900FF',\n\t'#9933CC',\n\t'#9933FF',\n\t'#99CC00',\n\t'#99CC33',\n\t'#CC0000',\n\t'#CC0033',\n\t'#CC0066',\n\t'#CC0099',\n\t'#CC00CC',\n\t'#CC00FF',\n\t'#CC3300',\n\t'#CC3333',\n\t'#CC3366',\n\t'#CC3399',\n\t'#CC33CC',\n\t'#CC33FF',\n\t'#CC6600',\n\t'#CC6633',\n\t'#CC9900',\n\t'#CC9933',\n\t'#CCCC00',\n\t'#CCCC33',\n\t'#FF0000',\n\t'#FF0033',\n\t'#FF0066',\n\t'#FF0099',\n\t'#FF00CC',\n\t'#FF00FF',\n\t'#FF3300',\n\t'#FF3333',\n\t'#FF3366',\n\t'#FF3399',\n\t'#FF33CC',\n\t'#FF33FF',\n\t'#FF6600',\n\t'#FF6633',\n\t'#FF9900',\n\t'#FF9933',\n\t'#FFCC00',\n\t'#FFCC33'\n];\n\n/**\n * Currently only WebKit-based Web Inspectors, Firefox >= v31,\n * and the Firebug extension (any Firefox version) are known\n * to support \"%c\" CSS customizations.\n *\n * TODO: add a `localStorage` variable to explicitly enable/disable colors\n */\n\n// eslint-disable-next-line complexity\nfunction useColors() {\n\t// NB: In an Electron preload script, document will be defined but not fully\n\t// initialized. Since we know we're in Chrome, we'll just detect this case\n\t// explicitly\n\tif (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {\n\t\treturn true;\n\t}\n\n\t// Internet Explorer and Edge do not support colors.\n\tif (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\\/(\\d+)/)) {\n\t\treturn false;\n\t}\n\n\t// Is webkit? http://stackoverflow.com/a/16459606/376773\n\t// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632\n\treturn (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||\n\t\t// Is firebug? http://stackoverflow.com/a/398120/376773\n\t\t(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||\n\t\t// Is firefox >= v31?\n\t\t// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||\n\t\t// Double check webkit in userAgent just in case we are in a worker\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/));\n}\n\n/**\n * Colorize log arguments if enabled.\n *\n * @api public\n */\n\nfunction formatArgs(args) {\n\targs[0] = (this.useColors ? '%c' : '') +\n\t\tthis.namespace +\n\t\t(this.useColors ? ' %c' : ' ') +\n\t\targs[0] +\n\t\t(this.useColors ? '%c ' : ' ') +\n\t\t'+' + module.exports.humanize(this.diff);\n\n\tif (!this.useColors) {\n\t\treturn;\n\t}\n\n\tconst c = 'color: ' + this.color;\n\targs.splice(1, 0, c, 'color: inherit');\n\n\t// The final \"%c\" is somewhat tricky, because there could be other\n\t// arguments passed either before or after the %c, so we need to\n\t// figure out the correct index to insert the CSS into\n\tlet index = 0;\n\tlet lastC = 0;\n\targs[0].replace(/%[a-zA-Z%]/g, match => {\n\t\tif (match === '%%') {\n\t\t\treturn;\n\t\t}\n\t\tindex++;\n\t\tif (match === '%c') {\n\t\t\t// We only are interested in the *last* %c\n\t\t\t// (the user may have provided their own)\n\t\t\tlastC = index;\n\t\t}\n\t});\n\n\targs.splice(lastC, 0, c);\n}\n\n/**\n * Invokes `console.debug()` when available.\n * No-op when `console.debug` is not a \"function\".\n * If `console.debug` is not available, falls back\n * to `console.log`.\n *\n * @api public\n */\nexports.log = console.debug || console.log || (() => {});\n\n/**\n * Save `namespaces`.\n *\n * @param {String} namespaces\n * @api private\n */\nfunction save(namespaces) {\n\ttry {\n\t\tif (namespaces) {\n\t\t\texports.storage.setItem('debug', namespaces);\n\t\t} else {\n\t\t\texports.storage.removeItem('debug');\n\t\t}\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\n/**\n * Load `namespaces`.\n *\n * @return {String} returns the previously persisted debug modes\n * @api private\n */\nfunction load() {\n\tlet r;\n\ttry {\n\t\tr = exports.storage.getItem('debug');\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n\n\t// If debug isn't set in LS, and we're in Electron, try to load $DEBUG\n\tif (!r && typeof process !== 'undefined' && 'env' in process) {\n\t\tr = process.env.DEBUG;\n\t}\n\n\treturn r;\n}\n\n/**\n * Localstorage attempts to return the localstorage.\n *\n * This is necessary because safari throws\n * when a user disables cookies/localstorage\n * and you attempt to access it.\n *\n * @return {LocalStorage}\n * @api private\n */\n\nfunction localstorage() {\n\ttry {\n\t\t// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context\n\t\t// The Browser also has localStorage in the global context.\n\t\treturn localStorage;\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\nmodule.exports = require('./common')(exports);\n\nconst {formatters} = module.exports;\n\n/**\n * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.\n */\n\nformatters.j = function (v) {\n\ttry {\n\t\treturn JSON.stringify(v);\n\t} catch (error) {\n\t\treturn '[UnexpectedJSONParseError]: ' + error.message;\n\t}\n};\n","\n/**\n * This is the common logic for both the Node.js and web browser\n * implementations of `debug()`.\n */\n\nfunction setup(env) {\n\tcreateDebug.debug = createDebug;\n\tcreateDebug.default = createDebug;\n\tcreateDebug.coerce = coerce;\n\tcreateDebug.disable = disable;\n\tcreateDebug.enable = enable;\n\tcreateDebug.enabled = enabled;\n\tcreateDebug.humanize = require('ms');\n\tcreateDebug.destroy = destroy;\n\n\tObject.keys(env).forEach(key => {\n\t\tcreateDebug[key] = env[key];\n\t});\n\n\t/**\n\t* The currently active debug mode names, and names to skip.\n\t*/\n\n\tcreateDebug.names = [];\n\tcreateDebug.skips = [];\n\n\t/**\n\t* Map of special \"%n\" handling functions, for the debug \"format\" argument.\n\t*\n\t* Valid key names are a single, lower or upper-case letter, i.e. \"n\" and \"N\".\n\t*/\n\tcreateDebug.formatters = {};\n\n\t/**\n\t* Selects a color for a debug namespace\n\t* @param {String} namespace The namespace string for the debug instance to be colored\n\t* @return {Number|String} An ANSI color code for the given namespace\n\t* @api private\n\t*/\n\tfunction selectColor(namespace) {\n\t\tlet hash = 0;\n\n\t\tfor (let i = 0; i < namespace.length; i++) {\n\t\t\thash = ((hash << 5) - hash) + namespace.charCodeAt(i);\n\t\t\thash |= 0; // Convert to 32bit integer\n\t\t}\n\n\t\treturn createDebug.colors[Math.abs(hash) % createDebug.colors.length];\n\t}\n\tcreateDebug.selectColor = selectColor;\n\n\t/**\n\t* Create a debugger with the given `namespace`.\n\t*\n\t* @param {String} namespace\n\t* @return {Function}\n\t* @api public\n\t*/\n\tfunction createDebug(namespace) {\n\t\tlet prevTime;\n\t\tlet enableOverride = null;\n\t\tlet namespacesCache;\n\t\tlet enabledCache;\n\n\t\tfunction debug(...args) {\n\t\t\t// Disabled?\n\t\t\tif (!debug.enabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst self = debug;\n\n\t\t\t// Set `diff` timestamp\n\t\t\tconst curr = Number(new Date());\n\t\t\tconst ms = curr - (prevTime || curr);\n\t\t\tself.diff = ms;\n\t\t\tself.prev = prevTime;\n\t\t\tself.curr = curr;\n\t\t\tprevTime = curr;\n\n\t\t\targs[0] = createDebug.coerce(args[0]);\n\n\t\t\tif (typeof args[0] !== 'string') {\n\t\t\t\t// Anything else let's inspect with %O\n\t\t\t\targs.unshift('%O');\n\t\t\t}\n\n\t\t\t// Apply any `formatters` transformations\n\t\t\tlet index = 0;\n\t\t\targs[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {\n\t\t\t\t// If we encounter an escaped % then don't increase the array index\n\t\t\t\tif (match === '%%') {\n\t\t\t\t\treturn '%';\n\t\t\t\t}\n\t\t\t\tindex++;\n\t\t\t\tconst formatter = createDebug.formatters[format];\n\t\t\t\tif (typeof formatter === 'function') {\n\t\t\t\t\tconst val = args[index];\n\t\t\t\t\tmatch = formatter.call(self, val);\n\n\t\t\t\t\t// Now we need to remove `args[index]` since it's inlined in the `format`\n\t\t\t\t\targs.splice(index, 1);\n\t\t\t\t\tindex--;\n\t\t\t\t}\n\t\t\t\treturn match;\n\t\t\t});\n\n\t\t\t// Apply env-specific formatting (colors, etc.)\n\t\t\tcreateDebug.formatArgs.call(self, args);\n\n\t\t\tconst logFn = self.log || createDebug.log;\n\t\t\tlogFn.apply(self, args);\n\t\t}\n\n\t\tdebug.namespace = namespace;\n\t\tdebug.useColors = createDebug.useColors();\n\t\tdebug.color = createDebug.selectColor(namespace);\n\t\tdebug.extend = extend;\n\t\tdebug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.\n\n\t\tObject.defineProperty(debug, 'enabled', {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: false,\n\t\t\tget: () => {\n\t\t\t\tif (enableOverride !== null) {\n\t\t\t\t\treturn enableOverride;\n\t\t\t\t}\n\t\t\t\tif (namespacesCache !== createDebug.namespaces) {\n\t\t\t\t\tnamespacesCache = createDebug.namespaces;\n\t\t\t\t\tenabledCache = createDebug.enabled(namespace);\n\t\t\t\t}\n\n\t\t\t\treturn enabledCache;\n\t\t\t},\n\t\t\tset: v => {\n\t\t\t\tenableOverride = v;\n\t\t\t}\n\t\t});\n\n\t\t// Env-specific initialization logic for debug instances\n\t\tif (typeof createDebug.init === 'function') {\n\t\t\tcreateDebug.init(debug);\n\t\t}\n\n\t\treturn debug;\n\t}\n\n\tfunction extend(namespace, delimiter) {\n\t\tconst newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);\n\t\tnewDebug.log = this.log;\n\t\treturn newDebug;\n\t}\n\n\t/**\n\t* Enables a debug mode by namespaces. This can include modes\n\t* separated by a colon and wildcards.\n\t*\n\t* @param {String} namespaces\n\t* @api public\n\t*/\n\tfunction enable(namespaces) {\n\t\tcreateDebug.save(namespaces);\n\t\tcreateDebug.namespaces = namespaces;\n\n\t\tcreateDebug.names = [];\n\t\tcreateDebug.skips = [];\n\n\t\tlet i;\n\t\tconst split = (typeof namespaces === 'string' ? namespaces : '').split(/[\\s,]+/);\n\t\tconst len = split.length;\n\n\t\tfor (i = 0; i < len; i++) {\n\t\t\tif (!split[i]) {\n\t\t\t\t// ignore empty strings\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tnamespaces = split[i].replace(/\\*/g, '.*?');\n\n\t\t\tif (namespaces[0] === '-') {\n\t\t\t\tcreateDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$'));\n\t\t\t} else {\n\t\t\t\tcreateDebug.names.push(new RegExp('^' + namespaces + '$'));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t* Disable debug output.\n\t*\n\t* @return {String} namespaces\n\t* @api public\n\t*/\n\tfunction disable() {\n\t\tconst namespaces = [\n\t\t\t...createDebug.names.map(toNamespace),\n\t\t\t...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)\n\t\t].join(',');\n\t\tcreateDebug.enable('');\n\t\treturn namespaces;\n\t}\n\n\t/**\n\t* Returns true if the given mode name is enabled, false otherwise.\n\t*\n\t* @param {String} name\n\t* @return {Boolean}\n\t* @api public\n\t*/\n\tfunction enabled(name) {\n\t\tif (name[name.length - 1] === '*') {\n\t\t\treturn true;\n\t\t}\n\n\t\tlet i;\n\t\tlet len;\n\n\t\tfor (i = 0, len = createDebug.skips.length; i < len; i++) {\n\t\t\tif (createDebug.skips[i].test(name)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tfor (i = 0, len = createDebug.names.length; i < len; i++) {\n\t\t\tif (createDebug.names[i].test(name)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t* Convert regexp to namespace\n\t*\n\t* @param {RegExp} regxep\n\t* @return {String} namespace\n\t* @api private\n\t*/\n\tfunction toNamespace(regexp) {\n\t\treturn regexp.toString()\n\t\t\t.substring(2, regexp.toString().length - 2)\n\t\t\t.replace(/\\.\\*\\?$/, '*');\n\t}\n\n\t/**\n\t* Coerce `val`.\n\t*\n\t* @param {Mixed} val\n\t* @return {Mixed}\n\t* @api private\n\t*/\n\tfunction coerce(val) {\n\t\tif (val instanceof Error) {\n\t\t\treturn val.stack || val.message;\n\t\t}\n\t\treturn val;\n\t}\n\n\t/**\n\t* XXX DO NOT USE. This is a temporary stub function.\n\t* XXX It WILL be removed in the next major release.\n\t*/\n\tfunction destroy() {\n\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t}\n\n\tcreateDebug.enable(createDebug.load());\n\n\treturn createDebug;\n}\n\nmodule.exports = setup;\n","/**\n * Helpers.\n */\n\nvar s = 1000;\nvar m = s * 60;\nvar h = m * 60;\nvar d = h * 24;\nvar w = d * 7;\nvar y = d * 365.25;\n\n/**\n * Parse or format the given `val`.\n *\n * Options:\n *\n * - `long` verbose formatting [false]\n *\n * @param {String|Number} val\n * @param {Object} [options]\n * @throws {Error} throw an error if val is not a non-empty string or a number\n * @return {String|Number}\n * @api public\n */\n\nmodule.exports = function(val, options) {\n options = options || {};\n var type = typeof val;\n if (type === 'string' && val.length > 0) {\n return parse(val);\n } else if (type === 'number' && isFinite(val)) {\n return options.long ? fmtLong(val) : fmtShort(val);\n }\n throw new Error(\n 'val is not a non-empty string or a valid number. val=' +\n JSON.stringify(val)\n );\n};\n\n/**\n * Parse the given `str` and return milliseconds.\n *\n * @param {String} str\n * @return {Number}\n * @api private\n */\n\nfunction parse(str) {\n str = String(str);\n if (str.length > 100) {\n return;\n }\n var match = /^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(\n str\n );\n if (!match) {\n return;\n }\n var n = parseFloat(match[1]);\n var type = (match[2] || 'ms').toLowerCase();\n switch (type) {\n case 'years':\n case 'year':\n case 'yrs':\n case 'yr':\n case 'y':\n return n * y;\n case 'weeks':\n case 'week':\n case 'w':\n return n * w;\n case 'days':\n case 'day':\n case 'd':\n return n * d;\n case 'hours':\n case 'hour':\n case 'hrs':\n case 'hr':\n case 'h':\n return n * h;\n case 'minutes':\n case 'minute':\n case 'mins':\n case 'min':\n case 'm':\n return n * m;\n case 'seconds':\n case 'second':\n case 'secs':\n case 'sec':\n case 's':\n return n * s;\n case 'milliseconds':\n case 'millisecond':\n case 'msecs':\n case 'msec':\n case 'ms':\n return n;\n default:\n return undefined;\n }\n}\n\n/**\n * Short format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtShort(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return Math.round(ms / d) + 'd';\n }\n if (msAbs >= h) {\n return Math.round(ms / h) + 'h';\n }\n if (msAbs >= m) {\n return Math.round(ms / m) + 'm';\n }\n if (msAbs >= s) {\n return Math.round(ms / s) + 's';\n }\n return ms + 'ms';\n}\n\n/**\n * Long format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtLong(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return plural(ms, msAbs, d, 'day');\n }\n if (msAbs >= h) {\n return plural(ms, msAbs, h, 'hour');\n }\n if (msAbs >= m) {\n return plural(ms, msAbs, m, 'minute');\n }\n if (msAbs >= s) {\n return plural(ms, msAbs, s, 'second');\n }\n return ms + ' ms';\n}\n\n/**\n * Pluralization helper.\n */\n\nfunction plural(ms, msAbs, n, name) {\n var isPlural = msAbs >= n * 1.5;\n return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');\n}\n","/* eslint-env node */\n'use strict';\n\n// SDP helpers.\nconst SDPUtils = {};\n\n// Generate an alphanumeric identifier for cname or mids.\n// TODO: use UUIDs instead? https://gist.github.com/jed/982883\nSDPUtils.generateIdentifier = function() {\n return Math.random().toString(36).substring(2, 12);\n};\n\n// The RTCP CNAME used by all peerconnections from the same JS.\nSDPUtils.localCName = SDPUtils.generateIdentifier();\n\n// Splits SDP into lines, dealing with both CRLF and LF.\nSDPUtils.splitLines = function(blob) {\n return blob.trim().split('\\n').map(line => line.trim());\n};\n// Splits SDP into sessionpart and mediasections. Ensures CRLF.\nSDPUtils.splitSections = function(blob) {\n const parts = blob.split('\\nm=');\n return parts.map((part, index) => (index > 0 ?\n 'm=' + part : part).trim() + '\\r\\n');\n};\n\n// Returns the session description.\nSDPUtils.getDescription = function(blob) {\n const sections = SDPUtils.splitSections(blob);\n return sections && sections[0];\n};\n\n// Returns the individual media sections.\nSDPUtils.getMediaSections = function(blob) {\n const sections = SDPUtils.splitSections(blob);\n sections.shift();\n return sections;\n};\n\n// Returns lines that start with a certain prefix.\nSDPUtils.matchPrefix = function(blob, prefix) {\n return SDPUtils.splitLines(blob).filter(line => line.indexOf(prefix) === 0);\n};\n\n// Parses an ICE candidate line. Sample input:\n// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8\n// rport 55996\"\n// Input can be prefixed with a=.\nSDPUtils.parseCandidate = function(line) {\n let parts;\n // Parse both variants.\n if (line.indexOf('a=candidate:') === 0) {\n parts = line.substring(12).split(' ');\n } else {\n parts = line.substring(10).split(' ');\n }\n\n const candidate = {\n foundation: parts[0],\n component: {1: 'rtp', 2: 'rtcp'}[parts[1]] || parts[1],\n protocol: parts[2].toLowerCase(),\n priority: parseInt(parts[3], 10),\n ip: parts[4],\n address: parts[4], // address is an alias for ip.\n port: parseInt(parts[5], 10),\n // skip parts[6] == 'typ'\n type: parts[7],\n };\n\n for (let i = 8; i < parts.length; i += 2) {\n switch (parts[i]) {\n case 'raddr':\n candidate.relatedAddress = parts[i + 1];\n break;\n case 'rport':\n candidate.relatedPort = parseInt(parts[i + 1], 10);\n break;\n case 'tcptype':\n candidate.tcpType = parts[i + 1];\n break;\n case 'ufrag':\n candidate.ufrag = parts[i + 1]; // for backward compatibility.\n candidate.usernameFragment = parts[i + 1];\n break;\n default: // extension handling, in particular ufrag. Don't overwrite.\n if (candidate[parts[i]] === undefined) {\n candidate[parts[i]] = parts[i + 1];\n }\n break;\n }\n }\n return candidate;\n};\n\n// Translates a candidate object into SDP candidate attribute.\n// This does not include the a= prefix!\nSDPUtils.writeCandidate = function(candidate) {\n const sdp = [];\n sdp.push(candidate.foundation);\n\n const component = candidate.component;\n if (component === 'rtp') {\n sdp.push(1);\n } else if (component === 'rtcp') {\n sdp.push(2);\n } else {\n sdp.push(component);\n }\n sdp.push(candidate.protocol.toUpperCase());\n sdp.push(candidate.priority);\n sdp.push(candidate.address || candidate.ip);\n sdp.push(candidate.port);\n\n const type = candidate.type;\n sdp.push('typ');\n sdp.push(type);\n if (type !== 'host' && candidate.relatedAddress &&\n candidate.relatedPort) {\n sdp.push('raddr');\n sdp.push(candidate.relatedAddress);\n sdp.push('rport');\n sdp.push(candidate.relatedPort);\n }\n if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {\n sdp.push('tcptype');\n sdp.push(candidate.tcpType);\n }\n if (candidate.usernameFragment || candidate.ufrag) {\n sdp.push('ufrag');\n sdp.push(candidate.usernameFragment || candidate.ufrag);\n }\n return 'candidate:' + sdp.join(' ');\n};\n\n// Parses an ice-options line, returns an array of option tags.\n// Sample input:\n// a=ice-options:foo bar\nSDPUtils.parseIceOptions = function(line) {\n return line.substring(14).split(' ');\n};\n\n// Parses a rtpmap line, returns RTCRtpCoddecParameters. Sample input:\n// a=rtpmap:111 opus/48000/2\nSDPUtils.parseRtpMap = function(line) {\n let parts = line.substring(9).split(' ');\n const parsed = {\n payloadType: parseInt(parts.shift(), 10), // was: id\n };\n\n parts = parts[0].split('/');\n\n parsed.name = parts[0];\n parsed.clockRate = parseInt(parts[1], 10); // was: clockrate\n parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1;\n // legacy alias, got renamed back to channels in ORTC.\n parsed.numChannels = parsed.channels;\n return parsed;\n};\n\n// Generates a rtpmap line from RTCRtpCodecCapability or\n// RTCRtpCodecParameters.\nSDPUtils.writeRtpMap = function(codec) {\n let pt = codec.payloadType;\n if (codec.preferredPayloadType !== undefined) {\n pt = codec.preferredPayloadType;\n }\n const channels = codec.channels || codec.numChannels || 1;\n return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate +\n (channels !== 1 ? '/' + channels : '') + '\\r\\n';\n};\n\n// Parses a extmap line (headerextension from RFC 5285). Sample input:\n// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\n// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset\nSDPUtils.parseExtmap = function(line) {\n const parts = line.substring(9).split(' ');\n return {\n id: parseInt(parts[0], 10),\n direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv',\n uri: parts[1],\n attributes: parts.slice(2).join(' '),\n };\n};\n\n// Generates an extmap line from RTCRtpHeaderExtensionParameters or\n// RTCRtpHeaderExtension.\nSDPUtils.writeExtmap = function(headerExtension) {\n return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) +\n (headerExtension.direction && headerExtension.direction !== 'sendrecv'\n ? '/' + headerExtension.direction\n : '') +\n ' ' + headerExtension.uri +\n (headerExtension.attributes ? ' ' + headerExtension.attributes : '') +\n '\\r\\n';\n};\n\n// Parses a fmtp line, returns dictionary. Sample input:\n// a=fmtp:96 vbr=on;cng=on\n// Also deals with vbr=on; cng=on\nSDPUtils.parseFmtp = function(line) {\n const parsed = {};\n let kv;\n const parts = line.substring(line.indexOf(' ') + 1).split(';');\n for (let j = 0; j < parts.length; j++) {\n kv = parts[j].trim().split('=');\n parsed[kv[0].trim()] = kv[1];\n }\n return parsed;\n};\n\n// Generates a fmtp line from RTCRtpCodecCapability or RTCRtpCodecParameters.\nSDPUtils.writeFmtp = function(codec) {\n let line = '';\n let pt = codec.payloadType;\n if (codec.preferredPayloadType !== undefined) {\n pt = codec.preferredPayloadType;\n }\n if (codec.parameters && Object.keys(codec.parameters).length) {\n const params = [];\n Object.keys(codec.parameters).forEach(param => {\n if (codec.parameters[param] !== undefined) {\n params.push(param + '=' + codec.parameters[param]);\n } else {\n params.push(param);\n }\n });\n line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\\r\\n';\n }\n return line;\n};\n\n// Parses a rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:\n// a=rtcp-fb:98 nack rpsi\nSDPUtils.parseRtcpFb = function(line) {\n const parts = line.substring(line.indexOf(' ') + 1).split(' ');\n return {\n type: parts.shift(),\n parameter: parts.join(' '),\n };\n};\n\n// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.\nSDPUtils.writeRtcpFb = function(codec) {\n let lines = '';\n let pt = codec.payloadType;\n if (codec.preferredPayloadType !== undefined) {\n pt = codec.preferredPayloadType;\n }\n if (codec.rtcpFeedback && codec.rtcpFeedback.length) {\n // FIXME: special handling for trr-int?\n codec.rtcpFeedback.forEach(fb => {\n lines += 'a=rtcp-fb:' + pt + ' ' + fb.type +\n (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') +\n '\\r\\n';\n });\n }\n return lines;\n};\n\n// Parses a RFC 5576 ssrc media attribute. Sample input:\n// a=ssrc:3735928559 cname:something\nSDPUtils.parseSsrcMedia = function(line) {\n const sp = line.indexOf(' ');\n const parts = {\n ssrc: parseInt(line.substring(7, sp), 10),\n };\n const colon = line.indexOf(':', sp);\n if (colon > -1) {\n parts.attribute = line.substring(sp + 1, colon);\n parts.value = line.substring(colon + 1);\n } else {\n parts.attribute = line.substring(sp + 1);\n }\n return parts;\n};\n\n// Parse a ssrc-group line (see RFC 5576). Sample input:\n// a=ssrc-group:semantics 12 34\nSDPUtils.parseSsrcGroup = function(line) {\n const parts = line.substring(13).split(' ');\n return {\n semantics: parts.shift(),\n ssrcs: parts.map(ssrc => parseInt(ssrc, 10)),\n };\n};\n\n// Extracts the MID (RFC 5888) from a media section.\n// Returns the MID or undefined if no mid line was found.\nSDPUtils.getMid = function(mediaSection) {\n const mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0];\n if (mid) {\n return mid.substring(6);\n }\n};\n\n// Parses a fingerprint line for DTLS-SRTP.\nSDPUtils.parseFingerprint = function(line) {\n const parts = line.substring(14).split(' ');\n return {\n algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge.\n value: parts[1].toUpperCase(), // the definition is upper-case in RFC 4572.\n };\n};\n\n// Extracts DTLS parameters from SDP media section or sessionpart.\n// FIXME: for consistency with other functions this should only\n// get the fingerprint line as input. See also getIceParameters.\nSDPUtils.getDtlsParameters = function(mediaSection, sessionpart) {\n const lines = SDPUtils.matchPrefix(mediaSection + sessionpart,\n 'a=fingerprint:');\n // Note: a=setup line is ignored since we use the 'auto' role in Edge.\n return {\n role: 'auto',\n fingerprints: lines.map(SDPUtils.parseFingerprint),\n };\n};\n\n// Serializes DTLS parameters to SDP.\nSDPUtils.writeDtlsParameters = function(params, setupType) {\n let sdp = 'a=setup:' + setupType + '\\r\\n';\n params.fingerprints.forEach(fp => {\n sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\\r\\n';\n });\n return sdp;\n};\n\n// Parses a=crypto lines into\n// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members\nSDPUtils.parseCryptoLine = function(line) {\n const parts = line.substring(9).split(' ');\n return {\n tag: parseInt(parts[0], 10),\n cryptoSuite: parts[1],\n keyParams: parts[2],\n sessionParams: parts.slice(3),\n };\n};\n\nSDPUtils.writeCryptoLine = function(parameters) {\n return 'a=crypto:' + parameters.tag + ' ' +\n parameters.cryptoSuite + ' ' +\n (typeof parameters.keyParams === 'object'\n ? SDPUtils.writeCryptoKeyParams(parameters.keyParams)\n : parameters.keyParams) +\n (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') +\n '\\r\\n';\n};\n\n// Parses the crypto key parameters into\n// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam*\nSDPUtils.parseCryptoKeyParams = function(keyParams) {\n if (keyParams.indexOf('inline:') !== 0) {\n return null;\n }\n const parts = keyParams.substring(7).split('|');\n return {\n keyMethod: 'inline',\n keySalt: parts[0],\n lifeTime: parts[1],\n mkiValue: parts[2] ? parts[2].split(':')[0] : undefined,\n mkiLength: parts[2] ? parts[2].split(':')[1] : undefined,\n };\n};\n\nSDPUtils.writeCryptoKeyParams = function(keyParams) {\n return keyParams.keyMethod + ':'\n + keyParams.keySalt +\n (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') +\n (keyParams.mkiValue && keyParams.mkiLength\n ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength\n : '');\n};\n\n// Extracts all SDES parameters.\nSDPUtils.getCryptoParameters = function(mediaSection, sessionpart) {\n const lines = SDPUtils.matchPrefix(mediaSection + sessionpart,\n 'a=crypto:');\n return lines.map(SDPUtils.parseCryptoLine);\n};\n\n// Parses ICE information from SDP media section or sessionpart.\n// FIXME: for consistency with other functions this should only\n// get the ice-ufrag and ice-pwd lines as input.\nSDPUtils.getIceParameters = function(mediaSection, sessionpart) {\n const ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart,\n 'a=ice-ufrag:')[0];\n const pwd = SDPUtils.matchPrefix(mediaSection + sessionpart,\n 'a=ice-pwd:')[0];\n if (!(ufrag && pwd)) {\n return null;\n }\n return {\n usernameFragment: ufrag.substring(12),\n password: pwd.substring(10),\n };\n};\n\n// Serializes ICE parameters to SDP.\nSDPUtils.writeIceParameters = function(params) {\n let sdp = 'a=ice-ufrag:' + params.usernameFragment + '\\r\\n' +\n 'a=ice-pwd:' + params.password + '\\r\\n';\n if (params.iceLite) {\n sdp += 'a=ice-lite\\r\\n';\n }\n return sdp;\n};\n\n// Parses the SDP media section and returns RTCRtpParameters.\nSDPUtils.parseRtpParameters = function(mediaSection) {\n const description = {\n codecs: [],\n headerExtensions: [],\n fecMechanisms: [],\n rtcp: [],\n };\n const lines = SDPUtils.splitLines(mediaSection);\n const mline = lines[0].split(' ');\n description.profile = mline[2];\n for (let i = 3; i < mline.length; i++) { // find all codecs from mline[3..]\n const pt = mline[i];\n const rtpmapline = SDPUtils.matchPrefix(\n mediaSection, 'a=rtpmap:' + pt + ' ')[0];\n if (rtpmapline) {\n const codec = SDPUtils.parseRtpMap(rtpmapline);\n const fmtps = SDPUtils.matchPrefix(\n mediaSection, 'a=fmtp:' + pt + ' ');\n // Only the first a=fmtp: is considered.\n codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};\n codec.rtcpFeedback = SDPUtils.matchPrefix(\n mediaSection, 'a=rtcp-fb:' + pt + ' ')\n .map(SDPUtils.parseRtcpFb);\n description.codecs.push(codec);\n // parse FEC mechanisms from rtpmap lines.\n switch (codec.name.toUpperCase()) {\n case 'RED':\n case 'ULPFEC':\n description.fecMechanisms.push(codec.name.toUpperCase());\n break;\n default: // only RED and ULPFEC are recognized as FEC mechanisms.\n break;\n }\n }\n }\n SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(line => {\n description.headerExtensions.push(SDPUtils.parseExtmap(line));\n });\n const wildcardRtcpFb = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-fb:* ')\n .map(SDPUtils.parseRtcpFb);\n description.codecs.forEach(codec => {\n wildcardRtcpFb.forEach(fb=> {\n const duplicate = codec.rtcpFeedback.find(existingFeedback => {\n return existingFeedback.type === fb.type &&\n existingFeedback.parameter === fb.parameter;\n });\n if (!duplicate) {\n codec.rtcpFeedback.push(fb);\n }\n });\n });\n // FIXME: parse rtcp.\n return description;\n};\n\n// Generates parts of the SDP media section describing the capabilities /\n// parameters.\nSDPUtils.writeRtpDescription = function(kind, caps) {\n let sdp = '';\n\n // Build the mline.\n sdp += 'm=' + kind + ' ';\n sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.\n sdp += ' ' + (caps.profile || 'UDP/TLS/RTP/SAVPF') + ' ';\n sdp += caps.codecs.map(codec => {\n if (codec.preferredPayloadType !== undefined) {\n return codec.preferredPayloadType;\n }\n return codec.payloadType;\n }).join(' ') + '\\r\\n';\n\n sdp += 'c=IN IP4 0.0.0.0\\r\\n';\n sdp += 'a=rtcp:9 IN IP4 0.0.0.0\\r\\n';\n\n // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.\n caps.codecs.forEach(codec => {\n sdp += SDPUtils.writeRtpMap(codec);\n sdp += SDPUtils.writeFmtp(codec);\n sdp += SDPUtils.writeRtcpFb(codec);\n });\n let maxptime = 0;\n caps.codecs.forEach(codec => {\n if (codec.maxptime > maxptime) {\n maxptime = codec.maxptime;\n }\n });\n if (maxptime > 0) {\n sdp += 'a=maxptime:' + maxptime + '\\r\\n';\n }\n\n if (caps.headerExtensions) {\n caps.headerExtensions.forEach(extension => {\n sdp += SDPUtils.writeExtmap(extension);\n });\n }\n // FIXME: write fecMechanisms.\n return sdp;\n};\n\n// Parses the SDP media section and returns an array of\n// RTCRtpEncodingParameters.\nSDPUtils.parseRtpEncodingParameters = function(mediaSection) {\n const encodingParameters = [];\n const description = SDPUtils.parseRtpParameters(mediaSection);\n const hasRed = description.fecMechanisms.indexOf('RED') !== -1;\n const hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;\n\n // filter a=ssrc:... cname:, ignore PlanB-msid\n const ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')\n .map(line => SDPUtils.parseSsrcMedia(line))\n .filter(parts => parts.attribute === 'cname');\n const primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;\n let secondarySsrc;\n\n const flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID')\n .map(line => {\n const parts = line.substring(17).split(' ');\n return parts.map(part => parseInt(part, 10));\n });\n if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {\n secondarySsrc = flows[0][1];\n }\n\n description.codecs.forEach(codec => {\n if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {\n let encParam = {\n ssrc: primarySsrc,\n codecPayloadType: parseInt(codec.parameters.apt, 10),\n };\n if (primarySsrc && secondarySsrc) {\n encParam.rtx = {ssrc: secondarySsrc};\n }\n encodingParameters.push(encParam);\n if (hasRed) {\n encParam = JSON.parse(JSON.stringify(encParam));\n encParam.fec = {\n ssrc: primarySsrc,\n mechanism: hasUlpfec ? 'red+ulpfec' : 'red',\n };\n encodingParameters.push(encParam);\n }\n }\n });\n if (encodingParameters.length === 0 && primarySsrc) {\n encodingParameters.push({\n ssrc: primarySsrc,\n });\n }\n\n // we support both b=AS and b=TIAS but interpret AS as TIAS.\n let bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');\n if (bandwidth.length) {\n if (bandwidth[0].indexOf('b=TIAS:') === 0) {\n bandwidth = parseInt(bandwidth[0].substring(7), 10);\n } else if (bandwidth[0].indexOf('b=AS:') === 0) {\n // use formula from JSEP to convert b=AS to TIAS value.\n bandwidth = parseInt(bandwidth[0].substring(5), 10) * 1000 * 0.95\n - (50 * 40 * 8);\n } else {\n bandwidth = undefined;\n }\n encodingParameters.forEach(params => {\n params.maxBitrate = bandwidth;\n });\n }\n return encodingParameters;\n};\n\n// parses http://draft.ortc.org/#rtcrtcpparameters*\nSDPUtils.parseRtcpParameters = function(mediaSection) {\n const rtcpParameters = {};\n\n // Gets the first SSRC. Note that with RTX there might be multiple\n // SSRCs.\n const remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')\n .map(line => SDPUtils.parseSsrcMedia(line))\n .filter(obj => obj.attribute === 'cname')[0];\n if (remoteSsrc) {\n rtcpParameters.cname = remoteSsrc.value;\n rtcpParameters.ssrc = remoteSsrc.ssrc;\n }\n\n // Edge uses the compound attribute instead of reducedSize\n // compound is !reducedSize\n const rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize');\n rtcpParameters.reducedSize = rsize.length > 0;\n rtcpParameters.compound = rsize.length === 0;\n\n // parses the rtcp-mux attrŅ–bute.\n // Note that Edge does not support unmuxed RTCP.\n const mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux');\n rtcpParameters.mux = mux.length > 0;\n\n return rtcpParameters;\n};\n\nSDPUtils.writeRtcpParameters = function(rtcpParameters) {\n let sdp = '';\n if (rtcpParameters.reducedSize) {\n sdp += 'a=rtcp-rsize\\r\\n';\n }\n if (rtcpParameters.mux) {\n sdp += 'a=rtcp-mux\\r\\n';\n }\n if (rtcpParameters.ssrc !== undefined && rtcpParameters.cname) {\n sdp += 'a=ssrc:' + rtcpParameters.ssrc +\n ' cname:' + rtcpParameters.cname + '\\r\\n';\n }\n return sdp;\n};\n\n\n// parses either a=msid: or a=ssrc:... msid lines and returns\n// the id of the MediaStream and MediaStreamTrack.\nSDPUtils.parseMsid = function(mediaSection) {\n let parts;\n const spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:');\n if (spec.length === 1) {\n parts = spec[0].substring(7).split(' ');\n return {stream: parts[0], track: parts[1]};\n }\n const planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')\n .map(line => SDPUtils.parseSsrcMedia(line))\n .filter(msidParts => msidParts.attribute === 'msid');\n if (planB.length > 0) {\n parts = planB[0].value.split(' ');\n return {stream: parts[0], track: parts[1]};\n }\n};\n\n// SCTP\n// parses draft-ietf-mmusic-sctp-sdp-26 first and falls back\n// to draft-ietf-mmusic-sctp-sdp-05\nSDPUtils.parseSctpDescription = function(mediaSection) {\n const mline = SDPUtils.parseMLine(mediaSection);\n const maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:');\n let maxMessageSize;\n if (maxSizeLine.length > 0) {\n maxMessageSize = parseInt(maxSizeLine[0].substring(19), 10);\n }\n if (isNaN(maxMessageSize)) {\n maxMessageSize = 65536;\n }\n const sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:');\n if (sctpPort.length > 0) {\n return {\n port: parseInt(sctpPort[0].substring(12), 10),\n protocol: mline.fmt,\n maxMessageSize,\n };\n }\n const sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:');\n if (sctpMapLines.length > 0) {\n const parts = sctpMapLines[0]\n .substring(10)\n .split(' ');\n return {\n port: parseInt(parts[0], 10),\n protocol: parts[1],\n maxMessageSize,\n };\n }\n};\n\n// SCTP\n// outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers\n// support by now receiving in this format, unless we originally parsed\n// as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line\n// protocol of DTLS/SCTP -- without UDP/ or TCP/)\nSDPUtils.writeSctpDescription = function(media, sctp) {\n let output = [];\n if (media.protocol !== 'DTLS/SCTP') {\n output = [\n 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\\r\\n',\n 'c=IN IP4 0.0.0.0\\r\\n',\n 'a=sctp-port:' + sctp.port + '\\r\\n',\n ];\n } else {\n output = [\n 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\\r\\n',\n 'c=IN IP4 0.0.0.0\\r\\n',\n 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\\r\\n',\n ];\n }\n if (sctp.maxMessageSize !== undefined) {\n output.push('a=max-message-size:' + sctp.maxMessageSize + '\\r\\n');\n }\n return output.join('');\n};\n\n// Generate a session ID for SDP.\n// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1\n// recommends using a cryptographically random +ve 64-bit value\n// but right now this should be acceptable and within the right range\nSDPUtils.generateSessionId = function() {\n return Math.random().toString().substr(2, 22);\n};\n\n// Write boiler plate for start of SDP\n// sessId argument is optional - if not supplied it will\n// be generated randomly\n// sessVersion is optional and defaults to 2\n// sessUser is optional and defaults to 'thisisadapterortc'\nSDPUtils.writeSessionBoilerplate = function(sessId, sessVer, sessUser) {\n let sessionId;\n const version = sessVer !== undefined ? sessVer : 2;\n if (sessId) {\n sessionId = sessId;\n } else {\n sessionId = SDPUtils.generateSessionId();\n }\n const user = sessUser || 'thisisadapterortc';\n // FIXME: sess-id should be an NTP timestamp.\n return 'v=0\\r\\n' +\n 'o=' + user + ' ' + sessionId + ' ' + version +\n ' IN IP4 127.0.0.1\\r\\n' +\n 's=-\\r\\n' +\n 't=0 0\\r\\n';\n};\n\n// Gets the direction from the mediaSection or the sessionpart.\nSDPUtils.getDirection = function(mediaSection, sessionpart) {\n // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.\n const lines = SDPUtils.splitLines(mediaSection);\n for (let i = 0; i < lines.length; i++) {\n switch (lines[i]) {\n case 'a=sendrecv':\n case 'a=sendonly':\n case 'a=recvonly':\n case 'a=inactive':\n return lines[i].substring(2);\n default:\n // FIXME: What should happen here?\n }\n }\n if (sessionpart) {\n return SDPUtils.getDirection(sessionpart);\n }\n return 'sendrecv';\n};\n\nSDPUtils.getKind = function(mediaSection) {\n const lines = SDPUtils.splitLines(mediaSection);\n const mline = lines[0].split(' ');\n return mline[0].substring(2);\n};\n\nSDPUtils.isRejected = function(mediaSection) {\n return mediaSection.split(' ', 2)[1] === '0';\n};\n\nSDPUtils.parseMLine = function(mediaSection) {\n const lines = SDPUtils.splitLines(mediaSection);\n const parts = lines[0].substring(2).split(' ');\n return {\n kind: parts[0],\n port: parseInt(parts[1], 10),\n protocol: parts[2],\n fmt: parts.slice(3).join(' '),\n };\n};\n\nSDPUtils.parseOLine = function(mediaSection) {\n const line = SDPUtils.matchPrefix(mediaSection, 'o=')[0];\n const parts = line.substring(2).split(' ');\n return {\n username: parts[0],\n sessionId: parts[1],\n sessionVersion: parseInt(parts[2], 10),\n netType: parts[3],\n addressType: parts[4],\n address: parts[5],\n };\n};\n\n// a very naive interpretation of a valid SDP.\nSDPUtils.isValidSDP = function(blob) {\n if (typeof blob !== 'string' || blob.length === 0) {\n return false;\n }\n const lines = SDPUtils.splitLines(blob);\n for (let i = 0; i < lines.length; i++) {\n if (lines[i].length < 2 || lines[i].charAt(1) !== '=') {\n return false;\n }\n // TODO: check the modifier a bit more.\n }\n return true;\n};\n\n// Expose public methods.\nif (typeof module === 'object') {\n module.exports = SDPUtils;\n}\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(497);\n"],"names":["JanusPluginHandle","session","this","id","undefined","JanusSession","output","options","nextTxId","txns","eventHandlers","Object","assign","verbose","timeoutMs","keepaliveMs","prototype","attach","plugin","loop_index","payload","send","then","resp","data","detach","on","ev","callback","signal","sender","type","handle_id","sendMessage","body","sendJsep","jsep","sendTrickle","candidate","create","destroy","dispose","txId","_killKeepalive","hasOwnProperty","txn","clearTimeout","timeout","reject","Error","isError","janus","handlers","push","receive","_logIncoming","session_id","console","warn","responseType","i","length","transaction","resolve","toString","Promise","setTimeout","_transmit","_logOutgoing","JSON","stringify","_resetKeepalive","kind","message","debug","_sendKeepalive","keepaliveTimeout","catch","e","error","module","exports","mj","require","sendOriginal","indexOf","NAF","connection","adapter","reconnect","sdpUtils","isSafari","test","navigator","userAgent","debounce","fn","curr","args","Array","slice","call","arguments","_","apply","untilDataChannelOpen","dataChannel","readyState","resolver","rejector","clear","removeEventListener","addEventListener","isH264VideoSupported","document","createElement","canPlayType","OPUS_PARAMETERS","usedtx","stereo","DEFAULT_PEER_CONNECTION_CONFIG","iceServers","urls","JanusAdapter","constructor","room","clientId","joinToken","serverUrl","webRtcOptions","peerConnectionConfig","ws","reliableTransport","unreliableTransport","initialReconnectionDelay","Math","random","reconnectionDelay","reconnectionTimeout","maxReconnectionAttempts","reconnectionAttempts","publisher","occupantIds","occupants","mediaStreams","localMediaStream","pendingMediaRequests","Map","pendingOccupants","Set","availableOccupants","requestedOccupants","blockedClients","frozenUpdates","timeOffsets","serverTimeRequests","avgTimeOffset","onWebsocketOpen","bind","onWebsocketClose","onWebsocketMessage","onDataChannelMessage","onData","setServerUrl","url","setApp","app","setRoom","roomName","setJoinToken","setClientId","setWebRtcOptions","setPeerConnectionConfig","setServerConnectListeners","successListener","failureListener","connectSuccess","connectFailure","setRoomOccupantListener","occupantListener","onOccupantsChanged","setDataChannelListeners","openListener","closedListener","messageListener","onOccupantConnected","onOccupantDisconnected","onOccupantMessage","setReconnectionListeners","reconnectingListener","reconnectedListener","reconnectionErrorListener","onReconnecting","onReconnected","onReconnectionError","setEventLoops","loops","connect","websocketConnection","WebSocket","wsOnOpen","all","updateTimeOffset","disconnect","removeAllOccupants","conn","close","delayedReconnectTimeout","isDisconnected","createPublisher","initialOccupants","occupantId","addAvailableOccupant","syncOccupants","event","code","performDelayedReconnect","parse","removeAvailableOccupant","idx","splice","has","addOccupant","j","removeOccupant","add","delay","subscriber","createSubscriber","delete","setMediaStream","mediaStream","msg","get","audio","video","associate","handle","iceConnectionState","log","offer","createOffer","configurePublisherSdp","fixSafariIceUFrag","local","o","setLocalDescription","remote","r","setRemoteDescription","answer","configureSubscriberSdp","createAnswer","a","RTCPeerConnection","parseInt","webrtcup","reliableChannel","createDataChannel","ordered","unreliableChannel","maxRetransmits","getTracks","forEach","track","addTrack","plugindata","room_id","user_id","dispatchEvent","CustomEvent","detail","by","sendJoin","notifications","success","err","response","users","includes","sdp","replace","line","pt","parameters","parseFmtp","writeFmtp","payloadType","maxRetries","webrtcFailed","leftInterval","setInterval","clearInterval","media","_iOSHackDelayedInitialPeer","MediaStream","getReceivers","receiver","subscribe","token","toggleFreeze","frozen","unfreeze","freeze","flushPendingUpdates","dataForUpdateMultiMessage","networkId","l","d","getPendingData","dataType","owner","getPendingDataForNetworkId","source","storeMessage","storeSingleMessage","index","storedMessage","storedData","isOutdatedMessage","lastOwnerTime","isContemporaneousMessage","isFirstSync","set","components","enabled","shouldStartConnectionTo","client","startStreamConnection","closeStreamConnection","getConnectStatus","adapters","IS_CONNECTED","NOT_CONNECTED","clientSentTime","Date","now","res","fetch","location","href","method","cache","serverReceivedTime","headers","getTime","precision","clientReceivedTime","timeOffset","reduce","acc","offset","getServerTime","getMediaStream","audioPromise","videoPromise","promise","stream","audioStream","getAudioTracks","videoStream","getVideoTracks","getLocalMediaStream","setLocalMediaStream","existingSenders","getSenders","newSenders","tracks","t","find","s","replaceTrack","removeTrack","enableMicrophone","sendData","whom","sendDataGuaranteed","broadcastData","broadcastDataGuaranteed","kick","permsToken","block","unblock","register","formatArgs","useColors","namespace","humanize","diff","c","color","lastC","match","save","namespaces","storage","setItem","removeItem","load","getItem","process","env","DEBUG","window","__nwjs","toLowerCase","documentElement","style","WebkitAppearance","firebug","exception","table","RegExp","$1","localStorage","localstorage","warned","colors","formatters","v","createDebug","prevTime","namespacesCache","enabledCache","enableOverride","self","Number","ms","prev","coerce","unshift","format","formatter","val","selectColor","extend","defineProperty","enumerable","configurable","init","delimiter","newDebug","toNamespace","regexp","substring","default","stack","disable","names","map","skips","join","enable","split","len","name","keys","key","hash","charCodeAt","abs","m","h","plural","msAbs","n","isPlural","round","str","String","exec","parseFloat","isFinite","long","fmtShort","SDPUtils","localCName","generateIdentifier","splitLines","blob","trim","splitSections","part","getDescription","sections","getMediaSections","shift","matchPrefix","prefix","filter","parseCandidate","parts","foundation","component","protocol","priority","ip","address","port","relatedAddress","relatedPort","tcpType","ufrag","usernameFragment","writeCandidate","toUpperCase","parseIceOptions","parseRtpMap","parsed","clockRate","channels","numChannels","writeRtpMap","codec","preferredPayloadType","parseExtmap","direction","uri","attributes","writeExtmap","headerExtension","preferredId","kv","params","param","parseRtcpFb","parameter","writeRtcpFb","lines","rtcpFeedback","fb","parseSsrcMedia","sp","ssrc","colon","attribute","value","parseSsrcGroup","semantics","ssrcs","getMid","mediaSection","mid","parseFingerprint","algorithm","getDtlsParameters","sessionpart","role","fingerprints","writeDtlsParameters","setupType","fp","parseCryptoLine","tag","cryptoSuite","keyParams","sessionParams","writeCryptoLine","writeCryptoKeyParams","parseCryptoKeyParams","keyMethod","keySalt","lifeTime","mkiValue","mkiLength","getCryptoParameters","getIceParameters","pwd","password","writeIceParameters","iceLite","parseRtpParameters","description","codecs","headerExtensions","fecMechanisms","rtcp","mline","profile","rtpmapline","fmtps","wildcardRtcpFb","existingFeedback","writeRtpDescription","caps","maxptime","extension","parseRtpEncodingParameters","encodingParameters","hasRed","hasUlpfec","primarySsrc","secondarySsrc","flows","apt","encParam","codecPayloadType","rtx","fec","mechanism","bandwidth","maxBitrate","parseRtcpParameters","rtcpParameters","remoteSsrc","obj","cname","rsize","reducedSize","compound","mux","writeRtcpParameters","parseMsid","spec","planB","msidParts","parseSctpDescription","parseMLine","maxSizeLine","maxMessageSize","isNaN","sctpPort","fmt","sctpMapLines","writeSctpDescription","sctp","generateSessionId","substr","writeSessionBoilerplate","sessId","sessVer","sessUser","sessionId","version","getDirection","getKind","isRejected","parseOLine","username","sessionVersion","netType","addressType","isValidSDP","charAt","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"naf-janus-adapter.min.js","mappings":"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","sources":["webpack://@networked-aframe/naf-janus-adapter/./node_modules/@networked-aframe/minijanus/minijanus.js","webpack://@networked-aframe/naf-janus-adapter/./src/index.js","webpack://@networked-aframe/naf-janus-adapter/./node_modules/debug/src/browser.js","webpack://@networked-aframe/naf-janus-adapter/./node_modules/debug/src/common.js","webpack://@networked-aframe/naf-janus-adapter/./node_modules/ms/index.js","webpack://@networked-aframe/naf-janus-adapter/./node_modules/sdp/sdp.js","webpack://@networked-aframe/naf-janus-adapter/webpack/bootstrap","webpack://@networked-aframe/naf-janus-adapter/webpack/startup"],"sourcesContent":["/**\n * Represents a handle to a single Janus plugin on a Janus session. Each WebRTC connection to the Janus server will be\n * associated with a single handle. Once attached to the server, this handle will be given a unique ID which should be\n * used to associate it with future signalling messages.\n *\n * See https://janus.conf.meetecho.com/docs/rest.html#handles.\n **/\nfunction JanusPluginHandle(session) {\n this.session = session;\n this.id = undefined;\n}\n\n/** Attaches this handle to the Janus server and sets its ID. **/\nJanusPluginHandle.prototype.attach = function(plugin, loop_index) {\n var payload = { plugin: plugin, loop_index: loop_index, \"force-bundle\": true, \"force-rtcp-mux\": true };\n return this.session.send(\"attach\", payload).then(resp => {\n this.id = resp.data.id;\n return resp;\n });\n};\n\n/** Detaches this handle. **/\nJanusPluginHandle.prototype.detach = function() {\n return this.send(\"detach\");\n};\n\n/** Registers a callback to be fired upon the reception of any incoming Janus signals for this plugin handle with the\n * `janus` attribute equal to `ev`.\n **/\nJanusPluginHandle.prototype.on = function(ev, callback) {\n return this.session.on(ev, signal => {\n if (signal.sender == this.id) {\n callback(signal);\n }\n });\n};\n\n/**\n * Sends a signal associated with this handle. Signals should be JSON-serializable objects. Returns a promise that will\n * be resolved or rejected when a response to this signal is received, or when no response is received within the\n * session timeout.\n **/\nJanusPluginHandle.prototype.send = function(type, signal) {\n return this.session.send(type, Object.assign({ handle_id: this.id }, signal));\n};\n\n/** Sends a plugin-specific message associated with this handle. **/\nJanusPluginHandle.prototype.sendMessage = function(body) {\n return this.send(\"message\", { body: body });\n};\n\n/** Sends a JSEP offer or answer associated with this handle. **/\nJanusPluginHandle.prototype.sendJsep = function(jsep) {\n return this.send(\"message\", { body: {}, jsep: jsep });\n};\n\n/** Sends an ICE trickle candidate associated with this handle. **/\nJanusPluginHandle.prototype.sendTrickle = function(candidate) {\n return this.send(\"trickle\", { candidate: candidate });\n};\n\n/**\n * Represents a Janus session -- a Janus context from within which you can open multiple handles and connections. Once\n * created, this session will be given a unique ID which should be used to associate it with future signalling messages.\n *\n * See https://janus.conf.meetecho.com/docs/rest.html#sessions.\n **/\nfunction JanusSession(output, options) {\n this.output = output;\n this.id = undefined;\n this.nextTxId = 0;\n this.txns = {};\n this.eventHandlers = {};\n this.options = Object.assign({\n verbose: false,\n timeoutMs: 10000,\n keepaliveMs: 30000\n }, options);\n}\n\n/** Creates this session on the Janus server and sets its ID. **/\nJanusSession.prototype.create = function() {\n return this.send(\"create\").then(resp => {\n this.id = resp.data.id;\n return resp;\n });\n};\n\n/**\n * Destroys this session. Note that upon destruction, Janus will also close the signalling transport (if applicable) and\n * any open WebRTC connections.\n **/\nJanusSession.prototype.destroy = function() {\n return this.send(\"destroy\").then((resp) => {\n this.dispose();\n return resp;\n });\n};\n\n/**\n * Disposes of this session in a way such that no further incoming signalling messages will be processed.\n * Outstanding transactions will be rejected.\n **/\nJanusSession.prototype.dispose = function() {\n this._killKeepalive();\n this.eventHandlers = {};\n for (var txId in this.txns) {\n if (this.txns.hasOwnProperty(txId)) {\n var txn = this.txns[txId];\n clearTimeout(txn.timeout);\n txn.reject(new Error(\"Janus session was disposed.\"));\n delete this.txns[txId];\n }\n }\n};\n\n/**\n * Whether this signal represents an error, and the associated promise (if any) should be rejected.\n * Users should override this to handle any custom plugin-specific error conventions.\n **/\nJanusSession.prototype.isError = function(signal) {\n return signal.janus === \"error\";\n};\n\n/** Registers a callback to be fired upon the reception of any incoming Janus signals for this session with the\n * `janus` attribute equal to `ev`.\n **/\nJanusSession.prototype.on = function(ev, callback) {\n var handlers = this.eventHandlers[ev];\n if (handlers == null) {\n handlers = this.eventHandlers[ev] = [];\n }\n handlers.push(callback);\n};\n\n/**\n * Callback for receiving JSON signalling messages pertinent to this session. If the signals are responses to previously\n * sent signals, the promises for the outgoing signals will be resolved or rejected appropriately with this signal as an\n * argument.\n *\n * External callers should call this function every time a new signal arrives on the transport; for example, in a\n * WebSocket's `message` event, or when a new datum shows up in an HTTP long-polling response.\n **/\nJanusSession.prototype.receive = function(signal) {\n if (this.options.verbose) {\n this._logIncoming(signal);\n }\n if (signal.session_id != this.id) {\n console.warn(\"Incorrect session ID received in Janus signalling message: was \" + signal.session_id + \", expected \" + this.id + \".\");\n }\n\n var responseType = signal.janus;\n var handlers = this.eventHandlers[responseType];\n if (handlers != null) {\n for (var i = 0; i < handlers.length; i++) {\n handlers[i](signal);\n }\n }\n\n if (signal.transaction != null) {\n var txn = this.txns[signal.transaction];\n if (txn == null) {\n // this is a response to a transaction that wasn't caused via JanusSession.send, or a plugin replied twice to a\n // single request, or the session was disposed, or something else that isn't under our purview; that's fine\n return;\n }\n\n if (responseType === \"ack\" && txn.type == \"message\") {\n // this is an ack of an asynchronously-processed plugin request, we should wait to resolve the promise until the\n // actual response comes in\n return;\n }\n\n clearTimeout(txn.timeout);\n\n delete this.txns[signal.transaction];\n (this.isError(signal) ? txn.reject : txn.resolve)(signal);\n }\n};\n\n/**\n * Sends a signal associated with this session, beginning a new transaction. Returns a promise that will be resolved or\n * rejected when a response is received in the same transaction, or when no response is received within the session\n * timeout.\n **/\nJanusSession.prototype.send = function(type, signal) {\n signal = Object.assign({ transaction: (this.nextTxId++).toString() }, signal);\n return new Promise((resolve, reject) => {\n var timeout = null;\n if (this.options.timeoutMs) {\n timeout = setTimeout(() => {\n delete this.txns[signal.transaction];\n reject(new Error(\"Signalling transaction with txid \" + signal.transaction + \" timed out.\"));\n }, this.options.timeoutMs);\n }\n this.txns[signal.transaction] = { resolve: resolve, reject: reject, timeout: timeout, type: type };\n this._transmit(type, signal);\n });\n};\n\nJanusSession.prototype._transmit = function(type, signal) {\n signal = Object.assign({ janus: type }, signal);\n\n if (this.id != null) { // this.id is undefined in the special case when we're sending the session create message\n signal = Object.assign({ session_id: this.id }, signal);\n }\n\n if (this.options.verbose) {\n this._logOutgoing(signal);\n }\n\n this.output(JSON.stringify(signal));\n this._resetKeepalive();\n};\n\nJanusSession.prototype._logOutgoing = function(signal) {\n var kind = signal.janus;\n if (kind === \"message\" && signal.jsep) {\n kind = signal.jsep.type;\n }\n var message = \"> Outgoing Janus \" + (kind || \"signal\") + \" (#\" + signal.transaction + \"): \";\n console.debug(\"%c\" + message, \"color: #040\", signal);\n};\n\nJanusSession.prototype._logIncoming = function(signal) {\n var kind = signal.janus;\n var message = signal.transaction ?\n \"< Incoming Janus \" + (kind || \"signal\") + \" (#\" + signal.transaction + \"): \" :\n \"< Incoming Janus \" + (kind || \"signal\") + \": \";\n console.debug(\"%c\" + message, \"color: #004\", signal);\n};\n\nJanusSession.prototype._sendKeepalive = function() {\n return this.send(\"keepalive\");\n};\n\nJanusSession.prototype._killKeepalive = function() {\n clearTimeout(this.keepaliveTimeout);\n};\n\nJanusSession.prototype._resetKeepalive = function() {\n this._killKeepalive();\n if (this.options.keepaliveMs) {\n this.keepaliveTimeout = setTimeout(() => {\n this._sendKeepalive().catch(e => console.error(\"Error received from keepalive: \", e));\n }, this.options.keepaliveMs);\n }\n};\n\nmodule.exports = {\n JanusPluginHandle,\n JanusSession\n};\n","/* global NAF */\nvar mj = require(\"@networked-aframe/minijanus\");\nmj.JanusSession.prototype.sendOriginal = mj.JanusSession.prototype.send;\nmj.JanusSession.prototype.send = function(type, signal) {\n return this.sendOriginal(type, signal).catch((e) => {\n if (e.message && e.message.indexOf(\"timed out\") > -1) {\n console.error(\"web socket timed out\");\n NAF.connection.adapter.reconnect();\n } else {\n throw(e);\n }\n });\n}\n\nvar sdpUtils = require(\"sdp\");\nvar debug = require(\"debug\")(\"naf-janus-adapter:debug\");\nvar warn = require(\"debug\")(\"naf-janus-adapter:warn\");\nvar error = require(\"debug\")(\"naf-janus-adapter:error\");\nvar isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\nconst SUBSCRIBE_TIMEOUT_MS = 15000;\n\nconst AVAILABLE_OCCUPANTS_THRESHOLD = 5;\nconst MAX_SUBSCRIBE_DELAY = 5000;\n\nfunction randomDelay(min, max) {\n return new Promise(resolve => {\n const delay = Math.random() * (max - min) + min;\n setTimeout(resolve, delay);\n });\n}\n\nfunction debounce(fn) {\n var curr = Promise.resolve();\n return function() {\n var args = Array.prototype.slice.call(arguments);\n curr = curr.then(_ => fn.apply(this, args));\n };\n}\n\nfunction randomUint() {\n return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);\n}\n\nfunction untilDataChannelOpen(dataChannel) {\n return new Promise((resolve, reject) => {\n if (dataChannel.readyState === \"open\") {\n resolve();\n } else {\n let resolver, rejector;\n\n const clear = () => {\n dataChannel.removeEventListener(\"open\", resolver);\n dataChannel.removeEventListener(\"error\", rejector);\n };\n\n resolver = () => {\n clear();\n resolve();\n };\n rejector = () => {\n clear();\n reject();\n };\n\n dataChannel.addEventListener(\"open\", resolver);\n dataChannel.addEventListener(\"error\", rejector);\n }\n });\n}\n\nconst isH264VideoSupported = (() => {\n const video = document.createElement(\"video\");\n return video.canPlayType('video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"') !== \"\";\n})();\n\nconst OPUS_PARAMETERS = {\n // indicates that we want to enable DTX to elide silence packets\n usedtx: 1,\n // indicates that we prefer to receive mono audio (important for voip profile)\n stereo: 0,\n // indicates that we prefer to send mono audio (important for voip profile)\n \"sprop-stereo\": 0\n};\n\nconst DEFAULT_PEER_CONNECTION_CONFIG = {\n iceServers: [{ urls: \"stun:stun1.l.google.com:19302\" }, { urls: \"stun:stun2.l.google.com:19302\" }]\n};\n\nconst WS_NORMAL_CLOSURE = 1000;\n\nclass JanusAdapter {\n constructor() {\n this.room = null;\n // We expect the consumer to set a client id before connecting.\n this.clientId = null;\n this.joinToken = null;\n\n this.serverUrl = null;\n this.webRtcOptions = {};\n this.peerConnectionConfig = null;\n this.ws = null;\n this.session = null;\n this.reliableTransport = \"datachannel\";\n this.unreliableTransport = \"datachannel\";\n\n // In the event the server restarts and all clients lose connection, reconnect with\n // some random jitter added to prevent simultaneous reconnection requests.\n this.initialReconnectionDelay = 1000 * Math.random();\n this.reconnectionDelay = this.initialReconnectionDelay;\n this.reconnectionTimeout = null;\n this.maxReconnectionAttempts = 10;\n this.reconnectionAttempts = 0;\n this.isReconnecting = false;\n\n this.publisher = null;\n this.occupantIds = [];\n this.occupants = {};\n this.mediaStreams = {};\n this.localMediaStream = null;\n this.pendingMediaRequests = new Map();\n\n this.pendingOccupants = new Set();\n this.availableOccupants = [];\n this.requestedOccupants = null;\n\n this.blockedClients = new Map();\n this.frozenUpdates = new Map();\n\n this.timeOffsets = [];\n this.serverTimeRequests = 0;\n this.avgTimeOffset = 0;\n\n this.onWebsocketOpen = this.onWebsocketOpen.bind(this);\n this.onWebsocketClose = this.onWebsocketClose.bind(this);\n this.onWebsocketMessage = this.onWebsocketMessage.bind(this);\n this.onDataChannelMessage = this.onDataChannelMessage.bind(this);\n this.onData = this.onData.bind(this);\n }\n\n setServerUrl(url) {\n this.serverUrl = url;\n }\n\n setApp(app) {}\n\n setRoom(roomName) {\n this.room = roomName;\n }\n\n setJoinToken(joinToken) {\n this.joinToken = joinToken;\n }\n\n setClientId(clientId) {\n this.clientId = clientId;\n }\n\n setWebRtcOptions(options) {\n this.webRtcOptions = options;\n }\n\n setPeerConnectionConfig(peerConnectionConfig) {\n this.peerConnectionConfig = peerConnectionConfig;\n }\n\n setServerConnectListeners(successListener, failureListener) {\n this.connectSuccess = successListener;\n this.connectFailure = failureListener;\n }\n\n setRoomOccupantListener(occupantListener) {\n this.onOccupantsChanged = occupantListener;\n }\n\n setDataChannelListeners(openListener, closedListener, messageListener) {\n this.onOccupantConnected = openListener;\n this.onOccupantDisconnected = closedListener;\n this.onOccupantMessage = messageListener;\n }\n\n setReconnectionListeners(reconnectingListener, reconnectedListener, reconnectionErrorListener) {\n // onReconnecting is called with the number of milliseconds until the next reconnection attempt\n this.onReconnecting = reconnectingListener;\n // onReconnected is called when the connection has been reestablished\n this.onReconnected = reconnectedListener;\n // onReconnectionError is called with an error when maxReconnectionAttempts has been reached\n this.onReconnectionError = reconnectionErrorListener;\n }\n\n setEventLoops(loops) {\n this.loops = loops;\n }\n\n connect() {\n if (this.serverUrl === '/') {\n this.serverUrl = '/janus';\n }\n if (this.serverUrl === '/janus') {\n if (location.protocol === 'https:') {\n this.serverUrl = 'wss://' + location.host + '/janus';\n } else {\n this.serverUrl = 'ws://' + location.host + '/janus';\n }\n }\n debug(`connecting to ${this.serverUrl}`);\n\n const websocketConnection = new Promise((resolve, reject) => {\n this.ws = new WebSocket(this.serverUrl, \"janus-protocol\");\n\n this.session = new mj.JanusSession(this.ws.send.bind(this.ws), { timeoutMs: 40000 });\n\n this.websocketConnectionPromise = {};\n this.websocketConnectionPromise.resolve = resolve;\n this.websocketConnectionPromise.reject = reject;\n\n this.ws.addEventListener(\"close\", this.onWebsocketClose);\n this.ws.addEventListener(\"message\", this.onWebsocketMessage);\n\n this.wsOnOpen = () => {\n this.ws.removeEventListener(\"open\", this.wsOnOpen);\n this.onWebsocketOpen()\n .then(resolve)\n .catch(reject);\n };\n\n this.ws.addEventListener(\"open\", this.wsOnOpen);\n });\n\n return Promise.all([websocketConnection, this.updateTimeOffset()]);\n }\n\n disconnect() {\n debug(`disconnecting`);\n\n clearTimeout(this.reconnectionTimeout);\n\n this.removeAllOccupants();\n\n if (this.publisher) {\n // Close the publisher peer connection. Which also detaches the plugin handle.\n this.publisher.conn.close();\n this.publisher = null;\n }\n\n if (this.session) {\n this.session.dispose();\n this.session = null;\n }\n\n if (this.ws) {\n this.ws.removeEventListener(\"open\", this.wsOnOpen);\n this.ws.removeEventListener(\"close\", this.onWebsocketClose);\n this.ws.removeEventListener(\"message\", this.onWebsocketMessage);\n this.ws.close();\n this.ws = null;\n }\n\n // Now that all RTCPeerConnection closed, be sure to not call\n // reconnect() again via performDelayedReconnect if previous\n // RTCPeerConnection was in the failed state.\n if (this.delayedReconnectTimeout) {\n clearTimeout(this.delayedReconnectTimeout);\n this.delayedReconnectTimeout = null;\n }\n }\n\n isDisconnected() {\n return this.ws === null;\n }\n\n async onWebsocketOpen() {\n // Create the Janus Session\n await this.session.create();\n\n // Attach the SFU Plugin and create a RTCPeerConnection for the publisher.\n // The publisher sends audio and opens two bidirectional data channels.\n // One reliable datachannel and one unreliable.\n this.publisher = await this.createPublisher();\n\n // Call the naf connectSuccess callback before we start receiving WebRTC messages.\n this.connectSuccess(this.clientId);\n\n for (let i = 0; i < this.publisher.initialOccupants.length; i++) {\n const occupantId = this.publisher.initialOccupants[i];\n if (occupantId === this.clientId) continue; // Happens during non-graceful reconnects due to zombie sessions\n this.addAvailableOccupant(occupantId);\n }\n\n this.syncOccupants();\n }\n\n onWebsocketClose(event) {\n // The connection was closed successfully. Don't try to reconnect.\n if (event.code === WS_NORMAL_CLOSURE) {\n return;\n }\n\n this.websocketConnectionPromise.reject(event);\n\n if (!this.isReconnecting) {\n this.isReconnecting = true;\n console.warn(\"Janus websocket closed unexpectedly.\");\n if (this.onReconnecting) {\n this.onReconnecting(this.reconnectionDelay);\n }\n\n this.reconnectionTimeout = setTimeout(() => this.reconnect(), this.reconnectionDelay);\n }\n }\n\n reconnect() {\n // Dispose of all networked entities and other resources tied to the session.\n this.disconnect();\n\n this.connect()\n .then(() => {\n this.reconnectionDelay = this.initialReconnectionDelay;\n this.reconnectionAttempts = 0;\n this.isReconnecting = false;\n\n if (this.onReconnected) {\n this.onReconnected();\n }\n })\n .catch(error => {\n this.reconnectionDelay += 1000;\n this.reconnectionAttempts++;\n\n if (this.reconnectionAttempts > this.maxReconnectionAttempts) {\n const error = new Error(\n \"Connection could not be reestablished, exceeded maximum number of reconnection attempts.\"\n );\n if (this.onReconnectionError) {\n return this.onReconnectionError(error);\n } else {\n console.warn(error);\n return;\n }\n }\n\n console.warn(\"Error during reconnect, retrying.\");\n console.warn(error);\n\n if (this.onReconnecting) {\n this.onReconnecting(this.reconnectionDelay);\n }\n\n this.reconnectionTimeout = setTimeout(() => this.reconnect(), this.reconnectionDelay);\n });\n }\n\n performDelayedReconnect() {\n if (this.delayedReconnectTimeout) {\n clearTimeout(this.delayedReconnectTimeout);\n }\n\n this.delayedReconnectTimeout = setTimeout(() => {\n this.delayedReconnectTimeout = null;\n this.reconnect();\n }, 10000);\n }\n\n onWebsocketMessage(event) {\n this.session.receive(JSON.parse(event.data));\n }\n\n addAvailableOccupant(occupantId) {\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n this.availableOccupants.push(occupantId);\n }\n }\n\n removeAvailableOccupant(occupantId) {\n const idx = this.availableOccupants.indexOf(occupantId);\n if (idx !== -1) {\n this.availableOccupants.splice(idx, 1);\n }\n }\n\n syncOccupants(requestedOccupants) {\n if (requestedOccupants) {\n this.requestedOccupants = requestedOccupants;\n }\n\n if (!this.requestedOccupants) {\n return;\n }\n\n // Add any requested, available, and non-pending occupants.\n for (let i = 0; i < this.requestedOccupants.length; i++) {\n const occupantId = this.requestedOccupants[i];\n if (!this.occupants[occupantId] && this.availableOccupants.indexOf(occupantId) !== -1 && !this.pendingOccupants.has(occupantId)) {\n this.addOccupant(occupantId);\n }\n }\n\n // Remove any unrequested and currently added occupants.\n for (let j = 0; j < this.availableOccupants.length; j++) {\n const occupantId = this.availableOccupants[j];\n if (this.occupants[occupantId] && this.requestedOccupants.indexOf(occupantId) === -1) {\n this.removeOccupant(occupantId);\n }\n }\n\n // Call the Networked AFrame callbacks for the updated occupants list.\n this.onOccupantsChanged(this.occupants);\n }\n\n async addOccupant(occupantId) {\n this.pendingOccupants.add(occupantId);\n \n const availableOccupantsCount = this.availableOccupants.length;\n if (availableOccupantsCount > AVAILABLE_OCCUPANTS_THRESHOLD) {\n await randomDelay(0, MAX_SUBSCRIBE_DELAY);\n }\n \n const subscriber = await this.createSubscriber(occupantId);\n if (subscriber) {\n if(!this.pendingOccupants.has(occupantId)) {\n subscriber.conn.close();\n } else {\n this.pendingOccupants.delete(occupantId);\n this.occupantIds.push(occupantId);\n this.occupants[occupantId] = subscriber;\n\n this.setMediaStream(occupantId, subscriber.mediaStream);\n\n // Call the Networked AFrame callbacks for the new occupant.\n this.onOccupantConnected(occupantId);\n }\n }\n }\n\n removeAllOccupants() {\n this.pendingOccupants.clear();\n for (let i = this.occupantIds.length - 1; i >= 0; i--) {\n this.removeOccupant(this.occupantIds[i]);\n }\n }\n\n removeOccupant(occupantId) {\n this.pendingOccupants.delete(occupantId);\n \n if (this.occupants[occupantId]) {\n // Close the subscriber peer connection. Which also detaches the plugin handle.\n this.occupants[occupantId].conn.close();\n delete this.occupants[occupantId];\n \n this.occupantIds.splice(this.occupantIds.indexOf(occupantId), 1);\n }\n\n if (this.mediaStreams[occupantId]) {\n delete this.mediaStreams[occupantId];\n }\n\n if (this.pendingMediaRequests.has(occupantId)) {\n const msg = \"The user disconnected before the media stream was resolved.\";\n this.pendingMediaRequests.get(occupantId).audio.reject(msg);\n this.pendingMediaRequests.get(occupantId).video.reject(msg);\n this.pendingMediaRequests.delete(occupantId);\n }\n\n // Call the Networked AFrame callbacks for the removed occupant.\n this.onOccupantDisconnected(occupantId);\n }\n\n associate(conn, handle) {\n conn.addEventListener(\"icecandidate\", ev => {\n handle.sendTrickle(ev.candidate || null).catch(e => error(\"Error trickling ICE: %o\", e));\n });\n conn.addEventListener(\"iceconnectionstatechange\", ev => {\n if (conn.iceConnectionState === \"connected\") {\n console.log(\"ICE state changed to connected\");\n }\n if (conn.iceConnectionState === \"disconnected\") {\n console.warn(\"ICE state changed to disconnected\");\n }\n if (conn.iceConnectionState === \"failed\") {\n console.warn(\"ICE failure detected. Reconnecting in 10s.\");\n this.performDelayedReconnect();\n }\n })\n\n // we have to debounce these because janus gets angry if you send it a new SDP before\n // it's finished processing an existing SDP. in actuality, it seems like this is maybe\n // too liberal and we need to wait some amount of time after an offer before sending another,\n // but we don't currently know any good way of detecting exactly how long :(\n conn.addEventListener(\n \"negotiationneeded\",\n debounce(ev => {\n debug(\"Sending new offer for handle: %o\", handle);\n var offer = conn.createOffer().then(this.configurePublisherSdp).then(this.fixSafariIceUFrag);\n var local = offer.then(o => conn.setLocalDescription(o));\n var remote = offer;\n\n remote = remote\n .then(this.fixSafariIceUFrag)\n .then(j => handle.sendJsep(j))\n .then(r => conn.setRemoteDescription(r.jsep));\n return Promise.all([local, remote]).catch(e => error(\"Error negotiating offer: %o\", e));\n })\n );\n handle.on(\n \"event\",\n debounce(ev => {\n var jsep = ev.jsep;\n if (jsep && jsep.type == \"offer\") {\n debug(\"Accepting new offer for handle: %o\", handle);\n var answer = conn\n .setRemoteDescription(this.configureSubscriberSdp(jsep))\n .then(_ => conn.createAnswer())\n .then(this.fixSafariIceUFrag);\n var local = answer.then(a => conn.setLocalDescription(a));\n var remote = answer.then(j => handle.sendJsep(j));\n return Promise.all([local, remote]).catch(e => error(\"Error negotiating answer: %o\", e));\n } else {\n // some other kind of event, nothing to do\n return null;\n }\n })\n );\n }\n\n async createPublisher() {\n var handle = new mj.JanusPluginHandle(this.session);\n var conn = new RTCPeerConnection(this.peerConnectionConfig || DEFAULT_PEER_CONNECTION_CONFIG);\n\n debug(\"pub waiting for sfu\");\n await handle.attach(\"janus.plugin.sfu\", this.loops && this.clientId ? parseInt(this.clientId) % this.loops : undefined);\n\n this.associate(conn, handle);\n\n debug(\"pub waiting for data channels & webrtcup\");\n var webrtcup = new Promise(resolve => handle.on(\"webrtcup\", resolve));\n\n // Unreliable datachannel: sending and receiving component updates.\n // Reliable datachannel: sending and recieving entity instantiations.\n var reliableChannel = conn.createDataChannel(\"reliable\", { ordered: true });\n var unreliableChannel = conn.createDataChannel(\"unreliable\", {\n ordered: false,\n maxRetransmits: 0\n });\n\n reliableChannel.addEventListener(\"message\", e => this.onDataChannelMessage(e, \"janus-reliable\"));\n unreliableChannel.addEventListener(\"message\", e => this.onDataChannelMessage(e, \"janus-unreliable\"));\n\n await webrtcup;\n await untilDataChannelOpen(reliableChannel);\n await untilDataChannelOpen(unreliableChannel);\n\n // doing this here is sort of a hack around chrome renegotiation weirdness --\n // if we do it prior to webrtcup, chrome on gear VR will sometimes put a\n // renegotiation offer in flight while the first offer was still being\n // processed by janus. we should find some more principled way to figure out\n // when janus is done in the future.\n if (this.localMediaStream) {\n this.localMediaStream.getTracks().forEach(track => {\n conn.addTrack(track, this.localMediaStream);\n });\n }\n\n // Handle all of the join and leave events.\n handle.on(\"event\", ev => {\n var data = ev.plugindata.data;\n if (data.event == \"join\" && data.room_id == this.room) {\n if (this.delayedReconnectTimeout) {\n // Don't create a new RTCPeerConnection, all RTCPeerConnection will be closed in less than 10s.\n return;\n }\n this.addAvailableOccupant(data.user_id);\n this.syncOccupants();\n } else if (data.event == \"leave\" && data.room_id == this.room) {\n this.removeAvailableOccupant(data.user_id);\n this.removeOccupant(data.user_id);\n } else if (data.event == \"blocked\") {\n document.body.dispatchEvent(new CustomEvent(\"blocked\", { detail: { clientId: data.by } }));\n } else if (data.event == \"unblocked\") {\n document.body.dispatchEvent(new CustomEvent(\"unblocked\", { detail: { clientId: data.by } }));\n } else if (data.event === \"data\") {\n this.onData(JSON.parse(data.body), \"janus-event\");\n }\n });\n\n debug(\"pub waiting for join\");\n\n // Send join message to janus. Listen for join/leave messages. Automatically subscribe to all users' WebRTC data.\n var message = await this.sendJoin(handle, {\n notifications: true,\n data: true\n });\n\n if (!message.plugindata.data.success) {\n const err = message.plugindata.data.error;\n console.error(err);\n // We may get here because of an expired JWT.\n // Close the connection ourself otherwise janus will close it after\n // session_timeout because we didn't send any keepalive and this will\n // trigger a delayed reconnect because of the iceconnectionstatechange\n // listener for failure state.\n // Even if the app code calls disconnect in case of error, disconnect\n // won't close the peer connection because this.publisher is not set.\n conn.close();\n throw err;\n }\n\n var initialOccupants = message.plugindata.data.response.users[this.room] || [];\n\n if (initialOccupants.includes(this.clientId)) {\n console.warn(\"Janus still has previous session for this client. Reconnecting in 10s.\");\n this.performDelayedReconnect();\n }\n\n debug(\"publisher ready\");\n return {\n handle,\n initialOccupants,\n reliableChannel,\n unreliableChannel,\n conn\n };\n }\n\n configurePublisherSdp(jsep) {\n jsep.sdp = jsep.sdp.replace(/a=fmtp:(109|111).*\\r\\n/g, (line, pt) => {\n const parameters = Object.assign(sdpUtils.parseFmtp(line), OPUS_PARAMETERS);\n return sdpUtils.writeFmtp({ payloadType: pt, parameters: parameters });\n });\n return jsep;\n }\n\n configureSubscriberSdp(jsep) {\n // todo: consider cleaning up these hacks to use sdputils\n if (!isH264VideoSupported) {\n if (navigator.userAgent.indexOf(\"HeadlessChrome\") !== -1) {\n // HeadlessChrome (e.g. puppeteer) doesn't support webrtc video streams, so we remove those lines from the SDP.\n jsep.sdp = jsep.sdp.replace(/m=video[^]*m=/, \"m=\");\n }\n }\n\n // TODO: Hack to get video working on Chrome for Android. https://groups.google.com/forum/#!topic/mozilla.dev.media/Ye29vuMTpo8\n if (navigator.userAgent.indexOf(\"Android\") === -1) {\n jsep.sdp = jsep.sdp.replace(\n \"a=rtcp-fb:107 goog-remb\\r\\n\",\n \"a=rtcp-fb:107 goog-remb\\r\\na=rtcp-fb:107 transport-cc\\r\\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\\r\\n\"\n );\n } else {\n jsep.sdp = jsep.sdp.replace(\n \"a=rtcp-fb:107 goog-remb\\r\\n\",\n \"a=rtcp-fb:107 goog-remb\\r\\na=rtcp-fb:107 transport-cc\\r\\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\\r\\n\"\n );\n }\n return jsep;\n }\n\n async fixSafariIceUFrag(jsep) {\n // Safari produces a \\n instead of an \\r\\n for the ice-ufrag. See https://github.com/meetecho/janus-gateway/issues/1818\n jsep.sdp = jsep.sdp.replace(/[^\\r]\\na=ice-ufrag/g, \"\\r\\na=ice-ufrag\");\n return jsep\n }\n\n async createSubscriber(occupantId, maxRetries = 5) {\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n console.warn(occupantId + \": cancelled occupant connection, occupant left before subscription negotation.\");\n return null;\n }\n\n var handle = new mj.JanusPluginHandle(this.session);\n var conn = new RTCPeerConnection(this.peerConnectionConfig || DEFAULT_PEER_CONNECTION_CONFIG);\n\n debug(occupantId + \": sub waiting for sfu\");\n await handle.attach(\"janus.plugin.sfu\", this.loops ? parseInt(occupantId) % this.loops : undefined);\n\n this.associate(conn, handle);\n\n debug(occupantId + \": sub waiting for join\");\n\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n conn.close();\n console.warn(occupantId + \": cancelled occupant connection, occupant left after attach\");\n return null;\n }\n\n let webrtcFailed = false;\n\n const webrtcup = new Promise(resolve => {\n const leftInterval = setInterval(() => {\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n clearInterval(leftInterval);\n resolve();\n }\n }, 1000);\n\n const timeout = setTimeout(() => {\n clearInterval(leftInterval);\n webrtcFailed = true;\n resolve();\n }, SUBSCRIBE_TIMEOUT_MS);\n\n handle.on(\"webrtcup\", () => {\n clearTimeout(timeout);\n clearInterval(leftInterval);\n resolve();\n });\n });\n\n // Send join message to janus. Don't listen for join/leave messages. Subscribe to the occupant's media.\n // Janus should send us an offer for this occupant's media in response to this.\n await this.sendJoin(handle, { media: occupantId });\n\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n conn.close();\n console.warn(occupantId + \": cancelled occupant connection, occupant left after join\");\n return null;\n }\n\n debug(occupantId + \": sub waiting for webrtcup\");\n await webrtcup;\n\n if (this.availableOccupants.indexOf(occupantId) === -1) {\n conn.close();\n console.warn(occupantId + \": cancel occupant connection, occupant left during or after webrtcup\");\n return null;\n }\n\n if (webrtcFailed) {\n conn.close();\n if (maxRetries > 0) {\n console.warn(occupantId + \": webrtc up timed out, retrying\");\n return this.createSubscriber(occupantId, maxRetries - 1);\n } else {\n console.warn(occupantId + \": webrtc up timed out\");\n return null;\n }\n }\n\n if (isSafari && !this._iOSHackDelayedInitialPeer) {\n // HACK: the first peer on Safari during page load can fail to work if we don't\n // wait some time before continuing here. See: https://github.com/mozilla/hubs/pull/1692\n await (new Promise((resolve) => setTimeout(resolve, 3000)));\n this._iOSHackDelayedInitialPeer = true;\n }\n\n var mediaStream = new MediaStream();\n var receivers = conn.getReceivers();\n receivers.forEach(receiver => {\n if (receiver.track) {\n mediaStream.addTrack(receiver.track);\n }\n });\n if (mediaStream.getTracks().length === 0) {\n mediaStream = null;\n }\n\n debug(occupantId + \": subscriber ready\");\n return {\n handle,\n mediaStream,\n conn\n };\n }\n\n sendJoin(handle, subscribe) {\n return handle.sendMessage({\n kind: \"join\",\n room_id: this.room,\n user_id: this.clientId,\n subscribe,\n token: this.joinToken\n });\n }\n\n toggleFreeze() {\n if (this.frozen) {\n this.unfreeze();\n } else {\n this.freeze();\n }\n }\n\n freeze() {\n this.frozen = true;\n }\n\n unfreeze() {\n this.frozen = false;\n this.flushPendingUpdates();\n }\n\n dataForUpdateMultiMessage(networkId, message) {\n // \"d\" is an array of entity datas, where each item in the array represents a unique entity and contains\n // metadata for the entity, and an array of components that have been updated on the entity.\n // This method finds the data corresponding to the given networkId.\n for (let i = 0, l = message.data.d.length; i < l; i++) {\n const data = message.data.d[i];\n\n if (data.networkId === networkId) {\n return data;\n }\n }\n\n return null;\n }\n\n getPendingData(networkId, message) {\n if (!message) return null;\n\n let data = message.dataType === \"um\" ? this.dataForUpdateMultiMessage(networkId, message) : message.data;\n\n // Ignore messages relating to users who have disconnected since freezing, their entities\n // will have aleady been removed by NAF.\n // Note that delete messages have no \"owner\" so we have to check for that as well.\n if (data.owner && !this.occupants[data.owner]) return null;\n\n // Ignore messages from users that we may have blocked while frozen.\n if (data.owner && this.blockedClients.has(data.owner)) return null;\n\n return data\n }\n\n // Used externally\n getPendingDataForNetworkId(networkId) {\n return this.getPendingData(networkId, this.frozenUpdates.get(networkId));\n }\n\n flushPendingUpdates() {\n for (const [networkId, message] of this.frozenUpdates) {\n let data = this.getPendingData(networkId, message);\n if (!data) continue;\n\n // Override the data type on \"um\" messages types, since we extract entity updates from \"um\" messages into\n // individual frozenUpdates in storeSingleMessage.\n const dataType = message.dataType === \"um\" ? \"u\" : message.dataType;\n\n this.onOccupantMessage(null, dataType, data, message.source);\n }\n this.frozenUpdates.clear();\n }\n\n storeMessage(message) {\n if (message.dataType === \"um\") { // UpdateMulti\n for (let i = 0, l = message.data.d.length; i < l; i++) {\n this.storeSingleMessage(message, i);\n }\n } else {\n this.storeSingleMessage(message);\n }\n }\n\n storeSingleMessage(message, index) {\n const data = index !== undefined ? message.data.d[index] : message.data;\n const dataType = message.dataType;\n const source = message.source;\n\n const networkId = data.networkId;\n\n if (!this.frozenUpdates.has(networkId)) {\n this.frozenUpdates.set(networkId, message);\n } else {\n const storedMessage = this.frozenUpdates.get(networkId);\n const storedData = storedMessage.dataType === \"um\" ? this.dataForUpdateMultiMessage(networkId, storedMessage) : storedMessage.data;\n\n // Avoid updating components if the entity data received did not come from the current owner.\n const isOutdatedMessage = data.lastOwnerTime < storedData.lastOwnerTime;\n const isContemporaneousMessage = data.lastOwnerTime === storedData.lastOwnerTime;\n if (isOutdatedMessage || (isContemporaneousMessage && storedData.owner > data.owner)) {\n return;\n }\n\n if (dataType === \"r\") {\n const createdWhileFrozen = storedData && storedData.isFirstSync;\n if (createdWhileFrozen) {\n // If the entity was created and deleted while frozen, don't bother conveying anything to the consumer.\n this.frozenUpdates.delete(networkId);\n } else {\n // Delete messages override any other messages for this entity\n this.frozenUpdates.set(networkId, message);\n }\n } else {\n // merge in component updates\n if (storedData.components && data.components) {\n Object.assign(storedData.components, data.components);\n }\n }\n }\n }\n\n onDataChannelMessage(e, source) {\n this.onData(JSON.parse(e.data), source);\n }\n\n onData(message, source) {\n if (debug.enabled) {\n debug(`DC in: ${message}`);\n }\n\n if (!message.dataType) return;\n\n message.source = source;\n\n if (this.frozen) {\n this.storeMessage(message);\n } else {\n this.onOccupantMessage(null, message.dataType, message.data, message.source);\n }\n }\n\n shouldStartConnectionTo(client) {\n return true;\n }\n\n startStreamConnection(client) {}\n\n closeStreamConnection(client) {}\n\n getConnectStatus(clientId) {\n return this.occupants[clientId] ? NAF.adapters.IS_CONNECTED : NAF.adapters.NOT_CONNECTED;\n }\n\n async updateTimeOffset() {\n if (this.isDisconnected()) return;\n\n const clientSentTime = Date.now();\n\n const res = await fetch(document.location.href, {\n method: \"HEAD\",\n cache: \"no-cache\"\n });\n\n const precision = 1000;\n const serverReceivedTime = new Date(res.headers.get(\"Date\")).getTime() + precision / 2;\n const clientReceivedTime = Date.now();\n const serverTime = serverReceivedTime + (clientReceivedTime - clientSentTime) / 2;\n const timeOffset = serverTime - clientReceivedTime;\n\n this.serverTimeRequests++;\n\n if (this.serverTimeRequests <= 10) {\n this.timeOffsets.push(timeOffset);\n } else {\n this.timeOffsets[this.serverTimeRequests % 10] = timeOffset;\n }\n\n this.avgTimeOffset = this.timeOffsets.reduce((acc, offset) => (acc += offset), 0) / this.timeOffsets.length;\n\n if (this.serverTimeRequests > 10) {\n debug(`new server time offset: ${this.avgTimeOffset}ms`);\n setTimeout(() => this.updateTimeOffset(), 5 * 60 * 1000); // Sync clock every 5 minutes.\n } else {\n this.updateTimeOffset();\n }\n }\n\n getServerTime() {\n return Date.now() + this.avgTimeOffset;\n }\n\n getMediaStream(clientId, type = \"audio\") {\n if (this.mediaStreams[clientId]) {\n debug(`Already had ${type} for ${clientId}`);\n return Promise.resolve(this.mediaStreams[clientId][type]);\n } else {\n debug(`Waiting on ${type} for ${clientId}`);\n if (!this.pendingMediaRequests.has(clientId)) {\n this.pendingMediaRequests.set(clientId, {});\n\n const audioPromise = new Promise((resolve, reject) => {\n this.pendingMediaRequests.get(clientId).audio = { resolve, reject };\n });\n const videoPromise = new Promise((resolve, reject) => {\n this.pendingMediaRequests.get(clientId).video = { resolve, reject };\n });\n\n this.pendingMediaRequests.get(clientId).audio.promise = audioPromise;\n this.pendingMediaRequests.get(clientId).video.promise = videoPromise;\n\n audioPromise.catch(e => console.warn(`${clientId} getMediaStream Audio Error`, e));\n videoPromise.catch(e => console.warn(`${clientId} getMediaStream Video Error`, e));\n }\n return this.pendingMediaRequests.get(clientId)[type].promise;\n }\n }\n\n setMediaStream(clientId, stream) {\n // Safari doesn't like it when you use single a mixed media stream where one of the tracks is inactive, so we\n // split the tracks into two streams.\n const audioStream = new MediaStream();\n try {\n stream.getAudioTracks().forEach(track => audioStream.addTrack(track));\n\n } catch(e) {\n console.warn(`${clientId} setMediaStream Audio Error`, e);\n }\n const videoStream = new MediaStream();\n try {\n stream.getVideoTracks().forEach(track => videoStream.addTrack(track));\n\n } catch (e) {\n console.warn(`${clientId} setMediaStream Video Error`, e);\n }\n\n this.mediaStreams[clientId] = { audio: audioStream, video: videoStream };\n\n // Resolve the promise for the user's media stream if it exists.\n if (this.pendingMediaRequests.has(clientId)) {\n this.pendingMediaRequests.get(clientId).audio.resolve(audioStream);\n this.pendingMediaRequests.get(clientId).video.resolve(videoStream);\n }\n }\n\n getLocalMediaStream() {\n return this.localMediaStream;\n }\n\n async setLocalMediaStream(stream) {\n // our job here is to make sure the connection winds up with RTP senders sending the stuff in this stream,\n // and not the stuff that isn't in this stream. strategy is to replace existing tracks if we can, add tracks\n // that we can't replace, and disable tracks that don't exist anymore.\n\n // note that we don't ever remove a track from the stream -- since Janus doesn't support Unified Plan, we absolutely\n // can't wind up with a SDP that has >1 audio or >1 video tracks, even if one of them is inactive (what you get if\n // you remove a track from an existing stream.)\n if (this.publisher && this.publisher.conn) {\n const existingSenders = this.publisher.conn.getSenders();\n const newSenders = [];\n const tracks = stream.getTracks();\n\n for (let i = 0; i < tracks.length; i++) {\n const t = tracks[i];\n const sender = existingSenders.find(s => s.track != null && s.track.kind == t.kind);\n\n if (sender != null) {\n if (sender.replaceTrack) {\n await sender.replaceTrack(t);\n } else {\n // Fallback for browsers that don't support replaceTrack. At this time of this writing\n // most browsers support it, and testing this code path seems to not work properly\n // in Chrome anymore.\n stream.removeTrack(sender.track);\n stream.addTrack(t);\n }\n newSenders.push(sender);\n } else {\n newSenders.push(this.publisher.conn.addTrack(t, stream));\n }\n }\n existingSenders.forEach(s => {\n if (!newSenders.includes(s)) {\n s.track.enabled = false;\n }\n });\n }\n this.localMediaStream = stream;\n this.setMediaStream(this.clientId, stream);\n }\n\n enableMicrophone(enabled) {\n if (this.publisher && this.publisher.conn) {\n this.publisher.conn.getSenders().forEach(s => {\n if (s.track.kind == \"audio\") {\n s.track.enabled = enabled;\n }\n });\n }\n }\n\n sendData(clientId, dataType, data) {\n if (!this.publisher) {\n console.warn(\"sendData called without a publisher\");\n } else {\n switch (this.unreliableTransport) {\n case \"websocket\":\n if (this.ws.readyState === 1) { // OPEN\n this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }), whom: clientId });\n }\n break;\n case \"datachannel\":\n if (this.publisher.unreliableChannel.readyState === \"open\") {\n this.publisher.unreliableChannel.send(JSON.stringify({ clientId, dataType, data }));\n }\n break;\n default:\n this.unreliableTransport(clientId, dataType, data);\n break;\n }\n }\n }\n\n sendDataGuaranteed(clientId, dataType, data) {\n if (!this.publisher) {\n console.warn(\"sendDataGuaranteed called without a publisher\");\n } else {\n switch (this.reliableTransport) {\n case \"websocket\":\n if (this.ws.readyState === 1) { // OPEN\n this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }), whom: clientId });\n }\n break;\n case \"datachannel\":\n if (this.publisher.reliableChannel.readyState === \"open\") {\n this.publisher.reliableChannel.send(JSON.stringify({ clientId, dataType, data }));\n }\n break;\n default:\n this.reliableTransport(clientId, dataType, data);\n break;\n }\n }\n }\n\n broadcastData(dataType, data) {\n if (!this.publisher) {\n console.warn(\"broadcastData called without a publisher\");\n } else {\n switch (this.unreliableTransport) {\n case \"websocket\":\n if (this.ws.readyState === 1) { // OPEN\n this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }) });\n }\n break;\n case \"datachannel\":\n if (this.publisher.unreliableChannel.readyState === \"open\") {\n this.publisher.unreliableChannel.send(JSON.stringify({ dataType, data }));\n }\n break;\n default:\n this.unreliableTransport(undefined, dataType, data);\n break;\n }\n }\n }\n\n broadcastDataGuaranteed(dataType, data) {\n if (!this.publisher) {\n console.warn(\"broadcastDataGuaranteed called without a publisher\");\n } else {\n switch (this.reliableTransport) {\n case \"websocket\":\n if (this.ws.readyState === 1) { // OPEN\n this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }) });\n }\n break;\n case \"datachannel\":\n if (this.publisher.reliableChannel.readyState === \"open\") {\n this.publisher.reliableChannel.send(JSON.stringify({ dataType, data }));\n }\n break;\n default:\n this.reliableTransport(undefined, dataType, data);\n break;\n }\n }\n }\n\n kick(clientId, permsToken) {\n return this.publisher.handle.sendMessage({ kind: \"kick\", room_id: this.room, user_id: clientId, token: permsToken }).then(() => {\n document.body.dispatchEvent(new CustomEvent(\"kicked\", { detail: { clientId: clientId } }));\n });\n }\n\n block(clientId) {\n return this.publisher.handle.sendMessage({ kind: \"block\", whom: clientId }).then(() => {\n this.blockedClients.set(clientId, true);\n document.body.dispatchEvent(new CustomEvent(\"blocked\", { detail: { clientId: clientId } }));\n });\n }\n\n unblock(clientId) {\n return this.publisher.handle.sendMessage({ kind: \"unblock\", whom: clientId }).then(() => {\n this.blockedClients.delete(clientId);\n document.body.dispatchEvent(new CustomEvent(\"unblocked\", { detail: { clientId: clientId } }));\n });\n }\n}\n\nNAF.adapters.register(\"janus\", JanusAdapter);\n\nmodule.exports = JanusAdapter;\n","/* eslint-env browser */\n\n/**\n * This is the web browser implementation of `debug()`.\n */\n\nexports.formatArgs = formatArgs;\nexports.save = save;\nexports.load = load;\nexports.useColors = useColors;\nexports.storage = localstorage();\nexports.destroy = (() => {\n\tlet warned = false;\n\n\treturn () => {\n\t\tif (!warned) {\n\t\t\twarned = true;\n\t\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t\t}\n\t};\n})();\n\n/**\n * Colors.\n */\n\nexports.colors = [\n\t'#0000CC',\n\t'#0000FF',\n\t'#0033CC',\n\t'#0033FF',\n\t'#0066CC',\n\t'#0066FF',\n\t'#0099CC',\n\t'#0099FF',\n\t'#00CC00',\n\t'#00CC33',\n\t'#00CC66',\n\t'#00CC99',\n\t'#00CCCC',\n\t'#00CCFF',\n\t'#3300CC',\n\t'#3300FF',\n\t'#3333CC',\n\t'#3333FF',\n\t'#3366CC',\n\t'#3366FF',\n\t'#3399CC',\n\t'#3399FF',\n\t'#33CC00',\n\t'#33CC33',\n\t'#33CC66',\n\t'#33CC99',\n\t'#33CCCC',\n\t'#33CCFF',\n\t'#6600CC',\n\t'#6600FF',\n\t'#6633CC',\n\t'#6633FF',\n\t'#66CC00',\n\t'#66CC33',\n\t'#9900CC',\n\t'#9900FF',\n\t'#9933CC',\n\t'#9933FF',\n\t'#99CC00',\n\t'#99CC33',\n\t'#CC0000',\n\t'#CC0033',\n\t'#CC0066',\n\t'#CC0099',\n\t'#CC00CC',\n\t'#CC00FF',\n\t'#CC3300',\n\t'#CC3333',\n\t'#CC3366',\n\t'#CC3399',\n\t'#CC33CC',\n\t'#CC33FF',\n\t'#CC6600',\n\t'#CC6633',\n\t'#CC9900',\n\t'#CC9933',\n\t'#CCCC00',\n\t'#CCCC33',\n\t'#FF0000',\n\t'#FF0033',\n\t'#FF0066',\n\t'#FF0099',\n\t'#FF00CC',\n\t'#FF00FF',\n\t'#FF3300',\n\t'#FF3333',\n\t'#FF3366',\n\t'#FF3399',\n\t'#FF33CC',\n\t'#FF33FF',\n\t'#FF6600',\n\t'#FF6633',\n\t'#FF9900',\n\t'#FF9933',\n\t'#FFCC00',\n\t'#FFCC33'\n];\n\n/**\n * Currently only WebKit-based Web Inspectors, Firefox >= v31,\n * and the Firebug extension (any Firefox version) are known\n * to support \"%c\" CSS customizations.\n *\n * TODO: add a `localStorage` variable to explicitly enable/disable colors\n */\n\n// eslint-disable-next-line complexity\nfunction useColors() {\n\t// NB: In an Electron preload script, document will be defined but not fully\n\t// initialized. Since we know we're in Chrome, we'll just detect this case\n\t// explicitly\n\tif (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {\n\t\treturn true;\n\t}\n\n\t// Internet Explorer and Edge do not support colors.\n\tif (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\\/(\\d+)/)) {\n\t\treturn false;\n\t}\n\n\tlet m;\n\n\t// Is webkit? http://stackoverflow.com/a/16459606/376773\n\t// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632\n\t// eslint-disable-next-line no-return-assign\n\treturn (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||\n\t\t// Is firebug? http://stackoverflow.com/a/398120/376773\n\t\t(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||\n\t\t// Is firefox >= v31?\n\t\t// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/)) && parseInt(m[1], 10) >= 31) ||\n\t\t// Double check webkit in userAgent just in case we are in a worker\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/));\n}\n\n/**\n * Colorize log arguments if enabled.\n *\n * @api public\n */\n\nfunction formatArgs(args) {\n\targs[0] = (this.useColors ? '%c' : '') +\n\t\tthis.namespace +\n\t\t(this.useColors ? ' %c' : ' ') +\n\t\targs[0] +\n\t\t(this.useColors ? '%c ' : ' ') +\n\t\t'+' + module.exports.humanize(this.diff);\n\n\tif (!this.useColors) {\n\t\treturn;\n\t}\n\n\tconst c = 'color: ' + this.color;\n\targs.splice(1, 0, c, 'color: inherit');\n\n\t// The final \"%c\" is somewhat tricky, because there could be other\n\t// arguments passed either before or after the %c, so we need to\n\t// figure out the correct index to insert the CSS into\n\tlet index = 0;\n\tlet lastC = 0;\n\targs[0].replace(/%[a-zA-Z%]/g, match => {\n\t\tif (match === '%%') {\n\t\t\treturn;\n\t\t}\n\t\tindex++;\n\t\tif (match === '%c') {\n\t\t\t// We only are interested in the *last* %c\n\t\t\t// (the user may have provided their own)\n\t\t\tlastC = index;\n\t\t}\n\t});\n\n\targs.splice(lastC, 0, c);\n}\n\n/**\n * Invokes `console.debug()` when available.\n * No-op when `console.debug` is not a \"function\".\n * If `console.debug` is not available, falls back\n * to `console.log`.\n *\n * @api public\n */\nexports.log = console.debug || console.log || (() => {});\n\n/**\n * Save `namespaces`.\n *\n * @param {String} namespaces\n * @api private\n */\nfunction save(namespaces) {\n\ttry {\n\t\tif (namespaces) {\n\t\t\texports.storage.setItem('debug', namespaces);\n\t\t} else {\n\t\t\texports.storage.removeItem('debug');\n\t\t}\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\n/**\n * Load `namespaces`.\n *\n * @return {String} returns the previously persisted debug modes\n * @api private\n */\nfunction load() {\n\tlet r;\n\ttry {\n\t\tr = exports.storage.getItem('debug');\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n\n\t// If debug isn't set in LS, and we're in Electron, try to load $DEBUG\n\tif (!r && typeof process !== 'undefined' && 'env' in process) {\n\t\tr = process.env.DEBUG;\n\t}\n\n\treturn r;\n}\n\n/**\n * Localstorage attempts to return the localstorage.\n *\n * This is necessary because safari throws\n * when a user disables cookies/localstorage\n * and you attempt to access it.\n *\n * @return {LocalStorage}\n * @api private\n */\n\nfunction localstorage() {\n\ttry {\n\t\t// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context\n\t\t// The Browser also has localStorage in the global context.\n\t\treturn localStorage;\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\nmodule.exports = require('./common')(exports);\n\nconst {formatters} = module.exports;\n\n/**\n * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.\n */\n\nformatters.j = function (v) {\n\ttry {\n\t\treturn JSON.stringify(v);\n\t} catch (error) {\n\t\treturn '[UnexpectedJSONParseError]: ' + error.message;\n\t}\n};\n","\n/**\n * This is the common logic for both the Node.js and web browser\n * implementations of `debug()`.\n */\n\nfunction setup(env) {\n\tcreateDebug.debug = createDebug;\n\tcreateDebug.default = createDebug;\n\tcreateDebug.coerce = coerce;\n\tcreateDebug.disable = disable;\n\tcreateDebug.enable = enable;\n\tcreateDebug.enabled = enabled;\n\tcreateDebug.humanize = require('ms');\n\tcreateDebug.destroy = destroy;\n\n\tObject.keys(env).forEach(key => {\n\t\tcreateDebug[key] = env[key];\n\t});\n\n\t/**\n\t* The currently active debug mode names, and names to skip.\n\t*/\n\n\tcreateDebug.names = [];\n\tcreateDebug.skips = [];\n\n\t/**\n\t* Map of special \"%n\" handling functions, for the debug \"format\" argument.\n\t*\n\t* Valid key names are a single, lower or upper-case letter, i.e. \"n\" and \"N\".\n\t*/\n\tcreateDebug.formatters = {};\n\n\t/**\n\t* Selects a color for a debug namespace\n\t* @param {String} namespace The namespace string for the debug instance to be colored\n\t* @return {Number|String} An ANSI color code for the given namespace\n\t* @api private\n\t*/\n\tfunction selectColor(namespace) {\n\t\tlet hash = 0;\n\n\t\tfor (let i = 0; i < namespace.length; i++) {\n\t\t\thash = ((hash << 5) - hash) + namespace.charCodeAt(i);\n\t\t\thash |= 0; // Convert to 32bit integer\n\t\t}\n\n\t\treturn createDebug.colors[Math.abs(hash) % createDebug.colors.length];\n\t}\n\tcreateDebug.selectColor = selectColor;\n\n\t/**\n\t* Create a debugger with the given `namespace`.\n\t*\n\t* @param {String} namespace\n\t* @return {Function}\n\t* @api public\n\t*/\n\tfunction createDebug(namespace) {\n\t\tlet prevTime;\n\t\tlet enableOverride = null;\n\t\tlet namespacesCache;\n\t\tlet enabledCache;\n\n\t\tfunction debug(...args) {\n\t\t\t// Disabled?\n\t\t\tif (!debug.enabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst self = debug;\n\n\t\t\t// Set `diff` timestamp\n\t\t\tconst curr = Number(new Date());\n\t\t\tconst ms = curr - (prevTime || curr);\n\t\t\tself.diff = ms;\n\t\t\tself.prev = prevTime;\n\t\t\tself.curr = curr;\n\t\t\tprevTime = curr;\n\n\t\t\targs[0] = createDebug.coerce(args[0]);\n\n\t\t\tif (typeof args[0] !== 'string') {\n\t\t\t\t// Anything else let's inspect with %O\n\t\t\t\targs.unshift('%O');\n\t\t\t}\n\n\t\t\t// Apply any `formatters` transformations\n\t\t\tlet index = 0;\n\t\t\targs[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {\n\t\t\t\t// If we encounter an escaped % then don't increase the array index\n\t\t\t\tif (match === '%%') {\n\t\t\t\t\treturn '%';\n\t\t\t\t}\n\t\t\t\tindex++;\n\t\t\t\tconst formatter = createDebug.formatters[format];\n\t\t\t\tif (typeof formatter === 'function') {\n\t\t\t\t\tconst val = args[index];\n\t\t\t\t\tmatch = formatter.call(self, val);\n\n\t\t\t\t\t// Now we need to remove `args[index]` since it's inlined in the `format`\n\t\t\t\t\targs.splice(index, 1);\n\t\t\t\t\tindex--;\n\t\t\t\t}\n\t\t\t\treturn match;\n\t\t\t});\n\n\t\t\t// Apply env-specific formatting (colors, etc.)\n\t\t\tcreateDebug.formatArgs.call(self, args);\n\n\t\t\tconst logFn = self.log || createDebug.log;\n\t\t\tlogFn.apply(self, args);\n\t\t}\n\n\t\tdebug.namespace = namespace;\n\t\tdebug.useColors = createDebug.useColors();\n\t\tdebug.color = createDebug.selectColor(namespace);\n\t\tdebug.extend = extend;\n\t\tdebug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.\n\n\t\tObject.defineProperty(debug, 'enabled', {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: false,\n\t\t\tget: () => {\n\t\t\t\tif (enableOverride !== null) {\n\t\t\t\t\treturn enableOverride;\n\t\t\t\t}\n\t\t\t\tif (namespacesCache !== createDebug.namespaces) {\n\t\t\t\t\tnamespacesCache = createDebug.namespaces;\n\t\t\t\t\tenabledCache = createDebug.enabled(namespace);\n\t\t\t\t}\n\n\t\t\t\treturn enabledCache;\n\t\t\t},\n\t\t\tset: v => {\n\t\t\t\tenableOverride = v;\n\t\t\t}\n\t\t});\n\n\t\t// Env-specific initialization logic for debug instances\n\t\tif (typeof createDebug.init === 'function') {\n\t\t\tcreateDebug.init(debug);\n\t\t}\n\n\t\treturn debug;\n\t}\n\n\tfunction extend(namespace, delimiter) {\n\t\tconst newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);\n\t\tnewDebug.log = this.log;\n\t\treturn newDebug;\n\t}\n\n\t/**\n\t* Enables a debug mode by namespaces. This can include modes\n\t* separated by a colon and wildcards.\n\t*\n\t* @param {String} namespaces\n\t* @api public\n\t*/\n\tfunction enable(namespaces) {\n\t\tcreateDebug.save(namespaces);\n\t\tcreateDebug.namespaces = namespaces;\n\n\t\tcreateDebug.names = [];\n\t\tcreateDebug.skips = [];\n\n\t\tconst split = (typeof namespaces === 'string' ? namespaces : '')\n\t\t\t.trim()\n\t\t\t.replace(' ', ',')\n\t\t\t.split(',')\n\t\t\t.filter(Boolean);\n\n\t\tfor (const ns of split) {\n\t\t\tif (ns[0] === '-') {\n\t\t\t\tcreateDebug.skips.push(ns.slice(1));\n\t\t\t} else {\n\t\t\t\tcreateDebug.names.push(ns);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if the given string matches a namespace template, honoring\n\t * asterisks as wildcards.\n\t *\n\t * @param {String} search\n\t * @param {String} template\n\t * @return {Boolean}\n\t */\n\tfunction matchesTemplate(search, template) {\n\t\tlet searchIndex = 0;\n\t\tlet templateIndex = 0;\n\t\tlet starIndex = -1;\n\t\tlet matchIndex = 0;\n\n\t\twhile (searchIndex < search.length) {\n\t\t\tif (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) {\n\t\t\t\t// Match character or proceed with wildcard\n\t\t\t\tif (template[templateIndex] === '*') {\n\t\t\t\t\tstarIndex = templateIndex;\n\t\t\t\t\tmatchIndex = searchIndex;\n\t\t\t\t\ttemplateIndex++; // Skip the '*'\n\t\t\t\t} else {\n\t\t\t\t\tsearchIndex++;\n\t\t\t\t\ttemplateIndex++;\n\t\t\t\t}\n\t\t\t} else if (starIndex !== -1) { // eslint-disable-line no-negated-condition\n\t\t\t\t// Backtrack to the last '*' and try to match more characters\n\t\t\t\ttemplateIndex = starIndex + 1;\n\t\t\t\tmatchIndex++;\n\t\t\t\tsearchIndex = matchIndex;\n\t\t\t} else {\n\t\t\t\treturn false; // No match\n\t\t\t}\n\t\t}\n\n\t\t// Handle trailing '*' in template\n\t\twhile (templateIndex < template.length && template[templateIndex] === '*') {\n\t\t\ttemplateIndex++;\n\t\t}\n\n\t\treturn templateIndex === template.length;\n\t}\n\n\t/**\n\t* Disable debug output.\n\t*\n\t* @return {String} namespaces\n\t* @api public\n\t*/\n\tfunction disable() {\n\t\tconst namespaces = [\n\t\t\t...createDebug.names,\n\t\t\t...createDebug.skips.map(namespace => '-' + namespace)\n\t\t].join(',');\n\t\tcreateDebug.enable('');\n\t\treturn namespaces;\n\t}\n\n\t/**\n\t* Returns true if the given mode name is enabled, false otherwise.\n\t*\n\t* @param {String} name\n\t* @return {Boolean}\n\t* @api public\n\t*/\n\tfunction enabled(name) {\n\t\tfor (const skip of createDebug.skips) {\n\t\t\tif (matchesTemplate(name, skip)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tfor (const ns of createDebug.names) {\n\t\t\tif (matchesTemplate(name, ns)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t* Coerce `val`.\n\t*\n\t* @param {Mixed} val\n\t* @return {Mixed}\n\t* @api private\n\t*/\n\tfunction coerce(val) {\n\t\tif (val instanceof Error) {\n\t\t\treturn val.stack || val.message;\n\t\t}\n\t\treturn val;\n\t}\n\n\t/**\n\t* XXX DO NOT USE. This is a temporary stub function.\n\t* XXX It WILL be removed in the next major release.\n\t*/\n\tfunction destroy() {\n\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t}\n\n\tcreateDebug.enable(createDebug.load());\n\n\treturn createDebug;\n}\n\nmodule.exports = setup;\n","/**\n * Helpers.\n */\n\nvar s = 1000;\nvar m = s * 60;\nvar h = m * 60;\nvar d = h * 24;\nvar w = d * 7;\nvar y = d * 365.25;\n\n/**\n * Parse or format the given `val`.\n *\n * Options:\n *\n * - `long` verbose formatting [false]\n *\n * @param {String|Number} val\n * @param {Object} [options]\n * @throws {Error} throw an error if val is not a non-empty string or a number\n * @return {String|Number}\n * @api public\n */\n\nmodule.exports = function (val, options) {\n options = options || {};\n var type = typeof val;\n if (type === 'string' && val.length > 0) {\n return parse(val);\n } else if (type === 'number' && isFinite(val)) {\n return options.long ? fmtLong(val) : fmtShort(val);\n }\n throw new Error(\n 'val is not a non-empty string or a valid number. val=' +\n JSON.stringify(val)\n );\n};\n\n/**\n * Parse the given `str` and return milliseconds.\n *\n * @param {String} str\n * @return {Number}\n * @api private\n */\n\nfunction parse(str) {\n str = String(str);\n if (str.length > 100) {\n return;\n }\n var match = /^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(\n str\n );\n if (!match) {\n return;\n }\n var n = parseFloat(match[1]);\n var type = (match[2] || 'ms').toLowerCase();\n switch (type) {\n case 'years':\n case 'year':\n case 'yrs':\n case 'yr':\n case 'y':\n return n * y;\n case 'weeks':\n case 'week':\n case 'w':\n return n * w;\n case 'days':\n case 'day':\n case 'd':\n return n * d;\n case 'hours':\n case 'hour':\n case 'hrs':\n case 'hr':\n case 'h':\n return n * h;\n case 'minutes':\n case 'minute':\n case 'mins':\n case 'min':\n case 'm':\n return n * m;\n case 'seconds':\n case 'second':\n case 'secs':\n case 'sec':\n case 's':\n return n * s;\n case 'milliseconds':\n case 'millisecond':\n case 'msecs':\n case 'msec':\n case 'ms':\n return n;\n default:\n return undefined;\n }\n}\n\n/**\n * Short format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtShort(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return Math.round(ms / d) + 'd';\n }\n if (msAbs >= h) {\n return Math.round(ms / h) + 'h';\n }\n if (msAbs >= m) {\n return Math.round(ms / m) + 'm';\n }\n if (msAbs >= s) {\n return Math.round(ms / s) + 's';\n }\n return ms + 'ms';\n}\n\n/**\n * Long format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtLong(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return plural(ms, msAbs, d, 'day');\n }\n if (msAbs >= h) {\n return plural(ms, msAbs, h, 'hour');\n }\n if (msAbs >= m) {\n return plural(ms, msAbs, m, 'minute');\n }\n if (msAbs >= s) {\n return plural(ms, msAbs, s, 'second');\n }\n return ms + ' ms';\n}\n\n/**\n * Pluralization helper.\n */\n\nfunction plural(ms, msAbs, n, name) {\n var isPlural = msAbs >= n * 1.5;\n return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');\n}\n","/* eslint-env node */\n'use strict';\n\n// SDP helpers.\nconst SDPUtils = {};\n\n// Generate an alphanumeric identifier for cname or mids.\n// TODO: use UUIDs instead? https://gist.github.com/jed/982883\nSDPUtils.generateIdentifier = function() {\n return Math.random().toString(36).substring(2, 12);\n};\n\n// The RTCP CNAME used by all peerconnections from the same JS.\nSDPUtils.localCName = SDPUtils.generateIdentifier();\n\n// Splits SDP into lines, dealing with both CRLF and LF.\nSDPUtils.splitLines = function(blob) {\n return blob.trim().split('\\n').map(line => line.trim());\n};\n// Splits SDP into sessionpart and mediasections. Ensures CRLF.\nSDPUtils.splitSections = function(blob) {\n const parts = blob.split('\\nm=');\n return parts.map((part, index) => (index > 0 ?\n 'm=' + part : part).trim() + '\\r\\n');\n};\n\n// Returns the session description.\nSDPUtils.getDescription = function(blob) {\n const sections = SDPUtils.splitSections(blob);\n return sections && sections[0];\n};\n\n// Returns the individual media sections.\nSDPUtils.getMediaSections = function(blob) {\n const sections = SDPUtils.splitSections(blob);\n sections.shift();\n return sections;\n};\n\n// Returns lines that start with a certain prefix.\nSDPUtils.matchPrefix = function(blob, prefix) {\n return SDPUtils.splitLines(blob).filter(line => line.indexOf(prefix) === 0);\n};\n\n// Parses an ICE candidate line. Sample input:\n// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8\n// rport 55996\"\n// Input can be prefixed with a=.\nSDPUtils.parseCandidate = function(line) {\n let parts;\n // Parse both variants.\n if (line.indexOf('a=candidate:') === 0) {\n parts = line.substring(12).split(' ');\n } else {\n parts = line.substring(10).split(' ');\n }\n\n const candidate = {\n foundation: parts[0],\n component: {1: 'rtp', 2: 'rtcp'}[parts[1]] || parts[1],\n protocol: parts[2].toLowerCase(),\n priority: parseInt(parts[3], 10),\n ip: parts[4],\n address: parts[4], // address is an alias for ip.\n port: parseInt(parts[5], 10),\n // skip parts[6] == 'typ'\n type: parts[7],\n };\n\n for (let i = 8; i < parts.length; i += 2) {\n switch (parts[i]) {\n case 'raddr':\n candidate.relatedAddress = parts[i + 1];\n break;\n case 'rport':\n candidate.relatedPort = parseInt(parts[i + 1], 10);\n break;\n case 'tcptype':\n candidate.tcpType = parts[i + 1];\n break;\n case 'ufrag':\n candidate.ufrag = parts[i + 1]; // for backward compatibility.\n candidate.usernameFragment = parts[i + 1];\n break;\n default: // extension handling, in particular ufrag. Don't overwrite.\n if (candidate[parts[i]] === undefined) {\n candidate[parts[i]] = parts[i + 1];\n }\n break;\n }\n }\n return candidate;\n};\n\n// Translates a candidate object into SDP candidate attribute.\n// This does not include the a= prefix!\nSDPUtils.writeCandidate = function(candidate) {\n const sdp = [];\n sdp.push(candidate.foundation);\n\n const component = candidate.component;\n if (component === 'rtp') {\n sdp.push(1);\n } else if (component === 'rtcp') {\n sdp.push(2);\n } else {\n sdp.push(component);\n }\n sdp.push(candidate.protocol.toUpperCase());\n sdp.push(candidate.priority);\n sdp.push(candidate.address || candidate.ip);\n sdp.push(candidate.port);\n\n const type = candidate.type;\n sdp.push('typ');\n sdp.push(type);\n if (type !== 'host' && candidate.relatedAddress &&\n candidate.relatedPort) {\n sdp.push('raddr');\n sdp.push(candidate.relatedAddress);\n sdp.push('rport');\n sdp.push(candidate.relatedPort);\n }\n if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {\n sdp.push('tcptype');\n sdp.push(candidate.tcpType);\n }\n if (candidate.usernameFragment || candidate.ufrag) {\n sdp.push('ufrag');\n sdp.push(candidate.usernameFragment || candidate.ufrag);\n }\n return 'candidate:' + sdp.join(' ');\n};\n\n// Parses an ice-options line, returns an array of option tags.\n// Sample input:\n// a=ice-options:foo bar\nSDPUtils.parseIceOptions = function(line) {\n return line.substring(14).split(' ');\n};\n\n// Parses a rtpmap line, returns RTCRtpCoddecParameters. Sample input:\n// a=rtpmap:111 opus/48000/2\nSDPUtils.parseRtpMap = function(line) {\n let parts = line.substring(9).split(' ');\n const parsed = {\n payloadType: parseInt(parts.shift(), 10), // was: id\n };\n\n parts = parts[0].split('/');\n\n parsed.name = parts[0];\n parsed.clockRate = parseInt(parts[1], 10); // was: clockrate\n parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1;\n // legacy alias, got renamed back to channels in ORTC.\n parsed.numChannels = parsed.channels;\n return parsed;\n};\n\n// Generates a rtpmap line from RTCRtpCodecCapability or\n// RTCRtpCodecParameters.\nSDPUtils.writeRtpMap = function(codec) {\n let pt = codec.payloadType;\n if (codec.preferredPayloadType !== undefined) {\n pt = codec.preferredPayloadType;\n }\n const channels = codec.channels || codec.numChannels || 1;\n return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate +\n (channels !== 1 ? '/' + channels : '') + '\\r\\n';\n};\n\n// Parses a extmap line (headerextension from RFC 5285). Sample input:\n// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\n// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset\nSDPUtils.parseExtmap = function(line) {\n const parts = line.substring(9).split(' ');\n return {\n id: parseInt(parts[0], 10),\n direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv',\n uri: parts[1],\n attributes: parts.slice(2).join(' '),\n };\n};\n\n// Generates an extmap line from RTCRtpHeaderExtensionParameters or\n// RTCRtpHeaderExtension.\nSDPUtils.writeExtmap = function(headerExtension) {\n return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) +\n (headerExtension.direction && headerExtension.direction !== 'sendrecv'\n ? '/' + headerExtension.direction\n : '') +\n ' ' + headerExtension.uri +\n (headerExtension.attributes ? ' ' + headerExtension.attributes : '') +\n '\\r\\n';\n};\n\n// Parses a fmtp line, returns dictionary. Sample input:\n// a=fmtp:96 vbr=on;cng=on\n// Also deals with vbr=on; cng=on\nSDPUtils.parseFmtp = function(line) {\n const parsed = {};\n let kv;\n const parts = line.substring(line.indexOf(' ') + 1).split(';');\n for (let j = 0; j < parts.length; j++) {\n kv = parts[j].trim().split('=');\n parsed[kv[0].trim()] = kv[1];\n }\n return parsed;\n};\n\n// Generates a fmtp line from RTCRtpCodecCapability or RTCRtpCodecParameters.\nSDPUtils.writeFmtp = function(codec) {\n let line = '';\n let pt = codec.payloadType;\n if (codec.preferredPayloadType !== undefined) {\n pt = codec.preferredPayloadType;\n }\n if (codec.parameters && Object.keys(codec.parameters).length) {\n const params = [];\n Object.keys(codec.parameters).forEach(param => {\n if (codec.parameters[param] !== undefined) {\n params.push(param + '=' + codec.parameters[param]);\n } else {\n params.push(param);\n }\n });\n line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\\r\\n';\n }\n return line;\n};\n\n// Parses a rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:\n// a=rtcp-fb:98 nack rpsi\nSDPUtils.parseRtcpFb = function(line) {\n const parts = line.substring(line.indexOf(' ') + 1).split(' ');\n return {\n type: parts.shift(),\n parameter: parts.join(' '),\n };\n};\n\n// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.\nSDPUtils.writeRtcpFb = function(codec) {\n let lines = '';\n let pt = codec.payloadType;\n if (codec.preferredPayloadType !== undefined) {\n pt = codec.preferredPayloadType;\n }\n if (codec.rtcpFeedback && codec.rtcpFeedback.length) {\n // FIXME: special handling for trr-int?\n codec.rtcpFeedback.forEach(fb => {\n lines += 'a=rtcp-fb:' + pt + ' ' + fb.type +\n (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') +\n '\\r\\n';\n });\n }\n return lines;\n};\n\n// Parses a RFC 5576 ssrc media attribute. Sample input:\n// a=ssrc:3735928559 cname:something\nSDPUtils.parseSsrcMedia = function(line) {\n const sp = line.indexOf(' ');\n const parts = {\n ssrc: parseInt(line.substring(7, sp), 10),\n };\n const colon = line.indexOf(':', sp);\n if (colon > -1) {\n parts.attribute = line.substring(sp + 1, colon);\n parts.value = line.substring(colon + 1);\n } else {\n parts.attribute = line.substring(sp + 1);\n }\n return parts;\n};\n\n// Parse a ssrc-group line (see RFC 5576). Sample input:\n// a=ssrc-group:semantics 12 34\nSDPUtils.parseSsrcGroup = function(line) {\n const parts = line.substring(13).split(' ');\n return {\n semantics: parts.shift(),\n ssrcs: parts.map(ssrc => parseInt(ssrc, 10)),\n };\n};\n\n// Extracts the MID (RFC 5888) from a media section.\n// Returns the MID or undefined if no mid line was found.\nSDPUtils.getMid = function(mediaSection) {\n const mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0];\n if (mid) {\n return mid.substring(6);\n }\n};\n\n// Parses a fingerprint line for DTLS-SRTP.\nSDPUtils.parseFingerprint = function(line) {\n const parts = line.substring(14).split(' ');\n return {\n algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge.\n value: parts[1].toUpperCase(), // the definition is upper-case in RFC 4572.\n };\n};\n\n// Extracts DTLS parameters from SDP media section or sessionpart.\n// FIXME: for consistency with other functions this should only\n// get the fingerprint line as input. See also getIceParameters.\nSDPUtils.getDtlsParameters = function(mediaSection, sessionpart) {\n const lines = SDPUtils.matchPrefix(mediaSection + sessionpart,\n 'a=fingerprint:');\n // Note: a=setup line is ignored since we use the 'auto' role in Edge.\n return {\n role: 'auto',\n fingerprints: lines.map(SDPUtils.parseFingerprint),\n };\n};\n\n// Serializes DTLS parameters to SDP.\nSDPUtils.writeDtlsParameters = function(params, setupType) {\n let sdp = 'a=setup:' + setupType + '\\r\\n';\n params.fingerprints.forEach(fp => {\n sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\\r\\n';\n });\n return sdp;\n};\n\n// Parses a=crypto lines into\n// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members\nSDPUtils.parseCryptoLine = function(line) {\n const parts = line.substring(9).split(' ');\n return {\n tag: parseInt(parts[0], 10),\n cryptoSuite: parts[1],\n keyParams: parts[2],\n sessionParams: parts.slice(3),\n };\n};\n\nSDPUtils.writeCryptoLine = function(parameters) {\n return 'a=crypto:' + parameters.tag + ' ' +\n parameters.cryptoSuite + ' ' +\n (typeof parameters.keyParams === 'object'\n ? SDPUtils.writeCryptoKeyParams(parameters.keyParams)\n : parameters.keyParams) +\n (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') +\n '\\r\\n';\n};\n\n// Parses the crypto key parameters into\n// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam*\nSDPUtils.parseCryptoKeyParams = function(keyParams) {\n if (keyParams.indexOf('inline:') !== 0) {\n return null;\n }\n const parts = keyParams.substring(7).split('|');\n return {\n keyMethod: 'inline',\n keySalt: parts[0],\n lifeTime: parts[1],\n mkiValue: parts[2] ? parts[2].split(':')[0] : undefined,\n mkiLength: parts[2] ? parts[2].split(':')[1] : undefined,\n };\n};\n\nSDPUtils.writeCryptoKeyParams = function(keyParams) {\n return keyParams.keyMethod + ':'\n + keyParams.keySalt +\n (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') +\n (keyParams.mkiValue && keyParams.mkiLength\n ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength\n : '');\n};\n\n// Extracts all SDES parameters.\nSDPUtils.getCryptoParameters = function(mediaSection, sessionpart) {\n const lines = SDPUtils.matchPrefix(mediaSection + sessionpart,\n 'a=crypto:');\n return lines.map(SDPUtils.parseCryptoLine);\n};\n\n// Parses ICE information from SDP media section or sessionpart.\n// FIXME: for consistency with other functions this should only\n// get the ice-ufrag and ice-pwd lines as input.\nSDPUtils.getIceParameters = function(mediaSection, sessionpart) {\n const ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart,\n 'a=ice-ufrag:')[0];\n const pwd = SDPUtils.matchPrefix(mediaSection + sessionpart,\n 'a=ice-pwd:')[0];\n if (!(ufrag && pwd)) {\n return null;\n }\n return {\n usernameFragment: ufrag.substring(12),\n password: pwd.substring(10),\n };\n};\n\n// Serializes ICE parameters to SDP.\nSDPUtils.writeIceParameters = function(params) {\n let sdp = 'a=ice-ufrag:' + params.usernameFragment + '\\r\\n' +\n 'a=ice-pwd:' + params.password + '\\r\\n';\n if (params.iceLite) {\n sdp += 'a=ice-lite\\r\\n';\n }\n return sdp;\n};\n\n// Parses the SDP media section and returns RTCRtpParameters.\nSDPUtils.parseRtpParameters = function(mediaSection) {\n const description = {\n codecs: [],\n headerExtensions: [],\n fecMechanisms: [],\n rtcp: [],\n };\n const lines = SDPUtils.splitLines(mediaSection);\n const mline = lines[0].split(' ');\n description.profile = mline[2];\n for (let i = 3; i < mline.length; i++) { // find all codecs from mline[3..]\n const pt = mline[i];\n const rtpmapline = SDPUtils.matchPrefix(\n mediaSection, 'a=rtpmap:' + pt + ' ')[0];\n if (rtpmapline) {\n const codec = SDPUtils.parseRtpMap(rtpmapline);\n const fmtps = SDPUtils.matchPrefix(\n mediaSection, 'a=fmtp:' + pt + ' ');\n // Only the first a=fmtp: is considered.\n codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};\n codec.rtcpFeedback = SDPUtils.matchPrefix(\n mediaSection, 'a=rtcp-fb:' + pt + ' ')\n .map(SDPUtils.parseRtcpFb);\n description.codecs.push(codec);\n // parse FEC mechanisms from rtpmap lines.\n switch (codec.name.toUpperCase()) {\n case 'RED':\n case 'ULPFEC':\n description.fecMechanisms.push(codec.name.toUpperCase());\n break;\n default: // only RED and ULPFEC are recognized as FEC mechanisms.\n break;\n }\n }\n }\n SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(line => {\n description.headerExtensions.push(SDPUtils.parseExtmap(line));\n });\n const wildcardRtcpFb = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-fb:* ')\n .map(SDPUtils.parseRtcpFb);\n description.codecs.forEach(codec => {\n wildcardRtcpFb.forEach(fb=> {\n const duplicate = codec.rtcpFeedback.find(existingFeedback => {\n return existingFeedback.type === fb.type &&\n existingFeedback.parameter === fb.parameter;\n });\n if (!duplicate) {\n codec.rtcpFeedback.push(fb);\n }\n });\n });\n // FIXME: parse rtcp.\n return description;\n};\n\n// Generates parts of the SDP media section describing the capabilities /\n// parameters.\nSDPUtils.writeRtpDescription = function(kind, caps) {\n let sdp = '';\n\n // Build the mline.\n sdp += 'm=' + kind + ' ';\n sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.\n sdp += ' ' + (caps.profile || 'UDP/TLS/RTP/SAVPF') + ' ';\n sdp += caps.codecs.map(codec => {\n if (codec.preferredPayloadType !== undefined) {\n return codec.preferredPayloadType;\n }\n return codec.payloadType;\n }).join(' ') + '\\r\\n';\n\n sdp += 'c=IN IP4 0.0.0.0\\r\\n';\n sdp += 'a=rtcp:9 IN IP4 0.0.0.0\\r\\n';\n\n // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.\n caps.codecs.forEach(codec => {\n sdp += SDPUtils.writeRtpMap(codec);\n sdp += SDPUtils.writeFmtp(codec);\n sdp += SDPUtils.writeRtcpFb(codec);\n });\n let maxptime = 0;\n caps.codecs.forEach(codec => {\n if (codec.maxptime > maxptime) {\n maxptime = codec.maxptime;\n }\n });\n if (maxptime > 0) {\n sdp += 'a=maxptime:' + maxptime + '\\r\\n';\n }\n\n if (caps.headerExtensions) {\n caps.headerExtensions.forEach(extension => {\n sdp += SDPUtils.writeExtmap(extension);\n });\n }\n // FIXME: write fecMechanisms.\n return sdp;\n};\n\n// Parses the SDP media section and returns an array of\n// RTCRtpEncodingParameters.\nSDPUtils.parseRtpEncodingParameters = function(mediaSection) {\n const encodingParameters = [];\n const description = SDPUtils.parseRtpParameters(mediaSection);\n const hasRed = description.fecMechanisms.indexOf('RED') !== -1;\n const hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;\n\n // filter a=ssrc:... cname:, ignore PlanB-msid\n const ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')\n .map(line => SDPUtils.parseSsrcMedia(line))\n .filter(parts => parts.attribute === 'cname');\n const primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;\n let secondarySsrc;\n\n const flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID')\n .map(line => {\n const parts = line.substring(17).split(' ');\n return parts.map(part => parseInt(part, 10));\n });\n if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {\n secondarySsrc = flows[0][1];\n }\n\n description.codecs.forEach(codec => {\n if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {\n let encParam = {\n ssrc: primarySsrc,\n codecPayloadType: parseInt(codec.parameters.apt, 10),\n };\n if (primarySsrc && secondarySsrc) {\n encParam.rtx = {ssrc: secondarySsrc};\n }\n encodingParameters.push(encParam);\n if (hasRed) {\n encParam = JSON.parse(JSON.stringify(encParam));\n encParam.fec = {\n ssrc: primarySsrc,\n mechanism: hasUlpfec ? 'red+ulpfec' : 'red',\n };\n encodingParameters.push(encParam);\n }\n }\n });\n if (encodingParameters.length === 0 && primarySsrc) {\n encodingParameters.push({\n ssrc: primarySsrc,\n });\n }\n\n // we support both b=AS and b=TIAS but interpret AS as TIAS.\n let bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');\n if (bandwidth.length) {\n if (bandwidth[0].indexOf('b=TIAS:') === 0) {\n bandwidth = parseInt(bandwidth[0].substring(7), 10);\n } else if (bandwidth[0].indexOf('b=AS:') === 0) {\n // use formula from JSEP to convert b=AS to TIAS value.\n bandwidth = parseInt(bandwidth[0].substring(5), 10) * 1000 * 0.95\n - (50 * 40 * 8);\n } else {\n bandwidth = undefined;\n }\n encodingParameters.forEach(params => {\n params.maxBitrate = bandwidth;\n });\n }\n return encodingParameters;\n};\n\n// parses http://draft.ortc.org/#rtcrtcpparameters*\nSDPUtils.parseRtcpParameters = function(mediaSection) {\n const rtcpParameters = {};\n\n // Gets the first SSRC. Note that with RTX there might be multiple\n // SSRCs.\n const remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')\n .map(line => SDPUtils.parseSsrcMedia(line))\n .filter(obj => obj.attribute === 'cname')[0];\n if (remoteSsrc) {\n rtcpParameters.cname = remoteSsrc.value;\n rtcpParameters.ssrc = remoteSsrc.ssrc;\n }\n\n // Edge uses the compound attribute instead of reducedSize\n // compound is !reducedSize\n const rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize');\n rtcpParameters.reducedSize = rsize.length > 0;\n rtcpParameters.compound = rsize.length === 0;\n\n // parses the rtcp-mux attrŅ–bute.\n // Note that Edge does not support unmuxed RTCP.\n const mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux');\n rtcpParameters.mux = mux.length > 0;\n\n return rtcpParameters;\n};\n\nSDPUtils.writeRtcpParameters = function(rtcpParameters) {\n let sdp = '';\n if (rtcpParameters.reducedSize) {\n sdp += 'a=rtcp-rsize\\r\\n';\n }\n if (rtcpParameters.mux) {\n sdp += 'a=rtcp-mux\\r\\n';\n }\n if (rtcpParameters.ssrc !== undefined && rtcpParameters.cname) {\n sdp += 'a=ssrc:' + rtcpParameters.ssrc +\n ' cname:' + rtcpParameters.cname + '\\r\\n';\n }\n return sdp;\n};\n\n\n// parses either a=msid: or a=ssrc:... msid lines and returns\n// the id of the MediaStream and MediaStreamTrack.\nSDPUtils.parseMsid = function(mediaSection) {\n let parts;\n const spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:');\n if (spec.length === 1) {\n parts = spec[0].substring(7).split(' ');\n return {stream: parts[0], track: parts[1]};\n }\n const planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')\n .map(line => SDPUtils.parseSsrcMedia(line))\n .filter(msidParts => msidParts.attribute === 'msid');\n if (planB.length > 0) {\n parts = planB[0].value.split(' ');\n return {stream: parts[0], track: parts[1]};\n }\n};\n\n// SCTP\n// parses draft-ietf-mmusic-sctp-sdp-26 first and falls back\n// to draft-ietf-mmusic-sctp-sdp-05\nSDPUtils.parseSctpDescription = function(mediaSection) {\n const mline = SDPUtils.parseMLine(mediaSection);\n const maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:');\n let maxMessageSize;\n if (maxSizeLine.length > 0) {\n maxMessageSize = parseInt(maxSizeLine[0].substring(19), 10);\n }\n if (isNaN(maxMessageSize)) {\n maxMessageSize = 65536;\n }\n const sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:');\n if (sctpPort.length > 0) {\n return {\n port: parseInt(sctpPort[0].substring(12), 10),\n protocol: mline.fmt,\n maxMessageSize,\n };\n }\n const sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:');\n if (sctpMapLines.length > 0) {\n const parts = sctpMapLines[0]\n .substring(10)\n .split(' ');\n return {\n port: parseInt(parts[0], 10),\n protocol: parts[1],\n maxMessageSize,\n };\n }\n};\n\n// SCTP\n// outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers\n// support by now receiving in this format, unless we originally parsed\n// as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line\n// protocol of DTLS/SCTP -- without UDP/ or TCP/)\nSDPUtils.writeSctpDescription = function(media, sctp) {\n let output = [];\n if (media.protocol !== 'DTLS/SCTP') {\n output = [\n 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\\r\\n',\n 'c=IN IP4 0.0.0.0\\r\\n',\n 'a=sctp-port:' + sctp.port + '\\r\\n',\n ];\n } else {\n output = [\n 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\\r\\n',\n 'c=IN IP4 0.0.0.0\\r\\n',\n 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\\r\\n',\n ];\n }\n if (sctp.maxMessageSize !== undefined) {\n output.push('a=max-message-size:' + sctp.maxMessageSize + '\\r\\n');\n }\n return output.join('');\n};\n\n// Generate a session ID for SDP.\n// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1\n// recommends using a cryptographically random +ve 64-bit value\n// but right now this should be acceptable and within the right range\nSDPUtils.generateSessionId = function() {\n return Math.random().toString().substr(2, 22);\n};\n\n// Write boiler plate for start of SDP\n// sessId argument is optional - if not supplied it will\n// be generated randomly\n// sessVersion is optional and defaults to 2\n// sessUser is optional and defaults to 'thisisadapterortc'\nSDPUtils.writeSessionBoilerplate = function(sessId, sessVer, sessUser) {\n let sessionId;\n const version = sessVer !== undefined ? sessVer : 2;\n if (sessId) {\n sessionId = sessId;\n } else {\n sessionId = SDPUtils.generateSessionId();\n }\n const user = sessUser || 'thisisadapterortc';\n // FIXME: sess-id should be an NTP timestamp.\n return 'v=0\\r\\n' +\n 'o=' + user + ' ' + sessionId + ' ' + version +\n ' IN IP4 127.0.0.1\\r\\n' +\n 's=-\\r\\n' +\n 't=0 0\\r\\n';\n};\n\n// Gets the direction from the mediaSection or the sessionpart.\nSDPUtils.getDirection = function(mediaSection, sessionpart) {\n // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.\n const lines = SDPUtils.splitLines(mediaSection);\n for (let i = 0; i < lines.length; i++) {\n switch (lines[i]) {\n case 'a=sendrecv':\n case 'a=sendonly':\n case 'a=recvonly':\n case 'a=inactive':\n return lines[i].substring(2);\n default:\n // FIXME: What should happen here?\n }\n }\n if (sessionpart) {\n return SDPUtils.getDirection(sessionpart);\n }\n return 'sendrecv';\n};\n\nSDPUtils.getKind = function(mediaSection) {\n const lines = SDPUtils.splitLines(mediaSection);\n const mline = lines[0].split(' ');\n return mline[0].substring(2);\n};\n\nSDPUtils.isRejected = function(mediaSection) {\n return mediaSection.split(' ', 2)[1] === '0';\n};\n\nSDPUtils.parseMLine = function(mediaSection) {\n const lines = SDPUtils.splitLines(mediaSection);\n const parts = lines[0].substring(2).split(' ');\n return {\n kind: parts[0],\n port: parseInt(parts[1], 10),\n protocol: parts[2],\n fmt: parts.slice(3).join(' '),\n };\n};\n\nSDPUtils.parseOLine = function(mediaSection) {\n const line = SDPUtils.matchPrefix(mediaSection, 'o=')[0];\n const parts = line.substring(2).split(' ');\n return {\n username: parts[0],\n sessionId: parts[1],\n sessionVersion: parseInt(parts[2], 10),\n netType: parts[3],\n addressType: parts[4],\n address: parts[5],\n };\n};\n\n// a very naive interpretation of a valid SDP.\nSDPUtils.isValidSDP = function(blob) {\n if (typeof blob !== 'string' || blob.length === 0) {\n return false;\n }\n const lines = SDPUtils.splitLines(blob);\n for (let i = 0; i < lines.length; i++) {\n if (lines[i].length < 2 || lines[i].charAt(1) !== '=') {\n return false;\n }\n // TODO: check the modifier a bit more.\n }\n return true;\n};\n\n// Expose public methods.\nif (typeof module === 'object') {\n module.exports = SDPUtils;\n}\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(497);\n"],"names":["JanusPluginHandle","session","this","id","undefined","JanusSession","output","options","nextTxId","txns","eventHandlers","Object","assign","verbose","timeoutMs","keepaliveMs","prototype","attach","plugin","loop_index","payload","send","then","resp","data","detach","on","ev","callback","signal","sender","type","handle_id","sendMessage","body","sendJsep","jsep","sendTrickle","candidate","create","destroy","dispose","txId","_killKeepalive","hasOwnProperty","txn","clearTimeout","timeout","reject","Error","isError","janus","handlers","push","receive","_logIncoming","session_id","console","warn","responseType","i","length","transaction","resolve","toString","Promise","setTimeout","_transmit","_logOutgoing","JSON","stringify","_resetKeepalive","kind","message","debug","_sendKeepalive","keepaliveTimeout","catch","e","error","module","exports","mj","require","sendOriginal","indexOf","NAF","connection","adapter","reconnect","sdpUtils","isSafari","test","navigator","userAgent","debounce","fn","curr","args","Array","slice","call","arguments","_","apply","untilDataChannelOpen","dataChannel","readyState","resolver","rejector","clear","removeEventListener","addEventListener","isH264VideoSupported","document","createElement","canPlayType","OPUS_PARAMETERS","usedtx","stereo","DEFAULT_PEER_CONNECTION_CONFIG","iceServers","urls","JanusAdapter","constructor","room","clientId","joinToken","serverUrl","webRtcOptions","peerConnectionConfig","ws","reliableTransport","unreliableTransport","initialReconnectionDelay","Math","random","reconnectionDelay","reconnectionTimeout","maxReconnectionAttempts","reconnectionAttempts","isReconnecting","publisher","occupantIds","occupants","mediaStreams","localMediaStream","pendingMediaRequests","Map","pendingOccupants","Set","availableOccupants","requestedOccupants","blockedClients","frozenUpdates","timeOffsets","serverTimeRequests","avgTimeOffset","onWebsocketOpen","bind","onWebsocketClose","onWebsocketMessage","onDataChannelMessage","onData","setServerUrl","url","setApp","app","setRoom","roomName","setJoinToken","setClientId","setWebRtcOptions","setPeerConnectionConfig","setServerConnectListeners","successListener","failureListener","connectSuccess","connectFailure","setRoomOccupantListener","occupantListener","onOccupantsChanged","setDataChannelListeners","openListener","closedListener","messageListener","onOccupantConnected","onOccupantDisconnected","onOccupantMessage","setReconnectionListeners","reconnectingListener","reconnectedListener","reconnectionErrorListener","onReconnecting","onReconnected","onReconnectionError","setEventLoops","loops","connect","location","protocol","host","websocketConnection","WebSocket","websocketConnectionPromise","wsOnOpen","all","updateTimeOffset","disconnect","removeAllOccupants","conn","close","delayedReconnectTimeout","isDisconnected","createPublisher","initialOccupants","occupantId","addAvailableOccupant","syncOccupants","event","code","performDelayedReconnect","parse","removeAvailableOccupant","idx","splice","has","addOccupant","j","removeOccupant","add","delay","subscriber","createSubscriber","delete","setMediaStream","mediaStream","msg","get","audio","video","associate","handle","iceConnectionState","log","offer","createOffer","configurePublisherSdp","fixSafariIceUFrag","local","o","setLocalDescription","remote","r","setRemoteDescription","answer","configureSubscriberSdp","createAnswer","a","RTCPeerConnection","parseInt","webrtcup","reliableChannel","createDataChannel","ordered","unreliableChannel","maxRetransmits","getTracks","forEach","track","addTrack","plugindata","room_id","user_id","dispatchEvent","CustomEvent","detail","by","sendJoin","notifications","success","err","response","users","includes","sdp","replace","line","pt","parameters","parseFmtp","writeFmtp","payloadType","maxRetries","webrtcFailed","leftInterval","setInterval","clearInterval","media","_iOSHackDelayedInitialPeer","MediaStream","getReceivers","receiver","subscribe","token","toggleFreeze","frozen","unfreeze","freeze","flushPendingUpdates","dataForUpdateMultiMessage","networkId","l","d","getPendingData","dataType","owner","getPendingDataForNetworkId","source","storeMessage","storeSingleMessage","index","storedMessage","storedData","isOutdatedMessage","lastOwnerTime","isContemporaneousMessage","isFirstSync","set","components","enabled","shouldStartConnectionTo","client","startStreamConnection","closeStreamConnection","getConnectStatus","adapters","IS_CONNECTED","NOT_CONNECTED","clientSentTime","Date","now","res","fetch","href","method","cache","serverReceivedTime","headers","getTime","precision","clientReceivedTime","timeOffset","reduce","acc","offset","getServerTime","getMediaStream","audioPromise","videoPromise","promise","stream","audioStream","getAudioTracks","videoStream","getVideoTracks","getLocalMediaStream","setLocalMediaStream","existingSenders","getSenders","newSenders","tracks","t","find","s","replaceTrack","removeTrack","enableMicrophone","sendData","whom","sendDataGuaranteed","broadcastData","broadcastDataGuaranteed","kick","permsToken","block","unblock","register","formatArgs","useColors","namespace","humanize","diff","c","color","lastC","match","save","namespaces","storage","setItem","removeItem","load","getItem","process","env","DEBUG","window","__nwjs","toLowerCase","m","documentElement","style","WebkitAppearance","firebug","exception","table","localStorage","localstorage","warned","colors","formatters","v","createDebug","prevTime","namespacesCache","enabledCache","enableOverride","self","Number","ms","prev","coerce","unshift","format","formatter","val","selectColor","extend","defineProperty","enumerable","configurable","init","delimiter","newDebug","matchesTemplate","search","template","searchIndex","templateIndex","starIndex","matchIndex","default","stack","disable","names","skips","map","join","enable","split","trim","filter","Boolean","ns","name","skip","keys","key","hash","charCodeAt","abs","h","w","plural","msAbs","n","isPlural","round","str","String","exec","parseFloat","isFinite","long","fmtShort","SDPUtils","substring","localCName","generateIdentifier","splitLines","blob","splitSections","part","getDescription","sections","getMediaSections","shift","matchPrefix","prefix","parseCandidate","parts","foundation","component","priority","ip","address","port","relatedAddress","relatedPort","tcpType","ufrag","usernameFragment","writeCandidate","toUpperCase","parseIceOptions","parseRtpMap","parsed","clockRate","channels","numChannels","writeRtpMap","codec","preferredPayloadType","parseExtmap","direction","uri","attributes","writeExtmap","headerExtension","preferredId","kv","params","param","parseRtcpFb","parameter","writeRtcpFb","lines","rtcpFeedback","fb","parseSsrcMedia","sp","ssrc","colon","attribute","value","parseSsrcGroup","semantics","ssrcs","getMid","mediaSection","mid","parseFingerprint","algorithm","getDtlsParameters","sessionpart","role","fingerprints","writeDtlsParameters","setupType","fp","parseCryptoLine","tag","cryptoSuite","keyParams","sessionParams","writeCryptoLine","writeCryptoKeyParams","parseCryptoKeyParams","keyMethod","keySalt","lifeTime","mkiValue","mkiLength","getCryptoParameters","getIceParameters","pwd","password","writeIceParameters","iceLite","parseRtpParameters","description","codecs","headerExtensions","fecMechanisms","rtcp","mline","profile","rtpmapline","fmtps","wildcardRtcpFb","existingFeedback","writeRtpDescription","caps","maxptime","extension","parseRtpEncodingParameters","encodingParameters","hasRed","hasUlpfec","primarySsrc","secondarySsrc","flows","apt","encParam","codecPayloadType","rtx","fec","mechanism","bandwidth","maxBitrate","parseRtcpParameters","rtcpParameters","remoteSsrc","obj","cname","rsize","reducedSize","compound","mux","writeRtcpParameters","parseMsid","spec","planB","msidParts","parseSctpDescription","parseMLine","maxSizeLine","maxMessageSize","isNaN","sctpPort","fmt","sctpMapLines","writeSctpDescription","sctp","generateSessionId","substr","writeSessionBoilerplate","sessId","sessVer","sessUser","sessionId","version","getDirection","getKind","isRejected","parseOLine","username","sessionVersion","netType","addressType","isValidSDP","charAt","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__"],"sourceRoot":""} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 55a1d22..2cf1ba7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@networked-aframe/naf-janus-adapter", - "version": "4.2.0", + "version": "4.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@networked-aframe/naf-janus-adapter", - "version": "4.2.0", + "version": "4.3.0", "license": "MPL-2.0", "dependencies": { "@networked-aframe/minijanus": "0.7.0", diff --git a/package.json b/package.json index d769967..6a7db05 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@networked-aframe/naf-janus-adapter", - "version": "4.2.0", + "version": "4.3.0", "description": "networked-aframe Janus network adapter", "main": "src/index.js", "license": "MPL-2.0",