diff --git a/dist/naf-janus-adapter.js b/dist/naf-janus-adapter.js index 6abdb7f..e538f8f 100644 --- a/dist/naf-janus-adapter.js +++ b/dist/naf-janus-adapter.js @@ -270,27 +270,11 @@ module.exports = { \**********************/ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { -function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } -function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } -function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } -function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i["return"] && (_r = _i["return"](), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } } -function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } -function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } -function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } -function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } -function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return exports; }; var exports = {}, Op = Object.prototype, hasOwn = Op.hasOwnProperty, defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; }, $Symbol = "function" == typeof Symbol ? Symbol : {}, iteratorSymbol = $Symbol.iterator || "@@iterator", asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator", toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; function define(obj, key, value) { return Object.defineProperty(obj, key, { value: value, enumerable: !0, configurable: !0, writable: !0 }), obj[key]; } try { define({}, ""); } catch (err) { define = function define(obj, key, value) { return obj[key] = value; }; } function wrap(innerFn, outerFn, self, tryLocsList) { var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator, generator = Object.create(protoGenerator.prototype), context = new Context(tryLocsList || []); return defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) }), generator; } function tryCatch(fn, obj, arg) { try { return { type: "normal", arg: fn.call(obj, arg) }; } catch (err) { return { type: "throw", arg: err }; } } exports.wrap = wrap; var ContinueSentinel = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var IteratorPrototype = {}; define(IteratorPrototype, iteratorSymbol, function () { return this; }); var getProto = Object.getPrototypeOf, NativeIteratorPrototype = getProto && getProto(getProto(values([]))); NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype); var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype); function defineIteratorMethods(prototype) { ["next", "throw", "return"].forEach(function (method) { define(prototype, method, function (arg) { return this._invoke(method, arg); }); }); } function AsyncIterator(generator, PromiseImpl) { function invoke(method, arg, resolve, reject) { var record = tryCatch(generator[method], generator, arg); if ("throw" !== record.type) { var result = record.arg, value = result.value; return value && "object" == _typeof(value) && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) { invoke("next", value, resolve, reject); }, function (err) { invoke("throw", err, resolve, reject); }) : PromiseImpl.resolve(value).then(function (unwrapped) { result.value = unwrapped, resolve(result); }, function (error) { return invoke("throw", error, resolve, reject); }); } reject(record.arg); } var previousPromise; defineProperty(this, "_invoke", { value: function value(method, arg) { function callInvokeWithMethodAndArg() { return new PromiseImpl(function (resolve, reject) { invoke(method, arg, resolve, reject); }); } return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(innerFn, self, context) { var state = "suspendedStart"; return function (method, arg) { if ("executing" === state) throw new Error("Generator is already running"); if ("completed" === state) { if ("throw" === method) throw arg; return doneResult(); } for (context.method = method, context.arg = arg;;) { var delegate = context.delegate; if (delegate) { var delegateResult = maybeInvokeDelegate(delegate, context); if (delegateResult) { if (delegateResult === ContinueSentinel) continue; return delegateResult; } } if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) { if ("suspendedStart" === state) throw state = "completed", context.arg; context.dispatchException(context.arg); } else "return" === context.method && context.abrupt("return", context.arg); state = "executing"; var record = tryCatch(innerFn, self, context); if ("normal" === record.type) { if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue; return { value: record.arg, done: context.done }; } "throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg); } }; } function maybeInvokeDelegate(delegate, context) { var methodName = context.method, method = delegate.iterator[methodName]; if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator["return"] && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel; var record = tryCatch(method, delegate.iterator, context.arg); if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel; var info = record.arg; return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel); } function pushTryEntry(locs) { var entry = { tryLoc: locs[0] }; 1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry); } function resetTryEntry(entry) { var record = entry.completion || {}; record.type = "normal", delete record.arg, entry.completion = record; } function Context(tryLocsList) { this.tryEntries = [{ tryLoc: "root" }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0); } function values(iterable) { if (iterable) { var iteratorMethod = iterable[iteratorSymbol]; if (iteratorMethod) return iteratorMethod.call(iterable); if ("function" == typeof iterable.next) return iterable; if (!isNaN(iterable.length)) { var i = -1, next = function next() { for (; ++i < iterable.length;) if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next; return next.value = undefined, next.done = !0, next; }; return next.next = next; } } return { next: doneResult }; } function doneResult() { return { value: undefined, done: !0 }; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), defineProperty(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) { var ctor = "function" == typeof genFun && genFun.constructor; return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name)); }, exports.mark = function (genFun) { return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun; }, exports.awrap = function (arg) { return { __await: arg }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () { return this; }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) { void 0 === PromiseImpl && (PromiseImpl = Promise); var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl); return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) { return result.done ? result.value : iter.next(); }); }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () { return this; }), define(Gp, "toString", function () { return "[object Generator]"; }), exports.keys = function (val) { var object = Object(val), keys = []; for (var key in object) keys.push(key); return keys.reverse(), function next() { for (; keys.length;) { var key = keys.pop(); if (key in object) return next.value = key, next.done = !1, next; } return next.done = !0, next; }; }, exports.values = values, Context.prototype = { constructor: Context, reset: function reset(skipTempReset) { if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined); }, stop: function stop() { this.done = !0; var rootRecord = this.tryEntries[0].completion; if ("throw" === rootRecord.type) throw rootRecord.arg; return this.rval; }, dispatchException: function dispatchException(exception) { if (this.done) throw exception; var context = this; function handle(loc, caught) { return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught; } for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i], record = entry.completion; if ("root" === entry.tryLoc) return handle("end"); if (entry.tryLoc <= this.prev) { var hasCatch = hasOwn.call(entry, "catchLoc"), hasFinally = hasOwn.call(entry, "finallyLoc"); if (hasCatch && hasFinally) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } else if (hasCatch) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); } else { if (!hasFinally) throw new Error("try statement without catch or finally"); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } } } }, abrupt: function abrupt(type, arg) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) { var finallyEntry = entry; break; } } finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null); var record = finallyEntry ? finallyEntry.completion : {}; return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record); }, complete: function complete(record, afterLoc) { if ("throw" === record.type) throw record.arg; return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel; }, finish: function finish(finallyLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel; } }, "catch": function _catch(tryLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc === tryLoc) { var record = entry.completion; if ("throw" === record.type) { var thrown = record.arg; resetTryEntry(entry); } return thrown; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(iterable, resultName, nextLoc) { return this.delegate = { iterator: values(iterable), resultName: resultName, nextLoc: nextLoc }, "next" === this.method && (this.arg = undefined), ContinueSentinel; } }, exports; } -function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } -function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } -function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } -function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } -function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } /* global NAF */ var mj = __webpack_require__(/*! @networked-aframe/minijanus */ "./node_modules/@networked-aframe/minijanus/minijanus.js"); mj.JanusSession.prototype.sendOriginal = mj.JanusSession.prototype.send; mj.JanusSession.prototype.send = function (type, signal) { - return this.sendOriginal(type, signal)["catch"](function (e) { + return this.sendOriginal(type, signal).catch(e => { if (e.message && e.message.indexOf("timed out") > -1) { console.error("web socket timed out"); NAF.connection.adapter.reconnect(); @@ -304,43 +288,40 @@ var debug = __webpack_require__(/*! debug */ "./node_modules/debug/src/browser.j var warn = __webpack_require__(/*! debug */ "./node_modules/debug/src/browser.js")("naf-janus-adapter:warn"); var error = __webpack_require__(/*! debug */ "./node_modules/debug/src/browser.js")("naf-janus-adapter:error"); var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); -var SUBSCRIBE_TIMEOUT_MS = 15000; -var AVAILABLE_OCCUPANTS_THRESHOLD = 5; -var MAX_SUBSCRIBE_DELAY = 5000; +const SUBSCRIBE_TIMEOUT_MS = 15000; +const AVAILABLE_OCCUPANTS_THRESHOLD = 5; +const MAX_SUBSCRIBE_DELAY = 5000; function randomDelay(min, max) { - return new Promise(function (resolve) { - var delay = Math.random() * (max - min) + min; + return new Promise(resolve => { + const delay = Math.random() * (max - min) + min; setTimeout(resolve, delay); }); } function debounce(fn) { var curr = Promise.resolve(); return function () { - var _this = this; var args = Array.prototype.slice.call(arguments); - curr = curr.then(function (_) { - return fn.apply(_this, args); - }); + curr = curr.then(_ => fn.apply(this, args)); }; } function randomUint() { return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); } function untilDataChannelOpen(dataChannel) { - return new Promise(function (resolve, reject) { + return new Promise((resolve, reject) => { if (dataChannel.readyState === "open") { resolve(); } else { - var resolver, rejector; - var clear = function clear() { + let resolver, rejector; + const clear = () => { dataChannel.removeEventListener("open", resolver); dataChannel.removeEventListener("error", rejector); }; - resolver = function resolver() { + resolver = () => { clear(); resolve(); }; - rejector = function rejector() { + rejector = () => { clear(); reject(); }; @@ -349,11 +330,11 @@ function untilDataChannelOpen(dataChannel) { } }); } -var isH264VideoSupported = function () { - var video = document.createElement("video"); +const isH264VideoSupported = (() => { + const video = document.createElement("video"); return video.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"') !== ""; -}(); -var OPUS_PARAMETERS = { +})(); +const OPUS_PARAMETERS = { // indicates that we want to enable DTX to elide silence packets usedtx: 1, // indicates that we prefer to receive mono audio (important for voip profile) @@ -361,17 +342,16 @@ var OPUS_PARAMETERS = { // indicates that we prefer to send mono audio (important for voip profile) "sprop-stereo": 0 }; -var DEFAULT_PEER_CONNECTION_CONFIG = { +const DEFAULT_PEER_CONNECTION_CONFIG = { iceServers: [{ urls: "stun:stun1.l.google.com:19302" }, { urls: "stun:stun2.l.google.com:19302" }] }; -var WS_NORMAL_CLOSURE = 1000; -var JanusAdapter = /*#__PURE__*/function () { - function JanusAdapter() { - _classCallCheck(this, JanusAdapter); +const WS_NORMAL_CLOSURE = 1000; +class JanusAdapter { + constructor() { this.room = null; // We expect the consumer to set a client id before connecting. this.clientId = null; @@ -411,1321 +391,944 @@ var JanusAdapter = /*#__PURE__*/function () { this.onDataChannelMessage = this.onDataChannelMessage.bind(this); this.onData = this.onData.bind(this); } - _createClass(JanusAdapter, [{ - key: "setServerUrl", - value: function setServerUrl(url) { - this.serverUrl = url; - } - }, { - key: "setApp", - value: function setApp(app) {} - }, { - key: "setRoom", - value: function setRoom(roomName) { - this.room = roomName; - } - }, { - key: "setJoinToken", - value: function setJoinToken(joinToken) { - this.joinToken = joinToken; - } - }, { - key: "setClientId", - value: function setClientId(clientId) { - this.clientId = clientId; - } - }, { - key: "setWebRtcOptions", - value: function setWebRtcOptions(options) { - this.webRtcOptions = options; - } - }, { - key: "setPeerConnectionConfig", - value: function setPeerConnectionConfig(peerConnectionConfig) { - this.peerConnectionConfig = peerConnectionConfig; - } - }, { - key: "setServerConnectListeners", - value: function setServerConnectListeners(successListener, failureListener) { - this.connectSuccess = successListener; - this.connectFailure = failureListener; - } - }, { - key: "setRoomOccupantListener", - value: function setRoomOccupantListener(occupantListener) { - this.onOccupantsChanged = occupantListener; - } - }, { - key: "setDataChannelListeners", - value: function setDataChannelListeners(openListener, closedListener, messageListener) { - this.onOccupantConnected = openListener; - this.onOccupantDisconnected = closedListener; - this.onOccupantMessage = messageListener; - } - }, { - key: "setReconnectionListeners", - value: function setReconnectionListeners(reconnectingListener, reconnectedListener, reconnectionErrorListener) { - // onReconnecting is called with the number of milliseconds until the next reconnection attempt - this.onReconnecting = reconnectingListener; - // onReconnected is called when the connection has been reestablished - this.onReconnected = reconnectedListener; - // onReconnectionError is called with an error when maxReconnectionAttempts has been reached - this.onReconnectionError = reconnectionErrorListener; - } - }, { - key: "setEventLoops", - value: function setEventLoops(loops) { - this.loops = loops; - } - }, { - key: "connect", - value: function connect() { - var _this2 = this; - debug("connecting to ".concat(this.serverUrl)); - var websocketConnection = new Promise(function (resolve, reject) { - _this2.ws = new WebSocket(_this2.serverUrl, "janus-protocol"); - _this2.session = new mj.JanusSession(_this2.ws.send.bind(_this2.ws), { - timeoutMs: 40000 - }); - _this2.ws.addEventListener("close", _this2.onWebsocketClose); - _this2.ws.addEventListener("message", _this2.onWebsocketMessage); - _this2.wsOnOpen = function () { - _this2.ws.removeEventListener("open", _this2.wsOnOpen); - _this2.onWebsocketOpen().then(resolve)["catch"](reject); - }; - _this2.ws.addEventListener("open", _this2.wsOnOpen); + setServerUrl(url) { + this.serverUrl = url; + } + setApp(app) {} + setRoom(roomName) { + this.room = roomName; + } + setJoinToken(joinToken) { + this.joinToken = joinToken; + } + setClientId(clientId) { + this.clientId = clientId; + } + setWebRtcOptions(options) { + this.webRtcOptions = options; + } + setPeerConnectionConfig(peerConnectionConfig) { + this.peerConnectionConfig = peerConnectionConfig; + } + setServerConnectListeners(successListener, failureListener) { + this.connectSuccess = successListener; + this.connectFailure = failureListener; + } + setRoomOccupantListener(occupantListener) { + this.onOccupantsChanged = occupantListener; + } + setDataChannelListeners(openListener, closedListener, messageListener) { + this.onOccupantConnected = openListener; + this.onOccupantDisconnected = closedListener; + this.onOccupantMessage = messageListener; + } + setReconnectionListeners(reconnectingListener, reconnectedListener, reconnectionErrorListener) { + // onReconnecting is called with the number of milliseconds until the next reconnection attempt + this.onReconnecting = reconnectingListener; + // onReconnected is called when the connection has been reestablished + this.onReconnected = reconnectedListener; + // onReconnectionError is called with an error when maxReconnectionAttempts has been reached + this.onReconnectionError = reconnectionErrorListener; + } + setEventLoops(loops) { + this.loops = loops; + } + connect() { + 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 }); - return Promise.all([websocketConnection, this.updateTimeOffset()]); - } - }, { - key: "disconnect", - value: function disconnect() { - debug("disconnecting"); - clearTimeout(this.reconnectionTimeout); - this.removeAllOccupants(); - if (this.publisher) { - // Close the publisher peer connection. Which also detaches the plugin handle. - this.publisher.conn.close(); - this.publisher = null; - } - if (this.session) { - this.session.dispose(); - this.session = null; - } - if (this.ws) { + this.ws.addEventListener("close", this.onWebsocketClose); + this.ws.addEventListener("message", this.onWebsocketMessage); + this.wsOnOpen = () => { this.ws.removeEventListener("open", this.wsOnOpen); - this.ws.removeEventListener("close", this.onWebsocketClose); - this.ws.removeEventListener("message", this.onWebsocketMessage); - this.ws.close(); - this.ws = null; - } - - // Now that all RTCPeerConnection closed, be sure to not call - // reconnect() again via performDelayedReconnect if previous - // RTCPeerConnection was in the failed state. - if (this.delayedReconnectTimeout) { - clearTimeout(this.delayedReconnectTimeout); - this.delayedReconnectTimeout = null; - } + this.onWebsocketOpen().then(resolve).catch(reject); + }; + this.ws.addEventListener("open", this.wsOnOpen); + }); + return Promise.all([websocketConnection, this.updateTimeOffset()]); + } + disconnect() { + debug(`disconnecting`); + clearTimeout(this.reconnectionTimeout); + this.removeAllOccupants(); + if (this.publisher) { + // Close the publisher peer connection. Which also detaches the plugin handle. + this.publisher.conn.close(); + this.publisher = null; + } + if (this.session) { + this.session.dispose(); + this.session = null; + } + if (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; + } + + // Now that all RTCPeerConnection closed, be sure to not call + // reconnect() again via performDelayedReconnect if previous + // RTCPeerConnection was in the failed state. + if (this.delayedReconnectTimeout) { + clearTimeout(this.delayedReconnectTimeout); + this.delayedReconnectTimeout = null; } - }, { - key: "isDisconnected", - value: function isDisconnected() { - return this.ws === null; + } + isDisconnected() { + return this.ws === null; + } + async onWebsocketOpen() { + // Create the Janus Session + await this.session.create(); + + // Attach the SFU Plugin and create a RTCPeerConnection for the publisher. + // The publisher sends audio and opens two bidirectional data channels. + // One reliable datachannel and one unreliable. + this.publisher = await this.createPublisher(); + + // Call the naf connectSuccess callback before we start receiving WebRTC messages. + this.connectSuccess(this.clientId); + for (let i = 0; i < this.publisher.initialOccupants.length; i++) { + const occupantId = this.publisher.initialOccupants[i]; + if (occupantId === this.clientId) continue; // Happens during non-graceful reconnects due to zombie sessions + this.addAvailableOccupant(occupantId); + } + this.syncOccupants(); + } + onWebsocketClose(event) { + // The connection was closed successfully. Don't try to reconnect. + if (event.code === WS_NORMAL_CLOSURE) { + return; } - }, { - key: "onWebsocketOpen", - value: function () { - var _onWebsocketOpen = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() { - var i, occupantId; - return _regeneratorRuntime().wrap(function _callee$(_context) { - while (1) switch (_context.prev = _context.next) { - case 0: - _context.next = 2; - return this.session.create(); - case 2: - _context.next = 4; - return this.createPublisher(); - case 4: - this.publisher = _context.sent; - // Call the naf connectSuccess callback before we start receiving WebRTC messages. - this.connectSuccess(this.clientId); - i = 0; - case 7: - if (!(i < this.publisher.initialOccupants.length)) { - _context.next = 15; - break; - } - occupantId = this.publisher.initialOccupants[i]; - if (!(occupantId === this.clientId)) { - _context.next = 11; - break; - } - return _context.abrupt("continue", 12); - case 11: - // Happens during non-graceful reconnects due to zombie sessions - this.addAvailableOccupant(occupantId); - case 12: - i++; - _context.next = 7; - break; - case 15: - this.syncOccupants(); - case 16: - case "end": - return _context.stop(); - } - }, _callee, this); - })); - function onWebsocketOpen() { - return _onWebsocketOpen.apply(this, arguments); + console.warn("Janus websocket closed unexpectedly."); + if (this.onReconnecting) { + this.onReconnecting(this.reconnectionDelay); + } + this.reconnectionTimeout = setTimeout(() => this.reconnect(), this.reconnectionDelay); + } + reconnect() { + // Dispose of all networked entities and other resources tied to the session. + this.disconnect(); + this.connect().then(() => { + this.reconnectionDelay = this.initialReconnectionDelay; + this.reconnectionAttempts = 0; + if (this.onReconnected) { + this.onReconnected(); } - return onWebsocketOpen; - }() - }, { - key: "onWebsocketClose", - value: function onWebsocketClose(event) { - var _this3 = this; - // The connection was closed successfully. Don't try to reconnect. - if (event.code === WS_NORMAL_CLOSURE) { - return; + }).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.")); } - console.warn("Janus websocket closed unexpectedly."); + console.warn("Error during reconnect, retrying."); + console.warn(error); if (this.onReconnecting) { this.onReconnecting(this.reconnectionDelay); } - this.reconnectionTimeout = setTimeout(function () { - return _this3.reconnect(); - }, this.reconnectionDelay); + this.reconnectionTimeout = setTimeout(() => this.reconnect(), this.reconnectionDelay); + }); + } + performDelayedReconnect() { + if (this.delayedReconnectTimeout) { + clearTimeout(this.delayedReconnectTimeout); + } + this.delayedReconnectTimeout = setTimeout(() => { + this.delayedReconnectTimeout = null; + this.reconnect(); + }, 10000); + } + onWebsocketMessage(event) { + this.session.receive(JSON.parse(event.data)); + } + addAvailableOccupant(occupantId) { + if (this.availableOccupants.indexOf(occupantId) === -1) { + this.availableOccupants.push(occupantId); } - }, { - key: "reconnect", - value: function reconnect() { - var _this4 = this; - // Dispose of all networked entities and other resources tied to the session. - this.disconnect(); - this.connect().then(function () { - _this4.reconnectionDelay = _this4.initialReconnectionDelay; - _this4.reconnectionAttempts = 0; - if (_this4.onReconnected) { - _this4.onReconnected(); - } - })["catch"](function (error) { - _this4.reconnectionDelay += 1000; - _this4.reconnectionAttempts++; - if (_this4.reconnectionAttempts > _this4.maxReconnectionAttempts && _this4.onReconnectionError) { - return _this4.onReconnectionError(new Error("Connection could not be reestablished, exceeded maximum number of reconnection attempts.")); - } - console.warn("Error during reconnect, retrying."); - console.warn(error); - if (_this4.onReconnecting) { - _this4.onReconnecting(_this4.reconnectionDelay); - } - _this4.reconnectionTimeout = setTimeout(function () { - return _this4.reconnect(); - }, _this4.reconnectionDelay); - }); + } + removeAvailableOccupant(occupantId) { + const idx = this.availableOccupants.indexOf(occupantId); + if (idx !== -1) { + this.availableOccupants.splice(idx, 1); } - }, { - key: "performDelayedReconnect", - value: function performDelayedReconnect() { - var _this5 = this; - if (this.delayedReconnectTimeout) { - clearTimeout(this.delayedReconnectTimeout); - } - this.delayedReconnectTimeout = setTimeout(function () { - _this5.delayedReconnectTimeout = null; - _this5.reconnect(); - }, 10000); + } + syncOccupants(requestedOccupants) { + if (requestedOccupants) { + this.requestedOccupants = requestedOccupants; } - }, { - key: "onWebsocketMessage", - value: function onWebsocketMessage(event) { - this.session.receive(JSON.parse(event.data)); + if (!this.requestedOccupants) { + return; } - }, { - key: "addAvailableOccupant", - value: function addAvailableOccupant(occupantId) { - if (this.availableOccupants.indexOf(occupantId) === -1) { - this.availableOccupants.push(occupantId); + + // Add any requested, available, and non-pending occupants. + for (let i = 0; i < this.requestedOccupants.length; i++) { + const occupantId = this.requestedOccupants[i]; + if (!this.occupants[occupantId] && this.availableOccupants.indexOf(occupantId) !== -1 && !this.pendingOccupants.has(occupantId)) { + this.addOccupant(occupantId); } } - }, { - key: "removeAvailableOccupant", - value: function removeAvailableOccupant(occupantId) { - var idx = this.availableOccupants.indexOf(occupantId); - if (idx !== -1) { - this.availableOccupants.splice(idx, 1); + + // Remove any unrequested and currently added occupants. + for (let j = 0; j < this.availableOccupants.length; j++) { + const occupantId = this.availableOccupants[j]; + if (this.occupants[occupantId] && this.requestedOccupants.indexOf(occupantId) === -1) { + this.removeOccupant(occupantId); } } - }, { - key: "syncOccupants", - value: function syncOccupants(requestedOccupants) { - if (requestedOccupants) { - this.requestedOccupants = requestedOccupants; - } - if (!this.requestedOccupants) { - return; - } - // Add any requested, available, and non-pending occupants. - for (var i = 0; i < this.requestedOccupants.length; i++) { - var occupantId = this.requestedOccupants[i]; - if (!this.occupants[occupantId] && this.availableOccupants.indexOf(occupantId) !== -1 && !this.pendingOccupants.has(occupantId)) { - this.addOccupant(occupantId); - } - } + // Call the Networked AFrame callbacks for the updated occupants list. + this.onOccupantsChanged(this.occupants); + } + async addOccupant(occupantId) { + this.pendingOccupants.add(occupantId); + const availableOccupantsCount = this.availableOccupants.length; + if (availableOccupantsCount > AVAILABLE_OCCUPANTS_THRESHOLD) { + await randomDelay(0, MAX_SUBSCRIBE_DELAY); + } + const subscriber = await this.createSubscriber(occupantId); + if (subscriber) { + if (!this.pendingOccupants.has(occupantId)) { + subscriber.conn.close(); + } else { + this.pendingOccupants.delete(occupantId); + this.occupantIds.push(occupantId); + this.occupants[occupantId] = subscriber; + this.setMediaStream(occupantId, subscriber.mediaStream); - // Remove any unrequested and currently added occupants. - for (var j = 0; j < this.availableOccupants.length; j++) { - var _occupantId = this.availableOccupants[j]; - if (this.occupants[_occupantId] && this.requestedOccupants.indexOf(_occupantId) === -1) { - this.removeOccupant(_occupantId); - } + // Call the Networked AFrame callbacks for the new occupant. + this.onOccupantConnected(occupantId); } - - // Call the Networked AFrame callbacks for the updated occupants list. - this.onOccupantsChanged(this.occupants); } - }, { - key: "addOccupant", - value: function () { - var _addOccupant = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(occupantId) { - var availableOccupantsCount, subscriber; - return _regeneratorRuntime().wrap(function _callee2$(_context2) { - while (1) switch (_context2.prev = _context2.next) { - case 0: - this.pendingOccupants.add(occupantId); - availableOccupantsCount = this.availableOccupants.length; - if (!(availableOccupantsCount > AVAILABLE_OCCUPANTS_THRESHOLD)) { - _context2.next = 5; - break; - } - _context2.next = 5; - return randomDelay(0, MAX_SUBSCRIBE_DELAY); - case 5: - _context2.next = 7; - return this.createSubscriber(occupantId); - case 7: - subscriber = _context2.sent; - if (subscriber) { - if (!this.pendingOccupants.has(occupantId)) { - subscriber.conn.close(); - } else { - this.pendingOccupants["delete"](occupantId); - this.occupantIds.push(occupantId); - this.occupants[occupantId] = subscriber; - this.setMediaStream(occupantId, subscriber.mediaStream); - - // Call the Networked AFrame callbacks for the new occupant. - this.onOccupantConnected(occupantId); - } - } - case 9: - case "end": - return _context2.stop(); - } - }, _callee2, this); - })); - function addOccupant(_x) { - return _addOccupant.apply(this, arguments); - } - return addOccupant; - }() - }, { - key: "removeAllOccupants", - value: function removeAllOccupants() { - this.pendingOccupants.clear(); - for (var i = this.occupantIds.length - 1; i >= 0; i--) { - this.removeOccupant(this.occupantIds[i]); - } + } + removeAllOccupants() { + this.pendingOccupants.clear(); + for (let i = this.occupantIds.length - 1; i >= 0; i--) { + this.removeOccupant(this.occupantIds[i]); } - }, { - key: "removeOccupant", - value: function removeOccupant(occupantId) { - this.pendingOccupants["delete"](occupantId); - if (this.occupants[occupantId]) { - // Close the subscriber peer connection. Which also detaches the plugin handle. - this.occupants[occupantId].conn.close(); - delete this.occupants[occupantId]; - this.occupantIds.splice(this.occupantIds.indexOf(occupantId), 1); + } + removeOccupant(occupantId) { + this.pendingOccupants.delete(occupantId); + if (this.occupants[occupantId]) { + // Close the subscriber peer connection. Which also detaches the plugin handle. + this.occupants[occupantId].conn.close(); + delete this.occupants[occupantId]; + this.occupantIds.splice(this.occupantIds.indexOf(occupantId), 1); + } + if (this.mediaStreams[occupantId]) { + delete this.mediaStreams[occupantId]; + } + if (this.pendingMediaRequests.has(occupantId)) { + const msg = "The user disconnected before the media stream was resolved."; + this.pendingMediaRequests.get(occupantId).audio.reject(msg); + this.pendingMediaRequests.get(occupantId).video.reject(msg); + this.pendingMediaRequests.delete(occupantId); + } + + // Call the Networked AFrame callbacks for the removed occupant. + this.onOccupantDisconnected(occupantId); + } + associate(conn, handle) { + conn.addEventListener("icecandidate", ev => { + handle.sendTrickle(ev.candidate || null).catch(e => error("Error trickling ICE: %o", e)); + }); + conn.addEventListener("iceconnectionstatechange", ev => { + if (conn.iceConnectionState === "connected") { + console.log("ICE state changed to connected"); } - if (this.mediaStreams[occupantId]) { - delete this.mediaStreams[occupantId]; + if (conn.iceConnectionState === "disconnected") { + console.warn("ICE state changed to disconnected"); } - if (this.pendingMediaRequests.has(occupantId)) { - var msg = "The user disconnected before the media stream was resolved."; - this.pendingMediaRequests.get(occupantId).audio.reject(msg); - this.pendingMediaRequests.get(occupantId).video.reject(msg); - this.pendingMediaRequests["delete"](occupantId); + if (conn.iceConnectionState === "failed") { + console.warn("ICE failure detected. Reconnecting in 10s."); + this.performDelayedReconnect(); } + }); - // Call the Networked AFrame callbacks for the removed occupant. - this.onOccupantDisconnected(occupantId); - } - }, { - key: "associate", - value: function associate(conn, handle) { - var _this6 = this; - conn.addEventListener("icecandidate", function (ev) { - handle.sendTrickle(ev.candidate || null)["catch"](function (e) { - return error("Error trickling ICE: %o", e); - }); - }); - conn.addEventListener("iceconnectionstatechange", function (ev) { - if (conn.iceConnectionState === "connected") { - console.log("ICE state changed to connected"); - } - if (conn.iceConnectionState === "disconnected") { - console.warn("ICE state changed to disconnected"); - } - if (conn.iceConnectionState === "failed") { - console.warn("ICE failure detected. Reconnecting in 10s."); - _this6.performDelayedReconnect(); - } - }); - - // we have to debounce these because janus gets angry if you send it a new SDP before - // it's finished processing an existing SDP. in actuality, it seems like this is maybe - // too liberal and we need to wait some amount of time after an offer before sending another, - // but we don't currently know any good way of detecting exactly how long :( - conn.addEventListener("negotiationneeded", debounce(function (ev) { - debug("Sending new offer for handle: %o", handle); - var offer = conn.createOffer().then(_this6.configurePublisherSdp).then(_this6.fixSafariIceUFrag); - var local = offer.then(function (o) { - return conn.setLocalDescription(o); - }); - var remote = offer; - remote = remote.then(_this6.fixSafariIceUFrag).then(function (j) { - return handle.sendJsep(j); - }).then(function (r) { - return conn.setRemoteDescription(r.jsep); - }); - return Promise.all([local, remote])["catch"](function (e) { - return error("Error negotiating offer: %o", e); - }); - })); - handle.on("event", debounce(function (ev) { - var jsep = ev.jsep; - if (jsep && jsep.type == "offer") { - debug("Accepting new offer for handle: %o", handle); - var answer = conn.setRemoteDescription(_this6.configureSubscriberSdp(jsep)).then(function (_) { - return conn.createAnswer(); - }).then(_this6.fixSafariIceUFrag); - var local = answer.then(function (a) { - return conn.setLocalDescription(a); - }); - var remote = answer.then(function (j) { - return handle.sendJsep(j); - }); - return Promise.all([local, remote])["catch"](function (e) { - return error("Error negotiating answer: %o", e); - }); - } else { - // some other kind of event, nothing to do - return null; - } - })); - } - }, { - key: "createPublisher", - value: function () { - var _createPublisher = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3() { - var _this7 = this; - var handle, conn, webrtcup, reliableChannel, unreliableChannel, message, err, initialOccupants; - return _regeneratorRuntime().wrap(function _callee3$(_context3) { - while (1) switch (_context3.prev = _context3.next) { - case 0: - handle = new mj.JanusPluginHandle(this.session); - conn = new RTCPeerConnection(this.peerConnectionConfig || DEFAULT_PEER_CONNECTION_CONFIG); - debug("pub waiting for sfu"); - _context3.next = 5; - return handle.attach("janus.plugin.sfu", this.loops && this.clientId ? parseInt(this.clientId) % this.loops : undefined); - case 5: - this.associate(conn, handle); - debug("pub waiting for data channels & webrtcup"); - webrtcup = new Promise(function (resolve) { - return handle.on("webrtcup", resolve); - }); // Unreliable datachannel: sending and receiving component updates. - // Reliable datachannel: sending and recieving entity instantiations. - reliableChannel = conn.createDataChannel("reliable", { - ordered: true - }); - unreliableChannel = conn.createDataChannel("unreliable", { - ordered: false, - maxRetransmits: 0 - }); - reliableChannel.addEventListener("message", function (e) { - return _this7.onDataChannelMessage(e, "janus-reliable"); - }); - unreliableChannel.addEventListener("message", function (e) { - return _this7.onDataChannelMessage(e, "janus-unreliable"); - }); - _context3.next = 14; - return webrtcup; - case 14: - _context3.next = 16; - return untilDataChannelOpen(reliableChannel); - case 16: - _context3.next = 18; - return untilDataChannelOpen(unreliableChannel); - case 18: - // doing this here is sort of a hack around chrome renegotiation weirdness -- - // if we do it prior to webrtcup, chrome on gear VR will sometimes put a - // renegotiation offer in flight while the first offer was still being - // processed by janus. we should find some more principled way to figure out - // when janus is done in the future. - if (this.localMediaStream) { - this.localMediaStream.getTracks().forEach(function (track) { - conn.addTrack(track, _this7.localMediaStream); - }); - } - - // Handle all of the join and leave events. - handle.on("event", function (ev) { - var data = ev.plugindata.data; - if (data.event == "join" && data.room_id == _this7.room) { - if (_this7.delayedReconnectTimeout) { - // Don't create a new RTCPeerConnection, all RTCPeerConnection will be closed in less than 10s. - return; - } - _this7.addAvailableOccupant(data.user_id); - _this7.syncOccupants(); - } else if (data.event == "leave" && data.room_id == _this7.room) { - _this7.removeAvailableOccupant(data.user_id); - _this7.removeOccupant(data.user_id); - } else if (data.event == "blocked") { - document.body.dispatchEvent(new CustomEvent("blocked", { - detail: { - clientId: data.by - } - })); - } else if (data.event == "unblocked") { - document.body.dispatchEvent(new CustomEvent("unblocked", { - detail: { - clientId: data.by - } - })); - } else if (data.event === "data") { - _this7.onData(JSON.parse(data.body), "janus-event"); - } - }); - debug("pub waiting for join"); - - // Send join message to janus. Listen for join/leave messages. Automatically subscribe to all users' WebRTC data. - _context3.next = 23; - return this.sendJoin(handle, { - notifications: true, - data: true - }); - case 23: - message = _context3.sent; - if (message.plugindata.data.success) { - _context3.next = 29; - break; - } - err = message.plugindata.data.error; - console.error(err); - // We may get here because of an expired JWT. - // Close the connection ourself otherwise janus will close it after - // session_timeout because we didn't send any keepalive and this will - // trigger a delayed reconnect because of the iceconnectionstatechange - // listener for failure state. - // Even if the app code calls disconnect in case of error, disconnect - // won't close the peer connection because this.publisher is not set. - conn.close(); - throw err; - case 29: - initialOccupants = message.plugindata.data.response.users[this.room] || []; - if (initialOccupants.includes(this.clientId)) { - console.warn("Janus still has previous session for this client. Reconnecting in 10s."); - this.performDelayedReconnect(); - } - debug("publisher ready"); - return _context3.abrupt("return", { - handle: handle, - initialOccupants: initialOccupants, - reliableChannel: reliableChannel, - unreliableChannel: unreliableChannel, - conn: conn - }); - case 33: - case "end": - return _context3.stop(); - } - }, _callee3, this); - })); - function createPublisher() { - return _createPublisher.apply(this, arguments); + // we have to debounce these because janus gets angry if you send it a new SDP before + // it's finished processing an existing SDP. in actuality, it seems like this is maybe + // too liberal and we need to wait some amount of time after an offer before sending another, + // but we don't currently know any good way of detecting exactly how long :( + conn.addEventListener("negotiationneeded", debounce(ev => { + debug("Sending new offer for handle: %o", handle); + var offer = conn.createOffer().then(this.configurePublisherSdp).then(this.fixSafariIceUFrag); + var local = offer.then(o => conn.setLocalDescription(o)); + var remote = offer; + remote = remote.then(this.fixSafariIceUFrag).then(j => handle.sendJsep(j)).then(r => conn.setRemoteDescription(r.jsep)); + return Promise.all([local, remote]).catch(e => error("Error negotiating offer: %o", e)); + })); + handle.on("event", debounce(ev => { + var jsep = ev.jsep; + if (jsep && jsep.type == "offer") { + debug("Accepting new offer for handle: %o", handle); + var answer = conn.setRemoteDescription(this.configureSubscriberSdp(jsep)).then(_ => conn.createAnswer()).then(this.fixSafariIceUFrag); + var local = answer.then(a => conn.setLocalDescription(a)); + var remote = answer.then(j => handle.sendJsep(j)); + return Promise.all([local, remote]).catch(e => error("Error negotiating answer: %o", e)); + } else { + // some other kind of event, nothing to do + return null; } - return createPublisher; - }() - }, { - key: "configurePublisherSdp", - value: function configurePublisherSdp(jsep) { - jsep.sdp = jsep.sdp.replace(/a=fmtp:(109|111).*\r\n/g, function (line, pt) { - var parameters = Object.assign(sdpUtils.parseFmtp(line), OPUS_PARAMETERS); - return sdpUtils.writeFmtp({ - payloadType: pt, - parameters: parameters - }); + })); + } + async createPublisher() { + var handle = new mj.JanusPluginHandle(this.session); + var conn = new RTCPeerConnection(this.peerConnectionConfig || DEFAULT_PEER_CONNECTION_CONFIG); + debug("pub waiting for sfu"); + await handle.attach("janus.plugin.sfu", this.loops && this.clientId ? parseInt(this.clientId) % this.loops : undefined); + this.associate(conn, handle); + debug("pub waiting for data channels & webrtcup"); + var webrtcup = new Promise(resolve => handle.on("webrtcup", resolve)); + + // Unreliable datachannel: sending and receiving component updates. + // Reliable datachannel: sending and recieving entity instantiations. + var reliableChannel = conn.createDataChannel("reliable", { + ordered: true + }); + var unreliableChannel = conn.createDataChannel("unreliable", { + ordered: false, + maxRetransmits: 0 + }); + reliableChannel.addEventListener("message", e => this.onDataChannelMessage(e, "janus-reliable")); + unreliableChannel.addEventListener("message", e => this.onDataChannelMessage(e, "janus-unreliable")); + await webrtcup; + await untilDataChannelOpen(reliableChannel); + await untilDataChannelOpen(unreliableChannel); + + // doing this here is sort of a hack around chrome renegotiation weirdness -- + // if we do it prior to webrtcup, chrome on gear VR will sometimes put a + // renegotiation offer in flight while the first offer was still being + // processed by janus. we should find some more principled way to figure out + // when janus is done in the future. + if (this.localMediaStream) { + this.localMediaStream.getTracks().forEach(track => { + conn.addTrack(track, this.localMediaStream); }); - return jsep; } - }, { - key: "configureSubscriberSdp", - value: function configureSubscriberSdp(jsep) { - // todo: consider cleaning up these hacks to use sdputils - if (!isH264VideoSupported) { - if (navigator.userAgent.indexOf("HeadlessChrome") !== -1) { - // HeadlessChrome (e.g. puppeteer) doesn't support webrtc video streams, so we remove those lines from the SDP. - jsep.sdp = jsep.sdp.replace(/m=video[^]*m=/, "m="); - } - } - // TODO: Hack to get video working on Chrome for Android. https://groups.google.com/forum/#!topic/mozilla.dev.media/Ye29vuMTpo8 - if (navigator.userAgent.indexOf("Android") === -1) { - jsep.sdp = jsep.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"); - } else { - jsep.sdp = jsep.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"); - } - return jsep; - } - }, { - key: "fixSafariIceUFrag", - value: function () { - var _fixSafariIceUFrag = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(jsep) { - return _regeneratorRuntime().wrap(function _callee4$(_context4) { - while (1) switch (_context4.prev = _context4.next) { - case 0: - // Safari produces a \n instead of an \r\n for the ice-ufrag. See https://github.com/meetecho/janus-gateway/issues/1818 - jsep.sdp = jsep.sdp.replace(/[^\r]\na=ice-ufrag/g, "\r\na=ice-ufrag"); - return _context4.abrupt("return", jsep); - case 2: - case "end": - return _context4.stop(); + // Handle all of the join and leave events. + handle.on("event", ev => { + var data = ev.plugindata.data; + if (data.event == "join" && data.room_id == this.room) { + if (this.delayedReconnectTimeout) { + // Don't create a new RTCPeerConnection, all RTCPeerConnection will be closed in less than 10s. + return; + } + this.addAvailableOccupant(data.user_id); + this.syncOccupants(); + } else if (data.event == "leave" && data.room_id == this.room) { + this.removeAvailableOccupant(data.user_id); + this.removeOccupant(data.user_id); + } else if (data.event == "blocked") { + document.body.dispatchEvent(new CustomEvent("blocked", { + detail: { + clientId: data.by } - }, _callee4); - })); - function fixSafariIceUFrag(_x2) { - return _fixSafariIceUFrag.apply(this, arguments); - } - return fixSafariIceUFrag; - }() - }, { - key: "createSubscriber", - value: function () { - var _createSubscriber = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(occupantId) { - var _this8 = this; - var maxRetries, - handle, - conn, - webrtcFailed, - webrtcup, - mediaStream, - receivers, - _args5 = arguments; - return _regeneratorRuntime().wrap(function _callee5$(_context5) { - while (1) switch (_context5.prev = _context5.next) { - case 0: - maxRetries = _args5.length > 1 && _args5[1] !== undefined ? _args5[1] : 5; - if (!(this.availableOccupants.indexOf(occupantId) === -1)) { - _context5.next = 4; - break; - } - console.warn(occupantId + ": cancelled occupant connection, occupant left before subscription negotation."); - return _context5.abrupt("return", null); - case 4: - handle = new mj.JanusPluginHandle(this.session); - conn = new RTCPeerConnection(this.peerConnectionConfig || DEFAULT_PEER_CONNECTION_CONFIG); - debug(occupantId + ": sub waiting for sfu"); - _context5.next = 9; - return handle.attach("janus.plugin.sfu", this.loops ? parseInt(occupantId) % this.loops : undefined); - case 9: - this.associate(conn, handle); - debug(occupantId + ": sub waiting for join"); - if (!(this.availableOccupants.indexOf(occupantId) === -1)) { - _context5.next = 15; - break; - } - conn.close(); - console.warn(occupantId + ": cancelled occupant connection, occupant left after attach"); - return _context5.abrupt("return", null); - case 15: - webrtcFailed = false; - webrtcup = new Promise(function (resolve) { - var leftInterval = setInterval(function () { - if (_this8.availableOccupants.indexOf(occupantId) === -1) { - clearInterval(leftInterval); - resolve(); - } - }, 1000); - var timeout = setTimeout(function () { - clearInterval(leftInterval); - webrtcFailed = true; - resolve(); - }, SUBSCRIBE_TIMEOUT_MS); - handle.on("webrtcup", function () { - clearTimeout(timeout); - clearInterval(leftInterval); - resolve(); - }); - }); // Send join message to janus. Don't listen for join/leave messages. Subscribe to the occupant's media. - // Janus should send us an offer for this occupant's media in response to this. - _context5.next = 19; - return this.sendJoin(handle, { - media: occupantId - }); - case 19: - if (!(this.availableOccupants.indexOf(occupantId) === -1)) { - _context5.next = 23; - break; - } - conn.close(); - console.warn(occupantId + ": cancelled occupant connection, occupant left after join"); - return _context5.abrupt("return", null); - case 23: - debug(occupantId + ": sub waiting for webrtcup"); - _context5.next = 26; - return webrtcup; - case 26: - if (!(this.availableOccupants.indexOf(occupantId) === -1)) { - _context5.next = 30; - break; - } - conn.close(); - console.warn(occupantId + ": cancel occupant connection, occupant left during or after webrtcup"); - return _context5.abrupt("return", null); - case 30: - if (!webrtcFailed) { - _context5.next = 39; - break; - } - conn.close(); - if (!(maxRetries > 0)) { - _context5.next = 37; - break; - } - console.warn(occupantId + ": webrtc up timed out, retrying"); - return _context5.abrupt("return", this.createSubscriber(occupantId, maxRetries - 1)); - case 37: - console.warn(occupantId + ": webrtc up timed out"); - return _context5.abrupt("return", null); - case 39: - if (!(isSafari && !this._iOSHackDelayedInitialPeer)) { - _context5.next = 43; - break; - } - _context5.next = 42; - return new Promise(function (resolve) { - return setTimeout(resolve, 3000); - }); - case 42: - this._iOSHackDelayedInitialPeer = true; - case 43: - mediaStream = new MediaStream(); - receivers = conn.getReceivers(); - receivers.forEach(function (receiver) { - if (receiver.track) { - mediaStream.addTrack(receiver.track); - } - }); - if (mediaStream.getTracks().length === 0) { - mediaStream = null; - } - debug(occupantId + ": subscriber ready"); - return _context5.abrupt("return", { - handle: handle, - mediaStream: mediaStream, - conn: conn - }); - case 49: - case "end": - return _context5.stop(); + })); + } else if (data.event == "unblocked") { + document.body.dispatchEvent(new CustomEvent("unblocked", { + detail: { + clientId: data.by } - }, _callee5, this); - })); - function createSubscriber(_x3) { - return _createSubscriber.apply(this, arguments); + })); + } else if (data.event === "data") { + this.onData(JSON.parse(data.body), "janus-event"); } - return createSubscriber; - }() - }, { - key: "sendJoin", - value: function sendJoin(handle, subscribe) { - return handle.sendMessage({ - kind: "join", - room_id: this.room, - user_id: this.clientId, - subscribe: subscribe, - token: this.joinToken + }); + debug("pub waiting for join"); + + // Send join message to janus. Listen for join/leave messages. Automatically subscribe to all users' WebRTC data. + var message = await this.sendJoin(handle, { + notifications: true, + data: true + }); + if (!message.plugindata.data.success) { + const err = message.plugindata.data.error; + console.error(err); + // We may get here because of an expired JWT. + // Close the connection ourself otherwise janus will close it after + // session_timeout because we didn't send any keepalive and this will + // trigger a delayed reconnect because of the iceconnectionstatechange + // listener for failure state. + // Even if the app code calls disconnect in case of error, disconnect + // won't close the peer connection because this.publisher is not set. + conn.close(); + throw err; + } + var initialOccupants = message.plugindata.data.response.users[this.room] || []; + if (initialOccupants.includes(this.clientId)) { + console.warn("Janus still has previous session for this client. Reconnecting in 10s."); + this.performDelayedReconnect(); + } + debug("publisher ready"); + return { + handle, + initialOccupants, + reliableChannel, + unreliableChannel, + conn + }; + } + configurePublisherSdp(jsep) { + jsep.sdp = jsep.sdp.replace(/a=fmtp:(109|111).*\r\n/g, (line, pt) => { + const parameters = Object.assign(sdpUtils.parseFmtp(line), OPUS_PARAMETERS); + return sdpUtils.writeFmtp({ + payloadType: pt, + parameters: parameters }); - } - }, { - key: "toggleFreeze", - value: function toggleFreeze() { - if (this.frozen) { - this.unfreeze(); - } else { - this.freeze(); + }); + return jsep; + } + configureSubscriberSdp(jsep) { + // todo: consider cleaning up these hacks to use sdputils + if (!isH264VideoSupported) { + if (navigator.userAgent.indexOf("HeadlessChrome") !== -1) { + // HeadlessChrome (e.g. puppeteer) doesn't support webrtc video streams, so we remove those lines from the SDP. + jsep.sdp = jsep.sdp.replace(/m=video[^]*m=/, "m="); } } - }, { - key: "freeze", - value: function freeze() { - this.frozen = true; - } - }, { - key: "unfreeze", - value: function unfreeze() { - this.frozen = false; - this.flushPendingUpdates(); + + // TODO: Hack to get video working on Chrome for Android. https://groups.google.com/forum/#!topic/mozilla.dev.media/Ye29vuMTpo8 + if (navigator.userAgent.indexOf("Android") === -1) { + jsep.sdp = jsep.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"); + } else { + jsep.sdp = jsep.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"); } - }, { - key: "dataForUpdateMultiMessage", - value: function dataForUpdateMultiMessage(networkId, message) { - // "d" is an array of entity datas, where each item in the array represents a unique entity and contains - // metadata for the entity, and an array of components that have been updated on the entity. - // This method finds the data corresponding to the given networkId. - for (var i = 0, l = message.data.d.length; i < l; i++) { - var data = message.data.d[i]; - if (data.networkId === networkId) { - return data; - } - } + return jsep; + } + async fixSafariIceUFrag(jsep) { + // Safari produces a \n instead of an \r\n for the ice-ufrag. See https://github.com/meetecho/janus-gateway/issues/1818 + jsep.sdp = jsep.sdp.replace(/[^\r]\na=ice-ufrag/g, "\r\na=ice-ufrag"); + return jsep; + } + async createSubscriber(occupantId, maxRetries = 5) { + if (this.availableOccupants.indexOf(occupantId) === -1) { + console.warn(occupantId + ": cancelled occupant connection, occupant left before subscription negotation."); return null; } - }, { - key: "getPendingData", - value: function getPendingData(networkId, message) { - if (!message) return null; - var data = message.dataType === "um" ? this.dataForUpdateMultiMessage(networkId, message) : message.data; - - // Ignore messages relating to users who have disconnected since freezing, their entities - // will have aleady been removed by NAF. - // Note that delete messages have no "owner" so we have to check for that as well. - if (data.owner && !this.occupants[data.owner]) return null; - - // Ignore messages from users that we may have blocked while frozen. - if (data.owner && this.blockedClients.has(data.owner)) return null; - return data; + var handle = new mj.JanusPluginHandle(this.session); + var conn = new RTCPeerConnection(this.peerConnectionConfig || DEFAULT_PEER_CONNECTION_CONFIG); + debug(occupantId + ": sub waiting for sfu"); + await handle.attach("janus.plugin.sfu", this.loops ? parseInt(occupantId) % this.loops : undefined); + this.associate(conn, handle); + debug(occupantId + ": sub waiting for join"); + if (this.availableOccupants.indexOf(occupantId) === -1) { + conn.close(); + console.warn(occupantId + ": cancelled occupant connection, occupant left after attach"); + return null; } + let webrtcFailed = false; + const webrtcup = new Promise(resolve => { + const leftInterval = setInterval(() => { + if (this.availableOccupants.indexOf(occupantId) === -1) { + clearInterval(leftInterval); + resolve(); + } + }, 1000); + const timeout = setTimeout(() => { + clearInterval(leftInterval); + webrtcFailed = true; + resolve(); + }, SUBSCRIBE_TIMEOUT_MS); + handle.on("webrtcup", () => { + clearTimeout(timeout); + clearInterval(leftInterval); + resolve(); + }); + }); - // Used externally - }, { - key: "getPendingDataForNetworkId", - value: function getPendingDataForNetworkId(networkId) { - return this.getPendingData(networkId, this.frozenUpdates.get(networkId)); + // Send join message to janus. Don't listen for join/leave messages. Subscribe to the occupant's media. + // Janus should send us an offer for this occupant's media in response to this. + await this.sendJoin(handle, { + media: occupantId + }); + if (this.availableOccupants.indexOf(occupantId) === -1) { + conn.close(); + console.warn(occupantId + ": cancelled occupant connection, occupant left after join"); + return null; } - }, { - key: "flushPendingUpdates", - value: function flushPendingUpdates() { - var _iterator = _createForOfIteratorHelper(this.frozenUpdates), - _step; - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - var _step$value = _slicedToArray(_step.value, 2), - networkId = _step$value[0], - message = _step$value[1]; - var data = this.getPendingData(networkId, message); - if (!data) continue; - - // Override the data type on "um" messages types, since we extract entity updates from "um" messages into - // individual frozenUpdates in storeSingleMessage. - var dataType = message.dataType === "um" ? "u" : message.dataType; - this.onOccupantMessage(null, dataType, data, message.source); - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - this.frozenUpdates.clear(); + debug(occupantId + ": sub waiting for webrtcup"); + await webrtcup; + if (this.availableOccupants.indexOf(occupantId) === -1) { + conn.close(); + console.warn(occupantId + ": cancel occupant connection, occupant left during or after webrtcup"); + return null; } - }, { - key: "storeMessage", - value: function storeMessage(message) { - if (message.dataType === "um") { - // UpdateMulti - for (var i = 0, l = message.data.d.length; i < l; i++) { - this.storeSingleMessage(message, i); - } + if (webrtcFailed) { + conn.close(); + if (maxRetries > 0) { + console.warn(occupantId + ": webrtc up timed out, retrying"); + return this.createSubscriber(occupantId, maxRetries - 1); } else { - this.storeSingleMessage(message); + console.warn(occupantId + ": webrtc up timed out"); + return null; } } - }, { - key: "storeSingleMessage", - value: function storeSingleMessage(message, index) { - var data = index !== undefined ? message.data.d[index] : message.data; - var dataType = message.dataType; - var source = message.source; - var networkId = data.networkId; - if (!this.frozenUpdates.has(networkId)) { - this.frozenUpdates.set(networkId, message); - } else { - var storedMessage = this.frozenUpdates.get(networkId); - var storedData = storedMessage.dataType === "um" ? this.dataForUpdateMultiMessage(networkId, storedMessage) : storedMessage.data; - - // Avoid updating components if the entity data received did not come from the current owner. - var isOutdatedMessage = data.lastOwnerTime < storedData.lastOwnerTime; - var isContemporaneousMessage = data.lastOwnerTime === storedData.lastOwnerTime; - if (isOutdatedMessage || isContemporaneousMessage && storedData.owner > data.owner) { - return; - } - if (dataType === "r") { - var createdWhileFrozen = storedData && storedData.isFirstSync; - if (createdWhileFrozen) { - // If the entity was created and deleted while frozen, don't bother conveying anything to the consumer. - this.frozenUpdates["delete"](networkId); - } else { - // Delete messages override any other messages for this entity - this.frozenUpdates.set(networkId, message); - } - } else { - // merge in component updates - if (storedData.components && data.components) { - Object.assign(storedData.components, data.components); - } - } + if (isSafari && !this._iOSHackDelayedInitialPeer) { + // HACK: the first peer on Safari during page load can fail to work if we don't + // wait some time before continuing here. See: https://github.com/mozilla/hubs/pull/1692 + await new Promise(resolve => setTimeout(resolve, 3000)); + this._iOSHackDelayedInitialPeer = true; + } + var mediaStream = new MediaStream(); + var receivers = conn.getReceivers(); + receivers.forEach(receiver => { + if (receiver.track) { + mediaStream.addTrack(receiver.track); } + }); + if (mediaStream.getTracks().length === 0) { + mediaStream = null; } - }, { - key: "onDataChannelMessage", - value: function onDataChannelMessage(e, source) { - this.onData(JSON.parse(e.data), source); + debug(occupantId + ": subscriber ready"); + return { + handle, + mediaStream, + conn + }; + } + sendJoin(handle, subscribe) { + return handle.sendMessage({ + kind: "join", + room_id: this.room, + user_id: this.clientId, + subscribe, + token: this.joinToken + }); + } + toggleFreeze() { + if (this.frozen) { + this.unfreeze(); + } else { + this.freeze(); } - }, { - key: "onData", - value: function onData(message, source) { - if (debug.enabled) { - debug("DC in: ".concat(message)); - } - if (!message.dataType) return; - message.source = source; - if (this.frozen) { - this.storeMessage(message); - } else { - this.onOccupantMessage(null, message.dataType, message.data, message.source); + } + freeze() { + this.frozen = true; + } + unfreeze() { + this.frozen = false; + this.flushPendingUpdates(); + } + dataForUpdateMultiMessage(networkId, message) { + // "d" is an array of entity datas, where each item in the array represents a unique entity and contains + // metadata for the entity, and an array of components that have been updated on the entity. + // This method finds the data corresponding to the given networkId. + for (let i = 0, l = message.data.d.length; i < l; i++) { + const data = message.data.d[i]; + if (data.networkId === networkId) { + return data; } } - }, { - key: "shouldStartConnectionTo", - value: function shouldStartConnectionTo(client) { - return true; - } - }, { - key: "startStreamConnection", - value: function startStreamConnection(client) {} - }, { - key: "closeStreamConnection", - value: function closeStreamConnection(client) {} - }, { - key: "getConnectStatus", - value: function getConnectStatus(clientId) { - return this.occupants[clientId] ? NAF.adapters.IS_CONNECTED : NAF.adapters.NOT_CONNECTED; + return null; + } + getPendingData(networkId, message) { + if (!message) return null; + let data = message.dataType === "um" ? this.dataForUpdateMultiMessage(networkId, message) : message.data; + + // Ignore messages relating to users who have disconnected since freezing, their entities + // will have aleady been removed by NAF. + // Note that delete messages have no "owner" so we have to check for that as well. + if (data.owner && !this.occupants[data.owner]) return null; + + // Ignore messages from users that we may have blocked while frozen. + if (data.owner && this.blockedClients.has(data.owner)) return null; + return data; + } + + // Used externally + getPendingDataForNetworkId(networkId) { + return this.getPendingData(networkId, this.frozenUpdates.get(networkId)); + } + flushPendingUpdates() { + for (const [networkId, message] of this.frozenUpdates) { + let data = this.getPendingData(networkId, message); + if (!data) continue; + + // Override the data type on "um" messages types, since we extract entity updates from "um" messages into + // individual frozenUpdates in storeSingleMessage. + const dataType = message.dataType === "um" ? "u" : message.dataType; + this.onOccupantMessage(null, dataType, data, message.source); } - }, { - key: "updateTimeOffset", - value: function () { - var _updateTimeOffset = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6() { - var _this9 = this; - var clientSentTime, res, precision, serverReceivedTime, clientReceivedTime, serverTime, timeOffset; - return _regeneratorRuntime().wrap(function _callee6$(_context6) { - while (1) switch (_context6.prev = _context6.next) { - case 0: - if (!this.isDisconnected()) { - _context6.next = 2; - break; - } - return _context6.abrupt("return"); - case 2: - clientSentTime = Date.now(); - _context6.next = 5; - return fetch(document.location.href, { - method: "HEAD", - cache: "no-cache" - }); - case 5: - res = _context6.sent; - precision = 1000; - serverReceivedTime = new Date(res.headers.get("Date")).getTime() + precision / 2; - clientReceivedTime = Date.now(); - serverTime = serverReceivedTime + (clientReceivedTime - clientSentTime) / 2; - timeOffset = serverTime - clientReceivedTime; - this.serverTimeRequests++; - if (this.serverTimeRequests <= 10) { - this.timeOffsets.push(timeOffset); - } else { - this.timeOffsets[this.serverTimeRequests % 10] = timeOffset; - } - this.avgTimeOffset = this.timeOffsets.reduce(function (acc, offset) { - return acc += offset; - }, 0) / this.timeOffsets.length; - if (this.serverTimeRequests > 10) { - debug("new server time offset: ".concat(this.avgTimeOffset, "ms")); - setTimeout(function () { - return _this9.updateTimeOffset(); - }, 5 * 60 * 1000); // Sync clock every 5 minutes. - } else { - this.updateTimeOffset(); - } - case 15: - case "end": - return _context6.stop(); - } - }, _callee6, this); - })); - function updateTimeOffset() { - return _updateTimeOffset.apply(this, arguments); + this.frozenUpdates.clear(); + } + storeMessage(message) { + if (message.dataType === "um") { + // UpdateMulti + for (let i = 0, l = message.data.d.length; i < l; i++) { + this.storeSingleMessage(message, i); } - return updateTimeOffset; - }() - }, { - key: "getServerTime", - value: function getServerTime() { - return Date.now() + this.avgTimeOffset; + } else { + this.storeSingleMessage(message); } - }, { - key: "getMediaStream", - value: function getMediaStream(clientId) { - var _this10 = this; - var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "audio"; - if (this.mediaStreams[clientId]) { - debug("Already had ".concat(type, " for ").concat(clientId)); - return Promise.resolve(this.mediaStreams[clientId][type]); + } + storeSingleMessage(message, index) { + const data = index !== undefined ? message.data.d[index] : message.data; + const dataType = message.dataType; + const source = message.source; + const networkId = data.networkId; + if (!this.frozenUpdates.has(networkId)) { + this.frozenUpdates.set(networkId, message); + } else { + const storedMessage = this.frozenUpdates.get(networkId); + const storedData = storedMessage.dataType === "um" ? this.dataForUpdateMultiMessage(networkId, storedMessage) : storedMessage.data; + + // Avoid updating components if the entity data received did not come from the current owner. + const isOutdatedMessage = data.lastOwnerTime < storedData.lastOwnerTime; + const isContemporaneousMessage = data.lastOwnerTime === storedData.lastOwnerTime; + if (isOutdatedMessage || isContemporaneousMessage && storedData.owner > data.owner) { + return; + } + if (dataType === "r") { + const createdWhileFrozen = storedData && storedData.isFirstSync; + if (createdWhileFrozen) { + // If the entity was created and deleted while frozen, don't bother conveying anything to the consumer. + this.frozenUpdates.delete(networkId); + } else { + // Delete messages override any other messages for this entity + this.frozenUpdates.set(networkId, message); + } } else { - debug("Waiting on ".concat(type, " for ").concat(clientId)); - if (!this.pendingMediaRequests.has(clientId)) { - this.pendingMediaRequests.set(clientId, {}); - var audioPromise = new Promise(function (resolve, reject) { - _this10.pendingMediaRequests.get(clientId).audio = { - resolve: resolve, - reject: reject - }; - }); - var videoPromise = new Promise(function (resolve, reject) { - _this10.pendingMediaRequests.get(clientId).video = { - resolve: resolve, - reject: reject - }; - }); - this.pendingMediaRequests.get(clientId).audio.promise = audioPromise; - this.pendingMediaRequests.get(clientId).video.promise = videoPromise; - audioPromise["catch"](function (e) { - return console.warn("".concat(clientId, " getMediaStream Audio Error"), e); - }); - videoPromise["catch"](function (e) { - return console.warn("".concat(clientId, " getMediaStream Video Error"), e); - }); + // merge in component updates + if (storedData.components && data.components) { + Object.assign(storedData.components, data.components); } - return this.pendingMediaRequests.get(clientId)[type].promise; } } - }, { - key: "setMediaStream", - value: function setMediaStream(clientId, stream) { - // Safari doesn't like it when you use single a mixed media stream where one of the tracks is inactive, so we - // split the tracks into two streams. - var audioStream = new MediaStream(); - try { - stream.getAudioTracks().forEach(function (track) { - return audioStream.addTrack(track); + } + onDataChannelMessage(e, source) { + this.onData(JSON.parse(e.data), source); + } + onData(message, source) { + if (debug.enabled) { + debug(`DC in: ${message}`); + } + if (!message.dataType) return; + message.source = source; + if (this.frozen) { + this.storeMessage(message); + } else { + this.onOccupantMessage(null, message.dataType, message.data, message.source); + } + } + shouldStartConnectionTo(client) { + return true; + } + startStreamConnection(client) {} + closeStreamConnection(client) {} + getConnectStatus(clientId) { + return this.occupants[clientId] ? NAF.adapters.IS_CONNECTED : NAF.adapters.NOT_CONNECTED; + } + async updateTimeOffset() { + if (this.isDisconnected()) return; + const clientSentTime = Date.now(); + const res = await fetch(document.location.href, { + method: "HEAD", + cache: "no-cache" + }); + const precision = 1000; + const serverReceivedTime = new Date(res.headers.get("Date")).getTime() + precision / 2; + const clientReceivedTime = Date.now(); + const serverTime = serverReceivedTime + (clientReceivedTime - clientSentTime) / 2; + const timeOffset = serverTime - clientReceivedTime; + this.serverTimeRequests++; + if (this.serverTimeRequests <= 10) { + this.timeOffsets.push(timeOffset); + } else { + this.timeOffsets[this.serverTimeRequests % 10] = timeOffset; + } + this.avgTimeOffset = this.timeOffsets.reduce((acc, offset) => acc += offset, 0) / this.timeOffsets.length; + if (this.serverTimeRequests > 10) { + debug(`new server time offset: ${this.avgTimeOffset}ms`); + setTimeout(() => this.updateTimeOffset(), 5 * 60 * 1000); // Sync clock every 5 minutes. + } else { + this.updateTimeOffset(); + } + } + getServerTime() { + return Date.now() + this.avgTimeOffset; + } + getMediaStream(clientId, type = "audio") { + if (this.mediaStreams[clientId]) { + debug(`Already had ${type} for ${clientId}`); + return Promise.resolve(this.mediaStreams[clientId][type]); + } else { + debug(`Waiting on ${type} for ${clientId}`); + if (!this.pendingMediaRequests.has(clientId)) { + this.pendingMediaRequests.set(clientId, {}); + const audioPromise = new Promise((resolve, reject) => { + this.pendingMediaRequests.get(clientId).audio = { + resolve, + reject + }; }); - } catch (e) { - console.warn("".concat(clientId, " setMediaStream Audio Error"), e); - } - var videoStream = new MediaStream(); - try { - stream.getVideoTracks().forEach(function (track) { - return videoStream.addTrack(track); + const videoPromise = new Promise((resolve, reject) => { + this.pendingMediaRequests.get(clientId).video = { + resolve, + reject + }; }); - } catch (e) { - console.warn("".concat(clientId, " setMediaStream Video Error"), e); + this.pendingMediaRequests.get(clientId).audio.promise = audioPromise; + this.pendingMediaRequests.get(clientId).video.promise = videoPromise; + audioPromise.catch(e => console.warn(`${clientId} getMediaStream Audio Error`, e)); + videoPromise.catch(e => console.warn(`${clientId} getMediaStream Video Error`, e)); } - this.mediaStreams[clientId] = { - audio: audioStream, - video: videoStream - }; + return this.pendingMediaRequests.get(clientId)[type].promise; + } + } + setMediaStream(clientId, stream) { + // Safari doesn't like it when you use single a mixed media stream where one of the tracks is inactive, so we + // split the tracks into two streams. + const audioStream = new MediaStream(); + try { + stream.getAudioTracks().forEach(track => audioStream.addTrack(track)); + } catch (e) { + console.warn(`${clientId} setMediaStream Audio Error`, e); + } + const videoStream = new MediaStream(); + try { + stream.getVideoTracks().forEach(track => videoStream.addTrack(track)); + } catch (e) { + console.warn(`${clientId} setMediaStream Video Error`, e); + } + this.mediaStreams[clientId] = { + audio: audioStream, + video: videoStream + }; - // Resolve the promise for the user's media stream if it exists. - if (this.pendingMediaRequests.has(clientId)) { - this.pendingMediaRequests.get(clientId).audio.resolve(audioStream); - this.pendingMediaRequests.get(clientId).video.resolve(videoStream); - } + // Resolve the promise for the user's media stream if it exists. + if (this.pendingMediaRequests.has(clientId)) { + this.pendingMediaRequests.get(clientId).audio.resolve(audioStream); + this.pendingMediaRequests.get(clientId).video.resolve(videoStream); } - }, { - key: "setLocalMediaStream", - value: function () { - var _setLocalMediaStream = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7(stream) { - var _this11 = this; - var existingSenders, newSenders, tracks, _loop, i; - return _regeneratorRuntime().wrap(function _callee7$(_context8) { - while (1) switch (_context8.prev = _context8.next) { - case 0: - if (!(this.publisher && this.publisher.conn)) { - _context8.next = 12; - break; - } - existingSenders = this.publisher.conn.getSenders(); - newSenders = []; - tracks = stream.getTracks(); - _loop = /*#__PURE__*/_regeneratorRuntime().mark(function _loop() { - var t, sender; - return _regeneratorRuntime().wrap(function _loop$(_context7) { - while (1) switch (_context7.prev = _context7.next) { - case 0: - t = tracks[i]; - sender = existingSenders.find(function (s) { - return s.track != null && s.track.kind == t.kind; - }); - if (!(sender != null)) { - _context7.next = 14; - break; - } - if (!sender.replaceTrack) { - _context7.next = 9; - break; - } - _context7.next = 6; - return sender.replaceTrack(t); - case 6: - // Workaround https://bugzilla.mozilla.org/show_bug.cgi?id=1576771 - if (t.kind === "video" && t.enabled && navigator.userAgent.toLowerCase().indexOf('firefox') > -1) { - t.enabled = false; - setTimeout(function () { - return t.enabled = true; - }, 1000); - } - _context7.next = 11; - break; - case 9: - // Fallback for browsers that don't support replaceTrack. At this time of this writing - // most browsers support it, and testing this code path seems to not work properly - // in Chrome anymore. - stream.removeTrack(sender.track); - stream.addTrack(t); - case 11: - newSenders.push(sender); - _context7.next = 15; - break; - case 14: - newSenders.push(_this11.publisher.conn.addTrack(t, stream)); - case 15: - case "end": - return _context7.stop(); - } - }, _loop); - }); - i = 0; - case 6: - if (!(i < tracks.length)) { - _context8.next = 11; - break; - } - return _context8.delegateYield(_loop(), "t0", 8); - case 8: - i++; - _context8.next = 6; - break; - case 11: - existingSenders.forEach(function (s) { - if (!newSenders.includes(s)) { - s.track.enabled = false; - } - }); - case 12: - this.localMediaStream = stream; - this.setMediaStream(this.clientId, stream); - case 14: - case "end": - return _context8.stop(); - } - }, _callee7, this); - })); - function setLocalMediaStream(_x4) { - return _setLocalMediaStream.apply(this, arguments); - } - return setLocalMediaStream; - }() - }, { - key: "enableMicrophone", - value: function enableMicrophone(enabled) { - if (this.publisher && this.publisher.conn) { - this.publisher.conn.getSenders().forEach(function (s) { - if (s.track.kind == "audio") { - s.track.enabled = enabled; + } + async setLocalMediaStream(stream) { + // our job here is to make sure the connection winds up with RTP senders sending the stuff in this stream, + // and not the stuff that isn't in this stream. strategy is to replace existing tracks if we can, add tracks + // that we can't replace, and disable tracks that don't exist anymore. + + // note that we don't ever remove a track from the stream -- since Janus doesn't support Unified Plan, we absolutely + // 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 + // you remove a track from an existing stream.) + if (this.publisher && this.publisher.conn) { + const existingSenders = this.publisher.conn.getSenders(); + const newSenders = []; + const tracks = stream.getTracks(); + for (let i = 0; i < tracks.length; i++) { + const t = tracks[i]; + const sender = existingSenders.find(s => s.track != null && s.track.kind == t.kind); + if (sender != null) { + if (sender.replaceTrack) { + await sender.replaceTrack(t); + + // Workaround https://bugzilla.mozilla.org/show_bug.cgi?id=1576771 + if (t.kind === "video" && t.enabled && navigator.userAgent.toLowerCase().indexOf('firefox') > -1) { + t.enabled = false; + setTimeout(() => t.enabled = true, 1000); + } + } else { + // Fallback for browsers that don't support replaceTrack. At this time of this writing + // most browsers support it, and testing this code path seems to not work properly + // in Chrome anymore. + stream.removeTrack(sender.track); + stream.addTrack(t); } - }); + newSenders.push(sender); + } else { + newSenders.push(this.publisher.conn.addTrack(t, stream)); + } } + existingSenders.forEach(s => { + if (!newSenders.includes(s)) { + s.track.enabled = false; + } + }); } - }, { - key: "sendData", - value: function sendData(clientId, dataType, data) { - if (!this.publisher) { - console.warn("sendData called without a publisher"); - } else { - switch (this.unreliableTransport) { - case "websocket": + this.localMediaStream = stream; + this.setMediaStream(this.clientId, stream); + } + enableMicrophone(enabled) { + if (this.publisher && this.publisher.conn) { + this.publisher.conn.getSenders().forEach(s => { + if (s.track.kind == "audio") { + s.track.enabled = enabled; + } + }); + } + } + sendData(clientId, dataType, data) { + if (!this.publisher) { + console.warn("sendData called without a publisher"); + } else { + switch (this.unreliableTransport) { + case "websocket": + if (this.ws.readyState === 1) { + // OPEN this.publisher.handle.sendMessage({ kind: "data", body: JSON.stringify({ - dataType: dataType, - data: data + dataType, + data }), whom: clientId }); - break; - case "datachannel": + } + break; + case "datachannel": + if (this.publisher.unreliableChannel.readyState === "open") { this.publisher.unreliableChannel.send(JSON.stringify({ - clientId: clientId, - dataType: dataType, - data: data + clientId, + dataType, + data })); - break; - default: - this.unreliableTransport(clientId, dataType, data); - break; - } + } + break; + default: + this.unreliableTransport(clientId, dataType, data); + break; } } - }, { - key: "sendDataGuaranteed", - value: function sendDataGuaranteed(clientId, dataType, data) { - if (!this.publisher) { - console.warn("sendDataGuaranteed called without a publisher"); - } else { - switch (this.reliableTransport) { - case "websocket": + } + sendDataGuaranteed(clientId, dataType, data) { + if (!this.publisher) { + console.warn("sendDataGuaranteed called without a publisher"); + } else { + switch (this.reliableTransport) { + case "websocket": + if (this.ws.readyState === 1) { + // OPEN this.publisher.handle.sendMessage({ kind: "data", body: JSON.stringify({ - dataType: dataType, - data: data + dataType, + data }), whom: clientId }); - break; - case "datachannel": + } + break; + case "datachannel": + if (this.publisher.reliableChannel.readyState === "open") { this.publisher.reliableChannel.send(JSON.stringify({ - clientId: clientId, - dataType: dataType, - data: data + clientId, + dataType, + data })); - break; - default: - this.reliableTransport(clientId, dataType, data); - break; - } + } + break; + default: + this.reliableTransport(clientId, dataType, data); + break; } } - }, { - key: "broadcastData", - value: function broadcastData(dataType, data) { - if (!this.publisher) { - console.warn("broadcastData called without a publisher"); - } else { - switch (this.unreliableTransport) { - case "websocket": + } + broadcastData(dataType, data) { + if (!this.publisher) { + console.warn("broadcastData called without a publisher"); + } else { + switch (this.unreliableTransport) { + case "websocket": + if (this.ws.readyState === 1) { + // OPEN this.publisher.handle.sendMessage({ kind: "data", body: JSON.stringify({ - dataType: dataType, - data: data + dataType, + data }) }); - break; - case "datachannel": + } + break; + case "datachannel": + if (this.publisher.unreliableChannel.readyState === "open") { this.publisher.unreliableChannel.send(JSON.stringify({ - dataType: dataType, - data: data + dataType, + data })); - break; - default: - this.unreliableTransport(undefined, dataType, data); - break; - } + } + break; + default: + this.unreliableTransport(undefined, dataType, data); + break; } } - }, { - key: "broadcastDataGuaranteed", - value: function broadcastDataGuaranteed(dataType, data) { - if (!this.publisher) { - console.warn("broadcastDataGuaranteed called without a publisher"); - } else { - switch (this.reliableTransport) { - case "websocket": + } + broadcastDataGuaranteed(dataType, data) { + if (!this.publisher) { + console.warn("broadcastDataGuaranteed called without a publisher"); + } else { + switch (this.reliableTransport) { + case "websocket": + if (this.ws.readyState === 1) { + // OPEN this.publisher.handle.sendMessage({ kind: "data", body: JSON.stringify({ - dataType: dataType, - data: data + dataType, + data }) }); - break; - case "datachannel": + } + break; + case "datachannel": + if (this.publisher.reliableChannel.readyState === "open") { this.publisher.reliableChannel.send(JSON.stringify({ - dataType: dataType, - data: data + dataType, + data })); - break; - default: - this.reliableTransport(undefined, dataType, data); - break; - } - } - } - }, { - key: "kick", - value: function kick(clientId, permsToken) { - return this.publisher.handle.sendMessage({ - kind: "kick", - room_id: this.room, - user_id: clientId, - token: permsToken - }).then(function () { - document.body.dispatchEvent(new CustomEvent("kicked", { - detail: { - clientId: clientId - } - })); - }); - } - }, { - key: "block", - value: function block(clientId) { - var _this12 = this; - return this.publisher.handle.sendMessage({ - kind: "block", - whom: clientId - }).then(function () { - _this12.blockedClients.set(clientId, true); - document.body.dispatchEvent(new CustomEvent("blocked", { - detail: { - clientId: clientId } - })); - }); - } - }, { - key: "unblock", - value: function unblock(clientId) { - var _this13 = this; - return this.publisher.handle.sendMessage({ - kind: "unblock", - whom: clientId - }).then(function () { - _this13.blockedClients["delete"](clientId); - document.body.dispatchEvent(new CustomEvent("unblocked", { - detail: { - clientId: clientId - } - })); - }); + break; + default: + this.reliableTransport(undefined, dataType, data); + break; + } } - }]); - return JanusAdapter; -}(); + } + kick(clientId, permsToken) { + return this.publisher.handle.sendMessage({ + kind: "kick", + room_id: this.room, + user_id: clientId, + token: permsToken + }).then(() => { + document.body.dispatchEvent(new CustomEvent("kicked", { + detail: { + clientId: clientId + } + })); + }); + } + block(clientId) { + return this.publisher.handle.sendMessage({ + kind: "block", + whom: clientId + }).then(() => { + this.blockedClients.set(clientId, true); + document.body.dispatchEvent(new CustomEvent("blocked", { + detail: { + clientId: clientId + } + })); + }); + } + unblock(clientId) { + return this.publisher.handle.sendMessage({ + kind: "unblock", + whom: clientId + }).then(() => { + this.blockedClients.delete(clientId); + document.body.dispatchEvent(new CustomEvent("unblocked", { + detail: { + clientId: clientId + } + })); + }); + } +} NAF.adapters.register("janus", JanusAdapter); module.exports = JanusAdapter; @@ -3314,4 +2917,4 @@ if (true) { /******/ /******/ })() ; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,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O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0Isa0JBQWtCLE9BQU87QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNkNBQTZDO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQixrQkFBa0I7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0Isa0JBQWtCO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsSUFBSSxJQUEwQjtBQUM5QjtBQUNBOzs7Ozs7O1VDanlCQTtVQUNBOztVQUVBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBOztVQUVBO1VBQ0E7O1VBRUE7VUFDQTtVQUNBOzs7O1VFdEJBO1VBQ0E7VUFDQTtVQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvLi9ub2RlX21vZHVsZXMvQG5ldHdvcmtlZC1hZnJhbWUvbWluaWphbnVzL21pbmlqYW51cy5qcyIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci8uL3NyYy9pbmRleC5qcyIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci8uL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvYnJvd3Nlci5qcyIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci8uL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvY29tbW9uLmpzIiwid2VicGFjazovL0BuZXR3b3JrZWQtYWZyYW1lL25hZi1qYW51cy1hZGFwdGVyLy4vbm9kZV9tb2R1bGVzL21zL2luZGV4LmpzIiwid2VicGFjazovL0BuZXR3b3JrZWQtYWZyYW1lL25hZi1qYW51cy1hZGFwdGVyLy4vbm9kZV9tb2R1bGVzL3NkcC9zZHAuanMiLCJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvd2VicGFjay9iZWZvcmUtc3RhcnR1cCIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci93ZWJwYWNrL3N0YXJ0dXAiLCJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvd2VicGFjay9hZnRlci1zdGFydHVwIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUmVwcmVzZW50cyBhIGhhbmRsZSB0byBhIHNpbmdsZSBKYW51cyBwbHVnaW4gb24gYSBKYW51cyBzZXNzaW9uLiBFYWNoIFdlYlJUQyBjb25uZWN0aW9uIHRvIHRoZSBKYW51cyBzZXJ2ZXIgd2lsbCBiZVxuICogYXNzb2NpYXRlZCB3aXRoIGEgc2luZ2xlIGhhbmRsZS4gT25jZSBhdHRhY2hlZCB0byB0aGUgc2VydmVyLCB0aGlzIGhhbmRsZSB3aWxsIGJlIGdpdmVuIGEgdW5pcXVlIElEIHdoaWNoIHNob3VsZCBiZVxuICogdXNlZCB0byBhc3NvY2lhdGUgaXQgd2l0aCBmdXR1cmUgc2lnbmFsbGluZyBtZXNzYWdlcy5cbiAqXG4gKiBTZWUgaHR0cHM6Ly9qYW51cy5jb25mLm1lZXRlY2hvLmNvbS9kb2NzL3Jlc3QuaHRtbCNoYW5kbGVzLlxuICoqL1xuZnVuY3Rpb24gSmFudXNQbHVnaW5IYW5kbGUoc2Vzc2lvbikge1xuICB0aGlzLnNlc3Npb24gPSBzZXNzaW9uO1xuICB0aGlzLmlkID0gdW5kZWZpbmVkO1xufVxuXG4vKiogQXR0YWNoZXMgdGhpcyBoYW5kbGUgdG8gdGhlIEphbnVzIHNlcnZlciBhbmQgc2V0cyBpdHMgSUQuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLmF0dGFjaCA9IGZ1bmN0aW9uKHBsdWdpbiwgbG9vcF9pbmRleCkge1xuICB2YXIgcGF5bG9hZCA9IHsgcGx1Z2luOiBwbHVnaW4sIGxvb3BfaW5kZXg6IGxvb3BfaW5kZXgsIFwiZm9yY2UtYnVuZGxlXCI6IHRydWUsIFwiZm9yY2UtcnRjcC1tdXhcIjogdHJ1ZSB9O1xuICByZXR1cm4gdGhpcy5zZXNzaW9uLnNlbmQoXCJhdHRhY2hcIiwgcGF5bG9hZCkudGhlbihyZXNwID0+IHtcbiAgICB0aGlzLmlkID0gcmVzcC5kYXRhLmlkO1xuICAgIHJldHVybiByZXNwO1xuICB9KTtcbn07XG5cbi8qKiBEZXRhY2hlcyB0aGlzIGhhbmRsZS4gKiovXG5KYW51c1BsdWdpbkhhbmRsZS5wcm90b3R5cGUuZGV0YWNoID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJkZXRhY2hcIik7XG59O1xuXG4vKiogUmVnaXN0ZXJzIGEgY2FsbGJhY2sgdG8gYmUgZmlyZWQgdXBvbiB0aGUgcmVjZXB0aW9uIG9mIGFueSBpbmNvbWluZyBKYW51cyBzaWduYWxzIGZvciB0aGlzIHBsdWdpbiBoYW5kbGUgd2l0aCB0aGVcbiAqIGBqYW51c2AgYXR0cmlidXRlIGVxdWFsIHRvIGBldmAuXG4gKiovXG5KYW51c1BsdWdpbkhhbmRsZS5wcm90b3R5cGUub24gPSBmdW5jdGlvbihldiwgY2FsbGJhY2spIHtcbiAgcmV0dXJuIHRoaXMuc2Vzc2lvbi5vbihldiwgc2lnbmFsID0+IHtcbiAgICBpZiAoc2lnbmFsLnNlbmRlciA9PSB0aGlzLmlkKSB7XG4gICAgICBjYWxsYmFjayhzaWduYWwpO1xuICAgIH1cbiAgfSk7XG59O1xuXG4vKipcbiAqIFNlbmRzIGEgc2lnbmFsIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGhhbmRsZS4gU2lnbmFscyBzaG91bGQgYmUgSlNPTi1zZXJpYWxpemFibGUgb2JqZWN0cy4gUmV0dXJucyBhIHByb21pc2UgdGhhdCB3aWxsXG4gKiBiZSByZXNvbHZlZCBvciByZWplY3RlZCB3aGVuIGEgcmVzcG9uc2UgdG8gdGhpcyBzaWduYWwgaXMgcmVjZWl2ZWQsIG9yIHdoZW4gbm8gcmVzcG9uc2UgaXMgcmVjZWl2ZWQgd2l0aGluIHRoZVxuICogc2Vzc2lvbiB0aW1lb3V0LlxuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbih0eXBlLCBzaWduYWwpIHtcbiAgcmV0dXJuIHRoaXMuc2Vzc2lvbi5zZW5kKHR5cGUsIE9iamVjdC5hc3NpZ24oeyBoYW5kbGVfaWQ6IHRoaXMuaWQgfSwgc2lnbmFsKSk7XG59O1xuXG4vKiogU2VuZHMgYSBwbHVnaW4tc3BlY2lmaWMgbWVzc2FnZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBoYW5kbGUuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmRNZXNzYWdlID0gZnVuY3Rpb24oYm9keSkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwibWVzc2FnZVwiLCB7IGJvZHk6IGJvZHkgfSk7XG59O1xuXG4vKiogU2VuZHMgYSBKU0VQIG9mZmVyIG9yIGFuc3dlciBhc3NvY2lhdGVkIHdpdGggdGhpcyBoYW5kbGUuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmRKc2VwID0gZnVuY3Rpb24oanNlcCkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwibWVzc2FnZVwiLCB7IGJvZHk6IHt9LCBqc2VwOiBqc2VwIH0pO1xufTtcblxuLyoqIFNlbmRzIGFuIElDRSB0cmlja2xlIGNhbmRpZGF0ZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBoYW5kbGUuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmRUcmlja2xlID0gZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJ0cmlja2xlXCIsIHsgY2FuZGlkYXRlOiBjYW5kaWRhdGUgfSk7XG59O1xuXG4vKipcbiAqIFJlcHJlc2VudHMgYSBKYW51cyBzZXNzaW9uIC0tIGEgSmFudXMgY29udGV4dCBmcm9tIHdpdGhpbiB3aGljaCB5b3UgY2FuIG9wZW4gbXVsdGlwbGUgaGFuZGxlcyBhbmQgY29ubmVjdGlvbnMuIE9uY2VcbiAqIGNyZWF0ZWQsIHRoaXMgc2Vzc2lvbiB3aWxsIGJlIGdpdmVuIGEgdW5pcXVlIElEIHdoaWNoIHNob3VsZCBiZSB1c2VkIHRvIGFzc29jaWF0ZSBpdCB3aXRoIGZ1dHVyZSBzaWduYWxsaW5nIG1lc3NhZ2VzLlxuICpcbiAqIFNlZSBodHRwczovL2phbnVzLmNvbmYubWVldGVjaG8uY29tL2RvY3MvcmVzdC5odG1sI3Nlc3Npb25zLlxuICoqL1xuZnVuY3Rpb24gSmFudXNTZXNzaW9uKG91dHB1dCwgb3B0aW9ucykge1xuICB0aGlzLm91dHB1dCA9IG91dHB1dDtcbiAgdGhpcy5pZCA9IHVuZGVmaW5lZDtcbiAgdGhpcy5uZXh0VHhJZCA9IDA7XG4gIHRoaXMudHhucyA9IHt9O1xuICB0aGlzLmV2ZW50SGFuZGxlcnMgPSB7fTtcbiAgdGhpcy5vcHRpb25zID0gT2JqZWN0LmFzc2lnbih7XG4gICAgdmVyYm9zZTogZmFsc2UsXG4gICAgdGltZW91dE1zOiAxMDAwMCxcbiAgICBrZWVwYWxpdmVNczogMzAwMDBcbiAgfSwgb3B0aW9ucyk7XG59XG5cbi8qKiBDcmVhdGVzIHRoaXMgc2Vzc2lvbiBvbiB0aGUgSmFudXMgc2VydmVyIGFuZCBzZXRzIGl0cyBJRC4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLmNyZWF0ZSA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwiY3JlYXRlXCIpLnRoZW4ocmVzcCA9PiB7XG4gICAgdGhpcy5pZCA9IHJlc3AuZGF0YS5pZDtcbiAgICByZXR1cm4gcmVzcDtcbiAgfSk7XG59O1xuXG4vKipcbiAqIERlc3Ryb3lzIHRoaXMgc2Vzc2lvbi4gTm90ZSB0aGF0IHVwb24gZGVzdHJ1Y3Rpb24sIEphbnVzIHdpbGwgYWxzbyBjbG9zZSB0aGUgc2lnbmFsbGluZyB0cmFuc3BvcnQgKGlmIGFwcGxpY2FibGUpIGFuZFxuICogYW55IG9wZW4gV2ViUlRDIGNvbm5lY3Rpb25zLlxuICoqL1xuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJkZXN0cm95XCIpLnRoZW4oKHJlc3ApID0+IHtcbiAgICB0aGlzLmRpc3Bvc2UoKTtcbiAgICByZXR1cm4gcmVzcDtcbiAgfSk7XG59O1xuXG4vKipcbiAqIERpc3Bvc2VzIG9mIHRoaXMgc2Vzc2lvbiBpbiBhIHdheSBzdWNoIHRoYXQgbm8gZnVydGhlciBpbmNvbWluZyBzaWduYWxsaW5nIG1lc3NhZ2VzIHdpbGwgYmUgcHJvY2Vzc2VkLlxuICogT3V0c3RhbmRpbmcgdHJhbnNhY3Rpb25zIHdpbGwgYmUgcmVqZWN0ZWQuXG4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLmRpc3Bvc2UgPSBmdW5jdGlvbigpIHtcbiAgdGhpcy5fa2lsbEtlZXBhbGl2ZSgpO1xuICB0aGlzLmV2ZW50SGFuZGxlcnMgPSB7fTtcbiAgZm9yICh2YXIgdHhJZCBpbiB0aGlzLnR4bnMpIHtcbiAgICBpZiAodGhpcy50eG5zLmhhc093blByb3BlcnR5KHR4SWQpKSB7XG4gICAgICB2YXIgdHhuID0gdGhpcy50eG5zW3R4SWRdO1xuICAgICAgY2xlYXJUaW1lb3V0KHR4bi50aW1lb3V0KTtcbiAgICAgIHR4bi5yZWplY3QobmV3IEVycm9yKFwiSmFudXMgc2Vzc2lvbiB3YXMgZGlzcG9zZWQuXCIpKTtcbiAgICAgIGRlbGV0ZSB0aGlzLnR4bnNbdHhJZF07XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIFdoZXRoZXIgdGhpcyBzaWduYWwgcmVwcmVzZW50cyBhbiBlcnJvciwgYW5kIHRoZSBhc3NvY2lhdGVkIHByb21pc2UgKGlmIGFueSkgc2hvdWxkIGJlIHJlamVjdGVkLlxuICogVXNlcnMgc2hvdWxkIG92ZXJyaWRlIHRoaXMgdG8gaGFuZGxlIGFueSBjdXN0b20gcGx1Z2luLXNwZWNpZmljIGVycm9yIGNvbnZlbnRpb25zLlxuICoqL1xuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5pc0Vycm9yID0gZnVuY3Rpb24oc2lnbmFsKSB7XG4gIHJldHVybiBzaWduYWwuamFudXMgPT09IFwiZXJyb3JcIjtcbn07XG5cbi8qKiBSZWdpc3RlcnMgYSBjYWxsYmFjayB0byBiZSBmaXJlZCB1cG9uIHRoZSByZWNlcHRpb24gb2YgYW55IGluY29taW5nIEphbnVzIHNpZ25hbHMgZm9yIHRoaXMgc2Vzc2lvbiB3aXRoIHRoZVxuICogYGphbnVzYCBhdHRyaWJ1dGUgZXF1YWwgdG8gYGV2YC5cbiAqKi9cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUub24gPSBmdW5jdGlvbihldiwgY2FsbGJhY2spIHtcbiAgdmFyIGhhbmRsZXJzID0gdGhpcy5ldmVudEhhbmRsZXJzW2V2XTtcbiAgaWYgKGhhbmRsZXJzID09IG51bGwpIHtcbiAgICBoYW5kbGVycyA9IHRoaXMuZXZlbnRIYW5kbGVyc1tldl0gPSBbXTtcbiAgfVxuICBoYW5kbGVycy5wdXNoKGNhbGxiYWNrKTtcbn07XG5cbi8qKlxuICogQ2FsbGJhY2sgZm9yIHJlY2VpdmluZyBKU09OIHNpZ25hbGxpbmcgbWVzc2FnZXMgcGVydGluZW50IHRvIHRoaXMgc2Vzc2lvbi4gSWYgdGhlIHNpZ25hbHMgYXJlIHJlc3BvbnNlcyB0byBwcmV2aW91c2x5XG4gKiBzZW50IHNpZ25hbHMsIHRoZSBwcm9taXNlcyBmb3IgdGhlIG91dGdvaW5nIHNpZ25hbHMgd2lsbCBiZSByZXNvbHZlZCBvciByZWplY3RlZCBhcHByb3ByaWF0ZWx5IHdpdGggdGhpcyBzaWduYWwgYXMgYW5cbiAqIGFyZ3VtZW50LlxuICpcbiAqIEV4dGVybmFsIGNhbGxlcnMgc2hvdWxkIGNhbGwgdGhpcyBmdW5jdGlvbiBldmVyeSB0aW1lIGEgbmV3IHNpZ25hbCBhcnJpdmVzIG9uIHRoZSB0cmFuc3BvcnQ7IGZvciBleGFtcGxlLCBpbiBhXG4gKiBXZWJTb2NrZXQncyBgbWVzc2FnZWAgZXZlbnQsIG9yIHdoZW4gYSBuZXcgZGF0dW0gc2hvd3MgdXAgaW4gYW4gSFRUUCBsb25nLXBvbGxpbmcgcmVzcG9uc2UuXG4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLnJlY2VpdmUgPSBmdW5jdGlvbihzaWduYWwpIHtcbiAgaWYgKHRoaXMub3B0aW9ucy52ZXJib3NlKSB7XG4gICAgdGhpcy5fbG9nSW5jb21pbmcoc2lnbmFsKTtcbiAgfVxuICBpZiAoc2lnbmFsLnNlc3Npb25faWQgIT0gdGhpcy5pZCkge1xuICAgIGNvbnNvbGUud2FybihcIkluY29ycmVjdCBzZXNzaW9uIElEIHJlY2VpdmVkIGluIEphbnVzIHNpZ25hbGxpbmcgbWVzc2FnZTogd2FzIFwiICsgc2lnbmFsLnNlc3Npb25faWQgKyBcIiwgZXhwZWN0ZWQgXCIgKyB0aGlzLmlkICsgXCIuXCIpO1xuICB9XG5cbiAgdmFyIHJlc3BvbnNlVHlwZSA9IHNpZ25hbC5qYW51cztcbiAgdmFyIGhhbmRsZXJzID0gdGhpcy5ldmVudEhhbmRsZXJzW3Jlc3BvbnNlVHlwZV07XG4gIGlmIChoYW5kbGVycyAhPSBudWxsKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoYW5kbGVycy5sZW5ndGg7IGkrKykge1xuICAgICAgaGFuZGxlcnNbaV0oc2lnbmFsKTtcbiAgICB9XG4gIH1cblxuICBpZiAoc2lnbmFsLnRyYW5zYWN0aW9uICE9IG51bGwpIHtcbiAgICB2YXIgdHhuID0gdGhpcy50eG5zW3NpZ25hbC50cmFuc2FjdGlvbl07XG4gICAgaWYgKHR4biA9PSBudWxsKSB7XG4gICAgICAvLyB0aGlzIGlzIGEgcmVzcG9uc2UgdG8gYSB0cmFuc2FjdGlvbiB0aGF0IHdhc24ndCBjYXVzZWQgdmlhIEphbnVzU2Vzc2lvbi5zZW5kLCBvciBhIHBsdWdpbiByZXBsaWVkIHR3aWNlIHRvIGFcbiAgICAgIC8vIHNpbmdsZSByZXF1ZXN0LCBvciB0aGUgc2Vzc2lvbiB3YXMgZGlzcG9zZWQsIG9yIHNvbWV0aGluZyBlbHNlIHRoYXQgaXNuJ3QgdW5kZXIgb3VyIHB1cnZpZXc7IHRoYXQncyBmaW5lXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHJlc3BvbnNlVHlwZSA9PT0gXCJhY2tcIiAmJiB0eG4udHlwZSA9PSBcIm1lc3NhZ2VcIikge1xuICAgICAgLy8gdGhpcyBpcyBhbiBhY2sgb2YgYW4gYXN5bmNocm9ub3VzbHktcHJvY2Vzc2VkIHBsdWdpbiByZXF1ZXN0LCB3ZSBzaG91bGQgd2FpdCB0byByZXNvbHZlIHRoZSBwcm9taXNlIHVudGlsIHRoZVxuICAgICAgLy8gYWN0dWFsIHJlc3BvbnNlIGNvbWVzIGluXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY2xlYXJUaW1lb3V0KHR4bi50aW1lb3V0KTtcblxuICAgIGRlbGV0ZSB0aGlzLnR4bnNbc2lnbmFsLnRyYW5zYWN0aW9uXTtcbiAgICAodGhpcy5pc0Vycm9yKHNpZ25hbCkgPyB0eG4ucmVqZWN0IDogdHhuLnJlc29sdmUpKHNpZ25hbCk7XG4gIH1cbn07XG5cbi8qKlxuICogU2VuZHMgYSBzaWduYWwgYXNzb2NpYXRlZCB3aXRoIHRoaXMgc2Vzc2lvbiwgYmVnaW5uaW5nIGEgbmV3IHRyYW5zYWN0aW9uLiBSZXR1cm5zIGEgcHJvbWlzZSB0aGF0IHdpbGwgYmUgcmVzb2x2ZWQgb3JcbiAqIHJlamVjdGVkIHdoZW4gYSByZXNwb25zZSBpcyByZWNlaXZlZCBpbiB0aGUgc2FtZSB0cmFuc2FjdGlvbiwgb3Igd2hlbiBubyByZXNwb25zZSBpcyByZWNlaXZlZCB3aXRoaW4gdGhlIHNlc3Npb25cbiAqIHRpbWVvdXQuXG4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbih0eXBlLCBzaWduYWwpIHtcbiAgc2lnbmFsID0gT2JqZWN0LmFzc2lnbih7IHRyYW5zYWN0aW9uOiAodGhpcy5uZXh0VHhJZCsrKS50b1N0cmluZygpIH0sIHNpZ25hbCk7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgdmFyIHRpbWVvdXQgPSBudWxsO1xuICAgIGlmICh0aGlzLm9wdGlvbnMudGltZW91dE1zKSB7XG4gICAgICB0aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGRlbGV0ZSB0aGlzLnR4bnNbc2lnbmFsLnRyYW5zYWN0aW9uXTtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihcIlNpZ25hbGxpbmcgdHJhbnNhY3Rpb24gd2l0aCB0eGlkIFwiICsgc2lnbmFsLnRyYW5zYWN0aW9uICsgXCIgdGltZWQgb3V0LlwiKSk7XG4gICAgICB9LCB0aGlzLm9wdGlvbnMudGltZW91dE1zKTtcbiAgICB9XG4gICAgdGhpcy50eG5zW3NpZ25hbC50cmFuc2FjdGlvbl0gPSB7IHJlc29sdmU6IHJlc29sdmUsIHJlamVjdDogcmVqZWN0LCB0aW1lb3V0OiB0aW1lb3V0LCB0eXBlOiB0eXBlIH07XG4gICAgdGhpcy5fdHJhbnNtaXQodHlwZSwgc2lnbmFsKTtcbiAgfSk7XG59O1xuXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLl90cmFuc21pdCA9IGZ1bmN0aW9uKHR5cGUsIHNpZ25hbCkge1xuICBzaWduYWwgPSBPYmplY3QuYXNzaWduKHsgamFudXM6IHR5cGUgfSwgc2lnbmFsKTtcblxuICBpZiAodGhpcy5pZCAhPSBudWxsKSB7IC8vIHRoaXMuaWQgaXMgdW5kZWZpbmVkIGluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlbiB3ZSdyZSBzZW5kaW5nIHRoZSBzZXNzaW9uIGNyZWF0ZSBtZXNzYWdlXG4gICAgc2lnbmFsID0gT2JqZWN0LmFzc2lnbih7IHNlc3Npb25faWQ6IHRoaXMuaWQgfSwgc2lnbmFsKTtcbiAgfVxuXG4gIGlmICh0aGlzLm9wdGlvbnMudmVyYm9zZSkge1xuICAgIHRoaXMuX2xvZ091dGdvaW5nKHNpZ25hbCk7XG4gIH1cblxuICB0aGlzLm91dHB1dChKU09OLnN0cmluZ2lmeShzaWduYWwpKTtcbiAgdGhpcy5fcmVzZXRLZWVwYWxpdmUoKTtcbn07XG5cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuX2xvZ091dGdvaW5nID0gZnVuY3Rpb24oc2lnbmFsKSB7XG4gIHZhciBraW5kID0gc2lnbmFsLmphbnVzO1xuICBpZiAoa2luZCA9PT0gXCJtZXNzYWdlXCIgJiYgc2lnbmFsLmpzZXApIHtcbiAgICBraW5kID0gc2lnbmFsLmpzZXAudHlwZTtcbiAgfVxuICB2YXIgbWVzc2FnZSA9IFwiPiBPdXRnb2luZyBKYW51cyBcIiArIChraW5kIHx8IFwic2lnbmFsXCIpICsgXCIgKCNcIiArIHNpZ25hbC50cmFuc2FjdGlvbiArIFwiKTogXCI7XG4gIGNvbnNvbGUuZGVidWcoXCIlY1wiICsgbWVzc2FnZSwgXCJjb2xvcjogIzA0MFwiLCBzaWduYWwpO1xufTtcblxuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5fbG9nSW5jb21pbmcgPSBmdW5jdGlvbihzaWduYWwpIHtcbiAgdmFyIGtpbmQgPSBzaWduYWwuamFudXM7XG4gIHZhciBtZXNzYWdlID0gc2lnbmFsLnRyYW5zYWN0aW9uID9cbiAgICAgIFwiPCBJbmNvbWluZyBKYW51cyBcIiArIChraW5kIHx8IFwic2lnbmFsXCIpICsgXCIgKCNcIiArIHNpZ25hbC50cmFuc2FjdGlvbiArIFwiKTogXCIgOlxuICAgICAgXCI8IEluY29taW5nIEphbnVzIFwiICsgKGtpbmQgfHwgXCJzaWduYWxcIikgKyBcIjogXCI7XG4gIGNvbnNvbGUuZGVidWcoXCIlY1wiICsgbWVzc2FnZSwgXCJjb2xvcjogIzAwNFwiLCBzaWduYWwpO1xufTtcblxuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5fc2VuZEtlZXBhbGl2ZSA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwia2VlcGFsaXZlXCIpO1xufTtcblxuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5fa2lsbEtlZXBhbGl2ZSA9IGZ1bmN0aW9uKCkge1xuICBjbGVhclRpbWVvdXQodGhpcy5rZWVwYWxpdmVUaW1lb3V0KTtcbn07XG5cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuX3Jlc2V0S2VlcGFsaXZlID0gZnVuY3Rpb24oKSB7XG4gIHRoaXMuX2tpbGxLZWVwYWxpdmUoKTtcbiAgaWYgKHRoaXMub3B0aW9ucy5rZWVwYWxpdmVNcykge1xuICAgIHRoaXMua2VlcGFsaXZlVGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5fc2VuZEtlZXBhbGl2ZSgpLmNhdGNoKGUgPT4gY29uc29sZS5lcnJvcihcIkVycm9yIHJlY2VpdmVkIGZyb20ga2VlcGFsaXZlOiBcIiwgZSkpO1xuICAgIH0sIHRoaXMub3B0aW9ucy5rZWVwYWxpdmVNcyk7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBKYW51c1BsdWdpbkhhbmRsZSxcbiAgSmFudXNTZXNzaW9uXG59O1xuIiwiLyogZ2xvYmFsIE5BRiAqL1xudmFyIG1qID0gcmVxdWlyZShcIkBuZXR3b3JrZWQtYWZyYW1lL21pbmlqYW51c1wiKTtcbm1qLkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuc2VuZE9yaWdpbmFsID0gbWouSmFudXNTZXNzaW9uLnByb3RvdHlwZS5zZW5kO1xubWouSmFudXNTZXNzaW9uLnByb3RvdHlwZS5zZW5kID0gZnVuY3Rpb24odHlwZSwgc2lnbmFsKSB7XG4gIHJldHVybiB0aGlzLnNlbmRPcmlnaW5hbCh0eXBlLCBzaWduYWwpLmNhdGNoKChlKSA9PiB7XG4gICAgaWYgKGUubWVzc2FnZSAmJiBlLm1lc3NhZ2UuaW5kZXhPZihcInRpbWVkIG91dFwiKSA+IC0xKSB7XG4gICAgICBjb25zb2xlLmVycm9yKFwid2ViIHNvY2tldCB0aW1lZCBvdXRcIik7XG4gICAgICBOQUYuY29ubmVjdGlvbi5hZGFwdGVyLnJlY29ubmVjdCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyhlKTtcbiAgICB9XG4gIH0pO1xufVxuXG52YXIgc2RwVXRpbHMgPSByZXF1aXJlKFwic2RwXCIpO1xudmFyIGRlYnVnID0gcmVxdWlyZShcImRlYnVnXCIpKFwibmFmLWphbnVzLWFkYXB0ZXI6ZGVidWdcIik7XG52YXIgd2FybiA9IHJlcXVpcmUoXCJkZWJ1Z1wiKShcIm5hZi1qYW51cy1hZGFwdGVyOndhcm5cIik7XG52YXIgZXJyb3IgPSByZXF1aXJlKFwiZGVidWdcIikoXCJuYWYtamFudXMtYWRhcHRlcjplcnJvclwiKTtcbnZhciBpc1NhZmFyaSA9IC9eKCg/IWNocm9tZXxhbmRyb2lkKS4pKnNhZmFyaS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCk7XG5cbmNvbnN0IFNVQlNDUklCRV9USU1FT1VUX01TID0gMTUwMDA7XG5cbmNvbnN0IEFWQUlMQUJMRV9PQ0NVUEFOVFNfVEhSRVNIT0xEID0gNTtcbmNvbnN0IE1BWF9TVUJTQ1JJQkVfREVMQVkgPSA1MDAwO1xuXG5mdW5jdGlvbiByYW5kb21EZWxheShtaW4sIG1heCkge1xuICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgY29uc3QgZGVsYXkgPSBNYXRoLnJhbmRvbSgpICogKG1heCAtIG1pbikgKyBtaW47XG4gICAgc2V0VGltZW91dChyZXNvbHZlLCBkZWxheSk7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkZWJvdW5jZShmbikge1xuICB2YXIgY3VyciA9IFByb21pc2UucmVzb2x2ZSgpO1xuICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgIGN1cnIgPSBjdXJyLnRoZW4oXyA9PiBmbi5hcHBseSh0aGlzLCBhcmdzKSk7XG4gIH07XG59XG5cbmZ1bmN0aW9uIHJhbmRvbVVpbnQoKSB7XG4gIHJldHVybiBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUik7XG59XG5cbmZ1bmN0aW9uIHVudGlsRGF0YUNoYW5uZWxPcGVuKGRhdGFDaGFubmVsKSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgaWYgKGRhdGFDaGFubmVsLnJlYWR5U3RhdGUgPT09IFwib3BlblwiKSB7XG4gICAgICByZXNvbHZlKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCByZXNvbHZlciwgcmVqZWN0b3I7XG5cbiAgICAgIGNvbnN0IGNsZWFyID0gKCkgPT4ge1xuICAgICAgICBkYXRhQ2hhbm5lbC5yZW1vdmVFdmVudExpc3RlbmVyKFwib3BlblwiLCByZXNvbHZlcik7XG4gICAgICAgIGRhdGFDaGFubmVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJlcnJvclwiLCByZWplY3Rvcik7XG4gICAgICB9O1xuXG4gICAgICByZXNvbHZlciA9ICgpID0+IHtcbiAgICAgICAgY2xlYXIoKTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfTtcbiAgICAgIHJlamVjdG9yID0gKCkgPT4ge1xuICAgICAgICBjbGVhcigpO1xuICAgICAgICByZWplY3QoKTtcbiAgICAgIH07XG5cbiAgICAgIGRhdGFDaGFubmVsLmFkZEV2ZW50TGlzdGVuZXIoXCJvcGVuXCIsIHJlc29sdmVyKTtcbiAgICAgIGRhdGFDaGFubmVsLmFkZEV2ZW50TGlzdGVuZXIoXCJlcnJvclwiLCByZWplY3Rvcik7XG4gICAgfVxuICB9KTtcbn1cblxuY29uc3QgaXNIMjY0VmlkZW9TdXBwb3J0ZWQgPSAoKCkgPT4ge1xuICBjb25zdCB2aWRlbyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJ2aWRlb1wiKTtcbiAgcmV0dXJuIHZpZGVvLmNhblBsYXlUeXBlKCd2aWRlby9tcDQ7IGNvZGVjcz1cImF2YzEuNDJFMDFFLCBtcDRhLjQwLjJcIicpICE9PSBcIlwiO1xufSkoKTtcblxuY29uc3QgT1BVU19QQVJBTUVURVJTID0ge1xuICAvLyBpbmRpY2F0ZXMgdGhhdCB3ZSB3YW50IHRvIGVuYWJsZSBEVFggdG8gZWxpZGUgc2lsZW5jZSBwYWNrZXRzXG4gIHVzZWR0eDogMSxcbiAgLy8gaW5kaWNhdGVzIHRoYXQgd2UgcHJlZmVyIHRvIHJlY2VpdmUgbW9ubyBhdWRpbyAoaW1wb3J0YW50IGZvciB2b2lwIHByb2ZpbGUpXG4gIHN0ZXJlbzogMCxcbiAgLy8gaW5kaWNhdGVzIHRoYXQgd2UgcHJlZmVyIHRvIHNlbmQgbW9ubyBhdWRpbyAoaW1wb3J0YW50IGZvciB2b2lwIHByb2ZpbGUpXG4gIFwic3Byb3Atc3RlcmVvXCI6IDBcbn07XG5cbmNvbnN0IERFRkFVTFRfUEVFUl9DT05ORUNUSU9OX0NPTkZJRyA9IHtcbiAgaWNlU2VydmVyczogW3sgdXJsczogXCJzdHVuOnN0dW4xLmwuZ29vZ2xlLmNvbToxOTMwMlwiIH0sIHsgdXJsczogXCJzdHVuOnN0dW4yLmwuZ29vZ2xlLmNvbToxOTMwMlwiIH1dXG59O1xuXG5jb25zdCBXU19OT1JNQUxfQ0xPU1VSRSA9IDEwMDA7XG5cbmNsYXNzIEphbnVzQWRhcHRlciB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMucm9vbSA9IG51bGw7XG4gICAgLy8gV2UgZXhwZWN0IHRoZSBjb25zdW1lciB0byBzZXQgYSBjbGllbnQgaWQgYmVmb3JlIGNvbm5lY3RpbmcuXG4gICAgdGhpcy5jbGllbnRJZCA9IG51bGw7XG4gICAgdGhpcy5qb2luVG9rZW4gPSBudWxsO1xuXG4gICAgdGhpcy5zZXJ2ZXJVcmwgPSBudWxsO1xuICAgIHRoaXMud2ViUnRjT3B0aW9ucyA9IHt9O1xuICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db25maWcgPSBudWxsO1xuICAgIHRoaXMud3MgPSBudWxsO1xuICAgIHRoaXMuc2Vzc2lvbiA9IG51bGw7XG4gICAgdGhpcy5yZWxpYWJsZVRyYW5zcG9ydCA9IFwiZGF0YWNoYW5uZWxcIjtcbiAgICB0aGlzLnVucmVsaWFibGVUcmFuc3BvcnQgPSBcImRhdGFjaGFubmVsXCI7XG5cbiAgICAvLyBJbiB0aGUgZXZlbnQgdGhlIHNlcnZlciByZXN0YXJ0cyBhbmQgYWxsIGNsaWVudHMgbG9zZSBjb25uZWN0aW9uLCByZWNvbm5lY3Qgd2l0aFxuICAgIC8vIHNvbWUgcmFuZG9tIGppdHRlciBhZGRlZCB0byBwcmV2ZW50IHNpbXVsdGFuZW91cyByZWNvbm5lY3Rpb24gcmVxdWVzdHMuXG4gICAgdGhpcy5pbml0aWFsUmVjb25uZWN0aW9uRGVsYXkgPSAxMDAwICogTWF0aC5yYW5kb20oKTtcbiAgICB0aGlzLnJlY29ubmVjdGlvbkRlbGF5ID0gdGhpcy5pbml0aWFsUmVjb25uZWN0aW9uRGVsYXk7XG4gICAgdGhpcy5yZWNvbm5lY3Rpb25UaW1lb3V0ID0gbnVsbDtcbiAgICB0aGlzLm1heFJlY29ubmVjdGlvbkF0dGVtcHRzID0gMTA7XG4gICAgdGhpcy5yZWNvbm5lY3Rpb25BdHRlbXB0cyA9IDA7XG5cbiAgICB0aGlzLnB1Ymxpc2hlciA9IG51bGw7XG4gICAgdGhpcy5vY2N1cGFudElkcyA9IFtdO1xuICAgIHRoaXMub2NjdXBhbnRzID0ge307XG4gICAgdGhpcy5tZWRpYVN0cmVhbXMgPSB7fTtcbiAgICB0aGlzLmxvY2FsTWVkaWFTdHJlYW0gPSBudWxsO1xuICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMgPSBuZXcgTWFwKCk7XG5cbiAgICB0aGlzLnBlbmRpbmdPY2N1cGFudHMgPSBuZXcgU2V0KCk7XG4gICAgdGhpcy5hdmFpbGFibGVPY2N1cGFudHMgPSBbXTtcbiAgICB0aGlzLnJlcXVlc3RlZE9jY3VwYW50cyA9IG51bGw7XG5cbiAgICB0aGlzLmJsb2NrZWRDbGllbnRzID0gbmV3IE1hcCgpO1xuICAgIHRoaXMuZnJvemVuVXBkYXRlcyA9IG5ldyBNYXAoKTtcblxuICAgIHRoaXMudGltZU9mZnNldHMgPSBbXTtcbiAgICB0aGlzLnNlcnZlclRpbWVSZXF1ZXN0cyA9IDA7XG4gICAgdGhpcy5hdmdUaW1lT2Zmc2V0ID0gMDtcblxuICAgIHRoaXMub25XZWJzb2NrZXRPcGVuID0gdGhpcy5vbldlYnNvY2tldE9wZW4uYmluZCh0aGlzKTtcbiAgICB0aGlzLm9uV2Vic29ja2V0Q2xvc2UgPSB0aGlzLm9uV2Vic29ja2V0Q2xvc2UuYmluZCh0aGlzKTtcbiAgICB0aGlzLm9uV2Vic29ja2V0TWVzc2FnZSA9IHRoaXMub25XZWJzb2NrZXRNZXNzYWdlLmJpbmQodGhpcyk7XG4gICAgdGhpcy5vbkRhdGFDaGFubmVsTWVzc2FnZSA9IHRoaXMub25EYXRhQ2hhbm5lbE1lc3NhZ2UuYmluZCh0aGlzKTtcbiAgICB0aGlzLm9uRGF0YSA9IHRoaXMub25EYXRhLmJpbmQodGhpcyk7XG4gIH1cblxuICBzZXRTZXJ2ZXJVcmwodXJsKSB7XG4gICAgdGhpcy5zZXJ2ZXJVcmwgPSB1cmw7XG4gIH1cblxuICBzZXRBcHAoYXBwKSB7fVxuXG4gIHNldFJvb20ocm9vbU5hbWUpIHtcbiAgICB0aGlzLnJvb20gPSByb29tTmFtZTtcbiAgfVxuXG4gIHNldEpvaW5Ub2tlbihqb2luVG9rZW4pIHtcbiAgICB0aGlzLmpvaW5Ub2tlbiA9IGpvaW5Ub2tlbjtcbiAgfVxuXG4gIHNldENsaWVudElkKGNsaWVudElkKSB7XG4gICAgdGhpcy5jbGllbnRJZCA9IGNsaWVudElkO1xuICB9XG5cbiAgc2V0V2ViUnRjT3B0aW9ucyhvcHRpb25zKSB7XG4gICAgdGhpcy53ZWJSdGNPcHRpb25zID0gb3B0aW9ucztcbiAgfVxuXG4gIHNldFBlZXJDb25uZWN0aW9uQ29uZmlnKHBlZXJDb25uZWN0aW9uQ29uZmlnKSB7XG4gICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbmZpZyA9IHBlZXJDb25uZWN0aW9uQ29uZmlnO1xuICB9XG5cbiAgc2V0U2VydmVyQ29ubmVjdExpc3RlbmVycyhzdWNjZXNzTGlzdGVuZXIsIGZhaWx1cmVMaXN0ZW5lcikge1xuICAgIHRoaXMuY29ubmVjdFN1Y2Nlc3MgPSBzdWNjZXNzTGlzdGVuZXI7XG4gICAgdGhpcy5jb25uZWN0RmFpbHVyZSA9IGZhaWx1cmVMaXN0ZW5lcjtcbiAgfVxuXG4gIHNldFJvb21PY2N1cGFudExpc3RlbmVyKG9jY3VwYW50TGlzdGVuZXIpIHtcbiAgICB0aGlzLm9uT2NjdXBhbnRzQ2hhbmdlZCA9IG9jY3VwYW50TGlzdGVuZXI7XG4gIH1cblxuICBzZXREYXRhQ2hhbm5lbExpc3RlbmVycyhvcGVuTGlzdGVuZXIsIGNsb3NlZExpc3RlbmVyLCBtZXNzYWdlTGlzdGVuZXIpIHtcbiAgICB0aGlzLm9uT2NjdXBhbnRDb25uZWN0ZWQgPSBvcGVuTGlzdGVuZXI7XG4gICAgdGhpcy5vbk9jY3VwYW50RGlzY29ubmVjdGVkID0gY2xvc2VkTGlzdGVuZXI7XG4gICAgdGhpcy5vbk9jY3VwYW50TWVzc2FnZSA9IG1lc3NhZ2VMaXN0ZW5lcjtcbiAgfVxuXG4gIHNldFJlY29ubmVjdGlvbkxpc3RlbmVycyhyZWNvbm5lY3RpbmdMaXN0ZW5lciwgcmVjb25uZWN0ZWRMaXN0ZW5lciwgcmVjb25uZWN0aW9uRXJyb3JMaXN0ZW5lcikge1xuICAgIC8vIG9uUmVjb25uZWN0aW5nIGlzIGNhbGxlZCB3aXRoIHRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHVudGlsIHRoZSBuZXh0IHJlY29ubmVjdGlvbiBhdHRlbXB0XG4gICAgdGhpcy5vblJlY29ubmVjdGluZyA9IHJlY29ubmVjdGluZ0xpc3RlbmVyO1xuICAgIC8vIG9uUmVjb25uZWN0ZWQgaXMgY2FsbGVkIHdoZW4gdGhlIGNvbm5lY3Rpb24gaGFzIGJlZW4gcmVlc3RhYmxpc2hlZFxuICAgIHRoaXMub25SZWNvbm5lY3RlZCA9IHJlY29ubmVjdGVkTGlzdGVuZXI7XG4gICAgLy8gb25SZWNvbm5lY3Rpb25FcnJvciBpcyBjYWxsZWQgd2l0aCBhbiBlcnJvciB3aGVuIG1heFJlY29ubmVjdGlvbkF0dGVtcHRzIGhhcyBiZWVuIHJlYWNoZWRcbiAgICB0aGlzLm9uUmVjb25uZWN0aW9uRXJyb3IgPSByZWNvbm5lY3Rpb25FcnJvckxpc3RlbmVyO1xuICB9XG5cbiAgc2V0RXZlbnRMb29wcyhsb29wcykge1xuICAgIHRoaXMubG9vcHMgPSBsb29wcztcbiAgfVxuXG4gIGNvbm5lY3QoKSB7XG4gICAgZGVidWcoYGNvbm5lY3RpbmcgdG8gJHt0aGlzLnNlcnZlclVybH1gKTtcblxuICAgIGNvbnN0IHdlYnNvY2tldENvbm5lY3Rpb24gPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICB0aGlzLndzID0gbmV3IFdlYlNvY2tldCh0aGlzLnNlcnZlclVybCwgXCJqYW51cy1wcm90b2NvbFwiKTtcblxuICAgICAgdGhpcy5zZXNzaW9uID0gbmV3IG1qLkphbnVzU2Vzc2lvbih0aGlzLndzLnNlbmQuYmluZCh0aGlzLndzKSwgeyB0aW1lb3V0TXM6IDQwMDAwIH0pO1xuXG4gICAgICB0aGlzLndzLmFkZEV2ZW50TGlzdGVuZXIoXCJjbG9zZVwiLCB0aGlzLm9uV2Vic29ja2V0Q2xvc2UpO1xuICAgICAgdGhpcy53cy5hZGRFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCB0aGlzLm9uV2Vic29ja2V0TWVzc2FnZSk7XG5cbiAgICAgIHRoaXMud3NPbk9wZW4gPSAoKSA9PiB7XG4gICAgICAgIHRoaXMud3MucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIm9wZW5cIiwgdGhpcy53c09uT3Blbik7XG4gICAgICAgIHRoaXMub25XZWJzb2NrZXRPcGVuKClcbiAgICAgICAgICAudGhlbihyZXNvbHZlKVxuICAgICAgICAgIC5jYXRjaChyZWplY3QpO1xuICAgICAgfTtcblxuICAgICAgdGhpcy53cy5hZGRFdmVudExpc3RlbmVyKFwib3BlblwiLCB0aGlzLndzT25PcGVuKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBQcm9taXNlLmFsbChbd2Vic29ja2V0Q29ubmVjdGlvbiwgdGhpcy51cGRhdGVUaW1lT2Zmc2V0KCldKTtcbiAgfVxuXG4gIGRpc2Nvbm5lY3QoKSB7XG4gICAgZGVidWcoYGRpc2Nvbm5lY3RpbmdgKTtcblxuICAgIGNsZWFyVGltZW91dCh0aGlzLnJlY29ubmVjdGlvblRpbWVvdXQpO1xuXG4gICAgdGhpcy5yZW1vdmVBbGxPY2N1cGFudHMoKTtcblxuICAgIGlmICh0aGlzLnB1Ymxpc2hlcikge1xuICAgICAgLy8gQ2xvc2UgdGhlIHB1Ymxpc2hlciBwZWVyIGNvbm5lY3Rpb24uIFdoaWNoIGFsc28gZGV0YWNoZXMgdGhlIHBsdWdpbiBoYW5kbGUuXG4gICAgICB0aGlzLnB1Ymxpc2hlci5jb25uLmNsb3NlKCk7XG4gICAgICB0aGlzLnB1Ymxpc2hlciA9IG51bGw7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc2Vzc2lvbikge1xuICAgICAgdGhpcy5zZXNzaW9uLmRpc3Bvc2UoKTtcbiAgICAgIHRoaXMuc2Vzc2lvbiA9IG51bGw7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMud3MpIHtcbiAgICAgIHRoaXMud3MucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIm9wZW5cIiwgdGhpcy53c09uT3Blbik7XG4gICAgICB0aGlzLndzLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJjbG9zZVwiLCB0aGlzLm9uV2Vic29ja2V0Q2xvc2UpO1xuICAgICAgdGhpcy53cy5yZW1vdmVFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCB0aGlzLm9uV2Vic29ja2V0TWVzc2FnZSk7XG4gICAgICB0aGlzLndzLmNsb3NlKCk7XG4gICAgICB0aGlzLndzID0gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBOb3cgdGhhdCBhbGwgUlRDUGVlckNvbm5lY3Rpb24gY2xvc2VkLCBiZSBzdXJlIHRvIG5vdCBjYWxsXG4gICAgLy8gcmVjb25uZWN0KCkgYWdhaW4gdmlhIHBlcmZvcm1EZWxheWVkUmVjb25uZWN0IGlmIHByZXZpb3VzXG4gICAgLy8gUlRDUGVlckNvbm5lY3Rpb24gd2FzIGluIHRoZSBmYWlsZWQgc3RhdGUuXG4gICAgaWYgKHRoaXMuZGVsYXllZFJlY29ubmVjdFRpbWVvdXQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLmRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0KTtcbiAgICAgIHRoaXMuZGVsYXllZFJlY29ubmVjdFRpbWVvdXQgPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIGlzRGlzY29ubmVjdGVkKCkge1xuICAgIHJldHVybiB0aGlzLndzID09PSBudWxsO1xuICB9XG5cbiAgYXN5bmMgb25XZWJzb2NrZXRPcGVuKCkge1xuICAgIC8vIENyZWF0ZSB0aGUgSmFudXMgU2Vzc2lvblxuICAgIGF3YWl0IHRoaXMuc2Vzc2lvbi5jcmVhdGUoKTtcblxuICAgIC8vIEF0dGFjaCB0aGUgU0ZVIFBsdWdpbiBhbmQgY3JlYXRlIGEgUlRDUGVlckNvbm5lY3Rpb24gZm9yIHRoZSBwdWJsaXNoZXIuXG4gICAgLy8gVGhlIHB1Ymxpc2hlciBzZW5kcyBhdWRpbyBhbmQgb3BlbnMgdHdvIGJpZGlyZWN0aW9uYWwgZGF0YSBjaGFubmVscy5cbiAgICAvLyBPbmUgcmVsaWFibGUgZGF0YWNoYW5uZWwgYW5kIG9uZSB1bnJlbGlhYmxlLlxuICAgIHRoaXMucHVibGlzaGVyID0gYXdhaXQgdGhpcy5jcmVhdGVQdWJsaXNoZXIoKTtcblxuICAgIC8vIENhbGwgdGhlIG5hZiBjb25uZWN0U3VjY2VzcyBjYWxsYmFjayBiZWZvcmUgd2Ugc3RhcnQgcmVjZWl2aW5nIFdlYlJUQyBtZXNzYWdlcy5cbiAgICB0aGlzLmNvbm5lY3RTdWNjZXNzKHRoaXMuY2xpZW50SWQpO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnB1Ymxpc2hlci5pbml0aWFsT2NjdXBhbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBvY2N1cGFudElkID0gdGhpcy5wdWJsaXNoZXIuaW5pdGlhbE9jY3VwYW50c1tpXTtcbiAgICAgIGlmIChvY2N1cGFudElkID09PSB0aGlzLmNsaWVudElkKSBjb250aW51ZTsgLy8gSGFwcGVucyBkdXJpbmcgbm9uLWdyYWNlZnVsIHJlY29ubmVjdHMgZHVlIHRvIHpvbWJpZSBzZXNzaW9uc1xuICAgICAgdGhpcy5hZGRBdmFpbGFibGVPY2N1cGFudChvY2N1cGFudElkKTtcbiAgICB9XG5cbiAgICB0aGlzLnN5bmNPY2N1cGFudHMoKTtcbiAgfVxuXG4gIG9uV2Vic29ja2V0Q2xvc2UoZXZlbnQpIHtcbiAgICAvLyBUaGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkIHN1Y2Nlc3NmdWxseS4gRG9uJ3QgdHJ5IHRvIHJlY29ubmVjdC5cbiAgICBpZiAoZXZlbnQuY29kZSA9PT0gV1NfTk9STUFMX0NMT1NVUkUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zb2xlLndhcm4oXCJKYW51cyB3ZWJzb2NrZXQgY2xvc2VkIHVuZXhwZWN0ZWRseS5cIik7XG4gICAgaWYgKHRoaXMub25SZWNvbm5lY3RpbmcpIHtcbiAgICAgIHRoaXMub25SZWNvbm5lY3RpbmcodGhpcy5yZWNvbm5lY3Rpb25EZWxheSk7XG4gICAgfVxuXG4gICAgdGhpcy5yZWNvbm5lY3Rpb25UaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB0aGlzLnJlY29ubmVjdCgpLCB0aGlzLnJlY29ubmVjdGlvbkRlbGF5KTtcbiAgfVxuXG4gIHJlY29ubmVjdCgpIHtcbiAgICAvLyBEaXNwb3NlIG9mIGFsbCBuZXR3b3JrZWQgZW50aXRpZXMgYW5kIG90aGVyIHJlc291cmNlcyB0aWVkIHRvIHRoZSBzZXNzaW9uLlxuICAgIHRoaXMuZGlzY29ubmVjdCgpO1xuXG4gICAgdGhpcy5jb25uZWN0KClcbiAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgdGhpcy5yZWNvbm5lY3Rpb25EZWxheSA9IHRoaXMuaW5pdGlhbFJlY29ubmVjdGlvbkRlbGF5O1xuICAgICAgICB0aGlzLnJlY29ubmVjdGlvbkF0dGVtcHRzID0gMDtcblxuICAgICAgICBpZiAodGhpcy5vblJlY29ubmVjdGVkKSB7XG4gICAgICAgICAgdGhpcy5vblJlY29ubmVjdGVkKCk7XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICB0aGlzLnJlY29ubmVjdGlvbkRlbGF5ICs9IDEwMDA7XG4gICAgICAgIHRoaXMucmVjb25uZWN0aW9uQXR0ZW1wdHMrKztcblxuICAgICAgICBpZiAodGhpcy5yZWNvbm5lY3Rpb25BdHRlbXB0cyA+IHRoaXMubWF4UmVjb25uZWN0aW9uQXR0ZW1wdHMgJiYgdGhpcy5vblJlY29ubmVjdGlvbkVycm9yKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMub25SZWNvbm5lY3Rpb25FcnJvcihcbiAgICAgICAgICAgIG5ldyBFcnJvcihcIkNvbm5lY3Rpb24gY291bGQgbm90IGJlIHJlZXN0YWJsaXNoZWQsIGV4Y2VlZGVkIG1heGltdW0gbnVtYmVyIG9mIHJlY29ubmVjdGlvbiBhdHRlbXB0cy5cIilcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc29sZS53YXJuKFwiRXJyb3IgZHVyaW5nIHJlY29ubmVjdCwgcmV0cnlpbmcuXCIpO1xuICAgICAgICBjb25zb2xlLndhcm4oZXJyb3IpO1xuXG4gICAgICAgIGlmICh0aGlzLm9uUmVjb25uZWN0aW5nKSB7XG4gICAgICAgICAgdGhpcy5vblJlY29ubmVjdGluZyh0aGlzLnJlY29ubmVjdGlvbkRlbGF5KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVjb25uZWN0aW9uVGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4gdGhpcy5yZWNvbm5lY3QoKSwgdGhpcy5yZWNvbm5lY3Rpb25EZWxheSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHBlcmZvcm1EZWxheWVkUmVjb25uZWN0KCkge1xuICAgIGlmICh0aGlzLmRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0KSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5kZWxheWVkUmVjb25uZWN0VGltZW91dCk7XG4gICAgfVxuXG4gICAgdGhpcy5kZWxheWVkUmVjb25uZWN0VGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5kZWxheWVkUmVjb25uZWN0VGltZW91dCA9IG51bGw7XG4gICAgICB0aGlzLnJlY29ubmVjdCgpO1xuICAgIH0sIDEwMDAwKTtcbiAgfVxuXG4gIG9uV2Vic29ja2V0TWVzc2FnZShldmVudCkge1xuICAgIHRoaXMuc2Vzc2lvbi5yZWNlaXZlKEpTT04ucGFyc2UoZXZlbnQuZGF0YSkpO1xuICB9XG5cbiAgYWRkQXZhaWxhYmxlT2NjdXBhbnQob2NjdXBhbnRJZCkge1xuICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgdGhpcy5hdmFpbGFibGVPY2N1cGFudHMucHVzaChvY2N1cGFudElkKTtcbiAgICB9XG4gIH1cblxuICByZW1vdmVBdmFpbGFibGVPY2N1cGFudChvY2N1cGFudElkKSB7XG4gICAgY29uc3QgaWR4ID0gdGhpcy5hdmFpbGFibGVPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKTtcbiAgICBpZiAoaWR4ICE9PSAtMSkge1xuICAgICAgdGhpcy5hdmFpbGFibGVPY2N1cGFudHMuc3BsaWNlKGlkeCwgMSk7XG4gICAgfVxuICB9XG5cbiAgc3luY09jY3VwYW50cyhyZXF1ZXN0ZWRPY2N1cGFudHMpIHtcbiAgICBpZiAocmVxdWVzdGVkT2NjdXBhbnRzKSB7XG4gICAgICB0aGlzLnJlcXVlc3RlZE9jY3VwYW50cyA9IHJlcXVlc3RlZE9jY3VwYW50cztcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMucmVxdWVzdGVkT2NjdXBhbnRzKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gQWRkIGFueSByZXF1ZXN0ZWQsIGF2YWlsYWJsZSwgYW5kIG5vbi1wZW5kaW5nIG9jY3VwYW50cy5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMucmVxdWVzdGVkT2NjdXBhbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBvY2N1cGFudElkID0gdGhpcy5yZXF1ZXN0ZWRPY2N1cGFudHNbaV07XG4gICAgICBpZiAoIXRoaXMub2NjdXBhbnRzW29jY3VwYW50SWRdICYmIHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmluZGV4T2Yob2NjdXBhbnRJZCkgIT09IC0xICYmICF0aGlzLnBlbmRpbmdPY2N1cGFudHMuaGFzKG9jY3VwYW50SWQpKSB7XG4gICAgICAgIHRoaXMuYWRkT2NjdXBhbnQob2NjdXBhbnRJZCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmVtb3ZlIGFueSB1bnJlcXVlc3RlZCBhbmQgY3VycmVudGx5IGFkZGVkIG9jY3VwYW50cy5cbiAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmxlbmd0aDsgaisrKSB7XG4gICAgICBjb25zdCBvY2N1cGFudElkID0gdGhpcy5hdmFpbGFibGVPY2N1cGFudHNbal07XG4gICAgICBpZiAodGhpcy5vY2N1cGFudHNbb2NjdXBhbnRJZF0gJiYgdGhpcy5yZXF1ZXN0ZWRPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKSA9PT0gLTEpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVPY2N1cGFudChvY2N1cGFudElkKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDYWxsIHRoZSBOZXR3b3JrZWQgQUZyYW1lIGNhbGxiYWNrcyBmb3IgdGhlIHVwZGF0ZWQgb2NjdXBhbnRzIGxpc3QuXG4gICAgdGhpcy5vbk9jY3VwYW50c0NoYW5nZWQodGhpcy5vY2N1cGFudHMpO1xuICB9XG5cbiAgYXN5bmMgYWRkT2NjdXBhbnQob2NjdXBhbnRJZCkge1xuICAgIHRoaXMucGVuZGluZ09jY3VwYW50cy5hZGQob2NjdXBhbnRJZCk7XG4gICAgXG4gICAgY29uc3QgYXZhaWxhYmxlT2NjdXBhbnRzQ291bnQgPSB0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5sZW5ndGg7XG4gICAgaWYgKGF2YWlsYWJsZU9jY3VwYW50c0NvdW50ID4gQVZBSUxBQkxFX09DQ1VQQU5UU19USFJFU0hPTEQpIHtcbiAgICAgIGF3YWl0IHJhbmRvbURlbGF5KDAsIE1BWF9TVUJTQ1JJQkVfREVMQVkpO1xuICAgIH1cbiAgXG4gICAgY29uc3Qgc3Vic2NyaWJlciA9IGF3YWl0IHRoaXMuY3JlYXRlU3Vic2NyaWJlcihvY2N1cGFudElkKTtcbiAgICBpZiAoc3Vic2NyaWJlcikge1xuICAgICAgaWYoIXRoaXMucGVuZGluZ09jY3VwYW50cy5oYXMob2NjdXBhbnRJZCkpIHtcbiAgICAgICAgc3Vic2NyaWJlci5jb25uLmNsb3NlKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnBlbmRpbmdPY2N1cGFudHMuZGVsZXRlKG9jY3VwYW50SWQpO1xuICAgICAgICB0aGlzLm9jY3VwYW50SWRzLnB1c2gob2NjdXBhbnRJZCk7XG4gICAgICAgIHRoaXMub2NjdXBhbnRzW29jY3VwYW50SWRdID0gc3Vic2NyaWJlcjtcblxuICAgICAgICB0aGlzLnNldE1lZGlhU3RyZWFtKG9jY3VwYW50SWQsIHN1YnNjcmliZXIubWVkaWFTdHJlYW0pO1xuXG4gICAgICAgIC8vIENhbGwgdGhlIE5ldHdvcmtlZCBBRnJhbWUgY2FsbGJhY2tzIGZvciB0aGUgbmV3IG9jY3VwYW50LlxuICAgICAgICB0aGlzLm9uT2NjdXBhbnRDb25uZWN0ZWQob2NjdXBhbnRJZCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmVtb3ZlQWxsT2NjdXBhbnRzKCkge1xuICAgIHRoaXMucGVuZGluZ09jY3VwYW50cy5jbGVhcigpO1xuICAgIGZvciAobGV0IGkgPSB0aGlzLm9jY3VwYW50SWRzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICB0aGlzLnJlbW92ZU9jY3VwYW50KHRoaXMub2NjdXBhbnRJZHNbaV0pO1xuICAgIH1cbiAgfVxuXG4gIHJlbW92ZU9jY3VwYW50KG9jY3VwYW50SWQpIHtcbiAgICB0aGlzLnBlbmRpbmdPY2N1cGFudHMuZGVsZXRlKG9jY3VwYW50SWQpO1xuICAgIFxuICAgIGlmICh0aGlzLm9jY3VwYW50c1tvY2N1cGFudElkXSkge1xuICAgICAgLy8gQ2xvc2UgdGhlIHN1YnNjcmliZXIgcGVlciBjb25uZWN0aW9uLiBXaGljaCBhbHNvIGRldGFjaGVzIHRoZSBwbHVnaW4gaGFuZGxlLlxuICAgICAgdGhpcy5vY2N1cGFudHNbb2NjdXBhbnRJZF0uY29ubi5jbG9zZSgpO1xuICAgICAgZGVsZXRlIHRoaXMub2NjdXBhbnRzW29jY3VwYW50SWRdO1xuICAgICAgXG4gICAgICB0aGlzLm9jY3VwYW50SWRzLnNwbGljZSh0aGlzLm9jY3VwYW50SWRzLmluZGV4T2Yob2NjdXBhbnRJZCksIDEpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLm1lZGlhU3RyZWFtc1tvY2N1cGFudElkXSkge1xuICAgICAgZGVsZXRlIHRoaXMubWVkaWFTdHJlYW1zW29jY3VwYW50SWRdO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmhhcyhvY2N1cGFudElkKSkge1xuICAgICAgY29uc3QgbXNnID0gXCJUaGUgdXNlciBkaXNjb25uZWN0ZWQgYmVmb3JlIHRoZSBtZWRpYSBzdHJlYW0gd2FzIHJlc29sdmVkLlwiO1xuICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5nZXQob2NjdXBhbnRJZCkuYXVkaW8ucmVqZWN0KG1zZyk7XG4gICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChvY2N1cGFudElkKS52aWRlby5yZWplY3QobXNnKTtcbiAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZGVsZXRlKG9jY3VwYW50SWQpO1xuICAgIH1cblxuICAgIC8vIENhbGwgdGhlIE5ldHdvcmtlZCBBRnJhbWUgY2FsbGJhY2tzIGZvciB0aGUgcmVtb3ZlZCBvY2N1cGFudC5cbiAgICB0aGlzLm9uT2NjdXBhbnREaXNjb25uZWN0ZWQob2NjdXBhbnRJZCk7XG4gIH1cblxuICBhc3NvY2lhdGUoY29ubiwgaGFuZGxlKSB7XG4gICAgY29ubi5hZGRFdmVudExpc3RlbmVyKFwiaWNlY2FuZGlkYXRlXCIsIGV2ID0+IHtcbiAgICAgIGhhbmRsZS5zZW5kVHJpY2tsZShldi5jYW5kaWRhdGUgfHwgbnVsbCkuY2F0Y2goZSA9PiBlcnJvcihcIkVycm9yIHRyaWNrbGluZyBJQ0U6ICVvXCIsIGUpKTtcbiAgICB9KTtcbiAgICBjb25uLmFkZEV2ZW50TGlzdGVuZXIoXCJpY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2VcIiwgZXYgPT4ge1xuICAgICAgaWYgKGNvbm4uaWNlQ29ubmVjdGlvblN0YXRlID09PSBcImNvbm5lY3RlZFwiKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiSUNFIHN0YXRlIGNoYW5nZWQgdG8gY29ubmVjdGVkXCIpO1xuICAgICAgfVxuICAgICAgaWYgKGNvbm4uaWNlQ29ubmVjdGlvblN0YXRlID09PSBcImRpc2Nvbm5lY3RlZFwiKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcIklDRSBzdGF0ZSBjaGFuZ2VkIHRvIGRpc2Nvbm5lY3RlZFwiKTtcbiAgICAgIH1cbiAgICAgIGlmIChjb25uLmljZUNvbm5lY3Rpb25TdGF0ZSA9PT0gXCJmYWlsZWRcIikge1xuICAgICAgICBjb25zb2xlLndhcm4oXCJJQ0UgZmFpbHVyZSBkZXRlY3RlZC4gUmVjb25uZWN0aW5nIGluIDEwcy5cIik7XG4gICAgICAgIHRoaXMucGVyZm9ybURlbGF5ZWRSZWNvbm5lY3QoKTtcbiAgICAgIH1cbiAgICB9KVxuXG4gICAgLy8gd2UgaGF2ZSB0byBkZWJvdW5jZSB0aGVzZSBiZWNhdXNlIGphbnVzIGdldHMgYW5ncnkgaWYgeW91IHNlbmQgaXQgYSBuZXcgU0RQIGJlZm9yZVxuICAgIC8vIGl0J3MgZmluaXNoZWQgcHJvY2Vzc2luZyBhbiBleGlzdGluZyBTRFAuIGluIGFjdHVhbGl0eSwgaXQgc2VlbXMgbGlrZSB0aGlzIGlzIG1heWJlXG4gICAgLy8gdG9vIGxpYmVyYWwgYW5kIHdlIG5lZWQgdG8gd2FpdCBzb21lIGFtb3VudCBvZiB0aW1lIGFmdGVyIGFuIG9mZmVyIGJlZm9yZSBzZW5kaW5nIGFub3RoZXIsXG4gICAgLy8gYnV0IHdlIGRvbid0IGN1cnJlbnRseSBrbm93IGFueSBnb29kIHdheSBvZiBkZXRlY3RpbmcgZXhhY3RseSBob3cgbG9uZyA6KFxuICAgIGNvbm4uYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgIFwibmVnb3RpYXRpb25uZWVkZWRcIixcbiAgICAgIGRlYm91bmNlKGV2ID0+IHtcbiAgICAgICAgZGVidWcoXCJTZW5kaW5nIG5ldyBvZmZlciBmb3IgaGFuZGxlOiAlb1wiLCBoYW5kbGUpO1xuICAgICAgICB2YXIgb2ZmZXIgPSBjb25uLmNyZWF0ZU9mZmVyKCkudGhlbih0aGlzLmNvbmZpZ3VyZVB1Ymxpc2hlclNkcCkudGhlbih0aGlzLmZpeFNhZmFyaUljZVVGcmFnKTtcbiAgICAgICAgdmFyIGxvY2FsID0gb2ZmZXIudGhlbihvID0+IGNvbm4uc2V0TG9jYWxEZXNjcmlwdGlvbihvKSk7XG4gICAgICAgIHZhciByZW1vdGUgPSBvZmZlcjtcblxuICAgICAgICByZW1vdGUgPSByZW1vdGVcbiAgICAgICAgICAudGhlbih0aGlzLmZpeFNhZmFyaUljZVVGcmFnKVxuICAgICAgICAgIC50aGVuKGogPT4gaGFuZGxlLnNlbmRKc2VwKGopKVxuICAgICAgICAgIC50aGVuKHIgPT4gY29ubi5zZXRSZW1vdGVEZXNjcmlwdGlvbihyLmpzZXApKTtcbiAgICAgICAgcmV0dXJuIFByb21pc2UuYWxsKFtsb2NhbCwgcmVtb3RlXSkuY2F0Y2goZSA9PiBlcnJvcihcIkVycm9yIG5lZ290aWF0aW5nIG9mZmVyOiAlb1wiLCBlKSk7XG4gICAgICB9KVxuICAgICk7XG4gICAgaGFuZGxlLm9uKFxuICAgICAgXCJldmVudFwiLFxuICAgICAgZGVib3VuY2UoZXYgPT4ge1xuICAgICAgICB2YXIganNlcCA9IGV2LmpzZXA7XG4gICAgICAgIGlmIChqc2VwICYmIGpzZXAudHlwZSA9PSBcIm9mZmVyXCIpIHtcbiAgICAgICAgICBkZWJ1ZyhcIkFjY2VwdGluZyBuZXcgb2ZmZXIgZm9yIGhhbmRsZTogJW9cIiwgaGFuZGxlKTtcbiAgICAgICAgICB2YXIgYW5zd2VyID0gY29ublxuICAgICAgICAgICAgLnNldFJlbW90ZURlc2NyaXB0aW9uKHRoaXMuY29uZmlndXJlU3Vic2NyaWJlclNkcChqc2VwKSlcbiAgICAgICAgICAgIC50aGVuKF8gPT4gY29ubi5jcmVhdGVBbnN3ZXIoKSlcbiAgICAgICAgICAgIC50aGVuKHRoaXMuZml4U2FmYXJpSWNlVUZyYWcpO1xuICAgICAgICAgIHZhciBsb2NhbCA9IGFuc3dlci50aGVuKGEgPT4gY29ubi5zZXRMb2NhbERlc2NyaXB0aW9uKGEpKTtcbiAgICAgICAgICB2YXIgcmVtb3RlID0gYW5zd2VyLnRoZW4oaiA9PiBoYW5kbGUuc2VuZEpzZXAoaikpO1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLmFsbChbbG9jYWwsIHJlbW90ZV0pLmNhdGNoKGUgPT4gZXJyb3IoXCJFcnJvciBuZWdvdGlhdGluZyBhbnN3ZXI6ICVvXCIsIGUpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBzb21lIG90aGVyIGtpbmQgb2YgZXZlbnQsIG5vdGhpbmcgdG8gZG9cbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgYXN5bmMgY3JlYXRlUHVibGlzaGVyKCkge1xuICAgIHZhciBoYW5kbGUgPSBuZXcgbWouSmFudXNQbHVnaW5IYW5kbGUodGhpcy5zZXNzaW9uKTtcbiAgICB2YXIgY29ubiA9IG5ldyBSVENQZWVyQ29ubmVjdGlvbih0aGlzLnBlZXJDb25uZWN0aW9uQ29uZmlnIHx8IERFRkFVTFRfUEVFUl9DT05ORUNUSU9OX0NPTkZJRyk7XG5cbiAgICBkZWJ1ZyhcInB1YiB3YWl0aW5nIGZvciBzZnVcIik7XG4gICAgYXdhaXQgaGFuZGxlLmF0dGFjaChcImphbnVzLnBsdWdpbi5zZnVcIiwgdGhpcy5sb29wcyAmJiB0aGlzLmNsaWVudElkID8gcGFyc2VJbnQodGhpcy5jbGllbnRJZCkgJSB0aGlzLmxvb3BzIDogdW5kZWZpbmVkKTtcblxuICAgIHRoaXMuYXNzb2NpYXRlKGNvbm4sIGhhbmRsZSk7XG5cbiAgICBkZWJ1ZyhcInB1YiB3YWl0aW5nIGZvciBkYXRhIGNoYW5uZWxzICYgd2VicnRjdXBcIik7XG4gICAgdmFyIHdlYnJ0Y3VwID0gbmV3IFByb21pc2UocmVzb2x2ZSA9PiBoYW5kbGUub24oXCJ3ZWJydGN1cFwiLCByZXNvbHZlKSk7XG5cbiAgICAvLyBVbnJlbGlhYmxlIGRhdGFjaGFubmVsOiBzZW5kaW5nIGFuZCByZWNlaXZpbmcgY29tcG9uZW50IHVwZGF0ZXMuXG4gICAgLy8gUmVsaWFibGUgZGF0YWNoYW5uZWw6IHNlbmRpbmcgYW5kIHJlY2lldmluZyBlbnRpdHkgaW5zdGFudGlhdGlvbnMuXG4gICAgdmFyIHJlbGlhYmxlQ2hhbm5lbCA9IGNvbm4uY3JlYXRlRGF0YUNoYW5uZWwoXCJyZWxpYWJsZVwiLCB7IG9yZGVyZWQ6IHRydWUgfSk7XG4gICAgdmFyIHVucmVsaWFibGVDaGFubmVsID0gY29ubi5jcmVhdGVEYXRhQ2hhbm5lbChcInVucmVsaWFibGVcIiwge1xuICAgICAgb3JkZXJlZDogZmFsc2UsXG4gICAgICBtYXhSZXRyYW5zbWl0czogMFxuICAgIH0pO1xuXG4gICAgcmVsaWFibGVDaGFubmVsLmFkZEV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIGUgPT4gdGhpcy5vbkRhdGFDaGFubmVsTWVzc2FnZShlLCBcImphbnVzLXJlbGlhYmxlXCIpKTtcbiAgICB1bnJlbGlhYmxlQ2hhbm5lbC5hZGRFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCBlID0+IHRoaXMub25EYXRhQ2hhbm5lbE1lc3NhZ2UoZSwgXCJqYW51cy11bnJlbGlhYmxlXCIpKTtcblxuICAgIGF3YWl0IHdlYnJ0Y3VwO1xuICAgIGF3YWl0IHVudGlsRGF0YUNoYW5uZWxPcGVuKHJlbGlhYmxlQ2hhbm5lbCk7XG4gICAgYXdhaXQgdW50aWxEYXRhQ2hhbm5lbE9wZW4odW5yZWxpYWJsZUNoYW5uZWwpO1xuXG4gICAgLy8gZG9pbmcgdGhpcyBoZXJlIGlzIHNvcnQgb2YgYSBoYWNrIGFyb3VuZCBjaHJvbWUgcmVuZWdvdGlhdGlvbiB3ZWlyZG5lc3MgLS1cbiAgICAvLyBpZiB3ZSBkbyBpdCBwcmlvciB0byB3ZWJydGN1cCwgY2hyb21lIG9uIGdlYXIgVlIgd2lsbCBzb21ldGltZXMgcHV0IGFcbiAgICAvLyByZW5lZ290aWF0aW9uIG9mZmVyIGluIGZsaWdodCB3aGlsZSB0aGUgZmlyc3Qgb2ZmZXIgd2FzIHN0aWxsIGJlaW5nXG4gICAgLy8gcHJvY2Vzc2VkIGJ5IGphbnVzLiB3ZSBzaG91bGQgZmluZCBzb21lIG1vcmUgcHJpbmNpcGxlZCB3YXkgdG8gZmlndXJlIG91dFxuICAgIC8vIHdoZW4gamFudXMgaXMgZG9uZSBpbiB0aGUgZnV0dXJlLlxuICAgIGlmICh0aGlzLmxvY2FsTWVkaWFTdHJlYW0pIHtcbiAgICAgIHRoaXMubG9jYWxNZWRpYVN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKHRyYWNrID0+IHtcbiAgICAgICAgY29ubi5hZGRUcmFjayh0cmFjaywgdGhpcy5sb2NhbE1lZGlhU3RyZWFtKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIEhhbmRsZSBhbGwgb2YgdGhlIGpvaW4gYW5kIGxlYXZlIGV2ZW50cy5cbiAgICBoYW5kbGUub24oXCJldmVudFwiLCBldiA9PiB7XG4gICAgICB2YXIgZGF0YSA9IGV2LnBsdWdpbmRhdGEuZGF0YTtcbiAgICAgIGlmIChkYXRhLmV2ZW50ID09IFwiam9pblwiICYmIGRhdGEucm9vbV9pZCA9PSB0aGlzLnJvb20pIHtcbiAgICAgICAgaWYgKHRoaXMuZGVsYXllZFJlY29ubmVjdFRpbWVvdXQpIHtcbiAgICAgICAgICAvLyBEb24ndCBjcmVhdGUgYSBuZXcgUlRDUGVlckNvbm5lY3Rpb24sIGFsbCBSVENQZWVyQ29ubmVjdGlvbiB3aWxsIGJlIGNsb3NlZCBpbiBsZXNzIHRoYW4gMTBzLlxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmFkZEF2YWlsYWJsZU9jY3VwYW50KGRhdGEudXNlcl9pZCk7XG4gICAgICAgIHRoaXMuc3luY09jY3VwYW50cygpO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50ID09IFwibGVhdmVcIiAmJiBkYXRhLnJvb21faWQgPT0gdGhpcy5yb29tKSB7XG4gICAgICAgIHRoaXMucmVtb3ZlQXZhaWxhYmxlT2NjdXBhbnQoZGF0YS51c2VyX2lkKTtcbiAgICAgICAgdGhpcy5yZW1vdmVPY2N1cGFudChkYXRhLnVzZXJfaWQpO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50ID09IFwiYmxvY2tlZFwiKSB7XG4gICAgICAgIGRvY3VtZW50LmJvZHkuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoXCJibG9ja2VkXCIsIHsgZGV0YWlsOiB7IGNsaWVudElkOiBkYXRhLmJ5IH0gfSkpO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50ID09IFwidW5ibG9ja2VkXCIpIHtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChcInVuYmxvY2tlZFwiLCB7IGRldGFpbDogeyBjbGllbnRJZDogZGF0YS5ieSB9IH0pKTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudCA9PT0gXCJkYXRhXCIpIHtcbiAgICAgICAgdGhpcy5vbkRhdGEoSlNPTi5wYXJzZShkYXRhLmJvZHkpLCBcImphbnVzLWV2ZW50XCIpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgZGVidWcoXCJwdWIgd2FpdGluZyBmb3Igam9pblwiKTtcblxuICAgIC8vIFNlbmQgam9pbiBtZXNzYWdlIHRvIGphbnVzLiBMaXN0ZW4gZm9yIGpvaW4vbGVhdmUgbWVzc2FnZXMuIEF1dG9tYXRpY2FsbHkgc3Vic2NyaWJlIHRvIGFsbCB1c2VycycgV2ViUlRDIGRhdGEuXG4gICAgdmFyIG1lc3NhZ2UgPSBhd2FpdCB0aGlzLnNlbmRKb2luKGhhbmRsZSwge1xuICAgICAgbm90aWZpY2F0aW9uczogdHJ1ZSxcbiAgICAgIGRhdGE6IHRydWVcbiAgICB9KTtcblxuICAgIGlmICghbWVzc2FnZS5wbHVnaW5kYXRhLmRhdGEuc3VjY2Vzcykge1xuICAgICAgY29uc3QgZXJyID0gbWVzc2FnZS5wbHVnaW5kYXRhLmRhdGEuZXJyb3I7XG4gICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICAvLyBXZSBtYXkgZ2V0IGhlcmUgYmVjYXVzZSBvZiBhbiBleHBpcmVkIEpXVC5cbiAgICAgIC8vIENsb3NlIHRoZSBjb25uZWN0aW9uIG91cnNlbGYgb3RoZXJ3aXNlIGphbnVzIHdpbGwgY2xvc2UgaXQgYWZ0ZXJcbiAgICAgIC8vIHNlc3Npb25fdGltZW91dCBiZWNhdXNlIHdlIGRpZG4ndCBzZW5kIGFueSBrZWVwYWxpdmUgYW5kIHRoaXMgd2lsbFxuICAgICAgLy8gdHJpZ2dlciBhIGRlbGF5ZWQgcmVjb25uZWN0IGJlY2F1c2Ugb2YgdGhlIGljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZVxuICAgICAgLy8gbGlzdGVuZXIgZm9yIGZhaWx1cmUgc3RhdGUuXG4gICAgICAvLyBFdmVuIGlmIHRoZSBhcHAgY29kZSBjYWxscyBkaXNjb25uZWN0IGluIGNhc2Ugb2YgZXJyb3IsIGRpc2Nvbm5lY3RcbiAgICAgIC8vIHdvbid0IGNsb3NlIHRoZSBwZWVyIGNvbm5lY3Rpb24gYmVjYXVzZSB0aGlzLnB1Ymxpc2hlciBpcyBub3Qgc2V0LlxuICAgICAgY29ubi5jbG9zZSgpO1xuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cblxuICAgIHZhciBpbml0aWFsT2NjdXBhbnRzID0gbWVzc2FnZS5wbHVnaW5kYXRhLmRhdGEucmVzcG9uc2UudXNlcnNbdGhpcy5yb29tXSB8fCBbXTtcblxuICAgIGlmIChpbml0aWFsT2NjdXBhbnRzLmluY2x1ZGVzKHRoaXMuY2xpZW50SWQpKSB7XG4gICAgICBjb25zb2xlLndhcm4oXCJKYW51cyBzdGlsbCBoYXMgcHJldmlvdXMgc2Vzc2lvbiBmb3IgdGhpcyBjbGllbnQuIFJlY29ubmVjdGluZyBpbiAxMHMuXCIpO1xuICAgICAgdGhpcy5wZXJmb3JtRGVsYXllZFJlY29ubmVjdCgpO1xuICAgIH1cblxuICAgIGRlYnVnKFwicHVibGlzaGVyIHJlYWR5XCIpO1xuICAgIHJldHVybiB7XG4gICAgICBoYW5kbGUsXG4gICAgICBpbml0aWFsT2NjdXBhbnRzLFxuICAgICAgcmVsaWFibGVDaGFubmVsLFxuICAgICAgdW5yZWxpYWJsZUNoYW5uZWwsXG4gICAgICBjb25uXG4gICAgfTtcbiAgfVxuXG4gIGNvbmZpZ3VyZVB1Ymxpc2hlclNkcChqc2VwKSB7XG4gICAganNlcC5zZHAgPSBqc2VwLnNkcC5yZXBsYWNlKC9hPWZtdHA6KDEwOXwxMTEpLipcXHJcXG4vZywgKGxpbmUsIHB0KSA9PiB7XG4gICAgICBjb25zdCBwYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbihzZHBVdGlscy5wYXJzZUZtdHAobGluZSksIE9QVVNfUEFSQU1FVEVSUyk7XG4gICAgICByZXR1cm4gc2RwVXRpbHMud3JpdGVGbXRwKHsgcGF5bG9hZFR5cGU6IHB0LCBwYXJhbWV0ZXJzOiBwYXJhbWV0ZXJzIH0pO1xuICAgIH0pO1xuICAgIHJldHVybiBqc2VwO1xuICB9XG5cbiAgY29uZmlndXJlU3Vic2NyaWJlclNkcChqc2VwKSB7XG4gICAgLy8gdG9kbzogY29uc2lkZXIgY2xlYW5pbmcgdXAgdGhlc2UgaGFja3MgdG8gdXNlIHNkcHV0aWxzXG4gICAgaWYgKCFpc0gyNjRWaWRlb1N1cHBvcnRlZCkge1xuICAgICAgaWYgKG5hdmlnYXRvci51c2VyQWdlbnQuaW5kZXhPZihcIkhlYWRsZXNzQ2hyb21lXCIpICE9PSAtMSkge1xuICAgICAgICAvLyBIZWFkbGVzc0Nocm9tZSAoZS5nLiBwdXBwZXRlZXIpIGRvZXNuJ3Qgc3VwcG9ydCB3ZWJydGMgdmlkZW8gc3RyZWFtcywgc28gd2UgcmVtb3ZlIHRob3NlIGxpbmVzIGZyb20gdGhlIFNEUC5cbiAgICAgICAganNlcC5zZHAgPSBqc2VwLnNkcC5yZXBsYWNlKC9tPXZpZGVvW15dKm09LywgXCJtPVwiKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUT0RPOiBIYWNrIHRvIGdldCB2aWRlbyB3b3JraW5nIG9uIENocm9tZSBmb3IgQW5kcm9pZC4gaHR0cHM6Ly9ncm91cHMuZ29vZ2xlLmNvbS9mb3J1bS8jIXRvcGljL21vemlsbGEuZGV2Lm1lZGlhL1llMjl2dU1UcG84XG4gICAgaWYgKG5hdmlnYXRvci51c2VyQWdlbnQuaW5kZXhPZihcIkFuZHJvaWRcIikgPT09IC0xKSB7XG4gICAgICBqc2VwLnNkcCA9IGpzZXAuc2RwLnJlcGxhY2UoXG4gICAgICAgIFwiYT1ydGNwLWZiOjEwNyBnb29nLXJlbWJcXHJcXG5cIixcbiAgICAgICAgXCJhPXJ0Y3AtZmI6MTA3IGdvb2ctcmVtYlxcclxcbmE9cnRjcC1mYjoxMDcgdHJhbnNwb3J0LWNjXFxyXFxuYT1mbXRwOjEwNyBsZXZlbC1hc3ltbWV0cnktYWxsb3dlZD0xO3BhY2tldGl6YXRpb24tbW9kZT0xO3Byb2ZpbGUtbGV2ZWwtaWQ9NDJlMDFmXFxyXFxuXCJcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGpzZXAuc2RwID0ganNlcC5zZHAucmVwbGFjZShcbiAgICAgICAgXCJhPXJ0Y3AtZmI6MTA3IGdvb2ctcmVtYlxcclxcblwiLFxuICAgICAgICBcImE9cnRjcC1mYjoxMDcgZ29vZy1yZW1iXFxyXFxuYT1ydGNwLWZiOjEwNyB0cmFuc3BvcnQtY2NcXHJcXG5hPWZtdHA6MTA3IGxldmVsLWFzeW1tZXRyeS1hbGxvd2VkPTE7cGFja2V0aXphdGlvbi1tb2RlPTE7cHJvZmlsZS1sZXZlbC1pZD00MjAwMWZcXHJcXG5cIlxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGpzZXA7XG4gIH1cblxuICBhc3luYyBmaXhTYWZhcmlJY2VVRnJhZyhqc2VwKSB7XG4gICAgLy8gU2FmYXJpIHByb2R1Y2VzIGEgXFxuIGluc3RlYWQgb2YgYW4gXFxyXFxuIGZvciB0aGUgaWNlLXVmcmFnLiBTZWUgaHR0cHM6Ly9naXRodWIuY29tL21lZXRlY2hvL2phbnVzLWdhdGV3YXkvaXNzdWVzLzE4MThcbiAgICBqc2VwLnNkcCA9IGpzZXAuc2RwLnJlcGxhY2UoL1teXFxyXVxcbmE9aWNlLXVmcmFnL2csIFwiXFxyXFxuYT1pY2UtdWZyYWdcIik7XG4gICAgcmV0dXJuIGpzZXBcbiAgfVxuXG4gIGFzeW5jIGNyZWF0ZVN1YnNjcmliZXIob2NjdXBhbnRJZCwgbWF4UmV0cmllcyA9IDUpIHtcbiAgICBpZiAodGhpcy5hdmFpbGFibGVPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKSA9PT0gLTEpIHtcbiAgICAgIGNvbnNvbGUud2FybihvY2N1cGFudElkICsgXCI6IGNhbmNlbGxlZCBvY2N1cGFudCBjb25uZWN0aW9uLCBvY2N1cGFudCBsZWZ0IGJlZm9yZSBzdWJzY3JpcHRpb24gbmVnb3RhdGlvbi5cIik7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICB2YXIgaGFuZGxlID0gbmV3IG1qLkphbnVzUGx1Z2luSGFuZGxlKHRoaXMuc2Vzc2lvbik7XG4gICAgdmFyIGNvbm4gPSBuZXcgUlRDUGVlckNvbm5lY3Rpb24odGhpcy5wZWVyQ29ubmVjdGlvbkNvbmZpZyB8fCBERUZBVUxUX1BFRVJfQ09OTkVDVElPTl9DT05GSUcpO1xuXG4gICAgZGVidWcob2NjdXBhbnRJZCArIFwiOiBzdWIgd2FpdGluZyBmb3Igc2Z1XCIpO1xuICAgIGF3YWl0IGhhbmRsZS5hdHRhY2goXCJqYW51cy5wbHVnaW4uc2Z1XCIsIHRoaXMubG9vcHMgPyBwYXJzZUludChvY2N1cGFudElkKSAlIHRoaXMubG9vcHMgOiB1bmRlZmluZWQpO1xuXG4gICAgdGhpcy5hc3NvY2lhdGUoY29ubiwgaGFuZGxlKTtcblxuICAgIGRlYnVnKG9jY3VwYW50SWQgKyBcIjogc3ViIHdhaXRpbmcgZm9yIGpvaW5cIik7XG5cbiAgICBpZiAodGhpcy5hdmFpbGFibGVPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKSA9PT0gLTEpIHtcbiAgICAgIGNvbm4uY2xvc2UoKTtcbiAgICAgIGNvbnNvbGUud2FybihvY2N1cGFudElkICsgXCI6IGNhbmNlbGxlZCBvY2N1cGFudCBjb25uZWN0aW9uLCBvY2N1cGFudCBsZWZ0IGFmdGVyIGF0dGFjaFwiKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGxldCB3ZWJydGNGYWlsZWQgPSBmYWxzZTtcblxuICAgIGNvbnN0IHdlYnJ0Y3VwID0gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgICBjb25zdCBsZWZ0SW50ZXJ2YWwgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgICAgIGNsZWFySW50ZXJ2YWwobGVmdEludGVydmFsKTtcbiAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgIH1cbiAgICAgIH0sIDEwMDApO1xuXG4gICAgICBjb25zdCB0aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwobGVmdEludGVydmFsKTtcbiAgICAgICAgd2VicnRjRmFpbGVkID0gdHJ1ZTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfSwgU1VCU0NSSUJFX1RJTUVPVVRfTVMpO1xuXG4gICAgICBoYW5kbGUub24oXCJ3ZWJydGN1cFwiLCAoKSA9PiB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgY2xlYXJJbnRlcnZhbChsZWZ0SW50ZXJ2YWwpO1xuICAgICAgICByZXNvbHZlKCk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIC8vIFNlbmQgam9pbiBtZXNzYWdlIHRvIGphbnVzLiBEb24ndCBsaXN0ZW4gZm9yIGpvaW4vbGVhdmUgbWVzc2FnZXMuIFN1YnNjcmliZSB0byB0aGUgb2NjdXBhbnQncyBtZWRpYS5cbiAgICAvLyBKYW51cyBzaG91bGQgc2VuZCB1cyBhbiBvZmZlciBmb3IgdGhpcyBvY2N1cGFudCdzIG1lZGlhIGluIHJlc3BvbnNlIHRvIHRoaXMuXG4gICAgYXdhaXQgdGhpcy5zZW5kSm9pbihoYW5kbGUsIHsgbWVkaWE6IG9jY3VwYW50SWQgfSk7XG5cbiAgICBpZiAodGhpcy5hdmFpbGFibGVPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKSA9PT0gLTEpIHtcbiAgICAgIGNvbm4uY2xvc2UoKTtcbiAgICAgIGNvbnNvbGUud2FybihvY2N1cGFudElkICsgXCI6IGNhbmNlbGxlZCBvY2N1cGFudCBjb25uZWN0aW9uLCBvY2N1cGFudCBsZWZ0IGFmdGVyIGpvaW5cIik7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBkZWJ1ZyhvY2N1cGFudElkICsgXCI6IHN1YiB3YWl0aW5nIGZvciB3ZWJydGN1cFwiKTtcbiAgICBhd2FpdCB3ZWJydGN1cDtcblxuICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgY29ubi5jbG9zZSgpO1xuICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogY2FuY2VsIG9jY3VwYW50IGNvbm5lY3Rpb24sIG9jY3VwYW50IGxlZnQgZHVyaW5nIG9yIGFmdGVyIHdlYnJ0Y3VwXCIpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgaWYgKHdlYnJ0Y0ZhaWxlZCkge1xuICAgICAgY29ubi5jbG9zZSgpO1xuICAgICAgaWYgKG1heFJldHJpZXMgPiAwKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihvY2N1cGFudElkICsgXCI6IHdlYnJ0YyB1cCB0aW1lZCBvdXQsIHJldHJ5aW5nXCIpO1xuICAgICAgICByZXR1cm4gdGhpcy5jcmVhdGVTdWJzY3JpYmVyKG9jY3VwYW50SWQsIG1heFJldHJpZXMgLSAxKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUud2FybihvY2N1cGFudElkICsgXCI6IHdlYnJ0YyB1cCB0aW1lZCBvdXRcIik7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChpc1NhZmFyaSAmJiAhdGhpcy5faU9TSGFja0RlbGF5ZWRJbml0aWFsUGVlcikge1xuICAgICAgLy8gSEFDSzogdGhlIGZpcnN0IHBlZXIgb24gU2FmYXJpIGR1cmluZyBwYWdlIGxvYWQgY2FuIGZhaWwgdG8gd29yayBpZiB3ZSBkb24ndFxuICAgICAgLy8gd2FpdCBzb21lIHRpbWUgYmVmb3JlIGNvbnRpbnVpbmcgaGVyZS4gU2VlOiBodHRwczovL2dpdGh1Yi5jb20vbW96aWxsYS9odWJzL3B1bGwvMTY5MlxuICAgICAgYXdhaXQgKG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDMwMDApKSk7XG4gICAgICB0aGlzLl9pT1NIYWNrRGVsYXllZEluaXRpYWxQZWVyID0gdHJ1ZTtcbiAgICB9XG5cbiAgICB2YXIgbWVkaWFTdHJlYW0gPSBuZXcgTWVkaWFTdHJlYW0oKTtcbiAgICB2YXIgcmVjZWl2ZXJzID0gY29ubi5nZXRSZWNlaXZlcnMoKTtcbiAgICByZWNlaXZlcnMuZm9yRWFjaChyZWNlaXZlciA9PiB7XG4gICAgICBpZiAocmVjZWl2ZXIudHJhY2spIHtcbiAgICAgICAgbWVkaWFTdHJlYW0uYWRkVHJhY2socmVjZWl2ZXIudHJhY2spO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGlmIChtZWRpYVN0cmVhbS5nZXRUcmFja3MoKS5sZW5ndGggPT09IDApIHtcbiAgICAgIG1lZGlhU3RyZWFtID0gbnVsbDtcbiAgICB9XG5cbiAgICBkZWJ1ZyhvY2N1cGFudElkICsgXCI6IHN1YnNjcmliZXIgcmVhZHlcIik7XG4gICAgcmV0dXJuIHtcbiAgICAgIGhhbmRsZSxcbiAgICAgIG1lZGlhU3RyZWFtLFxuICAgICAgY29ublxuICAgIH07XG4gIH1cblxuICBzZW5kSm9pbihoYW5kbGUsIHN1YnNjcmliZSkge1xuICAgIHJldHVybiBoYW5kbGUuc2VuZE1lc3NhZ2Uoe1xuICAgICAga2luZDogXCJqb2luXCIsXG4gICAgICByb29tX2lkOiB0aGlzLnJvb20sXG4gICAgICB1c2VyX2lkOiB0aGlzLmNsaWVudElkLFxuICAgICAgc3Vic2NyaWJlLFxuICAgICAgdG9rZW46IHRoaXMuam9pblRva2VuXG4gICAgfSk7XG4gIH1cblxuICB0b2dnbGVGcmVlemUoKSB7XG4gICAgaWYgKHRoaXMuZnJvemVuKSB7XG4gICAgICB0aGlzLnVuZnJlZXplKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZnJlZXplKCk7XG4gICAgfVxuICB9XG5cbiAgZnJlZXplKCkge1xuICAgIHRoaXMuZnJvemVuID0gdHJ1ZTtcbiAgfVxuXG4gIHVuZnJlZXplKCkge1xuICAgIHRoaXMuZnJvemVuID0gZmFsc2U7XG4gICAgdGhpcy5mbHVzaFBlbmRpbmdVcGRhdGVzKCk7XG4gIH1cblxuICBkYXRhRm9yVXBkYXRlTXVsdGlNZXNzYWdlKG5ldHdvcmtJZCwgbWVzc2FnZSkge1xuICAgIC8vIFwiZFwiIGlzIGFuIGFycmF5IG9mIGVudGl0eSBkYXRhcywgd2hlcmUgZWFjaCBpdGVtIGluIHRoZSBhcnJheSByZXByZXNlbnRzIGEgdW5pcXVlIGVudGl0eSBhbmQgY29udGFpbnNcbiAgICAvLyBtZXRhZGF0YSBmb3IgdGhlIGVudGl0eSwgYW5kIGFuIGFycmF5IG9mIGNvbXBvbmVudHMgdGhhdCBoYXZlIGJlZW4gdXBkYXRlZCBvbiB0aGUgZW50aXR5LlxuICAgIC8vIFRoaXMgbWV0aG9kIGZpbmRzIHRoZSBkYXRhIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGdpdmVuIG5ldHdvcmtJZC5cbiAgICBmb3IgKGxldCBpID0gMCwgbCA9IG1lc3NhZ2UuZGF0YS5kLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgY29uc3QgZGF0YSA9IG1lc3NhZ2UuZGF0YS5kW2ldO1xuXG4gICAgICBpZiAoZGF0YS5uZXR3b3JrSWQgPT09IG5ldHdvcmtJZCkge1xuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGdldFBlbmRpbmdEYXRhKG5ldHdvcmtJZCwgbWVzc2FnZSkge1xuICAgIGlmICghbWVzc2FnZSkgcmV0dXJuIG51bGw7XG5cbiAgICBsZXQgZGF0YSA9IG1lc3NhZ2UuZGF0YVR5cGUgPT09IFwidW1cIiA/IHRoaXMuZGF0YUZvclVwZGF0ZU11bHRpTWVzc2FnZShuZXR3b3JrSWQsIG1lc3NhZ2UpIDogbWVzc2FnZS5kYXRhO1xuXG4gICAgLy8gSWdub3JlIG1lc3NhZ2VzIHJlbGF0aW5nIHRvIHVzZXJzIHdobyBoYXZlIGRpc2Nvbm5lY3RlZCBzaW5jZSBmcmVlemluZywgdGhlaXIgZW50aXRpZXNcbiAgICAvLyB3aWxsIGhhdmUgYWxlYWR5IGJlZW4gcmVtb3ZlZCBieSBOQUYuXG4gICAgLy8gTm90ZSB0aGF0IGRlbGV0ZSBtZXNzYWdlcyBoYXZlIG5vIFwib3duZXJcIiBzbyB3ZSBoYXZlIHRvIGNoZWNrIGZvciB0aGF0IGFzIHdlbGwuXG4gICAgaWYgKGRhdGEub3duZXIgJiYgIXRoaXMub2NjdXBhbnRzW2RhdGEub3duZXJdKSByZXR1cm4gbnVsbDtcblxuICAgIC8vIElnbm9yZSBtZXNzYWdlcyBmcm9tIHVzZXJzIHRoYXQgd2UgbWF5IGhhdmUgYmxvY2tlZCB3aGlsZSBmcm96ZW4uXG4gICAgaWYgKGRhdGEub3duZXIgJiYgdGhpcy5ibG9ja2VkQ2xpZW50cy5oYXMoZGF0YS5vd25lcikpIHJldHVybiBudWxsO1xuXG4gICAgcmV0dXJuIGRhdGFcbiAgfVxuXG4gIC8vIFVzZWQgZXh0ZXJuYWxseVxuICBnZXRQZW5kaW5nRGF0YUZvck5ldHdvcmtJZChuZXR3b3JrSWQpIHtcbiAgICByZXR1cm4gdGhpcy5nZXRQZW5kaW5nRGF0YShuZXR3b3JrSWQsIHRoaXMuZnJvemVuVXBkYXRlcy5nZXQobmV0d29ya0lkKSk7XG4gIH1cblxuICBmbHVzaFBlbmRpbmdVcGRhdGVzKCkge1xuICAgIGZvciAoY29uc3QgW25ldHdvcmtJZCwgbWVzc2FnZV0gb2YgdGhpcy5mcm96ZW5VcGRhdGVzKSB7XG4gICAgICBsZXQgZGF0YSA9IHRoaXMuZ2V0UGVuZGluZ0RhdGEobmV0d29ya0lkLCBtZXNzYWdlKTtcbiAgICAgIGlmICghZGF0YSkgY29udGludWU7XG5cbiAgICAgIC8vIE92ZXJyaWRlIHRoZSBkYXRhIHR5cGUgb24gXCJ1bVwiIG1lc3NhZ2VzIHR5cGVzLCBzaW5jZSB3ZSBleHRyYWN0IGVudGl0eSB1cGRhdGVzIGZyb20gXCJ1bVwiIG1lc3NhZ2VzIGludG9cbiAgICAgIC8vIGluZGl2aWR1YWwgZnJvemVuVXBkYXRlcyBpbiBzdG9yZVNpbmdsZU1lc3NhZ2UuXG4gICAgICBjb25zdCBkYXRhVHlwZSA9IG1lc3NhZ2UuZGF0YVR5cGUgPT09IFwidW1cIiA/IFwidVwiIDogbWVzc2FnZS5kYXRhVHlwZTtcblxuICAgICAgdGhpcy5vbk9jY3VwYW50TWVzc2FnZShudWxsLCBkYXRhVHlwZSwgZGF0YSwgbWVzc2FnZS5zb3VyY2UpO1xuICAgIH1cbiAgICB0aGlzLmZyb3plblVwZGF0ZXMuY2xlYXIoKTtcbiAgfVxuXG4gIHN0b3JlTWVzc2FnZShtZXNzYWdlKSB7XG4gICAgaWYgKG1lc3NhZ2UuZGF0YVR5cGUgPT09IFwidW1cIikgeyAvLyBVcGRhdGVNdWx0aVxuICAgICAgZm9yIChsZXQgaSA9IDAsIGwgPSBtZXNzYWdlLmRhdGEuZC5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgdGhpcy5zdG9yZVNpbmdsZU1lc3NhZ2UobWVzc2FnZSwgaSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc3RvcmVTaW5nbGVNZXNzYWdlKG1lc3NhZ2UpO1xuICAgIH1cbiAgfVxuXG4gIHN0b3JlU2luZ2xlTWVzc2FnZShtZXNzYWdlLCBpbmRleCkge1xuICAgIGNvbnN0IGRhdGEgPSBpbmRleCAhPT0gdW5kZWZpbmVkID8gbWVzc2FnZS5kYXRhLmRbaW5kZXhdIDogbWVzc2FnZS5kYXRhO1xuICAgIGNvbnN0IGRhdGFUeXBlID0gbWVzc2FnZS5kYXRhVHlwZTtcbiAgICBjb25zdCBzb3VyY2UgPSBtZXNzYWdlLnNvdXJjZTtcblxuICAgIGNvbnN0IG5ldHdvcmtJZCA9IGRhdGEubmV0d29ya0lkO1xuXG4gICAgaWYgKCF0aGlzLmZyb3plblVwZGF0ZXMuaGFzKG5ldHdvcmtJZCkpIHtcbiAgICAgIHRoaXMuZnJvemVuVXBkYXRlcy5zZXQobmV0d29ya0lkLCBtZXNzYWdlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3Qgc3RvcmVkTWVzc2FnZSA9IHRoaXMuZnJvemVuVXBkYXRlcy5nZXQobmV0d29ya0lkKTtcbiAgICAgIGNvbnN0IHN0b3JlZERhdGEgPSBzdG9yZWRNZXNzYWdlLmRhdGFUeXBlID09PSBcInVtXCIgPyB0aGlzLmRhdGFGb3JVcGRhdGVNdWx0aU1lc3NhZ2UobmV0d29ya0lkLCBzdG9yZWRNZXNzYWdlKSA6IHN0b3JlZE1lc3NhZ2UuZGF0YTtcblxuICAgICAgLy8gQXZvaWQgdXBkYXRpbmcgY29tcG9uZW50cyBpZiB0aGUgZW50aXR5IGRhdGEgcmVjZWl2ZWQgZGlkIG5vdCBjb21lIGZyb20gdGhlIGN1cnJlbnQgb3duZXIuXG4gICAgICBjb25zdCBpc091dGRhdGVkTWVzc2FnZSA9IGRhdGEubGFzdE93bmVyVGltZSA8IHN0b3JlZERhdGEubGFzdE93bmVyVGltZTtcbiAgICAgIGNvbnN0IGlzQ29udGVtcG9yYW5lb3VzTWVzc2FnZSA9IGRhdGEubGFzdE93bmVyVGltZSA9PT0gc3RvcmVkRGF0YS5sYXN0T3duZXJUaW1lO1xuICAgICAgaWYgKGlzT3V0ZGF0ZWRNZXNzYWdlIHx8IChpc0NvbnRlbXBvcmFuZW91c01lc3NhZ2UgJiYgc3RvcmVkRGF0YS5vd25lciA+IGRhdGEub3duZXIpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRhdGFUeXBlID09PSBcInJcIikge1xuICAgICAgICBjb25zdCBjcmVhdGVkV2hpbGVGcm96ZW4gPSBzdG9yZWREYXRhICYmIHN0b3JlZERhdGEuaXNGaXJzdFN5bmM7XG4gICAgICAgIGlmIChjcmVhdGVkV2hpbGVGcm96ZW4pIHtcbiAgICAgICAgICAvLyBJZiB0aGUgZW50aXR5IHdhcyBjcmVhdGVkIGFuZCBkZWxldGVkIHdoaWxlIGZyb3plbiwgZG9uJ3QgYm90aGVyIGNvbnZleWluZyBhbnl0aGluZyB0byB0aGUgY29uc3VtZXIuXG4gICAgICAgICAgdGhpcy5mcm96ZW5VcGRhdGVzLmRlbGV0ZShuZXR3b3JrSWQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIERlbGV0ZSBtZXNzYWdlcyBvdmVycmlkZSBhbnkgb3RoZXIgbWVzc2FnZXMgZm9yIHRoaXMgZW50aXR5XG4gICAgICAgICAgdGhpcy5mcm96ZW5VcGRhdGVzLnNldChuZXR3b3JrSWQsIG1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBtZXJnZSBpbiBjb21wb25lbnQgdXBkYXRlc1xuICAgICAgICBpZiAoc3RvcmVkRGF0YS5jb21wb25lbnRzICYmIGRhdGEuY29tcG9uZW50cykge1xuICAgICAgICAgIE9iamVjdC5hc3NpZ24oc3RvcmVkRGF0YS5jb21wb25lbnRzLCBkYXRhLmNvbXBvbmVudHMpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgb25EYXRhQ2hhbm5lbE1lc3NhZ2UoZSwgc291cmNlKSB7XG4gICAgdGhpcy5vbkRhdGEoSlNPTi5wYXJzZShlLmRhdGEpLCBzb3VyY2UpO1xuICB9XG5cbiAgb25EYXRhKG1lc3NhZ2UsIHNvdXJjZSkge1xuICAgIGlmIChkZWJ1Zy5lbmFibGVkKSB7XG4gICAgICBkZWJ1ZyhgREMgaW46ICR7bWVzc2FnZX1gKTtcbiAgICB9XG5cbiAgICBpZiAoIW1lc3NhZ2UuZGF0YVR5cGUpIHJldHVybjtcblxuICAgIG1lc3NhZ2Uuc291cmNlID0gc291cmNlO1xuXG4gICAgaWYgKHRoaXMuZnJvemVuKSB7XG4gICAgICB0aGlzLnN0b3JlTWVzc2FnZShtZXNzYWdlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5vbk9jY3VwYW50TWVzc2FnZShudWxsLCBtZXNzYWdlLmRhdGFUeXBlLCBtZXNzYWdlLmRhdGEsIG1lc3NhZ2Uuc291cmNlKTtcbiAgICB9XG4gIH1cblxuICBzaG91bGRTdGFydENvbm5lY3Rpb25UbyhjbGllbnQpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHN0YXJ0U3RyZWFtQ29ubmVjdGlvbihjbGllbnQpIHt9XG5cbiAgY2xvc2VTdHJlYW1Db25uZWN0aW9uKGNsaWVudCkge31cblxuICBnZXRDb25uZWN0U3RhdHVzKGNsaWVudElkKSB7XG4gICAgcmV0dXJuIHRoaXMub2NjdXBhbnRzW2NsaWVudElkXSA/IE5BRi5hZGFwdGVycy5JU19DT05ORUNURUQgOiBOQUYuYWRhcHRlcnMuTk9UX0NPTk5FQ1RFRDtcbiAgfVxuXG4gIGFzeW5jIHVwZGF0ZVRpbWVPZmZzZXQoKSB7XG4gICAgaWYgKHRoaXMuaXNEaXNjb25uZWN0ZWQoKSkgcmV0dXJuO1xuXG4gICAgY29uc3QgY2xpZW50U2VudFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gICAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2goZG9jdW1lbnQubG9jYXRpb24uaHJlZiwge1xuICAgICAgbWV0aG9kOiBcIkhFQURcIixcbiAgICAgIGNhY2hlOiBcIm5vLWNhY2hlXCJcbiAgICB9KTtcblxuICAgIGNvbnN0IHByZWNpc2lvbiA9IDEwMDA7XG4gICAgY29uc3Qgc2VydmVyUmVjZWl2ZWRUaW1lID0gbmV3IERhdGUocmVzLmhlYWRlcnMuZ2V0KFwiRGF0ZVwiKSkuZ2V0VGltZSgpICsgcHJlY2lzaW9uIC8gMjtcbiAgICBjb25zdCBjbGllbnRSZWNlaXZlZFRpbWUgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IHNlcnZlclRpbWUgPSBzZXJ2ZXJSZWNlaXZlZFRpbWUgKyAoY2xpZW50UmVjZWl2ZWRUaW1lIC0gY2xpZW50U2VudFRpbWUpIC8gMjtcbiAgICBjb25zdCB0aW1lT2Zmc2V0ID0gc2VydmVyVGltZSAtIGNsaWVudFJlY2VpdmVkVGltZTtcblxuICAgIHRoaXMuc2VydmVyVGltZVJlcXVlc3RzKys7XG5cbiAgICBpZiAodGhpcy5zZXJ2ZXJUaW1lUmVxdWVzdHMgPD0gMTApIHtcbiAgICAgIHRoaXMudGltZU9mZnNldHMucHVzaCh0aW1lT2Zmc2V0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy50aW1lT2Zmc2V0c1t0aGlzLnNlcnZlclRpbWVSZXF1ZXN0cyAlIDEwXSA9IHRpbWVPZmZzZXQ7XG4gICAgfVxuXG4gICAgdGhpcy5hdmdUaW1lT2Zmc2V0ID0gdGhpcy50aW1lT2Zmc2V0cy5yZWR1Y2UoKGFjYywgb2Zmc2V0KSA9PiAoYWNjICs9IG9mZnNldCksIDApIC8gdGhpcy50aW1lT2Zmc2V0cy5sZW5ndGg7XG5cbiAgICBpZiAodGhpcy5zZXJ2ZXJUaW1lUmVxdWVzdHMgPiAxMCkge1xuICAgICAgZGVidWcoYG5ldyBzZXJ2ZXIgdGltZSBvZmZzZXQ6ICR7dGhpcy5hdmdUaW1lT2Zmc2V0fW1zYCk7XG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMudXBkYXRlVGltZU9mZnNldCgpLCA1ICogNjAgKiAxMDAwKTsgLy8gU3luYyBjbG9jayBldmVyeSA1IG1pbnV0ZXMuXG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMudXBkYXRlVGltZU9mZnNldCgpO1xuICAgIH1cbiAgfVxuXG4gIGdldFNlcnZlclRpbWUoKSB7XG4gICAgcmV0dXJuIERhdGUubm93KCkgKyB0aGlzLmF2Z1RpbWVPZmZzZXQ7XG4gIH1cblxuICBnZXRNZWRpYVN0cmVhbShjbGllbnRJZCwgdHlwZSA9IFwiYXVkaW9cIikge1xuICAgIGlmICh0aGlzLm1lZGlhU3RyZWFtc1tjbGllbnRJZF0pIHtcbiAgICAgIGRlYnVnKGBBbHJlYWR5IGhhZCAke3R5cGV9IGZvciAke2NsaWVudElkfWApO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh0aGlzLm1lZGlhU3RyZWFtc1tjbGllbnRJZF1bdHlwZV0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWJ1ZyhgV2FpdGluZyBvbiAke3R5cGV9IGZvciAke2NsaWVudElkfWApO1xuICAgICAgaWYgKCF0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmhhcyhjbGllbnRJZCkpIHtcbiAgICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5zZXQoY2xpZW50SWQsIHt9KTtcblxuICAgICAgICBjb25zdCBhdWRpb1Byb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5nZXQoY2xpZW50SWQpLmF1ZGlvID0geyByZXNvbHZlLCByZWplY3QgfTtcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHZpZGVvUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChjbGllbnRJZCkudmlkZW8gPSB7IHJlc29sdmUsIHJlamVjdCB9O1xuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChjbGllbnRJZCkuYXVkaW8ucHJvbWlzZSA9IGF1ZGlvUHJvbWlzZTtcbiAgICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5nZXQoY2xpZW50SWQpLnZpZGVvLnByb21pc2UgPSB2aWRlb1Byb21pc2U7XG5cbiAgICAgICAgYXVkaW9Qcm9taXNlLmNhdGNoKGUgPT4gY29uc29sZS53YXJuKGAke2NsaWVudElkfSBnZXRNZWRpYVN0cmVhbSBBdWRpbyBFcnJvcmAsIGUpKTtcbiAgICAgICAgdmlkZW9Qcm9taXNlLmNhdGNoKGUgPT4gY29uc29sZS53YXJuKGAke2NsaWVudElkfSBnZXRNZWRpYVN0cmVhbSBWaWRlbyBFcnJvcmAsIGUpKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChjbGllbnRJZClbdHlwZV0ucHJvbWlzZTtcbiAgICB9XG4gIH1cblxuICBzZXRNZWRpYVN0cmVhbShjbGllbnRJZCwgc3RyZWFtKSB7XG4gICAgLy8gU2FmYXJpIGRvZXNuJ3QgbGlrZSBpdCB3aGVuIHlvdSB1c2Ugc2luZ2xlIGEgbWl4ZWQgbWVkaWEgc3RyZWFtIHdoZXJlIG9uZSBvZiB0aGUgdHJhY2tzIGlzIGluYWN0aXZlLCBzbyB3ZVxuICAgIC8vIHNwbGl0IHRoZSB0cmFja3MgaW50byB0d28gc3RyZWFtcy5cbiAgICBjb25zdCBhdWRpb1N0cmVhbSA9IG5ldyBNZWRpYVN0cmVhbSgpO1xuICAgIHRyeSB7XG4gICAgc3RyZWFtLmdldEF1ZGlvVHJhY2tzKCkuZm9yRWFjaCh0cmFjayA9PiBhdWRpb1N0cmVhbS5hZGRUcmFjayh0cmFjaykpO1xuXG4gICAgfSBjYXRjaChlKSB7XG4gICAgICBjb25zb2xlLndhcm4oYCR7Y2xpZW50SWR9IHNldE1lZGlhU3RyZWFtIEF1ZGlvIEVycm9yYCwgZSk7XG4gICAgfVxuICAgIGNvbnN0IHZpZGVvU3RyZWFtID0gbmV3IE1lZGlhU3RyZWFtKCk7XG4gICAgdHJ5IHtcbiAgICBzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5mb3JFYWNoKHRyYWNrID0+IHZpZGVvU3RyZWFtLmFkZFRyYWNrKHRyYWNrKSk7XG5cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjb25zb2xlLndhcm4oYCR7Y2xpZW50SWR9IHNldE1lZGlhU3RyZWFtIFZpZGVvIEVycm9yYCwgZSk7XG4gICAgfVxuXG4gICAgdGhpcy5tZWRpYVN0cmVhbXNbY2xpZW50SWRdID0geyBhdWRpbzogYXVkaW9TdHJlYW0sIHZpZGVvOiB2aWRlb1N0cmVhbSB9O1xuXG4gICAgLy8gUmVzb2x2ZSB0aGUgcHJvbWlzZSBmb3IgdGhlIHVzZXIncyBtZWRpYSBzdHJlYW0gaWYgaXQgZXhpc3RzLlxuICAgIGlmICh0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmhhcyhjbGllbnRJZCkpIHtcbiAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KGNsaWVudElkKS5hdWRpby5yZXNvbHZlKGF1ZGlvU3RyZWFtKTtcbiAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KGNsaWVudElkKS52aWRlby5yZXNvbHZlKHZpZGVvU3RyZWFtKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBzZXRMb2NhbE1lZGlhU3RyZWFtKHN0cmVhbSkge1xuICAgIC8vIG91ciBqb2IgaGVyZSBpcyB0byBtYWtlIHN1cmUgdGhlIGNvbm5lY3Rpb24gd2luZHMgdXAgd2l0aCBSVFAgc2VuZGVycyBzZW5kaW5nIHRoZSBzdHVmZiBpbiB0aGlzIHN0cmVhbSxcbiAgICAvLyBhbmQgbm90IHRoZSBzdHVmZiB0aGF0IGlzbid0IGluIHRoaXMgc3RyZWFtLiBzdHJhdGVneSBpcyB0byByZXBsYWNlIGV4aXN0aW5nIHRyYWNrcyBpZiB3ZSBjYW4sIGFkZCB0cmFja3NcbiAgICAvLyB0aGF0IHdlIGNhbid0IHJlcGxhY2UsIGFuZCBkaXNhYmxlIHRyYWNrcyB0aGF0IGRvbid0IGV4aXN0IGFueW1vcmUuXG5cbiAgICAvLyBub3RlIHRoYXQgd2UgZG9uJ3QgZXZlciByZW1vdmUgYSB0cmFjayBmcm9tIHRoZSBzdHJlYW0gLS0gc2luY2UgSmFudXMgZG9lc24ndCBzdXBwb3J0IFVuaWZpZWQgUGxhbiwgd2UgYWJzb2x1dGVseVxuICAgIC8vIGNhbid0IHdpbmQgdXAgd2l0aCBhIFNEUCB0aGF0IGhhcyA+MSBhdWRpbyBvciA+MSB2aWRlbyB0cmFja3MsIGV2ZW4gaWYgb25lIG9mIHRoZW0gaXMgaW5hY3RpdmUgKHdoYXQgeW91IGdldCBpZlxuICAgIC8vIHlvdSByZW1vdmUgYSB0cmFjayBmcm9tIGFuIGV4aXN0aW5nIHN0cmVhbS4pXG4gICAgaWYgKHRoaXMucHVibGlzaGVyICYmIHRoaXMucHVibGlzaGVyLmNvbm4pIHtcbiAgICAgIGNvbnN0IGV4aXN0aW5nU2VuZGVycyA9IHRoaXMucHVibGlzaGVyLmNvbm4uZ2V0U2VuZGVycygpO1xuICAgICAgY29uc3QgbmV3U2VuZGVycyA9IFtdO1xuICAgICAgY29uc3QgdHJhY2tzID0gc3RyZWFtLmdldFRyYWNrcygpO1xuXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRyYWNrcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zdCB0ID0gdHJhY2tzW2ldO1xuICAgICAgICBjb25zdCBzZW5kZXIgPSBleGlzdGluZ1NlbmRlcnMuZmluZChzID0+IHMudHJhY2sgIT0gbnVsbCAmJiBzLnRyYWNrLmtpbmQgPT0gdC5raW5kKTtcblxuICAgICAgICBpZiAoc2VuZGVyICE9IG51bGwpIHtcbiAgICAgICAgICBpZiAoc2VuZGVyLnJlcGxhY2VUcmFjaykge1xuICAgICAgICAgICAgYXdhaXQgc2VuZGVyLnJlcGxhY2VUcmFjayh0KTtcblxuICAgICAgICAgICAgLy8gV29ya2Fyb3VuZCBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD0xNTc2NzcxXG4gICAgICAgICAgICBpZiAodC5raW5kID09PSBcInZpZGVvXCIgJiYgdC5lbmFibGVkICYmIG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5pbmRleE9mKCdmaXJlZm94JykgPiAtMSkge1xuICAgICAgICAgICAgICB0LmVuYWJsZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0LmVuYWJsZWQgPSB0cnVlLCAxMDAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gRmFsbGJhY2sgZm9yIGJyb3dzZXJzIHRoYXQgZG9uJ3Qgc3VwcG9ydCByZXBsYWNlVHJhY2suIEF0IHRoaXMgdGltZSBvZiB0aGlzIHdyaXRpbmdcbiAgICAgICAgICAgIC8vIG1vc3QgYnJvd3NlcnMgc3VwcG9ydCBpdCwgYW5kIHRlc3RpbmcgdGhpcyBjb2RlIHBhdGggc2VlbXMgdG8gbm90IHdvcmsgcHJvcGVybHlcbiAgICAgICAgICAgIC8vIGluIENocm9tZSBhbnltb3JlLlxuICAgICAgICAgICAgc3RyZWFtLnJlbW92ZVRyYWNrKHNlbmRlci50cmFjayk7XG4gICAgICAgICAgICBzdHJlYW0uYWRkVHJhY2sodCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIG5ld1NlbmRlcnMucHVzaChzZW5kZXIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG5ld1NlbmRlcnMucHVzaCh0aGlzLnB1Ymxpc2hlci5jb25uLmFkZFRyYWNrKHQsIHN0cmVhbSkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBleGlzdGluZ1NlbmRlcnMuZm9yRWFjaChzID0+IHtcbiAgICAgICAgaWYgKCFuZXdTZW5kZXJzLmluY2x1ZGVzKHMpKSB7XG4gICAgICAgICAgcy50cmFjay5lbmFibGVkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgICB0aGlzLmxvY2FsTWVkaWFTdHJlYW0gPSBzdHJlYW07XG4gICAgdGhpcy5zZXRNZWRpYVN0cmVhbSh0aGlzLmNsaWVudElkLCBzdHJlYW0pO1xuICB9XG5cbiAgZW5hYmxlTWljcm9waG9uZShlbmFibGVkKSB7XG4gICAgaWYgKHRoaXMucHVibGlzaGVyICYmIHRoaXMucHVibGlzaGVyLmNvbm4pIHtcbiAgICAgIHRoaXMucHVibGlzaGVyLmNvbm4uZ2V0U2VuZGVycygpLmZvckVhY2gocyA9PiB7XG4gICAgICAgIGlmIChzLnRyYWNrLmtpbmQgPT0gXCJhdWRpb1wiKSB7XG4gICAgICAgICAgcy50cmFjay5lbmFibGVkID0gZW5hYmxlZDtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgc2VuZERhdGEoY2xpZW50SWQsIGRhdGFUeXBlLCBkYXRhKSB7XG4gICAgaWYgKCF0aGlzLnB1Ymxpc2hlcikge1xuICAgICAgY29uc29sZS53YXJuKFwic2VuZERhdGEgY2FsbGVkIHdpdGhvdXQgYSBwdWJsaXNoZXJcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXRjaCAodGhpcy51bnJlbGlhYmxlVHJhbnNwb3J0KSB7XG4gICAgICAgIGNhc2UgXCJ3ZWJzb2NrZXRcIjpcbiAgICAgICAgICB0aGlzLnB1Ymxpc2hlci5oYW5kbGUuc2VuZE1lc3NhZ2UoeyBraW5kOiBcImRhdGFcIiwgYm9keTogSlNPTi5zdHJpbmdpZnkoeyBkYXRhVHlwZSwgZGF0YSB9KSwgd2hvbTogY2xpZW50SWQgfSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJkYXRhY2hhbm5lbFwiOlxuICAgICAgICAgIHRoaXMucHVibGlzaGVyLnVucmVsaWFibGVDaGFubmVsLnNlbmQoSlNPTi5zdHJpbmdpZnkoeyBjbGllbnRJZCwgZGF0YVR5cGUsIGRhdGEgfSkpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRoaXMudW5yZWxpYWJsZVRyYW5zcG9ydChjbGllbnRJZCwgZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHNlbmREYXRhR3VhcmFudGVlZChjbGllbnRJZCwgZGF0YVR5cGUsIGRhdGEpIHtcbiAgICBpZiAoIXRoaXMucHVibGlzaGVyKSB7XG4gICAgICBjb25zb2xlLndhcm4oXCJzZW5kRGF0YUd1YXJhbnRlZWQgY2FsbGVkIHdpdGhvdXQgYSBwdWJsaXNoZXJcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXRjaCAodGhpcy5yZWxpYWJsZVRyYW5zcG9ydCkge1xuICAgICAgICBjYXNlIFwid2Vic29ja2V0XCI6XG4gICAgICAgICAgdGhpcy5wdWJsaXNoZXIuaGFuZGxlLnNlbmRNZXNzYWdlKHsga2luZDogXCJkYXRhXCIsIGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgZGF0YVR5cGUsIGRhdGEgfSksIHdob206IGNsaWVudElkIH0pO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiZGF0YWNoYW5uZWxcIjpcbiAgICAgICAgICB0aGlzLnB1Ymxpc2hlci5yZWxpYWJsZUNoYW5uZWwuc2VuZChKU09OLnN0cmluZ2lmeSh7IGNsaWVudElkLCBkYXRhVHlwZSwgZGF0YSB9KSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy5yZWxpYWJsZVRyYW5zcG9ydChjbGllbnRJZCwgZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGJyb2FkY2FzdERhdGEoZGF0YVR5cGUsIGRhdGEpIHtcbiAgICBpZiAoIXRoaXMucHVibGlzaGVyKSB7XG4gICAgICBjb25zb2xlLndhcm4oXCJicm9hZGNhc3REYXRhIGNhbGxlZCB3aXRob3V0IGEgcHVibGlzaGVyXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzd2l0Y2ggKHRoaXMudW5yZWxpYWJsZVRyYW5zcG9ydCkge1xuICAgICAgICBjYXNlIFwid2Vic29ja2V0XCI6XG4gICAgICAgICAgdGhpcy5wdWJsaXNoZXIuaGFuZGxlLnNlbmRNZXNzYWdlKHsga2luZDogXCJkYXRhXCIsIGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgZGF0YVR5cGUsIGRhdGEgfSkgfSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJkYXRhY2hhbm5lbFwiOlxuICAgICAgICAgIHRoaXMucHVibGlzaGVyLnVucmVsaWFibGVDaGFubmVsLnNlbmQoSlNPTi5zdHJpbmdpZnkoeyBkYXRhVHlwZSwgZGF0YSB9KSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy51bnJlbGlhYmxlVHJhbnNwb3J0KHVuZGVmaW5lZCwgZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGJyb2FkY2FzdERhdGFHdWFyYW50ZWVkKGRhdGFUeXBlLCBkYXRhKSB7XG4gICAgaWYgKCF0aGlzLnB1Ymxpc2hlcikge1xuICAgICAgY29uc29sZS53YXJuKFwiYnJvYWRjYXN0RGF0YUd1YXJhbnRlZWQgY2FsbGVkIHdpdGhvdXQgYSBwdWJsaXNoZXJcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXRjaCAodGhpcy5yZWxpYWJsZVRyYW5zcG9ydCkge1xuICAgICAgICBjYXNlIFwid2Vic29ja2V0XCI6XG4gICAgICAgICAgdGhpcy5wdWJsaXNoZXIuaGFuZGxlLnNlbmRNZXNzYWdlKHsga2luZDogXCJkYXRhXCIsIGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgZGF0YVR5cGUsIGRhdGEgfSkgfSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJkYXRhY2hhbm5lbFwiOlxuICAgICAgICAgIHRoaXMucHVibGlzaGVyLnJlbGlhYmxlQ2hhbm5lbC5zZW5kKEpTT04uc3RyaW5naWZ5KHsgZGF0YVR5cGUsIGRhdGEgfSkpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRoaXMucmVsaWFibGVUcmFuc3BvcnQodW5kZWZpbmVkLCBkYXRhVHlwZSwgZGF0YSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAga2ljayhjbGllbnRJZCwgcGVybXNUb2tlbikge1xuICAgIHJldHVybiB0aGlzLnB1Ymxpc2hlci5oYW5kbGUuc2VuZE1lc3NhZ2UoeyBraW5kOiBcImtpY2tcIiwgcm9vbV9pZDogdGhpcy5yb29tLCB1c2VyX2lkOiBjbGllbnRJZCwgdG9rZW46IHBlcm1zVG9rZW4gfSkudGhlbigoKSA9PiB7XG4gICAgICBkb2N1bWVudC5ib2R5LmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KFwia2lja2VkXCIsIHsgZGV0YWlsOiB7IGNsaWVudElkOiBjbGllbnRJZCB9IH0pKTtcbiAgICB9KTtcbiAgfVxuXG4gIGJsb2NrKGNsaWVudElkKSB7XG4gICAgcmV0dXJuIHRoaXMucHVibGlzaGVyLmhhbmRsZS5zZW5kTWVzc2FnZSh7IGtpbmQ6IFwiYmxvY2tcIiwgd2hvbTogY2xpZW50SWQgfSkudGhlbigoKSA9PiB7XG4gICAgICB0aGlzLmJsb2NrZWRDbGllbnRzLnNldChjbGllbnRJZCwgdHJ1ZSk7XG4gICAgICBkb2N1bWVudC5ib2R5LmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KFwiYmxvY2tlZFwiLCB7IGRldGFpbDogeyBjbGllbnRJZDogY2xpZW50SWQgfSB9KSk7XG4gICAgfSk7XG4gIH1cblxuICB1bmJsb2NrKGNsaWVudElkKSB7XG4gICAgcmV0dXJuIHRoaXMucHVibGlzaGVyLmhhbmRsZS5zZW5kTWVzc2FnZSh7IGtpbmQ6IFwidW5ibG9ja1wiLCB3aG9tOiBjbGllbnRJZCB9KS50aGVuKCgpID0+IHtcbiAgICAgIHRoaXMuYmxvY2tlZENsaWVudHMuZGVsZXRlKGNsaWVudElkKTtcbiAgICAgIGRvY3VtZW50LmJvZHkuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoXCJ1bmJsb2NrZWRcIiwgeyBkZXRhaWw6IHsgY2xpZW50SWQ6IGNsaWVudElkIH0gfSkpO1xuICAgIH0pO1xuICB9XG59XG5cbk5BRi5hZGFwdGVycy5yZWdpc3RlcihcImphbnVzXCIsIEphbnVzQWRhcHRlcik7XG5cbm1vZHVsZS5leHBvcnRzID0gSmFudXNBZGFwdGVyO1xuIiwiLyogZXNsaW50LWVudiBicm93c2VyICovXG5cbi8qKlxuICogVGhpcyBpcyB0aGUgd2ViIGJyb3dzZXIgaW1wbGVtZW50YXRpb24gb2YgYGRlYnVnKClgLlxuICovXG5cbmV4cG9ydHMuZm9ybWF0QXJncyA9IGZvcm1hdEFyZ3M7XG5leHBvcnRzLnNhdmUgPSBzYXZlO1xuZXhwb3J0cy5sb2FkID0gbG9hZDtcbmV4cG9ydHMudXNlQ29sb3JzID0gdXNlQ29sb3JzO1xuZXhwb3J0cy5zdG9yYWdlID0gbG9jYWxzdG9yYWdlKCk7XG5leHBvcnRzLmRlc3Ryb3kgPSAoKCkgPT4ge1xuXHRsZXQgd2FybmVkID0gZmFsc2U7XG5cblx0cmV0dXJuICgpID0+IHtcblx0XHRpZiAoIXdhcm5lZCkge1xuXHRcdFx0d2FybmVkID0gdHJ1ZTtcblx0XHRcdGNvbnNvbGUud2FybignSW5zdGFuY2UgbWV0aG9kIGBkZWJ1Zy5kZXN0cm95KClgIGlzIGRlcHJlY2F0ZWQgYW5kIG5vIGxvbmdlciBkb2VzIGFueXRoaW5nLiBJdCB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5leHQgbWFqb3IgdmVyc2lvbiBvZiBgZGVidWdgLicpO1xuXHRcdH1cblx0fTtcbn0pKCk7XG5cbi8qKlxuICogQ29sb3JzLlxuICovXG5cbmV4cG9ydHMuY29sb3JzID0gW1xuXHQnIzAwMDBDQycsXG5cdCcjMDAwMEZGJyxcblx0JyMwMDMzQ0MnLFxuXHQnIzAwMzNGRicsXG5cdCcjMDA2NkNDJyxcblx0JyMwMDY2RkYnLFxuXHQnIzAwOTlDQycsXG5cdCcjMDA5OUZGJyxcblx0JyMwMENDMDAnLFxuXHQnIzAwQ0MzMycsXG5cdCcjMDBDQzY2Jyxcblx0JyMwMENDOTknLFxuXHQnIzAwQ0NDQycsXG5cdCcjMDBDQ0ZGJyxcblx0JyMzMzAwQ0MnLFxuXHQnIzMzMDBGRicsXG5cdCcjMzMzM0NDJyxcblx0JyMzMzMzRkYnLFxuXHQnIzMzNjZDQycsXG5cdCcjMzM2NkZGJyxcblx0JyMzMzk5Q0MnLFxuXHQnIzMzOTlGRicsXG5cdCcjMzNDQzAwJyxcblx0JyMzM0NDMzMnLFxuXHQnIzMzQ0M2NicsXG5cdCcjMzNDQzk5Jyxcblx0JyMzM0NDQ0MnLFxuXHQnIzMzQ0NGRicsXG5cdCcjNjYwMENDJyxcblx0JyM2NjAwRkYnLFxuXHQnIzY2MzNDQycsXG5cdCcjNjYzM0ZGJyxcblx0JyM2NkNDMDAnLFxuXHQnIzY2Q0MzMycsXG5cdCcjOTkwMENDJyxcblx0JyM5OTAwRkYnLFxuXHQnIzk5MzNDQycsXG5cdCcjOTkzM0ZGJyxcblx0JyM5OUNDMDAnLFxuXHQnIzk5Q0MzMycsXG5cdCcjQ0MwMDAwJyxcblx0JyNDQzAwMzMnLFxuXHQnI0NDMDA2NicsXG5cdCcjQ0MwMDk5Jyxcblx0JyNDQzAwQ0MnLFxuXHQnI0NDMDBGRicsXG5cdCcjQ0MzMzAwJyxcblx0JyNDQzMzMzMnLFxuXHQnI0NDMzM2NicsXG5cdCcjQ0MzMzk5Jyxcblx0JyNDQzMzQ0MnLFxuXHQnI0NDMzNGRicsXG5cdCcjQ0M2NjAwJyxcblx0JyNDQzY2MzMnLFxuXHQnI0NDOTkwMCcsXG5cdCcjQ0M5OTMzJyxcblx0JyNDQ0NDMDAnLFxuXHQnI0NDQ0MzMycsXG5cdCcjRkYwMDAwJyxcblx0JyNGRjAwMzMnLFxuXHQnI0ZGMDA2NicsXG5cdCcjRkYwMDk5Jyxcblx0JyNGRjAwQ0MnLFxuXHQnI0ZGMDBGRicsXG5cdCcjRkYzMzAwJyxcblx0JyNGRjMzMzMnLFxuXHQnI0ZGMzM2NicsXG5cdCcjRkYzMzk5Jyxcblx0JyNGRjMzQ0MnLFxuXHQnI0ZGMzNGRicsXG5cdCcjRkY2NjAwJyxcblx0JyNGRjY2MzMnLFxuXHQnI0ZGOTkwMCcsXG5cdCcjRkY5OTMzJyxcblx0JyNGRkNDMDAnLFxuXHQnI0ZGQ0MzMydcbl07XG5cbi8qKlxuICogQ3VycmVudGx5IG9ubHkgV2ViS2l0LWJhc2VkIFdlYiBJbnNwZWN0b3JzLCBGaXJlZm94ID49IHYzMSxcbiAqIGFuZCB0aGUgRmlyZWJ1ZyBleHRlbnNpb24gKGFueSBGaXJlZm94IHZlcnNpb24pIGFyZSBrbm93blxuICogdG8gc3VwcG9ydCBcIiVjXCIgQ1NTIGN1c3RvbWl6YXRpb25zLlxuICpcbiAqIFRPRE86IGFkZCBhIGBsb2NhbFN0b3JhZ2VgIHZhcmlhYmxlIHRvIGV4cGxpY2l0bHkgZW5hYmxlL2Rpc2FibGUgY29sb3JzXG4gKi9cblxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbmZ1bmN0aW9uIHVzZUNvbG9ycygpIHtcblx0Ly8gTkI6IEluIGFuIEVsZWN0cm9uIHByZWxvYWQgc2NyaXB0LCBkb2N1bWVudCB3aWxsIGJlIGRlZmluZWQgYnV0IG5vdCBmdWxseVxuXHQvLyBpbml0aWFsaXplZC4gU2luY2Ugd2Uga25vdyB3ZSdyZSBpbiBDaHJvbWUsIHdlJ2xsIGp1c3QgZGV0ZWN0IHRoaXMgY2FzZVxuXHQvLyBleHBsaWNpdGx5XG5cdGlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiB3aW5kb3cucHJvY2VzcyAmJiAod2luZG93LnByb2Nlc3MudHlwZSA9PT0gJ3JlbmRlcmVyJyB8fCB3aW5kb3cucHJvY2Vzcy5fX253anMpKSB7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH1cblxuXHQvLyBJbnRlcm5ldCBFeHBsb3JlciBhbmQgRWRnZSBkbyBub3Qgc3VwcG9ydCBjb2xvcnMuXG5cdGlmICh0eXBlb2YgbmF2aWdhdG9yICE9PSAndW5kZWZpbmVkJyAmJiBuYXZpZ2F0b3IudXNlckFnZW50ICYmIG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5tYXRjaCgvKGVkZ2V8dHJpZGVudClcXC8oXFxkKykvKSkge1xuXHRcdHJldHVybiBmYWxzZTtcblx0fVxuXG5cdC8vIElzIHdlYmtpdD8gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMTY0NTk2MDYvMzc2NzczXG5cdC8vIGRvY3VtZW50IGlzIHVuZGVmaW5lZCBpbiByZWFjdC1uYXRpdmU6IGh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9vay9yZWFjdC1uYXRpdmUvcHVsbC8xNjMyXG5cdHJldHVybiAodHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQgJiYgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlICYmIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZS5XZWJraXRBcHBlYXJhbmNlKSB8fFxuXHRcdC8vIElzIGZpcmVidWc/IGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzM5ODEyMC8zNzY3NzNcblx0XHQodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LmNvbnNvbGUgJiYgKHdpbmRvdy5jb25zb2xlLmZpcmVidWcgfHwgKHdpbmRvdy5jb25zb2xlLmV4Y2VwdGlvbiAmJiB3aW5kb3cuY29uc29sZS50YWJsZSkpKSB8fFxuXHRcdC8vIElzIGZpcmVmb3ggPj0gdjMxP1xuXHRcdC8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvVG9vbHMvV2ViX0NvbnNvbGUjU3R5bGluZ19tZXNzYWdlc1xuXHRcdCh0eXBlb2YgbmF2aWdhdG9yICE9PSAndW5kZWZpbmVkJyAmJiBuYXZpZ2F0b3IudXNlckFnZW50ICYmIG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5tYXRjaCgvZmlyZWZveFxcLyhcXGQrKS8pICYmIHBhcnNlSW50KFJlZ0V4cC4kMSwgMTApID49IDMxKSB8fFxuXHRcdC8vIERvdWJsZSBjaGVjayB3ZWJraXQgaW4gdXNlckFnZW50IGp1c3QgaW4gY2FzZSB3ZSBhcmUgaW4gYSB3b3JrZXJcblx0XHQodHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudCAmJiBuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCkubWF0Y2goL2FwcGxld2Via2l0XFwvKFxcZCspLykpO1xufVxuXG4vKipcbiAqIENvbG9yaXplIGxvZyBhcmd1bWVudHMgaWYgZW5hYmxlZC5cbiAqXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbmZ1bmN0aW9uIGZvcm1hdEFyZ3MoYXJncykge1xuXHRhcmdzWzBdID0gKHRoaXMudXNlQ29sb3JzID8gJyVjJyA6ICcnKSArXG5cdFx0dGhpcy5uYW1lc3BhY2UgK1xuXHRcdCh0aGlzLnVzZUNvbG9ycyA/ICcgJWMnIDogJyAnKSArXG5cdFx0YXJnc1swXSArXG5cdFx0KHRoaXMudXNlQ29sb3JzID8gJyVjICcgOiAnICcpICtcblx0XHQnKycgKyBtb2R1bGUuZXhwb3J0cy5odW1hbml6ZSh0aGlzLmRpZmYpO1xuXG5cdGlmICghdGhpcy51c2VDb2xvcnMpIHtcblx0XHRyZXR1cm47XG5cdH1cblxuXHRjb25zdCBjID0gJ2NvbG9yOiAnICsgdGhpcy5jb2xvcjtcblx0YXJncy5zcGxpY2UoMSwgMCwgYywgJ2NvbG9yOiBpbmhlcml0Jyk7XG5cblx0Ly8gVGhlIGZpbmFsIFwiJWNcIiBpcyBzb21ld2hhdCB0cmlja3ksIGJlY2F1c2UgdGhlcmUgY291bGQgYmUgb3RoZXJcblx0Ly8gYXJndW1lbnRzIHBhc3NlZCBlaXRoZXIgYmVmb3JlIG9yIGFmdGVyIHRoZSAlYywgc28gd2UgbmVlZCB0b1xuXHQvLyBmaWd1cmUgb3V0IHRoZSBjb3JyZWN0IGluZGV4IHRvIGluc2VydCB0aGUgQ1NTIGludG9cblx0bGV0IGluZGV4ID0gMDtcblx0bGV0IGxhc3RDID0gMDtcblx0YXJnc1swXS5yZXBsYWNlKC8lW2EtekEtWiVdL2csIG1hdGNoID0+IHtcblx0XHRpZiAobWF0Y2ggPT09ICclJScpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aW5kZXgrKztcblx0XHRpZiAobWF0Y2ggPT09ICclYycpIHtcblx0XHRcdC8vIFdlIG9ubHkgYXJlIGludGVyZXN0ZWQgaW4gdGhlICpsYXN0KiAlY1xuXHRcdFx0Ly8gKHRoZSB1c2VyIG1heSBoYXZlIHByb3ZpZGVkIHRoZWlyIG93bilcblx0XHRcdGxhc3RDID0gaW5kZXg7XG5cdFx0fVxuXHR9KTtcblxuXHRhcmdzLnNwbGljZShsYXN0QywgMCwgYyk7XG59XG5cbi8qKlxuICogSW52b2tlcyBgY29uc29sZS5kZWJ1ZygpYCB3aGVuIGF2YWlsYWJsZS5cbiAqIE5vLW9wIHdoZW4gYGNvbnNvbGUuZGVidWdgIGlzIG5vdCBhIFwiZnVuY3Rpb25cIi5cbiAqIElmIGBjb25zb2xlLmRlYnVnYCBpcyBub3QgYXZhaWxhYmxlLCBmYWxscyBiYWNrXG4gKiB0byBgY29uc29sZS5sb2dgLlxuICpcbiAqIEBhcGkgcHVibGljXG4gKi9cbmV4cG9ydHMubG9nID0gY29uc29sZS5kZWJ1ZyB8fCBjb25zb2xlLmxvZyB8fCAoKCkgPT4ge30pO1xuXG4vKipcbiAqIFNhdmUgYG5hbWVzcGFjZXNgLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lc3BhY2VzXG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gc2F2ZShuYW1lc3BhY2VzKSB7XG5cdHRyeSB7XG5cdFx0aWYgKG5hbWVzcGFjZXMpIHtcblx0XHRcdGV4cG9ydHMuc3RvcmFnZS5zZXRJdGVtKCdkZWJ1ZycsIG5hbWVzcGFjZXMpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRleHBvcnRzLnN0b3JhZ2UucmVtb3ZlSXRlbSgnZGVidWcnKTtcblx0XHR9XG5cdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0Ly8gU3dhbGxvd1xuXHRcdC8vIFhYWCAoQFFpeC0pIHNob3VsZCB3ZSBiZSBsb2dnaW5nIHRoZXNlP1xuXHR9XG59XG5cbi8qKlxuICogTG9hZCBgbmFtZXNwYWNlc2AuXG4gKlxuICogQHJldHVybiB7U3RyaW5nfSByZXR1cm5zIHRoZSBwcmV2aW91c2x5IHBlcnNpc3RlZCBkZWJ1ZyBtb2Rlc1xuICogQGFwaSBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGxvYWQoKSB7XG5cdGxldCByO1xuXHR0cnkge1xuXHRcdHIgPSBleHBvcnRzLnN0b3JhZ2UuZ2V0SXRlbSgnZGVidWcnKTtcblx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHQvLyBTd2FsbG93XG5cdFx0Ly8gWFhYIChAUWl4LSkgc2hvdWxkIHdlIGJlIGxvZ2dpbmcgdGhlc2U/XG5cdH1cblxuXHQvLyBJZiBkZWJ1ZyBpc24ndCBzZXQgaW4gTFMsIGFuZCB3ZSdyZSBpbiBFbGVjdHJvbiwgdHJ5IHRvIGxvYWQgJERFQlVHXG5cdGlmICghciAmJiB0eXBlb2YgcHJvY2VzcyAhPT0gJ3VuZGVmaW5lZCcgJiYgJ2VudicgaW4gcHJvY2Vzcykge1xuXHRcdHIgPSBwcm9jZXNzLmVudi5ERUJVRztcblx0fVxuXG5cdHJldHVybiByO1xufVxuXG4vKipcbiAqIExvY2Fsc3RvcmFnZSBhdHRlbXB0cyB0byByZXR1cm4gdGhlIGxvY2Fsc3RvcmFnZS5cbiAqXG4gKiBUaGlzIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIHNhZmFyaSB0aHJvd3NcbiAqIHdoZW4gYSB1c2VyIGRpc2FibGVzIGNvb2tpZXMvbG9jYWxzdG9yYWdlXG4gKiBhbmQgeW91IGF0dGVtcHQgdG8gYWNjZXNzIGl0LlxuICpcbiAqIEByZXR1cm4ge0xvY2FsU3RvcmFnZX1cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIGxvY2Fsc3RvcmFnZSgpIHtcblx0dHJ5IHtcblx0XHQvLyBUVk1MS2l0IChBcHBsZSBUViBKUyBSdW50aW1lKSBkb2VzIG5vdCBoYXZlIGEgd2luZG93IG9iamVjdCwganVzdCBsb2NhbFN0b3JhZ2UgaW4gdGhlIGdsb2JhbCBjb250ZXh0XG5cdFx0Ly8gVGhlIEJyb3dzZXIgYWxzbyBoYXMgbG9jYWxTdG9yYWdlIGluIHRoZSBnbG9iYWwgY29udGV4dC5cblx0XHRyZXR1cm4gbG9jYWxTdG9yYWdlO1xuXHR9IGNhdGNoIChlcnJvcikge1xuXHRcdC8vIFN3YWxsb3dcblx0XHQvLyBYWFggKEBRaXgtKSBzaG91bGQgd2UgYmUgbG9nZ2luZyB0aGVzZT9cblx0fVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoJy4vY29tbW9uJykoZXhwb3J0cyk7XG5cbmNvbnN0IHtmb3JtYXR0ZXJzfSA9IG1vZHVsZS5leHBvcnRzO1xuXG4vKipcbiAqIE1hcCAlaiB0byBgSlNPTi5zdHJpbmdpZnkoKWAsIHNpbmNlIG5vIFdlYiBJbnNwZWN0b3JzIGRvIHRoYXQgYnkgZGVmYXVsdC5cbiAqL1xuXG5mb3JtYXR0ZXJzLmogPSBmdW5jdGlvbiAodikge1xuXHR0cnkge1xuXHRcdHJldHVybiBKU09OLnN0cmluZ2lmeSh2KTtcblx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHRyZXR1cm4gJ1tVbmV4cGVjdGVkSlNPTlBhcnNlRXJyb3JdOiAnICsgZXJyb3IubWVzc2FnZTtcblx0fVxufTtcbiIsIlxuLyoqXG4gKiBUaGlzIGlzIHRoZSBjb21tb24gbG9naWMgZm9yIGJvdGggdGhlIE5vZGUuanMgYW5kIHdlYiBicm93c2VyXG4gKiBpbXBsZW1lbnRhdGlvbnMgb2YgYGRlYnVnKClgLlxuICovXG5cbmZ1bmN0aW9uIHNldHVwKGVudikge1xuXHRjcmVhdGVEZWJ1Zy5kZWJ1ZyA9IGNyZWF0ZURlYnVnO1xuXHRjcmVhdGVEZWJ1Zy5kZWZhdWx0ID0gY3JlYXRlRGVidWc7XG5cdGNyZWF0ZURlYnVnLmNvZXJjZSA9IGNvZXJjZTtcblx0Y3JlYXRlRGVidWcuZGlzYWJsZSA9IGRpc2FibGU7XG5cdGNyZWF0ZURlYnVnLmVuYWJsZSA9IGVuYWJsZTtcblx0Y3JlYXRlRGVidWcuZW5hYmxlZCA9IGVuYWJsZWQ7XG5cdGNyZWF0ZURlYnVnLmh1bWFuaXplID0gcmVxdWlyZSgnbXMnKTtcblx0Y3JlYXRlRGVidWcuZGVzdHJveSA9IGRlc3Ryb3k7XG5cblx0T2JqZWN0LmtleXMoZW52KS5mb3JFYWNoKGtleSA9PiB7XG5cdFx0Y3JlYXRlRGVidWdba2V5XSA9IGVudltrZXldO1xuXHR9KTtcblxuXHQvKipcblx0KiBUaGUgY3VycmVudGx5IGFjdGl2ZSBkZWJ1ZyBtb2RlIG5hbWVzLCBhbmQgbmFtZXMgdG8gc2tpcC5cblx0Ki9cblxuXHRjcmVhdGVEZWJ1Zy5uYW1lcyA9IFtdO1xuXHRjcmVhdGVEZWJ1Zy5za2lwcyA9IFtdO1xuXG5cdC8qKlxuXHQqIE1hcCBvZiBzcGVjaWFsIFwiJW5cIiBoYW5kbGluZyBmdW5jdGlvbnMsIGZvciB0aGUgZGVidWcgXCJmb3JtYXRcIiBhcmd1bWVudC5cblx0KlxuXHQqIFZhbGlkIGtleSBuYW1lcyBhcmUgYSBzaW5nbGUsIGxvd2VyIG9yIHVwcGVyLWNhc2UgbGV0dGVyLCBpLmUuIFwiblwiIGFuZCBcIk5cIi5cblx0Ki9cblx0Y3JlYXRlRGVidWcuZm9ybWF0dGVycyA9IHt9O1xuXG5cdC8qKlxuXHQqIFNlbGVjdHMgYSBjb2xvciBmb3IgYSBkZWJ1ZyBuYW1lc3BhY2Vcblx0KiBAcGFyYW0ge1N0cmluZ30gbmFtZXNwYWNlIFRoZSBuYW1lc3BhY2Ugc3RyaW5nIGZvciB0aGUgZGVidWcgaW5zdGFuY2UgdG8gYmUgY29sb3JlZFxuXHQqIEByZXR1cm4ge051bWJlcnxTdHJpbmd9IEFuIEFOU0kgY29sb3IgY29kZSBmb3IgdGhlIGdpdmVuIG5hbWVzcGFjZVxuXHQqIEBhcGkgcHJpdmF0ZVxuXHQqL1xuXHRmdW5jdGlvbiBzZWxlY3RDb2xvcihuYW1lc3BhY2UpIHtcblx0XHRsZXQgaGFzaCA9IDA7XG5cblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IG5hbWVzcGFjZS5sZW5ndGg7IGkrKykge1xuXHRcdFx0aGFzaCA9ICgoaGFzaCA8PCA1KSAtIGhhc2gpICsgbmFtZXNwYWNlLmNoYXJDb2RlQXQoaSk7XG5cdFx0XHRoYXNoIHw9IDA7IC8vIENvbnZlcnQgdG8gMzJiaXQgaW50ZWdlclxuXHRcdH1cblxuXHRcdHJldHVybiBjcmVhdGVEZWJ1Zy5jb2xvcnNbTWF0aC5hYnMoaGFzaCkgJSBjcmVhdGVEZWJ1Zy5jb2xvcnMubGVuZ3RoXTtcblx0fVxuXHRjcmVhdGVEZWJ1Zy5zZWxlY3RDb2xvciA9IHNlbGVjdENvbG9yO1xuXG5cdC8qKlxuXHQqIENyZWF0ZSBhIGRlYnVnZ2VyIHdpdGggdGhlIGdpdmVuIGBuYW1lc3BhY2VgLlxuXHQqXG5cdCogQHBhcmFtIHtTdHJpbmd9IG5hbWVzcGFjZVxuXHQqIEByZXR1cm4ge0Z1bmN0aW9ufVxuXHQqIEBhcGkgcHVibGljXG5cdCovXG5cdGZ1bmN0aW9uIGNyZWF0ZURlYnVnKG5hbWVzcGFjZSkge1xuXHRcdGxldCBwcmV2VGltZTtcblx0XHRsZXQgZW5hYmxlT3ZlcnJpZGUgPSBudWxsO1xuXHRcdGxldCBuYW1lc3BhY2VzQ2FjaGU7XG5cdFx0bGV0IGVuYWJsZWRDYWNoZTtcblxuXHRcdGZ1bmN0aW9uIGRlYnVnKC4uLmFyZ3MpIHtcblx0XHRcdC8vIERpc2FibGVkP1xuXHRcdFx0aWYgKCFkZWJ1Zy5lbmFibGVkKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0Y29uc3Qgc2VsZiA9IGRlYnVnO1xuXG5cdFx0XHQvLyBTZXQgYGRpZmZgIHRpbWVzdGFtcFxuXHRcdFx0Y29uc3QgY3VyciA9IE51bWJlcihuZXcgRGF0ZSgpKTtcblx0XHRcdGNvbnN0IG1zID0gY3VyciAtIChwcmV2VGltZSB8fCBjdXJyKTtcblx0XHRcdHNlbGYuZGlmZiA9IG1zO1xuXHRcdFx0c2VsZi5wcmV2ID0gcHJldlRpbWU7XG5cdFx0XHRzZWxmLmN1cnIgPSBjdXJyO1xuXHRcdFx0cHJldlRpbWUgPSBjdXJyO1xuXG5cdFx0XHRhcmdzWzBdID0gY3JlYXRlRGVidWcuY29lcmNlKGFyZ3NbMF0pO1xuXG5cdFx0XHRpZiAodHlwZW9mIGFyZ3NbMF0gIT09ICdzdHJpbmcnKSB7XG5cdFx0XHRcdC8vIEFueXRoaW5nIGVsc2UgbGV0J3MgaW5zcGVjdCB3aXRoICVPXG5cdFx0XHRcdGFyZ3MudW5zaGlmdCgnJU8nKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQXBwbHkgYW55IGBmb3JtYXR0ZXJzYCB0cmFuc2Zvcm1hdGlvbnNcblx0XHRcdGxldCBpbmRleCA9IDA7XG5cdFx0XHRhcmdzWzBdID0gYXJnc1swXS5yZXBsYWNlKC8lKFthLXpBLVolXSkvZywgKG1hdGNoLCBmb3JtYXQpID0+IHtcblx0XHRcdFx0Ly8gSWYgd2UgZW5jb3VudGVyIGFuIGVzY2FwZWQgJSB0aGVuIGRvbid0IGluY3JlYXNlIHRoZSBhcnJheSBpbmRleFxuXHRcdFx0XHRpZiAobWF0Y2ggPT09ICclJScpIHtcblx0XHRcdFx0XHRyZXR1cm4gJyUnO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGluZGV4Kys7XG5cdFx0XHRcdGNvbnN0IGZvcm1hdHRlciA9IGNyZWF0ZURlYnVnLmZvcm1hdHRlcnNbZm9ybWF0XTtcblx0XHRcdFx0aWYgKHR5cGVvZiBmb3JtYXR0ZXIgPT09ICdmdW5jdGlvbicpIHtcblx0XHRcdFx0XHRjb25zdCB2YWwgPSBhcmdzW2luZGV4XTtcblx0XHRcdFx0XHRtYXRjaCA9IGZvcm1hdHRlci5jYWxsKHNlbGYsIHZhbCk7XG5cblx0XHRcdFx0XHQvLyBOb3cgd2UgbmVlZCB0byByZW1vdmUgYGFyZ3NbaW5kZXhdYCBzaW5jZSBpdCdzIGlubGluZWQgaW4gdGhlIGBmb3JtYXRgXG5cdFx0XHRcdFx0YXJncy5zcGxpY2UoaW5kZXgsIDEpO1xuXHRcdFx0XHRcdGluZGV4LS07XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIG1hdGNoO1xuXHRcdFx0fSk7XG5cblx0XHRcdC8vIEFwcGx5IGVudi1zcGVjaWZpYyBmb3JtYXR0aW5nIChjb2xvcnMsIGV0Yy4pXG5cdFx0XHRjcmVhdGVEZWJ1Zy5mb3JtYXRBcmdzLmNhbGwoc2VsZiwgYXJncyk7XG5cblx0XHRcdGNvbnN0IGxvZ0ZuID0gc2VsZi5sb2cgfHwgY3JlYXRlRGVidWcubG9nO1xuXHRcdFx0bG9nRm4uYXBwbHkoc2VsZiwgYXJncyk7XG5cdFx0fVxuXG5cdFx0ZGVidWcubmFtZXNwYWNlID0gbmFtZXNwYWNlO1xuXHRcdGRlYnVnLnVzZUNvbG9ycyA9IGNyZWF0ZURlYnVnLnVzZUNvbG9ycygpO1xuXHRcdGRlYnVnLmNvbG9yID0gY3JlYXRlRGVidWcuc2VsZWN0Q29sb3IobmFtZXNwYWNlKTtcblx0XHRkZWJ1Zy5leHRlbmQgPSBleHRlbmQ7XG5cdFx0ZGVidWcuZGVzdHJveSA9IGNyZWF0ZURlYnVnLmRlc3Ryb3k7IC8vIFhYWCBUZW1wb3JhcnkuIFdpbGwgYmUgcmVtb3ZlZCBpbiB0aGUgbmV4dCBtYWpvciByZWxlYXNlLlxuXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGRlYnVnLCAnZW5hYmxlZCcsIHtcblx0XHRcdGVudW1lcmFibGU6IHRydWUsXG5cdFx0XHRjb25maWd1cmFibGU6IGZhbHNlLFxuXHRcdFx0Z2V0OiAoKSA9PiB7XG5cdFx0XHRcdGlmIChlbmFibGVPdmVycmlkZSAhPT0gbnVsbCkge1xuXHRcdFx0XHRcdHJldHVybiBlbmFibGVPdmVycmlkZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAobmFtZXNwYWNlc0NhY2hlICE9PSBjcmVhdGVEZWJ1Zy5uYW1lc3BhY2VzKSB7XG5cdFx0XHRcdFx0bmFtZXNwYWNlc0NhY2hlID0gY3JlYXRlRGVidWcubmFtZXNwYWNlcztcblx0XHRcdFx0XHRlbmFibGVkQ2FjaGUgPSBjcmVhdGVEZWJ1Zy5lbmFibGVkKG5hbWVzcGFjZSk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gZW5hYmxlZENhY2hlO1xuXHRcdFx0fSxcblx0XHRcdHNldDogdiA9PiB7XG5cdFx0XHRcdGVuYWJsZU92ZXJyaWRlID0gdjtcblx0XHRcdH1cblx0XHR9KTtcblxuXHRcdC8vIEVudi1zcGVjaWZpYyBpbml0aWFsaXphdGlvbiBsb2dpYyBmb3IgZGVidWcgaW5zdGFuY2VzXG5cdFx0aWYgKHR5cGVvZiBjcmVhdGVEZWJ1Zy5pbml0ID09PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRjcmVhdGVEZWJ1Zy5pbml0KGRlYnVnKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZGVidWc7XG5cdH1cblxuXHRmdW5jdGlvbiBleHRlbmQobmFtZXNwYWNlLCBkZWxpbWl0ZXIpIHtcblx0XHRjb25zdCBuZXdEZWJ1ZyA9IGNyZWF0ZURlYnVnKHRoaXMubmFtZXNwYWNlICsgKHR5cGVvZiBkZWxpbWl0ZXIgPT09ICd1bmRlZmluZWQnID8gJzonIDogZGVsaW1pdGVyKSArIG5hbWVzcGFjZSk7XG5cdFx0bmV3RGVidWcubG9nID0gdGhpcy5sb2c7XG5cdFx0cmV0dXJuIG5ld0RlYnVnO1xuXHR9XG5cblx0LyoqXG5cdCogRW5hYmxlcyBhIGRlYnVnIG1vZGUgYnkgbmFtZXNwYWNlcy4gVGhpcyBjYW4gaW5jbHVkZSBtb2Rlc1xuXHQqIHNlcGFyYXRlZCBieSBhIGNvbG9uIGFuZCB3aWxkY2FyZHMuXG5cdCpcblx0KiBAcGFyYW0ge1N0cmluZ30gbmFtZXNwYWNlc1xuXHQqIEBhcGkgcHVibGljXG5cdCovXG5cdGZ1bmN0aW9uIGVuYWJsZShuYW1lc3BhY2VzKSB7XG5cdFx0Y3JlYXRlRGVidWcuc2F2ZShuYW1lc3BhY2VzKTtcblx0XHRjcmVhdGVEZWJ1Zy5uYW1lc3BhY2VzID0gbmFtZXNwYWNlcztcblxuXHRcdGNyZWF0ZURlYnVnLm5hbWVzID0gW107XG5cdFx0Y3JlYXRlRGVidWcuc2tpcHMgPSBbXTtcblxuXHRcdGxldCBpO1xuXHRcdGNvbnN0IHNwbGl0ID0gKHR5cGVvZiBuYW1lc3BhY2VzID09PSAnc3RyaW5nJyA/IG5hbWVzcGFjZXMgOiAnJykuc3BsaXQoL1tcXHMsXSsvKTtcblx0XHRjb25zdCBsZW4gPSBzcGxpdC5sZW5ndGg7XG5cblx0XHRmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdGlmICghc3BsaXRbaV0pIHtcblx0XHRcdFx0Ly8gaWdub3JlIGVtcHR5IHN0cmluZ3Ncblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cblx0XHRcdG5hbWVzcGFjZXMgPSBzcGxpdFtpXS5yZXBsYWNlKC9cXCovZywgJy4qPycpO1xuXG5cdFx0XHRpZiAobmFtZXNwYWNlc1swXSA9PT0gJy0nKSB7XG5cdFx0XHRcdGNyZWF0ZURlYnVnLnNraXBzLnB1c2gobmV3IFJlZ0V4cCgnXicgKyBuYW1lc3BhY2VzLnNsaWNlKDEpICsgJyQnKSk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRjcmVhdGVEZWJ1Zy5uYW1lcy5wdXNoKG5ldyBSZWdFeHAoJ14nICsgbmFtZXNwYWNlcyArICckJykpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQqIERpc2FibGUgZGVidWcgb3V0cHV0LlxuXHQqXG5cdCogQHJldHVybiB7U3RyaW5nfSBuYW1lc3BhY2VzXG5cdCogQGFwaSBwdWJsaWNcblx0Ki9cblx0ZnVuY3Rpb24gZGlzYWJsZSgpIHtcblx0XHRjb25zdCBuYW1lc3BhY2VzID0gW1xuXHRcdFx0Li4uY3JlYXRlRGVidWcubmFtZXMubWFwKHRvTmFtZXNwYWNlKSxcblx0XHRcdC4uLmNyZWF0ZURlYnVnLnNraXBzLm1hcCh0b05hbWVzcGFjZSkubWFwKG5hbWVzcGFjZSA9PiAnLScgKyBuYW1lc3BhY2UpXG5cdFx0XS5qb2luKCcsJyk7XG5cdFx0Y3JlYXRlRGVidWcuZW5hYmxlKCcnKTtcblx0XHRyZXR1cm4gbmFtZXNwYWNlcztcblx0fVxuXG5cdC8qKlxuXHQqIFJldHVybnMgdHJ1ZSBpZiB0aGUgZ2l2ZW4gbW9kZSBuYW1lIGlzIGVuYWJsZWQsIGZhbHNlIG90aGVyd2lzZS5cblx0KlxuXHQqIEBwYXJhbSB7U3RyaW5nfSBuYW1lXG5cdCogQHJldHVybiB7Qm9vbGVhbn1cblx0KiBAYXBpIHB1YmxpY1xuXHQqL1xuXHRmdW5jdGlvbiBlbmFibGVkKG5hbWUpIHtcblx0XHRpZiAobmFtZVtuYW1lLmxlbmd0aCAtIDFdID09PSAnKicpIHtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblxuXHRcdGxldCBpO1xuXHRcdGxldCBsZW47XG5cblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBjcmVhdGVEZWJ1Zy5za2lwcy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuXHRcdFx0aWYgKGNyZWF0ZURlYnVnLnNraXBzW2ldLnRlc3QobmFtZSkpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGZvciAoaSA9IDAsIGxlbiA9IGNyZWF0ZURlYnVnLm5hbWVzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRpZiAoY3JlYXRlRGVidWcubmFtZXNbaV0udGVzdChuYW1lKSkge1xuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHQvKipcblx0KiBDb252ZXJ0IHJlZ2V4cCB0byBuYW1lc3BhY2Vcblx0KlxuXHQqIEBwYXJhbSB7UmVnRXhwfSByZWd4ZXBcblx0KiBAcmV0dXJuIHtTdHJpbmd9IG5hbWVzcGFjZVxuXHQqIEBhcGkgcHJpdmF0ZVxuXHQqL1xuXHRmdW5jdGlvbiB0b05hbWVzcGFjZShyZWdleHApIHtcblx0XHRyZXR1cm4gcmVnZXhwLnRvU3RyaW5nKClcblx0XHRcdC5zdWJzdHJpbmcoMiwgcmVnZXhwLnRvU3RyaW5nKCkubGVuZ3RoIC0gMilcblx0XHRcdC5yZXBsYWNlKC9cXC5cXCpcXD8kLywgJyonKTtcblx0fVxuXG5cdC8qKlxuXHQqIENvZXJjZSBgdmFsYC5cblx0KlxuXHQqIEBwYXJhbSB7TWl4ZWR9IHZhbFxuXHQqIEByZXR1cm4ge01peGVkfVxuXHQqIEBhcGkgcHJpdmF0ZVxuXHQqL1xuXHRmdW5jdGlvbiBjb2VyY2UodmFsKSB7XG5cdFx0aWYgKHZhbCBpbnN0YW5jZW9mIEVycm9yKSB7XG5cdFx0XHRyZXR1cm4gdmFsLnN0YWNrIHx8IHZhbC5tZXNzYWdlO1xuXHRcdH1cblx0XHRyZXR1cm4gdmFsO1xuXHR9XG5cblx0LyoqXG5cdCogWFhYIERPIE5PVCBVU0UuIFRoaXMgaXMgYSB0ZW1wb3Jhcnkgc3R1YiBmdW5jdGlvbi5cblx0KiBYWFggSXQgV0lMTCBiZSByZW1vdmVkIGluIHRoZSBuZXh0IG1ham9yIHJlbGVhc2UuXG5cdCovXG5cdGZ1bmN0aW9uIGRlc3Ryb3koKSB7XG5cdFx0Y29uc29sZS53YXJuKCdJbnN0YW5jZSBtZXRob2QgYGRlYnVnLmRlc3Ryb3koKWAgaXMgZGVwcmVjYXRlZCBhbmQgbm8gbG9uZ2VyIGRvZXMgYW55dGhpbmcuIEl0IHdpbGwgYmUgcmVtb3ZlZCBpbiB0aGUgbmV4dCBtYWpvciB2ZXJzaW9uIG9mIGBkZWJ1Z2AuJyk7XG5cdH1cblxuXHRjcmVhdGVEZWJ1Zy5lbmFibGUoY3JlYXRlRGVidWcubG9hZCgpKTtcblxuXHRyZXR1cm4gY3JlYXRlRGVidWc7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gc2V0dXA7XG4iLCIvKipcbiAqIEhlbHBlcnMuXG4gKi9cblxudmFyIHMgPSAxMDAwO1xudmFyIG0gPSBzICogNjA7XG52YXIgaCA9IG0gKiA2MDtcbnZhciBkID0gaCAqIDI0O1xudmFyIHcgPSBkICogNztcbnZhciB5ID0gZCAqIDM2NS4yNTtcblxuLyoqXG4gKiBQYXJzZSBvciBmb3JtYXQgdGhlIGdpdmVuIGB2YWxgLlxuICpcbiAqIE9wdGlvbnM6XG4gKlxuICogIC0gYGxvbmdgIHZlcmJvc2UgZm9ybWF0dGluZyBbZmFsc2VdXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfSB2YWxcbiAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0aW9uc11cbiAqIEB0aHJvd3Mge0Vycm9yfSB0aHJvdyBhbiBlcnJvciBpZiB2YWwgaXMgbm90IGEgbm9uLWVtcHR5IHN0cmluZyBvciBhIG51bWJlclxuICogQHJldHVybiB7U3RyaW5nfE51bWJlcn1cbiAqIEBhcGkgcHVibGljXG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbih2YWwsIG9wdGlvbnMpIHtcbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gIHZhciB0eXBlID0gdHlwZW9mIHZhbDtcbiAgaWYgKHR5cGUgPT09ICdzdHJpbmcnICYmIHZhbC5sZW5ndGggPiAwKSB7XG4gICAgcmV0dXJuIHBhcnNlKHZhbCk7XG4gIH0gZWxzZSBpZiAodHlwZSA9PT0gJ251bWJlcicgJiYgaXNGaW5pdGUodmFsKSkge1xuICAgIHJldHVybiBvcHRpb25zLmxvbmcgPyBmbXRMb25nKHZhbCkgOiBmbXRTaG9ydCh2YWwpO1xuICB9XG4gIHRocm93IG5ldyBFcnJvcihcbiAgICAndmFsIGlzIG5vdCBhIG5vbi1lbXB0eSBzdHJpbmcgb3IgYSB2YWxpZCBudW1iZXIuIHZhbD0nICtcbiAgICAgIEpTT04uc3RyaW5naWZ5KHZhbClcbiAgKTtcbn07XG5cbi8qKlxuICogUGFyc2UgdGhlIGdpdmVuIGBzdHJgIGFuZCByZXR1cm4gbWlsbGlzZWNvbmRzLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzdHJcbiAqIEByZXR1cm4ge051bWJlcn1cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIHBhcnNlKHN0cikge1xuICBzdHIgPSBTdHJpbmcoc3RyKTtcbiAgaWYgKHN0ci5sZW5ndGggPiAxMDApIHtcbiAgICByZXR1cm47XG4gIH1cbiAgdmFyIG1hdGNoID0gL14oLT8oPzpcXGQrKT9cXC4/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/XG4gICAgfVxuICB9XG4gIGlmIChzZXNzaW9ucGFydCkge1xuICAgIHJldHVybiBTRFBVdGlscy5nZXREaXJlY3Rpb24oc2Vzc2lvbnBhcnQpO1xuICB9XG4gIHJldHVybiAnc2VuZHJlY3YnO1xufTtcblxuU0RQVXRpbHMuZ2V0S2luZCA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICBjb25zdCBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMobWVkaWFTZWN0aW9uKTtcbiAgY29uc3QgbWxpbmUgPSBsaW5lc1swXS5zcGxpdCgnICcpO1xuICByZXR1cm4gbWxpbmVbMF0uc3Vic3RyaW5nKDIpO1xufTtcblxuU0RQVXRpbHMuaXNSZWplY3RlZCA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICByZXR1cm4gbWVkaWFTZWN0aW9uLnNwbGl0KCcgJywgMilbMV0gPT09ICcwJztcbn07XG5cblNEUFV0aWxzLnBhcnNlTUxpbmUgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgY29uc3QgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIGNvbnN0IHBhcnRzID0gbGluZXNbMF0uc3Vic3RyaW5nKDIpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAga2luZDogcGFydHNbMF0sXG4gICAgcG9ydDogcGFyc2VJbnQocGFydHNbMV0sIDEwKSxcbiAgICBwcm90b2NvbDogcGFydHNbMl0sXG4gICAgZm10OiBwYXJ0cy5zbGljZSgzKS5qb2luKCcgJyksXG4gIH07XG59O1xuXG5TRFBVdGlscy5wYXJzZU9MaW5lID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIGNvbnN0IGxpbmUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdvPScpWzBdO1xuICBjb25zdCBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDIpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAgdXNlcm5hbWU6IHBhcnRzWzBdLFxuICAgIHNlc3Npb25JZDogcGFydHNbMV0sXG4gICAgc2Vzc2lvblZlcnNpb246IHBhcnNlSW50KHBhcnRzWzJdLCAxMCksXG4gICAgbmV0VHlwZTogcGFydHNbM10sXG4gICAgYWRkcmVzc1R5cGU6IHBhcnRzWzRdLFxuICAgIGFkZHJlc3M6IHBhcnRzWzVdLFxuICB9O1xufTtcblxuLy8gYSB2ZXJ5IG5haXZlIGludGVycHJldGF0aW9uIG9mIGEgdmFsaWQgU0RQLlxuU0RQVXRpbHMuaXNWYWxpZFNEUCA9IGZ1bmN0aW9uKGJsb2IpIHtcbiAgaWYgKHR5cGVvZiBibG9iICE9PSAnc3RyaW5nJyB8fCBibG9iLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBjb25zdCBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMoYmxvYik7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAobGluZXNbaV0ubGVuZ3RoIDwgMiB8fCBsaW5lc1tpXS5jaGFyQXQoMSkgIT09ICc9Jykge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICAvLyBUT0RPOiBjaGVjayB0aGUgbW9kaWZpZXIgYSBiaXQgbW9yZS5cbiAgfVxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbi8vIEV4cG9zZSBwdWJsaWMgbWV0aG9kcy5cbmlmICh0eXBlb2YgbW9kdWxlID09PSAnb2JqZWN0Jykge1xuICBtb2R1bGUuZXhwb3J0cyA9IFNEUFV0aWxzO1xufVxuIiwiLy8gVGhlIG1vZHVsZSBjYWNoZVxudmFyIF9fd2VicGFja19tb2R1bGVfY2FjaGVfXyA9IHt9O1xuXG4vLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcblx0dmFyIGNhY2hlZE1vZHVsZSA9IF9fd2VicGFja19tb2R1bGVfY2FjaGVfX1ttb2R1bGVJZF07XG5cdGlmIChjYWNoZWRNb2R1bGUgIT09IHVuZGVmaW5lZCkge1xuXHRcdHJldHVybiBjYWNoZWRNb2R1bGUuZXhwb3J0cztcblx0fVxuXHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuXHR2YXIgbW9kdWxlID0gX193ZWJwYWNrX21vZHVsZV9jYWNoZV9fW21vZHVsZUlkXSA9IHtcblx0XHQvLyBubyBtb2R1bGUuaWQgbmVlZGVkXG5cdFx0Ly8gbm8gbW9kdWxlLmxvYWRlZCBuZWVkZWRcblx0XHRleHBvcnRzOiB7fVxuXHR9O1xuXG5cdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuXHRfX3dlYnBhY2tfbW9kdWxlc19fW21vZHVsZUlkXShtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuXHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuXHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG59XG5cbiIsIiIsIi8vIHN0YXJ0dXBcbi8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuLy8gVGhpcyBlbnRyeSBtb2R1bGUgaXMgcmVmZXJlbmNlZCBieSBvdGhlciBtb2R1bGVzIHNvIGl0IGNhbid0IGJlIGlubGluZWRcbnZhciBfX3dlYnBhY2tfZXhwb3J0c19fID0gX193ZWJwYWNrX3JlcXVpcmVfXyhcIi4vc3JjL2luZGV4LmpzXCIpO1xuIiwiIl0sIm5hbWVzIjpbIl9yZWdlbmVyYXRvclJ1bnRpbWUiLCJleHBvcnRzIiwiT3AiLCJPYmplY3QiLCJwcm90b3R5cGUiLCJoYXNPd24iLCJoYXNPd25Qcm9wZXJ0eSIsImRlZmluZVByb3BlcnR5Iiwib2JqIiwia2V5IiwiZGVzYyIsInZhbHVlIiwiJFN5bWJvbCIsIlN5bWJvbCIsIml0ZXJhdG9yU3ltYm9sIiwiaXRlcmF0b3IiLCJhc3luY0l0ZXJhdG9yU3ltYm9sIiwiYXN5bmNJdGVyYXRvciIsInRvU3RyaW5nVGFnU3ltYm9sIiwidG9TdHJpbmdUYWciLCJkZWZpbmUiLCJlbnVtZXJhYmxlIiwiY29uZmlndXJhYmxlIiwid3JpdGFibGUiLCJlcnIiLCJ3cmFwIiwiaW5uZXJGbiIsIm91dGVyRm4iLCJzZWxmIiwidHJ5TG9jc0xpc3QiLCJwcm90b0dlbmVyYXRvciIsIkdlbmVyYXRvciIsImdlbmVyYXRvciIsImNyZWF0ZSIsImNvbnRleHQiLCJDb250ZXh0IiwibWFrZUludm9rZU1ldGhvZCIsInRyeUNhdGNoIiwiZm4iLCJhcmciLCJ0eXBlIiwiY2FsbCIsIkNvbnRpbnVlU2VudGluZWwiLCJHZW5lcmF0b3JGdW5jdGlvbiIsIkdlbmVyYXRvckZ1bmN0aW9uUHJvdG90eXBlIiwiSXRlcmF0b3JQcm90b3R5cGUiLCJnZXRQcm90byIsImdldFByb3RvdHlwZU9mIiwiTmF0aXZlSXRlcmF0b3JQcm90b3R5cGUiLCJ2YWx1ZXMiLCJHcCIsImRlZmluZUl0ZXJhdG9yTWV0aG9kcyIsImZvckVhY2giLCJtZXRob2QiLCJfaW52b2tlIiwiQXN5bmNJdGVyYXRvciIsIlByb21pc2VJbXBsIiwiaW52b2tlIiwicmVzb2x2ZSIsInJlamVjdCIsInJlY29yZCIsInJlc3VsdCIsIl90eXBlb2YiLCJfX2F3YWl0IiwidGhlbiIsInVud3JhcHBlZCIsImVycm9yIiwicHJldmlvdXNQcm9taXNlIiwiY2FsbEludm9rZVdpdGhNZXRob2RBbmRBcmciLCJzdGF0ZSIsIkVycm9yIiwiZG9uZVJlc3VsdCIsImRlbGVnYXRlIiwiZGVsZWdhdGVSZXN1bHQiLCJtYXliZUludm9rZURlbGVnYXRlIiwic2VudCIsIl9zZW50IiwiZGlzcGF0Y2hFeGNlcHRpb24iLCJhYnJ1cHQiLCJkb25lIiwibWV0aG9kTmFtZSIsInVuZGVmaW5lZCIsIlR5cGVFcnJvciIsImluZm8iLCJyZXN1bHROYW1lIiwibmV4dCIsIm5leHRMb2MiLCJwdXNoVHJ5RW50cnkiLCJsb2NzIiwiZW50cnkiLCJ0cnlMb2MiLCJjYXRjaExvYyIsImZpbmFsbHlMb2MiLCJhZnRlckxvYyIsInRyeUVudHJpZXMiLCJwdXNoIiwicmVzZXRUcnlFbnRyeSIsImNvbXBsZXRpb24iLCJyZXNldCIsIml0ZXJhYmxlIiwiaXRlcmF0b3JNZXRob2QiLCJpc05hTiIsImxlbmd0aCIsImkiLCJkaXNwbGF5TmFtZSIsImlzR2VuZXJhdG9yRnVuY3Rpb24iLCJnZW5GdW4iLCJjdG9yIiwiY29uc3RydWN0b3IiLCJuYW1lIiwibWFyayIsInNldFByb3RvdHlwZU9mIiwiX19wcm90b19fIiwiYXdyYXAiLCJhc3luYyIsIlByb21pc2UiLCJpdGVyIiwia2V5cyIsInZhbCIsIm9iamVjdCIsInJldmVyc2UiLCJwb3AiLCJza2lwVGVtcFJlc2V0IiwicHJldiIsImNoYXJBdCIsInNsaWNlIiwic3RvcCIsInJvb3RSZWNvcmQiLCJydmFsIiwiZXhjZXB0aW9uIiwiaGFuZGxlIiwibG9jIiwiY2F1Z2h0IiwiaGFzQ2F0Y2giLCJoYXNGaW5hbGx5IiwiZmluYWxseUVudHJ5IiwiY29tcGxldGUiLCJmaW5pc2giLCJfY2F0Y2giLCJ0aHJvd24iLCJkZWxlZ2F0ZVlpZWxkIiwiYXN5bmNHZW5lcmF0b3JTdGVwIiwiZ2VuIiwiX25leHQiLCJfdGhyb3ciLCJfYXN5bmNUb0dlbmVyYXRvciIsImFyZ3MiLCJhcmd1bWVudHMiLCJhcHBseSIsIl9jbGFzc0NhbGxDaGVjayIsImluc3RhbmNlIiwiQ29uc3RydWN0b3IiLCJfZGVmaW5lUHJvcGVydGllcyIsInRhcmdldCIsInByb3BzIiwiZGVzY3JpcHRvciIsIl90b1Byb3BlcnR5S2V5IiwiX2NyZWF0ZUNsYXNzIiwicHJvdG9Qcm9wcyIsInN0YXRpY1Byb3BzIiwiX3RvUHJpbWl0aXZlIiwiU3RyaW5nIiwiaW5wdXQiLCJoaW50IiwicHJpbSIsInRvUHJpbWl0aXZlIiwicmVzIiwiTnVtYmVyIiwibWoiLCJyZXF1aXJlIiwiSmFudXNTZXNzaW9uIiwic2VuZE9yaWdpbmFsIiwic2VuZCIsInNpZ25hbCIsImUiLCJtZXNzYWdlIiwiaW5kZXhPZiIsImNvbnNvbGUiLCJOQUYiLCJjb25uZWN0aW9uIiwiYWRhcHRlciIsInJlY29ubmVjdCIsInNkcFV0aWxzIiwiZGVidWciLCJ3YXJuIiwiaXNTYWZhcmkiLCJ0ZXN0IiwibmF2aWdhdG9yIiwidXNlckFnZW50IiwiU1VCU0NSSUJFX1RJTUVPVVRfTVMiLCJBVkFJTEFCTEVfT0NDVVBBTlRTX1RIUkVTSE9MRCIsIk1BWF9TVUJTQ1JJQkVfREVMQVkiLCJyYW5kb21EZWxheSIsIm1pbiIsIm1heCIsImRlbGF5IiwiTWF0aCIsInJhbmRvbSIsInNldFRpbWVvdXQiLCJkZWJvdW5jZSIsImN1cnIiLCJfdGhpcyIsIkFycmF5IiwiXyIsInJhbmRvbVVpbnQiLCJmbG9vciIsIk1BWF9TQUZFX0lOVEVHRVIiLCJ1bnRpbERhdGFDaGFubmVsT3BlbiIsImRhdGFDaGFubmVsIiwicmVhZHlTdGF0ZSIsInJlc29sdmVyIiwicmVqZWN0b3IiLCJjbGVhciIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJhZGRFdmVudExpc3RlbmVyIiwiaXNIMjY0VmlkZW9TdXBwb3J0ZWQiLCJ2aWRlbyIsImRvY3VtZW50IiwiY3JlYXRlRWxlbWVudCIsImNhblBsYXlUeXBlIiwiT1BVU19QQVJBTUVURVJTIiwidXNlZHR4Iiwic3RlcmVvIiwiREVGQVVMVF9QRUVSX0NPTk5FQ1RJT05fQ09ORklHIiwiaWNlU2VydmVycyIsInVybHMiLCJXU19OT1JNQUxfQ0xPU1VSRSIsIkphbnVzQWRhcHRlciIsInJvb20iLCJjbGllbnRJZCIsImpvaW5Ub2tlbiIsInNlcnZlclVybCIsIndlYlJ0Y09wdGlvbnMiLCJwZWVyQ29ubmVjdGlvbkNvbmZpZyIsIndzIiwic2Vzc2lvbiIsInJlbGlhYmxlVHJhbnNwb3J0IiwidW5yZWxpYWJsZVRyYW5zcG9ydCIsImluaXRpYWxSZWNvbm5lY3Rpb25EZWxheSIsInJlY29ubmVjdGlvbkRlbGF5IiwicmVjb25uZWN0aW9uVGltZW91dCIsIm1heFJlY29ubmVjdGlvbkF0dGVtcHRzIiwicmVjb25uZWN0aW9uQXR0ZW1wdHMiLCJwdWJsaXNoZXIiLCJvY2N1cGFudElkcyIsIm9jY3VwYW50cyIsIm1lZGlhU3RyZWFtcyIsImxvY2FsTWVkaWFTdHJlYW0iLCJwZW5kaW5nTWVkaWFSZXF1ZXN0cyIsIk1hcCIsInBlbmRpbmdPY2N1cGFudHMiLCJTZXQiLCJhdmFpbGFibGVPY2N1cGFudHMiLCJyZXF1ZXN0ZWRPY2N1cGFudHMiLCJibG9ja2VkQ2xpZW50cyIsImZyb3plblVwZGF0ZXMiLCJ0aW1lT2Zmc2V0cyIsInNlcnZlclRpbWVSZXF1ZXN0cyIsImF2Z1RpbWVPZmZzZXQiLCJvbldlYnNvY2tldE9wZW4iLCJiaW5kIiwib25XZWJzb2NrZXRDbG9zZSIsIm9uV2Vic29ja2V0TWVzc2FnZSIsIm9uRGF0YUNoYW5uZWxNZXNzYWdlIiwib25EYXRhIiwic2V0U2VydmVyVXJsIiwidXJsIiwic2V0QXBwIiwiYXBwIiwic2V0Um9vbSIsInJvb21OYW1lIiwic2V0Sm9pblRva2VuIiwic2V0Q2xpZW50SWQiLCJzZXRXZWJSdGNPcHRpb25zIiwib3B0aW9ucyIsInNldFBlZXJDb25uZWN0aW9uQ29uZmlnIiwic2V0U2VydmVyQ29ubmVjdExpc3RlbmVycyIsInN1Y2Nlc3NMaXN0ZW5lciIsImZhaWx1cmVMaXN0ZW5lciIsImNvbm5lY3RTdWNjZXNzIiwiY29ubmVjdEZhaWx1cmUiLCJzZXRSb29tT2NjdXBhbnRMaXN0ZW5lciIsIm9jY3VwYW50TGlzdGVuZXIiLCJvbk9jY3VwYW50c0NoYW5nZWQiLCJzZXREYXRhQ2hhbm5lbExpc3RlbmVycyIsIm9wZW5MaXN0ZW5lciIsImNsb3NlZExpc3RlbmVyIiwibWVzc2FnZUxpc3RlbmVyIiwib25PY2N1cGFudENvbm5lY3RlZCIsIm9uT2NjdXBhbnREaXNjb25uZWN0ZWQiLCJvbk9jY3VwYW50TWVzc2FnZSIsInNldFJlY29ubmVjdGlvbkxpc3RlbmVycyIsInJlY29ubmVjdGluZ0xpc3RlbmVyIiwicmVjb25uZWN0ZWRMaXN0ZW5lciIsInJlY29ubmVjdGlvbkVycm9yTGlzdGVuZXIiLCJvblJlY29ubmVjdGluZyIsIm9uUmVjb25uZWN0ZWQiLCJvblJlY29ubmVjdGlvbkVycm9yIiwic2V0RXZlbnRMb29wcyIsImxvb3BzIiwiY29ubmVjdCIsIl90aGlzMiIsImNvbmNhdCIsIndlYnNvY2tldENvbm5lY3Rpb24iLCJXZWJTb2NrZXQiLCJ0aW1lb3V0TXMiLCJ3c09uT3BlbiIsImFsbCIsInVwZGF0ZVRpbWVPZmZzZXQiLCJkaXNjb25uZWN0IiwiY2xlYXJUaW1lb3V0IiwicmVtb3ZlQWxsT2NjdXBhbnRzIiwiY29ubiIsImNsb3NlIiwiZGlzcG9zZSIsImRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0IiwiaXNEaXNjb25uZWN0ZWQiLCJfb25XZWJzb2NrZXRPcGVuIiwiX2NhbGxlZSIsIm9jY3VwYW50SWQiLCJfY2FsbGVlJCIsIl9jb250ZXh0IiwiY3JlYXRlUHVibGlzaGVyIiwiaW5pdGlhbE9jY3VwYW50cyIsImFkZEF2YWlsYWJsZU9jY3VwYW50Iiwic3luY09jY3VwYW50cyIsImV2ZW50IiwiX3RoaXMzIiwiY29kZSIsIl90aGlzNCIsInBlcmZvcm1EZWxheWVkUmVjb25uZWN0IiwiX3RoaXM1IiwicmVjZWl2ZSIsIkpTT04iLCJwYXJzZSIsImRhdGEiLCJyZW1vdmVBdmFpbGFibGVPY2N1cGFudCIsImlkeCIsInNwbGljZSIsImhhcyIsImFkZE9jY3VwYW50IiwiaiIsInJlbW92ZU9jY3VwYW50IiwiX2FkZE9jY3VwYW50IiwiX2NhbGxlZTIiLCJhdmFpbGFibGVPY2N1cGFudHNDb3VudCIsInN1YnNjcmliZXIiLCJfY2FsbGVlMiQiLCJfY29udGV4dDIiLCJhZGQiLCJjcmVhdGVTdWJzY3JpYmVyIiwic2V0TWVkaWFTdHJlYW0iLCJtZWRpYVN0cmVhbSIsIl94IiwibXNnIiwiZ2V0IiwiYXVkaW8iLCJhc3NvY2lhdGUiLCJfdGhpczYiLCJldiIsInNlbmRUcmlja2xlIiwiY2FuZGlkYXRlIiwiaWNlQ29ubmVjdGlvblN0YXRlIiwibG9nIiwib2ZmZXIiLCJjcmVhdGVPZmZlciIsImNvbmZpZ3VyZVB1Ymxpc2hlclNkcCIsImZpeFNhZmFyaUljZVVGcmFnIiwibG9jYWwiLCJvIiwic2V0TG9jYWxEZXNjcmlwdGlvbiIsInJlbW90ZSIsInNlbmRKc2VwIiwiciIsInNldFJlbW90ZURlc2NyaXB0aW9uIiwianNlcCIsIm9uIiwiYW5zd2VyIiwiY29uZmlndXJlU3Vic2NyaWJlclNkcCIsImNyZWF0ZUFuc3dlciIsImEiLCJfY3JlYXRlUHVibGlzaGVyIiwiX2NhbGxlZTMiLCJfdGhpczciLCJ3ZWJydGN1cCIsInJlbGlhYmxlQ2hhbm5lbCIsInVucmVsaWFibGVDaGFubmVsIiwiX2NhbGxlZTMkIiwiX2NvbnRleHQzIiwiSmFudXNQbHVnaW5IYW5kbGUiLCJSVENQZWVyQ29ubmVjdGlvbiIsImF0dGFjaCIsInBhcnNlSW50IiwiY3JlYXRlRGF0YUNoYW5uZWwiLCJvcmRlcmVkIiwibWF4UmV0cmFuc21pdHMiLCJnZXRUcmFja3MiLCJ0cmFjayIsImFkZFRyYWNrIiwicGx1Z2luZGF0YSIsInJvb21faWQiLCJ1c2VyX2lkIiwiYm9keSIsImRpc3BhdGNoRXZlbnQiLCJDdXN0b21FdmVudCIsImRldGFpbCIsImJ5Iiwic2VuZEpvaW4iLCJub3RpZmljYXRpb25zIiwic3VjY2VzcyIsInJlc3BvbnNlIiwidXNlcnMiLCJpbmNsdWRlcyIsInNkcCIsInJlcGxhY2UiLCJsaW5lIiwicHQiLCJwYXJhbWV0ZXJzIiwiYXNzaWduIiwicGFyc2VGbXRwIiwid3JpdGVGbXRwIiwicGF5bG9hZFR5cGUiLCJfZml4U2FmYXJpSWNlVUZyYWciLCJfY2FsbGVlNCIsIl9jYWxsZWU0JCIsIl9jb250ZXh0NCIsIl94MiIsIl9jcmVhdGVTdWJzY3JpYmVyIiwiX2NhbGxlZTUiLCJfdGhpczgiLCJtYXhSZXRyaWVzIiwid2VicnRjRmFpbGVkIiwicmVjZWl2ZXJzIiwiX2FyZ3M1IiwiX2NhbGxlZTUkIiwiX2NvbnRleHQ1IiwibGVmdEludGVydmFsIiwic2V0SW50ZXJ2YWwiLCJjbGVhckludGVydmFsIiwidGltZW91dCIsIm1lZGlhIiwiX2lPU0hhY2tEZWxheWVkSW5pdGlhbFBlZXIiLCJNZWRpYVN0cmVhbSIsImdldFJlY2VpdmVycyIsInJlY2VpdmVyIiwiX3gzIiwic3Vic2NyaWJlIiwic2VuZE1lc3NhZ2UiLCJraW5kIiwidG9rZW4iLCJ0b2dnbGVGcmVlemUiLCJmcm96ZW4iLCJ1bmZyZWV6ZSIsImZyZWV6ZSIsImZsdXNoUGVuZGluZ1VwZGF0ZXMiLCJkYXRhRm9yVXBkYXRlTXVsdGlNZXNzYWdlIiwibmV0d29ya0lkIiwibCIsImQiLCJnZXRQZW5kaW5nRGF0YSIsImRhdGFUeXBlIiwib3duZXIiLCJnZXRQZW5kaW5nRGF0YUZvck5ldHdvcmtJZCIsIl9pdGVyYXRvciIsIl9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyIiwiX3N0ZXAiLCJzIiwibiIsIl9zdGVwJHZhbHVlIiwiX3NsaWNlZFRvQXJyYXkiLCJzb3VyY2UiLCJmIiwic3RvcmVNZXNzYWdlIiwic3RvcmVTaW5nbGVNZXNzYWdlIiwiaW5kZXgiLCJzZXQiLCJzdG9yZWRNZXNzYWdlIiwic3RvcmVkRGF0YSIsImlzT3V0ZGF0ZWRNZXNzYWdlIiwibGFzdE93bmVyVGltZSIsImlzQ29udGVtcG9yYW5lb3VzTWVzc2FnZSIsImNyZWF0ZWRXaGlsZUZyb3plbiIsImlzRmlyc3RTeW5jIiwiY29tcG9uZW50cyIsImVuYWJsZWQiLCJzaG91bGRTdGFydENvbm5lY3Rpb25UbyIsImNsaWVudCIsInN0YXJ0U3RyZWFtQ29ubmVjdGlvbiIsImNsb3NlU3RyZWFtQ29ubmVjdGlvbiIsImdldENvbm5lY3RTdGF0dXMiLCJhZGFwdGVycyIsIklTX0NPTk5FQ1RFRCIsIk5PVF9DT05ORUNURUQiLCJfdXBkYXRlVGltZU9mZnNldCIsIl9jYWxsZWU2IiwiX3RoaXM5IiwiY2xpZW50U2VudFRpbWUiLCJwcmVjaXNpb24iLCJzZXJ2ZXJSZWNlaXZlZFRpbWUiLCJjbGllbnRSZWNlaXZlZFRpbWUiLCJzZXJ2ZXJUaW1lIiwidGltZU9mZnNldCIsIl9jYWxsZWU2JCIsIl9jb250ZXh0NiIsIkRhdGUiLCJub3ciLCJmZXRjaCIsImxvY2F0aW9uIiwiaHJlZiIsImNhY2hlIiwiaGVhZGVycyIsImdldFRpbWUiLCJyZWR1Y2UiLCJhY2MiLCJvZmZzZXQiLCJnZXRTZXJ2ZXJUaW1lIiwiZ2V0TWVkaWFTdHJlYW0iLCJfdGhpczEwIiwiYXVkaW9Qcm9taXNlIiwidmlkZW9Qcm9taXNlIiwicHJvbWlzZSIsInN0cmVhbSIsImF1ZGlvU3RyZWFtIiwiZ2V0QXVkaW9UcmFja3MiLCJ2aWRlb1N0cmVhbSIsImdldFZpZGVvVHJhY2tzIiwiX3NldExvY2FsTWVkaWFTdHJlYW0iLCJfY2FsbGVlNyIsIl90aGlzMTEiLCJleGlzdGluZ1NlbmRlcnMiLCJuZXdTZW5kZXJzIiwidHJhY2tzIiwiX2xvb3AiLCJfY2FsbGVlNyQiLCJfY29udGV4dDgiLCJnZXRTZW5kZXJzIiwidCIsInNlbmRlciIsIl9sb29wJCIsIl9jb250ZXh0NyIsImZpbmQiLCJyZXBsYWNlVHJhY2siLCJ0b0xvd2VyQ2FzZSIsInJlbW92ZVRyYWNrIiwic2V0TG9jYWxNZWRpYVN0cmVhbSIsIl94NCIsImVuYWJsZU1pY3JvcGhvbmUiLCJzZW5kRGF0YSIsInN0cmluZ2lmeSIsIndob20iLCJzZW5kRGF0YUd1YXJhbnRlZWQiLCJicm9hZGNhc3REYXRhIiwiYnJvYWRjYXN0RGF0YUd1YXJhbnRlZWQiLCJraWNrIiwicGVybXNUb2tlbiIsImJsb2NrIiwiX3RoaXMxMiIsInVuYmxvY2siLCJfdGhpczEzIiwicmVnaXN0ZXIiLCJtb2R1bGUiXSwic291cmNlUm9vdCI6IiJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTs7QUFFQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsNENBQTRDOztBQUV2RDtBQUNBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Es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QTs7QUFFQTtBQUNBOztBQUVBOzs7Ozs7Ozs7OztBQ2pSQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxlQUFlO0FBQzFCLFdBQVcsUUFBUTtBQUNuQixZQUFZLE9BQU87QUFDbkIsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkIsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkIsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxRQUFRO0FBQ25CLFlBQVk7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7O0FDaktBO0FBQ2E7O0FBRWI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGdCQUFnQixvQkFBb0I7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxrQkFBa0Isa0JBQWtCO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3Q0FBd0M7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSw2Q0FBNkM7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esb0JBQW9CO0FBQ3BCLDJCQUEyQjtBQUMzQjtBQUNBO0FBQ0E7QUFDQSw4REFBOEQ7QUFDOUQsa0JBQWtCLGtCQUFrQjtBQUNwQztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsS0FBSztBQUNMLGlEQUFpRDtBQUNqRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0Isa0JBQWtCLE9BQU87QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNkNBQTZDO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQixrQkFBa0I7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0Isa0JBQWtCO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsSUFBSSxJQUEwQjtBQUM5QjtBQUNBOzs7Ozs7O1VDanlCQTtVQUNBOztVQUVBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBOztVQUVBO1VBQ0E7O1VBRUE7VUFDQTtVQUNBOzs7O1VFdEJBO1VBQ0E7VUFDQTtVQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvLi9ub2RlX21vZHVsZXMvQG5ldHdvcmtlZC1hZnJhbWUvbWluaWphbnVzL21pbmlqYW51cy5qcyIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci8uL3NyYy9pbmRleC5qcyIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci8uL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvYnJvd3Nlci5qcyIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci8uL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvY29tbW9uLmpzIiwid2VicGFjazovL0BuZXR3b3JrZWQtYWZyYW1lL25hZi1qYW51cy1hZGFwdGVyLy4vbm9kZV9tb2R1bGVzL21zL2luZGV4LmpzIiwid2VicGFjazovL0BuZXR3b3JrZWQtYWZyYW1lL25hZi1qYW51cy1hZGFwdGVyLy4vbm9kZV9tb2R1bGVzL3NkcC9zZHAuanMiLCJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvd2VicGFjay9iZWZvcmUtc3RhcnR1cCIsIndlYnBhY2s6Ly9AbmV0d29ya2VkLWFmcmFtZS9uYWYtamFudXMtYWRhcHRlci93ZWJwYWNrL3N0YXJ0dXAiLCJ3ZWJwYWNrOi8vQG5ldHdvcmtlZC1hZnJhbWUvbmFmLWphbnVzLWFkYXB0ZXIvd2VicGFjay9hZnRlci1zdGFydHVwIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUmVwcmVzZW50cyBhIGhhbmRsZSB0byBhIHNpbmdsZSBKYW51cyBwbHVnaW4gb24gYSBKYW51cyBzZXNzaW9uLiBFYWNoIFdlYlJUQyBjb25uZWN0aW9uIHRvIHRoZSBKYW51cyBzZXJ2ZXIgd2lsbCBiZVxuICogYXNzb2NpYXRlZCB3aXRoIGEgc2luZ2xlIGhhbmRsZS4gT25jZSBhdHRhY2hlZCB0byB0aGUgc2VydmVyLCB0aGlzIGhhbmRsZSB3aWxsIGJlIGdpdmVuIGEgdW5pcXVlIElEIHdoaWNoIHNob3VsZCBiZVxuICogdXNlZCB0byBhc3NvY2lhdGUgaXQgd2l0aCBmdXR1cmUgc2lnbmFsbGluZyBtZXNzYWdlcy5cbiAqXG4gKiBTZWUgaHR0cHM6Ly9qYW51cy5jb25mLm1lZXRlY2hvLmNvbS9kb2NzL3Jlc3QuaHRtbCNoYW5kbGVzLlxuICoqL1xuZnVuY3Rpb24gSmFudXNQbHVnaW5IYW5kbGUoc2Vzc2lvbikge1xuICB0aGlzLnNlc3Npb24gPSBzZXNzaW9uO1xuICB0aGlzLmlkID0gdW5kZWZpbmVkO1xufVxuXG4vKiogQXR0YWNoZXMgdGhpcyBoYW5kbGUgdG8gdGhlIEphbnVzIHNlcnZlciBhbmQgc2V0cyBpdHMgSUQuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLmF0dGFjaCA9IGZ1bmN0aW9uKHBsdWdpbiwgbG9vcF9pbmRleCkge1xuICB2YXIgcGF5bG9hZCA9IHsgcGx1Z2luOiBwbHVnaW4sIGxvb3BfaW5kZXg6IGxvb3BfaW5kZXgsIFwiZm9yY2UtYnVuZGxlXCI6IHRydWUsIFwiZm9yY2UtcnRjcC1tdXhcIjogdHJ1ZSB9O1xuICByZXR1cm4gdGhpcy5zZXNzaW9uLnNlbmQoXCJhdHRhY2hcIiwgcGF5bG9hZCkudGhlbihyZXNwID0+IHtcbiAgICB0aGlzLmlkID0gcmVzcC5kYXRhLmlkO1xuICAgIHJldHVybiByZXNwO1xuICB9KTtcbn07XG5cbi8qKiBEZXRhY2hlcyB0aGlzIGhhbmRsZS4gKiovXG5KYW51c1BsdWdpbkhhbmRsZS5wcm90b3R5cGUuZGV0YWNoID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJkZXRhY2hcIik7XG59O1xuXG4vKiogUmVnaXN0ZXJzIGEgY2FsbGJhY2sgdG8gYmUgZmlyZWQgdXBvbiB0aGUgcmVjZXB0aW9uIG9mIGFueSBpbmNvbWluZyBKYW51cyBzaWduYWxzIGZvciB0aGlzIHBsdWdpbiBoYW5kbGUgd2l0aCB0aGVcbiAqIGBqYW51c2AgYXR0cmlidXRlIGVxdWFsIHRvIGBldmAuXG4gKiovXG5KYW51c1BsdWdpbkhhbmRsZS5wcm90b3R5cGUub24gPSBmdW5jdGlvbihldiwgY2FsbGJhY2spIHtcbiAgcmV0dXJuIHRoaXMuc2Vzc2lvbi5vbihldiwgc2lnbmFsID0+IHtcbiAgICBpZiAoc2lnbmFsLnNlbmRlciA9PSB0aGlzLmlkKSB7XG4gICAgICBjYWxsYmFjayhzaWduYWwpO1xuICAgIH1cbiAgfSk7XG59O1xuXG4vKipcbiAqIFNlbmRzIGEgc2lnbmFsIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGhhbmRsZS4gU2lnbmFscyBzaG91bGQgYmUgSlNPTi1zZXJpYWxpemFibGUgb2JqZWN0cy4gUmV0dXJucyBhIHByb21pc2UgdGhhdCB3aWxsXG4gKiBiZSByZXNvbHZlZCBvciByZWplY3RlZCB3aGVuIGEgcmVzcG9uc2UgdG8gdGhpcyBzaWduYWwgaXMgcmVjZWl2ZWQsIG9yIHdoZW4gbm8gcmVzcG9uc2UgaXMgcmVjZWl2ZWQgd2l0aGluIHRoZVxuICogc2Vzc2lvbiB0aW1lb3V0LlxuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbih0eXBlLCBzaWduYWwpIHtcbiAgcmV0dXJuIHRoaXMuc2Vzc2lvbi5zZW5kKHR5cGUsIE9iamVjdC5hc3NpZ24oeyBoYW5kbGVfaWQ6IHRoaXMuaWQgfSwgc2lnbmFsKSk7XG59O1xuXG4vKiogU2VuZHMgYSBwbHVnaW4tc3BlY2lmaWMgbWVzc2FnZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBoYW5kbGUuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmRNZXNzYWdlID0gZnVuY3Rpb24oYm9keSkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwibWVzc2FnZVwiLCB7IGJvZHk6IGJvZHkgfSk7XG59O1xuXG4vKiogU2VuZHMgYSBKU0VQIG9mZmVyIG9yIGFuc3dlciBhc3NvY2lhdGVkIHdpdGggdGhpcyBoYW5kbGUuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmRKc2VwID0gZnVuY3Rpb24oanNlcCkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwibWVzc2FnZVwiLCB7IGJvZHk6IHt9LCBqc2VwOiBqc2VwIH0pO1xufTtcblxuLyoqIFNlbmRzIGFuIElDRSB0cmlja2xlIGNhbmRpZGF0ZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBoYW5kbGUuICoqL1xuSmFudXNQbHVnaW5IYW5kbGUucHJvdG90eXBlLnNlbmRUcmlja2xlID0gZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJ0cmlja2xlXCIsIHsgY2FuZGlkYXRlOiBjYW5kaWRhdGUgfSk7XG59O1xuXG4vKipcbiAqIFJlcHJlc2VudHMgYSBKYW51cyBzZXNzaW9uIC0tIGEgSmFudXMgY29udGV4dCBmcm9tIHdpdGhpbiB3aGljaCB5b3UgY2FuIG9wZW4gbXVsdGlwbGUgaGFuZGxlcyBhbmQgY29ubmVjdGlvbnMuIE9uY2VcbiAqIGNyZWF0ZWQsIHRoaXMgc2Vzc2lvbiB3aWxsIGJlIGdpdmVuIGEgdW5pcXVlIElEIHdoaWNoIHNob3VsZCBiZSB1c2VkIHRvIGFzc29jaWF0ZSBpdCB3aXRoIGZ1dHVyZSBzaWduYWxsaW5nIG1lc3NhZ2VzLlxuICpcbiAqIFNlZSBodHRwczovL2phbnVzLmNvbmYubWVldGVjaG8uY29tL2RvY3MvcmVzdC5odG1sI3Nlc3Npb25zLlxuICoqL1xuZnVuY3Rpb24gSmFudXNTZXNzaW9uKG91dHB1dCwgb3B0aW9ucykge1xuICB0aGlzLm91dHB1dCA9IG91dHB1dDtcbiAgdGhpcy5pZCA9IHVuZGVmaW5lZDtcbiAgdGhpcy5uZXh0VHhJZCA9IDA7XG4gIHRoaXMudHhucyA9IHt9O1xuICB0aGlzLmV2ZW50SGFuZGxlcnMgPSB7fTtcbiAgdGhpcy5vcHRpb25zID0gT2JqZWN0LmFzc2lnbih7XG4gICAgdmVyYm9zZTogZmFsc2UsXG4gICAgdGltZW91dE1zOiAxMDAwMCxcbiAgICBrZWVwYWxpdmVNczogMzAwMDBcbiAgfSwgb3B0aW9ucyk7XG59XG5cbi8qKiBDcmVhdGVzIHRoaXMgc2Vzc2lvbiBvbiB0aGUgSmFudXMgc2VydmVyIGFuZCBzZXRzIGl0cyBJRC4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLmNyZWF0ZSA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwiY3JlYXRlXCIpLnRoZW4ocmVzcCA9PiB7XG4gICAgdGhpcy5pZCA9IHJlc3AuZGF0YS5pZDtcbiAgICByZXR1cm4gcmVzcDtcbiAgfSk7XG59O1xuXG4vKipcbiAqIERlc3Ryb3lzIHRoaXMgc2Vzc2lvbi4gTm90ZSB0aGF0IHVwb24gZGVzdHJ1Y3Rpb24sIEphbnVzIHdpbGwgYWxzbyBjbG9zZSB0aGUgc2lnbmFsbGluZyB0cmFuc3BvcnQgKGlmIGFwcGxpY2FibGUpIGFuZFxuICogYW55IG9wZW4gV2ViUlRDIGNvbm5lY3Rpb25zLlxuICoqL1xuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLnNlbmQoXCJkZXN0cm95XCIpLnRoZW4oKHJlc3ApID0+IHtcbiAgICB0aGlzLmRpc3Bvc2UoKTtcbiAgICByZXR1cm4gcmVzcDtcbiAgfSk7XG59O1xuXG4vKipcbiAqIERpc3Bvc2VzIG9mIHRoaXMgc2Vzc2lvbiBpbiBhIHdheSBzdWNoIHRoYXQgbm8gZnVydGhlciBpbmNvbWluZyBzaWduYWxsaW5nIG1lc3NhZ2VzIHdpbGwgYmUgcHJvY2Vzc2VkLlxuICogT3V0c3RhbmRpbmcgdHJhbnNhY3Rpb25zIHdpbGwgYmUgcmVqZWN0ZWQuXG4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLmRpc3Bvc2UgPSBmdW5jdGlvbigpIHtcbiAgdGhpcy5fa2lsbEtlZXBhbGl2ZSgpO1xuICB0aGlzLmV2ZW50SGFuZGxlcnMgPSB7fTtcbiAgZm9yICh2YXIgdHhJZCBpbiB0aGlzLnR4bnMpIHtcbiAgICBpZiAodGhpcy50eG5zLmhhc093blByb3BlcnR5KHR4SWQpKSB7XG4gICAgICB2YXIgdHhuID0gdGhpcy50eG5zW3R4SWRdO1xuICAgICAgY2xlYXJUaW1lb3V0KHR4bi50aW1lb3V0KTtcbiAgICAgIHR4bi5yZWplY3QobmV3IEVycm9yKFwiSmFudXMgc2Vzc2lvbiB3YXMgZGlzcG9zZWQuXCIpKTtcbiAgICAgIGRlbGV0ZSB0aGlzLnR4bnNbdHhJZF07XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIFdoZXRoZXIgdGhpcyBzaWduYWwgcmVwcmVzZW50cyBhbiBlcnJvciwgYW5kIHRoZSBhc3NvY2lhdGVkIHByb21pc2UgKGlmIGFueSkgc2hvdWxkIGJlIHJlamVjdGVkLlxuICogVXNlcnMgc2hvdWxkIG92ZXJyaWRlIHRoaXMgdG8gaGFuZGxlIGFueSBjdXN0b20gcGx1Z2luLXNwZWNpZmljIGVycm9yIGNvbnZlbnRpb25zLlxuICoqL1xuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5pc0Vycm9yID0gZnVuY3Rpb24oc2lnbmFsKSB7XG4gIHJldHVybiBzaWduYWwuamFudXMgPT09IFwiZXJyb3JcIjtcbn07XG5cbi8qKiBSZWdpc3RlcnMgYSBjYWxsYmFjayB0byBiZSBmaXJlZCB1cG9uIHRoZSByZWNlcHRpb24gb2YgYW55IGluY29taW5nIEphbnVzIHNpZ25hbHMgZm9yIHRoaXMgc2Vzc2lvbiB3aXRoIHRoZVxuICogYGphbnVzYCBhdHRyaWJ1dGUgZXF1YWwgdG8gYGV2YC5cbiAqKi9cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUub24gPSBmdW5jdGlvbihldiwgY2FsbGJhY2spIHtcbiAgdmFyIGhhbmRsZXJzID0gdGhpcy5ldmVudEhhbmRsZXJzW2V2XTtcbiAgaWYgKGhhbmRsZXJzID09IG51bGwpIHtcbiAgICBoYW5kbGVycyA9IHRoaXMuZXZlbnRIYW5kbGVyc1tldl0gPSBbXTtcbiAgfVxuICBoYW5kbGVycy5wdXNoKGNhbGxiYWNrKTtcbn07XG5cbi8qKlxuICogQ2FsbGJhY2sgZm9yIHJlY2VpdmluZyBKU09OIHNpZ25hbGxpbmcgbWVzc2FnZXMgcGVydGluZW50IHRvIHRoaXMgc2Vzc2lvbi4gSWYgdGhlIHNpZ25hbHMgYXJlIHJlc3BvbnNlcyB0byBwcmV2aW91c2x5XG4gKiBzZW50IHNpZ25hbHMsIHRoZSBwcm9taXNlcyBmb3IgdGhlIG91dGdvaW5nIHNpZ25hbHMgd2lsbCBiZSByZXNvbHZlZCBvciByZWplY3RlZCBhcHByb3ByaWF0ZWx5IHdpdGggdGhpcyBzaWduYWwgYXMgYW5cbiAqIGFyZ3VtZW50LlxuICpcbiAqIEV4dGVybmFsIGNhbGxlcnMgc2hvdWxkIGNhbGwgdGhpcyBmdW5jdGlvbiBldmVyeSB0aW1lIGEgbmV3IHNpZ25hbCBhcnJpdmVzIG9uIHRoZSB0cmFuc3BvcnQ7IGZvciBleGFtcGxlLCBpbiBhXG4gKiBXZWJTb2NrZXQncyBgbWVzc2FnZWAgZXZlbnQsIG9yIHdoZW4gYSBuZXcgZGF0dW0gc2hvd3MgdXAgaW4gYW4gSFRUUCBsb25nLXBvbGxpbmcgcmVzcG9uc2UuXG4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLnJlY2VpdmUgPSBmdW5jdGlvbihzaWduYWwpIHtcbiAgaWYgKHRoaXMub3B0aW9ucy52ZXJib3NlKSB7XG4gICAgdGhpcy5fbG9nSW5jb21pbmcoc2lnbmFsKTtcbiAgfVxuICBpZiAoc2lnbmFsLnNlc3Npb25faWQgIT0gdGhpcy5pZCkge1xuICAgIGNvbnNvbGUud2FybihcIkluY29ycmVjdCBzZXNzaW9uIElEIHJlY2VpdmVkIGluIEphbnVzIHNpZ25hbGxpbmcgbWVzc2FnZTogd2FzIFwiICsgc2lnbmFsLnNlc3Npb25faWQgKyBcIiwgZXhwZWN0ZWQgXCIgKyB0aGlzLmlkICsgXCIuXCIpO1xuICB9XG5cbiAgdmFyIHJlc3BvbnNlVHlwZSA9IHNpZ25hbC5qYW51cztcbiAgdmFyIGhhbmRsZXJzID0gdGhpcy5ldmVudEhhbmRsZXJzW3Jlc3BvbnNlVHlwZV07XG4gIGlmIChoYW5kbGVycyAhPSBudWxsKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoYW5kbGVycy5sZW5ndGg7IGkrKykge1xuICAgICAgaGFuZGxlcnNbaV0oc2lnbmFsKTtcbiAgICB9XG4gIH1cblxuICBpZiAoc2lnbmFsLnRyYW5zYWN0aW9uICE9IG51bGwpIHtcbiAgICB2YXIgdHhuID0gdGhpcy50eG5zW3NpZ25hbC50cmFuc2FjdGlvbl07XG4gICAgaWYgKHR4biA9PSBudWxsKSB7XG4gICAgICAvLyB0aGlzIGlzIGEgcmVzcG9uc2UgdG8gYSB0cmFuc2FjdGlvbiB0aGF0IHdhc24ndCBjYXVzZWQgdmlhIEphbnVzU2Vzc2lvbi5zZW5kLCBvciBhIHBsdWdpbiByZXBsaWVkIHR3aWNlIHRvIGFcbiAgICAgIC8vIHNpbmdsZSByZXF1ZXN0LCBvciB0aGUgc2Vzc2lvbiB3YXMgZGlzcG9zZWQsIG9yIHNvbWV0aGluZyBlbHNlIHRoYXQgaXNuJ3QgdW5kZXIgb3VyIHB1cnZpZXc7IHRoYXQncyBmaW5lXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHJlc3BvbnNlVHlwZSA9PT0gXCJhY2tcIiAmJiB0eG4udHlwZSA9PSBcIm1lc3NhZ2VcIikge1xuICAgICAgLy8gdGhpcyBpcyBhbiBhY2sgb2YgYW4gYXN5bmNocm9ub3VzbHktcHJvY2Vzc2VkIHBsdWdpbiByZXF1ZXN0LCB3ZSBzaG91bGQgd2FpdCB0byByZXNvbHZlIHRoZSBwcm9taXNlIHVudGlsIHRoZVxuICAgICAgLy8gYWN0dWFsIHJlc3BvbnNlIGNvbWVzIGluXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY2xlYXJUaW1lb3V0KHR4bi50aW1lb3V0KTtcblxuICAgIGRlbGV0ZSB0aGlzLnR4bnNbc2lnbmFsLnRyYW5zYWN0aW9uXTtcbiAgICAodGhpcy5pc0Vycm9yKHNpZ25hbCkgPyB0eG4ucmVqZWN0IDogdHhuLnJlc29sdmUpKHNpZ25hbCk7XG4gIH1cbn07XG5cbi8qKlxuICogU2VuZHMgYSBzaWduYWwgYXNzb2NpYXRlZCB3aXRoIHRoaXMgc2Vzc2lvbiwgYmVnaW5uaW5nIGEgbmV3IHRyYW5zYWN0aW9uLiBSZXR1cm5zIGEgcHJvbWlzZSB0aGF0IHdpbGwgYmUgcmVzb2x2ZWQgb3JcbiAqIHJlamVjdGVkIHdoZW4gYSByZXNwb25zZSBpcyByZWNlaXZlZCBpbiB0aGUgc2FtZSB0cmFuc2FjdGlvbiwgb3Igd2hlbiBubyByZXNwb25zZSBpcyByZWNlaXZlZCB3aXRoaW4gdGhlIHNlc3Npb25cbiAqIHRpbWVvdXQuXG4gKiovXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbih0eXBlLCBzaWduYWwpIHtcbiAgc2lnbmFsID0gT2JqZWN0LmFzc2lnbih7IHRyYW5zYWN0aW9uOiAodGhpcy5uZXh0VHhJZCsrKS50b1N0cmluZygpIH0sIHNpZ25hbCk7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgdmFyIHRpbWVvdXQgPSBudWxsO1xuICAgIGlmICh0aGlzLm9wdGlvbnMudGltZW91dE1zKSB7XG4gICAgICB0aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGRlbGV0ZSB0aGlzLnR4bnNbc2lnbmFsLnRyYW5zYWN0aW9uXTtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihcIlNpZ25hbGxpbmcgdHJhbnNhY3Rpb24gd2l0aCB0eGlkIFwiICsgc2lnbmFsLnRyYW5zYWN0aW9uICsgXCIgdGltZWQgb3V0LlwiKSk7XG4gICAgICB9LCB0aGlzLm9wdGlvbnMudGltZW91dE1zKTtcbiAgICB9XG4gICAgdGhpcy50eG5zW3NpZ25hbC50cmFuc2FjdGlvbl0gPSB7IHJlc29sdmU6IHJlc29sdmUsIHJlamVjdDogcmVqZWN0LCB0aW1lb3V0OiB0aW1lb3V0LCB0eXBlOiB0eXBlIH07XG4gICAgdGhpcy5fdHJhbnNtaXQodHlwZSwgc2lnbmFsKTtcbiAgfSk7XG59O1xuXG5KYW51c1Nlc3Npb24ucHJvdG90eXBlLl90cmFuc21pdCA9IGZ1bmN0aW9uKHR5cGUsIHNpZ25hbCkge1xuICBzaWduYWwgPSBPYmplY3QuYXNzaWduKHsgamFudXM6IHR5cGUgfSwgc2lnbmFsKTtcblxuICBpZiAodGhpcy5pZCAhPSBudWxsKSB7IC8vIHRoaXMuaWQgaXMgdW5kZWZpbmVkIGluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlbiB3ZSdyZSBzZW5kaW5nIHRoZSBzZXNzaW9uIGNyZWF0ZSBtZXNzYWdlXG4gICAgc2lnbmFsID0gT2JqZWN0LmFzc2lnbih7IHNlc3Npb25faWQ6IHRoaXMuaWQgfSwgc2lnbmFsKTtcbiAgfVxuXG4gIGlmICh0aGlzLm9wdGlvbnMudmVyYm9zZSkge1xuICAgIHRoaXMuX2xvZ091dGdvaW5nKHNpZ25hbCk7XG4gIH1cblxuICB0aGlzLm91dHB1dChKU09OLnN0cmluZ2lmeShzaWduYWwpKTtcbiAgdGhpcy5fcmVzZXRLZWVwYWxpdmUoKTtcbn07XG5cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuX2xvZ091dGdvaW5nID0gZnVuY3Rpb24oc2lnbmFsKSB7XG4gIHZhciBraW5kID0gc2lnbmFsLmphbnVzO1xuICBpZiAoa2luZCA9PT0gXCJtZXNzYWdlXCIgJiYgc2lnbmFsLmpzZXApIHtcbiAgICBraW5kID0gc2lnbmFsLmpzZXAudHlwZTtcbiAgfVxuICB2YXIgbWVzc2FnZSA9IFwiPiBPdXRnb2luZyBKYW51cyBcIiArIChraW5kIHx8IFwic2lnbmFsXCIpICsgXCIgKCNcIiArIHNpZ25hbC50cmFuc2FjdGlvbiArIFwiKTogXCI7XG4gIGNvbnNvbGUuZGVidWcoXCIlY1wiICsgbWVzc2FnZSwgXCJjb2xvcjogIzA0MFwiLCBzaWduYWwpO1xufTtcblxuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5fbG9nSW5jb21pbmcgPSBmdW5jdGlvbihzaWduYWwpIHtcbiAgdmFyIGtpbmQgPSBzaWduYWwuamFudXM7XG4gIHZhciBtZXNzYWdlID0gc2lnbmFsLnRyYW5zYWN0aW9uID9cbiAgICAgIFwiPCBJbmNvbWluZyBKYW51cyBcIiArIChraW5kIHx8IFwic2lnbmFsXCIpICsgXCIgKCNcIiArIHNpZ25hbC50cmFuc2FjdGlvbiArIFwiKTogXCIgOlxuICAgICAgXCI8IEluY29taW5nIEphbnVzIFwiICsgKGtpbmQgfHwgXCJzaWduYWxcIikgKyBcIjogXCI7XG4gIGNvbnNvbGUuZGVidWcoXCIlY1wiICsgbWVzc2FnZSwgXCJjb2xvcjogIzAwNFwiLCBzaWduYWwpO1xufTtcblxuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5fc2VuZEtlZXBhbGl2ZSA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gdGhpcy5zZW5kKFwia2VlcGFsaXZlXCIpO1xufTtcblxuSmFudXNTZXNzaW9uLnByb3RvdHlwZS5fa2lsbEtlZXBhbGl2ZSA9IGZ1bmN0aW9uKCkge1xuICBjbGVhclRpbWVvdXQodGhpcy5rZWVwYWxpdmVUaW1lb3V0KTtcbn07XG5cbkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuX3Jlc2V0S2VlcGFsaXZlID0gZnVuY3Rpb24oKSB7XG4gIHRoaXMuX2tpbGxLZWVwYWxpdmUoKTtcbiAgaWYgKHRoaXMub3B0aW9ucy5rZWVwYWxpdmVNcykge1xuICAgIHRoaXMua2VlcGFsaXZlVGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5fc2VuZEtlZXBhbGl2ZSgpLmNhdGNoKGUgPT4gY29uc29sZS5lcnJvcihcIkVycm9yIHJlY2VpdmVkIGZyb20ga2VlcGFsaXZlOiBcIiwgZSkpO1xuICAgIH0sIHRoaXMub3B0aW9ucy5rZWVwYWxpdmVNcyk7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBKYW51c1BsdWdpbkhhbmRsZSxcbiAgSmFudXNTZXNzaW9uXG59O1xuIiwiLyogZ2xvYmFsIE5BRiAqL1xudmFyIG1qID0gcmVxdWlyZShcIkBuZXR3b3JrZWQtYWZyYW1lL21pbmlqYW51c1wiKTtcbm1qLkphbnVzU2Vzc2lvbi5wcm90b3R5cGUuc2VuZE9yaWdpbmFsID0gbWouSmFudXNTZXNzaW9uLnByb3RvdHlwZS5zZW5kO1xubWouSmFudXNTZXNzaW9uLnByb3RvdHlwZS5zZW5kID0gZnVuY3Rpb24odHlwZSwgc2lnbmFsKSB7XG4gIHJldHVybiB0aGlzLnNlbmRPcmlnaW5hbCh0eXBlLCBzaWduYWwpLmNhdGNoKChlKSA9PiB7XG4gICAgaWYgKGUubWVzc2FnZSAmJiBlLm1lc3NhZ2UuaW5kZXhPZihcInRpbWVkIG91dFwiKSA+IC0xKSB7XG4gICAgICBjb25zb2xlLmVycm9yKFwid2ViIHNvY2tldCB0aW1lZCBvdXRcIik7XG4gICAgICBOQUYuY29ubmVjdGlvbi5hZGFwdGVyLnJlY29ubmVjdCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyhlKTtcbiAgICB9XG4gIH0pO1xufVxuXG52YXIgc2RwVXRpbHMgPSByZXF1aXJlKFwic2RwXCIpO1xudmFyIGRlYnVnID0gcmVxdWlyZShcImRlYnVnXCIpKFwibmFmLWphbnVzLWFkYXB0ZXI6ZGVidWdcIik7XG52YXIgd2FybiA9IHJlcXVpcmUoXCJkZWJ1Z1wiKShcIm5hZi1qYW51cy1hZGFwdGVyOndhcm5cIik7XG52YXIgZXJyb3IgPSByZXF1aXJlKFwiZGVidWdcIikoXCJuYWYtamFudXMtYWRhcHRlcjplcnJvclwiKTtcbnZhciBpc1NhZmFyaSA9IC9eKCg/IWNocm9tZXxhbmRyb2lkKS4pKnNhZmFyaS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCk7XG5cbmNvbnN0IFNVQlNDUklCRV9USU1FT1VUX01TID0gMTUwMDA7XG5cbmNvbnN0IEFWQUlMQUJMRV9PQ0NVUEFOVFNfVEhSRVNIT0xEID0gNTtcbmNvbnN0IE1BWF9TVUJTQ1JJQkVfREVMQVkgPSA1MDAwO1xuXG5mdW5jdGlvbiByYW5kb21EZWxheShtaW4sIG1heCkge1xuICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgY29uc3QgZGVsYXkgPSBNYXRoLnJhbmRvbSgpICogKG1heCAtIG1pbikgKyBtaW47XG4gICAgc2V0VGltZW91dChyZXNvbHZlLCBkZWxheSk7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkZWJvdW5jZShmbikge1xuICB2YXIgY3VyciA9IFByb21pc2UucmVzb2x2ZSgpO1xuICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgIGN1cnIgPSBjdXJyLnRoZW4oXyA9PiBmbi5hcHBseSh0aGlzLCBhcmdzKSk7XG4gIH07XG59XG5cbmZ1bmN0aW9uIHJhbmRvbVVpbnQoKSB7XG4gIHJldHVybiBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUik7XG59XG5cbmZ1bmN0aW9uIHVudGlsRGF0YUNoYW5uZWxPcGVuKGRhdGFDaGFubmVsKSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgaWYgKGRhdGFDaGFubmVsLnJlYWR5U3RhdGUgPT09IFwib3BlblwiKSB7XG4gICAgICByZXNvbHZlKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCByZXNvbHZlciwgcmVqZWN0b3I7XG5cbiAgICAgIGNvbnN0IGNsZWFyID0gKCkgPT4ge1xuICAgICAgICBkYXRhQ2hhbm5lbC5yZW1vdmVFdmVudExpc3RlbmVyKFwib3BlblwiLCByZXNvbHZlcik7XG4gICAgICAgIGRhdGFDaGFubmVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJlcnJvclwiLCByZWplY3Rvcik7XG4gICAgICB9O1xuXG4gICAgICByZXNvbHZlciA9ICgpID0+IHtcbiAgICAgICAgY2xlYXIoKTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfTtcbiAgICAgIHJlamVjdG9yID0gKCkgPT4ge1xuICAgICAgICBjbGVhcigpO1xuICAgICAgICByZWplY3QoKTtcbiAgICAgIH07XG5cbiAgICAgIGRhdGFDaGFubmVsLmFkZEV2ZW50TGlzdGVuZXIoXCJvcGVuXCIsIHJlc29sdmVyKTtcbiAgICAgIGRhdGFDaGFubmVsLmFkZEV2ZW50TGlzdGVuZXIoXCJlcnJvclwiLCByZWplY3Rvcik7XG4gICAgfVxuICB9KTtcbn1cblxuY29uc3QgaXNIMjY0VmlkZW9TdXBwb3J0ZWQgPSAoKCkgPT4ge1xuICBjb25zdCB2aWRlbyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJ2aWRlb1wiKTtcbiAgcmV0dXJuIHZpZGVvLmNhblBsYXlUeXBlKCd2aWRlby9tcDQ7IGNvZGVjcz1cImF2YzEuNDJFMDFFLCBtcDRhLjQwLjJcIicpICE9PSBcIlwiO1xufSkoKTtcblxuY29uc3QgT1BVU19QQVJBTUVURVJTID0ge1xuICAvLyBpbmRpY2F0ZXMgdGhhdCB3ZSB3YW50IHRvIGVuYWJsZSBEVFggdG8gZWxpZGUgc2lsZW5jZSBwYWNrZXRzXG4gIHVzZWR0eDogMSxcbiAgLy8gaW5kaWNhdGVzIHRoYXQgd2UgcHJlZmVyIHRvIHJlY2VpdmUgbW9ubyBhdWRpbyAoaW1wb3J0YW50IGZvciB2b2lwIHByb2ZpbGUpXG4gIHN0ZXJlbzogMCxcbiAgLy8gaW5kaWNhdGVzIHRoYXQgd2UgcHJlZmVyIHRvIHNlbmQgbW9ubyBhdWRpbyAoaW1wb3J0YW50IGZvciB2b2lwIHByb2ZpbGUpXG4gIFwic3Byb3Atc3RlcmVvXCI6IDBcbn07XG5cbmNvbnN0IERFRkFVTFRfUEVFUl9DT05ORUNUSU9OX0NPTkZJRyA9IHtcbiAgaWNlU2VydmVyczogW3sgdXJsczogXCJzdHVuOnN0dW4xLmwuZ29vZ2xlLmNvbToxOTMwMlwiIH0sIHsgdXJsczogXCJzdHVuOnN0dW4yLmwuZ29vZ2xlLmNvbToxOTMwMlwiIH1dXG59O1xuXG5jb25zdCBXU19OT1JNQUxfQ0xPU1VSRSA9IDEwMDA7XG5cbmNsYXNzIEphbnVzQWRhcHRlciB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMucm9vbSA9IG51bGw7XG4gICAgLy8gV2UgZXhwZWN0IHRoZSBjb25zdW1lciB0byBzZXQgYSBjbGllbnQgaWQgYmVmb3JlIGNvbm5lY3RpbmcuXG4gICAgdGhpcy5jbGllbnRJZCA9IG51bGw7XG4gICAgdGhpcy5qb2luVG9rZW4gPSBudWxsO1xuXG4gICAgdGhpcy5zZXJ2ZXJVcmwgPSBudWxsO1xuICAgIHRoaXMud2ViUnRjT3B0aW9ucyA9IHt9O1xuICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db25maWcgPSBudWxsO1xuICAgIHRoaXMud3MgPSBudWxsO1xuICAgIHRoaXMuc2Vzc2lvbiA9IG51bGw7XG4gICAgdGhpcy5yZWxpYWJsZVRyYW5zcG9ydCA9IFwiZGF0YWNoYW5uZWxcIjtcbiAgICB0aGlzLnVucmVsaWFibGVUcmFuc3BvcnQgPSBcImRhdGFjaGFubmVsXCI7XG5cbiAgICAvLyBJbiB0aGUgZXZlbnQgdGhlIHNlcnZlciByZXN0YXJ0cyBhbmQgYWxsIGNsaWVudHMgbG9zZSBjb25uZWN0aW9uLCByZWNvbm5lY3Qgd2l0aFxuICAgIC8vIHNvbWUgcmFuZG9tIGppdHRlciBhZGRlZCB0byBwcmV2ZW50IHNpbXVsdGFuZW91cyByZWNvbm5lY3Rpb24gcmVxdWVzdHMuXG4gICAgdGhpcy5pbml0aWFsUmVjb25uZWN0aW9uRGVsYXkgPSAxMDAwICogTWF0aC5yYW5kb20oKTtcbiAgICB0aGlzLnJlY29ubmVjdGlvbkRlbGF5ID0gdGhpcy5pbml0aWFsUmVjb25uZWN0aW9uRGVsYXk7XG4gICAgdGhpcy5yZWNvbm5lY3Rpb25UaW1lb3V0ID0gbnVsbDtcbiAgICB0aGlzLm1heFJlY29ubmVjdGlvbkF0dGVtcHRzID0gMTA7XG4gICAgdGhpcy5yZWNvbm5lY3Rpb25BdHRlbXB0cyA9IDA7XG5cbiAgICB0aGlzLnB1Ymxpc2hlciA9IG51bGw7XG4gICAgdGhpcy5vY2N1cGFudElkcyA9IFtdO1xuICAgIHRoaXMub2NjdXBhbnRzID0ge307XG4gICAgdGhpcy5tZWRpYVN0cmVhbXMgPSB7fTtcbiAgICB0aGlzLmxvY2FsTWVkaWFTdHJlYW0gPSBudWxsO1xuICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMgPSBuZXcgTWFwKCk7XG5cbiAgICB0aGlzLnBlbmRpbmdPY2N1cGFudHMgPSBuZXcgU2V0KCk7XG4gICAgdGhpcy5hdmFpbGFibGVPY2N1cGFudHMgPSBbXTtcbiAgICB0aGlzLnJlcXVlc3RlZE9jY3VwYW50cyA9IG51bGw7XG5cbiAgICB0aGlzLmJsb2NrZWRDbGllbnRzID0gbmV3IE1hcCgpO1xuICAgIHRoaXMuZnJvemVuVXBkYXRlcyA9IG5ldyBNYXAoKTtcblxuICAgIHRoaXMudGltZU9mZnNldHMgPSBbXTtcbiAgICB0aGlzLnNlcnZlclRpbWVSZXF1ZXN0cyA9IDA7XG4gICAgdGhpcy5hdmdUaW1lT2Zmc2V0ID0gMDtcblxuICAgIHRoaXMub25XZWJzb2NrZXRPcGVuID0gdGhpcy5vbldlYnNvY2tldE9wZW4uYmluZCh0aGlzKTtcbiAgICB0aGlzLm9uV2Vic29ja2V0Q2xvc2UgPSB0aGlzLm9uV2Vic29ja2V0Q2xvc2UuYmluZCh0aGlzKTtcbiAgICB0aGlzLm9uV2Vic29ja2V0TWVzc2FnZSA9IHRoaXMub25XZWJzb2NrZXRNZXNzYWdlLmJpbmQodGhpcyk7XG4gICAgdGhpcy5vbkRhdGFDaGFubmVsTWVzc2FnZSA9IHRoaXMub25EYXRhQ2hhbm5lbE1lc3NhZ2UuYmluZCh0aGlzKTtcbiAgICB0aGlzLm9uRGF0YSA9IHRoaXMub25EYXRhLmJpbmQodGhpcyk7XG4gIH1cblxuICBzZXRTZXJ2ZXJVcmwodXJsKSB7XG4gICAgdGhpcy5zZXJ2ZXJVcmwgPSB1cmw7XG4gIH1cblxuICBzZXRBcHAoYXBwKSB7fVxuXG4gIHNldFJvb20ocm9vbU5hbWUpIHtcbiAgICB0aGlzLnJvb20gPSByb29tTmFtZTtcbiAgfVxuXG4gIHNldEpvaW5Ub2tlbihqb2luVG9rZW4pIHtcbiAgICB0aGlzLmpvaW5Ub2tlbiA9IGpvaW5Ub2tlbjtcbiAgfVxuXG4gIHNldENsaWVudElkKGNsaWVudElkKSB7XG4gICAgdGhpcy5jbGllbnRJZCA9IGNsaWVudElkO1xuICB9XG5cbiAgc2V0V2ViUnRjT3B0aW9ucyhvcHRpb25zKSB7XG4gICAgdGhpcy53ZWJSdGNPcHRpb25zID0gb3B0aW9ucztcbiAgfVxuXG4gIHNldFBlZXJDb25uZWN0aW9uQ29uZmlnKHBlZXJDb25uZWN0aW9uQ29uZmlnKSB7XG4gICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbmZpZyA9IHBlZXJDb25uZWN0aW9uQ29uZmlnO1xuICB9XG5cbiAgc2V0U2VydmVyQ29ubmVjdExpc3RlbmVycyhzdWNjZXNzTGlzdGVuZXIsIGZhaWx1cmVMaXN0ZW5lcikge1xuICAgIHRoaXMuY29ubmVjdFN1Y2Nlc3MgPSBzdWNjZXNzTGlzdGVuZXI7XG4gICAgdGhpcy5jb25uZWN0RmFpbHVyZSA9IGZhaWx1cmVMaXN0ZW5lcjtcbiAgfVxuXG4gIHNldFJvb21PY2N1cGFudExpc3RlbmVyKG9jY3VwYW50TGlzdGVuZXIpIHtcbiAgICB0aGlzLm9uT2NjdXBhbnRzQ2hhbmdlZCA9IG9jY3VwYW50TGlzdGVuZXI7XG4gIH1cblxuICBzZXREYXRhQ2hhbm5lbExpc3RlbmVycyhvcGVuTGlzdGVuZXIsIGNsb3NlZExpc3RlbmVyLCBtZXNzYWdlTGlzdGVuZXIpIHtcbiAgICB0aGlzLm9uT2NjdXBhbnRDb25uZWN0ZWQgPSBvcGVuTGlzdGVuZXI7XG4gICAgdGhpcy5vbk9jY3VwYW50RGlzY29ubmVjdGVkID0gY2xvc2VkTGlzdGVuZXI7XG4gICAgdGhpcy5vbk9jY3VwYW50TWVzc2FnZSA9IG1lc3NhZ2VMaXN0ZW5lcjtcbiAgfVxuXG4gIHNldFJlY29ubmVjdGlvbkxpc3RlbmVycyhyZWNvbm5lY3RpbmdMaXN0ZW5lciwgcmVjb25uZWN0ZWRMaXN0ZW5lciwgcmVjb25uZWN0aW9uRXJyb3JMaXN0ZW5lcikge1xuICAgIC8vIG9uUmVjb25uZWN0aW5nIGlzIGNhbGxlZCB3aXRoIHRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHVudGlsIHRoZSBuZXh0IHJlY29ubmVjdGlvbiBhdHRlbXB0XG4gICAgdGhpcy5vblJlY29ubmVjdGluZyA9IHJlY29ubmVjdGluZ0xpc3RlbmVyO1xuICAgIC8vIG9uUmVjb25uZWN0ZWQgaXMgY2FsbGVkIHdoZW4gdGhlIGNvbm5lY3Rpb24gaGFzIGJlZW4gcmVlc3RhYmxpc2hlZFxuICAgIHRoaXMub25SZWNvbm5lY3RlZCA9IHJlY29ubmVjdGVkTGlzdGVuZXI7XG4gICAgLy8gb25SZWNvbm5lY3Rpb25FcnJvciBpcyBjYWxsZWQgd2l0aCBhbiBlcnJvciB3aGVuIG1heFJlY29ubmVjdGlvbkF0dGVtcHRzIGhhcyBiZWVuIHJlYWNoZWRcbiAgICB0aGlzLm9uUmVjb25uZWN0aW9uRXJyb3IgPSByZWNvbm5lY3Rpb25FcnJvckxpc3RlbmVyO1xuICB9XG5cbiAgc2V0RXZlbnRMb29wcyhsb29wcykge1xuICAgIHRoaXMubG9vcHMgPSBsb29wcztcbiAgfVxuXG4gIGNvbm5lY3QoKSB7XG4gICAgZGVidWcoYGNvbm5lY3RpbmcgdG8gJHt0aGlzLnNlcnZlclVybH1gKTtcblxuICAgIGNvbnN0IHdlYnNvY2tldENvbm5lY3Rpb24gPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICB0aGlzLndzID0gbmV3IFdlYlNvY2tldCh0aGlzLnNlcnZlclVybCwgXCJqYW51cy1wcm90b2NvbFwiKTtcblxuICAgICAgdGhpcy5zZXNzaW9uID0gbmV3IG1qLkphbnVzU2Vzc2lvbih0aGlzLndzLnNlbmQuYmluZCh0aGlzLndzKSwgeyB0aW1lb3V0TXM6IDQwMDAwIH0pO1xuXG4gICAgICB0aGlzLndzLmFkZEV2ZW50TGlzdGVuZXIoXCJjbG9zZVwiLCB0aGlzLm9uV2Vic29ja2V0Q2xvc2UpO1xuICAgICAgdGhpcy53cy5hZGRFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCB0aGlzLm9uV2Vic29ja2V0TWVzc2FnZSk7XG5cbiAgICAgIHRoaXMud3NPbk9wZW4gPSAoKSA9PiB7XG4gICAgICAgIHRoaXMud3MucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIm9wZW5cIiwgdGhpcy53c09uT3Blbik7XG4gICAgICAgIHRoaXMub25XZWJzb2NrZXRPcGVuKClcbiAgICAgICAgICAudGhlbihyZXNvbHZlKVxuICAgICAgICAgIC5jYXRjaChyZWplY3QpO1xuICAgICAgfTtcblxuICAgICAgdGhpcy53cy5hZGRFdmVudExpc3RlbmVyKFwib3BlblwiLCB0aGlzLndzT25PcGVuKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBQcm9taXNlLmFsbChbd2Vic29ja2V0Q29ubmVjdGlvbiwgdGhpcy51cGRhdGVUaW1lT2Zmc2V0KCldKTtcbiAgfVxuXG4gIGRpc2Nvbm5lY3QoKSB7XG4gICAgZGVidWcoYGRpc2Nvbm5lY3RpbmdgKTtcblxuICAgIGNsZWFyVGltZW91dCh0aGlzLnJlY29ubmVjdGlvblRpbWVvdXQpO1xuXG4gICAgdGhpcy5yZW1vdmVBbGxPY2N1cGFudHMoKTtcblxuICAgIGlmICh0aGlzLnB1Ymxpc2hlcikge1xuICAgICAgLy8gQ2xvc2UgdGhlIHB1Ymxpc2hlciBwZWVyIGNvbm5lY3Rpb24uIFdoaWNoIGFsc28gZGV0YWNoZXMgdGhlIHBsdWdpbiBoYW5kbGUuXG4gICAgICB0aGlzLnB1Ymxpc2hlci5jb25uLmNsb3NlKCk7XG4gICAgICB0aGlzLnB1Ymxpc2hlciA9IG51bGw7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuc2Vzc2lvbikge1xuICAgICAgdGhpcy5zZXNzaW9uLmRpc3Bvc2UoKTtcbiAgICAgIHRoaXMuc2Vzc2lvbiA9IG51bGw7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMud3MpIHtcbiAgICAgIHRoaXMud3MucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIm9wZW5cIiwgdGhpcy53c09uT3Blbik7XG4gICAgICB0aGlzLndzLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJjbG9zZVwiLCB0aGlzLm9uV2Vic29ja2V0Q2xvc2UpO1xuICAgICAgdGhpcy53cy5yZW1vdmVFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCB0aGlzLm9uV2Vic29ja2V0TWVzc2FnZSk7XG4gICAgICB0aGlzLndzLmNsb3NlKCk7XG4gICAgICB0aGlzLndzID0gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBOb3cgdGhhdCBhbGwgUlRDUGVlckNvbm5lY3Rpb24gY2xvc2VkLCBiZSBzdXJlIHRvIG5vdCBjYWxsXG4gICAgLy8gcmVjb25uZWN0KCkgYWdhaW4gdmlhIHBlcmZvcm1EZWxheWVkUmVjb25uZWN0IGlmIHByZXZpb3VzXG4gICAgLy8gUlRDUGVlckNvbm5lY3Rpb24gd2FzIGluIHRoZSBmYWlsZWQgc3RhdGUuXG4gICAgaWYgKHRoaXMuZGVsYXllZFJlY29ubmVjdFRpbWVvdXQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLmRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0KTtcbiAgICAgIHRoaXMuZGVsYXllZFJlY29ubmVjdFRpbWVvdXQgPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIGlzRGlzY29ubmVjdGVkKCkge1xuICAgIHJldHVybiB0aGlzLndzID09PSBudWxsO1xuICB9XG5cbiAgYXN5bmMgb25XZWJzb2NrZXRPcGVuKCkge1xuICAgIC8vIENyZWF0ZSB0aGUgSmFudXMgU2Vzc2lvblxuICAgIGF3YWl0IHRoaXMuc2Vzc2lvbi5jcmVhdGUoKTtcblxuICAgIC8vIEF0dGFjaCB0aGUgU0ZVIFBsdWdpbiBhbmQgY3JlYXRlIGEgUlRDUGVlckNvbm5lY3Rpb24gZm9yIHRoZSBwdWJsaXNoZXIuXG4gICAgLy8gVGhlIHB1Ymxpc2hlciBzZW5kcyBhdWRpbyBhbmQgb3BlbnMgdHdvIGJpZGlyZWN0aW9uYWwgZGF0YSBjaGFubmVscy5cbiAgICAvLyBPbmUgcmVsaWFibGUgZGF0YWNoYW5uZWwgYW5kIG9uZSB1bnJlbGlhYmxlLlxuICAgIHRoaXMucHVibGlzaGVyID0gYXdhaXQgdGhpcy5jcmVhdGVQdWJsaXNoZXIoKTtcblxuICAgIC8vIENhbGwgdGhlIG5hZiBjb25uZWN0U3VjY2VzcyBjYWxsYmFjayBiZWZvcmUgd2Ugc3RhcnQgcmVjZWl2aW5nIFdlYlJUQyBtZXNzYWdlcy5cbiAgICB0aGlzLmNvbm5lY3RTdWNjZXNzKHRoaXMuY2xpZW50SWQpO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnB1Ymxpc2hlci5pbml0aWFsT2NjdXBhbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBvY2N1cGFudElkID0gdGhpcy5wdWJsaXNoZXIuaW5pdGlhbE9jY3VwYW50c1tpXTtcbiAgICAgIGlmIChvY2N1cGFudElkID09PSB0aGlzLmNsaWVudElkKSBjb250aW51ZTsgLy8gSGFwcGVucyBkdXJpbmcgbm9uLWdyYWNlZnVsIHJlY29ubmVjdHMgZHVlIHRvIHpvbWJpZSBzZXNzaW9uc1xuICAgICAgdGhpcy5hZGRBdmFpbGFibGVPY2N1cGFudChvY2N1cGFudElkKTtcbiAgICB9XG5cbiAgICB0aGlzLnN5bmNPY2N1cGFudHMoKTtcbiAgfVxuXG4gIG9uV2Vic29ja2V0Q2xvc2UoZXZlbnQpIHtcbiAgICAvLyBUaGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkIHN1Y2Nlc3NmdWxseS4gRG9uJ3QgdHJ5IHRvIHJlY29ubmVjdC5cbiAgICBpZiAoZXZlbnQuY29kZSA9PT0gV1NfTk9STUFMX0NMT1NVUkUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zb2xlLndhcm4oXCJKYW51cyB3ZWJzb2NrZXQgY2xvc2VkIHVuZXhwZWN0ZWRseS5cIik7XG4gICAgaWYgKHRoaXMub25SZWNvbm5lY3RpbmcpIHtcbiAgICAgIHRoaXMub25SZWNvbm5lY3RpbmcodGhpcy5yZWNvbm5lY3Rpb25EZWxheSk7XG4gICAgfVxuXG4gICAgdGhpcy5yZWNvbm5lY3Rpb25UaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB0aGlzLnJlY29ubmVjdCgpLCB0aGlzLnJlY29ubmVjdGlvbkRlbGF5KTtcbiAgfVxuXG4gIHJlY29ubmVjdCgpIHtcbiAgICAvLyBEaXNwb3NlIG9mIGFsbCBuZXR3b3JrZWQgZW50aXRpZXMgYW5kIG90aGVyIHJlc291cmNlcyB0aWVkIHRvIHRoZSBzZXNzaW9uLlxuICAgIHRoaXMuZGlzY29ubmVjdCgpO1xuXG4gICAgdGhpcy5jb25uZWN0KClcbiAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgdGhpcy5yZWNvbm5lY3Rpb25EZWxheSA9IHRoaXMuaW5pdGlhbFJlY29ubmVjdGlvbkRlbGF5O1xuICAgICAgICB0aGlzLnJlY29ubmVjdGlvbkF0dGVtcHRzID0gMDtcblxuICAgICAgICBpZiAodGhpcy5vblJlY29ubmVjdGVkKSB7XG4gICAgICAgICAgdGhpcy5vblJlY29ubmVjdGVkKCk7XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICB0aGlzLnJlY29ubmVjdGlvbkRlbGF5ICs9IDEwMDA7XG4gICAgICAgIHRoaXMucmVjb25uZWN0aW9uQXR0ZW1wdHMrKztcblxuICAgICAgICBpZiAodGhpcy5yZWNvbm5lY3Rpb25BdHRlbXB0cyA+IHRoaXMubWF4UmVjb25uZWN0aW9uQXR0ZW1wdHMgJiYgdGhpcy5vblJlY29ubmVjdGlvbkVycm9yKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMub25SZWNvbm5lY3Rpb25FcnJvcihcbiAgICAgICAgICAgIG5ldyBFcnJvcihcIkNvbm5lY3Rpb24gY291bGQgbm90IGJlIHJlZXN0YWJsaXNoZWQsIGV4Y2VlZGVkIG1heGltdW0gbnVtYmVyIG9mIHJlY29ubmVjdGlvbiBhdHRlbXB0cy5cIilcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc29sZS53YXJuKFwiRXJyb3IgZHVyaW5nIHJlY29ubmVjdCwgcmV0cnlpbmcuXCIpO1xuICAgICAgICBjb25zb2xlLndhcm4oZXJyb3IpO1xuXG4gICAgICAgIGlmICh0aGlzLm9uUmVjb25uZWN0aW5nKSB7XG4gICAgICAgICAgdGhpcy5vblJlY29ubmVjdGluZyh0aGlzLnJlY29ubmVjdGlvbkRlbGF5KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVjb25uZWN0aW9uVGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4gdGhpcy5yZWNvbm5lY3QoKSwgdGhpcy5yZWNvbm5lY3Rpb25EZWxheSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHBlcmZvcm1EZWxheWVkUmVjb25uZWN0KCkge1xuICAgIGlmICh0aGlzLmRlbGF5ZWRSZWNvbm5lY3RUaW1lb3V0KSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5kZWxheWVkUmVjb25uZWN0VGltZW91dCk7XG4gICAgfVxuXG4gICAgdGhpcy5kZWxheWVkUmVjb25uZWN0VGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5kZWxheWVkUmVjb25uZWN0VGltZW91dCA9IG51bGw7XG4gICAgICB0aGlzLnJlY29ubmVjdCgpO1xuICAgIH0sIDEwMDAwKTtcbiAgfVxuXG4gIG9uV2Vic29ja2V0TWVzc2FnZShldmVudCkge1xuICAgIHRoaXMuc2Vzc2lvbi5yZWNlaXZlKEpTT04ucGFyc2UoZXZlbnQuZGF0YSkpO1xuICB9XG5cbiAgYWRkQXZhaWxhYmxlT2NjdXBhbnQob2NjdXBhbnRJZCkge1xuICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgdGhpcy5hdmFpbGFibGVPY2N1cGFudHMucHVzaChvY2N1cGFudElkKTtcbiAgICB9XG4gIH1cblxuICByZW1vdmVBdmFpbGFibGVPY2N1cGFudChvY2N1cGFudElkKSB7XG4gICAgY29uc3QgaWR4ID0gdGhpcy5hdmFpbGFibGVPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKTtcbiAgICBpZiAoaWR4ICE9PSAtMSkge1xuICAgICAgdGhpcy5hdmFpbGFibGVPY2N1cGFudHMuc3BsaWNlKGlkeCwgMSk7XG4gICAgfVxuICB9XG5cbiAgc3luY09jY3VwYW50cyhyZXF1ZXN0ZWRPY2N1cGFudHMpIHtcbiAgICBpZiAocmVxdWVzdGVkT2NjdXBhbnRzKSB7XG4gICAgICB0aGlzLnJlcXVlc3RlZE9jY3VwYW50cyA9IHJlcXVlc3RlZE9jY3VwYW50cztcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMucmVxdWVzdGVkT2NjdXBhbnRzKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gQWRkIGFueSByZXF1ZXN0ZWQsIGF2YWlsYWJsZSwgYW5kIG5vbi1wZW5kaW5nIG9jY3VwYW50cy5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMucmVxdWVzdGVkT2NjdXBhbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBvY2N1cGFudElkID0gdGhpcy5yZXF1ZXN0ZWRPY2N1cGFudHNbaV07XG4gICAgICBpZiAoIXRoaXMub2NjdXBhbnRzW29jY3VwYW50SWRdICYmIHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmluZGV4T2Yob2NjdXBhbnRJZCkgIT09IC0xICYmICF0aGlzLnBlbmRpbmdPY2N1cGFudHMuaGFzKG9jY3VwYW50SWQpKSB7XG4gICAgICAgIHRoaXMuYWRkT2NjdXBhbnQob2NjdXBhbnRJZCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmVtb3ZlIGFueSB1bnJlcXVlc3RlZCBhbmQgY3VycmVudGx5IGFkZGVkIG9jY3VwYW50cy5cbiAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMuYXZhaWxhYmxlT2NjdXBhbnRzLmxlbmd0aDsgaisrKSB7XG4gICAgICBjb25zdCBvY2N1cGFudElkID0gdGhpcy5hdmFpbGFibGVPY2N1cGFudHNbal07XG4gICAgICBpZiAodGhpcy5vY2N1cGFudHNbb2NjdXBhbnRJZF0gJiYgdGhpcy5yZXF1ZXN0ZWRPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKSA9PT0gLTEpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVPY2N1cGFudChvY2N1cGFudElkKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDYWxsIHRoZSBOZXR3b3JrZWQgQUZyYW1lIGNhbGxiYWNrcyBmb3IgdGhlIHVwZGF0ZWQgb2NjdXBhbnRzIGxpc3QuXG4gICAgdGhpcy5vbk9jY3VwYW50c0NoYW5nZWQodGhpcy5vY2N1cGFudHMpO1xuICB9XG5cbiAgYXN5bmMgYWRkT2NjdXBhbnQob2NjdXBhbnRJZCkge1xuICAgIHRoaXMucGVuZGluZ09jY3VwYW50cy5hZGQob2NjdXBhbnRJZCk7XG4gICAgXG4gICAgY29uc3QgYXZhaWxhYmxlT2NjdXBhbnRzQ291bnQgPSB0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5sZW5ndGg7XG4gICAgaWYgKGF2YWlsYWJsZU9jY3VwYW50c0NvdW50ID4gQVZBSUxBQkxFX09DQ1VQQU5UU19USFJFU0hPTEQpIHtcbiAgICAgIGF3YWl0IHJhbmRvbURlbGF5KDAsIE1BWF9TVUJTQ1JJQkVfREVMQVkpO1xuICAgIH1cbiAgXG4gICAgY29uc3Qgc3Vic2NyaWJlciA9IGF3YWl0IHRoaXMuY3JlYXRlU3Vic2NyaWJlcihvY2N1cGFudElkKTtcbiAgICBpZiAoc3Vic2NyaWJlcikge1xuICAgICAgaWYoIXRoaXMucGVuZGluZ09jY3VwYW50cy5oYXMob2NjdXBhbnRJZCkpIHtcbiAgICAgICAgc3Vic2NyaWJlci5jb25uLmNsb3NlKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnBlbmRpbmdPY2N1cGFudHMuZGVsZXRlKG9jY3VwYW50SWQpO1xuICAgICAgICB0aGlzLm9jY3VwYW50SWRzLnB1c2gob2NjdXBhbnRJZCk7XG4gICAgICAgIHRoaXMub2NjdXBhbnRzW29jY3VwYW50SWRdID0gc3Vic2NyaWJlcjtcblxuICAgICAgICB0aGlzLnNldE1lZGlhU3RyZWFtKG9jY3VwYW50SWQsIHN1YnNjcmliZXIubWVkaWFTdHJlYW0pO1xuXG4gICAgICAgIC8vIENhbGwgdGhlIE5ldHdvcmtlZCBBRnJhbWUgY2FsbGJhY2tzIGZvciB0aGUgbmV3IG9jY3VwYW50LlxuICAgICAgICB0aGlzLm9uT2NjdXBhbnRDb25uZWN0ZWQob2NjdXBhbnRJZCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmVtb3ZlQWxsT2NjdXBhbnRzKCkge1xuICAgIHRoaXMucGVuZGluZ09jY3VwYW50cy5jbGVhcigpO1xuICAgIGZvciAobGV0IGkgPSB0aGlzLm9jY3VwYW50SWRzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICB0aGlzLnJlbW92ZU9jY3VwYW50KHRoaXMub2NjdXBhbnRJZHNbaV0pO1xuICAgIH1cbiAgfVxuXG4gIHJlbW92ZU9jY3VwYW50KG9jY3VwYW50SWQpIHtcbiAgICB0aGlzLnBlbmRpbmdPY2N1cGFudHMuZGVsZXRlKG9jY3VwYW50SWQpO1xuICAgIFxuICAgIGlmICh0aGlzLm9jY3VwYW50c1tvY2N1cGFudElkXSkge1xuICAgICAgLy8gQ2xvc2UgdGhlIHN1YnNjcmliZXIgcGVlciBjb25uZWN0aW9uLiBXaGljaCBhbHNvIGRldGFjaGVzIHRoZSBwbHVnaW4gaGFuZGxlLlxuICAgICAgdGhpcy5vY2N1cGFudHNbb2NjdXBhbnRJZF0uY29ubi5jbG9zZSgpO1xuICAgICAgZGVsZXRlIHRoaXMub2NjdXBhbnRzW29jY3VwYW50SWRdO1xuICAgICAgXG4gICAgICB0aGlzLm9jY3VwYW50SWRzLnNwbGljZSh0aGlzLm9jY3VwYW50SWRzLmluZGV4T2Yob2NjdXBhbnRJZCksIDEpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLm1lZGlhU3RyZWFtc1tvY2N1cGFudElkXSkge1xuICAgICAgZGVsZXRlIHRoaXMubWVkaWFTdHJlYW1zW29jY3VwYW50SWRdO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmhhcyhvY2N1cGFudElkKSkge1xuICAgICAgY29uc3QgbXNnID0gXCJUaGUgdXNlciBkaXNjb25uZWN0ZWQgYmVmb3JlIHRoZSBtZWRpYSBzdHJlYW0gd2FzIHJlc29sdmVkLlwiO1xuICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5nZXQob2NjdXBhbnRJZCkuYXVkaW8ucmVqZWN0KG1zZyk7XG4gICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChvY2N1cGFudElkKS52aWRlby5yZWplY3QobXNnKTtcbiAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZGVsZXRlKG9jY3VwYW50SWQpO1xuICAgIH1cblxuICAgIC8vIENhbGwgdGhlIE5ldHdvcmtlZCBBRnJhbWUgY2FsbGJhY2tzIGZvciB0aGUgcmVtb3ZlZCBvY2N1cGFudC5cbiAgICB0aGlzLm9uT2NjdXBhbnREaXNjb25uZWN0ZWQob2NjdXBhbnRJZCk7XG4gIH1cblxuICBhc3NvY2lhdGUoY29ubiwgaGFuZGxlKSB7XG4gICAgY29ubi5hZGRFdmVudExpc3RlbmVyKFwiaWNlY2FuZGlkYXRlXCIsIGV2ID0+IHtcbiAgICAgIGhhbmRsZS5zZW5kVHJpY2tsZShldi5jYW5kaWRhdGUgfHwgbnVsbCkuY2F0Y2goZSA9PiBlcnJvcihcIkVycm9yIHRyaWNrbGluZyBJQ0U6ICVvXCIsIGUpKTtcbiAgICB9KTtcbiAgICBjb25uLmFkZEV2ZW50TGlzdGVuZXIoXCJpY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2VcIiwgZXYgPT4ge1xuICAgICAgaWYgKGNvbm4uaWNlQ29ubmVjdGlvblN0YXRlID09PSBcImNvbm5lY3RlZFwiKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiSUNFIHN0YXRlIGNoYW5nZWQgdG8gY29ubmVjdGVkXCIpO1xuICAgICAgfVxuICAgICAgaWYgKGNvbm4uaWNlQ29ubmVjdGlvblN0YXRlID09PSBcImRpc2Nvbm5lY3RlZFwiKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcIklDRSBzdGF0ZSBjaGFuZ2VkIHRvIGRpc2Nvbm5lY3RlZFwiKTtcbiAgICAgIH1cbiAgICAgIGlmIChjb25uLmljZUNvbm5lY3Rpb25TdGF0ZSA9PT0gXCJmYWlsZWRcIikge1xuICAgICAgICBjb25zb2xlLndhcm4oXCJJQ0UgZmFpbHVyZSBkZXRlY3RlZC4gUmVjb25uZWN0aW5nIGluIDEwcy5cIik7XG4gICAgICAgIHRoaXMucGVyZm9ybURlbGF5ZWRSZWNvbm5lY3QoKTtcbiAgICAgIH1cbiAgICB9KVxuXG4gICAgLy8gd2UgaGF2ZSB0byBkZWJvdW5jZSB0aGVzZSBiZWNhdXNlIGphbnVzIGdldHMgYW5ncnkgaWYgeW91IHNlbmQgaXQgYSBuZXcgU0RQIGJlZm9yZVxuICAgIC8vIGl0J3MgZmluaXNoZWQgcHJvY2Vzc2luZyBhbiBleGlzdGluZyBTRFAuIGluIGFjdHVhbGl0eSwgaXQgc2VlbXMgbGlrZSB0aGlzIGlzIG1heWJlXG4gICAgLy8gdG9vIGxpYmVyYWwgYW5kIHdlIG5lZWQgdG8gd2FpdCBzb21lIGFtb3VudCBvZiB0aW1lIGFmdGVyIGFuIG9mZmVyIGJlZm9yZSBzZW5kaW5nIGFub3RoZXIsXG4gICAgLy8gYnV0IHdlIGRvbid0IGN1cnJlbnRseSBrbm93IGFueSBnb29kIHdheSBvZiBkZXRlY3RpbmcgZXhhY3RseSBob3cgbG9uZyA6KFxuICAgIGNvbm4uYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgIFwibmVnb3RpYXRpb25uZWVkZWRcIixcbiAgICAgIGRlYm91bmNlKGV2ID0+IHtcbiAgICAgICAgZGVidWcoXCJTZW5kaW5nIG5ldyBvZmZlciBmb3IgaGFuZGxlOiAlb1wiLCBoYW5kbGUpO1xuICAgICAgICB2YXIgb2ZmZXIgPSBjb25uLmNyZWF0ZU9mZmVyKCkudGhlbih0aGlzLmNvbmZpZ3VyZVB1Ymxpc2hlclNkcCkudGhlbih0aGlzLmZpeFNhZmFyaUljZVVGcmFnKTtcbiAgICAgICAgdmFyIGxvY2FsID0gb2ZmZXIudGhlbihvID0+IGNvbm4uc2V0TG9jYWxEZXNjcmlwdGlvbihvKSk7XG4gICAgICAgIHZhciByZW1vdGUgPSBvZmZlcjtcblxuICAgICAgICByZW1vdGUgPSByZW1vdGVcbiAgICAgICAgICAudGhlbih0aGlzLmZpeFNhZmFyaUljZVVGcmFnKVxuICAgICAgICAgIC50aGVuKGogPT4gaGFuZGxlLnNlbmRKc2VwKGopKVxuICAgICAgICAgIC50aGVuKHIgPT4gY29ubi5zZXRSZW1vdGVEZXNjcmlwdGlvbihyLmpzZXApKTtcbiAgICAgICAgcmV0dXJuIFByb21pc2UuYWxsKFtsb2NhbCwgcmVtb3RlXSkuY2F0Y2goZSA9PiBlcnJvcihcIkVycm9yIG5lZ290aWF0aW5nIG9mZmVyOiAlb1wiLCBlKSk7XG4gICAgICB9KVxuICAgICk7XG4gICAgaGFuZGxlLm9uKFxuICAgICAgXCJldmVudFwiLFxuICAgICAgZGVib3VuY2UoZXYgPT4ge1xuICAgICAgICB2YXIganNlcCA9IGV2LmpzZXA7XG4gICAgICAgIGlmIChqc2VwICYmIGpzZXAudHlwZSA9PSBcIm9mZmVyXCIpIHtcbiAgICAgICAgICBkZWJ1ZyhcIkFjY2VwdGluZyBuZXcgb2ZmZXIgZm9yIGhhbmRsZTogJW9cIiwgaGFuZGxlKTtcbiAgICAgICAgICB2YXIgYW5zd2VyID0gY29ublxuICAgICAgICAgICAgLnNldFJlbW90ZURlc2NyaXB0aW9uKHRoaXMuY29uZmlndXJlU3Vic2NyaWJlclNkcChqc2VwKSlcbiAgICAgICAgICAgIC50aGVuKF8gPT4gY29ubi5jcmVhdGVBbnN3ZXIoKSlcbiAgICAgICAgICAgIC50aGVuKHRoaXMuZml4U2FmYXJpSWNlVUZyYWcpO1xuICAgICAgICAgIHZhciBsb2NhbCA9IGFuc3dlci50aGVuKGEgPT4gY29ubi5zZXRMb2NhbERlc2NyaXB0aW9uKGEpKTtcbiAgICAgICAgICB2YXIgcmVtb3RlID0gYW5zd2VyLnRoZW4oaiA9PiBoYW5kbGUuc2VuZEpzZXAoaikpO1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLmFsbChbbG9jYWwsIHJlbW90ZV0pLmNhdGNoKGUgPT4gZXJyb3IoXCJFcnJvciBuZWdvdGlhdGluZyBhbnN3ZXI6ICVvXCIsIGUpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBzb21lIG90aGVyIGtpbmQgb2YgZXZlbnQsIG5vdGhpbmcgdG8gZG9cbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgYXN5bmMgY3JlYXRlUHVibGlzaGVyKCkge1xuICAgIHZhciBoYW5kbGUgPSBuZXcgbWouSmFudXNQbHVnaW5IYW5kbGUodGhpcy5zZXNzaW9uKTtcbiAgICB2YXIgY29ubiA9IG5ldyBSVENQZWVyQ29ubmVjdGlvbih0aGlzLnBlZXJDb25uZWN0aW9uQ29uZmlnIHx8IERFRkFVTFRfUEVFUl9DT05ORUNUSU9OX0NPTkZJRyk7XG5cbiAgICBkZWJ1ZyhcInB1YiB3YWl0aW5nIGZvciBzZnVcIik7XG4gICAgYXdhaXQgaGFuZGxlLmF0dGFjaChcImphbnVzLnBsdWdpbi5zZnVcIiwgdGhpcy5sb29wcyAmJiB0aGlzLmNsaWVudElkID8gcGFyc2VJbnQodGhpcy5jbGllbnRJZCkgJSB0aGlzLmxvb3BzIDogdW5kZWZpbmVkKTtcblxuICAgIHRoaXMuYXNzb2NpYXRlKGNvbm4sIGhhbmRsZSk7XG5cbiAgICBkZWJ1ZyhcInB1YiB3YWl0aW5nIGZvciBkYXRhIGNoYW5uZWxzICYgd2VicnRjdXBcIik7XG4gICAgdmFyIHdlYnJ0Y3VwID0gbmV3IFByb21pc2UocmVzb2x2ZSA9PiBoYW5kbGUub24oXCJ3ZWJydGN1cFwiLCByZXNvbHZlKSk7XG5cbiAgICAvLyBVbnJlbGlhYmxlIGRhdGFjaGFubmVsOiBzZW5kaW5nIGFuZCByZWNlaXZpbmcgY29tcG9uZW50IHVwZGF0ZXMuXG4gICAgLy8gUmVsaWFibGUgZGF0YWNoYW5uZWw6IHNlbmRpbmcgYW5kIHJlY2lldmluZyBlbnRpdHkgaW5zdGFudGlhdGlvbnMuXG4gICAgdmFyIHJlbGlhYmxlQ2hhbm5lbCA9IGNvbm4uY3JlYXRlRGF0YUNoYW5uZWwoXCJyZWxpYWJsZVwiLCB7IG9yZGVyZWQ6IHRydWUgfSk7XG4gICAgdmFyIHVucmVsaWFibGVDaGFubmVsID0gY29ubi5jcmVhdGVEYXRhQ2hhbm5lbChcInVucmVsaWFibGVcIiwge1xuICAgICAgb3JkZXJlZDogZmFsc2UsXG4gICAgICBtYXhSZXRyYW5zbWl0czogMFxuICAgIH0pO1xuXG4gICAgcmVsaWFibGVDaGFubmVsLmFkZEV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIGUgPT4gdGhpcy5vbkRhdGFDaGFubmVsTWVzc2FnZShlLCBcImphbnVzLXJlbGlhYmxlXCIpKTtcbiAgICB1bnJlbGlhYmxlQ2hhbm5lbC5hZGRFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCBlID0+IHRoaXMub25EYXRhQ2hhbm5lbE1lc3NhZ2UoZSwgXCJqYW51cy11bnJlbGlhYmxlXCIpKTtcblxuICAgIGF3YWl0IHdlYnJ0Y3VwO1xuICAgIGF3YWl0IHVudGlsRGF0YUNoYW5uZWxPcGVuKHJlbGlhYmxlQ2hhbm5lbCk7XG4gICAgYXdhaXQgdW50aWxEYXRhQ2hhbm5lbE9wZW4odW5yZWxpYWJsZUNoYW5uZWwpO1xuXG4gICAgLy8gZG9pbmcgdGhpcyBoZXJlIGlzIHNvcnQgb2YgYSBoYWNrIGFyb3VuZCBjaHJvbWUgcmVuZWdvdGlhdGlvbiB3ZWlyZG5lc3MgLS1cbiAgICAvLyBpZiB3ZSBkbyBpdCBwcmlvciB0byB3ZWJydGN1cCwgY2hyb21lIG9uIGdlYXIgVlIgd2lsbCBzb21ldGltZXMgcHV0IGFcbiAgICAvLyByZW5lZ290aWF0aW9uIG9mZmVyIGluIGZsaWdodCB3aGlsZSB0aGUgZmlyc3Qgb2ZmZXIgd2FzIHN0aWxsIGJlaW5nXG4gICAgLy8gcHJvY2Vzc2VkIGJ5IGphbnVzLiB3ZSBzaG91bGQgZmluZCBzb21lIG1vcmUgcHJpbmNpcGxlZCB3YXkgdG8gZmlndXJlIG91dFxuICAgIC8vIHdoZW4gamFudXMgaXMgZG9uZSBpbiB0aGUgZnV0dXJlLlxuICAgIGlmICh0aGlzLmxvY2FsTWVkaWFTdHJlYW0pIHtcbiAgICAgIHRoaXMubG9jYWxNZWRpYVN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKHRyYWNrID0+IHtcbiAgICAgICAgY29ubi5hZGRUcmFjayh0cmFjaywgdGhpcy5sb2NhbE1lZGlhU3RyZWFtKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIEhhbmRsZSBhbGwgb2YgdGhlIGpvaW4gYW5kIGxlYXZlIGV2ZW50cy5cbiAgICBoYW5kbGUub24oXCJldmVudFwiLCBldiA9PiB7XG4gICAgICB2YXIgZGF0YSA9IGV2LnBsdWdpbmRhdGEuZGF0YTtcbiAgICAgIGlmIChkYXRhLmV2ZW50ID09IFwiam9pblwiICYmIGRhdGEucm9vbV9pZCA9PSB0aGlzLnJvb20pIHtcbiAgICAgICAgaWYgKHRoaXMuZGVsYXllZFJlY29ubmVjdFRpbWVvdXQpIHtcbiAgICAgICAgICAvLyBEb24ndCBjcmVhdGUgYSBuZXcgUlRDUGVlckNvbm5lY3Rpb24sIGFsbCBSVENQZWVyQ29ubmVjdGlvbiB3aWxsIGJlIGNsb3NlZCBpbiBsZXNzIHRoYW4gMTBzLlxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmFkZEF2YWlsYWJsZU9jY3VwYW50KGRhdGEudXNlcl9pZCk7XG4gICAgICAgIHRoaXMuc3luY09jY3VwYW50cygpO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50ID09IFwibGVhdmVcIiAmJiBkYXRhLnJvb21faWQgPT0gdGhpcy5yb29tKSB7XG4gICAgICAgIHRoaXMucmVtb3ZlQXZhaWxhYmxlT2NjdXBhbnQoZGF0YS51c2VyX2lkKTtcbiAgICAgICAgdGhpcy5yZW1vdmVPY2N1cGFudChkYXRhLnVzZXJfaWQpO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50ID09IFwiYmxvY2tlZFwiKSB7XG4gICAgICAgIGRvY3VtZW50LmJvZHkuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoXCJibG9ja2VkXCIsIHsgZGV0YWlsOiB7IGNsaWVudElkOiBkYXRhLmJ5IH0gfSkpO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmV2ZW50ID09IFwidW5ibG9ja2VkXCIpIHtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChcInVuYmxvY2tlZFwiLCB7IGRldGFpbDogeyBjbGllbnRJZDogZGF0YS5ieSB9IH0pKTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5ldmVudCA9PT0gXCJkYXRhXCIpIHtcbiAgICAgICAgdGhpcy5vbkRhdGEoSlNPTi5wYXJzZShkYXRhLmJvZHkpLCBcImphbnVzLWV2ZW50XCIpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgZGVidWcoXCJwdWIgd2FpdGluZyBmb3Igam9pblwiKTtcblxuICAgIC8vIFNlbmQgam9pbiBtZXNzYWdlIHRvIGphbnVzLiBMaXN0ZW4gZm9yIGpvaW4vbGVhdmUgbWVzc2FnZXMuIEF1dG9tYXRpY2FsbHkgc3Vic2NyaWJlIHRvIGFsbCB1c2VycycgV2ViUlRDIGRhdGEuXG4gICAgdmFyIG1lc3NhZ2UgPSBhd2FpdCB0aGlzLnNlbmRKb2luKGhhbmRsZSwge1xuICAgICAgbm90aWZpY2F0aW9uczogdHJ1ZSxcbiAgICAgIGRhdGE6IHRydWVcbiAgICB9KTtcblxuICAgIGlmICghbWVzc2FnZS5wbHVnaW5kYXRhLmRhdGEuc3VjY2Vzcykge1xuICAgICAgY29uc3QgZXJyID0gbWVzc2FnZS5wbHVnaW5kYXRhLmRhdGEuZXJyb3I7XG4gICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICAvLyBXZSBtYXkgZ2V0IGhlcmUgYmVjYXVzZSBvZiBhbiBleHBpcmVkIEpXVC5cbiAgICAgIC8vIENsb3NlIHRoZSBjb25uZWN0aW9uIG91cnNlbGYgb3RoZXJ3aXNlIGphbnVzIHdpbGwgY2xvc2UgaXQgYWZ0ZXJcbiAgICAgIC8vIHNlc3Npb25fdGltZW91dCBiZWNhdXNlIHdlIGRpZG4ndCBzZW5kIGFueSBrZWVwYWxpdmUgYW5kIHRoaXMgd2lsbFxuICAgICAgLy8gdHJpZ2dlciBhIGRlbGF5ZWQgcmVjb25uZWN0IGJlY2F1c2Ugb2YgdGhlIGljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZVxuICAgICAgLy8gbGlzdGVuZXIgZm9yIGZhaWx1cmUgc3RhdGUuXG4gICAgICAvLyBFdmVuIGlmIHRoZSBhcHAgY29kZSBjYWxscyBkaXNjb25uZWN0IGluIGNhc2Ugb2YgZXJyb3IsIGRpc2Nvbm5lY3RcbiAgICAgIC8vIHdvbid0IGNsb3NlIHRoZSBwZWVyIGNvbm5lY3Rpb24gYmVjYXVzZSB0aGlzLnB1Ymxpc2hlciBpcyBub3Qgc2V0LlxuICAgICAgY29ubi5jbG9zZSgpO1xuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cblxuICAgIHZhciBpbml0aWFsT2NjdXBhbnRzID0gbWVzc2FnZS5wbHVnaW5kYXRhLmRhdGEucmVzcG9uc2UudXNlcnNbdGhpcy5yb29tXSB8fCBbXTtcblxuICAgIGlmIChpbml0aWFsT2NjdXBhbnRzLmluY2x1ZGVzKHRoaXMuY2xpZW50SWQpKSB7XG4gICAgICBjb25zb2xlLndhcm4oXCJKYW51cyBzdGlsbCBoYXMgcHJldmlvdXMgc2Vzc2lvbiBmb3IgdGhpcyBjbGllbnQuIFJlY29ubmVjdGluZyBpbiAxMHMuXCIpO1xuICAgICAgdGhpcy5wZXJmb3JtRGVsYXllZFJlY29ubmVjdCgpO1xuICAgIH1cblxuICAgIGRlYnVnKFwicHVibGlzaGVyIHJlYWR5XCIpO1xuICAgIHJldHVybiB7XG4gICAgICBoYW5kbGUsXG4gICAgICBpbml0aWFsT2NjdXBhbnRzLFxuICAgICAgcmVsaWFibGVDaGFubmVsLFxuICAgICAgdW5yZWxpYWJsZUNoYW5uZWwsXG4gICAgICBjb25uXG4gICAgfTtcbiAgfVxuXG4gIGNvbmZpZ3VyZVB1Ymxpc2hlclNkcChqc2VwKSB7XG4gICAganNlcC5zZHAgPSBqc2VwLnNkcC5yZXBsYWNlKC9hPWZtdHA6KDEwOXwxMTEpLipcXHJcXG4vZywgKGxpbmUsIHB0KSA9PiB7XG4gICAgICBjb25zdCBwYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbihzZHBVdGlscy5wYXJzZUZtdHAobGluZSksIE9QVVNfUEFSQU1FVEVSUyk7XG4gICAgICByZXR1cm4gc2RwVXRpbHMud3JpdGVGbXRwKHsgcGF5bG9hZFR5cGU6IHB0LCBwYXJhbWV0ZXJzOiBwYXJhbWV0ZXJzIH0pO1xuICAgIH0pO1xuICAgIHJldHVybiBqc2VwO1xuICB9XG5cbiAgY29uZmlndXJlU3Vic2NyaWJlclNkcChqc2VwKSB7XG4gICAgLy8gdG9kbzogY29uc2lkZXIgY2xlYW5pbmcgdXAgdGhlc2UgaGFja3MgdG8gdXNlIHNkcHV0aWxzXG4gICAgaWYgKCFpc0gyNjRWaWRlb1N1cHBvcnRlZCkge1xuICAgICAgaWYgKG5hdmlnYXRvci51c2VyQWdlbnQuaW5kZXhPZihcIkhlYWRsZXNzQ2hyb21lXCIpICE9PSAtMSkge1xuICAgICAgICAvLyBIZWFkbGVzc0Nocm9tZSAoZS5nLiBwdXBwZXRlZXIpIGRvZXNuJ3Qgc3VwcG9ydCB3ZWJydGMgdmlkZW8gc3RyZWFtcywgc28gd2UgcmVtb3ZlIHRob3NlIGxpbmVzIGZyb20gdGhlIFNEUC5cbiAgICAgICAganNlcC5zZHAgPSBqc2VwLnNkcC5yZXBsYWNlKC9tPXZpZGVvW15dKm09LywgXCJtPVwiKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUT0RPOiBIYWNrIHRvIGdldCB2aWRlbyB3b3JraW5nIG9uIENocm9tZSBmb3IgQW5kcm9pZC4gaHR0cHM6Ly9ncm91cHMuZ29vZ2xlLmNvbS9mb3J1bS8jIXRvcGljL21vemlsbGEuZGV2Lm1lZGlhL1llMjl2dU1UcG84XG4gICAgaWYgKG5hdmlnYXRvci51c2VyQWdlbnQuaW5kZXhPZihcIkFuZHJvaWRcIikgPT09IC0xKSB7XG4gICAgICBqc2VwLnNkcCA9IGpzZXAuc2RwLnJlcGxhY2UoXG4gICAgICAgIFwiYT1ydGNwLWZiOjEwNyBnb29nLXJlbWJcXHJcXG5cIixcbiAgICAgICAgXCJhPXJ0Y3AtZmI6MTA3IGdvb2ctcmVtYlxcclxcbmE9cnRjcC1mYjoxMDcgdHJhbnNwb3J0LWNjXFxyXFxuYT1mbXRwOjEwNyBsZXZlbC1hc3ltbWV0cnktYWxsb3dlZD0xO3BhY2tldGl6YXRpb24tbW9kZT0xO3Byb2ZpbGUtbGV2ZWwtaWQ9NDJlMDFmXFxyXFxuXCJcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGpzZXAuc2RwID0ganNlcC5zZHAucmVwbGFjZShcbiAgICAgICAgXCJhPXJ0Y3AtZmI6MTA3IGdvb2ctcmVtYlxcclxcblwiLFxuICAgICAgICBcImE9cnRjcC1mYjoxMDcgZ29vZy1yZW1iXFxyXFxuYT1ydGNwLWZiOjEwNyB0cmFuc3BvcnQtY2NcXHJcXG5hPWZtdHA6MTA3IGxldmVsLWFzeW1tZXRyeS1hbGxvd2VkPTE7cGFja2V0aXphdGlvbi1tb2RlPTE7cHJvZmlsZS1sZXZlbC1pZD00MjAwMWZcXHJcXG5cIlxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGpzZXA7XG4gIH1cblxuICBhc3luYyBmaXhTYWZhcmlJY2VVRnJhZyhqc2VwKSB7XG4gICAgLy8gU2FmYXJpIHByb2R1Y2VzIGEgXFxuIGluc3RlYWQgb2YgYW4gXFxyXFxuIGZvciB0aGUgaWNlLXVmcmFnLiBTZWUgaHR0cHM6Ly9naXRodWIuY29tL21lZXRlY2hvL2phbnVzLWdhdGV3YXkvaXNzdWVzLzE4MThcbiAgICBqc2VwLnNkcCA9IGpzZXAuc2RwLnJlcGxhY2UoL1teXFxyXVxcbmE9aWNlLXVmcmFnL2csIFwiXFxyXFxuYT1pY2UtdWZyYWdcIik7XG4gICAgcmV0dXJuIGpzZXBcbiAgfVxuXG4gIGFzeW5jIGNyZWF0ZVN1YnNjcmliZXIob2NjdXBhbnRJZCwgbWF4UmV0cmllcyA9IDUpIHtcbiAgICBpZiAodGhpcy5hdmFpbGFibGVPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKSA9PT0gLTEpIHtcbiAgICAgIGNvbnNvbGUud2FybihvY2N1cGFudElkICsgXCI6IGNhbmNlbGxlZCBvY2N1cGFudCBjb25uZWN0aW9uLCBvY2N1cGFudCBsZWZ0IGJlZm9yZSBzdWJzY3JpcHRpb24gbmVnb3RhdGlvbi5cIik7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICB2YXIgaGFuZGxlID0gbmV3IG1qLkphbnVzUGx1Z2luSGFuZGxlKHRoaXMuc2Vzc2lvbik7XG4gICAgdmFyIGNvbm4gPSBuZXcgUlRDUGVlckNvbm5lY3Rpb24odGhpcy5wZWVyQ29ubmVjdGlvbkNvbmZpZyB8fCBERUZBVUxUX1BFRVJfQ09OTkVDVElPTl9DT05GSUcpO1xuXG4gICAgZGVidWcob2NjdXBhbnRJZCArIFwiOiBzdWIgd2FpdGluZyBmb3Igc2Z1XCIpO1xuICAgIGF3YWl0IGhhbmRsZS5hdHRhY2goXCJqYW51cy5wbHVnaW4uc2Z1XCIsIHRoaXMubG9vcHMgPyBwYXJzZUludChvY2N1cGFudElkKSAlIHRoaXMubG9vcHMgOiB1bmRlZmluZWQpO1xuXG4gICAgdGhpcy5hc3NvY2lhdGUoY29ubiwgaGFuZGxlKTtcblxuICAgIGRlYnVnKG9jY3VwYW50SWQgKyBcIjogc3ViIHdhaXRpbmcgZm9yIGpvaW5cIik7XG5cbiAgICBpZiAodGhpcy5hdmFpbGFibGVPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKSA9PT0gLTEpIHtcbiAgICAgIGNvbm4uY2xvc2UoKTtcbiAgICAgIGNvbnNvbGUud2FybihvY2N1cGFudElkICsgXCI6IGNhbmNlbGxlZCBvY2N1cGFudCBjb25uZWN0aW9uLCBvY2N1cGFudCBsZWZ0IGFmdGVyIGF0dGFjaFwiKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGxldCB3ZWJydGNGYWlsZWQgPSBmYWxzZTtcblxuICAgIGNvbnN0IHdlYnJ0Y3VwID0gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgICBjb25zdCBsZWZ0SW50ZXJ2YWwgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgICAgIGNsZWFySW50ZXJ2YWwobGVmdEludGVydmFsKTtcbiAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgIH1cbiAgICAgIH0sIDEwMDApO1xuXG4gICAgICBjb25zdCB0aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwobGVmdEludGVydmFsKTtcbiAgICAgICAgd2VicnRjRmFpbGVkID0gdHJ1ZTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfSwgU1VCU0NSSUJFX1RJTUVPVVRfTVMpO1xuXG4gICAgICBoYW5kbGUub24oXCJ3ZWJydGN1cFwiLCAoKSA9PiB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgY2xlYXJJbnRlcnZhbChsZWZ0SW50ZXJ2YWwpO1xuICAgICAgICByZXNvbHZlKCk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIC8vIFNlbmQgam9pbiBtZXNzYWdlIHRvIGphbnVzLiBEb24ndCBsaXN0ZW4gZm9yIGpvaW4vbGVhdmUgbWVzc2FnZXMuIFN1YnNjcmliZSB0byB0aGUgb2NjdXBhbnQncyBtZWRpYS5cbiAgICAvLyBKYW51cyBzaG91bGQgc2VuZCB1cyBhbiBvZmZlciBmb3IgdGhpcyBvY2N1cGFudCdzIG1lZGlhIGluIHJlc3BvbnNlIHRvIHRoaXMuXG4gICAgYXdhaXQgdGhpcy5zZW5kSm9pbihoYW5kbGUsIHsgbWVkaWE6IG9jY3VwYW50SWQgfSk7XG5cbiAgICBpZiAodGhpcy5hdmFpbGFibGVPY2N1cGFudHMuaW5kZXhPZihvY2N1cGFudElkKSA9PT0gLTEpIHtcbiAgICAgIGNvbm4uY2xvc2UoKTtcbiAgICAgIGNvbnNvbGUud2FybihvY2N1cGFudElkICsgXCI6IGNhbmNlbGxlZCBvY2N1cGFudCBjb25uZWN0aW9uLCBvY2N1cGFudCBsZWZ0IGFmdGVyIGpvaW5cIik7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBkZWJ1ZyhvY2N1cGFudElkICsgXCI6IHN1YiB3YWl0aW5nIGZvciB3ZWJydGN1cFwiKTtcbiAgICBhd2FpdCB3ZWJydGN1cDtcblxuICAgIGlmICh0aGlzLmF2YWlsYWJsZU9jY3VwYW50cy5pbmRleE9mKG9jY3VwYW50SWQpID09PSAtMSkge1xuICAgICAgY29ubi5jbG9zZSgpO1xuICAgICAgY29uc29sZS53YXJuKG9jY3VwYW50SWQgKyBcIjogY2FuY2VsIG9jY3VwYW50IGNvbm5lY3Rpb24sIG9jY3VwYW50IGxlZnQgZHVyaW5nIG9yIGFmdGVyIHdlYnJ0Y3VwXCIpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgaWYgKHdlYnJ0Y0ZhaWxlZCkge1xuICAgICAgY29ubi5jbG9zZSgpO1xuICAgICAgaWYgKG1heFJldHJpZXMgPiAwKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihvY2N1cGFudElkICsgXCI6IHdlYnJ0YyB1cCB0aW1lZCBvdXQsIHJldHJ5aW5nXCIpO1xuICAgICAgICByZXR1cm4gdGhpcy5jcmVhdGVTdWJzY3JpYmVyKG9jY3VwYW50SWQsIG1heFJldHJpZXMgLSAxKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUud2FybihvY2N1cGFudElkICsgXCI6IHdlYnJ0YyB1cCB0aW1lZCBvdXRcIik7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChpc1NhZmFyaSAmJiAhdGhpcy5faU9TSGFja0RlbGF5ZWRJbml0aWFsUGVlcikge1xuICAgICAgLy8gSEFDSzogdGhlIGZpcnN0IHBlZXIgb24gU2FmYXJpIGR1cmluZyBwYWdlIGxvYWQgY2FuIGZhaWwgdG8gd29yayBpZiB3ZSBkb24ndFxuICAgICAgLy8gd2FpdCBzb21lIHRpbWUgYmVmb3JlIGNvbnRpbnVpbmcgaGVyZS4gU2VlOiBodHRwczovL2dpdGh1Yi5jb20vbW96aWxsYS9odWJzL3B1bGwvMTY5MlxuICAgICAgYXdhaXQgKG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDMwMDApKSk7XG4gICAgICB0aGlzLl9pT1NIYWNrRGVsYXllZEluaXRpYWxQZWVyID0gdHJ1ZTtcbiAgICB9XG5cbiAgICB2YXIgbWVkaWFTdHJlYW0gPSBuZXcgTWVkaWFTdHJlYW0oKTtcbiAgICB2YXIgcmVjZWl2ZXJzID0gY29ubi5nZXRSZWNlaXZlcnMoKTtcbiAgICByZWNlaXZlcnMuZm9yRWFjaChyZWNlaXZlciA9PiB7XG4gICAgICBpZiAocmVjZWl2ZXIudHJhY2spIHtcbiAgICAgICAgbWVkaWFTdHJlYW0uYWRkVHJhY2socmVjZWl2ZXIudHJhY2spO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGlmIChtZWRpYVN0cmVhbS5nZXRUcmFja3MoKS5sZW5ndGggPT09IDApIHtcbiAgICAgIG1lZGlhU3RyZWFtID0gbnVsbDtcbiAgICB9XG5cbiAgICBkZWJ1ZyhvY2N1cGFudElkICsgXCI6IHN1YnNjcmliZXIgcmVhZHlcIik7XG4gICAgcmV0dXJuIHtcbiAgICAgIGhhbmRsZSxcbiAgICAgIG1lZGlhU3RyZWFtLFxuICAgICAgY29ublxuICAgIH07XG4gIH1cblxuICBzZW5kSm9pbihoYW5kbGUsIHN1YnNjcmliZSkge1xuICAgIHJldHVybiBoYW5kbGUuc2VuZE1lc3NhZ2Uoe1xuICAgICAga2luZDogXCJqb2luXCIsXG4gICAgICByb29tX2lkOiB0aGlzLnJvb20sXG4gICAgICB1c2VyX2lkOiB0aGlzLmNsaWVudElkLFxuICAgICAgc3Vic2NyaWJlLFxuICAgICAgdG9rZW46IHRoaXMuam9pblRva2VuXG4gICAgfSk7XG4gIH1cblxuICB0b2dnbGVGcmVlemUoKSB7XG4gICAgaWYgKHRoaXMuZnJvemVuKSB7XG4gICAgICB0aGlzLnVuZnJlZXplKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZnJlZXplKCk7XG4gICAgfVxuICB9XG5cbiAgZnJlZXplKCkge1xuICAgIHRoaXMuZnJvemVuID0gdHJ1ZTtcbiAgfVxuXG4gIHVuZnJlZXplKCkge1xuICAgIHRoaXMuZnJvemVuID0gZmFsc2U7XG4gICAgdGhpcy5mbHVzaFBlbmRpbmdVcGRhdGVzKCk7XG4gIH1cblxuICBkYXRhRm9yVXBkYXRlTXVsdGlNZXNzYWdlKG5ldHdvcmtJZCwgbWVzc2FnZSkge1xuICAgIC8vIFwiZFwiIGlzIGFuIGFycmF5IG9mIGVudGl0eSBkYXRhcywgd2hlcmUgZWFjaCBpdGVtIGluIHRoZSBhcnJheSByZXByZXNlbnRzIGEgdW5pcXVlIGVudGl0eSBhbmQgY29udGFpbnNcbiAgICAvLyBtZXRhZGF0YSBmb3IgdGhlIGVudGl0eSwgYW5kIGFuIGFycmF5IG9mIGNvbXBvbmVudHMgdGhhdCBoYXZlIGJlZW4gdXBkYXRlZCBvbiB0aGUgZW50aXR5LlxuICAgIC8vIFRoaXMgbWV0aG9kIGZpbmRzIHRoZSBkYXRhIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGdpdmVuIG5ldHdvcmtJZC5cbiAgICBmb3IgKGxldCBpID0gMCwgbCA9IG1lc3NhZ2UuZGF0YS5kLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgY29uc3QgZGF0YSA9IG1lc3NhZ2UuZGF0YS5kW2ldO1xuXG4gICAgICBpZiAoZGF0YS5uZXR3b3JrSWQgPT09IG5ldHdvcmtJZCkge1xuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGdldFBlbmRpbmdEYXRhKG5ldHdvcmtJZCwgbWVzc2FnZSkge1xuICAgIGlmICghbWVzc2FnZSkgcmV0dXJuIG51bGw7XG5cbiAgICBsZXQgZGF0YSA9IG1lc3NhZ2UuZGF0YVR5cGUgPT09IFwidW1cIiA/IHRoaXMuZGF0YUZvclVwZGF0ZU11bHRpTWVzc2FnZShuZXR3b3JrSWQsIG1lc3NhZ2UpIDogbWVzc2FnZS5kYXRhO1xuXG4gICAgLy8gSWdub3JlIG1lc3NhZ2VzIHJlbGF0aW5nIHRvIHVzZXJzIHdobyBoYXZlIGRpc2Nvbm5lY3RlZCBzaW5jZSBmcmVlemluZywgdGhlaXIgZW50aXRpZXNcbiAgICAvLyB3aWxsIGhhdmUgYWxlYWR5IGJlZW4gcmVtb3ZlZCBieSBOQUYuXG4gICAgLy8gTm90ZSB0aGF0IGRlbGV0ZSBtZXNzYWdlcyBoYXZlIG5vIFwib3duZXJcIiBzbyB3ZSBoYXZlIHRvIGNoZWNrIGZvciB0aGF0IGFzIHdlbGwuXG4gICAgaWYgKGRhdGEub3duZXIgJiYgIXRoaXMub2NjdXBhbnRzW2RhdGEub3duZXJdKSByZXR1cm4gbnVsbDtcblxuICAgIC8vIElnbm9yZSBtZXNzYWdlcyBmcm9tIHVzZXJzIHRoYXQgd2UgbWF5IGhhdmUgYmxvY2tlZCB3aGlsZSBmcm96ZW4uXG4gICAgaWYgKGRhdGEub3duZXIgJiYgdGhpcy5ibG9ja2VkQ2xpZW50cy5oYXMoZGF0YS5vd25lcikpIHJldHVybiBudWxsO1xuXG4gICAgcmV0dXJuIGRhdGFcbiAgfVxuXG4gIC8vIFVzZWQgZXh0ZXJuYWxseVxuICBnZXRQZW5kaW5nRGF0YUZvck5ldHdvcmtJZChuZXR3b3JrSWQpIHtcbiAgICByZXR1cm4gdGhpcy5nZXRQZW5kaW5nRGF0YShuZXR3b3JrSWQsIHRoaXMuZnJvemVuVXBkYXRlcy5nZXQobmV0d29ya0lkKSk7XG4gIH1cblxuICBmbHVzaFBlbmRpbmdVcGRhdGVzKCkge1xuICAgIGZvciAoY29uc3QgW25ldHdvcmtJZCwgbWVzc2FnZV0gb2YgdGhpcy5mcm96ZW5VcGRhdGVzKSB7XG4gICAgICBsZXQgZGF0YSA9IHRoaXMuZ2V0UGVuZGluZ0RhdGEobmV0d29ya0lkLCBtZXNzYWdlKTtcbiAgICAgIGlmICghZGF0YSkgY29udGludWU7XG5cbiAgICAgIC8vIE92ZXJyaWRlIHRoZSBkYXRhIHR5cGUgb24gXCJ1bVwiIG1lc3NhZ2VzIHR5cGVzLCBzaW5jZSB3ZSBleHRyYWN0IGVudGl0eSB1cGRhdGVzIGZyb20gXCJ1bVwiIG1lc3NhZ2VzIGludG9cbiAgICAgIC8vIGluZGl2aWR1YWwgZnJvemVuVXBkYXRlcyBpbiBzdG9yZVNpbmdsZU1lc3NhZ2UuXG4gICAgICBjb25zdCBkYXRhVHlwZSA9IG1lc3NhZ2UuZGF0YVR5cGUgPT09IFwidW1cIiA/IFwidVwiIDogbWVzc2FnZS5kYXRhVHlwZTtcblxuICAgICAgdGhpcy5vbk9jY3VwYW50TWVzc2FnZShudWxsLCBkYXRhVHlwZSwgZGF0YSwgbWVzc2FnZS5zb3VyY2UpO1xuICAgIH1cbiAgICB0aGlzLmZyb3plblVwZGF0ZXMuY2xlYXIoKTtcbiAgfVxuXG4gIHN0b3JlTWVzc2FnZShtZXNzYWdlKSB7XG4gICAgaWYgKG1lc3NhZ2UuZGF0YVR5cGUgPT09IFwidW1cIikgeyAvLyBVcGRhdGVNdWx0aVxuICAgICAgZm9yIChsZXQgaSA9IDAsIGwgPSBtZXNzYWdlLmRhdGEuZC5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgdGhpcy5zdG9yZVNpbmdsZU1lc3NhZ2UobWVzc2FnZSwgaSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc3RvcmVTaW5nbGVNZXNzYWdlKG1lc3NhZ2UpO1xuICAgIH1cbiAgfVxuXG4gIHN0b3JlU2luZ2xlTWVzc2FnZShtZXNzYWdlLCBpbmRleCkge1xuICAgIGNvbnN0IGRhdGEgPSBpbmRleCAhPT0gdW5kZWZpbmVkID8gbWVzc2FnZS5kYXRhLmRbaW5kZXhdIDogbWVzc2FnZS5kYXRhO1xuICAgIGNvbnN0IGRhdGFUeXBlID0gbWVzc2FnZS5kYXRhVHlwZTtcbiAgICBjb25zdCBzb3VyY2UgPSBtZXNzYWdlLnNvdXJjZTtcblxuICAgIGNvbnN0IG5ldHdvcmtJZCA9IGRhdGEubmV0d29ya0lkO1xuXG4gICAgaWYgKCF0aGlzLmZyb3plblVwZGF0ZXMuaGFzKG5ldHdvcmtJZCkpIHtcbiAgICAgIHRoaXMuZnJvemVuVXBkYXRlcy5zZXQobmV0d29ya0lkLCBtZXNzYWdlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3Qgc3RvcmVkTWVzc2FnZSA9IHRoaXMuZnJvemVuVXBkYXRlcy5nZXQobmV0d29ya0lkKTtcbiAgICAgIGNvbnN0IHN0b3JlZERhdGEgPSBzdG9yZWRNZXNzYWdlLmRhdGFUeXBlID09PSBcInVtXCIgPyB0aGlzLmRhdGFGb3JVcGRhdGVNdWx0aU1lc3NhZ2UobmV0d29ya0lkLCBzdG9yZWRNZXNzYWdlKSA6IHN0b3JlZE1lc3NhZ2UuZGF0YTtcblxuICAgICAgLy8gQXZvaWQgdXBkYXRpbmcgY29tcG9uZW50cyBpZiB0aGUgZW50aXR5IGRhdGEgcmVjZWl2ZWQgZGlkIG5vdCBjb21lIGZyb20gdGhlIGN1cnJlbnQgb3duZXIuXG4gICAgICBjb25zdCBpc091dGRhdGVkTWVzc2FnZSA9IGRhdGEubGFzdE93bmVyVGltZSA8IHN0b3JlZERhdGEubGFzdE93bmVyVGltZTtcbiAgICAgIGNvbnN0IGlzQ29udGVtcG9yYW5lb3VzTWVzc2FnZSA9IGRhdGEubGFzdE93bmVyVGltZSA9PT0gc3RvcmVkRGF0YS5sYXN0T3duZXJUaW1lO1xuICAgICAgaWYgKGlzT3V0ZGF0ZWRNZXNzYWdlIHx8IChpc0NvbnRlbXBvcmFuZW91c01lc3NhZ2UgJiYgc3RvcmVkRGF0YS5vd25lciA+IGRhdGEub3duZXIpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGRhdGFUeXBlID09PSBcInJcIikge1xuICAgICAgICBjb25zdCBjcmVhdGVkV2hpbGVGcm96ZW4gPSBzdG9yZWREYXRhICYmIHN0b3JlZERhdGEuaXNGaXJzdFN5bmM7XG4gICAgICAgIGlmIChjcmVhdGVkV2hpbGVGcm96ZW4pIHtcbiAgICAgICAgICAvLyBJZiB0aGUgZW50aXR5IHdhcyBjcmVhdGVkIGFuZCBkZWxldGVkIHdoaWxlIGZyb3plbiwgZG9uJ3QgYm90aGVyIGNvbnZleWluZyBhbnl0aGluZyB0byB0aGUgY29uc3VtZXIuXG4gICAgICAgICAgdGhpcy5mcm96ZW5VcGRhdGVzLmRlbGV0ZShuZXR3b3JrSWQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIERlbGV0ZSBtZXNzYWdlcyBvdmVycmlkZSBhbnkgb3RoZXIgbWVzc2FnZXMgZm9yIHRoaXMgZW50aXR5XG4gICAgICAgICAgdGhpcy5mcm96ZW5VcGRhdGVzLnNldChuZXR3b3JrSWQsIG1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBtZXJnZSBpbiBjb21wb25lbnQgdXBkYXRlc1xuICAgICAgICBpZiAoc3RvcmVkRGF0YS5jb21wb25lbnRzICYmIGRhdGEuY29tcG9uZW50cykge1xuICAgICAgICAgIE9iamVjdC5hc3NpZ24oc3RvcmVkRGF0YS5jb21wb25lbnRzLCBkYXRhLmNvbXBvbmVudHMpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgb25EYXRhQ2hhbm5lbE1lc3NhZ2UoZSwgc291cmNlKSB7XG4gICAgdGhpcy5vbkRhdGEoSlNPTi5wYXJzZShlLmRhdGEpLCBzb3VyY2UpO1xuICB9XG5cbiAgb25EYXRhKG1lc3NhZ2UsIHNvdXJjZSkge1xuICAgIGlmIChkZWJ1Zy5lbmFibGVkKSB7XG4gICAgICBkZWJ1ZyhgREMgaW46ICR7bWVzc2FnZX1gKTtcbiAgICB9XG5cbiAgICBpZiAoIW1lc3NhZ2UuZGF0YVR5cGUpIHJldHVybjtcblxuICAgIG1lc3NhZ2Uuc291cmNlID0gc291cmNlO1xuXG4gICAgaWYgKHRoaXMuZnJvemVuKSB7XG4gICAgICB0aGlzLnN0b3JlTWVzc2FnZShtZXNzYWdlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5vbk9jY3VwYW50TWVzc2FnZShudWxsLCBtZXNzYWdlLmRhdGFUeXBlLCBtZXNzYWdlLmRhdGEsIG1lc3NhZ2Uuc291cmNlKTtcbiAgICB9XG4gIH1cblxuICBzaG91bGRTdGFydENvbm5lY3Rpb25UbyhjbGllbnQpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHN0YXJ0U3RyZWFtQ29ubmVjdGlvbihjbGllbnQpIHt9XG5cbiAgY2xvc2VTdHJlYW1Db25uZWN0aW9uKGNsaWVudCkge31cblxuICBnZXRDb25uZWN0U3RhdHVzKGNsaWVudElkKSB7XG4gICAgcmV0dXJuIHRoaXMub2NjdXBhbnRzW2NsaWVudElkXSA/IE5BRi5hZGFwdGVycy5JU19DT05ORUNURUQgOiBOQUYuYWRhcHRlcnMuTk9UX0NPTk5FQ1RFRDtcbiAgfVxuXG4gIGFzeW5jIHVwZGF0ZVRpbWVPZmZzZXQoKSB7XG4gICAgaWYgKHRoaXMuaXNEaXNjb25uZWN0ZWQoKSkgcmV0dXJuO1xuXG4gICAgY29uc3QgY2xpZW50U2VudFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gICAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2goZG9jdW1lbnQubG9jYXRpb24uaHJlZiwge1xuICAgICAgbWV0aG9kOiBcIkhFQURcIixcbiAgICAgIGNhY2hlOiBcIm5vLWNhY2hlXCJcbiAgICB9KTtcblxuICAgIGNvbnN0IHByZWNpc2lvbiA9IDEwMDA7XG4gICAgY29uc3Qgc2VydmVyUmVjZWl2ZWRUaW1lID0gbmV3IERhdGUocmVzLmhlYWRlcnMuZ2V0KFwiRGF0ZVwiKSkuZ2V0VGltZSgpICsgcHJlY2lzaW9uIC8gMjtcbiAgICBjb25zdCBjbGllbnRSZWNlaXZlZFRpbWUgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IHNlcnZlclRpbWUgPSBzZXJ2ZXJSZWNlaXZlZFRpbWUgKyAoY2xpZW50UmVjZWl2ZWRUaW1lIC0gY2xpZW50U2VudFRpbWUpIC8gMjtcbiAgICBjb25zdCB0aW1lT2Zmc2V0ID0gc2VydmVyVGltZSAtIGNsaWVudFJlY2VpdmVkVGltZTtcblxuICAgIHRoaXMuc2VydmVyVGltZVJlcXVlc3RzKys7XG5cbiAgICBpZiAodGhpcy5zZXJ2ZXJUaW1lUmVxdWVzdHMgPD0gMTApIHtcbiAgICAgIHRoaXMudGltZU9mZnNldHMucHVzaCh0aW1lT2Zmc2V0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy50aW1lT2Zmc2V0c1t0aGlzLnNlcnZlclRpbWVSZXF1ZXN0cyAlIDEwXSA9IHRpbWVPZmZzZXQ7XG4gICAgfVxuXG4gICAgdGhpcy5hdmdUaW1lT2Zmc2V0ID0gdGhpcy50aW1lT2Zmc2V0cy5yZWR1Y2UoKGFjYywgb2Zmc2V0KSA9PiAoYWNjICs9IG9mZnNldCksIDApIC8gdGhpcy50aW1lT2Zmc2V0cy5sZW5ndGg7XG5cbiAgICBpZiAodGhpcy5zZXJ2ZXJUaW1lUmVxdWVzdHMgPiAxMCkge1xuICAgICAgZGVidWcoYG5ldyBzZXJ2ZXIgdGltZSBvZmZzZXQ6ICR7dGhpcy5hdmdUaW1lT2Zmc2V0fW1zYCk7XG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMudXBkYXRlVGltZU9mZnNldCgpLCA1ICogNjAgKiAxMDAwKTsgLy8gU3luYyBjbG9jayBldmVyeSA1IG1pbnV0ZXMuXG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMudXBkYXRlVGltZU9mZnNldCgpO1xuICAgIH1cbiAgfVxuXG4gIGdldFNlcnZlclRpbWUoKSB7XG4gICAgcmV0dXJuIERhdGUubm93KCkgKyB0aGlzLmF2Z1RpbWVPZmZzZXQ7XG4gIH1cblxuICBnZXRNZWRpYVN0cmVhbShjbGllbnRJZCwgdHlwZSA9IFwiYXVkaW9cIikge1xuICAgIGlmICh0aGlzLm1lZGlhU3RyZWFtc1tjbGllbnRJZF0pIHtcbiAgICAgIGRlYnVnKGBBbHJlYWR5IGhhZCAke3R5cGV9IGZvciAke2NsaWVudElkfWApO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh0aGlzLm1lZGlhU3RyZWFtc1tjbGllbnRJZF1bdHlwZV0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWJ1ZyhgV2FpdGluZyBvbiAke3R5cGV9IGZvciAke2NsaWVudElkfWApO1xuICAgICAgaWYgKCF0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmhhcyhjbGllbnRJZCkpIHtcbiAgICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5zZXQoY2xpZW50SWQsIHt9KTtcblxuICAgICAgICBjb25zdCBhdWRpb1Byb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5nZXQoY2xpZW50SWQpLmF1ZGlvID0geyByZXNvbHZlLCByZWplY3QgfTtcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHZpZGVvUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChjbGllbnRJZCkudmlkZW8gPSB7IHJlc29sdmUsIHJlamVjdCB9O1xuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChjbGllbnRJZCkuYXVkaW8ucHJvbWlzZSA9IGF1ZGlvUHJvbWlzZTtcbiAgICAgICAgdGhpcy5wZW5kaW5nTWVkaWFSZXF1ZXN0cy5nZXQoY2xpZW50SWQpLnZpZGVvLnByb21pc2UgPSB2aWRlb1Byb21pc2U7XG5cbiAgICAgICAgYXVkaW9Qcm9taXNlLmNhdGNoKGUgPT4gY29uc29sZS53YXJuKGAke2NsaWVudElkfSBnZXRNZWRpYVN0cmVhbSBBdWRpbyBFcnJvcmAsIGUpKTtcbiAgICAgICAgdmlkZW9Qcm9taXNlLmNhdGNoKGUgPT4gY29uc29sZS53YXJuKGAke2NsaWVudElkfSBnZXRNZWRpYVN0cmVhbSBWaWRlbyBFcnJvcmAsIGUpKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmdldChjbGllbnRJZClbdHlwZV0ucHJvbWlzZTtcbiAgICB9XG4gIH1cblxuICBzZXRNZWRpYVN0cmVhbShjbGllbnRJZCwgc3RyZWFtKSB7XG4gICAgLy8gU2FmYXJpIGRvZXNuJ3QgbGlrZSBpdCB3aGVuIHlvdSB1c2Ugc2luZ2xlIGEgbWl4ZWQgbWVkaWEgc3RyZWFtIHdoZXJlIG9uZSBvZiB0aGUgdHJhY2tzIGlzIGluYWN0aXZlLCBzbyB3ZVxuICAgIC8vIHNwbGl0IHRoZSB0cmFja3MgaW50byB0d28gc3RyZWFtcy5cbiAgICBjb25zdCBhdWRpb1N0cmVhbSA9IG5ldyBNZWRpYVN0cmVhbSgpO1xuICAgIHRyeSB7XG4gICAgc3RyZWFtLmdldEF1ZGlvVHJhY2tzKCkuZm9yRWFjaCh0cmFjayA9PiBhdWRpb1N0cmVhbS5hZGRUcmFjayh0cmFjaykpO1xuXG4gICAgfSBjYXRjaChlKSB7XG4gICAgICBjb25zb2xlLndhcm4oYCR7Y2xpZW50SWR9IHNldE1lZGlhU3RyZWFtIEF1ZGlvIEVycm9yYCwgZSk7XG4gICAgfVxuICAgIGNvbnN0IHZpZGVvU3RyZWFtID0gbmV3IE1lZGlhU3RyZWFtKCk7XG4gICAgdHJ5IHtcbiAgICBzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5mb3JFYWNoKHRyYWNrID0+IHZpZGVvU3RyZWFtLmFkZFRyYWNrKHRyYWNrKSk7XG5cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjb25zb2xlLndhcm4oYCR7Y2xpZW50SWR9IHNldE1lZGlhU3RyZWFtIFZpZGVvIEVycm9yYCwgZSk7XG4gICAgfVxuXG4gICAgdGhpcy5tZWRpYVN0cmVhbXNbY2xpZW50SWRdID0geyBhdWRpbzogYXVkaW9TdHJlYW0sIHZpZGVvOiB2aWRlb1N0cmVhbSB9O1xuXG4gICAgLy8gUmVzb2x2ZSB0aGUgcHJvbWlzZSBmb3IgdGhlIHVzZXIncyBtZWRpYSBzdHJlYW0gaWYgaXQgZXhpc3RzLlxuICAgIGlmICh0aGlzLnBlbmRpbmdNZWRpYVJlcXVlc3RzLmhhcyhjbGllbnRJZCkpIHtcbiAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KGNsaWVudElkKS5hdWRpby5yZXNvbHZlKGF1ZGlvU3RyZWFtKTtcbiAgICAgIHRoaXMucGVuZGluZ01lZGlhUmVxdWVzdHMuZ2V0KGNsaWVudElkKS52aWRlby5yZXNvbHZlKHZpZGVvU3RyZWFtKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBzZXRMb2NhbE1lZGlhU3RyZWFtKHN0cmVhbSkge1xuICAgIC8vIG91ciBqb2IgaGVyZSBpcyB0byBtYWtlIHN1cmUgdGhlIGNvbm5lY3Rpb24gd2luZHMgdXAgd2l0aCBSVFAgc2VuZGVycyBzZW5kaW5nIHRoZSBzdHVmZiBpbiB0aGlzIHN0cmVhbSxcbiAgICAvLyBhbmQgbm90IHRoZSBzdHVmZiB0aGF0IGlzbid0IGluIHRoaXMgc3RyZWFtLiBzdHJhdGVneSBpcyB0byByZXBsYWNlIGV4aXN0aW5nIHRyYWNrcyBpZiB3ZSBjYW4sIGFkZCB0cmFja3NcbiAgICAvLyB0aGF0IHdlIGNhbid0IHJlcGxhY2UsIGFuZCBkaXNhYmxlIHRyYWNrcyB0aGF0IGRvbid0IGV4aXN0IGFueW1vcmUuXG5cbiAgICAvLyBub3RlIHRoYXQgd2UgZG9uJ3QgZXZlciByZW1vdmUgYSB0cmFjayBmcm9tIHRoZSBzdHJlYW0gLS0gc2luY2UgSmFudXMgZG9lc24ndCBzdXBwb3J0IFVuaWZpZWQgUGxhbiwgd2UgYWJzb2x1dGVseVxuICAgIC8vIGNhbid0IHdpbmQgdXAgd2l0aCBhIFNEUCB0aGF0IGhhcyA+MSBhdWRpbyBvciA+MSB2aWRlbyB0cmFja3MsIGV2ZW4gaWYgb25lIG9mIHRoZW0gaXMgaW5hY3RpdmUgKHdoYXQgeW91IGdldCBpZlxuICAgIC8vIHlvdSByZW1vdmUgYSB0cmFjayBmcm9tIGFuIGV4aXN0aW5nIHN0cmVhbS4pXG4gICAgaWYgKHRoaXMucHVibGlzaGVyICYmIHRoaXMucHVibGlzaGVyLmNvbm4pIHtcbiAgICAgIGNvbnN0IGV4aXN0aW5nU2VuZGVycyA9IHRoaXMucHVibGlzaGVyLmNvbm4uZ2V0U2VuZGVycygpO1xuICAgICAgY29uc3QgbmV3U2VuZGVycyA9IFtdO1xuICAgICAgY29uc3QgdHJhY2tzID0gc3RyZWFtLmdldFRyYWNrcygpO1xuXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRyYWNrcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zdCB0ID0gdHJhY2tzW2ldO1xuICAgICAgICBjb25zdCBzZW5kZXIgPSBleGlzdGluZ1NlbmRlcnMuZmluZChzID0+IHMudHJhY2sgIT0gbnVsbCAmJiBzLnRyYWNrLmtpbmQgPT0gdC5raW5kKTtcblxuICAgICAgICBpZiAoc2VuZGVyICE9IG51bGwpIHtcbiAgICAgICAgICBpZiAoc2VuZGVyLnJlcGxhY2VUcmFjaykge1xuICAgICAgICAgICAgYXdhaXQgc2VuZGVyLnJlcGxhY2VUcmFjayh0KTtcblxuICAgICAgICAgICAgLy8gV29ya2Fyb3VuZCBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD0xNTc2NzcxXG4gICAgICAgICAgICBpZiAodC5raW5kID09PSBcInZpZGVvXCIgJiYgdC5lbmFibGVkICYmIG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5pbmRleE9mKCdmaXJlZm94JykgPiAtMSkge1xuICAgICAgICAgICAgICB0LmVuYWJsZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0LmVuYWJsZWQgPSB0cnVlLCAxMDAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gRmFsbGJhY2sgZm9yIGJyb3dzZXJzIHRoYXQgZG9uJ3Qgc3VwcG9ydCByZXBsYWNlVHJhY2suIEF0IHRoaXMgdGltZSBvZiB0aGlzIHdyaXRpbmdcbiAgICAgICAgICAgIC8vIG1vc3QgYnJvd3NlcnMgc3VwcG9ydCBpdCwgYW5kIHRlc3RpbmcgdGhpcyBjb2RlIHBhdGggc2VlbXMgdG8gbm90IHdvcmsgcHJvcGVybHlcbiAgICAgICAgICAgIC8vIGluIENocm9tZSBhbnltb3JlLlxuICAgICAgICAgICAgc3RyZWFtLnJlbW92ZVRyYWNrKHNlbmRlci50cmFjayk7XG4gICAgICAgICAgICBzdHJlYW0uYWRkVHJhY2sodCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIG5ld1NlbmRlcnMucHVzaChzZW5kZXIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG5ld1NlbmRlcnMucHVzaCh0aGlzLnB1Ymxpc2hlci5jb25uLmFkZFRyYWNrKHQsIHN0cmVhbSkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBleGlzdGluZ1NlbmRlcnMuZm9yRWFjaChzID0+IHtcbiAgICAgICAgaWYgKCFuZXdTZW5kZXJzLmluY2x1ZGVzKHMpKSB7XG4gICAgICAgICAgcy50cmFjay5lbmFibGVkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgICB0aGlzLmxvY2FsTWVkaWFTdHJlYW0gPSBzdHJlYW07XG4gICAgdGhpcy5zZXRNZWRpYVN0cmVhbSh0aGlzLmNsaWVudElkLCBzdHJlYW0pO1xuICB9XG5cbiAgZW5hYmxlTWljcm9waG9uZShlbmFibGVkKSB7XG4gICAgaWYgKHRoaXMucHVibGlzaGVyICYmIHRoaXMucHVibGlzaGVyLmNvbm4pIHtcbiAgICAgIHRoaXMucHVibGlzaGVyLmNvbm4uZ2V0U2VuZGVycygpLmZvckVhY2gocyA9PiB7XG4gICAgICAgIGlmIChzLnRyYWNrLmtpbmQgPT0gXCJhdWRpb1wiKSB7XG4gICAgICAgICAgcy50cmFjay5lbmFibGVkID0gZW5hYmxlZDtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgc2VuZERhdGEoY2xpZW50SWQsIGRhdGFUeXBlLCBkYXRhKSB7XG4gICAgaWYgKCF0aGlzLnB1Ymxpc2hlcikge1xuICAgICAgY29uc29sZS53YXJuKFwic2VuZERhdGEgY2FsbGVkIHdpdGhvdXQgYSBwdWJsaXNoZXJcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXRjaCAodGhpcy51bnJlbGlhYmxlVHJhbnNwb3J0KSB7XG4gICAgICAgIGNhc2UgXCJ3ZWJzb2NrZXRcIjpcbiAgICAgICAgICBpZiAodGhpcy53cy5yZWFkeVN0YXRlID09PSAxKSB7IC8vIE9QRU5cbiAgICAgICAgICAgIHRoaXMucHVibGlzaGVyLmhhbmRsZS5zZW5kTWVzc2FnZSh7IGtpbmQ6IFwiZGF0YVwiLCBib2R5OiBKU09OLnN0cmluZ2lmeSh7IGRhdGFUeXBlLCBkYXRhIH0pLCB3aG9tOiBjbGllbnRJZCB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJkYXRhY2hhbm5lbFwiOlxuICAgICAgICAgIGlmICh0aGlzLnB1Ymxpc2hlci51bnJlbGlhYmxlQ2hhbm5lbC5yZWFkeVN0YXRlID09PSBcIm9wZW5cIikge1xuICAgICAgICAgICAgdGhpcy5wdWJsaXNoZXIudW5yZWxpYWJsZUNoYW5uZWwuc2VuZChKU09OLnN0cmluZ2lmeSh7IGNsaWVudElkLCBkYXRhVHlwZSwgZGF0YSB9KSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRoaXMudW5yZWxpYWJsZVRyYW5zcG9ydChjbGllbnRJZCwgZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHNlbmREYXRhR3VhcmFudGVlZChjbGllbnRJZCwgZGF0YVR5cGUsIGRhdGEpIHtcbiAgICBpZiAoIXRoaXMucHVibGlzaGVyKSB7XG4gICAgICBjb25zb2xlLndhcm4oXCJzZW5kRGF0YUd1YXJhbnRlZWQgY2FsbGVkIHdpdGhvdXQgYSBwdWJsaXNoZXJcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXRjaCAodGhpcy5yZWxpYWJsZVRyYW5zcG9ydCkge1xuICAgICAgICBjYXNlIFwid2Vic29ja2V0XCI6XG4gICAgICAgICAgaWYgKHRoaXMud3MucmVhZHlTdGF0ZSA9PT0gMSkgeyAvLyBPUEVOXG4gICAgICAgICAgICB0aGlzLnB1Ymxpc2hlci5oYW5kbGUuc2VuZE1lc3NhZ2UoeyBraW5kOiBcImRhdGFcIiwgYm9keTogSlNPTi5zdHJpbmdpZnkoeyBkYXRhVHlwZSwgZGF0YSB9KSwgd2hvbTogY2xpZW50SWQgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiZGF0YWNoYW5uZWxcIjpcbiAgICAgICAgICBpZiAodGhpcy5wdWJsaXNoZXIucmVsaWFibGVDaGFubmVsLnJlYWR5U3RhdGUgPT09IFwib3BlblwiKSB7XG4gICAgICAgICAgICB0aGlzLnB1Ymxpc2hlci5yZWxpYWJsZUNoYW5uZWwuc2VuZChKU09OLnN0cmluZ2lmeSh7IGNsaWVudElkLCBkYXRhVHlwZSwgZGF0YSB9KSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRoaXMucmVsaWFibGVUcmFuc3BvcnQoY2xpZW50SWQsIGRhdGFUeXBlLCBkYXRhKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBicm9hZGNhc3REYXRhKGRhdGFUeXBlLCBkYXRhKSB7XG4gICAgaWYgKCF0aGlzLnB1Ymxpc2hlcikge1xuICAgICAgY29uc29sZS53YXJuKFwiYnJvYWRjYXN0RGF0YSBjYWxsZWQgd2l0aG91dCBhIHB1Ymxpc2hlclwiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3dpdGNoICh0aGlzLnVucmVsaWFibGVUcmFuc3BvcnQpIHtcbiAgICAgICAgY2FzZSBcIndlYnNvY2tldFwiOlxuICAgICAgICAgIGlmICh0aGlzLndzLnJlYWR5U3RhdGUgPT09IDEpIHsgLy8gT1BFTlxuICAgICAgICAgICAgdGhpcy5wdWJsaXNoZXIuaGFuZGxlLnNlbmRNZXNzYWdlKHsga2luZDogXCJkYXRhXCIsIGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgZGF0YVR5cGUsIGRhdGEgfSkgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiZGF0YWNoYW5uZWxcIjpcbiAgICAgICAgICBpZiAodGhpcy5wdWJsaXNoZXIudW5yZWxpYWJsZUNoYW5uZWwucmVhZHlTdGF0ZSA9PT0gXCJvcGVuXCIpIHtcbiAgICAgICAgICAgIHRoaXMucHVibGlzaGVyLnVucmVsaWFibGVDaGFubmVsLnNlbmQoSlNPTi5zdHJpbmdpZnkoeyBkYXRhVHlwZSwgZGF0YSB9KSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRoaXMudW5yZWxpYWJsZVRyYW5zcG9ydCh1bmRlZmluZWQsIGRhdGFUeXBlLCBkYXRhKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBicm9hZGNhc3REYXRhR3VhcmFudGVlZChkYXRhVHlwZSwgZGF0YSkge1xuICAgIGlmICghdGhpcy5wdWJsaXNoZXIpIHtcbiAgICAgIGNvbnNvbGUud2FybihcImJyb2FkY2FzdERhdGFHdWFyYW50ZWVkIGNhbGxlZCB3aXRob3V0IGEgcHVibGlzaGVyXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzd2l0Y2ggKHRoaXMucmVsaWFibGVUcmFuc3BvcnQpIHtcbiAgICAgICAgY2FzZSBcIndlYnNvY2tldFwiOlxuICAgICAgICAgIGlmICh0aGlzLndzLnJlYWR5U3RhdGUgPT09IDEpIHsgLy8gT1BFTlxuICAgICAgICAgICAgdGhpcy5wdWJsaXNoZXIuaGFuZGxlLnNlbmRNZXNzYWdlKHsga2luZDogXCJkYXRhXCIsIGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgZGF0YVR5cGUsIGRhdGEgfSkgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiZGF0YWNoYW5uZWxcIjpcbiAgICAgICAgICBpZiAodGhpcy5wdWJsaXNoZXIucmVsaWFibGVDaGFubmVsLnJlYWR5U3RhdGUgPT09IFwib3BlblwiKSB7XG4gICAgICAgICAgICB0aGlzLnB1Ymxpc2hlci5yZWxpYWJsZUNoYW5uZWwuc2VuZChKU09OLnN0cmluZ2lmeSh7IGRhdGFUeXBlLCBkYXRhIH0pKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy5yZWxpYWJsZVRyYW5zcG9ydCh1bmRlZmluZWQsIGRhdGFUeXBlLCBkYXRhKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBraWNrKGNsaWVudElkLCBwZXJtc1Rva2VuKSB7XG4gICAgcmV0dXJuIHRoaXMucHVibGlzaGVyLmhhbmRsZS5zZW5kTWVzc2FnZSh7IGtpbmQ6IFwia2lja1wiLCByb29tX2lkOiB0aGlzLnJvb20sIHVzZXJfaWQ6IGNsaWVudElkLCB0b2tlbjogcGVybXNUb2tlbiB9KS50aGVuKCgpID0+IHtcbiAgICAgIGRvY3VtZW50LmJvZHkuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoXCJraWNrZWRcIiwgeyBkZXRhaWw6IHsgY2xpZW50SWQ6IGNsaWVudElkIH0gfSkpO1xuICAgIH0pO1xuICB9XG5cbiAgYmxvY2soY2xpZW50SWQpIHtcbiAgICByZXR1cm4gdGhpcy5wdWJsaXNoZXIuaGFuZGxlLnNlbmRNZXNzYWdlKHsga2luZDogXCJibG9ja1wiLCB3aG9tOiBjbGllbnRJZCB9KS50aGVuKCgpID0+IHtcbiAgICAgIHRoaXMuYmxvY2tlZENsaWVudHMuc2V0KGNsaWVudElkLCB0cnVlKTtcbiAgICAgIGRvY3VtZW50LmJvZHkuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoXCJibG9ja2VkXCIsIHsgZGV0YWlsOiB7IGNsaWVudElkOiBjbGllbnRJZCB9IH0pKTtcbiAgICB9KTtcbiAgfVxuXG4gIHVuYmxvY2soY2xpZW50SWQpIHtcbiAgICByZXR1cm4gdGhpcy5wdWJsaXNoZXIuaGFuZGxlLnNlbmRNZXNzYWdlKHsga2luZDogXCJ1bmJsb2NrXCIsIHdob206IGNsaWVudElkIH0pLnRoZW4oKCkgPT4ge1xuICAgICAgdGhpcy5ibG9ja2VkQ2xpZW50cy5kZWxldGUoY2xpZW50SWQpO1xuICAgICAgZG9jdW1lbnQuYm9keS5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChcInVuYmxvY2tlZFwiLCB7IGRldGFpbDogeyBjbGllbnRJZDogY2xpZW50SWQgfSB9KSk7XG4gICAgfSk7XG4gIH1cbn1cblxuTkFGLmFkYXB0ZXJzLnJlZ2lzdGVyKFwiamFudXNcIiwgSmFudXNBZGFwdGVyKTtcblxubW9kdWxlLmV4cG9ydHMgPSBKYW51c0FkYXB0ZXI7XG4iLCIvKiBlc2xpbnQtZW52IGJyb3dzZXIgKi9cblxuLyoqXG4gKiBUaGlzIGlzIHRoZSB3ZWIgYnJvd3NlciBpbXBsZW1lbnRhdGlvbiBvZiBgZGVidWcoKWAuXG4gKi9cblxuZXhwb3J0cy5mb3JtYXRBcmdzID0gZm9ybWF0QXJncztcbmV4cG9ydHMuc2F2ZSA9IHNhdmU7XG5leHBvcnRzLmxvYWQgPSBsb2FkO1xuZXhwb3J0cy51c2VDb2xvcnMgPSB1c2VDb2xvcnM7XG5leHBvcnRzLnN0b3JhZ2UgPSBsb2NhbHN0b3JhZ2UoKTtcbmV4cG9ydHMuZGVzdHJveSA9ICgoKSA9PiB7XG5cdGxldCB3YXJuZWQgPSBmYWxzZTtcblxuXHRyZXR1cm4gKCkgPT4ge1xuXHRcdGlmICghd2FybmVkKSB7XG5cdFx0XHR3YXJuZWQgPSB0cnVlO1xuXHRcdFx0Y29uc29sZS53YXJuKCdJbnN0YW5jZSBtZXRob2QgYGRlYnVnLmRlc3Ryb3koKWAgaXMgZGVwcmVjYXRlZCBhbmQgbm8gbG9uZ2VyIGRvZXMgYW55dGhpbmcuIEl0IHdpbGwgYmUgcmVtb3ZlZCBpbiB0aGUgbmV4dCBtYWpvciB2ZXJzaW9uIG9mIGBkZWJ1Z2AuJyk7XG5cdFx0fVxuXHR9O1xufSkoKTtcblxuLyoqXG4gKiBDb2xvcnMuXG4gKi9cblxuZXhwb3J0cy5jb2xvcnMgPSBbXG5cdCcjMDAwMENDJyxcblx0JyMwMDAwRkYnLFxuXHQnIzAwMzNDQycsXG5cdCcjMDAzM0ZGJyxcblx0JyMwMDY2Q0MnLFxuXHQnIzAwNjZGRicsXG5cdCcjMDA5OUNDJyxcblx0JyMwMDk5RkYnLFxuXHQnIzAwQ0MwMCcsXG5cdCcjMDBDQzMzJyxcblx0JyMwMENDNjYnLFxuXHQnIzAwQ0M5OScsXG5cdCcjMDBDQ0NDJyxcblx0JyMwMENDRkYnLFxuXHQnIzMzMDBDQycsXG5cdCcjMzMwMEZGJyxcblx0JyMzMzMzQ0MnLFxuXHQnIzMzMzNGRicsXG5cdCcjMzM2NkNDJyxcblx0JyMzMzY2RkYnLFxuXHQnIzMzOTlDQycsXG5cdCcjMzM5OUZGJyxcblx0JyMzM0NDMDAnLFxuXHQnIzMzQ0MzMycsXG5cdCcjMzNDQzY2Jyxcblx0JyMzM0NDOTknLFxuXHQnIzMzQ0NDQycsXG5cdCcjMzNDQ0ZGJyxcblx0JyM2NjAwQ0MnLFxuXHQnIzY2MDBGRicsXG5cdCcjNjYzM0NDJyxcblx0JyM2NjMzRkYnLFxuXHQnIzY2Q0MwMCcsXG5cdCcjNjZDQzMzJyxcblx0JyM5OTAwQ0MnLFxuXHQnIzk5MDBGRicsXG5cdCcjOTkzM0NDJyxcblx0JyM5OTMzRkYnLFxuXHQnIzk5Q0MwMCcsXG5cdCcjOTlDQzMzJyxcblx0JyNDQzAwMDAnLFxuXHQnI0NDMDAzMycsXG5cdCcjQ0MwMDY2Jyxcblx0JyNDQzAwOTknLFxuXHQnI0NDMDBDQycsXG5cdCcjQ0MwMEZGJyxcblx0JyNDQzMzMDAnLFxuXHQnI0NDMzMzMycsXG5cdCcjQ0MzMzY2Jyxcblx0JyNDQzMzOTknLFxuXHQnI0NDMzNDQycsXG5cdCcjQ0MzM0ZGJyxcblx0JyNDQzY2MDAnLFxuXHQnI0NDNjYzMycsXG5cdCcjQ0M5OTAwJyxcblx0JyNDQzk5MzMnLFxuXHQnI0NDQ0MwMCcsXG5cdCcjQ0NDQzMzJyxcblx0JyNGRjAwMDAnLFxuXHQnI0ZGMDAzMycsXG5cdCcjRkYwMDY2Jyxcblx0JyNGRjAwOTknLFxuXHQnI0ZGMDBDQycsXG5cdCcjRkYwMEZGJyxcblx0JyNGRjMzMDAnLFxuXHQnI0ZGMzMzMycsXG5cdCcjRkYzMzY2Jyxcblx0JyNGRjMzOTknLFxuXHQnI0ZGMzNDQycsXG5cdCcjRkYzM0ZGJyxcblx0JyNGRjY2MDAnLFxuXHQnI0ZGNjYzMycsXG5cdCcjRkY5OTAwJyxcblx0JyNGRjk5MzMnLFxuXHQnI0ZGQ0MwMCcsXG5cdCcjRkZDQzMzJ1xuXTtcblxuLyoqXG4gKiBDdXJyZW50bHkgb25seSBXZWJLaXQtYmFzZWQgV2ViIEluc3BlY3RvcnMsIEZpcmVmb3ggPj0gdjMxLFxuICogYW5kIHRoZSBGaXJlYnVnIGV4dGVuc2lvbiAoYW55IEZpcmVmb3ggdmVyc2lvbikgYXJlIGtub3duXG4gKiB0byBzdXBwb3J0IFwiJWNcIiBDU1MgY3VzdG9taXphdGlvbnMuXG4gKlxuICogVE9ETzogYWRkIGEgYGxvY2FsU3RvcmFnZWAgdmFyaWFibGUgdG8gZXhwbGljaXRseSBlbmFibGUvZGlzYWJsZSBjb2xvcnNcbiAqL1xuXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY29tcGxleGl0eVxuZnVuY3Rpb24gdXNlQ29sb3JzKCkge1xuXHQvLyBOQjogSW4gYW4gRWxlY3Ryb24gcHJlbG9hZCBzY3JpcHQsIGRvY3VtZW50IHdpbGwgYmUgZGVmaW5lZCBidXQgbm90IGZ1bGx5XG5cdC8vIGluaXRpYWxpemVkLiBTaW5jZSB3ZSBrbm93IHdlJ3JlIGluIENocm9tZSwgd2UnbGwganVzdCBkZXRlY3QgdGhpcyBjYXNlXG5cdC8vIGV4cGxpY2l0bHlcblx0aWYgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHdpbmRvdy5wcm9jZXNzICYmICh3aW5kb3cucHJvY2Vzcy50eXBlID09PSAncmVuZGVyZXInIHx8IHdpbmRvdy5wcm9jZXNzLl9fbndqcykpIHtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXG5cdC8vIEludGVybmV0IEV4cGxvcmVyIGFuZCBFZGdlIGRvIG5vdCBzdXBwb3J0IGNvbG9ycy5cblx0aWYgKHR5cGVvZiBuYXZpZ2F0b3IgIT09ICd1bmRlZmluZWQnICYmIG5hdmlnYXRvci51c2VyQWdlbnQgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudC50b0xvd2VyQ2FzZSgpLm1hdGNoKC8oZWRnZXx0cmlkZW50KVxcLyhcXGQrKS8pKSB7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG5cblx0Ly8gSXMgd2Via2l0PyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8xNjQ1OTYwNi8zNzY3NzNcblx0Ly8gZG9jdW1lbnQgaXMgdW5kZWZpbmVkIGluIHJlYWN0LW5hdGl2ZTogaHR0cHM6Ly9naXRodWIuY29tL2ZhY2Vib29rL3JlYWN0LW5hdGl2ZS9wdWxsLzE2MzJcblx0cmV0dXJuICh0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCAmJiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGUgJiYgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlLldlYmtpdEFwcGVhcmFuY2UpIHx8XG5cdFx0Ly8gSXMgZmlyZWJ1Zz8gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzk4MTIwLzM3Njc3M1xuXHRcdCh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiB3aW5kb3cuY29uc29sZSAmJiAod2luZG93LmNvbnNvbGUuZmlyZWJ1ZyB8fCAod2luZG93LmNvbnNvbGUuZXhjZXB0aW9uICYmIHdpbmRvdy5jb25zb2xlLnRhYmxlKSkpIHx8XG5cdFx0Ly8gSXMgZmlyZWZveCA+PSB2MzE/XG5cdFx0Ly8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9Ub29scy9XZWJfQ29uc29sZSNTdHlsaW5nX21lc3NhZ2VzXG5cdFx0KHR5cGVvZiBuYXZpZ2F0b3IgIT09ICd1bmRlZmluZWQnICYmIG5hdmlnYXRvci51c2VyQWdlbnQgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudC50b0xvd2VyQ2FzZSgpLm1hdGNoKC9maXJlZm94XFwvKFxcZCspLykgJiYgcGFyc2VJbnQoUmVnRXhwLiQxLCAxMCkgPj0gMzEpIHx8XG5cdFx0Ly8gRG91YmxlIGNoZWNrIHdlYmtpdCBpbiB1c2VyQWdlbnQganVzdCBpbiBjYXNlIHdlIGFyZSBpbiBhIHdvcmtlclxuXHRcdCh0eXBlb2YgbmF2aWdhdG9yICE9PSAndW5kZWZpbmVkJyAmJiBuYXZpZ2F0b3IudXNlckFnZW50ICYmIG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5tYXRjaCgvYXBwbGV3ZWJraXRcXC8oXFxkKykvKSk7XG59XG5cbi8qKlxuICogQ29sb3JpemUgbG9nIGFyZ3VtZW50cyBpZiBlbmFibGVkLlxuICpcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuZnVuY3Rpb24gZm9ybWF0QXJncyhhcmdzKSB7XG5cdGFyZ3NbMF0gPSAodGhpcy51c2VDb2xvcnMgPyAnJWMnIDogJycpICtcblx0XHR0aGlzLm5hbWVzcGFjZSArXG5cdFx0KHRoaXMudXNlQ29sb3JzID8gJyAlYycgOiAnICcpICtcblx0XHRhcmdzWzBdICtcblx0XHQodGhpcy51c2VDb2xvcnMgPyAnJWMgJyA6ICcgJykgK1xuXHRcdCcrJyArIG1vZHVsZS5leHBvcnRzLmh1bWFuaXplKHRoaXMuZGlmZik7XG5cblx0aWYgKCF0aGlzLnVzZUNvbG9ycykge1xuXHRcdHJldHVybjtcblx0fVxuXG5cdGNvbnN0IGMgPSAnY29sb3I6ICcgKyB0aGlzLmNvbG9yO1xuXHRhcmdzLnNwbGljZSgxLCAwLCBjLCAnY29sb3I6IGluaGVyaXQnKTtcblxuXHQvLyBUaGUgZmluYWwgXCIlY1wiIGlzIHNvbWV3aGF0IHRyaWNreSwgYmVjYXVzZSB0aGVyZSBjb3VsZCBiZSBvdGhlclxuXHQvLyBhcmd1bWVudHMgcGFzc2VkIGVpdGhlciBiZWZvcmUgb3IgYWZ0ZXIgdGhlICVjLCBzbyB3ZSBuZWVkIHRvXG5cdC8vIGZpZ3VyZSBvdXQgdGhlIGNvcnJlY3QgaW5kZXggdG8gaW5zZXJ0IHRoZSBDU1MgaW50b1xuXHRsZXQgaW5kZXggPSAwO1xuXHRsZXQgbGFzdEMgPSAwO1xuXHRhcmdzWzBdLnJlcGxhY2UoLyVbYS16QS1aJV0vZywgbWF0Y2ggPT4ge1xuXHRcdGlmIChtYXRjaCA9PT0gJyUlJykge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRpbmRleCsrO1xuXHRcdGlmIChtYXRjaCA9PT0gJyVjJykge1xuXHRcdFx0Ly8gV2Ugb25seSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgKmxhc3QqICVjXG5cdFx0XHQvLyAodGhlIHVzZXIgbWF5IGhhdmUgcHJvdmlkZWQgdGhlaXIgb3duKVxuXHRcdFx0bGFzdEMgPSBpbmRleDtcblx0XHR9XG5cdH0pO1xuXG5cdGFyZ3Muc3BsaWNlKGxhc3RDLCAwLCBjKTtcbn1cblxuLyoqXG4gKiBJbnZva2VzIGBjb25zb2xlLmRlYnVnKClgIHdoZW4gYXZhaWxhYmxlLlxuICogTm8tb3Agd2hlbiBgY29uc29sZS5kZWJ1Z2AgaXMgbm90IGEgXCJmdW5jdGlvblwiLlxuICogSWYgYGNvbnNvbGUuZGVidWdgIGlzIG5vdCBhdmFpbGFibGUsIGZhbGxzIGJhY2tcbiAqIHRvIGBjb25zb2xlLmxvZ2AuXG4gKlxuICogQGFwaSBwdWJsaWNcbiAqL1xuZXhwb3J0cy5sb2cgPSBjb25zb2xlLmRlYnVnIHx8IGNvbnNvbGUubG9nIHx8ICgoKSA9PiB7fSk7XG5cbi8qKlxuICogU2F2ZSBgbmFtZXNwYWNlc2AuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWVzcGFjZXNcbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBzYXZlKG5hbWVzcGFjZXMpIHtcblx0dHJ5IHtcblx0XHRpZiAobmFtZXNwYWNlcykge1xuXHRcdFx0ZXhwb3J0cy5zdG9yYWdlLnNldEl0ZW0oJ2RlYnVnJywgbmFtZXNwYWNlcyk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGV4cG9ydHMuc3RvcmFnZS5yZW1vdmVJdGVtKCdkZWJ1ZycpO1xuXHRcdH1cblx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHQvLyBTd2FsbG93XG5cdFx0Ly8gWFhYIChAUWl4LSkgc2hvdWxkIHdlIGJlIGxvZ2dpbmcgdGhlc2U/XG5cdH1cbn1cblxuLyoqXG4gKiBMb2FkIGBuYW1lc3BhY2VzYC5cbiAqXG4gKiBAcmV0dXJuIHtTdHJpbmd9IHJldHVybnMgdGhlIHByZXZpb3VzbHkgcGVyc2lzdGVkIGRlYnVnIG1vZGVzXG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gbG9hZCgpIHtcblx0bGV0IHI7XG5cdHRyeSB7XG5cdFx0ciA9IGV4cG9ydHMuc3RvcmFnZS5nZXRJdGVtKCdkZWJ1ZycpO1xuXHR9IGNhdGNoIChlcnJvcikge1xuXHRcdC8vIFN3YWxsb3dcblx0XHQvLyBYWFggKEBRaXgtKSBzaG91bGQgd2UgYmUgbG9nZ2luZyB0aGVzZT9cblx0fVxuXG5cdC8vIElmIGRlYnVnIGlzbid0IHNldCBpbiBMUywgYW5kIHdlJ3JlIGluIEVsZWN0cm9uLCB0cnkgdG8gbG9hZCAkREVCVUdcblx0aWYgKCFyICYmIHR5cGVvZiBwcm9jZXNzICE9PSAndW5kZWZpbmVkJyAmJiAnZW52JyBpbiBwcm9jZXNzKSB7XG5cdFx0ciA9IHByb2Nlc3MuZW52LkRFQlVHO1xuXHR9XG5cblx0cmV0dXJuIHI7XG59XG5cbi8qKlxuICogTG9jYWxzdG9yYWdlIGF0dGVtcHRzIHRvIHJldHVybiB0aGUgbG9jYWxzdG9yYWdlLlxuICpcbiAqIFRoaXMgaXMgbmVjZXNzYXJ5IGJlY2F1c2Ugc2FmYXJpIHRocm93c1xuICogd2hlbiBhIHVzZXIgZGlzYWJsZXMgY29va2llcy9sb2NhbHN0b3JhZ2VcbiAqIGFuZCB5b3UgYXR0ZW1wdCB0byBhY2Nlc3MgaXQuXG4gKlxuICogQHJldHVybiB7TG9jYWxTdG9yYWdlfVxuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gbG9jYWxzdG9yYWdlKCkge1xuXHR0cnkge1xuXHRcdC8vIFRWTUxLaXQgKEFwcGxlIFRWIEpTIFJ1bnRpbWUpIGRvZXMgbm90IGhhdmUgYSB3aW5kb3cgb2JqZWN0LCBqdXN0IGxvY2FsU3RvcmFnZSBpbiB0aGUgZ2xvYmFsIGNvbnRleHRcblx0XHQvLyBUaGUgQnJvd3NlciBhbHNvIGhhcyBsb2NhbFN0b3JhZ2UgaW4gdGhlIGdsb2JhbCBjb250ZXh0LlxuXHRcdHJldHVybiBsb2NhbFN0b3JhZ2U7XG5cdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0Ly8gU3dhbGxvd1xuXHRcdC8vIFhYWCAoQFFpeC0pIHNob3VsZCB3ZSBiZSBsb2dnaW5nIHRoZXNlP1xuXHR9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9jb21tb24nKShleHBvcnRzKTtcblxuY29uc3Qge2Zvcm1hdHRlcnN9ID0gbW9kdWxlLmV4cG9ydHM7XG5cbi8qKlxuICogTWFwICVqIHRvIGBKU09OLnN0cmluZ2lmeSgpYCwgc2luY2Ugbm8gV2ViIEluc3BlY3RvcnMgZG8gdGhhdCBieSBkZWZhdWx0LlxuICovXG5cbmZvcm1hdHRlcnMuaiA9IGZ1bmN0aW9uICh2KSB7XG5cdHRyeSB7XG5cdFx0cmV0dXJuIEpTT04uc3RyaW5naWZ5KHYpO1xuXHR9IGNhdGNoIChlcnJvcikge1xuXHRcdHJldHVybiAnW1VuZXhwZWN0ZWRKU09OUGFyc2VFcnJvcl06ICcgKyBlcnJvci5tZXNzYWdlO1xuXHR9XG59O1xuIiwiXG4vKipcbiAqIFRoaXMgaXMgdGhlIGNvbW1vbiBsb2dpYyBmb3IgYm90aCB0aGUgTm9kZS5qcyBhbmQgd2ViIGJyb3dzZXJcbiAqIGltcGxlbWVudGF0aW9ucyBvZiBgZGVidWcoKWAuXG4gKi9cblxuZnVuY3Rpb24gc2V0dXAoZW52KSB7XG5cdGNyZWF0ZURlYnVnLmRlYnVnID0gY3JlYXRlRGVidWc7XG5cdGNyZWF0ZURlYnVnLmRlZmF1bHQgPSBjcmVhdGVEZWJ1Zztcblx0Y3JlYXRlRGVidWcuY29lcmNlID0gY29lcmNlO1xuXHRjcmVhdGVEZWJ1Zy5kaXNhYmxlID0gZGlzYWJsZTtcblx0Y3JlYXRlRGVidWcuZW5hYmxlID0gZW5hYmxlO1xuXHRjcmVhdGVEZWJ1Zy5lbmFibGVkID0gZW5hYmxlZDtcblx0Y3JlYXRlRGVidWcuaHVtYW5pemUgPSByZXF1aXJlKCdtcycpO1xuXHRjcmVhdGVEZWJ1Zy5kZXN0cm95ID0gZGVzdHJveTtcblxuXHRPYmplY3Qua2V5cyhlbnYpLmZvckVhY2goa2V5ID0+IHtcblx0XHRjcmVhdGVEZWJ1Z1trZXldID0gZW52W2tleV07XG5cdH0pO1xuXG5cdC8qKlxuXHQqIFRoZSBjdXJyZW50bHkgYWN0aXZlIGRlYnVnIG1vZGUgbmFtZXMsIGFuZCBuYW1lcyB0byBza2lwLlxuXHQqL1xuXG5cdGNyZWF0ZURlYnVnLm5hbWVzID0gW107XG5cdGNyZWF0ZURlYnVnLnNraXBzID0gW107XG5cblx0LyoqXG5cdCogTWFwIG9mIHNwZWNpYWwgXCIlblwiIGhhbmRsaW5nIGZ1bmN0aW9ucywgZm9yIHRoZSBkZWJ1ZyBcImZvcm1hdFwiIGFyZ3VtZW50LlxuXHQqXG5cdCogVmFsaWQga2V5IG5hbWVzIGFyZSBhIHNpbmdsZSwgbG93ZXIgb3IgdXBwZXItY2FzZSBsZXR0ZXIsIGkuZS4gXCJuXCIgYW5kIFwiTlwiLlxuXHQqL1xuXHRjcmVhdGVEZWJ1Zy5mb3JtYXR0ZXJzID0ge307XG5cblx0LyoqXG5cdCogU2VsZWN0cyBhIGNvbG9yIGZvciBhIGRlYnVnIG5hbWVzcGFjZVxuXHQqIEBwYXJhbSB7U3RyaW5nfSBuYW1lc3BhY2UgVGhlIG5hbWVzcGFjZSBzdHJpbmcgZm9yIHRoZSBkZWJ1ZyBpbnN0YW5jZSB0byBiZSBjb2xvcmVkXG5cdCogQHJldHVybiB7TnVtYmVyfFN0cmluZ30gQW4gQU5TSSBjb2xvciBjb2RlIGZvciB0aGUgZ2l2ZW4gbmFtZXNwYWNlXG5cdCogQGFwaSBwcml2YXRlXG5cdCovXG5cdGZ1bmN0aW9uIHNlbGVjdENvbG9yKG5hbWVzcGFjZSkge1xuXHRcdGxldCBoYXNoID0gMDtcblxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgbmFtZXNwYWNlLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRoYXNoID0gKChoYXNoIDw8IDUpIC0gaGFzaCkgKyBuYW1lc3BhY2UuY2hhckNvZGVBdChpKTtcblx0XHRcdGhhc2ggfD0gMDsgLy8gQ29udmVydCB0byAzMmJpdCBpbnRlZ2VyXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNyZWF0ZURlYnVnLmNvbG9yc1tNYXRoLmFicyhoYXNoKSAlIGNyZWF0ZURlYnVnLmNvbG9ycy5sZW5ndGhdO1xuXHR9XG5cdGNyZWF0ZURlYnVnLnNlbGVjdENvbG9yID0gc2VsZWN0Q29sb3I7XG5cblx0LyoqXG5cdCogQ3JlYXRlIGEgZGVidWdnZXIgd2l0aCB0aGUgZ2l2ZW4gYG5hbWVzcGFjZWAuXG5cdCpcblx0KiBAcGFyYW0ge1N0cmluZ30gbmFtZXNwYWNlXG5cdCogQHJldHVybiB7RnVuY3Rpb259XG5cdCogQGFwaSBwdWJsaWNcblx0Ki9cblx0ZnVuY3Rpb24gY3JlYXRlRGVidWcobmFtZXNwYWNlKSB7XG5cdFx0bGV0IHByZXZUaW1lO1xuXHRcdGxldCBlbmFibGVPdmVycmlkZSA9IG51bGw7XG5cdFx0bGV0IG5hbWVzcGFjZXNDYWNoZTtcblx0XHRsZXQgZW5hYmxlZENhY2hlO1xuXG5cdFx0ZnVuY3Rpb24gZGVidWcoLi4uYXJncykge1xuXHRcdFx0Ly8gRGlzYWJsZWQ/XG5cdFx0XHRpZiAoIWRlYnVnLmVuYWJsZWQpIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBzZWxmID0gZGVidWc7XG5cblx0XHRcdC8vIFNldCBgZGlmZmAgdGltZXN0YW1wXG5cdFx0XHRjb25zdCBjdXJyID0gTnVtYmVyKG5ldyBEYXRlKCkpO1xuXHRcdFx0Y29uc3QgbXMgPSBjdXJyIC0gKHByZXZUaW1lIHx8IGN1cnIpO1xuXHRcdFx0c2VsZi5kaWZmID0gbXM7XG5cdFx0XHRzZWxmLnByZXYgPSBwcmV2VGltZTtcblx0XHRcdHNlbGYuY3VyciA9IGN1cnI7XG5cdFx0XHRwcmV2VGltZSA9IGN1cnI7XG5cblx0XHRcdGFyZ3NbMF0gPSBjcmVhdGVEZWJ1Zy5jb2VyY2UoYXJnc1swXSk7XG5cblx0XHRcdGlmICh0eXBlb2YgYXJnc1swXSAhPT0gJ3N0cmluZycpIHtcblx0XHRcdFx0Ly8gQW55dGhpbmcgZWxzZSBsZXQncyBpbnNwZWN0IHdpdGggJU9cblx0XHRcdFx0YXJncy51bnNoaWZ0KCclTycpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBBcHBseSBhbnkgYGZvcm1hdHRlcnNgIHRyYW5zZm9ybWF0aW9uc1xuXHRcdFx0bGV0IGluZGV4ID0gMDtcblx0XHRcdGFyZ3NbMF0gPSBhcmdzWzBdLnJlcGxhY2UoLyUoW2EtekEtWiVdKS9nLCAobWF0Y2gsIGZvcm1hdCkgPT4ge1xuXHRcdFx0XHQvLyBJZiB3ZSBlbmNvdW50ZXIgYW4gZXNjYXBlZCAlIHRoZW4gZG9uJ3QgaW5jcmVhc2UgdGhlIGFycmF5IGluZGV4XG5cdFx0XHRcdGlmIChtYXRjaCA9PT0gJyUlJykge1xuXHRcdFx0XHRcdHJldHVybiAnJSc7XG5cdFx0XHRcdH1cblx0XHRcdFx0aW5kZXgrKztcblx0XHRcdFx0Y29uc3QgZm9ybWF0dGVyID0gY3JlYXRlRGVidWcuZm9ybWF0dGVyc1tmb3JtYXRdO1xuXHRcdFx0XHRpZiAodHlwZW9mIGZvcm1hdHRlciA9PT0gJ2Z1bmN0aW9uJykge1xuXHRcdFx0XHRcdGNvbnN0IHZhbCA9IGFyZ3NbaW5kZXhdO1xuXHRcdFx0XHRcdG1hdGNoID0gZm9ybWF0dGVyLmNhbGwoc2VsZiwgdmFsKTtcblxuXHRcdFx0XHRcdC8vIE5vdyB3ZSBuZWVkIHRvIHJlbW92ZSBgYXJnc1tpbmRleF1gIHNpbmNlIGl0J3MgaW5saW5lZCBpbiB0aGUgYGZvcm1hdGBcblx0XHRcdFx0XHRhcmdzLnNwbGljZShpbmRleCwgMSk7XG5cdFx0XHRcdFx0aW5kZXgtLTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gbWF0Y2g7XG5cdFx0XHR9KTtcblxuXHRcdFx0Ly8gQXBwbHkgZW52LXNwZWNpZmljIGZvcm1hdHRpbmcgKGNvbG9ycywgZXRjLilcblx0XHRcdGNyZWF0ZURlYnVnLmZvcm1hdEFyZ3MuY2FsbChzZWxmLCBhcmdzKTtcblxuXHRcdFx0Y29uc3QgbG9nRm4gPSBzZWxmLmxvZyB8fCBjcmVhdGVEZWJ1Zy5sb2c7XG5cdFx0XHRsb2dGbi5hcHBseShzZWxmLCBhcmdzKTtcblx0XHR9XG5cblx0XHRkZWJ1Zy5uYW1lc3BhY2UgPSBuYW1lc3BhY2U7XG5cdFx0ZGVidWcudXNlQ29sb3JzID0gY3JlYXRlRGVidWcudXNlQ29sb3JzKCk7XG5cdFx0ZGVidWcuY29sb3IgPSBjcmVhdGVEZWJ1Zy5zZWxlY3RDb2xvcihuYW1lc3BhY2UpO1xuXHRcdGRlYnVnLmV4dGVuZCA9IGV4dGVuZDtcblx0XHRkZWJ1Zy5kZXN0cm95ID0gY3JlYXRlRGVidWcuZGVzdHJveTsgLy8gWFhYIFRlbXBvcmFyeS4gV2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZXh0IG1ham9yIHJlbGVhc2UuXG5cblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZGVidWcsICdlbmFibGVkJywge1xuXHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcblx0XHRcdGNvbmZpZ3VyYWJsZTogZmFsc2UsXG5cdFx0XHRnZXQ6ICgpID0+IHtcblx0XHRcdFx0aWYgKGVuYWJsZU92ZXJyaWRlICE9PSBudWxsKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGVuYWJsZU92ZXJyaWRlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmIChuYW1lc3BhY2VzQ2FjaGUgIT09IGNyZWF0ZURlYnVnLm5hbWVzcGFjZXMpIHtcblx0XHRcdFx0XHRuYW1lc3BhY2VzQ2FjaGUgPSBjcmVhdGVEZWJ1Zy5uYW1lc3BhY2VzO1xuXHRcdFx0XHRcdGVuYWJsZWRDYWNoZSA9IGNyZWF0ZURlYnVnLmVuYWJsZWQobmFtZXNwYWNlKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiBlbmFibGVkQ2FjaGU7XG5cdFx0XHR9LFxuXHRcdFx0c2V0OiB2ID0+IHtcblx0XHRcdFx0ZW5hYmxlT3ZlcnJpZGUgPSB2O1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0Ly8gRW52LXNwZWNpZmljIGluaXRpYWxpemF0aW9uIGxvZ2ljIGZvciBkZWJ1ZyBpbnN0YW5jZXNcblx0XHRpZiAodHlwZW9mIGNyZWF0ZURlYnVnLmluaXQgPT09ICdmdW5jdGlvbicpIHtcblx0XHRcdGNyZWF0ZURlYnVnLmluaXQoZGVidWcpO1xuXHRcdH1cblxuXHRcdHJldHVybiBkZWJ1Zztcblx0fVxuXG5cdGZ1bmN0aW9uIGV4dGVuZChuYW1lc3BhY2UsIGRlbGltaXRlcikge1xuXHRcdGNvbnN0IG5ld0RlYnVnID0gY3JlYXRlRGVidWcodGhpcy5uYW1lc3BhY2UgKyAodHlwZW9mIGRlbGltaXRlciA9PT0gJ3VuZGVmaW5lZCcgPyAnOicgOiBkZWxpbWl0ZXIpICsgbmFtZXNwYWNlKTtcblx0XHRuZXdEZWJ1Zy5sb2cgPSB0aGlzLmxvZztcblx0XHRyZXR1cm4gbmV3RGVidWc7XG5cdH1cblxuXHQvKipcblx0KiBFbmFibGVzIGEgZGVidWcgbW9kZSBieSBuYW1lc3BhY2VzLiBUaGlzIGNhbiBpbmNsdWRlIG1vZGVzXG5cdCogc2VwYXJhdGVkIGJ5IGEgY29sb24gYW5kIHdpbGRjYXJkcy5cblx0KlxuXHQqIEBwYXJhbSB7U3RyaW5nfSBuYW1lc3BhY2VzXG5cdCogQGFwaSBwdWJsaWNcblx0Ki9cblx0ZnVuY3Rpb24gZW5hYmxlKG5hbWVzcGFjZXMpIHtcblx0XHRjcmVhdGVEZWJ1Zy5zYXZlKG5hbWVzcGFjZXMpO1xuXHRcdGNyZWF0ZURlYnVnLm5hbWVzcGFjZXMgPSBuYW1lc3BhY2VzO1xuXG5cdFx0Y3JlYXRlRGVidWcubmFtZXMgPSBbXTtcblx0XHRjcmVhdGVEZWJ1Zy5za2lwcyA9IFtdO1xuXG5cdFx0bGV0IGk7XG5cdFx0Y29uc3Qgc3BsaXQgPSAodHlwZW9mIG5hbWVzcGFjZXMgPT09ICdzdHJpbmcnID8gbmFtZXNwYWNlcyA6ICcnKS5zcGxpdCgvW1xccyxdKy8pO1xuXHRcdGNvbnN0IGxlbiA9IHNwbGl0Lmxlbmd0aDtcblxuXHRcdGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKykge1xuXHRcdFx0aWYgKCFzcGxpdFtpXSkge1xuXHRcdFx0XHQvLyBpZ25vcmUgZW1wdHkgc3RyaW5nc1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0bmFtZXNwYWNlcyA9IHNwbGl0W2ldLnJlcGxhY2UoL1xcKi9nLCAnLio/Jyk7XG5cblx0XHRcdGlmIChuYW1lc3BhY2VzWzBdID09PSAnLScpIHtcblx0XHRcdFx0Y3JlYXRlRGVidWcuc2tpcHMucHVzaChuZXcgUmVnRXhwKCdeJyArIG5hbWVzcGFjZXMuc2xpY2UoMSkgKyAnJCcpKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGNyZWF0ZURlYnVnLm5hbWVzLnB1c2gobmV3IFJlZ0V4cCgnXicgKyBuYW1lc3BhY2VzICsgJyQnKSk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCogRGlzYWJsZSBkZWJ1ZyBvdXRwdXQuXG5cdCpcblx0KiBAcmV0dXJuIHtTdHJpbmd9IG5hbWVzcGFjZXNcblx0KiBAYXBpIHB1YmxpY1xuXHQqL1xuXHRmdW5jdGlvbiBkaXNhYmxlKCkge1xuXHRcdGNvbnN0IG5hbWVzcGFjZXMgPSBbXG5cdFx0XHQuLi5jcmVhdGVEZWJ1Zy5uYW1lcy5tYXAodG9OYW1lc3BhY2UpLFxuXHRcdFx0Li4uY3JlYXRlRGVidWcuc2tpcHMubWFwKHRvTmFtZXNwYWNlKS5tYXAobmFtZXNwYWNlID0+ICctJyArIG5hbWVzcGFjZSlcblx0XHRdLmpvaW4oJywnKTtcblx0XHRjcmVhdGVEZWJ1Zy5lbmFibGUoJycpO1xuXHRcdHJldHVybiBuYW1lc3BhY2VzO1xuXHR9XG5cblx0LyoqXG5cdCogUmV0dXJucyB0cnVlIGlmIHRoZSBnaXZlbiBtb2RlIG5hbWUgaXMgZW5hYmxlZCwgZmFsc2Ugb3RoZXJ3aXNlLlxuXHQqXG5cdCogQHBhcmFtIHtTdHJpbmd9IG5hbWVcblx0KiBAcmV0dXJuIHtCb29sZWFufVxuXHQqIEBhcGkgcHVibGljXG5cdCovXG5cdGZ1bmN0aW9uIGVuYWJsZWQobmFtZSkge1xuXHRcdGlmIChuYW1lW25hbWUubGVuZ3RoIC0gMV0gPT09ICcqJykge1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fVxuXG5cdFx0bGV0IGk7XG5cdFx0bGV0IGxlbjtcblxuXHRcdGZvciAoaSA9IDAsIGxlbiA9IGNyZWF0ZURlYnVnLnNraXBzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRpZiAoY3JlYXRlRGVidWcuc2tpcHNbaV0udGVzdChuYW1lKSkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Zm9yIChpID0gMCwgbGVuID0gY3JlYXRlRGVidWcubmFtZXMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdGlmIChjcmVhdGVEZWJ1Zy5uYW1lc1tpXS50ZXN0KG5hbWUpKSB7XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiBmYWxzZTtcblx0fVxuXG5cdC8qKlxuXHQqIENvbnZlcnQgcmVnZXhwIHRvIG5hbWVzcGFjZVxuXHQqXG5cdCogQHBhcmFtIHtSZWdFeHB9IHJlZ3hlcFxuXHQqIEByZXR1cm4ge1N0cmluZ30gbmFtZXNwYWNlXG5cdCogQGFwaSBwcml2YXRlXG5cdCovXG5cdGZ1bmN0aW9uIHRvTmFtZXNwYWNlKHJlZ2V4cCkge1xuXHRcdHJldHVybiByZWdleHAudG9TdHJpbmcoKVxuXHRcdFx0LnN1YnN0cmluZygyLCByZWdleHAudG9TdHJpbmcoKS5sZW5ndGggLSAyKVxuXHRcdFx0LnJlcGxhY2UoL1xcLlxcKlxcPyQvLCAnKicpO1xuXHR9XG5cblx0LyoqXG5cdCogQ29lcmNlIGB2YWxgLlxuXHQqXG5cdCogQHBhcmFtIHtNaXhlZH0gdmFsXG5cdCogQHJldHVybiB7TWl4ZWR9XG5cdCogQGFwaSBwcml2YXRlXG5cdCovXG5cdGZ1bmN0aW9uIGNvZXJjZSh2YWwpIHtcblx0XHRpZiAodmFsIGluc3RhbmNlb2YgRXJyb3IpIHtcblx0XHRcdHJldHVybiB2YWwuc3RhY2sgfHwgdmFsLm1lc3NhZ2U7XG5cdFx0fVxuXHRcdHJldHVybiB2YWw7XG5cdH1cblxuXHQvKipcblx0KiBYWFggRE8gTk9UIFVTRS4gVGhpcyBpcyBhIHRlbXBvcmFyeSBzdHViIGZ1bmN0aW9uLlxuXHQqIFhYWCBJdCBXSUxMIGJlIHJlbW92ZWQgaW4gdGhlIG5leHQgbWFqb3IgcmVsZWFzZS5cblx0Ki9cblx0ZnVuY3Rpb24gZGVzdHJveSgpIHtcblx0XHRjb25zb2xlLndhcm4oJ0luc3RhbmNlIG1ldGhvZCBgZGVidWcuZGVzdHJveSgpYCBpcyBkZXByZWNhdGVkIGFuZCBubyBsb25nZXIgZG9lcyBhbnl0aGluZy4gSXQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZXh0IG1ham9yIHZlcnNpb24gb2YgYGRlYnVnYC4nKTtcblx0fVxuXG5cdGNyZWF0ZURlYnVnLmVuYWJsZShjcmVhdGVEZWJ1Zy5sb2FkKCkpO1xuXG5cdHJldHVybiBjcmVhdGVEZWJ1Zztcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBzZXR1cDtcbiIsIi8qKlxuICogSGVscGVycy5cbiAqL1xuXG52YXIgcyA9IDEwMDA7XG52YXIgbSA9IHMgKiA2MDtcbnZhciBoID0gbSAqIDYwO1xudmFyIGQgPSBoICogMjQ7XG52YXIgdyA9IGQgKiA3O1xudmFyIHkgPSBkICogMzY1LjI1O1xuXG4vKipcbiAqIFBhcnNlIG9yIGZvcm1hdCB0aGUgZ2l2ZW4gYHZhbGAuXG4gKlxuICogT3B0aW9uczpcbiAqXG4gKiAgLSBgbG9uZ2AgdmVyYm9zZSBmb3JtYXR0aW5nIFtmYWxzZV1cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ3xOdW1iZXJ9IHZhbFxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zXVxuICogQHRocm93cyB7RXJyb3J9IHRocm93IGFuIGVycm9yIGlmIHZhbCBpcyBub3QgYSBub24tZW1wdHkgc3RyaW5nIG9yIGEgbnVtYmVyXG4gKiBAcmV0dXJuIHtTdHJpbmd8TnVtYmVyfVxuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKHZhbCwgb3B0aW9ucykge1xuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgdmFyIHR5cGUgPSB0eXBlb2YgdmFsO1xuICBpZiAodHlwZSA9PT0gJ3N0cmluZycgJiYgdmFsLmxlbmd0aCA+IDApIHtcbiAgICByZXR1cm4gcGFyc2UodmFsKTtcbiAgfSBlbHNlIGlmICh0eXBlID09PSAnbnVtYmVyJyAmJiBpc0Zpbml0ZSh2YWwpKSB7XG4gICAgcmV0dXJuIG9wdGlvbnMubG9uZyA/IGZtdExvbmcodmFsKSA6IGZtdFNob3J0KHZhbCk7XG4gIH1cbiAgdGhyb3cgbmV3IEVycm9yKFxuICAgICd2YWwgaXMgbm90IGEgbm9uLWVtcHR5IHN0cmluZyBvciBhIHZhbGlkIG51bWJlci4gdmFsPScgK1xuICAgICAgSlNPTi5zdHJpbmdpZnkodmFsKVxuICApO1xufTtcblxuLyoqXG4gKiBQYXJzZSB0aGUgZ2l2ZW4gYHN0cmAgYW5kIHJldHVybiBtaWxsaXNlY29uZHMuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHN0clxuICogQHJldHVybiB7TnVtYmVyfVxuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gcGFyc2Uoc3RyKSB7XG4gIHN0ciA9IFN0cmluZyhzdHIpO1xuICBpZiAoc3RyLmxlbmd0aCA+IDEwMCkge1xuICAgIHJldHVybjtcbiAgfVxuICB2YXIgbWF0Y2ggPSAvXigtPyg/OlxcZCspP1xcLj9cXGQrKSAqKG1pbGxpc2Vjb25kcz98bXNlY3M/fG1zfHNlY29uZHM/fHNlY3M/fHN8bWludXRlcz98bWlucz98bXxob3Vycz98aHJzP3xofGRheXM/fGR8d2Vla3M/fHd8eWVhcnM/fHlycz98eSk/JC9pLmV4ZWMoXG4gICAgc3RyXG4gICk7XG4gIGlmICghbWF0Y2gpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgdmFyIG4gPSBwYXJzZUZsb2F0KG1hdGNoWzFdKTtcbiAgdmFyIHR5cGUgPSAobWF0Y2hbMl0gfHwgJ21zJykudG9Mb3dlckNhc2UoKTtcbiAgc3dpdGNoICh0eXBlKSB7XG4gICAgY2FzZSAneWVhcnMnOlxuICAgIGNhc2UgJ3llYXInOlxuICAgIGNhc2UgJ3lycyc6XG4gICAgY2FzZSAneXInOlxuICAgIGNhc2UgJ3knOlxuICAgICAgcmV0dXJuIG4gKiB5O1xuICAgIGNhc2UgJ3dlZWtzJzpcbiAgICBjYXNlICd3ZWVrJzpcbiAgICBjYXNlICd3JzpcbiAgICAgIHJldHVybiBuICogdztcbiAgICBjYXNlICdkYXlzJzpcbiAgICBjYXNlICdkYXknOlxuICAgIGNhc2UgJ2QnOlxuICAgICAgcmV0dXJuIG4gKiBkO1xuICAgIGNhc2UgJ2hvdXJzJzpcbiAgICBjYXNlICdob3VyJzpcbiAgICBjYXNlICdocnMnOlxuICAgIGNhc2UgJ2hyJzpcbiAgICBjYXNlICdoJzpcbiAgICAgIHJldHVybiBuICogaDtcbiAgICBjYXNlICdtaW51dGVzJzpcbiAgICBjYXNlICdtaW51dGUnOlxuICAgIGNhc2UgJ21pbnMnOlxuICAgIGNhc2UgJ21pbic6XG4gICAgY2FzZSAnbSc6XG4gICAgICByZXR1cm4gbiAqIG07XG4gICAgY2FzZSAnc2Vjb25kcyc6XG4gICAgY2FzZSAnc2Vjb25kJzpcbiAgICBjYXNlICdzZWNzJzpcbiAgICBjYXNlICdzZWMnOlxuICAgIGNhc2UgJ3MnOlxuICAgICAgcmV0dXJuIG4gKiBzO1xuICAgIGNhc2UgJ21pbGxpc2Vjb25kcyc6XG4gICAgY2FzZSAnbWlsbGlzZWNvbmQnOlxuICAgIGNhc2UgJ21zZWNzJzpcbiAgICBjYXNlICdtc2VjJzpcbiAgICBjYXNlICdtcyc6XG4gICAgICByZXR1cm4gbjtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIFNob3J0IGZvcm1hdCBmb3IgYG1zYC5cbiAqXG4gKiBAcGFyYW0ge051bWJlcn0gbXNcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIGZtdFNob3J0KG1zKSB7XG4gIHZhciBtc0FicyA9IE1hdGguYWJzKG1zKTtcbiAgaWYgKG1zQWJzID49IGQpIHtcbiAgICByZXR1cm4gTWF0aC5yb3VuZChtcyAvIGQpICsgJ2QnO1xuICB9XG4gIGlmIChtc0FicyA+PSBoKSB7XG4gICAgcmV0dXJuIE1hdGgucm91bmQobXMgLyBoKSArICdoJztcbiAgfVxuICBpZiAobXNBYnMgPj0gbSkge1xuICAgIHJldHVybiBNYXRoLnJvdW5kKG1zIC8gbSkgKyAnbSc7XG4gIH1cbiAgaWYgKG1zQWJzID49IHMpIHtcbiAgICByZXR1cm4gTWF0aC5yb3VuZChtcyAvIHMpICsgJ3MnO1xuICB9XG4gIHJldHVybiBtcyArICdtcyc7XG59XG5cbi8qKlxuICogTG9uZyBmb3JtYXQgZm9yIGBtc2AuXG4gKlxuICogQHBhcmFtIHtOdW1iZXJ9IG1zXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuXG5mdW5jdGlvbiBmbXRMb25nKG1zKSB7XG4gIHZhciBtc0FicyA9IE1hdGguYWJzKG1zKTtcbiAgaWYgKG1zQWJzID49IGQpIHtcbiAgICByZXR1cm4gcGx1cmFsKG1zLCBtc0FicywgZCwgJ2RheScpO1xuICB9XG4gIGlmIChtc0FicyA+PSBoKSB7XG4gICAgcmV0dXJuIHBsdXJhbChtcywgbXNBYnMsIGgsICdob3VyJyk7XG4gIH1cbiAgaWYgKG1zQWJzID49IG0pIHtcbiAgICByZXR1cm4gcGx1cmFsKG1zLCBtc0FicywgbSwgJ21pbnV0ZScpO1xuICB9XG4gIGlmIChtc0FicyA+PSBzKSB7XG4gICAgcmV0dXJuIHBsdXJhbChtcywgbXNBYnMsIHMsICdzZWNvbmQnKTtcbiAgfVxuICByZXR1cm4gbXMgKyAnIG1zJztcbn1cblxuLyoqXG4gKiBQbHVyYWxpemF0aW9uIGhlbHBlci5cbiAqL1xuXG5mdW5jdGlvbiBwbHVyYWwobXMsIG1zQWJzLCBuLCBuYW1lKSB7XG4gIHZhciBpc1BsdXJhbCA9IG1zQWJzID49IG4gKiAxLjU7XG4gIHJldHVybiBNYXRoLnJvdW5kKG1zIC8gbikgKyAnICcgKyBuYW1lICsgKGlzUGx1cmFsID8gJ3MnIDogJycpO1xufVxuIiwiLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG5cbi8vIFNEUCBoZWxwZXJzLlxuY29uc3QgU0RQVXRpbHMgPSB7fTtcblxuLy8gR2VuZXJhdGUgYW4gYWxwaGFudW1lcmljIGlkZW50aWZpZXIgZm9yIGNuYW1lIG9yIG1pZHMuXG4vLyBUT0RPOiB1c2UgVVVJRHMgaW5zdGVhZD8gaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vamVkLzk4Mjg4M1xuU0RQVXRpbHMuZ2VuZXJhdGVJZGVudGlmaWVyID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiBNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zdWJzdHJpbmcoMiwgMTIpO1xufTtcblxuLy8gVGhlIFJUQ1AgQ05BTUUgdXNlZCBieSBhbGwgcGVlcmNvbm5lY3Rpb25zIGZyb20gdGhlIHNhbWUgSlMuXG5TRFBVdGlscy5sb2NhbENOYW1lID0gU0RQVXRpbHMuZ2VuZXJhdGVJZGVudGlmaWVyKCk7XG5cbi8vIFNwbGl0cyBTRFAgaW50byBsaW5lcywgZGVhbGluZyB3aXRoIGJvdGggQ1JMRiBhbmQgTEYuXG5TRFBVdGlscy5zcGxpdExpbmVzID0gZnVuY3Rpb24oYmxvYikge1xuICByZXR1cm4gYmxvYi50cmltKCkuc3BsaXQoJ1xcbicpLm1hcChsaW5lID0+IGxpbmUudHJpbSgpKTtcbn07XG4vLyBTcGxpdHMgU0RQIGludG8gc2Vzc2lvbnBhcnQgYW5kIG1lZGlhc2VjdGlvbnMuIEVuc3VyZXMgQ1JMRi5cblNEUFV0aWxzLnNwbGl0U2VjdGlvbnMgPSBmdW5jdGlvbihibG9iKSB7XG4gIGNvbnN0IHBhcnRzID0gYmxvYi5zcGxpdCgnXFxubT0nKTtcbiAgcmV0dXJuIHBhcnRzLm1hcCgocGFydCwgaW5kZXgpID0+IChpbmRleCA+IDAgP1xuICAgICdtPScgKyBwYXJ0IDogcGFydCkudHJpbSgpICsgJ1xcclxcbicpO1xufTtcblxuLy8gUmV0dXJucyB0aGUgc2Vzc2lvbiBkZXNjcmlwdGlvbi5cblNEUFV0aWxzLmdldERlc2NyaXB0aW9uID0gZnVuY3Rpb24oYmxvYikge1xuICBjb25zdCBzZWN0aW9ucyA9IFNEUFV0aWxzLnNwbGl0U2VjdGlvbnMoYmxvYik7XG4gIHJldHVybiBzZWN0aW9ucyAmJiBzZWN0aW9uc1swXTtcbn07XG5cbi8vIFJldHVybnMgdGhlIGluZGl2aWR1YWwgbWVkaWEgc2VjdGlvbnMuXG5TRFBVdGlscy5nZXRNZWRpYVNlY3Rpb25zID0gZnVuY3Rpb24oYmxvYikge1xuICBjb25zdCBzZWN0aW9ucyA9IFNEUFV0aWxzLnNwbGl0U2VjdGlvbnMoYmxvYik7XG4gIHNlY3Rpb25zLnNoaWZ0KCk7XG4gIHJldHVybiBzZWN0aW9ucztcbn07XG5cbi8vIFJldHVybnMgbGluZXMgdGhhdCBzdGFydCB3aXRoIGEgY2VydGFpbiBwcmVmaXguXG5TRFBVdGlscy5tYXRjaFByZWZpeCA9IGZ1bmN0aW9uKGJsb2IsIHByZWZpeCkge1xuICByZXR1cm4gU0RQVXRpbHMuc3BsaXRMaW5lcyhibG9iKS5maWx0ZXIobGluZSA9PiBsaW5lLmluZGV4T2YocHJlZml4KSA9PT0gMCk7XG59O1xuXG4vLyBQYXJzZXMgYW4gSUNFIGNhbmRpZGF0ZSBsaW5lLiBTYW1wbGUgaW5wdXQ6XG4vLyBjYW5kaWRhdGU6NzAyNzg2MzUwIDIgdWRwIDQxODE5OTAyIDguOC44LjggNjA3NjkgdHlwIHJlbGF5IHJhZGRyIDguOC44Ljhcbi8vIHJwb3J0IDU1OTk2XCJcbi8vIElucHV0IGNhbiBiZSBwcmVmaXhlZCB3aXRoIGE9LlxuU0RQVXRpbHMucGFyc2VDYW5kaWRhdGUgPSBmdW5jdGlvbihsaW5lKSB7XG4gIGxldCBwYXJ0cztcbiAgLy8gUGFyc2UgYm90aCB2YXJpYW50cy5cbiAgaWYgKGxpbmUuaW5kZXhPZignYT1jYW5kaWRhdGU6JykgPT09IDApIHtcbiAgICBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDEyKS5zcGxpdCgnICcpO1xuICB9IGVsc2Uge1xuICAgIHBhcnRzID0gbGluZS5zdWJzdHJpbmcoMTApLnNwbGl0KCcgJyk7XG4gIH1cblxuICBjb25zdCBjYW5kaWRhdGUgPSB7XG4gICAgZm91bmRhdGlvbjogcGFydHNbMF0sXG4gICAgY29tcG9uZW50OiB7MTogJ3J0cCcsIDI6ICdydGNwJ31bcGFydHNbMV1dIHx8IHBhcnRzWzFdLFxuICAgIHByb3RvY29sOiBwYXJ0c1syXS50b0xvd2VyQ2FzZSgpLFxuICAgIHByaW9yaXR5OiBwYXJzZUludChwYXJ0c1szXSwgMTApLFxuICAgIGlwOiBwYXJ0c1s0XSxcbiAgICBhZGRyZXNzOiBwYXJ0c1s0XSwgLy8gYWRkcmVzcyBpcyBhbiBhbGlhcyBmb3IgaXAuXG4gICAgcG9ydDogcGFyc2VJbnQocGFydHNbNV0sIDEwKSxcbiAgICAvLyBza2lwIHBhcnRzWzZdID09ICd0eXAnXG4gICAgdHlwZTogcGFydHNbN10sXG4gIH07XG5cbiAgZm9yIChsZXQgaSA9IDg7IGkgPCBwYXJ0cy5sZW5ndGg7IGkgKz0gMikge1xuICAgIHN3aXRjaCAocGFydHNbaV0pIHtcbiAgICAgIGNhc2UgJ3JhZGRyJzpcbiAgICAgICAgY2FuZGlkYXRlLnJlbGF0ZWRBZGRyZXNzID0gcGFydHNbaSArIDFdO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3Jwb3J0JzpcbiAgICAgICAgY2FuZGlkYXRlLnJlbGF0ZWRQb3J0ID0gcGFyc2VJbnQocGFydHNbaSArIDFdLCAxMCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAndGNwdHlwZSc6XG4gICAgICAgIGNhbmRpZGF0ZS50Y3BUeXBlID0gcGFydHNbaSArIDFdO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3VmcmFnJzpcbiAgICAgICAgY2FuZGlkYXRlLnVmcmFnID0gcGFydHNbaSArIDFdOyAvLyBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eS5cbiAgICAgICAgY2FuZGlkYXRlLnVzZXJuYW1lRnJhZ21lbnQgPSBwYXJ0c1tpICsgMV07XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDogLy8gZXh0ZW5zaW9uIGhhbmRsaW5nLCBpbiBwYXJ0aWN1bGFyIHVmcmFnLiBEb24ndCBvdmVyd3JpdGUuXG4gICAgICAgIGlmIChjYW5kaWRhdGVbcGFydHNbaV1dID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBjYW5kaWRhdGVbcGFydHNbaV1dID0gcGFydHNbaSArIDFdO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuICByZXR1cm4gY2FuZGlkYXRlO1xufTtcblxuLy8gVHJhbnNsYXRlcyBhIGNhbmRpZGF0ZSBvYmplY3QgaW50byBTRFAgY2FuZGlkYXRlIGF0dHJpYnV0ZS5cbi8vIFRoaXMgZG9lcyBub3QgaW5jbHVkZSB0aGUgYT0gcHJlZml4IVxuU0RQVXRpbHMud3JpdGVDYW5kaWRhdGUgPSBmdW5jdGlvbihjYW5kaWRhdGUpIHtcbiAgY29uc3Qgc2RwID0gW107XG4gIHNkcC5wdXNoKGNhbmRpZGF0ZS5mb3VuZGF0aW9uKTtcblxuICBjb25zdCBjb21wb25lbnQgPSBjYW5kaWRhdGUuY29tcG9uZW50O1xuICBpZiAoY29tcG9uZW50ID09PSAncnRwJykge1xuICAgIHNkcC5wdXNoKDEpO1xuICB9IGVsc2UgaWYgKGNvbXBvbmVudCA9PT0gJ3J0Y3AnKSB7XG4gICAgc2RwLnB1c2goMik7XG4gIH0gZWxzZSB7XG4gICAgc2RwLnB1c2goY29tcG9uZW50KTtcbiAgfVxuICBzZHAucHVzaChjYW5kaWRhdGUucHJvdG9jb2wudG9VcHBlckNhc2UoKSk7XG4gIHNkcC5wdXNoKGNhbmRpZGF0ZS5wcmlvcml0eSk7XG4gIHNkcC5wdXNoKGNhbmRpZGF0ZS5hZGRyZXNzIHx8IGNhbmRpZGF0ZS5pcCk7XG4gIHNkcC5wdXNoKGNhbmRpZGF0ZS5wb3J0KTtcblxuICBjb25zdCB0eXBlID0gY2FuZGlkYXRlLnR5cGU7XG4gIHNkcC5wdXNoKCd0eXAnKTtcbiAgc2RwLnB1c2godHlwZSk7XG4gIGlmICh0eXBlICE9PSAnaG9zdCcgJiYgY2FuZGlkYXRlLnJlbGF0ZWRBZGRyZXNzICYmXG4gICAgICBjYW5kaWRhdGUucmVsYXRlZFBvcnQpIHtcbiAgICBzZHAucHVzaCgncmFkZHInKTtcbiAgICBzZHAucHVzaChjYW5kaWRhdGUucmVsYXRlZEFkZHJlc3MpO1xuICAgIHNkcC5wdXNoKCdycG9ydCcpO1xuICAgIHNkcC5wdXNoKGNhbmRpZGF0ZS5yZWxhdGVkUG9ydCk7XG4gIH1cbiAgaWYgKGNhbmRpZGF0ZS50Y3BUeXBlICYmIGNhbmRpZGF0ZS5wcm90b2NvbC50b0xvd2VyQ2FzZSgpID09PSAndGNwJykge1xuICAgIHNkcC5wdXNoKCd0Y3B0eXBlJyk7XG4gICAgc2RwLnB1c2goY2FuZGlkYXRlLnRjcFR5cGUpO1xuICB9XG4gIGlmIChjYW5kaWRhdGUudXNlcm5hbWVGcmFnbWVudCB8fCBjYW5kaWRhdGUudWZyYWcpIHtcbiAgICBzZHAucHVzaCgndWZyYWcnKTtcbiAgICBzZHAucHVzaChjYW5kaWRhdGUudXNlcm5hbWVGcmFnbWVudCB8fCBjYW5kaWRhdGUudWZyYWcpO1xuICB9XG4gIHJldHVybiAnY2FuZGlkYXRlOicgKyBzZHAuam9pbignICcpO1xufTtcblxuLy8gUGFyc2VzIGFuIGljZS1vcHRpb25zIGxpbmUsIHJldHVybnMgYW4gYXJyYXkgb2Ygb3B0aW9uIHRhZ3MuXG4vLyBTYW1wbGUgaW5wdXQ6XG4vLyBhPWljZS1vcHRpb25zOmZvbyBiYXJcblNEUFV0aWxzLnBhcnNlSWNlT3B0aW9ucyA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgcmV0dXJuIGxpbmUuc3Vic3RyaW5nKDE0KS5zcGxpdCgnICcpO1xufTtcblxuLy8gUGFyc2VzIGEgcnRwbWFwIGxpbmUsIHJldHVybnMgUlRDUnRwQ29kZGVjUGFyYW1ldGVycy4gU2FtcGxlIGlucHV0OlxuLy8gYT1ydHBtYXA6MTExIG9wdXMvNDgwMDAvMlxuU0RQVXRpbHMucGFyc2VSdHBNYXAgPSBmdW5jdGlvbihsaW5lKSB7XG4gIGxldCBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDkpLnNwbGl0KCcgJyk7XG4gIGNvbnN0IHBhcnNlZCA9IHtcbiAgICBwYXlsb2FkVHlwZTogcGFyc2VJbnQocGFydHMuc2hpZnQoKSwgMTApLCAvLyB3YXM6IGlkXG4gIH07XG5cbiAgcGFydHMgPSBwYXJ0c1swXS5zcGxpdCgnLycpO1xuXG4gIHBhcnNlZC5uYW1lID0gcGFydHNbMF07XG4gIHBhcnNlZC5jbG9ja1JhdGUgPSBwYXJzZUludChwYXJ0c1sxXSwgMTApOyAvLyB3YXM6IGNsb2NrcmF0ZVxuICBwYXJzZWQuY2hhbm5lbHMgPSBwYXJ0cy5sZW5ndGggPT09IDMgPyBwYXJzZUludChwYXJ0c1syXSwgMTApIDogMTtcbiAgLy8gbGVnYWN5IGFsaWFzLCBnb3QgcmVuYW1lZCBiYWNrIHRvIGNoYW5uZWxzIGluIE9SVEMuXG4gIHBhcnNlZC5udW1DaGFubmVscyA9IHBhcnNlZC5jaGFubmVscztcbiAgcmV0dXJuIHBhcnNlZDtcbn07XG5cbi8vIEdlbmVyYXRlcyBhIHJ0cG1hcCBsaW5lIGZyb20gUlRDUnRwQ29kZWNDYXBhYmlsaXR5IG9yXG4vLyBSVENSdHBDb2RlY1BhcmFtZXRlcnMuXG5TRFBVdGlscy53cml0ZVJ0cE1hcCA9IGZ1bmN0aW9uKGNvZGVjKSB7XG4gIGxldCBwdCA9IGNvZGVjLnBheWxvYWRUeXBlO1xuICBpZiAoY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGUgIT09IHVuZGVmaW5lZCkge1xuICAgIHB0ID0gY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGU7XG4gIH1cbiAgY29uc3QgY2hhbm5lbHMgPSBjb2RlYy5jaGFubmVscyB8fCBjb2RlYy5udW1DaGFubmVscyB8fCAxO1xuICByZXR1cm4gJ2E9cnRwbWFwOicgKyBwdCArICcgJyArIGNvZGVjLm5hbWUgKyAnLycgKyBjb2RlYy5jbG9ja1JhdGUgK1xuICAgICAgKGNoYW5uZWxzICE9PSAxID8gJy8nICsgY2hhbm5lbHMgOiAnJykgKyAnXFxyXFxuJztcbn07XG5cbi8vIFBhcnNlcyBhIGV4dG1hcCBsaW5lIChoZWFkZXJleHRlbnNpb24gZnJvbSBSRkMgNTI4NSkuIFNhbXBsZSBpbnB1dDpcbi8vIGE9ZXh0bWFwOjIgdXJuOmlldGY6cGFyYW1zOnJ0cC1oZHJleHQ6dG9mZnNldFxuLy8gYT1leHRtYXA6Mi9zZW5kb25seSB1cm46aWV0ZjpwYXJhbXM6cnRwLWhkcmV4dDp0b2Zmc2V0XG5TRFBVdGlscy5wYXJzZUV4dG1hcCA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgY29uc3QgcGFydHMgPSBsaW5lLnN1YnN0cmluZyg5KS5zcGxpdCgnICcpO1xuICByZXR1cm4ge1xuICAgIGlkOiBwYXJzZUludChwYXJ0c1swXSwgMTApLFxuICAgIGRpcmVjdGlvbjogcGFydHNbMF0uaW5kZXhPZignLycpID4gMCA/IHBhcnRzWzBdLnNwbGl0KCcvJylbMV0gOiAnc2VuZHJlY3YnLFxuICAgIHVyaTogcGFydHNbMV0sXG4gICAgYXR0cmlidXRlczogcGFydHMuc2xpY2UoMikuam9pbignICcpLFxuICB9O1xufTtcblxuLy8gR2VuZXJhdGVzIGFuIGV4dG1hcCBsaW5lIGZyb20gUlRDUnRwSGVhZGVyRXh0ZW5zaW9uUGFyYW1ldGVycyBvclxuLy8gUlRDUnRwSGVhZGVyRXh0ZW5zaW9uLlxuU0RQVXRpbHMud3JpdGVFeHRtYXAgPSBmdW5jdGlvbihoZWFkZXJFeHRlbnNpb24pIHtcbiAgcmV0dXJuICdhPWV4dG1hcDonICsgKGhlYWRlckV4dGVuc2lvbi5pZCB8fCBoZWFkZXJFeHRlbnNpb24ucHJlZmVycmVkSWQpICtcbiAgICAgIChoZWFkZXJFeHRlbnNpb24uZGlyZWN0aW9uICYmIGhlYWRlckV4dGVuc2lvbi5kaXJlY3Rpb24gIT09ICdzZW5kcmVjdidcbiAgICAgICAgPyAnLycgKyBoZWFkZXJFeHRlbnNpb24uZGlyZWN0aW9uXG4gICAgICAgIDogJycpICtcbiAgICAgICcgJyArIGhlYWRlckV4dGVuc2lvbi51cmkgK1xuICAgICAgKGhlYWRlckV4dGVuc2lvbi5hdHRyaWJ1dGVzID8gJyAnICsgaGVhZGVyRXh0ZW5zaW9uLmF0dHJpYnV0ZXMgOiAnJykgK1xuICAgICAgJ1xcclxcbic7XG59O1xuXG4vLyBQYXJzZXMgYSBmbXRwIGxpbmUsIHJldHVybnMgZGljdGlvbmFyeS4gU2FtcGxlIGlucHV0OlxuLy8gYT1mbXRwOjk2IHZicj1vbjtjbmc9b25cbi8vIEFsc28gZGVhbHMgd2l0aCB2YnI9b247IGNuZz1vblxuU0RQVXRpbHMucGFyc2VGbXRwID0gZnVuY3Rpb24obGluZSkge1xuICBjb25zdCBwYXJzZWQgPSB7fTtcbiAgbGV0IGt2O1xuICBjb25zdCBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKGxpbmUuaW5kZXhPZignICcpICsgMSkuc3BsaXQoJzsnKTtcbiAgZm9yIChsZXQgaiA9IDA7IGogPCBwYXJ0cy5sZW5ndGg7IGorKykge1xuICAgIGt2ID0gcGFydHNbal0udHJpbSgpLnNwbGl0KCc9Jyk7XG4gICAgcGFyc2VkW2t2WzBdLnRyaW0oKV0gPSBrdlsxXTtcbiAgfVxuICByZXR1cm4gcGFyc2VkO1xufTtcblxuLy8gR2VuZXJhdGVzIGEgZm10cCBsaW5lIGZyb20gUlRDUnRwQ29kZWNDYXBhYmlsaXR5IG9yIFJUQ1J0cENvZGVjUGFyYW1ldGVycy5cblNEUFV0aWxzLndyaXRlRm10cCA9IGZ1bmN0aW9uKGNvZGVjKSB7XG4gIGxldCBsaW5lID0gJyc7XG4gIGxldCBwdCA9IGNvZGVjLnBheWxvYWRUeXBlO1xuICBpZiAoY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGUgIT09IHVuZGVmaW5lZCkge1xuICAgIHB0ID0gY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGU7XG4gIH1cbiAgaWYgKGNvZGVjLnBhcmFtZXRlcnMgJiYgT2JqZWN0LmtleXMoY29kZWMucGFyYW1ldGVycykubGVuZ3RoKSB7XG4gICAgY29uc3QgcGFyYW1zID0gW107XG4gICAgT2JqZWN0LmtleXMoY29kZWMucGFyYW1ldGVycykuZm9yRWFjaChwYXJhbSA9PiB7XG4gICAgICBpZiAoY29kZWMucGFyYW1ldGVyc1twYXJhbV0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBwYXJhbXMucHVzaChwYXJhbSArICc9JyArIGNvZGVjLnBhcmFtZXRlcnNbcGFyYW1dKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBhcmFtcy5wdXNoKHBhcmFtKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBsaW5lICs9ICdhPWZtdHA6JyArIHB0ICsgJyAnICsgcGFyYW1zLmpvaW4oJzsnKSArICdcXHJcXG4nO1xuICB9XG4gIHJldHVybiBsaW5lO1xufTtcblxuLy8gUGFyc2VzIGEgcnRjcC1mYiBsaW5lLCByZXR1cm5zIFJUQ1BSdGNwRmVlZGJhY2sgb2JqZWN0LiBTYW1wbGUgaW5wdXQ6XG4vLyBhPXJ0Y3AtZmI6OTggbmFjayBycHNpXG5TRFBVdGlscy5wYXJzZVJ0Y3BGYiA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgY29uc3QgcGFydHMgPSBsaW5lLnN1YnN0cmluZyhsaW5lLmluZGV4T2YoJyAnKSArIDEpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAgdHlwZTogcGFydHMuc2hpZnQoKSxcbiAgICBwYXJhbWV0ZXI6IHBhcnRzLmpvaW4oJyAnKSxcbiAgfTtcbn07XG5cbi8vIEdlbmVyYXRlIGE9cnRjcC1mYiBsaW5lcyBmcm9tIFJUQ1J0cENvZGVjQ2FwYWJpbGl0eSBvciBSVENSdHBDb2RlY1BhcmFtZXRlcnMuXG5TRFBVdGlscy53cml0ZVJ0Y3BGYiA9IGZ1bmN0aW9uKGNvZGVjKSB7XG4gIGxldCBsaW5lcyA9ICcnO1xuICBsZXQgcHQgPSBjb2RlYy5wYXlsb2FkVHlwZTtcbiAgaWYgKGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlICE9PSB1bmRlZmluZWQpIHtcbiAgICBwdCA9IGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlO1xuICB9XG4gIGlmIChjb2RlYy5ydGNwRmVlZGJhY2sgJiYgY29kZWMucnRjcEZlZWRiYWNrLmxlbmd0aCkge1xuICAgIC8vIEZJWE1FOiBzcGVjaWFsIGhhbmRsaW5nIGZvciB0cnItaW50P1xuICAgIGNvZGVjLnJ0Y3BGZWVkYmFjay5mb3JFYWNoKGZiID0+IHtcbiAgICAgIGxpbmVzICs9ICdhPXJ0Y3AtZmI6JyArIHB0ICsgJyAnICsgZmIudHlwZSArXG4gICAgICAoZmIucGFyYW1ldGVyICYmIGZiLnBhcmFtZXRlci5sZW5ndGggPyAnICcgKyBmYi5wYXJhbWV0ZXIgOiAnJykgK1xuICAgICAgICAgICdcXHJcXG4nO1xuICAgIH0pO1xuICB9XG4gIHJldHVybiBsaW5lcztcbn07XG5cbi8vIFBhcnNlcyBhIFJGQyA1NTc2IHNzcmMgbWVkaWEgYXR0cmlidXRlLiBTYW1wbGUgaW5wdXQ6XG4vLyBhPXNzcmM6MzczNTkyODU1OSBjbmFtZTpzb21ldGhpbmdcblNEUFV0aWxzLnBhcnNlU3NyY01lZGlhID0gZnVuY3Rpb24obGluZSkge1xuICBjb25zdCBzcCA9IGxpbmUuaW5kZXhPZignICcpO1xuICBjb25zdCBwYXJ0cyA9IHtcbiAgICBzc3JjOiBwYXJzZUludChsaW5lLnN1YnN0cmluZyg3LCBzcCksIDEwKSxcbiAgfTtcbiAgY29uc3QgY29sb24gPSBsaW5lLmluZGV4T2YoJzonLCBzcCk7XG4gIGlmIChjb2xvbiA+IC0xKSB7XG4gICAgcGFydHMuYXR0cmlidXRlID0gbGluZS5zdWJzdHJpbmcoc3AgKyAxLCBjb2xvbik7XG4gICAgcGFydHMudmFsdWUgPSBsaW5lLnN1YnN0cmluZyhjb2xvbiArIDEpO1xuICB9IGVsc2Uge1xuICAgIHBhcnRzLmF0dHJpYnV0ZSA9IGxpbmUuc3Vic3RyaW5nKHNwICsgMSk7XG4gIH1cbiAgcmV0dXJuIHBhcnRzO1xufTtcblxuLy8gUGFyc2UgYSBzc3JjLWdyb3VwIGxpbmUgKHNlZSBSRkMgNTU3NikuIFNhbXBsZSBpbnB1dDpcbi8vIGE9c3NyYy1ncm91cDpzZW1hbnRpY3MgMTIgMzRcblNEUFV0aWxzLnBhcnNlU3NyY0dyb3VwID0gZnVuY3Rpb24obGluZSkge1xuICBjb25zdCBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDEzKS5zcGxpdCgnICcpO1xuICByZXR1cm4ge1xuICAgIHNlbWFudGljczogcGFydHMuc2hpZnQoKSxcbiAgICBzc3JjczogcGFydHMubWFwKHNzcmMgPT4gcGFyc2VJbnQoc3NyYywgMTApKSxcbiAgfTtcbn07XG5cbi8vIEV4dHJhY3RzIHRoZSBNSUQgKFJGQyA1ODg4KSBmcm9tIGEgbWVkaWEgc2VjdGlvbi5cbi8vIFJldHVybnMgdGhlIE1JRCBvciB1bmRlZmluZWQgaWYgbm8gbWlkIGxpbmUgd2FzIGZvdW5kLlxuU0RQVXRpbHMuZ2V0TWlkID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIGNvbnN0IG1pZCA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9bWlkOicpWzBdO1xuICBpZiAobWlkKSB7XG4gICAgcmV0dXJuIG1pZC5zdWJzdHJpbmcoNik7XG4gIH1cbn07XG5cbi8vIFBhcnNlcyBhIGZpbmdlcnByaW50IGxpbmUgZm9yIERUTFMtU1JUUC5cblNEUFV0aWxzLnBhcnNlRmluZ2VycHJpbnQgPSBmdW5jdGlvbihsaW5lKSB7XG4gIGNvbnN0IHBhcnRzID0gbGluZS5zdWJzdHJpbmcoMTQpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAgYWxnb3JpdGhtOiBwYXJ0c1swXS50b0xvd2VyQ2FzZSgpLCAvLyBhbGdvcml0aG0gaXMgY2FzZS1zZW5zaXRpdmUgaW4gRWRnZS5cbiAgICB2YWx1ZTogcGFydHNbMV0udG9VcHBlckNhc2UoKSwgLy8gdGhlIGRlZmluaXRpb24gaXMgdXBwZXItY2FzZSBpbiBSRkMgNDU3Mi5cbiAgfTtcbn07XG5cbi8vIEV4dHJhY3RzIERUTFMgcGFyYW1ldGVycyBmcm9tIFNEUCBtZWRpYSBzZWN0aW9uIG9yIHNlc3Npb25wYXJ0LlxuLy8gRklYTUU6IGZvciBjb25zaXN0ZW5jeSB3aXRoIG90aGVyIGZ1bmN0aW9ucyB0aGlzIHNob3VsZCBvbmx5XG4vLyAgIGdldCB0aGUgZmluZ2VycHJpbnQgbGluZSBhcyBpbnB1dC4gU2VlIGFsc28gZ2V0SWNlUGFyYW1ldGVycy5cblNEUFV0aWxzLmdldER0bHNQYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZXNzaW9ucGFydCkge1xuICBjb25zdCBsaW5lcyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiArIHNlc3Npb25wYXJ0LFxuICAgICdhPWZpbmdlcnByaW50OicpO1xuICAvLyBOb3RlOiBhPXNldHVwIGxpbmUgaXMgaWdub3JlZCBzaW5jZSB3ZSB1c2UgdGhlICdhdXRvJyByb2xlIGluIEVkZ2UuXG4gIHJldHVybiB7XG4gICAgcm9sZTogJ2F1dG8nLFxuICAgIGZpbmdlcnByaW50czogbGluZXMubWFwKFNEUFV0aWxzLnBhcnNlRmluZ2VycHJpbnQpLFxuICB9O1xufTtcblxuLy8gU2VyaWFsaXplcyBEVExTIHBhcmFtZXRlcnMgdG8gU0RQLlxuU0RQVXRpbHMud3JpdGVEdGxzUGFyYW1ldGVycyA9IGZ1bmN0aW9uKHBhcmFtcywgc2V0dXBUeXBlKSB7XG4gIGxldCBzZHAgPSAnYT1zZXR1cDonICsgc2V0dXBUeXBlICsgJ1xcclxcbic7XG4gIHBhcmFtcy5maW5nZXJwcmludHMuZm9yRWFjaChmcCA9PiB7XG4gICAgc2RwICs9ICdhPWZpbmdlcnByaW50OicgKyBmcC5hbGdvcml0aG0gKyAnICcgKyBmcC52YWx1ZSArICdcXHJcXG4nO1xuICB9KTtcbiAgcmV0dXJuIHNkcDtcbn07XG5cbi8vIFBhcnNlcyBhPWNyeXB0byBsaW5lcyBpbnRvXG4vLyAgIGh0dHBzOi8vcmF3Z2l0LmNvbS9hYm9iYS9lZGdlcnRjL21hc3Rlci9tc29ydGMtcnM0Lmh0bWwjZGljdGlvbmFyeS1ydGNzcnRwc2Rlc3BhcmFtZXRlcnMtbWVtYmVyc1xuU0RQVXRpbHMucGFyc2VDcnlwdG9MaW5lID0gZnVuY3Rpb24obGluZSkge1xuICBjb25zdCBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDkpLnNwbGl0KCcgJyk7XG4gIHJldHVybiB7XG4gICAgdGFnOiBwYXJzZUludChwYXJ0c1swXSwgMTApLFxuICAgIGNyeXB0b1N1aXRlOiBwYXJ0c1sxXSxcbiAgICBrZXlQYXJhbXM6IHBhcnRzWzJdLFxuICAgIHNlc3Npb25QYXJhbXM6IHBhcnRzLnNsaWNlKDMpLFxuICB9O1xufTtcblxuU0RQVXRpbHMud3JpdGVDcnlwdG9MaW5lID0gZnVuY3Rpb24ocGFyYW1ldGVycykge1xuICByZXR1cm4gJ2E9Y3J5cHRvOicgKyBwYXJhbWV0ZXJzLnRhZyArICcgJyArXG4gICAgcGFyYW1ldGVycy5jcnlwdG9TdWl0ZSArICcgJyArXG4gICAgKHR5cGVvZiBwYXJhbWV0ZXJzLmtleVBhcmFtcyA9PT0gJ29iamVjdCdcbiAgICAgID8gU0RQVXRpbHMud3JpdGVDcnlwdG9LZXlQYXJhbXMocGFyYW1ldGVycy5rZXlQYXJhbXMpXG4gICAgICA6IHBhcmFtZXRlcnMua2V5UGFyYW1zKSArXG4gICAgKHBhcmFtZXRlcnMuc2Vzc2lvblBhcmFtcyA/ICcgJyArIHBhcmFtZXRlcnMuc2Vzc2lvblBhcmFtcy5qb2luKCcgJykgOiAnJykgK1xuICAgICdcXHJcXG4nO1xufTtcblxuLy8gUGFyc2VzIHRoZSBjcnlwdG8ga2V5IHBhcmFtZXRlcnMgaW50b1xuLy8gICBodHRwczovL3Jhd2dpdC5jb20vYWJvYmEvZWRnZXJ0Yy9tYXN0ZXIvbXNvcnRjLXJzNC5odG1sI3J0Y3NydHBrZXlwYXJhbSpcblNEUFV0aWxzLnBhcnNlQ3J5cHRvS2V5UGFyYW1zID0gZnVuY3Rpb24oa2V5UGFyYW1zKSB7XG4gIGlmIChrZXlQYXJhbXMuaW5kZXhPZignaW5saW5lOicpICE9PSAwKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgY29uc3QgcGFydHMgPSBrZXlQYXJhbXMuc3Vic3RyaW5nKDcpLnNwbGl0KCd8Jyk7XG4gIHJldHVybiB7XG4gICAga2V5TWV0aG9kOiAnaW5saW5lJyxcbiAgICBrZXlTYWx0OiBwYXJ0c1swXSxcbiAgICBsaWZlVGltZTogcGFydHNbMV0sXG4gICAgbWtpVmFsdWU6IHBhcnRzWzJdID8gcGFydHNbMl0uc3BsaXQoJzonKVswXSA6IHVuZGVmaW5lZCxcbiAgICBta2lMZW5ndGg6IHBhcnRzWzJdID8gcGFydHNbMl0uc3BsaXQoJzonKVsxXSA6IHVuZGVmaW5lZCxcbiAgfTtcbn07XG5cblNEUFV0aWxzLndyaXRlQ3J5cHRvS2V5UGFyYW1zID0gZnVuY3Rpb24oa2V5UGFyYW1zKSB7XG4gIHJldHVybiBrZXlQYXJhbXMua2V5TWV0aG9kICsgJzonXG4gICAgKyBrZXlQYXJhbXMua2V5U2FsdCArXG4gICAgKGtleVBhcmFtcy5saWZlVGltZSA/ICd8JyArIGtleVBhcmFtcy5saWZlVGltZSA6ICcnKSArXG4gICAgKGtleVBhcmFtcy5ta2lWYWx1ZSAmJiBrZXlQYXJhbXMubWtpTGVuZ3RoXG4gICAgICA/ICd8JyArIGtleVBhcmFtcy5ta2lWYWx1ZSArICc6JyArIGtleVBhcmFtcy5ta2lMZW5ndGhcbiAgICAgIDogJycpO1xufTtcblxuLy8gRXh0cmFjdHMgYWxsIFNERVMgcGFyYW1ldGVycy5cblNEUFV0aWxzLmdldENyeXB0b1BhcmFtZXRlcnMgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KSB7XG4gIGNvbnN0IGxpbmVzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uICsgc2Vzc2lvbnBhcnQsXG4gICAgJ2E9Y3J5cHRvOicpO1xuICByZXR1cm4gbGluZXMubWFwKFNEUFV0aWxzLnBhcnNlQ3J5cHRvTGluZSk7XG59O1xuXG4vLyBQYXJzZXMgSUNFIGluZm9ybWF0aW9uIGZyb20gU0RQIG1lZGlhIHNlY3Rpb24gb3Igc2Vzc2lvbnBhcnQuXG4vLyBGSVhNRTogZm9yIGNvbnNpc3RlbmN5IHdpdGggb3RoZXIgZnVuY3Rpb25zIHRoaXMgc2hvdWxkIG9ubHlcbi8vICAgZ2V0IHRoZSBpY2UtdWZyYWcgYW5kIGljZS1wd2QgbGluZXMgYXMgaW5wdXQuXG5TRFBVdGlscy5nZXRJY2VQYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZXNzaW9ucGFydCkge1xuICBjb25zdCB1ZnJhZyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiArIHNlc3Npb25wYXJ0LFxuICAgICdhPWljZS11ZnJhZzonKVswXTtcbiAgY29uc3QgcHdkID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uICsgc2Vzc2lvbnBhcnQsXG4gICAgJ2E9aWNlLXB3ZDonKVswXTtcbiAgaWYgKCEodWZyYWcgJiYgcHdkKSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIHJldHVybiB7XG4gICAgdXNlcm5hbWVGcmFnbWVudDogdWZyYWcuc3Vic3RyaW5nKDEyKSxcbiAgICBwYXNzd29yZDogcHdkLnN1YnN0cmluZygxMCksXG4gIH07XG59O1xuXG4vLyBTZXJpYWxpemVzIElDRSBwYXJhbWV0ZXJzIHRvIFNEUC5cblNEUFV0aWxzLndyaXRlSWNlUGFyYW1ldGVycyA9IGZ1bmN0aW9uKHBhcmFtcykge1xuICBsZXQgc2RwID0gJ2E9aWNlLXVmcmFnOicgKyBwYXJhbXMudXNlcm5hbWVGcmFnbWVudCArICdcXHJcXG4nICtcbiAgICAgICdhPWljZS1wd2Q6JyArIHBhcmFtcy5wYXNzd29yZCArICdcXHJcXG4nO1xuICBpZiAocGFyYW1zLmljZUxpdGUpIHtcbiAgICBzZHAgKz0gJ2E9aWNlLWxpdGVcXHJcXG4nO1xuICB9XG4gIHJldHVybiBzZHA7XG59O1xuXG4vLyBQYXJzZXMgdGhlIFNEUCBtZWRpYSBzZWN0aW9uIGFuZCByZXR1cm5zIFJUQ1J0cFBhcmFtZXRlcnMuXG5TRFBVdGlscy5wYXJzZVJ0cFBhcmFtZXRlcnMgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgY29uc3QgZGVzY3JpcHRpb24gPSB7XG4gICAgY29kZWNzOiBbXSxcbiAgICBoZWFkZXJFeHRlbnNpb25zOiBbXSxcbiAgICBmZWNNZWNoYW5pc21zOiBbXSxcbiAgICBydGNwOiBbXSxcbiAgfTtcbiAgY29uc3QgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIGNvbnN0IG1saW5lID0gbGluZXNbMF0uc3BsaXQoJyAnKTtcbiAgZGVzY3JpcHRpb24ucHJvZmlsZSA9IG1saW5lWzJdO1xuICBmb3IgKGxldCBpID0gMzsgaSA8IG1saW5lLmxlbmd0aDsgaSsrKSB7IC8vIGZpbmQgYWxsIGNvZGVjcyBmcm9tIG1saW5lWzMuLl1cbiAgICBjb25zdCBwdCA9IG1saW5lW2ldO1xuICAgIGNvbnN0IHJ0cG1hcGxpbmUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChcbiAgICAgIG1lZGlhU2VjdGlvbiwgJ2E9cnRwbWFwOicgKyBwdCArICcgJylbMF07XG4gICAgaWYgKHJ0cG1hcGxpbmUpIHtcbiAgICAgIGNvbnN0IGNvZGVjID0gU0RQVXRpbHMucGFyc2VSdHBNYXAocnRwbWFwbGluZSk7XG4gICAgICBjb25zdCBmbXRwcyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KFxuICAgICAgICBtZWRpYVNlY3Rpb24sICdhPWZtdHA6JyArIHB0ICsgJyAnKTtcbiAgICAgIC8vIE9ubHkgdGhlIGZpcnN0IGE9Zm10cDo8cHQ+IGlzIGNvbnNpZGVyZWQuXG4gICAgICBjb2RlYy5wYXJhbWV0ZXJzID0gZm10cHMubGVuZ3RoID8gU0RQVXRpbHMucGFyc2VGbXRwKGZtdHBzWzBdKSA6IHt9O1xuICAgICAgY29kZWMucnRjcEZlZWRiYWNrID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgoXG4gICAgICAgIG1lZGlhU2VjdGlvbiwgJ2E9cnRjcC1mYjonICsgcHQgKyAnICcpXG4gICAgICAgIC5tYXAoU0RQVXRpbHMucGFyc2VSdGNwRmIpO1xuICAgICAgZGVzY3JpcHRpb24uY29kZWNzLnB1c2goY29kZWMpO1xuICAgICAgLy8gcGFyc2UgRkVDIG1lY2hhbmlzbXMgZnJvbSBydHBtYXAgbGluZXMuXG4gICAgICBzd2l0Y2ggKGNvZGVjLm5hbWUudG9VcHBlckNhc2UoKSkge1xuICAgICAgICBjYXNlICdSRUQnOlxuICAgICAgICBjYXNlICdVTFBGRUMnOlxuICAgICAgICAgIGRlc2NyaXB0aW9uLmZlY01lY2hhbmlzbXMucHVzaChjb2RlYy5uYW1lLnRvVXBwZXJDYXNlKCkpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OiAvLyBvbmx5IFJFRCBhbmQgVUxQRkVDIGFyZSByZWNvZ25pemVkIGFzIEZFQyBtZWNoYW5pc21zLlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPWV4dG1hcDonKS5mb3JFYWNoKGxpbmUgPT4ge1xuICAgIGRlc2NyaXB0aW9uLmhlYWRlckV4dGVuc2lvbnMucHVzaChTRFBVdGlscy5wYXJzZUV4dG1hcChsaW5lKSk7XG4gIH0pO1xuICBjb25zdCB3aWxkY2FyZFJ0Y3BGYiA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9cnRjcC1mYjoqICcpXG4gICAgLm1hcChTRFBVdGlscy5wYXJzZVJ0Y3BGYik7XG4gIGRlc2NyaXB0aW9uLmNvZGVjcy5mb3JFYWNoKGNvZGVjID0+IHtcbiAgICB3aWxkY2FyZFJ0Y3BGYi5mb3JFYWNoKGZiPT4ge1xuICAgICAgY29uc3QgZHVwbGljYXRlID0gY29kZWMucnRjcEZlZWRiYWNrLmZpbmQoZXhpc3RpbmdGZWVkYmFjayA9PiB7XG4gICAgICAgIHJldHVybiBleGlzdGluZ0ZlZWRiYWNrLnR5cGUgPT09IGZiLnR5cGUgJiZcbiAgICAgICAgICBleGlzdGluZ0ZlZWRiYWNrLnBhcmFtZXRlciA9PT0gZmIucGFyYW1ldGVyO1xuICAgICAgfSk7XG4gICAgICBpZiAoIWR1cGxpY2F0ZSkge1xuICAgICAgICBjb2RlYy5ydGNwRmVlZGJhY2sucHVzaChmYik7XG4gICAgICB9XG4gICAgfSk7XG4gIH0pO1xuICAvLyBGSVhNRTogcGFyc2UgcnRjcC5cbiAgcmV0dXJuIGRlc2NyaXB0aW9uO1xufTtcblxuLy8gR2VuZXJhdGVzIHBhcnRzIG9mIHRoZSBTRFAgbWVkaWEgc2VjdGlvbiBkZXNjcmliaW5nIHRoZSBjYXBhYmlsaXRpZXMgL1xuLy8gcGFyYW1ldGVycy5cblNEUFV0aWxzLndyaXRlUnRwRGVzY3JpcHRpb24gPSBmdW5jdGlvbihraW5kLCBjYXBzKSB7XG4gIGxldCBzZHAgPSAnJztcblxuICAvLyBCdWlsZCB0aGUgbWxpbmUuXG4gIHNkcCArPSAnbT0nICsga2luZCArICcgJztcbiAgc2RwICs9IGNhcHMuY29kZWNzLmxlbmd0aCA+IDAgPyAnOScgOiAnMCc7IC8vIHJlamVjdCBpZiBubyBjb2RlY3MuXG4gIHNkcCArPSAnICcgKyAoY2Fwcy5wcm9maWxlIHx8ICdVRFAvVExTL1JUUC9TQVZQRicpICsgJyAnO1xuICBzZHAgKz0gY2Fwcy5jb2RlY3MubWFwKGNvZGVjID0+IHtcbiAgICBpZiAoY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlO1xuICAgIH1cbiAgICByZXR1cm4gY29kZWMucGF5bG9hZFR5cGU7XG4gIH0pLmpvaW4oJyAnKSArICdcXHJcXG4nO1xuXG4gIHNkcCArPSAnYz1JTiBJUDQgMC4wLjAuMFxcclxcbic7XG4gIHNkcCArPSAnYT1ydGNwOjkgSU4gSVA0IDAuMC4wLjBcXHJcXG4nO1xuXG4gIC8vIEFkZCBhPXJ0cG1hcCBsaW5lcyBmb3IgZWFjaCBjb2RlYy4gQWxzbyBmbXRwIGFuZCBydGNwLWZiLlxuICBjYXBzLmNvZGVjcy5mb3JFYWNoKGNvZGVjID0+IHtcbiAgICBzZHAgKz0gU0RQVXRpbHMud3JpdGVSdHBNYXAoY29kZWMpO1xuICAgIHNkcCArPSBTRFBVdGlscy53cml0ZUZtdHAoY29kZWMpO1xuICAgIHNkcCArPSBTRFBVdGlscy53cml0ZVJ0Y3BGYihjb2RlYyk7XG4gIH0pO1xuICBsZXQgbWF4cHRpbWUgPSAwO1xuICBjYXBzLmNvZGVjcy5mb3JFYWNoKGNvZGVjID0+IHtcbiAgICBpZiAoY29kZWMubWF4cHRpbWUgPiBtYXhwdGltZSkge1xuICAgICAgbWF4cHRpbWUgPSBjb2RlYy5tYXhwdGltZTtcbiAgICB9XG4gIH0pO1xuICBpZiAobWF4cHRpbWUgPiAwKSB7XG4gICAgc2RwICs9ICdhPW1heHB0aW1lOicgKyBtYXhwdGltZSArICdcXHJcXG4nO1xuICB9XG5cbiAgaWYgKGNhcHMuaGVhZGVyRXh0ZW5zaW9ucykge1xuICAgIGNhcHMuaGVhZGVyRXh0ZW5zaW9ucy5mb3JFYWNoKGV4dGVuc2lvbiA9PiB7XG4gICAgICBzZHAgKz0gU0RQVXRpbHMud3JpdGVFeHRtYXAoZXh0ZW5zaW9uKTtcbiAgICB9KTtcbiAgfVxuICAvLyBGSVhNRTogd3JpdGUgZmVjTWVjaGFuaXNtcy5cbiAgcmV0dXJuIHNkcDtcbn07XG5cbi8vIFBhcnNlcyB0aGUgU0RQIG1lZGlhIHNlY3Rpb24gYW5kIHJldHVybnMgYW4gYXJyYXkgb2Zcbi8vIFJUQ1J0cEVuY29kaW5nUGFyYW1ldGVycy5cblNEUFV0aWxzLnBhcnNlUnRwRW5jb2RpbmdQYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIGNvbnN0IGVuY29kaW5nUGFyYW1ldGVycyA9IFtdO1xuICBjb25zdCBkZXNjcmlwdGlvbiA9IFNEUFV0aWxzLnBhcnNlUnRwUGFyYW1ldGVycyhtZWRpYVNlY3Rpb24pO1xuICBjb25zdCBoYXNSZWQgPSBkZXNjcmlwdGlvbi5mZWNNZWNoYW5pc21zLmluZGV4T2YoJ1JFRCcpICE9PSAtMTtcbiAgY29uc3QgaGFzVWxwZmVjID0gZGVzY3JpcHRpb24uZmVjTWVjaGFuaXNtcy5pbmRleE9mKCdVTFBGRUMnKSAhPT0gLTE7XG5cbiAgLy8gZmlsdGVyIGE9c3NyYzouLi4gY25hbWU6LCBpZ25vcmUgUGxhbkItbXNpZFxuICBjb25zdCBzc3JjcyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9c3NyYzonKVxuICAgIC5tYXAobGluZSA9PiBTRFBVdGlscy5wYXJzZVNzcmNNZWRpYShsaW5lKSlcbiAgICAuZmlsdGVyKHBhcnRzID0+IHBhcnRzLmF0dHJpYnV0ZSA9PT0gJ2NuYW1lJyk7XG4gIGNvbnN0IHByaW1hcnlTc3JjID0gc3NyY3MubGVuZ3RoID4gMCAmJiBzc3Jjc1swXS5zc3JjO1xuICBsZXQgc2Vjb25kYXJ5U3NyYztcblxuICBjb25zdCBmbG93cyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9c3NyYy1ncm91cDpGSUQnKVxuICAgIC5tYXAobGluZSA9PiB7XG4gICAgICBjb25zdCBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDE3KS5zcGxpdCgnICcpO1xuICAgICAgcmV0dXJuIHBhcnRzLm1hcChwYXJ0ID0+IHBhcnNlSW50KHBhcnQsIDEwKSk7XG4gICAgfSk7XG4gIGlmIChmbG93cy5sZW5ndGggPiAwICYmIGZsb3dzWzBdLmxlbmd0aCA+IDEgJiYgZmxvd3NbMF1bMF0gPT09IHByaW1hcnlTc3JjKSB7XG4gICAgc2Vjb25kYXJ5U3NyYyA9IGZsb3dzWzBdWzFdO1xuICB9XG5cbiAgZGVzY3JpcHRpb24uY29kZWNzLmZvckVhY2goY29kZWMgPT4ge1xuICAgIGlmIChjb2RlYy5uYW1lLnRvVXBwZXJDYXNlKCkgPT09ICdSVFgnICYmIGNvZGVjLnBhcmFtZXRlcnMuYXB0KSB7XG4gICAgICBsZXQgZW5jUGFyYW0gPSB7XG4gICAgICAgIHNzcmM6IHByaW1hcnlTc3JjLFxuICAgICAgICBjb2RlY1BheWxvYWRUeXBlOiBwYXJzZUludChjb2RlYy5wYXJhbWV0ZXJzLmFwdCwgMTApLFxuICAgICAgfTtcbiAgICAgIGlmIChwcmltYXJ5U3NyYyAmJiBzZWNvbmRhcnlTc3JjKSB7XG4gICAgICAgIGVuY1BhcmFtLnJ0eCA9IHtzc3JjOiBzZWNvbmRhcnlTc3JjfTtcbiAgICAgIH1cbiAgICAgIGVuY29kaW5nUGFyYW1ldGVycy5wdXNoKGVuY1BhcmFtKTtcbiAgICAgIGlmIChoYXNSZWQpIHtcbiAgICAgICAgZW5jUGFyYW0gPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGVuY1BhcmFtKSk7XG4gICAgICAgIGVuY1BhcmFtLmZlYyA9IHtcbiAgICAgICAgICBzc3JjOiBwcmltYXJ5U3NyYyxcbiAgICAgICAgICBtZWNoYW5pc206IGhhc1VscGZlYyA/ICdyZWQrdWxwZmVjJyA6ICdyZWQnLFxuICAgICAgICB9O1xuICAgICAgICBlbmNvZGluZ1BhcmFtZXRlcnMucHVzaChlbmNQYXJhbSk7XG4gICAgICB9XG4gICAgfVxuICB9KTtcbiAgaWYgKGVuY29kaW5nUGFyYW1ldGVycy5sZW5ndGggPT09IDAgJiYgcHJpbWFyeVNzcmMpIHtcbiAgICBlbmNvZGluZ1BhcmFtZXRlcnMucHVzaCh7XG4gICAgICBzc3JjOiBwcmltYXJ5U3NyYyxcbiAgICB9KTtcbiAgfVxuXG4gIC8vIHdlIHN1cHBvcnQgYm90aCBiPUFTIGFuZCBiPVRJQVMgYnV0IGludGVycHJldCBBUyBhcyBUSUFTLlxuICBsZXQgYmFuZHdpZHRoID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYj0nKTtcbiAgaWYgKGJhbmR3aWR0aC5sZW5ndGgpIHtcbiAgICBpZiAoYmFuZHdpZHRoWzBdLmluZGV4T2YoJ2I9VElBUzonKSA9PT0gMCkge1xuICAgICAgYmFuZHdpZHRoID0gcGFyc2VJbnQoYmFuZHdpZHRoWzBdLnN1YnN0cmluZyg3KSwgMTApO1xuICAgIH0gZWxzZSBpZiAoYmFuZHdpZHRoWzBdLmluZGV4T2YoJ2I9QVM6JykgPT09IDApIHtcbiAgICAgIC8vIHVzZSBmb3JtdWxhIGZyb20gSlNFUCB0byBjb252ZXJ0IGI9QVMgdG8gVElBUyB2YWx1ZS5cbiAgICAgIGJhbmR3aWR0aCA9IHBhcnNlSW50KGJhbmR3aWR0aFswXS5zdWJzdHJpbmcoNSksIDEwKSAqIDEwMDAgKiAwLjk1XG4gICAgICAgICAgLSAoNTAgKiA0MCAqIDgpO1xuICAgIH0gZWxzZSB7XG4gICAgICBiYW5kd2lkdGggPSB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGVuY29kaW5nUGFyYW1ldGVycy5mb3JFYWNoKHBhcmFtcyA9PiB7XG4gICAgICBwYXJhbXMubWF4Qml0cmF0ZSA9IGJhbmR3aWR0aDtcbiAgICB9KTtcbiAgfVxuICByZXR1cm4gZW5jb2RpbmdQYXJhbWV0ZXJzO1xufTtcblxuLy8gcGFyc2VzIGh0dHA6Ly9kcmFmdC5vcnRjLm9yZy8jcnRjcnRjcHBhcmFtZXRlcnMqXG5TRFBVdGlscy5wYXJzZVJ0Y3BQYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIGNvbnN0IHJ0Y3BQYXJhbWV0ZXJzID0ge307XG5cbiAgLy8gR2V0cyB0aGUgZmlyc3QgU1NSQy4gTm90ZSB0aGF0IHdpdGggUlRYIHRoZXJlIG1pZ2h0IGJlIG11bHRpcGxlXG4gIC8vIFNTUkNzLlxuICBjb25zdCByZW1vdGVTc3JjID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1zc3JjOicpXG4gICAgLm1hcChsaW5lID0+IFNEUFV0aWxzLnBhcnNlU3NyY01lZGlhKGxpbmUpKVxuICAgIC5maWx0ZXIob2JqID0+IG9iai5hdHRyaWJ1dGUgPT09ICdjbmFtZScpWzBdO1xuICBpZiAocmVtb3RlU3NyYykge1xuICAgIHJ0Y3BQYXJhbWV0ZXJzLmNuYW1lID0gcmVtb3RlU3NyYy52YWx1ZTtcbiAgICBydGNwUGFyYW1ldGVycy5zc3JjID0gcmVtb3RlU3NyYy5zc3JjO1xuICB9XG5cbiAgLy8gRWRnZSB1c2VzIHRoZSBjb21wb3VuZCBhdHRyaWJ1dGUgaW5zdGVhZCBvZiByZWR1Y2VkU2l6ZVxuICAvLyBjb21wb3VuZCBpcyAhcmVkdWNlZFNpemVcbiAgY29uc3QgcnNpemUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXJ0Y3AtcnNpemUnKTtcbiAgcnRjcFBhcmFtZXRlcnMucmVkdWNlZFNpemUgPSByc2l6ZS5sZW5ndGggPiAwO1xuICBydGNwUGFyYW1ldGVycy5jb21wb3VuZCA9IHJzaXplLmxlbmd0aCA9PT0gMDtcblxuICAvLyBwYXJzZXMgdGhlIHJ0Y3AtbXV4IGF0dHLRlmJ1dGUuXG4gIC8vIE5vdGUgdGhhdCBFZGdlIGRvZXMgbm90IHN1cHBvcnQgdW5tdXhlZCBSVENQLlxuICBjb25zdCBtdXggPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXJ0Y3AtbXV4Jyk7XG4gIHJ0Y3BQYXJhbWV0ZXJzLm11eCA9IG11eC5sZW5ndGggPiAwO1xuXG4gIHJldHVybiBydGNwUGFyYW1ldGVycztcbn07XG5cblNEUFV0aWxzLndyaXRlUnRjcFBhcmFtZXRlcnMgPSBmdW5jdGlvbihydGNwUGFyYW1ldGVycykge1xuICBsZXQgc2RwID0gJyc7XG4gIGlmIChydGNwUGFyYW1ldGVycy5yZWR1Y2VkU2l6ZSkge1xuICAgIHNkcCArPSAnYT1ydGNwLXJzaXplXFxyXFxuJztcbiAgfVxuICBpZiAocnRjcFBhcmFtZXRlcnMubXV4KSB7XG4gICAgc2RwICs9ICdhPXJ0Y3AtbXV4XFxyXFxuJztcbiAgfVxuICBpZiAocnRjcFBhcmFtZXRlcnMuc3NyYyAhPT0gdW5kZWZpbmVkICYmIHJ0Y3BQYXJhbWV0ZXJzLmNuYW1lKSB7XG4gICAgc2RwICs9ICdhPXNzcmM6JyArIHJ0Y3BQYXJhbWV0ZXJzLnNzcmMgK1xuICAgICAgJyBjbmFtZTonICsgcnRjcFBhcmFtZXRlcnMuY25hbWUgKyAnXFxyXFxuJztcbiAgfVxuICByZXR1cm4gc2RwO1xufTtcblxuXG4vLyBwYXJzZXMgZWl0aGVyIGE9bXNpZDogb3IgYT1zc3JjOi4uLiBtc2lkIGxpbmVzIGFuZCByZXR1cm5zXG4vLyB0aGUgaWQgb2YgdGhlIE1lZGlhU3RyZWFtIGFuZCBNZWRpYVN0cmVhbVRyYWNrLlxuU0RQVXRpbHMucGFyc2VNc2lkID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIGxldCBwYXJ0cztcbiAgY29uc3Qgc3BlYyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9bXNpZDonKTtcbiAgaWYgKHNwZWMubGVuZ3RoID09PSAxKSB7XG4gICAgcGFydHMgPSBzcGVjWzBdLnN1YnN0cmluZyg3KS5zcGxpdCgnICcpO1xuICAgIHJldHVybiB7c3RyZWFtOiBwYXJ0c1swXSwgdHJhY2s6IHBhcnRzWzFdfTtcbiAgfVxuICBjb25zdCBwbGFuQiA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9c3NyYzonKVxuICAgIC5tYXAobGluZSA9PiBTRFBVdGlscy5wYXJzZVNzcmNNZWRpYShsaW5lKSlcbiAgICAuZmlsdGVyKG1zaWRQYXJ0cyA9PiBtc2lkUGFydHMuYXR0cmlidXRlID09PSAnbXNpZCcpO1xuICBpZiAocGxhbkIubGVuZ3RoID4gMCkge1xuICAgIHBhcnRzID0gcGxhbkJbMF0udmFsdWUuc3BsaXQoJyAnKTtcbiAgICByZXR1cm4ge3N0cmVhbTogcGFydHNbMF0sIHRyYWNrOiBwYXJ0c1sxXX07XG4gIH1cbn07XG5cbi8vIFNDVFBcbi8vIHBhcnNlcyBkcmFmdC1pZXRmLW1tdXNpYy1zY3RwLXNkcC0yNiBmaXJzdCBhbmQgZmFsbHMgYmFja1xuLy8gdG8gZHJhZnQtaWV0Zi1tbXVzaWMtc2N0cC1zZHAtMDVcblNEUFV0aWxzLnBhcnNlU2N0cERlc2NyaXB0aW9uID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIGNvbnN0IG1saW5lID0gU0RQVXRpbHMucGFyc2VNTGluZShtZWRpYVNlY3Rpb24pO1xuICBjb25zdCBtYXhTaXplTGluZSA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9bWF4LW1lc3NhZ2Utc2l6ZTonKTtcbiAgbGV0IG1heE1lc3NhZ2VTaXplO1xuICBpZiAobWF4U2l6ZUxpbmUubGVuZ3RoID4gMCkge1xuICAgIG1heE1lc3NhZ2VTaXplID0gcGFyc2VJbnQobWF4U2l6ZUxpbmVbMF0uc3Vic3RyaW5nKDE5KSwgMTApO1xuICB9XG4gIGlmIChpc05hTihtYXhNZXNzYWdlU2l6ZSkpIHtcbiAgICBtYXhNZXNzYWdlU2l6ZSA9IDY1NTM2O1xuICB9XG4gIGNvbnN0IHNjdHBQb3J0ID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1zY3RwLXBvcnQ6Jyk7XG4gIGlmIChzY3RwUG9ydC5sZW5ndGggPiAwKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHBvcnQ6IHBhcnNlSW50KHNjdHBQb3J0WzBdLnN1YnN0cmluZygxMiksIDEwKSxcbiAgICAgIHByb3RvY29sOiBtbGluZS5mbXQsXG4gICAgICBtYXhNZXNzYWdlU2l6ZSxcbiAgICB9O1xuICB9XG4gIGNvbnN0IHNjdHBNYXBMaW5lcyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9c2N0cG1hcDonKTtcbiAgaWYgKHNjdHBNYXBMaW5lcy5sZW5ndGggPiAwKSB7XG4gICAgY29uc3QgcGFydHMgPSBzY3RwTWFwTGluZXNbMF1cbiAgICAgIC5zdWJzdHJpbmcoMTApXG4gICAgICAuc3BsaXQoJyAnKTtcbiAgICByZXR1cm4ge1xuICAgICAgcG9ydDogcGFyc2VJbnQocGFydHNbMF0sIDEwKSxcbiAgICAgIHByb3RvY29sOiBwYXJ0c1sxXSxcbiAgICAgIG1heE1lc3NhZ2VTaXplLFxuICAgIH07XG4gIH1cbn07XG5cbi8vIFNDVFBcbi8vIG91dHB1dHMgdGhlIGRyYWZ0LWlldGYtbW11c2ljLXNjdHAtc2RwLTI2IHZlcnNpb24gdGhhdCBhbGwgYnJvd3NlcnNcbi8vIHN1cHBvcnQgYnkgbm93IHJlY2VpdmluZyBpbiB0aGlzIGZvcm1hdCwgdW5sZXNzIHdlIG9yaWdpbmFsbHkgcGFyc2VkXG4vLyBhcyB0aGUgZHJhZnQtaWV0Zi1tbXVzaWMtc2N0cC1zZHAtMDUgZm9ybWF0IChpbmRpY2F0ZWQgYnkgdGhlIG0tbGluZVxuLy8gcHJvdG9jb2wgb2YgRFRMUy9TQ1RQIC0tIHdpdGhvdXQgVURQLyBvciBUQ1AvKVxuU0RQVXRpbHMud3JpdGVTY3RwRGVzY3JpcHRpb24gPSBmdW5jdGlvbihtZWRpYSwgc2N0cCkge1xuICBsZXQgb3V0cHV0ID0gW107XG4gIGlmIChtZWRpYS5wcm90b2NvbCAhPT0gJ0RUTFMvU0NUUCcpIHtcbiAgICBvdXRwdXQgPSBbXG4gICAgICAnbT0nICsgbWVkaWEua2luZCArICcgOSAnICsgbWVkaWEucHJvdG9jb2wgKyAnICcgKyBzY3RwLnByb3RvY29sICsgJ1xcclxcbicsXG4gICAgICAnYz1JTiBJUDQgMC4wLjAuMFxcclxcbicsXG4gICAgICAnYT1zY3RwLXBvcnQ6JyArIHNjdHAucG9ydCArICdcXHJcXG4nLFxuICAgIF07XG4gIH0gZWxzZSB7XG4gICAgb3V0cHV0ID0gW1xuICAgICAgJ209JyArIG1lZGlhLmtpbmQgKyAnIDkgJyArIG1lZGlhLnByb3RvY29sICsgJyAnICsgc2N0cC5wb3J0ICsgJ1xcclxcbicsXG4gICAgICAnYz1JTiBJUDQgMC4wLjAuMFxcclxcbicsXG4gICAgICAnYT1zY3RwbWFwOicgKyBzY3RwLnBvcnQgKyAnICcgKyBzY3RwLnByb3RvY29sICsgJyA2NTUzNVxcclxcbicsXG4gICAgXTtcbiAgfVxuICBpZiAoc2N0cC5tYXhNZXNzYWdlU2l6ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgb3V0cHV0LnB1c2goJ2E9bWF4LW1lc3NhZ2Utc2l6ZTonICsgc2N0cC5tYXhNZXNzYWdlU2l6ZSArICdcXHJcXG4nKTtcbiAgfVxuICByZXR1cm4gb3V0cHV0LmpvaW4oJycpO1xufTtcblxuLy8gR2VuZXJhdGUgYSBzZXNzaW9uIElEIGZvciBTRFAuXG4vLyBodHRwczovL3Rvb2xzLmlldGYub3JnL2h0bWwvZHJhZnQtaWV0Zi1ydGN3ZWItanNlcC0yMCNzZWN0aW9uLTUuMi4xXG4vLyByZWNvbW1lbmRzIHVzaW5nIGEgY3J5cHRvZ3JhcGhpY2FsbHkgcmFuZG9tICt2ZSA2NC1iaXQgdmFsdWVcbi8vIGJ1dCByaWdodCBub3cgdGhpcyBzaG91bGQgYmUgYWNjZXB0YWJsZSBhbmQgd2l0aGluIHRoZSByaWdodCByYW5nZVxuU0RQVXRpbHMuZ2VuZXJhdGVTZXNzaW9uSWQgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIE1hdGgucmFuZG9tKCkudG9TdHJpbmcoKS5zdWJzdHIoMiwgMjIpO1xufTtcblxuLy8gV3JpdGUgYm9pbGVyIHBsYXRlIGZvciBzdGFydCBvZiBTRFBcbi8vIHNlc3NJZCBhcmd1bWVudCBpcyBvcHRpb25hbCAtIGlmIG5vdCBzdXBwbGllZCBpdCB3aWxsXG4vLyBiZSBnZW5lcmF0ZWQgcmFuZG9tbHlcbi8vIHNlc3NWZXJzaW9uIGlzIG9wdGlvbmFsIGFuZCBkZWZhdWx0cyB0byAyXG4vLyBzZXNzVXNlciBpcyBvcHRpb25hbCBhbmQgZGVmYXVsdHMgdG8gJ3RoaXNpc2FkYXB0ZXJvcnRjJ1xuU0RQVXRpbHMud3JpdGVTZXNzaW9uQm9pbGVycGxhdGUgPSBmdW5jdGlvbihzZXNzSWQsIHNlc3NWZXIsIHNlc3NVc2VyKSB7XG4gIGxldCBzZXNzaW9uSWQ7XG4gIGNvbnN0IHZlcnNpb24gPSBzZXNzVmVyICE9PSB1bmRlZmluZWQgPyBzZXNzVmVyIDogMjtcbiAgaWYgKHNlc3NJZCkge1xuICAgIHNlc3Npb25JZCA9IHNlc3NJZDtcbiAgfSBlbHNlIHtcbiAgICBzZXNzaW9uSWQgPSBTRFBVdGlscy5nZW5lcmF0ZVNlc3Npb25JZCgpO1xuICB9XG4gIGNvbnN0IHVzZXIgPSBzZXNzVXNlciB8fCAndGhpc2lzYWRhcHRlcm9ydGMnO1xuICAvLyBGSVhNRTogc2Vzcy1pZCBzaG91bGQgYmUgYW4gTlRQIHRpbWVzdGFtcC5cbiAgcmV0dXJuICd2PTBcXHJcXG4nICtcbiAgICAgICdvPScgKyB1c2VyICsgJyAnICsgc2Vzc2lvbklkICsgJyAnICsgdmVyc2lvbiArXG4gICAgICAgICcgSU4gSVA0IDEyNy4wLjAuMVxcclxcbicgK1xuICAgICAgJ3M9LVxcclxcbicgK1xuICAgICAgJ3Q9MCAwXFxyXFxuJztcbn07XG5cbi8vIEdldHMgdGhlIGRpcmVjdGlvbiBmcm9tIHRoZSBtZWRpYVNlY3Rpb24gb3IgdGhlIHNlc3Npb25wYXJ0LlxuU0RQVXRpbHMuZ2V0RGlyZWN0aW9uID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZXNzaW9ucGFydCkge1xuICAvLyBMb29rIGZvciBzZW5kcmVjdiwgc2VuZG9ubHksIHJlY3Zvbmx5LCBpbmFjdGl2ZSwgZGVmYXVsdCB0byBzZW5kcmVjdi5cbiAgY29uc3QgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICBzd2l0Y2ggKGxpbmVzW2ldKSB7XG4gICAgICBjYXNlICdhPXNlbmRyZWN2JzpcbiAgICAgIGNhc2UgJ2E9c2VuZG9ubHknOlxuICAgICAgY2FzZSAnYT1yZWN2b25seSc6XG4gICAgICBjYXNlICdhPWluYWN0aXZlJzpcbiAgICAgICAgcmV0dXJuIGxpbmVzW2ldLnN1YnN0cmluZygyKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIC8vIEZJWE1FOiBXaGF0IHNob3VsZCBoYXBwZW4gaGVyZT9cbiAgICB9XG4gIH1cbiAgaWYgKHNlc3Npb25wYXJ0KSB7XG4gICAgcmV0dXJuIFNEUFV0aWxzLmdldERpcmVjdGlvbihzZXNzaW9ucGFydCk7XG4gIH1cbiAgcmV0dXJuICdzZW5kcmVjdic7XG59O1xuXG5TRFBVdGlscy5nZXRLaW5kID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIGNvbnN0IGxpbmVzID0gU0RQVXRpbHMuc3BsaXRMaW5lcyhtZWRpYVNlY3Rpb24pO1xuICBjb25zdCBtbGluZSA9IGxpbmVzWzBdLnNwbGl0KCcgJyk7XG4gIHJldHVybiBtbGluZVswXS5zdWJzdHJpbmcoMik7XG59O1xuXG5TRFBVdGlscy5pc1JlamVjdGVkID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIHJldHVybiBtZWRpYVNlY3Rpb24uc3BsaXQoJyAnLCAyKVsxXSA9PT0gJzAnO1xufTtcblxuU0RQVXRpbHMucGFyc2VNTGluZSA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbikge1xuICBjb25zdCBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMobWVkaWFTZWN0aW9uKTtcbiAgY29uc3QgcGFydHMgPSBsaW5lc1swXS5zdWJzdHJpbmcoMikuc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICBraW5kOiBwYXJ0c1swXSxcbiAgICBwb3J0OiBwYXJzZUludChwYXJ0c1sxXSwgMTApLFxuICAgIHByb3RvY29sOiBwYXJ0c1syXSxcbiAgICBmbXQ6IHBhcnRzLnNsaWNlKDMpLmpvaW4oJyAnKSxcbiAgfTtcbn07XG5cblNEUFV0aWxzLnBhcnNlT0xpbmUgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgY29uc3QgbGluZSA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ289JylbMF07XG4gIGNvbnN0IHBhcnRzID0gbGluZS5zdWJzdHJpbmcoMikuc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICB1c2VybmFtZTogcGFydHNbMF0sXG4gICAgc2Vzc2lvbklkOiBwYXJ0c1sxXSxcbiAgICBzZXNzaW9uVmVyc2lvbjogcGFyc2VJbnQocGFydHNbMl0sIDEwKSxcbiAgICBuZXRUeXBlOiBwYXJ0c1szXSxcbiAgICBhZGRyZXNzVHlwZTogcGFydHNbNF0sXG4gICAgYWRkcmVzczogcGFydHNbNV0sXG4gIH07XG59O1xuXG4vLyBhIHZlcnkgbmFpdmUgaW50ZXJwcmV0YXRpb24gb2YgYSB2YWxpZCBTRFAuXG5TRFBVdGlscy5pc1ZhbGlkU0RQID0gZnVuY3Rpb24oYmxvYikge1xuICBpZiAodHlwZW9mIGJsb2IgIT09ICdzdHJpbmcnIHx8IGJsb2IubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGNvbnN0IGxpbmVzID0gU0RQVXRpbHMuc3BsaXRMaW5lcyhibG9iKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKykge1xuICAgIGlmIChsaW5lc1tpXS5sZW5ndGggPCAyIHx8IGxpbmVzW2ldLmNoYXJBdCgxKSAhPT0gJz0nKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIC8vIFRPRE86IGNoZWNrIHRoZSBtb2RpZmllciBhIGJpdCBtb3JlLlxuICB9XG4gIHJldHVybiB0cnVlO1xufTtcblxuLy8gRXhwb3NlIHB1YmxpYyBtZXRob2RzLlxuaWYgKHR5cGVvZiBtb2R1bGUgPT09ICdvYmplY3QnKSB7XG4gIG1vZHVsZS5leHBvcnRzID0gU0RQVXRpbHM7XG59XG4iLCIvLyBUaGUgbW9kdWxlIGNhY2hlXG52YXIgX193ZWJwYWNrX21vZHVsZV9jYWNoZV9fID0ge307XG5cbi8vIFRoZSByZXF1aXJlIGZ1bmN0aW9uXG5mdW5jdGlvbiBfX3dlYnBhY2tfcmVxdWlyZV9fKG1vZHVsZUlkKSB7XG5cdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuXHR2YXIgY2FjaGVkTW9kdWxlID0gX193ZWJwYWNrX21vZHVsZV9jYWNoZV9fW21vZHVsZUlkXTtcblx0aWYgKGNhY2hlZE1vZHVsZSAhPT0gdW5kZWZpbmVkKSB7XG5cdFx0cmV0dXJuIGNhY2hlZE1vZHVsZS5leHBvcnRzO1xuXHR9XG5cdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG5cdHZhciBtb2R1bGUgPSBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX19bbW9kdWxlSWRdID0ge1xuXHRcdC8vIG5vIG1vZHVsZS5pZCBuZWVkZWRcblx0XHQvLyBubyBtb2R1bGUubG9hZGVkIG5lZWRlZFxuXHRcdGV4cG9ydHM6IHt9XG5cdH07XG5cblx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG5cdF9fd2VicGFja19tb2R1bGVzX19bbW9kdWxlSWRdKG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xuXG5cdC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXG5cdHJldHVybiBtb2R1bGUuZXhwb3J0cztcbn1cblxuIiwiIiwiLy8gc3RhcnR1cFxuLy8gTG9hZCBlbnRyeSBtb2R1bGUgYW5kIHJldHVybiBleHBvcnRzXG4vLyBUaGlzIGVudHJ5IG1vZHVsZSBpcyByZWZlcmVuY2VkIGJ5IG90aGVyIG1vZHVsZXMgc28gaXQgY2FuJ3QgYmUgaW5saW5lZFxudmFyIF9fd2VicGFja19leHBvcnRzX18gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKFwiLi9zcmMvaW5kZXguanNcIik7XG4iLCIiXSwibmFtZXMiOlsibWoiLCJyZXF1aXJlIiwiSmFudXNTZXNzaW9uIiwicHJvdG90eXBlIiwic2VuZE9yaWdpbmFsIiwic2VuZCIsInR5cGUiLCJzaWduYWwiLCJjYXRjaCIsImUiLCJtZXNzYWdlIiwiaW5kZXhPZiIsImNvbnNvbGUiLCJlcnJvciIsIk5BRiIsImNvbm5lY3Rpb24iLCJhZGFwdGVyIiwicmVjb25uZWN0Iiwic2RwVXRpbHMiLCJkZWJ1ZyIsIndhcm4iLCJpc1NhZmFyaSIsInRlc3QiLCJuYXZpZ2F0b3IiLCJ1c2VyQWdlbnQiLCJTVUJTQ1JJQkVfVElNRU9VVF9NUyIsIkFWQUlMQUJMRV9PQ0NVUEFOVFNfVEhSRVNIT0xEIiwiTUFYX1NVQlNDUklCRV9ERUxBWSIsInJhbmRvbURlbGF5IiwibWluIiwibWF4IiwiUHJvbWlzZSIsInJlc29sdmUiLCJkZWxheSIsIk1hdGgiLCJyYW5kb20iLCJzZXRUaW1lb3V0IiwiZGVib3VuY2UiLCJmbiIsImN1cnIiLCJhcmdzIiwiQXJyYXkiLCJzbGljZSIsImNhbGwiLCJhcmd1bWVudHMiLCJ0aGVuIiwiXyIsImFwcGx5IiwicmFuZG9tVWludCIsImZsb29yIiwiTnVtYmVyIiwiTUFYX1NBRkVfSU5URUdFUiIsInVudGlsRGF0YUNoYW5uZWxPcGVuIiwiZGF0YUNoYW5uZWwiLCJyZWplY3QiLCJyZWFkeVN0YXRlIiwicmVzb2x2ZXIiLCJyZWplY3RvciIsImNsZWFyIiwicmVtb3ZlRXZlbnRMaXN0ZW5lciIsImFkZEV2ZW50TGlzdGVuZXIiLCJpc0gyNjRWaWRlb1N1cHBvcnRlZCIsInZpZGVvIiwiZG9jdW1lbnQiLCJjcmVhdGVFbGVtZW50IiwiY2FuUGxheVR5cGUiLCJPUFVTX1BBUkFNRVRFUlMiLCJ1c2VkdHgiLCJzdGVyZW8iLCJERUZBVUxUX1BFRVJfQ09OTkVDVElPTl9DT05GSUciLCJpY2VTZXJ2ZXJzIiwidXJscyIsIldTX05PUk1BTF9DTE9TVVJFIiwiSmFudXNBZGFwdGVyIiwiY29uc3RydWN0b3IiLCJyb29tIiwiY2xpZW50SWQiLCJqb2luVG9rZW4iLCJzZXJ2ZXJVcmwiLCJ3ZWJSdGNPcHRpb25zIiwicGVlckNvbm5lY3Rpb25Db25maWciLCJ3cyIsInNlc3Npb24iLCJyZWxpYWJsZVRyYW5zcG9ydCIsInVucmVsaWFibGVUcmFuc3BvcnQiLCJpbml0aWFsUmVjb25uZWN0aW9uRGVsYXkiLCJyZWNvbm5lY3Rpb25EZWxheSIsInJlY29ubmVjdGlvblRpbWVvdXQiLCJtYXhSZWNvbm5lY3Rpb25BdHRlbXB0cyIsInJlY29ubmVjdGlvbkF0dGVtcHRzIiwicHVibGlzaGVyIiwib2NjdXBhbnRJZHMiLCJvY2N1cGFudHMiLCJtZWRpYVN0cmVhbXMiLCJsb2NhbE1lZGlhU3RyZWFtIiwicGVuZGluZ01lZGlhUmVxdWVzdHMiLCJNYXAiLCJwZW5kaW5nT2NjdXBhbnRzIiwiU2V0IiwiYXZhaWxhYmxlT2NjdXBhbnRzIiwicmVxdWVzdGVkT2NjdXBhbnRzIiwiYmxvY2tlZENsaWVudHMiLCJmcm96ZW5VcGRhdGVzIiwidGltZU9mZnNldHMiLCJzZXJ2ZXJUaW1lUmVxdWVzdHMiLCJhdmdUaW1lT2Zmc2V0Iiwib25XZWJzb2NrZXRPcGVuIiwiYmluZCIsIm9uV2Vic29ja2V0Q2xvc2UiLCJvbldlYnNvY2tldE1lc3NhZ2UiLCJvbkRhdGFDaGFubmVsTWVzc2FnZSIsIm9uRGF0YSIsInNldFNlcnZlclVybCIsInVybCIsInNldEFwcCIsImFwcCIsInNldFJvb20iLCJyb29tTmFtZSIsInNldEpvaW5Ub2tlbiIsInNldENsaWVudElkIiwic2V0V2ViUnRjT3B0aW9ucyIsIm9wdGlvbnMiLCJzZXRQZWVyQ29ubmVjdGlvbkNvbmZpZyIsInNldFNlcnZlckNvbm5lY3RMaXN0ZW5lcnMiLCJzdWNjZXNzTGlzdGVuZXIiLCJmYWlsdXJlTGlzdGVuZXIiLCJjb25uZWN0U3VjY2VzcyIsImNvbm5lY3RGYWlsdXJlIiwic2V0Um9vbU9jY3VwYW50TGlzdGVuZXIiLCJvY2N1cGFudExpc3RlbmVyIiwib25PY2N1cGFudHNDaGFuZ2VkIiwic2V0RGF0YUNoYW5uZWxMaXN0ZW5lcnMiLCJvcGVuTGlzdGVuZXIiLCJjbG9zZWRMaXN0ZW5lciIsIm1lc3NhZ2VMaXN0ZW5lciIsIm9uT2NjdXBhbnRDb25uZWN0ZWQiLCJvbk9jY3VwYW50RGlzY29ubmVjdGVkIiwib25PY2N1cGFudE1lc3NhZ2UiLCJzZXRSZWNvbm5lY3Rpb25MaXN0ZW5lcnMiLCJyZWNvbm5lY3RpbmdMaXN0ZW5lciIsInJlY29ubmVjdGVkTGlzdGVuZXIiLCJyZWNvbm5lY3Rpb25FcnJvckxpc3RlbmVyIiwib25SZWNvbm5lY3RpbmciLCJvblJlY29ubmVjdGVkIiwib25SZWNvbm5lY3Rpb25FcnJvciIsInNldEV2ZW50TG9vcHMiLCJsb29wcyIsImNvbm5lY3QiLCJ3ZWJzb2NrZXRDb25uZWN0aW9uIiwiV2ViU29ja2V0IiwidGltZW91dE1zIiwid3NPbk9wZW4iLCJhbGwiLCJ1cGRhdGVUaW1lT2Zmc2V0IiwiZGlzY29ubmVjdCIsImNsZWFyVGltZW91dCIsInJlbW92ZUFsbE9jY3VwYW50cyIsImNvbm4iLCJjbG9zZSIsImRpc3Bvc2UiLCJkZWxheWVkUmVjb25uZWN0VGltZW91dCIsImlzRGlzY29ubmVjdGVkIiwiY3JlYXRlIiwiY3JlYXRlUHVibGlzaGVyIiwiaSIsImluaXRpYWxPY2N1cGFudHMiLCJsZW5ndGgiLCJvY2N1cGFudElkIiwiYWRkQXZhaWxhYmxlT2NjdXBhbnQiLCJzeW5jT2NjdXBhbnRzIiwiZXZlbnQiLCJjb2RlIiwiRXJyb3IiLCJwZXJmb3JtRGVsYXllZFJlY29ubmVjdCIsInJlY2VpdmUiLCJKU09OIiwicGFyc2UiLCJkYXRhIiwicHVzaCIsInJlbW92ZUF2YWlsYWJsZU9jY3VwYW50IiwiaWR4Iiwic3BsaWNlIiwiaGFzIiwiYWRkT2NjdXBhbnQiLCJqIiwicmVtb3ZlT2NjdXBhbnQiLCJhZGQiLCJhdmFpbGFibGVPY2N1cGFudHNDb3VudCIsInN1YnNjcmliZXIiLCJjcmVhdGVTdWJzY3JpYmVyIiwiZGVsZXRlIiwic2V0TWVkaWFTdHJlYW0iLCJtZWRpYVN0cmVhbSIsIm1zZyIsImdldCIsImF1ZGlvIiwiYXNzb2NpYXRlIiwiaGFuZGxlIiwiZXYiLCJzZW5kVHJpY2tsZSIsImNhbmRpZGF0ZSIsImljZUNvbm5lY3Rpb25TdGF0ZSIsImxvZyIsIm9mZmVyIiwiY3JlYXRlT2ZmZXIiLCJjb25maWd1cmVQdWJsaXNoZXJTZHAiLCJmaXhTYWZhcmlJY2VVRnJhZyIsImxvY2FsIiwibyIsInNldExvY2FsRGVzY3JpcHRpb24iLCJyZW1vdGUiLCJzZW5kSnNlcCIsInIiLCJzZXRSZW1vdGVEZXNjcmlwdGlvbiIsImpzZXAiLCJvbiIsImFuc3dlciIsImNvbmZpZ3VyZVN1YnNjcmliZXJTZHAiLCJjcmVhdGVBbnN3ZXIiLCJhIiwiSmFudXNQbHVnaW5IYW5kbGUiLCJSVENQZWVyQ29ubmVjdGlvbiIsImF0dGFjaCIsInBhcnNlSW50IiwidW5kZWZpbmVkIiwid2VicnRjdXAiLCJyZWxpYWJsZUNoYW5uZWwiLCJjcmVhdGVEYXRhQ2hhbm5lbCIsIm9yZGVyZWQiLCJ1bnJlbGlhYmxlQ2hhbm5lbCIsIm1heFJldHJhbnNtaXRzIiwiZ2V0VHJhY2tzIiwiZm9yRWFjaCIsInRyYWNrIiwiYWRkVHJhY2siLCJwbHVnaW5kYXRhIiwicm9vbV9pZCIsInVzZXJfaWQiLCJib2R5IiwiZGlzcGF0Y2hFdmVudCIsIkN1c3RvbUV2ZW50IiwiZGV0YWlsIiwiYnkiLCJzZW5kSm9pbiIsIm5vdGlmaWNhdGlvbnMiLCJzdWNjZXNzIiwiZXJyIiwicmVzcG9uc2UiLCJ1c2VycyIsImluY2x1ZGVzIiwic2RwIiwicmVwbGFjZSIsImxpbmUiLCJwdCIsInBhcmFtZXRlcnMiLCJPYmplY3QiLCJhc3NpZ24iLCJwYXJzZUZtdHAiLCJ3cml0ZUZtdHAiLCJwYXlsb2FkVHlwZSIsIm1heFJldHJpZXMiLCJ3ZWJydGNGYWlsZWQiLCJsZWZ0SW50ZXJ2YWwiLCJzZXRJbnRlcnZhbCIsImNsZWFySW50ZXJ2YWwiLCJ0aW1lb3V0IiwibWVkaWEiLCJfaU9TSGFja0RlbGF5ZWRJbml0aWFsUGVlciIsIk1lZGlhU3RyZWFtIiwicmVjZWl2ZXJzIiwiZ2V0UmVjZWl2ZXJzIiwicmVjZWl2ZXIiLCJzdWJzY3JpYmUiLCJzZW5kTWVzc2FnZSIsImtpbmQiLCJ0b2tlbiIsInRvZ2dsZUZyZWV6ZSIsImZyb3plbiIsInVuZnJlZXplIiwiZnJlZXplIiwiZmx1c2hQZW5kaW5nVXBkYXRlcyIsImRhdGFGb3JVcGRhdGVNdWx0aU1lc3NhZ2UiLCJuZXR3b3JrSWQiLCJsIiwiZCIsImdldFBlbmRpbmdEYXRhIiwiZGF0YVR5cGUiLCJvd25lciIsImdldFBlbmRpbmdEYXRhRm9yTmV0d29ya0lkIiwic291cmNlIiwic3RvcmVNZXNzYWdlIiwic3RvcmVTaW5nbGVNZXNzYWdlIiwiaW5kZXgiLCJzZXQiLCJzdG9yZWRNZXNzYWdlIiwic3RvcmVkRGF0YSIsImlzT3V0ZGF0ZWRNZXNzYWdlIiwibGFzdE93bmVyVGltZSIsImlzQ29udGVtcG9yYW5lb3VzTWVzc2FnZSIsImNyZWF0ZWRXaGlsZUZyb3plbiIsImlzRmlyc3RTeW5jIiwiY29tcG9uZW50cyIsImVuYWJsZWQiLCJzaG91bGRTdGFydENvbm5lY3Rpb25UbyIsImNsaWVudCIsInN0YXJ0U3RyZWFtQ29ubmVjdGlvbiIsImNsb3NlU3RyZWFtQ29ubmVjdGlvbiIsImdldENvbm5lY3RTdGF0dXMiLCJhZGFwdGVycyIsIklTX0NPTk5FQ1RFRCIsIk5PVF9DT05ORUNURUQiLCJjbGllbnRTZW50VGltZSIsIkRhdGUiLCJub3ciLCJyZXMiLCJmZXRjaCIsImxvY2F0aW9uIiwiaHJlZiIsIm1ldGhvZCIsImNhY2hlIiwicHJlY2lzaW9uIiwic2VydmVyUmVjZWl2ZWRUaW1lIiwiaGVhZGVycyIsImdldFRpbWUiLCJjbGllbnRSZWNlaXZlZFRpbWUiLCJzZXJ2ZXJUaW1lIiwidGltZU9mZnNldCIsInJlZHVjZSIsImFjYyIsIm9mZnNldCIsImdldFNlcnZlclRpbWUiLCJnZXRNZWRpYVN0cmVhbSIsImF1ZGlvUHJvbWlzZSIsInZpZGVvUHJvbWlzZSIsInByb21pc2UiLCJzdHJlYW0iLCJhdWRpb1N0cmVhbSIsImdldEF1ZGlvVHJhY2tzIiwidmlkZW9TdHJlYW0iLCJnZXRWaWRlb1RyYWNrcyIsInNldExvY2FsTWVkaWFTdHJlYW0iLCJleGlzdGluZ1NlbmRlcnMiLCJnZXRTZW5kZXJzIiwibmV3U2VuZGVycyIsInRyYWNrcyIsInQiLCJzZW5kZXIiLCJmaW5kIiwicyIsInJlcGxhY2VUcmFjayIsInRvTG93ZXJDYXNlIiwicmVtb3ZlVHJhY2siLCJlbmFibGVNaWNyb3Bob25lIiwic2VuZERhdGEiLCJzdHJpbmdpZnkiLCJ3aG9tIiwic2VuZERhdGFHdWFyYW50ZWVkIiwiYnJvYWRjYXN0RGF0YSIsImJyb2FkY2FzdERhdGFHdWFyYW50ZWVkIiwia2ljayIsInBlcm1zVG9rZW4iLCJibG9jayIsInVuYmxvY2siLCJyZWdpc3RlciIsIm1vZHVsZSIsImV4cG9ydHMiXSwic291cmNlUm9vdCI6IiJ9 \ No newline at end of file diff --git a/dist/naf-janus-adapter.min.js b/dist/naf-janus-adapter.min.js index 7b54003..d08c5c4 100644 --- a/dist/naf-janus-adapter.min.js +++ b/dist/naf-janus-adapter.min.js @@ -1,3 +1,2 @@ -/*! For license information please see naf-janus-adapter.min.js.LICENSE.txt */ -(()=>{var e={806: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 r=0;r{var s=null;this.options.timeoutMs&&(s=setTimeout((()=>{delete this.txns[t.transaction],r(new Error("Signalling transaction with txid "+t.transaction+" timed out."))}),this.options.timeoutMs)),this.txns[t.transaction]={resolve:n,reject:r,timeout:s,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}},579:(e,t,n)=>{function r(e){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r(e)}function s(e,t){if(e){if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?i(e,t):void 0}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0;--s){var i=this.tryEntries[s],a=i.completion;if("root"===i.tryLoc)return r("end");if(i.tryLoc<=this.prev){var o=n.call(i,"catchLoc"),c=n.call(i,"finallyLoc");if(o&&c){if(this.prev=0;--r){var s=this.tryEntries[r];if(s.tryLoc<=this.prev&&n.call(s,"finallyLoc")&&this.prev=0;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),T(n),h}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var r=n.completion;if("throw"===r.type){var s=r.arg;T(n)}return s}}throw new Error("illegal catch attempt")},delegateYield:function(e,t,n){return this.delegate={iterator:F(e),resultName:t,nextLoc:n},"next"===this.method&&(this.arg=void 0),h}},e}function o(e,t,n,r,s,i,a){try{var o=e[i](a),c=o.value}catch(e){return void n(e)}o.done?t(c):Promise.resolve(c).then(r,s)}function c(e){return function(){var t=this,n=arguments;return new Promise((function(r,s){var i=e.apply(t,n);function a(e){o(i,r,s,a,c,"next",e)}function c(e){o(i,r,s,a,c,"throw",e)}a(void 0)}))}}function u(e,t){for(var n=0;n-1))throw e;console.error("web socket timed out"),NAF.connection.adapter.reconnect()}))};var p=n(539),d=n(227)("naf-janus-adapter:debug"),h=(n(227)("naf-janus-adapter:warn"),n(227)("naf-janus-adapter:error")),f=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function m(e,t){return new Promise((function(n){var r=Math.random()*(t-e)+e;setTimeout(n,r)}))}function g(e){var t=Promise.resolve();return function(){var n=this,r=Array.prototype.slice.call(arguments);t=t.then((function(t){return e.apply(n,r)}))}}function v(e){return new Promise((function(t,n){if("open"===e.readyState)t();else{var r,s,i=function(){e.removeEventListener("open",r),e.removeEventListener("error",s)};r=function(){i(),t()},s=function(){i(),n()},e.addEventListener("open",r),e.addEventListener("error",s)}}))}var y=""!==document.createElement("video").canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'),b={usedtx:1,stereo:0,"sprop-stereo":0},w={iceServers:[{urls:"stun:stun1.l.google.com:19302"},{urls:"stun:stun2.l.google.com:19302"}]},k=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),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)}var t,n,r,i,o,k,C,x,O;return t=e,n=[{key:"setServerUrl",value:function(e){this.serverUrl=e}},{key:"setApp",value:function(e){}},{key:"setRoom",value:function(e){this.room=e}},{key:"setJoinToken",value:function(e){this.joinToken=e}},{key:"setClientId",value:function(e){this.clientId=e}},{key:"setWebRtcOptions",value:function(e){this.webRtcOptions=e}},{key:"setPeerConnectionConfig",value:function(e){this.peerConnectionConfig=e}},{key:"setServerConnectListeners",value:function(e,t){this.connectSuccess=e,this.connectFailure=t}},{key:"setRoomOccupantListener",value:function(e){this.onOccupantsChanged=e}},{key:"setDataChannelListeners",value:function(e,t,n){this.onOccupantConnected=e,this.onOccupantDisconnected=t,this.onOccupantMessage=n}},{key:"setReconnectionListeners",value:function(e,t,n){this.onReconnecting=e,this.onReconnected=t,this.onReconnectionError=n}},{key:"setEventLoops",value:function(e){this.loops=e}},{key:"connect",value:function(){var e=this;d("connecting to ".concat(this.serverUrl));var t=new Promise((function(t,n){e.ws=new WebSocket(e.serverUrl,"janus-protocol"),e.session=new l.JanusSession(e.ws.send.bind(e.ws),{timeoutMs:4e4}),e.ws.addEventListener("close",e.onWebsocketClose),e.ws.addEventListener("message",e.onWebsocketMessage),e.wsOnOpen=function(){e.ws.removeEventListener("open",e.wsOnOpen),e.onWebsocketOpen().then(t).catch(n)},e.ws.addEventListener("open",e.wsOnOpen)}));return Promise.all([t,this.updateTimeOffset()])}},{key:"disconnect",value:function(){d("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)}},{key:"isDisconnected",value:function(){return null===this.ws}},{key:"onWebsocketOpen",value:(O=c(a().mark((function e(){var t,n;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,this.session.create();case 2:return e.next=4,this.createPublisher();case 4:this.publisher=e.sent,this.connectSuccess(this.clientId),t=0;case 7:if(!(te.maxReconnectionAttempts&&e.onReconnectionError)return e.onReconnectionError(new Error("Connection could not be reestablished, exceeded maximum number of reconnection attempts."));console.warn("Error during reconnect, retrying."),console.warn(t),e.onReconnecting&&e.onReconnecting(e.reconnectionDelay),e.reconnectionTimeout=setTimeout((function(){return e.reconnect()}),e.reconnectionDelay)}))}},{key:"performDelayedReconnect",value:function(){var e=this;this.delayedReconnectTimeout&&clearTimeout(this.delayedReconnectTimeout),this.delayedReconnectTimeout=setTimeout((function(){e.delayedReconnectTimeout=null,e.reconnect()}),1e4)}},{key:"onWebsocketMessage",value:function(e){this.session.receive(JSON.parse(e.data))}},{key:"addAvailableOccupant",value:function(e){-1===this.availableOccupants.indexOf(e)&&this.availableOccupants.push(e)}},{key:"removeAvailableOccupant",value:function(e){var t=this.availableOccupants.indexOf(e);-1!==t&&this.availableOccupants.splice(t,1)}},{key:"syncOccupants",value:function(e){if(e&&(this.requestedOccupants=e),this.requestedOccupants){for(var t=0;t5)){e.next=5;break}return e.next=5,m(0,5e3);case 5:return e.next=7,this.createSubscriber(t);case 7:(n=e.sent)&&(this.pendingOccupants.has(t)?(this.pendingOccupants.delete(t),this.occupantIds.push(t),this.occupants[t]=n,this.setMediaStream(t,n.mediaStream),this.onOccupantConnected(t)):n.conn.close());case 9:case"end":return e.stop()}}),e,this)}))),function(e){return x.apply(this,arguments)})},{key:"removeAllOccupants",value:function(){this.pendingOccupants.clear();for(var e=this.occupantIds.length-1;e>=0;e--)this.removeOccupant(this.occupantIds[e])}},{key:"removeOccupant",value:function(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)){var 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)}},{key:"associate",value:function(e,t){var n=this;e.addEventListener("icecandidate",(function(e){t.sendTrickle(e.candidate||null).catch((function(e){return h("Error trickling ICE: %o",e)}))})),e.addEventListener("iceconnectionstatechange",(function(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."),n.performDelayedReconnect())})),e.addEventListener("negotiationneeded",g((function(r){d("Sending new offer for handle: %o",t);var s=e.createOffer().then(n.configurePublisherSdp).then(n.fixSafariIceUFrag),i=s.then((function(t){return e.setLocalDescription(t)})),a=s;return a=a.then(n.fixSafariIceUFrag).then((function(e){return t.sendJsep(e)})).then((function(t){return e.setRemoteDescription(t.jsep)})),Promise.all([i,a]).catch((function(e){return h("Error negotiating offer: %o",e)}))}))),t.on("event",g((function(r){var s=r.jsep;if(s&&"offer"==s.type){d("Accepting new offer for handle: %o",t);var i=e.setRemoteDescription(n.configureSubscriberSdp(s)).then((function(t){return e.createAnswer()})).then(n.fixSafariIceUFrag),a=i.then((function(t){return e.setLocalDescription(t)})),o=i.then((function(e){return t.sendJsep(e)}));return Promise.all([a,o]).catch((function(e){return h("Error negotiating answer: %o",e)}))}return null})))}},{key:"createPublisher",value:(C=c(a().mark((function e(){var t,n,r,s,i,o,c,u,p=this;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return t=new l.JanusPluginHandle(this.session),n=new RTCPeerConnection(this.peerConnectionConfig||w),d("pub waiting for sfu"),e.next=5,t.attach("janus.plugin.sfu",this.loops&&this.clientId?parseInt(this.clientId)%this.loops:void 0);case 5:return this.associate(n,t),d("pub waiting for data channels & webrtcup"),r=new Promise((function(e){return t.on("webrtcup",e)})),s=n.createDataChannel("reliable",{ordered:!0}),i=n.createDataChannel("unreliable",{ordered:!1,maxRetransmits:0}),s.addEventListener("message",(function(e){return p.onDataChannelMessage(e,"janus-reliable")})),i.addEventListener("message",(function(e){return p.onDataChannelMessage(e,"janus-unreliable")})),e.next=14,r;case 14:return e.next=16,v(s);case 16:return e.next=18,v(i);case 18:return this.localMediaStream&&this.localMediaStream.getTracks().forEach((function(e){n.addTrack(e,p.localMediaStream)})),t.on("event",(function(e){var t=e.plugindata.data;if("join"==t.event&&t.room_id==p.room){if(p.delayedReconnectTimeout)return;p.addAvailableOccupant(t.user_id),p.syncOccupants()}else"leave"==t.event&&t.room_id==p.room?(p.removeAvailableOccupant(t.user_id),p.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&&p.onData(JSON.parse(t.body),"janus-event")})),d("pub waiting for join"),e.next=23,this.sendJoin(t,{notifications:!0,data:!0});case 23:if((o=e.sent).plugindata.data.success){e.next=29;break}throw c=o.plugindata.data.error,console.error(c),n.close(),c;case 29:return(u=o.plugindata.data.response.users[this.room]||[]).includes(this.clientId)&&(console.warn("Janus still has previous session for this client. Reconnecting in 10s."),this.performDelayedReconnect()),d("publisher ready"),e.abrupt("return",{handle:t,initialOccupants:u,reliableChannel:s,unreliableChannel:i,conn:n});case 33:case"end":return e.stop()}}),e,this)}))),function(){return C.apply(this,arguments)})},{key:"configurePublisherSdp",value:function(e){return e.sdp=e.sdp.replace(/a=fmtp:(109|111).*\r\n/g,(function(e,t){var n=Object.assign(p.parseFmtp(e),b);return p.writeFmtp({payloadType:t,parameters:n})})),e}},{key:"configureSubscriberSdp",value:function(e){return y||-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}},{key:"fixSafariIceUFrag",value:(k=c(a().mark((function e(t){return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return t.sdp=t.sdp.replace(/[^\r]\na=ice-ufrag/g,"\r\na=ice-ufrag"),e.abrupt("return",t);case 2:case"end":return e.stop()}}),e)}))),function(e){return k.apply(this,arguments)})},{key:"createSubscriber",value:(o=c(a().mark((function e(t){var n,r,s,i,o,c,u=this,p=arguments;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(n=p.length>1&&void 0!==p[1]?p[1]:5,-1!==this.availableOccupants.indexOf(t)){e.next=4;break}return console.warn(t+": cancelled occupant connection, occupant left before subscription negotation."),e.abrupt("return",null);case 4:return r=new l.JanusPluginHandle(this.session),s=new RTCPeerConnection(this.peerConnectionConfig||w),d(t+": sub waiting for sfu"),e.next=9,r.attach("janus.plugin.sfu",this.loops?parseInt(t)%this.loops:void 0);case 9:if(this.associate(s,r),d(t+": sub waiting for join"),-1!==this.availableOccupants.indexOf(t)){e.next=15;break}return s.close(),console.warn(t+": cancelled occupant connection, occupant left after attach"),e.abrupt("return",null);case 15:return i=!1,o=new Promise((function(e){var n=setInterval((function(){-1===u.availableOccupants.indexOf(t)&&(clearInterval(n),e())}),1e3),s=setTimeout((function(){clearInterval(n),i=!0,e()}),15e3);r.on("webrtcup",(function(){clearTimeout(s),clearInterval(n),e()}))})),e.next=19,this.sendJoin(r,{media:t});case 19:if(-1!==this.availableOccupants.indexOf(t)){e.next=23;break}return s.close(),console.warn(t+": cancelled occupant connection, occupant left after join"),e.abrupt("return",null);case 23:return d(t+": sub waiting for webrtcup"),e.next=26,o;case 26:if(-1!==this.availableOccupants.indexOf(t)){e.next=30;break}return s.close(),console.warn(t+": cancel occupant connection, occupant left during or after webrtcup"),e.abrupt("return",null);case 30:if(!i){e.next=39;break}if(s.close(),!(n>0)){e.next=37;break}return console.warn(t+": webrtc up timed out, retrying"),e.abrupt("return",this.createSubscriber(t,n-1));case 37:return console.warn(t+": webrtc up timed out"),e.abrupt("return",null);case 39:if(!f||this._iOSHackDelayedInitialPeer){e.next=43;break}return e.next=42,new Promise((function(e){return setTimeout(e,3e3)}));case 42:this._iOSHackDelayedInitialPeer=!0;case 43:return c=new MediaStream,s.getReceivers().forEach((function(e){e.track&&c.addTrack(e.track)})),0===c.getTracks().length&&(c=null),d(t+": subscriber ready"),e.abrupt("return",{handle:r,mediaStream:c,conn:s});case 49:case"end":return e.stop()}}),e,this)}))),function(e){return o.apply(this,arguments)})},{key:"sendJoin",value:function(e,t){return e.sendMessage({kind:"join",room_id:this.room,user_id:this.clientId,subscribe:t,token:this.joinToken})}},{key:"toggleFreeze",value:function(){this.frozen?this.unfreeze():this.freeze()}},{key:"freeze",value:function(){this.frozen=!0}},{key:"unfreeze",value:function(){this.frozen=!1,this.flushPendingUpdates()}},{key:"dataForUpdateMultiMessage",value:function(e,t){for(var n=0,r=t.data.d.length;n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,o=!0,c=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return o=e.done,e},e:function(e){c=!0,a=e},f:function(){try{o||null==n.return||n.return()}finally{if(c)throw a}}}}(this.frozenUpdates);try{for(r.s();!(e=r.n()).done;){var i=(t=e.value,n=2,function(e){if(Array.isArray(e))return e}(t)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,s,i,a,o=[],c=!0,u=!1;try{if(i=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;c=!1}else for(;!(c=(r=i.call(n)).done)&&(o.push(r.value),o.length!==t);c=!0);}catch(e){u=!0,s=e}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(u)throw s}}return o}}(t,n)||s(t,n)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),a=i[0],o=i[1],c=this.getPendingData(a,o);if(c){var u="um"===o.dataType?"u":o.dataType;this.onOccupantMessage(null,u,c,o.source)}}}catch(e){r.e(e)}finally{r.f()}this.frozenUpdates.clear()}},{key:"storeMessage",value:function(e){if("um"===e.dataType)for(var t=0,n=e.data.d.length;tn.owner)return;"r"===r?a&&a.isFirstSync?this.frozenUpdates.delete(s):this.frozenUpdates.set(s,e):a.components&&n.components&&Object.assign(a.components,n.components)}else this.frozenUpdates.set(s,e)}},{key:"onDataChannelMessage",value:function(e,t){this.onData(JSON.parse(e.data),t)}},{key:"onData",value:function(e,t){d.enabled&&d("DC in: ".concat(e)),e.dataType&&(e.source=t,this.frozen?this.storeMessage(e):this.onOccupantMessage(null,e.dataType,e.data,e.source))}},{key:"shouldStartConnectionTo",value:function(e){return!0}},{key:"startStreamConnection",value:function(e){}},{key:"closeStreamConnection",value:function(e){}},{key:"getConnectStatus",value:function(e){return this.occupants[e]?NAF.adapters.IS_CONNECTED:NAF.adapters.NOT_CONNECTED}},{key:"updateTimeOffset",value:(i=c(a().mark((function e(){var t,n,r,s,i,o=this;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(!this.isDisconnected()){e.next=2;break}return e.abrupt("return");case 2:return t=Date.now(),e.next=5,fetch(document.location.href,{method:"HEAD",cache:"no-cache"});case 5:n=e.sent,r=new Date(n.headers.get("Date")).getTime()+500,s=Date.now(),i=r+(s-t)/2-s,this.serverTimeRequests++,this.serverTimeRequests<=10?this.timeOffsets.push(i):this.timeOffsets[this.serverTimeRequests%10]=i,this.avgTimeOffset=this.timeOffsets.reduce((function(e,t){return e+t}),0)/this.timeOffsets.length,this.serverTimeRequests>10?(d("new server time offset: ".concat(this.avgTimeOffset,"ms")),setTimeout((function(){return o.updateTimeOffset()}),3e5)):this.updateTimeOffset();case 15:case"end":return e.stop()}}),e,this)}))),function(){return i.apply(this,arguments)})},{key:"getServerTime",value:function(){return Date.now()+this.avgTimeOffset}},{key:"getMediaStream",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"audio";if(this.mediaStreams[e])return d("Already had ".concat(n," for ").concat(e)),Promise.resolve(this.mediaStreams[e][n]);if(d("Waiting on ".concat(n," for ").concat(e)),!this.pendingMediaRequests.has(e)){this.pendingMediaRequests.set(e,{});var r=new Promise((function(n,r){t.pendingMediaRequests.get(e).audio={resolve:n,reject:r}})),s=new Promise((function(n,r){t.pendingMediaRequests.get(e).video={resolve:n,reject:r}}));this.pendingMediaRequests.get(e).audio.promise=r,this.pendingMediaRequests.get(e).video.promise=s,r.catch((function(t){return console.warn("".concat(e," getMediaStream Audio Error"),t)})),s.catch((function(t){return console.warn("".concat(e," getMediaStream Video Error"),t)}))}return this.pendingMediaRequests.get(e)[n].promise}},{key:"setMediaStream",value:function(e,t){var n=new MediaStream;try{t.getAudioTracks().forEach((function(e){return n.addTrack(e)}))}catch(t){console.warn("".concat(e," setMediaStream Audio Error"),t)}var r=new MediaStream;try{t.getVideoTracks().forEach((function(e){return r.addTrack(e)}))}catch(t){console.warn("".concat(e," setMediaStream Video Error"),t)}this.mediaStreams[e]={audio:n,video:r},this.pendingMediaRequests.has(e)&&(this.pendingMediaRequests.get(e).audio.resolve(n),this.pendingMediaRequests.get(e).video.resolve(r))}},{key:"setLocalMediaStream",value:(r=c(a().mark((function e(t){var n,r,s,i,o,c=this;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(!this.publisher||!this.publisher.conn){e.next=12;break}n=this.publisher.conn.getSenders(),r=[],s=t.getTracks(),i=a().mark((function e(){var i,u;return a().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(i=s[o],null==(u=n.find((function(e){return null!=e.track&&e.track.kind==i.kind})))){e.next=14;break}if(!u.replaceTrack){e.next=9;break}return e.next=6,u.replaceTrack(i);case 6:"video"===i.kind&&i.enabled&&navigator.userAgent.toLowerCase().indexOf("firefox")>-1&&(i.enabled=!1,setTimeout((function(){return i.enabled=!0}),1e3)),e.next=11;break;case 9:t.removeTrack(u.track),t.addTrack(i);case 11:r.push(u),e.next=15;break;case 14:r.push(c.publisher.conn.addTrack(i,t));case 15:case"end":return e.stop()}}),e)})),o=0;case 6:if(!(o{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 r=0,s=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(r++,"%c"===e&&(s=r))})),t.splice(s,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(447)(t);const{formatters:r}=e.exports;r.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},447:(e,t,n)=>{e.exports=function(e){function t(e){let n,s,i,a=null;function o(...e){if(!o.enabled)return;const r=o,s=Number(new Date),i=s-(n||s);r.diff=i,r.prev=n,r.curr=s,n=s,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,s)=>{if("%%"===n)return"%";a++;const i=t.formatters[s];if("function"==typeof i){const t=e[a];n=i.call(r,t),e.splice(a,1),a--}return n})),t.formatArgs.call(r,e),(r.log||t.log).apply(r,e)}return o.namespace=e,o.useColors=t.useColors(),o.color=t.selectColor(e),o.extend=r,o.destroy=t.destroy,Object.defineProperty(o,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==a?a:(s!==t.namespaces&&(s=t.namespaces,i=t.enabled(e)),i),set:e=>{a=e}}),"function"==typeof t.init&&t.init(o),o}function r(e,n){const r=t(this.namespace+(void 0===n?":":n)+e);return r.log=this.log,r}function s(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(s),...t.skips.map(s).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 r=("string"==typeof e?e:"").split(/[\s,]+/),s=r.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,r=60*n,s=24*r;function i(e,t,n,r){var s=t>=1.5*n;return Math.round(e/n)+" "+r+(s?"s":"")}e.exports=function(e,a){a=a||{};var o,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var i=/^(-?(?:\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(i){var a=parseFloat(i[1]);switch((i[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*s;case"hours":case"hour":case"hrs":case"hr":case"h":return a*r;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"===u&&isFinite(e))return a.long?(o=e,(c=Math.abs(o))>=s?i(o,c,s,"day"):c>=r?i(o,c,r,"hour"):c>=n?i(o,c,n,"minute"):c>=t?i(o,c,t,"second"):o+" ms"):function(e){var i=Math.abs(e);return i>=s?Math.round(e/s)+"d":i>=r?Math.round(e/r)+"h":i>=n?Math.round(e/n)+"m":i>=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))}},539: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 r=e.substring(e.indexOf(" ")+1).split(";");for(let e=0;e{void 0!==e.parameters[t]?r.push(t+"="+e.parameters[t]):r.push(t)})),t+="a=fmtp:"+n+" "+r.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)},r=e.indexOf(":",t);return r>-1?(n.attribute=e.substring(t+1,r),n.value=e.substring(r+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 r=t.matchPrefix(e+n,"a=ice-ufrag:")[0],s=t.matchPrefix(e+n,"a=ice-pwd:")[0];return r&&s?{usernameFragment:r.substring(12),password:s.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:[]},r=t.splitLines(e)[0].split(" ");n.profile=r[2];for(let s=3;s{n.headerExtensions.push(t.parseExtmap(e))}));const s=t.matchPrefix(e,"a=rtcp-fb:* ").map(t.parseRtcpFb);return n.codecs.forEach((e=>{s.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 r="";r+="m="+e+" ",r+=n.codecs.length>0?"9":"0",r+=" "+(n.profile||"UDP/TLS/RTP/SAVPF")+" ",r+=n.codecs.map((e=>void 0!==e.preferredPayloadType?e.preferredPayloadType:e.payloadType)).join(" ")+"\r\n",r+="c=IN IP4 0.0.0.0\r\n",r+="a=rtcp:9 IN IP4 0.0.0.0\r\n",n.codecs.forEach((e=>{r+=t.writeRtpMap(e),r+=t.writeFmtp(e),r+=t.writeRtcpFb(e)}));let s=0;return n.codecs.forEach((e=>{e.maxptime>s&&(s=e.maxptime)})),s>0&&(r+="a=maxptime:"+s+"\r\n"),n.headerExtensions&&n.headerExtensions.forEach((e=>{r+=t.writeExtmap(e)})),r},t.parseRtpEncodingParameters=function(e){const n=[],r=t.parseRtpParameters(e),s=-1!==r.fecMechanisms.indexOf("RED"),i=-1!==r.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 u=t.matchPrefix(e,"a=ssrc-group:FID").map((e=>e.substring(17).split(" ").map((e=>parseInt(e,10)))));u.length>0&&u[0].length>1&&u[0][0]===o&&(c=u[0][1]),r.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),s&&(t=JSON.parse(JSON.stringify(t)),t.fec={ssrc:o,mechanism:i?"red+ulpfec":"red"},n.push(t))}})),0===n.length&&o&&n.push({ssrc:o});let l=t.matchPrefix(e,"b=");return l.length&&(l=0===l[0].indexOf("b=TIAS:")?parseInt(l[0].substring(7),10):0===l[0].indexOf("b=AS:")?1e3*parseInt(l[0].substring(5),10)*.95-16e3:void 0,n.forEach((e=>{e.maxBitrate=l}))),n},t.parseRtcpParameters=function(e){const n={},r=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"cname"===e.attribute))[0];r&&(n.cname=r.value,n.ssrc=r.ssrc);const s=t.matchPrefix(e,"a=rtcp-rsize");n.reducedSize=s.length>0,n.compound=0===s.length;const i=t.matchPrefix(e,"a=rtcp-mux");return n.mux=i.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 r=t.matchPrefix(e,"a=msid:");if(1===r.length)return n=r[0].substring(7).split(" "),{stream:n[0],track:n[1]};const s=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"msid"===e.attribute));return s.length>0?(n=s[0].value.split(" "),{stream:n[0],track:n[1]}):void 0},t.parseSctpDescription=function(e){const n=t.parseMLine(e),r=t.matchPrefix(e,"a=max-message-size:");let s;r.length>0&&(s=parseInt(r[0].substring(19),10)),isNaN(s)&&(s=65536);const i=t.matchPrefix(e,"a=sctp-port:");if(i.length>0)return{port:parseInt(i[0].substring(12),10),protocol:n.fmt,maxMessageSize:s};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:s}}},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,r){let s;const i=void 0!==n?n:2;return s=e||t.generateSessionId(),"v=0\r\no="+(r||"thisisadapterortc")+" "+s+" "+i+" IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},t.getDirection=function(e,n){const r=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.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||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))}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),"video"===r.kind&&r.enabled&&navigator.userAgent.toLowerCase().indexOf("firefox")>-1&&(r.enabled=!1,setTimeout((()=>r.enabled=!0),1e3))):(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 {\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 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\n // Workaround https://bugzilla.mozilla.org/show_bug.cgi?id=1576771\n if (t.kind === \"video\" && t.enabled && navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {\n t.enabled = false;\n setTimeout(() => t.enabled = true, 1000);\n }\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 this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }), whom: clientId });\n break;\n case \"datachannel\":\n this.publisher.unreliableChannel.send(JSON.stringify({ clientId, dataType, data }));\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 this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }), whom: clientId });\n break;\n case \"datachannel\":\n this.publisher.reliableChannel.send(JSON.stringify({ clientId, dataType, data }));\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 this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }) });\n break;\n case \"datachannel\":\n this.publisher.unreliableChannel.send(JSON.stringify({ dataType, data }));\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 this.publisher.handle.sendMessage({ kind: \"data\", body: JSON.stringify({ dataType, data }) });\n break;\n case \"datachannel\":\n this.publisher.reliableChannel.send(JSON.stringify({ dataType, data }));\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__(579);\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","_regeneratorRuntime","Op","hasOwn","defineProperty","obj","key","desc","value","$Symbol","Symbol","iteratorSymbol","iterator","asyncIteratorSymbol","asyncIterator","toStringTagSymbol","toStringTag","define","enumerable","configurable","writable","err","wrap","innerFn","outerFn","self","tryLocsList","protoGenerator","Generator","generator","context","Context","makeInvokeMethod","tryCatch","fn","arg","call","ContinueSentinel","GeneratorFunction","GeneratorFunctionPrototype","IteratorPrototype","getProto","getPrototypeOf","NativeIteratorPrototype","values","Gp","defineIteratorMethods","forEach","method","_invoke","AsyncIterator","PromiseImpl","invoke","record","result","_typeof","__await","unwrapped","previousPromise","callInvokeWithMethodAndArg","state","done","delegate","delegateResult","maybeInvokeDelegate","sent","_sent","dispatchException","abrupt","methodName","TypeError","info","resultName","next","nextLoc","pushTryEntry","locs","entry","tryLoc","catchLoc","finallyLoc","afterLoc","tryEntries","resetTryEntry","completion","reset","iterable","iteratorMethod","isNaN","doneResult","displayName","isGeneratorFunction","genFun","ctor","constructor","name","mark","setPrototypeOf","__proto__","awrap","async","iter","keys","val","object","reverse","pop","skipTempReset","prev","charAt","slice","stop","rootRecord","rval","exception","handle","loc","caught","hasCatch","hasFinally","finallyEntry","complete","finish","thrown","delegateYield","asyncGeneratorStep","gen","_next","_throw","_asyncToGenerator","args","arguments","apply","_defineProperties","target","props","descriptor","input","hint","prim","toPrimitive","res","String","_toPrimitive","mj","require","sendOriginal","indexOf","NAF","connection","adapter","reconnect","sdpUtils","isSafari","test","navigator","userAgent","randomDelay","min","max","delay","Math","random","debounce","curr","_this","Array","_","untilDataChannelOpen","dataChannel","readyState","resolver","rejector","clear","removeEventListener","addEventListener","isH264VideoSupported","document","createElement","canPlayType","OPUS_PARAMETERS","usedtx","stereo","DEFAULT_PEER_CONNECTION_CONFIG","iceServers","urls","JanusAdapter","instance","Constructor","_classCallCheck","room","clientId","joinToken","serverUrl","webRtcOptions","peerConnectionConfig","ws","reliableTransport","unreliableTransport","initialReconnectionDelay","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","protoProps","_setLocalMediaStream","_updateTimeOffset","_createSubscriber","_fixSafariIceUFrag","_createPublisher","_addOccupant","_onWebsocketOpen","url","app","roomName","successListener","failureListener","connectSuccess","connectFailure","occupantListener","onOccupantsChanged","openListener","closedListener","messageListener","onOccupantConnected","onOccupantDisconnected","onOccupantMessage","reconnectingListener","reconnectedListener","reconnectionErrorListener","onReconnecting","onReconnected","onReconnectionError","loops","_this2","concat","websocketConnection","WebSocket","wsOnOpen","all","updateTimeOffset","removeAllOccupants","conn","close","delayedReconnectTimeout","_callee","occupantId","_context","createPublisher","initialOccupants","addAvailableOccupant","syncOccupants","event","_this3","code","_this4","disconnect","connect","_this5","parse","idx","splice","has","addOccupant","j","removeOccupant","_callee2","subscriber","_context2","add","createSubscriber","setMediaStream","mediaStream","_x","msg","get","audio","video","_this6","iceConnectionState","log","performDelayedReconnect","offer","createOffer","configurePublisherSdp","fixSafariIceUFrag","local","o","setLocalDescription","remote","r","setRemoteDescription","answer","configureSubscriberSdp","createAnswer","a","_callee3","webrtcup","reliableChannel","unreliableChannel","_this7","_context3","RTCPeerConnection","parseInt","associate","createDataChannel","ordered","maxRetransmits","getTracks","track","addTrack","plugindata","room_id","user_id","removeAvailableOccupant","dispatchEvent","CustomEvent","detail","by","sendJoin","notifications","success","response","users","includes","sdp","replace","line","pt","parameters","parseFmtp","writeFmtp","payloadType","_callee4","_context4","_x2","_callee5","maxRetries","webrtcFailed","_this8","_args5","_context5","leftInterval","setInterval","clearInterval","media","_iOSHackDelayedInitialPeer","MediaStream","getReceivers","receiver","_x3","subscribe","token","frozen","unfreeze","freeze","flushPendingUpdates","networkId","l","d","dataType","dataForUpdateMultiMessage","owner","getPendingData","_step","_iterator","_createForOfIteratorHelper","s","n","_step$value","source","f","storeSingleMessage","index","storedMessage","storedData","isOutdatedMessage","lastOwnerTime","isContemporaneousMessage","isFirstSync","set","components","enabled","storeMessage","client","adapters","IS_CONNECTED","NOT_CONNECTED","_callee6","clientSentTime","serverReceivedTime","clientReceivedTime","timeOffset","_this9","_context6","isDisconnected","Date","now","fetch","location","href","cache","headers","getTime","precision","reduce","acc","offset","_this10","audioPromise","videoPromise","promise","stream","audioStream","getAudioTracks","videoStream","getVideoTracks","_callee7","existingSenders","newSenders","tracks","_loop","_this11","_context8","getSenders","t","_context7","find","replaceTrack","toLowerCase","removeTrack","_x4","whom","permsToken","_this12","_this13","register","formatArgs","useColors","namespace","humanize","diff","c","color","lastC","match","save","namespaces","storage","setItem","removeItem","load","getItem","process","env","DEBUG","window","__nwjs","documentElement","style","WebkitAppearance","firebug","table","RegExp","$1","localStorage","localstorage","warned","colors","formatters","v","createDebug","prevTime","namespacesCache","enabledCache","enableOverride","Number","ms","coerce","unshift","format","formatter","selectColor","extend","init","delimiter","newDebug","toNamespace","regexp","substring","default","stack","disable","names","map","skips","join","enable","split","len","hash","charCodeAt","abs","m","h","plural","msAbs","isPlural","round","str","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","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","cname","rsize","reducedSize","compound","mux","writeRtcpParameters","parseMsid","spec","planB","msidParts","parseSctpDescription","parseMLine","maxSizeLine","maxMessageSize","sctpPort","fmt","sctpMapLines","writeSctpDescription","sctp","generateSessionId","substr","writeSessionBoilerplate","sessId","sessVer","sessUser","sessionId","version","getDirection","getKind","isRejected","parseOLine","username","sessionVersion","netType","addressType","isValidSDP","__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\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 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\n // Workaround https://bugzilla.mozilla.org/show_bug.cgi?id=1576771\n if (t.kind === \"video\" && t.enabled && navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {\n t.enabled = false;\n setTimeout(() => t.enabled = true, 1000);\n }\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","setLocalMediaStream","existingSenders","getSenders","newSenders","tracks","t","find","s","replaceTrack","toLowerCase","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","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