{"version":3,"file":"lib-jitsi-meet.min.js","mappings":"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","sources":["webpack://JitsiMeetJS/webpack/universalModuleDefinition","webpack://JitsiMeetJS/./index.js","webpack://JitsiMeetJS/./modules/statistics/SpeakerStats.js","webpack://JitsiMeetJS/./modules/util/AuthUtil.js","webpack://JitsiMeetJS/./modules/util/EventEmitterForwarder.js","webpack://JitsiMeetJS/./modules/util/GlobalOnErrorHandler.js","webpack://JitsiMeetJS/./modules/util/RandomUtil.js","webpack://JitsiMeetJS/./modules/util/ScriptUtil.js","webpack://JitsiMeetJS/./modules/util/UsernameGenerator.js","webpack://JitsiMeetJS/./node_modules/@jitsi/logger/lib/LogCollector.js","webpack://JitsiMeetJS/./node_modules/@jitsi/logger/lib/Logger.js","webpack://JitsiMeetJS/./node_modules/@jitsi/logger/lib/index.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-interop/node_modules/sdp-transform/lib/grammar.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-interop/node_modules/sdp-transform/lib/index.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-interop/node_modules/sdp-transform/lib/parser.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-interop/node_modules/sdp-transform/lib/writer.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-simulcast/lib/index.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-simulcast/lib/transform-utils.js","webpack://JitsiMeetJS/./node_modules/base64-js/index.js","webpack://JitsiMeetJS/./node_modules/bowser/es5.js","webpack://JitsiMeetJS/./node_modules/current-executing-script/dist/currentExecutingScript.js","webpack://JitsiMeetJS/./node_modules/events/events.js","webpack://JitsiMeetJS/./node_modules/jquery/dist/jquery.slim.min.js","webpack://JitsiMeetJS/./node_modules/js-md5/src/md5.js","webpack://JitsiMeetJS/./node_modules/lodash.clonedeep/index.js","webpack://JitsiMeetJS/./node_modules/lodash.debounce/index.js","webpack://JitsiMeetJS/./node_modules/lodash.isequal/index.js","webpack://JitsiMeetJS/./node_modules/sdp-transform/lib/grammar.js","webpack://JitsiMeetJS/./node_modules/sdp-transform/lib/index.js","webpack://JitsiMeetJS/./node_modules/sdp-transform/lib/parser.js","webpack://JitsiMeetJS/./node_modules/sdp-transform/lib/writer.js","webpack://JitsiMeetJS/./node_modules/sdp/sdp.js","webpack://JitsiMeetJS/./node_modules/strophe.js/dist/strophe.umd.js","webpack://JitsiMeetJS/../src/strophe.disco.js","webpack://JitsiMeetJS/../src/strophe.stream-management.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/bytesToUuid.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/index.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/md5-browser.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/rng-browser.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/sha1-browser.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/v1.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/v3.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/v35.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/v4.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/v5.js","webpack://JitsiMeetJS/./service/RTC/BridgeVideoType.js","webpack://JitsiMeetJS/./service/RTC/CameraFacingMode.js","webpack://JitsiMeetJS/./service/RTC/CodecMimeType.js","webpack://JitsiMeetJS/./service/RTC/RTCEvents.ts","webpack://JitsiMeetJS/./service/RTC/Resolutions.js","webpack://JitsiMeetJS/./service/RTC/VideoType.ts","webpack://JitsiMeetJS/./service/authentication/AuthenticationEvents.js","webpack://JitsiMeetJS/./service/statistics/constants.ts","webpack://JitsiMeetJS/./service/xmpp/XMPPEvents.ts","webpack://JitsiMeetJS/./JitsiConferenceErrors.ts","webpack://JitsiMeetJS/./JitsiConferenceEvents.ts","webpack://JitsiMeetJS/./JitsiTrackEvents.ts","webpack://JitsiMeetJS/./modules/statistics/constants.js","webpack://JitsiMeetJS/./JitsiTrackErrors.ts","webpack://JitsiMeetJS/./JitsiTrackError.js","webpack://JitsiMeetJS/./service/statistics/AnalyticsEvents.ts","webpack://JitsiMeetJS/./service/statistics/Events.ts","webpack://JitsiMeetJS/./node_modules/@jitsi/js-utils/browser-detection/browsers.js","webpack://JitsiMeetJS/./node_modules/@jitsi/js-utils/browser-detection/BrowserDetection.js","webpack://JitsiMeetJS/./node_modules/@jitsi/js-utils/jitsi-local-storage/index.js","webpack://JitsiMeetJS/./modules/browser/BrowserCapabilities.js","webpack://JitsiMeetJS/./modules/browser/index.js","webpack://JitsiMeetJS/./modules/statistics/AnalyticsAdapter.js","webpack://JitsiMeetJS/./modules/statistics/CallStats.js","webpack://JitsiMeetJS/./modules/statistics/LocalStatsCollector.js","webpack://JitsiMeetJS/./modules/util/MathUtil.js","webpack://JitsiMeetJS/./modules/statistics/PerformanceObserverStats.js","webpack://JitsiMeetJS/./service/RTC/MediaType.ts","webpack://JitsiMeetJS/./modules/flags/FeatureFlags.js","webpack://JitsiMeetJS/./modules/statistics/RTPStatsCollector.js","webpack://JitsiMeetJS/./modules/statistics/statistics.js","webpack://JitsiMeetJS/./JitsiConferenceEventManager.js","webpack://JitsiMeetJS/./JitsiParticipant.js","webpack://JitsiMeetJS/./JitsiConnectionEvents.ts","webpack://JitsiMeetJS/./JitsiConnectionErrors.ts","webpack://JitsiMeetJS/./modules/util/Deferred.js","webpack://JitsiMeetJS/./modules/util/Listenable.js","webpack://JitsiMeetJS/./modules/e2ee/E2EEContext.js","webpack://JitsiMeetJS/./modules/e2ee/KeyHandler.js","webpack://JitsiMeetJS/./modules/e2ee/ExternallyManagedKeyHandler.js","webpack://JitsiMeetJS/./node_modules/uuid/wrapper.mjs","webpack://JitsiMeetJS/./modules/e2ee/E2EEErrors.ts","webpack://JitsiMeetJS/./modules/e2ee/SAS.js","webpack://JitsiMeetJS/./modules/e2ee/OlmAdapter.js","webpack://JitsiMeetJS/./modules/e2ee/ManagedKeyHandler.js","webpack://JitsiMeetJS/./modules/e2ee/crypto-utils.js","webpack://JitsiMeetJS/./modules/e2ee/E2EEncryption.js","webpack://JitsiMeetJS/./modules/xmpp/sha1.js","webpack://JitsiMeetJS/./modules/xmpp/Caps.js","webpack://JitsiMeetJS/./modules/connectivity/NetworkInfo.js","webpack://JitsiMeetJS/./modules/xmpp/ResumeTask.js","webpack://JitsiMeetJS/./modules/util/Retry.js","webpack://JitsiMeetJS/./modules/xmpp/StropheLastSuccess.js","webpack://JitsiMeetJS/./modules/xmpp/ConnectionPlugin.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.ping.js","webpack://JitsiMeetJS/./modules/xmpp/XmppConnection.js","webpack://JitsiMeetJS/./JitsiTranscriptionStatus.ts","webpack://JitsiMeetJS/./modules/xmpp/AVModeration.js","webpack://JitsiMeetJS/./modules/xmpp/BreakoutRooms.js","webpack://JitsiMeetJS/./modules/xmpp/Lobby.js","webpack://JitsiMeetJS/./modules/xmpp/RoomMetadata.ts","webpack://JitsiMeetJS/./modules/settings/Settings.js","webpack://JitsiMeetJS/./modules/xmpp/moderator.js","webpack://JitsiMeetJS/./modules/xmpp/ChatRoom.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.emuc.js","webpack://JitsiMeetJS/./modules/xmpp/JingleHelperFunctions.js","webpack://JitsiMeetJS/./service/RTC/MediaDirection.ts","webpack://JitsiMeetJS/./modules/RTC/ScreenObtainer.js","webpack://JitsiMeetJS/./modules/sdp/SDPUtil.js","webpack://JitsiMeetJS/./modules/sdp/SDP.js","webpack://JitsiMeetJS/./modules/sdp/SDPDiffer.js","webpack://JitsiMeetJS/./node_modules/async/dist/async.mjs","webpack://JitsiMeetJS/./modules/util/AsyncQueue.js","webpack://JitsiMeetJS/./modules/xmpp/JingleSessionState.ts","webpack://JitsiMeetJS/./modules/xmpp/JingleSession.js","webpack://JitsiMeetJS/./modules/xmpp/MediaSessionEvents.ts","webpack://JitsiMeetJS/./modules/xmpp/JingleSessionPC.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.jingle.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.logger.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.rayo.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.util.js","webpack://JitsiMeetJS/./modules/xmpp/xmpp.js","webpack://JitsiMeetJS/./authenticateAndUpgradeRole.js","webpack://JitsiMeetJS/./modules/RTC/CodecSelection.js","webpack://JitsiMeetJS/./modules/RTC/BridgeChannel.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/utils.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/chrome/getusermedia.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/chrome/getdisplaymedia.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/chrome/chrome_shim.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/firefox/getusermedia.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/firefox/getdisplaymedia.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/firefox/firefox_shim.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/safari/safari_shim.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/common_shim.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/adapter_factory.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/adapter_core.js","webpack://JitsiMeetJS/./modules/RTC/RTCUtils.js","webpack://JitsiMeetJS/./modules/RTC/JitsiTrack.js","webpack://JitsiMeetJS/./modules/RTC/JitsiLocalTrack.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-interop/lib/transform.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-interop/lib/interop.js","webpack://JitsiMeetJS/./service/RTC/SignalingEvents.ts","webpack://JitsiMeetJS/./service/RTC/SignalingLayer.js","webpack://JitsiMeetJS/./modules/sdp/SdpTransformUtil.js","webpack://JitsiMeetJS/./modules/sdp/LocalSdpMunger.js","webpack://JitsiMeetJS/./modules/sdp/RtxModifier.js","webpack://JitsiMeetJS/./modules/sdp/SdpConsistency.js","webpack://JitsiMeetJS/./modules/sdp/SdpSimulcast.ts","webpack://JitsiMeetJS/./modules/connectivity/TrackStreamingStatus.ts","webpack://JitsiMeetJS/./modules/RTC/JitsiRemoteTrack.js","webpack://JitsiMeetJS/./modules/RTC/TPCUtils.js","webpack://JitsiMeetJS/./modules/RTC/TraceablePeerConnection.js","webpack://JitsiMeetJS/./modules/RTC/RTC.js","webpack://JitsiMeetJS/./service/connectivity/ConnectionQualityEvents.ts","webpack://JitsiMeetJS/./modules/connectivity/ConnectionQuality.js","webpack://JitsiMeetJS/./modules/connectivity/IceFailedHandling.js","webpack://JitsiMeetJS/./modules/detection/DetectionEvents.ts","webpack://JitsiMeetJS/./modules/detection/NoAudioSignalDetection.js","webpack://JitsiMeetJS/./modules/detection/P2PDominantSpeakerDetection.js","webpack://JitsiMeetJS/./modules/webaudio/WebAudioUtils.js","webpack://JitsiMeetJS/./modules/detection/TrackVADEmitter.js","webpack://JitsiMeetJS/./modules/detection/VADAudioAnalyser.js","webpack://JitsiMeetJS/./modules/detection/VADNoiseDetection.js","webpack://JitsiMeetJS/./modules/detection/VADTalkMutedDetection.js","webpack://JitsiMeetJS/./service/e2eping/E2ePingEvents.ts","webpack://JitsiMeetJS/./modules/e2eping/e2eping.js","webpack://JitsiMeetJS/./modules/event/Jvb121EventGenerator.js","webpack://JitsiMeetJS/./modules/litemode/LiteModeContext.js","webpack://JitsiMeetJS/./modules/qualitycontrol/ReceiveVideoController.js","webpack://JitsiMeetJS/./modules/qualitycontrol/SendVideoController.js","webpack://JitsiMeetJS/./modules/recording/recordingXMLUtils.js","webpack://JitsiMeetJS/./modules/recording/JibriSession.js","webpack://JitsiMeetJS/./modules/recording/RecordingManager.js","webpack://JitsiMeetJS/./modules/statistics/AudioOutputProblemDetector.js","webpack://JitsiMeetJS/./modules/statistics/AvgRTPStatsReporter.js","webpack://JitsiMeetJS/./modules/statistics/SpeakerStatsCollector.js","webpack://JitsiMeetJS/./modules/transcription/recordingResult.js","webpack://JitsiMeetJS/./modules/transcription/trackRecorder.js","webpack://JitsiMeetJS/./modules/transcription/audioRecorder.js","webpack://JitsiMeetJS/./modules/transcription/word.js","webpack://JitsiMeetJS/./modules/transcription/transcriptionServices/AbstractTranscriptionService.js","webpack://JitsiMeetJS/./modules/transcription/transcriptionServices/SphinxTranscriptionService.js","webpack://JitsiMeetJS/./modules/transcription/transcriber.js","webpack://JitsiMeetJS/./modules/version/ComponentsVersions.js","webpack://JitsiMeetJS/./modules/videosipgw/VideoSIPGWConstants.ts","webpack://JitsiMeetJS/./modules/videosipgw/JitsiVideoSIPGWSession.js","webpack://JitsiMeetJS/./modules/videosipgw/VideoSIPGW.js","webpack://JitsiMeetJS/./modules/xmpp/SignalingLayerImpl.js","webpack://JitsiMeetJS/./JitsiConference.js","webpack://JitsiMeetJS/./JitsiConnection.js","webpack://JitsiMeetJS/./JitsiMediaDevicesEvents.ts","webpack://JitsiMeetJS/./JitsiMediaDevices.js","webpack://JitsiMeetJS/./modules/detection/ActiveDeviceDetector.js","webpack://JitsiMeetJS/./modules/proxyconnection/CustomSignalingLayer.js","webpack://JitsiMeetJS/./modules/proxyconnection/constants.ts","webpack://JitsiMeetJS/./modules/proxyconnection/ProxyConnectionPC.js","webpack://JitsiMeetJS/./modules/proxyconnection/ProxyConnectionService.js","webpack://JitsiMeetJS/./modules/statistics/PrecallTest.js","webpack://JitsiMeetJS/./modules/webaudio/AudioMixer.js","webpack://JitsiMeetJS/./JitsiMeetJS.ts","webpack://JitsiMeetJS/./modules/recording/recordingConstants.js","webpack://JitsiMeetJS/webpack/bootstrap","webpack://JitsiMeetJS/webpack/runtime/amd options","webpack://JitsiMeetJS/webpack/runtime/compat get default export","webpack://JitsiMeetJS/webpack/runtime/define property getters","webpack://JitsiMeetJS/webpack/runtime/global","webpack://JitsiMeetJS/webpack/runtime/hasOwnProperty shorthand","webpack://JitsiMeetJS/webpack/runtime/make namespace object","webpack://JitsiMeetJS/webpack/runtime/node module decorator","webpack://JitsiMeetJS/webpack/startup"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"JitsiMeetJS\"] = factory();\n\telse\n\t\troot[\"JitsiMeetJS\"] = factory();\n})(self, () => {\nreturn ","const ljm = require('./JitsiMeetJS').default;\n\n/**\n * Tries to deal with the following problem: {@code JitsiMeetJS} is not only\n * this module, it's also a global (i.e. attached to {@code window}) namespace\n * for all globals of the projects in the Jitsi Meet family. If lib-jitsi-meet\n * is loaded through an HTML {@code script} tag, {@code JitsiMeetJS} will\n * automatically be attached to {@code window} by webpack. Unfortunately,\n * webpack's source code does not check whether the global variable has already\n * been assigned and overwrites it. Which is OK for the module\n * {@code JitsiMeetJS} but is not OK for the namespace {@code JitsiMeetJS}\n * because it may already contain the values of other projects in the Jitsi Meet\n * family. The solution offered here works around webpack by merging all\n * existing values of the namespace {@code JitsiMeetJS} into the module\n * {@code JitsiMeetJS}.\n *\n * @param {Object} module - The module {@code JitsiMeetJS} (which will be\n * exported and may be attached to {@code window} by webpack later on).\n * @private\n * @returns {Object} - A {@code JitsiMeetJS} module which contains all existing\n * value of the namespace {@code JitsiMeetJS} (if any).\n */\nfunction _mergeNamespaceAndModule(module) {\n    return (\n        typeof window.JitsiMeetJS === 'object'\n            ? Object.assign({}, window.JitsiMeetJS, module)\n            : module);\n}\n\nmodule.exports = _mergeNamespaceAndModule(ljm);\n","/**\n * A model for keeping track of each user's total\n * time as a dominant speaker. The model also\n * keeps track of the user's last known name\n * in case the user has left the meeting,\n * which is also tracked.\n */\nclass SpeakerStats {\n    /**\n     * Initializes a new SpeakerStats instance.\n     *\n     * @constructor\n     * @param {string} userId - The id of the user being tracked.\n     * @param {string} displayName - The name of the user being tracked.\n     * @param {boolean} isLocalStats - True if the stats model tracks\n     * the local user.\n     * @returns {void}\n     */\n    constructor(userId, displayName, isLocalStats) {\n        this._userId = userId;\n        this.setDisplayName(displayName);\n        this._isLocalStats = isLocalStats || false;\n        this.setDominantSpeaker(false);\n        this.totalDominantSpeakerTime = 0;\n        this._dominantSpeakerStart = 0;\n        this._isDominantSpeaker = false;\n        this._isSilent = false;\n        this._hasLeft = false;\n        this._faceLandmarks = [];\n    }\n\n    /**\n     * Get the user id being tracked.\n     *\n     * @returns {string} The user id.\n     */\n    getUserId() {\n        return this._userId;\n    }\n\n    /**\n     * Get the name of the user being tracked.\n     *\n     * @returns {string} The user name.\n     */\n    getDisplayName() {\n        return this.displayName;\n    }\n\n    /**\n     * Updates the last known name of the user being tracked.\n     *\n     * @param {string} - The user name.\n     * @returns {void}\n     */\n    setDisplayName(newName) {\n        this.displayName = newName;\n    }\n\n    /**\n     * Returns true if the stats are tracking the local user.\n     *\n     * @returns {boolean}\n     */\n    isLocalStats() {\n        return this._isLocalStats;\n    }\n\n    /**\n     * Returns true if the tracked user is currently a dominant speaker.\n     *\n     * @returns {boolean}\n     */\n    isDominantSpeaker() {\n        return this._isDominantSpeaker;\n    }\n\n    /**\n     * Returns true if the tracked user is currently a dominant speaker.\n     *\n     * @param {boolean} isNowDominantSpeaker - If true, the user will be accumulating time\n     * as dominant speaker. If false, the user will not accumulate time\n     * and will record any time accumulated since starting as dominant speaker.\n     * @param {boolean} silence - Indecates whether the dominant speaker is silent or not.\n     * @returns {void}\n     */\n    setDominantSpeaker(isNowDominantSpeaker, silence) {\n        if (!this.isDominantSpeaker() && isNowDominantSpeaker && !silence) {\n            this._dominantSpeakerStart = Date.now();\n        } else if (this.isDominantSpeaker()) {\n            if (!isNowDominantSpeaker) {\n                if (!this._isSilent) {\n                    const now = Date.now();\n                    const timeElapsed = now - this._dominantSpeakerStart;\n\n                    this.totalDominantSpeakerTime += timeElapsed;\n                    this._dominantSpeakerStart = 0;\n                }\n            } else if (this._isSilent && !silence) {\n                this._dominantSpeakerStart = Date.now();\n            } else if (!this._isSilent && silence) {\n                const now = Date.now();\n                const timeElapsed = now - this._dominantSpeakerStart;\n\n                this.totalDominantSpeakerTime += timeElapsed;\n                this._dominantSpeakerStart = 0;\n            }\n        }\n\n        this._isDominantSpeaker = isNowDominantSpeaker;\n        this._isSilent = silence;\n    }\n\n    /**\n     * Get how long the tracked user has been dominant speaker.\n     *\n     * @returns {number} - The speaker time in milliseconds.\n     */\n    getTotalDominantSpeakerTime() {\n        let total = this.totalDominantSpeakerTime;\n\n        if (this.isDominantSpeaker() && !this._isSilent) {\n            total += Date.now() - this._dominantSpeakerStart;\n        }\n\n        return total;\n    }\n\n    /**\n     * Get whether or not the user is still in the meeting.\n     *\n     * @returns {boolean} True if the user is no longer in the meeting.\n     */\n    hasLeft() {\n        return this._hasLeft;\n    }\n\n    /**\n     * Set the user as having left the meeting.\n     *\n     * @returns {void}\n     */\n    markAsHasLeft() {\n        this._hasLeft = true;\n        this.setDominantSpeaker(false);\n    }\n\n    /**\n     * Gets the face landmarks of the user.\n     *\n     * @returns {Object}\n     */\n    getFaceLandmarks() {\n        return this._faceLandmarks;\n    }\n\n    /**\n     * Sets the face landmarks of the user.\n     *\n     * @param {Object} faceLandmarks - object with face expressions.\n     * @returns {void}\n     */\n    setFaceLandmarks(faceLandmarks) {\n        this._faceLandmarks = faceLandmarks;\n    }\n\n    /**\n     * Adds new face landmarks to speaker stats.\n     *\n     * @param  {string} faceExpression\n     * @param {number} duration\n     */\n    addFaceLandmarks(faceLandmarks) {\n        this._faceLandmarks.push(faceLandmarks);\n    }\n}\n\nmodule.exports = SpeakerStats;\n","const AuthUtil = {\n    /**\n     * Creates the URL pointing to JWT token authentication service. It is\n     * formatted from the 'urlPattern' argument which can contain the following\n     * constants:\n     * '{room}' - name of the conference room passed as <tt>roomName</tt>\n     * argument to this method.\n     * '{roleUpgrade}' - will contain 'true' if the URL will be used for\n     * the role upgrade scenario, where user connects from anonymous domain and\n     * then gets upgraded to the moderator by logging-in from the popup window.\n     *\n     * @param urlPattern a URL pattern pointing to the login service\n     * @param roomName the name of the conference room for which the user will\n     * be authenticated\n     * @param {boolean} roleUpgrade <tt>true</tt> if the URL will be used for role\n     * upgrade scenario, where the user logs-in from the popup window in order\n     * to have the moderator rights granted\n     *\n     * @returns {string|null} the URL pointing to JWT login service or\n     * <tt>null</tt> if 'urlPattern' is not a string and the URL can not be\n     * constructed.\n     */\n    getTokenAuthUrl(urlPattern, roomName, roleUpgrade) {\n        const url = urlPattern;\n\n        if (typeof url !== 'string') {\n            return null;\n        }\n\n        return url.replace('{room}', roomName)\n            .replace('{roleUpgrade}', roleUpgrade === true);\n    }\n};\n\nmodule.exports = AuthUtil;\n","/**\n * Implements utility to forward events from one eventEmitter to another.\n * @param src {object} instance of EventEmitter or another class that implements\n * addListener method which will register listener to EventEmitter instance.\n * @param dest {object} instance of EventEmitter or another class that\n * implements emit method which will emit an event.\n */\nfunction EventEmitterForwarder(src, dest) {\n    if (!src || !dest || typeof src.addListener !== 'function'\n        || typeof dest.emit !== 'function') {\n        throw new Error('Invalid arguments passed to EventEmitterForwarder');\n    }\n    this.src = src;\n    this.dest = dest;\n}\n\n/**\n * Adds event to be forwarded from src to dest.\n * @param srcEvent {string} the event that EventEmitterForwarder is listening\n * for.\n * @param dstEvent {string} the event that will be fired from dest.\n * @param arguments all other passed arguments are going to be fired with\n * dstEvent.\n */\nEventEmitterForwarder.prototype.forward = function(...args) {\n    const srcEvent = args[0];\n\n    // This will be the \"this\" value for emit function.\n\n    args[0] = this.dest;\n\n    // Using bind.apply to pass the arguments as Array-like object (\"arguments\")\n    this.src.addListener(\n        srcEvent,\n        Function.prototype.bind.apply(this.dest.emit, args));\n};\n\nmodule.exports = EventEmitterForwarder;\n","/**\n * This utility class defines custom onerror and onunhandledrejection functions.\n * The custom error handlers respect the previously-defined error handlers.\n * GlobalOnErrorHandler class provides utilities to add many custom error\n * handlers and to execute the error handlers directly.\n */\n\n\n/**\n * List with global error handlers that will be executed.\n */\nconst handlers = [];\n\n// If an old handler exists, also fire its events.\nconst oldOnErrorHandler = window.onerror;\n\n/**\n * Custom error handler that calls the old global error handler and executes\n * all handlers that were previously added.\n */\nfunction JitsiGlobalErrorHandler(...args) {\n    handlers.forEach(handler => handler(...args));\n    oldOnErrorHandler && oldOnErrorHandler(...args);\n}\n\n// If an old handler exists, also fire its events.\nconst oldOnUnhandledRejection = window.onunhandledrejection;\n\n/**\n * Custom handler that calls the old global handler and executes all handlers\n * that were previously added. This handler handles rejected Promises.\n */\nfunction JitsiGlobalUnhandledRejection(event) {\n    handlers.forEach(handler => handler(null, null, null, null, event.reason));\n    oldOnUnhandledRejection && oldOnUnhandledRejection(event);\n}\n\n// Setting the custom error handlers.\nwindow.onerror = JitsiGlobalErrorHandler;\nwindow.onunhandledrejection = JitsiGlobalUnhandledRejection;\n\nconst GlobalOnErrorHandler = {\n    /**\n     * Adds new error handlers.\n     * @param handler the new handler.\n     */\n    addHandler(handler) {\n        handlers.push(handler);\n    },\n\n    /**\n     * Calls the global error handler if there is one.\n     * @param error the error to pass to the error handler\n     */\n    callErrorHandler(error) {\n        const errHandler = window.onerror;\n\n        if (!errHandler) {\n            return;\n        }\n        errHandler(null, null, null, null, error);\n    },\n\n    /**\n     * Calls the global rejection handler if there is one.\n     * @param error the error to pass to the rejection handler.\n     */\n    callUnhandledRejectionHandler(error) {\n        const errHandler = window.onunhandledrejection;\n\n        if (!errHandler) {\n            return;\n        }\n        errHandler(error);\n    }\n};\n\n\nmodule.exports = GlobalOnErrorHandler;\n","/**\n * @const\n */\nconst ALPHANUM\n    = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\n\n/**\n * Hexadecimal digits.\n * @const\n */\nconst HEX_DIGITS = '0123456789abcdef';\n\n/**\n * Generates random int within the range [min, max]\n * @param min the minimum value for the generated number\n * @param max the maximum value for the generated number\n * @returns random int number\n */\nfunction randomInt(min, max) {\n    return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\n/**\n * Get random element from array or string.\n * @param {Array|string} arr source\n * @returns array element or string character\n */\nfunction randomElement(arr) {\n    return arr[randomInt(0, arr.length - 1)];\n}\n\n/**\n * Generate random alphanumeric string.\n * @param {number} length expected string length\n * @returns {string} random string of specified length\n */\nfunction randomAlphanumStr(length) {\n    let result = '';\n\n    for (let i = 0; i < length; i += 1) {\n        result += randomElement(ALPHANUM);\n    }\n\n    return result;\n}\n\n/**\n * Exported interface.\n */\nconst RandomUtil = {\n    /**\n     * Returns a random hex digit.\n     * @returns {*}\n     */\n    randomHexDigit() {\n        return randomElement(HEX_DIGITS);\n    },\n\n    /**\n     * Returns a random string of hex digits with length 'len'.\n     * @param len the length.\n     */\n    randomHexString(len) {\n        let ret = '';\n\n        while (len--) { // eslint-disable-line no-param-reassign\n            ret += this.randomHexDigit();\n        }\n\n        return ret;\n    },\n    randomElement,\n    randomAlphanumStr,\n    randomInt\n};\n\nmodule.exports = RandomUtil;\n","const currentExecutingScript = require('current-executing-script');\n\n/* eslint-disable max-params */\n\n/**\n * Implements utility functions which facilitate the dealing with scripts such\n * as the download and execution of a JavaScript file.\n */\nconst ScriptUtil = {\n    /**\n     * Loads a script from a specific source.\n     *\n     * @param src the source from the which the script is to be (down)loaded\n     * @param async true to asynchronously load the script or false to\n     * synchronously load the script\n     * @param prepend true to schedule the loading of the script as soon as\n     * possible or false to schedule the loading of the script at the end of the\n     * scripts known at the time\n     * @param relativeURL whether we need load the library from url relative\n     * to the url that lib-jitsi-meet was loaded. Useful when sourcing the\n     * library from different location than the app that is using it\n     * @param loadCallback on load callback function\n     * @param errorCallback callback to be called on error loading the script\n     */\n    loadScript(\n            src,\n            async,\n            prepend,\n            relativeURL,\n            loadCallback,\n            errorCallback) {\n        const d = document;\n        const tagName = 'script';\n        const script = d.createElement(tagName);\n        const referenceNode = d.getElementsByTagName(tagName)[0];\n\n        script.async = async;\n\n        if (relativeURL) {\n            // finds the src url of the current loaded script\n            // and use it as base of the src supplied argument\n            const scriptEl = currentExecutingScript();\n\n            if (scriptEl) {\n                const scriptSrc = scriptEl.src;\n                const baseScriptSrc\n                    = scriptSrc.substring(0, scriptSrc.lastIndexOf('/') + 1);\n\n                if (scriptSrc && baseScriptSrc) {\n                    // eslint-disable-next-line no-param-reassign\n                    src = baseScriptSrc + src;\n                }\n            }\n        }\n\n        if (loadCallback) {\n            script.onload = loadCallback;\n        }\n        if (errorCallback) {\n            script.onerror = errorCallback;\n        }\n\n        script.src = src;\n        if (prepend) {\n            referenceNode.parentNode.insertBefore(script, referenceNode);\n        } else {\n            referenceNode.parentNode.appendChild(script);\n        }\n    }\n};\n\n/* eslint-enable max-params */\n\nmodule.exports = ScriptUtil;\n","const RandomUtil = require('./RandomUtil');\n\n/**\n * from faker.js - Copyright (c) 2014-2015 Matthew Bergman & Marak Squires\n * MIT License\n * http://github.com/marak/faker.js/\n *\n * @const\n */\nconst names = [\n    'Aaliyah', 'Aaron', 'Abagail', 'Abbey', 'Abbie', 'Abbigail', 'Abby',\n    'Abdiel', 'Abdul', 'Abdullah', 'Abe', 'Abel', 'Abelardo', 'Abigail',\n    'Abigale', 'Abigayle', 'Abner', 'Abraham', 'Ada', 'Adah', 'Adalberto',\n    'Adaline', 'Adam', 'Adan', 'Addie', 'Addison', 'Adela', 'Adelbert', 'Adele',\n    'Adelia', 'Adeline', 'Adell', 'Adella', 'Adelle', 'Aditya', 'Adolf',\n    'Adolfo', 'Adolph', 'Adolphus', 'Adonis', 'Adrain', 'Adrian', 'Adriana',\n    'Adrianna', 'Adriel', 'Adrien', 'Adrienne', 'Afton', 'Aglae', 'Agnes',\n    'Agustin', 'Agustina', 'Ahmad', 'Ahmed', 'Aida', 'Aidan', 'Aiden', 'Aileen',\n    'Aisha', 'Aiyana', 'Akeem', 'Al', 'Alaina', 'Alan', 'Alana', 'Alanis',\n    'Alanna', 'Alayna', 'Alba', 'Albert', 'Alberta', 'Albertha', 'Alberto',\n    'Albin', 'Albina', 'Alda', 'Alden', 'Alec', 'Aleen', 'Alejandra',\n    'Alejandrin', 'Alek', 'Alena', 'Alene', 'Alessandra', 'Alessandro',\n    'Alessia', 'Aletha', 'Alex', 'Alexa', 'Alexander', 'Alexandra', 'Alexandre',\n    'Alexandrea', 'Alexandria', 'Alexandrine', 'Alexandro', 'Alexane',\n    'Alexanne', 'Alexie', 'Alexis', 'Alexys', 'Alexzander', 'Alf', 'Alfonso',\n    'Alfonzo', 'Alford', 'Alfred', 'Alfreda', 'Alfredo', 'Ali', 'Alia', 'Alice',\n    'Alicia', 'Alisa', 'Alisha', 'Alison', 'Alivia', 'Aliya', 'Aliyah', 'Aliza',\n    'Alize', 'Allan', 'Allen', 'Allene', 'Allie', 'Allison', 'Ally', 'Alphonso',\n    'Alta', 'Althea', 'Alva', 'Alvah', 'Alvena', 'Alvera', 'Alverta', 'Alvina',\n    'Alvis', 'Alyce', 'Alycia', 'Alysa', 'Alysha', 'Alyson', 'Alysson',\n    'Amalia', 'Amanda', 'Amani', 'Amara', 'Amari', 'Amaya', 'Amber', 'Ambrose',\n    'Amelia', 'Amelie', 'Amely', 'America', 'Americo', 'Amie', 'Amina', 'Amir',\n    'Amira', 'Amiya', 'Amos', 'Amparo', 'Amy', 'Amya', 'Ana', 'Anabel',\n    'Anabelle', 'Anahi', 'Anais', 'Anastacio', 'Anastasia', 'Anderson', 'Andre',\n    'Andreane', 'Andreanne', 'Andres', 'Andrew', 'Andy', 'Angel', 'Angela',\n    'Angelica', 'Angelina', 'Angeline', 'Angelita', 'Angelo', 'Angie', 'Angus',\n    'Anibal', 'Anika', 'Anissa', 'Anita', 'Aniya', 'Aniyah', 'Anjali', 'Anna',\n    'Annabel', 'Annabell', 'Annabelle', 'Annalise', 'Annamae', 'Annamarie',\n    'Anne', 'Annetta', 'Annette', 'Annie', 'Ansel', 'Ansley', 'Anthony',\n    'Antoinette', 'Antone', 'Antonetta', 'Antonette', 'Antonia', 'Antonietta',\n    'Antonina', 'Antonio', 'Antwan', 'Antwon', 'Anya', 'April', 'Ara',\n    'Araceli', 'Aracely', 'Arch', 'Archibald', 'Ardella', 'Arden', 'Ardith',\n    'Arely', 'Ari', 'Ariane', 'Arianna', 'Aric', 'Ariel', 'Arielle', 'Arjun',\n    'Arlene', 'Arlie', 'Arlo', 'Armand', 'Armando', 'Armani', 'Arnaldo', 'Arne',\n    'Arno', 'Arnold', 'Arnoldo', 'Arnulfo', 'Aron', 'Art', 'Arthur', 'Arturo',\n    'Arvel', 'Arvid', 'Arvilla', 'Aryanna', 'Asa', 'Asha', 'Ashlee', 'Ashleigh',\n    'Ashley', 'Ashly', 'Ashlynn', 'Ashton', 'Ashtyn', 'Asia', 'Assunta',\n    'Astrid', 'Athena', 'Aubree', 'Aubrey', 'Audie', 'Audra', 'Audreanne',\n    'Audrey', 'August', 'Augusta', 'Augustine', 'Augustus', 'Aurelia',\n    'Aurelie', 'Aurelio', 'Aurore', 'Austen', 'Austin', 'Austyn', 'Autumn',\n    'Ava', 'Avery', 'Avis', 'Axel', 'Ayana', 'Ayden', 'Ayla', 'Aylin', 'Baby',\n    'Bailee', 'Bailey', 'Barbara', 'Barney', 'Baron', 'Barrett', 'Barry',\n    'Bart', 'Bartholome', 'Barton', 'Baylee', 'Beatrice', 'Beau', 'Beaulah',\n    'Bell', 'Bella', 'Belle', 'Ben', 'Benedict', 'Benjamin', 'Bennett',\n    'Bennie', 'Benny', 'Benton', 'Berenice', 'Bernadette', 'Bernadine',\n    'Bernard', 'Bernardo', 'Berneice', 'Bernhard', 'Bernice', 'Bernie',\n    'Berniece', 'Bernita', 'Berry', 'Bert', 'Berta', 'Bertha', 'Bertram',\n    'Bertrand', 'Beryl', 'Bessie', 'Beth', 'Bethany', 'Bethel', 'Betsy',\n    'Bette', 'Bettie', 'Betty', 'Bettye', 'Beulah', 'Beverly', 'Bianka', 'Bill',\n    'Billie', 'Billy', 'Birdie', 'Blair', 'Blaise', 'Blake', 'Blanca',\n    'Blanche', 'Blaze', 'Bo', 'Bobbie', 'Bobby', 'Bonita', 'Bonnie', 'Boris',\n    'Boyd', 'Brad', 'Braden', 'Bradford', 'Bradley', 'Bradly', 'Brady',\n    'Braeden', 'Brain', 'Brandi', 'Brando', 'Brandon', 'Brandt', 'Brandy',\n    'Brandyn', 'Brannon', 'Branson', 'Brant', 'Braulio', 'Braxton', 'Brayan',\n    'Breana', 'Breanna', 'Breanne', 'Brenda', 'Brendan', 'Brenden', 'Brendon',\n    'Brenna', 'Brennan', 'Brennon', 'Brent', 'Bret', 'Brett', 'Bria', 'Brian',\n    'Briana', 'Brianne', 'Brice', 'Bridget', 'Bridgette', 'Bridie', 'Brielle',\n    'Brigitte', 'Brionna', 'Brisa', 'Britney', 'Brittany', 'Brock', 'Broderick',\n    'Brody', 'Brook', 'Brooke', 'Brooklyn', 'Brooks', 'Brown', 'Bruce',\n    'Bryana', 'Bryce', 'Brycen', 'Bryon', 'Buck', 'Bud', 'Buddy', 'Buford',\n    'Bulah', 'Burdette', 'Burley', 'Burnice', 'Buster', 'Cade', 'Caden',\n    'Caesar', 'Caitlyn', 'Cale', 'Caleb', 'Caleigh', 'Cali', 'Calista',\n    'Callie', 'Camden', 'Cameron', 'Camila', 'Camilla', 'Camille', 'Camren',\n    'Camron', 'Camryn', 'Camylle', 'Candace', 'Candelario', 'Candice',\n    'Candida', 'Candido', 'Cara', 'Carey', 'Carissa', 'Carlee', 'Carleton',\n    'Carley', 'Carli', 'Carlie', 'Carlo', 'Carlos', 'Carlotta', 'Carmel',\n    'Carmela', 'Carmella', 'Carmelo', 'Carmen', 'Carmine', 'Carol', 'Carolanne',\n    'Carole', 'Carolina', 'Caroline', 'Carolyn', 'Carolyne', 'Carrie',\n    'Carroll', 'Carson', 'Carter', 'Cary', 'Casandra', 'Casey', 'Casimer',\n    'Casimir', 'Casper', 'Cassandra', 'Cassandre', 'Cassidy', 'Cassie',\n    'Catalina', 'Caterina', 'Catharine', 'Catherine', 'Cathrine', 'Cathryn',\n    'Cathy', 'Cayla', 'Ceasar', 'Cecelia', 'Cecil', 'Cecile', 'Cecilia',\n    'Cedrick', 'Celestine', 'Celestino', 'Celia', 'Celine', 'Cesar', 'Chad',\n    'Chadd', 'Chadrick', 'Chaim', 'Chance', 'Chandler', 'Chanel', 'Chanelle',\n    'Charity', 'Charlene', 'Charles', 'Charley', 'Charlie', 'Charlotte',\n    'Chase', 'Chasity', 'Chauncey', 'Chaya', 'Chaz', 'Chelsea', 'Chelsey',\n    'Chelsie', 'Chesley', 'Chester', 'Chet', 'Cheyanne', 'Cheyenne', 'Chloe',\n    'Chris', 'Christ', 'Christa', 'Christelle', 'Christian', 'Christiana',\n    'Christina', 'Christine', 'Christop', 'Christophe', 'Christopher',\n    'Christy', 'Chyna', 'Ciara', 'Cicero', 'Cielo', 'Cierra', 'Cindy',\n    'Citlalli', 'Clair', 'Claire', 'Clara', 'Clarabelle', 'Clare', 'Clarissa',\n    'Clark', 'Claud', 'Claude', 'Claudia', 'Claudie', 'Claudine', 'Clay',\n    'Clemens', 'Clement', 'Clementina', 'Clementine', 'Clemmie', 'Cleo',\n    'Cleora', 'Cleta', 'Cletus', 'Cleve', 'Cleveland', 'Clifford', 'Clifton',\n    'Clint', 'Clinton', 'Clotilde', 'Clovis', 'Cloyd', 'Clyde', 'Coby', 'Cody',\n    'Colby', 'Cole', 'Coleman', 'Colin', 'Colleen', 'Collin', 'Colt', 'Colten',\n    'Colton', 'Columbus', 'Concepcion', 'Conner', 'Connie', 'Connor', 'Conor',\n    'Conrad', 'Constance', 'Constantin', 'Consuelo', 'Cooper', 'Cora',\n    'Coralie', 'Corbin', 'Cordelia', 'Cordell', 'Cordia', 'Cordie', 'Corene',\n    'Corine', 'Cornelius', 'Cornell', 'Corrine', 'Cortez', 'Cortney', 'Cory',\n    'Coty', 'Courtney', 'Coy', 'Craig', 'Crawford', 'Creola', 'Cristal',\n    'Cristian', 'Cristina', 'Cristobal', 'Cristopher', 'Cruz', 'Crystal',\n    'Crystel', 'Cullen', 'Curt', 'Curtis', 'Cydney', 'Cynthia', 'Cyril',\n    'Cyrus', 'Dagmar', 'Dahlia', 'Daija', 'Daisha', 'Daisy', 'Dakota', 'Dale',\n    'Dallas', 'Dallin', 'Dalton', 'Damaris', 'Dameon', 'Damian', 'Damien',\n    'Damion', 'Damon', 'Dan', 'Dana', 'Dandre', 'Dane', 'D\\'angelo', 'Dangelo',\n    'Danial', 'Daniela', 'Daniella', 'Danielle', 'Danika', 'Dannie', 'Danny',\n    'Dante', 'Danyka', 'Daphne', 'Daphnee', 'Daphney', 'Darby', 'Daren',\n    'Darian', 'Dariana', 'Darien', 'Dario', 'Darion', 'Darius', 'Darlene',\n    'Daron', 'Darrel', 'Darrell', 'Darren', 'Darrick', 'Darrin', 'Darrion',\n    'Darron', 'Darryl', 'Darwin', 'Daryl', 'Dashawn', 'Dasia', 'Dave', 'David',\n    'Davin', 'Davion', 'Davon', 'Davonte', 'Dawn', 'Dawson', 'Dax', 'Dayana',\n    'Dayna', 'Dayne', 'Dayton', 'Dean', 'Deangelo', 'Deanna', 'Deborah',\n    'Declan', 'Dedric', 'Dedrick', 'Dee', 'Deion', 'Deja', 'Dejah', 'Dejon',\n    'Dejuan', 'Delaney', 'Delbert', 'Delfina', 'Delia', 'Delilah', 'Dell',\n    'Della', 'Delmer', 'Delores', 'Delpha', 'Delphia', 'Delphine', 'Delta',\n    'Demarco', 'Demarcus', 'Demario', 'Demetris', 'Demetrius', 'Demond', 'Dena',\n    'Denis', 'Dennis', 'Deon', 'Deondre', 'Deontae', 'Deonte', 'Dereck',\n    'Derek', 'Derick', 'Deron', 'Derrick', 'Deshaun', 'Deshawn', 'Desiree',\n    'Desmond', 'Dessie', 'Destany', 'Destin', 'Destinee', 'Destiney', 'Destini',\n    'Destiny', 'Devan', 'Devante', 'Deven', 'Devin', 'Devon', 'Devonte',\n    'Devyn', 'Dewayne', 'Dewitt', 'Dexter', 'Diamond', 'Diana', 'Dianna',\n    'Diego', 'Dillan', 'Dillon', 'Dimitri', 'Dina', 'Dino', 'Dion', 'Dixie',\n    'Dock', 'Dolly', 'Dolores', 'Domenic', 'Domenica', 'Domenick', 'Domenico',\n    'Domingo', 'Dominic', 'Dominique', 'Don', 'Donald', 'Donato', 'Donavon',\n    'Donna', 'Donnell', 'Donnie', 'Donny', 'Dora', 'Dorcas', 'Dorian', 'Doris',\n    'Dorothea', 'Dorothy', 'Dorris', 'Dortha', 'Dorthy', 'Doug', 'Douglas',\n    'Dovie', 'Doyle', 'Drake', 'Drew', 'Duane', 'Dudley', 'Dulce', 'Duncan',\n    'Durward', 'Dustin', 'Dusty', 'Dwight', 'Dylan', 'Earl', 'Earlene',\n    'Earline', 'Earnest', 'Earnestine', 'Easter', 'Easton', 'Ebba', 'Ebony',\n    'Ed', 'Eda', 'Edd', 'Eddie', 'Eden', 'Edgar', 'Edgardo', 'Edison', 'Edmond',\n    'Edmund', 'Edna', 'Eduardo', 'Edward', 'Edwardo', 'Edwin', 'Edwina',\n    'Edyth', 'Edythe', 'Effie', 'Efrain', 'Efren', 'Eileen', 'Einar', 'Eino',\n    'Eladio', 'Elaina', 'Elbert', 'Elda', 'Eldon', 'Eldora', 'Eldred',\n    'Eldridge', 'Eleanora', 'Eleanore', 'Eleazar', 'Electa', 'Elena', 'Elenor',\n    'Elenora', 'Eleonore', 'Elfrieda', 'Eli', 'Elian', 'Eliane', 'Elias',\n    'Eliezer', 'Elijah', 'Elinor', 'Elinore', 'Elisa', 'Elisabeth', 'Elise',\n    'Eliseo', 'Elisha', 'Elissa', 'Eliza', 'Elizabeth', 'Ella', 'Ellen',\n    'Ellie', 'Elliot', 'Elliott', 'Ellis', 'Ellsworth', 'Elmer', 'Elmira',\n    'Elmo', 'Elmore', 'Elna', 'Elnora', 'Elody', 'Eloisa', 'Eloise', 'Elouise',\n    'Eloy', 'Elroy', 'Elsa', 'Else', 'Elsie', 'Elta', 'Elton', 'Elva', 'Elvera',\n    'Elvie', 'Elvis', 'Elwin', 'Elwyn', 'Elyse', 'Elyssa', 'Elza', 'Emanuel',\n    'Emelia', 'Emelie', 'Emely', 'Emerald', 'Emerson', 'Emery', 'Emie', 'Emil',\n    'Emile', 'Emilia', 'Emiliano', 'Emilie', 'Emilio', 'Emily', 'Emma',\n    'Emmalee', 'Emmanuel', 'Emmanuelle', 'Emmet', 'Emmett', 'Emmie', 'Emmitt',\n    'Emmy', 'Emory', 'Ena', 'Enid', 'Enoch', 'Enola', 'Enos', 'Enrico',\n    'Enrique', 'Ephraim', 'Era', 'Eriberto', 'Eric', 'Erica', 'Erich', 'Erick',\n    'Ericka', 'Erik', 'Erika', 'Erin', 'Erling', 'Erna', 'Ernest', 'Ernestina',\n    'Ernestine', 'Ernesto', 'Ernie', 'Ervin', 'Erwin', 'Eryn', 'Esmeralda',\n    'Esperanza', 'Esta', 'Esteban', 'Estefania', 'Estel', 'Estell', 'Estella',\n    'Estelle', 'Estevan', 'Esther', 'Estrella', 'Etha', 'Ethan', 'Ethel',\n    'Ethelyn', 'Ethyl', 'Ettie', 'Eudora', 'Eugene', 'Eugenia', 'Eula', 'Eulah',\n    'Eulalia', 'Euna', 'Eunice', 'Eusebio', 'Eva', 'Evalyn', 'Evan',\n    'Evangeline', 'Evans', 'Eve', 'Eveline', 'Evelyn', 'Everardo', 'Everett',\n    'Everette', 'Evert', 'Evie', 'Ewald', 'Ewell', 'Ezekiel', 'Ezequiel',\n    'Ezra', 'Fabian', 'Fabiola', 'Fae', 'Fannie', 'Fanny', 'Fatima', 'Faustino',\n    'Fausto', 'Favian', 'Fay', 'Faye', 'Federico', 'Felicia', 'Felicita',\n    'Felicity', 'Felipa', 'Felipe', 'Felix', 'Felton', 'Fermin', 'Fern',\n    'Fernando', 'Ferne', 'Fidel', 'Filiberto', 'Filomena', 'Finn', 'Fiona',\n    'Flavie', 'Flavio', 'Fleta', 'Fletcher', 'Flo', 'Florence', 'Florencio',\n    'Florian', 'Florida', 'Florine', 'Flossie', 'Floy', 'Floyd', 'Ford',\n    'Forest', 'Forrest', 'Foster', 'Frances', 'Francesca', 'Francesco',\n    'Francis', 'Francisca', 'Francisco', 'Franco', 'Frank', 'Frankie', 'Franz',\n    'Fred', 'Freda', 'Freddie', 'Freddy', 'Frederic', 'Frederick', 'Frederik',\n    'Frederique', 'Fredrick', 'Fredy', 'Freeda', 'Freeman', 'Freida', 'Frida',\n    'Frieda', 'Friedrich', 'Fritz', 'Furman', 'Gabe', 'Gabriel', 'Gabriella',\n    'Gabrielle', 'Gaetano', 'Gage', 'Gail', 'Gardner', 'Garett', 'Garfield',\n    'Garland', 'Garnet', 'Garnett', 'Garret', 'Garrett', 'Garrick', 'Garrison',\n    'Garry', 'Garth', 'Gaston', 'Gavin', 'Gay', 'Gayle', 'Gaylord', 'Gene',\n    'General', 'Genesis', 'Genevieve', 'Gennaro', 'Genoveva', 'Geo', 'Geoffrey',\n    'George', 'Georgette', 'Georgiana', 'Georgianna', 'Geovanni', 'Geovanny',\n    'Geovany', 'Gerald', 'Geraldine', 'Gerard', 'Gerardo', 'Gerda', 'Gerhard',\n    'Germaine', 'German', 'Gerry', 'Gerson', 'Gertrude', 'Gia', 'Gianni',\n    'Gideon', 'Gilbert', 'Gilberto', 'Gilda', 'Giles', 'Gillian', 'Gina',\n    'Gino', 'Giovani', 'Giovanna', 'Giovanni', 'Giovanny', 'Gisselle',\n    'Giuseppe', 'Gladyce', 'Gladys', 'Glen', 'Glenda', 'Glenna', 'Glennie',\n    'Gloria', 'Godfrey', 'Golda', 'Golden', 'Gonzalo', 'Gordon', 'Grace',\n    'Gracie', 'Graciela', 'Grady', 'Graham', 'Grant', 'Granville', 'Grayce',\n    'Grayson', 'Green', 'Greg', 'Gregg', 'Gregoria', 'Gregorio', 'Gregory',\n    'Greta', 'Gretchen', 'Greyson', 'Griffin', 'Grover', 'Guadalupe', 'Gudrun',\n    'Guido', 'Guillermo', 'Guiseppe', 'Gunnar', 'Gunner', 'Gus', 'Gussie',\n    'Gust', 'Gustave', 'Guy', 'Gwen', 'Gwendolyn', 'Hadley', 'Hailee', 'Hailey',\n    'Hailie', 'Hal', 'Haleigh', 'Haley', 'Halie', 'Halle', 'Hallie', 'Hank',\n    'Hanna', 'Hannah', 'Hans', 'Hardy', 'Harley', 'Harmon', 'Harmony', 'Harold',\n    'Harrison', 'Harry', 'Harvey', 'Haskell', 'Hassan', 'Hassie', 'Hattie',\n    'Haven', 'Hayden', 'Haylee', 'Hayley', 'Haylie', 'Hazel', 'Hazle', 'Heath',\n    'Heather', 'Heaven', 'Heber', 'Hector', 'Heidi', 'Helen', 'Helena',\n    'Helene', 'Helga', 'Hellen', 'Helmer', 'Heloise', 'Henderson', 'Henri',\n    'Henriette', 'Henry', 'Herbert', 'Herman', 'Hermann', 'Hermina', 'Herminia',\n    'Herminio', 'Hershel', 'Herta', 'Hertha', 'Hester', 'Hettie', 'Hilario',\n    'Hilbert', 'Hilda', 'Hildegard', 'Hillard', 'Hillary', 'Hilma', 'Hilton',\n    'Hipolito', 'Hiram', 'Hobart', 'Holden', 'Hollie', 'Hollis', 'Holly',\n    'Hope', 'Horace', 'Horacio', 'Hortense', 'Hosea', 'Houston', 'Howard',\n    'Howell', 'Hoyt', 'Hubert', 'Hudson', 'Hugh', 'Hulda', 'Humberto', 'Hunter',\n    'Hyman', 'Ian', 'Ibrahim', 'Icie', 'Ida', 'Idell', 'Idella', 'Ignacio',\n    'Ignatius', 'Ike', 'Ila', 'Ilene', 'Iliana', 'Ima', 'Imani', 'Imelda',\n    'Immanuel', 'Imogene', 'Ines', 'Irma', 'Irving', 'Irwin', 'Isaac', 'Isabel',\n    'Isabell', 'Isabella', 'Isabelle', 'Isac', 'Isadore', 'Isai', 'Isaiah',\n    'Isaias', 'Isidro', 'Ismael', 'Isobel', 'Isom', 'Israel', 'Issac', 'Itzel',\n    'Iva', 'Ivah', 'Ivory', 'Ivy', 'Izabella', 'Izaiah', 'Jabari', 'Jace',\n    'Jacey', 'Jacinthe', 'Jacinto', 'Jack', 'Jackeline', 'Jackie', 'Jacklyn',\n    'Jackson', 'Jacky', 'Jaclyn', 'Jacquelyn', 'Jacques', 'Jacynthe', 'Jada',\n    'Jade', 'Jaden', 'Jadon', 'Jadyn', 'Jaeden', 'Jaida', 'Jaiden', 'Jailyn',\n    'Jaime', 'Jairo', 'Jakayla', 'Jake', 'Jakob', 'Jaleel', 'Jalen', 'Jalon',\n    'Jalyn', 'Jamaal', 'Jamal', 'Jamar', 'Jamarcus', 'Jamel', 'Jameson',\n    'Jamey', 'Jamie', 'Jamil', 'Jamir', 'Jamison', 'Jammie', 'Jan', 'Jana',\n    'Janae', 'Jane', 'Janelle', 'Janessa', 'Janet', 'Janice', 'Janick', 'Janie',\n    'Janis', 'Janiya', 'Jannie', 'Jany', 'Jaquan', 'Jaquelin', 'Jaqueline',\n    'Jared', 'Jaren', 'Jarod', 'Jaron', 'Jarred', 'Jarrell', 'Jarret',\n    'Jarrett', 'Jarrod', 'Jarvis', 'Jasen', 'Jasmin', 'Jason', 'Jasper',\n    'Jaunita', 'Javier', 'Javon', 'Javonte', 'Jay', 'Jayce', 'Jaycee', 'Jayda',\n    'Jayde', 'Jayden', 'Jaydon', 'Jaylan', 'Jaylen', 'Jaylin', 'Jaylon',\n    'Jayme', 'Jayne', 'Jayson', 'Jazlyn', 'Jazmin', 'Jazmyn', 'Jazmyne', 'Jean',\n    'Jeanette', 'Jeanie', 'Jeanne', 'Jed', 'Jedediah', 'Jedidiah', 'Jeff',\n    'Jefferey', 'Jeffery', 'Jeffrey', 'Jeffry', 'Jena', 'Jenifer', 'Jennie',\n    'Jennifer', 'Jennings', 'Jennyfer', 'Jensen', 'Jerad', 'Jerald', 'Jeramie',\n    'Jeramy', 'Jerel', 'Jeremie', 'Jeremy', 'Jermain', 'Jermaine', 'Jermey',\n    'Jerod', 'Jerome', 'Jeromy', 'Jerrell', 'Jerrod', 'Jerrold', 'Jerry',\n    'Jess', 'Jesse', 'Jessica', 'Jessie', 'Jessika', 'Jessy', 'Jessyca',\n    'Jesus', 'Jett', 'Jettie', 'Jevon', 'Jewel', 'Jewell', 'Jillian', 'Jimmie',\n    'Jimmy', 'Jo', 'Joan', 'Joana', 'Joanie', 'Joanne', 'Joannie', 'Joanny',\n    'Joany', 'Joaquin', 'Jocelyn', 'Jodie', 'Jody', 'Joe', 'Joel', 'Joelle',\n    'Joesph', 'Joey', 'Johan', 'Johann', 'Johanna', 'Johathan', 'John',\n    'Johnathan', 'Johnathon', 'Johnnie', 'Johnny', 'Johnpaul', 'Johnson',\n    'Jolie', 'Jon', 'Jonas', 'Jonatan', 'Jonathan', 'Jonathon', 'Jordan',\n    'Jordane', 'Jordi', 'Jordon', 'Jordy', 'Jordyn', 'Jorge', 'Jose', 'Josefa',\n    'Josefina', 'Joseph', 'Josephine', 'Josh', 'Joshua', 'Joshuah', 'Josiah',\n    'Josiane', 'Josianne', 'Josie', 'Josue', 'Jovan', 'Jovani', 'Jovanny',\n    'Jovany', 'Joy', 'Joyce', 'Juana', 'Juanita', 'Judah', 'Judd', 'Jude',\n    'Judge', 'Judson', 'Judy', 'Jules', 'Julia', 'Julian', 'Juliana',\n    'Julianne', 'Julie', 'Julien', 'Juliet', 'Julio', 'Julius', 'June',\n    'Junior', 'Junius', 'Justen', 'Justice', 'Justina', 'Justine', 'Juston',\n    'Justus', 'Justyn', 'Juvenal', 'Juwan', 'Kacey', 'Kaci', 'Kacie', 'Kade',\n    'Kaden', 'Kadin', 'Kaela', 'Kaelyn', 'Kaia', 'Kailee', 'Kailey', 'Kailyn',\n    'Kaitlin', 'Kaitlyn', 'Kale', 'Kaleb', 'Kaleigh', 'Kaley', 'Kali', 'Kallie',\n    'Kameron', 'Kamille', 'Kamren', 'Kamron', 'Kamryn', 'Kane', 'Kara',\n    'Kareem', 'Karelle', 'Karen', 'Kari', 'Kariane', 'Karianne', 'Karina',\n    'Karine', 'Karl', 'Karlee', 'Karley', 'Karli', 'Karlie', 'Karolann',\n    'Karson', 'Kasandra', 'Kasey', 'Kassandra', 'Katarina', 'Katelin',\n    'Katelyn', 'Katelynn', 'Katharina', 'Katherine', 'Katheryn', 'Kathleen',\n    'Kathlyn', 'Kathryn', 'Kathryne', 'Katlyn', 'Katlynn', 'Katrina', 'Katrine',\n    'Kattie', 'Kavon', 'Kay', 'Kaya', 'Kaycee', 'Kayden', 'Kayla', 'Kaylah',\n    'Kaylee', 'Kayleigh', 'Kayley', 'Kayli', 'Kaylie', 'Kaylin', 'Keagan',\n    'Keanu', 'Keara', 'Keaton', 'Keegan', 'Keeley', 'Keely', 'Keenan', 'Keira',\n    'Keith', 'Kellen', 'Kelley', 'Kelli', 'Kellie', 'Kelly', 'Kelsi', 'Kelsie',\n    'Kelton', 'Kelvin', 'Ken', 'Kendall', 'Kendra', 'Kendrick', 'Kenna',\n    'Kennedi', 'Kennedy', 'Kenneth', 'Kennith', 'Kenny', 'Kenton', 'Kenya',\n    'Kenyatta', 'Kenyon', 'Keon', 'Keshaun', 'Keshawn', 'Keven', 'Kevin',\n    'Kevon', 'Keyon', 'Keyshawn', 'Khalid', 'Khalil', 'Kian', 'Kiana', 'Kianna',\n    'Kiara', 'Kiarra', 'Kiel', 'Kiera', 'Kieran', 'Kiley', 'Kim', 'Kimberly',\n    'King', 'Kip', 'Kira', 'Kirk', 'Kirsten', 'Kirstin', 'Kitty', 'Kobe',\n    'Koby', 'Kody', 'Kolby', 'Kole', 'Korbin', 'Korey', 'Kory', 'Kraig', 'Kris',\n    'Krista', 'Kristian', 'Kristin', 'Kristina', 'Kristofer', 'Kristoffer',\n    'Kristopher', 'Kristy', 'Krystal', 'Krystel', 'Krystina', 'Kurt', 'Kurtis',\n    'Kyla', 'Kyle', 'Kylee', 'Kyleigh', 'Kyler', 'Kylie', 'Kyra', 'Lacey',\n    'Lacy', 'Ladarius', 'Lafayette', 'Laila', 'Laisha', 'Lamar', 'Lambert',\n    'Lamont', 'Lance', 'Landen', 'Lane', 'Laney', 'Larissa', 'Laron', 'Larry',\n    'Larue', 'Laura', 'Laurel', 'Lauren', 'Laurence', 'Lauretta', 'Lauriane',\n    'Laurianne', 'Laurie', 'Laurine', 'Laury', 'Lauryn', 'Lavada', 'Lavern',\n    'Laverna', 'Laverne', 'Lavina', 'Lavinia', 'Lavon', 'Lavonne', 'Lawrence',\n    'Lawson', 'Layla', 'Layne', 'Lazaro', 'Lea', 'Leann', 'Leanna', 'Leanne',\n    'Leatha', 'Leda', 'Lee', 'Leif', 'Leila', 'Leilani', 'Lela', 'Lelah',\n    'Leland', 'Lelia', 'Lempi', 'Lemuel', 'Lenna', 'Lennie', 'Lenny', 'Lenora',\n    'Lenore', 'Leo', 'Leola', 'Leon', 'Leonard', 'Leonardo', 'Leone', 'Leonel',\n    'Leonie', 'Leonor', 'Leonora', 'Leopold', 'Leopoldo', 'Leora', 'Lera',\n    'Lesley', 'Leslie', 'Lesly', 'Lessie', 'Lester', 'Leta', 'Letha', 'Letitia',\n    'Levi', 'Lew', 'Lewis', 'Lexi', 'Lexie', 'Lexus', 'Lia', 'Liam', 'Liana',\n    'Libbie', 'Libby', 'Lila', 'Lilian', 'Liliana', 'Liliane', 'Lilla',\n    'Lillian', 'Lilliana', 'Lillie', 'Lilly', 'Lily', 'Lilyan', 'Lina',\n    'Lincoln', 'Linda', 'Lindsay', 'Lindsey', 'Linnea', 'Linnie', 'Linwood',\n    'Lionel', 'Lisa', 'Lisandro', 'Lisette', 'Litzy', 'Liza', 'Lizeth',\n    'Lizzie', 'Llewellyn', 'Lloyd', 'Logan', 'Lois', 'Lola', 'Lolita', 'Loma',\n    'Lon', 'London', 'Lonie', 'Lonnie', 'Lonny', 'Lonzo', 'Lora', 'Loraine',\n    'Loren', 'Lorena', 'Lorenz', 'Lorenza', 'Lorenzo', 'Lori', 'Lorine',\n    'Lorna', 'Lottie', 'Lou', 'Louie', 'Louisa', 'Lourdes', 'Louvenia',\n    'Lowell', 'Loy', 'Loyal', 'Loyce', 'Lucas', 'Luciano', 'Lucie', 'Lucienne',\n    'Lucile', 'Lucinda', 'Lucio', 'Lucious', 'Lucius', 'Lucy', 'Ludie',\n    'Ludwig', 'Lue', 'Luella', 'Luigi', 'Luis', 'Luisa', 'Lukas', 'Lula',\n    'Lulu', 'Luna', 'Lupe', 'Lura', 'Lurline', 'Luther', 'Luz', 'Lyda', 'Lydia',\n    'Lyla', 'Lynn', 'Lyric', 'Lysanne', 'Mabel', 'Mabelle', 'Mable', 'Mac',\n    'Macey', 'Maci', 'Macie', 'Mack', 'Mackenzie', 'Macy', 'Madaline',\n    'Madalyn', 'Maddison', 'Madeline', 'Madelyn', 'Madelynn', 'Madge', 'Madie',\n    'Madilyn', 'Madisen', 'Madison', 'Madisyn', 'Madonna', 'Madyson', 'Mae',\n    'Maegan', 'Maeve', 'Mafalda', 'Magali', 'Magdalen', 'Magdalena', 'Maggie',\n    'Magnolia', 'Magnus', 'Maia', 'Maida', 'Maiya', 'Major', 'Makayla',\n    'Makenna', 'Makenzie', 'Malachi', 'Malcolm', 'Malika', 'Malinda', 'Mallie',\n    'Mallory', 'Malvina', 'Mandy', 'Manley', 'Manuel', 'Manuela', 'Mara',\n    'Marc', 'Marcel', 'Marcelina', 'Marcelino', 'Marcella', 'Marcelle',\n    'Marcellus', 'Marcelo', 'Marcia', 'Marco', 'Marcos', 'Marcus', 'Margaret',\n    'Margarete', 'Margarett', 'Margaretta', 'Margarette', 'Margarita', 'Marge',\n    'Margie', 'Margot', 'Margret', 'Marguerite', 'Maria', 'Mariah', 'Mariam',\n    'Marian', 'Mariana', 'Mariane', 'Marianna', 'Marianne', 'Mariano',\n    'Maribel', 'Marie', 'Mariela', 'Marielle', 'Marietta', 'Marilie', 'Marilou',\n    'Marilyne', 'Marina', 'Mario', 'Marion', 'Marisa', 'Marisol', 'Maritza',\n    'Marjolaine', 'Marjorie', 'Marjory', 'Mark', 'Markus', 'Marlee', 'Marlen',\n    'Marlene', 'Marley', 'Marlin', 'Marlon', 'Marques', 'Marquis', 'Marquise',\n    'Marshall', 'Marta', 'Martin', 'Martina', 'Martine', 'Marty', 'Marvin',\n    'Mary', 'Maryam', 'Maryjane', 'Maryse', 'Mason', 'Mateo', 'Mathew',\n    'Mathias', 'Mathilde', 'Matilda', 'Matilde', 'Matt', 'Matteo', 'Mattie',\n    'Maud', 'Maude', 'Maudie', 'Maureen', 'Maurice', 'Mauricio', 'Maurine',\n    'Maverick', 'Mavis', 'Max', 'Maxie', 'Maxime', 'Maximilian', 'Maximillia',\n    'Maximillian', 'Maximo', 'Maximus', 'Maxine', 'Maxwell', 'May', 'Maya',\n    'Maybell', 'Maybelle', 'Maye', 'Maymie', 'Maynard', 'Mayra', 'Mazie',\n    'Mckayla', 'Mckenna', 'Mckenzie', 'Meagan', 'Meaghan', 'Meda', 'Megane',\n    'Meggie', 'Meghan', 'Mekhi', 'Melany', 'Melba', 'Melisa', 'Melissa',\n    'Mellie', 'Melody', 'Melvin', 'Melvina', 'Melyna', 'Melyssa', 'Mercedes',\n    'Meredith', 'Merl', 'Merle', 'Merlin', 'Merritt', 'Mertie', 'Mervin',\n    'Meta', 'Mia', 'Micaela', 'Micah', 'Michael', 'Michaela', 'Michale',\n    'Micheal', 'Michel', 'Michele', 'Michelle', 'Miguel', 'Mikayla', 'Mike',\n    'Mikel', 'Milan', 'Miles', 'Milford', 'Miller', 'Millie', 'Milo', 'Milton',\n    'Mina', 'Minerva', 'Minnie', 'Miracle', 'Mireille', 'Mireya', 'Misael',\n    'Missouri', 'Misty', 'Mitchel', 'Mitchell', 'Mittie', 'Modesta', 'Modesto',\n    'Mohamed', 'Mohammad', 'Mohammed', 'Moises', 'Mollie', 'Molly', 'Mona',\n    'Monica', 'Monique', 'Monroe', 'Monserrat', 'Monserrate', 'Montana',\n    'Monte', 'Monty', 'Morgan', 'Moriah', 'Morris', 'Mortimer', 'Morton',\n    'Mose', 'Moses', 'Moshe', 'Mossie', 'Mozell', 'Mozelle', 'Muhammad',\n    'Muriel', 'Murl', 'Murphy', 'Murray', 'Mustafa', 'Mya', 'Myah', 'Mylene',\n    'Myles', 'Myra', 'Myriam', 'Myrl', 'Myrna', 'Myron', 'Myrtice', 'Myrtie',\n    'Myrtis', 'Myrtle', 'Nadia', 'Nakia', 'Name', 'Nannie', 'Naomi', 'Naomie',\n    'Napoleon', 'Narciso', 'Nash', 'Nasir', 'Nat', 'Natalia', 'Natalie',\n    'Natasha', 'Nathan', 'Nathanael', 'Nathanial', 'Nathaniel', 'Nathen',\n    'Nayeli', 'Neal', 'Ned', 'Nedra', 'Neha', 'Neil', 'Nelda', 'Nella', 'Nelle',\n    'Nellie', 'Nels', 'Nelson', 'Neoma', 'Nestor', 'Nettie', 'Neva', 'Newell',\n    'Newton', 'Nia', 'Nicholas', 'Nicholaus', 'Nichole', 'Nick', 'Nicklaus',\n    'Nickolas', 'Nico', 'Nicola', 'Nicolas', 'Nicole', 'Nicolette', 'Nigel',\n    'Nikita', 'Nikki', 'Nikko', 'Niko', 'Nikolas', 'Nils', 'Nina', 'Noah',\n    'Noble', 'Noe', 'Noel', 'Noelia', 'Noemi', 'Noemie', 'Noemy', 'Nola',\n    'Nolan', 'Nona', 'Nora', 'Norbert', 'Norberto', 'Norene', 'Norma', 'Norris',\n    'Norval', 'Norwood', 'Nova', 'Novella', 'Nya', 'Nyah', 'Nyasia', 'Obie',\n    'Oceane', 'Ocie', 'Octavia', 'Oda', 'Odell', 'Odessa', 'Odie', 'Ofelia',\n    'Okey', 'Ola', 'Olaf', 'Ole', 'Olen', 'Oleta', 'Olga', 'Olin', 'Oliver',\n    'Ollie', 'Oma', 'Omari', 'Omer', 'Ona', 'Onie', 'Opal', 'Ophelia', 'Ora',\n    'Oral', 'Oran', 'Oren', 'Orie', 'Orin', 'Orion', 'Orland', 'Orlando',\n    'Orlo', 'Orpha', 'Orrin', 'Orval', 'Orville', 'Osbaldo', 'Osborne', 'Oscar',\n    'Osvaldo', 'Oswald', 'Oswaldo', 'Otha', 'Otho', 'Otilia', 'Otis', 'Ottilie',\n    'Ottis', 'Otto', 'Ova', 'Owen', 'Ozella', 'Pablo', 'Paige', 'Palma',\n    'Pamela', 'Pansy', 'Paolo', 'Paris', 'Parker', 'Pascale', 'Pasquale', 'Pat',\n    'Patience', 'Patricia', 'Patrick', 'Patsy', 'Pattie', 'Paul', 'Paula',\n    'Pauline', 'Paxton', 'Payton', 'Pearl', 'Pearlie', 'Pearline', 'Pedro',\n    'Peggie', 'Penelope', 'Percival', 'Percy', 'Perry', 'Pete', 'Peter',\n    'Petra', 'Peyton', 'Philip', 'Phoebe', 'Phyllis', 'Pierce', 'Pierre',\n    'Pietro', 'Pink', 'Pinkie', 'Piper', 'Polly', 'Porter', 'Precious',\n    'Presley', 'Preston', 'Price', 'Prince', 'Princess', 'Priscilla',\n    'Providenci', 'Prudence', 'Queen', 'Queenie', 'Quentin', 'Quincy', 'Quinn',\n    'Quinten', 'Quinton', 'Rachael', 'Rachel', 'Rachelle', 'Rae', 'Raegan',\n    'Rafael', 'Rafaela', 'Raheem', 'Rahsaan', 'Rahul', 'Raina', 'Raleigh',\n    'Ralph', 'Ramiro', 'Ramon', 'Ramona', 'Randal', 'Randall', 'Randi', 'Randy',\n    'Ransom', 'Raoul', 'Raphael', 'Raphaelle', 'Raquel', 'Rashad', 'Rashawn',\n    'Rasheed', 'Raul', 'Raven', 'Ray', 'Raymond', 'Raymundo', 'Reagan',\n    'Reanna', 'Reba', 'Rebeca', 'Rebecca', 'Rebeka', 'Rebekah', 'Reece', 'Reed',\n    'Reese', 'Regan', 'Reggie', 'Reginald', 'Reid', 'Reilly', 'Reina',\n    'Reinhold', 'Remington', 'Rene', 'Renee', 'Ressie', 'Reta', 'Retha',\n    'Retta', 'Reuben', 'Reva', 'Rex', 'Rey', 'Reyes', 'Reymundo', 'Reyna',\n    'Reynold', 'Rhea', 'Rhett', 'Rhianna', 'Rhiannon', 'Rhoda', 'Ricardo',\n    'Richard', 'Richie', 'Richmond', 'Rick', 'Rickey', 'Rickie', 'Ricky',\n    'Rico', 'Rigoberto', 'Riley', 'Rita', 'River', 'Robb', 'Robbie', 'Robert',\n    'Roberta', 'Roberto', 'Robin', 'Robyn', 'Rocio', 'Rocky', 'Rod', 'Roderick',\n    'Rodger', 'Rodolfo', 'Rodrick', 'Rodrigo', 'Roel', 'Rogelio', 'Roger',\n    'Rogers', 'Rolando', 'Rollin', 'Roma', 'Romaine', 'Roman', 'Ron', 'Ronaldo',\n    'Ronny', 'Roosevelt', 'Rory', 'Rosa', 'Rosalee', 'Rosalia', 'Rosalind',\n    'Rosalinda', 'Rosalyn', 'Rosamond', 'Rosanna', 'Rosario', 'Roscoe', 'Rose',\n    'Rosella', 'Roselyn', 'Rosemarie', 'Rosemary', 'Rosendo', 'Rosetta',\n    'Rosie', 'Rosina', 'Roslyn', 'Ross', 'Rossie', 'Rowan', 'Rowena', 'Rowland',\n    'Roxane', 'Roxanne', 'Roy', 'Royal', 'Royce', 'Rozella', 'Ruben', 'Rubie',\n    'Ruby', 'Rubye', 'Rudolph', 'Rudy', 'Rupert', 'Russ', 'Russel', 'Russell',\n    'Rusty', 'Ruth', 'Ruthe', 'Ruthie', 'Ryan', 'Ryann', 'Ryder', 'Rylan',\n    'Rylee', 'Ryleigh', 'Ryley', 'Sabina', 'Sabrina', 'Sabryna', 'Sadie',\n    'Sadye', 'Sage', 'Saige', 'Sallie', 'Sally', 'Salma', 'Salvador',\n    'Salvatore', 'Sam', 'Samanta', 'Samantha', 'Samara', 'Samir', 'Sammie',\n    'Sammy', 'Samson', 'Sandra', 'Sandrine', 'Sandy', 'Sanford', 'Santa',\n    'Santiago', 'Santina', 'Santino', 'Santos', 'Sarah', 'Sarai', 'Sarina',\n    'Sasha', 'Saul', 'Savanah', 'Savanna', 'Savannah', 'Savion', 'Scarlett',\n    'Schuyler', 'Scot', 'Scottie', 'Scotty', 'Seamus', 'Sean', 'Sebastian',\n    'Sedrick', 'Selena', 'Selina', 'Selmer', 'Serena', 'Serenity', 'Seth',\n    'Shad', 'Shaina', 'Shakira', 'Shana', 'Shane', 'Shanel', 'Shanelle',\n    'Shania', 'Shanie', 'Shaniya', 'Shanna', 'Shannon', 'Shanny', 'Shanon',\n    'Shany', 'Sharon', 'Shaun', 'Shawn', 'Shawna', 'Shaylee', 'Shayna',\n    'Shayne', 'Shea', 'Sheila', 'Sheldon', 'Shemar', 'Sheridan', 'Sherman',\n    'Sherwood', 'Shirley', 'Shyann', 'Shyanne', 'Sibyl', 'Sid', 'Sidney',\n    'Sienna', 'Sierra', 'Sigmund', 'Sigrid', 'Sigurd', 'Silas', 'Sim', 'Simeon',\n    'Simone', 'Sincere', 'Sister', 'Skye', 'Skyla', 'Skylar', 'Sofia',\n    'Soledad', 'Solon', 'Sonia', 'Sonny', 'Sonya', 'Sophia', 'Sophie',\n    'Spencer', 'Stacey', 'Stacy', 'Stan', 'Stanford', 'Stanley', 'Stanton',\n    'Stefan', 'Stefanie', 'Stella', 'Stephan', 'Stephania', 'Stephanie',\n    'Stephany', 'Stephen', 'Stephon', 'Sterling', 'Steve', 'Stevie', 'Stewart',\n    'Stone', 'Stuart', 'Summer', 'Sunny', 'Susan', 'Susana', 'Susanna', 'Susie',\n    'Suzanne', 'Sven', 'Syble', 'Sydnee', 'Sydney', 'Sydni', 'Sydnie', 'Sylvan',\n    'Sylvester', 'Sylvia', 'Tabitha', 'Tad', 'Talia', 'Talon', 'Tamara',\n    'Tamia', 'Tania', 'Tanner', 'Tanya', 'Tara', 'Taryn', 'Tate', 'Tatum',\n    'Tatyana', 'Taurean', 'Tavares', 'Taya', 'Taylor', 'Teagan', 'Ted', 'Telly',\n    'Terence', 'Teresa', 'Terrance', 'Terrell', 'Terrence', 'Terrill', 'Terry',\n    'Tess', 'Tessie', 'Tevin', 'Thad', 'Thaddeus', 'Thalia', 'Thea', 'Thelma',\n    'Theo', 'Theodora', 'Theodore', 'Theresa', 'Therese', 'Theresia', 'Theron',\n    'Thomas', 'Thora', 'Thurman', 'Tia', 'Tiana', 'Tianna', 'Tiara', 'Tierra',\n    'Tiffany', 'Tillman', 'Timmothy', 'Timmy', 'Timothy', 'Tina', 'Tito',\n    'Titus', 'Tobin', 'Toby', 'Tod', 'Tom', 'Tomas', 'Tomasa', 'Tommie',\n    'Toney', 'Toni', 'Tony', 'Torey', 'Torrance', 'Torrey', 'Toy', 'Trace',\n    'Tracey', 'Tracy', 'Travis', 'Travon', 'Tre', 'Tremaine', 'Tremayne',\n    'Trent', 'Trenton', 'Tressa', 'Tressie', 'Treva', 'Trever', 'Trevion',\n    'Trevor', 'Trey', 'Trinity', 'Trisha', 'Tristian', 'Tristin', 'Triston',\n    'Troy', 'Trudie', 'Trycia', 'Trystan', 'Turner', 'Twila', 'Tyler', 'Tyra',\n    'Tyree', 'Tyreek', 'Tyrel', 'Tyrell', 'Tyrese', 'Tyrique', 'Tyshawn',\n    'Tyson', 'Ubaldo', 'Ulices', 'Ulises', 'Una', 'Unique', 'Urban', 'Uriah',\n    'Uriel', 'Ursula', 'Vada', 'Valentin', 'Valentina', 'Valentine', 'Valerie',\n    'Vallie', 'Van', 'Vance', 'Vanessa', 'Vaughn', 'Veda', 'Velda', 'Vella',\n    'Velma', 'Velva', 'Vena', 'Verda', 'Verdie', 'Vergie', 'Verla', 'Verlie',\n    'Vern', 'Verna', 'Verner', 'Vernice', 'Vernie', 'Vernon', 'Verona',\n    'Veronica', 'Vesta', 'Vicenta', 'Vicente', 'Vickie', 'Vicky', 'Victor',\n    'Victoria', 'Vida', 'Vidal', 'Vilma', 'Vince', 'Vincent', 'Vincenza',\n    'Vincenzo', 'Vinnie', 'Viola', 'Violet', 'Violette', 'Virgie', 'Virgil',\n    'Virginia', 'Virginie', 'Vita', 'Vito', 'Viva', 'Vivian', 'Viviane',\n    'Vivianne', 'Vivien', 'Vivienne', 'Vladimir', 'Wade', 'Waino', 'Waldo',\n    'Walker', 'Wallace', 'Walter', 'Walton', 'Wanda', 'Ward', 'Warren',\n    'Watson', 'Wava', 'Waylon', 'Wayne', 'Webster', 'Weldon', 'Wellington',\n    'Wendell', 'Wendy', 'Werner', 'Westley', 'Weston', 'Whitney', 'Wilber',\n    'Wilbert', 'Wilburn', 'Wiley', 'Wilford', 'Wilfred', 'Wilfredo', 'Wilfrid',\n    'Wilhelm', 'Wilhelmine', 'Will', 'Willa', 'Willard', 'William', 'Willie',\n    'Willis', 'Willow', 'Willy', 'Wilma', 'Wilmer', 'Wilson', 'Wilton',\n    'Winfield', 'Winifred', 'Winnifred', 'Winona', 'Winston', 'Woodrow',\n    'Wyatt', 'Wyman', 'Xander', 'Xavier', 'Xzavier', 'Yadira', 'Yasmeen',\n    'Yasmin', 'Yasmine', 'Yazmin', 'Yesenia', 'Yessenia', 'Yolanda', 'Yoshiko',\n    'Yvette', 'Yvonne', 'Zachariah', 'Zachary', 'Zachery', 'Zack', 'Zackary',\n    'Zackery', 'Zakary', 'Zander', 'Zane', 'Zaria', 'Zechariah', 'Zelda',\n    'Zella', 'Zelma', 'Zena', 'Zetta', 'Zion', 'Zita', 'Zoe', 'Zoey', 'Zoie',\n    'Zoila', 'Zola', 'Zora', 'Zula'\n];\n\n/**\n * Generate random username.\n * @returns {string} random username\n */\nfunction generateUsername() {\n    const name = RandomUtil.randomElement(names);\n    const suffix = RandomUtil.randomAlphanumStr(3);\n\n    return `${name}-${suffix}`;\n}\n\nmodule.exports = {\n    generateUsername\n};\n","/* Copyright @ 2016-present 8x8, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nvar Logger = require('./Logger.js');\n\n/**\n * Creates new <tt>LogCollector</tt>. Class implements <tt>LoggerTransport</tt>\n * and thus can be added as global transport in order to capture all the logs.\n *\n * It captures subsequent log lines created whenever <tt>Logger</tt> logs\n * a message and stores them in a queue in order to batch log entries. There are\n * time and size limit constraints which determine how often batch entries are\n * stored. Whenever one of these limits is exceeded the <tt>LogCollector</tt>\n * will use the <tt>logStorage</tt> object given as an argument to save\n * the batch log entry.\n *\n * @param {Object} logStorage an object which allows to store the logs collected\n * @param {function(string|object[])} logStorage.storeLogs a method called when\n * this <tt>LogCollector</tt> requests log entry storage. The method's argument\n * is an array which can contain <tt>string</tt>s and <tt>object</tt>s. If given\n * item is an object it means that it's an aggregated message. That is a message\n * which is the same as the previous one and it's representation has\n * the following format:\n * {\n *   {string} text: 'the text of some duplicated message'\n *   {number} count: 3 // how many times the message appeared in a row\n * }\n * If a message \"B\" after an aggregated message \"A\" is different, then it breaks\n * the sequence of \"A\". Which means that even if the next message \"C\" is\n * the same as \"A\" it will start a new aggregated message \"C\".\n * @param {function()} logStorage.isReady a method which should return\n * a <tt>boolean</tt> to tell the collector that it's ready to store. During the\n * time storage is not ready log batches will be cached and stored on the next\n * occasion (flush or interval timeout).\n *\n * @param {Object} options the <tt>LogCollector</tt> configuration options.\n * @param {number} options.maxEntryLength the size limit for a single log entry\n * to be stored. The <tt>LogCollector</tt> will push the entry as soon as it\n * reaches or exceeds this limit given that <tt>logStorage.isReady</tt>\n * returns <tt>true</tt>. Otherwise the log entry will be cached until the log\n * storage becomes ready. Note that the \"is ready\" condition is checked every\n * <tt>options.storeInterval</tt> milliseconds.\n * @param {number} options.storeInterval how often the logs should be stored in\n * case <tt>maxEntryLength</tt> was not exceeded.\n * @param {boolean} options.stringifyObjects indicates whether or not object\n * arguments should be \"stringified\" with <tt>JSON.stringify</tt> when a log\n * message is composed. Note that objects logged on the error log level are\n * always stringified.\n *\n * @constructor\n */\nfunction LogCollector(logStorage, options) {\n    this.logStorage = logStorage;\n    this.stringifyObjects = options && options.stringifyObjects ? options.stringifyObjects : false;\n    this.storeInterval = options && options.storeInterval ? options.storeInterval: 30000;\n    this.maxEntryLength = options && options.maxEntryLength ? options.maxEntryLength : 10000;\n    // Bind the log method for each level to the corresponding method name\n    // in order to implement \"global log transport\" object.\n    Object.keys(Logger.levels).forEach(\n    function (logLevel) {\n        var methodName = Logger.levels[logLevel];\n        this[methodName] = function () {\n            this._log.apply(this, arguments);\n        }.bind(this, logLevel);\n    }.bind(this));\n    /**\n     * The ID of store logs interval if one is currently scheduled or\n     * <tt>null</tt> otherwise.\n     * @type {number|null}\n     */\n    this.storeLogsIntervalID = null;\n    /**\n     * The log messages that are to be batched into log entry when\n     * {@link LogCollector._flush} method is called.\n     * @type {string[]}\n     */\n    this.queue = [];\n    /**\n     * The total length of all messages currently stored in the {@link queue}.\n     * @type {number}\n     */\n    this.totalLen = 0;\n    /**\n     * An array used to temporarily store log batches, before the storage gets\n     * ready.\n     * @type {string[]}\n     */\n    this.outputCache = [];\n}\n\n/**\n * Method called inside of {@link formatLogMessage} in order to covert an\n * <tt>Object</tt> argument to string. The conversion will happen when either\n * 'stringifyObjects' option is enabled or on the {@link Logger.levels.ERROR}\n * log level. The default implementation uses <tt>JSON.stringify</tt> and\n * returns \"[object with circular refs?]\" instead of an object if it fails.\n *\n * @param {object} someObject the <tt>object</tt> to be stringified.\n *\n * @return {string} the result of <tt>JSON.stringify</tt> or\n * \"[object with circular refs?]\" if any error occurs during \"stringification\".\n *\n * @protected\n */\nLogCollector.prototype.stringify = function (someObject) {\n    try {\n        return JSON.stringify(someObject);\n    } catch (error) {\n        return '[object with circular refs?]';\n    }\n};\n\n/**\n * Formats log entry for the given logging level and arguments passed to the\n * <tt>Logger</tt>'s log method. The first argument is log level and the next\n * arguments have to be captured using JS built-in 'arguments' variable.\n *\n * @param {Logger.levels} logLevel provides the logging level of the message to\n * be logged.\n * @param {Date} timestamp - The {@code Date} when a message has been logged.\n *\n * @return {string|null} a non-empty string representation of the log entry\n * crafted from the log arguments. If the return value is <tt>null</tt> then\n * the message wil be discarded by this <tt>LogCollector</tt>.\n *\n * @protected\n */\nLogCollector.prototype.formatLogMessage = function (\nlogLevel /* timestamp, arg2, arg3, arg4... */) {\n    var msg = '';\n    for (var i = 1, len = arguments.length; i < len; i++) {\n        var arg = arguments[i];\n        // objects logged on error level are always converted to JSON\n        if ((this.stringifyObjects || logLevel === Logger.levels.ERROR) &&\n            typeof arg === 'object') {\n            arg = this.stringify(arg);\n        }\n        msg += arg;\n        if (i !== len - 1) {\n            msg += ' ';\n        }\n    }\n    return msg.length ? msg : null;\n};\n\n/**\n * The log method bound to each of the logging levels in order to implement\n * \"global log transport\" object.\n *\n * @private\n */\nLogCollector.prototype._log = function() {\n\n    // var logLevel = arguments[0]; first argument is the log level\n    var timestamp = arguments[1];\n    var msg = this.formatLogMessage.apply(this, arguments);\n    if (msg) {\n        // The same as the previous message aggregation logic\n        var prevMessage = this.queue[this.queue.length - 1];\n        var prevMessageText = prevMessage && prevMessage.text;\n        if (prevMessageText === msg) {\n            prevMessage.count += 1;\n        } else {\n            this.queue.push({\n                text: msg,\n                timestamp: timestamp,\n                count: 1\n            });\n            this.totalLen += msg.length;\n        }\n    }\n\n    if (this.totalLen >= this.maxEntryLength) {\n        this._flush(true /* force */, true /* reschedule */);\n    }\n};\n\n/**\n * Starts periodical \"store logs\" task which will be triggered at the interval\n * specified in the constructor options.\n */\nLogCollector.prototype.start = function () {\n    this._reschedulePublishInterval();\n};\n\n/**\n * Reschedules the periodical \"store logs\" task which will store the next batch\n * log entry in the storage.\n * @private\n */\nLogCollector.prototype._reschedulePublishInterval = function () {\n    if (this.storeLogsIntervalID) {\n        window.clearTimeout(this.storeLogsIntervalID);\n        this.storeLogsIntervalID = null;\n    }\n    // It's actually a timeout, because it is rescheduled on every flush\n    this.storeLogsIntervalID = window.setTimeout(\n        this._flush.bind(\n            this, false /* do not force */, true /* reschedule */),\n        this.storeInterval);\n};\n\n/**\n * Call this method to flush the log entry buffer and store it in the log\n * storage immediately (given that the storage is ready).\n */\nLogCollector.prototype.flush = function() {\n    this._flush(\n        false /* do not force, as it will not be stored anyway */,\n        true /* reschedule next update */ );\n};\n\n/**\n * Stores the next batch log entry in the log storage.\n * @param {boolean} force enforce current logs batch to be stored or cached if\n * there is anything to be logged, but the storage is not ready yet. One of\n * legitimate reasons to force is when the logs length exceeds size limit which\n * could result in truncation.\n * @param {boolean} reschedule <tt>true</tt> if the next periodic task should be\n * scheduled after the log entry is stored. <tt>false</tt> will end the periodic\n * task cycle.\n * @private\n */\nLogCollector.prototype._flush = function(force, reschedule) {\n    // Publish only if there's anything to be logged\n    if (this.totalLen > 0 && (this.logStorage.isReady() || force)) {\n        //FIXME avoid truncating\n        // right now we don't care if the message size is \"slightly\" exceeded\n        if (this.logStorage.isReady()) {\n            // Sends all cached logs\n            if (this.outputCache.length) {\n                this.outputCache.forEach(\n                    function (cachedQueue) {\n                        this.logStorage.storeLogs(cachedQueue);\n                    }.bind(this)\n                );\n                // Clear the cache\n                this.outputCache = [];\n            }\n            // Send current batch\n            this.logStorage.storeLogs(this.queue);\n        } else {\n            this.outputCache.push(this.queue);\n        }\n\n        this.queue = [];\n        this.totalLen = 0;\n    }\n\n    if (reschedule) {\n        this._reschedulePublishInterval();\n    }\n};\n\n/**\n * Stops the periodical \"store logs\" task and immediately stores any pending\n * log entries as a batch.\n */\nLogCollector.prototype.stop = function() {\n    // Flush and stop publishing logs\n    this._flush(false /* do not force */, false /* do not reschedule */);\n};\n\nmodule.exports = LogCollector;\n","/* Copyright @ 2015-present 8x8, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/*jslint latedef:false*/\n\n/**\n * Ordered log levels.\n */\nvar levels = {\n    \"trace\": 0,\n    \"debug\": 1,\n    \"info\": 2,\n    \"log\": 3,\n    \"warn\": 4,\n    \"error\": 5\n};\n\n/**\n * The default transport - console\n * @type LoggerTransport\n */\nLogger.consoleTransport = console;\n\n/**\n * The array which stores currently registered global transports.\n * @type {[LoggerTransport]}\n */\nvar globalTransports = [ Logger.consoleTransport ];\n\n/**\n * Adds given {@link LoggerTransport} instance to the list of global\n * transports which means that it'll be used by all {@link Logger}s\n * @param {LoggerTransport} transport\n */\nLogger.addGlobalTransport = function(transport) {\n    if (globalTransports.indexOf(transport) === -1) {\n        globalTransports.push(transport);\n    }\n};\n\n/**\n * Removes given {@link LoggerTransport} instance from the list of global\n * transports\n * @param {LoggerTransport} transport\n */\nLogger.removeGlobalTransport = function(transport) {\n    var transportIdx = globalTransports.indexOf(transport);\n    if (transportIdx !== -1) {\n        globalTransports.splice(transportIdx, 1);\n    }\n};\n\n/**\n * The global configuration options.\n */\nvar globalOptions = {};\n\n/**\n * Sets global options which will be used by all loggers. Changing these works\n * even after other loggers are created.\n */\nLogger.setGlobalOptions = function(options) {\n    globalOptions = options || {};\n};\n\n/**\n * Parses Error's object stack trace and extracts information about the last\n * caller before the log method was called.\n * @returns JS object with info about the caller - method name, file location,\n * line and column.\n */\nfunction getCallerInfo() {\n    var callerInfo = {\n        methodName: \"\",\n        fileLocation: \"\",\n        line: null,\n        column: null\n    };\n    //gets the part of the stack without the logger wrappers\n    var error = new Error();\n    var stack = error.stack? error.stack.split(\"\\n\") : [];\n    if(!stack || stack.length < 3) {\n        return callerInfo;\n    }\n    var m = null;\n    if(stack[3]) {\n        m = stack[3].match(/\\s*at\\s*(.+?)\\s*\\((\\S*)\\s*:(\\d*)\\s*:(\\d*)\\)/);\n    }\n    if(!m || m.length <= 4) {\n        //Firefox && Safari\n        if(stack[2].indexOf(\"log@\") === 0){\n            //Safari\n            callerInfo.methodName = stack[3].substr(0, stack[3].indexOf(\"@\"));\n        } else {\n            //Firefox\n            callerInfo.methodName = stack[2].substr(0, stack[2].indexOf(\"@\"));\n        }\n        return callerInfo;\n    }\n\n    callerInfo.methodName = m[1];\n    callerInfo.fileLocation = m[2];\n    callerInfo.line = m[3];\n    callerInfo.column = m[4];\n    return callerInfo;\n}\n\n/**\n * Logs messages using the transports and level from the logger.\n * @param logger a logger instance.\n * @param level the log level of the message. See the levels variable.\n * @param arguments array with arguments that will be logged.\n */\nfunction log() {\n    var logger = arguments[0], level = arguments[1],\n        args = Array.prototype.slice.call(arguments, 2);\n    if(levels[level] < logger.level) {\n        return;\n    }\n\n    var callerInfo\n        = !(logger.options.disableCallerInfo || globalOptions.disableCallerInfo) &&\n            getCallerInfo();\n    var transports = globalTransports.concat(logger.transports);\n    for(var i = 0; i < transports.length; i++) {\n        var t = transports[i];\n        var l = t[level];\n        if(l && typeof(l) === \"function\") {\n            var logPrefixes = [];\n\n            logPrefixes.push(new Date().toISOString());\n\n            if (logger.id) {\n                logPrefixes.push(\"[\" + logger.id + \"]\");\n            }\n\n            if (callerInfo && callerInfo.methodName.length > 1) {\n                logPrefixes.push(\"<\" + callerInfo.methodName + \">: \");\n            }\n\n            var fullLogParts = logPrefixes.concat(args);\n\n            l.bind(t).apply(t, fullLogParts);\n        }\n    }\n}\n\n/**\n *\n * Constructs new logger object.\n * @param level the logging level for the new logger\n * @param id optional identifier for the logger instance.\n * @param {LoggerTransport} transports optional list of handlers(objects) for\n * the logs. The handlers must support - log, warn, error, debug, info, trace.\n * @param options optional configuration file for how the logger should behave.\n * @param {boolean} options.disableCallerInfo Whether the call site of a logger\n * method invocation should be included in the log. Defaults to false, so the\n * call site will be included.\n */\nfunction Logger(level, id, transports, options) {\n    this.id = id;\n    this.options = options || {};\n    this.transports = transports;\n    if(!this.transports) {\n        this.transports = [];\n    }\n    this.level = levels[level];\n    var methods = Object.keys(levels);\n    for(var i = 0; i < methods.length; i++){\n        this[methods[i]] =\n            log.bind(null, this, methods[i]);\n    }\n}\n\n/**\n * Sets the log level for the logger.\n * @param level the new log level.\n */\nLogger.prototype.setLevel = function (level) {\n    this.level = levels[level];\n};\nmodule.exports = Logger;\n\n/**\n * Enum for the supported log levels.\n */\nLogger.levels = {\n    TRACE: \"trace\",\n    DEBUG: \"debug\",\n    INFO: \"info\",\n    LOG: \"log\",\n    WARN: \"warn\",\n    ERROR: \"error\"\n};\n","/* Copyright @ 2015-present 8x8, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nvar Logger = require(\"./Logger\");\nvar LogCollector = require(\"./LogCollector\");\n\n/**\n * Definition of the log method\n * @name log_method\n * @function\n * @param {...*} log_args the arguments to be logged\n */\n/**\n * The logger's transport type definition.\n *\n * @typedef {object} LoggerTransport\n *\n * @property {log_method} trace method called to log on {@link Logger.levels.TRACE} logging level\n * @property {log_method} debug method called to log on {@link Logger.levels.DEBUG} logging level\n * @property {log_method} info method called to log on {@link Logger.levels.INFO} logging level\n * @property {log_method} log method called to log on {@link Logger.levels.LOG} logging level\n * @property {log_method} warn method called to log on {@link Logger.levels.WARN} logging level\n * @property {log_method} error method called to log on {@link Logger.levels.ERROR} logging level\n */\n\n/**\n * Map with the created loggers with ID.\n */\nvar idLoggers = {};\n\n/**\n * Array with the loggers without id.\n */\nvar loggers = [];\n\n/**\n * Log level for the lbrary.\n */\nvar curLevel = Logger.levels.TRACE;\n\n\nmodule.exports = {\n    /**\n     * Adds given {@link LoggerTransport} instance to the list of global\n     * transports which means that it'll be used by all {@link Logger}s\n     * @param {LoggerTransport} transport\n     */\n    addGlobalTransport: function(transport) {\n        Logger.addGlobalTransport(transport);\n    },\n    /**\n     * Removes given {@link LoggerTransport} instance from the list of global\n     * transports\n     * @param {LoggerTransport} transport\n     */\n    removeGlobalTransport: function(transport) {\n        Logger.removeGlobalTransport(transport);\n    },\n    /**\n    * Sets global options which will be used by all loggers. Changing these\n    * works even after other loggers are created.\n    */\n    setGlobalOptions: function(options) {\n        Logger.setGlobalOptions(options);\n    },\n    /**\n     * Creates new logger.\n     * @arguments the same as Logger constructor\n     */\n    getLogger: function(id, transports, options) {\n        var logger = new Logger(curLevel, id, transports, options);\n        if(id) {\n            idLoggers[id] = idLoggers[id] || [];\n            idLoggers[id].push(logger);\n        } else {\n            loggers.push(logger);\n        }\n        return logger;\n    },\n    /**\n     * Changes the log level for the existing loggers by id.\n     * @param level the new log level.\n     * @param id if specified the level will be changed only for loggers with the\n     * same id. Otherwise the operation will affect all loggers that don't\n     * have id.\n     */\n    setLogLevelById: function(level, id) {\n        var l = id? (idLoggers[id] || []) : loggers;\n        for(var i = 0; i < l.length; i++) {\n            l[i].setLevel(level);\n        }\n    },\n    /**\n     * Changes the log level for all existing loggers.\n     * @param level the new log level.\n     */\n    setLogLevel: function (level) {\n        curLevel = level;\n        var i = 0;\n        for(; i < loggers.length; i++) {\n            loggers[i].setLevel(level);\n        }\n\n        for(var id in idLoggers) {\n            var l = idLoggers[id] || [];\n            for(i = 0; i < l.length; i++) {\n                l[i].setLevel(level);\n            }\n        }\n    },\n    /**\n     * The supported log levels.\n     */\n    levels: Logger.levels,\n    /**\n     * Exports the <tt>LogCollector</tt>.\n     */\n    LogCollector: LogCollector\n};\n","var grammar = module.exports = {\n  v: [{\n    name: 'version',\n    reg: /^(\\d*)$/\n  }],\n  o: [{\n    // o=- 20518 0 IN IP4 203.0.113.1\n    // NB: sessionId will be a String in most cases because it is huge\n    name: 'origin',\n    reg: /^(\\S*) (\\d*) (\\d*) (\\S*) IP(\\d) (\\S*)/,\n    names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],\n    format: '%s %s %d %s IP%d %s'\n  }],\n  // default parsing of these only (though some of these feel outdated)\n  s: [{ name: 'name' }],\n  i: [{ name: 'description' }],\n  u: [{ name: 'uri' }],\n  e: [{ name: 'email' }],\n  p: [{ name: 'phone' }],\n  z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly...\n  r: [{ name: 'repeats' }],   // TODO: this one can also be parsed properly\n  // k: [{}], // outdated thing ignored\n  t: [{\n    // t=0 0\n    name: 'timing',\n    reg: /^(\\d*) (\\d*)/,\n    names: ['start', 'stop'],\n    format: '%d %d'\n  }],\n  c: [{\n    // c=IN IP4 10.47.197.26\n    name: 'connection',\n    reg: /^IN IP(\\d) (\\S*)/,\n    names: ['version', 'ip'],\n    format: 'IN IP%d %s'\n  }],\n  b: [{\n    // b=AS:4000\n    push: 'bandwidth',\n    reg: /^(TIAS|AS|CT|RR|RS):(\\d*)/,\n    names: ['type', 'limit'],\n    format: '%s:%s'\n  }],\n  m: [{\n    // m=video 51744 RTP/AVP 126 97 98 34 31\n    // NB: special - pushes to session\n    // TODO: rtp/fmtp should be filtered by the payloads found here?\n    reg: /^(\\w*) (\\d*) ([\\w/]*)(?: (.*))?/,\n    names: ['type', 'port', 'protocol', 'payloads'],\n    format: '%s %d %s %s'\n  }],\n  a: [\n    {\n      // a=rtpmap:110 opus/48000/2\n      push: 'rtp',\n      reg: /^rtpmap:(\\d*) ([\\w\\-.]*)(?:\\s*\\/(\\d*)(?:\\s*\\/(\\S*))?)?/,\n      names: ['payload', 'codec', 'rate', 'encoding'],\n      format: function (o) {\n        return (o.encoding)\n          ? 'rtpmap:%d %s/%s/%s'\n          : o.rate\n            ? 'rtpmap:%d %s/%s'\n            : 'rtpmap:%d %s';\n      }\n    },\n    {\n      // a=fmtp:108 profile-level-id=24;object=23;bitrate=64000\n      // a=fmtp:111 minptime=10; useinbandfec=1\n      push: 'fmtp',\n      reg: /^fmtp:(\\d*) ([\\S| ]*)/,\n      names: ['payload', 'config'],\n      format: 'fmtp:%d %s'\n    },\n    {\n      // a=control:streamid=0\n      name: 'control',\n      reg: /^control:(.*)/,\n      format: 'control:%s'\n    },\n    {\n      // a=rtcp:65179 IN IP4 193.84.77.194\n      name: 'rtcp',\n      reg: /^rtcp:(\\d*)(?: (\\S*) IP(\\d) (\\S*))?/,\n      names: ['port', 'netType', 'ipVer', 'address'],\n      format: function (o) {\n        return (o.address != null)\n          ? 'rtcp:%d %s IP%d %s'\n          : 'rtcp:%d';\n      }\n    },\n    {\n      // a=rtcp-fb:98 trr-int 100\n      push: 'rtcpFbTrrInt',\n      reg: /^rtcp-fb:(\\*|\\d*) trr-int (\\d*)/,\n      names: ['payload', 'value'],\n      format: 'rtcp-fb:%s trr-int %d'\n    },\n    {\n      // a=rtcp-fb:98 nack rpsi\n      push: 'rtcpFb',\n      reg: /^rtcp-fb:(\\*|\\d*) ([\\w-_]*)(?: ([\\w-_]*))?/,\n      names: ['payload', 'type', 'subtype'],\n      format: function (o) {\n        return (o.subtype != null)\n          ? 'rtcp-fb:%s %s %s'\n          : 'rtcp-fb:%s %s';\n      }\n    },\n    {\n      // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\n      // a=extmap:1/recvonly URI-gps-string\n      // a=extmap:3 urn:ietf:params:rtp-hdrext:encrypt urn:ietf:params:rtp-hdrext:smpte-tc 25@600/24\n      push: 'ext',\n      reg: /^extmap:(\\d+)(?:\\/(\\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\\S*)(?: (\\S*))?/,\n      names: ['value', 'direction', 'encrypt-uri', 'uri', 'config'],\n      format: function (o) {\n        return (\n          'extmap:%d' +\n          (o.direction ? '/%s' : '%v') +\n          (o['encrypt-uri'] ? ' %s' : '%v') +\n          ' %s' +\n          (o.config ? ' %s' : '')\n        );\n      }\n    },\n    {\n      // a=extmap-allow-mixed\n      name: 'extmapAllowMixed',\n      reg: /^(extmap-allow-mixed)/\n    },\n    {\n      // a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32\n      push: 'crypto',\n      reg: /^crypto:(\\d*) ([\\w_]*) (\\S*)(?: (\\S*))?/,\n      names: ['id', 'suite', 'config', 'sessionConfig'],\n      format: function (o) {\n        return (o.sessionConfig != null)\n          ? 'crypto:%d %s %s %s'\n          : 'crypto:%d %s %s';\n      }\n    },\n    {\n      // a=setup:actpass\n      name: 'setup',\n      reg: /^setup:(\\w*)/,\n      format: 'setup:%s'\n    },\n    {\n      // a=connection:new\n      name: 'connectionType',\n      reg: /^connection:(new|existing)/,\n      format: 'connection:%s'\n    },\n    {\n      // a=mid:1\n      name: 'mid',\n      reg: /^mid:([^\\s]*)/,\n      format: 'mid:%s'\n    },\n    {\n      // a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a\n      name: 'msid',\n      reg: /^msid:(.*)/,\n      format: 'msid:%s'\n    },\n    {\n      // a=ptime:20\n      name: 'ptime',\n      reg: /^ptime:(\\d*(?:\\.\\d*)*)/,\n      format: 'ptime:%d'\n    },\n    {\n      // a=maxptime:60\n      name: 'maxptime',\n      reg: /^maxptime:(\\d*(?:\\.\\d*)*)/,\n      format: 'maxptime:%d'\n    },\n    {\n      // a=sendrecv\n      name: 'direction',\n      reg: /^(sendrecv|recvonly|sendonly|inactive)/\n    },\n    {\n      // a=ice-lite\n      name: 'icelite',\n      reg: /^(ice-lite)/\n    },\n    {\n      // a=ice-ufrag:F7gI\n      name: 'iceUfrag',\n      reg: /^ice-ufrag:(\\S*)/,\n      format: 'ice-ufrag:%s'\n    },\n    {\n      // a=ice-pwd:x9cml/YzichV2+XlhiMu8g\n      name: 'icePwd',\n      reg: /^ice-pwd:(\\S*)/,\n      format: 'ice-pwd:%s'\n    },\n    {\n      // a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33\n      name: 'fingerprint',\n      reg: /^fingerprint:(\\S*) (\\S*)/,\n      names: ['type', 'hash'],\n      format: 'fingerprint:%s %s'\n    },\n    {\n      // a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\n      // a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10\n      // a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0 network-id 3 network-cost 10\n      // a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10\n      // a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0 network-id 3 network-cost 10\n      push:'candidates',\n      reg: /^candidate:(\\S*) (\\d*) (\\S*) (\\d*) (\\S*) (\\d*) typ (\\S*)(?: raddr (\\S*) rport (\\d*))?(?: tcptype (\\S*))?(?: generation (\\d*))?(?: network-id (\\d*))?(?: network-cost (\\d*))?/,\n      names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation', 'network-id', 'network-cost'],\n      format: function (o) {\n        var str = 'candidate:%s %d %s %d %s %d typ %s';\n\n        str += (o.raddr != null) ? ' raddr %s rport %d' : '%v%v';\n\n        // NB: candidate has three optional chunks, so %void middles one if it's missing\n        str += (o.tcptype != null) ? ' tcptype %s' : '%v';\n\n        if (o.generation != null) {\n          str += ' generation %d';\n        }\n\n        str += (o['network-id'] != null) ? ' network-id %d' : '%v';\n        str += (o['network-cost'] != null) ? ' network-cost %d' : '%v';\n        return str;\n      }\n    },\n    {\n      // a=end-of-candidates (keep after the candidates line for readability)\n      name: 'endOfCandidates',\n      reg: /^(end-of-candidates)/\n    },\n    {\n      // a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...\n      name: 'remoteCandidates',\n      reg: /^remote-candidates:(.*)/,\n      format: 'remote-candidates:%s'\n    },\n    {\n      // a=ice-options:google-ice\n      name: 'iceOptions',\n      reg: /^ice-options:(\\S*)/,\n      format: 'ice-options:%s'\n    },\n    {\n      // a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1\n      push: 'ssrcs',\n      reg: /^ssrc:(\\d*) ([\\w_-]*)(?::(.*))?/,\n      names: ['id', 'attribute', 'value'],\n      format: function (o) {\n        var str = 'ssrc:%d';\n        if (o.attribute != null) {\n          str += ' %s';\n          if (o.value != null) {\n            str += ':%s';\n          }\n        }\n        return str;\n      }\n    },\n    {\n      // a=ssrc-group:FEC 1 2\n      // a=ssrc-group:FEC-FR 3004364195 1080772241\n      push: 'ssrcGroups',\n      // token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E\n      reg: /^ssrc-group:([\\x21\\x23\\x24\\x25\\x26\\x27\\x2A\\x2B\\x2D\\x2E\\w]*) (.*)/,\n      names: ['semantics', 'ssrcs'],\n      format: 'ssrc-group:%s %s'\n    },\n    {\n      // a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV\n      name: 'msidSemantic',\n      reg: /^msid-semantic:\\s?(\\w*) (\\S*)/,\n      names: ['semantic', 'token'],\n      format: 'msid-semantic: %s %s' // space after ':' is not accidental\n    },\n    {\n      // a=group:BUNDLE audio video\n      push: 'groups',\n      reg: /^group:(\\w*) (.*)/,\n      names: ['type', 'mids'],\n      format: 'group:%s %s'\n    },\n    {\n      // a=rtcp-mux\n      name: 'rtcpMux',\n      reg: /^(rtcp-mux)/\n    },\n    {\n      // a=rtcp-rsize\n      name: 'rtcpRsize',\n      reg: /^(rtcp-rsize)/\n    },\n    {\n      // a=sctpmap:5000 webrtc-datachannel 1024\n      name: 'sctpmap',\n      reg: /^sctpmap:([\\w_/]*) (\\S*)(?: (\\S*))?/,\n      names: ['sctpmapNumber', 'app', 'maxMessageSize'],\n      format: function (o) {\n        return (o.maxMessageSize != null)\n          ? 'sctpmap:%s %s %s'\n          : 'sctpmap:%s %s';\n      }\n    },\n    {\n      // a=x-google-flag:conference\n      name: 'xGoogleFlag',\n      reg: /^x-google-flag:([^\\s]*)/,\n      format: 'x-google-flag:%s'\n    },\n    {\n      // a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0\n      push: 'rids',\n      reg: /^rid:([\\d\\w]+) (\\w+)(?: ([\\S| ]*))?/,\n      names: ['id', 'direction', 'params'],\n      format: function (o) {\n        return (o.params) ? 'rid:%s %s %s' : 'rid:%s %s';\n      }\n    },\n    {\n      // a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]\n      // a=imageattr:* send [x=800,y=640] recv *\n      // a=imageattr:100 recv [x=320,y=240]\n      push: 'imageattrs',\n      reg: new RegExp(\n        // a=imageattr:97\n        '^imageattr:(\\\\d+|\\\\*)' +\n        // send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320]\n        '[\\\\s\\\\t]+(send|recv)[\\\\s\\\\t]+(\\\\*|\\\\[\\\\S+\\\\](?:[\\\\s\\\\t]+\\\\[\\\\S+\\\\])*)' +\n        // recv [x=330,y=250]\n        '(?:[\\\\s\\\\t]+(recv|send)[\\\\s\\\\t]+(\\\\*|\\\\[\\\\S+\\\\](?:[\\\\s\\\\t]+\\\\[\\\\S+\\\\])*))?'\n      ),\n      names: ['pt', 'dir1', 'attrs1', 'dir2', 'attrs2'],\n      format: function (o) {\n        return 'imageattr:%s %s %s' + (o.dir2 ? ' %s %s' : '');\n      }\n    },\n    {\n      // a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8\n      // a=simulcast:recv 1;4,5 send 6;7\n      name: 'simulcast',\n      reg: new RegExp(\n        // a=simulcast:\n        '^simulcast:' +\n        // send 1,2,3;~4,~5\n        '(send|recv) ([a-zA-Z0-9\\\\-_~;,]+)' +\n        // space + recv 6;~7,~8\n        '(?:\\\\s?(send|recv) ([a-zA-Z0-9\\\\-_~;,]+))?' +\n        // end\n        '$'\n      ),\n      names: ['dir1', 'list1', 'dir2', 'list2'],\n      format: function (o) {\n        return 'simulcast:%s %s' + (o.dir2 ? ' %s %s' : '');\n      }\n    },\n    {\n      // old simulcast draft 03 (implemented by Firefox)\n      //   https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03\n      // a=simulcast: recv pt=97;98 send pt=97\n      // a=simulcast: send rid=5;6;7 paused=6,7\n      name: 'simulcast_03',\n      reg: /^simulcast:[\\s\\t]+([\\S+\\s\\t]+)$/,\n      names: ['value'],\n      format: 'simulcast: %s'\n    },\n    {\n      // a=framerate:25\n      // a=framerate:29.97\n      name: 'framerate',\n      reg: /^framerate:(\\d+(?:$|\\.\\d+))/,\n      format: 'framerate:%s'\n    },\n    {\n      // RFC4570\n      // a=source-filter: incl IN IP4 239.5.2.31 10.1.15.5\n      name: 'sourceFilter',\n      reg: /^source-filter: *(excl|incl) (\\S*) (IP4|IP6|\\*) (\\S*) (.*)/,\n      names: ['filterMode', 'netType', 'addressTypes', 'destAddress', 'srcList'],\n      format: 'source-filter: %s %s %s %s %s'\n    },\n    {\n      // a=bundle-only\n      name: 'bundleOnly',\n      reg: /^(bundle-only)/\n    },\n    {\n      // a=label:1\n      name: 'label',\n      reg: /^label:(.+)/,\n      format: 'label:%s'\n    },\n    {\n      // RFC version 26 for SCTP over DTLS\n      // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-5\n      name: 'sctpPort',\n      reg: /^sctp-port:(\\d+)$/,\n      format: 'sctp-port:%s'\n    },\n    {\n      // RFC version 26 for SCTP over DTLS\n      // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6\n      name: 'maxMessageSize',\n      reg: /^max-message-size:(\\d+)$/,\n      format: 'max-message-size:%s'\n    },\n    {\n      // RFC7273\n      // a=ts-refclk:ptp=IEEE1588-2008:39-A7-94-FF-FE-07-CB-D0:37\n      push:'tsRefClocks',\n      reg: /^ts-refclk:([^\\s=]*)(?:=(\\S*))?/,\n      names: ['clksrc', 'clksrcExt'],\n      format: function (o) {\n        return 'ts-refclk:%s' + (o.clksrcExt != null ? '=%s' : '');\n      }\n    },\n    {\n      // RFC7273\n      // a=mediaclk:direct=963214424\n      name:'mediaClk',\n      reg: /^mediaclk:(?:id=(\\S*))? *([^\\s=]*)(?:=(\\S*))?(?: *rate=(\\d+)\\/(\\d+))?/,\n      names: ['id', 'mediaClockName', 'mediaClockValue', 'rateNumerator', 'rateDenominator'],\n      format: function (o) {\n        var str = 'mediaclk:';\n        str += (o.id != null ? 'id=%s %s' : '%v%s');\n        str += (o.mediaClockValue != null ? '=%s' : '');\n        str += (o.rateNumerator != null ? ' rate=%s' : '');\n        str += (o.rateDenominator != null ? '/%s' : '');\n        return str;\n      }\n    },\n    {\n      // a=keywds:keywords\n      name: 'keywords',\n      reg: /^keywds:(.+)$/,\n      format: 'keywds:%s'\n    },\n    {\n      // a=content:main\n      name: 'content',\n      reg: /^content:(.+)/,\n      format: 'content:%s'\n    },\n    // BFCP https://tools.ietf.org/html/rfc4583\n    {\n      // a=floorctrl:c-s\n      name: 'bfcpFloorCtrl',\n      reg: /^floorctrl:(c-only|s-only|c-s)/,\n      format: 'floorctrl:%s'\n    },\n    {\n      // a=confid:1\n      name: 'bfcpConfId',\n      reg: /^confid:(\\d+)/,\n      format: 'confid:%s'\n    },\n    {\n      // a=userid:1\n      name: 'bfcpUserId',\n      reg: /^userid:(\\d+)/,\n      format: 'userid:%s'\n    },\n    {\n      // a=floorid:1\n      name: 'bfcpFloorId',\n      reg: /^floorid:(.+) (?:m-stream|mstrm):(.+)/,\n      names: ['id', 'mStream'],\n      format: 'floorid:%s mstrm:%s'\n    },\n    {\n      // any a= that we don't understand is kept verbatim on media.invalid\n      push: 'invalid',\n      names: ['value']\n    }\n  ]\n};\n\n// set sensible defaults to avoid polluting the grammar with boring details\nObject.keys(grammar).forEach(function (key) {\n  var objs = grammar[key];\n  objs.forEach(function (obj) {\n    if (!obj.reg) {\n      obj.reg = /(.*)/;\n    }\n    if (!obj.format) {\n      obj.format = '%s';\n    }\n  });\n});\n","var parser = require('./parser');\nvar writer = require('./writer');\n\nexports.write = writer;\nexports.parse = parser.parse;\nexports.parseParams = parser.parseParams;\nexports.parseFmtpConfig = parser.parseFmtpConfig; // Alias of parseParams().\nexports.parsePayloads = parser.parsePayloads;\nexports.parseRemoteCandidates = parser.parseRemoteCandidates;\nexports.parseImageAttributes = parser.parseImageAttributes;\nexports.parseSimulcastStreamList = parser.parseSimulcastStreamList;\n","var toIntIfInt = function (v) {\n  return String(Number(v)) === v ? Number(v) : v;\n};\n\nvar attachProperties = function (match, location, names, rawName) {\n  if (rawName && !names) {\n    location[rawName] = toIntIfInt(match[1]);\n  }\n  else {\n    for (var i = 0; i < names.length; i += 1) {\n      if (match[i+1] != null) {\n        location[names[i]] = toIntIfInt(match[i+1]);\n      }\n    }\n  }\n};\n\nvar parseReg = function (obj, location, content) {\n  var needsBlank = obj.name && obj.names;\n  if (obj.push && !location[obj.push]) {\n    location[obj.push] = [];\n  }\n  else if (needsBlank && !location[obj.name]) {\n    location[obj.name] = {};\n  }\n  var keyLocation = obj.push ?\n    {} :  // blank object that will be pushed\n    needsBlank ? location[obj.name] : location; // otherwise, named location or root\n\n  attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);\n\n  if (obj.push) {\n    location[obj.push].push(keyLocation);\n  }\n};\n\nvar grammar = require('./grammar');\nvar validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);\n\nexports.parse = function (sdp) {\n  var session = {}\n    , media = []\n    , location = session; // points at where properties go under (one of the above)\n\n  // parse lines we understand\n  sdp.split(/(\\r\\n|\\r|\\n)/).filter(validLine).forEach(function (l) {\n    var type = l[0];\n    var content = l.slice(2);\n    if (type === 'm') {\n      media.push({rtp: [], fmtp: []});\n      location = media[media.length-1]; // point at latest media line\n    }\n\n    for (var j = 0; j < (grammar[type] || []).length; j += 1) {\n      var obj = grammar[type][j];\n      if (obj.reg.test(content)) {\n        return parseReg(obj, location, content);\n      }\n    }\n  });\n\n  session.media = media; // link it up\n  return session;\n};\n\nvar paramReducer = function (acc, expr) {\n  var s = expr.split(/=(.+)/, 2);\n  if (s.length === 2) {\n    acc[s[0]] = toIntIfInt(s[1]);\n  } else if (s.length === 1 && expr.length > 1) {\n    acc[s[0]] = undefined;\n  }\n  return acc;\n};\n\nexports.parseParams = function (str) {\n  return str.split(/;\\s?/).reduce(paramReducer, {});\n};\n\n// For backward compatibility - alias will be removed in 3.0.0\nexports.parseFmtpConfig = exports.parseParams;\n\nexports.parsePayloads = function (str) {\n  return str.toString().split(' ').map(Number);\n};\n\nexports.parseRemoteCandidates = function (str) {\n  var candidates = [];\n  var parts = str.split(' ').map(toIntIfInt);\n  for (var i = 0; i < parts.length; i += 3) {\n    candidates.push({\n      component: parts[i],\n      ip: parts[i + 1],\n      port: parts[i + 2]\n    });\n  }\n  return candidates;\n};\n\nexports.parseImageAttributes = function (str) {\n  return str.split(' ').map(function (item) {\n    return item.substring(1, item.length-1).split(',').reduce(paramReducer, {});\n  });\n};\n\nexports.parseSimulcastStreamList = function (str) {\n  return str.split(';').map(function (stream) {\n    return stream.split(',').map(function (format) {\n      var scid, paused = false;\n\n      if (format[0] !== '~') {\n        scid = toIntIfInt(format);\n      } else {\n        scid = toIntIfInt(format.substring(1, format.length));\n        paused = true;\n      }\n\n      return {\n        scid: scid,\n        paused: paused\n      };\n    });\n  });\n};\n","var grammar = require('./grammar');\n\n// customized util.format - discards excess arguments and can void middle ones\nvar formatRegExp = /%[sdv%]/g;\nvar format = function (formatStr) {\n  var i = 1;\n  var args = arguments;\n  var len = args.length;\n  return formatStr.replace(formatRegExp, function (x) {\n    if (i >= len) {\n      return x; // missing argument\n    }\n    var arg = args[i];\n    i += 1;\n    switch (x) {\n    case '%%':\n      return '%';\n    case '%s':\n      return String(arg);\n    case '%d':\n      return Number(arg);\n    case '%v':\n      return '';\n    }\n  });\n  // NB: we discard excess arguments - they are typically undefined from makeLine\n};\n\nvar makeLine = function (type, obj, location) {\n  var str = obj.format instanceof Function ?\n    (obj.format(obj.push ? location : location[obj.name])) :\n    obj.format;\n\n  var args = [type + '=' + str];\n  if (obj.names) {\n    for (var i = 0; i < obj.names.length; i += 1) {\n      var n = obj.names[i];\n      if (obj.name) {\n        args.push(location[obj.name][n]);\n      }\n      else { // for mLine and push attributes\n        args.push(location[obj.names[i]]);\n      }\n    }\n  }\n  else {\n    args.push(location[obj.name]);\n  }\n  return format.apply(null, args);\n};\n\n// RFC specified order\n// TODO: extend this with all the rest\nvar defaultOuterOrder = [\n  'v', 'o', 's', 'i',\n  'u', 'e', 'p', 'c',\n  'b', 't', 'r', 'z', 'a'\n];\nvar defaultInnerOrder = ['i', 'c', 'b', 'a'];\n\n\nmodule.exports = function (session, opts) {\n  opts = opts || {};\n  // ensure certain properties exist\n  if (session.version == null) {\n    session.version = 0; // 'v=0' must be there (only defined version atm)\n  }\n  if (session.name == null) {\n    session.name = ' '; // 's= ' must be there if no meaningful name set\n  }\n  session.media.forEach(function (mLine) {\n    if (mLine.payloads == null) {\n      mLine.payloads = '';\n    }\n  });\n\n  var outerOrder = opts.outerOrder || defaultOuterOrder;\n  var innerOrder = opts.innerOrder || defaultInnerOrder;\n  var sdp = [];\n\n  // loop through outerOrder for matching properties on session\n  outerOrder.forEach(function (type) {\n    grammar[type].forEach(function (obj) {\n      if (obj.name in session && session[obj.name] != null) {\n        sdp.push(makeLine(type, obj, session));\n      }\n      else if (obj.push in session && session[obj.push] != null) {\n        session[obj.push].forEach(function (el) {\n          sdp.push(makeLine(type, obj, el));\n        });\n      }\n    });\n  });\n\n  // then for each media line, follow the innerOrder\n  session.media.forEach(function (mLine) {\n    sdp.push(makeLine('m', grammar.m[0], mLine));\n\n    innerOrder.forEach(function (type) {\n      grammar[type].forEach(function (obj) {\n        if (obj.name in mLine && mLine[obj.name] != null) {\n          sdp.push(makeLine(type, obj, mLine));\n        }\n        else if (obj.push in mLine && mLine[obj.push] != null) {\n          mLine[obj.push].forEach(function (el) {\n            sdp.push(makeLine(type, obj, el));\n          });\n        }\n      });\n    });\n  });\n\n  return sdp.join('\\r\\n') + '\\r\\n';\n};\n","/* Copyright @ 2016 Atlassian Pty Ltd\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nvar transform = require('sdp-transform');\nvar transformUtils = require('./transform-utils');\nvar parseSsrcs = transformUtils.parseSsrcs;\nvar writeSsrcs = transformUtils.writeSsrcs;\n\n//region Constants\n\nvar DEFAULT_NUM_OF_LAYERS = 3;\n\n//endregion\n\nfunction getSsrcAttribute (mLine, ssrc, attributeName) {\n    return mLine\n        .ssrcs\n        .filter(function(ssrcInfo) { return ssrcInfo.id === ssrc; })\n        .filter(function(ssrcInfo) { return ssrcInfo.attribute === attributeName; })\n        .map(function(ssrcInfo) { return ssrcInfo.value; })[0];\n}\n\n//region Ctor\n\nfunction Simulcast(options) {\n\n    this.options = options ? options : {};\n\n    if (!this.options.numOfLayers) {\n        this.options.numOfLayers = DEFAULT_NUM_OF_LAYERS;\n    }\n    console.log(\"SdpSimulcast: using \" + this.options.numOfLayers + \" layers\");\n\n    /**\n     * An IN-ORDER list of the simulcast ssrcs\n     * @type {list<number>}\n     */\n    this.ssrcCache = [];\n}\n\n//endregion\n\n//region Stateless private utility functions\n\n/**\n * Returns a random integer between min (included) and max (excluded)\n * Using Math.round() gives a non-uniform distribution!\n * @returns {number}\n */\nfunction generateSSRC() {\n    var min = 0, max = 0xffffffff;\n    return Math.floor(Math.random() * (max - min)) + min;\n};\n\nfunction processVideo(session, action) {\n    if (session == null || !Array.isArray(session.media)) {\n        return;\n    }\n\n    session.media.forEach(function (mLine) {\n        if (mLine.type === 'video') {\n            action(mLine);\n        }\n    });\n};\n\nfunction validateDescription(desc)\n{\n    return desc && desc != null\n        && desc.type && desc.type != ''\n        && desc.sdp && desc.sdp != '';\n}\n\nfunction explodeRemoteSimulcast(mLine) {\n\n    if (!mLine || !Array.isArray(mLine.ssrcGroups)) {\n        return;\n    }\n\n    var sources = parseSsrcs(mLine);\n    var order = [];\n\n    // Find the SIM group and explode its sources.\n    var j = mLine.ssrcGroups.length;\n    while (j--) {\n\n        if (mLine.ssrcGroups[j].semantics !== 'SIM') {\n            continue;\n        }\n\n        var simulcastSsrcs = mLine.ssrcGroups[j].ssrcs.split(' ');\n\n        for (var i = 0; i < simulcastSsrcs.length; i++) {\n\n            var ssrc = simulcastSsrcs[i];\n            order.push(ssrc);\n\n            var parts = sources[ssrc].msid.split(' ');\n            sources[ssrc].msid = [parts[0], '/', i, ' ', parts[1], '/', i].join('');\n            sources[ssrc].cname = [sources[ssrc].cname, '/', i].join('');\n\n            // Remove all the groups that this SSRC participates in.\n            mLine.ssrcGroups.forEach(function (relatedGroup) {\n                if (relatedGroup.semantics === 'SIM') {\n                    return;\n                }\n\n                var relatedSsrcs = relatedGroup.ssrcs.split(' ');\n                if (relatedSsrcs.indexOf(ssrc) === -1) {\n                    return;\n                }\n\n                // Nuke all the related SSRCs.\n                relatedSsrcs.forEach(function (relatedSSRC) {\n                    sources[relatedSSRC].msid = sources[ssrc].msid;\n                    sources[relatedSSRC].cname = sources[ssrc].cname;\n                    if (relatedSSRC !== ssrc) {\n                        order.push(relatedSSRC);\n                    }\n                });\n\n                // Schedule the related group for nuking.\n            })\n        }\n\n        mLine.ssrcs = writeSsrcs(sources, order);\n        mLine.ssrcGroups.splice(j, 1);\n    };\n}\n\nfunction implodeRemoteSimulcast(mLine) {\n\n    if (!mLine || !Array.isArray(mLine.ssrcGroups)) {\n        console.info('Halt: There are no SSRC groups in the remote ' +\n                'description.');\n        return;\n    }\n\n    var sources = parseSsrcs(mLine);\n\n    // Find the SIM group and nuke it.\n    mLine.ssrcGroups.forEach(function (simulcastGroup) {\n        if (simulcastGroup.semantics !== 'SIM') {\n            return;\n        }\n\n        console.info(\"Imploding SIM group: \" + simulcastGroup.ssrcs);\n        // Schedule the SIM group for nuking.\n        simulcastGroup.nuke = true;\n\n        var simulcastSsrcs = simulcastGroup.ssrcs.split(' ');\n\n        // Nuke all the higher layer SSRCs.\n        for (var i = 1; i < simulcastSsrcs.length; i++) {\n\n            var ssrc = simulcastSsrcs[i];\n            delete sources[ssrc];\n\n            // Remove all the groups that this SSRC participates in.\n            mLine.ssrcGroups.forEach(function (relatedGroup) {\n                if (relatedGroup.semantics === 'SIM') {\n                    return;\n                }\n\n                var relatedSsrcs = relatedGroup.ssrcs.split(' ');\n                if (relatedSsrcs.indexOf(ssrc) === -1) {\n                    return;\n                }\n\n                // Nuke all the related SSRCs.\n                relatedSsrcs.forEach(function (relatedSSRC) {\n                    delete sources[relatedSSRC];\n                });\n\n                // Schedule the related group for nuking.\n                relatedGroup.nuke = true;\n            })\n        }\n\n        return;\n    });\n\n    mLine.ssrcs = writeSsrcs(sources);\n\n    // Nuke all the scheduled groups.\n    var i = mLine.ssrcGroups.length;\n    while (i--) {\n        if (mLine.ssrcGroups[i].nuke) {\n            mLine.ssrcGroups.splice(i, 1);\n        }\n    }\n}\n\nfunction removeGoogConference(mLine) {\n    if (!mLine || typeof mLine.xGoogleFlag === 'undefined') {\n        return;\n    }\n\n    mLine.xGoogleFlag = undefined;\n}\n\nfunction assertGoogConference(mLine) {\n    if (!mLine) {\n        return;\n    }\n\n    if (!Array.isArray(mLine.invalid)) {\n        mLine.invalid = [];\n    }\n\n    if (!mLine.invalid.some(\n            function (i) { return i.value === 'x-google-flag:conference' })) {\n        mLine.invalid.push({'value': 'x-google-flag:conference'});\n    }\n}\n\nSimulcast.prototype.clearSsrcCache = function() {\n    this.ssrcCache = [];\n}\n\n/**\n * When we start as video muted, all of the video\n *  ssrcs get generated so we can include them as part\n *  of the original session-accept.  That means we\n *  need this library to restore to those same ssrcs\n *  the first time we unmute, so we need the ability to\n *  force its cache\n */\nSimulcast.prototype.setSsrcCache = function(ssrcs) {\n    this.ssrcCache = ssrcs;\n}\n\n//endregion\n\n//region \"Private\" functions\n\n/**\n * Given a video mLine, return a list of the video ssrcs\n *  in simulcast layer order (returns a list of just\n *  the primary ssrc if there are no simulcast layers)\n */\nSimulcast.prototype._parseSimLayers = function (mLine) {\n    var simGroup = mLine.ssrcGroups &&\n        mLine.ssrcGroups.find(function(group) { return group.semantics === \"SIM\"; });\n    if (simGroup) {\n        return simGroup.ssrcs\n            .split(\" \")\n            .map(function(ssrcStr) { return parseInt(ssrcStr) });\n    } else {\n        return [mLine.ssrcs[0].id];\n    }\n}\n\nSimulcast.prototype._buildNewToOldSsrcMap = function (newSsrcList, oldSsrcList) {\n    var ssrcMap = {};\n    for (var i = 0; i < newSsrcList.length; ++i) {\n        var newSsrc = newSsrcList[i];\n        var oldSsrc = oldSsrcList[i] || null;\n        ssrcMap[newSsrc] = oldSsrc;\n    }\n    return ssrcMap;\n}\n\nSimulcast.prototype._fillInSourceDataFromCache = function(mLine) {\n    console.log(\"SdpSimulcast restoring from cache: \", this.ssrcCache);\n    var newSimSsrcs = this._parseSimLayers(mLine);\n    console.log(\"SdpSimulcast Parsed new sim ssrcs: \", newSimSsrcs);\n    var newMsid = getSsrcAttribute(mLine, newSimSsrcs[0], \"msid\");\n    var newCname = getSsrcAttribute(mLine, newSimSsrcs[0], \"cname\");\n    var ssrcsToReplace = this._buildNewToOldSsrcMap(newSimSsrcs, this.ssrcCache);\n    console.log(\"SdpSimulcast built replacement map: \", ssrcsToReplace);\n    // New sdp might only have 1 layer, so not every cached ssrc will have a new one\n    //  to replace directly\n    var ssrcsToAdd = this.ssrcCache\n        .filter(function(ssrc) { return Object.values(ssrcsToReplace).indexOf(ssrc) === -1; });\n    console.log(\"SdpSimulcast built ssrcs to add: \", ssrcsToAdd);\n\n    // First do the replacements\n    mLine.ssrcs.forEach(function(ssrc) {\n        if (ssrcsToReplace[ssrc.id]) {\n            ssrc.id = ssrcsToReplace[ssrc.id];\n        }\n    });\n    // Now the adds\n    ssrcsToAdd.forEach(function(ssrc) {\n        mLine.ssrcs.push({\n            id: ssrc,\n            attribute: \"msid\",\n            value: newMsid\n        });\n        mLine.ssrcs.push({\n            id: ssrc,\n            attribute: \"cname\",\n            value: newCname\n        });\n    });\n    mLine.ssrcGroups = mLine.ssrcGroups || [];\n    mLine.ssrcGroups.push({\n        semantics: \"SIM\",\n        ssrcs: this.ssrcCache.join(\" \")\n    });\n    return mLine;\n}\n\nSimulcast.prototype._generateSourceData = function(mLine, primarySsrc) {\n    var addAssociatedStream = function(mLine, ssrc) {\n        mLine.ssrcs.push({\n            id: ssrc,\n            attribute: \"cname\",\n            value: primarySsrcCname\n        });\n        mLine.ssrcs.push({\n            id: ssrc,\n            attribute: \"msid\",\n            value: primarySsrcMsid\n        });\n    }\n    var primarySsrcMsid = getSsrcAttribute(mLine, primarySsrc, \"msid\");\n    var primarySsrcCname = getSsrcAttribute(mLine, primarySsrc, \"cname\");\n\n    // In Unified-plan mode, the a=ssrc lines with the msid attribute are not present\n    // in the answers that Chrome and Safari generate for an offer received from Jicofo.\n    // Generate these a=ssrc lines using the msid values from the a=msid line.\n    if (this.options.usesUnifiedPlan && !primarySsrcMsid) {\n        primarySsrcMsid = mLine.msid;\n        var primarySsrcs = mLine.ssrcs;\n        primarySsrcs.forEach(ssrc => {\n            mLine.ssrcs.push({\n                id: ssrc.id,\n                attribute: \"msid\",\n                value: primarySsrcMsid\n            });\n        });\n    }\n\n    // Generate sim layers\n    var simSsrcs = [];\n    for (var i = 0; i < this.options.numOfLayers - 1; ++i) {\n        var simSsrc = generateSSRC();\n        addAssociatedStream(mLine, simSsrc);\n        simSsrcs.push(simSsrc);\n    }\n    mLine.ssrcGroups = mLine.ssrcGroups || [];\n    mLine.ssrcGroups.push({\n        semantics: \"SIM\",\n        ssrcs: primarySsrc + \" \" + simSsrcs.join(\" \")\n    });\n    return mLine;\n}\n\n\n\n// Assumptions:\n//  1) 'mLine' contains only a single primary video source\n//   (i.e. it will not already have simulcast streams inserted)\n//  2) 'mLine' MAY already contain an RTX stream for its video source\n//  3) 'mLine' is in sendrecv or sendonly state\n// Guarantees:\n//  1) return mLine will contain 2 additional simulcast layers\n//   generated\n//  2) if the base video ssrc in mLine has been seen before,\n//   then the same generated simulcast streams from before will\n//   be used again\n//  3) if rtx is enabled for the mLine, all generated simulcast\n//   streams will have rtx streams generated as well\n//  4) if rtx has been generated for a src before, we will generate\n//   the same rtx stream again\nSimulcast.prototype._restoreSimulcast = function(mLine) {\n    // First, find the primary video source in the given\n    // mLine and see if we've seen it before.\n    var primarySsrc;\n    var numSsrcs = mLine.ssrcs && mLine.ssrcs\n        .map(function(ssrcInfo) { return ssrcInfo.id; })\n        .filter(function(ssrc, index, array) {\n            return array.indexOf(ssrc) === index;\n        })\n        .length || 0;\n    var numGroups = (mLine.ssrcGroups && mLine.ssrcGroups.length) || 0;\n\n    if (numSsrcs === 0 || numSsrcs > 2) {\n        // Unsupported scenario\n        return mLine;\n    }\n    if (numSsrcs == 2 && numGroups === 0) {\n        // Unsupported scenario\n        return mLine;\n    }\n\n    if (numSsrcs === 1) {\n        primarySsrc = mLine.ssrcs[0].id;\n    } else {\n        // There must be an FID group, so parse\n        //  that and pull the primary ssrc from there\n        var fidGroup = mLine.ssrcGroups.filter(function(group) { return group.semantics === \"FID\"; })[0];\n        if (fidGroup) {\n            primarySsrc = parseInt(fidGroup.ssrcs.split(\" \")[0]);\n        } else {\n            // Unsupported scenario\n            return mLine;\n        }\n    }\n    console.log(\"SdpSimulcast: current ssrc cache: \", this.ssrcCache);\n    console.log(\"SdpSimulcast: parsed primary ssrc \" + primarySsrc);\n\n    var seenPrimarySsrc = this.ssrcCache.indexOf(primarySsrc) !== -1;\n\n    if (seenPrimarySsrc) {\n        console.log(\"SdpSimulcast: Have seen primary ssrc before, \" +\n            \"filling in data from cache\");\n        mLine = this._fillInSourceDataFromCache(mLine);\n    } else {\n        console.log(\"SdpSimulcast: Have not seen primary ssrc before, \" +\n            \"generating source data\");\n        mLine = this._generateSourceData(mLine, primarySsrc);\n    }\n    // Now update the cache to match whatever we've just put into this sdp\n    this.ssrcCache = this._parseSimLayers(mLine);\n    return mLine;\n}\n\n//endregion\n\n//region \"Public\" functions\n\n/**\n *\n * @param desc\n * @param enableConferenceFlag\n * @returns {RTCSessionDescription}\n */\nSimulcast.prototype.mungeRemoteDescription = function (desc, enableConferenceFlag) {\n\n    if (!validateDescription(desc)) {\n        return desc;\n    }\n\n    var session = transform.parse(desc.sdp);\n\n    var self = this;\n    processVideo(session, function (mLine) {\n\n        // Handle simulcast reception.\n        if (self.options.explodeRemoteSimulcast) {\n            explodeRemoteSimulcast(mLine);\n        } else {\n            implodeRemoteSimulcast(mLine);\n        }\n\n        // Add or remove \"x-google-conference\" from the remote description based on whether the client\n        // has enabled simulcast for the local video source. For cases where we disable simulcast for desktop share,\n        // it is necessary to remove the flag so that Chrome stops sending T1 temporal layers. It also fixes other\n        // issues related to screensharing like https://bugs.chromium.org/p/chromium/issues/detail?id=1093819.\n        if (!self.options.usesUnifiedPlan && enableConferenceFlag) {\n            assertGoogConference(mLine);\n        } else {\n            removeGoogConference(mLine);\n        }\n    });\n\n    return new RTCSessionDescription({\n        type: desc.type,\n        sdp: transform.write(session)\n    });\n};\n\n/**\n *\n * NOTE this method should be called only if simulcast is supported by\n * the current browser, otherwise local SDP should not be munged.\n * @param desc\n * @returns {RTCSessionDescription}\n */\nSimulcast.prototype.mungeLocalDescription = function (desc) {\n\n    if (!validateDescription(desc)) {\n        return desc;\n    }\n\n    var session = transform.parse(desc.sdp);\n\n    var self = this;\n    processVideo(session, function (mLine) {\n        if (mLine.direction == 'recvonly' || mLine.direction == 'inactive')\n        {\n            return;\n        }\n        self._restoreSimulcast(mLine);\n    });\n\n    return new RTCSessionDescription({\n        type: desc.type,\n        sdp: transform.write(session)\n    });\n};\n\n//endregion\n\nmodule.exports = Simulcast;\n","/* Copyright @ 2015 Atlassian Pty Ltd\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * FIXME\n * @param sources FIXME\n * @param order An array of SSRCs which will be used to order the entries in\n * the returned array. Sources whose SSRC appears in 'order' will be added first,\n * in the specified order, and all other sources will be added afterwards (in\n * no specific order).\n * @returns {Array} FIXME\n */\nexports.writeSsrcs = function(sources, order) {\n  var ssrcs = [];\n\n  // expand sources to ssrcs\n  if (typeof sources !== 'undefined' &&\n      Object.keys(sources).length !== 0) {\n\n    if (!Array.isArray(order)) {\n      order = []\n    }\n\n    // Add the sources that appear in 'order' first.\n    for (var i = 0; i < order.length; i++) {\n      var ssrc = order[i];\n      var source = sources[ssrc];\n      Object.keys(source).forEach(function (attribute) {\n        ssrcs.push({\n          id: ssrc,\n          attribute: attribute,\n          value: source[attribute]\n        });\n      });\n    }\n\n    // Now add the rest of the sources.\n    Object.keys(sources).forEach(function (ssrc) {\n      ssrc = parseInt(ssrc); // Object.keys() returns string\n      if (order.indexOf(ssrc) >= 0) {\n        // Already added.\n        return;\n      }\n\n      var source = sources[ssrc];\n      Object.keys(source).forEach(function (attribute) {\n        ssrcs.push({\n          id: ssrc,\n          attribute: attribute,\n          value: source[attribute]\n        });\n      });\n    });\n  }\n\n  return ssrcs;\n};\n\nexports.parseSsrcs = function (mLine) {\n  var sources = {};\n  // group sources attributes by ssrc.\n  if (typeof mLine.ssrcs !== 'undefined' && Array.isArray(mLine.ssrcs)) {\n    mLine.ssrcs.forEach(function (ssrc) {\n      if (!sources[ssrc.id])\n        sources[ssrc.id] = {};\n      sources[ssrc.id][ssrc.attribute] = ssrc.value;\n    });\n  }\n  return sources;\n};\n\n","'use strict'\n\nexports.byteLength = byteLength\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nfor (var i = 0, len = code.length; i < len; ++i) {\n  lookup[i] = code[i]\n  revLookup[code.charCodeAt(i)] = i\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup['-'.charCodeAt(0)] = 62\nrevLookup['_'.charCodeAt(0)] = 63\n\nfunction getLens (b64) {\n  var len = b64.length\n\n  if (len % 4 > 0) {\n    throw new Error('Invalid string. Length must be a multiple of 4')\n  }\n\n  // Trim off extra bytes after placeholder bytes are found\n  // See: https://github.com/beatgammit/base64-js/issues/42\n  var validLen = b64.indexOf('=')\n  if (validLen === -1) validLen = len\n\n  var placeHoldersLen = validLen === len\n    ? 0\n    : 4 - (validLen % 4)\n\n  return [validLen, placeHoldersLen]\n}\n\n// base64 is 4/3 + up to two characters of the original data\nfunction byteLength (b64) {\n  var lens = getLens(b64)\n  var validLen = lens[0]\n  var placeHoldersLen = lens[1]\n  return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\n}\n\nfunction _byteLength (b64, validLen, placeHoldersLen) {\n  return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\n}\n\nfunction toByteArray (b64) {\n  var tmp\n  var lens = getLens(b64)\n  var validLen = lens[0]\n  var placeHoldersLen = lens[1]\n\n  var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))\n\n  var curByte = 0\n\n  // if there are placeholders, only get up to the last complete 4 chars\n  var len = placeHoldersLen > 0\n    ? validLen - 4\n    : validLen\n\n  var i\n  for (i = 0; i < len; i += 4) {\n    tmp =\n      (revLookup[b64.charCodeAt(i)] << 18) |\n      (revLookup[b64.charCodeAt(i + 1)] << 12) |\n      (revLookup[b64.charCodeAt(i + 2)] << 6) |\n      revLookup[b64.charCodeAt(i + 3)]\n    arr[curByte++] = (tmp >> 16) & 0xFF\n    arr[curByte++] = (tmp >> 8) & 0xFF\n    arr[curByte++] = tmp & 0xFF\n  }\n\n  if (placeHoldersLen === 2) {\n    tmp =\n      (revLookup[b64.charCodeAt(i)] << 2) |\n      (revLookup[b64.charCodeAt(i + 1)] >> 4)\n    arr[curByte++] = tmp & 0xFF\n  }\n\n  if (placeHoldersLen === 1) {\n    tmp =\n      (revLookup[b64.charCodeAt(i)] << 10) |\n      (revLookup[b64.charCodeAt(i + 1)] << 4) |\n      (revLookup[b64.charCodeAt(i + 2)] >> 2)\n    arr[curByte++] = (tmp >> 8) & 0xFF\n    arr[curByte++] = tmp & 0xFF\n  }\n\n  return arr\n}\n\nfunction tripletToBase64 (num) {\n  return lookup[num >> 18 & 0x3F] +\n    lookup[num >> 12 & 0x3F] +\n    lookup[num >> 6 & 0x3F] +\n    lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n  var tmp\n  var output = []\n  for (var i = start; i < end; i += 3) {\n    tmp =\n      ((uint8[i] << 16) & 0xFF0000) +\n      ((uint8[i + 1] << 8) & 0xFF00) +\n      (uint8[i + 2] & 0xFF)\n    output.push(tripletToBase64(tmp))\n  }\n  return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n  var tmp\n  var len = uint8.length\n  var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n  var parts = []\n  var maxChunkLength = 16383 // must be multiple of 3\n\n  // go through the array every three bytes, we'll deal with trailing stuff later\n  for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n    parts.push(encodeChunk(\n      uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)\n    ))\n  }\n\n  // pad the end with zeros, but make sure to not forget the extra bytes\n  if (extraBytes === 1) {\n    tmp = uint8[len - 1]\n    parts.push(\n      lookup[tmp >> 2] +\n      lookup[(tmp << 4) & 0x3F] +\n      '=='\n    )\n  } else if (extraBytes === 2) {\n    tmp = (uint8[len - 2] << 8) + uint8[len - 1]\n    parts.push(\n      lookup[tmp >> 10] +\n      lookup[(tmp >> 4) & 0x3F] +\n      lookup[(tmp << 2) & 0x3F] +\n      '='\n    )\n  }\n\n  return parts.join('')\n}\n","!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define([],t):\"object\"==typeof exports?exports.bowser=t():e.bowser=t()}(this,(function(){return function(e){var t={};function r(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=e,r.c=t,r.d=function(e,t,i){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},r.r=function(e){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&\"object\"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(r.r(i),Object.defineProperty(i,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var n in e)r.d(i,n,function(t){return e[t]}.bind(null,n));return i},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,\"a\",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p=\"\",r(r.s=90)}({17:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i=r(18),n=function(){function e(){}return e.getFirstMatch=function(e,t){var r=t.match(e);return r&&r.length>0&&r[1]||\"\"},e.getSecondMatch=function(e,t){var r=t.match(e);return r&&r.length>1&&r[2]||\"\"},e.matchAndReturnConst=function(e,t,r){if(e.test(t))return r},e.getWindowsVersionName=function(e){switch(e){case\"NT\":return\"NT\";case\"XP\":return\"XP\";case\"NT 5.0\":return\"2000\";case\"NT 5.1\":return\"XP\";case\"NT 5.2\":return\"2003\";case\"NT 6.0\":return\"Vista\";case\"NT 6.1\":return\"7\";case\"NT 6.2\":return\"8\";case\"NT 6.3\":return\"8.1\";case\"NT 10.0\":return\"10\";default:return}},e.getMacOSVersionName=function(e){var t=e.split(\".\").splice(0,2).map((function(e){return parseInt(e,10)||0}));if(t.push(0),10===t[0])switch(t[1]){case 5:return\"Leopard\";case 6:return\"Snow Leopard\";case 7:return\"Lion\";case 8:return\"Mountain Lion\";case 9:return\"Mavericks\";case 10:return\"Yosemite\";case 11:return\"El Capitan\";case 12:return\"Sierra\";case 13:return\"High Sierra\";case 14:return\"Mojave\";case 15:return\"Catalina\";default:return}},e.getAndroidVersionName=function(e){var t=e.split(\".\").splice(0,2).map((function(e){return parseInt(e,10)||0}));if(t.push(0),!(1===t[0]&&t[1]<5))return 1===t[0]&&t[1]<6?\"Cupcake\":1===t[0]&&t[1]>=6?\"Donut\":2===t[0]&&t[1]<2?\"Eclair\":2===t[0]&&2===t[1]?\"Froyo\":2===t[0]&&t[1]>2?\"Gingerbread\":3===t[0]?\"Honeycomb\":4===t[0]&&t[1]<1?\"Ice Cream Sandwich\":4===t[0]&&t[1]<4?\"Jelly Bean\":4===t[0]&&t[1]>=4?\"KitKat\":5===t[0]?\"Lollipop\":6===t[0]?\"Marshmallow\":7===t[0]?\"Nougat\":8===t[0]?\"Oreo\":9===t[0]?\"Pie\":void 0},e.getVersionPrecision=function(e){return e.split(\".\").length},e.compareVersions=function(t,r,i){void 0===i&&(i=!1);var n=e.getVersionPrecision(t),s=e.getVersionPrecision(r),o=Math.max(n,s),a=0,u=e.map([t,r],(function(t){var r=o-e.getVersionPrecision(t),i=t+new Array(r+1).join(\".0\");return e.map(i.split(\".\"),(function(e){return new Array(20-e.length).join(\"0\")+e})).reverse()}));for(i&&(a=o-Math.min(n,s)),o-=1;o>=a;){if(u[0][o]>u[1][o])return 1;if(u[0][o]===u[1][o]){if(o===a)return 0;o-=1}else if(u[0][o]<u[1][o])return-1}},e.map=function(e,t){var r,i=[];if(Array.prototype.map)return Array.prototype.map.call(e,t);for(r=0;r<e.length;r+=1)i.push(t(e[r]));return i},e.getBrowserAlias=function(e){return i.BROWSER_ALIASES_MAP[e]},e.getBrowserTypeByAlias=function(e){return i.BROWSER_MAP[e]||\"\"},e}();t.default=n,e.exports=t.default},18:function(e,t,r){\"use strict\";t.__esModule=!0,t.ENGINE_MAP=t.OS_MAP=t.PLATFORMS_MAP=t.BROWSER_MAP=t.BROWSER_ALIASES_MAP=void 0;t.BROWSER_ALIASES_MAP={\"Amazon Silk\":\"amazon_silk\",\"Android Browser\":\"android\",Bada:\"bada\",BlackBerry:\"blackberry\",Chrome:\"chrome\",Chromium:\"chromium\",Epiphany:\"epiphany\",Firefox:\"firefox\",Focus:\"focus\",Generic:\"generic\",\"Google Search\":\"google_search\",Googlebot:\"googlebot\",\"Internet Explorer\":\"ie\",\"K-Meleon\":\"k_meleon\",Maxthon:\"maxthon\",\"Microsoft Edge\":\"edge\",\"MZ Browser\":\"mz\",\"NAVER Whale Browser\":\"naver\",Opera:\"opera\",\"Opera Coast\":\"opera_coast\",PhantomJS:\"phantomjs\",Puffin:\"puffin\",QupZilla:\"qupzilla\",QQ:\"qq\",QQLite:\"qqlite\",Safari:\"safari\",Sailfish:\"sailfish\",\"Samsung Internet for Android\":\"samsung_internet\",SeaMonkey:\"seamonkey\",Sleipnir:\"sleipnir\",Swing:\"swing\",Tizen:\"tizen\",\"UC Browser\":\"uc\",Vivaldi:\"vivaldi\",\"WebOS Browser\":\"webos\",WeChat:\"wechat\",\"Yandex Browser\":\"yandex\",Roku:\"roku\"};t.BROWSER_MAP={amazon_silk:\"Amazon Silk\",android:\"Android Browser\",bada:\"Bada\",blackberry:\"BlackBerry\",chrome:\"Chrome\",chromium:\"Chromium\",epiphany:\"Epiphany\",firefox:\"Firefox\",focus:\"Focus\",generic:\"Generic\",googlebot:\"Googlebot\",google_search:\"Google Search\",ie:\"Internet Explorer\",k_meleon:\"K-Meleon\",maxthon:\"Maxthon\",edge:\"Microsoft Edge\",mz:\"MZ Browser\",naver:\"NAVER Whale Browser\",opera:\"Opera\",opera_coast:\"Opera Coast\",phantomjs:\"PhantomJS\",puffin:\"Puffin\",qupzilla:\"QupZilla\",qq:\"QQ Browser\",qqlite:\"QQ Browser Lite\",safari:\"Safari\",sailfish:\"Sailfish\",samsung_internet:\"Samsung Internet for Android\",seamonkey:\"SeaMonkey\",sleipnir:\"Sleipnir\",swing:\"Swing\",tizen:\"Tizen\",uc:\"UC Browser\",vivaldi:\"Vivaldi\",webos:\"WebOS Browser\",wechat:\"WeChat\",yandex:\"Yandex Browser\"};t.PLATFORMS_MAP={tablet:\"tablet\",mobile:\"mobile\",desktop:\"desktop\",tv:\"tv\"};t.OS_MAP={WindowsPhone:\"Windows Phone\",Windows:\"Windows\",MacOS:\"macOS\",iOS:\"iOS\",Android:\"Android\",WebOS:\"WebOS\",BlackBerry:\"BlackBerry\",Bada:\"Bada\",Tizen:\"Tizen\",Linux:\"Linux\",ChromeOS:\"Chrome OS\",PlayStation4:\"PlayStation 4\",Roku:\"Roku\"};t.ENGINE_MAP={EdgeHTML:\"EdgeHTML\",Blink:\"Blink\",Trident:\"Trident\",Presto:\"Presto\",Gecko:\"Gecko\",WebKit:\"WebKit\"}},90:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i,n=(i=r(91))&&i.__esModule?i:{default:i},s=r(18);function o(e,t){for(var r=0;r<t.length;r++){var i=t[r];i.enumerable=i.enumerable||!1,i.configurable=!0,\"value\"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}var a=function(){function e(){}var t,r,i;return e.getParser=function(e,t){if(void 0===t&&(t=!1),\"string\"!=typeof e)throw new Error(\"UserAgent should be a string\");return new n.default(e,t)},e.parse=function(e){return new n.default(e).getResult()},t=e,i=[{key:\"BROWSER_MAP\",get:function(){return s.BROWSER_MAP}},{key:\"ENGINE_MAP\",get:function(){return s.ENGINE_MAP}},{key:\"OS_MAP\",get:function(){return s.OS_MAP}},{key:\"PLATFORMS_MAP\",get:function(){return s.PLATFORMS_MAP}}],(r=null)&&o(t.prototype,r),i&&o(t,i),e}();t.default=a,e.exports=t.default},91:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i=u(r(92)),n=u(r(93)),s=u(r(94)),o=u(r(95)),a=u(r(17));function u(e){return e&&e.__esModule?e:{default:e}}var d=function(){function e(e,t){if(void 0===t&&(t=!1),null==e||\"\"===e)throw new Error(\"UserAgent parameter can't be empty\");this._ua=e,this.parsedResult={},!0!==t&&this.parse()}var t=e.prototype;return t.getUA=function(){return this._ua},t.test=function(e){return e.test(this._ua)},t.parseBrowser=function(){var e=this;this.parsedResult.browser={};var t=i.default.find((function(t){if(\"function\"==typeof t.test)return t.test(e);if(t.test instanceof Array)return t.test.some((function(t){return e.test(t)}));throw new Error(\"Browser's test function is not valid\")}));return t&&(this.parsedResult.browser=t.describe(this.getUA())),this.parsedResult.browser},t.getBrowser=function(){return this.parsedResult.browser?this.parsedResult.browser:this.parseBrowser()},t.getBrowserName=function(e){return e?String(this.getBrowser().name).toLowerCase()||\"\":this.getBrowser().name||\"\"},t.getBrowserVersion=function(){return this.getBrowser().version},t.getOS=function(){return this.parsedResult.os?this.parsedResult.os:this.parseOS()},t.parseOS=function(){var e=this;this.parsedResult.os={};var t=n.default.find((function(t){if(\"function\"==typeof t.test)return t.test(e);if(t.test instanceof Array)return t.test.some((function(t){return e.test(t)}));throw new Error(\"Browser's test function is not valid\")}));return t&&(this.parsedResult.os=t.describe(this.getUA())),this.parsedResult.os},t.getOSName=function(e){var t=this.getOS().name;return e?String(t).toLowerCase()||\"\":t||\"\"},t.getOSVersion=function(){return this.getOS().version},t.getPlatform=function(){return this.parsedResult.platform?this.parsedResult.platform:this.parsePlatform()},t.getPlatformType=function(e){void 0===e&&(e=!1);var t=this.getPlatform().type;return e?String(t).toLowerCase()||\"\":t||\"\"},t.parsePlatform=function(){var e=this;this.parsedResult.platform={};var t=s.default.find((function(t){if(\"function\"==typeof t.test)return t.test(e);if(t.test instanceof Array)return t.test.some((function(t){return e.test(t)}));throw new Error(\"Browser's test function is not valid\")}));return t&&(this.parsedResult.platform=t.describe(this.getUA())),this.parsedResult.platform},t.getEngine=function(){return this.parsedResult.engine?this.parsedResult.engine:this.parseEngine()},t.getEngineName=function(e){return e?String(this.getEngine().name).toLowerCase()||\"\":this.getEngine().name||\"\"},t.parseEngine=function(){var e=this;this.parsedResult.engine={};var t=o.default.find((function(t){if(\"function\"==typeof t.test)return t.test(e);if(t.test instanceof Array)return t.test.some((function(t){return e.test(t)}));throw new Error(\"Browser's test function is not valid\")}));return t&&(this.parsedResult.engine=t.describe(this.getUA())),this.parsedResult.engine},t.parse=function(){return this.parseBrowser(),this.parseOS(),this.parsePlatform(),this.parseEngine(),this},t.getResult=function(){return Object.assign({},this.parsedResult)},t.satisfies=function(e){var t=this,r={},i=0,n={},s=0;if(Object.keys(e).forEach((function(t){var o=e[t];\"string\"==typeof o?(n[t]=o,s+=1):\"object\"==typeof o&&(r[t]=o,i+=1)})),i>0){var o=Object.keys(r),a=o.find((function(e){return t.isOS(e)}));if(a){var u=this.satisfies(r[a]);if(void 0!==u)return u}var d=o.find((function(e){return t.isPlatform(e)}));if(d){var c=this.satisfies(r[d]);if(void 0!==c)return c}}if(s>0){var f=Object.keys(n).find((function(e){return t.isBrowser(e,!0)}));if(void 0!==f)return this.compareVersion(n[f])}},t.isBrowser=function(e,t){void 0===t&&(t=!1);var r=this.getBrowserName().toLowerCase(),i=e.toLowerCase(),n=a.default.getBrowserTypeByAlias(i);return t&&n&&(i=n.toLowerCase()),i===r},t.compareVersion=function(e){var t=[0],r=e,i=!1,n=this.getBrowserVersion();if(\"string\"==typeof n)return\">\"===e[0]||\"<\"===e[0]?(r=e.substr(1),\"=\"===e[1]?(i=!0,r=e.substr(2)):t=[],\">\"===e[0]?t.push(1):t.push(-1)):\"=\"===e[0]?r=e.substr(1):\"~\"===e[0]&&(i=!0,r=e.substr(1)),t.indexOf(a.default.compareVersions(n,r,i))>-1},t.isOS=function(e){return this.getOSName(!0)===String(e).toLowerCase()},t.isPlatform=function(e){return this.getPlatformType(!0)===String(e).toLowerCase()},t.isEngine=function(e){return this.getEngineName(!0)===String(e).toLowerCase()},t.is=function(e){return this.isBrowser(e)||this.isOS(e)||this.isPlatform(e)},t.some=function(e){var t=this;return void 0===e&&(e=[]),e.some((function(e){return t.is(e)}))},e}();t.default=d,e.exports=t.default},92:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i};var s=/version\\/(\\d+(\\.?_?\\d+)+)/i,o=[{test:[/googlebot/i],describe:function(e){var t={name:\"Googlebot\"},r=n.default.getFirstMatch(/googlebot\\/(\\d+(\\.\\d+))/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/opera/i],describe:function(e){var t={name:\"Opera\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:opera)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/opr\\/|opios/i],describe:function(e){var t={name:\"Opera\"},r=n.default.getFirstMatch(/(?:opr|opios)[\\s/](\\S+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/SamsungBrowser/i],describe:function(e){var t={name:\"Samsung Internet for Android\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:SamsungBrowser)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/Whale/i],describe:function(e){var t={name:\"NAVER Whale Browser\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:whale)[\\s/](\\d+(?:\\.\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/MZBrowser/i],describe:function(e){var t={name:\"MZ Browser\"},r=n.default.getFirstMatch(/(?:MZBrowser)[\\s/](\\d+(?:\\.\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/focus/i],describe:function(e){var t={name:\"Focus\"},r=n.default.getFirstMatch(/(?:focus)[\\s/](\\d+(?:\\.\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/swing/i],describe:function(e){var t={name:\"Swing\"},r=n.default.getFirstMatch(/(?:swing)[\\s/](\\d+(?:\\.\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/coast/i],describe:function(e){var t={name:\"Opera Coast\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:coast)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/yabrowser/i],describe:function(e){var t={name:\"Yandex Browser\"},r=n.default.getFirstMatch(/(?:yabrowser)[\\s/](\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/ucbrowser/i],describe:function(e){var t={name:\"UC Browser\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:ucbrowser)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/Maxthon|mxios/i],describe:function(e){var t={name:\"Maxthon\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:Maxthon|mxios)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/epiphany/i],describe:function(e){var t={name:\"Epiphany\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:epiphany)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/puffin/i],describe:function(e){var t={name:\"Puffin\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:puffin)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/sleipnir/i],describe:function(e){var t={name:\"Sleipnir\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:sleipnir)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/k-meleon/i],describe:function(e){var t={name:\"K-Meleon\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:k-meleon)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/micromessenger/i],describe:function(e){var t={name:\"WeChat\"},r=n.default.getFirstMatch(/(?:micromessenger)[\\s/](\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/qqbrowser/i],describe:function(e){var t={name:/qqbrowserlite/i.test(e)?\"QQ Browser Lite\":\"QQ Browser\"},r=n.default.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/msie|trident/i],describe:function(e){var t={name:\"Internet Explorer\"},r=n.default.getFirstMatch(/(?:msie |rv:)(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/\\sedg\\//i],describe:function(e){var t={name:\"Microsoft Edge\"},r=n.default.getFirstMatch(/\\sedg\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/edg([ea]|ios)/i],describe:function(e){var t={name:\"Microsoft Edge\"},r=n.default.getSecondMatch(/edg([ea]|ios)\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/vivaldi/i],describe:function(e){var t={name:\"Vivaldi\"},r=n.default.getFirstMatch(/vivaldi\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/seamonkey/i],describe:function(e){var t={name:\"SeaMonkey\"},r=n.default.getFirstMatch(/seamonkey\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/sailfish/i],describe:function(e){var t={name:\"Sailfish\"},r=n.default.getFirstMatch(/sailfish\\s?browser\\/(\\d+(\\.\\d+)?)/i,e);return r&&(t.version=r),t}},{test:[/silk/i],describe:function(e){var t={name:\"Amazon Silk\"},r=n.default.getFirstMatch(/silk\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/phantom/i],describe:function(e){var t={name:\"PhantomJS\"},r=n.default.getFirstMatch(/phantomjs\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/slimerjs/i],describe:function(e){var t={name:\"SlimerJS\"},r=n.default.getFirstMatch(/slimerjs\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/blackberry|\\bbb\\d+/i,/rim\\stablet/i],describe:function(e){var t={name:\"BlackBerry\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/blackberry[\\d]+\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t={name:\"WebOS Browser\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/w(?:eb)?[o0]sbrowser\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/bada/i],describe:function(e){var t={name:\"Bada\"},r=n.default.getFirstMatch(/dolfin\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/tizen/i],describe:function(e){var t={name:\"Tizen\"},r=n.default.getFirstMatch(/(?:tizen\\s?)?browser\\/(\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/qupzilla/i],describe:function(e){var t={name:\"QupZilla\"},r=n.default.getFirstMatch(/(?:qupzilla)[\\s/](\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/firefox|iceweasel|fxios/i],describe:function(e){var t={name:\"Firefox\"},r=n.default.getFirstMatch(/(?:firefox|iceweasel|fxios)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/chromium/i],describe:function(e){var t={name:\"Chromium\"},r=n.default.getFirstMatch(/(?:chromium)[\\s/](\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/chrome|crios|crmo/i],describe:function(e){var t={name:\"Chrome\"},r=n.default.getFirstMatch(/(?:chrome|crios|crmo)\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/GSA/i],describe:function(e){var t={name:\"Google Search\"},r=n.default.getFirstMatch(/(?:GSA)\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){var t=!e.test(/like android/i),r=e.test(/android/i);return t&&r},describe:function(e){var t={name:\"Android Browser\"},r=n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/playstation 4/i],describe:function(e){var t={name:\"PlayStation 4\"},r=n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/safari|applewebkit/i],describe:function(e){var t={name:\"Safari\"},r=n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/.*/i],describe:function(e){var t=-1!==e.search(\"\\\\(\")?/^(.*)\\/(.*)[ \\t]\\((.*)/:/^(.*)\\/(.*) /;return{name:n.default.getFirstMatch(t,e),version:n.default.getSecondMatch(t,e)}}}];t.default=o,e.exports=t.default},93:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i},s=r(18);var o=[{test:[/Roku\\/DVP/],describe:function(e){var t=n.default.getFirstMatch(/Roku\\/DVP-(\\d+\\.\\d+)/i,e);return{name:s.OS_MAP.Roku,version:t}}},{test:[/windows phone/i],describe:function(e){var t=n.default.getFirstMatch(/windows phone (?:os)?\\s?(\\d+(\\.\\d+)*)/i,e);return{name:s.OS_MAP.WindowsPhone,version:t}}},{test:[/windows/i],describe:function(e){var t=n.default.getFirstMatch(/Windows ((NT|XP)( \\d\\d?.\\d)?)/i,e),r=n.default.getWindowsVersionName(t);return{name:s.OS_MAP.Windows,version:t,versionName:r}}},{test:[/macintosh/i],describe:function(e){var t=n.default.getFirstMatch(/mac os x (\\d+(\\.?_?\\d+)+)/i,e).replace(/[_\\s]/g,\".\"),r=n.default.getMacOSVersionName(t),i={name:s.OS_MAP.MacOS,version:t};return r&&(i.versionName=r),i}},{test:[/(ipod|iphone|ipad)/i],describe:function(e){var t=n.default.getFirstMatch(/os (\\d+([_\\s]\\d+)*) like mac os x/i,e).replace(/[_\\s]/g,\".\");return{name:s.OS_MAP.iOS,version:t}}},{test:function(e){var t=!e.test(/like android/i),r=e.test(/android/i);return t&&r},describe:function(e){var t=n.default.getFirstMatch(/android[\\s/-](\\d+(\\.\\d+)*)/i,e),r=n.default.getAndroidVersionName(t),i={name:s.OS_MAP.Android,version:t};return r&&(i.versionName=r),i}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t=n.default.getFirstMatch(/(?:web|hpw)[o0]s\\/(\\d+(\\.\\d+)*)/i,e),r={name:s.OS_MAP.WebOS};return t&&t.length&&(r.version=t),r}},{test:[/blackberry|\\bbb\\d+/i,/rim\\stablet/i],describe:function(e){var t=n.default.getFirstMatch(/rim\\stablet\\sos\\s(\\d+(\\.\\d+)*)/i,e)||n.default.getFirstMatch(/blackberry\\d+\\/(\\d+([_\\s]\\d+)*)/i,e)||n.default.getFirstMatch(/\\bbb(\\d+)/i,e);return{name:s.OS_MAP.BlackBerry,version:t}}},{test:[/bada/i],describe:function(e){var t=n.default.getFirstMatch(/bada\\/(\\d+(\\.\\d+)*)/i,e);return{name:s.OS_MAP.Bada,version:t}}},{test:[/tizen/i],describe:function(e){var t=n.default.getFirstMatch(/tizen[/\\s](\\d+(\\.\\d+)*)/i,e);return{name:s.OS_MAP.Tizen,version:t}}},{test:[/linux/i],describe:function(){return{name:s.OS_MAP.Linux}}},{test:[/CrOS/],describe:function(){return{name:s.OS_MAP.ChromeOS}}},{test:[/PlayStation 4/],describe:function(e){var t=n.default.getFirstMatch(/PlayStation 4[/\\s](\\d+(\\.\\d+)*)/i,e);return{name:s.OS_MAP.PlayStation4,version:t}}}];t.default=o,e.exports=t.default},94:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i},s=r(18);var o=[{test:[/googlebot/i],describe:function(){return{type:\"bot\",vendor:\"Google\"}}},{test:[/huawei/i],describe:function(e){var t=n.default.getFirstMatch(/(can-l01)/i,e)&&\"Nova\",r={type:s.PLATFORMS_MAP.mobile,vendor:\"Huawei\"};return t&&(r.model=t),r}},{test:[/nexus\\s*(?:7|8|9|10).*/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:\"Nexus\"}}},{test:[/ipad/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:\"Apple\",model:\"iPad\"}}},{test:[/kftt build/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:\"Amazon\",model:\"Kindle Fire HD 7\"}}},{test:[/silk/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:\"Amazon\"}}},{test:[/tablet(?! pc)/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet}}},{test:function(e){var t=e.test(/ipod|iphone/i),r=e.test(/like (ipod|iphone)/i);return t&&!r},describe:function(e){var t=n.default.getFirstMatch(/(ipod|iphone)/i,e);return{type:s.PLATFORMS_MAP.mobile,vendor:\"Apple\",model:t}}},{test:[/nexus\\s*[0-6].*/i,/galaxy nexus/i],describe:function(){return{type:s.PLATFORMS_MAP.mobile,vendor:\"Nexus\"}}},{test:[/[^-]mobi/i],describe:function(){return{type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return\"blackberry\"===e.getBrowserName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.mobile,vendor:\"BlackBerry\"}}},{test:function(e){return\"bada\"===e.getBrowserName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return\"windows phone\"===e.getBrowserName()},describe:function(){return{type:s.PLATFORMS_MAP.mobile,vendor:\"Microsoft\"}}},{test:function(e){var t=Number(String(e.getOSVersion()).split(\".\")[0]);return\"android\"===e.getOSName(!0)&&t>=3},describe:function(){return{type:s.PLATFORMS_MAP.tablet}}},{test:function(e){return\"android\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return\"macos\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.desktop,vendor:\"Apple\"}}},{test:function(e){return\"windows\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.desktop}}},{test:function(e){return\"linux\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.desktop}}},{test:function(e){return\"playstation 4\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.tv}}},{test:function(e){return\"roku\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.tv}}}];t.default=o,e.exports=t.default},95:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i},s=r(18);var o=[{test:function(e){return\"microsoft edge\"===e.getBrowserName(!0)},describe:function(e){if(/\\sedg\\//i.test(e))return{name:s.ENGINE_MAP.Blink};var t=n.default.getFirstMatch(/edge\\/(\\d+(\\.?_?\\d+)+)/i,e);return{name:s.ENGINE_MAP.EdgeHTML,version:t}}},{test:[/trident/i],describe:function(e){var t={name:s.ENGINE_MAP.Trident},r=n.default.getFirstMatch(/trident\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){return e.test(/presto/i)},describe:function(e){var t={name:s.ENGINE_MAP.Presto},r=n.default.getFirstMatch(/presto\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){var t=e.test(/gecko/i),r=e.test(/like gecko/i);return t&&!r},describe:function(e){var t={name:s.ENGINE_MAP.Gecko},r=n.default.getFirstMatch(/gecko\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/(apple)?webkit\\/537\\.36/i],describe:function(){return{name:s.ENGINE_MAP.Blink}}},{test:[/(apple)?webkit/i],describe:function(e){var t={name:s.ENGINE_MAP.WebKit},r=n.default.getFirstMatch(/webkit\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}}];t.default=o,e.exports=t.default}})}));","/*!\n * currentExecutingScript\n * Get the currently executing script, regardless of its source/trigger/synchronicity. Similar to HTML5's `document.currentScript` but arguably much more useful!\n * Copyright (c) 2015 James M. Greene\n * Licensed MIT\n * https://github.com/JamesMGreene/currentExecutingScript\n * v0.1.3\n */\n(function(root, factory) {\n  if (typeof define === \"function\" && define.amd) {\n    // AMD. Register as an anonymous module.\n    define([], factory);\n  } else if (typeof exports === \"object\") {\n    // CommonJS-like environments that support `module.exports`,\n    // like Node.js. Does not work with strict CommonJS!\n    module.exports = factory();\n  } else {\n    // Browser globals (`root` is `window`)\n    root.currentExecutingScript = factory();\n  }\n}(\n  // Current context/scope\n  this || window,\n\n  // Factory function to return the export\n  function() {\n\nvar scriptReadyRegex = /^(interactive|loaded|complete)$/;\n\n// This page's URL (minus query string and fragment identifer hash, if any)\nvar fullPageUrl = !!window.location ? window.location.href : null;\nvar pageUrl = fullPageUrl ? fullPageUrl.replace(/#.*$/, \"\").replace(/\\?.*$/, \"\") || null : null;\n\n// Live NodeList collection\nvar scripts = document.getElementsByTagName(\"script\");\n\n// Check if the browser supports the `readyState` property on `script` elements\nvar supportsScriptReadyState = \"readyState\" in (scripts[0] || document.createElement(\"script\"));\n\n// Lousy browser detection for [not] Opera\nvar isNotOpera = !window.opera || window.opera.toString() !== \"[object Opera]\";\n\n// Detect if `document.currentScript` is supported\nvar hasNativeCurrentScriptAccessor = \"currentScript\" in document;\n\nvar originalStackDepthConfig;\n// Detect if the V8 Error Stack Trace API is supported\nif (\"stackTraceLimit\" in Error && Error.stackTraceLimit !== Infinity) {\n  originalStackDepthConfig = Error.stackTraceLimit;\n  Error.stackTraceLimit = Infinity;\n}\n\n\n// In some browsers (e.g. Chrome), you can get the current stack from an Error\n// object instance without needing to throw it. Avoiding an unnecessary\n// use of `throw` saves time and performance.\nvar hasStackBeforeThrowing = false,\n    hasStackAfterThrowing = false;\n(function() {\n  try {\n    var err = new Error();\n    hasStackBeforeThrowing = typeof err.stack === \"string\" && !!err.stack;\n    throw err;\n  }\n  catch (thrownErr) {\n    hasStackAfterThrowing = typeof thrownErr.stack === \"string\" && !!thrownErr.stack;\n  }\n})();\n\n\n// Normalize whitespace within a string\nfunction normalizeWhitespace(str) {\n  return str ? str.replace(/^\\s+$|\\s+$/g, \"\").replace(/\\s\\s+/g, \" \") : \"\";\n}\n\n// Get script object based on the `src` URL\nfunction getScriptFromUrl(url, eligibleScripts) {\n  var i,\n      script = null;\n\n  eligibleScripts = eligibleScripts || scripts;\n\n  if (typeof url === \"string\" && url) {\n    for (i = eligibleScripts.length; i--; ) {\n      if (eligibleScripts[i].src === url) {\n        // NOTE: Could check if the same script URL is used by more than one `script` element\n        // here... but let's not. That would yield less useful results in \"loose\" detection. ;)\n        script = eligibleScripts[i];\n        break;\n      }\n    }\n  }\n  return script;\n}\n\n// Get script object based on the caller function's source code body (text)\nfunction getInlineScriptFromCallerSource(callerFnSource, eligibleScripts) {\n  var i, inlineScriptText,\n      script = null,\n      callerSourceText = normalizeWhitespace(callerFnSource);\n\n  eligibleScripts = eligibleScripts || scripts;\n\n  if (callerFnSource && callerSourceText) {\n    for (i = eligibleScripts.length; i--; ) {\n      // Only look at inline scripts\n      if (!eligibleScripts[i].hasAttribute(\"src\")) {\n        inlineScriptText = normalizeWhitespace(eligibleScripts[i].text);\n        if (inlineScriptText.indexOf(callerSourceText) !== -1) {\n          // If more than one match is found, don't return any\n          if (script) {\n            script = null;\n            break;\n          }\n          script = eligibleScripts[i];\n        }\n      }\n    }\n  }\n\n  return script;\n}\n\n// If there is only a single inline script on the page, return it; otherwise `null`\nfunction getSoleInlineScript(eligibleScripts) {\n  var i, len,\n      script = null;\n  eligibleScripts = eligibleScripts || scripts;\n  for (i = 0, len = eligibleScripts.length; i < len; i++) {\n    if (!eligibleScripts[i].hasAttribute(\"src\")) {\n      if (script) {\n        script = null;\n        break;\n      }\n      script = eligibleScripts[i];\n    }\n  }\n  return script;\n}\n\n// Get the currently executing script URL from an Error stack trace\nfunction getScriptUrlFromStack(stack, skipStackDepth) {\n  var matches, remainingStack,\n      url = null,\n      ignoreMessage = typeof skipStackDepth === \"number\";\n  skipStackDepth = ignoreMessage ? Math.round(skipStackDepth) : 0;\n  if (typeof stack === \"string\" && stack) {\n    if (ignoreMessage) {\n      matches = stack.match(/(data:text\\/javascript(?:;[^,]+)?,.+?|(?:|blob:)(?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?/);\n    }\n    else {\n      matches = stack.match(/^(?:|[^:@]*@|.+\\)@(?=data:text\\/javascript|blob|http[s]?|file)|.+?\\s+(?: at |@)(?:[^:\\(]+ )*[\\(]?)(data:text\\/javascript(?:;[^,]+)?,.+?|(?:|blob:)(?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?/);\n\n      if (!(matches && matches[1])) {\n        matches = stack.match(/\\)@(data:text\\/javascript(?:;[^,]+)?,.+?|(?:|blob:)(?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?/);\n      }\n    }\n\n    if (matches && matches[1]) {\n      if (skipStackDepth > 0) {\n        remainingStack = stack.slice(stack.indexOf(matches[0]) + matches[0].length);\n        url = getScriptUrlFromStack(remainingStack, (skipStackDepth - 1));\n      }\n      else {\n        url = matches[1];\n      }\n    }\n\n    // TODO: Handle more edge cases!\n    // Fixes #1\n    // See https://github.com/JamesMGreene/currentExecutingScript/issues/1\n\n    // ???\n\n  }\n  return url;\n}\n\n\n// Get the farthest currently executing (i.e. yes, EXECUTING) `script` DOM\n// element for the caller function, regardless of whether it is that `script`\n// DOM element is currently being evaluated for the first time. The farthest\n// currently executing `script` DOM element would typically be considered the\n// originator of the current execution stack.\nfunction _farthestExecutingScript() {\n  /*jshint noarg:false */\n\n  // TODO: Implement!\n  // Fixes #3\n  // See https://github.com/JamesMGreene/currentExecutingScript/issues/3\n  return null;\n\n/*\n  // Yes, this IS possible, i.e. if a script removes other scripts (or itself)\n  if (scripts.length === 0) {\n    return null;\n  }\n\n  // Guaranteed accurate in IE 6-10.\n  // Not accurate/supported in any other browsers.\n  if (isNotOpera && supportsScriptReadyState) {\n    for (var i = scripts.length; i--; ) {\n      if (scripts[i].readyState === \"interactive\") {\n        return scripts[i];\n      }\n    }\n  }\n\n  var stack,\n      e = new Error();\n  if (hasStackBeforeThrowing) {\n    stack = e.stack;\n  }\n  if (!stack && hasStackAfterThrowing) {\n    try {\n      throw e;\n    }\n    catch (err) {\n      // NOTE: Cannot use `err.sourceURL` or `err.fileName` as they will always be THIS script\n      stack = err.stack;\n    }\n  }\n  if (stack) {\n    var url = getScriptUrlFromStack(stack, skipStackDepth);\n    var script = getScriptFromUrl(url, scripts );\n    if (!script && pageUrl && url === pageUrl) {\n      // Try to find the correct inline script by searching through\n      // inline scripts' text content for the caller function's source\n      // code to be present. If the caller function's source code is\n      // not available, see if there is only one inline script element\n      // in the DOM and return that (even though it may be wrong)\n\n      // TODO: Implement!\n      // Fixes #4 in part\n      // See https://github.com/JamesMGreene/currentExecutingScript/issues/4\n\n      var callerFn = _farthestExecutingScript.caller || null,\n          callerFnStack = [],\n          callerFnSource = null;\n\n      while (callerFn) {\n        callerFnStack.push(callerFn);\n        callerFn = callerFn.caller || null;\n      }\n      callerFn = callerFnStack.slice(-1)[0];\n      callerFnSource = callerFn ? (\"\" + callerFn) : null;\n\n\n      if (callerFnSource) {\n        script = getInlineScriptFromCallerSource(callerFnSource);\n      }\n      else {\n        // NOTE: This is a loose assumption that could be inaccurate!\n        //\n        // Inaccuracies:\n        //  - If the inline script that initiated the call was also removed from the DOM.\n        //  - If the call was initiated by an element's inline event handler,\n        //    e.g. `<a onclick=\"(function() { alert(currentExecutingScript()); }()\">click</a>`\n        script = getSoleInlineScript();\n      }\n    }\n    return script;\n  }\n\n  // NOTE: This is a loose assumption that could be inaccurate!\n  //\n  // Inaccuracies:\n  //  - If a script is created dynamically and appended to some position\n  //    other than the very end of the document.\n  //  - If multiple scripts are created dynamically and all appended to the\n  //    same position within the document (and do not have their `async` attributes\n  //    set to `false`, at least in browsers that support async script evaluation.\n  //    other than the very end of the document.\n  //  - If any scripts are added with the `async` attribute set to `true` in a browser\n  //    that supports it.\n  //  - May get confused by `script` elements within `svg` elements\n  return scripts[scripts.length - 1] || null;\n*/\n}\n\n\n// Get the originating currently executing (i.e. yes, EXECUTING) `script` DOM\n// element or attribute node (e.g. `onclick`) for the caller function,\n// regardless of whether it is that `script` DOM element is currently being\n// evaluated for the first time. The originating currently executing `script`\n// DOM element [or attribute node] is the originator of the current execution stack.\nfunction _originatingExecutingScript() {\n  // TODO: Implement!\n  // Fixes #2\n  // See https://github.com/JamesMGreene/currentExecutingScript/issues/2\n  return null;\n}\n\n// Get the nearest currently executing (i.e. yes, EXECUTING) `script` DOM\n// element for the caller function, regardless of whether it is that `script`\n// DOM element is currently being evaluated for the first time.\nfunction _nearestExecutingScript() {\n  /*jshint noarg:false */\n\n  // Yes, this IS possible, i.e. if a script removes other scripts (or itself)\n  if (scripts.length === 0) {\n    return null;\n  }\n\n  var i, e, stack, url, script,\n      eligibleScripts = [],\n      skipStackDepth = _nearestExecutingScript.skipStackDepth || 1,\n\n      // TODO: Implement!\n      // Fixes #4 in part\n      // See https://github.com/JamesMGreene/currentExecutingScript/issues/4\n      callerFnSource = null;  //(\"\" + (_nearestExecutingScript.caller || \"\")) || null;\n\n  // This part will only help in IE 6-10.\n  for (i = 0; i < scripts.length; i++) {\n    if (isNotOpera && supportsScriptReadyState) {\n      if (scriptReadyRegex.test(scripts[i].readyState)) {\n        eligibleScripts.push(scripts[i]);\n      }\n    }\n    else {\n      eligibleScripts.push(scripts[i]);\n    }\n  }\n\n  e = new Error();\n  if (hasStackBeforeThrowing) {\n    stack = e.stack;\n  }\n  if (!stack && hasStackAfterThrowing) {\n    try {\n      throw e;\n    }\n    catch (err) {\n      // NOTE: Cannot use `err.sourceURL` or `err.fileName` as they will always be THIS script\n      stack = err.stack;\n    }\n  }\n\n  if (stack) {\n    url = getScriptUrlFromStack(stack, skipStackDepth);\n    script = getScriptFromUrl(url, eligibleScripts);\n\n    if (!script && pageUrl && url === pageUrl) {\n      // Try to find the correct inline script by searching through\n      // inline scripts' text content for the caller function's source\n      // code to be present.\n      if (callerFnSource) {\n        script = getInlineScriptFromCallerSource(callerFnSource, eligibleScripts);\n      }\n      // If the caller function's source code is not available, see if\n      // there is only one inline script element in the DOM and return\n      // that (even though it may be wrong)...\n      else {\n        // NOTE: This is a loose assumption that could be inaccurate!\n        //\n        // Inaccuracies:\n        //  - If the inline script that initiated the call was also removed from the DOM.\n        //  - If the call was initiated by an element's inline event handler,\n        //    e.g. `<a onclick=\"(function() { alert(currentExecutingScript()); }()\">click</a>`\n        script = getSoleInlineScript(eligibleScripts);\n      }\n    }\n  }\n\n  //\n  // Welcome to the Island of Inaccurate Assumptions!\n  // NOTE: ALL of the following are loose assumptions that could be inaccurate!\n  //\n\n  if (!script) {\n    // Inaccuracies:\n    //  - If the inline script that initiated the call was also removed from the DOM.\n    //  - If the call was initiated by an element's inline event handler,\n    //    e.g. `<a onclick=\"(function() { alert(currentExecutingScript()); }()\">click</a>`\n    if (eligibleScripts.length === 1) {\n      script = eligibleScripts[0];\n    }\n  }\n\n  if (!script) {\n    // Inaccuracies:\n    //  - If script currently being synchronously evaluated by the parser is the\n    //    originator of this call stack but NOT the source script of the caller/invocation\n    //    e.g.\n    //    ```html\n    //    <script id=\"a\">\n    //    function getCurrentScriptCallerFn() {\n    //      return currentExecutingScript.near();\n    //    }\n    //    </script>\n    //    <script id=\"b\">\n    //    // Should get `script[id=\"a\"]` but will get `script[id=\"b\"]` instead\n    //    getCurrentScriptCallerFn();\n    //    </script>\n    if (hasNativeCurrentScriptAccessor) {\n      script = document.currentScript;\n    }\n  }\n\n  if (!script) {\n    // Inaccuracies:\n    //  - If script currently being synchronously evaluated by the parser is the\n    //    originator of this call stack but NOT the source script of the caller/invocation\n    //    e.g.\n    //    ```html\n    //    <script id=\"a\">\n    //    function getCurrentScriptCallerFn() {\n    //      return currentExecutingScript.near();\n    //    }\n    //    </script>\n    //    <script id=\"b\">\n    //    // Should get `script[id=\"a\"]` but will get `script[id=\"b\"]` instead\n    //    getCurrentScriptCallerFn();\n    //    </script>\n    if (isNotOpera && supportsScriptReadyState) {\n      for (i = eligibleScripts.length; i--; ) {\n        if (eligibleScripts[i].readyState === \"interactive\") {\n          script = eligibleScripts[i];\n          break;\n        }\n      }\n    }\n  }\n\n  if (!script) {\n    // Inaccuracies:\n    //  - If a script is created dynamically and appended to some position\n    //    other than the very end of the document.\n    //  - If multiple scripts are created dynamically and all appended to the\n    //    same position within the document (and do not have their `async` attributes\n    //    set to `false`, at least in browsers that support async script evaluation.\n    //    other than the very end of the document.\n    //  - If any scripts are added with the `async` attribute set to `true` in a browser\n    //    that supports it.\n    //  - May get confused by `script` elements within `svg` elements\n    //  - If script currently being synchronously evaluated by the parser is the\n    //    originator of this call stack but NOT the source script of the caller/invocation\n    //    e.g.\n    //    ```html\n    //    <script id=\"a\">\n    //    function getCurrentScriptCallerFn() {\n    //      return currentExecutingScript.near();\n    //    }\n    //    </script>\n    //    <script id=\"b\">\n    //    // Should get `script[id=\"a\"]` but will get `script[id=\"b\"]` instead\n    //    getCurrentScriptCallerFn();\n    //    </script>\n    //    ```\n    script = eligibleScripts[eligibleScripts.length - 1] || null;\n  }\n\n  return script;\n}\n\n// Default stack depth to skip over when analyzing call stack frames\n_nearestExecutingScript.skipStackDepth = 1;\n\n\n\n    //\n    // Export the API\n    //\n    var currentExecutingScript    = _nearestExecutingScript;      // default\n    currentExecutingScript.near   = _nearestExecutingScript;\n    currentExecutingScript.far    = _farthestExecutingScript;\n    currentExecutingScript.origin = _originatingExecutingScript;\n\n\n    // Just return a value to define the module export.\n    // This example returns an object, but the module\n    // can return a function as the exported value.\n    return currentExecutingScript;\n  })\n);\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n  ? R.apply\n  : function ReflectApply(target, receiver, args) {\n    return Function.prototype.apply.call(target, receiver, args);\n  }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n  ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n  ReflectOwnKeys = function ReflectOwnKeys(target) {\n    return Object.getOwnPropertyNames(target)\n      .concat(Object.getOwnPropertySymbols(target));\n  };\n} else {\n  ReflectOwnKeys = function ReflectOwnKeys(target) {\n    return Object.getOwnPropertyNames(target);\n  };\n}\n\nfunction ProcessEmitWarning(warning) {\n  if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n  return value !== value;\n}\n\nfunction EventEmitter() {\n  EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\nmodule.exports.once = once;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n  if (typeof listener !== 'function') {\n    throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n  }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n  enumerable: true,\n  get: function() {\n    return defaultMaxListeners;\n  },\n  set: function(arg) {\n    if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n      throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n    }\n    defaultMaxListeners = arg;\n  }\n});\n\nEventEmitter.init = function() {\n\n  if (this._events === undefined ||\n      this._events === Object.getPrototypeOf(this)._events) {\n    this._events = Object.create(null);\n    this._eventsCount = 0;\n  }\n\n  this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n  if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n    throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n  }\n  this._maxListeners = n;\n  return this;\n};\n\nfunction _getMaxListeners(that) {\n  if (that._maxListeners === undefined)\n    return EventEmitter.defaultMaxListeners;\n  return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n  return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n  var args = [];\n  for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n  var doError = (type === 'error');\n\n  var events = this._events;\n  if (events !== undefined)\n    doError = (doError && events.error === undefined);\n  else if (!doError)\n    return false;\n\n  // If there is no 'error' event listener then throw.\n  if (doError) {\n    var er;\n    if (args.length > 0)\n      er = args[0];\n    if (er instanceof Error) {\n      // Note: The comments on the `throw` lines are intentional, they show\n      // up in Node's output if this results in an unhandled exception.\n      throw er; // Unhandled 'error' event\n    }\n    // At least give some kind of context to the user\n    var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n    err.context = er;\n    throw err; // Unhandled 'error' event\n  }\n\n  var handler = events[type];\n\n  if (handler === undefined)\n    return false;\n\n  if (typeof handler === 'function') {\n    ReflectApply(handler, this, args);\n  } else {\n    var len = handler.length;\n    var listeners = arrayClone(handler, len);\n    for (var i = 0; i < len; ++i)\n      ReflectApply(listeners[i], this, args);\n  }\n\n  return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n  var m;\n  var events;\n  var existing;\n\n  checkListener(listener);\n\n  events = target._events;\n  if (events === undefined) {\n    events = target._events = Object.create(null);\n    target._eventsCount = 0;\n  } else {\n    // To avoid recursion in the case that type === \"newListener\"! Before\n    // adding it to the listeners, first emit \"newListener\".\n    if (events.newListener !== undefined) {\n      target.emit('newListener', type,\n                  listener.listener ? listener.listener : listener);\n\n      // Re-assign `events` because a newListener handler could have caused the\n      // this._events to be assigned to a new object\n      events = target._events;\n    }\n    existing = events[type];\n  }\n\n  if (existing === undefined) {\n    // Optimize the case of one listener. Don't need the extra array object.\n    existing = events[type] = listener;\n    ++target._eventsCount;\n  } else {\n    if (typeof existing === 'function') {\n      // Adding the second element, need to change to array.\n      existing = events[type] =\n        prepend ? [listener, existing] : [existing, listener];\n      // If we've already got an array, just append.\n    } else if (prepend) {\n      existing.unshift(listener);\n    } else {\n      existing.push(listener);\n    }\n\n    // Check for listener leak\n    m = _getMaxListeners(target);\n    if (m > 0 && existing.length > m && !existing.warned) {\n      existing.warned = true;\n      // No error code for this since it is a Warning\n      // eslint-disable-next-line no-restricted-syntax\n      var w = new Error('Possible EventEmitter memory leak detected. ' +\n                          existing.length + ' ' + String(type) + ' listeners ' +\n                          'added. Use emitter.setMaxListeners() to ' +\n                          'increase limit');\n      w.name = 'MaxListenersExceededWarning';\n      w.emitter = target;\n      w.type = type;\n      w.count = existing.length;\n      ProcessEmitWarning(w);\n    }\n  }\n\n  return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n  return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n    function prependListener(type, listener) {\n      return _addListener(this, type, listener, true);\n    };\n\nfunction onceWrapper() {\n  if (!this.fired) {\n    this.target.removeListener(this.type, this.wrapFn);\n    this.fired = true;\n    if (arguments.length === 0)\n      return this.listener.call(this.target);\n    return this.listener.apply(this.target, arguments);\n  }\n}\n\nfunction _onceWrap(target, type, listener) {\n  var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n  var wrapped = onceWrapper.bind(state);\n  wrapped.listener = listener;\n  state.wrapFn = wrapped;\n  return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n  checkListener(listener);\n  this.on(type, _onceWrap(this, type, listener));\n  return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n    function prependOnceListener(type, listener) {\n      checkListener(listener);\n      this.prependListener(type, _onceWrap(this, type, listener));\n      return this;\n    };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n    function removeListener(type, listener) {\n      var list, events, position, i, originalListener;\n\n      checkListener(listener);\n\n      events = this._events;\n      if (events === undefined)\n        return this;\n\n      list = events[type];\n      if (list === undefined)\n        return this;\n\n      if (list === listener || list.listener === listener) {\n        if (--this._eventsCount === 0)\n          this._events = Object.create(null);\n        else {\n          delete events[type];\n          if (events.removeListener)\n            this.emit('removeListener', type, list.listener || listener);\n        }\n      } else if (typeof list !== 'function') {\n        position = -1;\n\n        for (i = list.length - 1; i >= 0; i--) {\n          if (list[i] === listener || list[i].listener === listener) {\n            originalListener = list[i].listener;\n            position = i;\n            break;\n          }\n        }\n\n        if (position < 0)\n          return this;\n\n        if (position === 0)\n          list.shift();\n        else {\n          spliceOne(list, position);\n        }\n\n        if (list.length === 1)\n          events[type] = list[0];\n\n        if (events.removeListener !== undefined)\n          this.emit('removeListener', type, originalListener || listener);\n      }\n\n      return this;\n    };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n    function removeAllListeners(type) {\n      var listeners, events, i;\n\n      events = this._events;\n      if (events === undefined)\n        return this;\n\n      // not listening for removeListener, no need to emit\n      if (events.removeListener === undefined) {\n        if (arguments.length === 0) {\n          this._events = Object.create(null);\n          this._eventsCount = 0;\n        } else if (events[type] !== undefined) {\n          if (--this._eventsCount === 0)\n            this._events = Object.create(null);\n          else\n            delete events[type];\n        }\n        return this;\n      }\n\n      // emit removeListener for all listeners on all events\n      if (arguments.length === 0) {\n        var keys = Object.keys(events);\n        var key;\n        for (i = 0; i < keys.length; ++i) {\n          key = keys[i];\n          if (key === 'removeListener') continue;\n          this.removeAllListeners(key);\n        }\n        this.removeAllListeners('removeListener');\n        this._events = Object.create(null);\n        this._eventsCount = 0;\n        return this;\n      }\n\n      listeners = events[type];\n\n      if (typeof listeners === 'function') {\n        this.removeListener(type, listeners);\n      } else if (listeners !== undefined) {\n        // LIFO order\n        for (i = listeners.length - 1; i >= 0; i--) {\n          this.removeListener(type, listeners[i]);\n        }\n      }\n\n      return this;\n    };\n\nfunction _listeners(target, type, unwrap) {\n  var events = target._events;\n\n  if (events === undefined)\n    return [];\n\n  var evlistener = events[type];\n  if (evlistener === undefined)\n    return [];\n\n  if (typeof evlistener === 'function')\n    return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n  return unwrap ?\n    unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n  return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n  return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n  if (typeof emitter.listenerCount === 'function') {\n    return emitter.listenerCount(type);\n  } else {\n    return listenerCount.call(emitter, type);\n  }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n  var events = this._events;\n\n  if (events !== undefined) {\n    var evlistener = events[type];\n\n    if (typeof evlistener === 'function') {\n      return 1;\n    } else if (evlistener !== undefined) {\n      return evlistener.length;\n    }\n  }\n\n  return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n  return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n  var copy = new Array(n);\n  for (var i = 0; i < n; ++i)\n    copy[i] = arr[i];\n  return copy;\n}\n\nfunction spliceOne(list, index) {\n  for (; index + 1 < list.length; index++)\n    list[index] = list[index + 1];\n  list.pop();\n}\n\nfunction unwrapListeners(arr) {\n  var ret = new Array(arr.length);\n  for (var i = 0; i < ret.length; ++i) {\n    ret[i] = arr[i].listener || arr[i];\n  }\n  return ret;\n}\n\nfunction once(emitter, name) {\n  return new Promise(function (resolve, reject) {\n    function errorListener(err) {\n      emitter.removeListener(name, resolver);\n      reject(err);\n    }\n\n    function resolver() {\n      if (typeof emitter.removeListener === 'function') {\n        emitter.removeListener('error', errorListener);\n      }\n      resolve([].slice.call(arguments));\n    };\n\n    eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });\n    if (name !== 'error') {\n      addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });\n    }\n  });\n}\n\nfunction addErrorHandlerIfEventEmitter(emitter, handler, flags) {\n  if (typeof emitter.on === 'function') {\n    eventTargetAgnosticAddListener(emitter, 'error', handler, flags);\n  }\n}\n\nfunction eventTargetAgnosticAddListener(emitter, name, listener, flags) {\n  if (typeof emitter.on === 'function') {\n    if (flags.once) {\n      emitter.once(name, listener);\n    } else {\n      emitter.on(name, listener);\n    }\n  } else if (typeof emitter.addEventListener === 'function') {\n    // EventTarget does not have `error` event semantics like Node\n    // EventEmitters, we do not listen for `error` events here.\n    emitter.addEventListener(name, function wrapListener(arg) {\n      // IE does not have builtin `{ once: true }` support so we\n      // have to do it manually.\n      if (flags.once) {\n        emitter.removeEventListener(name, wrapListener);\n      }\n      listener(arg);\n    });\n  } else {\n    throw new TypeError('The \"emitter\" argument must be of type EventEmitter. Received type ' + typeof emitter);\n  }\n}\n","/*! jQuery v3.6.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) OpenJS Foundation and other contributors | jquery.org/license */\n!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(g,e){\"use strict\";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return\"function\"==typeof e&&\"number\"!=typeof e.nodeType&&\"function\"!=typeof e.item},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement(\"script\");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?n[o.call(e)]||\"object\":typeof e}var f=\"3.6.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector\",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&\"length\"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0<t&&t-1 in e)}E.fn=E.prototype={jquery:f,constructor:E,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=E.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return E.each(this,e)},map:function(n){return this.pushStack(E.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(E.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(E.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},E.extend=E.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||b(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],\"__proto__\"!==t&&a!==r&&(l&&r&&(E.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||E.isPlainObject(n)?n:{},i=!1,a[t]=E.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},E.extend({expando:\"jQuery\"+(f+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==o.call(e))&&(!(t=r(e))||\"function\"==typeof(n=y.call(t,\"constructor\")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){C(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?E.merge(n,\"string\"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return v(a)},guid:1,support:m}),\"function\"==typeof Symbol&&(E.fn[Symbol.iterator]=t[Symbol.iterator]),E.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){n[\"[object \"+t+\"]\"]=t.toLowerCase()});var p=function(n){var e,p,x,o,i,h,f,g,w,u,l,C,T,a,E,v,s,c,y,A=\"sizzle\"+1*new Date,d=n.document,N=0,r=0,m=ue(),b=ue(),S=ue(),k=ue(),D=function(e,t){return e===t&&(l=!0),0},L={}.hasOwnProperty,t=[],j=t.pop,q=t.push,O=t.push,P=t.slice,H=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},I=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",R=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",B=\"(?:\\\\\\\\[\\\\da-fA-F]{1,6}\"+R+\"?|\\\\\\\\[^\\\\r\\\\n\\\\f]|[\\\\w-]|[^\\0-\\\\x7f])+\",M=\"\\\\[\"+R+\"*(\"+B+\")(?:\"+R+\"*([*^$|!~]?=)\"+R+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+B+\"))|)\"+R+\"*\\\\]\",W=\":(\"+B+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+M+\")*)|.*)\\\\)|)\",F=new RegExp(R+\"+\",\"g\"),$=new RegExp(\"^\"+R+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+R+\"+$\",\"g\"),z=new RegExp(\"^\"+R+\"*,\"+R+\"*\"),_=new RegExp(\"^\"+R+\"*([>+~]|\"+R+\")\"+R+\"*\"),U=new RegExp(R+\"|>\"),V=new RegExp(W),X=new RegExp(\"^\"+B+\"$\"),Q={ID:new RegExp(\"^#(\"+B+\")\"),CLASS:new RegExp(\"^\\\\.(\"+B+\")\"),TAG:new RegExp(\"^(\"+B+\"|[*])\"),ATTR:new RegExp(\"^\"+M),PSEUDO:new RegExp(\"^\"+W),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+R+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+R+\"*(?:([+-]|)\"+R+\"*(\\\\d+)|))\"+R+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+I+\")$\",\"i\"),needsContext:new RegExp(\"^\"+R+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+R+\"*((?:-\\\\d)?\\\\d*)\"+R+\"*\\\\)|)(?=[^-]|$)\",\"i\")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\\d$/i,J=/^[^{]+\\{\\s*\\[native \\w/,Z=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ee=/[+~]/,te=new RegExp(\"\\\\\\\\[\\\\da-fA-F]{1,6}\"+R+\"?|\\\\\\\\([^\\\\r\\\\n\\\\f])\",\"g\"),ne=function(e,t){var n=\"0x\"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ie=function(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&\"fieldset\"===e.nodeName.toLowerCase()},{dir:\"parentNode\",next:\"legend\"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],\"string\"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+\" \"]&&(!v||!v.test(t))&&(1!==d||\"object\"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute(\"id\"))?s=s.replace(re,ie):e.setAttribute(\"id\",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?\"#\"+s:\":scope\")+\" \"+be(l[o]);c=l.join(\",\")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute(\"id\")}}}return g(t.replace($,\"$1\"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+\" \")>x.cacheLength&&delete e[r.shift()],e[t+\" \"]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split(\"|\"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return\"input\"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return(\"input\"===t||\"button\"===t)&&e.type===n}}function ge(t){return function(e){return\"form\"in e?e.parentNode&&!1===e.disabled?\"label\"in e?\"label\"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:\"label\"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||\"HTML\")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",oe,!1):n.attachEvent&&n.attachEvent(\"onunload\",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement(\"div\")),\"undefined\"!=typeof e.querySelectorAll&&!e.querySelectorAll(\":scope fieldset div\").length}),p.attributes=ce(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute(\"id\")===t}},x.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return t&&t.value===n}},x.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML=\"<a id='\"+A+\"'></a><select id='\"+A+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&v.push(\"[*^$]=\"+R+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||v.push(\"\\\\[\"+R+\"*(?:value|\"+I+\")\"),e.querySelectorAll(\"[id~=\"+A+\"-]\").length||v.push(\"~=\"),(t=T.createElement(\"input\")).setAttribute(\"name\",\"\"),e.appendChild(t),e.querySelectorAll(\"[name='']\").length||v.push(\"\\\\[\"+R+\"*name\"+R+\"*=\"+R+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\":checked\").length||v.push(\":checked\"),e.querySelectorAll(\"a#\"+A+\"+*\").length||v.push(\".#.+[+~]\"),e.querySelectorAll(\"\\\\\\f\"),v.push(\"[\\\\r\\\\n\\\\f]\")}),ce(function(e){e.innerHTML=\"<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>\";var t=T.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&v.push(\"name\"+R+\"*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&v.push(\":enabled\",\":disabled\"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&v.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),v.push(\",.*:\")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,\"*\"),c.call(e,\"[s!='']:x\"),s.push(\"!=\",W)}),v=v.length&&new RegExp(v.join(\"|\")),s=s.length&&new RegExp(s.join(\"|\")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+\" \"]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0<se(t,T,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=T&&C(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=T&&C(e);var n=x.attrHandle[t.toLowerCase()],r=n&&L.call(x.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:p.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+\"\").replace(re,ie)},se.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!p.detectDuplicates,u=!p.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n=\"\",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(x=se.selectors={cacheLength:50,createPseudo:le,match:Q,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||\"\").replace(te,ne),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+\" \"];return t||(t=new RegExp(\"(^|\"+R+\")\"+e+\"(\"+R+\"|$)\"))&&m(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?\"!=\"===r:!r||(t+=\"\",\"=\"===r?t===i:\"!=\"===r?t!==i:\"^=\"===r?i&&0===t.indexOf(i):\"*=\"===r?i&&-1<t.indexOf(i):\"$=\"===r?i&&t.slice(-i.length)===i:\"~=\"===r?-1<(\" \"+t.replace(F,\" \")+\" \").indexOf(i):\"|=\"===r&&(t===i||t.slice(0,i.length+1)===i+\"-\"))}},CHILD:function(h,e,t,g,v){var y=\"nth\"!==h.slice(0,3),m=\"last\"!==h.slice(-4),b=\"of-type\"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?\"nextSibling\":\"previousSibling\",c=e.parentNode,f=b&&e.nodeName.toLowerCase(),d=!n&&!b,p=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(b?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l=\"only\"===h&&!u&&\"nextSibling\"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&d){p=(s=(r=(i=(o=(a=c)[A]||(a[A]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===N&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(p=s=0)||u.pop())if(1===a.nodeType&&++p&&a===e){i[h]=[N,s,p];break}}else if(d&&(p=s=(r=(i=(o=(a=e)[A]||(a[A]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===N&&r[1]),!1===p)while(a=++s&&a&&a[l]||(p=s=0)||u.pop())if((b?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++p&&(d&&((i=(o=a[A]||(a[A]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[N,p]),a===e))break;return(p-=v)===g||p%g==0&&0<=p/g}}},PSEUDO:function(e,o){var t,a=x.pseudos[e]||x.setFilters[e.toLowerCase()]||se.error(\"unsupported pseudo: \"+e);return a[A]?a(o):1<a.length?(t=[e,e,\"\",o],x.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=H(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,\"$1\"));return s[A]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return X.test(n||\"\")||se.error(\"unsupported lang: \"+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute(\"xml:lang\")||e.getAttribute(\"lang\"))return(t=t.toLowerCase())===n||0===t.indexOf(n+\"-\")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===T.activeElement&&(!T.hasFocus||T.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!x.pseudos.empty(e)},header:function(e){return K.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=x.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})x.pseudos[e]=pe(e);for(e in{submit:!0,reset:!0})x.pseudos[e]=he(e);function me(){}function be(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function xe(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&\"parentNode\"===c,d=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[N,d];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[A]||(e[A]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===N&&r[1]===d)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Ce(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Te(p,h,g,v,y,e){return v&&!v[A]&&(v=Te(v)),y&&!y[A]&&(y=Te(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||\"*\",n.nodeType?[n]:n,[]),f=!p||!e&&h?c:Ce(c,s,p,n,r),d=g?y||(e?p:l||v)?[]:t:f;if(g&&g(f,d,n,r),v){i=Ce(d,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(d[u[o]]=!(f[u[o]]=a))}if(e){if(y||p){if(y){i=[],o=d.length;while(o--)(a=d[o])&&i.push(f[o]=a);y(null,d=[],i,r)}o=d.length;while(o--)(a=d[o])&&-1<(i=y?H(e,a):s[o])&&(e[i]=!(t[i]=a))}}else d=Ce(d===t?d.splice(l,d.length):d),y?y(null,t,d,r):O.apply(t,d)})}function Ee(e){for(var i,t,n,r=e.length,o=x.relative[e[0].type],a=o||x.relative[\" \"],s=o?1:0,u=xe(function(e){return e===i},a,!0),l=xe(function(e){return-1<H(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=x.relative[e[s].type])c=[xe(we(c),t)];else{if((t=x.filter[e[s].type].apply(null,e[s].matches))[A]){for(n=++s;n<r;n++)if(x.relative[e[n].type])break;return Te(1<s&&we(c),1<s&&be(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace($,\"$1\"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&be(e))}c.push(t)}return we(c)}return me.prototype=x.filters=x.pseudos,x.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=b[e+\" \"];if(l)return t?0:l.slice(0);a=e,s=[],u=x.preFilter;while(a){for(o in n&&!(r=z.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=_.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($,\" \")}),a=a.slice(n.length)),x.filter)!(r=Q[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):b(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,b,r,i=[],o=[],a=S[e+\" \"];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[A]?i.push(a):o.push(a);(a=S(e,(v=o,m=0<(y=i).length,b=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l=\"0\",c=e&&[],f=[],d=w,p=e||b&&x.find.TAG(\"*\",i),h=N+=null==d?1:Math.random()||.1,g=p.length;for(i&&(w=t==T||t||i);l!==g&&null!=(o=p[l]);l++){if(b&&o){a=0,t||o.ownerDocument==T||(C(o),n=!E);while(s=v[a++])if(s(o,t||T,n)){r.push(o);break}i&&(N=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=j.call(r));f=Ce(f)}O.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(N=h,w=d),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&\"ID\"===(a=o[0]).type&&9===t.nodeType&&E&&x.relative[o[1].type]){if(!(t=(x.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=Q.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],x.relative[s=a.type])break;if((u=x.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&be(o)))return O.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},p.sortStable=A.split(\"\").sort(D).join(\"\")===A,p.detectDuplicates=!!l,C(),p.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(T.createElement(\"fieldset\"))}),ce(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||fe(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),p.attributes&&ce(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||fe(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute(\"disabled\")})||fe(I,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(g);E.find=p,E.expr=p.selectors,E.expr[\":\"]=E.expr.pseudos,E.uniqueSort=E.unique=p.uniqueSort,E.text=p.getText,E.isXMLDoc=p.isXML,E.contains=p.contains,E.escapeSelector=p.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&E(e).is(n))break;r.push(e)}return r},A=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=E.expr.match.needsContext;function S(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var k=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):\"string\"!=typeof n?E.grep(e,function(e){return-1<i.call(n,e)!==r}):E.filter(n,e,r)}E.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?E.find.matchesSelector(r,e)?[r]:[]:E.find.matches(e,E.grep(t,function(e){return 1===e.nodeType}))},E.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(\"string\"!=typeof e)return this.pushStack(E(e).filter(function(){for(t=0;t<r;t++)if(E.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)E.find(e,i[t],n);return 1<r?E.uniqueSort(n):n},filter:function(e){return this.pushStack(D(this,e||[],!1))},not:function(e){return this.pushStack(D(this,e||[],!0))},is:function(e){return!!D(this,\"string\"==typeof e&&N.test(e)?E(e):e||[],!1).length}});var L,j=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,\"string\"==typeof e){if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(E.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a=\"string\"!=typeof e&&E(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&E.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?E.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?i.call(E(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(E.uniqueSort(E.merge(this.get(),E(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),E.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,\"parentNode\")},parentsUntil:function(e,t,n){return h(e,\"parentNode\",n)},next:function(e){return P(e,\"nextSibling\")},prev:function(e){return P(e,\"previousSibling\")},nextAll:function(e){return h(e,\"nextSibling\")},prevAll:function(e){return h(e,\"previousSibling\")},nextUntil:function(e,t,n){return h(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return h(e,\"previousSibling\",n)},siblings:function(e){return A((e.parentNode||{}).firstChild,e)},children:function(e){return A(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(S(e,\"template\")&&(e=e.content||e),E.merge([],e.childNodes))}},function(r,i){E.fn[r]=function(e,t){var n=E.map(this,i,e);return\"Until\"!==r.slice(-5)&&(t=e),t&&\"string\"==typeof t&&(n=E.filter(t,n)),1<this.length&&(O[r]||E.uniqueSort(n),q.test(r)&&n.reverse()),this.pushStack(n)}});var H=/[^\\x20\\t\\r\\n\\f]+/g;function I(e){return e}function R(e){throw e}function B(e,t,n,r){var i;try{e&&b(i=e.promise)?i.call(e).done(t).fail(n):e&&b(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}E.Callbacks=function(r){var e,n;r=\"string\"==typeof r?(e=r,n={},E.each(e.match(H)||[],function(e,t){n[t]=!0}),n):E.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:\"\")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){E.each(e,function(e,t){b(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&\"string\"!==T(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return E.each(arguments,function(e,t){var n;while(-1<(n=E.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<E.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t=\"\",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=\"\"),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},E.extend({Deferred:function(e){var o=[[\"notify\",\"progress\",E.Callbacks(\"memory\"),E.Callbacks(\"memory\"),2],[\"resolve\",\"done\",E.Callbacks(\"once memory\"),E.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",E.Callbacks(\"once memory\"),E.Callbacks(\"once memory\"),1,\"rejected\"]],i=\"pending\",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},\"catch\":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return E.Deferred(function(r){E.each(o,function(e,t){var n=b(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&b(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+\"With\"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError(\"Thenable self-resolution\");t=e&&(\"object\"==typeof e||\"function\"==typeof e)&&e.then,b(t)?s?t.call(e,l(u,o,I,s),l(u,o,R,s)):(u++,t.call(e,l(u,o,I,s),l(u,o,R,s),l(u,o,I,o.notifyWith))):(a!==I&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){E.Deferred.exceptionHook&&E.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==R&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(E.Deferred.getStackHook&&(t.stackTrace=E.Deferred.getStackHook()),g.setTimeout(t))}}return E.Deferred(function(e){o[0][3].add(l(0,e,b(r)?r:I,e.notifyWith)),o[1][3].add(l(0,e,b(t)?t:I)),o[2][3].add(l(0,e,b(n)?n:R))}).promise()},promise:function(e){return null!=e?E.extend(e,a):a}},s={};return E.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+\"With\"](this===s?void 0:this,arguments),this},s[t[0]+\"With\"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=E.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(B(e,o.done(a(t)).resolve,o.reject,!n),\"pending\"===o.state()||b(i[t]&&i[t].then)))return o.then();while(t--)B(i[t],a(t),o.reject);return o.promise()}});var M=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;E.Deferred.exceptionHook=function(e,t){g.console&&g.console.warn&&e&&M.test(e.name)&&g.console.warn(\"jQuery.Deferred exception: \"+e.message,e.stack,t)},E.readyException=function(e){g.setTimeout(function(){throw e})};var W=E.Deferred();function F(){w.removeEventListener(\"DOMContentLoaded\",F),g.removeEventListener(\"load\",F),E.ready()}E.fn.ready=function(e){return W.then(e)[\"catch\"](function(e){E.readyException(e)}),this},E.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--E.readyWait:E.isReady)||(E.isReady=!0)!==e&&0<--E.readyWait||W.resolveWith(w,[E])}}),E.ready.then=W.then,\"complete\"===w.readyState||\"loading\"!==w.readyState&&!w.documentElement.doScroll?g.setTimeout(E.ready):(w.addEventListener(\"DOMContentLoaded\",F),g.addEventListener(\"load\",F));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===T(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,b(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(E(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,_=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function V(e){return e.replace(z,\"ms-\").replace(_,U)}var X=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Q(){this.expando=E.expando+Q.uid++}Q.uid=1,Q.prototype={cache:function(e){var t=e[this.expando];return t||(t={},X(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if(\"string\"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&\"string\"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(H)||[]).length;while(n--)delete r[t[n]]}(void 0===t||E.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!E.isEmptyObject(t)}};var Y=new Q,G=new Q,K=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,J=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r=\"data-\"+t.replace(J,\"-$&\").toLowerCase(),\"string\"==typeof(n=e.getAttribute(r))){try{n=\"true\"===(i=n)||\"false\"!==i&&(\"null\"===i?null:i===+i+\"\"?+i:K.test(i)?JSON.parse(i):i)}catch(e){}G.set(e,t,n)}else n=void 0;return n}E.extend({hasData:function(e){return G.hasData(e)||Y.hasData(e)},data:function(e,t,n){return G.access(e,t,n)},removeData:function(e,t){G.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),E.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=G.get(o),1===o.nodeType&&!Y.get(o,\"hasDataAttrs\"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf(\"data-\")&&(r=V(r.slice(5)),Z(o,r,i[r]));Y.set(o,\"hasDataAttrs\",!0)}return i}return\"object\"==typeof n?this.each(function(){G.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=G.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){G.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){G.remove(this,e)})}}),E.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,E.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=E.queue(e,t),r=n.length,i=n.shift(),o=E._queueHooks(e,t);\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,function(){E.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return Y.get(e,n)||Y.access(e,n,{empty:E.Callbacks(\"once memory\").add(function(){Y.remove(e,[t+\"queue\",n])})})}}),E.fn.extend({queue:function(t,n){var e=2;return\"string\"!=typeof t&&(n=t,t=\"fx\",e--),arguments.length<e?E.queue(this[0],t):void 0===n?this:this.each(function(){var e=E.queue(this,t,n);E._queueHooks(this,t),\"fx\"===t&&\"inprogress\"!==e[0]&&E.dequeue(this,t)})},dequeue:function(e){return this.each(function(){E.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=E.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";while(a--)(n=Y.get(o[a],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,te=new RegExp(\"^(?:([+-])=|)(\"+ee+\")([a-z%]*)$\",\"i\"),ne=[\"Top\",\"Right\",\"Bottom\",\"Left\"],re=w.documentElement,ie=function(e){return E.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return E.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return\"none\"===(e=t||e).style.display||\"\"===e.style.display&&ie(e)&&\"none\"===E.css(e,\"display\")};var se={};function ue(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?(\"none\"===n&&(l[c]=Y.get(r,\"display\")||null,l[c]||(r.style.display=\"\")),\"\"===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=se[s])||(o=a.body.appendChild(a.createElement(s)),u=E.css(o,\"display\"),o.parentNode.removeChild(o),\"none\"===u&&(u=\"block\"),se[s]=u)))):\"none\"!==n&&(l[c]=\"none\",Y.set(r,\"display\",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}E.fn.extend({show:function(){return ue(this,!0)},hide:function(){return ue(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?E(this).show():E(this).hide()})}});var le,ce,fe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i,pe=/^$|^module$|\\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement(\"div\")),(ce=w.createElement(\"input\")).setAttribute(\"type\",\"radio\"),ce.setAttribute(\"checked\",\"checked\"),ce.setAttribute(\"name\",\"t\"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML=\"<textarea>x</textarea>\",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML=\"<option></option>\",m.option=!!le.lastChild;var he={thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};function ge(e,t){var n;return n=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],\"globalEval\",!t||Y.get(t[n],\"globalEval\"))}he.tbody=he.tfoot=he.colgroup=he.caption=he.thead,he.th=he.td,m.option||(he.optgroup=he.option=[1,\"<select multiple='multiple'>\",\"</select>\"]);var ye=/<|&#?\\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p<h;p++)if((o=e[p])||0===o)if(\"object\"===T(o))E.merge(d,o.nodeType?[o]:o);else if(ye.test(o)){a=a||f.appendChild(t.createElement(\"div\")),s=(de.exec(o)||[\"\",\"\"])[1].toLowerCase(),u=he[s]||he._default,a.innerHTML=u[1]+E.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;E.merge(d,a.childNodes),(a=f.firstChild).textContent=\"\"}else d.push(t.createTextNode(o));f.textContent=\"\",p=0;while(o=d[p++])if(r&&-1<E.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ge(f.appendChild(o),\"script\"),l&&ve(a),n){c=0;while(o=a[c++])pe.test(o.type||\"\")&&n.push(o)}return f}var be=/^([^.]*)(?:\\.(.+)|)/;function xe(){return!0}function we(){return!1}function Ce(e,t){return e===function(){try{return w.activeElement}catch(e){}}()==(\"focus\"===t)}function Te(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Te(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=we;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return E().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=E.guid++)),e.each(function(){E.event.add(this,t,i,r,n)})}function Ee(e,i,o){o?(Y.set(e,i,!1),E.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(E.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n&&n.value}else r.length&&(Y.set(this,i,{value:E.event.trigger(E.extend(r[0],E.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&E.event.add(e,i,xe)}E.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,d,p,h,g,v=Y.get(t);if(X(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&E.find.matchesSelector(re,i),n.guid||(n.guid=E.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return\"undefined\"!=typeof E&&E.event.triggered!==e.type?E.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||\"\").match(H)||[\"\"]).length;while(l--)p=g=(s=be.exec(e[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),p&&(f=E.event.special[p]||{},p=(i?f.delegateType:f.bindType)||p,f=E.event.special[p]||{},c=E.extend({type:p,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&E.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(d=u[p])||((d=u[p]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(p,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?d.splice(d.delegateCount++,0,c):d.push(c),E.event.global[p]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,d,p,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||\"\").match(H)||[\"\"]).length;while(l--)if(p=g=(s=be.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),p){f=E.event.special[p]||{},d=u[p=(r?f.delegateType:f.bindType)||p]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=d.length;while(o--)c=d[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(d.splice(o,1),c.selector&&d.delegateCount--,f.remove&&f.remove.call(e,c));a&&!d.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||E.removeEvent(e,p,v.handle),delete u[p])}else for(p in u)E.event.remove(e,p+t[l],n,r,!0);E.isEmptyObject(u)&&Y.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=E.event.fix(e),l=(Y.get(this,\"events\")||Object.create(null))[u.type]||[],c=E.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=E.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((E.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!(\"click\"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+\" \"]&&(a[i]=r.needsContext?-1<E(i,this).index(l):E.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(E.Event.prototype,t,{enumerable:!0,configurable:!0,get:b(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[E.expando]?e:new E.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return fe.test(t.type)&&t.click&&S(t,\"input\")&&Ee(t,\"click\",xe),!1},trigger:function(e){var t=this||e;return fe.test(t.type)&&t.click&&S(t,\"input\")&&Ee(t,\"click\"),!0},_default:function(e){var t=e.target;return fe.test(t.type)&&t.click&&S(t,\"input\")&&Y.get(t,\"click\")||S(t,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},E.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},E.Event=function(e,t){if(!(this instanceof E.Event))return new E.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?xe:we,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&E.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[E.expando]=!0},E.Event.prototype={constructor:E.Event,isDefaultPrevented:we,isPropagationStopped:we,isImmediatePropagationStopped:we,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=xe,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=xe,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=xe,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},E.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,\"char\":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},E.event.addProp),E.each({focus:\"focusin\",blur:\"focusout\"},function(t,e){E.event.special[t]={setup:function(){return Ee(this,t,Ce),!1},trigger:function(){return Ee(this,t),!0},_default:function(e){return Y.get(e.target,t)},delegateType:e}}),E.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,i){E.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||E.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),E.fn.extend({on:function(e,t,n,r){return Te(this,e,t,n,r)},one:function(e,t,n,r){return Te(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,E(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&\"function\"!=typeof t||(n=t,t=void 0),!1===n&&(n=we),this.each(function(){E.event.remove(this,e,n,t)})}});var Ae=/<script|<style|<link/i,Ne=/checked\\s*(?:[^=]|=\\s*.checked.)/i,Se=/^\\s*<!\\[CDATA\\[|\\]\\]>\\s*$/g;function ke(e,t){return S(e,\"table\")&&S(11!==t.nodeType?t:t.firstChild,\"tr\")&&E(e).children(\"tbody\")[0]||e}function De(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function Le(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function je(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,\"handle events\"),s)for(n=0,r=s[i].length;n<r;n++)E.event.add(t,i,s[i][n]);G.hasData(e)&&(o=G.access(e),a=E.extend({},o),G.set(t,a))}}function qe(n,r,i,o){r=v(r);var e,t,a,s,u,l,c=0,f=n.length,d=f-1,p=r[0],h=b(p);if(h||1<f&&\"string\"==typeof p&&!m.checkClone&&Ne.test(p))return n.each(function(e){var t=n.eq(e);h&&(r[0]=p.call(this,e,t.html())),qe(t,r,i,o)});if(f&&(t=(e=me(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=E.map(ge(e,\"script\"),De)).length;c<f;c++)u=e,c!==d&&(u=E.clone(u,!0,!0),s&&E.merge(a,ge(u,\"script\"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,E.map(a,Le),c=0;c<s;c++)u=a[c],pe.test(u.type||\"\")&&!Y.access(u,\"globalEval\")&&E.contains(l,u)&&(u.src&&\"module\"!==(u.type||\"\").toLowerCase()?E._evalUrl&&!u.noModule&&E._evalUrl(u.src,{nonce:u.nonce||u.getAttribute(\"nonce\")},l):C(u.textContent.replace(Se,\"\"),u,l))}return n}function Oe(e,t,n){for(var r,i=t?E.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||E.cleanData(ge(r)),r.parentNode&&(n&&ie(r)&&ve(ge(r,\"script\")),r.parentNode.removeChild(r));return e}E.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(m.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||E.isXMLDoc(e)))for(a=ge(c),r=0,i=(o=ge(e)).length;r<i;r++)s=o[r],u=a[r],void 0,\"input\"===(l=u.nodeName.toLowerCase())&&fe.test(s.type)?u.checked=s.checked:\"input\"!==l&&\"textarea\"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ge(e),a=a||ge(c),r=0,i=o.length;r<i;r++)je(o[r],a[r]);else je(e,c);return 0<(a=ge(c,\"script\")).length&&ve(a,!f&&ge(e,\"script\")),c},cleanData:function(e){for(var t,n,r,i=E.event.special,o=0;void 0!==(n=e[o]);o++)if(X(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?E.event.remove(n,r):E.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[G.expando]&&(n[G.expando]=void 0)}}}),E.fn.extend({detach:function(e){return Oe(this,e,!0)},remove:function(e){return Oe(this,e)},text:function(e){return $(this,function(e){return void 0===e?E.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return qe(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||ke(this,e).appendChild(e)})},prepend:function(){return qe(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=ke(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return qe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return qe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(E.cleanData(ge(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return E.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!Ae.test(e)&&!he[(de.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=E.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(E.cleanData(ge(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return qe(this,arguments,function(e){var t=this.parentNode;E.inArray(this,n)<0&&(E.cleanData(ge(this)),t&&t.replaceChild(e,this))},n)}}),E.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,a){E.fn[e]=function(e){for(var t,n=[],r=E(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),E(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Pe=new RegExp(\"^(\"+ee+\")(?!px)[a-z%]+$\",\"i\"),He=/^--/,Ie=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=g),t.getComputedStyle(e)},Re=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Be=new RegExp(ne.join(\"|\"),\"i\"),Me=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",We=new RegExp(\"^\"+Me+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+Me+\"+$\",\"g\");function Fe(e,t,n){var r,i,o,a,s=He.test(t),u=e.style;return(n=n||Ie(e))&&(a=n.getPropertyValue(t)||n[t],s&&(a=a.replace(We,\"$1\")),\"\"!==a||ie(e)||(a=E.style(e,t)),!m.pixelBoxStyles()&&Pe.test(a)&&Be.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=n.width,u.width=r,u.minWidth=i,u.maxWidth=o)),void 0!==a?a+\"\":a}function $e(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText=\"position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0\",l.style.cssText=\"position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%\",re.appendChild(u).appendChild(l);var e=g.getComputedStyle(l);n=\"1%\"!==e.top,s=12===t(e.marginLeft),l.style.right=\"60%\",o=36===t(e.right),r=36===t(e.width),l.style.position=\"absolute\",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=w.createElement(\"div\"),l=w.createElement(\"div\");l.style&&(l.style.backgroundClip=\"content-box\",l.cloneNode(!0).style.backgroundClip=\"\",m.clearCloneStyle=\"content-box\"===l.style.backgroundClip,E.extend(m,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=w.createElement(\"table\"),t=w.createElement(\"tr\"),n=w.createElement(\"div\"),e.style.cssText=\"position:absolute;left:-11111px;border-collapse:separate\",t.style.cssText=\"border:1px solid\",t.style.height=\"1px\",n.style.height=\"9px\",n.style.display=\"block\",re.appendChild(e).appendChild(t).appendChild(n),r=g.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,re.removeChild(e)),a}}))}();var ze=[\"Webkit\",\"Moz\",\"ms\"],_e=w.createElement(\"div\").style,Ue={};function Ve(e){var t=E.cssProps[e]||Ue[e];return t||(e in _e?e:Ue[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=ze.length;while(n--)if((e=ze[n]+t)in _e)return e}(e)||e)}var Xe,Qe,Ye=/^(none|table(?!-c[ea]).+)/,Ge={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Ke={letterSpacing:\"0\",fontWeight:\"400\"};function Je(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||\"px\"):t}function Ze(e,t,n,r,i,o){var a=\"width\"===t?1:0,s=0,u=0;if(n===(r?\"border\":\"content\"))return 0;for(;a<4;a+=2)\"margin\"===n&&(u+=E.css(e,n+ne[a],!0,i)),r?(\"content\"===n&&(u-=E.css(e,\"padding\"+ne[a],!0,i)),\"margin\"!==n&&(u-=E.css(e,\"border\"+ne[a]+\"Width\",!0,i))):(u+=E.css(e,\"padding\"+ne[a],!0,i),\"padding\"!==n?u+=E.css(e,\"border\"+ne[a]+\"Width\",!0,i):s+=E.css(e,\"border\"+ne[a]+\"Width\",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function et(e,t,n){var r=Ie(e),i=(!m.boxSizingReliable()||n)&&\"border-box\"===E.css(e,\"boxSizing\",!1,r),o=i,a=Fe(e,t,r),s=\"offset\"+t[0].toUpperCase()+t.slice(1);if(Pe.test(a)){if(!n)return a;a=\"auto\"}return(!m.boxSizingReliable()&&i||!m.reliableTrDimensions()&&S(e,\"tr\")||\"auto\"===a||!parseFloat(a)&&\"inline\"===E.css(e,\"display\",!1,r))&&e.getClientRects().length&&(i=\"border-box\"===E.css(e,\"boxSizing\",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Ze(e,t,n||(i?\"border\":\"content\"),o,r,a)+\"px\"}E.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=He.test(t),l=e.style;if(u||(t=Ve(s)),a=E.cssHooks[t]||E.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];\"string\"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=function(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return E.css(e,t,\"\")},u=s(),l=n&&n[3]||(E.cssNumber[t]?\"\":\"px\"),c=e.nodeType&&(E.cssNumber[t]||\"px\"!==l&&+u)&&te.exec(E.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)E.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,E.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}(e,t,i),o=\"number\"),null!=n&&n==n&&(\"number\"!==o||u||(n+=i&&i[3]||(E.cssNumber[s]?\"\":\"px\")),m.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(l[t]=\"inherit\"),a&&\"set\"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return He.test(t)||(t=Ve(s)),(a=E.cssHooks[t]||E.cssHooks[s])&&\"get\"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),\"normal\"===i&&t in Ke&&(i=Ke[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),E.each([\"height\",\"width\"],function(e,u){E.cssHooks[u]={get:function(e,t,n){if(t)return!Ye.test(E.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,u,n):Re(e,Ge,function(){return et(e,u,n)})},set:function(e,t,n){var r,i=Ie(e),o=!m.scrollboxSize()&&\"absolute\"===i.position,a=(o||n)&&\"border-box\"===E.css(e,\"boxSizing\",!1,i),s=n?Ze(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e[\"offset\"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Ze(e,u,\"border\",!1,i)-.5)),s&&(r=te.exec(t))&&\"px\"!==(r[3]||\"px\")&&(e.style[u]=t,t=E.css(e,u)),Je(0,t,s)}}}),E.cssHooks.marginLeft=$e(m.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,\"marginLeft\"))||e.getBoundingClientRect().left-Re(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+\"px\"}),E.each({margin:\"\",padding:\"\",border:\"Width\"},function(i,o){E.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r=\"string\"==typeof e?e.split(\" \"):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},\"margin\"!==i&&(E.cssHooks[i+o].set=Je)}),E.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Ie(e),i=t.length;a<i;a++)o[t[a]]=E.css(e,t[a],!1,r);return o}return void 0!==n?E.style(e,t,n):E.css(e,t)},e,t,1<arguments.length)}}),E.fn.delay=function(r,e){return r=E.fx&&E.fx.speeds[r]||r,e=e||\"fx\",this.queue(e,function(e,t){var n=g.setTimeout(e,r);t.stop=function(){g.clearTimeout(n)}})},Xe=w.createElement(\"input\"),Qe=w.createElement(\"select\").appendChild(w.createElement(\"option\")),Xe.type=\"checkbox\",m.checkOn=\"\"!==Xe.value,m.optSelected=Qe.selected,(Xe=w.createElement(\"input\")).value=\"t\",Xe.type=\"radio\",m.radioValue=\"t\"===Xe.value;var tt,nt=E.expr.attrHandle;E.fn.extend({attr:function(e,t){return $(this,E.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){E.removeAttr(this,e)})}}),E.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?E.prop(e,t,n):(1===o&&E.isXMLDoc(e)||(i=E.attrHooks[t.toLowerCase()]||(E.expr.match.bool.test(t)?tt:void 0)),void 0!==n?null===n?void E.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:null==(r=E.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!m.radioValue&&\"radio\"===t&&S(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(H);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),tt={set:function(e,t,n){return!1===t?E.removeAttr(e,n):e.setAttribute(n,n),n}},E.each(E.expr.match.bool.source.match(/\\w+/g),function(e,t){var a=nt[t]||E.find.attr;nt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=nt[o],nt[o]=r,r=null!=a(e,t,n)?o:null,nt[o]=i),r}});var rt=/^(?:input|select|textarea|button)$/i,it=/^(?:a|area)$/i;function ot(e){return(e.match(H)||[]).join(\" \")}function at(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function st(e){return Array.isArray(e)?e:\"string\"==typeof e&&e.match(H)||[]}E.fn.extend({prop:function(e,t){return $(this,E.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[E.propFix[e]||e]})}}),E.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&E.isXMLDoc(e)||(t=E.propFix[t]||t,i=E.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=E.find.attr(e,\"tabindex\");return t?parseInt(t,10):rt.test(e.nodeName)||it.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),m.optSelected||(E.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),E.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){E.propFix[this.toLowerCase()]=this}),E.fn.extend({addClass:function(t){var e,n,r,i,o,a;return b(t)?this.each(function(e){E(this).addClass(t.call(this,e,at(this)))}):(e=st(t)).length?this.each(function(){if(r=at(this),n=1===this.nodeType&&\" \"+ot(r)+\" \"){for(o=0;o<e.length;o++)i=e[o],n.indexOf(\" \"+i+\" \")<0&&(n+=i+\" \");a=ot(n),r!==a&&this.setAttribute(\"class\",a)}}):this},removeClass:function(t){var e,n,r,i,o,a;return b(t)?this.each(function(e){E(this).removeClass(t.call(this,e,at(this)))}):arguments.length?(e=st(t)).length?this.each(function(){if(r=at(this),n=1===this.nodeType&&\" \"+ot(r)+\" \"){for(o=0;o<e.length;o++){i=e[o];while(-1<n.indexOf(\" \"+i+\" \"))n=n.replace(\" \"+i+\" \",\" \")}a=ot(n),r!==a&&this.setAttribute(\"class\",a)}}):this:this.attr(\"class\",\"\")},toggleClass:function(t,n){var e,r,i,o,a=typeof t,s=\"string\"===a||Array.isArray(t);return b(t)?this.each(function(e){E(this).toggleClass(t.call(this,e,at(this),n),n)}):\"boolean\"==typeof n&&s?n?this.addClass(t):this.removeClass(t):(e=st(t),this.each(function(){if(s)for(o=E(this),i=0;i<e.length;i++)r=e[i],o.hasClass(r)?o.removeClass(r):o.addClass(r);else void 0!==t&&\"boolean\"!==a||((r=at(this))&&Y.set(this,\"__className__\",r),this.setAttribute&&this.setAttribute(\"class\",r||!1===t?\"\":Y.get(this,\"__className__\")||\"\"))}))},hasClass:function(e){var t,n,r=0;t=\" \"+e+\" \";while(n=this[r++])if(1===n.nodeType&&-1<(\" \"+ot(at(n))+\" \").indexOf(t))return!0;return!1}});var ut=/\\r/g;E.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=b(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,E(this).val()):n)?t=\"\":\"number\"==typeof t?t+=\"\":Array.isArray(t)&&(t=E.map(t,function(e){return null==e?\"\":e+\"\"})),(r=E.valHooks[this.type]||E.valHooks[this.nodeName.toLowerCase()])&&\"set\"in r&&void 0!==r.set(this,t,\"value\")||(this.value=t))})):t?(r=E.valHooks[t.type]||E.valHooks[t.nodeName.toLowerCase()])&&\"get\"in r&&void 0!==(e=r.get(t,\"value\"))?e:\"string\"==typeof(e=t.value)?e.replace(ut,\"\"):null==e?\"\":e:void 0}}),E.extend({valHooks:{option:{get:function(e){var t=E.find.attr(e,\"value\");return null!=t?t:ot(E.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a=\"select-one\"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!S(n.parentNode,\"optgroup\"))){if(t=E(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=E.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<E.inArray(E.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),E.each([\"radio\",\"checkbox\"],function(){E.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<E.inArray(E(e).val(),t)}},m.checkOn||(E.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})}),m.focusin=\"onfocusin\"in g;var lt=/^(?:focusinfocus|focusoutblur)$/,ct=function(e){e.stopPropagation()};E.extend(E.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,d=[n||w],p=y.call(e,\"type\")?e.type:e,h=y.call(e,\"namespace\")?e.namespace.split(\".\"):[];if(o=f=a=n=n||w,3!==n.nodeType&&8!==n.nodeType&&!lt.test(p+E.event.triggered)&&(-1<p.indexOf(\".\")&&(p=(h=p.split(\".\")).shift(),h.sort()),u=p.indexOf(\":\")<0&&\"on\"+p,(e=e[E.expando]?e:new E.Event(p,\"object\"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join(\".\"),e.rnamespace=e.namespace?new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:E.makeArray(t,[e]),c=E.event.special[p]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||p,lt.test(s+p)||(o=o.parentNode);o;o=o.parentNode)d.push(o),a=o;a===(n.ownerDocument||w)&&d.push(a.defaultView||a.parentWindow||g)}i=0;while((o=d[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||p,(l=(Y.get(o,\"events\")||Object.create(null))[e.type]&&Y.get(o,\"handle\"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&X(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=p,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(d.pop(),t)||!X(n)||u&&b(n[p])&&!x(n)&&((a=n[u])&&(n[u]=null),E.event.triggered=p,e.isPropagationStopped()&&f.addEventListener(p,ct),n[p](),e.isPropagationStopped()&&f.removeEventListener(p,ct),E.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=E.extend(new E.Event,n,{type:e,isSimulated:!0});E.event.trigger(r,null,t)}}),E.fn.extend({trigger:function(e,t){return this.each(function(){E.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return E.event.trigger(e,t,n,!0)}}),m.focusin||E.each({focus:\"focusin\",blur:\"focusout\"},function(n,r){var i=function(e){E.event.simulate(r,e.target,E.event.fix(e))};E.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}}),E.parseXML=function(e){var t,n;if(!e||\"string\"!=typeof e)return null;try{t=(new g.DOMParser).parseFromString(e,\"text/xml\")}catch(e){}return n=t&&t.getElementsByTagName(\"parsererror\")[0],t&&!n||E.error(\"Invalid XML: \"+(n?E.map(n.childNodes,function(e){return e.textContent}).join(\"\\n\"):e)),t};var ft,dt=/\\[\\]$/,pt=/\\r?\\n/g,ht=/^(?:submit|button|image|reset|file)$/i,gt=/^(?:input|select|textarea|keygen)/i;function vt(n,e,r,i){var t;if(Array.isArray(e))E.each(e,function(e,t){r||dt.test(n)?i(n,t):vt(n+\"[\"+(\"object\"==typeof t&&null!=t?e:\"\")+\"]\",t,r,i)});else if(r||\"object\"!==T(e))i(n,e);else for(t in e)vt(n+\"[\"+t+\"]\",e[t],r,i)}E.param=function(e,t){var n,r=[],i=function(e,t){var n=b(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(null==e)return\"\";if(Array.isArray(e)||e.jquery&&!E.isPlainObject(e))E.each(e,function(){i(this.name,this.value)});else for(n in e)vt(n,e[n],t,i);return r.join(\"&\")},E.fn.extend({serialize:function(){return E.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=E.prop(this,\"elements\");return e?E.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!E(this).is(\":disabled\")&&gt.test(this.nodeName)&&!ht.test(e)&&(this.checked||!fe.test(e))}).map(function(e,t){var n=E(this).val();return null==n?null:Array.isArray(n)?E.map(n,function(e){return{name:t.name,value:e.replace(pt,\"\\r\\n\")}}):{name:t.name,value:n.replace(pt,\"\\r\\n\")}}).get()}}),E.fn.extend({wrapAll:function(e){var t;return this[0]&&(b(e)&&(e=e.call(this[0])),t=E(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return b(n)?this.each(function(e){E(this).wrapInner(n.call(this,e))}):this.each(function(){var e=E(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=b(t);return this.each(function(e){E(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not(\"body\").each(function(){E(this).replaceWith(this.childNodes)}),this}}),E.expr.pseudos.hidden=function(e){return!E.expr.pseudos.visible(e)},E.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},m.createHTMLDocument=((ft=w.implementation.createHTMLDocument(\"\").body).innerHTML=\"<form></form><form></form>\",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return\"string\"!=typeof e?[]:(\"boolean\"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,\"position\"),c=E(e),f={};\"static\"===l&&(e.style.position=\"relative\"),s=c.offset(),o=E.css(e,\"top\"),u=E.css(e,\"left\"),(\"absolute\"===l||\"fixed\"===l)&&-1<(o+u).indexOf(\"auto\")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),\"using\"in t?t.using.call(e,f):c.css(f)}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if(\"fixed\"===E.css(r,\"position\"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&\"static\"===E.css(e,\"position\"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,\"borderTopWidth\",!0),i.left+=E.css(e,\"borderLeftWidth\",!0))}return{top:t.top-i.top-E.css(r,\"marginTop\",!0),left:t.left-i.left-E.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&\"static\"===E.css(e,\"position\"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,i){var o=\"pageYOffset\"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each([\"top\",\"left\"],function(e,n){E.cssHooks[n]=$e(m.pixelPosition,function(e,t){if(t)return t=Fe(e,n),Pe.test(t)?E(e).position()[n]+\"px\":t})}),E.each({Height:\"height\",Width:\"width\"},function(a,s){E.each({padding:\"inner\"+a,content:s,\"\":\"outer\"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),i=r||(!0===e||!0===t?\"margin\":\"border\");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf(\"outer\")?e[\"inner\"+a]:e.document.documentElement[\"client\"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+a],r[\"scroll\"+a],e.body[\"offset\"+a],r[\"offset\"+a],r[\"client\"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,n){E.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var yt=/^[\\s\\uFEFF\\xA0]+|([^\\s\\uFEFF\\xA0])[\\s\\uFEFF\\xA0]+$/g;E.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),b(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||E.guid++,i},E.holdReady=function(e){e?E.readyWait++:E.ready(!0)},E.isArray=Array.isArray,E.parseJSON=JSON.parse,E.nodeName=S,E.isFunction=b,E.isWindow=x,E.camelCase=V,E.type=T,E.now=Date.now,E.isNumeric=function(e){var t=E.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},E.trim=function(e){return null==e?\"\":(e+\"\").replace(yt,\"$1\")},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return E});var mt=g.jQuery,bt=g.$;return E.noConflict=function(e){return g.$===E&&(g.$=bt),e&&g.jQuery===E&&(g.jQuery=mt),E},\"undefined\"==typeof e&&(g.jQuery=g.$=E),E});\n","/**\n * [js-md5]{@link https://github.com/emn178/js-md5}\n *\n * @namespace md5\n * @version 0.7.3\n * @author Chen, Yi-Cyuan [emn178@gmail.com]\n * @copyright Chen, Yi-Cyuan 2014-2017\n * @license MIT\n */\n(function () {\n  'use strict';\n\n  var ERROR = 'input is invalid type';\n  var WINDOW = typeof window === 'object';\n  var root = WINDOW ? window : {};\n  if (root.JS_MD5_NO_WINDOW) {\n    WINDOW = false;\n  }\n  var WEB_WORKER = !WINDOW && typeof self === 'object';\n  var NODE_JS = !root.JS_MD5_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;\n  if (NODE_JS) {\n    root = global;\n  } else if (WEB_WORKER) {\n    root = self;\n  }\n  var COMMON_JS = !root.JS_MD5_NO_COMMON_JS && typeof module === 'object' && module.exports;\n  var AMD = typeof define === 'function' && define.amd;\n  var ARRAY_BUFFER = !root.JS_MD5_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';\n  var HEX_CHARS = '0123456789abcdef'.split('');\n  var EXTRA = [128, 32768, 8388608, -2147483648];\n  var SHIFT = [0, 8, 16, 24];\n  var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64'];\n  var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');\n\n  var blocks = [], buffer8;\n  if (ARRAY_BUFFER) {\n    var buffer = new ArrayBuffer(68);\n    buffer8 = new Uint8Array(buffer);\n    blocks = new Uint32Array(buffer);\n  }\n\n  if (root.JS_MD5_NO_NODE_JS || !Array.isArray) {\n    Array.isArray = function (obj) {\n      return Object.prototype.toString.call(obj) === '[object Array]';\n    };\n  }\n\n  if (ARRAY_BUFFER && (root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {\n    ArrayBuffer.isView = function (obj) {\n      return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;\n    };\n  }\n\n  /**\n   * @method hex\n   * @memberof md5\n   * @description Output hash as hex string\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {String} Hex string\n   * @example\n   * md5.hex('The quick brown fox jumps over the lazy dog');\n   * // equal to\n   * md5('The quick brown fox jumps over the lazy dog');\n   */\n  /**\n   * @method digest\n   * @memberof md5\n   * @description Output hash as bytes array\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {Array} Bytes array\n   * @example\n   * md5.digest('The quick brown fox jumps over the lazy dog');\n   */\n  /**\n   * @method array\n   * @memberof md5\n   * @description Output hash as bytes array\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {Array} Bytes array\n   * @example\n   * md5.array('The quick brown fox jumps over the lazy dog');\n   */\n  /**\n   * @method arrayBuffer\n   * @memberof md5\n   * @description Output hash as ArrayBuffer\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {ArrayBuffer} ArrayBuffer\n   * @example\n   * md5.arrayBuffer('The quick brown fox jumps over the lazy dog');\n   */\n  /**\n   * @method buffer\n   * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.\n   * @memberof md5\n   * @description Output hash as ArrayBuffer\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {ArrayBuffer} ArrayBuffer\n   * @example\n   * md5.buffer('The quick brown fox jumps over the lazy dog');\n   */\n  /**\n   * @method base64\n   * @memberof md5\n   * @description Output hash as base64 string\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {String} base64 string\n   * @example\n   * md5.base64('The quick brown fox jumps over the lazy dog');\n   */\n  var createOutputMethod = function (outputType) {\n    return function (message) {\n      return new Md5(true).update(message)[outputType]();\n    };\n  };\n\n  /**\n   * @method create\n   * @memberof md5\n   * @description Create Md5 object\n   * @returns {Md5} Md5 object.\n   * @example\n   * var hash = md5.create();\n   */\n  /**\n   * @method update\n   * @memberof md5\n   * @description Create and update Md5 object\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {Md5} Md5 object.\n   * @example\n   * var hash = md5.update('The quick brown fox jumps over the lazy dog');\n   * // equal to\n   * var hash = md5.create();\n   * hash.update('The quick brown fox jumps over the lazy dog');\n   */\n  var createMethod = function () {\n    var method = createOutputMethod('hex');\n    if (NODE_JS) {\n      method = nodeWrap(method);\n    }\n    method.create = function () {\n      return new Md5();\n    };\n    method.update = function (message) {\n      return method.create().update(message);\n    };\n    for (var i = 0; i < OUTPUT_TYPES.length; ++i) {\n      var type = OUTPUT_TYPES[i];\n      method[type] = createOutputMethod(type);\n    }\n    return method;\n  };\n\n  var nodeWrap = function (method) {\n    var crypto = eval(\"require('crypto')\");\n    var Buffer = eval(\"require('buffer').Buffer\");\n    var nodeMethod = function (message) {\n      if (typeof message === 'string') {\n        return crypto.createHash('md5').update(message, 'utf8').digest('hex');\n      } else {\n        if (message === null || message === undefined) {\n          throw ERROR;\n        } else if (message.constructor === ArrayBuffer) {\n          message = new Uint8Array(message);\n        }\n      }\n      if (Array.isArray(message) || ArrayBuffer.isView(message) ||\n        message.constructor === Buffer) {\n        return crypto.createHash('md5').update(new Buffer(message)).digest('hex');\n      } else {\n        return method(message);\n      }\n    };\n    return nodeMethod;\n  };\n\n  /**\n   * Md5 class\n   * @class Md5\n   * @description This is internal class.\n   * @see {@link md5.create}\n   */\n  function Md5(sharedMemory) {\n    if (sharedMemory) {\n      blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =\n      blocks[4] = blocks[5] = blocks[6] = blocks[7] =\n      blocks[8] = blocks[9] = blocks[10] = blocks[11] =\n      blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n      this.blocks = blocks;\n      this.buffer8 = buffer8;\n    } else {\n      if (ARRAY_BUFFER) {\n        var buffer = new ArrayBuffer(68);\n        this.buffer8 = new Uint8Array(buffer);\n        this.blocks = new Uint32Array(buffer);\n      } else {\n        this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n      }\n    }\n    this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0;\n    this.finalized = this.hashed = false;\n    this.first = true;\n  }\n\n  /**\n   * @method update\n   * @memberof Md5\n   * @instance\n   * @description Update hash\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {Md5} Md5 object.\n   * @see {@link md5.update}\n   */\n  Md5.prototype.update = function (message) {\n    if (this.finalized) {\n      return;\n    }\n\n    var notString, type = typeof message;\n    if (type !== 'string') {\n      if (type === 'object') {\n        if (message === null) {\n          throw ERROR;\n        } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {\n          message = new Uint8Array(message);\n        } else if (!Array.isArray(message)) {\n          if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {\n            throw ERROR;\n          }\n        }\n      } else {\n        throw ERROR;\n      }\n      notString = true;\n    }\n    var code, index = 0, i, length = message.length, blocks = this.blocks;\n    var buffer8 = this.buffer8;\n\n    while (index < length) {\n      if (this.hashed) {\n        this.hashed = false;\n        blocks[0] = blocks[16];\n        blocks[16] = blocks[1] = blocks[2] = blocks[3] =\n        blocks[4] = blocks[5] = blocks[6] = blocks[7] =\n        blocks[8] = blocks[9] = blocks[10] = blocks[11] =\n        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n      }\n\n      if (notString) {\n        if (ARRAY_BUFFER) {\n          for (i = this.start; index < length && i < 64; ++index) {\n            buffer8[i++] = message[index];\n          }\n        } else {\n          for (i = this.start; index < length && i < 64; ++index) {\n            blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];\n          }\n        }\n      } else {\n        if (ARRAY_BUFFER) {\n          for (i = this.start; index < length && i < 64; ++index) {\n            code = message.charCodeAt(index);\n            if (code < 0x80) {\n              buffer8[i++] = code;\n            } else if (code < 0x800) {\n              buffer8[i++] = 0xc0 | (code >> 6);\n              buffer8[i++] = 0x80 | (code & 0x3f);\n            } else if (code < 0xd800 || code >= 0xe000) {\n              buffer8[i++] = 0xe0 | (code >> 12);\n              buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);\n              buffer8[i++] = 0x80 | (code & 0x3f);\n            } else {\n              code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));\n              buffer8[i++] = 0xf0 | (code >> 18);\n              buffer8[i++] = 0x80 | ((code >> 12) & 0x3f);\n              buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);\n              buffer8[i++] = 0x80 | (code & 0x3f);\n            }\n          }\n        } else {\n          for (i = this.start; index < length && i < 64; ++index) {\n            code = message.charCodeAt(index);\n            if (code < 0x80) {\n              blocks[i >> 2] |= code << SHIFT[i++ & 3];\n            } else if (code < 0x800) {\n              blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n            } else if (code < 0xd800 || code >= 0xe000) {\n              blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n            } else {\n              code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));\n              blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n            }\n          }\n        }\n      }\n      this.lastByteIndex = i;\n      this.bytes += i - this.start;\n      if (i >= 64) {\n        this.start = i - 64;\n        this.hash();\n        this.hashed = true;\n      } else {\n        this.start = i;\n      }\n    }\n    if (this.bytes > 4294967295) {\n      this.hBytes += this.bytes / 4294967296 << 0;\n      this.bytes = this.bytes % 4294967296;\n    }\n    return this;\n  };\n\n  Md5.prototype.finalize = function () {\n    if (this.finalized) {\n      return;\n    }\n    this.finalized = true;\n    var blocks = this.blocks, i = this.lastByteIndex;\n    blocks[i >> 2] |= EXTRA[i & 3];\n    if (i >= 56) {\n      if (!this.hashed) {\n        this.hash();\n      }\n      blocks[0] = blocks[16];\n      blocks[16] = blocks[1] = blocks[2] = blocks[3] =\n      blocks[4] = blocks[5] = blocks[6] = blocks[7] =\n      blocks[8] = blocks[9] = blocks[10] = blocks[11] =\n      blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n    }\n    blocks[14] = this.bytes << 3;\n    blocks[15] = this.hBytes << 3 | this.bytes >>> 29;\n    this.hash();\n  };\n\n  Md5.prototype.hash = function () {\n    var a, b, c, d, bc, da, blocks = this.blocks;\n\n    if (this.first) {\n      a = blocks[0] - 680876937;\n      a = (a << 7 | a >>> 25) - 271733879 << 0;\n      d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708;\n      d = (d << 12 | d >>> 20) + a << 0;\n      c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375;\n      c = (c << 17 | c >>> 15) + d << 0;\n      b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209;\n      b = (b << 22 | b >>> 10) + c << 0;\n    } else {\n      a = this.h0;\n      b = this.h1;\n      c = this.h2;\n      d = this.h3;\n      a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936;\n      a = (a << 7 | a >>> 25) + b << 0;\n      d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586;\n      d = (d << 12 | d >>> 20) + a << 0;\n      c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819;\n      c = (c << 17 | c >>> 15) + d << 0;\n      b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330;\n      b = (b << 22 | b >>> 10) + c << 0;\n    }\n\n    a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897;\n    a = (a << 7 | a >>> 25) + b << 0;\n    d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426;\n    d = (d << 12 | d >>> 20) + a << 0;\n    c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341;\n    c = (c << 17 | c >>> 15) + d << 0;\n    b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983;\n    b = (b << 22 | b >>> 10) + c << 0;\n    a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416;\n    a = (a << 7 | a >>> 25) + b << 0;\n    d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417;\n    d = (d << 12 | d >>> 20) + a << 0;\n    c += (b ^ (d & (a ^ b))) + blocks[10] - 42063;\n    c = (c << 17 | c >>> 15) + d << 0;\n    b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162;\n    b = (b << 22 | b >>> 10) + c << 0;\n    a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682;\n    a = (a << 7 | a >>> 25) + b << 0;\n    d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101;\n    d = (d << 12 | d >>> 20) + a << 0;\n    c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290;\n    c = (c << 17 | c >>> 15) + d << 0;\n    b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329;\n    b = (b << 22 | b >>> 10) + c << 0;\n    a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510;\n    a = (a << 5 | a >>> 27) + b << 0;\n    d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632;\n    d = (d << 9 | d >>> 23) + a << 0;\n    c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713;\n    c = (c << 14 | c >>> 18) + d << 0;\n    b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302;\n    b = (b << 20 | b >>> 12) + c << 0;\n    a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691;\n    a = (a << 5 | a >>> 27) + b << 0;\n    d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083;\n    d = (d << 9 | d >>> 23) + a << 0;\n    c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335;\n    c = (c << 14 | c >>> 18) + d << 0;\n    b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848;\n    b = (b << 20 | b >>> 12) + c << 0;\n    a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438;\n    a = (a << 5 | a >>> 27) + b << 0;\n    d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690;\n    d = (d << 9 | d >>> 23) + a << 0;\n    c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961;\n    c = (c << 14 | c >>> 18) + d << 0;\n    b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501;\n    b = (b << 20 | b >>> 12) + c << 0;\n    a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467;\n    a = (a << 5 | a >>> 27) + b << 0;\n    d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784;\n    d = (d << 9 | d >>> 23) + a << 0;\n    c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473;\n    c = (c << 14 | c >>> 18) + d << 0;\n    b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734;\n    b = (b << 20 | b >>> 12) + c << 0;\n    bc = b ^ c;\n    a += (bc ^ d) + blocks[5] - 378558;\n    a = (a << 4 | a >>> 28) + b << 0;\n    d += (bc ^ a) + blocks[8] - 2022574463;\n    d = (d << 11 | d >>> 21) + a << 0;\n    da = d ^ a;\n    c += (da ^ b) + blocks[11] + 1839030562;\n    c = (c << 16 | c >>> 16) + d << 0;\n    b += (da ^ c) + blocks[14] - 35309556;\n    b = (b << 23 | b >>> 9) + c << 0;\n    bc = b ^ c;\n    a += (bc ^ d) + blocks[1] - 1530992060;\n    a = (a << 4 | a >>> 28) + b << 0;\n    d += (bc ^ a) + blocks[4] + 1272893353;\n    d = (d << 11 | d >>> 21) + a << 0;\n    da = d ^ a;\n    c += (da ^ b) + blocks[7] - 155497632;\n    c = (c << 16 | c >>> 16) + d << 0;\n    b += (da ^ c) + blocks[10] - 1094730640;\n    b = (b << 23 | b >>> 9) + c << 0;\n    bc = b ^ c;\n    a += (bc ^ d) + blocks[13] + 681279174;\n    a = (a << 4 | a >>> 28) + b << 0;\n    d += (bc ^ a) + blocks[0] - 358537222;\n    d = (d << 11 | d >>> 21) + a << 0;\n    da = d ^ a;\n    c += (da ^ b) + blocks[3] - 722521979;\n    c = (c << 16 | c >>> 16) + d << 0;\n    b += (da ^ c) + blocks[6] + 76029189;\n    b = (b << 23 | b >>> 9) + c << 0;\n    bc = b ^ c;\n    a += (bc ^ d) + blocks[9] - 640364487;\n    a = (a << 4 | a >>> 28) + b << 0;\n    d += (bc ^ a) + blocks[12] - 421815835;\n    d = (d << 11 | d >>> 21) + a << 0;\n    da = d ^ a;\n    c += (da ^ b) + blocks[15] + 530742520;\n    c = (c << 16 | c >>> 16) + d << 0;\n    b += (da ^ c) + blocks[2] - 995338651;\n    b = (b << 23 | b >>> 9) + c << 0;\n    a += (c ^ (b | ~d)) + blocks[0] - 198630844;\n    a = (a << 6 | a >>> 26) + b << 0;\n    d += (b ^ (a | ~c)) + blocks[7] + 1126891415;\n    d = (d << 10 | d >>> 22) + a << 0;\n    c += (a ^ (d | ~b)) + blocks[14] - 1416354905;\n    c = (c << 15 | c >>> 17) + d << 0;\n    b += (d ^ (c | ~a)) + blocks[5] - 57434055;\n    b = (b << 21 | b >>> 11) + c << 0;\n    a += (c ^ (b | ~d)) + blocks[12] + 1700485571;\n    a = (a << 6 | a >>> 26) + b << 0;\n    d += (b ^ (a | ~c)) + blocks[3] - 1894986606;\n    d = (d << 10 | d >>> 22) + a << 0;\n    c += (a ^ (d | ~b)) + blocks[10] - 1051523;\n    c = (c << 15 | c >>> 17) + d << 0;\n    b += (d ^ (c | ~a)) + blocks[1] - 2054922799;\n    b = (b << 21 | b >>> 11) + c << 0;\n    a += (c ^ (b | ~d)) + blocks[8] + 1873313359;\n    a = (a << 6 | a >>> 26) + b << 0;\n    d += (b ^ (a | ~c)) + blocks[15] - 30611744;\n    d = (d << 10 | d >>> 22) + a << 0;\n    c += (a ^ (d | ~b)) + blocks[6] - 1560198380;\n    c = (c << 15 | c >>> 17) + d << 0;\n    b += (d ^ (c | ~a)) + blocks[13] + 1309151649;\n    b = (b << 21 | b >>> 11) + c << 0;\n    a += (c ^ (b | ~d)) + blocks[4] - 145523070;\n    a = (a << 6 | a >>> 26) + b << 0;\n    d += (b ^ (a | ~c)) + blocks[11] - 1120210379;\n    d = (d << 10 | d >>> 22) + a << 0;\n    c += (a ^ (d | ~b)) + blocks[2] + 718787259;\n    c = (c << 15 | c >>> 17) + d << 0;\n    b += (d ^ (c | ~a)) + blocks[9] - 343485551;\n    b = (b << 21 | b >>> 11) + c << 0;\n\n    if (this.first) {\n      this.h0 = a + 1732584193 << 0;\n      this.h1 = b - 271733879 << 0;\n      this.h2 = c - 1732584194 << 0;\n      this.h3 = d + 271733878 << 0;\n      this.first = false;\n    } else {\n      this.h0 = this.h0 + a << 0;\n      this.h1 = this.h1 + b << 0;\n      this.h2 = this.h2 + c << 0;\n      this.h3 = this.h3 + d << 0;\n    }\n  };\n\n  /**\n   * @method hex\n   * @memberof Md5\n   * @instance\n   * @description Output hash as hex string\n   * @returns {String} Hex string\n   * @see {@link md5.hex}\n   * @example\n   * hash.hex();\n   */\n  Md5.prototype.hex = function () {\n    this.finalize();\n\n    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;\n\n    return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +\n      HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +\n      HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +\n      HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +\n      HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +\n      HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +\n      HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +\n      HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +\n      HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +\n      HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +\n      HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +\n      HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +\n      HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +\n      HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +\n      HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +\n      HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F];\n  };\n\n  /**\n   * @method toString\n   * @memberof Md5\n   * @instance\n   * @description Output hash as hex string\n   * @returns {String} Hex string\n   * @see {@link md5.hex}\n   * @example\n   * hash.toString();\n   */\n  Md5.prototype.toString = Md5.prototype.hex;\n\n  /**\n   * @method digest\n   * @memberof Md5\n   * @instance\n   * @description Output hash as bytes array\n   * @returns {Array} Bytes array\n   * @see {@link md5.digest}\n   * @example\n   * hash.digest();\n   */\n  Md5.prototype.digest = function () {\n    this.finalize();\n\n    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;\n    return [\n      h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF,\n      h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF,\n      h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF,\n      h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF\n    ];\n  };\n\n  /**\n   * @method array\n   * @memberof Md5\n   * @instance\n   * @description Output hash as bytes array\n   * @returns {Array} Bytes array\n   * @see {@link md5.array}\n   * @example\n   * hash.array();\n   */\n  Md5.prototype.array = Md5.prototype.digest;\n\n  /**\n   * @method arrayBuffer\n   * @memberof Md5\n   * @instance\n   * @description Output hash as ArrayBuffer\n   * @returns {ArrayBuffer} ArrayBuffer\n   * @see {@link md5.arrayBuffer}\n   * @example\n   * hash.arrayBuffer();\n   */\n  Md5.prototype.arrayBuffer = function () {\n    this.finalize();\n\n    var buffer = new ArrayBuffer(16);\n    var blocks = new Uint32Array(buffer);\n    blocks[0] = this.h0;\n    blocks[1] = this.h1;\n    blocks[2] = this.h2;\n    blocks[3] = this.h3;\n    return buffer;\n  };\n\n  /**\n   * @method buffer\n   * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.\n   * @memberof Md5\n   * @instance\n   * @description Output hash as ArrayBuffer\n   * @returns {ArrayBuffer} ArrayBuffer\n   * @see {@link md5.buffer}\n   * @example\n   * hash.buffer();\n   */\n  Md5.prototype.buffer = Md5.prototype.arrayBuffer;\n\n  /**\n   * @method base64\n   * @memberof Md5\n   * @instance\n   * @description Output hash as base64 string\n   * @returns {String} base64 string\n   * @see {@link md5.base64}\n   * @example\n   * hash.base64();\n   */\n  Md5.prototype.base64 = function () {\n    var v1, v2, v3, base64Str = '', bytes = this.array();\n    for (var i = 0; i < 15;) {\n      v1 = bytes[i++];\n      v2 = bytes[i++];\n      v3 = bytes[i++];\n      base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +\n        BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] +\n        BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] +\n        BASE64_ENCODE_CHAR[v3 & 63];\n    }\n    v1 = bytes[i];\n    base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +\n      BASE64_ENCODE_CHAR[(v1 << 4) & 63] +\n      '==';\n    return base64Str;\n  };\n\n  var exports = createMethod();\n\n  if (COMMON_JS) {\n    module.exports = exports;\n  } else {\n    /**\n     * @method md5\b\n     * @description Md5 hash function, export to global in browsers.\n     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n     * @returns {String} md5 hashes\n     * @example\n     * md5(''); // d41d8cd98f00b204e9800998ecf8427e\n     * md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6\n     * md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0\n     *\n     * // It also supports UTF-8 encoding\n     * md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07\n     *\n     * // It also supports byte `Array`, `Uint8Array`, `ArrayBuffer`\n     * md5([]); // d41d8cd98f00b204e9800998ecf8427e\n     * md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e\n     */\n    root.md5 = exports;\n    if (AMD) {\n      define(function () {\n        return exports;\n      });\n    }\n  }\n})();\n","/**\n * lodash (Custom Build) <https://lodash.com/>\n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors <https://jquery.org/>\n * Released under MIT license <https://lodash.com/license>\n * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n    arrayTag = '[object Array]',\n    boolTag = '[object Boolean]',\n    dateTag = '[object Date]',\n    errorTag = '[object Error]',\n    funcTag = '[object Function]',\n    genTag = '[object GeneratorFunction]',\n    mapTag = '[object Map]',\n    numberTag = '[object Number]',\n    objectTag = '[object Object]',\n    promiseTag = '[object Promise]',\n    regexpTag = '[object RegExp]',\n    setTag = '[object Set]',\n    stringTag = '[object String]',\n    symbolTag = '[object Symbol]',\n    weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n    dataViewTag = '[object DataView]',\n    float32Tag = '[object Float32Array]',\n    float64Tag = '[object Float64Array]',\n    int8Tag = '[object Int8Array]',\n    int16Tag = '[object Int16Array]',\n    int32Tag = '[object Int32Array]',\n    uint8Tag = '[object Uint8Array]',\n    uint8ClampedTag = '[object Uint8ClampedArray]',\n    uint16Tag = '[object Uint16Array]',\n    uint32Tag = '[object Uint32Array]';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to match `RegExp` flags from their coerced string values. */\nvar reFlags = /\\w*$/;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/** Used to identify `toStringTag` values supported by `_.clone`. */\nvar cloneableTags = {};\ncloneableTags[argsTag] = cloneableTags[arrayTag] =\ncloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =\ncloneableTags[boolTag] = cloneableTags[dateTag] =\ncloneableTags[float32Tag] = cloneableTags[float64Tag] =\ncloneableTags[int8Tag] = cloneableTags[int16Tag] =\ncloneableTags[int32Tag] = cloneableTags[mapTag] =\ncloneableTags[numberTag] = cloneableTags[objectTag] =\ncloneableTags[regexpTag] = cloneableTags[setTag] =\ncloneableTags[stringTag] = cloneableTags[symbolTag] =\ncloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =\ncloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;\ncloneableTags[errorTag] = cloneableTags[funcTag] =\ncloneableTags[weakMapTag] = false;\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/**\n * Adds the key-value `pair` to `map`.\n *\n * @private\n * @param {Object} map The map to modify.\n * @param {Array} pair The key-value pair to add.\n * @returns {Object} Returns `map`.\n */\nfunction addMapEntry(map, pair) {\n  // Don't return `map.set` because it's not chainable in IE 11.\n  map.set(pair[0], pair[1]);\n  return map;\n}\n\n/**\n * Adds `value` to `set`.\n *\n * @private\n * @param {Object} set The set to modify.\n * @param {*} value The value to add.\n * @returns {Object} Returns `set`.\n */\nfunction addSetEntry(set, value) {\n  // Don't return `set.add` because it's not chainable in IE 11.\n  set.add(value);\n  return set;\n}\n\n/**\n * A specialized version of `_.forEach` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns `array`.\n */\nfunction arrayEach(array, iteratee) {\n  var index = -1,\n      length = array ? array.length : 0;\n\n  while (++index < length) {\n    if (iteratee(array[index], index, array) === false) {\n      break;\n    }\n  }\n  return array;\n}\n\n/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n  var index = -1,\n      length = values.length,\n      offset = array.length;\n\n  while (++index < length) {\n    array[offset + index] = values[index];\n  }\n  return array;\n}\n\n/**\n * A specialized version of `_.reduce` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @param {*} [accumulator] The initial value.\n * @param {boolean} [initAccum] Specify using the first element of `array` as\n *  the initial value.\n * @returns {*} Returns the accumulated value.\n */\nfunction arrayReduce(array, iteratee, accumulator, initAccum) {\n  var index = -1,\n      length = array ? array.length : 0;\n\n  if (initAccum && length) {\n    accumulator = array[++index];\n  }\n  while (++index < length) {\n    accumulator = iteratee(accumulator, array[index], index, array);\n  }\n  return accumulator;\n}\n\n/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n  var index = -1,\n      result = Array(n);\n\n  while (++index < n) {\n    result[index] = iteratee(index);\n  }\n  return result;\n}\n\n/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n  return object == null ? undefined : object[key];\n}\n\n/**\n * Checks if `value` is a host object in IE < 9.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a host object, else `false`.\n */\nfunction isHostObject(value) {\n  // Many host objects are `Object` objects that can coerce to strings\n  // despite having improperly defined `toString` methods.\n  var result = false;\n  if (value != null && typeof value.toString != 'function') {\n    try {\n      result = !!(value + '');\n    } catch (e) {}\n  }\n  return result;\n}\n\n/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n  var index = -1,\n      result = Array(map.size);\n\n  map.forEach(function(value, key) {\n    result[++index] = [key, value];\n  });\n  return result;\n}\n\n/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n  return function(arg) {\n    return func(transform(arg));\n  };\n}\n\n/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n  var index = -1,\n      result = Array(set.size);\n\n  set.forEach(function(value) {\n    result[++index] = value;\n  });\n  return result;\n}\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype,\n    funcProto = Function.prototype,\n    objectProto = Object.prototype;\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n  var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n  return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n  funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n  .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined,\n    Symbol = root.Symbol,\n    Uint8Array = root.Uint8Array,\n    getPrototype = overArg(Object.getPrototypeOf, Object),\n    objectCreate = Object.create,\n    propertyIsEnumerable = objectProto.propertyIsEnumerable,\n    splice = arrayProto.splice;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols,\n    nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,\n    nativeKeys = overArg(Object.keys, Object);\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView'),\n    Map = getNative(root, 'Map'),\n    Promise = getNative(root, 'Promise'),\n    Set = getNative(root, 'Set'),\n    WeakMap = getNative(root, 'WeakMap'),\n    nativeCreate = getNative(Object, 'create');\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n    mapCtorString = toSource(Map),\n    promiseCtorString = toSource(Promise),\n    setCtorString = toSource(Set),\n    weakMapCtorString = toSource(WeakMap);\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n    symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n  var index = -1,\n      length = entries ? entries.length : 0;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n  this.__data__ = nativeCreate ? nativeCreate(null) : {};\n}\n\n/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n  return this.has(key) && delete this.__data__[key];\n}\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n  var data = this.__data__;\n  if (nativeCreate) {\n    var result = data[key];\n    return result === HASH_UNDEFINED ? undefined : result;\n  }\n  return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n  var data = this.__data__;\n  return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);\n}\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n  var data = this.__data__;\n  data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n  return this;\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n  var index = -1,\n      length = entries ? entries.length : 0;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n  this.__data__ = [];\n}\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  if (index < 0) {\n    return false;\n  }\n  var lastIndex = data.length - 1;\n  if (index == lastIndex) {\n    data.pop();\n  } else {\n    splice.call(data, index, 1);\n  }\n  return true;\n}\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  return index < 0 ? undefined : data[index][1];\n}\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n  return assocIndexOf(this.__data__, key) > -1;\n}\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  if (index < 0) {\n    data.push([key, value]);\n  } else {\n    data[index][1] = value;\n  }\n  return this;\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n  var index = -1,\n      length = entries ? entries.length : 0;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n  this.__data__ = {\n    'hash': new Hash,\n    'map': new (Map || ListCache),\n    'string': new Hash\n  };\n}\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n  return getMapData(this, key)['delete'](key);\n}\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n  return getMapData(this, key).get(key);\n}\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n  return getMapData(this, key).has(key);\n}\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n  getMapData(this, key).set(key, value);\n  return this;\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n  this.__data__ = new ListCache(entries);\n}\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n  this.__data__ = new ListCache;\n}\n\n/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n  return this.__data__['delete'](key);\n}\n\n/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n  return this.__data__.get(key);\n}\n\n/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n  return this.__data__.has(key);\n}\n\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n  var cache = this.__data__;\n  if (cache instanceof ListCache) {\n    var pairs = cache.__data__;\n    if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n      pairs.push([key, value]);\n      return this;\n    }\n    cache = this.__data__ = new MapCache(pairs);\n  }\n  cache.set(key, value);\n  return this;\n}\n\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n  // Safari 8.1 makes `arguments.callee` enumerable in strict mode.\n  // Safari 9 makes `arguments.length` enumerable in strict mode.\n  var result = (isArray(value) || isArguments(value))\n    ? baseTimes(value.length, String)\n    : [];\n\n  var length = result.length,\n      skipIndexes = !!length;\n\n  for (var key in value) {\n    if ((inherited || hasOwnProperty.call(value, key)) &&\n        !(skipIndexes && (key == 'length' || isIndex(key, length)))) {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\n/**\n * Assigns `value` to `key` of `object` if the existing value is not equivalent\n * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignValue(object, key, value) {\n  var objValue = object[key];\n  if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||\n      (value === undefined && !(key in object))) {\n    object[key] = value;\n  }\n}\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n  var length = array.length;\n  while (length--) {\n    if (eq(array[length][0], key)) {\n      return length;\n    }\n  }\n  return -1;\n}\n\n/**\n * The base implementation of `_.assign` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssign(object, source) {\n  return object && copyObject(source, keys(source), object);\n}\n\n/**\n * The base implementation of `_.clone` and `_.cloneDeep` which tracks\n * traversed objects.\n *\n * @private\n * @param {*} value The value to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @param {boolean} [isFull] Specify a clone including symbols.\n * @param {Function} [customizer] The function to customize cloning.\n * @param {string} [key] The key of `value`.\n * @param {Object} [object] The parent object of `value`.\n * @param {Object} [stack] Tracks traversed objects and their clone counterparts.\n * @returns {*} Returns the cloned value.\n */\nfunction baseClone(value, isDeep, isFull, customizer, key, object, stack) {\n  var result;\n  if (customizer) {\n    result = object ? customizer(value, key, object, stack) : customizer(value);\n  }\n  if (result !== undefined) {\n    return result;\n  }\n  if (!isObject(value)) {\n    return value;\n  }\n  var isArr = isArray(value);\n  if (isArr) {\n    result = initCloneArray(value);\n    if (!isDeep) {\n      return copyArray(value, result);\n    }\n  } else {\n    var tag = getTag(value),\n        isFunc = tag == funcTag || tag == genTag;\n\n    if (isBuffer(value)) {\n      return cloneBuffer(value, isDeep);\n    }\n    if (tag == objectTag || tag == argsTag || (isFunc && !object)) {\n      if (isHostObject(value)) {\n        return object ? value : {};\n      }\n      result = initCloneObject(isFunc ? {} : value);\n      if (!isDeep) {\n        return copySymbols(value, baseAssign(result, value));\n      }\n    } else {\n      if (!cloneableTags[tag]) {\n        return object ? value : {};\n      }\n      result = initCloneByTag(value, tag, baseClone, isDeep);\n    }\n  }\n  // Check for circular references and return its corresponding clone.\n  stack || (stack = new Stack);\n  var stacked = stack.get(value);\n  if (stacked) {\n    return stacked;\n  }\n  stack.set(value, result);\n\n  if (!isArr) {\n    var props = isFull ? getAllKeys(value) : keys(value);\n  }\n  arrayEach(props || value, function(subValue, key) {\n    if (props) {\n      key = subValue;\n      subValue = value[key];\n    }\n    // Recursively populate clone (susceptible to call stack limits).\n    assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack));\n  });\n  return result;\n}\n\n/**\n * The base implementation of `_.create` without support for assigning\n * properties to the created object.\n *\n * @private\n * @param {Object} prototype The object to inherit from.\n * @returns {Object} Returns the new object.\n */\nfunction baseCreate(proto) {\n  return isObject(proto) ? objectCreate(proto) : {};\n}\n\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n  var result = keysFunc(object);\n  return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\n/**\n * The base implementation of `getTag`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n  return objectToString.call(value);\n}\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n *  else `false`.\n */\nfunction baseIsNative(value) {\n  if (!isObject(value) || isMasked(value)) {\n    return false;\n  }\n  var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;\n  return pattern.test(toSource(value));\n}\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n  if (!isPrototype(object)) {\n    return nativeKeys(object);\n  }\n  var result = [];\n  for (var key in Object(object)) {\n    if (hasOwnProperty.call(object, key) && key != 'constructor') {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\n/**\n * Creates a clone of  `buffer`.\n *\n * @private\n * @param {Buffer} buffer The buffer to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Buffer} Returns the cloned buffer.\n */\nfunction cloneBuffer(buffer, isDeep) {\n  if (isDeep) {\n    return buffer.slice();\n  }\n  var result = new buffer.constructor(buffer.length);\n  buffer.copy(result);\n  return result;\n}\n\n/**\n * Creates a clone of `arrayBuffer`.\n *\n * @private\n * @param {ArrayBuffer} arrayBuffer The array buffer to clone.\n * @returns {ArrayBuffer} Returns the cloned array buffer.\n */\nfunction cloneArrayBuffer(arrayBuffer) {\n  var result = new arrayBuffer.constructor(arrayBuffer.byteLength);\n  new Uint8Array(result).set(new Uint8Array(arrayBuffer));\n  return result;\n}\n\n/**\n * Creates a clone of `dataView`.\n *\n * @private\n * @param {Object} dataView The data view to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned data view.\n */\nfunction cloneDataView(dataView, isDeep) {\n  var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;\n  return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);\n}\n\n/**\n * Creates a clone of `map`.\n *\n * @private\n * @param {Object} map The map to clone.\n * @param {Function} cloneFunc The function to clone values.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned map.\n */\nfunction cloneMap(map, isDeep, cloneFunc) {\n  var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map);\n  return arrayReduce(array, addMapEntry, new map.constructor);\n}\n\n/**\n * Creates a clone of `regexp`.\n *\n * @private\n * @param {Object} regexp The regexp to clone.\n * @returns {Object} Returns the cloned regexp.\n */\nfunction cloneRegExp(regexp) {\n  var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));\n  result.lastIndex = regexp.lastIndex;\n  return result;\n}\n\n/**\n * Creates a clone of `set`.\n *\n * @private\n * @param {Object} set The set to clone.\n * @param {Function} cloneFunc The function to clone values.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned set.\n */\nfunction cloneSet(set, isDeep, cloneFunc) {\n  var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set);\n  return arrayReduce(array, addSetEntry, new set.constructor);\n}\n\n/**\n * Creates a clone of the `symbol` object.\n *\n * @private\n * @param {Object} symbol The symbol object to clone.\n * @returns {Object} Returns the cloned symbol object.\n */\nfunction cloneSymbol(symbol) {\n  return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};\n}\n\n/**\n * Creates a clone of `typedArray`.\n *\n * @private\n * @param {Object} typedArray The typed array to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned typed array.\n */\nfunction cloneTypedArray(typedArray, isDeep) {\n  var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;\n  return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);\n}\n\n/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n  var index = -1,\n      length = source.length;\n\n  array || (array = Array(length));\n  while (++index < length) {\n    array[index] = source[index];\n  }\n  return array;\n}\n\n/**\n * Copies properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy properties from.\n * @param {Array} props The property identifiers to copy.\n * @param {Object} [object={}] The object to copy properties to.\n * @param {Function} [customizer] The function to customize copied values.\n * @returns {Object} Returns `object`.\n */\nfunction copyObject(source, props, object, customizer) {\n  object || (object = {});\n\n  var index = -1,\n      length = props.length;\n\n  while (++index < length) {\n    var key = props[index];\n\n    var newValue = customizer\n      ? customizer(object[key], source[key], key, object, source)\n      : undefined;\n\n    assignValue(object, key, newValue === undefined ? source[key] : newValue);\n  }\n  return object;\n}\n\n/**\n * Copies own symbol properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbols(source, object) {\n  return copyObject(source, getSymbols(source), object);\n}\n\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n  return baseGetAllKeys(object, keys, getSymbols);\n}\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n  var data = map.__data__;\n  return isKeyable(key)\n    ? data[typeof key == 'string' ? 'string' : 'hash']\n    : data.map;\n}\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n  var value = getValue(object, key);\n  return baseIsNative(value) ? value : undefined;\n}\n\n/**\n * Creates an array of the own enumerable symbol properties of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = nativeGetSymbols ? overArg(nativeGetSymbols, Object) : stubArray;\n\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11,\n// for data views in Edge < 14, and promises in Node.js.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n    (Map && getTag(new Map) != mapTag) ||\n    (Promise && getTag(Promise.resolve()) != promiseTag) ||\n    (Set && getTag(new Set) != setTag) ||\n    (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n  getTag = function(value) {\n    var result = objectToString.call(value),\n        Ctor = result == objectTag ? value.constructor : undefined,\n        ctorString = Ctor ? toSource(Ctor) : undefined;\n\n    if (ctorString) {\n      switch (ctorString) {\n        case dataViewCtorString: return dataViewTag;\n        case mapCtorString: return mapTag;\n        case promiseCtorString: return promiseTag;\n        case setCtorString: return setTag;\n        case weakMapCtorString: return weakMapTag;\n      }\n    }\n    return result;\n  };\n}\n\n/**\n * Initializes an array clone.\n *\n * @private\n * @param {Array} array The array to clone.\n * @returns {Array} Returns the initialized clone.\n */\nfunction initCloneArray(array) {\n  var length = array.length,\n      result = array.constructor(length);\n\n  // Add properties assigned by `RegExp#exec`.\n  if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {\n    result.index = array.index;\n    result.input = array.input;\n  }\n  return result;\n}\n\n/**\n * Initializes an object clone.\n *\n * @private\n * @param {Object} object The object to clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneObject(object) {\n  return (typeof object.constructor == 'function' && !isPrototype(object))\n    ? baseCreate(getPrototype(object))\n    : {};\n}\n\n/**\n * Initializes an object clone based on its `toStringTag`.\n *\n * **Note:** This function only supports cloning values with tags of\n * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.\n *\n * @private\n * @param {Object} object The object to clone.\n * @param {string} tag The `toStringTag` of the object to clone.\n * @param {Function} cloneFunc The function to clone values.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneByTag(object, tag, cloneFunc, isDeep) {\n  var Ctor = object.constructor;\n  switch (tag) {\n    case arrayBufferTag:\n      return cloneArrayBuffer(object);\n\n    case boolTag:\n    case dateTag:\n      return new Ctor(+object);\n\n    case dataViewTag:\n      return cloneDataView(object, isDeep);\n\n    case float32Tag: case float64Tag:\n    case int8Tag: case int16Tag: case int32Tag:\n    case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:\n      return cloneTypedArray(object, isDeep);\n\n    case mapTag:\n      return cloneMap(object, isDeep, cloneFunc);\n\n    case numberTag:\n    case stringTag:\n      return new Ctor(object);\n\n    case regexpTag:\n      return cloneRegExp(object);\n\n    case setTag:\n      return cloneSet(object, isDeep, cloneFunc);\n\n    case symbolTag:\n      return cloneSymbol(object);\n  }\n}\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n  length = length == null ? MAX_SAFE_INTEGER : length;\n  return !!length &&\n    (typeof value == 'number' || reIsUint.test(value)) &&\n    (value > -1 && value % 1 == 0 && value < length);\n}\n\n/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n  var type = typeof value;\n  return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n    ? (value !== '__proto__')\n    : (value === null);\n}\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n  return !!maskSrcKey && (maskSrcKey in func);\n}\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n  var Ctor = value && value.constructor,\n      proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n  return value === proto;\n}\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to process.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n  if (func != null) {\n    try {\n      return funcToString.call(func);\n    } catch (e) {}\n    try {\n      return (func + '');\n    } catch (e) {}\n  }\n  return '';\n}\n\n/**\n * This method is like `_.clone` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 1.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @returns {*} Returns the deep cloned value.\n * @see _.clone\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var deep = _.cloneDeep(objects);\n * console.log(deep[0] === objects[0]);\n * // => false\n */\nfunction cloneDeep(value) {\n  return baseClone(value, true, true);\n}\n\n/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n  return value === other || (value !== value && other !== other);\n}\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n *  else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nfunction isArguments(value) {\n  // Safari 8.1 makes `arguments.callee` enumerable in strict mode.\n  return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&\n    (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);\n}\n\n/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n  return value != null && isLength(value.length) && !isFunction(value);\n}\n\n/**\n * This method is like `_.isArrayLike` except that it also checks if `value`\n * is an object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array-like object,\n *  else `false`.\n * @example\n *\n * _.isArrayLikeObject([1, 2, 3]);\n * // => true\n *\n * _.isArrayLikeObject(document.body.children);\n * // => true\n *\n * _.isArrayLikeObject('abc');\n * // => false\n *\n * _.isArrayLikeObject(_.noop);\n * // => false\n */\nfunction isArrayLikeObject(value) {\n  return isObjectLike(value) && isArrayLike(value);\n}\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n  // The use of `Object#toString` avoids issues with the `typeof` operator\n  // in Safari 8-9 which returns 'object' for typed array and other constructors.\n  var tag = isObject(value) ? objectToString.call(value) : '';\n  return tag == funcTag || tag == genTag;\n}\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n  return typeof value == 'number' &&\n    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n  var type = typeof value;\n  return !!value && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n  return !!value && typeof value == 'object';\n}\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n *   this.a = 1;\n *   this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n  return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\n/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n  return [];\n}\n\n/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n  return false;\n}\n\nmodule.exports = cloneDeep;\n","/**\n * lodash (Custom Build) <https://lodash.com/>\n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors <https://jquery.org/>\n * Released under MIT license <https://lodash.com/license>\n * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the `TypeError` message for \"Functions\" methods. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/** Used to match leading and trailing whitespace. */\nvar reTrim = /^\\s+|\\s+$/g;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max,\n    nativeMin = Math.min;\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n *   console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n  return root.Date.now();\n};\n\n/**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n *  Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n *  The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n *  Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n *   'leading': true,\n *   'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n  var lastArgs,\n      lastThis,\n      maxWait,\n      result,\n      timerId,\n      lastCallTime,\n      lastInvokeTime = 0,\n      leading = false,\n      maxing = false,\n      trailing = true;\n\n  if (typeof func != 'function') {\n    throw new TypeError(FUNC_ERROR_TEXT);\n  }\n  wait = toNumber(wait) || 0;\n  if (isObject(options)) {\n    leading = !!options.leading;\n    maxing = 'maxWait' in options;\n    maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n    trailing = 'trailing' in options ? !!options.trailing : trailing;\n  }\n\n  function invokeFunc(time) {\n    var args = lastArgs,\n        thisArg = lastThis;\n\n    lastArgs = lastThis = undefined;\n    lastInvokeTime = time;\n    result = func.apply(thisArg, args);\n    return result;\n  }\n\n  function leadingEdge(time) {\n    // Reset any `maxWait` timer.\n    lastInvokeTime = time;\n    // Start the timer for the trailing edge.\n    timerId = setTimeout(timerExpired, wait);\n    // Invoke the leading edge.\n    return leading ? invokeFunc(time) : result;\n  }\n\n  function remainingWait(time) {\n    var timeSinceLastCall = time - lastCallTime,\n        timeSinceLastInvoke = time - lastInvokeTime,\n        result = wait - timeSinceLastCall;\n\n    return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;\n  }\n\n  function shouldInvoke(time) {\n    var timeSinceLastCall = time - lastCallTime,\n        timeSinceLastInvoke = time - lastInvokeTime;\n\n    // Either this is the first call, activity has stopped and we're at the\n    // trailing edge, the system time has gone backwards and we're treating\n    // it as the trailing edge, or we've hit the `maxWait` limit.\n    return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n      (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n  }\n\n  function timerExpired() {\n    var time = now();\n    if (shouldInvoke(time)) {\n      return trailingEdge(time);\n    }\n    // Restart the timer.\n    timerId = setTimeout(timerExpired, remainingWait(time));\n  }\n\n  function trailingEdge(time) {\n    timerId = undefined;\n\n    // Only invoke if we have `lastArgs` which means `func` has been\n    // debounced at least once.\n    if (trailing && lastArgs) {\n      return invokeFunc(time);\n    }\n    lastArgs = lastThis = undefined;\n    return result;\n  }\n\n  function cancel() {\n    if (timerId !== undefined) {\n      clearTimeout(timerId);\n    }\n    lastInvokeTime = 0;\n    lastArgs = lastCallTime = lastThis = timerId = undefined;\n  }\n\n  function flush() {\n    return timerId === undefined ? result : trailingEdge(now());\n  }\n\n  function debounced() {\n    var time = now(),\n        isInvoking = shouldInvoke(time);\n\n    lastArgs = arguments;\n    lastThis = this;\n    lastCallTime = time;\n\n    if (isInvoking) {\n      if (timerId === undefined) {\n        return leadingEdge(lastCallTime);\n      }\n      if (maxing) {\n        // Handle invocations in a tight loop.\n        timerId = setTimeout(timerExpired, wait);\n        return invokeFunc(lastCallTime);\n      }\n    }\n    if (timerId === undefined) {\n      timerId = setTimeout(timerExpired, wait);\n    }\n    return result;\n  }\n  debounced.cancel = cancel;\n  debounced.flush = flush;\n  return debounced;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n  var type = typeof value;\n  return !!value && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n  return !!value && typeof value == 'object';\n}\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n  return typeof value == 'symbol' ||\n    (isObjectLike(value) && objectToString.call(value) == symbolTag);\n}\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n  if (typeof value == 'number') {\n    return value;\n  }\n  if (isSymbol(value)) {\n    return NAN;\n  }\n  if (isObject(value)) {\n    var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n    value = isObject(other) ? (other + '') : other;\n  }\n  if (typeof value != 'string') {\n    return value === 0 ? value : +value;\n  }\n  value = value.replace(reTrim, '');\n  var isBinary = reIsBinary.test(value);\n  return (isBinary || reIsOctal.test(value))\n    ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n    : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nmodule.exports = debounce;\n","/**\n * Lodash (Custom Build) <https://lodash.com/>\n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright JS Foundation and other contributors <https://js.foundation/>\n * Released under MIT license <https://lodash.com/license>\n * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n    COMPARE_UNORDERED_FLAG = 2;\n\n/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n    arrayTag = '[object Array]',\n    asyncTag = '[object AsyncFunction]',\n    boolTag = '[object Boolean]',\n    dateTag = '[object Date]',\n    errorTag = '[object Error]',\n    funcTag = '[object Function]',\n    genTag = '[object GeneratorFunction]',\n    mapTag = '[object Map]',\n    numberTag = '[object Number]',\n    nullTag = '[object Null]',\n    objectTag = '[object Object]',\n    promiseTag = '[object Promise]',\n    proxyTag = '[object Proxy]',\n    regexpTag = '[object RegExp]',\n    setTag = '[object Set]',\n    stringTag = '[object String]',\n    symbolTag = '[object Symbol]',\n    undefinedTag = '[object Undefined]',\n    weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n    dataViewTag = '[object DataView]',\n    float32Tag = '[object Float32Array]',\n    float64Tag = '[object Float64Array]',\n    int8Tag = '[object Int8Array]',\n    int16Tag = '[object Int16Array]',\n    int32Tag = '[object Int32Array]',\n    uint8Tag = '[object Uint8Array]',\n    uint8ClampedTag = '[object Uint8ClampedArray]',\n    uint16Tag = '[object Uint16Array]',\n    uint32Tag = '[object Uint32Array]';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/** Used to identify `toStringTag` values of typed arrays. */\nvar typedArrayTags = {};\ntypedArrayTags[float32Tag] = typedArrayTags[float64Tag] =\ntypedArrayTags[int8Tag] = typedArrayTags[int16Tag] =\ntypedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =\ntypedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =\ntypedArrayTags[uint32Tag] = true;\ntypedArrayTags[argsTag] = typedArrayTags[arrayTag] =\ntypedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =\ntypedArrayTags[dataViewTag] = typedArrayTags[dateTag] =\ntypedArrayTags[errorTag] = typedArrayTags[funcTag] =\ntypedArrayTags[mapTag] = typedArrayTags[numberTag] =\ntypedArrayTags[objectTag] = typedArrayTags[regexpTag] =\ntypedArrayTags[setTag] = typedArrayTags[stringTag] =\ntypedArrayTags[weakMapTag] = false;\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Detect free variable `process` from Node.js. */\nvar freeProcess = moduleExports && freeGlobal.process;\n\n/** Used to access faster Node.js helpers. */\nvar nodeUtil = (function() {\n  try {\n    return freeProcess && freeProcess.binding && freeProcess.binding('util');\n  } catch (e) {}\n}());\n\n/* Node.js helper references. */\nvar nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;\n\n/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n  var index = -1,\n      length = array == null ? 0 : array.length,\n      resIndex = 0,\n      result = [];\n\n  while (++index < length) {\n    var value = array[index];\n    if (predicate(value, index, array)) {\n      result[resIndex++] = value;\n    }\n  }\n  return result;\n}\n\n/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n  var index = -1,\n      length = values.length,\n      offset = array.length;\n\n  while (++index < length) {\n    array[offset + index] = values[index];\n  }\n  return array;\n}\n\n/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n *  else `false`.\n */\nfunction arraySome(array, predicate) {\n  var index = -1,\n      length = array == null ? 0 : array.length;\n\n  while (++index < length) {\n    if (predicate(array[index], index, array)) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n  var index = -1,\n      result = Array(n);\n\n  while (++index < n) {\n    result[index] = iteratee(index);\n  }\n  return result;\n}\n\n/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n  return function(value) {\n    return func(value);\n  };\n}\n\n/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n  return cache.has(key);\n}\n\n/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n  return object == null ? undefined : object[key];\n}\n\n/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n  var index = -1,\n      result = Array(map.size);\n\n  map.forEach(function(value, key) {\n    result[++index] = [key, value];\n  });\n  return result;\n}\n\n/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n  return function(arg) {\n    return func(transform(arg));\n  };\n}\n\n/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n  var index = -1,\n      result = Array(set.size);\n\n  set.forEach(function(value) {\n    result[++index] = value;\n  });\n  return result;\n}\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype,\n    funcProto = Function.prototype,\n    objectProto = Object.prototype;\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n  var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n  return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n  funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n  .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined,\n    Symbol = root.Symbol,\n    Uint8Array = root.Uint8Array,\n    propertyIsEnumerable = objectProto.propertyIsEnumerable,\n    splice = arrayProto.splice,\n    symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols,\n    nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,\n    nativeKeys = overArg(Object.keys, Object);\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView'),\n    Map = getNative(root, 'Map'),\n    Promise = getNative(root, 'Promise'),\n    Set = getNative(root, 'Set'),\n    WeakMap = getNative(root, 'WeakMap'),\n    nativeCreate = getNative(Object, 'create');\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n    mapCtorString = toSource(Map),\n    promiseCtorString = toSource(Promise),\n    setCtorString = toSource(Set),\n    weakMapCtorString = toSource(WeakMap);\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n    symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n  var index = -1,\n      length = entries == null ? 0 : entries.length;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n  this.__data__ = nativeCreate ? nativeCreate(null) : {};\n  this.size = 0;\n}\n\n/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n  var result = this.has(key) && delete this.__data__[key];\n  this.size -= result ? 1 : 0;\n  return result;\n}\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n  var data = this.__data__;\n  if (nativeCreate) {\n    var result = data[key];\n    return result === HASH_UNDEFINED ? undefined : result;\n  }\n  return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n  var data = this.__data__;\n  return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);\n}\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n  var data = this.__data__;\n  this.size += this.has(key) ? 0 : 1;\n  data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n  return this;\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n  var index = -1,\n      length = entries == null ? 0 : entries.length;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n  this.__data__ = [];\n  this.size = 0;\n}\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  if (index < 0) {\n    return false;\n  }\n  var lastIndex = data.length - 1;\n  if (index == lastIndex) {\n    data.pop();\n  } else {\n    splice.call(data, index, 1);\n  }\n  --this.size;\n  return true;\n}\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  return index < 0 ? undefined : data[index][1];\n}\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n  return assocIndexOf(this.__data__, key) > -1;\n}\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  if (index < 0) {\n    ++this.size;\n    data.push([key, value]);\n  } else {\n    data[index][1] = value;\n  }\n  return this;\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n  var index = -1,\n      length = entries == null ? 0 : entries.length;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n  this.size = 0;\n  this.__data__ = {\n    'hash': new Hash,\n    'map': new (Map || ListCache),\n    'string': new Hash\n  };\n}\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n  var result = getMapData(this, key)['delete'](key);\n  this.size -= result ? 1 : 0;\n  return result;\n}\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n  return getMapData(this, key).get(key);\n}\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n  return getMapData(this, key).has(key);\n}\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n  var data = getMapData(this, key),\n      size = data.size;\n\n  data.set(key, value);\n  this.size += data.size == size ? 0 : 1;\n  return this;\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\n/**\n *\n * Creates an array cache object to store unique values.\n *\n * @private\n * @constructor\n * @param {Array} [values] The values to cache.\n */\nfunction SetCache(values) {\n  var index = -1,\n      length = values == null ? 0 : values.length;\n\n  this.__data__ = new MapCache;\n  while (++index < length) {\n    this.add(values[index]);\n  }\n}\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n  this.__data__.set(value, HASH_UNDEFINED);\n  return this;\n}\n\n/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n  return this.__data__.has(value);\n}\n\n// Add methods to `SetCache`.\nSetCache.prototype.add = SetCache.prototype.push = setCacheAdd;\nSetCache.prototype.has = setCacheHas;\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n  var data = this.__data__ = new ListCache(entries);\n  this.size = data.size;\n}\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n  this.__data__ = new ListCache;\n  this.size = 0;\n}\n\n/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n  var data = this.__data__,\n      result = data['delete'](key);\n\n  this.size = data.size;\n  return result;\n}\n\n/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n  return this.__data__.get(key);\n}\n\n/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n  return this.__data__.has(key);\n}\n\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n  var data = this.__data__;\n  if (data instanceof ListCache) {\n    var pairs = data.__data__;\n    if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n      pairs.push([key, value]);\n      this.size = ++data.size;\n      return this;\n    }\n    data = this.__data__ = new MapCache(pairs);\n  }\n  data.set(key, value);\n  this.size = data.size;\n  return this;\n}\n\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n  var isArr = isArray(value),\n      isArg = !isArr && isArguments(value),\n      isBuff = !isArr && !isArg && isBuffer(value),\n      isType = !isArr && !isArg && !isBuff && isTypedArray(value),\n      skipIndexes = isArr || isArg || isBuff || isType,\n      result = skipIndexes ? baseTimes(value.length, String) : [],\n      length = result.length;\n\n  for (var key in value) {\n    if ((inherited || hasOwnProperty.call(value, key)) &&\n        !(skipIndexes && (\n           // Safari 9 has enumerable `arguments.length` in strict mode.\n           key == 'length' ||\n           // Node.js 0.10 has enumerable non-index properties on buffers.\n           (isBuff && (key == 'offset' || key == 'parent')) ||\n           // PhantomJS 2 has enumerable non-index properties on typed arrays.\n           (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||\n           // Skip index properties.\n           isIndex(key, length)\n        ))) {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n  var length = array.length;\n  while (length--) {\n    if (eq(array[length][0], key)) {\n      return length;\n    }\n  }\n  return -1;\n}\n\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n  var result = keysFunc(object);\n  return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n  if (value == null) {\n    return value === undefined ? undefinedTag : nullTag;\n  }\n  return (symToStringTag && symToStringTag in Object(value))\n    ? getRawTag(value)\n    : objectToString(value);\n}\n\n/**\n * The base implementation of `_.isArguments`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n */\nfunction baseIsArguments(value) {\n  return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\n/**\n * The base implementation of `_.isEqual` which supports partial comparisons\n * and tracks traversed objects.\n *\n * @private\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @param {boolean} bitmask The bitmask flags.\n *  1 - Unordered comparison\n *  2 - Partial comparison\n * @param {Function} [customizer] The function to customize comparisons.\n * @param {Object} [stack] Tracks traversed `value` and `other` objects.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n */\nfunction baseIsEqual(value, other, bitmask, customizer, stack) {\n  if (value === other) {\n    return true;\n  }\n  if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {\n    return value !== value && other !== other;\n  }\n  return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);\n}\n\n/**\n * A specialized version of `baseIsEqual` for arrays and objects which performs\n * deep comparisons and tracks traversed objects enabling objects with circular\n * references to be compared.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} [stack] Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {\n  var objIsArr = isArray(object),\n      othIsArr = isArray(other),\n      objTag = objIsArr ? arrayTag : getTag(object),\n      othTag = othIsArr ? arrayTag : getTag(other);\n\n  objTag = objTag == argsTag ? objectTag : objTag;\n  othTag = othTag == argsTag ? objectTag : othTag;\n\n  var objIsObj = objTag == objectTag,\n      othIsObj = othTag == objectTag,\n      isSameTag = objTag == othTag;\n\n  if (isSameTag && isBuffer(object)) {\n    if (!isBuffer(other)) {\n      return false;\n    }\n    objIsArr = true;\n    objIsObj = false;\n  }\n  if (isSameTag && !objIsObj) {\n    stack || (stack = new Stack);\n    return (objIsArr || isTypedArray(object))\n      ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)\n      : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);\n  }\n  if (!(bitmask & COMPARE_PARTIAL_FLAG)) {\n    var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),\n        othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');\n\n    if (objIsWrapped || othIsWrapped) {\n      var objUnwrapped = objIsWrapped ? object.value() : object,\n          othUnwrapped = othIsWrapped ? other.value() : other;\n\n      stack || (stack = new Stack);\n      return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);\n    }\n  }\n  if (!isSameTag) {\n    return false;\n  }\n  stack || (stack = new Stack);\n  return equalObjects(object, other, bitmask, customizer, equalFunc, stack);\n}\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n *  else `false`.\n */\nfunction baseIsNative(value) {\n  if (!isObject(value) || isMasked(value)) {\n    return false;\n  }\n  var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n  return pattern.test(toSource(value));\n}\n\n/**\n * The base implementation of `_.isTypedArray` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n */\nfunction baseIsTypedArray(value) {\n  return isObjectLike(value) &&\n    isLength(value.length) && !!typedArrayTags[baseGetTag(value)];\n}\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n  if (!isPrototype(object)) {\n    return nativeKeys(object);\n  }\n  var result = [];\n  for (var key in Object(object)) {\n    if (hasOwnProperty.call(object, key) && key != 'constructor') {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\n/**\n * A specialized version of `baseIsEqualDeep` for arrays with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Array} array The array to compare.\n * @param {Array} other The other array to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `array` and `other` objects.\n * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.\n */\nfunction equalArrays(array, other, bitmask, customizer, equalFunc, stack) {\n  var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n      arrLength = array.length,\n      othLength = other.length;\n\n  if (arrLength != othLength && !(isPartial && othLength > arrLength)) {\n    return false;\n  }\n  // Assume cyclic values are equal.\n  var stacked = stack.get(array);\n  if (stacked && stack.get(other)) {\n    return stacked == other;\n  }\n  var index = -1,\n      result = true,\n      seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;\n\n  stack.set(array, other);\n  stack.set(other, array);\n\n  // Ignore non-index properties.\n  while (++index < arrLength) {\n    var arrValue = array[index],\n        othValue = other[index];\n\n    if (customizer) {\n      var compared = isPartial\n        ? customizer(othValue, arrValue, index, other, array, stack)\n        : customizer(arrValue, othValue, index, array, other, stack);\n    }\n    if (compared !== undefined) {\n      if (compared) {\n        continue;\n      }\n      result = false;\n      break;\n    }\n    // Recursively compare arrays (susceptible to call stack limits).\n    if (seen) {\n      if (!arraySome(other, function(othValue, othIndex) {\n            if (!cacheHas(seen, othIndex) &&\n                (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {\n              return seen.push(othIndex);\n            }\n          })) {\n        result = false;\n        break;\n      }\n    } else if (!(\n          arrValue === othValue ||\n            equalFunc(arrValue, othValue, bitmask, customizer, stack)\n        )) {\n      result = false;\n      break;\n    }\n  }\n  stack['delete'](array);\n  stack['delete'](other);\n  return result;\n}\n\n/**\n * A specialized version of `baseIsEqualDeep` for comparing objects of\n * the same `toStringTag`.\n *\n * **Note:** This function only supports comparing values with tags of\n * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {string} tag The `toStringTag` of the objects to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {\n  switch (tag) {\n    case dataViewTag:\n      if ((object.byteLength != other.byteLength) ||\n          (object.byteOffset != other.byteOffset)) {\n        return false;\n      }\n      object = object.buffer;\n      other = other.buffer;\n\n    case arrayBufferTag:\n      if ((object.byteLength != other.byteLength) ||\n          !equalFunc(new Uint8Array(object), new Uint8Array(other))) {\n        return false;\n      }\n      return true;\n\n    case boolTag:\n    case dateTag:\n    case numberTag:\n      // Coerce booleans to `1` or `0` and dates to milliseconds.\n      // Invalid dates are coerced to `NaN`.\n      return eq(+object, +other);\n\n    case errorTag:\n      return object.name == other.name && object.message == other.message;\n\n    case regexpTag:\n    case stringTag:\n      // Coerce regexes to strings and treat strings, primitives and objects,\n      // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring\n      // for more details.\n      return object == (other + '');\n\n    case mapTag:\n      var convert = mapToArray;\n\n    case setTag:\n      var isPartial = bitmask & COMPARE_PARTIAL_FLAG;\n      convert || (convert = setToArray);\n\n      if (object.size != other.size && !isPartial) {\n        return false;\n      }\n      // Assume cyclic values are equal.\n      var stacked = stack.get(object);\n      if (stacked) {\n        return stacked == other;\n      }\n      bitmask |= COMPARE_UNORDERED_FLAG;\n\n      // Recursively compare objects (susceptible to call stack limits).\n      stack.set(object, other);\n      var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);\n      stack['delete'](object);\n      return result;\n\n    case symbolTag:\n      if (symbolValueOf) {\n        return symbolValueOf.call(object) == symbolValueOf.call(other);\n      }\n  }\n  return false;\n}\n\n/**\n * A specialized version of `baseIsEqualDeep` for objects with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalObjects(object, other, bitmask, customizer, equalFunc, stack) {\n  var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n      objProps = getAllKeys(object),\n      objLength = objProps.length,\n      othProps = getAllKeys(other),\n      othLength = othProps.length;\n\n  if (objLength != othLength && !isPartial) {\n    return false;\n  }\n  var index = objLength;\n  while (index--) {\n    var key = objProps[index];\n    if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {\n      return false;\n    }\n  }\n  // Assume cyclic values are equal.\n  var stacked = stack.get(object);\n  if (stacked && stack.get(other)) {\n    return stacked == other;\n  }\n  var result = true;\n  stack.set(object, other);\n  stack.set(other, object);\n\n  var skipCtor = isPartial;\n  while (++index < objLength) {\n    key = objProps[index];\n    var objValue = object[key],\n        othValue = other[key];\n\n    if (customizer) {\n      var compared = isPartial\n        ? customizer(othValue, objValue, key, other, object, stack)\n        : customizer(objValue, othValue, key, object, other, stack);\n    }\n    // Recursively compare objects (susceptible to call stack limits).\n    if (!(compared === undefined\n          ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))\n          : compared\n        )) {\n      result = false;\n      break;\n    }\n    skipCtor || (skipCtor = key == 'constructor');\n  }\n  if (result && !skipCtor) {\n    var objCtor = object.constructor,\n        othCtor = other.constructor;\n\n    // Non `Object` object instances with different constructors are not equal.\n    if (objCtor != othCtor &&\n        ('constructor' in object && 'constructor' in other) &&\n        !(typeof objCtor == 'function' && objCtor instanceof objCtor &&\n          typeof othCtor == 'function' && othCtor instanceof othCtor)) {\n      result = false;\n    }\n  }\n  stack['delete'](object);\n  stack['delete'](other);\n  return result;\n}\n\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n  return baseGetAllKeys(object, keys, getSymbols);\n}\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n  var data = map.__data__;\n  return isKeyable(key)\n    ? data[typeof key == 'string' ? 'string' : 'hash']\n    : data.map;\n}\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n  var value = getValue(object, key);\n  return baseIsNative(value) ? value : undefined;\n}\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n  var isOwn = hasOwnProperty.call(value, symToStringTag),\n      tag = value[symToStringTag];\n\n  try {\n    value[symToStringTag] = undefined;\n    var unmasked = true;\n  } catch (e) {}\n\n  var result = nativeObjectToString.call(value);\n  if (unmasked) {\n    if (isOwn) {\n      value[symToStringTag] = tag;\n    } else {\n      delete value[symToStringTag];\n    }\n  }\n  return result;\n}\n\n/**\n * Creates an array of the own enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = !nativeGetSymbols ? stubArray : function(object) {\n  if (object == null) {\n    return [];\n  }\n  object = Object(object);\n  return arrayFilter(nativeGetSymbols(object), function(symbol) {\n    return propertyIsEnumerable.call(object, symbol);\n  });\n};\n\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n    (Map && getTag(new Map) != mapTag) ||\n    (Promise && getTag(Promise.resolve()) != promiseTag) ||\n    (Set && getTag(new Set) != setTag) ||\n    (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n  getTag = function(value) {\n    var result = baseGetTag(value),\n        Ctor = result == objectTag ? value.constructor : undefined,\n        ctorString = Ctor ? toSource(Ctor) : '';\n\n    if (ctorString) {\n      switch (ctorString) {\n        case dataViewCtorString: return dataViewTag;\n        case mapCtorString: return mapTag;\n        case promiseCtorString: return promiseTag;\n        case setCtorString: return setTag;\n        case weakMapCtorString: return weakMapTag;\n      }\n    }\n    return result;\n  };\n}\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n  length = length == null ? MAX_SAFE_INTEGER : length;\n  return !!length &&\n    (typeof value == 'number' || reIsUint.test(value)) &&\n    (value > -1 && value % 1 == 0 && value < length);\n}\n\n/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n  var type = typeof value;\n  return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n    ? (value !== '__proto__')\n    : (value === null);\n}\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n  return !!maskSrcKey && (maskSrcKey in func);\n}\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n  var Ctor = value && value.constructor,\n      proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n  return value === proto;\n}\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n  return nativeObjectToString.call(value);\n}\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n  if (func != null) {\n    try {\n      return funcToString.call(func);\n    } catch (e) {}\n    try {\n      return (func + '');\n    } catch (e) {}\n  }\n  return '';\n}\n\n/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n  return value === other || (value !== value && other !== other);\n}\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n *  else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n  return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n    !propertyIsEnumerable.call(value, 'callee');\n};\n\n/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n  return value != null && isLength(value.length) && !isFunction(value);\n}\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\n/**\n * Performs a deep comparison between two values to determine if they are\n * equivalent.\n *\n * **Note:** This method supports comparing arrays, array buffers, booleans,\n * date objects, error objects, maps, numbers, `Object` objects, regexes,\n * sets, strings, symbols, and typed arrays. `Object` objects are compared\n * by their own, not inherited, enumerable properties. Functions and DOM\n * nodes are compared by strict equality, i.e. `===`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.isEqual(object, other);\n * // => true\n *\n * object === other;\n * // => false\n */\nfunction isEqual(value, other) {\n  return baseIsEqual(value, other);\n}\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n  if (!isObject(value)) {\n    return false;\n  }\n  // The use of `Object#toString` avoids issues with the `typeof` operator\n  // in Safari 9 which returns 'object' for typed arrays and other constructors.\n  var tag = baseGetTag(value);\n  return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n  return typeof value == 'number' &&\n    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n  var type = typeof value;\n  return value != null && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n  return value != null && typeof value == 'object';\n}\n\n/**\n * Checks if `value` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\nvar isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n *   this.a = 1;\n *   this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n  return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\n/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n  return [];\n}\n\n/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n  return false;\n}\n\nmodule.exports = isEqual;\n","var grammar = module.exports = {\n  v: [{\n    name: 'version',\n    reg: /^(\\d*)$/\n  }],\n  o: [{ //o=- 20518 0 IN IP4 203.0.113.1\n    // NB: sessionId will be a String in most cases because it is huge\n    name: 'origin',\n    reg: /^(\\S*) (\\d*) (\\d*) (\\S*) IP(\\d) (\\S*)/,\n    names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],\n    format: '%s %s %d %s IP%d %s'\n  }],\n  // default parsing of these only (though some of these feel outdated)\n  s: [{ name: 'name' }],\n  i: [{ name: 'description' }],\n  u: [{ name: 'uri' }],\n  e: [{ name: 'email' }],\n  p: [{ name: 'phone' }],\n  z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..\n  r: [{ name: 'repeats' }],   // TODO: this one can also be parsed properly\n  //k: [{}], // outdated thing ignored\n  t: [{ //t=0 0\n    name: 'timing',\n    reg: /^(\\d*) (\\d*)/,\n    names: ['start', 'stop'],\n    format: '%d %d'\n  }],\n  c: [{ //c=IN IP4 10.47.197.26\n    name: 'connection',\n    reg: /^IN IP(\\d) (\\S*)/,\n    names: ['version', 'ip'],\n    format: 'IN IP%d %s'\n  }],\n  b: [{ //b=AS:4000\n    push: 'bandwidth',\n    reg: /^(TIAS|AS|CT|RR|RS):(\\d*)/,\n    names: ['type', 'limit'],\n    format: '%s:%s'\n  }],\n  m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31\n    // NB: special - pushes to session\n    // TODO: rtp/fmtp should be filtered by the payloads found here?\n    reg: /^(\\w*) (\\d*) ([\\w\\/]*)(?: (.*))?/,\n    names: ['type', 'port', 'protocol', 'payloads'],\n    format: '%s %d %s %s'\n  }],\n  a: [\n    { //a=rtpmap:110 opus/48000/2\n      push: 'rtp',\n      reg: /^rtpmap:(\\d*) ([\\w\\-\\.]*)(?:\\s*\\/(\\d*)(?:\\s*\\/(\\S*))?)?/,\n      names: ['payload', 'codec', 'rate', 'encoding'],\n      format: function (o) {\n        return (o.encoding) ?\n          'rtpmap:%d %s/%s/%s':\n          o.rate ?\n          'rtpmap:%d %s/%s':\n          'rtpmap:%d %s';\n      }\n    },\n    { //a=fmtp:108 profile-level-id=24;object=23;bitrate=64000\n      //a=fmtp:111 minptime=10; useinbandfec=1\n      push: 'fmtp',\n      reg: /^fmtp:(\\d*) ([\\S| ]*)/,\n      names: ['payload', 'config'],\n      format: 'fmtp:%d %s'\n    },\n    { //a=control:streamid=0\n      name: 'control',\n      reg: /^control:(.*)/,\n      format: 'control:%s'\n    },\n    { //a=rtcp:65179 IN IP4 193.84.77.194\n      name: 'rtcp',\n      reg: /^rtcp:(\\d*)(?: (\\S*) IP(\\d) (\\S*))?/,\n      names: ['port', 'netType', 'ipVer', 'address'],\n      format: function (o) {\n        return (o.address != null) ?\n          'rtcp:%d %s IP%d %s':\n          'rtcp:%d';\n      }\n    },\n    { //a=rtcp-fb:98 trr-int 100\n      push: 'rtcpFbTrrInt',\n      reg: /^rtcp-fb:(\\*|\\d*) trr-int (\\d*)/,\n      names: ['payload', 'value'],\n      format: 'rtcp-fb:%d trr-int %d'\n    },\n    { //a=rtcp-fb:98 nack rpsi\n      push: 'rtcpFb',\n      reg: /^rtcp-fb:(\\*|\\d*) ([\\w-_]*)(?: ([\\w-_]*))?/,\n      names: ['payload', 'type', 'subtype'],\n      format: function (o) {\n        return (o.subtype != null) ?\n          'rtcp-fb:%s %s %s':\n          'rtcp-fb:%s %s';\n      }\n    },\n    { //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\n      //a=extmap:1/recvonly URI-gps-string\n      push: 'ext',\n      reg: /^extmap:(\\d+)(?:\\/(\\w+))? (\\S*)(?: (\\S*))?/,\n      names: ['value', 'direction', 'uri', 'config'],\n      format: function (o) {\n        return 'extmap:%d' + (o.direction ? '/%s' : '%v') + ' %s' + (o.config ? ' %s' : '');\n      }\n    },\n    { //a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32\n      push: 'crypto',\n      reg: /^crypto:(\\d*) ([\\w_]*) (\\S*)(?: (\\S*))?/,\n      names: ['id', 'suite', 'config', 'sessionConfig'],\n      format: function (o) {\n        return (o.sessionConfig != null) ?\n          'crypto:%d %s %s %s':\n          'crypto:%d %s %s';\n      }\n    },\n    { //a=setup:actpass\n      name: 'setup',\n      reg: /^setup:(\\w*)/,\n      format: 'setup:%s'\n    },\n    { //a=mid:1\n      name: 'mid',\n      reg: /^mid:([^\\s]*)/,\n      format: 'mid:%s'\n    },\n    { //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a\n      name: 'msid',\n      reg: /^msid:(.*)/,\n      format: 'msid:%s'\n    },\n    { //a=ptime:20\n      name: 'ptime',\n      reg: /^ptime:(\\d*)/,\n      format: 'ptime:%d'\n    },\n    { //a=maxptime:60\n      name: 'maxptime',\n      reg: /^maxptime:(\\d*)/,\n      format: 'maxptime:%d'\n    },\n    { //a=sendrecv\n      name: 'direction',\n      reg: /^(sendrecv|recvonly|sendonly|inactive)/\n    },\n    { //a=ice-lite\n      name: 'icelite',\n      reg: /^(ice-lite)/\n    },\n    { //a=ice-ufrag:F7gI\n      name: 'iceUfrag',\n      reg: /^ice-ufrag:(\\S*)/,\n      format: 'ice-ufrag:%s'\n    },\n    { //a=ice-pwd:x9cml/YzichV2+XlhiMu8g\n      name: 'icePwd',\n      reg: /^ice-pwd:(\\S*)/,\n      format: 'ice-pwd:%s'\n    },\n    { //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33\n      name: 'fingerprint',\n      reg: /^fingerprint:(\\S*) (\\S*)/,\n      names: ['type', 'hash'],\n      format: 'fingerprint:%s %s'\n    },\n    { //a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\n      //a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10\n      //a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0 network-id 3 network-cost 10\n      //a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10\n      //a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0 network-id 3 network-cost 10\n      push:'candidates',\n      reg: /^candidate:(\\S*) (\\d*) (\\S*) (\\d*) (\\S*) (\\d*) typ (\\S*)(?: raddr (\\S*) rport (\\d*))?(?: tcptype (\\S*))?(?: generation (\\d*))?(?: network-id (\\d*))?(?: network-cost (\\d*))?/,\n      names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation', 'network-id', 'network-cost'],\n      format: function (o) {\n        var str = 'candidate:%s %d %s %d %s %d typ %s';\n\n        str += (o.raddr != null) ? ' raddr %s rport %d' : '%v%v';\n\n        // NB: candidate has three optional chunks, so %void middles one if it's missing\n        str += (o.tcptype != null) ? ' tcptype %s' : '%v';\n\n        if (o.generation != null) {\n          str += ' generation %d';\n        }\n\n        str += (o['network-id'] != null) ? ' network-id %d' : '%v';\n        str += (o['network-cost'] != null) ? ' network-cost %d' : '%v';\n        return str;\n      }\n    },\n    { //a=end-of-candidates (keep after the candidates line for readability)\n      name: 'endOfCandidates',\n      reg: /^(end-of-candidates)/\n    },\n    { //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...\n      name: 'remoteCandidates',\n      reg: /^remote-candidates:(.*)/,\n      format: 'remote-candidates:%s'\n    },\n    { //a=ice-options:google-ice\n      name: 'iceOptions',\n      reg: /^ice-options:(\\S*)/,\n      format: 'ice-options:%s'\n    },\n    { //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1\n      push: 'ssrcs',\n      reg: /^ssrc:(\\d*) ([\\w_]*)(?::(.*))?/,\n      names: ['id', 'attribute', 'value'],\n      format: function (o) {\n        var str = 'ssrc:%d';\n        if (o.attribute != null) {\n          str += ' %s';\n          if (o.value != null) {\n            str += ':%s';\n          }\n        }\n        return str;\n      }\n    },\n    { //a=ssrc-group:FEC 1 2\n      //a=ssrc-group:FEC-FR 3004364195 1080772241\n      push: 'ssrcGroups',\n      // token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E\n      reg: /^ssrc-group:([\\x21\\x23\\x24\\x25\\x26\\x27\\x2A\\x2B\\x2D\\x2E\\w]*) (.*)/,\n      names: ['semantics', 'ssrcs'],\n      format: 'ssrc-group:%s %s'\n    },\n    { //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV\n      name: 'msidSemantic',\n      reg: /^msid-semantic:\\s?(\\w*) (\\S*)/,\n      names: ['semantic', 'token'],\n      format: 'msid-semantic: %s %s' // space after ':' is not accidental\n    },\n    { //a=group:BUNDLE audio video\n      push: 'groups',\n      reg: /^group:(\\w*) (.*)/,\n      names: ['type', 'mids'],\n      format: 'group:%s %s'\n    },\n    { //a=rtcp-mux\n      name: 'rtcpMux',\n      reg: /^(rtcp-mux)/\n    },\n    { //a=rtcp-rsize\n      name: 'rtcpRsize',\n      reg: /^(rtcp-rsize)/\n    },\n    { //a=sctpmap:5000 webrtc-datachannel 1024\n      name: 'sctpmap',\n      reg: /^sctpmap:([\\w_\\/]*) (\\S*)(?: (\\S*))?/,\n      names: ['sctpmapNumber', 'app', 'maxMessageSize'],\n      format: function (o) {\n        return (o.maxMessageSize != null) ?\n          'sctpmap:%s %s %s' :\n          'sctpmap:%s %s';\n      }\n    },\n    { //a=x-google-flag:conference\n      name: 'xGoogleFlag',\n      reg: /^x-google-flag:([^\\s]*)/,\n      format: 'x-google-flag:%s'\n    },\n    { //a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0\n      push: 'rids',\n      reg: /^rid:([\\d\\w]+) (\\w+)(?: ([\\S| ]*))?/,\n      names: ['id', 'direction', 'params'],\n      format: function (o) {\n        return (o.params) ? 'rid:%s %s %s' : 'rid:%s %s';\n      }\n    },\n    { //a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]\n      //a=imageattr:* send [x=800,y=640] recv *\n      //a=imageattr:100 recv [x=320,y=240]\n      push: 'imageattrs',\n      reg: new RegExp(\n        //a=imageattr:97\n        '^imageattr:(\\\\d+|\\\\*)' +\n        //send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320]\n        '[\\\\s\\\\t]+(send|recv)[\\\\s\\\\t]+(\\\\*|\\\\[\\\\S+\\\\](?:[\\\\s\\\\t]+\\\\[\\\\S+\\\\])*)' +\n        //recv [x=330,y=250]\n        '(?:[\\\\s\\\\t]+(recv|send)[\\\\s\\\\t]+(\\\\*|\\\\[\\\\S+\\\\](?:[\\\\s\\\\t]+\\\\[\\\\S+\\\\])*))?'\n      ),\n      names: ['pt', 'dir1', 'attrs1', 'dir2', 'attrs2'],\n      format: function (o) {\n        return 'imageattr:%s %s %s' + (o.dir2 ? ' %s %s' : '');\n      }\n    },\n    { //a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8\n      //a=simulcast:recv 1;4,5 send 6;7\n      name: 'simulcast',\n      reg: new RegExp(\n        //a=simulcast:\n        '^simulcast:' +\n        //send 1,2,3;~4,~5\n        '(send|recv) ([a-zA-Z0-9\\\\-_~;,]+)' +\n        //space + recv 6;~7,~8\n        '(?:\\\\s?(send|recv) ([a-zA-Z0-9\\\\-_~;,]+))?' +\n        //end\n        '$'\n      ),\n      names: ['dir1', 'list1', 'dir2', 'list2'],\n      format: function (o) {\n        return 'simulcast:%s %s' + (o.dir2 ? ' %s %s' : '');\n      }\n    },\n    { //Old simulcast draft 03 (implemented by Firefox)\n      //  https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03\n      //a=simulcast: recv pt=97;98 send pt=97\n      //a=simulcast: send rid=5;6;7 paused=6,7\n      name: 'simulcast_03',\n      reg: /^simulcast:[\\s\\t]+([\\S+\\s\\t]+)$/,\n      names: ['value'],\n      format: 'simulcast: %s'\n    },\n    {\n      //a=framerate:25\n      //a=framerate:29.97\n      name: 'framerate',\n      reg: /^framerate:(\\d+(?:$|\\.\\d+))/,\n      format: 'framerate:%s'\n    },\n    { // any a= that we don't understand is kepts verbatim on media.invalid\n      push: 'invalid',\n      names: ['value']\n    }\n  ]\n};\n\n// set sensible defaults to avoid polluting the grammar with boring details\nObject.keys(grammar).forEach(function (key) {\n  var objs = grammar[key];\n  objs.forEach(function (obj) {\n    if (!obj.reg) {\n      obj.reg = /(.*)/;\n    }\n    if (!obj.format) {\n      obj.format = '%s';\n    }\n  });\n});\n","var parser = require('./parser');\nvar writer = require('./writer');\n\nexports.write = writer;\nexports.parse = parser.parse;\nexports.parseFmtpConfig = parser.parseFmtpConfig;\nexports.parseParams = parser.parseParams;\nexports.parsePayloads = parser.parsePayloads;\nexports.parseRemoteCandidates = parser.parseRemoteCandidates;\nexports.parseImageAttributes = parser.parseImageAttributes;\nexports.parseSimulcastStreamList = parser.parseSimulcastStreamList;\n","var toIntIfInt = function (v) {\n  return String(Number(v)) === v ? Number(v) : v;\n};\n\nvar attachProperties = function (match, location, names, rawName) {\n  if (rawName && !names) {\n    location[rawName] = toIntIfInt(match[1]);\n  }\n  else {\n    for (var i = 0; i < names.length; i += 1) {\n      if (match[i+1] != null) {\n        location[names[i]] = toIntIfInt(match[i+1]);\n      }\n    }\n  }\n};\n\nvar parseReg = function (obj, location, content) {\n  var needsBlank = obj.name && obj.names;\n  if (obj.push && !location[obj.push]) {\n    location[obj.push] = [];\n  }\n  else if (needsBlank && !location[obj.name]) {\n    location[obj.name] = {};\n  }\n  var keyLocation = obj.push ?\n    {} :  // blank object that will be pushed\n    needsBlank ? location[obj.name] : location; // otherwise, named location or root\n\n  attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);\n\n  if (obj.push) {\n    location[obj.push].push(keyLocation);\n  }\n};\n\nvar grammar = require('./grammar');\nvar validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);\n\nexports.parse = function (sdp) {\n  var session = {}\n    , media = []\n    , location = session; // points at where properties go under (one of the above)\n\n  // parse lines we understand\n  sdp.split(/(\\r\\n|\\r|\\n)/).filter(validLine).forEach(function (l) {\n    var type = l[0];\n    var content = l.slice(2);\n    if (type === 'm') {\n      media.push({rtp: [], fmtp: []});\n      location = media[media.length-1]; // point at latest media line\n    }\n\n    for (var j = 0; j < (grammar[type] || []).length; j += 1) {\n      var obj = grammar[type][j];\n      if (obj.reg.test(content)) {\n        return parseReg(obj, location, content);\n      }\n    }\n  });\n\n  session.media = media; // link it up\n  return session;\n};\n\nvar paramReducer = function (acc, expr) {\n  var s = expr.split(/=(.+)/, 2);\n  if (s.length === 2) {\n    acc[s[0]] = toIntIfInt(s[1]);\n  }\n  return acc;\n};\n\nexports.parseParams = function (str) {\n  return str.split(/\\;\\s?/).reduce(paramReducer, {});\n};\n\n// For backward compatibility - alias will be removed in 3.0.0\nexports.parseFmtpConfig = exports.parseParams;\n\nexports.parsePayloads = function (str) {\n  return str.split(' ').map(Number);\n};\n\nexports.parseRemoteCandidates = function (str) {\n  var candidates = [];\n  var parts = str.split(' ').map(toIntIfInt);\n  for (var i = 0; i < parts.length; i += 3) {\n    candidates.push({\n      component: parts[i],\n      ip: parts[i + 1],\n      port: parts[i + 2]\n    });\n  }\n  return candidates;\n};\n\nexports.parseImageAttributes = function (str) {\n  return str.split(' ').map(function (item) {\n    return item.substring(1, item.length-1).split(',').reduce(paramReducer, {});\n  });\n};\n\nexports.parseSimulcastStreamList = function (str) {\n  return str.split(';').map(function (stream) {\n    return stream.split(',').map(function (format) {\n      var scid, paused = false;\n\n      if (format[0] !== '~') {\n        scid = toIntIfInt(format);\n      } else {\n        scid = toIntIfInt(format.substring(1, format.length));\n        paused = true;\n      }\n\n      return {\n        scid: scid,\n        paused: paused\n      };\n    });\n  });\n};\n","var grammar = require('./grammar');\n\n// customized util.format - discards excess arguments and can void middle ones\nvar formatRegExp = /%[sdv%]/g;\nvar format = function (formatStr) {\n  var i = 1;\n  var args = arguments;\n  var len = args.length;\n  return formatStr.replace(formatRegExp, function (x) {\n    if (i >= len) {\n      return x; // missing argument\n    }\n    var arg = args[i];\n    i += 1;\n    switch (x) {\n    case '%%':\n      return '%';\n    case '%s':\n      return String(arg);\n    case '%d':\n      return Number(arg);\n    case '%v':\n      return '';\n    }\n  });\n  // NB: we discard excess arguments - they are typically undefined from makeLine\n};\n\nvar makeLine = function (type, obj, location) {\n  var str = obj.format instanceof Function ?\n    (obj.format(obj.push ? location : location[obj.name])) :\n    obj.format;\n\n  var args = [type + '=' + str];\n  if (obj.names) {\n    for (var i = 0; i < obj.names.length; i += 1) {\n      var n = obj.names[i];\n      if (obj.name) {\n        args.push(location[obj.name][n]);\n      }\n      else { // for mLine and push attributes\n        args.push(location[obj.names[i]]);\n      }\n    }\n  }\n  else {\n    args.push(location[obj.name]);\n  }\n  return format.apply(null, args);\n};\n\n// RFC specified order\n// TODO: extend this with all the rest\nvar defaultOuterOrder = [\n  'v', 'o', 's', 'i',\n  'u', 'e', 'p', 'c',\n  'b', 't', 'r', 'z', 'a'\n];\nvar defaultInnerOrder = ['i', 'c', 'b', 'a'];\n\n\nmodule.exports = function (session, opts) {\n  opts = opts || {};\n  // ensure certain properties exist\n  if (session.version == null) {\n    session.version = 0; // 'v=0' must be there (only defined version atm)\n  }\n  if (session.name == null) {\n    session.name = ' '; // 's= ' must be there if no meaningful name set\n  }\n  session.media.forEach(function (mLine) {\n    if (mLine.payloads == null) {\n      mLine.payloads = '';\n    }\n  });\n\n  var outerOrder = opts.outerOrder || defaultOuterOrder;\n  var innerOrder = opts.innerOrder || defaultInnerOrder;\n  var sdp = [];\n\n  // loop through outerOrder for matching properties on session\n  outerOrder.forEach(function (type) {\n    grammar[type].forEach(function (obj) {\n      if (obj.name in session && session[obj.name] != null) {\n        sdp.push(makeLine(type, obj, session));\n      }\n      else if (obj.push in session && session[obj.push] != null) {\n        session[obj.push].forEach(function (el) {\n          sdp.push(makeLine(type, obj, el));\n        });\n      }\n    });\n  });\n\n  // then for each media line, follow the innerOrder\n  session.media.forEach(function (mLine) {\n    sdp.push(makeLine('m', grammar.m[0], mLine));\n\n    innerOrder.forEach(function (type) {\n      grammar[type].forEach(function (obj) {\n        if (obj.name in mLine && mLine[obj.name] != null) {\n          sdp.push(makeLine(type, obj, mLine));\n        }\n        else if (obj.push in mLine && mLine[obj.push] != null) {\n          mLine[obj.push].forEach(function (el) {\n            sdp.push(makeLine(type, obj, el));\n          });\n        }\n      });\n    });\n  });\n\n  return sdp.join('\\r\\n') + '\\r\\n';\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).substr(2, 10);\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.substr(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.substr(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.substr(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  };\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 + '\\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.substr(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.substr(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.substr(7, sp - 7), 10),\n  };\n  const colon = line.indexOf(':', sp);\n  if (colon > -1) {\n    parts.attribute = line.substr(sp + 1, colon - sp - 1);\n    parts.value = line.substr(colon + 1);\n  } else {\n    parts.attribute = line.substr(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.substr(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.substr(6);\n  }\n};\n\n// Parses a fingerprint line for DTLS-SRTP.\nSDPUtils.parseFingerprint = function(line) {\n  const parts = line.substr(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.substr(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.substr(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.substr(12),\n    password: pwd.substr(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  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:<pt> 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  // 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 += ' 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.substr(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].substr(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].substr(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].substr(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].substr(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].substr(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      .substr(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, 21);\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].substr(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].substr(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].substr(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.substr(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","(function (global, factory) {\n            typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n            typeof define === 'function' && define.amd ? define(['exports'], factory) :\n            (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.strophe = {}));\n})(this, (function (exports) { 'use strict';\n\n            var global$1 = typeof global !== \"undefined\" ? global : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {};\n\n            /*\n             * This module provides uniform\n             * Shims APIs and globals that are not present in all JS environments,\n             * the most common example for Strophe being browser APIs like WebSocket\n             * and DOM that don't exist under nodejs.\n             *\n             * Usually these will be supplied in nodejs by conditionally requiring a\n             * NPM module that provides a compatible implementation.\n             */\n\n            /* global global */\n\n            /**\n             * WHATWG WebSockets API\n             * https://www.w3.org/TR/websockets/\n             *\n             * Interface to use the web socket protocol\n             *\n             * Used implementations:\n             * - supported browsers: built-in in WebSocket global\n             *   https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Browser_compatibility\n             * - nodejs: use standard-compliant 'ws' module\n             *   https://www.npmjs.com/package/ws\n             */\n            function getWebSocketImplementation() {\n              let WebSocketImplementation = global$1.WebSocket;\n\n              if (typeof WebSocketImplementation === 'undefined') {\n                try {\n                  WebSocketImplementation = require('ws');\n                } catch (err) {\n                  throw new Error('You must install the \"ws\" package to use Strophe in nodejs.');\n                }\n              }\n\n              return WebSocketImplementation;\n            }\n\n            const WebSocket = getWebSocketImplementation();\n            /**\n             * DOMParser\n             * https://w3c.github.io/DOM-Parsing/#the-domparser-interface\n             *\n             * Interface to parse XML strings into Document objects\n             *\n             * Used implementations:\n             * - supported browsers: built-in in DOMParser global\n             *   https://developer.mozilla.org/en-US/docs/Web/API/DOMParser#Browser_compatibility\n             * - nodejs: use '@xmldom/xmldom' module\n             *   https://www.npmjs.com/package/@xmldom/xmldom\n             */\n\n            function getDOMParserImplementation() {\n              let DOMParserImplementation = global$1.DOMParser;\n\n              if (typeof DOMParserImplementation === 'undefined') {\n                try {\n                  DOMParserImplementation = require('@xmldom/xmldom').DOMParser;\n                } catch (err) {\n                  throw new Error('You must install the \"@xmldom/xmldom\" package to use Strophe in nodejs.');\n                }\n              }\n\n              return DOMParserImplementation;\n            }\n\n            const DOMParser = getDOMParserImplementation();\n            /**\n             *  Gets IE xml doc object. Used by getDummyXMLDocument shim.\n             *\n             *  Returns:\n             *    A Microsoft XML DOM Object\n             *  See Also:\n             *    http://msdn.microsoft.com/en-us/library/ms757837%28VS.85%29.aspx\n             */\n\n            function _getIEXmlDom() {\n              const docStrings = [\"Msxml2.DOMDocument.6.0\", \"Msxml2.DOMDocument.5.0\", \"Msxml2.DOMDocument.4.0\", \"MSXML2.DOMDocument.3.0\", \"MSXML2.DOMDocument\", \"MSXML.DOMDocument\", \"Microsoft.XMLDOM\"];\n\n              for (let d = 0; d < docStrings.length; d++) {\n                try {\n                  // eslint-disable-next-line no-undef\n                  const doc = new ActiveXObject(docStrings[d]);\n                  return doc;\n                } catch (e) {// Try next one\n                }\n              }\n            }\n            /**\n             * Creates a dummy XML DOM document to serve as an element and text node generator.\n             *\n             * Used implementations:\n             *  - IE < 10: avoid using createDocument() due to a memory leak, use ie-specific\n             *    workaround\n             *  - other supported browsers: use document's createDocument\n             *  - nodejs: use '@xmldom/xmldom'\n             */\n\n\n            function getDummyXMLDOMDocument() {\n              // nodejs\n              if (typeof document === 'undefined') {\n                try {\n                  const DOMImplementation = require('@xmldom/xmldom').DOMImplementation;\n\n                  return new DOMImplementation().createDocument('jabber:client', 'strophe', null);\n                } catch (err) {\n                  throw new Error('You must install the \"@xmldom/xmldom\" package to use Strophe in nodejs.');\n                }\n              } // IE < 10\n\n\n              if (document.implementation.createDocument === undefined || document.implementation.createDocument && document.documentMode && document.documentMode < 10) {\n                const doc = _getIEXmlDom();\n\n                doc.appendChild(doc.createElement('strophe'));\n                return doc;\n              } // All other supported browsers\n\n\n              return document.implementation.createDocument('jabber:client', 'strophe', null);\n            }\n\n            /*\n             * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message\n             * Digest Algorithm, as defined in RFC 1321.\n             * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.\n             * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\n             * Distributed under the BSD License\n             * See http://pajhome.org.uk/crypt/md5 for more info.\n             */\n\n            /*\n             * Everything that isn't used by Strophe has been stripped here!\n             */\n\n            /*\n             * Add integers, wrapping at 2^32. This uses 16-bit operations internally\n             * to work around bugs in some JS interpreters.\n             */\n            const safe_add$1 = function (x, y) {\n              const lsw = (x & 0xFFFF) + (y & 0xFFFF);\n              const msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n              return msw << 16 | lsw & 0xFFFF;\n            };\n            /*\n             * Bitwise rotate a 32-bit number to the left.\n             */\n\n\n            const bit_rol = function (num, cnt) {\n              return num << cnt | num >>> 32 - cnt;\n            };\n            /*\n             * Convert a string to an array of little-endian words\n             */\n\n\n            const str2binl = function (str) {\n              if (typeof str !== \"string\") {\n                throw new Error(\"str2binl was passed a non-string\");\n              }\n\n              const bin = [];\n\n              for (let i = 0; i < str.length * 8; i += 8) {\n                bin[i >> 5] |= (str.charCodeAt(i / 8) & 255) << i % 32;\n              }\n\n              return bin;\n            };\n            /*\n             * Convert an array of little-endian words to a string\n             */\n\n\n            const binl2str = function (bin) {\n              let str = \"\";\n\n              for (let i = 0; i < bin.length * 32; i += 8) {\n                str += String.fromCharCode(bin[i >> 5] >>> i % 32 & 255);\n              }\n\n              return str;\n            };\n            /*\n             * Convert an array of little-endian words to a hex string.\n             */\n\n\n            const binl2hex = function (binarray) {\n              const hex_tab = \"0123456789abcdef\";\n              let str = \"\";\n\n              for (let i = 0; i < binarray.length * 4; i++) {\n                str += hex_tab.charAt(binarray[i >> 2] >> i % 4 * 8 + 4 & 0xF) + hex_tab.charAt(binarray[i >> 2] >> i % 4 * 8 & 0xF);\n              }\n\n              return str;\n            };\n            /*\n             * These functions implement the four basic operations the algorithm uses.\n             */\n\n\n            const md5_cmn = function (q, a, b, x, s, t) {\n              return safe_add$1(bit_rol(safe_add$1(safe_add$1(a, q), safe_add$1(x, t)), s), b);\n            };\n\n            const md5_ff = function (a, b, c, d, x, s, t) {\n              return md5_cmn(b & c | ~b & d, a, b, x, s, t);\n            };\n\n            const md5_gg = function (a, b, c, d, x, s, t) {\n              return md5_cmn(b & d | c & ~d, a, b, x, s, t);\n            };\n\n            const md5_hh = function (a, b, c, d, x, s, t) {\n              return md5_cmn(b ^ c ^ d, a, b, x, s, t);\n            };\n\n            const md5_ii = function (a, b, c, d, x, s, t) {\n              return md5_cmn(c ^ (b | ~d), a, b, x, s, t);\n            };\n            /*\n             * Calculate the MD5 of an array of little-endian words, and a bit length\n             */\n\n\n            const core_md5 = function (x, len) {\n              /* append padding */\n              x[len >> 5] |= 0x80 << len % 32;\n              x[(len + 64 >>> 9 << 4) + 14] = len;\n              let a = 1732584193;\n              let b = -271733879;\n              let c = -1732584194;\n              let d = 271733878;\n              let olda, oldb, oldc, oldd;\n\n              for (let i = 0; i < x.length; i += 16) {\n                olda = a;\n                oldb = b;\n                oldc = c;\n                oldd = d;\n                a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);\n                d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);\n                c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);\n                b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);\n                a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);\n                d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);\n                c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);\n                b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);\n                a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);\n                d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);\n                c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);\n                b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);\n                a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);\n                d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);\n                c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);\n                b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);\n                a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);\n                d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);\n                c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);\n                b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);\n                a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);\n                d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);\n                c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);\n                b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);\n                a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);\n                d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);\n                c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);\n                b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);\n                a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);\n                d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);\n                c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);\n                b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);\n                a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);\n                d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);\n                c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);\n                b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);\n                a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);\n                d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);\n                c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);\n                b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);\n                a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);\n                d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);\n                c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);\n                b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);\n                a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);\n                d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);\n                c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);\n                b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);\n                a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);\n                d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);\n                c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);\n                b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);\n                a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);\n                d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);\n                c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);\n                b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);\n                a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);\n                d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);\n                c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);\n                b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);\n                a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);\n                d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);\n                c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);\n                b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);\n                a = safe_add$1(a, olda);\n                b = safe_add$1(b, oldb);\n                c = safe_add$1(c, oldc);\n                d = safe_add$1(d, oldd);\n              }\n\n              return [a, b, c, d];\n            };\n            /*\n             * These are the functions you'll usually want to call.\n             * They take string arguments and return either hex or base-64 encoded\n             * strings.\n             */\n\n\n            const MD5 = {\n              hexdigest: function (s) {\n                return binl2hex(core_md5(str2binl(s), s.length * 8));\n              },\n              hash: function (s) {\n                return binl2str(core_md5(str2binl(s), s.length * 8));\n              }\n            };\n\n            /** Class: Strophe.SASLMechanism\n             *\n             *  Encapsulates an SASL authentication mechanism.\n             *\n             *  User code may override the priority for each mechanism or disable it completely.\n             *  See <priority> for information about changing priority and <test> for informatian on\n             *  how to disable a mechanism.\n             *\n             *  By default, all mechanisms are enabled and the priorities are\n             *\n             *      SCRAM-SHA-1 - 60\n             *      PLAIN       - 50\n             *      OAUTHBEARER - 40\n             *      X-OAUTH2    - 30\n             *      ANONYMOUS   - 20\n             *      EXTERNAL    - 10\n             *\n             *  See: Strophe.Connection.addSupportedSASLMechanisms\n             */\n            class SASLMechanism {\n              /**\n               * PrivateConstructor: Strophe.SASLMechanism\n               * SASL auth mechanism abstraction.\n               *\n               *  Parameters:\n               *    (String) name - SASL Mechanism name.\n               *    (Boolean) isClientFirst - If client should send response first without challenge.\n               *    (Number) priority - Priority.\n               *\n               *  Returns:\n               *    A new Strophe.SASLMechanism object.\n               */\n              constructor(name, isClientFirst, priority) {\n                /** PrivateVariable: mechname\n                 *  Mechanism name.\n                 */\n                this.mechname = name;\n                /** PrivateVariable: isClientFirst\n                 *  If client sends response without initial server challenge.\n                 */\n\n                this.isClientFirst = isClientFirst;\n                /** Variable: priority\n                 *  Determines which <SASLMechanism> is chosen for authentication (Higher is better).\n                 *  Users may override this to prioritize mechanisms differently.\n                 *\n                 *  Example: (This will cause Strophe to choose the mechanism that the server sent first)\n                 *\n                 *  > Strophe.SASLPlain.priority = Strophe.SASLSHA1.priority;\n                 *\n                 *  See <SASL mechanisms> for a list of available mechanisms.\n                 *\n                 */\n\n                this.priority = priority;\n              }\n              /**\n               *  Function: test\n               *  Checks if mechanism able to run.\n               *  To disable a mechanism, make this return false;\n               *\n               *  To disable plain authentication run\n               *  > Strophe.SASLPlain.test = function() {\n               *  >   return false;\n               *  > }\n               *\n               *  See <SASL mechanisms> for a list of available mechanisms.\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - Target Connection.\n               *\n               *  Returns:\n               *    (Boolean) If mechanism was able to run.\n               */\n\n\n              test() {\n                // eslint-disable-line class-methods-use-this\n                return true;\n              }\n              /** PrivateFunction: onStart\n               *  Called before starting mechanism on some connection.\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - Target Connection.\n               */\n\n\n              onStart(connection) {\n                this._connection = connection;\n              }\n              /** PrivateFunction: onChallenge\n               *  Called by protocol implementation on incoming challenge.\n               *\n               *  By deafult, if the client is expected to send data first (isClientFirst === true),\n               *  this method is called with `challenge` as null on the first call,\n               *  unless `clientChallenge` is overridden in the relevant subclass.\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - Target Connection.\n               *    (String) challenge - current challenge to handle.\n               *\n               *  Returns:\n               *    (String) Mechanism response.\n               */\n\n\n              onChallenge(connection, challenge) {\n                // eslint-disable-line\n                throw new Error(\"You should implement challenge handling!\");\n              }\n              /** PrivateFunction: clientChallenge\n               *  Called by the protocol implementation if the client is expected to send\n               *  data first in the authentication exchange (i.e. isClientFirst === true).\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - Target Connection.\n               *\n               *  Returns:\n               *    (String) Mechanism response.\n               */\n\n\n              clientChallenge(connection) {\n                if (!this.isClientFirst) {\n                  throw new Error(\"clientChallenge should not be called if isClientFirst is false!\");\n                }\n\n                return this.onChallenge(connection);\n              }\n              /** PrivateFunction: onFailure\n               *  Protocol informs mechanism implementation about SASL failure.\n               */\n\n\n              onFailure() {\n                this._connection = null;\n              }\n              /** PrivateFunction: onSuccess\n               *  Protocol informs mechanism implementation about SASL success.\n               */\n\n\n              onSuccess() {\n                this._connection = null;\n              }\n\n            }\n\n            class SASLAnonymous extends SASLMechanism {\n              /** PrivateConstructor: SASLAnonymous\n               *  SASL ANONYMOUS authentication.\n               */\n              constructor() {\n                let mechname = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'ANONYMOUS';\n                let isClientFirst = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n                let priority = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 20;\n                super(mechname, isClientFirst, priority);\n              }\n\n              test(connection) {\n                // eslint-disable-line class-methods-use-this\n                return connection.authcid === null;\n              }\n\n            }\n\n            class SASLExternal extends SASLMechanism {\n              /** PrivateConstructor: SASLExternal\n               *  SASL EXTERNAL authentication.\n               *\n               *  The EXTERNAL mechanism allows a client to request the server to use\n               *  credentials established by means external to the mechanism to\n               *  authenticate the client. The external means may be, for instance,\n               *  TLS services.\n               */\n              constructor() {\n                let mechname = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'EXTERNAL';\n                let isClientFirst = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n                let priority = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;\n                super(mechname, isClientFirst, priority);\n              }\n\n              onChallenge(connection) {\n                // eslint-disable-line class-methods-use-this\n\n                /** According to XEP-178, an authzid SHOULD NOT be presented when the\n                 * authcid contained or implied in the client certificate is the JID (i.e.\n                 * authzid) with which the user wants to log in as.\n                 *\n                 * To NOT send the authzid, the user should therefore set the authcid equal\n                 * to the JID when instantiating a new Strophe.Connection object.\n                 */\n                return connection.authcid === connection.authzid ? '' : connection.authzid;\n              }\n\n            }\n\n            const utils = {\n              utf16to8: function (str) {\n                var i, c;\n                var out = \"\";\n                var len = str.length;\n\n                for (i = 0; i < len; i++) {\n                  c = str.charCodeAt(i);\n\n                  if (c >= 0x0000 && c <= 0x007F) {\n                    out += str.charAt(i);\n                  } else if (c > 0x07FF) {\n                    out += String.fromCharCode(0xE0 | c >> 12 & 0x0F);\n                    out += String.fromCharCode(0x80 | c >> 6 & 0x3F);\n                    out += String.fromCharCode(0x80 | c >> 0 & 0x3F);\n                  } else {\n                    out += String.fromCharCode(0xC0 | c >> 6 & 0x1F);\n                    out += String.fromCharCode(0x80 | c >> 0 & 0x3F);\n                  }\n                }\n\n                return out;\n              },\n              addCookies: function (cookies) {\n                /* Parameters:\n                 *  (Object) cookies - either a map of cookie names\n                 *    to string values or to maps of cookie values.\n                 *\n                 * For example:\n                 * { \"myCookie\": \"1234\" }\n                 *\n                 * or:\n                 * { \"myCookie\": {\n                 *      \"value\": \"1234\",\n                 *      \"domain\": \".example.org\",\n                 *      \"path\": \"/\",\n                 *      \"expires\": expirationDate\n                 *      }\n                 *  }\n                 *\n                 *  These values get passed to Strophe.Connection via\n                 *   options.cookies\n                 */\n                cookies = cookies || {};\n\n                for (const cookieName in cookies) {\n                  if (Object.prototype.hasOwnProperty.call(cookies, cookieName)) {\n                    let expires = '';\n                    let domain = '';\n                    let path = '';\n                    const cookieObj = cookies[cookieName];\n                    const isObj = typeof cookieObj === \"object\";\n                    const cookieValue = escape(unescape(isObj ? cookieObj.value : cookieObj));\n\n                    if (isObj) {\n                      expires = cookieObj.expires ? \";expires=\" + cookieObj.expires : '';\n                      domain = cookieObj.domain ? \";domain=\" + cookieObj.domain : '';\n                      path = cookieObj.path ? \";path=\" + cookieObj.path : '';\n                    }\n\n                    document.cookie = cookieName + '=' + cookieValue + expires + domain + path;\n                  }\n                }\n              }\n            };\n\n            class SASLOAuthBearer extends SASLMechanism {\n              /** PrivateConstructor: SASLOAuthBearer\n               *  SASL OAuth Bearer authentication.\n               */\n              constructor() {\n                let mechname = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'OAUTHBEARER';\n                let isClientFirst = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n                let priority = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 40;\n                super(mechname, isClientFirst, priority);\n              }\n\n              test(connection) {\n                // eslint-disable-line class-methods-use-this\n                return connection.pass !== null;\n              }\n\n              onChallenge(connection) {\n                // eslint-disable-line class-methods-use-this\n                let auth_str = 'n,';\n\n                if (connection.authcid !== null) {\n                  auth_str = auth_str + 'a=' + connection.authzid;\n                }\n\n                auth_str = auth_str + ',';\n                auth_str = auth_str + \"\\u0001\";\n                auth_str = auth_str + 'auth=Bearer ';\n                auth_str = auth_str + connection.pass;\n                auth_str = auth_str + \"\\u0001\";\n                auth_str = auth_str + \"\\u0001\";\n                return utils.utf16to8(auth_str);\n              }\n\n            }\n\n            class SASLPlain extends SASLMechanism {\n              /** PrivateConstructor: SASLPlain\n               *  SASL PLAIN authentication.\n               */\n              constructor() {\n                let mechname = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'PLAIN';\n                let isClientFirst = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n                let priority = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 50;\n                super(mechname, isClientFirst, priority);\n              }\n\n              test(connection) {\n                // eslint-disable-line class-methods-use-this\n                return connection.authcid !== null;\n              }\n\n              onChallenge(connection) {\n                // eslint-disable-line class-methods-use-this\n                const {\n                  authcid,\n                  authzid,\n                  domain,\n                  pass\n                } = connection;\n\n                if (!domain) {\n                  throw new Error(\"SASLPlain onChallenge: domain is not defined!\");\n                } // Only include authzid if it differs from authcid.\n                // See: https://tools.ietf.org/html/rfc6120#section-6.3.8\n\n\n                let auth_str = authzid !== `${authcid}@${domain}` ? authzid : '';\n                auth_str = auth_str + \"\\u0000\";\n                auth_str = auth_str + authcid;\n                auth_str = auth_str + \"\\u0000\";\n                auth_str = auth_str + pass;\n                return utils.utf16to8(auth_str);\n              }\n\n            }\n\n            /*\n             * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined\n             * in FIPS PUB 180-1\n             * Version 2.1a Copyright Paul Johnston 2000 - 2002.\n             * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\n             * Distributed under the BSD License\n             * See http://pajhome.org.uk/crypt/md5 for details.\n             */\n\n            /* global define */\n\n            /* Some functions and variables have been stripped for use with Strophe */\n\n            /*\n             * Calculate the SHA-1 of an array of big-endian words, and a bit length\n             */\n            function core_sha1(x, len) {\n              /* append padding */\n              x[len >> 5] |= 0x80 << 24 - len % 32;\n              x[(len + 64 >> 9 << 4) + 15] = len;\n              var w = new Array(80);\n              var a = 1732584193;\n              var b = -271733879;\n              var c = -1732584194;\n              var d = 271733878;\n              var e = -1009589776;\n              var i, j, t, olda, oldb, oldc, oldd, olde;\n\n              for (i = 0; i < x.length; i += 16) {\n                olda = a;\n                oldb = b;\n                oldc = c;\n                oldd = d;\n                olde = e;\n\n                for (j = 0; j < 80; j++) {\n                  if (j < 16) {\n                    w[j] = x[i + j];\n                  } else {\n                    w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);\n                  }\n\n                  t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j)));\n                  e = d;\n                  d = c;\n                  c = rol(b, 30);\n                  b = a;\n                  a = t;\n                }\n\n                a = safe_add(a, olda);\n                b = safe_add(b, oldb);\n                c = safe_add(c, oldc);\n                d = safe_add(d, oldd);\n                e = safe_add(e, olde);\n              }\n\n              return [a, b, c, d, e];\n            }\n            /*\n             * Perform the appropriate triplet combination function for the current\n             * iteration\n             */\n\n\n            function sha1_ft(t, b, c, d) {\n              if (t < 20) {\n                return b & c | ~b & d;\n              }\n\n              if (t < 40) {\n                return b ^ c ^ d;\n              }\n\n              if (t < 60) {\n                return b & c | b & d | c & d;\n              }\n\n              return b ^ c ^ d;\n            }\n            /*\n             * Determine the appropriate additive constant for the current iteration\n             */\n\n\n            function sha1_kt(t) {\n              return t < 20 ? 1518500249 : t < 40 ? 1859775393 : t < 60 ? -1894007588 : -899497514;\n            }\n            /*\n             * Calculate the HMAC-SHA1 of a key and some data\n             */\n\n\n            function core_hmac_sha1(key, data) {\n              var bkey = str2binb(key);\n\n              if (bkey.length > 16) {\n                bkey = core_sha1(bkey, key.length * 8);\n              }\n\n              var ipad = new Array(16),\n                  opad = new Array(16);\n\n              for (var i = 0; i < 16; i++) {\n                ipad[i] = bkey[i] ^ 0x36363636;\n                opad[i] = bkey[i] ^ 0x5C5C5C5C;\n              }\n\n              var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * 8);\n              return core_sha1(opad.concat(hash), 512 + 160);\n            }\n            /*\n             * Add integers, wrapping at 2^32. This uses 16-bit operations internally\n             * to work around bugs in some JS interpreters.\n             */\n\n\n            function safe_add(x, y) {\n              var lsw = (x & 0xFFFF) + (y & 0xFFFF);\n              var msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n              return msw << 16 | lsw & 0xFFFF;\n            }\n            /*\n             * Bitwise rotate a 32-bit number to the left.\n             */\n\n\n            function rol(num, cnt) {\n              return num << cnt | num >>> 32 - cnt;\n            }\n            /*\n             * Convert an 8-bit or 16-bit string to an array of big-endian words\n             * In 8-bit function, characters >255 have their hi-byte silently ignored.\n             */\n\n\n            function str2binb(str) {\n              var bin = [];\n              var mask = 255;\n\n              for (var i = 0; i < str.length * 8; i += 8) {\n                bin[i >> 5] |= (str.charCodeAt(i / 8) & mask) << 24 - i % 32;\n              }\n\n              return bin;\n            }\n            /*\n             * Convert an array of big-endian words to a base-64 string\n             */\n\n\n            function binb2b64(binarray) {\n              var tab = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n              var str = \"\";\n              var triplet, j;\n\n              for (var i = 0; i < binarray.length * 4; i += 3) {\n                triplet = (binarray[i >> 2] >> 8 * (3 - i % 4) & 0xFF) << 16 | (binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4) & 0xFF) << 8 | binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4) & 0xFF;\n\n                for (j = 0; j < 4; j++) {\n                  if (i * 8 + j * 6 > binarray.length * 32) {\n                    str += \"=\";\n                  } else {\n                    str += tab.charAt(triplet >> 6 * (3 - j) & 0x3F);\n                  }\n                }\n              }\n\n              return str;\n            }\n            /*\n             * Convert an array of big-endian words to a string\n             */\n\n\n            function binb2str(bin) {\n              var str = \"\";\n              var mask = 255;\n\n              for (var i = 0; i < bin.length * 32; i += 8) {\n                str += String.fromCharCode(bin[i >> 5] >>> 24 - i % 32 & mask);\n              }\n\n              return str;\n            }\n            /*\n             * These are the functions you'll usually want to call\n             * They take string arguments and return either hex or base-64 encoded strings\n             */\n\n\n            const SHA1 = {\n              b64_hmac_sha1: function (key, data) {\n                return binb2b64(core_hmac_sha1(key, data));\n              },\n              b64_sha1: function (s) {\n                return binb2b64(core_sha1(str2binb(s), s.length * 8));\n              },\n              binb2str: binb2str,\n              core_hmac_sha1: core_hmac_sha1,\n              str_hmac_sha1: function (key, data) {\n                return binb2str(core_hmac_sha1(key, data));\n              },\n              str_sha1: function (s) {\n                return binb2str(core_sha1(str2binb(s), s.length * 8));\n              }\n            };\n\n            class SASLSHA1 extends SASLMechanism {\n              /** PrivateConstructor: SASLSHA1\n               *  SASL SCRAM SHA 1 authentication.\n               */\n              constructor() {\n                let mechname = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'SCRAM-SHA-1';\n                let isClientFirst = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n                let priority = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 60;\n                super(mechname, isClientFirst, priority);\n              }\n\n              test(connection) {\n                // eslint-disable-line class-methods-use-this\n                return connection.authcid !== null;\n              }\n\n              onChallenge(connection, challenge) {\n                // eslint-disable-line class-methods-use-this\n                let nonce, salt, iter, Hi, U, U_old, i, k;\n                let responseText = \"c=biws,\";\n                let authMessage = `${connection._sasl_data[\"client-first-message-bare\"]},${challenge},`;\n                const cnonce = connection._sasl_data.cnonce;\n                const attribMatch = /([a-z]+)=([^,]+)(,|$)/;\n\n                while (challenge.match(attribMatch)) {\n                  const matches = challenge.match(attribMatch);\n                  challenge = challenge.replace(matches[0], \"\");\n\n                  switch (matches[1]) {\n                    case \"r\":\n                      nonce = matches[2];\n                      break;\n\n                    case \"s\":\n                      salt = matches[2];\n                      break;\n\n                    case \"i\":\n                      iter = matches[2];\n                      break;\n                  }\n                }\n\n                if (nonce.slice(0, cnonce.length) !== cnonce) {\n                  connection._sasl_data = {};\n                  return connection._sasl_failure_cb();\n                }\n\n                responseText += \"r=\" + nonce;\n                authMessage += responseText;\n                salt = atob(salt);\n                salt += \"\\x00\\x00\\x00\\x01\";\n                const pass = utils.utf16to8(connection.pass);\n                Hi = U_old = SHA1.core_hmac_sha1(pass, salt);\n\n                for (i = 1; i < iter; i++) {\n                  U = SHA1.core_hmac_sha1(pass, SHA1.binb2str(U_old));\n\n                  for (k = 0; k < 5; k++) {\n                    Hi[k] ^= U[k];\n                  }\n\n                  U_old = U;\n                }\n\n                Hi = SHA1.binb2str(Hi);\n                const clientKey = SHA1.core_hmac_sha1(Hi, \"Client Key\");\n                const serverKey = SHA1.str_hmac_sha1(Hi, \"Server Key\");\n                const clientSignature = SHA1.core_hmac_sha1(SHA1.str_sha1(SHA1.binb2str(clientKey)), authMessage);\n                connection._sasl_data[\"server-signature\"] = SHA1.b64_hmac_sha1(serverKey, authMessage);\n\n                for (k = 0; k < 5; k++) {\n                  clientKey[k] ^= clientSignature[k];\n                }\n\n                responseText += \",p=\" + btoa(SHA1.binb2str(clientKey));\n                return responseText;\n              }\n\n              clientChallenge(connection, test_cnonce) {\n                // eslint-disable-line class-methods-use-this\n                const cnonce = test_cnonce || MD5.hexdigest(\"\" + Math.random() * 1234567890);\n                let auth_str = \"n=\" + utils.utf16to8(connection.authcid);\n                auth_str += \",r=\";\n                auth_str += cnonce;\n                connection._sasl_data.cnonce = cnonce;\n                connection._sasl_data[\"client-first-message-bare\"] = auth_str;\n                auth_str = \"n,,\" + auth_str;\n                return auth_str;\n              }\n\n            }\n\n            class SASLXOAuth2 extends SASLMechanism {\n              /** PrivateConstructor: SASLXOAuth2\n               *  SASL X-OAuth2 authentication.\n               */\n              constructor() {\n                let mechname = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'X-OAUTH2';\n                let isClientFirst = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n                let priority = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 30;\n                super(mechname, isClientFirst, priority);\n              }\n\n              test(connection) {\n                // eslint-disable-line class-methods-use-this\n                return connection.pass !== null;\n              }\n\n              onChallenge(connection) {\n                // eslint-disable-line class-methods-use-this\n                let auth_str = '\\u0000';\n\n                if (connection.authcid !== null) {\n                  auth_str = auth_str + connection.authzid;\n                }\n\n                auth_str = auth_str + \"\\u0000\";\n                auth_str = auth_str + connection.pass;\n                return utils.utf16to8(auth_str);\n              }\n\n            }\n\n            /**\n             * Implementation of atob() according to the HTML and Infra specs, except that\n             * instead of throwing INVALID_CHARACTER_ERR we return null.\n             */\n\n            function atob$2(data) {\n              if (arguments.length === 0) {\n                throw new TypeError(\"1 argument required, but only 0 present.\");\n              } // Web IDL requires DOMStrings to just be converted using ECMAScript\n              // ToString, which in our case amounts to using a template literal.\n\n\n              data = `${data}`; // \"Remove all ASCII whitespace from data.\"\n\n              data = data.replace(/[ \\t\\n\\f\\r]/g, \"\"); // \"If data's length divides by 4 leaving no remainder, then: if data ends\n              // with one or two U+003D (=) code points, then remove them from data.\"\n\n              if (data.length % 4 === 0) {\n                data = data.replace(/==?$/, \"\");\n              } // \"If data's length divides by 4 leaving a remainder of 1, then return\n              // failure.\"\n              //\n              // \"If data contains a code point that is not one of\n              //\n              // U+002B (+)\n              // U+002F (/)\n              // ASCII alphanumeric\n              //\n              // then return failure.\"\n\n\n              if (data.length % 4 === 1 || /[^+/0-9A-Za-z]/.test(data)) {\n                return null;\n              } // \"Let output be an empty byte sequence.\"\n\n\n              let output = \"\"; // \"Let buffer be an empty buffer that can have bits appended to it.\"\n              //\n              // We append bits via left-shift and or.  accumulatedBits is used to track\n              // when we've gotten to 24 bits.\n\n              let buffer = 0;\n              let accumulatedBits = 0; // \"Let position be a position variable for data, initially pointing at the\n              // start of data.\"\n              //\n              // \"While position does not point past the end of data:\"\n\n              for (let i = 0; i < data.length; i++) {\n                // \"Find the code point pointed to by position in the second column of\n                // Table 1: The Base 64 Alphabet of RFC 4648. Let n be the number given in\n                // the first cell of the same row.\n                //\n                // \"Append to buffer the six bits corresponding to n, most significant bit\n                // first.\"\n                //\n                // atobLookup() implements the table from RFC 4648.\n                buffer <<= 6;\n                buffer |= atobLookup(data[i]);\n                accumulatedBits += 6; // \"If buffer has accumulated 24 bits, interpret them as three 8-bit\n                // big-endian numbers. Append three bytes with values equal to those\n                // numbers to output, in the same order, and then empty buffer.\"\n\n                if (accumulatedBits === 24) {\n                  output += String.fromCharCode((buffer & 0xff0000) >> 16);\n                  output += String.fromCharCode((buffer & 0xff00) >> 8);\n                  output += String.fromCharCode(buffer & 0xff);\n                  buffer = accumulatedBits = 0;\n                } // \"Advance position by 1.\"\n\n              } // \"If buffer is not empty, it contains either 12 or 18 bits. If it contains\n              // 12 bits, then discard the last four and interpret the remaining eight as\n              // an 8-bit big-endian number. If it contains 18 bits, then discard the last\n              // two and interpret the remaining 16 as two 8-bit big-endian numbers. Append\n              // the one or two bytes with values equal to those one or two numbers to\n              // output, in the same order.\"\n\n\n              if (accumulatedBits === 12) {\n                buffer >>= 4;\n                output += String.fromCharCode(buffer);\n              } else if (accumulatedBits === 18) {\n                buffer >>= 2;\n                output += String.fromCharCode((buffer & 0xff00) >> 8);\n                output += String.fromCharCode(buffer & 0xff);\n              } // \"Return output.\"\n\n\n              return output;\n            }\n            /**\n             * A lookup table for atob(), which converts an ASCII character to the\n             * corresponding six-bit number.\n             */\n\n\n            const keystr$1 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\n            function atobLookup(chr) {\n              const index = keystr$1.indexOf(chr); // Throw exception if character is not in the lookup string; should not be hit in tests\n\n              return index < 0 ? undefined : index;\n            }\n\n            var atob_1 = atob$2;\n\n            /**\n             * btoa() as defined by the HTML and Infra specs, which mostly just references\n             * RFC 4648.\n             */\n\n            function btoa$2(s) {\n              if (arguments.length === 0) {\n                throw new TypeError(\"1 argument required, but only 0 present.\");\n              }\n\n              let i; // String conversion as required by Web IDL.\n\n              s = `${s}`; // \"The btoa() method must throw an \"InvalidCharacterError\" DOMException if\n              // data contains any character whose code point is greater than U+00FF.\"\n\n              for (i = 0; i < s.length; i++) {\n                if (s.charCodeAt(i) > 255) {\n                  return null;\n                }\n              }\n\n              let out = \"\";\n\n              for (i = 0; i < s.length; i += 3) {\n                const groupsOfSix = [undefined, undefined, undefined, undefined];\n                groupsOfSix[0] = s.charCodeAt(i) >> 2;\n                groupsOfSix[1] = (s.charCodeAt(i) & 0x03) << 4;\n\n                if (s.length > i + 1) {\n                  groupsOfSix[1] |= s.charCodeAt(i + 1) >> 4;\n                  groupsOfSix[2] = (s.charCodeAt(i + 1) & 0x0f) << 2;\n                }\n\n                if (s.length > i + 2) {\n                  groupsOfSix[2] |= s.charCodeAt(i + 2) >> 6;\n                  groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f;\n                }\n\n                for (let j = 0; j < groupsOfSix.length; j++) {\n                  if (typeof groupsOfSix[j] === \"undefined\") {\n                    out += \"=\";\n                  } else {\n                    out += btoaLookup(groupsOfSix[j]);\n                  }\n                }\n              }\n\n              return out;\n            }\n            /**\n             * Lookup table for btoa(), which converts a six-bit number into the\n             * corresponding ASCII character.\n             */\n\n\n            const keystr = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\n            function btoaLookup(index) {\n              if (index >= 0 && index < 64) {\n                return keystr[index];\n              } // Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests.\n\n\n              return undefined;\n            }\n\n            var btoa_1 = btoa$2;\n\n            const atob$1 = atob_1;\n\n            const btoa$1 = btoa_1;\n\n            var abab = {\n              atob: atob$1,\n              btoa: btoa$1\n            };\n\n            /*\n                This program is distributed under the terms of the MIT license.\n                Please see the LICENSE file for details.\n\n                Copyright 2006-2018, OGG, LLC\n            */\n            /** Function: $build\n             *  Create a Strophe.Builder.\n             *  This is an alias for 'new Strophe.Builder(name, attrs)'.\n             *\n             *  Parameters:\n             *    (String) name - The root element name.\n             *    (Object) attrs - The attributes for the root element in object notation.\n             *\n             *  Returns:\n             *    A new Strophe.Builder object.\n             */\n\n            function $build(name, attrs) {\n              return new Strophe.Builder(name, attrs);\n            }\n            /** Function: $msg\n             *  Create a Strophe.Builder with a <message/> element as the root.\n             *\n             *  Parameters:\n             *    (Object) attrs - The <message/> element attributes in object notation.\n             *\n             *  Returns:\n             *    A new Strophe.Builder object.\n             */\n\n            function $msg(attrs) {\n              return new Strophe.Builder(\"message\", attrs);\n            }\n            /** Function: $iq\n             *  Create a Strophe.Builder with an <iq/> element as the root.\n             *\n             *  Parameters:\n             *    (Object) attrs - The <iq/> element attributes in object notation.\n             *\n             *  Returns:\n             *    A new Strophe.Builder object.\n             */\n\n            function $iq(attrs) {\n              return new Strophe.Builder(\"iq\", attrs);\n            }\n            /** Function: $pres\n             *  Create a Strophe.Builder with a <presence/> element as the root.\n             *\n             *  Parameters:\n             *    (Object) attrs - The <presence/> element attributes in object notation.\n             *\n             *  Returns:\n             *    A new Strophe.Builder object.\n             */\n\n            function $pres(attrs) {\n              return new Strophe.Builder(\"presence\", attrs);\n            }\n            /** Class: Strophe\n             *  An object container for all Strophe library functions.\n             *\n             *  This class is just a container for all the objects and constants\n             *  used in the library.  It is not meant to be instantiated, but to\n             *  provide a namespace for library objects, constants, and functions.\n             */\n\n            const Strophe = {\n              /** Constant: VERSION */\n              VERSION: \"1.5.0\",\n\n              /** Constants: XMPP Namespace Constants\n               *  Common namespace constants from the XMPP RFCs and XEPs.\n               *\n               *  NS.HTTPBIND - HTTP BIND namespace from XEP 124.\n               *  NS.BOSH - BOSH namespace from XEP 206.\n               *  NS.CLIENT - Main XMPP client namespace.\n               *  NS.AUTH - Legacy authentication namespace.\n               *  NS.ROSTER - Roster operations namespace.\n               *  NS.PROFILE - Profile namespace.\n               *  NS.DISCO_INFO - Service discovery info namespace from XEP 30.\n               *  NS.DISCO_ITEMS - Service discovery items namespace from XEP 30.\n               *  NS.MUC - Multi-User Chat namespace from XEP 45.\n               *  NS.SASL - XMPP SASL namespace from RFC 3920.\n               *  NS.STREAM - XMPP Streams namespace from RFC 3920.\n               *  NS.BIND - XMPP Binding namespace from RFC 3920 and RFC 6120.\n               *  NS.SESSION - XMPP Session namespace from RFC 3920.\n               *  NS.XHTML_IM - XHTML-IM namespace from XEP 71.\n               *  NS.XHTML - XHTML body namespace from XEP 71.\n               */\n              NS: {\n                HTTPBIND: \"http://jabber.org/protocol/httpbind\",\n                BOSH: \"urn:xmpp:xbosh\",\n                CLIENT: \"jabber:client\",\n                AUTH: \"jabber:iq:auth\",\n                ROSTER: \"jabber:iq:roster\",\n                PROFILE: \"jabber:iq:profile\",\n                DISCO_INFO: \"http://jabber.org/protocol/disco#info\",\n                DISCO_ITEMS: \"http://jabber.org/protocol/disco#items\",\n                MUC: \"http://jabber.org/protocol/muc\",\n                SASL: \"urn:ietf:params:xml:ns:xmpp-sasl\",\n                STREAM: \"http://etherx.jabber.org/streams\",\n                FRAMING: \"urn:ietf:params:xml:ns:xmpp-framing\",\n                BIND: \"urn:ietf:params:xml:ns:xmpp-bind\",\n                SESSION: \"urn:ietf:params:xml:ns:xmpp-session\",\n                VERSION: \"jabber:iq:version\",\n                STANZAS: \"urn:ietf:params:xml:ns:xmpp-stanzas\",\n                XHTML_IM: \"http://jabber.org/protocol/xhtml-im\",\n                XHTML: \"http://www.w3.org/1999/xhtml\"\n              },\n\n              /** Constants: XHTML_IM Namespace\n               *  contains allowed tags, tag attributes, and css properties.\n               *  Used in the createHtml function to filter incoming html into the allowed XHTML-IM subset.\n               *  See http://xmpp.org/extensions/xep-0071.html#profile-summary for the list of recommended\n               *  allowed tags and their attributes.\n               */\n              XHTML: {\n                tags: ['a', 'blockquote', 'br', 'cite', 'em', 'img', 'li', 'ol', 'p', 'span', 'strong', 'ul', 'body'],\n                attributes: {\n                  'a': ['href'],\n                  'blockquote': ['style'],\n                  'br': [],\n                  'cite': ['style'],\n                  'em': [],\n                  'img': ['src', 'alt', 'style', 'height', 'width'],\n                  'li': ['style'],\n                  'ol': ['style'],\n                  'p': ['style'],\n                  'span': ['style'],\n                  'strong': [],\n                  'ul': ['style'],\n                  'body': []\n                },\n                css: ['background-color', 'color', 'font-family', 'font-size', 'font-style', 'font-weight', 'margin-left', 'margin-right', 'text-align', 'text-decoration'],\n\n                /** Function: XHTML.validTag\n                 *\n                 * Utility method to determine whether a tag is allowed\n                 * in the XHTML_IM namespace.\n                 *\n                 * XHTML tag names are case sensitive and must be lower case.\n                 */\n                validTag(tag) {\n                  for (let i = 0; i < Strophe.XHTML.tags.length; i++) {\n                    if (tag === Strophe.XHTML.tags[i]) {\n                      return true;\n                    }\n                  }\n\n                  return false;\n                },\n\n                /** Function: XHTML.validAttribute\n                 *\n                 * Utility method to determine whether an attribute is allowed\n                 * as recommended per XEP-0071\n                 *\n                 * XHTML attribute names are case sensitive and must be lower case.\n                 */\n                validAttribute(tag, attribute) {\n                  if (typeof Strophe.XHTML.attributes[tag] !== 'undefined' && Strophe.XHTML.attributes[tag].length > 0) {\n                    for (let i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {\n                      if (attribute === Strophe.XHTML.attributes[tag][i]) {\n                        return true;\n                      }\n                    }\n                  }\n\n                  return false;\n                },\n\n                validCSS(style) {\n                  for (let i = 0; i < Strophe.XHTML.css.length; i++) {\n                    if (style === Strophe.XHTML.css[i]) {\n                      return true;\n                    }\n                  }\n\n                  return false;\n                }\n\n              },\n\n              /** Constants: Connection Status Constants\n               *  Connection status constants for use by the connection handler\n               *  callback.\n               *\n               *  Status.ERROR - An error has occurred\n               *  Status.CONNECTING - The connection is currently being made\n               *  Status.CONNFAIL - The connection attempt failed\n               *  Status.AUTHENTICATING - The connection is authenticating\n               *  Status.AUTHFAIL - The authentication attempt failed\n               *  Status.CONNECTED - The connection has succeeded\n               *  Status.DISCONNECTED - The connection has been terminated\n               *  Status.DISCONNECTING - The connection is currently being terminated\n               *  Status.ATTACHED - The connection has been attached\n               *  Status.REDIRECT - The connection has been redirected\n               *  Status.CONNTIMEOUT - The connection has timed out\n               */\n              Status: {\n                ERROR: 0,\n                CONNECTING: 1,\n                CONNFAIL: 2,\n                AUTHENTICATING: 3,\n                AUTHFAIL: 4,\n                CONNECTED: 5,\n                DISCONNECTED: 6,\n                DISCONNECTING: 7,\n                ATTACHED: 8,\n                REDIRECT: 9,\n                CONNTIMEOUT: 10,\n                BINDREQUIRED: 11,\n                ATTACHFAIL: 12\n              },\n              ErrorCondition: {\n                BAD_FORMAT: \"bad-format\",\n                CONFLICT: \"conflict\",\n                MISSING_JID_NODE: \"x-strophe-bad-non-anon-jid\",\n                NO_AUTH_MECH: \"no-auth-mech\",\n                UNKNOWN_REASON: \"unknown\"\n              },\n\n              /** Constants: Log Level Constants\n               *  Logging level indicators.\n               *\n               *  LogLevel.DEBUG - Debug output\n               *  LogLevel.INFO - Informational output\n               *  LogLevel.WARN - Warnings\n               *  LogLevel.ERROR - Errors\n               *  LogLevel.FATAL - Fatal errors\n               */\n              LogLevel: {\n                DEBUG: 0,\n                INFO: 1,\n                WARN: 2,\n                ERROR: 3,\n                FATAL: 4\n              },\n\n              /** PrivateConstants: DOM Element Type Constants\n               *  DOM element types.\n               *\n               *  ElementType.NORMAL - Normal element.\n               *  ElementType.TEXT - Text data element.\n               *  ElementType.FRAGMENT - XHTML fragment element.\n               */\n              ElementType: {\n                NORMAL: 1,\n                TEXT: 3,\n                CDATA: 4,\n                FRAGMENT: 11\n              },\n\n              /** PrivateConstants: Timeout Values\n               *  Timeout values for error states.  These values are in seconds.\n               *  These should not be changed unless you know exactly what you are\n               *  doing.\n               *\n               *  TIMEOUT - Timeout multiplier. A waiting request will be considered\n               *      failed after Math.floor(TIMEOUT * wait) seconds have elapsed.\n               *      This defaults to 1.1, and with default wait, 66 seconds.\n               *  SECONDARY_TIMEOUT - Secondary timeout multiplier. In cases where\n               *      Strophe can detect early failure, it will consider the request\n               *      failed if it doesn't return after\n               *      Math.floor(SECONDARY_TIMEOUT * wait) seconds have elapsed.\n               *      This defaults to 0.1, and with default wait, 6 seconds.\n               */\n              TIMEOUT: 1.1,\n              SECONDARY_TIMEOUT: 0.1,\n\n              /** Function: addNamespace\n               *  This function is used to extend the current namespaces in\n               *  Strophe.NS.  It takes a key and a value with the key being the\n               *  name of the new namespace, with its actual value.\n               *  For example:\n               *  Strophe.addNamespace('PUBSUB', \"http://jabber.org/protocol/pubsub\");\n               *\n               *  Parameters:\n               *    (String) name - The name under which the namespace will be\n               *      referenced under Strophe.NS\n               *    (String) value - The actual namespace.\n               */\n              addNamespace(name, value) {\n                Strophe.NS[name] = value;\n              },\n\n              /** Function: forEachChild\n               *  Map a function over some or all child elements of a given element.\n               *\n               *  This is a small convenience function for mapping a function over\n               *  some or all of the children of an element.  If elemName is null, all\n               *  children will be passed to the function, otherwise only children\n               *  whose tag names match elemName will be passed.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The element to operate on.\n               *    (String) elemName - The child element tag name filter.\n               *    (Function) func - The function to apply to each child.  This\n               *      function should take a single argument, a DOM element.\n               */\n              forEachChild(elem, elemName, func) {\n                for (let i = 0; i < elem.childNodes.length; i++) {\n                  const childNode = elem.childNodes[i];\n\n                  if (childNode.nodeType === Strophe.ElementType.NORMAL && (!elemName || this.isTagEqual(childNode, elemName))) {\n                    func(childNode);\n                  }\n                }\n              },\n\n              /** Function: isTagEqual\n               *  Compare an element's tag name with a string.\n               *\n               *  This function is case sensitive.\n               *\n               *  Parameters:\n               *    (XMLElement) el - A DOM element.\n               *    (String) name - The element name.\n               *\n               *  Returns:\n               *    true if the element's tag name matches _el_, and false\n               *    otherwise.\n               */\n              isTagEqual(el, name) {\n                return el.tagName === name;\n              },\n\n              /** PrivateVariable: _xmlGenerator\n               *  _Private_ variable that caches a DOM document to\n               *  generate elements.\n               */\n              _xmlGenerator: null,\n\n              /** Function: xmlGenerator\n               *  Get the DOM document to generate elements.\n               *\n               *  Returns:\n               *    The currently used DOM document.\n               */\n              xmlGenerator() {\n                if (!Strophe._xmlGenerator) {\n                  Strophe._xmlGenerator = getDummyXMLDOMDocument();\n                }\n\n                return Strophe._xmlGenerator;\n              },\n\n              /** Function: xmlElement\n               *  Create an XML DOM element.\n               *\n               *  This function creates an XML DOM element correctly across all\n               *  implementations. Note that these are not HTML DOM elements, which\n               *  aren't appropriate for XMPP stanzas.\n               *\n               *  Parameters:\n               *    (String) name - The name for the element.\n               *    (Array|Object) attrs - An optional array or object containing\n               *      key/value pairs to use as element attributes. The object should\n               *      be in the format {'key': 'value'} or {key: 'value'}. The array\n               *      should have the format [['key1', 'value1'], ['key2', 'value2']].\n               *    (String) text - The text child data for the element.\n               *\n               *  Returns:\n               *    A new XML DOM element.\n               */\n              xmlElement(name) {\n                if (!name) {\n                  return null;\n                }\n\n                const node = Strophe.xmlGenerator().createElement(name); // FIXME: this should throw errors if args are the wrong type or\n                // there are more than two optional args\n\n                for (let a = 1; a < arguments.length; a++) {\n                  const arg = arguments[a];\n\n                  if (!arg) {\n                    continue;\n                  }\n\n                  if (typeof arg === \"string\" || typeof arg === \"number\") {\n                    node.appendChild(Strophe.xmlTextNode(arg));\n                  } else if (typeof arg === \"object\" && typeof arg.sort === \"function\") {\n                    for (let i = 0; i < arg.length; i++) {\n                      const attr = arg[i];\n\n                      if (typeof attr === \"object\" && typeof attr.sort === \"function\" && attr[1] !== undefined && attr[1] !== null) {\n                        node.setAttribute(attr[0], attr[1]);\n                      }\n                    }\n                  } else if (typeof arg === \"object\") {\n                    for (const k in arg) {\n                      if (Object.prototype.hasOwnProperty.call(arg, k) && arg[k] !== undefined && arg[k] !== null) {\n                        node.setAttribute(k, arg[k]);\n                      }\n                    }\n                  }\n                }\n\n                return node;\n              },\n\n              /*  Function: xmlescape\n               *  Excapes invalid xml characters.\n               *\n               *  Parameters:\n               *     (String) text - text to escape.\n               *\n               *  Returns:\n               *      Escaped text.\n               */\n              xmlescape(text) {\n                text = text.replace(/\\&/g, \"&amp;\");\n                text = text.replace(/</g, \"&lt;\");\n                text = text.replace(/>/g, \"&gt;\");\n                text = text.replace(/'/g, \"&apos;\");\n                text = text.replace(/\"/g, \"&quot;\");\n                return text;\n              },\n\n              /*  Function: xmlunescape\n              *  Unexcapes invalid xml characters.\n              *\n              *  Parameters:\n              *     (String) text - text to unescape.\n              *\n              *  Returns:\n              *      Unescaped text.\n              */\n              xmlunescape(text) {\n                text = text.replace(/\\&amp;/g, \"&\");\n                text = text.replace(/&lt;/g, \"<\");\n                text = text.replace(/&gt;/g, \">\");\n                text = text.replace(/&apos;/g, \"'\");\n                text = text.replace(/&quot;/g, \"\\\"\");\n                return text;\n              },\n\n              /** Function: xmlTextNode\n               *  Creates an XML DOM text node.\n               *\n               *  Provides a cross implementation version of document.createTextNode.\n               *\n               *  Parameters:\n               *    (String) text - The content of the text node.\n               *\n               *  Returns:\n               *    A new XML DOM text node.\n               */\n              xmlTextNode(text) {\n                return Strophe.xmlGenerator().createTextNode(text);\n              },\n\n              /** Function: xmlHtmlNode\n               *  Creates an XML DOM html node.\n               *\n               *  Parameters:\n               *    (String) html - The content of the html node.\n               *\n               *  Returns:\n               *    A new XML DOM text node.\n               */\n              xmlHtmlNode(html) {\n                let node; //ensure text is escaped\n\n                if (DOMParser) {\n                  const parser = new DOMParser();\n                  node = parser.parseFromString(html, \"text/xml\");\n                } else {\n                  node = new ActiveXObject(\"Microsoft.XMLDOM\");\n                  node.async = \"false\";\n                  node.loadXML(html);\n                }\n\n                return node;\n              },\n\n              /** Function: getText\n               *  Get the concatenation of all text children of an element.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - A DOM element.\n               *\n               *  Returns:\n               *    A String with the concatenated text of all text element children.\n               */\n              getText(elem) {\n                if (!elem) {\n                  return null;\n                }\n\n                let str = \"\";\n\n                if (elem.childNodes.length === 0 && elem.nodeType === Strophe.ElementType.TEXT) {\n                  str += elem.nodeValue;\n                }\n\n                for (let i = 0; i < elem.childNodes.length; i++) {\n                  if (elem.childNodes[i].nodeType === Strophe.ElementType.TEXT) {\n                    str += elem.childNodes[i].nodeValue;\n                  }\n                }\n\n                return Strophe.xmlescape(str);\n              },\n\n              /** Function: copyElement\n               *  Copy an XML DOM element.\n               *\n               *  This function copies a DOM element and all its descendants and returns\n               *  the new copy.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - A DOM element.\n               *\n               *  Returns:\n               *    A new, copied DOM element tree.\n               */\n              copyElement(elem) {\n                let el;\n\n                if (elem.nodeType === Strophe.ElementType.NORMAL) {\n                  el = Strophe.xmlElement(elem.tagName);\n\n                  for (let i = 0; i < elem.attributes.length; i++) {\n                    el.setAttribute(elem.attributes[i].nodeName, elem.attributes[i].value);\n                  }\n\n                  for (let i = 0; i < elem.childNodes.length; i++) {\n                    el.appendChild(Strophe.copyElement(elem.childNodes[i]));\n                  }\n                } else if (elem.nodeType === Strophe.ElementType.TEXT) {\n                  el = Strophe.xmlGenerator().createTextNode(elem.nodeValue);\n                }\n\n                return el;\n              },\n\n              /** Function: createHtml\n               *  Copy an HTML DOM element into an XML DOM.\n               *\n               *  This function copies a DOM element and all its descendants and returns\n               *  the new copy.\n               *\n               *  Parameters:\n               *    (HTMLElement) elem - A DOM element.\n               *\n               *  Returns:\n               *    A new, copied DOM element tree.\n               */\n              createHtml(elem) {\n                let el;\n\n                if (elem.nodeType === Strophe.ElementType.NORMAL) {\n                  const tag = elem.nodeName.toLowerCase(); // XHTML tags must be lower case.\n\n                  if (Strophe.XHTML.validTag(tag)) {\n                    try {\n                      el = Strophe.xmlElement(tag);\n\n                      for (let i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {\n                        const attribute = Strophe.XHTML.attributes[tag][i];\n                        let value = elem.getAttribute(attribute);\n\n                        if (typeof value === 'undefined' || value === null || value === '' || value === false || value === 0) {\n                          continue;\n                        }\n\n                        if (attribute === 'style' && typeof value === 'object' && typeof value.cssText !== 'undefined') {\n                          value = value.cssText; // we're dealing with IE, need to get CSS out\n                        } // filter out invalid css styles\n\n\n                        if (attribute === 'style') {\n                          const css = [];\n                          const cssAttrs = value.split(';');\n\n                          for (let j = 0; j < cssAttrs.length; j++) {\n                            const attr = cssAttrs[j].split(':');\n                            const cssName = attr[0].replace(/^\\s*/, \"\").replace(/\\s*$/, \"\").toLowerCase();\n\n                            if (Strophe.XHTML.validCSS(cssName)) {\n                              const cssValue = attr[1].replace(/^\\s*/, \"\").replace(/\\s*$/, \"\");\n                              css.push(cssName + ': ' + cssValue);\n                            }\n                          }\n\n                          if (css.length > 0) {\n                            value = css.join('; ');\n                            el.setAttribute(attribute, value);\n                          }\n                        } else {\n                          el.setAttribute(attribute, value);\n                        }\n                      }\n\n                      for (let i = 0; i < elem.childNodes.length; i++) {\n                        el.appendChild(Strophe.createHtml(elem.childNodes[i]));\n                      }\n                    } catch (e) {\n                      // invalid elements\n                      el = Strophe.xmlTextNode('');\n                    }\n                  } else {\n                    el = Strophe.xmlGenerator().createDocumentFragment();\n\n                    for (let i = 0; i < elem.childNodes.length; i++) {\n                      el.appendChild(Strophe.createHtml(elem.childNodes[i]));\n                    }\n                  }\n                } else if (elem.nodeType === Strophe.ElementType.FRAGMENT) {\n                  el = Strophe.xmlGenerator().createDocumentFragment();\n\n                  for (let i = 0; i < elem.childNodes.length; i++) {\n                    el.appendChild(Strophe.createHtml(elem.childNodes[i]));\n                  }\n                } else if (elem.nodeType === Strophe.ElementType.TEXT) {\n                  el = Strophe.xmlTextNode(elem.nodeValue);\n                }\n\n                return el;\n              },\n\n              /** Function: escapeNode\n               *  Escape the node part (also called local part) of a JID.\n               *\n               *  Parameters:\n               *    (String) node - A node (or local part).\n               *\n               *  Returns:\n               *    An escaped node (or local part).\n               */\n              escapeNode(node) {\n                if (typeof node !== \"string\") {\n                  return node;\n                }\n\n                return node.replace(/^\\s+|\\s+$/g, '').replace(/\\\\/g, \"\\\\5c\").replace(/ /g, \"\\\\20\").replace(/\\\"/g, \"\\\\22\").replace(/\\&/g, \"\\\\26\").replace(/\\'/g, \"\\\\27\").replace(/\\//g, \"\\\\2f\").replace(/:/g, \"\\\\3a\").replace(/</g, \"\\\\3c\").replace(/>/g, \"\\\\3e\").replace(/@/g, \"\\\\40\");\n              },\n\n              /** Function: unescapeNode\n               *  Unescape a node part (also called local part) of a JID.\n               *\n               *  Parameters:\n               *    (String) node - A node (or local part).\n               *\n               *  Returns:\n               *    An unescaped node (or local part).\n               */\n              unescapeNode(node) {\n                if (typeof node !== \"string\") {\n                  return node;\n                }\n\n                return node.replace(/\\\\20/g, \" \").replace(/\\\\22/g, '\"').replace(/\\\\26/g, \"&\").replace(/\\\\27/g, \"'\").replace(/\\\\2f/g, \"/\").replace(/\\\\3a/g, \":\").replace(/\\\\3c/g, \"<\").replace(/\\\\3e/g, \">\").replace(/\\\\40/g, \"@\").replace(/\\\\5c/g, \"\\\\\");\n              },\n\n              /** Function: getNodeFromJid\n               *  Get the node portion of a JID String.\n               *\n               *  Parameters:\n               *    (String) jid - A JID.\n               *\n               *  Returns:\n               *    A String containing the node.\n               */\n              getNodeFromJid(jid) {\n                if (jid.indexOf(\"@\") < 0) {\n                  return null;\n                }\n\n                return jid.split(\"@\")[0];\n              },\n\n              /** Function: getDomainFromJid\n               *  Get the domain portion of a JID String.\n               *\n               *  Parameters:\n               *    (String) jid - A JID.\n               *\n               *  Returns:\n               *    A String containing the domain.\n               */\n              getDomainFromJid(jid) {\n                const bare = Strophe.getBareJidFromJid(jid);\n\n                if (bare.indexOf(\"@\") < 0) {\n                  return bare;\n                } else {\n                  const parts = bare.split(\"@\");\n                  parts.splice(0, 1);\n                  return parts.join('@');\n                }\n              },\n\n              /** Function: getResourceFromJid\n               *  Get the resource portion of a JID String.\n               *\n               *  Parameters:\n               *    (String) jid - A JID.\n               *\n               *  Returns:\n               *    A String containing the resource.\n               */\n              getResourceFromJid(jid) {\n                if (!jid) {\n                  return null;\n                }\n\n                const s = jid.split(\"/\");\n\n                if (s.length < 2) {\n                  return null;\n                }\n\n                s.splice(0, 1);\n                return s.join('/');\n              },\n\n              /** Function: getBareJidFromJid\n               *  Get the bare JID from a JID String.\n               *\n               *  Parameters:\n               *    (String) jid - A JID.\n               *\n               *  Returns:\n               *    A String containing the bare JID.\n               */\n              getBareJidFromJid(jid) {\n                return jid ? jid.split(\"/\")[0] : null;\n              },\n\n              /** PrivateFunction: _handleError\n               *  _Private_ function that properly logs an error to the console\n               */\n              _handleError(e) {\n                if (typeof e.stack !== \"undefined\") {\n                  Strophe.fatal(e.stack);\n                }\n\n                if (e.sourceURL) {\n                  Strophe.fatal(\"error: \" + this.handler + \" \" + e.sourceURL + \":\" + e.line + \" - \" + e.name + \": \" + e.message);\n                } else if (e.fileName) {\n                  Strophe.fatal(\"error: \" + this.handler + \" \" + e.fileName + \":\" + e.lineNumber + \" - \" + e.name + \": \" + e.message);\n                } else {\n                  Strophe.fatal(\"error: \" + e.message);\n                }\n              },\n\n              /** Function: log\n               *  User overrideable logging function.\n               *\n               *  This function is called whenever the Strophe library calls any\n               *  of the logging functions.  The default implementation of this\n               *  function logs only fatal errors.  If client code wishes to handle the logging\n               *  messages, it should override this with\n               *  > Strophe.log = function (level, msg) {\n               *  >   (user code here)\n               *  > };\n               *\n               *  Please note that data sent and received over the wire is logged\n               *  via Strophe.Connection.rawInput() and Strophe.Connection.rawOutput().\n               *\n               *  The different levels and their meanings are\n               *\n               *    DEBUG - Messages useful for debugging purposes.\n               *    INFO - Informational messages.  This is mostly information like\n               *      'disconnect was called' or 'SASL auth succeeded'.\n               *    WARN - Warnings about potential problems.  This is mostly used\n               *      to report transient connection errors like request timeouts.\n               *    ERROR - Some error occurred.\n               *    FATAL - A non-recoverable fatal error occurred.\n               *\n               *  Parameters:\n               *    (Integer) level - The log level of the log message.  This will\n               *      be one of the values in Strophe.LogLevel.\n               *    (String) msg - The log message.\n               */\n              log(level, msg) {\n                if (level === this.LogLevel.FATAL) {\n                  var _console;\n\n                  (_console = console) === null || _console === void 0 ? void 0 : _console.error(msg);\n                }\n              },\n\n              /** Function: debug\n               *  Log a message at the Strophe.LogLevel.DEBUG level.\n               *\n               *  Parameters:\n               *    (String) msg - The log message.\n               */\n              debug(msg) {\n                this.log(this.LogLevel.DEBUG, msg);\n              },\n\n              /** Function: info\n               *  Log a message at the Strophe.LogLevel.INFO level.\n               *\n               *  Parameters:\n               *    (String) msg - The log message.\n               */\n              info(msg) {\n                this.log(this.LogLevel.INFO, msg);\n              },\n\n              /** Function: warn\n               *  Log a message at the Strophe.LogLevel.WARN level.\n               *\n               *  Parameters:\n               *    (String) msg - The log message.\n               */\n              warn(msg) {\n                this.log(this.LogLevel.WARN, msg);\n              },\n\n              /** Function: error\n               *  Log a message at the Strophe.LogLevel.ERROR level.\n               *\n               *  Parameters:\n               *    (String) msg - The log message.\n               */\n              error(msg) {\n                this.log(this.LogLevel.ERROR, msg);\n              },\n\n              /** Function: fatal\n               *  Log a message at the Strophe.LogLevel.FATAL level.\n               *\n               *  Parameters:\n               *    (String) msg - The log message.\n               */\n              fatal(msg) {\n                this.log(this.LogLevel.FATAL, msg);\n              },\n\n              /** Function: serialize\n               *  Render a DOM element and all descendants to a String.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - A DOM element.\n               *\n               *  Returns:\n               *    The serialized element tree as a String.\n               */\n              serialize(elem) {\n                if (!elem) {\n                  return null;\n                }\n\n                if (typeof elem.tree === \"function\") {\n                  elem = elem.tree();\n                }\n\n                const names = [...Array(elem.attributes.length).keys()].map(i => elem.attributes[i].nodeName);\n                names.sort();\n                let result = names.reduce((a, n) => `${a} ${n}=\"${Strophe.xmlescape(elem.attributes.getNamedItem(n).value)}\"`, `<${elem.nodeName}`);\n\n                if (elem.childNodes.length > 0) {\n                  result += \">\";\n\n                  for (let i = 0; i < elem.childNodes.length; i++) {\n                    const child = elem.childNodes[i];\n\n                    switch (child.nodeType) {\n                      case Strophe.ElementType.NORMAL:\n                        // normal element, so recurse\n                        result += Strophe.serialize(child);\n                        break;\n\n                      case Strophe.ElementType.TEXT:\n                        // text element to escape values\n                        result += Strophe.xmlescape(child.nodeValue);\n                        break;\n\n                      case Strophe.ElementType.CDATA:\n                        // cdata section so don't escape values\n                        result += \"<![CDATA[\" + child.nodeValue + \"]]>\";\n                    }\n                  }\n\n                  result += \"</\" + elem.nodeName + \">\";\n                } else {\n                  result += \"/>\";\n                }\n\n                return result;\n              },\n\n              /** PrivateVariable: _requestId\n               *  _Private_ variable that keeps track of the request ids for\n               *  connections.\n               */\n              _requestId: 0,\n\n              /** PrivateVariable: Strophe.connectionPlugins\n               *  _Private_ variable Used to store plugin names that need\n               *  initialization on Strophe.Connection construction.\n               */\n              _connectionPlugins: {},\n\n              /** Function: addConnectionPlugin\n               *  Extends the Strophe.Connection object with the given plugin.\n               *\n               *  Parameters:\n               *    (String) name - The name of the extension.\n               *    (Object) ptype - The plugin's prototype.\n               */\n              addConnectionPlugin(name, ptype) {\n                Strophe._connectionPlugins[name] = ptype;\n              }\n\n            };\n            /** Class: Strophe.Builder\n             *  XML DOM builder.\n             *\n             *  This object provides an interface similar to JQuery but for building\n             *  DOM elements easily and rapidly.  All the functions except for toString()\n             *  and tree() return the object, so calls can be chained.  Here's an\n             *  example using the $iq() builder helper.\n             *  > $iq({to: 'you', from: 'me', type: 'get', id: '1'})\n             *  >     .c('query', {xmlns: 'strophe:example'})\n             *  >     .c('example')\n             *  >     .toString()\n             *\n             *  The above generates this XML fragment\n             *  > <iq to='you' from='me' type='get' id='1'>\n             *  >   <query xmlns='strophe:example'>\n             *  >     <example/>\n             *  >   </query>\n             *  > </iq>\n             *  The corresponding DOM manipulations to get a similar fragment would be\n             *  a lot more tedious and probably involve several helper variables.\n             *\n             *  Since adding children makes new operations operate on the child, up()\n             *  is provided to traverse up the tree.  To add two children, do\n             *  > builder.c('child1', ...).up().c('child2', ...)\n             *  The next operation on the Builder will be relative to the second child.\n             */\n\n            /** Constructor: Strophe.Builder\n             *  Create a Strophe.Builder object.\n             *\n             *  The attributes should be passed in object notation.  For example\n             *  > let b = new Builder('message', {to: 'you', from: 'me'});\n             *  or\n             *  > let b = new Builder('messsage', {'xml:lang': 'en'});\n             *\n             *  Parameters:\n             *    (String) name - The name of the root element.\n             *    (Object) attrs - The attributes for the root element in object notation.\n             *\n             *  Returns:\n             *    A new Strophe.Builder.\n             */\n\n            Strophe.Builder = class Builder {\n              constructor(name, attrs) {\n                // Set correct namespace for jabber:client elements\n                if (name === \"presence\" || name === \"message\" || name === \"iq\") {\n                  if (attrs && !attrs.xmlns) {\n                    attrs.xmlns = Strophe.NS.CLIENT;\n                  } else if (!attrs) {\n                    attrs = {\n                      xmlns: Strophe.NS.CLIENT\n                    };\n                  }\n                } // Holds the tree being built.\n\n\n                this.nodeTree = Strophe.xmlElement(name, attrs); // Points to the current operation node.\n\n                this.node = this.nodeTree;\n              }\n              /** Function: tree\n               *  Return the DOM tree.\n               *\n               *  This function returns the current DOM tree as an element object.  This\n               *  is suitable for passing to functions like Strophe.Connection.send().\n               *\n               *  Returns:\n               *    The DOM tree as a element object.\n               */\n\n\n              tree() {\n                return this.nodeTree;\n              }\n              /** Function: toString\n               *  Serialize the DOM tree to a String.\n               *\n               *  This function returns a string serialization of the current DOM\n               *  tree.  It is often used internally to pass data to a\n               *  Strophe.Request object.\n               *\n               *  Returns:\n               *    The serialized DOM tree in a String.\n               */\n\n\n              toString() {\n                return Strophe.serialize(this.nodeTree);\n              }\n              /** Function: up\n               *  Make the current parent element the new current element.\n               *\n               *  This function is often used after c() to traverse back up the tree.\n               *  For example, to add two children to the same element\n               *  > builder.c('child1', {}).up().c('child2', {});\n               *\n               *  Returns:\n               *    The Stophe.Builder object.\n               */\n\n\n              up() {\n                this.node = this.node.parentNode;\n                return this;\n              }\n              /** Function: root\n               *  Make the root element the new current element.\n               *\n               *  When at a deeply nested element in the tree, this function can be used\n               *  to jump back to the root of the tree, instead of having to repeatedly\n               *  call up().\n               *\n               *  Returns:\n               *    The Stophe.Builder object.\n               */\n\n\n              root() {\n                this.node = this.nodeTree;\n                return this;\n              }\n              /** Function: attrs\n               *  Add or modify attributes of the current element.\n               *\n               *  The attributes should be passed in object notation.  This function\n               *  does not move the current element pointer.\n               *\n               *  Parameters:\n               *    (Object) moreattrs - The attributes to add/modify in object notation.\n               *\n               *  Returns:\n               *    The Strophe.Builder object.\n               */\n\n\n              attrs(moreattrs) {\n                for (const k in moreattrs) {\n                  if (Object.prototype.hasOwnProperty.call(moreattrs, k)) {\n                    if (moreattrs[k] === undefined) {\n                      this.node.removeAttribute(k);\n                    } else {\n                      this.node.setAttribute(k, moreattrs[k]);\n                    }\n                  }\n                }\n\n                return this;\n              }\n              /** Function: c\n               *  Add a child to the current element and make it the new current\n               *  element.\n               *\n               *  This function moves the current element pointer to the child,\n               *  unless text is provided.  If you need to add another child, it\n               *  is necessary to use up() to go back to the parent in the tree.\n               *\n               *  Parameters:\n               *    (String) name - The name of the child.\n               *    (Object) attrs - The attributes of the child in object notation.\n               *    (String) text - The text to add to the child.\n               *\n               *  Returns:\n               *    The Strophe.Builder object.\n               */\n\n\n              c(name, attrs, text) {\n                const child = Strophe.xmlElement(name, attrs, text);\n                this.node.appendChild(child);\n\n                if (typeof text !== \"string\" && typeof text !== \"number\") {\n                  this.node = child;\n                }\n\n                return this;\n              }\n              /** Function: cnode\n               *  Add a child to the current element and make it the new current\n               *  element.\n               *\n               *  This function is the same as c() except that instead of using a\n               *  name and an attributes object to create the child it uses an\n               *  existing DOM element object.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - A DOM element.\n               *\n               *  Returns:\n               *    The Strophe.Builder object.\n               */\n\n\n              cnode(elem) {\n                let impNode;\n                const xmlGen = Strophe.xmlGenerator();\n\n                try {\n                  impNode = xmlGen.importNode !== undefined;\n                } catch (e) {\n                  impNode = false;\n                }\n\n                const newElem = impNode ? xmlGen.importNode(elem, true) : Strophe.copyElement(elem);\n                this.node.appendChild(newElem);\n                this.node = newElem;\n                return this;\n              }\n              /** Function: t\n               *  Add a child text element.\n               *\n               *  This *does not* make the child the new current element since there\n               *  are no children of text elements.\n               *\n               *  Parameters:\n               *    (String) text - The text data to append to the current element.\n               *\n               *  Returns:\n               *    The Strophe.Builder object.\n               */\n\n\n              t(text) {\n                const child = Strophe.xmlTextNode(text);\n                this.node.appendChild(child);\n                return this;\n              }\n              /** Function: h\n               *  Replace current element contents with the HTML passed in.\n               *\n               *  This *does not* make the child the new current element\n               *\n               *  Parameters:\n               *    (String) html - The html to insert as contents of current element.\n               *\n               *  Returns:\n               *    The Strophe.Builder object.\n               */\n\n\n              h(html) {\n                const fragment = Strophe.xmlGenerator().createElement('body'); // force the browser to try and fix any invalid HTML tags\n\n                fragment.innerHTML = html; // copy cleaned html into an xml dom\n\n                const xhtml = Strophe.createHtml(fragment);\n\n                while (xhtml.childNodes.length > 0) {\n                  this.node.appendChild(xhtml.childNodes[0]);\n                }\n\n                return this;\n              }\n\n            };\n            /** PrivateClass: Strophe.Handler\n             *  _Private_ helper class for managing stanza handlers.\n             *\n             *  A Strophe.Handler encapsulates a user provided callback function to be\n             *  executed when matching stanzas are received by the connection.\n             *  Handlers can be either one-off or persistant depending on their\n             *  return value. Returning true will cause a Handler to remain active, and\n             *  returning false will remove the Handler.\n             *\n             *  Users will not use Strophe.Handler objects directly, but instead they\n             *  will use Strophe.Connection.addHandler() and\n             *  Strophe.Connection.deleteHandler().\n             */\n\n            /** PrivateConstructor: Strophe.Handler\n             *  Create and initialize a new Strophe.Handler.\n             *\n             *  Parameters:\n             *    (Function) handler - A function to be executed when the handler is run.\n             *    (String) ns - The namespace to match.\n             *    (String) name - The element name to match.\n             *    (String) type - The element type to match.\n             *    (String) id - The element id attribute to match.\n             *    (String) from - The element from attribute to match.\n             *    (Object) options - Handler options\n             *\n             *  Returns:\n             *    A new Strophe.Handler object.\n             */\n\n            Strophe.Handler = function (handler, ns, name, type, id, from, options) {\n              this.handler = handler;\n              this.ns = ns;\n              this.name = name;\n              this.type = type;\n              this.id = id;\n              this.options = options || {\n                'matchBareFromJid': false,\n                'ignoreNamespaceFragment': false\n              }; // BBB: Maintain backward compatibility with old `matchBare` option\n\n              if (this.options.matchBare) {\n                Strophe.warn('The \"matchBare\" option is deprecated, use \"matchBareFromJid\" instead.');\n                this.options.matchBareFromJid = this.options.matchBare;\n                delete this.options.matchBare;\n              }\n\n              if (this.options.matchBareFromJid) {\n                this.from = from ? Strophe.getBareJidFromJid(from) : null;\n              } else {\n                this.from = from;\n              } // whether the handler is a user handler or a system handler\n\n\n              this.user = true;\n            };\n\n            Strophe.Handler.prototype = {\n              /** PrivateFunction: getNamespace\n               *  Returns the XML namespace attribute on an element.\n               *  If `ignoreNamespaceFragment` was passed in for this handler, then the\n               *  URL fragment will be stripped.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XML element with the namespace.\n               *\n               *  Returns:\n               *    The namespace, with optionally the fragment stripped.\n               */\n              getNamespace(elem) {\n                let elNamespace = elem.getAttribute(\"xmlns\");\n\n                if (elNamespace && this.options.ignoreNamespaceFragment) {\n                  elNamespace = elNamespace.split('#')[0];\n                }\n\n                return elNamespace;\n              },\n\n              /** PrivateFunction: namespaceMatch\n               *  Tests if a stanza matches the namespace set for this Strophe.Handler.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XML element to test.\n               *\n               *  Returns:\n               *    true if the stanza matches and false otherwise.\n               */\n              namespaceMatch(elem) {\n                let nsMatch = false;\n\n                if (!this.ns) {\n                  return true;\n                } else {\n                  Strophe.forEachChild(elem, null, elem => {\n                    if (this.getNamespace(elem) === this.ns) {\n                      nsMatch = true;\n                    }\n                  });\n                  return nsMatch || this.getNamespace(elem) === this.ns;\n                }\n              },\n\n              /** PrivateFunction: isMatch\n               *  Tests if a stanza matches the Strophe.Handler.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XML element to test.\n               *\n               *  Returns:\n               *    true if the stanza matches and false otherwise.\n               */\n              isMatch(elem) {\n                let from = elem.getAttribute('from');\n\n                if (this.options.matchBareFromJid) {\n                  from = Strophe.getBareJidFromJid(from);\n                }\n\n                const elem_type = elem.getAttribute(\"type\");\n\n                if (this.namespaceMatch(elem) && (!this.name || Strophe.isTagEqual(elem, this.name)) && (!this.type || (Array.isArray(this.type) ? this.type.indexOf(elem_type) !== -1 : elem_type === this.type)) && (!this.id || elem.getAttribute(\"id\") === this.id) && (!this.from || from === this.from)) {\n                  return true;\n                }\n\n                return false;\n              },\n\n              /** PrivateFunction: run\n               *  Run the callback on a matching stanza.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The DOM element that triggered the\n               *      Strophe.Handler.\n               *\n               *  Returns:\n               *    A boolean indicating if the handler should remain active.\n               */\n              run(elem) {\n                let result = null;\n\n                try {\n                  result = this.handler(elem);\n                } catch (e) {\n                  Strophe._handleError(e);\n\n                  throw e;\n                }\n\n                return result;\n              },\n\n              /** PrivateFunction: toString\n               *  Get a String representation of the Strophe.Handler object.\n               *\n               *  Returns:\n               *    A String.\n               */\n              toString() {\n                return \"{Handler: \" + this.handler + \"(\" + this.name + \",\" + this.id + \",\" + this.ns + \")}\";\n              }\n\n            };\n            /** PrivateClass: Strophe.TimedHandler\n             *  _Private_ helper class for managing timed handlers.\n             *\n             *  A Strophe.TimedHandler encapsulates a user provided callback that\n             *  should be called after a certain period of time or at regular\n             *  intervals.  The return value of the callback determines whether the\n             *  Strophe.TimedHandler will continue to fire.\n             *\n             *  Users will not use Strophe.TimedHandler objects directly, but instead\n             *  they will use Strophe.Connection.addTimedHandler() and\n             *  Strophe.Connection.deleteTimedHandler().\n             */\n\n            Strophe.TimedHandler = class TimedHandler {\n              /** PrivateConstructor: Strophe.TimedHandler\n               *  Create and initialize a new Strophe.TimedHandler object.\n               *\n               *  Parameters:\n               *    (Integer) period - The number of milliseconds to wait before the\n               *      handler is called.\n               *    (Function) handler - The callback to run when the handler fires.  This\n               *      function should take no arguments.\n               *\n               *  Returns:\n               *    A new Strophe.TimedHandler object.\n               */\n              constructor(period, handler) {\n                this.period = period;\n                this.handler = handler;\n                this.lastCalled = new Date().getTime();\n                this.user = true;\n              }\n              /** PrivateFunction: run\n               *  Run the callback for the Strophe.TimedHandler.\n               *\n               *  Returns:\n               *    true if the Strophe.TimedHandler should be called again, and false\n               *      otherwise.\n               */\n\n\n              run() {\n                this.lastCalled = new Date().getTime();\n                return this.handler();\n              }\n              /** PrivateFunction: reset\n               *  Reset the last called time for the Strophe.TimedHandler.\n               */\n\n\n              reset() {\n                this.lastCalled = new Date().getTime();\n              }\n              /** PrivateFunction: toString\n               *  Get a string representation of the Strophe.TimedHandler object.\n               *\n               *  Returns:\n               *    The string representation.\n               */\n\n\n              toString() {\n                return \"{TimedHandler: \" + this.handler + \"(\" + this.period + \")}\";\n              }\n\n            };\n            /** Class: Strophe.Connection\n             *  XMPP Connection manager.\n             *\n             *  This class is the main part of Strophe.  It manages a BOSH or websocket\n             *  connection to an XMPP server and dispatches events to the user callbacks\n             *  as data arrives. It supports SASL PLAIN, SASL SCRAM-SHA-1\n             *  and legacy authentication.\n             *\n             *  After creating a Strophe.Connection object, the user will typically\n             *  call connect() with a user supplied callback to handle connection level\n             *  events like authentication failure, disconnection, or connection\n             *  complete.\n             *\n             *  The user will also have several event handlers defined by using\n             *  addHandler() and addTimedHandler().  These will allow the user code to\n             *  respond to interesting stanzas or do something periodically with the\n             *  connection. These handlers will be active once authentication is\n             *  finished.\n             *\n             *  To send data to the connection, use send().\n             */\n\n            /** Constructor: Strophe.Connection\n             *  Create and initialize a Strophe.Connection object.\n             *\n             *  The transport-protocol for this connection will be chosen automatically\n             *  based on the given service parameter. URLs starting with \"ws://\" or\n             *  \"wss://\" will use WebSockets, URLs starting with \"http://\", \"https://\"\n             *  or without a protocol will use BOSH.\n             *\n             *  To make Strophe connect to the current host you can leave out the protocol\n             *  and host part and just pass the path, e.g.\n             *\n             *  > let conn = new Strophe.Connection(\"/http-bind/\");\n             *\n             *  Options common to both Websocket and BOSH:\n             *  ------------------------------------------\n             *\n             *  cookies:\n             *\n             *  The *cookies* option allows you to pass in cookies to be added to the\n             *  document. These cookies will then be included in the BOSH XMLHttpRequest\n             *  or in the websocket connection.\n             *\n             *  The passed in value must be a map of cookie names and string values.\n             *\n             *  > { \"myCookie\": {\n             *  >     \"value\": \"1234\",\n             *  >     \"domain\": \".example.org\",\n             *  >     \"path\": \"/\",\n             *  >     \"expires\": expirationDate\n             *  >     }\n             *  > }\n             *\n             *  Note that cookies can't be set in this way for other domains (i.e. cross-domain).\n             *  Those cookies need to be set under those domains, for example they can be\n             *  set server-side by making a XHR call to that domain to ask it to set any\n             *  necessary cookies.\n             *\n             *  mechanisms:\n             *\n             *  The *mechanisms* option allows you to specify the SASL mechanisms that this\n             *  instance of Strophe.Connection (and therefore your XMPP client) will\n             *  support.\n             *\n             *  The value must be an array of objects with Strophe.SASLMechanism\n             *  prototypes.\n             *\n             *  If nothing is specified, then the following mechanisms (and their\n             *  priorities) are registered:\n             *\n             *      SCRAM-SHA-1 - 60\n             *      PLAIN       - 50\n             *      OAUTHBEARER - 40\n             *      X-OAUTH2    - 30\n             *      ANONYMOUS   - 20\n             *      EXTERNAL    - 10\n             *\n             *  explicitResourceBinding:\n             *\n             *  If `explicitResourceBinding` is set to a truthy value, then the XMPP client\n             *  needs to explicitly call `Strophe.Connection.prototype.bind` once the XMPP\n             *  server has advertised the \"urn:ietf:params:xml:ns:xmpp-bind\" feature.\n             *\n             *  Making this step explicit allows client authors to first finish other\n             *  stream related tasks, such as setting up an XEP-0198 Stream Management\n             *  session, before binding the JID resource for this session.\n             *\n             *  WebSocket options:\n             *  ------------------\n             *\n             *  protocol:\n             *\n             *  If you want to connect to the current host with a WebSocket connection you\n             *  can tell Strophe to use WebSockets through a \"protocol\" attribute in the\n             *  optional options parameter. Valid values are \"ws\" for WebSocket and \"wss\"\n             *  for Secure WebSocket.\n             *  So to connect to \"wss://CURRENT_HOSTNAME/xmpp-websocket\" you would call\n             *\n             *  > let conn = new Strophe.Connection(\"/xmpp-websocket/\", {protocol: \"wss\"});\n             *\n             *  Note that relative URLs _NOT_ starting with a \"/\" will also include the path\n             *  of the current site.\n             *\n             *  Also because downgrading security is not permitted by browsers, when using\n             *  relative URLs both BOSH and WebSocket connections will use their secure\n             *  variants if the current connection to the site is also secure (https).\n             *\n             *  worker:\n             *\n             *  Set this option to URL from where the shared worker script should be loaded.\n             *\n             *  To run the websocket connection inside a shared worker.\n             *  This allows you to share a single websocket-based connection between\n             *  multiple Strophe.Connection instances, for example one per browser tab.\n             *\n             *  The script to use is the one in `src/shared-connection-worker.js`.\n             *\n             *  BOSH options:\n             *  -------------\n             *\n             *  By adding \"sync\" to the options, you can control if requests will\n             *  be made synchronously or not. The default behaviour is asynchronous.\n             *  If you want to make requests synchronous, make \"sync\" evaluate to true.\n             *  > let conn = new Strophe.Connection(\"/http-bind/\", {sync: true});\n             *\n             *  You can also toggle this on an already established connection.\n             *  > conn.options.sync = true;\n             *\n             *  The *customHeaders* option can be used to provide custom HTTP headers to be\n             *  included in the XMLHttpRequests made.\n             *\n             *  The *keepalive* option can be used to instruct Strophe to maintain the\n             *  current BOSH session across interruptions such as webpage reloads.\n             *\n             *  It will do this by caching the sessions tokens in sessionStorage, and when\n             *  \"restore\" is called it will check whether there are cached tokens with\n             *  which it can resume an existing session.\n             *\n             *  The *withCredentials* option should receive a Boolean value and is used to\n             *  indicate wether cookies should be included in ajax requests (by default\n             *  they're not).\n             *  Set this value to true if you are connecting to a BOSH service\n             *  and for some reason need to send cookies to it.\n             *  In order for this to work cross-domain, the server must also enable\n             *  credentials by setting the Access-Control-Allow-Credentials response header\n             *  to \"true\". For most usecases however this setting should be false (which\n             *  is the default).\n             *  Additionally, when using Access-Control-Allow-Credentials, the\n             *  Access-Control-Allow-Origin header can't be set to the wildcard \"*\", but\n             *  instead must be restricted to actual domains.\n             *\n             *  The *contentType* option can be set to change the default Content-Type\n             *  of \"text/xml; charset=utf-8\", which can be useful to reduce the amount of\n             *  CORS preflight requests that are sent to the server.\n             *\n             *  Parameters:\n             *    (String) service - The BOSH or WebSocket service URL.\n             *    (Object) options - A hash of configuration options\n             *\n             *  Returns:\n             *    A new Strophe.Connection object.\n             */\n\n            Strophe.Connection = class Connection {\n              constructor(service, options) {\n                // The service URL\n                this.service = service; // Configuration options\n\n                this.options = options || {};\n                this.setProtocol();\n                /* The connected JID. */\n\n                this.jid = \"\";\n                /* the JIDs domain */\n\n                this.domain = null;\n                /* stream:features */\n\n                this.features = null; // SASL\n\n                this._sasl_data = {};\n                this.do_bind = false;\n                this.do_session = false;\n                this.mechanisms = {}; // handler lists\n\n                this.timedHandlers = [];\n                this.handlers = [];\n                this.removeTimeds = [];\n                this.removeHandlers = [];\n                this.addTimeds = [];\n                this.addHandlers = [];\n                this.protocolErrorHandlers = {\n                  'HTTP': {},\n                  'websocket': {}\n                };\n                this._idleTimeout = null;\n                this._disconnectTimeout = null;\n                this.authenticated = false;\n                this.connected = false;\n                this.disconnecting = false;\n                this.do_authentication = true;\n                this.paused = false;\n                this.restored = false;\n                this._data = [];\n                this._uniqueId = 0;\n                this._sasl_success_handler = null;\n                this._sasl_failure_handler = null;\n                this._sasl_challenge_handler = null; // Max retries before disconnecting\n\n                this.maxRetries = 5; // Call onIdle callback every 1/10th of a second\n\n                this._idleTimeout = setTimeout(() => this._onIdle(), 100);\n                utils.addCookies(this.options.cookies);\n                this.registerSASLMechanisms(this.options.mechanisms); // A client must always respond to incoming IQ \"set\" and \"get\" stanzas.\n                // See https://datatracker.ietf.org/doc/html/rfc6120#section-8.2.3\n                //\n                // This is a fallback handler which gets called when no other handler\n                // was called for a received IQ \"set\" or \"get\".\n\n                this.iqFallbackHandler = new Strophe.Handler(iq => this.send($iq({\n                  type: 'error',\n                  id: iq.getAttribute('id')\n                }).c('error', {\n                  'type': 'cancel'\n                }).c('service-unavailable', {\n                  'xmlns': Strophe.NS.STANZAS\n                })), null, 'iq', ['get', 'set']); // initialize plugins\n\n                for (const k in Strophe._connectionPlugins) {\n                  if (Object.prototype.hasOwnProperty.call(Strophe._connectionPlugins, k)) {\n                    const F = function () {};\n\n                    F.prototype = Strophe._connectionPlugins[k];\n                    this[k] = new F();\n                    this[k].init(this);\n                  }\n                }\n              }\n              /** Function: setProtocol\n               *  Select protocal based on this.options or this.service\n               */\n\n\n              setProtocol() {\n                const proto = this.options.protocol || \"\";\n\n                if (this.options.worker) {\n                  this._proto = new Strophe.WorkerWebsocket(this);\n                } else if (this.service.indexOf(\"ws:\") === 0 || this.service.indexOf(\"wss:\") === 0 || proto.indexOf(\"ws\") === 0) {\n                  this._proto = new Strophe.Websocket(this);\n                } else {\n                  this._proto = new Strophe.Bosh(this);\n                }\n              }\n              /** Function: reset\n               *  Reset the connection.\n               *\n               *  This function should be called after a connection is disconnected\n               *  before that connection is reused.\n               */\n\n\n              reset() {\n                this._proto._reset(); // SASL\n\n\n                this.do_session = false;\n                this.do_bind = false; // handler lists\n\n                this.timedHandlers = [];\n                this.handlers = [];\n                this.removeTimeds = [];\n                this.removeHandlers = [];\n                this.addTimeds = [];\n                this.addHandlers = [];\n                this.authenticated = false;\n                this.connected = false;\n                this.disconnecting = false;\n                this.restored = false;\n                this._data = [];\n                this._requests = [];\n                this._uniqueId = 0;\n              }\n              /** Function: pause\n               *  Pause the request manager.\n               *\n               *  This will prevent Strophe from sending any more requests to the\n               *  server.  This is very useful for temporarily pausing\n               *  BOSH-Connections while a lot of send() calls are happening quickly.\n               *  This causes Strophe to send the data in a single request, saving\n               *  many request trips.\n               */\n\n\n              pause() {\n                this.paused = true;\n              }\n              /** Function: resume\n               *  Resume the request manager.\n               *\n               *  This resumes after pause() has been called.\n               */\n\n\n              resume() {\n                this.paused = false;\n              }\n              /** Function: getUniqueId\n               *  Generate a unique ID for use in <iq/> elements.\n               *\n               *  All <iq/> stanzas are required to have unique id attributes.  This\n               *  function makes creating these easy.  Each connection instance has\n               *  a counter which starts from zero, and the value of this counter\n               *  plus a colon followed by the suffix becomes the unique id. If no\n               *  suffix is supplied, the counter is used as the unique id.\n               *\n               *  Suffixes are used to make debugging easier when reading the stream\n               *  data, and their use is recommended.  The counter resets to 0 for\n               *  every new connection for the same reason.  For connections to the\n               *  same server that authenticate the same way, all the ids should be\n               *  the same, which makes it easy to see changes.  This is useful for\n               *  automated testing as well.\n               *\n               *  Parameters:\n               *    (String) suffix - A optional suffix to append to the id.\n               *\n               *  Returns:\n               *    A unique string to be used for the id attribute.\n               */\n\n\n              getUniqueId(suffix) {\n                // eslint-disable-line class-methods-use-this\n                const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n                  const r = Math.random() * 16 | 0,\n                        v = c === 'x' ? r : r & 0x3 | 0x8;\n                  return v.toString(16);\n                });\n\n                if (typeof suffix === \"string\" || typeof suffix === \"number\") {\n                  return uuid + \":\" + suffix;\n                } else {\n                  return uuid + \"\";\n                }\n              }\n              /** Function: addProtocolErrorHandler\n               *  Register a handler function for when a protocol (websocker or HTTP)\n               *  error occurs.\n               *\n               *  NOTE: Currently only HTTP errors for BOSH requests are handled.\n               *  Patches that handle websocket errors would be very welcome.\n               *\n               *  Parameters:\n               *    (String) protocol - 'HTTP' or 'websocket'\n               *    (Integer) status_code - Error status code (e.g 500, 400 or 404)\n               *    (Function) callback - Function that will fire on Http error\n               *\n               *  Example:\n               *  function onError(err_code){\n               *    //do stuff\n               *  }\n               *\n               *  let conn = Strophe.connect('http://example.com/http-bind');\n               *  conn.addProtocolErrorHandler('HTTP', 500, onError);\n               *  // Triggers HTTP 500 error and onError handler will be called\n               *  conn.connect('user_jid@incorrect_jabber_host', 'secret', onConnect);\n               */\n\n\n              addProtocolErrorHandler(protocol, status_code, callback) {\n                this.protocolErrorHandlers[protocol][status_code] = callback;\n              }\n              /** Function: connect\n               *  Starts the connection process.\n               *\n               *  As the connection process proceeds, the user supplied callback will\n               *  be triggered multiple times with status updates.  The callback\n               *  should take two arguments - the status code and the error condition.\n               *\n               *  The status code will be one of the values in the Strophe.Status\n               *  constants.  The error condition will be one of the conditions\n               *  defined in RFC 3920 or the condition 'strophe-parsererror'.\n               *\n               *  The Parameters _wait_, _hold_ and _route_ are optional and only relevant\n               *  for BOSH connections. Please see XEP 124 for a more detailed explanation\n               *  of the optional parameters.\n               *\n               *  Parameters:\n               *    (String) jid - The user's JID.  This may be a bare JID,\n               *      or a full JID.  If a node is not supplied, SASL OAUTHBEARER or\n               *      SASL ANONYMOUS authentication will be attempted (OAUTHBEARER will\n               *      process the provided password value as an access token).\n               *    (String) pass - The user's password.\n               *    (Function) callback - The connect callback function.\n               *    (Integer) wait - The optional HTTPBIND wait value.  This is the\n               *      time the server will wait before returning an empty result for\n               *      a request.  The default setting of 60 seconds is recommended.\n               *    (Integer) hold - The optional HTTPBIND hold value.  This is the\n               *      number of connections the server will hold at one time.  This\n               *      should almost always be set to 1 (the default).\n               *    (String) route - The optional route value.\n               *    (String) authcid - The optional alternative authentication identity\n               *      (username) if intending to impersonate another user.\n               *      When using the SASL-EXTERNAL authentication mechanism, for example\n               *      with client certificates, then the authcid value is used to\n               *      determine whether an authorization JID (authzid) should be sent to\n               *      the server. The authzid should NOT be sent to the server if the\n               *      authzid and authcid are the same. So to prevent it from being sent\n               *      (for example when the JID is already contained in the client\n               *      certificate), set authcid to that same JID. See XEP-178 for more\n               *      details.\n               *     (Integer) disconnection_timeout - The optional disconnection timeout\n               *      in milliseconds before _doDisconnect will be called.\n               */\n\n\n              connect(jid, pass, callback, wait, hold, route, authcid) {\n                let disconnection_timeout = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 3000;\n                this.jid = jid;\n                /** Variable: authzid\n                 *  Authorization identity.\n                 */\n\n                this.authzid = Strophe.getBareJidFromJid(this.jid);\n                /** Variable: authcid\n                 *  Authentication identity (User name).\n                 */\n\n                this.authcid = authcid || Strophe.getNodeFromJid(this.jid);\n                /** Variable: pass\n                 *  Authentication identity (User password).\n                 */\n\n                this.pass = pass;\n                this.connect_callback = callback;\n                this.disconnecting = false;\n                this.connected = false;\n                this.authenticated = false;\n                this.restored = false;\n                this.disconnection_timeout = disconnection_timeout; // parse jid for domain\n\n                this.domain = Strophe.getDomainFromJid(this.jid);\n\n                this._changeConnectStatus(Strophe.Status.CONNECTING, null);\n\n                this._proto._connect(wait, hold, route);\n              }\n              /** Function: attach\n               *  Attach to an already created and authenticated BOSH session.\n               *\n               *  This function is provided to allow Strophe to attach to BOSH\n               *  sessions which have been created externally, perhaps by a Web\n               *  application.  This is often used to support auto-login type features\n               *  without putting user credentials into the page.\n               *\n               *  Parameters:\n               *    (String) jid - The full JID that is bound by the session.\n               *    (String) sid - The SID of the BOSH session.\n               *    (String) rid - The current RID of the BOSH session.  This RID\n               *      will be used by the next request.\n               *    (Function) callback The connect callback function.\n               *    (Integer) wait - The optional HTTPBIND wait value.  This is the\n               *      time the server will wait before returning an empty result for\n               *      a request.  The default setting of 60 seconds is recommended.\n               *      Other settings will require tweaks to the Strophe.TIMEOUT value.\n               *    (Integer) hold - The optional HTTPBIND hold value.  This is the\n               *      number of connections the server will hold at one time.  This\n               *      should almost always be set to 1 (the default).\n               *    (Integer) wind - The optional HTTBIND window value.  This is the\n               *      allowed range of request ids that are valid.  The default is 5.\n               */\n\n\n              attach(jid, sid, rid, callback, wait, hold, wind) {\n                if (this._proto._attach) {\n                  return this._proto._attach(jid, sid, rid, callback, wait, hold, wind);\n                } else {\n                  const error = new Error('The \"attach\" method is not available for your connection protocol');\n                  error.name = 'StropheSessionError';\n                  throw error;\n                }\n              }\n              /** Function: restore\n               *  Attempt to restore a cached BOSH session.\n               *\n               *  This function is only useful in conjunction with providing the\n               *  \"keepalive\":true option when instantiating a new Strophe.Connection.\n               *\n               *  When \"keepalive\" is set to true, Strophe will cache the BOSH tokens\n               *  RID (Request ID) and SID (Session ID) and then when this function is\n               *  called, it will attempt to restore the session from those cached\n               *  tokens.\n               *\n               *  This function must therefore be called instead of connect or attach.\n               *\n               *  For an example on how to use it, please see examples/restore.js\n               *\n               *  Parameters:\n               *    (String) jid - The user's JID.  This may be a bare JID or a full JID.\n               *    (Function) callback - The connect callback function.\n               *    (Integer) wait - The optional HTTPBIND wait value.  This is the\n               *      time the server will wait before returning an empty result for\n               *      a request.  The default setting of 60 seconds is recommended.\n               *    (Integer) hold - The optional HTTPBIND hold value.  This is the\n               *      number of connections the server will hold at one time.  This\n               *      should almost always be set to 1 (the default).\n               *    (Integer) wind - The optional HTTBIND window value.  This is the\n               *      allowed range of request ids that are valid.  The default is 5.\n               */\n\n\n              restore(jid, callback, wait, hold, wind) {\n                if (this._sessionCachingSupported()) {\n                  this._proto._restore(jid, callback, wait, hold, wind);\n                } else {\n                  const error = new Error('The \"restore\" method can only be used with a BOSH connection.');\n                  error.name = 'StropheSessionError';\n                  throw error;\n                }\n              }\n              /** PrivateFunction: _sessionCachingSupported\n               * Checks whether sessionStorage and JSON are supported and whether we're\n               * using BOSH.\n               */\n\n\n              _sessionCachingSupported() {\n                if (this._proto instanceof Strophe.Bosh) {\n                  if (!JSON) {\n                    return false;\n                  }\n\n                  try {\n                    sessionStorage.setItem('_strophe_', '_strophe_');\n                    sessionStorage.removeItem('_strophe_');\n                  } catch (e) {\n                    return false;\n                  }\n\n                  return true;\n                }\n\n                return false;\n              }\n              /** Function: xmlInput\n               *  User overrideable function that receives XML data coming into the\n               *  connection.\n               *\n               *  The default function does nothing.  User code can override this with\n               *  > Strophe.Connection.xmlInput = function (elem) {\n               *  >   (user code)\n               *  > };\n               *\n               *  Due to limitations of current Browsers' XML-Parsers the opening and closing\n               *  <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.\n               *\n               *  BOSH-Connections will have all stanzas wrapped in a <body> tag. See\n               *  <Strophe.Bosh.strip> if you want to strip this tag.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XML data received by the connection.\n               */\n\n\n              xmlInput(elem) {\n                // eslint-disable-line\n                return;\n              }\n              /** Function: xmlOutput\n               *  User overrideable function that receives XML data sent to the\n               *  connection.\n               *\n               *  The default function does nothing.  User code can override this with\n               *  > Strophe.Connection.xmlOutput = function (elem) {\n               *  >   (user code)\n               *  > };\n               *\n               *  Due to limitations of current Browsers' XML-Parsers the opening and closing\n               *  <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.\n               *\n               *  BOSH-Connections will have all stanzas wrapped in a <body> tag. See\n               *  <Strophe.Bosh.strip> if you want to strip this tag.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XMLdata sent by the connection.\n               */\n\n\n              xmlOutput(elem) {\n                // eslint-disable-line\n                return;\n              }\n              /** Function: rawInput\n               *  User overrideable function that receives raw data coming into the\n               *  connection.\n               *\n               *  The default function does nothing.  User code can override this with\n               *  > Strophe.Connection.rawInput = function (data) {\n               *  >   (user code)\n               *  > };\n               *\n               *  Parameters:\n               *    (String) data - The data received by the connection.\n               */\n\n\n              rawInput(data) {\n                // eslint-disable-line\n                return;\n              }\n              /** Function: rawOutput\n               *  User overrideable function that receives raw data sent to the\n               *  connection.\n               *\n               *  The default function does nothing.  User code can override this with\n               *  > Strophe.Connection.rawOutput = function (data) {\n               *  >   (user code)\n               *  > };\n               *\n               *  Parameters:\n               *    (String) data - The data sent by the connection.\n               */\n\n\n              rawOutput(data) {\n                // eslint-disable-line\n                return;\n              }\n              /** Function: nextValidRid\n               *  User overrideable function that receives the new valid rid.\n               *\n               *  The default function does nothing. User code can override this with\n               *  > Strophe.Connection.nextValidRid = function (rid) {\n               *  >    (user code)\n               *  > };\n               *\n               *  Parameters:\n               *    (Number) rid - The next valid rid\n               */\n\n\n              nextValidRid(rid) {\n                // eslint-disable-line\n                return;\n              }\n              /** Function: send\n               *  Send a stanza.\n               *\n               *  This function is called to push data onto the send queue to\n               *  go out over the wire.  Whenever a request is sent to the BOSH\n               *  server, all pending data is sent and the queue is flushed.\n               *\n               *  Parameters:\n               *    (XMLElement |\n               *     [XMLElement] |\n               *     Strophe.Builder) elem - The stanza to send.\n               */\n\n\n              send(elem) {\n                if (elem === null) {\n                  return;\n                }\n\n                if (typeof elem.sort === \"function\") {\n                  for (let i = 0; i < elem.length; i++) {\n                    this._queueData(elem[i]);\n                  }\n                } else if (typeof elem.tree === \"function\") {\n                  this._queueData(elem.tree());\n                } else {\n                  this._queueData(elem);\n                }\n\n                this._proto._send();\n              }\n              /** Function: flush\n               *  Immediately send any pending outgoing data.\n               *\n               *  Normally send() queues outgoing data until the next idle period\n               *  (100ms), which optimizes network use in the common cases when\n               *  several send()s are called in succession. flush() can be used to\n               *  immediately send all pending data.\n               */\n\n\n              flush() {\n                // cancel the pending idle period and run the idle function\n                // immediately\n                clearTimeout(this._idleTimeout);\n\n                this._onIdle();\n              }\n              /** Function: sendPresence\n               *  Helper function to send presence stanzas. The main benefit is for\n               *  sending presence stanzas for which you expect a responding presence\n               *  stanza with the same id (for example when leaving a chat room).\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The stanza to send.\n               *    (Function) callback - The callback function for a successful request.\n               *    (Function) errback - The callback function for a failed or timed\n               *      out request.  On timeout, the stanza will be null.\n               *    (Integer) timeout - The time specified in milliseconds for a\n               *      timeout to occur.\n               *\n               *  Returns:\n               *    The id used to send the presence.\n               */\n\n\n              sendPresence(elem, callback, errback, timeout) {\n                let timeoutHandler = null;\n\n                if (typeof elem.tree === \"function\") {\n                  elem = elem.tree();\n                }\n\n                let id = elem.getAttribute('id');\n\n                if (!id) {\n                  // inject id if not found\n                  id = this.getUniqueId(\"sendPresence\");\n                  elem.setAttribute(\"id\", id);\n                }\n\n                if (typeof callback === \"function\" || typeof errback === \"function\") {\n                  const handler = this.addHandler(stanza => {\n                    // remove timeout handler if there is one\n                    if (timeoutHandler) {\n                      this.deleteTimedHandler(timeoutHandler);\n                    }\n\n                    if (stanza.getAttribute('type') === 'error') {\n                      if (errback) {\n                        errback(stanza);\n                      }\n                    } else if (callback) {\n                      callback(stanza);\n                    }\n                  }, null, 'presence', null, id); // if timeout specified, set up a timeout handler.\n\n                  if (timeout) {\n                    timeoutHandler = this.addTimedHandler(timeout, () => {\n                      // get rid of normal handler\n                      this.deleteHandler(handler); // call errback on timeout with null stanza\n\n                      if (errback) {\n                        errback(null);\n                      }\n\n                      return false;\n                    });\n                  }\n                }\n\n                this.send(elem);\n                return id;\n              }\n              /** Function: sendIQ\n               *  Helper function to send IQ stanzas.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The stanza to send.\n               *    (Function) callback - The callback function for a successful request.\n               *    (Function) errback - The callback function for a failed or timed\n               *      out request.  On timeout, the stanza will be null.\n               *    (Integer) timeout - The time specified in milliseconds for a\n               *      timeout to occur.\n               *\n               *  Returns:\n               *    The id used to send the IQ.\n              */\n\n\n              sendIQ(elem, callback, errback, timeout) {\n                let timeoutHandler = null;\n\n                if (typeof elem.tree === \"function\") {\n                  elem = elem.tree();\n                }\n\n                let id = elem.getAttribute('id');\n\n                if (!id) {\n                  // inject id if not found\n                  id = this.getUniqueId(\"sendIQ\");\n                  elem.setAttribute(\"id\", id);\n                }\n\n                if (typeof callback === \"function\" || typeof errback === \"function\") {\n                  const handler = this.addHandler(stanza => {\n                    // remove timeout handler if there is one\n                    if (timeoutHandler) {\n                      this.deleteTimedHandler(timeoutHandler);\n                    }\n\n                    const iqtype = stanza.getAttribute('type');\n\n                    if (iqtype === 'result') {\n                      if (callback) {\n                        callback(stanza);\n                      }\n                    } else if (iqtype === 'error') {\n                      if (errback) {\n                        errback(stanza);\n                      }\n                    } else {\n                      const error = new Error(`Got bad IQ type of ${iqtype}`);\n                      error.name = \"StropheError\";\n                      throw error;\n                    }\n                  }, null, 'iq', ['error', 'result'], id); // if timeout specified, set up a timeout handler.\n\n                  if (timeout) {\n                    timeoutHandler = this.addTimedHandler(timeout, () => {\n                      // get rid of normal handler\n                      this.deleteHandler(handler); // call errback on timeout with null stanza\n\n                      if (errback) {\n                        errback(null);\n                      }\n\n                      return false;\n                    });\n                  }\n                }\n\n                this.send(elem);\n                return id;\n              }\n              /** PrivateFunction: _queueData\n               *  Queue outgoing data for later sending.  Also ensures that the data\n               *  is a DOMElement.\n               */\n\n\n              _queueData(element) {\n                if (element === null || !element.tagName || !element.childNodes) {\n                  const error = new Error(\"Cannot queue non-DOMElement.\");\n                  error.name = \"StropheError\";\n                  throw error;\n                }\n\n                this._data.push(element);\n              }\n              /** PrivateFunction: _sendRestart\n               *  Send an xmpp:restart stanza.\n               */\n\n\n              _sendRestart() {\n                this._data.push(\"restart\");\n\n                this._proto._sendRestart();\n\n                this._idleTimeout = setTimeout(() => this._onIdle(), 100);\n              }\n              /** Function: addTimedHandler\n               *  Add a timed handler to the connection.\n               *\n               *  This function adds a timed handler.  The provided handler will\n               *  be called every period milliseconds until it returns false,\n               *  the connection is terminated, or the handler is removed.  Handlers\n               *  that wish to continue being invoked should return true.\n               *\n               *  Because of method binding it is necessary to save the result of\n               *  this function if you wish to remove a handler with\n               *  deleteTimedHandler().\n               *\n               *  Note that user handlers are not active until authentication is\n               *  successful.\n               *\n               *  Parameters:\n               *    (Integer) period - The period of the handler.\n               *    (Function) handler - The callback function.\n               *\n               *  Returns:\n               *    A reference to the handler that can be used to remove it.\n               */\n\n\n              addTimedHandler(period, handler) {\n                const thand = new Strophe.TimedHandler(period, handler);\n                this.addTimeds.push(thand);\n                return thand;\n              }\n              /** Function: deleteTimedHandler\n               *  Delete a timed handler for a connection.\n               *\n               *  This function removes a timed handler from the connection.  The\n               *  handRef parameter is *not* the function passed to addTimedHandler(),\n               *  but is the reference returned from addTimedHandler().\n               *\n               *  Parameters:\n               *    (Strophe.TimedHandler) handRef - The handler reference.\n               */\n\n\n              deleteTimedHandler(handRef) {\n                // this must be done in the Idle loop so that we don't change\n                // the handlers during iteration\n                this.removeTimeds.push(handRef);\n              }\n              /** Function: addHandler\n               *  Add a stanza handler for the connection.\n               *\n               *  This function adds a stanza handler to the connection.  The\n               *  handler callback will be called for any stanza that matches\n               *  the parameters.  Note that if multiple parameters are supplied,\n               *  they must all match for the handler to be invoked.\n               *\n               *  The handler will receive the stanza that triggered it as its argument.\n               *  *The handler should return true if it is to be invoked again;\n               *  returning false will remove the handler after it returns.*\n               *\n               *  As a convenience, the ns parameters applies to the top level element\n               *  and also any of its immediate children.  This is primarily to make\n               *  matching /iq/query elements easy.\n               *\n               *  Options\n               *  ~~~~~~~\n               *  With the options argument, you can specify boolean flags that affect how\n               *  matches are being done.\n               *\n               *  Currently two flags exist:\n               *\n               *  - matchBareFromJid:\n               *      When set to true, the from parameter and the\n               *      from attribute on the stanza will be matched as bare JIDs instead\n               *      of full JIDs. To use this, pass {matchBareFromJid: true} as the\n               *      value of options. The default value for matchBareFromJid is false.\n               *\n               *  - ignoreNamespaceFragment:\n               *      When set to true, a fragment specified on the stanza's namespace\n               *      URL will be ignored when it's matched with the one configured for\n               *      the handler.\n               *\n               *      This means that if you register like this:\n               *      >   connection.addHandler(\n               *      >       handler,\n               *      >       'http://jabber.org/protocol/muc',\n               *      >       null, null, null, null,\n               *      >       {'ignoreNamespaceFragment': true}\n               *      >   );\n               *\n               *      Then a stanza with XML namespace of\n               *      'http://jabber.org/protocol/muc#user' will also be matched. If\n               *      'ignoreNamespaceFragment' is false, then only stanzas with\n               *      'http://jabber.org/protocol/muc' will be matched.\n               *\n               *  Deleting the handler\n               *  ~~~~~~~~~~~~~~~~~~~~\n               *  The return value should be saved if you wish to remove the handler\n               *  with deleteHandler().\n               *\n               *  Parameters:\n               *    (Function) handler - The user callback.\n               *    (String) ns - The namespace to match.\n               *    (String) name - The stanza name to match.\n               *    (String|Array) type - The stanza type (or types if an array) to match.\n               *    (String) id - The stanza id attribute to match.\n               *    (String) from - The stanza from attribute to match.\n               *    (String) options - The handler options\n               *\n               *  Returns:\n               *    A reference to the handler that can be used to remove it.\n               */\n\n\n              addHandler(handler, ns, name, type, id, from, options) {\n                const hand = new Strophe.Handler(handler, ns, name, type, id, from, options);\n                this.addHandlers.push(hand);\n                return hand;\n              }\n              /** Function: deleteHandler\n               *  Delete a stanza handler for a connection.\n               *\n               *  This function removes a stanza handler from the connection.  The\n               *  handRef parameter is *not* the function passed to addHandler(),\n               *  but is the reference returned from addHandler().\n               *\n               *  Parameters:\n               *    (Strophe.Handler) handRef - The handler reference.\n               */\n\n\n              deleteHandler(handRef) {\n                // this must be done in the Idle loop so that we don't change\n                // the handlers during iteration\n                this.removeHandlers.push(handRef); // If a handler is being deleted while it is being added,\n                // prevent it from getting added\n\n                const i = this.addHandlers.indexOf(handRef);\n\n                if (i >= 0) {\n                  this.addHandlers.splice(i, 1);\n                }\n              }\n              /** Function: registerSASLMechanisms\n               *\n               * Register the SASL mechanisms which will be supported by this instance of\n               * Strophe.Connection (i.e. which this XMPP client will support).\n               *\n               *  Parameters:\n               *    (Array) mechanisms - Array of objects with Strophe.SASLMechanism prototypes\n               *\n               */\n\n\n              registerSASLMechanisms(mechanisms) {\n                this.mechanisms = {};\n                mechanisms = mechanisms || [Strophe.SASLAnonymous, Strophe.SASLExternal, Strophe.SASLOAuthBearer, Strophe.SASLXOAuth2, Strophe.SASLPlain, Strophe.SASLSHA1];\n                mechanisms.forEach(m => this.registerSASLMechanism(m));\n              }\n              /** Function: registerSASLMechanism\n               *\n               * Register a single SASL mechanism, to be supported by this client.\n               *\n               *  Parameters:\n               *    (Object) mechanism - Object with a Strophe.SASLMechanism prototype\n               *\n               */\n\n\n              registerSASLMechanism(Mechanism) {\n                const mechanism = new Mechanism();\n                this.mechanisms[mechanism.mechname] = mechanism;\n              }\n              /** Function: disconnect\n               *  Start the graceful disconnection process.\n               *\n               *  This function starts the disconnection process.  This process starts\n               *  by sending unavailable presence and sending BOSH body of type\n               *  terminate.  A timeout handler makes sure that disconnection happens\n               *  even if the BOSH server does not respond.\n               *  If the Connection object isn't connected, at least tries to abort all pending requests\n               *  so the connection object won't generate successful requests (which were already opened).\n               *\n               *  The user supplied connection callback will be notified of the\n               *  progress as this process happens.\n               *\n               *  Parameters:\n               *    (String) reason - The reason the disconnect is occuring.\n               */\n\n\n              disconnect(reason) {\n                this._changeConnectStatus(Strophe.Status.DISCONNECTING, reason);\n\n                if (reason) {\n                  Strophe.warn(\"Disconnect was called because: \" + reason);\n                } else {\n                  Strophe.info(\"Disconnect was called\");\n                }\n\n                if (this.connected) {\n                  let pres = false;\n                  this.disconnecting = true;\n\n                  if (this.authenticated) {\n                    pres = $pres({\n                      'xmlns': Strophe.NS.CLIENT,\n                      'type': 'unavailable'\n                    });\n                  } // setup timeout handler\n\n\n                  this._disconnectTimeout = this._addSysTimedHandler(this.disconnection_timeout, this._onDisconnectTimeout.bind(this));\n\n                  this._proto._disconnect(pres);\n                } else {\n                  Strophe.warn(\"Disconnect was called before Strophe connected to the server\");\n\n                  this._proto._abortAllRequests();\n\n                  this._doDisconnect();\n                }\n              }\n              /** PrivateFunction: _changeConnectStatus\n               *  _Private_ helper function that makes sure plugins and the user's\n               *  callback are notified of connection status changes.\n               *\n               *  Parameters:\n               *    (Integer) status - the new connection status, one of the values\n               *      in Strophe.Status\n               *    (String) condition - the error condition or null\n               *    (XMLElement) elem - The triggering stanza.\n               */\n\n\n              _changeConnectStatus(status, condition, elem) {\n                // notify all plugins listening for status changes\n                for (const k in Strophe._connectionPlugins) {\n                  if (Object.prototype.hasOwnProperty.call(Strophe._connectionPlugins, k)) {\n                    const plugin = this[k];\n\n                    if (plugin.statusChanged) {\n                      try {\n                        plugin.statusChanged(status, condition);\n                      } catch (err) {\n                        Strophe.error(`${k} plugin caused an exception changing status: ${err}`);\n                      }\n                    }\n                  }\n                } // notify the user's callback\n\n\n                if (this.connect_callback) {\n                  try {\n                    this.connect_callback(status, condition, elem);\n                  } catch (e) {\n                    Strophe._handleError(e);\n\n                    Strophe.error(`User connection callback caused an exception: ${e}`);\n                  }\n                }\n              }\n              /** PrivateFunction: _doDisconnect\n               *  _Private_ function to disconnect.\n               *\n               *  This is the last piece of the disconnection logic.  This resets the\n               *  connection and alerts the user's connection callback.\n               */\n\n\n              _doDisconnect(condition) {\n                if (typeof this._idleTimeout === \"number\") {\n                  clearTimeout(this._idleTimeout);\n                } // Cancel Disconnect Timeout\n\n\n                if (this._disconnectTimeout !== null) {\n                  this.deleteTimedHandler(this._disconnectTimeout);\n                  this._disconnectTimeout = null;\n                }\n\n                Strophe.debug(\"_doDisconnect was called\");\n\n                this._proto._doDisconnect();\n\n                this.authenticated = false;\n                this.disconnecting = false;\n                this.restored = false; // delete handlers\n\n                this.handlers = [];\n                this.timedHandlers = [];\n                this.removeTimeds = [];\n                this.removeHandlers = [];\n                this.addTimeds = [];\n                this.addHandlers = []; // tell the parent we disconnected\n\n                this._changeConnectStatus(Strophe.Status.DISCONNECTED, condition);\n\n                this.connected = false;\n              }\n              /** PrivateFunction: _dataRecv\n               *  _Private_ handler to processes incoming data from the the connection.\n               *\n               *  Except for _connect_cb handling the initial connection request,\n               *  this function handles the incoming data for all requests.  This\n               *  function also fires stanza handlers that match each incoming\n               *  stanza.\n               *\n               *  Parameters:\n               *    (Strophe.Request) req - The request that has data ready.\n               *    (string) req - The stanza a raw string (optiona).\n               */\n\n\n              _dataRecv(req, raw) {\n                const elem = this._proto._reqToData(req);\n\n                if (elem === null) {\n                  return;\n                }\n\n                if (this.xmlInput !== Strophe.Connection.prototype.xmlInput) {\n                  if (elem.nodeName === this._proto.strip && elem.childNodes.length) {\n                    this.xmlInput(elem.childNodes[0]);\n                  } else {\n                    this.xmlInput(elem);\n                  }\n                }\n\n                if (this.rawInput !== Strophe.Connection.prototype.rawInput) {\n                  if (raw) {\n                    this.rawInput(raw);\n                  } else {\n                    this.rawInput(Strophe.serialize(elem));\n                  }\n                } // remove handlers scheduled for deletion\n\n\n                while (this.removeHandlers.length > 0) {\n                  const hand = this.removeHandlers.pop();\n                  const i = this.handlers.indexOf(hand);\n\n                  if (i >= 0) {\n                    this.handlers.splice(i, 1);\n                  }\n                } // add handlers scheduled for addition\n\n\n                while (this.addHandlers.length > 0) {\n                  this.handlers.push(this.addHandlers.pop());\n                } // handle graceful disconnect\n\n\n                if (this.disconnecting && this._proto._emptyQueue()) {\n                  this._doDisconnect();\n\n                  return;\n                }\n\n                const type = elem.getAttribute(\"type\");\n\n                if (type !== null && type === \"terminate\") {\n                  // Don't process stanzas that come in after disconnect\n                  if (this.disconnecting) {\n                    return;\n                  } // an error occurred\n\n\n                  let cond = elem.getAttribute(\"condition\");\n                  const conflict = elem.getElementsByTagName(\"conflict\");\n\n                  if (cond !== null) {\n                    if (cond === \"remote-stream-error\" && conflict.length > 0) {\n                      cond = \"conflict\";\n                    }\n\n                    this._changeConnectStatus(Strophe.Status.CONNFAIL, cond);\n                  } else {\n                    this._changeConnectStatus(Strophe.Status.CONNFAIL, Strophe.ErrorCondition.UNKOWN_REASON);\n                  }\n\n                  this._doDisconnect(cond);\n\n                  return;\n                } // send each incoming stanza through the handler chain\n\n\n                Strophe.forEachChild(elem, null, child => {\n                  const matches = [];\n                  this.handlers = this.handlers.reduce((handlers, handler) => {\n                    try {\n                      if (handler.isMatch(child) && (this.authenticated || !handler.user)) {\n                        if (handler.run(child)) {\n                          handlers.push(handler);\n                        }\n\n                        matches.push(handler);\n                      } else {\n                        handlers.push(handler);\n                      }\n                    } catch (e) {\n                      // if the handler throws an exception, we consider it as false\n                      Strophe.warn('Removing Strophe handlers due to uncaught exception: ' + e.message);\n                    }\n\n                    return handlers;\n                  }, []); // If no handler was fired for an incoming IQ with type=\"set\",\n                  // then we return an IQ error stanza with service-unavailable.\n\n                  if (!matches.length && this.iqFallbackHandler.isMatch(child)) {\n                    this.iqFallbackHandler.run(child);\n                  }\n                });\n              }\n              /** PrivateFunction: _connect_cb\n               *  _Private_ handler for initial connection request.\n               *\n               *  This handler is used to process the initial connection request\n               *  response from the BOSH server. It is used to set up authentication\n               *  handlers and start the authentication process.\n               *\n               *  SASL authentication will be attempted if available, otherwise\n               *  the code will fall back to legacy authentication.\n               *\n               *  Parameters:\n               *    (Strophe.Request) req - The current request.\n               *    (Function) _callback - low level (xmpp) connect callback function.\n               *      Useful for plugins with their own xmpp connect callback (when they\n               *      want to do something special).\n               */\n\n\n              _connect_cb(req, _callback, raw) {\n                Strophe.debug(\"_connect_cb was called\");\n                this.connected = true;\n                let bodyWrap;\n\n                try {\n                  bodyWrap = this._proto._reqToData(req);\n                } catch (e) {\n                  if (e.name !== Strophe.ErrorCondition.BAD_FORMAT) {\n                    throw e;\n                  }\n\n                  this._changeConnectStatus(Strophe.Status.CONNFAIL, Strophe.ErrorCondition.BAD_FORMAT);\n\n                  this._doDisconnect(Strophe.ErrorCondition.BAD_FORMAT);\n                }\n\n                if (!bodyWrap) {\n                  return;\n                }\n\n                if (this.xmlInput !== Strophe.Connection.prototype.xmlInput) {\n                  if (bodyWrap.nodeName === this._proto.strip && bodyWrap.childNodes.length) {\n                    this.xmlInput(bodyWrap.childNodes[0]);\n                  } else {\n                    this.xmlInput(bodyWrap);\n                  }\n                }\n\n                if (this.rawInput !== Strophe.Connection.prototype.rawInput) {\n                  if (raw) {\n                    this.rawInput(raw);\n                  } else {\n                    this.rawInput(Strophe.serialize(bodyWrap));\n                  }\n                }\n\n                const conncheck = this._proto._connect_cb(bodyWrap);\n\n                if (conncheck === Strophe.Status.CONNFAIL) {\n                  return;\n                } // Check for the stream:features tag\n\n\n                let hasFeatures;\n\n                if (bodyWrap.getElementsByTagNameNS) {\n                  hasFeatures = bodyWrap.getElementsByTagNameNS(Strophe.NS.STREAM, \"features\").length > 0;\n                } else {\n                  hasFeatures = bodyWrap.getElementsByTagName(\"stream:features\").length > 0 || bodyWrap.getElementsByTagName(\"features\").length > 0;\n                }\n\n                if (!hasFeatures) {\n                  this._proto._no_auth_received(_callback);\n\n                  return;\n                }\n\n                const matched = Array.from(bodyWrap.getElementsByTagName(\"mechanism\")).map(m => this.mechanisms[m.textContent]).filter(m => m);\n\n                if (matched.length === 0) {\n                  if (bodyWrap.getElementsByTagName(\"auth\").length === 0) {\n                    // There are no matching SASL mechanisms and also no legacy\n                    // auth available.\n                    this._proto._no_auth_received(_callback);\n\n                    return;\n                  }\n                }\n\n                if (this.do_authentication !== false) {\n                  this.authenticate(matched);\n                }\n              }\n              /** Function: sortMechanismsByPriority\n               *\n               *  Sorts an array of objects with prototype SASLMechanism according to\n               *  their priorities.\n               *\n               *  Parameters:\n               *    (Array) mechanisms - Array of SASL mechanisms.\n               *\n               */\n\n\n              sortMechanismsByPriority(mechanisms) {\n                // eslint-disable-line class-methods-use-this\n                // Sorting mechanisms according to priority.\n                for (let i = 0; i < mechanisms.length - 1; ++i) {\n                  let higher = i;\n\n                  for (let j = i + 1; j < mechanisms.length; ++j) {\n                    if (mechanisms[j].priority > mechanisms[higher].priority) {\n                      higher = j;\n                    }\n                  }\n\n                  if (higher !== i) {\n                    const swap = mechanisms[i];\n                    mechanisms[i] = mechanisms[higher];\n                    mechanisms[higher] = swap;\n                  }\n                }\n\n                return mechanisms;\n              }\n              /** Function: authenticate\n               * Set up authentication\n               *\n               *  Continues the initial connection request by setting up authentication\n               *  handlers and starting the authentication process.\n               *\n               *  SASL authentication will be attempted if available, otherwise\n               *  the code will fall back to legacy authentication.\n               *\n               *  Parameters:\n               *    (Array) matched - Array of SASL mechanisms supported.\n               *\n               */\n\n\n              authenticate(matched) {\n                if (!this._attemptSASLAuth(matched)) {\n                  this._attemptLegacyAuth();\n                }\n              }\n              /** PrivateFunction: _attemptSASLAuth\n               *\n               *  Iterate through an array of SASL mechanisms and attempt authentication\n               *  with the highest priority (enabled) mechanism.\n               *\n               *  Parameters:\n               *    (Array) mechanisms - Array of SASL mechanisms.\n               *\n               *  Returns:\n               *    (Boolean) mechanism_found - true or false, depending on whether a\n               *          valid SASL mechanism was found with which authentication could be\n               *          started.\n               */\n\n\n              _attemptSASLAuth(mechanisms) {\n                mechanisms = this.sortMechanismsByPriority(mechanisms || []);\n                let mechanism_found = false;\n\n                for (let i = 0; i < mechanisms.length; ++i) {\n                  if (!mechanisms[i].test(this)) {\n                    continue;\n                  }\n\n                  this._sasl_success_handler = this._addSysHandler(this._sasl_success_cb.bind(this), null, \"success\", null, null);\n                  this._sasl_failure_handler = this._addSysHandler(this._sasl_failure_cb.bind(this), null, \"failure\", null, null);\n                  this._sasl_challenge_handler = this._addSysHandler(this._sasl_challenge_cb.bind(this), null, \"challenge\", null, null);\n                  this._sasl_mechanism = mechanisms[i];\n\n                  this._sasl_mechanism.onStart(this);\n\n                  const request_auth_exchange = $build(\"auth\", {\n                    'xmlns': Strophe.NS.SASL,\n                    'mechanism': this._sasl_mechanism.mechname\n                  });\n\n                  if (this._sasl_mechanism.isClientFirst) {\n                    const response = this._sasl_mechanism.clientChallenge(this);\n\n                    request_auth_exchange.t(abab.btoa(response));\n                  }\n\n                  this.send(request_auth_exchange.tree());\n                  mechanism_found = true;\n                  break;\n                }\n\n                return mechanism_found;\n              }\n              /** PrivateFunction: _sasl_challenge_cb\n               *  _Private_ handler for the SASL challenge\n               *\n               */\n\n\n              _sasl_challenge_cb(elem) {\n                const challenge = abab.atob(Strophe.getText(elem));\n\n                const response = this._sasl_mechanism.onChallenge(this, challenge);\n\n                const stanza = $build('response', {\n                  'xmlns': Strophe.NS.SASL\n                });\n\n                if (response !== \"\") {\n                  stanza.t(abab.btoa(response));\n                }\n\n                this.send(stanza.tree());\n                return true;\n              }\n              /** PrivateFunction: _attemptLegacyAuth\n               *\n               *  Attempt legacy (i.e. non-SASL) authentication.\n               */\n\n\n              _attemptLegacyAuth() {\n                if (Strophe.getNodeFromJid(this.jid) === null) {\n                  // we don't have a node, which is required for non-anonymous\n                  // client connections\n                  this._changeConnectStatus(Strophe.Status.CONNFAIL, Strophe.ErrorCondition.MISSING_JID_NODE);\n\n                  this.disconnect(Strophe.ErrorCondition.MISSING_JID_NODE);\n                } else {\n                  // Fall back to legacy authentication\n                  this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);\n\n                  this._addSysHandler(this._onLegacyAuthIQResult.bind(this), null, null, null, \"_auth_1\");\n\n                  this.send($iq({\n                    'type': \"get\",\n                    'to': this.domain,\n                    'id': \"_auth_1\"\n                  }).c(\"query\", {\n                    xmlns: Strophe.NS.AUTH\n                  }).c(\"username\", {}).t(Strophe.getNodeFromJid(this.jid)).tree());\n                }\n              }\n              /** PrivateFunction: _onLegacyAuthIQResult\n               *  _Private_ handler for legacy authentication.\n               *\n               *  This handler is called in response to the initial <iq type='get'/>\n               *  for legacy authentication.  It builds an authentication <iq/> and\n               *  sends it, creating a handler (calling back to _auth2_cb()) to\n               *  handle the result\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The stanza that triggered the callback.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _onLegacyAuthIQResult(elem) {\n                // eslint-disable-line no-unused-vars\n                // build plaintext auth iq\n                const iq = $iq({\n                  type: \"set\",\n                  id: \"_auth_2\"\n                }).c('query', {\n                  xmlns: Strophe.NS.AUTH\n                }).c('username', {}).t(Strophe.getNodeFromJid(this.jid)).up().c('password').t(this.pass);\n\n                if (!Strophe.getResourceFromJid(this.jid)) {\n                  // since the user has not supplied a resource, we pick\n                  // a default one here.  unlike other auth methods, the server\n                  // cannot do this for us.\n                  this.jid = Strophe.getBareJidFromJid(this.jid) + '/strophe';\n                }\n\n                iq.up().c('resource', {}).t(Strophe.getResourceFromJid(this.jid));\n\n                this._addSysHandler(this._auth2_cb.bind(this), null, null, null, \"_auth_2\");\n\n                this.send(iq.tree());\n                return false;\n              }\n              /** PrivateFunction: _sasl_success_cb\n               *  _Private_ handler for succesful SASL authentication.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The matching stanza.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _sasl_success_cb(elem) {\n                if (this._sasl_data[\"server-signature\"]) {\n                  let serverSignature;\n                  const success = abab.atob(Strophe.getText(elem));\n                  const attribMatch = /([a-z]+)=([^,]+)(,|$)/;\n                  const matches = success.match(attribMatch);\n\n                  if (matches[1] === \"v\") {\n                    serverSignature = matches[2];\n                  }\n\n                  if (serverSignature !== this._sasl_data[\"server-signature\"]) {\n                    // remove old handlers\n                    this.deleteHandler(this._sasl_failure_handler);\n                    this._sasl_failure_handler = null;\n\n                    if (this._sasl_challenge_handler) {\n                      this.deleteHandler(this._sasl_challenge_handler);\n                      this._sasl_challenge_handler = null;\n                    }\n\n                    this._sasl_data = {};\n                    return this._sasl_failure_cb(null);\n                  }\n                }\n\n                Strophe.info(\"SASL authentication succeeded.\");\n\n                if (this._sasl_mechanism) {\n                  this._sasl_mechanism.onSuccess();\n                } // remove old handlers\n\n\n                this.deleteHandler(this._sasl_failure_handler);\n                this._sasl_failure_handler = null;\n\n                if (this._sasl_challenge_handler) {\n                  this.deleteHandler(this._sasl_challenge_handler);\n                  this._sasl_challenge_handler = null;\n                }\n\n                const streamfeature_handlers = [];\n\n                const wrapper = (handlers, elem) => {\n                  while (handlers.length) {\n                    this.deleteHandler(handlers.pop());\n                  }\n\n                  this._onStreamFeaturesAfterSASL(elem);\n\n                  return false;\n                };\n\n                streamfeature_handlers.push(this._addSysHandler(elem => wrapper(streamfeature_handlers, elem), null, \"stream:features\", null, null));\n                streamfeature_handlers.push(this._addSysHandler(elem => wrapper(streamfeature_handlers, elem), Strophe.NS.STREAM, \"features\", null, null)); // we must send an xmpp:restart now\n\n                this._sendRestart();\n\n                return false;\n              }\n              /** PrivateFunction: _onStreamFeaturesAfterSASL\n               *  Parameters:\n               *    (XMLElement) elem - The matching stanza.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _onStreamFeaturesAfterSASL(elem) {\n                // save stream:features for future usage\n                this.features = elem;\n\n                for (let i = 0; i < elem.childNodes.length; i++) {\n                  const child = elem.childNodes[i];\n\n                  if (child.nodeName === 'bind') {\n                    this.do_bind = true;\n                  }\n\n                  if (child.nodeName === 'session') {\n                    this.do_session = true;\n                  }\n                }\n\n                if (!this.do_bind) {\n                  this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);\n\n                  return false;\n                } else if (!this.options.explicitResourceBinding) {\n                  this.bind();\n                } else {\n                  this._changeConnectStatus(Strophe.Status.BINDREQUIRED, null);\n                }\n\n                return false;\n              }\n              /** Function: bind\n               *\n               *  Sends an IQ to the XMPP server to bind a JID resource for this session.\n               *\n               *  https://tools.ietf.org/html/rfc6120#section-7.5\n               *\n               *  If `explicitResourceBinding` was set to a truthy value in the options\n               *  passed to the Strophe.Connection constructor, then this function needs\n               *  to be called explicitly by the client author.\n               *\n               *  Otherwise it'll be called automatically as soon as the XMPP server\n               *  advertises the \"urn:ietf:params:xml:ns:xmpp-bind\" stream feature.\n               */\n\n\n              bind() {\n                if (!this.do_bind) {\n                  Strophe.log(Strophe.LogLevel.INFO, `Strophe.Connection.prototype.bind called but \"do_bind\" is false`);\n                  return;\n                }\n\n                this._addSysHandler(this._onResourceBindResultIQ.bind(this), null, null, null, \"_bind_auth_2\");\n\n                const resource = Strophe.getResourceFromJid(this.jid);\n\n                if (resource) {\n                  this.send($iq({\n                    type: \"set\",\n                    id: \"_bind_auth_2\"\n                  }).c('bind', {\n                    xmlns: Strophe.NS.BIND\n                  }).c('resource', {}).t(resource).tree());\n                } else {\n                  this.send($iq({\n                    type: \"set\",\n                    id: \"_bind_auth_2\"\n                  }).c('bind', {\n                    xmlns: Strophe.NS.BIND\n                  }).tree());\n                }\n              }\n              /** PrivateFunction: _onResourceBindIQ\n               *  _Private_ handler for binding result and session start.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The matching stanza.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _onResourceBindResultIQ(elem) {\n                if (elem.getAttribute(\"type\") === \"error\") {\n                  Strophe.warn(\"Resource binding failed.\");\n                  const conflict = elem.getElementsByTagName(\"conflict\");\n                  let condition;\n\n                  if (conflict.length > 0) {\n                    condition = Strophe.ErrorCondition.CONFLICT;\n                  }\n\n                  this._changeConnectStatus(Strophe.Status.AUTHFAIL, condition, elem);\n\n                  return false;\n                } // TODO - need to grab errors\n\n\n                const bind = elem.getElementsByTagName(\"bind\");\n\n                if (bind.length > 0) {\n                  const jidNode = bind[0].getElementsByTagName(\"jid\");\n\n                  if (jidNode.length > 0) {\n                    this.authenticated = true;\n                    this.jid = Strophe.getText(jidNode[0]);\n\n                    if (this.do_session) {\n                      this._establishSession();\n                    } else {\n                      this._changeConnectStatus(Strophe.Status.CONNECTED, null);\n                    }\n                  }\n                } else {\n                  Strophe.warn(\"Resource binding failed.\");\n\n                  this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);\n\n                  return false;\n                }\n              }\n              /** PrivateFunction: _establishSession\n               *  Send IQ request to establish a session with the XMPP server.\n               *\n               *  See https://xmpp.org/rfcs/rfc3921.html#session\n               *\n               *  Note: The protocol for session establishment has been determined as\n               *  unnecessary and removed in RFC-6121.\n               */\n\n\n              _establishSession() {\n                if (!this.do_session) {\n                  throw new Error(`Strophe.Connection.prototype._establishSession ` + `called but apparently ${Strophe.NS.SESSION} wasn't advertised by the server`);\n                }\n\n                this._addSysHandler(this._onSessionResultIQ.bind(this), null, null, null, \"_session_auth_2\");\n\n                this.send($iq({\n                  type: \"set\",\n                  id: \"_session_auth_2\"\n                }).c('session', {\n                  xmlns: Strophe.NS.SESSION\n                }).tree());\n              }\n              /** PrivateFunction: _onSessionResultIQ\n               *  _Private_ handler for the server's IQ response to a client's session\n               *  request.\n               *\n               *  This sets Connection.authenticated to true on success, which\n               *  starts the processing of user handlers.\n               *\n               *  See https://xmpp.org/rfcs/rfc3921.html#session\n               *\n               *  Note: The protocol for session establishment has been determined as\n               *  unnecessary and removed in RFC-6121.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The matching stanza.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _onSessionResultIQ(elem) {\n                if (elem.getAttribute(\"type\") === \"result\") {\n                  this.authenticated = true;\n\n                  this._changeConnectStatus(Strophe.Status.CONNECTED, null);\n                } else if (elem.getAttribute(\"type\") === \"error\") {\n                  this.authenticated = false;\n                  Strophe.warn(\"Session creation failed.\");\n\n                  this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);\n\n                  return false;\n                }\n\n                return false;\n              }\n              /** PrivateFunction: _sasl_failure_cb\n               *  _Private_ handler for SASL authentication failure.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The matching stanza.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _sasl_failure_cb(elem) {\n                // delete unneeded handlers\n                if (this._sasl_success_handler) {\n                  this.deleteHandler(this._sasl_success_handler);\n                  this._sasl_success_handler = null;\n                }\n\n                if (this._sasl_challenge_handler) {\n                  this.deleteHandler(this._sasl_challenge_handler);\n                  this._sasl_challenge_handler = null;\n                }\n\n                if (this._sasl_mechanism) this._sasl_mechanism.onFailure();\n\n                this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);\n\n                return false;\n              }\n              /** PrivateFunction: _auth2_cb\n               *  _Private_ handler to finish legacy authentication.\n               *\n               *  This handler is called when the result from the jabber:iq:auth\n               *  <iq/> stanza is returned.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The stanza that triggered the callback.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _auth2_cb(elem) {\n                if (elem.getAttribute(\"type\") === \"result\") {\n                  this.authenticated = true;\n\n                  this._changeConnectStatus(Strophe.Status.CONNECTED, null);\n                } else if (elem.getAttribute(\"type\") === \"error\") {\n                  this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);\n\n                  this.disconnect('authentication failed');\n                }\n\n                return false;\n              }\n              /** PrivateFunction: _addSysTimedHandler\n               *  _Private_ function to add a system level timed handler.\n               *\n               *  This function is used to add a Strophe.TimedHandler for the\n               *  library code.  System timed handlers are allowed to run before\n               *  authentication is complete.\n               *\n               *  Parameters:\n               *    (Integer) period - The period of the handler.\n               *    (Function) handler - The callback function.\n               */\n\n\n              _addSysTimedHandler(period, handler) {\n                const thand = new Strophe.TimedHandler(period, handler);\n                thand.user = false;\n                this.addTimeds.push(thand);\n                return thand;\n              }\n              /** PrivateFunction: _addSysHandler\n               *  _Private_ function to add a system level stanza handler.\n               *\n               *  This function is used to add a Strophe.Handler for the\n               *  library code.  System stanza handlers are allowed to run before\n               *  authentication is complete.\n               *\n               *  Parameters:\n               *    (Function) handler - The callback function.\n               *    (String) ns - The namespace to match.\n               *    (String) name - The stanza name to match.\n               *    (String) type - The stanza type attribute to match.\n               *    (String) id - The stanza id attribute to match.\n               */\n\n\n              _addSysHandler(handler, ns, name, type, id) {\n                const hand = new Strophe.Handler(handler, ns, name, type, id);\n                hand.user = false;\n                this.addHandlers.push(hand);\n                return hand;\n              }\n              /** PrivateFunction: _onDisconnectTimeout\n               *  _Private_ timeout handler for handling non-graceful disconnection.\n               *\n               *  If the graceful disconnect process does not complete within the\n               *  time allotted, this handler finishes the disconnect anyway.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _onDisconnectTimeout() {\n                Strophe.debug(\"_onDisconnectTimeout was called\");\n\n                this._changeConnectStatus(Strophe.Status.CONNTIMEOUT, null);\n\n                this._proto._onDisconnectTimeout(); // actually disconnect\n\n\n                this._doDisconnect();\n\n                return false;\n              }\n              /** PrivateFunction: _onIdle\n               *  _Private_ handler to process events during idle cycle.\n               *\n               *  This handler is called every 100ms to fire timed handlers that\n               *  are ready and keep poll requests going.\n               */\n\n\n              _onIdle() {\n                // add timed handlers scheduled for addition\n                // NOTE: we add before remove in the case a timed handler is\n                // added and then deleted before the next _onIdle() call.\n                while (this.addTimeds.length > 0) {\n                  this.timedHandlers.push(this.addTimeds.pop());\n                } // remove timed handlers that have been scheduled for deletion\n\n\n                while (this.removeTimeds.length > 0) {\n                  const thand = this.removeTimeds.pop();\n                  const i = this.timedHandlers.indexOf(thand);\n\n                  if (i >= 0) {\n                    this.timedHandlers.splice(i, 1);\n                  }\n                } // call ready timed handlers\n\n\n                const now = new Date().getTime();\n                const newList = [];\n\n                for (let i = 0; i < this.timedHandlers.length; i++) {\n                  const thand = this.timedHandlers[i];\n\n                  if (this.authenticated || !thand.user) {\n                    const since = thand.lastCalled + thand.period;\n\n                    if (since - now <= 0) {\n                      if (thand.run()) {\n                        newList.push(thand);\n                      }\n                    } else {\n                      newList.push(thand);\n                    }\n                  }\n                }\n\n                this.timedHandlers = newList;\n                clearTimeout(this._idleTimeout);\n\n                this._proto._onIdle(); // reactivate the timer only if connected\n\n\n                if (this.connected) {\n                  this._idleTimeout = setTimeout(() => this._onIdle(), 100);\n                }\n              }\n\n            };\n            Strophe.SASLMechanism = SASLMechanism;\n            /** Constants: SASL mechanisms\n             *  Available authentication mechanisms\n             *\n             *  Strophe.SASLAnonymous   - SASL ANONYMOUS authentication.\n             *  Strophe.SASLPlain       - SASL PLAIN authentication.\n             *  Strophe.SASLSHA1        - SASL SCRAM-SHA-1 authentication\n             *  Strophe.SASLOAuthBearer - SASL OAuth Bearer authentication\n             *  Strophe.SASLExternal    - SASL EXTERNAL authentication\n             *  Strophe.SASLXOAuth2     - SASL X-OAuth2 authentication\n             */\n\n            Strophe.SASLAnonymous = SASLAnonymous;\n            Strophe.SASLPlain = SASLPlain;\n            Strophe.SASLSHA1 = SASLSHA1;\n            Strophe.SASLOAuthBearer = SASLOAuthBearer;\n            Strophe.SASLExternal = SASLExternal;\n            Strophe.SASLXOAuth2 = SASLXOAuth2;\n            var core = {\n              'Strophe': Strophe,\n              '$build': $build,\n              '$iq': $iq,\n              '$msg': $msg,\n              '$pres': $pres,\n              'SHA1': SHA1,\n              'MD5': MD5,\n              'b64_hmac_sha1': SHA1.b64_hmac_sha1,\n              'b64_sha1': SHA1.b64_sha1,\n              'str_hmac_sha1': SHA1.str_hmac_sha1,\n              'str_sha1': SHA1.str_sha1\n            };\n\n            /*\n                This program is distributed under the terms of the MIT license.\n                Please see the LICENSE file for details.\n\n                Copyright 2006-2008, OGG, LLC\n            */\n            /** PrivateClass: Strophe.Request\n             *  _Private_ helper class that provides a cross implementation abstraction\n             *  for a BOSH related XMLHttpRequest.\n             *\n             *  The Strophe.Request class is used internally to encapsulate BOSH request\n             *  information.  It is not meant to be used from user's code.\n             */\n\n            Strophe.Request = class Request {\n              /** PrivateConstructor: Strophe.Request\n               *  Create and initialize a new Strophe.Request object.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XML data to be sent in the request.\n               *    (Function) func - The function that will be called when the\n               *      XMLHttpRequest readyState changes.\n               *    (Integer) rid - The BOSH rid attribute associated with this request.\n               *    (Integer) sends - The number of times this same request has been sent.\n               */\n              constructor(elem, func, rid, sends) {\n                this.id = ++Strophe._requestId;\n                this.xmlData = elem;\n                this.data = Strophe.serialize(elem); // save original function in case we need to make a new request\n                // from this one.\n\n                this.origFunc = func;\n                this.func = func;\n                this.rid = rid;\n                this.date = NaN;\n                this.sends = sends || 0;\n                this.abort = false;\n                this.dead = null;\n\n                this.age = function () {\n                  if (!this.date) {\n                    return 0;\n                  }\n\n                  const now = new Date();\n                  return (now - this.date) / 1000;\n                };\n\n                this.timeDead = function () {\n                  if (!this.dead) {\n                    return 0;\n                  }\n\n                  const now = new Date();\n                  return (now - this.dead) / 1000;\n                };\n\n                this.xhr = this._newXHR();\n              }\n              /** PrivateFunction: getResponse\n               *  Get a response from the underlying XMLHttpRequest.\n               *\n               *  This function attempts to get a response from the request and checks\n               *  for errors.\n               *\n               *  Throws:\n               *    \"parsererror\" - A parser error occured.\n               *    \"bad-format\" - The entity has sent XML that cannot be processed.\n               *\n               *  Returns:\n               *    The DOM element tree of the response.\n               */\n\n\n              getResponse() {\n                let node = null;\n\n                if (this.xhr.responseXML && this.xhr.responseXML.documentElement) {\n                  node = this.xhr.responseXML.documentElement;\n\n                  if (node.tagName === \"parsererror\") {\n                    Strophe.error(\"invalid response received\");\n                    Strophe.error(\"responseText: \" + this.xhr.responseText);\n                    Strophe.error(\"responseXML: \" + Strophe.serialize(this.xhr.responseXML));\n                    throw new Error(\"parsererror\");\n                  }\n                } else if (this.xhr.responseText) {\n                  // In React Native, we may get responseText but no responseXML.  We can try to parse it manually.\n                  Strophe.debug(\"Got responseText but no responseXML; attempting to parse it with DOMParser...\");\n                  node = new DOMParser().parseFromString(this.xhr.responseText, 'application/xml').documentElement;\n\n                  if (!node) {\n                    throw new Error('Parsing produced null node');\n                  } else if (node.querySelector('parsererror')) {\n                    Strophe.error(\"invalid response received: \" + node.querySelector('parsererror').textContent);\n                    Strophe.error(\"responseText: \" + this.xhr.responseText);\n                    const error = new Error();\n                    error.name = Strophe.ErrorCondition.BAD_FORMAT;\n                    throw error;\n                  }\n                }\n\n                return node;\n              }\n              /** PrivateFunction: _newXHR\n               *  _Private_ helper function to create XMLHttpRequests.\n               *\n               *  This function creates XMLHttpRequests across all implementations.\n               *\n               *  Returns:\n               *    A new XMLHttpRequest.\n               */\n\n\n              _newXHR() {\n                let xhr = null;\n\n                if (window.XMLHttpRequest) {\n                  xhr = new XMLHttpRequest();\n\n                  if (xhr.overrideMimeType) {\n                    xhr.overrideMimeType(\"text/xml; charset=utf-8\");\n                  }\n                } else if (window.ActiveXObject) {\n                  xhr = new ActiveXObject(\"Microsoft.XMLHTTP\");\n                } // use Function.bind() to prepend ourselves as an argument\n\n\n                xhr.onreadystatechange = this.func.bind(null, this);\n                return xhr;\n              }\n\n            };\n            /** Class: Strophe.Bosh\n             *  _Private_ helper class that handles BOSH Connections\n             *\n             *  The Strophe.Bosh class is used internally by Strophe.Connection\n             *  to encapsulate BOSH sessions. It is not meant to be used from user's code.\n             */\n\n            /** File: bosh.js\n             *  A JavaScript library to enable BOSH in Strophejs.\n             *\n             *  this library uses Bidirectional-streams Over Synchronous HTTP (BOSH)\n             *  to emulate a persistent, stateful, two-way connection to an XMPP server.\n             *  More information on BOSH can be found in XEP 124.\n             */\n\n            /** PrivateConstructor: Strophe.Bosh\n             *  Create and initialize a Strophe.Bosh object.\n             *\n             *  Parameters:\n             *    (Strophe.Connection) connection - The Strophe.Connection that will use BOSH.\n             *\n             *  Returns:\n             *    A new Strophe.Bosh object.\n             */\n\n            Strophe.Bosh = class Bosh {\n              constructor(connection) {\n                this._conn = connection;\n                /* request id for body tags */\n\n                this.rid = Math.floor(Math.random() * 4294967295);\n                /* The current session ID. */\n\n                this.sid = null; // default BOSH values\n\n                this.hold = 1;\n                this.wait = 60;\n                this.window = 5;\n                this.errors = 0;\n                this.inactivity = null;\n                this.lastResponseHeaders = null;\n                this._requests = [];\n              }\n              /** PrivateFunction: _buildBody\n               *  _Private_ helper function to generate the <body/> wrapper for BOSH.\n               *\n               *  Returns:\n               *    A Strophe.Builder with a <body/> element.\n               */\n\n\n              _buildBody() {\n                const bodyWrap = $build('body', {\n                  'rid': this.rid++,\n                  'xmlns': Strophe.NS.HTTPBIND\n                });\n\n                if (this.sid !== null) {\n                  bodyWrap.attrs({\n                    'sid': this.sid\n                  });\n                }\n\n                if (this._conn.options.keepalive && this._conn._sessionCachingSupported()) {\n                  this._cacheSession();\n                }\n\n                return bodyWrap;\n              }\n              /** PrivateFunction: _reset\n               *  Reset the connection.\n               *\n               *  This function is called by the reset function of the Strophe Connection\n               */\n\n\n              _reset() {\n                this.rid = Math.floor(Math.random() * 4294967295);\n                this.sid = null;\n                this.errors = 0;\n\n                if (this._conn._sessionCachingSupported()) {\n                  window.sessionStorage.removeItem('strophe-bosh-session');\n                }\n\n                this._conn.nextValidRid(this.rid);\n              }\n              /** PrivateFunction: _connect\n               *  _Private_ function that initializes the BOSH connection.\n               *\n               *  Creates and sends the Request that initializes the BOSH connection.\n               */\n\n\n              _connect(wait, hold, route) {\n                this.wait = wait || this.wait;\n                this.hold = hold || this.hold;\n                this.errors = 0;\n\n                const body = this._buildBody().attrs({\n                  \"to\": this._conn.domain,\n                  \"xml:lang\": \"en\",\n                  \"wait\": this.wait,\n                  \"hold\": this.hold,\n                  \"content\": \"text/xml; charset=utf-8\",\n                  \"ver\": \"1.6\",\n                  \"xmpp:version\": \"1.0\",\n                  \"xmlns:xmpp\": Strophe.NS.BOSH\n                });\n\n                if (route) {\n                  body.attrs({\n                    'route': route\n                  });\n                }\n\n                const _connect_cb = this._conn._connect_cb;\n\n                this._requests.push(new Strophe.Request(body.tree(), this._onRequestStateChange.bind(this, _connect_cb.bind(this._conn)), body.tree().getAttribute(\"rid\")));\n\n                this._throttledRequestHandler();\n              }\n              /** PrivateFunction: _attach\n               *  Attach to an already created and authenticated BOSH session.\n               *\n               *  This function is provided to allow Strophe to attach to BOSH\n               *  sessions which have been created externally, perhaps by a Web\n               *  application.  This is often used to support auto-login type features\n               *  without putting user credentials into the page.\n               *\n               *  Parameters:\n               *    (String) jid - The full JID that is bound by the session.\n               *    (String) sid - The SID of the BOSH session.\n               *    (String) rid - The current RID of the BOSH session.  This RID\n               *      will be used by the next request.\n               *    (Function) callback The connect callback function.\n               *    (Integer) wait - The optional HTTPBIND wait value.  This is the\n               *      time the server will wait before returning an empty result for\n               *      a request.  The default setting of 60 seconds is recommended.\n               *      Other settings will require tweaks to the Strophe.TIMEOUT value.\n               *    (Integer) hold - The optional HTTPBIND hold value.  This is the\n               *      number of connections the server will hold at one time.  This\n               *      should almost always be set to 1 (the default).\n               *    (Integer) wind - The optional HTTBIND window value.  This is the\n               *      allowed range of request ids that are valid.  The default is 5.\n               */\n\n\n              _attach(jid, sid, rid, callback, wait, hold, wind) {\n                this._conn.jid = jid;\n                this.sid = sid;\n                this.rid = rid;\n                this._conn.connect_callback = callback;\n                this._conn.domain = Strophe.getDomainFromJid(this._conn.jid);\n                this._conn.authenticated = true;\n                this._conn.connected = true;\n                this.wait = wait || this.wait;\n                this.hold = hold || this.hold;\n                this.window = wind || this.window;\n\n                this._conn._changeConnectStatus(Strophe.Status.ATTACHED, null);\n              }\n              /** PrivateFunction: _restore\n               *  Attempt to restore a cached BOSH session\n               *\n               *  Parameters:\n               *    (String) jid - The full JID that is bound by the session.\n               *      This parameter is optional but recommended, specifically in cases\n               *      where prebinded BOSH sessions are used where it's important to know\n               *      that the right session is being restored.\n               *    (Function) callback The connect callback function.\n               *    (Integer) wait - The optional HTTPBIND wait value.  This is the\n               *      time the server will wait before returning an empty result for\n               *      a request.  The default setting of 60 seconds is recommended.\n               *      Other settings will require tweaks to the Strophe.TIMEOUT value.\n               *    (Integer) hold - The optional HTTPBIND hold value.  This is the\n               *      number of connections the server will hold at one time.  This\n               *      should almost always be set to 1 (the default).\n               *    (Integer) wind - The optional HTTBIND window value.  This is the\n               *      allowed range of request ids that are valid.  The default is 5.\n               */\n\n\n              _restore(jid, callback, wait, hold, wind) {\n                const session = JSON.parse(window.sessionStorage.getItem('strophe-bosh-session'));\n\n                if (typeof session !== \"undefined\" && session !== null && session.rid && session.sid && session.jid && (typeof jid === \"undefined\" || jid === null || Strophe.getBareJidFromJid(session.jid) === Strophe.getBareJidFromJid(jid) || // If authcid is null, then it's an anonymous login, so\n                // we compare only the domains:\n                Strophe.getNodeFromJid(jid) === null && Strophe.getDomainFromJid(session.jid) === jid)) {\n                  this._conn.restored = true;\n\n                  this._attach(session.jid, session.sid, session.rid, callback, wait, hold, wind);\n                } else {\n                  const error = new Error(\"_restore: no restoreable session.\");\n                  error.name = \"StropheSessionError\";\n                  throw error;\n                }\n              }\n              /** PrivateFunction: _cacheSession\n               *  _Private_ handler for the beforeunload event.\n               *\n               *  This handler is used to process the Bosh-part of the initial request.\n               *  Parameters:\n               *    (Strophe.Request) bodyWrap - The received stanza.\n               */\n\n\n              _cacheSession() {\n                if (this._conn.authenticated) {\n                  if (this._conn.jid && this.rid && this.sid) {\n                    window.sessionStorage.setItem('strophe-bosh-session', JSON.stringify({\n                      'jid': this._conn.jid,\n                      'rid': this.rid,\n                      'sid': this.sid\n                    }));\n                  }\n                } else {\n                  window.sessionStorage.removeItem('strophe-bosh-session');\n                }\n              }\n              /** PrivateFunction: _connect_cb\n               *  _Private_ handler for initial connection request.\n               *\n               *  This handler is used to process the Bosh-part of the initial request.\n               *  Parameters:\n               *    (Strophe.Request) bodyWrap - The received stanza.\n               */\n\n\n              _connect_cb(bodyWrap) {\n                const typ = bodyWrap.getAttribute(\"type\");\n\n                if (typ !== null && typ === \"terminate\") {\n                  // an error occurred\n                  let cond = bodyWrap.getAttribute(\"condition\");\n                  Strophe.error(\"BOSH-Connection failed: \" + cond);\n                  const conflict = bodyWrap.getElementsByTagName(\"conflict\");\n\n                  if (cond !== null) {\n                    if (cond === \"remote-stream-error\" && conflict.length > 0) {\n                      cond = \"conflict\";\n                    }\n\n                    this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, cond);\n                  } else {\n                    this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"unknown\");\n                  }\n\n                  this._conn._doDisconnect(cond);\n\n                  return Strophe.Status.CONNFAIL;\n                } // check to make sure we don't overwrite these if _connect_cb is\n                // called multiple times in the case of missing stream:features\n\n\n                if (!this.sid) {\n                  this.sid = bodyWrap.getAttribute(\"sid\");\n                }\n\n                const wind = bodyWrap.getAttribute('requests');\n\n                if (wind) {\n                  this.window = parseInt(wind, 10);\n                }\n\n                const hold = bodyWrap.getAttribute('hold');\n\n                if (hold) {\n                  this.hold = parseInt(hold, 10);\n                }\n\n                const wait = bodyWrap.getAttribute('wait');\n\n                if (wait) {\n                  this.wait = parseInt(wait, 10);\n                }\n\n                const inactivity = bodyWrap.getAttribute('inactivity');\n\n                if (inactivity) {\n                  this.inactivity = parseInt(inactivity, 10);\n                }\n              }\n              /** PrivateFunction: _disconnect\n               *  _Private_ part of Connection.disconnect for Bosh\n               *\n               *  Parameters:\n               *    (Request) pres - This stanza will be sent before disconnecting.\n               */\n\n\n              _disconnect(pres) {\n                this._sendTerminate(pres);\n              }\n              /** PrivateFunction: _doDisconnect\n               *  _Private_ function to disconnect.\n               *\n               *  Resets the SID and RID.\n               */\n\n\n              _doDisconnect() {\n                this.sid = null;\n                this.rid = Math.floor(Math.random() * 4294967295);\n\n                if (this._conn._sessionCachingSupported()) {\n                  window.sessionStorage.removeItem('strophe-bosh-session');\n                }\n\n                this._conn.nextValidRid(this.rid);\n              }\n              /** PrivateFunction: _emptyQueue\n               * _Private_ function to check if the Request queue is empty.\n               *\n               *  Returns:\n               *    True, if there are no Requests queued, False otherwise.\n               */\n\n\n              _emptyQueue() {\n                return this._requests.length === 0;\n              }\n              /** PrivateFunction: _callProtocolErrorHandlers\n               *  _Private_ function to call error handlers registered for HTTP errors.\n               *\n               *  Parameters:\n               *    (Strophe.Request) req - The request that is changing readyState.\n               */\n\n\n              _callProtocolErrorHandlers(req) {\n                const reqStatus = Bosh._getRequestStatus(req);\n\n                const err_callback = this._conn.protocolErrorHandlers.HTTP[reqStatus];\n\n                if (err_callback) {\n                  err_callback.call(this, reqStatus);\n                }\n              }\n              /** PrivateFunction: _hitError\n               *  _Private_ function to handle the error count.\n               *\n               *  Requests are resent automatically until their error count reaches\n               *  5.  Each time an error is encountered, this function is called to\n               *  increment the count and disconnect if the count is too high.\n               *\n               *  Parameters:\n               *    (Integer) reqStatus - The request status.\n               */\n\n\n              _hitError(reqStatus) {\n                this.errors++;\n                Strophe.warn(\"request errored, status: \" + reqStatus + \", number of errors: \" + this.errors);\n\n                if (this.errors > 4) {\n                  this._conn._onDisconnectTimeout();\n                }\n              }\n              /** PrivateFunction: _no_auth_received\n               *\n               * Called on stream start/restart when no stream:features\n               * has been received and sends a blank poll request.\n               */\n\n\n              _no_auth_received(callback) {\n                Strophe.warn(\"Server did not yet offer a supported authentication \" + \"mechanism. Sending a blank poll request.\");\n\n                if (callback) {\n                  callback = callback.bind(this._conn);\n                } else {\n                  callback = this._conn._connect_cb.bind(this._conn);\n                }\n\n                const body = this._buildBody();\n\n                this._requests.push(new Strophe.Request(body.tree(), this._onRequestStateChange.bind(this, callback), body.tree().getAttribute(\"rid\")));\n\n                this._throttledRequestHandler();\n              }\n              /** PrivateFunction: _onDisconnectTimeout\n               *  _Private_ timeout handler for handling non-graceful disconnection.\n               *\n               *  Cancels all remaining Requests and clears the queue.\n               */\n\n\n              _onDisconnectTimeout() {\n                this._abortAllRequests();\n              }\n              /** PrivateFunction: _abortAllRequests\n               *  _Private_ helper function that makes sure all pending requests are aborted.\n               */\n\n\n              _abortAllRequests() {\n                while (this._requests.length > 0) {\n                  const req = this._requests.pop();\n\n                  req.abort = true;\n                  req.xhr.abort();\n\n                  req.xhr.onreadystatechange = function () {};\n                }\n              }\n              /** PrivateFunction: _onIdle\n               *  _Private_ handler called by Strophe.Connection._onIdle\n               *\n               *  Sends all queued Requests or polls with empty Request if there are none.\n               */\n\n\n              _onIdle() {\n                const data = this._conn._data; // if no requests are in progress, poll\n\n                if (this._conn.authenticated && this._requests.length === 0 && data.length === 0 && !this._conn.disconnecting) {\n                  Strophe.debug(\"no requests during idle cycle, sending blank request\");\n                  data.push(null);\n                }\n\n                if (this._conn.paused) {\n                  return;\n                }\n\n                if (this._requests.length < 2 && data.length > 0) {\n                  const body = this._buildBody();\n\n                  for (let i = 0; i < data.length; i++) {\n                    if (data[i] !== null) {\n                      if (data[i] === \"restart\") {\n                        body.attrs({\n                          \"to\": this._conn.domain,\n                          \"xml:lang\": \"en\",\n                          \"xmpp:restart\": \"true\",\n                          \"xmlns:xmpp\": Strophe.NS.BOSH\n                        });\n                      } else {\n                        body.cnode(data[i]).up();\n                      }\n                    }\n                  }\n\n                  delete this._conn._data;\n                  this._conn._data = [];\n\n                  this._requests.push(new Strophe.Request(body.tree(), this._onRequestStateChange.bind(this, this._conn._dataRecv.bind(this._conn)), body.tree().getAttribute(\"rid\")));\n\n                  this._throttledRequestHandler();\n                }\n\n                if (this._requests.length > 0) {\n                  const time_elapsed = this._requests[0].age();\n\n                  if (this._requests[0].dead !== null) {\n                    if (this._requests[0].timeDead() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait)) {\n                      this._throttledRequestHandler();\n                    }\n                  }\n\n                  if (time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait)) {\n                    Strophe.warn(\"Request \" + this._requests[0].id + \" timed out, over \" + Math.floor(Strophe.TIMEOUT * this.wait) + \" seconds since last activity\");\n\n                    this._throttledRequestHandler();\n                  }\n                }\n              }\n              /** PrivateFunction: _getRequestStatus\n               *\n               *  Returns the HTTP status code from a Strophe.Request\n               *\n               *  Parameters:\n               *    (Strophe.Request) req - The Strophe.Request instance.\n               *    (Integer) def - The default value that should be returned if no\n               *          status value was found.\n               */\n\n\n              static _getRequestStatus(req, def) {\n                let reqStatus;\n\n                if (req.xhr.readyState === 4) {\n                  try {\n                    reqStatus = req.xhr.status;\n                  } catch (e) {\n                    // ignore errors from undefined status attribute. Works\n                    // around a browser bug\n                    Strophe.error(\"Caught an error while retrieving a request's status, \" + \"reqStatus: \" + reqStatus);\n                  }\n                }\n\n                if (typeof reqStatus === \"undefined\") {\n                  reqStatus = typeof def === 'number' ? def : 0;\n                }\n\n                return reqStatus;\n              }\n              /** PrivateFunction: _onRequestStateChange\n               *  _Private_ handler for Strophe.Request state changes.\n               *\n               *  This function is called when the XMLHttpRequest readyState changes.\n               *  It contains a lot of error handling logic for the many ways that\n               *  requests can fail, and calls the request callback when requests\n               *  succeed.\n               *\n               *  Parameters:\n               *    (Function) func - The handler for the request.\n               *    (Strophe.Request) req - The request that is changing readyState.\n               */\n\n\n              _onRequestStateChange(func, req) {\n                Strophe.debug(\"request id \" + req.id + \".\" + req.sends + \" state changed to \" + req.xhr.readyState);\n\n                if (req.abort) {\n                  req.abort = false;\n                  return;\n                }\n\n                if (req.xhr.readyState !== 4) {\n                  // The request is not yet complete\n                  return;\n                }\n\n                const reqStatus = Bosh._getRequestStatus(req);\n\n                this.lastResponseHeaders = req.xhr.getAllResponseHeaders();\n\n                if (this._conn.disconnecting && reqStatus >= 400) {\n                  this._hitError(reqStatus);\n\n                  this._callProtocolErrorHandlers(req);\n\n                  return;\n                }\n\n                const reqIs0 = this._requests[0] === req;\n                const reqIs1 = this._requests[1] === req;\n                const valid_request = reqStatus > 0 && reqStatus < 500;\n                const too_many_retries = req.sends > this._conn.maxRetries;\n\n                if (valid_request || too_many_retries) {\n                  // remove from internal queue\n                  this._removeRequest(req);\n\n                  Strophe.debug(\"request id \" + req.id + \" should now be removed\");\n                }\n\n                if (reqStatus === 200) {\n                  // request succeeded\n                  // if request 1 finished, or request 0 finished and request\n                  // 1 is over Strophe.SECONDARY_TIMEOUT seconds old, we need to\n                  // restart the other - both will be in the first spot, as the\n                  // completed request has been removed from the queue already\n                  if (reqIs1 || reqIs0 && this._requests.length > 0 && this._requests[0].age() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait)) {\n                    this._restartRequest(0);\n                  }\n\n                  this._conn.nextValidRid(Number(req.rid) + 1);\n\n                  Strophe.debug(\"request id \" + req.id + \".\" + req.sends + \" got 200\");\n                  func(req); // call handler\n\n                  this.errors = 0;\n                } else if (reqStatus === 0 || reqStatus >= 400 && reqStatus < 600 || reqStatus >= 12000) {\n                  // request failed\n                  Strophe.error(\"request id \" + req.id + \".\" + req.sends + \" error \" + reqStatus + \" happened\");\n\n                  this._hitError(reqStatus);\n\n                  this._callProtocolErrorHandlers(req);\n\n                  if (reqStatus >= 400 && reqStatus < 500) {\n                    this._conn._changeConnectStatus(Strophe.Status.DISCONNECTING, null);\n\n                    this._conn._doDisconnect();\n                  }\n                } else {\n                  Strophe.error(\"request id \" + req.id + \".\" + req.sends + \" error \" + reqStatus + \" happened\");\n                }\n\n                if (!valid_request && !too_many_retries) {\n                  this._throttledRequestHandler();\n                } else if (too_many_retries && !this._conn.connected) {\n                  this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"giving-up\");\n                }\n              }\n              /** PrivateFunction: _processRequest\n               *  _Private_ function to process a request in the queue.\n               *\n               *  This function takes requests off the queue and sends them and\n               *  restarts dead requests.\n               *\n               *  Parameters:\n               *    (Integer) i - The index of the request in the queue.\n               */\n\n\n              _processRequest(i) {\n                let req = this._requests[i];\n\n                const reqStatus = Bosh._getRequestStatus(req, -1); // make sure we limit the number of retries\n\n\n                if (req.sends > this._conn.maxRetries) {\n                  this._conn._onDisconnectTimeout();\n\n                  return;\n                }\n\n                const time_elapsed = req.age();\n                const primary_timeout = !isNaN(time_elapsed) && time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait);\n                const secondary_timeout = req.dead !== null && req.timeDead() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait);\n                const server_error = req.xhr.readyState === 4 && (reqStatus < 1 || reqStatus >= 500);\n\n                if (primary_timeout || secondary_timeout || server_error) {\n                  if (secondary_timeout) {\n                    Strophe.error(`Request ${this._requests[i].id} timed out (secondary), restarting`);\n                  }\n\n                  req.abort = true;\n                  req.xhr.abort(); // setting to null fails on IE6, so set to empty function\n\n                  req.xhr.onreadystatechange = function () {};\n\n                  this._requests[i] = new Strophe.Request(req.xmlData, req.origFunc, req.rid, req.sends);\n                  req = this._requests[i];\n                }\n\n                if (req.xhr.readyState === 0) {\n                  Strophe.debug(\"request id \" + req.id + \".\" + req.sends + \" posting\");\n\n                  try {\n                    const content_type = this._conn.options.contentType || \"text/xml; charset=utf-8\";\n                    req.xhr.open(\"POST\", this._conn.service, this._conn.options.sync ? false : true);\n\n                    if (typeof req.xhr.setRequestHeader !== 'undefined') {\n                      // IE9 doesn't have setRequestHeader\n                      req.xhr.setRequestHeader(\"Content-Type\", content_type);\n                    }\n\n                    if (this._conn.options.withCredentials) {\n                      req.xhr.withCredentials = true;\n                    }\n                  } catch (e2) {\n                    Strophe.error(\"XHR open failed: \" + e2.toString());\n\n                    if (!this._conn.connected) {\n                      this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"bad-service\");\n                    }\n\n                    this._conn.disconnect();\n\n                    return;\n                  } // Fires the XHR request -- may be invoked immediately\n                  // or on a gradually expanding retry window for reconnects\n\n\n                  const sendFunc = () => {\n                    req.date = new Date();\n\n                    if (this._conn.options.customHeaders) {\n                      const headers = this._conn.options.customHeaders;\n\n                      for (const header in headers) {\n                        if (Object.prototype.hasOwnProperty.call(headers, header)) {\n                          req.xhr.setRequestHeader(header, headers[header]);\n                        }\n                      }\n                    }\n\n                    req.xhr.send(req.data);\n                  }; // Implement progressive backoff for reconnects --\n                  // First retry (send === 1) should also be instantaneous\n\n\n                  if (req.sends > 1) {\n                    // Using a cube of the retry number creates a nicely\n                    // expanding retry window\n                    const backoff = Math.min(Math.floor(Strophe.TIMEOUT * this.wait), Math.pow(req.sends, 3)) * 1000;\n                    setTimeout(function () {\n                      // XXX: setTimeout should be called only with function expressions (23974bc1)\n                      sendFunc();\n                    }, backoff);\n                  } else {\n                    sendFunc();\n                  }\n\n                  req.sends++;\n\n                  if (this._conn.xmlOutput !== Strophe.Connection.prototype.xmlOutput) {\n                    if (req.xmlData.nodeName === this.strip && req.xmlData.childNodes.length) {\n                      this._conn.xmlOutput(req.xmlData.childNodes[0]);\n                    } else {\n                      this._conn.xmlOutput(req.xmlData);\n                    }\n                  }\n\n                  if (this._conn.rawOutput !== Strophe.Connection.prototype.rawOutput) {\n                    this._conn.rawOutput(req.data);\n                  }\n                } else {\n                  Strophe.debug(\"_processRequest: \" + (i === 0 ? \"first\" : \"second\") + \" request has readyState of \" + req.xhr.readyState);\n                }\n              }\n              /** PrivateFunction: _removeRequest\n               *  _Private_ function to remove a request from the queue.\n               *\n               *  Parameters:\n               *    (Strophe.Request) req - The request to remove.\n               */\n\n\n              _removeRequest(req) {\n                Strophe.debug(\"removing request\");\n\n                for (let i = this._requests.length - 1; i >= 0; i--) {\n                  if (req === this._requests[i]) {\n                    this._requests.splice(i, 1);\n                  }\n                } // IE6 fails on setting to null, so set to empty function\n\n\n                req.xhr.onreadystatechange = function () {};\n\n                this._throttledRequestHandler();\n              }\n              /** PrivateFunction: _restartRequest\n               *  _Private_ function to restart a request that is presumed dead.\n               *\n               *  Parameters:\n               *    (Integer) i - The index of the request in the queue.\n               */\n\n\n              _restartRequest(i) {\n                const req = this._requests[i];\n\n                if (req.dead === null) {\n                  req.dead = new Date();\n                }\n\n                this._processRequest(i);\n              }\n              /** PrivateFunction: _reqToData\n               * _Private_ function to get a stanza out of a request.\n               *\n               * Tries to extract a stanza out of a Request Object.\n               * When this fails the current connection will be disconnected.\n               *\n               *  Parameters:\n               *    (Object) req - The Request.\n               *\n               *  Returns:\n               *    The stanza that was passed.\n               */\n\n\n              _reqToData(req) {\n                try {\n                  return req.getResponse();\n                } catch (e) {\n                  if (e.message !== \"parsererror\") {\n                    throw e;\n                  }\n\n                  this._conn.disconnect(\"strophe-parsererror\");\n                }\n              }\n              /** PrivateFunction: _sendTerminate\n               *  _Private_ function to send initial disconnect sequence.\n               *\n               *  This is the first step in a graceful disconnect.  It sends\n               *  the BOSH server a terminate body and includes an unavailable\n               *  presence if authentication has completed.\n               */\n\n\n              _sendTerminate(pres) {\n                Strophe.debug(\"_sendTerminate was called\");\n\n                const body = this._buildBody().attrs({\n                  type: \"terminate\"\n                });\n\n                if (pres) {\n                  body.cnode(pres.tree());\n                }\n\n                const req = new Strophe.Request(body.tree(), this._onRequestStateChange.bind(this, this._conn._dataRecv.bind(this._conn)), body.tree().getAttribute(\"rid\"));\n\n                this._requests.push(req);\n\n                this._throttledRequestHandler();\n              }\n              /** PrivateFunction: _send\n               *  _Private_ part of the Connection.send function for BOSH\n               *\n               * Just triggers the RequestHandler to send the messages that are in the queue\n               */\n\n\n              _send() {\n                clearTimeout(this._conn._idleTimeout);\n\n                this._throttledRequestHandler();\n\n                this._conn._idleTimeout = setTimeout(() => this._conn._onIdle(), 100);\n              }\n              /** PrivateFunction: _sendRestart\n               *\n               *  Send an xmpp:restart stanza.\n               */\n\n\n              _sendRestart() {\n                this._throttledRequestHandler();\n\n                clearTimeout(this._conn._idleTimeout);\n              }\n              /** PrivateFunction: _throttledRequestHandler\n               *  _Private_ function to throttle requests to the connection window.\n               *\n               *  This function makes sure we don't send requests so fast that the\n               *  request ids overflow the connection window in the case that one\n               *  request died.\n               */\n\n\n              _throttledRequestHandler() {\n                if (!this._requests) {\n                  Strophe.debug(\"_throttledRequestHandler called with \" + \"undefined requests\");\n                } else {\n                  Strophe.debug(\"_throttledRequestHandler called with \" + this._requests.length + \" requests\");\n                }\n\n                if (!this._requests || this._requests.length === 0) {\n                  return;\n                }\n\n                if (this._requests.length > 0) {\n                  this._processRequest(0);\n                }\n\n                if (this._requests.length > 1 && Math.abs(this._requests[0].rid - this._requests[1].rid) < this.window) {\n                  this._processRequest(1);\n                }\n              }\n\n            };\n            /** Variable: strip\n             *\n             *  BOSH-Connections will have all stanzas wrapped in a <body> tag when\n             *  passed to <Strophe.Connection.xmlInput> or <Strophe.Connection.xmlOutput>.\n             *  To strip this tag, User code can set <Strophe.Bosh.strip> to \"body\":\n             *\n             *  > Strophe.Bosh.prototype.strip = \"body\";\n             *\n             *  This will enable stripping of the body tag in both\n             *  <Strophe.Connection.xmlInput> and <Strophe.Connection.xmlOutput>.\n             */\n\n            Strophe.Bosh.prototype.strip = null;\n\n            /*\n                This program is distributed under the terms of the MIT license.\n                Please see the LICENSE file for details.\n\n                Copyright 2006-2008, OGG, LLC\n            */\n            /** Class: Strophe.WebSocket\n             *  _Private_ helper class that handles WebSocket Connections\n             *\n             *  The Strophe.WebSocket class is used internally by Strophe.Connection\n             *  to encapsulate WebSocket sessions. It is not meant to be used from user's code.\n             */\n\n            /** File: websocket.js\n             *  A JavaScript library to enable XMPP over Websocket in Strophejs.\n             *\n             *  This file implements XMPP over WebSockets for Strophejs.\n             *  If a Connection is established with a Websocket url (ws://...)\n             *  Strophe will use WebSockets.\n             *  For more information on XMPP-over-WebSocket see RFC 7395:\n             *  http://tools.ietf.org/html/rfc7395\n             *\n             *  WebSocket support implemented by Andreas Guth (andreas.guth@rwth-aachen.de)\n             */\n\n            Strophe.Websocket = class Websocket {\n              /** PrivateConstructor: Strophe.Websocket\n               *  Create and initialize a Strophe.WebSocket object.\n               *  Currently only sets the connection Object.\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - The Strophe.Connection that will use WebSockets.\n               *\n               *  Returns:\n               *    A new Strophe.WebSocket object.\n               */\n              constructor(connection) {\n                this._conn = connection;\n                this.strip = \"wrapper\";\n                const service = connection.service;\n\n                if (service.indexOf(\"ws:\") !== 0 && service.indexOf(\"wss:\") !== 0) {\n                  // If the service is not an absolute URL, assume it is a path and put the absolute\n                  // URL together from options, current URL and the path.\n                  let new_service = \"\";\n\n                  if (connection.options.protocol === \"ws\" && window.location.protocol !== \"https:\") {\n                    new_service += \"ws\";\n                  } else {\n                    new_service += \"wss\";\n                  }\n\n                  new_service += \"://\" + window.location.host;\n\n                  if (service.indexOf(\"/\") !== 0) {\n                    new_service += window.location.pathname + service;\n                  } else {\n                    new_service += service;\n                  }\n\n                  connection.service = new_service;\n                }\n              }\n              /** PrivateFunction: _buildStream\n               *  _Private_ helper function to generate the <stream> start tag for WebSockets\n               *\n               *  Returns:\n               *    A Strophe.Builder with a <stream> element.\n               */\n\n\n              _buildStream() {\n                return $build(\"open\", {\n                  \"xmlns\": Strophe.NS.FRAMING,\n                  \"to\": this._conn.domain,\n                  \"version\": '1.0'\n                });\n              }\n              /** PrivateFunction: _checkStreamError\n               * _Private_ checks a message for stream:error\n               *\n               *  Parameters:\n               *    (Strophe.Request) bodyWrap - The received stanza.\n               *    connectstatus - The ConnectStatus that will be set on error.\n               *  Returns:\n               *     true if there was a streamerror, false otherwise.\n               */\n\n\n              _checkStreamError(bodyWrap, connectstatus) {\n                let errors;\n\n                if (bodyWrap.getElementsByTagNameNS) {\n                  errors = bodyWrap.getElementsByTagNameNS(Strophe.NS.STREAM, \"error\");\n                } else {\n                  errors = bodyWrap.getElementsByTagName(\"stream:error\");\n                }\n\n                if (errors.length === 0) {\n                  return false;\n                }\n\n                const error = errors[0];\n                let condition = \"\";\n                let text = \"\";\n                const ns = \"urn:ietf:params:xml:ns:xmpp-streams\";\n\n                for (let i = 0; i < error.childNodes.length; i++) {\n                  const e = error.childNodes[i];\n\n                  if (e.getAttribute(\"xmlns\") !== ns) {\n                    break;\n                  }\n\n                  if (e.nodeName === \"text\") {\n                    text = e.textContent;\n                  } else {\n                    condition = e.nodeName;\n                  }\n                }\n\n                let errorString = \"WebSocket stream error: \";\n\n                if (condition) {\n                  errorString += condition;\n                } else {\n                  errorString += \"unknown\";\n                }\n\n                if (text) {\n                  errorString += \" - \" + text;\n                }\n\n                Strophe.error(errorString); // close the connection on stream_error\n\n                this._conn._changeConnectStatus(connectstatus, condition);\n\n                this._conn._doDisconnect();\n\n                return true;\n              }\n              /** PrivateFunction: _reset\n               *  Reset the connection.\n               *\n               *  This function is called by the reset function of the Strophe Connection.\n               *  Is not needed by WebSockets.\n               */\n\n\n              _reset() {\n                // eslint-disable-line class-methods-use-this\n                return;\n              }\n              /** PrivateFunction: _connect\n               *  _Private_ function called by Strophe.Connection.connect\n               *\n               *  Creates a WebSocket for a connection and assigns Callbacks to it.\n               *  Does nothing if there already is a WebSocket.\n               */\n\n\n              _connect() {\n                // Ensure that there is no open WebSocket from a previous Connection.\n                this._closeSocket();\n\n                this.socket = new WebSocket(this._conn.service, \"xmpp\");\n\n                this.socket.onopen = () => this._onOpen();\n\n                this.socket.onerror = e => this._onError(e);\n\n                this.socket.onclose = e => this._onClose(e); // Gets replaced with this._onMessage once _onInitialMessage is called\n\n\n                this.socket.onmessage = message => this._onInitialMessage(message);\n              }\n              /** PrivateFunction: _connect_cb\n               *  _Private_ function called by Strophe.Connection._connect_cb\n               *\n               * checks for stream:error\n               *\n               *  Parameters:\n               *    (Strophe.Request) bodyWrap - The received stanza.\n               */\n\n\n              _connect_cb(bodyWrap) {\n                const error = this._checkStreamError(bodyWrap, Strophe.Status.CONNFAIL);\n\n                if (error) {\n                  return Strophe.Status.CONNFAIL;\n                }\n              }\n              /** PrivateFunction: _handleStreamStart\n               * _Private_ function that checks the opening <open /> tag for errors.\n               *\n               * Disconnects if there is an error and returns false, true otherwise.\n               *\n               *  Parameters:\n               *    (Node) message - Stanza containing the <open /> tag.\n               */\n\n\n              _handleStreamStart(message) {\n                let error = false; // Check for errors in the <open /> tag\n\n                const ns = message.getAttribute(\"xmlns\");\n\n                if (typeof ns !== \"string\") {\n                  error = \"Missing xmlns in <open />\";\n                } else if (ns !== Strophe.NS.FRAMING) {\n                  error = \"Wrong xmlns in <open />: \" + ns;\n                }\n\n                const ver = message.getAttribute(\"version\");\n\n                if (typeof ver !== \"string\") {\n                  error = \"Missing version in <open />\";\n                } else if (ver !== \"1.0\") {\n                  error = \"Wrong version in <open />: \" + ver;\n                }\n\n                if (error) {\n                  this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, error);\n\n                  this._conn._doDisconnect();\n\n                  return false;\n                }\n\n                return true;\n              }\n              /** PrivateFunction: _onInitialMessage\n               * _Private_ function that handles the first connection messages.\n               *\n               * On receiving an opening stream tag this callback replaces itself with the real\n               * message handler. On receiving a stream error the connection is terminated.\n               */\n\n\n              _onInitialMessage(message) {\n                if (message.data.indexOf(\"<open \") === 0 || message.data.indexOf(\"<?xml\") === 0) {\n                  // Strip the XML Declaration, if there is one\n                  const data = message.data.replace(/^(<\\?.*?\\?>\\s*)*/, \"\");\n                  if (data === '') return;\n                  const streamStart = new DOMParser().parseFromString(data, \"text/xml\").documentElement;\n\n                  this._conn.xmlInput(streamStart);\n\n                  this._conn.rawInput(message.data); //_handleStreamSteart will check for XML errors and disconnect on error\n\n\n                  if (this._handleStreamStart(streamStart)) {\n                    //_connect_cb will check for stream:error and disconnect on error\n                    this._connect_cb(streamStart);\n                  }\n                } else if (message.data.indexOf(\"<close \") === 0) {\n                  // <close xmlns=\"urn:ietf:params:xml:ns:xmpp-framing />\n                  // Parse the raw string to an XML element\n                  const parsedMessage = new DOMParser().parseFromString(message.data, \"text/xml\").documentElement; // Report this input to the raw and xml handlers\n\n                  this._conn.xmlInput(parsedMessage);\n\n                  this._conn.rawInput(message.data);\n\n                  const see_uri = parsedMessage.getAttribute(\"see-other-uri\");\n\n                  if (see_uri) {\n                    const service = this._conn.service; // Valid scenarios: WSS->WSS, WS->ANY\n\n                    const isSecureRedirect = service.indexOf(\"wss:\") >= 0 && see_uri.indexOf(\"wss:\") >= 0 || service.indexOf(\"ws:\") >= 0;\n\n                    if (isSecureRedirect) {\n                      this._conn._changeConnectStatus(Strophe.Status.REDIRECT, \"Received see-other-uri, resetting connection\");\n\n                      this._conn.reset();\n\n                      this._conn.service = see_uri;\n\n                      this._connect();\n                    }\n                  } else {\n                    this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"Received closing stream\");\n\n                    this._conn._doDisconnect();\n                  }\n                } else {\n                  this._replaceMessageHandler();\n\n                  const string = this._streamWrap(message.data);\n\n                  const elem = new DOMParser().parseFromString(string, \"text/xml\").documentElement;\n\n                  this._conn._connect_cb(elem, null, message.data);\n                }\n              }\n              /** PrivateFunction: _replaceMessageHandler\n               *\n               * Called by _onInitialMessage in order to replace itself with the general message handler.\n               * This method is overridden by Strophe.WorkerWebsocket, which manages a\n               * websocket connection via a service worker and doesn't have direct access\n               * to the socket.\n               */\n\n\n              _replaceMessageHandler() {\n                this.socket.onmessage = m => this._onMessage(m);\n              }\n              /** PrivateFunction: _disconnect\n               *  _Private_ function called by Strophe.Connection.disconnect\n               *\n               *  Disconnects and sends a last stanza if one is given\n               *\n               *  Parameters:\n               *    (Request) pres - This stanza will be sent before disconnecting.\n               */\n\n\n              _disconnect(pres) {\n                if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {\n                  if (pres) {\n                    this._conn.send(pres);\n                  }\n\n                  const close = $build(\"close\", {\n                    \"xmlns\": Strophe.NS.FRAMING\n                  });\n\n                  this._conn.xmlOutput(close.tree());\n\n                  const closeString = Strophe.serialize(close);\n\n                  this._conn.rawOutput(closeString);\n\n                  try {\n                    this.socket.send(closeString);\n                  } catch (e) {\n                    Strophe.warn(\"Couldn't send <close /> tag.\");\n                  }\n                }\n\n                setTimeout(() => this._conn._doDisconnect(), 0);\n              }\n              /** PrivateFunction: _doDisconnect\n               *  _Private_ function to disconnect.\n               *\n               *  Just closes the Socket for WebSockets\n               */\n\n\n              _doDisconnect() {\n                Strophe.debug(\"WebSockets _doDisconnect was called\");\n\n                this._closeSocket();\n              }\n              /** PrivateFunction _streamWrap\n               *  _Private_ helper function to wrap a stanza in a <stream> tag.\n               *  This is used so Strophe can process stanzas from WebSockets like BOSH\n               */\n\n\n              _streamWrap(stanza) {\n                // eslint-disable-line class-methods-use-this\n                return \"<wrapper>\" + stanza + '</wrapper>';\n              }\n              /** PrivateFunction: _closeSocket\n               *  _Private_ function to close the WebSocket.\n               *\n               *  Closes the socket if it is still open and deletes it\n               */\n\n\n              _closeSocket() {\n                if (this.socket) {\n                  try {\n                    this.socket.onclose = null;\n                    this.socket.onerror = null;\n                    this.socket.onmessage = null;\n                    this.socket.close();\n                  } catch (e) {\n                    Strophe.debug(e.message);\n                  }\n                }\n\n                this.socket = null;\n              }\n              /** PrivateFunction: _emptyQueue\n               * _Private_ function to check if the message queue is empty.\n               *\n               *  Returns:\n               *    True, because WebSocket messages are send immediately after queueing.\n               */\n\n\n              _emptyQueue() {\n                // eslint-disable-line class-methods-use-this\n                return true;\n              }\n              /** PrivateFunction: _onClose\n               * _Private_ function to handle websockets closing.\n               */\n\n\n              _onClose(e) {\n                if (this._conn.connected && !this._conn.disconnecting) {\n                  Strophe.error(\"Websocket closed unexpectedly\");\n\n                  this._conn._doDisconnect();\n                } else if (e && e.code === 1006 && !this._conn.connected && this.socket) {\n                  // in case the onError callback was not called (Safari 10 does not\n                  // call onerror when the initial connection fails) we need to\n                  // dispatch a CONNFAIL status update to be consistent with the\n                  // behavior on other browsers.\n                  Strophe.error(\"Websocket closed unexcectedly\");\n\n                  this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"The WebSocket connection could not be established or was disconnected.\");\n\n                  this._conn._doDisconnect();\n                } else {\n                  Strophe.debug(\"Websocket closed\");\n                }\n              }\n              /** PrivateFunction: _no_auth_received\n               *\n               * Called on stream start/restart when no stream:features\n               * has been received.\n               */\n\n\n              _no_auth_received(callback) {\n                Strophe.error(\"Server did not offer a supported authentication mechanism\");\n\n                this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, Strophe.ErrorCondition.NO_AUTH_MECH);\n\n                if (callback) {\n                  callback.call(this._conn);\n                }\n\n                this._conn._doDisconnect();\n              }\n              /** PrivateFunction: _onDisconnectTimeout\n               *  _Private_ timeout handler for handling non-graceful disconnection.\n               *\n               *  This does nothing for WebSockets\n               */\n\n\n              _onDisconnectTimeout() {} // eslint-disable-line class-methods-use-this\n\n              /** PrivateFunction: _abortAllRequests\n               *  _Private_ helper function that makes sure all pending requests are aborted.\n               */\n\n\n              _abortAllRequests() {} // eslint-disable-line class-methods-use-this\n\n              /** PrivateFunction: _onError\n               * _Private_ function to handle websockets errors.\n               *\n               * Parameters:\n               * (Object) error - The websocket error.\n               */\n\n\n              _onError(error) {\n                Strophe.error(\"Websocket error \" + JSON.stringify(error));\n\n                this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"The WebSocket connection could not be established or was disconnected.\");\n\n                this._disconnect();\n              }\n              /** PrivateFunction: _onIdle\n               *  _Private_ function called by Strophe.Connection._onIdle\n               *\n               *  sends all queued stanzas\n               */\n\n\n              _onIdle() {\n                const data = this._conn._data;\n\n                if (data.length > 0 && !this._conn.paused) {\n                  for (let i = 0; i < data.length; i++) {\n                    if (data[i] !== null) {\n                      let stanza;\n\n                      if (data[i] === \"restart\") {\n                        stanza = this._buildStream().tree();\n                      } else {\n                        stanza = data[i];\n                      }\n\n                      const rawStanza = Strophe.serialize(stanza);\n\n                      this._conn.xmlOutput(stanza);\n\n                      this._conn.rawOutput(rawStanza);\n\n                      this.socket.send(rawStanza);\n                    }\n                  }\n\n                  this._conn._data = [];\n                }\n              }\n              /** PrivateFunction: _onMessage\n               * _Private_ function to handle websockets messages.\n               *\n               * This function parses each of the messages as if they are full documents.\n               * [TODO : We may actually want to use a SAX Push parser].\n               *\n               * Since all XMPP traffic starts with\n               *  <stream:stream version='1.0'\n               *                 xml:lang='en'\n               *                 xmlns='jabber:client'\n               *                 xmlns:stream='http://etherx.jabber.org/streams'\n               *                 id='3697395463'\n               *                 from='SERVER'>\n               *\n               * The first stanza will always fail to be parsed.\n               *\n               * Additionally, the seconds stanza will always be <stream:features> with\n               * the stream NS defined in the previous stanza, so we need to 'force'\n               * the inclusion of the NS in this stanza.\n               *\n               * Parameters:\n               * (string) message - The websocket message.\n               */\n\n\n              _onMessage(message) {\n                let elem; // check for closing stream\n\n                const close = '<close xmlns=\"urn:ietf:params:xml:ns:xmpp-framing\" />';\n\n                if (message.data === close) {\n                  this._conn.rawInput(close);\n\n                  this._conn.xmlInput(message);\n\n                  if (!this._conn.disconnecting) {\n                    this._conn._doDisconnect();\n                  }\n\n                  return;\n                } else if (message.data.search(\"<open \") === 0) {\n                  // This handles stream restarts\n                  elem = new DOMParser().parseFromString(message.data, \"text/xml\").documentElement;\n\n                  if (!this._handleStreamStart(elem)) {\n                    return;\n                  }\n                } else {\n                  const data = this._streamWrap(message.data);\n\n                  elem = new DOMParser().parseFromString(data, \"text/xml\").documentElement;\n                }\n\n                if (this._checkStreamError(elem, Strophe.Status.ERROR)) {\n                  return;\n                } //handle unavailable presence stanza before disconnecting\n\n\n                if (this._conn.disconnecting && elem.firstChild.nodeName === \"presence\" && elem.firstChild.getAttribute(\"type\") === \"unavailable\") {\n                  this._conn.xmlInput(elem);\n\n                  this._conn.rawInput(Strophe.serialize(elem)); // if we are already disconnecting we will ignore the unavailable stanza and\n                  // wait for the </stream:stream> tag before we close the connection\n\n\n                  return;\n                }\n\n                this._conn._dataRecv(elem, message.data);\n              }\n              /** PrivateFunction: _onOpen\n               * _Private_ function to handle websockets connection setup.\n               *\n               * The opening stream tag is sent here.\n               */\n\n\n              _onOpen() {\n                Strophe.debug(\"Websocket open\");\n\n                const start = this._buildStream();\n\n                this._conn.xmlOutput(start.tree());\n\n                const startString = Strophe.serialize(start);\n\n                this._conn.rawOutput(startString);\n\n                this.socket.send(startString);\n              }\n              /** PrivateFunction: _reqToData\n               * _Private_ function to get a stanza out of a request.\n               *\n               * WebSockets don't use requests, so the passed argument is just returned.\n               *\n               *  Parameters:\n               *    (Object) stanza - The stanza.\n               *\n               *  Returns:\n               *    The stanza that was passed.\n               */\n\n\n              _reqToData(stanza) {\n                // eslint-disable-line class-methods-use-this\n                return stanza;\n              }\n              /** PrivateFunction: _send\n               *  _Private_ part of the Connection.send function for WebSocket\n               *\n               * Just flushes the messages that are in the queue\n               */\n\n\n              _send() {\n                this._conn.flush();\n              }\n              /** PrivateFunction: _sendRestart\n               *\n               *  Send an xmpp:restart stanza.\n               */\n\n\n              _sendRestart() {\n                clearTimeout(this._conn._idleTimeout);\n\n                this._conn._onIdle.bind(this._conn)();\n              }\n\n            };\n\n            /*\n                This program is distributed under the terms of the MIT license.\n                Please see the LICENSE file for details.\n\n                Copyright 2020, JC Brand\n            */\n            const lmap = {};\n            lmap['debug'] = Strophe.LogLevel.DEBUG;\n            lmap['info'] = Strophe.LogLevel.INFO;\n            lmap['warn'] = Strophe.LogLevel.WARN;\n            lmap['error'] = Strophe.LogLevel.ERROR;\n            lmap['fatal'] = Strophe.LogLevel.FATAL;\n            /** Class: Strophe.WorkerWebsocket\n             *  _Private_ helper class that handles a websocket connection inside a shared worker.\n             */\n\n            Strophe.WorkerWebsocket = class WorkerWebsocket extends Strophe.Websocket {\n              /** PrivateConstructor: Strophe.WorkerWebsocket\n               *  Create and initialize a Strophe.WorkerWebsocket object.\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - The Strophe.Connection\n               *\n               *  Returns:\n               *    A new Strophe.WorkerWebsocket object.\n               */\n              constructor(connection) {\n                super(connection);\n                this._conn = connection;\n                this.worker = new SharedWorker(this._conn.options.worker, 'Strophe XMPP Connection');\n\n                this.worker.onerror = e => {\n                  var _console;\n\n                  (_console = console) === null || _console === void 0 ? void 0 : _console.error(e);\n                  Strophe.log(Strophe.LogLevel.ERROR, `Shared Worker Error: ${e}`);\n                };\n              }\n\n              get socket() {\n                return {\n                  'send': str => this.worker.port.postMessage(['send', str])\n                };\n              }\n\n              _connect() {\n                this._messageHandler = m => this._onInitialMessage(m);\n\n                this.worker.port.start();\n\n                this.worker.port.onmessage = ev => this._onWorkerMessage(ev);\n\n                this.worker.port.postMessage(['_connect', this._conn.service, this._conn.jid]);\n              }\n\n              _attach(callback) {\n                this._messageHandler = m => this._onMessage(m);\n\n                this._conn.connect_callback = callback;\n                this.worker.port.start();\n\n                this.worker.port.onmessage = ev => this._onWorkerMessage(ev);\n\n                this.worker.port.postMessage(['_attach', this._conn.service]);\n              }\n\n              _attachCallback(status, jid) {\n                if (status === Strophe.Status.ATTACHED) {\n                  this._conn.jid = jid;\n                  this._conn.authenticated = true;\n                  this._conn.connected = true;\n                  this._conn.restored = true;\n\n                  this._conn._changeConnectStatus(Strophe.Status.ATTACHED);\n                } else if (status === Strophe.Status.ATTACHFAIL) {\n                  this._conn.authenticated = false;\n                  this._conn.connected = false;\n                  this._conn.restored = false;\n\n                  this._conn._changeConnectStatus(Strophe.Status.ATTACHFAIL);\n                }\n              }\n\n              _disconnect(readyState, pres) {\n                pres && this._conn.send(pres);\n                const close = $build(\"close\", {\n                  \"xmlns\": Strophe.NS.FRAMING\n                });\n\n                this._conn.xmlOutput(close.tree());\n\n                const closeString = Strophe.serialize(close);\n\n                this._conn.rawOutput(closeString);\n\n                this.worker.port.postMessage(['send', closeString]);\n\n                this._conn._doDisconnect();\n              }\n\n              _onClose(e) {\n                if (this._conn.connected && !this._conn.disconnecting) {\n                  Strophe.error(\"Websocket closed unexpectedly\");\n\n                  this._conn._doDisconnect();\n                } else if (e && e.code === 1006 && !this._conn.connected) {\n                  // in case the onError callback was not called (Safari 10 does not\n                  // call onerror when the initial connection fails) we need to\n                  // dispatch a CONNFAIL status update to be consistent with the\n                  // behavior on other browsers.\n                  Strophe.error(\"Websocket closed unexcectedly\");\n\n                  this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"The WebSocket connection could not be established or was disconnected.\");\n\n                  this._conn._doDisconnect();\n                } else {\n                  Strophe.debug(\"Websocket closed\");\n                }\n              }\n\n              _closeSocket() {\n                this.worker.port.postMessage(['_closeSocket']);\n              }\n              /** PrivateFunction: _replaceMessageHandler\n               *\n               * Called by _onInitialMessage in order to replace itself with the general message handler.\n               * This method is overridden by Strophe.WorkerWebsocket, which manages a\n               * websocket connection via a service worker and doesn't have direct access\n               * to the socket.\n               */\n\n\n              _replaceMessageHandler() {\n                this._messageHandler = m => this._onMessage(m);\n              }\n              /** PrivateFunction: _onWorkerMessage\n               * _Private_ function that handles messages received from the service worker\n               */\n\n\n              _onWorkerMessage(ev) {\n                const {\n                  data\n                } = ev;\n                const method_name = data[0];\n\n                if (method_name === '_onMessage') {\n                  this._messageHandler(data[1]);\n                } else if (method_name in this) {\n                  try {\n                    this[method_name].apply(this, ev.data.slice(1));\n                  } catch (e) {\n                    Strophe.log(Strophe.LogLevel.ERROR, e);\n                  }\n                } else if (method_name === 'log') {\n                  const level = data[1];\n                  const msg = data[2];\n                  Strophe.log(lmap[level], msg);\n                } else {\n                  Strophe.log(Strophe.LogLevel.ERROR, `Found unhandled service worker message: ${data}`);\n                }\n              }\n\n            };\n\n            global$1.$build = core.$build;\n            global$1.$iq = core.$iq;\n            global$1.$msg = core.$msg;\n            global$1.$pres = core.$pres;\n            global$1.Strophe = core.Strophe;\n            const {\n              b64_sha1\n            } = SHA1;\n\n            exports.$build = $build;\n            exports.$iq = $iq;\n            exports.$msg = $msg;\n            exports.$pres = $pres;\n            exports.Strophe = Strophe;\n            exports.b64_sha1 = b64_sha1;\n\n            Object.defineProperty(exports, '__esModule', { value: true });\n\n}));\n","import { $iq, Strophe } from 'strophe.js';\n\nStrophe.addConnectionPlugin('disco',\n{\n    _connection: null,\n    _identities : [],\n    _features : [],\n    _items : [],\n    /** Function: init\n     * Plugin init\n     *\n     * Parameters:\n     *   (Strophe.Connection) conn - Strophe connection\n     */\n    init: function(conn)\n    {\n    this._connection = conn;\n        this._identities = [];\n        this._features   = [];\n        this._items      = [];\n        // disco info\n        conn.addHandler(this._onDiscoInfo.bind(this), Strophe.NS.DISCO_INFO, 'iq', 'get', null, null);\n        // disco items\n        conn.addHandler(this._onDiscoItems.bind(this), Strophe.NS.DISCO_ITEMS, 'iq', 'get', null, null);\n    },\n    /** Function: addIdentity\n     * See http://xmpp.org/registrar/disco-categories.html\n     * Parameters:\n     *   (String) category - category of identity (like client, automation, etc ...)\n     *   (String) type - type of identity (like pc, web, bot , etc ...)\n     *   (String) name - name of identity in natural language\n     *   (String) lang - lang of name parameter\n     *\n     * Returns:\n     *   Boolean\n     */\n    addIdentity: function(category, type, name, lang)\n    {\n        for (var i=0; i<this._identities.length; i++)\n        {\n            if (this._identities[i].category == category &&\n                this._identities[i].type == type &&\n                this._identities[i].name == name &&\n                this._identities[i].lang == lang)\n            {\n                return false;\n            }\n        }\n        this._identities.push({category: category, type: type, name: name, lang: lang});\n        return true;\n    },\n    /** Function: addFeature\n     *\n     * Parameters:\n     *   (String) var_name - feature name (like jabber:iq:version)\n     *\n     * Returns:\n     *   boolean\n     */\n    addFeature: function(var_name)\n    {\n        for (var i=0; i<this._features.length; i++)\n        {\n             if (this._features[i] == var_name)\n                 return false;\n        }\n        this._features.push(var_name);\n        return true;\n    },\n    /** Function: removeFeature\n     *\n     * Parameters:\n     *   (String) var_name - feature name (like jabber:iq:version)\n     *\n     * Returns:\n     *   boolean\n     */\n    removeFeature: function(var_name)\n    {\n        for (var i=0; i<this._features.length; i++)\n        {\n             if (this._features[i] === var_name){\n                 this._features.splice(i,1);\n                 return true;\n             }\n        }\n        return false;\n    },\n    /** Function: addItem\n     *\n     * Parameters:\n     *   (String) jid\n     *   (String) name\n     *   (String) node\n     *   (Function) call_back\n     *\n     * Returns:\n     *   boolean\n     */\n    addItem: function(jid, name, node, call_back)\n    {\n        if (node && !call_back)\n            return false;\n        this._items.push({jid: jid, name: name, node: node, call_back: call_back});\n        return true;\n    },\n    /** Function: info\n     * Info query\n     *\n     * Parameters:\n     *   (Function) call_back\n     *   (String) jid\n     *   (String) node\n     */\n    info: function(jid, node, success, error, timeout)\n    {\n        var attrs = {xmlns: Strophe.NS.DISCO_INFO};\n        if (node)\n            attrs.node = node;\n\n        var info = $iq({from:this._connection.jid,\n                         to:jid, type:'get'}).c('query', attrs);\n        this._connection.sendIQ(info, success, error, timeout);\n    },\n    /** Function: items\n     * Items query\n     *\n     * Parameters:\n     *   (Function) call_back\n     *   (String) jid\n     *   (String) node\n     */\n    items: function(jid, node, success, error, timeout)\n    {\n        var attrs = {xmlns: Strophe.NS.DISCO_ITEMS};\n        if (node)\n            attrs.node = node;\n\n        var items = $iq({from:this._connection.jid,\n                         to:jid, type:'get'}).c('query', attrs);\n        this._connection.sendIQ(items, success, error, timeout);\n    },\n\n    /** PrivateFunction: _buildIQResult\n     */\n    _buildIQResult: function(stanza, query_attrs)\n    {\n        var id   =  stanza.getAttribute('id');\n        var from = stanza.getAttribute('from');\n        var iqresult = $iq({type: 'result', id: id});\n\n        if (from !== null) {\n            iqresult.attrs({to: from});\n        }\n\n        return iqresult.c('query', query_attrs);\n    },\n\n    /** PrivateFunction: _onDiscoInfo\n     * Called when receive info request\n     */\n    _onDiscoInfo: function(stanza)\n    {\n        var node = stanza.getElementsByTagName('query')[0].getAttribute('node');\n        var attrs = {xmlns: Strophe.NS.DISCO_INFO};\n        var i;\n        if (node)\n        {\n            attrs.node = node;\n        }\n        var iqresult = this._buildIQResult(stanza, attrs);\n        for (i=0; i<this._identities.length; i++)\n        {\n            attrs = {category: this._identities[i].category,\n                         type    : this._identities[i].type};\n            if (this._identities[i].name)\n                attrs.name = this._identities[i].name;\n            if (this._identities[i].lang)\n                attrs['xml:lang'] = this._identities[i].lang;\n            iqresult.c('identity', attrs).up();\n        }\n        for (i=0; i<this._features.length; i++)\n        {\n            iqresult.c('feature', {'var':this._features[i]}).up();\n        }\n        this._connection.send(iqresult.tree());\n        return true;\n    },\n    /** PrivateFunction: _onDiscoItems\n     * Called when receive items request\n     */\n    _onDiscoItems: function(stanza)\n    {\n        var query_attrs = {xmlns: Strophe.NS.DISCO_ITEMS};\n        var node = stanza.getElementsByTagName('query')[0].getAttribute('node');\n        var items, i;\n        if (node)\n        {\n            query_attrs.node = node;\n            items = [];\n            for (i = 0; i < this._items.length; i++)\n            {\n                if (this._items[i].node == node)\n                {\n                    items = this._items[i].call_back(stanza);\n                    break;\n                }\n            }\n        }\n        else\n        {\n            items = this._items;\n        }\n        var iqresult = this._buildIQResult(stanza, query_attrs);\n        for (i = 0; i < items.length; i++)\n        {\n            var attrs = {jid:  items[i].jid};\n            if (items[i].name)\n                attrs.name = items[i].name;\n            if (items[i].node)\n                attrs.node = items[i].node;\n            iqresult.c('item', attrs).up();\n        }\n        this._connection.send(iqresult.tree());\n        return true;\n    }\n});\n","import { $build, Strophe } from 'strophe.js';\n\n/**\n* StropheJS - Stream Management XEP-0198\n*\n* This plugin implements stream management ACK capabilities of the specs XEP-0198.\n* Note: Resumption is not supported in this current implementation.\n*\n* Reference: http://xmpp.org/extensions/xep-0198.html\n*\n* @class streamManagement\n*/\nStrophe.addConnectionPlugin('streamManagement', {\n\n\t/**\n\t* @property {Boolean} logging: Set to true to enable logging regarding out of sync stanzas.\n\t*/\n\tlogging: false,\n\n\t/**\n\t* @property {Boolean} autoSendCountOnEveryIncomingStanza: Set to true to send an 'a' response after every stanza.\n\t* @default false\n\t* @public\n\t*/\n\tautoSendCountOnEveryIncomingStanza: false,\n\n\t/**\n\t* @property {Integer} requestResponseInterval: Set this value to send a request for counter on very interval\n\t* number of stanzas sent. Set to 0 to disable.\n\t* @default 5\n\t* @public\n\t*/\n\trequestResponseInterval: 5,\n\n\t/**\n\t* @property {Pointer} _c: Strophe connection instance.\n\t* @private\n\t*/\n\t_c: null,\n\n\t/**\n\t* @property {String} _NS XMPP Namespace.\n\t* @private\n\t*/\n\t_NS: 'urn:xmpp:sm:3',\n\n\t/**\n\t* @property {Boolean} _isStreamManagementEnabled\n\t* @private\n\t*/\n\t_isStreamManagementEnabled: false,\n\n\t/**\n\t* @property {Integer} _serverProcesssedStanzasCounter: Keeps count of stanzas confirmed processed by the server.\n\t* The server is the source of truth of this value. It is the 'h' attribute on the latest 'a' element received\n\t* from the server.\n\t* @private\n\t*/\n\t_serverProcesssedStanzasCounter: null,\n\n\t/**\n\t* @property {Integer} _clientProcessedStanzasCounter: Counter of stanzas received by the client from the server.\n\t* Client is the source of truth of this value. It is the 'h' attribute in the 'a' sent from the client to\n\t* the server.\n\t* @private\n\t*/\n\t_clientProcessedStanzasCounter: null,\n\n\t/**\n\t* @property {Integer} _clientSentStanzasCounter\n\t* @private\n\t*/\n\t_clientSentStanzasCounter: null,\n\n\t/**\n\t* Stores a reference to Strophe connection xmlOutput function to wrap counting functionality.\n\t* @method _originalXMLOutput\n\t* @type {Handler}\n\t* @private\n\t*/\n\t_originalXMLOutput: null,\n\n\t/**\n\t* @property {Handler} _requestHandler: Stores reference to handler that process count request from server.\n\t* @private\n\t*/\n\t_requestHandler: null,\n\n\t/**\n\t* @property {Handler} _incomingHandler: Stores reference to handler that processes incoming stanzas count.\n\t* @private\n\t*/\n\t_incomingHandler: null,\n\n\t/**\n\t* @property {Integer} _requestResponseIntervalCount: Counts sent stanzas since last response request.\n\t*/\n\t_requestResponseIntervalCount: 0,\n\n\t/**\n\t * @property {boolean} _isSupported: indicates whether or not the server has advertised support for the stream\n\t * management namespace.\n\t */\n\t_isSupported: false,\n\n\t/**\n\t* @property {Queue} _unacknowledgedStanzas: Maintains a list of packet ids for stanzas which have yet to be acknowledged.\n\t*/\n\t_unacknowledgedStanzas: [],\n\n\t/**\n\t* @property {Array} _acknowledgedStanzaListeners: Stores callbacks for each stanza acknowledged by the server.\n\t* Provides the packet id of the stanza as a parameter.\n\t* @private\n\t*/\n\t_acknowledgedStanzaListeners: [],\n\n\taddAcknowledgedStanzaListener: function(listener) {\n\t\tthis._acknowledgedStanzaListeners.push(listener);\n\t},\n\n\tenable: function(resume) {\n\t\tif (!this._isSupported) {\n\t\t\tthrow new Error('The server doesn\\'t support urn:xmpp:sm:3 namespace');\n\t\t} else if (this._connectionStatus !== Strophe.Status.CONNECTED) {\n\t\t\tthrow new Error('enable() can only be called in the CONNECTED state');\n\t\t}\n\t\tthis._c.send($build('enable', { xmlns: this._NS, resume }));\n\t\tthis._c.flush();\n\t\tthis._c.pause();\n\t},\n\n\tgetResumeToken: function() {\n\t\treturn this._resumeToken;\n\t},\n\n\tisSupported() {\n\t\treturn this._isSupported;\n\t},\n\n\tresume: function() {\n\t\tif (!this.getResumeToken()) {\n\t\t\tthrow new Error('No resume token');\n\t\t}\n\t\tif (this._connectionStatus !== Strophe.Status.DISCONNECTED) {\n\t\t\tthrow new Error('resume() can only be called in the DISCONNECTED state');\n\t\t}\n\n\t\tthis._c.options.explicitResourceBinding = true;\n\t\tthis._resuming = true;\n\n\t\tthis._originalConnect.apply(this._c, this._connectArgs);\n\t},\n\n\trequestAcknowledgement: function() {\n\t\tif (this._connectionStatus !== Strophe.Status.CONNECTED) {\n\t\t\tthrow new Error('requestAcknowledgement() can only be called in the CONNECTED state');\n\t\t}\n\t\tthis._requestResponseIntervalCount = 0;\n\t\tthis._c.send($build('r', { xmlns: this._NS }));\n\t},\n\n\tgetOutgoingCounter: function() {\n\t\treturn this._clientSentStanzasCounter;\n\t},\n\n\tgetIncomingCounter: function() {\n\t\treturn this._clientProcessedStanzasCounter;\n\t},\n\n\tinit: function(conn) {\n\t\tthis._c = conn;\n\t\tStrophe.addNamespace('SM', this._NS);\n\n\t\t// Storing original xmlOutput function to use additional logic\n\t\tthis._originalXMLOutput = this._c.xmlOutput;\n\t\tthis._c.xmlOutput = this.xmlOutput.bind(this);\n\n\t\tthis._originalConnect = this._c.connect;\n\t\tthis._c.connect = this._interceptConnectArgs.bind(this);\n\n\t\tthis._originalOnStreamFeaturesAfterSASL = this._c._onStreamFeaturesAfterSASL;\n\t\tthis._c._onStreamFeaturesAfterSASL = this._onStreamFeaturesAfterSASL.bind(this);\n\n\t\tthis._originalDoDisconnect = this._c._doDisconnect;\n\t\tthis._c._doDisconnect = this._interceptDoDisconnect.bind(this);\n\n\t\tthis._originalDisconnect = this._c.disconnect;\n\t\tthis._c.disconnect = this._interceptDisconnect.bind(this);\n\t},\n\n\t_interceptDisconnect: function() {\n\t\tthis._resumeToken = undefined;\n\t\tthis._originalDisconnect.apply(this._c, arguments);\n\t},\n\n\t_interceptDoDisconnect: function() {\n\t\tif (this.getResumeToken()\n\t\t\t\t&& !this._resuming\n\t\t\t\t&& this._c.connected && !this._c.disconnecting) {\n\t\t\tthis._resumeState = {\n\t\t\t\thandlers: this._c.handlers,\n\t\t\t\ttimedHandlers: this._c.timedHandlers,\n\t\t\t\tremoveTimeds: this._c.removeTimeds,\n\t\t\t\tremoveHandlers: this._c.removeHandlers,\n\t\t\t\taddTimeds: this._c.addTimeds,\n\t\t\t\taddHandlers: this._c.addHandlers\n\t\t\t};\n\t\t\tthis._storedJid = this._c.jid;\n\n\t\t\tthis.logging && Strophe.debug('SM stored resume state, handler count: ' + this._resumeState.handlers.length);\n\t\t}\n\n\t\t// Remove any queued stanzas from the buffer that have failed to send while the socket was closed,\n\t\t// as they would interfere with the resume flow. They will be resent anyway.\n\t\tthis._c._data = [];\n\n\t\tthis._originalDoDisconnect.apply(this._c, arguments);\n\t},\n\n\t_interceptConnectArgs: function() {\n\t\tthis._connectArgs = arguments;\n\n\t\tthis._originalConnect.apply(this._c, arguments);\n\t},\n\n\t_onStreamFeaturesAfterSASL: function(elem) {\n\t\tthis._isSupported = elem.getElementsByTagNameNS(this._NS, \"sm\").length > 0;\n\n\t\treturn this._originalOnStreamFeaturesAfterSASL.apply(this._c, arguments);\n\t},\n\n\tstatusChanged: function (status) {\n\t\tthis._connectionStatus = status;\n\t\tif (!this.getResumeToken()\n\t\t\t&& (status === Strophe.Status.CONNECTED || status === Strophe.Status.DISCONNECTED)) {\n\t\t\tthis.logging && Strophe.debug('SM reset state');\n\n\t\t\tthis._serverProcesssedStanzasCounter = 0;\n\t\t\tthis._clientProcessedStanzasCounter = 0;\n\n\t\t\tthis._clientSentStanzasCounter = 0;\n\n\t\t\tthis._isStreamManagementEnabled = false;\n\t\t\tthis._requestResponseIntervalCount = 0;\n\n\t\t\t// FIXME not described in JSDocs\n\t\t\tthis._resuming = false;\n\n\t\t\tif (status === Strophe.Status.DISCONNECTED) {\n\t\t\t\tthis._isSupported = false;\n\t\t\t}\n\n\t\t\tthis._unacknowledgedStanzas = [];\n\n\t\t\tif (this._requestHandler) {\n\t\t\t\tthis._c.deleteHandler(this._requestHandler);\n\t\t\t}\n\n\t\t\tif (this._incomingHandler) {\n\t\t\t\tthis._c.deleteHandler(this._incomingHandler);\n\t\t\t}\n\n\t\t\tthis._requestHandler = this._c.addHandler(this._handleServerRequestHandler.bind(this), this._NS, 'r');\n\t\t\tthis._ackHandler = this._c.addHandler(this._handleServerAck.bind(this), this._NS, 'a');\n\t\t\tthis._incomingHandler = this._c.addHandler(this._incomingStanzaHandler.bind(this));\n\n\t\t\t// FIXME handler instances stored, but never used\n\t\t\tthis._enabledHandler = this._c._addSysHandler(this._handleEnabled.bind(this), this._NS, 'enabled');\n\t\t\tthis._resumeFailedHandler = this._c._addSysHandler(this._handleResumeFailed.bind(this), this._NS, 'failed');\n\t\t\tthis._resumedHandler =  this._c._addSysHandler(this._handleResumed.bind(this), this._NS,'resumed');\n\n\t\t} else if (status === Strophe.Status.BINDREQUIRED)  {\n\t\t\tthis._c.jid = this._storedJid;\n\n\t\t\t// Restore Strophe handlers\n\t\t\tfor (const h of (this._resumeState.handlers || [])\n\t\t\t\t\t.concat(this._resumeState.addHandlers || [])) {\n\t\t\t\tthis._c._addSysHandler(h.handler, h.ns, h.name, h.type, h.id);\n\t\t\t}\n\t\t\tfor (const h of (this._resumeState.timedHandlers || [])\n\t\t\t\t\t.concat(this._resumeState.addTimeds)) {\n\t\t\t\tthis._c.addTimedHandler(h.period, h.handler);\n\t\t\t}\n\t\t\tfor (const h of (this._resumeState.removeTimeds || [])\n\t\t\t\t\t.concat(this._resumeState.removeHandlers || [])) {\n\t\t\t\tthis._c.deleteTimedHandler(h);\n\t\t\t}\n\n\t\t\t// FIXME check conditions if there's session ID and if enabled\n\t\t\tthis._c.send($build('resume', {\n\t\t\t\txmlns: this._NS,\n\t\t\t\th: this._clientProcessedStanzasCounter,\n\t\t\t\tprevid: this._resumeToken\n\t\t\t}));\n\t\t\tthis._c.flush();\n\t\t} else if (status === Strophe.Status.ERROR) {\n\t\t\tthis.logging && Strophe.debug('SM cleared resume token on error');\n\t\t\tthis._resumeToken = undefined;\n\t\t}\n\t},\n\n\t/**\n\t* This method overrides the send method implemented by Strophe.Connection\n\t* to count outgoing stanzas\n\t*\n\t* @method Send\n\t* @public\n\t*/\n\txmlOutput: function(elem) {\n\t\tif (Strophe.isTagEqual(elem, 'iq') ||\n\t\t\tStrophe.isTagEqual(elem, 'presence') ||\n\t\t\tStrophe.isTagEqual(elem, 'message')) {\n\t\t\tthis._increaseSentStanzasCounter(elem);\n\t\t}\n\n\t\treturn this._originalXMLOutput.call(this._c, elem);\n\t},\n\n\t_handleEnabled: function(elem) {\n\t\tthis._isStreamManagementEnabled = true;\n\t\t// FIXME fail if requested, but not enabled\n\t\tthis._resumeToken = elem.getAttribute('resume') === 'true' && elem.getAttribute('id');\n\n\t\tthis._c.resume();\n\n\t\treturn true;\n\t},\n\n\t_handleResumeFailed: function(elem) {\n\t\tconst error = elem && (\n\t\t\t(elem.firstElementChild && elem.firstElementChild.tagName)\n\t\t\t|| (elem.firstChild && elem.firstChild.tagName));\n\n\t\tthis._c._changeConnectStatus(Strophe.Status.ERROR, error, elem);\n\t\tthis._c._doDisconnect();\n\n\t\treturn true;\n\t},\n\n\t_handleResumed: function(elem) {\n\t\t// FIXME check if in the correct state\n\t\tvar handledCount = parseInt(elem.getAttribute('h'));\n\t\tthis._handleAcknowledgedStanzas(handledCount, this._serverProcesssedStanzasCounter);\n\n\t\tthis._resuming = false;\n\t\tthis._c.do_bind = false; // No need to bind our resource anymore\n\t\tthis._c.authenticated = true;\n\t\tthis._c.restored = true;\n\n\t\tif (this._unacknowledgedStanzas.length > 0) {\n\t\t\tthis.logging && Strophe.debug('SM Sending unacknowledged stanzas', this._unacknowledgedStanzas);\n\t\t\tfor(const stanza of this._unacknowledgedStanzas) {\n\t\t\t\tthis._c.send(stanza);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.logging && Strophe.debug('SM No unacknowledged stanzas', this._unacknowledgedStanzas);\n\t\t}\n\n\t\tthis._c._changeConnectStatus(Strophe.Status.CONNECTED, null);\n\n\t\treturn true;\n\t},\n\n\t_incomingStanzaHandler: function(elem) {\n\t\tif (Strophe.isTagEqual(elem, 'iq') || Strophe.isTagEqual(elem, 'presence') || Strophe.isTagEqual(elem, 'message'))  {\n\t\t\tthis._increaseReceivedStanzasCounter();\n\n\t\t\tif (this.autoSendCountOnEveryIncomingStanza) {\n\t\t\t\tthis._answerProcessedStanzas();\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t},\n\n\t_handleAcknowledgedStanzas: function(reportedHandledCount, lastKnownHandledCount) {\n\t\tvar delta = reportedHandledCount - lastKnownHandledCount;\n\n\t\tif (delta < 0) {\n\t\t\tthis._throwError('New reported stanza count lower than previous. New: ' + reportedHandledCount + ' - Previous: ' + lastKnownHandledCount);\n\t\t}\n\n\t\tif (delta > this._unacknowledgedStanzas.length) {\n\t\t\tthis._throwError('Higher reported acknowledge count than unacknowledged stanzas. Reported Acknowledge Count: ' + delta + ' - Unacknowledge Stanza Count: ' + this._unacknowledgedStanzas.length + ' - New: ' + reportedHandledCount + ' - Previous: ' + lastKnownHandledCount);\n\t\t}\n\n\t\tfor(var i = 0; i < delta; i++) {\n\t\t\tvar stanza = this._unacknowledgedStanzas.shift();\n\t\t\tfor (var j = 0; j < this._acknowledgedStanzaListeners.length; j++) {\n\t\t\t\tthis._acknowledgedStanzaListeners[j](stanza);\n\t\t\t}\n\t\t}\n\n\t\tif (this.logging && this._unacknowledgedStanzas.length > 0) {\n\t\t\tStrophe.warn('SM Unacknowledged stanzas', this._unacknowledgedStanzas);\n\t\t}\n\n\t\tthis._serverProcesssedStanzasCounter = reportedHandledCount;\n\n\t\tif (this.requestResponseInterval > 0) {\n\t\t\tthis._requestResponseIntervalCount = 0;\n\t\t}\n\t},\n\n\t_handleServerRequestHandler: function() {\n\t\tthis._answerProcessedStanzas();\n\n\t\treturn true;\n\t},\n\n\t_handleServerAck: function(elem){\n\t\tvar handledCount = parseInt(elem.getAttribute('h'));\n\t\tthis._handleAcknowledgedStanzas(handledCount, this._serverProcesssedStanzasCounter);\n\n\t\treturn true;\n\t},\n\n\t_answerProcessedStanzas: function() {\n\t\tif (this._isStreamManagementEnabled) {\n\t\t\tthis._c.send($build('a', { xmlns: this._NS, h: this._clientProcessedStanzasCounter }));\n\t\t}\n\t},\n\n\t_increaseSentStanzasCounter: function(elem) {\n\t\tif (this._isStreamManagementEnabled) {\n\t\t\tif (this._unacknowledgedStanzas.indexOf(elem) !== -1) {\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._unacknowledgedStanzas.push(elem);\n\t\t\tthis._clientSentStanzasCounter++;\n\n\t\t\tif (this.requestResponseInterval > 0) {\n\t\t\t\tthis._requestResponseIntervalCount++;\n\n\t\t\t\tif (this._requestResponseIntervalCount === this.requestResponseInterval) {\n\t\t\t\t\t// FIXME Can not call send from onIdle.\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tif (this._connectionStatus === Strophe.Status.CONNECTED) {\n\t\t\t\t\t\t\tthis.requestAcknowledgement();\n\t\t\t\t\t\t}\n\t\t\t\t\t}, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t_increaseReceivedStanzasCounter: function() {\n\t\tif (this._isStreamManagementEnabled) {\n\t\t\tthis._clientProcessedStanzasCounter++;\n\t\t}\n\t},\n\n\t_throwError: function(msg) {\n\t\tStrophe.error(msg);\n\t\tthrow new Error(msg);\n\t}\n\n});\n","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = void 0;\n\n/**\n * Convert array of 16 byte values to UUID string format of the form:\n * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\n */\nconst byteToHex = [];\n\nfor (let i = 0; i < 256; ++i) {\n  byteToHex.push((i + 0x100).toString(16).substr(1));\n}\n\nfunction bytesToUuid(buf, offset) {\n  const i = offset || 0;\n  const bth = byteToHex; // Note: Be careful editing this code!  It's been tuned for performance\n  // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434\n\n  return (bth[buf[i + 0]] + bth[buf[i + 1]] + bth[buf[i + 2]] + bth[buf[i + 3]] + '-' + bth[buf[i + 4]] + bth[buf[i + 5]] + '-' + bth[buf[i + 6]] + bth[buf[i + 7]] + '-' + bth[buf[i + 8]] + bth[buf[i + 9]] + '-' + bth[buf[i + 10]] + bth[buf[i + 11]] + bth[buf[i + 12]] + bth[buf[i + 13]] + bth[buf[i + 14]] + bth[buf[i + 15]]).toLowerCase();\n}\n\nvar _default = bytesToUuid;\nexports.default = _default;","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nObject.defineProperty(exports, \"v1\", {\n  enumerable: true,\n  get: function () {\n    return _v.default;\n  }\n});\nObject.defineProperty(exports, \"v3\", {\n  enumerable: true,\n  get: function () {\n    return _v2.default;\n  }\n});\nObject.defineProperty(exports, \"v4\", {\n  enumerable: true,\n  get: function () {\n    return _v3.default;\n  }\n});\nObject.defineProperty(exports, \"v5\", {\n  enumerable: true,\n  get: function () {\n    return _v4.default;\n  }\n});\n\nvar _v = _interopRequireDefault(require(\"./v1.js\"));\n\nvar _v2 = _interopRequireDefault(require(\"./v3.js\"));\n\nvar _v3 = _interopRequireDefault(require(\"./v4.js\"));\n\nvar _v4 = _interopRequireDefault(require(\"./v5.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = void 0;\n\n/*\n * Browser-compatible JavaScript MD5\n *\n * Modification of JavaScript MD5\n * https://github.com/blueimp/JavaScript-MD5\n *\n * Copyright 2011, Sebastian Tschan\n * https://blueimp.net\n *\n * Licensed under the MIT license:\n * https://opensource.org/licenses/MIT\n *\n * Based on\n * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message\n * Digest Algorithm, as defined in RFC 1321.\n * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009\n * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\n * Distributed under the BSD License\n * See http://pajhome.org.uk/crypt/md5 for more info.\n */\nfunction md5(bytes) {\n  if (typeof bytes === 'string') {\n    const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape\n\n    bytes = new Uint8Array(msg.length);\n\n    for (let i = 0; i < msg.length; ++i) {\n      bytes[i] = msg.charCodeAt(i);\n    }\n  }\n\n  return md5ToHexEncodedArray(wordsToMd5(bytesToWords(bytes), bytes.length * 8));\n}\n/*\n * Convert an array of little-endian words to an array of bytes\n */\n\n\nfunction md5ToHexEncodedArray(input) {\n  const output = [];\n  const length32 = input.length * 32;\n  const hexTab = '0123456789abcdef';\n\n  for (let i = 0; i < length32; i += 8) {\n    const x = input[i >> 5] >>> i % 32 & 0xff;\n    const hex = parseInt(hexTab.charAt(x >>> 4 & 0x0f) + hexTab.charAt(x & 0x0f), 16);\n    output.push(hex);\n  }\n\n  return output;\n}\n/**\n * Calculate output length with padding and bit length\n */\n\n\nfunction getOutputLength(inputLength8) {\n  return (inputLength8 + 64 >>> 9 << 4) + 14 + 1;\n}\n/*\n * Calculate the MD5 of an array of little-endian words, and a bit length.\n */\n\n\nfunction wordsToMd5(x, len) {\n  /* append padding */\n  x[len >> 5] |= 0x80 << len % 32;\n  x[getOutputLength(len) - 1] = len;\n  let a = 1732584193;\n  let b = -271733879;\n  let c = -1732584194;\n  let d = 271733878;\n\n  for (let i = 0; i < x.length; i += 16) {\n    const olda = a;\n    const oldb = b;\n    const oldc = c;\n    const oldd = d;\n    a = md5ff(a, b, c, d, x[i], 7, -680876936);\n    d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);\n    c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);\n    b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);\n    a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);\n    d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);\n    c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);\n    b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);\n    a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);\n    d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);\n    c = md5ff(c, d, a, b, x[i + 10], 17, -42063);\n    b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);\n    a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);\n    d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);\n    c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);\n    b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);\n    a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);\n    d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);\n    c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);\n    b = md5gg(b, c, d, a, x[i], 20, -373897302);\n    a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);\n    d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);\n    c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);\n    b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);\n    a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);\n    d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);\n    c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);\n    b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);\n    a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);\n    d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);\n    c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);\n    b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);\n    a = md5hh(a, b, c, d, x[i + 5], 4, -378558);\n    d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);\n    c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);\n    b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);\n    a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);\n    d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);\n    c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);\n    b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);\n    a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);\n    d = md5hh(d, a, b, c, x[i], 11, -358537222);\n    c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);\n    b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);\n    a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);\n    d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);\n    c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);\n    b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);\n    a = md5ii(a, b, c, d, x[i], 6, -198630844);\n    d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);\n    c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);\n    b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);\n    a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);\n    d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);\n    c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);\n    b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);\n    a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);\n    d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);\n    c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);\n    b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);\n    a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);\n    d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);\n    c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);\n    b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);\n    a = safeAdd(a, olda);\n    b = safeAdd(b, oldb);\n    c = safeAdd(c, oldc);\n    d = safeAdd(d, oldd);\n  }\n\n  return [a, b, c, d];\n}\n/*\n * Convert an array bytes to an array of little-endian words\n * Characters >255 have their high-byte silently ignored.\n */\n\n\nfunction bytesToWords(input) {\n  if (input.length === 0) {\n    return [];\n  }\n\n  const length8 = input.length * 8;\n  const output = new Uint32Array(getOutputLength(length8));\n\n  for (let i = 0; i < length8; i += 8) {\n    output[i >> 5] |= (input[i / 8] & 0xff) << i % 32;\n  }\n\n  return output;\n}\n/*\n * Add integers, wrapping at 2^32. This uses 16-bit operations internally\n * to work around bugs in some JS interpreters.\n */\n\n\nfunction safeAdd(x, y) {\n  const lsw = (x & 0xffff) + (y & 0xffff);\n  const msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n  return msw << 16 | lsw & 0xffff;\n}\n/*\n * Bitwise rotate a 32-bit number to the left.\n */\n\n\nfunction bitRotateLeft(num, cnt) {\n  return num << cnt | num >>> 32 - cnt;\n}\n/*\n * These functions implement the four basic operations the algorithm uses.\n */\n\n\nfunction md5cmn(q, a, b, x, s, t) {\n  return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);\n}\n\nfunction md5ff(a, b, c, d, x, s, t) {\n  return md5cmn(b & c | ~b & d, a, b, x, s, t);\n}\n\nfunction md5gg(a, b, c, d, x, s, t) {\n  return md5cmn(b & d | c & ~d, a, b, x, s, t);\n}\n\nfunction md5hh(a, b, c, d, x, s, t) {\n  return md5cmn(b ^ c ^ d, a, b, x, s, t);\n}\n\nfunction md5ii(a, b, c, d, x, s, t) {\n  return md5cmn(c ^ (b | ~d), a, b, x, s, t);\n}\n\nvar _default = md5;\nexports.default = _default;","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = rng;\n// Unique ID creation requires a high quality random # generator. In the browser we therefore\n// require the crypto API and do not support built-in fallback to lower quality random number\n// generators (like Math.random()).\n// getRandomValues needs to be invoked in a context where \"this\" is a Crypto implementation. Also,\n// find the complete implementation of crypto (msCrypto) on IE11.\nconst getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto);\nconst rnds8 = new Uint8Array(16);\n\nfunction rng() {\n  if (!getRandomValues) {\n    throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');\n  }\n\n  return getRandomValues(rnds8);\n}","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = void 0;\n\n// Adapted from Chris Veness' SHA1 code at\n// http://www.movable-type.co.uk/scripts/sha1.html\nfunction f(s, x, y, z) {\n  switch (s) {\n    case 0:\n      return x & y ^ ~x & z;\n\n    case 1:\n      return x ^ y ^ z;\n\n    case 2:\n      return x & y ^ x & z ^ y & z;\n\n    case 3:\n      return x ^ y ^ z;\n  }\n}\n\nfunction ROTL(x, n) {\n  return x << n | x >>> 32 - n;\n}\n\nfunction sha1(bytes) {\n  const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];\n  const H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];\n\n  if (typeof bytes === 'string') {\n    const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape\n\n    bytes = [];\n\n    for (let i = 0; i < msg.length; ++i) {\n      bytes.push(msg.charCodeAt(i));\n    }\n  }\n\n  bytes.push(0x80);\n  const l = bytes.length / 4 + 2;\n  const N = Math.ceil(l / 16);\n  const M = new Array(N);\n\n  for (let i = 0; i < N; ++i) {\n    const arr = new Uint32Array(16);\n\n    for (let j = 0; j < 16; ++j) {\n      arr[j] = bytes[i * 64 + j * 4] << 24 | bytes[i * 64 + j * 4 + 1] << 16 | bytes[i * 64 + j * 4 + 2] << 8 | bytes[i * 64 + j * 4 + 3];\n    }\n\n    M[i] = arr;\n  }\n\n  M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32);\n  M[N - 1][14] = Math.floor(M[N - 1][14]);\n  M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff;\n\n  for (let i = 0; i < N; ++i) {\n    const W = new Uint32Array(80);\n\n    for (let t = 0; t < 16; ++t) {\n      W[t] = M[i][t];\n    }\n\n    for (let t = 16; t < 80; ++t) {\n      W[t] = ROTL(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);\n    }\n\n    let a = H[0];\n    let b = H[1];\n    let c = H[2];\n    let d = H[3];\n    let e = H[4];\n\n    for (let t = 0; t < 80; ++t) {\n      const s = Math.floor(t / 20);\n      const T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[t] >>> 0;\n      e = d;\n      d = c;\n      c = ROTL(b, 30) >>> 0;\n      b = a;\n      a = T;\n    }\n\n    H[0] = H[0] + a >>> 0;\n    H[1] = H[1] + b >>> 0;\n    H[2] = H[2] + c >>> 0;\n    H[3] = H[3] + d >>> 0;\n    H[4] = H[4] + e >>> 0;\n  }\n\n  return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff];\n}\n\nvar _default = sha1;\nexports.default = _default;","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = void 0;\n\nvar _rng = _interopRequireDefault(require(\"./rng.js\"));\n\nvar _bytesToUuid = _interopRequireDefault(require(\"./bytesToUuid.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n// **`v1()` - Generate time-based UUID**\n//\n// Inspired by https://github.com/LiosK/UUID.js\n// and http://docs.python.org/library/uuid.html\nlet _nodeId;\n\nlet _clockseq; // Previous uuid creation time\n\n\nlet _lastMSecs = 0;\nlet _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details\n\nfunction v1(options, buf, offset) {\n  let i = buf && offset || 0;\n  const b = buf || [];\n  options = options || {};\n  let node = options.node || _nodeId;\n  let clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not\n  // specified.  We do this lazily to minimize issues related to insufficient\n  // system entropy.  See #189\n\n  if (node == null || clockseq == null) {\n    const seedBytes = options.random || (options.rng || _rng.default)();\n\n    if (node == null) {\n      // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)\n      node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]];\n    }\n\n    if (clockseq == null) {\n      // Per 4.2.2, randomize (14 bit) clockseq\n      clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff;\n    }\n  } // UUID timestamps are 100 nano-second units since the Gregorian epoch,\n  // (1582-10-15 00:00).  JSNumbers aren't precise enough for this, so\n  // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'\n  // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.\n\n\n  let msecs = options.msecs !== undefined ? options.msecs : Date.now(); // Per 4.2.1.2, use count of uuid's generated during the current clock\n  // cycle to simulate higher resolution clock\n\n  let nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs)\n\n  const dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; // Per 4.2.1.2, Bump clockseq on clock regression\n\n  if (dt < 0 && options.clockseq === undefined) {\n    clockseq = clockseq + 1 & 0x3fff;\n  } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new\n  // time interval\n\n\n  if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {\n    nsecs = 0;\n  } // Per 4.2.1.2 Throw error if too many uuids are requested\n\n\n  if (nsecs >= 10000) {\n    throw new Error(\"uuid.v1(): Can't create more than 10M uuids/sec\");\n  }\n\n  _lastMSecs = msecs;\n  _lastNSecs = nsecs;\n  _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch\n\n  msecs += 12219292800000; // `time_low`\n\n  const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;\n  b[i++] = tl >>> 24 & 0xff;\n  b[i++] = tl >>> 16 & 0xff;\n  b[i++] = tl >>> 8 & 0xff;\n  b[i++] = tl & 0xff; // `time_mid`\n\n  const tmh = msecs / 0x100000000 * 10000 & 0xfffffff;\n  b[i++] = tmh >>> 8 & 0xff;\n  b[i++] = tmh & 0xff; // `time_high_and_version`\n\n  b[i++] = tmh >>> 24 & 0xf | 0x10; // include version\n\n  b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)\n\n  b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low`\n\n  b[i++] = clockseq & 0xff; // `node`\n\n  for (let n = 0; n < 6; ++n) {\n    b[i + n] = node[n];\n  }\n\n  return buf || (0, _bytesToUuid.default)(b);\n}\n\nvar _default = v1;\nexports.default = _default;","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = void 0;\n\nvar _v = _interopRequireDefault(require(\"./v35.js\"));\n\nvar _md = _interopRequireDefault(require(\"./md5.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nconst v3 = (0, _v.default)('v3', 0x30, _md.default);\nvar _default = v3;\nexports.default = _default;","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = _default;\nexports.URL = exports.DNS = void 0;\n\nvar _bytesToUuid = _interopRequireDefault(require(\"./bytesToUuid.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction uuidToBytes(uuid) {\n  // Note: We assume we're being passed a valid uuid string\n  const bytes = [];\n  uuid.replace(/[a-fA-F0-9]{2}/g, function (hex) {\n    bytes.push(parseInt(hex, 16));\n  });\n  return bytes;\n}\n\nfunction stringToBytes(str) {\n  str = unescape(encodeURIComponent(str)); // UTF8 escape\n\n  const bytes = [];\n\n  for (let i = 0; i < str.length; ++i) {\n    bytes.push(str.charCodeAt(i));\n  }\n\n  return bytes;\n}\n\nconst DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';\nexports.DNS = DNS;\nconst URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';\nexports.URL = URL;\n\nfunction _default(name, version, hashfunc) {\n  function generateUUID(value, namespace, buf, offset) {\n    const off = buf && offset || 0;\n    if (typeof value === 'string') value = stringToBytes(value);\n    if (typeof namespace === 'string') namespace = uuidToBytes(namespace);\n\n    if (!Array.isArray(value)) {\n      throw TypeError('value must be an array of bytes');\n    }\n\n    if (!Array.isArray(namespace) || namespace.length !== 16) {\n      throw TypeError('namespace must be uuid string or an Array of 16 byte values');\n    } // Per 4.3\n\n\n    const bytes = hashfunc(namespace.concat(value));\n    bytes[6] = bytes[6] & 0x0f | version;\n    bytes[8] = bytes[8] & 0x3f | 0x80;\n\n    if (buf) {\n      for (let idx = 0; idx < 16; ++idx) {\n        buf[off + idx] = bytes[idx];\n      }\n    }\n\n    return buf || (0, _bytesToUuid.default)(bytes);\n  } // Function#name is not settable on some platforms (#270)\n\n\n  try {\n    generateUUID.name = name; // eslint-disable-next-line no-empty\n  } catch (err) {} // For CommonJS default export support\n\n\n  generateUUID.DNS = DNS;\n  generateUUID.URL = URL;\n  return generateUUID;\n}","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = void 0;\n\nvar _rng = _interopRequireDefault(require(\"./rng.js\"));\n\nvar _bytesToUuid = _interopRequireDefault(require(\"./bytesToUuid.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction v4(options, buf, offset) {\n  if (typeof options === 'string') {\n    buf = options === 'binary' ? new Uint8Array(16) : null;\n    options = null;\n  }\n\n  options = options || {};\n\n  const rnds = options.random || (options.rng || _rng.default)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`\n\n\n  rnds[6] = rnds[6] & 0x0f | 0x40;\n  rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided\n\n  if (buf) {\n    const start = offset || 0;\n\n    for (let i = 0; i < 16; ++i) {\n      buf[start + i] = rnds[i];\n    }\n\n    return buf;\n  }\n\n  return (0, _bytesToUuid.default)(rnds);\n}\n\nvar _default = v4;\nexports.default = _default;","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = void 0;\n\nvar _v = _interopRequireDefault(require(\"./v35.js\"));\n\nvar _sha = _interopRequireDefault(require(\"./sha1.js\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nconst v5 = (0, _v.default)('v5', 0x50, _sha.default);\nvar _default = v5;\nexports.default = _default;","/**\n * Enumeration of the video types that are signaled to the bridge\n * @type {{CAMERA: string, DESKTOP: string, DESKTOP_HIGH_FPS: string, NONE: string}}\n */\nconst BridgeVideoType = {\n    /**\n     * The camera video type.\n     */\n    CAMERA: 'camera',\n\n    /**\n     * The low fps desktop video type.\n     */\n    DESKTOP: 'desktop',\n\n    /**\n     * The high fps desktop video type.\n     */\n    DESKTOP_HIGH_FPS: 'desktop_high_fps',\n\n    /**\n     * Video type when no local source is present.\n     */\n    NONE: 'none'\n};\n\nmodule.exports = BridgeVideoType;\n","/**\n * The possible camera facing modes. For now support only 'user' and\n * 'environment' because 'left' and 'right' are not used anywhere in our\n * projects at the time of this writing. For more information please refer to\n * https://w3c.github.io/mediacapture-main/getusermedia.html\n * #def-constraint-facingMode.\n *\n * @enum {string}\n */\nconst CameraFacingMode = {\n    /**\n     * The mode which specifies the environment-facing camera.\n     */\n    ENVIRONMENT: 'environment',\n\n    /**\n     * The mode which specifies the user-facing camera.\n     */\n    USER: 'user'\n};\n\nmodule.exports = CameraFacingMode;\n","/**\n * Enumeration of the codec mime types\n * @type {{H264: string, OPUS: string, ULPFEC: string, VP8: string, VP9: string}}\n */\nconst CodecMimeType = {\n    /**\n     * AV1 codec mime type.\n     */\n    AV1: 'av1',\n\n    /**\n     * The h264 codec mime type.\n     */\n    H264: 'h264',\n\n    /**\n     * The opus codec mime type.\n     */\n    OPUS: 'opus',\n\n    /**\n     * The ulpfec codec mime type.\n     */\n    ULPFEC: 'ulpfec',\n\n    /**\n     * The vp8 codec mime type.\n     */\n    VP8: 'vp8',\n\n    /**\n     * The vp9 codec mime type.\n     */\n    VP9: 'vp9'\n\n};\n\nmodule.exports = CodecMimeType;\n","export enum RTCEvents {\n    /**\n     * Indicates error while create answer call.\n     */\n    CREATE_ANSWER_FAILED = 'rtc.create_answer_failed',\n\n    /**\n     * Indicates error while create offer call.\n     */\n    CREATE_OFFER_FAILED = 'rtc.create_offer_failed',\n    DATA_CHANNEL_OPEN = 'rtc.data_channel_open',\n    DATA_CHANNEL_CLOSED = 'rtc.data_channel_closed',\n    ENDPOINT_CONN_STATUS_CHANGED = 'rtc.endpoint_conn_status_changed',\n    DOMINANT_SPEAKER_CHANGED = 'rtc.dominant_speaker_changed',\n    FORWARDED_SOURCES_CHANGED = 'rtc.forwarded_sources_changed',\n\n    /**\n     * Event emitted when the user granted/blocked a permission for the camera / mic.\n     * Used to keep track of the granted permissions on browsers which don't\n     * support the Permissions API.\n     */\n    PERMISSIONS_CHANGED = 'rtc.permissions_changed',\n\n    SENDER_VIDEO_CONSTRAINTS_CHANGED = 'rtc.sender_video_constraints_changed',\n\n    /**\n     * Event emitted when {@link RTC.setLastN} method is called to update with\n     * the new value set.\n     * The first argument is the value passed to {@link RTC.setLastN}.\n     */\n    LASTN_VALUE_CHANGED = 'rtc.lastn_value_changed',\n\n    /**\n     * Event emitted when ssrc for a local track is extracted and stored\n     * in {@link TraceablePeerConnection}.\n     * @param {JitsiLocalTrack} track which ssrc was updated\n     * @param {string} ssrc that was stored\n     */\n    LOCAL_TRACK_SSRC_UPDATED = 'rtc.local_track_ssrc_updated',\n\n    /**\n     * The max enabled resolution of a local video track was changed.\n     */\n    LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED = 'rtc.local_track_max_enabled_resolution_changed',\n\n    TRACK_ATTACHED = 'rtc.track_attached',\n\n    /**\n     * Event fired when we remote track is added to the conference.\n     * 1st event argument is the added <tt>JitsiRemoteTrack</tt> instance.\n     **/\n    REMOTE_TRACK_ADDED = 'rtc.remote_track_added',\n\n    // FIXME get rid of this event in favour of NO_DATA_FROM_SOURCE event\n    // (currently implemented for local tracks only)\n    REMOTE_TRACK_MUTE = 'rtc.remote_track_mute',\n\n    /**\n     * Indicates that the remote track has been removed from the conference.\n     * 1st event argument is the removed {@link JitsiRemoteTrack} instance.\n     */\n    REMOTE_TRACK_REMOVED = 'rtc.remote_track_removed',\n\n    // FIXME get rid of this event in favour of NO_DATA_FROM_SOURCE event\n    // (currently implemented for local tracks only)\n    REMOTE_TRACK_UNMUTE = 'rtc.remote_track_unmute',\n\n    /**\n     * Indicates error while set local description.\n     */\n    SET_LOCAL_DESCRIPTION_FAILED = 'rtc.set_local_description_failed',\n\n    /**\n     * Indicates error while set remote description.\n     */\n    SET_REMOTE_DESCRIPTION_FAILED = 'rtc.set_remote_description_failed',\n    AUDIO_OUTPUT_DEVICE_CHANGED = 'rtc.audio_output_device_changed',\n    DEVICE_LIST_CHANGED = 'rtc.device_list_changed',\n\n    /**\n     * Indicates that the list with available devices will change.\n     */\n    DEVICE_LIST_WILL_CHANGE = 'rtc.device_list_will_change',\n    DEVICE_LIST_AVAILABLE = 'rtc.device_list_available',\n\n    /**\n     * Indicates that a message from another participant is received on\n     * data channel.\n     */\n    ENDPOINT_MESSAGE_RECEIVED = 'rtc.endpoint_message_received',\n\n    /**\n     * Indicates that the remote endpoint stats have been received on data channel.\n     */\n    ENDPOINT_STATS_RECEIVED = 'rtc.endpoint_stats_received',\n\n    /**\n     * Designates an event indicating that the local ICE username fragment of\n     * the jingle session has changed.\n     * The first argument of the vent is <tt>TraceablePeerConnection</tt> which\n     * is the source of the event.\n     * The second argument is the actual \"ufrag\" string.\n     */\n    LOCAL_UFRAG_CHANGED = 'rtc.local_ufrag_changed',\n\n    /**\n     * Designates an event indicating that the local ICE username fragment of\n     * the jingle session has changed.\n     * The first argument of the vent is <tt>TraceablePeerConnection</tt> which\n     * is the source of the event.\n     * The second argument is the actual \"ufrag\" string.\n     */\n    REMOTE_UFRAG_CHANGED = 'rtc.remote_ufrag_changed',\n\n    /**\n     * Designates an event indicating that some received video SSRCs will now map to\n     * new remote sources.\n     */\n    VIDEO_SSRCS_REMAPPED = 'rtc.video_ssrcs_remapped',\n\n    /**\n     * Designates an event indicating that some received audio SSRCs will now map to\n     * new remote sources.\n     */\n    AUDIO_SSRCS_REMAPPED = 'rtc.audio_ssrcs_remapped'\n};\n\nexport const CREATE_ANSWER_FAILED = RTCEvents.CREATE_ANSWER_FAILED;\nexport const CREATE_OFFER_FAILED = RTCEvents.CREATE_OFFER_FAILED;\nexport const DATA_CHANNEL_OPEN = RTCEvents.DATA_CHANNEL_OPEN;\nexport const DATA_CHANNEL_CLOSED = RTCEvents.DATA_CHANNEL_CLOSED;\nexport const ENDPOINT_CONN_STATUS_CHANGED = RTCEvents.ENDPOINT_CONN_STATUS_CHANGED;\nexport const DOMINANT_SPEAKER_CHANGED = RTCEvents.DOMINANT_SPEAKER_CHANGED;\nexport const FORWARDED_SOURCES_CHANGED = RTCEvents.FORWARDED_SOURCES_CHANGED;\nexport const PERMISSIONS_CHANGED = RTCEvents.PERMISSIONS_CHANGED;\nexport const SENDER_VIDEO_CONSTRAINTS_CHANGED = RTCEvents.SENDER_VIDEO_CONSTRAINTS_CHANGED;\nexport const LASTN_VALUE_CHANGED = RTCEvents.LASTN_VALUE_CHANGED;\nexport const LOCAL_TRACK_SSRC_UPDATED = RTCEvents.LOCAL_TRACK_SSRC_UPDATED;\nexport const LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED = RTCEvents.LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED;\nexport const TRACK_ATTACHED = RTCEvents.TRACK_ATTACHED;\nexport const REMOTE_TRACK_ADDED = RTCEvents.REMOTE_TRACK_ADDED;\nexport const REMOTE_TRACK_MUTE = RTCEvents.REMOTE_TRACK_MUTE;\nexport const REMOTE_TRACK_REMOVED = RTCEvents.REMOTE_TRACK_REMOVED;\nexport const REMOTE_TRACK_UNMUTE = RTCEvents.REMOTE_TRACK_UNMUTE;\nexport const SET_LOCAL_DESCRIPTION_FAILED = RTCEvents.SET_LOCAL_DESCRIPTION_FAILED;\nexport const SET_REMOTE_DESCRIPTION_FAILED = RTCEvents.SET_REMOTE_DESCRIPTION_FAILED;\nexport const AUDIO_OUTPUT_DEVICE_CHANGED = RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED;\nexport const DEVICE_LIST_CHANGED = RTCEvents.DEVICE_LIST_CHANGED;\nexport const DEVICE_LIST_WILL_CHANGE = RTCEvents.DEVICE_LIST_WILL_CHANGE;\nexport const DEVICE_LIST_AVAILABLE = RTCEvents.DEVICE_LIST_AVAILABLE;\nexport const ENDPOINT_MESSAGE_RECEIVED = RTCEvents.ENDPOINT_MESSAGE_RECEIVED;\nexport const ENDPOINT_STATS_RECEIVED = RTCEvents.ENDPOINT_STATS_RECEIVED;\nexport const LOCAL_UFRAG_CHANGED = RTCEvents.LOCAL_UFRAG_CHANGED;\nexport const REMOTE_UFRAG_CHANGED = RTCEvents.REMOTE_UFRAG_CHANGED;\nexport const VIDEO_SSRCS_REMAPPED = RTCEvents.VIDEO_SSRCS_REMAPPED;\nexport const AUDIO_SSRCS_REMAPPED = RTCEvents.AUDIO_SSRCS_REMAPPED;\n\n// TODO: this was a pre-ES6 module using module.exports = RTCEvents which doesn't translate well\n// it is used in a number of places and should be updated to use the named export\n\nexport default RTCEvents;","const Resolutions = {\n    '2160': {\n        width: 3840,\n        height: 2160\n    },\n    '4k': {\n        width: 3840,\n        height: 2160\n    },\n    '1080': {\n        width: 1920,\n        height: 1080\n    },\n    'fullhd': {\n        width: 1920,\n        height: 1080\n    },\n    '720': {\n        width: 1280,\n        height: 720\n    },\n    'hd': {\n        width: 1280,\n        height: 720\n    },\n    '540': {\n        width: 960,\n        height: 540\n    },\n    'qhd': {\n        width: 960,\n        height: 540\n    },\n    '480': {\n        width: 640,\n        height: 480\n    },\n    'vga': {\n        width: 640,\n        height: 480\n    },\n    '360': {\n        width: 640,\n        height: 360\n    },\n    '240': {\n        width: 320,\n        height: 240\n    },\n    '180': {\n        width: 320,\n        height: 180\n    }\n};\n\nmodule.exports = Resolutions;\n","/**\n * Enumeration of the video types\n */\nexport enum VideoType {\n    /**\n     * The camera video type.\n     */\n    CAMERA = 'camera',\n\n    /**\n     * The desktop video type.\n     */\n    DESKTOP = 'desktop'\n};\n","const AuthenticationEvents = {\n    /**\n     * Event callback arguments:\n     * function(authenticationEnabled, userIdentity)\n     * authenticationEnabled - indicates whether authentication has been enabled\n     *                         in this session\n     * userIdentity - if user has been logged in then it contains user name. If\n     *                contains 'null' or 'undefined' then user is not logged in.\n     */\n    IDENTITY_UPDATED: 'authentication.identity_updated'\n};\n\nmodule.exports = AuthenticationEvents;\n","export const LOCAL_JID = 'local'\n","export enum XMPPEvents {\n    /**\n     * Indicates error while adding ice candidate.\n     */\n    ADD_ICE_CANDIDATE_FAILED = 'xmpp.add_ice_candidate_failed',\n\n    // Designates an event indicating that the focus has asked us to mute our\n    // audio.\n    AUDIO_MUTED_BY_FOCUS = 'xmpp.audio_muted_by_focus',\n\n    // Designates an event indicating that the focus has asked us to disable our\n    // camera.\n    VIDEO_MUTED_BY_FOCUS = 'xmpp.video_muted_by_focus',\n    AUTHENTICATION_REQUIRED = 'xmpp.authentication_required',\n    BRIDGE_DOWN = 'xmpp.bridge_down',\n\n    /**\n     * Triggered when 'session-accept' is received from the responder.\n     */\n    CALL_ACCEPTED = 'xmpp.callaccepted.jingle',\n\n    // Designates an event indicating that an offer (e.g. Jingle\n    // session-initiate) was received.\n    CALL_INCOMING = 'xmpp.callincoming.jingle',\n\n    // Triggered when Jicofo kills our media session, this can happen while\n    // we're still in the MUC, when it decides to terminate the media session.\n    // For example when the session is idle for too long, because we're the only\n    // person in the conference room.\n    CALL_ENDED = 'xmpp.callended.jingle',\n    CHAT_ERROR_RECEIVED = 'xmpp.chat_error_received',\n    SETTINGS_ERROR_RECEIVED = 'xmpp.settings_error_received',\n\n    // The conference properties (as advertised by jicofo) have changed\n    CONFERENCE_PROPERTIES_CHANGED = 'xmpp.conference_properties_changed',\n\n    /**\n     * This event is triggered when the ICE connects for the first time.\n     */\n    CONNECTION_ESTABLISHED = 'xmpp.connection.connected',\n\n    // Designates an event indicating that the connection to the XMPP server\n    // failed.\n    CONNECTION_FAILED = 'xmpp.connection.failed',\n\n    // Designates an event indicating that the media (ICE) connection was\n    // interrupted. This should go to the RTC module.\n    CONNECTION_INTERRUPTED = 'xmpp.connection.interrupted',\n\n    // Designates an event indicating that the media (ICE) connection was\n    // restored. This should go to the RTC module.\n    CONNECTION_RESTORED = 'xmpp.connection.restored',\n\n    // Designates an event indicating that the media (ICE) connection failed.\n    // This should go to the RTC module.\n    CONNECTION_ICE_FAILED = 'xmpp.connection.ice.failed',\n\n    // Designates an event indicating that the call has been migrated to a different\n    // bridge and that the client needs to be restarted for a successful transition.\n    CONNECTION_RESTARTED = 'xmpp.connection.restart',\n\n    /**\n     * Designates an event indicating connection status changes.\n     */\n    CONNECTION_STATUS_CHANGED = 'xmpp.connection.status.changed',\n\n    // Designates an event indicating that the display name of a participant\n    // has changed.\n    DISPLAY_NAME_CHANGED = 'xmpp.display_name_changed',\n\n    /**\n     * Chat room instance have been added to Strophe.emuc plugin.\n     */\n    EMUC_ROOM_ADDED = 'xmpp.emuc_room_added',\n\n    /**\n     * Chat room instance have been removed from Strophe.emuc plugin.\n     */\n    EMUC_ROOM_REMOVED = 'xmpp.emuc_room_removed',\n    ETHERPAD = 'xmpp.etherpad',\n    FOCUS_DISCONNECTED = 'xmpp.focus_disconnected',\n    FOCUS_LEFT = 'xmpp.focus_left',\n    GRACEFUL_SHUTDOWN = 'xmpp.graceful_shutdown',\n\n    /**\n     * Event fired when 'transport-replace' Jingle message has been received,\n     * before the new offer is set on the PeerConnection.\n     */\n    ICE_RESTARTING = 'rtc.ice_restarting',\n\n    /**\n     * Event fired after the 'transport-replace' message has been processed\n     * and the new offer has been set successfully.\n     */\n    ICE_RESTART_SUCCESS = 'rtc.ice_restart_success',\n\n    /**\n     * Designates an event indicating that we were kicked from the XMPP MUC.\n     * @param {boolean} isSelfPresence - whether it is for local participant\n     * or another participant.\n     * @param {string} actorJid - the jid of the participant who was initiator\n     * of the kick.\n     * @param {?string} participantJid - when it is not a kick for local participant,\n     * this is the jid of the participant which was kicked.\n     */\n    KICKED = 'xmpp.kicked',\n\n    // Designates an event indicating that our role in the XMPP MUC has changed.\n    LOCAL_ROLE_CHANGED = 'xmpp.localrole_changed',\n\n    /**\n     * Event fired when the unique meeting id is set.\n     */\n    MEETING_ID_SET = 'xmpp.meeting_id_set',\n\n    // Designates an event indicating that an XMPP message in the MUC was\n    // received.\n    MESSAGE_RECEIVED = 'xmpp.message_received',\n\n    // Designates an event indicating that an invite XMPP message in the MUC was\n    // received.\n    INVITE_MESSAGE_RECEIVED = 'xmpp.invite_message_received',\n\n    // Designates an event indicating that a private XMPP message in the MUC was\n    // received.\n    PRIVATE_MESSAGE_RECEIVED = 'xmpp.private_message_received',\n\n    // Designates an event indicating that a bot participant type had changed\n    MUC_MEMBER_BOT_TYPE_CHANGED = 'xmpp.muc_member_bot_type_changed',\n\n    // Designates an event indicating that the XMPP MUC was destroyed.\n    MUC_DESTROYED = 'xmpp.muc_destroyed',\n\n    // Designates an event indicating that we are currently in process of joining the XMPP MUC.\n    MUC_JOIN_IN_PROGRESS = 'xmpp.muc_join_in_progress',\n\n    // Designates an event indicating that we have joined the XMPP MUC.\n    MUC_JOINED = 'xmpp.muc_joined',\n\n    // Designates an event indicating that a participant joined the XMPP MUC.\n    MUC_MEMBER_JOINED = 'xmpp.muc_member_joined',\n\n    // Designates an event indicating that a participant left the XMPP MUC.\n    MUC_MEMBER_LEFT = 'xmpp.muc_member_left',\n\n    // Designates an event indicating that a participant joined the lobby XMPP MUC.\n    MUC_LOBBY_MEMBER_JOINED = 'xmpp.muc_lobby_member_joined',\n\n    // Designates an event indicating that a participant in the lobby XMPP MUC has been updated\n    MUC_LOBBY_MEMBER_UPDATED = 'xmpp.muc_lobby_member_updated',\n\n    // Designates an event indicating that a participant left the XMPP MUC.\n    MUC_LOBBY_MEMBER_LEFT = 'xmpp.muc_lobby_member_left',\n\n    // Designates an event indicating that a participant was denied access to a conference from the lobby XMPP MUC.\n    MUC_DENIED_ACCESS = 'xmpp.muc_denied access',\n\n    // Designates an event indicating that local participant left the muc\n    MUC_LEFT = 'xmpp.muc_left',\n\n    // Designates an event indicating that the MUC role of a participant has\n    // changed.\n    MUC_ROLE_CHANGED = 'xmpp.muc_role_changed',\n\n    // Designates an event indicating that the MUC has been locked or unlocked.\n    MUC_LOCK_CHANGED = 'xmpp.muc_lock_changed',\n\n    // Designates an event indicating that the MUC members only config has changed.\n    MUC_MEMBERS_ONLY_CHANGED = 'xmpp.muc_members_only_changed',\n\n    // Designates an event indicating that a participant in the XMPP MUC has\n    // advertised that they have audio muted (or unmuted).\n    PARTICIPANT_AUDIO_MUTED = 'xmpp.audio_muted',\n\n    // Designates an event indicating that a participant in the XMPP MUC has\n    // advertised that they have video muted (or unmuted).\n    PARTICIPANT_VIDEO_MUTED = 'xmpp.video_muted',\n\n    // Designates an event indicating that the video type (e.g. 'camera' or\n    // 'screen') for a participant has changed.\n    // Note = currently this event fires every time we receive presence from\n    // someone (regardless of whether or not the \"video type\" changed).\n    PARTICIPANT_VIDEO_TYPE_CHANGED = 'xmpp.video_type',\n\n    /**\n     * Indicates that the features of the participant has been changed.\n     */\n    PARTICIPANT_FEATURES_CHANGED = 'xmpp.participant_features_changed',\n    PASSWORD_REQUIRED = 'xmpp.password_required',\n\n    /**\n     * Indicates that phone number changed.\n     */\n    PHONE_NUMBER_CHANGED = 'conference.phoneNumberChanged',\n    PRESENCE_RECEIVED = 'xmpp.presence_received',\n    PRESENCE_STATUS = 'xmpp.presence_status',\n    PROMPT_FOR_LOGIN = 'xmpp.prompt_for_login',\n\n    // xmpp is connected and obtained user media\n    READY_TO_JOIN = 'xmpp.ready_to_join',\n\n    /**\n     * Indicates that recording state changed.\n     */\n    RECORDER_STATE_CHANGED = 'xmpp.recorderStateChanged',\n\n    /**\n     * The conference was redirected to a visitor node.\n     */\n    REDIRECTED = 'xmpp.redirected',\n\n    // Designates an event indicating that we received statistics from a\n    // participant in the MUC.\n    REMOTE_STATS = 'xmpp.remote_stats',\n\n    /**\n     * Indicates that the offer / answer renegotiation has failed.\n     */\n    RENEGOTIATION_FAILED = 'xmpp.renegotiation_failed',\n    RESERVATION_ERROR = 'xmpp.room_reservation_error',\n    ROOM_CONNECT_ERROR = 'xmpp.room_connect_error',\n    ROOM_CONNECT_NOT_ALLOWED_ERROR = 'xmpp.room_connect_error.not_allowed',\n    ROOM_JOIN_ERROR = 'xmpp.room_join_error',\n    ROOM_CONNECT_MEMBERS_ONLY_ERROR = 'xmpp.room_connect_error.members_only',\n\n    /**\n     * Indicates that max users limit has been reached.\n     */\n    ROOM_MAX_USERS_ERROR = 'xmpp.room_max_users_error',\n\n    // Designates an event indicating that we sent an XMPP message to the MUC.\n    SENDING_CHAT_MESSAGE = 'xmpp.sending_chat_message',\n\n    // Designates an event indicating that we sent a private XMPP message to\n    // a specific user of the muc.\n    SENDING_PRIVATE_CHAT_MESSAGE = 'xmpp.sending_private_chat_message',\n\n    /**\n     * Event fired after receiving the confirmation about session accept.\n     */\n    SESSION_ACCEPT = 'xmpp.session_accept',\n\n    /**\n     * Event fired if we receive an error after sending the session accept.\n     */\n    SESSION_ACCEPT_ERROR = 'xmpp.session_accept_error',\n\n    /**\n     * Event fired when we do not get our 'session-accept' acknowledged by\n     * Jicofo. It most likely means that there is serious problem with our\n     * connection or XMPP server and we should reload the conference.\n     *\n     * We have seen that to happen in BOSH requests race condition when the BOSH\n     * request table containing the 'session-accept' was discarded by Prosody.\n     * Jicofo does send the RESULT immediately without any condition, so missing\n     * packets means that most likely it has never seen our IQ.\n     */\n    SESSION_ACCEPT_TIMEOUT = 'xmpp.session_accept_timeout',\n\n    /**\n     * Event fired after successful sending of jingle source-add.\n     */\n    SOURCE_ADD = 'xmpp.source_add',\n\n    /**\n     * Event fired after receiving an error sending of jingle source-add.\n     */\n    SOURCE_ADD_ERROR = 'xmpp.source_add_error',\n\n    /**\n     * Event fired after successful sending of jingle source-remove.\n     */\n    SOURCE_REMOVE = 'xmpp.source_remove',\n\n    /**\n     * Event fired after receiving an error sending of jingle source-remove.\n     */\n    SOURCE_REMOVE_ERROR = 'xmpp.source_remove_error',\n\n    /**\n     * Event fired when speaker stats update message is received.\n     */\n    SPEAKER_STATS_RECEIVED = 'xmpp.speaker_stats_received',\n\n    /**\n     * Event fired when conference creation timestamp is received.\n     */\n    CONFERENCE_TIMESTAMP_RECEIVED = 'xmpp.conference_timestamp_received',\n\n    /**\n     * Event fired when we receive a message for AV moderation approved for the local participant.\n     */\n    AV_MODERATION_APPROVED = 'xmpp.av_moderation.approved',\n\n    /**\n    * Event fired when we receive a message for AV moderation rejected for the local participant.\n    */\n    AV_MODERATION_REJECTED = 'xmpp.av_moderation.rejected',\n\n    /**\n     * Event fired when we receive a message for AV moderation.\n     */\n    AV_MODERATION_RECEIVED = 'xmpp.av_moderation.received',\n\n    /**\n     * Event fired when the moderation enable/disable changes.\n     */\n    AV_MODERATION_CHANGED = 'xmpp.av_moderation.changed',\n\n    /**\n     * Event fired when we receive message that a new jid was approved.\n     */\n    AV_MODERATION_PARTICIPANT_APPROVED = 'xmpp.av_moderation.participant.approved',\n\n    /**\n     * Event fired when we receive message that a new jid was approved.\n     */\n    AV_MODERATION_PARTICIPANT_REJECTED = 'xmpp.av_moderation.participant.rejected',\n\n    /**\n     * Event fired when a participant is requested to join a given (breakout) room.\n     */\n    BREAKOUT_ROOMS_MOVE_TO_ROOM = 'xmpp.breakout-rooms.move-to-room',\n\n    /**\n     * Event fired when we receive a message for breakout rooms.\n     */\n    BREAKOUT_ROOMS_EVENT = 'xmpp.breakout-rooms.event',\n\n    /**\n     * Event fired when the breakout rooms data was updated.\n     */\n    BREAKOUT_ROOMS_UPDATED = 'xmpp.breakout-rooms.updated',\n\n    /**\n     * Event fired when we receive a message related to room metadata.\n     */\n    ROOM_METADATA_EVENT = 'xmpp.room-metadata.event',\n\n    /**\n     * Event fired when we receive a message related to room metadata.\n     */\n    ROOM_METADATA_UPDATED = 'xmpp.room-metadata.updated',\n\n    // Designates an event indicating that we should join the conference with\n    // audio and/or video muted.\n    START_MUTED_FROM_FOCUS = 'xmpp.start_muted_from_focus',\n\n    // Designates an event indicating that the subject of the XMPP MUC has\n    // changed.\n    SUBJECT_CHANGED = 'xmpp.subject_changed',\n\n    // FIXME: how does it belong to XMPP ? - it's detected by the PeerConnection\n    // suspending detected\n    SUSPEND_DETECTED = 'xmpp.suspend_detected',\n\n    /**\n     * Notifies for transcription status changes. The event provides the\n     * following parameters to its listeners:\n     *\n     * @param {String} status - The new status.\n     */\n    TRANSCRIPTION_STATUS_CHANGED = 'xmpp.transcription_status_changed',\n\n    /**\n     * Event fired when 'transport-info' with new ICE candidates is received.\n     */\n    TRANSPORT_INFO = 'xmpp.transportinfo.jingle',\n\n    /**\n     * Indicates that video SIP GW state changed.\n     *\n     * @param {VideoSIPGWStatusConstants} status - Any of the following statuses:\n     * STATUS_BUSY, STATUS_AVAILABLE or STATUS_UNDEFINED.\n     */\n    VIDEO_SIP_GW_AVAILABILITY_CHANGED = 'xmpp.videoSIPGWAvailabilityChanged',\n\n    /**\n     * Indicates that video SIP GW Session state changed.\n     * The statuses are any of the following statuses:\n     * STATE_ON, STATE_OFF, STATE_PENDING, STATE_RETRYING, STATE_FAILED.\n     * {@see VideoSIPGWStateConstants}\n     *\n     * @param {options} event - {address, oldState, newState, displayName}.\n     */\n    VIDEO_SIP_GW_SESSION_STATE_CHANGED = 'xmpp.videoSIPGWSessionStateChanged',\n\n    // Designates an event indicating that the local ICE connection state has\n    // changed.\n    ICE_CONNECTION_STATE_CHANGED = 'xmpp.ice_connection_state_changed',\n\n    /**\n     * Event which is emitted when the body in an XMPP message in the MUC\n     * contains JSON\n     * TODO: this event contains a typo (xmmp vs xmpp) but it's unlikely this can be changed now\n     */\n    JSON_MESSAGE_RECEIVED = 'xmmp.json_message_received'\n};\n","/**\n * The errors for the conference.\n */\n\nexport enum JitsiConferenceErrors {\n    /**\n     * Indicates that client must be authenticated to create the conference.\n     */\n    AUTHENTICATION_REQUIRED = 'conference.authenticationRequired',\n\n    /**\n     * Indicates that chat error occurred.\n     */\n    CHAT_ERROR = 'conference.chatError',\n\n    /**\n     * Indicates that a settings error occurred.\n     */\n    SETTINGS_ERROR = 'conference.settingsError',\n\n    /**\n     * Indicates that conference has been destroyed.\n     */\n    CONFERENCE_DESTROYED = 'conference.destroyed',\n\n    /**\n     * Indicates that max users limit has been reached.\n     */\n    CONFERENCE_MAX_USERS = 'conference.max_users',\n\n    /**\n     * Indicates that a connection error occurred when trying to join a conference.\n     */\n    CONNECTION_ERROR = 'conference.connectionError',\n\n    /**\n     * Indicates that the client has been forced to restart by jicofo when the\n     * conference was migrated from one bridge to another.\n     */\n    CONFERENCE_RESTARTED = 'conference.restarted',\n\n    /**\n     * Indicates that a connection error is due to not allowed,\n     * occurred when trying to join a conference.\n     */\n    NOT_ALLOWED_ERROR = 'conference.connectionError.notAllowed',\n\n    /**\n     * Indicates that a connection error is due to not allowed,\n     * occurred when trying to join a conference, only approved members are allowed to join.\n     */\n    MEMBERS_ONLY_ERROR = 'conference.connectionError.membersOnly',\n\n    /**\n     * Indicates that a connection error is due to denied access to the room,\n     * occurred after joining a lobby room and access is denied by the room moderators.\n     */\n    CONFERENCE_ACCESS_DENIED = 'conference.connectionError.accessDenied',\n\n    /**\n     * Indicates that focus error happened.\n     */\n    FOCUS_DISCONNECTED = 'conference.focusDisconnected',\n\n    /**\n     * Indicates that focus left the conference.\n     */\n    FOCUS_LEFT = 'conference.focusLeft',\n\n    /**\n     * Indicates that graceful shutdown happened.\n     */\n    GRACEFUL_SHUTDOWN = 'conference.gracefulShutdown',\n\n    /**\n     * Indicates that the media connection has failed.\n     */\n    ICE_FAILED = 'conference.iceFailed',\n\n    /**\n     * Indicates that the versions of the server side components are incompatible\n     * with the client side.\n     */\n    INCOMPATIBLE_SERVER_VERSIONS = 'conference.incompatible_server_versions',\n\n    /**\n     * Indicates that offer/answer had failed.\n     */\n    OFFER_ANSWER_FAILED = 'conference.offerAnswerFailed',\n\n    /**\n     * Indicates that password cannot be set for this conference.\n     */\n    PASSWORD_NOT_SUPPORTED = 'conference.passwordNotSupported',\n\n    /**\n     * Indicates that a password is required in order to join the conference.\n     */\n    PASSWORD_REQUIRED = 'conference.passwordRequired',\n\n    /**\n     * The conference is redirected to a visitor node.\n     */\n    REDIRECTED = 'conference.redirected',\n\n    /**\n     * Indicates that reservation system returned error.\n     */\n    RESERVATION_ERROR = 'conference.reservationError',\n\n    /**\n     * Indicates that there is no available videobridge.\n     */\n    VIDEOBRIDGE_NOT_AVAILABLE = 'conference.videobridgeNotAvailable'\n};\n\n// exported for backward compatibility\nexport const AUTHENTICATION_REQUIRED = JitsiConferenceErrors.AUTHENTICATION_REQUIRED;\nexport const CHAT_ERROR = JitsiConferenceErrors.CHAT_ERROR;\nexport const SETTINGS_ERROR = JitsiConferenceErrors.SETTINGS_ERROR;\nexport const CONFERENCE_DESTROYED = JitsiConferenceErrors.CONFERENCE_DESTROYED;\nexport const CONFERENCE_MAX_USERS = JitsiConferenceErrors.CONFERENCE_MAX_USERS;\nexport const CONNECTION_ERROR = JitsiConferenceErrors.CONNECTION_ERROR;\nexport const CONFERENCE_RESTARTED = JitsiConferenceErrors.CONFERENCE_RESTARTED;\nexport const NOT_ALLOWED_ERROR = JitsiConferenceErrors.NOT_ALLOWED_ERROR;\nexport const MEMBERS_ONLY_ERROR = JitsiConferenceErrors.MEMBERS_ONLY_ERROR;\nexport const CONFERENCE_ACCESS_DENIED = JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED;\nexport const FOCUS_DISCONNECTED = JitsiConferenceErrors.FOCUS_DISCONNECTED;\nexport const FOCUS_LEFT = JitsiConferenceErrors.FOCUS_LEFT;\nexport const GRACEFUL_SHUTDOWN = JitsiConferenceErrors.GRACEFUL_SHUTDOWN;\nexport const ICE_FAILED = JitsiConferenceErrors.ICE_FAILED;\nexport const INCOMPATIBLE_SERVER_VERSIONS = JitsiConferenceErrors.INCOMPATIBLE_SERVER_VERSIONS;\nexport const OFFER_ANSWER_FAILED = JitsiConferenceErrors.OFFER_ANSWER_FAILED;\nexport const PASSWORD_NOT_SUPPORTED = JitsiConferenceErrors.PASSWORD_NOT_SUPPORTED;\nexport const PASSWORD_REQUIRED = JitsiConferenceErrors.PASSWORD_REQUIRED;\nexport const REDIRECTED = JitsiConferenceErrors.REDIRECTED;\nexport const RESERVATION_ERROR = JitsiConferenceErrors.RESERVATION_ERROR;\nexport const VIDEOBRIDGE_NOT_AVAILABLE = JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE;\n","/**\n * The events for the conference.\n */\n\nexport enum JitsiConferenceEvents {\n    /**\n     * Event indicates that the current conference audio input switched between audio\n     * input states,i.e. with or without audio input.\n     */\n    AUDIO_INPUT_STATE_CHANGE = 'conference.audio_input_state_changed',\n\n    /**\n     * Event indicates that the permission for unmuting audio has changed based on the number of audio senders in the call\n     * and the audio sender limit configured in Jicofo.\n     */\n    AUDIO_UNMUTE_PERMISSIONS_CHANGED = 'conference.audio_unmute_permissions_changed',\n\n    /**\n     * Indicates that authentication status changed.\n     */\n    AUTH_STATUS_CHANGED = 'conference.auth_status_changed',\n\n    /**\n     * Fired just before the statistics module is disposed and it's the last chance\n     * to submit some logs to the statistics service (ex. CallStats if enabled),\n     * before it's disconnected.\n     */\n    BEFORE_STATISTICS_DISPOSED = 'conference.beforeStatisticsDisposed',\n\n    /**\n     * Indicates that an error occurred.\n     */\n    CONFERENCE_ERROR = 'conference.error',\n\n    /**\n     * Indicates that conference failed.\n     */\n    CONFERENCE_FAILED = 'conference.failed',\n\n    /**\n     * Indicates that conference is in progress of joining.\n     */\n    CONFERENCE_JOIN_IN_PROGRESS = 'conference.join_in_progress',\n\n    /**\n     * Indicates that conference has been joined. The event does NOT provide any\n     * parameters to its listeners.\n     */\n    CONFERENCE_JOINED = 'conference.joined',\n\n    /**\n     * Indicates that conference has been left.\n     */\n    CONFERENCE_LEFT = 'conference.left',\n\n    /**\n     * Indicates that the conference unique identifier has been set.\n     */\n    CONFERENCE_UNIQUE_ID_SET = 'conference.unique_id_set',\n\n    /**\n     * Indicates that the connection to the conference has been established\n     * XXX This is currently fired when the *ICE* connection enters 'connected'\n     * state for the first time.\n     */\n    CONNECTION_ESTABLISHED = 'conference.connectionEstablished',\n\n    /**\n     * Indicates that the connection to the conference has been interrupted for some\n     * reason.\n     * XXX This is currently fired when the *ICE* connection is interrupted.\n     */\n    CONNECTION_INTERRUPTED = 'conference.connectionInterrupted',\n\n    /**\n     * Indicates that the connection to the conference has been restored.\n     * XXX This is currently fired when the *ICE* connection is restored.\n     */\n    CONNECTION_RESTORED = 'conference.connectionRestored',\n\n    /**\n     * A connection to the video bridge's data channel has been established.\n     */\n    DATA_CHANNEL_OPENED = 'conference.dataChannelOpened',\n\n    /**\n     * A connection to the video bridge's data channel has been closed.\n     * This event is only emitted in \n     */\n    DATA_CHANNEL_CLOSED = 'conference.dataChannelClosed',\n\n    /**\n     * A user has changed it display name\n     */\n    DISPLAY_NAME_CHANGED = 'conference.displayNameChanged',\n\n    /**\n     * The dominant speaker was changed.\n     */\n    DOMINANT_SPEAKER_CHANGED = 'conference.dominantSpeaker',\n\n    /**\n     * UTC conference timestamp when first participant joined.\n     */\n    CONFERENCE_CREATED_TIMESTAMP = 'conference.createdTimestamp',\n\n    /**\n     * Indicates that DTMF support changed.\n     */\n    DTMF_SUPPORT_CHANGED = 'conference.dtmfSupportChanged',\n\n    /**\n     * Indicates that a message from another participant is received on data\n     * channel.\n     */\n    ENDPOINT_MESSAGE_RECEIVED = 'conference.endpoint_message_received',\n\n    /**\n     * Indicates that a message for the remote endpoint statistics has been received on the bridge channel.\n     */\n    ENDPOINT_STATS_RECEIVED = 'conference.endpoint_stats_received',\n\n    /**\n     * NOTE This is lib-jitsi-meet internal event and can be removed at any time !\n     *\n     * Event emitted when conference transits, between one to one and multiparty JVB\n     * conference. If the conference switches to P2P it's neither one to one nor\n     * a multiparty JVB conference, but P2P (the status argument of this event will\n     * be <tt>false</tt>).\n     *\n     * The first argument is a boolean which carries the previous value and\n     * the seconds argument is a boolean with the new status. The event is emitted\n     * only if the previous and the new values are different.\n     *\n     * @type {string}\n     */\n    JVB121_STATUS = 'conference.jvb121Status',\n\n    /**\n     * You are kicked from the conference.\n     * @param {JitsiParticipant} the participant that initiated the kick.\n     */\n    KICKED = 'conference.kicked',\n\n    /**\n     * Participant was kicked from the conference.\n     * @param {JitsiParticipant} the participant that initiated the kick.\n     * @param {JitsiParticipant} the participant that was kicked.\n     */\n    PARTICIPANT_KICKED = 'conference.participant_kicked',\n\n    /**\n     * The Last N set is changed.\n     *\n     * @param {Array<string>|null} leavingEndpointIds the ids of all the endpoints\n     * which are leaving Last N\n     * @param {Array<string>|null} enteringEndpointIds the ids of all the endpoints\n     * which are entering Last N\n     */\n    LAST_N_ENDPOINTS_CHANGED = 'conference.lastNEndpointsChanged',\n\n    /**\n     * The forwarded sources set is changed.\n     *\n     * @param {Array<string>} leavingForwardedSources the sourceNames of all the tracks which are leaving forwarded\n     * sources\n     * @param {Array<string>} enteringForwardedSources the sourceNames of all the tracks which are entering forwarded\n     * sources\n     */\n    FORWARDED_SOURCES_CHANGED = 'conference.forwardedSourcesChanged',\n\n    /**\n     * Indicates that the room has been locked or unlocked.\n     */\n    LOCK_STATE_CHANGED = 'conference.lock_state_changed',\n\n    /**\n     * Indicates that the region of the media server (jitsi-videobridge) that we\n     * are connected to changed (or was initially set).\n     * @type {string} the region.\n     */\n    SERVER_REGION_CHANGED = 'conference.server_region_changed',\n\n    /**\n     * An event(library-private) fired when a new media session is added to the conference.\n     * @type {string}\n     * @private\n     */\n    _MEDIA_SESSION_STARTED = 'conference.media_session.started',\n\n    /**\n     * An event(library-private) fired when the conference switches the currently active media session.\n     * @type {string}\n     * @private\n     */\n    _MEDIA_SESSION_ACTIVE_CHANGED = 'conference.media_session.active_changed',\n\n    /**\n     * Indicates that the conference had changed to members only enabled/disabled.\n     * The first argument of this event is a <tt>boolean</tt> which when set to\n     * <tt>true</tt> means that the conference is running in members only mode.\n     * You may need to use Lobby if supported to ask for permissions to enter the conference.\n     */\n    MEMBERS_ONLY_CHANGED = 'conference.membersOnlyChanged',\n\n    /**\n     * New text message was received.\n     */\n    MESSAGE_RECEIVED = 'conference.messageReceived',\n\n    /**\n     * Event indicates that the current selected input device has no signal\n     */\n    NO_AUDIO_INPUT = 'conference.no_audio_input',\n\n    /**\n     * Event indicates that the current microphone used by the conference is noisy.\n     */\n    NOISY_MIC = 'conference.noisy_mic',\n\n    /**\n     * Indicates that a message from the local user or from the Prosody backend\n     * was received on the data channel.\n     */\n    NON_PARTICIPANT_MESSAGE_RECEIVED = 'conference.non_participant_message_received',\n\n    /**\n     * New private text message was received.\n     */\n    PRIVATE_MESSAGE_RECEIVED = 'conference.privateMessageReceived',\n\n    /**\n     * Indicates that the features of the participant has been changed.\n     * TODO: there is a spelling mistake in this event name and associated constants\n     */\n    PARTCIPANT_FEATURES_CHANGED = 'conference.partcipant_features_changed',\n\n    /**\n     * Indicates that a the value of a specific property of a specific participant\n     * has changed.\n     */\n    PARTICIPANT_PROPERTY_CHANGED = 'conference.participant_property_changed',\n\n    /**\n     * Indicates the state of sources attached to a given remote participant has changed.\n     */\n    PARTICIPANT_SOURCE_UPDATED = 'conference.participant_source_updated',\n\n    /**\n     * Indicates that the conference has switched between JVB and P2P connections.\n     * The first argument of this event is a <tt>boolean</tt> which when set to\n     * <tt>true</tt> means that the conference is running on the P2P connection.\n     */\n    P2P_STATUS = 'conference.p2pStatus',\n\n    /**\n     * Indicates that phone number changed.\n     */\n    PHONE_NUMBER_CHANGED = 'conference.phoneNumberChanged',\n\n    /**\n     * The conference properties changed.\n     * @type {string}\n     */\n    PROPERTIES_CHANGED = 'conference.propertiesChanged',\n\n    /**\n     * Indicates that recording state changed.\n     */\n    RECORDER_STATE_CHANGED = 'conference.recorderStateChanged',\n\n    /**\n     * Indicates that video SIP GW state changed.\n     * @param {VideoSIPGWConstants} status.\n     */\n    VIDEO_SIP_GW_AVAILABILITY_CHANGED = 'conference.videoSIPGWAvailabilityChanged',\n\n    /**\n     * Indicates that video SIP GW Session state changed.\n     * @param {options} event - {\n     *     {string} address,\n     *     {VideoSIPGWConstants} oldState,\n     *     {VideoSIPGWConstants} newState,\n     *     {string} displayName}\n     * }.\n     */\n    VIDEO_SIP_GW_SESSION_STATE_CHANGED = 'conference.videoSIPGWSessionStateChanged',\n\n    /**\n     * Indicates that start muted settings changed.\n     */\n    START_MUTED_POLICY_CHANGED = 'conference.start_muted_policy_changed',\n\n    /**\n     * Indicates that the local user has started muted.\n     */\n    STARTED_MUTED = 'conference.started_muted',\n\n    /**\n     * Indicates that subject of the conference has changed.\n     */\n    SUBJECT_CHANGED = 'conference.subjectChanged',\n\n    /**\n     * Indicates that DTMF support changed.\n     */\n    SUSPEND_DETECTED = 'conference.suspendDetected',\n\n    /**\n     * Event indicates that local user is talking while he muted himself\n     */\n    TALK_WHILE_MUTED = 'conference.talk_while_muted',\n\n    /**\n     * A new media track was added to the conference. The event provides the\n     * following parameters to its listeners:\n     *\n     * @param {JitsiTrack} track the added JitsiTrack\n     */\n    TRACK_ADDED = 'conference.trackAdded',\n\n    /**\n     * Audio levels of a media track ( attached to the conference) was changed.\n     */\n    TRACK_AUDIO_LEVEL_CHANGED = 'conference.audioLevelsChanged',\n\n    /**\n     * A media track ( attached to the conference) mute status was changed.\n     * @param {JitsiParticipant|null} the participant that initiated the mute\n     * if it is a remote mute.\n     */\n    TRACK_MUTE_CHANGED = 'conference.trackMuteChanged',\n\n    /**\n     * The media track was removed from the conference. The event provides the\n     * following parameters to its listeners:\n     *\n     * @param {JitsiTrack} track the removed JitsiTrack\n     */\n    TRACK_REMOVED = 'conference.trackRemoved',\n\n    /**\n     * The source-add for unmuting of a media track was rejected by Jicofo.\n     *\n     */\n    TRACK_UNMUTE_REJECTED = 'conference.trackUnmuteRejected',\n\n    /**\n     * Notifies for transcription status changes. The event provides the\n     * following parameters to its listeners:\n     *\n     * @param {String} status - The new status.\n     */\n    TRANSCRIPTION_STATUS_CHANGED = 'conference.transcriptionStatusChanged',\n\n    /**\n     * A new user joined the conference.\n     */\n    USER_JOINED = 'conference.userJoined',\n\n    /**\n     * A user has left the conference.\n     */\n    USER_LEFT = 'conference.userLeft',\n\n    /**\n     * User role changed.\n     */\n    USER_ROLE_CHANGED = 'conference.roleChanged',\n\n    /**\n     * User status changed.\n     */\n    USER_STATUS_CHANGED = 'conference.statusChanged',\n\n    /**\n     * Event indicates that the permission for unmuting video has changed based on the number of video senders in the call\n     * and the video sender limit configured in Jicofo.\n     */\n    VIDEO_UNMUTE_PERMISSIONS_CHANGED = 'conference.video_unmute_permissions_changed',\n\n    /**\n     * Event indicates that the bot participant type changed.\n     */\n    BOT_TYPE_CHANGED = 'conference.bot_type_changed',\n\n    /**\n     * A new user joined the lobby room.\n     */\n    LOBBY_USER_JOINED = 'conference.lobby.userJoined',\n\n    /**\n     * A user from the lobby room has been update.\n     */\n    LOBBY_USER_UPDATED = 'conference.lobby.userUpdated',\n\n    /**\n     * A user left the lobby room.\n     */\n    LOBBY_USER_LEFT = 'conference.lobby.userLeft',\n\n    /**\n     * The local participant was approved to be able to unmute.\n     * @param {options} event - {\n     *     {MediaType} mediaType\n     * }.\n     */\n    AV_MODERATION_APPROVED = 'conference.av_moderation.approved',\n\n    /**\n     * The local participant was blocked to be able to unmute.\n     * @param {options} event - {\n     *     {MediaType} mediaType\n     * }.\n     */\n    AV_MODERATION_REJECTED = 'conference.av_moderation.rejected',\n\n    /**\n     * AV Moderation was enabled/disabled. The actor is the participant that is currently in the meeting,\n     * or undefined if that participant has left the meeting.\n     *\n     * @param {options} event - {\n     *     {boolean} enabled,\n     *     {MediaType} mediaType,\n     *     {JitsiParticipant} actor\n     * }.\n     */\n    AV_MODERATION_CHANGED = 'conference.av_moderation.changed',\n\n    /**\n     * AV Moderation, report for user being approved to unmute.\n     * @param {options} event - {\n     *     {JitsiParticipant} participant,\n     *     {MediaType} mediaType\n     * }.\n     */\n    AV_MODERATION_PARTICIPANT_APPROVED = 'conference.av_moderation.participant.approved',\n\n    /**\n     * AV Moderation, report for user being blocked to unmute.\n     * @param {options} event - {\n     *     {JitsiParticipant} participant,\n     *     {MediaType} mediaType\n     * }.\n     */\n    AV_MODERATION_PARTICIPANT_REJECTED = 'conference.av_moderation.participant.rejected',\n\n    /**\n     * Event fired when a participant is requested to join a given (breakout) room.\n     */\n    BREAKOUT_ROOMS_MOVE_TO_ROOM = 'conference.breakout-rooms.move-to-room',\n\n    /**\n     * Event fired when the breakout rooms data was updated.\n     */\n    BREAKOUT_ROOMS_UPDATED = 'conference.breakout-rooms.updated',\n\n    /**\n     * Event fired when the conference metadata is updated.\n     */\n    METADATA_UPDATED = 'conference.metadata.updated',\n\n    E2EE_VERIFICATION_AVAILABLE = 'conference.e2ee.verification.available',\n\n    E2EE_VERIFICATION_READY = 'conference.e2ee.verification.ready',\n\n    E2EE_VERIFICATION_COMPLETED = 'conference.e2ee.verification.completed'\n};\n\n// exported for backward compatibility\nexport const AUDIO_INPUT_STATE_CHANGE = JitsiConferenceEvents.AUDIO_INPUT_STATE_CHANGE;\nexport const AUDIO_UNMUTE_PERMISSIONS_CHANGED = JitsiConferenceEvents.AUDIO_UNMUTE_PERMISSIONS_CHANGED;\nexport const AUTH_STATUS_CHANGED = JitsiConferenceEvents.AUTH_STATUS_CHANGED;\nexport const BEFORE_STATISTICS_DISPOSED = JitsiConferenceEvents.BEFORE_STATISTICS_DISPOSED;\nexport const CONFERENCE_ERROR = JitsiConferenceEvents.CONFERENCE_ERROR;\nexport const CONFERENCE_FAILED = JitsiConferenceEvents.CONFERENCE_FAILED;\nexport const CONFERENCE_JOIN_IN_PROGRESS = JitsiConferenceEvents.CONFERENCE_JOIN_IN_PROGRESS;\nexport const CONFERENCE_JOINED = JitsiConferenceEvents.CONFERENCE_JOINED;\nexport const CONFERENCE_LEFT = JitsiConferenceEvents.CONFERENCE_LEFT;\nexport const CONFERENCE_UNIQUE_ID_SET = JitsiConferenceEvents.CONFERENCE_UNIQUE_ID_SET;\nexport const CONNECTION_ESTABLISHED = JitsiConferenceEvents.CONNECTION_ESTABLISHED;\nexport const CONNECTION_INTERRUPTED = JitsiConferenceEvents.CONNECTION_INTERRUPTED;\nexport const CONNECTION_RESTORED = JitsiConferenceEvents.CONNECTION_RESTORED;\nexport const DATA_CHANNEL_OPENED = JitsiConferenceEvents.DATA_CHANNEL_OPENED;\nexport const DATA_CHANNEL_CLOSED = JitsiConferenceEvents.DATA_CHANNEL_CLOSED;\nexport const DISPLAY_NAME_CHANGED = JitsiConferenceEvents.DISPLAY_NAME_CHANGED;\nexport const DOMINANT_SPEAKER_CHANGED = JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED;\nexport const CONFERENCE_CREATED_TIMESTAMP = JitsiConferenceEvents.CONFERENCE_CREATED_TIMESTAMP;\nexport const DTMF_SUPPORT_CHANGED = JitsiConferenceEvents.DTMF_SUPPORT_CHANGED;\nexport const ENDPOINT_MESSAGE_RECEIVED = JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED;\nexport const ENDPOINT_STATS_RECEIVED = JitsiConferenceEvents.ENDPOINT_STATS_RECEIVED;\nexport const E2EE_VERIFICATION_AVAILABLE = JitsiConferenceEvents.E2EE_VERIFICATION_AVAILABLE;\nexport const E2EE_VERIFICATION_READY = JitsiConferenceEvents.E2EE_VERIFICATION_READY;\nexport const E2EE_VERIFICATION_COMPLETED = JitsiConferenceEvents.E2EE_VERIFICATION_COMPLETED;\nexport const JVB121_STATUS = JitsiConferenceEvents.JVB121_STATUS;\nexport const KICKED = JitsiConferenceEvents.KICKED;\nexport const PARTICIPANT_KICKED = JitsiConferenceEvents.PARTICIPANT_KICKED;\nexport const PARTICIPANT_SOURCE_UPDATED = JitsiConferenceEvents.PARTICIPANT_SOURCE_UPDATED;\nexport const LAST_N_ENDPOINTS_CHANGED = JitsiConferenceEvents.LAST_N_ENDPOINTS_CHANGED;\nexport const FORWARDED_SOURCES_CHANGED = JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED;\nexport const LOCK_STATE_CHANGED = JitsiConferenceEvents.LOCK_STATE_CHANGED;\nexport const SERVER_REGION_CHANGED = JitsiConferenceEvents.SERVER_REGION_CHANGED;\nexport const _MEDIA_SESSION_STARTED = JitsiConferenceEvents._MEDIA_SESSION_STARTED;\nexport const _MEDIA_SESSION_ACTIVE_CHANGED = JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED;\nexport const MEMBERS_ONLY_CHANGED = JitsiConferenceEvents.MEMBERS_ONLY_CHANGED;\nexport const MESSAGE_RECEIVED = JitsiConferenceEvents.MESSAGE_RECEIVED;\nexport const NO_AUDIO_INPUT = JitsiConferenceEvents.NO_AUDIO_INPUT;\nexport const NOISY_MIC = JitsiConferenceEvents.NOISY_MIC;\nexport const NON_PARTICIPANT_MESSAGE_RECEIVED = JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED;\nexport const PRIVATE_MESSAGE_RECEIVED = JitsiConferenceEvents.PRIVATE_MESSAGE_RECEIVED;\nexport const PARTCIPANT_FEATURES_CHANGED = JitsiConferenceEvents.PARTCIPANT_FEATURES_CHANGED;\nexport const PARTICIPANT_PROPERTY_CHANGED = JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED;\nexport const P2P_STATUS = JitsiConferenceEvents.P2P_STATUS;\nexport const PHONE_NUMBER_CHANGED = JitsiConferenceEvents.PHONE_NUMBER_CHANGED;\nexport const PROPERTIES_CHANGED = JitsiConferenceEvents.PROPERTIES_CHANGED;\nexport const RECORDER_STATE_CHANGED = JitsiConferenceEvents.RECORDER_STATE_CHANGED;\nexport const VIDEO_SIP_GW_AVAILABILITY_CHANGED = JitsiConferenceEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED;\nexport const VIDEO_SIP_GW_SESSION_STATE_CHANGED = JitsiConferenceEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED;\nexport const START_MUTED_POLICY_CHANGED = JitsiConferenceEvents.START_MUTED_POLICY_CHANGED;\nexport const STARTED_MUTED = JitsiConferenceEvents.STARTED_MUTED;\nexport const SUBJECT_CHANGED = JitsiConferenceEvents.SUBJECT_CHANGED;\nexport const SUSPEND_DETECTED = JitsiConferenceEvents.SUSPEND_DETECTED;\nexport const TALK_WHILE_MUTED = JitsiConferenceEvents.TALK_WHILE_MUTED;\nexport const TRACK_ADDED = JitsiConferenceEvents.TRACK_ADDED;\nexport const TRACK_AUDIO_LEVEL_CHANGED = JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED;\nexport const TRACK_MUTE_CHANGED = JitsiConferenceEvents.TRACK_MUTE_CHANGED;\nexport const TRACK_REMOVED = JitsiConferenceEvents.TRACK_REMOVED;\nexport const TRACK_UNMUTE_REJECTED = JitsiConferenceEvents.TRACK_UNMUTE_REJECTED;\nexport const TRANSCRIPTION_STATUS_CHANGED = JitsiConferenceEvents.TRANSCRIPTION_STATUS_CHANGED;\nexport const USER_JOINED = JitsiConferenceEvents.USER_JOINED;\nexport const USER_LEFT = JitsiConferenceEvents.USER_LEFT;\nexport const USER_ROLE_CHANGED = JitsiConferenceEvents.USER_ROLE_CHANGED;\nexport const USER_STATUS_CHANGED = JitsiConferenceEvents.USER_STATUS_CHANGED;\nexport const VIDEO_UNMUTE_PERMISSIONS_CHANGED = JitsiConferenceEvents.VIDEO_UNMUTE_PERMISSIONS_CHANGED;\nexport const BOT_TYPE_CHANGED = JitsiConferenceEvents.BOT_TYPE_CHANGED;\nexport const LOBBY_USER_JOINED = JitsiConferenceEvents.LOBBY_USER_JOINED;\nexport const LOBBY_USER_UPDATED = JitsiConferenceEvents.LOBBY_USER_UPDATED;\nexport const LOBBY_USER_LEFT = JitsiConferenceEvents.LOBBY_USER_LEFT;\nexport const AV_MODERATION_APPROVED = JitsiConferenceEvents.AV_MODERATION_APPROVED;\nexport const AV_MODERATION_REJECTED = JitsiConferenceEvents.AV_MODERATION_REJECTED;\nexport const AV_MODERATION_CHANGED = JitsiConferenceEvents.AV_MODERATION_CHANGED;\nexport const AV_MODERATION_PARTICIPANT_APPROVED = JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_APPROVED;\nexport const AV_MODERATION_PARTICIPANT_REJECTED = JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_REJECTED;\nexport const BREAKOUT_ROOMS_MOVE_TO_ROOM = JitsiConferenceEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM;\nexport const BREAKOUT_ROOMS_UPDATED = JitsiConferenceEvents.BREAKOUT_ROOMS_UPDATED;\nexport const METADATA_UPDATED = JitsiConferenceEvents.METADATA_UPDATED;\n","export enum JitsiTrackEvents {\n    /**\n     * The media track was removed to the conference.\n     */\n    LOCAL_TRACK_STOPPED = 'track.stopped',\n\n    /**\n     * Audio levels of a this track was changed.\n     * The first argument is a number with audio level value in range [0, 1].\n     * The second argument is a <tt>TraceablePeerConnection</tt> which is the peer\n     * connection which measured the audio level (one audio track can be added\n     * to multiple peer connection at the same time). This argument is optional for\n     * local tracks for which we can measure audio level without the peer\n     * connection (the value will be <tt>undefined</tt>).\n     *\n     * NOTE The second argument should be treated as library internal and can be\n     * removed at any time.\n     */\n    TRACK_AUDIO_LEVEL_CHANGED = 'track.audioLevelsChanged',\n\n    /**\n     * The audio output of the track was changed.\n     */\n    TRACK_AUDIO_OUTPUT_CHANGED = 'track.audioOutputChanged',\n\n    /**\n     * A media track mute status was changed.\n     */\n    TRACK_MUTE_CHANGED = 'track.trackMuteChanged',\n\n    /**\n     * The video type(\"camera\" or \"desktop\") of the track was changed.\n     */\n    TRACK_VIDEOTYPE_CHANGED = 'track.videoTypeChanged',\n\n    /**\n     * Indicates that the track is not receiving any data even though we expect it\n     * to receive data (i.e. the stream is not stopped).\n     */\n    NO_DATA_FROM_SOURCE = 'track.no_data_from_source',\n\n    /**\n     * Indicates that the local audio track is not receiving any audio input from\n     * the microphone that is currently selected.\n     */\n    NO_AUDIO_INPUT = 'track.no_audio_input',\n\n    /**\n     * Event fired whenever video track's streaming changes.\n     * First argument is the sourceName of the track and the second is a string indicating if the connection is currently\n     * - active - the connection is active.\n     * - inactive - the connection is inactive, was intentionally interrupted by the bridge because of low BWE or because\n     *   of the endpoint falling out of last N.\n     * - interrupted - a network problem occurred.\n     * - restoring - the connection was inactive and is restoring now.\n     *\n     * The current status value can be obtained by calling JitsiRemoteTrack.getTrackStreamingStatus().\n     */\n    TRACK_STREAMING_STATUS_CHANGED = 'track.streaming_status_changed',\n\n    /**\n     * An SSRC has been remapped. The track is now associated with a new participant.\n     */\n    TRACK_OWNER_CHANGED = 'track.owner_changed',\n\n    /**\n     * A track is being removed. Fired when a session terminates for tracks\n     * that persist in ssrc-rewriting mode.\n     */\n    TRACK_REMOVED = 'track.removed',\n};\n\n// exported for backward compatibility\nexport const LOCAL_TRACK_STOPPED = JitsiTrackEvents.LOCAL_TRACK_STOPPED;\nexport const TRACK_AUDIO_LEVEL_CHANGED = JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED;\nexport const TRACK_AUDIO_OUTPUT_CHANGED = JitsiTrackEvents.TRACK_AUDIO_OUTPUT_CHANGED;\nexport const TRACK_MUTE_CHANGED = JitsiTrackEvents.TRACK_MUTE_CHANGED;\nexport const TRACK_VIDEOTYPE_CHANGED = JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED;\nexport const NO_DATA_FROM_SOURCE = JitsiTrackEvents.NO_DATA_FROM_SOURCE;\nexport const NO_AUDIO_INPUT = JitsiTrackEvents.NO_AUDIO_INPUT;\nexport const TRACK_STREAMING_STATUS_CHANGED = JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED;\nexport const TRACK_OWNER_CHANGED = JitsiTrackEvents.TRACK_OWNER_CHANGED;\nexport const TRACK_REMOVED = JitsiTrackEvents.TRACK_REMOVED;\n","export const CALLSTATS_SCRIPT_URL = 'https://api.callstats.io/static/callstats-ws.min.js';\n\n/**\n * The number of remote speakers for which the audio levels will be calculated using\n * RTCRtpReceiver#getSynchronizationSources. Limit the number of endpoints to save cpu on the client as this API call\n * is known to take longer to execute when there are many audio receivers.\n */\nexport const SPEAKERS_AUDIO_LEVELS = 5;\n","/**\n * The errors for the JitsiTrack objects.\n */\n\nexport enum JitsiTrackErrors {\n    /**\n     * An error which indicates that some of requested constraints in\n     * getUserMedia call were not satisfied.\n     */\n    CONSTRAINT_FAILED = 'gum.constraint_failed',\n\n    /**\n     * A generic error which indicates an error occurred while selecting\n     * a DesktopCapturerSource from the electron app.\n     */\n    ELECTRON_DESKTOP_PICKER_ERROR = 'gum.electron_desktop_picker_error',\n\n    /**\n     * An error which indicates a custom desktop picker could not be detected\n     * for the electron app.\n     */\n    ELECTRON_DESKTOP_PICKER_NOT_FOUND = 'gum.electron_desktop_picker_not_found',\n\n    /**\n     * Generic getUserMedia error.\n     */\n    GENERAL = 'gum.general',\n\n    /**\n     * An error which indicates that requested device was not found.\n     */\n    NOT_FOUND = 'gum.not_found',\n\n    /**\n     * An error which indicates that user denied permission to share requested\n     * device.\n     */\n    PERMISSION_DENIED = 'gum.permission_denied',\n\n    /**\n     * Generic error for screensharing failure.\n     */\n    SCREENSHARING_GENERIC_ERROR = 'gum.screensharing_generic_error',\n\n    /**\n     * An error which indicates that user canceled screen sharing window\n     * selection dialog.\n     */\n    SCREENSHARING_USER_CANCELED = 'gum.screensharing_user_canceled',\n\n    /**\n     * Indicates that the timeout passed to the obtainAudioAndVideoPermissions has expired without GUM resolving.\n     */\n    TIMEOUT = 'gum.timeout',\n\n    /**\n     * An error which indicates that track has been already disposed and cannot\n     * be longer used.\n     */\n    TRACK_IS_DISPOSED = 'track.track_is_disposed',\n\n    /**\n     * An error which indicates that track has no MediaStream associated.\n     */\n    TRACK_NO_STREAM_FOUND = 'track.no_stream_found',\n\n    /**\n     * An error which indicates that requested video resolution is not supported\n     * by a webcam.\n     */\n    UNSUPPORTED_RESOLUTION = 'gum.unsupported_resolution'\n}\n\n// exported for backward compatibility\nexport const CONSTRAINT_FAILED = JitsiTrackErrors.CONSTRAINT_FAILED;\nexport const ELECTRON_DESKTOP_PICKER_ERROR = JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_ERROR;\nexport const ELECTRON_DESKTOP_PICKER_NOT_FOUND = JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_NOT_FOUND;\nexport const GENERAL = JitsiTrackErrors.GENERAL;\nexport const NOT_FOUND = JitsiTrackErrors.NOT_FOUND;\nexport const PERMISSION_DENIED = JitsiTrackErrors.PERMISSION_DENIED;\nexport const SCREENSHARING_GENERIC_ERROR = JitsiTrackErrors.SCREENSHARING_GENERIC_ERROR;\nexport const SCREENSHARING_USER_CANCELED = JitsiTrackErrors.SCREENSHARING_USER_CANCELED;\nexport const TIMEOUT = JitsiTrackErrors.TIMEOUT;\nexport const TRACK_IS_DISPOSED = JitsiTrackErrors.TRACK_IS_DISPOSED;\nexport const TRACK_NO_STREAM_FOUND = JitsiTrackErrors.TRACK_NO_STREAM_FOUND;\nexport const UNSUPPORTED_RESOLUTION = JitsiTrackErrors.UNSUPPORTED_RESOLUTION;\n","import * as JitsiTrackErrors from './JitsiTrackErrors';\n\nconst TRACK_ERROR_TO_MESSAGE_MAP = {};\n\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.UNSUPPORTED_RESOLUTION]\n    = 'Video resolution is not supported: ';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.SCREENSHARING_USER_CANCELED]\n    = 'User canceled screen sharing prompt';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.SCREENSHARING_GENERIC_ERROR]\n    = 'Unknown error from screensharing';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_ERROR]\n    = 'Unkown error from desktop picker';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_NOT_FOUND]\n    = 'Failed to detect desktop picker';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.GENERAL]\n    = 'Generic getUserMedia error';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.PERMISSION_DENIED]\n    = 'User denied permission to use device(s): ';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.NOT_FOUND]\n    = 'Requested device(s) was/were not found: ';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.CONSTRAINT_FAILED]\n    = 'Constraint could not be satisfied: ';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TIMEOUT]\n    = 'Could not start media source. Timeout occured!';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_IS_DISPOSED]\n    = 'Track has been already disposed';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_NO_STREAM_FOUND]\n    = 'Track does not have an associated Media Stream';\n\n// FIXME: Using prototype inheritance because otherwise instanceof is not\n// working properly (see https://github.com/babel/babel/issues/3083)\n\n/**\n *\n * Represents an error that occurred to a JitsiTrack. Can represent various\n * types of errors. For error descriptions (@see JitsiTrackErrors).\n *\n * @extends Error\n *\n *\n * @constructor\n * @param {Object|string} error - error object or error name\n * @param {Object|string} (options) - getUserMedia constraints object or\n * error message\n * @param {('audio'|'video'|'desktop'|'screen'|'audiooutput')[]} (devices) -\n * list of getUserMedia requested devices\n */\nfunction JitsiTrackError(error, options, devices) {\n    if (typeof error === 'object' && typeof error.name !== 'undefined') {\n        /**\n         * Additional information about original getUserMedia error\n         * and constraints.\n         * @type {{\n         *     error: Object,\n         *     constraints: Object,\n         *     devices: Array.<'audio'|'video'|'desktop'|'screen'>\n         * }}\n         */\n        this.gum = {\n            error,\n            constraints: options,\n            devices: devices && Array.isArray(devices)\n                ? devices.slice(0)\n                : undefined\n        };\n\n        switch (error.name) {\n        case 'NotAllowedError':\n        case 'PermissionDeniedError':\n        case 'SecurityError':\n            this.name = JitsiTrackErrors.PERMISSION_DENIED;\n            this.message\n                = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\n                    + (this.gum.devices || []).join(', ');\n            break;\n        case 'DevicesNotFoundError':\n        case 'NotFoundError':\n            this.name = JitsiTrackErrors.NOT_FOUND;\n            this.message\n                = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\n                    + (this.gum.devices || []).join(', ');\n            break;\n        case 'ConstraintNotSatisfiedError':\n        case 'OverconstrainedError': {\n            const constraintName = error.constraintName || error.constraint;\n\n            // we treat deviceId as unsupported resolution, as we want to\n            // retry and finally if everything fails to remove deviceId from\n            // mandatory constraints\n            if (options\n                    && options.video\n                    && (!devices || devices.indexOf('video') > -1)\n                    && (constraintName === 'minWidth'\n                        || constraintName === 'maxWidth'\n                        || constraintName === 'minHeight'\n                        || constraintName === 'maxHeight'\n                        || constraintName === 'width'\n                        || constraintName === 'height'\n                        || constraintName === 'deviceId')) {\n                this.name = JitsiTrackErrors.UNSUPPORTED_RESOLUTION;\n                this.message\n                    = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\n                        + getResolutionFromFailedConstraint(\n                            constraintName,\n                            options);\n            } else {\n                this.name = JitsiTrackErrors.CONSTRAINT_FAILED;\n                this.message\n                    = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\n                        + error.constraintName;\n            }\n            break;\n        }\n\n        default:\n            this.name = JitsiTrackErrors.GENERAL;\n            this.message\n                = error.message || TRACK_ERROR_TO_MESSAGE_MAP[this.name];\n            break;\n        }\n    } else if (typeof error === 'string') {\n        if (TRACK_ERROR_TO_MESSAGE_MAP[error]) {\n            this.name = error;\n            this.message = options || TRACK_ERROR_TO_MESSAGE_MAP[error];\n        } else {\n            // this is some generic error that do not fit any of our\n            // pre-defined errors, so don't give it any specific name, just\n            // store message\n            this.message = error;\n        }\n    } else {\n        throw new Error('Invalid arguments');\n    }\n\n    this.stack = error.stack || new Error().stack;\n}\n\nJitsiTrackError.prototype = Object.create(Error.prototype);\nJitsiTrackError.prototype.constructor = JitsiTrackError;\n\n/**\n * Gets failed resolution constraint from corresponding object.\n * @param {string} failedConstraintName\n * @param {Object} constraints\n * @returns {string|number}\n */\nfunction getResolutionFromFailedConstraint(failedConstraintName, constraints) {\n    if (constraints && constraints.video && constraints.video.mandatory) {\n        switch (failedConstraintName) {\n        case 'width':\n            return constraints.video.mandatory.minWidth;\n        case 'height':\n            return constraints.video.mandatory.minHeight;\n        default:\n            return constraints.video.mandatory[failedConstraintName] || '';\n        }\n    }\n\n    return '';\n}\n\nexport default JitsiTrackError;\n","/**\n * This class exports constants and factory methods related to the analytics\n * API provided by AnalyticsAdapter. In order for entries in a database to be\n * somewhat easily traceable back to the code which produced them, events sent\n * through analytics should be defined here.\n *\n * Since the AnalyticsAdapter API can be used in different ways, for some events\n * it is more convenient to just define the event name as a constant. For other\n * events a factory function is easier.\n *\n * A general approach for adding a new event:\n * 1. Determine the event type: track, UI, page, or operational. If in doubt use\n * operational.\n * 2. Determine whether the event is related to other existing events, and\n * which fields are desired to be set: name, action, actionSubject, source.\n * 3. If the name is sufficient (the other fields are not important), use a\n * constant. Otherwise use a factory function.\n *\n * Note that the AnalyticsAdapter uses the events passed to its functions for\n * its own purposes, and might modify them. Because of this, factory functions\n * should create new objects.\n *\n */\n\nexport enum AnalyticsEvents {\n    /**\n     * The constant which identifies an event of type \"operational\".\n     */\n    TYPE_OPERATIONAL = 'operational',\n\n    /**\n     * The constant which identifies an event of type \"page\".\n     */\n    TYPE_PAGE = 'page',\n\n    /**\n     * The constant which identifies an event of type \"track\".\n     */\n    TYPE_TRACK = 'track',\n\n    /**\n     * The constant which identifies an event of type \"ui\".\n     */\n    TYPE_UI = 'ui',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that the Jingle session\n     * was restarted (TODO: verify/fix the documentation)\n     */\n    ACTION_JINGLE_RESTART = 'restart',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that a session-accept\n     * timed out (TODO: verify/fix the documentation)\n     */\n    ACTION_JINGLE_SA_TIMEOUT = 'session-accept.timeout',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that a session-initiate\n     * was received.\n     */\n    ACTION_JINGLE_SI_RECEIVED = 'session-initiate.received',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that a session-initiate\n     * not arrived within a timeout (the value is specified in\n     * the {@link JingleSessionPC}.\n     */\n    ACTION_JINGLE_SI_TIMEOUT = 'session-initiate.timeout',\n\n    /**\n     * A constant for the \"terminate\" action for Jingle events. TODO: verify/fix\n     * the documentation)\n     */\n    ACTION_JINGLE_TERMINATE = 'terminate',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that a transport-replace\n     * was received.\n     */\n    ACTION_JINGLE_TR_RECEIVED = 'transport-replace.received',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that a transport-replace\n     * succeeded (TODO: verify/fix the documentation)\n     */\n    ACTION_JINGLE_TR_SUCCESS = 'transport-replace.success',\n\n    /**\n     * The \"action\" value for P2P events which indicates that P2P session initiate message has been rejected by the client\n     * because the mandatory requirements were not met.\n     */\n    ACTION_P2P_DECLINED = 'decline',\n\n    /**\n     * The \"action\" value for P2P events which indicates that a connection was\n     * established (TODO: verify/fix the documentation)\n     */\n    ACTION_P2P_ESTABLISHED = 'established',\n\n    /**\n     * The \"action\" value for P2P events which indicates that something failed.\n     */\n    ACTION_P2P_FAILED = 'failed',\n\n    /**\n     * The \"action\" value for P2P events which indicates that a switch to\n     * jitsi-videobridge happened.\n     */\n    ACTION_P2P_SWITCH_TO_JVB = 'switch.to.jvb',\n\n    /**\n     * The name of an event which indicates an available device. We send one such\n     * event per available device once when the available devices are first known,\n     * and every time that they change\n     *\n     * Properties:\n     *      audio_input_device_count: the number of audio input devices available at\n     *          the time the event was sent.\n     *      audio_output_device_count: the number of audio output devices available\n     *          at the time the event was sent.\n     *      video_input_device_count: the number of video input devices available at\n     *          the time the event was sent.\n     *      video_output_device_count: the number of video output devices available\n     *          at the time the event was sent.\n     *      device_id: an identifier of the device described in this event.\n     *      device_group_id:\n     *      device_kind: one of 'audioinput', 'audiooutput', 'videoinput' or\n     *          'videooutput'.\n     *      device_label: a string which describes the device.\n     */\n    AVAILABLE_DEVICE = 'available.device',\n\n    /**\n     * This appears to be fired only in certain cases when the XMPP connection\n     * disconnects (and it was intentional?). It is currently never observed to\n     * fire in production.\n     *\n     * TODO: document\n     *\n     * Properties:\n     *      message: an error message\n     */\n    CONNECTION_DISCONNECTED = 'connection.disconnected',\n\n    /**\n     * Indicates that the user of the application provided feedback in terms of a\n     * rating (an integer from 1 to 5) and an optional comment.\n     * Properties:\n     *      value: the user's rating (an integer from 1 to 5)\n     *      comment: the user's comment\n     */\n    FEEDBACK = 'feedback',\n\n    /**\n     * Indicates the duration of a particular phase of the ICE connectivity\n     * establishment.\n     *\n     * Properties:\n     *      phase: the ICE phase (e.g. 'gathering', 'checking', 'establishment')\n     *      value: the duration in milliseconds.\n     *      p2p: whether the associated ICE connection is p2p or towards a\n     *          jitsi-videobridge\n     *      initiator: whether the local Jingle peer is the initiator or responder\n     *          in the Jingle session. XXX we probably actually care about the ICE\n     *          role (controlling vs controlled), and we assume that this correlates\n     *          with the Jingle initiator.\n     */\n    ICE_DURATION = 'ice.duration',\n\n    /**\n     * Indicates the difference in milliseconds between the ICE establishment time\n     * for the P2P and JVB connections (e.g. a value of 10 would indicate that the\n     * P2P connection took 10ms more than JVB connection to establish).\n     *\n     * Properties:\n     *      value: the difference in establishment durations in milliseconds.\n     *\n     */\n    ICE_ESTABLISHMENT_DURATION_DIFF = 'ice.establishment.duration.diff',\n\n    /**\n     * Indicates that the ICE state has changed.\n     *\n     * Properties:\n     *      state: the ICE state which was entered (e.g. 'checking', 'connected',\n     *          'completed', etc).\n     *      value: the time in milliseconds (as reported by\n     *          window.performance.now()) that the state change occurred.\n     *      p2p: whether the associated ICE connection is p2p or towards a\n     *          jitsi-videobridge\n     *      signalingState: The signaling state of the associated PeerConnection\n     *      reconnect: whether the associated Jingle session is in the process of\n     *          reconnecting (or is it ICE? TODO: verify/fix the documentation)\n     */\n    ICE_STATE_CHANGED = 'ice.state.changed',\n\n    /**\n     * Indicates that no bytes have been sent for the track.\n     *\n     * Properties:\n     *      mediaType: the media type of the local track ('audio' or 'video').\n     */\n    NO_BYTES_SENT = 'track.no-bytes-sent',\n\n    /**\n     * Indicates that a track was unmuted (?).\n     *\n     * Properties:\n     *      mediaType: the media type of the local track ('audio' or 'video').\n     *      trackType: the type of the track ('local' or 'remote').\n     *      value: TODO: document\n     */\n    TRACK_UNMUTED = 'track.unmuted'\n}\n\n// exported for backward compatibility\nexport const TYPE_OPERATIONAL = AnalyticsEvents.TYPE_OPERATIONAL;\nexport const TYPE_PAGE = AnalyticsEvents.TYPE_PAGE;\nexport const TYPE_TRACK = AnalyticsEvents.TYPE_TRACK;\nexport const TYPE_UI = AnalyticsEvents.TYPE_UI;\nexport const ACTION_JINGLE_RESTART = AnalyticsEvents.ACTION_JINGLE_RESTART;\nexport const ACTION_JINGLE_SA_TIMEOUT = AnalyticsEvents.ACTION_JINGLE_SA_TIMEOUT;\nexport const ACTION_JINGLE_SI_RECEIVED = AnalyticsEvents.ACTION_JINGLE_SI_RECEIVED;\nexport const ACTION_JINGLE_SI_TIMEOUT = AnalyticsEvents.ACTION_JINGLE_SI_TIMEOUT;\nexport const ACTION_JINGLE_TERMINATE = AnalyticsEvents.ACTION_JINGLE_TERMINATE;\nexport const ACTION_JINGLE_TR_RECEIVED = AnalyticsEvents.ACTION_JINGLE_TR_RECEIVED;\nexport const ACTION_JINGLE_TR_SUCCESS = AnalyticsEvents.ACTION_JINGLE_TR_SUCCESS;\nexport const ACTION_P2P_DECLINED = AnalyticsEvents.ACTION_P2P_DECLINED;\nexport const ACTION_P2P_ESTABLISHED = AnalyticsEvents.ACTION_P2P_ESTABLISHED;\nexport const ACTION_P2P_FAILED = AnalyticsEvents.ACTION_P2P_FAILED;\nexport const ACTION_P2P_SWITCH_TO_JVB = AnalyticsEvents.ACTION_P2P_SWITCH_TO_JVB;\nexport const AVAILABLE_DEVICE = AnalyticsEvents.AVAILABLE_DEVICE;\nexport const CONNECTION_DISCONNECTED = AnalyticsEvents.CONNECTION_DISCONNECTED;\nexport const FEEDBACK = AnalyticsEvents.FEEDBACK;\nexport const ICE_DURATION = AnalyticsEvents.ICE_DURATION;\nexport const ICE_ESTABLISHMENT_DURATION_DIFF = AnalyticsEvents.ICE_ESTABLISHMENT_DURATION_DIFF;\nexport const ICE_STATE_CHANGED = AnalyticsEvents.ICE_STATE_CHANGED;\nexport const NO_BYTES_SENT = AnalyticsEvents.NO_BYTES_SENT;\nexport const TRACK_UNMUTED = AnalyticsEvents.TRACK_UNMUTED;\n\n/**\n * Creates an operational event which indicates that we have received a\n * \"bridge down\" event from jicofo.\n */\nexport const createBridgeDownEvent = () => ( {\n    action: 'bridge.down',\n    actionSubject: 'bridge.down',\n    type: TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an event which indicates that the XMPP connection failed\n * @param errorType TODO\n * @param errorMessage TODO\n * @param detail connection failed details.\n */\nexport const createConnectionFailedEvent = ( errorType: unknown, errorMessage: unknown, details: object ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'connection.failed',\n    attributes: {\n        'error_type': errorType,\n        'error_message': errorMessage,\n        ...details\n    }\n} );\n\n/**\n * Creates a conference event.\n *\n * @param action - The action of the event.\n * @param attributes - The attributes to be added to the event.\n */\nexport const createConferenceEvent = ( action: string, attributes: object ) => ( {\n    action,\n    attributes,\n    source: 'conference',\n    type: AnalyticsEvents.TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an operational event which indicates that a particular connection\n * stage was reached (i.e. the XMPP connection transitioned to the \"connected\"\n * state).\n *\n * @param stage the stage which was reached\n * @param attributes additional attributes for the event. This should be an\n * object with a \"value\" property indicating a timestamp in milliseconds\n * relative to the beginning of the document's lifetime.\n *\n */\nexport const createConnectionStageReachedEvent = ( stage: unknown, attributes: object ) => ( {\n    action: 'connection.stage.reached',\n    actionSubject: stage,\n    attributes,\n    source: 'connection.stage.reached',\n    type: AnalyticsEvents.TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an operational event for the end-to-end round trip time to a\n * specific remote participant.\n * @param participantId the ID of the remote participant.\n * @param region the region of the remote participant\n * @param rtt the rtt\n */\nexport const createE2eRttEvent = ( participantId: unknown, region: unknown, rtt: unknown ) => ( {\n    attributes: {\n        'participant_id': participantId,\n        region,\n        rtt\n    },\n    name: 'e2e_rtt',\n    type: AnalyticsEvents.TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an event which indicates that the focus has left the MUC.\n */\nexport const createFocusLeftEvent = () => ( {\n    action: 'focus.left',\n    actionSubject: 'focus.left',\n    type: AnalyticsEvents.TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an event related to a getUserMedia call.\n *\n * @param action the type of the result that the event represents: 'error',\n * 'success', 'warning', etc.\n * @param attributes the attributes to attach to the event.\n */\nexport const createGetUserMediaEvent = ( action: 'error' | 'success' | 'warning' | string, attributes: object = {} ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    source: 'get.user.media',\n    action,\n    attributes\n} );\n\n/**\n * Creates an event related to remote participant connection status changes.\n *\n * @param attributes the attributes to attach to the event.\n */\nexport const createParticipantConnectionStatusEvent = ( attributes: object = {} ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    source: 'peer.conn.status',\n    action: 'duration',\n    attributes\n} );\n\n/**\n * Creates an event related to remote track streaming status changes.\n *\n * @param attributes the attributes to attach to the event.\n */\nexport const createTrackStreamingStatusEvent = ( attributes: object = {} ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    source: 'track.streaming.status',\n    action: 'duration',\n    attributes\n} );\n\n/**\n * Creates an event for a Jingle-related event.\n * @param action the action of the event\n * @param attributes attributes to add to the event.\n */\nexport const createJingleEvent = ( action: unknown, attributes: object = {} ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action,\n    source: 'jingle',\n    attributes\n} );\n\n/**\n * Creates an event which indicates that a local track was not able to read\n * data from its source (a camera or a microphone).\n *\n * @param mediaType the media type of the local track ('audio' or\n * 'video').\n */\nexport const createNoDataFromSourceEvent = ( mediaType: 'audio' | 'video' | string, value: unknown ) => ( {\n    attributes: {\n        'media_type': mediaType,\n        value\n    },\n    action: 'track.no.data.from.source',\n    type: AnalyticsEvents.TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an event for a p2p-related event.\n * @param action the action of the event\n * @param attributes attributes to add to the event.\n */\nexport const createP2PEvent = ( action: unknown, attributes: object = {} ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action,\n    source: 'p2p',\n    attributes\n} )\n\n/**\n * Indicates that we received a remote command to mute.\n */\nexport const createRemotelyMutedEvent = ( mediaType: unknown ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'remotely.muted',\n    mediaType\n} );\n\n/**\n * Creates an event which contains RTP statistics such as RTT and packet loss.\n *\n * All average RTP stats are currently reported under 1 event name, but with\n * different properties that allows to distinguish between a P2P call, a\n * call relayed through TURN or the JVB, and multiparty vs 1:1.\n *\n * The structure of the event is:\n *\n * {\n *      p2p: true,\n *      conferenceSize: 2,\n *      localCandidateType: \"relay\",\n *      remoteCandidateType: \"relay\",\n *      transportType: \"udp\",\n *\n *      // Average RTT of 200ms\n *      \"rtt.avg\": 200,\n *      \"rtt.samples\": \"[100, 200, 300]\",\n *\n *      // Average packet loss of 10%\n *      \"packet.loss.avg\": 10,\n *      \"packet.loss.samples\": '[5, 10, 15]'\n *\n *      // Difference in milliseconds in the end-to-end RTT between p2p and jvb.\n *      // The e2e RTT through jvb is 15ms shorter:\n *      \"rtt.diff\": 15,\n *\n *      // End-to-end RTT through JVB is ms.\n *      \"end2end.rtt.avg\" = 100\n * }\n *\n * Note that the value of the \"samples\" properties are (JSON encoded) strings,\n * and not JSON arrays, as events' attributes can not be nested. The samples are\n * currently included for debug purposes only and can be removed anytime soon\n * from the structure.\n *\n * Also note that not all of values are present in each event, as values are\n * obtained and calculated as part of different process/event pipe. For example\n * {@link ConnectionAvgStats} instances are doing the reports for each\n * {@link TraceablePeerConnection} and work independently from the main stats\n * pipe.\n */\nexport const createRtpStatsEvent = ( attributes: object ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'rtp.stats',\n    attributes\n} );\n\n/**\n * Creates an event which contains the round trip time (RTT) to a set of\n * regions.\n *\n * @param attributes\n */\nexport const createRttByRegionEvent = ( attributes: object ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'rtt.by.region',\n    attributes\n} );\n\n/**\n * Creates an event which contains the local and remote ICE candidate types\n * for the transport that is currently selected.\n *\n * @param attributes\n */\nexport const createTransportStatsEvent = ( attributes: object ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'transport.stats',\n    attributes\n} );\n\n/**\n * Creates an event which contains information about the audio output problem (the user id of the affected participant,\n * the local audio levels and the remote audio levels that triggered the event).\n *\n * @param userID - The user id of the affected participant.\n * @param localAudioLevels - The local audio levels.\n * @param remoteAudioLevels - The audio levels received from the participant.\n */\nexport const createAudioOutputProblemEvent = ( userID: string, localAudioLevels: unknown, remoteAudioLevels: unknown ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'audio.output.problem',\n    attributes: {\n        userID,\n        localAudioLevels,\n        remoteAudioLevels\n    }\n} );\n\n/**\n * Creates an event which contains an information related to the bridge channel close event.\n *\n * @param code - A code from {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}\n * @param reason - A string which describes the reason for closing the bridge channel.\n */\nexport const createBridgeChannelClosedEvent = ( code: string, reason: string ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'bridge-channel.error',\n    attributes: {\n        code,\n        reason\n    }\n} );\n\n/**\n * Creates an event which indicates the Time To First Media (TTFM).\n * It is measured in milliseconds relative to the beginning of the document's\n * lifetime (i.e. the origin used by window.performance.now()), and it excludes\n * the following:\n * 1. The delay due to getUserMedia()\n * 2. The period between the MUC being joined and the reception of the Jingle\n * session-initiate from jicofo. This is because jicofo will not start a Jingle\n * session until there are at least 2 participants in the room.\n *\n * @param attributes the attributes to add to the event. Currently used fields:\n *      mediaType: the media type of the local track ('audio' or 'video').\n *      muted: whether the track has ever been muted (?)\n *      value: the TTMF in milliseconds.\n */\nexport const createTtfmEvent = ( attributes: object ) => createConnectionStageReachedEvent( 'ttfm', attributes );\n","export enum Events {\n    /**\n     * Notifies about audio level in RTP statistics by SSRC.\n     *\n     * @param ssrc - The synchronization source identifier (SSRC) of the\n     * endpoint/participant whose audio level is being reported.\n     * @param {number} audioLevel - The audio level of <tt>ssrc</tt> according to\n     * RTP statistics.\n     * @param {boolean} isLocal - <tt>true</tt> if <tt>ssrc</tt> identifies the\n     * local endpoint/participant; otherwise, <tt>false</tt>.\n     */\n    AUDIO_LEVEL = 'statistics.audioLevel',\n\n    /**\n     * An event fired just before the statistics module gets disposes and it's\n     * the last chance to submit some logs that will end up in stats services like\n     * CallStats (if enabled).\n     */\n    BEFORE_DISPOSED = 'statistics.before_disposed',\n\n    /**\n     * An event carrying all statistics by ssrc.\n     */\n    BYTE_SENT_STATS = 'statistics.byte_sent_stats',\n\n    /**\n     * An event carrying connection statistics.\n     *\n     * @param {object} connectionStats - The connection statistics carried by the\n     * event such as <tt>bandwidth</tt>, <tt>bitrate</tt>, <tt>packetLoss</tt>,\n     * <tt>resolution</tt>, and <tt>transport</tt>.\n     */\n    CONNECTION_STATS = 'statistics.connectionstats',\n\n    /**\n     * An event carrying performance stats.\n     */\n    LONG_TASKS_STATS = 'statistics.long_tasks_stats'\n};\n\n// exported for backward compatibility\nexport const AUDIO_LEVEL = Events.AUDIO_LEVEL;\nexport const BEFORE_DISPOSED = Events.BEFORE_DISPOSED;\nexport const BYTE_SENT_STATS = Events.BYTE_SENT_STATS;\nexport const CONNECTION_STATS = Events.CONNECTION_STATS;\nexport const LONG_TASKS_STATS = Events.LONG_TASKS_STATS;\n","// TODO: Maybe fix the values to 'Chrome', 'Internet Explorer', etc. Currently\n// this values needs to be as they are becuse they are going to analytics,\n// callstats, etc.\n\nexport const CHROME = 'chrome';\n\nexport const OPERA = 'opera';\n\nexport const FIREFOX = 'firefox';\n\nexport const INTERNET_EXPLORER = 'iexplorer';\n\nexport const SAFARI = 'safari';\n\nexport const NWJS = 'nwjs';\n\nexport const ELECTRON = 'electron';\n\nexport const REACT_NATIVE = 'react-native';\n\nexport const UNKNOWN = 'unknown';\n","import Bowser from 'bowser';\n\nimport {\n    CHROME,\n    OPERA,\n    FIREFOX,\n    INTERNET_EXPLORER,\n    SAFARI,\n    NWJS,\n    ELECTRON,\n    REACT_NATIVE,\n    UNKNOWN\n} from './browsers.js';\n\n/**\n * Maps the names of the browsers from bowser to the internal names defined in\n * ./browsers.js\n */\nconst bowserNameToJitsiName = {\n    'Chrome': CHROME,\n    'Chromium': CHROME,\n    'Opera': OPERA,\n    'Firefox': FIREFOX,\n    'Internet Explorer': INTERNET_EXPLORER,\n    'Safari': SAFARI\n};\n\n/**\n * Detects a Chromium based environent.\n *\n * NOTE: Here we cannot check solely for \"Chrome\" in the UA, because Edge has\n * it too. We need to check explicitly for chromium based Edge first and then\n * detect other chromium based browsers.\n *\n * @returns {Object|undefined} - The name (CHROME) and version.\n */\nfunction _detectChromiumBased() {\n    const userAgent = navigator.userAgent;\n    const browserInfo = {\n        name: UNKNOWN,\n        version: undefined\n    };\n\n    if (userAgent.match(/Chrome/) && !userAgent.match(/Edge/)) {\n        // Edge is currenly supported only on desktop and android.\n        if (userAgent.match(/Edg(A?)/)) {\n            // Compare the underlying chromium version.\n            const version = userAgent.match(/Chrome\\/([\\d.]+)/)[1];\n\n            if (Number.parseInt(version, 10) > 72) {\n                browserInfo.name = CHROME;\n                browserInfo.version = version;\n            }\n        } else {\n            browserInfo.name = CHROME;\n            browserInfo.version = userAgent.match(/Chrome\\/([\\d.]+)/)[1];\n        }\n    }\n\n    return browserInfo;\n}\n\n/**\n * Detects Electron environment.\n *\n * @returns {Object|undefined} - The name (ELECTRON) and version.\n */\nfunction _detectElectron() {\n    const userAgent = navigator.userAgent;\n\n    if (userAgent.match(/Electron/)) {\n        const version = userAgent.match(/Electron(?:\\s|\\/)([\\d.]+)/)[1];\n\n        return {\n            name: ELECTRON,\n            version\n        };\n    } else if (typeof window.JitsiMeetElectron !== 'undefined') {\n        return {\n            name: ELECTRON,\n            version: undefined\n        };\n    }\n}\n\n/**\n * Detects NWJS environment.\n *\n * @returns {Object|undefined} - The name (NWJS) and version.\n */\nfunction _detectNWJS() {\n    const userAgent = navigator.userAgent;\n\n    if (userAgent.match(/JitsiMeetNW/)) {\n        const version = userAgent.match(/JitsiMeetNW\\/([\\d.]+)/)[1];\n\n        return {\n            name: NWJS,\n            version\n        };\n    }\n}\n\n/**\n * Detects React Native environment.\n * @returns {Object|undefined} - The name (REACT_NATIVE) and version.\n */\nfunction _detectReactNative() {\n    const match\n        = navigator.userAgent.match(/\\b(react[ \\t_-]*native)(?:\\/(\\S+))?/i);\n    let version;\n\n    // If we're remote debugging a React Native app, it may be treated as\n    // Chrome. Check navigator.product as well and always return some version\n    // even if we can't get the real one.\n\n    if (match || navigator.product === 'ReactNative') {\n        let name;\n\n        if (match && match.length > 2) {\n            name = match[1];\n            version = match[2];\n        }\n        name || (name = 'react-native');\n        version || (version = 'unknown');\n\n        return {\n            name: REACT_NATIVE,\n            version\n        };\n    }\n}\n\n/**\n * Returns information about the current browser.\n * @param {Object} - The bowser instance.\n * @returns {Object} - The name and version of the browser.\n */\nfunction _detect(bowser) {\n    let browserInfo;\n    const detectors = [\n        _detectReactNative,\n        _detectElectron,\n        _detectNWJS\n    ];\n\n    // Try all browser detectors\n    for (let i = 0; i < detectors.length; i++) {\n        browserInfo = detectors[i]();\n        if (browserInfo) {\n            return browserInfo;\n        }\n    }\n\n    const name = bowser.getBrowserName();\n\n    if (name in bowserNameToJitsiName) {\n        return {\n            name: bowserNameToJitsiName[name],\n            version: bowser.getBrowserVersion()\n        };\n    }\n\n    // Detect other browsers with the Chrome engine, such as Vivaldi and Brave.\n    browserInfo = _detectChromiumBased();\n    if (browserInfo) {\n        return browserInfo;\n    }\n\n    return {\n        name: UNKNOWN,\n        version: undefined\n    };\n}\n\n/**\n * Implements browser detection.\n */\nexport default class BrowserDetection {\n    /**\n     * Creates new BrowserDetection instance.\n     *\n     * @param {Object} [browserInfo] - Information about the browser.\n     * @param {string} browserInfo.name - The name of the browser.\n     * @param {string} browserInfo.version - The version of the browser.\n     */\n    constructor(browserInfo) {\n        let name, version;\n\n        this._bowser = Bowser.getParser(navigator.userAgent);\n        if (typeof browserInfo === 'undefined') {\n            const detectedBrowserInfo = _detect(this._bowser);\n\n            name = detectedBrowserInfo.name;\n            version = detectedBrowserInfo.version;\n        } else if (browserInfo.name in bowserNameToJitsiName) {\n            name = bowserNameToJitsiName[browserInfo.name];\n            version = browserInfo.version;\n        } else {\n            name = UNKNOWN;\n            version = undefined;\n        }\n\n        this._name = name;\n        this._version = version;\n    }\n\n    /**\n     * Gets current browser name.\n     * @returns {string}\n     */\n    getName() {\n        return this._name;\n    }\n\n    /**\n     * Checks if current browser is Chrome.\n     * @returns {boolean}\n     */\n    isChrome() {\n        return this._name === CHROME;\n    }\n\n    /**\n     * Checks if current browser is Opera.\n     * @returns {boolean}\n     */\n    isOpera() {\n        return this._name === OPERA;\n    }\n\n    /**\n     * Checks if current browser is Firefox.\n     * @returns {boolean}\n     */\n    isFirefox() {\n        return this._name === FIREFOX;\n    }\n\n    /**\n     * Checks if current browser is Internet Explorer.\n     * @returns {boolean}\n     */\n    isIExplorer() {\n        return this._name === INTERNET_EXPLORER;\n    }\n\n    /**\n     * Checks if current browser is Safari.\n     * @returns {boolean}\n     */\n    isSafari() {\n        return this._name === SAFARI;\n    }\n\n    /**\n     * Checks if current environment is NWJS.\n     * @returns {boolean}\n     */\n    isNWJS() {\n        return this._name === NWJS;\n    }\n\n    /**\n     * Checks if current environment is Electron.\n     * @returns {boolean}\n     */\n    isElectron() {\n        return this._name === ELECTRON;\n    }\n\n    /**\n     * Checks if current environment is React Native.\n     * @returns {boolean}\n     */\n    isReactNative() {\n        return this._name === REACT_NATIVE;\n    }\n\n    /**\n     * Returns the version of the current browser.\n     * @returns {string}\n     */\n    getVersion() {\n        return this._version;\n    }\n\n    /**\n     * Check if the parsed browser matches the passed condition.\n     *\n     * @param {Object} checkTree - It's one or two layered object, which can include a\n     * platform or an OS on the first layer and should have browsers specs on the\n     * bottom layer.\n     * Eg. { chrome: '>71.1.0' }\n     *     { windows: { chrome: '<70.2' } }\n     * @returns {boolean | undefined} - Returns true if the browser satisfies the set\n     * conditions, false if not and undefined when the browser is not defined in the\n     * checktree object or when the current browser's version is unknown.\n     * @private\n     */\n    _checkCondition(checkTree) {\n        if (this._version) {\n            return this._bowser.satisfies(checkTree);\n        }\n    }\n\n    /**\n     * Compares the passed version with the current browser version.\n     *\n     * @param {*} version - The version to compare with. Anything different\n     * than string will be converted to string.\n     * @returns {boolean|undefined} - Returns true if the current version is\n     * greater than the passed version and false otherwise. Returns undefined if\n     * the current browser version is unknown.\n     */\n    isVersionGreaterThan(version) {\n        return this._checkCondition({ [this._name]: `>${version}` });\n    }\n\n    /**\n     * Compares the passed version with the current browser version.\n     *\n     * @param {*} version - The version to compare with. Anything different\n     * than string will be converted to string.\n     * @returns {boolean|undefined} - Returns true if the current version is\n     * lower than the passed version and false otherwise. Returns undefined if\n     * the current browser version is unknown.\n     */\n    isVersionLessThan(version) {\n        return this._checkCondition({ [this._name]: `<${version}` });\n    }\n\n    /**\n     * Compares the passed version with the current browser version.\n     *\n     * @param {*} version - The version to compare with. Anything different\n     * than string will be converted to string.\n     * @returns {boolean|undefined} - Returns true if the current version is\n     * equal to the passed version and false otherwise. Returns undefined if\n     * the current browser version is unknown.\n     * A loose-equality operator is used here so that it matches the sub-versions as well.\n     */\n    isVersionEqualTo(version) {\n        return this._checkCondition({ [this._name]: `~${version}` });\n    }\n}\n","import EventEmitter from 'events';\n\n/**\n * Dummy implementation of Storage interface.\n */\nclass DummyLocalStorage extends EventEmitter {\n\n    /**\n     * The object used for storage.\n     */\n    _storage = {};\n\n    /**\n     * Empties all keys out of the storage.\n     *\n     * @returns {void}\n     */\n    clear() {\n        this._storage = {};\n    }\n\n    /**\n     * Returns the number of data items stored in the Storage object.\n     *\n     * @returns {number} - The number of data items stored in the Storage object.\n     */\n    get length() {\n        return Object.keys(this._storage).length;\n    }\n\n    /**\n     * Will return that key's value associated to the passed key name.\n     *\n     * @param {string} keyName - The key name.\n     * @returns {*} - The key value.\n     */\n    getItem(keyName) {\n        return this._storage[keyName];\n    }\n\n    /**\n     * When passed a key name and value, will add that key to the storage,\n     * or update that key's value if it already exists.\n     *\n     * @param {string} keyName - The key name.\n     * @param {*} keyValue - The key value.\n     * @returns {void}\n     */\n    setItem(keyName, keyValue) {\n        this._storage[keyName] = keyValue;\n    }\n\n    /**\n     * When passed a key name, will remove that key from the storage.\n     *\n     * @param {string} keyName - The key name.\n     * @returns {void}\n     */\n    removeItem(keyName) {\n        delete this._storage[keyName];\n    }\n\n    /**\n     * When passed a number n, this method will return the name of the nth key in the storage.\n     *\n     * @param {number} idx - The index of the key.\n     * @returns {string} - The nth key name.\n     */\n    key(n) {\n        const keys = Object.keys(this._storage);\n\n        if (keys.length <= n) {\n            return undefined;\n        }\n\n        return keys[n];\n    }\n\n    /**\n     * Serializes the content of the storage.\n     *\n     * @returns {string} - The serialized content.\n     */\n    serialize() {\n        return JSON.stringify(this._storage);\n    }\n}\n\n/**\n * Wrapper class for browser's local storage object.\n */\nclass JitsiLocalStorage extends EventEmitter {\n    /**\n     * @constructor\n     * @param {Storage} storage browser's local storage object.\n     */\n    constructor() {\n        super();\n\n        try {\n            this._storage = window.localStorage;\n            this._localStorageDisabled = false;\n        } catch (ignore) {\n            // localStorage throws an exception.\n        }\n\n        if (!this._storage) { // Handles the case when window.localStorage is undefined or throws an exception.\n            console.warn('Local storage is disabled.');\n            this._storage = new DummyLocalStorage();\n            this._localStorageDisabled = true;\n        }\n    }\n\n    /**\n     * Returns true if window.localStorage is disabled and false otherwise.\n     *\n     * @returns {boolean} - True if window.localStorage is disabled and false otherwise.\n     */\n    isLocalStorageDisabled() {\n        return this._localStorageDisabled;\n    }\n\n    /**\n     * Empties all keys out of the storage.\n     *\n     * @returns {void}\n     */\n    clear() {\n        this._storage.clear();\n        this.emit('changed');\n    }\n\n    /**\n     * Returns the number of data items stored in the Storage object.\n     *\n     * @returns {number} - The number of data items stored in the Storage object.\n     */\n    get length() {\n        return this._storage.length;\n    }\n\n    /**\n     * Returns that passed key's value.\n     * @param {string} keyName the name of the key you want to retrieve\n     * the value of.\n     * @returns {String|null} the value of the key. If the key does not exist,\n     * null is returned.\n     */\n    getItem(keyName) {\n        return this._storage.getItem(keyName);\n    }\n\n    /**\n     * Adds a key to the storage, or update key's value if it already exists.\n     * @param {string} keyName - the name of the key you want to create/update.\n     * @param {string} keyValue - the value you want to give the key you are\n     * creating/updating.\n     * @param {boolean} dontEmitChangedEvent - If true a changed event won't be emitted.\n     */\n    setItem(keyName, keyValue, dontEmitChangedEvent = false) {\n        this._storage.setItem(keyName, keyValue);\n\n        if (!dontEmitChangedEvent) {\n            this.emit('changed');\n        }\n    }\n\n    /**\n     * Remove a key from the storage.\n     * @param {string} keyName the name of the key you want to remove.\n     */\n    removeItem(keyName) {\n        this._storage.removeItem(keyName);\n        this.emit('changed');\n    }\n\n    /**\n     * Returns the name of the nth key in the list, or null if n is greater\n     * than or equal to the number of key/value pairs in the object.\n     *\n     * @param {number} i - The index of the key in the list.\n     * @returns {string}\n     */\n    key(i) {\n        return this._storage.key(i);\n    }\n\n    /**\n     * Serializes the content of the storage.\n     *\n     * @returns {string} - The serialized content.\n     */\n    serialize() {\n        if (this.isLocalStorageDisabled()) {\n            return this._storage.serialize();\n        }\n\n        const length = this._storage.length;\n        const localStorageContent = {};\n\n        for (let i = 0; i < length; i++) {\n            const key = this._storage.key(i);\n\n            localStorageContent[key] = this._storage.getItem(key);\n        }\n\n        return JSON.stringify(localStorageContent);\n    }\n}\n\nexport const jitsiLocalStorage = new JitsiLocalStorage();\n","import { BrowserDetection } from '@jitsi/js-utils';\nimport { getLogger } from '@jitsi/logger';\n\nconst logger = getLogger(__filename);\n\n/* Minimum required Chrome / Chromium version. This applies also to derivatives. */\nconst MIN_REQUIRED_CHROME_VERSION = 72;\nconst MIN_REQUIRED_SAFARI_VERSION = 14;\nconst MIN_REQUIRED_IOS_VERSION = 14;\n\n// TODO: Move this code to js-utils.\n\n// NOTE: Now we are extending BrowserDetection in order to preserve\n// RTCBrowserType interface but maybe it worth exporting BrowserCapabilities\n// and BrowserDetection as separate objects in future.\n\n/**\n * Implements browser capabilities for lib-jitsi-meet.\n */\nexport default class BrowserCapabilities extends BrowserDetection {\n    /**\n     * Creates new BrowserCapabilities instance.\n     */\n    constructor() {\n        super();\n        logger.info(`This appears to be ${this.getName()}, ver: ${this.getVersion()}`);\n    }\n\n    /**\n     * Tells whether or not the <tt>MediaStream/tt> is removed from the <tt>PeerConnection</tt> and disposed on video\n     * mute (in order to turn off the camera device). This is needed on Firefox because of the following bug\n     * https://bugzilla.mozilla.org/show_bug.cgi?id=1735951\n     *\n     * @return {boolean} <tt>true</tt> if the current browser supports this strategy or <tt>false</tt> otherwise.\n     */\n    doesVideoMuteByStreamRemove() {\n        return this.isChromiumBased() || this.isWebKitBased() || this.isFirefox();\n    }\n\n    /**\n     * Checks if the current browser is Chromium based, i.e., it's either Chrome / Chromium or uses it as its engine,\n     * but doesn't identify as Chrome.\n     *\n     * This includes the following browsers:\n     * - Chrome and Chromium.\n     * - Other browsers which use the Chrome engine, but are detected as Chrome, such as Brave and Vivaldi.\n     * - Browsers which are NOT Chrome but use it as their engine, and have custom detection code: Opera, Electron\n     *   and NW.JS.\n     * This excludes\n     * - Chrome on iOS since it uses WKWebView.\n     */\n    isChromiumBased() {\n        return (this.isChrome()\n            || this.isElectron()\n            || this.isNWJS()\n            || this.isOpera())\n            && !this.isWebKitBased();\n    }\n\n    /**\n     * Checks if the current platform is iOS.\n     *\n     * @returns {boolean}\n     */\n    isIosBrowser() {\n        const { userAgent, maxTouchPoints, platform } = navigator;\n\n        return Boolean(userAgent.match(/iP(ad|hone|od)/i))\n            || (maxTouchPoints && maxTouchPoints > 2 && /MacIntel/.test(platform));\n    }\n\n    /**\n     * Checks if the current browser is WebKit based. It's either\n     * Safari or uses WebKit as its engine.\n     *\n     * This includes Chrome and Firefox on iOS\n     *\n     * @returns {boolean}\n     */\n    isWebKitBased() {\n        // https://trac.webkit.org/changeset/236144/webkit/trunk/LayoutTests/webrtc/video-addLegacyTransceiver.html\n        return this._bowser.isEngine('webkit')\n            && typeof navigator.mediaDevices !== 'undefined'\n            && typeof navigator.mediaDevices.getUserMedia !== 'undefined'\n            && typeof window.RTCRtpTransceiver !== 'undefined'\n            // eslint-disable-next-line no-undef\n            && Object.keys(RTCRtpTransceiver.prototype).indexOf('currentDirection') > -1;\n    }\n\n    /**\n     * Checks whether current running context is a Trusted Web Application.\n     *\n     * @returns {boolean} Whether the current context is a TWA.\n     */\n    isTwa() {\n        return 'matchMedia' in window && window.matchMedia('(display-mode:standalone)').matches;\n    }\n\n    /**\n     * Checks if the current browser is supported.\n     *\n     * @returns {boolean} true if the browser is supported, false otherwise.\n     */\n    isSupported() {\n        if (this.isSafari() && this._getSafariVersion() < MIN_REQUIRED_SAFARI_VERSION) {\n            return false;\n        }\n\n        return (this.isChromiumBased() && this._getChromiumBasedVersion() >= MIN_REQUIRED_CHROME_VERSION)\n            || this.isFirefox()\n            || this.isReactNative()\n            || this.isWebKitBased();\n    }\n\n    /**\n     * Returns whether the browser is supported for Android\n     * @returns {boolean} true if the browser is supported for Android devices\n     */\n    isSupportedAndroidBrowser() {\n        return this.isChromiumBased() || this.isFirefox();\n    }\n\n    /**\n     * Returns whether the browser is supported for iOS\n     * @returns {boolean} true if the browser is supported for iOS devices\n     */\n    isSupportedIOSBrowser() {\n        return this._getIOSVersion() >= MIN_REQUIRED_IOS_VERSION;\n    }\n\n    /**\n     * Returns whether or not the current environment needs a user interaction\n     * with the page before any unmute can occur.\n     *\n     * @returns {boolean}\n     */\n    isUserInteractionRequiredForUnmute() {\n        return this.isFirefox() && this.isVersionLessThan('68');\n    }\n\n    /**\n     * Checks if the current browser triggers 'onmute'/'onunmute' events when\n     * user's connection is interrupted and the video stops playback.\n     * @returns {*|boolean} 'true' if the event is supported or 'false'\n     * otherwise.\n     */\n    supportsVideoMuteOnConnInterrupted() {\n        return this.isChromiumBased() || this.isReactNative();\n    }\n\n    /**\n     * Checks if the current browser reports upload and download bandwidth\n     * statistics.\n     * @return {boolean}\n     */\n    supportsBandwidthStatistics() {\n        // FIXME bandwidth stats are currently not implemented for FF on our\n        // side, but not sure if not possible ?\n        return !this.isFirefox() && !this.isWebKitBased();\n    }\n\n    /**\n     * Checks if the current browser supports setting codec preferences on the transceiver.\n     * @returns {boolean}\n     */\n    supportsCodecPreferences() {\n        return Boolean(window.RTCRtpTransceiver\n            && 'setCodecPreferences' in window.RTCRtpTransceiver.prototype\n            && window.RTCRtpReceiver\n            && typeof window.RTCRtpReceiver.getCapabilities !== 'undefined')\n\n            // this is not working on Safari because of the following bug\n            // https://bugs.webkit.org/show_bug.cgi?id=215567\n            && !this.isWebKitBased();\n    }\n\n    /**\n     * Checks if the current browser support the device change event.\n     * @return {boolean}\n     */\n    supportsDeviceChangeEvent() {\n        return navigator.mediaDevices\n            && typeof navigator.mediaDevices.ondevicechange !== 'undefined'\n            && typeof navigator.mediaDevices.addEventListener !== 'undefined';\n    }\n\n    /**\n     * Checks if the current browser supports the Long Tasks API that lets us observe\n     * performance measurement events and be notified of tasks that take longer than\n     * 50ms to execute on the main thread.\n     */\n    supportsPerformanceObserver() {\n        return typeof window.PerformanceObserver !== 'undefined'\n            && PerformanceObserver.supportedEntryTypes.indexOf('longtask') > -1;\n    }\n\n    /**\n     * Checks if the current browser supports audio level stats on the receivers.\n     */\n    supportsReceiverStats() {\n        return typeof window.RTCRtpReceiver !== 'undefined'\n            && Object.keys(RTCRtpReceiver.prototype).indexOf('getSynchronizationSources') > -1;\n    }\n\n    /**\n     * Checks if the current browser reports round trip time statistics for\n     * the ICE candidate pair.\n     * @return {boolean}\n     */\n    supportsRTTStatistics() {\n        // Firefox does not seem to report RTT for ICE candidate pair:\n        // eslint-disable-next-line max-len\n        // https://www.w3.org/TR/webrtc-stats/#dom-rtcicecandidatepairstats-currentroundtriptime\n        // It does report mozRTT for RTP streams, but at the time of this\n        // writing it's value does not make sense most of the time\n        // (is reported as 1):\n        // https://bugzilla.mozilla.org/show_bug.cgi?id=1241066\n        // For Chrome and others we rely on 'googRtt'.\n        return !this.isFirefox();\n    }\n\n    /**\n     * Returns true if the browser supports track based statistics for the local video track. Otherwise,\n     * track resolution and framerate will be calculated based on the 'outbound-rtp' statistics.\n     * @returns {boolean}\n     */\n    supportsTrackBasedStats() {\n        return this.isChromiumBased() && this.isVersionLessThan(112);\n    }\n\n    /**\n     * Returns true if VP9 is supported by the client on the browser. VP9 is currently disabled on Firefox and Safari\n     * because of issues with rendering. Please check https://bugzilla.mozilla.org/show_bug.cgi?id=1492500,\n     * https://bugs.webkit.org/show_bug.cgi?id=231071 and https://bugs.webkit.org/show_bug.cgi?id=231074 for details.\n     */\n    supportsVP9() {\n        return this.isChromiumBased() || this.isReactNative();\n    }\n\n    /**\n     * Checks if the browser uses SDP munging for turning on simulcast.\n     *\n     * @returns {boolean}\n     */\n    usesSdpMungingForSimulcast() {\n        return this.isChromiumBased() || this.isReactNative() || this.isWebKitBased();\n    }\n\n    /**\n     * Checks if the browser uses RIDs/MIDs for siganling the simulcast streams\n     * to the bridge instead of the ssrcs.\n     */\n    usesRidsForSimulcast() {\n        return false;\n    }\n\n    /**\n     * Checks if the browser supports getDisplayMedia.\n     * @returns {boolean} {@code true} if the browser supports getDisplayMedia.\n     */\n    supportsGetDisplayMedia() {\n        return typeof navigator.getDisplayMedia !== 'undefined'\n            || (typeof navigator.mediaDevices !== 'undefined'\n                && typeof navigator.mediaDevices.getDisplayMedia\n                    !== 'undefined');\n    }\n\n    /**\n     * Checks if the browser supports WebRTC Encoded Transform, an alternative\n     * to insertable streams.\n     *\n     * NOTE: At the time of this writing the only browser supporting this is\n     * Safari / WebKit, behind a flag.\n     *\n     * @returns {boolean} {@code true} if the browser supports it.\n     */\n    supportsEncodedTransform() {\n        return Boolean(window.RTCRtpScriptTransform);\n    }\n\n    /**\n     * Checks if the browser supports insertable streams, needed for E2EE.\n     * @returns {boolean} {@code true} if the browser supports insertable streams.\n     */\n    supportsInsertableStreams() {\n        if (!(typeof window.RTCRtpSender !== 'undefined'\n            && window.RTCRtpSender.prototype.createEncodedStreams)) {\n            return false;\n        }\n\n        // Feature-detect transferable streams which we need to operate in a worker.\n        // See https://groups.google.com/a/chromium.org/g/blink-dev/c/1LStSgBt6AM/m/hj0odB8pCAAJ\n        const stream = new ReadableStream();\n\n        try {\n            window.postMessage(stream, '*', [ stream ]);\n\n            return true;\n        } catch {\n            return false;\n        }\n    }\n\n    /**\n     * Whether the browser supports the RED format for audio.\n     */\n    supportsAudioRed() {\n        return Boolean(window.RTCRtpSender\n            && window.RTCRtpSender.getCapabilities\n            && window.RTCRtpSender.getCapabilities('audio').codecs.some(codec => codec.mimeType === 'audio/red')\n            && window.RTCRtpReceiver\n            && window.RTCRtpReceiver.getCapabilities\n            && window.RTCRtpReceiver.getCapabilities('audio').codecs.some(codec => codec.mimeType === 'audio/red'));\n    }\n\n    /**\n     * Checks if the browser supports unified plan.\n     *\n     * @returns {boolean}\n     */\n    supportsUnifiedPlan() {\n        // We do not want to enable unified plan on Electron clients that have Chromium version < 96 because of\n        // performance and screensharing issues.\n        return !(this.isElectron() && (this._getChromiumBasedVersion() < 96));\n    }\n\n    /**\n     * Checks if the browser supports voice activity detection via the @type {VADAudioAnalyser} service.\n     *\n     * @returns {boolean}\n     */\n    supportsVADDetection() {\n        return this.isChromiumBased();\n    }\n\n    /**\n     * Check if the browser supports the RTP RTX feature (and it is usable).\n     *\n     * @returns {boolean}\n     */\n    supportsRTX() {\n        // Disable RTX on Firefox up to 96 because we prefer simulcast over RTX\n        // see https://bugzilla.mozilla.org/show_bug.cgi?id=1738504\n        return !(this.isFirefox() && this.isVersionLessThan('96'));\n    }\n\n    /**\n     * Returns the version of a Chromium based browser.\n     *\n     * @returns {Number}\n     */\n    _getChromiumBasedVersion() {\n        if (this.isChromiumBased()) {\n            // NW.JS doesn't expose the Chrome version in the UA string.\n            if (this.isNWJS()) {\n                // eslint-disable-next-line no-undef\n                return Number.parseInt(process.versions.chromium, 10);\n            }\n\n            // Here we process all browsers which use the Chrome engine but\n            // don't necessarily identify as Chrome. We cannot use the version\n            // comparing functions because the Electron, Opera and NW.JS\n            // versions are inconsequential here, as we need to know the actual\n            // Chrome engine version.\n            const ua = navigator.userAgent;\n\n            if (ua.match(/Chrome/)) {\n                const version\n                    = Number.parseInt(ua.match(/Chrome\\/([\\d.]+)/)[1], 10);\n\n                return version;\n            }\n        }\n\n        return -1;\n    }\n\n    /**\n     * Returns the version of a Safari browser.\n     *\n     * @returns {Number}\n     */\n    _getSafariVersion() {\n        if (this.isSafari()) {\n            return Number.parseInt(this.getVersion(), 10);\n        }\n\n        return -1;\n    }\n\n    /**\n     * Returns the version of an ios browser.\n     *\n     * @returns {Number}\n     */\n    _getIOSVersion() {\n        if (this.isWebKitBased()) {\n            return Number.parseInt(this.getVersion(), 10);\n        }\n\n        return -1;\n    }\n}\n","import BrowserCapabilities from './BrowserCapabilities';\n\nexport default new BrowserCapabilities();\n","import { getLogger } from '@jitsi/logger';\n\nimport {\n    TYPE_OPERATIONAL,\n    TYPE_PAGE,\n    TYPE_TRACK,\n    TYPE_UI\n} from '../../service/statistics/AnalyticsEvents';\nimport browser from '../browser';\n\nconst MAX_CACHE_SIZE = 100;\n\n// eslist-disable-line no-undef\nconst logger = getLogger(__filename);\n\n/**\n * This class provides an API to lib-jitsi-meet and its users for sending\n * analytics events. It serves as a bridge to different backend implementations\n * (\"analytics handlers\") and a cache for events attempted to be sent before\n * the analytics handlers were enabled.\n *\n * The API is designed to be an easy replacement for the previous version of\n * this adapter, and is meant to be extended with more convenience methods.\n *\n *\n * The API calls are translated to objects with the following structure, which\n * are then passed to the sendEvent(event) function of the underlying handlers:\n *\n * {\n *    type,\n *\n *    action,\n *    actionSubject,\n *    actionSubjectId,\n *    attributes,\n *    categories,\n *    containerId,\n *    containerType,\n *    name,\n *    objectId,\n *    objectType,\n *    source,\n *    tags\n * }\n *\n * The 'type' is one of 'operational', 'page', 'track' or 'ui', and some of the\n * other properties are considered required according to the type.\n *\n * For events with type 'page', the required properties are: name.\n *\n * For events with type 'operational' and 'ui', the required properties are:\n * action, actionSubject, source\n *\n * For events with type 'page', the required properties are:\n * action, actionSubject, source, containerType, containerId, objectType,\n * objectId\n */\nclass AnalyticsAdapter {\n    /**\n     * Creates new AnalyticsAdapter instance.\n     */\n    constructor() {\n        this.reset();\n    }\n\n    /**\n     * Reset the state to the initial one.\n     *\n     * @returns {void}\n     */\n    reset() {\n        /**\n         * Whether this AnalyticsAdapter has been disposed of or not. Once this\n         * is set to true, the AnalyticsAdapter is disabled and does not accept\n         * any more events, and it can not be re-enabled.\n         * @type {boolean}\n         */\n        this.disposed = false;\n\n        /**\n         * The set of handlers to which events will be sent.\n         * @type {Set<any>}\n         */\n        this.analyticsHandlers = new Set();\n\n        /**\n         * The cache of events which are not sent yet. The cache is enabled\n         * while this field is truthy, and disabled otherwise.\n         * @type {Array}\n         */\n        this.cache = [];\n\n        /**\n         * Map of properties that will be added to every event. Note that the\n         * keys will be prefixed with \"permanent.\".\n         */\n        this.permanentProperties = {};\n\n        /**\n         * The name of the conference that this AnalyticsAdapter is associated\n         * with.\n         * @type {null}\n         */\n        this.conferenceName = '';\n\n        this.addPermanentProperties({\n            'user_agent': navigator.userAgent,\n            'browser_name': browser.getName()\n        });\n    }\n\n    /**\n     * Dispose analytics. Clears all handlers.\n     */\n    dispose() {\n        logger.warn('Disposing of analytics adapter.');\n\n        if (this.analyticsHandlers && this.analyticsHandlers.size > 0) {\n            this.analyticsHandlers.forEach(handler => {\n                if (typeof handler.dispose === 'function') {\n                    handler.dispose();\n                }\n            });\n        }\n\n        this.setAnalyticsHandlers([]);\n        this.disposed = true;\n    }\n\n    /**\n     * Sets the handlers that are going to be used to send analytics. Sends any\n     * cached events.\n     * @param {Array} handlers the handlers\n     */\n    setAnalyticsHandlers(handlers) {\n        if (this.disposed) {\n            return;\n        }\n\n        this.analyticsHandlers = new Set(handlers);\n\n        this._setUserProperties();\n\n        // Note that we disable the cache even if the set of handlers is empty.\n        const cache = this.cache;\n\n        this.cache = null;\n        if (cache) {\n            cache.forEach(event => this._sendEvent(event));\n        }\n    }\n\n    /**\n     * Set the user properties to the analytics handlers.\n     *\n     * @returns {void}\n     */\n    _setUserProperties() {\n        this.analyticsHandlers.forEach(handler => {\n            try {\n                handler.setUserProperties(this.permanentProperties);\n            } catch (error) {\n                logger.warn('Error in setUserProperties method of one of the '\n                    + `analytics handlers: ${error}`);\n            }\n        });\n    }\n\n    /**\n     * Adds a set of permanent properties to this this AnalyticsAdapter.\n     * Permanent properties will be added as \"attributes\" to events sent to\n     * the underlying \"analytics handlers\", and their keys will be prefixed\n     * by \"permanent_\", i.e. adding a permanent property {key: \"value\"} will\n     * result in {\"permanent_key\": \"value\"} object to be added to the\n     * \"attributes\" field of events.\n     *\n     * @param {Object} properties the properties to add\n     */\n    addPermanentProperties(properties) {\n        this.permanentProperties = {\n            ...this.permanentProperties,\n            ...properties\n        };\n\n        this._setUserProperties();\n    }\n\n    /**\n     * Sets the name of the conference that this AnalyticsAdapter is associated\n     * with.\n     * @param name the name to set.\n     */\n    setConferenceName(name) {\n        this.conferenceName = name;\n        this.addPermanentProperties({ 'conference_name': name });\n    }\n\n    /**\n     * Sends an event with a given name and given properties. The first\n     * parameter is either a string or an object. If it is a string, it is used\n     * as the event name and the second parameter is used at the attributes to\n     * attach to the event. If it is an object, it represents the whole event,\n     * including any desired attributes, and the second parameter is ignored.\n     *\n     * @param {String|Object} eventName either a string to be used as the name\n     * of the event, or an event object. If an event object is passed, the\n     * properties parameters is ignored.\n     * @param {Object} properties the properties/attributes to attach to the\n     * event, if eventName is a string.\n     */\n    sendEvent(eventName, properties = {}) {\n        if (this.disposed) {\n            return;\n        }\n\n        let event = null;\n\n        if (typeof eventName === 'string') {\n            event = {\n                type: TYPE_OPERATIONAL,\n                action: eventName,\n                actionSubject: eventName,\n                source: eventName,\n                attributes: properties\n            };\n        } else if (typeof eventName === 'object') {\n            event = eventName;\n        }\n\n        if (!this._verifyRequiredFields(event)) {\n            logger.error(\n                `Dropping a mis-formatted event: ${JSON.stringify(event)}`);\n\n            return;\n        }\n\n        this._sendEvent(event);\n    }\n\n    /**\n     * Checks whether an event has all of the required fields set, and tries\n     * to fill in some of the missing fields with reasonable default values.\n     * Returns true if after this operation the event has all of the required\n     * fields set, and false otherwise (if some of the required fields were not\n     * set and the attempt to fill them in with a default failed).\n     *\n     * @param event the event object.\n     * @return {boolean} true if the event (after the call to this function)\n     * contains all of the required fields, and false otherwise.\n     * @private\n     */\n    _verifyRequiredFields(event) {\n        if (!event) {\n            return false;\n        }\n\n        if (!event.type) {\n            event.type = TYPE_OPERATIONAL;\n        }\n\n        const type = event.type;\n\n        if (type !== TYPE_OPERATIONAL && type !== TYPE_PAGE\n            && type !== TYPE_UI && type !== TYPE_TRACK) {\n            logger.error(`Unknown event type: ${type}`);\n\n            return false;\n        }\n\n        if (type === TYPE_PAGE) {\n            return Boolean(event.name);\n        }\n\n        // Try to set some reasonable default values in case some of the\n        // parameters required by the handler API are missing.\n        event.action = event.action || event.name || event.actionSubject;\n        event.actionSubject = event.actionSubject || event.name || event.action;\n        event.source = event.source || event.name || event.action\n            || event.actionSubject;\n\n        if (!event.action || !event.actionSubject || !event.source) {\n            logger.error(\n                'Required field missing (action, actionSubject or source)');\n\n            return false;\n        }\n\n        // Track events have additional required fields.\n        if (type === TYPE_TRACK) {\n            event.objectType = event.objectType || 'generic-object-type';\n            event.containerType = event.containerType || 'conference';\n            if (event.containerType === 'conference' && !event.containerId) {\n                event.containerId = this.conferenceName;\n            }\n\n\n            if (!event.objectType || !event.objectId\n                || !event.containerType || !event.containerId) {\n                logger.error(\n                    'Required field missing (containerId, containerType, '\n                        + 'objectId or objectType)');\n\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Saves an event to the cache, if the cache is enabled.\n     * @param event the event to save.\n     * @returns {boolean} true if the event was saved, and false otherwise (i.e.\n     * if the cache was disabled).\n     * @private\n     */\n    _maybeCacheEvent(event) {\n        if (this.cache) {\n            this.cache.push(event);\n\n            // We limit the size of the cache, in case the user fails to ever\n            // set the analytics handlers.\n            if (this.cache.length > MAX_CACHE_SIZE) {\n                this.cache.splice(0, 1);\n            }\n\n            return true;\n        }\n\n        return false;\n\n    }\n\n    /**\n     *\n     * @param event\n     * @private\n     */\n    _sendEvent(event) {\n        if (this._maybeCacheEvent(event)) {\n            // The event was consumed by the cache.\n        } else {\n            this.analyticsHandlers.forEach(handler => {\n                try {\n                    handler.sendEvent(event);\n                } catch (e) {\n                    logger.warn(`Error sending analytics event: ${e}`);\n                }\n            });\n        }\n    }\n}\n\nexport default new AnalyticsAdapter();\n","/* global callstats */\n\nimport browser from '../browser';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\n\nconst logger = require('@jitsi/logger').getLogger(__filename);\n\n/**\n * We define enumeration of wrtcFuncNames as we need them before\n * callstats is initialized to queue events.\n * @const\n * @see http://www.callstats.io/api/#enumeration-of-wrtcfuncnames\n */\nconst wrtcFuncNames = {\n    createOffer: 'createOffer',\n    createAnswer: 'createAnswer',\n    setLocalDescription: 'setLocalDescription',\n    setRemoteDescription: 'setRemoteDescription',\n    addIceCandidate: 'addIceCandidate',\n    getUserMedia: 'getUserMedia',\n    iceConnectionFailure: 'iceConnectionFailure',\n    signalingError: 'signalingError',\n    applicationLog: 'applicationLog'\n};\n\n/**\n * We define enumeration of fabricEvent as we need them before\n * callstats is initialized to queue events.\n * @const\n * @see http://www.callstats.io/api/#enumeration-of-fabricevent\n */\nconst fabricEvent = {\n    fabricHold: 'fabricHold',\n    fabricResume: 'fabricResume',\n    audioMute: 'audioMute',\n    audioUnmute: 'audioUnmute',\n    videoPause: 'videoPause',\n    videoResume: 'videoResume',\n    fabricUsageEvent: 'fabricUsageEvent',\n    fabricStats: 'fabricStats',\n    fabricTerminated: 'fabricTerminated',\n    screenShareStart: 'screenShareStart',\n    screenShareStop: 'screenShareStop',\n    dominantSpeaker: 'dominantSpeaker',\n    activeDeviceList: 'activeDeviceList'\n};\n\n/**\n * The user id to report to callstats as destination.\n * @type {string}\n */\nconst DEFAULT_REMOTE_USER = 'jitsi';\n\n/**\n * Type of pending reports, can be event or an error.\n * @type {{ERROR: string, EVENT: string}}\n */\nconst reportType = {\n    ERROR: 'error',\n    EVENT: 'event',\n    MST_WITH_USERID: 'mstWithUserID'\n};\n\n/**\n * Set of currently existing {@link CallStats} instances.\n * @type {Set<CallStats>}\n */\nlet _fabrics;\n\n/**\n * An instance of this class is a wrapper for the CallStats API fabric. A fabric\n * reports one peer connection to the CallStats backend and is allocated with\n * {@link callstats.addNewFabric}. It has a bunch of instance methods for\n * reporting various events. A fabric is considered disposed when\n * {@link CallStats.sendTerminateEvent} is executed.\n *\n * Currently only one backend instance can be created ever and it's done using\n * {@link CallStats.initBackend}. At the time of this writing there is no way to\n * explicitly shutdown the backend, but it's supposed to close it's connection\n * automatically, after all fabrics have been terminated.\n */\nexport default class CallStats {\n    /**\n     * A callback passed to {@link callstats.addNewFabric}.\n     * @param {string} error 'success' means ok\n     * @param {string} msg some more details\n     * @private\n     */\n    static _addNewFabricCallback(error, msg) {\n        if (CallStats.backend && error !== 'success') {\n            logger.error(`Monitoring status: ${error} msg: ${msg}`);\n        }\n    }\n\n    /**\n     * Callback passed to {@link callstats.initialize} (backend initialization)\n     * @param {string} error 'success' means ok\n     * @param {String} msg\n     * @private\n     */\n    static _initCallback(error, msg) {\n        logger.log(`CallStats Status: err=${error} msg=${msg}`);\n\n        // there is no lib, nothing to report to\n        if (error !== 'success') {\n            return;\n        }\n\n        CallStats.backendInitialized = true;\n\n        // I hate that\n        let atLeastOneFabric = false;\n        let defaultInstance = null;\n\n        for (const callStatsInstance of CallStats.fabrics.values()) {\n            if (!callStatsInstance.hasFabric) {\n                logger.debug('addNewFabric - initCallback');\n                if (callStatsInstance._addNewFabric()) {\n                    atLeastOneFabric = true;\n                    if (!defaultInstance) {\n                        defaultInstance = callStatsInstance;\n                    }\n                }\n            }\n        }\n\n        if (!atLeastOneFabric) {\n            return;\n        }\n\n        CallStats._emptyReportQueue(defaultInstance);\n    }\n\n    /**\n     * Empties report queue.\n     *\n     * @param {CallStats} csInstance - The callstats instance.\n     * @private\n     */\n    static _emptyReportQueue(csInstance) {\n        // There is no conference ID nor a PeerConnection available when some of\n        // the events are scheduled on the reportsQueue, so those will be\n        // reported on the first initialized fabric.\n        const defaultConfID = csInstance.confID;\n        const defaultPC = csInstance.peerconnection;\n\n        // notify callstats about failures if there were any\n        for (const report of CallStats.reportsQueue) {\n            if (report.type === reportType.ERROR) {\n                const errorData = report.data;\n\n                CallStats._reportError(\n                    csInstance,\n                    errorData.type,\n                    errorData.error,\n                    errorData.pc || defaultPC);\n            } else if (report.type === reportType.EVENT) {\n                // if we have and event to report and we failed to add\n                // fabric this event will not be reported anyway, returning\n                // an error\n                const eventData = report.data;\n\n                CallStats.backend.sendFabricEvent(\n                    report.pc || defaultPC,\n                    eventData.event,\n                    defaultConfID,\n                    eventData.eventData);\n            } else if (report.type === reportType.MST_WITH_USERID) {\n                const data = report.data;\n\n                CallStats.backend.associateMstWithUserID(\n                    report.pc || defaultPC,\n                    data.callStatsId,\n                    defaultConfID,\n                    data.ssrc,\n                    data.usageLabel,\n                    data.containerId\n                );\n            }\n        }\n        CallStats.reportsQueue.length = 0;\n    }\n\n    /* eslint-disable max-params */\n    /**\n     * Reports an error to callstats.\n     *\n     * @param {CallStats} [cs]\n     * @param type the type of the error, which will be one of the wrtcFuncNames\n     * @param error the error\n     * @param pc the peerconnection\n     * @private\n     */\n    static _reportError(cs, type, error, pc) {\n        let _error = error;\n\n        if (!_error) {\n            logger.warn('No error is passed!');\n            _error = new Error('Unknown error');\n        }\n        if (CallStats.backendInitialized && cs) {\n            CallStats.backend.reportError(pc, cs.confID, type, _error);\n        } else {\n            CallStats.reportsQueue.push({\n                type: reportType.ERROR,\n                data: {\n                    error: _error,\n                    pc,\n                    type\n                }\n            });\n        }\n\n        // else just ignore it\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Reports an error to callstats.\n     *\n     * @param {CallStats} cs\n     * @param event the type of the event, which will be one of the fabricEvent\n     * @param eventData additional data to pass to event\n     * @private\n     */\n    static _reportEvent(cs, event, eventData) {\n        const pc = cs && cs.peerconnection;\n        const confID = cs && cs.confID;\n\n        if (CallStats.backendInitialized && cs) {\n            CallStats.backend.sendFabricEvent(pc, event, confID, eventData);\n        } else {\n            CallStats.reportsQueue.push({\n                confID,\n                pc,\n                type: reportType.EVENT,\n                data: { event,\n                    eventData }\n            });\n        }\n    }\n\n    /**\n     * Wraps some of the CallStats API method and logs their calls with\n     * arguments on the debug logging level. Also wraps some of the backend\n     * methods execution into try catch blocks to not crash the app in case\n     * there is a problem with the backend itself.\n     * @param {callstats} theBackend\n     * @private\n     */\n    static _traceAndCatchBackendCalls(theBackend) {\n        const tryCatchMethods = [\n            'associateMstWithUserID',\n            'sendFabricEvent',\n            'sendUserFeedback'\n\n            // 'reportError', - this one needs special handling - see code below\n        ];\n\n        for (const methodName of tryCatchMethods) {\n            const originalMethod = theBackend[methodName];\n\n            theBackend[methodName] = function(...theArguments) {\n                try {\n                    return originalMethod.apply(theBackend, theArguments);\n                } catch (e) {\n                    GlobalOnErrorHandler.callErrorHandler(e);\n                }\n            };\n        }\n        const debugMethods = [\n            'associateMstWithUserID',\n            'sendFabricEvent',\n            'sendUserFeedback'\n\n            // 'reportError', - this one needs special handling - see code below\n        ];\n\n        for (const methodName of debugMethods) {\n            const originalMethod = theBackend[methodName];\n\n            theBackend[methodName] = function(...theArguments) {\n                logger.debug(methodName, theArguments);\n                originalMethod.apply(theBackend, theArguments);\n            };\n        }\n        const originalReportError = theBackend.reportError;\n\n        /* eslint-disable max-params */\n        theBackend.reportError = function(pc, cs, type, ...args) {\n            // Logs from the logger are submitted on the applicationLog event\n            // \"type\". Logging the arguments on the logger will create endless\n            // loop, because it will put all the logs to the logger queue again.\n            if (type === wrtcFuncNames.applicationLog) {\n                // NOTE otherArguments are not logged to the console on purpose\n                // to not log the whole log batch\n                // FIXME check the current logging level (currently not exposed\n                // by the logger implementation)\n                // NOTE it is not safe to log whole objects on react-native as\n                // those contain too many circular references and may crash\n                // the app.\n                if (!browser.isReactNative()) {\n                    console && console.debug('reportError', pc, cs, type);\n                }\n            } else {\n                logger.debug('reportError', pc, cs, type, ...args);\n            }\n            try {\n                originalReportError.call(theBackend, pc, cs, type, ...args);\n            } catch (exception) {\n                if (type === wrtcFuncNames.applicationLog) {\n                    console && console.error('reportError', exception);\n                } else {\n                    GlobalOnErrorHandler.callErrorHandler(exception);\n                }\n            }\n        };\n\n        /* eslint-enable max-params */\n    }\n\n    /**\n     * Returns the Set with the currently existing {@link CallStats} instances.\n     * Lazily initializes the Set to allow any Set polyfills to be applied.\n     * @type {Set<CallStats>}\n     */\n    static get fabrics() {\n        if (!_fabrics) {\n            _fabrics = new Set();\n        }\n\n        return _fabrics;\n    }\n\n    /**\n     * Initializes the CallStats backend. Should be called only if\n     * {@link CallStats.isBackendInitialized} returns <tt>false</tt>.\n     * @param {object} options\n     * @param {String} options.callStatsID CallStats credentials - ID\n     * @param {String} options.callStatsSecret CallStats credentials - secret\n     * @param {string} options.aliasName the <tt>aliasName</tt> part of\n     * the <tt>userID</tt> aka endpoint ID, see CallStats docs for more info.\n     * @param {string} options.userName the <tt>userName</tt> part of\n     * the <tt>userID</tt> aka display name, see CallStats docs for more info.\n     * @param {object} options.configParams the set of parameters\n     * to enable/disable certain features in the library. See CallStats docs for more info.\n     *\n     */\n    static initBackend(options) {\n        if (CallStats.backend) {\n            throw new Error('CallStats backend has been initialized already!');\n        }\n        try {\n            const CallStatsBackend = callstats;\n\n            CallStats.backend = new CallStatsBackend();\n            CallStats._traceAndCatchBackendCalls(CallStats.backend);\n            CallStats.userID = {\n                aliasName: options.aliasName,\n                userName: options.userName\n            };\n            CallStats.callStatsID = options.callStatsID;\n            CallStats.callStatsSecret = options.callStatsSecret;\n\n            const configParams = { ...options.configParams };\n\n            if (options.applicationName) {\n                configParams.applicationVersion = `${options.applicationName} (${browser.getName()})`;\n            }\n\n            if (options.confID) {\n                // we first check is there a tenant in the confID\n                const match = options.confID.match(/.*\\/(.*)\\/.*/);\n\n                // if there is no tenant, we will just set '/'\n                configParams.siteID = options.siteID || (match && match[1]) || '/';\n            }\n\n            // userID is generated or given by the origin server\n            CallStats.backend.initialize(\n                CallStats.callStatsID,\n                CallStats.callStatsSecret,\n                CallStats.userID,\n                CallStats._initCallback,\n                undefined,\n                configParams);\n\n            return true;\n        } catch (e) {\n            // The callstats.io API failed to initialize (e.g. because its\n            // download did not succeed in general or on time). Further attempts\n            // to utilize it cannot possibly succeed.\n            GlobalOnErrorHandler.callErrorHandler(e);\n            CallStats.backend = null;\n            logger.error(e);\n\n            return false;\n        }\n    }\n\n    /**\n     * Checks if the CallStats backend has been created. It does not mean that\n     * it has been initialized, but only that the API instance has been\n     * allocated successfully.\n     * @return {boolean} <tt>true</tt> if backend exists or <tt>false</tt>\n     * otherwise\n     */\n    static isBackendInitialized() {\n        return Boolean(CallStats.backend);\n    }\n\n    /**\n     * Notifies CallStats about active device.\n     * @param {{deviceList: {String:String}}} devicesData list of devices with\n     * their data\n     * @param {CallStats} cs callstats instance related to the event\n     */\n    static sendActiveDeviceListEvent(devicesData, cs) {\n        CallStats._reportEvent(cs, fabricEvent.activeDeviceList, devicesData);\n    }\n\n    /**\n     * Notifies CallStats that there is a log we want to report.\n     *\n     * @param {Error} e error to send or {String} message\n     * @param {CallStats} cs callstats instance related to the error (optional)\n     */\n    static sendApplicationLog(e, cs) {\n        try {\n            CallStats._reportError(\n                cs,\n                wrtcFuncNames.applicationLog,\n                e,\n                cs && cs.peerconnection);\n        } catch (error) {\n            // If sendApplicationLog fails it should not be printed to\n            // the logger, because it will try to push the logs again\n            // (through sendApplicationLog) and an endless loop is created.\n            if (console && (typeof console.error === 'function')) {\n                // FIXME send analytics event as well\n                console.error('sendApplicationLog failed', error);\n            }\n        }\n    }\n\n    /**\n     * Sends the given feedback through CallStats.\n     *\n     * @param {string} conferenceID the conference ID for which the feedback\n     * will be reported.\n     * @param overall an integer between 1 and 5 indicating the\n     * user feedback\n     * @param comment detailed feedback from the user.\n     */\n    static sendFeedback(conferenceID, overall, comment) {\n        return new Promise((resolve, reject) => {\n            if (CallStats.backend) {\n                CallStats.backend.sendUserFeedback(\n                    conferenceID,\n                    {\n                        userID: CallStats.userID,\n                        overall,\n                        comment\n                    },\n                    (status, message) => {\n                        if (status === 'success') {\n                            resolve(message);\n                        } else {\n                            reject(message);\n                        }\n                    });\n            } else {\n                const reason = 'Failed to submit feedback to CallStats - no backend';\n\n                logger.error(reason);\n                reject(reason);\n            }\n        });\n    }\n\n    /**\n     * Notifies CallStats that getUserMedia failed.\n     *\n     * @param {Error} e error to send\n     * @param {CallStats} cs callstats instance related to the error (optional)\n     */\n    static sendGetUserMediaFailed(e, cs) {\n        CallStats._reportError(cs, wrtcFuncNames.getUserMedia, e, null);\n    }\n\n    /**\n     * Notifies CallStats for mute events\n     * @param mute {boolean} true for muted and false for not muted\n     * @param type {String} \"audio\"/\"video\"\n     * @param {CallStats} cs callstats instance related to the event\n     */\n    static sendMuteEvent(mute, type, cs) {\n        let event;\n\n        if (type === 'video') {\n            event = mute ? fabricEvent.videoPause : fabricEvent.videoResume;\n        } else {\n            event = mute ? fabricEvent.audioMute : fabricEvent.audioUnmute;\n        }\n\n        CallStats._reportEvent(cs, event);\n    }\n\n    /**\n     * Creates new CallStats instance that handles all callstats API calls for\n     * given {@link TraceablePeerConnection}. Each instance is meant to handle\n     * one CallStats fabric added with 'addFabric' API method for the\n     * {@link TraceablePeerConnection} instance passed in the constructor.\n     * @param {TraceablePeerConnection} tpc\n     * @param {Object} options\n     * @param {string} options.confID the conference ID that wil be used to\n     * report the session.\n     * @param {string} [options.remoteUserID='jitsi'] the remote user ID to\n     * which given <tt>tpc</tt> is connected.\n     */\n    constructor(tpc, options) {\n        this.confID = options.confID;\n        this.tpc = tpc;\n        this.peerconnection = tpc.peerconnection;\n        this.remoteUserID = options.remoteUserID || DEFAULT_REMOTE_USER;\n        this.hasFabric = false;\n\n        CallStats.fabrics.add(this);\n\n        if (CallStats.backendInitialized) {\n            this._addNewFabric();\n\n            // if this is the first fabric let's try to empty the\n            // report queue. Reports all events that we recorded between\n            // backend initialization and receiving the first fabric\n            if (CallStats.fabrics.size === 1) {\n                CallStats._emptyReportQueue(this);\n            }\n        }\n    }\n\n    /**\n     * Initializes CallStats fabric by calling \"addNewFabric\" for\n     * the peer connection associated with this instance.\n     * @return {boolean} true if the call was successful or false otherwise.\n     */\n    _addNewFabric() {\n        logger.info('addNewFabric', this.remoteUserID);\n        try {\n            const fabricAttributes = {\n                remoteEndpointType:\n                    this.tpc.isP2P\n                        ? CallStats.backend.endpointType.peer\n                        : CallStats.backend.endpointType.server\n            };\n            const ret\n                = CallStats.backend.addNewFabric(\n                    this.peerconnection,\n                    this.remoteUserID,\n                    CallStats.backend.fabricUsage.multiplex,\n                    this.confID,\n                    fabricAttributes,\n                    CallStats._addNewFabricCallback);\n\n            this.hasFabric = true;\n\n            const success = ret.status === 'success';\n\n            if (!success) {\n                logger.error('callstats fabric not initilized', ret.message);\n            }\n\n            return success;\n\n        } catch (error) {\n            GlobalOnErrorHandler.callErrorHandler(error);\n\n            return false;\n        }\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     * Lets CallStats module know where is given SSRC rendered by providing\n     * renderer tag ID.\n     * If the lib is not initialized yet queue the call for later, when it's\n     * ready.\n     * @param {number} ssrc the SSRC of the stream\n     * @param {boolean} isLocal indicates whether this the stream is local\n     * @param {string|null} streamEndpointId if the stream is not local the it\n     * needs to contain the stream owner's ID\n     * @param {string} usageLabel meaningful usage label of this stream like\n     *        'microphone', 'camera' or 'screen'.\n     * @param {string} containerId  the id of media 'audio' or 'video' tag which\n     *        renders the stream.\n     */\n    associateStreamWithVideoTag(\n            ssrc,\n            isLocal,\n            streamEndpointId,\n            usageLabel,\n            containerId) {\n        if (!CallStats.backend) {\n            return;\n        }\n\n        const callStatsId = isLocal ? CallStats.userID : streamEndpointId;\n\n        if (CallStats.backendInitialized) {\n            CallStats.backend.associateMstWithUserID(\n                this.peerconnection,\n                callStatsId,\n                this.confID,\n                ssrc,\n                usageLabel,\n                containerId);\n        } else {\n            CallStats.reportsQueue.push({\n                type: reportType.MST_WITH_USERID,\n                pc: this.peerconnection,\n                data: {\n                    callStatsId,\n                    containerId,\n                    ssrc,\n                    usageLabel\n                }\n            });\n        }\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Notifies CallStats that we are the new dominant speaker in the\n     * conference.\n     */\n    sendDominantSpeakerEvent() {\n        CallStats._reportEvent(this, fabricEvent.dominantSpeaker);\n    }\n\n    /**\n     * Notifies CallStats that the fabric for the underlying peerconnection was\n     * closed and no evens should be reported, after this call.\n     */\n    sendTerminateEvent() {\n        if (CallStats.backendInitialized) {\n            CallStats.backend.sendFabricEvent(\n                this.peerconnection,\n                CallStats.backend.fabricEvent.fabricTerminated,\n                this.confID);\n        }\n        CallStats.fabrics.delete(this);\n    }\n\n    /**\n     * Notifies CallStats for ice connection failed\n     */\n    sendIceConnectionFailedEvent() {\n        CallStats._reportError(\n            this,\n            wrtcFuncNames.iceConnectionFailure,\n            null,\n            this.peerconnection);\n    }\n\n    /**\n     * Notifies CallStats that peer connection failed to create offer.\n     *\n     * @param {Error} e error to send\n     */\n    sendCreateOfferFailed(e) {\n        CallStats._reportError(\n            this, wrtcFuncNames.createOffer, e, this.peerconnection);\n    }\n\n    /**\n     * Notifies CallStats that peer connection failed to create answer.\n     *\n     * @param {Error} e error to send\n     */\n    sendCreateAnswerFailed(e) {\n        CallStats._reportError(\n            this, wrtcFuncNames.createAnswer, e, this.peerconnection);\n    }\n\n    /**\n     * Sends either resume or hold event for the fabric associated with\n     * the underlying peerconnection.\n     * @param {boolean} isResume true to resume or false to hold\n     */\n    sendResumeOrHoldEvent(isResume) {\n        CallStats._reportEvent(\n            this,\n            isResume ? fabricEvent.fabricResume : fabricEvent.fabricHold);\n    }\n\n    /**\n     * Notifies CallStats for screen sharing events\n     * @param {boolean} start true for starting screen sharing and\n     * false for not stopping\n     * @param {string|null} ssrc - optional ssrc value, used only when\n     * starting screen sharing.\n     */\n    sendScreenSharingEvent(start, ssrc) {\n        let eventData;\n\n        if (ssrc) {\n            eventData = { ssrc };\n        }\n\n        CallStats._reportEvent(\n            this,\n            start ? fabricEvent.screenShareStart : fabricEvent.screenShareStop,\n            eventData);\n    }\n\n    /**\n     * Notifies CallStats that peer connection failed to set local description.\n     *\n     * @param {Error} e error to send\n     */\n    sendSetLocalDescFailed(e) {\n        CallStats._reportError(\n            this, wrtcFuncNames.setLocalDescription, e, this.peerconnection);\n    }\n\n    /**\n     * Notifies CallStats that peer connection failed to set remote description.\n     *\n     * @param {Error} e error to send\n     */\n    sendSetRemoteDescFailed(e) {\n        CallStats._reportError(\n            this, wrtcFuncNames.setRemoteDescription, e, this.peerconnection);\n    }\n\n    /**\n     * Notifies CallStats that peer connection failed to add ICE candidate.\n     *\n     * @param {Error} e error to send\n     */\n    sendAddIceCandidateFailed(e) {\n        CallStats._reportError(\n            this, wrtcFuncNames.addIceCandidate, e, this.peerconnection);\n    }\n}\n\n/**\n * The CallStats API backend instance\n * @type {callstats}\n */\nCallStats.backend = null;\n\n// some errors/events may happen before CallStats init\n// in this case we accumulate them in this array\n// and send them to callstats on init\nCallStats.reportsQueue = [];\n\n/**\n * Whether the library was successfully initialized(the backend) using its\n * initialize method.\n * @type {boolean}\n */\nCallStats.backendInitialized = false;\n\n/**\n * Part of the CallStats credentials - application ID\n * @type {string}\n */\nCallStats.callStatsID = null;\n\n/**\n * Part of the CallStats credentials - application secret\n * @type {string}\n */\nCallStats.callStatsSecret = null;\n\n/**\n * Local CallStats user ID structure. Can be set only once when\n * {@link backend} is initialized, so it's static for the time being.\n * See CallStats API for more info:\n * https://www.callstats.io/api/#userid\n * @type {object}\n */\nCallStats.userID = null;\n","/**\n * Provides statistics for the local stream.\n */\n\nconst logger = require('@jitsi/logger').getLogger(__filename);\n\n/**\n * Size of the webaudio analyzer buffer.\n * @type {number}\n */\nconst WEBAUDIO_ANALYZER_FFT_SIZE = 2048;\n\n/**\n * Value of the webaudio analyzer smoothing time parameter.\n * @type {number}\n */\nconst WEBAUDIO_ANALYZER_SMOOTING_TIME = 0.8;\n\nwindow.AudioContext = window.AudioContext || window.webkitAudioContext;\n\n/**\n * The audio context.\n * @type {AudioContext}\n */\nlet context = null;\n\n\n/**\n * Converts time domain data array to audio level.\n * @param samples the time domain data array.\n * @returns {number} the audio level\n */\nfunction timeDomainDataToAudioLevel(samples) {\n\n    let maxVolume = 0;\n\n    const length = samples.length;\n\n    for (let i = 0; i < length; i++) {\n        if (maxVolume < samples[i]) {\n            maxVolume = samples[i];\n        }\n    }\n\n    return parseFloat(((maxVolume - 127) / 128).toFixed(3));\n}\n\n/**\n * Animates audio level change\n * @param newLevel the new audio level\n * @param lastLevel the last audio level\n * @returns {Number} the audio level to be set\n */\nfunction animateLevel(newLevel, lastLevel) {\n    let value = 0;\n    const diff = lastLevel - newLevel;\n\n    if (diff > 0.2) {\n        value = lastLevel - 0.2;\n    } else if (diff < -0.4) {\n        value = lastLevel + 0.4;\n    } else {\n        value = newLevel;\n    }\n\n    return parseFloat(value.toFixed(3));\n}\n\n\n/**\n * <tt>LocalStatsCollector</tt> calculates statistics for the local stream.\n *\n * @param stream the local stream\n * @param interval stats refresh interval given in ms.\n * @param callback function that receives the audio levels.\n * @constructor\n */\nexport default function LocalStatsCollector(stream, interval, callback) {\n    this.stream = stream;\n    this.intervalId = null;\n    this.intervalMilis = interval;\n    this.audioLevel = 0;\n    this.callback = callback;\n    this.source = null;\n    this.analyser = null;\n}\n\n/**\n * Starts the collecting the statistics.\n */\nLocalStatsCollector.prototype.start = function() {\n    if (!LocalStatsCollector.isLocalStatsSupported()) {\n        return;\n    }\n\n    context.resume();\n    this.analyser = context.createAnalyser();\n\n    this.analyser.smoothingTimeConstant = WEBAUDIO_ANALYZER_SMOOTING_TIME;\n    this.analyser.fftSize = WEBAUDIO_ANALYZER_FFT_SIZE;\n\n    this.source = context.createMediaStreamSource(this.stream);\n\n    this.source.connect(this.analyser);\n\n    this.intervalId = setInterval(\n        () => {\n            const array = new Uint8Array(this.analyser.frequencyBinCount);\n\n            this.analyser.getByteTimeDomainData(array);\n            const audioLevel = timeDomainDataToAudioLevel(array);\n\n            // Set the audio levels always as NoAudioSignalDetection now\n            // uses audio levels from LocalStatsCollector and waits for\n            // atleast 4 secs for a no audio signal before displaying the\n            // notification on the UI.\n            this.audioLevel = animateLevel(audioLevel, this.audioLevel);\n            this.callback(this.audioLevel);\n        },\n        this.intervalMilis\n    );\n};\n\n/**\n * Stops collecting the statistics.\n */\nLocalStatsCollector.prototype.stop = function() {\n    if (this.intervalId) {\n        clearInterval(this.intervalId);\n        this.intervalId = null;\n    }\n\n    this.analyser?.disconnect();\n    this.analyser = null;\n    this.source?.disconnect();\n    this.source = null;\n};\n\n/**\n * Checks if the environment has the necessary conditions to support\n * collecting stats from local streams.\n *\n * @returns {boolean}\n */\nLocalStatsCollector.isLocalStatsSupported = function() {\n    return Boolean(window?.AudioContext);\n};\n\n/**\n * Disconnects the audio context.\n */\nLocalStatsCollector.disconnectAudioContext = async function() {\n    if (context) {\n        logger.info('Disconnecting audio context');\n        await context.close();\n        context = null;\n    }\n};\n\n/**\n * Connects the audio context.\n */\nLocalStatsCollector.connectAudioContext = function() {\n    if (!LocalStatsCollector.isLocalStatsSupported()) {\n        return;\n    }\n\n    logger.info('Connecting audio context');\n    context = new AudioContext();\n\n    context.suspend();\n};\n\n/**\n * Initialize the audio context on startup.\n */\nLocalStatsCollector.connectAudioContext();\n","\n/**\n * The method will increase the given number by 1. If the given counter is equal\n * or greater to {@link Number.MAX_SAFE_INTEGER} then it will be rolled back to\n * 1.\n * @param {number} number - An integer counter value to be incremented.\n * @return {number} the next counter value increased by 1 (see the description\n * above for exception).\n */\nexport function safeCounterIncrement(number) {\n    let nextValue = number;\n\n    if (number >= Number.MAX_SAFE_INTEGER) {\n        nextValue = 0;\n    }\n\n    return nextValue + 1;\n}\n\n/**\n * Calculates the average value of am Array of numbers.\n *\n * @param {Float32Array} valueArray - Array of numbers.\n * @returns {number} - Number array average.\n */\nexport function calculateAverage(valueArray) {\n    return valueArray.length > 0 ? valueArray.reduce((a, b) => a + b) / valueArray.length : 0;\n}\n\n/**\n * Calculates a unique hash for a given string similar to Java's\n * implementation of String.hashCode()\n *\n * @param {String} string - String whose hash has to be calculated.\n * @returns {number} - Unique hash code calculated.\n */\nexport function hashString(string) {\n    let hash = 0;\n\n    for (let i = 0; i < string.length; i++) {\n        hash += Math.pow(string.charCodeAt(i) * 31, string.length - i);\n\n        /* eslint-disable no-bitwise */\n        hash = hash & hash; // Convert to 32bit integer\n    }\n\n    return Math.abs(hash);\n}\n\n/**\n * Returns only the positive values from an array of numbers.\n *\n * @param {Float32Array} valueArray - Array of vad scores.\n * @returns {Array} - Array of positive numbers.\n */\nexport function filterPositiveValues(valueArray) {\n    return valueArray.filter(value => value >= 0);\n}\n\n/**\n * This class calculates a simple running average that continually changes\n * as more data points are collected and added.\n */\nexport class RunningAverage {\n    /**\n     * Creates an instance of the running average calculator.\n     */\n    constructor() {\n        this.average = 0;\n        this.n = 0;\n    }\n\n    /**\n     * Adds a new data point to the existing set of values and recomputes\n     * the running average.\n     * @param {number} value\n     * @returns {void}\n     */\n    addNext(value) {\n        if (typeof value !== 'number') {\n            return;\n        }\n        this.n += 1;\n        this.average = this.average + ((value - this.average) / this.n);\n    }\n\n    /**\n     * Obtains the average value for the current subset of values.\n     * @returns {number} - computed average.\n     */\n    getAverage() {\n        return this.average;\n    }\n}\n","\nimport { getLogger } from '@jitsi/logger';\n\nimport * as StatisticsEvents from '../../service/statistics/Events';\nimport { RunningAverage } from '../util/MathUtil';\n\nconst logger = getLogger(__filename);\nconst MILLI_SECONDS = 1000;\nconst SECONDS = 60;\n\n/**\n * This class creates an observer that monitors browser's performance measurement events\n * as they are recorded in the browser's performance timeline and computes an average and\n * a maximum value for the long task events. Tasks are classified as long tasks if they take\n * longer than 50ms to execute on the main thread.\n */\nexport class PerformanceObserverStats {\n    /**\n     * Creates a new instance of Performance observer statistics.\n     *\n     * @param {*} emitter Event emitter for emitting stats periodically\n     * @param {*} statsInterval interval for calculating the stats\n     */\n    constructor(emitter, statsInterval) {\n        this.eventEmitter = emitter;\n        this.longTasks = 0;\n        this.maxDuration = 0;\n        this.performanceStatsInterval = statsInterval;\n        this.stats = new RunningAverage();\n    }\n\n    /**\n     * Obtains the average rate of long tasks observed per min and the\n     * duration of the longest task recorded by the observer.\n     * @returns {Object}\n     */\n    getLongTasksStats() {\n        return {\n            avgRatePerMinute: (this.stats.getAverage() * SECONDS).toFixed(2), // calc rate per min\n            maxDurationMs: this.maxDuration\n        };\n    }\n\n    /**\n     * Starts the performance observer by registering the callback function\n     * that calculates the performance statistics periodically.\n     * @returns {void}\n     */\n    startObserver() {\n        // Create a handler for when the long task event is fired.\n        this.longTaskEventHandler = list => {\n            const entries = list.getEntries();\n\n            for (const task of entries) {\n                this.longTasks++;\n                this.maxDuration = Math.max(this.maxDuration, task.duration).toFixed(3);\n            }\n        };\n\n        // Create an observer for monitoring long tasks.\n        logger.info('Creating a Performance Observer for monitoring Long Tasks');\n        this.observer = new PerformanceObserver(this.longTaskEventHandler);\n        this.observer.observe({ type: 'longtask',\n            buffered: true });\n        const startTime = Date.now();\n\n        // Calculate the average # of events/sec and emit a stats event.\n        this.longTasksIntervalId = setInterval(() => {\n            const now = Date.now();\n            const interval = this._lastTimeStamp\n                ? (now - this._lastTimeStamp) / MILLI_SECONDS\n                : (now - startTime) / MILLI_SECONDS;\n            const rate = this.longTasks / interval;\n\n            this.stats.addNext(rate);\n            this.eventEmitter.emit(\n                StatisticsEvents.LONG_TASKS_STATS, this.getLongTasksStats());\n\n            // Reset the counter and start counting events again.\n            this.longTasks = 0;\n            this._lastTimeStamp = Date.now();\n        }, this.performanceStatsInterval);\n    }\n\n    /**\n     * Stops the performance observer.\n     * @returns {void}\n     */\n    stopObserver() {\n        this.observer && this.observer.disconnect();\n        this.longTaskEventHandler = null;\n        if (this.longTasksIntervalId) {\n            clearInterval(this.longTasksIntervalId);\n            this.longTasksIntervalId = null;\n        }\n    }\n}\n","export enum MediaType {\n    /**\n     * The audio type.\n     */\n    AUDIO = 'audio',\n\n    /**\n     * The video type.\n     */\n    VIDEO = 'video'\n}\n","\nimport browser from '../browser';\n\n/**\n * A global module for accessing information about different feature flags state.\n */\nclass FeatureFlags {\n    /**\n     * Configures the module.\n     *\n     * @param {object} flags - The feature flags.\n     * @param {boolean=} flags.runInLiteMode - Enables lite mode for testing to disable media decoding.\n     * @param {boolean=} flags.ssrcRewritingEnabled - Use SSRC rewriting. Requires sourceNameSignaling to be enabled.\n     * @param {boolean=} flags.enableJoinAsVisitor - Enable joining as a visitor.\n     */\n    init(flags) {\n        this._runInLiteMode = Boolean(flags.runInLiteMode);\n        this._ssrcRewriting = Boolean(flags.ssrcRewritingEnabled);\n        this._joinAsVisitor = Boolean(flags.enableJoinAsVisitor ?? true);\n    }\n\n    /**\n     * Checks if multiple local video streams support is enabled.\n     *\n     * @returns {boolean}\n     */\n    isMultiStreamSendSupportEnabled() {\n        return browser.supportsUnifiedPlan();\n    }\n\n    /**\n     * Checks if the run in lite mode is enabled.\n     * This will cause any media to be received and not decoded. (Insertable streams are used to discard\n     * all media before it is decoded). This can be used for various test scenarios.\n     *\n     * @returns {boolean}\n     */\n    isRunInLiteModeEnabled() {\n        return this._runInLiteMode && browser.supportsInsertableStreams();\n    }\n\n    /**\n     * Checks if the clients supports re-writing of the SSRCs on the media streams by the bridge.\n     * @returns {boolean}\n     */\n    isSsrcRewritingSupported() {\n        return this._ssrcRewriting;\n    }\n\n    /**\n     * Checks if the clients supports joining as a visitor.\n     * @returns {boolean}\n     */\n    isJoinAsVisitorSupported() {\n        return this._joinAsVisitor;\n    }\n}\n\nexport default new FeatureFlags();\n","import { getLogger } from '@jitsi/logger';\n\nimport { MediaType } from '../../service/RTC/MediaType';\nimport * as StatisticsEvents from '../../service/statistics/Events';\nimport browser from '../browser';\nimport FeatureFlags from '../flags/FeatureFlags';\n\nconst GlobalOnErrorHandler = require('../util/GlobalOnErrorHandler');\n\nconst logger = getLogger(__filename);\n\n/**\n * Calculates packet lost percent using the number of lost packets and the\n * number of all packet.\n * @param lostPackets the number of lost packets\n * @param totalPackets the number of all packets.\n * @returns {number} packet loss percent\n */\nfunction calculatePacketLoss(lostPackets, totalPackets) {\n    if (!totalPackets || totalPackets <= 0\n            || !lostPackets || lostPackets <= 0) {\n        return 0;\n    }\n\n    return Math.round((lostPackets / totalPackets) * 100);\n}\n\n/**\n * Holds \"statistics\" for a single SSRC.\n * @constructor\n */\nfunction SsrcStats() {\n    this.loss = {};\n    this.bitrate = {\n        download: 0,\n        upload: 0\n    };\n    this.resolution = {};\n    this.framerate = 0;\n    this.codec = '';\n}\n\n/**\n * Sets the \"loss\" object.\n * @param loss the value to set.\n */\nSsrcStats.prototype.setLoss = function(loss) {\n    this.loss = loss || {};\n};\n\n/**\n * Sets resolution that belong to the ssrc represented by this instance.\n * @param resolution new resolution value to be set.\n */\nSsrcStats.prototype.setResolution = function(resolution) {\n    this.resolution = resolution || {};\n};\n\n/**\n * Adds the \"download\" and \"upload\" fields from the \"bitrate\" parameter to\n * the respective fields of the \"bitrate\" field of this object.\n * @param bitrate an object holding the values to add.\n */\nSsrcStats.prototype.addBitrate = function(bitrate) {\n    this.bitrate.download += bitrate.download;\n    this.bitrate.upload += bitrate.upload;\n};\n\n/**\n * Resets the bit rate for given <tt>ssrc</tt> that belong to the peer\n * represented by this instance.\n */\nSsrcStats.prototype.resetBitrate = function() {\n    this.bitrate.download = 0;\n    this.bitrate.upload = 0;\n};\n\n/**\n * Sets the \"framerate\".\n * @param framerate the value to set.\n */\nSsrcStats.prototype.setFramerate = function(framerate) {\n    this.framerate = framerate || 0;\n};\n\nSsrcStats.prototype.setCodec = function(codec) {\n    this.codec = codec || '';\n};\n\n/**\n *\n */\nfunction ConferenceStats() {\n\n    /**\n     * The bandwidth\n     * @type {{}}\n     */\n    this.bandwidth = {};\n\n    /**\n     * The bit rate\n     * @type {{}}\n     */\n    this.bitrate = {};\n\n    /**\n     * The packet loss rate\n     * @type {{}}\n     */\n    this.packetLoss = null;\n\n    /**\n     * Array with the transport information.\n     * @type {Array}\n     */\n    this.transport = [];\n}\n\n/* eslint-disable max-params */\n\n/**\n * <tt>StatsCollector</tt> registers for stats updates of given\n * <tt>peerconnection</tt> in given <tt>interval</tt>. On each update particular\n * stats are extracted and put in {@link SsrcStats} objects. Once the processing\n * is done <tt>audioLevelsUpdateCallback</tt> is called with <tt>this</tt>\n * instance as an event source.\n *\n * @param peerconnection WebRTC PeerConnection object.\n * @param audioLevelsInterval\n * @param statsInterval stats refresh interval given in ms.\n * @param eventEmitter\n * @constructor\n */\nexport default function StatsCollector(peerconnection, audioLevelsInterval, statsInterval, eventEmitter) {\n    this.peerconnection = peerconnection;\n    this.currentStatsReport = null;\n    this.previousStatsReport = null;\n    this.audioLevelReportHistory = {};\n    this.audioLevelsIntervalId = null;\n    this.eventEmitter = eventEmitter;\n    this.conferenceStats = new ConferenceStats();\n\n    // Updates stats interval\n    this.audioLevelsIntervalMilis = audioLevelsInterval;\n\n    this.speakerList = [];\n    this.statsIntervalId = null;\n    this.statsIntervalMilis = statsInterval;\n\n    /**\n     * Maps SSRC numbers to {@link SsrcStats}.\n     * @type {Map<number,SsrcStats}\n     */\n    this.ssrc2stats = new Map();\n}\n\n/**\n * Set the list of the remote speakers for which audio levels are to be calculated.\n *\n * @param {Array<string>} speakerList - Endpoint ids.\n * @returns {void}\n */\nStatsCollector.prototype.setSpeakerList = function(speakerList) {\n    this.speakerList = speakerList;\n};\n\n/**\n * Stops stats updates.\n */\nStatsCollector.prototype.stop = function() {\n    if (this.audioLevelsIntervalId) {\n        clearInterval(this.audioLevelsIntervalId);\n        this.audioLevelsIntervalId = null;\n    }\n\n    if (this.statsIntervalId) {\n        clearInterval(this.statsIntervalId);\n        this.statsIntervalId = null;\n    }\n};\n\n/**\n * Callback passed to <tt>getStats</tt> method.\n * @param error an error that occurred on <tt>getStats</tt> call.\n */\nStatsCollector.prototype.errorCallback = function(error) {\n    GlobalOnErrorHandler.callErrorHandler(error);\n    logger.error('Get stats error', error);\n    this.stop();\n};\n\n/**\n * Starts stats updates.\n */\nStatsCollector.prototype.start = function(startAudioLevelStats) {\n    if (startAudioLevelStats && browser.supportsReceiverStats()) {\n        this.audioLevelsIntervalId = setInterval(\n            () => {\n                const audioLevels = this.peerconnection.getAudioLevels(this.speakerList);\n\n                for (const ssrc in audioLevels) {\n                    if (audioLevels.hasOwnProperty(ssrc)) {\n                        // Use a scaling factor of 2.5 to report the same audio levels that getStats reports.\n                        const audioLevel = audioLevels[ssrc] * 2.5;\n\n                        this.eventEmitter.emit(\n                            StatisticsEvents.AUDIO_LEVEL,\n                            this.peerconnection,\n                            Number.parseInt(ssrc, 10),\n                            audioLevel,\n                            false /* isLocal */);\n                    }\n                }\n            },\n            this.audioLevelsIntervalMilis\n        );\n    }\n\n    const processStats = () => {\n        // Interval updates\n        this.peerconnection.getStats()\n            .then(report => {\n                this.currentStatsReport = typeof report?.result === 'function'\n                    ? report.result()\n                    : report;\n\n                try {\n                    this.processStatsReport();\n                } catch (error) {\n                    GlobalOnErrorHandler.callErrorHandler(error);\n                    logger.error('Processing of RTP stats failed:', error);\n                }\n                this.previousStatsReport = this.currentStatsReport;\n            })\n            .catch(error => this.errorCallback(error));\n    };\n\n    processStats();\n    this.statsIntervalId = setInterval(processStats, this.statsIntervalMilis);\n};\n\n/**\n *\n */\nStatsCollector.prototype._processAndEmitReport = function() {\n    // process stats\n    const totalPackets = {\n        download: 0,\n        upload: 0\n    };\n    const lostPackets = {\n        download: 0,\n        upload: 0\n    };\n    let bitrateDownload = 0;\n    let bitrateUpload = 0;\n    const resolutions = {};\n    const framerates = {};\n    const codecs = {};\n    let audioBitrateDownload = 0;\n    let audioBitrateUpload = 0;\n    let videoBitrateDownload = 0;\n    let videoBitrateUpload = 0;\n\n    for (const [ ssrc, ssrcStats ] of this.ssrc2stats) {\n        // process packet loss stats\n        const loss = ssrcStats.loss;\n        const type = loss.isDownloadStream ? 'download' : 'upload';\n\n        totalPackets[type] += loss.packetsTotal;\n        lostPackets[type] += loss.packetsLost;\n\n        // process bitrate stats\n        bitrateDownload += ssrcStats.bitrate.download;\n        bitrateUpload += ssrcStats.bitrate.upload;\n\n        ssrcStats.resetBitrate();\n\n        // collect resolutions and framerates\n        const track = this.peerconnection.getTrackBySSRC(ssrc);\n\n        if (!track) {\n            continue; // eslint-disable-line no-continue\n        }\n\n        let audioCodec;\n        let videoCodec;\n\n        if (track.isAudioTrack()) {\n            audioBitrateDownload += ssrcStats.bitrate.download;\n            audioBitrateUpload += ssrcStats.bitrate.upload;\n            audioCodec = ssrcStats.codec;\n        } else {\n            videoBitrateDownload += ssrcStats.bitrate.download;\n            videoBitrateUpload += ssrcStats.bitrate.upload;\n            videoCodec = ssrcStats.codec;\n        }\n\n        const participantId = track.getParticipantId();\n\n        if (!participantId) {\n            // All tracks in ssrc-rewriting mode need not have a participant associated with it.\n            if (!FeatureFlags.isSsrcRewritingSupported()) {\n                logger.error(`No participant ID returned by ${track}`);\n            }\n            continue; // eslint-disable-line no-continue\n        }\n\n        const userCodecs = codecs[participantId] ?? { };\n\n        userCodecs[ssrc] = {\n            audio: audioCodec,\n            video: videoCodec\n        };\n\n        codecs[participantId] = userCodecs;\n        const { resolution } = ssrcStats;\n\n        if (!track.isVideoTrack()\n            || isNaN(resolution?.height)\n            || isNaN(resolution?.width)\n            || resolution.height === -1\n            || resolution.width === -1) {\n            continue; // eslint-disable-line no-continue\n        }\n        const userResolutions = resolutions[participantId] || {};\n\n        // If simulcast (VP8) is used, there will be 3 \"outbound-rtp\" streams with different resolutions and 3\n        // different SSRCs. Based on the requested resolution and the current cpu and available bandwidth\n        // values, some of the streams might get suspended. Therefore the actual send resolution needs to be\n        // calculated based on the outbound-rtp streams that are currently active for the simulcast case.\n        // However for the SVC case, there will be only 1 \"outbound-rtp\" stream which will have the correct\n        // send resolution width and height.\n        if (track.isLocal() && !browser.supportsTrackBasedStats() && this.peerconnection.doesTrueSimulcast()) {\n            const localSsrcs = this.peerconnection.getLocalVideoSSRCs(track);\n\n            for (const localSsrc of localSsrcs) {\n                const ssrcResolution = this.ssrc2stats.get(localSsrc)?.resolution;\n\n                // The code processes resolution stats only for 'outbound-rtp' streams that are currently active.\n                if (ssrcResolution?.height && ssrcResolution?.width) {\n                    resolution.height = Math.max(resolution.height, ssrcResolution.height);\n                    resolution.width = Math.max(resolution.width, ssrcResolution.width);\n                }\n            }\n        }\n\n        userResolutions[ssrc] = resolution;\n        resolutions[participantId] = userResolutions;\n\n        if (ssrcStats.framerate > 0) {\n            const userFramerates = framerates[participantId] || {};\n\n            userFramerates[ssrc] = ssrcStats.framerate;\n            framerates[participantId] = userFramerates;\n        }\n    }\n\n    this.conferenceStats.bitrate = {\n        'upload': bitrateUpload,\n        'download': bitrateDownload\n    };\n\n    this.conferenceStats.bitrate.audio = {\n        'upload': audioBitrateUpload,\n        'download': audioBitrateDownload\n    };\n\n    this.conferenceStats.bitrate.video = {\n        'upload': videoBitrateUpload,\n        'download': videoBitrateDownload\n    };\n\n    this.conferenceStats.packetLoss = {\n        total:\n            calculatePacketLoss(\n                lostPackets.download + lostPackets.upload,\n                totalPackets.download + totalPackets.upload),\n        download:\n            calculatePacketLoss(lostPackets.download, totalPackets.download),\n        upload:\n            calculatePacketLoss(lostPackets.upload, totalPackets.upload)\n    };\n\n    const avgAudioLevels = {};\n    let localAvgAudioLevels;\n\n    Object.keys(this.audioLevelReportHistory).forEach(ssrc => {\n        const { data, isLocal } = this.audioLevelReportHistory[ssrc];\n        const avgAudioLevel = data.reduce((sum, currentValue) => sum + currentValue) / data.length;\n\n        if (isLocal) {\n            localAvgAudioLevels = avgAudioLevel;\n        } else {\n            const track = this.peerconnection.getTrackBySSRC(Number(ssrc));\n\n            if (track) {\n                const participantId = track.getParticipantId();\n\n                if (participantId) {\n                    avgAudioLevels[participantId] = avgAudioLevel;\n                }\n            }\n        }\n    });\n    this.audioLevelReportHistory = {};\n\n    this.eventEmitter.emit(\n        StatisticsEvents.CONNECTION_STATS,\n        this.peerconnection,\n        {\n            'bandwidth': this.conferenceStats.bandwidth,\n            'bitrate': this.conferenceStats.bitrate,\n            'packetLoss': this.conferenceStats.packetLoss,\n            'resolution': resolutions,\n            'framerate': framerates,\n            'codec': codecs,\n            'transport': this.conferenceStats.transport,\n            localAvgAudioLevels,\n            avgAudioLevels\n        });\n    this.conferenceStats.transport = [];\n};\n\n/**\n * Converts the value to a non-negative number.\n * If the value is either invalid or negative then 0 will be returned.\n * @param {*} v\n * @return {number}\n * @private\n */\nStatsCollector.prototype.getNonNegativeValue = function(v) {\n    let value = v;\n\n    if (typeof value !== 'number') {\n        value = Number(value);\n    }\n\n    if (isNaN(value)) {\n        return 0;\n    }\n\n    return Math.max(0, value);\n};\n\n/**\n * Calculates bitrate between before and now using a supplied field name and its\n * value in the stats.\n * @param {RTCInboundRtpStreamStats|RTCSentRtpStreamStats} now the current stats\n * @param {RTCInboundRtpStreamStats|RTCSentRtpStreamStats} before the\n * previous stats.\n * @param fieldName the field to use for calculations.\n * @return {number} the calculated bitrate between now and before.\n * @private\n */\nStatsCollector.prototype._calculateBitrate = function(now, before, fieldName) {\n    const bytesNow = this.getNonNegativeValue(now[fieldName]);\n    const bytesBefore = this.getNonNegativeValue(before[fieldName]);\n    const bytesProcessed = Math.max(0, bytesNow - bytesBefore);\n\n    const timeMs = now.timestamp - before.timestamp;\n    let bitrateKbps = 0;\n\n    if (timeMs > 0) {\n        // TODO is there any reason to round here?\n        bitrateKbps = Math.round((bytesProcessed * 8) / timeMs);\n    }\n\n    return bitrateKbps;\n};\n\n/**\n * Calculates the frames per second rate between before and now using a supplied field name and its value in stats.\n * @param {RTCOutboundRtpStreamStats|RTCSentRtpStreamStats} now the current stats\n * @param {RTCOutboundRtpStreamStats|RTCSentRtpStreamStats} before the previous stats\n * @param {string} fieldName the field to use for calculations.\n * @returns {number} the calculated frame rate between now and before.\n */\nStatsCollector.prototype._calculateFps = function(now, before, fieldName) {\n    const timeMs = now.timestamp - before.timestamp;\n    let frameRate = 0;\n\n    if (timeMs > 0 && now[fieldName]) {\n        const numberOfFramesSinceBefore = now[fieldName] - before[fieldName];\n\n        frameRate = (numberOfFramesSinceBefore / timeMs) * 1000;\n    }\n\n    return frameRate;\n};\n\n/**\n * Stats processing for spec-compliant RTCPeerConnection#getStats.\n */\nStatsCollector.prototype.processStatsReport = function() {\n    const byteSentStats = {};\n\n    this.currentStatsReport.forEach(now => {\n        const before = this.previousStatsReport ? this.previousStatsReport.get(now.id) : null;\n\n        // RTCIceCandidatePairStats - https://w3c.github.io/webrtc-stats/#candidatepair-dict*\n        if (now.type === 'candidate-pair' && now.nominated && now.state === 'succeeded') {\n            const availableIncomingBitrate = now.availableIncomingBitrate;\n            const availableOutgoingBitrate = now.availableOutgoingBitrate;\n\n            if (availableIncomingBitrate || availableOutgoingBitrate) {\n                this.conferenceStats.bandwidth = {\n                    'download': Math.round(availableIncomingBitrate / 1000),\n                    'upload': Math.round(availableOutgoingBitrate / 1000)\n                };\n            }\n\n            const remoteUsedCandidate = this.currentStatsReport.get(now.remoteCandidateId);\n            const localUsedCandidate = this.currentStatsReport.get(now.localCandidateId);\n\n            // RTCIceCandidateStats\n            // https://w3c.github.io/webrtc-stats/#icecandidate-dict*\n            if (remoteUsedCandidate && localUsedCandidate) {\n                const remoteIpAddress = browser.isChromiumBased()\n                    ? remoteUsedCandidate.ip\n                    : remoteUsedCandidate.address;\n                const remotePort = remoteUsedCandidate.port;\n                const ip = `${remoteIpAddress}:${remotePort}`;\n\n                const localIpAddress = browser.isChromiumBased()\n                    ? localUsedCandidate.ip\n                    : localUsedCandidate.address;\n                const localPort = localUsedCandidate.port;\n                const localip = `${localIpAddress}:${localPort}`;\n                const type = remoteUsedCandidate.protocol;\n\n                // Save the address unless it has been saved already.\n                const conferenceStatsTransport = this.conferenceStats.transport;\n\n                if (!conferenceStatsTransport.some(t =>\n                    t.ip === ip\n                    && t.type === type\n                    && t.localip === localip)) {\n                    conferenceStatsTransport.push({\n                        ip,\n                        type,\n                        localip,\n                        p2p: this.peerconnection.isP2P,\n                        localCandidateType: localUsedCandidate.candidateType,\n                        remoteCandidateType: remoteUsedCandidate.candidateType,\n                        networkType: localUsedCandidate.networkType,\n                        rtt: now.currentRoundTripTime * 1000\n                    });\n                }\n            }\n\n        // RTCReceivedRtpStreamStats\n        // https://w3c.github.io/webrtc-stats/#receivedrtpstats-dict*\n        // RTCSentRtpStreamStats\n        // https://w3c.github.io/webrtc-stats/#sentrtpstats-dict*\n        } else if (now.type === 'inbound-rtp' || now.type === 'outbound-rtp') {\n            const ssrc = this.getNonNegativeValue(now.ssrc);\n\n            if (!ssrc) {\n                return;\n            }\n\n            let ssrcStats = this.ssrc2stats.get(ssrc);\n\n            if (!ssrcStats) {\n                ssrcStats = new SsrcStats();\n                this.ssrc2stats.set(ssrc, ssrcStats);\n            }\n\n            let isDownloadStream = true;\n            let key = 'packetsReceived';\n\n            if (now.type === 'outbound-rtp') {\n                isDownloadStream = false;\n                key = 'packetsSent';\n            }\n\n            let packetsNow = now[key];\n\n            if (!packetsNow || packetsNow < 0) {\n                packetsNow = 0;\n            }\n\n            if (before) {\n                const packetsBefore = this.getNonNegativeValue(before[key]);\n                const packetsDiff = Math.max(0, packetsNow - packetsBefore);\n\n                const packetsLostNow = this.getNonNegativeValue(now.packetsLost);\n                const packetsLostBefore = this.getNonNegativeValue(before.packetsLost);\n                const packetsLostDiff = Math.max(0, packetsLostNow - packetsLostBefore);\n\n                ssrcStats.setLoss({\n                    packetsTotal: packetsDiff + packetsLostDiff,\n                    packetsLost: packetsLostDiff,\n                    isDownloadStream\n                });\n            }\n\n            let resolution;\n\n            // Process the stats for 'inbound-rtp' streams always and 'outbound-rtp' only if the browser is\n            // Chromium based and version 112 and later since 'track' based stats are no longer available there\n            // for calculating send resolution and frame rate.\n            if (typeof now.frameHeight !== 'undefined' && typeof now.frameWidth !== 'undefined') {\n                // Assume the stream is active if the field is missing in the stats(Firefox)\n                const isStreamActive = now.active ?? true;\n\n                if (now.type === 'inbound-rtp' || (!browser.supportsTrackBasedStats() && isStreamActive)) {\n                    resolution = {\n                        height: now.frameHeight,\n                        width: now.frameWidth\n                    };\n                }\n            }\n            ssrcStats.setResolution(resolution);\n\n            let frameRate = now.framesPerSecond;\n\n            if (!frameRate && before) {\n                frameRate = this._calculateFps(now, before, 'framesSent');\n            }\n\n            ssrcStats.setFramerate(Math.round(frameRate || 0));\n\n            if (now.type === 'inbound-rtp' && before) {\n                ssrcStats.addBitrate({\n                    'download': this._calculateBitrate(now, before, 'bytesReceived'),\n                    'upload': 0\n                });\n            } else if (before) {\n                byteSentStats[ssrc] = this.getNonNegativeValue(now.bytesSent);\n                ssrcStats.addBitrate({\n                    'download': 0,\n                    'upload': this._calculateBitrate(now, before, 'bytesSent')\n                });\n            }\n\n            const codec = this.currentStatsReport.get(now.codecId);\n\n            if (codec) {\n                /**\n                 * The mime type has the following form: video/VP8 or audio/ISAC,\n                 * so we what to keep just the type after the '/', audio and video\n                 * keys will be added on the processing side.\n                 */\n                const codecShortType = codec.mimeType.split('/')[1];\n\n                codecShortType && ssrcStats.setCodec(codecShortType);\n            }\n\n        // Continue to use the 'track' based stats for Firefox and Safari and older versions of Chromium.\n        } else if (browser.supportsTrackBasedStats()\n            && now.type === 'track'\n            && now.kind === MediaType.VIDEO\n            && !now.remoteSource) {\n            const resolution = {\n                height: now.frameHeight,\n                width: now.frameWidth\n            };\n            const localVideoTracks = this.peerconnection.getLocalTracks(MediaType.VIDEO);\n\n            if (!localVideoTracks?.length) {\n                return;\n            }\n\n            const ssrc = this.peerconnection.getSsrcByTrackId(now.trackIdentifier);\n\n            if (!ssrc) {\n                return;\n            }\n            let ssrcStats = this.ssrc2stats.get(ssrc);\n\n            if (!ssrcStats) {\n                ssrcStats = new SsrcStats();\n                this.ssrc2stats.set(ssrc, ssrcStats);\n            }\n            if (resolution.height && resolution.width) {\n                ssrcStats.setResolution(resolution);\n            }\n\n            // Calculate the frame rate. 'framesSent' is the total aggregate value for all the simulcast streams.\n            // Therefore, it needs to be divided by the total number of active simulcast streams.\n            let frameRate = now.framesPerSecond;\n\n            if (!frameRate && before) {\n                frameRate = this._calculateFps(now, before, 'framesSent');\n            }\n            ssrcStats.setFramerate(frameRate);\n        }\n    });\n\n    if (Object.keys(byteSentStats).length) {\n        this.eventEmitter.emit(StatisticsEvents.BYTE_SENT_STATS, this.peerconnection, byteSentStats);\n    }\n\n    this._processAndEmitReport();\n};\n","import EventEmitter from 'events';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport JitsiTrackError from '../../JitsiTrackError';\nimport { JitsiTrackEvents } from '../../JitsiTrackEvents';\nimport { FEEDBACK } from '../../service/statistics/AnalyticsEvents';\nimport * as StatisticsEvents from '../../service/statistics/Events';\nimport browser from '../browser';\nimport ScriptUtil from '../util/ScriptUtil';\n\nimport analytics from './AnalyticsAdapter';\nimport CallStats from './CallStats';\nimport LocalStats from './LocalStatsCollector';\nimport { PerformanceObserverStats } from './PerformanceObserverStats';\nimport RTPStats from './RTPStatsCollector';\nimport { CALLSTATS_SCRIPT_URL } from './constants';\n\nconst logger = require('@jitsi/logger').getLogger(__filename);\n\n/**\n * Stores all active {@link Statistics} instances.\n * @type {Set<Statistics>}\n */\nlet _instances;\n\n/**\n * True if callstats API is loaded\n */\nlet isCallstatsLoaded = false;\n\n/**\n * Since callstats.io is a third party, we cannot guarantee the quality of their\n * service. More specifically, their server may take noticeably long time to\n * respond. Consequently, it is in our best interest (in the sense that the\n * intergration of callstats.io is pretty important to us but not enough to\n * allow it to prevent people from joining a conference) to (1) start\n * downloading their API as soon as possible and (2) do the downloading\n * asynchronously.\n *\n * @param {StatisticsOptions} options - Options to use for downloading and\n * initializing callstats backend.\n */\nfunction loadCallStatsAPI(options) {\n    if (!isCallstatsLoaded) {\n        ScriptUtil.loadScript(\n            options.customScriptUrl || CALLSTATS_SCRIPT_URL,\n            /* async */ true,\n            /* prepend */ true,\n            /* relativeURL */ undefined,\n            /* loadCallback */ () => _initCallStatsBackend(options)\n        );\n        isCallstatsLoaded = true;\n    }\n}\n\n/**\n * Initializes Callstats backend.\n *\n * @param {StatisticsOptions} options - The options to use for initializing\n * callstats backend.\n * @private\n */\nfunction _initCallStatsBackend(options) {\n    if (CallStats.isBackendInitialized()) {\n        return;\n    }\n\n    if (!CallStats.initBackend({\n        callStatsID: options.callStatsID,\n        callStatsSecret: options.callStatsSecret,\n        userName: options.userName,\n        aliasName: options.aliasName,\n        applicationName: options.applicationName,\n        confID: options.confID,\n        siteID: options.siteID,\n        configParams: options.configParams\n    })) {\n        logger.error('CallStats Backend initialization failed bad');\n    }\n}\n\n/**\n * callstats strips any additional fields from Error except for \"name\", \"stack\",\n * \"message\" and \"constraintName\". So we need to bundle additional information\n * from JitsiTrackError into error passed to callstats to preserve valuable\n * information about error.\n * @param {JitsiTrackError} error\n */\nfunction formatJitsiTrackErrorForCallStats(error) {\n    const err = new Error();\n\n    // Just copy original stack from error\n    err.stack = error.stack;\n\n    // Combine name from error's name plus (possibly) name of original GUM error\n    err.name = (error.name || 'Unknown error') + (error.gum && error.gum.error\n        && error.gum.error.name ? ` - ${error.gum.error.name}` : '');\n\n    // Put all constraints into this field. For constraint failed errors we will\n    // still know which exactly constraint failed as it will be a part of\n    // message.\n    err.constraintName = error.gum && error.gum.constraints\n        ? JSON.stringify(error.gum.constraints) : '';\n\n    // Just copy error's message.\n    err.message = error.message;\n\n    return err;\n}\n\n/**\n * Init statistic options\n * @param options\n */\nStatistics.init = function(options) {\n    Statistics.audioLevelsEnabled = !options.disableAudioLevels;\n    if (typeof options.pcStatsInterval === 'number') {\n        Statistics.pcStatsInterval = options.pcStatsInterval;\n    }\n\n    if (typeof options.audioLevelsInterval === 'number') {\n        Statistics.audioLevelsInterval = options.audioLevelsInterval;\n    }\n\n    if (typeof options.longTasksStatsInterval === 'number') {\n        Statistics.longTasksStatsInterval = options.longTasksStatsInterval;\n    }\n\n    Statistics.disableThirdPartyRequests = options.disableThirdPartyRequests;\n};\n\n/**\n * The options to configure Statistics.\n * @typedef {Object} StatisticsOptions\n * @property {string} applicationName - The application name to pass to\n * callstats.\n * @property {string} aliasName - The alias name to use when initializing callstats.\n * @property {string} userName - The user name to use when initializing callstats.\n * @property {string} confID - The callstats conference ID to use.\n * @property {string} callStatsID - Callstats credentials - the id.\n * @property {string} callStatsSecret - Callstats credentials - the secret.\n * @property {string} customScriptUrl - A custom lib url to use when downloading\n * callstats library.\n * @property {string} roomName - The room name we are currently in.\n * @property {string} configParams - The set of parameters\n * to enable/disable certain features in the library. See CallStats docs for more info.\n */\n/**\n *\n * @param xmpp\n * @param {StatisticsOptions} options - The options to use creating the\n * Statistics.\n */\nexport default function Statistics(xmpp, options) {\n    /**\n     * {@link RTPStats} mapped by {@link TraceablePeerConnection.id} which\n     * collect RTP statistics for each peerconnection.\n     * @type {Map<string, RTPStats}\n     */\n    this.rtpStatsMap = new Map();\n    this.eventEmitter = new EventEmitter();\n    this.xmpp = xmpp;\n    this.options = options || {};\n\n    this.callStatsIntegrationEnabled\n        = this.options.callStatsID && this.options.callStatsSecret\n\n            // Even though AppID and AppSecret may be specified, the integration\n            // of callstats.io may be disabled because of globally-disallowed\n            // requests to any third parties.\n            && (Statistics.disableThirdPartyRequests !== true);\n    if (this.callStatsIntegrationEnabled) {\n        this.callStatsApplicationLogsDisabled\n            = this.options.callStatsApplicationLogsDisabled;\n        if (browser.isReactNative()) {\n            _initCallStatsBackend(this.options);\n        } else {\n            loadCallStatsAPI(this.options);\n        }\n\n        if (!this.options.confID) {\n            logger.warn('\"confID\" is not defined');\n        }\n    }\n\n    /**\n     * Stores {@link CallStats} instances for each\n     * {@link TraceablePeerConnection} (one {@link CallStats} instance serves\n     * one TPC). The instances are mapped by {@link TraceablePeerConnection.id}.\n     * @type {Map<number, CallStats>}\n     */\n    this.callsStatsInstances = new Map();\n\n    Statistics.instances.add(this);\n}\nStatistics.audioLevelsEnabled = false;\nStatistics.audioLevelsInterval = 200;\nStatistics.pcStatsInterval = 10000;\nStatistics.disableThirdPartyRequests = false;\nStatistics.analytics = analytics;\n\nObject.defineProperty(Statistics, 'instances', {\n    /**\n     * Returns the Set holding all active {@link Statistics} instances. Lazily\n     * initializes the Set to allow any Set polyfills to be applied.\n     * @type {Set<Statistics>}\n     */\n    get() {\n        if (!_instances) {\n            _instances = new Set();\n        }\n\n        return _instances;\n    }\n});\n\n/**\n * Starts collecting RTP stats for given peerconnection.\n * @param {TraceablePeerConnection} peerconnection\n */\nStatistics.prototype.startRemoteStats = function(peerconnection) {\n    this.stopRemoteStats(peerconnection);\n\n    try {\n        const rtpStats\n            = new RTPStats(\n                peerconnection,\n                Statistics.audioLevelsInterval,\n                Statistics.pcStatsInterval,\n                this.eventEmitter);\n\n        rtpStats.start(Statistics.audioLevelsEnabled);\n        this.rtpStatsMap.set(peerconnection.id, rtpStats);\n    } catch (e) {\n        logger.error(`Failed to start collecting remote statistics: ${e}`);\n    }\n};\n\nStatistics.localStats = [];\n\nStatistics.startLocalStats = function(track, callback) {\n    if (browser.isIosBrowser()) {\n        // On iOS browsers audio is lost if the audio input device is in use by another app\n        // https://bugs.webkit.org/show_bug.cgi?id=233473\n        // The culprit was using the AudioContext, so now we close the AudioContext during\n        // the track being muted, and re-instantiate it afterwards.\n        track.addEventListener(\n        JitsiTrackEvents.NO_DATA_FROM_SOURCE,\n\n        /**\n         * Closes AudioContext on no audio data, and enables it on data received again.\n         *\n         * @param {boolean} value - Whether we receive audio data or not.\n         */\n        async value => {\n            if (value) {\n                for (const localStat of Statistics.localStats) {\n                    localStat.stop();\n                }\n\n                await LocalStats.disconnectAudioContext();\n            } else {\n                LocalStats.connectAudioContext();\n                for (const localStat of Statistics.localStats) {\n                    localStat.start();\n                }\n            }\n        });\n    }\n\n    if (!Statistics.audioLevelsEnabled) {\n        return;\n    }\n\n    track.addEventListener(\n        JitsiTrackEvents.LOCAL_TRACK_STOPPED,\n        () => {\n            Statistics.stopLocalStats(track);\n        });\n\n    const stream = track.getOriginalStream();\n    const localStats = new LocalStats(stream, Statistics.audioLevelsInterval,\n        callback);\n\n    this.localStats.push(localStats);\n    localStats.start();\n};\n\nStatistics.prototype.addAudioLevelListener = function(listener) {\n    if (!Statistics.audioLevelsEnabled) {\n        return;\n    }\n    this.eventEmitter.on(StatisticsEvents.AUDIO_LEVEL, listener);\n};\n\nStatistics.prototype.removeAudioLevelListener = function(listener) {\n    if (!Statistics.audioLevelsEnabled) {\n        return;\n    }\n    this.eventEmitter.removeListener(StatisticsEvents.AUDIO_LEVEL, listener);\n};\n\nStatistics.prototype.addBeforeDisposedListener = function(listener) {\n    this.eventEmitter.on(StatisticsEvents.BEFORE_DISPOSED, listener);\n};\n\nStatistics.prototype.removeBeforeDisposedListener = function(listener) {\n    this.eventEmitter.removeListener(\n        StatisticsEvents.BEFORE_DISPOSED, listener);\n};\n\nStatistics.prototype.addConnectionStatsListener = function(listener) {\n    this.eventEmitter.on(StatisticsEvents.CONNECTION_STATS, listener);\n};\n\nStatistics.prototype.removeConnectionStatsListener = function(listener) {\n    this.eventEmitter.removeListener(\n        StatisticsEvents.CONNECTION_STATS,\n        listener);\n};\n\nStatistics.prototype.addByteSentStatsListener = function(listener) {\n    this.eventEmitter.on(StatisticsEvents.BYTE_SENT_STATS, listener);\n};\n\nStatistics.prototype.removeByteSentStatsListener = function(listener) {\n    this.eventEmitter.removeListener(StatisticsEvents.BYTE_SENT_STATS,\n        listener);\n};\n\n/**\n * Add a listener that would be notified on a LONG_TASKS_STATS event.\n *\n * @param {Function} listener a function that would be called when notified.\n * @returns {void}\n */\nStatistics.prototype.addLongTasksStatsListener = function(listener) {\n    this.eventEmitter.on(StatisticsEvents.LONG_TASKS_STATS, listener);\n};\n\n/**\n * Creates an instance of {@link PerformanceObserverStats} and starts the\n * observer that records the stats periodically.\n *\n * @returns {void}\n */\nStatistics.prototype.attachLongTasksStats = function(conference) {\n    if (!browser.supportsPerformanceObserver()) {\n        logger.warn('Performance observer for long tasks not supported by browser!');\n\n        return;\n    }\n\n    this.performanceObserverStats = new PerformanceObserverStats(\n        this.eventEmitter,\n        Statistics.longTasksStatsInterval);\n\n    conference.on(\n        JitsiConferenceEvents.CONFERENCE_JOINED,\n        () => this.performanceObserverStats.startObserver());\n    conference.on(\n        JitsiConferenceEvents.CONFERENCE_LEFT,\n        () => this.performanceObserverStats.stopObserver());\n};\n\n/**\n * Obtains the current value of the LongTasks event statistics.\n *\n * @returns {Object|null} stats object if the observer has been\n * created, null otherwise.\n */\nStatistics.prototype.getLongTasksStats = function() {\n    return this.performanceObserverStats\n        ? this.performanceObserverStats.getLongTasksStats()\n        : null;\n};\n\n/**\n * Removes the given listener for the LONG_TASKS_STATS event.\n *\n * @param {Function} listener the listener we want to remove.\n * @returns {void}\n */\nStatistics.prototype.removeLongTasksStatsListener = function(listener) {\n    this.eventEmitter.removeListener(StatisticsEvents.LONG_TASKS_STATS, listener);\n};\n\n/**\n * Updates the list of speakers for which the audio levels are to be calculated. This is needed for the jvb pc only.\n *\n * @param {Array<string>} speakerList The list of remote endpoint ids.\n * @returns {void}\n */\nStatistics.prototype.setSpeakerList = function(speakerList) {\n    for (const rtpStats of Array.from(this.rtpStatsMap.values())) {\n        if (!rtpStats.peerconnection.isP2P) {\n            rtpStats.setSpeakerList(speakerList);\n        }\n    }\n};\n\nStatistics.prototype.dispose = function() {\n    try {\n        // NOTE Before reading this please see the comment in stopCallStats...\n        //\n        // Here we prevent from emitting the event twice in case it will be\n        // triggered from stopCallStats.\n        // If the event is triggered from here it means that the logs will not\n        // be submitted anyway (because there is no CallStats instance), but\n        // we're doing that for the sake of some kind of consistency.\n        if (!this.callsStatsInstances.size) {\n            this.eventEmitter.emit(StatisticsEvents.BEFORE_DISPOSED);\n        }\n        for (const callStats of this.callsStatsInstances.values()) {\n            this.stopCallStats(callStats.tpc);\n        }\n        for (const tpcId of this.rtpStatsMap.keys()) {\n            this._stopRemoteStats(tpcId);\n        }\n        if (this.eventEmitter) {\n            this.eventEmitter.removeAllListeners();\n        }\n    } finally {\n        Statistics.instances.delete(this);\n    }\n};\n\nStatistics.stopLocalStats = function(track) {\n    if (!Statistics.audioLevelsEnabled) {\n        return;\n    }\n\n    const stream = track.getOriginalStream();\n\n    for (let i = 0; i < Statistics.localStats.length; i++) {\n        if (Statistics.localStats[i].stream === stream) {\n            const localStats = Statistics.localStats.splice(i, 1);\n\n            localStats[0].stop();\n            break;\n        }\n    }\n};\n\n/**\n * Stops remote RTP stats for given peerconnection ID.\n * @param {string} tpcId {@link TraceablePeerConnection.id}\n * @private\n */\nStatistics.prototype._stopRemoteStats = function(tpcId) {\n    const rtpStats = this.rtpStatsMap.get(tpcId);\n\n    if (rtpStats) {\n        rtpStats.stop();\n        this.rtpStatsMap.delete(tpcId);\n    }\n};\n\n/**\n * Stops collecting RTP stats for given peerconnection\n * @param {TraceablePeerConnection} tpc\n */\nStatistics.prototype.stopRemoteStats = function(tpc) {\n    this._stopRemoteStats(tpc.id);\n};\n\n// CALSTATS METHODS\n\n/**\n * Initializes the callstats.io API.\n * @param {TraceablePeerConnection} tpc the {@link TraceablePeerConnection}\n * instance for which CalStats will be started.\n * @param {string} remoteUserID\n */\nStatistics.prototype.startCallStats = function(tpc, remoteUserID) {\n    if (!this.callStatsIntegrationEnabled) {\n        return;\n    } else if (this.callsStatsInstances.has(tpc.id)) {\n        logger.error('CallStats instance for ${tpc} exists already');\n\n        return;\n    }\n    let confID = this.options.confID;\n\n    // confID - domain/tenant/roomName\n    // roomName - meeting name or breakout room ID\n    // For breakout rooms we change the conference ID used for callstats to use\n    // the room ID instead of the meeting name\n    if (!confID.endsWith(this.options.roomName)) {\n        confID = `${this.options.confID.slice(0, this.options.confID.lastIndexOf('/'))}/${this.options.roomName}`;\n    }\n\n    logger.info(`Starting CallStats for ${tpc}...`);\n    const newInstance\n        = new CallStats(\n            tpc,\n            {\n                confID,\n                remoteUserID\n            });\n\n    this.callsStatsInstances.set(tpc.id, newInstance);\n};\n\n/**\n * Obtains the list of *all* {@link CallStats} instances collected from every\n * valid {@link Statistics} instance.\n * @return {Set<CallStats>}\n * @private\n */\nStatistics._getAllCallStatsInstances = function() {\n    const csInstances = new Set();\n\n    for (const statistics of Statistics.instances) {\n        for (const cs of statistics.callsStatsInstances.values()) {\n            csInstances.add(cs);\n        }\n    }\n\n    return csInstances;\n};\n\n/**\n * Removes the callstats.io instances.\n */\nStatistics.prototype.stopCallStats = function(tpc) {\n    const callStatsInstance = this.callsStatsInstances.get(tpc.id);\n\n    if (callStatsInstance) {\n        // FIXME the original purpose of adding BEFORE_DISPOSED event was to be\n        // able to submit the last log batch from jitsi-meet to CallStats. After\n        // recent changes we dispose the CallStats earlier\n        // (before Statistics.dispose), so we need to emit this event here to\n        // give this last chance for final log batch submission.\n        //\n        // Eventually there should be a separate module called \"log storage\"\n        // which should emit proper events when it's underlying\n        // CallStats instance is going away.\n        if (this.callsStatsInstances.size === 1) {\n            this.eventEmitter.emit(StatisticsEvents.BEFORE_DISPOSED);\n        }\n        this.callsStatsInstances.delete(tpc.id);\n\n        // The fabric needs to be terminated when being stopped\n        callStatsInstance.sendTerminateEvent();\n    }\n};\n\n/**\n * Returns true if the callstats integration is enabled, otherwise returns\n * false.\n *\n * @returns true if the callstats integration is enabled, otherwise returns\n * false.\n */\nStatistics.prototype.isCallstatsEnabled = function() {\n    return this.callStatsIntegrationEnabled;\n};\n\n/**\n * Logs either resume or hold event for the given peer connection.\n * @param {TraceablePeerConnection} tpc the connection for which event will be\n * reported\n * @param {boolean} isResume true for resume or false for hold\n */\nStatistics.prototype.sendConnectionResumeOrHoldEvent = function(tpc, isResume) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendResumeOrHoldEvent(isResume);\n    }\n};\n\n/**\n * Notifies CallStats and analytics (if present) for ice connection failed\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n */\nStatistics.prototype.sendIceConnectionFailedEvent = function(tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendIceConnectionFailedEvent();\n    }\n};\n\n/**\n * Notifies CallStats for mute events\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n * @param {boolean} muted true for muted and false for not muted\n * @param {String} type \"audio\"/\"video\"\n */\nStatistics.prototype.sendMuteEvent = function(tpc, muted, type) {\n    const instance = tpc && this.callsStatsInstances.get(tpc.id);\n\n    CallStats.sendMuteEvent(muted, type, instance);\n};\n\n/**\n * Notifies CallStats for screen sharing events\n * @param start {boolean} true for starting screen sharing and\n * false for not stopping\n * @param {string|null} ssrc - optional ssrc value, used only when\n * starting screen sharing.\n */\nStatistics.prototype.sendScreenSharingEvent\n    = function(start, ssrc) {\n        for (const cs of this.callsStatsInstances.values()) {\n            cs.sendScreenSharingEvent(start, ssrc);\n        }\n    };\n\n/**\n * Notifies the statistics module that we are now the dominant speaker of the\n * conference.\n * @param {String} roomJid - The room jid where the speaker event occurred.\n * @param {boolean} silence - Whether the dominant speaker is silent or not.\n */\nStatistics.prototype.sendDominantSpeakerEvent = function(roomJid, silence) {\n    for (const cs of this.callsStatsInstances.values()) {\n        cs.sendDominantSpeakerEvent();\n    }\n\n    // xmpp send dominant speaker event\n    this.xmpp.sendDominantSpeakerEvent(roomJid, silence);\n};\n\n/**\n * Notifies about active device.\n * @param {{deviceList: {String:String}}} devicesData - list of devices with\n *      their data\n */\nStatistics.sendActiveDeviceListEvent = function(devicesData) {\n    const globalSet = Statistics._getAllCallStatsInstances();\n\n    if (globalSet.size) {\n        for (const cs of globalSet) {\n            CallStats.sendActiveDeviceListEvent(devicesData, cs);\n        }\n    } else {\n        CallStats.sendActiveDeviceListEvent(devicesData, null);\n    }\n};\n\n/* eslint-disable max-params */\n\n/**\n * Lets the underlying statistics module know where is given SSRC rendered by\n * providing renderer tag ID.\n * @param {TraceablePeerConnection} tpc the connection to which the stream\n * belongs to\n * @param {number} ssrc the SSRC of the stream\n * @param {boolean} isLocal\n * @param {string} userId\n * @param {string} usageLabel  meaningful usage label of this stream like\n *        'microphone', 'camera' or 'screen'.\n * @param {string} containerId the id of media 'audio' or 'video' tag which\n *        renders the stream.\n */\nStatistics.prototype.associateStreamWithVideoTag = function(\n        tpc,\n        ssrc,\n        isLocal,\n        userId,\n        usageLabel,\n        containerId) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.associateStreamWithVideoTag(\n            ssrc,\n            isLocal,\n            userId,\n            usageLabel,\n            containerId);\n    }\n};\n\n/* eslint-enable max-params */\n\n/**\n * Notifies CallStats that getUserMedia failed.\n *\n * @param {Error} e error to send\n */\nStatistics.sendGetUserMediaFailed = function(e) {\n    const error\n        = e instanceof JitsiTrackError\n            ? formatJitsiTrackErrorForCallStats(e) : e;\n    const globalSet = Statistics._getAllCallStatsInstances();\n\n    if (globalSet.size) {\n        for (const cs of globalSet) {\n            CallStats.sendGetUserMediaFailed(error, cs);\n        }\n    } else {\n        CallStats.sendGetUserMediaFailed(error, null);\n    }\n};\n\n/**\n * Notifies CallStats that peer connection failed to create offer.\n *\n * @param {Error} e error to send\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n */\nStatistics.prototype.sendCreateOfferFailed = function(e, tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendCreateOfferFailed(e);\n    }\n};\n\n/**\n * Notifies CallStats that peer connection failed to create answer.\n *\n * @param {Error} e error to send\n * @param {TraceablePeerConnection} tpc connection on which failure occured.\n */\nStatistics.prototype.sendCreateAnswerFailed = function(e, tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendCreateAnswerFailed(e);\n    }\n};\n\n/**\n * Notifies CallStats that peer connection failed to set local description.\n *\n * @param {Error} e error to send\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n */\nStatistics.prototype.sendSetLocalDescFailed = function(e, tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendSetLocalDescFailed(e);\n    }\n};\n\n/**\n * Notifies CallStats that peer connection failed to set remote description.\n *\n * @param {Error} e error to send\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n */\nStatistics.prototype.sendSetRemoteDescFailed = function(e, tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendSetRemoteDescFailed(e);\n    }\n};\n\n/**\n * Notifies CallStats that peer connection failed to add ICE candidate.\n *\n * @param {Error} e error to send\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n */\nStatistics.prototype.sendAddIceCandidateFailed = function(e, tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendAddIceCandidateFailed(e);\n    }\n};\n\n/**\n * Adds to CallStats an application log.\n *\n * @param {String} m a log message to send or an {Error} object to be reported\n */\nStatistics.sendLog = function(m) {\n    const globalSubSet = new Set();\n\n    // FIXME we don't want to duplicate logs over P2P instance, but\n    // here we should go over instances and call this method for each\n    // unique conference ID rather than selecting the first one.\n    // We don't have such use case though, so leaving as is for now.\n    for (const stats of Statistics.instances) {\n        if (stats.callStatsApplicationLogsDisabled) {\n            return;\n        }\n\n        if (stats.callsStatsInstances.size) {\n            globalSubSet.add(stats.callsStatsInstances.values().next().value);\n        }\n    }\n\n    if (globalSubSet.size) {\n        for (const csPerStats of globalSubSet) {\n            CallStats.sendApplicationLog(m, csPerStats);\n        }\n    } else {\n        CallStats.sendApplicationLog(m, null);\n    }\n};\n\n/**\n * Sends the given feedback through CallStats.\n *\n * @param overall an integer between 1 and 5 indicating the user's rating.\n * @param comment the comment from the user.\n * @returns {Promise} Resolves when callstats feedback has been submitted\n * successfully.\n */\nStatistics.prototype.sendFeedback = function(overall, comment) {\n    // Statistics.analytics.sendEvent is currently fire and forget, without\n    // confirmation of successful send.\n    Statistics.analytics.sendEvent(\n        FEEDBACK,\n        {\n            rating: overall,\n            comment\n        });\n\n    return CallStats.sendFeedback(this.options.confID, overall, comment);\n};\n\nStatistics.LOCAL_JID = require('../../service/statistics/constants').LOCAL_JID;\n\n/**\n * Reports global error to CallStats.\n *\n * @param {Error} error\n */\nStatistics.reportGlobalError = function(error) {\n    if (error instanceof JitsiTrackError && error.gum) {\n        Statistics.sendGetUserMediaFailed(error);\n    } else {\n        Statistics.sendLog(error);\n    }\n};\n\n/**\n * Sends event to analytics and logs a message to the logger/console. Console\n * messages might also be logged to callstats automatically.\n *\n * @param {string | Object} event the event name, or an object which\n * represents the entire event.\n * @param {Object} properties properties to attach to the event (if an event\n * name as opposed to an event object is provided).\n */\nStatistics.sendAnalyticsAndLog = function(event, properties = {}) {\n    if (!event) {\n        logger.warn('No event or event name given.');\n\n        return;\n    }\n\n    let eventToLog;\n\n    // Also support an API with a single object as an event.\n    if (typeof event === 'object') {\n        eventToLog = event;\n    } else {\n        eventToLog = {\n            name: event,\n            properties\n        };\n    }\n\n    logger.log(JSON.stringify(eventToLog));\n\n    // We do this last, because it may modify the object which is passed.\n    this.analytics.sendEvent(event, properties);\n};\n\n/**\n * Sends event to analytics.\n *\n * @param {string | Object} eventName the event name, or an object which\n * represents the entire event.\n * @param {Object} properties properties to attach to the event\n */\nStatistics.sendAnalytics = function(eventName, properties = {}) {\n    this.analytics.sendEvent(eventName, properties);\n};\n","import { getLogger } from '@jitsi/logger';\nimport { Strophe } from 'strophe.js';\n\nimport * as JitsiConferenceErrors from './JitsiConferenceErrors';\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\nimport * as JitsiTrackEvents from './JitsiTrackEvents';\nimport { SPEAKERS_AUDIO_LEVELS } from './modules/statistics/constants';\nimport Statistics from './modules/statistics/statistics';\nimport EventEmitterForwarder from './modules/util/EventEmitterForwarder';\nimport { MediaType } from './service/RTC/MediaType';\nimport RTCEvents from './service/RTC/RTCEvents';\nimport { VideoType } from './service/RTC/VideoType';\nimport AuthenticationEvents\n    from './service/authentication/AuthenticationEvents';\nimport {\n    ACTION_JINGLE_SA_TIMEOUT,\n    createBridgeDownEvent,\n    createConnectionStageReachedEvent,\n    createFocusLeftEvent,\n    createJingleEvent,\n    createRemotelyMutedEvent\n} from './service/statistics/AnalyticsEvents';\nimport { XMPPEvents } from './service/xmpp/XMPPEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * Setups all event listeners related to conference\n * @param conference {JitsiConference} the conference\n */\nexport default function JitsiConferenceEventManager(conference) {\n    this.conference = conference;\n    this.xmppListeners = {};\n\n    // Listeners related to the conference only\n    conference.on(JitsiConferenceEvents.TRACK_MUTE_CHANGED,\n        track => {\n            if (!track.isLocal() || !conference.statistics) {\n                return;\n            }\n            const session\n                = track.isP2P\n                    ? conference.p2pJingleSession : conference.jvbJingleSession;\n\n            // TPC will be null, before the conference starts, but the event\n            // still should be queued\n            const tpc = (session && session.peerconnection) || null;\n\n            conference.statistics.sendMuteEvent(\n                tpc,\n                track.isMuted(),\n                track.getType());\n        });\n}\n\n/**\n * Setups event listeners related to conference.chatRoom\n */\nJitsiConferenceEventManager.prototype.setupChatRoomListeners = function() {\n    const conference = this.conference;\n    const chatRoom = conference.room;\n\n    this.chatRoomForwarder = new EventEmitterForwarder(chatRoom,\n        this.conference.eventEmitter);\n\n    chatRoom.addListener(XMPPEvents.ICE_RESTARTING, jingleSession => {\n        if (!jingleSession.isP2P) {\n            // If using DataChannel as bridge channel, it must be closed\n            // before ICE restart, otherwise Chrome will not trigger \"opened\"\n            // event for the channel established with the new bridge.\n            // TODO: This may be bypassed when using a WebSocket as bridge\n            // channel.\n            conference.rtc.closeBridgeChannel();\n        }\n\n        // else: there are no DataChannels in P2P session (at least for now)\n    });\n\n    chatRoom.addListener(XMPPEvents.PARTICIPANT_FEATURES_CHANGED, (from, features) => {\n        const participant = conference.getParticipantById(Strophe.getResourceFromJid(from));\n\n        if (participant) {\n            participant.setFeatures(features);\n            conference.eventEmitter.emit(JitsiConferenceEvents.PARTCIPANT_FEATURES_CHANGED, participant);\n        }\n    });\n\n    chatRoom.addListener(\n        XMPPEvents.ICE_RESTART_SUCCESS,\n        (jingleSession, offerIq) => {\n            // The JVB data chanel needs to be reopened in case the conference\n            // has been moved to a new bridge.\n            !jingleSession.isP2P\n                && conference._setBridgeChannel(\n                    offerIq, jingleSession.peerconnection);\n        });\n\n\n    chatRoom.addListener(XMPPEvents.AUDIO_MUTED_BY_FOCUS,\n        actor => {\n            // TODO: Add a way to differentiate between commands which caused\n            // us to mute and those that did not change our state (i.e. we were\n            // already muted).\n            Statistics.sendAnalytics(createRemotelyMutedEvent(MediaType.AUDIO));\n\n            conference.mutedByFocusActor = actor;\n\n            // set isMutedByFocus when setAudioMute Promise ends\n            conference.rtc.setAudioMute(true).then(\n                () => {\n                    conference.isMutedByFocus = true;\n                    conference.mutedByFocusActor = null;\n                })\n                .catch(\n                    error => {\n                        conference.mutedByFocusActor = null;\n                        logger.warn(\n                            'Error while audio muting due to focus request', error);\n                    });\n        }\n    );\n\n    chatRoom.addListener(XMPPEvents.VIDEO_MUTED_BY_FOCUS,\n        actor => {\n            // TODO: Add a way to differentiate between commands which caused\n            // us to mute and those that did not change our state (i.e. we were\n            // already muted).\n            Statistics.sendAnalytics(createRemotelyMutedEvent(MediaType.VIDEO));\n\n            conference.mutedVideoByFocusActor = actor;\n\n            // set isVideoMutedByFocus when setVideoMute Promise ends\n            conference.rtc.setVideoMute(true).then(\n                () => {\n                    conference.isVideoMutedByFocus = true;\n                    conference.mutedVideoByFocusActor = null;\n                })\n                .catch(\n                    error => {\n                        conference.mutedVideoByFocusActor = null;\n                        logger.warn(\n                            'Error while video muting due to focus request', error);\n                    });\n        }\n    );\n\n    this.chatRoomForwarder.forward(XMPPEvents.SUBJECT_CHANGED,\n        JitsiConferenceEvents.SUBJECT_CHANGED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_JOINED,\n        JitsiConferenceEvents.CONFERENCE_JOINED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_JOIN_IN_PROGRESS,\n        JitsiConferenceEvents.CONFERENCE_JOIN_IN_PROGRESS);\n\n    this.chatRoomForwarder.forward(XMPPEvents.MEETING_ID_SET,\n        JitsiConferenceEvents.CONFERENCE_UNIQUE_ID_SET);\n\n    // send some analytics events\n    chatRoom.addListener(XMPPEvents.MUC_JOINED,\n        () => {\n            this.conference._onMucJoined();\n\n            this.conference.isJvbConnectionInterrupted = false;\n\n            // TODO: Move all of the 'connectionTimes' logic to its own module.\n            Object.keys(chatRoom.connectionTimes).forEach(key => {\n                const event\n                    = createConnectionStageReachedEvent(\n                        `conference_${key}`,\n                        { value: chatRoom.connectionTimes[key] });\n\n                Statistics.sendAnalytics(event);\n            });\n\n            // TODO: Move all of the 'connectionTimes' logic to its own module.\n            Object.keys(chatRoom.xmpp.connectionTimes).forEach(key => {\n                const event\n                    = createConnectionStageReachedEvent(\n                        `xmpp_${key}`,\n                        { value: chatRoom.xmpp.connectionTimes[key] });\n\n                Statistics.sendAnalytics(event);\n            });\n        });\n\n    chatRoom.addListener(XMPPEvents.RENEGOTIATION_FAILED, (e, session) => {\n        if (!session.isP2P) {\n            conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n                JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\n        }\n    });\n\n    chatRoom.addListener(JitsiTrackEvents.TRACK_REMOVED, track => {\n        conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);\n    });\n\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_JOIN_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.CONNECTION_ERROR);\n\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_CONNECT_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.CONNECTION_ERROR);\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_CONNECT_NOT_ALLOWED_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.NOT_ALLOWED_ERROR);\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_CONNECT_MEMBERS_ONLY_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.MEMBERS_ONLY_ERROR);\n\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_MAX_USERS_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.CONFERENCE_MAX_USERS);\n    chatRoom.addListener(XMPPEvents.ROOM_MAX_USERS_ERROR, () => conference.leave());\n\n    this.chatRoomForwarder.forward(XMPPEvents.PASSWORD_REQUIRED,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.PASSWORD_REQUIRED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.AUTHENTICATION_REQUIRED,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.AUTHENTICATION_REQUIRED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.REDIRECTED,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.REDIRECTED);\n    chatRoom.addListener(XMPPEvents.REDIRECTED, () => conference.leave());\n\n    this.chatRoomForwarder.forward(XMPPEvents.BRIDGE_DOWN,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE);\n    chatRoom.addListener(\n        XMPPEvents.BRIDGE_DOWN,\n        () => Statistics.sendAnalytics(createBridgeDownEvent()));\n\n    chatRoom.addListener(XMPPEvents.CONNECTION_RESTARTED,\n        jingleSession => {\n            conference._onConferenceRestarted(jingleSession);\n        });\n\n    this.chatRoomForwarder.forward(XMPPEvents.RESERVATION_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.RESERVATION_ERROR);\n    chatRoom.addListener(XMPPEvents.RESERVATION_ERROR, () => conference.leave());\n\n    this.chatRoomForwarder.forward(XMPPEvents.GRACEFUL_SHUTDOWN,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.GRACEFUL_SHUTDOWN);\n\n    chatRoom.addListener(XMPPEvents.CONNECTION_ICE_FAILED,\n        jingleSession => {\n            conference._onIceConnectionFailed(jingleSession);\n        });\n\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_DESTROYED,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.CONFERENCE_DESTROYED);\n    chatRoom.addListener(XMPPEvents.MUC_DESTROYED, () => conference.leave());\n\n    this.chatRoomForwarder.forward(XMPPEvents.CHAT_ERROR_RECEIVED,\n        JitsiConferenceEvents.CONFERENCE_ERROR,\n        JitsiConferenceErrors.CHAT_ERROR);\n\n    this.chatRoomForwarder.forward(XMPPEvents.SETTINGS_ERROR_RECEIVED,\n        JitsiConferenceEvents.CONFERENCE_ERROR,\n        JitsiConferenceErrors.SETTINGS_ERROR);\n\n    this.chatRoomForwarder.forward(XMPPEvents.FOCUS_DISCONNECTED,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.FOCUS_DISCONNECTED);\n\n    chatRoom.addListener(XMPPEvents.FOCUS_LEFT,\n        () => {\n            Statistics.sendAnalytics(createFocusLeftEvent());\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.CONFERENCE_FAILED,\n                JitsiConferenceErrors.FOCUS_LEFT);\n        });\n\n    chatRoom.addListener(XMPPEvents.SESSION_ACCEPT_TIMEOUT,\n        jingleSession => {\n            Statistics.sendAnalyticsAndLog(\n                createJingleEvent(\n                    ACTION_JINGLE_SA_TIMEOUT,\n                    { p2p: jingleSession.isP2P }));\n        });\n\n    chatRoom.addListener(XMPPEvents.RECORDER_STATE_CHANGED,\n        (session, jid) => {\n\n            if (jid) {\n                const resource = Strophe.getResourceFromJid(jid);\n                const participant = conference.getParticipantById(resource) || resource;\n\n                if (session.getStatus() === 'off') {\n                    session.setTerminator(participant);\n                } else if (session.getStatus() === 'on') {\n                    session.setInitiator(participant);\n                }\n            }\n\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.RECORDER_STATE_CHANGED,\n                session);\n        });\n\n    this.chatRoomForwarder.forward(XMPPEvents.TRANSCRIPTION_STATUS_CHANGED,\n        JitsiConferenceEvents.TRANSCRIPTION_STATUS_CHANGED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED,\n        JitsiConferenceEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED);\n\n    this.chatRoomForwarder.forward(\n        XMPPEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED,\n        JitsiConferenceEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.PHONE_NUMBER_CHANGED,\n        JitsiConferenceEvents.PHONE_NUMBER_CHANGED);\n\n    chatRoom.setParticipantPropertyListener((node, from) => {\n        const participant = conference.getParticipantById(from);\n\n        if (!participant) {\n            return;\n        }\n\n        participant.setProperty(\n            node.tagName.substring('jitsi_participant_'.length),\n            node.value);\n    });\n\n    chatRoom.addListener(XMPPEvents.KICKED,\n        conference.onMemberKicked.bind(conference));\n    chatRoom.addListener(XMPPEvents.SUSPEND_DETECTED,\n        conference.onSuspendDetected.bind(conference));\n\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOCK_CHANGED,\n        JitsiConferenceEvents.LOCK_STATE_CHANGED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_MEMBERS_ONLY_CHANGED,\n        JitsiConferenceEvents.MEMBERS_ONLY_CHANGED);\n\n    chatRoom.addListener(XMPPEvents.MUC_MEMBER_JOINED,\n        conference.onMemberJoined.bind(conference));\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOBBY_MEMBER_JOINED,\n        JitsiConferenceEvents.LOBBY_USER_JOINED);\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOBBY_MEMBER_UPDATED,\n        JitsiConferenceEvents.LOBBY_USER_UPDATED);\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOBBY_MEMBER_LEFT,\n        JitsiConferenceEvents.LOBBY_USER_LEFT);\n    chatRoom.addListener(XMPPEvents.MUC_MEMBER_BOT_TYPE_CHANGED,\n        conference._onMemberBotTypeChanged.bind(conference));\n    chatRoom.addListener(XMPPEvents.MUC_MEMBER_LEFT,\n        conference.onMemberLeft.bind(conference));\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LEFT,\n        JitsiConferenceEvents.CONFERENCE_LEFT);\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_DENIED_ACCESS,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED);\n\n    chatRoom.addListener(XMPPEvents.DISPLAY_NAME_CHANGED,\n        conference.onDisplayNameChanged.bind(conference));\n\n    chatRoom.addListener(XMPPEvents.LOCAL_ROLE_CHANGED, role => {\n        conference.onLocalRoleChanged(role);\n\n        // log all events for the recorder operated by the moderator\n        if (conference.statistics && conference.isModerator()) {\n            conference.on(JitsiConferenceEvents.RECORDER_STATE_CHANGED,\n                recorderSession => {\n                    const logObject = {\n                        error: recorderSession.getError(),\n                        id: 'recorder_status',\n                        status: recorderSession.getStatus()\n                    };\n\n                    Statistics.sendLog(JSON.stringify(logObject));\n                });\n        }\n    });\n\n    chatRoom.addListener(XMPPEvents.MUC_ROLE_CHANGED,\n        conference.onUserRoleChanged.bind(conference));\n\n    chatRoom.addListener(AuthenticationEvents.IDENTITY_UPDATED,\n        (authEnabled, authIdentity) => {\n            conference.authEnabled = authEnabled;\n            conference.authIdentity = authIdentity;\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.AUTH_STATUS_CHANGED, authEnabled,\n                authIdentity);\n        });\n\n    chatRoom.addListener(\n        XMPPEvents.MESSAGE_RECEIVED,\n\n        // eslint-disable-next-line max-params\n        (jid, txt, myJid, ts, nick, isGuest) => {\n            const id = Strophe.getResourceFromJid(jid);\n\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.MESSAGE_RECEIVED,\n                id, txt, ts, nick, isGuest);\n        });\n\n    chatRoom.addListener(\n        XMPPEvents.PRIVATE_MESSAGE_RECEIVED,\n\n        // eslint-disable-next-line max-params\n        (jid, txt, myJid, ts) => {\n            const id = Strophe.getResourceFromJid(jid);\n\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.PRIVATE_MESSAGE_RECEIVED,\n                id, txt, ts);\n        });\n\n    chatRoom.addListener(XMPPEvents.PRESENCE_STATUS,\n        (jid, status) => {\n            const id = Strophe.getResourceFromJid(jid);\n            const participant = conference.getParticipantById(id);\n\n            if (!participant || participant._status === status) {\n                return;\n            }\n            participant._status = status;\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.USER_STATUS_CHANGED, id, status);\n        });\n\n    chatRoom.addListener(XMPPEvents.JSON_MESSAGE_RECEIVED,\n        (from, payload) => {\n            const id = Strophe.getResourceFromJid(from);\n            const participant = conference.getParticipantById(id);\n\n            if (participant) {\n                conference.eventEmitter.emit(\n                    JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\n                    participant, payload);\n            } else {\n                conference.eventEmitter.emit(\n                    JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED,\n                    id, payload);\n            }\n        });\n\n    chatRoom.addPresenceListener('startmuted', (data, from) => {\n        let isModerator = false;\n\n        if (conference.myUserId() === from && conference.isModerator()) {\n            isModerator = true;\n        } else {\n            const participant = conference.getParticipantById(from);\n\n            if (participant && participant.isModerator()) {\n                isModerator = true;\n            }\n        }\n\n        if (!isModerator) {\n            return;\n        }\n\n        const startAudioMuted = data.attributes.audio === 'true';\n        const startVideoMuted = data.attributes.video === 'true';\n\n        let updated = false;\n\n        if (startAudioMuted !== conference.startMutedPolicy.audio) {\n            conference.startMutedPolicy.audio = startAudioMuted;\n            updated = true;\n        }\n\n        if (startVideoMuted !== conference.startMutedPolicy.video) {\n            conference.startMutedPolicy.video = startVideoMuted;\n            updated = true;\n        }\n\n        if (updated) {\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.START_MUTED_POLICY_CHANGED,\n                conference.startMutedPolicy\n            );\n        }\n    });\n\n    if (conference.statistics) {\n        // FIXME ICE related events should end up in RTCEvents eventually\n        chatRoom.addListener(XMPPEvents.CONNECTION_ICE_FAILED,\n            session => {\n                conference.statistics.sendIceConnectionFailedEvent(\n                    session.peerconnection);\n            });\n\n        // FIXME XMPPEvents.ADD_ICE_CANDIDATE_FAILED is never emitted\n        chatRoom.addListener(XMPPEvents.ADD_ICE_CANDIDATE_FAILED,\n            (e, pc) => {\n                conference.statistics.sendAddIceCandidateFailed(e, pc);\n            });\n    }\n\n    // Breakout rooms.\n    this.chatRoomForwarder.forward(XMPPEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM,\n        JitsiConferenceEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM);\n    this.chatRoomForwarder.forward(XMPPEvents.BREAKOUT_ROOMS_UPDATED,\n        JitsiConferenceEvents.BREAKOUT_ROOMS_UPDATED);\n\n    // Room metadata.\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_METADATA_UPDATED,\n        JitsiConferenceEvents.METADATA_UPDATED);\n};\n\n/**\n * Setups event listeners related to conference.rtc\n */\nJitsiConferenceEventManager.prototype.setupRTCListeners = function() {\n    const conference = this.conference;\n    const rtc = conference.rtc;\n\n    rtc.addListener(\n        RTCEvents.REMOTE_TRACK_ADDED,\n        conference.onRemoteTrackAdded.bind(conference));\n\n    rtc.addListener(\n        RTCEvents.REMOTE_TRACK_REMOVED,\n        conference.onRemoteTrackRemoved.bind(conference));\n\n    rtc.addListener(RTCEvents.DOMINANT_SPEAKER_CHANGED,\n        (dominant, previous, silence) => {\n            if ((conference.lastDominantSpeaker !== dominant || conference.dominantSpeakerIsSilent !== silence)\n                    && conference.room) {\n                conference.lastDominantSpeaker = dominant;\n                conference.dominantSpeakerIsSilent = silence;\n                conference.eventEmitter.emit(\n                    JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED, dominant, previous, silence);\n                if (conference.statistics && conference.myUserId() === dominant) {\n                    // We are the new dominant speaker.\n                    conference.statistics.sendDominantSpeakerEvent(conference.room.roomjid, silence);\n                }\n                if (conference.lastDominantSpeaker !== dominant) {\n                    if (previous && previous.length) {\n                        const speakerList = previous.slice(0);\n\n                        // Add the dominant speaker to the top of the list (exclude self).\n                        if (conference.myUserId !== dominant) {\n                            speakerList.splice(0, 0, dominant);\n                        }\n\n                        // Trim the list to the top 5 speakers only.\n                        if (speakerList.length > SPEAKERS_AUDIO_LEVELS) {\n                            speakerList.splice(SPEAKERS_AUDIO_LEVELS, speakerList.length - SPEAKERS_AUDIO_LEVELS);\n                        }\n                        conference.statistics && conference.statistics.setSpeakerList(speakerList);\n                    }\n                }\n            }\n        });\n\n    rtc.addListener(RTCEvents.DATA_CHANNEL_OPEN, () => {\n        const now = window.performance.now();\n        const key = 'data.channel.opened';\n\n        // TODO: Move all of the 'connectionTimes' logic to its own module.\n        logger.log(`(TIME) ${key}:\\t`, now);\n        conference.room.connectionTimes[key] = now;\n        Statistics.sendAnalytics(\n            createConnectionStageReachedEvent(key, { value: now }));\n\n        conference.eventEmitter.emit(JitsiConferenceEvents.DATA_CHANNEL_OPENED);\n    });\n\n    rtc.addListener(RTCEvents.DATA_CHANNEL_CLOSED, ev => {\n        conference.eventEmitter.emit(JitsiConferenceEvents.DATA_CHANNEL_CLOSED, ev);\n    });\n\n    rtc.addListener(RTCEvents.VIDEO_SSRCS_REMAPPED, msg => {\n        for (const session of this.conference.getMediaSessions()) {\n            session.processSourceMap(msg, MediaType.VIDEO);\n        }\n    });\n\n    rtc.addListener(RTCEvents.AUDIO_SSRCS_REMAPPED, msg => {\n        for (const session of this.conference.getMediaSessions()) {\n            session.processSourceMap(msg, MediaType.AUDIO);\n        }\n    });\n\n    rtc.addListener(RTCEvents.ENDPOINT_MESSAGE_RECEIVED,\n        (from, payload) => {\n            const participant = conference.getParticipantById(from);\n\n            if (participant) {\n                conference.eventEmitter.emit(\n                    JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\n                    participant, payload);\n            } else {\n                logger.warn(\n                    'Ignored ENDPOINT_MESSAGE_RECEIVED for not existing '\n                        + `participant: ${from}`,\n                    payload);\n            }\n        });\n\n    rtc.addListener(RTCEvents.ENDPOINT_STATS_RECEIVED,\n        (from, payload) => {\n            const participant = conference.getParticipantById(from);\n\n            if (participant) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.ENDPOINT_STATS_RECEIVED, participant, payload);\n            } else {\n                logger.warn(`Ignoring ENDPOINT_STATS_RECEIVED for a non-existant participant: ${from}`);\n            }\n        });\n\n    rtc.addListener(RTCEvents.LOCAL_UFRAG_CHANGED,\n        (tpc, ufrag) => {\n            if (!tpc.isP2P) {\n                Statistics.sendLog(\n                    JSON.stringify({\n                        id: 'local_ufrag',\n                        value: ufrag\n                    }));\n            }\n        });\n    rtc.addListener(RTCEvents.REMOTE_UFRAG_CHANGED,\n        (tpc, ufrag) => {\n            if (!tpc.isP2P) {\n                Statistics.sendLog(\n                    JSON.stringify({\n                        id: 'remote_ufrag',\n                        value: ufrag\n                    }));\n            }\n        });\n\n    rtc.addListener(RTCEvents.CREATE_ANSWER_FAILED,\n        (e, tpc) => {\n            conference.statistics.sendCreateAnswerFailed(e, tpc);\n            if (!tpc.isP2P) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\n            }\n        });\n\n    rtc.addListener(RTCEvents.CREATE_OFFER_FAILED,\n        (e, tpc) => {\n            conference.statistics.sendCreateOfferFailed(e, tpc);\n            if (!tpc.isP2P) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\n            }\n        });\n\n    rtc.addListener(RTCEvents.SET_LOCAL_DESCRIPTION_FAILED,\n        (e, tpc) => {\n            conference.statistics.sendSetLocalDescFailed(e, tpc);\n            if (!tpc.isP2P) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\n            }\n        });\n\n    rtc.addListener(RTCEvents.SET_REMOTE_DESCRIPTION_FAILED,\n        (e, tpc) => {\n            conference.statistics.sendSetRemoteDescFailed(e, tpc);\n            if (!tpc.isP2P) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\n            }\n        });\n\n    rtc.addListener(RTCEvents.LOCAL_TRACK_SSRC_UPDATED,\n        (track, ssrc) => {\n            // when starting screen sharing, the track is created and when\n            // we do set local description and we process the ssrc we\n            // will be notified for it and we will report it with the event\n            // for screen sharing\n            if (track.isVideoTrack() && track.videoType === VideoType.DESKTOP) {\n                conference.statistics.sendScreenSharingEvent(true, ssrc);\n            }\n        });\n};\n\n/**\n * Removes event listeners related to conference.xmpp\n */\nJitsiConferenceEventManager.prototype.removeXMPPListeners = function() {\n    const conference = this.conference;\n\n    Object.keys(this.xmppListeners).forEach(eventName => {\n        conference.xmpp.removeListener(\n            eventName,\n            this.xmppListeners[eventName]);\n    });\n    this.xmppListeners = {};\n};\n\n\n/**\n * Setups event listeners related to conference.xmpp\n */\nJitsiConferenceEventManager.prototype.setupXMPPListeners = function() {\n    const conference = this.conference;\n\n    this._addConferenceXMPPListener(\n        XMPPEvents.CALL_INCOMING,\n        conference.onIncomingCall.bind(conference));\n    this._addConferenceXMPPListener(\n        XMPPEvents.CALL_ACCEPTED,\n        conference.onCallAccepted.bind(conference));\n    this._addConferenceXMPPListener(\n        XMPPEvents.TRANSPORT_INFO,\n        conference.onTransportInfo.bind(conference));\n    this._addConferenceXMPPListener(\n        XMPPEvents.CALL_ENDED,\n        conference.onCallEnded.bind(conference));\n\n    this._addConferenceXMPPListener(XMPPEvents.START_MUTED_FROM_FOCUS,\n        (audioMuted, videoMuted) => {\n            if (conference.options.config.ignoreStartMuted) {\n                return;\n            }\n\n            conference.startAudioMuted = audioMuted;\n            conference.startVideoMuted = videoMuted;\n\n            if (audioMuted) {\n                conference.isMutedByFocus = true;\n            }\n\n            if (videoMuted) {\n                conference.isVideoMutedByFocus = true;\n            }\n\n            // mute existing local tracks because this is initial mute from\n            // Jicofo\n            conference.getLocalTracks().forEach(track => {\n                switch (track.getType()) {\n                case MediaType.AUDIO:\n                    conference.startAudioMuted && track.mute();\n                    break;\n                case MediaType.VIDEO:\n                    conference.startVideoMuted && track.mute();\n                    break;\n                }\n            });\n\n            conference.eventEmitter.emit(JitsiConferenceEvents.STARTED_MUTED);\n        });\n\n    this._addConferenceXMPPListener(XMPPEvents.CONFERENCE_TIMESTAMP_RECEIVED,\n        createdTimestamp => {\n            conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_CREATED_TIMESTAMP, createdTimestamp);\n        });\n\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_CHANGED,\n        (value, mediaType, actorJid) => {\n            const actorParticipant = conference.getParticipants().find(p => p.getJid() === actorJid);\n\n            conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_CHANGED, {\n                enabled: value,\n                mediaType,\n                actor: actorParticipant\n            });\n        });\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_PARTICIPANT_APPROVED,\n        (mediaType, jid) => {\n            const participant = conference.getParticipantById(Strophe.getResourceFromJid(jid));\n\n            if (participant) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_APPROVED, {\n                    participant,\n                    mediaType\n                });\n            }\n        });\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_PARTICIPANT_REJECTED,\n        (mediaType, jid) => {\n            const participant = conference.getParticipantById(Strophe.getResourceFromJid(jid));\n\n            if (participant) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_REJECTED, {\n                    participant,\n                    mediaType\n                });\n            }\n        });\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_APPROVED,\n        value => conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_APPROVED, { mediaType: value }));\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_REJECTED,\n        value => {\n            conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_REJECTED, { mediaType: value });\n        });\n};\n\n/**\n * Add XMPP listener and save its reference for remove on leave conference.\n */\nJitsiConferenceEventManager.prototype._addConferenceXMPPListener = function(\n        eventName, listener) {\n    this.xmppListeners[eventName] = listener;\n    this.conference.xmpp.addListener(eventName, listener);\n};\n\n/**\n * Setups event listeners related to conference.statistics\n */\nJitsiConferenceEventManager.prototype.setupStatisticsListeners = function() {\n    const conference = this.conference;\n\n    if (!conference.statistics) {\n        return;\n    }\n\n    /* eslint-disable max-params */\n    conference.statistics.addAudioLevelListener((tpc, ssrc, level, isLocal) => {\n        conference.rtc.setAudioLevel(tpc, ssrc, level, isLocal);\n    });\n\n    /* eslint-enable max-params */\n\n    // Forward the \"before stats disposed\" event\n    conference.statistics.addBeforeDisposedListener(() => {\n        conference.eventEmitter.emit(\n            JitsiConferenceEvents.BEFORE_STATISTICS_DISPOSED);\n    });\n\n    // if we are in startSilent mode we will not be sending/receiving so nothing to detect\n    if (!conference.options.config.startSilent) {\n        conference.statistics.addByteSentStatsListener((tpc, stats) => {\n            conference.getLocalTracks(MediaType.AUDIO).forEach(track => {\n                const ssrc = tpc.getLocalSSRC(track);\n\n                if (!ssrc || !stats.hasOwnProperty(ssrc)) {\n                    return;\n                }\n\n                track.onByteSentStatsReceived(tpc, stats[ssrc]);\n            });\n        });\n    }\n};\n","\nimport { Strophe } from 'strophe.js';\n\n\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\nimport { MediaType } from './service/RTC/MediaType';\n\n/**\n * Represents a participant in (i.e. a member of) a conference.\n */\nexport default class JitsiParticipant {\n\n    /* eslint-disable max-params */\n\n    /**\n     * Initializes a new JitsiParticipant instance.\n     *\n     * @constructor\n     * @param jid the conference XMPP jid\n     * @param conference\n     * @param displayName\n     * @param {Boolean} hidden - True if the new JitsiParticipant instance is to\n     * represent a hidden participant; otherwise, false.\n     * @param {string} statsID - optional participant statsID\n     * @param {string} status - the initial status if any.\n     * @param {object} identity - the xmpp identity\n     * @param {boolean?} isReplacing - whether this is a participant replacing another into the meeting.\n     * @param {boolean?} isReplaced - whether this is a participant to be kicked and replaced into the meeting.\n     */\n    constructor(jid, conference, displayName, hidden, statsID, status, identity, isReplacing, isReplaced) {\n        this._jid = jid;\n        this._id = Strophe.getResourceFromJid(jid);\n        this._conference = conference;\n        this._displayName = displayName;\n        this._supportsDTMF = false;\n        this._tracks = [];\n        this._role = 'none';\n        this._status = status;\n        this._hidden = hidden;\n        this._statsID = statsID;\n        this._properties = {};\n        this._identity = identity;\n        this._isReplacing = isReplacing;\n        this._isReplaced = isReplaced;\n        this._features = new Set();\n\n        /**\n         * Remote sources associated with the participant in the following format.\n         * Map<mediaType, Map<sourceName, sourceInfo>>\n         *\n         * mediaType - 'audio' or 'video'.\n         * sourceName - name of the remote source.\n         * sourceInfo: {\n         *   muted: boolean;\n         *   videoType: string;\n         * }\n         */\n        this._sources = new Map();\n    }\n\n    /**\n     * Determines whether all JitsiTracks which are of a specific MediaType and which belong to this\n     * JitsiParticipant are muted.\n     *\n     * @param {MediaType} mediaType - The MediaType of the JitsiTracks to be checked.\n     * @private\n     * @returns {Boolean} True if all JitsiTracks which are of the specified mediaType and which belong to this\n     * JitsiParticipant are muted; otherwise, false.\n     */\n    _isMediaTypeMuted(mediaType) {\n        return this.getTracks().reduce(\n            (muted, track) =>\n                muted && (track.getType() !== mediaType || track.isMuted()),\n            true);\n    }\n\n    /**\n     * Sets source info.\n     * @param {MediaType} mediaType The media type, 'audio' or 'video'.\n     * @param {boolean} muted The new muted state.\n     * @param {string} sourceName The name of the source.\n     * @param {string} videoType The video type of the source.\n     * @returns {void}\n     */\n    _setSources(mediaType, muted, sourceName, videoType) {\n        let sourceByMediaType = this._sources.get(mediaType);\n        const sourceInfo = {\n            muted,\n            videoType\n        };\n\n        if (sourceByMediaType?.size) {\n            sourceByMediaType.set(sourceName, sourceInfo);\n\n            return;\n        }\n\n        sourceByMediaType = new Map();\n        sourceByMediaType.set(sourceName, sourceInfo);\n        this._sources.set(mediaType, sourceByMediaType);\n    }\n\n    /**\n     * Returns the bot type for the participant.\n     *\n     * @returns {string|undefined} - The bot type of the participant.\n     */\n    getBotType() {\n        return this._botType;\n    }\n\n    /**\n     * @returns {JitsiConference} The conference that this participant belongs\n     * to.\n     */\n    getConference() {\n        return this._conference;\n    }\n\n    /**\n     * Returns the connection jid for the participant.\n     *\n     * @returns {string|undefined} - The connection jid of the participant.\n     */\n    getConnectionJid() {\n        return this._connectionJid;\n    }\n\n    /**\n     * @returns {String} The human-readable display name of this participant.\n     */\n    getDisplayName() {\n        return this._displayName;\n    }\n\n    /**\n     * Returns a set with the features for the participant.\n     * @returns {Promise<Set<String>, Error>}\n     */\n    getFeatures() {\n        return Promise.resolve(this._features);\n    }\n\n    /**\n     * @returns {String} The ID of this participant.\n     */\n    getId() {\n        return this._id;\n    }\n\n    /**\n     * @returns {String} The JID of this participant.\n     */\n    getJid() {\n        return this._jid;\n    }\n\n    /**\n     * Gets the value of a property of this participant.\n     */\n    getProperty(name) {\n        return this._properties[name];\n    }\n\n    /**\n     * @returns {String} The role of this participant.\n     */\n    getRole() {\n        return this._role;\n    }\n\n    /**\n     * Returns the sources associated with this participant.\n     * @returns Map<string, Map<string, Object>>\n     */\n    getSources() {\n        return this._sources;\n    }\n\n    /**\n     * @returns {String} The stats ID of this participant.\n     */\n    getStatsID() {\n        return this._statsID;\n    }\n\n    /**\n     * @returns {String} The status of the participant.\n     */\n    getStatus() {\n        return this._status;\n    }\n\n    /**\n     * @returns {Array.<JitsiTrack>} The list of media tracks for this\n     * participant.\n     */\n    getTracks() {\n        return this._tracks.slice();\n    }\n\n    /**\n     * @param {MediaType} mediaType\n     * @returns {Array.<JitsiTrack>} an array of media tracks for this\n     * participant, for given media type.\n     */\n    getTracksByMediaType(mediaType) {\n        return this.getTracks().filter(track => track.getType() === mediaType);\n    }\n\n    /**\n     * Checks current set features.\n     * @param {String} feature - the feature to check.\n     * @return {boolean} <tt>true</tt> if this <tt>participant</tt> contains the\n     * <tt>feature</tt>.\n     */\n    hasFeature(feature) {\n        return this._features.has(feature);\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant has muted their audio.\n     */\n    isAudioMuted() {\n        return this._isMediaTypeMuted(MediaType.AUDIO);\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant is a hidden participant. Some\n     * special system participants may want to join hidden (like for example the\n     * recorder).\n     */\n    isHidden() {\n        return this._hidden;\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant is a hidden participant. Some\n     * special system participants may want to join hidden (like for example the\n     * recorder).\n     */\n    isHiddenFromRecorder() {\n        return this._identity?.user?.['hidden-from-recorder'] === 'true';\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant is a moderator or not.\n     */\n    isModerator() {\n        return this._role === 'moderator';\n    }\n\n    /**\n     * @returns {Boolean} Wheter this participants will be replaced by another\n     * participant in the meeting.\n     */\n    isReplaced() {\n        return this._isReplaced;\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant replaces another participant\n     * from the meeting.\n     */\n    isReplacing() {\n        return this._isReplacing;\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant has muted their video.\n     */\n    isVideoMuted() {\n        return this._isMediaTypeMuted(MediaType.VIDEO);\n    }\n\n    /**\n     * Sets the bot type for the participant.\n     * @param {String} newBotType - The new bot type to set.\n     */\n    setBotType(newBotType) {\n        this._botType = newBotType;\n    }\n\n    /**\n     * Sets the connection jid for the participant.\n     * @param {String} newJid - The connection jid to set.\n     */\n    setConnectionJid(newJid) {\n        this._connectionJid = newJid;\n    }\n\n    /**\n     * Set new features.\n     * @param {Set<String>|undefined} newFeatures - Sets new features.\n     */\n    setFeatures(newFeatures) {\n        this._features = newFeatures || new Set();\n    }\n\n    /**\n     * Sets whether participant is being replaced by another based on jwt.\n     * @param {boolean} newIsReplaced - whether is being replaced.\n     */\n    setIsReplaced(newIsReplaced) {\n        this._isReplaced = newIsReplaced;\n    }\n\n    /**\n     * Sets whether participant is replacing another based on jwt.\n     * @param {String} newIsReplacing - whether is replacing.\n     */\n    setIsReplacing(newIsReplacing) {\n        this._isReplacing = newIsReplacing;\n    }\n\n    /**\n     * Sets the value of a property of this participant, and fires an event if\n     * the value has changed.\n     * @name the name of the property.\n     * @value the value to set.\n     */\n    setProperty(name, value) {\n        const oldValue = this._properties[name];\n\n        if (value !== oldValue) {\n            this._properties[name] = value;\n            this._conference.eventEmitter.emit(\n                JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,\n                this,\n                name,\n                oldValue,\n                value);\n        }\n    }\n\n    /**\n     * Sets a new participant role.\n     * @param {String} newRole - the new role.\n     */\n    setRole(newRole) {\n        this._role = newRole;\n    }\n\n    /**\n     *\n     */\n    supportsDTMF() {\n        return this._supportsDTMF;\n    }\n}\n","/**\n * The events for the connection.\n */\n\nexport enum JitsiConnectionEvents {\n    /**\n     * Indicates that the connection has been disconnected. The event provides\n     * the following parameters to its listeners:\n     *\n     * @param msg {string} a message associated with the disconnect such as the\n     * last (known) error message\n     */\n    CONNECTION_DISCONNECTED = 'connection.connectionDisconnected',\n\n    /**\n     * Indicates that the connection has been established. The event provides\n     * the following parameters to its listeners:\n     *\n     * @param id {string} the ID of the local endpoint/participant/peer (within\n     * the context of the established connection)\n     */\n    CONNECTION_ESTABLISHED = 'connection.connectionEstablished',\n\n    /**\n     * Indicates that the connection has been failed for some reason. The event\n     * provides the following parameters to its listeners:\n     *\n     * @param errType {JitsiConnectionErrors} the type of error associated with\n     * the failure\n     * @param errReason {string} the error (message) associated with the failure\n     * @param credentials {object} the credentials used to connect (if any)\n     * @param errReasonDetails {object} an optional object with details about\n     * the error, like shard moving, suspending. Used for analytics purposes.\n     */\n    CONNECTION_FAILED = 'connection.connectionFailed',\n\n    /**\n     * Indicates that the performed action cannot be executed because the\n     * connection is not in the correct state(connected, disconnected, etc.)\n     */\n    WRONG_STATE = 'connection.wrongState',\n\n    /**\n     * Indicates that the display name is required over this connection and need to be supplied when\n     * joining the room.\n     * There are cases like lobby room where display name is required.\n     */\n    DISPLAY_NAME_REQUIRED = 'connection.display_name_required'\n};\n\n// exported for backward compatibility\nexport const CONNECTION_DISCONNECTED = JitsiConnectionEvents.CONNECTION_DISCONNECTED;\nexport const CONNECTION_ESTABLISHED = JitsiConnectionEvents.CONNECTION_ESTABLISHED;\nexport const CONNECTION_FAILED = JitsiConnectionEvents.CONNECTION_FAILED;\nexport const WRONG_STATE = JitsiConnectionEvents.WRONG_STATE;\nexport const DISPLAY_NAME_REQUIRED = JitsiConnectionEvents.DISPLAY_NAME_REQUIRED;\n","/**\n * The errors for the connection.\n */\n\nexport enum JitsiConnectionErrors {\n    /**\n     * Indicates that the connection was dropped with an error which was most likely\n     * caused by some networking issues. The dropped term in this context means that\n     * the connection was closed unexpectedly (not on user's request).\n     *\n     * One example is 'item-not-found' error thrown by Prosody when the BOSH session\n     * times out after 60 seconds of inactivity. On the other hand 'item-not-found'\n     * could also happen when BOSH request is sent to the server with the session-id\n     * that is not know to the server. But this should not happen in lib-jitsi-meet\n     * case as long as the service is configured correctly (there is no bug).\n     */\n    CONNECTION_DROPPED_ERROR = 'connection.droppedError',\n\n    /**\n     * Not specified errors.\n     */\n    OTHER_ERROR = 'connection.otherError',\n\n    /**\n     * Indicates that a password is required in order to join the conference.\n     */\n    PASSWORD_REQUIRED = 'connection.passwordRequired',\n\n    /**\n     * Indicates that the connection was dropped, because of too many 5xx HTTP\n     * errors on BOSH requests.\n     */\n    SERVER_ERROR = 'connection.serverError'\n};\n\n// exported for backward compatibility\nexport const CONNECTION_DROPPED_ERROR = JitsiConnectionErrors.CONNECTION_DROPPED_ERROR;\nexport const OTHER_ERROR = JitsiConnectionErrors.OTHER_ERROR;\nexport const PASSWORD_REQUIRED = JitsiConnectionErrors.PASSWORD_REQUIRED;\nexport const SERVER_ERROR = JitsiConnectionErrors.SERVER_ERROR;\n","\n/**\n * Promise-like object which can be passed around for resolving it later. It\n * implements the \"thenable\" interface, so it can be used wherever a Promise\n * could be used.\n *\n * In addition a \"reject on timeout\" functionality is provided.\n */\nexport default class Deferred {\n    /**\n     * Instantiates a Deferred object.\n     */\n    constructor() {\n        this.promise = new Promise((resolve, reject) => {\n            this.resolve = (...args) => {\n                this.clearRejectTimeout();\n                resolve(...args);\n            };\n            this.reject = (...args) => {\n                this.clearRejectTimeout();\n                reject(...args);\n            };\n        });\n        this.then = this.promise.then.bind(this.promise);\n        this.catch = this.promise.catch.bind(this.promise);\n    }\n\n    /**\n     * Clears the reject timeout.\n     */\n    clearRejectTimeout() {\n        clearTimeout(this._timeout);\n    }\n\n    /**\n     * Rejects the promise after the given timeout.\n     */\n    setRejectTimeout(ms) {\n        this._timeout = setTimeout(() => {\n            this.reject(new Error('timeout'));\n        }, ms);\n    }\n}\n","import EventEmitter from 'events';\n\n/**\n * The class implements basic event operations - add/remove listener.\n * NOTE: The purpose of the class is to be extended in order to add\n * this functionality to other classes.\n */\nexport default class Listenable {\n    /**\n     * Creates new instance.\n     * @param {EventEmitter} eventEmitter\n     * @constructor\n     */\n    constructor(eventEmitter = new EventEmitter()) {\n        this.eventEmitter = eventEmitter;\n\n        // aliases for addListener/removeListener\n        this.addEventListener = this.on = this.addListener;\n        this.removeEventListener = this.off = this.removeListener;\n    }\n\n    /**\n     * Adds new listener.\n     * @param {String} eventName the name of the event\n     * @param {Function} listener the listener.\n     * @returns {Function} - The unsubscribe function.\n     */\n    addListener(eventName, listener) {\n        this.eventEmitter.addListener(eventName, listener);\n\n        return () => this.removeEventListener(eventName, listener);\n    }\n\n    /**\n     * Removes listener.\n     * @param {String} eventName the name of the event that triggers the\n     * listener\n     * @param {Function} listener the listener.\n     */\n    removeListener(eventName, listener) {\n        this.eventEmitter.removeListener(eventName, listener);\n    }\n}\n","/* global RTCRtpScriptTransform */\n\nimport { getLogger } from '@jitsi/logger';\n\nconst logger = getLogger(__filename);\n\n// Flag to set on senders / receivers to avoid setting up the encryption transform\n// more than once.\nconst kJitsiE2EE = Symbol('kJitsiE2EE');\n\n/**\n * Context encapsulating the cryptography bits required for E2EE.\n * This uses the WebRTC Insertable Streams API which is explained in\n *   https://github.com/alvestrand/webrtc-media-streams/blob/master/explainer.md\n * that provides access to the encoded frames and allows them to be transformed.\n *\n * The encoded frame format is explained below in the _encodeFunction method.\n * High level design goals were:\n * - do not require changes to existing SFUs and retain (VP8) metadata.\n * - allow the SFU to rewrite SSRCs, timestamp, pictureId.\n * - allow for the key to be rotated frequently.\n */\nexport default class E2EEcontext {\n    /**\n     * Build a new E2EE context instance, which will be used in a given conference.\n     * @param {boolean} [options.sharedKey] - whether there is a uniques key shared amoung all participants.\n     */\n    constructor({ sharedKey } = {}) {\n        // Determine the URL for the worker script. Relative URLs are relative to\n        // the entry point, not the script that launches the worker.\n        let baseUrl = '';\n        const ljm = document.querySelector('script[src*=\"lib-jitsi-meet\"]');\n\n        if (ljm) {\n            const idx = ljm.src.lastIndexOf('/');\n\n            baseUrl = `${ljm.src.substring(0, idx)}/`;\n        }\n\n        let workerUrl = `${baseUrl}lib-jitsi-meet.e2ee-worker.js`;\n\n        // If there is no baseUrl then we create the worker in a normal way\n        // as you cant load scripts inside blobs from relative paths.\n        // See: https://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers-loadingscripts\n        if (baseUrl && baseUrl !== '/') {\n            // Initialize the E2EE worker. In order to avoid CORS issues, start the worker and have it\n            // synchronously load the JS.\n            const workerBlob\n                = new Blob([ `importScripts(\"${workerUrl}\");` ], { type: 'application/javascript' });\n\n            workerUrl = window.URL.createObjectURL(workerBlob);\n        }\n\n        this._worker = new Worker(workerUrl, { name: 'E2EE Worker' });\n\n        this._worker.onerror = e => logger.error(e);\n\n        this._worker.postMessage({\n            operation: 'initialize',\n            sharedKey\n        });\n    }\n\n    /**\n     * Cleans up all state associated with the given participant. This is needed when a\n     * participant leaves the current conference.\n     *\n     * @param {string} participantId - The participant that just left.\n     */\n    cleanup(participantId) {\n        this._worker.postMessage({\n            operation: 'cleanup',\n            participantId\n        });\n    }\n\n    /**\n     * Cleans up all state associated with all participants in the conference. This is needed when disabling e2ee.\n     *\n     */\n    cleanupAll() {\n        this._worker.postMessage({\n            operation: 'cleanupAll'\n        });\n    }\n\n    /**\n     * Handles the given {@code RTCRtpReceiver} by creating a {@code TransformStream} which will inject\n     * a frame decoder.\n     *\n     * @param {RTCRtpReceiver} receiver - The receiver which will get the decoding function injected.\n     * @param {string} kind - The kind of track this receiver belongs to.\n     * @param {string} participantId - The participant id that this receiver belongs to.\n     */\n    handleReceiver(receiver, kind, participantId) {\n        if (receiver[kJitsiE2EE]) {\n            return;\n        }\n        receiver[kJitsiE2EE] = true;\n\n        if (window.RTCRtpScriptTransform) {\n            const options = {\n                operation: 'decode',\n                participantId\n            };\n\n            receiver.transform = new RTCRtpScriptTransform(this._worker, options);\n        } else {\n            const receiverStreams = receiver.createEncodedStreams();\n\n            this._worker.postMessage({\n                operation: 'decode',\n                readableStream: receiverStreams.readable,\n                writableStream: receiverStreams.writable,\n                participantId\n            }, [ receiverStreams.readable, receiverStreams.writable ]);\n        }\n    }\n\n    /**\n     * Handles the given {@code RTCRtpSender} by creating a {@code TransformStream} which will inject\n     * a frame encoder.\n     *\n     * @param {RTCRtpSender} sender - The sender which will get the encoding function injected.\n     * @param {string} kind - The kind of track this sender belongs to.\n     * @param {string} participantId - The participant id that this sender belongs to.\n     */\n    handleSender(sender, kind, participantId) {\n        if (sender[kJitsiE2EE]) {\n            return;\n        }\n        sender[kJitsiE2EE] = true;\n\n        if (window.RTCRtpScriptTransform) {\n            const options = {\n                operation: 'encode',\n                participantId\n            };\n\n            sender.transform = new RTCRtpScriptTransform(this._worker, options);\n        } else {\n            const senderStreams = sender.createEncodedStreams();\n\n            this._worker.postMessage({\n                operation: 'encode',\n                readableStream: senderStreams.readable,\n                writableStream: senderStreams.writable,\n                participantId\n            }, [ senderStreams.readable, senderStreams.writable ]);\n        }\n    }\n\n    /**\n     * Set the E2EE key for the specified participant.\n     *\n     * @param {string} participantId - the ID of the participant who's key we are setting.\n     * @param {Uint8Array | boolean} key - they key for the given participant.\n     * @param {Number} keyIndex - the key index.\n     */\n    setKey(participantId, key, keyIndex) {\n        this._worker.postMessage({\n            operation: 'setKey',\n            key,\n            keyIndex,\n            participantId\n        });\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport browser from '../browser';\nimport Deferred from '../util/Deferred';\nimport Listenable from '../util/Listenable';\n\nimport E2EEContext from './E2EEContext';\n\nconst logger = getLogger(__filename);\n\n/**\n * Abstract class that integrates {@link E2EEContext} with a key management system.\n */\nexport class KeyHandler extends Listenable {\n    /**\n     * Build a new KeyHandler instance, which will be used in a given conference.\n     * @param {JitsiConference} conference - the current conference.\n     * @param {object} options - the options passed to {E2EEContext}, see implemention.\n     */\n    constructor(conference, options = {}) {\n        super();\n\n        this.conference = conference;\n        this.e2eeCtx = new E2EEContext(options);\n\n        this.enabled = false;\n        this._enabling = undefined;\n\n        // Conference media events in order to attach the encryptor / decryptor.\n        // FIXME add events to TraceablePeerConnection which will allow to see when there's new receiver or sender\n        // added instead of shenanigans around conference track events and track muted.\n        //\n\n        this.conference.on(\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\n            this._onMediaSessionStarted.bind(this));\n        this.conference.on(\n            JitsiConferenceEvents.TRACK_ADDED,\n            track => track.isLocal() && this._onLocalTrackAdded(track));\n        this.conference.rtc.on(\n            RTCEvents.REMOTE_TRACK_ADDED,\n            (track, tpc) => this._setupReceiverE2EEForTrack(tpc, track));\n        this.conference.on(\n            JitsiConferenceEvents.TRACK_MUTE_CHANGED,\n            this._trackMuteChanged.bind(this));\n    }\n\n    /**\n     * Indicates whether E2EE is currently enabled or not.\n     *\n     * @returns {boolean}\n     */\n    isEnabled() {\n        return this.enabled;\n    }\n\n    /**\n     * Enables / disables End-To-End encryption.\n     *\n     * @param {boolean} enabled - whether E2EE should be enabled or not.\n     * @returns {void}\n     */\n    async setEnabled(enabled) {\n        this._enabling && await this._enabling;\n\n        if (enabled === this.enabled) {\n            return;\n        }\n\n        this._enabling = new Deferred();\n\n        this.enabled = enabled;\n\n        if (!enabled) {\n            this.e2eeCtx.cleanupAll();\n        }\n\n        this._setEnabled && await this._setEnabled(enabled);\n\n        this.conference.setLocalParticipantProperty('e2ee.enabled', enabled);\n\n        this.conference._restartMediaSessions();\n\n        this._enabling.resolve();\n    }\n\n    /**\n     * Sets the key for End-to-End encryption.\n     *\n     * @returns {void}\n     */\n    setEncryptionKey() {\n        throw new Error('Not implemented by subclass');\n    }\n\n    /**\n     * Setup E2EE on the new track that has been added to the conference, apply it on all the open peerconnections.\n     * @param {JitsiLocalTrack} track - the new track that's being added to the conference.\n     * @private\n     */\n    _onLocalTrackAdded(track) {\n        for (const session of this.conference.getMediaSessions()) {\n            this._setupSenderE2EEForTrack(session, track);\n        }\n    }\n\n    /**\n     * Setups E2E encryption for the new session.\n     * @param {JingleSessionPC} session - the new media session.\n     * @private\n     */\n    _onMediaSessionStarted(session) {\n        const localTracks = this.conference.getLocalTracks();\n\n        for (const track of localTracks) {\n            this._setupSenderE2EEForTrack(session, track);\n        }\n    }\n\n    /**\n     * Setup E2EE for the receiving side.\n     *\n     * @private\n     */\n    _setupReceiverE2EEForTrack(tpc, track) {\n        if (!this.enabled) {\n            return;\n        }\n\n        const receiver = tpc.findReceiverForTrack(track.track);\n\n        if (receiver) {\n            this.e2eeCtx.handleReceiver(receiver, track.getType(), track.getParticipantId());\n        } else {\n            logger.warn(`Could not handle E2EE for ${track}: receiver not found in: ${tpc}`);\n        }\n    }\n\n    /**\n     * Setup E2EE for the sending side.\n     *\n     * @param {JingleSessionPC} session - the session which sends the media produced by the track.\n     * @param {JitsiLocalTrack} track - the local track for which e2e encoder will be configured.\n     * @private\n     */\n    _setupSenderE2EEForTrack(session, track) {\n        if (!this.enabled) {\n            return;\n        }\n\n        const pc = session.peerconnection;\n        const sender = pc && pc.findSenderForTrack(track.track);\n\n        if (sender) {\n            this.e2eeCtx.handleSender(sender, track.getType(), track.getParticipantId());\n        } else {\n            logger.warn(`Could not handle E2EE for ${track}: sender not found in ${pc}`);\n        }\n    }\n\n    /**\n     * Setup E2EE on the sender that is created for the unmuted local video track.\n     * @param {JitsiLocalTrack} track - the track for which muted status has changed.\n     * @private\n     */\n    _trackMuteChanged(track) {\n        if (browser.doesVideoMuteByStreamRemove() && track.isLocal() && track.isVideoTrack() && !track.isMuted()) {\n            for (const session of this.conference.getMediaSessions()) {\n                this._setupSenderE2EEForTrack(session, track);\n            }\n        }\n    }\n}\n","import { KeyHandler } from './KeyHandler';\n\n/**\n * This module integrates {@link E2EEContext} with {external} in order to set the keys for encryption.\n */\nexport class ExternallyManagedKeyHandler extends KeyHandler {\n    /**\n     * Build a new ExternallyManagedKeyHandler instance, which will be used in a given conference.\n     * @param conference - the current conference.\n     */\n    constructor(conference) {\n        super(conference, { sharedKey: true });\n    }\n\n    /**\n     * Sets the key and index for End-to-End encryption.\n     *\n     * @param {CryptoKey} [keyInfo.encryptionKey] - encryption key.\n     * @param {Number} [keyInfo.index] - the index of the encryption key.\n     * @returns {void}\n     */\n    setKey(keyInfo) {\n        this.e2eeCtx.setKey(undefined, { encryptionKey: keyInfo.encryptionKey }, keyInfo.index);\n    }\n}\n","import uuid from './dist/index.js';\nexport const v1 = uuid.v1;\nexport const v3 = uuid.v3;\nexport const v4 = uuid.v4;\nexport const v5 = uuid.v5;\n","export enum E2EEErrors {\n    E2EE_SAS_KEYS_MAC_MISMATCH = 'e2ee.sas.keys-mac-mismatch',\n    E2EE_SAS_MAC_MISMATCH = 'e2ee.sas.mac-mismatch',\n    E2EE_SAS_MISSING_KEY =  'e2ee.sas.missing-key',\n    E2EE_SAS_COMMITMENT_MISMATCHED =  'e2ee.sas.commitment-mismatched',\n    E2EE_SAS_CHANNEL_VERIFICATION_FAILED = 'e2ee.sas.channel-verification-failed',\n    E2EE_SAS_INVALID_SAS_VERIFICATION =  'e2ee.sas.invalid-sas-verification',\n}\n","/* eslint-disable no-bitwise */\n/* eslint-disable no-mixed-operators */\n\n/**\n * Generates a SAS composed of decimal numbers.\n * Borrowed from the Matrix JS SDK.\n *\n * @param {Uint8Array} sasBytes - The bytes from sas.generate_bytes.\n * @returns Array<number>\n */\nfunction generateDecimalSas(sasBytes) {\n    /**\n     *      +--------+--------+--------+--------+--------+\n     *      | Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 |\n     *      +--------+--------+--------+--------+--------+\n     * bits: 87654321 87654321 87654321 87654321 87654321\n     *       \\____________/\\_____________/\\____________/\n     *         1st number    2nd number     3rd number\n     */\n    return [\n        (sasBytes[0] << 5 | sasBytes[1] >> 3) + 1000,\n        ((sasBytes[1] & 0x7) << 10 | sasBytes[2] << 2 | sasBytes[3] >> 6) + 1000,\n        ((sasBytes[3] & 0x3f) << 7 | sasBytes[4] >> 1) + 1000\n    ];\n}\n\nconst emojiMapping = [\n    [ '🐶', 'dog' ],\n    [ '🐱', 'cat' ],\n    [ '🦁', 'lion' ],\n    [ '🐎', 'horse' ],\n    [ '🦄', 'unicorn' ],\n    [ '🐷', 'pig' ],\n    [ '🐘', 'elephant' ],\n    [ '🐰', 'rabbit' ],\n    [ '🐼', 'panda' ],\n    [ '🐓', 'rooster' ],\n    [ '🐧', 'penguin' ],\n    [ '🐢', 'turtle' ],\n    [ '🐟', 'fish' ],\n    [ '🐙', 'octopus' ],\n    [ '🦋', 'butterfly' ],\n    [ '🌷', 'flower' ],\n    [ '🌳', 'tree' ],\n    [ '🌵', 'cactus' ],\n    [ '🍄', 'mushroom' ],\n    [ '🌏', 'globe' ],\n    [ '🌙', 'moon' ],\n    [ '☁️', 'cloud' ],\n    [ '🔥', 'fire' ],\n    [ '🍌', 'banana' ],\n    [ '🍎', 'apple' ],\n    [ '🍓', 'strawberry' ],\n    [ '🌽', 'corn' ],\n    [ '🍕', 'pizza' ],\n    [ '🎂', 'cake' ],\n    [ '❤️', 'heart' ],\n    [ '🙂', 'smiley' ],\n    [ '🤖', 'robot' ],\n    [ '🎩', 'hat' ],\n    [ '👓', 'glasses' ],\n    [ '🔧', 'spanner' ],\n    [ '🎅', 'santa' ],\n    [ '👍', 'thumbs up' ],\n    [ '☂️', 'umbrella' ],\n    [ '⌛', 'hourglass' ],\n    [ '⏰', 'clock' ],\n    [ '🎁', 'gift' ],\n    [ '💡', 'light bulb' ],\n    [ '📕', 'book' ],\n    [ '✏️', 'pencil' ],\n    [ '📎', 'paperclip' ],\n    [ '✂️', 'scissors' ],\n    [ '🔒', 'lock' ],\n    [ '🔑', 'key' ],\n    [ '🔨', 'hammer' ],\n    [ '☎️', 'telephone' ],\n    [ '🏁', 'flag' ],\n    [ '🚂', 'train' ],\n    [ '🚲', 'bicycle' ],\n    [ '✈️', 'aeroplane' ],\n    [ '🚀', 'rocket' ],\n    [ '🏆', 'trophy' ],\n    [ '⚽', 'ball' ],\n    [ '🎸', 'guitar' ],\n    [ '🎺', 'trumpet' ],\n    [ '🔔', 'bell' ],\n    [ '⚓️', 'anchor' ],\n    [ '🎧', 'headphones' ],\n    [ '📁', 'folder' ],\n    [ '📌', 'pin' ]\n];\n\n/**\n * Generates a SAS composed of defimal numbers.\n * Borrowed from the Matrix JS SDK.\n *\n * @param {Uint8Array} sasBytes - The bytes from sas.generate_bytes.\n * @returns Array<number>\n */\nfunction generateEmojiSas(sasBytes) {\n    // Just like base64.\n    const emojis = [\n        sasBytes[0] >> 2,\n        (sasBytes[0] & 0x3) << 4 | sasBytes[1] >> 4,\n        (sasBytes[1] & 0xf) << 2 | sasBytes[2] >> 6,\n        sasBytes[2] & 0x3f,\n        sasBytes[3] >> 2,\n        (sasBytes[3] & 0x3) << 4 | sasBytes[4] >> 4,\n        (sasBytes[4] & 0xf) << 2 | sasBytes[5] >> 6\n    ];\n\n    return emojis.map(num => emojiMapping[num]);\n}\n\nconst sasGenerators = {\n    decimal: generateDecimalSas,\n    emoji: generateEmojiSas\n};\n\n/**\n * Generates multiple SAS for the given bytes.\n *\n * @param {Uint8Array} sasBytes - The bytes from sas.generate_bytes.\n * @returns {object}\n */\nexport function generateSas(sasBytes) {\n    const sas = {};\n\n    for (const method in sasGenerators) {\n        if (sasGenerators.hasOwnProperty(method)) {\n            sas[method] = sasGenerators[method](sasBytes);\n        }\n    }\n\n    return sas;\n}\n","/* global Olm */\n\nimport { getLogger } from '@jitsi/logger';\nimport base64js from 'base64-js';\nimport isEqual from 'lodash.isequal';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport Deferred from '../util/Deferred';\nimport Listenable from '../util/Listenable';\nimport { FEATURE_E2EE, JITSI_MEET_MUC_TYPE } from '../xmpp/xmpp';\n\nimport { E2EEErrors } from './E2EEErrors';\nimport { generateSas } from './SAS';\n\nconst logger = getLogger(__filename);\n\nconst REQ_TIMEOUT = 5 * 1000;\nconst OLM_MESSAGE_TYPE = 'olm';\nconst OLM_MESSAGE_TYPES = {\n    ERROR: 'error',\n    KEY_INFO: 'key-info',\n    KEY_INFO_ACK: 'key-info-ack',\n    SESSION_ACK: 'session-ack',\n    SESSION_INIT: 'session-init',\n    SAS_START: 'sas-start',\n    SAS_ACCEPT: 'sas-accept',\n    SAS_KEY: 'sas-key',\n    SAS_MAC: 'sas-mac'\n};\n\nconst OLM_SAS_NUM_BYTES = 6;\nconst OLM_KEY_VERIFICATION_MAC_INFO = 'Jitsi-KEY_VERIFICATION_MAC';\nconst OLM_KEY_VERIFICATION_MAC_KEY_IDS = 'Jitsi-KEY_IDS';\n\nconst kOlmData = Symbol('OlmData');\n\nconst OlmAdapterEvents = {\n    PARTICIPANT_E2EE_CHANNEL_READY: 'olm.participant_e2ee_channel_ready',\n    PARTICIPANT_SAS_AVAILABLE: 'olm.participant_sas_available',\n    PARTICIPANT_SAS_READY: 'olm.participant_sas_ready',\n    PARTICIPANT_KEY_UPDATED: 'olm.partitipant_key_updated',\n    PARTICIPANT_VERIFICATION_COMPLETED: 'olm.participant_verification_completed'\n};\n\n/**\n * This class implements an End-to-End Encrypted communication channel between every two peers\n * in the conference. This channel uses libolm to achieve E2EE.\n *\n * The created channel is then used to exchange the secret key that each participant will use\n * to encrypt the actual media (see {@link E2EEContext}).\n *\n * A simple JSON message based protocol is implemented, which follows a request - response model:\n * - session-init: Initiates an olm session establishment procedure. This message will be sent\n *                 by the participant who just joined, to everyone else.\n * - session-ack: Completes the olm session etablishment. This messsage may contain ancilliary\n *                encrypted data, more specifically the sender's current key.\n * - key-info: Includes the sender's most up to date key information.\n * - key-info-ack: Acknowledges the reception of a key-info request. In addition, it may contain\n *                 the sender's key information, if available.\n * - error: Indicates a request processing error has occurred.\n *\n * These requessts and responses are transport independent. Currently they are sent using XMPP\n * MUC private messages.\n */\nexport class OlmAdapter extends Listenable {\n    /**\n     * Creates an adapter instance for the given conference.\n     */\n    constructor(conference) {\n        super();\n\n        this._conf = conference;\n        this._init = new Deferred();\n        this._mediaKey = undefined;\n        this._mediaKeyIndex = -1;\n        this._reqs = new Map();\n        this._sessionInitialization = undefined;\n\n        if (OlmAdapter.isSupported()) {\n            this._bootstrapOlm();\n\n            this._conf.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, this._onEndpointMessageReceived.bind(this));\n            this._conf.on(JitsiConferenceEvents.CONFERENCE_LEFT, this._onConferenceLeft.bind(this));\n            this._conf.on(JitsiConferenceEvents.USER_LEFT, this._onParticipantLeft.bind(this));\n            this._conf.on(JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,\n                this._onParticipantPropertyChanged.bind(this));\n        } else {\n            this._init.reject(new Error('Olm not supported'));\n        }\n    }\n\n    /**\n     * Returns the current participants conference ID.\n     *\n     * @returns {string}\n     */\n    get myId() {\n        return this._conf.myUserId();\n    }\n\n    /**\n     * Starts new olm sessions with every other participant that has the participantId \"smaller\" the localParticipantId.\n     */\n    async initSessions() {\n        if (this._sessionInitialization) {\n            throw new Error('OlmAdapter initSessions called multiple times');\n        } else {\n            this._sessionInitialization = new Deferred();\n\n            await this._init;\n\n            const promises = [];\n            const localParticipantId = this._conf.myUserId();\n\n            for (const participant of this._conf.getParticipants()) {\n                if (participant.hasFeature(FEATURE_E2EE) && localParticipantId < participant.getId()) {\n                    promises.push(this._sendSessionInit(participant));\n                }\n            }\n\n            await Promise.allSettled(promises);\n\n            // TODO: retry failed ones.\n\n            this._sessionInitialization.resolve();\n            this._sessionInitialization = undefined;\n        }\n    }\n\n    /**\n     * Indicates if olm is supported on the current platform.\n     *\n     * @returns {boolean}\n     */\n    static isSupported() {\n        return typeof window.Olm !== 'undefined';\n    }\n\n    /**\n     * Updates the current participant key and distributes it to all participants in the conference\n     * by sending a key-info message.\n     *\n     * @param {Uint8Array|boolean} key - The new key.\n     * @retrns {Promise<Number>}\n     */\n    async updateKey(key) {\n        // Store it locally for new sessions.\n        this._mediaKey = key;\n        this._mediaKeyIndex++;\n\n        // Broadcast it.\n        const promises = [];\n\n        for (const participant of this._conf.getParticipants()) {\n            const pId = participant.getId();\n            const olmData = this._getParticipantOlmData(participant);\n\n            // TODO: skip those who don't support E2EE.\n            if (!olmData.session) {\n                logger.warn(`Tried to send key to participant ${pId} but we have no session`);\n\n                // eslint-disable-next-line no-continue\n                continue;\n            }\n\n            const uuid = uuidv4();\n            const data = {\n                [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n                olm: {\n                    type: OLM_MESSAGE_TYPES.KEY_INFO,\n                    data: {\n                        ciphertext: this._encryptKeyInfo(olmData.session),\n                        uuid\n                    }\n                }\n            };\n            const d = new Deferred();\n\n            d.setRejectTimeout(REQ_TIMEOUT);\n            d.catch(() => {\n                this._reqs.delete(uuid);\n            });\n            this._reqs.set(uuid, d);\n            promises.push(d);\n\n            this._sendMessage(data, pId);\n        }\n\n        await Promise.allSettled(promises);\n\n        // TODO: retry failed ones?\n\n        return this._mediaKeyIndex;\n    }\n\n    /**\n     * Updates the current participant key.\n     * @param {Uint8Array|boolean} key - The new key.\n     * @returns {number}\n    */\n    updateCurrentMediaKey(key) {\n        this._mediaKey = key;\n\n        return this._mediaKeyIndex;\n    }\n\n    /**\n     * Frees the olmData session for the given participant.\n     *\n     */\n    clearParticipantSession(participant) {\n        const olmData = this._getParticipantOlmData(participant);\n\n        if (olmData.session) {\n            olmData.session.free();\n            olmData.session = undefined;\n        }\n    }\n\n    /**\n     * Frees the olmData sessions for all participants.\n     *\n     */\n    clearAllParticipantsSessions() {\n        for (const participant of this._conf.getParticipants()) {\n            this.clearParticipantSession(participant);\n        }\n    }\n\n    /**\n     * Sends sacMac if channel verification waas successful.\n     *\n     */\n    markParticipantVerified(participant, isVerified) {\n        const olmData = this._getParticipantOlmData(participant);\n\n        const pId = participant.getId();\n\n        if (!isVerified) {\n            olmData.sasVerification = undefined;\n            logger.warn(`Verification failed for participant ${pId}`);\n            this.eventEmitter.emit(\n                OlmAdapterEvents.PARTICIPANT_VERIFICATION_COMPLETED,\n                pId,\n                false,\n                E2EEErrors.E2EE_SAS_CHANNEL_VERIFICATION_FAILED);\n\n            return;\n        }\n\n        if (!olmData.sasVerification) {\n            logger.warn(`Participant ${pId} does not have valid sasVerification`);\n            this.eventEmitter.emit(\n                OlmAdapterEvents.PARTICIPANT_VERIFICATION_COMPLETED,\n                pId,\n                false,\n                E2EEErrors.E2EE_SAS_INVALID_SAS_VERIFICATION);\n\n            return;\n        }\n\n        const { sas, sasMacSent } = olmData.sasVerification;\n\n        if (sas && sas.is_their_key_set() && !sasMacSent) {\n            this._sendSasMac(participant);\n\n            // Mark the MAC as sent so we don't send it multiple times.\n            olmData.sasVerification.sasMacSent = true;\n        }\n    }\n\n    /**\n     * Internal helper to bootstrap the olm library.\n     *\n     * @returns {Promise<void>}\n     * @private\n     */\n    async _bootstrapOlm() {\n        logger.debug('Initializing Olm...');\n\n        try {\n            await Olm.init();\n\n            this._olmAccount = new Olm.Account();\n            this._olmAccount.create();\n\n            this._idKeys = JSON.parse(this._olmAccount.identity_keys());\n\n            logger.debug(`Olm ${Olm.get_library_version().join('.')} initialized`);\n            this._init.resolve();\n            this._onIdKeysReady(this._idKeys);\n        } catch (e) {\n            logger.error('Failed to initialize Olm', e);\n            this._init.reject(e);\n        }\n    }\n\n    /**\n     * Starts the verification process for the given participant as described here\n     * https://spec.matrix.org/latest/client-server-api/#short-authentication-string-sas-verification\n     *\n     *    |                                 |\n          | m.key.verification.start        |\n          |-------------------------------->|\n          |                                 |\n          |       m.key.verification.accept |\n          |<--------------------------------|\n          |                                 |\n          | m.key.verification.key          |\n          |-------------------------------->|\n          |                                 |\n          |          m.key.verification.key |\n          |<--------------------------------|\n          |                                 |\n          | m.key.verification.mac          |\n          |-------------------------------->|\n          |                                 |\n          |          m.key.verification.mac |\n          |<--------------------------------|\n          |                                 |\n     *\n     * @param {JitsiParticipant} participant - The target participant.\n     * @returns {Promise<void>}\n     * @private\n     */\n    startVerification(participant) {\n        const pId = participant.getId();\n        const olmData = this._getParticipantOlmData(participant);\n\n        if (!olmData.session) {\n            logger.warn(`Tried to start verification with participant ${pId} but we have no session`);\n\n            return;\n        }\n\n        if (olmData.sasVerification) {\n            logger.warn(`There is already a verification in progress with participant ${pId}`);\n\n            return;\n        }\n\n        olmData.sasVerification = {\n            sas: new Olm.SAS(),\n            transactionId: uuidv4()\n        };\n\n        const startContent = {\n            transactionId: olmData.sasVerification.transactionId\n        };\n\n        olmData.sasVerification.startContent = startContent;\n        olmData.sasVerification.isInitiator = true;\n\n        const startMessage = {\n            [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n            olm: {\n                type: OLM_MESSAGE_TYPES.SAS_START,\n                data: startContent\n            }\n        };\n\n        this._sendMessage(startMessage, pId);\n    }\n\n    /**\n     * Publishes our own Olmn id key in presence.\n     * @private\n     */\n    _onIdKeysReady(idKeys) {\n        logger.debug(`Olm id key ready: ${idKeys}`);\n\n        // Publish it in presence.\n        for (const keyType in idKeys) {\n            if (idKeys.hasOwnProperty(keyType)) {\n                const key = idKeys[keyType];\n\n                this._conf.setLocalParticipantProperty(`e2ee.idKey.${keyType}`, key);\n            }\n        }\n    }\n\n    /**\n     * Event posted when the E2EE signalling channel has been established with the given participant.\n     * @private\n     */\n    _onParticipantE2EEChannelReady(id) {\n        logger.debug(`E2EE channel with participant ${id} is ready`);\n    }\n\n    /**\n     * Internal helper for encrypting the current key information for a given participant.\n     *\n     * @param {Olm.Session} session - Participant's session.\n     * @returns {string} - The encrypted text with the key information.\n     * @private\n     */\n    _encryptKeyInfo(session) {\n        const keyInfo = {};\n\n        if (this._mediaKey !== undefined) {\n            keyInfo.key = this._mediaKey ? base64js.fromByteArray(this._mediaKey) : false;\n            keyInfo.keyIndex = this._mediaKeyIndex;\n        }\n\n        return session.encrypt(JSON.stringify(keyInfo));\n    }\n\n    /**\n     * Internal helper for getting the olm related data associated with a participant.\n     *\n     * @param {JitsiParticipant} participant - Participant whose data wants to be extracted.\n     * @returns {Object}\n     * @private\n     */\n    _getParticipantOlmData(participant) {\n        participant[kOlmData] = participant[kOlmData] || {};\n\n        return participant[kOlmData];\n    }\n\n    /**\n     * Handles leaving the conference, cleaning up olm sessions.\n     *\n     * @private\n     */\n    async _onConferenceLeft() {\n        logger.debug('Conference left');\n\n        await this._init;\n\n        for (const participant of this._conf.getParticipants()) {\n            this._onParticipantLeft(participant.getId(), participant);\n        }\n\n        if (this._olmAccount) {\n            this._olmAccount.free();\n            this._olmAccount = undefined;\n        }\n    }\n\n    /**\n     * Main message handler. Handles 1-to-1 messages received from other participants\n     * and send the appropriate replies.\n     *\n     * @private\n     */\n    async _onEndpointMessageReceived(participant, payload) {\n        if (payload[JITSI_MEET_MUC_TYPE] !== OLM_MESSAGE_TYPE) {\n            return;\n        }\n\n        if (!payload.olm) {\n            logger.warn('Incorrectly formatted message');\n\n            return;\n        }\n\n        await this._init;\n\n        const msg = payload.olm;\n        const pId = participant.getId();\n        const olmData = this._getParticipantOlmData(participant);\n\n        switch (msg.type) {\n        case OLM_MESSAGE_TYPES.SESSION_INIT: {\n            if (olmData.session) {\n                logger.warn(`Participant ${pId} already has a session`);\n\n                this._sendError(participant, 'Session already established');\n            } else {\n                // Create a session for communicating with this participant.\n\n                const session = new Olm.Session();\n\n                session.create_outbound(this._olmAccount, msg.data.idKey, msg.data.otKey);\n                olmData.session = session;\n\n                // Send ACK\n                const ack = {\n                    [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n                    olm: {\n                        type: OLM_MESSAGE_TYPES.SESSION_ACK,\n                        data: {\n                            ciphertext: this._encryptKeyInfo(session),\n                            uuid: msg.data.uuid\n                        }\n                    }\n                };\n\n                this._sendMessage(ack, pId);\n                this._onParticipantE2EEChannelReady(pId);\n            }\n            break;\n        }\n        case OLM_MESSAGE_TYPES.SESSION_ACK: {\n            if (olmData.session) {\n                logger.warn(`Participant ${pId} already has a session`);\n\n                this._sendError(participant, 'No session found');\n            } else if (msg.data.uuid === olmData.pendingSessionUuid) {\n                const { ciphertext } = msg.data;\n                const d = this._reqs.get(msg.data.uuid);\n                const session = new Olm.Session();\n\n                session.create_inbound(this._olmAccount, ciphertext.body);\n\n                // Remove OT keys that have been used to setup this session.\n                this._olmAccount.remove_one_time_keys(session);\n\n                // Decrypt first message.\n                const data = session.decrypt(ciphertext.type, ciphertext.body);\n\n                olmData.session = session;\n                olmData.pendingSessionUuid = undefined;\n\n                this._onParticipantE2EEChannelReady(pId);\n\n                this._reqs.delete(msg.data.uuid);\n                d.resolve();\n\n                const json = safeJsonParse(data);\n\n                if (json.key) {\n                    const key = base64js.toByteArray(json.key);\n                    const keyIndex = json.keyIndex;\n\n                    olmData.lastKey = key;\n                    this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_KEY_UPDATED, pId, key, keyIndex);\n                }\n            } else {\n                logger.warn('Received ACK with the wrong UUID');\n\n                this._sendError(participant, 'Invalid UUID');\n            }\n            break;\n        }\n        case OLM_MESSAGE_TYPES.ERROR: {\n            logger.error(msg.data.error);\n\n            break;\n        }\n        case OLM_MESSAGE_TYPES.KEY_INFO: {\n            if (olmData.session) {\n                const { ciphertext } = msg.data;\n                const data = olmData.session.decrypt(ciphertext.type, ciphertext.body);\n                const json = safeJsonParse(data);\n\n                if (json.key !== undefined && json.keyIndex !== undefined) {\n                    const key = json.key ? base64js.toByteArray(json.key) : false;\n                    const keyIndex = json.keyIndex;\n\n                    if (!isEqual(olmData.lastKey, key)) {\n                        olmData.lastKey = key;\n                        this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_KEY_UPDATED, pId, key, keyIndex);\n                    }\n\n                    // Send ACK.\n                    const ack = {\n                        [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n                        olm: {\n                            type: OLM_MESSAGE_TYPES.KEY_INFO_ACK,\n                            data: {\n                                ciphertext: this._encryptKeyInfo(olmData.session),\n                                uuid: msg.data.uuid\n                            }\n                        }\n                    };\n\n                    this._sendMessage(ack, pId);\n                }\n            } else {\n                logger.debug(`Received key info message from ${pId} but we have no session for them!`);\n\n                this._sendError(participant, 'No session found while processing key-info');\n            }\n            break;\n        }\n        case OLM_MESSAGE_TYPES.KEY_INFO_ACK: {\n            if (olmData.session) {\n                const { ciphertext } = msg.data;\n                const data = olmData.session.decrypt(ciphertext.type, ciphertext.body);\n                const json = safeJsonParse(data);\n\n                if (json.key !== undefined && json.keyIndex !== undefined) {\n                    const key = json.key ? base64js.toByteArray(json.key) : false;\n                    const keyIndex = json.keyIndex;\n\n                    if (!isEqual(olmData.lastKey, key)) {\n                        olmData.lastKey = key;\n                        this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_KEY_UPDATED, pId, key, keyIndex);\n                    }\n                }\n\n                const d = this._reqs.get(msg.data.uuid);\n\n                this._reqs.delete(msg.data.uuid);\n                d.resolve();\n            } else {\n                logger.debug(`Received key info ack message from ${pId} but we have no session for them!`);\n\n                this._sendError(participant, 'No session found while processing key-info-ack');\n            }\n            break;\n        }\n        case OLM_MESSAGE_TYPES.SAS_START: {\n            if (!olmData.session) {\n                logger.debug(`Received sas init message from ${pId} but we have no session for them!`);\n\n                this._sendError(participant, 'No session found while processing sas-init');\n\n                return;\n            }\n\n            if (olmData.sasVerification?.sas) {\n                logger.warn(`SAS already created for participant ${pId}`);\n                this.eventEmitter.emit(\n                    OlmAdapterEvents.PARTICIPANT_VERIFICATION_COMPLETED,\n                    pId,\n                    false,\n                    E2EEErrors.E2EE_SAS_INVALID_SAS_VERIFICATION);\n\n                return;\n            }\n\n            const { transactionId } = msg.data;\n\n            const sas = new Olm.SAS();\n\n            olmData.sasVerification = {\n                sas,\n                transactionId,\n                isInitiator: false\n            };\n\n            const pubKey = olmData.sasVerification.sas.get_pubkey();\n            const commitment = this._computeCommitment(pubKey, msg.data);\n\n            /* The first phase of the verification process, the Key agreement phase\n                https://spec.matrix.org/latest/client-server-api/#short-authentication-string-sas-verification\n            */\n            const acceptMessage = {\n                [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n                olm: {\n                    type: OLM_MESSAGE_TYPES.SAS_ACCEPT,\n                    data: {\n                        transactionId,\n                        commitment\n                    }\n                }\n            };\n\n            this._sendMessage(acceptMessage, pId);\n            break;\n        }\n        case OLM_MESSAGE_TYPES.SAS_ACCEPT: {\n            if (!olmData.session) {\n                logger.debug(`Received sas accept message from ${pId} but we have no session for them!`);\n\n                this._sendError(participant, 'No session found while processing sas-accept');\n\n                return;\n            }\n\n            const { commitment, transactionId } = msg.data;\n\n\n            if (!olmData.sasVerification) {\n                logger.warn(`SAS_ACCEPT Participant ${pId} does not have valid sasVerification`);\n                this.eventEmitter.emit(\n                    OlmAdapterEvents.PARTICIPANT_VERIFICATION_COMPLETED,\n                    pId,\n                    false,\n                    E2EEErrors.E2EE_SAS_INVALID_SAS_VERIFICATION);\n\n                return;\n            }\n\n            if (olmData.sasVerification.sasCommitment) {\n                logger.debug(`Already received sas commitment message from ${pId}!`);\n\n                this._sendError(participant, 'Already received sas commitment message from ${pId}!');\n\n                return;\n            }\n\n            olmData.sasVerification.sasCommitment = commitment;\n\n            const pubKey = olmData.sasVerification.sas.get_pubkey();\n\n            // Send KEY.\n            const keyMessage = {\n                [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n                olm: {\n                    type: OLM_MESSAGE_TYPES.SAS_KEY,\n                    data: {\n                        key: pubKey,\n                        transactionId\n                    }\n                }\n            };\n\n            this._sendMessage(keyMessage, pId);\n\n            olmData.sasVerification.keySent = true;\n            break;\n        }\n        case OLM_MESSAGE_TYPES.SAS_KEY: {\n            if (!olmData.session) {\n                logger.debug(`Received sas key message from ${pId} but we have no session for them!`);\n\n                this._sendError(participant, 'No session found while processing sas-key');\n\n                return;\n            }\n\n            if (!olmData.sasVerification) {\n                logger.warn(`SAS_KEY Participant ${pId} does not have valid sasVerification`);\n                this.eventEmitter.emit(\n                    OlmAdapterEvents.PARTICIPANT_VERIFICATION_COMPLETED,\n                    pId,\n                    false,\n                    E2EEErrors.E2EE_SAS_INVALID_SAS_VERIFICATION);\n\n                return;\n            }\n\n            const { isInitiator, sas, sasCommitment, startContent, keySent } = olmData.sasVerification;\n\n            if (sas.is_their_key_set()) {\n                logger.warn('SAS already has their key!');\n\n                return;\n            }\n\n            const { key: theirKey, transactionId } = msg.data;\n\n            if (sasCommitment) {\n                const commitment = this._computeCommitment(theirKey, startContent);\n\n                if (sasCommitment !== commitment) {\n                    this._sendError(participant, 'OlmAdapter commitments mismatched');\n                    this.eventEmitter.emit(\n                        OlmAdapterEvents.PARTICIPANT_VERIFICATION_COMPLETED,\n                        pId,\n                        false,\n                        E2EEErrors.E2EE_SAS_COMMITMENT_MISMATCHED);\n                    olmData.sasVerification.free();\n\n                    return;\n                }\n            }\n\n            sas.set_their_key(theirKey);\n\n            const pubKey = sas.get_pubkey();\n\n            const myInfo = `${this.myId}|${pubKey}`;\n            const theirInfo = `${pId}|${theirKey}`;\n\n            const info = isInitiator ? `${myInfo}|${theirInfo}` : `${theirInfo}|${myInfo}`;\n\n            const sasBytes = sas.generate_bytes(info, OLM_SAS_NUM_BYTES);\n            const generatedSas = generateSas(sasBytes);\n\n            this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_SAS_READY, pId, generatedSas);\n\n            if (keySent) {\n                return;\n            }\n\n            const keyMessage = {\n                [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n                olm: {\n                    type: OLM_MESSAGE_TYPES.SAS_KEY,\n                    data: {\n                        key: pubKey,\n                        transactionId\n                    }\n                }\n            };\n\n            this._sendMessage(keyMessage, pId);\n\n            olmData.sasVerification.keySent = true;\n            break;\n        }\n        case OLM_MESSAGE_TYPES.SAS_MAC: {\n            if (!olmData.session) {\n                logger.debug(`Received sas mac message from ${pId} but we have no session for them!`);\n\n                this._sendError(participant, 'No session found while processing sas-mac');\n\n                return;\n            }\n\n            const { keys, mac, transactionId } = msg.data;\n\n            if (!mac || !keys) {\n                logger.warn('Invalid SAS MAC message');\n\n                return;\n            }\n\n            if (!olmData.sasVerification) {\n                logger.warn(`SAS_MAC Participant ${pId} does not have valid sasVerification`);\n\n                return;\n            }\n\n            const sas = olmData.sasVerification.sas;\n\n            // Verify the received MACs.\n            const baseInfo = `${OLM_KEY_VERIFICATION_MAC_INFO}${pId}${this.myId}${transactionId}`;\n            const keysMac = sas.calculate_mac(\n                Object.keys(mac).sort().join(','), // eslint-disable-line newline-per-chained-call\n                baseInfo + OLM_KEY_VERIFICATION_MAC_KEY_IDS\n            );\n\n            if (keysMac !== keys) {\n                logger.error('SAS verification error: keys MAC mismatch');\n                this.eventEmitter.emit(\n                    OlmAdapterEvents.PARTICIPANT_VERIFICATION_COMPLETED,\n                    pId,\n                    false,\n                    E2EEErrors.E2EE_SAS_KEYS_MAC_MISMATCH);\n\n                return;\n            }\n\n            if (!olmData.ed25519) {\n                logger.warn('SAS verification error: Missing ed25519 key');\n\n                this.eventEmitter.emit(\n                    OlmAdapterEvents.PARTICIPANT_VERIFICATION_COMPLETED,\n                    pId,\n                    false,\n                    E2EEErrors.E2EE_SAS_MISSING_KEY);\n\n                return;\n            }\n\n            for (const [ keyInfo, computedMac ] of Object.entries(mac)) {\n                const ourComputedMac = sas.calculate_mac(\n                    olmData.ed25519,\n                    baseInfo + keyInfo\n                );\n\n                if (computedMac !== ourComputedMac) {\n                    logger.error('SAS verification error: MAC mismatch');\n                    this.eventEmitter.emit(\n                        OlmAdapterEvents.PARTICIPANT_VERIFICATION_COMPLETED,\n                        pId,\n                        false,\n                        E2EEErrors.E2EE_SAS_MAC_MISMATCH);\n\n                    return;\n                }\n            }\n\n            logger.info(`SAS MAC verified for participant ${pId}`);\n            this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_VERIFICATION_COMPLETED, pId, true);\n\n            break;\n        }\n        }\n    }\n\n    /**\n     * Handles a participant leaving. When a participant leaves their olm session is destroyed.\n     *\n     * @private\n     */\n    _onParticipantLeft(id, participant) {\n        logger.debug(`Participant ${id} left`);\n\n        this.clearParticipantSession(participant);\n    }\n\n    /**\n    * Handles an update in a participant's presence property.\n    *\n    * @param {JitsiParticipant} participant - The participant.\n    * @param {string} name - The name of the property that changed.\n    * @param {*} oldValue - The property's previous value.\n    * @param {*} newValue - The property's new value.\n    * @private\n    */\n    async _onParticipantPropertyChanged(participant, name, oldValue, newValue) {\n        const participantId = participant.getId();\n        const olmData = this._getParticipantOlmData(participant);\n\n        switch (name) {\n        case 'e2ee.enabled':\n            if (newValue && this._conf.isE2EEEnabled()) {\n                const localParticipantId = this._conf.myUserId();\n                const participantFeatures = await participant.getFeatures();\n\n                if (participantFeatures.has(FEATURE_E2EE) && localParticipantId < participantId) {\n                    if (this._sessionInitialization) {\n                        await this._sessionInitialization;\n                    }\n                    await this._sendSessionInit(participant);\n\n                    const uuid = uuidv4();\n\n                    const d = new Deferred();\n\n                    d.setRejectTimeout(REQ_TIMEOUT);\n                    d.catch(() => {\n                        this._reqs.delete(uuid);\n                        olmData.pendingSessionUuid = undefined;\n                    });\n                    this._reqs.set(uuid, d);\n\n                    const data = {\n                        [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n                        olm: {\n                            type: OLM_MESSAGE_TYPES.KEY_INFO,\n                            data: {\n                                ciphertext: this._encryptKeyInfo(olmData.session),\n                                uuid\n                            }\n                        }\n                    };\n\n                    this._sendMessage(data, participantId);\n                }\n            }\n            break;\n        case 'e2ee.idKey.ed25519':\n            olmData.ed25519 = newValue;\n            this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_SAS_AVAILABLE, participantId);\n            break;\n        }\n    }\n\n    /**\n     * Builds and sends an error message to the target participant.\n     *\n     * @param {JitsiParticipant} participant - The target participant.\n     * @param {string} error - The error message.\n     * @returns {void}\n     */\n    _sendError(participant, error) {\n        const pId = participant.getId();\n        const err = {\n            [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n            olm: {\n                type: OLM_MESSAGE_TYPES.ERROR,\n                data: {\n                    error\n                }\n            }\n        };\n\n        this._sendMessage(err, pId);\n    }\n\n    /**\n     * Internal helper to send the given object to the given participant ID.\n     * This function merely exists so the transport can be easily swapped.\n     * Currently messages are transmitted via XMPP MUC private messages.\n     *\n     * @param {object} data - The data that will be sent to the target participant.\n     * @param {string} participantId - ID of the target participant.\n     */\n    _sendMessage(data, participantId) {\n        this._conf.sendMessage(data, participantId);\n    }\n\n    /**\n     * Builds and sends the session-init request to the target participant.\n     *\n     * @param {JitsiParticipant} participant - Participant to whom we'll send the request.\n     * @returns {Promise} - The promise will be resolved when the session-ack is received.\n     * @private\n     */\n    _sendSessionInit(participant) {\n        const pId = participant.getId();\n        const olmData = this._getParticipantOlmData(participant);\n\n        if (olmData.session) {\n            logger.warn(`Tried to send session-init to ${pId} but we already have a session`);\n\n            return Promise.reject();\n        }\n\n        if (olmData.pendingSessionUuid !== undefined) {\n            logger.warn(`Tried to send session-init to ${pId} but we already have a pending session`);\n\n            return Promise.reject();\n        }\n\n        // Generate a One Time Key.\n        this._olmAccount.generate_one_time_keys(1);\n\n        const otKeys = JSON.parse(this._olmAccount.one_time_keys());\n        const otKey = Object.values(otKeys.curve25519)[0];\n\n        if (!otKey) {\n            return Promise.reject(new Error('No one-time-keys generated'));\n        }\n\n        // Mark the OT keys (one really) as published so they are not reused.\n        this._olmAccount.mark_keys_as_published();\n\n        const uuid = uuidv4();\n        const init = {\n            [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n            olm: {\n                type: OLM_MESSAGE_TYPES.SESSION_INIT,\n                data: {\n                    idKey: this._idKeys.curve25519,\n                    otKey,\n                    uuid\n                }\n            }\n        };\n\n        const d = new Deferred();\n\n        d.setRejectTimeout(REQ_TIMEOUT);\n        d.catch(() => {\n            this._reqs.delete(uuid);\n            olmData.pendingSessionUuid = undefined;\n        });\n        this._reqs.set(uuid, d);\n\n        this._sendMessage(init, pId);\n\n        // Store the UUID for matching with the ACK.\n        olmData.pendingSessionUuid = uuid;\n\n        return d;\n    }\n\n    /**\n     * Builds and sends the SAS MAC message to the given participant.\n     * The second phase of the verification process, the Key verification phase\n        https://spec.matrix.org/latest/client-server-api/#short-authentication-string-sas-verification\n     */\n    _sendSasMac(participant) {\n        const pId = participant.getId();\n        const olmData = this._getParticipantOlmData(participant);\n        const { sas, transactionId } = olmData.sasVerification;\n\n        // Calculate and send MAC with the keys to be verified.\n        const mac = {};\n        const keyList = [];\n        const baseInfo = `${OLM_KEY_VERIFICATION_MAC_INFO}${this.myId}${pId}${transactionId}`;\n\n        const deviceKeyId = `ed25519:${pId}`;\n\n        mac[deviceKeyId] = sas.calculate_mac(\n            this._idKeys.ed25519,\n            baseInfo + deviceKeyId);\n        keyList.push(deviceKeyId);\n\n        const keys = sas.calculate_mac(\n            keyList.sort().join(','),\n            baseInfo + OLM_KEY_VERIFICATION_MAC_KEY_IDS\n        );\n\n        const macMessage = {\n            [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n            olm: {\n                type: OLM_MESSAGE_TYPES.SAS_MAC,\n                data: {\n                    keys,\n                    mac,\n                    transactionId\n                }\n            }\n        };\n\n        this._sendMessage(macMessage, pId);\n    }\n\n    /**\n     * Computes the commitment.\n     */\n    _computeCommitment(pubKey, data) {\n        const olmUtil = new Olm.Utility();\n        const commitment = olmUtil.sha256(pubKey + JSON.stringify(data));\n\n        olmUtil.free();\n\n        return commitment;\n    }\n}\n\n/**\n * Helper to ensure JSON parsing always returns an object.\n *\n * @param {string} data - The data that needs to be parsed.\n * @returns {object} - Parsed data or empty object in case of failure.\n */\nfunction safeJsonParse(data) {\n    try {\n        return JSON.parse(data);\n    } catch (e) {\n        return {};\n    }\n}\n\nOlmAdapter.events = OlmAdapterEvents;\n","import { getLogger } from '@jitsi/logger';\nimport debounce from 'lodash.debounce';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\n\nimport { KeyHandler } from './KeyHandler';\nimport { OlmAdapter } from './OlmAdapter';\nimport { importKey, ratchet } from './crypto-utils';\n\nconst logger = getLogger(__filename);\n\n// Period which we'll wait before updating / rotating our keys when a participant\n// joins or leaves.\nconst DEBOUNCE_PERIOD = 5000;\n\n/**\n * This module integrates {@link E2EEContext} with {@link OlmAdapter} in order to distribute the keys for encryption.\n */\nexport class ManagedKeyHandler extends KeyHandler {\n    /**\n     * Build a new AutomaticKeyHandler instance, which will be used in a given conference.\n     */\n    constructor(conference) {\n        super(conference);\n\n        this._key = undefined;\n        this._conferenceJoined = false;\n\n        this._olmAdapter = new OlmAdapter(conference);\n\n        this._rotateKey = debounce(this._rotateKeyImpl, DEBOUNCE_PERIOD);\n        this._ratchetKey = debounce(this._ratchetKeyImpl, DEBOUNCE_PERIOD);\n\n        // Olm signalling events.\n        this._olmAdapter.on(\n            OlmAdapter.events.PARTICIPANT_KEY_UPDATED,\n            this._onParticipantKeyUpdated.bind(this));\n\n        this._olmAdapter.on(\n            OlmAdapter.events.PARTICIPANT_SAS_READY,\n            this._onParticipantSasReady.bind(this));\n\n        this._olmAdapter.on(\n            OlmAdapter.events.PARTICIPANT_SAS_AVAILABLE,\n            this._onParticipantSasAvailable.bind(this));\n\n        this._olmAdapter.on(\n            OlmAdapter.events.PARTICIPANT_VERIFICATION_COMPLETED,\n            this._onParticipantVerificationCompleted.bind(this));\n\n        this.conference.on(\n            JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,\n            this._onParticipantPropertyChanged.bind(this));\n        this.conference.on(\n            JitsiConferenceEvents.USER_JOINED,\n            this._onParticipantJoined.bind(this));\n        this.conference.on(\n            JitsiConferenceEvents.USER_LEFT,\n            this._onParticipantLeft.bind(this));\n        this.conference.on(\n                JitsiConferenceEvents.CONFERENCE_JOINED,\n                () => {\n                    this._conferenceJoined = true;\n                });\n    }\n\n    /**\n     * Returns the sasVerficiation object.\n     *\n     * @returns {Object}\n     */\n    get sasVerification() {\n        return this._olmAdapter;\n    }\n\n    /**\n     * When E2EE is enabled it initializes sessions and sets the key.\n     * Cleans up the sessions when disabled.\n     *\n     * @param {boolean} enabled - whether E2EE should be enabled or not.\n     * @returns {void}\n     */\n    async _setEnabled(enabled) {\n        if (enabled) {\n            await this._olmAdapter.initSessions();\n        } else {\n            this._olmAdapter.clearAllParticipantsSessions();\n        }\n\n        // Generate a random key in case we are enabling.\n        this._key = enabled ? this._generateKey() : false;\n\n        // Send it to others using the E2EE olm channel.\n        const index = await this._olmAdapter.updateKey(this._key);\n\n        // Set our key so we begin encrypting.\n        this.e2eeCtx.setKey(this.conference.myUserId(), this._key, index);\n    }\n\n    /**\n     * Handles an update in a participant's presence property.\n     *\n     * @param {JitsiParticipant} participant - The participant.\n     * @param {string} name - The name of the property that changed.\n     * @param {*} oldValue - The property's previous value.\n     * @param {*} newValue - The property's new value.\n     * @private\n     */\n    async _onParticipantPropertyChanged(participant, name, oldValue, newValue) {\n        switch (name) {\n        case 'e2ee.idKey':\n            logger.debug(`Participant ${participant.getId()} updated their id key: ${newValue}`);\n            break;\n        case 'e2ee.enabled':\n            if (!newValue && this.enabled) {\n                this._olmAdapter.clearParticipantSession(participant);\n            }\n            break;\n        }\n    }\n\n    /**\n     * Advances (using ratcheting) the current key when a new participant joins the conference.\n     * @private\n     */\n    _onParticipantJoined() {\n        if (this._conferenceJoined && this.enabled) {\n            this._ratchetKey();\n        }\n    }\n\n    /**\n     * Rotates the current key when a participant leaves the conference.\n     * @private\n     */\n    _onParticipantLeft(id) {\n        this.e2eeCtx.cleanup(id);\n\n        if (this.enabled) {\n            this._rotateKey();\n        }\n    }\n\n    /**\n     * Rotates the local key. Rotating the key implies creating a new one, then distributing it\n     * to all participants and once they all received it, start using it.\n     *\n     * @private\n     */\n    async _rotateKeyImpl() {\n        logger.debug('Rotating key');\n\n        this._key = this._generateKey();\n        const index = await this._olmAdapter.updateKey(this._key);\n\n        this.e2eeCtx.setKey(this.conference.myUserId(), this._key, index);\n    }\n\n    /**\n     * Advances the current key by using ratcheting.\n     *\n     * @private\n     */\n    async _ratchetKeyImpl() {\n        logger.debug('Ratchetting key');\n\n        const material = await importKey(this._key);\n        const newKey = await ratchet(material);\n\n        this._key = new Uint8Array(newKey);\n\n        const index = this._olmAdapter.updateCurrentKey(this._key);\n\n        this.e2eeCtx.setKey(this.conference.myUserId(), this._key, index);\n    }\n\n    /**\n     * Handles an update in a participant's key.\n     *\n     * @param {string} id - The participant ID.\n     * @param {Uint8Array | boolean} key - The new key for the participant.\n     * @param {Number} index - The new key's index.\n     * @private\n     */\n    _onParticipantKeyUpdated(id, key, index) {\n        logger.debug(`Participant ${id} updated their key`);\n\n        this.e2eeCtx.setKey(id, key, index);\n    }\n\n    /**\n     * Handles the SAS ready event.\n     *\n     * @param {string} pId - The participant ID.\n     * @param {Uint8Array} sas - The bytes from sas.generate_bytes..\n     * @private\n     */\n    _onParticipantSasReady(pId, sas) {\n        this.conference.eventEmitter.emit(JitsiConferenceEvents.E2EE_VERIFICATION_READY, pId, sas);\n    }\n\n    /**\n     * Handles the sas available event.\n     *\n     * @param {string} pId - The participant ID.\n     * @private\n     */\n    _onParticipantSasAvailable(pId) {\n        this.conference.eventEmitter.emit(JitsiConferenceEvents.E2EE_VERIFICATION_AVAILABLE, pId);\n    }\n\n\n    /**\n     * Handles the SAS completed event.\n     *\n     * @param {string} pId - The participant ID.\n     * @param {boolean} success - Wheter the verification was succesfull.\n     * @private\n     */\n    _onParticipantVerificationCompleted(pId, success, message) {\n        this.conference.eventEmitter.emit(JitsiConferenceEvents.E2EE_VERIFICATION_COMPLETED, pId, success, message);\n    }\n\n    /**\n     * Generates a new 256 bit random key.\n     *\n     * @returns {Uint8Array}\n     * @private\n     */\n    _generateKey() {\n        return window.crypto.getRandomValues(new Uint8Array(32));\n    }\n}\n","/**\n * Derives a set of keys from the master key.\n * @param {CryptoKey} material - master key to derive from\n *\n * See https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.1\n */\nexport async function deriveKeys(material) {\n    const info = new ArrayBuffer();\n    const textEncoder = new TextEncoder();\n\n    // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey#HKDF\n    // https://developer.mozilla.org/en-US/docs/Web/API/HkdfParams\n    const encryptionKey = await crypto.subtle.deriveKey({\n        name: 'HKDF',\n        salt: textEncoder.encode('JFrameEncryptionKey'),\n        hash: 'SHA-256',\n        info\n    }, material, {\n        name: 'AES-GCM',\n        length: 128\n    }, false, [ 'encrypt', 'decrypt' ]);\n\n    return {\n        material,\n        encryptionKey\n    };\n}\n\n/**\n * Ratchets a key. See\n * https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.5.1\n * @param {CryptoKey} material - base key material\n * @returns {Promise<ArrayBuffer>} - ratcheted key material\n */\nexport async function ratchet(material) {\n    const textEncoder = new TextEncoder();\n\n    // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveBits\n    return crypto.subtle.deriveBits({\n        name: 'HKDF',\n        salt: textEncoder.encode('JFrameRatchetKey'),\n        hash: 'SHA-256',\n        info: new ArrayBuffer()\n    }, material, 256);\n}\n\n/**\n * Converts a raw key into a WebCrypto key object with default options\n * suitable for our usage.\n * @param {ArrayBuffer} keyBytes - raw key\n * @param {Array} keyUsages - key usages, see importKey documentation\n * @returns {Promise<CryptoKey>} - the WebCrypto key.\n */\nexport async function importKey(keyBytes) {\n    // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey\n    return crypto.subtle.importKey('raw', keyBytes, 'HKDF', false, [ 'deriveBits', 'deriveKey' ]);\n}\n","import browser from '../browser';\n\nimport { ExternallyManagedKeyHandler } from './ExternallyManagedKeyHandler';\nimport { ManagedKeyHandler } from './ManagedKeyHandler';\nimport { OlmAdapter } from './OlmAdapter';\n\n/**\n * This module integrates {@link KeyHandler} with {@link JitsiConference} in order to enable E2E encryption.\n */\nexport class E2EEncryption {\n    /**\n     * A constructor.\n     * @param {JitsiConference} conference - The conference instance for which E2E encryption is to be enabled.\n     */\n    constructor(conference) {\n        const { e2ee = {} } = conference.options.config;\n\n        this._externallyManaged = e2ee.externallyManagedKey;\n\n        if (this._externallyManaged) {\n            this._keyHandler = new ExternallyManagedKeyHandler(conference);\n        } else {\n            this._keyHandler = new ManagedKeyHandler(conference);\n        }\n    }\n\n    /**\n     * Indicates if E2EE is supported in the current platform.\n     *\n     * @param {object} config - Global configuration.\n     * @returns {boolean}\n     */\n    static isSupported(config) {\n        const { e2ee = {} } = config;\n\n        if (!e2ee.externallyManagedKey && !OlmAdapter.isSupported()) {\n            return false;\n        }\n\n        return !(config.testing && config.testing.disableE2EE)\n            && (browser.supportsInsertableStreams()\n                || (config.enableEncodedTransformSupport && browser.supportsEncodedTransform()));\n    }\n\n    /**\n     * Indicates whether E2EE is currently enabled or not.\n     *\n     * @returns {boolean}\n     */\n    isEnabled() {\n        return this._keyHandler.isEnabled();\n    }\n\n    /**\n     * Enables / disables End-To-End encryption.\n     *\n     * @param {boolean} enabled - whether E2EE should be enabled or not.\n     * @returns {void}\n     */\n    async setEnabled(enabled) {\n        await this._keyHandler.setEnabled(enabled);\n    }\n\n    /**\n     * Sets the key and index for End-to-End encryption.\n     *\n     * @param {CryptoKey} [keyInfo.encryptionKey] - encryption key.\n     * @param {Number} [keyInfo.index] - the index of the encryption key.\n     * @returns {void}\n     */\n    setEncryptionKey(keyInfo) {\n        this._keyHandler.setKey(keyInfo);\n    }\n\n    /**\n     * Starts the verification process of the participant\n     *\n     * @param {Participant} - participant to be verified.\n     * @returns {void}\n     */\n    startVerification(participant) {\n        this._keyHandler.sasVerification?.startVerification(participant);\n    }\n\n    /**\n     * Marks the channel as verified\n     *\n     * @param {Participant} - participant to be verified.\n     * @param {boolean} isVerified - whether the verification was succesfull.\n     * @returns {void}\n     */\n    markParticipantVerified(participant, isVerified) {\n        this._keyHandler.sasVerification?.markParticipantVerified(participant, isVerified);\n    }\n}\n","/* eslint-disable */\n\n/*\n * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined\n * in FIPS PUB 180-1\n * Version 2.1a Copyright Paul Johnston 2000 - 2002.\n * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\n * Distributed under the BSD License\n * See http://pajhome.org.uk/crypt/md5 for details.\n */\n/* global define */\n\n/* Some functions and variables have been stripped for use with Strophe */\n\n/*\n * Calculate the SHA-1 of an array of big-endian words, and a bit length\n */\nfunction core_sha1(x, len) {\n    /* append padding */\n    x[len >> 5] |= 0x80 << (24 - len % 32);\n    x[((len + 64 >> 9) << 4) + 15] = len;\n\n    var w = new Array(80);\n    var a =  1732584193;\n    var b = -271733879;\n    var c = -1732584194;\n    var d =  271733878;\n    var e = -1009589776;\n\n    var i, j, t, olda, oldb, oldc, oldd, olde;\n    for (i = 0; i < x.length; i += 16) {\n        olda = a;\n        oldb = b;\n        oldc = c;\n        oldd = d;\n        olde = e;\n\n        for (j = 0; j < 80; j++) {\n            if (j < 16) {\n                w[j] = x[i + j];\n            } else {\n                w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);\n            }\n\n            t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),\n                         safe_add(safe_add(e, w[j]), sha1_kt(j)));\n            e = d;\n            d = c;\n            c = rol(b, 30);\n            b = a;\n            a = t;\n        }\n\n        a = safe_add(a, olda);\n        b = safe_add(b, oldb);\n        c = safe_add(c, oldc);\n        d = safe_add(d, oldd);\n        e = safe_add(e, olde);\n    }\n    return [a, b, c, d, e];\n}\n\n/*\n * Perform the appropriate triplet combination function for the current\n * iteration\n */\nfunction sha1_ft (t, b, c, d) {\n    if (t < 20) { return (b & c) | ((~b) & d); }\n    if (t < 40) { return b ^ c ^ d; }\n    if (t < 60) { return (b & c) | (b & d) | (c & d); }\n    return b ^ c ^ d;\n}\n\n/*\n * Determine the appropriate additive constant for the current iteration\n */\nfunction sha1_kt(t) {\n    return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 : (t < 60) ? -1894007588 : -899497514;\n}\n\n/*\n * Calculate the HMAC-SHA1 of a key and some data\n */\nfunction core_hmac_sha1(key, data) {\n    var bkey = str2binb(key);\n    if (bkey.length > 16) {\n        bkey = core_sha1(bkey, key.length * 8);\n    }\n\n    var ipad = new Array(16), opad = new Array(16);\n    for (var i = 0; i < 16; i++) {\n        ipad[i] = bkey[i] ^ 0x36363636;\n        opad[i] = bkey[i] ^ 0x5C5C5C5C;\n    }\n\n    var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * 8);\n    return core_sha1(opad.concat(hash), 512 + 160);\n}\n\n/*\n * Add integers, wrapping at 2^32. This uses 16-bit operations internally\n * to work around bugs in some JS interpreters.\n */\nfunction safe_add(x, y) {\n    var lsw = (x & 0xFFFF) + (y & 0xFFFF);\n    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n    return (msw << 16) | (lsw & 0xFFFF);\n}\n\n/*\n * Bitwise rotate a 32-bit number to the left.\n */\nfunction rol(num, cnt) {\n    return (num << cnt) | (num >>> (32 - cnt));\n}\n\n/*\n * Convert an 8-bit or 16-bit string to an array of big-endian words\n * In 8-bit function, characters >255 have their hi-byte silently ignored.\n */\nfunction str2binb(str) {\n    var bin = [];\n    var mask = 255;\n    for (var i = 0; i < str.length * 8; i += 8) {\n        bin[i>>5] |= (str.charCodeAt(i / 8) & mask) << (24 - i%32);\n    }\n    return bin;\n}\n\n/*\n * Convert an array of big-endian words to a base-64 string\n */\nfunction binb2b64 (binarray) {\n    var tab = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n    var str = \"\";\n    var triplet, j;\n    for (var i = 0; i < binarray.length * 4; i += 3) {\n        triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16) |\n                  (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) |\n                  ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);\n\n        for (j = 0; j < 4; j++) {\n            if (i * 8 + j * 6 > binarray.length * 32) { str += \"=\"; }\n            else { str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); }\n        }\n    }\n    return str;\n}\n\n/*\n * Convert an array of big-endian words to a string\n */\nfunction binb2str(bin) {\n    var str = \"\";\n    var mask = 255;\n    for (var i = 0; i < bin.length * 32; i += 8) {\n        str += String.fromCharCode((bin[i>>5] >>> (24 - i%32)) & mask);\n    }\n    return str;\n}\n\n/*\n * These are the functions you'll usually want to call\n * They take string arguments and return either hex or base-64 encoded strings\n */\nconst SHA1 = {\n    b64_hmac_sha1:  function (key, data){ return binb2b64(core_hmac_sha1(key, data)); },\n    b64_sha1:       function (s) { return binb2b64(core_sha1(str2binb(s),s.length * 8)); },\n    binb2str:       binb2str,\n    core_hmac_sha1: core_hmac_sha1,\n    str_hmac_sha1:  function (key, data){ return binb2str(core_hmac_sha1(key, data)); },\n    str_sha1:       function (s) { return binb2str(core_sha1(str2binb(s),s.length * 8)); },\n};\nexport { SHA1 as default };\n","import $ from 'jquery';\nimport { Strophe } from 'strophe.js'; // eslint-disable-line camelcase\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport Listenable from '../util/Listenable';\n\nimport sha1 from './sha1';\n\n/**\n * The property\n */\nconst IDENTITY_PROPERTIES = [ 'category', 'type', 'lang', 'name' ];\nconst IDENTITY_PROPERTIES_FOR_COMPARE = [ 'category', 'type', 'lang' ];\nconst HASH = 'sha-1';\n\n/**\n *\n * @param a\n * @param b\n */\nfunction compareIdentities(a, b) {\n    let res = 0;\n\n    IDENTITY_PROPERTIES_FOR_COMPARE.some(key =>\n        (res = ((a[key] > b[key]) && 1) || ((a[key] < b[key]) && -1)) !== 0\n    );\n\n    return res;\n}\n\n/**\n * Produces a sha-1 from provided identity and features values.\n *\n * @param {Array<Object>} identities - The identity objects.\n * @param {Array<string>} features - The features.\n * @returns {string}\n */\nfunction generateSha(identities, features) {\n    const sortedIdentities = identities.sort(compareIdentities).reduce(\n        (accumulatedValue, identity) => `${\n            IDENTITY_PROPERTIES.reduce(\n                (tmp, key, idx) =>\n                    tmp\n                        + (idx === 0 ? '' : '/')\n                        + (identity[key] ? identity[key] : ''),\n                '')\n        }<`, '');\n    const sortedFeatures = features.sort().reduce(\n        (tmp, feature) => `${tmp + feature}<`, '');\n\n    return sha1.b64_sha1(sortedIdentities + sortedFeatures);\n}\n\n/**\n * Parses the disco-info node and returns the sets of features and identities.\n * @param {String} node The node with results to parse.\n * @returns {{features: Set<any>, identities: Set<any>}}\n */\nexport function parseDiscoInfo(node) {\n    const features = new Set();\n    const identities = new Set();\n\n    $(node).find('>query>feature')\n        .each((_, el) => features.add(el.getAttribute('var')));\n    $(node).find('>query>identity')\n        .each((_, el) => identities.add({\n            type: el.getAttribute('type'),\n            name: el.getAttribute('name'),\n            category: el.getAttribute('category')\n        }));\n\n    return {\n        features,\n        identities\n    };\n}\n\n/**\n * Implements xep-0115 ( http://xmpp.org/extensions/xep-0115.html )\n */\nexport default class Caps extends Listenable {\n    /**\n     * Constructs new Caps instance.\n     * @param {Strophe.Connection} connection the strophe connection object\n     * @param {String} node the value of the node attribute of the \"c\" xml node\n     * that will be sent to the other participants\n     */\n    constructor(connection = {}, node = 'http://jitsi.org/jitsimeet') {\n        super();\n        this.node = node;\n        this.disco = connection.disco;\n        if (!this.disco) {\n            throw new Error(\n                'Missing strophe-plugins '\n                + '(disco plugin is required)!');\n        }\n\n        this.version = '';\n        this.rooms = new Set();\n\n        // We keep track of features added outside the library and we publish them\n        // in the presence of the participant for simplicity, avoiding the disco info request-response.\n        this.externalFeatures = new Set();\n\n        const emuc = connection.emuc;\n\n        emuc.addListener(XMPPEvents.EMUC_ROOM_ADDED,\n            room => this._addChatRoom(room));\n        emuc.addListener(XMPPEvents.EMUC_ROOM_REMOVED,\n            room => this._removeChatRoom(room));\n        Object.keys(emuc.rooms).forEach(jid => {\n            this._addChatRoom(emuc.rooms[jid]);\n        });\n\n        Strophe.addNamespace('CAPS', 'http://jabber.org/protocol/caps');\n        this.disco.addFeature(Strophe.NS.CAPS);\n    }\n\n    /**\n     * Adds new feature to the list of supported features for the local\n     * participant\n     * @param {String} feature the name of the feature.\n     * @param {boolean} submit if true - new presence with updated \"c\" node\n     * will be sent.\n     * @param {boolean} external whether this feature was added externally to the library.\n     * We put features used directly by the clients (is jibri, remote-control enabled etc.) in the presence\n     * to avoid additional disco-info queries by those clients.\n     */\n    addFeature(feature, submit = false, external = false) {\n        this.disco.addFeature(feature);\n        this._generateVersion();\n\n        if (external && !this.externalFeatures.has(feature)) {\n            this.externalFeatures.add(feature);\n            this.rooms.forEach(room => this._updateRoomWithExternalFeatures(room));\n        }\n\n        if (submit) {\n            this.submit();\n        }\n    }\n\n    /**\n     * Removes a feature from the list of supported features for the local\n     * participant\n     * @param {String} feature the name of the feature.\n     * @param {boolean} submit if true - new presence with updated \"c\" node\n     * will be sent.\n     * @param {boolean} external whether this feature was added externally to the library.\n     */\n    removeFeature(feature, submit = false, external = false) {\n        this.disco.removeFeature(feature);\n        this._generateVersion();\n\n        if (external && this.externalFeatures.has(feature)) {\n            this.externalFeatures.delete(feature);\n            this.rooms.forEach(room => this._updateRoomWithExternalFeatures(room));\n        }\n\n        if (submit) {\n            this.submit();\n        }\n    }\n\n    /**\n     * Sends new presence stanza for every room from the list of rooms.\n     */\n    submit() {\n        this.rooms.forEach(room => room.sendPresence());\n    }\n\n    /**\n     * Updates the presences in the room based on the current values in externalFeatures.\n     * @param {ChatRoom} room the room to update.\n     * @private\n     */\n    _updateRoomWithExternalFeatures(room) {\n        if (this.externalFeatures.size === 0) {\n            room.removeFromPresence('features');\n        } else {\n            const children = [];\n\n            this.externalFeatures.forEach(f => {\n                children.push({\n                    'tagName': 'feature',\n                    attributes: { 'var': f }\n                });\n            });\n\n            room.addOrReplaceInPresence('features', { children });\n        }\n    }\n\n    /**\n     * Returns a set with the features for a host.\n     * @param {String} jid the jid of the host\n     * @param {int} timeout the timeout in ms for reply from the host.\n     * @returns {Promise<Set<String>, Error>}\n     */\n    getFeaturesAndIdentities(jid, node, timeout = 5000) {\n        return this._getDiscoInfo(jid, node, timeout);\n    }\n\n    /**\n     * Returns a set with the features and identities for a host.\n     * @param {String} jid the jid of the host\n     * @param {String|null} node the node to query\n     * @param {int} timeout the timeout in ms for reply from the host.\n     * @returns {Promise<Object>}\n     * @private\n     */\n    _getDiscoInfo(jid, node, timeout) {\n        return new Promise((resolve, reject) =>\n            this.disco.info(jid, node, response => {\n                resolve(parseDiscoInfo(response));\n            }, reject, timeout)\n        );\n    }\n\n    /**\n     * Adds ChatRoom instance to the list of rooms. Adds listeners to the room\n     * and adds \"c\" element to the presences of the room.\n     * @param {ChatRoom} room the room.\n     */\n    _addChatRoom(room) {\n        this.rooms.add(room);\n        this._fixChatRoomPresenceMap(room);\n\n        this._updateRoomWithExternalFeatures(room);\n    }\n\n    /**\n     * Removes ChatRoom instance from the list of rooms. Removes listeners\n     * added from the Caps class.\n     * @param {ChatRoom} room the room.\n     */\n    _removeChatRoom(room) {\n        this.rooms.delete(room);\n    }\n\n    /**\n     * Creates/updates the \"c\" xml node into the presence of the passed room.\n     * @param {ChatRoom} room the room.\n     */\n    _fixChatRoomPresenceMap(room) {\n        room.addOrReplaceInPresence('c', {\n            attributes: {\n                xmlns: Strophe.NS.CAPS,\n                hash: HASH,\n                node: this.node,\n                ver: this.version\n            }\n        });\n    }\n\n    /**\n     * Handles this.version changes.\n     */\n    _notifyVersionChanged() {\n        // update the version for all rooms\n        this.rooms.forEach(room => this._fixChatRoomPresenceMap(room));\n    }\n\n    /**\n     * Generates the value for the \"ver\" attribute.\n     */\n    _generateVersion() {\n        this.version\n            = generateSha(this.disco._identities, this.disco._features);\n\n        this._notifyVersionChanged();\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport Listenable from '../util/Listenable';\n\nexport const NETWORK_INFO_EVENT = 'NETWORK_INFO_CHANGED';\n\nconst logger = getLogger(__filename);\n\n/**\n * Module provides information about the current status of the internet\n * connection. Lib-jitsi-meet doesn't have any logic for detecting internet\n * online/offline, but rather it relies on the information supplied by the app\n * that uses it. By default the online state is assumed and the lib acts as if\n * it was connected. See {@link JitsiMeetJS.setNetworkInfo}.\n */\nexport class NetworkInfo extends Listenable {\n    /**\n     * Creates new {@link NetworkInfo} instance.\n     */\n    constructor() {\n        super();\n        this._current = {\n            isOnline: true\n        };\n    }\n\n    /**\n     * Updates the network info state.\n     *\n     * @param {object} state - The network info state.\n     * @param {boolean} state.isOnline - {@code true} if the internet connectivity is online or {@code false}\n     * otherwise.\n     */\n    updateNetworkInfo({ isOnline }) {\n        logger.debug('updateNetworkInfo', { isOnline });\n        this._current = {\n            isOnline: isOnline === true\n        };\n        this.eventEmitter.emit(NETWORK_INFO_EVENT, this._current);\n    }\n\n    /**\n     * Returns the online/offline internet status. By default the value is {@code true} and changes only if\n     * the lib's user wires the state through {@link JitsiMeetJS.setNetworkInfo} like the jitsi-meet does. Because of\n     * that any logic should still assume that the internet may be offline and should handle the failure gracefully.\n     * It's only a good hint in the other way around: to pause internet operations until it comes back online.\n     * @returns {boolean}\n     */\n    isOnline() {\n        return this._current.isOnline === true;\n    }\n}\n\nconst networkInfo = new NetworkInfo();\n\nexport default networkInfo;\n","import { getLogger } from '@jitsi/logger';\n\nimport {\n    NETWORK_INFO_EVENT,\n    default as NetworkInfo\n} from '../connectivity/NetworkInfo';\nimport { getJitterDelay } from '../util/Retry';\n\nconst logger = getLogger(__filename);\n\n/**\n * The class contains the logic for triggering connection resume via XEP-0198 stream management.\n * It does two things, the first one is it tracks the internet online/offline status and it makes sure that\n * the reconnect is attempted only while online. The seconds thing is that it tracks the retry attempts and extends\n * the retry interval using the full jitter pattern.\n */\nexport default class ResumeTask {\n    /**\n     * Initializes new {@code RetryTask}.\n     * @param {Strophe.Connection} stropheConnection - The Strophe connection instance.\n     */\n    constructor(stropheConnection) {\n        this._stropheConn = stropheConnection;\n\n        /**\n         * The counter increased before each resume retry attempt, used to calculate exponential backoff.\n         * @type {number}\n         * @private\n         */\n        this._resumeRetryN = 0;\n\n        this._retryDelay = undefined;\n    }\n\n    /**\n     * @returns {number|undefined} - How much the app will wait before trying to resume the XMPP connection. When\n     * 'undefined' it means that no resume task was not scheduled.\n     */\n    get retryDelay() {\n        return this._retryDelay;\n    }\n\n    /**\n     * Called by {@link XmppConnection} when the connection drops and it's a signal it wants to schedule a reconnect.\n     *\n     * @returns {void}\n     */\n    schedule() {\n        this._cancelResume();\n\n        this._resumeRetryN += 1;\n\n        this._networkOnlineListener\n            = NetworkInfo.addEventListener(\n                NETWORK_INFO_EVENT,\n                ({ isOnline }) => {\n                    if (isOnline) {\n                        this._scheduleResume();\n                    } else {\n                        this._cancelResume();\n                    }\n                });\n\n        NetworkInfo.isOnline() && this._scheduleResume();\n    }\n\n    /**\n     * Schedules a delayed timeout which will execute the resume action.\n     * @private\n     * @returns {void}\n     */\n    _scheduleResume() {\n        if (this._resumeTimeout) {\n\n            // NO-OP\n            return;\n        }\n\n        // The retry delay will be:\n        //   1st retry: 1.5s - 3s\n        //   2nd retry: 3s - 9s\n        //   3rd and next retry: 4.5s - 27s\n        this._resumeRetryN = Math.min(3, this._resumeRetryN);\n        this._retryDelay = getJitterDelay(\n            /* retry */ this._resumeRetryN,\n            /* minDelay */ this._resumeRetryN * 1500,\n            3);\n\n        logger.info(`Will try to resume the XMPP connection in ${this.retryDelay}ms`);\n\n        this._resumeTimeout = setTimeout(() => this._resumeConnection(), this.retryDelay);\n    }\n\n    /**\n     * Cancels the delayed resume task.\n     *\n     * @private\n     * @returns {void}\n     */\n    _cancelResume() {\n        if (this._resumeTimeout) {\n            logger.info('Canceling connection resume task');\n            clearTimeout(this._resumeTimeout);\n            this._resumeTimeout = undefined;\n            this._retryDelay = undefined;\n        }\n    }\n\n    /**\n     * Resumes the XMPP connection using the stream management plugin.\n     *\n     * @private\n     * @returns {void}\n     */\n    _resumeConnection() {\n        const { streamManagement } = this._stropheConn;\n        const resumeToken = streamManagement.getResumeToken();\n\n        // Things may have changed since when the task was scheduled\n        if (!resumeToken) {\n            return;\n        }\n\n        logger.info('Trying to resume the XMPP connection');\n\n        const url = new URL(this._stropheConn.service);\n        let { search } = url;\n        const pattern = /(previd=)([\\w-]+)/;\n        const oldToken = search.match(pattern);\n\n        // Replace previd if the previd value has changed.\n        if (oldToken && oldToken.indexOf(resumeToken) === -1) {\n            search = search.replace(pattern, `$1${resumeToken}`);\n\n        // Append previd if it doesn't exist.\n        } else if (!oldToken) {\n            search += search.indexOf('?') === -1 ? `?previd=${resumeToken}` : `&previd=${resumeToken}`;\n        }\n\n        url.search = search;\n\n        this._stropheConn.service = url.toString();\n\n        streamManagement.resume();\n    }\n\n    /**\n     * Cancels the retry task. It's called by {@link XmppConnection} when it's no longer interested in reconnecting for\n     * example when the disconnect method is called.\n     *\n     * @returns {void}\n     */\n    cancel() {\n        this._cancelResume();\n        this._resumeRetryN = 0;\n        if (this._networkOnlineListener) {\n            this._networkOnlineListener();\n            this._networkOnlineListener = null;\n        }\n    }\n}\n","/**\n* Gets next timeout using the full jitter pattern.\n*\n* NOTE that there are no checks for argument correctness, so either do the math or use defaults.\n*\n* @param {number} retry - The retry number.\n* @param {number} minDelay - The minimal delay in milliseconds.\n* @param {number} base - The exponent base.\n* @returns {number} - The amount of waiting before trying another time given in milliseconds.\n* @private\n*/\nexport function getJitterDelay(retry, minDelay = 500, base = 2) {\n    return Math.floor((Math.random() * ((Math.pow(base, retry) * 1000) - minDelay)) + minDelay);\n}\n","/**\n * Attaches to the {@link Strophe.Connection.rawInput} which is called whenever any data is received from the server.\n */\nexport default class LastRequestTracker {\n    /**\n     * Initializes new instance.\n     */\n    constructor() {\n        this._lastSuccess = null;\n        this._lastFailedMessage = null;\n    }\n\n    /**\n     * Starts tracking requests on the given connection.\n     *\n     * @param {XmppConnection} xmppConnection - The XMPP connection which manages the given {@code stropheConnection}.\n     * @param {Object} stropheConnection - Strophe connection instance.\n     */\n    startTracking(xmppConnection, stropheConnection) {\n        const originalRawInput = stropheConnection.rawInput;\n\n        stropheConnection.rawInput = (...args) => {\n            const rawMessage = args[0];\n\n            if (rawMessage.includes('failure')) {\n                this._lastFailedMessage = rawMessage;\n            }\n\n            // It's okay to use rawInput callback only once the connection has been established, otherwise it will\n            // treat 'item-not-found' or other connection error on websocket reconnect as successful stanza received.\n            if (xmppConnection.connected) {\n                this._lastSuccess = Date.now();\n            }\n            originalRawInput.apply(stropheConnection, args);\n        };\n    }\n\n    /**\n     * Returns the last raw failed incoming message on the xmpp connection.\n     *\n     * @returns {string|null}\n     */\n    getLastFailedMessage() {\n        return this._lastFailedMessage;\n    }\n\n    /**\n     * Returns how many milliseconds have passed since the last successful BOSH request.\n     *\n     * @returns {number|null}\n     */\n    getTimeSinceLastSuccess() {\n        return this._lastSuccess\n            ? Date.now() - this._lastSuccess\n            : null;\n    }\n}\n","import Listenable from '../util/Listenable';\n\n/**\n * Creates ConnectionPlugin class that extends the passed class.\n * @param {Class} base the definition of the class that will be extended by\n * ConnectionPlugin\n */\nfunction getConnectionPluginDefinition(base = class {}) {\n    /**\n     * Base class for strophe connection plugins.\n     */\n    return class extends base {\n        /**\n         *\n         */\n        constructor(...args) {\n            super(...args);\n            this.connection = null;\n        }\n\n        /**\n         *\n         * @param connection\n         */\n        init(connection) {\n            this.connection = connection;\n        }\n    };\n}\n\n/**\n * ConnectionPlugin class.\n */\nexport default getConnectionPluginDefinition();\n\n/**\n * ConnectionPlugin class that extends Listenable.\n */\nexport const ConnectionPluginListenable\n    = getConnectionPluginDefinition(Listenable);\n","import { getLogger } from '@jitsi/logger';\nimport { $iq, Strophe } from 'strophe.js';\n\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\n\nimport ConnectionPlugin from './ConnectionPlugin';\n\n\nconst logger = getLogger(__filename);\n\n/**\n * Default ping every 10 sec\n */\nconst PING_DEFAULT_INTERVAL = 10000;\n\n/**\n * Default ping timeout error after 5 sec of waiting.\n */\nconst PING_DEFAULT_TIMEOUT = 5000;\n\n/**\n * Default value for how many ping failures will be tolerated before the WebSocket connection is killed.\n * The worst case scenario in case of ping timing out without a response is (25 seconds at the time of this writing):\n * PING_THRESHOLD * PING_INTERVAL + PING_TIMEOUT\n */\nconst PING_DEFAULT_THRESHOLD = 2;\n\n/**\n * XEP-0199 ping plugin.\n *\n * Registers \"urn:xmpp:ping\" namespace under Strophe.NS.PING.\n */\nexport default class PingConnectionPlugin extends ConnectionPlugin {\n    /**\n     * Constructs new object\n     * @param {Object} options\n     * @param {Function} options.onPingThresholdExceeded - Callback called when ping fails too many times (controlled\n     * by the {@link PING_THRESHOLD} constant).\n     * @param {Function} options._getTimeSinceLastServerResponse - A function to obtain the last seen\n     * response from the server.\n     * @param {Object} options.pingOptions - The ping options if any.\n     * @constructor\n     */\n    constructor({ getTimeSinceLastServerResponse, onPingThresholdExceeded, pingOptions = {} }) {\n        super();\n        this.failedPings = 0;\n        this._onPingThresholdExceeded = onPingThresholdExceeded;\n        this._getTimeSinceLastServerResponse = getTimeSinceLastServerResponse;\n\n        this.pingInterval = typeof pingOptions.interval === 'number' ? pingOptions.interval : PING_DEFAULT_INTERVAL;\n        this.pingTimeout = typeof pingOptions.timeout === 'number' ? pingOptions.timeout : PING_DEFAULT_TIMEOUT;\n        this.pingThreshold = typeof pingOptions.threshold === 'number'\n            ? pingOptions.threshold : PING_DEFAULT_THRESHOLD;\n\n        // The number of timestamps of send pings to keep.\n        // The current value is 2 minutes.\n        this.pingTimestampsToKeep = Math.round(120000 / this.pingInterval);\n        this.pingExecIntervals = new Array(this.pingTimestampsToKeep);\n    }\n\n    /**\n     * Initializes the plugin. Method called by Strophe.\n     * @param connection Strophe connection instance.\n     */\n    init(connection) {\n        super.init(connection);\n        Strophe.addNamespace('PING', 'urn:xmpp:ping');\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     * Sends \"ping\" to given <tt>jid</tt>\n     * @param jid the JID to which ping request will be sent.\n     * @param success callback called on success.\n     * @param error callback called on error.\n     * @param timeout ms how long are we going to wait for the response. On\n     * timeout <tt>error<//t> callback is called with undefined error argument.\n     */\n    ping(jid, success, error, timeout) {\n        this._addPingExecutionTimestamp();\n\n        const iq = $iq({\n            type: 'get',\n            to: jid\n        });\n\n        iq.c('ping', { xmlns: Strophe.NS.PING });\n        this.connection.sendIQ2(iq, { timeout })\n            .then(success, error);\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Starts to send ping in given interval to specified remote JID.\n     * This plugin supports only one such task and <tt>stopInterval</tt>\n     * must be called before starting a new one.\n     * @param remoteJid remote JID to which ping requests will be sent to.\n     */\n    startInterval(remoteJid) {\n        clearInterval(this.intervalId);\n        this.intervalId = window.setInterval(() => {\n\n            // when there were some server responses in the interval since the last time we checked (_lastServerCheck)\n            // let's skip the ping\n\n            const now = Date.now();\n\n            if (this._getTimeSinceLastServerResponse() < now - this._lastServerCheck) {\n                // do this just to keep in sync the intervals so we can detect suspended device\n                this._addPingExecutionTimestamp();\n\n                this._lastServerCheck = now;\n                this.failedPings = 0;\n\n                return;\n            }\n\n            this.ping(remoteJid, () => {\n                // server response is measured on raw input and ping response time is measured after all the xmpp\n                // processing is done in js, so there can be some misalignment when we do the check above.\n                // That's why we store the last time we got the response\n                this._lastServerCheck = this._getTimeSinceLastServerResponse() + Date.now();\n\n                this.failedPings = 0;\n            }, error => {\n                this.failedPings += 1;\n                const errmsg = `Ping ${error ? 'error' : 'timeout'}`;\n\n                if (this.failedPings >= this.pingThreshold) {\n                    GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\n                    logger.error(errmsg, error);\n                    this._onPingThresholdExceeded && this._onPingThresholdExceeded();\n                } else {\n                    logger.warn(errmsg, error);\n                }\n            }, this.pingTimeout);\n        }, this.pingInterval);\n        logger.info(`XMPP pings will be sent every ${this.pingInterval} ms`);\n    }\n\n    /**\n     * Stops current \"ping\"  interval task.\n     */\n    stopInterval() {\n        if (this.intervalId) {\n            window.clearInterval(this.intervalId);\n            this.intervalId = null;\n            this.failedPings = 0;\n            logger.info('Ping interval cleared');\n        }\n    }\n\n    /**\n     * Adds the current time to the array of send ping timestamps.\n     * @private\n     */\n    _addPingExecutionTimestamp() {\n        this.pingExecIntervals.push(new Date().getTime());\n\n        // keep array length to PING_TIMESTAMPS_TO_KEEP\n        if (this.pingExecIntervals.length > this.pingTimestampsToKeep) {\n            this.pingExecIntervals.shift();\n        }\n    }\n\n    /**\n     * Returns the maximum time between the recent sent pings, if there is a\n     * big value it means the computer was inactive for some time(suspended).\n     * Checks the maximum gap between sending pings, considering and the\n     * current time. Trying to detect computer inactivity (sleep).\n     *\n     * @returns {int} the time ping was suspended, if it was not 0 is returned.\n     */\n    getPingSuspendTime() {\n        const pingIntervals = this.pingExecIntervals.slice();\n\n        // we need current time, as if ping was sent now\n        // if computer sleeps we will get correct interval after next\n        // scheduled ping, bet we sometimes need that interval before waiting\n        // for the next ping, on closing the connection on error.\n        pingIntervals.push(new Date().getTime());\n\n        let maxInterval = 0;\n        let previousTS = pingIntervals[0];\n\n        pingIntervals.forEach(e => {\n            const currentInterval = e - previousTS;\n\n            if (currentInterval > maxInterval) {\n                maxInterval = currentInterval;\n            }\n\n            previousTS = e;\n        });\n\n        // remove the interval between the ping sent\n        // this way in normal execution there is no suspend and the return\n        // will be 0 or close to 0.\n        maxInterval -= this.pingInterval;\n\n        // make sure we do not return less than 0\n        return Math.max(maxInterval, 0);\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { $pres, Strophe } from 'strophe.js';\nimport 'strophejs-plugin-stream-management';\n\nimport Listenable from '../util/Listenable';\n\nimport ResumeTask from './ResumeTask';\nimport LastSuccessTracker from './StropheLastSuccess';\nimport PingConnectionPlugin from './strophe.ping';\n\nconst logger = getLogger(__filename);\n\n/**\n * The lib-jitsi-meet layer for {@link Strophe.Connection}.\n */\nexport default class XmppConnection extends Listenable {\n    /**\n     * The list of {@link XmppConnection} events.\n     *\n     * @returns {Object}\n     */\n    static get Events() {\n        return {\n            CONN_STATUS_CHANGED: 'CONN_STATUS_CHANGED',\n            CONN_SHARD_CHANGED: 'CONN_SHARD_CHANGED'\n        };\n    }\n\n    /**\n     * The list of Xmpp connection statuses.\n     *\n     * @returns {Strophe.Status}\n     */\n    static get Status() {\n        return Strophe.Status;\n    }\n\n    /**\n     * Initializes new connection instance.\n     *\n     * @param {Object} options\n     * @param {String} options.serviceUrl - The BOSH or WebSocket service URL.\n     * @param {String} options.shard - The BOSH or WebSocket is connecting to this shard.\n     * Useful for detecting when shard changes.\n     * @param {String} [options.enableWebsocketResume=true] - True/false to control the stream resumption functionality.\n     * It will enable automatically by default if supported by the XMPP server.\n     * @param {Number} [options.websocketKeepAlive=60000] - The websocket keep alive interval.\n     * It's the interval + a up to a minute of jitter. Pass -1 to disable.\n     * The keep alive is HTTP GET request to {@link options.serviceUrl} or to {@link options.websocketKeepAliveUrl}.\n     * @param {Number} [options.websocketKeepAliveUrl] - The websocket keep alive url to use if any,\n     * if missing the serviceUrl url will be used.\n     * @param {Object} [options.xmppPing] - The xmpp ping settings.\n     */\n    constructor({ enableWebsocketResume, websocketKeepAlive, websocketKeepAliveUrl, serviceUrl, shard, xmppPing }) {\n        super();\n        this._options = {\n            enableWebsocketResume: typeof enableWebsocketResume === 'undefined' ? true : enableWebsocketResume,\n            pingOptions: xmppPing,\n            shard,\n            websocketKeepAlive: typeof websocketKeepAlive === 'undefined' ? 60 * 1000 : Number(websocketKeepAlive),\n            websocketKeepAliveUrl\n        };\n\n        this._stropheConn = new Strophe.Connection(serviceUrl);\n        this._usesWebsocket = serviceUrl.startsWith('ws:') || serviceUrl.startsWith('wss:');\n\n        // The default maxRetries is 5, which is too long.\n        this._stropheConn.maxRetries = 3;\n\n        this._rawInputTracker = new LastSuccessTracker();\n        this._rawInputTracker.startTracking(this, this._stropheConn);\n\n        this._resumeTask = new ResumeTask(this._stropheConn);\n\n        /**\n         * @typedef DeferredSendIQ Object\n         * @property {Element} iq - The IQ to send.\n         * @property {function} resolve - The resolve method of the deferred Promise.\n         * @property {function} reject - The reject method of the deferred Promise.\n         * @property {number} timeout - The ID of the timeout task that needs to be cleared, before sending the IQ.\n         */\n        /**\n         * Deferred IQs to be sent upon reconnect.\n         * @type {Array<DeferredSendIQ>}\n         * @private\n         */\n        this._deferredIQs = [];\n\n        // Ping plugin is mandatory for the Websocket mode to work correctly. It's used to detect when the connection\n        // is broken (WebSocket/TCP connection not closed gracefully).\n        this.addConnectionPlugin(\n            'ping',\n            new PingConnectionPlugin({\n                getTimeSinceLastServerResponse: () => this.getTimeSinceLastSuccess(),\n                onPingThresholdExceeded: () => this._onPingErrorThresholdExceeded(),\n                pingOptions: xmppPing\n            }));\n\n        // tracks whether this is the initial connection or a reconnect\n        this._oneSuccessfulConnect = false;\n    }\n\n    /**\n     * A getter for the connected state.\n     *\n     * @returns {boolean}\n     */\n    get connected() {\n        const websocket = this._stropheConn && this._stropheConn._proto && this._stropheConn._proto.socket;\n\n        return (this._status === Strophe.Status.CONNECTED || this._status === Strophe.Status.ATTACHED)\n            && (!this.isUsingWebSocket || (websocket && websocket.readyState === WebSocket.OPEN));\n    }\n\n    /**\n     * Retrieves the feature discovery plugin instance.\n     *\n     * @returns {Strophe.Connection.disco}\n     */\n    get disco() {\n        return this._stropheConn.disco;\n    }\n\n    /**\n     * A getter for the disconnecting state.\n     *\n     * @returns {boolean}\n     */\n    get disconnecting() {\n        return this._stropheConn.disconnecting === true;\n    }\n\n    /**\n     * A getter for the domain.\n     *\n     * @returns {string|null}\n     */\n    get domain() {\n        return this._stropheConn.domain;\n    }\n\n    /**\n     * Tells if Websocket is used as the transport for the current XMPP connection. Returns true for Websocket or false\n     * for BOSH.\n     * @returns {boolean}\n     */\n    get isUsingWebSocket() {\n        return this._usesWebsocket;\n    }\n\n    /**\n     * A getter for the JID.\n     *\n     * @returns {string|null}\n     */\n    get jid() {\n        return this._stropheConn.jid;\n    }\n\n    /**\n     * Returns headers for the last BOSH response received.\n     *\n     * @returns {string}\n     */\n    get lastResponseHeaders() {\n        return this._stropheConn._proto && this._stropheConn._proto.lastResponseHeaders;\n    }\n\n    /**\n     * A getter for the logger plugin instance.\n     *\n     * @returns {*}\n     */\n    get logger() {\n        return this._stropheConn.logger;\n    }\n\n    /**\n     * A getter for the connection options.\n     *\n     * @returns {*}\n     */\n    get options() {\n        return this._stropheConn.options;\n    }\n\n    /**\n     * A getter for the domain to be used for ping.\n     */\n    get pingDomain() {\n        return this._options.pingOptions?.domain || this.domain;\n    }\n\n    /**\n     * A getter for the service URL.\n     *\n     * @returns {string}\n     */\n    get service() {\n        return this._stropheConn.service;\n    }\n\n    /**\n     * Sets new value for shard.\n     * @param value the new shard value.\n     */\n    set shard(value) {\n        this._options.shard = value;\n\n        // shard setting changed so let's schedule a new keep-alive check if connected\n        if (this._oneSuccessfulConnect) {\n            this._maybeStartWSKeepAlive();\n        }\n    }\n\n    /**\n     * Returns the current connection status.\n     *\n     * @returns {Strophe.Status}\n     */\n    get status() {\n        return this._status;\n    }\n\n    /**\n     * Adds a connection plugin to this instance.\n     *\n     * @param {string} name - The name of the plugin or rather a key under which it will be stored on this connection\n     * instance.\n     * @param {ConnectionPluginListenable} plugin - The plugin to add.\n     */\n    addConnectionPlugin(name, plugin) {\n        this[name] = plugin;\n        plugin.init(this);\n    }\n\n    /**\n     * See {@link Strophe.Connection.addHandler}\n     *\n     * @returns {Object} - handler for the connection.\n     */\n    addHandler(...args) {\n        return this._stropheConn.addHandler(...args);\n    }\n\n    /**\n     * See {@link Strophe.Connection.deleteHandler}\n     *\n     * @returns {void}\n     */\n    deleteHandler(...args) {\n        this._stropheConn.deleteHandler(...args);\n    }\n\n    /* eslint-disable max-params */\n    /**\n     * Wraps {@link Strophe.Connection.attach} method in order to intercept the connection status updates.\n     * See {@link Strophe.Connection.attach} for the params description.\n     *\n     * @returns {void}\n     */\n    attach(jid, sid, rid, callback, ...args) {\n        this._stropheConn.attach(jid, sid, rid, this._stropheConnectionCb.bind(this, callback), ...args);\n    }\n\n    /**\n     * Wraps Strophe.Connection.connect method in order to intercept the connection status updates.\n     * See {@link Strophe.Connection.connect} for the params description.\n     *\n     * @returns {void}\n     */\n    connect(jid, pass, callback, ...args) {\n        this._stropheConn.connect(jid, pass, this._stropheConnectionCb.bind(this, callback), ...args);\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Handles {@link Strophe.Status} updates for the current connection.\n     *\n     * @param {function} targetCallback - The callback passed by the {@link XmppConnection} consumer to one of\n     * the connect methods.\n     * @param {Strophe.Status} status - The new connection status.\n     * @param {*} args - The rest of the arguments passed by Strophe.\n     * @private\n     */\n    _stropheConnectionCb(targetCallback, status, ...args) {\n        this._status = status;\n\n        let blockCallback = false;\n\n        if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {\n            this._maybeEnableStreamResume();\n\n            // after connecting - immediately check whether shard changed,\n            // we need this only when using websockets as bosh checks headers from every response\n            if (this._usesWebsocket && this._oneSuccessfulConnect) {\n                this._keepAliveAndCheckShard();\n            }\n            this._oneSuccessfulConnect = true;\n\n            this._maybeStartWSKeepAlive();\n            this._processDeferredIQs();\n            this._resumeTask.cancel();\n            this.ping.startInterval(this._options.pingOptions?.domain || this.domain);\n        } else if (status === Strophe.Status.DISCONNECTED) {\n            this.ping.stopInterval();\n\n            // FIXME add RECONNECTING state instead of blocking the DISCONNECTED update\n            blockCallback = this._tryResumingConnection();\n            if (!blockCallback) {\n                clearTimeout(this._wsKeepAlive);\n            }\n        }\n\n        if (!blockCallback) {\n            targetCallback(status, ...args);\n            this.eventEmitter.emit(XmppConnection.Events.CONN_STATUS_CHANGED, status);\n        }\n    }\n\n    /**\n     * Clears the list of IQs and rejects deferred Promises with an error.\n     *\n     * @private\n     */\n    _clearDeferredIQs() {\n        for (const deferred of this._deferredIQs) {\n            deferred.reject(new Error('disconnect'));\n        }\n        this._deferredIQs = [];\n    }\n\n    /**\n     * The method is meant to be used for testing. It's a shortcut for closing the WebSocket.\n     *\n     * @returns {void}\n     */\n    closeWebsocket() {\n        if (this._stropheConn && this._stropheConn._proto) {\n            this._stropheConn._proto._closeSocket();\n            this._stropheConn._proto._onClose(null);\n        }\n    }\n\n    /**\n     * See {@link Strophe.Connection.disconnect}.\n     *\n     * @returns {void}\n     */\n    disconnect(...args) {\n        this._resumeTask.cancel();\n        clearTimeout(this._wsKeepAlive);\n        this._clearDeferredIQs();\n        this._stropheConn.disconnect(...args);\n    }\n\n    /**\n     * See {@link Strophe.Connection.flush}.\n     *\n     * @returns {void}\n     */\n    flush(...args) {\n        this._stropheConn.flush(...args);\n    }\n\n    /**\n     * See {@link LastRequestTracker.getTimeSinceLastSuccess}.\n     *\n     * @returns {number|null}\n     */\n    getTimeSinceLastSuccess() {\n        return this._rawInputTracker.getTimeSinceLastSuccess();\n    }\n\n    /**\n     * See {@link LastRequestTracker.getLastFailedMessage}.\n     *\n     * @returns {string|null}\n     */\n    getLastFailedMessage() {\n        return this._rawInputTracker.getLastFailedMessage();\n    }\n\n    /**\n     * Requests a resume token from the server if enabled and all requirements are met.\n     *\n     * @private\n     */\n    _maybeEnableStreamResume() {\n        if (!this._options.enableWebsocketResume) {\n\n            return;\n        }\n\n        const { streamManagement } = this._stropheConn;\n\n        if (!this.isUsingWebSocket) {\n            logger.warn('Stream resume enabled, but WebSockets are not enabled');\n        } else if (!streamManagement) {\n            logger.warn('Stream resume enabled, but Strophe streamManagement plugin is not installed');\n        } else if (!streamManagement.isSupported()) {\n            logger.warn('Stream resume enabled, but XEP-0198 is not supported by the server');\n        } else if (!streamManagement.getResumeToken()) {\n            logger.info('Enabling XEP-0198 stream management');\n            streamManagement.enable(/* resume */ true);\n        }\n    }\n\n    /**\n     * Starts the Websocket keep alive if enabled.\n     *\n     * @private\n     * @returns {void}\n     */\n    _maybeStartWSKeepAlive() {\n        const { websocketKeepAlive } = this._options;\n\n        if (this._usesWebsocket && websocketKeepAlive > 0) {\n            this._wsKeepAlive || logger.info(`WebSocket keep alive interval: ${websocketKeepAlive}ms`);\n            clearTimeout(this._wsKeepAlive);\n\n            const intervalWithJitter = /* base */ websocketKeepAlive + /* jitter */ (Math.random() * 60 * 1000);\n\n            logger.debug(`Scheduling next WebSocket keep-alive in ${intervalWithJitter}ms`);\n\n            this._wsKeepAlive = setTimeout(\n                () => this._keepAliveAndCheckShard()\n                    .then(() => this._maybeStartWSKeepAlive()),\n                intervalWithJitter);\n        }\n    }\n\n    /**\n     * Do a http GET to the shard and if shard change will throw an event.\n     *\n     * @private\n     * @returns {Promise}\n     */\n    _keepAliveAndCheckShard() {\n        const { shard, websocketKeepAliveUrl } = this._options;\n        const url = websocketKeepAliveUrl ? websocketKeepAliveUrl\n            : this.service.replace('wss://', 'https://').replace('ws://', 'http://');\n\n        return fetch(url)\n            .then(response => {\n\n                // skips header checking if there is no info in options\n                if (!shard) {\n                    return;\n                }\n\n                const responseShard = response.headers.get('x-jitsi-shard');\n\n                if (responseShard !== shard) {\n                    logger.error(\n                        `Detected that shard changed from ${shard} to ${responseShard}`);\n                    this.eventEmitter.emit(XmppConnection.Events.CONN_SHARD_CHANGED);\n                }\n            })\n            .catch(error => {\n                logger.error(`Websocket Keep alive failed for url: ${url}`, { error });\n            });\n    }\n\n    /**\n     * Goes over the list of {@link DeferredSendIQ} tasks and sends them.\n     *\n     * @private\n     * @returns {void}\n     */\n    _processDeferredIQs() {\n        for (const deferred of this._deferredIQs) {\n            if (deferred.iq) {\n                clearTimeout(deferred.timeout);\n\n                const timeLeft = Date.now() - deferred.start;\n\n                this.sendIQ(\n                    deferred.iq,\n                    result => deferred.resolve(result),\n                    error => deferred.reject(error),\n                    timeLeft);\n            }\n        }\n\n        this._deferredIQs = [];\n    }\n\n    /**\n     * Send a stanza. This function is called to push data onto the send queue to go out over the wire.\n     *\n     * @param {Element|Strophe.Builder} stanza - The stanza to send.\n     * @returns {void}\n     */\n    send(stanza) {\n        if (!this.connected) {\n            logger.error(`Trying to send stanza while not connected. Status:${this._status} Proto:${\n                this.isUsingWebSocket ? this._stropheConn?._proto?.socket?.readyState : 'bosh'\n            }`);\n            throw new Error('Not connected');\n        }\n        this._stropheConn.send(stanza);\n    }\n\n    /**\n     * Helper function to send IQ stanzas.\n     *\n     * @param {Element} elem - The stanza to send.\n     * @param {Function} callback - The callback function for a successful request.\n     * @param {Function} errback - The callback function for a failed or timed out request.  On timeout, the stanza will\n     * be null.\n     * @param {number} timeout - The time specified in milliseconds for a timeout to occur.\n     * @returns {number} - The id used to send the IQ.\n     */\n    sendIQ(elem, callback, errback, timeout) {\n        if (!this.connected) {\n            errback('Not connected');\n\n            return;\n        }\n\n        return this._stropheConn.sendIQ(elem, callback, errback, timeout);\n    }\n\n    /**\n     * Sends an IQ immediately if connected or puts it on the send queue otherwise(in contrary to other send methods\n     * which would fail immediately if disconnected).\n     *\n     * @param {Element} iq - The IQ to send.\n     * @param {number} timeout - How long to wait for the response. The time when the connection is reconnecting is\n     * included, which means that the IQ may never be sent and still fail with a timeout.\n     */\n    sendIQ2(iq, { timeout }) {\n        return new Promise((resolve, reject) => {\n            if (this.connected) {\n                this.sendIQ(\n                    iq,\n                    result => resolve(result),\n                    error => reject(error),\n                    timeout);\n            } else {\n                const deferred = {\n                    iq,\n                    resolve,\n                    reject,\n                    start: Date.now(),\n                    timeout: setTimeout(() => {\n                        // clears the IQ on timeout and invalidates the deferred task\n                        deferred.iq = undefined;\n\n                        // Strophe calls with undefined on timeout\n                        reject(undefined);\n                    }, timeout)\n                };\n\n                this._deferredIQs.push(deferred);\n            }\n        });\n    }\n\n    /**\n     * Called by the ping plugin when ping fails too many times.\n     *\n     * @returns {void}\n     */\n    _onPingErrorThresholdExceeded() {\n        if (this.isUsingWebSocket) {\n            logger.warn('Ping error threshold exceeded - killing the WebSocket');\n            this.closeWebsocket();\n        }\n    }\n\n    /**\n     *  Helper function to send presence stanzas. The main benefit is for sending presence stanzas for which you expect\n     *  a responding presence stanza with the same id (for example when leaving a chat room).\n     *\n     * @param {Element} elem - The stanza to send.\n     * @param {Function} callback - The callback function for a successful request.\n     * @param {Function} errback - The callback function for a failed or timed out request. On timeout, the stanza will\n     * be null.\n     * @param {number} timeout - The time specified in milliseconds for a timeout to occur.\n     * @returns {number} - The id used to send the presence.\n     */\n    sendPresence(elem, callback, errback, timeout) {\n        if (!this.connected) {\n            errback('Not connected');\n\n            return;\n        }\n        this._stropheConn.sendPresence(elem, callback, errback, timeout);\n    }\n\n    /**\n     * The method gracefully closes the BOSH connection by using 'navigator.sendBeacon'.\n     *\n     * @returns {boolean} - true if the beacon was sent.\n     */\n    sendUnavailableBeacon() {\n        if (!navigator.sendBeacon || this._stropheConn.disconnecting || !this._stropheConn.connected) {\n            return false;\n        }\n\n        this._stropheConn._changeConnectStatus(Strophe.Status.DISCONNECTING);\n        this._stropheConn.disconnecting = true;\n\n        const body = this._stropheConn._proto._buildBody()\n            .attrs({\n                type: 'terminate'\n            });\n        const pres = $pres({\n            xmlns: Strophe.NS.CLIENT,\n            type: 'unavailable'\n        });\n\n        body.cnode(pres.tree());\n\n        const res = navigator.sendBeacon(\n            this.service.indexOf('https://') === -1 ? `https:${this.service}` : this.service,\n            Strophe.serialize(body.tree()));\n\n        logger.info(`Successfully send unavailable beacon ${res}`);\n\n        this._stropheConn._proto._abortAllRequests();\n        this._stropheConn._doDisconnect();\n\n        return true;\n    }\n\n    /**\n     * Tries to use stream management plugin to resume dropped XMPP connection. The streamManagement plugin clears\n     * the resume token if any connection error occurs which would put it in unrecoverable state, so as long as\n     * the token is present it means the connection can be resumed.\n     *\n     * @private\n     * @returns {boolean}\n     */\n    _tryResumingConnection() {\n        const { streamManagement } = this._stropheConn;\n        const resumeToken = streamManagement && streamManagement.getResumeToken();\n\n        if (resumeToken) {\n            this._resumeTask.schedule();\n\n            return true;\n        }\n\n        return false;\n    }\n}\n","export enum JitsiTranscriptionStatus {\n    /**\n     * The transcription is on.\n     */\n    ON = 'on',\n\n    /**\n     * The transcription is off.\n     */\n    OFF = 'off'\n}\n\n// exported for backward compatibility\nexport const ON = JitsiTranscriptionStatus.ON;\nexport const OFF = JitsiTranscriptionStatus.OFF;\n","import { getLogger } from '@jitsi/logger';\nimport { $msg } from 'strophe.js';\n\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * The AVModeration logic.\n */\nexport default class AVModeration {\n\n    /**\n     * Constructs AV moderation room.\n     *\n     * @param {ChatRoom} room the main room.\n     */\n    constructor(room) {\n        this._xmpp = room.xmpp;\n\n        this._mainRoom = room;\n\n        this._moderationEnabledByType = {\n            [MediaType.AUDIO]: false,\n            [MediaType.VIDEO]: false\n        };\n\n        this._whitelistAudio = [];\n        this._whitelistVideo = [];\n\n        this._onMessage = this._onMessage.bind(this);\n        this._xmpp.addListener(XMPPEvents.AV_MODERATION_RECEIVED, this._onMessage);\n    }\n\n    /**\n     * Stops listening for events.\n     */\n    dispose() {\n        this._xmpp.removeListener(XMPPEvents.AV_MODERATION_RECEIVED, this._onMessage);\n    }\n\n    /**\n     * Whether AV moderation is supported on backend.\n     *\n     * @returns {boolean} whether AV moderation is supported on backend.\n     */\n    isSupported() {\n        return Boolean(this._xmpp.avModerationComponentAddress);\n    }\n\n    /**\n     * Enables or disables AV Moderation by sending a msg with command to the component.\n     */\n    enable(state, mediaType) {\n        if (!this.isSupported() || !this._mainRoom.isModerator()) {\n            logger.error(`Cannot enable:${state} AV moderation supported:${this.isSupported()},\n                moderator:${this._mainRoom.isModerator()}`);\n\n            return;\n        }\n\n        if (state === this._moderationEnabledByType[mediaType]) {\n            logger.warn(`Moderation already in state:${state} for mediaType:${mediaType}`);\n\n            return;\n        }\n\n        // send the enable/disable message\n        const msg = $msg({ to: this._xmpp.avModerationComponentAddress });\n\n        msg.c('av_moderation', {\n            enable: state,\n            mediaType\n        }).up();\n\n        this._xmpp.connection.send(msg);\n    }\n\n    /**\n     * Approves that a participant can unmute by sending a msg with its jid to the component.\n     */\n    approve(mediaType, jid) {\n        if (!this.isSupported() || !this._mainRoom.isModerator()) {\n            logger.error(`Cannot approve in AV moderation supported:${this.isSupported()},\n                moderator:${this._mainRoom.isModerator()}`);\n\n            return;\n        }\n\n        // send a message to whitelist the jid and approve it to unmute\n        const msg = $msg({ to: this._xmpp.avModerationComponentAddress });\n\n        msg.c('av_moderation', {\n            mediaType,\n            jidToWhitelist: jid }).up();\n\n        this._xmpp.connection.send(msg);\n    }\n\n    /**\n     * Rejects that a participant can unmute by sending a msg with its jid to the component.\n     */\n    reject(mediaType, jid) {\n        if (!this.isSupported() || !this._mainRoom.isModerator()) {\n            logger.error(`Cannot reject in AV moderation supported:${this.isSupported()},\n                moderator:${this._mainRoom.isModerator()}`);\n\n            return;\n        }\n\n        // send a message to remove from whitelist the jid and reject it to unmute\n        const msg = $msg({ to: this._xmpp.avModerationComponentAddress });\n\n        msg.c('av_moderation', {\n            mediaType,\n            jidToBlacklist: jid\n        }).up();\n\n        this._xmpp.connection.send(msg);\n    }\n\n    /**\n     * Receives av_moderation parsed messages as json.\n     * @param obj the parsed json content of the message to process.\n     * @private\n     */\n    _onMessage(obj) {\n        const { removed, mediaType: media, enabled, approved, actor, whitelists: newWhitelists } = obj;\n\n        if (newWhitelists) {\n            const oldList = media === MediaType.AUDIO\n                ? this._whitelistAudio\n                : this._whitelistVideo;\n            const newList = Array.isArray(newWhitelists[media]) ? newWhitelists[media] : [];\n\n            if (removed) {\n                oldList.filter(x => !newList.includes(x))\n                    .forEach(jid => this._xmpp.eventEmitter\n                        .emit(XMPPEvents.AV_MODERATION_PARTICIPANT_REJECTED, media, jid));\n            } else {\n                newList.filter(x => !oldList.includes(x))\n                    .forEach(jid => this._xmpp.eventEmitter\n                        .emit(XMPPEvents.AV_MODERATION_PARTICIPANT_APPROVED, media, jid));\n            }\n\n            if (media === MediaType.AUDIO) {\n                this._whitelistAudio = newList;\n            } else {\n                this._whitelistVideo = newList;\n            }\n        } else if (enabled !== undefined && this._moderationEnabledByType[media] !== enabled) {\n            this._moderationEnabledByType[media] = enabled;\n\n            this._xmpp.eventEmitter.emit(XMPPEvents.AV_MODERATION_CHANGED, enabled, media, actor);\n        } else if (removed) {\n            this._xmpp.eventEmitter.emit(XMPPEvents.AV_MODERATION_REJECTED, media);\n        } else if (approved) {\n            this._xmpp.eventEmitter.emit(XMPPEvents.AV_MODERATION_APPROVED, media);\n        }\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { $msg, Strophe } from 'strophe.js';\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nconst FEATURE_KEY = 'features/breakout-rooms';\nconst BREAKOUT_ROOM_ACTIONS = {\n    ADD: `${FEATURE_KEY}/add`,\n    REMOVE: `${FEATURE_KEY}/remove`,\n    MOVE_TO_ROOM: `${FEATURE_KEY}/move-to-room`\n};\nconst BREAKOUT_ROOM_EVENTS = {\n    MOVE_TO_ROOM: `${FEATURE_KEY}/move-to-room`,\n    UPDATE: `${FEATURE_KEY}/update`\n};\n\nconst logger = getLogger(__filename);\n\n/**\n * Helper class for handling breakout rooms.\n */\nexport default class BreakoutRooms {\n\n    /**\n     * Constructs lobby room.\n     *\n     * @param {ChatRoom} room the room we are in.\n     */\n    constructor(room) {\n        this.room = room;\n\n        this._handleMessages = this._handleMessages.bind(this);\n        this.room.xmpp.addListener(XMPPEvents.BREAKOUT_ROOMS_EVENT, this._handleMessages);\n\n        this._rooms = {};\n    }\n\n    /**\n     * Stops listening for events.\n     */\n    dispose() {\n        this.room.xmpp.removeListener(XMPPEvents.BREAKOUT_ROOMS_EVENT, this._handleMessages);\n    }\n\n    /**\n     * Creates a breakout room with the given subject.\n     *\n     * @param {string} subject - A subject for the breakout room.\n     */\n    createBreakoutRoom(subject) {\n        if (!this.isSupported() || !this.room.isModerator()) {\n            logger.error(`Cannot create breakout room - supported:${this.isSupported()},\n                moderator:${this.room.isModerator()}`);\n\n            return;\n        }\n\n        const message = {\n            type: BREAKOUT_ROOM_ACTIONS.ADD,\n            subject\n        };\n\n        this._sendMessage(message);\n    }\n\n    /**\n     * Removes a breakout room.\n     *\n     * @param {string} breakoutRoomJid - JID of the room to be removed.\n     */\n    removeBreakoutRoom(breakoutRoomJid) {\n        if (!this.isSupported() || !this.room.isModerator()) {\n            logger.error(`Cannot remove breakout room - supported:${this.isSupported()},\n                moderator:${this.room.isModerator()}`);\n\n            return;\n        }\n\n        const message = {\n            type: BREAKOUT_ROOM_ACTIONS.REMOVE,\n            breakoutRoomJid\n        };\n\n        this._sendMessage(message);\n    }\n\n    /**\n     * Sends the given participant to the given room.\n     *\n     * @param {string} participantJid - JID of the participant to be sent to a room.\n     * @param {string} roomJid - JID of the target room.\n     */\n    sendParticipantToRoom(participantJid, roomJid) {\n        if (!this.isSupported() || !this.room.isModerator()) {\n            logger.error(`Cannot send participant to room - supported:${this.isSupported()},\n                moderator:${this.room.isModerator()}`);\n\n            return;\n        }\n\n        const message = {\n            type: BREAKOUT_ROOM_ACTIONS.MOVE_TO_ROOM,\n            participantJid,\n            roomJid\n        };\n\n        this._sendMessage(message);\n    }\n\n    /**\n     * Whether Breakout Rooms support is enabled in the backend or not.\n     */\n    isSupported() {\n        return Boolean(this.getComponentAddress());\n    }\n\n    /**\n     * Gets the address of the Breakout Rooms XMPP component.\n     *\n     * @returns The address of the component.\n     */\n    getComponentAddress() {\n        return this.room.xmpp.breakoutRoomsComponentAddress;\n    }\n\n    /**\n     * Stores if the current room is a breakout room.\n     *\n     * @param {boolean} isBreakoutRoom - Whether this room is a breakout room.\n     */\n    _setIsBreakoutRoom(isBreakoutRoom) {\n        this._isBreakoutRoom = isBreakoutRoom;\n    }\n\n    /**\n     * Checks whether this room is a breakout room.\n     *\n     * @returns True if the room is a breakout room, false otherwise.\n     */\n    isBreakoutRoom() {\n        if (typeof this._isBreakoutRoom !== 'undefined') {\n            return this._isBreakoutRoom;\n        }\n\n        // Use heuristic, helpful for checking in the MUC_JOINED event.\n        return Strophe.getDomainFromJid(this.room.myroomjid) === this.getComponentAddress();\n    }\n\n    /**\n     * Sets the main room JID associated with this breakout room. Only applies when\n     * in a breakout room.\n     *\n     * @param {string} jid - The main room JID.\n     */\n    _setMainRoomJid(jid) {\n        this._mainRoomJid = jid;\n    }\n\n    /**\n     * Gets the main room's JID associated with this breakout room.\n     *\n     * @returns The main room JID.\n     */\n    getMainRoomJid() {\n        return this._mainRoomJid;\n    }\n\n    /**\n     * Handles a message for managing breakout rooms.\n     *\n     * @param {object} payload - Arbitrary data.\n     */\n    _handleMessages(payload) {\n        switch (payload.event) {\n        case BREAKOUT_ROOM_EVENTS.MOVE_TO_ROOM:\n            this.room.eventEmitter.emit(XMPPEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM, payload.roomJid);\n            break;\n        case BREAKOUT_ROOM_EVENTS.UPDATE: {\n            const filteredPayload = this._filterUpdatePayload(payload);\n\n            this._rooms = filteredPayload.rooms;\n            this.room.eventEmitter.emit(XMPPEvents.BREAKOUT_ROOMS_UPDATED, filteredPayload);\n            break;\n        }\n        }\n    }\n\n    /**\n     * Filters the hidden participants from the payload.\n     *\n     * @param {Object} payload - The payload of the update message.\n     * @return {Object} - The filtered payload.\n     */\n    _filterUpdatePayload(payload) {\n        const hiddenDomain = this.room.options.hiddenDomain;\n        const { rooms } = payload;\n        const filteredRooms = {};\n\n        Object.entries(rooms).forEach(([ key, room ]) => {\n            const { participants = {} } = room;\n            const filteredParticipants = {};\n\n            Object.entries(participants).forEach(([ k, participant ]) => {\n                if (Strophe.getDomainFromJid(participant.jid) !== hiddenDomain) {\n                    filteredParticipants[k] = participant;\n                }\n            });\n\n            filteredRooms[key] = {\n                ...room,\n                participants: filteredParticipants\n            };\n        });\n\n        return {\n            ...payload,\n            rooms: filteredRooms\n        };\n    }\n\n    /**\n     * Helper to send a breakout rooms message to the component.\n     *\n     * @param {Object} message - Command that needs to be sent.\n     */\n    _sendMessage(message) {\n        const msg = $msg({ to: this.getComponentAddress() });\n\n        msg.c('breakout_rooms', message).up();\n\n        this.room.xmpp.connection.send(msg);\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { $msg, Strophe } from 'strophe.js';\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * The command type for updating a lobby participant's e-mail address.\n *\n * @type {string}\n */\nconst EMAIL_COMMAND = 'email';\n\n/**\n * The Lobby room implementation. Setting a room to members only, joining the lobby room\n * approving or denying access to participants from the lobby room.\n */\nexport default class Lobby {\n\n    /**\n     * Constructs lobby room.\n     *\n     * @param {ChatRoom} room the main room.\n     */\n    constructor(room) {\n        this.xmpp = room.xmpp;\n        this.mainRoom = room;\n\n        const maybeJoinLobbyRoom = this._maybeJoinLobbyRoom.bind(this);\n\n        this.mainRoom.addEventListener(\n            XMPPEvents.LOCAL_ROLE_CHANGED,\n            maybeJoinLobbyRoom);\n\n        this.mainRoom.addEventListener(\n            XMPPEvents.MUC_MEMBERS_ONLY_CHANGED,\n            maybeJoinLobbyRoom);\n\n        this.mainRoom.addEventListener(\n            XMPPEvents.ROOM_CONNECT_MEMBERS_ONLY_ERROR,\n            jid => {\n                this.lobbyRoomJid = jid;\n            });\n    }\n\n    /**\n     * Whether lobby is supported on backend.\n     *\n     * @returns {boolean} whether lobby is supported on backend.\n     */\n    isSupported() {\n        return this.xmpp.lobbySupported;\n    }\n\n    /**\n     * Enables lobby by setting the main room to be members only and joins the lobby chat room.\n     *\n     * @returns {Promise}\n     */\n    enable() {\n        if (!this.isSupported()) {\n            return Promise.reject(new Error('Lobby not supported!'));\n        }\n\n        return new Promise((resolve, reject) => {\n            this.mainRoom.setMembersOnly(true, resolve, reject);\n        });\n    }\n\n    /**\n     * Disable lobby by setting the main room to be non members only and levaes the lobby chat room if joined.\n     *\n     * @returns {void}\n     */\n    disable() {\n        if (!this.isSupported() || !this.mainRoom.isModerator()\n                || !this.lobbyRoom || !this.mainRoom.membersOnlyEnabled) {\n            return;\n        }\n\n        this.mainRoom.setMembersOnly(false);\n    }\n\n    /**\n     * Broadcast a message to all participants in the lobby room\n     * @param {Object} message The message to send\n     *\n     * @returns {void}\n     */\n    sendMessage(message) {\n        if (this.lobbyRoom) {\n            this.lobbyRoom.sendMessage(JSON.stringify(message), 'json-message');\n        }\n    }\n\n    /**\n     * Sends a private message to a participant in a lobby room.\n     * @param {string} id The message to send\n     * @param {Object} message The message to send\n     *\n     * @returns {void}\n     */\n    sendPrivateMessage(id, message) {\n        if (this.lobbyRoom) {\n            this.lobbyRoom.sendPrivateMessage(id, JSON.stringify(message), 'json-message');\n        }\n    }\n\n    /**\n     * Gets the local id for a participant in a lobby room.\n     * This is used for lobby room private chat messages.\n     *\n     * @returns {string}\n     */\n    getLocalId() {\n        if (this.lobbyRoom) {\n            return Strophe.getResourceFromJid(this.lobbyRoom.myroomjid);\n        }\n    }\n\n    /**\n     * Adds a message listener to the lobby room.\n     * @param {Function} listener The listener function,\n     * called when a new message is received in the lobby room.\n     *\n     * @returns {Function} Handler returned to be able to remove it later.\n     */\n    addMessageListener(listener) {\n        if (this.lobbyRoom) {\n            const handler = (participantId, message) => {\n                listener(message, Strophe.getResourceFromJid(participantId));\n            };\n\n            this.lobbyRoom.on(XMPPEvents.JSON_MESSAGE_RECEIVED, handler);\n\n            return handler;\n        }\n    }\n\n    /**\n     * Remove a message handler from the lobby room.\n     * @param {Function} handler The handler function to remove.\n     *\n     * @returns {void}\n     */\n    removeMessageHandler(handler) {\n        if (this.lobbyRoom) {\n            this.lobbyRoom.off(XMPPEvents.JSON_MESSAGE_RECEIVED, handler);\n        }\n    }\n\n    /**\n     * Leaves the lobby room.\n     *\n     * @returns {Promise}\n     */\n    leave() {\n        if (this.lobbyRoom) {\n            return this.lobbyRoom.leave()\n                .then(() => {\n                    this.lobbyRoom = undefined;\n                    logger.info('Lobby room left!');\n                })\n                .catch(() => {}); // eslint-disable-line no-empty-function\n        }\n\n        return Promise.reject(\n                new Error('The lobby has already been left'));\n    }\n\n    /**\n     * We had received a jid for the lobby room.\n     *\n     * @param jid the lobby room jid to join.\n     */\n    setLobbyRoomJid(jid) {\n        this.lobbyRoomJid = jid;\n    }\n\n    /**\n     * Checks the state of mainRoom, lobbyRoom and current user role to decide whether to join lobby room.\n     * @private\n     */\n    _maybeJoinLobbyRoom() {\n        if (!this.isSupported()) {\n            return;\n        }\n\n        const isModerator = this.mainRoom.joined && this.mainRoom.isModerator();\n\n        if (isModerator && this.mainRoom.membersOnlyEnabled && !this.lobbyRoom) {\n            // join the lobby\n            this.join()\n                .then(() => logger.info('Joined lobby room'))\n                .catch(e => logger.error('Failed joining lobby', e));\n        }\n    }\n\n    /**\n     * Joins a lobby room setting display name and eventually avatar(using the email provided).\n     *\n     * @param {string} username is required.\n     * @param {string} email is optional.\n     * @returns {Promise} resolves once we join the room.\n     */\n    join(displayName, email) {\n        const isModerator = this.mainRoom.joined && this.mainRoom.isModerator();\n\n        if (!this.lobbyRoomJid) {\n            return Promise.reject(new Error('Missing lobbyRoomJid, cannot join lobby room.'));\n        }\n\n        const roomName = Strophe.getNodeFromJid(this.lobbyRoomJid);\n        const customDomain = Strophe.getDomainFromJid(this.lobbyRoomJid);\n\n        this.lobbyRoom = this.xmpp.createRoom(\n            roomName, {\n                customDomain,\n                disableDiscoInfo: true,\n                disableFocus: true,\n                enableLobby: false\n            }\n        );\n\n        if (displayName) {\n            // remove previously set nickname\n            this.lobbyRoom.addOrReplaceInPresence('nick', {\n                attributes: { xmlns: 'http://jabber.org/protocol/nick' },\n                value: displayName\n            });\n        }\n\n        if (isModerator) {\n            this.lobbyRoom.addPresenceListener(EMAIL_COMMAND, (node, from) => {\n                this.mainRoom.eventEmitter.emit(XMPPEvents.MUC_LOBBY_MEMBER_UPDATED, from, { email: node.value });\n            });\n            this.lobbyRoom.addEventListener(\n                XMPPEvents.MUC_MEMBER_JOINED,\n                // eslint-disable-next-line max-params\n                (from, nick, role, isHiddenDomain, statsID, status, identity, botType, jid) => {\n                    // we need to ignore joins on lobby for participants that are already in the main room\n                    if (Object.values(this.mainRoom.members).find(m => m.jid === jid)) {\n                        return;\n                    }\n\n                    // Check if the user is a member if any breakout room.\n                    for (const room of Object.values(this.mainRoom.getBreakoutRooms()._rooms)) {\n                        if (Object.values(room.participants).find(p => p.jid === jid)) {\n                            return;\n                        }\n                    }\n\n                    // we emit the new event on the main room so we can propagate\n                    // events to the conference\n                    this.mainRoom.eventEmitter.emit(\n                        XMPPEvents.MUC_LOBBY_MEMBER_JOINED,\n                        Strophe.getResourceFromJid(from),\n                        nick,\n                        identity ? identity.avatar : undefined\n                    );\n                });\n            this.lobbyRoom.addEventListener(\n                XMPPEvents.MUC_MEMBER_LEFT, from => {\n                    // we emit the new event on the main room so we can propagate\n                    // events to the conference\n                    this.mainRoom.eventEmitter.emit(\n                        XMPPEvents.MUC_LOBBY_MEMBER_LEFT,\n                        Strophe.getResourceFromJid(from)\n                    );\n                });\n            this.lobbyRoom.addEventListener(\n                XMPPEvents.MUC_DESTROYED,\n                () => {\n                    // let's make sure we emit that all lobby users had left\n                    Object.keys(this.lobbyRoom.members)\n                        .forEach(j => this.mainRoom.eventEmitter.emit(\n                            XMPPEvents.MUC_LOBBY_MEMBER_LEFT, Strophe.getResourceFromJid(j)));\n\n                    this.lobbyRoom.clean();\n\n                    this.lobbyRoom = undefined;\n                    logger.info('Lobby room left(destroyed)!');\n                });\n        } else {\n            // this should only be handled by those waiting in lobby\n            this.lobbyRoom.addEventListener(XMPPEvents.KICKED, isSelfPresence => {\n                if (isSelfPresence) {\n                    this.mainRoom.eventEmitter.emit(XMPPEvents.MUC_DENIED_ACCESS);\n\n                    this.lobbyRoom.clean();\n\n                    return;\n                }\n            });\n\n            // As there is still reference of the main room\n            // the invite will be detected and addressed to its eventEmitter, even though we are not in it\n            // the invite message should be received directly to the xmpp conn in general\n            this.mainRoom.addEventListener(\n                XMPPEvents.INVITE_MESSAGE_RECEIVED,\n                (roomJid, from, txt, invitePassword) => {\n                    logger.debug(`Received approval to join ${roomJid} ${from} ${txt}`);\n                    if (roomJid === this.mainRoom.roomjid) {\n                        // we are now allowed, so let's join\n                        this.mainRoom.join(invitePassword);\n                    }\n                });\n            this.lobbyRoom.addEventListener(\n                XMPPEvents.MUC_DESTROYED,\n                (reason, jid) => {\n                    // we are receiving the jid of the main room\n                    // means we are invited to join, maybe lobby was disabled\n                    if (jid) {\n                        this.mainRoom.join();\n\n                        return;\n                    }\n\n                    this.lobbyRoom.clean();\n\n                    this.mainRoom.eventEmitter.emit(XMPPEvents.MUC_DESTROYED, reason);\n                });\n\n            // If participant retries joining shared password while waiting in the lobby\n            // and succeeds make sure we leave lobby\n            this.mainRoom.addEventListener(\n                XMPPEvents.MUC_JOINED,\n                () => {\n                    this.leave();\n                });\n        }\n\n        return new Promise((resolve, reject) => {\n            this.lobbyRoom.addEventListener(XMPPEvents.MUC_JOINED, () => {\n                resolve();\n\n                // send our email, as we do not handle this on initial presence we need a second one\n                if (email && !isModerator) {\n                    this.lobbyRoom.addOrReplaceInPresence(EMAIL_COMMAND, { value: email })\n                        && this.lobbyRoom.sendPresence();\n                }\n            });\n            this.lobbyRoom.addEventListener(XMPPEvents.ROOM_JOIN_ERROR, reject);\n            this.lobbyRoom.addEventListener(XMPPEvents.ROOM_CONNECT_NOT_ALLOWED_ERROR, reject);\n            this.lobbyRoom.addEventListener(XMPPEvents.ROOM_CONNECT_ERROR, reject);\n\n            this.lobbyRoom.join();\n        });\n\n    }\n\n    /**\n     * Should be possible only for moderators.\n     * @param id\n     */\n    denyAccess(id) {\n        if (!this.isSupported() || !this.mainRoom.isModerator()) {\n            return;\n        }\n\n        const jid = Object.keys(this.lobbyRoom.members)\n            .find(j => Strophe.getResourceFromJid(j) === id);\n\n        if (jid) {\n            this.lobbyRoom.kick(jid);\n        } else {\n            logger.error(`Not found member for ${id} in lobby room.`);\n        }\n    }\n\n    /**\n     * Should be possible only for moderators.\n     * @param id\n     */\n    approveAccess(id) {\n        if (!this.isSupported() || !this.mainRoom.isModerator()) {\n            return;\n        }\n\n        // Get the main room JID. If we are in a breakout room we'll use the main\n        // room's lobby.\n        let mainRoomJid = this.mainRoom.roomjid;\n\n        if (this.mainRoom.getBreakoutRooms().isBreakoutRoom()) {\n            mainRoomJid = this.mainRoom.getBreakoutRooms().getMainRoomJid();\n        }\n\n        const memberRoomJid = Object.keys(this.lobbyRoom.members)\n            .find(j => Strophe.getResourceFromJid(j) === id);\n\n        if (memberRoomJid) {\n            const jid = this.lobbyRoom.members[memberRoomJid].jid;\n            const msgToSend\n                = $msg({ to: mainRoomJid })\n                    .c('x', { xmlns: 'http://jabber.org/protocol/muc#user' })\n                    .c('invite', { to: jid });\n\n            this.xmpp.connection.sendIQ(msgToSend,\n                () => { }, // eslint-disable-line no-empty-function\n                e => {\n                    logger.error(`Error sending invite for ${jid}`, e);\n                });\n        } else {\n            logger.error(`Not found member for ${memberRoomJid} in lobby room.`);\n        }\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport isEqual from 'lodash.isequal';\nimport { $msg } from 'strophe.js';\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nimport { JITSI_MEET_MUC_TYPE } from './xmpp';\n\nconst logger = getLogger(__filename);\n\n/**\n * Helper class for handling room metadata.\n */\nexport default class RoomMetadata {\n    room: any;\n    _metadata: any;\n\n    /**\n     * Constructs lobby room.\n     *\n     * @param {ChatRoom} room the room we are in.\n     */\n    constructor(room) {\n        this.room = room;\n\n        this._handleMessages = this._handleMessages.bind(this);\n        this.room.xmpp.addListener(XMPPEvents.ROOM_METADATA_EVENT, this._handleMessages);\n\n        this._metadata = {};\n    }\n\n    /**\n     * Stops listening for events.\n     */\n    dispose() {\n        this.room.xmpp.removeListener(XMPPEvents.ROOM_METADATA_EVENT, this._handleMessages);\n    }\n\n    /**\n     * Sets metadata for the given key.\n     *\n     * @param {string} key - key under which the metadata will be stored.\n     * @param {object} data - data to be stored.\n     */\n    setMetadata(key, data) {\n        if (!this.isSupported() || !this.room.isModerator()) {\n            logger.error(`Cannot set room metadata - supported:${this.isSupported()},\n                moderator:${this.room.isModerator()}`);\n\n            return;\n        }\n\n        const message = {\n            key,\n            data\n        };\n\n        this._sendMessage(message);\n    }\n\n    /**\n     * Gets the stored metadata (all of it).\n     *\n     * @returns The stored metadata.\n     */\n    getMetadata() {\n        return this._metadata;\n    }\n\n    /**\n     * Whether Breakout Rooms support is enabled in the backend or not.\n     */\n    isSupported() {\n        return Boolean(this.getComponentAddress());\n    }\n\n    /**\n     * Gets the address of the Breakout Rooms XMPP component.\n     *\n     * @returns The address of the component.\n     */\n    getComponentAddress() {\n        return this.room.xmpp.roomMetadataComponentAddress;\n    }\n\n    /**\n     * Handles a message with metadata updates.\n     *\n     * @param {object} payload - Arbitrary data.\n     */\n    _handleMessages(payload) {\n        const { metadata } = payload;\n\n        if (!metadata || isEqual(this._metadata, metadata)) {\n            return;\n        }\n\n        this._metadata = metadata;\n        this.room.eventEmitter.emit(XMPPEvents.ROOM_METADATA_UPDATED, metadata);\n    }\n\n    /**\n     * Helper to send a breakout rooms message to the component.\n     *\n     * @param {Object} message - Command that needs to be sent.\n     */\n    _sendMessage(message) {\n        message[JITSI_MEET_MUC_TYPE] = 'room_metadata';\n\n        const msg = $msg({ to: this.getComponentAddress() });\n\n        msg.c('room_metadata', {\n            room: this.room.roomjid,\n            xmlns: 'http://jitsi.org/jitmeet'\n        }, JSON.stringify(message)).up();\n\n        this.room.xmpp.connection.send(msg);\n    }\n}\n","import { jitsiLocalStorage } from '@jitsi/js-utils';\nimport { getLogger } from '@jitsi/logger';\n\nconst logger = getLogger(__filename);\n\nimport UsernameGenerator from '../util/UsernameGenerator';\n\nlet _callStatsUserName;\n\nlet _machineId;\n\n/**\n *\n */\nexport default {\n\n    /**\n     * The storage used to store the settings.\n     */\n    _storage: jitsiLocalStorage,\n\n    /**\n     * Initializes the Settings class.\n     *\n     * @param {Storage|undefined} externalStorage - Object that implements the Storage interface. This object will be\n     * used for storing data instead of jitsiLocalStorage if specified.\n     */\n    init(externalStorage) {\n        this._storage = externalStorage || jitsiLocalStorage;\n    },\n\n    /**\n     * Returns fake username for callstats\n     * @returns {string} fake username for callstats\n     */\n    get callStatsUserName() {\n        if (!_callStatsUserName) {\n            _callStatsUserName = this._storage.getItem('callStatsUserName');\n            if (!_callStatsUserName) {\n                _callStatsUserName = generateCallStatsUserName();\n                this._storage.setItem('callStatsUserName', _callStatsUserName);\n            }\n        }\n\n        return _callStatsUserName;\n    },\n\n    /**\n     * Returns current machine id.\n     * @returns {string} machine id\n     */\n    get machineId() {\n        if (!_machineId) {\n            const amDid = this._storage.getItem('billingId');\n\n            _machineId = amDid || this._storage.getItem('jitsiMeetId');\n\n            if (amDid) {\n                this._storage.setItem('jitsiMeetId', amDid);\n            } else if (!_machineId) {\n                _machineId = generateJitsiMeetId();\n                this._storage.setItem('jitsiMeetId', _machineId);\n            }\n        }\n\n        return _machineId;\n    },\n\n    /**\n     * Returns current session id.\n     * @returns {string} current session id\n     */\n    get sessionId() {\n        // We may update sessionId in localStorage from another JitsiConference\n        // instance and that's why we should always re-read it.\n        return this._storage.getItem('sessionId');\n    },\n\n    /**\n     * Save current session id.\n     * @param {string} sessionId session id\n     */\n    set sessionId(sessionId) {\n        if (sessionId) {\n            this._storage.setItem('sessionId', sessionId);\n        } else {\n            this._storage.removeItem('sessionId');\n        }\n    }\n};\n\n/**\n * Generate fake username for callstats.\n * @returns {string} fake random username\n */\nfunction generateCallStatsUserName() {\n    const username = UsernameGenerator.generateUsername();\n\n    logger.log('generated callstats uid', username);\n\n    return username;\n}\n\n/**\n * Generate unique id.\n * @returns {string} random unique id\n */\nfunction generateJitsiMeetId() {\n    const jitsiMeetId = generateUniqueId();\n\n    logger.log('generated id', jitsiMeetId);\n\n    return jitsiMeetId;\n}\n\n/**\n *\n */\nfunction generateUniqueId() {\n    return _p8() + _p8() + _p8() + _p8();\n}\n\n/**\n *\n */\nfunction _p8() {\n    return `${Math.random().toString(16)}000000000`.substr(2, 8);\n}\n","/* eslint-disable newline-per-chained-call */\nimport { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $iq, Strophe } from 'strophe.js';\n\nimport FeatureFlags from '../flags/FeatureFlags';\nimport Settings from '../settings/Settings';\n\nconst AuthenticationEvents\n    = require('../../service/authentication/AuthenticationEvents');\nconst { XMPPEvents } = require('../../service/xmpp/XMPPEvents');\nconst GlobalOnErrorHandler = require('../util/GlobalOnErrorHandler');\n\nconst logger = getLogger(__filename);\n\n/**\n *\n * @param step\n */\nfunction createExpBackoffTimer(step) {\n    let count = 1;\n    const maxTimeout = 120000;\n\n    return function(reset) {\n        // Reset call\n        if (reset) {\n            count = 1;\n\n            return;\n        }\n\n        // Calculate next timeout\n        const timeout = Math.pow(2, count - 1);\n\n        count += 1;\n\n        return Math.min(timeout * step, maxTimeout);\n    };\n}\n\n/**\n *\n * @param roomName\n * @param xmpp\n * @param emitter\n * @param options\n */\nexport default function Moderator(roomName, xmpp, emitter, options) {\n    this.roomName = roomName;\n    this.getNextTimeout = createExpBackoffTimer(1000);\n    this.getNextErrorTimeout = createExpBackoffTimer(1000);\n    this.options = options;\n\n    // External authentication stuff\n    this.externalAuthEnabled = false;\n\n    // Whether SIP gateway (jigasi) support is enabled. TODO: use presence so it can be changed based on jigasi\n    // availability.\n    this.sipGatewayEnabled = false;\n\n    this.eventEmitter = emitter;\n\n    this.connection = xmpp.connection;\n\n    // The JID to which conference-iq requests are sent over XMPP.\n    this.targetJid = this.options.hosts?.focus;\n\n    // If not specified default to 'focus.domain'\n    if (!this.targetJid) {\n        this.targetJid = `focus.${this.options.hosts?.domain}`;\n    }\n\n    this.targetUrl = this.options.conferenceRequestUrl;\n\n    // Whether to send conference requests over HTTP or XMPP\n    this.mode = this.targetUrl ? 'http' : 'xmpp';\n    logger.info(`Using ${this.mode} for conference requests.`);\n\n    // The set of JIDs known to belong to jicofo. Populated from configuration\n    // and responses from conference requests.\n    this.focusUserJids = new Set();\n\n    if (options.focusUserJid) {\n        this.focusUserJids.add(options.focusUserJid);\n    }\n\n    // FIXME: Message listener that talks to POPUP window\n    /**\n     *\n     * @param event\n     */\n    function listener(event) {\n        if (event.data && event.data.sessionId) {\n            if (event.origin !== window.location.origin) {\n                logger.warn(`Ignoring sessionId from different origin: ${event.origin}`);\n\n                return;\n            }\n            Settings.sessionId = event.data.sessionId;\n\n            // After popup is closed we will authenticate\n        }\n    }\n\n    // Register\n    if (window.addEventListener) {\n        window.addEventListener('message', listener, false);\n    } else {\n        window.attachEvent('onmessage', listener);\n    }\n}\n\nModerator.prototype.isFocusJid = function(jid) {\n    if (!jid) {\n        return false;\n    }\n\n    for (const focusJid of this.focusUserJids) {\n        // jid may be a full JID, and focusUserJids may be bare JIDs\n        if (jid.indexOf(`${focusJid}/`) === 0) {\n            return true;\n        }\n    }\n\n    return false;\n};\n\nModerator.prototype.isExternalAuthEnabled = function() {\n    return this.externalAuthEnabled;\n};\n\nModerator.prototype.isSipGatewayEnabled = function() {\n    return this.sipGatewayEnabled;\n};\n\n/**\n * Create a conference request based on the configured options and saved Settings.\n *\n * A conference request has the following format:\n * {\n *   room: \"room@example.com\",\n *   sessionId: \"foo\", // optional\n *   machineUdi: \"bar\", // optional\n *   identity: \"baz\", // optional\n *   properties: { } // map string to string\n * }\n *\n * It can be encoded in either JSON or and IQ.\n *\n * @returns the created conference request.\n */\nModerator.prototype._createConferenceRequest = function() {\n\n    // Session Id used for authentication\n    const { sessionId } = Settings;\n    const config = this.options;\n    const properties = {};\n\n    if (config.startAudioMuted !== undefined) {\n        properties.startAudioMuted = config.startAudioMuted;\n    }\n    if (config.startVideoMuted !== undefined) {\n        properties.startVideoMuted = config.startVideoMuted;\n    }\n\n    // this flag determines whether the bridge will include this call in its\n    // rtcstats reporting or not. If the site admin hasn't set the flag in\n    // config.js, then the client defaults to false (see\n    // react/features/rtcstats/functions.js in jitsi-meet). The server-side\n    // components default to true to match the pre-existing behavior so we only\n    // signal if false.\n    const rtcstatsEnabled = config?.analytics?.rtcstatsEnabled ?? false;\n\n    if (!rtcstatsEnabled) {\n        properties.rtcstatsEnabled = false;\n    }\n\n    const conferenceRequest = {\n        properties,\n        machineUid: Settings.machineId,\n        room: this.roomName\n    };\n\n    if (sessionId) {\n        conferenceRequest.sessionId = sessionId;\n    }\n\n    return conferenceRequest;\n};\n\n/**\n * Create a conference request and encode it as an IQ.\n */\nModerator.prototype._createConferenceIq = function() {\n    const conferenceRequest = this._createConferenceRequest();\n\n    // Generate create conference IQ\n    const elem = $iq({ to: this.targetJid,\n        type: 'set' });\n\n    elem.c('conference', {\n        xmlns: 'http://jitsi.org/protocol/focus',\n        room: this.roomName,\n        'machine-uid': conferenceRequest.machineUid\n    });\n\n    if (conferenceRequest.sessionId) {\n        elem.attrs({ 'session-id': conferenceRequest.sessionId });\n    }\n\n    for (const k in conferenceRequest.properties) {\n        if (conferenceRequest.properties.hasOwnProperty(k)) {\n            elem.c(\n                'property', {\n                    name: k,\n                    value: conferenceRequest.properties[k]\n                }).up();\n        }\n    }\n    if (FeatureFlags.isJoinAsVisitorSupported()) {\n        elem.c('property', {\n            name: 'visitors-version',\n            value: 1 }).up();\n    }\n\n    return elem;\n};\n\nModerator.prototype._parseConferenceIq = function(resultIq) {\n    const conferenceRequest = { properties: {} };\n\n    conferenceRequest.focusJid = $(resultIq).find('conference').attr('focusjid');\n    conferenceRequest.sessionId = $(resultIq).find('conference').attr('session-id');\n    conferenceRequest.identity = $(resultIq).find('>conference').attr('identity');\n    conferenceRequest.ready = $(resultIq).find('conference').attr('ready') === 'true';\n    conferenceRequest.vnode = $(resultIq).find('conference').attr('vnode');\n\n    if ($(resultIq).find('>conference>property[name=\\'authentication\\'][value=\\'true\\']').length > 0) {\n        conferenceRequest.properties.authentication = 'true';\n    }\n\n    if ($(resultIq).find('>conference>property[name=\\'externalAuth\\'][value=\\'true\\']').length > 0) {\n        conferenceRequest.properties.externalAuth = 'true';\n    }\n\n    // Check if jicofo has jigasi support enabled.\n    if ($(resultIq).find('>conference>property[name=\\'sipGatewayEnabled\\'][value=\\'true\\']').length > 0) {\n        conferenceRequest.properties.sipGatewayEnabled = 'true';\n    }\n\n    return conferenceRequest;\n};\n\n// FIXME We need to show the fact that we're waiting for the focus to the user\n// (or that the focus is not available)\n/**\n * Allocates the conference focus.\n *\n * @param {Function} callback - the function to be called back upon the\n * successful allocation of the conference focus\n * @returns {Promise} - Resolved when Jicofo allows to join the room. It's never\n * rejected and it'll keep on pinging Jicofo forever.\n */\nModerator.prototype.sendConferenceRequest = function() {\n    return new Promise(resolve => {\n        if (this.mode === 'xmpp') {\n            logger.info(`Sending conference request over XMPP to ${this.targetJid}`);\n\n            this.connection.sendIQ(\n                this._createConferenceIq(),\n                result => this._handleIqSuccess(result, resolve),\n                error => this._handleIqError(error, resolve));\n\n            // XXX We're pressed for time here because we're beginning a complex\n            // and/or lengthy conference-establishment process which supposedly\n            // involves multiple RTTs. We don't have the time to wait for Strophe to\n            // decide to send our IQ.\n            this.connection.flush();\n        } else {\n            logger.info(`Sending conference request over HTTP to ${this.targetUrl}`);\n            fetch(this.targetUrl, {\n                method: 'POST',\n                body: JSON.stringify(this._createConferenceRequest()),\n                headers: { 'Content-Type': 'application/json' }\n            })\n            .then(response => {\n                if (!response.ok) {\n                    response.text().then(text => {\n                        logger.warn(`Received HTTP ${response.status} ${response.statusText}. Body: ${text}`);\n                        const sessionError = response.status === 400 && text.indexOf('400 invalid-session') > 0;\n                        const notAuthorized = response.status === 403;\n\n                        this._handleError(sessionError, notAuthorized, resolve);\n                    })\n                    .catch(error => {\n                        logger.warn(`Error: ${error}`);\n                        this._handleError();\n                    });\n\n                    // _handleError has either scheduled a retry or fired an event indicating failure.\n                    return;\n                }\n                response.json().then(resultJson => {\n                    this._handleSuccess(resultJson, resolve);\n                });\n            })\n            .catch(error => {\n                logger.warn(`Error: ${error}`);\n                this._handleError();\n            });\n        }\n    });\n};\n\nModerator.prototype._handleSuccess = function(conferenceRequest, callback) {\n\n    // Reset the error timeout (because we haven't failed here).\n    this.getNextErrorTimeout(true);\n\n    if (conferenceRequest.focusJid) {\n        logger.info(`Adding focus JID: ${conferenceRequest.focusJid}`);\n        this.focusUserJids.add(conferenceRequest.focusJid);\n    } else {\n        logger.warn('Conference request response contained no focusJid.');\n    }\n\n    const authenticationEnabled = conferenceRequest.properties.authentication === 'true';\n\n    logger.info(`Authentication enabled: ${authenticationEnabled}`);\n\n    this.externalAuthEnabled = conferenceRequest.properties.externalAuth === 'true';\n    logger.info(`External authentication enabled: ${this.externalAuthEnabled}`);\n\n    if (!this.externalAuthEnabled && conferenceRequest.sessionId) {\n        logger.info(`Received sessionId: ${conferenceRequest.sessionId}`);\n        Settings.sessionId = conferenceRequest.sessionId;\n    }\n\n    this.eventEmitter.emit(AuthenticationEvents.IDENTITY_UPDATED, authenticationEnabled, conferenceRequest.identity);\n\n    this.sipGatewayEnabled = conferenceRequest.properties.sipGatewayEnabled;\n    logger.info(`Sip gateway enabled: ${this.sipGatewayEnabled}`);\n\n    if (conferenceRequest.ready) {\n        // Reset the non-error timeout (because we've succeeded here).\n        this.getNextTimeout(true);\n\n        // we want to ignore redirects when this is jibri (record/live-stream or a sip jibri)\n        if (conferenceRequest.vnode && !this.options.iAmRecorder && !this.options.iAmSipGateway) {\n            logger.warn(`Redirected to: ${conferenceRequest.vnode} with focusJid ${conferenceRequest.focusJid} }`);\n\n            this.eventEmitter.emit(XMPPEvents.REDIRECTED, conferenceRequest.vnode, conferenceRequest.focusJid);\n\n            return;\n        }\n\n        logger.info('Conference-request successful, ready to join the MUC.');\n        callback();\n    } else {\n        const waitMs = this.getNextTimeout();\n\n        // This was a successful response, but the \"ready\" flag is not set. Retry after a timeout.\n        logger.info(`Not ready yet, will retry in ${waitMs} ms.`);\n        window.setTimeout(\n            () => this.sendConferenceRequest().then(callback),\n            waitMs);\n    }\n};\n\nModerator.prototype._handleError = function(sessionError, notAuthorized, callback) {\n    // If the session is invalid, remove and try again without session ID to get\n    // a new one\n    if (sessionError) {\n        logger.info('Session expired! - removing');\n        Settings.sessionId = undefined;\n    }\n\n    // Not authorized to create new room\n    if (notAuthorized) {\n        logger.warn('Unauthorized to start the conference');\n        this.eventEmitter.emit(XMPPEvents.AUTHENTICATION_REQUIRED);\n\n        return;\n    }\n\n    const waitMs = this.getNextErrorTimeout();\n\n    if (sessionError && waitMs < 60000) {\n        // If the session is invalid, retry a limited number of times and then fire an error.\n        logger.info(`Invalid session, will retry after ${waitMs} ms.`);\n        this.getNextTimeout(true);\n        window.setTimeout(() => this.sendConferenceRequest().then(callback), waitMs);\n    } else {\n        const errmsg = 'Failed to get a successful response, giving up.';\n        const error = new Error(errmsg);\n\n        logger.error(errmsg, error);\n        GlobalOnErrorHandler.callErrorHandler(error);\n\n        // This is a \"fatal\" error and the user of the lib should handle it accordingly.\n        // TODO: change the event name to something accurate.\n        this.eventEmitter.emit(XMPPEvents.FOCUS_DISCONNECTED);\n    }\n};\n\n/**\n * Invoked by {@link #sendConferenecRequest} upon its request receiving an\n * error result.\n *\n * @param error - the error result of the request that {@link sendConferenceRequest} sent\n * @param {Function} callback - the function to be called back upon the\n * successful allocation of the conference focus\n */\nModerator.prototype._handleIqError = function(error, callback) {\n\n    // The reservation system only works over XMPP. Handle the error separately.\n    // Check for error returned by the reservation system\n    const reservationErr = $(error).find('>error>reservation-error');\n\n    if (reservationErr.length) {\n        // Trigger error event\n        const errorCode = reservationErr.attr('error-code');\n        const errorTextNode = $(error).find('>error>text');\n        let errorMsg;\n\n        if (errorTextNode) {\n            errorMsg = errorTextNode.text();\n        }\n        this.eventEmitter.emit(\n            XMPPEvents.RESERVATION_ERROR,\n            errorCode,\n            errorMsg);\n\n        return;\n    }\n\n    const invalidSession\n        = Boolean($(error).find('>error>session-invalid').length\n            || $(error).find('>error>not-acceptable').length);\n\n    // Not authorized to create new room\n    const notAuthorized = $(error).find('>error>not-authorized').length > 0;\n\n    if (notAuthorized && Strophe.getDomainFromJid(error.getAttribute('to')) !== this.options.hosts.anonymousdomain) {\n        // FIXME \"is external\" should come either from the focus or\n        // config.js\n        this.externalAuthEnabled = true;\n    }\n\n    this._handleError(invalidSession, notAuthorized, callback);\n};\n\n/**\n * Invoked by {@link #sendConferenecRequest} upon its request receiving a\n * success (i.e. non-error) result.\n *\n * @param result - the success (i.e. non-error) result of the request that {@link #sendConferenecRequest} sent\n * @param {Function} callback - the function to be called back upon the\n * successful allocation of the conference focus\n */\nModerator.prototype._handleIqSuccess = function(\n        result,\n        callback) {\n    // Setup config options\n    const conferenceRequest = this._parseConferenceIq(result);\n\n    this._handleSuccess(conferenceRequest, callback);\n};\n\nModerator.prototype.authenticate = function() {\n    return new Promise((resolve, reject) => {\n        this.connection.sendIQ(\n            this._createConferenceIq(),\n            result => {\n                const sessionId = $(result).find('conference').attr('session-id');\n\n                if (sessionId) {\n                    logger.info(`Received sessionId:  ${sessionId}`);\n                    Settings.sessionId = sessionId;\n                } else {\n                    logger.warn('Response did not contain a session-id');\n                }\n\n                resolve();\n            },\n            errorIq => reject({\n                error: $(errorIq).find('iq>error :first').prop('tagName'),\n                message: $(errorIq).find('iq>error>text').text()\n            })\n        );\n    });\n};\n\nModerator.prototype.getLoginUrl = function(urlCallback, failureCallback) {\n    this._getLoginUrl(/* popup */ false, urlCallback, failureCallback);\n};\n\n/**\n *\n * @param {boolean} popup false for {@link Moderator#getLoginUrl} or true for\n * {@link Moderator#getPopupLoginUrl}\n * @param urlCb\n * @param failureCb\n */\nModerator.prototype._getLoginUrl = function(popup, urlCb, failureCb) {\n    const iq = $iq({ to: this.targetJid,\n        type: 'get' });\n    const attrs = {\n        xmlns: 'http://jitsi.org/protocol/focus',\n        room: this.roomName,\n        'machine-uid': Settings.machineId\n    };\n    let str = 'auth url'; // for logger\n\n    if (popup) {\n        attrs.popup = true;\n        str = `POPUP ${str}`;\n    }\n    iq.c('login-url', attrs);\n\n    /**\n     * Implements a failure callback which reports an error message and an error\n     * through (1) GlobalOnErrorHandler, (2) logger, and (3) failureCb.\n     *\n     * @param {string} errmsg the error messsage to report\n     * @param {*} error the error to report (in addition to errmsg)\n     */\n    function reportError(errmsg, err) {\n        GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\n        logger.error(errmsg, err);\n        failureCb(err);\n    }\n    this.connection.sendIQ(\n        iq,\n        result => {\n            let url = $(result).find('login-url').attr('url');\n\n            url = decodeURIComponent(url);\n            if (url) {\n                logger.info(`Got ${str}: ${url}`);\n                urlCb(url);\n            } else {\n                reportError(`Failed to get ${str} from the focus`, result);\n            }\n        },\n        reportError.bind(undefined, `Get ${str} error`)\n    );\n};\n\nModerator.prototype.getPopupLoginUrl = function(urlCallback, failureCallback) {\n    this._getLoginUrl(/* popup */ true, urlCallback, failureCallback);\n};\n\nModerator.prototype.logout = function(callback) {\n    const iq = $iq({ to: this.targetJid,\n        type: 'set' });\n    const { sessionId } = Settings;\n\n    if (!sessionId) {\n        callback();\n\n        return;\n    }\n    iq.c('logout', {\n        xmlns: 'http://jitsi.org/protocol/focus',\n        'session-id': sessionId\n    });\n    this.connection.sendIQ(\n        iq,\n        result => {\n            let logoutUrl = $(result).find('logout').attr('logout-url');\n\n            if (logoutUrl) {\n                logoutUrl = decodeURIComponent(logoutUrl);\n            }\n            logger.info(`Log out OK, url: ${logoutUrl}`, result);\n            Settings.sessionId = undefined;\n            callback(logoutUrl);\n        },\n        error => {\n            const errmsg = 'Logout error';\n\n            GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\n            logger.error(errmsg, error);\n        }\n    );\n};\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport isEqual from 'lodash.isequal';\nimport { $iq, $msg, $pres, Strophe } from 'strophe.js';\n\nimport * as JitsiTranscriptionStatus from '../../JitsiTranscriptionStatus';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\nimport Listenable from '../util/Listenable';\n\nimport AVModeration from './AVModeration';\nimport BreakoutRooms from './BreakoutRooms';\nimport Lobby from './Lobby';\nimport RoomMetadata from './RoomMetadata';\nimport XmppConnection from './XmppConnection';\nimport Moderator from './moderator';\n\nconst logger = getLogger(__filename);\n\nexport const parser = {\n    packet2JSON(xmlElement, nodes) {\n        for (const child of Array.from(xmlElement.children)) {\n            const node = {\n                attributes: {},\n                children: [],\n                tagName: child.tagName\n            };\n\n            for (const attr of Array.from(child.attributes)) {\n                node.attributes[attr.name] = attr.value;\n            }\n            const text = Strophe.getText(child);\n\n            if (text) {\n                // Using Strophe.getText will do work for traversing all direct\n                // child text nodes but returns an escaped value, which is not\n                // desirable at this point.\n                node.value = Strophe.xmlunescape(text);\n            }\n            nodes.push(node);\n            this.packet2JSON(child, node.children);\n        }\n    },\n    json2packet(nodes, packet) {\n        for (let i = 0; i < nodes.length; i++) {\n            const node = nodes[i];\n\n            if (node) {\n                packet.c(node.tagName, node.attributes);\n                if (node.value) {\n                    packet.t(node.value);\n                }\n                if (node.children) {\n                    this.json2packet(node.children, packet);\n                }\n                packet.up();\n            }\n        }\n\n        // packet.up();\n    }\n};\n\n/**\n * Returns array of JS objects from the presence JSON associated with the passed\n / nodeName\n * @param pres the presence JSON\n * @param nodeName the name of the node (videomuted, audiomuted, etc)\n */\nexport function filterNodeFromPresenceJSON(pres, nodeName) {\n    const res = [];\n\n    for (let i = 0; i < pres.length; i++) {\n        if (pres[i].tagName === nodeName) {\n            res.push(pres[i]);\n        }\n    }\n\n    return res;\n}\n\n// XXX As ChatRoom constructs XMPP stanzas and Strophe is build around the idea\n// of chaining function calls, allow long function call chains.\n/* eslint-disable newline-per-chained-call */\n\n/**\n * Array of affiliations that are allowed in members only room.\n * @type {string[]}\n */\nconst MEMBERS_AFFILIATIONS = [ 'owner', 'admin', 'member' ];\n\n/**\n * Process nodes to extract data needed for MUC_JOINED and MUC_MEMBER_JOINED events.\n *\n */\nfunction extractIdentityInformation(node, hiddenFromRecorderFeatureEnabled) {\n    const identity = {};\n    const userInfo = node.children.find(c => c.tagName === 'user');\n\n    if (userInfo) {\n        identity.user = {};\n        const tags = [ 'id', 'name', 'avatar' ];\n\n        if (hiddenFromRecorderFeatureEnabled) {\n            tags.push('hidden-from-recorder');\n        }\n\n        for (const tag of tags) {\n            const child\n                = userInfo.children.find(c => c.tagName === tag);\n\n            if (child) {\n                identity.user[tag] = child.value;\n            }\n        }\n    }\n    const groupInfo = node.children.find(c => c.tagName === 'group');\n\n    if (groupInfo) {\n        identity.group = groupInfo.value;\n    }\n\n    return identity;\n}\n\n/**\n *\n */\nexport default class ChatRoom extends Listenable {\n\n    /* eslint-disable max-params */\n\n    /**\n     *\n     * @param {XmppConnection} connection - The XMPP connection instance.\n     * @param jid\n     * @param password\n     * @param XMPP\n     * @param options\n     * @param {boolean} options.disableFocus - when set to {@code false} will\n     * not invite Jicofo into the room.\n     * @param {boolean} options.disableDiscoInfo - when set to {@code false} will skip disco info.\n     * This is intended to be used only for lobby rooms.\n     * @param {boolean} options.enableLobby - when set to {@code false} will skip creating lobby room.\n     * @param {boolean} options.hiddenFromRecorderFeatureEnabled - when set to {@code true} we will check identity tag\n     * for node presence.\n     */\n    constructor(connection, jid, password, xmpp, options) {\n        super();\n        this.xmpp = xmpp;\n        this.connection = connection;\n        this.roomjid = Strophe.getBareJidFromJid(jid);\n        this.myroomjid = jid;\n        this.password = password;\n        this.replaceParticipant = false;\n        logger.info(`Joining MUC as ${this.myroomjid}`);\n        this.members = {};\n        this.presMap = {};\n        this.presHandlers = {};\n        this._removeConnListeners = [];\n        this.joined = false;\n        this.inProgressEmitted = false;\n        this.role = null;\n        this.focusMucJid = null;\n        this.noBridgeAvailable = false;\n        this.options = options || {};\n        this.moderator = new Moderator(this.roomjid, this.xmpp, this.eventEmitter, xmpp.options);\n        if (typeof this.options.enableLobby === 'undefined' || this.options.enableLobby) {\n            this.lobby = new Lobby(this);\n        }\n        this.avModeration = new AVModeration(this);\n        this.breakoutRooms = new BreakoutRooms(this);\n        this.roomMetadata = new RoomMetadata(this);\n        this.initPresenceMap(options);\n        this.lastPresences = {};\n        this.phoneNumber = null;\n        this.phonePin = null;\n        this.connectionTimes = {};\n        this.participantPropertyListener = null;\n\n        this.locked = false;\n        this.transcriptionStatus = JitsiTranscriptionStatus.OFF;\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     *\n     */\n    initPresenceMap(options = {}) {\n        this.presMap.to = this.myroomjid;\n        this.presMap.xns = 'http://jabber.org/protocol/muc';\n        this.presMap.nodes = [];\n\n        if (options.statsId) {\n            this.presMap.nodes.push({\n                'tagName': 'stats-id',\n                'value': options.statsId\n            });\n        }\n\n        this.presenceUpdateTime = Date.now();\n    }\n\n    /**\n     * Joins the chat room.\n     * @param {string} password - Password to unlock room on joining.\n     * @returns {Promise} - resolved when join completes. At the time of this\n     * writing it's never rejected.\n     */\n    join(password, replaceParticipant) {\n        this.password = password;\n        this.replaceParticipant = replaceParticipant;\n\n        return new Promise(resolve => {\n            this.options.disableFocus\n                && logger.info(`Conference focus disabled for ${this.roomjid}`);\n\n            // there is no point of sending conference iq when in visitor mode\n            const preJoin\n                = this.options.disableFocus\n                    ? Promise.resolve()\n                    : this.moderator.sendConferenceRequest();\n\n            preJoin.then(() => {\n                this.sendPresence(true);\n                this._removeConnListeners.push(\n                    this.connection.addEventListener(\n                        XmppConnection.Events.CONN_STATUS_CHANGED,\n                        this.onConnStatusChanged.bind(this))\n                );\n                resolve();\n            });\n        });\n    }\n\n    /**\n     *\n     * @param fromJoin - Whether this is initial presence to join the room.\n     */\n    sendPresence(fromJoin) {\n        const to = this.presMap.to;\n\n        if (!this.connection || !this.connection.connected || !to || (!this.joined && !fromJoin)) {\n            // Too early to send presence - not initialized\n            return;\n        }\n\n        const pres = $pres({ to });\n\n        // xep-0045 defines: \"including in the initial presence stanza an empty\n        // <x/> element qualified by the 'http://jabber.org/protocol/muc'\n        // namespace\" and subsequent presences should not include that or it can\n        // be considered as joining, and server can send us the message history\n        // for the room on every presence\n        if (fromJoin) {\n            if (this.replaceParticipant) {\n                pres.c('flip_device').up();\n            }\n\n            pres.c('x', { xmlns: this.presMap.xns });\n\n            if (this.password) {\n                pres.c('password').t(this.password).up();\n            }\n            if (this.options.billingId) {\n                pres.c('billingid').t(this.options.billingId).up();\n            }\n\n            pres.up();\n        }\n\n        parser.json2packet(this.presMap.nodes, pres);\n\n        // we store time we last synced presence state\n        this.presenceSyncTime = Date.now();\n\n        this.connection.send(pres);\n        if (fromJoin) {\n            // XXX We're pressed for time here because we're beginning a complex\n            // and/or lengthy conference-establishment process which supposedly\n            // involves multiple RTTs. We don't have the time to wait for\n            // Strophe to decide to send our IQ.\n            this.connection.flush();\n        }\n    }\n\n    /**\n     * Sends the presence unavailable, signaling the server\n     * we want to leave the room.\n     */\n    doLeave(reason) {\n        logger.log('do leave', this.myroomjid);\n        const pres = $pres({\n            to: this.myroomjid,\n            type: 'unavailable'\n        });\n\n        if (reason) {\n            pres.c('status').t(reason).up();\n        }\n\n        this.presMap.length = 0;\n\n        // XXX Strophe is asynchronously sending by default. Unfortunately, that\n        // means that there may not be enough time to send the unavailable\n        // presence. Switching Strophe to synchronous sending is not much of an\n        // option because it may lead to a noticeable delay in navigating away\n        // from the current location. As a compromise, we will try to increase\n        // the chances of sending the unavailable presence within the short time\n        // span that we have upon unloading by invoking flush() on the\n        // connection. We flush() once before sending/queuing the unavailable\n        // presence in order to attemtp to have the unavailable presence at the\n        // top of the send queue. We flush() once more after sending/queuing the\n        // unavailable presence in order to attempt to have it sent as soon as\n        // possible.\n        // FIXME do not use Strophe.Connection in the ChatRoom directly\n        !this.connection.isUsingWebSocket && this.connection.flush();\n        this.connection.send(pres);\n        this.connection.flush();\n    }\n\n    /**\n     *\n     */\n    discoRoomInfo() {\n        // https://xmpp.org/extensions/xep-0045.html#disco-roominfo\n\n        const getInfo\n            = $iq({\n                type: 'get',\n                to: this.roomjid\n            })\n                .c('query', { xmlns: Strophe.NS.DISCO_INFO });\n\n        this.connection.sendIQ(getInfo, result => {\n            const locked\n                = $(result).find('>query>feature[var=\"muc_passwordprotected\"]')\n                    .length\n                    === 1;\n\n            if (locked !== this.locked) {\n                this.eventEmitter.emit(XMPPEvents.MUC_LOCK_CHANGED, locked);\n                this.locked = locked;\n            }\n\n            const meetingIdValEl\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_meetingId\"]>value');\n\n            if (meetingIdValEl.length) {\n                this.setMeetingId(meetingIdValEl.text());\n            } else {\n                logger.warn('No meeting ID from backend');\n            }\n\n            const membersOnly = $(result).find('>query>feature[var=\"muc_membersonly\"]').length === 1;\n\n            const lobbyRoomField\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_lobbyroom\"]>value');\n\n            if (this.lobby) {\n                this.lobby.setLobbyRoomJid(lobbyRoomField && lobbyRoomField.length ? lobbyRoomField.text() : undefined);\n            }\n\n            const isBreakoutField\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_isbreakout\"]>value');\n            const isBreakoutRoom = Boolean(isBreakoutField?.text());\n\n            this.breakoutRooms._setIsBreakoutRoom(isBreakoutRoom);\n\n            const breakoutMainRoomField\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_breakout_main_room\"]>value');\n\n            if (breakoutMainRoomField?.length) {\n                this.breakoutRooms._setMainRoomJid(breakoutMainRoomField.text());\n            }\n\n            if (membersOnly !== this.membersOnlyEnabled) {\n                this.membersOnlyEnabled = membersOnly;\n                this.eventEmitter.emit(XMPPEvents.MUC_MEMBERS_ONLY_CHANGED, membersOnly);\n            }\n\n            const roomMetadataEl\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_jitsimetadata\"]>value');\n            const roomMetadataText = roomMetadataEl?.text();\n\n            if (roomMetadataText) {\n                try {\n                    this.roomMetadata._handleMessages(JSON.parse(roomMetadataText));\n                } catch (e) {\n                    logger.warn('Failed to set room metadata', e);\n                }\n            }\n        }, error => {\n            GlobalOnErrorHandler.callErrorHandler(error);\n            logger.error('Error getting room info: ', error);\n        });\n    }\n\n    /**\n     * Sets the meeting unique Id (received from the backend).\n     *\n     * @param {string} meetingId - The new meetings id.\n     * @returns {void}\n     */\n    setMeetingId(meetingId) {\n        if (this.meetingId !== meetingId) {\n            if (this.meetingId) {\n                logger.warn(`Meeting Id changed from:${this.meetingId} to:${meetingId}`);\n            }\n            this.meetingId = meetingId;\n            this.eventEmitter.emit(XMPPEvents.MEETING_ID_SET, meetingId);\n        }\n    }\n\n    /**\n     *\n     */\n    createNonAnonymousRoom() {\n        // http://xmpp.org/extensions/xep-0045.html#createroom-reserved\n\n        if (this.options.disableDiscoInfo) {\n            return;\n        }\n\n        const getForm = $iq({ type: 'get',\n            to: this.roomjid })\n            .c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' })\n            .c('x', { xmlns: 'jabber:x:data',\n                type: 'submit' });\n\n        this.connection.sendIQ(getForm, form => {\n            if (!$(form).find(\n                    '>query>x[xmlns=\"jabber:x:data\"]'\n                    + '>field[var=\"muc#roomconfig_whois\"]').length) {\n                const errmsg = 'non-anonymous rooms not supported';\n\n                GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\n                logger.error(errmsg);\n\n                return;\n            }\n\n            const formSubmit = $iq({ to: this.roomjid,\n                type: 'set' })\n                .c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' });\n\n            formSubmit.c('x', { xmlns: 'jabber:x:data',\n                type: 'submit' });\n\n            formSubmit.c('field', { 'var': 'FORM_TYPE' })\n                .c('value')\n                .t('http://jabber.org/protocol/muc#roomconfig').up().up();\n\n            formSubmit.c('field', { 'var': 'muc#roomconfig_whois' })\n                .c('value').t('anyone').up().up();\n\n            this.connection.sendIQ(formSubmit);\n\n        }, error => {\n            GlobalOnErrorHandler.callErrorHandler(error);\n            logger.error('Error getting room configuration form: ', error);\n        });\n    }\n\n    /**\n     * Handles Xmpp Connection status updates.\n     *\n     * @param {Strophe.Status} status - The Strophe connection status.\n     */\n    onConnStatusChanged(status) {\n        // Send cached presence when the XMPP connection is re-established, only if needed\n        if (status === XmppConnection.Status.CONNECTED && this.presenceUpdateTime > this.presenceSyncTime) {\n            this.sendPresence();\n        }\n    }\n\n    /**\n     *\n     * @param pres\n     */\n    onPresence(pres) {\n        const from = pres.getAttribute('from');\n        const member = {};\n        const statusEl = pres.getElementsByTagName('status')[0];\n\n        if (statusEl) {\n            member.status = statusEl.textContent || '';\n        }\n        let hasStatusUpdate = false;\n        let hasVersionUpdate = false;\n        const xElement\n            = pres.getElementsByTagNameNS(\n                'http://jabber.org/protocol/muc#user', 'x')[0];\n        const mucUserItem\n            = xElement && xElement.getElementsByTagName('item')[0];\n\n        member.isReplaceParticipant\n            = pres.getElementsByTagName('flip_device').length;\n\n        member.affiliation\n            = mucUserItem && mucUserItem.getAttribute('affiliation');\n        member.role = mucUserItem && mucUserItem.getAttribute('role');\n\n        // Focus recognition\n        const jid = mucUserItem && mucUserItem.getAttribute('jid');\n\n        member.jid = jid;\n        member.isFocus = this.moderator.isFocusJid(jid);\n        member.isHiddenDomain\n            = jid && jid.indexOf('@') > 0\n                && this.options.hiddenDomain\n                    === jid.substring(jid.indexOf('@') + 1, jid.indexOf('/'));\n\n        this.eventEmitter.emit(XMPPEvents.PRESENCE_RECEIVED, {\n            fromHiddenDomain: member.isHiddenDomain,\n            presence: pres\n        });\n\n        const xEl = pres.querySelector('x');\n\n        if (xEl) {\n            xEl.remove();\n        }\n\n        const nodes = [];\n\n        parser.packet2JSON(pres, nodes);\n        this.lastPresences[from] = nodes;\n\n        for (let i = 0; i < nodes.length; i++) {\n            const node = nodes[i];\n\n            switch (node.tagName) {\n            case 'bot': {\n                const { attributes } = node;\n\n                if (!attributes) {\n                    break;\n                }\n                const { type } = attributes;\n\n                member.botType = type;\n                break;\n            }\n            case 'nick':\n                member.nick = node.value;\n                break;\n            case 'userId':\n                member.id = node.value;\n                break;\n            case 'stats-id':\n                member.statsID = node.value;\n                break;\n            case 'identity':\n                member.identity = extractIdentityInformation(node, this.options.hiddenFromRecorderFeatureEnabled);\n                break;\n            case 'features': {\n                member.features = this._extractFeatures(node);\n                break;\n            }\n            case 'stat': {\n                const { attributes } = node;\n\n                if (!attributes) {\n                    break;\n                }\n                const { name } = attributes;\n\n                if (name === 'version') {\n                    member.version = attributes.value;\n                }\n                break;\n            }\n            }\n        }\n\n        if (!this.joined && !this.inProgressEmitted) {\n            const now = this.connectionTimes['muc.join.started'] = window.performance.now();\n\n            logger.log('(TIME) MUC join started:\\t', now);\n\n            this.eventEmitter.emit(XMPPEvents.MUC_JOIN_IN_PROGRESS);\n            this.inProgressEmitted = true;\n        }\n\n        if (from === this.myroomjid) {\n            const newRole\n                = member.affiliation === 'owner' ? member.role : 'none';\n\n            if (this.role !== newRole) {\n                this.role = newRole;\n                this.eventEmitter.emit(\n                    XMPPEvents.LOCAL_ROLE_CHANGED,\n                    this.role);\n            }\n            if (!this.joined) {\n                this.joined = true;\n                const now = this.connectionTimes['muc.joined']\n                    = window.performance.now();\n\n                logger.log('(TIME) MUC joined:\\t', now);\n\n                // set correct initial state of locked\n                if (this.password) {\n                    this.locked = true;\n                }\n\n                // Re-send presence in case any presence updates were added,\n                // but blocked from sending, during the join process.\n                // send the presence only if there was a modification after we had synced it\n                if (this.presenceUpdateTime >= this.presenceSyncTime) {\n                    this.sendPresence();\n                }\n\n                this.eventEmitter.emit(XMPPEvents.MUC_JOINED);\n\n                // Now let's check the disco-info to retrieve the\n                // meeting Id if any\n                !this.options.disableDiscoInfo && this.discoRoomInfo();\n            }\n        } else if (jid === undefined) {\n            logger.info('Ignoring member with undefined JID');\n        } else if (this.members[from] === undefined) {\n            // new participant\n            this.members[from] = member;\n            logger.log('entered', from, member);\n            hasStatusUpdate = member.status !== undefined;\n            hasVersionUpdate = member.version !== undefined;\n            if (member.isFocus) {\n                this._initFocus(from, member.features);\n            } else {\n                // identity is being added to member joined, so external\n                // services can be notified for that (currently identity is\n                // not used inside library)\n                this.eventEmitter.emit(\n                    XMPPEvents.MUC_MEMBER_JOINED,\n                    from,\n                    member.nick,\n                    member.role,\n                    member.isHiddenDomain,\n                    member.statsID,\n                    member.status,\n                    member.identity,\n                    member.botType,\n                    member.jid,\n                    member.features,\n                    member.isReplaceParticipant);\n\n                // we are reporting the status with the join\n                // so we do not want a second event about status update\n                hasStatusUpdate = false;\n            }\n        } else {\n            // Presence update for existing participant\n            // Watch role change:\n            const memberOfThis = this.members[from];\n\n            if (memberOfThis.role !== member.role) {\n                memberOfThis.role = member.role;\n                this.eventEmitter.emit(\n                    XMPPEvents.MUC_ROLE_CHANGED, from, member.role);\n            }\n\n            // affiliation changed\n            if (memberOfThis.affiliation !== member.affiliation) {\n                memberOfThis.affiliation = member.affiliation;\n            }\n\n            // fire event that botType had changed\n            if (memberOfThis.botType !== member.botType) {\n                memberOfThis.botType = member.botType;\n                this.eventEmitter.emit(\n                    XMPPEvents.MUC_MEMBER_BOT_TYPE_CHANGED,\n                    from,\n                    member.botType);\n            }\n\n            if (member.isFocus) {\n                // From time to time first few presences of the focus are not\n                // containing it's jid. That way we can mark later the focus\n                // member instead of not marking it at all and not starting the\n                // conference.\n                // FIXME: Maybe there is a better way to handle this issue. It\n                // seems there is some period of time in prosody that the\n                // configuration form is received but not applied. And if any\n                // participant joins during that period of time the first\n                // presence from the focus won't contain\n                // <item jid=\"focus...\" />.\n                // By default we are disabling the waiting for form submission in order to use the room\n                // and we had enabled by default that jids are public in the room ,\n                // so this case should not happen, if public jid is turned off we will receive the jid\n                // when we become moderator in the room\n                memberOfThis.isFocus = true;\n                this._initFocus(from, member.features);\n            }\n\n            // store the new display name\n            if (member.displayName) {\n                memberOfThis.displayName = member.displayName;\n            }\n\n            // update stored status message to be able to detect changes\n            if (memberOfThis.status !== member.status) {\n                hasStatusUpdate = true;\n                memberOfThis.status = member.status;\n            }\n\n            if (memberOfThis.version !== member.version) {\n                hasVersionUpdate = true;\n                memberOfThis.version = member.version;\n            }\n\n            if (!isEqual(memberOfThis.features, member.features)) {\n                memberOfThis.features = member.features;\n                this.eventEmitter.emit(XMPPEvents.PARTICIPANT_FEATURES_CHANGED, from, member.features);\n            }\n        }\n\n        // after we had fired member or room joined events, lets fire events\n        // for the rest info we got in presence\n        for (let i = 0; i < nodes.length; i++) {\n            const node = nodes[i];\n\n            switch (node.tagName) {\n            case 'nick':\n                if (!member.isFocus) {\n                    const displayName\n                        = this.xmpp.options.displayJids\n                            ? Strophe.getResourceFromJid(from)\n                            : member.nick;\n\n                    this.eventEmitter.emit(\n                        XMPPEvents.DISPLAY_NAME_CHANGED,\n                        from,\n                        displayName);\n                }\n                break;\n            case 'bridgeNotAvailable':\n                if (member.isFocus && !this.noBridgeAvailable) {\n                    this.noBridgeAvailable = true;\n                    this.eventEmitter.emit(XMPPEvents.BRIDGE_DOWN);\n                }\n                break;\n            case 'conference-properties':\n                if (member.isFocus) {\n                    const properties = {};\n\n                    for (let j = 0; j < node.children.length; j++) {\n                        const { attributes } = node.children[j];\n\n                        if (attributes && attributes.key) {\n                            properties[attributes.key] = attributes.value;\n                        }\n                    }\n\n                    this.eventEmitter.emit(XMPPEvents.CONFERENCE_PROPERTIES_CHANGED, properties);\n\n                    // Log if Jicofo supports restart by terminate only once. This conference property does not change\n                    // during the call.\n                    if (typeof this.restartByTerminateSupported === 'undefined') {\n                        this.restartByTerminateSupported = properties['support-terminate-restart'] === 'true';\n                        logger.info(`Jicofo supports restart by terminate: ${this.supportsRestartByTerminate()}`);\n                    }\n                }\n                break;\n            case 'transcription-status': {\n                const { attributes } = node;\n\n                if (!attributes) {\n                    break;\n                }\n\n                const { status } = attributes;\n\n                if (status && status !== this.transcriptionStatus) {\n                    this.transcriptionStatus = status;\n                    this.eventEmitter.emit(\n                        XMPPEvents.TRANSCRIPTION_STATUS_CHANGED,\n                        status\n                    );\n                }\n\n\n                break;\n            }\n            case 'call-control': {\n                const att = node.attributes;\n\n                if (!att) {\n                    break;\n                }\n                this.phoneNumber = att.phone || null;\n                this.phonePin = att.pin || null;\n                this.eventEmitter.emit(XMPPEvents.PHONE_NUMBER_CHANGED);\n                break;\n            }\n            default:\n                this.processNode(node, from);\n            }\n        }\n\n        // Trigger status message update if necessary\n        if (hasStatusUpdate) {\n            this.eventEmitter.emit(\n                XMPPEvents.PRESENCE_STATUS,\n                from,\n                member.status);\n        }\n\n        if (hasVersionUpdate) {\n            logger.info(`Received version for ${jid}: ${member.version}`);\n        }\n    }\n\n    /**\n     * Extracts the features from the presence.\n     * @param node the node to process.\n     * @return features the Set of features where extracted data is added.\n     * @private\n     */\n    _extractFeatures(node) {\n        const features = new Set();\n\n        for (let j = 0; j < node.children.length; j++) {\n            const { attributes } = node.children[j];\n\n            if (attributes && attributes.var) {\n                features.add(attributes.var);\n            }\n        }\n\n        return features;\n    }\n\n    /**\n     * Initialize some properties when the focus participant is verified.\n     * @param from jid of the focus\n     * @param features the features reported in jicofo presence\n     */\n    _initFocus(from, features) {\n        this.focusMucJid = from;\n        this.focusFeatures = features;\n    }\n\n    /**\n     * Sets the special listener to be used for \"command\"s whose name starts\n     * with \"jitsi_participant_\".\n     */\n    setParticipantPropertyListener(listener) {\n        this.participantPropertyListener = listener;\n    }\n\n    /**\n     * Checks if Jicofo supports restarting Jingle session after 'session-terminate'.\n     * @returns {boolean}\n     */\n    supportsRestartByTerminate() {\n        return this.restartByTerminateSupported;\n    }\n\n    /**\n     *\n     * @param node\n     * @param from\n     */\n    processNode(node, from) {\n        // make sure we catch all errors coming from any handler\n        // otherwise we can remove the presence handler from strophe\n        try {\n            let tagHandlers = this.presHandlers[node.tagName];\n\n            if (node.tagName.startsWith('jitsi_participant_')) {\n                tagHandlers = [ this.participantPropertyListener ];\n            }\n\n            if (tagHandlers) {\n                tagHandlers.forEach(handler => {\n                    handler(node, Strophe.getResourceFromJid(from), from);\n                });\n            }\n        } catch (e) {\n            GlobalOnErrorHandler.callErrorHandler(e);\n            logger.error(`Error processing:${node.tagName} node.`, e);\n        }\n    }\n\n    /**\n     * Send text message to the other participants in the conference\n     * @param message\n     * @param elementName\n     */\n    sendMessage(message, elementName) {\n        const msg = $msg({ to: this.roomjid,\n            type: 'groupchat' });\n\n        // We are adding the message in a packet extension. If this element\n        // is different from 'body', we add a custom namespace.\n        // e.g. for 'json-message' extension of message stanza.\n        if (elementName === 'body') {\n            msg.c(elementName, {}, message);\n        } else {\n            msg.c(elementName, { xmlns: 'http://jitsi.org/jitmeet' }, message);\n        }\n\n        this.connection.send(msg);\n        this.eventEmitter.emit(XMPPEvents.SENDING_CHAT_MESSAGE, message);\n    }\n\n    /* eslint-disable max-params */\n    /**\n     * Send private text message to another participant of the conference\n     * @param id id/muc resource of the receiver\n     * @param message\n     * @param elementName\n     */\n    sendPrivateMessage(id, message, elementName) {\n        const msg = $msg({ to: `${this.roomjid}/${id}`,\n            type: 'chat' });\n\n        // We are adding the message in packet. If this element is different\n        // from 'body', we add our custom namespace for the same.\n        // e.g. for 'json-message' message extension.\n        if (elementName === 'body') {\n            msg.c(elementName, message).up();\n        } else {\n            msg.c(elementName, { xmlns: 'http://jitsi.org/jitmeet' }, message)\n                .up();\n        }\n\n        this.connection.send(msg);\n        this.eventEmitter.emit(\n            XMPPEvents.SENDING_PRIVATE_CHAT_MESSAGE, message);\n    }\n    /* eslint-enable max-params */\n\n    /**\n     *\n     * @param subject\n     */\n    setSubject(subject) {\n        const msg = $msg({ to: this.roomjid,\n            type: 'groupchat' });\n\n        msg.c('subject', subject);\n        this.connection.send(msg);\n    }\n\n    /**\n     *\n     * @param pres\n     * @param from\n     */\n    onPresenceUnavailable(pres, from) {\n        // ignore presence\n        if ($(pres).find('>ignore[xmlns=\"http://jitsi.org/jitmeet/\"]').length) {\n            return true;\n        }\n\n        // room destroyed ?\n        const destroySelect = $(pres).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>destroy');\n\n        if (destroySelect.length) {\n            let reason;\n            const reasonSelect\n                = $(pres).find(\n                    '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\n                        + '>destroy>reason');\n\n            if (reasonSelect.length) {\n                reason = reasonSelect.text();\n            }\n\n            this.eventEmitter.emit(XMPPEvents.MUC_DESTROYED, reason, destroySelect.attr('jid'));\n            this.connection.emuc.doLeave(this.roomjid);\n\n            return true;\n        }\n\n        // Status code 110 indicates that this notification is \"self-presence\".\n        const isSelfPresence\n            = $(pres)\n                .find(\n                    '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>'\n                        + 'status[code=\"110\"]')\n                .length;\n        const isKick\n            = $(pres)\n                .find(\n                    '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\n                        + '>status[code=\"307\"]')\n                .length;\n        const membersKeys = Object.keys(this.members);\n        const isReplaceParticipant = $(pres).find('flip_device').length;\n\n        if (isKick) {\n            const actorSelect\n                = $(pres)\n                .find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>item>actor');\n            let actorNick;\n\n            if (actorSelect.length) {\n                actorNick = actorSelect.attr('nick');\n            }\n\n            let reason;\n            const reasonSelect\n                = $(pres).find(\n                '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\n                + '>item>reason');\n\n            if (reasonSelect.length) {\n                reason = reasonSelect.text();\n            }\n\n            // we first fire the kicked so we can show the participant\n            // who kicked, before notifying that participant left\n            // we fire kicked for us and for any participant kicked\n            this.eventEmitter.emit(\n                XMPPEvents.KICKED,\n                isSelfPresence,\n                actorNick,\n                Strophe.getResourceFromJid(from),\n                reason,\n                isReplaceParticipant);\n        }\n\n        if (isSelfPresence) {\n            // If the status code is 110 this means we're leaving and we would\n            // like to remove everyone else from our view, so we trigger the\n            // event.\n            membersKeys.forEach(jid => {\n                const member = this.members[jid];\n\n                delete this.members[jid];\n                delete this.lastPresences[jid];\n                if (!member.isFocus) {\n                    this.eventEmitter.emit(XMPPEvents.MUC_MEMBER_LEFT, jid);\n                }\n            });\n            this.connection.emuc.doLeave(this.roomjid);\n\n            // we fire muc_left only if this is not a kick,\n            // kick has both statuses 110 and 307.\n            if (!isKick) {\n                this.eventEmitter.emit(XMPPEvents.MUC_LEFT);\n            }\n        } else {\n            const reasonSelect = $(pres).find('>status');\n            const member = this.members[from];\n            let reason;\n\n            if (reasonSelect.length) {\n                reason = reasonSelect.text();\n            }\n\n            delete this.members[from];\n            delete this.lastPresences[from];\n\n            // In this case we *do* fire MUC_MEMBER_LEFT for the focus?\n            this.eventEmitter.emit(XMPPEvents.MUC_MEMBER_LEFT, from, reason);\n            if (member?.isFocus) {\n                logger.info('Focus has left the room - leaving conference');\n                this.eventEmitter.emit(XMPPEvents.FOCUS_LEFT);\n            }\n        }\n    }\n\n    /**\n     *\n     * @param msg\n     * @param from\n     */\n    onMessage(msg, from) {\n        const type = msg.getAttribute('type');\n\n        if (type === 'error') {\n            const settingsErrorMsg = $(msg).find('>settings-error>text').text();\n\n            if (settingsErrorMsg.length) {\n                this.eventEmitter.emit(XMPPEvents.SETTINGS_ERROR_RECEIVED, settingsErrorMsg);\n\n                return true;\n            }\n            const errorMsg = $(msg).find('>error>text').text();\n\n            this.eventEmitter.emit(XMPPEvents.CHAT_ERROR_RECEIVED, errorMsg);\n\n            return true;\n        }\n\n        const txt = $(msg).find('>body').text();\n        const subject = $(msg).find('>subject');\n\n        if (subject.length) {\n            const subjectText = subject.text();\n\n            if (subjectText || subjectText === '') {\n                this.eventEmitter.emit(XMPPEvents.SUBJECT_CHANGED, subjectText);\n                logger.log(`Subject is changed to ${subjectText}`);\n            }\n        }\n\n        // xep-0203 delay\n        let stamp = $(msg).find('>delay').attr('stamp');\n\n        if (!stamp) {\n            // or xep-0091 delay, UTC timestamp\n            stamp = $(msg).find('>[xmlns=\"jabber:x:delay\"]').attr('stamp');\n\n            if (stamp) {\n                // the format is CCYYMMDDThh:mm:ss\n                const dateParts\n                    = stamp.match(/(\\d{4})(\\d{2})(\\d{2}T\\d{2}:\\d{2}:\\d{2})/);\n\n                stamp = `${dateParts[1]}-${dateParts[2]}-${dateParts[3]}Z`;\n            }\n        }\n\n        if (from === this.roomjid) {\n            let invite;\n\n            if ($(msg).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>status[code=\"104\"]').length) {\n                this.discoRoomInfo();\n            } else if ((invite = $(msg).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>invite'))\n                        && invite.length) {\n                const passwordSelect = $(msg).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>password');\n                let password;\n\n                if (passwordSelect && passwordSelect.length) {\n                    password = passwordSelect.text();\n                }\n\n                this.eventEmitter.emit(XMPPEvents.INVITE_MESSAGE_RECEIVED,\n                    from, invite.attr('from'), txt, password);\n            }\n        }\n\n        const jsonMessage = $(msg).find('>json-message').text();\n\n        if (jsonMessage) {\n            const parsedJson = this.xmpp.tryParseJSONAndVerify(jsonMessage);\n\n            // We emit this event if the message is a valid json, and is not\n            // delivered after a delay, i.e. stamp is undefined.\n            // e.g. - subtitles should not be displayed if delayed.\n            if (parsedJson && stamp === undefined) {\n                this.eventEmitter.emit(XMPPEvents.JSON_MESSAGE_RECEIVED,\n                    from, parsedJson);\n\n                return;\n            }\n        }\n\n        if (txt) {\n            if (type === 'chat') {\n                this.eventEmitter.emit(XMPPEvents.PRIVATE_MESSAGE_RECEIVED,\n                        from, txt, this.myroomjid, stamp);\n            } else if (type === 'groupchat') {\n                const nickEl = $(msg).find('>nick');\n                let nick;\n\n                if (nickEl.length > 0) {\n                    nick = nickEl.text();\n                }\n\n                // we will fire explicitly that this is a guest(isGuest:true) to the conference\n                // informing that this is probably a message from a guest to the conference (visitor)\n                // a message with explicit name set\n                this.eventEmitter.emit(XMPPEvents.MESSAGE_RECEIVED,\n                    from, txt, this.myroomjid, stamp, nick, Boolean(nick));\n            }\n        }\n    }\n\n    /**\n     *\n     * @param pres\n     * @param from\n     */\n    onPresenceError(pres, from) {\n        if ($(pres)\n                .find(\n                    '>error[type=\"auth\"]'\n                        + '>not-authorized['\n                        + 'xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"]')\n                .length) {\n            logger.log('on password required', from);\n            this.eventEmitter.emit(XMPPEvents.PASSWORD_REQUIRED);\n        } else if ($(pres)\n                .find(\n                    '>error[type=\"cancel\"]'\n                        + '>not-allowed['\n                        + 'xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"]')\n                .length) {\n            const toDomain = Strophe.getDomainFromJid(pres.getAttribute('to'));\n\n            if (toDomain === this.xmpp.options.hosts.anonymousdomain) {\n                // enter the room by replying with 'not-authorized'. This would\n                // result in reconnection from authorized domain.\n                // We're either missing Jicofo/Prosody config for anonymous\n                // domains or something is wrong.\n                this.eventEmitter.emit(XMPPEvents.ROOM_JOIN_ERROR);\n\n            } else {\n                logger.warn('onPresError ', pres);\n                this.eventEmitter.emit(\n                    XMPPEvents.ROOM_CONNECT_NOT_ALLOWED_ERROR);\n            }\n        } else if ($(pres).find('>error>service-unavailable').length) {\n            logger.warn('Maximum users limit for the room has been reached',\n                pres);\n            this.eventEmitter.emit(XMPPEvents.ROOM_MAX_USERS_ERROR);\n        } else if ($(pres)\n            .find(\n                '>error[type=\"auth\"]'\n                + '>registration-required['\n                + 'xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"]').length) {\n\n            // let's extract the lobby jid from the custom field\n            const lobbyRoomNode = $(pres).find('>error[type=\"auth\"]>lobbyroom');\n            let lobbyRoomJid;\n\n            if (lobbyRoomNode.length) {\n                lobbyRoomJid = lobbyRoomNode.text();\n            } else {\n                // let's fallback to old location of lobbyroom node, TODO: to be removed in the future once\n                // everything is updated\n                const lobbyRoomOldNode = $(pres).find('>lobbyroom');\n\n                if (lobbyRoomOldNode.length) {\n                    lobbyRoomJid = lobbyRoomOldNode.text();\n                }\n            }\n\n            this.eventEmitter.emit(XMPPEvents.ROOM_CONNECT_MEMBERS_ONLY_ERROR, lobbyRoomJid);\n        } else {\n            logger.warn('onPresError ', pres);\n            this.eventEmitter.emit(XMPPEvents.ROOM_CONNECT_ERROR);\n        }\n    }\n\n    /**\n     *\n     * @param jid\n     * @param affiliation\n     */\n    setAffiliation(jid, affiliation) {\n        const grantIQ = $iq({\n            to: this.roomjid,\n            type: 'set'\n        })\n        .c('query', { xmlns: 'http://jabber.org/protocol/muc#admin' })\n        .c('item', {\n            affiliation,\n            jid: Strophe.getBareJidFromJid(jid)\n        })\n        .c('reason').t(`Your affiliation has been changed to '${affiliation}'.`)\n        .up().up().up();\n\n        this.connection.sendIQ(\n            grantIQ,\n            result => logger.log('Set affiliation of participant with jid: ', jid, 'to', affiliation, result),\n            error => logger.log('Set affiliation of participant error: ', error));\n    }\n\n    /**\n     *\n     * @param jid\n     * @param reason\n     */\n    kick(jid, reason = 'You have been kicked.') {\n        const kickIQ = $iq({ to: this.roomjid,\n            type: 'set' })\n            .c('query', { xmlns: 'http://jabber.org/protocol/muc#admin' })\n            .c('item', { nick: Strophe.getResourceFromJid(jid),\n                role: 'none' })\n            .c('reason').t(reason).up().up().up();\n\n        this.connection.sendIQ(\n            kickIQ,\n            result => logger.log('Kick participant with jid: ', jid, result),\n            error => logger.log('Kick participant error: ', error));\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     *\n     * @param key\n     * @param onSuccess\n     * @param onError\n     * @param onNotSupported\n     */\n    lockRoom(key, onSuccess, onError, onNotSupported) {\n        // http://xmpp.org/extensions/xep-0045.html#roomconfig\n        this.connection.sendIQ(\n            $iq({\n                to: this.roomjid,\n                type: 'get'\n            })\n                .c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' }),\n            res => {\n                if ($(res)\n                        .find(\n                            '>query>x[xmlns=\"jabber:x:data\"]'\n                                + '>field[var=\"muc#roomconfig_roomsecret\"]')\n                        .length) {\n                    const formsubmit\n                        = $iq({\n                            to: this.roomjid,\n                            type: 'set'\n                        })\n                            .c('query', {\n                                xmlns: 'http://jabber.org/protocol/muc#owner'\n                            });\n\n                    formsubmit.c('x', {\n                        xmlns: 'jabber:x:data',\n                        type: 'submit'\n                    });\n                    formsubmit\n                        .c('field', { 'var': 'FORM_TYPE' })\n                        .c('value')\n                        .t('http://jabber.org/protocol/muc#roomconfig')\n                        .up()\n                        .up();\n                    formsubmit\n                        .c('field', { 'var': 'muc#roomconfig_roomsecret' })\n                        .c('value')\n                        .t(key)\n                        .up()\n                        .up();\n                    formsubmit\n                        .c('field',\n                             { 'var': 'muc#roomconfig_passwordprotectedroom' })\n                        .c('value')\n                        .t(key === null || key.length === 0 ? '0' : '1')\n                        .up()\n                        .up();\n\n                    // if members only enabled\n                    if (this.membersOnlyEnabled) {\n                        formsubmit\n                            .c('field', { 'var': 'muc#roomconfig_membersonly' })\n                            .c('value')\n                            .t('true')\n                            .up()\n                            .up();\n                    }\n\n                    // Fixes a bug in prosody 0.9.+\n                    // https://prosody.im/issues/issue/373\n                    formsubmit\n                        .c('field', { 'var': 'muc#roomconfig_whois' })\n                        .c('value')\n                        .t('anyone')\n                        .up()\n                        .up();\n\n                    this.connection.sendIQ(\n                        formsubmit,\n                        () => {\n\n                            // we set the password in chat room so we can use it\n                            // later when dialing out\n                            this.password = key;\n                            onSuccess();\n                        },\n                        onError);\n                } else {\n                    onNotSupported();\n                }\n            },\n            onError);\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Turns off or on the members only config for the main room.\n     *\n     * @param {boolean} enabled - Whether to turn it on or off.\n     * @param onSuccess - optional callback.\n     * @param onError - optional callback.\n     */\n    setMembersOnly(enabled, onSuccess, onError) {\n        if (enabled && Object.values(this.members).filter(m => !m.isFocus).length) {\n            // first grant membership to all that are in the room\n            // currently there is a bug in prosody where it handles only the first item\n            // that's why we will send iq per member\n            Object.values(this.members).forEach(m => {\n                if (m.jid && !MEMBERS_AFFILIATIONS.includes(m.affiliation)) {\n                    this.xmpp.connection.sendIQ(\n                        $iq({\n                            to: this.roomjid,\n                            type: 'set' })\n                        .c('query', {\n                            xmlns: 'http://jabber.org/protocol/muc#admin' })\n                        .c('item', {\n                            'affiliation': 'member',\n                            'jid': Strophe.getBareJidFromJid(m.jid)\n                        }).up().up());\n                }\n            });\n        }\n\n        const errorCallback = onError ? onError : () => {}; // eslint-disable-line no-empty-function\n\n        this.xmpp.connection.sendIQ(\n            $iq({\n                to: this.roomjid,\n                type: 'get'\n            }).c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' }),\n            res => {\n                if ($(res).find('>query>x[xmlns=\"jabber:x:data\"]>field[var=\"muc#roomconfig_membersonly\"]').length) {\n                    const formToSubmit\n                        = $iq({\n                            to: this.roomjid,\n                            type: 'set'\n                        }).c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' });\n\n                    formToSubmit.c('x', {\n                        xmlns: 'jabber:x:data',\n                        type: 'submit'\n                    });\n                    formToSubmit\n                        .c('field', { 'var': 'FORM_TYPE' })\n                        .c('value')\n                        .t('http://jabber.org/protocol/muc#roomconfig')\n                        .up()\n                        .up();\n                    formToSubmit\n                        .c('field', { 'var': 'muc#roomconfig_membersonly' })\n                        .c('value')\n                        .t(enabled ? 'true' : 'false')\n                        .up()\n                        .up();\n\n                    // if room is locked from other participant or we are locking it\n                    if (this.locked) {\n                        formToSubmit\n                            .c('field',\n                                { 'var': 'muc#roomconfig_passwordprotectedroom' })\n                            .c('value')\n                            .t('1')\n                            .up()\n                            .up();\n                    }\n\n                    this.xmpp.connection.sendIQ(formToSubmit, onSuccess, errorCallback);\n                } else {\n                    errorCallback(new Error('Setting members only room not supported!'));\n                }\n            },\n            errorCallback);\n    }\n\n    /**\n     * Adds the key to the presence map, overriding any previous value.\n     * This method is used by jibri.\n     *\n     * @param key The key to add or replace.\n     * @param values The new values.\n     * @returns {boolean|null} <tt>true</tt> if the operation succeeded or <tt>false</tt> when no add or replce was\n     * performed as the value was already there.\n     * @deprecated Use 'addOrReplaceInPresence' instead. TODO: remove it from here and jibri.\n     */\n    addToPresence(key, values) {\n        return this.addOrReplaceInPresence(key, values);\n    }\n\n    /**\n     * Adds the key to the presence map, overriding any previous value.\n     * @param key The key to add or replace.\n     * @param values The new values.\n     * @returns {boolean|null} <tt>true</tt> if the operation succeeded or <tt>false</tt> when no add or replace was\n     * performed as the value was already there.\n     */\n    addOrReplaceInPresence(key, values) {\n        values.tagName = key;\n\n        const matchingNodes = this.presMap.nodes.filter(node => key === node.tagName);\n\n        // if we have found just one, let's check is it the same\n        if (matchingNodes.length === 1 && isEqual(matchingNodes[0], values)) {\n            return false;\n        }\n\n        this.removeFromPresence(key);\n        this.presMap.nodes.push(values);\n        this.presenceUpdateTime = Date.now();\n\n        return true;\n    }\n\n    /**\n     * Retrieves a value from the presence map.\n     *\n     * @param {string} key - The key to find the value for.\n     * @returns {Object?}\n     */\n    getFromPresence(key) {\n        return this.presMap.nodes.find(node => key === node.tagName);\n    }\n\n    /**\n     * Removes a key from the presence map.\n     * @param key\n     */\n    removeFromPresence(key) {\n        const nodes = this.presMap.nodes.filter(node => key !== node.tagName);\n\n        this.presMap.nodes = nodes;\n        this.presenceUpdateTime = Date.now();\n    }\n\n    /**\n     *\n     * @param name\n     * @param handler\n     */\n    addPresenceListener(name, handler) {\n        if (typeof handler !== 'function') {\n            throw new Error('\"handler\" is not a function');\n        }\n        let tagHandlers = this.presHandlers[name];\n\n        if (!tagHandlers) {\n            this.presHandlers[name] = tagHandlers = [];\n        }\n        if (tagHandlers.indexOf(handler) === -1) {\n            tagHandlers.push(handler);\n        } else {\n            logger.warn(\n                `Trying to add the same handler more than once for: ${name}`);\n        }\n    }\n\n    /**\n     *\n     * @param name\n     * @param handler\n     */\n    removePresenceListener(name, handler) {\n        const tagHandlers = this.presHandlers[name];\n        const handlerIdx = tagHandlers ? tagHandlers.indexOf(handler) : -1;\n\n        // eslint-disable-next-line no-negated-condition\n        if (handlerIdx !== -1) {\n            tagHandlers.splice(handlerIdx, 1);\n        } else {\n            logger.warn(`Handler for: ${name} was not registered`);\n        }\n    }\n\n    /**\n     * Checks if the user identified by given <tt>mucJid</tt> is the conference\n     * focus.\n     * @param mucJid the full MUC address of the user to be checked.\n     * @returns {boolean|null} <tt>true</tt> if MUC user is the conference focus\n     * or <tt>false</tt> if is not. When given <tt>mucJid</tt> does not exist in\n     * the MUC then <tt>null</tt> is returned.\n     */\n    isFocus(mucJid) {\n        const member = this.members[mucJid];\n\n        if (member) {\n            return member.isFocus;\n        }\n\n        return null;\n    }\n\n    /**\n     *\n     */\n    isModerator() {\n        return this.role === 'moderator';\n    }\n\n    /**\n     * Redirected back.\n     * @param iq The received iq.\n     */\n    onVisitorIQ(iq) {\n        const visitors = $(iq).find('>visitors[xmlns=\"jitsi:visitors\"]');\n        const response = $(iq).find('promotion-response');\n\n        if (visitors.length && response.length\n            && String(response.attr('allow')).toLowerCase() === 'true') {\n            logger.warn('Redirected back to main room.');\n\n            this.eventEmitter.emit(\n                XMPPEvents.REDIRECTED, undefined, visitors.attr('focusjid'), response.attr('username'));\n        }\n    }\n\n    /**\n     * Obtains the info about given media advertised (in legacy format) in the MUC presence of the participant\n     * identified by the given endpoint JID. This is for mantining interop with endpoints that do not support\n     * source-name signaling (Jigasi and very old mobile clients).\n     *\n     * @param {string} endpointId the endpoint ID mapped to the participant which corresponds to MUC nickname.\n     * @param {MediaType} mediaType the type of the media for which presence info will be obtained.\n     * @return {PeerMediaInfo} presenceInfo an object with media presence info or <tt>null</tt> either if there\n     * is no presence available or if the media type given is invalid.\n     */\n    getMediaPresenceInfo(endpointId, mediaType) {\n        // Will figure out current muted status by looking up owner's presence\n        const pres = this.lastPresences[`${this.roomjid}/${endpointId}`];\n\n        if (!pres) {\n            // No presence available\n            return null;\n        }\n        const data = {\n            muted: true, // muted by default\n            videoType: mediaType === MediaType.VIDEO ? VideoType.CAMERA : undefined // 'camera' by default\n        };\n        let mutedNode = null;\n\n        if (mediaType === MediaType.AUDIO) {\n            mutedNode = filterNodeFromPresenceJSON(pres, 'audiomuted');\n        } else if (mediaType === MediaType.VIDEO) {\n            mutedNode = filterNodeFromPresenceJSON(pres, 'videomuted');\n            const codecTypeNode = filterNodeFromPresenceJSON(pres, 'jitsi_participant_codecType');\n            const videoTypeNode = filterNodeFromPresenceJSON(pres, 'videoType');\n\n            if (videoTypeNode.length > 0) {\n                data.videoType = videoTypeNode[0].value;\n            }\n            if (codecTypeNode.length > 0) {\n                data.codecType = codecTypeNode[0].value;\n            }\n        } else {\n            logger.error(`Unsupported media type: ${mediaType}`);\n\n            return null;\n        }\n\n        if (mutedNode.length > 0) {\n            data.muted = mutedNode[0].value === 'true';\n        }\n\n        return data;\n    }\n\n    /**\n     *\n     * @param peerJid\n     */\n    getMemberRole(peerJid) {\n        if (this.members[peerJid]) {\n            return this.members[peerJid].role;\n        }\n\n        return null;\n    }\n\n    /**\n     * Returns the last presence advertised by a MUC member.\n     * @param {string} mucNick\n     * @returns {*}\n     */\n    getLastPresence(mucNick) {\n        return this.lastPresences[`${this.roomjid}/${mucNick}`];\n    }\n\n    /**\n     * Dials a number.\n     * @param number the number\n     */\n    dial(number) {\n        return this.connection.rayo.dial(number, 'fromnumber',\n            Strophe.getBareJidFromJid(this.myroomjid), this.password,\n            this.focusMucJid);\n    }\n\n    /**\n     * Hangup an existing call\n     */\n    hangup() {\n        return this.connection.rayo.hangup();\n    }\n\n    /**\n     *\n     * @returns {Lobby}\n     */\n    getLobby() {\n        return this.lobby;\n    }\n\n    /**\n     * @returns {AVModeration}\n     */\n    getAVModeration() {\n        return this.avModeration;\n    }\n\n    /**\n     * @returns {BreakoutRooms}\n     */\n    getBreakoutRooms() {\n        return this.breakoutRooms;\n    }\n\n    /**\n     * @returns {RoomMetadata}\n     */\n    getMetadataHandler() {\n        return this.roomMetadata;\n    }\n\n    /**\n     * Returns the phone number for joining the conference.\n     */\n    getPhoneNumber() {\n        return this.phoneNumber;\n    }\n\n    /**\n     * Returns the pin for joining the conference with phone.\n     */\n    getPhonePin() {\n        return this.phonePin;\n    }\n\n    /**\n     * Returns the meeting unique ID if any came from backend.\n     *\n     * @returns {string} - The meeting ID.\n     */\n    getMeetingId() {\n        return this.meetingId;\n    }\n\n    /**\n     * Mutes remote participant.\n     * @param jid of the participant\n     * @param mute\n     * @param mediaType\n     */\n    muteParticipant(jid, mute, mediaType) {\n        logger.info('set mute', mute, jid);\n        const iqToFocus = $iq(\n            { to: this.focusMucJid,\n                type: 'set' })\n            .c('mute', {\n                xmlns: `http://jitsi.org/jitmeet/${mediaType}`,\n                jid\n            })\n            .t(mute.toString())\n            .up();\n\n        this.connection.sendIQ(\n            iqToFocus,\n            result => logger.log('set mute', result),\n            error => logger.log('set mute error', error));\n    }\n\n    /**\n     * TODO: Document\n     * @param iq\n     */\n    onMute(iq) {\n        const from = iq.getAttribute('from');\n\n        if (from !== this.focusMucJid) {\n            logger.warn('Ignored mute from non focus peer');\n\n            return;\n        }\n        const mute = $(iq).find('mute');\n\n        if (mute.length && mute.text() === 'true') {\n            this.eventEmitter.emit(XMPPEvents.AUDIO_MUTED_BY_FOCUS, mute.attr('actor'));\n        } else {\n            // XXX Why do we support anything but muting? Why do we encode the\n            // value in the text of the element? Why do we use a separate XML\n            // namespace?\n            logger.warn('Ignoring a mute request which does not explicitly '\n                + 'specify a positive mute command.');\n        }\n    }\n\n    /**\n     * TODO: Document\n     * @param iq\n     */\n    onMuteVideo(iq) {\n        const from = iq.getAttribute('from');\n\n        if (from !== this.focusMucJid) {\n            logger.warn('Ignored mute from non focus peer');\n\n            return;\n        }\n        const mute = $(iq).find('mute');\n\n        if (mute.length && mute.text() === 'true') {\n            this.eventEmitter.emit(XMPPEvents.VIDEO_MUTED_BY_FOCUS, mute.attr('actor'));\n        } else {\n            // XXX Why do we support anything but muting? Why do we encode the\n            // value in the text of the element? Why do we use a separate XML\n            // namespace?\n            logger.warn('Ignoring a mute request which does not explicitly '\n                + 'specify a positive mute command.');\n        }\n    }\n\n    /**\n     * Clean any listeners or resources, executed on leaving.\n     */\n    clean() {\n        this._removeConnListeners.forEach(remove => remove());\n        this._removeConnListeners = [];\n\n        this.joined = false;\n        this.inProgressEmitted = false;\n    }\n\n    /**\n     * Leaves the room. Closes the jingle session.\n     * @returns {Promise} which is resolved if XMPPEvents.MUC_LEFT is received\n     * less than 5s after sending presence unavailable. Otherwise the promise is\n     * rejected.\n     */\n    leave(reason) {\n        this.avModeration.dispose();\n        this.breakoutRooms.dispose();\n        this.roomMetadata.dispose();\n\n        const promises = [];\n\n        this.lobby?.lobbyRoom && promises.push(this.lobby.leave());\n\n        promises.push(new Promise((resolve, reject) => {\n            let timeout = -1;\n\n            const onMucLeft = (doReject = false) => {\n                this.eventEmitter.removeListener(XMPPEvents.MUC_LEFT, onMucLeft);\n                clearTimeout(timeout);\n                if (doReject) {\n                    // The timeout expired. Make sure we clean the EMUC state.\n                    this.connection.emuc.doLeave(this.roomjid);\n                    reject(new Error('The timeout for the confirmation about leaving the room expired.'));\n                } else {\n                    resolve();\n                }\n            };\n\n            if (this.joined) {\n                timeout = setTimeout(() => onMucLeft(true), 5000);\n\n                this.clean();\n                this.eventEmitter.on(XMPPEvents.MUC_LEFT, onMucLeft);\n                this.doLeave(reason);\n            } else {\n                // we are clearing up, and we haven't joined the room\n                // there is no point of sending presence unavailable and check for timeout\n                // let's just clean\n                this.connection.emuc.doLeave(this.roomjid);\n                this.clean();\n            }\n        }));\n\n        return Promise.allSettled(promises);\n    }\n\n    /**\n     * Ends the conference for all participants.\n     */\n    end() {\n        if (this.breakoutRooms.isBreakoutRoom()) {\n            logger.warn('Cannot end conference: this is a breakout room.');\n\n            return;\n        }\n\n        // Send the end conference message.\n        const msg = $msg({ to: this.xmpp.endConferenceComponentAddress });\n\n        msg.c('end_conference').up();\n\n        this.xmpp.connection.send(msg);\n    }\n}\n\n/* eslint-enable newline-per-chained-call */\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { Strophe } from 'strophe.js';\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nimport ChatRoom from './ChatRoom';\nimport { ConnectionPluginListenable } from './ConnectionPlugin';\n\nconst logger = getLogger(__filename);\n\n/**\n * MUC connection plugin.\n */\nexport default class MucConnectionPlugin extends ConnectionPluginListenable {\n    /**\n     *\n     * @param xmpp\n     */\n    constructor(xmpp) {\n        super();\n        this.xmpp = xmpp;\n        this.rooms = {};\n    }\n\n    /**\n     *\n     * @param connection\n     */\n    init(connection) {\n        super.init(connection);\n\n        // add handlers (just once)\n        this.connection.addHandler(this.onPresence.bind(this), null,\n            'presence', null, null, null, null);\n        this.connection.addHandler(this.onPresenceUnavailable.bind(this),\n            null, 'presence', 'unavailable', null);\n        this.connection.addHandler(this.onPresenceError.bind(this), null,\n            'presence', 'error', null);\n        this.connection.addHandler(this.onMessage.bind(this), null,\n            'message', null, null);\n        this.connection.addHandler(this.onMute.bind(this),\n            'http://jitsi.org/jitmeet/audio', 'iq', 'set', null, null);\n        this.connection.addHandler(this.onMuteVideo.bind(this),\n            'http://jitsi.org/jitmeet/video', 'iq', 'set', null, null);\n        this.connection.addHandler(this.onVisitors.bind(this),\n            'jitsi:visitors', 'iq', 'set', null, null);\n    }\n\n    /**\n     *\n     * @param jid\n     * @param password\n     * @param options\n     */\n    createRoom(jid, password, options) {\n        const roomJid = Strophe.getBareJidFromJid(jid);\n\n        if (this.isRoomCreated(roomJid)) {\n            const errmsg = 'You are already in the room!';\n\n            logger.error(errmsg);\n            throw new Error(errmsg);\n        }\n        this.rooms[roomJid] = new ChatRoom(this.connection, jid,\n            password, this.xmpp, options);\n        this.eventEmitter.emit(\n            XMPPEvents.EMUC_ROOM_ADDED, this.rooms[roomJid]);\n\n        return this.rooms[roomJid];\n    }\n\n    /**\n     *  Check if a room with the passed JID is already created.\n     *\n     * @param {string} roomJid - The JID of the room.\n     * @returns {boolean}\n     */\n    isRoomCreated(roomJid) {\n        return roomJid in this.rooms;\n    }\n\n    /**\n     *\n     * @param jid\n     */\n    doLeave(jid) {\n        this.eventEmitter.emit(\n            XMPPEvents.EMUC_ROOM_REMOVED, this.rooms[jid]);\n        delete this.rooms[jid];\n    }\n\n    /**\n     *\n     * @param pres\n     */\n    onPresence(pres) {\n        const from = pres.getAttribute('from');\n\n        // What is this for? A workaround for something?\n        if (pres.getAttribute('type')) {\n            return true;\n        }\n\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        if (!room) {\n            return true;\n        }\n\n        // Parse status.\n        if ($(pres).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\n            + '>status[code=\"201\"]').length) {\n            room.createNonAnonymousRoom();\n        }\n\n        room.onPresence(pres);\n\n        return true;\n    }\n\n    /**\n     *\n     * @param pres\n     */\n    onPresenceUnavailable(pres) {\n        const from = pres.getAttribute('from');\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        if (!room) {\n            return true;\n        }\n\n        room.onPresenceUnavailable(pres, from);\n\n        return true;\n    }\n\n    /**\n     *\n     * @param pres\n     */\n    onPresenceError(pres) {\n        const from = pres.getAttribute('from');\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        if (!room) {\n            return true;\n        }\n\n        room.onPresenceError(pres, from);\n\n        return true;\n    }\n\n    /**\n     *\n     * @param msg\n     */\n    onMessage(msg) {\n        // FIXME: this is a hack. but jingle on muc makes nickchanges hard\n        const from = msg.getAttribute('from');\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        if (!room) {\n            return true;\n        }\n\n        room.onMessage(msg, from);\n\n        return true;\n    }\n\n    /**\n     * TODO: Document\n     * @param iq\n     */\n    onMute(iq) {\n        const from = iq.getAttribute('from');\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        // Returning false would result in the listener being deregistered by Strophe\n        if (!room) {\n            return true;\n        }\n\n        room.onMute(iq);\n\n        return true;\n    }\n\n    /**\n     * TODO: Document\n     * @param iq\n     */\n    onMuteVideo(iq) {\n        const from = iq.getAttribute('from');\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        // Returning false would result in the listener being deregistered by Strophe\n        if (!room) {\n            return true;\n        }\n\n        room.onMuteVideo(iq);\n\n        return true;\n    }\n\n    /**\n     * A visitor IQ is received, pass it to the room.\n     * @param iq The received iq.\n     * @returns {boolean}\n     */\n    onVisitors(iq) {\n        const from = iq.getAttribute('from');\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        room?.onVisitorIQ(iq);\n\n        return true;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $build } from 'strophe.js';\n\nimport { MediaType } from '../../service/RTC/MediaType';\n\nconst logger = getLogger(__filename);\n\n/**\n * Creates a \"source\" XML element for the source described in compact JSON format in [sourceCompactJson].\n * @param {*} owner the endpoint ID of the owner of the source.\n * @param {*} sourceCompactJson the compact JSON representation of the source.\n * @returns the created \"source\" XML element.\n */\nfunction _createSourceExtension(owner, sourceCompactJson) {\n    const node = $build('source', {\n        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\n        ssrc: sourceCompactJson.s,\n        name: sourceCompactJson.n\n    });\n\n    if (sourceCompactJson.m) {\n        node.c('parameter', {\n            name: 'msid',\n            value: sourceCompactJson.m\n        }).up();\n    }\n    node.c('ssrc-info', {\n        xmlns: 'http://jitsi.org/jitmeet',\n        owner\n    }).up();\n\n    return node.node;\n}\n\n/**\n * Creates an \"ssrc-group\" XML element for the SSRC group described in compact JSON format in [ssrcGroupCompactJson].\n * @param {*} ssrcGroupCompactJson the compact JSON representation of the SSRC group.\n * @returns the created \"ssrc-group\" element.\n */\nfunction _createSsrcGroupExtension(ssrcGroupCompactJson) {\n    const node = $build('ssrc-group', {\n        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\n        semantics: _getSemantics(ssrcGroupCompactJson[0])\n    });\n\n    for (let i = 1; i < ssrcGroupCompactJson.length; i++) {\n        node.c('source', {\n            xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\n            ssrc: ssrcGroupCompactJson[i]\n        }).up();\n    }\n\n    return node.node;\n}\n\n/**\n * Finds in a Jingle IQ the RTP description element with the given media type. If one does not exists, create it (as\n *  well as the required  \"content\" parent element) and adds it to the IQ.\n * @param {*} iq\n * @param {*} mediaType The media type, \"audio\" or \"video\".\n * @returns the RTP description element with the given media type.\n */\nfunction _getOrCreateRtpDescription(iq, mediaType) {\n    const jingle = $(iq).find('jingle')[0];\n    let content = $(jingle).find(`content[name=\"${mediaType}\"]`);\n    let description;\n\n    if (content.length) {\n        content = content[0];\n    } else {\n        // I'm not suree if \"creator\" and \"senders\" are required.\n        content = $build('content', {\n            name: mediaType\n        }).node;\n        jingle.appendChild(content);\n    }\n\n    description = $(content).find('description');\n\n    if (description.length) {\n        description = description[0];\n    } else {\n        description = $build('description', {\n            xmlns: 'urn:xmpp:jingle:apps:rtp:1',\n            media: mediaType\n        }).node;\n        content.appendChild(description);\n    }\n\n    return description;\n}\n\n/**\n * Converts the short string representing SSRC group semantics in compact JSON format to the standard representation\n * (i.e. convert \"f\" to \"FID\" and \"s\" to \"SIM\").\n * @param {*} str the compact JSON format representation of an SSRC group's semantics.\n * @returns the SSRC group semantics corresponding to [str].\n */\nfunction _getSemantics(str) {\n    if (str === 'f') {\n        return 'FID';\n    } else if (str === 's') {\n        return 'SIM';\n    }\n\n    return null;\n}\n\n/**\n * Reads a JSON-encoded message (from a \"json-message\" element) and extracts source descriptions. Adds the extracted\n * source descriptions to the given Jingle IQ in the standard Jingle format.\n *\n * Encoding sources in this compact JSON format instead of standard Jingle was introduced in order to reduce the\n * network traffic and load on the XMPP server. The format is described in Jicofo [TODO: insert link].\n *\n * @param {*} iq the IQ to which source descriptions will be added.\n * @param {*} jsonMessageXml The XML node for the \"json-message\" element.\n * @returns {Map<string, Array<string>} The audio and video ssrcs extracted from the JSON-encoded message with remote\n * endpoint id as the key.\n */\nexport function expandSourcesFromJson(iq, jsonMessageXml) {\n    let json;\n\n    try {\n        json = JSON.parse(jsonMessageXml.textContent);\n    } catch (error) {\n        logger.error(`json-message XML contained invalid JSON, ignoring: ${jsonMessageXml.textContent}`);\n\n        return null;\n    }\n\n    if (!json?.sources) {\n        // It might be a message of a different type, no need to log.\n        return null;\n    }\n\n    // This is where we'll add \"source\" and \"ssrc-group\" elements. Create them elements if they don't exist.\n    const audioRtpDescription = _getOrCreateRtpDescription(iq, MediaType.AUDIO);\n    const videoRtpDescription = _getOrCreateRtpDescription(iq, MediaType.VIDEO);\n    const ssrcMap = new Map();\n\n    for (const owner in json.sources) {\n        if (json.sources.hasOwnProperty(owner)) {\n            const ssrcs = [];\n            const ownerSources = json.sources[owner];\n\n            // The video sources, video ssrc-groups, audio sources and audio ssrc-groups are encoded in that order in\n            // the elements of the array.\n            const videoSources = ownerSources?.length && ownerSources[0];\n            const videoSsrcGroups = ownerSources?.length > 1 && ownerSources[1];\n            const audioSources = ownerSources?.length > 2 && ownerSources[2];\n            const audioSsrcGroups = ownerSources?.length > 3 && ownerSources[3];\n\n            if (videoSources?.length) {\n                for (let i = 0; i < videoSources.length; i++) {\n                    videoRtpDescription.appendChild(_createSourceExtension(owner, videoSources[i]));\n                    ssrcs.push(videoSources[i]?.s);\n                }\n            }\n\n            if (videoSsrcGroups?.length) {\n                for (let i = 0; i < videoSsrcGroups.length; i++) {\n                    videoRtpDescription.appendChild(_createSsrcGroupExtension(videoSsrcGroups[i]));\n                }\n            }\n            if (audioSources?.length) {\n                for (let i = 0; i < audioSources.length; i++) {\n                    audioRtpDescription.appendChild(_createSourceExtension(owner, audioSources[i]));\n                    ssrcs.push(audioSources[i]?.s);\n                }\n            }\n\n            if (audioSsrcGroups?.length) {\n                for (let i = 0; i < audioSsrcGroups.length; i++) {\n                    audioRtpDescription.appendChild(_createSsrcGroupExtension(audioSsrcGroups[i]));\n                }\n            }\n            ssrcMap.set(owner, ssrcs);\n        }\n    }\n\n    return ssrcMap;\n}\n","/**\n * Enumeration of the media direction types.\n */\nexport enum MediaDirection {\n    /**\n     * Media is send and receive is suspended.\n     */\n    INACTIVE = 'inactive',\n\n    /**\n     * Media is only received from remote peer.\n     */\n    RECVONLY = 'recvonly',\n\n    /**\n     * Media is only sent to the remote peer.\n     */\n    SENDONLY = 'sendonly',\n\n    /**\n     * Media is sent and received.\n     */\n    SENDRECV = 'sendrecv'\n};\n","\nimport JitsiTrackError from '../../JitsiTrackError';\nimport * as JitsiTrackErrors from '../../JitsiTrackErrors';\nimport browser from '../browser';\n\nconst logger = require('@jitsi/logger').getLogger(__filename);\n\n/**\n * The default frame rate for Screen Sharing.\n */\nexport const SS_DEFAULT_FRAME_RATE = 5;\n\n/**\n * Handles obtaining a stream from a screen capture on different browsers.\n */\nconst ScreenObtainer = {\n    /**\n     * If not <tt>null</tt> it means that the initialization process is still in\n     * progress. It is used to make desktop stream request wait and continue\n     * after it's done.\n     * {@type Promise|null}\n     */\n\n    obtainStream: null,\n\n    /**\n     * Initializes the function used to obtain a screen capture\n     * (this.obtainStream).\n     *\n     * @param {object} options\n     */\n    init(options = {}) {\n        this.options = options;\n        this.obtainStream = this._createObtainStreamMethod();\n\n        if (!this.obtainStream) {\n            logger.info('Desktop sharing disabled');\n        }\n    },\n\n    /**\n     * Returns a method which will be used to obtain the screen sharing stream\n     * (based on the browser type).\n     *\n     * @returns {Function}\n     * @private\n     */\n    _createObtainStreamMethod() {\n        if (browser.isNWJS()) {\n            return (onSuccess, onFailure) => {\n                window.JitsiMeetNW.obtainDesktopStream(\n                    onSuccess,\n                    (error, constraints) => {\n                        let jitsiError;\n\n                        // FIXME:\n                        // This is very very dirty fix for recognising that the\n                        // user have clicked the cancel button from the Desktop\n                        // sharing pick window. The proper solution would be to\n                        // detect this in the NWJS application by checking the\n                        // streamId === \"\". Even better solution would be to\n                        // stop calling GUM from the NWJS app and just pass the\n                        // streamId to lib-jitsi-meet. This way the desktop\n                        // sharing implementation for NWJS and chrome extension\n                        // will be the same and lib-jitsi-meet will be able to\n                        // control the constraints, check the streamId, etc.\n                        //\n                        // I cannot find documentation about \"InvalidStateError\"\n                        // but this is what we are receiving from GUM when the\n                        // streamId for the desktop sharing is \"\".\n\n                        if (error && error.name === 'InvalidStateError') {\n                            jitsiError = new JitsiTrackError(\n                                JitsiTrackErrors.SCREENSHARING_USER_CANCELED\n                            );\n                        } else {\n                            jitsiError = new JitsiTrackError(\n                                error, constraints, [ 'desktop' ]);\n                        }\n                        (typeof onFailure === 'function')\n                            && onFailure(jitsiError);\n                    });\n            };\n        } else if (browser.isElectron()) {\n            return this.obtainScreenOnElectron;\n        } else if (browser.isReactNative() && browser.supportsGetDisplayMedia()) {\n            return this.obtainScreenFromGetDisplayMediaRN;\n        } else if (browser.supportsGetDisplayMedia()) {\n            return this.obtainScreenFromGetDisplayMedia;\n        }\n        logger.log('Screen sharing not supported on ', browser.getName());\n\n        return null;\n    },\n\n    /**\n     * Gets the appropriate constraints for audio sharing.\n     *\n     * @returns {Object|boolean}\n     */\n    _getAudioConstraints() {\n        const { audioQuality } = this.options;\n        const audio = audioQuality?.stereo ? {\n            autoGainControl: false,\n            channelCount: 2,\n            echoCancellation: false,\n            noiseSuppression: false\n        } : true;\n\n        return audio;\n    },\n\n    /**\n     * Checks whether obtaining a screen capture is supported in the current\n     * environment.\n     * @returns {boolean}\n     */\n    isSupported() {\n        return this.obtainStream !== null;\n    },\n\n    /**\n     * Obtains a screen capture stream on Electron.\n     *\n     * @param onSuccess - Success callback.\n     * @param onFailure - Failure callback.\n     * @param {Object} options - Optional parameters.\n     */\n    obtainScreenOnElectron(onSuccess, onFailure, options = {}) {\n        if (window.JitsiMeetScreenObtainer && window.JitsiMeetScreenObtainer.openDesktopPicker) {\n            const { desktopSharingFrameRate, desktopSharingResolution, desktopSharingSources } = this.options;\n\n            window.JitsiMeetScreenObtainer.openDesktopPicker(\n                {\n                    desktopSharingSources:\n                        options.desktopSharingSources || desktopSharingSources || [ 'screen', 'window' ]\n                },\n                (streamId, streamType, screenShareAudio = false) => {\n                    if (streamId) {\n                        let audioConstraints = false;\n\n                        if (screenShareAudio) {\n                            audioConstraints = {};\n                            const optionalConstraints = this._getAudioConstraints();\n\n                            if (typeof optionalConstraints !== 'boolean') {\n                                audioConstraints = {\n                                    optional: optionalConstraints\n                                };\n                            }\n\n                            // Audio screen sharing for electron only works for screen type devices.\n                            // i.e. when the user shares the whole desktop.\n                            // Note. The documentation specifies that chromeMediaSourceId should not be present\n                            // which, in the case a users has multiple monitors, leads to them being shared all\n                            // at once. However we tested with chromeMediaSourceId present and it seems to be\n                            // working properly.\n                            if (streamType === 'screen') {\n                                audioConstraints.mandatory = {\n                                    chromeMediaSource: 'desktop'\n                                };\n                            }\n                        }\n\n                        const constraints = {\n                            audio: audioConstraints,\n                            video: {\n                                mandatory: {\n                                    chromeMediaSource: 'desktop',\n                                    chromeMediaSourceId: streamId,\n                                    minFrameRate: desktopSharingFrameRate?.min ?? SS_DEFAULT_FRAME_RATE,\n                                    maxFrameRate: desktopSharingFrameRate?.max ?? SS_DEFAULT_FRAME_RATE,\n                                    minWidth: desktopSharingResolution?.width?.min,\n                                    minHeight: desktopSharingResolution?.height?.min,\n                                    maxWidth: desktopSharingResolution?.width?.max ?? window.screen.width,\n                                    maxHeight: desktopSharingResolution?.height?.max ?? window.screen.height\n                                }\n                            }\n                        };\n\n                        // We have to use the old API on Electron to get a desktop stream.\n                        navigator.mediaDevices.getUserMedia(constraints)\n                            .then(stream => onSuccess({\n                                stream,\n                                sourceId: streamId,\n                                sourceType: streamType\n                            }), onFailure);\n                    } else {\n                        // As noted in Chrome Desktop Capture API:\n                        // If user didn't select any source (i.e. canceled the prompt)\n                        // then the callback is called with an empty streamId.\n                        onFailure(new JitsiTrackError(JitsiTrackErrors.SCREENSHARING_USER_CANCELED));\n                    }\n                },\n                err => onFailure(new JitsiTrackError(\n                    JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_ERROR,\n                    err\n                ))\n            );\n        } else {\n            onFailure(new JitsiTrackError(JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_NOT_FOUND));\n        }\n    },\n\n    /**\n     * Obtains a screen capture stream using getDisplayMedia.\n     *\n     * @param callback - The success callback.\n     * @param errorCallback - The error callback.\n     */\n    obtainScreenFromGetDisplayMedia(callback, errorCallback) {\n        let getDisplayMedia;\n\n        if (navigator.getDisplayMedia) {\n            getDisplayMedia = navigator.getDisplayMedia.bind(navigator);\n        } else {\n            // eslint-disable-next-line max-len\n            getDisplayMedia = navigator.mediaDevices.getDisplayMedia.bind(navigator.mediaDevices);\n        }\n\n        const audio = this._getAudioConstraints();\n        let video = {};\n        const { desktopSharingFrameRate } = this.options;\n\n        if (typeof desktopSharingFrameRate === 'object') {\n            video.frameRate = desktopSharingFrameRate;\n        }\n\n        // At the time of this writing 'min' constraint for fps is not supported by getDisplayMedia on any of the\n        // browsers. getDisplayMedia will fail with an error \"invalid constraints\" in this case.\n        video.frameRate && delete video.frameRate.min;\n\n        if (browser.isChromiumBased()) {\n            // Allow users to seamlessly switch which tab they are sharing without having to select the tab again.\n            browser.isVersionGreaterThan(106) && (video.surfaceSwitching = 'include');\n\n            // Set bogus resolution constraints to work around\n            // https://bugs.chromium.org/p/chromium/issues/detail?id=1056311 for low fps screenshare. Capturing SS at\n            // very high resolutions restricts the framerate. Therefore, skip this hack when capture fps > 5 fps.\n            if (!(desktopSharingFrameRate?.max > SS_DEFAULT_FRAME_RATE)) {\n                video.height = 99999;\n                video.width = 99999;\n            }\n        }\n\n        if (Object.keys(video).length === 0) {\n            video = true;\n        }\n\n        const constraints = {\n            video,\n            audio,\n            cursor: 'always'\n        };\n\n        logger.info('Using getDisplayMedia for screen sharing', constraints);\n\n        getDisplayMedia(constraints)\n            .then(stream => {\n                callback({\n                    stream,\n                    sourceId: stream.id\n                });\n            })\n            .catch(error => {\n                const errorDetails = {\n                    errorName: error && error.name,\n                    errorMsg: error && error.message,\n                    errorStack: error && error.stack\n                };\n\n                logger.error('getDisplayMedia error', constraints, errorDetails);\n\n                if (errorDetails.errorMsg && errorDetails.errorMsg.indexOf('denied by system') !== -1) {\n                    // On Chrome this is the only thing different between error returned when user cancels\n                    // and when no permission was given on the OS level.\n                    errorCallback(new JitsiTrackError(JitsiTrackErrors.PERMISSION_DENIED));\n\n                    return;\n                }\n\n                errorCallback(new JitsiTrackError(JitsiTrackErrors.SCREENSHARING_USER_CANCELED));\n            });\n    },\n\n    /**\n     * Obtains a screen capture stream using getDisplayMedia.\n     *\n     * @param callback - The success callback.\n     * @param errorCallback - The error callback.\n     */\n    obtainScreenFromGetDisplayMediaRN(callback, errorCallback) {\n        logger.info('Using getDisplayMedia for screen sharing');\n\n        navigator.mediaDevices.getDisplayMedia({ video: true })\n            .then(stream => {\n                callback({\n                    stream,\n                    sourceId: stream.id });\n            })\n            .catch(() => {\n                errorCallback(new JitsiTrackError(JitsiTrackErrors\n                    .SCREENSHARING_USER_CANCELED));\n            });\n    },\n\n    /**\n     * Sets the max frame rate to be used for a desktop track capture.\n     *\n     * @param {number} maxFps capture frame rate to be used for desktop tracks.\n     * @returns {void}\n     */\n    setDesktopSharingFrameRate(maxFps) {\n        logger.info(`Setting the desktop capture rate to ${maxFps}`);\n\n        this.options.desktopSharingFrameRate = {\n            min: SS_DEFAULT_FRAME_RATE,\n            max: maxFps\n        };\n    }\n};\n\nexport default ScreenObtainer;\n","import { getLogger } from '@jitsi/logger';\nconst logger = getLogger(__filename);\n\nimport CodecMimeType from '../../service/RTC/CodecMimeType';\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\nimport browser from '../browser';\nimport RandomUtil from '../util/RandomUtil';\n\nconst SDPUtil = {\n    filterSpecialChars(text) {\n        // XXX Neither one of the falsy values (e.g. null, undefined, false,\n        // \"\", etc.) \"contain\" special chars.\n        // eslint-disable-next-line no-useless-escape\n        return text ? text.replace(/[\\\\\\/\\{,\\}\\+]/g, '') : text;\n    },\n    iceparams(mediadesc, sessiondesc) {\n        let data = null;\n        let pwd, ufrag;\n\n        if ((ufrag = SDPUtil.findLine(mediadesc, 'a=ice-ufrag:', sessiondesc))\n                && (pwd\n                    = SDPUtil.findLine(\n                        mediadesc,\n                        'a=ice-pwd:',\n                        sessiondesc))) {\n            data = {\n                ufrag: SDPUtil.parseICEUfrag(ufrag),\n                pwd: SDPUtil.parseICEPwd(pwd)\n            };\n        }\n\n        return data;\n    },\n    parseICEUfrag(line) {\n        return line.substring(12);\n    },\n    buildICEUfrag(frag) {\n        return `a=ice-ufrag:${frag}`;\n    },\n    parseICEPwd(line) {\n        return line.substring(10);\n    },\n    buildICEPwd(pwd) {\n        return `a=ice-pwd:${pwd}`;\n    },\n    parseMID(line) {\n        return line.substring(6);\n    },\n\n    /**\n     * Finds the MSID attribute in the given array of SSRC attribute lines and returns the value.\n     *\n     * @param {string[]} ssrcLines - an array of lines similar to 'a:213123 msid:stream-id track-id'.\n     * @returns {undefined|string}\n     */\n    parseMSIDAttribute(ssrcLines) {\n        const msidLine = ssrcLines.find(line => line.indexOf(' msid:') > 0);\n\n        if (!msidLine) {\n            return undefined;\n        }\n\n        const v = msidLine.substring(msidLine.indexOf(' msid:') + 6 /* the length of ' msid:' */);\n\n        return SDPUtil.filterSpecialChars(v);\n    },\n    parseMLine(line) {\n        const data = {};\n        const parts = line.substring(2).split(' ');\n\n        data.media = parts.shift();\n        data.port = parts.shift();\n        data.proto = parts.shift();\n        if (parts[parts.length - 1] === '') { // trailing whitespace\n            parts.pop();\n        }\n        data.fmt = parts;\n\n        return data;\n    },\n    buildMLine(mline) {\n        return (\n            `m=${mline.media} ${mline.port} ${mline.proto} ${\n                mline.fmt.join(' ')}`);\n    },\n    parseRTPMap(line) {\n        const data = {};\n        let parts = line.substring(9).split(' ');\n\n        data.id = parts.shift();\n        parts = parts[0].split('/');\n        data.name = parts.shift();\n        data.clockrate = parts.shift();\n        data.channels = parts.length ? parts.shift() : '1';\n\n        return data;\n    },\n\n    /**\n     * Parses SDP line \"a=sctpmap:...\" and extracts SCTP port from it.\n     * @param line eg. \"a=sctpmap:5000 webrtc-datachannel\"\n     * @returns [SCTP port number, protocol, streams]\n     */\n    parseSCTPMap(line) {\n        const parts = line.substring(10).split(' ');\n        const sctpPort = parts[0];\n        const protocol = parts[1];\n\n        // Stream count is optional\n        const streamCount = parts.length > 2 ? parts[2] : null;\n\n\n        return [ sctpPort, protocol, streamCount ];// SCTP port\n    },\n    parseSCTPPort(line) {\n        return line.substring(12);\n    },\n    buildRTPMap(el) {\n        let line\n            = `a=rtpmap:${el.getAttribute('id')} ${el.getAttribute('name')}/${\n                el.getAttribute('clockrate')}`;\n\n        if (el.getAttribute('channels')\n            && el.getAttribute('channels') !== '1') {\n            line += `/${el.getAttribute('channels')}`;\n        }\n\n        return line;\n    },\n    parseCrypto(line) {\n        const data = {};\n        const parts = line.substring(9).split(' ');\n\n        data.tag = parts.shift();\n        data['crypto-suite'] = parts.shift();\n        data['key-params'] = parts.shift();\n        if (parts.length) {\n            data['session-params'] = parts.join(' ');\n        }\n\n        return data;\n    },\n    parseFingerprint(line) { // RFC 4572\n        const data = {};\n        const parts = line.substring(14).split(' ');\n\n        data.hash = parts.shift();\n        data.fingerprint = parts.shift();\n\n        // TODO assert that fingerprint satisfies 2UHEX *(\":\" 2UHEX) ?\n        return data;\n    },\n    parseFmtp(line) {\n        const data = [];\n        let parts = line.split(' ');\n\n        parts.shift();\n        parts = parts.join(' ').split(';');\n        for (let i = 0; i < parts.length; i++) {\n            let key = parts[i].split('=')[0];\n\n            while (key.length && key[0] === ' ') {\n                key = key.substring(1);\n            }\n            const value = parts[i].split('=')[1];\n\n            if (key && value) {\n                data.push({ name: key,\n                    value });\n            } else if (key) {\n                // rfc 4733 (DTMF) style stuff\n                data.push({ name: '',\n                    value: key });\n            }\n        }\n\n        return data;\n    },\n    parseICECandidate(line) {\n        const candidate = {};\n        const elems = line.split(' ');\n\n        candidate.foundation = elems[0].substring(12);\n        candidate.component = elems[1];\n        candidate.protocol = elems[2].toLowerCase();\n        candidate.priority = elems[3];\n        candidate.ip = elems[4];\n        candidate.port = elems[5];\n\n        // elems[6] => \"typ\"\n        candidate.type = elems[7];\n        candidate.generation = 0; // default value, may be overwritten below\n        for (let i = 8; i < elems.length; i += 2) {\n            switch (elems[i]) {\n            case 'raddr':\n                candidate['rel-addr'] = elems[i + 1];\n                break;\n            case 'rport':\n                candidate['rel-port'] = elems[i + 1];\n                break;\n            case 'generation':\n                candidate.generation = elems[i + 1];\n                break;\n            case 'tcptype':\n                candidate.tcptype = elems[i + 1];\n                break;\n            default: // TODO\n                logger.debug(\n                    `parseICECandidate not translating \"${\n                        elems[i]}\" = \"${elems[i + 1]}\"`);\n            }\n        }\n        candidate.network = '1';\n\n        // not applicable to SDP -- FIXME: should be unique, not just random\n        // eslint-disable-next-line newline-per-chained-call\n        candidate.id = Math.random().toString(36).substr(2, 10);\n\n        return candidate;\n    },\n    buildICECandidate(cand) {\n        let line = [\n            `a=candidate:${cand.foundation}`,\n            cand.component,\n            cand.protocol,\n            cand.priority,\n            cand.ip,\n            cand.port,\n            'typ',\n            cand.type\n        ].join(' ');\n\n        line += ' ';\n        switch (cand.type) {\n        case 'srflx':\n        case 'prflx':\n        case 'relay':\n            if (cand.hasOwnAttribute('rel-addr')\n                    && cand.hasOwnAttribute('rel-port')) {\n                line += 'raddr';\n                line += ' ';\n                line += cand['rel-addr'];\n                line += ' ';\n                line += 'rport';\n                line += ' ';\n                line += cand['rel-port'];\n                line += ' ';\n            }\n            break;\n        }\n        if (cand.hasOwnAttribute('tcptype')) {\n            line += 'tcptype';\n            line += ' ';\n            line += cand.tcptype;\n            line += ' ';\n        }\n        line += 'generation';\n        line += ' ';\n        line += cand.hasOwnAttribute('generation') ? cand.generation : '0';\n\n        return line;\n    },\n    parseSSRC(desc) {\n        // proprietary mapping of a=ssrc lines\n        // TODO: see \"Jingle RTP Source Description\" by Juberti and P. Thatcher\n        // on google docs and parse according to that\n        const data = new Map();\n        const lines = desc.split('\\r\\n');\n\n        for (let i = 0; i < lines.length; i++) {\n            if (lines[i].substring(0, 7) === 'a=ssrc:') {\n                // FIXME: Use regex to smartly find the ssrc.\n                const ssrc = lines[i].split('a=ssrc:')[1].split(' ')[0];\n\n                if (!data.get(ssrc)) {\n                    data.set(ssrc, []);\n                }\n\n                data.get(ssrc).push(lines[i]);\n            }\n        }\n\n        return data;\n    },\n\n    /**\n     * Gets the source name out of the name attribute \"a=ssrc:254321 name:name1\".\n     *\n     * @param {string[]} ssrcLines\n     * @returns {string | undefined}\n     */\n    parseSourceNameLine(ssrcLines) {\n        const sourceNameLine = ssrcLines.find(ssrcSdpLine => ssrcSdpLine.indexOf(' name:') > 0);\n\n        // Everything past the \"name:\" part\n        return sourceNameLine?.substring(sourceNameLine.indexOf(' name:') + 6);\n    },\n\n    /**\n     * Parse the \"videoType\" attribute encoded in a set of SSRC attributes (e.g.\n     * \"a=ssrc:1234 videoType:desktop\")\n     *\n     * @param {string[]} ssrcLines\n     * @returns {string | undefined}\n     */\n    parseVideoTypeLine(ssrcLines) {\n        const s = ' videoType:';\n        const videoTypeLine = ssrcLines.find(ssrcSdpLine => ssrcSdpLine.indexOf(s) > 0);\n\n        return videoTypeLine?.substring(videoTypeLine.indexOf(s) + s.length);\n    },\n    parseRTCPFB(line) {\n        const parts = line.substr(10).split(' ');\n        const data = {};\n\n        data.pt = parts.shift();\n        data.type = parts.shift();\n        data.params = parts;\n\n        return data;\n    },\n    parseExtmap(line) {\n        const parts = line.substr(9).split(' ');\n        const data = {};\n\n        data.value = parts.shift();\n        if (data.value.indexOf('/') === -1) {\n            data.direction = 'both';\n        } else {\n            data.direction = data.value.substr(data.value.indexOf('/') + 1);\n            data.value = data.value.substr(0, data.value.indexOf('/'));\n        }\n        data.uri = parts.shift();\n        data.params = parts;\n\n        return data;\n    },\n    findLine(haystack, needle, sessionpart) {\n        let lines = haystack.split('\\r\\n');\n\n        for (let i = 0; i < lines.length; i++) {\n            if (lines[i].substring(0, needle.length) === needle) {\n                return lines[i];\n            }\n        }\n        if (!sessionpart) {\n            return false;\n        }\n\n        // search session part\n        lines = sessionpart.split('\\r\\n');\n        for (let j = 0; j < lines.length; j++) {\n            if (lines[j].substring(0, needle.length) === needle) {\n                return lines[j];\n            }\n        }\n\n        return false;\n    },\n    findLines(haystack, needle, sessionpart) {\n        let lines = haystack.split('\\r\\n');\n        const needles = [];\n\n        for (let i = 0; i < lines.length; i++) {\n            if (lines[i].substring(0, needle.length) === needle) {\n                needles.push(lines[i]);\n            }\n        }\n        if (needles.length || !sessionpart) {\n            return needles;\n        }\n\n        // search session part\n        lines = sessionpart.split('\\r\\n');\n        for (let j = 0; j < lines.length; j++) {\n            if (lines[j].substring(0, needle.length) === needle) {\n                needles.push(lines[j]);\n            }\n        }\n\n        return needles;\n    },\n    candidateToJingle(line) {\n        // a=candidate:2979166662 1 udp 2113937151 192.168.2.100 57698 typ host\n        // generation 0\n        //      <candidate component=... foundation=... generation=... id=...\n        // ip=... network=... port=... priority=... protocol=... type=.../>\n        if (line.indexOf('candidate:') === 0) {\n            // eslint-disable-next-line no-param-reassign\n            line = `a=${line}`;\n        } else if (line.substring(0, 12) !== 'a=candidate:') {\n            logger.warn(\n                'parseCandidate called with a line that is not a candidate'\n                    + ' line');\n            logger.warn(line);\n\n            return null;\n        }\n        if (line.substring(line.length - 2) === '\\r\\n') { // chomp it\n            // eslint-disable-next-line no-param-reassign\n            line = line.substring(0, line.length - 2);\n        }\n        const candidate = {};\n        const elems = line.split(' ');\n\n        if (elems[6] !== 'typ') {\n            logger.warn('did not find typ in the right place');\n            logger.warn(line);\n\n            return null;\n        }\n        candidate.foundation = elems[0].substring(12);\n        candidate.component = elems[1];\n        candidate.protocol = elems[2].toLowerCase();\n        candidate.priority = elems[3];\n        candidate.ip = elems[4];\n        candidate.port = elems[5];\n\n        // elems[6] => \"typ\"\n        candidate.type = elems[7];\n\n        candidate.generation = '0'; // default, may be overwritten below\n        for (let i = 8; i < elems.length; i += 2) {\n            switch (elems[i]) {\n            case 'raddr':\n                candidate['rel-addr'] = elems[i + 1];\n                break;\n            case 'rport':\n                candidate['rel-port'] = elems[i + 1];\n                break;\n            case 'generation':\n                candidate.generation = elems[i + 1];\n                break;\n            case 'tcptype':\n                candidate.tcptype = elems[i + 1];\n                break;\n            default: // TODO\n                logger.debug(`not translating \"${elems[i]}\" = \"${elems[i + 1]}\"`);\n            }\n        }\n        candidate.network = '1';\n\n        // not applicable to SDP -- FIXME: should be unique, not just random\n        // eslint-disable-next-line newline-per-chained-call\n        candidate.id = Math.random().toString(36).substr(2, 10);\n\n        return candidate;\n    },\n    candidateFromJingle(cand) {\n        let line = 'a=candidate:';\n\n        line += cand.getAttribute('foundation');\n        line += ' ';\n        line += cand.getAttribute('component');\n        line += ' ';\n\n        let protocol = cand.getAttribute('protocol');\n\n        // use tcp candidates for FF\n\n        if (browser.isFirefox() && protocol.toLowerCase() === 'ssltcp') {\n            protocol = 'tcp';\n        }\n\n        line += protocol; // .toUpperCase(); // chrome M23 doesn't like this\n        line += ' ';\n        line += cand.getAttribute('priority');\n        line += ' ';\n        line += cand.getAttribute('ip');\n        line += ' ';\n        line += cand.getAttribute('port');\n        line += ' ';\n        line += 'typ';\n        line += ` ${cand.getAttribute('type')}`;\n        line += ' ';\n        switch (cand.getAttribute('type')) {\n        case 'srflx':\n        case 'prflx':\n        case 'relay':\n            if (cand.getAttribute('rel-addr')\n                    && cand.getAttribute('rel-port')) {\n                line += 'raddr';\n                line += ' ';\n                line += cand.getAttribute('rel-addr');\n                line += ' ';\n                line += 'rport';\n                line += ' ';\n                line += cand.getAttribute('rel-port');\n                line += ' ';\n            }\n            break;\n        }\n        if (protocol.toLowerCase() === 'tcp') {\n            line += 'tcptype';\n            line += ' ';\n            line += cand.getAttribute('tcptype');\n            line += ' ';\n        }\n        line += 'generation';\n        line += ' ';\n        line += cand.getAttribute('generation') || '0';\n\n        return `${line}\\r\\n`;\n    },\n\n    /**\n     * Parse the 'most' primary video ssrc from the given m line\n     * @param {object} mLine object as parsed from transform.parse\n     * @return {number} the primary video ssrc from the given m line\n     */\n    parsePrimaryVideoSsrc(videoMLine) {\n        const numSsrcs = videoMLine.ssrcs\n            .map(ssrcInfo => ssrcInfo.id)\n            .filter((ssrc, index, array) => array.indexOf(ssrc) === index)\n            .length;\n        const numGroups\n            = (videoMLine.ssrcGroups && videoMLine.ssrcGroups.length) || 0;\n\n        if (numSsrcs > 1 && numGroups === 0) {\n            // Ambiguous, can't figure out the primary\n            return;\n        }\n        let primarySsrc = null;\n\n        if (numSsrcs === 1) {\n            primarySsrc = videoMLine.ssrcs[0].id;\n        } else if (numSsrcs === 2) {\n            // Can figure it out if there's an FID group\n            const fidGroup\n                = videoMLine.ssrcGroups.find(\n                    group => group.semantics === 'FID');\n\n            if (fidGroup) {\n                primarySsrc = fidGroup.ssrcs.split(' ')[0];\n            }\n        } else if (numSsrcs >= 3) {\n            // Can figure it out if there's a sim group\n            const simGroup\n                = videoMLine.ssrcGroups.find(\n                    group => group.semantics === 'SIM');\n\n            if (simGroup) {\n                primarySsrc = simGroup.ssrcs.split(' ')[0];\n            }\n        }\n\n        return primarySsrc;\n    },\n\n    /**\n     * Generate an ssrc\n     * @returns {number} an ssrc\n     */\n    generateSsrc() {\n        return RandomUtil.randomInt(1, 0xffffffff);\n    },\n\n    /**\n     * Get an attribute for the given ssrc with the given attributeName\n     *  from the given mline\n     * @param {object} mLine an mLine object as parsed from transform.parse\n     * @param {number} ssrc the ssrc for which an attribute is desired\n     * @param {string} attributeName the name of the desired attribute\n     * @returns {string} the value corresponding to the given ssrc\n     *  and attributeName\n     */\n    getSsrcAttribute(mLine, ssrc, attributeName) {\n        for (let i = 0; i < mLine.ssrcs.length; ++i) {\n            const ssrcLine = mLine.ssrcs[i];\n\n            if (ssrcLine.id === ssrc\n                && ssrcLine.attribute === attributeName) {\n                return ssrcLine.value;\n            }\n        }\n    },\n\n    /**\n     * Parses the ssrcs from the group sdp line and\n     *  returns them as a list of numbers\n     * @param {object} the ssrcGroup object as parsed from\n     *  sdp-transform\n     * @returns {list<number>} a list of the ssrcs in the group\n     *  parsed as numbers\n     */\n    parseGroupSsrcs(ssrcGroup) {\n        return ssrcGroup\n            .ssrcs\n            .split(' ')\n            .map(ssrcStr => parseInt(ssrcStr, 10));\n    },\n\n    /**\n     * Get the mline of the given type from the given sdp\n     * @param {object} sdp sdp as parsed from transform.parse\n     * @param {string} type the type of the desired mline (e.g. \"video\")\n     * @returns {object} a media object\n     */\n    getMedia(sdp, type) {\n        return sdp.media.find(m => m.type === type);\n    },\n\n    /**\n     * Extracts the ICE username fragment from an SDP string.\n     * @param {string} sdp the SDP in raw text format\n     */\n    getUfrag(sdp) {\n        const ufragLines\n            = sdp.split('\\n').filter(line => line.startsWith('a=ice-ufrag:'));\n\n        if (ufragLines.length > 0) {\n            return ufragLines[0].substr('a=ice-ufrag:'.length);\n        }\n    },\n\n    /**\n     * Sets the given codecName as the preferred codec by moving it to the beginning\n     * of the payload types list (modifies the given mline in place). All instances\n     * of the codec are moved up.\n     * @param {object} mLine the mline object from an sdp as parsed by transform.parse\n     * @param {string} codecName the name of the preferred codec\n     */\n    preferCodec(mline, codecName) {\n        if (!mline || !codecName) {\n            return;\n        }\n\n        const matchingPayloadTypes = mline.rtp\n            .filter(rtp => rtp.codec && rtp.codec.toLowerCase() === codecName.toLowerCase())\n            .map(rtp => rtp.payload);\n\n        if (matchingPayloadTypes) {\n            // Call toString() on payloads to get around an issue within SDPTransform that sets\n            // payloads as a number, instead of a string, when there is only one payload.\n            const payloadTypes\n                = mline.payloads\n                .toString()\n                .split(' ')\n                .map(p => parseInt(p, 10));\n\n            for (const pt of matchingPayloadTypes.reverse()) {\n                const payloadIndex = payloadTypes.indexOf(pt);\n\n                payloadTypes.splice(payloadIndex, 1);\n                payloadTypes.unshift(pt);\n            }\n            mline.payloads = payloadTypes.join(' ');\n        } else {\n            logger.error(`No matching RTP payload type found for ${codecName}, failed to set preferred codecs`);\n        }\n    },\n\n    /**\n     * Strips the given codec from the given mline. All related RTX payload\n     * types are also stripped. If the resulting mline would have no codecs,\n     * it's disabled.\n     *\n     * @param {object} mLine the mline object from an sdp as parsed by transform.parse.\n     * @param {string} codecName the name of the codec which will be stripped.\n     * @param {boolean} highProfile determines if only the high profile H264 codec needs to be\n     * stripped from the sdp when the passed codecName is H264.\n     */\n    stripCodec(mLine, codecName, highProfile = false) {\n        if (!mLine || !codecName) {\n            return;\n        }\n\n        const h264Pts = [];\n        let removePts = [];\n        const stripH264HighCodec = codecName.toLowerCase() === CodecMimeType.H264 && highProfile;\n\n        for (const rtp of mLine.rtp) {\n            if (rtp.codec\n                && rtp.codec.toLowerCase() === codecName.toLowerCase()) {\n                if (stripH264HighCodec) {\n                    h264Pts.push(rtp.payload);\n                } else {\n                    removePts.push(rtp.payload);\n                }\n            }\n        }\n\n        // high profile H264 codecs have 64 as the first two bytes of the profile-level-id.\n        if (stripH264HighCodec) {\n            removePts = mLine.fmtp\n                .filter(item => h264Pts.indexOf(item.payload) > -1 && item.config.includes('profile-level-id=64'))\n                .map(item => item.payload);\n        }\n\n        if (removePts.length > 0) {\n            // We also need to remove the payload types that are related to RTX\n            // for the codecs we want to disable.\n            const rtxApts = removePts.map(item => `apt=${item}`);\n            const rtxPts = mLine.fmtp.filter(\n                item => rtxApts.indexOf(item.config) !== -1);\n\n            removePts.push(...rtxPts.map(item => item.payload));\n\n            // Call toString() on payloads to get around an issue within\n            // SDPTransform that sets payloads as a number, instead of a string,\n            // when there is only one payload.\n            const allPts = mLine.payloads\n                .toString()\n                .split(' ')\n                .map(Number);\n            const keepPts = allPts.filter(pt => removePts.indexOf(pt) === -1);\n\n            if (keepPts.length === 0) {\n                // There are no other codecs, disable the stream.\n                mLine.port = 0;\n                mLine.direction = MediaDirection.INACTIVE;\n                mLine.payloads = '*';\n            } else {\n                mLine.payloads = keepPts.join(' ');\n            }\n\n            mLine.rtp = mLine.rtp.filter(\n                item => keepPts.indexOf(item.payload) !== -1);\n            mLine.fmtp = mLine.fmtp.filter(\n                item => keepPts.indexOf(item.payload) !== -1);\n            if (mLine.rtcpFb) {\n                mLine.rtcpFb = mLine.rtcpFb.filter(\n                    item => keepPts.indexOf(item.payload) !== -1);\n            }\n        }\n    }\n};\n\nexport default SDPUtil;\n","import $ from 'jquery';\nimport clonedeep from 'lodash.clonedeep';\nimport transform from 'sdp-transform';\n\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\nimport browser from '../browser';\n\nimport SDPUtil from './SDPUtil';\n\n/**\n *\n * @param sdp\n */\nexport default function SDP(sdp) {\n    const media = sdp.split('\\r\\nm=');\n\n    for (let i = 1, length = media.length; i < length; i++) {\n        let mediaI = `m=${media[i]}`;\n\n        if (i !== length - 1) {\n            mediaI += '\\r\\n';\n        }\n        media[i] = mediaI;\n    }\n    const session = `${media.shift()}\\r\\n`;\n\n    this.media = media;\n    this.raw = session + media.join('');\n    this.session = session;\n}\n\n/**\n * A flag will make {@link transportToJingle} and {@link jingle2media} replace\n * ICE candidates IPs with invalid value of '1.1.1.1' which will cause ICE\n * failure. The flag is used in the automated testing.\n * @type {boolean}\n */\nSDP.prototype.failICE = false;\n\n/**\n * Whether or not to remove TCP ice candidates when translating from/to jingle.\n * @type {boolean}\n */\nSDP.prototype.removeTcpCandidates = false;\n\n/**\n * Whether or not to remove UDP ice candidates when translating from/to jingle.\n * @type {boolean}\n */\nSDP.prototype.removeUdpCandidates = false;\n\n/**\n * Adds a new m-line to the description so that a new local source can then be attached to the transceiver that gets\n * added after a reneogtiation cycle.\n *\n * @param {MediaType} mediaType media type of the new source that is being added.\n */\nSDP.prototype.addMlineForNewLocalSource = function(mediaType) {\n    const mid = this.media.length;\n    const sdp = transform.parse(this.raw);\n    const mline = clonedeep(sdp.media.find(m => m.type === mediaType));\n\n    // Edit media direction, mid and remove the existing ssrc lines in the m-line.\n    mline.mid = mid;\n    mline.direction = MediaDirection.RECVONLY;\n\n    // Remove the ssrcs and source groups.\n    mline.msid = undefined;\n    mline.ssrcs = undefined;\n    mline.ssrcGroups = undefined;\n\n    sdp.media = sdp.media.concat(mline);\n\n    // We regenerate the BUNDLE group (since we added a new m-line)\n    sdp.groups.forEach(group => {\n        if (group.type === 'BUNDLE') {\n            const mids = group.mids.split(' ');\n\n            mids.push(mid);\n            group.mids = mids.join(' ');\n        }\n    });\n    this.raw = transform.write(sdp);\n};\n\n/**\n * Returns map of MediaChannel mapped per channel idx.\n */\nSDP.prototype.getMediaSsrcMap = function() {\n    const mediaSSRCs = {};\n\n    for (let mediaindex = 0; mediaindex < this.media.length; mediaindex++) {\n        const mid\n            = SDPUtil.parseMID(\n                SDPUtil.findLine(this.media[mediaindex], 'a=mid:'));\n        const media = {\n            mediaindex,\n            mid,\n            ssrcs: {},\n            ssrcGroups: []\n        };\n\n        mediaSSRCs[mediaindex] = media;\n\n        SDPUtil.findLines(this.media[mediaindex], 'a=ssrc:').forEach(line => {\n            const linessrc = line.substring(7).split(' ')[0];\n\n            // allocate new ChannelSsrc\n\n            if (!media.ssrcs[linessrc]) {\n                media.ssrcs[linessrc] = {\n                    ssrc: linessrc,\n                    lines: []\n                };\n            }\n            media.ssrcs[linessrc].lines.push(line);\n        });\n        SDPUtil.findLines(this.media[mediaindex], 'a=ssrc-group:').forEach(line => {\n            const idx = line.indexOf(' ');\n            const semantics = line.substr(0, idx).substr(13);\n            const ssrcs = line.substr(14 + semantics.length).split(' ');\n\n            if (ssrcs.length) {\n                media.ssrcGroups.push({\n                    semantics,\n                    ssrcs\n                });\n            }\n        });\n    }\n\n    return mediaSSRCs;\n};\n\n/**\n * Returns <tt>true</tt> if this SDP contains given SSRC.\n * @param ssrc the ssrc to check.\n * @returns {boolean} <tt>true</tt> if this SDP contains given SSRC.\n */\nSDP.prototype.containsSSRC = function(ssrc) {\n    // FIXME this code is really strange - improve it if you can\n    const medias = this.getMediaSsrcMap();\n    let result = false;\n\n    Object.keys(medias).forEach(mediaindex => {\n        if (result) {\n            return;\n        }\n        if (medias[mediaindex].ssrcs[ssrc]) {\n            result = true;\n        }\n    });\n\n    return result;\n};\n\n// add content's to a jingle element\nSDP.prototype.toJingle = function(elem, thecreator) {\n    // https://xmpp.org/extensions/xep-0338.html\n    SDPUtil.findLines(this.session, 'a=group:').forEach(line => {\n        const parts = line.split(' ');\n        const semantics = parts.shift().substr(8);\n\n        elem.c('group', { xmlns: 'urn:xmpp:jingle:apps:grouping:0',\n            semantics });\n        for (let j = 0; j < parts.length; j++) {\n            elem.c('content', { name: parts[j] }).up();\n        }\n        elem.up();\n    });\n\n    for (let i = 0; i < this.media.length; i++) {\n        const mline = SDPUtil.parseMLine(this.media[i].split('\\r\\n')[0]);\n\n        if (!(mline.media === 'audio'\n              || mline.media === 'video'\n              || mline.media === 'application')) {\n            continue; // eslint-disable-line no-continue\n        }\n\n        let ssrc;\n        const assrcline = SDPUtil.findLine(this.media[i], 'a=ssrc:');\n\n        if (assrcline) {\n            ssrc = assrcline.substring(7).split(' ')[0]; // take the first\n        } else {\n            ssrc = false;\n        }\n\n        elem.c('content', { creator: thecreator,\n            name: mline.media });\n        const amidline = SDPUtil.findLine(this.media[i], 'a=mid:');\n\n        if (amidline) {\n            // prefer identifier from a=mid if present\n            const mid = SDPUtil.parseMID(amidline);\n\n            elem.attrs({ name: mid });\n        }\n\n        if (mline.media === 'video' && typeof this.initialLastN === 'number') {\n            elem.c('initial-last-n',\n                { xmlns: 'jitsi:colibri2',\n                    value: this.initialLastN }).up();\n        }\n\n        if (mline.media === 'audio' || mline.media === 'video') {\n            elem.c('description',\n                { xmlns: 'urn:xmpp:jingle:apps:rtp:1',\n                    media: mline.media });\n            if (ssrc) {\n                elem.attrs({ ssrc });\n            }\n            for (let j = 0; j < mline.fmt.length; j++) {\n                const rtpmap\n                    = SDPUtil.findLine(\n                        this.media[i],\n                        `a=rtpmap:${mline.fmt[j]}`);\n\n                elem.c('payload-type', SDPUtil.parseRTPMap(rtpmap));\n\n                // put any 'a=fmtp:' + mline.fmt[j] lines into <param name=foo\n                // value=bar/>\n                const afmtpline\n                    = SDPUtil.findLine(\n                        this.media[i],\n                        `a=fmtp:${mline.fmt[j]}`);\n\n                if (afmtpline) {\n                    const fmtpParameters = SDPUtil.parseFmtp(afmtpline);\n\n                    // eslint-disable-next-line max-depth\n                    for (let k = 0; k < fmtpParameters.length; k++) {\n                        elem.c('parameter', fmtpParameters[k]).up();\n                    }\n                }\n\n                // XEP-0293 -- map a=rtcp-fb\n                this.rtcpFbToJingle(i, elem, mline.fmt[j]);\n\n                elem.up();\n            }\n\n            if (ssrc) {\n                const ssrcMap = SDPUtil.parseSSRC(this.media[i]);\n\n                for (const [ availableSsrc, ssrcParameters ] of ssrcMap) {\n                    const sourceName = SDPUtil.parseSourceNameLine(ssrcParameters);\n                    const videoType = SDPUtil.parseVideoTypeLine(ssrcParameters);\n\n                    elem.c('source', {\n                        ssrc: availableSsrc,\n                        name: sourceName,\n                        videoType,\n                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\n                    });\n\n                    const msid = SDPUtil.parseMSIDAttribute(ssrcParameters);\n\n                    // eslint-disable-next-line max-depth\n                    if (msid) {\n                        elem.c('parameter');\n                        elem.attrs({ name: 'msid' });\n                        elem.attrs({ value: msid });\n                        elem.up();\n                    }\n\n                    elem.up();\n                }\n\n                // XEP-0339 handle ssrc-group attributes\n                const ssrcGroupLines\n                    = SDPUtil.findLines(this.media[i], 'a=ssrc-group:');\n\n                ssrcGroupLines.forEach(line => {\n                    const idx = line.indexOf(' ');\n                    const semantics = line.substr(0, idx).substr(13);\n                    const ssrcs = line.substr(14 + semantics.length).split(' ');\n\n                    if (ssrcs.length) {\n                        elem.c('ssrc-group', { semantics,\n                            xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });\n                        ssrcs.forEach(s => elem.c('source', { ssrc: s }).up());\n                        elem.up();\n                    }\n                });\n            }\n\n            const ridLines = SDPUtil.findLines(this.media[i], 'a=rid:');\n\n            if (ridLines.length && browser.usesRidsForSimulcast()) {\n                // Map a line which looks like \"a=rid:2 send\" to just\n                // the rid (\"2\")\n                const rids = ridLines\n                    .map(ridLine => ridLine.split(':')[1])\n                    .map(ridInfo => ridInfo.split(' ')[0]);\n\n                rids.forEach(rid => {\n                    elem.c('source', {\n                        rid,\n                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\n                    });\n                    elem.up();\n                });\n                const unifiedSimulcast\n                    = SDPUtil.findLine(this.media[i], 'a=simulcast:');\n\n                if (unifiedSimulcast) {\n                    elem.c('rid-group', {\n                        semantics: 'SIM',\n                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\n                    });\n                    rids.forEach(rid => {\n                        elem.c('source', { rid }).up();\n                    });\n                    elem.up();\n                }\n            }\n\n            if (SDPUtil.findLine(this.media[i], 'a=rtcp-mux')) {\n                elem.c('rtcp-mux').up();\n            }\n\n            // XEP-0293 -- map a=rtcp-fb:*\n            this.rtcpFbToJingle(i, elem, '*');\n\n            // XEP-0294\n            const extmapLines = SDPUtil.findLines(this.media[i], 'a=extmap:', this.session);\n\n            for (let j = 0; j < extmapLines.length; j++) {\n                const extmap = SDPUtil.parseExtmap(extmapLines[j]);\n\n                elem.c('rtp-hdrext', {\n                    xmlns: 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0',\n                    uri: extmap.uri,\n                    id: extmap.value\n                });\n\n                // eslint-disable-next-line max-depth\n                if (extmap.hasOwnProperty('direction')) {\n\n                    // eslint-disable-next-line max-depth\n                    switch (extmap.direction) {\n                    case MediaDirection.SENDONLY:\n                        elem.attrs({ senders: 'responder' });\n                        break;\n                    case MediaDirection.RECVONLY:\n                        elem.attrs({ senders: 'initiator' });\n                        break;\n                    case MediaDirection.SENDRECV:\n                        elem.attrs({ senders: 'both' });\n                        break;\n                    case MediaDirection.INACTIVE:\n                        elem.attrs({ senders: 'none' });\n                        break;\n                    }\n                }\n\n                // TODO: handle params\n                elem.up();\n            }\n\n            if (SDPUtil.findLine(this.media[i], 'a=extmap-allow-mixed', this.session)) {\n                elem.c('extmap-allow-mixed', {\n                    xmlns: 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0'\n                });\n                elem.up();\n            }\n            elem.up(); // end of description\n        }\n\n        // map ice-ufrag/pwd, dtls fingerprint, candidates\n        this.transportToJingle(i, elem);\n\n        const m = this.media[i];\n\n        if (SDPUtil.findLine(m, `a=${MediaDirection.SENDRECV}`, this.session)) {\n            elem.attrs({ senders: 'both' });\n        } else if (SDPUtil.findLine(m, `a=${MediaDirection.SENDONLY}`, this.session)) {\n            elem.attrs({ senders: 'initiator' });\n        } else if (SDPUtil.findLine(m, `a=${MediaDirection.RECVONLY}`, this.session)) {\n            elem.attrs({ senders: 'responder' });\n        } else if (SDPUtil.findLine(m, `a=${MediaDirection.INACTIVE}`, this.session)) {\n            elem.attrs({ senders: 'none' });\n        }\n\n        // Reject an m-line only when port is 0 and a=bundle-only is not present in the section.\n        // The port is automatically set to 0 when bundle-only is used.\n        if (mline.port === '0' && !SDPUtil.findLine(m, 'a=bundle-only', this.session)) {\n            // estos hack to reject an m-line\n            elem.attrs({ senders: 'rejected' });\n        }\n        elem.up(); // end of content\n    }\n    elem.up();\n\n    return elem;\n};\n\nSDP.prototype.transportToJingle = function(mediaindex, elem) {\n    elem.c('transport');\n\n    // XEP-0343 DTLS/SCTP\n    const sctpport\n        = SDPUtil.findLine(this.media[mediaindex], 'a=sctp-port:', this.session);\n    const sctpmap\n        = SDPUtil.findLine(this.media[mediaindex], 'a=sctpmap:', this.session);\n\n    if (sctpport) {\n        const sctpAttrs = SDPUtil.parseSCTPPort(sctpport);\n\n        elem.c('sctpmap', {\n            xmlns: 'urn:xmpp:jingle:transports:dtls-sctp:1',\n            number: sctpAttrs, /* SCTP port */\n            protocol: 'webrtc-datachannel' /* protocol */\n        });\n\n        // The parser currently requires streams to be present\n        elem.attrs({ streams: 0 });\n        elem.up();\n    } else if (sctpmap) {\n        const sctpAttrs = SDPUtil.parseSCTPMap(sctpmap);\n\n        elem.c('sctpmap', {\n            xmlns: 'urn:xmpp:jingle:transports:dtls-sctp:1',\n            number: sctpAttrs[0], /* SCTP port */\n            protocol: sctpAttrs[1] /* protocol */\n        });\n\n        // Optional stream count attribute\n        if (sctpAttrs.length > 2) {\n            elem.attrs({ streams: sctpAttrs[2] });\n        } else {\n            elem.attrs({ streams: 0 });\n        }\n        elem.up();\n    }\n\n    // XEP-0320\n    const fingerprints\n        = SDPUtil.findLines(\n            this.media[mediaindex],\n            'a=fingerprint:',\n            this.session);\n\n    fingerprints.forEach(line => {\n        const fingerprint = SDPUtil.parseFingerprint(line);\n\n        fingerprint.xmlns = 'urn:xmpp:jingle:apps:dtls:0';\n        elem.c('fingerprint').t(fingerprint.fingerprint);\n        delete fingerprint.fingerprint;\n\n        const setupLine\n            = SDPUtil.findLine(\n                this.media[mediaindex],\n                'a=setup:',\n                this.session);\n\n        if (setupLine) {\n            fingerprint.setup = setupLine.substr(8);\n        }\n        elem.attrs(fingerprint);\n        elem.up(); // end of fingerprint\n    });\n    const iceParameters = SDPUtil.iceparams(this.media[mediaindex], this.session);\n\n    if (iceParameters) {\n        iceParameters.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';\n        elem.attrs(iceParameters);\n\n        // XEP-0176\n        const candidateLines\n            = SDPUtil.findLines(\n                this.media[mediaindex],\n                'a=candidate:',\n                this.session);\n\n        candidateLines.forEach(line => { // add any a=candidate lines\n            const candidate = SDPUtil.candidateToJingle(line);\n\n            if (this.failICE) {\n                candidate.ip = '1.1.1.1';\n            }\n            const protocol\n                = candidate && typeof candidate.protocol === 'string'\n                    ? candidate.protocol.toLowerCase()\n                    : '';\n\n            if ((this.removeTcpCandidates\n                    && (protocol === 'tcp' || protocol === 'ssltcp'))\n                || (this.removeUdpCandidates && protocol === 'udp')) {\n                return;\n            }\n            elem.c('candidate', candidate).up();\n        });\n    }\n    elem.up(); // end of transport\n};\n\n// XEP-0293\nSDP.prototype.rtcpFbToJingle = function(mediaindex, elem, payloadtype) {\n    const lines\n        = SDPUtil.findLines(\n            this.media[mediaindex],\n            `a=rtcp-fb:${payloadtype}`);\n\n    lines.forEach(line => {\n        const feedback = SDPUtil.parseRTCPFB(line);\n\n        if (feedback.type === 'trr-int') {\n            elem.c('rtcp-fb-trr-int', {\n                xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0',\n                value: feedback.params[0]\n            });\n            elem.up();\n        } else {\n            elem.c('rtcp-fb', {\n                xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0',\n                type: feedback.type\n            });\n            if (feedback.params.length > 0) {\n                elem.attrs({ 'subtype': feedback.params[0] });\n            }\n            elem.up();\n        }\n    });\n};\n\nSDP.prototype.rtcpFbFromJingle = function(elem, payloadtype) { // XEP-0293\n    let sdp = '';\n    const feedbackElementTrrInt\n        = elem.find(\n            '>rtcp-fb-trr-int[xmlns=\"urn:xmpp:jingle:apps:rtp:rtcp-fb:0\"]');\n\n    if (feedbackElementTrrInt.length) {\n        sdp += 'a=rtcp-fb:* trr-int ';\n        if (feedbackElementTrrInt.attr('value')) {\n            sdp += feedbackElementTrrInt.attr('value');\n        } else {\n            sdp += '0';\n        }\n        sdp += '\\r\\n';\n    }\n\n    const feedbackElements = elem.find('>rtcp-fb[xmlns=\"urn:xmpp:jingle:apps:rtp:rtcp-fb:0\"]');\n\n    feedbackElements.each((_, fb) => {\n        sdp += `a=rtcp-fb:${payloadtype} ${fb.getAttribute('type')}`;\n        if (fb.hasAttribute('subtype')) {\n            sdp += ` ${fb.getAttribute('subtype')}`;\n        }\n        sdp += '\\r\\n';\n    });\n\n    return sdp;\n};\n\n// construct an SDP from a jingle stanza\nSDP.prototype.fromJingle = function(jingle) {\n    const sessionId = Date.now();\n\n    // Use a unique session id for every TPC.\n    this.raw = 'v=0\\r\\n'\n        + `o=- ${sessionId} 2 IN IP4 0.0.0.0\\r\\n`\n        + 's=-\\r\\n'\n        + 't=0 0\\r\\n';\n\n    // http://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-04\n    // #section-8\n    const groups\n        = $(jingle).find('>group[xmlns=\"urn:xmpp:jingle:apps:grouping:0\"]');\n\n    if (groups.length) {\n        groups.each((idx, group) => {\n            const contents\n                = $(group)\n                    .find('>content')\n                    .map((_, content) => content.getAttribute('name'))\n                    .get();\n\n            if (contents.length > 0) {\n                this.raw\n                    += `a=group:${\n                        group.getAttribute('semantics')\n                            || group.getAttribute('type')} ${\n                        contents.join(' ')}\\r\\n`;\n            }\n        });\n    }\n\n    this.session = this.raw;\n    jingle.find('>content').each((_, content) => {\n        const m = this.jingle2media($(content));\n\n        this.media.push(m);\n    });\n\n    // reconstruct msid-semantic -- apparently not necessary\n    /*\n     var msid = SDPUtil.parseSSRC(this.raw);\n     if (msid.hasOwnProperty('mslabel')) {\n     this.session += \"a=msid-semantic: WMS \" + msid.mslabel + \"\\r\\n\";\n     }\n     */\n\n    this.raw = this.session + this.media.join('');\n};\n\n// translate a jingle content element into an an SDP media part\nSDP.prototype.jingle2media = function(content) {\n    const desc = content.find('>description');\n    const transport = content.find('>transport[xmlns=\"urn:xmpp:jingle:transports:ice-udp:1\"]');\n    let sdp = '';\n    const sctp = transport.find(\n        '>sctpmap[xmlns=\"urn:xmpp:jingle:transports:dtls-sctp:1\"]');\n\n    const media = { media: desc.attr('media') };\n\n    media.port = '9';\n    if (content.attr('senders') === 'rejected') {\n        // estos hack to reject an m-line.\n        media.port = '0';\n    }\n    if (transport.find('>fingerprint[xmlns=\"urn:xmpp:jingle:apps:dtls:0\"]').length) {\n        media.proto = sctp.length ? 'UDP/DTLS/SCTP' : 'UDP/TLS/RTP/SAVPF';\n    } else {\n        media.proto = 'UDP/TLS/RTP/SAVPF';\n    }\n    if (sctp.length) {\n        sdp += `m=application ${media.port} UDP/DTLS/SCTP webrtc-datachannel\\r\\n`;\n        sdp += `a=sctp-port:${sctp.attr('number')}\\r\\n`;\n        sdp += 'a=max-message-size:262144\\r\\n';\n    } else {\n        media.fmt\n            = desc\n                .find('>payload-type')\n                .map((_, payloadType) => payloadType.getAttribute('id'))\n                .get();\n        sdp += `${SDPUtil.buildMLine(media)}\\r\\n`;\n    }\n\n    sdp += 'c=IN IP4 0.0.0.0\\r\\n';\n    if (!sctp.length) {\n        sdp += 'a=rtcp:1 IN IP4 0.0.0.0\\r\\n';\n    }\n\n    // XEP-0176 ICE parameters\n    if (transport.length) {\n        if (transport.attr('ufrag')) {\n            sdp += `${SDPUtil.buildICEUfrag(transport.attr('ufrag'))}\\r\\n`;\n        }\n        if (transport.attr('pwd')) {\n            sdp += `${SDPUtil.buildICEPwd(transport.attr('pwd'))}\\r\\n`;\n        }\n        transport.find('>fingerprint[xmlns=\"urn:xmpp:jingle:apps:dtls:0\"]').each((_, fingerprint) => {\n            sdp += `a=fingerprint:${fingerprint.getAttribute('hash')}`;\n            sdp += ` ${$(fingerprint).text()}`;\n            sdp += '\\r\\n';\n            if (fingerprint.hasAttribute('setup')) {\n                sdp += `a=setup:${fingerprint.getAttribute('setup')}\\r\\n`;\n            }\n        });\n    }\n\n    // XEP-0176 ICE candidates\n    transport.find('>candidate')\n        .each((_, candidate) => {\n            let protocol = candidate.getAttribute('protocol');\n\n            protocol\n                = typeof protocol === 'string' ? protocol.toLowerCase() : '';\n\n            if ((this.removeTcpCandidates\n                    && (protocol === 'tcp' || protocol === 'ssltcp'))\n                || (this.removeUdpCandidates && protocol === 'udp')) {\n                return;\n            } else if (this.failICE) {\n                candidate.setAttribute('ip', '1.1.1.1');\n            }\n\n            sdp += SDPUtil.candidateFromJingle(candidate);\n        });\n\n    switch (content.attr('senders')) {\n    case 'initiator':\n        sdp += `a=${MediaDirection.SENDONLY}\\r\\n`;\n        break;\n    case 'responder':\n        sdp += `a=${MediaDirection.RECVONLY}\\r\\n`;\n        break;\n    case 'none':\n        sdp += `a=${MediaDirection.INACTIVE}\\r\\n`;\n        break;\n    case 'both':\n        sdp += `a=${MediaDirection.SENDRECV}\\r\\n`;\n        break;\n    }\n    sdp += `a=mid:${content.attr('name')}\\r\\n`;\n\n    // <description><rtcp-mux/></description>\n    // see http://code.google.com/p/libjingle/issues/detail?id=309 -- no spec\n    // though\n    // and http://mail.jabber.org/pipermail/jingle/2011-December/001761.html\n    if (desc.find('>rtcp-mux').length) {\n        sdp += 'a=rtcp-mux\\r\\n';\n    }\n\n    desc.find('>payload-type').each((_, payloadType) => {\n        sdp += `${SDPUtil.buildRTPMap(payloadType)}\\r\\n`;\n        if ($(payloadType).find('>parameter').length) {\n            sdp += `a=fmtp:${payloadType.getAttribute('id')} `;\n            sdp\n                += $(payloadType)\n                    .find('>parameter')\n                    .map((__, parameter) => {\n                        const name = parameter.getAttribute('name');\n\n                        return (\n                            (name ? `${name}=` : '')\n                                + parameter.getAttribute('value'));\n                    })\n                    .get()\n                    .join(';');\n            sdp += '\\r\\n';\n        }\n\n        // xep-0293\n        sdp += this.rtcpFbFromJingle($(payloadType), payloadType.getAttribute('id'));\n    });\n\n    // xep-0293\n    sdp += this.rtcpFbFromJingle(desc, '*');\n\n    // xep-0294\n    desc\n        .find('>rtp-hdrext[xmlns=\"urn:xmpp:jingle:apps:rtp:rtp-hdrext:0\"]')\n        .each((_, hdrExt) => {\n            sdp\n                += `a=extmap:${hdrExt.getAttribute('id')} ${\n                    hdrExt.getAttribute('uri')}\\r\\n`;\n        });\n    if (desc.find('>extmap-allow-mixed[xmlns=\"urn:xmpp:jingle:apps:rtp:rtp-hdrext:0\"]').length > 0) {\n        sdp += 'a=extmap-allow-mixed\\r\\n';\n    }\n\n    // XEP-0339 handle ssrc-group attributes\n    desc\n        .find('>ssrc-group[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\n        .each((_, ssrcGroup) => {\n            const semantics = ssrcGroup.getAttribute('semantics');\n            const ssrcs\n                = $(ssrcGroup)\n                    .find('>source')\n                    .map((__, source) => source.getAttribute('ssrc'))\n                    .get();\n\n            if (ssrcs.length) {\n                sdp += `a=ssrc-group:${semantics} ${ssrcs.join(' ')}\\r\\n`;\n            }\n        });\n\n    // XEP-0339 handle source attributes\n    let userSources = '';\n    let nonUserSources = '';\n\n    desc\n        .find('>source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\n        .each((_, source) => {\n            const ssrc = source.getAttribute('ssrc');\n            let isUserSource = true;\n            let sourceStr = '';\n\n            $(source)\n                .find('>parameter')\n                .each((__, parameter) => {\n                    const name = parameter.getAttribute('name');\n                    let value = parameter.getAttribute('value');\n\n                    value = SDPUtil.filterSpecialChars(value);\n                    sourceStr += `a=ssrc:${ssrc} ${name}`;\n\n                    if (value && value.length) {\n                        sourceStr += `:${value}`;\n                    }\n\n                    sourceStr += '\\r\\n';\n\n                    if (value?.includes('mixedmslabel')) {\n                        isUserSource = false;\n                    }\n                });\n\n            if (isUserSource) {\n                userSources += sourceStr;\n            } else {\n                nonUserSources += sourceStr;\n            }\n        });\n\n    // The sdp-interop package is relying the mixedmslabel m line to be the first one in order to set the direction\n    // to sendrecv.\n    sdp += nonUserSources + userSources;\n\n    return sdp;\n};\n","\nimport SDPUtil from './SDPUtil';\n\n// this could be useful in Array.prototype.\n/**\n *\n * @param array1\n * @param array2\n */\nfunction arrayEquals(array1, array2) {\n    // if the other array is a falsy value, return\n    if (!array2) {\n        return false;\n    }\n\n    // compare lengths - can save a lot of time\n    if (array1.length !== array2.length) {\n        return false;\n    }\n\n    for (let i = 0, l = array1.length; i < l; i++) {\n        // Check if we have nested arrays\n        if (array1[i] instanceof Array && array2[i] instanceof Array) {\n            // recurse into the nested arrays\n            if (!array1[i].equals(array2[i])) {\n                return false;\n            }\n        } else if (array1[i] !== array2[i]) {\n            // Warning - two different object instances will never be\n            // equal: {x:20} != {x:20}\n            return false;\n        }\n    }\n\n    return true;\n}\n\n/**\n *\n * @param mySDP\n * @param otherSDP\n */\nexport default function SDPDiffer(mySDP, otherSDP) {\n    this.mySDP = mySDP;\n    this.otherSDP = otherSDP;\n    if (!mySDP) {\n        throw new Error('\"mySDP\" is undefined!');\n    } else if (!otherSDP) {\n        throw new Error('\"otherSDP\" is undefined!');\n    }\n}\n\n/**\n * Returns map of MediaChannel that contains media contained in\n * 'mySDP', but not contained in 'otherSdp'. Mapped by channel idx.\n */\nSDPDiffer.prototype.getNewMedia = function() {\n\n    const myMedias = this.mySDP.getMediaSsrcMap();\n    const othersMedias = this.otherSDP.getMediaSsrcMap();\n    const newMedia = {};\n\n    Object.keys(othersMedias).forEach(othersMediaIdx => {\n        const myMedia = myMedias[othersMediaIdx];\n        const othersMedia = othersMedias[othersMediaIdx];\n\n        if (!myMedia && othersMedia) {\n            // Add whole channel\n            newMedia[othersMediaIdx] = othersMedia;\n\n            return;\n        }\n\n        // Look for new ssrcs across the channel\n        Object.keys(othersMedia.ssrcs).forEach(ssrc => {\n            if (Object.keys(myMedia.ssrcs).indexOf(ssrc) === -1) {\n                // Allocate channel if we've found ssrc that doesn't exist in\n                // our channel\n                if (!newMedia[othersMediaIdx]) {\n                    newMedia[othersMediaIdx] = {\n                        mediaindex: othersMedia.mediaindex,\n                        mid: othersMedia.mid,\n                        ssrcs: {},\n                        ssrcGroups: []\n                    };\n                }\n                newMedia[othersMediaIdx].ssrcs[ssrc] = othersMedia.ssrcs[ssrc];\n            } else if (othersMedia.ssrcs[ssrc].lines\n                        && myMedia.ssrcs[ssrc].lines) {\n                // we want to detect just changes in adding/removing msid\n                const myContainMsid = myMedia.ssrcs[ssrc].lines.find(\n                    line => line.indexOf('msid') !== -1) !== undefined;\n                const newContainMsid = othersMedia.ssrcs[ssrc].lines.find(\n                    line => line.indexOf('msid') !== -1) !== undefined;\n\n                if (myContainMsid !== newContainMsid) {\n                    if (!newMedia[othersMediaIdx]) {\n                        newMedia[othersMediaIdx] = {\n                            mediaindex: othersMedia.mediaindex,\n                            mid: othersMedia.mid,\n                            ssrcs: {},\n                            ssrcGroups: []\n                        };\n                    }\n                    newMedia[othersMediaIdx].ssrcs[ssrc]\n                        = othersMedia.ssrcs[ssrc];\n                }\n            }\n        });\n\n        // Look for new ssrc groups across the channels\n        othersMedia.ssrcGroups.forEach(otherSsrcGroup => {\n\n            // try to match the other ssrc-group with an ssrc-group of ours\n            let matched = false;\n\n            for (let i = 0; i < myMedia.ssrcGroups.length; i++) {\n                const mySsrcGroup = myMedia.ssrcGroups[i];\n\n                if (otherSsrcGroup.semantics === mySsrcGroup.semantics\n                    && arrayEquals(otherSsrcGroup.ssrcs, mySsrcGroup.ssrcs)) {\n\n                    matched = true;\n                    break;\n                }\n            }\n\n            if (!matched) {\n                // Allocate channel if we've found an ssrc-group that doesn't\n                // exist in our channel\n\n                if (!newMedia[othersMediaIdx]) {\n                    newMedia[othersMediaIdx] = {\n                        mediaindex: othersMedia.mediaindex,\n                        mid: othersMedia.mid,\n                        ssrcs: {},\n                        ssrcGroups: []\n                    };\n                }\n                newMedia[othersMediaIdx].ssrcGroups.push(otherSsrcGroup);\n            }\n        });\n    });\n\n    return newMedia;\n};\n\n/**\n * TODO: document!\n */\nSDPDiffer.prototype.toJingle = function(modify) {\n    const sdpMediaSsrcs = this.getNewMedia();\n\n    let modified = false;\n\n    Object.keys(sdpMediaSsrcs).forEach(mediaindex => {\n        modified = true;\n        const media = sdpMediaSsrcs[mediaindex];\n\n        modify.c('content', { name: media.mid });\n\n        modify.c('description',\n            { xmlns: 'urn:xmpp:jingle:apps:rtp:1',\n                media: media.mid });\n\n        // FIXME: not completely sure this operates on blocks and / or handles\n        // different ssrcs correctly\n        // generate sources from lines\n        Object.keys(media.ssrcs).forEach(ssrcNum => {\n            const mediaSsrc = media.ssrcs[ssrcNum];\n            const ssrcLines = mediaSsrc.lines;\n            const sourceName = SDPUtil.parseSourceNameLine(ssrcLines);\n            const videoType = SDPUtil.parseVideoTypeLine(ssrcLines);\n\n            modify.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });\n            modify.attrs({\n                name: sourceName,\n                videoType,\n                ssrc: mediaSsrc.ssrc\n            });\n\n            // Only MSID attribute is sent\n            const msid = SDPUtil.parseMSIDAttribute(ssrcLines);\n\n            if (msid) {\n                modify.c('parameter');\n                modify.attrs({ name: 'msid' });\n                modify.attrs({ value: msid });\n                modify.up();\n            }\n\n            modify.up(); // end of source\n        });\n\n        // generate source groups from lines\n        media.ssrcGroups.forEach(ssrcGroup => {\n            if (ssrcGroup.ssrcs.length) {\n\n                modify.c('ssrc-group', {\n                    semantics: ssrcGroup.semantics,\n                    xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\n                });\n\n                ssrcGroup.ssrcs.forEach(ssrc => {\n                    modify.c('source', { ssrc })\n                        .up(); // end of source\n                });\n                modify.up(); // end of ssrc-group\n            }\n        });\n\n        modify.up(); // end of description\n        modify.up(); // end of content\n    });\n\n    return modified;\n};\n","/**\n * Creates a continuation function with some arguments already applied.\n *\n * Useful as a shorthand when combined with other control flow functions. Any\n * arguments passed to the returned function are added to the arguments\n * originally passed to apply.\n *\n * @name apply\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {Function} fn - The function you want to eventually apply all\n * arguments to. Invokes with (arguments...).\n * @param {...*} arguments... - Any number of arguments to automatically apply\n * when the continuation is called.\n * @returns {Function} the partially-applied function\n * @example\n *\n * // using apply\n * async.parallel([\n *     async.apply(fs.writeFile, 'testfile1', 'test1'),\n *     async.apply(fs.writeFile, 'testfile2', 'test2')\n * ]);\n *\n *\n * // the same process without using apply\n * async.parallel([\n *     function(callback) {\n *         fs.writeFile('testfile1', 'test1', callback);\n *     },\n *     function(callback) {\n *         fs.writeFile('testfile2', 'test2', callback);\n *     }\n * ]);\n *\n * // It's possible to pass any number of additional arguments when calling the\n * // continuation:\n *\n * node> var fn = async.apply(sys.puts, 'one');\n * node> fn('two', 'three');\n * one\n * two\n * three\n */\nfunction apply(fn, ...args) {\n    return (...callArgs) => fn(...args,...callArgs);\n}\n\nfunction initialParams (fn) {\n    return function (...args/*, callback*/) {\n        var callback = args.pop();\n        return fn.call(this, args, callback);\n    };\n}\n\n/* istanbul ignore file */\n\nvar hasQueueMicrotask = typeof queueMicrotask === 'function' && queueMicrotask;\nvar hasSetImmediate = typeof setImmediate === 'function' && setImmediate;\nvar hasNextTick = typeof process === 'object' && typeof process.nextTick === 'function';\n\nfunction fallback(fn) {\n    setTimeout(fn, 0);\n}\n\nfunction wrap(defer) {\n    return (fn, ...args) => defer(() => fn(...args));\n}\n\nvar _defer;\n\nif (hasQueueMicrotask) {\n    _defer = queueMicrotask;\n} else if (hasSetImmediate) {\n    _defer = setImmediate;\n} else if (hasNextTick) {\n    _defer = process.nextTick;\n} else {\n    _defer = fallback;\n}\n\nvar setImmediate$1 = wrap(_defer);\n\n/**\n * Take a sync function and make it async, passing its return value to a\n * callback. This is useful for plugging sync functions into a waterfall,\n * series, or other async functions. Any arguments passed to the generated\n * function will be passed to the wrapped function (except for the final\n * callback argument). Errors thrown will be passed to the callback.\n *\n * If the function passed to `asyncify` returns a Promise, that promises's\n * resolved/rejected state will be used to call the callback, rather than simply\n * the synchronous return value.\n *\n * This also means you can asyncify ES2017 `async` functions.\n *\n * @name asyncify\n * @static\n * @memberOf module:Utils\n * @method\n * @alias wrapSync\n * @category Util\n * @param {Function} func - The synchronous function, or Promise-returning\n * function to convert to an {@link AsyncFunction}.\n * @returns {AsyncFunction} An asynchronous wrapper of the `func`. To be\n * invoked with `(args..., callback)`.\n * @example\n *\n * // passing a regular synchronous function\n * async.waterfall([\n *     async.apply(fs.readFile, filename, \"utf8\"),\n *     async.asyncify(JSON.parse),\n *     function (data, next) {\n *         // data is the result of parsing the text.\n *         // If there was a parsing error, it would have been caught.\n *     }\n * ], callback);\n *\n * // passing a function returning a promise\n * async.waterfall([\n *     async.apply(fs.readFile, filename, \"utf8\"),\n *     async.asyncify(function (contents) {\n *         return db.model.create(contents);\n *     }),\n *     function (model, next) {\n *         // `model` is the instantiated model object.\n *         // If there was an error, this function would be skipped.\n *     }\n * ], callback);\n *\n * // es2017 example, though `asyncify` is not needed if your JS environment\n * // supports async functions out of the box\n * var q = async.queue(async.asyncify(async function(file) {\n *     var intermediateStep = await processFile(file);\n *     return await somePromise(intermediateStep)\n * }));\n *\n * q.push(files);\n */\nfunction asyncify(func) {\n    if (isAsync(func)) {\n        return function (...args/*, callback*/) {\n            const callback = args.pop();\n            const promise = func.apply(this, args);\n            return handlePromise(promise, callback)\n        }\n    }\n\n    return initialParams(function (args, callback) {\n        var result;\n        try {\n            result = func.apply(this, args);\n        } catch (e) {\n            return callback(e);\n        }\n        // if result is Promise object\n        if (result && typeof result.then === 'function') {\n            return handlePromise(result, callback)\n        } else {\n            callback(null, result);\n        }\n    });\n}\n\nfunction handlePromise(promise, callback) {\n    return promise.then(value => {\n        invokeCallback(callback, null, value);\n    }, err => {\n        invokeCallback(callback, err && err.message ? err : new Error(err));\n    });\n}\n\nfunction invokeCallback(callback, error, value) {\n    try {\n        callback(error, value);\n    } catch (err) {\n        setImmediate$1(e => { throw e }, err);\n    }\n}\n\nfunction isAsync(fn) {\n    return fn[Symbol.toStringTag] === 'AsyncFunction';\n}\n\nfunction isAsyncGenerator(fn) {\n    return fn[Symbol.toStringTag] === 'AsyncGenerator';\n}\n\nfunction isAsyncIterable(obj) {\n    return typeof obj[Symbol.asyncIterator] === 'function';\n}\n\nfunction wrapAsync(asyncFn) {\n    if (typeof asyncFn !== 'function') throw new Error('expected a function')\n    return isAsync(asyncFn) ? asyncify(asyncFn) : asyncFn;\n}\n\n// conditionally promisify a function.\n// only return a promise if a callback is omitted\nfunction awaitify (asyncFn, arity = asyncFn.length) {\n    if (!arity) throw new Error('arity is undefined')\n    function awaitable (...args) {\n        if (typeof args[arity - 1] === 'function') {\n            return asyncFn.apply(this, args)\n        }\n\n        return new Promise((resolve, reject) => {\n            args[arity - 1] = (err, ...cbArgs) => {\n                if (err) return reject(err)\n                resolve(cbArgs.length > 1 ? cbArgs : cbArgs[0]);\n            };\n            asyncFn.apply(this, args);\n        })\n    }\n\n    return awaitable\n}\n\nfunction applyEach (eachfn) {\n    return function applyEach(fns, ...callArgs) {\n        const go = awaitify(function (callback) {\n            var that = this;\n            return eachfn(fns, (fn, cb) => {\n                wrapAsync(fn).apply(that, callArgs.concat(cb));\n            }, callback);\n        });\n        return go;\n    };\n}\n\nfunction _asyncMap(eachfn, arr, iteratee, callback) {\n    arr = arr || [];\n    var results = [];\n    var counter = 0;\n    var _iteratee = wrapAsync(iteratee);\n\n    return eachfn(arr, (value, _, iterCb) => {\n        var index = counter++;\n        _iteratee(value, (err, v) => {\n            results[index] = v;\n            iterCb(err);\n        });\n    }, err => {\n        callback(err, results);\n    });\n}\n\nfunction isArrayLike(value) {\n    return value &&\n        typeof value.length === 'number' &&\n        value.length >= 0 &&\n        value.length % 1 === 0;\n}\n\n// A temporary value used to identify if the loop should be broken.\n// See #1064, #1293\nconst breakLoop = {};\n\nfunction once(fn) {\n    function wrapper (...args) {\n        if (fn === null) return;\n        var callFn = fn;\n        fn = null;\n        callFn.apply(this, args);\n    }\n    Object.assign(wrapper, fn);\n    return wrapper\n}\n\nfunction getIterator (coll) {\n    return coll[Symbol.iterator] && coll[Symbol.iterator]();\n}\n\nfunction createArrayIterator(coll) {\n    var i = -1;\n    var len = coll.length;\n    return function next() {\n        return ++i < len ? {value: coll[i], key: i} : null;\n    }\n}\n\nfunction createES2015Iterator(iterator) {\n    var i = -1;\n    return function next() {\n        var item = iterator.next();\n        if (item.done)\n            return null;\n        i++;\n        return {value: item.value, key: i};\n    }\n}\n\nfunction createObjectIterator(obj) {\n    var okeys = obj ? Object.keys(obj) : [];\n    var i = -1;\n    var len = okeys.length;\n    return function next() {\n        var key = okeys[++i];\n        if (key === '__proto__') {\n            return next();\n        }\n        return i < len ? {value: obj[key], key} : null;\n    };\n}\n\nfunction createIterator(coll) {\n    if (isArrayLike(coll)) {\n        return createArrayIterator(coll);\n    }\n\n    var iterator = getIterator(coll);\n    return iterator ? createES2015Iterator(iterator) : createObjectIterator(coll);\n}\n\nfunction onlyOnce(fn) {\n    return function (...args) {\n        if (fn === null) throw new Error(\"Callback was already called.\");\n        var callFn = fn;\n        fn = null;\n        callFn.apply(this, args);\n    };\n}\n\n// for async generators\nfunction asyncEachOfLimit(generator, limit, iteratee, callback) {\n    let done = false;\n    let canceled = false;\n    let awaiting = false;\n    let running = 0;\n    let idx = 0;\n\n    function replenish() {\n        //console.log('replenish')\n        if (running >= limit || awaiting || done) return\n        //console.log('replenish awaiting')\n        awaiting = true;\n        generator.next().then(({value, done: iterDone}) => {\n            //console.log('got value', value)\n            if (canceled || done) return\n            awaiting = false;\n            if (iterDone) {\n                done = true;\n                if (running <= 0) {\n                    //console.log('done nextCb')\n                    callback(null);\n                }\n                return;\n            }\n            running++;\n            iteratee(value, idx, iterateeCallback);\n            idx++;\n            replenish();\n        }).catch(handleError);\n    }\n\n    function iterateeCallback(err, result) {\n        //console.log('iterateeCallback')\n        running -= 1;\n        if (canceled) return\n        if (err) return handleError(err)\n\n        if (err === false) {\n            done = true;\n            canceled = true;\n            return\n        }\n\n        if (result === breakLoop || (done && running <= 0)) {\n            done = true;\n            //console.log('done iterCb')\n            return callback(null);\n        }\n        replenish();\n    }\n\n    function handleError(err) {\n        if (canceled) return\n        awaiting = false;\n        done = true;\n        callback(err);\n    }\n\n    replenish();\n}\n\nvar eachOfLimit = (limit) => {\n    return (obj, iteratee, callback) => {\n        callback = once(callback);\n        if (limit <= 0) {\n            throw new RangeError('concurrency limit cannot be less than 1')\n        }\n        if (!obj) {\n            return callback(null);\n        }\n        if (isAsyncGenerator(obj)) {\n            return asyncEachOfLimit(obj, limit, iteratee, callback)\n        }\n        if (isAsyncIterable(obj)) {\n            return asyncEachOfLimit(obj[Symbol.asyncIterator](), limit, iteratee, callback)\n        }\n        var nextElem = createIterator(obj);\n        var done = false;\n        var canceled = false;\n        var running = 0;\n        var looping = false;\n\n        function iterateeCallback(err, value) {\n            if (canceled) return\n            running -= 1;\n            if (err) {\n                done = true;\n                callback(err);\n            }\n            else if (err === false) {\n                done = true;\n                canceled = true;\n            }\n            else if (value === breakLoop || (done && running <= 0)) {\n                done = true;\n                return callback(null);\n            }\n            else if (!looping) {\n                replenish();\n            }\n        }\n\n        function replenish () {\n            looping = true;\n            while (running < limit && !done) {\n                var elem = nextElem();\n                if (elem === null) {\n                    done = true;\n                    if (running <= 0) {\n                        callback(null);\n                    }\n                    return;\n                }\n                running += 1;\n                iteratee(elem.value, elem.key, onlyOnce(iterateeCallback));\n            }\n            looping = false;\n        }\n\n        replenish();\n    };\n};\n\n/**\n * The same as [`eachOf`]{@link module:Collections.eachOf} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name eachOfLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.eachOf]{@link module:Collections.eachOf}\n * @alias forEachOfLimit\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each\n * item in `coll`. The `key` is the item's key, or index in the case of an\n * array.\n * Invoked with (item, key, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n */\nfunction eachOfLimit$1(coll, limit, iteratee, callback) {\n    return eachOfLimit(limit)(coll, wrapAsync(iteratee), callback);\n}\n\nvar eachOfLimit$2 = awaitify(eachOfLimit$1, 4);\n\n// eachOf implementation optimized for array-likes\nfunction eachOfArrayLike(coll, iteratee, callback) {\n    callback = once(callback);\n    var index = 0,\n        completed = 0,\n        {length} = coll,\n        canceled = false;\n    if (length === 0) {\n        callback(null);\n    }\n\n    function iteratorCallback(err, value) {\n        if (err === false) {\n            canceled = true;\n        }\n        if (canceled === true) return\n        if (err) {\n            callback(err);\n        } else if ((++completed === length) || value === breakLoop) {\n            callback(null);\n        }\n    }\n\n    for (; index < length; index++) {\n        iteratee(coll[index], index, onlyOnce(iteratorCallback));\n    }\n}\n\n// a generic version of eachOf which can handle array, object, and iterator cases.\nfunction eachOfGeneric (coll, iteratee, callback) {\n    return eachOfLimit$2(coll, Infinity, iteratee, callback);\n}\n\n/**\n * Like [`each`]{@link module:Collections.each}, except that it passes the key (or index) as the second argument\n * to the iteratee.\n *\n * @name eachOf\n * @static\n * @memberOf module:Collections\n * @method\n * @alias forEachOf\n * @category Collection\n * @see [async.each]{@link module:Collections.each}\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each\n * item in `coll`.\n * The `key` is the item's key, or index in the case of an array.\n * Invoked with (item, key, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n * @example\n *\n * // dev.json is a file containing a valid json object config for dev environment\n * // dev.json is a file containing a valid json object config for test environment\n * // prod.json is a file containing a valid json object config for prod environment\n * // invalid.json is a file with a malformed json object\n *\n * let configs = {}; //global variable\n * let validConfigFileMap = {dev: 'dev.json', test: 'test.json', prod: 'prod.json'};\n * let invalidConfigFileMap = {dev: 'dev.json', test: 'test.json', invalid: 'invalid.json'};\n *\n * // asynchronous function that reads a json file and parses the contents as json object\n * function parseFile(file, key, callback) {\n *     fs.readFile(file, \"utf8\", function(err, data) {\n *         if (err) return calback(err);\n *         try {\n *             configs[key] = JSON.parse(data);\n *         } catch (e) {\n *             return callback(e);\n *         }\n *         callback();\n *     });\n * }\n *\n * // Using callbacks\n * async.forEachOf(validConfigFileMap, parseFile, function (err) {\n *     if (err) {\n *         console.error(err);\n *     } else {\n *         console.log(configs);\n *         // configs is now a map of JSON data, e.g.\n *         // { dev: //parsed dev.json, test: //parsed test.json, prod: //parsed prod.json}\n *     }\n * });\n *\n * //Error handing\n * async.forEachOf(invalidConfigFileMap, parseFile, function (err) {\n *     if (err) {\n *         console.error(err);\n *         // JSON parse error exception\n *     } else {\n *         console.log(configs);\n *     }\n * });\n *\n * // Using Promises\n * async.forEachOf(validConfigFileMap, parseFile)\n * .then( () => {\n *     console.log(configs);\n *     // configs is now a map of JSON data, e.g.\n *     // { dev: //parsed dev.json, test: //parsed test.json, prod: //parsed prod.json}\n * }).catch( err => {\n *     console.error(err);\n * });\n *\n * //Error handing\n * async.forEachOf(invalidConfigFileMap, parseFile)\n * .then( () => {\n *     console.log(configs);\n * }).catch( err => {\n *     console.error(err);\n *     // JSON parse error exception\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.forEachOf(validConfigFileMap, parseFile);\n *         console.log(configs);\n *         // configs is now a map of JSON data, e.g.\n *         // { dev: //parsed dev.json, test: //parsed test.json, prod: //parsed prod.json}\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * //Error handing\n * async () => {\n *     try {\n *         let result = await async.forEachOf(invalidConfigFileMap, parseFile);\n *         console.log(configs);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // JSON parse error exception\n *     }\n * }\n *\n */\nfunction eachOf(coll, iteratee, callback) {\n    var eachOfImplementation = isArrayLike(coll) ? eachOfArrayLike : eachOfGeneric;\n    return eachOfImplementation(coll, wrapAsync(iteratee), callback);\n}\n\nvar eachOf$1 = awaitify(eachOf, 3);\n\n/**\n * Produces a new collection of values by mapping each value in `coll` through\n * the `iteratee` function. The `iteratee` is called with an item from `coll`\n * and a callback for when it has finished processing. Each of these callbacks\n * takes 2 arguments: an `error`, and the transformed item from `coll`. If\n * `iteratee` passes an error to its callback, the main `callback` (for the\n * `map` function) is immediately called with the error.\n *\n * Note, that since this function applies the `iteratee` to each item in\n * parallel, there is no guarantee that the `iteratee` functions will complete\n * in order. However, the results array will be in the same order as the\n * original `coll`.\n *\n * If `map` is passed an Object, the results will be an Array.  The results\n * will roughly be in the order of the original Objects' keys (but this can\n * vary across JavaScript engines).\n *\n * @name map\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with the transformed item.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Results is an Array of the\n * transformed items from the `coll`. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * // file1.txt is a file that is 1000 bytes in size\n * // file2.txt is a file that is 2000 bytes in size\n * // file3.txt is a file that is 3000 bytes in size\n * // file4.txt does not exist\n *\n * const fileList = ['file1.txt','file2.txt','file3.txt'];\n * const withMissingFileList = ['file1.txt','file2.txt','file4.txt'];\n *\n * // asynchronous function that returns the file size in bytes\n * function getFileSizeInBytes(file, callback) {\n *     fs.stat(file, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         callback(null, stat.size);\n *     });\n * }\n *\n * // Using callbacks\n * async.map(fileList, getFileSizeInBytes, function(err, results) {\n *     if (err) {\n *         console.log(err);\n *     } else {\n *         console.log(results);\n *         // results is now an array of the file size in bytes for each file, e.g.\n *         // [ 1000, 2000, 3000]\n *     }\n * });\n *\n * // Error Handling\n * async.map(withMissingFileList, getFileSizeInBytes, function(err, results) {\n *     if (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     } else {\n *         console.log(results);\n *     }\n * });\n *\n * // Using Promises\n * async.map(fileList, getFileSizeInBytes)\n * .then( results => {\n *     console.log(results);\n *     // results is now an array of the file size in bytes for each file, e.g.\n *     // [ 1000, 2000, 3000]\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Error Handling\n * async.map(withMissingFileList, getFileSizeInBytes)\n * .then( results => {\n *     console.log(results);\n * }).catch( err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let results = await async.map(fileList, getFileSizeInBytes);\n *         console.log(results);\n *         // results is now an array of the file size in bytes for each file, e.g.\n *         // [ 1000, 2000, 3000]\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // Error Handling\n * async () => {\n *     try {\n *         let results = await async.map(withMissingFileList, getFileSizeInBytes);\n *         console.log(results);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     }\n * }\n *\n */\nfunction map (coll, iteratee, callback) {\n    return _asyncMap(eachOf$1, coll, iteratee, callback)\n}\nvar map$1 = awaitify(map, 3);\n\n/**\n * Applies the provided arguments to each function in the array, calling\n * `callback` after all functions have completed. If you only provide the first\n * argument, `fns`, then it will return a function which lets you pass in the\n * arguments as if it were a single function call. If more arguments are\n * provided, `callback` is required while `args` is still optional. The results\n * for each of the applied async functions are passed to the final callback\n * as an array.\n *\n * @name applyEach\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} fns - A collection of {@link AsyncFunction}s\n * to all call with the same arguments\n * @param {...*} [args] - any number of separate arguments to pass to the\n * function.\n * @param {Function} [callback] - the final argument should be the callback,\n * called when all functions have completed processing.\n * @returns {AsyncFunction} - Returns a function that takes no args other than\n * an optional callback, that is the result of applying the `args` to each\n * of the functions.\n * @example\n *\n * const appliedFn = async.applyEach([enableSearch, updateSchema], 'bucket')\n *\n * appliedFn((err, results) => {\n *     // results[0] is the results for `enableSearch`\n *     // results[1] is the results for `updateSchema`\n * });\n *\n * // partial application example:\n * async.each(\n *     buckets,\n *     async (bucket) => async.applyEach([enableSearch, updateSchema], bucket)(),\n *     callback\n * );\n */\nvar applyEach$1 = applyEach(map$1);\n\n/**\n * The same as [`eachOf`]{@link module:Collections.eachOf} but runs only a single async operation at a time.\n *\n * @name eachOfSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.eachOf]{@link module:Collections.eachOf}\n * @alias forEachOfSeries\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * Invoked with (item, key, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n */\nfunction eachOfSeries(coll, iteratee, callback) {\n    return eachOfLimit$2(coll, 1, iteratee, callback)\n}\nvar eachOfSeries$1 = awaitify(eachOfSeries, 3);\n\n/**\n * The same as [`map`]{@link module:Collections.map} but runs only a single async operation at a time.\n *\n * @name mapSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.map]{@link module:Collections.map}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with the transformed item.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Results is an array of the\n * transformed items from the `coll`. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction mapSeries (coll, iteratee, callback) {\n    return _asyncMap(eachOfSeries$1, coll, iteratee, callback)\n}\nvar mapSeries$1 = awaitify(mapSeries, 3);\n\n/**\n * The same as [`applyEach`]{@link module:ControlFlow.applyEach} but runs only a single async operation at a time.\n *\n * @name applyEachSeries\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.applyEach]{@link module:ControlFlow.applyEach}\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} fns - A collection of {@link AsyncFunction}s to all\n * call with the same arguments\n * @param {...*} [args] - any number of separate arguments to pass to the\n * function.\n * @param {Function} [callback] - the final argument should be the callback,\n * called when all functions have completed processing.\n * @returns {AsyncFunction} - A function, that when called, is the result of\n * appling the `args` to the list of functions.  It takes no args, other than\n * a callback.\n */\nvar applyEachSeries = applyEach(mapSeries$1);\n\nconst PROMISE_SYMBOL = Symbol('promiseCallback');\n\nfunction promiseCallback () {\n    let resolve, reject;\n    function callback (err, ...args) {\n        if (err) return reject(err)\n        resolve(args.length > 1 ? args : args[0]);\n    }\n\n    callback[PROMISE_SYMBOL] = new Promise((res, rej) => {\n        resolve = res,\n        reject = rej;\n    });\n\n    return callback\n}\n\n/**\n * Determines the best order for running the {@link AsyncFunction}s in `tasks`, based on\n * their requirements. Each function can optionally depend on other functions\n * being completed first, and each function is run as soon as its requirements\n * are satisfied.\n *\n * If any of the {@link AsyncFunction}s pass an error to their callback, the `auto` sequence\n * will stop. Further tasks will not execute (so any other functions depending\n * on it will not run), and the main `callback` is immediately called with the\n * error.\n *\n * {@link AsyncFunction}s also receive an object containing the results of functions which\n * have completed so far as the first argument, if they have dependencies. If a\n * task function has no dependencies, it will only be passed a callback.\n *\n * @name auto\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Object} tasks - An object. Each of its properties is either a\n * function or an array of requirements, with the {@link AsyncFunction} itself the last item\n * in the array. The object's key of a property serves as the name of the task\n * defined by that property, i.e. can be used when specifying requirements for\n * other tasks. The function receives one or two arguments:\n * * a `results` object, containing the results of the previously executed\n *   functions, only passed if the task has any dependencies,\n * * a `callback(err, result)` function, which must be called when finished,\n *   passing an `error` (which can be `null`) and the result of the function's\n *   execution.\n * @param {number} [concurrency=Infinity] - An optional `integer` for\n * determining the maximum number of tasks that can be run in parallel. By\n * default, as many as possible.\n * @param {Function} [callback] - An optional callback which is called when all\n * the tasks have been completed. It receives the `err` argument if any `tasks`\n * pass an error to their callback. Results are always returned; however, if an\n * error occurs, no further `tasks` will be performed, and the results object\n * will only contain partial results. Invoked with (err, results).\n * @returns {Promise} a promise, if a callback is not passed\n * @example\n *\n * //Using Callbacks\n * async.auto({\n *     get_data: function(callback) {\n *         // async code to get some data\n *         callback(null, 'data', 'converted to array');\n *     },\n *     make_folder: function(callback) {\n *         // async code to create a directory to store a file in\n *         // this is run at the same time as getting the data\n *         callback(null, 'folder');\n *     },\n *     write_file: ['get_data', 'make_folder', function(results, callback) {\n *         // once there is some data and the directory exists,\n *         // write the data to a file in the directory\n *         callback(null, 'filename');\n *     }],\n *     email_link: ['write_file', function(results, callback) {\n *         // once the file is written let's email a link to it...\n *         callback(null, {'file':results.write_file, 'email':'user@example.com'});\n *     }]\n * }, function(err, results) {\n *     if (err) {\n *         console.log('err = ', err);\n *     }\n *     console.log('results = ', results);\n *     // results = {\n *     //     get_data: ['data', 'converted to array']\n *     //     make_folder; 'folder',\n *     //     write_file: 'filename'\n *     //     email_link: { file: 'filename', email: 'user@example.com' }\n *     // }\n * });\n *\n * //Using Promises\n * async.auto({\n *     get_data: function(callback) {\n *         console.log('in get_data');\n *         // async code to get some data\n *         callback(null, 'data', 'converted to array');\n *     },\n *     make_folder: function(callback) {\n *         console.log('in make_folder');\n *         // async code to create a directory to store a file in\n *         // this is run at the same time as getting the data\n *         callback(null, 'folder');\n *     },\n *     write_file: ['get_data', 'make_folder', function(results, callback) {\n *         // once there is some data and the directory exists,\n *         // write the data to a file in the directory\n *         callback(null, 'filename');\n *     }],\n *     email_link: ['write_file', function(results, callback) {\n *         // once the file is written let's email a link to it...\n *         callback(null, {'file':results.write_file, 'email':'user@example.com'});\n *     }]\n * }).then(results => {\n *     console.log('results = ', results);\n *     // results = {\n *     //     get_data: ['data', 'converted to array']\n *     //     make_folder; 'folder',\n *     //     write_file: 'filename'\n *     //     email_link: { file: 'filename', email: 'user@example.com' }\n *     // }\n * }).catch(err => {\n *     console.log('err = ', err);\n * });\n *\n * //Using async/await\n * async () => {\n *     try {\n *         let results = await async.auto({\n *             get_data: function(callback) {\n *                 // async code to get some data\n *                 callback(null, 'data', 'converted to array');\n *             },\n *             make_folder: function(callback) {\n *                 // async code to create a directory to store a file in\n *                 // this is run at the same time as getting the data\n *                 callback(null, 'folder');\n *             },\n *             write_file: ['get_data', 'make_folder', function(results, callback) {\n *                 // once there is some data and the directory exists,\n *                 // write the data to a file in the directory\n *                 callback(null, 'filename');\n *             }],\n *             email_link: ['write_file', function(results, callback) {\n *                 // once the file is written let's email a link to it...\n *                 callback(null, {'file':results.write_file, 'email':'user@example.com'});\n *             }]\n *         });\n *         console.log('results = ', results);\n *         // results = {\n *         //     get_data: ['data', 'converted to array']\n *         //     make_folder; 'folder',\n *         //     write_file: 'filename'\n *         //     email_link: { file: 'filename', email: 'user@example.com' }\n *         // }\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction auto(tasks, concurrency, callback) {\n    if (typeof concurrency !== 'number') {\n        // concurrency is optional, shift the args.\n        callback = concurrency;\n        concurrency = null;\n    }\n    callback = once(callback || promiseCallback());\n    var numTasks = Object.keys(tasks).length;\n    if (!numTasks) {\n        return callback(null);\n    }\n    if (!concurrency) {\n        concurrency = numTasks;\n    }\n\n    var results = {};\n    var runningTasks = 0;\n    var canceled = false;\n    var hasError = false;\n\n    var listeners = Object.create(null);\n\n    var readyTasks = [];\n\n    // for cycle detection:\n    var readyToCheck = []; // tasks that have been identified as reachable\n    // without the possibility of returning to an ancestor task\n    var uncheckedDependencies = {};\n\n    Object.keys(tasks).forEach(key => {\n        var task = tasks[key];\n        if (!Array.isArray(task)) {\n            // no dependencies\n            enqueueTask(key, [task]);\n            readyToCheck.push(key);\n            return;\n        }\n\n        var dependencies = task.slice(0, task.length - 1);\n        var remainingDependencies = dependencies.length;\n        if (remainingDependencies === 0) {\n            enqueueTask(key, task);\n            readyToCheck.push(key);\n            return;\n        }\n        uncheckedDependencies[key] = remainingDependencies;\n\n        dependencies.forEach(dependencyName => {\n            if (!tasks[dependencyName]) {\n                throw new Error('async.auto task `' + key +\n                    '` has a non-existent dependency `' +\n                    dependencyName + '` in ' +\n                    dependencies.join(', '));\n            }\n            addListener(dependencyName, () => {\n                remainingDependencies--;\n                if (remainingDependencies === 0) {\n                    enqueueTask(key, task);\n                }\n            });\n        });\n    });\n\n    checkForDeadlocks();\n    processQueue();\n\n    function enqueueTask(key, task) {\n        readyTasks.push(() => runTask(key, task));\n    }\n\n    function processQueue() {\n        if (canceled) return\n        if (readyTasks.length === 0 && runningTasks === 0) {\n            return callback(null, results);\n        }\n        while(readyTasks.length && runningTasks < concurrency) {\n            var run = readyTasks.shift();\n            run();\n        }\n\n    }\n\n    function addListener(taskName, fn) {\n        var taskListeners = listeners[taskName];\n        if (!taskListeners) {\n            taskListeners = listeners[taskName] = [];\n        }\n\n        taskListeners.push(fn);\n    }\n\n    function taskComplete(taskName) {\n        var taskListeners = listeners[taskName] || [];\n        taskListeners.forEach(fn => fn());\n        processQueue();\n    }\n\n\n    function runTask(key, task) {\n        if (hasError) return;\n\n        var taskCallback = onlyOnce((err, ...result) => {\n            runningTasks--;\n            if (err === false) {\n                canceled = true;\n                return\n            }\n            if (result.length < 2) {\n                [result] = result;\n            }\n            if (err) {\n                var safeResults = {};\n                Object.keys(results).forEach(rkey => {\n                    safeResults[rkey] = results[rkey];\n                });\n                safeResults[key] = result;\n                hasError = true;\n                listeners = Object.create(null);\n                if (canceled) return\n                callback(err, safeResults);\n            } else {\n                results[key] = result;\n                taskComplete(key);\n            }\n        });\n\n        runningTasks++;\n        var taskFn = wrapAsync(task[task.length - 1]);\n        if (task.length > 1) {\n            taskFn(results, taskCallback);\n        } else {\n            taskFn(taskCallback);\n        }\n    }\n\n    function checkForDeadlocks() {\n        // Kahn's algorithm\n        // https://en.wikipedia.org/wiki/Topological_sorting#Kahn.27s_algorithm\n        // http://connalle.blogspot.com/2013/10/topological-sortingkahn-algorithm.html\n        var currentTask;\n        var counter = 0;\n        while (readyToCheck.length) {\n            currentTask = readyToCheck.pop();\n            counter++;\n            getDependents(currentTask).forEach(dependent => {\n                if (--uncheckedDependencies[dependent] === 0) {\n                    readyToCheck.push(dependent);\n                }\n            });\n        }\n\n        if (counter !== numTasks) {\n            throw new Error(\n                'async.auto cannot execute tasks due to a recursive dependency'\n            );\n        }\n    }\n\n    function getDependents(taskName) {\n        var result = [];\n        Object.keys(tasks).forEach(key => {\n            const task = tasks[key];\n            if (Array.isArray(task) && task.indexOf(taskName) >= 0) {\n                result.push(key);\n            }\n        });\n        return result;\n    }\n\n    return callback[PROMISE_SYMBOL]\n}\n\nvar FN_ARGS = /^(?:async\\s+)?(?:function)?\\s*\\w*\\s*\\(\\s*([^)]+)\\s*\\)(?:\\s*{)/;\nvar ARROW_FN_ARGS = /^(?:async\\s+)?\\(?\\s*([^)=]+)\\s*\\)?(?:\\s*=>)/;\nvar FN_ARG_SPLIT = /,/;\nvar FN_ARG = /(=.+)?(\\s*)$/;\n\nfunction stripComments(string) {\n    let stripped = '';\n    let index = 0;\n    let endBlockComment = string.indexOf('*/');\n    while (index < string.length) {\n        if (string[index] === '/' && string[index+1] === '/') {\n            // inline comment\n            let endIndex = string.indexOf('\\n', index);\n            index = (endIndex === -1) ? string.length : endIndex;\n        } else if ((endBlockComment !== -1) && (string[index] === '/') && (string[index+1] === '*')) {\n            // block comment\n            let endIndex = string.indexOf('*/', index);\n            if (endIndex !== -1) {\n                index = endIndex + 2;\n                endBlockComment = string.indexOf('*/', index);\n            } else {\n                stripped += string[index];\n                index++;\n            }\n        } else {\n            stripped += string[index];\n            index++;\n        }\n    }\n    return stripped;\n}\n\nfunction parseParams(func) {\n    const src = stripComments(func.toString());\n    let match = src.match(FN_ARGS);\n    if (!match) {\n        match = src.match(ARROW_FN_ARGS);\n    }\n    if (!match) throw new Error('could not parse args in autoInject\\nSource:\\n' + src)\n    let [, args] = match;\n    return args\n        .replace(/\\s/g, '')\n        .split(FN_ARG_SPLIT)\n        .map((arg) => arg.replace(FN_ARG, '').trim());\n}\n\n/**\n * A dependency-injected version of the [async.auto]{@link module:ControlFlow.auto} function. Dependent\n * tasks are specified as parameters to the function, after the usual callback\n * parameter, with the parameter names matching the names of the tasks it\n * depends on. This can provide even more readable task graphs which can be\n * easier to maintain.\n *\n * If a final callback is specified, the task results are similarly injected,\n * specified as named parameters after the initial error parameter.\n *\n * The autoInject function is purely syntactic sugar and its semantics are\n * otherwise equivalent to [async.auto]{@link module:ControlFlow.auto}.\n *\n * @name autoInject\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.auto]{@link module:ControlFlow.auto}\n * @category Control Flow\n * @param {Object} tasks - An object, each of whose properties is an {@link AsyncFunction} of\n * the form 'func([dependencies...], callback). The object's key of a property\n * serves as the name of the task defined by that property, i.e. can be used\n * when specifying requirements for other tasks.\n * * The `callback` parameter is a `callback(err, result)` which must be called\n *   when finished, passing an `error` (which can be `null`) and the result of\n *   the function's execution. The remaining parameters name other tasks on\n *   which the task is dependent, and the results from those tasks are the\n *   arguments of those parameters.\n * @param {Function} [callback] - An optional callback which is called when all\n * the tasks have been completed. It receives the `err` argument if any `tasks`\n * pass an error to their callback, and a `results` object with any completed\n * task results, similar to `auto`.\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * //  The example from `auto` can be rewritten as follows:\n * async.autoInject({\n *     get_data: function(callback) {\n *         // async code to get some data\n *         callback(null, 'data', 'converted to array');\n *     },\n *     make_folder: function(callback) {\n *         // async code to create a directory to store a file in\n *         // this is run at the same time as getting the data\n *         callback(null, 'folder');\n *     },\n *     write_file: function(get_data, make_folder, callback) {\n *         // once there is some data and the directory exists,\n *         // write the data to a file in the directory\n *         callback(null, 'filename');\n *     },\n *     email_link: function(write_file, callback) {\n *         // once the file is written let's email a link to it...\n *         // write_file contains the filename returned by write_file.\n *         callback(null, {'file':write_file, 'email':'user@example.com'});\n *     }\n * }, function(err, results) {\n *     console.log('err = ', err);\n *     console.log('email_link = ', results.email_link);\n * });\n *\n * // If you are using a JS minifier that mangles parameter names, `autoInject`\n * // will not work with plain functions, since the parameter names will be\n * // collapsed to a single letter identifier.  To work around this, you can\n * // explicitly specify the names of the parameters your task function needs\n * // in an array, similar to Angular.js dependency injection.\n *\n * // This still has an advantage over plain `auto`, since the results a task\n * // depends on are still spread into arguments.\n * async.autoInject({\n *     //...\n *     write_file: ['get_data', 'make_folder', function(get_data, make_folder, callback) {\n *         callback(null, 'filename');\n *     }],\n *     email_link: ['write_file', function(write_file, callback) {\n *         callback(null, {'file':write_file, 'email':'user@example.com'});\n *     }]\n *     //...\n * }, function(err, results) {\n *     console.log('err = ', err);\n *     console.log('email_link = ', results.email_link);\n * });\n */\nfunction autoInject(tasks, callback) {\n    var newTasks = {};\n\n    Object.keys(tasks).forEach(key => {\n        var taskFn = tasks[key];\n        var params;\n        var fnIsAsync = isAsync(taskFn);\n        var hasNoDeps =\n            (!fnIsAsync && taskFn.length === 1) ||\n            (fnIsAsync && taskFn.length === 0);\n\n        if (Array.isArray(taskFn)) {\n            params = [...taskFn];\n            taskFn = params.pop();\n\n            newTasks[key] = params.concat(params.length > 0 ? newTask : taskFn);\n        } else if (hasNoDeps) {\n            // no dependencies, use the function as-is\n            newTasks[key] = taskFn;\n        } else {\n            params = parseParams(taskFn);\n            if ((taskFn.length === 0 && !fnIsAsync) && params.length === 0) {\n                throw new Error(\"autoInject task functions require explicit parameters.\");\n            }\n\n            // remove callback param\n            if (!fnIsAsync) params.pop();\n\n            newTasks[key] = params.concat(newTask);\n        }\n\n        function newTask(results, taskCb) {\n            var newArgs = params.map(name => results[name]);\n            newArgs.push(taskCb);\n            wrapAsync(taskFn)(...newArgs);\n        }\n    });\n\n    return auto(newTasks, callback);\n}\n\n// Simple doubly linked list (https://en.wikipedia.org/wiki/Doubly_linked_list) implementation\n// used for queues. This implementation assumes that the node provided by the user can be modified\n// to adjust the next and last properties. We implement only the minimal functionality\n// for queue support.\nclass DLL {\n    constructor() {\n        this.head = this.tail = null;\n        this.length = 0;\n    }\n\n    removeLink(node) {\n        if (node.prev) node.prev.next = node.next;\n        else this.head = node.next;\n        if (node.next) node.next.prev = node.prev;\n        else this.tail = node.prev;\n\n        node.prev = node.next = null;\n        this.length -= 1;\n        return node;\n    }\n\n    empty () {\n        while(this.head) this.shift();\n        return this;\n    }\n\n    insertAfter(node, newNode) {\n        newNode.prev = node;\n        newNode.next = node.next;\n        if (node.next) node.next.prev = newNode;\n        else this.tail = newNode;\n        node.next = newNode;\n        this.length += 1;\n    }\n\n    insertBefore(node, newNode) {\n        newNode.prev = node.prev;\n        newNode.next = node;\n        if (node.prev) node.prev.next = newNode;\n        else this.head = newNode;\n        node.prev = newNode;\n        this.length += 1;\n    }\n\n    unshift(node) {\n        if (this.head) this.insertBefore(this.head, node);\n        else setInitial(this, node);\n    }\n\n    push(node) {\n        if (this.tail) this.insertAfter(this.tail, node);\n        else setInitial(this, node);\n    }\n\n    shift() {\n        return this.head && this.removeLink(this.head);\n    }\n\n    pop() {\n        return this.tail && this.removeLink(this.tail);\n    }\n\n    toArray() {\n        return [...this]\n    }\n\n    *[Symbol.iterator] () {\n        var cur = this.head;\n        while (cur) {\n            yield cur.data;\n            cur = cur.next;\n        }\n    }\n\n    remove (testFn) {\n        var curr = this.head;\n        while(curr) {\n            var {next} = curr;\n            if (testFn(curr)) {\n                this.removeLink(curr);\n            }\n            curr = next;\n        }\n        return this;\n    }\n}\n\nfunction setInitial(dll, node) {\n    dll.length = 1;\n    dll.head = dll.tail = node;\n}\n\nfunction queue(worker, concurrency, payload) {\n    if (concurrency == null) {\n        concurrency = 1;\n    }\n    else if(concurrency === 0) {\n        throw new RangeError('Concurrency must not be zero');\n    }\n\n    var _worker = wrapAsync(worker);\n    var numRunning = 0;\n    var workersList = [];\n    const events = {\n        error: [],\n        drain: [],\n        saturated: [],\n        unsaturated: [],\n        empty: []\n    };\n\n    function on (event, handler) {\n        events[event].push(handler);\n    }\n\n    function once (event, handler) {\n        const handleAndRemove = (...args) => {\n            off(event, handleAndRemove);\n            handler(...args);\n        };\n        events[event].push(handleAndRemove);\n    }\n\n    function off (event, handler) {\n        if (!event) return Object.keys(events).forEach(ev => events[ev] = [])\n        if (!handler) return events[event] = []\n        events[event] = events[event].filter(ev => ev !== handler);\n    }\n\n    function trigger (event, ...args) {\n        events[event].forEach(handler => handler(...args));\n    }\n\n    var processingScheduled = false;\n    function _insert(data, insertAtFront, rejectOnError, callback) {\n        if (callback != null && typeof callback !== 'function') {\n            throw new Error('task callback must be a function');\n        }\n        q.started = true;\n\n        var res, rej;\n        function promiseCallback (err, ...args) {\n            // we don't care about the error, let the global error handler\n            // deal with it\n            if (err) return rejectOnError ? rej(err) : res()\n            if (args.length <= 1) return res(args[0])\n            res(args);\n        }\n\n        var item = {\n            data,\n            callback: rejectOnError ?\n                promiseCallback :\n                (callback || promiseCallback)\n        };\n\n        if (insertAtFront) {\n            q._tasks.unshift(item);\n        } else {\n            q._tasks.push(item);\n        }\n\n        if (!processingScheduled) {\n            processingScheduled = true;\n            setImmediate$1(() => {\n                processingScheduled = false;\n                q.process();\n            });\n        }\n\n        if (rejectOnError || !callback) {\n            return new Promise((resolve, reject) => {\n                res = resolve;\n                rej = reject;\n            })\n        }\n    }\n\n    function _createCB(tasks) {\n        return function (err, ...args) {\n            numRunning -= 1;\n\n            for (var i = 0, l = tasks.length; i < l; i++) {\n                var task = tasks[i];\n\n                var index = workersList.indexOf(task);\n                if (index === 0) {\n                    workersList.shift();\n                } else if (index > 0) {\n                    workersList.splice(index, 1);\n                }\n\n                task.callback(err, ...args);\n\n                if (err != null) {\n                    trigger('error', err, task.data);\n                }\n            }\n\n            if (numRunning <= (q.concurrency - q.buffer) ) {\n                trigger('unsaturated');\n            }\n\n            if (q.idle()) {\n                trigger('drain');\n            }\n            q.process();\n        };\n    }\n\n    function _maybeDrain(data) {\n        if (data.length === 0 && q.idle()) {\n            // call drain immediately if there are no tasks\n            setImmediate$1(() => trigger('drain'));\n            return true\n        }\n        return false\n    }\n\n    const eventMethod = (name) => (handler) => {\n        if (!handler) {\n            return new Promise((resolve, reject) => {\n                once(name, (err, data) => {\n                    if (err) return reject(err)\n                    resolve(data);\n                });\n            })\n        }\n        off(name);\n        on(name, handler);\n\n    };\n\n    var isProcessing = false;\n    var q = {\n        _tasks: new DLL(),\n        *[Symbol.iterator] () {\n            yield* q._tasks[Symbol.iterator]();\n        },\n        concurrency,\n        payload,\n        buffer: concurrency / 4,\n        started: false,\n        paused: false,\n        push (data, callback) {\n            if (Array.isArray(data)) {\n                if (_maybeDrain(data)) return\n                return data.map(datum => _insert(datum, false, false, callback))\n            }\n            return _insert(data, false, false, callback);\n        },\n        pushAsync (data, callback) {\n            if (Array.isArray(data)) {\n                if (_maybeDrain(data)) return\n                return data.map(datum => _insert(datum, false, true, callback))\n            }\n            return _insert(data, false, true, callback);\n        },\n        kill () {\n            off();\n            q._tasks.empty();\n        },\n        unshift (data, callback) {\n            if (Array.isArray(data)) {\n                if (_maybeDrain(data)) return\n                return data.map(datum => _insert(datum, true, false, callback))\n            }\n            return _insert(data, true, false, callback);\n        },\n        unshiftAsync (data, callback) {\n            if (Array.isArray(data)) {\n                if (_maybeDrain(data)) return\n                return data.map(datum => _insert(datum, true, true, callback))\n            }\n            return _insert(data, true, true, callback);\n        },\n        remove (testFn) {\n            q._tasks.remove(testFn);\n        },\n        process () {\n            // Avoid trying to start too many processing operations. This can occur\n            // when callbacks resolve synchronously (#1267).\n            if (isProcessing) {\n                return;\n            }\n            isProcessing = true;\n            while(!q.paused && numRunning < q.concurrency && q._tasks.length){\n                var tasks = [], data = [];\n                var l = q._tasks.length;\n                if (q.payload) l = Math.min(l, q.payload);\n                for (var i = 0; i < l; i++) {\n                    var node = q._tasks.shift();\n                    tasks.push(node);\n                    workersList.push(node);\n                    data.push(node.data);\n                }\n\n                numRunning += 1;\n\n                if (q._tasks.length === 0) {\n                    trigger('empty');\n                }\n\n                if (numRunning === q.concurrency) {\n                    trigger('saturated');\n                }\n\n                var cb = onlyOnce(_createCB(tasks));\n                _worker(data, cb);\n            }\n            isProcessing = false;\n        },\n        length () {\n            return q._tasks.length;\n        },\n        running () {\n            return numRunning;\n        },\n        workersList () {\n            return workersList;\n        },\n        idle() {\n            return q._tasks.length + numRunning === 0;\n        },\n        pause () {\n            q.paused = true;\n        },\n        resume () {\n            if (q.paused === false) { return; }\n            q.paused = false;\n            setImmediate$1(q.process);\n        }\n    };\n    // define these as fixed properties, so people get useful errors when updating\n    Object.defineProperties(q, {\n        saturated: {\n            writable: false,\n            value: eventMethod('saturated')\n        },\n        unsaturated: {\n            writable: false,\n            value: eventMethod('unsaturated')\n        },\n        empty: {\n            writable: false,\n            value: eventMethod('empty')\n        },\n        drain: {\n            writable: false,\n            value: eventMethod('drain')\n        },\n        error: {\n            writable: false,\n            value: eventMethod('error')\n        },\n    });\n    return q;\n}\n\n/**\n * Creates a `cargo` object with the specified payload. Tasks added to the\n * cargo will be processed altogether (up to the `payload` limit). If the\n * `worker` is in progress, the task is queued until it becomes available. Once\n * the `worker` has completed some tasks, each callback of those tasks is\n * called. Check out [these](https://camo.githubusercontent.com/6bbd36f4cf5b35a0f11a96dcd2e97711ffc2fb37/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130382f62626330636662302d356632392d313165322d393734662d3333393763363464633835382e676966) [animations](https://camo.githubusercontent.com/f4810e00e1c5f5f8addbe3e9f49064fd5d102699/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130312f38346339323036362d356632392d313165322d383134662d3964336430323431336266642e676966)\n * for how `cargo` and `queue` work.\n *\n * While [`queue`]{@link module:ControlFlow.queue} passes only one task to one of a group of workers\n * at a time, cargo passes an array of tasks to a single worker, repeating\n * when the worker is finished.\n *\n * @name cargo\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.queue]{@link module:ControlFlow.queue}\n * @category Control Flow\n * @param {AsyncFunction} worker - An asynchronous function for processing an array\n * of queued tasks. Invoked with `(tasks, callback)`.\n * @param {number} [payload=Infinity] - An optional `integer` for determining\n * how many tasks should be processed per round; if omitted, the default is\n * unlimited.\n * @returns {module:ControlFlow.QueueObject} A cargo object to manage the tasks. Callbacks can\n * attached as certain properties to listen for specific events during the\n * lifecycle of the cargo and inner queue.\n * @example\n *\n * // create a cargo object with payload 2\n * var cargo = async.cargo(function(tasks, callback) {\n *     for (var i=0; i<tasks.length; i++) {\n *         console.log('hello ' + tasks[i].name);\n *     }\n *     callback();\n * }, 2);\n *\n * // add some items\n * cargo.push({name: 'foo'}, function(err) {\n *     console.log('finished processing foo');\n * });\n * cargo.push({name: 'bar'}, function(err) {\n *     console.log('finished processing bar');\n * });\n * await cargo.push({name: 'baz'});\n * console.log('finished processing baz');\n */\nfunction cargo(worker, payload) {\n    return queue(worker, 1, payload);\n}\n\n/**\n * Creates a `cargoQueue` object with the specified payload. Tasks added to the\n * cargoQueue will be processed together (up to the `payload` limit) in `concurrency` parallel workers.\n * If the all `workers` are in progress, the task is queued until one becomes available. Once\n * a `worker` has completed some tasks, each callback of those tasks is\n * called. Check out [these](https://camo.githubusercontent.com/6bbd36f4cf5b35a0f11a96dcd2e97711ffc2fb37/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130382f62626330636662302d356632392d313165322d393734662d3333393763363464633835382e676966) [animations](https://camo.githubusercontent.com/f4810e00e1c5f5f8addbe3e9f49064fd5d102699/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130312f38346339323036362d356632392d313165322d383134662d3964336430323431336266642e676966)\n * for how `cargo` and `queue` work.\n *\n * While [`queue`]{@link module:ControlFlow.queue} passes only one task to one of a group of workers\n * at a time, and [`cargo`]{@link module:ControlFlow.cargo} passes an array of tasks to a single worker,\n * the cargoQueue passes an array of tasks to multiple parallel workers.\n *\n * @name cargoQueue\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.queue]{@link module:ControlFlow.queue}\n * @see [async.cargo]{@link module:ControlFLow.cargo}\n * @category Control Flow\n * @param {AsyncFunction} worker - An asynchronous function for processing an array\n * of queued tasks. Invoked with `(tasks, callback)`.\n * @param {number} [concurrency=1] - An `integer` for determining how many\n * `worker` functions should be run in parallel.  If omitted, the concurrency\n * defaults to `1`.  If the concurrency is `0`, an error is thrown.\n * @param {number} [payload=Infinity] - An optional `integer` for determining\n * how many tasks should be processed per round; if omitted, the default is\n * unlimited.\n * @returns {module:ControlFlow.QueueObject} A cargoQueue object to manage the tasks. Callbacks can\n * attached as certain properties to listen for specific events during the\n * lifecycle of the cargoQueue and inner queue.\n * @example\n *\n * // create a cargoQueue object with payload 2 and concurrency 2\n * var cargoQueue = async.cargoQueue(function(tasks, callback) {\n *     for (var i=0; i<tasks.length; i++) {\n *         console.log('hello ' + tasks[i].name);\n *     }\n *     callback();\n * }, 2, 2);\n *\n * // add some items\n * cargoQueue.push({name: 'foo'}, function(err) {\n *     console.log('finished processing foo');\n * });\n * cargoQueue.push({name: 'bar'}, function(err) {\n *     console.log('finished processing bar');\n * });\n * cargoQueue.push({name: 'baz'}, function(err) {\n *     console.log('finished processing baz');\n * });\n * cargoQueue.push({name: 'boo'}, function(err) {\n *     console.log('finished processing boo');\n * });\n */\nfunction cargo$1(worker, concurrency, payload) {\n    return queue(worker, concurrency, payload);\n}\n\n/**\n * Reduces `coll` into a single value using an async `iteratee` to return each\n * successive step. `memo` is the initial state of the reduction. This function\n * only operates in series.\n *\n * For performance reasons, it may make sense to split a call to this function\n * into a parallel map, and then use the normal `Array.prototype.reduce` on the\n * results. This function is for situations where each step in the reduction\n * needs to be async; if you can get the data before reducing it, then it's\n * probably a good idea to do so.\n *\n * @name reduce\n * @static\n * @memberOf module:Collections\n * @method\n * @alias inject\n * @alias foldl\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {*} memo - The initial state of the reduction.\n * @param {AsyncFunction} iteratee - A function applied to each item in the\n * array to produce the next step in the reduction.\n * The `iteratee` should complete with the next state of the reduction.\n * If the iteratee completes with an error, the reduction is stopped and the\n * main `callback` is immediately called with the error.\n * Invoked with (memo, item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result is the reduced value. Invoked with\n * (err, result).\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * // file1.txt is a file that is 1000 bytes in size\n * // file2.txt is a file that is 2000 bytes in size\n * // file3.txt is a file that is 3000 bytes in size\n * // file4.txt does not exist\n *\n * const fileList = ['file1.txt','file2.txt','file3.txt'];\n * const withMissingFileList = ['file1.txt','file2.txt','file3.txt', 'file4.txt'];\n *\n * // asynchronous function that computes the file size in bytes\n * // file size is added to the memoized value, then returned\n * function getFileSizeInBytes(memo, file, callback) {\n *     fs.stat(file, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         callback(null, memo + stat.size);\n *     });\n * }\n *\n * // Using callbacks\n * async.reduce(fileList, 0, getFileSizeInBytes, function(err, result) {\n *     if (err) {\n *         console.log(err);\n *     } else {\n *         console.log(result);\n *         // 6000\n *         // which is the sum of the file sizes of the three files\n *     }\n * });\n *\n * // Error Handling\n * async.reduce(withMissingFileList, 0, getFileSizeInBytes, function(err, result) {\n *     if (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     } else {\n *         console.log(result);\n *     }\n * });\n *\n * // Using Promises\n * async.reduce(fileList, 0, getFileSizeInBytes)\n * .then( result => {\n *     console.log(result);\n *     // 6000\n *     // which is the sum of the file sizes of the three files\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Error Handling\n * async.reduce(withMissingFileList, 0, getFileSizeInBytes)\n * .then( result => {\n *     console.log(result);\n * }).catch( err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.reduce(fileList, 0, getFileSizeInBytes);\n *         console.log(result);\n *         // 6000\n *         // which is the sum of the file sizes of the three files\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // Error Handling\n * async () => {\n *     try {\n *         let result = await async.reduce(withMissingFileList, 0, getFileSizeInBytes);\n *         console.log(result);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     }\n * }\n *\n */\nfunction reduce(coll, memo, iteratee, callback) {\n    callback = once(callback);\n    var _iteratee = wrapAsync(iteratee);\n    return eachOfSeries$1(coll, (x, i, iterCb) => {\n        _iteratee(memo, x, (err, v) => {\n            memo = v;\n            iterCb(err);\n        });\n    }, err => callback(err, memo));\n}\nvar reduce$1 = awaitify(reduce, 4);\n\n/**\n * Version of the compose function that is more natural to read. Each function\n * consumes the return value of the previous function. It is the equivalent of\n * [compose]{@link module:ControlFlow.compose} with the arguments reversed.\n *\n * Each function is executed with the `this` binding of the composed function.\n *\n * @name seq\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.compose]{@link module:ControlFlow.compose}\n * @category Control Flow\n * @param {...AsyncFunction} functions - the asynchronous functions to compose\n * @returns {Function} a function that composes the `functions` in order\n * @example\n *\n * // Requires lodash (or underscore), express3 and dresende's orm2.\n * // Part of an app, that fetches cats of the logged user.\n * // This example uses `seq` function to avoid overnesting and error\n * // handling clutter.\n * app.get('/cats', function(request, response) {\n *     var User = request.models.User;\n *     async.seq(\n *         User.get.bind(User),  // 'User.get' has signature (id, callback(err, data))\n *         function(user, fn) {\n *             user.getCats(fn);      // 'getCats' has signature (callback(err, data))\n *         }\n *     )(req.session.user_id, function (err, cats) {\n *         if (err) {\n *             console.error(err);\n *             response.json({ status: 'error', message: err.message });\n *         } else {\n *             response.json({ status: 'ok', message: 'Cats found', data: cats });\n *         }\n *     });\n * });\n */\nfunction seq(...functions) {\n    var _functions = functions.map(wrapAsync);\n    return function (...args) {\n        var that = this;\n\n        var cb = args[args.length - 1];\n        if (typeof cb == 'function') {\n            args.pop();\n        } else {\n            cb = promiseCallback();\n        }\n\n        reduce$1(_functions, args, (newargs, fn, iterCb) => {\n            fn.apply(that, newargs.concat((err, ...nextargs) => {\n                iterCb(err, nextargs);\n            }));\n        },\n        (err, results) => cb(err, ...results));\n\n        return cb[PROMISE_SYMBOL]\n    };\n}\n\n/**\n * Creates a function which is a composition of the passed asynchronous\n * functions. Each function consumes the return value of the function that\n * follows. Composing functions `f()`, `g()`, and `h()` would produce the result\n * of `f(g(h()))`, only this version uses callbacks to obtain the return values.\n *\n * If the last argument to the composed function is not a function, a promise\n * is returned when you call it.\n *\n * Each function is executed with the `this` binding of the composed function.\n *\n * @name compose\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {...AsyncFunction} functions - the asynchronous functions to compose\n * @returns {Function} an asynchronous function that is the composed\n * asynchronous `functions`\n * @example\n *\n * function add1(n, callback) {\n *     setTimeout(function () {\n *         callback(null, n + 1);\n *     }, 10);\n * }\n *\n * function mul3(n, callback) {\n *     setTimeout(function () {\n *         callback(null, n * 3);\n *     }, 10);\n * }\n *\n * var add1mul3 = async.compose(mul3, add1);\n * add1mul3(4, function (err, result) {\n *     // result now equals 15\n * });\n */\nfunction compose(...args) {\n    return seq(...args.reverse());\n}\n\n/**\n * The same as [`map`]{@link module:Collections.map} but runs a maximum of `limit` async operations at a time.\n *\n * @name mapLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.map]{@link module:Collections.map}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with the transformed item.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Results is an array of the\n * transformed items from the `coll`. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction mapLimit (coll, limit, iteratee, callback) {\n    return _asyncMap(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar mapLimit$1 = awaitify(mapLimit, 4);\n\n/**\n * The same as [`concat`]{@link module:Collections.concat} but runs a maximum of `limit` async operations at a time.\n *\n * @name concatLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.concat]{@link module:Collections.concat}\n * @category Collection\n * @alias flatMapLimit\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - A function to apply to each item in `coll`,\n * which should use an array as its result. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished, or an error occurs. Results is an array\n * containing the concatenated results of the `iteratee` function. Invoked with\n * (err, results).\n * @returns A Promise, if no callback is passed\n */\nfunction concatLimit(coll, limit, iteratee, callback) {\n    var _iteratee = wrapAsync(iteratee);\n    return mapLimit$1(coll, limit, (val, iterCb) => {\n        _iteratee(val, (err, ...args) => {\n            if (err) return iterCb(err);\n            return iterCb(err, args);\n        });\n    }, (err, mapResults) => {\n        var result = [];\n        for (var i = 0; i < mapResults.length; i++) {\n            if (mapResults[i]) {\n                result = result.concat(...mapResults[i]);\n            }\n        }\n\n        return callback(err, result);\n    });\n}\nvar concatLimit$1 = awaitify(concatLimit, 4);\n\n/**\n * Applies `iteratee` to each item in `coll`, concatenating the results. Returns\n * the concatenated list. The `iteratee`s are called in parallel, and the\n * results are concatenated as they return. The results array will be returned in\n * the original order of `coll` passed to the `iteratee` function.\n *\n * @name concat\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @alias flatMap\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each item in `coll`,\n * which should use an array as its result. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished, or an error occurs. Results is an array\n * containing the concatenated results of the `iteratee` function. Invoked with\n * (err, results).\n * @returns A Promise, if no callback is passed\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n * // dir4 does not exist\n *\n * let directoryList = ['dir1','dir2','dir3'];\n * let withMissingDirectoryList = ['dir1','dir2','dir3', 'dir4'];\n *\n * // Using callbacks\n * async.concat(directoryList, fs.readdir, function(err, results) {\n *    if (err) {\n *        console.log(err);\n *    } else {\n *        console.log(results);\n *        // [ 'file1.txt', 'file2.txt', 'file3.txt', 'file4.txt', file5.txt ]\n *    }\n * });\n *\n * // Error Handling\n * async.concat(withMissingDirectoryList, fs.readdir, function(err, results) {\n *    if (err) {\n *        console.log(err);\n *        // [ Error: ENOENT: no such file or directory ]\n *        // since dir4 does not exist\n *    } else {\n *        console.log(results);\n *    }\n * });\n *\n * // Using Promises\n * async.concat(directoryList, fs.readdir)\n * .then(results => {\n *     console.log(results);\n *     // [ 'file1.txt', 'file2.txt', 'file3.txt', 'file4.txt', file5.txt ]\n * }).catch(err => {\n *      console.log(err);\n * });\n *\n * // Error Handling\n * async.concat(withMissingDirectoryList, fs.readdir)\n * .then(results => {\n *     console.log(results);\n * }).catch(err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n *     // since dir4 does not exist\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let results = await async.concat(directoryList, fs.readdir);\n *         console.log(results);\n *         // [ 'file1.txt', 'file2.txt', 'file3.txt', 'file4.txt', file5.txt ]\n *     } catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // Error Handling\n * async () => {\n *     try {\n *         let results = await async.concat(withMissingDirectoryList, fs.readdir);\n *         console.log(results);\n *     } catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *         // since dir4 does not exist\n *     }\n * }\n *\n */\nfunction concat(coll, iteratee, callback) {\n    return concatLimit$1(coll, Infinity, iteratee, callback)\n}\nvar concat$1 = awaitify(concat, 3);\n\n/**\n * The same as [`concat`]{@link module:Collections.concat} but runs only a single async operation at a time.\n *\n * @name concatSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.concat]{@link module:Collections.concat}\n * @category Collection\n * @alias flatMapSeries\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each item in `coll`.\n * The iteratee should complete with an array an array of results.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished, or an error occurs. Results is an array\n * containing the concatenated results of the `iteratee` function. Invoked with\n * (err, results).\n * @returns A Promise, if no callback is passed\n */\nfunction concatSeries(coll, iteratee, callback) {\n    return concatLimit$1(coll, 1, iteratee, callback)\n}\nvar concatSeries$1 = awaitify(concatSeries, 3);\n\n/**\n * Returns a function that when called, calls-back with the values provided.\n * Useful as the first function in a [`waterfall`]{@link module:ControlFlow.waterfall}, or for plugging values in to\n * [`auto`]{@link module:ControlFlow.auto}.\n *\n * @name constant\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {...*} arguments... - Any number of arguments to automatically invoke\n * callback with.\n * @returns {AsyncFunction} Returns a function that when invoked, automatically\n * invokes the callback with the previous given arguments.\n * @example\n *\n * async.waterfall([\n *     async.constant(42),\n *     function (value, next) {\n *         // value === 42\n *     },\n *     //...\n * ], callback);\n *\n * async.waterfall([\n *     async.constant(filename, \"utf8\"),\n *     fs.readFile,\n *     function (fileData, next) {\n *         //...\n *     }\n *     //...\n * ], callback);\n *\n * async.auto({\n *     hostname: async.constant(\"https://server.net/\"),\n *     port: findFreePort,\n *     launchServer: [\"hostname\", \"port\", function (options, cb) {\n *         startServer(options, cb);\n *     }],\n *     //...\n * }, callback);\n */\nfunction constant(...args) {\n    return function (...ignoredArgs/*, callback*/) {\n        var callback = ignoredArgs.pop();\n        return callback(null, ...args);\n    };\n}\n\nfunction _createTester(check, getResult) {\n    return (eachfn, arr, _iteratee, cb) => {\n        var testPassed = false;\n        var testResult;\n        const iteratee = wrapAsync(_iteratee);\n        eachfn(arr, (value, _, callback) => {\n            iteratee(value, (err, result) => {\n                if (err || err === false) return callback(err);\n\n                if (check(result) && !testResult) {\n                    testPassed = true;\n                    testResult = getResult(true, value);\n                    return callback(null, breakLoop);\n                }\n                callback();\n            });\n        }, err => {\n            if (err) return cb(err);\n            cb(null, testPassed ? testResult : getResult(false));\n        });\n    };\n}\n\n/**\n * Returns the first value in `coll` that passes an async truth test. The\n * `iteratee` is applied in parallel, meaning the first iteratee to return\n * `true` will fire the detect `callback` with that result. That means the\n * result might not be the first item in the original `coll` (in terms of order)\n * that passes the test.\n\n * If order within the original `coll` is important, then look at\n * [`detectSeries`]{@link module:Collections.detectSeries}.\n *\n * @name detect\n * @static\n * @memberOf module:Collections\n * @method\n * @alias find\n * @category Collections\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.\n * The iteratee must complete with a boolean value as its result.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the `iteratee` functions have finished.\n * Result will be the first item in the array that passes the truth test\n * (iteratee) or the value `undefined` if none passed. Invoked with\n * (err, result).\n * @returns A Promise, if no callback is passed\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n *\n * // asynchronous function that checks if a file exists\n * function fileExists(file, callback) {\n *    fs.access(file, fs.constants.F_OK, (err) => {\n *        callback(null, !err);\n *    });\n * }\n *\n * async.detect(['file3.txt','file2.txt','dir1/file1.txt'], fileExists,\n *    function(err, result) {\n *        console.log(result);\n *        // dir1/file1.txt\n *        // result now equals the first file in the list that exists\n *    }\n *);\n *\n * // Using Promises\n * async.detect(['file3.txt','file2.txt','dir1/file1.txt'], fileExists)\n * .then(result => {\n *     console.log(result);\n *     // dir1/file1.txt\n *     // result now equals the first file in the list that exists\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.detect(['file3.txt','file2.txt','dir1/file1.txt'], fileExists);\n *         console.log(result);\n *         // dir1/file1.txt\n *         // result now equals the file in the list that exists\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction detect(coll, iteratee, callback) {\n    return _createTester(bool => bool, (res, item) => item)(eachOf$1, coll, iteratee, callback)\n}\nvar detect$1 = awaitify(detect, 3);\n\n/**\n * The same as [`detect`]{@link module:Collections.detect} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name detectLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.detect]{@link module:Collections.detect}\n * @alias findLimit\n * @category Collections\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.\n * The iteratee must complete with a boolean value as its result.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the `iteratee` functions have finished.\n * Result will be the first item in the array that passes the truth test\n * (iteratee) or the value `undefined` if none passed. Invoked with\n * (err, result).\n * @returns a Promise if no callback is passed\n */\nfunction detectLimit(coll, limit, iteratee, callback) {\n    return _createTester(bool => bool, (res, item) => item)(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar detectLimit$1 = awaitify(detectLimit, 4);\n\n/**\n * The same as [`detect`]{@link module:Collections.detect} but runs only a single async operation at a time.\n *\n * @name detectSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.detect]{@link module:Collections.detect}\n * @alias findSeries\n * @category Collections\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.\n * The iteratee must complete with a boolean value as its result.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the `iteratee` functions have finished.\n * Result will be the first item in the array that passes the truth test\n * (iteratee) or the value `undefined` if none passed. Invoked with\n * (err, result).\n * @returns a Promise if no callback is passed\n */\nfunction detectSeries(coll, iteratee, callback) {\n    return _createTester(bool => bool, (res, item) => item)(eachOfLimit(1), coll, iteratee, callback)\n}\n\nvar detectSeries$1 = awaitify(detectSeries, 3);\n\nfunction consoleFunc(name) {\n    return (fn, ...args) => wrapAsync(fn)(...args, (err, ...resultArgs) => {\n        /* istanbul ignore else */\n        if (typeof console === 'object') {\n            /* istanbul ignore else */\n            if (err) {\n                /* istanbul ignore else */\n                if (console.error) {\n                    console.error(err);\n                }\n            } else if (console[name]) { /* istanbul ignore else */\n                resultArgs.forEach(x => console[name](x));\n            }\n        }\n    })\n}\n\n/**\n * Logs the result of an [`async` function]{@link AsyncFunction} to the\n * `console` using `console.dir` to display the properties of the resulting object.\n * Only works in Node.js or in browsers that support `console.dir` and\n * `console.error` (such as FF and Chrome).\n * If multiple arguments are returned from the async function,\n * `console.dir` is called on each argument in order.\n *\n * @name dir\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} function - The function you want to eventually apply\n * all arguments to.\n * @param {...*} arguments... - Any number of arguments to apply to the function.\n * @example\n *\n * // in a module\n * var hello = function(name, callback) {\n *     setTimeout(function() {\n *         callback(null, {hello: name});\n *     }, 1000);\n * };\n *\n * // in the node repl\n * node> async.dir(hello, 'world');\n * {hello: 'world'}\n */\nvar dir = consoleFunc('dir');\n\n/**\n * The post-check version of [`whilst`]{@link module:ControlFlow.whilst}. To reflect the difference in\n * the order of operations, the arguments `test` and `iteratee` are switched.\n *\n * `doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.\n *\n * @name doWhilst\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.whilst]{@link module:ControlFlow.whilst}\n * @category Control Flow\n * @param {AsyncFunction} iteratee - A function which is called each time `test`\n * passes. Invoked with (callback).\n * @param {AsyncFunction} test - asynchronous truth test to perform after each\n * execution of `iteratee`. Invoked with (...args, callback), where `...args` are the\n * non-error args from the previous callback of `iteratee`.\n * @param {Function} [callback] - A callback which is called after the test\n * function has failed and repeated execution of `iteratee` has stopped.\n * `callback` will be passed an error and any arguments passed to the final\n * `iteratee`'s callback. Invoked with (err, [results]);\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction doWhilst(iteratee, test, callback) {\n    callback = onlyOnce(callback);\n    var _fn = wrapAsync(iteratee);\n    var _test = wrapAsync(test);\n    var results;\n\n    function next(err, ...args) {\n        if (err) return callback(err);\n        if (err === false) return;\n        results = args;\n        _test(...args, check);\n    }\n\n    function check(err, truth) {\n        if (err) return callback(err);\n        if (err === false) return;\n        if (!truth) return callback(null, ...results);\n        _fn(next);\n    }\n\n    return check(null, true);\n}\n\nvar doWhilst$1 = awaitify(doWhilst, 3);\n\n/**\n * Like ['doWhilst']{@link module:ControlFlow.doWhilst}, except the `test` is inverted. Note the\n * argument ordering differs from `until`.\n *\n * @name doUntil\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.doWhilst]{@link module:ControlFlow.doWhilst}\n * @category Control Flow\n * @param {AsyncFunction} iteratee - An async function which is called each time\n * `test` fails. Invoked with (callback).\n * @param {AsyncFunction} test - asynchronous truth test to perform after each\n * execution of `iteratee`. Invoked with (...args, callback), where `...args` are the\n * non-error args from the previous callback of `iteratee`\n * @param {Function} [callback] - A callback which is called after the test\n * function has passed and repeated execution of `iteratee` has stopped. `callback`\n * will be passed an error and any arguments passed to the final `iteratee`'s\n * callback. Invoked with (err, [results]);\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction doUntil(iteratee, test, callback) {\n    const _test = wrapAsync(test);\n    return doWhilst$1(iteratee, (...args) => {\n        const cb = args.pop();\n        _test(...args, (err, truth) => cb (err, !truth));\n    }, callback);\n}\n\nfunction _withoutIndex(iteratee) {\n    return (value, index, callback) => iteratee(value, callback);\n}\n\n/**\n * Applies the function `iteratee` to each item in `coll`, in parallel.\n * The `iteratee` is called with an item from the list, and a callback for when\n * it has finished. If the `iteratee` passes an error to its `callback`, the\n * main `callback` (for the `each` function) is immediately called with the\n * error.\n *\n * Note, that since this function applies `iteratee` to each item in parallel,\n * there is no guarantee that the iteratee functions will complete in order.\n *\n * @name each\n * @static\n * @memberOf module:Collections\n * @method\n * @alias forEach\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to\n * each item in `coll`. Invoked with (item, callback).\n * The array index is not passed to the iteratee.\n * If you need the index, use `eachOf`.\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n * // dir4 does not exist\n *\n * const fileList = [ 'dir1/file2.txt', 'dir2/file3.txt', 'dir/file5.txt'];\n * const withMissingFileList = ['dir1/file1.txt', 'dir4/file2.txt'];\n *\n * // asynchronous function that deletes a file\n * const deleteFile = function(file, callback) {\n *     fs.unlink(file, callback);\n * };\n *\n * // Using callbacks\n * async.each(fileList, deleteFile, function(err) {\n *     if( err ) {\n *         console.log(err);\n *     } else {\n *         console.log('All files have been deleted successfully');\n *     }\n * });\n *\n * // Error Handling\n * async.each(withMissingFileList, deleteFile, function(err){\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n *     // since dir4/file2.txt does not exist\n *     // dir1/file1.txt could have been deleted\n * });\n *\n * // Using Promises\n * async.each(fileList, deleteFile)\n * .then( () => {\n *     console.log('All files have been deleted successfully');\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Error Handling\n * async.each(fileList, deleteFile)\n * .then( () => {\n *     console.log('All files have been deleted successfully');\n * }).catch( err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n *     // since dir4/file2.txt does not exist\n *     // dir1/file1.txt could have been deleted\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         await async.each(files, deleteFile);\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // Error Handling\n * async () => {\n *     try {\n *         await async.each(withMissingFileList, deleteFile);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *         // since dir4/file2.txt does not exist\n *         // dir1/file1.txt could have been deleted\n *     }\n * }\n *\n */\nfunction eachLimit(coll, iteratee, callback) {\n    return eachOf$1(coll, _withoutIndex(wrapAsync(iteratee)), callback);\n}\n\nvar each = awaitify(eachLimit, 3);\n\n/**\n * The same as [`each`]{@link module:Collections.each} but runs a maximum of `limit` async operations at a time.\n *\n * @name eachLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.each]{@link module:Collections.each}\n * @alias forEachLimit\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The array index is not passed to the iteratee.\n * If you need the index, use `eachOfLimit`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n */\nfunction eachLimit$1(coll, limit, iteratee, callback) {\n    return eachOfLimit(limit)(coll, _withoutIndex(wrapAsync(iteratee)), callback);\n}\nvar eachLimit$2 = awaitify(eachLimit$1, 4);\n\n/**\n * The same as [`each`]{@link module:Collections.each} but runs only a single async operation at a time.\n *\n * Note, that unlike [`each`]{@link module:Collections.each}, this function applies iteratee to each item\n * in series and therefore the iteratee functions will complete in order.\n\n * @name eachSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.each]{@link module:Collections.each}\n * @alias forEachSeries\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each\n * item in `coll`.\n * The array index is not passed to the iteratee.\n * If you need the index, use `eachOfSeries`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n */\nfunction eachSeries(coll, iteratee, callback) {\n    return eachLimit$2(coll, 1, iteratee, callback)\n}\nvar eachSeries$1 = awaitify(eachSeries, 3);\n\n/**\n * Wrap an async function and ensure it calls its callback on a later tick of\n * the event loop.  If the function already calls its callback on a next tick,\n * no extra deferral is added. This is useful for preventing stack overflows\n * (`RangeError: Maximum call stack size exceeded`) and generally keeping\n * [Zalgo](http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony)\n * contained. ES2017 `async` functions are returned as-is -- they are immune\n * to Zalgo's corrupting influences, as they always resolve on a later tick.\n *\n * @name ensureAsync\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} fn - an async function, one that expects a node-style\n * callback as its last argument.\n * @returns {AsyncFunction} Returns a wrapped function with the exact same call\n * signature as the function passed in.\n * @example\n *\n * function sometimesAsync(arg, callback) {\n *     if (cache[arg]) {\n *         return callback(null, cache[arg]); // this would be synchronous!!\n *     } else {\n *         doSomeIO(arg, callback); // this IO would be asynchronous\n *     }\n * }\n *\n * // this has a risk of stack overflows if many results are cached in a row\n * async.mapSeries(args, sometimesAsync, done);\n *\n * // this will defer sometimesAsync's callback if necessary,\n * // preventing stack overflows\n * async.mapSeries(args, async.ensureAsync(sometimesAsync), done);\n */\nfunction ensureAsync(fn) {\n    if (isAsync(fn)) return fn;\n    return function (...args/*, callback*/) {\n        var callback = args.pop();\n        var sync = true;\n        args.push((...innerArgs) => {\n            if (sync) {\n                setImmediate$1(() => callback(...innerArgs));\n            } else {\n                callback(...innerArgs);\n            }\n        });\n        fn.apply(this, args);\n        sync = false;\n    };\n}\n\n/**\n * Returns `true` if every element in `coll` satisfies an async test. If any\n * iteratee call returns `false`, the main `callback` is immediately called.\n *\n * @name every\n * @static\n * @memberOf module:Collections\n * @method\n * @alias all\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collection in parallel.\n * The iteratee must complete with a boolean result value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result will be either `true` or `false`\n * depending on the values of the async tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n * // dir4 does not exist\n *\n * const fileList = ['dir1/file1.txt','dir2/file3.txt','dir3/file5.txt'];\n * const withMissingFileList = ['file1.txt','file2.txt','file4.txt'];\n *\n * // asynchronous function that checks if a file exists\n * function fileExists(file, callback) {\n *    fs.access(file, fs.constants.F_OK, (err) => {\n *        callback(null, !err);\n *    });\n * }\n *\n * // Using callbacks\n * async.every(fileList, fileExists, function(err, result) {\n *     console.log(result);\n *     // true\n *     // result is true since every file exists\n * });\n *\n * async.every(withMissingFileList, fileExists, function(err, result) {\n *     console.log(result);\n *     // false\n *     // result is false since NOT every file exists\n * });\n *\n * // Using Promises\n * async.every(fileList, fileExists)\n * .then( result => {\n *     console.log(result);\n *     // true\n *     // result is true since every file exists\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * async.every(withMissingFileList, fileExists)\n * .then( result => {\n *     console.log(result);\n *     // false\n *     // result is false since NOT every file exists\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.every(fileList, fileExists);\n *         console.log(result);\n *         // true\n *         // result is true since every file exists\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * async () => {\n *     try {\n *         let result = await async.every(withMissingFileList, fileExists);\n *         console.log(result);\n *         // false\n *         // result is false since NOT every file exists\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction every(coll, iteratee, callback) {\n    return _createTester(bool => !bool, res => !res)(eachOf$1, coll, iteratee, callback)\n}\nvar every$1 = awaitify(every, 3);\n\n/**\n * The same as [`every`]{@link module:Collections.every} but runs a maximum of `limit` async operations at a time.\n *\n * @name everyLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.every]{@link module:Collections.every}\n * @alias allLimit\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collection in parallel.\n * The iteratee must complete with a boolean result value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result will be either `true` or `false`\n * depending on the values of the async tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n */\nfunction everyLimit(coll, limit, iteratee, callback) {\n    return _createTester(bool => !bool, res => !res)(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar everyLimit$1 = awaitify(everyLimit, 4);\n\n/**\n * The same as [`every`]{@link module:Collections.every} but runs only a single async operation at a time.\n *\n * @name everySeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.every]{@link module:Collections.every}\n * @alias allSeries\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collection in series.\n * The iteratee must complete with a boolean result value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result will be either `true` or `false`\n * depending on the values of the async tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n */\nfunction everySeries(coll, iteratee, callback) {\n    return _createTester(bool => !bool, res => !res)(eachOfSeries$1, coll, iteratee, callback)\n}\nvar everySeries$1 = awaitify(everySeries, 3);\n\nfunction filterArray(eachfn, arr, iteratee, callback) {\n    var truthValues = new Array(arr.length);\n    eachfn(arr, (x, index, iterCb) => {\n        iteratee(x, (err, v) => {\n            truthValues[index] = !!v;\n            iterCb(err);\n        });\n    }, err => {\n        if (err) return callback(err);\n        var results = [];\n        for (var i = 0; i < arr.length; i++) {\n            if (truthValues[i]) results.push(arr[i]);\n        }\n        callback(null, results);\n    });\n}\n\nfunction filterGeneric(eachfn, coll, iteratee, callback) {\n    var results = [];\n    eachfn(coll, (x, index, iterCb) => {\n        iteratee(x, (err, v) => {\n            if (err) return iterCb(err);\n            if (v) {\n                results.push({index, value: x});\n            }\n            iterCb(err);\n        });\n    }, err => {\n        if (err) return callback(err);\n        callback(null, results\n            .sort((a, b) => a.index - b.index)\n            .map(v => v.value));\n    });\n}\n\nfunction _filter(eachfn, coll, iteratee, callback) {\n    var filter = isArrayLike(coll) ? filterArray : filterGeneric;\n    return filter(eachfn, coll, wrapAsync(iteratee), callback);\n}\n\n/**\n * Returns a new array of all the values in `coll` which pass an async truth\n * test. This operation is performed in parallel, but the results array will be\n * in the same order as the original.\n *\n * @name filter\n * @static\n * @memberOf module:Collections\n * @method\n * @alias select\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - A truth test to apply to each item in `coll`.\n * The `iteratee` is passed a `callback(err, truthValue)`, which must be called\n * with a boolean argument once it has completed. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback provided\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n *\n * const files = ['dir1/file1.txt','dir2/file3.txt','dir3/file6.txt'];\n *\n * // asynchronous function that checks if a file exists\n * function fileExists(file, callback) {\n *    fs.access(file, fs.constants.F_OK, (err) => {\n *        callback(null, !err);\n *    });\n * }\n *\n * // Using callbacks\n * async.filter(files, fileExists, function(err, results) {\n *    if(err) {\n *        console.log(err);\n *    } else {\n *        console.log(results);\n *        // [ 'dir1/file1.txt', 'dir2/file3.txt' ]\n *        // results is now an array of the existing files\n *    }\n * });\n *\n * // Using Promises\n * async.filter(files, fileExists)\n * .then(results => {\n *     console.log(results);\n *     // [ 'dir1/file1.txt', 'dir2/file3.txt' ]\n *     // results is now an array of the existing files\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let results = await async.filter(files, fileExists);\n *         console.log(results);\n *         // [ 'dir1/file1.txt', 'dir2/file3.txt' ]\n *         // results is now an array of the existing files\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction filter (coll, iteratee, callback) {\n    return _filter(eachOf$1, coll, iteratee, callback)\n}\nvar filter$1 = awaitify(filter, 3);\n\n/**\n * The same as [`filter`]{@link module:Collections.filter} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name filterLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.filter]{@link module:Collections.filter}\n * @alias selectLimit\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {Function} iteratee - A truth test to apply to each item in `coll`.\n * The `iteratee` is passed a `callback(err, truthValue)`, which must be called\n * with a boolean argument once it has completed. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback provided\n */\nfunction filterLimit (coll, limit, iteratee, callback) {\n    return _filter(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar filterLimit$1 = awaitify(filterLimit, 4);\n\n/**\n * The same as [`filter`]{@link module:Collections.filter} but runs only a single async operation at a time.\n *\n * @name filterSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.filter]{@link module:Collections.filter}\n * @alias selectSeries\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - A truth test to apply to each item in `coll`.\n * The `iteratee` is passed a `callback(err, truthValue)`, which must be called\n * with a boolean argument once it has completed. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results)\n * @returns {Promise} a promise, if no callback provided\n */\nfunction filterSeries (coll, iteratee, callback) {\n    return _filter(eachOfSeries$1, coll, iteratee, callback)\n}\nvar filterSeries$1 = awaitify(filterSeries, 3);\n\n/**\n * Calls the asynchronous function `fn` with a callback parameter that allows it\n * to call itself again, in series, indefinitely.\n\n * If an error is passed to the callback then `errback` is called with the\n * error, and execution stops, otherwise it will never be called.\n *\n * @name forever\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {AsyncFunction} fn - an async function to call repeatedly.\n * Invoked with (next).\n * @param {Function} [errback] - when `fn` passes an error to it's callback,\n * this function will be called, and execution stops. Invoked with (err).\n * @returns {Promise} a promise that rejects if an error occurs and an errback\n * is not passed\n * @example\n *\n * async.forever(\n *     function(next) {\n *         // next is suitable for passing to things that need a callback(err [, whatever]);\n *         // it will result in this function being called again.\n *     },\n *     function(err) {\n *         // if next is called with a value in its first parameter, it will appear\n *         // in here as 'err', and execution will stop.\n *     }\n * );\n */\nfunction forever(fn, errback) {\n    var done = onlyOnce(errback);\n    var task = wrapAsync(ensureAsync(fn));\n\n    function next(err) {\n        if (err) return done(err);\n        if (err === false) return;\n        task(next);\n    }\n    return next();\n}\nvar forever$1 = awaitify(forever, 2);\n\n/**\n * The same as [`groupBy`]{@link module:Collections.groupBy} but runs a maximum of `limit` async operations at a time.\n *\n * @name groupByLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.groupBy]{@link module:Collections.groupBy}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a `key` to group the value under.\n * Invoked with (value, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Result is an `Object` whoses\n * properties are arrays of values which returned the corresponding key.\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction groupByLimit(coll, limit, iteratee, callback) {\n    var _iteratee = wrapAsync(iteratee);\n    return mapLimit$1(coll, limit, (val, iterCb) => {\n        _iteratee(val, (err, key) => {\n            if (err) return iterCb(err);\n            return iterCb(err, {key, val});\n        });\n    }, (err, mapResults) => {\n        var result = {};\n        // from MDN, handle object having an `hasOwnProperty` prop\n        var {hasOwnProperty} = Object.prototype;\n\n        for (var i = 0; i < mapResults.length; i++) {\n            if (mapResults[i]) {\n                var {key} = mapResults[i];\n                var {val} = mapResults[i];\n\n                if (hasOwnProperty.call(result, key)) {\n                    result[key].push(val);\n                } else {\n                    result[key] = [val];\n                }\n            }\n        }\n\n        return callback(err, result);\n    });\n}\n\nvar groupByLimit$1 = awaitify(groupByLimit, 4);\n\n/**\n * Returns a new object, where each value corresponds to an array of items, from\n * `coll`, that returned the corresponding key. That is, the keys of the object\n * correspond to the values passed to the `iteratee` callback.\n *\n * Note: Since this function applies the `iteratee` to each item in parallel,\n * there is no guarantee that the `iteratee` functions will complete in order.\n * However, the values for each key in the `result` will be in the same order as\n * the original `coll`. For Objects, the values will roughly be in the order of\n * the original Objects' keys (but this can vary across JavaScript engines).\n *\n * @name groupBy\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a `key` to group the value under.\n * Invoked with (value, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Result is an `Object` whoses\n * properties are arrays of values which returned the corresponding key.\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n * // dir4 does not exist\n *\n * const files = ['dir1/file1.txt','dir2','dir4']\n *\n * // asynchronous function that detects file type as none, file, or directory\n * function detectFile(file, callback) {\n *     fs.stat(file, function(err, stat) {\n *         if (err) {\n *             return callback(null, 'none');\n *         }\n *         callback(null, stat.isDirectory() ? 'directory' : 'file');\n *     });\n * }\n *\n * //Using callbacks\n * async.groupBy(files, detectFile, function(err, result) {\n *     if(err) {\n *         console.log(err);\n *     } else {\n *\t       console.log(result);\n *         // {\n *         //     file: [ 'dir1/file1.txt' ],\n *         //     none: [ 'dir4' ],\n *         //     directory: [ 'dir2']\n *         // }\n *         // result is object containing the files grouped by type\n *     }\n * });\n *\n * // Using Promises\n * async.groupBy(files, detectFile)\n * .then( result => {\n *     console.log(result);\n *     // {\n *     //     file: [ 'dir1/file1.txt' ],\n *     //     none: [ 'dir4' ],\n *     //     directory: [ 'dir2']\n *     // }\n *     // result is object containing the files grouped by type\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.groupBy(files, detectFile);\n *         console.log(result);\n *         // {\n *         //     file: [ 'dir1/file1.txt' ],\n *         //     none: [ 'dir4' ],\n *         //     directory: [ 'dir2']\n *         // }\n *         // result is object containing the files grouped by type\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction groupBy (coll, iteratee, callback) {\n    return groupByLimit$1(coll, Infinity, iteratee, callback)\n}\n\n/**\n * The same as [`groupBy`]{@link module:Collections.groupBy} but runs only a single async operation at a time.\n *\n * @name groupBySeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.groupBy]{@link module:Collections.groupBy}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a `key` to group the value under.\n * Invoked with (value, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Result is an `Object` whose\n * properties are arrays of values which returned the corresponding key.\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction groupBySeries (coll, iteratee, callback) {\n    return groupByLimit$1(coll, 1, iteratee, callback)\n}\n\n/**\n * Logs the result of an `async` function to the `console`. Only works in\n * Node.js or in browsers that support `console.log` and `console.error` (such\n * as FF and Chrome). If multiple arguments are returned from the async\n * function, `console.log` is called on each argument in order.\n *\n * @name log\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} function - The function you want to eventually apply\n * all arguments to.\n * @param {...*} arguments... - Any number of arguments to apply to the function.\n * @example\n *\n * // in a module\n * var hello = function(name, callback) {\n *     setTimeout(function() {\n *         callback(null, 'hello ' + name);\n *     }, 1000);\n * };\n *\n * // in the node repl\n * node> async.log(hello, 'world');\n * 'hello world'\n */\nvar log = consoleFunc('log');\n\n/**\n * The same as [`mapValues`]{@link module:Collections.mapValues} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name mapValuesLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.mapValues]{@link module:Collections.mapValues}\n * @category Collection\n * @param {Object} obj - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - A function to apply to each value and key\n * in `coll`.\n * The iteratee should complete with the transformed value as its result.\n * Invoked with (value, key, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. `result` is a new object consisting\n * of each key from `obj`, with each transformed value on the right-hand side.\n * Invoked with (err, result).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction mapValuesLimit(obj, limit, iteratee, callback) {\n    callback = once(callback);\n    var newObj = {};\n    var _iteratee = wrapAsync(iteratee);\n    return eachOfLimit(limit)(obj, (val, key, next) => {\n        _iteratee(val, key, (err, result) => {\n            if (err) return next(err);\n            newObj[key] = result;\n            next(err);\n        });\n    }, err => callback(err, newObj));\n}\n\nvar mapValuesLimit$1 = awaitify(mapValuesLimit, 4);\n\n/**\n * A relative of [`map`]{@link module:Collections.map}, designed for use with objects.\n *\n * Produces a new Object by mapping each value of `obj` through the `iteratee`\n * function. The `iteratee` is called each `value` and `key` from `obj` and a\n * callback for when it has finished processing. Each of these callbacks takes\n * two arguments: an `error`, and the transformed item from `obj`. If `iteratee`\n * passes an error to its callback, the main `callback` (for the `mapValues`\n * function) is immediately called with the error.\n *\n * Note, the order of the keys in the result is not guaranteed.  The keys will\n * be roughly in the order they complete, (but this is very engine-specific)\n *\n * @name mapValues\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Object} obj - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each value and key\n * in `coll`.\n * The iteratee should complete with the transformed value as its result.\n * Invoked with (value, key, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. `result` is a new object consisting\n * of each key from `obj`, with each transformed value on the right-hand side.\n * Invoked with (err, result).\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * // file1.txt is a file that is 1000 bytes in size\n * // file2.txt is a file that is 2000 bytes in size\n * // file3.txt is a file that is 3000 bytes in size\n * // file4.txt does not exist\n *\n * const fileMap = {\n *     f1: 'file1.txt',\n *     f2: 'file2.txt',\n *     f3: 'file3.txt'\n * };\n *\n * const withMissingFileMap = {\n *     f1: 'file1.txt',\n *     f2: 'file2.txt',\n *     f3: 'file4.txt'\n * };\n *\n * // asynchronous function that returns the file size in bytes\n * function getFileSizeInBytes(file, key, callback) {\n *     fs.stat(file, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         callback(null, stat.size);\n *     });\n * }\n *\n * // Using callbacks\n * async.mapValues(fileMap, getFileSizeInBytes, function(err, result) {\n *     if (err) {\n *         console.log(err);\n *     } else {\n *         console.log(result);\n *         // result is now a map of file size in bytes for each file, e.g.\n *         // {\n *         //     f1: 1000,\n *         //     f2: 2000,\n *         //     f3: 3000\n *         // }\n *     }\n * });\n *\n * // Error handling\n * async.mapValues(withMissingFileMap, getFileSizeInBytes, function(err, result) {\n *     if (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     } else {\n *         console.log(result);\n *     }\n * });\n *\n * // Using Promises\n * async.mapValues(fileMap, getFileSizeInBytes)\n * .then( result => {\n *     console.log(result);\n *     // result is now a map of file size in bytes for each file, e.g.\n *     // {\n *     //     f1: 1000,\n *     //     f2: 2000,\n *     //     f3: 3000\n *     // }\n * }).catch (err => {\n *     console.log(err);\n * });\n *\n * // Error Handling\n * async.mapValues(withMissingFileMap, getFileSizeInBytes)\n * .then( result => {\n *     console.log(result);\n * }).catch (err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.mapValues(fileMap, getFileSizeInBytes);\n *         console.log(result);\n *         // result is now a map of file size in bytes for each file, e.g.\n *         // {\n *         //     f1: 1000,\n *         //     f2: 2000,\n *         //     f3: 3000\n *         // }\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // Error Handling\n * async () => {\n *     try {\n *         let result = await async.mapValues(withMissingFileMap, getFileSizeInBytes);\n *         console.log(result);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     }\n * }\n *\n */\nfunction mapValues(obj, iteratee, callback) {\n    return mapValuesLimit$1(obj, Infinity, iteratee, callback)\n}\n\n/**\n * The same as [`mapValues`]{@link module:Collections.mapValues} but runs only a single async operation at a time.\n *\n * @name mapValuesSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.mapValues]{@link module:Collections.mapValues}\n * @category Collection\n * @param {Object} obj - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each value and key\n * in `coll`.\n * The iteratee should complete with the transformed value as its result.\n * Invoked with (value, key, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. `result` is a new object consisting\n * of each key from `obj`, with each transformed value on the right-hand side.\n * Invoked with (err, result).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction mapValuesSeries(obj, iteratee, callback) {\n    return mapValuesLimit$1(obj, 1, iteratee, callback)\n}\n\n/**\n * Caches the results of an async function. When creating a hash to store\n * function results against, the callback is omitted from the hash and an\n * optional hash function can be used.\n *\n * **Note: if the async function errs, the result will not be cached and\n * subsequent calls will call the wrapped function.**\n *\n * If no hash function is specified, the first argument is used as a hash key,\n * which may work reasonably if it is a string or a data type that converts to a\n * distinct string. Note that objects and arrays will not behave reasonably.\n * Neither will cases where the other arguments are significant. In such cases,\n * specify your own hash function.\n *\n * The cache of results is exposed as the `memo` property of the function\n * returned by `memoize`.\n *\n * @name memoize\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} fn - The async function to proxy and cache results from.\n * @param {Function} hasher - An optional function for generating a custom hash\n * for storing results. It has all the arguments applied to it apart from the\n * callback, and must be synchronous.\n * @returns {AsyncFunction} a memoized version of `fn`\n * @example\n *\n * var slow_fn = function(name, callback) {\n *     // do something\n *     callback(null, result);\n * };\n * var fn = async.memoize(slow_fn);\n *\n * // fn can now be used as if it were slow_fn\n * fn('some name', function() {\n *     // callback\n * });\n */\nfunction memoize(fn, hasher = v => v) {\n    var memo = Object.create(null);\n    var queues = Object.create(null);\n    var _fn = wrapAsync(fn);\n    var memoized = initialParams((args, callback) => {\n        var key = hasher(...args);\n        if (key in memo) {\n            setImmediate$1(() => callback(null, ...memo[key]));\n        } else if (key in queues) {\n            queues[key].push(callback);\n        } else {\n            queues[key] = [callback];\n            _fn(...args, (err, ...resultArgs) => {\n                // #1465 don't memoize if an error occurred\n                if (!err) {\n                    memo[key] = resultArgs;\n                }\n                var q = queues[key];\n                delete queues[key];\n                for (var i = 0, l = q.length; i < l; i++) {\n                    q[i](err, ...resultArgs);\n                }\n            });\n        }\n    });\n    memoized.memo = memo;\n    memoized.unmemoized = fn;\n    return memoized;\n}\n\n/* istanbul ignore file */\n\n/**\n * Calls `callback` on a later loop around the event loop. In Node.js this just\n * calls `process.nextTick`.  In the browser it will use `setImmediate` if\n * available, otherwise `setTimeout(callback, 0)`, which means other higher\n * priority events may precede the execution of `callback`.\n *\n * This is used internally for browser-compatibility purposes.\n *\n * @name nextTick\n * @static\n * @memberOf module:Utils\n * @method\n * @see [async.setImmediate]{@link module:Utils.setImmediate}\n * @category Util\n * @param {Function} callback - The function to call on a later loop around\n * the event loop. Invoked with (args...).\n * @param {...*} args... - any number of additional arguments to pass to the\n * callback on the next tick.\n * @example\n *\n * var call_order = [];\n * async.nextTick(function() {\n *     call_order.push('two');\n *     // call_order now equals ['one','two']\n * });\n * call_order.push('one');\n *\n * async.setImmediate(function (a, b, c) {\n *     // a, b, and c equal 1, 2, and 3\n * }, 1, 2, 3);\n */\nvar _defer$1;\n\nif (hasNextTick) {\n    _defer$1 = process.nextTick;\n} else if (hasSetImmediate) {\n    _defer$1 = setImmediate;\n} else {\n    _defer$1 = fallback;\n}\n\nvar nextTick = wrap(_defer$1);\n\nvar _parallel = awaitify((eachfn, tasks, callback) => {\n    var results = isArrayLike(tasks) ? [] : {};\n\n    eachfn(tasks, (task, key, taskCb) => {\n        wrapAsync(task)((err, ...result) => {\n            if (result.length < 2) {\n                [result] = result;\n            }\n            results[key] = result;\n            taskCb(err);\n        });\n    }, err => callback(err, results));\n}, 3);\n\n/**\n * Run the `tasks` collection of functions in parallel, without waiting until\n * the previous function has completed. If any of the functions pass an error to\n * its callback, the main `callback` is immediately called with the value of the\n * error. Once the `tasks` have completed, the results are passed to the final\n * `callback` as an array.\n *\n * **Note:** `parallel` is about kicking-off I/O tasks in parallel, not about\n * parallel execution of code.  If your tasks do not use any timers or perform\n * any I/O, they will actually be executed in series.  Any synchronous setup\n * sections for each task will happen one after the other.  JavaScript remains\n * single-threaded.\n *\n * **Hint:** Use [`reflect`]{@link module:Utils.reflect} to continue the\n * execution of other tasks when a task fails.\n *\n * It is also possible to use an object instead of an array. Each property will\n * be run as a function and the results will be passed to the final `callback`\n * as an object instead of an array. This can be a more readable way of handling\n * results from {@link async.parallel}.\n *\n * @name parallel\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} tasks - A collection of\n * [async functions]{@link AsyncFunction} to run.\n * Each async function can complete with any number of optional `result` values.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed successfully. This function gets a results array\n * (or object) containing all the result arguments passed to the task callbacks.\n * Invoked with (err, results).\n * @returns {Promise} a promise, if a callback is not passed\n *\n * @example\n *\n * //Using Callbacks\n * async.parallel([\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ], function(err, results) {\n *     console.log(results);\n *     // results is equal to ['one','two'] even though\n *     // the second function had a shorter timeout.\n * });\n *\n * // an example using an object instead of an array\n * async.parallel({\n *     one: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 1);\n *         }, 200);\n *     },\n *     two: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 2);\n *         }, 100);\n *     }\n * }, function(err, results) {\n *     console.log(results);\n *     // results is equal to: { one: 1, two: 2 }\n * });\n *\n * //Using Promises\n * async.parallel([\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ]).then(results => {\n *     console.log(results);\n *     // results is equal to ['one','two'] even though\n *     // the second function had a shorter timeout.\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // an example using an object instead of an array\n * async.parallel({\n *     one: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 1);\n *         }, 200);\n *     },\n *     two: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 2);\n *         }, 100);\n *     }\n * }).then(results => {\n *     console.log(results);\n *     // results is equal to: { one: 1, two: 2 }\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * //Using async/await\n * async () => {\n *     try {\n *         let results = await async.parallel([\n *             function(callback) {\n *                 setTimeout(function() {\n *                     callback(null, 'one');\n *                 }, 200);\n *             },\n *             function(callback) {\n *                 setTimeout(function() {\n *                     callback(null, 'two');\n *                 }, 100);\n *             }\n *         ]);\n *         console.log(results);\n *         // results is equal to ['one','two'] even though\n *         // the second function had a shorter timeout.\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // an example using an object instead of an array\n * async () => {\n *     try {\n *         let results = await async.parallel({\n *             one: function(callback) {\n *                 setTimeout(function() {\n *                     callback(null, 1);\n *                 }, 200);\n *             },\n *            two: function(callback) {\n *                 setTimeout(function() {\n *                     callback(null, 2);\n *                 }, 100);\n *            }\n *         });\n *         console.log(results);\n *         // results is equal to: { one: 1, two: 2 }\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction parallel(tasks, callback) {\n    return _parallel(eachOf$1, tasks, callback);\n}\n\n/**\n * The same as [`parallel`]{@link module:ControlFlow.parallel} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name parallelLimit\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.parallel]{@link module:ControlFlow.parallel}\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} tasks - A collection of\n * [async functions]{@link AsyncFunction} to run.\n * Each async function can complete with any number of optional `result` values.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed successfully. This function gets a results array\n * (or object) containing all the result arguments passed to the task callbacks.\n * Invoked with (err, results).\n * @returns {Promise} a promise, if a callback is not passed\n */\nfunction parallelLimit(tasks, limit, callback) {\n    return _parallel(eachOfLimit(limit), tasks, callback);\n}\n\n/**\n * A queue of tasks for the worker function to complete.\n * @typedef {Iterable} QueueObject\n * @memberOf module:ControlFlow\n * @property {Function} length - a function returning the number of items\n * waiting to be processed. Invoke with `queue.length()`.\n * @property {boolean} started - a boolean indicating whether or not any\n * items have been pushed and processed by the queue.\n * @property {Function} running - a function returning the number of items\n * currently being processed. Invoke with `queue.running()`.\n * @property {Function} workersList - a function returning the array of items\n * currently being processed. Invoke with `queue.workersList()`.\n * @property {Function} idle - a function returning false if there are items\n * waiting or being processed, or true if not. Invoke with `queue.idle()`.\n * @property {number} concurrency - an integer for determining how many `worker`\n * functions should be run in parallel. This property can be changed after a\n * `queue` is created to alter the concurrency on-the-fly.\n * @property {number} payload - an integer that specifies how many items are\n * passed to the worker function at a time. only applies if this is a\n * [cargo]{@link module:ControlFlow.cargo} object\n * @property {AsyncFunction} push - add a new task to the `queue`. Calls `callback`\n * once the `worker` has finished processing the task. Instead of a single task,\n * a `tasks` array can be submitted. The respective callback is used for every\n * task in the list. Invoke with `queue.push(task, [callback])`,\n * @property {AsyncFunction} unshift - add a new task to the front of the `queue`.\n * Invoke with `queue.unshift(task, [callback])`.\n * @property {AsyncFunction} pushAsync - the same as `q.push`, except this returns\n * a promise that rejects if an error occurs.\n * @property {AsyncFunction} unshiftAsync - the same as `q.unshift`, except this returns\n * a promise that rejects if an error occurs.\n * @property {Function} remove - remove items from the queue that match a test\n * function.  The test function will be passed an object with a `data` property,\n * and a `priority` property, if this is a\n * [priorityQueue]{@link module:ControlFlow.priorityQueue} object.\n * Invoked with `queue.remove(testFn)`, where `testFn` is of the form\n * `function ({data, priority}) {}` and returns a Boolean.\n * @property {Function} saturated - a function that sets a callback that is\n * called when the number of running workers hits the `concurrency` limit, and\n * further tasks will be queued.  If the callback is omitted, `q.saturated()`\n * returns a promise for the next occurrence.\n * @property {Function} unsaturated - a function that sets a callback that is\n * called when the number of running workers is less than the `concurrency` &\n * `buffer` limits, and further tasks will not be queued. If the callback is\n * omitted, `q.unsaturated()` returns a promise for the next occurrence.\n * @property {number} buffer - A minimum threshold buffer in order to say that\n * the `queue` is `unsaturated`.\n * @property {Function} empty - a function that sets a callback that is called\n * when the last item from the `queue` is given to a `worker`. If the callback\n * is omitted, `q.empty()` returns a promise for the next occurrence.\n * @property {Function} drain - a function that sets a callback that is called\n * when the last item from the `queue` has returned from the `worker`. If the\n * callback is omitted, `q.drain()` returns a promise for the next occurrence.\n * @property {Function} error - a function that sets a callback that is called\n * when a task errors. Has the signature `function(error, task)`. If the\n * callback is omitted, `error()` returns a promise that rejects on the next\n * error.\n * @property {boolean} paused - a boolean for determining whether the queue is\n * in a paused state.\n * @property {Function} pause - a function that pauses the processing of tasks\n * until `resume()` is called. Invoke with `queue.pause()`.\n * @property {Function} resume - a function that resumes the processing of\n * queued tasks when the queue is paused. Invoke with `queue.resume()`.\n * @property {Function} kill - a function that removes the `drain` callback and\n * empties remaining tasks from the queue forcing it to go idle. No more tasks\n * should be pushed to the queue after calling this function. Invoke with `queue.kill()`.\n *\n * @example\n * const q = async.queue(worker, 2)\n * q.push(item1)\n * q.push(item2)\n * q.push(item3)\n * // queues are iterable, spread into an array to inspect\n * const items = [...q] // [item1, item2, item3]\n * // or use for of\n * for (let item of q) {\n *     console.log(item)\n * }\n *\n * q.drain(() => {\n *     console.log('all done')\n * })\n * // or\n * await q.drain()\n */\n\n/**\n * Creates a `queue` object with the specified `concurrency`. Tasks added to the\n * `queue` are processed in parallel (up to the `concurrency` limit). If all\n * `worker`s are in progress, the task is queued until one becomes available.\n * Once a `worker` completes a `task`, that `task`'s callback is called.\n *\n * @name queue\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {AsyncFunction} worker - An async function for processing a queued task.\n * If you want to handle errors from an individual task, pass a callback to\n * `q.push()`. Invoked with (task, callback).\n * @param {number} [concurrency=1] - An `integer` for determining how many\n * `worker` functions should be run in parallel.  If omitted, the concurrency\n * defaults to `1`.  If the concurrency is `0`, an error is thrown.\n * @returns {module:ControlFlow.QueueObject} A queue object to manage the tasks. Callbacks can be\n * attached as certain properties to listen for specific events during the\n * lifecycle of the queue.\n * @example\n *\n * // create a queue object with concurrency 2\n * var q = async.queue(function(task, callback) {\n *     console.log('hello ' + task.name);\n *     callback();\n * }, 2);\n *\n * // assign a callback\n * q.drain(function() {\n *     console.log('all items have been processed');\n * });\n * // or await the end\n * await q.drain()\n *\n * // assign an error callback\n * q.error(function(err, task) {\n *     console.error('task experienced an error');\n * });\n *\n * // add some items to the queue\n * q.push({name: 'foo'}, function(err) {\n *     console.log('finished processing foo');\n * });\n * // callback is optional\n * q.push({name: 'bar'});\n *\n * // add some items to the queue (batch-wise)\n * q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function(err) {\n *     console.log('finished processing item');\n * });\n *\n * // add some items to the front of the queue\n * q.unshift({name: 'bar'}, function (err) {\n *     console.log('finished processing bar');\n * });\n */\nfunction queue$1 (worker, concurrency) {\n    var _worker = wrapAsync(worker);\n    return queue((items, cb) => {\n        _worker(items[0], cb);\n    }, concurrency, 1);\n}\n\n// Binary min-heap implementation used for priority queue.\n// Implementation is stable, i.e. push time is considered for equal priorities\nclass Heap {\n    constructor() {\n        this.heap = [];\n        this.pushCount = Number.MIN_SAFE_INTEGER;\n    }\n\n    get length() {\n        return this.heap.length;\n    }\n\n    empty () {\n        this.heap = [];\n        return this;\n    }\n\n    percUp(index) {\n        let p;\n\n        while (index > 0 && smaller(this.heap[index], this.heap[p=parent(index)])) {\n            let t = this.heap[index];\n            this.heap[index] = this.heap[p];\n            this.heap[p] = t;\n\n            index = p;\n        }\n    }\n\n    percDown(index) {\n        let l;\n\n        while ((l=leftChi(index)) < this.heap.length) {\n            if (l+1 < this.heap.length && smaller(this.heap[l+1], this.heap[l])) {\n                l = l+1;\n            }\n\n            if (smaller(this.heap[index], this.heap[l])) {\n                break;\n            }\n\n            let t = this.heap[index];\n            this.heap[index] = this.heap[l];\n            this.heap[l] = t;\n\n            index = l;\n        }\n    }\n\n    push(node) {\n        node.pushCount = ++this.pushCount;\n        this.heap.push(node);\n        this.percUp(this.heap.length-1);\n    }\n\n    unshift(node) {\n        return this.heap.push(node);\n    }\n\n    shift() {\n        let [top] = this.heap;\n\n        this.heap[0] = this.heap[this.heap.length-1];\n        this.heap.pop();\n        this.percDown(0);\n\n        return top;\n    }\n\n    toArray() {\n        return [...this];\n    }\n\n    *[Symbol.iterator] () {\n        for (let i = 0; i < this.heap.length; i++) {\n            yield this.heap[i].data;\n        }\n    }\n\n    remove (testFn) {\n        let j = 0;\n        for (let i = 0; i < this.heap.length; i++) {\n            if (!testFn(this.heap[i])) {\n                this.heap[j] = this.heap[i];\n                j++;\n            }\n        }\n\n        this.heap.splice(j);\n\n        for (let i = parent(this.heap.length-1); i >= 0; i--) {\n            this.percDown(i);\n        }\n\n        return this;\n    }\n}\n\nfunction leftChi(i) {\n    return (i<<1)+1;\n}\n\nfunction parent(i) {\n    return ((i+1)>>1)-1;\n}\n\nfunction smaller(x, y) {\n    if (x.priority !== y.priority) {\n        return x.priority < y.priority;\n    }\n    else {\n        return x.pushCount < y.pushCount;\n    }\n}\n\n/**\n * The same as [async.queue]{@link module:ControlFlow.queue} only tasks are assigned a priority and\n * completed in ascending priority order.\n *\n * @name priorityQueue\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.queue]{@link module:ControlFlow.queue}\n * @category Control Flow\n * @param {AsyncFunction} worker - An async function for processing a queued task.\n * If you want to handle errors from an individual task, pass a callback to\n * `q.push()`.\n * Invoked with (task, callback).\n * @param {number} concurrency - An `integer` for determining how many `worker`\n * functions should be run in parallel.  If omitted, the concurrency defaults to\n * `1`.  If the concurrency is `0`, an error is thrown.\n * @returns {module:ControlFlow.QueueObject} A priorityQueue object to manage the tasks. There are two\n * differences between `queue` and `priorityQueue` objects:\n * * `push(task, priority, [callback])` - `priority` should be a number. If an\n *   array of `tasks` is given, all tasks will be assigned the same priority.\n * * The `unshift` method was removed.\n */\nfunction priorityQueue(worker, concurrency) {\n    // Start with a normal queue\n    var q = queue$1(worker, concurrency);\n    var processingScheduled = false;\n\n    q._tasks = new Heap();\n\n    // Override push to accept second parameter representing priority\n    q.push = function(data, priority = 0, callback = () => {}) {\n        if (typeof callback !== 'function') {\n            throw new Error('task callback must be a function');\n        }\n        q.started = true;\n        if (!Array.isArray(data)) {\n            data = [data];\n        }\n        if (data.length === 0 && q.idle()) {\n            // call drain immediately if there are no tasks\n            return setImmediate$1(() => q.drain());\n        }\n\n        for (var i = 0, l = data.length; i < l; i++) {\n            var item = {\n                data: data[i],\n                priority,\n                callback\n            };\n\n            q._tasks.push(item);\n        }\n\n        if (!processingScheduled) {\n            processingScheduled = true;\n            setImmediate$1(() => {\n                processingScheduled = false;\n                q.process();\n            });\n        }\n    };\n\n    // Remove unshift function\n    delete q.unshift;\n\n    return q;\n}\n\n/**\n * Runs the `tasks` array of functions in parallel, without waiting until the\n * previous function has completed. Once any of the `tasks` complete or pass an\n * error to its callback, the main `callback` is immediately called. It's\n * equivalent to `Promise.race()`.\n *\n * @name race\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array} tasks - An array containing [async functions]{@link AsyncFunction}\n * to run. Each function can complete with an optional `result` value.\n * @param {Function} callback - A callback to run once any of the functions have\n * completed. This function gets an error or result from the first function that\n * completed. Invoked with (err, result).\n * @returns undefined\n * @example\n *\n * async.race([\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ],\n * // main callback\n * function(err, result) {\n *     // the result will be equal to 'two' as it finishes earlier\n * });\n */\nfunction race(tasks, callback) {\n    callback = once(callback);\n    if (!Array.isArray(tasks)) return callback(new TypeError('First argument to race must be an array of functions'));\n    if (!tasks.length) return callback();\n    for (var i = 0, l = tasks.length; i < l; i++) {\n        wrapAsync(tasks[i])(callback);\n    }\n}\n\nvar race$1 = awaitify(race, 2);\n\n/**\n * Same as [`reduce`]{@link module:Collections.reduce}, only operates on `array` in reverse order.\n *\n * @name reduceRight\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.reduce]{@link module:Collections.reduce}\n * @alias foldr\n * @category Collection\n * @param {Array} array - A collection to iterate over.\n * @param {*} memo - The initial state of the reduction.\n * @param {AsyncFunction} iteratee - A function applied to each item in the\n * array to produce the next step in the reduction.\n * The `iteratee` should complete with the next state of the reduction.\n * If the iteratee completes with an error, the reduction is stopped and the\n * main `callback` is immediately called with the error.\n * Invoked with (memo, item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result is the reduced value. Invoked with\n * (err, result).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction reduceRight (array, memo, iteratee, callback) {\n    var reversed = [...array].reverse();\n    return reduce$1(reversed, memo, iteratee, callback);\n}\n\n/**\n * Wraps the async function in another function that always completes with a\n * result object, even when it errors.\n *\n * The result object has either the property `error` or `value`.\n *\n * @name reflect\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} fn - The async function you want to wrap\n * @returns {Function} - A function that always passes null to it's callback as\n * the error. The second argument to the callback will be an `object` with\n * either an `error` or a `value` property.\n * @example\n *\n * async.parallel([\n *     async.reflect(function(callback) {\n *         // do some stuff ...\n *         callback(null, 'one');\n *     }),\n *     async.reflect(function(callback) {\n *         // do some more stuff but error ...\n *         callback('bad stuff happened');\n *     }),\n *     async.reflect(function(callback) {\n *         // do some more stuff ...\n *         callback(null, 'two');\n *     })\n * ],\n * // optional callback\n * function(err, results) {\n *     // values\n *     // results[0].value = 'one'\n *     // results[1].error = 'bad stuff happened'\n *     // results[2].value = 'two'\n * });\n */\nfunction reflect(fn) {\n    var _fn = wrapAsync(fn);\n    return initialParams(function reflectOn(args, reflectCallback) {\n        args.push((error, ...cbArgs) => {\n            let retVal = {};\n            if (error) {\n                retVal.error = error;\n            }\n            if (cbArgs.length > 0){\n                var value = cbArgs;\n                if (cbArgs.length <= 1) {\n                    [value] = cbArgs;\n                }\n                retVal.value = value;\n            }\n            reflectCallback(null, retVal);\n        });\n\n        return _fn.apply(this, args);\n    });\n}\n\n/**\n * A helper function that wraps an array or an object of functions with `reflect`.\n *\n * @name reflectAll\n * @static\n * @memberOf module:Utils\n * @method\n * @see [async.reflect]{@link module:Utils.reflect}\n * @category Util\n * @param {Array|Object|Iterable} tasks - The collection of\n * [async functions]{@link AsyncFunction} to wrap in `async.reflect`.\n * @returns {Array} Returns an array of async functions, each wrapped in\n * `async.reflect`\n * @example\n *\n * let tasks = [\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         // do some more stuff but error ...\n *         callback(new Error('bad stuff happened'));\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ];\n *\n * async.parallel(async.reflectAll(tasks),\n * // optional callback\n * function(err, results) {\n *     // values\n *     // results[0].value = 'one'\n *     // results[1].error = Error('bad stuff happened')\n *     // results[2].value = 'two'\n * });\n *\n * // an example using an object instead of an array\n * let tasks = {\n *     one: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     two: function(callback) {\n *         callback('two');\n *     },\n *     three: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'three');\n *         }, 100);\n *     }\n * };\n *\n * async.parallel(async.reflectAll(tasks),\n * // optional callback\n * function(err, results) {\n *     // values\n *     // results.one.value = 'one'\n *     // results.two.error = 'two'\n *     // results.three.value = 'three'\n * });\n */\nfunction reflectAll(tasks) {\n    var results;\n    if (Array.isArray(tasks)) {\n        results = tasks.map(reflect);\n    } else {\n        results = {};\n        Object.keys(tasks).forEach(key => {\n            results[key] = reflect.call(this, tasks[key]);\n        });\n    }\n    return results;\n}\n\nfunction reject(eachfn, arr, _iteratee, callback) {\n    const iteratee = wrapAsync(_iteratee);\n    return _filter(eachfn, arr, (value, cb) => {\n        iteratee(value, (err, v) => {\n            cb(err, !v);\n        });\n    }, callback);\n}\n\n/**\n * The opposite of [`filter`]{@link module:Collections.filter}. Removes values that pass an `async` truth test.\n *\n * @name reject\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.filter]{@link module:Collections.filter}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - An async truth test to apply to each item in\n * `coll`.\n * The should complete with a boolean value as its `result`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n *\n * const fileList = ['dir1/file1.txt','dir2/file3.txt','dir3/file6.txt'];\n *\n * // asynchronous function that checks if a file exists\n * function fileExists(file, callback) {\n *    fs.access(file, fs.constants.F_OK, (err) => {\n *        callback(null, !err);\n *    });\n * }\n *\n * // Using callbacks\n * async.reject(fileList, fileExists, function(err, results) {\n *    // [ 'dir3/file6.txt' ]\n *    // results now equals an array of the non-existing files\n * });\n *\n * // Using Promises\n * async.reject(fileList, fileExists)\n * .then( results => {\n *     console.log(results);\n *     // [ 'dir3/file6.txt' ]\n *     // results now equals an array of the non-existing files\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let results = await async.reject(fileList, fileExists);\n *         console.log(results);\n *         // [ 'dir3/file6.txt' ]\n *         // results now equals an array of the non-existing files\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction reject$1 (coll, iteratee, callback) {\n    return reject(eachOf$1, coll, iteratee, callback)\n}\nvar reject$2 = awaitify(reject$1, 3);\n\n/**\n * The same as [`reject`]{@link module:Collections.reject} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name rejectLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.reject]{@link module:Collections.reject}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {Function} iteratee - An async truth test to apply to each item in\n * `coll`.\n * The should complete with a boolean value as its `result`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction rejectLimit (coll, limit, iteratee, callback) {\n    return reject(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar rejectLimit$1 = awaitify(rejectLimit, 4);\n\n/**\n * The same as [`reject`]{@link module:Collections.reject} but runs only a single async operation at a time.\n *\n * @name rejectSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.reject]{@link module:Collections.reject}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - An async truth test to apply to each item in\n * `coll`.\n * The should complete with a boolean value as its `result`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction rejectSeries (coll, iteratee, callback) {\n    return reject(eachOfSeries$1, coll, iteratee, callback)\n}\nvar rejectSeries$1 = awaitify(rejectSeries, 3);\n\nfunction constant$1(value) {\n    return function () {\n        return value;\n    }\n}\n\n/**\n * Attempts to get a successful response from `task` no more than `times` times\n * before returning an error. If the task is successful, the `callback` will be\n * passed the result of the successful task. If all attempts fail, the callback\n * will be passed the error and result (if any) of the final attempt.\n *\n * @name retry\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @see [async.retryable]{@link module:ControlFlow.retryable}\n * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - Can be either an\n * object with `times` and `interval` or a number.\n * * `times` - The number of attempts to make before giving up.  The default\n *   is `5`.\n * * `interval` - The time to wait between retries, in milliseconds.  The\n *   default is `0`. The interval may also be specified as a function of the\n *   retry count (see example).\n * * `errorFilter` - An optional synchronous function that is invoked on\n *   erroneous result. If it returns `true` the retry attempts will continue;\n *   if the function returns `false` the retry flow is aborted with the current\n *   attempt's error and result being returned to the final callback.\n *   Invoked with (err).\n * * If `opts` is a number, the number specifies the number of times to retry,\n *   with the default interval of `0`.\n * @param {AsyncFunction} task - An async function to retry.\n * Invoked with (callback).\n * @param {Function} [callback] - An optional callback which is called when the\n * task has succeeded, or after the final failed attempt. It receives the `err`\n * and `result` arguments of the last attempt at completing the `task`. Invoked\n * with (err, results).\n * @returns {Promise} a promise if no callback provided\n *\n * @example\n *\n * // The `retry` function can be used as a stand-alone control flow by passing\n * // a callback, as shown below:\n *\n * // try calling apiMethod 3 times\n * async.retry(3, apiMethod, function(err, result) {\n *     // do something with the result\n * });\n *\n * // try calling apiMethod 3 times, waiting 200 ms between each retry\n * async.retry({times: 3, interval: 200}, apiMethod, function(err, result) {\n *     // do something with the result\n * });\n *\n * // try calling apiMethod 10 times with exponential backoff\n * // (i.e. intervals of 100, 200, 400, 800, 1600, ... milliseconds)\n * async.retry({\n *   times: 10,\n *   interval: function(retryCount) {\n *     return 50 * Math.pow(2, retryCount);\n *   }\n * }, apiMethod, function(err, result) {\n *     // do something with the result\n * });\n *\n * // try calling apiMethod the default 5 times no delay between each retry\n * async.retry(apiMethod, function(err, result) {\n *     // do something with the result\n * });\n *\n * // try calling apiMethod only when error condition satisfies, all other\n * // errors will abort the retry control flow and return to final callback\n * async.retry({\n *   errorFilter: function(err) {\n *     return err.message === 'Temporary error'; // only retry on a specific error\n *   }\n * }, apiMethod, function(err, result) {\n *     // do something with the result\n * });\n *\n * // to retry individual methods that are not as reliable within other\n * // control flow functions, use the `retryable` wrapper:\n * async.auto({\n *     users: api.getUsers.bind(api),\n *     payments: async.retryable(3, api.getPayments.bind(api))\n * }, function(err, results) {\n *     // do something with the results\n * });\n *\n */\nconst DEFAULT_TIMES = 5;\nconst DEFAULT_INTERVAL = 0;\n\nfunction retry(opts, task, callback) {\n    var options = {\n        times: DEFAULT_TIMES,\n        intervalFunc: constant$1(DEFAULT_INTERVAL)\n    };\n\n    if (arguments.length < 3 && typeof opts === 'function') {\n        callback = task || promiseCallback();\n        task = opts;\n    } else {\n        parseTimes(options, opts);\n        callback = callback || promiseCallback();\n    }\n\n    if (typeof task !== 'function') {\n        throw new Error(\"Invalid arguments for async.retry\");\n    }\n\n    var _task = wrapAsync(task);\n\n    var attempt = 1;\n    function retryAttempt() {\n        _task((err, ...args) => {\n            if (err === false) return\n            if (err && attempt++ < options.times &&\n                (typeof options.errorFilter != 'function' ||\n                    options.errorFilter(err))) {\n                setTimeout(retryAttempt, options.intervalFunc(attempt - 1));\n            } else {\n                callback(err, ...args);\n            }\n        });\n    }\n\n    retryAttempt();\n    return callback[PROMISE_SYMBOL]\n}\n\nfunction parseTimes(acc, t) {\n    if (typeof t === 'object') {\n        acc.times = +t.times || DEFAULT_TIMES;\n\n        acc.intervalFunc = typeof t.interval === 'function' ?\n            t.interval :\n            constant$1(+t.interval || DEFAULT_INTERVAL);\n\n        acc.errorFilter = t.errorFilter;\n    } else if (typeof t === 'number' || typeof t === 'string') {\n        acc.times = +t || DEFAULT_TIMES;\n    } else {\n        throw new Error(\"Invalid arguments for async.retry\");\n    }\n}\n\n/**\n * A close relative of [`retry`]{@link module:ControlFlow.retry}.  This method\n * wraps a task and makes it retryable, rather than immediately calling it\n * with retries.\n *\n * @name retryable\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.retry]{@link module:ControlFlow.retry}\n * @category Control Flow\n * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - optional\n * options, exactly the same as from `retry`, except for a `opts.arity` that\n * is the arity of the `task` function, defaulting to `task.length`\n * @param {AsyncFunction} task - the asynchronous function to wrap.\n * This function will be passed any arguments passed to the returned wrapper.\n * Invoked with (...args, callback).\n * @returns {AsyncFunction} The wrapped function, which when invoked, will\n * retry on an error, based on the parameters specified in `opts`.\n * This function will accept the same parameters as `task`.\n * @example\n *\n * async.auto({\n *     dep1: async.retryable(3, getFromFlakyService),\n *     process: [\"dep1\", async.retryable(3, function (results, cb) {\n *         maybeProcessData(results.dep1, cb);\n *     })]\n * }, callback);\n */\nfunction retryable (opts, task) {\n    if (!task) {\n        task = opts;\n        opts = null;\n    }\n    let arity = (opts && opts.arity) || task.length;\n    if (isAsync(task)) {\n        arity += 1;\n    }\n    var _task = wrapAsync(task);\n    return initialParams((args, callback) => {\n        if (args.length < arity - 1 || callback == null) {\n            args.push(callback);\n            callback = promiseCallback();\n        }\n        function taskFn(cb) {\n            _task(...args, cb);\n        }\n\n        if (opts) retry(opts, taskFn, callback);\n        else retry(taskFn, callback);\n\n        return callback[PROMISE_SYMBOL]\n    });\n}\n\n/**\n * Run the functions in the `tasks` collection in series, each one running once\n * the previous function has completed. If any functions in the series pass an\n * error to its callback, no more functions are run, and `callback` is\n * immediately called with the value of the error. Otherwise, `callback`\n * receives an array of results when `tasks` have completed.\n *\n * It is also possible to use an object instead of an array. Each property will\n * be run as a function, and the results will be passed to the final `callback`\n * as an object instead of an array. This can be a more readable way of handling\n *  results from {@link async.series}.\n *\n * **Note** that while many implementations preserve the order of object\n * properties, the [ECMAScript Language Specification](http://www.ecma-international.org/ecma-262/5.1/#sec-8.6)\n * explicitly states that\n *\n * > The mechanics and order of enumerating the properties is not specified.\n *\n * So if you rely on the order in which your series of functions are executed,\n * and want this to work on all platforms, consider using an array.\n *\n * @name series\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} tasks - A collection containing\n * [async functions]{@link AsyncFunction} to run in series.\n * Each function can complete with any number of optional `result` values.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed. This function gets a results array (or object)\n * containing all the result arguments passed to the `task` callbacks. Invoked\n * with (err, result).\n * @return {Promise} a promise, if no callback is passed\n * @example\n *\n * //Using Callbacks\n * async.series([\n *     function(callback) {\n *         setTimeout(function() {\n *             // do some async task\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             // then do another async task\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ], function(err, results) {\n *     console.log(results);\n *     // results is equal to ['one','two']\n * });\n *\n * // an example using objects instead of arrays\n * async.series({\n *     one: function(callback) {\n *         setTimeout(function() {\n *             // do some async task\n *             callback(null, 1);\n *         }, 200);\n *     },\n *     two: function(callback) {\n *         setTimeout(function() {\n *             // then do another async task\n *             callback(null, 2);\n *         }, 100);\n *     }\n * }, function(err, results) {\n *     console.log(results);\n *     // results is equal to: { one: 1, two: 2 }\n * });\n *\n * //Using Promises\n * async.series([\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ]).then(results => {\n *     console.log(results);\n *     // results is equal to ['one','two']\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // an example using an object instead of an array\n * async.series({\n *     one: function(callback) {\n *         setTimeout(function() {\n *             // do some async task\n *             callback(null, 1);\n *         }, 200);\n *     },\n *     two: function(callback) {\n *         setTimeout(function() {\n *             // then do another async task\n *             callback(null, 2);\n *         }, 100);\n *     }\n * }).then(results => {\n *     console.log(results);\n *     // results is equal to: { one: 1, two: 2 }\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * //Using async/await\n * async () => {\n *     try {\n *         let results = await async.series([\n *             function(callback) {\n *                 setTimeout(function() {\n *                     // do some async task\n *                     callback(null, 'one');\n *                 }, 200);\n *             },\n *             function(callback) {\n *                 setTimeout(function() {\n *                     // then do another async task\n *                     callback(null, 'two');\n *                 }, 100);\n *             }\n *         ]);\n *         console.log(results);\n *         // results is equal to ['one','two']\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // an example using an object instead of an array\n * async () => {\n *     try {\n *         let results = await async.parallel({\n *             one: function(callback) {\n *                 setTimeout(function() {\n *                     // do some async task\n *                     callback(null, 1);\n *                 }, 200);\n *             },\n *            two: function(callback) {\n *                 setTimeout(function() {\n *                     // then do another async task\n *                     callback(null, 2);\n *                 }, 100);\n *            }\n *         });\n *         console.log(results);\n *         // results is equal to: { one: 1, two: 2 }\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction series(tasks, callback) {\n    return _parallel(eachOfSeries$1, tasks, callback);\n}\n\n/**\n * Returns `true` if at least one element in the `coll` satisfies an async test.\n * If any iteratee call returns `true`, the main `callback` is immediately\n * called.\n *\n * @name some\n * @static\n * @memberOf module:Collections\n * @method\n * @alias any\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collections in parallel.\n * The iteratee should complete with a boolean `result` value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the iteratee functions have finished.\n * Result will be either `true` or `false` depending on the values of the async\n * tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n * // dir4 does not exist\n *\n * // asynchronous function that checks if a file exists\n * function fileExists(file, callback) {\n *    fs.access(file, fs.constants.F_OK, (err) => {\n *        callback(null, !err);\n *    });\n * }\n *\n * // Using callbacks\n * async.some(['dir1/missing.txt','dir2/missing.txt','dir3/file5.txt'], fileExists,\n *    function(err, result) {\n *        console.log(result);\n *        // true\n *        // result is true since some file in the list exists\n *    }\n *);\n *\n * async.some(['dir1/missing.txt','dir2/missing.txt','dir4/missing.txt'], fileExists,\n *    function(err, result) {\n *        console.log(result);\n *        // false\n *        // result is false since none of the files exists\n *    }\n *);\n *\n * // Using Promises\n * async.some(['dir1/missing.txt','dir2/missing.txt','dir3/file5.txt'], fileExists)\n * .then( result => {\n *     console.log(result);\n *     // true\n *     // result is true since some file in the list exists\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * async.some(['dir1/missing.txt','dir2/missing.txt','dir4/missing.txt'], fileExists)\n * .then( result => {\n *     console.log(result);\n *     // false\n *     // result is false since none of the files exists\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.some(['dir1/missing.txt','dir2/missing.txt','dir3/file5.txt'], fileExists);\n *         console.log(result);\n *         // true\n *         // result is true since some file in the list exists\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * async () => {\n *     try {\n *         let result = await async.some(['dir1/missing.txt','dir2/missing.txt','dir4/missing.txt'], fileExists);\n *         console.log(result);\n *         // false\n *         // result is false since none of the files exists\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction some(coll, iteratee, callback) {\n    return _createTester(Boolean, res => res)(eachOf$1, coll, iteratee, callback)\n}\nvar some$1 = awaitify(some, 3);\n\n/**\n * The same as [`some`]{@link module:Collections.some} but runs a maximum of `limit` async operations at a time.\n *\n * @name someLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.some]{@link module:Collections.some}\n * @alias anyLimit\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collections in parallel.\n * The iteratee should complete with a boolean `result` value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the iteratee functions have finished.\n * Result will be either `true` or `false` depending on the values of the async\n * tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n */\nfunction someLimit(coll, limit, iteratee, callback) {\n    return _createTester(Boolean, res => res)(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar someLimit$1 = awaitify(someLimit, 4);\n\n/**\n * The same as [`some`]{@link module:Collections.some} but runs only a single async operation at a time.\n *\n * @name someSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.some]{@link module:Collections.some}\n * @alias anySeries\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collections in series.\n * The iteratee should complete with a boolean `result` value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the iteratee functions have finished.\n * Result will be either `true` or `false` depending on the values of the async\n * tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n */\nfunction someSeries(coll, iteratee, callback) {\n    return _createTester(Boolean, res => res)(eachOfSeries$1, coll, iteratee, callback)\n}\nvar someSeries$1 = awaitify(someSeries, 3);\n\n/**\n * Sorts a list by the results of running each `coll` value through an async\n * `iteratee`.\n *\n * @name sortBy\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a value to use as the sort criteria as\n * its `result`.\n * Invoked with (item, callback).\n * @param {Function} callback - A callback which is called after all the\n * `iteratee` functions have finished, or an error occurs. Results is the items\n * from the original `coll` sorted by the values returned by the `iteratee`\n * calls. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback passed\n * @example\n *\n * // bigfile.txt is a file that is 251100 bytes in size\n * // mediumfile.txt is a file that is 11000 bytes in size\n * // smallfile.txt is a file that is 121 bytes in size\n *\n * // asynchronous function that returns the file size in bytes\n * function getFileSizeInBytes(file, callback) {\n *     fs.stat(file, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         callback(null, stat.size);\n *     });\n * }\n *\n * // Using callbacks\n * async.sortBy(['mediumfile.txt','smallfile.txt','bigfile.txt'], getFileSizeInBytes,\n *     function(err, results) {\n *         if (err) {\n *             console.log(err);\n *         } else {\n *             console.log(results);\n *             // results is now the original array of files sorted by\n *             // file size (ascending by default), e.g.\n *             // [ 'smallfile.txt', 'mediumfile.txt', 'bigfile.txt']\n *         }\n *     }\n * );\n *\n * // By modifying the callback parameter the\n * // sorting order can be influenced:\n *\n * // ascending order\n * async.sortBy(['mediumfile.txt','smallfile.txt','bigfile.txt'], function(file, callback) {\n *     getFileSizeInBytes(file, function(getFileSizeErr, fileSize) {\n *         if (getFileSizeErr) return callback(getFileSizeErr);\n *         callback(null, fileSize);\n *     });\n * }, function(err, results) {\n *         if (err) {\n *             console.log(err);\n *         } else {\n *             console.log(results);\n *             // results is now the original array of files sorted by\n *             // file size (ascending by default), e.g.\n *             // [ 'smallfile.txt', 'mediumfile.txt', 'bigfile.txt']\n *         }\n *     }\n * );\n *\n * // descending order\n * async.sortBy(['bigfile.txt','mediumfile.txt','smallfile.txt'], function(file, callback) {\n *     getFileSizeInBytes(file, function(getFileSizeErr, fileSize) {\n *         if (getFileSizeErr) {\n *             return callback(getFileSizeErr);\n *         }\n *         callback(null, fileSize * -1);\n *     });\n * }, function(err, results) {\n *         if (err) {\n *             console.log(err);\n *         } else {\n *             console.log(results);\n *             // results is now the original array of files sorted by\n *             // file size (ascending by default), e.g.\n *             // [ 'bigfile.txt', 'mediumfile.txt', 'smallfile.txt']\n *         }\n *     }\n * );\n *\n * // Error handling\n * async.sortBy(['mediumfile.txt','smallfile.txt','missingfile.txt'], getFileSizeInBytes,\n *     function(err, results) {\n *         if (err) {\n *             console.log(err);\n *             // [ Error: ENOENT: no such file or directory ]\n *         } else {\n *             console.log(results);\n *         }\n *     }\n * );\n *\n * // Using Promises\n * async.sortBy(['mediumfile.txt','smallfile.txt','bigfile.txt'], getFileSizeInBytes)\n * .then( results => {\n *     console.log(results);\n *     // results is now the original array of files sorted by\n *     // file size (ascending by default), e.g.\n *     // [ 'smallfile.txt', 'mediumfile.txt', 'bigfile.txt']\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Error handling\n * async.sortBy(['mediumfile.txt','smallfile.txt','missingfile.txt'], getFileSizeInBytes)\n * .then( results => {\n *     console.log(results);\n * }).catch( err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n * });\n *\n * // Using async/await\n * (async () => {\n *     try {\n *         let results = await async.sortBy(['bigfile.txt','mediumfile.txt','smallfile.txt'], getFileSizeInBytes);\n *         console.log(results);\n *         // results is now the original array of files sorted by\n *         // file size (ascending by default), e.g.\n *         // [ 'smallfile.txt', 'mediumfile.txt', 'bigfile.txt']\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * })();\n *\n * // Error handling\n * async () => {\n *     try {\n *         let results = await async.sortBy(['missingfile.txt','mediumfile.txt','smallfile.txt'], getFileSizeInBytes);\n *         console.log(results);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     }\n * }\n *\n */\nfunction sortBy (coll, iteratee, callback) {\n    var _iteratee = wrapAsync(iteratee);\n    return map$1(coll, (x, iterCb) => {\n        _iteratee(x, (err, criteria) => {\n            if (err) return iterCb(err);\n            iterCb(err, {value: x, criteria});\n        });\n    }, (err, results) => {\n        if (err) return callback(err);\n        callback(null, results.sort(comparator).map(v => v.value));\n    });\n\n    function comparator(left, right) {\n        var a = left.criteria, b = right.criteria;\n        return a < b ? -1 : a > b ? 1 : 0;\n    }\n}\nvar sortBy$1 = awaitify(sortBy, 3);\n\n/**\n * Sets a time limit on an asynchronous function. If the function does not call\n * its callback within the specified milliseconds, it will be called with a\n * timeout error. The code property for the error object will be `'ETIMEDOUT'`.\n *\n * @name timeout\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} asyncFn - The async function to limit in time.\n * @param {number} milliseconds - The specified time limit.\n * @param {*} [info] - Any variable you want attached (`string`, `object`, etc)\n * to timeout Error for more information..\n * @returns {AsyncFunction} Returns a wrapped function that can be used with any\n * of the control flow functions.\n * Invoke this function with the same parameters as you would `asyncFunc`.\n * @example\n *\n * function myFunction(foo, callback) {\n *     doAsyncTask(foo, function(err, data) {\n *         // handle errors\n *         if (err) return callback(err);\n *\n *         // do some stuff ...\n *\n *         // return processed data\n *         return callback(null, data);\n *     });\n * }\n *\n * var wrapped = async.timeout(myFunction, 1000);\n *\n * // call `wrapped` as you would `myFunction`\n * wrapped({ bar: 'bar' }, function(err, data) {\n *     // if `myFunction` takes < 1000 ms to execute, `err`\n *     // and `data` will have their expected values\n *\n *     // else `err` will be an Error with the code 'ETIMEDOUT'\n * });\n */\nfunction timeout(asyncFn, milliseconds, info) {\n    var fn = wrapAsync(asyncFn);\n\n    return initialParams((args, callback) => {\n        var timedOut = false;\n        var timer;\n\n        function timeoutCallback() {\n            var name = asyncFn.name || 'anonymous';\n            var error  = new Error('Callback function \"' + name + '\" timed out.');\n            error.code = 'ETIMEDOUT';\n            if (info) {\n                error.info = info;\n            }\n            timedOut = true;\n            callback(error);\n        }\n\n        args.push((...cbArgs) => {\n            if (!timedOut) {\n                callback(...cbArgs);\n                clearTimeout(timer);\n            }\n        });\n\n        // setup timer and call original function\n        timer = setTimeout(timeoutCallback, milliseconds);\n        fn(...args);\n    });\n}\n\nfunction range(size) {\n    var result = Array(size);\n    while (size--) {\n        result[size] = size;\n    }\n    return result;\n}\n\n/**\n * The same as [times]{@link module:ControlFlow.times} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name timesLimit\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.times]{@link module:ControlFlow.times}\n * @category Control Flow\n * @param {number} count - The number of times to run the function.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - The async function to call `n` times.\n * Invoked with the iteration index and a callback: (n, next).\n * @param {Function} callback - see [async.map]{@link module:Collections.map}.\n * @returns {Promise} a promise, if no callback is provided\n */\nfunction timesLimit(count, limit, iteratee, callback) {\n    var _iteratee = wrapAsync(iteratee);\n    return mapLimit$1(range(count), limit, _iteratee, callback);\n}\n\n/**\n * Calls the `iteratee` function `n` times, and accumulates results in the same\n * manner you would use with [map]{@link module:Collections.map}.\n *\n * @name times\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.map]{@link module:Collections.map}\n * @category Control Flow\n * @param {number} n - The number of times to run the function.\n * @param {AsyncFunction} iteratee - The async function to call `n` times.\n * Invoked with the iteration index and a callback: (n, next).\n * @param {Function} callback - see {@link module:Collections.map}.\n * @returns {Promise} a promise, if no callback is provided\n * @example\n *\n * // Pretend this is some complicated async factory\n * var createUser = function(id, callback) {\n *     callback(null, {\n *         id: 'user' + id\n *     });\n * };\n *\n * // generate 5 users\n * async.times(5, function(n, next) {\n *     createUser(n, function(err, user) {\n *         next(err, user);\n *     });\n * }, function(err, users) {\n *     // we should now have 5 users\n * });\n */\nfunction times (n, iteratee, callback) {\n    return timesLimit(n, Infinity, iteratee, callback)\n}\n\n/**\n * The same as [times]{@link module:ControlFlow.times} but runs only a single async operation at a time.\n *\n * @name timesSeries\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.times]{@link module:ControlFlow.times}\n * @category Control Flow\n * @param {number} n - The number of times to run the function.\n * @param {AsyncFunction} iteratee - The async function to call `n` times.\n * Invoked with the iteration index and a callback: (n, next).\n * @param {Function} callback - see {@link module:Collections.map}.\n * @returns {Promise} a promise, if no callback is provided\n */\nfunction timesSeries (n, iteratee, callback) {\n    return timesLimit(n, 1, iteratee, callback)\n}\n\n/**\n * A relative of `reduce`.  Takes an Object or Array, and iterates over each\n * element in parallel, each step potentially mutating an `accumulator` value.\n * The type of the accumulator defaults to the type of collection passed in.\n *\n * @name transform\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {*} [accumulator] - The initial state of the transform.  If omitted,\n * it will default to an empty Object or Array, depending on the type of `coll`\n * @param {AsyncFunction} iteratee - A function applied to each item in the\n * collection that potentially modifies the accumulator.\n * Invoked with (accumulator, item, key, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result is the transformed accumulator.\n * Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n * @example\n *\n * // file1.txt is a file that is 1000 bytes in size\n * // file2.txt is a file that is 2000 bytes in size\n * // file3.txt is a file that is 3000 bytes in size\n *\n * // helper function that returns human-readable size format from bytes\n * function formatBytes(bytes, decimals = 2) {\n *   // implementation not included for brevity\n *   return humanReadbleFilesize;\n * }\n *\n * const fileList = ['file1.txt','file2.txt','file3.txt'];\n *\n * // asynchronous function that returns the file size, transformed to human-readable format\n * // e.g. 1024 bytes = 1KB, 1234 bytes = 1.21 KB, 1048576 bytes = 1MB, etc.\n * function transformFileSize(acc, value, key, callback) {\n *     fs.stat(value, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         acc[key] = formatBytes(stat.size);\n *         callback(null);\n *     });\n * }\n *\n * // Using callbacks\n * async.transform(fileList, transformFileSize, function(err, result) {\n *     if(err) {\n *         console.log(err);\n *     } else {\n *         console.log(result);\n *         // [ '1000 Bytes', '1.95 KB', '2.93 KB' ]\n *     }\n * });\n *\n * // Using Promises\n * async.transform(fileList, transformFileSize)\n * .then(result => {\n *     console.log(result);\n *     // [ '1000 Bytes', '1.95 KB', '2.93 KB' ]\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * (async () => {\n *     try {\n *         let result = await async.transform(fileList, transformFileSize);\n *         console.log(result);\n *         // [ '1000 Bytes', '1.95 KB', '2.93 KB' ]\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * })();\n *\n * @example\n *\n * // file1.txt is a file that is 1000 bytes in size\n * // file2.txt is a file that is 2000 bytes in size\n * // file3.txt is a file that is 3000 bytes in size\n *\n * // helper function that returns human-readable size format from bytes\n * function formatBytes(bytes, decimals = 2) {\n *   // implementation not included for brevity\n *   return humanReadbleFilesize;\n * }\n *\n * const fileMap = { f1: 'file1.txt', f2: 'file2.txt', f3: 'file3.txt' };\n *\n * // asynchronous function that returns the file size, transformed to human-readable format\n * // e.g. 1024 bytes = 1KB, 1234 bytes = 1.21 KB, 1048576 bytes = 1MB, etc.\n * function transformFileSize(acc, value, key, callback) {\n *     fs.stat(value, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         acc[key] = formatBytes(stat.size);\n *         callback(null);\n *     });\n * }\n *\n * // Using callbacks\n * async.transform(fileMap, transformFileSize, function(err, result) {\n *     if(err) {\n *         console.log(err);\n *     } else {\n *         console.log(result);\n *         // { f1: '1000 Bytes', f2: '1.95 KB', f3: '2.93 KB' }\n *     }\n * });\n *\n * // Using Promises\n * async.transform(fileMap, transformFileSize)\n * .then(result => {\n *     console.log(result);\n *     // { f1: '1000 Bytes', f2: '1.95 KB', f3: '2.93 KB' }\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.transform(fileMap, transformFileSize);\n *         console.log(result);\n *         // { f1: '1000 Bytes', f2: '1.95 KB', f3: '2.93 KB' }\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction transform (coll, accumulator, iteratee, callback) {\n    if (arguments.length <= 3 && typeof accumulator === 'function') {\n        callback = iteratee;\n        iteratee = accumulator;\n        accumulator = Array.isArray(coll) ? [] : {};\n    }\n    callback = once(callback || promiseCallback());\n    var _iteratee = wrapAsync(iteratee);\n\n    eachOf$1(coll, (v, k, cb) => {\n        _iteratee(accumulator, v, k, cb);\n    }, err => callback(err, accumulator));\n    return callback[PROMISE_SYMBOL]\n}\n\n/**\n * It runs each task in series but stops whenever any of the functions were\n * successful. If one of the tasks were successful, the `callback` will be\n * passed the result of the successful task. If all tasks fail, the callback\n * will be passed the error and result (if any) of the final attempt.\n *\n * @name tryEach\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} tasks - A collection containing functions to\n * run, each function is passed a `callback(err, result)` it must call on\n * completion with an error `err` (which can be `null`) and an optional `result`\n * value.\n * @param {Function} [callback] - An optional callback which is called when one\n * of the tasks has succeeded, or all have failed. It receives the `err` and\n * `result` arguments of the last attempt at completing the `task`. Invoked with\n * (err, results).\n * @returns {Promise} a promise, if no callback is passed\n * @example\n * async.tryEach([\n *     function getDataFromFirstWebsite(callback) {\n *         // Try getting the data from the first website\n *         callback(err, data);\n *     },\n *     function getDataFromSecondWebsite(callback) {\n *         // First website failed,\n *         // Try getting the data from the backup website\n *         callback(err, data);\n *     }\n * ],\n * // optional callback\n * function(err, results) {\n *     Now do something with the data.\n * });\n *\n */\nfunction tryEach(tasks, callback) {\n    var error = null;\n    var result;\n    return eachSeries$1(tasks, (task, taskCb) => {\n        wrapAsync(task)((err, ...args) => {\n            if (err === false) return taskCb(err);\n\n            if (args.length < 2) {\n                [result] = args;\n            } else {\n                result = args;\n            }\n            error = err;\n            taskCb(err ? null : {});\n        });\n    }, () => callback(error, result));\n}\n\nvar tryEach$1 = awaitify(tryEach);\n\n/**\n * Undoes a [memoize]{@link module:Utils.memoize}d function, reverting it to the original,\n * unmemoized form. Handy for testing.\n *\n * @name unmemoize\n * @static\n * @memberOf module:Utils\n * @method\n * @see [async.memoize]{@link module:Utils.memoize}\n * @category Util\n * @param {AsyncFunction} fn - the memoized function\n * @returns {AsyncFunction} a function that calls the original unmemoized function\n */\nfunction unmemoize(fn) {\n    return (...args) => {\n        return (fn.unmemoized || fn)(...args);\n    };\n}\n\n/**\n * Repeatedly call `iteratee`, while `test` returns `true`. Calls `callback` when\n * stopped, or an error occurs.\n *\n * @name whilst\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {AsyncFunction} test - asynchronous truth test to perform before each\n * execution of `iteratee`. Invoked with ().\n * @param {AsyncFunction} iteratee - An async function which is called each time\n * `test` passes. Invoked with (callback).\n * @param {Function} [callback] - A callback which is called after the test\n * function has failed and repeated execution of `iteratee` has stopped. `callback`\n * will be passed an error and any arguments passed to the final `iteratee`'s\n * callback. Invoked with (err, [results]);\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * var count = 0;\n * async.whilst(\n *     function test(cb) { cb(null, count < 5); },\n *     function iter(callback) {\n *         count++;\n *         setTimeout(function() {\n *             callback(null, count);\n *         }, 1000);\n *     },\n *     function (err, n) {\n *         // 5 seconds have passed, n = 5\n *     }\n * );\n */\nfunction whilst(test, iteratee, callback) {\n    callback = onlyOnce(callback);\n    var _fn = wrapAsync(iteratee);\n    var _test = wrapAsync(test);\n    var results = [];\n\n    function next(err, ...rest) {\n        if (err) return callback(err);\n        results = rest;\n        if (err === false) return;\n        _test(check);\n    }\n\n    function check(err, truth) {\n        if (err) return callback(err);\n        if (err === false) return;\n        if (!truth) return callback(null, ...results);\n        _fn(next);\n    }\n\n    return _test(check);\n}\nvar whilst$1 = awaitify(whilst, 3);\n\n/**\n * Repeatedly call `iteratee` until `test` returns `true`. Calls `callback` when\n * stopped, or an error occurs. `callback` will be passed an error and any\n * arguments passed to the final `iteratee`'s callback.\n *\n * The inverse of [whilst]{@link module:ControlFlow.whilst}.\n *\n * @name until\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.whilst]{@link module:ControlFlow.whilst}\n * @category Control Flow\n * @param {AsyncFunction} test - asynchronous truth test to perform before each\n * execution of `iteratee`. Invoked with (callback).\n * @param {AsyncFunction} iteratee - An async function which is called each time\n * `test` fails. Invoked with (callback).\n * @param {Function} [callback] - A callback which is called after the test\n * function has passed and repeated execution of `iteratee` has stopped. `callback`\n * will be passed an error and any arguments passed to the final `iteratee`'s\n * callback. Invoked with (err, [results]);\n * @returns {Promise} a promise, if a callback is not passed\n *\n * @example\n * const results = []\n * let finished = false\n * async.until(function test(cb) {\n *     cb(null, finished)\n * }, function iter(next) {\n *     fetchPage(url, (err, body) => {\n *         if (err) return next(err)\n *         results = results.concat(body.objects)\n *         finished = !!body.next\n *         next(err)\n *     })\n * }, function done (err) {\n *     // all pages have been fetched\n * })\n */\nfunction until(test, iteratee, callback) {\n    const _test = wrapAsync(test);\n    return whilst$1((cb) => _test((err, truth) => cb (err, !truth)), iteratee, callback);\n}\n\n/**\n * Runs the `tasks` array of functions in series, each passing their results to\n * the next in the array. However, if any of the `tasks` pass an error to their\n * own callback, the next function is not executed, and the main `callback` is\n * immediately called with the error.\n *\n * @name waterfall\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array} tasks - An array of [async functions]{@link AsyncFunction}\n * to run.\n * Each function should complete with any number of `result` values.\n * The `result` values will be passed as arguments, in order, to the next task.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed. This will be passed the results of the last task's\n * callback. Invoked with (err, [results]).\n * @returns undefined\n * @example\n *\n * async.waterfall([\n *     function(callback) {\n *         callback(null, 'one', 'two');\n *     },\n *     function(arg1, arg2, callback) {\n *         // arg1 now equals 'one' and arg2 now equals 'two'\n *         callback(null, 'three');\n *     },\n *     function(arg1, callback) {\n *         // arg1 now equals 'three'\n *         callback(null, 'done');\n *     }\n * ], function (err, result) {\n *     // result now equals 'done'\n * });\n *\n * // Or, with named functions:\n * async.waterfall([\n *     myFirstFunction,\n *     mySecondFunction,\n *     myLastFunction,\n * ], function (err, result) {\n *     // result now equals 'done'\n * });\n * function myFirstFunction(callback) {\n *     callback(null, 'one', 'two');\n * }\n * function mySecondFunction(arg1, arg2, callback) {\n *     // arg1 now equals 'one' and arg2 now equals 'two'\n *     callback(null, 'three');\n * }\n * function myLastFunction(arg1, callback) {\n *     // arg1 now equals 'three'\n *     callback(null, 'done');\n * }\n */\nfunction waterfall (tasks, callback) {\n    callback = once(callback);\n    if (!Array.isArray(tasks)) return callback(new Error('First argument to waterfall must be an array of functions'));\n    if (!tasks.length) return callback();\n    var taskIndex = 0;\n\n    function nextTask(args) {\n        var task = wrapAsync(tasks[taskIndex++]);\n        task(...args, onlyOnce(next));\n    }\n\n    function next(err, ...args) {\n        if (err === false) return\n        if (err || taskIndex === tasks.length) {\n            return callback(err, ...args);\n        }\n        nextTask(args);\n    }\n\n    nextTask([]);\n}\n\nvar waterfall$1 = awaitify(waterfall);\n\n/**\n * An \"async function\" in the context of Async is an asynchronous function with\n * a variable number of parameters, with the final parameter being a callback.\n * (`function (arg1, arg2, ..., callback) {}`)\n * The final callback is of the form `callback(err, results...)`, which must be\n * called once the function is completed.  The callback should be called with a\n * Error as its first argument to signal that an error occurred.\n * Otherwise, if no error occurred, it should be called with `null` as the first\n * argument, and any additional `result` arguments that may apply, to signal\n * successful completion.\n * The callback must be called exactly once, ideally on a later tick of the\n * JavaScript event loop.\n *\n * This type of function is also referred to as a \"Node-style async function\",\n * or a \"continuation passing-style function\" (CPS). Most of the methods of this\n * library are themselves CPS/Node-style async functions, or functions that\n * return CPS/Node-style async functions.\n *\n * Wherever we accept a Node-style async function, we also directly accept an\n * [ES2017 `async` function]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function}.\n * In this case, the `async` function will not be passed a final callback\n * argument, and any thrown error will be used as the `err` argument of the\n * implicit callback, and the return value will be used as the `result` value.\n * (i.e. a `rejected` of the returned Promise becomes the `err` callback\n * argument, and a `resolved` value becomes the `result`.)\n *\n * Note, due to JavaScript limitations, we can only detect native `async`\n * functions and not transpilied implementations.\n * Your environment must have `async`/`await` support for this to work.\n * (e.g. Node > v7.6, or a recent version of a modern browser).\n * If you are using `async` functions through a transpiler (e.g. Babel), you\n * must still wrap the function with [asyncify]{@link module:Utils.asyncify},\n * because the `async function` will be compiled to an ordinary function that\n * returns a promise.\n *\n * @typedef {Function} AsyncFunction\n * @static\n */\n\nvar index = {\n    apply,\n    applyEach: applyEach$1,\n    applyEachSeries,\n    asyncify,\n    auto,\n    autoInject,\n    cargo,\n    cargoQueue: cargo$1,\n    compose,\n    concat: concat$1,\n    concatLimit: concatLimit$1,\n    concatSeries: concatSeries$1,\n    constant,\n    detect: detect$1,\n    detectLimit: detectLimit$1,\n    detectSeries: detectSeries$1,\n    dir,\n    doUntil,\n    doWhilst: doWhilst$1,\n    each,\n    eachLimit: eachLimit$2,\n    eachOf: eachOf$1,\n    eachOfLimit: eachOfLimit$2,\n    eachOfSeries: eachOfSeries$1,\n    eachSeries: eachSeries$1,\n    ensureAsync,\n    every: every$1,\n    everyLimit: everyLimit$1,\n    everySeries: everySeries$1,\n    filter: filter$1,\n    filterLimit: filterLimit$1,\n    filterSeries: filterSeries$1,\n    forever: forever$1,\n    groupBy,\n    groupByLimit: groupByLimit$1,\n    groupBySeries,\n    log,\n    map: map$1,\n    mapLimit: mapLimit$1,\n    mapSeries: mapSeries$1,\n    mapValues,\n    mapValuesLimit: mapValuesLimit$1,\n    mapValuesSeries,\n    memoize,\n    nextTick,\n    parallel,\n    parallelLimit,\n    priorityQueue,\n    queue: queue$1,\n    race: race$1,\n    reduce: reduce$1,\n    reduceRight,\n    reflect,\n    reflectAll,\n    reject: reject$2,\n    rejectLimit: rejectLimit$1,\n    rejectSeries: rejectSeries$1,\n    retry,\n    retryable,\n    seq,\n    series,\n    setImmediate: setImmediate$1,\n    some: some$1,\n    someLimit: someLimit$1,\n    someSeries: someSeries$1,\n    sortBy: sortBy$1,\n    timeout,\n    times,\n    timesLimit,\n    timesSeries,\n    transform,\n    tryEach: tryEach$1,\n    unmemoize,\n    until,\n    waterfall: waterfall$1,\n    whilst: whilst$1,\n\n    // aliases\n    all: every$1,\n    allLimit: everyLimit$1,\n    allSeries: everySeries$1,\n    any: some$1,\n    anyLimit: someLimit$1,\n    anySeries: someSeries$1,\n    find: detect$1,\n    findLimit: detectLimit$1,\n    findSeries: detectSeries$1,\n    flatMap: concat$1,\n    flatMapLimit: concatLimit$1,\n    flatMapSeries: concatSeries$1,\n    forEach: each,\n    forEachSeries: eachSeries$1,\n    forEachLimit: eachLimit$2,\n    forEachOf: eachOf$1,\n    forEachOfSeries: eachOfSeries$1,\n    forEachOfLimit: eachOfLimit$2,\n    inject: reduce$1,\n    foldl: reduce$1,\n    foldr: reduceRight,\n    select: filter$1,\n    selectLimit: filterLimit$1,\n    selectSeries: filterSeries$1,\n    wrapSync: asyncify,\n    during: whilst$1,\n    doDuring: doWhilst$1\n};\n\nexport default index;\nexport { apply, applyEach$1 as applyEach, applyEachSeries, asyncify, auto, autoInject, cargo, cargo$1 as cargoQueue, compose, concat$1 as concat, concatLimit$1 as concatLimit, concatSeries$1 as concatSeries, constant, detect$1 as detect, detectLimit$1 as detectLimit, detectSeries$1 as detectSeries, dir, doUntil, doWhilst$1 as doWhilst, each, eachLimit$2 as eachLimit, eachOf$1 as eachOf, eachOfLimit$2 as eachOfLimit, eachOfSeries$1 as eachOfSeries, eachSeries$1 as eachSeries, ensureAsync, every$1 as every, everyLimit$1 as everyLimit, everySeries$1 as everySeries, filter$1 as filter, filterLimit$1 as filterLimit, filterSeries$1 as filterSeries, forever$1 as forever, groupBy, groupByLimit$1 as groupByLimit, groupBySeries, log, map$1 as map, mapLimit$1 as mapLimit, mapSeries$1 as mapSeries, mapValues, mapValuesLimit$1 as mapValuesLimit, mapValuesSeries, memoize, nextTick, parallel, parallelLimit, priorityQueue, queue$1 as queue, race$1 as race, reduce$1 as reduce, reduceRight, reflect, reflectAll, reject$2 as reject, rejectLimit$1 as rejectLimit, rejectSeries$1 as rejectSeries, retry, retryable, seq, series, setImmediate$1 as setImmediate, some$1 as some, someLimit$1 as someLimit, someSeries$1 as someSeries, sortBy$1 as sortBy, timeout, times, timesLimit, timesSeries, transform, tryEach$1 as tryEach, unmemoize, until, waterfall$1 as waterfall, whilst$1 as whilst, every$1 as all, everyLimit$1 as allLimit, everySeries$1 as allSeries, some$1 as any, someLimit$1 as anyLimit, someSeries$1 as anySeries, detect$1 as find, detectLimit$1 as findLimit, detectSeries$1 as findSeries, concat$1 as flatMap, concatLimit$1 as flatMapLimit, concatSeries$1 as flatMapSeries, each as forEach, eachSeries$1 as forEachSeries, eachLimit$2 as forEachLimit, eachOf$1 as forEachOf, eachOfSeries$1 as forEachOfSeries, eachOfLimit$2 as forEachOfLimit, reduce$1 as inject, reduce$1 as foldl, reduceRight as foldr, filter$1 as select, filterLimit$1 as selectLimit, filterSeries$1 as selectSeries, asyncify as wrapSync, whilst$1 as during, doWhilst$1 as doDuring };\n","import { getLogger } from '@jitsi/logger';\nimport { queue } from 'async';\n\nconst logger = getLogger(__filename);\n\n/**\n * A queue for async task execution.\n */\nexport default class AsyncQueue {\n    /**\n     * Creates new instance.\n     */\n    constructor() {\n        this._queue = queue(this._processQueueTasks.bind(this), 1);\n        this._stopped = false;\n    }\n\n    /**\n     * Removes any pending tasks from the queue.\n     */\n    clear() {\n        this._queue.kill();\n    }\n\n    /**\n     * Internal task processing implementation which makes things work.\n     */\n    _processQueueTasks(task, finishedCallback) {\n        try {\n            task(finishedCallback);\n        } catch (error) {\n            logger.error(`Task failed: ${error?.stack}`);\n            finishedCallback(error);\n        }\n    }\n\n    /**\n     * The 'task' function will be given a callback it MUST call with either:\n     *  1) No arguments if it was successful or\n     *  2) An error argument if there was an error\n     * If the task wants to process the success or failure of the task, it\n     * should pass the {@code callback} to the push function, e.g.:\n     * queue.push(task, (err) => {\n     *     if (err) {\n     *         // error handling\n     *     } else {\n     *         // success handling\n     *     }\n     * });\n     *\n     * @param {function} task - The task to be executed. See the description above.\n     * @param {function} [callback] - Optional callback to be called after the task has been executed.\n     */\n    push(task, callback) {\n        if (this._stopped) {\n            callback && callback(new Error('The queue has been stopped'));\n\n            return;\n        }\n        this._queue.push(task, callback);\n    }\n\n    /**\n     * Shutdowns the queue. All already queued tasks will execute, but no future tasks can be added. If a task is added\n     * after the queue has been shutdown then the callback will be called with an error.\n     */\n    shutdown() {\n        this._stopped = true;\n    }\n}\n","export enum JingleSessionState {\n    /**\n     * The pending Jingle session state which means the session as defined in\n     * XEP-0166(before 'session-invite/session-accept' took place).\n     */\n    PENDING = 'pending',\n\n    /**\n     * The active Jingle session state as defined in XEP-0166\n     * (after 'session-invite'/'session-accept').\n     */\n    ACTIVE = 'active',\n\n    /**\n     * The ended Jingle session state as defined in XEP-0166\n     * (after 'session-terminate').\n     */\n    ENDED = 'ended'\n};\n\n// exported for backward compatibility\nexport const PENDING = JingleSessionState.PENDING;\nexport const ACTIVE = JingleSessionState.ACTIVE;\nexport const ENDED = JingleSessionState.ENDED;\n","import { getLogger } from '@jitsi/logger';\n\nimport Listenable from '../util/Listenable';\n\nimport * as JingleSessionState from './JingleSessionState';\n\nconst logger = getLogger(__filename);\n\n/**\n * JingleSession provides an API to manage a single Jingle session. We will\n * have different implementations depending on the underlying interface used\n * (i.e. WebRTC and ORTC) and here we hold the code common to all of them.\n */\nexport default class JingleSession extends Listenable {\n\n    /* eslint-disable max-params */\n\n    /**\n     * Creates new <tt>JingleSession</tt>.\n     * @param {string} sid the Jingle session identifier\n     * @param {string} localJid our JID\n     * @param {string} remoteJid the JID of the remote peer\n     * @param {XmppConnection} connection the XMPP connection\n     * @param {Object} mediaConstraints the media constraints object passed to the PeerConnection onCreateAnswer/Offer.\n     * @param {Object} pcConfig The {@code RTCConfiguration} object passed to the PeerConnection's constructor.\n     * @param {boolean} isInitiator indicates if it will be the side which initiates the session.\n     */\n    constructor(\n            sid,\n            localJid,\n            remoteJid,\n            connection,\n            mediaConstraints,\n            pcConfig,\n            isInitiator) {\n        super();\n        this.sid = sid;\n        this.localJid = localJid;\n        this.remoteJid = remoteJid;\n        this.connection = connection;\n        this.mediaConstraints = mediaConstraints;\n        this.pcConfig = pcConfig;\n\n        /**\n         * Indicates whether this instance is an initiator or an answerer of\n         * the Jingle session.\n         * @type {boolean}\n         */\n        this.isInitiator = isInitiator;\n\n        /**\n         * Whether to use dripping or not. Dripping is sending trickle\n         * candidates not one-by-one.\n         */\n        this.usedrip = true;\n\n        /**\n         *  When dripping is used, stores ICE candidates which are to be sent.\n         */\n        this.dripContainer = [];\n\n        /**\n         * The chat room instance associated with the session.\n         * @type {ChatRoom}\n         */\n        this.room = null;\n\n        /**\n         * The signaling layer.\n         * @type {SignalingLayerImpl | null}\n         * @private\n         */\n        this._signalingLayer = null;\n\n        /**\n         * Jingle session state - uninitialized until {@link initialize} is\n         * called @type {JingleSessionState}\n         */\n        this.state = null;\n\n        /**\n         * The RTC service instance\n         * @type {RTC}\n         */\n        this.rtc = null;\n    }\n\n    /**\n     * Returns XMPP address of this session's initiator.\n     * @return {string}\n     */\n    get initiatorJid() {\n        return this.isInitiator ? this.localJid : this.remoteJid;\n    }\n\n    /**\n     * Returns XMPP address of this session's responder.\n     * @return {string}\n     */\n    get responderJid() {\n        return this.isInitiator ? this.remoteJid : this.localJid;\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Prepares this object to initiate a session.\n     * @param {ChatRoom} room the chat room for the conference associated with\n     * this session\n     * @param {RTC} rtc the RTC service instance\n     * @param {SignalingLayerImpl} signalingLayer - The signaling layer instance.\n     * @param {object} options - the options, see implementing class's\n     * {@link #doInitialize} description for more details.\n     */\n    initialize(room, rtc, signalingLayer, options) {\n        if (this.state !== null) {\n            const errmsg\n                = `attempt to initiate on session ${this.sid}\n                   in state ${this.state}`;\n\n            logger.error(errmsg);\n            throw new Error(errmsg);\n        }\n\n        // TODO decouple from room\n        this.room = room;\n        this.rtc = rtc;\n        this._signalingLayer = signalingLayer;\n        this.state = JingleSessionState.PENDING;\n        this.doInitialize(options);\n    }\n\n    /**\n     * The implementing class finishes initialization here. Called at the end of\n     * {@link initialize}.\n     * @param {Object} options - The options specific to the implementing class.\n     * @protected\n     */\n    doInitialize(options) { } // eslint-disable-line no-unused-vars, no-empty-function, max-len\n\n    /* eslint-disable no-unused-vars, no-empty-function */\n\n    /**\n     * Adds the ICE candidates found in the 'contents' array as remote\n     * candidates?\n     * Note: currently only used on transport-info\n     *\n     * @param contents\n     */\n    addIceCandidates(contents) {}\n\n    /* eslint-enable no-unused-vars, no-empty-function */\n\n    /**\n     * Returns current state of this <tt>JingleSession</tt> instance.\n     * @returns {JingleSessionState} the current state of this session instance.\n     */\n    getState() {\n        return this.state;\n    }\n\n    /* eslint-disable no-unused-vars, no-empty-function */\n\n    /**\n     * Handles an 'add-source' event.\n     *\n     * @param contents an array of Jingle 'content' elements.\n     */\n    addSources(contents) {}\n\n    /**\n     * Handles a 'remove-source' event.\n     *\n     * @param contents an array of Jingle 'content' elements.\n     */\n    removeSources(contents) {}\n\n    /**\n     * Terminates this Jingle session by sending session-terminate\n     * @param success a callback called once the 'session-terminate' packet has\n     * been acknowledged with RESULT.\n     * @param failure a callback called when either timeout occurs or ERROR\n     * response is received.\n     * @param {Object} options\n     * @param {string} [options.reason] XMPP Jingle error condition\n     * @param {string} [options.reasonDescription] some meaningful error message\n     * @param {boolean} [options.requestRestart=false] set to true to ask Jicofo to start a new session one this once is\n     * terminated.\n     * @param {boolean} [options.sendSessionTerminate=true] set to false to skip\n     * sending session-terminate. It may not make sense to send it if the XMPP\n     * connection has been closed already or if the remote peer has disconnected\n     */\n    terminate(success, failure, options) {}\n\n    /**\n     * Handles an offer from the remote peer (prepares to accept a session).\n     * @param jingle the 'jingle' XML element.\n     * @param success callback called when we the incoming session has been\n     * accepted\n     * @param failure callback called when we fail for any reason, will supply\n     * error object with details(which is meant more to be printed to the logger\n     * than analysed in the code, as the error is unrecoverable anyway)\n     */\n    acceptOffer(jingle, success, failure) {}\n\n    /* eslint-enable no-unused-vars, no-empty-function */\n}\n","enum MediaSessionEvents {\n    /**\n     * Event triggered when the remote party signals video max frame heights for its local sources.\n     */\n    REMOTE_SOURCE_CONSTRAINTS_CHANGED = 'media_session.REMOTE_SOURCE_CONSTRAINTS_CHANGED'\n};\n\nexport default MediaSessionEvents;","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $build, $iq, Strophe } from 'strophe.js';\n\nimport { JitsiTrackEvents } from '../../JitsiTrackEvents';\nimport * as CodecMimeType from '../../service/RTC/CodecMimeType';\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport {\n    ICE_DURATION,\n    ICE_STATE_CHANGED\n} from '../../service/statistics/AnalyticsEvents';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport { SS_DEFAULT_FRAME_RATE } from '../RTC/ScreenObtainer';\nimport FeatureFlags from '../flags/FeatureFlags';\nimport SDP from '../sdp/SDP';\nimport SDPDiffer from '../sdp/SDPDiffer';\nimport SDPUtil from '../sdp/SDPUtil';\nimport Statistics from '../statistics/statistics';\nimport AsyncQueue from '../util/AsyncQueue';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\n\nimport browser from './../browser';\nimport JingleSession from './JingleSession';\nimport * as JingleSessionState from './JingleSessionState';\nimport MediaSessionEvents from './MediaSessionEvents';\nimport XmppConnection from './XmppConnection';\n\nconst logger = getLogger(__filename);\n\n/**\n * Constant tells how long we're going to wait for IQ response, before timeout\n * error is  triggered.\n * @type {number}\n */\nconst IQ_TIMEOUT = 10000;\n\n/*\n * The default number of samples (per stat) to keep when webrtc stats gathering\n * is enabled in TraceablePeerConnection.\n */\nconst DEFAULT_MAX_STATS = 300;\n\n/**\n * The time duration for which the client keeps gathering ICE candidates to be sent out in a single IQ.\n * @type {number} timeout in ms.\n */\nconst ICE_CAND_GATHERING_TIMEOUT = 150;\n\n/**\n * Reads the endpoint ID given a string which represents either the endpoint's full JID, or the endpoint ID itself.\n * @param {String} jidOrEndpointId A string which is either the full JID of a participant, or the ID of an\n * endpoint/participant.\n * @returns The endpoint ID associated with 'jidOrEndpointId'.\n */\nfunction getEndpointId(jidOrEndpointId) {\n    return Strophe.getResourceFromJid(jidOrEndpointId) || jidOrEndpointId;\n}\n\n/**\n * Add \"source\" element as a child of \"description\" element.\n * @param {Object} description The \"description\" element to add to.\n * @param {Object} s Contains properties of the source being added.\n * @param {Number} ssrc_ The SSRC.\n * @param {String} msid The \"msid\" attribute.\n */\nfunction _addSourceElement(description, s, ssrc_, msid) {\n\n    description.c('source', {\n        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\n        ssrc: ssrc_,\n        name: s.source\n    })\n        .c('parameter', {\n            name: 'msid',\n            value: msid\n        })\n        .up()\n        .c('ssrc-info', {\n            xmlns: 'http://jitsi.org/jitmeet',\n            owner: s.owner\n        })\n        .up()\n        .up();\n}\n\n/**\n * @typedef {Object} JingleSessionPCOptions\n * video test ?(ask George).\n * @property {boolean} disableRtx - Described in the config.js[1].\n * @property {boolean} disableSimulcast - Described in the config.js[1].\n * @property {boolean} enableInsertableStreams - Set to true when the insertable streams constraints is to be enabled\n * on the PeerConnection.\n * @property {boolean} failICE - it's an option used in the tests. Set to\n * <tt>true</tt> to block any real candidates and make the ICE fail.\n * @property {boolean} gatherStats - Described in the config.js[1].\n * @property {object} p2p - Peer to peer related options (FIXME those could be\n * fetched from config.p2p on the upper level).\n * @property {boolean} preferH264 - Described in the config.js[1].\n * @property {Object} testing - Testing and/or experimental options.\n * @property {boolean} webrtcIceUdpDisable - Described in the config.js[1].\n * @property {boolean} webrtcIceTcpDisable - Described in the config.js[1].\n *\n * [1]: https://github.com/jitsi/jitsi-meet/blob/master/config.js\n */\n/**\n *\n */\nexport default class JingleSessionPC extends JingleSession {\n    /**\n     * Parses 'senders' attribute of the video content.\n     * @param {jQuery} jingleContents\n     * @return {string|null} one of the values of content \"senders\" attribute\n     * defined by Jingle. If there is no \"senders\" attribute or if the value is\n     * invalid then <tt>null</tt> will be returned.\n     * @private\n     */\n    static parseVideoSenders(jingleContents) {\n        const videoContents = jingleContents.find('>content[name=\"video\"]');\n\n        if (videoContents.length) {\n            const senders = videoContents[0].getAttribute('senders');\n\n            if (senders === 'both'\n                || senders === 'initiator'\n                || senders === 'responder'\n                || senders === 'none') {\n                return senders;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Parses the source-name and max frame height value of the 'content-modify' IQ when source-name signaling\n     * is enabled.\n     *\n     * @param {jQuery} jingleContents - A jQuery selector pointing to the '>jingle' element.\n     * @returns {Object|null}\n     */\n    static parseSourceMaxFrameHeight(jingleContents) {\n        const receiverConstraints = [];\n        const sourceFrameHeightSel = jingleContents.find('>content[name=\"video\"]>source-frame-height');\n        let maxHeight, sourceName;\n\n        if (sourceFrameHeightSel.length) {\n            sourceFrameHeightSel.each((_, source) => {\n                sourceName = source.getAttribute('sourceName');\n                maxHeight = source.getAttribute('maxHeight');\n                receiverConstraints.push({\n                    maxHeight,\n                    sourceName\n                });\n            });\n\n            return receiverConstraints;\n        }\n\n        return null;\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     * Creates new <tt>JingleSessionPC</tt>\n     * @param {string} sid the Jingle Session ID - random string which identifies the session\n     * @param {string} localJid our JID\n     * @param {string} remoteJid remote peer JID\n     * @param {XmppConnection} connection - The XMPP connection instance.\n     * @param mediaConstraints the media constraints object passed to createOffer/Answer, as defined\n     * by the WebRTC standard\n     * @param pcConfig The {@code RTCConfiguration} to use for the WebRTC peer connection.\n     * @param {boolean} isP2P indicates whether this instance is meant to be used in a direct, peer to\n     * peer connection or <tt>false</tt> if it's a JVB connection.\n     * @param {boolean} isInitiator indicates if it will be the side which initiates the session.\n     * @constructor\n     *\n     * @implements {SignalingLayer}\n     */\n    constructor(\n            sid,\n            localJid,\n            remoteJid,\n            connection,\n            mediaConstraints,\n            pcConfig,\n            isP2P,\n            isInitiator) {\n        super(\n            sid,\n            localJid,\n            remoteJid, connection, mediaConstraints, pcConfig, isInitiator);\n\n        /**\n         * The bridge session's identifier. One Jingle session can during\n         * it's lifetime participate in multiple bridge sessions managed by\n         * Jicofo. A new bridge session is started whenever Jicofo sends\n         * 'session-initiate' or 'transport-replace'.\n         *\n         * @type {?string}\n         * @private\n         */\n        this._bridgeSessionId = null;\n\n        /**\n         * The oldest SDP passed to {@link notifyMySSRCUpdate} while the XMPP connection was offline that will be\n         * used to update Jicofo once the XMPP connection goes back online.\n         * @type {SDP|undefined}\n         * @private\n         */\n        this._cachedOldLocalSdp = undefined;\n\n        /**\n         * The latest SDP passed to {@link notifyMySSRCUpdate} while the XMPP connection was offline that will be\n         * used to update Jicofo once the XMPP connection goes back online.\n         * @type {SDP|undefined}\n         * @private\n         */\n        this._cachedNewLocalSdp = undefined;\n\n        /**\n         * Stores result of {@link window.performance.now()} at the time when\n         * ICE enters 'checking' state.\n         * @type {number|null} null if no value has been stored yet\n         * @private\n         */\n        this._iceCheckingStartedTimestamp = null;\n\n        /**\n         * Stores result of {@link window.performance.now()} at the time when\n         * first ICE candidate is spawned by the peerconnection to mark when\n         * ICE gathering started. That's, because ICE gathering state changed\n         * events are not supported by most of the browsers, so we try something\n         * that will work everywhere. It may not be as accurate, but given that\n         * 'host' candidate usually comes first, the delay should be minimal.\n         * @type {number|null} null if no value has been stored yet\n         * @private\n         */\n        this._gatheringStartedTimestamp = null;\n\n        /**\n         * Receiver constraints (max height) set by the application per remote source. Will be used for p2p connection.\n         *\n         * @type {Map<string, number>}\n         */\n        this._sourceReceiverConstraints = undefined;\n\n        /**\n         * Indicates whether or not this session is willing to send/receive\n         * video media. When set to <tt>false</tt> the underlying peer\n         * connection will disable local video transfer and the remote peer will\n         * be will be asked to stop sending video via 'content-modify' IQ\n         * (the senders attribute of video contents will be adjusted\n         * accordingly). Note that this notification is sent only in P2P\n         * session, because Jicofo does not support it yet. Obviously when\n         * the value is changed from <tt>false</tt> to <tt>true</tt> another\n         * notification will be sent to resume video transfer on the remote\n         * side.\n         * @type {boolean}\n         * @private\n         */\n        this._localVideoActive = true;\n\n        /**\n         * Indicates whether or not the remote peer has video transfer active.\n         * When set to <tt>true</tt> it means that remote peer is neither\n         * sending nor willing to receive video. In such case we'll ask\n         * our peerconnection to stop sending video by calling\n         * {@link TraceablePeerConnection.setVideoTransferActive} with\n         * <tt>false</tt>.\n         * @type {boolean}\n         * @private\n         */\n        this._remoteVideoActive = true;\n\n        /**\n         * Marks that ICE gathering duration has been reported already. That\n         * prevents reporting it again, after eventual 'transport-replace' (JVB\n         * conference migration/ICE restart).\n         * @type {boolean}\n         * @private\n         */\n        this._gatheringReported = false;\n\n        this.lasticecandidate = false;\n        this.closed = false;\n\n        /**\n         * Indicates whether or not this <tt>JingleSessionPC</tt> is used in\n         * a peer to peer type of session.\n         * @type {boolean} <tt>true</tt> if it's a peer to peer\n         * session or <tt>false</tt> if it's a JVB session\n         */\n        this.isP2P = isP2P;\n\n        /**\n         * Remote preference for the receive video max frame height.\n         *\n         * @type {Number|undefined}\n         */\n        this.remoteRecvMaxFrameHeight = undefined;\n\n        /**\n         * Number of remote video sources, in SSRC rewriting mode.\n         * Used to generate next unique msid attribute.\n         *\n         * @type {Number}\n         */\n        this.numRemoteVideoSources = 0;\n\n        /**\n         * Number of remote audio sources, in SSRC rewriting mode.\n         * Used to generate next unique msid attribute.\n         *\n         * @type {Number}\n         */\n        this.numRemoteAudioSources = 0;\n\n        /**\n         * Remote preference for the receive video max frame heights when source-name signaling is enabled.\n         *\n         * @type {Map<string, number>|undefined}\n         */\n        this.remoteSourceMaxFrameHeights = undefined;\n\n        /**\n         * The queue used to serialize operations done on the peerconnection.\n         *\n         * @type {AsyncQueue}\n         */\n        this.modificationQueue = new AsyncQueue();\n\n        /**\n         * Flag used to guarantee that the connection established event is\n         * triggered just once.\n         * @type {boolean}\n         */\n        this.wasConnected = false;\n\n        /**\n         * Keeps track of how long (in ms) it took from ICE start to ICE\n         * connect.\n         *\n         * @type {number}\n         */\n        this.establishmentDuration = undefined;\n\n        this._xmppListeners = [];\n        this._xmppListeners.push(\n            connection.addEventListener(\n                XmppConnection.Events.CONN_STATUS_CHANGED,\n                this.onXmppStatusChanged.bind(this))\n        );\n\n        this._removeSenderVideoConstraintsChangeListener = undefined;\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Checks whether or not this session instance is still operational.\n     * @private\n     * @returns {boolean} {@code true} if operation or {@code false} otherwise.\n     */\n    _assertNotEnded() {\n        return this.state !== JingleSessionState.ENDED;\n    }\n\n    /**\n     * @inheritDoc\n     * @param {JingleSessionPCOptions} options  - a set of config options.\n     */\n    doInitialize(options) {\n        this.failICE = Boolean(options.failICE);\n        this.lasticecandidate = false;\n        this.options = options;\n\n        /**\n         * {@code true} if reconnect is in progress.\n         * @type {boolean}\n         */\n        this.isReconnect = false;\n\n        /**\n         * Set to {@code true} if the connection was ever stable\n         * @type {boolean}\n         */\n        this.wasstable = false;\n        this.webrtcIceUdpDisable = Boolean(options.webrtcIceUdpDisable);\n        this.webrtcIceTcpDisable = Boolean(options.webrtcIceTcpDisable);\n\n        const pcOptions = { disableRtx: options.disableRtx };\n\n        if (options.gatherStats) {\n            pcOptions.maxstats = DEFAULT_MAX_STATS;\n        }\n        pcOptions.capScreenshareBitrate = false;\n        pcOptions.codecSettings = options.codecSettings;\n        pcOptions.enableInsertableStreams = options.enableInsertableStreams;\n        pcOptions.videoQuality = options.videoQuality;\n        pcOptions.forceTurnRelay = options.forceTurnRelay;\n        pcOptions.audioQuality = options.audioQuality;\n        pcOptions.usesUnifiedPlan = this.usesUnifiedPlan = browser.supportsUnifiedPlan();\n\n        if (this.isP2P) {\n            // simulcast needs to be disabled for P2P (121) calls\n            pcOptions.disableSimulcast = true;\n        } else {\n            // H264 scalability is not supported on jvb, so simulcast needs to be disabled when H264 is preferred.\n            pcOptions.disableSimulcast\n                = options.disableSimulcast || options.videoQuality?.preferredCodec === CodecMimeType.H264;\n\n            // Do not send lower spatial layers for low fps screenshare and enable them only for high fps screenshare.\n            pcOptions.capScreenshareBitrate = pcOptions.disableSimulcast\n                || !(typeof options.desktopSharingFrameRate?.max === 'number'\n                    && options.desktopSharingFrameRate?.max > SS_DEFAULT_FRAME_RATE);\n        }\n\n        if (options.startSilent) {\n            pcOptions.startSilent = true;\n        }\n\n        this.peerconnection\n            = this.rtc.createPeerConnection(\n                    this._signalingLayer,\n                    this.pcConfig,\n                    this.isP2P,\n                    pcOptions);\n\n        this.peerconnection.onicecandidate = ev => {\n            if (!ev) {\n                // There was an incomplete check for ev before which left\n                // the last line of the function unprotected from a potential\n                // throw of an exception. Consequently, it may be argued that\n                // the check is unnecessary. Anyway, I'm leaving it and making\n                // the check complete.\n                return;\n            }\n\n            // XXX this is broken, candidate is not parsed.\n            const candidate = ev.candidate;\n            const now = window.performance.now();\n\n            if (candidate) {\n                if (this._gatheringStartedTimestamp === null) {\n                    this._gatheringStartedTimestamp = now;\n                }\n\n                // Discard candidates of disabled protocols.\n                let protocol = candidate.protocol;\n\n                if (typeof protocol === 'string') {\n                    protocol = protocol.toLowerCase();\n                    if (protocol === 'tcp' || protocol === 'ssltcp') {\n                        if (this.webrtcIceTcpDisable) {\n                            return;\n                        }\n                    } else if (protocol === 'udp') {\n                        if (this.webrtcIceUdpDisable) {\n                            return;\n                        }\n                    }\n                }\n            } else if (!this._gatheringReported) {\n                // End of gathering\n                Statistics.sendAnalytics(\n                    ICE_DURATION,\n                    {\n                        phase: 'gathering',\n                        value: now - this._gatheringStartedTimestamp,\n                        p2p: this.isP2P,\n                        initiator: this.isInitiator\n                    });\n                this._gatheringReported = true;\n            }\n            if (this.isP2P) {\n                this.sendIceCandidate(candidate);\n            }\n        };\n\n        // Note there is a change in the spec about closed:\n        // This value moved into the RTCPeerConnectionState enum in\n        // the May 13, 2016 draft of the specification, as it reflects the state\n        // of the RTCPeerConnection, not the signaling connection. You now\n        // detect a closed connection by checking for connectionState to be\n        // \"closed\" instead.\n        // I suppose at some point this will be moved to onconnectionstatechange\n        this.peerconnection.onsignalingstatechange = () => {\n            if (this.peerconnection.signalingState === 'stable') {\n                this.wasstable = true;\n            } else if (this.peerconnection.signalingState === 'closed'\n                || this.peerconnection.connectionState === 'closed') {\n                this.room.eventEmitter.emit(XMPPEvents.SUSPEND_DETECTED, this);\n            }\n        };\n\n        /**\n         * The oniceconnectionstatechange event handler contains the code to\n         * execute when the iceconnectionstatechange event, of type Event,\n         * is received by this RTCPeerConnection. Such an event is sent when\n         * the value of RTCPeerConnection.iceConnectionState changes.\n         */\n        this.peerconnection.oniceconnectionstatechange = () => {\n            const now = window.performance.now();\n            let isStable = false;\n\n            if (!this.isP2P) {\n                this.room.connectionTimes[\n                    `ice.state.${this.peerconnection.iceConnectionState}`]\n                    = now;\n            }\n            logger.log(`(TIME) ICE ${this.peerconnection.iceConnectionState} ${this.isP2P ? 'P2P' : 'JVB'}:\\t`, now);\n\n            Statistics.sendAnalytics(\n                ICE_STATE_CHANGED,\n                {\n                    p2p: this.isP2P,\n                    state: this.peerconnection.iceConnectionState,\n                    'signaling_state': this.peerconnection.signalingState,\n                    reconnect: this.isReconnect,\n                    value: now\n                });\n\n            this.room.eventEmitter.emit(\n                XMPPEvents.ICE_CONNECTION_STATE_CHANGED,\n                this,\n                this.peerconnection.iceConnectionState);\n            switch (this.peerconnection.iceConnectionState) {\n            case 'checking':\n                this._iceCheckingStartedTimestamp = now;\n                break;\n            case 'connected':\n                // Informs interested parties that the connection has been restored. This includes the case when\n                // media connection to the bridge has been restored after an ICE failure by using session-terminate.\n                if (this.peerconnection.signalingState === 'stable') {\n                    isStable = true;\n                    const usesTerminateForRestart = !this.options.enableIceRestart\n                        && this.room.supportsRestartByTerminate();\n\n                    if (this.isReconnect || usesTerminateForRestart) {\n                        this.room.eventEmitter.emit(\n                            XMPPEvents.CONNECTION_RESTORED, this);\n                    }\n                }\n\n                // Add a workaround for an issue on chrome in Unified plan when the local endpoint is the offerer.\n                // The 'signalingstatechange' event for 'stable' is handled after the 'iceconnectionstatechange' event\n                // for 'completed' is handled by the client. This prevents the client from firing a\n                // CONNECTION_ESTABLISHED event for the p2p session. As a result, the offerer continues to stay on the\n                // jvb connection while the remote peer switches to the p2p connection breaking the media flow between\n                // the endpoints.\n                // TODO - file a chromium bug and add the information here.\n                if (!this.wasConnected\n                    && (this.wasstable\n                        || isStable\n                        || (this.usesUnifiedPlan && this.isInitiator\n                            && (browser.isChromiumBased() || browser.isReactNative())))) {\n\n                    Statistics.sendAnalytics(\n                        ICE_DURATION,\n                        {\n                            phase: 'checking',\n                            value: now - this._iceCheckingStartedTimestamp,\n                            p2p: this.isP2P,\n                            initiator: this.isInitiator\n                        });\n\n                    // Switch between ICE gathering and ICE checking whichever\n                    // started first (scenarios are different for initiator\n                    // vs responder)\n                    const iceStarted\n                        = Math.min(\n                            this._iceCheckingStartedTimestamp,\n                            this._gatheringStartedTimestamp);\n\n                    this.establishmentDuration = now - iceStarted;\n\n                    Statistics.sendAnalytics(\n                        ICE_DURATION,\n                        {\n                            phase: 'establishment',\n                            value: this.establishmentDuration,\n                            p2p: this.isP2P,\n                            initiator: this.isInitiator\n                        });\n\n                    this.wasConnected = true;\n                    this.room.eventEmitter.emit(\n                        XMPPEvents.CONNECTION_ESTABLISHED, this);\n                }\n                this.isReconnect = false;\n                break;\n            case 'disconnected':\n                this.isReconnect = true;\n\n                // Informs interested parties that the connection has been\n                // interrupted.\n                if (this.wasstable) {\n                    this.room.eventEmitter.emit(\n                        XMPPEvents.CONNECTION_INTERRUPTED, this);\n                }\n                break;\n            case 'failed':\n                this.room.eventEmitter.emit(\n                    XMPPEvents.CONNECTION_ICE_FAILED, this);\n                break;\n            }\n        };\n\n\n        /**\n         * The connection state event is fired whenever the aggregate of underlying\n         * transports change their state.\n         */\n        this.peerconnection.onconnectionstatechange = () => {\n            const icestate = this.peerconnection.iceConnectionState;\n\n            switch (this.peerconnection.connectionState) {\n            case 'failed':\n                // Since version 76 Chrome no longer switches ICE connection\n                // state to failed (see\n                // https://bugs.chromium.org/p/chromium/issues/detail?id=982793\n                // for details) we use this workaround to recover from lost connections\n                if (icestate === 'disconnected') {\n                    this.room.eventEmitter.emit(\n                        XMPPEvents.CONNECTION_ICE_FAILED, this);\n                }\n                break;\n            }\n        };\n\n        /**\n         * The negotiationneeded event is fired whenever we shake the media on the\n         * RTCPeerConnection object.\n         */\n        this.peerconnection.onnegotiationneeded = () => {\n            const state = this.peerconnection.signalingState;\n            const remoteDescription = this.peerconnection.remoteDescription;\n\n            if (this.usesUnifiedPlan\n                && !this.isP2P\n                && state === 'stable'\n                && remoteDescription\n                && typeof remoteDescription.sdp === 'string') {\n                logger.info(`${this} onnegotiationneeded fired on ${this.peerconnection}`);\n\n                const workFunction = finishedCallback => {\n                    const oldSdp = new SDP(this.peerconnection.localDescription.sdp);\n\n                    this._renegotiate()\n                        .then(() => {\n                            const newSdp = new SDP(this.peerconnection.localDescription.sdp);\n\n                            this.notifyMySSRCUpdate(oldSdp, newSdp);\n                        })\n                        .then(() => finishedCallback(), error => finishedCallback(error));\n                };\n\n                this.modificationQueue.push(\n                    workFunction,\n                    error => {\n                        if (error) {\n                            logger.error(`${this} onnegotiationneeded error`, error);\n                        } else {\n                            logger.debug(`${this} onnegotiationneeded executed - OK`);\n                        }\n                    });\n            }\n        };\n    }\n\n    /**\n     * Remote preference for receive video max frame height.\n     *\n     * @returns {Number|undefined}\n     */\n    getRemoteRecvMaxFrameHeight() {\n        if (this.isP2P) {\n            return this.remoteRecvMaxFrameHeight;\n        }\n\n        return undefined;\n    }\n\n    /**\n     * Remote preference for receive video max frame heights when source-name signaling is enabled.\n     *\n     * @returns {Map<string, number>|undefined}\n     */\n    getRemoteSourcesRecvMaxFrameHeight() {\n        if (this.isP2P) {\n            return this.remoteSourceMaxFrameHeights;\n        }\n\n        return undefined;\n    }\n\n    /**\n     * Sends given candidate in Jingle 'transport-info' message.\n     * @param {RTCIceCandidate} candidate the WebRTC ICE candidate instance\n     * @private\n     */\n    sendIceCandidate(candidate) {\n        const localSDP = new SDP(this.peerconnection.localDescription.sdp);\n\n        if (candidate && candidate.candidate.length && !this.lasticecandidate) {\n            const ice = SDPUtil.iceparams(localSDP.media[candidate.sdpMLineIndex], localSDP.session);\n            const jcand = SDPUtil.candidateToJingle(candidate.candidate);\n\n            if (!(ice && jcand)) {\n                const errorMesssage = 'failed to get ice && jcand';\n\n                GlobalOnErrorHandler.callErrorHandler(new Error(errorMesssage));\n                logger.error(errorMesssage);\n\n                return;\n            }\n            ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';\n\n            if (this.usedrip) {\n                if (this.dripContainer.length === 0) {\n                    setTimeout(() => {\n                        if (this.dripContainer.length === 0) {\n                            return;\n                        }\n                        this.sendIceCandidates(this.dripContainer);\n                        this.dripContainer = [];\n                    }, ICE_CAND_GATHERING_TIMEOUT);\n                }\n                this.dripContainer.push(candidate);\n            } else {\n                this.sendIceCandidates([ candidate ]);\n            }\n        } else {\n            logger.log(`${this} sendIceCandidate: last candidate`);\n\n            // FIXME: remember to re-think in ICE-restart\n            this.lasticecandidate = true;\n        }\n    }\n\n    /**\n     * Sends given candidates in Jingle 'transport-info' message.\n     * @param {Array<RTCIceCandidate>} candidates an array of the WebRTC ICE\n     * candidate instances\n     * @private\n     */\n    sendIceCandidates(candidates) {\n        if (!this._assertNotEnded('sendIceCandidates')) {\n\n            return;\n        }\n\n        logger.log(`${this} sendIceCandidates ${JSON.stringify(candidates)}`);\n        const cand = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', { xmlns: 'urn:xmpp:jingle:1',\n                action: 'transport-info',\n                initiator: this.initiatorJid,\n                sid: this.sid });\n\n        const localSDP = new SDP(this.peerconnection.localDescription.sdp);\n\n        for (let mid = 0; mid < localSDP.media.length; mid++) {\n            const cands = candidates.filter(el => el.sdpMLineIndex === mid);\n            const mline\n                = SDPUtil.parseMLine(localSDP.media[mid].split('\\r\\n')[0]);\n\n            if (cands.length > 0) {\n                const ice\n                    = SDPUtil.iceparams(localSDP.media[mid], localSDP.session);\n\n                ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';\n                cand.c('content', {\n                    creator: this.initiatorJid === this.localJid\n                        ? 'initiator' : 'responder',\n                    name: cands[0].sdpMid ? cands[0].sdpMid : mline.media\n                }).c('transport', ice);\n                for (let i = 0; i < cands.length; i++) {\n                    const candidate\n                        = SDPUtil.candidateToJingle(cands[i].candidate);\n\n                    // Mangle ICE candidate if 'failICE' test option is enabled\n\n                    if (this.failICE) {\n                        candidate.ip = '1.1.1.1';\n                    }\n                    cand.c('candidate', candidate).up();\n                }\n\n                // add fingerprint\n                const fingerprintLine\n                    = SDPUtil.findLine(\n                        localSDP.media[mid],\n                        'a=fingerprint:', localSDP.session);\n\n                if (fingerprintLine) {\n                    const tmp = SDPUtil.parseFingerprint(fingerprintLine);\n\n                    tmp.required = true;\n                    cand.c(\n                        'fingerprint',\n                        { xmlns: 'urn:xmpp:jingle:apps:dtls:0' })\n                        .t(tmp.fingerprint);\n                    delete tmp.fingerprint;\n                    cand.attrs(tmp);\n                    cand.up();\n                }\n                cand.up(); // transport\n                cand.up(); // content\n            }\n        }\n\n        // might merge last-candidate notification into this, but it is called\n        // a lot later. See webrtc issue #2340\n        // logger.log('was this the last candidate', this.lasticecandidate);\n        this.connection.sendIQ(\n            cand, null, this.newJingleErrorHandler(cand), IQ_TIMEOUT);\n    }\n\n    /**\n     * Sends Jingle 'session-info' message which includes custom Jitsi Meet\n     * 'ice-state' element with the text value 'failed' to let Jicofo know\n     * that the ICE connection has entered the failed state. It can then\n     * choose to re-create JVB channels and send 'transport-replace' to\n     * retry the connection.\n     */\n    sendIceFailedNotification() {\n        const sessionInfo\n            = $iq({\n                to: this.remoteJid,\n                type: 'set' })\n            .c('jingle', { xmlns: 'urn:xmpp:jingle:1',\n                action: 'session-info',\n                initiator: this.initiatorJid,\n                sid: this.sid })\n            .c('ice-state', { xmlns: 'http://jitsi.org/protocol/focus' })\n            .t('failed')\n            .up();\n\n        this._bridgeSessionId\n            && sessionInfo.c(\n                'bridge-session', {\n                    xmlns: 'http://jitsi.org/protocol/focus',\n                    id: this._bridgeSessionId\n                });\n\n        this.connection.sendIQ2(\n            sessionInfo, {\n                /*\n                 * This message will be often sent when there are connectivity\n                 * issues, so make it slightly longer than Prosody's default BOSH\n                 * inactivity timeout of 60 seconds.\n                 */\n                timeout: 65\n            })\n            .catch(this.newJingleErrorHandler(sessionInfo));\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    addIceCandidates(elem) {\n        if (this.peerconnection.signalingState === 'closed') {\n            logger.warn(`${this} Ignored add ICE candidate when in closed state`);\n\n            return;\n        }\n\n        const iceCandidates = [];\n\n        elem.find('>content>transport>candidate')\n            .each((idx, candidate) => {\n                let line = SDPUtil.candidateFromJingle(candidate);\n\n                line = line.replace('\\r\\n', '').replace('a=', '');\n\n                // FIXME this code does not care to handle\n                // non-bundle transport\n                const rtcCandidate = new RTCIceCandidate({\n                    sdpMLineIndex: 0,\n\n                    // FF comes up with more complex names like audio-23423,\n                    // Given that it works on both Chrome and FF without\n                    // providing it, let's leave it like this for the time\n                    // being...\n                    // sdpMid: 'audio',\n                    sdpMid: '',\n                    candidate: line\n                });\n\n                iceCandidates.push(rtcCandidate);\n            });\n\n        if (!iceCandidates.length) {\n            logger.error(`${this} No ICE candidates to add ?`, elem[0] && elem[0].outerHTML);\n\n            return;\n        }\n\n        // We want to have this task queued, so that we know it is executed,\n        // after the initial sRD/sLD offer/answer cycle was done (based on\n        // the assumption that candidates are spawned after the offer/answer\n        // and XMPP preserves order).\n        const workFunction = finishedCallback => {\n            for (const iceCandidate of iceCandidates) {\n                this.peerconnection.addIceCandidate(iceCandidate)\n                    .then(\n                        () => logger.debug(`${this} addIceCandidate ok!`),\n                        err => logger.error(`${this} addIceCandidate failed!`, err));\n            }\n\n            finishedCallback();\n            logger.debug(`${this} ICE candidates task finished`);\n        };\n\n        logger.debug(`${this} Queued add (${iceCandidates.length}) ICE candidates task`);\n        this.modificationQueue.push(workFunction);\n    }\n\n    /**\n     *\n     * @param contents\n     */\n    readSsrcInfo(contents) {\n        const ssrcs = $(contents).find('>description>source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]');\n\n        ssrcs.each((i, ssrcElement) => {\n            const ssrc = Number(ssrcElement.getAttribute('ssrc'));\n\n            if (ssrcElement.hasAttribute('name')) {\n                const sourceName = ssrcElement.getAttribute('name');\n\n                this._signalingLayer.setTrackSourceName(ssrc, sourceName);\n            }\n\n            if (this.isP2P) {\n                // In P2P all SSRCs are owner by the remote peer\n                this._signalingLayer.setSSRCOwner(ssrc, Strophe.getResourceFromJid(this.remoteJid));\n            } else {\n                $(ssrcElement)\n                    .find('>ssrc-info[xmlns=\"http://jitsi.org/jitmeet\"]')\n                    .each((i3, ssrcInfoElement) => {\n                        const owner = ssrcInfoElement.getAttribute('owner');\n\n                        if (owner?.length) {\n                            if (isNaN(ssrc) || ssrc < 0) {\n                                logger.warn(`${this} Invalid SSRC ${ssrc} value received for ${owner}`);\n                            } else {\n                                this._signalingLayer.setSSRCOwner(ssrc, getEndpointId(owner));\n                            }\n                        }\n                    });\n            }\n        });\n    }\n\n    /**\n     * Makes the underlying TraceablePeerConnection generate new SSRC for\n     * the recvonly video stream.\n     * @deprecated\n     */\n    generateRecvonlySsrc() {\n        if (this.peerconnection) {\n            this.peerconnection.generateRecvonlySsrc();\n        } else {\n            logger.error(`${this} Unable to generate recvonly SSRC - no peerconnection`);\n        }\n    }\n\n    /**\n     * Returns the video codec configured as the preferred codec on the peerconnection.\n     */\n    getConfiguredVideoCodec() {\n        return this.peerconnection.getConfiguredVideoCodec();\n    }\n\n    /**\n     * Accepts incoming Jingle 'session-initiate' and should send 'session-accept' in result.\n     *\n     * @param jingleOffer jQuery selector pointing to the jingle element of the offer IQ\n     * @param success callback called when we accept incoming session successfully and receive RESULT packet to\n     * 'session-accept' sent.\n     * @param failure function(error) called if for any reason we fail to accept the incoming offer. 'error' argument\n     * can be used to log some details about the error.\n     * @param {Array<JitsiLocalTrack>} [localTracks] the optional list of the local tracks that will be added, before\n     * the offer/answer cycle executes. We allow the localTracks to optionally be passed in so that the addition of the\n     * local tracks and the processing of the initial offer can all be done atomically. We want to make sure that any\n     * other operations which originate in the XMPP Jingle messages related with this session to be executed with an\n     * assumption that the initial offer/answer cycle has been executed already.\n     */\n    acceptOffer(jingleOffer, success, failure, localTracks) {\n        this.setOfferAnswerCycle(\n            jingleOffer,\n            () => {\n                // FIXME we may not care about RESULT packet for session-accept\n                // then we should either call 'success' here immediately or\n                // modify sendSessionAccept method to do that\n                this.sendSessionAccept(() => {\n                    success();\n                    this.room.eventEmitter.emit(XMPPEvents.SESSION_ACCEPT, this);\n\n                    // The first video track is added to the peerconnection and signaled as part of the session-accept.\n                    // Add secondary video tracks (that were already added to conference) to the peerconnection here.\n                    // This will happen when someone shares a secondary source to a two people call, the other user\n                    // leaves and joins the call again, a new peerconnection is created for p2p/jvb connection. At this\n                    // point, there are 2 video tracks which need to be signaled to the remote peer.\n                    const videoTracks = localTracks.filter(track => track.getType() === MediaType.VIDEO);\n\n                    videoTracks.length && videoTracks.splice(0, 1);\n                    if (FeatureFlags.isMultiStreamSendSupportEnabled() && videoTracks.length) {\n                        this.addTracks(videoTracks);\n                    }\n                },\n                error => {\n                    failure(error);\n                    this.room.eventEmitter.emit(XMPPEvents.SESSION_ACCEPT_ERROR, this, error);\n                });\n            },\n            failure,\n            localTracks);\n    }\n\n    /**\n     * Creates an offer and sends Jingle 'session-initiate' to the remote peer.\n     *\n     * @param {Array<JitsiLocalTrack>} localTracks the local tracks that will be added, before the offer/answer cycle\n     * executes (for the local track addition to be an atomic operation together with the offer/answer).\n     */\n    invite(localTracks = []) {\n        if (!this.isInitiator) {\n            throw new Error('Trying to invite from the responder session');\n        }\n        const workFunction = finishedCallback => {\n            const addTracks = [];\n\n            for (const track of localTracks) {\n                addTracks.push(this.peerconnection.addTrack(track, this.isInitiator));\n            }\n\n            Promise.all(addTracks)\n                .then(() => this.peerconnection.createOffer(this.mediaConstraints))\n                .then(offerSdp => this.peerconnection.setLocalDescription(offerSdp))\n                .then(() => {\n                    this.peerconnection.processLocalSdpForTransceiverInfo(localTracks);\n\n                    // NOTE that the offer is obtained from the localDescription getter as it needs to go though\n                    // the transformation chain.\n                    this.sendSessionInitiate(this.peerconnection.localDescription.sdp);\n                })\n                .then(() => finishedCallback(), error => finishedCallback(error));\n        };\n\n        logger.debug(`${this} Queued invite task`);\n        this.modificationQueue.push(\n            workFunction,\n            error => {\n                if (error) {\n                    logger.error(`${this} invite error`, error);\n                } else {\n                    logger.debug(`${this} invite executed - OK`);\n                }\n            });\n    }\n\n    /**\n     * Sends 'session-initiate' to the remote peer.\n     *\n     * NOTE this method is synchronous and we're not waiting for the RESULT\n     * response which would delay the startup process.\n     *\n     * @param {string} offerSdp  - The local session description which will be\n     * used to generate an offer.\n     * @private\n     */\n    sendSessionInitiate(offerSdp) {\n        let init = $iq({\n            to: this.remoteJid,\n            type: 'set'\n        }).c('jingle', {\n            xmlns: 'urn:xmpp:jingle:1',\n            action: 'session-initiate',\n            initiator: this.initiatorJid,\n            sid: this.sid\n        });\n\n        new SDP(offerSdp).toJingle(\n            init,\n            this.isInitiator ? 'initiator' : 'responder');\n        init = init.tree();\n        logger.debug(`${this} Session-initiate: `, init);\n        this.connection.sendIQ(init,\n            () => {\n                logger.info(`${this} Got RESULT for \"session-initiate\"`);\n            },\n            error => {\n                logger.error(`${this} \"session-initiate\" error`, error);\n            },\n            IQ_TIMEOUT);\n    }\n\n    /**\n     * Sets the answer received from the remote peer as the remote description.\n     *\n     * @param jingleAnswer\n     */\n    setAnswer(jingleAnswer) {\n        if (!this.isInitiator) {\n            throw new Error('Trying to set an answer on the responder session');\n        }\n\n        const workFunction = finishedCallback => {\n            const newRemoteSdp = this._processNewJingleOfferIq(jingleAnswer);\n            const oldLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\n            const remoteDescription = new RTCSessionDescription({\n                type: 'answer',\n                sdp: newRemoteSdp.raw\n            });\n\n            this.peerconnection.setRemoteDescription(remoteDescription)\n                .then(() => {\n                    if (this.state === JingleSessionState.PENDING) {\n                        this.state = JingleSessionState.ACTIVE;\n                        const newLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\n\n                        this.sendContentModify();\n                        this.notifyMySSRCUpdate(oldLocalSdp, newLocalSdp);\n                    }\n                })\n                .then(() => finishedCallback(), error => finishedCallback(error));\n        };\n\n        logger.debug(`${this} Queued setAnswer task`);\n        this.modificationQueue.push(\n            workFunction,\n            error => {\n                if (error) {\n                    logger.error(`${this} setAnswer task failed: ${error}`);\n                } else {\n                    logger.debug(`${this} setAnswer task done`);\n                }\n            });\n    }\n\n    /**\n     * This is a setRemoteDescription/setLocalDescription cycle which starts at converting Strophe Jingle IQ into\n     * remote offer SDP. Once converted, setRemoteDescription, createAnswer and setLocalDescription calls follow.\n     *\n     * @param jingleOfferAnswerIq jQuery selector pointing to the jingle element of the offer (or answer) IQ\n     * @param success callback called when sRD/sLD cycle finishes successfully.\n     * @param failure callback called with an error object as an argument if we fail at any point during setRD,\n     * createAnswer, setLD.\n     * @param {Array<JitsiLocalTrack>} [localTracks] the optional list of the local tracks that will be added, before\n     * the offer/answer cycle executes (for the local track addition to be an atomic operation together with the\n     * offer/answer).\n     */\n    setOfferAnswerCycle(jingleOfferAnswerIq, success, failure, localTracks = []) {\n        const workFunction = finishedCallback => {\n            const addTracks = [];\n            const audioTracks = localTracks.filter(track => track.getType() === MediaType.AUDIO);\n            const videoTracks = localTracks.filter(track => track.getType() === MediaType.VIDEO);\n            let tracks = localTracks;\n\n            // Add only 1 video track at a time. Adding 2 or more video tracks to the peerconnection at the same time\n            // makes the browser go into a renegotiation loop by firing 'negotiationneeded' event after every\n            // renegotiation.\n            if (FeatureFlags.isMultiStreamSendSupportEnabled() && videoTracks.length > 1) {\n                tracks = [ ...audioTracks, videoTracks[0] ];\n            }\n            for (const track of tracks) {\n                addTracks.push(this.peerconnection.addTrack(track, this.isInitiator));\n            }\n            const newRemoteSdp = this._processNewJingleOfferIq(jingleOfferAnswerIq);\n            const oldLocalSdp = this.peerconnection.localDescription.sdp;\n\n            const bridgeSession = $(jingleOfferAnswerIq)\n                .find('>bridge-session[xmlns=\"http://jitsi.org/protocol/focus\"]');\n            const bridgeSessionId = bridgeSession.attr('id');\n\n            if (bridgeSessionId !== this._bridgeSessionId) {\n                this._bridgeSessionId = bridgeSessionId;\n            }\n            const remoteDescription = new RTCSessionDescription({\n                type: 'offer',\n                sdp: newRemoteSdp.raw\n            });\n\n            Promise.all(addTracks)\n                .then(() => this._responderRenegotiate(remoteDescription))\n                .then(() => {\n                    this.peerconnection.processLocalSdpForTransceiverInfo(tracks);\n                    if (this.state === JingleSessionState.PENDING) {\n                        this.state = JingleSessionState.ACTIVE;\n\n                        // #1 Sync up video transfer active/inactive only after the initial O/A cycle. We want to\n                        // adjust the video media direction only in the local SDP and the Jingle contents direction\n                        // included in the initial offer/answer is mapped to the remote SDP. Jingle 'content-modify'\n                        // IQ is processed in a way that it will only modify local SDP when remote peer is no longer\n                        // interested in receiving video content. Changing media direction in the remote SDP will mess\n                        // up our SDP translation chain (simulcast, video mute, RTX etc.)\n                        // #2 Sends the max frame height if it was set, before the session-initiate/accept\n                        if (this.isP2P\n                            && (!this._localVideoActive || this._sourceReceiverConstraints)) {\n                            this.sendContentModify();\n                        }\n                    }\n\n                    // Old local SDP will be available when we're setting answer for the first time, but not when offer\n                    // and it's fine since we're generating an answer now it will contain all our SSRCs.\n                    if (oldLocalSdp) {\n                        const newLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\n\n                        this.notifyMySSRCUpdate(new SDP(oldLocalSdp), newLocalSdp);\n                    }\n                })\n                .then(() => finishedCallback(), error => finishedCallback(error));\n        };\n\n        logger.debug(`${this} Queued setOfferAnswerCycle task`);\n        this.modificationQueue.push(\n            workFunction,\n            error => {\n                if (error) {\n                    logger.error(`${this} setOfferAnswerCycle task failed: ${error}`);\n                    failure(error);\n                } else {\n                    logger.debug(`${this} setOfferAnswerCycle task done`);\n                    success();\n                }\n            });\n    }\n\n    /**\n     * Updates the codecs on the peerconnection and initiates a renegotiation for the\n     * new codec config to take effect.\n     *\n     * @param {CodecMimeType} preferred the preferred codec.\n     * @param {CodecMimeType} disabled the codec that needs to be disabled.\n     */\n    setVideoCodecs(preferred = null, disabled = null) {\n        if (this._assertNotEnded()) {\n            logger.info(`${this} setVideoCodecs: preferred=${preferred}, disabled=${disabled}`);\n            this.peerconnection.setVideoCodecs(preferred, disabled);\n\n            // Initiate a renegotiate for the codec setting to take effect.\n            const workFunction = finishedCallback => {\n                this._renegotiate().then(\n                    () => {\n                        logger.debug(`${this} setVideoCodecs task is done`);\n\n                        return finishedCallback();\n                    }, error => {\n                        logger.error(`${this} setVideoCodecs task failed: ${error}`);\n\n                        return finishedCallback(error);\n                    });\n            };\n\n            logger.debug(`${this} Queued setVideoCodecs task`);\n\n            // Queue and execute\n            this.modificationQueue.push(workFunction);\n        }\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Although it states \"replace transport\" it does accept full Jingle offer\n     * which should contain new ICE transport details.\n     * @param jingleOfferElem an element Jingle IQ that contains new offer and\n     *        transport info.\n     * @param success callback called when we succeed to accept new offer.\n     * @param failure function(error) called when we fail to accept new offer.\n     */\n    replaceTransport(jingleOfferElem, success, failure) {\n        if (this.options.enableForcedReload) {\n            const sdp = new SDP(this.peerconnection.localDescription.sdp);\n\n            this.sendTransportAccept(sdp, success, failure);\n            this.room.eventEmitter.emit(XMPPEvents.CONNECTION_RESTARTED, this);\n\n            return;\n        }\n        this.room.eventEmitter.emit(XMPPEvents.ICE_RESTARTING, this);\n\n        // We need to first reject the 'data' section to have the SCTP stack\n        // cleaned up to signal the known data channel is now invalid. After\n        // that the original offer is set to have the SCTP connection\n        // established with the new bridge.\n        const originalOffer = jingleOfferElem.clone();\n\n        jingleOfferElem\n            .find('>content[name=\\'data\\']')\n            .attr('senders', 'rejected');\n\n        // Remove all remote sources in order to reset the client's state\n        // for the remote MediaStreams. When a conference is moved to\n        // another bridge it will start streaming with a sequence number\n        // that is not in sync with the most recently seen by the client.\n        // The symptoms include frozen or black video and lots of \"failed to\n        // unprotect SRTP packets\" in Chrome logs.\n        jingleOfferElem\n            .find('>content>description>source')\n            .remove();\n        jingleOfferElem\n            .find('>content>description>ssrc-group')\n            .remove();\n\n        // On the JVB it's not a real ICE restart and all layers are re-initialized from scratch as Jicofo does\n        // the restart by re-allocating new channels. Chrome (or WebRTC stack) needs to have the DTLS transport layer\n        // reset to start a new handshake with fresh DTLS transport on the bridge. Make it think that the DTLS\n        // fingerprint has changed by setting an all zeros key.\n        const newFingerprint = jingleOfferElem.find('>content>transport>fingerprint');\n\n        newFingerprint.attr('hash', 'sha-1');\n        newFingerprint.text('00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00');\n\n        // First set an offer with a rejected 'data' section\n        this.setOfferAnswerCycle(\n            jingleOfferElem,\n            () => {\n                // Now set the original offer(with the 'data' section)\n                this.setOfferAnswerCycle(\n                    originalOffer,\n                    () => {\n                        const localSDP = new SDP(this.peerconnection.localDescription.sdp);\n\n                        if (typeof this.options.channelLastN === 'number' && this.options.channelLastN >= 0) {\n                            localSDP.initialLastN = this.options.channelLastN;\n                        }\n\n                        this.sendTransportAccept(localSDP, success, failure);\n\n                        this.room.eventEmitter.emit(\n                            XMPPEvents.ICE_RESTART_SUCCESS,\n                            this,\n                            originalOffer);\n                    },\n                    failure);\n            },\n            failure\n        );\n    }\n\n    /**\n     * Sends Jingle 'session-accept' message.\n     * @param {function()} success callback called when we receive 'RESULT'\n     *        packet for the 'session-accept'\n     * @param {function(error)} failure called when we receive an error response\n     *        or when the request has timed out.\n     * @private\n     */\n    sendSessionAccept(success, failure) {\n        // NOTE: since we're just reading from it, we don't need to be within\n        //  the modification queue to access the local description\n        const localSDP = new SDP(this.peerconnection.localDescription.sdp);\n        const accept = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', { xmlns: 'urn:xmpp:jingle:1',\n                action: 'session-accept',\n                initiator: this.initiatorJid,\n                responder: this.responderJid,\n                sid: this.sid });\n\n        if (this.webrtcIceTcpDisable) {\n            localSDP.removeTcpCandidates = true;\n        }\n        if (this.webrtcIceUdpDisable) {\n            localSDP.removeUdpCandidates = true;\n        }\n        if (this.failICE) {\n            localSDP.failICE = true;\n        }\n        if (typeof this.options.channelLastN === 'number' && this.options.channelLastN >= 0) {\n            localSDP.initialLastN = this.options.channelLastN;\n        }\n        localSDP.toJingle(\n            accept,\n            this.initiatorJid === this.localJid ? 'initiator' : 'responder');\n\n        logger.info(`${this} Sending session-accept`);\n        logger.debug(accept.tree());\n        this.connection.sendIQ(accept,\n            success,\n            this.newJingleErrorHandler(accept, error => {\n                failure(error);\n\n                // 'session-accept' is a critical timeout and we'll\n                // have to restart\n                this.room.eventEmitter.emit(\n                    XMPPEvents.SESSION_ACCEPT_TIMEOUT, this);\n            }),\n            IQ_TIMEOUT);\n\n        // XXX Videobridge needs WebRTC's answer (ICE ufrag and pwd, DTLS\n        // fingerprint and setup) ASAP in order to start the connection\n        // establishment.\n        //\n        // FIXME Flushing the connection at this point triggers an issue with\n        // BOSH request handling in Prosody on slow connections.\n        //\n        // The problem is that this request will be quite large and it may take\n        // time before it reaches Prosody. In the meantime Strophe may decide\n        // to send the next one. And it was observed that a small request with\n        // 'transport-info' usually follows this one. It does reach Prosody\n        // before the previous one was completely received. 'rid' on the server\n        // is increased and Prosody ignores the request with 'session-accept'.\n        // It will never reach Jicofo and everything in the request table is\n        // lost. Removing the flush does not guarantee it will never happen, but\n        // makes it much less likely('transport-info' is bundled with\n        // 'session-accept' and any immediate requests).\n        //\n        // this.connection.flush();\n    }\n\n    /**\n     * Will send 'content-modify' IQ in order to ask the remote peer to\n     * either stop or resume sending video media or to adjust sender's video constraints.\n     * @private\n     */\n    sendContentModify() {\n        const senders = this._localVideoActive ? 'both' : 'none';\n        const sessionModify\n            = $iq({\n                to: this.remoteJid,\n                type: 'set'\n            })\n                .c('jingle', {\n                    xmlns: 'urn:xmpp:jingle:1',\n                    action: 'content-modify',\n                    initiator: this.initiatorJid,\n                    sid: this.sid\n                })\n                .c('content', {\n                    name: MediaType.VIDEO,\n                    senders\n                });\n\n        if (typeof this._sourceReceiverConstraints !== 'undefined') {\n            this._sourceReceiverConstraints.forEach((maxHeight, sourceName) => {\n                sessionModify\n                    .c('source-frame-height', { xmlns: 'http://jitsi.org/jitmeet/video' })\n                    .attrs({\n                        sourceName,\n                        maxHeight\n                    });\n\n                sessionModify.up();\n                logger.info(`${this} sending content-modify for source-name: ${sourceName}, maxHeight: ${maxHeight}`);\n            });\n        }\n\n        logger.debug(sessionModify.tree());\n\n        this.connection.sendIQ(\n            sessionModify,\n            null,\n            this.newJingleErrorHandler(sessionModify),\n            IQ_TIMEOUT);\n    }\n\n    /**\n     * Adjust the preference for max video frame height that the local party is willing to receive. Signals\n     * the remote p2p peer.\n     *\n     * @param {Map<string, number>} sourceReceiverConstraints - The receiver constraints per source.\n     */\n    setReceiverVideoConstraint(sourceReceiverConstraints) {\n        logger.info(`${this} setReceiverVideoConstraint - constraints: ${JSON.stringify(sourceReceiverConstraints)}`);\n        this._sourceReceiverConstraints = sourceReceiverConstraints;\n\n        if (this.isP2P) {\n            // Tell the remote peer about our receive constraint. If Jingle session is not yet active the state will\n            // be synced after offer/answer.\n            if (this.state === JingleSessionState.ACTIVE) {\n                this.sendContentModify();\n            }\n        }\n    }\n\n    /**\n     * Sends Jingle 'transport-accept' message which is a response to\n     * 'transport-replace'.\n     * @param localSDP the 'SDP' object with local session description\n     * @param success callback called when we receive 'RESULT' packet for\n     *        'transport-replace'\n     * @param failure function(error) called when we receive an error response\n     *        or when the request has timed out.\n     * @private\n     */\n    sendTransportAccept(localSDP, success, failure) {\n        const transportAccept = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', {\n                xmlns: 'urn:xmpp:jingle:1',\n                action: 'transport-accept',\n                initiator: this.initiatorJid,\n                sid: this.sid\n            });\n\n        localSDP.media.forEach((medialines, idx) => {\n            const mline = SDPUtil.parseMLine(medialines.split('\\r\\n')[0]);\n\n            transportAccept.c('content',\n                {\n                    creator:\n                        this.initiatorJid === this.localJid\n                            ? 'initiator'\n                            : 'responder',\n                    name: mline.media\n                }\n            );\n            localSDP.transportToJingle(idx, transportAccept);\n            transportAccept.up();\n        });\n\n        logger.info(`${this} Sending transport-accept`);\n        logger.debug(transportAccept.tree());\n\n        this.connection.sendIQ(transportAccept,\n            success,\n            this.newJingleErrorHandler(transportAccept, failure),\n            IQ_TIMEOUT);\n    }\n\n    /**\n     * Sends Jingle 'transport-reject' message which is a response to\n     * 'transport-replace'.\n     * @param success callback called when we receive 'RESULT' packet for\n     *        'transport-replace'\n     * @param failure function(error) called when we receive an error response\n     *        or when the request has timed out.\n     *\n     * FIXME method should be marked as private, but there's some spaghetti that\n     *       needs to be fixed prior doing that\n     */\n    sendTransportReject(success, failure) {\n        // Send 'transport-reject', so that the focus will\n        // know that we've failed\n        const transportReject = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', {\n                xmlns: 'urn:xmpp:jingle:1',\n                action: 'transport-reject',\n                initiator: this.initiatorJid,\n                sid: this.sid\n            });\n\n        logger.info(`${this} Sending 'transport-reject'`);\n        logger.debug(transportReject.tree());\n\n        this.connection.sendIQ(transportReject,\n            success,\n            this.newJingleErrorHandler(transportReject, failure),\n            IQ_TIMEOUT);\n    }\n\n    /**\n     * Sets the resolution constraint on the local camera track.\n     * @param {number} maxFrameHeight - The user preferred max frame height.\n     * @param {string} sourceName - The source name of the track.\n     * @returns {Promise} promise that will be resolved when the operation is\n     * successful and rejected otherwise.\n     */\n    setSenderVideoConstraint(maxFrameHeight, sourceName = null) {\n        if (this._assertNotEnded()) {\n            logger.info(`${this} setSenderVideoConstraint: ${maxFrameHeight}, sourceName: ${sourceName}`);\n\n            const jitsiLocalTrack = sourceName\n                ? this.rtc.getLocalVideoTracks().find(track => track.getSourceName() === sourceName)\n                : this.rtc.getLocalVideoTrack();\n\n            return this.peerconnection.setSenderVideoConstraints(maxFrameHeight, jitsiLocalTrack);\n        }\n\n        return Promise.resolve();\n    }\n\n    /**\n     * @inheritDoc\n     */\n    terminate(success, failure, options) {\n        if (this.state === JingleSessionState.ENDED) {\n            return;\n        }\n\n        if (!options || Boolean(options.sendSessionTerminate)) {\n            const sessionTerminate\n                = $iq({\n                    to: this.remoteJid,\n                    type: 'set'\n                })\n                    .c('jingle', {\n                        xmlns: 'urn:xmpp:jingle:1',\n                        action: 'session-terminate',\n                        initiator: this.initiatorJid,\n                        sid: this.sid\n                    })\n                    .c('reason')\n                    .c((options && options.reason) || 'success')\n                    .up();\n\n            if (options && options.reasonDescription) {\n                sessionTerminate\n                    .c('text')\n                    .t(options.reasonDescription)\n                    .up()\n                    .up();\n            } else {\n                sessionTerminate.up();\n            }\n\n            this._bridgeSessionId\n                && sessionTerminate.c(\n                    'bridge-session', {\n                        xmlns: 'http://jitsi.org/protocol/focus',\n                        id: this._bridgeSessionId,\n                        restart: options && options.requestRestart === true\n                    }).up();\n\n            logger.info(`${this} Sending session-terminate`);\n            logger.debug(sessionTerminate.tree());\n\n            this.connection.sendIQ(\n                sessionTerminate,\n                success,\n                this.newJingleErrorHandler(sessionTerminate, failure),\n                IQ_TIMEOUT);\n        } else {\n            logger.info(`${this} Skipped sending session-terminate`);\n        }\n\n        // this should result in 'onTerminated' being called by strope.jingle.js\n        this.connection.jingle.terminate(this.sid);\n    }\n\n    /**\n     *\n     * @param reasonCondition\n     * @param reasonText\n     */\n    onTerminated(reasonCondition, reasonText) {\n        // Do something with reason and reasonCondition when we start to care\n        // this.reasonCondition = reasonCondition;\n        // this.reasonText = reasonText;\n        logger.info(`${this} Session terminated`, reasonCondition, reasonText);\n\n        this._xmppListeners.forEach(removeListener => removeListener());\n        this._xmppListeners = [];\n\n        if (this._removeSenderVideoConstraintsChangeListener) {\n            this._removeSenderVideoConstraintsChangeListener();\n        }\n\n        if (FeatureFlags.isSsrcRewritingSupported() && this.peerconnection) {\n            this.peerconnection.getRemoteTracks().forEach(track => {\n                this.room.eventEmitter.emit(JitsiTrackEvents.TRACK_REMOVED, track);\n            });\n        }\n\n        this.close();\n    }\n\n    /**\n     * Handles XMPP connection state changes.\n     *\n     * @param {XmppConnection.Status} status - The new status.\n     */\n    onXmppStatusChanged(status) {\n        if (status === XmppConnection.Status.CONNECTED && this._cachedOldLocalSdp) {\n            logger.info(`${this} Sending SSRC update on reconnect`);\n            this.notifyMySSRCUpdate(\n                this._cachedOldLocalSdp,\n                this._cachedNewLocalSdp);\n        }\n    }\n\n    /**\n     * Parse the information from the xml sourceAddElem and translate it\n     *  into sdp lines\n     * @param {jquery xml element} sourceAddElem the source-add\n     *  element from jingle\n     * @param {SDP object} currentRemoteSdp the current remote\n     *  sdp (as of this new source-add)\n     * @returns {list} a list of SDP line strings that should\n     *  be added to the remote SDP\n     */\n    _parseSsrcInfoFromSourceAdd(sourceAddElem, currentRemoteSdp) {\n        const addSsrcInfo = [];\n        const self = this;\n\n        $(sourceAddElem).each((i1, content) => {\n            const name = $(content).attr('name');\n            let lines = '';\n\n            $(content)\n                .find('ssrc-group[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\n                .each(function() {\n                    // eslint-disable-next-line no-invalid-this\n                    const semantics = this.getAttribute('semantics');\n                    const ssrcs\n                        = $(this) // eslint-disable-line no-invalid-this\n                            .find('>source')\n                            .map(function() {\n                                // eslint-disable-next-line no-invalid-this\n                                return this.getAttribute('ssrc');\n                            })\n                            .get();\n\n                    if (ssrcs.length) {\n                        lines += `a=ssrc-group:${semantics} ${ssrcs.join(' ')}\\r\\n`;\n                    }\n                });\n\n            // handles both >source and >description>source\n            const tmp\n                = $(content).find(\n                    'source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]');\n\n            /* eslint-disable no-invalid-this */\n            tmp.each(function() {\n                const ssrc = $(this).attr('ssrc');\n\n                if (currentRemoteSdp.containsSSRC(ssrc)) {\n\n                    // Do not print the warning for unified plan p2p case since ssrcs are never removed from the SDP.\n                    !(self.usesUnifiedPlan && self.isP2P)\n                        && logger.warn(`${self} Source-add request for existing SSRC: ${ssrc}`);\n\n                    return;\n                }\n\n                // eslint-disable-next-line newline-per-chained-call\n                $(this).find('>parameter').each(function() {\n                    lines += `a=ssrc:${ssrc} ${$(this).attr('name')}`;\n                    if ($(this).attr('value') && $(this).attr('value').length) {\n                        lines += `:${$(this).attr('value')}`;\n                    }\n                    lines += '\\r\\n';\n                });\n            });\n\n            let midFound = false;\n\n            /* eslint-enable no-invalid-this */\n            currentRemoteSdp.media.forEach((media, i2) => {\n                if (!SDPUtil.findLine(media, `a=mid:${name}`)) {\n                    return;\n                }\n                if (!addSsrcInfo[i2]) {\n                    addSsrcInfo[i2] = '';\n                }\n                addSsrcInfo[i2] += lines;\n                midFound = true;\n            });\n\n            // In p2p unified mode with multi-stream enabled, the new sources will have content name that doesn't exist\n            // in the current remote description. Add a new m-line for this newly signaled source.\n            if (!midFound && this.isP2P) {\n                addSsrcInfo[name] = lines;\n            }\n        });\n\n        return addSsrcInfo;\n    }\n\n    /**\n     * Handles a Jingle source-add message for this Jingle session.\n     * @param elem An array of Jingle \"content\" elements.\n     */\n    addRemoteStream(elem) {\n        this._addOrRemoveRemoteStream(true /* add */, elem);\n    }\n\n    /**\n     * Handles a Jingle source-remove message for this Jingle session.\n     * @param elem An array of Jingle \"content\" elements.\n     */\n    removeRemoteStream(elem) {\n        this._addOrRemoveRemoteStream(false /* remove */, elem);\n    }\n\n    /**\n     * Processes the source map message received from the bridge and creates a new remote track for newly signaled\n     * SSRCs or updates the source-name and owner on the remote track for an existing SSRC.\n     *\n     * @param {Object} message - The source map message.\n     * @param {string} mediaType - The media type, 'audio' or 'video'.\n     * @returns {void}\n     */\n    processSourceMap(message, mediaType) {\n        const newSources = [];\n\n        for (const src of message.mappedSources) {\n            if (this.peerconnection.addRemoteSsrc(src.ssrc)) {\n                newSources.push(src);\n            } else {\n                const { owner, source, ssrc, videoType } = src;\n                const track = this.peerconnection.getTrackBySSRC(ssrc);\n\n                if (track) {\n                    logger.debug(`Existing SSRC ${ssrc}: new owner=${owner}, source-name=${source}`);\n\n                    // Update the SSRC owner.\n                    this._signalingLayer.setSSRCOwner(ssrc, owner);\n\n                    // Update the track with all the relevant info.\n                    track.setSourceName(source);\n                    track.setOwner(owner);\n                    if (mediaType === MediaType.VIDEO) {\n                        const type = videoType === 'CAMERA' ? VideoType.CAMERA : VideoType.DESKTOP;\n\n                        track._setVideoType(type);\n                    }\n\n                    // Update the muted state on the track since the presence for this track could have been received\n                    // before the updated source map is received on the bridge channel.\n                    const peerMediaInfo = this._signalingLayer.getPeerMediaInfo(owner, mediaType, source);\n\n                    peerMediaInfo && this.peerconnection._sourceMutedChanged(source, peerMediaInfo.muted);\n                } else {\n                    logger.error(`Remote track attached to a remote SSRC=${ssrc} not found`);\n                }\n            }\n        }\n\n        // Add the new SSRCs to the remote description by generating a source message.\n        if (newSources.length) {\n            let node = $build('content', {\n                xmlns: 'urn:xmpp:jingle:1',\n                name: mediaType\n            }).c('description', {\n                xmlns: 'urn:xmpp:jingle:apps:rtp:1',\n                media: mediaType\n            });\n\n            for (const src of newSources) {\n                const { rtx, ssrc } = src;\n                let msid;\n\n                if (mediaType === MediaType.VIDEO) {\n                    const idx = ++this.numRemoteVideoSources;\n\n                    msid = `remote-video-${idx} remote-video-${idx}`;\n\n                    if (rtx !== '-1') {\n                        _addSourceElement(node, src, rtx, msid);\n                        node.c('ssrc-group', {\n                            xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\n                            semantics: 'FID'\n                        })\n                            .c('source', {\n                                xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\n                                ssrc\n                            })\n                            .up()\n                            .c('source', {\n                                xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\n                                ssrc: rtx\n                            })\n                            .up()\n                            .up();\n                    }\n                } else {\n                    const idx = ++this.numRemoteAudioSources;\n\n                    msid = `remote-audio-${idx} remote-audio-${idx}`;\n                }\n                _addSourceElement(node, src, ssrc, msid);\n            }\n            node = node.up();\n            this._addOrRemoveRemoteStream(true /* add */, node.node);\n        }\n    }\n\n    /**\n     * Handles the deletion of SSRCs associated with a remote user from the remote description when the user leaves.\n     *\n     * @param {string} id Endpoint id of the participant that has left the call.\n     * @returns {void}\n     */\n    removeRemoteStreamsOnLeave(id) {\n        const workFunction = finishCallback => {\n            const removeSsrcInfo = this.peerconnection.getRemoteSourceInfoByParticipant(id);\n\n            if (removeSsrcInfo.length) {\n                const oldLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\n                const newRemoteSdp = this._processRemoteRemoveSource(removeSsrcInfo);\n\n                this._renegotiate(newRemoteSdp.raw)\n                    .then(() => {\n                        const newLocalSDP = new SDP(this.peerconnection.localDescription.sdp);\n\n                        this.notifyMySSRCUpdate(oldLocalSdp, newLocalSDP);\n                        finishCallback();\n                    })\n                    .catch(err => finishCallback(err));\n            } else {\n                finishCallback();\n            }\n        };\n\n        logger.debug(`${this} Queued removeRemoteStreamsOnLeave task for participant ${id}`);\n\n        this.modificationQueue.push(\n            workFunction,\n            error => {\n                if (error) {\n                    logger.error(`${this} removeRemoteStreamsOnLeave error:`, error);\n                } else {\n                    logger.info(`${this} removeRemoteStreamsOnLeave done!`);\n                }\n            });\n    }\n\n    /**\n     * Handles either Jingle 'source-add' or 'source-remove' message for this\n     * Jingle session.\n     * @param {boolean} isAdd <tt>true</tt> for 'source-add' or <tt>false</tt>\n     * otherwise.\n     * @param {Array<Element>} elem an array of Jingle \"content\" elements.\n     * @private\n     */\n    _addOrRemoveRemoteStream(isAdd, elem) {\n        const logPrefix = isAdd ? 'addRemoteStream' : 'removeRemoteStream';\n\n        if (isAdd) {\n            this.readSsrcInfo(elem);\n        }\n\n        const workFunction = finishedCallback => {\n            if (!this.peerconnection.localDescription\n                || !this.peerconnection.localDescription.sdp) {\n                const errMsg = `${logPrefix} - localDescription not ready yet`;\n\n                logger.error(errMsg);\n                finishedCallback(errMsg);\n\n                return;\n            }\n\n            logger.log(`${this} Processing ${logPrefix}`);\n\n            const oldLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\n            const sdp = new SDP(this.peerconnection.remoteDescription.sdp);\n            const addOrRemoveSsrcInfo\n                = isAdd\n                    ? this._parseSsrcInfoFromSourceAdd(elem, sdp)\n                    : this._parseSsrcInfoFromSourceRemove(elem, sdp);\n            const newRemoteSdp\n                = isAdd\n                    ? this._processRemoteAddSource(addOrRemoveSsrcInfo)\n                    : this._processRemoteRemoveSource(addOrRemoveSsrcInfo);\n            const remoteDescription = new RTCSessionDescription({\n                type: 'offer',\n                sdp: newRemoteSdp.raw\n            });\n\n            // Always initiate a sRD->cA->sLD cycle when a remote source is added or removed irrespective of whether\n            // the local endpoint is an initiator or responder. Fixes bugs on Chromium where decoders are not created\n            // when sLD->cO->sRD cycle is initiated for p2p cases when remote sources are received.\n            this._responderRenegotiate(remoteDescription).then(() => {\n                const newLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\n\n                logger.log(`${this} ${logPrefix} - OK`);\n                this.notifyMySSRCUpdate(oldLocalSdp, newLocalSdp);\n                finishedCallback();\n            }, error => {\n                logger.error(`${this} ${logPrefix} failed:`, error);\n                finishedCallback(error);\n            });\n        };\n\n        logger.debug(`${this} Queued ${logPrefix} task`);\n\n        // Queue and execute\n        this.modificationQueue.push(workFunction);\n    }\n\n    /**\n     * Takes in a jingle offer iq, returns the new sdp offer\n     * @param {jquery xml element} offerIq the incoming offer\n     * @returns {SDP object} the jingle offer translated to SDP\n     */\n    _processNewJingleOfferIq(offerIq) {\n        const remoteSdp = new SDP('');\n\n        if (this.webrtcIceTcpDisable) {\n            remoteSdp.removeTcpCandidates = true;\n        }\n        if (this.webrtcIceUdpDisable) {\n            remoteSdp.removeUdpCandidates = true;\n        }\n        if (this.failICE) {\n            remoteSdp.failICE = true;\n        }\n\n        remoteSdp.fromJingle(offerIq);\n        this.readSsrcInfo($(offerIq).find('>content'));\n\n        return remoteSdp;\n    }\n\n    /**\n     * Remove the given ssrc lines from the current remote sdp\n     * @param {list} removeSsrcInfo a list of SDP line strings that\n     *  should be removed from the remote SDP\n     * @returns type {SDP Object} the new remote SDP (after removing the lines\n     *  in removeSsrcInfo\n     */\n    _processRemoteRemoveSource(removeSsrcInfo) {\n        const remoteSdp = this.usesUnifiedPlan\n            ? new SDP(this.peerconnection.peerconnection.remoteDescription.sdp)\n            : new SDP(this.peerconnection.remoteDescription.sdp);\n        let ssrcs;\n\n        removeSsrcInfo.forEach((lines, idx) => {\n            // eslint-disable-next-line no-param-reassign\n            lines = lines.split('\\r\\n');\n            lines.pop(); // remove empty last element;\n            ssrcs = lines.map(line => Number(line.split('a=ssrc:')[1]?.split(' ')[0]));\n\n            if (this.usesUnifiedPlan) {\n                let mid;\n\n                lines.forEach(line => {\n                    mid = remoteSdp.media.findIndex(mLine => mLine.includes(line));\n\n                    if (mid > -1) {\n                        remoteSdp.media[mid] = remoteSdp.media[mid].replace(`${line}\\r\\n`, '');\n                        if (this.isP2P) {\n                            const mediaType = SDPUtil.parseMLine(remoteSdp.media[mid].split('\\r\\n')[0])?.media;\n                            const desiredDirection = this.peerconnection.getDesiredMediaDirection(mediaType, false);\n\n                            [ MediaDirection.SENDRECV, MediaDirection.SENDONLY ].forEach(direction => {\n                                remoteSdp.media[mid] = remoteSdp.media[mid]\n                                    .replace(`a=${direction}`, `a=${desiredDirection}`);\n                            });\n                        } else {\n                            // Jvb connections will have direction set to 'sendonly' for the remote sources.\n                            remoteSdp.media[mid] = remoteSdp.media[mid]\n                                .replace(`a=${MediaDirection.SENDONLY}`, `a=${MediaDirection.INACTIVE}`);\n                        }\n                    }\n                });\n\n                // Reject the m-line so that the browser removes the associated transceiver from the list of available\n                // transceivers. This will prevent the client from trying to re-use these inactive transceivers when\n                // additional video sources are added to the peerconnection.\n                if (mid > -1 && !this.isP2P && FeatureFlags.isMultiStreamSendSupportEnabled()) {\n                    const { media, port } = SDPUtil.parseMLine(remoteSdp.media[mid].split('\\r\\n')[0]);\n\n                    remoteSdp.media[mid] = remoteSdp.media[mid].replace(`m=${media} ${port}`, `m=${media} 0`);\n                }\n            } else {\n                lines.forEach(line => {\n                    remoteSdp.media[idx] = remoteSdp.media[idx].replace(`${line}\\r\\n`, '');\n                });\n            }\n        });\n\n        // Update the ssrc owners list.\n        ssrcs?.length && this._signalingLayer.removeSSRCOwners(ssrcs);\n\n        remoteSdp.raw = remoteSdp.session + remoteSdp.media.join('');\n\n        return remoteSdp;\n    }\n\n    /**\n     * Add the given ssrc lines to the current remote sdp\n     * @param {list} addSsrcInfo a list of SDP line strings that\n     *  should be added to the remote SDP\n     * @returns type {SDP Object} the new remote SDP (after removing the lines\n     *  in removeSsrcInfo\n     */\n    _processRemoteAddSource(addSsrcInfo) {\n        let remoteSdp = new SDP(this.peerconnection.remoteDescription.sdp);\n\n        // Add a new m-line in the remote description if the source info for a secondary video source is recceived from\n        // the remote p2p peer when multi-stream support is enabled.\n        if (addSsrcInfo.length > remoteSdp.media.length\n            && this.isP2P\n            && this.usesUnifiedPlan) {\n            remoteSdp.addMlineForNewLocalSource(MediaType.VIDEO);\n            remoteSdp = new SDP(remoteSdp.raw);\n        }\n        addSsrcInfo.forEach((lines, idx) => {\n            remoteSdp.media[idx] += lines;\n\n            // Make sure to change the direction to 'sendrecv/sendonly' only for p2p connections. For jvb connections,\n            // a new m-line is added for the new remote sources.\n            if (this.isP2P && this.usesUnifiedPlan) {\n                const mediaType = SDPUtil.parseMLine(remoteSdp.media[idx].split('\\r\\n')[0])?.media;\n                const desiredDirection = this.peerconnection.getDesiredMediaDirection(mediaType, true);\n\n                [ MediaDirection.RECVONLY, MediaDirection.INACTIVE ].forEach(direction => {\n                    remoteSdp.media[idx] = remoteSdp.media[idx]\n                        .replace(`a=${direction}`, `a=${desiredDirection}`);\n                });\n            }\n        });\n        remoteSdp.raw = remoteSdp.session + remoteSdp.media.join('');\n\n        return remoteSdp;\n    }\n\n    /**\n     * Do a new o/a flow using the existing remote description\n     * @param {string} [optionalRemoteSdp] optional, raw remote sdp\n     *  to use.  If not provided, the remote sdp from the\n     *  peerconnection will be used\n     * @returns {Promise} promise which resolves when the\n     *  o/a flow is complete with no arguments or\n     *  rejects with an error {string}\n     */\n    _renegotiate(optionalRemoteSdp) {\n        if (this.peerconnection.signalingState === 'closed') {\n            const error = new Error('Attempted to renegotiate in state closed');\n\n            this.room.eventEmitter.emit(XMPPEvents.RENEGOTIATION_FAILED, error, this);\n\n            return Promise.reject(error);\n        }\n\n        const remoteSdp\n            = optionalRemoteSdp || this.peerconnection.remoteDescription.sdp;\n\n        if (!remoteSdp) {\n            const error = new Error(`Can not renegotiate without remote description, current state: ${this.state}`);\n\n            this.room.eventEmitter.emit(XMPPEvents.RENEGOTIATION_FAILED, error, this);\n\n            return Promise.reject(error);\n        }\n\n        const remoteDescription = new RTCSessionDescription({\n            type: this.isInitiator ? 'answer' : 'offer',\n            sdp: remoteSdp\n        });\n\n        if (this.isInitiator) {\n            return this._initiatorRenegotiate(remoteDescription);\n        }\n\n        return this._responderRenegotiate(remoteDescription);\n    }\n\n    /**\n     * Renegotiate cycle implementation for the responder case.\n     * @param {object} remoteDescription the SDP object as defined by the WebRTC\n     * which will be used as remote description in the cycle.\n     * @private\n     */\n    _responderRenegotiate(remoteDescription) {\n        logger.debug(`${this} Renegotiate: setting remote description`);\n\n        return this.peerconnection.setRemoteDescription(remoteDescription)\n            .then(() => {\n                logger.debug(`${this} Renegotiate: creating answer`);\n\n                return this.peerconnection.createAnswer(this.mediaConstraints)\n                    .then(answer => {\n                        logger.debug(`${this} Renegotiate: setting local description`);\n\n                        return this.peerconnection.setLocalDescription(answer);\n                    });\n            });\n    }\n\n    /**\n     * Renegotiate cycle implementation for the initiator's case.\n     * @param {object} remoteDescription the SDP object as defined by the WebRTC\n     * which will be used as remote description in the cycle.\n     * @private\n     */\n    _initiatorRenegotiate(remoteDescription) {\n        logger.debug(`${this} Renegotiate: creating offer`);\n\n        return this.peerconnection.createOffer(this.mediaConstraints)\n            .then(offer => {\n                logger.debug(`${this} Renegotiate: setting local description`);\n\n                return this.peerconnection.setLocalDescription(offer)\n                    .then(() => {\n                        logger.debug(`${this} Renegotiate: setting remote description`);\n\n                        // eslint-disable-next-line max-len\n                        return this.peerconnection.setRemoteDescription(remoteDescription);\n                    });\n            });\n    }\n\n    /**\n     * Adds a new track to the peerconnection. This method needs to be called only when a secondary JitsiLocalTrack is\n     * being added to the peerconnection for the first time.\n     *\n     * @param {Array<JitsiLocalTrack>} localTracks - Tracks to be added to the peer connection.\n     * @returns {Promise<void>} that resolves when the track is successfully added to the peerconnection, rejected\n     * otherwise.\n     */\n    addTracks(localTracks = null) {\n        if (!FeatureFlags.isMultiStreamSendSupportEnabled()\n            || !localTracks?.length\n            || localTracks.find(track => track.getType() !== MediaType.VIDEO)) {\n            return Promise.reject(new Error('Multiple tracks of the given media type are not supported'));\n        }\n\n        const replaceTracks = [];\n        const workFunction = finishedCallback => {\n            const oldLocalSDP = new SDP(this.peerconnection.localDescription.sdp);\n            const remoteSdp = new SDP(this.peerconnection.peerconnection.remoteDescription.sdp);\n            const recvOnlyTransceiver = this.peerconnection.peerconnection.getTransceivers()\n                    .find(t => t.receiver.track.kind === MediaType.VIDEO\n                        && t.direction === MediaDirection.RECVONLY\n                        && t.currentDirection === MediaDirection.RECVONLY);\n\n            // Add transceivers by adding a new mline in the remote description for each track. Do not create a new\n            // m-line if a recv-only transceiver exists in the p2p case. The new track will be attached to the\n            // existing one in that case.\n            for (const track of localTracks) {\n                if (!this.isP2P || !recvOnlyTransceiver) {\n                    remoteSdp.addMlineForNewLocalSource(track.getType());\n                }\n            }\n\n            const remoteDescription = new RTCSessionDescription({\n                type: 'offer',\n                sdp: remoteSdp.raw\n            });\n\n            // Always initiate a responder renegotiate since the new m-line is added to remote SDP.\n            this._responderRenegotiate(remoteDescription)\n                .then(() => {\n                    // Replace the tracks on the newly generated transceivers.\n                    for (const track of localTracks) {\n                        replaceTracks.push(this.peerconnection.replaceTrack(null, track));\n                    }\n\n                    return Promise.all(replaceTracks);\n                })\n\n                // Trigger a renegotiation here since renegotiations are suppressed at TPC.replaceTrack for screenshare\n                // tracks. This is done here so that presence for screenshare tracks is sent before signaling.\n                .then(() => this._renegotiate())\n                .then(() => {\n                    const newLocalSDP = new SDP(this.peerconnection.localDescription.sdp);\n\n                    // Signal the new sources to the peer.\n                    this.notifyMySSRCUpdate(oldLocalSDP, newLocalSDP);\n                    finishedCallback();\n                })\n                .catch(error => finishedCallback(error));\n        };\n\n        return new Promise((resolve, reject) => {\n            logger.debug(`${this} Queued renegotiation after addTrack`);\n\n            this.modificationQueue.push(\n                workFunction,\n                error => {\n                    if (error) {\n                        logger.error(`${this} renegotiation after addTrack error`, error);\n                        reject(error);\n                    } else {\n                        logger.debug(`${this} renegotiation after addTrack executed - OK`);\n                        resolve();\n                    }\n                });\n        });\n    }\n\n    /**\n     * Resumes or suspends media transfer over the underlying peer connection.\n     *\n     * @param {boolean} active - <tt>true</tt> to enable media transfer or <tt>false</tt> to suspend media transmission\n     * @returns {Promise}\n     */\n    setMediaTransferActive(active) {\n        return this.peerconnection.tpcUtils.setMediaTransferActive(active)\n            .then(() => {\n                this.peerconnection.audioTransferActive = active;\n                this.peerconnection.videoTransferActive = active;\n            });\n    }\n\n    /**\n     * Replaces <tt>oldTrack</tt> with <tt>newTrack</tt> and performs a single\n     * offer/answer cycle after both operations are done. Either\n     * <tt>oldTrack</tt> or <tt>newTrack</tt> can be null; replacing a valid\n     * <tt>oldTrack</tt> with a null <tt>newTrack</tt> effectively just removes\n     * <tt>oldTrack</tt>\n     * @param {JitsiLocalTrack|null} oldTrack the current track in use to be\n     * replaced\n     * @param {JitsiLocalTrack|null} newTrack the new track to use\n     * @returns {Promise} which resolves once the replacement is complete\n     *  with no arguments or rejects with an error {string}\n     */\n    replaceTrack(oldTrack, newTrack) {\n        const workFunction = finishedCallback => {\n            logger.debug(`${this} replaceTrack worker started. oldTrack = ${oldTrack}, newTrack = ${newTrack}`);\n\n            const oldLocalSdp = this.peerconnection.localDescription.sdp;\n\n            if (!this.usesUnifiedPlan) {\n                // NOTE the code below assumes that no more than 1 video track\n                // can be added to the peer connection.\n                // Transition from camera to desktop share\n                // or transition from one camera source to another.\n                if (this.peerconnection.options.capScreenshareBitrate\n                    && oldTrack && newTrack && newTrack.isVideoTrack()) {\n                    // Clearing current primary SSRC will make\n                    // the SdpConsistency generate a new one which will result\n                    // with:\n                    // 1. source-remove for the old video stream.\n                    // 2. source-add for the new video stream.\n                    this.peerconnection.clearRecvonlySsrc();\n                }\n\n                // Transition from no video to video (unmute).\n                if (!oldTrack && newTrack && newTrack.isVideoTrack()) {\n                    // Clearing current primary SSRC will make\n                    // the SdpConsistency generate a new one which will result\n                    // with:\n                    // 1. source-remove for the recvonly\n                    // 2. source-add for the new video stream\n                    this.peerconnection.clearRecvonlySsrc();\n\n                // Transition from video to no video\n                } else if (oldTrack && oldTrack.isVideoTrack() && !newTrack) {\n                    // Clearing current primary SSRC and generating the recvonly\n                    // will result in:\n                    // 1. source-remove for the old video stream\n                    // 2. source-add for the recvonly stream\n                    this.peerconnection.clearRecvonlySsrc();\n                    this.peerconnection.generateRecvonlySsrc();\n                }\n            }\n\n            this.peerconnection.replaceTrack(oldTrack, newTrack)\n                .then(shouldRenegotiate => {\n                    let promise = Promise.resolve();\n\n                    logger.debug(`${this} TPC.replaceTrack finished. shouldRenegotiate = ${\n                        shouldRenegotiate}, JingleSessionState = ${this.state}`);\n\n                    if (shouldRenegotiate\n                        && (oldTrack || newTrack)\n                        && this.state === JingleSessionState.ACTIVE) {\n                        const remoteSdp = this.peerconnection.remoteDescription.sdp;\n                        const remoteDescription = new RTCSessionDescription({\n                            type: 'offer',\n                            sdp: remoteSdp\n                        });\n\n                        // Always initiate a sRD->cA->sLD cycle since renegotiation fails in the following scenario.\n                        // In a p2p call when channelLastN=0, the direction on the video tranceiver is set to\n                        // 'inactive'. At this point, if the user unmutes, the track is replaced on the video sender.\n                        // If a cO->sLD->sRD is triggered, the browser adds a third m-line which isn't expected and\n                        // possibly is a bug. All renegotiations fail as a result. However, the browser does not add a\n                        // third m-line in the answer it generates and renegotiation succeeds.\n                        promise = this._responderRenegotiate(remoteDescription).then(() => {\n                            const newLocalSDP = new SDP(this.peerconnection.localDescription.sdp);\n\n                            this.notifyMySSRCUpdate(new SDP(oldLocalSdp), newLocalSDP);\n                        });\n                    }\n\n                    return promise.then(() => {\n                        // Set the source name of the new track.\n                        if (oldTrack\n                            && newTrack\n                            && oldTrack.isVideoTrack()) {\n                            newTrack.setSourceName(oldTrack.getSourceName());\n                        }\n                    });\n                })\n                .then(() => finishedCallback(), error => finishedCallback(error));\n        };\n\n        return new Promise((resolve, reject) => {\n            logger.debug(`${this} Queued replaceTrack task. Old track = ${oldTrack}, new track = ${newTrack}`);\n\n            this.modificationQueue.push(\n                workFunction,\n                error => {\n                    if (error) {\n                        logger.error(`${this} Replace track error:`, error);\n                        reject(error);\n                    } else {\n                        logger.info(`${this}  Replace track done!`);\n                        resolve();\n                    }\n                });\n        });\n    }\n\n    /**\n     * Parse the information from the xml sourceRemoveElem and translate it\n     *  into sdp lines\n     * @param {jquery xml element} sourceRemoveElem the source-remove\n     *  element from jingle\n     * @param {SDP object} currentRemoteSdp the current remote\n     *  sdp (as of this new source-remove)\n     * @returns {list} a list of SDP line strings that should\n     *  be removed from the remote SDP\n     */\n    _parseSsrcInfoFromSourceRemove(sourceRemoveElem, currentRemoteSdp) {\n        const removeSsrcInfo = [];\n\n        $(sourceRemoveElem).each((i1, content) => {\n            const name = $(content).attr('name');\n            let lines = '';\n\n            $(content)\n                .find('ssrc-group[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\n                .each(function() {\n                    /* eslint-disable no-invalid-this */\n                    const semantics = this.getAttribute('semantics');\n                    const ssrcs\n                        = $(this)\n                            .find('>source')\n                            .map(function() {\n                                return this.getAttribute('ssrc');\n                            })\n                            .get();\n\n                    if (ssrcs.length) {\n                        lines\n                            += `a=ssrc-group:${semantics} ${\n                                ssrcs.join(' ')}\\r\\n`;\n                    }\n\n                    /* eslint-enable no-invalid-this */\n                });\n            const ssrcs = [];\n\n            // handles both >source and >description>source versions\n            const tmp\n                = $(content).find(\n                    'source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]');\n\n            tmp.each(function() {\n                // eslint-disable-next-line no-invalid-this\n                const ssrc = $(this).attr('ssrc');\n\n                ssrcs.push(ssrc);\n            });\n            currentRemoteSdp.media.forEach((media, i2) => {\n                if (!SDPUtil.findLine(media, `a=mid:${name}`)) {\n                    return;\n                }\n                if (!removeSsrcInfo[i2]) {\n                    removeSsrcInfo[i2] = '';\n                }\n                ssrcs.forEach(ssrc => {\n                    const ssrcLines\n                        = SDPUtil.findLines(media, `a=ssrc:${ssrc}`);\n\n                    if (ssrcLines.length) {\n                        removeSsrcInfo[i2] += `${ssrcLines.join('\\r\\n')}\\r\\n`;\n                    }\n                });\n                removeSsrcInfo[i2] += lines;\n            });\n        });\n\n        return removeSsrcInfo;\n    }\n\n    /**\n     * Will print an error if there is any difference, between the SSRCs given\n     * in the <tt>oldSDP</tt> and the ones currently described in\n     * the peerconnection's local description.\n     * @param {string} operationName the operation's name which will be printed\n     * in the error message.\n     * @param {SDP} oldSDP the old local SDP which will be compared with\n     * the current one.\n     * @return {boolean} <tt>true</tt> if there was any change or <tt>false</tt>\n     * otherwise.\n     * @private\n     */\n    _verifyNoSSRCChanged(operationName, oldSDP) {\n        const currentLocalSDP\n            = new SDP(this.peerconnection.localDescription.sdp);\n        let sdpDiff = new SDPDiffer(oldSDP, currentLocalSDP);\n        const addedMedia = sdpDiff.getNewMedia();\n\n        if (Object.keys(addedMedia).length) {\n            logger.error(`${this} - some SSRC were added on ${operationName}`, addedMedia);\n\n            return false;\n        }\n\n        sdpDiff = new SDPDiffer(currentLocalSDP, oldSDP);\n        const removedMedia = sdpDiff.getNewMedia();\n\n        if (Object.keys(removedMedia).length) {\n            logger.error(`${this} - some SSRCs were removed on ${operationName}`, removedMedia);\n\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Adds local track back to the peerconnection associated with this session.\n     * @param {JitsiLocalTrack} track\n     * @return {Promise} a promise that will resolve once the local track is added back to this session and\n     * renegotiation succeeds (if its warranted). Will be rejected with a <tt>string</tt> that provides some error\n     * details in case something goes wrong.\n     */\n    addTrackToPc(track) {\n        return this._addRemoveTrack(false /* add */, track)\n            .then(() => {\n                // Configure the video encodings after the track is unmuted. If the user joins the call muted and\n                // unmutes it the first time, all the parameters need to be configured.\n                if (track.isVideoTrack()) {\n                    return this.peerconnection.configureSenderVideoEncodings(track);\n                }\n            });\n    }\n\n    /**\n     * Remove local track as part of the mute operation.\n     * @param {JitsiLocalTrack} track the local track to be removed\n     * @return {Promise} a promise which will be resolved once the local track\n     * is removed from this session and the renegotiation is performed.\n     * The promise will be rejected with a <tt>string</tt> that the describes\n     * the error if anything goes wrong.\n     */\n    removeTrackFromPc(track) {\n        return this._addRemoveTrack(true /* remove */, track);\n    }\n\n    /**\n     * See {@link addTrackToPc} and {@link removeTrackFromPc}.\n     * @param {boolean} isRemove <tt>true</tt> for \"remove\" operation or <tt>false</tt> for \"add\" operation.\n     * @param {JitsiLocalTrack} track the track that will be added/removed\n     * @private\n     */\n    _addRemoveTrack(isRemove, track) {\n        if (!track) {\n            return Promise.reject('invalid \"track\" argument value');\n        }\n        const operationName = isRemove ? 'removeTrack' : 'addTrack';\n        const workFunction = finishedCallback => {\n            const tpc = this.peerconnection;\n\n            if (!tpc) {\n                finishedCallback(`Error:  tried ${operationName} track with no active peer connection`);\n\n                return;\n            }\n            const oldLocalSDP = tpc.localDescription.sdp;\n            const operationPromise\n                = isRemove\n                    ? tpc.removeTrackFromPc(track)\n                    : tpc.addTrackToPc(track);\n\n            operationPromise\n                .then(shouldRenegotiate => {\n                    if (shouldRenegotiate && oldLocalSDP && tpc.remoteDescription.sdp) {\n                        this._renegotiate()\n                            .then(() => {\n                                // The results are ignored, as this check failure is not enough to fail the whole\n                                // operation. It will log an error inside for plan-b.\n                                !this.usesUnifiedPlan && this._verifyNoSSRCChanged(operationName, new SDP(oldLocalSDP));\n                                const newLocalSdp = tpc.localDescription.sdp;\n\n                                // Signal the ssrc if an unmute operation results in a new ssrc being generated.\n                                this.notifyMySSRCUpdate(new SDP(oldLocalSDP), new SDP(newLocalSdp));\n                                finishedCallback();\n                            });\n                    } else {\n                        finishedCallback();\n                    }\n                },\n                finishedCallback /* will be called with an error */);\n        };\n\n        logger.debug(`${this} Queued ${operationName} task`);\n\n        return new Promise((resolve, reject) => {\n            this.modificationQueue.push(\n                workFunction,\n                error => {\n                    if (error) {\n                        logger.error(`${this} ${operationName} failed`);\n                        reject(error);\n                    } else {\n                        logger.debug(`${this} ${operationName} done`);\n                        resolve();\n                    }\n                });\n        });\n    }\n\n    /**\n     * Resumes or suspends video media transfer over the p2p peer connection.\n     *\n     * @param {boolean} videoActive <tt>true</tt> to enable video media transfer or <tt>false</tt> to suspend video\n     * media transmission.\n     * @return {Promise} a <tt>Promise</tt> which will resolve once the operation is done. It will be rejected with\n     * an error description as a string in case anything goes wrong.\n     */\n    setP2pVideoTransferActive(videoActive) {\n        if (!this.peerconnection) {\n            return Promise.reject('Can not modify video transfer active state,'\n                    + ' before \"initialize\" is called');\n        }\n\n        const logVideoStr = videoActive ? 'video active' : 'video inactive';\n\n        logger.info(`${this} Queued make ${logVideoStr} task`);\n\n        const workFunction = finishedCallback => {\n            const isSessionActive = this.state === JingleSessionState.ACTIVE;\n\n            if (this._localVideoActive !== videoActive) {\n                this._localVideoActive = videoActive;\n                if (this.isP2P && isSessionActive) {\n                    this.sendContentModify();\n                }\n            }\n\n            this.peerconnection.setVideoTransferActive(this._localVideoActive && this._remoteVideoActive);\n\n            // Always initiate a renegotiation cycle for p2p connection when the media direction is changed.\n            this._renegotiate()\n                .then(() => finishedCallback())\n                .catch(error => finishedCallback(error));\n        };\n\n        return new Promise((resolve, reject) => {\n            this.modificationQueue.push(\n                workFunction,\n                error => {\n                    if (error) {\n                        logger.error(`${this} Make ${logVideoStr} task failed!`);\n                        reject(error);\n                    } else {\n                        logger.debug(`${this} Make ${logVideoStr} task done!`);\n                        resolve();\n                    }\n                });\n        });\n    }\n\n    /**\n     * Will put and execute on the queue a session modify task. It checks if the sourceMaxFrameHeight (as requested by\n     * the p2p peer) or the senders attribute of the video content has changed and modifies the local video sources\n     * accordingly.\n     */\n    modifyContents(jingleContents) {\n        const newVideoSenders = JingleSessionPC.parseVideoSenders(jingleContents);\n        const sourceMaxFrameHeights = JingleSessionPC.parseSourceMaxFrameHeight(jingleContents);\n\n        if (sourceMaxFrameHeights) {\n            this.remoteSourceMaxFrameHeights = sourceMaxFrameHeights;\n            this.eventEmitter.emit(MediaSessionEvents.REMOTE_SOURCE_CONSTRAINTS_CHANGED, this, sourceMaxFrameHeights);\n        }\n\n        if (newVideoSenders === null) {\n            logger.error(`${this} - failed to parse video \"senders\" attribute in \"content-modify\" action`);\n\n            return;\n        }\n\n        const workFunction = finishedCallback => {\n            if (this._assertNotEnded() && this._modifyRemoteVideoActive(newVideoSenders)) {\n                // Will do the sRD/sLD cycle to update SDPs and adjust the media direction.\n                this._renegotiate()\n                    .then(finishedCallback, finishedCallback /* (error) */);\n            } else {\n                finishedCallback();\n            }\n        };\n\n        logger.debug(`${this} queued \"content-modify\" task(video senders=\"${newVideoSenders}\")`);\n\n        this.modificationQueue.push(\n            workFunction,\n            error => {\n                if (error) {\n                    logger.error(`${this} \"content-modify\" failed`, error);\n                } else {\n                    logger.debug(`${this} \"content-modify\" task(video senders=\"${newVideoSenders}\") done`);\n                }\n            });\n    }\n\n    /**\n     * Processes new value of remote video \"senders\" Jingle attribute and tries to apply it for\n     * {@link _remoteVideoActive}.\n     * @param {string} remoteVideoSenders the value of \"senders\" attribute of Jingle video content element advertised\n     * by remote peer.\n     * @return {boolean} <tt>true</tt> if the change affected state of the underlying peerconnection and renegotiation\n     * is required for the changes to take effect.\n     * @private\n     */\n    _modifyRemoteVideoActive(remoteVideoSenders) {\n        const isRemoteVideoActive\n            = remoteVideoSenders === 'both'\n                || (remoteVideoSenders === 'initiator' && this.isInitiator)\n                || (remoteVideoSenders === 'responder' && !this.isInitiator);\n\n        if (isRemoteVideoActive !== this._remoteVideoActive) {\n            logger.debug(`${this} new remote video active: ${isRemoteVideoActive}`);\n            this._remoteVideoActive = isRemoteVideoActive;\n\n            return this.peerconnection.setVideoTransferActive(this._localVideoActive && this._remoteVideoActive);\n        }\n\n        return false;\n    }\n\n    /**\n     * Figures out added/removed ssrcs and send update IQs.\n     * @param oldSDP SDP object for old description.\n     * @param newSDP SDP object for new description.\n     */\n    notifyMySSRCUpdate(oldSDP, newSDP) {\n        if (this.state !== JingleSessionState.ACTIVE) {\n            logger.warn(`${this} Skipping SSRC update in '${this.state} ' state.`);\n\n            return;\n        }\n\n        if (!this.connection.connected) {\n            // The goal is to compare the oldest SDP with the latest one upon reconnect\n            if (!this._cachedOldLocalSdp) {\n                this._cachedOldLocalSdp = oldSDP;\n            }\n            this._cachedNewLocalSdp = newSDP;\n            logger.warn(`${this} Not sending SSRC update while the signaling is disconnected`);\n\n            return;\n        }\n\n        this._cachedOldLocalSdp = undefined;\n        this._cachedNewLocalSdp = undefined;\n\n        const getSignaledSourceInfo = sdpDiffer => {\n            const newMedia = sdpDiffer.getNewMedia();\n            let ssrcs = [];\n            let mediaType = null;\n\n            // It is assumed that sources are signaled one at a time.\n            Object.keys(newMedia).forEach(mediaIndex => {\n                const signaledSsrcs = Object.keys(newMedia[mediaIndex].ssrcs);\n\n                mediaType = newMedia[mediaIndex].mid;\n                if (signaledSsrcs?.length) {\n                    ssrcs = ssrcs.concat(signaledSsrcs);\n                }\n            });\n\n            return {\n                mediaType,\n                ssrcs\n            };\n        };\n\n        // send source-remove IQ.\n        let sdpDiffer = new SDPDiffer(newSDP, oldSDP);\n        const remove = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', {\n                xmlns: 'urn:xmpp:jingle:1',\n                action: 'source-remove',\n                initiator: this.initiatorJid,\n                sid: this.sid\n            }\n            );\n\n        sdpDiffer.toJingle(remove);\n\n        // context a common object for one run of ssrc update (source-add and source-remove) so we can match them if we\n        // need to\n        const ctx = {};\n        const removedSsrcInfo = getSignaledSourceInfo(sdpDiffer);\n\n        if (removedSsrcInfo.ssrcs.length) {\n            // Log only the SSRCs instead of the full IQ.\n            logger.info(`${this} Sending source-remove for ${removedSsrcInfo.mediaType}`\n                + ` ssrcs=${removedSsrcInfo.ssrcs}`);\n            this.connection.sendIQ(\n                remove,\n                () => {\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_REMOVE, this, ctx);\n                },\n                this.newJingleErrorHandler(remove, error => {\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_REMOVE_ERROR, this, error, ctx);\n                }),\n                IQ_TIMEOUT);\n        }\n\n        // send source-add IQ.\n        sdpDiffer = new SDPDiffer(oldSDP, newSDP);\n        const add = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', {\n                xmlns: 'urn:xmpp:jingle:1',\n                action: 'source-add',\n                initiator: this.initiatorJid,\n                sid: this.sid\n            }\n            );\n\n        sdpDiffer.toJingle(add);\n        const addedSsrcInfo = getSignaledSourceInfo(sdpDiffer);\n\n        if (addedSsrcInfo.ssrcs.length) {\n            // Log only the SSRCs instead of the full IQ.\n            logger.info(`${this} Sending source-add for ${addedSsrcInfo.mediaType} ssrcs=${addedSsrcInfo.ssrcs}`);\n            this.connection.sendIQ(\n                add,\n                () => {\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_ADD, this, ctx);\n                },\n                this.newJingleErrorHandler(add, error => {\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_ADD_ERROR, this, error, addedSsrcInfo.mediaType, ctx);\n                }),\n                IQ_TIMEOUT);\n        }\n    }\n\n    /**\n     * Method returns function(errorResponse) which is a callback to be passed\n     * to Strophe connection.sendIQ method. An 'error' structure is created that\n     * is passed as 1st argument to given <tt>failureCb</tt>. The format of this\n     * structure is as follows:\n     * {\n     *  code: {XMPP error response code}\n     *  reason: {the name of XMPP error reason element or 'timeout' if the\n      *          request has timed out within <tt>IQ_TIMEOUT</tt> milliseconds}\n     *  source: {request.tree() that provides original request}\n     *  session: {this JingleSessionPC.toString()}\n     * }\n     * @param request Strophe IQ instance which is the request to be dumped into\n     *        the error structure\n     * @param failureCb function(error) called when error response was returned\n     *        or when a timeout has occurred.\n     * @returns {function(this:JingleSessionPC)}\n     */\n    newJingleErrorHandler(request, failureCb) {\n        return errResponse => {\n\n            const error = {};\n\n            // Get XMPP error code and condition(reason)\n            const errorElSel = $(errResponse).find('error');\n\n            if (errorElSel.length) {\n                error.code = errorElSel.attr('code');\n                const errorReasonSel = $(errResponse).find('error :first');\n\n                if (errorReasonSel.length) {\n                    error.reason = errorReasonSel[0].tagName;\n                }\n\n                const errorMsgSel = errorElSel.find('>text');\n\n                if (errorMsgSel.length) {\n                    error.msg = errorMsgSel.text();\n                }\n            }\n\n            if (!errResponse) {\n                error.reason = 'timeout';\n            }\n\n            error.session = this.toString();\n\n            if (failureCb) {\n                failureCb(error);\n            } else if (this.state === JingleSessionState.ENDED\n                        && error.reason === 'item-not-found') {\n                // When remote peer decides to terminate the session, but it\n                // still have few messages on the queue for processing,\n                // it will first send us 'session-terminate' (we enter ENDED)\n                // and then follow with 'item-not-found' for the queued requests\n                // We don't want to have that logged on error level.\n                logger.debug(`${this} Jingle error: ${JSON.stringify(error)}`);\n            } else {\n                GlobalOnErrorHandler.callErrorHandler(\n                    new Error(\n                        `Jingle error: ${JSON.stringify(error)}`));\n            }\n        };\n    }\n\n    /**\n     * Returns the ice connection state for the peer connection.\n     * @returns the ice connection state for the peer connection.\n     */\n    getIceConnectionState() {\n        return this.peerconnection.getConnectionState();\n    }\n\n    /**\n     * Closes the peerconnection.\n     */\n    close() {\n        this.state = JingleSessionState.ENDED;\n        this.establishmentDuration = undefined;\n\n        if (this.peerconnection) {\n            this.peerconnection.onicecandidate = null;\n            this.peerconnection.oniceconnectionstatechange = null;\n            this.peerconnection.onnegotiationneeded = null;\n            this.peerconnection.onsignalingstatechange = null;\n        }\n\n        logger.debug(`${this} Clearing modificationQueue`);\n\n        // Remove any pending tasks from the queue\n        this.modificationQueue.clear();\n\n        logger.debug(`${this} Queued PC close task`);\n        this.modificationQueue.push(finishCallback => {\n            // do not try to close if already closed.\n            this.peerconnection && this.peerconnection.close();\n            finishCallback();\n            logger.debug(`${this} PC close task done!`);\n        });\n\n        logger.debug(`${this} Shutdown modificationQueue!`);\n\n        // No more tasks can go in after the close task\n        this.modificationQueue.shutdown();\n    }\n\n    /**\n     * Converts to string with minor summary.\n     * @return {string}\n     */\n    toString() {\n        return `JingleSessionPC[session=${this.isP2P ? 'P2P' : 'JVB'},initiator=${this.isInitiator},sid=${this.sid}]`;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $iq, Strophe } from 'strophe.js';\n\nimport { MediaType } from '../../service/RTC/MediaType';\nimport {\n    ACTION_JINGLE_TR_RECEIVED,\n    ACTION_JINGLE_TR_SUCCESS,\n    createJingleEvent\n} from '../../service/statistics/AnalyticsEvents';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport Statistics from '../statistics/statistics';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\nimport RandomUtil from '../util/RandomUtil';\n\nimport ConnectionPlugin from './ConnectionPlugin';\nimport { expandSourcesFromJson } from './JingleHelperFunctions';\nimport JingleSessionPC from './JingleSessionPC';\n\nconst logger = getLogger(__filename);\n\n// XXX Strophe is build around the idea of chaining function calls so allow long\n// function call chains.\n/* eslint-disable newline-per-chained-call */\n\n/**\n * Parses the transport XML element and returns the list of ICE candidates formatted as text.\n *\n * @param {*} transport Transport XML element extracted from the IQ.\n * @returns {Array<string>}\n */\nfunction _parseIceCandidates(transport) {\n    const candidates = $(transport).find('>candidate');\n    const parseCandidates = [];\n\n    // Extract the candidate information from the IQ.\n    candidates.each((_, candidate) => {\n        const attributes = candidate.attributes;\n        const candidateAttrs = [];\n\n        for (let i = 0; i < attributes.length; i++) {\n            const attr = attributes[i];\n\n            candidateAttrs.push(`${attr.name}: ${attr.value}`);\n        }\n        parseCandidates.push(candidateAttrs.join(' '));\n    });\n\n    return parseCandidates;\n}\n\n/**\n *\n */\nexport default class JingleConnectionPlugin extends ConnectionPlugin {\n    /**\n     * Creates new <tt>JingleConnectionPlugin</tt>\n     * @param {XMPP} xmpp\n     * @param {EventEmitter} eventEmitter\n     * @param {Object} iceConfig an object that holds the iceConfig to be passed\n     * to the p2p and the jvb <tt>PeerConnection</tt>.\n     */\n    constructor(xmpp, eventEmitter, iceConfig) {\n        super();\n        this.xmpp = xmpp;\n        this.eventEmitter = eventEmitter;\n        this.sessions = {};\n        this.jvbIceConfig = iceConfig.jvb;\n        this.p2pIceConfig = iceConfig.p2p;\n        this.mediaConstraints = {\n            offerToReceiveAudio: true,\n            offerToReceiveVideo: true\n        };\n    }\n\n    /**\n     *\n     * @param connection\n     */\n    init(connection) {\n        super.init(connection);\n        this.connection.addHandler(this.onJingle.bind(this),\n            'urn:xmpp:jingle:1', 'iq', 'set', null, null);\n    }\n\n    /**\n     *\n     * @param iq\n     */\n    onJingle(iq) {\n        const sid = $(iq).find('jingle').attr('sid');\n        const action = $(iq).find('jingle').attr('action');\n        const fromJid = iq.getAttribute('from');\n\n        // send ack first\n        const ack = $iq({ type: 'result',\n            to: fromJid,\n            id: iq.getAttribute('id')\n        });\n\n        let sess = this.sessions[sid];\n\n        if (action !== 'session-initiate') {\n            if (!sess) {\n                ack.attrs({ type: 'error' });\n                ack.c('error', { type: 'cancel' })\n                    .c('item-not-found', {\n                        xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'\n                    })\n                    .up()\n                    .c('unknown-session', {\n                        xmlns: 'urn:xmpp:jingle:errors:1'\n                    });\n                logger.warn(`invalid session id: ${sid}`);\n                logger.debug(iq);\n                this.connection.send(ack);\n\n                return true;\n            }\n\n            // local jid is not checked\n            if (fromJid !== sess.remoteJid) {\n                logger.warn(\n                    'jid mismatch for session id', sid, sess.remoteJid, iq);\n                ack.attrs({ type: 'error' });\n                ack.c('error', { type: 'cancel' })\n                    .c('item-not-found', {\n                        xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'\n                    })\n                    .up()\n                    .c('unknown-session', {\n                        xmlns: 'urn:xmpp:jingle:errors:1'\n                    });\n                this.connection.send(ack);\n\n                return true;\n            }\n        } else if (sess !== undefined) {\n            // Existing session with same session id. This might be out-of-order\n            // if the sess.remoteJid is the same as from.\n            ack.attrs({ type: 'error' });\n            ack.c('error', { type: 'cancel' })\n                .c('service-unavailable', {\n                    xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'\n                })\n                .up();\n            logger.warn('duplicate session id', sid, iq);\n            this.connection.send(ack);\n\n            return true;\n        }\n        const now = window.performance.now();\n\n        // FIXME that should work most of the time, but we'd have to\n        // think how secure it is to assume that user with \"focus\"\n        // nickname is Jicofo.\n        const isP2P = Strophe.getResourceFromJid(fromJid) !== 'focus';\n\n        // see http://xmpp.org/extensions/xep-0166.html#concepts-session\n\n        const jsonMessages = $(iq).find('jingle>json-message');\n\n        if (jsonMessages?.length) {\n            let audioVideoSsrcs;\n\n            logger.info(`Found a JSON-encoded element in ${action}, translating to standard Jingle.`);\n            for (let i = 0; i < jsonMessages.length; i++) {\n                // Currently there is always a single json-message in the IQ with the source information.\n                audioVideoSsrcs = expandSourcesFromJson(iq, jsonMessages[i]);\n            }\n\n            if (audioVideoSsrcs?.size) {\n                const logMessage = [];\n\n                for (const endpoint of audioVideoSsrcs.keys()) {\n                    logMessage.push(`${endpoint}:[${audioVideoSsrcs.get(endpoint)}]`);\n                }\n                logger.debug(`Received ${action} from ${fromJid} with sources=${logMessage.join(', ')}`);\n            }\n\n            // TODO: is there a way to remove the json-message elements once we've extracted the information?\n            // removeChild doesn't seem to work.\n        }\n\n        switch (action) {\n        case 'session-initiate': {\n            logger.log('(TIME) received session-initiate:\\t', now);\n            const startMuted = $(iq).find('jingle>startmuted');\n\n            isP2P && logger.debug(`Received ${action} from ${fromJid}`);\n            if (startMuted?.length) {\n                const audioMuted = startMuted.attr(MediaType.AUDIO);\n                const videoMuted = startMuted.attr(MediaType.VIDEO);\n\n                this.eventEmitter.emit(\n                    XMPPEvents.START_MUTED_FROM_FOCUS,\n                    audioMuted === 'true',\n                    videoMuted === 'true');\n            }\n            const pcConfig = isP2P ? this.p2pIceConfig : this.jvbIceConfig;\n\n            sess\n                = new JingleSessionPC(\n                    $(iq).find('jingle').attr('sid'),\n                    $(iq).attr('to'),\n                    fromJid,\n                    this.connection,\n                    this.mediaConstraints,\n\n                    // Makes a copy in order to prevent exception thrown on RN when either this.p2pIceConfig or\n                    // this.jvbIceConfig is modified and there's a PeerConnection instance holding a reference\n                    JSON.parse(JSON.stringify(pcConfig)),\n                    isP2P,\n                    /* initiator */ false);\n\n            this.sessions[sess.sid] = sess;\n            this.eventEmitter.emit(XMPPEvents.CALL_INCOMING, sess, $(iq).find('>jingle'), now);\n            break;\n        }\n        case 'session-accept': {\n            const ssrcs = [];\n            const contents = $(iq).find('jingle>content');\n\n            // Extract the SSRCs from the session-accept received from a p2p peer.\n            for (const content of contents) {\n                const ssrc = $(content).find('description').attr('ssrc');\n\n                ssrc && ssrcs.push(ssrc);\n            }\n            logger.debug(`Received ${action} from ${fromJid} with ssrcs=${ssrcs}`);\n            this.eventEmitter.emit(XMPPEvents.CALL_ACCEPTED, sess, $(iq).find('>jingle'));\n            break;\n        }\n        case 'content-modify': {\n            logger.debug(`Received ${action} from ${fromJid}`);\n            sess.modifyContents($(iq).find('>jingle'));\n            break;\n        }\n        case 'transport-info': {\n            const candidates = _parseIceCandidates($(iq).find('jingle>content>transport'));\n\n            logger.debug(`Received ${action} from ${fromJid} for candidates=${candidates.join(', ')}`);\n            this.eventEmitter.emit(XMPPEvents.TRANSPORT_INFO, sess, $(iq).find('>jingle'));\n            break;\n        }\n        case 'session-terminate': {\n            logger.log('terminating...', sess.sid);\n            let reasonCondition = null;\n            let reasonText = null;\n\n            if ($(iq).find('>jingle>reason').length) {\n                reasonCondition\n                    = $(iq).find('>jingle>reason>:first')[0].tagName;\n                reasonText = $(iq).find('>jingle>reason>text').text();\n            }\n            logger.debug(`Received ${action} from ${fromJid} disconnect reason=${reasonText}`);\n            this.terminate(sess.sid, reasonCondition, reasonText);\n            this.eventEmitter.emit(XMPPEvents.CALL_ENDED, sess, reasonCondition, reasonText);\n            break;\n        }\n        case 'transport-replace': {\n            logger.info('(TIME) Start transport replace:\\t', now);\n            const transport = $(iq).find('jingle>content>transport');\n            const candidates = _parseIceCandidates(transport);\n            const iceUfrag = $(transport).attr('ufrag');\n            const icePwd = $(transport).attr('pwd');\n            const dtlsFingerprint = $(transport).find('>fingerprint')?.text();\n\n            logger.debug(`Received ${action} from ${fromJid} with iceUfrag=${iceUfrag},`\n            + ` icePwd=${icePwd}, DTLS fingerprint=${dtlsFingerprint}, candidates=${candidates.join(', ')}`);\n\n            Statistics.sendAnalytics(createJingleEvent(\n                ACTION_JINGLE_TR_RECEIVED,\n                {\n                    p2p: isP2P,\n                    value: now\n                }));\n\n            sess.replaceTransport($(iq).find('>jingle'), () => {\n                const successTime = window.performance.now();\n\n                logger.info('(TIME) Transport replace success:\\t', successTime);\n                Statistics.sendAnalytics(createJingleEvent(\n                    ACTION_JINGLE_TR_SUCCESS,\n                    {\n                        p2p: isP2P,\n                        value: successTime\n                    }));\n            }, error => {\n                GlobalOnErrorHandler.callErrorHandler(error);\n                logger.error('Transport replace failed', error);\n                sess.sendTransportReject();\n            });\n            break;\n        }\n        case 'source-add':\n            sess.addRemoteStream($(iq).find('>jingle>content'));\n            break;\n        case 'source-remove':\n            sess.removeRemoteStream($(iq).find('>jingle>content'));\n            break;\n        default:\n            logger.warn('jingle action not implemented', action);\n            ack.attrs({ type: 'error' });\n            ack.c('error', { type: 'cancel' })\n                .c('bad-request',\n                    { xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas' })\n                .up();\n            break;\n        }\n        this.connection.send(ack);\n\n        return true;\n    }\n\n    /**\n     * Creates new <tt>JingleSessionPC</tt> meant to be used in a direct P2P\n     * connection, configured as 'initiator'.\n     * @param {string} me our JID\n     * @param {string} peer remote participant's JID\n     * @return {JingleSessionPC}\n     */\n    newP2PJingleSession(me, peer) {\n        const sess\n            = new JingleSessionPC(\n                RandomUtil.randomHexString(12),\n                me,\n                peer,\n                this.connection,\n                this.mediaConstraints,\n                this.p2pIceConfig,\n                /* P2P */ true,\n                /* initiator */ true);\n\n        this.sessions[sess.sid] = sess;\n\n        return sess;\n    }\n\n    /**\n     *\n     * @param sid\n     * @param reasonCondition\n     * @param reasonText\n     */\n    terminate(sid, reasonCondition, reasonText) {\n        if (this.sessions.hasOwnProperty(sid)) {\n            if (this.sessions[sid].state !== 'ended') {\n                this.sessions[sid].onTerminated(reasonCondition, reasonText);\n            }\n            delete this.sessions[sid];\n        }\n    }\n\n    /**\n     *\n     */\n    getStunAndTurnCredentials() {\n        // get stun and turn configuration from server via xep-0215\n        // uses time-limited credentials as described in\n        // http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00\n        //\n        // See https://modules.prosody.im/mod_turncredentials.html\n        // for a prosody module which implements this.\n        // Or the new implementation https://modules.prosody.im/mod_external_services which will be in prosody 0.12\n        //\n        // Currently, this doesn't work with updateIce and therefore credentials\n        // with a long validity have to be fetched before creating the\n        // peerconnection.\n        // TODO: implement refresh via updateIce as described in\n        //      https://code.google.com/p/webrtc/issues/detail?id=1650\n        this.connection.sendIQ(\n            $iq({ type: 'get',\n                to: this.xmpp.options.hosts.domain })\n                .c('services', { xmlns: 'urn:xmpp:extdisco:2' }),\n            v2Res => this.onReceiveStunAndTurnCredentials(v2Res),\n            () => {\n                logger.warn('getting turn credentials with extdisco:2 failed, trying extdisco:1');\n                this.connection.sendIQ(\n                    $iq({ type: 'get',\n                        to: this.xmpp.options.hosts.domain })\n                        .c('services', { xmlns: 'urn:xmpp:extdisco:1' }),\n                    v1Res => this.onReceiveStunAndTurnCredentials(v1Res),\n                    () => {\n                        logger.warn('getting turn credentials failed');\n                        logger.warn('is mod_turncredentials or similar installed and configured?');\n                    }\n                );\n            });\n    }\n\n    /**\n     * Parses response when querying for services using urn:xmpp:extdisco:1 or urn:xmpp:extdisco:2.\n     * Stores results in jvbIceConfig and p2pIceConfig.\n     * @param res The response iq.\n     * @return {boolean} Whether something was processed from the supplied message.\n     */\n    onReceiveStunAndTurnCredentials(res) {\n        const iceservers = [];\n\n        $(res).find('>services>service').each((idx, el) => {\n            // eslint-disable-next-line no-param-reassign\n            el = $(el);\n            const dict = {};\n            const type = el.attr('type');\n\n            switch (type) {\n            case 'stun':\n                dict.urls = `stun:${el.attr('host')}`;\n                if (el.attr('port')) {\n                    dict.urls += `:${el.attr('port')}`;\n                }\n                iceservers.push(dict);\n                break;\n            case 'turn':\n            case 'turns': {\n                dict.urls = `${type}:`;\n                dict.username = el.attr('username');\n                dict.urls += el.attr('host');\n                const port = el.attr('port');\n\n                if (port) {\n                    dict.urls += `:${el.attr('port')}`;\n                }\n                const transport = el.attr('transport');\n\n                if (transport && transport !== 'udp') {\n                    dict.urls += `?transport=${transport}`;\n                }\n\n                dict.credential = el.attr('password')\n                        || dict.credential;\n                iceservers.push(dict);\n                break;\n            }\n            }\n        });\n\n        const options = this.xmpp.options;\n\n        // Shuffle ICEServers for loadbalancing\n        for (let i = iceservers.length - 1; i > 0; i--) {\n            const j = Math.floor(Math.random() * (i + 1));\n            const temp = iceservers[i];\n\n            iceservers[i] = iceservers[j];\n            iceservers[j] = temp;\n        }\n\n        let filter;\n\n        if (options.useTurnUdp) {\n            filter = s => s.urls.startsWith('turn');\n        } else {\n            // By default we filter out STUN and TURN/UDP and leave only TURN/TCP.\n            filter = s => s.urls.startsWith('turn') && (s.urls.indexOf('transport=tcp') >= 0);\n        }\n\n        this.jvbIceConfig.iceServers = iceservers.filter(filter);\n        this.p2pIceConfig.iceServers = iceservers;\n\n        return iceservers.length > 0;\n    }\n\n    /**\n     * Returns the data saved in 'updateLog' in a format to be logged.\n     */\n    getLog() {\n        const data = {};\n\n        Object.keys(this.sessions).forEach(sid => {\n            const session = this.sessions[sid];\n            const pc = session.peerconnection;\n\n            if (pc && pc.updateLog) {\n                // FIXME: should probably be a .dump call\n                data[`jingle_${sid}`] = {\n                    updateLog: pc.updateLog,\n                    stats: pc.stats,\n                    url: window.location.href\n                };\n            }\n        });\n\n        return data;\n    }\n}\n\n/* eslint-enable newline-per-chained-call */\n","import { Strophe } from 'strophe.js';\n\nimport ConnectionPlugin from './ConnectionPlugin';\n\n/**\n *  Logs raw stanzas and makes them available for download as JSON\n */\nclass StropheLogger extends ConnectionPlugin {\n    /**\n     *\n     */\n    constructor() {\n        super();\n        this.log = [];\n    }\n\n    /**\n     *\n     * @param connection\n     */\n    init(connection) {\n        super.init(connection);\n        this.connection.rawInput = this.logIncoming.bind(this);\n        this.connection.rawOutput = this.logOutgoing.bind(this);\n    }\n\n    /**\n     *\n     * @param stanza\n     */\n    logIncoming(stanza) {\n        this.log.push([ new Date().getTime(), 'incoming', stanza ]);\n    }\n\n    /**\n     *\n     * @param stanza\n     */\n    logOutgoing(stanza) {\n        this.log.push([ new Date().getTime(), 'outgoing', stanza ]);\n    }\n}\n\n/**\n *\n */\nexport default function() {\n    Strophe.addConnectionPlugin('logger', new StropheLogger());\n}\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $iq } from 'strophe.js';\n\nimport ConnectionPlugin from './ConnectionPlugin';\n\nconst logger = getLogger(__filename);\n\nconst RAYO_XMLNS = 'urn:xmpp:rayo:1';\n\n/**\n *\n */\nexport default class RayoConnectionPlugin extends ConnectionPlugin {\n    /**\n     *\n     * @param connection\n     */\n    init(connection) {\n        super.init(connection);\n\n        this.connection.addHandler(\n            this.onRayo.bind(this), RAYO_XMLNS, 'iq', 'set', null, null);\n    }\n\n    /**\n     *\n     * @param iq\n     */\n    onRayo(iq) {\n        logger.info('Rayo IQ', iq);\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     *\n     * @param to\n     * @param from\n     * @param roomName\n     * @param roomPass\n     * @param focusMucJid\n     */\n    dial(to, from, roomName, roomPass, focusMucJid) {\n        return new Promise((resolve, reject) => {\n            if (!focusMucJid) {\n                reject(new Error('Internal error!'));\n\n                return;\n            }\n            const req = $iq({\n                type: 'set',\n                to: focusMucJid\n            });\n\n            req.c('dial', {\n                xmlns: RAYO_XMLNS,\n                to,\n                from\n            });\n            req.c('header', {\n                name: 'JvbRoomName',\n                value: roomName\n            }).up();\n\n            if (roomPass && roomPass.length) {\n                req.c('header', {\n                    name: 'JvbRoomPassword',\n                    value: roomPass\n                }).up();\n            }\n\n            this.connection.sendIQ(\n                req,\n                result => {\n                    logger.info('Dial result ', result);\n\n                    // eslint-disable-next-line newline-per-chained-call\n                    const resource = $(result).find('ref').attr('uri');\n\n                    this.callResource = resource.substr('xmpp:'.length);\n                    logger.info(`Received call resource: ${this.callResource}`);\n                    resolve();\n                },\n                error => {\n                    logger.info('Dial error ', error);\n                    reject(error);\n                });\n        });\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     *\n     */\n    hangup() {\n        return new Promise((resolve, reject) => {\n            if (!this.callResource) {\n                reject(new Error('No call in progress'));\n                logger.warn('No call in progress');\n\n                return;\n            }\n\n            const req = $iq({\n                type: 'set',\n                to: this.callResource\n            });\n\n            req.c('hangup', {\n                xmlns: RAYO_XMLNS\n            });\n\n            this.connection.sendIQ(req, result => {\n                logger.info('Hangup result ', result);\n                this.callResource = null;\n                resolve();\n            }, error => {\n                logger.info('Hangup error ', error);\n                this.callResource = null;\n                reject(new Error('Hangup error '));\n            });\n        });\n    }\n}\n","/**\n * Strophe logger implementation. Logs from level WARN and above.\n */\nimport { getLogger } from '@jitsi/logger';\nimport { Strophe } from 'strophe.js';\n\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\n\nconst logger = getLogger(__filename);\n\n/**\n * This is the last HTTP error status captured from Strophe debug logs.\n * The purpose of storing it is to distinguish between the network and\n * infrastructure reason for connection being dropped (see connectionHandler in\n * xmpp.js). The value will be cleared (-1) if the subsequent request succeeds\n * which means that the failure could be transient.\n *\n * FIXME in the latest Strophe (not released on npm) there is API to handle\n * particular HTTP errors, but there is no way to learn if the subsequent\n * request succeeded in order to tell if the error was one time incident or if\n * it was the reason for dropping the connection by Strophe (the connection is\n * dropped after 5 subsequent failures). Ideally Strophe should provide more\n * details about the reason on why the connection stopped.\n *\n * @type {number}\n */\nlet lastErrorStatus = -1;\n\n/**\n * A regular expression used to catch Strophe's log message indicating that the\n * last BOSH request was successful. When there is such message seen the\n * {@link lastErrorStatus} will be set back to '-1'.\n * @type {RegExp}\n */\nconst resetLastErrorStatusRegExpr = /request id \\d+.\\d+ got 200/;\n\n/**\n * A regular expression used to capture the current value of the BOSH request\n * error status (HTTP error code or '0' or something else).\n * @type {RegExp}\n */\nconst lastErrorStatusRegExpr\n    = /request errored, status: (\\d+), number of errors: \\d+/;\n\n/**\n *\n */\nexport default function() {\n\n    Strophe.log = function(level, msg) {\n        // Our global handler reports uncaught errors to the stats which may\n        // interpret those as partial call failure.\n        // Strophe log entry about secondary request timeout does not mean that\n        // it's a final failure(the request will be restarted), so we lower it's\n        // level here to a warning.\n        logger.trace('Strophe', level, msg);\n        if (typeof msg === 'string'\n                && msg.indexOf('Request ') !== -1\n                && msg.indexOf('timed out (secondary), restarting') !== -1) {\n            // eslint-disable-next-line no-param-reassign\n            level = Strophe.LogLevel.WARN;\n        }\n\n        /* eslint-disable no-case-declarations */\n        switch (level) {\n        case Strophe.LogLevel.DEBUG:\n            // The log message which reports successful status is logged on\n            // Strophe's DEBUG level.\n            if (lastErrorStatus !== -1\n                    && resetLastErrorStatusRegExpr.test(msg)) {\n                logger.debug('Reset lastErrorStatus');\n                lastErrorStatus = -1;\n            }\n            break;\n        case Strophe.LogLevel.WARN:\n            logger.warn(`Strophe: ${msg}`);\n            const errStatusCapture = lastErrorStatusRegExpr.exec(msg);\n\n            if (errStatusCapture && errStatusCapture.length === 2) {\n                lastErrorStatus = parseInt(errStatusCapture[1], 10);\n                logger.debug(`lastErrorStatus set to: ${lastErrorStatus}`);\n            }\n            break;\n        case Strophe.LogLevel.ERROR:\n        case Strophe.LogLevel.FATAL:\n            // eslint-disable-next-line no-param-reassign\n            msg = `Strophe: ${msg}`;\n            GlobalOnErrorHandler.callErrorHandler(new Error(msg));\n            logger.error(msg);\n            break;\n        }\n\n        /* eslint-enable no-case-declarations */\n    };\n\n    /**\n     * Returns error status (HTTP error code) of the last BOSH request.\n     *\n     * @return {number} HTTP error code, '0' for unknown or \"god knows what\"\n     * (this is a hack).\n     */\n    Strophe.getLastErrorStatus = function() {\n        return lastErrorStatus;\n    };\n\n    Strophe.getStatusString = function(status) {\n        switch (status) {\n        case Strophe.Status.BINDREQUIRED:\n            return 'BINDREQUIRED';\n        case Strophe.Status.ERROR:\n            return 'ERROR';\n        case Strophe.Status.CONNECTING:\n            return 'CONNECTING';\n        case Strophe.Status.CONNFAIL:\n            return 'CONNFAIL';\n        case Strophe.Status.AUTHENTICATING:\n            return 'AUTHENTICATING';\n        case Strophe.Status.AUTHFAIL:\n            return 'AUTHFAIL';\n        case Strophe.Status.CONNECTED:\n            return 'CONNECTED';\n        case Strophe.Status.DISCONNECTED:\n            return 'DISCONNECTED';\n        case Strophe.Status.DISCONNECTING:\n            return 'DISCONNECTING';\n        case Strophe.Status.ATTACHED:\n            return 'ATTACHED';\n        default:\n            return 'unknown';\n        }\n    };\n}\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $msg, Strophe } from 'strophe.js';\nimport 'strophejs-plugin-disco';\n\nimport * as JitsiConnectionErrors from '../../JitsiConnectionErrors';\nimport * as JitsiConnectionEvents from '../../JitsiConnectionEvents';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport browser from '../browser';\nimport { E2EEncryption } from '../e2ee/E2EEncryption';\nimport FeatureFlags from '../flags/FeatureFlags';\nimport Statistics from '../statistics/statistics';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\nimport Listenable from '../util/Listenable';\nimport RandomUtil from '../util/RandomUtil';\n\nimport Caps, { parseDiscoInfo } from './Caps';\nimport XmppConnection from './XmppConnection';\nimport MucConnectionPlugin from './strophe.emuc';\nimport JingleConnectionPlugin from './strophe.jingle';\nimport initStropheLogger from './strophe.logger';\nimport RayoConnectionPlugin from './strophe.rayo';\nimport initStropheUtil from './strophe.util';\n\nconst logger = getLogger(__filename);\n\n/**\n* Regex to extract exact error message on jwt error.\n*/\nconst FAILURE_REGEX = /<failure.*><not-allowed\\/><text>(.*)<\\/text><\\/failure>/gi;\n\n/**\n * Creates XMPP connection.\n *\n * @param {Object} options\n * @param {string} [options.token] - JWT token used for authentication(JWT authentication module must be enabled in\n * Prosody).\n * @param {string} options.serviceUrl - The service URL for XMPP connection.\n * @param {string} options.shard - The shard where XMPP connection initially landed.\n * @param {string} options.enableWebsocketResume - True to enable stream resumption.\n * @param {number} [options.websocketKeepAlive] - See {@link XmppConnection} constructor.\n * @param {number} [options.websocketKeepAliveUrl] - See {@link XmppConnection} constructor.\n * @param {Object} [options.xmppPing] - See {@link XmppConnection} constructor.\n * @returns {XmppConnection}\n */\nfunction createConnection({\n    enableWebsocketResume,\n    serviceUrl = '/http-bind',\n    shard,\n    token,\n    websocketKeepAlive,\n    websocketKeepAliveUrl,\n    xmppPing }) {\n\n    // Append token as URL param\n    if (token) {\n        // eslint-disable-next-line no-param-reassign\n        serviceUrl += `${serviceUrl.indexOf('?') === -1 ? '?' : '&'}token=${token}`;\n    }\n\n    return new XmppConnection({\n        enableWebsocketResume,\n        serviceUrl,\n        websocketKeepAlive,\n        websocketKeepAliveUrl,\n        xmppPing,\n        shard\n    });\n}\n\n/**\n * Initializes Strophe plugins that need to work with Strophe.Connection directly rather than the lib-jitsi-meet's\n * {@link XmppConnection} wrapper.\n *\n * @returns {void}\n */\nfunction initStropheNativePlugins() {\n    initStropheUtil();\n    initStropheLogger();\n}\n\n// FIXME: remove once we have a default config template. -saghul\n/**\n * A list of ice servers to use by default for P2P.\n */\nexport const DEFAULT_STUN_SERVERS = [\n    { urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' }\n];\n\n/**\n * The name of the field used to recognize a chat message as carrying a JSON\n * payload from another endpoint.\n * If the json-message of a chat message contains a valid JSON object, and\n * the JSON has this key, then it is a valid json-message to be sent.\n */\nexport const JITSI_MEET_MUC_TYPE = 'type';\n\n/**\n * The feature used by jigasi participants.\n * @type {string}\n */\nexport const FEATURE_JIGASI = 'http://jitsi.org/protocol/jigasi';\n\n/**\n * The feature used by the lib to mark support for e2ee. We use the feature by putting it in the presence\n * to avoid additional signaling (disco-info).\n * @type {string}\n */\nexport const FEATURE_E2EE = 'https://jitsi.org/meet/e2ee';\n\n/**\n *\n */\nexport default class XMPP extends Listenable {\n    /**\n     * FIXME describe all options\n     * @param {Object} options\n     * @param {String} options.serviceUrl - URL passed to the XMPP client which will be used to establish XMPP\n     * connection with the server.\n     * @param {String} options.bosh - Deprecated, use {@code serviceUrl}.\n     * @param {boolean} options.enableWebsocketResume - Enables XEP-0198 stream management which will make the XMPP\n     * module try to resume the session in case the Websocket connection breaks.\n     * @param {number} [options.websocketKeepAlive] - The websocket keep alive interval. See {@link XmppConnection}\n     * constructor for more details.\n     * @param {number} [options.websocketKeepAliveUrl] - The websocket keep alive url. See {@link XmppConnection}\n     * constructor for more details.\n     * @param {Object} [options.xmppPing] - The xmpp ping settings.\n     * @param {Array<Object>} options.p2pStunServers see {@link JingleConnectionPlugin} for more details.\n     * @param token\n     */\n    constructor(options, token) {\n        super();\n        this.connection = null;\n        this.disconnectInProgress = false;\n        this.connectionTimes = {};\n        this.options = options;\n        this.token = token;\n        this.authenticatedUser = false;\n\n        if (!this.options.deploymentInfo) {\n            this.options.deploymentInfo = {};\n        }\n\n        // Cache of components used for certain features.\n        this._components = [];\n\n        initStropheNativePlugins();\n\n        const xmppPing = options.xmppPing || {};\n\n        // let's ping the main domain (in case a guest one is used for the connection)\n        xmppPing.domain = options.hosts.domain;\n\n        this.connection = createConnection({\n            enableWebsocketResume: options.enableWebsocketResume,\n\n            // FIXME remove deprecated bosh option at some point\n            serviceUrl: options.serviceUrl || options.bosh,\n            token,\n            websocketKeepAlive: options.websocketKeepAlive,\n            websocketKeepAliveUrl: options.websocketKeepAliveUrl,\n            xmppPing,\n            shard: options.deploymentInfo.shard\n        });\n\n        // forwards the shard changed event\n        this.connection.on(XmppConnection.Events.CONN_SHARD_CHANGED, () => {\n            /* eslint-disable camelcase */\n            const details = {\n                shard_changed: true,\n                suspend_time: this.connection.ping.getPingSuspendTime(),\n                time_since_last_success: this.connection.getTimeSinceLastSuccess()\n            };\n            /* eslint-enable camelcase */\n\n            this.eventEmitter.emit(\n                JitsiConnectionEvents.CONNECTION_FAILED,\n                JitsiConnectionErrors.OTHER_ERROR,\n                undefined,\n                undefined,\n                details);\n        });\n\n        this._initStrophePlugins();\n\n        this.caps = new Caps(this.connection, /* clientNode */ 'https://jitsi.org/jitsi-meet');\n\n        // Initialize features advertised in disco-info\n        this.initFeaturesList();\n\n        // Setup a disconnect on unload as a way to facilitate API consumers. It\n        // sounds like they would want that. A problem for them though may be if\n        // they wanted to utilize the connected connection in an unload handler\n        // of their own. However, it should be fairly easy for them to do that\n        // by registering their unload handler before us.\n        $(window).on(`${this.options.disableBeforeUnloadHandlers ? '' : 'beforeunload '}unload`, ev => {\n            this.disconnect(ev).catch(() => {\n                // ignore errors in order to not brake the unload.\n            });\n        });\n    }\n\n    /**\n     * Initializes the list of feature advertised through the disco-info\n     * mechanism.\n     */\n    initFeaturesList() {\n        // http://xmpp.org/extensions/xep-0167.html#support\n        // http://xmpp.org/extensions/xep-0176.html#support\n        this.caps.addFeature('urn:xmpp:jingle:1');\n        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:1');\n        this.caps.addFeature('urn:xmpp:jingle:transports:ice-udp:1');\n        this.caps.addFeature('urn:xmpp:jingle:apps:dtls:0');\n        this.caps.addFeature('urn:xmpp:jingle:transports:dtls-sctp:1');\n        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:audio');\n        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:video');\n        this.caps.addFeature('http://jitsi.org/json-encoded-sources');\n\n        if (!(this.options.disableRtx || !browser.supportsRTX())) {\n            this.caps.addFeature('urn:ietf:rfc:4588');\n        }\n        if (this.options.enableOpusRed === true && browser.supportsAudioRed()) {\n            this.caps.addFeature('http://jitsi.org/opus-red');\n        }\n\n        if (typeof this.options.enableRemb === 'undefined' || this.options.enableRemb) {\n            this.caps.addFeature('http://jitsi.org/remb');\n        }\n\n        // Disable TCC on Firefox because of a known issue where BWE is halved on every renegotiation.\n        if (!browser.isFirefox() && (typeof this.options.enableTcc === 'undefined' || this.options.enableTcc)) {\n            this.caps.addFeature('http://jitsi.org/tcc');\n        }\n\n        // this is dealt with by SDP O/A so we don't need to announce this\n        // XEP-0293\n        // this.caps.addFeature('urn:xmpp:jingle:apps:rtp:rtcp-fb:0');\n        // XEP-0294\n        // this.caps.addFeature('urn:xmpp:jingle:apps:rtp:rtp-hdrext:0');\n\n        // this.caps.addFeature('urn:ietf:rfc:5576'); // a=ssrc\n\n        // Enable Lipsync ?\n        if (browser.isChromiumBased() && this.options.enableLipSync === true) {\n            logger.info('Lip-sync enabled !');\n            this.caps.addFeature('http://jitsi.org/meet/lipsync');\n        }\n\n        if (this.connection.rayo) {\n            this.caps.addFeature('urn:xmpp:rayo:client:1');\n        }\n\n        if (E2EEncryption.isSupported(this.options)) {\n            this.caps.addFeature(FEATURE_E2EE, false, true);\n        }\n\n        // Advertise source-name signaling when the endpoint supports it.\n        logger.debug('Source-name signaling is enabled');\n        this.caps.addFeature('http://jitsi.org/source-name');\n\n        logger.debug('Receiving multiple video streams is enabled');\n        this.caps.addFeature('http://jitsi.org/receive-multiple-video-streams');\n\n        // Advertise support for ssrc-rewriting.\n        if (FeatureFlags.isSsrcRewritingSupported()) {\n            this.caps.addFeature('http://jitsi.org/ssrc-rewriting-1');\n        }\n\n        // Use \"-1\" as a version that we can bump later. This should match\n        // the version added in moderator.js, this one here is mostly defined\n        // for keeping stats, since it is not made available to jocofo at\n        // the time of the initial conference-request.\n        if (FeatureFlags.isJoinAsVisitorSupported()) {\n            this.caps.addFeature('http://jitsi.org/visitors-1');\n        }\n    }\n\n    /**\n     *\n     */\n    getConnection() {\n        return this.connection;\n    }\n\n    /**\n     * Receive connection status changes and handles them.\n     *\n     * @param {Object} credentials\n     * @param {string} credentials.jid - The user's XMPP ID passed to the\n     * connect method. For example, 'user@xmpp.com'.\n     * @param {string} credentials.password - The password passed to the connect\n     * method.\n     * @param {string} status - One of Strophe's connection status strings.\n     * @param {string} [msg] - The connection error message provided by Strophe.\n     */\n    connectionHandler(credentials = {}, status, msg) {\n        const now = window.performance.now();\n        const statusStr = Strophe.getStatusString(status).toLowerCase();\n\n        this.connectionTimes[statusStr] = now;\n        logger.log(\n            `(TIME) Strophe ${statusStr}${msg ? `[${msg}]` : ''}:\\t`,\n            now);\n\n        this.eventEmitter.emit(XMPPEvents.CONNECTION_STATUS_CHANGED, credentials, status, msg);\n        this._maybeSendDeploymentInfoStat();\n        if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {\n            // once connected or attached we no longer need this handle, drop it if it exist\n            if (this._sysMessageHandler) {\n                this.connection._stropheConn.deleteHandler(this._sysMessageHandler);\n                this._sysMessageHandler = null;\n            }\n\n            this.sendDiscoInfo && this.connection.jingle.getStunAndTurnCredentials();\n\n            logger.info(`My Jabber ID: ${this.connection.jid}`);\n\n            // XmppConnection emits CONNECTED again on reconnect - a good opportunity to clear any \"last error\" flags\n            this._resetState();\n\n            // make sure we will send the info after the features request succeeds or fails\n            this.sendDeploymentInfo = false;\n            this.sendDiscoInfo && this.caps.getFeaturesAndIdentities(this.options.hosts.domain)\n                .then(({ features, identities }) => {\n                    if (!features.has(Strophe.NS.PING)) {\n                        logger.error(`Ping NOT supported by ${\n                            this.options.hosts.domain} - please enable ping in your XMPP server config`);\n                    }\n\n                    this._processDiscoInfoIdentities(\n                        identities, undefined /* when querying we will query for features */);\n                })\n                .catch(error => {\n                    const errmsg = 'Feature discovery error';\n\n                    GlobalOnErrorHandler.callErrorHandler(\n                        new Error(`${errmsg}: ${error}`));\n                    logger.error(errmsg, error);\n\n                    this._maybeSendDeploymentInfoStat(true);\n                });\n\n            // make sure we don't query again\n            this.sendDiscoInfo = false;\n\n            if (credentials.password) {\n                this.authenticatedUser = true;\n            }\n            if (this.connection && this.connection.connected\n                && Strophe.getResourceFromJid(this.connection.jid)) {\n                // .connected is true while connecting?\n                // this.connection.send($pres());\n                this.eventEmitter.emit(\n                    JitsiConnectionEvents.CONNECTION_ESTABLISHED,\n                    Strophe.getResourceFromJid(this.connection.jid));\n            }\n        } else if (status === Strophe.Status.CONNFAIL) {\n            if (msg === 'x-strophe-bad-non-anon-jid') {\n                this.anonymousConnectionFailed = true;\n            } else {\n                this.connectionFailed = true;\n            }\n            this.lastErrorMsg = msg;\n            if (msg === 'giving-up') {\n                this.eventEmitter.emit(\n                    JitsiConnectionEvents.CONNECTION_FAILED,\n                    JitsiConnectionErrors.OTHER_ERROR, msg);\n            }\n        } else if (status === Strophe.Status.ERROR) {\n            this.lastErrorMsg = msg;\n        } else if (status === Strophe.Status.DISCONNECTED) {\n            // Stop ping interval\n            this.connection.ping.stopInterval();\n            const wasIntentionalDisconnect = Boolean(this.disconnectInProgress);\n            const errMsg = msg || this.lastErrorMsg;\n\n            if (this.anonymousConnectionFailed) {\n                // prompt user for username and password\n                this.eventEmitter.emit(\n                    JitsiConnectionEvents.CONNECTION_FAILED,\n                    JitsiConnectionErrors.PASSWORD_REQUIRED);\n            } else if (this.connectionFailed) {\n                this.eventEmitter.emit(\n                    JitsiConnectionEvents.CONNECTION_FAILED,\n                    JitsiConnectionErrors.OTHER_ERROR,\n                    errMsg,\n                    undefined, /* credentials */\n                    this._getConnectionFailedReasonDetails());\n            } else if (wasIntentionalDisconnect) {\n                this.eventEmitter.emit(\n                    JitsiConnectionEvents.CONNECTION_DISCONNECTED, errMsg);\n            } else {\n                // XXX if Strophe drops the connection while not being asked to,\n                // it means that most likely some serious error has occurred.\n                // One currently known case is when a BOSH request fails for\n                // more than 4 times. The connection is dropped without\n                // supplying a reason(error message/event) through the API.\n                logger.error('XMPP connection dropped!');\n\n                // XXX if the last request error is within 5xx range it means it\n                // was a server failure\n                const lastErrorStatus = Strophe.getLastErrorStatus();\n\n                if (lastErrorStatus >= 500 && lastErrorStatus < 600) {\n                    this.eventEmitter.emit(\n                        JitsiConnectionEvents.CONNECTION_FAILED,\n                        JitsiConnectionErrors.SERVER_ERROR,\n                        errMsg || 'server-error',\n                        /* credentials */ undefined,\n                        this._getConnectionFailedReasonDetails());\n                } else {\n                    this.eventEmitter.emit(\n                        JitsiConnectionEvents.CONNECTION_FAILED,\n                        JitsiConnectionErrors.CONNECTION_DROPPED_ERROR,\n                        errMsg || 'connection-dropped-error',\n                        /* credentials */ undefined,\n                        this._getConnectionFailedReasonDetails());\n                }\n            }\n        } else if (status === Strophe.Status.AUTHFAIL) {\n            const lastFailedRawMessage = this.getConnection().getLastFailedMessage();\n\n            // wrong password or username, prompt user\n            this.eventEmitter.emit(\n                JitsiConnectionEvents.CONNECTION_FAILED,\n                JitsiConnectionErrors.PASSWORD_REQUIRED,\n                msg || this._parseConnectionFailedMessage(lastFailedRawMessage),\n                credentials);\n        }\n    }\n\n    /**\n     * Process received identities.\n     * @param {Set<String>} identities The identities to process.\n     * @param {Set<String>} features The features to process, optional. If missing lobby component will be queried\n     * for more features.\n     * @private\n     */\n    _processDiscoInfoIdentities(identities, features) {\n        // check for speakerstats\n        identities.forEach(identity => {\n            if (identity.type === 'av_moderation') {\n                this.avModerationComponentAddress = identity.name;\n                this._components.push(this.avModerationComponentAddress);\n            }\n\n            if (identity.type === 'end_conference') {\n                this.endConferenceComponentAddress = identity.name;\n                this._components.push(this.endConferenceComponentAddress);\n            }\n\n            if (identity.type === 'speakerstats') {\n                this.speakerStatsComponentAddress = identity.name;\n                this._components.push(this.speakerStatsComponentAddress);\n            }\n\n            if (identity.type === 'conference_duration') {\n                this.conferenceDurationComponentAddress = identity.name;\n                this._components.push(this.conferenceDurationComponentAddress);\n            }\n\n            if (identity.type === 'lobbyrooms') {\n                this.lobbySupported = true;\n                const processLobbyFeatures = f => {\n                    f.forEach(fr => {\n                        if (fr.endsWith('#displayname_required')) {\n                            this.eventEmitter.emit(JitsiConnectionEvents.DISPLAY_NAME_REQUIRED);\n                        }\n                    });\n                };\n\n                if (features) {\n                    processLobbyFeatures(features);\n                } else {\n                    identity.name && this.caps.getFeaturesAndIdentities(identity.name, identity.type)\n                        .then(({ features: f }) => processLobbyFeatures(f))\n                        .catch(e => logger.warn('Error getting features from lobby.', e && e.message));\n                }\n            }\n\n            if (identity.type === 'shard') {\n                this.options.deploymentInfo.shard = this.connection.shard = identity.name;\n            }\n\n            if (identity.type === 'region') {\n                this.options.deploymentInfo.region = this.connection.region = identity.name;\n            }\n\n            if (identity.type === 'release') {\n                this.options.deploymentInfo.backendRelease = identity.name;\n            }\n\n            if (identity.type === 'breakout_rooms') {\n                this.breakoutRoomsComponentAddress = identity.name;\n                this._components.push(this.breakoutRoomsComponentAddress);\n            }\n\n            if (identity.type === 'room_metadata') {\n                this.roomMetadataComponentAddress = identity.name;\n                this._components.push(this.roomMetadataComponentAddress);\n            }\n        });\n\n        this._maybeSendDeploymentInfoStat(true);\n\n        if (this._components.length > 0) {\n            this.connection.addHandler(this._onPrivateMessage.bind(this), null, 'message', null, null);\n        }\n    }\n\n    /**\n    * Parses a raw failure xmpp xml message received on auth failed.\n    *\n    * @param {string} msg - The raw failure message from xmpp.\n    * @returns {string|null} - The parsed message from the raw xmpp message.\n    */\n    _parseConnectionFailedMessage(msg) {\n        if (!msg) {\n            return null;\n        }\n\n        const matches = FAILURE_REGEX.exec(msg);\n\n        return matches ? matches[1] : null;\n    }\n\n    /**\n     *\n     * @param jid\n     * @param password\n     */\n    _connect(jid, password) {\n        // connection.connect() starts the connection process.\n        //\n        // As the connection process proceeds, the user supplied callback will\n        // be triggered multiple times with status updates. The callback should\n        // take two arguments - the status code and the error condition.\n        //\n        // The status code will be one of the values in the Strophe.Status\n        // constants. The error condition will be one of the conditions defined\n        // in RFC 3920 or the condition ‘strophe-parsererror’.\n        //\n        // The Parameters wait, hold and route are optional and only relevant\n        // for BOSH connections. Please see XEP 124 for a more detailed\n        // explanation of the optional parameters.\n        //\n        // Connection status constants for use by the connection handler\n        // callback.\n        //\n        //  Status.ERROR - An error has occurred (websockets specific)\n        //  Status.CONNECTING - The connection is currently being made\n        //  Status.CONNFAIL - The connection attempt failed\n        //  Status.AUTHENTICATING - The connection is authenticating\n        //  Status.AUTHFAIL - The authentication attempt failed\n        //  Status.CONNECTED - The connection has succeeded\n        //  Status.DISCONNECTED - The connection has been terminated\n        //  Status.DISCONNECTING - The connection is currently being terminated\n        //  Status.ATTACHED - The connection has been attached\n\n        this._resetState();\n\n        // we want to send this only on the initial connect\n        this.sendDiscoInfo = true;\n        this.sendDeploymentInfo = true;\n\n        if (this.connection._stropheConn && this.connection._stropheConn._addSysHandler) {\n            this._sysMessageHandler = this.connection._stropheConn._addSysHandler(\n                this._onSystemMessage.bind(this),\n                null,\n                'message'\n            );\n        } else {\n            logger.warn('Cannot attach strophe system handler, jiconop cannot operate');\n        }\n\n        this.connection.connect(\n            jid,\n            password,\n            this.connectionHandler.bind(this, {\n                jid,\n                password\n            }));\n    }\n\n    /**\n     * Receives system messages during the connect/login process and checks for services or\n     * @param msg The received message.\n     * @returns {void}\n     * @private\n     */\n    _onSystemMessage(msg) {\n        // proceed only if the message has any of the expected information\n        if ($(msg).find('>services').length === 0 && $(msg).find('>query').length === 0) {\n            return;\n        }\n\n        this.sendDiscoInfo = false;\n\n        const foundIceServers = this.connection.jingle.onReceiveStunAndTurnCredentials(msg);\n\n        const { features, identities } = parseDiscoInfo(msg);\n\n        this._processDiscoInfoIdentities(identities, features);\n\n        if (foundIceServers || identities.size > 0 || features.size > 0) {\n            this.connection._stropheConn.deleteHandler(this._sysMessageHandler);\n            this._sysMessageHandler = null;\n        }\n    }\n\n    /**\n     * Attach to existing connection. Can be used for optimizations. For\n     * example: if the connection is created on the server we can attach to it\n     * and start using it.\n     *\n     * @param options {object} connecting options - rid, sid, jid and password.\n     */\n    attach(options) {\n        this._resetState();\n\n        // we want to send this only on the initial connect\n        this.sendDiscoInfo = true;\n\n        const now = this.connectionTimes.attaching = window.performance.now();\n\n        logger.log('(TIME) Strophe Attaching:\\t', now);\n        this.connection.attach(options.jid, options.sid,\n            parseInt(options.rid, 10) + 1,\n            this.connectionHandler.bind(this, {\n                jid: options.jid,\n                password: options.password\n            }));\n    }\n\n    /**\n     * Resets any state/flag before starting a new connection.\n     * @private\n     */\n    _resetState() {\n        this.anonymousConnectionFailed = false;\n        this.connectionFailed = false;\n        this.lastErrorMsg = undefined;\n        this.disconnectInProgress = undefined;\n    }\n\n    /**\n     *\n     * @param jid\n     * @param password\n     */\n    connect(jid, password) {\n        if (!jid) {\n            const { anonymousdomain, domain } = this.options.hosts;\n            let configDomain = anonymousdomain || domain;\n\n            // Force authenticated domain if room is appended with '?login=true'\n            // or if we're joining with the token\n\n            // FIXME Do not rely on window.location because (1) React Native\n            // does not have a window.location by default and (2) here we cannot\n            // know for sure that query/search has not be stripped from\n            // window.location by the time the following executes.\n            const { location } = window;\n\n            if (anonymousdomain) {\n                const search = location && location.search;\n\n                if ((search && search.indexOf('login=true') !== -1)\n                        || this.token) {\n                    configDomain = domain;\n                }\n            }\n\n            // eslint-disable-next-line no-param-reassign\n            jid = configDomain || (location && location.hostname);\n        }\n\n        return this._connect(jid, password);\n    }\n\n    /**\n     * Joins or creates a muc with the provided jid, created from the passed\n     * in room name and muc host and onCreateResource result.\n     *\n     * @param {string} roomName - The name of the muc to join.\n     * @param {Object} options - Configuration for how to join the muc.\n     * @param {Function} [onCreateResource] - Callback to invoke when a resource\n     * is to be added to the jid.\n     * @returns {Promise} Resolves with an instance of a strophe muc.\n     */\n    createRoom(roomName, options, onCreateResource) {\n        // Support passing the domain in a String object as part of the room name.\n        const domain = roomName.domain || options.customDomain;\n\n        // There are cases (when using subdomain) where muc can hold an uppercase part\n        let roomjid = `${this.getRoomJid(roomName, domain)}/`;\n        const mucNickname = onCreateResource\n            ? onCreateResource(this.connection.jid, this.authenticatedUser)\n            : RandomUtil.randomHexString(8).toLowerCase();\n\n        logger.info(`JID ${this.connection.jid} using MUC nickname ${mucNickname}`);\n        roomjid += mucNickname;\n\n        return this.connection.emuc.createRoom(roomjid, null, options);\n    }\n\n    /**\n     * Returns the room JID based on the passed room name and domain.\n     *\n     * @param {string} roomName - The room name.\n     * @param {string} domain - The domain.\n     * @returns {string} - The room JID.\n     */\n    getRoomJid(roomName, domain) {\n        return `${roomName}@${domain ? domain : this.options.hosts.muc.toLowerCase()}`;\n    }\n\n    /**\n     * Check if a room with the passed JID is already created.\n     *\n     * @param {string} roomJid - The JID of the room.\n     * @returns {boolean}\n     */\n    isRoomCreated(roomName, domain) {\n        return this.connection.emuc.isRoomCreated(this.getRoomJid(roomName, domain));\n    }\n\n    /**\n     * Returns the jid of the participant associated with the Strophe connection.\n     *\n     * @returns {string} The jid of the participant.\n     */\n    getJid() {\n        return this.connection.jid;\n    }\n\n    /**\n     * Returns the logs from strophe.jingle.\n     * @returns {Object}\n     */\n    getJingleLog() {\n        const jingle = this.connection.jingle;\n\n\n        return jingle ? jingle.getLog() : {};\n    }\n\n    /**\n     * Returns the logs from strophe.\n     */\n    getXmppLog() {\n        return (this.connection.logger || {}).log || null;\n    }\n\n    /**\n     *\n     */\n    dial(...args) {\n        this.connection.rayo.dial(...args);\n    }\n\n    /**\n     * Pings the server.\n     * @param timeout how many ms before a timeout should occur.\n     * @returns {Promise} resolved on ping success and reject on an error or\n     * a timeout.\n     */\n    ping(timeout) {\n        return new Promise((resolve, reject) => {\n            this.connection.ping.ping(this.connection.pingDomain, resolve, reject, timeout);\n        });\n    }\n\n    /**\n     *\n     */\n    getSessions() {\n        return this.connection.jingle.sessions;\n    }\n\n    /**\n     * Disconnects this from the XMPP server (if this is connected).\n     *\n     * @param {Object} ev - Optionally, the event which triggered the necessity to\n     * disconnect from the XMPP server (e.g. beforeunload, unload).\n     * @returns {Promise} - Resolves when the disconnect process is finished or rejects with an error.\n     */\n    disconnect(ev) {\n        if (this.disconnectInProgress) {\n            return this.disconnectInProgress;\n        } else if (!this.connection) {\n            return Promise.resolve();\n        }\n\n        this.disconnectInProgress = new Promise(resolve => {\n            const disconnectListener = (credentials, status) => {\n                if (status === Strophe.Status.DISCONNECTED) {\n                    this.eventEmitter.removeListener(XMPPEvents.CONNECTION_STATUS_CHANGED, disconnectListener);\n                    resolve();\n                }\n            };\n\n            this.eventEmitter.on(XMPPEvents.CONNECTION_STATUS_CHANGED, disconnectListener);\n        });\n\n        this._cleanupXmppConnection(ev);\n\n        return this.disconnectInProgress;\n    }\n\n    /**\n     * The method is supposed to gracefully close the XMPP connection and the main goal is to make sure that the current\n     * participant will be removed from the conference XMPP MUC, so that it doesn't leave a \"ghost\" participant behind.\n     *\n     * @param {Object} ev - Optionally, the event which triggered the necessity to disconnect from the XMPP server\n     * (e.g. beforeunload, unload).\n     * @private\n     * @returns {void}\n     */\n    _cleanupXmppConnection(ev) {\n        // XXX Strophe is asynchronously sending by default. Unfortunately, that means that there may not be enough time\n        // to send an unavailable presence or disconnect at all. Switching Strophe to synchronous sending is not much of\n        // an option because it may lead to a noticeable delay in navigating away from the current location. As\n        // a compromise, we will try to increase the chances of sending an unavailable presence and/or disconnecting\n        // within the short time span that we have upon unloading by invoking flush() on the connection. We flush() once\n        // before disconnect() in order to attempt to have its unavailable presence at the top of the send queue. We\n        // flush() once more after disconnect() in order to attempt to have its unavailable presence sent as soon as\n        // possible.\n        !this.connection.isUsingWebSocket && this.connection.flush();\n\n        if (!this.connection.isUsingWebSocket && ev !== null && typeof ev !== 'undefined') {\n            const evType = ev.type;\n\n            if (evType === 'beforeunload' || evType === 'unload') {\n                // XXX Whatever we said above, synchronous sending is the best (known) way to properly disconnect from\n                // the XMPP server. Consequently, it may be fine to have the source code and comment it in or out\n                // depending on whether we want to run with it for some time.\n                this.connection.options.sync = true;\n\n                // This is needed in some browsers where sync xhr sending is disabled by default on unload.\n                if (this.connection.sendUnavailableBeacon()) {\n\n                    return;\n                }\n            }\n        }\n\n        this.connection.disconnect();\n\n        if (this.connection.options.sync !== true) {\n            this.connection.flush();\n        }\n    }\n\n    /**\n     *\n     */\n    _initStrophePlugins() {\n        const iceConfig = {\n            jvb: { iceServers: [ ] },\n            p2p: { iceServers: [ ] }\n        };\n\n        const p2pStunServers = (this.options.p2p\n            && this.options.p2p.stunServers) || DEFAULT_STUN_SERVERS;\n\n        if (Array.isArray(p2pStunServers)) {\n            logger.info('P2P STUN servers: ', p2pStunServers);\n            iceConfig.p2p.iceServers = p2pStunServers;\n        }\n\n        if (this.options.p2p && this.options.p2p.iceTransportPolicy) {\n            logger.info('P2P ICE transport policy: ',\n                this.options.p2p.iceTransportPolicy);\n\n            iceConfig.p2p.iceTransportPolicy\n                = this.options.p2p.iceTransportPolicy;\n        }\n\n        this.connection.addConnectionPlugin('emuc', new MucConnectionPlugin(this));\n        this.connection.addConnectionPlugin('jingle', new JingleConnectionPlugin(this, this.eventEmitter, iceConfig));\n        this.connection.addConnectionPlugin('rayo', new RayoConnectionPlugin());\n    }\n\n    /**\n     * Returns details about connection failure. Shard change or is it after\n     * suspend.\n     * @returns {object} contains details about a connection failure.\n     * @private\n     */\n    _getConnectionFailedReasonDetails() {\n        const details = {};\n\n        // check for moving between shard if information is available\n        if (this.options.deploymentInfo\n            && this.options.deploymentInfo.shard\n            && this.connection.lastResponseHeaders) {\n\n            // split headers by line\n            const headersArr = this.connection.lastResponseHeaders\n                .trim().split(/[\\r\\n]+/);\n            const headers = {};\n\n            headersArr.forEach(line => {\n                const parts = line.split(': ');\n                const header = parts.shift();\n                const value = parts.join(': ');\n\n                headers[header] = value;\n            });\n\n            /* eslint-disable camelcase */\n            details.shard_changed\n                = this.options.deploymentInfo.shard\n                    !== headers['x-jitsi-shard'];\n            /* eslint-enable camelcase */\n        }\n\n        /* eslint-disable camelcase */\n        // check for possible suspend\n        details.suspend_time = this.connection.ping.getPingSuspendTime();\n        details.time_since_last_success = this.connection.getTimeSinceLastSuccess();\n        /* eslint-enable camelcase */\n\n        return details;\n    }\n\n    /**\n     * Notifies speaker stats component if available that we are the new\n     * dominant speaker in the conference.\n     * @param {String} roomJid - The room jid where the speaker event occurred.\n     * @param {boolean} silence - Whether the dominant speaker is silent or not.\n     */\n    sendDominantSpeakerEvent(roomJid, silence) {\n        // no speaker stats component advertised\n        if (!this.speakerStatsComponentAddress || !roomJid) {\n            return;\n        }\n\n        const msg = $msg({ to: this.speakerStatsComponentAddress });\n\n        msg.c('speakerstats', {\n            xmlns: 'http://jitsi.org/jitmeet',\n            room: roomJid,\n            silence })\n            .up();\n\n        this.connection.send(msg);\n    }\n\n    /**\n     * Sends face landmarks to speaker stats component.\n     * @param {String} roomJid - The room jid where the speaker event occurred.\n     * @param {Object} payload - The expression to be sent to the speaker stats.\n     */\n    sendFaceLandmarksEvent(roomJid, payload) {\n        // no speaker stats component advertised\n        if (!this.speakerStatsComponentAddress || !roomJid) {\n            return;\n        }\n\n        const msg = $msg({ to: this.speakerStatsComponentAddress });\n\n        msg.c('faceLandmarks', {\n            xmlns: 'http://jitsi.org/jitmeet',\n            room: roomJid,\n            faceExpression: payload.faceExpression,\n            timestamp: payload.timestamp,\n            duration: payload.duration\n        }).up();\n\n        this.connection.send(msg);\n    }\n\n    /**\n     * Check if the given argument is a valid JSON ENDPOINT_MESSAGE string by\n     * parsing it and checking if it has a field called 'type'.\n     *\n     * @param {string} jsonString check if this string is a valid json string\n     * and contains the special structure.\n     * @returns {boolean, object} if given object is a valid JSON string, return\n     * the json object. Otherwise, returns false.\n     */\n    tryParseJSONAndVerify(jsonString) {\n        // ignore empty strings, like message errors\n        if (!jsonString) {\n            return false;\n        }\n\n        try {\n            const json = JSON.parse(jsonString);\n\n            // Handle non-exception-throwing cases:\n            // Neither JSON.parse(false) or JSON.parse(1234) throw errors,\n            // hence the type-checking,\n            // but... JSON.parse(null) returns null, and\n            // typeof null === \"object\",\n            // so we must check for that, too.\n            // Thankfully, null is falsey, so this suffices:\n            if (json && typeof json === 'object') {\n                const type = json[JITSI_MEET_MUC_TYPE];\n\n                if (typeof type !== 'undefined') {\n                    return json;\n                }\n\n                logger.debug('parsing valid json but does not have correct '\n                    + 'structure', 'topic: ', type);\n            }\n        } catch (e) {\n            logger.error(`Error parsing json ${jsonString}`, e);\n\n            return false;\n        }\n\n        return false;\n    }\n\n    /**\n     * A private message is received, message that is not addressed to the muc.\n     * We expect private message coming from plugins component if it is\n     * enabled and running.\n     *\n     * @param {string} msg - The message.\n     */\n    _onPrivateMessage(msg) {\n        const from = msg.getAttribute('from');\n\n        if (!this._components.includes(from)) {\n            return true;\n        }\n\n        const jsonMessage = $(msg).find('>json-message')\n            .text();\n        const parsedJson = this.tryParseJSONAndVerify(jsonMessage);\n\n        if (!parsedJson) {\n            return true;\n        }\n\n        if (parsedJson[JITSI_MEET_MUC_TYPE] === 'speakerstats' && parsedJson.users) {\n            this.eventEmitter.emit(XMPPEvents.SPEAKER_STATS_RECEIVED, parsedJson.users);\n        } else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'conference_duration' && parsedJson.created_timestamp) {\n            this.eventEmitter.emit(XMPPEvents.CONFERENCE_TIMESTAMP_RECEIVED, parsedJson.created_timestamp);\n        } else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'av_moderation') {\n            this.eventEmitter.emit(XMPPEvents.AV_MODERATION_RECEIVED, parsedJson);\n        } else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'breakout_rooms') {\n            this.eventEmitter.emit(XMPPEvents.BREAKOUT_ROOMS_EVENT, parsedJson);\n        } else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'room_metadata') {\n            this.eventEmitter.emit(XMPPEvents.ROOM_METADATA_EVENT, parsedJson);\n        }\n\n        return true;\n    }\n\n    /**\n     * Sends deployment info to stats if not sent already.\n     * We want to try sending it on failure to connect\n     * or when we get a sys message(from jiconop2)\n     * or after success or failure of disco-info\n     * @param force Whether to force sending without checking anything.\n     * @private\n     */\n    _maybeSendDeploymentInfoStat(force) {\n        const acceptedStatuses = [\n            Strophe.Status.ERROR,\n            Strophe.Status.CONNFAIL,\n            Strophe.Status.AUTHFAIL,\n            Strophe.Status.DISCONNECTED,\n            Strophe.Status.CONNTIMEOUT\n        ];\n\n        if (!force && !(acceptedStatuses.includes(this.connection.status) && this.sendDeploymentInfo)) {\n            return;\n        }\n\n        // Log deployment-specific information, if available. Defined outside\n        // the application by individual deployments\n        const aprops = this.options.deploymentInfo;\n\n        if (aprops && Object.keys(aprops).length > 0) {\n            const logObject = {};\n\n            for (const attr in aprops) {\n                if (aprops.hasOwnProperty(attr)) {\n                    logObject[attr] = aprops[attr];\n                }\n            }\n\n            // Let's push to analytics any updates that may have come from the backend\n            Statistics.analytics.addPermanentProperties({ ...logObject });\n\n            logObject.id = 'deployment_info';\n            Statistics.sendLog(JSON.stringify(logObject));\n        }\n\n        this.sendDeploymentInfo = false;\n    }\n}\n","import {\n    CONNECTION_DISCONNECTED,\n    CONNECTION_ESTABLISHED,\n    CONNECTION_FAILED\n} from './JitsiConnectionEvents';\nimport XMPP from './modules/xmpp/xmpp';\n\n/**\n * @typedef {Object} UpgradeRoleError\n *\n * @property {JitsiConnectionErrors} [connectionError] - One of\n * {@link JitsiConnectionErrors} which occurred when trying to connect to the\n * XMPP server.\n * @property {String} [authenticationError] - One of XMPP error conditions\n * returned by Jicofo on authentication attempt. See\n * {@link https://xmpp.org/rfcs/rfc3920.html#streams-error}.\n * @property {String} [message] - More details about the error.\n * @property {Object} [credentials] - The credentials that failed the\n * authentication.\n * @property {String} [credentials.jid] - The XMPP ID part of the credentials\n * that failed the authentication.\n * @property {string} [credentials.password] - The password part of the\n * credentials that failed the authentication.\n *\n * NOTE If neither one of the errors is present, then the operation has been\n * canceled.\n */\n\n/* eslint-disable no-invalid-this */\n\n/**\n * Connects to the XMPP server using the specified credentials and contacts\n * Jicofo in order to obtain a session ID (which is then stored in the local\n * storage). The user's role of the parent conference will be upgraded to\n * moderator (by Jicofo). It's also used to join the conference when starting\n * from anonymous domain and only authenticated users are allowed to create new\n * rooms.\n *\n * @param {Object} options\n * @param {string} options.id - XMPP user's ID to log in. For example,\n * user@xmpp-server.com.\n * @param {string} options.password - XMPP user's password to log in with.\n * @param {Function} [options.onLoginSuccessful] - Callback called when logging\n * into the XMPP server was successful. The next step will be to obtain a new\n * session ID from Jicofo and join the MUC using it which will effectively\n * upgrade the user's role to moderator.\n * @returns {Object} A <tt>thenable</tt> which (1) settles when the process of\n * authenticating and upgrading the role of the specified XMPP user finishes and\n * (2) has a <tt>cancel</tt> method that allows the caller to interrupt the\n * process. If the process finishes successfully, the session ID has been stored\n * in the settings and the <tt>thenable</tt> is resolved. If the process\n * finishes with failure, the <tt>thenable</tt> is rejected with reason of type\n * {@link UpgradeRoleError} which will have either <tt>connectionError</tt> or\n * <tt>authenticationError</tt> property set depending on which of the steps has\n * failed. If <tt>cancel</tt> is called before the process finishes, then the\n * thenable will be rejected with an empty object (i.e. no error property will\n * be set on the rejection reason).\n */\nexport default function authenticateAndUpgradeRole({\n    // 1. Log the specified XMPP user in.\n    id,\n    password,\n    onCreateResource,\n\n    // 2. Let the API client/consumer know as soon as the XMPP user has been\n    //    successfully logged in.\n    onLoginSuccessful\n}) {\n    let canceled = false;\n    let rejectPromise;\n    let xmpp = new XMPP(this.connection.options);\n\n    const process = new Promise((resolve, reject) => {\n        // The process is represented by a Thenable with a cancel method. The\n        // Thenable is implemented using Promise and the cancel using the\n        // Promise's reject function.\n        rejectPromise = reject;\n\n\n        xmpp.addListener(\n            CONNECTION_DISCONNECTED,\n            () => {\n                xmpp = undefined;\n            });\n        xmpp.addListener(\n            CONNECTION_ESTABLISHED,\n            () => {\n                if (canceled) {\n                    return;\n                }\n\n                // Let the caller know that the XMPP login was successful.\n                onLoginSuccessful && onLoginSuccessful();\n\n                // Now authenticate with Jicofo and get a new session ID.\n                const room = xmpp.createRoom(\n                    this.options.name,\n                    this.options.config,\n                    onCreateResource\n                );\n\n                room.moderator.authenticate()\n                    .then(() => {\n                        xmpp && xmpp.disconnect();\n\n                        if (canceled) {\n                            return;\n                        }\n\n                        // At this point we should have the new session ID\n                        // stored in the settings. Send a new conference IQ.\n                        this.room.moderator.allocateConferenceFocus();\n\n                        resolve();\n                    })\n                    .catch(({ error, message }) => {\n                        xmpp.disconnect();\n\n                        reject({\n                            authenticationError: error,\n                            message\n                        });\n                    });\n            });\n        xmpp.addListener(\n            CONNECTION_FAILED,\n            (connectionError, message, credentials) => {\n                reject({\n                    connectionError,\n                    credentials,\n                    message\n                });\n                xmpp = undefined;\n            });\n\n        canceled || xmpp.connect(id, password);\n    });\n\n    /**\n     * Cancels the process, if it's in progress, of authenticating and upgrading\n     * the role of the local participant/user.\n     *\n     * @public\n     * @returns {void}\n     */\n    process.cancel = () => {\n        canceled = true;\n        rejectPromise({});\n        xmpp && xmpp.disconnect();\n    };\n\n    return process;\n}\n\n/* eslint-enable no-invalid-this */\n","\nimport { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport CodecMimeType from '../../service/RTC/CodecMimeType';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport browser from '../browser';\n\nconst logger = getLogger(__filename);\n\n/**\n * This class handles the codec selection mechanism for the conference based on the config.js settings.\n * The preferred codec is selected based on the settings and the list of codecs supported by the browser.\n * The preferred codec is published in presence which is then used by the other endpoints in the\n * conference to pick a supported codec at join time and when the call transitions between p2p and jvb\n * connections.\n */\nexport class CodecSelection {\n    /**\n     * Creates a new instance for a given conference.\n     *\n     * @param {JitsiConference} conference the conference instance\n     * @param {*} options\n     * @param {string} options.disabledCodec the codec that needs to be disabled.\n     * @param {boolean} options.enforcePreferredCodec whether codec preference has to be\n     * enforced even when an endpoints that doesn't support the preferred codec joins the call.\n     * Falling back to the standard codec will be skipped when this option is true, endpoints\n     * that do not support the preferred codec may not be able to encode/decode video when this happens.\n     * @param {string} options.jvbCodec the codec that is preferred on jvb connection.\n     * @param {string} options.p2pCodec the codec that is preferred on p2p connection.\n     */\n    constructor(conference, options) {\n        this.conference = conference;\n        this.options = options;\n        this.enforcePreferredCodec = options.enforcePreferredCodec;\n\n        // VP8 cannot be disabled since it the default codec.\n        this.p2pDisabledCodec = options.p2pDisabledCodec !== CodecMimeType.VP8\n            && this._isCodecSupported(options.p2pDisabledCodec)\n            && options.p2pDisabledCodec;\n        this.jvbDisabledCodec = options.jvbDisabledCodec !== CodecMimeType.VP8\n            && this._isCodecSupported(options.jvbDisabledCodec)\n            && options.jvbDisabledCodec;\n\n        // Determine the preferred codecs.\n        this.p2pPreferredCodec = this._isCodecSupported(options.p2pPreferredCodec)\n            && options.p2pPreferredCodec !== options.p2pDisabledCodec\n            ? options.p2pPreferredCodec\n            : CodecMimeType.VP8;\n        this.jvbPreferredCodec = this._isCodecSupported(options.jvbPreferredCodec)\n            && options.jvbPreferredCodec !== options.jvbDisabledCodec\n            ? options.jvbPreferredCodec\n            : CodecMimeType.VP8;\n\n        logger.debug(`Codec preferences for the conference are JVB: preferred=${this.jvbPreferredCodec},`\n            + `disabled=${this.jvbDisabledCodec} P2P: preferred=${this.p2pPreferredCodec},`\n            + `disabled=${this.p2pDisabledCodec}`);\n\n        this.conference.on(\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\n            session => this._selectPreferredCodec(session));\n        this.conference.on(\n            JitsiConferenceEvents.USER_JOINED,\n            () => this._selectPreferredCodec());\n        this.conference.on(\n            JitsiConferenceEvents.USER_LEFT,\n            () => this._selectPreferredCodec());\n    }\n\n    /**\n     * Checks if the given codec is supported by the browser.\n     *\n     * @param {CodecMimeType} preferredCodec codec to be checked.\n     * @returns {boolean} true if the given codec is supported, false otherwise.\n     * @private\n     */\n    _isCodecSupported(preferredCodec) {\n        if (!preferredCodec) {\n            return false;\n        }\n\n        if (preferredCodec === CodecMimeType.VP9 && !this.enforcePreferredCodec && !browser.supportsVP9()) {\n            return false;\n        }\n\n        // Skip the check on FF because it does not support the getCapabilities API.\n        // It is safe to assume that Firefox supports all the codecs supported by Chrome.\n        if (browser.isFirefox()) {\n            return true;\n        }\n\n        return window.RTCRtpReceiver\n            && window.RTCRtpReceiver.getCapabilities\n            && window.RTCRtpReceiver.getCapabilities('video').codecs\n            .some(codec => codec.mimeType.toLowerCase() === `video/${preferredCodec}`);\n    }\n\n    /**\n     * Sets the codec on the media session based on the preferred/disabled codec setting and the supported codecs\n     * published by the remote participants in their presence.\n     *\n     * @param {JingleSessionPC} mediaSession session for which the codec selection has to be made.\n     */\n    _selectPreferredCodec(mediaSession) {\n        const session = mediaSession ? mediaSession : this.conference.jvbJingleSession;\n\n        if (!session) {\n            return;\n        }\n        const preferredCodec = session.isP2P ? this.p2pPreferredCodec : this.jvbPreferredCodec;\n        const disabledCodec = session.isP2P ? this.p2pDisabledCodec : this.jvbDisabledCodec;\n        const currentCodec = session?.peerconnection.getConfiguredVideoCodec();\n        let selectedCodec = preferredCodec ?? currentCodec;\n\n        if (!this.enforcePreferredCodec) {\n            const remoteParticipants = this.conference.getParticipants().map(participant => participant.getId());\n            const remoteCodecs = remoteParticipants?.map(remote => {\n                const peerMediaInfo = session._signalingLayer.getPeerMediaInfo(remote, MediaType.VIDEO);\n\n                return peerMediaInfo?.codecType;\n            });\n\n            const nonPreferredCodecs = remoteCodecs.filter(codec => codec !== selectedCodec && codec !== disabledCodec);\n\n            // Find the fallback codec when there are endpoints in the call that don't have the same preferred codec\n            // set.\n            if (nonPreferredCodecs.length) {\n                // Always prefer VP8 as that is the default codec supported on all client types.\n                selectedCodec = nonPreferredCodecs.find(codec => codec === CodecMimeType.VP8)\n                    ?? nonPreferredCodecs.find(codec => this._isCodecSupported(codec));\n            }\n        }\n        if (selectedCodec !== currentCodec || !session?.peerconnection.isVideoCodecDisabled(disabledCodec)) {\n            session.setVideoCodecs(selectedCodec, disabledCodec);\n        }\n    }\n\n    /**\n     * Returns the preferred codec for the conference. The preferred codec for the JVB media session\n     * is the one that gets published in presence and a comparision is made whenever a participant joins\n     * or leaves the call.\n     *\n     * @returns {CodecMimeType} preferred codec.\n     */\n    getPreferredCodec() {\n        return this.jvbPreferredCodec;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport { createBridgeChannelClosedEvent } from '../../service/statistics/AnalyticsEvents';\nimport Statistics from '../statistics/statistics';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\n\nconst logger = getLogger(__filename);\n\n/**\n * Handles a WebRTC RTCPeerConnection or a WebSocket instance to communicate\n * with the videobridge.\n */\nexport default class BridgeChannel {\n    /**\n     * Binds \"ondatachannel\" event listener on the given RTCPeerConnection\n     * instance, or creates a WebSocket connection with the videobridge.\n     * At least one of both, peerconnection or wsUrl parameters, must be\n     * given.\n     * @param {RTCPeerConnection} [peerconnection] WebRTC peer connection\n     * instance.\n     * @param {string} [wsUrl] WebSocket URL.\n     * @param {EventEmitter} emitter the EventEmitter instance to use for event emission.\n     * @param {JitsiConference} conference the conference instance.\n     */\n    constructor(peerconnection, wsUrl, emitter, conference) {\n        if (!peerconnection && !wsUrl) {\n            throw new TypeError('At least peerconnection or wsUrl must be given');\n        } else if (peerconnection && wsUrl) {\n            throw new TypeError('Just one of peerconnection or wsUrl must be given');\n        }\n\n        if (peerconnection) {\n            logger.debug('constructor() with peerconnection');\n        } else {\n            logger.debug(`constructor() with wsUrl:\"${wsUrl}\"`);\n        }\n\n        // The underlying WebRTC RTCDataChannel or WebSocket instance.\n        // @type {RTCDataChannel|WebSocket}\n        this._channel = null;\n\n        // The conference that uses this bridge channel.\n        this._conference = conference;\n\n        // Whether the channel is connected or not. It will start as undefined\n        // for the first connection attempt. Then transition to either true or false.\n        this._connected = undefined;\n\n        // @type {EventEmitter}\n        this._eventEmitter = emitter;\n\n        // Whether a RTCDataChannel or WebSocket is internally used.\n        // @type {string} \"datachannel\" / \"websocket\"\n        this._mode = null;\n\n        // Indicates whether the connection retries are enabled or not.\n        this._areRetriesEnabled = false;\n\n        // Indicates whether the connection was closed from the client or not.\n        this._closedFromClient = false;\n\n        // If a RTCPeerConnection is given, listen for new RTCDataChannel\n        // event.\n        if (peerconnection) {\n            const datachannel\n                = peerconnection.createDataChannel(\n                    'JVB data channel', {\n                        protocol: 'http://jitsi.org/protocols/colibri'\n                    });\n\n            // Handle the RTCDataChannel.\n            this._handleChannel(datachannel);\n            this._mode = 'datachannel';\n\n        // Otherwise create a WebSocket connection.\n        } else if (wsUrl) {\n            this._areRetriesEnabled = true;\n            this._wsUrl = wsUrl;\n            this._initWebSocket();\n        }\n    }\n\n    /**\n     * Initializes the web socket channel.\n     *\n     * @returns {void}\n     */\n    _initWebSocket() {\n        // Create a WebSocket instance.\n        const ws = new WebSocket(this._wsUrl);\n\n        // Handle the WebSocket.\n        this._handleChannel(ws);\n        this._mode = 'websocket';\n    }\n\n    /**\n     * Starts the websocket connection retries.\n     *\n     * @returns {void}\n     */\n    _startConnectionRetries() {\n        let timeoutS = 1;\n\n        const reload = () => {\n            const isConnecting = this._channel && (this._channel.readyState === 'connecting'\n                    || this._channel.readyState === WebSocket.CONNECTING);\n\n            // Should not spawn new websockets while one is already trying to connect.\n            if (isConnecting) {\n                // Timeout is still required as there is flag `_areRetriesEnabled` that\n                // blocks new retrying cycles until any channel opens in current cycle.\n                this._retryTimeout = setTimeout(reload, timeoutS * 1000);\n\n                return;\n            }\n\n            if (this.isOpen()) {\n                return;\n            }\n            this._initWebSocket(this._wsUrl);\n            timeoutS = Math.min(timeoutS * 2, 60);\n            this._retryTimeout = setTimeout(reload, timeoutS * 1000);\n        };\n\n        this._retryTimeout = setTimeout(reload, timeoutS * 1000);\n    }\n\n    /**\n     * Stops the websocket connection retries.\n     *\n     * @returns {void}\n     */\n    _stopConnectionRetries() {\n        if (this._retryTimeout) {\n            clearTimeout(this._retryTimeout);\n            this._retryTimeout = undefined;\n        }\n    }\n\n    /**\n     * Retries to establish the websocket connection after the connection was closed by the server.\n     *\n     * @param {CloseEvent} closeEvent - The close event that triggered the retries.\n     * @returns {void}\n     */\n    _retryWebSocketConnection(closeEvent) {\n        if (!this._areRetriesEnabled) {\n            return;\n        }\n        const { code, reason } = closeEvent;\n\n        Statistics.sendAnalytics(createBridgeChannelClosedEvent(code, reason));\n        this._areRetriesEnabled = false;\n        this._eventEmitter.once(RTCEvents.DATA_CHANNEL_OPEN, () => {\n            this._stopConnectionRetries();\n            this._areRetriesEnabled = true;\n        });\n        this._startConnectionRetries();\n    }\n\n    /**\n     * The channel mode.\n     * @return {string} \"datachannel\" or \"websocket\" (or null if not yet set).\n     */\n    get mode() {\n        return this._mode;\n    }\n\n    /**\n     * Closes the currently opened channel.\n     */\n    close() {\n        this._closedFromClient = true;\n        this._stopConnectionRetries();\n        this._areRetriesEnabled = false;\n        if (this._channel) {\n            try {\n                this._channel.close();\n            } catch (error) {} // eslint-disable-line no-empty\n\n            this._channel = null;\n        }\n    }\n\n    /**\n     * Whether there is an underlying RTCDataChannel or WebSocket and it's\n     * open.\n     * @return {boolean}\n     */\n    isOpen() {\n        return this._channel && (this._channel.readyState === 'open'\n            || this._channel.readyState === WebSocket.OPEN);\n    }\n\n    /**\n     * Sends local stats via the bridge channel.\n     * @param {Object} payload The payload of the message.\n     * @throws NetworkError/InvalidStateError/Error if the operation fails or if there is no data channel created.\n     */\n    sendEndpointStatsMessage(payload) {\n        this._send({\n            colibriClass: 'EndpointStats',\n            ...payload\n        });\n    }\n\n    /**\n     * Sends message via the channel.\n     * @param {string} to The id of the endpoint that should receive the\n     * message. If \"\" the message will be sent to all participants.\n     * @param  {object} payload The payload of the message.\n     * @throws NetworkError or InvalidStateError from RTCDataChannel#send (@see\n     * {@link https://developer.mozilla.org/docs/Web/API/RTCDataChannel/send})\n     * or from WebSocket#send or Error with \"No opened channel\" message.\n     */\n    sendMessage(to, payload) {\n        this._send({\n            colibriClass: 'EndpointMessage',\n            msgPayload: payload,\n            to\n        });\n    }\n\n    /**\n     * Sends a \"lastN value changed\" message via the channel.\n     * @param {number} value The new value for lastN. -1 means unlimited.\n     */\n    sendSetLastNMessage(value) {\n        logger.log(`Sending lastN=${value}.`);\n\n        this._send({\n            colibriClass: 'LastNChangedEvent',\n            lastN: value\n        });\n    }\n\n    /**\n     * Sends a 'ReceiverVideoConstraints' message via the bridge channel.\n     *\n     * @param {ReceiverVideoConstraints} constraints video constraints.\n     */\n    sendReceiverVideoConstraintsMessage(constraints) {\n        logger.log(`Sending ReceiverVideoConstraints with ${JSON.stringify(constraints)}`);\n        this._send({\n            colibriClass: 'ReceiverVideoConstraints',\n            ...constraints\n        });\n    }\n\n    /**\n     * Sends a 'SourceVideoTypeMessage' message via the bridge channel.\n     *\n     * @param {BridgeVideoType} videoType - the video type.\n     * @param {SourceName} sourceName - the source name of the video track.\n     * @returns {void}\n     */\n    sendSourceVideoTypeMessage(sourceName, videoType) {\n        logger.info(`Sending SourceVideoTypeMessage with video type ${sourceName}: ${videoType}`);\n        this._send({\n            colibriClass: 'SourceVideoTypeMessage',\n            sourceName,\n            videoType\n        });\n    }\n\n    /**\n     * Set events on the given RTCDataChannel or WebSocket instance.\n     */\n    _handleChannel(channel) {\n        const emitter = this._eventEmitter;\n\n        channel.onopen = () => {\n            logger.info(`${this._mode} channel opened`);\n\n            this._connected = true;\n\n            emitter.emit(RTCEvents.DATA_CHANNEL_OPEN);\n        };\n\n        channel.onerror = event => {\n            // WS error events contain no information about the failure (this is available in the onclose event) and\n            // the event references the WS object itself, which causes hangs on mobile.\n            if (this._mode !== 'websocket') {\n                logger.error(`Channel error: ${event.message}`);\n            }\n        };\n\n        channel.onmessage = ({ data }) => {\n            // JSON object.\n            let obj;\n\n            try {\n                obj = JSON.parse(data);\n            } catch (error) {\n                GlobalOnErrorHandler.callErrorHandler(error);\n                logger.error('Failed to parse channel message as JSON: ', data, error);\n\n                return;\n            }\n\n            const colibriClass = obj.colibriClass;\n\n            switch (colibriClass) {\n            case 'DominantSpeakerEndpointChangeEvent': {\n                const { dominantSpeakerEndpoint, previousSpeakers = [], silence } = obj;\n\n                logger.debug(`Dominant speaker: ${dominantSpeakerEndpoint}, previous speakers: ${previousSpeakers}`);\n                emitter.emit(RTCEvents.DOMINANT_SPEAKER_CHANGED, dominantSpeakerEndpoint, previousSpeakers, silence);\n                break;\n            }\n            case 'EndpointConnectivityStatusChangeEvent': {\n                const endpoint = obj.endpoint;\n                const isActive = obj.active === 'true';\n\n                logger.info(`Endpoint connection status changed: ${endpoint} active=${isActive}`);\n                emitter.emit(RTCEvents.ENDPOINT_CONN_STATUS_CHANGED, endpoint, isActive);\n\n                break;\n            }\n            case 'EndpointMessage': {\n                emitter.emit(RTCEvents.ENDPOINT_MESSAGE_RECEIVED, obj.from, obj.msgPayload);\n\n                break;\n            }\n            case 'EndpointStats': {\n                emitter.emit(RTCEvents.ENDPOINT_STATS_RECEIVED, obj.from, obj);\n\n                break;\n            }\n            case 'ForwardedSources': {\n                const forwardedSources = obj.forwardedSources;\n\n                logger.info(`New forwarded sources: ${forwardedSources}`);\n                emitter.emit(RTCEvents.FORWARDED_SOURCES_CHANGED, forwardedSources);\n\n                break;\n            }\n            case 'SenderSourceConstraints': {\n                if (typeof obj.sourceName === 'string' && typeof obj.maxHeight === 'number') {\n                    logger.info(`SenderSourceConstraints: ${obj.sourceName} - ${obj.maxHeight}`);\n                    emitter.emit(RTCEvents.SENDER_VIDEO_CONSTRAINTS_CHANGED, obj);\n                } else {\n                    logger.error(`Invalid SenderSourceConstraints: ${obj.sourceName} - ${obj.maxHeight}`);\n                }\n                break;\n            }\n            case 'ServerHello': {\n                logger.info(`Received ServerHello, version=${obj.version}.`);\n                break;\n            }\n            case 'VideoSourcesMap': {\n                logger.info(`Received VideoSourcesMap: ${JSON.stringify(obj.mappedSources)}`);\n                emitter.emit(RTCEvents.VIDEO_SSRCS_REMAPPED, obj);\n                break;\n            }\n            case 'AudioSourcesMap': {\n                logger.info(`Received AudioSourcesMap: ${JSON.stringify(obj.mappedSources)}`);\n                emitter.emit(RTCEvents.AUDIO_SSRCS_REMAPPED, obj);\n                break;\n            }\n            default: {\n                logger.debug('Channel JSON-formatted message: ', obj);\n\n                // The received message appears to be appropriately formatted\n                // (i.e. is a JSON object which assigns a value to the\n                // mandatory property colibriClass) so don't just swallow it,\n                // expose it to public consumption.\n                emitter.emit(`rtc.datachannel.${colibriClass}`, obj);\n            }\n            }\n        };\n\n        channel.onclose = event => {\n            logger.debug(`Channel closed by ${this._closedFromClient ? 'client' : 'server'}`);\n\n            if (channel !== this._channel) {\n                logger.debug('Skip close handler, channel instance is not equal to stored one');\n\n                return;\n            }\n\n            // When the JVB closes the connection gracefully due to the participant being alone in the meeting it uses\n            // code 1001. However, the same code is also used by Cloudflare when it terminates the ws. Therefore, check\n            // for the number of remote participants in the call and abort retries only when the endpoint is the only\n            // endpoint in the call.\n            const isGracefulClose = this._closedFromClient\n                || (event.code === 1001 && this._conference.getParticipantCount() === 1);\n\n            if (!isGracefulClose) {\n                const { code, reason } = event;\n\n                logger.error(`Channel closed: ${code} ${reason}`);\n\n                if (this._mode === 'websocket') {\n                    this._retryWebSocketConnection(event);\n\n                    // We only want to send this event the first time the failure happens.\n                    if (this._connected !== false) {\n                        emitter.emit(RTCEvents.DATA_CHANNEL_CLOSED, {\n                            code,\n                            reason\n                        });\n                    }\n                }\n            }\n\n            this._connected = false;\n\n            // Remove the channel.\n            this._channel = null;\n        };\n\n        // Store the channel.\n        this._channel = channel;\n    }\n\n    /**\n     * Sends passed object via the channel.\n     * @param {object} jsonObject The object that will be sent.\n     * @throws NetworkError or InvalidStateError from RTCDataChannel#send (@see\n     * {@link https://developer.mozilla.org/docs/Web/API/RTCDataChannel/send})\n     * or from WebSocket#send or Error with \"No opened channel\" message.\n     */\n    _send(jsonObject) {\n        const channel = this._channel;\n\n        if (!this.isOpen()) {\n            logger.error('Bridge Channel send: no opened channel.');\n            throw new Error('No opened channel');\n        }\n\n        channel.send(JSON.stringify(jsonObject));\n    }\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n /* eslint-env node */\n'use strict';\n\nlet logDisabled_ = true;\nlet deprecationWarnings_ = true;\n\n/**\n * Extract browser version out of the provided user agent string.\n *\n * @param {!string} uastring userAgent string.\n * @param {!string} expr Regular expression used as match criteria.\n * @param {!number} pos position in the version string to be returned.\n * @return {!number} browser version.\n */\nexport function extractVersion(uastring, expr, pos) {\n  const match = uastring.match(expr);\n  return match && match.length >= pos && parseInt(match[pos], 10);\n}\n\n// Wraps the peerconnection event eventNameToWrap in a function\n// which returns the modified event object (or false to prevent\n// the event).\nexport function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) {\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n  const proto = window.RTCPeerConnection.prototype;\n  const nativeAddEventListener = proto.addEventListener;\n  proto.addEventListener = function(nativeEventName, cb) {\n    if (nativeEventName !== eventNameToWrap) {\n      return nativeAddEventListener.apply(this, arguments);\n    }\n    const wrappedCallback = (e) => {\n      const modifiedEvent = wrapper(e);\n      if (modifiedEvent) {\n        if (cb.handleEvent) {\n          cb.handleEvent(modifiedEvent);\n        } else {\n          cb(modifiedEvent);\n        }\n      }\n    };\n    this._eventMap = this._eventMap || {};\n    if (!this._eventMap[eventNameToWrap]) {\n      this._eventMap[eventNameToWrap] = new Map();\n    }\n    this._eventMap[eventNameToWrap].set(cb, wrappedCallback);\n    return nativeAddEventListener.apply(this, [nativeEventName,\n      wrappedCallback]);\n  };\n\n  const nativeRemoveEventListener = proto.removeEventListener;\n  proto.removeEventListener = function(nativeEventName, cb) {\n    if (nativeEventName !== eventNameToWrap || !this._eventMap\n        || !this._eventMap[eventNameToWrap]) {\n      return nativeRemoveEventListener.apply(this, arguments);\n    }\n    if (!this._eventMap[eventNameToWrap].has(cb)) {\n      return nativeRemoveEventListener.apply(this, arguments);\n    }\n    const unwrappedCb = this._eventMap[eventNameToWrap].get(cb);\n    this._eventMap[eventNameToWrap].delete(cb);\n    if (this._eventMap[eventNameToWrap].size === 0) {\n      delete this._eventMap[eventNameToWrap];\n    }\n    if (Object.keys(this._eventMap).length === 0) {\n      delete this._eventMap;\n    }\n    return nativeRemoveEventListener.apply(this, [nativeEventName,\n      unwrappedCb]);\n  };\n\n  Object.defineProperty(proto, 'on' + eventNameToWrap, {\n    get() {\n      return this['_on' + eventNameToWrap];\n    },\n    set(cb) {\n      if (this['_on' + eventNameToWrap]) {\n        this.removeEventListener(eventNameToWrap,\n            this['_on' + eventNameToWrap]);\n        delete this['_on' + eventNameToWrap];\n      }\n      if (cb) {\n        this.addEventListener(eventNameToWrap,\n            this['_on' + eventNameToWrap] = cb);\n      }\n    },\n    enumerable: true,\n    configurable: true\n  });\n}\n\nexport function disableLog(bool) {\n  if (typeof bool !== 'boolean') {\n    return new Error('Argument type: ' + typeof bool +\n        '. Please use a boolean.');\n  }\n  logDisabled_ = bool;\n  return (bool) ? 'adapter.js logging disabled' :\n      'adapter.js logging enabled';\n}\n\n/**\n * Disable or enable deprecation warnings\n * @param {!boolean} bool set to true to disable warnings.\n */\nexport function disableWarnings(bool) {\n  if (typeof bool !== 'boolean') {\n    return new Error('Argument type: ' + typeof bool +\n        '. Please use a boolean.');\n  }\n  deprecationWarnings_ = !bool;\n  return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled');\n}\n\nexport function log() {\n  if (typeof window === 'object') {\n    if (logDisabled_) {\n      return;\n    }\n    if (typeof console !== 'undefined' && typeof console.log === 'function') {\n      console.log.apply(console, arguments);\n    }\n  }\n}\n\n/**\n * Shows a deprecation warning suggesting the modern and spec-compatible API.\n */\nexport function deprecated(oldMethod, newMethod) {\n  if (!deprecationWarnings_) {\n    return;\n  }\n  console.warn(oldMethod + ' is deprecated, please use ' + newMethod +\n      ' instead.');\n}\n\n/**\n * Browser detector.\n *\n * @return {object} result containing browser and version\n *     properties.\n */\nexport function detectBrowser(window) {\n  // Returned result object.\n  const result = {browser: null, version: null};\n\n  // Fail early if it's not a browser\n  if (typeof window === 'undefined' || !window.navigator) {\n    result.browser = 'Not a browser.';\n    return result;\n  }\n\n  const {navigator} = window;\n\n  if (navigator.mozGetUserMedia) { // Firefox.\n    result.browser = 'firefox';\n    result.version = extractVersion(navigator.userAgent,\n        /Firefox\\/(\\d+)\\./, 1);\n  } else if (navigator.webkitGetUserMedia ||\n      (window.isSecureContext === false && window.webkitRTCPeerConnection &&\n       !window.RTCIceGatherer)) {\n    // Chrome, Chromium, Webview, Opera.\n    // Version matches Chrome/WebRTC version.\n    // Chrome 74 removed webkitGetUserMedia on http as well so we need the\n    // more complicated fallback to webkitRTCPeerConnection.\n    result.browser = 'chrome';\n    result.version = extractVersion(navigator.userAgent,\n        /Chrom(e|ium)\\/(\\d+)\\./, 2);\n  } else if (window.RTCPeerConnection &&\n      navigator.userAgent.match(/AppleWebKit\\/(\\d+)\\./)) { // Safari.\n    result.browser = 'safari';\n    result.version = extractVersion(navigator.userAgent,\n        /AppleWebKit\\/(\\d+)\\./, 1);\n    result.supportsUnifiedPlan = window.RTCRtpTransceiver &&\n        'currentDirection' in window.RTCRtpTransceiver.prototype;\n  } else { // Default fallthrough: not supported.\n    result.browser = 'Not a supported browser.';\n    return result;\n  }\n\n  return result;\n}\n\n/**\n * Checks if something is an object.\n *\n * @param {*} val The something you want to check.\n * @return true if val is an object, false otherwise.\n */\nfunction isObject(val) {\n  return Object.prototype.toString.call(val) === '[object Object]';\n}\n\n/**\n * Remove all empty objects and undefined values\n * from a nested object -- an enhanced and vanilla version\n * of Lodash's `compact`.\n */\nexport function compactObject(data) {\n  if (!isObject(data)) {\n    return data;\n  }\n\n  return Object.keys(data).reduce(function(accumulator, key) {\n    const isObj = isObject(data[key]);\n    const value = isObj ? compactObject(data[key]) : data[key];\n    const isEmptyObject = isObj && !Object.keys(value).length;\n    if (value === undefined || isEmptyObject) {\n      return accumulator;\n    }\n    return Object.assign(accumulator, {[key]: value});\n  }, {});\n}\n\n/* iterates the stats graph recursively. */\nexport function walkStats(stats, base, resultSet) {\n  if (!base || resultSet.has(base.id)) {\n    return;\n  }\n  resultSet.set(base.id, base);\n  Object.keys(base).forEach(name => {\n    if (name.endsWith('Id')) {\n      walkStats(stats, stats.get(base[name]), resultSet);\n    } else if (name.endsWith('Ids')) {\n      base[name].forEach(id => {\n        walkStats(stats, stats.get(id), resultSet);\n      });\n    }\n  });\n}\n\n/* filter getStats for a sender/receiver track. */\nexport function filterStats(result, track, outbound) {\n  const streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp';\n  const filteredResult = new Map();\n  if (track === null) {\n    return filteredResult;\n  }\n  const trackStats = [];\n  result.forEach(value => {\n    if (value.type === 'track' &&\n        value.trackIdentifier === track.id) {\n      trackStats.push(value);\n    }\n  });\n  trackStats.forEach(trackStat => {\n    result.forEach(stats => {\n      if (stats.type === streamStatsType && stats.trackId === trackStat.id) {\n        walkStats(result, stats, filteredResult);\n      }\n    });\n  });\n  return filteredResult;\n}\n\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\nimport * as utils from '../utils.js';\nconst logging = utils.log;\n\nexport function shimGetUserMedia(window, browserDetails) {\n  const navigator = window && window.navigator;\n\n  if (!navigator.mediaDevices) {\n    return;\n  }\n\n  const constraintsToChrome_ = function(c) {\n    if (typeof c !== 'object' || c.mandatory || c.optional) {\n      return c;\n    }\n    const cc = {};\n    Object.keys(c).forEach(key => {\n      if (key === 'require' || key === 'advanced' || key === 'mediaSource') {\n        return;\n      }\n      const r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]};\n      if (r.exact !== undefined && typeof r.exact === 'number') {\n        r.min = r.max = r.exact;\n      }\n      const oldname_ = function(prefix, name) {\n        if (prefix) {\n          return prefix + name.charAt(0).toUpperCase() + name.slice(1);\n        }\n        return (name === 'deviceId') ? 'sourceId' : name;\n      };\n      if (r.ideal !== undefined) {\n        cc.optional = cc.optional || [];\n        let oc = {};\n        if (typeof r.ideal === 'number') {\n          oc[oldname_('min', key)] = r.ideal;\n          cc.optional.push(oc);\n          oc = {};\n          oc[oldname_('max', key)] = r.ideal;\n          cc.optional.push(oc);\n        } else {\n          oc[oldname_('', key)] = r.ideal;\n          cc.optional.push(oc);\n        }\n      }\n      if (r.exact !== undefined && typeof r.exact !== 'number') {\n        cc.mandatory = cc.mandatory || {};\n        cc.mandatory[oldname_('', key)] = r.exact;\n      } else {\n        ['min', 'max'].forEach(mix => {\n          if (r[mix] !== undefined) {\n            cc.mandatory = cc.mandatory || {};\n            cc.mandatory[oldname_(mix, key)] = r[mix];\n          }\n        });\n      }\n    });\n    if (c.advanced) {\n      cc.optional = (cc.optional || []).concat(c.advanced);\n    }\n    return cc;\n  };\n\n  const shimConstraints_ = function(constraints, func) {\n    if (browserDetails.version >= 61) {\n      return func(constraints);\n    }\n    constraints = JSON.parse(JSON.stringify(constraints));\n    if (constraints && typeof constraints.audio === 'object') {\n      const remap = function(obj, a, b) {\n        if (a in obj && !(b in obj)) {\n          obj[b] = obj[a];\n          delete obj[a];\n        }\n      };\n      constraints = JSON.parse(JSON.stringify(constraints));\n      remap(constraints.audio, 'autoGainControl', 'googAutoGainControl');\n      remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression');\n      constraints.audio = constraintsToChrome_(constraints.audio);\n    }\n    if (constraints && typeof constraints.video === 'object') {\n      // Shim facingMode for mobile & surface pro.\n      let face = constraints.video.facingMode;\n      face = face && ((typeof face === 'object') ? face : {ideal: face});\n      const getSupportedFacingModeLies = browserDetails.version < 66;\n\n      if ((face && (face.exact === 'user' || face.exact === 'environment' ||\n                    face.ideal === 'user' || face.ideal === 'environment')) &&\n          !(navigator.mediaDevices.getSupportedConstraints &&\n            navigator.mediaDevices.getSupportedConstraints().facingMode &&\n            !getSupportedFacingModeLies)) {\n        delete constraints.video.facingMode;\n        let matches;\n        if (face.exact === 'environment' || face.ideal === 'environment') {\n          matches = ['back', 'rear'];\n        } else if (face.exact === 'user' || face.ideal === 'user') {\n          matches = ['front'];\n        }\n        if (matches) {\n          // Look for matches in label, or use last cam for back (typical).\n          return navigator.mediaDevices.enumerateDevices()\n          .then(devices => {\n            devices = devices.filter(d => d.kind === 'videoinput');\n            let dev = devices.find(d => matches.some(match =>\n              d.label.toLowerCase().includes(match)));\n            if (!dev && devices.length && matches.includes('back')) {\n              dev = devices[devices.length - 1]; // more likely the back cam\n            }\n            if (dev) {\n              constraints.video.deviceId = face.exact ? {exact: dev.deviceId} :\n                                                        {ideal: dev.deviceId};\n            }\n            constraints.video = constraintsToChrome_(constraints.video);\n            logging('chrome: ' + JSON.stringify(constraints));\n            return func(constraints);\n          });\n        }\n      }\n      constraints.video = constraintsToChrome_(constraints.video);\n    }\n    logging('chrome: ' + JSON.stringify(constraints));\n    return func(constraints);\n  };\n\n  const shimError_ = function(e) {\n    if (browserDetails.version >= 64) {\n      return e;\n    }\n    return {\n      name: {\n        PermissionDeniedError: 'NotAllowedError',\n        PermissionDismissedError: 'NotAllowedError',\n        InvalidStateError: 'NotAllowedError',\n        DevicesNotFoundError: 'NotFoundError',\n        ConstraintNotSatisfiedError: 'OverconstrainedError',\n        TrackStartError: 'NotReadableError',\n        MediaDeviceFailedDueToShutdown: 'NotAllowedError',\n        MediaDeviceKillSwitchOn: 'NotAllowedError',\n        TabCaptureError: 'AbortError',\n        ScreenCaptureError: 'AbortError',\n        DeviceCaptureError: 'AbortError'\n      }[e.name] || e.name,\n      message: e.message,\n      constraint: e.constraint || e.constraintName,\n      toString() {\n        return this.name + (this.message && ': ') + this.message;\n      }\n    };\n  };\n\n  const getUserMedia_ = function(constraints, onSuccess, onError) {\n    shimConstraints_(constraints, c => {\n      navigator.webkitGetUserMedia(c, onSuccess, e => {\n        if (onError) {\n          onError(shimError_(e));\n        }\n      });\n    });\n  };\n  navigator.getUserMedia = getUserMedia_.bind(navigator);\n\n  // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia\n  // function which returns a Promise, it does not accept spec-style\n  // constraints.\n  if (navigator.mediaDevices.getUserMedia) {\n    const origGetUserMedia = navigator.mediaDevices.getUserMedia.\n        bind(navigator.mediaDevices);\n    navigator.mediaDevices.getUserMedia = function(cs) {\n      return shimConstraints_(cs, c => origGetUserMedia(c).then(stream => {\n        if (c.audio && !stream.getAudioTracks().length ||\n            c.video && !stream.getVideoTracks().length) {\n          stream.getTracks().forEach(track => {\n            track.stop();\n          });\n          throw new DOMException('', 'NotFoundError');\n        }\n        return stream;\n      }, e => Promise.reject(shimError_(e))));\n    };\n  }\n}\n","/*\n *  Copyright (c) 2018 The adapter.js project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\nexport function shimGetDisplayMedia(window, getSourceId) {\n  if (window.navigator.mediaDevices &&\n    'getDisplayMedia' in window.navigator.mediaDevices) {\n    return;\n  }\n  if (!(window.navigator.mediaDevices)) {\n    return;\n  }\n  // getSourceId is a function that returns a promise resolving with\n  // the sourceId of the screen/window/tab to be shared.\n  if (typeof getSourceId !== 'function') {\n    console.error('shimGetDisplayMedia: getSourceId argument is not ' +\n        'a function');\n    return;\n  }\n  window.navigator.mediaDevices.getDisplayMedia =\n    function getDisplayMedia(constraints) {\n      return getSourceId(constraints)\n        .then(sourceId => {\n          const widthSpecified = constraints.video && constraints.video.width;\n          const heightSpecified = constraints.video &&\n            constraints.video.height;\n          const frameRateSpecified = constraints.video &&\n            constraints.video.frameRate;\n          constraints.video = {\n            mandatory: {\n              chromeMediaSource: 'desktop',\n              chromeMediaSourceId: sourceId,\n              maxFrameRate: frameRateSpecified || 3\n            }\n          };\n          if (widthSpecified) {\n            constraints.video.mandatory.maxWidth = widthSpecified;\n          }\n          if (heightSpecified) {\n            constraints.video.mandatory.maxHeight = heightSpecified;\n          }\n          return window.navigator.mediaDevices.getUserMedia(constraints);\n        });\n    };\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n /* eslint-env node */\n'use strict';\nimport * as utils from '../utils.js';\n\nexport {shimGetUserMedia} from './getusermedia';\nexport {shimGetDisplayMedia} from './getdisplaymedia';\n\nexport function shimMediaStream(window) {\n  window.MediaStream = window.MediaStream || window.webkitMediaStream;\n}\n\nexport function shimOnTrack(window) {\n  if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in\n      window.RTCPeerConnection.prototype)) {\n    Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {\n      get() {\n        return this._ontrack;\n      },\n      set(f) {\n        if (this._ontrack) {\n          this.removeEventListener('track', this._ontrack);\n        }\n        this.addEventListener('track', this._ontrack = f);\n      },\n      enumerable: true,\n      configurable: true\n    });\n    const origSetRemoteDescription =\n        window.RTCPeerConnection.prototype.setRemoteDescription;\n    window.RTCPeerConnection.prototype.setRemoteDescription =\n      function setRemoteDescription() {\n        if (!this._ontrackpoly) {\n          this._ontrackpoly = (e) => {\n            // onaddstream does not fire when a track is added to an existing\n            // stream. But stream.onaddtrack is implemented so we use that.\n            e.stream.addEventListener('addtrack', te => {\n              let receiver;\n              if (window.RTCPeerConnection.prototype.getReceivers) {\n                receiver = this.getReceivers()\n                  .find(r => r.track && r.track.id === te.track.id);\n              } else {\n                receiver = {track: te.track};\n              }\n\n              const event = new Event('track');\n              event.track = te.track;\n              event.receiver = receiver;\n              event.transceiver = {receiver};\n              event.streams = [e.stream];\n              this.dispatchEvent(event);\n            });\n            e.stream.getTracks().forEach(track => {\n              let receiver;\n              if (window.RTCPeerConnection.prototype.getReceivers) {\n                receiver = this.getReceivers()\n                  .find(r => r.track && r.track.id === track.id);\n              } else {\n                receiver = {track};\n              }\n              const event = new Event('track');\n              event.track = track;\n              event.receiver = receiver;\n              event.transceiver = {receiver};\n              event.streams = [e.stream];\n              this.dispatchEvent(event);\n            });\n          };\n          this.addEventListener('addstream', this._ontrackpoly);\n        }\n        return origSetRemoteDescription.apply(this, arguments);\n      };\n  } else {\n    // even if RTCRtpTransceiver is in window, it is only used and\n    // emitted in unified-plan. Unfortunately this means we need\n    // to unconditionally wrap the event.\n    utils.wrapPeerConnectionEvent(window, 'track', e => {\n      if (!e.transceiver) {\n        Object.defineProperty(e, 'transceiver',\n          {value: {receiver: e.receiver}});\n      }\n      return e;\n    });\n  }\n}\n\nexport function shimGetSendersWithDtmf(window) {\n  // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack.\n  if (typeof window === 'object' && window.RTCPeerConnection &&\n      !('getSenders' in window.RTCPeerConnection.prototype) &&\n      'createDTMFSender' in window.RTCPeerConnection.prototype) {\n    const shimSenderWithDtmf = function(pc, track) {\n      return {\n        track,\n        get dtmf() {\n          if (this._dtmf === undefined) {\n            if (track.kind === 'audio') {\n              this._dtmf = pc.createDTMFSender(track);\n            } else {\n              this._dtmf = null;\n            }\n          }\n          return this._dtmf;\n        },\n        _pc: pc\n      };\n    };\n\n    // augment addTrack when getSenders is not available.\n    if (!window.RTCPeerConnection.prototype.getSenders) {\n      window.RTCPeerConnection.prototype.getSenders = function getSenders() {\n        this._senders = this._senders || [];\n        return this._senders.slice(); // return a copy of the internal state.\n      };\n      const origAddTrack = window.RTCPeerConnection.prototype.addTrack;\n      window.RTCPeerConnection.prototype.addTrack =\n        function addTrack(track, stream) {\n          let sender = origAddTrack.apply(this, arguments);\n          if (!sender) {\n            sender = shimSenderWithDtmf(this, track);\n            this._senders.push(sender);\n          }\n          return sender;\n        };\n\n      const origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;\n      window.RTCPeerConnection.prototype.removeTrack =\n        function removeTrack(sender) {\n          origRemoveTrack.apply(this, arguments);\n          const idx = this._senders.indexOf(sender);\n          if (idx !== -1) {\n            this._senders.splice(idx, 1);\n          }\n        };\n    }\n    const origAddStream = window.RTCPeerConnection.prototype.addStream;\n    window.RTCPeerConnection.prototype.addStream = function addStream(stream) {\n      this._senders = this._senders || [];\n      origAddStream.apply(this, [stream]);\n      stream.getTracks().forEach(track => {\n        this._senders.push(shimSenderWithDtmf(this, track));\n      });\n    };\n\n    const origRemoveStream = window.RTCPeerConnection.prototype.removeStream;\n    window.RTCPeerConnection.prototype.removeStream =\n      function removeStream(stream) {\n        this._senders = this._senders || [];\n        origRemoveStream.apply(this, [stream]);\n\n        stream.getTracks().forEach(track => {\n          const sender = this._senders.find(s => s.track === track);\n          if (sender) { // remove sender\n            this._senders.splice(this._senders.indexOf(sender), 1);\n          }\n        });\n      };\n  } else if (typeof window === 'object' && window.RTCPeerConnection &&\n             'getSenders' in window.RTCPeerConnection.prototype &&\n             'createDTMFSender' in window.RTCPeerConnection.prototype &&\n             window.RTCRtpSender &&\n             !('dtmf' in window.RTCRtpSender.prototype)) {\n    const origGetSenders = window.RTCPeerConnection.prototype.getSenders;\n    window.RTCPeerConnection.prototype.getSenders = function getSenders() {\n      const senders = origGetSenders.apply(this, []);\n      senders.forEach(sender => sender._pc = this);\n      return senders;\n    };\n\n    Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', {\n      get() {\n        if (this._dtmf === undefined) {\n          if (this.track.kind === 'audio') {\n            this._dtmf = this._pc.createDTMFSender(this.track);\n          } else {\n            this._dtmf = null;\n          }\n        }\n        return this._dtmf;\n      }\n    });\n  }\n}\n\nexport function shimGetStats(window) {\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n\n  const origGetStats = window.RTCPeerConnection.prototype.getStats;\n  window.RTCPeerConnection.prototype.getStats = function getStats() {\n    const [selector, onSucc, onErr] = arguments;\n\n    // If selector is a function then we are in the old style stats so just\n    // pass back the original getStats format to avoid breaking old users.\n    if (arguments.length > 0 && typeof selector === 'function') {\n      return origGetStats.apply(this, arguments);\n    }\n\n    // When spec-style getStats is supported, return those when called with\n    // either no arguments or the selector argument is null.\n    if (origGetStats.length === 0 && (arguments.length === 0 ||\n        typeof selector !== 'function')) {\n      return origGetStats.apply(this, []);\n    }\n\n    const fixChromeStats_ = function(response) {\n      const standardReport = {};\n      const reports = response.result();\n      reports.forEach(report => {\n        const standardStats = {\n          id: report.id,\n          timestamp: report.timestamp,\n          type: {\n            localcandidate: 'local-candidate',\n            remotecandidate: 'remote-candidate'\n          }[report.type] || report.type\n        };\n        report.names().forEach(name => {\n          standardStats[name] = report.stat(name);\n        });\n        standardReport[standardStats.id] = standardStats;\n      });\n\n      return standardReport;\n    };\n\n    // shim getStats with maplike support\n    const makeMapStats = function(stats) {\n      return new Map(Object.keys(stats).map(key => [key, stats[key]]));\n    };\n\n    if (arguments.length >= 2) {\n      const successCallbackWrapper_ = function(response) {\n        onSucc(makeMapStats(fixChromeStats_(response)));\n      };\n\n      return origGetStats.apply(this, [successCallbackWrapper_,\n        selector]);\n    }\n\n    // promise-support\n    return new Promise((resolve, reject) => {\n      origGetStats.apply(this, [\n        function(response) {\n          resolve(makeMapStats(fixChromeStats_(response)));\n        }, reject]);\n    }).then(onSucc, onErr);\n  };\n}\n\nexport function shimSenderReceiverGetStats(window) {\n  if (!(typeof window === 'object' && window.RTCPeerConnection &&\n      window.RTCRtpSender && window.RTCRtpReceiver)) {\n    return;\n  }\n\n  // shim sender stats.\n  if (!('getStats' in window.RTCRtpSender.prototype)) {\n    const origGetSenders = window.RTCPeerConnection.prototype.getSenders;\n    if (origGetSenders) {\n      window.RTCPeerConnection.prototype.getSenders = function getSenders() {\n        const senders = origGetSenders.apply(this, []);\n        senders.forEach(sender => sender._pc = this);\n        return senders;\n      };\n    }\n\n    const origAddTrack = window.RTCPeerConnection.prototype.addTrack;\n    if (origAddTrack) {\n      window.RTCPeerConnection.prototype.addTrack = function addTrack() {\n        const sender = origAddTrack.apply(this, arguments);\n        sender._pc = this;\n        return sender;\n      };\n    }\n    window.RTCRtpSender.prototype.getStats = function getStats() {\n      const sender = this;\n      return this._pc.getStats().then(result =>\n        /* Note: this will include stats of all senders that\n         *   send a track with the same id as sender.track as\n         *   it is not possible to identify the RTCRtpSender.\n         */\n        utils.filterStats(result, sender.track, true));\n    };\n  }\n\n  // shim receiver stats.\n  if (!('getStats' in window.RTCRtpReceiver.prototype)) {\n    const origGetReceivers = window.RTCPeerConnection.prototype.getReceivers;\n    if (origGetReceivers) {\n      window.RTCPeerConnection.prototype.getReceivers =\n        function getReceivers() {\n          const receivers = origGetReceivers.apply(this, []);\n          receivers.forEach(receiver => receiver._pc = this);\n          return receivers;\n        };\n    }\n    utils.wrapPeerConnectionEvent(window, 'track', e => {\n      e.receiver._pc = e.srcElement;\n      return e;\n    });\n    window.RTCRtpReceiver.prototype.getStats = function getStats() {\n      const receiver = this;\n      return this._pc.getStats().then(result =>\n        utils.filterStats(result, receiver.track, false));\n    };\n  }\n\n  if (!('getStats' in window.RTCRtpSender.prototype &&\n      'getStats' in window.RTCRtpReceiver.prototype)) {\n    return;\n  }\n\n  // shim RTCPeerConnection.getStats(track).\n  const origGetStats = window.RTCPeerConnection.prototype.getStats;\n  window.RTCPeerConnection.prototype.getStats = function getStats() {\n    if (arguments.length > 0 &&\n        arguments[0] instanceof window.MediaStreamTrack) {\n      const track = arguments[0];\n      let sender;\n      let receiver;\n      let err;\n      this.getSenders().forEach(s => {\n        if (s.track === track) {\n          if (sender) {\n            err = true;\n          } else {\n            sender = s;\n          }\n        }\n      });\n      this.getReceivers().forEach(r => {\n        if (r.track === track) {\n          if (receiver) {\n            err = true;\n          } else {\n            receiver = r;\n          }\n        }\n        return r.track === track;\n      });\n      if (err || (sender && receiver)) {\n        return Promise.reject(new DOMException(\n          'There are more than one sender or receiver for the track.',\n          'InvalidAccessError'));\n      } else if (sender) {\n        return sender.getStats();\n      } else if (receiver) {\n        return receiver.getStats();\n      }\n      return Promise.reject(new DOMException(\n        'There is no sender or receiver for the track.',\n        'InvalidAccessError'));\n    }\n    return origGetStats.apply(this, arguments);\n  };\n}\n\nexport function shimAddTrackRemoveTrackWithNative(window) {\n  // shim addTrack/removeTrack with native variants in order to make\n  // the interactions with legacy getLocalStreams behave as in other browsers.\n  // Keeps a mapping stream.id => [stream, rtpsenders...]\n  window.RTCPeerConnection.prototype.getLocalStreams =\n    function getLocalStreams() {\n      this._shimmedLocalStreams = this._shimmedLocalStreams || {};\n      return Object.keys(this._shimmedLocalStreams)\n        .map(streamId => this._shimmedLocalStreams[streamId][0]);\n    };\n\n  const origAddTrack = window.RTCPeerConnection.prototype.addTrack;\n  window.RTCPeerConnection.prototype.addTrack =\n    function addTrack(track, stream) {\n      if (!stream) {\n        return origAddTrack.apply(this, arguments);\n      }\n      this._shimmedLocalStreams = this._shimmedLocalStreams || {};\n\n      const sender = origAddTrack.apply(this, arguments);\n      if (!this._shimmedLocalStreams[stream.id]) {\n        this._shimmedLocalStreams[stream.id] = [stream, sender];\n      } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) {\n        this._shimmedLocalStreams[stream.id].push(sender);\n      }\n      return sender;\n    };\n\n  const origAddStream = window.RTCPeerConnection.prototype.addStream;\n  window.RTCPeerConnection.prototype.addStream = function addStream(stream) {\n    this._shimmedLocalStreams = this._shimmedLocalStreams || {};\n\n    stream.getTracks().forEach(track => {\n      const alreadyExists = this.getSenders().find(s => s.track === track);\n      if (alreadyExists) {\n        throw new DOMException('Track already exists.',\n            'InvalidAccessError');\n      }\n    });\n    const existingSenders = this.getSenders();\n    origAddStream.apply(this, arguments);\n    const newSenders = this.getSenders()\n      .filter(newSender => existingSenders.indexOf(newSender) === -1);\n    this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders);\n  };\n\n  const origRemoveStream = window.RTCPeerConnection.prototype.removeStream;\n  window.RTCPeerConnection.prototype.removeStream =\n    function removeStream(stream) {\n      this._shimmedLocalStreams = this._shimmedLocalStreams || {};\n      delete this._shimmedLocalStreams[stream.id];\n      return origRemoveStream.apply(this, arguments);\n    };\n\n  const origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;\n  window.RTCPeerConnection.prototype.removeTrack =\n    function removeTrack(sender) {\n      this._shimmedLocalStreams = this._shimmedLocalStreams || {};\n      if (sender) {\n        Object.keys(this._shimmedLocalStreams).forEach(streamId => {\n          const idx = this._shimmedLocalStreams[streamId].indexOf(sender);\n          if (idx !== -1) {\n            this._shimmedLocalStreams[streamId].splice(idx, 1);\n          }\n          if (this._shimmedLocalStreams[streamId].length === 1) {\n            delete this._shimmedLocalStreams[streamId];\n          }\n        });\n      }\n      return origRemoveTrack.apply(this, arguments);\n    };\n}\n\nexport function shimAddTrackRemoveTrack(window, browserDetails) {\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n  // shim addTrack and removeTrack.\n  if (window.RTCPeerConnection.prototype.addTrack &&\n      browserDetails.version >= 65) {\n    return shimAddTrackRemoveTrackWithNative(window);\n  }\n\n  // also shim pc.getLocalStreams when addTrack is shimmed\n  // to return the original streams.\n  const origGetLocalStreams = window.RTCPeerConnection.prototype\n      .getLocalStreams;\n  window.RTCPeerConnection.prototype.getLocalStreams =\n    function getLocalStreams() {\n      const nativeStreams = origGetLocalStreams.apply(this);\n      this._reverseStreams = this._reverseStreams || {};\n      return nativeStreams.map(stream => this._reverseStreams[stream.id]);\n    };\n\n  const origAddStream = window.RTCPeerConnection.prototype.addStream;\n  window.RTCPeerConnection.prototype.addStream = function addStream(stream) {\n    this._streams = this._streams || {};\n    this._reverseStreams = this._reverseStreams || {};\n\n    stream.getTracks().forEach(track => {\n      const alreadyExists = this.getSenders().find(s => s.track === track);\n      if (alreadyExists) {\n        throw new DOMException('Track already exists.',\n            'InvalidAccessError');\n      }\n    });\n    // Add identity mapping for consistency with addTrack.\n    // Unless this is being used with a stream from addTrack.\n    if (!this._reverseStreams[stream.id]) {\n      const newStream = new window.MediaStream(stream.getTracks());\n      this._streams[stream.id] = newStream;\n      this._reverseStreams[newStream.id] = stream;\n      stream = newStream;\n    }\n    origAddStream.apply(this, [stream]);\n  };\n\n  const origRemoveStream = window.RTCPeerConnection.prototype.removeStream;\n  window.RTCPeerConnection.prototype.removeStream =\n    function removeStream(stream) {\n      this._streams = this._streams || {};\n      this._reverseStreams = this._reverseStreams || {};\n\n      origRemoveStream.apply(this, [(this._streams[stream.id] || stream)]);\n      delete this._reverseStreams[(this._streams[stream.id] ?\n          this._streams[stream.id].id : stream.id)];\n      delete this._streams[stream.id];\n    };\n\n  window.RTCPeerConnection.prototype.addTrack =\n    function addTrack(track, stream) {\n      if (this.signalingState === 'closed') {\n        throw new DOMException(\n          'The RTCPeerConnection\\'s signalingState is \\'closed\\'.',\n          'InvalidStateError');\n      }\n      const streams = [].slice.call(arguments, 1);\n      if (streams.length !== 1 ||\n          !streams[0].getTracks().find(t => t === track)) {\n        // this is not fully correct but all we can manage without\n        // [[associated MediaStreams]] internal slot.\n        throw new DOMException(\n          'The adapter.js addTrack polyfill only supports a single ' +\n          ' stream which is associated with the specified track.',\n          'NotSupportedError');\n      }\n\n      const alreadyExists = this.getSenders().find(s => s.track === track);\n      if (alreadyExists) {\n        throw new DOMException('Track already exists.',\n            'InvalidAccessError');\n      }\n\n      this._streams = this._streams || {};\n      this._reverseStreams = this._reverseStreams || {};\n      const oldStream = this._streams[stream.id];\n      if (oldStream) {\n        // this is using odd Chrome behaviour, use with caution:\n        // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815\n        // Note: we rely on the high-level addTrack/dtmf shim to\n        // create the sender with a dtmf sender.\n        oldStream.addTrack(track);\n\n        // Trigger ONN async.\n        Promise.resolve().then(() => {\n          this.dispatchEvent(new Event('negotiationneeded'));\n        });\n      } else {\n        const newStream = new window.MediaStream([track]);\n        this._streams[stream.id] = newStream;\n        this._reverseStreams[newStream.id] = stream;\n        this.addStream(newStream);\n      }\n      return this.getSenders().find(s => s.track === track);\n    };\n\n  // replace the internal stream id with the external one and\n  // vice versa.\n  function replaceInternalStreamId(pc, description) {\n    let sdp = description.sdp;\n    Object.keys(pc._reverseStreams || []).forEach(internalId => {\n      const externalStream = pc._reverseStreams[internalId];\n      const internalStream = pc._streams[externalStream.id];\n      sdp = sdp.replace(new RegExp(internalStream.id, 'g'),\n          externalStream.id);\n    });\n    return new RTCSessionDescription({\n      type: description.type,\n      sdp\n    });\n  }\n  function replaceExternalStreamId(pc, description) {\n    let sdp = description.sdp;\n    Object.keys(pc._reverseStreams || []).forEach(internalId => {\n      const externalStream = pc._reverseStreams[internalId];\n      const internalStream = pc._streams[externalStream.id];\n      sdp = sdp.replace(new RegExp(externalStream.id, 'g'),\n          internalStream.id);\n    });\n    return new RTCSessionDescription({\n      type: description.type,\n      sdp\n    });\n  }\n  ['createOffer', 'createAnswer'].forEach(function(method) {\n    const nativeMethod = window.RTCPeerConnection.prototype[method];\n    const methodObj = {[method]() {\n      const args = arguments;\n      const isLegacyCall = arguments.length &&\n          typeof arguments[0] === 'function';\n      if (isLegacyCall) {\n        return nativeMethod.apply(this, [\n          (description) => {\n            const desc = replaceInternalStreamId(this, description);\n            args[0].apply(null, [desc]);\n          },\n          (err) => {\n            if (args[1]) {\n              args[1].apply(null, err);\n            }\n          }, arguments[2]\n        ]);\n      }\n      return nativeMethod.apply(this, arguments)\n      .then(description => replaceInternalStreamId(this, description));\n    }};\n    window.RTCPeerConnection.prototype[method] = methodObj[method];\n  });\n\n  const origSetLocalDescription =\n      window.RTCPeerConnection.prototype.setLocalDescription;\n  window.RTCPeerConnection.prototype.setLocalDescription =\n    function setLocalDescription() {\n      if (!arguments.length || !arguments[0].type) {\n        return origSetLocalDescription.apply(this, arguments);\n      }\n      arguments[0] = replaceExternalStreamId(this, arguments[0]);\n      return origSetLocalDescription.apply(this, arguments);\n    };\n\n  // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier\n\n  const origLocalDescription = Object.getOwnPropertyDescriptor(\n      window.RTCPeerConnection.prototype, 'localDescription');\n  Object.defineProperty(window.RTCPeerConnection.prototype,\n      'localDescription', {\n        get() {\n          const description = origLocalDescription.get.apply(this);\n          if (description.type === '') {\n            return description;\n          }\n          return replaceInternalStreamId(this, description);\n        }\n      });\n\n  window.RTCPeerConnection.prototype.removeTrack =\n    function removeTrack(sender) {\n      if (this.signalingState === 'closed') {\n        throw new DOMException(\n          'The RTCPeerConnection\\'s signalingState is \\'closed\\'.',\n          'InvalidStateError');\n      }\n      // We can not yet check for sender instanceof RTCRtpSender\n      // since we shim RTPSender. So we check if sender._pc is set.\n      if (!sender._pc) {\n        throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' +\n            'does not implement interface RTCRtpSender.', 'TypeError');\n      }\n      const isLocal = sender._pc === this;\n      if (!isLocal) {\n        throw new DOMException('Sender was not created by this connection.',\n            'InvalidAccessError');\n      }\n\n      // Search for the native stream the senders track belongs to.\n      this._streams = this._streams || {};\n      let stream;\n      Object.keys(this._streams).forEach(streamid => {\n        const hasTrack = this._streams[streamid].getTracks()\n          .find(track => sender.track === track);\n        if (hasTrack) {\n          stream = this._streams[streamid];\n        }\n      });\n\n      if (stream) {\n        if (stream.getTracks().length === 1) {\n          // if this is the last track of the stream, remove the stream. This\n          // takes care of any shimmed _senders.\n          this.removeStream(this._reverseStreams[stream.id]);\n        } else {\n          // relying on the same odd chrome behaviour as above.\n          stream.removeTrack(sender.track);\n        }\n        this.dispatchEvent(new Event('negotiationneeded'));\n      }\n    };\n}\n\nexport function shimPeerConnection(window, browserDetails) {\n  if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) {\n    // very basic support for old versions.\n    window.RTCPeerConnection = window.webkitRTCPeerConnection;\n  }\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n\n  // shim implicit creation of RTCSessionDescription/RTCIceCandidate\n  if (browserDetails.version < 53) {\n    ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']\n        .forEach(function(method) {\n          const nativeMethod = window.RTCPeerConnection.prototype[method];\n          const methodObj = {[method]() {\n            arguments[0] = new ((method === 'addIceCandidate') ?\n                window.RTCIceCandidate :\n                window.RTCSessionDescription)(arguments[0]);\n            return nativeMethod.apply(this, arguments);\n          }};\n          window.RTCPeerConnection.prototype[method] = methodObj[method];\n        });\n  }\n}\n\n// Attempt to fix ONN in plan-b mode.\nexport function fixNegotiationNeeded(window, browserDetails) {\n  utils.wrapPeerConnectionEvent(window, 'negotiationneeded', e => {\n    const pc = e.target;\n    if (browserDetails.version < 72 || (pc.getConfiguration &&\n        pc.getConfiguration().sdpSemantics === 'plan-b')) {\n      if (pc.signalingState !== 'stable') {\n        return;\n      }\n    }\n    return e;\n  });\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\n\nimport * as utils from '../utils';\n\nexport function shimGetUserMedia(window, browserDetails) {\n  const navigator = window && window.navigator;\n  const MediaStreamTrack = window && window.MediaStreamTrack;\n\n  navigator.getUserMedia = function(constraints, onSuccess, onError) {\n    // Replace Firefox 44+'s deprecation warning with unprefixed version.\n    utils.deprecated('navigator.getUserMedia',\n        'navigator.mediaDevices.getUserMedia');\n    navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);\n  };\n\n  if (!(browserDetails.version > 55 &&\n      'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) {\n    const remap = function(obj, a, b) {\n      if (a in obj && !(b in obj)) {\n        obj[b] = obj[a];\n        delete obj[a];\n      }\n    };\n\n    const nativeGetUserMedia = navigator.mediaDevices.getUserMedia.\n        bind(navigator.mediaDevices);\n    navigator.mediaDevices.getUserMedia = function(c) {\n      if (typeof c === 'object' && typeof c.audio === 'object') {\n        c = JSON.parse(JSON.stringify(c));\n        remap(c.audio, 'autoGainControl', 'mozAutoGainControl');\n        remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression');\n      }\n      return nativeGetUserMedia(c);\n    };\n\n    if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) {\n      const nativeGetSettings = MediaStreamTrack.prototype.getSettings;\n      MediaStreamTrack.prototype.getSettings = function() {\n        const obj = nativeGetSettings.apply(this, arguments);\n        remap(obj, 'mozAutoGainControl', 'autoGainControl');\n        remap(obj, 'mozNoiseSuppression', 'noiseSuppression');\n        return obj;\n      };\n    }\n\n    if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) {\n      const nativeApplyConstraints =\n        MediaStreamTrack.prototype.applyConstraints;\n      MediaStreamTrack.prototype.applyConstraints = function(c) {\n        if (this.kind === 'audio' && typeof c === 'object') {\n          c = JSON.parse(JSON.stringify(c));\n          remap(c, 'autoGainControl', 'mozAutoGainControl');\n          remap(c, 'noiseSuppression', 'mozNoiseSuppression');\n        }\n        return nativeApplyConstraints.apply(this, [c]);\n      };\n    }\n  }\n}\n","/*\n *  Copyright (c) 2018 The adapter.js project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\n\nexport function shimGetDisplayMedia(window, preferredMediaSource) {\n  if (window.navigator.mediaDevices &&\n    'getDisplayMedia' in window.navigator.mediaDevices) {\n    return;\n  }\n  if (!(window.navigator.mediaDevices)) {\n    return;\n  }\n  window.navigator.mediaDevices.getDisplayMedia =\n    function getDisplayMedia(constraints) {\n      if (!(constraints && constraints.video)) {\n        const err = new DOMException('getDisplayMedia without video ' +\n            'constraints is undefined');\n        err.name = 'NotFoundError';\n        // from https://heycam.github.io/webidl/#idl-DOMException-error-names\n        err.code = 8;\n        return Promise.reject(err);\n      }\n      if (constraints.video === true) {\n        constraints.video = {mediaSource: preferredMediaSource};\n      } else {\n        constraints.video.mediaSource = preferredMediaSource;\n      }\n      return window.navigator.mediaDevices.getUserMedia(constraints);\n    };\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\n\nimport * as utils from '../utils';\nexport {shimGetUserMedia} from './getusermedia';\nexport {shimGetDisplayMedia} from './getdisplaymedia';\n\nexport function shimOnTrack(window) {\n  if (typeof window === 'object' && window.RTCTrackEvent &&\n      ('receiver' in window.RTCTrackEvent.prototype) &&\n      !('transceiver' in window.RTCTrackEvent.prototype)) {\n    Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', {\n      get() {\n        return {receiver: this.receiver};\n      }\n    });\n  }\n}\n\nexport function shimPeerConnection(window, browserDetails) {\n  if (typeof window !== 'object' ||\n      !(window.RTCPeerConnection || window.mozRTCPeerConnection)) {\n    return; // probably media.peerconnection.enabled=false in about:config\n  }\n  if (!window.RTCPeerConnection && window.mozRTCPeerConnection) {\n    // very basic support for old versions.\n    window.RTCPeerConnection = window.mozRTCPeerConnection;\n  }\n\n  if (browserDetails.version < 53) {\n    // shim away need for obsolete RTCIceCandidate/RTCSessionDescription.\n    ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']\n        .forEach(function(method) {\n          const nativeMethod = window.RTCPeerConnection.prototype[method];\n          const methodObj = {[method]() {\n            arguments[0] = new ((method === 'addIceCandidate') ?\n                window.RTCIceCandidate :\n                window.RTCSessionDescription)(arguments[0]);\n            return nativeMethod.apply(this, arguments);\n          }};\n          window.RTCPeerConnection.prototype[method] = methodObj[method];\n        });\n  }\n\n  const modernStatsTypes = {\n    inboundrtp: 'inbound-rtp',\n    outboundrtp: 'outbound-rtp',\n    candidatepair: 'candidate-pair',\n    localcandidate: 'local-candidate',\n    remotecandidate: 'remote-candidate'\n  };\n\n  const nativeGetStats = window.RTCPeerConnection.prototype.getStats;\n  window.RTCPeerConnection.prototype.getStats = function getStats() {\n    const [selector, onSucc, onErr] = arguments;\n    return nativeGetStats.apply(this, [selector || null])\n      .then(stats => {\n        if (browserDetails.version < 53 && !onSucc) {\n          // Shim only promise getStats with spec-hyphens in type names\n          // Leave callback version alone; misc old uses of forEach before Map\n          try {\n            stats.forEach(stat => {\n              stat.type = modernStatsTypes[stat.type] || stat.type;\n            });\n          } catch (e) {\n            if (e.name !== 'TypeError') {\n              throw e;\n            }\n            // Avoid TypeError: \"type\" is read-only, in old versions. 34-43ish\n            stats.forEach((stat, i) => {\n              stats.set(i, Object.assign({}, stat, {\n                type: modernStatsTypes[stat.type] || stat.type\n              }));\n            });\n          }\n        }\n        return stats;\n      })\n      .then(onSucc, onErr);\n  };\n}\n\nexport function shimSenderGetStats(window) {\n  if (!(typeof window === 'object' && window.RTCPeerConnection &&\n      window.RTCRtpSender)) {\n    return;\n  }\n  if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) {\n    return;\n  }\n  const origGetSenders = window.RTCPeerConnection.prototype.getSenders;\n  if (origGetSenders) {\n    window.RTCPeerConnection.prototype.getSenders = function getSenders() {\n      const senders = origGetSenders.apply(this, []);\n      senders.forEach(sender => sender._pc = this);\n      return senders;\n    };\n  }\n\n  const origAddTrack = window.RTCPeerConnection.prototype.addTrack;\n  if (origAddTrack) {\n    window.RTCPeerConnection.prototype.addTrack = function addTrack() {\n      const sender = origAddTrack.apply(this, arguments);\n      sender._pc = this;\n      return sender;\n    };\n  }\n  window.RTCRtpSender.prototype.getStats = function getStats() {\n    return this.track ? this._pc.getStats(this.track) :\n        Promise.resolve(new Map());\n  };\n}\n\nexport function shimReceiverGetStats(window) {\n  if (!(typeof window === 'object' && window.RTCPeerConnection &&\n      window.RTCRtpSender)) {\n    return;\n  }\n  if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) {\n    return;\n  }\n  const origGetReceivers = window.RTCPeerConnection.prototype.getReceivers;\n  if (origGetReceivers) {\n    window.RTCPeerConnection.prototype.getReceivers = function getReceivers() {\n      const receivers = origGetReceivers.apply(this, []);\n      receivers.forEach(receiver => receiver._pc = this);\n      return receivers;\n    };\n  }\n  utils.wrapPeerConnectionEvent(window, 'track', e => {\n    e.receiver._pc = e.srcElement;\n    return e;\n  });\n  window.RTCRtpReceiver.prototype.getStats = function getStats() {\n    return this._pc.getStats(this.track);\n  };\n}\n\nexport function shimRemoveStream(window) {\n  if (!window.RTCPeerConnection ||\n      'removeStream' in window.RTCPeerConnection.prototype) {\n    return;\n  }\n  window.RTCPeerConnection.prototype.removeStream =\n    function removeStream(stream) {\n      utils.deprecated('removeStream', 'removeTrack');\n      this.getSenders().forEach(sender => {\n        if (sender.track && stream.getTracks().includes(sender.track)) {\n          this.removeTrack(sender);\n        }\n      });\n    };\n}\n\nexport function shimRTCDataChannel(window) {\n  // rename DataChannel to RTCDataChannel (native fix in FF60):\n  // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851\n  if (window.DataChannel && !window.RTCDataChannel) {\n    window.RTCDataChannel = window.DataChannel;\n  }\n}\n\nexport function shimAddTransceiver(window) {\n  // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647\n  // Firefox ignores the init sendEncodings options passed to addTransceiver\n  // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918\n  if (!(typeof window === 'object' && window.RTCPeerConnection)) {\n    return;\n  }\n  const origAddTransceiver = window.RTCPeerConnection.prototype.addTransceiver;\n  if (origAddTransceiver) {\n    window.RTCPeerConnection.prototype.addTransceiver =\n      function addTransceiver() {\n        this.setParametersPromises = [];\n        const initParameters = arguments[1];\n        const shouldPerformCheck = initParameters &&\n                                  'sendEncodings' in initParameters;\n        if (shouldPerformCheck) {\n          // If sendEncodings params are provided, validate grammar\n          initParameters.sendEncodings.forEach((encodingParam) => {\n            if ('rid' in encodingParam) {\n              const ridRegex = /^[a-z0-9]{0,16}$/i;\n              if (!ridRegex.test(encodingParam.rid)) {\n                throw new TypeError('Invalid RID value provided.');\n              }\n            }\n            if ('scaleResolutionDownBy' in encodingParam) {\n              if (!(parseFloat(encodingParam.scaleResolutionDownBy) >= 1.0)) {\n                throw new RangeError('scale_resolution_down_by must be >= 1.0');\n              }\n            }\n            if ('maxFramerate' in encodingParam) {\n              if (!(parseFloat(encodingParam.maxFramerate) >= 0)) {\n                throw new RangeError('max_framerate must be >= 0.0');\n              }\n            }\n          });\n        }\n        const transceiver = origAddTransceiver.apply(this, arguments);\n        if (shouldPerformCheck) {\n          // Check if the init options were applied. If not we do this in an\n          // asynchronous way and save the promise reference in a global object.\n          // This is an ugly hack, but at the same time is way more robust than\n          // checking the sender parameters before and after the createOffer\n          // Also note that after the createoffer we are not 100% sure that\n          // the params were asynchronously applied so we might miss the\n          // opportunity to recreate offer.\n          const {sender} = transceiver;\n          const params = sender.getParameters();\n          if (!('encodings' in params) ||\n              // Avoid being fooled by patched getParameters() below.\n              (params.encodings.length === 1 &&\n               Object.keys(params.encodings[0]).length === 0)) {\n            params.encodings = initParameters.sendEncodings;\n            sender.sendEncodings = initParameters.sendEncodings;\n            this.setParametersPromises.push(sender.setParameters(params)\n              .then(() => {\n                delete sender.sendEncodings;\n              }).catch(() => {\n                delete sender.sendEncodings;\n              })\n            );\n          }\n        }\n        return transceiver;\n      };\n  }\n}\n\nexport function shimGetParameters(window) {\n  if (!(typeof window === 'object' && window.RTCRtpSender)) {\n    return;\n  }\n  const origGetParameters = window.RTCRtpSender.prototype.getParameters;\n  if (origGetParameters) {\n    window.RTCRtpSender.prototype.getParameters =\n      function getParameters() {\n        const params = origGetParameters.apply(this, arguments);\n        if (!('encodings' in params)) {\n          params.encodings = [].concat(this.sendEncodings || [{}]);\n        }\n        return params;\n      };\n  }\n}\n\nexport function shimCreateOffer(window) {\n  // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647\n  // Firefox ignores the init sendEncodings options passed to addTransceiver\n  // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918\n  if (!(typeof window === 'object' && window.RTCPeerConnection)) {\n    return;\n  }\n  const origCreateOffer = window.RTCPeerConnection.prototype.createOffer;\n  window.RTCPeerConnection.prototype.createOffer = function createOffer() {\n    if (this.setParametersPromises && this.setParametersPromises.length) {\n      return Promise.all(this.setParametersPromises)\n      .then(() => {\n        return origCreateOffer.apply(this, arguments);\n      })\n      .finally(() => {\n        this.setParametersPromises = [];\n      });\n    }\n    return origCreateOffer.apply(this, arguments);\n  };\n}\n\nexport function shimCreateAnswer(window) {\n  // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647\n  // Firefox ignores the init sendEncodings options passed to addTransceiver\n  // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918\n  if (!(typeof window === 'object' && window.RTCPeerConnection)) {\n    return;\n  }\n  const origCreateAnswer = window.RTCPeerConnection.prototype.createAnswer;\n  window.RTCPeerConnection.prototype.createAnswer = function createAnswer() {\n    if (this.setParametersPromises && this.setParametersPromises.length) {\n      return Promise.all(this.setParametersPromises)\n      .then(() => {\n        return origCreateAnswer.apply(this, arguments);\n      })\n      .finally(() => {\n        this.setParametersPromises = [];\n      });\n    }\n    return origCreateAnswer.apply(this, arguments);\n  };\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n'use strict';\nimport * as utils from '../utils';\n\nexport function shimLocalStreamsAPI(window) {\n  if (typeof window !== 'object' || !window.RTCPeerConnection) {\n    return;\n  }\n  if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) {\n    window.RTCPeerConnection.prototype.getLocalStreams =\n      function getLocalStreams() {\n        if (!this._localStreams) {\n          this._localStreams = [];\n        }\n        return this._localStreams;\n      };\n  }\n  if (!('addStream' in window.RTCPeerConnection.prototype)) {\n    const _addTrack = window.RTCPeerConnection.prototype.addTrack;\n    window.RTCPeerConnection.prototype.addStream = function addStream(stream) {\n      if (!this._localStreams) {\n        this._localStreams = [];\n      }\n      if (!this._localStreams.includes(stream)) {\n        this._localStreams.push(stream);\n      }\n      // Try to emulate Chrome's behaviour of adding in audio-video order.\n      // Safari orders by track id.\n      stream.getAudioTracks().forEach(track => _addTrack.call(this, track,\n        stream));\n      stream.getVideoTracks().forEach(track => _addTrack.call(this, track,\n        stream));\n    };\n\n    window.RTCPeerConnection.prototype.addTrack =\n      function addTrack(track, ...streams) {\n        if (streams) {\n          streams.forEach((stream) => {\n            if (!this._localStreams) {\n              this._localStreams = [stream];\n            } else if (!this._localStreams.includes(stream)) {\n              this._localStreams.push(stream);\n            }\n          });\n        }\n        return _addTrack.apply(this, arguments);\n      };\n  }\n  if (!('removeStream' in window.RTCPeerConnection.prototype)) {\n    window.RTCPeerConnection.prototype.removeStream =\n      function removeStream(stream) {\n        if (!this._localStreams) {\n          this._localStreams = [];\n        }\n        const index = this._localStreams.indexOf(stream);\n        if (index === -1) {\n          return;\n        }\n        this._localStreams.splice(index, 1);\n        const tracks = stream.getTracks();\n        this.getSenders().forEach(sender => {\n          if (tracks.includes(sender.track)) {\n            this.removeTrack(sender);\n          }\n        });\n      };\n  }\n}\n\nexport function shimRemoteStreamsAPI(window) {\n  if (typeof window !== 'object' || !window.RTCPeerConnection) {\n    return;\n  }\n  if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) {\n    window.RTCPeerConnection.prototype.getRemoteStreams =\n      function getRemoteStreams() {\n        return this._remoteStreams ? this._remoteStreams : [];\n      };\n  }\n  if (!('onaddstream' in window.RTCPeerConnection.prototype)) {\n    Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', {\n      get() {\n        return this._onaddstream;\n      },\n      set(f) {\n        if (this._onaddstream) {\n          this.removeEventListener('addstream', this._onaddstream);\n          this.removeEventListener('track', this._onaddstreampoly);\n        }\n        this.addEventListener('addstream', this._onaddstream = f);\n        this.addEventListener('track', this._onaddstreampoly = (e) => {\n          e.streams.forEach(stream => {\n            if (!this._remoteStreams) {\n              this._remoteStreams = [];\n            }\n            if (this._remoteStreams.includes(stream)) {\n              return;\n            }\n            this._remoteStreams.push(stream);\n            const event = new Event('addstream');\n            event.stream = stream;\n            this.dispatchEvent(event);\n          });\n        });\n      }\n    });\n    const origSetRemoteDescription =\n      window.RTCPeerConnection.prototype.setRemoteDescription;\n    window.RTCPeerConnection.prototype.setRemoteDescription =\n      function setRemoteDescription() {\n        const pc = this;\n        if (!this._onaddstreampoly) {\n          this.addEventListener('track', this._onaddstreampoly = function(e) {\n            e.streams.forEach(stream => {\n              if (!pc._remoteStreams) {\n                pc._remoteStreams = [];\n              }\n              if (pc._remoteStreams.indexOf(stream) >= 0) {\n                return;\n              }\n              pc._remoteStreams.push(stream);\n              const event = new Event('addstream');\n              event.stream = stream;\n              pc.dispatchEvent(event);\n            });\n          });\n        }\n        return origSetRemoteDescription.apply(pc, arguments);\n      };\n  }\n}\n\nexport function shimCallbacksAPI(window) {\n  if (typeof window !== 'object' || !window.RTCPeerConnection) {\n    return;\n  }\n  const prototype = window.RTCPeerConnection.prototype;\n  const origCreateOffer = prototype.createOffer;\n  const origCreateAnswer = prototype.createAnswer;\n  const setLocalDescription = prototype.setLocalDescription;\n  const setRemoteDescription = prototype.setRemoteDescription;\n  const addIceCandidate = prototype.addIceCandidate;\n\n  prototype.createOffer =\n    function createOffer(successCallback, failureCallback) {\n      const options = (arguments.length >= 2) ? arguments[2] : arguments[0];\n      const promise = origCreateOffer.apply(this, [options]);\n      if (!failureCallback) {\n        return promise;\n      }\n      promise.then(successCallback, failureCallback);\n      return Promise.resolve();\n    };\n\n  prototype.createAnswer =\n    function createAnswer(successCallback, failureCallback) {\n      const options = (arguments.length >= 2) ? arguments[2] : arguments[0];\n      const promise = origCreateAnswer.apply(this, [options]);\n      if (!failureCallback) {\n        return promise;\n      }\n      promise.then(successCallback, failureCallback);\n      return Promise.resolve();\n    };\n\n  let withCallback = function(description, successCallback, failureCallback) {\n    const promise = setLocalDescription.apply(this, [description]);\n    if (!failureCallback) {\n      return promise;\n    }\n    promise.then(successCallback, failureCallback);\n    return Promise.resolve();\n  };\n  prototype.setLocalDescription = withCallback;\n\n  withCallback = function(description, successCallback, failureCallback) {\n    const promise = setRemoteDescription.apply(this, [description]);\n    if (!failureCallback) {\n      return promise;\n    }\n    promise.then(successCallback, failureCallback);\n    return Promise.resolve();\n  };\n  prototype.setRemoteDescription = withCallback;\n\n  withCallback = function(candidate, successCallback, failureCallback) {\n    const promise = addIceCandidate.apply(this, [candidate]);\n    if (!failureCallback) {\n      return promise;\n    }\n    promise.then(successCallback, failureCallback);\n    return Promise.resolve();\n  };\n  prototype.addIceCandidate = withCallback;\n}\n\nexport function shimGetUserMedia(window) {\n  const navigator = window && window.navigator;\n\n  if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {\n    // shim not needed in Safari 12.1\n    const mediaDevices = navigator.mediaDevices;\n    const _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices);\n    navigator.mediaDevices.getUserMedia = (constraints) => {\n      return _getUserMedia(shimConstraints(constraints));\n    };\n  }\n\n  if (!navigator.getUserMedia && navigator.mediaDevices &&\n    navigator.mediaDevices.getUserMedia) {\n    navigator.getUserMedia = function getUserMedia(constraints, cb, errcb) {\n      navigator.mediaDevices.getUserMedia(constraints)\n      .then(cb, errcb);\n    }.bind(navigator);\n  }\n}\n\nexport function shimConstraints(constraints) {\n  if (constraints && constraints.video !== undefined) {\n    return Object.assign({},\n      constraints,\n      {video: utils.compactObject(constraints.video)}\n    );\n  }\n\n  return constraints;\n}\n\nexport function shimRTCIceServerUrls(window) {\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n  // migrate from non-spec RTCIceServer.url to RTCIceServer.urls\n  const OrigPeerConnection = window.RTCPeerConnection;\n  window.RTCPeerConnection =\n    function RTCPeerConnection(pcConfig, pcConstraints) {\n      if (pcConfig && pcConfig.iceServers) {\n        const newIceServers = [];\n        for (let i = 0; i < pcConfig.iceServers.length; i++) {\n          let server = pcConfig.iceServers[i];\n          if (!server.hasOwnProperty('urls') &&\n              server.hasOwnProperty('url')) {\n            utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls');\n            server = JSON.parse(JSON.stringify(server));\n            server.urls = server.url;\n            delete server.url;\n            newIceServers.push(server);\n          } else {\n            newIceServers.push(pcConfig.iceServers[i]);\n          }\n        }\n        pcConfig.iceServers = newIceServers;\n      }\n      return new OrigPeerConnection(pcConfig, pcConstraints);\n    };\n  window.RTCPeerConnection.prototype = OrigPeerConnection.prototype;\n  // wrap static methods. Currently just generateCertificate.\n  if ('generateCertificate' in OrigPeerConnection) {\n    Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {\n      get() {\n        return OrigPeerConnection.generateCertificate;\n      }\n    });\n  }\n}\n\nexport function shimTrackEventTransceiver(window) {\n  // Add event.transceiver member over deprecated event.receiver\n  if (typeof window === 'object' && window.RTCTrackEvent &&\n      'receiver' in window.RTCTrackEvent.prototype &&\n      !('transceiver' in window.RTCTrackEvent.prototype)) {\n    Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', {\n      get() {\n        return {receiver: this.receiver};\n      }\n    });\n  }\n}\n\nexport function shimCreateOfferLegacy(window) {\n  const origCreateOffer = window.RTCPeerConnection.prototype.createOffer;\n  window.RTCPeerConnection.prototype.createOffer =\n    function createOffer(offerOptions) {\n      if (offerOptions) {\n        if (typeof offerOptions.offerToReceiveAudio !== 'undefined') {\n          // support bit values\n          offerOptions.offerToReceiveAudio =\n            !!offerOptions.offerToReceiveAudio;\n        }\n        const audioTransceiver = this.getTransceivers().find(transceiver =>\n          transceiver.receiver.track.kind === 'audio');\n        if (offerOptions.offerToReceiveAudio === false && audioTransceiver) {\n          if (audioTransceiver.direction === 'sendrecv') {\n            if (audioTransceiver.setDirection) {\n              audioTransceiver.setDirection('sendonly');\n            } else {\n              audioTransceiver.direction = 'sendonly';\n            }\n          } else if (audioTransceiver.direction === 'recvonly') {\n            if (audioTransceiver.setDirection) {\n              audioTransceiver.setDirection('inactive');\n            } else {\n              audioTransceiver.direction = 'inactive';\n            }\n          }\n        } else if (offerOptions.offerToReceiveAudio === true &&\n            !audioTransceiver) {\n          this.addTransceiver('audio', {direction: 'recvonly'});\n        }\n\n        if (typeof offerOptions.offerToReceiveVideo !== 'undefined') {\n          // support bit values\n          offerOptions.offerToReceiveVideo =\n            !!offerOptions.offerToReceiveVideo;\n        }\n        const videoTransceiver = this.getTransceivers().find(transceiver =>\n          transceiver.receiver.track.kind === 'video');\n        if (offerOptions.offerToReceiveVideo === false && videoTransceiver) {\n          if (videoTransceiver.direction === 'sendrecv') {\n            if (videoTransceiver.setDirection) {\n              videoTransceiver.setDirection('sendonly');\n            } else {\n              videoTransceiver.direction = 'sendonly';\n            }\n          } else if (videoTransceiver.direction === 'recvonly') {\n            if (videoTransceiver.setDirection) {\n              videoTransceiver.setDirection('inactive');\n            } else {\n              videoTransceiver.direction = 'inactive';\n            }\n          }\n        } else if (offerOptions.offerToReceiveVideo === true &&\n            !videoTransceiver) {\n          this.addTransceiver('video', {direction: 'recvonly'});\n        }\n      }\n      return origCreateOffer.apply(this, arguments);\n    };\n}\n\nexport function shimAudioContext(window) {\n  if (typeof window !== 'object' || window.AudioContext) {\n    return;\n  }\n  window.AudioContext = window.webkitAudioContext;\n}\n\n","/*\n *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\n\nimport SDPUtils from 'sdp';\nimport * as utils from './utils';\n\nexport function shimRTCIceCandidate(window) {\n  // foundation is arbitrarily chosen as an indicator for full support for\n  // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface\n  if (!window.RTCIceCandidate || (window.RTCIceCandidate && 'foundation' in\n      window.RTCIceCandidate.prototype)) {\n    return;\n  }\n\n  const NativeRTCIceCandidate = window.RTCIceCandidate;\n  window.RTCIceCandidate = function RTCIceCandidate(args) {\n    // Remove the a= which shouldn't be part of the candidate string.\n    if (typeof args === 'object' && args.candidate &&\n        args.candidate.indexOf('a=') === 0) {\n      args = JSON.parse(JSON.stringify(args));\n      args.candidate = args.candidate.substr(2);\n    }\n\n    if (args.candidate && args.candidate.length) {\n      // Augment the native candidate with the parsed fields.\n      const nativeCandidate = new NativeRTCIceCandidate(args);\n      const parsedCandidate = SDPUtils.parseCandidate(args.candidate);\n      const augmentedCandidate = Object.assign(nativeCandidate,\n          parsedCandidate);\n\n      // Add a serializer that does not serialize the extra attributes.\n      augmentedCandidate.toJSON = function toJSON() {\n        return {\n          candidate: augmentedCandidate.candidate,\n          sdpMid: augmentedCandidate.sdpMid,\n          sdpMLineIndex: augmentedCandidate.sdpMLineIndex,\n          usernameFragment: augmentedCandidate.usernameFragment,\n        };\n      };\n      return augmentedCandidate;\n    }\n    return new NativeRTCIceCandidate(args);\n  };\n  window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype;\n\n  // Hook up the augmented candidate in onicecandidate and\n  // addEventListener('icecandidate', ...)\n  utils.wrapPeerConnectionEvent(window, 'icecandidate', e => {\n    if (e.candidate) {\n      Object.defineProperty(e, 'candidate', {\n        value: new window.RTCIceCandidate(e.candidate),\n        writable: 'false'\n      });\n    }\n    return e;\n  });\n}\n\nexport function shimMaxMessageSize(window, browserDetails) {\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n\n  if (!('sctp' in window.RTCPeerConnection.prototype)) {\n    Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', {\n      get() {\n        return typeof this._sctp === 'undefined' ? null : this._sctp;\n      }\n    });\n  }\n\n  const sctpInDescription = function(description) {\n    if (!description || !description.sdp) {\n      return false;\n    }\n    const sections = SDPUtils.splitSections(description.sdp);\n    sections.shift();\n    return sections.some(mediaSection => {\n      const mLine = SDPUtils.parseMLine(mediaSection);\n      return mLine && mLine.kind === 'application'\n          && mLine.protocol.indexOf('SCTP') !== -1;\n    });\n  };\n\n  const getRemoteFirefoxVersion = function(description) {\n    // TODO: Is there a better solution for detecting Firefox?\n    const match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\\d+)/);\n    if (match === null || match.length < 2) {\n      return -1;\n    }\n    const version = parseInt(match[1], 10);\n    // Test for NaN (yes, this is ugly)\n    return version !== version ? -1 : version;\n  };\n\n  const getCanSendMaxMessageSize = function(remoteIsFirefox) {\n    // Every implementation we know can send at least 64 KiB.\n    // Note: Although Chrome is technically able to send up to 256 KiB, the\n    //       data does not reach the other peer reliably.\n    //       See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419\n    let canSendMaxMessageSize = 65536;\n    if (browserDetails.browser === 'firefox') {\n      if (browserDetails.version < 57) {\n        if (remoteIsFirefox === -1) {\n          // FF < 57 will send in 16 KiB chunks using the deprecated PPID\n          // fragmentation.\n          canSendMaxMessageSize = 16384;\n        } else {\n          // However, other FF (and RAWRTC) can reassemble PPID-fragmented\n          // messages. Thus, supporting ~2 GiB when sending.\n          canSendMaxMessageSize = 2147483637;\n        }\n      } else if (browserDetails.version < 60) {\n        // Currently, all FF >= 57 will reset the remote maximum message size\n        // to the default value when a data channel is created at a later\n        // stage. :(\n        // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831\n        canSendMaxMessageSize =\n          browserDetails.version === 57 ? 65535 : 65536;\n      } else {\n        // FF >= 60 supports sending ~2 GiB\n        canSendMaxMessageSize = 2147483637;\n      }\n    }\n    return canSendMaxMessageSize;\n  };\n\n  const getMaxMessageSize = function(description, remoteIsFirefox) {\n    // Note: 65536 bytes is the default value from the SDP spec. Also,\n    //       every implementation we know supports receiving 65536 bytes.\n    let maxMessageSize = 65536;\n\n    // FF 57 has a slightly incorrect default remote max message size, so\n    // we need to adjust it here to avoid a failure when sending.\n    // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697\n    if (browserDetails.browser === 'firefox'\n         && browserDetails.version === 57) {\n      maxMessageSize = 65535;\n    }\n\n    const match = SDPUtils.matchPrefix(description.sdp,\n      'a=max-message-size:');\n    if (match.length > 0) {\n      maxMessageSize = parseInt(match[0].substr(19), 10);\n    } else if (browserDetails.browser === 'firefox' &&\n                remoteIsFirefox !== -1) {\n      // If the maximum message size is not present in the remote SDP and\n      // both local and remote are Firefox, the remote peer can receive\n      // ~2 GiB.\n      maxMessageSize = 2147483637;\n    }\n    return maxMessageSize;\n  };\n\n  const origSetRemoteDescription =\n      window.RTCPeerConnection.prototype.setRemoteDescription;\n  window.RTCPeerConnection.prototype.setRemoteDescription =\n    function setRemoteDescription() {\n      this._sctp = null;\n      // Chrome decided to not expose .sctp in plan-b mode.\n      // As usual, adapter.js has to do an 'ugly worakaround'\n      // to cover up the mess.\n      if (browserDetails.browser === 'chrome' && browserDetails.version >= 76) {\n        const {sdpSemantics} = this.getConfiguration();\n        if (sdpSemantics === 'plan-b') {\n          Object.defineProperty(this, 'sctp', {\n            get() {\n              return typeof this._sctp === 'undefined' ? null : this._sctp;\n            },\n            enumerable: true,\n            configurable: true,\n          });\n        }\n      }\n\n      if (sctpInDescription(arguments[0])) {\n        // Check if the remote is FF.\n        const isFirefox = getRemoteFirefoxVersion(arguments[0]);\n\n        // Get the maximum message size the local peer is capable of sending\n        const canSendMMS = getCanSendMaxMessageSize(isFirefox);\n\n        // Get the maximum message size of the remote peer.\n        const remoteMMS = getMaxMessageSize(arguments[0], isFirefox);\n\n        // Determine final maximum message size\n        let maxMessageSize;\n        if (canSendMMS === 0 && remoteMMS === 0) {\n          maxMessageSize = Number.POSITIVE_INFINITY;\n        } else if (canSendMMS === 0 || remoteMMS === 0) {\n          maxMessageSize = Math.max(canSendMMS, remoteMMS);\n        } else {\n          maxMessageSize = Math.min(canSendMMS, remoteMMS);\n        }\n\n        // Create a dummy RTCSctpTransport object and the 'maxMessageSize'\n        // attribute.\n        const sctp = {};\n        Object.defineProperty(sctp, 'maxMessageSize', {\n          get() {\n            return maxMessageSize;\n          }\n        });\n        this._sctp = sctp;\n      }\n\n      return origSetRemoteDescription.apply(this, arguments);\n    };\n}\n\nexport function shimSendThrowTypeError(window) {\n  if (!(window.RTCPeerConnection &&\n      'createDataChannel' in window.RTCPeerConnection.prototype)) {\n    return;\n  }\n\n  // Note: Although Firefox >= 57 has a native implementation, the maximum\n  //       message size can be reset for all data channels at a later stage.\n  //       See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831\n\n  function wrapDcSend(dc, pc) {\n    const origDataChannelSend = dc.send;\n    dc.send = function send() {\n      const data = arguments[0];\n      const length = data.length || data.size || data.byteLength;\n      if (dc.readyState === 'open' &&\n          pc.sctp && length > pc.sctp.maxMessageSize) {\n        throw new TypeError('Message too large (can send a maximum of ' +\n          pc.sctp.maxMessageSize + ' bytes)');\n      }\n      return origDataChannelSend.apply(dc, arguments);\n    };\n  }\n  const origCreateDataChannel =\n    window.RTCPeerConnection.prototype.createDataChannel;\n  window.RTCPeerConnection.prototype.createDataChannel =\n    function createDataChannel() {\n      const dataChannel = origCreateDataChannel.apply(this, arguments);\n      wrapDcSend(dataChannel, this);\n      return dataChannel;\n    };\n  utils.wrapPeerConnectionEvent(window, 'datachannel', e => {\n    wrapDcSend(e.channel, e.target);\n    return e;\n  });\n}\n\n\n/* shims RTCConnectionState by pretending it is the same as iceConnectionState.\n * See https://bugs.chromium.org/p/webrtc/issues/detail?id=6145#c12\n * for why this is a valid hack in Chrome. In Firefox it is slightly incorrect\n * since DTLS failures would be hidden. See\n * https://bugzilla.mozilla.org/show_bug.cgi?id=1265827\n * for the Firefox tracking bug.\n */\nexport function shimConnectionState(window) {\n  if (!window.RTCPeerConnection ||\n      'connectionState' in window.RTCPeerConnection.prototype) {\n    return;\n  }\n  const proto = window.RTCPeerConnection.prototype;\n  Object.defineProperty(proto, 'connectionState', {\n    get() {\n      return {\n        completed: 'connected',\n        checking: 'connecting'\n      }[this.iceConnectionState] || this.iceConnectionState;\n    },\n    enumerable: true,\n    configurable: true\n  });\n  Object.defineProperty(proto, 'onconnectionstatechange', {\n    get() {\n      return this._onconnectionstatechange || null;\n    },\n    set(cb) {\n      if (this._onconnectionstatechange) {\n        this.removeEventListener('connectionstatechange',\n            this._onconnectionstatechange);\n        delete this._onconnectionstatechange;\n      }\n      if (cb) {\n        this.addEventListener('connectionstatechange',\n            this._onconnectionstatechange = cb);\n      }\n    },\n    enumerable: true,\n    configurable: true\n  });\n\n  ['setLocalDescription', 'setRemoteDescription'].forEach((method) => {\n    const origMethod = proto[method];\n    proto[method] = function() {\n      if (!this._connectionstatechangepoly) {\n        this._connectionstatechangepoly = e => {\n          const pc = e.target;\n          if (pc._lastConnectionState !== pc.connectionState) {\n            pc._lastConnectionState = pc.connectionState;\n            const newEvent = new Event('connectionstatechange', e);\n            pc.dispatchEvent(newEvent);\n          }\n          return e;\n        };\n        this.addEventListener('iceconnectionstatechange',\n          this._connectionstatechangepoly);\n      }\n      return origMethod.apply(this, arguments);\n    };\n  });\n}\n\nexport function removeExtmapAllowMixed(window, browserDetails) {\n  /* remove a=extmap-allow-mixed for webrtc.org < M71 */\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n  if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) {\n    return;\n  }\n  if (browserDetails.browser === 'safari' && browserDetails.version >= 605) {\n    return;\n  }\n  const nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription;\n  window.RTCPeerConnection.prototype.setRemoteDescription =\n  function setRemoteDescription(desc) {\n    if (desc && desc.sdp && desc.sdp.indexOf('\\na=extmap-allow-mixed') !== -1) {\n      const sdp = desc.sdp.split('\\n').filter((line) => {\n        return line.trim() !== 'a=extmap-allow-mixed';\n      }).join('\\n');\n      // Safari enforces read-only-ness of RTCSessionDescription fields.\n      if (window.RTCSessionDescription &&\n          desc instanceof window.RTCSessionDescription) {\n        arguments[0] = new window.RTCSessionDescription({\n          type: desc.type,\n          sdp,\n        });\n      } else {\n        desc.sdp = sdp;\n      }\n    }\n    return nativeSRD.apply(this, arguments);\n  };\n}\n\nexport function shimAddIceCandidateNullOrEmpty(window, browserDetails) {\n  // Support for addIceCandidate(null or undefined)\n  // as well as addIceCandidate({candidate: \"\", ...})\n  // https://bugs.chromium.org/p/chromium/issues/detail?id=978582\n  // Note: must be called before other polyfills which change the signature.\n  if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) {\n    return;\n  }\n  const nativeAddIceCandidate =\n      window.RTCPeerConnection.prototype.addIceCandidate;\n  if (!nativeAddIceCandidate || nativeAddIceCandidate.length === 0) {\n    return;\n  }\n  window.RTCPeerConnection.prototype.addIceCandidate =\n    function addIceCandidate() {\n      if (!arguments[0]) {\n        if (arguments[1]) {\n          arguments[1].apply(null);\n        }\n        return Promise.resolve();\n      }\n      // Firefox 68+ emits and processes {candidate: \"\", ...}, ignore\n      // in older versions.\n      // Native support for ignoring exists for Chrome M77+.\n      // Safari ignores as well, exact version unknown but works in the same\n      // version that also ignores addIceCandidate(null).\n      if (((browserDetails.browser === 'chrome' && browserDetails.version < 78)\n           || (browserDetails.browser === 'firefox'\n               && browserDetails.version < 68)\n           || (browserDetails.browser === 'safari'))\n          && arguments[0] && arguments[0].candidate === '') {\n        return Promise.resolve();\n      }\n      return nativeAddIceCandidate.apply(this, arguments);\n    };\n}\n\n// Note: Make sure to call this ahead of APIs that modify\n// setLocalDescription.length\nexport function shimParameterlessSetLocalDescription(window, browserDetails) {\n  if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) {\n    return;\n  }\n  const nativeSetLocalDescription =\n      window.RTCPeerConnection.prototype.setLocalDescription;\n  if (!nativeSetLocalDescription || nativeSetLocalDescription.length === 0) {\n    return;\n  }\n  window.RTCPeerConnection.prototype.setLocalDescription =\n    function setLocalDescription() {\n      let desc = arguments[0] || {};\n      if (typeof desc !== 'object' || (desc.type && desc.sdp)) {\n        return nativeSetLocalDescription.apply(this, arguments);\n      }\n      // The remaining steps should technically happen when SLD comes off the\n      // RTCPeerConnection's operations chain (not ahead of going on it), but\n      // this is too difficult to shim. Instead, this shim only covers the\n      // common case where the operations chain is empty. This is imperfect, but\n      // should cover many cases. Rationale: Even if we can't reduce the glare\n      // window to zero on imperfect implementations, there's value in tapping\n      // into the perfect negotiation pattern that several browsers support.\n      desc = {type: desc.type, sdp: desc.sdp};\n      if (!desc.type) {\n        switch (this.signalingState) {\n          case 'stable':\n          case 'have-local-offer':\n          case 'have-remote-pranswer':\n            desc.type = 'offer';\n            break;\n          default:\n            desc.type = 'answer';\n            break;\n        }\n      }\n      if (desc.sdp || (desc.type !== 'offer' && desc.type !== 'answer')) {\n        return nativeSetLocalDescription.apply(this, [desc]);\n      }\n      const func = desc.type === 'offer' ? this.createOffer : this.createAnswer;\n      return func.apply(this)\n        .then(d => nativeSetLocalDescription.apply(this, [d]));\n    };\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\nimport * as utils from './utils';\n\n  // Browser shims.\nimport * as chromeShim from './chrome/chrome_shim';\nimport * as firefoxShim from './firefox/firefox_shim';\nimport * as safariShim from './safari/safari_shim';\nimport * as commonShim from './common_shim';\nimport * as sdp from 'sdp';\n\n// Shimming starts here.\nexport function adapterFactory({window} = {}, options = {\n  shimChrome: true,\n  shimFirefox: true,\n  shimSafari: true,\n}) {\n  // Utils.\n  const logging = utils.log;\n  const browserDetails = utils.detectBrowser(window);\n\n  const adapter = {\n    browserDetails,\n    commonShim,\n    extractVersion: utils.extractVersion,\n    disableLog: utils.disableLog,\n    disableWarnings: utils.disableWarnings,\n    // Expose sdp as a convenience. For production apps include directly.\n    sdp,\n  };\n\n  // Shim browser if found.\n  switch (browserDetails.browser) {\n    case 'chrome':\n      if (!chromeShim || !chromeShim.shimPeerConnection ||\n          !options.shimChrome) {\n        logging('Chrome shim is not included in this adapter release.');\n        return adapter;\n      }\n      if (browserDetails.version === null) {\n        logging('Chrome shim can not determine version, not shimming.');\n        return adapter;\n      }\n      logging('adapter.js shimming chrome.');\n      // Export to the adapter global object visible in the browser.\n      adapter.browserShim = chromeShim;\n\n      // Must be called before shimPeerConnection.\n      commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);\n      commonShim.shimParameterlessSetLocalDescription(window, browserDetails);\n\n      chromeShim.shimGetUserMedia(window, browserDetails);\n      chromeShim.shimMediaStream(window, browserDetails);\n      chromeShim.shimPeerConnection(window, browserDetails);\n      chromeShim.shimOnTrack(window, browserDetails);\n      chromeShim.shimAddTrackRemoveTrack(window, browserDetails);\n      chromeShim.shimGetSendersWithDtmf(window, browserDetails);\n      chromeShim.shimGetStats(window, browserDetails);\n      chromeShim.shimSenderReceiverGetStats(window, browserDetails);\n      chromeShim.fixNegotiationNeeded(window, browserDetails);\n\n      commonShim.shimRTCIceCandidate(window, browserDetails);\n      commonShim.shimConnectionState(window, browserDetails);\n      commonShim.shimMaxMessageSize(window, browserDetails);\n      commonShim.shimSendThrowTypeError(window, browserDetails);\n      commonShim.removeExtmapAllowMixed(window, browserDetails);\n      break;\n    case 'firefox':\n      if (!firefoxShim || !firefoxShim.shimPeerConnection ||\n          !options.shimFirefox) {\n        logging('Firefox shim is not included in this adapter release.');\n        return adapter;\n      }\n      logging('adapter.js shimming firefox.');\n      // Export to the adapter global object visible in the browser.\n      adapter.browserShim = firefoxShim;\n\n      // Must be called before shimPeerConnection.\n      commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);\n      commonShim.shimParameterlessSetLocalDescription(window, browserDetails);\n\n      firefoxShim.shimGetUserMedia(window, browserDetails);\n      firefoxShim.shimPeerConnection(window, browserDetails);\n      firefoxShim.shimOnTrack(window, browserDetails);\n      firefoxShim.shimRemoveStream(window, browserDetails);\n      firefoxShim.shimSenderGetStats(window, browserDetails);\n      firefoxShim.shimReceiverGetStats(window, browserDetails);\n      firefoxShim.shimRTCDataChannel(window, browserDetails);\n      firefoxShim.shimAddTransceiver(window, browserDetails);\n      firefoxShim.shimGetParameters(window, browserDetails);\n      firefoxShim.shimCreateOffer(window, browserDetails);\n      firefoxShim.shimCreateAnswer(window, browserDetails);\n\n      commonShim.shimRTCIceCandidate(window, browserDetails);\n      commonShim.shimConnectionState(window, browserDetails);\n      commonShim.shimMaxMessageSize(window, browserDetails);\n      commonShim.shimSendThrowTypeError(window, browserDetails);\n      break;\n    case 'safari':\n      if (!safariShim || !options.shimSafari) {\n        logging('Safari shim is not included in this adapter release.');\n        return adapter;\n      }\n      logging('adapter.js shimming safari.');\n      // Export to the adapter global object visible in the browser.\n      adapter.browserShim = safariShim;\n\n      // Must be called before shimCallbackAPI.\n      commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);\n      commonShim.shimParameterlessSetLocalDescription(window, browserDetails);\n\n      safariShim.shimRTCIceServerUrls(window, browserDetails);\n      safariShim.shimCreateOfferLegacy(window, browserDetails);\n      safariShim.shimCallbacksAPI(window, browserDetails);\n      safariShim.shimLocalStreamsAPI(window, browserDetails);\n      safariShim.shimRemoteStreamsAPI(window, browserDetails);\n      safariShim.shimTrackEventTransceiver(window, browserDetails);\n      safariShim.shimGetUserMedia(window, browserDetails);\n      safariShim.shimAudioContext(window, browserDetails);\n\n      commonShim.shimRTCIceCandidate(window, browserDetails);\n      commonShim.shimMaxMessageSize(window, browserDetails);\n      commonShim.shimSendThrowTypeError(window, browserDetails);\n      commonShim.removeExtmapAllowMixed(window, browserDetails);\n      break;\n    default:\n      logging('Unsupported browser!');\n      break;\n  }\n\n  return adapter;\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n\n'use strict';\n\nimport {adapterFactory} from './adapter_factory.js';\n\nconst adapter =\n  adapterFactory({window: typeof window === 'undefined' ? undefined : window});\nexport default adapter;\n","import { getLogger } from '@jitsi/logger';\nimport EventEmitter from 'events';\nimport clonedeep from 'lodash.clonedeep';\nimport 'webrtc-adapter';\n\nimport JitsiTrackError from '../../JitsiTrackError';\nimport * as JitsiTrackErrors from '../../JitsiTrackErrors';\nimport CameraFacingMode from '../../service/RTC/CameraFacingMode';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport Resolutions from '../../service/RTC/Resolutions';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport { AVAILABLE_DEVICE } from '../../service/statistics/AnalyticsEvents';\nimport browser from '../browser';\nimport Statistics from '../statistics/statistics';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\nimport Listenable from '../util/Listenable';\n\nimport screenObtainer from './ScreenObtainer';\n\nconst logger = getLogger(__filename);\n\nconst eventEmitter = new EventEmitter();\n\nconst AVAILABLE_DEVICES_POLL_INTERVAL_TIME = 3000; // ms\n\n/**\n * Default MediaStreamConstraints to use for calls to getUserMedia.\n *\n * @private\n */\nconst DEFAULT_CONSTRAINTS = {\n    video: {\n        height: {\n            ideal: 720,\n            max: 720,\n            min: 180\n        },\n        width: {\n            ideal: 1280,\n            max: 1280,\n            min: 320\n        }\n    }\n};\n\n// Currently audio output device change is supported only in Chrome and\n// default output always has 'default' device ID\nlet audioOutputDeviceId = 'default'; // default device\n// whether user has explicitly set a device to use\nlet audioOutputChanged = false;\n\n// Disables all audio processing\nlet disableAP = false;\n\n// Disables Acoustic Echo Cancellation\nlet disableAEC = false;\n\n// Disables Noise Suppression\nlet disableNS = false;\n\n// Disables Automatic Gain Control\nlet disableAGC = false;\n\n// Enables stereo.\nlet stereo = null;\n\nconst featureDetectionAudioEl = document.createElement('audio');\nconst isAudioOutputDeviceChangeAvailable\n    = typeof featureDetectionAudioEl.setSinkId !== 'undefined';\n\nlet availableDevices = [];\nlet availableDevicesPollTimer;\n\n/**\n * An empty function.\n */\nfunction emptyFuncton() {\n    // no-op\n}\n\n/**\n * Creates a constraints object to be passed into a call to getUserMedia.\n *\n * @param {Array} um - An array of user media types to get. The accepted types are \"video\", \"audio\", and \"desktop.\"\n * @param {Object} options - Various values to be added to the constraints.\n * @param {string} options.cameraDeviceId - The device id for the video capture device to get video from.\n * @param {Object} options.constraints - Default constraints object to use as a base for the returned constraints.\n * @param {Object} options.desktopStream - The desktop source id from which to capture a desktop sharing video.\n * @param {string} options.facingMode - Which direction the camera is pointing to (applicable on mobile)\n * @param {string} options.micDeviceId - The device id for the audio capture device to get audio from.\n * @private\n * @returns {Object}\n */\nfunction getConstraints(um = [], options = {}) {\n    // Create a deep copy of the constraints to avoid any modification of\n    // the passed in constraints object.\n    const constraints = clonedeep(options.constraints || DEFAULT_CONSTRAINTS);\n\n    if (um.indexOf('video') >= 0) {\n        // The \"resolution\" option is a shortcut and takes precendence.\n        if (Resolutions[options.resolution]) {\n            const r = Resolutions[options.resolution];\n\n            constraints.video.height = { ideal: r.height };\n            constraints.video.width = { ideal: r.width };\n        }\n\n        if (!constraints.video) {\n            constraints.video = {};\n        }\n\n        // Override the constraints on Safari because of the following webkit bug.\n        // https://bugs.webkit.org/show_bug.cgi?id=210932\n        // Camera doesn't start on older macOS versions if min/max constraints are specified.\n        // TODO: remove this hack when the bug fix is available on Mojave, Sierra and High Sierra.\n        if (browser.isWebKitBased()) {\n            if (constraints.video.height && constraints.video.height.ideal) {\n                constraints.video.height = { ideal: constraints.video.height.ideal };\n            } else {\n                logger.warn('Ideal camera height missing, camera may not start properly');\n            }\n            if (constraints.video.width && constraints.video.width.ideal) {\n                constraints.video.width = { ideal: constraints.video.width.ideal };\n            } else {\n                logger.warn('Ideal camera width missing, camera may not start properly');\n            }\n        }\n        if (options.cameraDeviceId) {\n            constraints.video.deviceId = options.cameraDeviceId;\n        } else {\n            const facingMode = options.facingMode || CameraFacingMode.USER;\n\n            constraints.video.facingMode = facingMode;\n        }\n    } else {\n        constraints.video = false;\n    }\n\n    if (um.indexOf('audio') >= 0) {\n        if (!constraints.audio || typeof constraints.audio === 'boolean') {\n            constraints.audio = {};\n        }\n\n        constraints.audio = {\n            autoGainControl: !disableAGC && !disableAP,\n            deviceId: options.micDeviceId,\n            echoCancellation: !disableAEC && !disableAP,\n            noiseSuppression: !disableNS && !disableAP\n        };\n\n        if (stereo) {\n            Object.assign(constraints.audio, { channelCount: 2 });\n        }\n    } else {\n        constraints.audio = false;\n    }\n\n    return constraints;\n}\n\n/**\n * Updates the granted permissions based on the options we requested and the\n * streams we received.\n * @param um the options we requested to getUserMedia.\n * @param stream the stream we received from calling getUserMedia.\n */\nfunction updateGrantedPermissions(um, stream) {\n    const audioTracksReceived\n        = Boolean(stream) && stream.getAudioTracks().length > 0;\n    const videoTracksReceived\n        = Boolean(stream) && stream.getVideoTracks().length > 0;\n    const grantedPermissions = {};\n\n    if (um.indexOf('video') !== -1) {\n        grantedPermissions.video = videoTracksReceived;\n    }\n    if (um.indexOf('audio') !== -1) {\n        grantedPermissions.audio = audioTracksReceived;\n    }\n\n    eventEmitter.emit(RTCEvents.PERMISSIONS_CHANGED, grantedPermissions);\n}\n\n/**\n * Checks if new list of available media devices differs from previous one.\n * @param {MediaDeviceInfo[]} newDevices - list of new devices.\n * @returns {boolean} - true if list is different, false otherwise.\n */\nfunction compareAvailableMediaDevices(newDevices) {\n    if (newDevices.length !== availableDevices.length) {\n        return true;\n    }\n\n    /* eslint-disable newline-per-chained-call */\n\n    return (\n        newDevices.map(mediaDeviceInfoToJSON).sort().join('')\n            !== availableDevices\n                .map(mediaDeviceInfoToJSON).sort().join(''));\n\n    /* eslint-enable newline-per-chained-call */\n\n    /**\n     *\n     * @param info\n     */\n    function mediaDeviceInfoToJSON(info) {\n        return JSON.stringify({\n            kind: info.kind,\n            deviceId: info.deviceId,\n            groupId: info.groupId,\n            label: info.label,\n            facing: info.facing\n        });\n    }\n}\n\n/**\n * Sends analytics event with the passed device list.\n *\n * @param {Array<MediaDeviceInfo>} deviceList - List with info about the\n * available devices.\n * @returns {void}\n */\nfunction sendDeviceListToAnalytics(deviceList) {\n    const audioInputDeviceCount\n        = deviceList.filter(d => d.kind === 'audioinput').length;\n    const audioOutputDeviceCount\n        = deviceList.filter(d => d.kind === 'audiooutput').length;\n    const videoInputDeviceCount\n        = deviceList.filter(d => d.kind === 'videoinput').length;\n    const videoOutputDeviceCount\n        = deviceList.filter(d => d.kind === 'videooutput').length;\n\n    deviceList.forEach(device => {\n        const attributes = {\n            'audio_input_device_count': audioInputDeviceCount,\n            'audio_output_device_count': audioOutputDeviceCount,\n            'video_input_device_count': videoInputDeviceCount,\n            'video_output_device_count': videoOutputDeviceCount,\n            'device_id': device.deviceId,\n            'device_group_id': device.groupId,\n            'device_kind': device.kind,\n            'device_label': device.label\n        };\n\n        Statistics.sendAnalytics(AVAILABLE_DEVICE, attributes);\n    });\n}\n\n\n/**\n * Update known devices.\n *\n * @param {Array<Object>} pds - The new devices.\n * @returns {void}\n *\n * NOTE: Use this function as a shared callback to handle both the devicechange event  and the polling implementations.\n * This prevents duplication and works around a chrome bug (verified to occur on 68) where devicechange fires twice in\n * a row, which can cause async post devicechange processing to collide.\n */\nfunction updateKnownDevices(pds) {\n    if (compareAvailableMediaDevices(pds)) {\n        onMediaDevicesListChanged(pds);\n    }\n}\n\n/**\n * Event handler for the 'devicechange' event.\n *\n * @param {MediaDeviceInfo[]} devices - list of media devices.\n * @emits RTCEvents.DEVICE_LIST_CHANGED\n */\nfunction onMediaDevicesListChanged(devicesReceived) {\n    availableDevices = devicesReceived.slice(0);\n    logger.info('list of media devices has changed:', availableDevices);\n\n    sendDeviceListToAnalytics(availableDevices);\n\n    // Used by tracks to update the real device id before the consumer of lib-jitsi-meet receives the new device list.\n    eventEmitter.emit(RTCEvents.DEVICE_LIST_WILL_CHANGE, availableDevices);\n\n    eventEmitter.emit(RTCEvents.DEVICE_LIST_CHANGED, availableDevices);\n}\n\n/**\n *\n */\nclass RTCUtils extends Listenable {\n    /**\n     *\n     */\n    constructor() {\n        super(eventEmitter);\n    }\n\n    /**\n     * Depending on the browser, sets difference instance methods for\n     * interacting with user media and adds methods to native WebRTC-related\n     * objects. Also creates an instance variable for peer connection\n     * constraints.\n     *\n     * @param {Object} options\n     * @returns {void}\n     */\n    init(options = {}) {\n        if (typeof options.disableAEC === 'boolean') {\n            disableAEC = options.disableAEC;\n            logger.info(`Disable AEC: ${disableAEC}`);\n        }\n        if (typeof options.disableNS === 'boolean') {\n            disableNS = options.disableNS;\n            logger.info(`Disable NS: ${disableNS}`);\n        }\n        if (typeof options.disableAP === 'boolean') {\n            disableAP = options.disableAP;\n            logger.info(`Disable AP: ${disableAP}`);\n        }\n        if (typeof options.disableAGC === 'boolean') {\n            disableAGC = options.disableAGC;\n            logger.info(`Disable AGC: ${disableAGC}`);\n        }\n        if (typeof options.audioQuality?.stereo === 'boolean') {\n            stereo = options.audioQuality.stereo;\n            logger.info(`Stereo: ${stereo}`);\n        }\n\n        window.clearInterval(availableDevicesPollTimer);\n        availableDevicesPollTimer = undefined;\n\n        if (!browser.isReactNative()) {\n            this.attachMediaStream\n                = wrapAttachMediaStream((element, stream) => {\n                    if (element) {\n                        element.srcObject = stream;\n                    }\n                });\n        }\n\n        this.pcConstraints = {};\n\n        screenObtainer.init(options);\n\n        if (this.isDeviceListAvailable()) {\n            this.enumerateDevices(ds => {\n                availableDevices = ds.slice(0);\n\n                logger.debug('Available devices: ', availableDevices);\n                sendDeviceListToAnalytics(availableDevices);\n\n                eventEmitter.emit(\n                    RTCEvents.DEVICE_LIST_AVAILABLE,\n                    availableDevices);\n\n                if (browser.supportsDeviceChangeEvent()) {\n                    navigator.mediaDevices.addEventListener(\n                        'devicechange',\n                        () => this.enumerateDevices(emptyFuncton));\n                } else {\n                    // Periodically poll enumerateDevices() method to check if\n                    // list of media devices has changed.\n                    availableDevicesPollTimer = window.setInterval(\n                        () => this.enumerateDevices(emptyFuncton),\n                        AVAILABLE_DEVICES_POLL_INTERVAL_TIME);\n                }\n            });\n        }\n    }\n\n    /**\n     *\n     * @param {Function} callback\n     */\n    enumerateDevices(callback) {\n        navigator.mediaDevices.enumerateDevices()\n            .then(devices => {\n                updateKnownDevices(devices);\n                callback(devices);\n            })\n            .catch(error => {\n                logger.warn(`Failed to  enumerate devices. ${error}`);\n                updateKnownDevices([]);\n                callback([]);\n            });\n    }\n\n    /**\n     * Acquires a media stream via getUserMedia that\n     * matches the given constraints\n     *\n     * @param {array} umDevices which devices to acquire (e.g. audio, video)\n     * @param {Object} constraints - Stream specifications to use.\n     * @param {number} timeout - The timeout in ms for GUM.\n     * @returns {Promise}\n     */\n    _getUserMedia(umDevices, constraints = {}, timeout = 0) {\n        return new Promise((resolve, reject) => {\n            let gumTimeout, timeoutExpired = false;\n\n            if (typeof timeout === 'number' && !isNaN(timeout) && timeout > 0) {\n                gumTimeout = setTimeout(() => {\n                    timeoutExpired = true;\n                    gumTimeout = undefined;\n                    reject(new JitsiTrackError(JitsiTrackErrors.TIMEOUT));\n                }, timeout);\n            }\n\n            navigator.mediaDevices.getUserMedia(constraints)\n                .then(stream => {\n                    logger.log('onUserMediaSuccess');\n                    updateGrantedPermissions(umDevices, stream);\n                    if (!timeoutExpired) {\n                        if (typeof gumTimeout !== 'undefined') {\n                            clearTimeout(gumTimeout);\n                        }\n                        resolve(stream);\n                    }\n                })\n                .catch(error => {\n                    logger.warn(`Failed to get access to local media. ${error} ${JSON.stringify(constraints)}`);\n                    const jitsiError = new JitsiTrackError(error, constraints, umDevices);\n\n                    if (!timeoutExpired) {\n                        if (typeof gumTimeout !== 'undefined') {\n                            clearTimeout(gumTimeout);\n                        }\n                        reject(jitsiError);\n                    }\n\n                    if (jitsiError.name === JitsiTrackErrors.PERMISSION_DENIED) {\n                        updateGrantedPermissions(umDevices, undefined);\n                    }\n\n                    // else {\n                    // Probably the error is not caused by the lack of permissions and we don't need to update them.\n                    // }\n                });\n        });\n    }\n\n    /**\n     * Acquire a display stream via the screenObtainer. This requires extra\n     * logic compared to use screenObtainer versus normal device capture logic\n     * in RTCUtils#_getUserMedia.\n     *\n     * @param {Object} options - Optional parameters.\n     * @returns {Promise} A promise which will be resolved with an object which\n     * contains the acquired display stream. If desktop sharing is not supported\n     * then a rejected promise will be returned.\n     */\n    _getDesktopMedia(options) {\n        if (!screenObtainer.isSupported()) {\n            return Promise.reject(new Error('Desktop sharing is not supported!'));\n        }\n\n        return new Promise((resolve, reject) => {\n            screenObtainer.obtainStream(\n                stream => {\n                    resolve(stream);\n                },\n                error => {\n                    reject(error);\n                },\n                options);\n        });\n    }\n\n    /**\n     * Private utility for determining if the passed in MediaStream contains\n     * tracks of the type(s) specified in the requested devices.\n     *\n     * @param {string[]} requestedDevices - The track types that are expected to\n     * be includes in the stream.\n     * @param {MediaStream} stream - The MediaStream to check if it has the\n     * expected track types.\n     * @returns {string[]} An array of string with the missing track types. The\n     * array will be empty if all requestedDevices are found in the stream.\n     */\n    _getMissingTracks(requestedDevices = [], stream) {\n        const missingDevices = [];\n\n        const audioDeviceRequested = requestedDevices.includes('audio');\n        const audioTracksReceived\n            = stream && stream.getAudioTracks().length > 0;\n\n        if (audioDeviceRequested && !audioTracksReceived) {\n            missingDevices.push('audio');\n        }\n\n        const videoDeviceRequested = requestedDevices.includes('video');\n        const videoTracksReceived\n            = stream && stream.getVideoTracks().length > 0;\n\n        if (videoDeviceRequested && !videoTracksReceived) {\n            missingDevices.push('video');\n        }\n\n        return missingDevices;\n    }\n\n    /**\n     * Gets streams from specified device types. This function intentionally\n     * ignores errors for upstream to catch and handle instead.\n     *\n     * @param {Object} options - A hash describing what devices to get and\n     * relevant constraints.\n     * @param {string[]} options.devices - The types of media to capture. Valid\n     * values are \"desktop\", \"audio\", and \"video\".\n     * @param {Object} options.desktopSharingFrameRate\n     * @param {Object} options.desktopSharingFrameRate.min - Minimum fps\n     * @param {Object} options.desktopSharingFrameRate.max - Maximum fps\n     * @param {String} options.desktopSharingSourceDevice - The device id or\n     * label for a video input source that should be used for screensharing.\n     * @param {Array<string>} options.desktopSharingSources - The types of sources (\"screen\", \"window\", etc)\n     * from which the user can select what to share.\n     * @returns {Promise} The promise, when successful, will return an array of\n     * meta data for the requested device type, which includes the stream and\n     * track. If an error occurs, it will be deferred to the caller for\n     * handling.\n     */\n    obtainAudioAndVideoPermissions(options) {\n        const {\n            timeout,\n            ...otherOptions\n        } = options;\n\n        const mediaStreamsMetaData = [];\n\n        // Declare private functions to be used in the promise chain below.\n        // These functions are declared in the scope of this function because\n        // they are not being used anywhere else, so only this function needs to\n        // know about them.\n\n        /**\n         * Executes a request for desktop media if specified in options.\n         *\n         * @returns {Promise}\n         */\n        const maybeRequestDesktopDevice = function() {\n            const umDevices = otherOptions.devices || [];\n            const isDesktopDeviceRequested\n                = umDevices.indexOf('desktop') !== -1;\n\n            if (!isDesktopDeviceRequested) {\n                return Promise.resolve();\n            }\n\n            const {\n                desktopSharingSourceDevice,\n                desktopSharingSources\n            } = otherOptions;\n\n            // Attempt to use a video input device as a screenshare source if\n            // the option is defined.\n            if (desktopSharingSourceDevice) {\n                const matchingDevice\n                    = availableDevices && availableDevices.find(device =>\n                        device.kind === 'videoinput'\n                            && (device.deviceId === desktopSharingSourceDevice\n                            || device.label === desktopSharingSourceDevice));\n\n                if (!matchingDevice) {\n                    return Promise.reject(new JitsiTrackError(\n                        { name: 'ConstraintNotSatisfiedError' },\n                        {},\n                        [ desktopSharingSourceDevice ]\n                    ));\n                }\n\n                const requestedDevices = [ 'video' ];\n                const constraints = {\n                    video: {\n                        deviceId: matchingDevice.deviceId\n\n                        // frameRate is omited here on purpose since this is a device that we'll pretend is a screen.\n                    }\n                };\n\n                return this._getUserMedia(requestedDevices, constraints, timeout)\n                    .then(stream => {\n                        return {\n                            sourceType: 'device',\n                            stream\n                        };\n                    });\n            }\n\n            return this._getDesktopMedia({ desktopSharingSources });\n        }.bind(this);\n\n        /**\n         * Creates a meta data object about the passed in desktopStream and\n         * pushes the meta data to the internal array mediaStreamsMetaData to be\n         * returned later.\n         *\n         * @param {MediaStreamTrack} desktopStream - A track for a desktop\n         * capture.\n         * @returns {void}\n         */\n        const maybeCreateAndAddDesktopTrack = function(desktopStream) {\n            if (!desktopStream) {\n                return;\n            }\n\n            const { stream, sourceId, sourceType } = desktopStream;\n\n            const desktopAudioTracks = stream.getAudioTracks();\n\n            if (desktopAudioTracks.length) {\n                const desktopAudioStream = new MediaStream(desktopAudioTracks);\n\n                mediaStreamsMetaData.push({\n                    stream: desktopAudioStream,\n                    sourceId,\n                    sourceType,\n                    track: desktopAudioStream.getAudioTracks()[0]\n                });\n            }\n\n            const desktopVideoTracks = stream.getVideoTracks();\n\n            if (desktopVideoTracks.length) {\n                const desktopVideoStream = new MediaStream(desktopVideoTracks);\n\n                mediaStreamsMetaData.push({\n                    stream: desktopVideoStream,\n                    sourceId,\n                    sourceType,\n                    track: desktopVideoStream.getVideoTracks()[0],\n                    videoType: VideoType.DESKTOP\n                });\n            }\n        };\n\n        /**\n         * Executes a request for audio and/or video, as specified in options.\n         * By default both audio and video will be captured if options.devices\n         * is not defined.\n         *\n         * @returns {Promise}\n         */\n        const maybeRequestCaptureDevices = function() {\n            const umDevices = otherOptions.devices || [ 'audio', 'video' ];\n            const requestedCaptureDevices = umDevices.filter(device => device === 'audio' || device === 'video');\n\n            if (!requestedCaptureDevices.length) {\n                return Promise.resolve();\n            }\n\n            const constraints = getConstraints(requestedCaptureDevices, otherOptions);\n\n            logger.info('Got media constraints: ', JSON.stringify(constraints));\n\n            return this._getUserMedia(requestedCaptureDevices, constraints, timeout);\n        }.bind(this);\n\n        /**\n         * Splits the passed in media stream into separate audio and video\n         * streams and creates meta data objects for each and pushes them to the\n         * internal array mediaStreamsMetaData to be returned later.\n         *\n         * @param {MediaStreamTrack} avStream - A track for with audio and/or\n         * video track.\n         * @returns {void}\n         */\n        const maybeCreateAndAddAVTracks = function(avStream) {\n            if (!avStream) {\n                return;\n            }\n\n            const audioTracks = avStream.getAudioTracks();\n\n            if (audioTracks.length) {\n                const audioStream = new MediaStream(audioTracks);\n\n                mediaStreamsMetaData.push({\n                    stream: audioStream,\n                    track: audioStream.getAudioTracks()[0],\n                    effects: otherOptions.effects\n                });\n            }\n\n            const videoTracks = avStream.getVideoTracks();\n\n            if (videoTracks.length) {\n                const videoStream = new MediaStream(videoTracks);\n\n                mediaStreamsMetaData.push({\n                    stream: videoStream,\n                    track: videoStream.getVideoTracks()[0],\n                    videoType: VideoType.CAMERA,\n                    effects: otherOptions.effects\n                });\n            }\n        };\n\n        return maybeRequestDesktopDevice()\n            .then(maybeCreateAndAddDesktopTrack)\n            .then(maybeRequestCaptureDevices)\n            .then(maybeCreateAndAddAVTracks)\n            .then(() => mediaStreamsMetaData)\n            .catch(error => {\n                mediaStreamsMetaData.forEach(({ stream }) => {\n                    this.stopMediaStream(stream);\n                });\n\n                return Promise.reject(error);\n            });\n    }\n\n    /**\n     * Checks whether it is possible to enumerate available cameras/microphones.\n     *\n     * @returns {boolean} {@code true} if the device listing is available;\n     * {@code false}, otherwise.\n     */\n    isDeviceListAvailable() {\n        return Boolean(\n            navigator.mediaDevices\n                && navigator.mediaDevices.enumerateDevices);\n    }\n\n    /**\n     * Returns true if changing the input (camera / microphone) or output\n     * (audio) device is supported and false if not.\n     * @params {string} [deviceType] - type of device to change. Default is\n     *      undefined or 'input', 'output' - for audio output device change.\n     * @returns {boolean} true if available, false otherwise.\n     */\n    isDeviceChangeAvailable(deviceType) {\n        if (deviceType === 'output' || deviceType === 'audiooutput') {\n            return isAudioOutputDeviceChangeAvailable;\n        }\n\n        return true;\n    }\n\n    /**\n     * A method to handle stopping of the stream.\n     * One point to handle the differences in various implementations.\n     * @param mediaStream MediaStream object to stop.\n     */\n    stopMediaStream(mediaStream) {\n        if (!mediaStream) {\n            return;\n        }\n\n        mediaStream.getTracks().forEach(track => {\n            if (track.stop) {\n                track.stop();\n            }\n        });\n\n        // leave stop for implementation still using it\n        if (mediaStream.stop) {\n            mediaStream.stop();\n        }\n\n        // The MediaStream implementation of the react-native-webrtc project has\n        // an explicit release method that is to be invoked in order to release\n        // used resources such as memory.\n        if (mediaStream.release) {\n            mediaStream.release();\n        }\n    }\n\n    /**\n     * Returns whether the desktop sharing is enabled or not.\n     * @returns {boolean}\n     */\n    isDesktopSharingEnabled() {\n        return screenObtainer.isSupported();\n    }\n\n    /**\n     * Sets current audio output device.\n     * @param {string} deviceId - id of 'audiooutput' device from\n     *      navigator.mediaDevices.enumerateDevices(), 'default' for default\n     *      device\n     * @returns {Promise} - resolves when audio output is changed, is rejected\n     *      otherwise\n     */\n    setAudioOutputDevice(deviceId) {\n        if (!this.isDeviceChangeAvailable('output')) {\n            return Promise.reject(\n                new Error('Audio output device change is not supported'));\n        }\n\n        return featureDetectionAudioEl.setSinkId(deviceId)\n            .then(() => {\n                audioOutputDeviceId = deviceId;\n                audioOutputChanged = true;\n\n                logger.log(`Audio output device set to ${deviceId}`);\n\n                eventEmitter.emit(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\n                    deviceId);\n            });\n    }\n\n    /**\n     * Sets the capture frame rate for desktop tracks.\n     *\n     * @param {number} maxFps - max fps to be used as the capture frame rate.\n     * @returns {void}\n     */\n    setDesktopSharingFrameRate(maxFps) {\n        screenObtainer.setDesktopSharingFrameRate(maxFps);\n    }\n\n    /**\n     * Returns currently used audio output device id, '' stands for default\n     * device\n     * @returns {string}\n     */\n    getAudioOutputDevice() {\n        return audioOutputDeviceId;\n    }\n\n    /**\n     * Returns list of available media devices if its obtained, otherwise an\n     * empty array is returned/\n     * @returns {Array} list of available media devices.\n     */\n    getCurrentlyAvailableMediaDevices() {\n        return availableDevices;\n    }\n\n    /**\n     * Returns whether available devices have permissions granted\n     * @returns {Boolean}\n     */\n    arePermissionsGrantedForAvailableDevices() {\n        return availableDevices.some(device => Boolean(device.label));\n    }\n\n    /**\n     * Returns event data for device to be reported to stats.\n     * @returns {MediaDeviceInfo} device.\n     */\n    getEventDataForActiveDevice(device) {\n        const deviceList = [];\n        const deviceData = {\n            'deviceId': device.deviceId,\n            'kind': device.kind,\n            'label': device.label,\n            'groupId': device.groupId\n        };\n\n        deviceList.push(deviceData);\n\n        return { deviceList };\n    }\n}\n\nconst rtcUtils = new RTCUtils();\n\n/**\n * Wraps original attachMediaStream function to set current audio output device\n * if this is supported.\n * @param {Function} origAttachMediaStream\n * @returns {Function}\n */\nfunction wrapAttachMediaStream(origAttachMediaStream) {\n    return function(element, stream) {\n        // eslint-disable-next-line prefer-rest-params\n        const res = origAttachMediaStream.apply(rtcUtils, arguments);\n\n        if (stream\n                && rtcUtils.isDeviceChangeAvailable('output')\n                && stream.getAudioTracks\n                && stream.getAudioTracks().length\n\n                // we skip setting audio output if there was no explicit change\n                && audioOutputChanged) {\n            element.setSinkId(rtcUtils.getAudioOutputDevice())\n                .catch(function(ex) {\n                    const err\n                        = new JitsiTrackError(ex, null, [ 'audiooutput' ]);\n\n                    GlobalOnErrorHandler.callUnhandledRejectionHandler({\n                        promise: this, // eslint-disable-line no-invalid-this\n                        reason: err\n                    });\n\n                    logger.warn(\n                        'Failed to set audio output device for the element.'\n                            + ' Default audio output device will be used'\n                            + ' instead',\n                        element,\n                        err);\n                });\n        }\n\n        return res;\n    };\n}\n\nexport default rtcUtils;\n","import { getLogger } from '@jitsi/logger';\nimport EventEmitter from 'events';\n\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport browser from '../browser';\n\nimport RTCUtils from './RTCUtils';\n\nconst logger = getLogger(__filename);\n\n/**\n * Maps our handler types to MediaStreamTrack properties.\n */\nconst trackHandler2Prop = {\n    'track_mute': 'onmute', // Not supported on FF\n    'track_unmute': 'onunmute',\n    'track_ended': 'onended'\n};\n\n/**\n * Represents a single media track (either audio or video).\n */\nexport default class JitsiTrack extends EventEmitter {\n    /* eslint-disable max-params */\n    /**\n     * Represents a single media track (either audio or video).\n     * @constructor\n     * @param conference the rtc instance\n     * @param stream the WebRTC MediaStream instance\n     * @param track the WebRTC MediaStreamTrack instance, must be part of\n     * the given <tt>stream</tt>.\n     * @param streamInactiveHandler the function that will handle\n     *        onended/oninactive events of the stream.\n     * @param trackMediaType the media type of the JitsiTrack\n     * @param videoType the VideoType for this track if any\n     */\n    constructor(\n            conference,\n            stream,\n            track,\n            streamInactiveHandler,\n            trackMediaType,\n            videoType) {\n        super();\n\n        // aliases for addListener/removeListener\n        this.addEventListener = this.addListener;\n        this.removeEventListener = this.off = this.removeListener;\n\n        /**\n         * Array with the HTML elements that are displaying the streams.\n         * @type {Array}\n         */\n        this.containers = [];\n        this.conference = conference;\n        this.audioLevel = -1;\n        this.type = trackMediaType;\n        this.track = track;\n        this.videoType = videoType;\n        this.handlers = new Map();\n\n        /**\n         * Indicates whether this JitsiTrack has been disposed. If true, this\n         * JitsiTrack is to be considered unusable and operations involving it\n         * are to fail (e.g. {@link JitsiConference#addTrack(JitsiTrack)},\n         * {@link JitsiConference#removeTrack(JitsiTrack)}).\n         * @type {boolean}\n         */\n        this.disposed = false;\n\n        /**\n         * The inactive handler which will be triggered when the underlying\n         * <tt>MediaStream</tt> ends.\n         *\n         * @private\n         * @type {Function}\n         */\n        this._streamInactiveHandler = streamInactiveHandler;\n\n        this._setStream(stream);\n    }\n\n    /**\n     * Adds onended/oninactive handler to a MediaStream or a MediaStreamTrack.\n     * Firefox doesn't fire a inactive event on the MediaStream, instead it fires\n     * a onended event on the MediaStreamTrack.\n     * @param {Function} handler the handler\n     */\n    _addMediaStreamInactiveHandler(handler) {\n        if (browser.isFirefox()) {\n            this.track.onended = handler;\n        } else {\n            this.stream.oninactive = handler;\n        }\n    }\n\n    /**\n     * Attach time to first media tracker only if there is conference and only\n     * for the first element.\n     *\n     * @param {HTMLElement} container the HTML container which can be 'video' or\n     * 'audio' element.\n     * @private\n     */\n    _attachTTFMTracker(container) { // eslint-disable-line no-unused-vars\n        // Should be defined by the classes that are extending JitsiTrack\n    }\n\n    /**\n     * Eventually will trigger RTCEvents.TRACK_ATTACHED event.\n     * @param container the video/audio container to which this stream is\n     *        attached and for which event will be fired.\n     * @private\n     */\n    _maybeFireTrackAttached(container) {\n        if (this.conference && container) {\n            this.conference._onTrackAttach(this, container);\n        }\n    }\n\n    /**\n     * Called when the track has been attached to a new container.\n     *\n     * @param {HTMLElement} container the HTML container which can be 'video' or\n     * 'audio' element.\n     * @private\n     */\n    _onTrackAttach(container) { // eslint-disable-line no-unused-vars\n        // Should be defined by the classes that are extending JitsiTrack\n    }\n\n    /**\n     * Called when the track has been detached from a container.\n     *\n     * @param {HTMLElement} container the HTML container which can be 'video' or\n     * 'audio' element.\n     * @private\n     */\n    _onTrackDetach(container) { // eslint-disable-line no-unused-vars\n        // Should be defined by the classes that are extending JitsiTrack\n    }\n\n    /**\n     * Sets handler to the WebRTC MediaStream or MediaStreamTrack object\n     * depending on the passed type.\n     * @param {string} type the type of the handler that is going to be set\n     * @param {Function} handler the handler.\n     */\n    _setHandler(type, handler) {\n        if (!trackHandler2Prop.hasOwnProperty(type)) {\n            logger.error(`Invalid handler type ${type}`);\n\n            return;\n        }\n        if (handler) {\n            this.handlers.set(type, handler);\n        } else {\n            this.handlers.delete(type);\n        }\n\n        if (this.stream) {\n            for (const track of this.stream.getTracks()) {\n                track[trackHandler2Prop[type]] = handler;\n            }\n        }\n    }\n\n    /**\n     * Sets the stream property of JitsiTrack object and sets all stored\n     * handlers to it.\n     *\n     * @param {MediaStream} stream the new stream.\n     * @protected\n     */\n    _setStream(stream) {\n        if (this.stream === stream) {\n            return;\n        }\n\n        this.stream = stream;\n\n        // TODO Practically, that's like the opposite of _unregisterHandlers\n        // i.e. may be abstracted into a function/method called\n        // _registerHandlers for clarity and easing the maintenance of the two\n        // pieces of source code.\n        if (this.stream) {\n            for (const type of this.handlers.keys()) {\n                this._setHandler(type, this.handlers.get(type));\n            }\n            if (this._streamInactiveHandler) {\n                this._addMediaStreamInactiveHandler(this._streamInactiveHandler);\n            }\n        }\n    }\n\n    /**\n     * Unregisters all event handlers bound to the underlying media stream/track\n     * @private\n     */\n    _unregisterHandlers() {\n        if (!this.stream) {\n            logger.warn(\n                `${this}: unable to unregister handlers - no stream object`);\n\n            return;\n        }\n\n        for (const type of this.handlers.keys()) {\n            // FIXME Why only video tracks?\n            for (const videoTrack of this.stream.getVideoTracks()) {\n                videoTrack[trackHandler2Prop[type]] = undefined;\n            }\n        }\n        if (this._streamInactiveHandler) {\n            this._addMediaStreamInactiveHandler(undefined);\n        }\n    }\n\n    /**\n     * Attaches the MediaStream of this track to an HTML container.\n     * Adds the container to the list of containers that are displaying the\n     * track.\n     *\n     * @param container the HTML container which can be 'video' or 'audio'\n     * element.\n     *\n     * @returns {void}\n     */\n    attach(container) {\n        if (this.stream) {\n            this._onTrackAttach(container);\n            RTCUtils.attachMediaStream(container, this.stream);\n        }\n        this.containers.push(container);\n        this._maybeFireTrackAttached(container);\n        this._attachTTFMTracker(container);\n    }\n\n    /**\n     * Removes this JitsiTrack from the passed HTML container.\n     *\n     * @param container the HTML container to detach from this JitsiTrack. If\n     * <tt>null</tt> or <tt>undefined</tt>, all containers are removed. A\n     * container can be a 'video', 'audio' or 'object' HTML element instance to\n     * which this JitsiTrack is currently attached.\n     */\n    detach(container) {\n        for (let cs = this.containers, i = cs.length - 1; i >= 0; --i) {\n            const c = cs[i];\n\n            if (!container) {\n                this._onTrackDetach(c);\n                RTCUtils.attachMediaStream(c, null);\n            }\n            if (!container || c === container) {\n                cs.splice(i, 1);\n            }\n        }\n\n        if (container) {\n            this._onTrackDetach(container);\n            RTCUtils.attachMediaStream(container, null);\n        }\n    }\n\n    /**\n     * Removes attached event listeners.\n     *\n     * @returns {Promise}\n     */\n    dispose() {\n        this.removeAllListeners();\n\n        this.disposed = true;\n\n        return Promise.resolve();\n    }\n\n    /**\n     * Returns id of the track.\n     * @returns {string|null} id of the track or null if this is fake track.\n     */\n    getId() {\n        return this.getStreamId();\n    }\n\n    /**\n     * Returns the msid of the stream attached to the JitsiTrack object or null\n     * if no stream is attached.\n     */\n    getMSID() {\n        const streamId = this.getStreamId();\n        const trackId = this.getTrackId();\n\n        return streamId && trackId ? `${streamId} ${trackId}` : null;\n    }\n\n    /**\n     * Returns the WebRTC MediaStream instance.\n     */\n    getOriginalStream() {\n        return this.stream;\n    }\n\n    /**\n     * Returns the source name of the track.\n     * @returns {String|undefined}\n     */\n    getSourceName() { // eslint-disable-line no-unused-vars\n        // Should be defined by the classes that are extending JitsiTrack\n    }\n\n    /**\n     * Returns the ID of the underlying WebRTC Media Stream(if any)\n     * @returns {String|null}\n     */\n    getStreamId() {\n        return this.stream ? this.stream.id : null;\n    }\n\n    /**\n     * Return the underlying WebRTC MediaStreamTrack\n     * @returns {MediaStreamTrack}\n     */\n    getTrack() {\n        return this.track;\n    }\n\n    /**\n     * Return the underlying WebRTC MediaStreamTrack label\n     * @returns {string}\n     */\n    getTrackLabel() {\n        return this.track.label;\n    }\n\n    /**\n     * Returns the ID of the underlying WebRTC MediaStreamTrack(if any)\n     * @returns {String|null}\n     */\n    getTrackId() {\n        return this.track ? this.track.id : null;\n    }\n\n    /**\n     * Returns the type (audio or video) of this track.\n     */\n    getType() {\n        return this.type;\n    }\n\n    /**\n     * Return meaningful usage label for this track depending on it's media and\n     * eventual video type.\n     * @returns {string}\n     */\n    getUsageLabel() {\n        if (this.isAudioTrack()) {\n            return 'mic';\n        }\n\n        return this.videoType ? this.videoType : 'default';\n    }\n\n    /**\n     * Returns the video type (camera or desktop) of this track.\n     */\n    getVideoType() {\n        return this.videoType;\n    }\n\n    /**\n     * Checks whether the MediaStream is active/not ended.\n     * When there is no check for active we don't have information and so\n     * will return that stream is active (in case of FF).\n     * @returns {boolean} whether MediaStream is active.\n     */\n    isActive() {\n        if (typeof this.stream.active !== 'undefined') {\n            return this.stream.active;\n        }\n\n        return true;\n    }\n\n    /**\n     * Check if this is an audio track.\n     */\n    isAudioTrack() {\n        return this.getType() === MediaType.AUDIO;\n    }\n\n    /**\n     * Checks whether this is a local track.\n     * @abstract\n     * @return {boolean} 'true' if it's a local track or 'false' otherwise.\n     */\n    isLocal() {\n        throw new Error('Not implemented by subclass');\n    }\n\n    /**\n     * Check whether this is a local audio track.\n     *\n     * @return {boolean} -  true if track represents a local audio track, false otherwise.\n     */\n    isLocalAudioTrack() {\n        return this.isAudioTrack() && this.isLocal();\n    }\n\n    /**\n     * Check if this is a video track.\n     */\n    isVideoTrack() {\n        return this.getType() === MediaType.VIDEO;\n    }\n\n    /**\n     * Checks whether the underlying WebRTC <tt>MediaStreamTrack</tt> is muted\n     * according to it's 'muted' field status.\n     * @return {boolean} <tt>true</tt> if the underlying\n     * <tt>MediaStreamTrack</tt> is muted or <tt>false</tt> otherwise.\n     */\n    isWebRTCTrackMuted() {\n        return this.track && this.track.muted;\n    }\n\n    /**\n     * Sets the audio level for the stream\n     * @param {number} audioLevel value between 0 and 1\n     * @param {TraceablePeerConnection} [tpc] the peerconnection instance which\n     * is source for the audio level. It can be <tt>undefined</tt> for\n     * a local track if the audio level was measured outside of the\n     * peerconnection (see /modules/statistics/LocalStatsCollector.js).\n     */\n    setAudioLevel(audioLevel, tpc) {\n        let newAudioLevel = audioLevel;\n\n        // When using getSynchornizationSources on the audio receiver to gather audio levels for\n        // remote tracks, browser reports last known audio levels even when the remote user is\n        // audio muted, we need to reset the value to zero here so that the audio levels are cleared.\n        // Remote tracks have the tpc info present while local tracks do not.\n        if (browser.supportsReceiverStats() && typeof tpc !== 'undefined' && this.isMuted()) {\n            newAudioLevel = 0;\n        }\n\n        if (this.audioLevel !== newAudioLevel) {\n            this.audioLevel = newAudioLevel;\n            this.emit(\n                JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,\n                newAudioLevel,\n                tpc);\n\n        // LocalStatsCollector reports a value of 0.008 for muted mics\n        // and a value of 0 when there is no audio input.\n        } else if (this.audioLevel === 0\n            && newAudioLevel === 0\n            && this.isLocal()\n            && !this.isWebRTCTrackMuted()) {\n            this.emit(\n                JitsiTrackEvents.NO_AUDIO_INPUT,\n                newAudioLevel);\n        }\n    }\n\n    /**\n     * Sets new audio output device for track's DOM elements. Video tracks are\n     * ignored.\n     * @param {string} audioOutputDeviceId - id of 'audiooutput' device from\n     *      navigator.mediaDevices.enumerateDevices(), '' for default device\n     * @emits JitsiTrackEvents.TRACK_AUDIO_OUTPUT_CHANGED\n     * @returns {Promise}\n     */\n    setAudioOutput(audioOutputDeviceId) {\n        if (!RTCUtils.isDeviceChangeAvailable('output')) {\n            return Promise.reject(\n                new Error('Audio output device change is not supported'));\n        }\n\n        // All audio communication is done through audio tracks, so ignore\n        // changing audio output for video tracks at all.\n        if (this.isVideoTrack()) {\n            return Promise.resolve();\n        }\n\n        return (\n            Promise.all(\n                this.containers.map(\n                    element =>\n                        element.setSinkId(audioOutputDeviceId)\n                            .catch(error => {\n                                logger.warn(\n                                    'Failed to change audio output device on'\n                                        + ' element. Default or previously set'\n                                        + ' audio output device will be used.',\n                                    element,\n                                    error);\n                                throw error;\n                            }))\n            )\n                .then(() => {\n                    this.emit(\n                        JitsiTrackEvents.TRACK_AUDIO_OUTPUT_CHANGED,\n                        audioOutputDeviceId);\n                }));\n    }\n\n    /**\n     * Assigns the source name to a track.\n     * @param {String} name - The name to be assigned to the track.\n     * @returns {void}\n     */\n    setSourceName(name) { // eslint-disable-line no-unused-vars\n        // Should be defined by the classes that are extending JitsiTrack\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport JitsiTrackError from '../../JitsiTrackError';\nimport {\n    TRACK_IS_DISPOSED,\n    TRACK_NO_STREAM_FOUND\n} from '../../JitsiTrackErrors';\nimport {\n    LOCAL_TRACK_STOPPED,\n    NO_DATA_FROM_SOURCE,\n    TRACK_MUTE_CHANGED\n} from '../../JitsiTrackEvents';\nimport CameraFacingMode from '../../service/RTC/CameraFacingMode';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport {\n    NO_BYTES_SENT,\n    TRACK_UNMUTED,\n    createNoDataFromSourceEvent\n} from '../../service/statistics/AnalyticsEvents';\nimport browser from '../browser';\nimport FeatureFlags from '../flags/FeatureFlags';\nimport Statistics from '../statistics/statistics';\n\nimport JitsiTrack from './JitsiTrack';\nimport RTCUtils from './RTCUtils';\n\nconst logger = getLogger(__filename);\n\n/**\n * Represents a single media track(either audio or video).\n * One <tt>JitsiLocalTrack</tt> corresponds to one WebRTC MediaStreamTrack.\n */\nexport default class JitsiLocalTrack extends JitsiTrack {\n    /**\n     * Constructs a new JitsiLocalTrack instance.\n     *\n     * @constructor\n     * @param {Object} trackInfo\n     * @param {number} trackInfo.rtcId - The ID assigned by the RTC module.\n     * @param {Object} trackInfo.stream - The WebRTC MediaStream, parent of the track.\n     * @param {Object} trackInfo.track - The underlying WebRTC MediaStreamTrack for new JitsiLocalTrack.\n     * @param {string} trackInfo.mediaType - The MediaType of the JitsiLocalTrack.\n     * @param {string} trackInfo.videoType - The VideoType of the JitsiLocalTrack.\n     * @param {Array<Object>} trackInfo.effects - The effects to be applied to the JitsiLocalTrack.\n     * @param {number} trackInfo.resolution - The the video resolution if it's a video track\n     * @param {string} trackInfo.deviceId - The ID of the local device for this track.\n     * @param {string} trackInfo.facingMode - Thehe camera facing mode used in getUserMedia call (for mobile only).\n     * @param {sourceId} trackInfo.sourceId - The id of the desktop sharing source. NOTE: defined for desktop sharing\n     * tracks only.\n     */\n    constructor({\n        deviceId,\n        facingMode,\n        mediaType,\n        resolution,\n        rtcId,\n        sourceId,\n        sourceType,\n        stream,\n        track,\n        videoType,\n        effects = []\n    }) {\n        super(\n            /* conference */ null,\n            stream,\n            track,\n            /* streamInactiveHandler */ () => this.emit(LOCAL_TRACK_STOPPED, this),\n            mediaType,\n            videoType);\n\n        this._setEffectInProgress = false;\n        const effect = effects.find(e => e.isEnabled(this));\n\n        if (effect) {\n            this._startStreamEffect(effect);\n        }\n\n        const displaySurface = videoType === VideoType.DESKTOP\n            ? track.getSettings().displaySurface\n            : null;\n\n        /**\n         * Track metadata.\n         */\n        this.metadata = {\n            timestamp: Date.now(),\n            ...displaySurface ? { displaySurface } : {}\n        };\n\n\n        /**\n         * The ID assigned by the RTC module on instance creation.\n         *\n         * @type {number}\n         */\n        this.rtcId = rtcId;\n        this.sourceId = sourceId;\n        this.sourceType = sourceType ?? displaySurface;\n\n        // Get the resolution from the track itself because it cannot be\n        // certain which resolution webrtc has fallen back to using.\n        this.resolution = track.getSettings().height;\n        this.maxEnabledResolution = resolution;\n\n        // Cache the constraints of the track in case of any this track\n        // model needs to call getUserMedia again, such as when unmuting.\n        this._constraints = track.getConstraints();\n\n        // Safari returns an empty constraints object, construct the constraints using getSettings.\n        if (!Object.keys(this._constraints).length && videoType === VideoType.CAMERA) {\n            this._constraints = {\n                height: track.getSettings().height,\n                width: track.getSettings().width\n            };\n        }\n\n        this.deviceId = deviceId;\n\n        /**\n         * The <tt>Promise</tt> which represents the progress of a previously\n         * queued/scheduled {@link _setMuted} (from the point of view of\n         * {@link _queueSetMuted}).\n         *\n         * @private\n         * @type {Promise}\n         */\n        this._prevSetMuted = Promise.resolve();\n\n        /**\n         * The facing mode of the camera from which this JitsiLocalTrack\n         * instance was obtained.\n         *\n         * @private\n         * @type {CameraFacingMode|undefined}\n         */\n        this._facingMode = facingMode;\n\n        // Currently there is no way to know the MediaStreamTrack ended due to\n        // to device disconnect in Firefox through e.g. \"readyState\" property.\n        // Instead we will compare current track's label with device labels from\n        // enumerateDevices() list.\n        this._trackEnded = false;\n\n        /**\n         * Indicates whether data has been sent or not.\n         */\n        this._hasSentData = false;\n\n        /**\n         * Used only for detection of audio problems. We want to check only once\n         * whether the track is sending data ot not. This flag is set to false\n         * after the check.\n         */\n        this._testDataSent = true;\n\n        // Currently there is no way to determine with what device track was\n        // created (until getConstraints() support), however we can associate\n        // tracks with real devices obtained from enumerateDevices() call as\n        // soon as it's called.\n        // NOTE: this.deviceId corresponds to the device id specified in GUM constraints and this._realDeviceId seems to\n        // correspond to the id of a matching device from the available device list.\n        this._realDeviceId = this.deviceId === '' ? undefined : this.deviceId;\n\n        // The source name that will be signaled for this track.\n        this._sourceName = null;\n\n        this._trackMutedTS = 0;\n\n        this._onDeviceListWillChange = devices => {\n            const oldRealDeviceId = this._realDeviceId;\n\n            this._setRealDeviceIdFromDeviceList(devices);\n\n            if (\n                // Mark track as ended for those browsers that do not support\n                // \"readyState\" property. We do not touch tracks created with\n                // default device ID \"\".\n                (typeof this.getTrack().readyState === 'undefined'\n                    && typeof this._realDeviceId !== 'undefined'\n                    && !devices.find(d => d.deviceId === this._realDeviceId))\n\n                // If there was an associated realDeviceID and after the device change the realDeviceId is undefined\n                // then the associated device has been disconnected and the _trackEnded flag needs to be set. In\n                // addition on some Chrome versions the readyState property is set after the device change event is\n                // triggered which causes issues in jitsi-meet with the selection of a new device because we don't\n                // detect that the old one was removed.\n                || (typeof oldRealDeviceId !== 'undefined' && typeof this._realDeviceId === 'undefined')\n            ) {\n                this._trackEnded = true;\n            }\n        };\n\n        // Subscribe each created local audio track to\n        // RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED event. This is different from\n        // handling this event for remote tracks (which are handled in RTC.js),\n        // because there might be local tracks not attached to a conference.\n        if (this.isAudioTrack() && RTCUtils.isDeviceChangeAvailable('output')) {\n            this._onAudioOutputDeviceChanged = this.setAudioOutput.bind(this);\n            RTCUtils.addListener(\n                RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\n                this._onAudioOutputDeviceChanged);\n        }\n\n        RTCUtils.addListener(RTCEvents.DEVICE_LIST_WILL_CHANGE, this._onDeviceListWillChange);\n\n        this._initNoDataFromSourceHandlers();\n    }\n\n    /**\n     * Adds stream to conference and marks it as \"unmute\" operation.\n     *\n     * @private\n     * @returns {Promise}\n     */\n    _addStreamToConferenceAsUnmute() {\n        if (!this.conference) {\n            return Promise.resolve();\n        }\n\n        // FIXME it would be good to not included conference as part of this process. Only TraceablePeerConnections to\n        // which the track is attached should care about this action. The TPCs to which the track is not attached can\n        // sync up when track is re-attached. A problem with that is that the \"modify sources\" queue is part of the\n        // JingleSessionPC and it would be excluded from the process. One solution would be to extract class between\n        // TPC and JingleSessionPC which would contain the queue and would notify the signaling layer when local SSRCs\n        // are changed. This would help to separate XMPP from the RTC module.\n        return new Promise((resolve, reject) => {\n            this.conference._addLocalTrackToPc(this)\n                .then(resolve, error => reject(new Error(error)));\n        });\n    }\n\n    /**\n     * Fires NO_DATA_FROM_SOURCE event and logs it to analytics and callstats.\n     *\n     * @private\n     * @returns {void}\n     */\n    _fireNoDataFromSourceEvent() {\n        const value = !this.isReceivingData();\n\n        this.emit(NO_DATA_FROM_SOURCE, value);\n\n        // FIXME: Should we report all of those events\n        Statistics.sendAnalytics(createNoDataFromSourceEvent(this.getType(), value));\n        Statistics.sendLog(JSON.stringify({\n            name: NO_DATA_FROM_SOURCE,\n            log: value\n        }));\n    }\n\n    /**\n     * Sets handlers to the MediaStreamTrack object that will detect camera issues.\n     *\n     * @private\n     * @returns {void}\n     */\n    _initNoDataFromSourceHandlers() {\n        if (!this._isNoDataFromSourceEventsEnabled()) {\n            return;\n        }\n\n        this._setHandler('track_mute', () => {\n            this._trackMutedTS = window.performance.now();\n            this._fireNoDataFromSourceEvent();\n        });\n\n        this._setHandler('track_unmute', () => {\n            this._fireNoDataFromSourceEvent();\n            Statistics.sendAnalyticsAndLog(\n                TRACK_UNMUTED,\n                {\n                    'media_type': this.getType(),\n                    'track_type': 'local',\n                    value: window.performance.now() - this._trackMutedTS\n                });\n        });\n\n        if (this.isVideoTrack() && this.videoType === VideoType.CAMERA) {\n            this._setHandler('track_ended', () => {\n                if (!this.isReceivingData()) {\n                    this._fireNoDataFromSourceEvent();\n                }\n            });\n        }\n    }\n\n    /**\n     * Returns true if no data from source events are enabled for this JitsiLocalTrack and false otherwise.\n     *\n     * @private\n     * @returns {boolean} - True if no data from source events are enabled for this JitsiLocalTrack and false otherwise.\n     */\n    _isNoDataFromSourceEventsEnabled() {\n        // Disable the events for screen sharing.\n        return !this.isVideoTrack() || this.videoType !== VideoType.DESKTOP;\n    }\n\n    /**\n     * Initializes a new Promise to execute {@link #_setMuted}. May be called multiple times in a row and the\n     * invocations of {@link #_setMuted} and, consequently, {@link #mute} and/or {@link #unmute} will be resolved in a\n     * serialized fashion.\n     *\n     * @param {boolean} muted - The value to invoke <tt>_setMuted</tt> with.\n     * @private\n     * @returns {Promise}\n     */\n    _queueSetMuted(muted) {\n        const setMuted = this._setMuted.bind(this, muted);\n\n        this._prevSetMuted = this._prevSetMuted.then(setMuted, setMuted);\n\n        return this._prevSetMuted;\n    }\n\n    /**\n     * Removes stream from conference and marks it as \"mute\" operation.\n     *\n     * @param {Function} successCallback - Callback that will be called when the operation is successful.\n     * @param {Function} errorCallback - Callback that will be called when the operation fails.\n     * @private\n     * @returns {Promise}\n     */\n    _removeStreamFromConferenceAsMute(successCallback, errorCallback) {\n        if (!this.conference) {\n            successCallback();\n\n            return;\n        }\n        this.conference._removeLocalTrackFromPc(this).then(\n            successCallback,\n            error => errorCallback(new Error(error)));\n    }\n\n    /**\n     * Sends mute status for a track to conference if any.\n     *\n     * @param {boolean} mute - If track is muted.\n     * @private\n     * @returns {void}\n     */\n    _sendMuteStatus(mute) {\n        if (this.conference) {\n            this.conference._setTrackMuteStatus(this.getType(), this, mute) && this.conference.room.sendPresence();\n        }\n    }\n\n    /**\n     * Mutes / unmutes this track.\n     *\n     * @param {boolean} muted - If <tt>true</tt>, this track will be muted; otherwise, this track will be unmuted.\n     * @private\n     * @returns {Promise}\n     */\n    _setMuted(muted) {\n        if (this.isMuted() === muted\n            && !(this.videoType === VideoType.DESKTOP && FeatureFlags.isMultiStreamSendSupportEnabled())) {\n            return Promise.resolve();\n        }\n\n        if (this.disposed) {\n            return Promise.reject(new JitsiTrackError(TRACK_IS_DISPOSED));\n        }\n\n        let promise = Promise.resolve();\n\n        // A function that will print info about muted status transition\n        const logMuteInfo = () => logger.info(`Mute ${this}: ${muted}`);\n\n        // In React Native we mute the camera by setting track.enabled but that doesn't\n        // work for screen-share tracks, so do the remove-as-mute for those.\n        const doesVideoMuteByStreamRemove\n            = browser.isReactNative() ? this.videoType === VideoType.DESKTOP : browser.doesVideoMuteByStreamRemove();\n\n        // In the multi-stream mode, desktop tracks are muted from jitsi-meet instead of being removed from the\n        // conference. This is needed because we don't want the client to signal a source-remove to the remote peer for\n        // the desktop track when screenshare is stopped. Later when screenshare is started again, the same sender will\n        // be re-used without the need for signaling a new ssrc through source-add.\n        if (this.isAudioTrack()\n                || (this.videoType === VideoType.DESKTOP && !FeatureFlags.isMultiStreamSendSupportEnabled())\n                || !doesVideoMuteByStreamRemove) {\n            logMuteInfo();\n\n            // If we have a stream effect that implements its own mute functionality, prioritize it before\n            // normal mute e.g. the stream effect that implements system audio sharing has a custom\n            // mute state in which if the user mutes, system audio still has to go through.\n            if (this._streamEffect && this._streamEffect.setMuted) {\n                this._streamEffect.setMuted(muted);\n            } else if (this.track) {\n                this.track.enabled = !muted;\n            }\n        } else if (muted) {\n            promise = new Promise((resolve, reject) => {\n                logMuteInfo();\n                this._removeStreamFromConferenceAsMute(\n                    () => {\n                        if (this._streamEffect) {\n                            this._stopStreamEffect();\n                        }\n\n                        // FIXME: Maybe here we should set the SRC for the\n                        // containers to something\n                        // We don't want any events to be fired on this stream\n                        this._unregisterHandlers();\n                        this.stopStream();\n                        this._setStream(null);\n\n                        resolve();\n                    },\n                    reject);\n            });\n        } else {\n            logMuteInfo();\n\n            // This path is only for camera.\n            const streamOptions = {\n                cameraDeviceId: this.getDeviceId(),\n                devices: [ MediaType.VIDEO ],\n                effects: this._streamEffect ? [ this._streamEffect ] : [],\n                facingMode: this.getCameraFacingMode()\n            };\n\n            promise\n                = RTCUtils.obtainAudioAndVideoPermissions(Object.assign(\n                    {},\n                    streamOptions,\n                    { constraints: { video: this._constraints } }));\n\n            promise = promise.then(streamsInfo => {\n                const streamInfo = streamsInfo.find(info => info.track.kind === this.getType());\n\n                if (streamInfo) {\n                    this._setStream(streamInfo.stream);\n                    this.track = streamInfo.track;\n\n                    // This is not good when video type changes after\n                    // unmute, but let's not crash here\n                    if (this.videoType !== streamInfo.videoType) {\n                        logger.warn(\n                            `${this}: video type has changed after unmute!`,\n                            this.videoType, streamInfo.videoType);\n                        this.videoType = streamInfo.videoType;\n                    }\n                } else {\n                    throw new JitsiTrackError(TRACK_NO_STREAM_FOUND);\n                }\n\n                if (this._streamEffect) {\n                    this._startStreamEffect(this._streamEffect);\n                }\n\n                this.containers.map(cont => RTCUtils.attachMediaStream(cont, this.stream));\n\n                return this._addStreamToConferenceAsUnmute();\n            });\n        }\n\n        return promise\n            .then(() => {\n                this._sendMuteStatus(muted);\n\n                // Send the videoType message to the bridge.\n                this.isVideoTrack() && this.conference && this.conference._sendBridgeVideoTypeMessage(this);\n                this.emit(TRACK_MUTE_CHANGED, this);\n            });\n    }\n\n    /**\n     * Sets real device ID by comparing track information with device information. This is temporary solution until\n     * getConstraints() method will be implemented in browsers.\n     *\n     * @param {MediaDeviceInfo[]} devices - The list of devices obtained from enumerateDevices() call.\n     * @private\n     * @returns {void}\n     */\n    _setRealDeviceIdFromDeviceList(devices) {\n        const track = this.getTrack();\n        const kind = `${track.kind}input`;\n\n        // We need to match by deviceId as well, in case of multiple devices with the same label.\n        let device = devices.find(d => d.kind === kind && d.label === track.label && d.deviceId === this.deviceId);\n\n        if (!device && this._realDeviceId === 'default') { // the default device has been changed.\n            // If the default device was 'A' and the default device is changed to 'B' the label for the track will\n            // remain 'Default - A' but the label for the device in the device list will be updated to 'A'. That's\n            // why in order to match it we need to remove the 'Default - ' part.\n            const label = (track.label || '').replace('Default - ', '');\n\n            device = devices.find(d => d.kind === kind && d.label === label);\n        }\n\n        if (device) {\n            this._realDeviceId = device.deviceId;\n        } else {\n            this._realDeviceId = undefined;\n        }\n    }\n\n    /**\n     * Sets the stream property of JitsiLocalTrack object and sets all stored handlers to it.\n     *\n     * @param {MediaStream} stream - The new MediaStream.\n     * @private\n     * @returns {void}\n     */\n    _setStream(stream) {\n        super._setStream(stream);\n\n        if (stream) {\n            // Store the MSID for video mute/unmute purposes.\n            this.storedMSID = this.getMSID();\n            logger.debug(`Setting new MSID: ${this.storedMSID} on ${this}`);\n        } else {\n            logger.debug(`Setting 'null' stream on ${this}`);\n        }\n    }\n\n    /**\n     * Starts the effect process and returns the modified stream.\n     *\n     * @param {Object} effect - Represents effect instance\n     * @private\n     * @returns {void}\n     */\n    _startStreamEffect(effect) {\n        this._streamEffect = effect;\n        this._originalStream = this.stream;\n        this._setStream(this._streamEffect.startEffect(this._originalStream));\n        this.track = this.stream.getTracks()[0];\n    }\n\n    /**\n     * Stops the effect process and returns the original stream.\n     *\n     * @private\n     * @returns {void}\n     */\n    _stopStreamEffect() {\n        if (this._streamEffect) {\n            this._streamEffect.stopEffect();\n            this._setStream(this._originalStream);\n            this._originalStream = null;\n            this.track = this.stream ? this.stream.getTracks()[0] : null;\n        }\n    }\n\n    /**\n     * Switches the camera facing mode if the WebRTC implementation supports the custom MediaStreamTrack._switchCamera\n     * method. Currently, the method in question is implemented in react-native-webrtc only. When such a WebRTC\n     * implementation is executing, the method is the preferred way to switch between the front/user-facing and the\n     * back/environment-facing cameras because it will likely be (as is the case of react-native-webrtc) noticeably\n     * faster that creating a new MediaStreamTrack via a new getUserMedia call with the switched facingMode constraint\n     * value. Moreover, the approach with a new getUserMedia call may not even work: WebRTC on Android and iOS is\n     * either very slow to open the camera a second time or plainly freezes attempting to do that.\n     *\n     * @returns {void}\n     */\n    _switchCamera() {\n        if (this.isVideoTrack()\n                && this.videoType === VideoType.CAMERA\n                && typeof this.track._switchCamera === 'function') {\n            this.track._switchCamera();\n\n            this._facingMode\n                = this._facingMode === CameraFacingMode.ENVIRONMENT\n                    ? CameraFacingMode.USER\n                    : CameraFacingMode.ENVIRONMENT;\n        }\n    }\n\n    /**\n     * Stops the currently used effect (if there is one) and starts the passed effect (if there is one).\n     *\n     * @param {Object|undefined} effect - The new effect to be set.\n     * @private\n     * @returns {void}\n     */\n    _switchStreamEffect(effect) {\n        if (this._streamEffect) {\n            this._stopStreamEffect();\n            this._streamEffect = undefined;\n        }\n        if (effect) {\n            this._startStreamEffect(effect);\n        }\n    }\n\n    /**\n     * @inheritdoc\n     *\n     * Stops sending the media track. And removes it from the HTML. NOTE: Works for local tracks only.\n     *\n     * @extends JitsiTrack#dispose\n     * @returns {Promise}\n     */\n    async dispose() {\n\n        // Remove the effect instead of stopping it so that the original stream is restored\n        // on both the local track and on the peerconnection.\n        if (this._streamEffect) {\n            await this.setEffect();\n        }\n\n        if (this.conference) {\n            await this.conference.removeTrack(this);\n        }\n\n        if (this.stream) {\n            this.stopStream();\n            this.detach();\n        }\n\n        RTCUtils.removeListener(RTCEvents.DEVICE_LIST_WILL_CHANGE, this._onDeviceListWillChange);\n\n        if (this._onAudioOutputDeviceChanged) {\n            RTCUtils.removeListener(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\n                this._onAudioOutputDeviceChanged);\n        }\n\n        return super.dispose();\n    }\n\n    /**\n     * Returns facing mode for video track from camera. For other cases (e.g. audio track or 'desktop' video track)\n     * returns undefined.\n     *\n     * @returns {CameraFacingMode|undefined}\n     */\n    getCameraFacingMode() {\n        if (this.isVideoTrack() && this.videoType === VideoType.CAMERA) {\n            // MediaStreamTrack#getSettings() is not implemented in many\n            // browsers, so we need feature checking here. Progress on the\n            // respective browser's implementation can be tracked at\n            // https://bugs.chromium.org/p/webrtc/issues/detail?id=2481 for\n            // Chromium and https://bugzilla.mozilla.org/show_bug.cgi?id=1213517\n            // for Firefox. Even if a browser implements getSettings() already,\n            // it might still not return anything for 'facingMode'.\n            const trackSettings = this.track.getSettings?.();\n\n            if (trackSettings && 'facingMode' in trackSettings) {\n                return trackSettings.facingMode;\n            }\n\n            if (typeof this._facingMode !== 'undefined') {\n                return this._facingMode;\n            }\n\n            // In most cases we are showing a webcam. So if we've gotten here,\n            // it should be relatively safe to assume that we are probably\n            // showing the user-facing camera.\n            return CameraFacingMode.USER;\n        }\n\n        return undefined;\n    }\n\n    /**\n     * Returns device id associated with track.\n     *\n     * @returns {string}\n     */\n    getDeviceId() {\n        return this._realDeviceId || this.deviceId;\n    }\n\n    /**\n     * Get the duration of the track.\n     *\n     * @returns {Number} the duration of the track in seconds\n     */\n    getDuration() {\n        return (Date.now() / 1000) - (this.metadata.timestamp / 1000);\n    }\n\n    /**\n     * Returns the participant id which owns the track.\n     *\n     * @returns {string} the id of the participants. It corresponds to the\n     * Colibri endpoint id/MUC nickname in case of Jitsi-meet.\n     */\n    getParticipantId() {\n        return this.conference && this.conference.myUserId();\n    }\n\n    /**\n     * Returns the source name associated with the jitsi track.\n     *\n     * @returns {string | null} source name\n     */\n    getSourceName() {\n        return this._sourceName;\n    }\n\n    /**\n     * Returns if associated MediaStreamTrack is in the 'ended' state\n     *\n     * @returns {boolean}\n     */\n    isEnded() {\n        if (this.isVideoTrack() && this.isMuted()) {\n            // If a video track is muted the readyState will be ended, that's why we need to rely only on the\n            // _trackEnded flag.\n            return this._trackEnded;\n        }\n\n        return this.getTrack().readyState === 'ended' || this._trackEnded;\n    }\n\n    /**\n     * Returns <tt>true</tt>.\n     *\n     * @returns {boolean} <tt>true</tt>\n     */\n    isLocal() {\n        return true;\n    }\n\n    /**\n     * Returns <tt>true</tt> - if the stream is muted and <tt>false</tt> otherwise.\n     *\n     * @returns {boolean} <tt>true</tt> - if the stream is muted and <tt>false</tt> otherwise.\n     */\n    isMuted() {\n        // this.stream will be null when we mute local video on Chrome\n        if (!this.stream) {\n            return true;\n        }\n        if (this.isVideoTrack() && !this.isActive()) {\n            return true;\n        }\n\n        // If currently used stream effect has its own muted state, use that.\n        if (this._streamEffect && this._streamEffect.isMuted) {\n            return this._streamEffect.isMuted();\n        }\n\n        return !this.track || !this.track.enabled;\n    }\n\n    /**\n     * Checks whether the attached MediaStream is receiving data from source or not. If the stream property is null\n     * (because of mute or another reason) this method will return false.\n     * NOTE: This method doesn't indicate problem with the streams directly. For example in case of video mute the\n     * method will return false or if the user has disposed the track.\n     *\n     * @returns {boolean} true if the stream is receiving data and false this otherwise.\n     */\n    isReceivingData() {\n        if (this.isVideoTrack()\n            && (this.isMuted() || this._stopStreamInProgress || this.videoType === VideoType.DESKTOP)) {\n            return true;\n        }\n\n        if (!this.stream) {\n            return false;\n        }\n\n        // In older version of the spec there is no muted property and readyState can have value muted. In the latest\n        // versions readyState can have values \"live\" and \"ended\" and there is muted boolean property. If the stream is\n        // muted that means that we aren't receiving any data from the source. We want to notify the users for error if\n        // the stream is muted or ended on it's creation.\n\n        // For video blur enabled use the original video stream\n        const stream = this._effectEnabled ? this._originalStream : this.stream;\n\n        return stream.getTracks().some(track =>\n            (!('readyState' in track) || track.readyState === 'live')\n                && (!('muted' in track) || track.muted !== true));\n    }\n\n    /**\n     * Asynchronously mutes this track.\n     *\n     * @returns {Promise}\n     */\n    mute() {\n        return this._queueSetMuted(true);\n    }\n\n    /**\n     * Handles bytes sent statistics. NOTE: used only for audio tracks to detect audio issues.\n     *\n     * @param {TraceablePeerConnection} tpc - The peerconnection that is reporting the bytes sent stat.\n     * @param {number} bytesSent - The new value.\n     * @returns {void}\n     */\n    onByteSentStatsReceived(tpc, bytesSent) {\n        if (bytesSent > 0) {\n            this._hasSentData = true;\n        }\n        const iceConnectionState = tpc.getConnectionState();\n\n        if (this._testDataSent && iceConnectionState === 'connected') {\n            setTimeout(() => {\n                if (!this._hasSentData) {\n                    logger.warn(`${this} 'bytes sent' <= 0: \\\n                        ${bytesSent}`);\n\n                    Statistics.analytics.sendEvent(NO_BYTES_SENT, { 'media_type': this.getType() });\n                }\n            }, 3000);\n            this._testDataSent = false;\n        }\n    }\n\n    /**\n     * Sets the JitsiConference object associated with the track. This is temp solution.\n     *\n     * @param conference - JitsiConference object.\n     * @returns {void}\n     */\n    setConference(conference) {\n        this.conference = conference;\n\n        // We want to keep up with postponed events which should have been fired\n        // on \"attach\" call, but for local track we not always have the\n        // conference before attaching. However this may result in duplicated\n        // events if they have been triggered on \"attach\" already.\n        for (let i = 0; i < this.containers.length; i++) {\n            this._maybeFireTrackAttached(this.containers[i]);\n        }\n    }\n\n    /**\n     * Sets the effect and switches between the modified stream and original one.\n     *\n     * @param {Object} effect - Represents the effect instance to be used.\n     * @returns {Promise}\n     */\n    setEffect(effect) {\n        if (typeof this._streamEffect === 'undefined' && typeof effect === 'undefined') {\n            return Promise.resolve();\n        }\n\n        if (typeof effect !== 'undefined' && !effect.isEnabled(this)) {\n            return Promise.reject(new Error('Incompatible effect instance!'));\n        }\n\n        if (this._setEffectInProgress === true) {\n            return Promise.reject(new Error('setEffect already in progress!'));\n        }\n\n        // In case we have an audio track that is being enhanced with an effect, we still want it to be applied,\n        // even if the track is muted. Where as for video the actual track doesn't exists if it's muted.\n        if (this.isMuted() && !this.isAudioTrack()) {\n            this._streamEffect = effect;\n\n            return Promise.resolve();\n        }\n\n        const conference = this.conference;\n\n        if (!conference) {\n            this._switchStreamEffect(effect);\n            if (this.isVideoTrack()) {\n                this.containers.forEach(cont => RTCUtils.attachMediaStream(cont, this.stream));\n            }\n\n            return Promise.resolve();\n        }\n\n        this._setEffectInProgress = true;\n\n        return conference._removeLocalTrackFromPc(this)\n            .then(() => {\n                this._switchStreamEffect(effect);\n                if (this.isVideoTrack()) {\n                    this.containers.forEach(cont => RTCUtils.attachMediaStream(cont, this.stream));\n                }\n\n                return conference._addLocalTrackToPc(this);\n            })\n            .then(() => {\n                this._setEffectInProgress = false;\n            })\n            .catch(error => {\n                // Any error will be not recovarable and will trigger CONFERENCE_FAILED event. But let's try to cleanup\n                // everyhting related to the effect functionality.\n                this._setEffectInProgress = false;\n                this._switchStreamEffect();\n                logger.error('Failed to switch to the new stream!', error);\n                throw error;\n            });\n    }\n\n    /**\n     * Sets the source name to be used for signaling the jitsi track.\n     *\n     * @param {string} name The source name.\n     */\n    setSourceName(name) {\n        this._sourceName = name;\n    }\n\n    /**\n     * Stops the associated MediaStream.\n     *\n     * @returns {void}\n     */\n    stopStream() {\n        /**\n         * Indicates that we are executing {@link #stopStream} i.e.\n         * {@link RTCUtils#stopMediaStream} for the <tt>MediaStream</tt>\n         * associated with this <tt>JitsiTrack</tt> instance.\n         *\n         * @private\n         * @type {boolean}\n         */\n        this._stopStreamInProgress = true;\n\n        try {\n            RTCUtils.stopMediaStream(this.stream);\n        } finally {\n            this._stopStreamInProgress = false;\n        }\n    }\n\n    /**\n     * Creates a text representation of this local track instance.\n     *\n     * @return {string}\n     */\n    toString() {\n        return `LocalTrack[${this.rtcId},${this.getType()}]`;\n    }\n\n    /**\n     * Asynchronously unmutes this track.\n     *\n     * @returns {Promise}\n     */\n    unmute() {\n        return this._queueSetMuted(false);\n    }\n}\n","/* Copyright @ 2015 - Present, 8x8 Inc\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport transform from 'sdp-transform';\n\n/**\n * Rewrites the source information in the way sdp-transform expects.\n * Source information is split into multiple ssrc objects each containing\n * an id, attribute and value.\n * @param {Object} media - media description to be modified.\n * @returns {void}\n */\nconst write = function(session, opts) {\n    if (typeof session !== 'undefined' && typeof session.media !== 'undefined' && Array.isArray(session.media)) {\n        session.media.forEach(mLine => {\n            if (mLine.sources && mLine.sources.length) {\n                mLine.ssrcs = [];\n                mLine.sources.forEach(source => {\n                    Object.keys(source).forEach(attribute => {\n                        if (attribute === 'id') {\n                            return;\n                        }\n                        mLine.ssrcs.push({\n                            id: source.id,\n                            attribute,\n                            value: source[attribute]\n                        });\n                    });\n                });\n                delete mLine.sources;\n            }\n\n            // join ssrcs in ssrc groups\n            if (mLine.ssrcGroups && mLine.ssrcGroups.length) {\n                mLine.ssrcGroups.forEach(ssrcGroup => {\n                    if (typeof ssrcGroup.ssrcs !== 'undefined'\n                    && Array.isArray(ssrcGroup.ssrcs)) {\n                        ssrcGroup.ssrcs = ssrcGroup.ssrcs.join(' ');\n                    }\n                });\n            }\n        });\n    }\n\n    return transform.write(session, opts);\n};\n\n/**\n * Rewrites the source information that we get from sdp-transform.\n * All the ssrc lines with different attributes that belong to the\n * same ssrc are grouped into a single soure object with multiple key value pairs.\n * @param {Object} media - media description to be modified.\n * @returns {void}\n */\nconst parse = function(sdp) {\n    const session = transform.parse(sdp);\n\n    if (typeof session !== 'undefined' && typeof session.media !== 'undefined' && Array.isArray(session.media)) {\n        session.media.forEach(mLine => {\n            // group sources attributes by ssrc\n            if (typeof mLine.ssrcs !== 'undefined' && Array.isArray(mLine.ssrcs)) {\n                mLine.sources = [];\n                mLine.ssrcs.forEach(ssrc => {\n                    const found = mLine.sources.findIndex(source => source.id === ssrc.id);\n\n                    if (found > -1) {\n                        mLine.sources[found][ssrc.attribute] = ssrc.value;\n                    } else {\n                        const src = { id: ssrc.id };\n\n                        src[ssrc.attribute] = ssrc.value;\n                        mLine.sources.push(src);\n                    }\n                });\n                delete mLine.ssrcs;\n            }\n\n            // split ssrcs in ssrc groups\n            if (typeof mLine.ssrcGroups !== 'undefined' && Array.isArray(mLine.ssrcGroups)) {\n                mLine.ssrcGroups.forEach(ssrcGroup => {\n                    if (typeof ssrcGroup.ssrcs === 'string') {\n                        ssrcGroup.ssrcs = ssrcGroup.ssrcs.split(' ');\n                    }\n                });\n            }\n        });\n    }\n\n    return session;\n};\n\nexport default {\n    write,\n    parse\n};\n","/* Copyright @ 2015 - Present, 8x8 Inc\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport clonedeep from 'lodash.clonedeep';\n\nimport transform from './transform.js';\n\nconst PLAN_B_MIDS = [ 'audio', 'video', 'data' ];\nconst findSimGroup = ssrcGroup => ssrcGroup.find(grp => grp.semantics === 'SIM');\nconst findFidGroup = ssrcGroup => ssrcGroup.find(grp => grp.semantics === 'FID');\n\n/**\n * Add the ssrcs of the SIM group and their corresponding FID group ssrcs\n * to the m-line.\n * @param {Object} mLine - The m-line to which ssrcs have to be added.\n * @param {Object} simGroup - The SIM group whose ssrcs have to be added to\n * the m-line.\n * @param {Object} sourceGroups - inverted source-group map.\n * @param {Array<Object>} sourceList - array containing all the sources.\n */\nfunction addSimGroupSources(mLine, simGroup, sourceGroups, sourceList) {\n    if (!mLine || !simGroup) {\n        return;\n    }\n    const findSourcebyId = src => sourceList.find(source => source.id.toString() === src);\n\n    simGroup.ssrcs.forEach(src => {\n        mLine.sources.push(findSourcebyId(src));\n\n        // find the related FID group member for this ssrc.\n        const relatedFidGroup = sourceGroups[parseInt(src, 10)].find(grp => grp.semantics === 'FID');\n\n        if (relatedFidGroup) {\n            const relatedSsrc = relatedFidGroup.ssrcs.find(s => s !== src);\n\n            mLine.sources.push(findSourcebyId(relatedSsrc));\n            mLine.ssrcGroups.push(relatedFidGroup);\n        }\n    });\n\n    // Add the SIM group last.\n    mLine.ssrcGroups.push(simGroup);\n}\n\n/**\n * Add ssrcs and ssrc-groups to the m-line. When a primary ssrc, i.e., the\n * first ssrc in a SIM group is passed, all the other ssrcs from the SIM\n * group and the other ssrcs from the related FID groups are added to the same\n * m-line since they all belong to the same remote source. Since the ssrcs are\n * not guaranteed to be in the correct order, try to find if a SIM group exists,\n * if not, just add the FID group.\n * @param {Object} mLine - The m-line to which ssrcs have to be added.\n * @param {Object} ssrc - the primary ssrc.\n * @param {Object} sourceGroups - inverted source-group map.\n * @param {Array<Object>} sourceList - array containing all the sources.\n * @returns {void}\n */\nfunction addSourcesToMline(mLine, ssrc, sourceGroups, sourceList) {\n    if (!mLine || !ssrc) {\n        return;\n    }\n    mLine.sources = [];\n    mLine.ssrcGroups = [];\n\n    // If there are no associated ssrc-groups, just add the ssrc and msid.\n    if (!sourceGroups[ssrc.id]) {\n        mLine.sources.push(ssrc);\n        mLine.msid = ssrc.msid;\n\n        return;\n    }\n    const findSourcebyId = src => sourceList.find(source => source.id.toString() === src);\n\n    // Find the SIM and FID groups that this ssrc belongs to.\n    const simGroup = findSimGroup(sourceGroups[ssrc.id]);\n    const fidGroup = findFidGroup(sourceGroups[ssrc.id]);\n\n    // Add the ssrcs for the SIM group and their corresponding FID groups.\n    if (simGroup) {\n        addSimGroupSources(mLine, simGroup, sourceGroups, sourceList);\n    } else if (fidGroup) {\n        // check if the other ssrc from this FID group is part of a SIM group\n        const otherSsrc = fidGroup.ssrcs.find(s => s !== ssrc);\n        const simGroup2 = findSimGroup(sourceGroups[otherSsrc]);\n\n        if (simGroup2) {\n            addSimGroupSources(mLine, simGroup2, sourceGroups, sourceList);\n        } else {\n            // Add the FID group ssrcs.\n            fidGroup.ssrcs.forEach(src => {\n                mLine.sources.push(findSourcebyId(src));\n            });\n            mLine.ssrcGroups.push(fidGroup);\n        }\n    }\n\n    // Set the msid for the media description using the msid attribute of the ssrcs.\n    mLine.msid = mLine.sources[0].msid;\n}\n\n/**\n * Checks if there is a mline for the given ssrc or its related primary ssrc.\n * We always implode the SIM group to the first ssrc in the SIM group before sRD,\n * so we also check if mline for that ssrc exists.\n * For example:\n * If the following ssrcs are in a SIM group,\n * <ssrc-group xmlns=\\\"urn:xmpp:jingle:apps:rtp:ssma:0\\\" semantics=\\\"SIM\\\">\n *        <source ssrc=\\\"1806330949\\\"/>\n *        <source ssrc=\\\"4173145196\\\"/>\n *        <source ssrc=\\\"2002632207\\\"/>\n * </ssrc-group>\n * This method returns true for any one of the 3 ssrcs if there is a mline for 1806330949.\n * @param {Object} ssrc - ssrc to check.\n * @param {Object} sourceGroups - inverted source-group map.\n * @param {Array<Object>} mlines - mlines in the description\n\n * @returns {Boolean} - Returns true if mline for the given ssrc or the related primary ssrc\n * exists, returns false otherwise.\n */\nfunction checkIfMlineForSsrcExists(ssrc, sourceGroups, mlines) {\n    const findMatchingMline = mline => {\n        if (mline.sources) {\n            return mline.sources.some(source => source.id === ssrc.id);\n        }\n\n        return false;\n    };\n\n    if (!mlines.find(findMatchingMline)) {\n        // check if this ssrc is member of a SIM group. If so, check if there\n        // is a matching m-line for the primary ssrc of the SIM group.\n        if (!sourceGroups[ssrc.id]) {\n            return false;\n        }\n        const simGroup = findSimGroup(sourceGroups[ssrc.id]);\n        const fidGroup = findFidGroup(sourceGroups[ssrc.id]);\n\n        if (simGroup) {\n            return mlines.some(mline => mline.sources\n                && mline.sources.some(src => src.id.toString() === simGroup.ssrcs[0]));\n        } else if (fidGroup && ssrc.id.toString() !== fidGroup.ssrcs[0]) {\n            const otherSsrc = { id: fidGroup.ssrcs[0] };\n\n            return checkIfMlineForSsrcExists(otherSsrc, sourceGroups, mlines);\n\n        }\n\n        return false;\n    }\n\n    return true;\n}\n\n/**\n * Create an inverted sourceGroup map to put all the grouped ssrcs\n * in the same m-line.\n * @param {Array<Object>} sourceGroups\n * @returns {Object} - An inverted sourceGroup map.\n */\nfunction createSourceGroupMap(sourceGroups) {\n    const ssrc2group = {};\n\n    if (!sourceGroups || !Array.isArray(sourceGroups)) {\n        return ssrc2group;\n    }\n    sourceGroups.forEach(group => {\n        if (group.ssrcs && Array.isArray(group.ssrcs)) {\n            group.ssrcs.forEach(ssrc => {\n                if (typeof ssrc2group[ssrc] === 'undefined') {\n                    ssrc2group[ssrc] = [];\n                }\n                ssrc2group[ssrc].push(group);\n            });\n        }\n    });\n\n    return ssrc2group;\n}\n\n/**\n * Check if a new SDP requests an ICE restart.\n * @param {Object} - the parsed new SDP\n * @param {Object} - the parsed previous SDP\n * @returns {Boolean} - Returns true if an ICE restart is requested otherwise false.\n */\nfunction checkForIceRestart(newDesc, oldDesc) {\n    if (!newDesc || !oldDesc || newDesc.media.length === 0 || oldDesc.media.length === 0) {\n        return false;\n    }\n\n    const newMLine = newDesc.media[0];\n    const oldMLine = oldDesc.media[0];\n\n    return newMLine.iceUfrag !== oldMLine.iceUfrag || newMLine.icePwd !== oldMLine.icePwd;\n}\n\n/**\n * Interop provides an API for tranforming a Plan B SDP to a Unified Plan SDP and\n * vice versa.\n */\nexport class Interop {\n    /**\n     * This method transforms a Unified Plan SDP to an equivalent Plan B SDP.\n     * @param {RTCSessionDescription} description - The description in Unified plan format.\n     * @returns RTCSessionDescription - The transformed session description.\n     */\n    toPlanB(description) {\n        if (!description || typeof description.sdp !== 'string') {\n            console.warn('An empty description was passed as an argument.');\n\n            return description;\n        }\n\n        // Objectify the SDP for easier manipulation.\n        const session = transform.parse(description.sdp);\n\n        // If the SDP contains no media, there's nothing to transform.\n        if (!session.media || !session.media.length) {\n            console.warn('The description has no media.');\n\n            return description;\n        }\n\n        // Make sure this is a unified plan sdp\n        if (session.media.every(m => PLAN_B_MIDS.indexOf(m.mid) !== -1)) {\n            console.warn('The description does not look like unified plan sdp');\n\n            return description;\n        }\n\n        const media = {};\n        const sessionMedia = session.media;\n\n        session.media = [];\n        sessionMedia.forEach(mLine => {\n            const type = mLine.type;\n\n            if (type === 'application') {\n                mLine.mid = 'data';\n                media[mLine.mid] = mLine;\n\n                return;\n            }\n            if (typeof media[type] === 'undefined') {\n                const bLine = clonedeep(mLine);\n\n                // Copy the msid attribute to all the ssrcs if they belong to the same source group\n                if (bLine.sources && Array.isArray(bLine.sources)) {\n                    bLine.sources.forEach(source => {\n                        mLine.msid ? source.msid = mLine.msid : delete source.msid;\n                    });\n                }\n\n                // Do not signal the FID groups if there is no msid attribute present\n                // on the sources as sesison-accept with this source info will fail strophe\n                // validation and the session will not be established. This behavior is seen\n                // on Firefox (with RTX enabled) when no video source is added at the join time.\n                // FF generates two recvonly ssrcs with no msid and a corresponding FID group in\n                // this case.\n                if (!bLine.ssrcGroups || !mLine.msid) {\n                    bLine.ssrcGroups = [];\n                }\n                delete bLine.msid;\n                bLine.mid = type;\n                media[type] = bLine;\n            } else if (mLine.msid) {\n                // Add sources and source-groups to the existing m-line of the same media type.\n                const bLine = clonedeep(mLine);\n\n                if (bLine.sources && Array.isArray(bLine.sources)) {\n                    // Copy the msid attribute to each ssrc.\n                    bLine.sources.forEach(ssrc => {\n                        ssrc.msid = mLine.msid;\n                    });\n                    media[type].sources = (media[type].sources || []).concat(bLine.sources);\n                }\n                if (typeof bLine.ssrcGroups !== 'undefined' && Array.isArray(bLine.ssrcGroups)) {\n                    media[type].ssrcGroups = (media[type].ssrcGroups || []).concat(bLine.ssrcGroups);\n                }\n            }\n        });\n        session.media = Object.values(media);\n\n        // Bundle the media only if it is active.\n        const bundle = [];\n\n        Object.values(media).forEach(mline => {\n            if (mline.direction !== 'inactive') {\n                bundle.push(mline.mid);\n            }\n        });\n\n        // We regenerate the BUNDLE group with the new mids.\n        session.groups.forEach(group => {\n            if (group.type === 'BUNDLE') {\n                group.mids = bundle.join(' ');\n            }\n        });\n\n        // msid semantic\n        session.msidSemantic = {\n            semantic: 'WMS',\n            token: '*'\n        };\n        const resStr = transform.write(session);\n\n        return new RTCSessionDescription({\n            type: description.type,\n            sdp: resStr\n        });\n    }\n\n    /**\n     * This method transforms a Plan B SDP to an equivalent Unified Plan SDP.\n     * @param {RTCSessionDescription} description - The description in plan-b format.\n     * @param {RTCSessionDescription} current - The current description set on\n     * the peerconnection in Unified-plan format, i.e., the readonly attribute\n     * remoteDescription on the RTCPeerConnection object.\n     * @returns RTCSessionDescription - The transformed session description.\n     */\n    toUnifiedPlan(description, current = null) {\n        if (!description || typeof description.sdp !== 'string') {\n            console.warn('An empty description was passed as an argument.');\n\n            return description;\n        }\n\n        // Objectify the SDP for easier manipulation.\n        const session = transform.parse(description.sdp);\n\n        // If the SDP contains no media, there's nothing to transform.\n        if (!session.media || !session.media.length) {\n            console.warn('The description has no media.');\n\n            return description;\n        }\n\n        // Make sure this is a plan-b sdp.\n        if (session.media.length > 3 || session.media.every(m => PLAN_B_MIDS.indexOf(m.mid) === -1)) {\n            console.warn('The description does not look like plan-b');\n\n            return description;\n        }\n        const currentDesc = current ? transform.parse(current.sdp) : null;\n        const iceRestart = checkForIceRestart(session, currentDesc);\n        const newIceUfrag = session.media[0].iceUfrag;\n        const newIcePwd = session.media[0].icePwd;\n        const newFingerprint = session.media[0].fingerprint;\n        const media = {};\n\n        session.media.forEach(mLine => {\n            const type = mLine.type;\n\n            if (type === 'application') {\n                if (!currentDesc || !currentDesc.media) {\n                    const newMline = clonedeep(mLine);\n\n                    newMline.mid = Object.keys(media).length.toString();\n                    media[mLine.mid] = newMline;\n\n                    return;\n                }\n                const mLineForData = currentDesc.media.findIndex(m => m.type === type);\n\n                if (mLineForData) {\n                    currentDesc.media[mLineForData] = mLine;\n                    currentDesc.media[mLineForData].mid = mLineForData;\n                }\n\n                return;\n            }\n\n            // Create an inverted sourceGroup map here to put all the grouped SSRCs in the same m-line.\n            const ssrc2group = createSourceGroupMap(mLine.ssrcGroups);\n\n            // If there are no sources advertised for a media type, add the description if this is the first\n            // remote offer, i.e., no current description was passed. Chrome in Unified plan does not produce\n            // recvonly ssrcs unlike Firefox and Safari.\n            if (!mLine.sources) {\n                if (!currentDesc) {\n                    const newMline = clonedeep(mLine);\n\n                    newMline.mid = Object.keys(media).length.toString();\n                    media[mLine.mid] = newMline;\n                }\n\n                return;\n            }\n            mLine.sources.forEach((ssrc, idx) => {\n                // Do not add the receive-only ssrcs that Jicofo sends in the source-add.\n                // These ssrcs do not have the \"msid\" attribute set.\n                if (!ssrc.msid) {\n                    return;\n                }\n\n                // If there is no description set on the peerconnection, create new m-lines.\n                if (!currentDesc || !currentDesc.media) {\n                    if (checkIfMlineForSsrcExists(ssrc, ssrc2group, Object.values(media))) {\n                        return;\n                    }\n                    const newMline = clonedeep(mLine);\n\n                    newMline.mid = Object.keys(media).length.toString();\n                    newMline.direction = idx\n                        ? 'sendonly'\n                        : mLine.direction === 'sendonly' ? 'sendonly' : 'sendrecv';\n                    newMline.bundleOnly = undefined;\n                    addSourcesToMline(newMline, ssrc, ssrc2group, mLine.sources);\n                    media[newMline.mid] = newMline;\n\n                    return;\n                }\n\n                // Create and append the m-lines to the existing description.\n                if (checkIfMlineForSsrcExists(ssrc, ssrc2group, currentDesc.media)) {\n                    return;\n                }\n                const newMline = clonedeep(mLine);\n\n                newMline.mid = currentDesc.media.length.toString();\n                newMline.direction = 'sendonly';\n                addSourcesToMline(newMline, ssrc, ssrc2group, mLine.sources);\n                currentDesc.media.push(newMline);\n            });\n        });\n        session.media = currentDesc ? currentDesc.media : Object.values(media);\n        const mids = [];\n\n        session.media.forEach(mLine => {\n            mids.push(mLine.mid);\n            if (iceRestart) {\n                mLine.iceUfrag = newIceUfrag;\n                mLine.icePwd = newIcePwd;\n                mLine.fingerprint = newFingerprint;\n            }\n        });\n\n        // We regenerate the BUNDLE group (since we regenerated the mids)\n        session.groups.forEach(group => {\n            if (group.type === 'BUNDLE') {\n                group.mids = mids.join(' ');\n            }\n        });\n\n        // msid semantic\n        session.msidSemantic = {\n            semantic: 'WMS',\n            token: '*'\n        };\n\n        // Increment the session version every time.\n        session.origin.sessionVersion++;\n        const resultSdp = transform.write(session);\n\n        return new RTCSessionDescription({\n            type: description.type,\n            sdp: resultSdp\n        });\n    }\n}\n","export enum SignalingEvents {\n    /**\n     * Event triggered when participant's muted status changes.\n     *\n     * @param {string} endpointId the track owner's identifier (MUC nickname)\n     * @param {MediaType} mediaType \"audio\" or \"video\"\n     * @param {boolean} isMuted the new muted state\n     */\n    PEER_MUTED_CHANGED = 'signaling.peerMuted',\n\n    /**\n     * Event triggered when participant's video type changes.\n     *\n     * @param {string} endpointId the video owner's ID (MUC nickname)\n     * @param {VideoType} videoType the new value\n     */\n    PEER_VIDEO_TYPE_CHANGED = 'signaling.peerVideoType',\n\n    /**\n     * Event triggered when source's muted status changes.\n     *\n     * @param {string} sourceName - The name of the source.\n     * @param {boolean} isMuted - The new muted state.\n     */\n    SOURCE_MUTED_CHANGED = 'signaling.sourceMuted',\n\n    /**\n     * Event triggered when presence for a source is received.\n     *\n     * @param {string} sourceName - The name of the source.\n     * @param {string} endpointId - The endpoint id.\n     * @param {boolean} muted - The new muted state.\n     * @param {string} videoType - The video type of the source.\n     */\n    SOURCE_UPDATED = 'signaling.sourceUpdated',\n\n    /**\n     * Event triggered when source's video type changes.\n     *\n     * @param {string} source - The name of the source.\n     * @param {VideoType} videoType - The new value.\n     */\n    SOURCE_VIDEO_TYPE_CHANGED = 'signaling.sourceVideoType'\n}\n\n// exported for backward compatibility\nexport const PEER_MUTED_CHANGED = SignalingEvents.PEER_MUTED_CHANGED;\nexport const PEER_VIDEO_TYPE_CHANGED = SignalingEvents.PEER_VIDEO_TYPE_CHANGED;\nexport const SOURCE_MUTED_CHANGED = SignalingEvents.SOURCE_MUTED_CHANGED;\nexport const SOURCE_UPDATED = SignalingEvents.SOURCE_UPDATED;\nexport const SOURCE_VIDEO_TYPE_CHANGED = SignalingEvents.SOURCE_VIDEO_TYPE_CHANGED;\n","\nimport Listenable from '../../modules/util/Listenable';\nimport { MediaType } from '../../service/RTC/MediaType';\n\n/**\n * @typedef {string} EndpointId\n */\n/**\n * @typedef {string} SourceName\n */\n/**\n * @typedef {Object} SourceInfo\n *\n * @property {SourceName} sourceName - Name of the media source.\n * @property {boolean} [muted=false] - Tells if the source is muted (paused?).\n * @property {string} [videoType] - Type of the video for video type.\n */\n\n/**\n * Generates a source name.\n *\n * @param {EndpointId} endpointId - Jitsi Endpoint Id.\n * @param {MediaType} mediaType - the media type string.\n * @param {number} trackIdx - Track index (or sender idx? - to be figured out) starting from 0.\n * @returns {SourceName} eg. endpointA-v0\n */\nexport function getSourceNameForJitsiTrack(endpointId, mediaType, trackIdx) {\n    const firstLetterOfMediaType = mediaType.substring(0, 1);\n\n    return `${endpointId}-${firstLetterOfMediaType}${trackIdx}`;\n}\n\n/**\n * Extracts MediaType from give source name (must be in the correct format as generated by\n * {@link getSourceNameForJitsiTrack}).\n *\n * @param {SourceName} sourceName - the source name.\n * @returns {MediaType}\n */\nexport function getMediaTypeFromSourceName(sourceName) {\n    const firstLetterOfMediaTypeIdx = sourceName.lastIndexOf('-') + 1;\n\n    if (firstLetterOfMediaTypeIdx <= 0) {\n        throw new Error(`Invalid source name: ${sourceName}`);\n    }\n\n    const firstLetterOfMediaType = sourceName.substr(firstLetterOfMediaTypeIdx, 1);\n\n    for (const type of Object.values(MediaType)) {\n        if (type.substr(0, 1) === firstLetterOfMediaType) {\n            return type;\n        }\n    }\n\n    throw new Error(`Invalid source name: ${sourceName}`);\n}\n\n/**\n * Extracts source index (zero based) from a given source name (must be in the correct format as generated by\n * {@link getSourceNameForJitsiTrack}).\n *\n * @param {SourceName} sourceName - the source name, eg. endpointA-v0.\n * @returns {number}\n */\nexport function getSourceIndexFromSourceName(sourceName) {\n    const nameParts = sourceName.split('-');\n    const trackIdx = Number(nameParts[nameParts.length - 1].substring(1));\n\n    if (Number.isNaN(trackIdx)) {\n        throw new Error(`Failed to parse track idx for source name: ${sourceName}`);\n    }\n\n    return trackIdx;\n}\n\n/**\n * An object that carries the info about specific media type advertised by\n * participant in the signaling channel.\n * @typedef {Object} PeerMediaInfo\n * @property {boolean} muted indicates if the media is currently muted\n * @property {VideoType|undefined} videoType the type of the video if applicable\n */\n\n/**\n * Interface used to expose the information carried over the signaling channel\n * which is not available to the RTC module in the media SDP.\n *\n * @interface SignalingLayer\n */\nexport default class SignalingLayer extends Listenable {\n    /**\n     * Obtains the info about given media advertised in the MUC presence of\n     * the participant identified by the given MUC JID.\n     * @param {string} owner the MUC jid of the participant for whom\n     * {@link PeerMediaInfo} will be obtained.\n     * @param {MediaType} mediaType the type of the media for which presence\n     * @param {SourceName} sourceName - The name of the source for which the info is to be obtained.\n     * info will be obtained.\n     * @return {PeerMediaInfo|null} presenceInfo an object with media presence\n     * info or <tt>null</tt> either if there is no presence available for given\n     * JID or if the media type given is invalid.\n     *\n     * @deprecated This method is to be replaced with getPeerSourceInfo.\n     */\n    getPeerMediaInfo(owner, mediaType, sourceName) { // eslint-disable-line no-unused-vars\n        throw new Error('not implemented');\n    }\n\n    /**\n     * Obtains the info about a source for given name and endpoint ID.\n     * @param {EndpointId} owner - The owner's endpoint ID.\n     * @param {SourceName} sourceName - The name of the source for which the info is to be obtained.\n     * @returns {SourceInfo | undefined}\n     */\n    getPeerSourceInfo(owner, sourceName) { // eslint-disable-line no-unused-vars\n        throw new Error('not implemented');\n    }\n\n    /**\n     * Obtains the endpoint ID for given SSRC.\n     * @param {number} ssrc the SSRC number.\n     * @return {string|null} the endpoint ID for given media SSRC.\n     */\n    getSSRCOwner(ssrc) { // eslint-disable-line no-unused-vars\n        throw new Error('not implemented');\n    }\n\n    /**\n     * Obtains the source name for given SSRC.\n     * @param {number} ssrc the track's SSRC identifier.\n     * @returns {SourceName | undefined} the track's source name.\n     */\n    getTrackSourceName(ssrc) { // eslint-disable-line no-unused-vars\n        throw new Error('not implemented');\n    }\n\n    /**\n     * Removes the association between a given SSRC and its current owner so that it can re-used when the SSRC gets\n     * remapped to another source from a different endpoint.\n     * @param {number} ssrc a list of SSRCs.\n     */\n    removeSSRCOwners(ssrcList) { // eslint-disable-line no-unused-vars\n    }\n\n    /**\n     * Set an SSRC owner.\n     * @param {number} ssrc an SSRC to be owned\n     * @param {string} endpointId owner's ID (MUC nickname)\n     * @throws TypeError if <tt>ssrc</tt> is not a number\n     */\n    setSSRCOwner(ssrc, endpointId) { // eslint-disable-line no-unused-vars\n    }\n\n    /**\n     * Adjusts muted status of given track.\n     *\n     * @param {SourceName} sourceName - the name of the track's source.\n     * @param {boolean} muted - the new muted status.\n     * @returns {boolean}\n     */\n    setTrackMuteStatus(sourceName, muted) { // eslint-disable-line no-unused-vars\n    }\n\n    /**\n     * Saves the source name for a track identified by it's ssrc.\n     * @param {number} ssrc the ssrc of the target track.\n     * @param {SourceName} sourceName the track's source name to save.\n     * @throws TypeError if <tt>ssrc</tt> is not a number\n     */\n    setTrackSourceName(ssrc, sourceName) { // eslint-disable-line no-unused-vars\n    }\n\n    /**\n     * Sets track's video type.\n     * @param {SourceName} sourceName - the track's source name.\n     * @param {VideoType} videoType - the new video type.\n     * @returns {boolean}\n     */\n    setTrackVideoType(sourceName, videoType) { // eslint-disable-line no-unused-vars\n    }\n\n    /**\n     * Removes the SSRCs associated with a given endpoint from the SSRC owners.\n     *\n     * @param {string} id endpoint id of the participant leaving the call.\n     * @returns {void}\n     */\n    updateSsrcOwnersOnLeave(id) { // eslint-disable-line no-unused-vars\n    }\n}\n","import * as transform from 'sdp-transform';\n\n/**\n * Parses the primary SSRC of given SSRC group.\n * @param {object} group the SSRC group object as defined by the 'sdp-transform'\n * @return {Number} the primary SSRC number\n */\nexport function parsePrimarySSRC(group) {\n    return parseInt(group.ssrcs.split(' ')[0], 10);\n}\n\n/**\n * Parses the secondary SSRC of given SSRC group.\n * @param {object} group the SSRC group object as defined by the 'sdp-transform'\n * @return {Number} the secondary SSRC number\n */\nexport function parseSecondarySSRC(group) {\n    return parseInt(group.ssrcs.split(' ')[1], 10);\n}\n\n/**\n * Tells how many distinct SSRCs are contained in given media line.\n * @param {Object} mLine the media line object as defined by 'sdp-transform' lib\n * @return {number}\n */\nfunction _getSSRCCount(mLine) {\n    if (!mLine.ssrcs) {\n        return 0;\n    }\n\n    return mLine.ssrcs\n        .map(ssrcInfo => ssrcInfo.id)\n        .filter((ssrc, index, array) => array.indexOf(ssrc) === index)\n        .length;\n}\n\n/**\n * A wrapper around 'sdp-transform' media description object which provides\n * utility methods for common SDP/SSRC related operations.\n */\nclass MLineWrap {\n\n    /**\n     * Creates new <tt>MLineWrap</t>>\n     * @param {Object} mLine the media line object as defined by 'sdp-transform'\n     * lib.\n     */\n    constructor(mLine) {\n        if (!mLine) {\n            throw new Error('mLine is undefined');\n        }\n\n        this.mLine = mLine;\n    }\n\n    /**\n     * Getter for the mLine's \"ssrcs\" array. If the array was undefined an empty\n     * one will be preassigned.\n     *\n     * @return {Array<Object>} an array of 'sdp-transform' SSRC attributes\n     * objects.\n     */\n    get ssrcs() {\n        if (!this.mLine.ssrcs) {\n            this.mLine.ssrcs = [];\n        }\n\n        return this.mLine.ssrcs;\n    }\n\n    /**\n     * Setter for the mLine's \"ssrcs\" array.\n     *\n     * @param {Array<Object>} ssrcs an array of 'sdp-transform' SSRC attributes\n     * objects.\n     */\n    set ssrcs(ssrcs) {\n        this.mLine.ssrcs = ssrcs;\n    }\n\n    /**\n     * Returns the direction of the underlying media description.\n     * @return {string} the media direction name as defined in the SDP.\n     */\n    get direction() {\n        return this.mLine.direction;\n    }\n\n    /**\n     * Modifies the direction of the underlying media description.\n     * @param {string} direction the new direction to be set\n     */\n    set direction(direction) {\n        this.mLine.direction = direction;\n    }\n\n    /**\n     * Exposes the SSRC group array of the underlying media description object.\n     * @return {Array.<Object>}\n     */\n    get ssrcGroups() {\n        if (!this.mLine.ssrcGroups) {\n            this.mLine.ssrcGroups = [];\n        }\n\n        return this.mLine.ssrcGroups;\n    }\n\n    /**\n     * Modifies the SSRC groups array of the underlying media description\n     * object.\n     * @param {Array.<Object>} ssrcGroups\n     */\n    set ssrcGroups(ssrcGroups) {\n        this.mLine.ssrcGroups = ssrcGroups;\n    }\n\n    /**\n     * Obtains value from SSRC attribute.\n     * @param {number} ssrcNumber the SSRC number for which attribute is to be\n     * found\n     * @param {string} attrName the name of the SSRC attribute to be found.\n     * @return {string|undefined} the value of SSRC attribute or\n     * <tt>undefined</tt> if no such attribute exists.\n     */\n    getSSRCAttrValue(ssrcNumber, attrName) {\n        const attribute = this.ssrcs.find(\n            ssrcObj => ssrcObj.id === ssrcNumber\n            && ssrcObj.attribute === attrName);\n\n\n        return attribute && attribute.value;\n    }\n\n    /**\n     * Removes all attributes for given SSRC number.\n     * @param {number} ssrcNum the SSRC number for which all attributes will be\n     * removed.\n     */\n    removeSSRC(ssrcNum) {\n        if (!this.mLine.ssrcs || !this.mLine.ssrcs.length) {\n            return;\n        }\n\n        this.mLine.ssrcs\n            = this.mLine.ssrcs.filter(ssrcObj => ssrcObj.id !== ssrcNum);\n    }\n\n    /**\n     * Adds SSRC attribute\n     * @param {object} ssrcObj the SSRC attribute object as defined in\n     * the 'sdp-transform' lib.\n     */\n    addSSRCAttribute(ssrcObj) {\n        this.ssrcs.push(ssrcObj);\n    }\n\n    /**\n     * Finds a SSRC group matching both semantics and SSRCs in order.\n     * @param {string} semantics the name of the semantics\n     * @param {string} [ssrcs] group SSRCs as a string (like it's defined in\n     * SSRC group object of the 'sdp-transform' lib) e.g. \"1232546 342344 25434\"\n     * @return {object|undefined} the SSRC group object or <tt>undefined</tt> if\n     * not found.\n     */\n    findGroup(semantics, ssrcs) {\n        return this.ssrcGroups.find(\n            group =>\n                group.semantics === semantics\n                    && (!ssrcs || ssrcs === group.ssrcs));\n    }\n\n    /**\n     * Finds all groups matching given semantic's name.\n     * @param {string} semantics the name of the semantics\n     * @return {Array.<object>} an array of SSRC group objects as defined by\n     * the 'sdp-transform' lib.\n     */\n    findGroups(semantics) {\n        return this.ssrcGroups.filter(\n            group => group.semantics === semantics);\n    }\n\n    /**\n     * Finds all groups matching given semantic's name and group's primary SSRC.\n     * @param {string} semantics the name of the semantics\n     * @param {number} primarySSRC the primary SSRC number to be matched\n     * @return {Object} SSRC group object as defined by the 'sdp-transform' lib.\n     */\n    findGroupByPrimarySSRC(semantics, primarySSRC) {\n        return this.ssrcGroups.find(\n            group => group.semantics === semantics\n                && parsePrimarySSRC(group) === primarySSRC);\n    }\n\n    /**\n     * @param {string|null} msid the media stream id or <tt>null</tt> to match\n     * the first SSRC object with any 'msid' value.\n     * @return {Object|undefined} the SSRC object as defined by 'sdp-transform'\n     * lib.\n     */\n    findSSRCByMSID(msid) {\n        return this.ssrcs.find(\n            ssrcObj => ssrcObj.attribute === 'msid'\n                && (msid === null || ssrcObj.value === msid));\n    }\n\n    /**\n     * Gets the SSRC count for the underlying media description.\n     * @return {number}\n     */\n    getSSRCCount() {\n        return _getSSRCCount(this.mLine);\n    }\n\n    /**\n     * Checks whether the underlying media description contains any SSRC groups.\n     * @return {boolean} <tt>true</tt> if there are any SSRC groups or\n     * <tt>false</tt> otherwise.\n     */\n    containsAnySSRCGroups() {\n        return this.mLine.ssrcGroups !== undefined;\n    }\n\n    /**\n     * Finds the primary video SSRC.\n     * @returns {number|undefined} the primary video ssrc\n     * @throws Error if the underlying media description is not a video\n     */\n    getPrimaryVideoSsrc() {\n        const mediaType = this.mLine.type;\n\n        if (mediaType !== 'video') {\n            throw new Error(\n                `getPrimarySsrc doesn't work with '${mediaType}'`);\n        }\n\n        const numSsrcs = _getSSRCCount(this.mLine);\n\n        if (numSsrcs === 1) {\n            // Not using \"ssrcs\" getter on purpose here\n            return this.mLine.ssrcs[0].id;\n        }\n\n        // Look for a SIM, FID, or FEC-FR group\n        if (this.mLine.ssrcGroups) {\n            const simGroup = this.findGroup('SIM');\n\n            if (simGroup) {\n                return parsePrimarySSRC(simGroup);\n            }\n            const fidGroup = this.findGroup('FID');\n\n            if (fidGroup) {\n                return parsePrimarySSRC(fidGroup);\n            }\n            const fecGroup = this.findGroup('FEC-FR');\n\n            if (fecGroup) {\n                return parsePrimarySSRC(fecGroup);\n            }\n        }\n\n    }\n\n    /**\n     * Obtains RTX SSRC from the underlying video description (the\n     * secondary SSRC of the first \"FID\" group found)\n     * @param {number} primarySsrc the video ssrc for which to find the\n     * corresponding rtx ssrc\n     * @returns {number|undefined} the rtx ssrc (or undefined if there isn't\n     * one)\n     */\n    getRtxSSRC(primarySsrc) {\n        const fidGroup = this.findGroupByPrimarySSRC('FID', primarySsrc);\n\n\n        return fidGroup && parseSecondarySSRC(fidGroup);\n    }\n\n    /**\n     * Obtains all SSRCs contained in the underlying media description.\n     * @return {Array.<number>} an array with all SSRC as numbers.\n     */\n    getSSRCs() {\n        return this.ssrcs\n            .map(ssrcInfo => ssrcInfo.id)\n            .filter((ssrc, index, array) => array.indexOf(ssrc) === index);\n    }\n\n    /**\n     * Obtains primary video SSRCs.\n     * @return {Array.<number>} an array of all primary video SSRCs as numbers.\n     * @throws Error if the wrapped media description is not a video.\n     */\n    getPrimaryVideoSSRCs() {\n        const mediaType = this.mLine.type;\n\n        if (mediaType !== 'video') {\n            throw new Error(\n                `getPrimaryVideoSSRCs doesn't work with ${mediaType}`);\n        }\n\n        const videoSSRCs = this.getSSRCs();\n\n        for (const ssrcGroupInfo of this.ssrcGroups) {\n            // Right now, FID and FEC-FR groups are the only ones we parse to\n            // disqualify streams.  If/when others arise we'll\n            // need to add support for them here\n            if (ssrcGroupInfo.semantics === 'FID'\n                    || ssrcGroupInfo.semantics === 'FEC-FR') {\n                // secondary streams should be filtered out\n                const secondarySsrc = parseSecondarySSRC(ssrcGroupInfo);\n\n                videoSSRCs.splice(\n                    videoSSRCs.indexOf(secondarySsrc), 1);\n            }\n        }\n\n        return videoSSRCs;\n    }\n\n    /**\n     * Dumps all SSRC groups of this media description to JSON.\n     */\n    dumpSSRCGroups() {\n        return JSON.stringify(this.mLine.ssrcGroups);\n    }\n\n    /**\n     * Removes all SSRC groups which contain given SSRC number at any position.\n     * @param {number} ssrc the SSRC for which all matching groups are to be\n     * removed.\n     */\n    removeGroupsWithSSRC(ssrc) {\n        if (!this.mLine.ssrcGroups) {\n            return;\n        }\n\n        this.mLine.ssrcGroups = this.mLine.ssrcGroups\n            .filter(groupInfo => groupInfo.ssrcs.indexOf(`${ssrc}`) === -1);\n    }\n\n    /**\n     * Removes groups that match given semantics.\n     * @param {string} semantics e.g. \"SIM\" or \"FID\"\n     */\n    removeGroupsBySemantics(semantics) {\n        if (!this.mLine.ssrcGroups) {\n            return;\n        }\n\n        this.mLine.ssrcGroups\n            = this.mLine.ssrcGroups\n                .filter(groupInfo => groupInfo.semantics !== semantics);\n    }\n\n    /**\n     * Replaces SSRC (does not affect SSRC groups, but only attributes).\n     * @param {number} oldSSRC the old SSRC number\n     * @param {number} newSSRC the new SSRC number\n     */\n    replaceSSRC(oldSSRC, newSSRC) {\n        if (this.mLine.ssrcs) {\n            this.mLine.ssrcs.forEach(ssrcInfo => {\n                if (ssrcInfo.id === oldSSRC) {\n                    ssrcInfo.id = newSSRC;\n                }\n            });\n        }\n    }\n\n    /**\n     * Adds given SSRC group to this media description.\n     * @param {object} group the SSRC group object as defined by\n     * the 'sdp-transform' lib.\n     */\n    addSSRCGroup(group) {\n        this.ssrcGroups.push(group);\n    }\n}\n\n/**\n * Utility class for SDP manipulation using the 'sdp-transform' library.\n *\n * Typical use usage scenario:\n *\n * const transformer = new SdpTransformWrap(rawSdp);\n * const videoMLine = transformer.selectMedia('video);\n * if (videoMLine) {\n *     videoMLiner.addSSRCAttribute({\n *         id: 2342343,\n *         attribute: \"cname\",\n *         value: \"someCname\"\n *     });\n *     rawSdp = transformer.toRawSdp();\n * }\n */\nexport class SdpTransformWrap {\n\n    /**\n     * Creates new instance and parses the raw SDP into objects using\n     * 'sdp-transform' lib.\n     * @param {string} rawSDP the SDP in raw text format.\n     */\n    constructor(rawSDP) {\n        this.parsedSDP = transform.parse(rawSDP);\n    }\n\n    /**\n     * Selects all the m-lines from the SDP for a given media type.\n     *\n     * @param {string} mediaType the name of the media e.g. 'audio', 'video', 'data'.\n     * @return {MLineWrap|null} return {@link MLineWrap} instance for the media line or <tt>null</tt> if not found. The\n     * object returned references the underlying SDP state held by this <tt>SdpTransformWrap</tt> instance (it's not a\n     * copy).\n     */\n    selectMedia(mediaType) {\n        const selectedMLines = this.parsedSDP.media\n            .filter(mLine => mLine.type === mediaType)\n            .map(mLine => new MLineWrap(mLine));\n\n        return selectedMLines ?? null;\n    }\n\n    /**\n     * Converts the currently stored SDP state in this instance to raw text SDP\n     * format.\n     * @return {string}\n     */\n    toRawSDP() {\n        return transform.write(this.parsedSDP);\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { getSourceNameForJitsiTrack } from '../../service/RTC/SignalingLayer';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport browser from '../browser';\nimport FeatureFlags from '../flags/FeatureFlags';\n\nimport { SdpTransformWrap } from './SdpTransformUtil';\n\nconst logger = getLogger(__filename);\n\n/**\n * Fakes local SDP exposed to {@link JingleSessionPC} through the local\n * description getter. Modifies the SDP, so that it will contain muted local\n * video tracks description, even though their underlying {MediaStreamTrack}s\n * are no longer in the WebRTC peerconnection. That prevents from SSRC updates\n * being sent to Jicofo/remote peer and prevents sRD/sLD cycle on the remote\n * side.\n */\nexport default class LocalSdpMunger {\n\n    /**\n     * Creates new <tt>LocalSdpMunger</tt> instance.\n     *\n     * @param {TraceablePeerConnection} tpc\n     * @param {string} localEndpointId - The endpoint id of the local user.\n     */\n    constructor(tpc, localEndpointId) {\n        this.tpc = tpc;\n        this.localEndpointId = localEndpointId;\n        this.audioSourcesToMsidMap = new Map();\n        this.videoSourcesToMsidMap = new Map();\n    }\n\n    /**\n     * Makes sure that muted local video tracks associated with the parent\n     * {@link TraceablePeerConnection} are described in the local SDP. It's done\n     * in order to prevent from sending 'source-remove'/'source-add' Jingle\n     * notifications when local video track is muted (<tt>MediaStream</tt> is\n     * removed from the peerconnection).\n     *\n     * NOTE 1 video track is assumed\n     *\n     * @param {SdpTransformWrap} transformer the transformer instance which will\n     * be used to process the SDP.\n     * @return {boolean} <tt>true</tt> if there were any modifications to\n     * the SDP wrapped by <tt>transformer</tt>.\n     * @private\n     */\n    _addMutedLocalVideoTracksToSDP(transformer) {\n        // Go over each video tracks and check if the SDP has to be changed\n        const localVideos = this.tpc.getLocalTracks(MediaType.VIDEO);\n\n        if (!localVideos.length) {\n            return false;\n        } else if (localVideos.length !== 1) {\n            logger.error(\n                `${this.tpc} there is more than 1 video track ! `\n                    + 'Strange things may happen !', localVideos);\n        }\n\n        const videoMLine = transformer.selectMedia(MediaType.VIDEO)?.[0];\n\n        if (!videoMLine) {\n            logger.debug(\n                `${this.tpc} unable to hack local video track SDP`\n                    + '- no \"video\" media');\n\n            return false;\n        }\n\n        let modified = false;\n\n        for (const videoTrack of localVideos) {\n            const muted = videoTrack.isMuted();\n            const mediaStream = videoTrack.getOriginalStream();\n            const isCamera = videoTrack.videoType === VideoType.CAMERA;\n\n            // During the mute/unmute operation there are periods of time when\n            // the track's underlying MediaStream is not added yet to\n            // the PeerConnection. The SDP needs to be munged in such case.\n            const isInPeerConnection\n                = mediaStream && this.tpc.isMediaStreamInPc(mediaStream);\n            const shouldFakeSdp = isCamera && (muted || !isInPeerConnection);\n\n            if (!shouldFakeSdp) {\n                continue; // eslint-disable-line no-continue\n            }\n\n            // Inject removed SSRCs\n            const requiredSSRCs\n                = this.tpc.isSimulcastOn()\n                    ? this.tpc.simulcast.ssrcCache\n                    : [ this.tpc.sdpConsistency.cachedPrimarySsrc ];\n\n            if (!requiredSSRCs.length) {\n                logger.error(`No SSRCs stored for: ${videoTrack} in ${this.tpc}`);\n\n                continue; // eslint-disable-line no-continue\n            }\n\n            modified = true;\n\n            // We need to fake sendrecv.\n            // NOTE the SDP produced here goes only to Jicofo and is never set\n            // as localDescription. That's why\n            // TraceablePeerConnection.mediaTransferActive is ignored here.\n            videoMLine.direction = MediaDirection.SENDRECV;\n\n            // Check if the recvonly has MSID\n            const primarySSRC = requiredSSRCs[0];\n\n            // FIXME The cname could come from the stream, but may turn out to\n            // be too complex. It is fine to come up with any value, as long as\n            // we only care about the actual SSRC values when deciding whether\n            // or not an update should be sent.\n            const primaryCname = `injected-${primarySSRC}`;\n\n            for (const ssrcNum of requiredSSRCs) {\n                // Remove old attributes\n                videoMLine.removeSSRC(ssrcNum);\n\n                // Inject\n                videoMLine.addSSRCAttribute({\n                    id: ssrcNum,\n                    attribute: 'cname',\n                    value: primaryCname\n                });\n                videoMLine.addSSRCAttribute({\n                    id: ssrcNum,\n                    attribute: 'msid',\n                    value: videoTrack.storedMSID\n                });\n            }\n            if (requiredSSRCs.length > 1) {\n                const group = {\n                    ssrcs: requiredSSRCs.join(' '),\n                    semantics: 'SIM'\n                };\n\n                if (!videoMLine.findGroup(group.semantics, group.ssrcs)) {\n                    // Inject the group\n                    videoMLine.addSSRCGroup(group);\n                }\n            }\n\n            // Insert RTX\n            // FIXME in P2P RTX is used by Chrome regardless of config option\n            // status. Because of that 'source-remove'/'source-add'\n            // notifications are still sent to remove/add RTX SSRC and FID group\n            if (!this.tpc.options.disableRtx) {\n                this.tpc.rtxModifier.modifyRtxSsrcs2(videoMLine);\n            }\n        }\n\n        return modified;\n    }\n\n    /**\n     * Returns a string that can be set as the MSID attribute for a source.\n     *\n     * @param {string} mediaType - Media type of the source.\n     * @param {string} trackId - Id of the MediaStreamTrack associated with the source.\n     * @param {string} streamId - Id of the MediaStream associated with the source.\n     * @returns {string|null}\n     */\n    _generateMsidAttribute(mediaType, trackId, streamId = null) {\n        if (!(mediaType && trackId)) {\n            logger.error(`Unable to munge local MSID - track id=${trackId} or media type=${mediaType} is missing`);\n\n            return null;\n        }\n        const pcId = this.tpc.id;\n\n        // Handle a case on Firefox when the browser doesn't produce a 'a:ssrc' line with the 'msid' attribute or has\n        // '-' for the stream id part of the msid line. Jicofo needs an unique identifier to be associated with a ssrc\n        // and uses the msid for that.\n        if (streamId === '-' || !streamId) {\n            return `${this.localEndpointId}-${mediaType}-${pcId} ${trackId}-${pcId}`;\n        }\n\n        return `${streamId}-${pcId} ${trackId}-${pcId}`;\n    }\n\n    /**\n     * Modifies 'cname', 'msid', 'label' and 'mslabel' by appending the id of {@link LocalSdpMunger#tpc} at the end,\n     * preceding by a dash sign.\n     *\n     * @param {MLineWrap} mediaSection - The media part (audio or video) of the session description which will be\n     * modified in place.\n     * @returns {void}\n     * @private\n     */\n    _transformMediaIdentifiers(mediaSection) {\n        const mediaType = mediaSection.mLine?.type;\n        const pcId = this.tpc.id;\n\n        for (const ssrcLine of mediaSection.ssrcs) {\n            switch (ssrcLine.attribute) {\n            case 'cname':\n            case 'label':\n            case 'mslabel':\n                ssrcLine.value = ssrcLine.value && `${ssrcLine.value}-${pcId}`;\n                break;\n            case 'msid': {\n                if (ssrcLine.value) {\n                    const streamAndTrackIDs = ssrcLine.value.split(' ');\n\n                    let streamId = streamAndTrackIDs[0];\n                    const trackId = streamAndTrackIDs[1];\n\n                    // Always overwrite streamId since we want the msid to be in this format even if the browser\n                    // generates one (in p2p mode).\n                    streamId = `${this.localEndpointId}-${mediaType}`;\n\n                    // eslint-disable-next-line max-depth\n                    if (mediaType === MediaType.VIDEO) {\n                        // eslint-disable-next-line max-depth\n                        if (!this.videoSourcesToMsidMap.has(trackId)) {\n                            streamId = `${streamId}-${this.videoSourcesToMsidMap.size}`;\n                            this.videoSourcesToMsidMap.set(trackId, streamId);\n                        }\n                    } else if (!this.audioSourcesToMsidMap.has(trackId)) {\n                        streamId = `${streamId}-${this.audioSourcesToMsidMap.size}`;\n                        this.audioSourcesToMsidMap.set(trackId, streamId);\n                    }\n\n                    streamId = mediaType === MediaType.VIDEO\n                        ? this.videoSourcesToMsidMap.get(trackId)\n                        : this.audioSourcesToMsidMap.get(trackId);\n\n                    ssrcLine.value = this._generateMsidAttribute(mediaType, trackId, streamId);\n                } else {\n                    logger.warn(`Unable to munge local MSID - weird format detected: ${ssrcLine.value}`);\n                }\n                break;\n            }\n            }\n        }\n\n        // Additional transformations related to MSID are applicable to Unified-plan implementation only.\n        if (!this.tpc.usesUnifiedPlan()) {\n            return;\n        }\n\n        const mediaDirection = mediaSection.mLine?.direction;\n\n        // On FF when the user has started muted create answer will generate a recv only SSRC. We don't want to signal\n        // this SSRC in order to reduce the load of the xmpp server for large calls. Therefore the SSRC needs to be\n        // removed from the SDP.\n        //\n        // For all other use cases (when the user has had media but then the user has stopped it) we want to keep the\n        // receive only SSRCs in the SDP. Otherwise source-remove will be triggered and the next time the user add a\n        // track we will reuse the SSRCs and send source-add with the same SSRCs. This is problematic because of issues\n        // on Chrome and FF (https://bugzilla.mozilla.org/show_bug.cgi?id=1768729) when removing and then adding the\n        // same SSRC in the remote sdp the remote track is not rendered.\n        if (browser.isFirefox()\n            && (mediaDirection === MediaDirection.RECVONLY || mediaDirection === MediaDirection.INACTIVE)\n            && (\n                (mediaType === MediaType.VIDEO && !this.tpc._hasHadVideoTrack)\n                || (mediaType === MediaType.AUDIO && !this.tpc._hasHadAudioTrack)\n            )\n        ) {\n            mediaSection.ssrcs = undefined;\n            mediaSection.ssrcGroups = undefined;\n        }\n\n        const msidLine = mediaSection.mLine?.msid;\n        const trackId = msidLine && msidLine.split(' ')[1];\n        const sources = [ ...new Set(mediaSection.mLine?.ssrcs?.map(s => s.id)) ];\n\n        for (const source of sources) {\n            const msidExists = mediaSection.ssrcs\n                .find(ssrc => ssrc.id === source && ssrc.attribute === 'msid');\n\n            if (!msidExists && trackId) {\n                const generatedMsid = this._generateMsidAttribute(mediaType, trackId);\n\n                mediaSection.ssrcs.push({\n                    id: source,\n                    attribute: 'msid',\n                    value: generatedMsid\n                });\n            }\n        }\n    }\n\n    /**\n     * Maybe modifies local description to fake local video tracks SDP when\n     * those are muted.\n     *\n     * @param {object} desc the WebRTC SDP object instance for the local\n     * description.\n     * @returns {RTCSessionDescription}\n     */\n    maybeAddMutedLocalVideoTracksToSDP(desc) {\n        if (!desc) {\n            throw new Error('No local description passed in.');\n        }\n\n        const transformer = new SdpTransformWrap(desc.sdp);\n\n        if (this._addMutedLocalVideoTracksToSDP(transformer)) {\n            return new RTCSessionDescription({\n                type: desc.type,\n                sdp: transformer.toRawSDP()\n            });\n        }\n\n        return desc;\n    }\n\n    /**\n     * This transformation will make sure that stream identifiers are unique\n     * across all of the local PeerConnections even if the same stream is used\n     * by multiple instances at the same time.\n     * Each PeerConnection assigns different SSRCs to the same local\n     * MediaStream, but the MSID remains the same as it's used to identify\n     * the stream by the WebRTC backend. The transformation will append\n     * {@link TraceablePeerConnection#id} at the end of each stream's identifier\n     * (\"cname\", \"msid\", \"label\" and \"mslabel\").\n     *\n     * @param {RTCSessionDescription} sessionDesc - The local session\n     * description (this instance remains unchanged).\n     * @return {RTCSessionDescription} - Transformed local session description\n     * (a modified copy of the one given as the input).\n     */\n    transformStreamIdentifiers(sessionDesc) {\n        // FIXME similar check is probably duplicated in all other transformers\n        if (!sessionDesc || !sessionDesc.sdp || !sessionDesc.type) {\n            return sessionDesc;\n        }\n\n        const transformer = new SdpTransformWrap(sessionDesc.sdp);\n        const audioMLine = transformer.selectMedia(MediaType.AUDIO)?.[0];\n\n        if (audioMLine) {\n            this._transformMediaIdentifiers(audioMLine);\n            this._injectSourceNames(audioMLine);\n        }\n\n        const videoMlines = transformer.selectMedia(MediaType.VIDEO);\n\n        if (!FeatureFlags.isMultiStreamSendSupportEnabled()) {\n            videoMlines.splice(1);\n        }\n\n        for (const videoMLine of videoMlines) {\n            this._transformMediaIdentifiers(videoMLine);\n            this._injectSourceNames(videoMLine);\n        }\n\n        // Plan-b clients generate new SSRCs and trackIds whenever tracks are removed and added back to the\n        // peerconnection, therefore local track based map for msids needs to be reset after every transformation.\n        if (!this.tpc._usesUnifiedPlan) {\n            this.audioSourcesToMsidMap.clear();\n            this.videoSourcesToMsidMap.clear();\n        }\n\n        return new RTCSessionDescription({\n            type: sessionDesc.type,\n            sdp: transformer.toRawSDP()\n        });\n    }\n\n    /**\n     * Injects source names. Source names are need to for multiple streams per endpoint support. The final plan is to\n     * use the \"mid\" attribute for source names, but because the SDP to Jingle conversion still operates in the Plan-B\n     * semantics (one source name per media), a custom \"name\" attribute is injected into SSRC lines..\n     *\n     * @param {MLineWrap} mediaSection - The media part (audio or video) of the session description which will be\n     * modified in place.\n     * @returns {void}\n     * @private\n     */\n    _injectSourceNames(mediaSection) {\n        const sources = [ ...new Set(mediaSection.mLine?.ssrcs?.map(s => s.id)) ];\n        const mediaType = mediaSection.mLine?.type;\n\n        if (!mediaType) {\n            throw new Error('_transformMediaIdentifiers - no media type in mediaSection');\n        }\n\n        for (const source of sources) {\n            const nameExists = mediaSection.ssrcs.find(ssrc => ssrc.id === source && ssrc.attribute === 'name');\n            const msid = mediaSection.ssrcs.find(ssrc => ssrc.id === source && ssrc.attribute === 'msid')?.value;\n            let trackIndex;\n\n            if (msid) {\n                const streamId = msid.split(' ')[0];\n\n                // Example stream id: d8ff91-video-8-1\n                // In the example above 8 is the track index\n                const trackIndexParts = streamId.split('-');\n\n                trackIndex = trackIndexParts[trackIndexParts.length - 2];\n            }\n\n            const sourceName = getSourceNameForJitsiTrack(this.localEndpointId, mediaType, trackIndex);\n\n            if (!nameExists) {\n                // Inject source names as a=ssrc:3124985624 name:endpointA-v0\n                mediaSection.ssrcs.push({\n                    id: source,\n                    attribute: 'name',\n                    value: sourceName\n                });\n            }\n\n            if (mediaType === MediaType.VIDEO) {\n                const videoType = this.tpc.getLocalVideoTracks().find(track => track.getSourceName() === sourceName)\n                    ?.getVideoType();\n\n                if (videoType) {\n                    // Inject videoType as a=ssrc:1234 videoType:desktop.\n                    mediaSection.ssrcs.push({\n                        id: source,\n                        attribute: 'videoType',\n                        value: videoType\n                    });\n                }\n            }\n        }\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\n\nimport SDPUtil from './SDPUtil';\nimport { SdpTransformWrap, parseSecondarySSRC } from './SdpTransformUtil';\n\nconst logger = getLogger(__filename);\n\n/**\n * Begin helper functions\n */\n/**\n * Updates or inserts the appropriate rtx information for primarySsrc with\n *  the given rtxSsrc.  If no rtx ssrc for primarySsrc currently exists, it will\n *  add the appropriate ssrc and ssrc group lines.  If primarySsrc already has\n *  an rtx ssrc, the appropriate ssrc and group lines will be updated\n * @param {MLineWrap} mLine\n * @param {object} primarySsrcInfo the info (ssrc, msid & cname) for the\n *  primary ssrc\n * @param {number} rtxSsrc the rtx ssrc to associate with the primary ssrc\n */\nfunction updateAssociatedRtxStream(mLine, primarySsrcInfo, rtxSsrc) {\n    const primarySsrc = primarySsrcInfo.id;\n    const primarySsrcMsid = primarySsrcInfo.msid;\n    const primarySsrcCname = primarySsrcInfo.cname;\n\n    const previousRtxSSRC = mLine.getRtxSSRC(primarySsrc);\n\n    if (previousRtxSSRC === rtxSsrc) {\n        return;\n    }\n    if (previousRtxSSRC) {\n        // Stream already had an rtx ssrc that is different than the one given,\n        //  remove all trace of the old one\n        mLine.removeSSRC(previousRtxSSRC);\n        mLine.removeGroupsWithSSRC(previousRtxSSRC);\n    }\n    mLine.addSSRCAttribute({\n        id: rtxSsrc,\n        attribute: 'cname',\n        value: primarySsrcCname\n    });\n    mLine.addSSRCAttribute({\n        id: rtxSsrc,\n        attribute: 'msid',\n        value: primarySsrcMsid\n    });\n    mLine.addSSRCGroup({\n        semantics: 'FID',\n        ssrcs: `${primarySsrc} ${rtxSsrc}`\n    });\n}\n\n/**\n * End helper functions\n */\n\n/**\n * Adds any missing RTX streams for video streams\n *  and makes sure that they remain consistent\n */\nexport default class RtxModifier {\n    /**\n     * Constructor\n     */\n    constructor() {\n        /**\n         * Map of video ssrc to corresponding RTX\n         *  ssrc\n         */\n        this.correspondingRtxSsrcs = new Map();\n    }\n\n    /**\n     * Clear the cached map of primary video ssrcs to\n     *  their corresponding rtx ssrcs so that they will\n     *  not be used for the next call to modifyRtxSsrcs\n     */\n    clearSsrcCache() {\n        this.correspondingRtxSsrcs.clear();\n    }\n\n    /**\n     * Explicitly set the primary video ssrc -> rtx ssrc\n     *  mapping to be used in modifyRtxSsrcs\n     * @param {Map} ssrcMapping a mapping of primary video\n     *  ssrcs to their corresponding rtx ssrcs\n     */\n    setSsrcCache(ssrcMapping) {\n        logger.debug('Setting ssrc cache to ', ssrcMapping);\n        this.correspondingRtxSsrcs = ssrcMapping;\n    }\n\n    /**\n     * Adds RTX ssrcs for any video ssrcs that don't already have them.  If the video ssrc has been seen before, and\n     * already had an RTX ssrc generated, the same RTX ssrc will be used again.\n     *\n     * @param {string} sdpStr sdp in raw string format\n     * @returns {string} The modified sdp in raw string format.\n     */\n    modifyRtxSsrcs(sdpStr) {\n        let modified = false;\n        const sdpTransformer = new SdpTransformWrap(sdpStr);\n        const videoMLines = sdpTransformer.selectMedia(MediaType.VIDEO);\n\n        if (!videoMLines?.length) {\n            logger.debug(`No 'video' media found in the sdp: ${sdpStr}`);\n\n            return sdpStr;\n        }\n\n        for (const videoMLine of videoMLines) {\n            if (this.modifyRtxSsrcs2(videoMLine)) {\n                modified = true;\n            }\n        }\n\n        return modified ? sdpTransformer.toRawSDP() : sdpStr;\n    }\n\n    /**\n     * Does the same thing as {@link modifyRtxSsrcs}, but takes the {@link MLineWrap} instance wrapping video media as\n     * an argument.\n     * @param {MLineWrap} videoMLine\n     * @return {boolean} <tt>true</tt> if the SDP wrapped by {@link SdpTransformWrap} has been modified or\n     * <tt>false</tt> otherwise.\n     */\n    modifyRtxSsrcs2(videoMLine) {\n        if (videoMLine.direction === MediaDirection.RECVONLY) {\n            return false;\n        }\n        if (videoMLine.getSSRCCount() < 1) {\n            return false;\n        }\n        const primaryVideoSsrcs = videoMLine.getPrimaryVideoSSRCs();\n\n        for (const ssrc of primaryVideoSsrcs) {\n            const msid = videoMLine.getSSRCAttrValue(ssrc, 'msid');\n            const cname = videoMLine.getSSRCAttrValue(ssrc, 'cname');\n            let correspondingRtxSsrc = this.correspondingRtxSsrcs.get(ssrc);\n\n            if (!correspondingRtxSsrc) {\n                // If there's one in the sdp already for it, we'll just set\n                //  that as the corresponding one\n                const previousAssociatedRtxStream = videoMLine.getRtxSSRC(ssrc);\n\n                if (previousAssociatedRtxStream) {\n                    correspondingRtxSsrc = previousAssociatedRtxStream;\n                } else {\n                    correspondingRtxSsrc = SDPUtil.generateSsrc();\n                }\n                this.correspondingRtxSsrcs.set(ssrc, correspondingRtxSsrc);\n            }\n            updateAssociatedRtxStream(\n                videoMLine,\n                {\n                    id: ssrc,\n                    cname,\n                    msid\n                },\n                correspondingRtxSsrc);\n        }\n\n        // FIXME we're not looking into much details whether the SDP has been\n        // modified or not once the precondition requirements are met.\n        return true;\n    }\n\n    /**\n     * Strip all rtx streams from the given sdp.\n     *\n     * @param {string} sdpStr sdp in raw string format\n     * @returns {string} sdp string with all rtx streams stripped\n     */\n    stripRtx(sdpStr) {\n        const sdpTransformer = new SdpTransformWrap(sdpStr);\n        const videoMLines = sdpTransformer.selectMedia(MediaType.VIDEO);\n\n        if (!videoMLines?.length) {\n            logger.debug(`No 'video' media found in the sdp: ${sdpStr}`);\n\n            return sdpStr;\n        }\n\n        for (const videoMLine of videoMLines) {\n            if (videoMLine.direction !== MediaDirection.RECVONLY\n                && videoMLine.getSSRCCount()\n                && videoMLine.containsAnySSRCGroups()) {\n                const fidGroups = videoMLine.findGroups('FID');\n\n                // Remove the fid groups from the mline\n                videoMLine.removeGroupsBySemantics('FID');\n\n                // Get the rtx ssrcs and remove them from the mline\n                for (const fidGroup of fidGroups) {\n                    const rtxSsrc = parseSecondarySSRC(fidGroup);\n\n                    videoMLine.removeSSRC(rtxSsrc);\n                }\n            }\n        }\n\n        return sdpTransformer.toRawSDP();\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport { MediaType } from '../../service/RTC/MediaType';\n\nimport {\n    SdpTransformWrap,\n    parsePrimarySSRC,\n    parseSecondarySSRC\n} from './SdpTransformUtil';\n\nconst logger = getLogger(__filename);\n\n/**\n * Handles the work of keeping video ssrcs consistent across multiple\n * o/a cycles, making it such that all stream operations can be\n * kept local and do not need to be signaled.\n * NOTE: This only keeps the 'primary' video ssrc consistent: meaning\n * the primary video stream\n */\nexport default class SdpConsistency {\n    /**\n     * Constructor\n     * @param {string} logPrefix the log prefix appended to every logged\n     * message, currently used to distinguish for which\n     * <tt>TraceablePeerConnection</tt> the instance works.\n     */\n    constructor(logPrefix) {\n        this.clearVideoSsrcCache();\n        this.logPrefix = logPrefix;\n    }\n\n    /**\n     * Clear the cached video primary and primary rtx ssrcs so that\n     *  they will not be used for the next call to\n     *  makeVideoPrimarySsrcsConsistent\n     */\n    clearVideoSsrcCache() {\n        this.cachedPrimarySsrc = null;\n        this.injectRecvOnly = false;\n    }\n\n    /**\n     * Explicitly set the primary ssrc to be used in\n     *  makeVideoPrimarySsrcsConsistent\n     * @param {number} primarySsrc the primarySsrc to be used\n     *  in future calls to makeVideoPrimarySsrcsConsistent\n     * @throws Error if <tt>primarySsrc</tt> is not a number\n     */\n    setPrimarySsrc(primarySsrc) {\n        if (typeof primarySsrc !== 'number') {\n            throw new Error('Primary SSRC must be a number!');\n        }\n        this.cachedPrimarySsrc = primarySsrc;\n    }\n\n    /**\n     * Checks whether or not there is a primary video SSRC cached already.\n     * @return {boolean}\n     */\n    hasPrimarySsrcCached() {\n        return Boolean(this.cachedPrimarySsrc);\n    }\n\n    /**\n     * Given an sdp string, either:\n     *  1) record the primary video and primary rtx ssrcs to be\n     *   used in future calls to makeVideoPrimarySsrcsConsistent or\n     *  2) change the primary and primary rtx ssrcs in the given sdp\n     *   to match the ones previously cached\n     * @param {string} sdpStr the sdp string to (potentially)\n     *  change to make the video ssrcs consistent\n     * @returns {string} a (potentially) modified sdp string\n     *  with ssrcs consistent with this class' cache\n     */\n    makeVideoPrimarySsrcsConsistent(sdpStr) {\n        const sdpTransformer = new SdpTransformWrap(sdpStr);\n        const videoMLine = sdpTransformer.selectMedia(MediaType.VIDEO)?.[0];\n\n        if (!videoMLine) {\n            logger.debug(`${this.logPrefix} no 'video' media found in the sdp: ${sdpStr}`);\n\n            return sdpStr;\n        }\n\n        if (videoMLine.direction === 'recvonly') {\n            // If the mline is recvonly, we'll add the primary\n            //  ssrc as a recvonly ssrc\n            if (this.cachedPrimarySsrc && this.injectRecvOnly) {\n                videoMLine.addSSRCAttribute({\n                    id: this.cachedPrimarySsrc,\n                    attribute: 'cname',\n                    value: `recvonly-${this.cachedPrimarySsrc}`\n                });\n            } else {\n                logger.info(`${this.logPrefix} no SSRC found for the recvonly video stream!`);\n            }\n        } else {\n            const newPrimarySsrc = videoMLine.getPrimaryVideoSsrc();\n\n            if (!newPrimarySsrc) {\n                logger.info(`${this.logPrefix} sdp-consistency couldn't parse new primary ssrc`);\n\n                return sdpStr;\n            }\n            if (this.cachedPrimarySsrc) {\n                videoMLine.replaceSSRC(newPrimarySsrc, this.cachedPrimarySsrc);\n                for (const group of videoMLine.ssrcGroups) {\n                    if (group.semantics === 'FID') {\n                        const primarySsrc = parsePrimarySSRC(group);\n                        const rtxSsrc = parseSecondarySSRC(group);\n\n                        // eslint-disable-next-line max-depth\n                        if (primarySsrc === newPrimarySsrc) {\n                            group.ssrcs\n                                = `${this.cachedPrimarySsrc} ${rtxSsrc}`;\n                        }\n                    }\n                }\n            } else {\n                this.cachedPrimarySsrc = newPrimarySsrc;\n            }\n            this.injectRecvOnly = true;\n        }\n\n        return sdpTransformer.toRawSDP();\n    }\n}\n","import { MediaDirection } from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\n\nimport * as transform from 'sdp-transform';\n\nconst DEFAULT_NUM_OF_LAYERS = 3;\n\ninterface Description {\n    type: RTCSdpType;\n    sdp: string;\n}\n\ninterface Options {\n    numOfLayers?: number\n}\n\n/**\n * This class handles SDP munging for enabling simulcast for local video streams in Unified plan. A set of random SSRCs\n * are generated for the higher layer streams and they are cached for a given mid. The cached SSRCs are then reused on\n * the subsequent iterations while munging the local description. This class also handles imploding of the simulcast\n * SSRCs for remote endpoints into the primary FID group in remote description since Jicofo signals all SSRCs relevant\n * to a given endpoint.\n */\nexport default class SdpSimulcast {\n    private _options: Options;\n    private _ssrcCache: Map<string, Array<number>>;\n\n    /**\n     * Creates a new instance.\n     *\n     * @param options\n     */\n    constructor(options: Options) {\n        this._options = options;\n        this._ssrcCache = new Map();\n\n        if (!this._options.numOfLayers) {\n            this._options.numOfLayers = DEFAULT_NUM_OF_LAYERS;\n        }\n    }\n\n    /**\n     * Updates the given media description using the SSRCs that were cached for the mid associated\n     * with the media description and returns the modified media description.\n     *\n     * @param mLine\n     * @returns\n     */\n     _fillSsrcsFromCache(mLine: transform.MediaDescription) : any {\n        const mid = mLine.mid;\n        const cachedSsrcs = this._ssrcCache.get(mid);\n        const newSsrcs = this._parseSimLayers(mLine);\n        const newMsid = this._getSsrcAttribute(mLine, newSsrcs[0], 'msid');\n        const newCname = this._getSsrcAttribute(mLine, newSsrcs[0], 'cname');\n\n        mLine.ssrcs = [];\n        mLine.ssrcGroups = [];\n\n        for (const ssrc of cachedSsrcs) {\n            mLine.ssrcs.push({\n                id: ssrc,\n                attribute: 'msid',\n                value: newMsid\n            });\n            mLine.ssrcs.push({\n                id: ssrc,\n                attribute: 'cname',\n                value: newCname\n            });\n        }\n\n        mLine.ssrcGroups.push({\n            semantics: 'SIM',\n            ssrcs: cachedSsrcs.join(' ')\n        });\n\n        return mLine;\n    }\n\n    /**\n     * Generates a new set of SSRCs for the higher simulcast layers/streams and adds the attributes and SIM group to\n     * the given media description and returns the modified media description.\n     *\n     * @param mLine\n     * @param primarySsrc\n     * @returns\n     */\n    _generateNewSsrcsForSimulcast(mLine: transform.MediaDescription, primarySsrc: number) : any {\n        const cname = this._getSsrcAttribute(mLine, primarySsrc, 'cname');\n        let msid = this._getSsrcAttribute(mLine, primarySsrc, 'msid');\n        const addAssociatedAttributes = (mLine: transform.MediaDescription, ssrc: number) => {\n            mLine.ssrcs.push({\n                id: ssrc,\n                attribute: 'cname',\n                value: cname\n            });\n            mLine.ssrcs.push({\n                id: ssrc,\n                attribute: 'msid',\n                value: msid\n            });\n        }\n\n        // In Unified-plan mode, the a=ssrc lines with the msid attribute are not present (only cname attributes are\n        // present) in the answers that Chrome and Safari generate for an offer received from Jicofo. Generate these\n        // a=ssrc lines using the msid values from the a=msid line.\n        if (!msid) {\n            msid = mLine.msid;\n            const primarySsrcs = mLine.ssrcs;\n\n            primarySsrcs.forEach(ssrc => {\n                mLine.ssrcs.push({\n                    id: ssrc.id,\n                    attribute: 'msid',\n                    value: msid\n                });\n            })\n        }\n\n        // Generate SIM layers.\n        const simSsrcs = [];\n\n        for (let i = 0; i < this._options.numOfLayers - 1; ++i) {\n            const simSsrc = this._generateSsrc();\n\n            addAssociatedAttributes(mLine, simSsrc);\n            simSsrcs.push(simSsrc);\n        }\n\n        mLine.ssrcGroups = mLine.ssrcGroups || [];\n        mLine.ssrcGroups.push({\n            semantics: 'SIM',\n            ssrcs: primarySsrc + ' ' + simSsrcs.join(' ')\n        });\n\n        return mLine;\n    }\n\n    /**\n     * Returns a random number to be used for the SSRC.\n     *\n     * @returns\n     */\n    _generateSsrc() : number {\n        const max = 0xffffffff;\n\n        return Math.floor(Math.random() * max);\n    }\n\n    /**\n     * Returns the requested attribute value for a SSRC from a given media description.\n     *\n     * @param mLine\n     * @param ssrc\n     * @param attributeName\n     * @returns\n     */\n    _getSsrcAttribute(mLine: transform.MediaDescription, ssrc: number, attributeName: string) : string | undefined {\n        return mLine.ssrcs?.find(\n            ssrcInfo => Number(ssrcInfo.id) === ssrc\n            && ssrcInfo.attribute === attributeName)?.value;\n    }\n\n    /**\n     * Returns an array of all the primary SSRCs in the SIM group for a given media description.\n     *\n     * @param mLine\n     * @returns\n     */\n    _parseSimLayers(mLine: transform.MediaDescription) : Array<number> | null {\n        const simGroup = mLine.ssrcGroups?.find(group => group.semantics === 'SIM');\n\n        if (simGroup) {\n            return simGroup.ssrcs.split(' ').map(ssrc => Number(ssrc));\n        }\n\n        if (mLine.ssrcs?.length) {\n            return [ Number(mLine.ssrcs[0].id) ];\n        }\n\n        return null;\n    }\n\n    /**\n     * Munges the given media description to enable simulcast for the video media sections that are in either have\n     * SENDRECV or SENDONLY as the media direction thereby ignoring all the RECVONLY transceivers created for remote\n     * endpoints.\n     * NOTE: This needs to be called only when simulcast is enabled.\n     *\n     * @param description\n     * @returns\n     */\n    mungeLocalDescription(description: Description) : Description {\n        if (!description || !description.sdp) {\n            return description;\n        }\n        const session = transform.parse(description.sdp);\n\n        for (let media of session.media) {\n            // Ignore recvonly and inactive transceivers created for remote sources.\n            if (media.direction === MediaDirection.RECVONLY || media.direction === MediaDirection.INACTIVE) {\n                continue;\n            }\n\n            // Ignore audio m-lines.\n            if (media.type !== MediaType.VIDEO) {\n                continue;\n            }\n            const mid = media.mid;\n            const numSsrcs = new Set(media.ssrcs?.map(ssrcInfo => ssrcInfo.id));\n            const numGroups = media.ssrcGroups?.length ?? 0;\n            let primarySsrc: number;\n\n            // Do not munge if the description has no ssrcs or if simulcast is already enabled.\n            if (numSsrcs.size === 0 || numSsrcs.size > 2 || (numSsrcs.size === 2 && numGroups === 0)) {\n                continue;\n            }\n            if (numSsrcs.size === 1) {\n                primarySsrc = Number(media.ssrcs[0]?.id);\n            } else {\n                const fidGroup = media.ssrcGroups.find(group => group.semantics === 'FID');\n\n                if (fidGroup) {\n                    primarySsrc = Number(fidGroup.ssrcs.split(' ')[0]);\n                }\n            }\n\n            if (this._ssrcCache.has(mid)) {\n                media = this._fillSsrcsFromCache(media);\n            } else {\n                media = this._generateNewSsrcsForSimulcast(media, primarySsrc);\n                const simulcastSsrcs = this._parseSimLayers(media);\n\n                // Update the SSRCs in the cache so that they can re-used for the same mid again.\n                this._ssrcCache.set(mid, simulcastSsrcs);\n            }\n        }\n\n        return new RTCSessionDescription({\n            type: description.type,\n            sdp: transform.write(session)\n        });\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport { JitsiConferenceEvents } from '../../JitsiConferenceEvents';\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport { createTrackStreamingStatusEvent } from '../../service/statistics/AnalyticsEvents';\nimport JitsiConference from '../../types/hand-crafted/JitsiConference';\nimport JitsiRemoteTrack from '../../types/hand-crafted/modules/RTC/JitsiRemoteTrack';\nimport RTC from '../../types/hand-crafted/modules/RTC/RTC';\nimport { VideoType } from '../../types/hand-crafted/service/RTC/VideoType';\nimport browser from '../browser';\nimport Statistics from '../statistics/statistics';\n\n/** Track streaming statuses. */\nexport enum TrackStreamingStatus {\n\n    /**\n     * Status indicating that streaming is currently active.\n     */\n    ACTIVE = 'active',\n\n    /**\n     * Status indicating that streaming is currently inactive.\n     * Inactive means the streaming was stopped on purpose from the bridge, like exiting forwarded sources or\n     * adaptivity decided to drop video because of not enough bandwidth.\n     */\n    INACTIVE = 'inactive',\n\n    /**\n     * Status indicating that streaming is currently interrupted.\n     */\n    INTERRUPTED = 'interrupted',\n\n    /**\n     * Status indicating that streaming is currently restoring.\n     */\n    RESTORING = 'restoring',\n  }\n\ntype StreamingStatusMap = {\n    // TODO: Replace this hand crafted VideoType when we convert VideoType.js to Typescript.\n    videoType?: VideoType,\n    startedMs?: number,\n    p2p?: boolean,\n    streamingStatus?: string,\n    value?: number\n};\n\nconst logger = getLogger(__filename);\n\n/**\n * Default value of 500 milliseconds for {@link TrackStreamingStatusImpl.outOfForwardedSourcesTimeout}.\n */\nconst DEFAULT_NOT_IN_FORWARDED_SOURCES_TIMEOUT = 500;\n\n/**\n * Default value of 2500 milliseconds for {@link TrackStreamingStatusImpl.p2pRtcMuteTimeout}.\n */\nconst DEFAULT_P2P_RTC_MUTE_TIMEOUT = 2500;\n\n/**\n * Default value of 10000 milliseconds for {@link TrackStreamingStatusImpl.rtcMuteTimeout}.\n */\nconst DEFAULT_RTC_MUTE_TIMEOUT = 10000;\n\n/**\n * The time to wait a track to be restored. Track which was out of forwarded sources should be inactive and when\n * entering forwarded sources it becomes restoring and when data is received from bridge it will become active, but if\n * no data is received for some time we set status of that track streaming to interrupted.\n */\nconst DEFAULT_RESTORING_TIMEOUT = 10000;\n\n/**\n * Class is responsible for emitting JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED events.\n */\nexport class TrackStreamingStatusImpl {\n    rtc: RTC;\n    conference: JitsiConference;\n    track: JitsiRemoteTrack;\n\n    /**  This holds the timeout callback ID scheduled using window.setTimeout. */\n    trackTimer: number | null;\n\n    /**\n     * If video track frozen detection through RTC mute event is supported, we wait some time until video track is\n     * considered frozen. But because when the track falls out of forwarded sources it is expected for the video to\n     * freeze this timeout must be significantly reduced in \"out of forwarded sources\" case.\n     *\n     * Basically this value is used instead of {@link rtcMuteTimeout} when track is not in forwarded sources.\n     */\n    outOfForwardedSourcesTimeout: number;\n\n    /**\n     * How long we are going to wait for the corresponding signaling mute event after the RTC video track muted\n     * event is fired on the Media stream, before the connection interrupted is fired. The default value is\n     * {@link DEFAULT_P2P_RTC_MUTE_TIMEOUT}.\n     */\n    p2pRtcMuteTimeout: number;\n\n    /**\n     * How long we're going to wait after the RTC video track muted event for the corresponding signalling mute\n     * event, before the connection interrupted is fired. The default value is {@link DEFAULT_RTC_MUTE_TIMEOUT}.\n     *\n     * @returns amount of time in milliseconds\n     */\n    rtcMuteTimeout: number;\n\n    /**\n     * This holds a timestamp indicating  when remote video track was RTC muted. The purpose of storing the\n     * timestamp is to avoid the transition to disconnected status in case of legitimate video mute operation where\n     * the signalling video muted event can arrive shortly after RTC muted event.\n     *\n     * The timestamp is measured in milliseconds obtained with <tt>Date.now()</tt>.\n     *\n     * FIXME merge this logic with NO_DATA_FROM_SOURCE event implemented in JitsiLocalTrack by extending the event\n     * to the remote track and allowing to set different timeout for local and remote tracks.\n     */\n    rtcMutedTimestamp: number | null;\n\n    /** This holds the restoring timeout callback ID scheduled using window.setTimeout. */\n    restoringTimer: ReturnType<typeof setTimeout> | null;\n\n    /**\n     * This holds the current streaming status (along with all the internal events that happen while in that\n     * state).\n     *\n     * The goal is to send this information to the analytics backend for post-mortem analysis.\n     */\n    streamingStatusMap: StreamingStatusMap;\n\n    _onP2PStatus: () => void;\n    _onUserLeft: () => void;\n    _onTrackRtcMuted: () => void;\n    _onTrackRtcUnmuted: () => void;\n    _onSignallingMuteChanged: () => void;\n    _onTrackVideoTypeChanged: () => void;\n    _onLastNValueChanged: () => void;\n    _onForwardedSourcesChanged: () => void;\n\n    /* eslint-disable max-params*/\n    /**\n     * Calculates the new {@link TrackStreamingStatus} based on the values given for some specific remote track. It is\n     * assumed that the conference is currently in the JVB mode (in contrary to the P2P mode)\n     * @param isInForwardedSources - indicates whether the track is in the forwarded sources set. When set to\n     * false it means that JVB is not sending any video for the track.\n     * @param isRestoringTimedout - if true it means that the track has been outside of forwarded sources too\n     * long to be considered {@link TrackStreamingStatus.RESTORING}.\n     * @param isVideoMuted - true if the track is video muted and we should not expect to receive any video.\n     * @param isVideoTrackFrozen - if the current browser support video frozen detection then it will be set to\n     * true when the video track is frozen. If the current browser does not support frozen detection the it's always\n     * false.\n     * @return {TrackStreamingStatus} the new streaming status for the track for whom the values above were provided.\n     * @private\n     */\n    static _getNewStateForJvbMode(\n            isInForwardedSources: boolean,\n            isRestoringTimedout: boolean,\n            isVideoMuted: boolean,\n            isVideoTrackFrozen: boolean): TrackStreamingStatus {\n\n        // We are currently not checking the endpoint connection status received from the JVB.\n        if (isVideoMuted) {\n            // If the connection is active according to JVB and the track is video muted there is no way for the\n            // connection to be inactive, because the detection logic below only makes sense for video.\n            return TrackStreamingStatus.ACTIVE;\n        }\n\n        // Logic when isVideoTrackFrozen is supported\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\n            if (!isVideoTrackFrozen) {\n                // If the video is playing we're good\n                return TrackStreamingStatus.ACTIVE;\n            } else if (isInForwardedSources) {\n                return isRestoringTimedout ? TrackStreamingStatus.INTERRUPTED : TrackStreamingStatus.RESTORING;\n            }\n\n            return TrackStreamingStatus.INACTIVE;\n        }\n\n        // Because this browser is incapable of detecting frozen video we must rely on the forwarded sources value\n        return isInForwardedSources ? TrackStreamingStatus.ACTIVE : TrackStreamingStatus.INACTIVE;\n    }\n\n    /* eslint-enable max-params*/\n\n    /**\n     * In P2P mode we don't care about any values coming from the JVB and the streaming status can be only active or\n     * interrupted.\n     * @param isVideoMuted - true if video muted\n     * @param isVideoTrackFrozen - true if the video track for the remote track is currently frozen. If the\n     * current browser does not support video frozen detection then it's always false.\n     * @return {TrackStreamingStatus}\n     * @private\n     */\n    static _getNewStateForP2PMode(isVideoMuted: boolean, isVideoTrackFrozen: boolean): TrackStreamingStatus {\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\n            // There's no way to detect problems in P2P when there's no video track frozen detection...\n            return TrackStreamingStatus.ACTIVE;\n        }\n\n        return isVideoMuted || !isVideoTrackFrozen\n            ? TrackStreamingStatus.ACTIVE : TrackStreamingStatus.INTERRUPTED;\n    }\n\n    /**\n     * Creates new instance of <tt>TrackStreamingStatus</tt>.\n     *\n     * @constructor\n     * @param rtc - the RTC service instance\n     * @param conference - parent conference instance\n     * @param {Object} options\n     * @param {number} [options.p2pRtcMuteTimeout=2500] custom value for\n     * {@link TrackStreamingStatusImpl.p2pRtcMuteTimeout}.\n     * @param {number} [options.rtcMuteTimeout=2000] custom value for\n     * {@link TrackStreamingStatusImpl.rtcMuteTimeout}.\n     * @param {number} [options.outOfForwardedSourcesTimeout=500] custom value for\n     * {@link TrackStreamingStatusImpl.outOfForwardedSourcesTimeout}.\n     */\n    constructor(rtc: RTC, conference: JitsiConference, track: JitsiRemoteTrack, options: {\n        outOfForwardedSourcesTimeout: number,\n        p2pRtcMuteTimeout: number,\n        rtcMuteTimeout: number\n    }) {\n        this.rtc = rtc;\n        this.conference = conference;\n        this.track = track;\n\n        this.restoringTimer = null;\n        this.rtcMutedTimestamp = null;\n        this.streamingStatusMap = {};\n        this.trackTimer = null;\n\n        this.outOfForwardedSourcesTimeout = typeof options.outOfForwardedSourcesTimeout === 'number'\n            ? options.outOfForwardedSourcesTimeout : DEFAULT_NOT_IN_FORWARDED_SOURCES_TIMEOUT;\n\n        this.p2pRtcMuteTimeout = typeof options.p2pRtcMuteTimeout === 'number'\n            ? options.p2pRtcMuteTimeout : DEFAULT_P2P_RTC_MUTE_TIMEOUT;\n\n        this.rtcMuteTimeout = typeof options.rtcMuteTimeout === 'number'\n            ? options.rtcMuteTimeout : DEFAULT_RTC_MUTE_TIMEOUT;\n        logger.info(`RtcMuteTimeout set to: ${this.rtcMuteTimeout}`);\n    }\n\n    /**\n     * Gets the video frozen timeout for given source name.\n     * @return how long are we going to wait since RTC video muted even, before a video track is considered\n     * frozen.\n     * @private\n     */\n    _getVideoFrozenTimeout(): number {\n        const sourceName = this.track.getSourceName();\n\n        return this.rtc.isInForwardedSources(sourceName)\n            ? this.rtcMuteTimeout\n            : this.conference.isP2PActive() ? this.p2pRtcMuteTimeout : this.outOfForwardedSourcesTimeout;\n    }\n\n    /**\n     * Initializes <tt>TrackStreamingStatus</tt> and bind required event listeners.\n     */\n    init(): void {\n        // Handles P2P status changes\n        this._onP2PStatus = this.figureOutStreamingStatus.bind(this);\n        this.conference.on(JitsiConferenceEvents.P2P_STATUS, this._onP2PStatus);\n\n        // Used to send analytics events for the participant that left the call.\n        this._onUserLeft = this.onUserLeft.bind(this);\n        this.conference.on(JitsiConferenceEvents.USER_LEFT, this._onUserLeft);\n\n        // On some browsers MediaStreamTrack trigger \"onmute\"/\"onunmute\" events for video type tracks when they stop\n        // receiving data which is often a sign that remote user is having connectivity issues.\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\n\n            this._onTrackRtcMuted = this.onTrackRtcMuted.bind(this);\n            this.rtc.addListener(RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);\n\n            this._onTrackRtcUnmuted = this.onTrackRtcUnmuted.bind(this);\n            this.rtc.addListener(RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);\n\n            // Listened which will be bound to JitsiRemoteTrack to listen for signalling mute/unmute events.\n            this._onSignallingMuteChanged = this.onSignallingMuteChanged.bind(this);\n            this.track.on(JitsiTrackEvents.TRACK_MUTE_CHANGED, this._onSignallingMuteChanged);\n\n            // Used to send an analytics event when the video type changes.\n            this._onTrackVideoTypeChanged = this.onTrackVideoTypeChanged.bind(this);\n            this.track.on(JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED, this._onTrackVideoTypeChanged);\n        }\n\n        this._onForwardedSourcesChanged = this.onForwardedSourcesChanged.bind(this);\n        this.conference.on(JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED, this._onForwardedSourcesChanged);\n\n        this._onLastNValueChanged = this.figureOutStreamingStatus.bind(this);\n        this.rtc.on(RTCEvents.LASTN_VALUE_CHANGED, this._onLastNValueChanged);\n    }\n\n    /**\n     * Removes all event listeners and disposes of all resources held by this instance.\n     */\n    dispose(): void {\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\n            this.rtc.removeListener(RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);\n            this.rtc.removeListener(RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);\n\n            this.track.off(JitsiTrackEvents.TRACK_MUTE_CHANGED, this._onSignallingMuteChanged);\n        }\n\n        this.conference.off(JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED, this._onForwardedSourcesChanged);\n        this.conference.off(JitsiConferenceEvents.P2P_STATUS, this._onP2PStatus);\n        this.conference.off(JitsiConferenceEvents.USER_LEFT, this._onUserLeft);\n        this.rtc.removeListener(RTCEvents.LASTN_VALUE_CHANGED, this._onLastNValueChanged);\n\n        this.clearTimeout();\n        this.clearRtcMutedTimestamp();\n        this.maybeSendTrackStreamingStatusEvent(Date.now());\n        this.figureOutStreamingStatus();\n    }\n\n    /**\n     * Changes streaming status.\n     * @param newStatus\n     */\n    _changeStreamingStatus(newStatus: TrackStreamingStatus): void {\n        if (this.track.getTrackStreamingStatus() !== newStatus) {\n\n            const sourceName = this.track.getSourceName();\n\n            this.track._setTrackStreamingStatus(newStatus);\n\n            logger.debug(`Emit track streaming status(${Date.now()}) ${sourceName}: ${newStatus}`);\n\n            // Log the event on CallStats\n            Statistics.sendLog(\n                JSON.stringify({\n                    id: 'track.streaming.status',\n                    track: sourceName,\n                    status: newStatus\n                }));\n\n            // It's common for the event listeners to access the JitsiRemoteTrack. Thus pass it as a parameter here.\n            this.track.emit(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED, this.track, newStatus);\n        }\n    }\n\n    /**\n     * Reset the postponed \"streaming interrupted\" event which was previously scheduled as a timeout on RTC 'onmute'\n     * event.\n     */\n    clearTimeout(): void {\n        if (this.trackTimer) {\n            window.clearTimeout(this.trackTimer);\n            this.trackTimer = null;\n        }\n    }\n\n    /**\n     * Clears the timestamp of the RTC muted event for remote video track.\n     */\n    clearRtcMutedTimestamp(): void {\n        this.rtcMutedTimestamp = null;\n    }\n\n    /**\n     * Checks if track is considered frozen.\n     * @return <tt>true</tt> if the video has frozen or <tt>false</tt> when it's either not considered frozen\n     * (yet) or if freeze detection is not supported by the current browser.\n     *\n     * FIXME merge this logic with NO_DATA_FROM_SOURCE event implemented in JitsiLocalTrack by extending the event to\n     *       the remote track and allowing to set different timeout for local and remote tracks.\n     */\n    isVideoTrackFrozen(): boolean {\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\n            return false;\n        }\n\n        const isVideoRTCMuted = this.track.isWebRTCTrackMuted();\n        const rtcMutedTimestamp = this.rtcMutedTimestamp;\n        const timeout = this._getVideoFrozenTimeout();\n\n        return isVideoRTCMuted && typeof rtcMutedTimestamp === 'number' && (Date.now() - rtcMutedTimestamp) >= timeout;\n    }\n\n    /**\n     * Figures out (and updates) the current streaming status for the track identified by the source name.\n     */\n    figureOutStreamingStatus(): void {\n        const sourceName = this.track.getSourceName();\n        const inP2PMode = this.conference.isP2PActive();\n        const isRestoringTimedOut = this._isRestoringTimedout();\n        const audioOnlyMode = this.conference.getLastN() === 0;\n\n        // NOTE Overriding videoMuted to true for audioOnlyMode should disable any detection based on video playback or\n        // forwarded sources.\n        const isVideoMuted = this.track.isMuted() || audioOnlyMode;\n        const isVideoTrackFrozen = this.isVideoTrackFrozen();\n        const isInForwardedSources = this.rtc.isInForwardedSources(sourceName);\n\n        const newState\n            = inP2PMode\n                ? TrackStreamingStatusImpl._getNewStateForP2PMode(\n                    isVideoMuted,\n                    isVideoTrackFrozen)\n                : TrackStreamingStatusImpl._getNewStateForJvbMode(\n                    isInForwardedSources,\n                    isRestoringTimedOut,\n                    isVideoMuted,\n                    isVideoTrackFrozen);\n\n        // if the new state is not restoring clear timers and timestamps that we use to track the restoring state\n        if (newState !== TrackStreamingStatus.RESTORING) {\n            this._clearRestoringTimer();\n        }\n\n        logger.debug(\n            `Figure out conn status for ${sourceName}, is video muted: ${\n                isVideoMuted} video track frozen: ${\n                isVideoTrackFrozen} p2p mode: ${\n                inP2PMode} is in forwarded sources: ${\n                isInForwardedSources} currentStatus => newStatus: ${\n                this.track.getTrackStreamingStatus()} => ${newState}`);\n\n        const oldStreamingStatus = this.streamingStatusMap || {};\n\n        // Send an analytics event (guard on either the p2p flag or the streaming status has changed since the last\n        // time this code block run).\n        if (!('p2p' in oldStreamingStatus)\n            || !('streamingStatus' in oldStreamingStatus)\n            || oldStreamingStatus.p2p !== inP2PMode\n            || oldStreamingStatus.streamingStatus !== newState) {\n\n            const nowMs = Date.now();\n\n            this.maybeSendTrackStreamingStatusEvent(nowMs);\n\n            this.streamingStatusMap = {\n                ...oldStreamingStatus,\n                streamingStatus: newState,\n                p2p: inP2PMode,\n                startedMs: nowMs\n            };\n\n            // sometimes (always?) we're late to hook the TRACK_VIDEOTYPE_CHANGED event and the video type is not in\n            // oldStreamingStatus.\n            if (!('videoType' in this.streamingStatusMap)) {\n                this.streamingStatusMap.videoType = this.track.getVideoType();\n            }\n        }\n        this._changeStreamingStatus(newState);\n    }\n\n    /**\n     * Computes the duration of the current streaming status for the track (i.e. 15 seconds in the INTERRUPTED state)\n     * and sends a track streaming status event.\n     * @param nowMs - The current time (in millis).\n     */\n    maybeSendTrackStreamingStatusEvent(nowMs: number): void {\n        const trackStreamingStatus = this.streamingStatusMap;\n\n        if (trackStreamingStatus\n            && 'startedMs' in trackStreamingStatus\n            && 'videoType' in trackStreamingStatus\n            && 'streamingStatus' in trackStreamingStatus\n            && 'p2p' in trackStreamingStatus) {\n            trackStreamingStatus.value = nowMs - trackStreamingStatus.startedMs;\n            Statistics.sendAnalytics(createTrackStreamingStatusEvent(trackStreamingStatus));\n        }\n    }\n\n    /**\n     * On change in forwarded sources set check all leaving and entering track to change their corresponding statuses.\n     *\n     * @param leavingForwardedSources - The array of sourceName leaving forwarded sources.\n     * @param enteringForwardedSources - The array of sourceName entering forwarded sources.\n     * @param timestamp - The time in millis\n     * @private\n     */\n    onForwardedSourcesChanged(\n            leavingForwardedSources: string[] = [],\n            enteringForwardedSources: string[] = [],\n            timestamp: number): void {\n\n        const sourceName = this.track.getSourceName();\n\n        // If the browser doesn't fire the mute/onmute events when the remote peer stops/starts sending media,\n        // calculate the streaming status for all the tracks since it won't get triggered automatically on the track\n        // that has started/stopped receiving media.\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\n            this.figureOutStreamingStatus();\n        }\n\n        if (leavingForwardedSources.includes(sourceName)) {\n            this.track._clearEnteredForwardedSourcesTimestamp();\n            this._clearRestoringTimer();\n            browser.supportsVideoMuteOnConnInterrupted() && this.figureOutStreamingStatus();\n        }\n\n        if (enteringForwardedSources.includes(sourceName)) {\n            // store the timestamp this track is entering forwarded sources\n            this.track._setEnteredForwardedSourcesTimestamp(timestamp);\n            browser.supportsVideoMuteOnConnInterrupted() && this.figureOutStreamingStatus();\n        }\n    }\n\n    /**\n     * Clears the restoring timer for video track and the timestamp for entering forwarded sources.\n     */\n    _clearRestoringTimer(): void {\n        const rTimer = this.restoringTimer;\n\n        if (rTimer) {\n            clearTimeout(rTimer);\n            this.restoringTimer = null;\n        }\n    }\n\n    /**\n     * Checks whether a track had stayed enough in restoring state, compares current time and the time the track\n     * entered in forwarded sources. If it hasn't timedout and there is no timer added, add new timer in order to give\n     * it more time to become active or mark it as interrupted on next check.\n     *\n     * @returns <tt>true</tt> if the track was in restoring state more than the timeout\n     * ({@link DEFAULT_RESTORING_TIMEOUT}.) in order to set its status to interrupted.\n     * @private\n     */\n    _isRestoringTimedout(): boolean {\n        const enteredForwardedSourcesTimestamp = this.track._getEnteredForwardedSourcesTimestamp();\n\n        if (enteredForwardedSourcesTimestamp\n            && (Date.now() - enteredForwardedSourcesTimestamp) >= DEFAULT_RESTORING_TIMEOUT) {\n            return true;\n        }\n\n        // still haven't reached timeout, if there is no timer scheduled, schedule one so we can track the restoring\n        // state and change it after reaching the timeout\n        const rTimer = this.restoringTimer;\n\n        if (!rTimer) {\n            this.restoringTimer = setTimeout(() => this.figureOutStreamingStatus(), DEFAULT_RESTORING_TIMEOUT);\n        }\n\n        return false;\n    }\n\n    /** Checks whether a track is the current track. */\n    _isCurrentTrack(track: JitsiRemoteTrack): boolean {\n        return track.getSourceName() === this.track.getSourceName();\n    }\n\n    /**\n     * Sends a last/final track streaming status event for the track of the user that left the conference.\n     * @param id - The id of the participant that left the conference.\n     */\n    onUserLeft(id: string): void {\n        if (this.track.getParticipantId() === id) {\n            this.maybeSendTrackStreamingStatusEvent(Date.now());\n            this.streamingStatusMap = {};\n        }\n    }\n\n    /**\n     * Handles RTC 'onmute' event for the video track.\n     *\n     * @param track - The video track for which 'onmute' event will be processed.\n     */\n    onTrackRtcMuted(track: JitsiRemoteTrack): void {\n        if (!this._isCurrentTrack(track)) {\n            return;\n        }\n\n        const sourceName = track.getSourceName();\n\n        logger.debug(`Detector track RTC muted: ${sourceName}`, Date.now());\n\n        this.rtcMutedTimestamp = Date.now();\n        if (!track.isMuted()) {\n            // If the user is not muted according to the signalling we'll give it some time, before the streaming\n            // interrupted event is triggered.\n            this.clearTimeout();\n\n            // The timeout is reduced when track is not in the forwarded sources\n            const timeout = this._getVideoFrozenTimeout();\n\n            this.trackTimer = window.setTimeout(() => {\n                logger.debug(`Set track RTC muted for: ${sourceName} after the timeout of ${timeout} ms`);\n                this.clearTimeout();\n                this.figureOutStreamingStatus();\n            }, timeout);\n        }\n    }\n\n    /**\n     * Handles RTC 'onunmute' event for the video track.\n     *\n     * @param track - The video track for which 'onunmute' event will be processed.\n     */\n    onTrackRtcUnmuted(track: JitsiRemoteTrack): void {\n        if (!this._isCurrentTrack(track)) {\n            return;\n        }\n\n        const sourceName = this.track.getSourceName();\n\n        logger.debug(`Detector track RTC unmuted: ${sourceName}`, Date.now());\n\n        this.clearTimeout();\n        this.clearRtcMutedTimestamp();\n\n        this.figureOutStreamingStatus();\n    }\n\n    /**\n     * Here the signalling \"mute\"/\"unmute\" events are processed.\n     *\n     * @param track - The remote video track for which the signalling mute/unmute event will be\n     * processed.\n     */\n    onSignallingMuteChanged(track: JitsiRemoteTrack): void {\n        if (!this._isCurrentTrack(track)) {\n            return;\n        }\n\n        const sourceName = this.track.getSourceName();\n\n        logger.debug(`Detector on track signalling mute changed: ${sourceName}`, track.isMuted());\n\n        this.figureOutStreamingStatus();\n    }\n\n    /**\n     * Sends a track streaming status event as a result of the video type changing.\n     * @deprecated this will go away with full multiple streams support\n     * @param type - The video type.\n     */\n    onTrackVideoTypeChanged(type: VideoType): void {\n        const nowMs = Date.now();\n\n        this.maybeSendTrackStreamingStatusEvent(nowMs);\n\n        this.streamingStatusMap = {\n            ...this.streamingStatusMap || {},\n            videoType: type,\n            startedMs: nowMs\n        };\n    }\n}\n\nexport default TrackStreamingStatusImpl;\n","import * as JitsiTrackEvents from '../../JitsiTrackEvents';\nimport { createTtfmEvent } from '../../service/statistics/AnalyticsEvents';\nimport TrackStreamingStatusImpl, { TrackStreamingStatus } from '../connectivity/TrackStreamingStatus';\nimport Statistics from '../statistics/statistics';\n\nimport JitsiTrack from './JitsiTrack';\n\nconst logger = require('@jitsi/logger').getLogger(__filename);\n\nconst RTCEvents = require('../../service/RTC/RTCEvents');\n\nlet ttfmTrackerAudioAttached = false;\nlet ttfmTrackerVideoAttached = false;\n\n/**\n * List of container events that we are going to process. _onContainerEventHandler will be added as listener to the\n * container for every event in the list.\n */\nconst containerEvents = [ 'abort', 'canplaythrough', 'ended', 'error' ];\n\n/* eslint-disable max-params */\n\n/**\n * Represents a single media track (either audio or video).\n */\nexport default class JitsiRemoteTrack extends JitsiTrack {\n    /**\n     * Creates new JitsiRemoteTrack instance.\n     * @param {RTC} rtc the RTC service instance.\n     * @param {JitsiConference} conference the conference to which this track\n     *        belongs to\n     * @param {string} ownerEndpointId the endpoint ID of the track owner\n     * @param {MediaStream} stream WebRTC MediaStream, parent of the track\n     * @param {MediaStreamTrack} track underlying WebRTC MediaStreamTrack for\n     *        the new JitsiRemoteTrack\n     * @param {MediaType} mediaType the type of the media\n     * @param {VideoType} videoType the type of the video if applicable\n     * @param {number} ssrc the SSRC number of the Media Stream\n     * @param {boolean} muted the initial muted state\n     * @param {boolean} isP2P indicates whether or not this track belongs to a\n     * P2P session\n     * @param {String} sourceName the source name signaled for the track\n     * @throws {TypeError} if <tt>ssrc</tt> is not a number.\n     * @constructor\n     */\n    constructor(\n            rtc,\n            conference,\n            ownerEndpointId,\n            stream,\n            track,\n            mediaType,\n            videoType,\n            ssrc,\n            muted,\n            isP2P,\n            sourceName) {\n        super(\n            conference,\n            stream,\n            track,\n            () => {\n                // Nothing to do if the track is inactive.\n            },\n            mediaType,\n            videoType);\n        this.rtc = rtc;\n\n        // Prevent from mixing up type of SSRC which should be a number\n        if (typeof ssrc !== 'number') {\n            throw new TypeError(`SSRC ${ssrc} is not a number`);\n        }\n        this.ssrc = ssrc;\n        this.ownerEndpointId = ownerEndpointId;\n        this.muted = muted;\n        this.isP2P = isP2P;\n        this._sourceName = sourceName;\n        this._trackStreamingStatus = null;\n        this._trackStreamingStatusImpl = null;\n\n        /**\n         * This holds the timestamp indicating when remote video track entered forwarded sources set. Track entering\n         * forwardedSources will have streaming status restoring and when we start receiving video will become active,\n         * but if video is not received for certain time {@link DEFAULT_RESTORING_TIMEOUT} that track streaming status\n         * will become interrupted.\n         */\n        this._enteredForwardedSourcesTimestamp = null;\n\n        this.addEventListener = this.on = this._addEventListener.bind(this);\n        this.removeEventListener = this.off = this._removeEventListener.bind(this);\n\n        logger.debug(`New remote track created: ${this}`);\n\n        // we want to mark whether the track has been ever muted\n        // to detect ttfm events for startmuted conferences, as it can\n        // significantly increase ttfm values\n        this.hasBeenMuted = muted;\n\n        // Bind 'onmute' and 'onunmute' event handlers\n        if (this.rtc && this.track) {\n            this._bindTrackHandlers();\n        }\n        this._containerHandlers = {};\n        containerEvents.forEach(event => {\n            this._containerHandlers[event] = this._containerEventHandler.bind(this, event);\n        });\n    }\n\n    /* eslint-enable max-params */\n    /**\n     * Attaches the track handlers.\n     *\n     * @returns {void}\n     */\n    _bindTrackHandlers() {\n        this.track.addEventListener('mute', () => this._onTrackMute());\n        this.track.addEventListener('unmute', () => this._onTrackUnmute());\n        this.track.addEventListener('ended', () => {\n            logger.debug(`\"onended\" event(${Date.now()}): ${this}`);\n        });\n    }\n\n    /**\n     * Overrides addEventListener method to init TrackStreamingStatus instance when there are listeners for the\n     * {@link JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED} event.\n     *\n     * @param {string} event - event name\n     * @param {function} handler - event handler\n     */\n    _addEventListener(event, handler) {\n        super.addListener(event, handler);\n\n        if (event === JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED\n            && this.listenerCount(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED)\n            && !this._trackStreamingStatusImpl\n        ) {\n            this._initTrackStreamingStatus();\n            logger.debug(`Initializing track streaming status: ${this._sourceName}`);\n        }\n    }\n\n    /**\n     * Overrides removeEventListener method to dispose TrackStreamingStatus instance.\n     *\n     * @param {string} event - event name\n     * @param {function} handler - event handler\n     */\n    _removeEventListener(event, handler) {\n        super.removeListener(event, handler);\n\n        if (event === JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED\n            && !this.listenerCount(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED)\n        ) {\n            this._disposeTrackStreamingStatus();\n            logger.debug(`Disposing track streaming status: ${this._sourceName}`);\n        }\n    }\n\n    /**\n     * Callback invoked when the track is muted. Emits an event notifying\n     * listeners of the mute event.\n     *\n     * @private\n     * @returns {void}\n     */\n    _onTrackMute() {\n        logger.debug(`\"onmute\" event(${Date.now()}): ${this}`);\n\n        this.rtc.eventEmitter.emit(RTCEvents.REMOTE_TRACK_MUTE, this);\n    }\n\n    /**\n     * Callback invoked when the track is unmuted. Emits an event notifying\n     * listeners of the mute event.\n     *\n     * @private\n     * @returns {void}\n     */\n    _onTrackUnmute() {\n        logger.debug(`\"onunmute\" event(${Date.now()}): ${this}`);\n\n        this.rtc.eventEmitter.emit(RTCEvents.REMOTE_TRACK_UNMUTE, this);\n    }\n\n    /**\n     * Removes attached event listeners and dispose TrackStreamingStatus .\n     *\n     * @returns {Promise}\n     */\n    dispose() {\n        this._disposeTrackStreamingStatus();\n\n        return super.dispose();\n    }\n\n    /**\n     * Sets current muted status and fires an events for the change.\n     * @param value the muted status.\n     */\n    setMute(value) {\n        if (this.muted === value) {\n            return;\n        }\n\n        if (value) {\n            this.hasBeenMuted = true;\n        }\n\n        // we can have a fake video stream\n        if (this.stream) {\n            this.stream.muted = value;\n        }\n\n        this.muted = value;\n        this.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED, this);\n    }\n\n    /**\n     * Returns the current muted status of the track.\n     * @returns {boolean|*|JitsiRemoteTrack.muted} <tt>true</tt> if the track is\n     * muted and <tt>false</tt> otherwise.\n     */\n    isMuted() {\n        return this.muted;\n    }\n\n    /**\n     * Returns the participant id which owns the track.\n     *\n     * @returns {string} the id of the participants. It corresponds to the\n     * Colibri endpoint id/MUC nickname in case of Jitsi-meet.\n     */\n    getParticipantId() {\n        return this.ownerEndpointId;\n    }\n\n    /**\n     * Return false;\n     */\n    isLocal() {\n        return false;\n    }\n\n    /**\n     * Returns the synchronization source identifier (SSRC) of this remote\n     * track.\n     *\n     * @returns {number} the SSRC of this remote track.\n     */\n    getSSRC() {\n        return this.ssrc;\n    }\n\n\n    /**\n     * Returns the tracks source name\n     *\n     * @returns {string} the track's source name\n     */\n    getSourceName() {\n        return this._sourceName;\n    }\n\n    /**\n     * Update the properties when the track is remapped to another source.\n     *\n     * @param {string} owner The endpoint ID of the new owner.\n     */\n    setOwner(owner) {\n        this.ownerEndpointId = owner;\n        this.emit(JitsiTrackEvents.TRACK_OWNER_CHANGED, owner);\n    }\n\n    /**\n     * Sets the name of the source associated with the remtoe track.\n     *\n     * @param {string} name - The source name to be associated with the track.\n     */\n    setSourceName(name) {\n        this._sourceName = name;\n    }\n\n    /**\n     * Changes the video type of the track.\n     *\n     * @param {string} type - The new video type(\"camera\", \"desktop\").\n     */\n    _setVideoType(type) {\n        if (this.videoType === type) {\n            return;\n        }\n        this.videoType = type;\n        this.emit(JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED, type);\n    }\n\n    /**\n     * Handles track play events.\n     */\n    _playCallback() {\n        if (!this.conference.room) {\n            return;\n        }\n\n        const type = this.isVideoTrack() ? 'video' : 'audio';\n\n        const now = window.performance.now();\n\n        console.log(`(TIME) Render ${type}:\\t`, now);\n        this.conference.getConnectionTimes()[`${type}.render`] = now;\n\n        // The conference can be started without calling GUM\n        // FIXME if there would be a module for connection times this kind\n        // of logic (gumDuration or ttfm) should end up there\n        const gumStart = window.connectionTimes['obtainPermissions.start'];\n        const gumEnd = window.connectionTimes['obtainPermissions.end'];\n        const gumDuration\n            = !isNaN(gumEnd) && !isNaN(gumStart) ? gumEnd - gumStart : 0;\n\n        // Subtract the muc.joined-to-session-initiate duration because jicofo\n        // waits until there are 2 participants to start Jingle sessions.\n        const ttfm = now\n            - (this.conference.getConnectionTimes()['session.initiate']\n                - this.conference.getConnectionTimes()['muc.joined'])\n            - gumDuration;\n\n        this.conference.getConnectionTimes()[`${type}.ttfm`] = ttfm;\n        console.log(`(TIME) TTFM ${type}:\\t`, ttfm);\n\n        Statistics.sendAnalytics(createTtfmEvent(\n            {\n                'media_type': type,\n                muted: this.hasBeenMuted,\n                value: ttfm\n            }));\n\n    }\n\n    /**\n     * Attach time to first media tracker only if there is conference and only\n     * for the first element.\n     * @param container the HTML container which can be 'video' or 'audio'\n     * element.\n     * @private\n     */\n    _attachTTFMTracker(container) {\n        if ((ttfmTrackerAudioAttached && this.isAudioTrack())\n            || (ttfmTrackerVideoAttached && this.isVideoTrack())) {\n            return;\n        }\n\n        if (this.isAudioTrack()) {\n            ttfmTrackerAudioAttached = true;\n        }\n        if (this.isVideoTrack()) {\n            ttfmTrackerVideoAttached = true;\n        }\n\n        container.addEventListener('canplay', this._playCallback.bind(this));\n    }\n\n    /**\n     * Called when the track has been attached to a new container.\n     *\n     * @param {HTMLElement} container the HTML container which can be 'video' or 'audio' element.\n     * @private\n     */\n    _onTrackAttach(container) {\n        containerEvents.forEach(event => {\n            container.addEventListener(event, this._containerHandlers[event]);\n        });\n    }\n\n    /**\n     * Called when the track has been detached from a container.\n     *\n     * @param {HTMLElement} container the HTML container which can be 'video' or 'audio' element.\n     * @private\n     */\n    _onTrackDetach(container) {\n        containerEvents.forEach(event => {\n            container.removeEventListener(event, this._containerHandlers[event]);\n        });\n    }\n\n    /**\n     * An event handler for events triggered by the attached container.\n     *\n     * @param {string} type - The type of the event.\n     */\n    _containerEventHandler(type) {\n        logger.debug(`${type} handler was called for a container with attached ${this}`);\n    }\n\n    /**\n     * Returns a string with a description of the current status of the track.\n     *\n     * @returns {string}\n     */\n    _getStatus() {\n        const { enabled, muted, readyState } = this.track;\n\n        return `readyState: ${readyState}, muted: ${muted}, enabled: ${enabled}`;\n    }\n\n    /**\n     * Initializes trackStreamingStatusImpl.\n     */\n    _initTrackStreamingStatus() {\n        const config = this.conference.options.config;\n\n        this._trackStreamingStatus = TrackStreamingStatus.ACTIVE;\n\n        this._trackStreamingStatusImpl = new TrackStreamingStatusImpl(\n            this.rtc,\n            this.conference,\n            this,\n            {\n                // These options are not public API, leaving it here only as an entry point through config for\n                // tuning up purposes. Default values should be adjusted as soon as optimal values are discovered.\n                p2pRtcMuteTimeout: config._p2pConnStatusRtcMuteTimeout,\n                rtcMuteTimeout: config._peerConnStatusRtcMuteTimeout,\n                outOfForwardedSourcesTimeout: config._peerConnStatusOutOfLastNTimeout\n            });\n\n        this._trackStreamingStatusImpl.init();\n\n        // In some edge cases, both browser 'unmute' and bridge's forwarded sources events are received before a\n        // LargeVideoUpdate is scheduled for auto-pinning a new screenshare track. If there are no layout changes and\n        // no further track events are received for the SS track, a black tile will be displayed for screenshare on\n        // stage. Fire a TRACK_STREAMING_STATUS_CHANGED event if the media is already being received for the remote\n        // track to prevent this from happening.\n        !this._trackStreamingStatusImpl.isVideoTrackFrozen()\n            && this.rtc.eventEmitter.emit(\n                JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED,\n                this,\n                this._trackStreamingStatus);\n    }\n\n    /**\n     * Disposes trackStreamingStatusImpl and clears trackStreamingStatus.\n     */\n    _disposeTrackStreamingStatus() {\n        if (this._trackStreamingStatusImpl) {\n            this._trackStreamingStatusImpl.dispose();\n            this._trackStreamingStatusImpl = null;\n            this._trackStreamingStatus = null;\n        }\n    }\n\n    /**\n     * Updates track's streaming status.\n     *\n     * @param {string} state the current track streaming state. {@link TrackStreamingStatus}.\n     */\n    _setTrackStreamingStatus(status) {\n        this._trackStreamingStatus = status;\n    }\n\n    /**\n     * Returns track's streaming status.\n     *\n     * @returns {string} the streaming status <tt>TrackStreamingStatus</tt> of the track. Returns null\n     * if trackStreamingStatusImpl hasn't been initialized.\n     *\n     * {@link TrackStreamingStatus}.\n     */\n    getTrackStreamingStatus() {\n        return this._trackStreamingStatus;\n    }\n\n    /**\n     * Clears the timestamp of when the track entered forwarded sources.\n     */\n    _clearEnteredForwardedSourcesTimestamp() {\n        this._enteredForwardedSourcesTimestamp = null;\n    }\n\n    /**\n     * Updates the timestamp of when the track entered forwarded sources.\n     *\n     * @param {number} timestamp the time in millis\n     */\n    _setEnteredForwardedSourcesTimestamp(timestamp) {\n        this._enteredForwardedSourcesTimestamp = timestamp;\n    }\n\n    /**\n     * Returns the timestamp of when the track entered forwarded sources.\n     *\n     * @returns {number} the time in millis\n     */\n    _getEnteredForwardedSourcesTimestamp() {\n        return this._enteredForwardedSourcesTimestamp;\n    }\n\n    /**\n     * Creates a text representation of this remote track instance.\n     * @return {string}\n     */\n    toString() {\n        return `RemoteTrack[userID: ${this.getParticipantId()}, type: ${this.getType()}, ssrc: ${\n            this.getSSRC()}, p2p: ${this.isP2P}, sourceName: ${this._sourceName}, status: {${this._getStatus()}}]`;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport transform from 'sdp-transform';\n\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { getSourceIndexFromSourceName } from '../../service/RTC/SignalingLayer';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport browser from '../browser';\nimport FeatureFlags from '../flags/FeatureFlags';\n\nconst logger = getLogger(__filename);\nconst DESKTOP_SHARE_RATE = 500000;\nconst LD_BITRATE = 200000;\nconst SD_BITRATE = 700000;\nconst SIM_LAYER_1_RID = '1';\nconst SIM_LAYER_2_RID = '2';\nconst SIM_LAYER_3_RID = '3';\n\nexport const HD_BITRATE = 2500000;\nexport const HD_SCALE_FACTOR = 1;\nexport const LD_SCALE_FACTOR = 4;\nexport const SD_SCALE_FACTOR = 2;\nexport const SIM_LAYER_RIDS = [ SIM_LAYER_1_RID, SIM_LAYER_2_RID, SIM_LAYER_3_RID ];\n\n/**\n * Handles track related operations on TraceablePeerConnection when browser is\n * running in unified plan mode.\n */\nexport class TPCUtils {\n    /**\n     * Creates a new instance for a given TraceablePeerConnection\n     *\n     * @param peerconnection - the tpc instance for which we have utility functions.\n     */\n    constructor(peerconnection) {\n        this.pc = peerconnection;\n        const bitrateSettings = this.pc.options?.videoQuality?.maxBitratesVideo;\n        const standardBitrates = {\n            low: LD_BITRATE,\n            standard: SD_BITRATE,\n            high: HD_BITRATE,\n            ssHigh: HD_BITRATE\n        };\n\n        // Check if the max. bitrates for video are specified through config.js videoQuality settings.\n        // Right now only VP8 bitrates are configured on the simulcast encodings, VP9 bitrates have to be\n        // configured on the SDP using b:AS line.\n        this.videoBitrates = bitrateSettings ?? standardBitrates;\n        this.encodingBitrates = this.videoBitrates.VP8 ?? this.videoBitrates;\n    }\n\n    /**\n     * Obtains stream encodings that need to be configured on the given track based\n     * on the track media type and the simulcast setting.\n     * @param {JitsiLocalTrack} localTrack\n     */\n    _getStreamEncodings(localTrack) {\n        if (this.pc.isSimulcastOn() && localTrack.isVideoTrack()) {\n            return this._getVideoStreamEncodings(localTrack.getVideoType());\n        }\n\n        return localTrack.isVideoTrack()\n            ? [ {\n                active: this.pc.videoTransferActive,\n                maxBitrate: this.videoBitrates.high\n            } ]\n            : [ { active: this.pc.audioTransferActive } ];\n    }\n\n    /**\n     * The startup configuration for the stream encodings that are applicable to\n     * the video stream when a new sender is created on the peerconnection. The initial\n     * config takes into account the differences in browser's simulcast implementation.\n     *\n     * Encoding parameters:\n     * active - determine the on/off state of a particular encoding.\n     * maxBitrate - max. bitrate value to be applied to that particular encoding\n     *  based on the encoding's resolution and config.js videoQuality settings if applicable.\n     * rid - Rtp Stream ID that is configured for a particular simulcast stream.\n     * scaleResolutionDownBy - the factor by which the encoding is scaled down from the\n     *  original resolution of the captured video.\n     *\n     *  @param {VideoType} videoType\n     */\n    _getVideoStreamEncodings(videoType) {\n        const maxVideoBitrate = videoType === VideoType.DESKTOP && this.encodingBitrates.ssHigh\n            ? this.encodingBitrates.ssHigh : this.encodingBitrates.high;\n\n        return [\n            {\n                active: this.pc.videoTransferActive,\n                maxBitrate: browser.isFirefox() ? maxVideoBitrate : this.encodingBitrates.low,\n                rid: SIM_LAYER_1_RID,\n                scaleResolutionDownBy: browser.isFirefox() ? HD_SCALE_FACTOR : LD_SCALE_FACTOR\n            },\n            {\n                active: this.pc.videoTransferActive,\n                maxBitrate: this.encodingBitrates.standard,\n                rid: SIM_LAYER_2_RID,\n                scaleResolutionDownBy: SD_SCALE_FACTOR\n            },\n            {\n                active: this.pc.videoTransferActive,\n                maxBitrate: browser.isFirefox() ? this.encodingBitrates.low : maxVideoBitrate,\n                rid: SIM_LAYER_3_RID,\n                scaleResolutionDownBy: browser.isFirefox() ? LD_SCALE_FACTOR : HD_SCALE_FACTOR\n            }\n        ];\n    }\n\n    /**\n     * Ensures that the ssrcs associated with a FID ssrc-group appear in the correct order, i.e.,\n     * the primary ssrc first and the secondary rtx ssrc later. This is important for unified\n     * plan since we have only one FID group per media description.\n     * @param {Object} description the webRTC session description instance for the remote\n     * description.\n     * @private\n     */\n    ensureCorrectOrderOfSsrcs(description) {\n        const parsedSdp = transform.parse(description.sdp);\n\n        parsedSdp.media.forEach(mLine => {\n            if (mLine.type === MediaType.AUDIO) {\n                return;\n            }\n            if (!mLine.ssrcGroups || !mLine.ssrcGroups.length) {\n                return;\n            }\n            let reorderedSsrcs = [];\n\n            const ssrcs = new Set();\n\n            mLine.ssrcGroups.map(group =>\n                group.ssrcs\n                    .split(' ')\n                    .filter(Boolean)\n                    .forEach(ssrc => ssrcs.add(ssrc))\n            );\n\n            ssrcs.forEach(ssrc => {\n                const sources = mLine.ssrcs.filter(source => source.id.toString() === ssrc);\n\n                reorderedSsrcs = reorderedSsrcs.concat(sources);\n            });\n            mLine.ssrcs = reorderedSsrcs;\n        });\n\n        return new RTCSessionDescription({\n            type: description.type,\n            sdp: transform.write(parsedSdp)\n        });\n    }\n\n    /**\n     * Returns the transceiver associated with a given RTCRtpSender/RTCRtpReceiver.\n     *\n     * @param {string} mediaType - type of track associated with the transceiver 'audio' or 'video'.\n     * @param {JitsiLocalTrack} localTrack - local track to be used for lookup.\n     * @returns {RTCRtpTransceiver}\n     */\n    findTransceiver(mediaType, localTrack = null) {\n        const transceiver = localTrack?.track && localTrack.getOriginalStream()\n            ? this.pc.peerconnection.getTransceivers().find(t => t.sender?.track?.id === localTrack.getTrackId())\n            : this.pc.peerconnection.getTransceivers().find(t => t.receiver?.track?.kind === mediaType);\n\n        return transceiver;\n    }\n\n    /**\n     * Takes in a *unified plan* offer and inserts the appropriate\n     * parameters for adding simulcast receive support.\n     * @param {Object} desc - A session description object\n     * @param {String} desc.type - the type (offer/answer)\n     * @param {String} desc.sdp - the sdp content\n     *\n     * @return {Object} A session description (same format as above) object\n     * with its sdp field modified to advertise simulcast receive support\n     */\n    insertUnifiedPlanSimulcastReceive(desc) {\n        // a=simulcast line is not needed on browsers where we SDP munging is used for enabling on simulcast.\n        // Remove this check when the client switches to RID/MID based simulcast on all browsers.\n        if (browser.usesSdpMungingForSimulcast()) {\n            return desc;\n        }\n        const sdp = transform.parse(desc.sdp);\n        const idx = sdp.media.findIndex(mline => mline.type === MediaType.VIDEO);\n\n        if (sdp.media[idx].rids && (sdp.media[idx].simulcast_03 || sdp.media[idx].simulcast)) {\n            // Make sure we don't have the simulcast recv line on video descriptions other than\n            // the first video description.\n            sdp.media.forEach((mline, i) => {\n                if (mline.type === MediaType.VIDEO && i !== idx) {\n                    sdp.media[i].rids = undefined;\n                    sdp.media[i].simulcast = undefined;\n\n                    // eslint-disable-next-line camelcase\n                    sdp.media[i].simulcast_03 = undefined;\n                }\n            });\n\n            return new RTCSessionDescription({\n                type: desc.type,\n                sdp: transform.write(sdp)\n            });\n        }\n\n        // In order of highest to lowest spatial quality\n        sdp.media[idx].rids = [\n            {\n                id: SIM_LAYER_1_RID,\n                direction: 'recv'\n            },\n            {\n                id: SIM_LAYER_2_RID,\n                direction: 'recv'\n            },\n            {\n                id: SIM_LAYER_3_RID,\n                direction: 'recv'\n            }\n        ];\n\n        // Firefox 72 has stopped parsing the legacy rid= parameters in simulcast attributes.\n        // eslint-disable-next-line max-len\n        // https://www.fxsitecompat.dev/en-CA/docs/2019/pt-and-rid-in-webrtc-simulcast-attributes-are-no-longer-supported/\n        const simulcastLine = browser.isFirefox() && browser.isVersionGreaterThan(71)\n            ? `recv ${SIM_LAYER_RIDS.join(';')}`\n            : `recv rid=${SIM_LAYER_RIDS.join(';')}`;\n\n        // eslint-disable-next-line camelcase\n        sdp.media[idx].simulcast_03 = {\n            value: simulcastLine\n        };\n\n        return new RTCSessionDescription({\n            type: desc.type,\n            sdp: transform.write(sdp)\n        });\n    }\n\n    /**\n    * Adds {@link JitsiLocalTrack} to the WebRTC peerconnection for the first time.\n    * @param {JitsiLocalTrack} track - track to be added to the peerconnection.\n    * @param {boolean} isInitiator - boolean that indicates if the endpoint is offerer in a p2p connection.\n    * @returns {void}\n    */\n    addTrack(localTrack, isInitiator) {\n        const track = localTrack.getTrack();\n\n        if (isInitiator) {\n            const streams = [];\n\n            if (localTrack.getOriginalStream()) {\n                streams.push(localTrack.getOriginalStream());\n            }\n\n            // Use pc.addTransceiver() for the initiator case when local tracks are getting added\n            // to the peerconnection before a session-initiate is sent over to the peer.\n            const transceiverInit = {\n                direction: MediaDirection.SENDRECV,\n                streams,\n                sendEncodings: []\n            };\n\n            if (!browser.isFirefox()) {\n                transceiverInit.sendEncodings = this._getStreamEncodings(localTrack);\n            }\n            this.pc.peerconnection.addTransceiver(track, transceiverInit);\n        } else {\n            // Use pc.addTrack() for responder case so that we can re-use the m-lines that were created\n            // when setRemoteDescription was called. pc.addTrack() automatically  attaches to any existing\n            // unused \"recv-only\" transceiver.\n            this.pc.peerconnection.addTrack(track);\n        }\n    }\n\n    /**\n     * Returns the calculated active state of the simulcast encodings based on the frame height requested for the send\n     * stream. All the encodings that have a resolution lower than the frame height requested will be enabled.\n     *\n     * @param {JitsiLocalTrack} localVideoTrack The local video track.\n     * @param {number} newHeight The resolution requested for the video track.\n     * @returns {Array<boolean>}\n     */\n    calculateEncodingsActiveState(localVideoTrack, newHeight) {\n        const localTrack = localVideoTrack.getTrack();\n        const { height } = localTrack.getSettings();\n        const videoStreamEncodings = this._getVideoStreamEncodings(localVideoTrack.getVideoType());\n        const encodingsState = videoStreamEncodings\n        .map(encoding => height / encoding.scaleResolutionDownBy)\n        .map((frameHeight, idx) => {\n            let active = localVideoTrack.getVideoType() === VideoType.CAMERA\n\n                // Keep the LD stream enabled even when the LD stream's resolution is higher than of the requested\n                // resolution. This can happen when camera is captured at resolutions higher than 720p but the\n                // requested resolution is 180. Since getParameters doesn't give us information about the resolutions\n                // of the simulcast encodings, we have to rely on our initial config for the simulcast streams.\n                ? newHeight > 0 && videoStreamEncodings[idx]?.scaleResolutionDownBy === LD_SCALE_FACTOR\n                    ? true\n                    : frameHeight <= newHeight\n\n                // Keep all the encodings for desktop track active.\n                : true;\n\n            // Disable the lower spatial layers for screensharing in Unified plan when low fps screensharing is in\n            // progress. Sending all three streams often results in the browser suspending the high resolution in low\n            // b/w and cpu cases, especially on the low end machines. Suspending the low resolution streams ensures\n            // that the highest resolution stream is available always. Safari is an exception here since it does not\n            // send the desktop stream at all if only the high resolution stream is enabled.\n            if (localVideoTrack.getVideoType() === VideoType.DESKTOP\n                && this.pc._capScreenshareBitrate\n                && this.pc.usesUnifiedPlan()\n                && !browser.isWebKitBased()\n                && videoStreamEncodings[idx].scaleResolutionDownBy !== HD_SCALE_FACTOR) {\n                active = false;\n            }\n\n            return active;\n        });\n\n        return encodingsState;\n    }\n\n    /**\n     * Returns the calculates max bitrates that need to be configured on the simulcast encodings based on the video\n     * type and other considerations associated with screenshare.\n     *\n     * @param {JitsiLocalTrack} localVideoTrack The local video track.\n     * @returns {Array<number>}\n     */\n    calculateEncodingsBitrates(localVideoTrack) {\n        const videoType = localVideoTrack.getVideoType();\n        const desktopShareBitrate = this.pc.options?.videoQuality?.desktopBitrate || DESKTOP_SHARE_RATE;\n        const lowFpsScreenshare = localVideoTrack.getVideoType() === VideoType.DESKTOP\n            && this.pc._capScreenshareBitrate\n            && !browser.isWebKitBased();\n        const encodingsBitrates = this._getVideoStreamEncodings(localVideoTrack.getVideoType())\n        .map(encoding => {\n            const bitrate = lowFpsScreenshare\n                ? desktopShareBitrate\n\n                // For high fps screenshare, 'maxBitrate' setting must be cleared on Chrome in plan-b, because\n                // if simulcast is enabled for screen and maxBitrates are set then Chrome will not send the\n                // desktop stream.\n                : videoType === VideoType.DESKTOP && browser.isChromiumBased() && !this.pc.usesUnifiedPlan()\n                    ? undefined\n                    : encoding.maxBitrate;\n\n            return bitrate;\n        });\n\n        return encodingsBitrates;\n    }\n\n    /**\n     * Returns the max resolution that the client is configured to encode for a given local video track. The actual\n     * send resolution might be downscaled based on cpu and bandwidth constraints.\n     *\n     * @param {JitsiLocalTrack} localVideoTrack - The local video track.\n     * @returns {number} The max encoded resolution for the given video track.\n     */\n    getConfiguredEncodeResolution(localVideoTrack) {\n        const localTrack = localVideoTrack.getTrack();\n        const { height } = localTrack.getSettings();\n        const videoSender = this.pc.findSenderForTrack(localVideoTrack.getTrack());\n        let maxHeight = 0;\n\n        if (!videoSender) {\n            return maxHeight;\n        }\n        const parameters = videoSender.getParameters();\n\n        if (!parameters?.encodings?.length) {\n            return maxHeight;\n        }\n        for (const encoding in parameters.encodings) {\n            if (parameters.encodings[encoding].active) {\n                const scaleResolutionDownBy\n                    = this.pc.isSimulcastOn()\n                        ? this._getVideoStreamEncodings(localVideoTrack.getVideoType())[encoding].scaleResolutionDownBy\n                        : parameters.encodings[encoding].scaleResolutionDownBy;\n\n                maxHeight = Math.max(maxHeight, height / scaleResolutionDownBy);\n            }\n        }\n\n        return maxHeight;\n    }\n\n    /**\n     * Replaces the existing track on a RTCRtpSender with the given track.\n     *\n     * @param {JitsiLocalTrack} oldTrack - existing track on the sender that needs to be removed.\n     * @param {JitsiLocalTrack} newTrack - new track that needs to be added to the sender.\n     * @returns {Promise<RTCRtpTransceiver>} - resolved with the associated transceiver when done, rejected otherwise.\n     */\n    replaceTrack(oldTrack, newTrack) {\n        const mediaType = newTrack?.getType() ?? oldTrack?.getType();\n        const localTracks = this.pc.getLocalTracks(mediaType);\n        const track = newTrack?.getTrack() ?? null;\n        const isNewLocalSource = FeatureFlags.isMultiStreamSendSupportEnabled()\n            && localTracks?.length\n            && !oldTrack\n            && newTrack\n            && !localTracks.find(t => t === newTrack);\n        let transceiver;\n\n        // If old track exists, replace the track on the corresponding sender.\n        if (oldTrack && !oldTrack.isMuted()) {\n            transceiver = this.pc.peerconnection.getTransceivers().find(t => t.sender.track === oldTrack.getTrack());\n\n        // Find the first recvonly transceiver when more than one track of the same media type is being added to the pc.\n        // As part of the track addition, a new m-line was added to the remote description with direction set to\n        // recvonly.\n        } else if (isNewLocalSource) {\n            transceiver = this.pc.peerconnection.getTransceivers().find(\n                t => t.receiver.track.kind === mediaType\n                && t.direction === MediaDirection.RECVONLY\n\n                // Re-use any existing recvonly transceiver (if available) for p2p case.\n                && ((this.pc.isP2P && t.currentDirection === MediaDirection.RECVONLY)\n                    || (t.currentDirection === MediaDirection.INACTIVE && !t.stopped)));\n\n        // For mute/unmute operations, find the transceiver based on the track index in the source name if present,\n        // otherwise it is assumed to be the first local track that was added to the peerconnection.\n        } else {\n            transceiver = this.pc.peerconnection.getTransceivers().find(t => t.receiver.track.kind === mediaType);\n            const sourceName = newTrack?.getSourceName() ?? oldTrack?.getSourceName();\n\n            if (sourceName) {\n                const trackIndex = getSourceIndexFromSourceName(sourceName);\n\n                if (this.pc.isP2P) {\n                    transceiver = this.pc.peerconnection.getTransceivers()\n                        .filter(t => t.receiver.track.kind === mediaType)[trackIndex];\n                } else if (oldTrack) {\n                    const transceiverMid = this.pc._localTrackTransceiverMids.get(oldTrack.rtcId);\n\n                    transceiver = this.pc.peerconnection.getTransceivers().find(t => t.mid === transceiverMid);\n                } else if (trackIndex) {\n                    transceiver = this.pc.peerconnection.getTransceivers()\n                            .filter(t => t.receiver.track.kind === mediaType\n                                && t.direction !== MediaDirection.RECVONLY)[trackIndex];\n                }\n            }\n        }\n        if (!transceiver) {\n            return Promise.reject(\n                new Error(`Replace track failed - no transceiver for old: ${oldTrack}, new: ${newTrack}`));\n        }\n        logger.debug(`${this.pc} Replacing ${oldTrack} with ${newTrack}`);\n\n        return transceiver.sender.replaceTrack(track)\n            .then(() => Promise.resolve(transceiver));\n    }\n\n    /**\n     * Set the simulcast stream encoding properties on the RTCRtpSender.\n     * @param {JitsiLocalTrack} track - the current track in use for which\n     * the encodings are to be set.\n     * @returns {Promise<void>} - resolved when done.\n     */\n    setEncodings(track) {\n        const mediaType = track.getType();\n        const transceiver = this.findTransceiver(mediaType, track);\n        const parameters = transceiver?.sender?.getParameters();\n\n        // Resolve if the encodings are not available yet. This happens immediately after the track is added to the\n        // peerconnection on chrome in unified-plan. It is ok to ignore and not report the error here since the\n        // action that triggers 'addTrack' (like unmute) will also configure the encodings and set bitrates after that.\n        if (!parameters?.encodings?.length) {\n            return Promise.resolve();\n        }\n        parameters.encodings = this._getStreamEncodings(track);\n        const promise = transceiver.sender.setParameters(parameters);\n\n        if (mediaType === MediaType.VIDEO) {\n            return this.pc._updateVideoSenderParameters(promise);\n        }\n\n        return promise;\n    }\n\n    /**\n     * Resumes or suspends media on the peerconnection by setting the active state on RTCRtpEncodingParameters\n     * associated with all the senders that have a track attached to it.\n     *\n     * @param {boolean} enable - whether media needs to be enabled or suspended.\n     * @returns {Promise} - A promise that is resolved when the change is succesful on all the senders, rejected\n     * otherwise.\n     */\n    setMediaTransferActive(enable) {\n        logger.info(`${this.pc} ${enable ? 'Resuming' : 'Suspending'} media transfer.`);\n\n        const senders = this.pc.peerconnection.getSenders().filter(s => Boolean(s.track));\n        const promises = [];\n\n        for (const sender of senders) {\n            const parameters = sender.getParameters();\n\n            if (parameters?.encodings?.length) {\n                for (const encoding of parameters.encodings) {\n                    encoding.active = enable;\n                }\n            }\n            const setActivePromise = sender.setParameters(parameters);\n\n            if (sender.track.kind === MediaType.VIDEO) {\n                promises.push(this.pc._updateVideoSenderParameters(setActivePromise));\n            } else {\n                promises.push(setActivePromise);\n            }\n        }\n\n        return Promise.allSettled(promises)\n            .then(settledResult => {\n                const errors = settledResult\n                    .filter(result => result.status === 'rejected')\n                    .map(result => result.reason);\n\n                if (errors.length) {\n                    return Promise.reject(new Error('Failed to change encodings on the RTCRtpSenders'\n                        + `${errors.join(' ')}`));\n                }\n\n                return Promise.resolve();\n            });\n    }\n\n    /**\n     * Enables/disables video media transmission on the peer connection. When disabled the SDP video media direction in\n     * the local SDP will be adjusted to 'inactive' which means that no data will be sent nor accepted, but the\n     * connection should be kept alive. This is used for setting lastn=0 on p2p connection.\n     *\n     * @param {boolean} active - true to enable media transmission or false to disable.\n     * @returns {void}\n     */\n    setVideoTransferActive(active) {\n        const transceivers = this.pc.peerconnection.getTransceivers()\n            .filter(t => t.receiver && t.receiver.track && t.receiver.track.kind === MediaType.VIDEO);\n\n        logger.info(`${this.pc} ${active ? 'Enabling' : 'Suspending'} video media transfer.`);\n        transceivers.forEach(transceiver => {\n            const localTrackMids = Array.from(this.pc._localTrackTransceiverMids);\n            const direction = active\n                ? localTrackMids.find(mids => mids[1] === transceiver.mid)\n                    ? MediaDirection.SENDRECV : MediaDirection.RECVONLY\n                : MediaDirection.INACTIVE;\n\n            logger.debug(`Setting direction to ${direction} on mid=${transceiver.mid}`);\n            transceiver.direction = direction;\n        });\n    }\n\n    /**\n     * Ensures that the resolution of the stream encodings are consistent with the values\n     * that were configured on the RTCRtpSender when the source was added to the peerconnection.\n     * This should prevent us from overriding the default values if the browser returns\n     * erroneous values when RTCRtpSender.getParameters is used for getting the encodings info.\n     * @param {JitsiLocalTrack} localVideoTrack The local video track.\n     * @param {Object} parameters - the RTCRtpEncodingParameters obtained from the browser.\n     * @returns {void}\n     */\n    updateEncodingsResolution(localVideoTrack, parameters) {\n        if (!(browser.isWebKitBased() && parameters.encodings && Array.isArray(parameters.encodings))) {\n            return;\n        }\n        const allEqualEncodings\n            = encodings => encodings.every(encoding => typeof encoding.scaleResolutionDownBy !== 'undefined'\n                && encoding.scaleResolutionDownBy === encodings[0].scaleResolutionDownBy);\n\n        // Implement the workaround only when all the encodings report the same resolution.\n        if (allEqualEncodings(parameters.encodings)) {\n            const videoStreamEncodings = this._getVideoStreamEncodings(localVideoTrack.getVideoType());\n\n            parameters.encodings.forEach((encoding, idx) => {\n                encoding.scaleResolutionDownBy = videoStreamEncodings[idx].scaleResolutionDownBy;\n            });\n        }\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { Interop } from '@jitsi/sdp-interop';\nimport transform from 'sdp-transform';\n\nimport * as CodecMimeType from '../../service/RTC/CodecMimeType';\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport * as SignalingEvents from '../../service/RTC/SignalingEvents';\nimport { getSourceIndexFromSourceName } from '../../service/RTC/SignalingLayer';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport { SS_DEFAULT_FRAME_RATE } from '../RTC/ScreenObtainer';\nimport browser from '../browser';\nimport FeatureFlags from '../flags/FeatureFlags';\nimport LocalSdpMunger from '../sdp/LocalSdpMunger';\nimport RtxModifier from '../sdp/RtxModifier';\nimport SDP from '../sdp/SDP';\nimport SDPUtil from '../sdp/SDPUtil';\nimport SdpConsistency from '../sdp/SdpConsistency';\nimport SdpSimulcast from '../sdp/SdpSimulcast';\nimport { SdpTransformWrap } from '../sdp/SdpTransformUtil';\nimport * as GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\n\nimport JitsiRemoteTrack from './JitsiRemoteTrack';\nimport RTC from './RTC';\nimport {\n    HD_BITRATE,\n    HD_SCALE_FACTOR,\n    SIM_LAYER_RIDS,\n    TPCUtils\n} from './TPCUtils';\n\n// FIXME SDP tools should end up in some kind of util module\n\nconst logger = getLogger(__filename);\nconst DEGRADATION_PREFERENCE_CAMERA = 'maintain-framerate';\nconst DEGRADATION_PREFERENCE_DESKTOP = 'maintain-resolution';\n\n/* eslint-disable max-params */\n\n/**\n * Creates new instance of 'TraceablePeerConnection'.\n *\n * @param {RTC} rtc the instance of <tt>RTC</tt> service\n * @param {number} id the peer connection id assigned by the parent RTC module.\n * @param {SignalingLayer} signalingLayer the signaling layer instance\n * @param {object} pcConfig The {@code RTCConfiguration} to use for the WebRTC peer connection.\n * @param {object} constraints WebRTC 'PeerConnection' constraints\n * @param {boolean} isP2P indicates whether or not the new instance will be used in a peer to peer connection.\n * @param {object} options <tt>TracablePeerConnection</tt> config options.\n * @param {boolean} options.disableSimulcast if set to 'true' will disable the simulcast.\n * @param {boolean} options.disableRtx if set to 'true' will disable the RTX.\n * @param {string} options.disabledCodec the mime type of the code that should not be negotiated on the peerconnection.\n * @param {string} options.preferredCodec the mime type of the codec that needs to be made the preferred codec for the\n * peerconnection.\n * @param {boolean} options.startSilent If set to 'true' no audio will be sent or received.\n * @param {boolean} options.usesUnifiedPlan Indicates if the  browser is running in unified plan mode.\n *\n * FIXME: initially the purpose of TraceablePeerConnection was to be able to\n * debug the peer connection. Since many other responsibilities have been added\n * it would make sense to extract a separate class from it and come up with\n * a more suitable name.\n *\n * @constructor\n */\nexport default function TraceablePeerConnection(\n        rtc,\n        id,\n        signalingLayer,\n        pcConfig,\n        constraints,\n        isP2P,\n        options) {\n\n    /**\n     * Indicates whether or not this peer connection instance is actively\n     * sending/receiving audio media. When set to <tt>false</tt> the SDP audio\n     * media direction will be adjusted to 'inactive' in order to suspend\n     * the transmission.\n     * @type {boolean}\n     * @private\n     */\n    this.audioTransferActive = !(options.startSilent === true);\n\n    /**\n     * The DTMF sender instance used to send DTMF tones.\n     *\n     * @type {RTCDTMFSender|undefined}\n     * @private\n     */\n    this._dtmfSender = undefined;\n\n    /**\n     * @typedef {Object} TouchToneRequest\n     * @property {string} tones - The DTMF tones string as defined by\n     * {@code RTCDTMFSender.insertDTMF}, 'tones' argument.\n     * @property {number} duration - The amount of time in milliseconds that\n     * each DTMF should last.\n     * @property {string} interToneGap - The length of time in miliseconds to\n     * wait between tones.\n     */\n    /**\n     * TouchToneRequests which are waiting to be played. This queue is filled\n     * if there are touch tones currently being played.\n     *\n     * @type {Array<TouchToneRequest>}\n     * @private\n     */\n    this._dtmfTonesQueue = [];\n\n    /**\n     * Indicates whether or not this peer connection instance is actively\n     * sending/receiving video media. When set to <tt>false</tt> the SDP video\n     * media direction will be adjusted to 'inactive' in order to suspend\n     * the transmission.\n     * @type {boolean}\n     * @private\n     */\n    this.videoTransferActive = true;\n\n    /**\n     * The parent instance of RTC service which created this\n     * <tt>TracablePeerConnection</tt>.\n     * @type {RTC}\n     */\n    this.rtc = rtc;\n\n    /**\n     * The peer connection identifier assigned by the RTC module.\n     * @type {number}\n     */\n    this.id = id;\n\n    /**\n     * Indicates whether or not this instance is used in a peer to peer\n     * connection.\n     * @type {boolean}\n     */\n    this.isP2P = isP2P;\n\n    /**\n     * The map holds remote tracks associated with this peer connection. It maps user's JID to media type and a set of\n     * remote tracks.\n     * @type {Map<string, Map<MediaType, Set<JitsiRemoteTrack>>>}\n     */\n    this.remoteTracks = new Map();\n\n    /**\n     * A map which stores local tracks mapped by {@link JitsiLocalTrack.rtcId}\n     * @type {Map<number, JitsiLocalTrack>}\n     */\n    this.localTracks = new Map();\n\n    /**\n     * Keeps tracks of the WebRTC <tt>MediaStream</tt>s that have been added to\n     * the underlying WebRTC PeerConnection.\n     * @type {Array}\n     * @private\n     */\n    this._addedStreams = [];\n\n    /**\n     * @typedef {Object} TPCGroupInfo\n     * @property {string} semantics the SSRC groups semantics\n     * @property {Array<number>} ssrcs group's SSRCs in order where the first\n     * one is group's primary SSRC, the second one is secondary (RTX) and so\n     * on...\n     */\n    /**\n     * @typedef {Object} TPCSSRCInfo\n     * @property {Array<number>} ssrcs an array which holds all track's SSRCs\n     * @property {Array<TPCGroupInfo>} groups an array stores all track's SSRC\n     * groups\n     */\n    /**\n     * Holds the info about local track's SSRCs mapped per their\n     * {@link JitsiLocalTrack.rtcId}\n     * @type {Map<number, TPCSSRCInfo>}\n     */\n    this.localSSRCs = new Map();\n\n    /**\n     * The set of remote SSRCs seen so far.\n     * Distinguishes new SSRCs from those that have been remapped.\n     */\n    this.remoteSSRCs = new Set();\n\n    /**\n     * The local ICE username fragment for this session.\n     */\n    this.localUfrag = null;\n\n    /**\n     * The remote ICE username fragment for this session.\n     */\n    this.remoteUfrag = null;\n\n    /**\n     * The DTLS transport object for the PeerConnection.\n     * Note: this assume only one shared transport exists because we bundled\n     *       all streams on the same underlying transport.\n     */\n    this._dtlsTransport = null;\n\n    /**\n     * The signaling layer which operates this peer connection.\n     * @type {SignalingLayer}\n     */\n    this.signalingLayer = signalingLayer;\n\n    // SignalingLayer listeners\n    this._peerVideoTypeChanged = this._peerVideoTypeChanged.bind(this);\n    this.signalingLayer.on(SignalingEvents.PEER_VIDEO_TYPE_CHANGED, this._peerVideoTypeChanged);\n\n    this._peerMutedChanged = this._peerMutedChanged.bind(this);\n    this.signalingLayer.on(SignalingEvents.PEER_MUTED_CHANGED, this._peerMutedChanged);\n    this.options = options;\n\n    // Setup SignalingLayer listeners for source-name based events.\n    this.signalingLayer.on(SignalingEvents.SOURCE_MUTED_CHANGED,\n        (sourceName, isMuted) => this._sourceMutedChanged(sourceName, isMuted));\n    this.signalingLayer.on(SignalingEvents.SOURCE_VIDEO_TYPE_CHANGED,\n        (sourceName, videoType) => this._sourceVideoTypeChanged(sourceName, videoType));\n\n    // Make sure constraints is properly formatted in order to provide information about whether or not this\n    // connection is P2P to rtcstats.\n    const safeConstraints = constraints || {};\n\n    safeConstraints.optional = safeConstraints.optional || [];\n\n    // The `optional` parameter needs to be of type array, otherwise chrome will throw an error.\n    // Firefox and Safari just ignore it.\n    if (Array.isArray(safeConstraints.optional)) {\n        safeConstraints.optional.push({ rtcStatsSFUP2P: this.isP2P });\n    } else {\n        logger.warn('Optional param is not an array, rtcstats p2p data is omitted.');\n    }\n\n    this.peerconnection = new RTCPeerConnection(pcConfig, safeConstraints);\n\n    this.tpcUtils = new TPCUtils(this);\n    this.updateLog = [];\n    this.stats = {};\n    this.statsinterval = null;\n\n    /**\n     * Flag used to indicate if low fps screenshare is desired.\n     */\n    this._capScreenshareBitrate = this.options.capScreenshareBitrate;\n\n    /**\n    * Flag used to indicate if the browser is running in unified  plan mode.\n    */\n    this._usesUnifiedPlan = options.usesUnifiedPlan;\n\n    /**\n     * Codec preferences set for the peerconnection through config.js.\n     */\n    this.codecSettings = this.options.codecSettings;\n\n    /**\n     * Flag used to indicate if RTCRtpTransceiver#setCodecPreferences is to be used instead of SDP\n     * munging for codec selection.\n     */\n    this._usesTransceiverCodecPreferences = browser.supportsCodecPreferences() && this._usesUnifiedPlan;\n    this._usesTransceiverCodecPreferences\n        && logger.info('Using RTCRtpTransceiver#setCodecPreferences for codec selection');\n\n    // We currently need these flags only for FF and that's why we are updating them only for unified plan.\n    if (this._usesUnifiedPlan) {\n        /**\n         * Indicates whether an audio track has ever been added to the peer connection.\n         */\n        this._hasHadAudioTrack = false;\n\n        /**\n         * Indicates whether a video track has ever been added to the peer connection.\n         */\n        this._hasHadVideoTrack = false;\n    }\n\n    /**\n     * @type {number} The max number of stats to keep in this.stats. Limit to\n     * 300 values, i.e. 5 minutes; set to 0 to disable\n     */\n    this.maxstats = options.maxstats;\n\n    this.interop = new Interop();\n\n    if (this._usesUnifiedPlan) {\n        this.simulcast = new SdpSimulcast({ numOfLayers: SIM_LAYER_RIDS.length });\n    } else {\n        const Simulcast = require('@jitsi/sdp-simulcast');\n\n        this.simulcast = new Simulcast(\n            {\n                numOfLayers: SIM_LAYER_RIDS.length,\n                explodeRemoteSimulcast: false,\n                usesUnifiedPlan: false\n            });\n    }\n\n    this.sdpConsistency = new SdpConsistency(this.toString());\n\n    /**\n     * Munges local SDP provided to the Jingle Session in order to prevent from\n     * sending SSRC updates on attach/detach and mute/unmute (for video).\n     * @type {LocalSdpMunger}\n     */\n    this.localSdpMunger = new LocalSdpMunger(this, this.rtc.getLocalEndpointId());\n\n    /**\n     * TracablePeerConnection uses RTC's eventEmitter\n     * @type {EventEmitter}\n     */\n    this.eventEmitter = rtc.eventEmitter;\n    this.rtxModifier = new RtxModifier();\n\n    /**\n     * The height constraint applied on the video sender. The default value is 2160 (4K) when layer suspension is\n     * explicitly disabled.\n     */\n    this._senderVideoMaxHeight = 2160;\n\n    /**\n     * The height constraints to be applied on the sender per local video source (source name as the key).\n     * @type {Map<string, number>}\n     */\n    this._senderMaxHeights = new Map();\n\n    /**\n     * Holds the RTCRtpTransceiver mids that the local tracks are attached to, mapped per their\n     * {@link JitsiLocalTrack.rtcId}.\n     * @type {Map<string, string>}\n     */\n    this._localTrackTransceiverMids = new Map();\n\n    // override as desired\n    this.trace = (what, info) => {\n        logger.debug(what, info);\n\n        this.updateLog.push({\n            time: new Date(),\n            type: what,\n            value: info || ''\n        });\n    };\n    this.onicecandidate = null;\n    this.peerconnection.onicecandidate = event => {\n        this.trace(\n            'onicecandidate',\n            JSON.stringify(event.candidate, null, ' '));\n\n        if (this.onicecandidate !== null) {\n            this.onicecandidate(event);\n        }\n    };\n\n    // Use track events when browser is running in unified plan mode and stream events in plan-b mode.\n    if (this._usesUnifiedPlan) {\n        this.onTrack = evt => {\n            const stream = evt.streams[0];\n\n            this._remoteTrackAdded(stream, evt.track, evt.transceiver);\n            stream.addEventListener('removetrack', e => {\n                this._remoteTrackRemoved(stream, e.track);\n            });\n        };\n        this.peerconnection.addEventListener('track', this.onTrack);\n    } else {\n        this.peerconnection.onaddstream = event => this._remoteStreamAdded(event.stream);\n        this.peerconnection.onremovestream = event => this._remoteStreamRemoved(event.stream);\n    }\n    this.onsignalingstatechange = null;\n    this.peerconnection.onsignalingstatechange = event => {\n        this.trace('onsignalingstatechange', this.signalingState);\n        if (this.onsignalingstatechange !== null) {\n            this.onsignalingstatechange(event);\n        }\n    };\n    this.oniceconnectionstatechange = null;\n    this.peerconnection.oniceconnectionstatechange = event => {\n        this.trace('oniceconnectionstatechange', this.iceConnectionState);\n        if (this.oniceconnectionstatechange !== null) {\n            this.oniceconnectionstatechange(event);\n        }\n    };\n    this.onnegotiationneeded = null;\n    this.peerconnection.onnegotiationneeded = event => {\n        this.trace('onnegotiationneeded');\n        if (this.onnegotiationneeded !== null) {\n            this.onnegotiationneeded(event);\n        }\n    };\n    this.onconnectionstatechange = null;\n    this.peerconnection.onconnectionstatechange = event => {\n        this.trace('onconnectionstatechange', this.connectionState);\n        if (this.onconnectionstatechange !== null) {\n            this.onconnectionstatechange(event);\n        }\n    };\n    this.ondatachannel = null;\n    this.peerconnection.ondatachannel = event => {\n        this.trace('ondatachannel');\n        if (this.ondatachannel !== null) {\n            this.ondatachannel(event);\n        }\n    };\n\n    if (this.maxstats) {\n        this.statsinterval = window.setInterval(() => {\n            this.getStats().then(stats => {\n                if (typeof stats?.result === 'function') {\n                    const results = stats.result();\n\n                    for (let i = 0; i < results.length; ++i) {\n                        const res = results[i];\n\n                        res.names().forEach(name => {\n                            this._processStat(res, name, res.stat(name));\n                        });\n                    }\n                } else {\n                    stats.forEach(r => this._processStat(r, '', r));\n                }\n            });\n        }, 1000);\n    }\n\n    this._lastVideoSenderUpdatePromise = Promise.resolve();\n\n    logger.info(`Create new ${this}`);\n}\n\n/* eslint-enable max-params */\n\n/**\n * Process stat and adds it to the array of stats we store.\n * @param report the current stats report.\n * @param name the name of the report, if available\n * @param statValue the value to add.\n * @private\n */\nTraceablePeerConnection.prototype._processStat\n    = function(report, name, statValue) {\n        const id = `${report.id}-${name}`;\n        let s = this.stats[id];\n        const now = new Date();\n\n        if (!s) {\n            this.stats[id] = s = {\n                startTime: now,\n                endTime: now,\n                values: [],\n                times: []\n            };\n        }\n        s.values.push(statValue);\n        s.times.push(now.getTime());\n        if (s.values.length > this.maxstats) {\n            s.values.shift();\n            s.times.shift();\n        }\n        s.endTime = now;\n    };\n\n/**\n * Returns a string representation of a SessionDescription object.\n */\nconst dumpSDP = function(description) {\n    if (typeof description === 'undefined' || description === null) {\n        return '';\n    }\n\n    return `type: ${description.type}\\r\\n${description.sdp}`;\n};\n\n\n/**\n * Forwards the {@link peerconnection.iceConnectionState} state except that it\n * will convert \"completed\" into \"connected\" where both mean that the ICE has\n * succeeded and is up and running. We never see \"completed\" state for\n * the JVB connection, but it started appearing for the P2P one. This method\n * allows to adapt old logic to this new situation.\n * @return {string}\n */\nTraceablePeerConnection.prototype.getConnectionState = function() {\n    const state = this.peerconnection.iceConnectionState;\n\n    if (state === 'completed') {\n        return 'connected';\n    }\n\n    return state;\n};\n\n/**\n * Obtains the media direction for given {@link MediaType}. The method takes\n * into account whether or not there are any local tracks for media and\n * the {@link audioTransferActive} and {@link videoTransferActive} flags.\n * @param {MediaType} mediaType\n * @param {boolean} isAddOperation whether the direction is to be calculated after a source-add action.\n * @return {string} one of the SDP direction constants ('sendrecv, 'recvonly'\n * etc.) which should be used when setting local description on the peer\n * connection.\n * @private\n */\nTraceablePeerConnection.prototype.getDesiredMediaDirection = function(mediaType, isAddOperation = false) {\n    const hasLocalSource = this.hasAnyTracksOfType(mediaType);\n\n    if (this._usesUnifiedPlan) {\n        return isAddOperation\n            ? hasLocalSource ? MediaDirection.SENDRECV : MediaDirection.SENDONLY\n            : hasLocalSource ? MediaDirection.RECVONLY : MediaDirection.INACTIVE;\n    }\n\n    const mediaTransferActive = mediaType === MediaType.AUDIO ? this.audioTransferActive : this.videoTransferActive;\n\n    if (mediaTransferActive) {\n        return hasLocalSource ? MediaDirection.SENDRECV : MediaDirection.RECVONLY;\n    }\n\n    return MediaDirection.INACTIVE;\n};\n\n/**\n * Returns the MID of the m-line associated with the local desktop track (if it exists).\n *\n * @returns {Number|null}\n */\nTraceablePeerConnection.prototype._getDesktopTrackMid = function() {\n    const desktopTrack = this.getLocalVideoTracks().find(track => track.getVideoType() === VideoType.DESKTOP);\n\n    if (desktopTrack) {\n        return Number(this._localTrackTransceiverMids.get(desktopTrack.rtcId));\n    }\n\n    return null;\n};\n\n/**\n * Returns the list of RTCRtpReceivers created for the source of the given media type associated with\n * the set of remote endpoints specified.\n * @param {Array<string>} endpoints list of the endpoints\n * @param {string} mediaType 'audio' or 'video'\n * @returns {Array<RTCRtpReceiver>} list of receivers created by the peerconnection.\n */\nTraceablePeerConnection.prototype._getReceiversByEndpointIds = function(endpoints, mediaType) {\n    let remoteTracks = [];\n    let receivers = [];\n\n    for (const endpoint of endpoints) {\n        remoteTracks = remoteTracks.concat(this.getRemoteTracks(endpoint, mediaType));\n    }\n\n    // Get the ids of the MediaStreamTracks associated with each of these remote tracks.\n    const remoteTrackIds = remoteTracks.map(remote => remote.track?.id);\n\n    receivers = this.peerconnection.getReceivers()\n        .filter(receiver => receiver.track\n            && receiver.track.kind === mediaType\n            && remoteTrackIds.find(trackId => trackId === receiver.track.id));\n\n    return receivers;\n};\n\n/**\n * Tells whether or not this TPC instance is using Simulcast.\n * @return {boolean} <tt>true</tt> if simulcast is enabled and active or\n * <tt>false</tt> if it's turned off.\n */\nTraceablePeerConnection.prototype.isSimulcastOn = function() {\n    return !this.options.disableSimulcast;\n};\n\n/**\n * Handles {@link SignalingEvents.PEER_VIDEO_TYPE_CHANGED}\n * @param {string} endpointId the video owner's ID (MUC nickname)\n * @param {VideoType} videoType the new value\n * @private\n */\nTraceablePeerConnection.prototype._peerVideoTypeChanged = function(endpointId, videoType) {\n    // Check if endpointId has a value to avoid action on random track\n    if (!endpointId) {\n        logger.error(`${this} No endpointID on peerVideoTypeChanged`);\n\n        return;\n    }\n    const videoTrack = this.getRemoteTracks(endpointId, MediaType.VIDEO);\n\n    if (videoTrack.length) {\n        // NOTE 1 track per media type is assumed\n        videoTrack[0]._setVideoType(videoType);\n    }\n};\n\n/**\n * Handles remote track mute / unmute events.\n * @param {string} endpointId the track owner's identifier (MUC nickname)\n * @param {MediaType} mediaType \"audio\" or \"video\"\n * @param {boolean} isMuted the new mute state\n * @private\n */\nTraceablePeerConnection.prototype._peerMutedChanged = function(endpointId, mediaType, isMuted) {\n    // Check if endpointId is a value to avoid doing action on all remote tracks\n    if (!endpointId) {\n        logger.error(`${this} On peerMuteChanged - no endpoint ID`);\n\n        return;\n    }\n    const track = this.getRemoteTracks(endpointId, mediaType);\n\n    if (track.length) {\n        // NOTE 1 track per media type is assumed\n        track[0].setMute(isMuted);\n    }\n};\n\n/**\n * Handles remote source mute and unmute changed events.\n *\n * @param {string} sourceName - The name of the remote source.\n * @param {boolean} isMuted - The new mute state.\n */\nTraceablePeerConnection.prototype._sourceMutedChanged = function(sourceName, isMuted) {\n    const track = this.getRemoteTracks().find(t => t.getSourceName() === sourceName);\n\n    if (!track) {\n        if (FeatureFlags.isSsrcRewritingSupported()) {\n            logger.debug(`Remote track not found for source=${sourceName}, mute update failed!`);\n        }\n\n        return;\n    }\n\n    track.setMute(isMuted);\n};\n\n/**\n * Handles remote source videoType changed events.\n *\n * @param {string} sourceName - The name of the remote source.\n * @param {boolean} isMuted - The new value.\n */\nTraceablePeerConnection.prototype._sourceVideoTypeChanged = function(sourceName, videoType) {\n    const track = this.getRemoteTracks().find(t => t.getSourceName() === sourceName);\n\n    if (!track) {\n        return;\n    }\n\n    track._setVideoType(videoType);\n};\n\n/**\n * Obtains audio levels of the remote audio tracks by getting the source information on the RTCRtpReceivers.\n * The information relevant to the ssrc is updated each time a RTP packet constaining the ssrc is received.\n * @param {Array<string>} speakerList list of endpoint ids for which audio levels are to be gathered.\n * @returns {Object} containing ssrc and audio level information as a key-value pair.\n */\nTraceablePeerConnection.prototype.getAudioLevels = function(speakerList = []) {\n    const audioLevels = {};\n    const audioReceivers = speakerList.length\n        ? this._getReceiversByEndpointIds(speakerList, MediaType.AUDIO)\n        : this.peerconnection.getReceivers()\n            .filter(receiver => receiver.track && receiver.track.kind === MediaType.AUDIO && receiver.track.enabled);\n\n    audioReceivers.forEach(remote => {\n        const ssrc = remote.getSynchronizationSources();\n\n        if (ssrc && ssrc.length) {\n            // As per spec, this audiolevel is a value between 0..1 (linear), where 1.0\n            // represents 0 dBov, 0 represents silence, and 0.5 represents approximately\n            // 6 dBSPL change in the sound pressure level from 0 dBov.\n            // https://www.w3.org/TR/webrtc/#dom-rtcrtpcontributingsource-audiolevel\n            audioLevels[ssrc[0].source] = ssrc[0].audioLevel;\n        }\n    });\n\n    return audioLevels;\n};\n\n/**\n * Checks if the browser is currently doing true simulcast where in three different media streams are being sent to the\n * bridge. Currently this happens only when VP8 is the selected codec.\n * @returns {boolean}\n */\nTraceablePeerConnection.prototype.doesTrueSimulcast = function() {\n    return this.isSimulcastOn() && this.getConfiguredVideoCodec() === CodecMimeType.VP8;\n};\n\n/**\n * Returns the SSRCs associated with a given local video track.\n *\n * @param {JitsiLocalTrack} localTrack\n * @returns\n */\nTraceablePeerConnection.prototype.getLocalVideoSSRCs = function(localTrack) {\n    const ssrcs = [];\n\n    if (!localTrack || !localTrack.isVideoTrack()) {\n        return ssrcs;\n    }\n\n    const ssrcGroup = this.isSimulcastOn() ? 'SIM' : 'FID';\n\n    return this.localSSRCs.get(localTrack.rtcId)?.groups?.find(group => group.semantics === ssrcGroup)?.ssrcs || ssrcs;\n};\n\n/**\n * Obtains local tracks for given {@link MediaType}. If the <tt>mediaType</tt>\n * argument is omitted the list of all local tracks will be returned.\n * @param {MediaType} [mediaType]\n * @return {Array<JitsiLocalTrack>}\n */\nTraceablePeerConnection.prototype.getLocalTracks = function(mediaType) {\n    let tracks = Array.from(this.localTracks.values());\n\n    if (mediaType !== undefined) {\n        tracks = tracks.filter(track => track.getType() === mediaType);\n    }\n\n    return tracks;\n};\n\n/**\n * Retrieves the local video tracks.\n *\n * @returns {Array<JitsiLocalTrack>} - local video tracks.\n */\nTraceablePeerConnection.prototype.getLocalVideoTracks = function() {\n    return this.getLocalTracks(MediaType.VIDEO);\n};\n\n/**\n * Checks whether or not this {@link TraceablePeerConnection} instance contains any local tracks for given\n * <tt>mediaType</tt>.\n *\n * @param {MediaType} mediaType - The media type.\n * @return {boolean}\n */\nTraceablePeerConnection.prototype.hasAnyTracksOfType = function(mediaType) {\n    if (!mediaType) {\n        throw new Error('\"mediaType\" is required');\n    }\n\n    return this.getLocalTracks(mediaType).length > 0;\n};\n\n/**\n * Obtains all remote tracks currently known to this PeerConnection instance.\n *\n * @param {string} [endpointId] - The track owner's identifier (MUC nickname)\n * @param {MediaType} [mediaType] - The remote tracks will be filtered by their media type if this argument is\n * specified.\n * @return {Array<JitsiRemoteTrack>}\n */\nTraceablePeerConnection.prototype.getRemoteTracks = function(endpointId, mediaType) {\n    let remoteTracks = [];\n    const endpoints = endpointId ? [ endpointId ] : this.remoteTracks.keys();\n\n    for (const endpoint of endpoints) {\n        const endpointTracksByMediaType = this.remoteTracks.get(endpoint);\n\n        if (endpointTracksByMediaType) {\n            for (const trackMediaType of endpointTracksByMediaType.keys()) {\n                // per media type filtering\n                if (!mediaType || mediaType === trackMediaType) {\n                    remoteTracks = remoteTracks.concat(Array.from(endpointTracksByMediaType.get(trackMediaType)));\n                }\n            }\n        }\n    }\n\n    return remoteTracks;\n};\n\n/**\n * Parses the remote description and returns the sdp lines of the sources associated with a remote participant.\n *\n * @param {string} id Endpoint id of the remote participant.\n * @returns {Array<string>} The sdp lines that have the ssrc information.\n */\nTraceablePeerConnection.prototype.getRemoteSourceInfoByParticipant = function(id) {\n    const removeSsrcInfo = [];\n    const remoteTracks = this.getRemoteTracks(id);\n\n    if (!remoteTracks?.length) {\n        return removeSsrcInfo;\n    }\n    const primarySsrcs = remoteTracks.map(track => track.getSSRC());\n    const sdp = new SDP(this.remoteDescription.sdp);\n\n    primarySsrcs.forEach((ssrc, idx) => {\n        for (const media of sdp.media) {\n            let lines = '';\n            let ssrcLines = SDPUtil.findLines(media, `a=ssrc:${ssrc}`);\n\n            if (ssrcLines.length) {\n                if (!removeSsrcInfo[idx]) {\n                    removeSsrcInfo[idx] = '';\n                }\n\n                // Check if there are any FID groups present for the primary ssrc.\n                const fidLines = SDPUtil.findLines(media, `a=ssrc-group:FID ${ssrc}`);\n\n                if (fidLines.length) {\n                    const secondarySsrc = fidLines[0].split(' ')[2];\n\n                    lines += `${fidLines[0]}\\r\\n`;\n                    ssrcLines = ssrcLines.concat(SDPUtil.findLines(media, `a=ssrc:${secondarySsrc}`));\n                }\n                removeSsrcInfo[idx] += `${ssrcLines.join('\\r\\n')}\\r\\n`;\n                removeSsrcInfo[idx] += lines;\n            }\n        }\n    });\n\n    return removeSsrcInfo;\n};\n\n/**\n * Returns the target bitrates configured for the local video source.\n *\n * @returns {Object}\n */\nTraceablePeerConnection.prototype.getTargetVideoBitrates = function() {\n    const currentCodec = this.getConfiguredVideoCodec();\n\n    return this.tpcUtils.videoBitrates[currentCodec.toUpperCase()] || this.tpcUtils.videoBitrates;\n};\n\n/**\n * Tries to find {@link JitsiTrack} for given SSRC number. It will search both\n * local and remote tracks bound to this instance.\n * @param {number} ssrc\n * @return {JitsiTrack|null}\n */\nTraceablePeerConnection.prototype.getTrackBySSRC = function(ssrc) {\n    if (typeof ssrc !== 'number') {\n        throw new Error(`SSRC ${ssrc} is not a number`);\n    }\n    for (const localTrack of this.localTracks.values()) {\n        if (this.getLocalSSRC(localTrack) === ssrc) {\n            return localTrack;\n        }\n    }\n    for (const remoteTrack of this.getRemoteTracks()) {\n        if (remoteTrack.getSSRC() === ssrc) {\n            return remoteTrack;\n        }\n    }\n\n    return null;\n};\n\n/**\n * Tries to find SSRC number for given {@link JitsiTrack} id. It will search\n * both local and remote tracks bound to this instance.\n * @param {string} id\n * @return {number|null}\n */\nTraceablePeerConnection.prototype.getSsrcByTrackId = function(id) {\n\n    const findTrackById = track => track.getTrack().id === id;\n    const localTrack = this.getLocalTracks().find(findTrackById);\n\n    if (localTrack) {\n        return this.getLocalSSRC(localTrack);\n    }\n\n    const remoteTrack = this.getRemoteTracks().find(findTrackById);\n\n    if (remoteTrack) {\n        return remoteTrack.getSSRC();\n    }\n\n    return null;\n};\n\n/**\n * Called when new remote MediaStream is added to the PeerConnection.\n * @param {MediaStream} stream the WebRTC MediaStream for remote participant\n */\nTraceablePeerConnection.prototype._remoteStreamAdded = function(stream) {\n    const streamId = stream.id;\n\n    // Do not create remote tracks for 'mixed' JVB SSRCs (used by JVB for RTCP termination).\n    if (!RTC.isUserStreamById(streamId)) {\n        return;\n    }\n\n    // Bind 'addtrack'/'removetrack' event handlers\n    if (browser.isChromiumBased()) {\n        stream.onaddtrack = event => {\n            this._remoteTrackAdded(stream, event.track);\n        };\n        stream.onremovetrack = event => {\n            this._remoteTrackRemoved(stream, event.track);\n        };\n    }\n\n    // Call remoteTrackAdded for each track in the stream\n    const streamAudioTracks = stream.getAudioTracks();\n\n    for (const audioTrack of streamAudioTracks) {\n        this._remoteTrackAdded(stream, audioTrack);\n    }\n    const streamVideoTracks = stream.getVideoTracks();\n\n    for (const videoTrack of streamVideoTracks) {\n        this._remoteTrackAdded(stream, videoTrack);\n    }\n};\n\n\n/**\n * Called on \"track added\" and \"stream added\" PeerConnection events (because we\n * handle streams on per track basis). Finds the owner and the SSRC for\n * the track and passes that to ChatRoom for further processing.\n * @param {MediaStream} stream the WebRTC MediaStream instance which is\n * the parent of the track\n * @param {MediaStreamTrack} track the WebRTC MediaStreamTrack added for remote\n * participant.\n * @param {RTCRtpTransceiver} transceiver the WebRTC transceiver that is created\n * for the remote participant in unified plan.\n */\nTraceablePeerConnection.prototype._remoteTrackAdded = function(stream, track, transceiver = null) {\n    const streamId = stream.id;\n    const mediaType = track.kind;\n\n    // Do not create remote tracks for 'mixed' JVB SSRCs (used by JVB for RTCP termination).\n    if (!this.isP2P && !RTC.isUserStreamById(streamId)) {\n        return;\n    }\n    logger.info(`${this} Received track event for remote stream[id=${streamId},type=${mediaType}]`);\n\n    // look up an associated JID for a stream id\n    if (!mediaType) {\n        GlobalOnErrorHandler.callErrorHandler(\n            new Error(`MediaType undefined for remote track, stream id: ${streamId}, track creation failed!`));\n\n        return;\n    }\n\n    const remoteSDP = this._usesUnifiedPlan\n        ? new SDP(this.peerconnection.remoteDescription.sdp)\n        : new SDP(this.remoteDescription.sdp);\n    let mediaLine;\n\n    // In unified plan mode, find the matching mline using 'mid' or the 'msid' attr of the stream.\n    if (this._usesUnifiedPlan) {\n        if (transceiver?.mid) {\n            const mid = transceiver.mid;\n\n            mediaLine = remoteSDP.media.find(mls => SDPUtil.findLine(mls, `a=mid:${mid}`));\n        } else {\n            mediaLine = remoteSDP.media.find(mls => {\n                const msid = SDPUtil.findLine(mls, 'a=msid:');\n\n                return typeof msid === 'string' && streamId === msid.substring(7).split(' ')[0];\n            });\n        }\n    } else {\n        mediaLine = remoteSDP.media.find(mls => mls.startsWith(`m=${mediaType}`));\n    }\n\n    if (!mediaLine) {\n        GlobalOnErrorHandler.callErrorHandler(\n            new Error(`Matching media line not found in remote SDP for remote stream[id=${streamId},type=${mediaType}],`\n                + 'track creation failed!'));\n\n        return;\n    }\n\n    let ssrcLines = SDPUtil.findLines(mediaLine, 'a=ssrc:');\n\n    ssrcLines = ssrcLines.filter(line => line.indexOf(`msid:${streamId}`) !== -1);\n    if (!ssrcLines.length) {\n        GlobalOnErrorHandler.callErrorHandler(\n            new Error(`No SSRC lines found in remote SDP for remote stream[msid=${streamId},type=${mediaType}]`\n                + 'track creation failed!'));\n\n        return;\n    }\n\n    // FIXME the length of ssrcLines[0] not verified, but it will fail\n    // with global error handler anyway\n    const ssrcStr = ssrcLines[0].substring(7).split(' ')[0];\n    const trackSsrc = Number(ssrcStr);\n    const ownerEndpointId = this.signalingLayer.getSSRCOwner(trackSsrc);\n\n    if (isNaN(trackSsrc) || trackSsrc < 0) {\n        GlobalOnErrorHandler.callErrorHandler(\n            new Error(`Invalid SSRC for remote stream[ssrc=${trackSsrc},id=${streamId},type=${mediaType}]`\n                + 'track creation failed!'));\n\n        return;\n    }\n\n    if (!ownerEndpointId) {\n        GlobalOnErrorHandler.callErrorHandler(\n            new Error(`No SSRC owner known for remote stream[ssrc=${trackSsrc},id=${streamId},type=${mediaType}]`\n            + 'track creation failed!'));\n\n        return;\n    }\n\n    const sourceName = this.signalingLayer.getTrackSourceName(trackSsrc);\n    const peerMediaInfo = this.signalingLayer.getPeerMediaInfo(ownerEndpointId, mediaType, sourceName);\n\n    // Assume default presence state for remote source. Presence can be received after source signaling. This shouldn't\n    // prevent the endpoint from creating a remote track for the source.\n    let muted = true;\n    let videoType = VideoType.CAMERA;\n\n    if (peerMediaInfo) {\n        muted = peerMediaInfo.muted;\n        videoType = peerMediaInfo.videoType; // can be undefined\n    } else {\n        logger.info(`${this}: no source-info available for ${ownerEndpointId}:${sourceName}, assuming default state`);\n    }\n\n    this._createRemoteTrack(ownerEndpointId, stream, track, mediaType, videoType, trackSsrc, muted, sourceName);\n};\n\n// FIXME cleanup params\n/* eslint-disable max-params */\n\n/**\n * Initializes a new JitsiRemoteTrack instance with the data provided by\n * the signaling layer and SDP.\n *\n * @param {string} ownerEndpointId the owner's endpoint ID (MUC nickname)\n * @param {MediaStream} stream the WebRTC stream instance\n * @param {MediaStreamTrack} track the WebRTC track instance\n * @param {MediaType} mediaType the track's type of the media\n * @param {VideoType} [videoType] the track's type of the video (if applicable)\n * @param {number} ssrc the track's main SSRC number\n * @param {boolean} muted the initial muted status\n * @param {String} sourceName the track's source name\n */\nTraceablePeerConnection.prototype._createRemoteTrack = function(\n        ownerEndpointId,\n        stream,\n        track,\n        mediaType,\n        videoType,\n        ssrc,\n        muted,\n        sourceName) {\n    logger.info(`${this} creating remote track[endpoint=${ownerEndpointId},ssrc=${ssrc},`\n        + `type=${mediaType},sourceName=${sourceName}]`);\n    let remoteTracksMap = this.remoteTracks.get(ownerEndpointId);\n\n    if (!remoteTracksMap) {\n        remoteTracksMap = new Map();\n        remoteTracksMap.set(MediaType.AUDIO, new Set());\n        remoteTracksMap.set(MediaType.VIDEO, new Set());\n        this.remoteTracks.set(ownerEndpointId, remoteTracksMap);\n    }\n\n    const userTracksByMediaType = remoteTracksMap.get(mediaType);\n\n    if (userTracksByMediaType?.size\n        && Array.from(userTracksByMediaType).find(jitsiTrack => jitsiTrack.getTrack() === track)) {\n        // Ignore duplicated event which can originate either from 'onStreamAdded' or 'onTrackAdded'.\n        logger.info(`${this} ignored duplicated track event for track[endpoint=${ownerEndpointId},type=${mediaType}]`);\n\n        return;\n    }\n\n    const remoteTrack\n        = new JitsiRemoteTrack(\n                this.rtc,\n                this.rtc.conference,\n                ownerEndpointId,\n                stream,\n                track,\n                mediaType,\n                videoType,\n                ssrc,\n                muted,\n                this.isP2P,\n                sourceName);\n\n    userTracksByMediaType.add(remoteTrack);\n    this.eventEmitter.emit(RTCEvents.REMOTE_TRACK_ADDED, remoteTrack, this);\n};\n\n/**\n * Handles remote stream removal.\n * @param stream the WebRTC MediaStream object which is being removed from the\n * PeerConnection\n */\nTraceablePeerConnection.prototype._remoteStreamRemoved = function(stream) {\n    if (!RTC.isUserStream(stream)) {\n        logger.info(`Ignored remote 'stream removed' event for stream[id=${stream.id}]`);\n\n        return;\n    }\n\n    // Call remoteTrackRemoved for each track in the stream\n    const streamVideoTracks = stream.getVideoTracks();\n\n    for (const videoTrack of streamVideoTracks) {\n        this._remoteTrackRemoved(stream, videoTrack);\n    }\n    const streamAudioTracks = stream.getAudioTracks();\n\n    for (const audioTrack of streamAudioTracks) {\n        this._remoteTrackRemoved(stream, audioTrack);\n    }\n};\n\n/**\n * Handles remote media track removal.\n *\n * @param {MediaStream} stream - WebRTC MediaStream instance which is the parent of the track.\n * @param {MediaStreamTrack} track - WebRTC MediaStreamTrack which has been removed from the PeerConnection.\n * @returns {void}\n */\nTraceablePeerConnection.prototype._remoteTrackRemoved = function(stream, track) {\n    const streamId = stream.id;\n    const trackId = track?.id;\n\n    // Ignore stream removed events for JVB \"mixed\" sources (used for RTCP termination).\n    if (!RTC.isUserStreamById(streamId)) {\n        return;\n    }\n\n    if (!streamId) {\n        GlobalOnErrorHandler.callErrorHandler(new Error(`${this} remote track removal failed - no stream ID`));\n\n        return;\n    }\n\n    if (!trackId) {\n        GlobalOnErrorHandler.callErrorHandler(new Error(`${this} remote track removal failed - no track ID`));\n\n        return;\n    }\n\n    const toBeRemoved = this.getRemoteTracks().find(\n        remoteTrack => remoteTrack.getStreamId() === streamId && remoteTrack.getTrackId() === trackId);\n\n    if (!toBeRemoved) {\n        GlobalOnErrorHandler.callErrorHandler(new Error(`${this} remote track removal failed - track not found`));\n\n        return;\n    }\n\n    this._removeRemoteTrack(toBeRemoved);\n};\n\n/**\n * Removes all JitsiRemoteTracks associated with given MUC nickname (resource part of the JID).\n *\n * @param {string} owner - The resource part of the MUC JID.\n * @returns {JitsiRemoteTrack[]} - The array of removed tracks.\n */\nTraceablePeerConnection.prototype.removeRemoteTracks = function(owner) {\n    let removedTracks = [];\n    const remoteTracksByMedia = this.remoteTracks.get(owner);\n\n    if (remoteTracksByMedia) {\n        removedTracks = removedTracks.concat(Array.from(remoteTracksByMedia.get(MediaType.AUDIO)));\n        removedTracks = removedTracks.concat(Array.from(remoteTracksByMedia.get(MediaType.VIDEO)));\n        this.remoteTracks.delete(owner);\n    }\n    logger.debug(`${this} removed remote tracks[endpoint=${owner},count=${removedTracks.length}`);\n\n    return removedTracks;\n};\n\n/**\n * Removes and disposes given <tt>JitsiRemoteTrack</tt> instance. Emits {@link RTCEvents.REMOTE_TRACK_REMOVED}.\n *\n * @param {JitsiRemoteTrack} toBeRemoved - The remote track to be removed.\n * @returns {void}\n */\nTraceablePeerConnection.prototype._removeRemoteTrack = function(toBeRemoved) {\n    logger.info(`${this} Removing remote track stream[id=${toBeRemoved.getStreamId()},`\n        + `trackId=${toBeRemoved.getTrackId()}]`);\n\n    toBeRemoved.dispose();\n    const participantId = toBeRemoved.getParticipantId();\n    const userTracksByMediaType = this.remoteTracks.get(participantId);\n\n    if (!userTracksByMediaType) {\n        logger.error(`${this} removeRemoteTrack: no remote tracks map for endpoint=${participantId}`);\n    } else if (!userTracksByMediaType.get(toBeRemoved.getType())?.delete(toBeRemoved)) {\n        logger.error(`${this} Failed to remove ${toBeRemoved} - type mapping messed up ?`);\n    }\n    this.eventEmitter.emit(RTCEvents.REMOTE_TRACK_REMOVED, toBeRemoved);\n};\n\n/**\n * Returns a map with keys msid/mediaType and <tt>TrackSSRCInfo</tt> values.\n * @param {RTCSessionDescription} desc the local description.\n * @return {Map<string,TrackSSRCInfo>}\n */\nTraceablePeerConnection.prototype._extractSSRCMap = function(desc) {\n    /**\n     * Track SSRC infos mapped by stream ID (msid) or mediaType (unified-plan)\n     * @type {Map<string,TrackSSRCInfo>}\n     */\n    const ssrcMap = new Map();\n\n    /**\n     * Groups mapped by primary SSRC number\n     * @type {Map<number,Array<SSRCGroupInfo>>}\n     */\n    const groupsMap = new Map();\n\n    if (typeof desc !== 'object' || desc === null\n        || typeof desc.sdp !== 'string') {\n        logger.warn('An empty description was passed as an argument');\n\n        return ssrcMap;\n    }\n\n    const session = transform.parse(desc.sdp);\n\n    if (!Array.isArray(session.media)) {\n        return ssrcMap;\n    }\n\n    let media = session.media;\n\n    if (this._usesUnifiedPlan) {\n        media = media.filter(mline => mline.direction === MediaDirection.SENDONLY\n            || mline.direction === MediaDirection.SENDRECV);\n    } else {\n        media = [];\n        [ MediaType.AUDIO, MediaType.VIDEO ].forEach(mediaType => {\n            const mLine = session.media.find(m => m.type === mediaType);\n\n            mLine && media.push(mLine);\n        });\n    }\n\n    let index = 0;\n\n    for (const mLine of media) {\n        if (!Array.isArray(mLine.ssrcs)) {\n            continue; // eslint-disable-line no-continue\n        }\n\n        if (Array.isArray(mLine.ssrcGroups)) {\n            for (const group of mLine.ssrcGroups) {\n                if (typeof group.semantics !== 'undefined' && typeof group.ssrcs !== 'undefined') {\n                    // Parse SSRCs and store as numbers\n                    const groupSSRCs = group.ssrcs.split(' ').map(ssrcStr => parseInt(ssrcStr, 10));\n                    const primarySSRC = groupSSRCs[0];\n\n                    // Note that group.semantics is already present\n                    group.ssrcs = groupSSRCs;\n\n                    // eslint-disable-next-line max-depth\n                    if (!groupsMap.has(primarySSRC)) {\n                        groupsMap.set(primarySSRC, []);\n                    }\n                    groupsMap.get(primarySSRC).push(group);\n                }\n            }\n\n            const simGroup = mLine.ssrcGroups.find(group => group.semantics === 'SIM');\n\n            // Add a SIM group if its missing in the description (happens on Firefox).\n            if (!simGroup) {\n                const groupSsrcs = mLine.ssrcGroups.map(group => group.ssrcs[0]);\n\n                groupsMap.get(groupSsrcs[0]).push({\n                    semantics: 'SIM',\n                    ssrcs: groupSsrcs\n                });\n            }\n        }\n\n        let ssrcs = mLine.ssrcs;\n\n        // Filter the ssrcs with 'msid' attribute for plan-b clients and 'cname' for unified-plan clients.\n        ssrcs = this._usesUnifiedPlan\n            ? ssrcs.filter(s => s.attribute === 'cname')\n            : ssrcs.filter(s => s.attribute === 'msid');\n\n        for (const ssrc of ssrcs) {\n            // Use the mediaType as key for the source map for unified plan clients since msids are not part of\n            // the standard and the unified plan SDPs do not have a proper msid attribute for the sources.\n            // Also the ssrcs for sources do not change for Unified plan clients since RTCRtpSender#replaceTrack is\n            // used for switching the tracks so it is safe to use the mediaType as the key for the TrackSSRCInfo map.\n            const key = this._usesUnifiedPlan ? `${mLine.type}-${index}` : ssrc.value;\n            const ssrcNumber = ssrc.id;\n            let ssrcInfo = ssrcMap.get(key);\n\n            if (!ssrcInfo) {\n                ssrcInfo = {\n                    ssrcs: [],\n                    groups: [],\n                    msid: key\n                };\n                ssrcMap.set(key, ssrcInfo);\n            }\n            ssrcInfo.ssrcs.push(ssrcNumber);\n\n            if (groupsMap.has(ssrcNumber)) {\n                const ssrcGroups = groupsMap.get(ssrcNumber);\n\n                for (const group of ssrcGroups) {\n                    ssrcInfo.groups.push(group);\n                }\n            }\n        }\n\n        // Currently multi-stream is supported for video only.\n        mLine.type === MediaType.VIDEO && index++;\n    }\n\n    return ssrcMap;\n};\n\n/**\n * Takes a SessionDescription object and returns a \"normalized\" version.\n * Currently it takes care of ordering the a=ssrc lines and denoting receive\n * only SSRCs.\n */\nconst normalizePlanB = function(desc) {\n    if (typeof desc !== 'object' || desc === null\n        || typeof desc.sdp !== 'string') {\n        logger.warn('An empty description was passed as an argument');\n\n        return desc;\n    }\n\n    // eslint-disable-next-line no-shadow\n    const transform = require('sdp-transform');\n    const session = transform.parse(desc.sdp);\n\n    if (typeof session !== 'undefined'\n            && typeof session.media !== 'undefined'\n            && Array.isArray(session.media)) {\n        session.media.forEach(mLine => {\n\n            // Chrome appears to be picky about the order in which a=ssrc lines\n            // are listed in an m-line when rtx is enabled (and thus there are\n            // a=ssrc-group lines with FID semantics). Specifically if we have\n            // \"a=ssrc-group:FID S1 S2\" and the \"a=ssrc:S2\" lines appear before\n            // the \"a=ssrc:S1\" lines, SRD fails.\n            // So, put SSRC which appear as the first SSRC in an FID ssrc-group\n            // first.\n            const firstSsrcs = [];\n            const newSsrcLines = [];\n\n            if (typeof mLine.ssrcGroups !== 'undefined'\n                && Array.isArray(mLine.ssrcGroups)) {\n                mLine.ssrcGroups.forEach(group => {\n                    if (typeof group.semantics !== 'undefined'\n                        && group.semantics === 'FID') {\n                        if (typeof group.ssrcs !== 'undefined') {\n                            firstSsrcs.push(Number(group.ssrcs.split(' ')[0]));\n                        }\n                    }\n                });\n            }\n\n            if (Array.isArray(mLine.ssrcs)) {\n                let i;\n\n                for (i = 0; i < mLine.ssrcs.length; i++) {\n                    if (typeof mLine.ssrcs[i] === 'object'\n                        && typeof mLine.ssrcs[i].id !== 'undefined'\n                        && firstSsrcs.indexOf(mLine.ssrcs[i].id) >= 0) {\n                        newSsrcLines.push(mLine.ssrcs[i]);\n                        delete mLine.ssrcs[i];\n                    }\n                }\n\n                for (i = 0; i < mLine.ssrcs.length; i++) {\n                    if (typeof mLine.ssrcs[i] !== 'undefined') {\n                        newSsrcLines.push(mLine.ssrcs[i]);\n                    }\n                }\n\n                mLine.ssrcs = replaceDefaultUnifiedPlanMsid(newSsrcLines);\n            }\n        });\n    }\n\n    const resStr = transform.write(session);\n\n\n    return new RTCSessionDescription({\n        type: desc.type,\n        sdp: resStr\n    });\n};\n\n/**\n * Unified plan differentiates a remote track not associated with a stream using\n * the msid \"-\", which can incorrectly trigger an onaddstream event in plan-b.\n * For jitsi, these tracks are actually receive-only ssrcs. To prevent\n * onaddstream from firing, remove the ssrcs with msid \"-\" except the cname\n * line. Normally the ssrcs are not used by the client, as the bridge controls\n * media flow, but keep one reference to the ssrc for the p2p case.\n *\n * @param {Array<Object>} ssrcLines - The ssrc lines from a remote description.\n * @private\n * @returns {Array<Object>} ssrcLines with removed lines referencing msid \"-\".\n */\nfunction replaceDefaultUnifiedPlanMsid(ssrcLines = []) {\n    if (!browser.isChrome() || !browser.isVersionGreaterThan(70)) {\n        return ssrcLines;\n    }\n\n    let filteredLines = [ ...ssrcLines ];\n\n    const problematicSsrcIds = ssrcLines.filter(ssrcLine =>\n        ssrcLine.attribute === 'mslabel' && ssrcLine.value === '-')\n        .map(ssrcLine => ssrcLine.id);\n\n    problematicSsrcIds.forEach(ssrcId => {\n        // Find the cname which is to be modified and left in.\n        const cnameLine = filteredLines.find(line =>\n            line.id === ssrcId && line.attribute === 'cname');\n\n        cnameLine.value = `${MediaDirection.RECVONLY}-${ssrcId}`;\n\n        // Remove all of lines for the ssrc.\n        filteredLines\n            = filteredLines.filter(line => line.id !== ssrcId);\n\n        // But re-add the cname line so there is a reference kept to the ssrc\n        // in the SDP.\n        filteredLines.push(cnameLine);\n    });\n\n    return filteredLines;\n}\n\n/**\n * Makes sure that both audio and video directions are configured as 'sendrecv'.\n * @param {Object} localDescription the SDP object as defined by WebRTC.\n * @param {object} options <tt>TracablePeerConnection</tt> config options.\n */\nconst enforceSendRecv = function(localDescription, options) {\n    if (!localDescription) {\n        throw new Error('No local description passed in.');\n    }\n\n    const transformer = new SdpTransformWrap(localDescription.sdp);\n    const audioMedia = transformer.selectMedia(MediaType.AUDIO)?.[0];\n    let changed = false;\n\n    if (audioMedia && audioMedia.direction !== MediaDirection.SENDRECV) {\n        if (options.startSilent) {\n            audioMedia.direction = MediaDirection.INACTIVE;\n        } else {\n            audioMedia.direction = MediaDirection.SENDRECV;\n        }\n\n        changed = true;\n    }\n\n    const videoMedia = transformer.selectMedia(MediaType.VIDEO)?.[0];\n\n    if (videoMedia && videoMedia.direction !== MediaDirection.SENDRECV) {\n        videoMedia.direction = MediaDirection.SENDRECV;\n        changed = true;\n    }\n\n    if (changed) {\n        return new RTCSessionDescription({\n            type: localDescription.type,\n            sdp: transformer.toRawSDP()\n        });\n    }\n\n    return localDescription;\n};\n\n/**\n *\n * @param {JitsiLocalTrack} localTrack\n */\nTraceablePeerConnection.prototype.getLocalSSRC = function(localTrack) {\n    const ssrcInfo = this._getSSRC(localTrack.rtcId);\n\n    return ssrcInfo && ssrcInfo.ssrcs[0];\n};\n\n/**\n * When doing unified plan simulcast, we'll have a set of ssrcs but no ssrc-groups on Firefox. Unfortunately, Jicofo\n * will complain if it sees ssrcs with matching msids but no ssrc-group, so a ssrc-group line is injected to make\n * Jicofo happy.\n *\n * @param desc A session description object (with 'type' and 'sdp' fields)\n * @return A session description object with its sdp field modified to contain an inject ssrc-group for simulcast.\n */\nTraceablePeerConnection.prototype._injectSsrcGroupForUnifiedSimulcast = function(desc) {\n    const sdp = transform.parse(desc.sdp);\n    const video = sdp.media.find(mline => mline.type === 'video');\n\n    // Check if the browser supports RTX, add only the primary ssrcs to the SIM group if that is the case.\n    video.ssrcGroups = video.ssrcGroups || [];\n    const fidGroups = video.ssrcGroups.filter(group => group.semantics === 'FID');\n\n    if (video.simulcast || video.simulcast_03) {\n        const ssrcs = [];\n\n        if (fidGroups && fidGroups.length) {\n            fidGroups.forEach(group => {\n                ssrcs.push(group.ssrcs.split(' ')[0]);\n            });\n        } else {\n            video.ssrcs.forEach(ssrc => {\n                if (ssrc.attribute === 'msid') {\n                    ssrcs.push(ssrc.id);\n                }\n            });\n        }\n        if (video.ssrcGroups.find(group => group.semantics === 'SIM')) {\n            // Group already exists, no need to do anything\n            return desc;\n        }\n\n        // Add a SIM group for every 3 FID groups.\n        for (let i = 0; i < ssrcs.length; i += 3) {\n            const simSsrcs = ssrcs.slice(i, i + 3);\n\n            video.ssrcGroups.push({\n                semantics: 'SIM',\n                ssrcs: simSsrcs.join(' ')\n            });\n        }\n    }\n\n    return new RTCSessionDescription({\n        type: desc.type,\n        sdp: transform.write(sdp)\n    });\n};\n\n/* eslint-disable-next-line vars-on-top */\nconst getters = {\n    signalingState() {\n        return this.peerconnection.signalingState;\n    },\n    iceConnectionState() {\n        return this.peerconnection.iceConnectionState;\n    },\n    connectionState() {\n        return this.peerconnection.connectionState;\n    },\n    localDescription() {\n        let desc = this.peerconnection.localDescription;\n\n        if (!desc) {\n            logger.debug(`${this} getLocalDescription no localDescription found`);\n\n            return {};\n        }\n\n        this.trace('getLocalDescription::preTransform', dumpSDP(desc));\n\n        // If the browser is running in unified plan mode and this is a jvb connection,\n        // transform the SDP to Plan B first.\n        if (this._usesUnifiedPlan && !this.isP2P) {\n            desc = this.interop.toPlanB(desc);\n            this.trace('getLocalDescription::postTransform (Plan B)',\n                dumpSDP(desc));\n\n            desc = this._injectSsrcGroupForUnifiedSimulcast(desc);\n            this.trace('getLocalDescription::postTransform (inject ssrc group)',\n                dumpSDP(desc));\n        } else if (!this._usesUnifiedPlan) {\n            if (browser.doesVideoMuteByStreamRemove()) {\n                desc = this.localSdpMunger.maybeAddMutedLocalVideoTracksToSDP(desc);\n                logger.debug(\n                    'getLocalDescription::postTransform (munge local SDP)', desc);\n            }\n\n            // What comes out of this getter will be signalled over Jingle to\n            // the other peer, so we need to make sure the media direction is\n            // 'sendrecv' because we won't change the direction later and don't want\n            // the other peer to think we can't send or receive.\n            //\n            // Note that the description we set in chrome does have the accurate\n            // direction (e.g. 'recvonly'), since that is technically what is\n            // happening (check setLocalDescription impl).\n            desc = enforceSendRecv(desc, this.options);\n        }\n\n        // See the method's doc for more info about this transformation.\n        desc = this.localSdpMunger.transformStreamIdentifiers(desc);\n\n        return desc;\n    },\n    remoteDescription() {\n        let desc = this.peerconnection.remoteDescription;\n\n        if (!desc) {\n            logger.debug(`${this} getRemoteDescription no remoteDescription found`);\n\n            return {};\n        }\n        this.trace('getRemoteDescription::preTransform', dumpSDP(desc));\n\n        if (this._usesUnifiedPlan) {\n            if (this.isP2P) {\n                // Adjust the media direction for p2p based on whether a local source has been added.\n                desc = this._adjustRemoteMediaDirection(desc);\n            } else {\n                // If this is a jvb connection, transform the SDP to Plan B first.\n                desc = this.interop.toPlanB(desc);\n                this.trace('getRemoteDescription::postTransform (Plan B)', dumpSDP(desc));\n            }\n        }\n\n        return desc;\n    }\n};\n\nObject.keys(getters).forEach(prop => {\n    Object.defineProperty(\n        TraceablePeerConnection.prototype,\n        prop, {\n            get: getters[prop]\n        }\n    );\n});\n\nTraceablePeerConnection.prototype._getSSRC = function(rtcId) {\n    return this.localSSRCs.get(rtcId);\n};\n\n/**\n * Checks if low fps screensharing is in progress.\n *\n * @private\n * @returns {boolean} Returns true if 5 fps screensharing is in progress, false otherwise.\n */\nTraceablePeerConnection.prototype.isSharingLowFpsScreen = function() {\n    return this._isSharingScreen() && this._capScreenshareBitrate;\n};\n\n/**\n * Checks if screensharing is in progress.\n *\n * @returns {boolean}  Returns true if a desktop track has been added to the peerconnection, false otherwise.\n */\nTraceablePeerConnection.prototype._isSharingScreen = function() {\n    const tracks = this.getLocalVideoTracks();\n\n    return Boolean(tracks.find(track => track.videoType === VideoType.DESKTOP));\n};\n\n/**\n * Munges the order of the codecs in the SDP passed based on the preference\n * set through config.js settings. All instances of the specified codec are\n * moved up to the top of the list when it is preferred. The specified codec\n * is deleted from the list if the configuration specifies that the codec be\n * disabled.\n * @param {RTCSessionDescription} description that needs to be munged.\n * @returns {RTCSessionDescription} the munged description.\n */\nTraceablePeerConnection.prototype._mungeCodecOrder = function(description) {\n    const parsedSdp = transform.parse(description.sdp);\n    const mLines = parsedSdp.media.filter(m => m.type === this.codecSettings.mediaType);\n\n    if (!mLines.length) {\n        return description;\n    }\n\n    for (const mLine of mLines) {\n        if (this.codecSettings.disabled) {\n            SDPUtil.stripCodec(mLine, this.codecSettings.disabled);\n        }\n\n        if (this.codecSettings.preferred) {\n            SDPUtil.preferCodec(mLine, this.codecSettings.preferred);\n\n            // Strip the high profile H264 codecs on mobile clients for p2p connection. High profile codecs give better\n            // quality at the expense of higher load which we do not want on mobile clients. Jicofo offers only the\n            // baseline code for the jvb connection and therefore this is not needed for jvb connection.\n            // TODO - add check for mobile browsers once js-utils provides that check.\n            if (this.codecSettings.preferred === CodecMimeType.H264 && browser.isReactNative() && this.isP2P) {\n                SDPUtil.stripCodec(mLine, this.codecSettings.preferred, true /* high profile */);\n            }\n        }\n    }\n\n    return new RTCSessionDescription({\n        type: description.type,\n        sdp: transform.write(parsedSdp)\n    });\n};\n\n/**\n * Add {@link JitsiLocalTrack} to this TPC.\n * @param {JitsiLocalTrack} track\n * @param {boolean} isInitiator indicates if the endpoint is the offerer.\n * @returns {Promise<void>} - resolved when done.\n */\nTraceablePeerConnection.prototype.addTrack = function(track, isInitiator = false) {\n    const rtcId = track.rtcId;\n\n    logger.info(`${this} adding ${track}`);\n\n    if (this.localTracks.has(rtcId)) {\n\n        return Promise.reject(new Error(`${track} is already in ${this}`));\n    }\n\n    this.localTracks.set(rtcId, track);\n    const webrtcStream = track.getOriginalStream();\n\n    if (this._usesUnifiedPlan) {\n        logger.debug(`${this} TPC.addTrack using unified plan`);\n        try {\n            this.tpcUtils.addTrack(track, isInitiator);\n            if (track) {\n                if (track.isAudioTrack()) {\n                    this._hasHadAudioTrack = true;\n                } else {\n                    this._hasHadVideoTrack = true;\n                }\n            }\n        } catch (error) {\n            logger.error(`${this} Adding track=${track} failed: ${error?.message}`);\n\n            return Promise.reject(error);\n        }\n    } else {\n        // Use addStream API for the plan-b case.\n        if (webrtcStream) {\n            this._addStream(webrtcStream);\n\n        // It's not ok for a track to not have a WebRTC stream if:\n        } else if (!browser.doesVideoMuteByStreamRemove()\n                    || track.isAudioTrack()\n                    || (track.isVideoTrack() && !track.isMuted())) {\n            return Promise.reject(new Error(`${this} no WebRTC stream for track=${track}`));\n        }\n\n        // Muted video tracks do not have WebRTC stream\n        if (browser.doesVideoMuteByStreamRemove() && track.isVideoTrack() && track.isMuted()) {\n            const ssrcInfo = this.generateNewStreamSSRCInfo(track);\n\n            this.sdpConsistency.setPrimarySsrc(ssrcInfo.ssrcs[0]);\n            const simGroup\n                = ssrcInfo.groups.find(groupInfo => groupInfo.semantics === 'SIM');\n\n            if (simGroup) {\n                this.simulcast.setSsrcCache(simGroup.ssrcs);\n            }\n            const fidGroups\n                = ssrcInfo.groups.filter(\n                    groupInfo => groupInfo.semantics === 'FID');\n\n            if (fidGroups) {\n                const rtxSsrcMapping = new Map();\n\n                fidGroups.forEach(fidGroup => {\n                    const primarySsrc = fidGroup.ssrcs[0];\n                    const rtxSsrc = fidGroup.ssrcs[1];\n\n                    rtxSsrcMapping.set(primarySsrc, rtxSsrc);\n                });\n                this.rtxModifier.setSsrcCache(rtxSsrcMapping);\n            }\n        }\n    }\n    let promiseChain = Promise.resolve();\n\n    // On Firefox, the encodings have to be configured on the sender only after the transceiver is created.\n    if (browser.isFirefox()) {\n        promiseChain = promiseChain.then(() => webrtcStream && this.tpcUtils.setEncodings(track));\n    }\n\n    return promiseChain;\n};\n\n/**\n * Adds local track to the RTCPeerConnection.\n *\n * @param {JitsiLocalTrack} track the track to be added to the pc.\n * @return {Promise<boolean>} Promise that resolves to true if the underlying PeerConnection's state has changed and\n * renegotiation is required, false if no renegotiation is needed or Promise is rejected when something goes wrong.\n */\nTraceablePeerConnection.prototype.addTrackToPc = function(track) {\n    logger.info(`${this} Adding track=${track} to PC`);\n\n    if (!this._assertTrackBelongs('addTrackToPc', track)) {\n        // Abort\n\n        return Promise.reject('Track not found on the peerconnection');\n    }\n\n    const webRtcStream = track.getOriginalStream();\n\n    if (!webRtcStream) {\n        logger.error(`${this} Unable to add track=${track} to PC - no WebRTC stream`);\n\n        return Promise.reject('Stream not found');\n    }\n\n    if (this._usesUnifiedPlan) {\n        return this.tpcUtils.replaceTrack(null, track).then(() => {\n            if (track) {\n                if (track.isAudioTrack()) {\n                    this._hasHadAudioTrack = true;\n                } else {\n                    this._hasHadVideoTrack = true;\n                }\n            }\n\n            return false;\n        });\n    }\n\n    this._addStream(webRtcStream);\n\n    return Promise.resolve(true);\n};\n\n/**\n * Adds WebRTC media stream to the underlying PeerConnection\n * @param {MediaStream} mediaStream\n * @private\n */\nTraceablePeerConnection.prototype._addStream = function(mediaStream) {\n    this.peerconnection.addStream(mediaStream);\n    this._addedStreams.push(mediaStream);\n};\n\n/**\n * Removes WebRTC media stream from the underlying PeerConection\n * @param {MediaStream} mediaStream\n */\nTraceablePeerConnection.prototype._removeStream = function(mediaStream) {\n    this.peerconnection.removeStream(mediaStream);\n    this._addedStreams\n        = this._addedStreams.filter(stream => stream !== mediaStream);\n};\n\n/**\n * This method when called will check if given <tt>localTrack</tt> belongs to\n * this TPC (that it has been previously added using {@link addTrack}). If the\n * track does not belong an error message will be logged.\n * @param {string} methodName the method name that will be logged in an error\n * message\n * @param {JitsiLocalTrack} localTrack\n * @return {boolean} <tt>true</tt> if given local track belongs to this TPC or\n * <tt>false</tt> otherwise.\n * @private\n */\nTraceablePeerConnection.prototype._assertTrackBelongs = function(\n        methodName,\n        localTrack) {\n    const doesBelong = this.localTracks.has(localTrack?.rtcId);\n\n    if (!doesBelong) {\n        logger.error(`${this} ${methodName}: track=${localTrack} does not belong to pc`);\n    }\n\n    return doesBelong;\n};\n\n/**\n * Returns the codec that is configured on the client as the preferred video codec.\n * This takes into account the current order of codecs in the local description sdp.\n *\n * @returns {CodecMimeType} The codec that is set as the preferred codec to receive\n * video in the local SDP.\n */\nTraceablePeerConnection.prototype.getConfiguredVideoCodec = function() {\n    const sdp = this.peerconnection.localDescription?.sdp;\n    const defaultCodec = CodecMimeType.VP8;\n\n    if (!sdp) {\n        return defaultCodec;\n    }\n    const parsedSdp = transform.parse(sdp);\n    const mLine = parsedSdp.media.find(m => m.type === MediaType.VIDEO);\n    const codec = mLine.rtp[0].codec;\n\n    if (codec) {\n        return Object.values(CodecMimeType).find(value => value === codec.toLowerCase());\n    }\n\n    return defaultCodec;\n};\n\n/**\n * Checks if the client has negotiated not to receive video encoded using the given codec, i.e., the codec has been\n * removed from the local description.\n */\nTraceablePeerConnection.prototype.isVideoCodecDisabled = function(codec) {\n    const sdp = this.peerconnection.localDescription?.sdp;\n\n    if (!sdp) {\n        return false;\n    }\n    const parsedSdp = transform.parse(sdp);\n    const mLine = parsedSdp.media.find(m => m.type === MediaType.VIDEO);\n\n    return !mLine.rtp.find(r => r.codec === codec);\n};\n\n/**\n * Enables or disables simulcast for screenshare based on the frame rate requested for desktop track capture.\n *\n * @param {number} maxFps framerate to be used for desktop track capture.\n */\nTraceablePeerConnection.prototype.setDesktopSharingFrameRate = function(maxFps) {\n    const lowFps = maxFps <= SS_DEFAULT_FRAME_RATE;\n\n    this._capScreenshareBitrate = this.isSimulcastOn() && lowFps;\n};\n\n/**\n * Sets the codec preference on the peerconnection. The codec preference goes into effect when\n * the next renegotiation happens.\n *\n * @param {CodecMimeType} preferredCodec the preferred codec.\n * @param {CodecMimeType} disabledCodec the codec that needs to be disabled.\n * @returns {void}\n */\nTraceablePeerConnection.prototype.setVideoCodecs = function(preferredCodec, disabledCodec) {\n    preferredCodec && (this.codecSettings.preferred = preferredCodec);\n    disabledCodec && (this.codecSettings.disabled = disabledCodec);\n};\n\n/**\n * Tells if the given WebRTC <tt>MediaStream</tt> has been added to\n * the underlying WebRTC PeerConnection.\n * @param {MediaStream} mediaStream\n * @returns {boolean}\n */\nTraceablePeerConnection.prototype.isMediaStreamInPc = function(mediaStream) {\n    return this._addedStreams.indexOf(mediaStream) > -1;\n};\n\n/**\n * Remove local track from this TPC.\n * @param {JitsiLocalTrack} localTrack the track to be removed from this TPC.\n *\n * FIXME It should probably remove a boolean just like {@link removeTrackFromPc}\n *       The same applies to addTrack.\n */\nTraceablePeerConnection.prototype.removeTrack = function(localTrack) {\n    const webRtcStream = localTrack.getOriginalStream();\n\n    this.trace(\n        'removeStream',\n        localTrack.rtcId, webRtcStream ? webRtcStream.id : undefined);\n\n    if (!this._assertTrackBelongs('removeStream', localTrack)) {\n        // Abort - nothing to be done here\n        return;\n    }\n    this.localTracks.delete(localTrack.rtcId);\n    this.localSSRCs.delete(localTrack.rtcId);\n\n    if (webRtcStream) {\n        this.peerconnection.removeStream(webRtcStream);\n    }\n};\n\n/**\n * Returns the sender corresponding to the given media type.\n * @param {MEDIA_TYPE} mediaType - The media type 'audio' or 'video' to be used for the search.\n * @returns {RTPSender|undefined} - The found sender or undefined if no sender\n * was found.\n */\nTraceablePeerConnection.prototype.findSenderByKind = function(mediaType) {\n    if (this.peerconnection.getSenders) {\n        return this.peerconnection.getSenders().find(s => s.track && s.track.kind === mediaType);\n    }\n};\n\n/**\n * Returns the receiver corresponding to the given MediaStreamTrack.\n *\n * @param {MediaSreamTrack} track - The media stream track used for the search.\n * @returns {RTCRtpReceiver|undefined} - The found receiver or undefined if no receiver\n * was found.\n */\nTraceablePeerConnection.prototype.findReceiverForTrack = function(track) {\n    return this.peerconnection.getReceivers().find(r => r.track === track);\n};\n\n/**\n * Returns the sender corresponding to the given MediaStreamTrack.\n *\n * @param {MediaSreamTrack} track - The media stream track used for the search.\n * @returns {RTCRtpSender|undefined} - The found sender or undefined if no sender\n * was found.\n */\nTraceablePeerConnection.prototype.findSenderForTrack = function(track) {\n    if (this.peerconnection.getSenders) {\n        return this.peerconnection.getSenders().find(s => s.track === track);\n    }\n};\n\n/**\n * Processes the local description SDP and caches the mids of the mlines associated with the given tracks.\n *\n * @param {Array<JitsiLocalTrack>} localTracks - local tracks that are added to the peerconnection.\n * @returns {void}\n */\nTraceablePeerConnection.prototype.processLocalSdpForTransceiverInfo = function(localTracks) {\n    const localSdp = this.peerconnection.localDescription?.sdp;\n\n    if (!localSdp) {\n        return;\n    }\n\n    [ MediaType.AUDIO, MediaType.VIDEO ].forEach(mediaType => {\n        const tracks = localTracks.filter(t => t.getType() === mediaType);\n        const parsedSdp = transform.parse(localSdp);\n        const mLines = parsedSdp.media.filter(mline => mline.type === mediaType);\n\n        tracks.forEach((track, idx) => {\n            if (!this._localTrackTransceiverMids.has(track.rtcId)) {\n                this._localTrackTransceiverMids.set(track.rtcId, mLines[idx].mid.toString());\n            }\n        });\n    });\n};\n\n/**\n * Replaces <tt>oldTrack</tt> with <tt>newTrack</tt> from the peer connection.\n * Either <tt>oldTrack</tt> or <tt>newTrack</tt> can be null; replacing a valid\n * <tt>oldTrack</tt> with a null <tt>newTrack</tt> effectively just removes\n * <tt>oldTrack</tt>\n *\n * @param {JitsiLocalTrack|null} oldTrack - The current track in use to be replaced on the pc.\n * @param {JitsiLocalTrack|null} newTrack - The new track to be used.\n *\n * @returns {Promise<boolean>} - If the promise resolves with true, renegotiation will be needed.\n * Otherwise no renegotiation is needed.\n */\nTraceablePeerConnection.prototype.replaceTrack = function(oldTrack, newTrack) {\n    if (!(oldTrack || newTrack)) {\n        logger.info(`${this} replaceTrack called with no new track and no old track`);\n\n        return Promise.resolve();\n    }\n\n    if (this._usesUnifiedPlan) {\n        logger.debug(`${this} TPC.replaceTrack using unified plan`);\n\n        return this.tpcUtils.replaceTrack(oldTrack, newTrack)\n            .then(transceiver => {\n                if (oldTrack) {\n                    this.localTracks.delete(oldTrack.rtcId);\n                    this._localTrackTransceiverMids.delete(oldTrack.rtcId);\n                }\n\n                if (newTrack) {\n                    if (newTrack.isAudioTrack()) {\n                        this._hasHadAudioTrack = true;\n                    } else {\n                        this._hasHadVideoTrack = true;\n                    }\n                    this._localTrackTransceiverMids.set(newTrack.rtcId, transceiver?.mid?.toString());\n                    this.localTracks.set(newTrack.rtcId, newTrack);\n                }\n\n                // Update the local SSRC cache for the case when one track gets replaced with another and no\n                // renegotiation is triggered as a result of this.\n                if (oldTrack && newTrack) {\n                    const oldTrackSSRC = this.localSSRCs.get(oldTrack.rtcId);\n\n                    if (oldTrackSSRC) {\n                        this.localSSRCs.delete(oldTrack.rtcId);\n                        this.localSSRCs.set(newTrack.rtcId, oldTrackSSRC);\n                    }\n                }\n\n                if (transceiver) {\n                    // In the scenario where we remove the oldTrack (oldTrack is not null and newTrack is null) on FF\n                    // if we change the direction to RECVONLY, create answer will generate SDP with only 1 receive\n                    // only ssrc instead of keeping all 6 ssrcs that we currently have. Stopping the screen sharing\n                    // and then starting it again will trigger 2 rounds of source-remove and source-add replacing\n                    // the 6 ssrcs for the screen sharing with 1 receive only ssrc and then removing the receive\n                    // only ssrc and adding the same 6 ssrcs. On the remote participant's side the same ssrcs will\n                    // be reused on a new m-line and if the remote participant is FF due to\n                    // https://bugzilla.mozilla.org/show_bug.cgi?id=1768729 the video stream won't be rendered.\n                    // That's why we need keep the direction to SENDRECV for FF.\n                    //\n                    // NOTE: If we return back to the approach of not removing the track for FF and instead using the\n                    // enabled property for mute or stopping screensharing we may need to change the direction to\n                    // RECVONLY if FF still sends the media even though the enabled flag is set to false.\n                    transceiver.direction\n                        = newTrack || browser.isFirefox() ? MediaDirection.SENDRECV : MediaDirection.RECVONLY;\n                }\n\n                // Avoid configuring the encodings on Chromium/Safari until simulcast is configured\n                // for the newly added track using SDP munging which happens during the renegotiation.\n                const configureEncodingsPromise = browser.usesSdpMungingForSimulcast() || !newTrack\n                    ? Promise.resolve()\n                    : this.tpcUtils.setEncodings(newTrack);\n\n                return configureEncodingsPromise.then(() => this.isP2P);\n            });\n    }\n\n    logger.debug(`${this} TPC.replaceTrack using plan B`);\n\n    let promiseChain = Promise.resolve();\n\n    if (oldTrack) {\n        this.removeTrack(oldTrack);\n    }\n    if (newTrack) {\n        promiseChain = this.addTrack(newTrack);\n    }\n\n    return promiseChain.then(() => true);\n};\n\n/**\n * Removes local track from the RTCPeerConnection.\n *\n * @param {JitsiLocalTrack} localTrack the local track to be removed.\n * @return {Promise<boolean>} Promise that resolves to true if the underlying PeerConnection's state has changed and\n * renegotiation is required, false if no renegotiation is needed or Promise is rejected when something goes wrong.\n */\nTraceablePeerConnection.prototype.removeTrackFromPc = function(localTrack) {\n    const webRtcStream = localTrack.getOriginalStream();\n\n    this.trace('removeTrack', localTrack.rtcId, webRtcStream ? webRtcStream.id : null);\n\n    if (!this._assertTrackBelongs('removeTrack', localTrack)) {\n        // Abort - nothing to be done here\n        return Promise.reject('Track not found in the peerconnection');\n    }\n\n    if (this._usesUnifiedPlan) {\n        return this.tpcUtils.replaceTrack(localTrack, null).then(() => false);\n    }\n\n    if (webRtcStream) {\n        logger.info(`${this} Removing track=${localTrack} from PC`);\n        this._removeStream(webRtcStream);\n\n        return Promise.resolve(true);\n    }\n\n    logger.error(`${this} removeTrack - no WebRTC stream for track=${localTrack}`);\n\n    return Promise.reject('Stream not found');\n};\n\nTraceablePeerConnection.prototype.createDataChannel = function(label, opts) {\n    this.trace('createDataChannel', label, opts);\n\n    return this.peerconnection.createDataChannel(label, opts);\n};\n\n/**\n * Ensures that the simulcast ssrc-group appears after any other ssrc-groups\n * in the SDP so that simulcast is properly activated.\n *\n * @param {Object} localSdp the WebRTC session description instance for\n * the local description.\n * @private\n */\nTraceablePeerConnection.prototype._ensureSimulcastGroupIsLast = function(localSdp) {\n    let sdpStr = localSdp.sdp;\n\n    const videoStartIndex = sdpStr.indexOf('m=video');\n    const simStartIndex = sdpStr.indexOf('a=ssrc-group:SIM', videoStartIndex);\n    let otherStartIndex = sdpStr.lastIndexOf('a=ssrc-group');\n\n    if (simStartIndex === -1\n        || otherStartIndex === -1\n        || otherStartIndex === simStartIndex) {\n        return localSdp;\n    }\n\n    const simEndIndex = sdpStr.indexOf('\\r\\n', simStartIndex);\n    const simStr = sdpStr.substring(simStartIndex, simEndIndex + 2);\n\n    sdpStr = sdpStr.replace(simStr, '');\n    otherStartIndex = sdpStr.lastIndexOf('a=ssrc-group');\n    const otherEndIndex = sdpStr.indexOf('\\r\\n', otherStartIndex);\n    const sdpHead = sdpStr.slice(0, otherEndIndex);\n    const simStrTrimmed = simStr.trim();\n    const sdpTail = sdpStr.slice(otherEndIndex);\n\n    sdpStr = `${sdpHead}\\r\\n${simStrTrimmed}${sdpTail}`;\n\n    return new RTCSessionDescription({\n        type: localSdp.type,\n        sdp: sdpStr\n    });\n};\n\n/**\n * Will adjust audio and video media direction in the given SDP object to\n * reflect the current status of the {@link audioTransferActive} and\n * {@link videoTransferActive} flags.\n * @param {RTCSessionDescription} localDescription the WebRTC session description instance for\n * the local description.\n * @private\n */\nTraceablePeerConnection.prototype._adjustLocalMediaDirection = function(localDescription) {\n    const transformer = new SdpTransformWrap(localDescription.sdp);\n    let modifiedDirection = false;\n    const audioMedia = transformer.selectMedia(MediaType.AUDIO)?.[0];\n\n    if (audioMedia) {\n        const desiredAudioDirection = this.getDesiredMediaDirection(MediaType.AUDIO);\n\n        if (audioMedia.direction !== desiredAudioDirection) {\n            audioMedia.direction = desiredAudioDirection;\n            logger.info(`${this} Adjusted local audio direction to ${desiredAudioDirection}`);\n            modifiedDirection = true;\n        }\n    } else {\n        logger.warn(`${this} No \"audio\" media found in the local description`);\n    }\n\n    const videoMedia = transformer.selectMedia(MediaType.VIDEO)?.[0];\n\n    if (videoMedia) {\n        const desiredVideoDirection = this.getDesiredMediaDirection(MediaType.VIDEO);\n\n        if (videoMedia.direction !== desiredVideoDirection) {\n            videoMedia.direction = desiredVideoDirection;\n            logger.info(`${this} Adjusted local video direction to ${desiredVideoDirection}`);\n            modifiedDirection = true;\n        }\n    } else {\n        logger.warn(`${this} No \"video\" media found in the local description`);\n    }\n\n    if (modifiedDirection) {\n        return new RTCSessionDescription({\n            type: localDescription.type,\n            sdp: transformer.toRawSDP()\n        });\n    }\n\n    return localDescription;\n};\n\n/**\n * Adjusts the media direction on the remote description based on availability of local and remote sources in a p2p\n * media connection.\n *\n * @param {RTCSessionDescription} remoteDescription the WebRTC session description instance for the remote description.\n * @returns the transformed remoteDescription.\n * @private\n */\nTraceablePeerConnection.prototype._adjustRemoteMediaDirection = function(remoteDescription) {\n    const transformer = new SdpTransformWrap(remoteDescription.sdp);\n\n    [ MediaType.AUDIO, MediaType.VIDEO ].forEach(mediaType => {\n        const media = transformer.selectMedia(mediaType);\n        const localSources = this.getLocalTracks(mediaType).length;\n        const remoteSources = this.getRemoteTracks(null, mediaType).length;\n\n        media.forEach((mLine, idx) => {\n            if (localSources && localSources === remoteSources) {\n                mLine.direction = MediaDirection.SENDRECV;\n            } else if (!localSources && !remoteSources) {\n                mLine.direction = MediaDirection.INACTIVE;\n            } else if (!localSources) {\n                mLine.direction = MediaDirection.SENDONLY;\n            } else if (!remoteSources) {\n                mLine.direction = MediaDirection.RECVONLY;\n\n            // When there are 2 local sources and 1 remote source, the first m-line should be set to 'sendrecv' while\n            // the second one needs to be set to 'recvonly'.\n            } else if (localSources > remoteSources) {\n                mLine.direction = idx ? MediaDirection.RECVONLY : MediaDirection.SENDRECV;\n\n            // When there are 2 remote sources and 1 local source, the first m-line should be set to 'sendrecv' while\n            // the second one needs to be set to 'sendonly'.\n            } else {\n                mLine.direction = idx ? MediaDirection.SENDONLY : MediaDirection.SENDRECV;\n            }\n        });\n    });\n\n    return new RTCSessionDescription({\n        type: remoteDescription.type,\n        sdp: transformer.toRawSDP()\n    });\n};\n\n/**\n * Munges the stereo flag as well as the opusMaxAverageBitrate in the SDP, based\n * on values set through config.js, if present.\n *\n * @param {RTCSessionDescription} description that needs to be munged.\n * @returns {RTCSessionDescription} the munged description.\n */\nTraceablePeerConnection.prototype._mungeOpus = function(description) {\n    const { audioQuality } = this.options;\n\n    if (!audioQuality?.enableOpusDtx && !audioQuality?.stereo && !audioQuality?.opusMaxAverageBitrate) {\n        return description;\n    }\n\n    const parsedSdp = transform.parse(description.sdp);\n    const mLines = parsedSdp.media;\n\n    for (const mLine of mLines) {\n        if (mLine.type === 'audio') {\n            const { payload } = mLine.rtp.find(protocol => protocol.codec === CodecMimeType.OPUS);\n\n            if (!payload) {\n                // eslint-disable-next-line no-continue\n                continue;\n            }\n\n            let fmtpOpus = mLine.fmtp.find(protocol => protocol.payload === payload);\n\n            if (!fmtpOpus) {\n                fmtpOpus = {\n                    payload,\n                    config: ''\n                };\n            }\n\n            const fmtpConfig = transform.parseParams(fmtpOpus.config);\n            let sdpChanged = false;\n\n            if (audioQuality?.stereo) {\n                fmtpConfig.stereo = 1;\n                sdpChanged = true;\n            }\n\n            if (audioQuality?.opusMaxAverageBitrate) {\n                fmtpConfig.maxaveragebitrate = audioQuality.opusMaxAverageBitrate;\n                sdpChanged = true;\n            }\n\n            // On Firefox, the OpusDtx enablement has no effect\n            if (!browser.isFirefox() && audioQuality?.enableOpusDtx) {\n                fmtpConfig.usedtx = 1;\n                sdpChanged = true;\n            }\n\n            if (!sdpChanged) {\n                // eslint-disable-next-line no-continue\n                continue;\n            }\n\n            let mungedConfig = '';\n\n            for (const key of Object.keys(fmtpConfig)) {\n                mungedConfig += `${key}=${fmtpConfig[key]}; `;\n            }\n\n            fmtpOpus.config = mungedConfig.trim();\n        }\n    }\n\n    return new RTCSessionDescription({\n        type: description.type,\n        sdp: transform.write(parsedSdp)\n    });\n};\n\n/**\n * Munges the SDP to set all directions to inactive and drop all ssrc and ssrc-groups.\n *\n * @param {RTCSessionDescription} description that needs to be munged.\n * @returns {RTCSessionDescription} the munged description.\n */\nTraceablePeerConnection.prototype._mungeInactive = function(description) {\n    const parsedSdp = transform.parse(description.sdp);\n    const mLines = parsedSdp.media;\n\n    for (const mLine of mLines) {\n        mLine.direction = MediaDirection.INACTIVE;\n        mLine.ssrcs = undefined;\n        mLine.ssrcGroups = undefined;\n    }\n\n    return new RTCSessionDescription({\n        type: description.type,\n        sdp: transform.write(parsedSdp)\n    });\n};\n\n/**\n * Sets up the _dtlsTransport object and initializes callbacks for it.\n */\nTraceablePeerConnection.prototype._initializeDtlsTransport = function() {\n    // We are assuming here that we only have one bundled transport here\n    if (!this.peerconnection.getSenders || this._dtlsTransport) {\n        return;\n    }\n\n    const senders = this.peerconnection.getSenders();\n\n    if (senders.length !== 0 && senders[0].transport) {\n        this._dtlsTransport = senders[0].transport;\n\n        this._dtlsTransport.onerror = error => {\n            logger.error(`${this} DtlsTransport error: ${error}`);\n        };\n\n        this._dtlsTransport.onstatechange = () => {\n            this.trace('dtlsTransport.onstatechange', this._dtlsTransport.state);\n        };\n    }\n};\n\n/**\n * Sets the max bitrates on the video m-lines when VP9 is the selected codec.\n *\n * @param {RTCSessionDescription} description - The local description that needs to be munged.\n * @param {boolean} isLocalSdp - Whether the max bitrate (via b=AS line in SDP) is set on local SDP.\n * @returns RTCSessionDescription\n */\nTraceablePeerConnection.prototype._setVp9MaxBitrates = function(description, isLocalSdp = false) {\n    const parsedSdp = transform.parse(description.sdp);\n\n    // Find all the m-lines associated with the local sources.\n    const direction = isLocalSdp ? MediaDirection.RECVONLY : MediaDirection.SENDONLY;\n    const mLines = parsedSdp.media.filter(m => m.type === MediaType.VIDEO && m.direction !== direction);\n\n    for (const mLine of mLines) {\n        if (this.codecSettings.preferred === CodecMimeType.VP9) {\n            const bitrates = this.tpcUtils.videoBitrates.VP9 || this.tpcUtils.videoBitrates;\n            const hdBitrate = bitrates.high ? bitrates.high : HD_BITRATE;\n            const ssHdBitrate = bitrates.ssHigh ? bitrates.ssHigh : HD_BITRATE;\n            const mid = mLine.mid;\n            const isSharingScreen = FeatureFlags.isMultiStreamSendSupportEnabled()\n                ? mid === this._getDesktopTrackMid()\n                : this._isSharingScreen();\n            const limit = Math.floor((isSharingScreen ? ssHdBitrate : hdBitrate) / 1000);\n\n            // Use only the HD bitrate for now as there is no API available yet for configuring\n            // the bitrates on the individual SVC layers.\n            mLine.bandwidth = [ {\n                type: 'AS',\n                limit\n            } ];\n        } else {\n            // Clear the bandwidth limit in SDP when VP9 is no longer the preferred codec.\n            // This is needed on react native clients as react-native-webrtc returns the\n            // SDP that the application passed instead of returning the SDP off the native side.\n            // This line automatically gets cleared on web on every renegotiation.\n            mLine.bandwidth = undefined;\n        }\n    }\n\n    return new RTCSessionDescription({\n        type: description.type,\n        sdp: transform.write(parsedSdp)\n    });\n};\n\n/**\n * Configures the stream encodings depending on the video type and the bitrates configured.\n *\n * @param {JitsiLocalTrack} - The local track for which the sender encodings have to configured.\n * @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.\n */\nTraceablePeerConnection.prototype.configureSenderVideoEncodings = function(localVideoTrack = null) {\n    // If media is suspended on the peerconnection, make sure that media stays disabled. The default 'active' state for\n    // the encodings after the source is added to the peerconnection is 'true', so it needs to be explicitly disabled\n    // after the source is added.\n    if (!(this.videoTransferActive && this.audioTransferActive)) {\n        return this.tpcUtils.setMediaTransferActive(false);\n    }\n\n    if (localVideoTrack) {\n        return this.setSenderVideoConstraints(\n            this._senderMaxHeights.get(localVideoTrack.getSourceName()),\n            localVideoTrack);\n    }\n    const promises = [];\n\n    for (const track of this.getLocalVideoTracks()) {\n        promises.push(this.setSenderVideoConstraints(this._senderMaxHeights.get(track.getSourceName()), track));\n    }\n\n    return Promise.allSettled(promises);\n};\n\nTraceablePeerConnection.prototype.setLocalDescription = function(description) {\n    let localDescription = description;\n\n    this.trace('setLocalDescription::preTransform', dumpSDP(localDescription));\n\n    // Munge stereo flag and opusMaxAverageBitrate based on config.js\n    localDescription = this._mungeOpus(localDescription);\n\n    if (!this._usesUnifiedPlan) {\n        localDescription = this._adjustLocalMediaDirection(localDescription);\n        localDescription = this._ensureSimulcastGroupIsLast(localDescription);\n    }\n\n    // Munge the order of the codecs based on the preferences set through config.js.\n    localDescription = this._mungeCodecOrder(localDescription);\n    localDescription = this._setVp9MaxBitrates(localDescription, true);\n\n    this.trace('setLocalDescription::postTransform', dumpSDP(localDescription));\n\n    return new Promise((resolve, reject) => {\n        this.peerconnection.setLocalDescription(localDescription)\n            .then(() => {\n                this.trace('setLocalDescriptionOnSuccess');\n                const localUfrag = SDPUtil.getUfrag(localDescription.sdp);\n\n                if (localUfrag !== this.localUfrag) {\n                    this.localUfrag = localUfrag;\n                    this.eventEmitter.emit(RTCEvents.LOCAL_UFRAG_CHANGED, this, localUfrag);\n                }\n\n                this._initializeDtlsTransport();\n\n                resolve();\n            }, err => {\n                this.trace('setLocalDescriptionOnFailure', err);\n                this.eventEmitter.emit(RTCEvents.SET_LOCAL_DESCRIPTION_FAILED, err, this);\n                reject(err);\n            });\n    });\n};\n\nTraceablePeerConnection.prototype.setRemoteDescription = function(description) {\n    let remoteDescription = description;\n\n    this.trace('setRemoteDescription::preTransform', dumpSDP(description));\n\n    // Munge stereo flag and opusMaxAverageBitrate based on config.js\n    remoteDescription = this._mungeOpus(remoteDescription);\n\n    if (this._usesUnifiedPlan) {\n        // Translate the SDP to Unified plan format first for the jvb case, p2p case will only have 2 m-lines.\n        if (!this.isP2P) {\n            const currentDescription = this.peerconnection.remoteDescription;\n\n            remoteDescription = this.interop.toUnifiedPlan(remoteDescription, currentDescription);\n            this.trace('setRemoteDescription::postTransform (Unified)', dumpSDP(remoteDescription));\n        }\n        if (this.isSimulcastOn()) {\n            remoteDescription = this.tpcUtils.insertUnifiedPlanSimulcastReceive(remoteDescription);\n            this.trace('setRemoteDescription::postTransform (sim receive)', dumpSDP(remoteDescription));\n        }\n        remoteDescription = this.tpcUtils.ensureCorrectOrderOfSsrcs(remoteDescription);\n        this.trace('setRemoteDescription::postTransform (correct ssrc order)', dumpSDP(remoteDescription));\n    } else {\n        if (this.isSimulcastOn()) {\n            // Implode the simulcast ssrcs so that the remote sdp has only the first ssrc in the SIM group.\n            remoteDescription = this.simulcast.mungeRemoteDescription(\n                remoteDescription,\n                true /* add x-google-conference flag */);\n            this.trace('setRemoteDescription::postTransform (simulcast)', dumpSDP(remoteDescription));\n        }\n        remoteDescription = normalizePlanB(remoteDescription);\n    }\n\n    // Munge the order of the codecs based on the preferences set through config.js.\n    remoteDescription = this._mungeCodecOrder(remoteDescription);\n    remoteDescription = this._setVp9MaxBitrates(remoteDescription);\n    this.trace('setRemoteDescription::postTransform (munge codec order)', dumpSDP(remoteDescription));\n\n    return new Promise((resolve, reject) => {\n        this.peerconnection.setRemoteDescription(remoteDescription)\n            .then(() => {\n                this.trace('setRemoteDescriptionOnSuccess');\n                const remoteUfrag = SDPUtil.getUfrag(remoteDescription.sdp);\n\n                if (remoteUfrag !== this.remoteUfrag) {\n                    this.remoteUfrag = remoteUfrag;\n                    this.eventEmitter.emit(RTCEvents.REMOTE_UFRAG_CHANGED, this, remoteUfrag);\n                }\n\n                this._initializeDtlsTransport();\n\n                resolve();\n            }, err => {\n                this.trace('setRemoteDescriptionOnFailure', err);\n                this.eventEmitter.emit(RTCEvents.SET_REMOTE_DESCRIPTION_FAILED, err, this);\n                reject(err);\n            });\n    });\n};\n\n/**\n * Changes the resolution of the video stream that is sent to the peer based on the resolution requested by the peer\n * and user preference, sets the degradation preference on the sender based on the video type, configures the maximum\n * bitrates on the send stream.\n *\n * @param {number} frameHeight - The max frame height to be imposed on the outgoing video stream.\n * @param {JitsiLocalTrack} - The local track for which the sender constraints have to be applied.\n * @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.\n */\nTraceablePeerConnection.prototype.setSenderVideoConstraints = function(frameHeight, localVideoTrack) {\n    if (frameHeight < 0) {\n        throw new Error(`Invalid frameHeight: ${frameHeight}`);\n    }\n    if (!localVideoTrack) {\n        throw new Error('Local video track is missing');\n    }\n    const sourceName = localVideoTrack.getSourceName();\n\n    // Ignore sender constraints if the media on the peerconnection is suspended (jvb conn when p2p is currently active)\n    // or if the video track is muted.\n    if (!this.videoTransferActive || localVideoTrack.isMuted()) {\n        this._senderMaxHeights.set(sourceName, frameHeight);\n\n        return Promise.resolve();\n    }\n\n    const configuredResolution = this.tpcUtils.getConfiguredEncodeResolution(localVideoTrack);\n\n    // Ignore sender constraints if the client is already sending video of the requested resolution. Note that for\n    // screensharing sources, the max resolution will be the height of the window being captured irrespective of the\n    // height being requested by the peer.\n    if ((localVideoTrack.getVideoType() === VideoType.CAMERA && configuredResolution === frameHeight)\n        || (localVideoTrack.getVideoType() === VideoType.DESKTOP\n            && frameHeight > 0\n            && configuredResolution === localVideoTrack.getTrack()?.getSettings()?.height)) {\n        return Promise.resolve();\n    }\n\n    this._senderMaxHeights.set(sourceName, frameHeight);\n\n    return this._updateVideoSenderParameters(this._updateVideoSenderEncodings(frameHeight, localVideoTrack));\n};\n\n/**\n * Returns a wrapped-up promise so that the setParameters() call on the RTCRtpSender for video sources are chained.\n * This is needed on Chrome as it resets the transaction id after executing setParameters() and can affect the next on\n * the fly updates if they are not chained.\n * https://chromium.googlesource.com/external/webrtc/+/master/pc/rtp_sender.cc#340\n * @param {Promise} promise - The promise that needs to be chained.\n * @returns {Promise}\n */\nTraceablePeerConnection.prototype._updateVideoSenderParameters = function(promise) {\n    const nextPromise = this._lastVideoSenderUpdatePromise\n        .finally(() => promise);\n\n    this._lastVideoSenderUpdatePromise = nextPromise;\n\n    return nextPromise;\n};\n\n/**\n * Configures the video stream with resolution / degradation / maximum bitrates\n *\n * @param {number} frameHeight - The max frame height to be imposed on the outgoing video stream.\n * @param {JitsiLocalTrack} - The local track for which the sender constraints have to be applied.\n * @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.\n */\nTraceablePeerConnection.prototype._updateVideoSenderEncodings = function(frameHeight, localVideoTrack) {\n    const videoSender = this.findSenderForTrack(localVideoTrack.getTrack());\n\n    if (!videoSender) {\n        return Promise.resolve();\n    }\n    const parameters = videoSender.getParameters();\n\n    if (!parameters?.encodings?.length) {\n        return Promise.resolve();\n    }\n\n    const isSharingLowFpsScreen = localVideoTrack.getVideoType() === VideoType.DESKTOP && this._capScreenshareBitrate;\n\n    // Set the degradation preference.\n    const preference = isSharingLowFpsScreen\n        ? DEGRADATION_PREFERENCE_DESKTOP // Prefer resolution for low fps share.\n        : DEGRADATION_PREFERENCE_CAMERA; // Prefer frame-rate for high fps share and camera.\n\n    parameters.degradationPreference = preference;\n    logger.info(`${this} Setting degradation preference [preference=${preference},track=${localVideoTrack}`);\n\n    // Calculate the encodings active state based on the resolution requested by the bridge.\n    this.encodingsEnabledState = this.tpcUtils.calculateEncodingsActiveState(localVideoTrack, frameHeight);\n    const maxBitrates = this.tpcUtils.calculateEncodingsBitrates(localVideoTrack);\n    const videoType = localVideoTrack.getVideoType();\n\n    if (this.isSimulcastOn()) {\n        for (const encoding in parameters.encodings) {\n            if (parameters.encodings.hasOwnProperty(encoding)) {\n                parameters.encodings[encoding].active = this.encodingsEnabledState[encoding];\n\n                // Firefox doesn't follow the spec and lets application specify the degradation preference on the\n                // encodings.\n                browser.isFirefox() && (parameters.encodings[encoding].degradationPreference = preference);\n\n                if (this.getConfiguredVideoCodec() === CodecMimeType.VP8\n                    && (this.options?.videoQuality?.maxBitratesVideo\n                        || isSharingLowFpsScreen\n                        || this._usesUnifiedPlan)) {\n                    parameters.encodings[encoding].maxBitrate = maxBitrates[encoding];\n                }\n            }\n        }\n        this.tpcUtils.updateEncodingsResolution(localVideoTrack, parameters);\n\n    // For p2p and cases and where simulcast is explicitly disabled.\n    } else if (frameHeight > 0) {\n        let scaleFactor = HD_SCALE_FACTOR;\n\n        // Do not scale down encodings for desktop tracks for non-simulcast case.\n        if (videoType === VideoType.CAMERA && localVideoTrack.resolution > frameHeight) {\n            scaleFactor = Math.floor(localVideoTrack.resolution / frameHeight);\n        }\n\n        parameters.encodings[0].active = true;\n        parameters.encodings[0].scaleResolutionDownBy = scaleFactor;\n\n        // Firefox doesn't follow the spec and lets application specify the degradation preference on the encodings.\n        browser.isFirefox() && (parameters.encodings[0].degradationPreference = preference);\n\n        // Configure the bitrate.\n        if (this.getConfiguredVideoCodec() === CodecMimeType.VP8 && this.options?.videoQuality?.maxBitratesVideo) {\n            let bitrate = this.getTargetVideoBitrates()?.high;\n\n            if (videoType === VideoType.CAMERA) {\n                bitrate = this.tpcUtils._getVideoStreamEncodings(localVideoTrack.getVideoType())\n                    .find(layer => layer.scaleResolutionDownBy === scaleFactor)?.maxBitrate ?? bitrate;\n            }\n            parameters.encodings[0].maxBitrate = bitrate;\n        } else {\n            parameters.encodings[0].maxBitrate = undefined;\n        }\n    } else {\n        parameters.encodings[0].active = false;\n    }\n\n    logger.info(`${this} setting max height=${frameHeight},encodings=${JSON.stringify(parameters.encodings)}`);\n\n    return videoSender.setParameters(parameters).then(() => {\n        localVideoTrack.maxEnabledResolution = frameHeight;\n        this.eventEmitter.emit(RTCEvents.LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED, localVideoTrack);\n    });\n};\n\n/**\n * Enables/disables video media transmission on this peer connection. When\n * disabled the SDP video media direction in the local SDP will be adjusted to\n * 'inactive' which means that no data will be sent nor accepted, but\n * the connection should be kept alive.\n * @param {boolean} active <tt>true</tt> to enable video media transmission or\n * <tt>false</tt> to disable. If the value is not a boolean the call will have\n * no effect.\n * @return {boolean} <tt>true</tt> if the value has changed and sRD/sLD cycle\n * needs to be executed in order for the changes to take effect or\n * <tt>false</tt> if the given value was the same as the previous one.\n * @public\n */\nTraceablePeerConnection.prototype.setVideoTransferActive = function(active) {\n    logger.debug(`${this} video transfer active: ${active}`);\n    const changed = this.videoTransferActive !== active;\n\n    this.videoTransferActive = active;\n\n    if (this._usesUnifiedPlan) {\n        this.tpcUtils.setVideoTransferActive(active);\n\n        // false means no renegotiation up the chain which is not needed in the Unified mode\n        return false;\n    }\n\n    return changed;\n};\n\n/**\n * Sends DTMF tones if possible.\n *\n * @param {string} tones - The DTMF tones string as defined by {@code RTCDTMFSender.insertDTMF}, 'tones' argument.\n * @param {number} duration - The amount of time in milliseconds that each DTMF should last. It's 200ms by default.\n * @param {number} interToneGap - The length of time in miliseconds to wait between tones. It's 200ms by default.\n *\n * @returns {void}\n */\nTraceablePeerConnection.prototype.sendTones = function(tones, duration = 200, interToneGap = 200) {\n    if (!this._dtmfSender) {\n        if (this.peerconnection.getSenders) {\n            const rtpSender = this.peerconnection.getSenders().find(s => s.dtmf);\n\n            this._dtmfSender = rtpSender && rtpSender.dtmf;\n            this._dtmfSender && logger.info(`${this} initialized DTMFSender using getSenders`);\n        }\n\n        if (!this._dtmfSender) {\n            const localAudioTrack = Array.from(this.localTracks.values()).find(t => t.isAudioTrack());\n\n            if (this.peerconnection.createDTMFSender && localAudioTrack) {\n                this._dtmfSender = this.peerconnection.createDTMFSender(localAudioTrack.getTrack());\n            }\n            this._dtmfSender && logger.info(`${this} initialized DTMFSender using deprecated createDTMFSender`);\n        }\n\n        if (this._dtmfSender) {\n            this._dtmfSender.ontonechange = this._onToneChange.bind(this);\n        }\n    }\n\n    if (this._dtmfSender) {\n        if (this._dtmfSender.toneBuffer) {\n            this._dtmfTonesQueue.push({\n                tones,\n                duration,\n                interToneGap\n            });\n\n            return;\n        }\n\n        this._dtmfSender.insertDTMF(tones, duration, interToneGap);\n    } else {\n        logger.warn(`${this} sendTones - failed to select DTMFSender`);\n    }\n};\n\n/**\n * Callback ivoked by {@code this._dtmfSender} when it has finished playing\n * a single tone.\n *\n * @param {Object} event - The tonechange event which indicates what characters\n * are left to be played for the current tone.\n * @private\n * @returns {void}\n */\nTraceablePeerConnection.prototype._onToneChange = function(event) {\n    // An empty event.tone indicates the current tones have finished playing.\n    // Automatically start playing any queued tones on finish.\n    if (this._dtmfSender && event.tone === '' && this._dtmfTonesQueue.length) {\n        const { tones, duration, interToneGap } = this._dtmfTonesQueue.shift();\n\n        this._dtmfSender.insertDTMF(tones, duration, interToneGap);\n    }\n};\n\n/**\n * Makes the underlying TraceablePeerConnection generate new SSRC for\n * the recvonly video stream.\n */\nTraceablePeerConnection.prototype.generateRecvonlySsrc = function() {\n    const newSSRC = SDPUtil.generateSsrc();\n\n    logger.info(`${this} generated new recvonly SSRC=${newSSRC}`);\n    this.sdpConsistency.setPrimarySsrc(newSSRC);\n};\n\n/**\n * Makes the underlying TraceablePeerConnection forget the current primary video\n * SSRC.\n */\nTraceablePeerConnection.prototype.clearRecvonlySsrc = function() {\n    logger.info(`${this} Clearing primary video SSRC!`);\n    this.sdpConsistency.clearVideoSsrcCache();\n};\n\n/**\n * Closes underlying WebRTC PeerConnection instance and removes all remote\n * tracks by emitting {@link RTCEvents.REMOTE_TRACK_REMOVED} for each one of\n * them.\n */\nTraceablePeerConnection.prototype.close = function() {\n    this.trace('stop');\n\n    // Off SignalingEvents\n    this.signalingLayer.off(SignalingEvents.PEER_MUTED_CHANGED, this._peerMutedChanged);\n    this.signalingLayer.off(SignalingEvents.PEER_VIDEO_TYPE_CHANGED, this._peerVideoTypeChanged);\n    this._usesUnifiedPlan && this.peerconnection.removeEventListener('track', this.onTrack);\n\n    for (const peerTracks of this.remoteTracks.values()) {\n        for (const remoteTracks of peerTracks.values()) {\n            for (const remoteTrack of remoteTracks) {\n                this._removeRemoteTrack(remoteTrack);\n            }\n        }\n    }\n    this.remoteTracks.clear();\n\n    this._addedStreams = [];\n\n    this._dtmfSender = null;\n    this._dtmfTonesQueue = [];\n\n    if (!this.rtc._removePeerConnection(this)) {\n        logger.error(`${this} RTC._removePeerConnection returned false`);\n    }\n    if (this.statsinterval !== null) {\n        window.clearInterval(this.statsinterval);\n        this.statsinterval = null;\n    }\n    logger.info(`${this} Closing peerconnection`);\n    this.peerconnection.close();\n};\n\nTraceablePeerConnection.prototype.createAnswer = function(constraints) {\n    return this._createOfferOrAnswer(false /* answer */, constraints);\n};\n\nTraceablePeerConnection.prototype.createOffer = function(constraints) {\n    return this._createOfferOrAnswer(true /* offer */, constraints);\n};\n\nTraceablePeerConnection.prototype._createOfferOrAnswer = function(\n        isOffer,\n        constraints) {\n    const logName = isOffer ? 'Offer' : 'Answer';\n\n    this.trace(`create${logName}`, JSON.stringify(constraints, null, ' '));\n\n    const handleSuccess = (resultSdp, resolveFn, rejectFn) => {\n        try {\n            this.trace(\n                `create${logName}OnSuccess::preTransform`, dumpSDP(resultSdp));\n\n            if (!this._usesUnifiedPlan) {\n                // If there are no local video tracks, then a \"recvonly\"\n                // SSRC needs to be generated\n                if (!this.hasAnyTracksOfType(MediaType.VIDEO)\n                    && !this.sdpConsistency.hasPrimarySsrcCached()) {\n                    this.generateRecvonlySsrc();\n                }\n\n                // eslint-disable-next-line no-param-reassign\n                resultSdp = new RTCSessionDescription({\n                    type: resultSdp.type,\n                    sdp: this.sdpConsistency.makeVideoPrimarySsrcsConsistent(\n                        resultSdp.sdp)\n                });\n\n                this.trace(\n                    `create${logName}OnSuccess::postTransform `\n                         + '(make primary audio/video ssrcs consistent)',\n                    dumpSDP(resultSdp));\n            }\n\n            const localVideoTrack = this.getLocalVideoTracks()[0];\n\n            // Configure simulcast for camera tracks and for desktop tracks that need simulcast.\n            if (this.isSimulcastOn() && browser.usesSdpMungingForSimulcast()\n                && (localVideoTrack?.getVideoType() === VideoType.CAMERA\n                || this._usesUnifiedPlan)) {\n                // eslint-disable-next-line no-param-reassign\n                resultSdp = this.simulcast.mungeLocalDescription(resultSdp);\n                this.trace(`create${logName} OnSuccess::postTransform (simulcast)`, dumpSDP(resultSdp));\n            }\n\n            if (!this.options.disableRtx && browser.usesSdpMungingForSimulcast()) {\n                // eslint-disable-next-line no-param-reassign\n                resultSdp = new RTCSessionDescription({\n                    type: resultSdp.type,\n                    sdp: this.rtxModifier.modifyRtxSsrcs(resultSdp.sdp)\n                });\n\n                this.trace(\n                    `create${logName}`\n                         + 'OnSuccess::postTransform (rtx modifier)',\n                    dumpSDP(resultSdp));\n            }\n\n            const ssrcMap = this._extractSSRCMap(resultSdp);\n\n            this._processLocalSSRCsMap(ssrcMap);\n\n            resolveFn(resultSdp);\n        } catch (e) {\n            this.trace(`create${logName}OnError`, e);\n            this.trace(`create${logName}OnError`, dumpSDP(resultSdp));\n            logger.error(`${this} create${logName}OnError`, e, dumpSDP(resultSdp));\n\n            rejectFn(e);\n        }\n    };\n\n    const handleFailure = (err, rejectFn) => {\n        this.trace(`create${logName}OnFailure`, err);\n        const eventType\n            = isOffer\n                ? RTCEvents.CREATE_OFFER_FAILED\n                : RTCEvents.CREATE_ANSWER_FAILED;\n\n        this.eventEmitter.emit(eventType, err, this);\n\n        rejectFn(err);\n    };\n\n    // Set the codec preference before creating an offer or answer so that the generated SDP will have\n    // the correct preference order.\n    if (this._usesTransceiverCodecPreferences) {\n        const { mediaType } = this.codecSettings;\n        const transceivers = this.peerconnection.getTransceivers()\n            .filter(t => t.receiver && t.receiver?.track?.kind === mediaType);\n\n        if (transceivers.length) {\n            let capabilities = RTCRtpReceiver.getCapabilities(mediaType)?.codecs;\n            const disabledCodecMimeType = this.codecSettings?.disabled;\n            const preferredCodecMimeType = this.codecSettings?.preferred;\n\n            if (capabilities && disabledCodecMimeType) {\n                capabilities = capabilities\n                    .filter(caps => caps.mimeType.toLowerCase() !== `${mediaType}/${disabledCodecMimeType}`);\n            }\n\n            if (capabilities && preferredCodecMimeType) {\n                // Move the desired codec (all variations of it as well) to the beginning of the list.\n                /* eslint-disable-next-line arrow-body-style */\n                capabilities.sort(caps => {\n                    return caps.mimeType.toLowerCase() === `${mediaType}/${preferredCodecMimeType}` ? -1 : 1;\n                });\n            }\n\n            // Disable ulpfec on Google Chrome and derivatives because\n            // https://bugs.chromium.org/p/chromium/issues/detail?id=1276427\n            if (browser.isChromiumBased() && mediaType === MediaType.VIDEO) {\n                capabilities = capabilities\n                    .filter(caps => caps.mimeType.toLowerCase() !== `${MediaType.VIDEO}/${CodecMimeType.ULPFEC}`);\n            }\n\n            // Apply codec preference to all the transceivers associated with the given media type.\n            for (const transceiver of transceivers) {\n                transceiver.setCodecPreferences(capabilities);\n            }\n        }\n    }\n\n    return new Promise((resolve, reject) => {\n        let oaPromise;\n\n        if (isOffer) {\n            oaPromise = this.peerconnection.createOffer(constraints);\n        } else {\n            oaPromise = this.peerconnection.createAnswer(constraints);\n        }\n\n        oaPromise\n            .then(\n                sdp => handleSuccess(sdp, resolve, reject),\n                error => handleFailure(error, reject));\n    });\n};\n\n/**\n * Extract primary SSRC from given {@link TrackSSRCInfo} object.\n * @param {TrackSSRCInfo} ssrcObj\n * @return {number|null} the primary SSRC or <tt>null</tt>\n */\nTraceablePeerConnection.prototype._extractPrimarySSRC = function(ssrcObj) {\n    if (ssrcObj && ssrcObj.groups && ssrcObj.groups.length) {\n        return ssrcObj.groups[0].ssrcs[0];\n    } else if (ssrcObj && ssrcObj.ssrcs && ssrcObj.ssrcs.length) {\n        return ssrcObj.ssrcs[0];\n    }\n\n    return null;\n};\n\n/**\n * Goes over the SSRC map extracted from the latest local description and tries\n * to match them with the local tracks (by MSID). Will update the values\n * currently stored in the {@link TraceablePeerConnection.localSSRCs} map.\n * @param {Map<string,TrackSSRCInfo>} ssrcMap\n * @private\n */\nTraceablePeerConnection.prototype._processLocalSSRCsMap = function(ssrcMap) {\n    for (const track of this.localTracks.values()) {\n        const sourceName = track.getSourceName();\n        const sourceIndex = getSourceIndexFromSourceName(sourceName);\n        const sourceIdentifier = this._usesUnifiedPlan\n            ? `${track.getType()}-${sourceIndex}`\n            : track.storedMSID;\n\n        if (ssrcMap.has(sourceIdentifier)) {\n            const newSSRC = ssrcMap.get(sourceIdentifier);\n\n            if (!newSSRC) {\n                logger.error(`${this} No SSRC found for stream=${sourceIdentifier}`);\n\n                return;\n            }\n            const oldSSRC = this.localSSRCs.get(track.rtcId);\n            const newSSRCNum = this._extractPrimarySSRC(newSSRC);\n            const oldSSRCNum = this._extractPrimarySSRC(oldSSRC);\n\n            // eslint-disable-next-line no-negated-condition\n            if (newSSRCNum !== oldSSRCNum) {\n                oldSSRCNum && logger.error(`${this} Overwriting SSRC for track=${track}] with ssrc=${newSSRC}`);\n                this.localSSRCs.set(track.rtcId, newSSRC);\n                this.eventEmitter.emit(RTCEvents.LOCAL_TRACK_SSRC_UPDATED, track, newSSRCNum);\n            }\n        } else if (!track.isVideoTrack() && !track.isMuted()) {\n            // It is normal to find no SSRCs for a muted video track in\n            // the local SDP as the recv-only SSRC is no longer munged in.\n            // So log the warning only if it's not a muted video track.\n            logger.warn(`${this} No SSRCs found in the local SDP for track=${track}, stream=${sourceIdentifier}`);\n        }\n    }\n};\n\n/**\n * Track the SSRCs seen so far.\n * @param {number} ssrc - SSRC.\n * @return {boolean} - Whether this is a new SSRC.\n */\nTraceablePeerConnection.prototype.addRemoteSsrc = function(ssrc) {\n    const existing = this.remoteSSRCs.has(ssrc);\n\n    if (!existing) {\n        this.remoteSSRCs.add(ssrc);\n    }\n\n    return !existing;\n};\n\nTraceablePeerConnection.prototype.addIceCandidate = function(candidate) {\n    this.trace('addIceCandidate', JSON.stringify({\n        candidate: candidate.candidate,\n        sdpMid: candidate.sdpMid,\n        sdpMLineIndex: candidate.sdpMLineIndex,\n        usernameFragment: candidate.usernameFragment\n    }, null, ' '));\n\n    return this.peerconnection.addIceCandidate(candidate);\n};\n\n/**\n * Returns the number of simulcast streams that are currently enabled on the peerconnection.\n *\n * @returns {number} The number of simulcast streams currently enabled or 1 when simulcast is disabled.\n */\nTraceablePeerConnection.prototype.getActiveSimulcastStreams = function() {\n    let activeStreams = 1;\n\n    if (this.isSimulcastOn() && this.encodingsEnabledState) {\n        activeStreams = this.encodingsEnabledState.filter(stream => Boolean(stream))?.length;\n    } else if (this.isSimulcastOn()) {\n        activeStreams = SIM_LAYER_RIDS.length;\n    }\n\n    return activeStreams;\n};\n\n/**\n * Obtains call-related stats from the peer connection.\n *\n * @returns {Promise<Object>} Promise which resolves with data providing statistics about\n * the peerconnection.\n */\nTraceablePeerConnection.prototype.getStats = function() {\n    return this.peerconnection.getStats();\n};\n\n/**\n * Generates and stores new SSRC info object for given local track.\n * The method should be called only for a video track being added to this TPC\n * in the muted state (given that the current browser uses this strategy).\n * @param {JitsiLocalTrack} track\n * @return {TPCSSRCInfo}\n */\nTraceablePeerConnection.prototype.generateNewStreamSSRCInfo = function(track) {\n    const rtcId = track.rtcId;\n    let ssrcInfo = this._getSSRC(rtcId);\n\n    if (ssrcInfo) {\n        logger.error(`${this} Overwriting local SSRCs for track id=${rtcId}`);\n    }\n\n    // Configure simulcast for camera tracks and desktop tracks that need simulcast.\n    if (this.isSimulcastOn()\n        && (track.getVideoType() === VideoType.CAMERA || !this.isSharingLowFpsScreen())) {\n        ssrcInfo = {\n            ssrcs: [],\n            groups: []\n        };\n        for (let i = 0; i < SIM_LAYER_RIDS.length; i++) {\n            ssrcInfo.ssrcs.push(SDPUtil.generateSsrc());\n        }\n        ssrcInfo.groups.push({\n            ssrcs: ssrcInfo.ssrcs.slice(),\n            semantics: 'SIM'\n        });\n    } else {\n        ssrcInfo = {\n            ssrcs: [ SDPUtil.generateSsrc() ],\n            groups: []\n        };\n    }\n    if (!this.options.disableRtx) {\n        // Specifically use a for loop here because we'll\n        //  be adding to the list we're iterating over, so we\n        //  only want to iterate through the items originally\n        //  on the list\n        const currNumSsrcs = ssrcInfo.ssrcs.length;\n\n        for (let i = 0; i < currNumSsrcs; ++i) {\n            const primarySsrc = ssrcInfo.ssrcs[i];\n            const rtxSsrc = SDPUtil.generateSsrc();\n\n            ssrcInfo.ssrcs.push(rtxSsrc);\n            ssrcInfo.groups.push({\n                ssrcs: [ primarySsrc, rtxSsrc ],\n                semantics: 'FID'\n            });\n        }\n    }\n    ssrcInfo.msid = track.storedMSID;\n    this.localSSRCs.set(rtcId, ssrcInfo);\n\n    return ssrcInfo;\n};\n\n/**\n * Returns if the peer connection uses Unified plan implementation.\n *\n * @returns {boolean} True if the pc uses Unified plan, false otherwise.\n */\nTraceablePeerConnection.prototype.usesUnifiedPlan = function() {\n    return this._usesUnifiedPlan;\n};\n\n/**\n * Creates a text representation of this <tt>TraceablePeerConnection</tt>\n * instance.\n * @return {string}\n */\nTraceablePeerConnection.prototype.toString = function() {\n    return `TPC[id=${this.id},type=${this.isP2P ? 'P2P' : 'JVB'}]`;\n};\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport browser from '../browser';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\nimport Listenable from '../util/Listenable';\nimport { safeCounterIncrement } from '../util/MathUtil';\n\nimport BridgeChannel from './BridgeChannel';\nimport JitsiLocalTrack from './JitsiLocalTrack';\nimport RTCUtils from './RTCUtils';\nimport TraceablePeerConnection from './TraceablePeerConnection';\n\n\nconst logger = getLogger(__filename);\n\n/**\n * The counter used to generated id numbers assigned to peer connections\n * @type {number}\n */\nlet peerConnectionIdCounter = 0;\n\n/**\n * The counter used to generate id number for the local\n * <code>MediaStreamTrack</code>s.\n * @type {number}\n */\nlet rtcTrackIdCounter = 0;\n\n/**\n * Creates {@code JitsiLocalTrack} instances from the passed in meta information\n * about MedieaTracks.\n *\n * @param {Object[]} mediaStreamMetaData - An array of meta information with\n * MediaTrack instances. Each can look like:\n * {{\n *     stream: MediaStream instance that holds a track with audio or video,\n *     track: MediaTrack within the MediaStream,\n *     videoType: \"camera\" or \"desktop\" or falsy,\n *     sourceId: ID of the desktopsharing source,\n *     sourceType: The desktopsharing source type,\n *     effects: Array of effect types\n * }}\n */\nfunction _createLocalTracks(mediaStreamMetaData = []) {\n    return mediaStreamMetaData.map(metaData => {\n        const {\n            sourceId,\n            sourceType,\n            stream,\n            track,\n            videoType,\n            effects\n        } = metaData;\n\n        const { deviceId, facingMode } = track.getSettings();\n\n        // FIXME Move rtcTrackIdCounter to a static method in JitsiLocalTrack\n        // so RTC does not need to handle ID management. This move would be\n        // safer to do once the old createLocalTracks is removed.\n        rtcTrackIdCounter = safeCounterIncrement(rtcTrackIdCounter);\n\n        return new JitsiLocalTrack({\n            deviceId,\n            facingMode,\n            mediaType: track.kind,\n            rtcId: rtcTrackIdCounter,\n            sourceId,\n            sourceType,\n            stream,\n            track,\n            videoType: videoType || null,\n            effects\n        });\n    });\n}\n\n/**\n *\n */\nexport default class RTC extends Listenable {\n    /**\n     *\n     * @param conference\n     * @param options\n     */\n    constructor(conference, options = {}) {\n        super();\n        this.conference = conference;\n\n        /**\n         * A map of active <tt>TraceablePeerConnection</tt>.\n         * @type {Map.<number, TraceablePeerConnection>}\n         */\n        this.peerConnections = new Map();\n\n        this.localTracks = [];\n\n        this.options = options;\n\n        // BridgeChannel instance.\n        // @private\n        // @type {BridgeChannel}\n        this._channel = null;\n\n        /**\n         * The value specified to the last invocation of setLastN before the\n         * channel completed opening. If non-null, the value will be sent\n         * through a channel (once) as soon as it opens and will then be\n         * discarded.\n         * @private\n         * @type {number}\n         */\n        this._lastN = undefined;\n\n        /**\n         * Defines the forwarded sources list. It can be null or an array once initialised with a channel forwarded\n         * sources event.\n         *\n         * @type {Array<string>|null}\n         * @private\n         */\n        this._forwardedSources = null;\n\n        // The forwarded sources change listener.\n        this._forwardedSourcesChangeListener = this._onForwardedSourcesChanged.bind(this);\n\n        this._onDeviceListChanged = this._onDeviceListChanged.bind(this);\n        this._updateAudioOutputForAudioTracks = this._updateAudioOutputForAudioTracks.bind(this);\n\n        // Switch audio output device on all remote audio tracks. Local audio\n        // tracks handle this event by themselves.\n        if (RTCUtils.isDeviceChangeAvailable('output')) {\n            RTCUtils.addListener(\n                RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\n                this._updateAudioOutputForAudioTracks\n            );\n\n            RTCUtils.addListener(\n                RTCEvents.DEVICE_LIST_CHANGED,\n                this._onDeviceListChanged\n            );\n        }\n    }\n\n    /**\n     * Removes any listeners and stored state from this {@code RTC} instance.\n     *\n     * @returns {void}\n     */\n    destroy() {\n        RTCUtils.removeListener(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED, this._updateAudioOutputForAudioTracks);\n        RTCUtils.removeListener(RTCEvents.DEVICE_LIST_CHANGED, this._onDeviceListChanged);\n\n        if (this._channelOpenListener) {\n            this.removeListener(RTCEvents.DATA_CHANNEL_OPEN, this._channelOpenListener);\n        }\n    }\n\n    /**\n     * Exposes the private helper for converting a WebRTC MediaStream to a\n     * JitsiLocalTrack.\n     *\n     * @param {Array<Object>} tracksInfo\n     * @returns {Array<JitsiLocalTrack>}\n     */\n    static createLocalTracks(tracksInfo) {\n        return _createLocalTracks(tracksInfo);\n    }\n\n    /**\n     * Creates the local MediaStreams.\n     * @param {object} [options] Optional parameters.\n     * @param {Array=} options.devices The devices that will be requested.\n     * @param {string=} options.resolution Resolution constraints.\n     * @param {string=} options.cameraDeviceId\n     * @param {string=} options.micDeviceId\n     * @returns {*} Promise object that will receive the new JitsiTracks\n     */\n    static obtainAudioAndVideoPermissions(options) {\n        return RTCUtils.obtainAudioAndVideoPermissions(options)\n            .then(tracksInfo => _createLocalTracks(tracksInfo));\n    }\n\n    /**\n     * Initializes the bridge channel of this instance.\n     * At least one of both, peerconnection or wsUrl parameters, must be\n     * given.\n     * @param {RTCPeerConnection} [peerconnection] WebRTC peer connection\n     * instance.\n     * @param {string} [wsUrl] WebSocket URL.\n     */\n    initializeBridgeChannel(peerconnection, wsUrl) {\n        this._channel = new BridgeChannel(peerconnection, wsUrl, this.eventEmitter, this.conference);\n\n        this._channelOpenListener = () => {\n            const logError = (error, msgType, value) => {\n                GlobalOnErrorHandler.callErrorHandler(error);\n                logger.error(`Cannot send ${msgType}(${JSON.stringify(value)}) endpoint message`, error);\n            };\n\n            // When the channel becomes available, tell the bridge about video selections so that it can do adaptive\n            // simulcast, we want the notification to trigger even if userJid is undefined, or null.\n            if (this._receiverVideoConstraints) {\n                try {\n                    this._channel.sendReceiverVideoConstraintsMessage(this._receiverVideoConstraints);\n                } catch (error) {\n                    logError(error, 'ReceiverVideoConstraints', this._receiverVideoConstraints);\n                }\n            }\n            if (typeof this._lastN !== 'undefined' && this._lastN !== -1) {\n                try {\n                    this._channel.sendSetLastNMessage(this._lastN);\n                } catch (error) {\n                    logError(error, 'LastNChangedEvent', this._lastN);\n                }\n            }\n        };\n        this.addListener(RTCEvents.DATA_CHANNEL_OPEN, this._channelOpenListener);\n\n        // Add forwarded sources change listener.\n        this.addListener(RTCEvents.FORWARDED_SOURCES_CHANGED, this._forwardedSourcesChangeListener);\n    }\n\n    /**\n     * Callback invoked when the list of known audio and video devices has\n     * been updated. Attempts to update the known available audio output\n     * devices.\n     *\n     * @private\n     * @returns {void}\n     */\n    _onDeviceListChanged() {\n        this._updateAudioOutputForAudioTracks(RTCUtils.getAudioOutputDevice());\n    }\n\n    /**\n     * Receives events when forwarded sources had changed.\n     *\n     * @param {array} forwardedSources The new forwarded sources.\n     * @private\n     */\n    _onForwardedSourcesChanged(forwardedSources = []) {\n        const oldForwardedSources = this._forwardedSources || [];\n        let leavingForwardedSources = [];\n        let enteringForwardedSources = [];\n        const timestamp = Date.now();\n\n        this._forwardedSources = forwardedSources;\n\n        leavingForwardedSources = oldForwardedSources.filter(sourceName => !this.isInForwardedSources(sourceName));\n\n        enteringForwardedSources = forwardedSources.filter(\n            sourceName => oldForwardedSources.indexOf(sourceName) === -1);\n\n        logger.debug(`Fowarded sources changed leaving=${leavingForwardedSources}, entering=`\n            + `${enteringForwardedSources} at ${timestamp}`);\n        this.conference.eventEmitter.emit(\n            JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED,\n            leavingForwardedSources,\n            enteringForwardedSources,\n            timestamp);\n    }\n\n    /**\n     * Should be called when current media session ends and after the\n     * PeerConnection has been closed using PeerConnection.close() method.\n     */\n    onCallEnded() {\n        if (this._channel) {\n            // The BridgeChannel is not explicitly closed as the PeerConnection\n            // is closed on call ended which triggers datachannel onclose\n            // events. If using a WebSocket, the channel must be closed since\n            // it is not managed by the PeerConnection.\n            // The reference is cleared to disable any logic related to the\n            // channel.\n            if (this._channel && this._channel.mode === 'websocket') {\n                this._channel.close();\n            }\n\n            this._channel = null;\n        }\n    }\n\n    /**\n     * Sets the capture frame rate to be used for desktop tracks.\n     *\n     * @param {number} maxFps framerate to be used for desktop track capture.\n     */\n    setDesktopSharingFrameRate(maxFps) {\n        RTCUtils.setDesktopSharingFrameRate(maxFps);\n    }\n\n    /**\n     * Sets the receiver video constraints that determine how bitrate is allocated to each of the video streams\n     * requested from the bridge. The constraints are cached and sent through the bridge channel once the channel\n     * is established.\n     * @param {*} constraints\n     */\n    setReceiverVideoConstraints(constraints) {\n        this._receiverVideoConstraints = constraints;\n\n        if (this._channel && this._channel.isOpen()) {\n            this._channel.sendReceiverVideoConstraintsMessage(constraints);\n        }\n    }\n\n    /**\n     * Sends the track's  video type to the JVB.\n     * @param {SourceName} sourceName - the track's source name.\n     * @param {BridgeVideoType} videoType - the track's video type.\n     */\n    sendSourceVideoType(sourceName, videoType) {\n        if (this._channel && this._channel.isOpen()) {\n            this._channel.sendSourceVideoTypeMessage(sourceName, videoType);\n        }\n    }\n\n    /**\n     *\n     * @param eventType\n     * @param listener\n     */\n    static addListener(eventType, listener) {\n        RTCUtils.addListener(eventType, listener);\n    }\n\n    /**\n     *\n     * @param eventType\n     * @param listener\n     */\n    static removeListener(eventType, listener) {\n        RTCUtils.removeListener(eventType, listener);\n    }\n\n    /**\n     *\n     * @param options\n     */\n    static init(options = {}) {\n        this.options = options;\n\n        return RTCUtils.init(this.options);\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     * Creates new <tt>TraceablePeerConnection</tt>\n     * @param {SignalingLayer} signaling The signaling layer that will provide information about the media or\n     * participants which is not carried over SDP.\n     * @param {object} pcConfig The {@code RTCConfiguration} to use for the WebRTC peer connection.\n     * @param {boolean} isP2P Indicates whether or not the new TPC will be used in a peer to peer type of session.\n     * @param {object} options The config options.\n     * @param {boolean} options.enableInsertableStreams - Set to true when the insertable streams constraints is to be\n     * enabled on the PeerConnection.\n     * @param {boolean} options.disableSimulcast If set to 'true' will disable the simulcast.\n     * @param {boolean} options.disableRtx If set to 'true' will disable the RTX.\n     * @param {boolean} options.startSilent If set to 'true' no audio will be sent or received.\n     * @return {TraceablePeerConnection}\n     */\n    createPeerConnection(signaling, pcConfig, isP2P, options) {\n        const pcConstraints = JSON.parse(JSON.stringify(RTCUtils.pcConstraints));\n\n        if (options.enableInsertableStreams) {\n            logger.debug('E2EE - setting insertable streams constraints');\n            pcConfig.encodedInsertableStreams = true;\n        }\n\n        // TODO: remove this.\n        const supportsSdpSemantics = browser.isChromiumBased() && !options.usesUnifiedPlan;\n\n        if (supportsSdpSemantics) {\n            logger.debug('WebRTC application is running in plan-b mode');\n            pcConfig.sdpSemantics = 'plan-b';\n        }\n\n        if (options.forceTurnRelay) {\n            pcConfig.iceTransportPolicy = 'relay';\n        }\n\n        // Set the RTCBundlePolicy to max-bundle so that only one set of ice candidates is generated.\n        // The default policy generates separate ice candidates for audio and video connections.\n        // This change is necessary for Unified plan to work properly on Chrome and Safari.\n        pcConfig.bundlePolicy = 'max-bundle';\n\n        peerConnectionIdCounter = safeCounterIncrement(peerConnectionIdCounter);\n\n        const newConnection\n            = new TraceablePeerConnection(\n                this,\n                peerConnectionIdCounter,\n                signaling,\n                pcConfig, pcConstraints,\n                isP2P, options);\n\n        this.peerConnections.set(newConnection.id, newConnection);\n\n        return newConnection;\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Removed given peer connection from this RTC module instance.\n     * @param {TraceablePeerConnection} traceablePeerConnection\n     * @return {boolean} <tt>true</tt> if the given peer connection was removed\n     * successfully or <tt>false</tt> if there was no peer connection mapped in\n     * this RTC instance.\n     */\n    _removePeerConnection(traceablePeerConnection) {\n        const id = traceablePeerConnection.id;\n\n        if (this.peerConnections.has(id)) {\n            // NOTE Remote tracks are not removed here.\n            this.peerConnections.delete(id);\n\n            return true;\n        }\n\n        return false;\n\n    }\n\n    /**\n     *\n     * @param track\n     */\n    addLocalTrack(track) {\n        if (!track) {\n            throw new Error('track must not be null nor undefined');\n        }\n\n        this.localTracks.push(track);\n\n        track.conference = this.conference;\n    }\n\n    /**\n     * Get forwarded sources list.\n     * @returns {Array<string>|null}\n     */\n    getForwardedSources() {\n        return this._forwardedSources;\n    }\n\n    /**\n     * Get local video track.\n     * @returns {JitsiLocalTrack|undefined}\n     */\n    getLocalVideoTrack() {\n        const localVideo = this.getLocalTracks(MediaType.VIDEO);\n\n        return localVideo.length ? localVideo[0] : undefined;\n    }\n\n    /**\n     * Returns all the local video tracks.\n     * @returns {Array<JitsiLocalTrack>}\n     */\n    getLocalVideoTracks() {\n        return this.getLocalTracks(MediaType.VIDEO);\n    }\n\n    /**\n     * Get local audio track.\n     * @returns {JitsiLocalTrack|undefined}\n     */\n    getLocalAudioTrack() {\n        const localAudio = this.getLocalTracks(MediaType.AUDIO);\n\n        return localAudio.length ? localAudio[0] : undefined;\n    }\n\n    /**\n     * Returns the endpoint id for the local user.\n     * @returns {string}\n     */\n    getLocalEndpointId() {\n        return this.conference.myUserId();\n    }\n\n    /**\n     * Returns the local tracks of the given media type, or all local tracks if\n     * no specific type is given.\n     * @param {MediaType} [mediaType] Optional media type filter.\n     * (audio or video).\n     */\n    getLocalTracks(mediaType) {\n        let tracks = this.localTracks.slice();\n\n        if (mediaType !== undefined) {\n            tracks = tracks.filter(\n                track => track.getType() === mediaType);\n        }\n\n        return tracks;\n    }\n\n    /**\n     * Obtains all remote tracks currently known to this RTC module instance.\n     * @param {MediaType} [mediaType] The remote tracks will be filtered\n     *      by their media type if this argument is specified.\n     * @return {Array<JitsiRemoteTrack>}\n     */\n    getRemoteTracks(mediaType) {\n        let remoteTracks = [];\n\n        for (const tpc of this.peerConnections.values()) {\n            const pcRemoteTracks = tpc.getRemoteTracks(undefined, mediaType);\n\n            if (pcRemoteTracks) {\n                remoteTracks = remoteTracks.concat(pcRemoteTracks);\n            }\n        }\n\n        return remoteTracks;\n    }\n\n    /**\n     * Set mute for all local audio streams attached to the conference.\n     * @param value The mute value.\n     * @returns {Promise}\n     */\n    setAudioMute(value) {\n        const mutePromises = [];\n\n        this.getLocalTracks(MediaType.AUDIO).forEach(audioTrack => {\n            // this is a Promise\n            mutePromises.push(value ? audioTrack.mute() : audioTrack.unmute());\n        });\n\n        // We return a Promise from all Promises so we can wait for their\n        // execution.\n        return Promise.all(mutePromises);\n    }\n\n    /**\n    * Set mute for all local video streams attached to the conference.\n    * @param value The mute value.\n    * @returns {Promise}\n    */\n    setVideoMute(value) {\n        const mutePromises = [];\n\n        this.getLocalTracks(MediaType.VIDEO)\n            .forEach(videoTrack => {\n                // this is a Promise\n                mutePromises.push(value ? videoTrack.mute() : videoTrack.unmute());\n            });\n\n        // We return a Promise from all Promises so we can wait for their\n        // execution.\n        return Promise.all(mutePromises);\n    }\n\n    /**\n     *\n     * @param track\n     */\n    removeLocalTrack(track) {\n        const pos = this.localTracks.indexOf(track);\n\n        if (pos === -1) {\n            return;\n        }\n\n        this.localTracks.splice(pos, 1);\n    }\n\n    /**\n     *\n     * @param elSelector\n     * @param stream\n     */\n    static attachMediaStream(elSelector, stream) {\n        return RTCUtils.attachMediaStream(elSelector, stream);\n    }\n\n    /**\n     * Returns true if retrieving the list of input devices is supported\n     * and false if not.\n     */\n    static isDeviceListAvailable() {\n        return RTCUtils.isDeviceListAvailable();\n    }\n\n    /**\n     * Returns true if changing the input (camera / microphone) or output\n     * (audio) device is supported and false if not.\n     * @param {string} [deviceType] Type of device to change. Default is\n     *      undefined or 'input', 'output' - for audio output device change.\n     * @returns {boolean} true if available, false otherwise.\n     */\n    static isDeviceChangeAvailable(deviceType) {\n        return RTCUtils.isDeviceChangeAvailable(deviceType);\n    }\n\n    /**\n     * Returns whether the current execution environment supports WebRTC (for\n     * use within this library).\n     *\n     * @returns {boolean} {@code true} if WebRTC is supported in the current\n     * execution environment (for use within this library); {@code false},\n     * otherwise.\n     */\n    static isWebRtcSupported() {\n        return browser.isSupported();\n    }\n\n    /**\n     * Returns currently used audio output device id, '' stands for default\n     * device\n     * @returns {string}\n     */\n    static getAudioOutputDevice() {\n        return RTCUtils.getAudioOutputDevice();\n    }\n\n    /**\n     * Returns list of available media devices if its obtained, otherwise an\n     * empty array is returned/\n     * @returns {array} list of available media devices.\n     */\n    static getCurrentlyAvailableMediaDevices() {\n        return RTCUtils.getCurrentlyAvailableMediaDevices();\n    }\n\n    /**\n     * Returns whether available devices have permissions granted\n     * @returns {Boolean}\n     */\n    static arePermissionsGrantedForAvailableDevices() {\n        return RTCUtils.arePermissionsGrantedForAvailableDevices();\n    }\n\n    /**\n     * Returns event data for device to be reported to stats.\n     * @returns {MediaDeviceInfo} device.\n     */\n    static getEventDataForActiveDevice(device) {\n        return RTCUtils.getEventDataForActiveDevice(device);\n    }\n\n    /**\n     * Sets current audio output device.\n     * @param {string} deviceId Id of 'audiooutput' device from\n     *      navigator.mediaDevices.enumerateDevices().\n     * @returns {Promise} resolves when audio output is changed, is rejected\n     *      otherwise\n     */\n    static setAudioOutputDevice(deviceId) {\n        return RTCUtils.setAudioOutputDevice(deviceId);\n    }\n\n    /**\n     * Returns <tt>true<tt/> if given WebRTC MediaStream is considered a valid\n     * \"user\" stream which means that it's not a \"receive only\" stream nor a\n     * \"mixed\" JVB stream.\n     *\n     * Clients that implement Unified Plan, such as Firefox use recvonly\n     * \"streams/channels/tracks\" for receiving remote stream/tracks, as opposed\n     * to Plan B where there are only 3 channels: audio, video and data.\n     *\n     * @param {MediaStream} stream The WebRTC MediaStream instance.\n     * @returns {boolean}\n     */\n    static isUserStream(stream) {\n        return RTC.isUserStreamById(stream.id);\n    }\n\n    /**\n     * Returns <tt>true<tt/> if a WebRTC MediaStream identified by given stream\n     * ID is considered a valid \"user\" stream which means that it's not a\n     * \"receive only\" stream nor a \"mixed\" JVB stream.\n     *\n     * Clients that implement Unified Plan, such as Firefox use recvonly\n     * \"streams/channels/tracks\" for receiving remote stream/tracks, as opposed\n     * to Plan B where there are only 3 channels: audio, video and data.\n     *\n     * @param {string} streamId The id of WebRTC MediaStream.\n     * @returns {boolean}\n     */\n    static isUserStreamById(streamId) {\n        return streamId && streamId !== 'mixedmslabel'\n            && streamId !== 'default';\n    }\n\n    /**\n     * Allows to receive list of available cameras/microphones.\n     * @param {function} callback Would receive array of devices as an\n     *      argument.\n     */\n    static enumerateDevices(callback) {\n        RTCUtils.enumerateDevices(callback);\n    }\n\n    /**\n     * A method to handle stopping of the stream.\n     * One point to handle the differences in various implementations.\n     * @param {MediaStream} mediaStream MediaStream object to stop.\n     */\n    static stopMediaStream(mediaStream) {\n        RTCUtils.stopMediaStream(mediaStream);\n    }\n\n    /**\n     * Returns whether the desktop sharing is enabled or not.\n     * @returns {boolean}\n     */\n    static isDesktopSharingEnabled() {\n        return RTCUtils.isDesktopSharingEnabled();\n    }\n\n    /**\n     * Closes the currently opened bridge channel.\n     */\n    closeBridgeChannel() {\n        if (this._channel) {\n            this._channel.close();\n            this._channel = null;\n        }\n    }\n\n    /* eslint-disable max-params */\n    /**\n     *\n     * @param {TraceablePeerConnection} tpc\n     * @param {number} ssrc\n     * @param {number} audioLevel\n     * @param {boolean} isLocal\n     */\n    setAudioLevel(tpc, ssrc, audioLevel, isLocal) {\n        const track = tpc.getTrackBySSRC(ssrc);\n\n        if (!track) {\n            return;\n        } else if (!track.isAudioTrack()) {\n            logger.warn(`Received audio level for non-audio track: ${ssrc}`);\n\n            return;\n        } else if (track.isLocal() !== isLocal) {\n            logger.error(\n                `${track} was expected to ${isLocal ? 'be' : 'not be'} local`);\n        }\n\n        track.setAudioLevel(audioLevel, tpc);\n    }\n\n    /**\n     * Sends message via the bridge channel.\n     * @param {string} to The id of the endpoint that should receive the\n     *      message. If \"\" the message will be sent to all participants.\n     * @param {object} payload The payload of the message.\n     * @throws NetworkError or InvalidStateError or Error if the operation\n     * fails or there is no data channel created.\n     */\n    sendChannelMessage(to, payload) {\n        if (this._channel) {\n            this._channel.sendMessage(to, payload);\n        } else {\n            throw new Error('Channel support is disabled!');\n        }\n    }\n\n    /**\n     * Sends the local stats via the bridge channel.\n     * @param {Object} payload The payload of the message.\n     * @throws NetworkError/InvalidStateError/Error if the operation fails or if there is no data channel created.\n     */\n    sendEndpointStatsMessage(payload) {\n        if (this._channel && this._channel.isOpen()) {\n            this._channel.sendEndpointStatsMessage(payload);\n        }\n    }\n\n    /**\n     * Selects a new value for \"lastN\". The requested amount of videos are going\n     * to be delivered after the value is in effect. Set to -1 for unlimited or\n     * all available videos.\n     * @param {number} value the new value for lastN.\n     */\n    setLastN(value) {\n        if (this._lastN !== value) {\n            this._lastN = value;\n            if (this._channel && this._channel.isOpen()) {\n                this._channel.sendSetLastNMessage(value);\n            }\n            this.eventEmitter.emit(RTCEvents.LASTN_VALUE_CHANGED, value);\n        }\n    }\n\n    /**\n     * Indicates if the source name is currently included in the forwarded sources.\n     *\n     * @param {string} sourceName The source name that we check for forwarded sources.\n     * @returns {boolean} true if the source name is in the forwarded sources or if we don't have bridge channel\n     * support, otherwise we return false.\n     */\n    isInForwardedSources(sourceName) {\n        return !this._forwardedSources // forwardedSources not initialised yet.\n            || this._forwardedSources.indexOf(sourceName) > -1;\n    }\n\n    /**\n     * Updates the target audio output device for all remote audio tracks.\n     *\n     * @param {string} deviceId - The device id of the audio ouput device to\n     * use for all remote tracks.\n     * @private\n     * @returns {void}\n     */\n    _updateAudioOutputForAudioTracks(deviceId) {\n        const remoteAudioTracks = this.getRemoteTracks(MediaType.AUDIO);\n\n        for (const track of remoteAudioTracks) {\n            track.setAudioOutput(deviceId);\n        }\n    }\n}\n","export enum ConnectionQualityEvents {\n    /**\n     * Indicates that the local connection statistics were updated.\n     */\n    LOCAL_STATS_UPDATED = 'cq.local_stats_updated',\n\n    /**\n     * Indicates that the connection statistics for a particular remote participant\n     * were updated.\n     */\n    REMOTE_STATS_UPDATED = 'cq.remote_stats_updated'\n};\n\n// exported for backward compatibility\nexport const LOCAL_STATS_UPDATED = ConnectionQualityEvents.LOCAL_STATS_UPDATED;\nexport const REMOTE_STATS_UPDATED = ConnectionQualityEvents.REMOTE_STATS_UPDATED;\n\n","import { getLogger } from '@jitsi/logger';\n\nimport * as ConferenceEvents from '../../JitsiConferenceEvents';\nimport CodecMimeType from '../../service/RTC/CodecMimeType';\nimport * as RTCEvents from '../../service/RTC/RTCEvents';\nimport * as ConnectionQualityEvents from '../../service/connectivity/ConnectionQualityEvents';\n\nconst Resolutions = require('../../service/RTC/Resolutions');\nconst { VideoType } = require('../../service/RTC/VideoType');\nconst { XMPPEvents } = require('../../service/xmpp/XMPPEvents');\n\nconst logger = getLogger(__filename);\n\n/**\n * The value to use for the \"type\" field for messages sent by ConnectionQuality\n * over the data channel.\n */\nconst STATS_MESSAGE_TYPE = 'stats';\n\nconst kSimulcastFormats = [\n    { width: 1920,\n        height: 1080,\n        layers: 3,\n        target: 'high' },\n    { width: 1280,\n        height: 720,\n        layers: 3,\n        target: 'high' },\n    { width: 960,\n        height: 540,\n        layers: 3,\n        target: 'standard' },\n    { width: 640,\n        height: 360,\n        layers: 2,\n        target: 'standard' },\n    { width: 480,\n        height: 270,\n        layers: 2,\n        target: 'low' },\n    { width: 320,\n        height: 180,\n        layers: 1,\n        target: 'low' }\n];\n\n/**\n * The maximum bitrate to use as a measurement against the participant's current\n * bitrate. This cap helps in the cases where the participant's bitrate is high\n * but not enough to fulfill high targets, such as with 1080p.\n */\nconst MAX_TARGET_BITRATE = 2500;\n\n/**\n * The initial bitrate for video in kbps.\n */\nlet startBitrate = 800;\n\n/**\n * Gets the expected bitrate (in kbps) in perfect network conditions.\n * @param simulcast {boolean} whether simulcast is enabled or not.\n * @param resolution {Resolution} the resolution.\n * @param millisSinceStart {number} the number of milliseconds since sending video started.\n * @param videoQualitySettings {Object} the bitrate and codec settings for the local video source.\n */\nfunction getTarget(simulcast, resolution, millisSinceStart, videoQualitySettings) {\n    let target = 0;\n    let height = Math.min(resolution.height, resolution.width);\n\n    // Find the first format with height no bigger than ours.\n    let simulcastFormat = kSimulcastFormats.find(f => f.height <= height);\n\n    if (simulcastFormat && simulcast && videoQualitySettings.codec === CodecMimeType.VP8) {\n        // Sum the target fields from all simulcast layers for the given\n        // resolution (e.g. 720p + 360p + 180p) for VP8 simulcast.\n        for (height = simulcastFormat.height; height >= 180; height /= 2) {\n            const targetHeight = height;\n\n            simulcastFormat = kSimulcastFormats.find(f => f.height === targetHeight);\n            if (simulcastFormat) {\n                target += videoQualitySettings[simulcastFormat.target];\n            } else {\n                break;\n            }\n        }\n    } else if (simulcastFormat) {\n        // For VP9 SVC, H.264 (simulcast automatically disabled) and p2p, target bitrate will be\n        // same as that of the individual stream bitrate.\n        target = videoQualitySettings[simulcastFormat.target];\n    }\n\n    // Allow for an additional 1 second for ramp up -- delay any initial drop\n    // of connection quality by 1 second. Convert target from bps to kbps.\n    return Math.min(target / 1000, rampUp(Math.max(0, millisSinceStart - 1000)));\n}\n\n/**\n * Gets the bitrate to which GCC would have ramped up in perfect network\n * conditions after millisSinceStart milliseconds.\n * @param millisSinceStart {number} the number of milliseconds since sending\n * video was enabled.\n */\nfunction rampUp(millisSinceStart) {\n    if (millisSinceStart > 60000) {\n        return Number.MAX_SAFE_INTEGER;\n    }\n\n    // According to GCC the send side bandwidth estimation grows with at most\n    // 8% per second.\n    // https://tools.ietf.org/html/draft-ietf-rmcat-gcc-02#section-5.5\n    return startBitrate * Math.pow(1.08, millisSinceStart / 1000);\n}\n\n/**\n * A class which monitors the local statistics coming from the RTC modules, and\n * calculates a \"connection quality\" value, in percent, for the media\n * connection. A value of 100% indicates a very good network connection, and a\n * value of 0% indicates a poor connection.\n */\nexport default class ConnectionQuality {\n    /**\n     *\n     * @param conference\n     * @param eventEmitter\n     * @param options\n     */\n    constructor(conference, eventEmitter, options) {\n        this.eventEmitter = eventEmitter;\n\n        /**\n         * The owning JitsiConference.\n         */\n        this._conference = conference;\n\n        /**\n         * Holds statistics about the local connection quality.\n         */\n        this._localStats = {\n            connectionQuality: 100,\n            jvbRTT: undefined\n        };\n\n        /**\n         * The time this._localStats.connectionQuality was last updated.\n         */\n        this._lastConnectionQualityUpdate = -1;\n\n        /**\n         * Conference options.\n         */\n        this._options = options;\n\n        /**\n         * Maps a participant ID to an object holding connection quality\n         * statistics received from this participant.\n         */\n        this._remoteStats = {};\n\n        /**\n         * The time that the ICE state last changed to CONNECTED. We use this\n         * to calculate how much time we as a sender have had to ramp-up.\n         */\n        this._timeIceConnected = -1;\n\n        /**\n         * The time that local video was unmuted. We use this to calculate how\n         * much time we as a sender have had to ramp-up.\n         */\n        this._timeVideoUnmuted = -1;\n\n        // We assume a global startBitrate value for the sake of simplicity.\n        if (this._options.config?.startBitrate > 0) {\n            startBitrate = this._options.config.startBitrate;\n        }\n\n        // TODO: consider ignoring these events and letting the user of\n        // lib-jitsi-meet handle these separately.\n        conference.on(\n            ConferenceEvents.CONNECTION_INTERRUPTED,\n            () => {\n                this._updateLocalConnectionQuality(0);\n                this.eventEmitter.emit(\n                    ConnectionQualityEvents.LOCAL_STATS_UPDATED,\n                    this._localStats);\n                this._broadcastLocalStats();\n            });\n\n        conference.room.addListener(\n            XMPPEvents.ICE_CONNECTION_STATE_CHANGED,\n            (jingleSession, newState) => {\n                if (!jingleSession.isP2P && newState === 'connected') {\n                    this._timeIceConnected = window.performance.now();\n                }\n            });\n\n        // Listen to DataChannel message from other participants in the\n        // conference, and update the _remoteStats field accordingly.\n        // TODO - Delete this when all the mobile endpoints switch to using the new Colibri\n        // message format for sending the endpoint stats.\n        conference.on(\n            ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\n            (participant, payload) => {\n                if (payload.type === STATS_MESSAGE_TYPE) {\n                    this._updateRemoteStats(\n                        participant.getId(), payload.values);\n                }\n            });\n\n        conference.on(\n            ConferenceEvents.ENDPOINT_STATS_RECEIVED,\n            (participant, payload) => {\n                this._updateRemoteStats(participant.getId(), payload);\n            });\n\n        if (!this._options.config.disableLocalStats) {\n            // Listen to local statistics events originating from the RTC module and update the _localStats field.\n            conference.statistics.addConnectionStatsListener(this._updateLocalStats.bind(this));\n        }\n\n        // Save the last time we were unmuted.\n        conference.on(\n            ConferenceEvents.TRACK_MUTE_CHANGED,\n            track => {\n                if (track.isVideoTrack()) {\n                    if (track.isMuted()) {\n                        this._timeVideoUnmuted = -1;\n                    } else {\n                        this._maybeUpdateUnmuteTime();\n                    }\n                }\n            });\n        conference.on(\n            ConferenceEvents.TRACK_ADDED,\n            track => {\n                if (track.isVideoTrack() && !track.isMuted()) {\n                    this._maybeUpdateUnmuteTime();\n                }\n            });\n        conference.rtc.on(\n            RTCEvents.LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED,\n            track => {\n                this._localStats.maxEnabledResolution = track.maxEnabledResolution;\n            });\n\n        conference.on(\n            ConferenceEvents.SERVER_REGION_CHANGED,\n            serverRegion => {\n                this._localStats.serverRegion = serverRegion;\n            });\n\n        conference.on(\n            ConferenceEvents.PROPERTIES_CHANGED,\n            properties => {\n                this._localStats.bridgeCount\n                    = Number((properties || {})['bridge-count']);\n            }\n        );\n    }\n\n    /**\n     * Sets _timeVideoUnmuted if it was previously unset. If it was already set,\n     * doesn't change it.\n     */\n    _maybeUpdateUnmuteTime() {\n        if (this._timeVideoUnmuted < 0) {\n            this._timeVideoUnmuted = window.performance.now();\n        }\n    }\n\n    /**\n     * Calculates a new \"connection quality\" value.\n     * @param videoType {VideoType} the type of the video source (camera or a screen capture).\n     * @param isMuted {boolean} whether the local video is muted.\n     * @param resolutionName {Resolution} the input resolution used by the camera.\n     * @returns {*} the newly calculated connection quality.\n     */\n    _calculateConnectionQuality(videoType, isMuted, resolutionName) {\n\n        // resolutionName is an index into Resolutions (where \"720\" is\n        // \"1280x720\" and \"960\" is \"960x720\" ...).\n        const resolution = Resolutions[resolutionName];\n\n        let quality = 100;\n        let packetLoss;\n\n        // TODO: take into account packet loss for received streams\n\n        if (this._localStats.packetLoss) {\n            packetLoss = this._localStats.packetLoss.upload;\n\n            // Ugly Hack Alert (UHA):\n            // The packet loss for the upload direction is calculated based on\n            // incoming RTCP Receiver Reports. Since we don't have RTCP\n            // termination for audio, these reports come from the actual\n            // receivers in the conference and therefore the reported packet\n            // loss includes loss from the bridge to the receiver.\n            // When we are sending video this effect is small, because the\n            // number of video packets is much larger than the number of audio\n            // packets (and our calculation is based on the total number of\n            // received and lost packets).\n            // When video is muted, however, the effect might be significant,\n            // but we don't know what it is. We do know that it is positive, so\n            // as a temporary solution, until RTCP termination is implemented\n            // for the audio streams, we relax the packet loss checks here.\n            if (isMuted) {\n                packetLoss *= 0.5;\n            }\n        }\n\n        if (isMuted || !resolution || videoType === VideoType.DESKTOP\n            || this._timeIceConnected < 0\n            || this._timeVideoUnmuted < 0) {\n\n            // Calculate a value based on packet loss only.\n            if (packetLoss === undefined) {\n                logger.error('Cannot calculate connection quality, unknown '\n                    + 'packet loss.');\n                quality = 100;\n            } else if (packetLoss <= 2) {\n                quality = 100; // Full 5 bars.\n            } else if (packetLoss <= 4) {\n                quality = 70; // 4 bars\n            } else if (packetLoss <= 6) {\n                quality = 50; // 3 bars\n            } else if (packetLoss <= 8) {\n                quality = 30; // 2 bars\n            } else if (packetLoss <= 12) {\n                quality = 10; // 1 bars\n            } else {\n                quality = 0; // Still 1 bar, but slower climb-up.\n            }\n        } else {\n            // Calculate a value based on the send video bitrate on the active TPC.\n            const activeTPC = this._conference.getActivePeerConnection();\n\n            if (activeTPC) {\n                const isSimulcastOn = activeTPC.isSimulcastOn();\n                const videoQualitySettings = activeTPC.getTargetVideoBitrates();\n\n                // Add the codec info as well.\n                videoQualitySettings.codec = activeTPC.getConfiguredVideoCodec();\n\n                // Time since sending of video was enabled.\n                const millisSinceStart = window.performance.now()\n                    - Math.max(this._timeVideoUnmuted, this._timeIceConnected);\n                const statsInterval = this._options.config?.pcStatsInterval ?? 10000;\n\n                // Expected sending bitrate in perfect conditions.\n                let target = getTarget(isSimulcastOn, resolution, millisSinceStart, videoQualitySettings);\n\n                target = Math.min(target, MAX_TARGET_BITRATE);\n\n                // Calculate the quality only after the stats are available (after video was enabled).\n                if (millisSinceStart > statsInterval) {\n                    quality = 100 * this._localStats.bitrate.upload / target;\n                }\n            }\n\n            // Whatever the bitrate, drop early if there is significant loss\n            if (packetLoss && packetLoss >= 10) {\n                quality = Math.min(quality, 30);\n            }\n        }\n\n        // Make sure that the quality doesn't climb quickly\n        if (this._lastConnectionQualityUpdate > 0) {\n            const maxIncreasePerSecond = 2;\n            const prevConnectionQuality = this._localStats.connectionQuality;\n            const diffSeconds = (window.performance.now() - this._lastConnectionQualityUpdate) / 1000;\n\n            quality = Math.min(quality, prevConnectionQuality + (diffSeconds * maxIncreasePerSecond));\n        }\n\n        return Math.min(100, quality);\n    }\n\n    /**\n     * Updates the localConnectionQuality value\n     * @param values {number} the new value. Should be in [0, 100].\n     */\n    _updateLocalConnectionQuality(value) {\n        this._localStats.connectionQuality = value;\n        this._lastConnectionQualityUpdate = window.performance.now();\n    }\n\n    /**\n     * Broadcasts the local statistics to all other participants in the\n     * conference.\n     */\n    _broadcastLocalStats() {\n        // Send only the data that remote participants care about.\n        const data = {\n            bitrate: this._localStats.bitrate,\n            packetLoss: this._localStats.packetLoss,\n            connectionQuality: this._localStats.connectionQuality,\n            jvbRTT: this._localStats.jvbRTT,\n            serverRegion: this._localStats.serverRegion,\n            maxEnabledResolution: this._localStats.maxEnabledResolution,\n            avgAudioLevels: this._localStats.localAvgAudioLevels\n        };\n\n        try {\n            this._conference.sendEndpointStatsMessage(data);\n        } catch (err) {\n            // Ignore the error as we might hit it in the beginning of the call before the channel is ready.\n            // The statistics will be sent again after few seconds and error is logged elseware as well.\n        }\n    }\n\n    /**\n     * Updates the local statistics\n     * @param {TraceablePeerConnection} tpc the peerconnection which emitted\n     * the stats\n     * @param data new statistics\n     */\n    _updateLocalStats(tpc, data) {\n        // Update jvbRTT\n        if (!tpc.isP2P) {\n            const jvbRTT\n                = data.transport\n                    && data.transport.length && data.transport[0].rtt;\n\n            this._localStats.jvbRTT = jvbRTT ? jvbRTT : undefined;\n        }\n\n        // Do not continue with processing of other stats if they do not\n        // originate from the active peerconnection\n        if (tpc !== this._conference.getActivePeerConnection()) {\n            return;\n        }\n\n        let key;\n        const updateLocalConnectionQuality\n            = !this._conference.isConnectionInterrupted();\n        const localVideoTrack\n            = this._conference.getLocalVideoTrack();\n        const videoType\n            = localVideoTrack ? localVideoTrack.videoType : undefined;\n        const isMuted = localVideoTrack ? localVideoTrack.isMuted() : true;\n        const resolution = localVideoTrack\n            ? Math.min(localVideoTrack.resolution, localVideoTrack.maxEnabledResolution) : null;\n\n        if (!isMuted) {\n            this._maybeUpdateUnmuteTime();\n        }\n\n        // Copy the fields already in 'data'.\n        for (key in data) {\n            if (data.hasOwnProperty(key)) {\n                this._localStats[key] = data[key];\n            }\n        }\n\n        // And re-calculate the connectionQuality field.\n        if (updateLocalConnectionQuality) {\n            this._updateLocalConnectionQuality(\n                this._calculateConnectionQuality(\n                    videoType,\n                    isMuted,\n                    resolution));\n        }\n\n        this.eventEmitter.emit(\n            ConnectionQualityEvents.LOCAL_STATS_UPDATED,\n            this._localStats);\n        this._broadcastLocalStats();\n    }\n\n    /**\n     * Updates remote statistics\n     * @param id the id of the remote participant\n     * @param data the statistics received\n     */\n    _updateRemoteStats(id, data) {\n        // Use only the fields we need\n        this._remoteStats[id] = {\n            bitrate: data.bitrate,\n            packetLoss: data.packetLoss,\n            connectionQuality: data.connectionQuality,\n            jvbRTT: data.jvbRTT,\n            serverRegion: data.serverRegion,\n            maxEnabledResolution: data.maxEnabledResolution,\n            avgAudioLevels: data.avgAudioLevels\n        };\n\n        this.eventEmitter.emit(\n            ConnectionQualityEvents.REMOTE_STATS_UPDATED,\n            id,\n            this._remoteStats[id]);\n    }\n\n    /**\n     * Returns the local statistics.\n     * Exported only for use in jitsi-meet-torture.\n     */\n    getStats() {\n        return this._localStats;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceErrors from '../../JitsiConferenceErrors';\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * This class deals with shenanigans around JVB media session's ICE failed status handling.\n *\n * If ICE restarts are NOT explicitly enabled by the {@code enableIceRestart} config option, then the conference will\n * delay emitting the {@JitsiConferenceErrors.ICE_FAILED} event by 15 seconds. If the network info module reports\n * the internet offline status then the time will start counting after the internet comes back online.\n *\n * If ICE restart are enabled, then a delayed ICE failed notification to Jicofo will be sent, only if the ICE connection\n * does not recover soon after or before the XMPP connection is restored (if it was ever broken). If ICE fails while\n * the XMPP connection is not broken then the notifications will be sent after 2 seconds delay.\n */\nexport default class IceFailedHandling {\n    /**\n     * Creates new {@code DelayedIceFailed} task.\n     * @param {JitsiConference} conference\n     */\n    constructor(conference) {\n        this._conference = conference;\n    }\n\n    /**\n     * After making sure there's no way for the ICE connection to recover this method either sends ICE failed\n     * notification to Jicofo or emits the ice failed conference event.\n     * @private\n     * @returns {void}\n     */\n    _actOnIceFailed() {\n        if (!this._conference.room) {\n            return;\n        }\n\n        const { enableForcedReload, enableIceRestart } = this._conference.options.config;\n        const explicitlyDisabled = typeof enableIceRestart !== 'undefined' && !enableIceRestart;\n        const supportsRestartByTerminate = this._conference.room.supportsRestartByTerminate();\n        const useTerminateForRestart = supportsRestartByTerminate && !enableIceRestart;\n\n        logger.info('ICE failed,'\n            + ` enableForcedReload: ${enableForcedReload},`\n            + ` enableIceRestart: ${enableIceRestart},`\n            + ` supports restart by terminate: ${supportsRestartByTerminate}`);\n\n        if (explicitlyDisabled || (!enableIceRestart && !supportsRestartByTerminate) || enableForcedReload) {\n            logger.info('ICE failed, but ICE restarts are disabled');\n            const reason = enableForcedReload\n                ? JitsiConferenceErrors.CONFERENCE_RESTARTED\n                : JitsiConferenceErrors.ICE_FAILED;\n\n            this._conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED, reason);\n\n            return;\n        }\n\n        const jvbConnection = this._conference.jvbJingleSession;\n        const jvbConnIceState = jvbConnection && jvbConnection.getIceConnectionState();\n\n        if (!jvbConnection) {\n            logger.warn('Not sending ICE failed - no JVB connection');\n        } else if (jvbConnIceState === 'connected') {\n            logger.info('ICE connection restored - not sending ICE failed');\n        } else {\n            logger.info('Sending ICE failed - the connection did not recover, '\n                + `ICE state: ${jvbConnIceState}, `\n                + `use 'session-terminate': ${useTerminateForRestart}`);\n            if (useTerminateForRestart) {\n                this._conference.jvbJingleSession.terminate(\n                    () => {\n                        logger.info('session-terminate for ice restart - done');\n                    },\n                    error => {\n                        logger.error(`session-terminate for ice restart - error: ${error.message}`);\n                    }, {\n                        reason: 'connectivity-error',\n                        reasonDescription: 'ICE FAILED',\n                        requestRestart: true,\n                        sendSessionTerminate: true\n                    });\n            } else {\n                this._conference.jvbJingleSession.sendIceFailedNotification();\n            }\n        }\n    }\n\n    /**\n     * Starts the task.\n     */\n    start() {\n        //  Using xmpp.ping allows to handle both XMPP being disconnected and internet offline cases. The ping function\n        // uses sendIQ2 method which is resilient to XMPP connection disconnected state and will patiently wait until it\n        // gets reconnected.\n        //  This also handles the case about waiting for the internet to come back online, because ping\n        // will only succeed when the internet is online and then there's a chance for the ICE to recover from FAILED to\n        // CONNECTED which is the extra 2 second timeout after ping.\n        //  The 65 second timeout is given on purpose as there's no chance for XMPP to recover after 65 seconds of no\n        // communication with the server. Such resume attempt will result in unrecoverable conference failed event due\n        // to 'item-not-found' error returned by the server.\n        this._conference.xmpp.ping(65000).then(\n            () => {\n                if (!this._canceled) {\n                    this._iceFailedTimeout = window.setTimeout(() => {\n                        this._iceFailedTimeout = undefined;\n                        this._actOnIceFailed();\n                    }, 2000);\n                }\n            },\n            error => {\n                logger.error('PING error/timeout - not sending ICE failed', error);\n            });\n    }\n\n    /**\n     * Cancels the task.\n     */\n    cancel() {\n        this._canceled = true;\n        window.clearTimeout(this._iceFailedTimeout);\n    }\n}\n","export enum DetectionEvents {\n    /**\n     * Event triggered by a audio detector indicating that its active state has changed from active to inactive or vice\n     * versa.\n     * @event\n     * @type {boolean} - true when service has changed to active false otherwise.\n     */\n    DETECTOR_STATE_CHANGE = 'detector_state_change',\n\n    /** Event triggered by {@link NoAudioSignalDetector} when the local audio device associated with a JitsiConference\n     * starts receiving audio levels with the value of 0 meaning no audio is being captured on that device, or when\n     * it starts receiving audio levels !== 0 after being in a state of no audio.\n     * @event\n     * @type {boolean} - true when the current conference audio track has audio input false otherwise.\n     */\n    AUDIO_INPUT_STATE_CHANGE = 'audio_input_state_changed',\n\n    /** Event triggered by NoAudioSignalDetector when the local audio device associated with a JitsiConference goes silent\n     * for a period of time, meaning that the device is either broken or hardware/software muted.\n     * @event\n     * @type {void}\n     */\n    NO_AUDIO_INPUT = 'no_audio_input_detected',\n\n    /**\n     *  Event generated by {@link VADNoiseDetection} when the tracked device is considered noisy.\n     *  @event\n     *  @type {Object}\n     */\n    VAD_NOISY_DEVICE = 'detection.vad_noise_device',\n\n    /**\n     * Event generated by VADReportingService when if finishes creating a VAD report for the monitored devices.\n     * The generated objects are of type Array<Object>, one score for each monitored device.\n     * @event VAD_REPORT_PUBLISHED\n     * @type Array<Object> with the following structure:\n     * @property {Date} timestamp - Timestamp at which the compute took place.\n     * @property {number} avgVAD - Average VAD score over monitored period of time.\n     * @property {string} deviceId - Associate local audio device ID.\n     */\n    VAD_REPORT_PUBLISHED = 'vad-report-published',\n\n    /**\n     * Event generated by {@link TrackVADEmitter} when PCM sample VAD score is available.\n     *\n     * @event\n     * @type {Object}\n     * @property {Date}   timestamp - Exact time at which processed PCM sample was generated.\n     * @property {number} score - VAD score on a scale from 0 to 1 (i.e. 0.7)\n     * @property {Float32Array} pcmData - Raw PCM data with which the VAD score was calculated.\n     * @property {string} deviceId - Device id of the associated track.\n     */\n    VAD_SCORE_PUBLISHED = 'detection.vad_score_published',\n\n    /**\n     *  Event generated by {@link VADTalkMutedDetection} when a user is talking while the mic is muted.\n     *\n     *  @event\n     *  @type {Object}\n     */\n    VAD_TALK_WHILE_MUTED = 'detection.vad_talk_while_muted'\n};\n\n// exported for backward compatibility\nexport const DETECTOR_STATE_CHANGE = DetectionEvents.DETECTOR_STATE_CHANGE;\nexport const AUDIO_INPUT_STATE_CHANGE = DetectionEvents.AUDIO_INPUT_STATE_CHANGE;\nexport const NO_AUDIO_INPUT = DetectionEvents.NO_AUDIO_INPUT;\nexport const VAD_NOISY_DEVICE = DetectionEvents.VAD_NOISY_DEVICE;\nexport const VAD_REPORT_PUBLISHED = DetectionEvents.VAD_REPORT_PUBLISHED;\nexport const VAD_SCORE_PUBLISHED = DetectionEvents.VAD_SCORE_PUBLISHED;\nexport const VAD_TALK_WHILE_MUTED = DetectionEvents.VAD_TALK_WHILE_MUTED;\n","import EventEmitter from 'events';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\n\nimport * as DetectionEvents from './DetectionEvents';\n\n// We wait a certain time interval for constant silence input from the current device to account for\n// potential abnormalities and for a better use experience i.e. don't generate event the instant\n// an audio track is added to the tcr.\n// Potential improvement - add this as a configurable parameter.\nconst SILENCE_PERIOD_MS = 4000;\n\n/**\n * Detect if there is no audio input on the current TraceAblePeerConnection selected track. The no audio\n * state must be constant for a configured amount of time in order for the event to be triggered.\n * @fires DetectionEvents.AUDIO_INPUT_STATE_CHANGE\n * @fires DetectionEvents.NO_AUDIO_INPUT\n */\nexport default class NoAudioSignalDetection extends EventEmitter {\n    /**\n     * Creates new NoAudioSignalDetection.\n     *\n     * @param conference the JitsiConference instance that created us.\n     * @constructor\n     */\n    constructor(conference) {\n        super();\n\n        this._conference = conference;\n        this._timeoutTrigger = null;\n        this._hasAudioInput = null;\n\n        conference.on(JitsiConferenceEvents.TRACK_ADDED, this._trackAdded.bind(this));\n    }\n\n    /**\n     * Clear the timeout state.\n     */\n    _clearTriggerTimeout() {\n        clearTimeout(this._timeoutTrigger);\n        this._timeoutTrigger = null;\n    }\n\n\n    /**\n     * Generated event triggered by a change in the current conference audio input state.\n     *\n     * @param {*} audioLevel - The audio level of the ssrc.\n     * @fires DetectionEvents.AUDIO_INPUT_STATE_CHANGE\n     */\n    _handleAudioInputStateChange(audioLevel) {\n        // Current audio input state of the active local track in the conference, true for audio input false for no\n        // audio input.\n        const status = audioLevel !== 0;\n\n        // If this is the first audio event picked up or the current status is different from the previous trigger\n        // the event.\n        if (this._hasAudioInput === null || this._hasAudioInput !== status) {\n            this._hasAudioInput = status;\n            this.emit(DetectionEvents.AUDIO_INPUT_STATE_CHANGE, this._hasAudioInput);\n        }\n    }\n\n    /**\n     * Generate event triggered by a prolonged period of no audio input.\n     *\n     * @param {number} audioLevel - The audio level of the ssrc.\n     * @fires DetectionEvents.NO_AUDIO_INPUT\n     */\n    _handleNoAudioInputDetection(audioLevel) {\n        if (this._eventFired) {\n            return;\n        }\n\n        if (audioLevel === 0 && !this._timeoutTrigger) {\n            this._timeoutTrigger = setTimeout(() => {\n                this._eventFired = true;\n\n                this.emit(DetectionEvents.NO_AUDIO_INPUT);\n            }, SILENCE_PERIOD_MS);\n        } else if (audioLevel !== 0 && this._timeoutTrigger) {\n            this._clearTriggerTimeout();\n        }\n    }\n\n    /**\n     * Receives audio level events for all send and receive streams on the current TraceablePeerConnection.\n     *\n     * @param {TraceablePeerConnection} tpc - TraceablePeerConnection of the owning conference.\n     * @param {number} ssrc - The synchronization source identifier (SSRC) of the endpoint/participant/stream\n     * being reported.\n     * @param {number} audioLevel - The audio level of the ssrc.\n     * @param {boolean} isLocal - true for local/send streams or false for remote/receive streams.\n     */\n    _audioLevel(tpc, ssrc, audioLevel, isLocal) {\n        // We are interested in the local audio streams\n        if (!isLocal || !this._audioTrack) {\n            return;\n        }\n\n        // Get currently active local tracks from the TraceablePeerConnection\n        const localSSRCs = tpc.localSSRCs.get(this._audioTrack.rtcId);\n\n        // Only target the current active track in the tpc. For some reason audio levels for previous\n        // devices are also picked up from the PeerConnection so we filter them out.\n        if (!localSSRCs || !localSSRCs.ssrcs.includes(ssrc)) {\n            return;\n        }\n\n        // First handle audio input state change. In case the state changed to no input the no audio input event\n        // can try to fire again.\n        this._handleAudioInputStateChange(audioLevel);\n        this._handleNoAudioInputDetection(audioLevel);\n    }\n\n    /**\n     * Notifies NoAudioSignalDetection that a JitsiTrack was added to the associated JitsiConference.\n     * Only take into account local audio tracks.\n     *\n     * @param {JitsiTrack} track - The added JitsiTrack.\n     */\n    _trackAdded(track) {\n        if (track.isLocalAudioTrack()) {\n            // Reset state for the new track.\n            this._audioTrack = track;\n            this._eventFired = false;\n            this._clearTriggerTimeout();\n\n            // Listen for the audio levels on the newly added audio track\n            track.on(\n                JitsiTrackEvents.NO_AUDIO_INPUT,\n                audioLevel => {\n                    this._handleNoAudioInputDetection(audioLevel);\n                }\n            );\n            track.on(\n                JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,\n                audioLevel => {\n                    this._handleNoAudioInputDetection(audioLevel);\n                    this._handleAudioInputStateChange(audioLevel);\n                }\n            );\n        }\n    }\n}\n","import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport RTCEvents from '../../service/RTC/RTCEvents';\n\n/**\n * The value which we use to say, every sound over this threshold\n * is talking on the mic.\n * @type {number}\n */\nconst SPEECH_DETECT_THRESHOLD = 0.6;\n\n/**\n * The <tt>P2PDominantSpeakerDetection</tt> is activated only when p2p is\n * currently used.\n * Listens for changes in the audio level changes of the local p2p audio track\n * or remote p2p one and fires dominant speaker events to be able to use\n * features depending on those events (speaker stats), to make them work without\n * the video bridge.\n */\nexport default class P2PDominantSpeakerDetection {\n    /**\n     * Creates P2PDominantSpeakerDetection\n     * @param conference the JitsiConference instance that created us.\n     * @constructor\n     */\n    constructor(conference) {\n        this.conference = conference;\n\n        conference.addEventListener(\n            JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,\n            this._audioLevel.bind(this));\n\n        this.myUserID = this.conference.myUserId();\n    }\n\n    /**\n     * Receives audio level events for all streams in the conference.\n     *\n     * @param {String} id - The participant id\n     * @param {number} audioLevel - The audio level.\n     */\n    _audioLevel(id, audioLevel) {\n\n        // we do not process if p2p is not active\n        // or audio level is under certain threshold\n        // or if the audio level is for local audio track which is muted\n        if (!this.conference.isP2PActive()\n            || audioLevel <= SPEECH_DETECT_THRESHOLD\n            || (id === this.myUserID\n                    && this.conference.getLocalAudioTrack().isMuted())) {\n            return;\n        }\n\n        this.conference.rtc.eventEmitter.emit(\n            RTCEvents.DOMINANT_SPEAKER_CHANGED,\n            id);\n    }\n}\n","/**\n * Adapter that creates AudioContext objects depending on the browser.\n *\n * @returns {AudioContext} - Return a new AudioContext or undefined if the browser does not support it.\n */\nexport function createAudioContext(options) {\n    const AudioContextImpl = window.AudioContext || window.webkitAudioContext;\n\n    if (!AudioContextImpl) {\n        return undefined;\n    }\n\n    return new AudioContextImpl(options);\n}\n","import EventEmitter from 'events';\n\nimport RTC from '../RTC/RTC';\nimport { createAudioContext } from '../webaudio/WebAudioUtils';\n\nimport { VAD_SCORE_PUBLISHED } from './DetectionEvents';\n\n/**\n * Connects an audio JitsiLocalTrack to a vadProcessor using WebAudio ScriptProcessorNode.\n * Once an object is created audio from the local track flows through the ScriptProcessorNode as raw PCM.\n * The PCM is processed by the injected vad module and a voice activity detection score is obtained, the\n * score is published to consumers via an EventEmitter.\n * After work is done with this service the destroy method needs to be called for a proper cleanup.\n *\n * @fires VAD_SCORE_PUBLISHED\n */\nexport default class TrackVADEmitter extends EventEmitter {\n    /**\n     * Constructor.\n     *\n     * @param {number} procNodeSampleRate - Sample rate of the ScriptProcessorNode. Possible values  256, 512, 1024,\n     *  2048, 4096, 8192, 16384. Passing other values will default to closes neighbor.\n     * @param {Object} vadProcessor - VAD processor that allows us to calculate VAD score for PCM samples.\n     * @param {JitsiLocalTrack} jitsiLocalTrack - JitsiLocalTrack corresponding to micDeviceId.\n     */\n    constructor(procNodeSampleRate, vadProcessor, jitsiLocalTrack) {\n        super();\n\n        /**\n         * Sample rate of the ScriptProcessorNode.\n         */\n        this._procNodeSampleRate = procNodeSampleRate;\n\n        /**\n         * VAD Processor that allows us to calculate VAD score for PCM samples\n         */\n        this._vadProcessor = vadProcessor;\n\n        /**\n         * The JitsiLocalTrack instance.\n         */\n        this._localTrack = jitsiLocalTrack;\n\n        /**\n         * Buffer to hold residue PCM resulting after a ScriptProcessorNode callback\n         */\n        this._bufferResidue = new Float32Array([]);\n\n        /**\n         * The AudioContext instance with the preferred sample frequency.\n         */\n        this._audioContext = createAudioContext({ sampleRate: vadProcessor.getRequiredPCMFrequency() });\n\n        /**\n         * PCM Sample size expected by the VAD Processor instance. We cache it here as this value is used extensively,\n         * saves a couple of function calls.\n         */\n        this._vadSampleSize = vadProcessor.getSampleLength();\n\n        /**\n         * Event listener function that will be called by the ScriptProcessNode with raw PCM data, depending on the set\n         * sample rate.\n         */\n        this._onAudioProcess = this._onAudioProcess.bind(this);\n\n        this._initializeAudioContext();\n    }\n\n    /**\n     * Factory method that sets up all the necessary components for the creation of the TrackVADEmitter.\n     *\n     * @param {string} micDeviceId - Target microphone device id.\n     * @param {number} procNodeSampleRate - Sample rate of the proc node.\n     * @param {Object} vadProcessor -Module that calculates the voice activity score for a certain audio PCM sample.\n     * The processor needs to implement the following functions:\n     * - <tt>getSampleLength()</tt> - Returns the sample size accepted by getSampleLength.\n     * - <tt>getRequiredPCMFrequency()</tt> - Returns the PCM frequency at which the processor operates.\n     * - <tt>calculateAudioFrameVAD(pcmSample)</tt> - Process a 32 float pcm sample of getSampleLength size.\n     * @returns {Promise<TrackVADEmitter>} - Promise resolving in a new instance of TrackVADEmitter.\n     */\n    static create(micDeviceId, procNodeSampleRate, vadProcessor) {\n        return RTC.obtainAudioAndVideoPermissions({\n            devices: [ 'audio' ],\n            micDeviceId\n        }).then(localTrack => {\n            // We only expect one audio track when specifying a device id.\n            if (!localTrack[0]) {\n                throw new Error(`Failed to create jitsi local track for device id: ${micDeviceId}`);\n            }\n\n            return new TrackVADEmitter(procNodeSampleRate, vadProcessor, localTrack[0]);\n\n            // We have no exception handling at this point as there is nothing to clean up, the vadProcessor\n            // life cycle is handled by whoever created this instance.\n        });\n    }\n\n    /**\n     * Sets up the audio graph in the AudioContext.\n     *\n     * @returns {void}\n     */\n    _initializeAudioContext() {\n        this._audioSource = this._audioContext.createMediaStreamSource(this._localTrack.stream);\n\n        // TODO AudioProcessingNode is deprecated in the web audio specifications and the recommended replacement\n        // is audio worklet, however at the point of implementation AudioProcessingNode was still de de facto way\n        // of achieving this functionality and supported in all major browsers as opposed to audio worklet which\n        // was only available in Chrome. This todo is just a reminder that we should replace AudioProcessingNode\n        // with audio worklet when it's mature enough and has more browser support.\n        // We don't need stereo for determining the VAD score so we create a single channel processing node.\n        this._audioProcessingNode = this._audioContext.createScriptProcessor(this._procNodeSampleRate, 1, 1);\n    }\n\n    /**\n     * ScriptProcessorNode callback, the input parameters contains the PCM audio that is then sent to rnnoise.\n     * Rnnoise only accepts PCM samples of 480 bytes whereas the webaudio processor node can't sample at a multiple\n     * of 480 thus after each _onAudioProcess callback there will remain and PCM buffer residue equal\n     * to _procNodeSampleRate / 480 which will be added to the next sample buffer and so on.\\\n     *\n     *\n     * @param {AudioProcessingEvent} audioEvent - Audio event.\n     * @returns {void}\n     * @fires VAD_SCORE_PUBLISHED\n     */\n    _onAudioProcess(audioEvent) {\n        // Prepend the residue PCM buffer from the previous process callback.\n        const inData = audioEvent.inputBuffer.getChannelData(0);\n        const completeInData = [ ...this._bufferResidue, ...inData ];\n        const sampleTimestamp = Date.now();\n\n        let i = 0;\n\n        for (; i + this._vadSampleSize < completeInData.length; i += this._vadSampleSize) {\n            const pcmSample = completeInData.slice(i, i + this._vadSampleSize);\n\n            // The VAD processor might change the values inside the array so we make a copy.\n            const vadScore = this._vadProcessor.calculateAudioFrameVAD(pcmSample.slice());\n\n            this.emit(VAD_SCORE_PUBLISHED, {\n                timestamp: sampleTimestamp,\n                score: vadScore,\n                pcmData: pcmSample,\n                deviceId: this._localTrack.getDeviceId()\n            });\n        }\n\n        this._bufferResidue = completeInData.slice(i, completeInData.length);\n    }\n\n    /**\n     * Connects the nodes in the AudioContext to start the flow of audio data.\n     *\n     * @returns {void}\n     */\n    _connectAudioGraph() {\n        this._audioProcessingNode.onaudioprocess = this._onAudioProcess;\n        this._audioSource.connect(this._audioProcessingNode);\n        this._audioProcessingNode.connect(this._audioContext.destination);\n    }\n\n    /**\n     * Disconnects the nodes in the AudioContext.\n     *\n     * @returns {void}\n     */\n    _disconnectAudioGraph() {\n        // Even thought we disconnect the processing node it seems that some callbacks remain queued,\n        // resulting in calls with and uninitialized context.\n        // eslint-disable-next-line no-empty-function\n        this._audioProcessingNode.onaudioprocess = () => {};\n        this._audioProcessingNode.disconnect();\n        this._audioSource.disconnect();\n    }\n\n    /**\n     * Cleanup potentially acquired resources.\n     *\n     * @returns {void}\n     */\n    _cleanupResources() {\n        this._disconnectAudioGraph();\n        this._localTrack.stopStream();\n    }\n\n    /**\n     * Get the associated track device ID.\n     *\n     * @returns {string}\n     */\n    getDeviceId() {\n        return this._localTrack.getDeviceId();\n    }\n\n\n    /**\n     * Get the associated track label.\n     *\n     * @returns {string}\n     */\n    getTrackLabel() {\n        return this._localTrack.getDeviceLabel();\n    }\n\n    /**\n     * Start the emitter by connecting the audio graph.\n     *\n     * @returns {void}\n     */\n    start() {\n        this._connectAudioGraph();\n    }\n\n    /**\n     * Stops the emitter by disconnecting the audio graph.\n     *\n     * @returns {void}\n     */\n    stop() {\n        this._disconnectAudioGraph();\n        this._bufferResidue = [];\n    }\n\n    /**\n     * Destroy TrackVADEmitter instance (release resources and stop callbacks).\n     *\n     * @returns {void}\n     */\n    destroy() {\n        if (this._destroyed) {\n            return;\n        }\n\n        this._cleanupResources();\n        this._destroyed = true;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { EventEmitter } from 'events';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\n\nimport { DETECTOR_STATE_CHANGE, VAD_SCORE_PUBLISHED } from './DetectionEvents';\nimport TrackVADEmitter from './TrackVADEmitter';\n\nconst logger = getLogger(__filename);\n\n/**\n * Sample rate of TrackVADEmitter, it defines how many audio samples are processed at a time.\n * @type {number}\n */\nconst VAD_EMITTER_SAMPLE_RATE = 4096;\n\n/**\n * Connects a TrackVADEmitter to the target conference local audio track and manages various services that use\n * the data to produce audio analytics (VADTalkMutedDetection and VADNoiseDetection).\n */\nexport default class VADAudioAnalyser extends EventEmitter {\n    /**\n     * Creates <tt>VADAudioAnalyser</tt>\n     * @param {JitsiConference} conference - JitsiConference instance that created us.\n     * @param {Object} createVADProcessor - Function that creates a Voice activity detection processor. The processor\n     * needs to implement the following functions:\n     * - <tt>getSampleLength()</tt> - Returns the sample size accepted by getSampleLength.\n     * - <tt>getRequiredPCMFrequency()</tt> - Returns the PCM frequency at which the processor operates.\n     * - <tt>calculateAudioFrameVAD(pcmSample)</tt> - Process a 32 float pcm sample of getSampleLength size.\n     * @constructor\n     */\n    constructor(conference, createVADProcessor) {\n        super();\n\n        /**\n         * Member function that instantiates a VAD processor.\n         */\n        this._createVADProcessor = createVADProcessor;\n\n        /**\n         * Current {@link TrackVADEmitter}. VAD Emitter uses a {@link JitsiLocalTrack} and VAD processor to generate\n         * period voice probability scores.\n         */\n        this._vadEmitter = null;\n\n        /**\n         * Current state of the _vadEmitter\n         */\n        this._isVADEmitterRunning = false;\n\n        /**\n         * Array of currently attached VAD processing services.\n         */\n        this._detectionServices = [];\n\n        /**\n         * Promise used to chain create and destroy operations associated with TRACK_ADDED and TRACK_REMOVED events\n         * coming from the conference.\n         * Because we have an async created component (VAD Processor) we need to make sure that it's initialized before\n         * we destroy it ( when changing the device for instance), or when we use it from an external point of entry\n         * i.e. (TRACK_MUTE_CHANGED event callback).\n         */\n        this._vadInitTracker = Promise.resolve();\n\n        /**\n         * Listens for {@link TrackVADEmitter} events and processes them.\n         */\n        this._processVADScore = this._processVADScore.bind(this);\n\n        conference.on(JitsiConferenceEvents.TRACK_ADDED, this._trackAdded.bind(this));\n        conference.on(JitsiConferenceEvents.TRACK_REMOVED, this._trackRemoved.bind(this));\n        conference.on(JitsiConferenceEvents.TRACK_MUTE_CHANGED, this._trackMuteChanged.bind(this));\n    }\n\n    /**\n     * Attach a VAD detector service to the analyser and handle it's state changes.\n     *\n     * @param {Object} vadTMDetector\n     */\n    addVADDetectionService(vadService) {\n        this._detectionServices.push(vadService);\n        vadService.on(DETECTOR_STATE_CHANGE, () => {\n            // When the state of a detector changes check if there are any active detectors attached so that\n            // the _vadEmitter doesn't run needlessly.\n            const activeDetector = this._detectionServices.filter(detector => detector.isActive() === true);\n\n            // If there are no active detectors running and the vadEmitter is running then stop the emitter as it is\n            // uses a considerable amount of CPU. Otherwise start the service if it's stopped and there is a detector\n            // that needs it.\n            if (!activeDetector.length && this._isVADEmitterRunning) {\n                this._stopVADEmitter();\n            } else if (!this._isVADEmitterRunning) {\n                this._startVADEmitter();\n            }\n        });\n    }\n\n    /**\n     * Start the {@link TrackVADEmitter} and attach the event listener.\n     * @returns {void}\n     */\n    _startVADEmitter() {\n        if (this._vadEmitter) {\n            this._vadEmitter.on(VAD_SCORE_PUBLISHED, this._processVADScore);\n            this._vadEmitter.start();\n            this._isVADEmitterRunning = true;\n        }\n    }\n\n    /**\n     * Stop the {@link TrackVADEmitter} and detach the event listener.\n     * @returns {void}\n     */\n    _stopVADEmitter() {\n        if (this._vadEmitter) {\n            this._vadEmitter.removeListener(VAD_SCORE_PUBLISHED, this._processVADScore);\n            this._vadEmitter.stop();\n        }\n        this._isVADEmitterRunning = false;\n    }\n\n    /**\n     * Listens for {@link TrackVADEmitter} events and directs them to attached services as needed.\n     *\n     * @param {Object} vadScore -VAD score emitted by {@link TrackVADEmitter}\n     * @param {Date}   vadScore.timestamp - Exact time at which processed PCM sample was generated.\n     * @param {number} vadScore.score - VAD score on a scale from 0 to 1 (i.e. 0.7)\n     * @param {Float32Array} pcmData - Raw PCM data with which the VAD score was calculated.\n     * @param {string} vadScore.deviceId - Device id of the associated track.\n     * @listens VAD_SCORE_PUBLISHED\n     */\n    _processVADScore(vadScore) {\n        for (const detector of this._detectionServices) {\n            detector.processVADScore(vadScore);\n        }\n    }\n\n    /**\n     * Change the isMuted state of all attached detection services.\n     *\n     * @param {boolean} isMuted\n     */\n    _changeDetectorsMuteState(isMuted) {\n        for (const detector of this._detectionServices) {\n            detector.changeMuteState(isMuted);\n        }\n    }\n\n    /**\n     * Notifies the detector that a track was added to the associated {@link JitsiConference}.\n     * Only take into account local audio tracks.\n     * @param {JitsiTrack} track - The added track.\n     * @returns {void}\n     * @listens TRACK_ADDED\n     */\n    _trackAdded(track) {\n        if (track.isLocalAudioTrack()) {\n            // Keep a track promise so we take into account successive TRACK_ADD events being generated so that we\n            // destroy/create the processing context in the proper order.\n            this._vadInitTracker = this._vadInitTracker.then(() => this._createVADProcessor())\n                .then(vadProcessor =>\n                    TrackVADEmitter.create(track.getDeviceId(), VAD_EMITTER_SAMPLE_RATE, vadProcessor)\n                )\n                .then(vadEmitter => {\n                    logger.debug('Created VAD emitter for track: ', track.getTrackLabel());\n\n                    this._vadEmitter = vadEmitter;\n\n                    // Iterate through the detection services and set their appropriate mute state, depending on\n                    // service this will trigger a DETECTOR_STATE_CHANGE which in turn might start the _vadEmitter.\n                    this._changeDetectorsMuteState(track.isMuted());\n                })\n                .catch(error => {\n                    logger.warn('Failed to start VADAudioAnalyser', error);\n                });\n        }\n    }\n\n    /**\n     * Notifies the detector that the mute state of a {@link JitsiConference} track has changed. Only takes into account\n     * local audio tracks.\n     * @param {JitsiTrack} track - The track whose mute state has changed.\n     * @returns {void}\n     * @listens TRACK_MUTE_CHANGED\n     */\n    _trackMuteChanged(track) {\n        if (track.isLocalAudioTrack()) {\n            // On a mute toggle reset the state.\n            this._vadInitTracker = this._vadInitTracker.then(() => {\n                // Set mute status for the attached detection services.\n                this._changeDetectorsMuteState(track.isMuted());\n            });\n        }\n    }\n\n    /**\n     * Notifies the detector that a track associated with the {@link JitsiConference} was removed. Only takes into\n     * account local audio tracks. Cleans up resources associated with the track and resets the processing context.\n     *\n     * @param {JitsiTrack} track - The removed track.\n     * @returns {void}\n     * @listens TRACK_REMOVED\n     */\n    _trackRemoved(track) {\n        if (track.isLocalAudioTrack()) {\n            // Use the promise to make sure operations are in sequence.\n            this._vadInitTracker = this._vadInitTracker.then(() => {\n                logger.debug('Removing track from VAD detection - ', track.getTrackLabel());\n\n                // Track was removed, clean up and set appropriate states.\n                if (this._vadEmitter) {\n                    this._stopVADEmitter();\n                    this._vadEmitter.destroy();\n                    this._vadEmitter = null;\n                }\n\n                // Reset state of detectors when active track is removed.\n                for (const detector of this._detectionServices) {\n                    detector.reset();\n                }\n            });\n        }\n    }\n\n\n}\n","import { EventEmitter } from 'events';\n\nimport { calculateAverage, filterPositiveValues } from '../util/MathUtil';\n\nimport { DETECTOR_STATE_CHANGE, VAD_NOISY_DEVICE } from './DetectionEvents';\n\n/**\n * The average value VAD needs to be under over a period of time to be considered noise.\n * @type {number}\n */\nconst VAD_NOISE_AVG_THRESHOLD = 0.2;\n\n/**\n * The average values that audio input need to be over to be considered loud.\n * @type {number}\n */\nconst NOISY_AUDIO_LEVEL_THRESHOLD = 0.040;\n\n/**\n * The value that a VAD score needs to be under in order for processing to begin.\n * @type {number}\n */\nconst VAD_SCORE_TRIGGER = 0.2;\n\n/**\n * The value that a VAD score needs to be under in order for processing to begin.\n * @type {number}\n */\nconst AUDIO_LEVEL_SCORE_TRIGGER = 0.020;\n\n/**\n * Time span over which we calculate an average score used to determine if we trigger the event.\n * @type {number}\n */\nconst PROCESS_TIME_FRAME_SPAN_MS = 1500;\n\n/**\n * Detect if provided VAD score and PCM data is considered noise.\n */\nexport default class VADNoiseDetection extends EventEmitter {\n    /**\n     * Creates <tt>VADNoiseDetection</tt>\n     *\n     * @constructor\n     */\n    constructor() {\n        super();\n\n        /**\n         * Flag which denotes the current state of the detection service i.e.if there is already a processing operation\n         * ongoing.\n         */\n        this._processing = false;\n\n        /**\n         * Buffer that keeps the VAD scores for a period of time.\n         */\n        this._scoreArray = [];\n\n        /**\n         * Buffer that keeps audio level samples for a period of time.\n         */\n        this._audioLvlArray = [];\n\n        /**\n         * Current state of the service, if it's not active no processing will occur.\n         */\n        this._active = false;\n\n        this._calculateNoisyScore = this._calculateNoisyScore.bind(this);\n    }\n\n    /**\n     * Compute cumulative VAD score and PCM audio levels once the PROCESS_TIME_FRAME_SPAN_MS timeout has elapsed.\n     * If the score is above the set threshold fire the event.\n     * @returns {void}\n     * @fires VAD_NOISY_DEVICE\n     */\n    _calculateNoisyScore() {\n        const scoreAvg = calculateAverage(this._scoreArray);\n        const audioLevelAvg = calculateAverage(this._audioLvlArray);\n\n        if (scoreAvg < VAD_NOISE_AVG_THRESHOLD && audioLevelAvg > NOISY_AUDIO_LEVEL_THRESHOLD) {\n            this.emit(VAD_NOISY_DEVICE);\n\n            this._setActiveState(false);\n        }\n\n        // We reset the context in case a new process phase needs to be triggered.\n        this.reset();\n    }\n\n    /**\n     * Record the vad score and average volume in the appropriate buffers.\n     *\n     * @param {number} vadScore\n     * @param {number} avgAudioLvl - average audio level of the PCM sample associated with the VAD score.s\n     */\n    _recordValues(vadScore, avgAudioLvl) {\n        this._scoreArray.push(vadScore);\n        this._audioLvlArray.push(avgAudioLvl);\n    }\n\n    /**\n     * Set the active state of the detection service and notify any listeners.\n     *\n     * @param {boolean} active\n     * @fires DETECTOR_STATE_CHANGE\n     */\n    _setActiveState(active) {\n        this._active = active;\n        this.emit(DETECTOR_STATE_CHANGE, this._active);\n    }\n\n    /**\n     * Change the state according to the muted status of the tracked device.\n     *\n     * @param {boolean} isMuted - Is the device muted or not.\n     */\n    changeMuteState(isMuted) {\n        // This service only needs to run when the microphone is not muted.\n        this._setActiveState(!isMuted);\n        this.reset();\n    }\n\n    /**\n     * Check whether or not the service is active or not.\n     *\n     * @returns {boolean}\n     */\n    isActive() {\n        return this._active;\n    }\n\n    /**\n     * Reset the processing context, clear buffers, cancel the timeout trigger.\n     *\n     * @returns {void}\n     */\n    reset() {\n        this._processing = false;\n        this._scoreArray = [];\n        this._audioLvlArray = [];\n        clearTimeout(this._processTimeout);\n    }\n\n    /**\n     * Listens for {@link TrackVADEmitter} events and processes them.\n     *\n     * @param {Object} vadScore -VAD score emitted by {@link TrackVADEmitter}\n     * @param {Date}   vadScore.timestamp - Exact time at which processed PCM sample was generated.\n     * @param {number} vadScore.score - VAD score on a scale from 0 to 1 (i.e. 0.7)\n     * @param {Float32Array} vadScore.pcmData - Raw PCM Data associated with the VAD score.\n     * @param {string} vadScore.deviceId - Device id of the associated track.\n     * @listens VAD_SCORE_PUBLISHED\n     */\n    processVADScore(vadScore) {\n        if (!this._active) {\n            return;\n        }\n\n        // There is a processing phase on going, add score to buffer array.\n        if (this._processing) {\n            // Filter and calculate sample average so we don't have to process one large array at a time.\n            const posAudioLevels = filterPositiveValues(vadScore.pcmData);\n\n            this._recordValues(vadScore.score, calculateAverage(posAudioLevels));\n\n            return;\n        }\n\n        // If the VAD score for the sample is low and audio level has a high enough level we can start listening for\n        // noise\n        if (vadScore.score < VAD_SCORE_TRIGGER) {\n            const posAudioLevels = filterPositiveValues(vadScore.pcmData);\n            const avgAudioLvl = calculateAverage(posAudioLevels);\n\n            if (avgAudioLvl > AUDIO_LEVEL_SCORE_TRIGGER) {\n                this._processing = true;\n                this._recordValues(vadScore.score, avgAudioLvl);\n\n                // Once the preset timeout executes the final score will be calculated.\n                this._processTimeout = setTimeout(this._calculateNoisyScore, PROCESS_TIME_FRAME_SPAN_MS);\n            }\n        }\n    }\n}\n","import { EventEmitter } from 'events';\n\nimport { calculateAverage } from '../util/MathUtil';\n\nimport { DETECTOR_STATE_CHANGE, VAD_TALK_WHILE_MUTED } from './DetectionEvents';\n\n\n/**\n * The threshold which the average VAD values for a span of time needs to exceed to trigger an event.\n * @type {number}\n */\nconst VAD_AVG_THRESHOLD = 0.6;\n\n/**\n * The VAD score needed to trigger the processing algorithm, i.e. if a sample has the VAD score >= VAD_VOICE_LEVEL\n * we start processing all scores for a time span defined by const PROCESS_TIME_FRAME_SPAN_MS.\n * @type {number}\n */\nconst VAD_VOICE_LEVEL = 0.9;\n\n/**\n * Sample rate of TrackVADEmitter, it defines how many audio samples are processed at a time.\n * @type {number}\n */\n\n/**\n * Time span over which we calculate an average score used to determine if we trigger the event.\n * @type {number}\n */\nconst PROCESS_TIME_FRAME_SPAN_MS = 700;\n\n/**\n * Detect if provided VAD score which is generated on a muted device is voice and fires an event.\n */\nexport default class VADTalkMutedDetection extends EventEmitter {\n    /**\n     * Creates <tt>VADTalkMutedDetection</tt>\n     * @constructor\n     */\n    constructor() {\n        super();\n\n        /**\n         * Flag which denotes the current state of the detection service i.e.if there is already a processing operation\n         * ongoing.\n         */\n        this._processing = false;\n\n        /**\n         * Buffer that keeps the VAD scores for a period of time.\n         */\n        this._scoreArray = [];\n\n        /**\n         * Current mute state of the audio track being monitored.\n         */\n        this._active = false;\n\n        this._calculateVADScore = this._calculateVADScore.bind(this);\n    }\n\n    /**\n     * Compute cumulative VAD score function called once the PROCESS_TIME_FRAME_SPAN_MS timeout has elapsed.\n     * @returns {void}\n     * @fires VAD_TALK_WHILE_MUTED\n     */\n    _calculateVADScore() {\n        const score = calculateAverage(this._scoreArray);\n\n        if (score > VAD_AVG_THRESHOLD) {\n            this.emit(VAD_TALK_WHILE_MUTED);\n\n            // Event was fired. Stop event emitter and remove listeners so no residue events kick off after this point\n            // and a single VAD_TALK_WHILE_MUTED is generated per mic muted state.\n            this._setActiveState(false);\n        }\n\n        // We reset the context in case a new process phase needs to be triggered.\n        this.reset();\n    }\n\n    /**\n     * Set the active state of the detection service and notify any listeners.\n     *\n     * @param {boolean} active\n     * @fires DETECTOR_STATE_CHANGE\n     */\n    _setActiveState(active) {\n        this._active = active;\n        this.emit(DETECTOR_STATE_CHANGE, this._active);\n    }\n\n    /**\n     * Change the state according to the muted status of the tracked device.\n     *\n     * @param {boolean} isMuted - Is the device muted or not.\n     */\n    changeMuteState(isMuted) {\n        // This service only needs to run when the microphone is muted.\n        this._setActiveState(isMuted);\n        this.reset();\n    }\n\n    /**\n     * Check whether or not the service is active or not.\n     *\n     * @returns {boolean}\n     */\n    isActive() {\n        return this._active;\n    }\n\n    /**\n     * Listens for {@link TrackVADEmitter} events and processes them.\n     *\n     * @param {Object} vadScore -VAD score emitted by {@link TrackVADEmitter}\n     * @param {Date}   vadScore.timestamp - Exact time at which processed PCM sample was generated.\n     * @param {number} vadScore.score - VAD score on a scale from 0 to 1 (i.e. 0.7)\n     * @param {string} vadScore.deviceId - Device id of the associated track.\n     * @listens VAD_SCORE_PUBLISHED\n     */\n    processVADScore(vadScore) {\n        if (!this._active) {\n            return;\n        }\n\n        // There is a processing phase on going, add score to buffer array.\n        if (this._processing) {\n            this._scoreArray.push(vadScore.score);\n\n            return;\n        }\n\n        // Because we remove all listeners on the vadEmitter once the main event is triggered,\n        // there is no need to check for rogue events.\n        if (vadScore.score > VAD_VOICE_LEVEL) {\n            this._processing = true;\n            this._scoreArray.push(vadScore.score);\n\n            // Start gathering VAD scores for the configured period of time.\n            this._processTimeout = setTimeout(this._calculateVADScore, PROCESS_TIME_FRAME_SPAN_MS);\n        }\n    }\n\n    /**\n     * Reset the processing context, clear buffer, cancel the timeout trigger.\n     *\n     * @returns {void}\n     */\n    reset() {\n        this._processing = false;\n        this._scoreArray = [];\n        clearTimeout(this._processTimeout);\n    }\n}\n","export enum E2ePingEvents {\n    /**\n     * Indicates that the end-to-end round-trip-time for a participant has changed.\n     */\n    E2E_RTT_CHANGED = 'e2eping.e2e_rtt_changed'\n};\n\n// exported for backward compatibility\nexport const E2E_RTT_CHANGED = E2ePingEvents.E2E_RTT_CHANGED;\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport * as JitsiE2EPingEvents from '../../service/e2eping/E2ePingEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * The 'type' of a message which designates an e2e ping request.\n * @type {string}\n */\nconst E2E_PING_REQUEST = 'e2e-ping-request';\n\n/**\n * The 'type' of a message which designates an e2e ping response.\n * @type {string}\n */\nconst E2E_PING_RESPONSE = 'e2e-ping-response';\n\n/**\n * The number of requests to wait for before emitting an RTT value.\n */\nconst DEFAULT_NUM_REQUESTS = 5;\n\n/**\n * The maximum number of messages per second to aim for. This is for the entire\n * conference, with the assumption that all endpoints join at once.\n */\nconst DEFAULT_MAX_MESSAGES_PER_SECOND = 250;\n\n/**\n * The conference size beyond which e2e pings will be disabled.\n */\nconst DEFAULT_MAX_CONFERENCE_SIZE = 200;\n\n/**\n * Saves e2e ping related state for a single JitsiParticipant.\n */\nclass ParticipantWrapper {\n    /**\n     * Creates a ParticipantWrapper\n     * @param {JitsiParticipant} participant - The remote participant that this\n     * object wraps.\n     * @param {E2ePing} e2eping\n     */\n    constructor(participant, e2eping) {\n        // The JitsiParticipant\n        this.participant = participant;\n\n        // The E2ePing\n        this.e2eping = e2eping;\n\n        // Caches the ID\n        this.id = participant.getId();\n\n        // Recently sent requests\n        this.requests = {};\n\n        // The ID of the last sent request. We just increment it for each new\n        // request. Start at 1 so we can consider only thruthy values valid.\n        this.lastRequestId = 1;\n\n        this.sendRequest = this.sendRequest.bind(this);\n        this.handleResponse = this.handleResponse.bind(this);\n        this.maybeLogRttAndStop = this.maybeLogRttAndStop.bind(this);\n        this.scheduleNext = this.scheduleNext.bind(this);\n        this.stop = this.stop.bind(this);\n        this.getDelay = this.getDelay.bind(this);\n        this.timeout = this.scheduleNext();\n    }\n\n    /**\n     * Schedule the next ping to be sent.\n     */\n    scheduleNext() {\n        return window.setTimeout(this.sendRequest, this.getDelay());\n    }\n\n    /**\n     * Stop pinging this participant, canceling a scheduled ping, if any.\n     */\n    stop() {\n        if (this.timeout) {\n            window.clearTimeout(this.timeout);\n        }\n        this.e2eping.removeParticipant(this.id);\n    }\n\n    /**\n     * Get the delay until the next ping in milliseconds.\n     */\n    getDelay() {\n        const conferenceSize = this.e2eping.conference.getParticipants().length;\n        const endpointPairs = conferenceSize * (conferenceSize - 1) / 2;\n        const totalMessages = endpointPairs * this.e2eping.numRequests;\n        const totalSeconds = totalMessages / this.e2eping.maxMessagesPerSecond;\n\n        // Randomize between .5 and 1.5\n        const r = 1.5 - Math.random();\n        const delayBetweenMessages = r * Math.max(1000 * (totalSeconds / this.e2eping.numRequests), 1000);\n\n        return delayBetweenMessages;\n    }\n\n    /**\n     * Sends the next ping request.\n     * @type {*}\n     */\n    sendRequest() {\n        const requestId = this.lastRequestId++;\n        const requestMessage = {\n            type: E2E_PING_REQUEST,\n            id: requestId\n        };\n\n        this.e2eping.sendMessage(requestMessage, this.id);\n        this.requests[requestId] = {\n            id: requestId,\n            timeSent: window.performance.now()\n        };\n    }\n\n    /**\n     * Handles a response from this participant.\n     * @type {*}\n     */\n    handleResponse(response) {\n        const request = this.requests[response.id];\n\n        if (request) {\n            request.rtt = window.performance.now() - request.timeSent;\n        }\n        this.maybeLogRttAndStop();\n    }\n\n    /**\n     * Check if we've received the pre-configured number of responses, and if\n     * so log the measured RTT and stop sending requests.\n     * @type {*}\n     */\n    maybeLogRttAndStop() {\n        // The RTT we'll report is the minimum RTT measured\n        let rtt = Infinity;\n        let request, requestId;\n        let numRequestsWithResponses = 0;\n        let totalNumRequests = 0;\n\n        for (requestId in this.requests) {\n            if (this.requests.hasOwnProperty(requestId)) {\n                request = this.requests[requestId];\n\n                totalNumRequests++;\n                if (request.rtt) {\n                    numRequestsWithResponses++;\n                    rtt = Math.min(rtt, request.rtt);\n                }\n            }\n        }\n\n        if (numRequestsWithResponses >= this.e2eping.numRequests) {\n            logger.info(`Measured RTT=${rtt} ms to ${this.id} (in ${this.participant.getProperty('region')})`);\n            this.stop();\n\n            this.e2eping.conference.eventEmitter.emit(\n                JitsiE2EPingEvents.E2E_RTT_CHANGED, this.participant, rtt);\n\n            return;\n        } else if (totalNumRequests > 2 * this.e2eping.numRequests) {\n            logger.info(`Stopping e2eping for ${this.id} because we sent ${totalNumRequests} with only `\n                + `${numRequestsWithResponses} responses.`);\n            this.stop();\n\n            return;\n        }\n\n        this.timeout = this.scheduleNext();\n    }\n}\n\n/**\n * Implements end-to-end ping (from one conference participant to another) via\n * the jitsi-videobridge channel (either WebRTC data channel or web socket).\n *\n * TODO: use a broadcast message instead of individual pings to each remote\n * participant.\n *\n * This class:\n * 1. Sends periodic ping requests to all other participants in the\n * conference.\n * 2. Responds to ping requests from other participants.\n * 3. Fires events with the end-to-end RTT to each participant whenever a\n * response is received.\n * 4. Fires analytics events with the end-to-end RTT periodically.\n */\nexport default class E2ePing {\n    /**\n     * @param {JitsiConference} conference - The conference.\n     * @param {Function} sendMessage - The function to use to send a message.\n     * @param {Object} options\n     */\n    constructor(conference, options, sendMessage) {\n        this.conference = conference;\n        this.eventEmitter = conference.eventEmitter;\n        this.sendMessage = sendMessage;\n\n        // Maps a participant ID to its ParticipantWrapper\n        this.participants = {};\n\n        this.numRequests = DEFAULT_NUM_REQUESTS;\n        this.maxConferenceSize = DEFAULT_MAX_CONFERENCE_SIZE;\n        this.maxMessagesPerSecond = DEFAULT_MAX_MESSAGES_PER_SECOND;\n\n        if (options && options.e2eping) {\n            if (typeof options.e2eping.numRequests === 'number') {\n                this.numRequests = options.e2eping.numRequests;\n            }\n            if (typeof options.e2eping.maxConferenceSize === 'number') {\n                this.maxConferenceSize = options.e2eping.maxConferenceSize;\n            }\n            if (typeof options.e2eping.maxMessagesPerSecond === 'number') {\n                this.maxMessagesPerSecond = options.e2eping.maxMessagesPerSecond;\n            }\n        }\n        logger.info(\n            `Initializing e2e ping with numRequests=${this.numRequests}, maxConferenceSize=${this.maxConferenceSize}, `\n            + `maxMessagesPerSecond=${this.maxMessagesPerSecond}.`);\n\n        this.participantJoined = this.participantJoined.bind(this);\n\n        this.participantLeft = this.participantLeft.bind(this);\n        conference.on(JitsiConferenceEvents.USER_LEFT, this.participantLeft);\n\n        this.messageReceived = this.messageReceived.bind(this);\n        conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, this.messageReceived);\n\n        this.conferenceJoined = this.conferenceJoined.bind(this);\n        conference.on(JitsiConferenceEvents.CONFERENCE_JOINED, this.conferenceJoined);\n    }\n\n    /**\n     * Delay processing USER_JOINED events until the MUC is fully joined,\n     * otherwise the apparent conference size will be wrong.\n     */\n    conferenceJoined() {\n        this.conference.getParticipants().forEach(p => this.participantJoined(p.getId(), p));\n        this.conference.on(JitsiConferenceEvents.USER_JOINED, this.participantJoined);\n    }\n\n    /**\n     * Handles a message that was received.\n     *\n     * @param participant - The message sender.\n     * @param payload - The payload of the message.\n     */\n    messageReceived(participant, payload) {\n        // Listen to E2E PING requests and responses from other participants\n        // in the conference.\n        if (payload.type === E2E_PING_REQUEST) {\n            this.handleRequest(participant.getId(), payload);\n        } else if (payload.type === E2E_PING_RESPONSE) {\n            this.handleResponse(participant.getId(), payload);\n        }\n    }\n\n    /**\n     * Handles a participant joining the conference. Starts to send ping\n     * requests to the participant.\n     *\n     * @param {String} id - The ID of the participant.\n     * @param {JitsiParticipant} participant - The participant that joined.\n     */\n    participantJoined(id, participant) {\n        if (this.participants[id]) {\n            logger.info(`Participant wrapper already exists for ${id}. Clearing.`);\n            this.participants[id].stop();\n        }\n\n        if (this.conference.getParticipants().length > this.maxConferenceSize) {\n            return;\n        }\n\n        // We don't need to send e2eping in both directions for a pair of\n        // endpoints. Force only one direction with just string comparison of\n        // the IDs.\n        if (this.conference.myUserId() > id) {\n            logger.info(`Starting e2eping for participant ${id}`);\n            this.participants[id] = new ParticipantWrapper(participant, this);\n        }\n    }\n\n    /**\n     * Remove a participant without calling \"stop\".\n     */\n    removeParticipant(id) {\n        if (this.participants[id]) {\n            delete this.participants[id];\n        }\n    }\n\n    /**\n     * Handles a participant leaving the conference. Stops sending requests.\n     *\n     * @param {String} id - The ID of the participant.\n     */\n    participantLeft(id) {\n        if (this.participants[id]) {\n            this.participants[id].stop();\n            delete this.participants[id];\n        }\n    }\n\n    /**\n     * Handles a ping request coming from another participant.\n     *\n     * @param {string} participantId - The ID of the participant who sent the\n     * request.\n     * @param {Object} request - The request.\n     */\n    handleRequest(participantId, request) {\n        // If it's a valid request, just send a response.\n        if (request && request.id) {\n            const response = {\n                type: E2E_PING_RESPONSE,\n                id: request.id\n            };\n\n            this.sendMessage(response, participantId);\n        } else {\n            logger.info(`Received an invalid e2e ping request from ${participantId}.`);\n        }\n    }\n\n    /**\n     * Handles a ping response coming from another participant\n     * @param {string} participantId - The ID of the participant who sent the\n     * response.\n     * @param {Object} response - The response.\n     */\n    handleResponse(participantId, response) {\n        const participantWrapper = this.participants[participantId];\n\n        if (participantWrapper) {\n            participantWrapper.handleResponse(response);\n        }\n    }\n\n    /**\n     * Stops this E2ePing (i.e. stop sending requests).\n     */\n    stop() {\n        logger.info('Stopping e2eping');\n\n        this.conference.off(JitsiConferenceEvents.USER_JOINED, this.participantJoined);\n        this.conference.off(JitsiConferenceEvents.USER_LEFT, this.participantLeft);\n        this.conference.off(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, this.messageReceived);\n\n        for (const id in this.participants) {\n            if (this.participants.hasOwnProperty(id)) {\n                this.participants[id].stop();\n            }\n        }\n\n        this.participants = {};\n    }\n}\n\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * Emits {@link JitsiConferenceEvents.JVB121_STATUS} events based on the current\n * P2P status and the conference participants count. See the event description\n * for more info.\n */\nexport default class Jvb121EventGenerator {\n    /**\n     * Creates new <tt>Jvb121EventGenerator</tt> for the given conference.\n     * @param {JitsiConference} conference\n     */\n    constructor(conference) {\n        this._conference = conference;\n\n        /**\n         * Indicates whether it's a one to one JVB conference (<tt>true</tt>)\n         * or a multiparty (<tt>false</tt>). Will be also <tt>false</tt> if\n         * the conference is currently in the P2P mode.\n         * @type {boolean}\n         * @private\n         */\n        this._jvb121 = true;\n\n        this._conference.addEventListener(\n            JitsiConferenceEvents.USER_JOINED, () => this.evaluateStatus());\n        this._conference.addEventListener(\n            JitsiConferenceEvents.USER_LEFT, () => this.evaluateStatus());\n        this._conference.addEventListener(\n            JitsiConferenceEvents.P2P_STATUS, () => this.evaluateStatus());\n    }\n\n    /**\n     * Checks whether the JVB121 value should be updated and a new event\n     * emitted.\n     */\n    evaluateStatus() {\n        const oldStatus = this._jvb121;\n        const newStatus\n            = !this._conference.isP2PActive()\n                && this._conference.getParticipantCount() <= 2;\n\n        if (oldStatus !== newStatus) {\n            this._jvb121 = newStatus;\n            logger.debug(`JVB121 status ${oldStatus} => ${newStatus}`);\n            this._conference.eventEmitter.emit(\n                JitsiConferenceEvents.JVB121_STATUS, oldStatus, newStatus);\n        }\n    }\n}\n","/* global TransformStream */\nimport { getLogger } from '@jitsi/logger';\n\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport FeatureFlags from '../flags/FeatureFlags';\n\n// Flag to set on receivers to avoid setting up the lite mode\n// more than once.\nconst kJitsiLiteMode = Symbol('kJitsiLiteMode');\n\nconst logger = getLogger(__filename);\n\n/**\n * This module implements a discard-all insertable stream.  Use to reduce decoder CPU load for testing.\n */\nexport class LiteModeContext {\n    /**\n     * A constructor.\n     * @param {JitsiConference} conference - The conference instance for which lite mode is to be enabled.\n     */\n    constructor(conference) {\n        this.enabled = FeatureFlags.isRunInLiteModeEnabled();\n        if (!this.enabled) {\n            return;\n        }\n\n        conference.rtc.on(\n            RTCEvents.REMOTE_TRACK_ADDED,\n            (track, tpc) => this._setupLiteModeForTrack(tpc, track));\n    }\n\n    /**\n     * Setup Lite Mode for a track.\n     *\n     * @private\n     */\n    _setupLiteModeForTrack(tpc, track) {\n        if (!this.enabled) {\n            return;\n        }\n\n        const receiver = tpc.findReceiverForTrack(track.track);\n\n        if (!receiver) {\n            logger.warn(`Could not set up lite mode for ${track}: receiver not found in: ${tpc}`);\n\n            return;\n        }\n\n        if (receiver[kJitsiLiteMode]) {\n            return;\n        }\n        receiver[kJitsiLiteMode] = true;\n\n        const receiverStreams = receiver.createEncodedStreams();\n\n        const transformStream = new TransformStream({\n            transform: () => {\n                // Don't call controller.enqueue(encodedFrame), and so drop everything\n            }\n        });\n\n        receiverStreams.readable.pipeThrough(transformStream).pipeTo(receiverStreams.writable);\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport isEqual from 'lodash.isequal';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport { MediaType } from '../../service/RTC/MediaType';\n\nconst logger = getLogger(__filename);\nconst MAX_HEIGHT = 2160;\nconst LASTN_UNLIMITED = -1;\nconst ASSUMED_BANDWIDTH_BPS = -1;\n\n/**\n * This class translates the legacy signaling format between the client and the bridge (that affects bandwidth\n * allocation) to the new format described here https://github.com/jitsi/jitsi-videobridge/blob/master/doc/allocation.md\n */\nclass ReceiverVideoConstraints {\n    /**\n     * Creates a new instance.\n     * @param {Object} options - The instance options:\n     * - lastN: Number of videos to be requested from the bridge.\n     * - assumedBandwidthBps: Number of bps to be requested from the bridge.\n     */\n    constructor(options) {\n        const { lastN, assumedBandwidthBps } = options;\n\n        // The number of videos requested from the bridge.\n        this._lastN = lastN ?? LASTN_UNLIMITED;\n\n        // The number representing the maximum video height the local client should receive from the bridge/peer.\n        this._maxFrameHeight = MAX_HEIGHT;\n\n        // The number representing the assumed count of bps the local client should receive from the bridge.\n        this._assumedBandwidthBps = assumedBandwidthBps ?? ASSUMED_BANDWIDTH_BPS;\n\n        this._receiverVideoConstraints = {\n            assumedBandwidthBps: this._assumedBandwidthBps,\n            constraints: {},\n            defaultConstraints: { 'maxHeight': this._maxFrameHeight },\n            lastN: this._lastN\n        };\n    }\n\n    /**\n     * Returns the receiver video constraints that need to be sent on the bridge channel or to the remote peer.\n     */\n    get constraints() {\n        this._receiverVideoConstraints.assumedBandwidthBps = this._assumedBandwidthBps;\n        this._receiverVideoConstraints.lastN = this._lastN;\n        if (Object.keys(this._receiverVideoConstraints.constraints)?.length) {\n            /* eslint-disable no-unused-vars */\n            for (const [ key, value ] of Object.entries(this._receiverVideoConstraints.constraints)) {\n                value.maxHeight = this._maxFrameHeight;\n            }\n        } else {\n            this._receiverVideoConstraints.defaultConstraints = { 'maxHeight': this._maxFrameHeight };\n        }\n\n        return this._receiverVideoConstraints;\n    }\n\n\n    /**\n     * Updates the assumed bandwidth bps of the ReceiverVideoConstraints sent to the bridge.\n     *\n     * @param {number} assumedBandwidthBps\n     * @requires {boolean} Returns true if the the value has been updated, false otherwise.\n     */\n    updateAssumedBandwidthBps(assumedBandwidthBps) {\n        const changed = this._assumedBandwidthBps !== assumedBandwidthBps;\n\n        if (changed) {\n            this._assumedBandwidthBps = assumedBandwidthBps;\n            logger.debug(`Updating receive assumedBandwidthBps: ${assumedBandwidthBps}`);\n        }\n\n        return changed;\n    }\n\n    /**\n     * Updates the lastN field of the ReceiverVideoConstraints sent to the bridge.\n     *\n     * @param {number} value\n     * @returns {boolean} Returns true if the the value has been updated, false otherwise.\n     */\n    updateLastN(value) {\n        const changed = this._lastN !== value;\n\n        if (changed) {\n            this._lastN = value;\n            logger.debug(`Updating ReceiverVideoConstraints lastN(${value})`);\n        }\n\n        return changed;\n    }\n\n    /**\n     * Updates the resolution (height requested) in the contraints field of the ReceiverVideoConstraints\n     * sent to the bridge.\n     *\n     * @param {number} maxFrameHeight\n     * @requires {boolean} Returns true if the the value has been updated, false otherwise.\n     */\n    updateReceiveResolution(maxFrameHeight) {\n        const changed = this._maxFrameHeight !== maxFrameHeight;\n\n        if (changed) {\n            this._maxFrameHeight = maxFrameHeight;\n            logger.debug(`Updating receive maxFrameHeight: ${maxFrameHeight}`);\n        }\n\n        return changed;\n    }\n\n    /**\n     * Updates the receiver constraints sent to the bridge.\n     *\n     * @param {Object} videoConstraints\n     * @returns {boolean} Returns true if the the value has been updated, false otherwise.\n     */\n    updateReceiverVideoConstraints(videoConstraints) {\n        const changed = !isEqual(this._receiverVideoConstraints, videoConstraints);\n\n        if (changed) {\n            this._receiverVideoConstraints = videoConstraints;\n            logger.debug(`Updating ReceiverVideoConstraints ${JSON.stringify(videoConstraints)}`);\n        }\n\n        return changed;\n    }\n}\n\n/**\n * This class manages the receive video contraints for a given {@link JitsiConference}. These constraints are\n * determined by the application based on how the remote video streams need to be displayed. This class is responsible\n * for communicating these constraints to the bridge over the bridge channel.\n */\nexport default class ReceiveVideoController {\n    /**\n     * Creates a new instance for a given conference.\n     *\n     * @param {JitsiConference} conference the conference instance for which the new instance will be managing\n     * the receive video quality constraints.\n     * @param {RTC} rtc the rtc instance which is responsible for initializing the bridge channel.\n     */\n    constructor(conference, rtc) {\n        this._conference = conference;\n        this._rtc = rtc;\n        const { config } = conference.options;\n\n        // The number of videos requested from the bridge, -1 represents unlimited or all available videos.\n        this._lastN = config?.startLastN ?? (config?.channelLastN || LASTN_UNLIMITED);\n\n        // The number representing the maximum video height the local client should receive from the bridge.\n        this._maxFrameHeight = MAX_HEIGHT;\n\n        /**\n         * The map that holds the max frame height requested per remote source for p2p connection.\n         *\n         * @type Map<string, number>\n         */\n        this._sourceReceiverConstraints = new Map();\n\n        /**\n         * The number of bps requested from the bridge.\n         */\n        this._assumedBandwidthBps = ASSUMED_BANDWIDTH_BPS;\n\n        // The default receiver video constraints.\n        this._receiverVideoConstraints = new ReceiverVideoConstraints({\n            lastN: this._lastN,\n            assumedBandwidthBps: this._assumedBandwidthBps\n        });\n\n        this._conference.on(\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\n            session => this._onMediaSessionStarted(session));\n    }\n\n    /**\n     * Returns a map of all the remote source names and the corresponding max frame heights.\n     *\n     * @param {JingleSessionPC} mediaSession - the media session.\n     * @param {number} maxFrameHeight - the height to be requested for remote sources.\n     * @returns\n     */\n    _getDefaultSourceReceiverConstraints(mediaSession, maxFrameHeight) {\n        const height = maxFrameHeight ?? MAX_HEIGHT;\n        const remoteVideoTracks = mediaSession.peerconnection?.getRemoteTracks(null, MediaType.VIDEO) || [];\n        const receiverConstraints = new Map();\n\n        for (const track of remoteVideoTracks) {\n            receiverConstraints.set(track.getSourceName(), height);\n        }\n\n        return receiverConstraints;\n    }\n\n    /**\n     * Handles the {@link JitsiConferenceEvents.MEDIA_SESSION_STARTED}, that is when the conference creates new media\n     * session. The preferred receive frameHeight is applied on the media session.\n     *\n     * @param {JingleSessionPC} mediaSession - the started media session.\n     * @returns {void}\n     * @private\n     */\n    _onMediaSessionStarted(mediaSession) {\n        if (mediaSession.isP2P) {\n            mediaSession.setReceiverVideoConstraint(this._getDefaultSourceReceiverConstraints(mediaSession));\n        } else {\n            this._rtc.setReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\n        }\n    }\n\n    /**\n     * Returns the lastN value for the conference.\n     *\n     * @returns {number}\n     */\n    getLastN() {\n        return this._lastN;\n    }\n\n    /**\n     * Sets the assumed bandwidth bps the local participant should receive from remote participants.\n     *\n     * @param {number|undefined} assumedBandwidthBps - the new value.\n     * @returns {void}\n     */\n    setAssumedBandwidthBps(assumedBandwidthBps) {\n        if (this._receiverVideoConstraints.updateAssumedBandwidthBps(assumedBandwidthBps)) {\n            this._rtc.setReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\n        }\n    }\n\n    /**\n     * Selects a new value for \"lastN\". The requested amount of videos are going to be delivered after the value is\n     * in effect. Set to -1 for unlimited or all available videos.\n     *\n     * @param {number} value the new value for lastN.\n     * @returns {void}\n     */\n    setLastN(value) {\n        if (this._lastN !== value) {\n            this._lastN = value;\n            if (this._receiverVideoConstraints.updateLastN(value)) {\n                this._rtc.setReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\n            }\n        }\n    }\n\n    /**\n     * Sets the maximum video resolution the local participant should receive from remote participants.\n     *\n     * @param {number|undefined} maxFrameHeight - the new value.\n     * @returns {void}\n     */\n    setPreferredReceiveMaxFrameHeight(maxFrameHeight) {\n        this._maxFrameHeight = maxFrameHeight;\n\n        for (const session of this._conference.getMediaSessions()) {\n            if (session.isP2P) {\n                session.setReceiverVideoConstraint(this._getDefaultSourceReceiverConstraints(session, maxFrameHeight));\n            } else if (this._receiverVideoConstraints.updateReceiveResolution(maxFrameHeight)) {\n                this._rtc.setReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\n            }\n        }\n    }\n\n    /**\n     * Sets the receiver constraints for the conference.\n     *\n     * @param {Object} constraints The video constraints.\n     */\n    setReceiverConstraints(constraints) {\n        if (!constraints) {\n            return;\n        }\n        const isEndpointsFormat = Object.keys(constraints).includes('onStageEndpoints', 'selectedEndpoints');\n\n        if (isEndpointsFormat) {\n            throw new Error(\n                '\"onStageEndpoints\" and \"selectedEndpoints\" are not supported when sourceNameSignaling is enabled.'\n            );\n        }\n        const constraintsChanged = this._receiverVideoConstraints.updateReceiverVideoConstraints(constraints);\n\n        if (constraintsChanged) {\n            this._assumedBandwidthBps = constraints.assumedBandwidthBps ?? this._assumedBandwidthBps;\n            this._lastN = constraints.lastN ?? this._lastN;\n\n            // Send the contraints on the bridge channel.\n            this._rtc.setReceiverVideoConstraints(constraints);\n\n            const p2pSession = this._conference.getMediaSessions().find(session => session.isP2P);\n\n            if (!p2pSession) {\n                return;\n            }\n\n            const mappedConstraints = Array.from(Object.entries(constraints.constraints))\n                .map(constraint => {\n                    constraint[1] = constraint[1].maxHeight;\n\n                    return constraint;\n                });\n\n            this._sourceReceiverConstraints = new Map(mappedConstraints);\n\n            // Send the receiver constraints to the peer through a \"content-modify\" message.\n            p2pSession.setReceiverVideoConstraint(this._sourceReceiverConstraints);\n        }\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport MediaSessionEvents from '../xmpp/MediaSessionEvents';\n\nconst logger = getLogger(__filename);\nconst MAX_LOCAL_RESOLUTION = 2160;\n\n/**\n * The class manages send video constraints across media sessions({@link JingleSessionPC}) which belong to\n * {@link JitsiConference}. It finds the lowest common value, between the local user's send preference and\n * the remote party's receive preference. Also this module will consider only the active session's receive value,\n * because local tracks are shared and while JVB may have no preference, the remote p2p may have and they may be totally\n * different.\n */\nexport default class SendVideoController {\n    /**\n     * Creates new instance for a given conference.\n     *\n     * @param {JitsiConference} conference - the conference instance for which the new instance will be managing\n     * the send video quality constraints.\n     * @param {RTC} rtc - the rtc instance that is responsible for sending the messages on the bridge channel.\n     */\n    constructor(conference, rtc) {\n        this._conference = conference;\n        this._preferredSendMaxFrameHeight = MAX_LOCAL_RESOLUTION;\n        this._rtc = rtc;\n\n        /**\n         * Source name based sender constraints.\n         * @type {Map<string, number>};\n         */\n\n        this._sourceSenderConstraints = new Map();\n        this._conference.on(\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\n            session => this._onMediaSessionStarted(session));\n        this._conference.on(\n            JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED,\n            () => this._configureConstraintsForLocalSources());\n        this._rtc.on(\n            RTCEvents.SENDER_VIDEO_CONSTRAINTS_CHANGED,\n            videoConstraints => this._onSenderConstraintsReceived(videoConstraints));\n    }\n\n    /**\n     * Configures the video encodings on the local sources when a media connection is established or becomes active.\n     *\n     * @returns {Promise<void[]>}\n     * @private\n     */\n    _configureConstraintsForLocalSources() {\n        for (const track of this._rtc.getLocalVideoTracks()) {\n            const sourceName = track.getSourceName();\n\n            sourceName && this._propagateSendMaxFrameHeight(sourceName);\n        }\n    }\n\n    /**\n     * Handles the {@link JitsiConferenceEvents.MEDIA_SESSION_STARTED}, that is when the conference creates new media\n     * session. It doesn't mean it's already active though. For example the JVB connection may be created after\n     * the conference has entered the p2p mode already.\n     *\n     * @param {JingleSessionPC} mediaSession - the started media session.\n     * @private\n     */\n    _onMediaSessionStarted(mediaSession) {\n        mediaSession.addListener(\n            MediaSessionEvents.REMOTE_SOURCE_CONSTRAINTS_CHANGED,\n            (session, sourceConstraints) => {\n                session === this._conference.getActiveMediaSession()\n                    && sourceConstraints.forEach(constraint => this._onSenderConstraintsReceived(constraint));\n            });\n    }\n\n    /**\n     * Propagates the video constraints if they have changed.\n     *\n     * @param {Object} videoConstraints - The sender video constraints received from the bridge.\n     * @returns {Promise<void[]>}\n     * @private\n     */\n    _onSenderConstraintsReceived(videoConstraints) {\n        const { maxHeight, sourceName } = videoConstraints;\n        const localVideoTracks = this._conference.getLocalVideoTracks() ?? [];\n\n        for (const track of localVideoTracks) {\n            // Propagate the sender constraint only if it has changed.\n            if (track.getSourceName() === sourceName\n                && this._sourceSenderConstraints.get(sourceName) !== maxHeight) {\n                this._sourceSenderConstraints.set(\n                    sourceName,\n                    maxHeight === -1\n                        ? Math.min(MAX_LOCAL_RESOLUTION, this._preferredSendMaxFrameHeight)\n                        : maxHeight);\n                logger.debug(`Sender constraints for source:${sourceName} changed to maxHeight:${maxHeight}`);\n                this._propagateSendMaxFrameHeight(sourceName);\n            }\n        }\n    }\n\n    /**\n     * Figures out the send video constraint as specified by {@link _selectSendMaxFrameHeight} and sets it on all media\n     * sessions for the reasons mentioned in this class description.\n     *\n     * @param {string} sourceName - The source for which sender constraints have changed.\n     * @returns {Promise<void[]>}\n     * @private\n     */\n    _propagateSendMaxFrameHeight(sourceName) {\n        if (!sourceName) {\n            throw new Error('sourceName missing for calculating the sendMaxHeight for video tracks');\n        }\n        const sendMaxFrameHeight = this._selectSendMaxFrameHeight(sourceName);\n        const promises = [];\n\n        if (sendMaxFrameHeight >= 0) {\n            for (const session of this._conference.getMediaSessions()) {\n                promises.push(session.setSenderVideoConstraint(sendMaxFrameHeight, sourceName));\n            }\n        }\n\n        return Promise.all(promises);\n    }\n\n    /**\n     * Selects the lowest common value for the local video send constraint by looking at local user's preference and\n     * the active media session's receive preference set by the remote party.\n     *\n     * @param {string} sourceName - The source for which sender constraints have changed.\n     * @returns {number|undefined}\n     * @private\n     */\n    _selectSendMaxFrameHeight(sourceName) {\n        if (!sourceName) {\n            throw new Error('sourceName missing for calculating the sendMaxHeight for video tracks');\n        }\n        const activeMediaSession = this._conference.getActiveMediaSession();\n        const remoteRecvMaxFrameHeight = activeMediaSession\n            ? this._sourceSenderConstraints.get(sourceName)\n            : undefined;\n\n        if (this._preferredSendMaxFrameHeight >= 0 && remoteRecvMaxFrameHeight >= 0) {\n            return Math.min(this._preferredSendMaxFrameHeight, remoteRecvMaxFrameHeight);\n        } else if (remoteRecvMaxFrameHeight >= 0) {\n            return remoteRecvMaxFrameHeight;\n        }\n\n        return this._preferredSendMaxFrameHeight;\n    }\n\n    /**\n     * Sets local preference for max send video frame height.\n     *\n     * @param {number} maxFrameHeight - the new value to set.\n     * @returns {Promise<void[]>} - resolved when the operation is complete.\n     */\n    setPreferredSendMaxFrameHeight(maxFrameHeight) {\n        this._preferredSendMaxFrameHeight = maxFrameHeight;\n        const promises = [];\n\n        for (const sourceName of this._sourceSenderConstraints.keys()) {\n            promises.push(this._propagateSendMaxFrameHeight(sourceName));\n        }\n\n        return Promise.allSettled(promises);\n    }\n}\n","/**\n * A collection of utility functions for taking in XML and parsing it to return\n * certain values.\n */\nexport default {\n    /**\n     * Parses the presence update of the focus and returns an object with the\n     * statuses related to recording.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {Object} The current presence values related to recording.\n     */\n    getFocusRecordingUpdate(presence) {\n        const jibriStatus = presence\n            && presence.getElementsByTagName('jibri-recording-status')[0];\n\n        if (!jibriStatus) {\n            return;\n        }\n\n        return {\n            error: jibriStatus.getAttribute('failure_reason'),\n            initiator: jibriStatus.getAttribute('initiator'),\n            recordingMode: jibriStatus.getAttribute('recording_mode'),\n            sessionID: jibriStatus.getAttribute('session_id'),\n            status: jibriStatus.getAttribute('status')\n        };\n    },\n\n    /**\n     * Parses the presence update from a hidden domain participant and returns\n     * an object with the statuses related to recording.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {Object} The current presence values related to recording.\n     */\n    getHiddenDomainUpdate(presence) {\n        const liveStreamViewURLContainer\n            = presence.getElementsByTagName('live-stream-view-url')[0];\n        const liveStreamViewURL = liveStreamViewURLContainer\n            && liveStreamViewURLContainer.textContent;\n        const modeContainer\n            = presence.getElementsByTagName('mode')[0];\n        const mode = modeContainer\n            && modeContainer.textContent\n            && modeContainer.textContent.toLowerCase();\n        const sessionIDContainer\n            = presence.getElementsByTagName('session_id')[0];\n        const sessionID\n            = sessionIDContainer && sessionIDContainer.textContent;\n\n        return {\n            liveStreamViewURL,\n            mode,\n            sessionID\n        };\n    },\n\n    /**\n     * Returns the recording session ID from a successful IQ.\n     *\n     * @param {Node} response - The response from the IQ.\n     * @returns {string} The session ID of the recording session.\n     */\n    getSessionIdFromIq(response) {\n        const jibri = response && response.getElementsByTagName('jibri')[0];\n\n        return jibri && jibri.getAttribute('session_id');\n    },\n\n    /**\n     * Returns the recording session ID from a presence, if it exists.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {string|undefined} The session ID of the recording session.\n     */\n    getSessionId(presence) {\n        const sessionIdContainer\n            = presence.getElementsByTagName('session_id')[0];\n        const sessionId = sessionIdContainer && sessionIdContainer.textContent;\n\n        return sessionId;\n    },\n\n    /**\n     * Returns whether or not a presence is from the focus.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {boolean} True if the presence is from the focus.\n     */\n    isFromFocus(presence) {\n        return presence.getAttribute('from').includes('focus');\n    }\n};\n","import { $iq } from 'strophe.js';\n\nimport recordingXMLUtils from './recordingXMLUtils';\n\n/**\n * Represents a recording session.\n */\nexport default class JibriSession {\n    /**\n     * Initializes a new JibriSession instance.\n     *\n     * @constructor\n     */\n    constructor(options = {}) {\n        this._connection = options.connection;\n        this._mode = options.mode;\n        this._jibriJid = null;\n        this._statusFromJicofo = '';\n\n        this._setSessionID(options.sessionID);\n        this.setStatus(options.status);\n    }\n\n    /**\n     * Returns the error related to the session instance, if any.\n     *\n     * @returns {string|undefined}\n     */\n    getError() {\n        return this._error;\n    }\n\n    /**\n     * Returns the session ID of the session instance.\n     *\n     * @returns {string|undefined}\n     */\n    getID() {\n        return this._sessionID;\n    }\n\n    /**\n     * Returns the initiator of the session instance.\n     *\n     * @returns {JitsiParticipant|string} The participant that started the session.\n     */\n    getInitiator() {\n        return this._initiator;\n    }\n\n    /**\n     * Returns the streaming URL of the session.\n     *\n     * @returns {string|undefined}\n     */\n    getLiveStreamViewURL() {\n        return this._liveStreamViewURL;\n    }\n\n    /**\n     * Returns the current status of the session.\n     *\n     * @returns {string|undefined}\n     */\n    getStatus() {\n        // If _status is not set fallback to the status reported by jicofo.\n        if (this._status) {\n            return this._status;\n        }\n\n        return this._statusFromJicofo;\n    }\n\n    /**\n     * @returns {string|undefined} the JID of jibri associated with this session.\n     */\n    getJibriJid() {\n        return this._jibriJid;\n    }\n\n    /**\n     * Returns the jid of the participant that stopped the session.\n     *\n     * @returns {JitsiParticipant|string} The participant that stopped the session.\n     */\n    getTerminator() {\n        return this._terminator;\n    }\n\n    /**\n     * Returns the current recording mode of the session, such as \"file\".\n     *\n     * @returns {string}\n     */\n    getMode() {\n        return this._mode;\n    }\n\n    /**\n     * Sets the last known error message related to the session.\n     *\n     * @param {string} error - The error string explaining why the session\n     * entered an error state.\n     * @returns {void}\n     */\n    setError(error) {\n        this._error = error;\n    }\n\n    /**\n     * Sets the last live stream URL for the session instance. Usually this is\n     * a YouTube URL and usually this is only set for \"stream\" sessions.\n     *\n     * @param {string} url - The live stream URL associated with the session.\n     * @returns {void}\n     */\n    setLiveStreamViewURL(url) {\n        this._liveStreamViewURL = url;\n    }\n\n    /**\n     * Sets the last known status for this recording session.\n     *\n     * @param {string} status - The new status to set.\n     * @returns {void}\n     */\n    setStatus(status) {\n        this._status = status;\n    }\n\n    /**\n     * Set the session status reported by jicofo. If a jibri is present in the room,\n     * the status is always 'on'. Otherwise, we fallback to the status reported by jicofo.\n     *\n     * @param {string} status\n     */\n    setStatusFromJicofo(status) {\n        this._statusFromJicofo = status;\n    }\n\n    /**\n     * Set the JID of the jibri associated with this session.\n     *\n     * @param {*} jibriJid\n     */\n    setJibriJid(jibriJid) {\n        this._jibriJid = jibriJid;\n    }\n\n    /**\n     * Sets the participant that started the session.\n     * @param {JitsiParticipant | string} participant - The participant or resource id\n     * if local participant.\n     */\n    setInitiator(participant) {\n        this._initiator = participant;\n    }\n\n    /**\n     * Sets the participant that stopped the session.\n     * @param {JitsiParticipant | string} participant - The participant or the resource id\n     * if local participant.\n     */\n    setTerminator(participant) {\n        this._terminator = participant;\n    }\n\n    /**\n     * Sends a message to start the actual recording.\n     *\n     * @param {Object} options - Additional arguments for starting the\n     * recording.\n     * @param {string} [options.appData] - Data specific to the app/service that\n     * the result file will be uploaded.\n     * @param {string} [options.broadcastId] - The broadcast ID of an\n     * associated YouTube stream, used for knowing the URL from which the stream\n     * can be viewed.\n     * @param {string} options.focusMucJid - The JID of the focus participant\n     * that controls recording.\n     * @param {streamId} options.streamId - Necessary for live streaming, this\n     * is the stream key needed to start a live streaming session with the\n     * streaming service provider.\n     * @returns Promise\n     */\n    start({ appData, broadcastId, focusMucJid, streamId }) {\n        return new Promise((resolve, reject) => {\n            this._connection.sendIQ(\n                this._createIQ({\n                    action: 'start',\n                    appData,\n                    focusMucJid,\n                    broadcastId,\n                    streamId\n                }),\n                result => {\n                    // All users will eventually receive the 'pending' status\n                    // from the backend, but for the user initiating the session\n                    // it's better to give some instant feedback that recording\n                    // is starting so fire 'pending' here manually.\n                    this.setStatus('pending');\n                    this._setSessionID(\n                        recordingXMLUtils.getSessionIdFromIq(result));\n\n                    resolve();\n                },\n                error => {\n                    this._setErrorFromIq(error);\n\n                    reject(error);\n                });\n        });\n    }\n\n    /**\n     * Sends a message to actually stop the recording session.\n     *\n     * @param {Object} options - Additional arguments for stopping the\n     * recording.\n     * @param {Object} options.focusMucJid - The JID of the focus participant\n     * that controls recording.\n     * @returns Promise\n     */\n    stop({ focusMucJid }) {\n        return new Promise((resolve, reject) => {\n            this._connection.sendIQ(\n                this._createIQ({\n                    action: 'stop',\n                    focusMucJid\n                }),\n                resolve,\n                reject);\n        });\n    }\n\n    /**\n     * Generates the message to change the status of the recording session.\n     *\n     * @param {string} status - The new status to which the recording session\n     * should transition.\n     * @param {string} [options.appData] - Data specific to the app/service that\n     * the result file will be uploaded.\n     * @param {string} [options.broadcastId] - The broadcast ID of an\n     * associated YouTube stream, used for knowing the URL from which the stream\n     * can be viewed.\n     * @param {string} options.focusMucJid - The JID of the focus participant\n     * that controls recording.\n     * @param {streamId} options.streamId - Necessary for live streaming, this\n     * is the stream key needed to start a live streaming session with the\n     * streaming service provider.\n     * @returns Object - The XMPP IQ message.\n     */\n    _createIQ({ action, appData, broadcastId, focusMucJid, streamId }) {\n        return $iq({\n            to: focusMucJid,\n            type: 'set'\n        })\n        .c('jibri', {\n            'xmlns': 'http://jitsi.org/protocol/jibri',\n            'action': action,\n            'app_data': appData,\n            'recording_mode': this._mode,\n            'streamid': streamId,\n            'you_tube_broadcast_id': broadcastId\n        })\n        .up();\n    }\n\n    /**\n     * Handles the error from an iq and stores the error.\n     *\n     * @param {Node} errorIq - The error response from an Iq.\n     * @private\n     * @returns {void}\n     */\n    _setErrorFromIq(errorIq) {\n        const error = errorIq.getElementsByTagName('error')[0];\n\n        this.setError(error.children[0].tagName);\n    }\n\n    /**\n     * Sets the known session ID for this recording session.\n     *\n     * @param {string} sessionID\n     * @private\n     * @returns {void}\n     */\n    _setSessionID(sessionID) {\n        this._sessionID = sessionID;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nimport JibriSession from './JibriSession';\nimport recordingXMLUtils from './recordingXMLUtils';\n\nconst logger = getLogger(__filename);\n\n/**\n * A class responsible for starting and stopping recording sessions and emitting\n * state updates for them.\n */\nclass RecordingManager {\n    /**\n     * Initialize {@code RecordingManager} with other objects that are necessary\n     * for starting a recording.\n     *\n     * @param {ChatRoom} chatRoom - The chat room to handle.\n     * @returns {void}\n     */\n    constructor(chatRoom) {\n        /**\n         * All known recording sessions from the current conference.\n         */\n        this._sessions = {};\n\n        this._chatRoom = chatRoom;\n\n        this.onPresence = this.onPresence.bind(this);\n\n        this.onMemberLeft = this.onMemberLeft.bind(this);\n\n        this._chatRoom.eventEmitter.addListener(\n            XMPPEvents.PRESENCE_RECEIVED, this.onPresence);\n        this._chatRoom.eventEmitter.addListener(\n            XMPPEvents.MUC_MEMBER_LEFT, this.onMemberLeft);\n    }\n\n    /**\n     * Finds an existing recording session by session ID.\n     *\n     * @param {string} sessionID - The session ID associated with the recording.\n     * @returns {JibriSession|undefined}\n     */\n    getSession(sessionID) {\n        return this._sessions[sessionID];\n    }\n\n    /**\n     * Find a session with a specific jibri JID.\n     *\n     * @param {string} jibriJid the JID to search for.\n     * @returns\n     */\n    getSessionByJibriJid(jibriJid) {\n        let s;\n\n        Object.values(this._sessions).forEach(session => {\n            if (session.getJibriJid() === jibriJid) {\n                s = session;\n            }\n        });\n\n        return s;\n    }\n\n    /**\n     * Callback to invoke to parse through a presence update to find recording\n     * related updates (from Jibri participant doing the recording and the\n     * focus which controls recording).\n     *\n     * @param {Object} event - The presence data from the pubsub event.\n     * @param {Node} event.presence - An XMPP presence update.\n     * @param {boolean} event.fromHiddenDomain - Whether or not the update comes\n     * from a participant that is trusted but not visible, as would be the case\n     * with the Jibri recorder participant.\n     * @returns {void}\n     */\n    onPresence({ fromHiddenDomain, presence }) {\n        if (recordingXMLUtils.isFromFocus(presence)) {\n            this._handleFocusPresence(presence);\n        } else if (fromHiddenDomain) {\n            this._handleJibriPresence(presence);\n        }\n    }\n\n    /**\n     * Handle a participant leaving the room.\n     * @param {string} jid the JID of the participant that left.\n     */\n    onMemberLeft(jid) {\n        const session = this.getSessionByJibriJid(jid);\n\n        if (session) {\n\n            const prevStatus = session.getStatus();\n\n            // Setting to ''\n            session.setStatus('');\n            session.setJibriJid(null);\n\n            if (session.getStatus() !== prevStatus) {\n                this._emitSessionUpdate(session);\n            }\n        }\n    }\n\n    /**\n     * Start a recording session.\n     *\n     * @param {Object} options - Configuration for the recording.\n     * @param {string} [options.appData] - Data specific to the app/service that\n     * the result file will be uploaded.\n     * @param {string} [optional] options.broadcastId - The channel on which a\n     * live stream will occur.\n     * @param {string} options.mode - The mode in which recording should be\n     * started. Recognized values are \"file\" and \"stream\".\n     * @param {string} [optional] options.streamId - The stream key to be used\n     * for live stream broadcasting. Required for live streaming.\n     * @returns {Promise} A promise for starting a recording, which will pass\n     * back the session on success. The promise resolves after receiving an\n     * acknowledgment of the start request success or fail.\n     */\n    startRecording(options) {\n        const session = new JibriSession({\n            ...options,\n            connection: this._chatRoom.connection\n        });\n\n        return session.start({\n            appData: options.appData,\n            broadcastId: options.broadcastId,\n            focusMucJid: this._chatRoom.focusMucJid,\n            streamId: options.streamId\n        })\n            .then(() => {\n                // Only store the session and emit if the session has not been\n                // added already. This is a workaround for the session getting\n                // created due to a presence update to announce a \"pending\"\n                // recording being received before JibriSession#start finishes.\n                if (!this.getSession(session.getID())) {\n                    this._addSession(session);\n                    this._emitSessionUpdate(session);\n                }\n\n                return session;\n            })\n            .catch(error => {\n                this._emitSessionUpdate(session);\n\n                return Promise.reject(error);\n            });\n    }\n\n    /**\n     * Stop a recording session.\n     *\n     * @param {string} sessionID - The ID associated with the recording session\n     * to be stopped.\n     * @returns {Promise} The promise resolves after receiving an\n     * acknowledgment of the stop request success or fail.\n     */\n    stopRecording(sessionID) {\n        const session = this.getSession(sessionID);\n\n        if (session) {\n            return session.stop({ focusMucJid: this._chatRoom.focusMucJid });\n        }\n\n        return Promise.reject(new Error('Could not find session'));\n    }\n\n    /**\n     * Stores a reference to the passed in JibriSession.\n     *\n     * @param {string} session - The JibriSession instance to store.\n     * @returns {void}\n     */\n    _addSession(session) {\n        this._sessions[session.getID()] = session;\n    }\n\n    /**\n     * Create a new instance of a recording session and stores a reference to\n     * it.\n     *\n     * @param {string} sessionID - The session ID of the recording in progress.\n     * @param {string} status - The current status of the recording session.\n     * @param {string} mode - The recording mode of the session.\n     * @returns {JibriSession}\n     */\n    _createSession(sessionID, status, mode) {\n        const session = new JibriSession({\n            connection: this._chatRoom.connection,\n            focusMucJid: this._chatRoom.focusMucJid,\n            mode,\n            sessionID,\n            status\n        });\n\n        this._addSession(session);\n\n        return session;\n    }\n\n    /**\n     * Notifies listeners of an update to a recording session.\n     *\n     * @param {JibriSession} session - The session that has been updated.\n     * @param {string|undefined} initiator - The jid of the initiator of the update.\n     */\n    _emitSessionUpdate(session, initiator) {\n        this._chatRoom.eventEmitter.emit(\n            XMPPEvents.RECORDER_STATE_CHANGED, session, initiator);\n    }\n\n    /**\n     * Parses presence to update an existing JibriSession or to create a new\n     * JibriSession.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {void}\n     */\n    _handleFocusPresence(presence) {\n        const jibriStatus = recordingXMLUtils.getFocusRecordingUpdate(presence);\n\n        if (!jibriStatus) {\n            return;\n        }\n\n        const { error, initiator, recordingMode, sessionID, status } = jibriStatus;\n\n        // We'll look for an existing session or create one (in case we're a\n        // participant joining a call with an existing recording going on).\n        let session = this.getSession(sessionID);\n\n        // Handle the case where a status update is received in presence but\n        // the local participant has joined while the JibriSession has already\n        // ended.\n        if (!session && status === 'off') {\n            logger.warn(\n                'Ignoring recording presence update',\n                'Received a new session with status off.');\n\n            return;\n        }\n\n        // Jicofo sends updates via presence, and any extension in presence\n        // is sent until it is explicitly removed.  It's difficult for\n        // Jicofo to know when a presence has been sent once, so it won't\n        // remove jibri status extension.  This means we may receive the same\n        // status update more than once, so check for that here\n        if (session\n            && session.getStatus() === status\n            && session.getError() === error) {\n            logger.warn('Ignoring duplicate presence update: ',\n                JSON.stringify(jibriStatus));\n\n            return;\n        }\n\n        if (!session) {\n            session = this._createSession(sessionID, status, recordingMode);\n        }\n\n        session.setStatusFromJicofo(status);\n\n        if (error) {\n            session.setError(error);\n        }\n\n        this._emitSessionUpdate(session, initiator);\n    }\n\n    /**\n     * Handles updates from the Jibri which can broadcast a YouTube URL that\n     * needs to be updated in a JibriSession.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {void}\n     */\n    _handleJibriPresence(presence) {\n        const { liveStreamViewURL, mode, sessionID }\n            = recordingXMLUtils.getHiddenDomainUpdate(presence);\n\n        if (!sessionID) {\n            logger.warn(\n                'Ignoring potential jibri presence due to no session id.');\n\n            return;\n        }\n\n        let session = this.getSession(sessionID);\n\n        if (!session) {\n            session = this._createSession(sessionID, 'on', mode);\n        }\n\n        // When a jibri is present the status is always 'on';\n        session.setStatus('on');\n        session.setJibriJid(presence.getAttribute('from'));\n        session.setLiveStreamViewURL(liveStreamViewURL);\n\n        this._emitSessionUpdate(session);\n    }\n}\n\nexport default RecordingManager;\n","import { getLogger } from '@jitsi/logger';\n\nimport * as ConferenceEvents from '../../JitsiConferenceEvents';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport * as ConnectionQualityEvents from '../../service/connectivity/ConnectionQualityEvents';\nimport { createAudioOutputProblemEvent } from '../../service/statistics/AnalyticsEvents';\n\nimport Statistics from './statistics';\n\nconst logger = getLogger(__filename);\n\n/**\n * Number of local samples that will be used for comparison before and after the remote sample is received.\n */\nconst NUMBER_OF_LOCAL_SAMPLES = 2;\n\n/**\n * Collects the average audio levels per participant from the local stats and the stats received by every remote\n * participant and compares them to detect potential audio problem for a participant.\n */\nexport default class AudioOutputProblemDetector {\n\n    /**\n     * Creates new <tt>AudioOutputProblemDetector</tt> instance.\n     *\n     * @param {JitsiConference} conference - The conference instance to be monitored.\n     */\n    constructor(conference) {\n        this._conference = conference;\n        this._localAudioLevelCache = {};\n        this._reportedParticipants = [];\n        this._audioProblemCandidates = {};\n        this._numberOfRemoteAudioLevelsReceived = {};\n        this._onLocalAudioLevelsReport = this._onLocalAudioLevelsReport.bind(this);\n        this._onRemoteAudioLevelReceived = this._onRemoteAudioLevelReceived.bind(this);\n        this._clearUserData = this._clearUserData.bind(this);\n        this._conference.on(ConnectionQualityEvents.REMOTE_STATS_UPDATED, this._onRemoteAudioLevelReceived);\n        this._conference.statistics.addConnectionStatsListener(this._onLocalAudioLevelsReport);\n        this._conference.on(ConferenceEvents.USER_LEFT, this._clearUserData);\n    }\n\n    /**\n     * A listener for audio level data received by a remote participant.\n     *\n     * @param {string} userID - The user id of the participant that sent the data.\n     * @param {number} audioLevel - The average audio level value.\n     * @returns {void}\n     */\n    _onRemoteAudioLevelReceived(userID, { avgAudioLevels }) {\n        const numberOfReports = (this._numberOfRemoteAudioLevelsReceived[userID] + 1) || 0;\n\n        this._numberOfRemoteAudioLevelsReceived[userID] = numberOfReports;\n\n        if (this._reportedParticipants.indexOf(userID) !== -1 || (userID in this._audioProblemCandidates)\n                || avgAudioLevels <= 0 || numberOfReports < 3) {\n            return;\n        }\n\n        const participant = this._conference.getParticipantById(userID);\n\n        if (participant) {\n            const tracks = participant.getTracksByMediaType(MediaType.AUDIO);\n\n            if (tracks.length > 0 && participant.isAudioMuted()) {\n                // We don't need to report an error if everything seems fine with the participant and its tracks but\n                // the participant is audio muted. Since those are average audio levels we potentially can receive non\n                // zero values for muted track.\n                return;\n            }\n        }\n\n        const localAudioLevels = this._localAudioLevelCache[userID];\n\n        if (!Array.isArray(localAudioLevels) || localAudioLevels.every(audioLevel => audioLevel === 0)) {\n            this._audioProblemCandidates[userID] = {\n                remoteAudioLevels: avgAudioLevels,\n                localAudioLevels: []\n            };\n        }\n    }\n\n    /**\n     * A listener for audio level data retrieved by the local stats.\n     *\n     * @param {TraceablePeerConnection} tpc - The <tt>TraceablePeerConnection</tt> instance used to gather the data.\n     * @param {Object} avgAudioLevels - The average audio levels per participant.\n     * @returns {void}\n     */\n    _onLocalAudioLevelsReport(tpc, { avgAudioLevels }) {\n        if (tpc !== this._conference.getActivePeerConnection()) {\n            return;\n        }\n\n        Object.keys(avgAudioLevels).forEach(userID => {\n            if (this._reportedParticipants.indexOf(userID) !== -1) {\n                return;\n            }\n\n            const localAudioLevels = this._localAudioLevelCache[userID];\n\n            if (!Array.isArray(localAudioLevels)) {\n                this._localAudioLevelCache[userID] = [ ];\n            } else if (localAudioLevels.length >= NUMBER_OF_LOCAL_SAMPLES) {\n                localAudioLevels.shift();\n            }\n\n            this._localAudioLevelCache[userID].push(avgAudioLevels[userID]);\n        });\n\n\n        Object.keys(this._audioProblemCandidates).forEach(userID => {\n            const { localAudioLevels, remoteAudioLevels } = this._audioProblemCandidates[userID];\n\n            localAudioLevels.push(avgAudioLevels[userID]);\n\n            if (localAudioLevels.length === NUMBER_OF_LOCAL_SAMPLES) {\n                if (localAudioLevels.every(audioLevel => typeof audioLevel === 'undefined' || audioLevel === 0)) {\n                    const localAudioLevelsString = JSON.stringify(localAudioLevels);\n\n                    Statistics.sendAnalytics(\n                        createAudioOutputProblemEvent(userID, localAudioLevelsString, remoteAudioLevels));\n                    logger.warn(`A potential problem is detected with the audio output for participant ${\n                        userID}, local audio levels: ${localAudioLevelsString}, remote audio levels: ${\n                        remoteAudioLevels}`);\n                    this._reportedParticipants.push(userID);\n                    this._clearUserData(userID);\n                }\n\n                delete this._audioProblemCandidates[userID];\n            }\n        });\n    }\n\n    /**\n     * Clears the data stored for a participant.\n     *\n     * @param {string} userID - The id of the participant.\n     * @returns {void}\n     */\n    _clearUserData(userID) {\n        delete this._localAudioLevelCache[userID];\n    }\n\n    /**\n     * Disposes the allocated resources.\n     *\n     * @returns {void}\n     */\n    dispose() {\n        this._conference.off(ConnectionQualityEvents.REMOTE_STATS_UPDATED, this._onRemoteAudioLevelReceived);\n        this._conference.off(ConferenceEvents.USER_LEFT, this._clearUserData);\n        this._conference.statistics.removeConnectionStatsListener(this._onLocalAudioLevelsReport);\n        this._localAudioLevelCache = undefined;\n        this._audioProblemCandidates = undefined;\n        this._reportedParticipants = undefined;\n        this._numberOfRemoteAudioLevelsReceived = undefined;\n        this._conference = undefined;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport isEqual from 'lodash.isequal';\n\nimport * as ConferenceEvents from '../../JitsiConferenceEvents';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport * as ConnectionQualityEvents\n    from '../../service/connectivity/ConnectionQualityEvents';\nimport {\n    createRtpStatsEvent,\n    createTransportStatsEvent\n} from '../../service/statistics/AnalyticsEvents';\nimport browser from '../browser';\n\nimport Statistics from './statistics';\n\n\nconst logger = getLogger(__filename);\n\n/**\n * This will calculate an average for one, named stat and submit it to\n * the analytics module when requested. It automatically counts the samples.\n */\nclass AverageStatReport {\n    /**\n     * Creates new <tt>AverageStatReport</tt> for given name.\n     * @param {string} name that's the name of the event that will be reported\n     * to the analytics module.\n     */\n    constructor(name) {\n        this.name = name;\n        this.count = 0;\n        this.sum = 0;\n        this.samples = [];\n    }\n\n    /**\n     * Adds the next value that will be included in the average when\n     * {@link calculate} is called.\n     * @param {number} nextValue\n     */\n    addNext(nextValue) {\n        if (typeof nextValue === 'undefined') {\n            return;\n        }\n\n        if (typeof nextValue !== 'number') {\n            logger.error(`${this.name} - invalid value for idx: ${this.count}`, nextValue);\n        } else if (!isNaN(nextValue)) {\n            this.sum += nextValue;\n            this.samples.push(nextValue);\n            this.count += 1;\n        }\n    }\n\n    /**\n     * Calculates an average for the samples collected using {@link addNext}.\n     * @return {number|NaN} an average of all collected samples or <tt>NaN</tt>\n     * if no samples were collected.\n     */\n    calculate() {\n        return this.sum / this.count;\n    }\n\n    /**\n     * Appends the report to the analytics \"data\" object. The object will be\n     * set under <tt>prefix</tt> + {@link this.name} key.\n     * @param {Object} report the analytics \"data\" object\n     */\n    appendReport(report) {\n        report[`${this.name}_avg`] = this.calculate();\n        report[`${this.name}_samples`] = JSON.stringify(this.samples);\n    }\n\n    /**\n     * Clears all memory of any samples collected, so that new average can be\n     * calculated using this instance.\n     */\n    reset() {\n        this.samples = [];\n        this.sum = 0;\n        this.count = 0;\n    }\n}\n\n/**\n * Class gathers the stats that are calculated and reported for a\n * {@link TraceablePeerConnection} even if it's not currently active. For\n * example we want to monitor RTT for the JVB connection while in P2P mode.\n */\nclass ConnectionAvgStats {\n    /**\n     * Creates new <tt>ConnectionAvgStats</tt>\n     * @param {AvgRTPStatsReporter} avgRtpStatsReporter\n     * @param {boolean} isP2P\n     * @param {number} n the number of samples, before arithmetic mean is to be\n     * calculated and values submitted to the analytics module.\n     */\n    constructor(avgRtpStatsReporter, isP2P, n) {\n        /**\n         * Is this instance for JVB or P2P connection ?\n         * @type {boolean}\n         */\n        this.isP2P = isP2P;\n\n        /**\n         * How many samples are to be included in arithmetic mean calculation.\n         * @type {number}\n         * @private\n         */\n        this._n = n;\n\n        /**\n         * The current sample index. Starts from 0 and goes up to {@link _n})\n         * when analytics report will be submitted.\n         * @type {number}\n         * @private\n         */\n        this._sampleIdx = 0;\n\n        /**\n         * Average round trip time reported by the ICE candidate pair.\n         * @type {AverageStatReport}\n         */\n        this._avgRTT = new AverageStatReport('rtt');\n\n        /**\n         * Map stores average RTT to the JVB reported by remote participants.\n         * Mapped per participant id {@link JitsiParticipant.getId}.\n         *\n         * This is used only when {@link ConnectionAvgStats.isP2P} equals to\n         * <tt>false</tt>.\n         *\n         * @type {Map<string,AverageStatReport>}\n         * @private\n         */\n        this._avgRemoteRTTMap = new Map();\n\n        /**\n         * The conference for which stats will be collected and reported.\n         * @type {JitsiConference}\n         * @private\n         */\n        this._avgRtpStatsReporter = avgRtpStatsReporter;\n\n        /**\n         * The latest average E2E RTT for the JVB connection only.\n         *\n         * This is used only when {@link ConnectionAvgStats.isP2P} equals to\n         * <tt>false</tt>.\n         *\n         * @type {number}\n         */\n        this._avgEnd2EndRTT = undefined;\n\n        this._onConnectionStats = (tpc, stats) => {\n            if (this.isP2P === tpc.isP2P) {\n                this._calculateAvgStats(stats);\n            }\n        };\n\n        const conference = avgRtpStatsReporter._conference;\n\n        conference.statistics.addConnectionStatsListener(\n            this._onConnectionStats);\n\n        if (!this.isP2P) {\n            this._onUserLeft = id => this._avgRemoteRTTMap.delete(id);\n            conference.on(ConferenceEvents.USER_LEFT, this._onUserLeft);\n\n            this._onRemoteStatsUpdated\n                = (id, data) => this._processRemoteStats(id, data);\n            conference.on(\n                ConnectionQualityEvents.REMOTE_STATS_UPDATED,\n                this._onRemoteStatsUpdated);\n        }\n    }\n\n    /**\n     * Processes next batch of stats.\n     * @param {go figure} data\n     * @private\n     */\n    _calculateAvgStats(data) {\n        if (!data) {\n            logger.error('No stats');\n\n            return;\n        }\n\n        if (browser.supportsRTTStatistics()) {\n            if (data.transport && data.transport.length) {\n                this._avgRTT.addNext(data.transport[0].rtt);\n            }\n        }\n\n        this._sampleIdx += 1;\n\n        if (this._sampleIdx >= this._n) {\n            if (browser.supportsRTTStatistics()) {\n                const conference = this._avgRtpStatsReporter._conference;\n\n                const batchReport = {\n                    p2p: this.isP2P,\n                    'conference_size': conference.getParticipantCount()\n                };\n\n                if (data.transport && data.transport.length) {\n                    Object.assign(batchReport, {\n                        'local_candidate_type':\n                            data.transport[0].localCandidateType,\n                        'remote_candidate_type':\n                            data.transport[0].remoteCandidateType,\n                        'transport_type': data.transport[0].type\n                    });\n                }\n\n                this._avgRTT.appendReport(batchReport);\n\n                if (this.isP2P) {\n                    // Report RTT diff only for P2P.\n                    const jvbEnd2EndRTT = this\n                        ._avgRtpStatsReporter.jvbStatsMonitor._avgEnd2EndRTT;\n\n                    if (!isNaN(jvbEnd2EndRTT)) {\n                        // eslint-disable-next-line dot-notation\n                        batchReport['rtt_diff']\n                            = this._avgRTT.calculate() - jvbEnd2EndRTT;\n                    }\n                } else {\n                    // Report end to end RTT only for JVB.\n                    const avgRemoteRTT = this._calculateAvgRemoteRTT();\n                    const avgLocalRTT = this._avgRTT.calculate();\n\n                    this._avgEnd2EndRTT = avgLocalRTT + avgRemoteRTT;\n\n                    if (!isNaN(avgLocalRTT) && !isNaN(avgRemoteRTT)) {\n                        // eslint-disable-next-line dot-notation\n                        batchReport['end2end_rtt_avg'] = this._avgEnd2EndRTT;\n                    }\n                }\n\n                Statistics.sendAnalytics(createRtpStatsEvent(batchReport));\n            }\n\n            this._resetAvgStats();\n        }\n    }\n\n    /**\n     * Calculates arithmetic mean of all RTTs towards the JVB reported by\n     * participants.\n     * @return {number|NaN} NaN if not available (not enough data)\n     * @private\n     */\n    _calculateAvgRemoteRTT() {\n        let count = 0, sum = 0;\n\n        // FIXME should we ignore RTT for participant\n        // who \"is having connectivity issues\" ?\n        for (const remoteAvg of this._avgRemoteRTTMap.values()) {\n            const avg = remoteAvg.calculate();\n\n            if (!isNaN(avg)) {\n                sum += avg;\n                count += 1;\n                remoteAvg.reset();\n            }\n        }\n\n        return sum / count;\n    }\n\n    /**\n     * Processes {@link ConnectionQualityEvents.REMOTE_STATS_UPDATED} to analyse\n     * RTT towards the JVB reported by each participant.\n     * @param {string} id {@link JitsiParticipant.getId}\n     * @param {go figure in ConnectionQuality.js} data\n     * @private\n     */\n    _processRemoteStats(id, data) {\n        const validData = typeof data.jvbRTT === 'number';\n        let rttAvg = this._avgRemoteRTTMap.get(id);\n\n        if (!rttAvg && validData) {\n            rttAvg = new AverageStatReport(`${id}_stat_rtt`);\n            this._avgRemoteRTTMap.set(id, rttAvg);\n        }\n\n        if (validData) {\n            rttAvg.addNext(data.jvbRTT);\n        } else if (rttAvg) {\n            this._avgRemoteRTTMap.delete(id);\n        }\n    }\n\n    /**\n     * Reset cache of all averages and {@link _sampleIdx}.\n     * @private\n     */\n    _resetAvgStats() {\n        this._avgRTT.reset();\n        if (this._avgRemoteRTTMap) {\n            this._avgRemoteRTTMap.clear();\n        }\n        this._sampleIdx = 0;\n    }\n\n    /**\n     *\n     */\n    dispose() {\n\n        const conference = this._avgRtpStatsReporter._conference;\n\n        conference.statistics.removeConnectionStatsListener(\n            this._onConnectionStats);\n        if (!this.isP2P) {\n            conference.off(\n                ConnectionQualityEvents.REMOTE_STATS_UPDATED,\n                this._onRemoteStatsUpdated);\n            conference.off(\n                ConferenceEvents.USER_LEFT,\n                this._onUserLeft);\n        }\n    }\n}\n\n/**\n * Reports average RTP statistics values (arithmetic mean) to the analytics\n * module for things like bit rate, bandwidth, packet loss etc. It keeps track\n * of the P2P vs JVB conference modes and submits the values under different\n * namespaces (the events for P2P mode have 'p2p.' prefix). Every switch between\n * P2P mode resets the data collected so far and averages are calculated from\n * scratch.\n */\nexport default class AvgRTPStatsReporter {\n    /**\n     * Creates new instance of <tt>AvgRTPStatsReporter</tt>\n     * @param {JitsiConference} conference\n     * @param {number} n the number of samples, before arithmetic mean is to be\n     * calculated and values submitted to the analytics module.\n     */\n    constructor(conference, n) {\n        /**\n         * How many {@link ConnectionQualityEvents.LOCAL_STATS_UPDATED} samples\n         * are to be included in arithmetic mean calculation.\n         * @type {number}\n         * @private\n         */\n        this._n = n;\n\n        if (n > 0) {\n            logger.info(`Avg RTP stats will be calculated every ${n} samples`);\n        } else {\n            logger.info('Avg RTP stats reports are disabled.');\n\n            // Do not initialize\n            return;\n        }\n\n        /**\n         * The current sample index. Starts from 0 and goes up to {@link _n})\n         * when analytics report will be submitted.\n         * @type {number}\n         * @private\n         */\n        this._sampleIdx = 0;\n\n        /**\n         * The conference for which stats will be collected and reported.\n         * @type {JitsiConference}\n         * @private\n         */\n        this._conference = conference;\n\n        /**\n         * Average audio upload bitrate\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgAudioBitrateUp\n            = new AverageStatReport('bitrate_audio_upload');\n\n        /**\n         * Average audio download bitrate\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgAudioBitrateDown\n            = new AverageStatReport('bitrate_audio_download');\n\n        /**\n         * Average video upload bitrate\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgVideoBitrateUp\n            = new AverageStatReport('bitrate_video_upload');\n\n        /**\n         * Average video download bitrate\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgVideoBitrateDown\n            = new AverageStatReport('bitrate_video_download');\n\n        /**\n         * Average upload bandwidth\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgBandwidthUp\n            = new AverageStatReport('bandwidth_upload');\n\n        /**\n         * Average download bandwidth\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgBandwidthDown\n            = new AverageStatReport('bandwidth_download');\n\n        /**\n         * Average total packet loss\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgPacketLossTotal\n            = new AverageStatReport('packet_loss_total');\n\n        /**\n         * Average upload packet loss\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgPacketLossUp\n            = new AverageStatReport('packet_loss_upload');\n\n        /**\n         * Average download packet loss\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgPacketLossDown\n            = new AverageStatReport('packet_loss_download');\n\n        /**\n         * Average FPS for remote videos\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgRemoteFPS = new AverageStatReport('framerate_remote');\n\n        /**\n         * Average FPS for remote screen streaming videos (reported only if not\n         * a <tt>NaN</tt>).\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgRemoteScreenFPS\n            = new AverageStatReport('framerate_screen_remote');\n\n        /**\n         * Average FPS for local video (camera)\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgLocalFPS = new AverageStatReport('framerate_local');\n\n        /**\n         * Average FPS for local screen streaming video (reported only if not\n         * a <tt>NaN</tt>).\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgLocalScreenFPS\n            = new AverageStatReport('framerate_screen_local');\n\n        /**\n         * Average pixels for remote screen streaming videos (reported only if\n         * not a <tt>NaN</tt>).\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgRemoteCameraPixels\n            = new AverageStatReport('pixels_remote');\n\n        /**\n         * Average pixels for remote screen streaming videos (reported only if\n         * not a <tt>NaN</tt>).\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgRemoteScreenPixels\n            = new AverageStatReport('pixels_screen_remote');\n\n        /**\n         * Average pixels for local video (camera)\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgLocalCameraPixels\n            = new AverageStatReport('pixels_local');\n\n        /**\n         * Average pixels for local screen streaming video (reported only if not\n         * a <tt>NaN</tt>).\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgLocalScreenPixels\n            = new AverageStatReport('pixels_screen_local');\n\n        /**\n         * Average connection quality as defined by\n         * the {@link ConnectionQuality} module.\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgCQ = new AverageStatReport('connection_quality');\n\n        this._cachedTransportStats = undefined;\n\n        this._onLocalStatsUpdated = data => {\n            this._calculateAvgStats(data);\n            this._maybeSendTransportAnalyticsEvent(data);\n        };\n        conference.on(\n            ConnectionQualityEvents.LOCAL_STATS_UPDATED,\n            this._onLocalStatsUpdated);\n\n        this._onP2PStatusChanged = () => {\n            logger.debug('Resetting average stats calculation');\n            this._resetAvgStats();\n            this.jvbStatsMonitor._resetAvgStats();\n            this.p2pStatsMonitor._resetAvgStats();\n        };\n        conference.on(\n            ConferenceEvents.P2P_STATUS,\n            this._onP2PStatusChanged);\n\n        this._onJvb121StatusChanged = (oldStatus, newStatus) => {\n            // We want to reset only on the transition from false => true,\n            // because otherwise those stats are resetted on JVB <=> P2P\n            // transition.\n            if (newStatus === true) {\n                logger.info('Resetting JVB avg RTP stats');\n                this._resetAvgJvbStats();\n            }\n        };\n        conference.on(\n            ConferenceEvents.JVB121_STATUS,\n            this._onJvb121StatusChanged);\n\n        this.jvbStatsMonitor\n            = new ConnectionAvgStats(this, false /* JVB */, n);\n\n        this.p2pStatsMonitor\n            = new ConnectionAvgStats(this, true /* P2P */, n);\n    }\n\n    /**\n     * Processes next batch of stats reported on\n     * {@link ConnectionQualityEvents.LOCAL_STATS_UPDATED}.\n     * @param {go figure} data\n     * @private\n     */\n    _calculateAvgStats(data) {\n\n        if (!data) {\n            logger.error('No stats');\n\n            return;\n        }\n\n        const isP2P = this._conference.isP2PActive();\n        const confSize = this._conference.getParticipantCount();\n\n        if (!isP2P && confSize < 2) {\n\n            // There's no point in collecting stats for a JVB conference of 1.\n            // That happens for short period of time after everyone leaves\n            // the room, until Jicofo terminates the session.\n            return;\n        }\n\n        /* Uncomment to figure out stats structure\n        for (const key in data) {\n            if (data.hasOwnProperty(key)) {\n                logger.info(`local stat ${key}: `, data[key]);\n            }\n        } */\n\n        const bitrate = data.bitrate;\n        const bandwidth = data.bandwidth;\n        const packetLoss = data.packetLoss;\n        const frameRate = data.framerate;\n        const resolution = data.resolution;\n\n        if (!bitrate) {\n            logger.error('No \"bitrate\"');\n\n            return;\n        } else if (!bandwidth) {\n            logger.error('No \"bandwidth\"');\n\n            return;\n        } else if (!packetLoss) {\n            logger.error('No \"packetloss\"');\n\n            return;\n        } else if (!frameRate) {\n            logger.error('No \"framerate\"');\n\n            return;\n        } else if (!resolution) {\n            logger.error('No resolution');\n\n            return;\n        }\n\n        this._avgAudioBitrateUp.addNext(bitrate.audio.upload);\n        this._avgAudioBitrateDown.addNext(bitrate.audio.download);\n\n        this._avgVideoBitrateUp.addNext(bitrate.video.upload);\n        this._avgVideoBitrateDown.addNext(bitrate.video.download);\n\n        if (browser.supportsBandwidthStatistics()) {\n            this._avgBandwidthUp.addNext(bandwidth.upload);\n            this._avgBandwidthDown.addNext(bandwidth.download);\n        }\n\n        this._avgPacketLossUp.addNext(packetLoss.upload);\n        this._avgPacketLossDown.addNext(packetLoss.download);\n        this._avgPacketLossTotal.addNext(packetLoss.total);\n\n        this._avgCQ.addNext(data.connectionQuality);\n\n        if (frameRate) {\n            this._avgRemoteFPS.addNext(\n                this._calculateAvgVideoFps(\n                    frameRate, false /* remote */, VideoType.CAMERA));\n            this._avgRemoteScreenFPS.addNext(\n                this._calculateAvgVideoFps(\n                    frameRate, false /* remote */, VideoType.DESKTOP));\n\n            this._avgLocalFPS.addNext(\n                this._calculateAvgVideoFps(\n                    frameRate, true /* local */, VideoType.CAMERA));\n            this._avgLocalScreenFPS.addNext(\n                this._calculateAvgVideoFps(\n                    frameRate, true /* local */, VideoType.DESKTOP));\n        }\n\n        if (resolution) {\n            this._avgRemoteCameraPixels.addNext(\n                this._calculateAvgVideoPixels(\n                    resolution, false /* remote */, VideoType.CAMERA));\n\n            this._avgRemoteScreenPixels.addNext(\n                this._calculateAvgVideoPixels(\n                    resolution, false /* remote */, VideoType.DESKTOP));\n\n            this._avgLocalCameraPixels.addNext(\n                this._calculateAvgVideoPixels(\n                    resolution, true /* local */, VideoType.CAMERA));\n\n            this._avgLocalScreenPixels.addNext(\n                this._calculateAvgVideoPixels(\n                    resolution, true /* local */, VideoType.DESKTOP));\n        }\n\n        this._sampleIdx += 1;\n\n        if (this._sampleIdx >= this._n) {\n\n            const batchReport = {\n                p2p: isP2P,\n                'conference_size': confSize\n            };\n\n            if (data.transport && data.transport.length) {\n                Object.assign(batchReport, {\n                    'local_candidate_type':\n                        data.transport[0].localCandidateType,\n                    'remote_candidate_type':\n                        data.transport[0].remoteCandidateType,\n                    'transport_type': data.transport[0].type\n                });\n            }\n\n            this._avgAudioBitrateUp.appendReport(batchReport);\n            this._avgAudioBitrateDown.appendReport(batchReport);\n\n            this._avgVideoBitrateUp.appendReport(batchReport);\n            this._avgVideoBitrateDown.appendReport(batchReport);\n\n            if (browser.supportsBandwidthStatistics()) {\n                this._avgBandwidthUp.appendReport(batchReport);\n                this._avgBandwidthDown.appendReport(batchReport);\n            }\n            this._avgPacketLossUp.appendReport(batchReport);\n            this._avgPacketLossDown.appendReport(batchReport);\n            this._avgPacketLossTotal.appendReport(batchReport);\n\n            this._avgRemoteFPS.appendReport(batchReport);\n            if (!isNaN(this._avgRemoteScreenFPS.calculate())) {\n                this._avgRemoteScreenFPS.appendReport(batchReport);\n            }\n            this._avgLocalFPS.appendReport(batchReport);\n            if (!isNaN(this._avgLocalScreenFPS.calculate())) {\n                this._avgLocalScreenFPS.appendReport(batchReport);\n            }\n\n            this._avgRemoteCameraPixels.appendReport(batchReport);\n            if (!isNaN(this._avgRemoteScreenPixels.calculate())) {\n                this._avgRemoteScreenPixels.appendReport(batchReport);\n            }\n            this._avgLocalCameraPixels.appendReport(batchReport);\n            if (!isNaN(this._avgLocalScreenPixels.calculate())) {\n                this._avgLocalScreenPixels.appendReport(batchReport);\n            }\n\n            this._avgCQ.appendReport(batchReport);\n\n            Statistics.sendAnalytics(createRtpStatsEvent(batchReport));\n\n            this._resetAvgStats();\n        }\n    }\n\n    /**\n     * Calculates average number of pixels for the report\n     *\n     * @param {map} peerResolutions a map of peer resolutions\n     * @param {boolean} isLocal if the average is to be calculated for the local\n     * video or <tt>false</tt> if for remote videos.\n     * @param {VideoType} videoType\n     * @return {number|NaN} average number of pixels or <tt>NaN</tt> if there\n     * are no samples.\n     * @private\n     */\n    _calculateAvgVideoPixels(peerResolutions, isLocal, videoType) {\n        let peerPixelsSum = 0;\n        let peerCount = 0;\n        const myID = this._conference.myUserId();\n\n        for (const peerID of Object.keys(peerResolutions)) {\n            if (isLocal ? peerID === myID : peerID !== myID) {\n                const participant\n                    = isLocal\n                        ? null\n                        : this._conference.getParticipantById(peerID);\n                const videosResolution = peerResolutions[peerID];\n\n                // Do not continue without participant for non local peerID\n                if ((isLocal || participant) && videosResolution) {\n                    const peerAvgPixels = this._calculatePeerAvgVideoPixels(\n                        videosResolution, participant, videoType);\n\n                    if (!isNaN(peerAvgPixels)) {\n                        peerPixelsSum += peerAvgPixels;\n                        peerCount += 1;\n                    }\n                }\n            }\n        }\n\n        return peerPixelsSum / peerCount;\n    }\n\n    /**\n     * Calculate average pixels for either remote or local participant\n     * @param {object} videos maps resolution per video SSRC\n     * @param {JitsiParticipant|null} participant remote participant or\n     * <tt>null</tt> for local video pixels calculation.\n     * @param {VideoType} videoType the type of the video for which an average\n     * will be calculated.\n     * @return {number|NaN} average video pixels of all participant's videos or\n     * <tt>NaN</tt> if currently not available\n     * @private\n     */\n    _calculatePeerAvgVideoPixels(videos, participant, videoType) {\n        let ssrcs = Object.keys(videos).map(ssrc => Number(ssrc));\n        let videoTracks = null;\n\n        // NOTE that this method is supposed to be called for the stats\n        // received from the current peerconnection.\n        const tpc = this._conference.getActivePeerConnection();\n\n        if (participant) {\n            videoTracks = participant.getTracksByMediaType(MediaType.VIDEO);\n            if (videoTracks) {\n                ssrcs\n                    = ssrcs.filter(\n                        ssrc => videoTracks.find(\n                            track =>\n                                !track.isMuted()\n                                    && track.getSSRC() === ssrc\n                                    && track.videoType === videoType));\n            }\n        } else {\n            videoTracks = this._conference.getLocalTracks(MediaType.VIDEO);\n            ssrcs\n                = ssrcs.filter(\n                    ssrc => videoTracks.find(\n                        track =>\n                            !track.isMuted()\n                                && tpc.getLocalSSRC(track) === ssrc\n                                && track.videoType === videoType));\n        }\n\n        let peerPixelsSum = 0;\n        let peerSsrcCount = 0;\n\n        for (const ssrc of ssrcs) {\n            const peerSsrcPixels\n                = Number(videos[ssrc].height) * Number(videos[ssrc].width);\n\n            // FPS is reported as 0 for users with no video\n            if (!isNaN(peerSsrcPixels) && peerSsrcPixels > 0) {\n                peerPixelsSum += peerSsrcPixels;\n                peerSsrcCount += 1;\n            }\n        }\n\n        return peerPixelsSum / peerSsrcCount;\n    }\n\n\n    /**\n     * Calculates average FPS for the report\n     * @param {go figure} frameRate\n     * @param {boolean} isLocal if the average is to be calculated for the local\n     * video or <tt>false</tt> if for remote videos.\n     * @param {VideoType} videoType\n     * @return {number|NaN} average FPS or <tt>NaN</tt> if there are no samples.\n     * @private\n     */\n    _calculateAvgVideoFps(frameRate, isLocal, videoType) {\n        let peerFpsSum = 0;\n        let peerCount = 0;\n        const myID = this._conference.myUserId();\n\n        for (const peerID of Object.keys(frameRate)) {\n            if (isLocal ? peerID === myID : peerID !== myID) {\n                const participant\n                    = isLocal\n                        ? null : this._conference.getParticipantById(peerID);\n                const videosFps = frameRate[peerID];\n\n                // Do not continue without participant for non local peerID\n                if ((isLocal || participant) && videosFps) {\n                    const peerAvgFPS\n                        = this._calculatePeerAvgVideoFps(\n                            videosFps, participant, videoType);\n\n                    if (!isNaN(peerAvgFPS)) {\n                        peerFpsSum += peerAvgFPS;\n                        peerCount += 1;\n                    }\n                }\n            }\n        }\n\n        return peerFpsSum / peerCount;\n    }\n\n    /**\n     * Calculate average FPS for either remote or local participant\n     * @param {object} videos maps FPS per video SSRC\n     * @param {JitsiParticipant|null} participant remote participant or\n     * <tt>null</tt> for local FPS calculation.\n     * @param {VideoType} videoType the type of the video for which an average\n     * will be calculated.\n     * @return {number|NaN} average FPS of all participant's videos or\n     * <tt>NaN</tt> if currently not available\n     * @private\n     */\n    _calculatePeerAvgVideoFps(videos, participant, videoType) {\n        let ssrcs = Object.keys(videos).map(ssrc => Number(ssrc));\n        let videoTracks = null;\n\n        // NOTE that this method is supposed to be called for the stats\n        // received from the current peerconnection.\n        const tpc = this._conference.getActivePeerConnection();\n\n        if (participant) {\n            videoTracks = participant.getTracksByMediaType(MediaType.VIDEO);\n            if (videoTracks) {\n                ssrcs\n                    = ssrcs.filter(\n                        ssrc => videoTracks.find(\n                            track => !track.isMuted()\n                                && track.getSSRC() === ssrc\n                                && track.videoType === videoType));\n            }\n        } else {\n            videoTracks = this._conference.getLocalTracks(MediaType.VIDEO);\n            ssrcs\n                = ssrcs.filter(\n                    ssrc => videoTracks.find(\n                        track => !track.isMuted()\n                            && tpc.getLocalSSRC(track) === ssrc\n                            && track.videoType === videoType));\n        }\n\n        let peerFpsSum = 0;\n        let peerSsrcCount = 0;\n\n        for (const ssrc of ssrcs) {\n            const peerSsrcFps = Number(videos[ssrc]);\n\n            // FPS is reported as 0 for users with no video\n            if (!isNaN(peerSsrcFps) && peerSsrcFps > 0) {\n                peerFpsSum += peerSsrcFps;\n                peerSsrcCount += 1;\n            }\n        }\n\n        return peerFpsSum / peerSsrcCount;\n    }\n\n    /**\n     * Sends the 'transport.stats' analytics event whenever we detect that\n     * there is a change in the local or remote candidate type on the transport\n     * that is currently selected.\n     * @param {*} data\n     * @private\n     */\n    _maybeSendTransportAnalyticsEvent(data) {\n        if (!data || !data.transport || !data.transport.length) {\n            return;\n        }\n        const transportStats = {\n            p2p: data.transport[0].p2p,\n            'local_candidate_type': data.transport[0].localCandidateType,\n            'remote_candidate_type': data.transport[0].remoteCandidateType,\n            'transport_type': data.transport[0].type\n        };\n\n        if (!this._cachedTransportStats || !isEqual(transportStats, this._cachedTransportStats)) {\n            this._cachedTransportStats = transportStats;\n            Statistics.sendAnalytics(createTransportStatsEvent(transportStats));\n        }\n    }\n\n    /**\n     * Resets the stats related to JVB connection. Must not be called when in\n     * P2P mode, because then the {@link AverageStatReport} instances are\n     * tracking P2P stats. Note that this should never happen unless something\n     * is wrong with the P2P and JVB121 events.\n     * @private\n     */\n    _resetAvgJvbStats() {\n        this._resetAvgStats();\n        this.jvbStatsMonitor._resetAvgStats();\n    }\n\n    /**\n     * Reset cache of all averages and {@link _sampleIdx}.\n     * @private\n     */\n    _resetAvgStats() {\n        this._avgAudioBitrateUp.reset();\n        this._avgAudioBitrateDown.reset();\n\n        this._avgVideoBitrateUp.reset();\n        this._avgVideoBitrateDown.reset();\n\n        this._avgBandwidthUp.reset();\n        this._avgBandwidthDown.reset();\n\n        this._avgPacketLossUp.reset();\n        this._avgPacketLossDown.reset();\n        this._avgPacketLossTotal.reset();\n\n        this._avgRemoteFPS.reset();\n        this._avgRemoteScreenFPS.reset();\n        this._avgLocalFPS.reset();\n        this._avgLocalScreenFPS.reset();\n\n        this._avgRemoteCameraPixels.reset();\n        this._avgRemoteScreenPixels.reset();\n        this._avgLocalCameraPixels.reset();\n        this._avgLocalScreenPixels.reset();\n\n        this._avgCQ.reset();\n\n        this._sampleIdx = 0;\n    }\n\n    /**\n     * Unregisters all event listeners and stops working.\n     */\n    dispose() {\n        this._conference.off(\n            ConferenceEvents.P2P_STATUS,\n            this._onP2PStatusChanged);\n        this._conference.off(\n            ConnectionQualityEvents.LOCAL_STATS_UPDATED,\n            this._onLocalStatsUpdated);\n        this._conference.off(\n            ConferenceEvents.JVB121_STATUS,\n            this._onJvb121StatusChanged);\n        this.jvbStatsMonitor.dispose();\n        this.p2pStatsMonitor.dispose();\n    }\n}\n","import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nimport SpeakerStats from './SpeakerStats';\n\n\n/**\n * The value to use for the \"type\" field for messages sent\n * over the data channel that contain a face landmark.\n */\n\nconst FACE_LANDMARK_MESSAGE_TYPE = 'face-landmarks';\n\n/**\n * A collection for tracking speaker stats. Attaches listeners\n * to the conference to automatically update on tracked events.\n */\nexport default class SpeakerStatsCollector {\n    /**\n     * Initializes a new SpeakerStatsCollector instance.\n     *\n     * @constructor\n     * @param {JitsiConference} conference - The conference to track.\n     * @returns {void}\n     */\n    constructor(conference) {\n        this.stats = {\n            users: {\n\n                // userId: SpeakerStats\n            },\n            dominantSpeakerId: null\n        };\n\n        const userId = conference.myUserId();\n\n        this.stats.users[userId] = new SpeakerStats(userId, null, true);\n        this.conference = conference;\n\n        conference.addEventListener(\n            JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,\n            this._onDominantSpeaker.bind(this));\n        conference.addEventListener(\n            JitsiConferenceEvents.USER_JOINED,\n            this._onUserJoin.bind(this));\n        conference.addEventListener(\n            JitsiConferenceEvents.USER_LEFT,\n            this._onUserLeave.bind(this));\n        conference.addEventListener(\n            JitsiConferenceEvents.DISPLAY_NAME_CHANGED,\n            this._onDisplayNameChange.bind(this));\n\n        conference.on(\n            JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\n                (participant, { type, faceLandmarks }) => {\n                    if (type === FACE_LANDMARK_MESSAGE_TYPE) {\n                        this._onFaceLandmarkAdd(participant.getId(), faceLandmarks);\n                    }\n                });\n        if (conference.xmpp) {\n            conference.xmpp.addListener(\n                XMPPEvents.SPEAKER_STATS_RECEIVED,\n                this._updateStats.bind(this));\n        }\n    }\n\n    /**\n     * Reacts to dominant speaker change events by changing its speaker stats\n     * models to reflect the current dominant speaker.\n     *\n     * @param {string} dominantSpeakerId - The user id of the new dominant speaker.\n     * @param {Array[string]} previous - The array with previous speakers.\n     * @param {boolean} silence - Indecates whether the dominant speaker is silent or not.\n     * @returns {void}\n     * @private\n     */\n    _onDominantSpeaker(dominantSpeakerId, previous, silence) {\n        const oldDominantSpeaker\n            = this.stats.users[this.stats.dominantSpeakerId];\n        const newDominantSpeaker = this.stats.users[dominantSpeakerId];\n\n        oldDominantSpeaker && oldDominantSpeaker.setDominantSpeaker(false);\n        newDominantSpeaker && newDominantSpeaker.setDominantSpeaker(true, silence);\n        this.stats.dominantSpeakerId = dominantSpeakerId;\n    }\n\n    /**\n     * Reacts to user join events by creating a new SpeakerStats model.\n     *\n     * @param {string} userId - The user id of the new user.\n     * @param {JitsiParticipant} - The JitsiParticipant model for the new user.\n     * @returns {void}\n     * @private\n     */\n    _onUserJoin(userId, participant) {\n        if (participant.isHidden()) {\n            return;\n        }\n\n        if (!this.stats.users[userId]) {\n            this.stats.users[userId] = new SpeakerStats(userId, participant.getDisplayName());\n        }\n    }\n\n    /**\n     * Reacts to user leave events by updating the associated user's\n     * SpeakerStats model.\n     *\n     * @param {string} userId - The user id of the user that left.\n     * @returns {void}\n     * @private\n     */\n    _onUserLeave(userId) {\n        const savedUser = this.stats.users[userId];\n\n        if (savedUser) {\n            savedUser.markAsHasLeft();\n        }\n    }\n\n    /**\n     * Reacts to user name change events by updating the last known name\n     * tracked in the associated SpeakerStats model.\n     *\n     * @param {string} userId - The user id of the user that left.\n     * @returns {void}\n     * @private\n     */\n    _onDisplayNameChange(userId, newName) {\n        const savedUser = this.stats.users[userId];\n\n        if (savedUser) {\n            savedUser.setDisplayName(newName);\n        }\n    }\n\n    /**\n     * Processes a new face landmark object of a remote user.\n     *\n     * @param {string} userId - The user id of the user that left.\n     * @param {Object} data - The face landmark object.\n     * @returns {void}\n     * @private\n     */\n    _onFaceLandmarkAdd(userId, data) {\n        const savedUser = this.stats.users[userId];\n\n        if (savedUser && data) {\n            savedUser.addFaceLandmarks(data);\n        }\n    }\n\n    /**\n     * Return a copy of the tracked SpeakerStats models.\n     *\n     * @returns {Object} The keys are the user ids and the values are the\n     * associated user's SpeakerStats model.\n     */\n    getStats() {\n        return this.stats.users;\n    }\n\n    /**\n     * Updates of the current stats is requested, passing the new values.\n     *\n     * @param {Object} newStats - The new values used to update current one.\n     * @private\n     */\n    _updateStats(newStats) {\n        for (const userId in newStats) { // eslint-disable-line guard-for-in\n            let speakerStatsToUpdate;\n            const newParticipant = this.conference.getParticipantById(userId);\n\n            // we want to ignore hidden participants\n            if (!newParticipant || !newParticipant.isHidden()) {\n                if (this.stats.users[userId]) {\n                    speakerStatsToUpdate = this.stats.users[userId];\n\n                    if (!speakerStatsToUpdate.getDisplayName()) {\n                        speakerStatsToUpdate\n                            .setDisplayName(newStats[userId].displayName);\n                    }\n                } else {\n                    speakerStatsToUpdate = new SpeakerStats(\n                        userId, newStats[userId].displayName);\n                    this.stats.users[userId] = speakerStatsToUpdate;\n                    speakerStatsToUpdate.markAsHasLeft();\n                }\n\n                speakerStatsToUpdate.totalDominantSpeakerTime\n                    = newStats[userId].totalDominantSpeakerTime;\n\n                if (Array.isArray(newStats[userId].faceLandmarks)) {\n                    speakerStatsToUpdate.setFaceLandmarks(newStats[userId].faceLandmarks);\n                }\n            }\n        }\n    }\n}\n","/* eslint-disable max-params */\n\n/**\n * This object stores variables needed around the recording of an audio stream\n * and passing this recording along with additional information along to\n * different processes\n */\nexport default class RecordingResult {\n    /**\n     * @param blob the recording audio stream as a single blob\n     * @param name the name of the person of the audio stream\n     * @param startTime the time in UTC when recording of the audiostream started\n     * @param wordArray the recorder audio stream transcribed as an array of Word objects\n     */\n    constructor(blob, name, startTime, wordArray) {\n        this.blob = blob;\n        this.name = name;\n        this.startTime = startTime;\n        this.wordArray = wordArray;\n    }\n}\n","/**\n * A TrackRecorder object holds all the information needed for recording a\n * single JitsiTrack (either remote or local)\n * @param track The JitsiTrack the object is going to hold\n */\nexport default class TrackRecorder {\n    /**\n     * @param track The JitsiTrack the object is going to hold\n     */\n    constructor(track) {\n        // The JitsiTrack holding the stream\n        this.track = track;\n\n        // The MediaRecorder recording the stream\n        this.recorder = null;\n\n        // The array of data chunks recorded from the stream\n        // acts as a buffer until the data is stored on disk\n        this.data = null;\n\n        // the name of the person of the JitsiTrack. This can be undefined and/or\n        // not unique\n        this.name = null;\n\n        // the time of the start of the recording\n        this.startTime = null;\n    }\n}\n","import RecordingResult from './recordingResult';\nimport TrackRecorder from './trackRecorder';\n\n/**\n * Possible audio formats MIME types\n */\nconst AUDIO_WEBM = 'audio/webm'; // Supported in chrome\nconst AUDIO_OGG = 'audio/ogg'; // Supported in firefox\n\n/**\n * Starts the recording of a JitsiTrack in a TrackRecorder object.\n * This will also define the timestamp and try to update the name\n * @param trackRecorder the TrackRecorder to start\n */\nfunction startRecorder(trackRecorder) {\n    if (trackRecorder.recorder === undefined) {\n        throw new Error('Passed an object to startRecorder which is not a '\n            + 'TrackRecorder object');\n    }\n    trackRecorder.recorder.start();\n    trackRecorder.startTime = new Date();\n}\n\n/**\n * Stops the recording of a JitsiTrack in a TrackRecorder object.\n * This will also try to update the name\n * @param trackRecorder the TrackRecorder to stop\n */\nfunction stopRecorder(trackRecorder) {\n    if (trackRecorder.recorder === undefined) {\n        throw new Error('Passed an object to stopRecorder which is not a '\n            + 'TrackRecorder object');\n    }\n    trackRecorder.recorder.stop();\n}\n\n/**\n * Determines which kind of audio recording the browser supports\n * chrome supports \"audio/webm\" and firefox supports \"audio/ogg\"\n */\nfunction determineCorrectFileType() {\n    if (MediaRecorder.isTypeSupported(AUDIO_WEBM)) {\n        return AUDIO_WEBM;\n    } else if (MediaRecorder.isTypeSupported(AUDIO_OGG)) {\n        return AUDIO_OGG;\n    }\n    throw new Error(\n        'unable to create a MediaRecorder with the right mimetype!');\n}\n\n/**\n * main exported object of the file, holding all\n * relevant functions and variables for the outside world\n * @param jitsiConference the jitsiConference which this object\n * is going to record\n */\nfunction AudioRecorder(jitsiConference) {\n    // array of TrackRecorders, where each trackRecorder\n    // holds the JitsiTrack, MediaRecorder and recorder data\n    this.recorders = [];\n\n    // get which file type is supported by the current browser\n    this.fileType = determineCorrectFileType();\n\n    // boolean flag for active recording\n    this.isRecording = false;\n\n    // the jitsiconference the object is recording\n    this.jitsiConference = jitsiConference;\n}\n\n/**\n * Add the exported module so that it can be accessed by other files\n */\nAudioRecorder.determineCorrectFileType = determineCorrectFileType;\n\n/**\n * Adds a new TrackRecorder object to the array.\n *\n * @param track the track potentially holding an audio stream\n */\nAudioRecorder.prototype.addTrack = function(track) {\n    if (track.isAudioTrack()) {\n        // create the track recorder\n        const trackRecorder = this.instantiateTrackRecorder(track);\n\n        // push it to the local array of all recorders\n\n        this.recorders.push(trackRecorder);\n\n        // update the name of the trackRecorders\n        this.updateNames();\n\n        // If we're already recording, immediately start recording this new\n        // track.\n        if (this.isRecording) {\n            startRecorder(trackRecorder);\n        }\n    }\n};\n\n/**\n * Creates a TrackRecorder object. Also creates the MediaRecorder and\n * data array for the trackRecorder.\n * @param track the JitsiTrack holding the audio MediaStream(s)\n */\nAudioRecorder.prototype.instantiateTrackRecorder = function(track) {\n    const trackRecorder = new TrackRecorder(track);\n\n    // Create a new stream which only holds the audio track\n    const originalStream = trackRecorder.track.getOriginalStream();\n    const stream = new MediaStream();\n\n    originalStream.getAudioTracks().forEach(t => stream.addTrack(t));\n\n    // Create the MediaRecorder\n    trackRecorder.recorder = new MediaRecorder(stream,\n        { mimeType: this.fileType });\n\n    // array for holding the recorder data. Resets it when\n    // audio already has been recorder once\n    trackRecorder.data = [];\n\n    // function handling a dataEvent, e.g the stream gets new data\n    trackRecorder.recorder.ondataavailable = function(dataEvent) {\n        if (dataEvent.data.size > 0) {\n            trackRecorder.data.push(dataEvent.data);\n        }\n    };\n\n    return trackRecorder;\n};\n\n/**\n * Notifies the module that a specific track has stopped, e.g participant left\n * the conference.\n * if the recording has not started yet, the TrackRecorder will be removed from\n * the array. If the recording has started, the recorder will stop recording\n * but not removed from the array so that the recorded stream can still be\n * accessed\n *\n * @param {JitsiTrack} track the JitsiTrack to remove from the recording session\n */\nAudioRecorder.prototype.removeTrack = function(track) {\n    if (track.isVideoTrack()) {\n        return;\n    }\n\n    const array = this.recorders;\n    let i;\n\n    for (i = 0; i < array.length; i++) {\n        if (array[i].track.getParticipantId() === track.getParticipantId()) {\n            const recorderToRemove = array[i];\n\n            if (this.isRecording) {\n                stopRecorder(recorderToRemove);\n            } else {\n                // remove the TrackRecorder from the array\n                array.splice(i, 1);\n            }\n        }\n    }\n\n    // make sure the names are up to date\n    this.updateNames();\n};\n\n/**\n * Tries to update the name value of all TrackRecorder in the array.\n * If it hasn't changed,it will keep the exiting name. If it changes to a\n * undefined value, the old value will also be kept.\n */\nAudioRecorder.prototype.updateNames = function() {\n    const conference = this.jitsiConference;\n\n    this.recorders.forEach(trackRecorder => {\n        if (trackRecorder.track.isLocal()) {\n            trackRecorder.name = 'the transcriber';\n        } else {\n            const id = trackRecorder.track.getParticipantId();\n            const participant = conference.getParticipantById(id);\n            const newName = participant.getDisplayName();\n\n            if (newName !== 'undefined') {\n                trackRecorder.name = newName;\n            }\n        }\n    });\n};\n\n/**\n * Starts the audio recording of every local and remote track\n */\nAudioRecorder.prototype.start = function() {\n    if (this.isRecording) {\n        throw new Error('audiorecorder is already recording');\n    }\n\n    // set boolean isRecording flag to true so if new participants join the\n    // conference, that track can instantly start recording as well\n    this.isRecording = true;\n\n    // start all the mediaRecorders\n    this.recorders.forEach(trackRecorder => startRecorder(trackRecorder));\n\n    // log that recording has started\n    console.log(\n        `Started the recording of the audio. There are currently ${\n            this.recorders.length} recorders active.`);\n};\n\n/**\n * Stops the audio recording of every local and remote track\n */\nAudioRecorder.prototype.stop = function() {\n    // set the boolean flag to false\n    this.isRecording = false;\n\n    // stop all recorders\n    this.recorders.forEach(trackRecorder => stopRecorder(trackRecorder));\n    console.log('stopped recording');\n};\n\n/**\n * link hacking to download all recorded audio streams\n */\nAudioRecorder.prototype.download = function() {\n    this.recorders.forEach(trackRecorder => {\n        const blob = new Blob(trackRecorder.data, { type: this.fileType });\n        const url = URL.createObjectURL(blob);\n        const a = document.createElement('a');\n\n        document.body.appendChild(a);\n        a.style = 'display: none';\n        a.href = url;\n        a.download = `test.${this.fileType.split('/')[1]}`;\n        a.click();\n        window.URL.revokeObjectURL(url);\n    });\n};\n\n/**\n * returns the audio files of all recorders as an array of objects,\n * which include the name of the owner of the track and the starting time stamp\n * @returns {Array} an array of RecordingResult objects\n */\nAudioRecorder.prototype.getRecordingResults = function() {\n    if (this.isRecording) {\n        throw new Error(\n            'cannot get blobs because the AudioRecorder is still recording!');\n    }\n\n    // make sure the names are up to date before sending them off\n    this.updateNames();\n\n    const array = [];\n\n    this.recorders.forEach(\n        recorder =>\n            array.push(\n                new RecordingResult(\n                    new Blob(recorder.data, { type: this.fileType }),\n                    recorder.name,\n                    recorder.startTime)));\n\n    return array;\n};\n\n/**\n * Gets the mime type of the recorder audio\n * @returns {String} the mime type of the recorder audio\n */\nAudioRecorder.prototype.getFileType = function() {\n    return this.fileType;\n};\n\n/**\n * export the main object AudioRecorder\n */\nexport default AudioRecorder;\n","/**\n * An object representing a transcribed word, with some additional information\n * @param word the word\n * @param begin the time the word was started being uttered\n * @param end the time the word stopped being uttered\n */\nexport default class Word {\n    /**\n     * @param word the word\n     * @param begin the time the word was started being uttered\n     * @param end the time the word stopped being uttered\n     */\n    constructor(word, begin, end) {\n        this.word = word;\n        this.begin = begin;\n        this.end = end;\n    }\n\n    /**\n     * Get the string representation of the word\n     * @returns {*} the word as a string\n     */\n    getWord() {\n        return this.word;\n    }\n\n    /**\n     * Get the time the word started being uttered\n     * @returns {*} the start time as an integer\n     */\n    getBeginTime() {\n        return this.begin;\n    }\n\n    /**\n     * Get the time the word stopped being uttered\n     * @returns {*} the end time as an integer\n     */\n    getEndTime() {\n        return this.end;\n    }\n}\n","/**\n * Abstract class representing an interface to implement a speech-to-text\n * service on.\n */\nexport default class TranscriptionService {\n    /**\n     * Abstract class representing an interface to implement a speech-to-text\n     * service on.\n     */\n    constructor() {\n        throw new Error('TranscriptionService is abstract and cannot be created');\n    }\n\n    /**\n     * This method can be used to send the recorder audio stream and\n     * retrieve the answer from the transcription service from the callback\n     *\n     * @param {RecordingResult} recordingResult a recordingResult object which\n     * includes the recorded audio stream as a blob\n     * @param {Function} callback  which will retrieve the a RecordingResult with\n     *        the answer as a WordArray\n     */\n    send(recordingResult, callback) {\n        this.sendRequest(recordingResult.blob, response => {\n            if (this.verify(response)) {\n                recordingResult.wordArray = this.formatResponse(response);\n            } else {\n                console.log('the retrieved response from the server is not valid!');\n                recordingResult.wordArray = [];\n            }\n            callback(recordingResult);\n        });\n    }\n\n    /**\n     * Abstract method which will rend the recorder audio stream to the implemented\n     * transcription service and will retrieve an answer, which will be\n     * called on the given callback method\n     *\n     * @param {Blob} audioBlob the recorded audio stream as a single Blob\n     * @param {function} callback function which will retrieve the answer\n     *                            from the service\n     */\n    sendRequest(audioBlob, callback) { // eslint-disable-line no-unused-vars\n        throw new Error('TranscriptionService.sendRequest is abstract');\n    }\n\n    /**\n     * Abstract method which will parse the output from the implemented\n     * transcription service to the expected format\n     *\n     * The transcriber class expect an array of word objects, where each word\n     * object is one transcribed word by the service.\n     *\n     * The expected output of this method is an array of word objects, in\n     * the correct order. That is, the first object in the array is the first word\n     * being said, and the last word in the array is the last word being said\n     *\n     * @param response the answer from the speech-to-text server which needs to be\n     *                 formatted\n     * @return {Array<Word>} an array of Word objects\n     */\n    formatResponse(response) { // eslint-disable-line no-unused-vars\n        throw new Error('TranscriptionService.format is abstract');\n    }\n\n    /**\n     * Abstract method which will verify that the response from the server is valid\n     *\n     * @param response the response from the server\n     * @return {boolean} true if response is valid, false otherwise\n     */\n    verify(response) { // eslint-disable-line no-unused-vars\n        throw new Error('TranscriptionService.verify is abstract');\n    }\n}\n","/* global config */\n\nimport Word from '../word';\n\nimport audioRecorder from './../audioRecorder';\nimport AbstractTranscriptionService from './AbstractTranscriptionService';\n\n/**\n * Implements a TranscriptionService for a Sphinx4 http server\n */\nexport default class SphinxService extends AbstractTranscriptionService {\n    /**\n     * Implements a TranscriptionService for a Sphinx4 http server\n     */\n    constructor() {\n        super();\n\n        // set the correct url\n        this.url = getURL();\n    }\n\n    /**\n     * Overrides the sendRequest method from AbstractTranscriptionService\n     * it will send the audio stream the a Sphinx4 server to get the transcription\n     *\n     * @param audioFileBlob the recorder audio stream an a single Blob\n     * @param callback the callback function retrieving the server response\n     */\n    sendRequest(audioFileBlob, callback) {\n        console.log(`sending an audio file  to ${this.url}`);\n        console.log(`the audio file being sent: ${audioFileBlob}`);\n        const request = new XMLHttpRequest();\n\n        request.onreadystatechange = function() {\n            if (request.readyState === XMLHttpRequest.DONE\n                && request.status === 200) {\n                callback(request.responseText);\n            } else if (request.readyState === XMLHttpRequest.DONE) {\n                throw new Error(\n                    `unable to accept response from sphinx server. status: ${request.status}`);\n            }\n\n            // if not ready no point to throw an error\n        };\n        request.open('POST', this.url);\n        request.setRequestHeader('Content-Type',\n            audioRecorder.determineCorrectFileType());\n        request.send(audioFileBlob);\n        console.log(`send ${audioFileBlob}`);\n    }\n\n    /**\n     * Overrides the formatResponse method from AbstractTranscriptionService\n     * It will parse the answer from the server in the expected format\n     *\n     * @param response the JSON body retrieved from the Sphinx4 server\n     */\n    formatResponse(response) {\n        const result = JSON.parse(response).objects;\n\n        // make sure to delete the session id object, which is always\n        // the first value in the JSON array\n        result.shift();\n        const array = [];\n\n        result.forEach(\n            word => word.filler\n                || array.push(new Word(word.word, word.start, word.end)));\n\n        return array;\n    }\n\n    /**\n     * checks wether the reply is empty, or doesn't contain a correct JSON object\n     * @param response the server response\n     * @return {boolean} whether the response is valid\n     */\n    verify(response) {\n        console.log(`response from server:${response.toString()}`);\n\n        // test if server responded with a string object\n        if (typeof response !== 'string') {\n            return false;\n        }\n\n        // test if the string can be parsed into valid JSON\n        let json;\n\n        try {\n            json = JSON.parse(response);\n        } catch (error) {\n            console.log(error);\n\n            return false;\n        }\n\n        // check if the JSON has a \"objects\" value\n        if (json.objects === undefined) {\n            return false;\n        }\n\n        // get the \"objects\" value and check for a session ID\n        const array = json.objects;\n\n        if (!(array[0] && array[0]['session-id'])) {\n            return false;\n        }\n\n        // everything seems to be in order\n        return true;\n    }\n}\n\n/**\n * Gets the URL to the Sphinx4 server from the config file. If it's not there,\n * it will throw an error\n *\n * @returns {string} the URL to the sphinx4 server\n */\nfunction getURL() {\n    const message = 'config does not contain an url to a Sphinx4 https server';\n\n    if (config.sphinxURL === undefined) {\n        console.log(message);\n    } else {\n        const toReturn = config.sphinxURL;\n\n        if (toReturn.includes !== undefined && toReturn.includes('https://')) {\n            return toReturn;\n        }\n        console.log(message);\n\n    }\n}\n","import AudioRecorder from './audioRecorder';\nimport SphinxService from './transcriptionServices/SphinxTranscriptionService';\n\nconst BEFORE_STATE = 'before';\nconst RECORDING_STATE = 'recording';\nconst TRANSCRIBING_STATE = 'transcribing';\nconst FINISHED_STATE = 'finished';\n\n// the amount of characters each line in the transcription will have\nconst MAXIMUM_SENTENCE_LENGTH = 80;\n\n/**\n * This is the main object for handing the Transcription. It interacts with\n * the audioRecorder to record every person in a conference and sends the\n * recorder audio to a transcriptionService. The returned speech-to-text result\n * will be merged to create a transcript\n * @param {AudioRecorder} audioRecorder An audioRecorder recording a conference\n */\nfunction Transcriber() {\n    // the object which can record all audio in the conference\n    this.audioRecorder = new AudioRecorder();\n\n    // this object can send the recorder audio to a speech-to-text service\n    this.transcriptionService = new SphinxService();\n\n    // holds a counter to keep track if merging can start\n    this.counter = null;\n\n    // holds the date when transcription started which makes it possible\n    // to calculate the offset between recordings\n    this.startTime = null;\n\n    // will hold the transcription once it is completed\n    this.transcription = null;\n\n    // this will be a method which will be called once the transcription is done\n    // with the transcription as parameter\n    this.callback = null;\n\n    // stores all the retrieved speech-to-text results to merge together\n    // this value will store an Array<Word> object\n    this.results = [];\n\n    // Stores the current state of the transcription process\n    this.state = BEFORE_STATE;\n\n    // Used in the updateTranscription method to add a new line when the\n    // sentence becomes to long\n    this.lineLength = 0;\n}\n\n/**\n * Method to start the transcription process. It will tell the audioRecorder\n * to start storing all audio streams and record the start time for merging\n * purposes\n */\nTranscriber.prototype.start = function start() {\n    if (this.state !== BEFORE_STATE) {\n        throw new Error(\n            `The transcription can only start when it's in the \"${\n                BEFORE_STATE}\" state. It's currently in the \"${\n                this.state}\" state`);\n    }\n    this.state = RECORDING_STATE;\n    this.audioRecorder.start();\n    this.startTime = new Date();\n};\n\n/**\n * Method to stop the transcription process. It will tell the audioRecorder to\n * stop, and get all the recorded audio to send it to the transcription service\n\n * @param callback a callback which will receive the transcription\n */\nTranscriber.prototype.stop = function stop(callback) {\n    if (this.state !== RECORDING_STATE) {\n        throw new Error(\n            `The transcription can only stop when it's in the \"${\n                RECORDING_STATE}\" state. It's currently in the \"${\n                this.state}\" state`);\n    }\n\n    // stop the recording\n    console.log('stopping recording and sending audio files');\n    this.audioRecorder.stop();\n\n    // and send all recorded audio to the transcription service\n    const callBack = blobCallBack.bind(null, this);\n\n    this.audioRecorder.getRecordingResults().forEach(recordingResult => {\n        this.transcriptionService.send(recordingResult, callBack);\n        this.counter++;\n    });\n\n    // set the state to \"transcribing\" so that maybeMerge() functions correctly\n    this.state = TRANSCRIBING_STATE;\n\n    // and store the callback for later\n    this.callback = callback;\n};\n\n/**\n * This method gets the answer from the transcription service, calculates the\n * offset and adds is to every Word object. It will also start the merging\n * when every send request has been received\n *\n * note: Make sure to bind this as a Transcription object\n * @param {Transcriber} transcriber the transcriber instance\n * @param {RecordingResult} answer a RecordingResult object with a defined\n * WordArray\n */\nfunction blobCallBack(transcriber, answer) {\n    console.log(\n        'retrieved an answer from the transcription service. The answer has an'\n            + ` array of length: ${answer.wordArray.length}`);\n\n    // first add the offset between the start of the transcription and\n    // the start of the recording to all start and end times\n    if (answer.wordArray.length > 0) {\n        let offset = answer.startTime.getUTCMilliseconds()\n            - transcriber.startTime.getUTCMilliseconds();\n\n        // transcriber time will always be earlier\n\n        if (offset < 0) {\n            offset = 0; // presume 0 if it somehow not earlier\n        }\n\n        let array = '[';\n\n        answer.wordArray.forEach(wordObject => {\n            wordObject.begin += offset;\n            wordObject.end += offset;\n            array += `${wordObject.word},`;\n        });\n        array += ']';\n        console.log(array);\n\n        // give a name value to the Array object so that the merging can access\n        // the name value without having to use the whole recordingResult object\n        // in the algorithm\n        answer.wordArray.name = answer.name;\n    }\n\n    // then store the array and decrease the counter\n    transcriber.results.push(answer.wordArray);\n    transcriber.counter--;\n    console.log(`current counter: ${transcriber.counter}`);\n\n    // and check if all results have been received.\n    transcriber.maybeMerge();\n}\n\n/**\n * this method will check if the counter is zero. If it is, it will call\n * the merging method\n */\nTranscriber.prototype.maybeMerge = function() {\n    if (this.state === TRANSCRIBING_STATE && this.counter === 0) {\n        // make sure to include the events in the result arrays before\n        // merging starts\n        this.merge();\n    }\n};\n\n/**\n * This method will merge all speech-to-text arrays together in one\n * readable transcription string\n */\nTranscriber.prototype.merge = function() {\n    console.log(\n        `starting merge process!\\n The length of the array: ${\n            this.results.length}`);\n    this.transcription = '';\n\n    // the merging algorithm will look over all Word objects who are at pos 0 in\n    // every array. It will then select the one closest in time to the\n    // previously placed word, while removing the selected word from its array\n    // note: words can be skipped the skipped word's begin and end time somehow\n    // end up between the closest word start and end time\n    const arrays = this.results;\n\n    // arrays of Word objects\n    const potentialWords = []; // array of the first Word objects\n    // check if any arrays are already empty and remove them\n\n    hasPopulatedArrays(arrays);\n\n    // populate all the potential Words for a first time\n    arrays.forEach(array => pushWordToSortedArray(potentialWords, array));\n\n    // keep adding words to transcription until all arrays are exhausted\n    while (hasPopulatedArrays(arrays)) {\n        // first select the lowest array;\n        let lowestWordArray = arrays[0];\n\n        arrays.forEach(wordArray => {\n            if (wordArray[0].begin < lowestWordArray[0].begin) {\n                lowestWordArray = wordArray;\n            }\n        });\n\n        // put the word in the transcription\n        let wordToAdd = lowestWordArray.shift();\n\n        this.updateTranscription(wordToAdd, lowestWordArray.name);\n\n        // keep going until a word in another array has a smaller time\n        // or the array is empty\n        while (lowestWordArray.length > 0) {\n            let foundSmaller = false;\n            const wordToCompare = lowestWordArray[0].begin;\n\n            arrays.forEach(wordArray => {\n                if (wordArray[0].begin < wordToCompare) {\n                    foundSmaller = true;\n                }\n            });\n\n            // add next word if no smaller time has been found\n            if (foundSmaller) {\n                break;\n            }\n\n            wordToAdd = lowestWordArray.shift();\n            this.updateTranscription(wordToAdd, null);\n        }\n\n    }\n\n    // set the state to finished and do the necessary left-over tasks\n    this.state = FINISHED_STATE;\n    if (this.callback) {\n        this.callback(this.transcription);\n    }\n};\n\n/**\n * Appends a word object to the transcription. It will make a new line with a\n * name if a name is specified\n * @param {Word} word the Word object holding the word to append\n * @param {String|null} name the name of a new speaker. Null if not applicable\n */\nTranscriber.prototype.updateTranscription = function(word, name) {\n    if (name !== undefined && name !== null) {\n        this.transcription += `\\n${name}:`;\n        this.lineLength = name.length + 1; // +1 for the semi-colon\n    }\n    if (this.lineLength + word.word.length > MAXIMUM_SENTENCE_LENGTH) {\n        this.transcription += '\\n    ';\n        this.lineLength = 4; // because of the 4 spaces after the new line\n    }\n    this.transcription += ` ${word.word}`;\n    this.lineLength += word.word.length + 1; // +1 for the space\n};\n\n/**\n * Check if the given 2 dimensional array has any non-zero Word-arrays in them.\n * All zero-element arrays inside will be removed\n * If any non-zero-element arrays are found, the method will return true.\n * otherwise it will return false\n * @param {Array<Array>} twoDimensionalArray the array to check\n * @returns {boolean} true if any non-zero arrays inside, otherwise false\n */\nfunction hasPopulatedArrays(twoDimensionalArray) {\n    for (let i = 0; i < twoDimensionalArray.length; i++) {\n        if (twoDimensionalArray[i].length === 0) {\n            twoDimensionalArray.splice(i, 1);\n        }\n    }\n\n    return twoDimensionalArray.length > 0;\n}\n\n/**\n * Push a word to the right location in a sorted array. The array is sorted\n * from lowest to highest start time. Every word is stored in an object which\n * includes the name of the person saying the word.\n *\n * @param {Array<Word>} array the sorted array to push to\n * @param {Word} word the word to push into the array\n */\nfunction pushWordToSortedArray(array, word) {\n    if (array.length === 0) {\n        array.push(word);\n    } else {\n        if (array[array.length - 1].begin <= word.begin) {\n            array.push(word);\n\n            return;\n        }\n\n        for (let i = 0; i < array.length; i++) {\n            if (word.begin < array[i].begin) {\n                array.splice(i, 0, word);\n\n                return;\n            }\n        }\n        array.push(word); // fail safe\n    }\n}\n\n/**\n * Gives the transcriber a JitsiTrack holding an audioStream to transcribe.\n * The JitsiTrack is given to the audioRecorder. If it doesn't hold an\n * audiostream, it will not be added by the audioRecorder\n * @param {JitsiTrack} track the track to give to the audioRecorder\n */\nTranscriber.prototype.addTrack = function(track) {\n    this.audioRecorder.addTrack(track);\n};\n\n/**\n * Remove the given track from the auioRecorder\n * @param track\n */\nTranscriber.prototype.removeTrack = function(track) {\n    this.audioRecorder.removeTrack(track);\n};\n\n/**\n * Will return the created transcription if it's avialable or throw an error\n * when it's not done yet\n * @returns {String} the transcription as a String\n */\nTranscriber.prototype.getTranscription = function() {\n    if (this.state !== FINISHED_STATE) {\n        throw new Error(\n            `The transcription can only be retrieved when it's in the \"${\n                FINISHED_STATE}\" state. It's currently in the \"${\n                this.state}\" state`);\n    }\n\n    return this.transcription;\n};\n\n/**\n * Returns the current state of the transcription process\n */\nTranscriber.prototype.getState = function() {\n    return this.state;\n};\n\n/**\n * Resets the state to the \"before\" state, such that it's again possible to\n * call the start method\n */\nTranscriber.prototype.reset = function() {\n    this.state = BEFORE_STATE;\n    this.counter = null;\n    this.transcription = null;\n    this.startTime = null;\n    this.callback = null;\n    this.results = [];\n    this.lineLength = 0;\n};\n\nexport default Transcriber;\n","import Statistics from '../statistics/statistics';\n\nconst logger = require('@jitsi/logger').getLogger(__filename);\n\n/**\n * Creates new instance of <tt>ComponentsVersions</tt> which will be discovering\n * the versions of conferencing system components in given\n * <tt>JitsiConference</tt>.\n * @param conference <tt>JitsiConference</tt> instance which will be used to\n *        listen for focus presence updates.\n * @constructor\n */\nexport default function ComponentsVersions(conference) {\n\n    this.versions = {};\n\n    this.conference = conference;\n    this.conference.addCommandListener(\n        'versions', this.processVersions.bind(this));\n}\n\nComponentsVersions.prototype.processVersions\n    = function(versions, mucResource, mucJid) {\n        if (!this.conference.isFocus(mucJid)) {\n            logger.warn(\n                `Received versions not from the focus user: ${versions}`,\n                mucJid);\n\n            return;\n        }\n\n        const log = [];\n\n        versions.children.forEach(component => {\n\n            const name = component.attributes.name;\n            const version = component.value;\n\n            if (this.versions[name] !== version) {\n                this.versions[name] = version;\n                logger.info(`Got ${name} version: ${version}`);\n\n                log.push({\n                    id: 'component_version',\n                    component: name,\n                    version\n                });\n            }\n        });\n\n        // logs versions to stats\n        if (log.length > 0) {\n            Statistics.sendLog(JSON.stringify(log));\n        }\n    };\n\n/**\n * Obtains the version of conferencing system component.\n * @param componentName the name of the component for which we want to obtain\n *        the version.\n * @returns {String} which describes the version of the component identified by\n *          given <tt>componentName</tt> or <tt>undefined</tt> if not found.\n */\nComponentsVersions.prototype.getComponentVersion = function(componentName) {\n    return this.versions[componentName];\n};\n","export enum VideoSIPGWStatusConstants {\n    /**\n     * Status that video SIP GW service is available.\n     */\n    STATUS_AVAILABLE = 'available',\n\n    /**\n     * Status that video SIP GW service is not available.\n     */\n    STATUS_UNDEFINED = 'undefined',\n\n    /**\n     * Status that video SIP GW service is available but there are no free nodes\n     * at the moment to serve new requests.\n     */\n    STATUS_BUSY = 'busy'\n};\n\nexport enum VideoSIPGWStateConstants {\n    /**\n     * Video SIP GW session state, currently running.\n     */\n    STATE_ON = 'on',\n\n    /**\n     * Video SIP GW session state, currently stopped and not running.\n     */\n    STATE_OFF = 'off',\n\n    /**\n     * Video SIP GW session state, currently is starting.\n     */\n    STATE_PENDING = 'pending',\n\n    /**\n     * Video SIP GW session state, has observed some issues and is retrying at the\n     * moment.\n     */\n    STATE_RETRYING = 'retrying',\n\n    /**\n     * Video SIP GW session state, tried to start but it failed.\n     */\n    STATE_FAILED = 'failed'\n};\n\nexport enum VideoSIPGWErrorConstants {\n    /**\n     * Error on trying to create video SIP GW session in conference where\n     * there is no room connection (hasn't joined or has left the room).\n     */\n    ERROR_NO_CONNECTION = 'error_no_connection',\n\n    /**\n     * Error on trying to create video SIP GW session with address for which\n     * there is an already created session.\n     */\n    ERROR_SESSION_EXISTS = 'error_session_already_exists'\n};\n\n// exported for backward compatibility\nexport const STATUS_AVAILABLE = VideoSIPGWStatusConstants.STATUS_AVAILABLE;\nexport const STATUS_UNDEFINED = VideoSIPGWStatusConstants.STATUS_UNDEFINED;\nexport const STATUS_BUSY = VideoSIPGWStatusConstants.STATUS_BUSY;\n\nexport const STATE_ON = VideoSIPGWStateConstants.STATE_ON;\nexport const STATE_OFF = VideoSIPGWStateConstants.STATE_OFF;\nexport const STATE_PENDING = VideoSIPGWStateConstants.STATE_PENDING;\nexport const STATE_RETRYING = VideoSIPGWStateConstants.STATE_RETRYING;\nexport const STATE_FAILED = VideoSIPGWStateConstants.STATE_FAILED;\n\nexport const ERROR_NO_CONNECTION = VideoSIPGWErrorConstants.ERROR_NO_CONNECTION;\nexport const ERROR_SESSION_EXISTS = VideoSIPGWErrorConstants.ERROR_SESSION_EXISTS;\n","import { getLogger } from '@jitsi/logger';\nimport { $iq } from 'strophe.js';\n\nimport Listenable from '../util/Listenable';\n\nimport * as VideoSIPGWConstants from './VideoSIPGWConstants';\n\nconst logger = getLogger(__filename);\n\n/**\n * The event name for current sip video session state changed.\n * @type {string} event name for sip video session state changed.\n */\nconst STATE_CHANGED = 'STATE_CHANGED';\n\n/**\n * Jitsi video SIP GW session. Holding its state and able to start/stop it.\n * When session is in OFF or FAILED stated it cannot be used anymore.\n */\nexport default class JitsiVideoSIPGWSession extends Listenable {\n\n    /**\n     * Creates new session with the desired sip address and display name.\n     *\n     * @param {string} sipAddress - The sip address to use when\n     * starting the session.\n     * @param {string} displayName - The display name to use for\n     * that participant.\n     * @param {ChatRoom} chatRoom - The chat room this session is bound to.\n     */\n    constructor(sipAddress, displayName, chatRoom) {\n        super();\n\n        this.sipAddress = sipAddress;\n        this.displayName = displayName;\n        this.chatRoom = chatRoom;\n\n        /*\n         * The initial state is undefined. Initial state cannot be STATE_OFF,\n         * the session enters this state when it was in STATE_ON and was stopped\n         * and such session cannot be used anymore.\n         *\n         * @type {VideoSIPGWConstants|undefined}\n         */\n        this.state = undefined;\n    }\n\n    /**\n     * Stops the current session.\n     */\n    stop() {\n        if (this.state === VideoSIPGWConstants.STATE_OFF\n            || this.state === VideoSIPGWConstants.STATE_FAILED) {\n            logger.warn('Video SIP GW session already stopped or failed!');\n\n            return;\n        }\n\n        this._sendJibriIQ('stop');\n    }\n\n    /**\n     * Starts a new session. Sends an iq to the focus.\n     */\n    start() {\n        // if state is off, this session was active for some reason\n        // and we should create new one, rather than reusing it\n        if (this.state === VideoSIPGWConstants.STATE_ON\n            || this.state === VideoSIPGWConstants.STATE_OFF\n            || this.state === VideoSIPGWConstants.STATE_PENDING\n            || this.state === VideoSIPGWConstants.STATE_RETRYING) {\n            logger.warn('Video SIP GW session already started!');\n\n            return;\n        }\n\n        this._sendJibriIQ('start');\n    }\n\n    /**\n     * Changes the state of this session.\n     *\n     * @param {string} newState - The new {VideoSIPGWConstants} state to set.\n     * @param {string} [optional] failureReason - The reason why a failure state\n     * was entered.\n     * @returns {void}\n     */\n    setState(newState, failureReason) {\n        if (newState === this.state) {\n            return;\n        }\n\n        const oldState = this.state;\n\n        this.state = newState;\n        this.eventEmitter.emit(STATE_CHANGED,\n            {\n                address: this.sipAddress,\n                failureReason,\n                oldState,\n                newState: this.state,\n                displayName: this.displayName\n            }\n        );\n    }\n\n    /**\n     * Subscribes the passed listener to the event for state change of this\n     * session.\n     *\n     * @param {Function} listener - The function that will receive the event.\n     */\n    addStateListener(listener) {\n        this.addListener(STATE_CHANGED, listener);\n    }\n\n    /**\n     * Unsubscribes the passed handler.\n     *\n     * @param {Function} listener - The function to be removed.\n     */\n    removeStateListener(listener) {\n        this.removeListener(STATE_CHANGED, listener);\n    }\n\n    /**\n     * Sends a jibri command using an iq.\n     *\n     * @private\n     * @param {string} action - The action to send ('start' or 'stop').\n     */\n    _sendJibriIQ(action) {\n        const attributes = {\n            'xmlns': 'http://jitsi.org/protocol/jibri',\n            'action': action,\n            sipaddress: this.sipAddress\n        };\n\n        attributes.displayname = this.displayName;\n\n        const iq = $iq({\n            to: this.chatRoom.focusMucJid,\n            type: 'set' })\n            .c('jibri', attributes)\n            .up();\n\n        logger.debug(`${action} video SIP GW session`, iq.nodeTree);\n        this.chatRoom.connection.sendIQ(\n            iq,\n            () => {}, // eslint-disable-line no-empty-function\n            error => {\n                logger.error(\n                    `Failed to ${action} video SIP GW session, error: `, error);\n                this.setState(VideoSIPGWConstants.STATE_FAILED);\n            });\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nconst logger = getLogger(__filename);\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nimport JitsiVideoSIPGWSession from './JitsiVideoSIPGWSession';\nimport * as Constants from './VideoSIPGWConstants';\n\n/**\n * Main video SIP GW handler. Stores references of all created sessions.\n */\nexport default class VideoSIPGW {\n\n    /**\n     * Creates new handler.\n     *\n     * @param {ChatRoom} chatRoom - Tha chat room to handle.\n     */\n    constructor(chatRoom) {\n        this.chatRoom = chatRoom;\n        this.eventEmitter = chatRoom.eventEmitter;\n        logger.debug('creating VideoSIPGW');\n        this.sessions = {};\n\n        this.sessionStateChangeListener = this.sessionStateChanged.bind(this);\n\n        // VideoSIPGW, JitsiConference and ChatRoom are not reusable and no\n        // more than one VideoSIPGW can be created per JitsiConference,\n        // so we don't bother to cleanup\n        chatRoom.addPresenceListener('jibri-sip-call-state',\n            this.handleJibriSIPState.bind(this));\n    }\n\n    /**\n     * Handles presence nodes with name: jibri-sip-call-state.\n     *\n     * @param {Object} node the presence node Object to handle.\n     * Object representing part of the presence received over xmpp.\n     */\n    handleJibriSIPState(node) {\n        const attributes = node.attributes;\n\n        if (!attributes) {\n            return;\n        }\n\n        logger.debug('Handle video sip gw state : ', attributes);\n\n        const newState = attributes.state;\n\n        if (newState === this.state) {\n            return;\n        }\n\n        switch (newState) {\n        case Constants.STATE_ON:\n        case Constants.STATE_OFF:\n        case Constants.STATE_PENDING:\n        case Constants.STATE_RETRYING:\n        case Constants.STATE_FAILED: {\n            const address = attributes.sipaddress;\n\n            if (!address) {\n                return;\n            }\n\n            // find the corresponding session and set its state\n            const session = this.sessions[address];\n\n            if (session) {\n                session.setState(newState, attributes.failure_reason);\n            } else {\n                logger.warn('Video SIP GW session not found:', address);\n            }\n        }\n        }\n    }\n\n    /**\n     * Creates new session and stores its reference if it does not exist or\n     * returns an error otherwise.\n     *\n     * @param {string} sipAddress - The sip address to use.\n     * @param {string} displayName - The display name to use.\n     * @returns {JitsiVideoSIPGWSession|Error}\n     */\n    createVideoSIPGWSession(sipAddress, displayName) {\n        if (this.sessions[sipAddress]) {\n            logger.warn('There was already a Video SIP GW session for address',\n                sipAddress);\n\n            return new Error(Constants.ERROR_SESSION_EXISTS);\n        }\n\n        const session = new JitsiVideoSIPGWSession(\n            sipAddress, displayName, this.chatRoom);\n\n        session.addStateListener(this.sessionStateChangeListener);\n\n        this.sessions[sipAddress] = session;\n\n        return session;\n    }\n\n    /**\n     * Listener for session state changed. When a session goes to off or failed\n     * we delete its reference.\n     *\n     * @param {options} event - { address, oldState, newState, displayName }\n     */\n    sessionStateChanged(event) {\n        const address = event.address;\n\n        if (event.newState === Constants.STATE_OFF\n            || event.newState === Constants.STATE_FAILED) {\n            const session = this.sessions[address];\n\n            if (!session) {\n                logger.error('Missing Video SIP GW session with address:',\n                    address);\n\n                return;\n            }\n\n            session.removeStateListener(this.sessionStateChangeListener);\n            delete this.sessions[address];\n        }\n\n        this.eventEmitter.emit(\n            XMPPEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED,\n            event);\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { Strophe } from 'strophe.js';\n\nimport { MediaType } from '../../service/RTC/MediaType';\nimport * as SignalingEvents from '../../service/RTC/SignalingEvents';\nimport SignalingLayer, { getMediaTypeFromSourceName } from '../../service/RTC/SignalingLayer';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport FeatureFlags from '../flags/FeatureFlags';\n\nimport { filterNodeFromPresenceJSON } from './ChatRoom';\n\nconst logger = getLogger(__filename);\n\nexport const SOURCE_INFO_PRESENCE_ELEMENT = 'SourceInfo';\n\n/**\n * Default XMPP implementation of the {@link SignalingLayer} interface. Obtains\n * the data from the MUC presence.\n */\nexport default class SignalingLayerImpl extends SignalingLayer {\n    /**\n     * Creates new instance.\n     */\n    constructor() {\n        super();\n\n        /**\n         * A map that stores SSRCs of remote streams. And is used only locally\n         * We store the mapping when jingle is received, and later is used\n         * onaddstream webrtc event where we have only the ssrc\n         * FIXME: This map got filled and never cleaned and can grow during long\n         * conference\n         * @type {Map<number, string>} maps SSRC number to jid\n         */\n        this.ssrcOwners = new Map();\n\n        /**\n         *\n         * @type {ChatRoom|null}\n         */\n        this.chatRoom = null;\n\n        /**\n         * @type {Map<SourceName, SourceInfo>}\n         * @private\n         */\n        this._localSourceState = { };\n\n        /**\n         * @type {Map<EndpointId, Map<SourceName, SourceInfo>>}\n         * @private\n         */\n        this._remoteSourceState = { };\n\n        /**\n         * A map that stores the source name of a track identified by it's ssrc.\n         * We store the mapping when jingle is received, and later is used\n         * onaddstream webrtc event where we have only the ssrc\n         * FIXME: This map got filled and never cleaned and can grow during long\n         * conference\n         * @type {Map<number, string>} maps SSRC number to source name\n         */\n        this._sourceNames = new Map();\n    }\n\n    /**\n     * Adds <SourceInfo> element to the local presence.\n     *\n     * @returns {void}\n     * @private\n     */\n    _addLocalSourceInfoToPresence() {\n        if (this.chatRoom) {\n            return this.chatRoom.addOrReplaceInPresence(\n                SOURCE_INFO_PRESENCE_ELEMENT,\n                { value: JSON.stringify(this._localSourceState) });\n        }\n\n        return false;\n    }\n\n    /**\n     * Binds event listeners to the chat room instance.\n     * @param {ChatRoom} room\n     * @private\n     * @returns {void}\n     */\n    _bindChatRoomEventHandlers(room) {\n        // Add handlers for 'audiomuted', 'videomuted' and 'videoType' fields in presence in order to support interop\n        // with very old versions of mobile clients and jigasi that do not support source-name signaling.\n        const emitAudioMutedEvent = (endpointId, muted) => {\n            this.eventEmitter.emit(\n                SignalingEvents.PEER_MUTED_CHANGED,\n                endpointId,\n                MediaType.AUDIO,\n                muted);\n        };\n\n        this._audioMuteHandler = (node, from) => {\n            if (!this._doesEndpointSendNewSourceInfo(from)) {\n                emitAudioMutedEvent(from, node.value === 'true');\n            }\n        };\n        room.addPresenceListener('audiomuted', this._audioMuteHandler);\n\n        const emitVideoMutedEvent = (endpointId, muted) => {\n            this.eventEmitter.emit(\n                SignalingEvents.PEER_MUTED_CHANGED,\n                endpointId,\n                MediaType.VIDEO,\n                muted);\n        };\n\n        this._videoMuteHandler = (node, from) => {\n            if (!this._doesEndpointSendNewSourceInfo(from)) {\n                emitVideoMutedEvent(from, node.value === 'true');\n            }\n        };\n        room.addPresenceListener('videomuted', this._videoMuteHandler);\n\n        const emitVideoTypeEvent = (endpointId, videoType) => {\n            this.eventEmitter.emit(\n                SignalingEvents.PEER_VIDEO_TYPE_CHANGED,\n                endpointId, videoType);\n        };\n\n        this._videoTypeHandler = (node, from) => {\n            if (!this._doesEndpointSendNewSourceInfo(from)) {\n                emitVideoTypeEvent(from, node.value);\n            }\n        };\n        room.addPresenceListener('videoType', this._videoTypeHandler);\n\n        // Add handlers for presence in the new format.\n        this._sourceInfoHandler = (node, mucNick) => {\n            const endpointId = mucNick;\n            const { value } = node;\n            const sourceInfoJSON = JSON.parse(value);\n            const emitEventsFromHere = this._doesEndpointSendNewSourceInfo(endpointId);\n            const endpointSourceState\n                = this._remoteSourceState[endpointId] || (this._remoteSourceState[endpointId] = {});\n\n            for (const sourceName of Object.keys(sourceInfoJSON)) {\n                let sourceChanged = false;\n                const mediaType = getMediaTypeFromSourceName(sourceName);\n                const newMutedState = Boolean(sourceInfoJSON[sourceName].muted);\n                const oldSourceState = endpointSourceState[sourceName]\n                    || (endpointSourceState[sourceName] = { sourceName });\n\n                if (oldSourceState.muted !== newMutedState) {\n                    sourceChanged = true;\n                    oldSourceState.muted = newMutedState;\n                    if (emitEventsFromHere && !this._localSourceState[sourceName]) {\n                        this.eventEmitter.emit(SignalingEvents.SOURCE_MUTED_CHANGED, sourceName, newMutedState);\n                    }\n                }\n\n                // Assume a default videoType of 'camera' for video sources.\n                const newVideoType = mediaType === MediaType.VIDEO\n                    ? sourceInfoJSON[sourceName].videoType ?? VideoType.CAMERA\n                    : undefined;\n\n                if (oldSourceState.videoType !== newVideoType) {\n                    oldSourceState.videoType = newVideoType;\n                    sourceChanged = true;\n\n                    // Since having a mix of eps that do/don't support multi-stream in the same call is supported, emit\n                    // SOURCE_VIDEO_TYPE_CHANGED event when the remote source changes videoType.\n                    if (emitEventsFromHere && !this._localSourceState[sourceName]) {\n                        this.eventEmitter.emit(SignalingEvents.SOURCE_VIDEO_TYPE_CHANGED, sourceName, newVideoType);\n                    }\n                }\n\n                if (sourceChanged && FeatureFlags.isSsrcRewritingSupported()) {\n                    this.eventEmitter.emit(\n                        SignalingEvents.SOURCE_UPDATED,\n                        sourceName,\n                        mucNick,\n                        newMutedState,\n                        newVideoType);\n                }\n            }\n\n            // Cleanup removed source names\n            const newSourceNames = Object.keys(sourceInfoJSON);\n\n            for (const sourceName of Object.keys(endpointSourceState)) {\n                if (newSourceNames.indexOf(sourceName) === -1) {\n                    delete endpointSourceState[sourceName];\n                }\n            }\n        };\n        room.addPresenceListener('SourceInfo', this._sourceInfoHandler);\n\n        // Cleanup when participant leaves\n        this._memberLeftHandler = jid => {\n            const endpointId = Strophe.getResourceFromJid(jid);\n\n            delete this._remoteSourceState[endpointId];\n\n            for (const [ key, value ] of this.ssrcOwners.entries()) {\n                if (value === endpointId) {\n                    delete this._sourceNames[key];\n                }\n            }\n        };\n        room.addEventListener(XMPPEvents.MUC_MEMBER_LEFT, this._memberLeftHandler);\n    }\n\n    /**\n     * Check is given endpoint has advertised <SourceInfo/> in it's presence which means that the source name signaling\n     * is used by this endpoint.\n     *\n     * @param {EndpointId} endpointId\n     * @returns {boolean}\n     */\n    _doesEndpointSendNewSourceInfo(endpointId) {\n        const presence = this.chatRoom?.getLastPresence(endpointId);\n\n        return Boolean(presence && presence.find(node => node.tagName === SOURCE_INFO_PRESENCE_ELEMENT));\n    }\n\n    /**\n     * Logs a debug or error message to console depending on whether SSRC rewriting is enabled or not.\n     * Owner changes are permitted only when SSRC rewriting is enabled.\n     *\n     * @param {string} message - The message to be logged.\n     * @returns {void}\n     */\n    _logOwnerChangedMessage(message) {\n        if (FeatureFlags.isSsrcRewritingSupported()) {\n            logger.debug(message);\n        } else {\n            logger.error(message);\n        }\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getPeerMediaInfo(owner, mediaType, sourceName) {\n        const legacyGetPeerMediaInfo = () => {\n            if (this.chatRoom) {\n                return this.chatRoom.getMediaPresenceInfo(owner, mediaType);\n            }\n            logger.warn('Requested peer media info, before room was set');\n        };\n\n        const lastPresence = this.chatRoom?.getLastPresence(owner);\n\n        if (!lastPresence) {\n            logger.warn(`getPeerMediaInfo - no presence stored for: ${owner}`);\n\n            return;\n        }\n        if (!this._doesEndpointSendNewSourceInfo(owner)) {\n            return legacyGetPeerMediaInfo();\n        }\n\n        if (sourceName) {\n            return this.getPeerSourceInfo(owner, sourceName);\n        }\n\n        const mediaInfo = {\n            muted: true\n        };\n\n        if (mediaType === MediaType.VIDEO) {\n            mediaInfo.videoType = undefined;\n            const codecTypeNode = filterNodeFromPresenceJSON(lastPresence, 'jitsi_participant_codecType');\n\n            if (codecTypeNode.length > 0) {\n                mediaInfo.codecType = codecTypeNode[0].value;\n            }\n        }\n\n        return mediaInfo;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getPeerSourceInfo(owner, sourceName) {\n        const mediaInfo = {\n            muted: true, // muted by default\n            videoType: VideoType.CAMERA // 'camera' by default\n        };\n\n        return this._remoteSourceState[owner]\n            ? this._remoteSourceState[owner][sourceName] ?? mediaInfo\n            : undefined;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getSSRCOwner(ssrc) {\n        return this.ssrcOwners.get(ssrc);\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getTrackSourceName(ssrc) {\n        return this._sourceNames.get(ssrc);\n    }\n\n    /**\n     * @inheritDoc\n     */\n    removeSSRCOwners(ssrcList) {\n        if (!ssrcList?.length) {\n            return;\n        }\n\n        for (const ssrc of ssrcList) {\n            this.ssrcOwners.delete(ssrc);\n        }\n    }\n\n    /**\n     * Sets the <tt>ChatRoom</tt> instance used and binds presence listeners.\n     * @param {ChatRoom} room\n     */\n    setChatRoom(room) {\n        const oldChatRoom = this.chatRoom;\n\n        this.chatRoom = room;\n        if (oldChatRoom) {\n            oldChatRoom.removePresenceListener(\n                'audiomuted', this._audioMuteHandler);\n            oldChatRoom.removePresenceListener(\n                'videomuted', this._videoMuteHandler);\n            oldChatRoom.removePresenceListener(\n                'videoType', this._videoTypeHandler);\n            this._sourceInfoHandler\n                && oldChatRoom.removePresenceListener(SOURCE_INFO_PRESENCE_ELEMENT, this._sourceInfoHandler);\n            this._memberLeftHandler\n                && oldChatRoom.removeEventListener(XMPPEvents.MUC_MEMBER_LEFT, this._memberLeftHandler);\n        }\n        if (room) {\n            this._bindChatRoomEventHandlers(room);\n            this._addLocalSourceInfoToPresence();\n        }\n    }\n\n    /**\n     * @inheritDoc\n     */\n    setSSRCOwner(ssrc, endpointId) {\n        if (typeof ssrc !== 'number') {\n            throw new TypeError(`SSRC(${ssrc}) must be a number`);\n        }\n\n        // Now signaling layer instance is shared between different JingleSessionPC instances, so although very unlikely\n        // an SSRC conflict could potentially occur. Log a message to make debugging easier.\n        const existingOwner = this.ssrcOwners.get(ssrc);\n\n        if (existingOwner && existingOwner !== endpointId) {\n            this._logOwnerChangedMessage(`SSRC owner re-assigned from ${existingOwner} to ${endpointId}`);\n        }\n        this.ssrcOwners.set(ssrc, endpointId);\n    }\n\n    /**\n     * @inheritDoc\n     */\n    setTrackMuteStatus(sourceName, muted) {\n        if (!this._localSourceState[sourceName]) {\n            this._localSourceState[sourceName] = {};\n        }\n\n        this._localSourceState[sourceName].muted = muted;\n\n        if (this.chatRoom) {\n            return this._addLocalSourceInfoToPresence();\n        }\n\n        return false;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    setTrackSourceName(ssrc, sourceName) {\n        if (typeof ssrc !== 'number') {\n            throw new TypeError(`SSRC(${ssrc}) must be a number`);\n        }\n\n        // Now signaling layer instance is shared between different JingleSessionPC instances, so although very unlikely\n        // an SSRC conflict could potentially occur. Log a message to make debugging easier.\n        const existingName = this._sourceNames.get(ssrc);\n\n        if (existingName && existingName !== sourceName) {\n            this._logOwnerChangedMessage(`SSRC(${ssrc}) sourceName re-assigned from ${existingName} to ${sourceName}`);\n        }\n\n        this._sourceNames.set(ssrc, sourceName);\n    }\n\n    /**\n     * @inheritDoc\n     */\n    setTrackVideoType(sourceName, videoType) {\n        if (!this._localSourceState[sourceName]) {\n            this._localSourceState[sourceName] = {};\n        }\n\n        if (this._localSourceState[sourceName].videoType !== videoType) {\n            // Include only if not a camera (default)\n            this._localSourceState[sourceName].videoType = videoType === VideoType.CAMERA ? undefined : videoType;\n\n            return this._addLocalSourceInfoToPresence();\n        }\n\n        return false;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    updateSsrcOwnersOnLeave(id) {\n        const ssrcs = Array.from(this.ssrcOwners)\n            .filter(entry => entry[1] === id)\n            .map(entry => entry[0]);\n\n        if (!ssrcs?.length) {\n            return;\n        }\n\n        this.removeSSRCOwners(ssrcs);\n    }\n\n}\n","import { getLogger } from '@jitsi/logger';\nimport EventEmitter from 'events';\nimport $ from 'jquery';\nimport isEqual from 'lodash.isequal';\nimport { Strophe } from 'strophe.js';\n\nimport * as JitsiConferenceErrors from './JitsiConferenceErrors';\nimport JitsiConferenceEventManager from './JitsiConferenceEventManager';\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\nimport JitsiParticipant from './JitsiParticipant';\nimport JitsiTrackError from './JitsiTrackError';\nimport * as JitsiTrackErrors from './JitsiTrackErrors';\nimport * as JitsiTrackEvents from './JitsiTrackEvents';\nimport authenticateAndUpgradeRole from './authenticateAndUpgradeRole';\nimport { CodecSelection } from './modules/RTC/CodecSelection';\nimport RTC from './modules/RTC/RTC';\nimport { SS_DEFAULT_FRAME_RATE } from './modules/RTC/ScreenObtainer';\nimport browser from './modules/browser';\nimport ConnectionQuality from './modules/connectivity/ConnectionQuality';\nimport IceFailedHandling from './modules/connectivity/IceFailedHandling';\nimport * as DetectionEvents from './modules/detection/DetectionEvents';\nimport NoAudioSignalDetection from './modules/detection/NoAudioSignalDetection';\nimport P2PDominantSpeakerDetection from './modules/detection/P2PDominantSpeakerDetection';\nimport VADAudioAnalyser from './modules/detection/VADAudioAnalyser';\nimport VADNoiseDetection from './modules/detection/VADNoiseDetection';\nimport VADTalkMutedDetection from './modules/detection/VADTalkMutedDetection';\nimport { E2EEncryption } from './modules/e2ee/E2EEncryption';\nimport E2ePing from './modules/e2eping/e2eping';\nimport Jvb121EventGenerator from './modules/event/Jvb121EventGenerator';\nimport FeatureFlags from './modules/flags/FeatureFlags';\nimport { LiteModeContext } from './modules/litemode/LiteModeContext';\nimport ReceiveVideoController from './modules/qualitycontrol/ReceiveVideoController';\nimport SendVideoController from './modules/qualitycontrol/SendVideoController';\nimport RecordingManager from './modules/recording/RecordingManager';\nimport Settings from './modules/settings/Settings';\nimport AudioOutputProblemDetector from './modules/statistics/AudioOutputProblemDetector';\nimport AvgRTPStatsReporter from './modules/statistics/AvgRTPStatsReporter';\nimport LocalStatsCollector from './modules/statistics/LocalStatsCollector';\nimport SpeakerStatsCollector from './modules/statistics/SpeakerStatsCollector';\nimport Statistics from './modules/statistics/statistics';\nimport Transcriber from './modules/transcription/transcriber';\nimport GlobalOnErrorHandler from './modules/util/GlobalOnErrorHandler';\nimport RandomUtil from './modules/util/RandomUtil';\nimport ComponentsVersions from './modules/version/ComponentsVersions';\nimport VideoSIPGW from './modules/videosipgw/VideoSIPGW';\nimport * as VideoSIPGWConstants from './modules/videosipgw/VideoSIPGWConstants';\nimport SignalingLayerImpl from './modules/xmpp/SignalingLayerImpl';\nimport {\n    FEATURE_E2EE,\n    FEATURE_JIGASI,\n    JITSI_MEET_MUC_TYPE\n} from './modules/xmpp/xmpp';\nimport BridgeVideoType from './service/RTC/BridgeVideoType';\nimport CodecMimeType from './service/RTC/CodecMimeType';\nimport { MediaType } from './service/RTC/MediaType';\nimport RTCEvents from './service/RTC/RTCEvents';\nimport { SignalingEvents } from './service/RTC/SignalingEvents';\nimport { getMediaTypeFromSourceName, getSourceNameForJitsiTrack } from './service/RTC/SignalingLayer';\nimport { VideoType } from './service/RTC/VideoType';\nimport {\n    ACTION_JINGLE_RESTART,\n    ACTION_JINGLE_SI_RECEIVED,\n    ACTION_JINGLE_SI_TIMEOUT,\n    ACTION_JINGLE_TERMINATE,\n    ACTION_P2P_DECLINED,\n    ACTION_P2P_ESTABLISHED,\n    ACTION_P2P_FAILED,\n    ACTION_P2P_SWITCH_TO_JVB,\n    ICE_ESTABLISHMENT_DURATION_DIFF,\n    createConferenceEvent,\n    createJingleEvent,\n    createP2PEvent\n} from './service/statistics/AnalyticsEvents';\nimport { XMPPEvents } from './service/xmpp/XMPPEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * How long since Jicofo is supposed to send a session-initiate, before\n * {@link ACTION_JINGLE_SI_TIMEOUT} analytics event is sent (in ms).\n * @type {number}\n */\nconst JINGLE_SI_TIMEOUT = 5000;\n\n/**\n * Checks if a given string is a valid video codec mime type.\n *\n * @param {string} codec the codec string that needs to be validated.\n * @returns {CodecMimeType|null} mime type if valid, null otherwise.\n * @private\n */\nfunction _getCodecMimeType(codec) {\n    if (typeof codec === 'string') {\n        return Object.values(CodecMimeType).find(value => value === codec.toLowerCase());\n    }\n\n    return null;\n}\n\n/**\n * Creates a JitsiConference object with the given name and properties.\n * Note: this constructor is not a part of the public API (objects should be\n * created using JitsiConnection.createConference).\n * @param options.config properties / settings related to the conference that\n * will be created.\n * @param options.name the name of the conference\n * @param options.connection the JitsiConnection object for this\n * JitsiConference.\n * @param {number} [options.config.avgRtpStatsN=15] how many samples are to be\n * collected by {@link AvgRTPStatsReporter}, before arithmetic mean is\n * calculated and submitted to the analytics module.\n * @param {boolean} [options.config.enableIceRestart=false] - enables the ICE\n * restart logic.\n * @param {boolean} [options.config.p2p.enabled] when set to <tt>true</tt>\n * the peer to peer mode will be enabled. It means that when there are only 2\n * participants in the conference an attempt to make direct connection will be\n * made. If the connection succeeds the conference will stop sending data\n * through the JVB connection and will use the direct one instead.\n * @param {number} [options.config.p2p.backToP2PDelay=5] a delay given in\n * seconds, before the conference switches back to P2P, after the 3rd\n * participant has left the room.\n * @param {number} [options.config.channelLastN=-1] The requested amount of\n * videos are going to be delivered after the value is in effect. Set to -1 for\n * unlimited or all available videos.\n * @param {number} [options.config.forceJVB121Ratio]\n * \"Math.random() < forceJVB121Ratio\" will determine whether a 2 people\n * conference should be moved to the JVB instead of P2P. The decision is made on\n * the responder side, after ICE succeeds on the P2P connection.\n * @constructor\n *\n * FIXME Make all methods which are called from lib-internal classes\n *       to non-public (use _). To name a few:\n *       {@link JitsiConference.onLocalRoleChanged}\n *       {@link JitsiConference.onUserRoleChanged}\n *       {@link JitsiConference.onMemberLeft}\n *       and so on...\n */\nexport default function JitsiConference(options) {\n    if (!options.name || options.name.toLowerCase() !== options.name.toString()) {\n        const errmsg\n            = 'Invalid conference name (no conference name passed or it '\n                + 'contains invalid characters like capital letters)!';\n\n        logger.error(errmsg);\n        throw new Error(errmsg);\n    }\n    this.connection = options.connection;\n    this.xmpp = this.connection?.xmpp;\n\n    if (this.xmpp.isRoomCreated(options.name, options.customDomain)) {\n        const errmsg = 'A conference with the same name has already been created!';\n\n        delete this.connection;\n        delete this.xmpp;\n        logger.error(errmsg);\n        throw new Error(errmsg);\n    }\n    this.eventEmitter = new EventEmitter();\n    this.options = options;\n    this.eventManager = new JitsiConferenceEventManager(this);\n\n    /**\n     * List of all the participants in the conference.\n     * @type {Map<string, JitsiParticipant>};\n     */\n    this.participants = new Map();\n\n    /**\n     * The signaling layer instance.\n     * @type {SignalingLayerImpl}\n     * @private\n     */\n    this._signalingLayer = new SignalingLayerImpl();\n\n    this._init(options);\n    this.componentsVersions = new ComponentsVersions(this);\n\n    /**\n     * Jingle session instance for the JVB connection.\n     * @type {JingleSessionPC}\n     */\n    this.jvbJingleSession = null;\n    this.lastDominantSpeaker = null;\n    this.dtmfManager = null;\n    this.somebodySupportsDTMF = false;\n    this.authEnabled = false;\n    this.startAudioMuted = false;\n    this.startVideoMuted = false;\n    this.startMutedPolicy = {\n        audio: false,\n        video: false\n    };\n    this.isMutedByFocus = false;\n\n    // when muted by focus we receive the jid of the initiator of the mute\n    this.mutedByFocusActor = null;\n\n    this.isVideoMutedByFocus = false;\n\n    // when video muted by focus we receive the jid of the initiator of the mute\n    this.mutedVideoByFocusActor = null;\n\n    // Flag indicates if the 'onCallEnded' method was ever called on this\n    // instance. Used to log extra analytics event for debugging purpose.\n    // We need to know if the potential issue happened before or after\n    // the restart.\n    this.wasStopped = false;\n\n    // Conference properties, maintained by jicofo.\n    this.properties = {};\n\n    /**\n     * The object which monitors local and remote connection statistics (e.g.\n     * sending bitrate) and calculates a number which represents the connection\n     * quality.\n     */\n    this.connectionQuality\n        = new ConnectionQuality(this, this.eventEmitter, options);\n\n    /**\n     * Reports average RTP statistics to the analytics module.\n     * @type {AvgRTPStatsReporter}\n     */\n    this.avgRtpStatsReporter\n        = new AvgRTPStatsReporter(this, options.config.avgRtpStatsN || 15);\n\n    /**\n     * Detects issues with the audio of remote participants.\n     * @type {AudioOutputProblemDetector}\n     */\n    if (!options.config.disableAudioLevels) {\n        this._audioOutputProblemDetector = new AudioOutputProblemDetector(this);\n    }\n\n    /**\n     * Indicates whether the connection is interrupted or not.\n     */\n    this.isJvbConnectionInterrupted = false;\n\n    /**\n     * The object which tracks active speaker times\n     */\n    this.speakerStatsCollector = new SpeakerStatsCollector(this);\n\n    /* P2P related fields below: */\n\n    /**\n     * Stores reference to deferred start P2P task. It's created when 3rd\n     * participant leaves the room in order to avoid ping pong effect (it\n     * could be just a page reload).\n     * @type {number|null}\n     */\n    this.deferredStartP2PTask = null;\n\n    const delay\n        = parseInt(options.config.p2p && options.config.p2p.backToP2PDelay, 10);\n\n    /**\n     * A delay given in seconds, before the conference switches back to P2P\n     * after the 3rd participant has left.\n     * @type {number}\n     */\n    this.backToP2PDelay = isNaN(delay) ? 5 : delay;\n    logger.info(`backToP2PDelay: ${this.backToP2PDelay}`);\n\n    /**\n     * If set to <tt>true</tt> it means the P2P ICE is no longer connected.\n     * When <tt>false</tt> it means that P2P ICE (media) connection is up\n     * and running.\n     * @type {boolean}\n     */\n    this.isP2PConnectionInterrupted = false;\n\n    /**\n     * Flag set to <tt>true</tt> when P2P session has been established\n     * (ICE has been connected) and this conference is currently in the peer to\n     * peer mode (P2P connection is the active one).\n     * @type {boolean}\n     */\n    this.p2p = false;\n\n    /**\n     * A JingleSession for the direct peer to peer connection.\n     * @type {JingleSessionPC}\n     */\n    this.p2pJingleSession = null;\n\n    this.videoSIPGWHandler = new VideoSIPGW(this.room);\n    this.recordingManager = new RecordingManager(this.room);\n\n    /**\n     * If the conference.joined event has been sent this will store the timestamp when it happened.\n     *\n     * @type {undefined|number}\n     * @private\n     */\n    this._conferenceJoinAnalyticsEventSent = undefined;\n\n    /**\n     * End-to-End Encryption. Make it available if supported.\n     */\n    if (this.isE2EESupported()) {\n        logger.info('End-to-End Encryption is supported');\n\n        this._e2eEncryption = new E2EEncryption(this);\n    }\n\n    if (FeatureFlags.isRunInLiteModeEnabled()) {\n        logger.info('Lite mode enabled');\n\n        this._liteModeContext = new LiteModeContext(this);\n    }\n\n    /**\n     * Flag set to <tt>true</tt> when Jicofo sends a presence message indicating that the max audio sender limit has\n     * been reached for the call. Once this is set, unmuting audio will be disabled from the client until it gets reset\n     * again by Jicofo.\n     */\n    this._audioSenderLimitReached = undefined;\n\n    /**\n     * Flag set to <tt>true</tt> when Jicofo sends a presence message indicating that the max video sender limit has\n     * been reached for the call. Once this is set, unmuting video will be disabled from the client until it gets reset\n     * again by Jicofo.\n     */\n    this._videoSenderLimitReached = undefined;\n}\n\n// FIXME convert JitsiConference to ES6 - ASAP !\nJitsiConference.prototype.constructor = JitsiConference;\n\n/**\n * Create a resource for the a jid. We use the room nickname (the resource part\n * of the occupant JID, see XEP-0045) as the endpoint ID in colibri. We require\n * endpoint IDs to be 8 hex digits because in some cases they get serialized\n * into a 32bit field.\n *\n * @param {string} jid - The id set onto the XMPP connection.\n * @param {boolean} isAuthenticatedUser - Whether or not the user has connected\n * to the XMPP service with a password.\n * @returns {string}\n * @static\n */\nJitsiConference.resourceCreator = function(jid, isAuthenticatedUser) {\n    let mucNickname;\n\n    if (isAuthenticatedUser) {\n        // For authenticated users generate a random ID.\n        mucNickname = RandomUtil.randomHexString(8).toLowerCase();\n    } else {\n        // We try to use the first part of the node (which for anonymous users\n        // on prosody is a UUID) to match the previous behavior (and maybe make\n        // debugging easier).\n        mucNickname = Strophe.getNodeFromJid(jid)?.substr(0, 8)\n            .toLowerCase();\n\n        // But if this doesn't have the required format we just generate a new\n        // random nickname.\n        const re = /[0-9a-f]{8}/g;\n\n        if (!mucNickname || !re.test(mucNickname)) {\n            mucNickname = RandomUtil.randomHexString(8).toLowerCase();\n        }\n    }\n\n    return mucNickname;\n};\n\n/**\n * Initializes the conference object properties\n * @param options {object}\n * @param options.connection {JitsiConnection} overrides this.connection\n */\nJitsiConference.prototype._init = function(options = {}) {\n    this.eventManager.setupXMPPListeners();\n\n    const { config } = this.options;\n\n    // Get the codec preference settings from config.js.\n    const codecSettings = {\n        jvbDisabledCodec: _getCodecMimeType(config.videoQuality?.disabledCodec),\n        p2pDisabledCodec: _getCodecMimeType(config.p2p?.disabledCodec),\n        enforcePreferredCodec: config.videoQuality?.enforcePreferredCodec,\n        jvbPreferredCodec: _getCodecMimeType(config.videoQuality?.preferredCodec),\n        p2pPreferredCodec: _getCodecMimeType(config.p2p?.preferredCodec)\n    };\n\n    this.codecSelection = new CodecSelection(this, codecSettings);\n    this._statsCurrentId = config.statisticsId ? config.statisticsId : Settings.callStatsUserName;\n    this.room = this.xmpp.createRoom(\n        this.options.name, {\n            ...config,\n            statsId: this._statsCurrentId\n        },\n        JitsiConference.resourceCreator\n    );\n\n    this._signalingLayer.setChatRoom(this.room);\n    this._signalingLayer.on(\n        SignalingEvents.SOURCE_UPDATED,\n        (sourceName, endpointId, muted, videoType) => {\n            const participant = this.participants.get(endpointId);\n            const mediaType = getMediaTypeFromSourceName(sourceName);\n\n            if (participant) {\n                participant._setSources(mediaType, muted, sourceName, videoType);\n                this.eventEmitter.emit(JitsiConferenceEvents.PARTICIPANT_SOURCE_UPDATED, participant);\n            }\n        });\n\n    // Connection interrupted/restored listeners\n    this._onIceConnectionInterrupted\n        = this._onIceConnectionInterrupted.bind(this);\n    this.room.addListener(\n        XMPPEvents.CONNECTION_INTERRUPTED, this._onIceConnectionInterrupted);\n\n    this._onIceConnectionRestored = this._onIceConnectionRestored.bind(this);\n    this.room.addListener(\n        XMPPEvents.CONNECTION_RESTORED, this._onIceConnectionRestored);\n\n    this._onIceConnectionEstablished\n        = this._onIceConnectionEstablished.bind(this);\n    this.room.addListener(\n        XMPPEvents.CONNECTION_ESTABLISHED, this._onIceConnectionEstablished);\n\n    this._updateProperties = this._updateProperties.bind(this);\n    this.room.addListener(XMPPEvents.CONFERENCE_PROPERTIES_CHANGED,\n        this._updateProperties);\n\n    this._sendConferenceJoinAnalyticsEvent = this._sendConferenceJoinAnalyticsEvent.bind(this);\n    this.room.addListener(XMPPEvents.MEETING_ID_SET, this._sendConferenceJoinAnalyticsEvent);\n\n    this._removeLocalSourceOnReject = this._removeLocalSourceOnReject.bind(this);\n    this._updateRoomPresence = this._updateRoomPresence.bind(this);\n    this.room.addListener(XMPPEvents.SESSION_ACCEPT, this._updateRoomPresence);\n    this.room.addListener(XMPPEvents.SOURCE_ADD, this._updateRoomPresence);\n    this.room.addListener(XMPPEvents.SOURCE_ADD_ERROR, this._removeLocalSourceOnReject);\n    this.room.addListener(XMPPEvents.SOURCE_REMOVE, this._updateRoomPresence);\n\n    if (config.e2eping?.enabled) {\n        this.e2eping = new E2ePing(\n            this,\n            config,\n            (message, to) => {\n                try {\n                    this.sendMessage(message, to, true /* sendThroughVideobridge */);\n                } catch (error) {\n                    logger.warn('Failed to send E2E ping request or response.', error && error.msg);\n                }\n            });\n    }\n\n    if (!this.rtc) {\n        this.rtc = new RTC(this, options);\n        this.eventManager.setupRTCListeners();\n        this._registerRtcListeners(this.rtc);\n    }\n\n    this.receiveVideoController = new ReceiveVideoController(this, this.rtc);\n    this.sendVideoController = new SendVideoController(this, this.rtc);\n\n    if (!this.statistics) {\n        this.statistics = new Statistics(this.xmpp, {\n            aliasName: this._statsCurrentId,\n            userName: config.statisticsDisplayName ? config.statisticsDisplayName : this.myUserId(),\n            confID: config.confID || `${this.connection.options.hosts.domain}/${this.options.name}`,\n            siteID: config.siteID,\n            customScriptUrl: config.callStatsCustomScriptUrl,\n            callStatsID: config.callStatsID,\n            callStatsSecret: config.callStatsSecret,\n            callStatsApplicationLogsDisabled: config.callStatsApplicationLogsDisabled,\n            roomName: this.options.name,\n            applicationName: config.applicationName,\n            configParams: config.callStatsConfigParams\n        });\n        Statistics.analytics.addPermanentProperties({\n            'callstats_name': this._statsCurrentId\n        });\n\n        // Start performance observer for monitoring long tasks\n        if (config.longTasksStatsInterval) {\n            this.statistics.attachLongTasksStats(this);\n        }\n    }\n\n    this.eventManager.setupChatRoomListeners();\n\n    // Always add listeners because on reload we are executing leave and the\n    // listeners are removed from statistics module.\n    this.eventManager.setupStatisticsListeners();\n\n    // Disable VAD processing on Safari since it causes audio input to\n    // fail on some of the mobile devices.\n    if (config.enableTalkWhileMuted && browser.supportsVADDetection()) {\n        // If VAD processor factory method is provided uses VAD based detection, otherwise fallback to audio level\n        // based detection.\n        if (config.createVADProcessor) {\n            logger.info('Using VAD detection for generating talk while muted events');\n\n            if (!this._audioAnalyser) {\n                this._audioAnalyser = new VADAudioAnalyser(this, config.createVADProcessor);\n            }\n\n            const vadTalkMutedDetection = new VADTalkMutedDetection();\n\n            vadTalkMutedDetection.on(DetectionEvents.VAD_TALK_WHILE_MUTED, () =>\n                this.eventEmitter.emit(JitsiConferenceEvents.TALK_WHILE_MUTED));\n\n            this._audioAnalyser.addVADDetectionService(vadTalkMutedDetection);\n        } else {\n            logger.warn('No VAD Processor was provided. Talk while muted detection service was not initialized!');\n        }\n    }\n\n    // Disable noisy mic detection on safari since it causes the audio input to\n    // fail on Safari on iPadOS.\n    if (config.enableNoisyMicDetection && browser.supportsVADDetection()) {\n        if (config.createVADProcessor) {\n            if (!this._audioAnalyser) {\n                this._audioAnalyser = new VADAudioAnalyser(this, config.createVADProcessor);\n            }\n\n            const vadNoiseDetection = new VADNoiseDetection();\n\n            vadNoiseDetection.on(DetectionEvents.VAD_NOISY_DEVICE, () =>\n                this.eventEmitter.emit(JitsiConferenceEvents.NOISY_MIC));\n\n            this._audioAnalyser.addVADDetectionService(vadNoiseDetection);\n        } else {\n            logger.warn('No VAD Processor was provided. Noisy microphone detection service was not initialized!');\n        }\n    }\n\n    // Generates events based on no audio input detector.\n    if (config.enableNoAudioDetection && !config.disableAudioLevels && LocalStatsCollector.isLocalStatsSupported()) {\n        this._noAudioSignalDetection = new NoAudioSignalDetection(this);\n        this._noAudioSignalDetection.on(DetectionEvents.NO_AUDIO_INPUT, () => {\n            this.eventEmitter.emit(JitsiConferenceEvents.NO_AUDIO_INPUT);\n        });\n        this._noAudioSignalDetection.on(DetectionEvents.AUDIO_INPUT_STATE_CHANGE, hasAudioSignal => {\n            this.eventEmitter.emit(JitsiConferenceEvents.AUDIO_INPUT_STATE_CHANGE, hasAudioSignal);\n        });\n    }\n\n    if ('channelLastN' in config) {\n        this.setLastN(config.channelLastN);\n    }\n\n    /**\n     * Emits {@link JitsiConferenceEvents.JVB121_STATUS}.\n     * @type {Jvb121EventGenerator}\n     */\n    this.jvb121Status = new Jvb121EventGenerator(this);\n\n    // creates dominant speaker detection that works only in p2p mode\n    this.p2pDominantSpeakerDetection = new P2PDominantSpeakerDetection(this);\n\n    if (config && config.deploymentInfo && config.deploymentInfo.userRegion) {\n        this.setLocalParticipantProperty(\n            'region', config.deploymentInfo.userRegion);\n    }\n\n    // Publish the codec type to presence.\n    this.setLocalParticipantProperty('codecType', this.codecSelection.getPreferredCodec());\n\n    // Set transcription language presence extension.\n    // In case the language config is undefined or has the default value that the transcriber uses\n    // (in our case Jigasi uses 'en-US'), don't set the participant property in order to avoid\n    // needlessly polluting the presence stanza.\n    if (config && config.transcriptionLanguage && config.transcriptionLanguage !== 'en-US') {\n        this.setLocalParticipantProperty('transcription_language', config.transcriptionLanguage);\n    }\n};\n\n/**\n * Joins the conference.\n * @param password {string} the password\n * @param replaceParticipant {boolean} whether the current join replaces\n * an existing participant with same jwt from the meeting.\n */\nJitsiConference.prototype.join = function(password, replaceParticipant = false) {\n    if (this.room) {\n        this.room.join(password, replaceParticipant).then(() => this._maybeSetSITimeout());\n    }\n};\n\n/**\n * Authenticates and upgrades the role of the local participant/user.\n *\n * @returns {Object} A <tt>thenable</tt> which (1) settles when the process of\n * authenticating and upgrading the role of the local participant/user finishes\n * and (2) has a <tt>cancel</tt> method that allows the caller to interrupt the\n * process.\n */\nJitsiConference.prototype.authenticateAndUpgradeRole = function(options) {\n    return authenticateAndUpgradeRole.call(this, {\n        ...options,\n        onCreateResource: JitsiConference.resourceCreator\n    });\n};\n\n/**\n * Check if joined to the conference.\n */\nJitsiConference.prototype.isJoined = function() {\n    return this.room && this.room.joined;\n};\n\n/**\n * Tells whether or not the P2P mode is enabled in the configuration.\n * @return {boolean}\n */\nJitsiConference.prototype.isP2PEnabled = function() {\n    return Boolean(this.options.config.p2p && this.options.config.p2p.enabled)\n\n        // FIXME: remove once we have a default config template. -saghul\n        || typeof this.options.config.p2p === 'undefined';\n};\n\n/**\n * When in P2P test mode, the conference will not automatically switch to P2P\n * when there 2 participants.\n * @return {boolean}\n */\nJitsiConference.prototype.isP2PTestModeEnabled = function() {\n    return Boolean(this.options.config.testing\n        && this.options.config.testing.p2pTestMode);\n};\n\n/**\n * Leaves the conference.\n * @param reason {string|undefined} The reason for leaving the conference.\n * @returns {Promise}\n */\nJitsiConference.prototype.leave = async function(reason) {\n    if (this.avgRtpStatsReporter) {\n        this.avgRtpStatsReporter.dispose();\n        this.avgRtpStatsReporter = null;\n    }\n\n    if (this._audioOutputProblemDetector) {\n        this._audioOutputProblemDetector.dispose();\n        this._audioOutputProblemDetector = null;\n    }\n\n    if (this.e2eping) {\n        this.e2eping.stop();\n        this.e2eping = null;\n    }\n\n    this.getLocalTracks().forEach(track => this.onLocalTrackRemoved(track));\n\n    this.rtc.closeBridgeChannel();\n\n    this._sendConferenceLeftAnalyticsEvent();\n\n    if (this.statistics) {\n        this.statistics.dispose();\n    }\n\n    this._delayedIceFailed && this._delayedIceFailed.cancel();\n\n    this._maybeClearSITimeout();\n\n    // Close both JVb and P2P JingleSessions\n    if (this.jvbJingleSession) {\n        this.jvbJingleSession.close();\n        this.jvbJingleSession = null;\n    }\n    if (this.p2pJingleSession) {\n        this.p2pJingleSession.close();\n        this.p2pJingleSession = null;\n    }\n\n    // Leave the conference. If this.room == null we are calling second time leave().\n    if (!this.room) {\n        throw new Error('You have already left the conference');\n    }\n\n    const room = this.room;\n\n    // Unregister connection state listeners\n    room.removeListener(\n        XMPPEvents.CONNECTION_INTERRUPTED,\n        this._onIceConnectionInterrupted);\n    room.removeListener(\n        XMPPEvents.CONNECTION_RESTORED,\n        this._onIceConnectionRestored);\n    room.removeListener(\n        XMPPEvents.CONNECTION_ESTABLISHED,\n        this._onIceConnectionEstablished);\n\n    room.removeListener(\n        XMPPEvents.CONFERENCE_PROPERTIES_CHANGED,\n        this._updateProperties);\n\n    room.removeListener(XMPPEvents.MEETING_ID_SET, this._sendConferenceJoinAnalyticsEvent);\n    room.removeListener(XMPPEvents.SESSION_ACCEPT, this._updateRoomPresence);\n    room.removeListener(XMPPEvents.SOURCE_ADD, this._updateRoomPresence);\n    room.removeListener(XMPPEvents.SOURCE_ADD_ERROR, this._removeLocalSourceOnReject);\n    room.removeListener(XMPPEvents.SOURCE_REMOVE, this._updateRoomPresence);\n\n    this.eventManager.removeXMPPListeners();\n\n    this._signalingLayer.setChatRoom(null);\n\n    this.room = null;\n\n    let leaveError;\n\n    try {\n        await room.leave(reason);\n    } catch (err) {\n        leaveError = err;\n\n        // Remove all participants because currently the conference\n        // won't be usable anyway. This is done on success automatically\n        // by the ChatRoom instance.\n        this.getParticipants().forEach(\n            participant => this.onMemberLeft(participant.getJid()));\n    }\n\n    if (this.rtc) {\n        this.rtc.destroy();\n    }\n\n    if (leaveError) {\n        throw leaveError;\n    }\n};\n\n/**\n * Returns <tt>true</tt> if end conference support is enabled in the backend.\n *\n * @returns {boolean} whether end conference is supported in the backend.\n */\nJitsiConference.prototype.isEndConferenceSupported = function() {\n    return Boolean(this.room && this.room.xmpp.endConferenceComponentAddress);\n};\n\n/**\n * Ends the conference.\n */\nJitsiConference.prototype.end = function() {\n    if (!this.isEndConferenceSupported()) {\n        logger.warn('Cannot end conference: is not supported.');\n\n        return;\n    }\n    if (!this.room) {\n        throw new Error('You have already left the conference');\n    }\n\n    this.room.end();\n};\n\n/**\n * Returns the currently active media session if any.\n *\n * @returns {JingleSessionPC|undefined}\n */\nJitsiConference.prototype.getActiveMediaSession = function() {\n    return this.isP2PActive() ? this.p2pJingleSession : this.jvbJingleSession;\n};\n\n/**\n * Returns an array containing all media sessions existing in this conference.\n *\n * @returns {Array<JingleSessionPC>}\n */\nJitsiConference.prototype.getMediaSessions = function() {\n    const sessions = [];\n\n    this.jvbJingleSession && sessions.push(this.jvbJingleSession);\n    this.p2pJingleSession && sessions.push(this.p2pJingleSession);\n\n    return sessions;\n};\n\n/**\n * Registers event listeners on the RTC instance.\n * @param {RTC} rtc - the RTC module instance used by this conference.\n * @private\n * @returns {void}\n */\nJitsiConference.prototype._registerRtcListeners = function(rtc) {\n    rtc.addListener(RTCEvents.DATA_CHANNEL_OPEN, () => {\n        for (const localTrack of this.rtc.localTracks) {\n            localTrack.isVideoTrack() && this._sendBridgeVideoTypeMessage(localTrack);\n        }\n    });\n};\n\n/**\n * Sends the 'VideoTypeMessage' to the bridge on the bridge channel so that the bridge can make bitrate allocation\n * decisions based on the video type of the local source.\n *\n * @param {JitsiLocalTrack} localtrack - The track associated with the local source signaled to the bridge.\n * @returns {void}\n * @private\n */\nJitsiConference.prototype._sendBridgeVideoTypeMessage = function(localtrack) {\n    let videoType = !localtrack || localtrack.isMuted() ? BridgeVideoType.NONE : localtrack.getVideoType();\n\n    if (videoType === BridgeVideoType.DESKTOP && this._desktopSharingFrameRate > SS_DEFAULT_FRAME_RATE) {\n        videoType = BridgeVideoType.DESKTOP_HIGH_FPS;\n    }\n\n    localtrack && this.rtc.sendSourceVideoType(localtrack.getSourceName(), videoType);\n};\n\n/**\n * Returns name of this conference.\n */\nJitsiConference.prototype.getName = function() {\n    return this.options.name.toString();\n};\n\n/**\n * Returns the {@link JitsiConnection} used by this this conference.\n */\nJitsiConference.prototype.getConnection = function() {\n    return this.connection;\n};\n\n/**\n * Check if authentication is enabled for this conference.\n */\nJitsiConference.prototype.isAuthEnabled = function() {\n    return this.authEnabled;\n};\n\n/**\n * Check if user is logged in.\n */\nJitsiConference.prototype.isLoggedIn = function() {\n    return Boolean(this.authIdentity);\n};\n\n/**\n * Get authorized login.\n */\nJitsiConference.prototype.getAuthLogin = function() {\n    return this.authIdentity;\n};\n\n/**\n * Check if external authentication is enabled for this conference.\n */\nJitsiConference.prototype.isExternalAuthEnabled = function() {\n    return this.room && this.room.moderator.isExternalAuthEnabled();\n};\n\n/**\n * Get url for external authentication.\n * @param {boolean} [urlForPopup] if true then return url for login popup,\n *                                else url of login page.\n * @returns {Promise}\n */\nJitsiConference.prototype.getExternalAuthUrl = function(urlForPopup) {\n    return new Promise((resolve, reject) => {\n        if (!this.isExternalAuthEnabled()) {\n            reject();\n\n            return;\n        }\n        if (urlForPopup) {\n            this.room.moderator.getPopupLoginUrl(resolve, reject);\n        } else {\n            this.room.moderator.getLoginUrl(resolve, reject);\n        }\n    });\n};\n\n/**\n * Returns the local tracks of the given media type, or all local tracks if no\n * specific type is given.\n * @param {MediaType} [mediaType] Optional media type (audio or video).\n */\nJitsiConference.prototype.getLocalTracks = function(mediaType) {\n    let tracks = [];\n\n    if (this.rtc) {\n        tracks = this.rtc.getLocalTracks(mediaType);\n    }\n\n    return tracks;\n};\n\n/**\n * Obtains local audio track.\n * @return {JitsiLocalTrack|null}\n */\nJitsiConference.prototype.getLocalAudioTrack = function() {\n    return this.rtc ? this.rtc.getLocalAudioTrack() : null;\n};\n\n/**\n * Obtains local video track.\n * @return {JitsiLocalTrack|null}\n */\nJitsiConference.prototype.getLocalVideoTrack = function() {\n    return this.rtc ? this.rtc.getLocalVideoTrack() : null;\n};\n\n/**\n * Returns all the local video tracks.\n * @returns {Array<JitsiLocalTrack>}\n */\nJitsiConference.prototype.getLocalVideoTracks = function() {\n    return this.rtc ? this.rtc.getLocalVideoTracks() : null;\n};\n\n/**\n * Obtains the performance statistics.\n * @returns {Object|null}\n */\nJitsiConference.prototype.getPerformanceStats = function() {\n    return {\n        longTasksStats: this.statistics.getLongTasksStats()\n    };\n};\n\n/**\n * Attaches a handler for events(For example - \"participant joined\".) in the\n * conference. All possible event are defined in JitsiConferenceEvents.\n * @param eventId the event ID.\n * @param handler handler for the event.\n *\n * Note: consider adding eventing functionality by extending an EventEmitter\n * impl, instead of rolling ourselves\n */\nJitsiConference.prototype.on = function(eventId, handler) {\n    if (this.eventEmitter) {\n        this.eventEmitter.on(eventId, handler);\n    }\n};\n\n/**\n * Removes event listener\n * @param eventId the event ID.\n * @param [handler] optional, the specific handler to unbind\n *\n * Note: consider adding eventing functionality by extending an EventEmitter\n * impl, instead of rolling ourselves\n */\nJitsiConference.prototype.off = function(eventId, handler) {\n    if (this.eventEmitter) {\n        this.eventEmitter.removeListener(eventId, handler);\n    }\n};\n\n// Common aliases for event emitter\nJitsiConference.prototype.addEventListener = JitsiConference.prototype.on;\nJitsiConference.prototype.removeEventListener = JitsiConference.prototype.off;\n\n/**\n * Receives notifications from other participants about commands / custom events\n * (sent by sendCommand or sendCommandOnce methods).\n * @param command {String} the name of the command\n * @param handler {Function} handler for the command\n */\nJitsiConference.prototype.addCommandListener = function(command, handler) {\n    if (this.room) {\n        this.room.addPresenceListener(command, handler);\n    }\n};\n\n/**\n  * Removes command  listener\n  * @param command {String} the name of the command\n  * @param handler {Function} handler to remove for the command\n  */\nJitsiConference.prototype.removeCommandListener = function(command, handler) {\n    if (this.room) {\n        this.room.removePresenceListener(command, handler);\n    }\n};\n\n/**\n * Sends text message to the other participants in the conference\n * @param message the text message.\n * @param elementName the element name to encapsulate the message.\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\n */\nJitsiConference.prototype.sendTextMessage = function(message, elementName = 'body') {\n    if (this.room) {\n        this.room.sendMessage(message, elementName);\n    }\n};\n\n/**\n * Send private text message to another participant of the conference\n * @param id the id of the participant to send a private message.\n * @param message the text message.\n * @param elementName the element name to encapsulate the message.\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\n */\nJitsiConference.prototype.sendPrivateTextMessage = function(id, message, elementName = 'body') {\n    if (this.room) {\n        this.room.sendPrivateMessage(id, message, elementName);\n    }\n};\n\n/**\n * Send presence command.\n * @param name {String} the name of the command.\n * @param values {Object} with keys and values that will be sent.\n **/\nJitsiConference.prototype.sendCommand = function(name, values) {\n    if (this.room) {\n        this.room.addOrReplaceInPresence(name, values) && this.room.sendPresence();\n    } else {\n        logger.warn('Not sending a command, room not initialized.');\n    }\n\n};\n\n/**\n * Send presence command one time.\n * @param name {String} the name of the command.\n * @param values {Object} with keys and values that will be sent.\n **/\nJitsiConference.prototype.sendCommandOnce = function(name, values) {\n    this.sendCommand(name, values);\n    this.removeCommand(name);\n};\n\n/**\n * Removes presence command.\n * @param name {String} the name of the command.\n **/\nJitsiConference.prototype.removeCommand = function(name) {\n    if (this.room) {\n        this.room.removeFromPresence(name);\n    }\n};\n\n/**\n * Sets the display name for this conference.\n * @param name the display name to set\n */\nJitsiConference.prototype.setDisplayName = function(name) {\n    if (this.room) {\n        const nickKey = 'nick';\n\n        if (name) {\n            this.room.addOrReplaceInPresence(nickKey, {\n                attributes: { xmlns: 'http://jabber.org/protocol/nick' },\n                value: name\n            }) && this.room.sendPresence();\n        } else if (this.room.getFromPresence(nickKey)) {\n            this.room.removeFromPresence(nickKey);\n            this.room.sendPresence();\n        }\n    }\n};\n\n/**\n * Set new subject for this conference. (available only for moderator)\n * @param {string} subject new subject\n */\nJitsiConference.prototype.setSubject = function(subject) {\n    if (this.room && this.isModerator()) {\n        this.room.setSubject(subject);\n    } else {\n        logger.warn(`Failed to set subject, ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator'}`);\n    }\n};\n\n/**\n * Get a transcriber object for all current participants in this conference\n * @return {Transcriber} the transcriber object\n */\nJitsiConference.prototype.getTranscriber = function() {\n    if (this.transcriber === undefined) {\n        this.transcriber = new Transcriber();\n\n        // add all existing local audio tracks to the transcriber\n        const localAudioTracks = this.getLocalTracks(MediaType.AUDIO);\n\n        for (const localAudio of localAudioTracks) {\n            this.transcriber.addTrack(localAudio);\n        }\n\n        // and all remote audio tracks\n        const remoteAudioTracks = this.rtc.getRemoteTracks(MediaType.AUDIO);\n\n        for (const remoteTrack of remoteAudioTracks) {\n            this.transcriber.addTrack(remoteTrack);\n        }\n    }\n\n    return this.transcriber;\n};\n\n/**\n * Returns the transcription status.\n *\n * @returns {String} \"on\" or \"off\".\n */\nJitsiConference.prototype.getTranscriptionStatus = function() {\n    return this.room.transcriptionStatus;\n};\n\n/**\n * Adds JitsiLocalTrack object to the conference.\n * @param {JitsiLocalTrack} track the JitsiLocalTrack object.\n * @returns {Promise<JitsiLocalTrack>}\n * @throws {Error} if the specified track is a video track and there is already\n * another video track in the conference.\n */\nJitsiConference.prototype.addTrack = function(track) {\n    if (!track) {\n        throw new Error('addTrack - a track is required');\n    }\n\n    const mediaType = track.getType();\n    const localTracks = this.rtc.getLocalTracks(mediaType);\n\n    // Ensure there's exactly 1 local track of each media type in the conference.\n    if (localTracks.length > 0) {\n        // Don't be excessively harsh and severe if the API client happens to attempt to add the same local track twice.\n        if (track === localTracks[0]) {\n            return Promise.resolve(track);\n        }\n\n        // Currently, only adding multiple video streams of different video types is supported.\n        // TODO - remove this limitation once issues with jitsi-meet trying to add multiple camera streams is fixed.\n        if (FeatureFlags.isMultiStreamSendSupportEnabled()\n            && mediaType === MediaType.VIDEO\n            && !localTracks.find(t => t.getVideoType() === track.getVideoType())) {\n            const sourceName = getSourceNameForJitsiTrack(\n                this.myUserId(),\n                mediaType,\n                this.getLocalTracks(mediaType)?.length);\n\n            track.setSourceName(sourceName);\n            const addTrackPromises = [];\n\n            this.p2pJingleSession && addTrackPromises.push(this.p2pJingleSession.addTracks([ track ]));\n            this.jvbJingleSession && addTrackPromises.push(this.jvbJingleSession.addTracks([ track ]));\n\n            return Promise.all(addTrackPromises)\n                .then(() => {\n                    this._setupNewTrack(track);\n                    this._sendBridgeVideoTypeMessage(track);\n                    this._updateRoomPresence(this.getActiveMediaSession());\n\n                    if (this.isMutedByFocus || this.isVideoMutedByFocus) {\n                        this._fireMuteChangeEvent(track);\n                    }\n                });\n        }\n\n        return Promise.reject(new Error(`Cannot add second ${mediaType} track to the conference`));\n    }\n\n    return this.replaceTrack(null, track)\n        .then(() => {\n            // Presence needs to be sent here for desktop track since we need the presence to reach the remote peer\n            // before signaling so that a fake participant tile is created for screenshare. Otherwise, presence will\n            // only be sent after a session-accept or source-add is ack'ed.\n            if (track.getVideoType() === VideoType.DESKTOP && FeatureFlags.isMultiStreamSendSupportEnabled()) {\n                this._updateRoomPresence(this.getActiveMediaSession());\n            }\n        });\n};\n\n/**\n * Fires TRACK_AUDIO_LEVEL_CHANGED change conference event (for local tracks).\n * @param {number} audioLevel the audio level\n * @param {TraceablePeerConnection} [tpc]\n */\nJitsiConference.prototype._fireAudioLevelChangeEvent = function(audioLevel, tpc) {\n    const activeTpc = this.getActivePeerConnection();\n\n    // There will be no TraceablePeerConnection if audio levels do not come from\n    // a peerconnection. LocalStatsCollector.js measures audio levels using Web\n    // Audio Analyser API and emits local audio levels events through\n    // JitsiTrack.setAudioLevel, but does not provide TPC instance which is\n    // optional.\n    if (!tpc || activeTpc === tpc) {\n        this.eventEmitter.emit(\n            JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,\n            this.myUserId(), audioLevel);\n    }\n};\n\n/**\n * Fires TRACK_MUTE_CHANGED change conference event.\n * @param track the JitsiTrack object related to the event.\n */\nJitsiConference.prototype._fireMuteChangeEvent = function(track) {\n    // check if track was muted by focus and now is unmuted by user\n    if (this.isMutedByFocus && track.isAudioTrack() && !track.isMuted()) {\n        this.isMutedByFocus = false;\n\n        // unmute local user on server\n        this.room.muteParticipant(this.room.myroomjid, false, MediaType.AUDIO);\n    } else if (this.isVideoMutedByFocus && track.isVideoTrack() && !track.isMuted()) {\n        this.isVideoMutedByFocus = false;\n\n        // unmute local user on server\n        this.room.muteParticipant(this.room.myroomjid, false, MediaType.VIDEO);\n    }\n\n    let actorParticipant;\n\n    if (this.mutedByFocusActor && track.isAudioTrack()) {\n        const actorId = Strophe.getResourceFromJid(this.mutedByFocusActor);\n\n        actorParticipant = this.participants.get(actorId);\n    } else if (this.mutedVideoByFocusActor && track.isVideoTrack()) {\n        const actorId = Strophe.getResourceFromJid(this.mutedVideoByFocusActor);\n\n        actorParticipant = this.participants.get(actorId);\n    }\n\n    // Send the video type message to the bridge if the track is not removed/added to the pc as part of\n    // the mute/unmute operation.\n    // In React Native we mute the camera by setting track.enabled but that doesn't\n    // work for screen-share tracks, so do the remove-as-mute for those.\n    const doesVideoMuteByStreamRemove\n        = browser.isReactNative() ? track.videoType === VideoType.DESKTOP : browser.doesVideoMuteByStreamRemove();\n\n    if (track.isVideoTrack() && !doesVideoMuteByStreamRemove) {\n        this._sendBridgeVideoTypeMessage(track);\n    }\n\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track, actorParticipant);\n};\n\n/**\n * Returns the list of local tracks that need to be added to the peerconnection on join.\n * This takes the startAudioMuted/startVideoMuted flags into consideration since we do not\n * want to add the tracks if the user joins the call audio/video muted. The tracks will be\n * added when the user unmutes for the first time.\n * @returns {Array<JitsiLocalTrack>} - list of local tracks that are unmuted.\n */\nJitsiConference.prototype._getInitialLocalTracks = function() {\n    // Always add the audio track on certain platforms:\n    //  * Safari / WebKit: because of a known issue where audio playout doesn't happen\n    //    if the user joins audio and video muted.\n    //  * React Native: after iOS 15, if a user joins muted they won't be able to unmute.\n    return this.getLocalTracks()\n        .filter(track => {\n            const trackType = track.getType();\n\n            if (trackType === MediaType.AUDIO\n                    && (!this.isStartAudioMuted() || browser.isWebKitBased() || browser.isReactNative())) {\n                return true;\n            } else if (trackType === MediaType.VIDEO && !this.isStartVideoMuted()) {\n                return true;\n            }\n\n            return false;\n        });\n};\n\n/**\n * Clear JitsiLocalTrack properties and listeners.\n * @param track the JitsiLocalTrack object.\n */\nJitsiConference.prototype.onLocalTrackRemoved = function(track) {\n    track.setConference(null);\n    this.rtc.removeLocalTrack(track);\n    track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, track.muteHandler);\n    if (track.isAudioTrack()) {\n        track.removeEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, track.audioLevelHandler);\n    }\n\n    // send event for stopping screen sharing\n    // FIXME: we assume we have only one screen sharing track\n    // if we change this we need to fix this check\n    if (track.isVideoTrack() && track.videoType === VideoType.DESKTOP) {\n        this.statistics.sendScreenSharingEvent(false);\n    }\n\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);\n};\n\n/**\n * Removes JitsiLocalTrack from the conference and performs\n * a new offer/answer cycle.\n * @param {JitsiLocalTrack} track\n * @returns {Promise}\n */\nJitsiConference.prototype.removeTrack = function(track) {\n    return this.replaceTrack(track, null);\n};\n\n/**\n * Replaces oldTrack with newTrack and performs a single offer/answer\n *  cycle after both operations are done.  Either oldTrack or newTrack\n *  can be null; replacing a valid 'oldTrack' with a null 'newTrack'\n *  effectively just removes 'oldTrack'\n * @param {JitsiLocalTrack} oldTrack the current stream in use to be replaced\n * @param {JitsiLocalTrack} newTrack the new stream to use\n * @returns {Promise} resolves when the replacement is finished\n */\nJitsiConference.prototype.replaceTrack = function(oldTrack, newTrack) {\n    const oldVideoType = oldTrack?.getVideoType();\n    const mediaType = oldTrack?.getType() || newTrack?.getType();\n    const newVideoType = newTrack?.getVideoType();\n\n    if (FeatureFlags.isMultiStreamSendSupportEnabled() && oldTrack && newTrack && oldVideoType !== newVideoType) {\n        throw new Error(`Replacing a track of videoType=${oldVideoType} with a track of videoType=${newVideoType} is`\n            + ' not supported in this mode.');\n    }\n\n    if (newTrack) {\n        const sourceName = oldTrack\n            ? oldTrack.getSourceName()\n            : getSourceNameForJitsiTrack(\n                this.myUserId(),\n                mediaType,\n                this.getLocalTracks(mediaType)?.length);\n\n        newTrack.setSourceName(sourceName);\n    }\n    const oldTrackBelongsToConference = this === oldTrack?.conference;\n\n    if (oldTrackBelongsToConference && oldTrack.disposed) {\n        return Promise.reject(new JitsiTrackError(JitsiTrackErrors.TRACK_IS_DISPOSED));\n    }\n    if (newTrack?.disposed) {\n        return Promise.reject(new JitsiTrackError(JitsiTrackErrors.TRACK_IS_DISPOSED));\n    }\n\n    if (oldTrack && !oldTrackBelongsToConference) {\n        logger.warn(`JitsiConference.replaceTrack oldTrack (${oldTrack} does not belong to this conference`);\n    }\n\n    // Now replace the stream at the lower levels\n    return this._doReplaceTrack(oldTrackBelongsToConference ? oldTrack : null, newTrack)\n        .then(() => {\n            if (oldTrackBelongsToConference && !oldTrack.isMuted() && !newTrack) {\n                oldTrack._sendMuteStatus(true);\n            }\n            oldTrackBelongsToConference && this.onLocalTrackRemoved(oldTrack);\n            newTrack && this._setupNewTrack(newTrack);\n\n            // Send 'VideoTypeMessage' on the bridge channel when a video track is added/removed.\n            if ((oldTrackBelongsToConference && oldTrack?.isVideoTrack()) || newTrack?.isVideoTrack()) {\n                this._sendBridgeVideoTypeMessage(newTrack);\n            }\n            this._updateRoomPresence(this.getActiveMediaSession());\n            if (newTrack !== null && (this.isMutedByFocus || this.isVideoMutedByFocus)) {\n                this._fireMuteChangeEvent(newTrack);\n            }\n\n            return Promise.resolve();\n        })\n        .catch(error => {\n            logger.error(`replaceTrack failed: ${error?.stack}`);\n\n            return Promise.reject(error);\n        });\n};\n\n/**\n * Replaces the tracks at the lower level by going through the Jingle session\n * and WebRTC peer connection. The method will resolve immediately if there is\n * currently no JingleSession started.\n * @param {JitsiLocalTrack|null} oldTrack the track to be removed during\n * the process or <tt>null</t> if the method should act as \"add track\"\n * @param {JitsiLocalTrack|null} newTrack the new track to be added or\n * <tt>null</tt> if the method should act as \"remove track\"\n * @return {Promise} resolved when the process is done or rejected with a string\n * which describes the error.\n * @private\n */\nJitsiConference.prototype._doReplaceTrack = function(oldTrack, newTrack) {\n    const replaceTrackPromises = [];\n\n    if (this.jvbJingleSession) {\n        replaceTrackPromises.push(this.jvbJingleSession.replaceTrack(oldTrack, newTrack));\n    } else {\n        logger.info('_doReplaceTrack - no JVB JingleSession');\n    }\n\n    if (this.p2pJingleSession) {\n        replaceTrackPromises.push(this.p2pJingleSession.replaceTrack(oldTrack, newTrack));\n    } else {\n        logger.info('_doReplaceTrack - no P2P JingleSession');\n    }\n\n    return Promise.all(replaceTrackPromises);\n};\n\n/**\n * Handler for when a source-add for a local source is rejected by Jicofo.\n *\n * @param {JingleSessionPC} jingleSession - The media session.\n * @param {Error} error - The error message.\n * @param {MediaType} mediaType - The media type of the track associated with the source that was rejected.\n * @returns {void}\n */\nJitsiConference.prototype._removeLocalSourceOnReject = function(jingleSession, error, mediaType) {\n    if (!jingleSession) {\n        return;\n    }\n    logger.warn(`Source-add rejected on ${jingleSession}, reason=\"${error?.reason}\", message=\"${error?.msg}\"`);\n    const track = this.getLocalTracks(mediaType)[0];\n\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_UNMUTE_REJECTED, track);\n};\n\n/**\n * Operations related to creating a new track\n * @param {JitsiLocalTrack} newTrack the new track being created\n */\nJitsiConference.prototype._setupNewTrack = function(newTrack) {\n    const mediaType = newTrack.getType();\n\n    if (newTrack.isAudioTrack() || (newTrack.isVideoTrack() && newTrack.videoType !== VideoType.DESKTOP)) {\n        // Report active device to statistics\n        const devices = RTC.getCurrentlyAvailableMediaDevices();\n        const device = devices\n            .find(d => d.kind === `${newTrack.getTrack().kind}input` && d.label === newTrack.getTrack().label);\n\n        if (device) {\n            Statistics.sendActiveDeviceListEvent(RTC.getEventDataForActiveDevice(device));\n        }\n    }\n\n    // Create a source name for this track if it doesn't exist.\n    if (!newTrack.getSourceName()) {\n        const sourceName = getSourceNameForJitsiTrack(\n            this.myUserId(),\n            mediaType,\n            this.getLocalTracks(mediaType)?.length);\n\n        newTrack.setSourceName(sourceName);\n    }\n\n    this.rtc.addLocalTrack(newTrack);\n    newTrack.setConference(this);\n\n    // Suspend media on the inactive media session since it gets automatically enabled for a newly added source.\n    if (this.isP2PActive()) {\n        this._suspendMediaTransferForJvbConnection();\n    }\n\n    // Add event handlers.\n    newTrack.muteHandler = this._fireMuteChangeEvent.bind(this, newTrack);\n    newTrack.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, newTrack.muteHandler);\n\n    if (newTrack.isAudioTrack()) {\n        newTrack.audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);\n        newTrack.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, newTrack.audioLevelHandler);\n    }\n\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, newTrack);\n};\n\n/**\n * Sets the video type.\n * @param track\n * @return <tt>true</tt> if video type was changed in presence.\n * @private\n */\nJitsiConference.prototype._setNewVideoType = function(track) {\n    let videoTypeChanged = false;\n\n    if (track) {\n        videoTypeChanged = this._signalingLayer.setTrackVideoType(track.getSourceName(), track.videoType);\n    }\n\n    return videoTypeChanged;\n};\n\n/**\n * Sets mute status.\n * @param mediaType\n * @param localTrack\n * @param isMuted\n * @param <tt>true</tt> when presence was changed, <tt>false</tt> otherwise.\n * @private\n */\nJitsiConference.prototype._setTrackMuteStatus = function(mediaType, localTrack, isMuted) {\n    let presenceChanged = false;\n\n    if (localTrack) {\n        presenceChanged = this._signalingLayer.setTrackMuteStatus(localTrack.getSourceName(), isMuted);\n    }\n\n    return presenceChanged;\n};\n\n/**\n * Method called by the {@link JitsiLocalTrack} in order to add the underlying MediaStream to the RTCPeerConnection.\n *\n * @param {JitsiLocalTrack} track the local track that will be added to the pc.\n * @return {Promise} resolved when the process is done or rejected with a string which describes the error.\n */\nJitsiConference.prototype._addLocalTrackToPc = function(track) {\n    const addPromises = [];\n\n    if (this.jvbJingleSession) {\n        addPromises.push(this.jvbJingleSession.addTrackToPc(track));\n    } else {\n        logger.debug('Add local MediaStream - no JVB Jingle session started yet');\n    }\n\n    if (this.p2pJingleSession) {\n        addPromises.push(this.p2pJingleSession.addTrackToPc(track));\n    } else {\n        logger.debug('Add local MediaStream - no P2P Jingle session started yet');\n    }\n\n    return Promise.allSettled(addPromises);\n};\n\n/**\n * Method called by the {@link JitsiLocalTrack} in order to remove the underlying MediaStream from the\n * RTCPeerConnection.\n *\n * @param {JitsiLocalTrack} track the local track that will be removed.\n * @return {Promise} resolved when the process is done or rejected with a string which describes the error.\n */\nJitsiConference.prototype._removeLocalTrackFromPc = function(track) {\n    const removePromises = [];\n\n    if (this.jvbJingleSession) {\n        removePromises.push(this.jvbJingleSession.removeTrackFromPc(track));\n    } else {\n        logger.debug('Remove local MediaStream - no JVB JingleSession started yet');\n    }\n    if (this.p2pJingleSession) {\n        removePromises.push(this.p2pJingleSession.removeTrackFromPc(track));\n    } else {\n        logger.debug('Remove local MediaStream - no P2P JingleSession started yet');\n    }\n\n    return Promise.allSettled(removePromises);\n};\n\n/**\n * Get role of the local user.\n * @returns {string} user role: 'moderator' or 'none'\n */\nJitsiConference.prototype.getRole = function() {\n    return this.room.role;\n};\n\n/**\n * Returns whether or not the current conference has been joined as a hidden\n * user.\n *\n * @returns {boolean|null} True if hidden, false otherwise. Will return null if\n * no connection is active.\n */\nJitsiConference.prototype.isHidden = function() {\n    if (!this.connection) {\n        return null;\n    }\n\n    return Strophe.getDomainFromJid(this.connection.getJid())\n        === this.options.config.hiddenDomain;\n};\n\n/**\n * Check if local user is moderator.\n * @returns {boolean|null} true if local user is moderator, false otherwise. If\n * we're no longer in the conference room then <tt>null</tt> is returned.\n */\nJitsiConference.prototype.isModerator = function() {\n    return this.room ? this.room.isModerator() : null;\n};\n\n/**\n * Set password for the room.\n * @param {string} password new password for the room.\n * @returns {Promise}\n */\nJitsiConference.prototype.lock = function(password) {\n    if (!this.isModerator()) {\n        return Promise.reject(new Error('You are not moderator.'));\n    }\n\n    return new Promise((resolve, reject) => {\n        this.room.lockRoom(\n            password || '',\n            () => resolve(),\n            err => reject(err),\n            () => reject(JitsiConferenceErrors.PASSWORD_NOT_SUPPORTED));\n    });\n};\n\n/**\n * Remove password from the room.\n * @returns {Promise}\n */\nJitsiConference.prototype.unlock = function() {\n    return this.lock();\n};\n\n/**\n * Obtains the current value for \"lastN\". See {@link setLastN} for more info.\n * @returns {number}\n */\nJitsiConference.prototype.getLastN = function() {\n    return this.receiveVideoController.getLastN();\n};\n\n/**\n * Obtains the forwarded sources list in this conference.\n * @return {Array<string>|null}\n */\nJitsiConference.prototype.getForwardedSources = function() {\n    return this.rtc.getForwardedSources();\n};\n\n/**\n * Selects a new value for \"lastN\". The requested amount of videos are going\n * to be delivered after the value is in effect. Set to -1 for unlimited or\n * all available videos.\n * @param lastN the new number of videos the user would like to receive.\n * @throws Error or RangeError if the given value is not a number or is smaller\n * than -1.\n */\nJitsiConference.prototype.setLastN = function(lastN) {\n    if (!Number.isInteger(lastN) && !Number.parseInt(lastN, 10)) {\n        throw new Error(`Invalid value for lastN: ${lastN}`);\n    }\n    const n = Number(lastN);\n\n    if (n < -1) {\n        throw new RangeError('lastN cannot be smaller than -1');\n    }\n    this.receiveVideoController.setLastN(n);\n\n    // If the P2P session is not fully established yet, we wait until it gets established.\n    if (this.p2pJingleSession) {\n        const isVideoActive = n !== 0;\n\n        this.p2pJingleSession\n            .setP2pVideoTransferActive(isVideoActive)\n            .catch(error => {\n                logger.error(`Failed to adjust video transfer status (${isVideoActive})`, error);\n            });\n    }\n};\n\n/**\n * @return Array<JitsiParticipant> an array of all participants in this conference.\n */\nJitsiConference.prototype.getParticipants = function() {\n    return Array.from(this.participants.values());\n};\n\n/**\n * Returns the number of participants in the conference, including the local\n * participant.\n * @param countHidden {boolean} Whether or not to include hidden participants\n * in the count. Default: false.\n **/\nJitsiConference.prototype.getParticipantCount = function(countHidden = false) {\n    let participants = this.getParticipants();\n\n    if (!countHidden) {\n        participants = participants.filter(p => !p.isHidden());\n    }\n\n    // Add one for the local participant.\n    return participants.length + 1;\n};\n\n/**\n * @returns {JitsiParticipant} the participant in this conference with the\n * specified id (or undefined if there isn't one).\n * @param id the id of the participant.\n */\nJitsiConference.prototype.getParticipantById = function(id) {\n    return this.participants.get(id);\n};\n\n/**\n * Grant owner rights to the participant.\n * @param {string} id id of the participant to grant owner rights to.\n */\nJitsiConference.prototype.grantOwner = function(id) {\n    const participant = this.getParticipantById(id);\n\n    if (!participant) {\n        return;\n    }\n    this.room.setAffiliation(participant.getConnectionJid(), 'owner');\n};\n\n/**\n * Revoke owner rights to the participant or local Participant as\n * the user might want to refuse to be a moderator.\n * @param {string} id id of the participant to revoke owner rights to.\n */\nJitsiConference.prototype.revokeOwner = function(id) {\n    const participant = this.getParticipantById(id);\n    const isMyself = this.myUserId() === id;\n    const role = this.isMembersOnly() ? 'member' : 'none';\n\n    if (isMyself) {\n        this.room.setAffiliation(this.connection.getJid(), role);\n    } else if (participant) {\n        this.room.setAffiliation(participant.getConnectionJid(), role);\n    }\n};\n\n/**\n * Kick participant from this conference.\n * @param {string} id id of the participant to kick\n * @param {string} reason reason of the participant to kick\n */\nJitsiConference.prototype.kickParticipant = function(id, reason) {\n    const participant = this.getParticipantById(id);\n\n    if (!participant) {\n        return;\n    }\n    this.room.kick(participant.getJid(), reason);\n};\n\n/**\n * Maybe clears the timeout which emits {@link ACTION_JINGLE_SI_TIMEOUT}\n * analytics event.\n * @private\n */\nJitsiConference.prototype._maybeClearSITimeout = function() {\n    if (this._sessionInitiateTimeout\n            && (this.jvbJingleSession || this.getParticipantCount() < 2)) {\n        window.clearTimeout(this._sessionInitiateTimeout);\n        this._sessionInitiateTimeout = null;\n    }\n};\n\n/**\n * Sets a timeout which will emit {@link ACTION_JINGLE_SI_TIMEOUT} analytics\n * event.\n * @private\n */\nJitsiConference.prototype._maybeSetSITimeout = function() {\n    // Jicofo is supposed to invite if there are at least 2 participants\n    if (!this.jvbJingleSession\n            && this.getParticipantCount() >= 2\n            && !this._sessionInitiateTimeout) {\n        this._sessionInitiateTimeout = window.setTimeout(() => {\n            this._sessionInitiateTimeout = null;\n            Statistics.sendAnalytics(createJingleEvent(\n                ACTION_JINGLE_SI_TIMEOUT,\n                {\n                    p2p: false,\n                    value: JINGLE_SI_TIMEOUT\n                }));\n        }, JINGLE_SI_TIMEOUT);\n    }\n};\n\n/**\n * Mutes a participant.\n * @param {string} id The id of the participant to mute.\n */\nJitsiConference.prototype.muteParticipant = function(id, mediaType) {\n    const muteMediaType = mediaType ? mediaType : MediaType.AUDIO;\n\n    if (muteMediaType !== MediaType.AUDIO && muteMediaType !== MediaType.VIDEO) {\n        logger.error(`Unsupported media type: ${muteMediaType}`);\n\n        return;\n    }\n\n    const participant = this.getParticipantById(id);\n\n    if (!participant) {\n        return;\n    }\n    this.room.muteParticipant(participant.getJid(), true, muteMediaType);\n};\n\n/* eslint-disable max-params */\n\n/**\n * Notifies this JitsiConference that a new member has joined its chat room.\n *\n * FIXME This should NOT be exposed!\n *\n * @param jid the jid of the participant in the MUC\n * @param nick the display name of the participant\n * @param role the role of the participant in the MUC\n * @param isHidden indicates if this is a hidden participant (system\n * participant for example a recorder).\n * @param statsID the participant statsID (optional)\n * @param status the initial status if any\n * @param identity the member identity, if any\n * @param botType the member botType, if any\n * @param fullJid the member full jid, if any\n * @param features the member botType, if any\n * @param isReplaceParticipant whether this join replaces a participant with\n * the same jwt.\n */\nJitsiConference.prototype.onMemberJoined = function(\n        jid, nick, role, isHidden, statsID, status, identity, botType, fullJid, features, isReplaceParticipant) {\n    const id = Strophe.getResourceFromJid(jid);\n\n    if (id === 'focus' || this.myUserId() === id) {\n        return;\n    }\n    const participant = new JitsiParticipant(jid, this, nick, isHidden, statsID, status, identity);\n\n    participant.setConnectionJid(fullJid);\n    participant.setRole(role);\n    participant.setBotType(botType);\n    participant.setFeatures(features);\n    participant.setIsReplacing(isReplaceParticipant);\n\n    // Set remote tracks on the participant if source signaling was received before presence.\n    const remoteTracks = this.isP2PActive()\n        ? this.p2pJingleSession?.peerconnection.getRemoteTracks(id) ?? []\n        : this.jvbJingleSession?.peerconnection.getRemoteTracks(id) ?? [];\n\n    for (const track of remoteTracks) {\n        participant._tracks.push(track);\n    }\n\n    this.participants.set(id, participant);\n    this.eventEmitter.emit(\n        JitsiConferenceEvents.USER_JOINED,\n        id,\n        participant);\n\n    this._updateFeatures(participant);\n\n    // maybeStart only if we had finished joining as then we will have information for the number of participants\n    if (this.isJoined()) {\n        this._maybeStartOrStopP2P();\n    }\n\n    this._maybeSetSITimeout();\n};\n\n/* eslint-enable max-params */\n\n/**\n * Get notified when we joined the room.\n *\n * FIXME This should NOT be exposed!\n *\n * @private\n */\nJitsiConference.prototype._onMucJoined = function() {\n    this._maybeStartOrStopP2P();\n};\n\n/**\n * Updates features for a participant.\n * @param {JitsiParticipant} participant - The participant to query for features.\n * @returns {void}\n * @private\n */\nJitsiConference.prototype._updateFeatures = function(participant) {\n    participant.getFeatures()\n        .then(features => {\n            participant._supportsDTMF = features.has('urn:xmpp:jingle:dtmf:0');\n            this.updateDTMFSupport();\n\n            if (features.has(FEATURE_JIGASI)) {\n                participant.setProperty('features_jigasi', true);\n            }\n\n            if (features.has(FEATURE_E2EE)) {\n                participant.setProperty('features_e2ee', true);\n            }\n        })\n        .catch(() => false);\n};\n\n/**\n * Get notified when member bot type had changed.\n * @param jid the member jid\n * @param botType the new botType value\n * @private\n */\nJitsiConference.prototype._onMemberBotTypeChanged = function(jid, botType) {\n\n    // find the participant and mark it as non bot, as the real one will join\n    // in a moment\n    const peers = this.getParticipants();\n    const botParticipant = peers.find(p => p.getJid() === jid);\n\n    if (botParticipant) {\n        botParticipant.setBotType(botType);\n        const id = Strophe.getResourceFromJid(jid);\n\n        this.eventEmitter.emit(\n            JitsiConferenceEvents.BOT_TYPE_CHANGED,\n            id,\n            botType);\n    }\n\n    // if botType changed to undefined, botType was removed, in case of\n    // poltergeist mode this is the moment when the poltergeist had exited and\n    // the real participant had already replaced it.\n    // In this case we can check and try p2p\n    if (!botParticipant.getBotType()) {\n        this._maybeStartOrStopP2P();\n    }\n};\n\nJitsiConference.prototype.onMemberLeft = function(jid, reason) {\n    const id = Strophe.getResourceFromJid(jid);\n\n    if (id === 'focus' || this.myUserId() === id) {\n        return;\n    }\n\n    const mediaSessions = this.getMediaSessions();\n    let tracksToBeRemoved = [];\n\n    for (const session of mediaSessions) {\n        const remoteTracks = session.peerconnection.getRemoteTracks(id);\n\n        remoteTracks && (tracksToBeRemoved = [ ...tracksToBeRemoved, ...remoteTracks ]);\n\n        // Update the SSRC owners list.\n        session._signalingLayer.updateSsrcOwnersOnLeave(id);\n        if (!FeatureFlags.isSsrcRewritingSupported()) {\n            // Remove the ssrcs from the remote description and renegotiate.\n            session.removeRemoteStreamsOnLeave(id);\n        }\n    }\n\n    tracksToBeRemoved.forEach(track => {\n        if (FeatureFlags.isSsrcRewritingSupported()) {\n            track.setSourceName(null);\n            track.setOwner(null);\n        } else {\n            // Fire the event before renegotiation is done so that the thumbnails can be removed immediately.\n            this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);\n        }\n    });\n\n    const participant = this.participants.get(id);\n\n    if (participant) {\n        this.participants.delete(id);\n        this.eventEmitter.emit(JitsiConferenceEvents.USER_LEFT, id, participant, reason);\n    }\n\n    if (this.room !== null) { // Skip if we have left the room already.\n        this._maybeStartOrStopP2P(true /* triggered by user left event */);\n        this._maybeClearSITimeout();\n    }\n};\n\n/* eslint-disable max-params */\n\n/**\n * Designates an event indicating that we were kicked from the XMPP MUC.\n * @param {boolean} isSelfPresence - whether it is for local participant\n * or another participant.\n * @param {string} actorId - the id of the participant who was initiator\n * of the kick.\n * @param {string?} kickedParticipantId - when it is not a kick for local participant,\n * this is the id of the participant which was kicked.\n * @param {string} reason - reason of the participant to kick\n * @param {boolean?} isReplaceParticipant - whether this is a server initiated kick in order\n * to replace it with a participant with same jwt.\n */\nJitsiConference.prototype.onMemberKicked = function(\n        isSelfPresence,\n        actorId,\n        kickedParticipantId,\n        reason,\n        isReplaceParticipant) {\n    // This check which be true when we kick someone else. With the introduction of lobby\n    // the ChatRoom KICKED event is now also emitted for ourselves (the kicker) so we want to\n    // avoid emitting an event where `undefined` kicked someone.\n    if (actorId === this.myUserId()) {\n        return;\n    }\n\n    const actorParticipant = this.participants.get(actorId);\n\n    if (isSelfPresence) {\n        this.eventEmitter.emit(\n            JitsiConferenceEvents.KICKED, actorParticipant, reason, isReplaceParticipant);\n\n        this.leave();\n\n        return;\n    }\n\n    const kickedParticipant = this.participants.get(kickedParticipantId);\n\n    kickedParticipant.setIsReplaced(isReplaceParticipant);\n\n    this.eventEmitter.emit(\n        JitsiConferenceEvents.PARTICIPANT_KICKED, actorParticipant, kickedParticipant, reason);\n};\n\n/**\n * Method called on local MUC role change.\n * @param {string} role the name of new user's role as defined by XMPP MUC.\n */\nJitsiConference.prototype.onLocalRoleChanged = function(role) {\n    // Emit role changed for local  JID\n    this.eventEmitter.emit(\n        JitsiConferenceEvents.USER_ROLE_CHANGED, this.myUserId(), role);\n};\n\nJitsiConference.prototype.onUserRoleChanged = function(jid, role) {\n    const id = Strophe.getResourceFromJid(jid);\n    const participant = this.getParticipantById(id);\n\n    if (!participant) {\n        return;\n    }\n    participant.setRole(role);\n    this.eventEmitter.emit(JitsiConferenceEvents.USER_ROLE_CHANGED, id, role);\n};\n\nJitsiConference.prototype.onDisplayNameChanged = function(jid, displayName) {\n    const id = Strophe.getResourceFromJid(jid);\n    const participant = this.getParticipantById(id);\n\n    if (!participant) {\n        return;\n    }\n\n    if (participant._displayName === displayName) {\n        return;\n    }\n\n    participant._displayName = displayName;\n    this.eventEmitter.emit(\n        JitsiConferenceEvents.DISPLAY_NAME_CHANGED,\n        id,\n        displayName);\n};\n\n/**\n * Notifies this JitsiConference that a JitsiRemoteTrack was added to the conference.\n *\n * @param {JitsiRemoteTrack} track the JitsiRemoteTrack which was added to this JitsiConference.\n */\nJitsiConference.prototype.onRemoteTrackAdded = function(track) {\n    if (track.isP2P && !this.isP2PActive()) {\n        logger.info('Trying to add remote P2P track, when not in P2P - IGNORED');\n\n        return;\n    } else if (!track.isP2P && this.isP2PActive()) {\n        logger.info('Trying to add remote JVB track, when in P2P - IGNORED');\n\n        return;\n    }\n\n    const id = track.getParticipantId();\n    const participant = this.getParticipantById(id);\n\n    // Add track to JitsiParticipant.\n    if (participant) {\n        participant._tracks.push(track);\n    } else {\n        logger.info(`Source signaling received before presence for ${id}`);\n    }\n\n    if (this.transcriber) {\n        this.transcriber.addTrack(track);\n    }\n\n    const emitter = this.eventEmitter;\n\n    track.addEventListener(\n        JitsiTrackEvents.TRACK_MUTE_CHANGED,\n        () => emitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track));\n    track.isAudioTrack() && track.addEventListener(\n        JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,\n        (audioLevel, tpc) => {\n            const activeTPC = this.getActivePeerConnection();\n\n            if (activeTPC === tpc) {\n                emitter.emit(JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED, id, audioLevel);\n            }\n        }\n    );\n\n    emitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);\n};\n\n/**\n * Callback called by the Jingle plugin when 'session-answer' is received.\n * @param {JingleSessionPC} session the Jingle session for which an answer was\n * received.\n * @param {jQuery} answer a jQuery selector pointing to 'jingle' IQ element\n */\n// eslint-disable-next-line no-unused-vars\nJitsiConference.prototype.onCallAccepted = function(session, answer) {\n    if (this.p2pJingleSession === session) {\n        logger.info('P2P setAnswer');\n\n        this.p2pJingleSession.setAnswer(answer);\n        this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_STARTED, this.p2pJingleSession);\n    }\n};\n\n/**\n * Callback called by the Jingle plugin when 'transport-info' is received.\n * @param {JingleSessionPC} session the Jingle session for which the IQ was\n * received\n * @param {jQuery} transportInfo a jQuery selector pointing to 'jingle' IQ\n * element\n */\n// eslint-disable-next-line no-unused-vars\nJitsiConference.prototype.onTransportInfo = function(session, transportInfo) {\n    if (this.p2pJingleSession === session) {\n        logger.info('P2P addIceCandidates');\n        this.p2pJingleSession.addIceCandidates(transportInfo);\n    }\n};\n\n/**\n * Notifies this JitsiConference that a JitsiRemoteTrack was removed from\n * the conference.\n *\n * @param {JitsiRemoteTrack} removedTrack\n */\nJitsiConference.prototype.onRemoteTrackRemoved = function(removedTrack) {\n    this.getParticipants().forEach(participant => {\n        const tracks = participant.getTracks();\n\n        for (let i = 0; i < tracks.length; i++) {\n            if (tracks[i] === removedTrack) {\n                // Since the tracks have been compared and are\n                // considered equal the result of splice can be ignored.\n                participant._tracks.splice(i, 1);\n\n                this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, removedTrack);\n\n                if (this.transcriber) {\n                    this.transcriber.removeTrack(removedTrack);\n                }\n\n                break;\n            }\n        }\n    }, this);\n};\n\n/**\n * Handles an incoming call event for the P2P jingle session.\n */\nJitsiConference.prototype._onIncomingCallP2P = function(jingleSession, jingleOffer) {\n    let rejectReason;\n    const usesUnifiedPlan = browser.supportsUnifiedPlan();\n    const contentName = jingleOffer.find('>content').attr('name');\n    const peerUsesUnifiedPlan = contentName === '0' || contentName === '1';\n\n    // Reject P2P between endpoints that are not running in the same mode w.r.t to SDPs (plan-b and unified plan).\n    if (usesUnifiedPlan !== peerUsesUnifiedPlan) {\n        rejectReason = {\n            reason: 'decline',\n            reasonDescription: 'P2P disabled',\n            errorMsg: 'P2P across two endpoints in different SDP modes is disabled'\n        };\n    } else if ((!this.isP2PEnabled() && !this.isP2PTestModeEnabled())\n        || browser.isFirefox()\n        || browser.isWebKitBased()) {\n        rejectReason = {\n            reason: 'decline',\n            reasonDescription: 'P2P disabled',\n            errorMsg: 'P2P mode disabled in the configuration or browser unsupported'\n        };\n    } else if (this.p2pJingleSession) {\n        // Reject incoming P2P call (already in progress)\n        rejectReason = {\n            reason: 'busy',\n            reasonDescription: 'P2P already in progress',\n            errorMsg: 'Duplicated P2P \"session-initiate\"'\n        };\n    } else if (!this._shouldBeInP2PMode()) {\n        rejectReason = {\n            reason: 'decline',\n            reasonDescription: 'P2P requirements not met',\n            errorMsg: 'Received P2P \"session-initiate\" when should not be in P2P mode'\n        };\n        Statistics.sendAnalytics(createJingleEvent(ACTION_P2P_DECLINED));\n    }\n\n    if (rejectReason) {\n        this._rejectIncomingCall(jingleSession, rejectReason);\n    } else {\n        this._acceptP2PIncomingCall(jingleSession, jingleOffer);\n    }\n};\n\n/**\n * Handles an incoming call event.\n */\nJitsiConference.prototype.onIncomingCall = function(jingleSession, jingleOffer, now) {\n    // Handle incoming P2P call\n    if (jingleSession.isP2P) {\n        this._onIncomingCallP2P(jingleSession, jingleOffer);\n    } else {\n        if (!this.isFocus(jingleSession.remoteJid)) {\n            const description = 'Rejecting session-initiate from non-focus.';\n\n            this._rejectIncomingCall(\n                jingleSession, {\n                    reason: 'security-error',\n                    reasonDescription: description,\n                    errorMsg: description\n                });\n\n            return;\n        }\n        this._acceptJvbIncomingCall(jingleSession, jingleOffer, now);\n    }\n};\n\n/**\n * Accepts an incoming call event for the JVB jingle session.\n */\nJitsiConference.prototype._acceptJvbIncomingCall = function(jingleSession, jingleOffer, now) {\n\n    // Accept incoming call\n    this.jvbJingleSession = jingleSession;\n    this.room.connectionTimes['session.initiate'] = now;\n    this._sendConferenceJoinAnalyticsEvent();\n\n    if (this.wasStopped) {\n        Statistics.sendAnalyticsAndLog(createJingleEvent(ACTION_JINGLE_RESTART, { p2p: false }));\n    }\n\n    const serverRegion\n        = $(jingleOffer)\n            .find('>bridge-session[xmlns=\"http://jitsi.org/protocol/focus\"]')\n            .attr('region');\n\n    this.eventEmitter.emit(JitsiConferenceEvents.SERVER_REGION_CHANGED, serverRegion);\n\n    this._maybeClearSITimeout();\n    Statistics.sendAnalytics(createJingleEvent(\n        ACTION_JINGLE_SI_RECEIVED,\n        {\n            p2p: false,\n            value: now\n        }));\n\n    try {\n        jingleSession.initialize(\n            this.room,\n            this.rtc,\n            this._signalingLayer,\n            {\n                ...this.options.config,\n                codecSettings: {\n                    mediaType: MediaType.VIDEO,\n                    preferred: this.codecSelection.jvbPreferredCodec,\n                    disabled: this.codecSelection.jvbDisabledCodec\n                },\n                enableInsertableStreams: this.isE2EEEnabled() || FeatureFlags.isRunInLiteModeEnabled()\n            });\n    } catch (error) {\n        GlobalOnErrorHandler.callErrorHandler(error);\n        logger.error(error);\n\n        return;\n    }\n\n    // Open a channel with the videobridge.\n    this._setBridgeChannel(jingleOffer, jingleSession.peerconnection);\n\n    const localTracks = this._getInitialLocalTracks();\n\n    try {\n        jingleSession.acceptOffer(\n            jingleOffer,\n            () => {\n                // If for any reason invite for the JVB session arrived after\n                // the P2P has been established already the media transfer needs\n                // to be turned off here.\n                if (this.isP2PActive() && this.jvbJingleSession) {\n                    this._suspendMediaTransferForJvbConnection();\n                }\n\n                this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_STARTED, jingleSession);\n                if (!this.isP2PActive()) {\n                    this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED, jingleSession);\n                }\n            },\n            error => {\n                GlobalOnErrorHandler.callErrorHandler(error);\n                logger.error('Failed to accept incoming Jingle session', error);\n            },\n            localTracks\n        );\n\n        // Enable or disable simulcast for plan-b screensharing based on the capture fps if it is set through the UI.\n        this._desktopSharingFrameRate\n            && jingleSession.peerconnection.setDesktopSharingFrameRate(this._desktopSharingFrameRate);\n\n        // Start callstats as soon as peerconnection is initialized,\n        // do not wait for XMPPEvents.PEERCONNECTION_READY, as it may never\n        // happen in case if user doesn't have or denied permission to\n        // both camera and microphone.\n        logger.info('Starting CallStats for JVB connection...');\n        this.statistics.startCallStats(\n            this.jvbJingleSession.peerconnection,\n            'jitsi' /* Remote user ID for JVB is 'jitsi' */);\n        this.statistics.startRemoteStats(this.jvbJingleSession.peerconnection);\n    } catch (e) {\n        GlobalOnErrorHandler.callErrorHandler(e);\n        logger.error(e);\n    }\n};\n\n/**\n * Sets the BridgeChannel.\n *\n * @param {jQuery} offerIq a jQuery selector pointing to the jingle element of\n * the offer IQ which may carry the WebSocket URL for the 'websocket'\n * BridgeChannel mode.\n * @param {TraceablePeerConnection} pc the peer connection which will be used\n * to listen for new WebRTC Data Channels (in the 'datachannel' mode).\n */\nJitsiConference.prototype._setBridgeChannel = function(offerIq, pc) {\n    const ignoreDomain = this.connection?.options?.bridgeChannel?.ignoreDomain;\n    const preferSctp = this.connection?.options?.bridgeChannel?.preferSctp ?? false;\n    const sctpOffered = $(offerIq).find('>content[name=\"data\"]')\n        .first().length === 1;\n    let wsUrl = null;\n\n    logger.info(`SCTP: offered=${sctpOffered}, prefered=${preferSctp}`);\n\n    if (!(sctpOffered && preferSctp)) {\n        $(offerIq).find('>content>transport>web-socket')\n            .toArray()\n            .map(e => e.getAttribute('url'))\n            .forEach(url => {\n                if (!wsUrl && (!ignoreDomain || ignoreDomain !== new URL(url).hostname)) {\n                    wsUrl = url;\n                    logger.info(`Using colibri-ws url ${url}`);\n                } else if (!wsUrl) {\n                    logger.info(`Ignoring colibri-ws url with domain ${ignoreDomain}`);\n                }\n            });\n\n        if (!wsUrl) {\n            const firstWsUrl = $(offerIq).find('>content>transport>web-socket')\n                .first();\n\n            if (firstWsUrl.length === 1) {\n                wsUrl = firstWsUrl[0].getAttribute('url');\n                logger.info(`Falling back to ${wsUrl}`);\n            }\n        }\n    }\n\n    if (wsUrl && !(sctpOffered && preferSctp)) {\n        // If the offer contains a websocket and we don't prefer SCTP use it.\n        this.rtc.initializeBridgeChannel(null, wsUrl);\n    } else if (sctpOffered) {\n        // Otherwise, fall back to an attempt to use SCTP.\n        this.rtc.initializeBridgeChannel(pc, null);\n    } else {\n        logger.warn('Neither SCTP nor a websocket is available. Will not initialize bridge channel.');\n    }\n};\n\n/**\n * Rejects incoming Jingle call.\n * @param {JingleSessionPC} jingleSession the session instance to be rejected.\n * @param {object} [options]\n * @param {string} options.reason the name of the reason element as defined\n * by Jingle\n * @param {string} options.reasonDescription the reason description which will\n * be included in Jingle 'session-terminate' message.\n * @param {string} options.errorMsg an error message to be logged on global\n * error handler\n * @private\n */\nJitsiConference.prototype._rejectIncomingCall = function(jingleSession, options) {\n    if (options?.errorMsg) {\n        logger.warn(options.errorMsg);\n    }\n\n    // Terminate the jingle session with a reason\n    jingleSession.terminate(\n        null /* success callback => we don't care */,\n        error => {\n            logger.warn(\n                'An error occurred while trying to terminate'\n                    + ' invalid Jingle session', error);\n        }, {\n            reason: options && options.reason,\n            reasonDescription: options && options.reasonDescription,\n            sendSessionTerminate: true\n        });\n};\n\n/**\n * Handles the call ended event.\n * XXX is this due to the remote side terminating the Jingle session?\n *\n * @param {JingleSessionPC} jingleSession the jingle session which has been\n * terminated.\n * @param {String} reasonCondition the Jingle reason condition.\n * @param {String|null} reasonText human readable reason text which may provide\n * more details about why the call has been terminated.\n */\nJitsiConference.prototype.onCallEnded = function(jingleSession, reasonCondition, reasonText) {\n    logger.info(\n        `Call ended: ${reasonCondition} - ${reasonText} P2P ?${\n            jingleSession.isP2P}`);\n    if (jingleSession === this.jvbJingleSession) {\n        this.wasStopped = true;\n\n        Statistics.sendAnalytics(\n            createJingleEvent(ACTION_JINGLE_TERMINATE, { p2p: false }));\n\n        // Stop the stats\n        if (this.statistics) {\n            this.statistics.stopRemoteStats(\n                this.jvbJingleSession.peerconnection);\n            logger.info('Stopping JVB CallStats');\n            this.statistics.stopCallStats(\n                this.jvbJingleSession.peerconnection);\n        }\n\n        // Current JVB JingleSession is no longer valid, so set it to null\n        this.jvbJingleSession = null;\n\n        // Let the RTC service do any cleanups\n        this.rtc.onCallEnded();\n    } else if (jingleSession === this.p2pJingleSession) {\n        const stopOptions = {};\n\n        // It's the responder who decides to enforce JVB mode, so that both\n        // initiator and responder are aware if it was intentional.\n        if (reasonCondition === 'decline' && reasonText === 'force JVB121') {\n            logger.info('In forced JVB 121 mode...');\n            Statistics.analytics.addPermanentProperties({ forceJvb121: true });\n        } else if (reasonCondition === 'connectivity-error'\n            && reasonText === 'ICE FAILED') {\n            // It can happen that the other peer detects ICE failed and\n            // terminates the session, before we get the event on our side.\n            // But we are able to parse the reason and mark it here.\n            Statistics.analytics.addPermanentProperties({ p2pFailed: true });\n        } else if (reasonCondition === 'success' && reasonText === 'restart') {\n            // When we are restarting media sessions we don't want to switch the tracks\n            // to the JVB just yet.\n            stopOptions.requestRestart = true;\n        }\n        this._stopP2PSession(stopOptions);\n    } else {\n        logger.error(\n            'Received onCallEnded for invalid session',\n            jingleSession.sid,\n            jingleSession.remoteJid,\n            reasonCondition,\n            reasonText);\n    }\n};\n\n/**\n * Handles the suspend detected event. Leaves the room and fires suspended.\n * @param {JingleSessionPC} jingleSession\n */\nJitsiConference.prototype.onSuspendDetected = function(jingleSession) {\n    if (!jingleSession.isP2P) {\n        this.leave();\n        this.eventEmitter.emit(JitsiConferenceEvents.SUSPEND_DETECTED);\n    }\n};\n\nJitsiConference.prototype.updateDTMFSupport = function() {\n    let somebodySupportsDTMF = false;\n    const participants = this.getParticipants();\n\n    // check if at least 1 participant supports DTMF\n    for (let i = 0; i < participants.length; i += 1) {\n        if (participants[i].supportsDTMF()) {\n            somebodySupportsDTMF = true;\n            break;\n        }\n    }\n    if (somebodySupportsDTMF !== this.somebodySupportsDTMF) {\n        this.somebodySupportsDTMF = somebodySupportsDTMF;\n        this.eventEmitter.emit(\n            JitsiConferenceEvents.DTMF_SUPPORT_CHANGED,\n            somebodySupportsDTMF);\n    }\n};\n\n/**\n * Allows to check if there is at least one user in the conference\n * that supports DTMF.\n * @returns {boolean} true if somebody supports DTMF, false otherwise\n */\nJitsiConference.prototype.isDTMFSupported = function() {\n    return this.somebodySupportsDTMF;\n};\n\n/**\n * Returns the local user's ID\n * @return {string} local user's ID\n */\nJitsiConference.prototype.myUserId = function() {\n    return (\n        this.room && this.room.myroomjid\n            ? Strophe.getResourceFromJid(this.room.myroomjid)\n            : null);\n};\n\nJitsiConference.prototype.sendTones = function(tones, duration, pause) {\n    const peerConnection = this.getActivePeerConnection();\n\n    if (peerConnection) {\n        peerConnection.sendTones(tones, duration, pause);\n    } else {\n        logger.warn('cannot sendTones: no peer connection');\n    }\n};\n\n/**\n * Starts recording the current conference.\n *\n * @param {Object} options - Configuration for the recording. See\n * {@link Chatroom#startRecording} for more info.\n * @returns {Promise} See {@link Chatroom#startRecording} for more info.\n */\nJitsiConference.prototype.startRecording = function(options) {\n    if (this.room) {\n        return this.recordingManager.startRecording(options);\n    }\n\n    return Promise.reject(new Error('The conference is not created yet!'));\n};\n\n/**\n * Stop a recording session.\n *\n * @param {string} sessionID - The ID of the recording session that\n * should be stopped.\n * @returns {Promise} See {@link Chatroom#stopRecording} for more info.\n */\nJitsiConference.prototype.stopRecording = function(sessionID) {\n    if (this.room) {\n        return this.recordingManager.stopRecording(sessionID);\n    }\n\n    return Promise.reject(new Error('The conference is not created yet!'));\n};\n\n/**\n * Returns true if the SIP calls are supported and false otherwise\n */\nJitsiConference.prototype.isSIPCallingSupported = function() {\n    return this.room?.moderator?.isSipGatewayEnabled() ?? false;\n};\n\n/**\n * Dials a number.\n * @param number the number\n */\nJitsiConference.prototype.dial = function(number) {\n    if (this.room) {\n        return this.room.dial(number);\n    }\n\n    return new Promise((resolve, reject) => {\n        reject(new Error('The conference is not created yet!'));\n    });\n};\n\n/**\n * Hangup an existing call\n */\nJitsiConference.prototype.hangup = function() {\n    if (this.room) {\n        return this.room.hangup();\n    }\n\n    return new Promise((resolve, reject) => {\n        reject(new Error('The conference is not created yet!'));\n    });\n};\n\n/**\n * Starts the transcription service.\n */\nJitsiConference.prototype.startTranscriber = function() {\n    return this.dial('jitsi_meet_transcribe');\n};\n\n\n/**\n * Stops the transcription service.\n */\nJitsiConference.prototype.stopTranscriber = JitsiConference.prototype.hangup;\n\n/**\n * Returns the phone number for joining the conference.\n */\nJitsiConference.prototype.getPhoneNumber = function() {\n    if (this.room) {\n        return this.room.getPhoneNumber();\n    }\n\n    return null;\n};\n\n/**\n * Returns the pin for joining the conference with phone.\n */\nJitsiConference.prototype.getPhonePin = function() {\n    if (this.room) {\n        return this.room.getPhonePin();\n    }\n\n    return null;\n};\n\n/**\n * Returns the meeting unique ID if any.\n *\n * @returns {string|undefined}\n */\nJitsiConference.prototype.getMeetingUniqueId = function() {\n    if (this.room) {\n        return this.room.getMeetingId();\n    }\n};\n\n/**\n * Will return P2P or JVB <tt>TraceablePeerConnection</tt> depending on\n * which connection is currently active.\n *\n * @return {TraceablePeerConnection|null} null if there isn't any active\n * <tt>TraceablePeerConnection</tt> currently available.\n * @public (FIXME how to make package local ?)\n */\nJitsiConference.prototype.getActivePeerConnection = function() {\n    const session = this.isP2PActive() ? this.p2pJingleSession : this.jvbJingleSession;\n\n    return session ? session.peerconnection : null;\n};\n\n/**\n * Returns the connection state for the current room. Its ice connection state\n * for its session.\n * NOTE that \"completed\" ICE state which can appear on the P2P connection will\n * be converted to \"connected\".\n * @return {string|null} ICE state name or <tt>null</tt> if there is no active\n * peer connection at this time.\n */\nJitsiConference.prototype.getConnectionState = function() {\n    const peerConnection = this.getActivePeerConnection();\n\n    return peerConnection ? peerConnection.getConnectionState() : null;\n};\n\n/**\n * Make all new participants mute their audio/video on join.\n * @param policy {Object} object with 2 boolean properties for video and audio:\n * @param {boolean} audio if audio should be muted.\n * @param {boolean} video if video should be muted.\n */\nJitsiConference.prototype.setStartMutedPolicy = function(policy) {\n    if (!this.isModerator()) {\n        logger.warn(`Failed to set start muted policy, ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator'}`);\n\n        return;\n    }\n    this.startMutedPolicy = policy;\n    this.room.addOrReplaceInPresence('startmuted', {\n        attributes: {\n            audio: policy.audio,\n            video: policy.video,\n            xmlns: 'http://jitsi.org/jitmeet/start-muted'\n        }\n    }) && this.room.sendPresence();\n};\n\n/**\n * Returns current start muted policy\n * @returns {Object} with 2 properties - audio and video.\n */\nJitsiConference.prototype.getStartMutedPolicy = function() {\n    return this.startMutedPolicy;\n};\n\n/**\n * Check if audio is muted on join.\n */\nJitsiConference.prototype.isStartAudioMuted = function() {\n    return this.startAudioMuted;\n};\n\n/**\n * Check if video is muted on join.\n */\nJitsiConference.prototype.isStartVideoMuted = function() {\n    return this.startVideoMuted;\n};\n\n/**\n * Returns measured connectionTimes.\n */\nJitsiConference.prototype.getConnectionTimes = function() {\n    return this.room.connectionTimes;\n};\n\n/**\n * Sets a property for the local participant.\n */\nJitsiConference.prototype.setLocalParticipantProperty = function(name, value) {\n    this.sendCommand(`jitsi_participant_${name}`, { value });\n};\n\n/**\n *  Removes a property for the local participant and sends the updated presence.\n */\nJitsiConference.prototype.removeLocalParticipantProperty = function(name) {\n    this.removeCommand(`jitsi_participant_${name}`);\n    this.room.sendPresence();\n};\n\n/**\n * Gets a local participant property.\n *\n * @return value of the local participant property if the tagName exists in the\n * list of properties, otherwise returns undefined.\n */\nJitsiConference.prototype.getLocalParticipantProperty = function(name) {\n    const property = this.room.presMap.nodes.find(prop =>\n        prop.tagName === `jitsi_participant_${name}`\n    );\n\n    return property ? property.value : undefined;\n};\n\n/**\n * Sends the given feedback through CallStats if enabled.\n *\n * @param overallFeedback an integer between 1 and 5 indicating the\n * user feedback\n * @param detailedFeedback detailed feedback from the user. Not yet used\n * @returns {Promise} Resolves if feedback is submitted successfully.\n */\nJitsiConference.prototype.sendFeedback = function(overallFeedback, detailedFeedback) {\n    return this.statistics.sendFeedback(overallFeedback, detailedFeedback);\n};\n\n/**\n * Returns true if the callstats integration is enabled, otherwise returns\n * false.\n *\n * @returns true if the callstats integration is enabled, otherwise returns\n * false.\n */\nJitsiConference.prototype.isCallstatsEnabled = function() {\n    return this.statistics.isCallstatsEnabled();\n};\n\n/**\n * Finds the SSRC of a given track\n *\n * @param track\n * @returns {number|undefined} the SSRC of the specificed track, otherwise undefined.\n */\nJitsiConference.prototype.getSsrcByTrack = function(track) {\n    return track.isLocal() ? this.getActivePeerConnection()?.getLocalSSRC(track) : track.getSSRC();\n};\n\n/**\n * Handles track attached to container (Calls associateStreamWithVideoTag method\n * from statistics module)\n * @param {JitsiLocalTrack|JitsiRemoteTrack} track the track\n * @param container the container\n */\nJitsiConference.prototype._onTrackAttach = function(track, container) {\n    const isLocal = track.isLocal();\n    let ssrc = null;\n    const isP2P = track.isP2P;\n    const remoteUserId = isP2P ? track.getParticipantId() : 'jitsi';\n    const peerConnection\n        = isP2P\n            ? this.p2pJingleSession && this.p2pJingleSession.peerconnection\n            : this.jvbJingleSession && this.jvbJingleSession.peerconnection;\n\n    if (isLocal) {\n        // Local tracks have SSRC stored on per peer connection basis.\n        if (peerConnection) {\n            ssrc = peerConnection.getLocalSSRC(track);\n        }\n    } else {\n        ssrc = track.getSSRC();\n    }\n    if (!container.id || !ssrc || !peerConnection) {\n        return;\n    }\n\n    this.statistics.associateStreamWithVideoTag(\n        peerConnection,\n        ssrc,\n        isLocal,\n        remoteUserId,\n        track.getUsageLabel(),\n        container.id);\n};\n\n/**\n * Logs an \"application log\" message.\n * @param message {string} The message to log. Note that while this can be a\n * generic string, the convention used by lib-jitsi-meet and jitsi-meet is to\n * log valid JSON strings, with an \"id\" field used for distinguishing between\n * message types. E.g.: {id: \"recorder_status\", status: \"off\"}\n */\nJitsiConference.prototype.sendApplicationLog = function(message) {\n    Statistics.sendLog(message);\n};\n\n/**\n * Checks if the user identified by given <tt>mucJid</tt> is the conference focus.\n * @param mucJid the full MUC address of the user to be checked.\n * @returns {boolean|null} <tt>true</tt> if MUC user is the conference focus,\n * <tt>false</tt> when is not. <tt>null</tt> if we're not in the MUC anymore and\n * are unable to figure out the status or if given <tt>mucJid</tt> is invalid.\n */\nJitsiConference.prototype.isFocus = function(mucJid) {\n    return this.room ? this.room.isFocus(mucJid) : null;\n};\n\n/**\n * Fires CONFERENCE_FAILED event with INCOMPATIBLE_SERVER_VERSIONS parameter\n */\nJitsiConference.prototype._fireIncompatibleVersionsEvent = function() {\n    this.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.INCOMPATIBLE_SERVER_VERSIONS);\n};\n\n/**\n * Sends a message via the data channel.\n * @param to {string} the id of the endpoint that should receive the message.\n * If \"\" the message will be sent to all participants.\n * @param payload {object} the payload of the message.\n * @throws NetworkError or InvalidStateError or Error if the operation fails.\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\n */\nJitsiConference.prototype.sendEndpointMessage = function(to, payload) {\n    this.rtc.sendChannelMessage(to, payload);\n};\n\n/**\n * Sends local stats via the bridge channel which then forwards to other endpoints selectively.\n * @param {Object} payload The payload of the message.\n * @throws NetworkError/InvalidStateError/Error if the operation fails or if there is no data channel created.\n */\nJitsiConference.prototype.sendEndpointStatsMessage = function(payload) {\n    this.rtc.sendEndpointStatsMessage(payload);\n};\n\n/**\n * Sends a broadcast message via the data channel.\n * @param payload {object} the payload of the message.\n * @throws NetworkError or InvalidStateError or Error if the operation fails.\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\n */\nJitsiConference.prototype.broadcastEndpointMessage = function(payload) {\n    this.sendEndpointMessage('', payload);\n};\n\n/**\n * Sends a message to a given endpoint (if 'to' is a non-empty string), or\n * broadcasts it to all endpoints in the conference.\n * @param {string} to The ID of the endpoint/participant which is to receive\n * the message, or '' to broadcast the message to all endpoints in the\n * conference.\n * @param {string|object} message the message to send. If this is of type\n * 'string' it will be sent as a chat message. If it is of type 'object', it\n * will be encapsulated in a format recognized by jitsi-meet and converted to\n * JSON before being sent.\n * @param {boolean} sendThroughVideobridge Whether to send the message through\n * jitsi-videobridge (via the COLIBRI data channel or web socket), or through\n * the XMPP MUC. Currently only objects can be sent through jitsi-videobridge.\n */\nJitsiConference.prototype.sendMessage = function(message, to = '', sendThroughVideobridge = false) {\n    const messageType = typeof message;\n\n    // Through videobridge we support only objects. Through XMPP we support\n    // objects (encapsulated in a specific JSON format) and strings (i.e.\n    // regular chat messages).\n    if (messageType !== 'object'\n            && (sendThroughVideobridge || messageType !== 'string')) {\n        logger.error(`Can not send a message of type ${messageType}`);\n\n        return;\n    }\n\n    if (sendThroughVideobridge) {\n        this.sendEndpointMessage(to, message);\n    } else {\n        let messageToSend = message;\n\n        // Name of packet extension of message stanza to send the required\n        // message in.\n        let elementName = 'body';\n\n        if (messageType === 'object') {\n            elementName = 'json-message';\n\n            // Mark as valid JSON message if not already\n            if (!messageToSend.hasOwnProperty(JITSI_MEET_MUC_TYPE)) {\n                messageToSend[JITSI_MEET_MUC_TYPE] = '';\n            }\n\n            try {\n                messageToSend = JSON.stringify(messageToSend);\n            } catch (e) {\n                logger.error('Can not send a message, stringify failed: ', e);\n\n                return;\n            }\n        }\n\n        if (to) {\n            this.sendPrivateTextMessage(to, messageToSend, elementName);\n        } else {\n            // Broadcast\n            this.sendTextMessage(messageToSend, elementName);\n        }\n    }\n\n};\n\nJitsiConference.prototype.isConnectionInterrupted = function() {\n    return this.isP2PActive()\n        ? this.isP2PConnectionInterrupted : this.isJvbConnectionInterrupted;\n};\n\n/**\n * Handles {@link XMPPEvents.CONNECTION_RESTARTED} event. This happens when the bridge goes down\n * and Jicofo moves conferences away to a different bridge.\n * @param {JingleSessionPC} session\n * @private\n */\nJitsiConference.prototype._onConferenceRestarted = function(session) {\n    if (!session.isP2P && this.options.config.enableForcedReload) {\n        this.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED, JitsiConferenceErrors.CONFERENCE_RESTARTED);\n    }\n};\n\n/**\n * Handles {@link XMPPEvents.CONNECTION_INTERRUPTED}\n * @param {JingleSessionPC} session\n * @private\n */\nJitsiConference.prototype._onIceConnectionInterrupted = function(session) {\n    if (session.isP2P) {\n        this.isP2PConnectionInterrupted = true;\n    } else {\n        this.isJvbConnectionInterrupted = true;\n    }\n    if (session.isP2P === this.isP2PActive()) {\n        this.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_INTERRUPTED);\n    }\n};\n\n/**\n * Handles {@link XMPPEvents.CONNECTION_ICE_FAILED}\n * @param {JingleSessionPC} session\n * @private\n */\nJitsiConference.prototype._onIceConnectionFailed = function(session) {\n    // We do nothing for the JVB connection, because it's up to the Jicofo to\n    // eventually come up with the new offer (at least for the time being).\n    if (session.isP2P) {\n        // Add p2pFailed property to analytics to distinguish, between \"good\"\n        // and \"bad\" connection\n        Statistics.analytics.addPermanentProperties({ p2pFailed: true });\n\n        if (this.p2pJingleSession) {\n            Statistics.sendAnalyticsAndLog(\n                createP2PEvent(\n                    ACTION_P2P_FAILED,\n                    {\n                        initiator: this.p2pJingleSession.isInitiator\n                    }));\n\n        }\n        this._stopP2PSession({\n            reason: 'connectivity-error',\n            reasonDescription: 'ICE FAILED'\n        });\n    } else if (session && this.jvbJingleSession === session) {\n        this._delayedIceFailed = new IceFailedHandling(this);\n        this._delayedIceFailed.start(session);\n    }\n};\n\n/**\n * Handles {@link XMPPEvents.CONNECTION_RESTORED}\n * @param {JingleSessionPC} session\n * @private\n */\nJitsiConference.prototype._onIceConnectionRestored = function(session) {\n    if (session.isP2P) {\n        this.isP2PConnectionInterrupted = false;\n    } else {\n        this.isJvbConnectionInterrupted = false;\n        this._delayedIceFailed && this._delayedIceFailed.cancel();\n    }\n\n    if (session.isP2P === this.isP2PActive()) {\n        this.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_RESTORED);\n    }\n};\n\n/**\n * Accept incoming P2P Jingle call.\n * @param {JingleSessionPC} jingleSession the session instance\n * @param {jQuery} jingleOffer a jQuery selector pointing to 'jingle' IQ element\n * @private\n */\nJitsiConference.prototype._acceptP2PIncomingCall = function(jingleSession, jingleOffer) {\n    this.isP2PConnectionInterrupted = false;\n\n    // Accept the offer\n    this.p2pJingleSession = jingleSession;\n    this._sendConferenceJoinAnalyticsEvent();\n\n    this.p2pJingleSession.initialize(\n        this.room,\n        this.rtc,\n        this._signalingLayer,\n        {\n            ...this.options.config,\n            codecSettings: {\n                mediaType: MediaType.VIDEO,\n                preferred: this.codecSelection.p2pPreferredCodec,\n                disabled: this.codecSelection.p2pDisabledCodec\n            },\n            enableInsertableStreams: this.isE2EEEnabled() || FeatureFlags.isRunInLiteModeEnabled()\n        });\n\n    logger.info('Starting CallStats for P2P connection...');\n\n    let remoteID = Strophe.getResourceFromJid(this.p2pJingleSession.remoteJid);\n\n    const participant = this.participants.get(remoteID);\n\n    if (participant) {\n        remoteID = participant.getStatsID() || remoteID;\n    }\n\n    this.statistics.startCallStats(\n        this.p2pJingleSession.peerconnection,\n        remoteID);\n\n    const localTracks = this.getLocalTracks();\n\n    this.p2pJingleSession.acceptOffer(\n        jingleOffer,\n        () => {\n            logger.debug('Got RESULT for P2P \"session-accept\"');\n\n            this.eventEmitter.emit(\n                JitsiConferenceEvents._MEDIA_SESSION_STARTED,\n                jingleSession);\n        },\n        error => {\n            logger.error(\n                'Failed to accept incoming P2P Jingle session', error);\n        },\n        localTracks);\n};\n\n/**\n * Adds remote tracks to the conference associated with the JVB session.\n * @private\n */\nJitsiConference.prototype._addRemoteJVBTracks = function() {\n    this._addRemoteTracks('JVB', this.jvbJingleSession.peerconnection.getRemoteTracks());\n};\n\n/**\n * Adds remote tracks to the conference associated with the P2P session.\n * @private\n */\nJitsiConference.prototype._addRemoteP2PTracks = function() {\n    this._addRemoteTracks('P2P', this.p2pJingleSession.peerconnection.getRemoteTracks());\n};\n\n/**\n * Generates fake \"remote track added\" events for given Jingle session.\n * @param {string} logName the session's nickname which will appear in log messages.\n * @param {Array<JitsiRemoteTrack>} remoteTracks the tracks that will be added\n * @private\n */\nJitsiConference.prototype._addRemoteTracks = function(logName, remoteTracks) {\n    for (const track of remoteTracks) {\n        // There will be orphan (with no owner) tracks when ssrc-rewriting is enabled and all of them need to be addded\n        // back to the conference.\n        if (FeatureFlags.isSsrcRewritingSupported() || this.participants.has(track.ownerEndpointId)) {\n            logger.info(`Adding remote ${logName} track: ${track}`);\n            this.onRemoteTrackAdded(track);\n        }\n    }\n};\n\n/**\n * Called when {@link XMPPEvents.CONNECTION_ESTABLISHED} event is\n * triggered for a {@link JingleSessionPC}. Switches the conference to use\n * the P2P connection if the event comes from the P2P session.\n * @param {JingleSessionPC} jingleSession the session instance.\n * @private\n */\nJitsiConference.prototype._onIceConnectionEstablished = function(jingleSession) {\n    if (this.p2pJingleSession !== null) {\n        // store the establishment time of the p2p session as a field of the\n        // JitsiConference because the p2pJingleSession might get disposed (thus\n        // the value is lost).\n        this.p2pEstablishmentDuration\n            = this.p2pJingleSession.establishmentDuration;\n    }\n\n    if (this.jvbJingleSession !== null) {\n        this.jvbEstablishmentDuration\n            = this.jvbJingleSession.establishmentDuration;\n    }\n\n    let done = false;\n    const forceJVB121Ratio = this.options.config.forceJVB121Ratio;\n\n    // We don't care about the JVB case, there's nothing to be done\n    if (!jingleSession.isP2P) {\n        done = true;\n    } else if (this.p2pJingleSession !== jingleSession) {\n        logger.error('CONNECTION_ESTABLISHED - wrong P2P session instance ?!');\n\n        done = true;\n    } else if (!jingleSession.isInitiator\n        && typeof forceJVB121Ratio === 'number'\n        && Math.random() < forceJVB121Ratio) {\n        logger.info(`Forcing JVB 121 mode (ratio=${forceJVB121Ratio})...`);\n        Statistics.analytics.addPermanentProperties({ forceJvb121: true });\n        this._stopP2PSession({\n            reason: 'decline',\n            reasonDescription: 'force JVB121'\n        });\n\n        done = true;\n    }\n\n    if (!isNaN(this.p2pEstablishmentDuration)\n        && !isNaN(this.jvbEstablishmentDuration)) {\n        const establishmentDurationDiff\n            = this.p2pEstablishmentDuration - this.jvbEstablishmentDuration;\n\n        Statistics.sendAnalytics(\n            ICE_ESTABLISHMENT_DURATION_DIFF,\n            { value: establishmentDurationDiff });\n    }\n\n    if (jingleSession.isP2P === this.isP2PActive()) {\n        this.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_ESTABLISHED);\n    }\n\n    if (done) {\n\n        return;\n    }\n\n    // Update P2P status and emit events\n    this._setP2PStatus(true);\n\n    // Remove remote tracks\n    if (this.jvbJingleSession) {\n        this._removeRemoteJVBTracks();\n    } else {\n        logger.info('Not removing remote JVB tracks - no session yet');\n    }\n\n    this._addRemoteP2PTracks();\n\n    // Stop media transfer over the JVB connection\n    if (this.jvbJingleSession) {\n        this._suspendMediaTransferForJvbConnection();\n    }\n\n    logger.info('Starting remote stats with p2p connection');\n    this.statistics.startRemoteStats(this.p2pJingleSession.peerconnection);\n\n    Statistics.sendAnalyticsAndLog(\n        createP2PEvent(\n            ACTION_P2P_ESTABLISHED,\n            {\n                initiator: this.p2pJingleSession.isInitiator\n            }));\n\n};\n\n/**\n * Called when the chat room reads a new list of properties from jicofo's\n * presence. The properties may have changed, but they don't have to.\n *\n * @param {Object} properties - The properties keyed by the property name\n * ('key').\n * @private\n */\nJitsiConference.prototype._updateProperties = function(properties = {}) {\n    const changed = !isEqual(properties, this.properties);\n\n    this.properties = properties;\n    if (changed) {\n        this.eventEmitter.emit(JitsiConferenceEvents.PROPERTIES_CHANGED, this.properties);\n\n        const audioLimitReached = this.properties['audio-limit-reached'] === 'true';\n        const videoLimitReached = this.properties['video-limit-reached'] === 'true';\n\n        if (this._audioSenderLimitReached !== audioLimitReached) {\n            this._audioSenderLimitReached = audioLimitReached;\n            this.eventEmitter.emit(JitsiConferenceEvents.AUDIO_UNMUTE_PERMISSIONS_CHANGED, audioLimitReached);\n            logger.info(`Audio unmute permissions set by Jicofo to ${audioLimitReached}`);\n        }\n\n        if (this._videoSenderLimitReached !== videoLimitReached) {\n            this._videoSenderLimitReached = videoLimitReached;\n            this.eventEmitter.emit(JitsiConferenceEvents.VIDEO_UNMUTE_PERMISSIONS_CHANGED, videoLimitReached);\n            logger.info(`Video unmute permissions set by Jicofo to ${videoLimitReached}`);\n        }\n\n        // Some of the properties need to be added to analytics events.\n        const analyticsKeys = [\n\n            // The number of jitsi-videobridge instances currently used for the\n            // conference.\n            'bridge-count'\n        ];\n\n        analyticsKeys.forEach(key => {\n            if (properties[key] !== undefined) {\n                Statistics.analytics.addPermanentProperties({\n                    [key.replace('-', '_')]: properties[key]\n                });\n            }\n        });\n    }\n};\n\n/**\n * Gets a conference property with a given key.\n *\n * @param {string} key - The key.\n * @returns {*} The value\n */\nJitsiConference.prototype.getProperty = function(key) {\n    return this.properties[key];\n};\n\n/**\n * Clears the deferred start P2P task if it has been scheduled.\n * @private\n */\nJitsiConference.prototype._maybeClearDeferredStartP2P = function() {\n    if (this.deferredStartP2PTask) {\n        logger.info('Cleared deferred start P2P task');\n        clearTimeout(this.deferredStartP2PTask);\n        this.deferredStartP2PTask = null;\n    }\n};\n\n/**\n * Removes from the conference remote tracks associated with the JVB\n * connection.\n * @private\n */\nJitsiConference.prototype._removeRemoteJVBTracks = function() {\n    this._removeRemoteTracks(\n        'JVB', this.jvbJingleSession.peerconnection.getRemoteTracks());\n};\n\n/**\n * Removes from the conference remote tracks associated with the P2P\n * connection.\n * @private\n */\nJitsiConference.prototype._removeRemoteP2PTracks = function() {\n    this._removeRemoteTracks(\n        'P2P', this.p2pJingleSession.peerconnection.getRemoteTracks());\n};\n\n/**\n * Generates fake \"remote track removed\" events for given Jingle session.\n * @param {string} sessionNickname the session's nickname which will appear in\n * log messages.\n * @param {Array<JitsiRemoteTrack>} remoteTracks the tracks that will be removed\n * @private\n */\nJitsiConference.prototype._removeRemoteTracks = function(sessionNickname, remoteTracks) {\n    for (const track of remoteTracks) {\n        logger.info(`Removing remote ${sessionNickname} track: ${track}`);\n        this.onRemoteTrackRemoved(track);\n    }\n};\n\n/**\n * Resumes media transfer over the JVB connection.\n * @private\n */\nJitsiConference.prototype._resumeMediaTransferForJvbConnection = function() {\n    logger.info('Resuming media transfer over the JVB connection...');\n    this.jvbJingleSession.setMediaTransferActive(true)\n        .then(() => {\n            logger.info('Resumed media transfer over the JVB connection!');\n        })\n        .catch(error => {\n            logger.error('Failed to resume media transfer over the JVB connection:', error);\n        });\n};\n\n/**\n * Sets new P2P status and updates some events/states hijacked from\n * the <tt>JitsiConference</tt>.\n * @param {boolean} newStatus the new P2P status value, <tt>true</tt> means that\n * P2P is now in use, <tt>false</tt> means that the JVB connection is now in use\n * @private\n */\nJitsiConference.prototype._setP2PStatus = function(newStatus) {\n    if (this.p2p === newStatus) {\n        logger.debug(`Called _setP2PStatus with the same status: ${newStatus}`);\n\n        return;\n    }\n    this.p2p = newStatus;\n    if (newStatus) {\n        logger.info('Peer to peer connection established!');\n\n        // When we end up in a valid P2P session need to reset the properties\n        // in case they have persisted, after session with another peer.\n        Statistics.analytics.addPermanentProperties({\n            p2pFailed: false,\n            forceJvb121: false\n        });\n\n        // Sync up video transfer active in case p2pJingleSession not existed\n        // when the lastN value was being adjusted.\n        const isVideoActive = this.getLastN() !== 0;\n\n        this.p2pJingleSession.setP2pVideoTransferActive(isVideoActive)\n            .catch(error => {\n                logger.error(`Failed to sync up P2P video transfer status (${isVideoActive}), ${error}`);\n            });\n    } else {\n        logger.info('Peer to peer connection closed!');\n    }\n\n    // Put the JVB connection on hold/resume\n    if (this.jvbJingleSession) {\n        this.statistics.sendConnectionResumeOrHoldEvent(\n            this.jvbJingleSession.peerconnection, !newStatus);\n    }\n\n    // Clear dtmfManager, so that it can be recreated with new connection\n    this.dtmfManager = null;\n\n    // Update P2P status\n    this.eventEmitter.emit(\n        JitsiConferenceEvents.P2P_STATUS,\n        this,\n        this.p2p);\n    this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED, this.getActiveMediaSession());\n\n    // Refresh connection interrupted/restored\n    this.eventEmitter.emit(\n        this.isConnectionInterrupted()\n            ? JitsiConferenceEvents.CONNECTION_INTERRUPTED\n            : JitsiConferenceEvents.CONNECTION_RESTORED);\n};\n\n/**\n * Starts new P2P session.\n * @param {string} remoteJid the JID of the remote participant\n * @private\n */\nJitsiConference.prototype._startP2PSession = function(remoteJid) {\n    this._maybeClearDeferredStartP2P();\n    if (this.p2pJingleSession) {\n        logger.error('P2P session already started!');\n\n        return;\n    }\n\n    this.isP2PConnectionInterrupted = false;\n    this.p2pJingleSession\n        = this.xmpp.connection.jingle.newP2PJingleSession(\n            this.room.myroomjid,\n            remoteJid);\n    logger.info(\n        'Created new P2P JingleSession', this.room.myroomjid, remoteJid);\n    this._sendConferenceJoinAnalyticsEvent();\n\n    this.p2pJingleSession.initialize(\n        this.room,\n        this.rtc,\n        this._signalingLayer,\n        {\n            ...this.options.config,\n            codecSettings: {\n                mediaType: MediaType.VIDEO,\n                preferred: this.codecSelection.p2pPreferredCodec,\n                disabled: this.codecSelection.p2pDisabledCodec\n            },\n            enableInsertableStreams: this.isE2EEEnabled() || FeatureFlags.isRunInLiteModeEnabled()\n        });\n\n    logger.info('Starting CallStats for P2P connection...');\n\n    let remoteID = Strophe.getResourceFromJid(this.p2pJingleSession.remoteJid);\n\n    const participant = this.participants.get(remoteID);\n\n    if (participant) {\n        remoteID = participant.getStatsID() || remoteID;\n    }\n\n    this.statistics.startCallStats(\n        this.p2pJingleSession.peerconnection,\n        remoteID);\n\n    const localTracks = this.getLocalTracks();\n\n    this.p2pJingleSession.invite(localTracks);\n};\n\n/**\n * Suspends media transfer over the JVB connection.\n * @private\n */\nJitsiConference.prototype._suspendMediaTransferForJvbConnection = function() {\n    logger.info('Suspending media transfer over the JVB connection...');\n    this.jvbJingleSession.setMediaTransferActive(false)\n        .then(() => {\n            logger.info('Suspended media transfer over the JVB connection !');\n        })\n        .catch(error => {\n            logger.error('Failed to suspend media transfer over the JVB connection:', error);\n        });\n};\n\n/**\n * Method when called will decide whether it's the time to start or stop\n * the P2P session.\n * @param {boolean} userLeftEvent if <tt>true</tt> it means that the call\n * originates from the user left event.\n * @private\n */\nJitsiConference.prototype._maybeStartOrStopP2P = function(userLeftEvent) {\n    if (!this.isP2PEnabled()\n            || this.isP2PTestModeEnabled()\n            || browser.isFirefox()\n            || browser.isWebKitBased()\n            || this.isE2EEEnabled()) {\n        logger.info('Auto P2P disabled');\n\n        return;\n    }\n    const peers = this.getParticipants();\n    const peerCount = peers.length;\n\n    // FIXME 1 peer and it must *support* P2P switching\n    const shouldBeInP2P = this._shouldBeInP2PMode();\n\n    // Clear deferred \"start P2P\" task\n    if (!shouldBeInP2P && this.deferredStartP2PTask) {\n        this._maybeClearDeferredStartP2P();\n    }\n\n    // Start peer to peer session\n    if (!this.p2pJingleSession && shouldBeInP2P) {\n        const peer = peerCount && peers[0];\n\n\n        const myId = this.myUserId();\n        const peersId = peer.getId();\n\n        if (myId > peersId) {\n            logger.debug(\n                'I\\'m the bigger peersId - '\n                + 'the other peer should start P2P', myId, peersId);\n\n            return;\n        } else if (myId === peersId) {\n            logger.error('The same IDs ? ', myId, peersId);\n\n            return;\n        }\n\n        const jid = peer.getJid();\n\n        if (userLeftEvent) {\n            if (this.deferredStartP2PTask) {\n                logger.error('Deferred start P2P task\\'s been set already!');\n\n                return;\n            }\n            logger.info(\n                `Will start P2P with: ${jid} after ${\n                    this.backToP2PDelay} seconds...`);\n            this.deferredStartP2PTask = setTimeout(\n                this._startP2PSession.bind(this, jid),\n                this.backToP2PDelay * 1000);\n        } else {\n            logger.info(`Will start P2P with: ${jid}`);\n            this._startP2PSession(jid);\n        }\n    } else if (this.p2pJingleSession && !shouldBeInP2P) {\n        logger.info(`Will stop P2P with: ${this.p2pJingleSession.remoteJid}`);\n\n        // Log that there will be a switch back to the JVB connection\n        if (this.p2pJingleSession.isInitiator && peerCount > 1) {\n            Statistics.sendAnalyticsAndLog(\n                createP2PEvent(ACTION_P2P_SWITCH_TO_JVB));\n        }\n        this._stopP2PSession();\n    }\n};\n\n/**\n * Tells whether or not this conference should be currently in the P2P mode.\n *\n * @private\n * @returns {boolean}\n */\nJitsiConference.prototype._shouldBeInP2PMode = function() {\n    const peers = this.getParticipants();\n    const peerCount = peers.length;\n    const hasBotPeer = peers.find(p => p.getBotType() === 'poltergeist' || p.hasFeature(FEATURE_JIGASI)) !== undefined;\n    const shouldBeInP2P = peerCount === 1 && !hasBotPeer;\n\n    logger.debug(`P2P? peerCount: ${peerCount}, hasBotPeer: ${hasBotPeer} => ${shouldBeInP2P}`);\n\n    return shouldBeInP2P;\n};\n\n/**\n * Stops the current P2P session.\n * @param {Object} options - Options for stopping P2P.\n * @param {string} options.reason - One of the Jingle \"reason\" element\n * names as defined by https://xmpp.org/extensions/xep-0166.html#def-reason\n * @param {string} options.reasonDescription - Text\n * description that will be included in the session terminate message\n * @param {boolean} requestRestart - Whether this is due to a session restart, in which case\n * media will not be resumed on the JVB.\n * @private\n */\nJitsiConference.prototype._stopP2PSession = function(options = {}) {\n    const {\n        reason = 'success',\n        reasonDescription = 'Turning off P2P session',\n        requestRestart = false\n    } = options;\n\n    if (!this.p2pJingleSession) {\n        logger.error('No P2P session to be stopped!');\n\n        return;\n    }\n\n    const wasP2PEstablished = this.isP2PActive();\n\n    // Swap remote tracks, but only if the P2P has been fully established\n    if (wasP2PEstablished) {\n        if (this.jvbJingleSession && !requestRestart) {\n            this._resumeMediaTransferForJvbConnection();\n        }\n\n        // Remove remote P2P tracks\n        this._removeRemoteP2PTracks();\n    }\n\n    // Stop P2P stats\n    logger.info('Stopping remote stats for P2P connection');\n    this.statistics.stopRemoteStats(this.p2pJingleSession.peerconnection);\n    logger.info('Stopping CallStats for P2P connection');\n    this.statistics.stopCallStats(this.p2pJingleSession.peerconnection);\n\n    this.p2pJingleSession.terminate(\n        () => {\n            logger.info('P2P session terminate RESULT');\n        },\n        error => {\n            // Because both initiator and responder are simultaneously\n            // terminating their JingleSessions in case of the 'to JVB switch'\n            // when 3rd participant joins, both will dispose their sessions and\n            // reply with 'item-not-found' (see strophe.jingle.js). We don't\n            // want to log this as an error since it's expected behaviour.\n            //\n            // We want them both to terminate, because in case of initiator's\n            // crash the responder would stay in P2P mode until ICE fails which\n            // could take up to 20 seconds.\n            //\n            // NOTE: whilst this is an error callback,  'success' as a reason is\n            // considered as graceful session terminate\n            // where both initiator and responder terminate their sessions\n            // simultaneously.\n            if (reason !== 'success') {\n                logger.error('An error occurred while trying to terminate P2P Jingle session', error);\n            }\n        }, {\n            reason,\n            reasonDescription,\n            sendSessionTerminate: this.room\n                && this.getParticipantById(\n                    Strophe.getResourceFromJid(this.p2pJingleSession.remoteJid))\n        });\n\n    this.p2pJingleSession = null;\n\n    // Update P2P status and other affected events/states\n    this._setP2PStatus(false);\n\n    if (wasP2PEstablished) {\n        // Add back remote JVB tracks\n        if (this.jvbJingleSession && !requestRestart) {\n            this._addRemoteJVBTracks();\n        } else {\n            logger.info('Not adding remote JVB tracks - no session yet');\n        }\n    }\n};\n\n/**\n * Updates room presence if needed and send the packet in case of a modification.\n * @param {JingleSessionPC} jingleSession the session firing the event, contains the peer connection which\n * tracks we will check.\n * @param {Object|null} ctx a context object we can distinguish multiple calls of the same pass of updating tracks.\n */\nJitsiConference.prototype._updateRoomPresence = function(jingleSession, ctx) {\n    if (!jingleSession) {\n        return;\n    }\n\n    // skips sending presence twice for the same pass of updating ssrcs\n    if (ctx) {\n        if (ctx.skip) {\n            return;\n        }\n        ctx.skip = true;\n    }\n\n    let presenceChanged = false;\n    let muteStatusChanged, videoTypeChanged;\n    const localTracks = jingleSession.peerconnection.getLocalTracks();\n\n    // Set presence for all the available local tracks.\n    for (const track of localTracks) {\n        muteStatusChanged = this._setTrackMuteStatus(track.getType(), track, track.isMuted());\n        if (track.getType() === MediaType.VIDEO) {\n            videoTypeChanged = this._setNewVideoType(track);\n        }\n        presenceChanged = presenceChanged || muteStatusChanged || videoTypeChanged;\n    }\n\n    presenceChanged && this.room.sendPresence();\n};\n\n/**\n * Checks whether or not the conference is currently in the peer to peer mode.\n * Being in peer to peer mode means that the direct connection has been\n * established and the P2P connection is being used for media transmission.\n * @return {boolean} <tt>true</tt> if in P2P mode or <tt>false</tt> otherwise.\n */\nJitsiConference.prototype.isP2PActive = function() {\n    return this.p2p;\n};\n\n/**\n * Returns the current ICE state of the P2P connection.\n * NOTE: method is used by the jitsi-meet-torture tests.\n * @return {string|null} an ICE state or <tt>null</tt> if there's currently\n * no P2P connection.\n */\nJitsiConference.prototype.getP2PConnectionState = function() {\n    if (this.isP2PActive()) {\n        return this.p2pJingleSession.peerconnection.getConnectionState();\n    }\n\n    return null;\n};\n\n/**\n * Configures the peerconnection so that a given framre rate can be achieved for desktop share.\n *\n * @param {number} maxFps The capture framerate to be used for desktop tracks.\n * @returns {boolean} true if the operation is successful, false otherwise.\n */\nJitsiConference.prototype.setDesktopSharingFrameRate = function(maxFps) {\n    if (typeof maxFps !== 'number' || isNaN(maxFps)) {\n        logger.error(`Invalid value ${maxFps} specified for desktop capture frame rate`);\n\n        return false;\n    }\n\n    this._desktopSharingFrameRate = maxFps;\n\n    // Enable or disable simulcast for plan-b screensharing based on the capture fps.\n    this.jvbJingleSession && this.jvbJingleSession.peerconnection.setDesktopSharingFrameRate(maxFps);\n\n    // Set the capture rate for desktop sharing.\n    this.rtc.setDesktopSharingFrameRate(maxFps);\n\n    return true;\n};\n\n/**\n * Manually starts new P2P session (should be used only in the tests).\n */\nJitsiConference.prototype.startP2PSession = function() {\n    const peers = this.getParticipants();\n\n    // Start peer to peer session\n    if (peers.length === 1) {\n        const peerJid = peers[0].getJid();\n\n        this._startP2PSession(peerJid);\n    } else {\n        throw new Error(\n            'There must be exactly 1 participant to start the P2P session !');\n    }\n};\n\n/**\n * Manually stops the current P2P session (should be used only in the tests).\n */\nJitsiConference.prototype.stopP2PSession = function(options) {\n    this._stopP2PSession(options);\n};\n\n/**\n * Get a summary of how long current participants have been the dominant speaker\n * @returns {object}\n */\nJitsiConference.prototype.getSpeakerStats = function() {\n    return this.speakerStatsCollector.getStats();\n};\n\n/**\n * Sends a face landmarks object to the xmpp server.\n * @param {Object} payload\n */\nJitsiConference.prototype.sendFaceLandmarks = function(payload) {\n    if (payload.faceExpression) {\n        this.xmpp.sendFaceLandmarksEvent(this.room.roomjid, payload);\n    }\n};\n\n/**\n * Sets the constraints for the video that is requested from the bridge.\n *\n * @param {Object} videoConstraints The constraints which are specified in the\n * following format. The message updates the fields that are present and leaves the\n * rest unchanged on the bridge. Therefore, any field that is not applicable anymore\n * should be cleared by passing an empty object or list (whatever is applicable).\n * {\n *      'lastN': 20,\n *      'selectedEndpoints': ['A', 'B', 'C'],\n *      'onStageEndpoints': ['A'],\n *      'defaultConstraints': { 'maxHeight': 180 },\n *      'constraints': {\n *          'A': { 'maxHeight': 720 }\n *      }\n * }\n */\nJitsiConference.prototype.setReceiverConstraints = function(videoConstraints) {\n    this.receiveVideoController.setReceiverConstraints(videoConstraints);\n};\n\n/**\n * Sets the assumed bandwidth bps for the video that is requested from the bridge.\n *\n * @param {Number} assumedBandwidthBps - The bandwidth value expressed in bits per second.\n */\nJitsiConference.prototype.setAssumedBandwidthBps = function(assumedBandwidthBps) {\n    this.receiveVideoController.setAssumedBandwidthBps(assumedBandwidthBps);\n};\n\n/**\n * Sets the maximum video size the local participant should receive from remote\n * participants.\n *\n * @param {number} maxFrameHeight - the maximum frame height, in pixels,\n * this receiver is willing to receive.\n * @returns {void}\n */\nJitsiConference.prototype.setReceiverVideoConstraint = function(maxFrameHeight) {\n    this.receiveVideoController.setPreferredReceiveMaxFrameHeight(maxFrameHeight);\n};\n\n/**\n * Sets the maximum video size the local participant should send to remote\n * participants.\n * @param {number} maxFrameHeight - The user preferred max frame height.\n * @returns {Promise} promise that will be resolved when the operation is\n * successful and rejected otherwise.\n */\nJitsiConference.prototype.setSenderVideoConstraint = function(maxFrameHeight) {\n    return this.sendVideoController.setPreferredSendMaxFrameHeight(maxFrameHeight);\n};\n\n/**\n * Creates a video SIP GW session and returns it if service is enabled. Before\n * creating a session one need to check whether video SIP GW service is\n * available in the system {@link JitsiConference.isVideoSIPGWAvailable}. Even\n * if there are available nodes to serve this request, after creating the\n * session those nodes can be taken and the request about using the\n * created session can fail.\n *\n * @param {string} sipAddress - The sip address to be used.\n * @param {string} displayName - The display name to be used for this session.\n * @returns {JitsiVideoSIPGWSession|Error} Returns null if conference is not\n * initialised and there is no room.\n */\nJitsiConference.prototype.createVideoSIPGWSession = function(sipAddress, displayName) {\n    if (!this.room) {\n        return new Error(VideoSIPGWConstants.ERROR_NO_CONNECTION);\n    }\n\n    return this.videoSIPGWHandler\n        .createVideoSIPGWSession(sipAddress, displayName);\n};\n\n/**\n * Sends a conference.join analytics event.\n *\n * @returns {void}\n */\nJitsiConference.prototype._sendConferenceJoinAnalyticsEvent = function() {\n    const meetingId = this.getMeetingUniqueId();\n\n    if (this._conferenceJoinAnalyticsEventSent || !meetingId || this.getActivePeerConnection() === null) {\n        return;\n    }\n\n    Statistics.sendAnalytics(createConferenceEvent('joined', {\n        meetingId,\n        participantId: `${meetingId}.${this._statsCurrentId}`\n    }));\n    this._conferenceJoinAnalyticsEventSent = Date.now();\n};\n\n/**\n * Sends conference.left analytics event.\n * @private\n */\nJitsiConference.prototype._sendConferenceLeftAnalyticsEvent = function() {\n    const meetingId = this.getMeetingUniqueId();\n\n    if (!meetingId || !this._conferenceJoinAnalyticsEventSent) {\n\n        return;\n    }\n\n    Statistics.sendAnalytics(createConferenceEvent('left', {\n        meetingId,\n        participantId: `${meetingId}.${this._statsCurrentId}`,\n        stats: {\n            duration: Math.floor((Date.now() - this._conferenceJoinAnalyticsEventSent) / 1000),\n            perf: this.getPerformanceStats()\n        }\n    }));\n};\n\n/**\n * Restarts all active media sessions.\n *\n * @returns {void}\n */\nJitsiConference.prototype._restartMediaSessions = function() {\n    if (this.p2pJingleSession) {\n        this._stopP2PSession({\n            reasonDescription: 'restart',\n            requestRestart: true\n        });\n    }\n\n    if (this.jvbJingleSession) {\n        this.jvbJingleSession.terminate(\n            null /* success callback => we don't care */,\n            error => {\n                logger.warn('An error occurred while trying to terminate the JVB session', error);\n            }, {\n                reason: 'success',\n                reasonDescription: 'restart required',\n                requestRestart: true,\n                sendSessionTerminate: true\n            });\n    }\n\n    this._maybeStartOrStopP2P(false);\n};\n\n/**\n * Returns whether End-To-End encryption is enabled.\n *\n * @returns {boolean}\n */\nJitsiConference.prototype.isE2EEEnabled = function() {\n    return Boolean(this._e2eEncryption && this._e2eEncryption.isEnabled());\n};\n\n/**\n * Returns whether End-To-End encryption is supported. Note that not all participants\n * in the conference may support it.\n *\n * @returns {boolean}\n */\nJitsiConference.prototype.isE2EESupported = function() {\n    return E2EEncryption.isSupported(this.options.config);\n};\n\n/**\n * Enables / disables End-to-End encryption.\n *\n * @param {boolean} enabled whether to enable E2EE or not.\n * @returns {void}\n */\nJitsiConference.prototype.toggleE2EE = function(enabled) {\n    if (!this.isE2EESupported()) {\n        logger.warn('Cannot enable / disable E2EE: platform is not supported.');\n\n        return;\n    }\n\n    this._e2eEncryption.setEnabled(enabled);\n};\n\n/**\n * Sets the key and index for End-to-End encryption.\n *\n * @param {CryptoKey} [keyInfo.encryptionKey] - encryption key.\n * @param {Number} [keyInfo.index] - the index of the encryption key.\n * @returns {void}\n */\nJitsiConference.prototype.setMediaEncryptionKey = function(keyInfo) {\n    this._e2eEncryption.setEncryptionKey(keyInfo);\n};\n\n/**\n * Starts the participant verification process.\n *\n * @param {string} participantId The participant which will be marked as verified.\n * @returns {void}\n */\nJitsiConference.prototype.startVerification = function(participantId) {\n    const participant = this.getParticipantById(participantId);\n\n    if (!participant) {\n        return;\n    }\n\n    this._e2eEncryption.startVerification(participant);\n};\n\n/**\n * Marks the given participant as verified. After this is done, MAC verification will\n * be performed and an event will be emitted with the result.\n *\n * @param {string} participantId The participant which will be marked as verified.\n * @param {boolean} isVerified - whether the verification was succesfull.\n * @returns {void}\n */\nJitsiConference.prototype.markParticipantVerified = function(participantId, isVerified) {\n    const participant = this.getParticipantById(participantId);\n\n    if (!participant) {\n        return;\n    }\n\n    this._e2eEncryption.markParticipantVerified(participant, isVerified);\n};\n\n/**\n * Returns <tt>true</tt> if lobby support is enabled in the backend.\n *\n * @returns {boolean} whether lobby is supported in the backend.\n */\nJitsiConference.prototype.isLobbySupported = function() {\n    return Boolean(this.room && this.room.getLobby().isSupported());\n};\n\n/**\n * Returns <tt>true</tt> if the room has members only enabled.\n *\n * @returns {boolean} whether conference room is members only.\n */\nJitsiConference.prototype.isMembersOnly = function() {\n    return Boolean(this.room && this.room.membersOnlyEnabled);\n};\n\n/**\n * Enables lobby by moderators\n *\n * @returns {Promise} resolves when lobby room is joined or rejects with the error.\n */\nJitsiConference.prototype.enableLobby = function() {\n    if (this.room && this.isModerator()) {\n        return this.room.getLobby().enable();\n    }\n\n    return Promise.reject(\n        new Error('The conference not started or user is not moderator'));\n};\n\n/**\n * Disabled lobby by moderators\n *\n * @returns {void}\n */\nJitsiConference.prototype.disableLobby = function() {\n    if (this.room && this.isModerator()) {\n        this.room.getLobby().disable();\n    } else {\n        logger.warn(`Failed to disable lobby, ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator'}`);\n    }\n};\n\n/**\n * Joins the lobby room with display name and optional email or with a shared password to skip waiting.\n *\n * @param {string} displayName Display name should be set to show it to moderators.\n * @param {string} email Optional email is used to present avatar to the moderator.\n * @returns {Promise<never>}\n */\nJitsiConference.prototype.joinLobby = function(displayName, email) {\n    if (this.room) {\n        return this.room.getLobby().join(displayName, email);\n    }\n\n    return Promise.reject(new Error('The conference not started'));\n};\n\n/**\n * Gets the local id for a participant in a lobby room.\n * Returns undefined when current participant is not in the lobby room.\n * This is used for lobby room private chat messages.\n *\n * @returns {string}\n */\nJitsiConference.prototype.myLobbyUserId = function() {\n    if (this.room) {\n        return this.room.getLobby().getLocalId();\n    }\n};\n\n/**\n * Sends a message to a lobby room.\n * When id is specified it sends a private message.\n * Otherwise it sends the message to all moderators.\n * @param {message} Object The message to send\n * @param {string} id The participant id.\n *\n * @returns {void}\n */\nJitsiConference.prototype.sendLobbyMessage = function(message, id) {\n    if (this.room) {\n        if (id) {\n            return this.room.getLobby().sendPrivateMessage(id, message);\n        }\n\n        return this.room.getLobby().sendMessage(message);\n    }\n};\n\n/**\n * Adds a message listener to the lobby room\n * @param {Function} listener The listener function,\n * called when a new message is received in the lobby room.\n *\n * @returns {Function} Handler returned to be able to remove it later.\n */\nJitsiConference.prototype.addLobbyMessageListener = function(listener) {\n    if (this.room) {\n        return this.room.getLobby().addMessageListener(listener);\n    }\n};\n\n/**\n * Removes a message handler from the lobby room\n * @param {Function} handler The handler function  to remove.\n *\n * @returns {void}\n */\nJitsiConference.prototype.removeLobbyMessageHandler = function(handler) {\n    if (this.room) {\n        return this.room.getLobby().removeMessageHandler(handler);\n    }\n};\n\n/**\n * Denies an occupant in the lobby room access to the conference.\n * @param {string} id The participant id.\n */\nJitsiConference.prototype.lobbyDenyAccess = function(id) {\n    if (this.room) {\n        this.room.getLobby().denyAccess(id);\n    }\n};\n\n/**\n * Approves the request to join the conference to a participant waiting in the lobby.\n *\n * @param {string} id The participant id.\n */\nJitsiConference.prototype.lobbyApproveAccess = function(id) {\n    if (this.room) {\n        this.room.getLobby().approveAccess(id);\n    }\n};\n\n/**\n * Returns <tt>true</tt> if AV Moderation support is enabled in the backend.\n *\n * @returns {boolean} whether AV Moderation is supported in the backend.\n */\nJitsiConference.prototype.isAVModerationSupported = function() {\n    return Boolean(this.room && this.room.getAVModeration().isSupported());\n};\n\n/**\n * Enables AV Moderation.\n * @param {MediaType} mediaType \"audio\" or \"video\"\n */\nJitsiConference.prototype.enableAVModeration = function(mediaType) {\n    if (this.room && this.isModerator()\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\n        this.room.getAVModeration().enable(true, mediaType);\n    } else {\n        logger.warn(`Failed to enable AV moderation, ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\n    }\n};\n\n/**\n * Disables AV Moderation.\n * @param {MediaType} mediaType \"audio\" or \"video\"\n */\nJitsiConference.prototype.disableAVModeration = function(mediaType) {\n    if (this.room && this.isModerator()\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\n        this.room.getAVModeration().enable(false, mediaType);\n    } else {\n        logger.warn(`Failed to disable AV moderation, ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\n    }\n};\n\n/**\n * Approve participant access to certain media, allows unmuting audio or video.\n *\n * @param {MediaType} mediaType \"audio\" or \"video\"\n * @param id the id of the participant.\n */\nJitsiConference.prototype.avModerationApprove = function(mediaType, id) {\n    if (this.room && this.isModerator()\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\n\n        const participant = this.getParticipantById(id);\n\n        if (!participant) {\n            return;\n        }\n\n        this.room.getAVModeration().approve(mediaType, participant.getJid());\n    } else {\n        logger.warn(`AV moderation approve skipped , ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\n    }\n};\n\n/**\n * Reject participant access to certain media, blocks unmuting audio or video.\n *\n * @param {MediaType} mediaType \"audio\" or \"video\"\n * @param id the id of the participant.\n */\nJitsiConference.prototype.avModerationReject = function(mediaType, id) {\n    if (this.room && this.isModerator()\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\n\n        const participant = this.getParticipantById(id);\n\n        if (!participant) {\n            return;\n        }\n\n        this.room.getAVModeration().reject(mediaType, participant.getJid());\n    } else {\n        logger.warn(`AV moderation reject skipped , ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\n    }\n};\n\n/**\n * Returns the breakout rooms manager object.\n *\n * @returns {Object} the breakout rooms manager.\n */\nJitsiConference.prototype.getBreakoutRooms = function() {\n    return this.room?.getBreakoutRooms();\n};\n\n/**\n * Returns the metadata handler object.\n *\n * @returns {Object} the room metadata handler.\n */\nJitsiConference.prototype.getMetadataHandler = function() {\n    return this.room?.getMetadataHandler();\n};\n","import JitsiConference from './JitsiConference';\nimport * as JitsiConnectionEvents from './JitsiConnectionEvents';\nimport Statistics from './modules/statistics/statistics';\nimport XMPP from './modules/xmpp/xmpp';\nimport {\n    CONNECTION_DISCONNECTED as ANALYTICS_CONNECTION_DISCONNECTED,\n    createConnectionFailedEvent\n} from './service/statistics/AnalyticsEvents';\n\n/**\n * Creates a new connection object for the Jitsi Meet server side video\n * conferencing service. Provides access to the JitsiConference interface.\n * @param appID identification for the provider of Jitsi Meet video conferencing\n * services.\n * @param token the JWT token used to authenticate with the server(optional)\n * @param options Object with properties / settings related to connection with\n * the server.\n * @constructor\n */\nexport default function JitsiConnection(appID, token, options) {\n    this.appID = appID;\n    this.token = token;\n    this.options = options;\n    this.xmpp = new XMPP(options, token);\n\n    /* eslint-disable max-params */\n    this.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED,\n        (errType, msg, credentials, details) => {\n            Statistics.sendAnalyticsAndLog(\n                createConnectionFailedEvent(errType, msg, details));\n        });\n    /* eslint-enable max-params */\n\n    this.addEventListener(JitsiConnectionEvents.CONNECTION_DISCONNECTED,\n        msg => {\n            // we can see disconnects from normal tab closing of the browser\n            // and then there are no msgs, but we want to log only disconnects\n            // when there is real error\n            // XXX Do we need the difference in handling between the log and\n            // analytics event here?\n            if (msg) {\n                Statistics.sendAnalytics(\n                    ANALYTICS_CONNECTION_DISCONNECTED,\n                    { message: msg });\n            }\n            Statistics.sendLog(\n                JSON.stringify(\n                    {\n                        id: ANALYTICS_CONNECTION_DISCONNECTED,\n                        msg\n                    }));\n        });\n}\n\n/**\n * Connect the client with the server.\n * @param options {object} connecting options\n * (for example authentications parameters).\n */\nJitsiConnection.prototype.connect = function(options = {}) {\n    this.xmpp.connect(options.id, options.password);\n};\n\n/**\n * Attach to existing connection. Can be used for optimizations. For example:\n * if the connection is created on the server we can attach to it and start\n * using it.\n *\n * @param options {object} connecting options - rid, sid and jid.\n */\nJitsiConnection.prototype.attach = function(options) {\n    this.xmpp.attach(options);\n};\n\n/**\n * Disconnect the client from the server.\n * @returns {Promise} - Resolves when the disconnect process is finished or rejects with an error.\n */\nJitsiConnection.prototype.disconnect = function(...args) {\n    // XXX Forward any arguments passed to JitsiConnection.disconnect to\n    // XMPP.disconnect. For example, the caller of JitsiConnection.disconnect\n    // may optionally pass the event which triggered the disconnect in order to\n    // provide the implementation with finer-grained context.\n    return this.xmpp.disconnect(...args);\n};\n\n/**\n * Returns the jid of the participant associated with the XMPP connection.\n *\n * @returns {string} The jid of the participant.\n */\nJitsiConnection.prototype.getJid = function() {\n    return this.xmpp.getJid();\n};\n\n/**\n * This method allows renewal of the tokens if they are expiring.\n * @param token the new token.\n */\nJitsiConnection.prototype.setToken = function(token) {\n    this.token = token;\n};\n\n/**\n * Creates and joins new conference.\n * @param name the name of the conference; if null - a generated name will be\n * provided from the api\n * @param options Object with properties / settings related to the conference\n * that will be created.\n * @returns {JitsiConference} returns the new conference object.\n */\nJitsiConnection.prototype.initJitsiConference = function(name, options) {\n    return new JitsiConference({\n        name,\n        config: options,\n        connection: this\n    });\n};\n\n/**\n * Subscribes the passed listener to the event.\n * @param event {JitsiConnectionEvents} the connection event.\n * @param listener {Function} the function that will receive the event\n */\nJitsiConnection.prototype.addEventListener = function(event, listener) {\n    this.xmpp.addListener(event, listener);\n};\n\n/**\n * Unsubscribes the passed handler.\n * @param event {JitsiConnectionEvents} the connection event.\n * @param listener {Function} the function that will receive the event\n */\nJitsiConnection.prototype.removeEventListener = function(event, listener) {\n    this.xmpp.removeListener(event, listener);\n};\n\n/**\n * Returns measured connectionTimes.\n */\nJitsiConnection.prototype.getConnectionTimes = function() {\n    return this.xmpp.connectionTimes;\n};\n\n/**\n * Adds new feature to the list of supported features for the local\n * participant.\n * @param {String} feature the name of the feature.\n * @param {boolean} submit if true - the new list of features will be\n * immediately submitted to the others.\n */\nJitsiConnection.prototype.addFeature = function(feature, submit = false) {\n    this.xmpp.caps.addFeature(feature, submit, true);\n};\n\n/**\n * Removes a feature from the list of supported features for the local\n * participant\n * @param {String} feature the name of the feature.\n * @param {boolean} submit if true - the new list of features will be\n * immediately submitted to the others.\n */\nJitsiConnection.prototype.removeFeature = function(feature, submit = false) {\n    this.xmpp.caps.removeFeature(feature, submit, true);\n};\n\n/**\n * Get object with internal logs.\n */\nJitsiConnection.prototype.getLogs = function() {\n    const data = this.xmpp.getJingleLog();\n\n    const metadata = {};\n\n    metadata.time = new Date();\n    metadata.url = window.location.href;\n    metadata.ua = navigator.userAgent;\n\n    const log = this.xmpp.getXmppLog();\n\n    if (log) {\n        metadata.xmpp = log;\n    }\n\n    data.metadata = metadata;\n\n    return data;\n};\n","/**\n * The events for the media devices.\n */\n\nexport enum JitsiMediaDevicesEvents {\n    /**\n     * Indicates that the list of available media devices has been changed. The\n     * event provides the following parameters to its listeners:\n     *\n     * @param {MediaDeviceInfo[]} devices - array of MediaDeviceInfo or\n     *  MediaDeviceInfo-like objects that are currently connected.\n     *  @see https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo\n     */\n    DEVICE_LIST_CHANGED = 'mediaDevices.devicechange',\n\n    /**\n     * Event emitted when the user granted/blocked a permission for the camera / mic.\n     * Used to keep track of the granted permissions on browsers which don't\n     * support the Permissions API.\n     */\n    PERMISSIONS_CHANGED = 'rtc.permissions_changed',\n\n    /**\n     * Indicates that the environment is currently showing permission prompt to\n     * access camera and/or microphone. The event provides the following\n     * parameters to its listeners:\n     *\n     * @param {'chrome'|'opera'|'firefox'|'safari'|'nwjs'\n     *  |'react-native'|'android'} environmentType - type of browser or\n     *  other execution environment.\n     */\n    PERMISSION_PROMPT_IS_SHOWN = 'mediaDevices.permissionPromptIsShown',\n\n    SLOW_GET_USER_MEDIA = 'mediaDevices.slowGetUserMedia'\n};\n\n// exported for backward compatibility\nexport const DEVICE_LIST_CHANGED = JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED;\nexport const PERMISSIONS_CHANGED = JitsiMediaDevicesEvents.PERMISSIONS_CHANGED;\nexport const PERMISSION_PROMPT_IS_SHOWN = JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN;\nexport const SLOW_GET_USER_MEDIA = JitsiMediaDevicesEvents.SLOW_GET_USER_MEDIA;\n","import EventEmitter from 'events';\n\nimport * as JitsiMediaDevicesEvents from './JitsiMediaDevicesEvents';\nimport RTC from './modules/RTC/RTC';\nimport browser from './modules/browser';\nimport Statistics from './modules/statistics/statistics';\nimport { MediaType } from './service/RTC/MediaType';\nimport RTCEvents from './service/RTC/RTCEvents';\n\nconst AUDIO_PERMISSION_NAME = 'microphone';\nconst PERMISSION_GRANTED_STATUS = 'granted';\nconst VIDEO_PERMISSION_NAME = 'camera';\n\n/**\n * Media devices utilities for Jitsi.\n */\nclass JitsiMediaDevices {\n    /**\n     * Initializes a {@code JitsiMediaDevices} object. There will be a single\n     * instance of this class.\n     */\n    constructor() {\n        this._eventEmitter = new EventEmitter();\n        this._permissions = {};\n\n        RTC.addListener(\n            RTCEvents.DEVICE_LIST_CHANGED,\n            devices =>\n                this._eventEmitter.emit(\n                    JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED,\n                    devices));\n        RTC.addListener(\n            RTCEvents.DEVICE_LIST_AVAILABLE,\n            devices =>\n                this._logOutputDevice(\n                    this.getAudioOutputDevice(),\n                    devices));\n\n        // We would still want to update the permissions cache in case the permissions API is not supported.\n        RTC.addListener(\n            RTCEvents.PERMISSIONS_CHANGED,\n            permissions => this._handlePermissionsChange(permissions));\n\n        // Test if the W3C Permissions API is implemented and the 'camera' and 'microphone' permissions are\n        // implemented. If supported add onchange listeners.\n        this._permissionsApiSupported = new Promise(resolve => {\n            if (!navigator.permissions) {\n                resolve(false);\n\n                return;\n            }\n\n            const self = this;\n\n            const promises = [];\n\n            promises.push(navigator.permissions.query({ name: VIDEO_PERMISSION_NAME })\n                .then(status => {\n                    this._handlePermissionsChange({\n                        [MediaType.VIDEO]: this._parsePermissionState(status)\n                    });\n                    status.onchange = function() {\n                        try {\n                            self._handlePermissionsChange({\n                                [MediaType.VIDEO]: self._parsePermissionState(this)\n                            });\n                        } catch (error) {\n                            // Nothing to do.\n                        }\n                    };\n\n                    return true;\n                })\n                .catch(() => false));\n\n            promises.push(navigator.permissions.query({ name: AUDIO_PERMISSION_NAME })\n                .then(status => {\n                    this._handlePermissionsChange({\n                        [MediaType.AUDIO]: this._parsePermissionState(status)\n                    });\n                    status.onchange = function() {\n                        try {\n                            self._handlePermissionsChange({\n                                [MediaType.AUDIO]: self._parsePermissionState(this)\n                            });\n                        } catch (error) {\n                            // Nothing to do.\n                        }\n                    };\n\n                    return true;\n                })\n                .catch(() => false));\n\n            Promise.all(promises).then(results => resolve(results.every(supported => supported)));\n\n        });\n    }\n\n\n    /**\n     * Parses a PermissionState object and returns true for granted and false otherwise.\n     *\n     * @param {PermissionState} permissionStatus - The PermissionState object retrieved from the Permissions API.\n     * @returns {boolean} - True for granted and false for denied.\n     * @throws {TypeError}\n     */\n    _parsePermissionState(permissionStatus = {}) {\n        // The status attribute is deprecated, and state\n        // should be used instead, but check both for now\n        // for backwards compatibility.\n        const status = permissionStatus.state || permissionStatus.status;\n\n        if (typeof status !== 'string') {\n            throw new TypeError();\n        }\n\n        return status === PERMISSION_GRANTED_STATUS;\n    }\n\n    /**\n     * Updates the local granted/denied permissions cache. A permissions might be\n     * granted, denied, or undefined. This is represented by having its media\n     * type key set to {@code true} or {@code false} respectively.\n     *\n     * @param {Object} permissions - Object with the permissions.\n     */\n    _handlePermissionsChange(permissions) {\n        const hasPermissionsChanged\n            = [ MediaType.AUDIO, MediaType.VIDEO ]\n                .some(type => type in permissions && permissions[type] !== this._permissions[type]);\n\n        if (hasPermissionsChanged) {\n            this._permissions = {\n                ...this._permissions,\n                ...permissions\n            };\n            this._eventEmitter.emit(JitsiMediaDevicesEvents.PERMISSIONS_CHANGED, this._permissions);\n\n            if (this._permissions[MediaType.AUDIO] || this._permissions[MediaType.VIDEO]) {\n                // Triggering device list update when the permissiions are granted in order to update\n                // the labels the devices.\n                // eslint-disable-next-line no-empty-function\n                this.enumerateDevices(() => {});\n            }\n        }\n    }\n\n    /**\n     * Gathers data and sends it to statistics.\n     * @param deviceID the device id to log\n     * @param devices list of devices\n     */\n    _logOutputDevice(deviceID, devices) {\n        const device\n            = devices.find(\n                d => d.kind === 'audiooutput' && d.deviceId === deviceID);\n\n        if (device) {\n            Statistics.sendActiveDeviceListEvent(\n                RTC.getEventDataForActiveDevice(device));\n        }\n    }\n\n    /**\n     * Executes callback with list of media devices connected.\n     * @param {function} callback\n     */\n    enumerateDevices(callback) {\n        RTC.enumerateDevices(callback);\n    }\n\n    /**\n     * Checks if its possible to enumerate available cameras/micropones.\n     * @returns {Promise<boolean>} a Promise which will be resolved only once\n     * the WebRTC stack is ready, either with true if the device listing is\n     * available available or with false otherwise.\n     */\n    isDeviceListAvailable() {\n        return RTC.isDeviceListAvailable();\n    }\n\n    /**\n     * Returns true if changing the input (camera / microphone) or output\n     * (audio) device is supported and false if not.\n     * @param {string} [deviceType] - type of device to change. Default is\n     *      undefined or 'input', 'output' - for audio output device change.\n     * @returns {boolean} true if available, false otherwise.\n     */\n    isDeviceChangeAvailable(deviceType) {\n        return RTC.isDeviceChangeAvailable(deviceType);\n    }\n\n    /**\n     * Checks if the permission for the given device was granted.\n     *\n     * @param {'audio'|'video'} [type] - type of devices to check,\n     *      undefined stands for both 'audio' and 'video' together\n     * @returns {Promise<boolean>}\n     */\n    isDevicePermissionGranted(type) {\n        return new Promise(resolve => {\n            // Shortcut: first check if we already know the permission was\n            // granted.\n            if (type in this._permissions) {\n                resolve(this._permissions[type]);\n\n                return;\n            }\n\n            // Check using the Permissions API.\n            this._permissionsApiSupported.then(supported => {\n                if (!supported) {\n                    resolve(false);\n\n                    return;\n                }\n\n                const promises = [];\n\n                switch (type) {\n                case MediaType.VIDEO:\n                    promises.push(\n                        navigator.permissions.query({\n                            name: VIDEO_PERMISSION_NAME\n                        }));\n                    break;\n                case MediaType.AUDIO:\n                    promises.push(\n                        navigator.permissions.query({\n                            name: AUDIO_PERMISSION_NAME\n                        }));\n                    break;\n                default:\n                    promises.push(\n                        navigator.permissions.query({\n                            name: VIDEO_PERMISSION_NAME\n                        }));\n                    promises.push(\n                        navigator.permissions.query({\n                            name: AUDIO_PERMISSION_NAME\n                        }));\n                }\n\n                Promise.all(promises).then(\n                    results => resolve(results.every(permissionStatus => {\n                        try {\n                            return this._parsePermissionState(permissionStatus);\n                        } catch {\n                            return false;\n                        }\n                    })),\n                    () => resolve(false)\n                );\n            });\n        });\n    }\n\n    /**\n     * Returns true if it is possible to be simultaneously capturing audio from more than one device.\n     *\n     * @returns {boolean}\n     */\n    isMultipleAudioInputSupported() {\n        return !(\n            (browser.isFirefox() && browser.isVersionLessThan('101'))\n            || browser.isIosBrowser()\n        );\n    }\n\n    /**\n     * Returns currently used audio output device id, 'default' stands\n     * for default device\n     * @returns {string}\n     */\n    getAudioOutputDevice() {\n        return RTC.getAudioOutputDevice();\n    }\n\n    /**\n     * Sets current audio output device.\n     * @param {string} deviceId - id of 'audiooutput' device from\n     *      navigator.mediaDevices.enumerateDevices(), 'default' is for\n     *      default device\n     * @returns {Promise} - resolves when audio output is changed, is rejected\n     *      otherwise\n     */\n    setAudioOutputDevice(deviceId) {\n        const availableDevices = RTC.getCurrentlyAvailableMediaDevices();\n\n        if (availableDevices.length > 0) {\n            // if we have devices info report device to stats\n            // normally this will not happen on startup as this method is called\n            // too early. This will happen only on user selection of new device\n            this._logOutputDevice(\n                deviceId, RTC.getCurrentlyAvailableMediaDevices());\n        }\n\n        return RTC.setAudioOutputDevice(deviceId);\n    }\n\n    /**\n     * Adds an event handler.\n     * @param {string} event - event name\n     * @param {function} handler - event handler\n     */\n    addEventListener(event, handler) {\n        this._eventEmitter.addListener(event, handler);\n    }\n\n    /**\n     * Removes event handler.\n     * @param {string} event - event name\n     * @param {function} handler - event handler\n     */\n    removeEventListener(event, handler) {\n        this._eventEmitter.removeListener(event, handler);\n    }\n\n    /**\n     * Emits an event.\n     * @param {string} event - event name\n     */\n    emitEvent(event, ...args) {\n        this._eventEmitter.emit(event, ...args);\n    }\n}\n\nexport default new JitsiMediaDevices();\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\nimport RTC from '../RTC/RTC';\nimport Statistics from '../statistics/statistics';\n\n\nconst logger = getLogger(__filename);\n\n// If after 3000 ms the detector did not find any active devices consider that there aren't any usable ones available\n// i.e. audioLevel > 0.008\nconst DETECTION_TIMEOUT = 3000;\n\n\n/**\n * Go through all audio devices on the system and return one that is active, i.e. has audio signal.\n *\n * @returns Promise<Object> - Object containing information about the found device.\n */\nexport default function getActiveAudioDevice() {\n\n    return new Promise(resolve => {\n        RTC.enumerateDevices(devices => {\n            const audioDevices = devices.filter(device => device.kind === 'audioinput');\n            const devicePromiseArray = [];\n\n\n            for (const micDevice of audioDevices) {\n                const devicePromise = RTC.obtainAudioAndVideoPermissions({ devices: [ 'audio' ],\n                    micDeviceId: micDevice.deviceId }).then(tracks => {\n\n                    // We expect a single device to be available when obtained from obtainAudioAndVideoPermissions\n                    // that's  why only take p.value[0].\n                    const track = tracks[0];\n\n                    Statistics.startLocalStats(track, track.setAudioLevel.bind(track));\n\n                    return track;\n                });\n\n                devicePromiseArray.push(devicePromise);\n            }\n\n            Promise.allSettled(devicePromiseArray).then(outcomeArray => {\n                const successfulPromises = outcomeArray.filter(p => p.status === 'fulfilled');\n                const rejectedPromises = outcomeArray.filter(p => p.status === 'rejected');\n\n\n                const availableDevices = successfulPromises.map(p => p.value);\n                const rejectReasons = rejectedPromises.map(p => p.value);\n\n                for (const reason of rejectReasons) {\n                    logger.error('Failed to acquire audio device with error: ', reason);\n                }\n\n                // Setup event handlers for monitored devices.\n                for (const device of availableDevices) {\n                    device.on(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevel => {\n                        // This is a very naive approach but works, a more accurate one would be to use rnnoise in\n                        // order to limit  the number of false positives. The 0.008 constant is due to how\n                        // LocalStatsCollector from lib-jitsi-meet publishes audio-levels, in this case 0.008 denotes //\n                        // no input.\n                        if (audioLevel > 0.008) {\n                            stopActiveDevices(availableDevices);\n                            resolve({ deviceId: device.deviceId,\n                                deviceLabel: device.track.label });\n                        }\n                    });\n                }\n\n                // Cancel the detection in case no devices was found with audioLevel > 0 in the set timeout.\n                setTimeout(() => {\n                    stopActiveDevices(availableDevices);\n                    resolve({\n                        deviceId: '',\n                        deviceLabel: '' }\n                    );\n                }, DETECTION_TIMEOUT);\n\n            });\n\n        });\n    });\n}\n\n/**\n * Stop the streams of the provided JitsiLocalTracks.\n *\n * @param {Array<JitsiLocalTrack>} deviceList - Array of JitsiLocalTracks to stop.\n * @returns {void}\n */\nfunction stopActiveDevices(deviceList) {\n    for (const device of deviceList) {\n        device.stopStream();\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport SignalingLayer from '../../service/RTC/SignalingLayer';\n\nconst logger = getLogger(__filename);\n\n/**\n * Custom semi-mock implementation for the Proxy connection service.\n */\nexport default class CustomSignalingLayer extends SignalingLayer {\n    /**\n     * Creates new instance.\n     */\n    constructor() {\n        super();\n\n        /**\n         * A map that stores SSRCs of remote streams.\n         * @type {Map<number, string>} maps SSRC number to jid\n         */\n        this.ssrcOwners = new Map();\n\n        /**\n         *\n         * @type {ChatRoom|null}\n         */\n        this.chatRoom = null;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getPeerMediaInfo(owner, mediaType, sourceName) { // eslint-disable-line no-unused-vars\n        return {};\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getPeerSourceInfo(owner, sourceName) { // eslint-disable-line no-unused-vars\n        return undefined;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getSSRCOwner(ssrc) {\n        return this.ssrcOwners.get(ssrc);\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getTrackSourceName(ssrc) { // eslint-disable-line no-unused-vars\n        return undefined;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    removeSSRCOwners(ssrcList) {\n        if (!ssrcList?.length) {\n            return;\n        }\n\n        for (const ssrc of ssrcList) {\n            this.ssrcOwners.delete(ssrc);\n        }\n    }\n\n    /**\n     * Sets the <tt>ChatRoom</tt> instance used.\n     * @param {ChatRoom} room\n     */\n    setChatRoom(room) {\n        this.chatRoom = room;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    setSSRCOwner(ssrc, endpointId) {\n        if (typeof ssrc !== 'number') {\n            throw new TypeError(`SSRC(${ssrc}) must be a number`);\n        }\n\n        // Now signaling layer instance is shared between different JingleSessionPC instances, so although very unlikely\n        // an SSRC conflict could potentially occur. Log a message to make debugging easier.\n        const existingOwner = this.ssrcOwners.get(ssrc);\n\n        if (existingOwner && existingOwner !== endpointId) {\n            logger.error(`SSRC owner re-assigned from ${existingOwner} to ${endpointId}`);\n        }\n        this.ssrcOwners.set(ssrc, endpointId);\n    }\n\n    /**\n     * @inheritDoc\n     */\n    setTrackMuteStatus(sourceName, muted) { // eslint-disable-line no-unused-vars\n        return false;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    setTrackVideoType(sourceName, videoType) { // eslint-disable-line no-unused-vars\n        return false;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    setTrackSourceName(ssrc, sourceName) { // eslint-disable-line no-unused-vars\n    }\n\n    /**\n     * @inheritDoc\n     */\n    updateSsrcOwnersOnLeave(id) {\n        const ssrcs = Array.from(this.ssrcOwners)\n            .filter(entry => entry[1] === id)\n            .map(entry => entry[0]);\n\n        if (!ssrcs?.length) {\n            return;\n        }\n\n        this.removeSSRCOwners(ssrcs);\n    }\n}\n","/**\n * The know jingle actions that can be sent and should be acted upon by\n * {@code ProxyConnectionService} and {@code ProxyConnectionPC}.\n */\nexport enum ACTIONS {\n    ACCEPT = 'session-accept',\n    CONNECTION_ERROR = 'connection-error-encountered',\n    INITIATE = 'session-initiate',\n    TERMINATE = 'session-terminate',\n    TRANSPORT_INFO = 'transport-info',\n    UNAVAILABLE = 'unavailable'\n};\n","import { getLogger } from '@jitsi/logger';\n\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport RTC from '../RTC/RTC';\nimport JingleSessionPC from '../xmpp/JingleSessionPC';\nimport { DEFAULT_STUN_SERVERS } from '../xmpp/xmpp';\n\nimport CustomSignalingLayer from './CustomSignalingLayer';\nimport { ACTIONS } from './constants';\n\nconst logger = getLogger(__filename);\n\n/**\n * An adapter around {@code JingleSessionPC} so its logic can be re-used without\n * an XMPP connection. It is being re-used for consistency with the rest of the\n * codebase and to leverage existing peer connection event handling. Also\n * this class provides a facade to hide most of the API for\n * {@code JingleSessionPC}.\n */\nexport default class ProxyConnectionPC {\n    /**\n     * Initializes a new {@code ProxyConnectionPC} instance.\n     *\n     * @param {Object} options - Values to initialize the instance with.\n     * @param {Object} [options.pcConfig] - The {@code RTCConfiguration} to use for the WebRTC peer connection.\n     * @param {boolean} [options.isInitiator] - If true, the local client should send offers. If false, the local\n     * client should send answers. Defaults to false.\n     * @param {Function} options.onRemoteStream - Callback to invoke when a remote media stream has been received\n     * through the peer connection.\n     * @param {string} options.peerJid - The jid of the remote client with which the peer connection is being establish\n     * and which should receive direct messages regarding peer connection updates.\n     * @param {boolean} [options.receiveVideo] - Whether or not the peer connection should accept incoming video\n     * streams. Defaults to false.\n     * @param {Function} options.onSendMessage - Callback to invoke when a message has to be sent (signaled) out.\n     */\n    constructor(options = {}) {\n        this._options = {\n            pcConfig: {},\n            isInitiator: false,\n            receiveAudio: false,\n            receiveVideo: false,\n            ...options\n        };\n\n        /**\n         * Instances of {@code JitsiTrack} associated with this instance of\n         * {@code ProxyConnectionPC}.\n         *\n         * @type {Array<JitsiTrack>}\n         */\n        this._tracks = [];\n\n        /**\n         * The active instance of {@code JingleSessionPC}.\n         *\n         * @type {JingleSessionPC|null}\n         */\n        this._peerConnection = null;\n\n        // Bind event handlers so they are only bound once for every instance.\n        this._onError = this._onError.bind(this);\n        this._onRemoteStream = this._onRemoteStream.bind(this);\n        this._onSendMessage = this._onSendMessage.bind(this);\n    }\n\n    /**\n     * Returns the jid of the remote peer with which this peer connection should\n     * be established with.\n     *\n     * @returns {string}\n     */\n    getPeerJid() {\n        return this._options.peerJid;\n    }\n\n    /**\n     * Updates the peer connection based on the passed in jingle.\n     *\n     * @param {Object} $jingle - An XML jingle element, wrapped in query,\n     * describing how the peer connection should be updated.\n     * @returns {void}\n     */\n    processMessage($jingle) {\n        switch ($jingle.attr('action')) {\n        case ACTIONS.ACCEPT:\n            this._onSessionAccept($jingle);\n            break;\n\n        case ACTIONS.INITIATE:\n            this._onSessionInitiate($jingle);\n            break;\n\n        case ACTIONS.TERMINATE:\n            this._onSessionTerminate($jingle);\n            break;\n\n        case ACTIONS.TRANSPORT_INFO:\n            this._onTransportInfo($jingle);\n            break;\n        }\n    }\n\n    /**\n     * Instantiates a peer connection and starts the offer/answer cycle to\n     * establish a connection with a remote peer.\n     *\n     * @param {Array<JitsiLocalTrack>} localTracks - Initial local tracks to add\n     * to add to the peer connection.\n     * @returns {void}\n     */\n    start(localTracks = []) {\n        if (this._peerConnection) {\n            return;\n        }\n\n        this._tracks = this._tracks.concat(localTracks);\n\n        this._peerConnection = this._createPeerConnection();\n\n        this._peerConnection.invite(localTracks);\n    }\n\n    /**\n     * Begins the process of disconnecting from a remote peer and cleaning up\n     * the peer connection.\n     *\n     * @returns {void}\n     */\n    stop() {\n        if (this._peerConnection) {\n            this._peerConnection.terminate();\n        }\n\n        this._onSessionTerminate();\n    }\n\n    /**\n     * Instantiates a new {@code JingleSessionPC} by stubbing out the various\n     * dependencies of {@code JingleSessionPC}.\n     *\n     * @private\n     * @returns {JingleSessionPC}\n     */\n    _createPeerConnection() {\n        /**\n         * {@code JingleSessionPC} takes in the entire jitsi-meet config.js\n         * object, which may not be accessible from the caller.\n         *\n         * @type {Object}\n         */\n        const configStub = {};\n\n        /**\n         * {@code JingleSessionPC} assumes an XMPP/Strophe connection object is\n         * passed through, which also has the jingle plugin initialized on it.\n         * This connection object is used to signal out peer connection updates\n         * via iqs, and those updates need to be piped back out to the remote\n         * peer.\n         *\n         * @type {Object}\n         */\n        const connectionStub = {\n            // At the time this is used for Spot and it's okay to say the connection is always connected, because if\n            // spot has no signalling it will not be in a meeting where this is used.\n            connected: true,\n            jingle: {\n                terminate: () => { /** no-op */ }\n            },\n            sendIQ: this._onSendMessage,\n\n            // Returns empty function, because it does not add any listeners for real\n            // eslint-disable-next-line no-empty-function\n            addEventListener: () => () => { }\n        };\n\n        /**\n         * {@code JingleSessionPC} can take in a custom ice configuration,\n         * depending on the peer connection type, peer-to-peer or other.\n         * However, {@code ProxyConnectionPC} always assume a peer-to-peer\n         * connection so the ice configuration is hard-coded with defaults.\n         *\n         * @type {Object}\n         */\n        const pcConfigStub = {\n            iceServers: DEFAULT_STUN_SERVERS,\n            ...this._options.pcConfig\n        };\n\n        /**\n         * {@code JingleSessionPC} expects an instance of\n         * {@code JitsiConference}, which has an event emitter that is used\n         * to signal various connection updates that the local client should\n         * act upon. The conference instance is not a dependency of a proxy\n         * connection, but the emitted events can be relevant to the proxy\n         * connection so the event emitter is stubbed.\n         *\n         * @param {string} event - The constant for the event type.\n         * @type {Function}\n         * @returns {void}\n         */\n        const emitter = event => {\n            switch (event) {\n            case XMPPEvents.CONNECTION_ICE_FAILED:\n            case XMPPEvents.CONNECTION_FAILED:\n                this._onError(ACTIONS.CONNECTION_ERROR, event);\n                break;\n            }\n        };\n\n        /**\n         * {@link JingleSessionPC} expects an instance of\n         * {@link ChatRoom} to be passed in. {@link ProxyConnectionPC}\n         * is instantiated outside of the {@code JitsiConference}, so it must be\n         * stubbed to prevent errors.\n         *\n         * @type {Object}\n         */\n        const roomStub = {\n            addEventListener: () => { /* no op */ },\n            addPresenceListener: () => { /* no-op */ },\n            connectionTimes: [],\n            eventEmitter: { emit: emitter },\n            removeEventListener: () => { /* no op */ },\n            removePresenceListener: () => { /* no-op */ },\n            supportsRestartByTerminate: () => false\n        };\n\n        /**\n         * A {@code JitsiConference} stub passed to the {@link RTC} module.\n         * @type {Object}\n         */\n        const conferenceStub = {\n            myUserId: () => ''\n        };\n\n        /**\n         * Create an instance of {@code RTC} as it is required for peer\n         * connection creation by {@code JingleSessionPC}. An existing instance\n         * of {@code RTC} from elsewhere should not be re-used because it is\n         * a stateful grouping of utilities.\n         */\n        this._rtc = new RTC(conferenceStub, {});\n\n        /**\n         * Add the remote track listener here as {@code JingleSessionPC} has\n         * {@code TraceablePeerConnection} which uses {@code RTC}'s event\n         * emitter.\n         */\n        this._rtc.addListener(\n            RTCEvents.REMOTE_TRACK_ADDED,\n            this._onRemoteStream\n        );\n\n        const peerConnection = new JingleSessionPC(\n            undefined, // sid\n            undefined, // localJid\n            this._options.peerJid, // remoteJid\n            connectionStub, // connection\n            {\n                offerToReceiveAudio: this._options.receiveAudio,\n                offerToReceiveVideo: this._options.receiveVideo\n            }, // mediaConstraints\n            pcConfigStub, // pcConfig\n            true, // isP2P\n            this._options.isInitiator // isInitiator\n        );\n\n        const signalingLayer = new CustomSignalingLayer();\n\n        signalingLayer.setChatRoom(roomStub);\n\n        /**\n         * An additional initialize call is necessary to properly set instance\n         * variable for calling.\n         */\n        peerConnection.initialize(roomStub, this._rtc, signalingLayer, configStub);\n\n        return peerConnection;\n    }\n\n    /**\n     * Invoked when a connection related issue has been encountered.\n     *\n     * @param {string} errorType - The constant indicating the type of the error\n     * that occured.\n     * @param {string} details - Optional additional data about the error.\n     * @private\n     * @returns {void}\n     */\n    _onError(errorType, details = '') {\n        this._options.onError(this._options.peerJid, errorType, details);\n    }\n\n    /**\n     * Callback invoked when the peer connection has received a remote media\n     * stream.\n     *\n     * @param {JitsiRemoteTrack} jitsiRemoteTrack - The remote media stream\n     * wrapped in {@code JitsiRemoteTrack}.\n     * @private\n     * @returns {void}\n     */\n    _onRemoteStream(jitsiRemoteTrack) {\n        this._tracks.push(jitsiRemoteTrack);\n\n        this._options.onRemoteStream(jitsiRemoteTrack);\n    }\n\n    /**\n     * Callback invoked when {@code JingleSessionPC} needs to signal a message\n     * out to the remote peer.\n     *\n     * @param {XML} iq - The message to signal out.\n     * @private\n     * @returns {void}\n     */\n    _onSendMessage(iq) {\n        this._options.onSendMessage(this._options.peerJid, iq);\n    }\n\n    /**\n     * Callback invoked in response to an agreement to start a proxy connection.\n     * The passed in jingle element should contain an SDP answer to a previously\n     * sent SDP offer.\n     *\n     * @param {Object} $jingle - The jingle element wrapped in jQuery.\n     * @private\n     * @returns {void}\n     */\n    _onSessionAccept($jingle) {\n        if (!this._peerConnection) {\n            logger.error('Received an answer when no peer connection exists.');\n\n            return;\n        }\n\n        this._peerConnection.setAnswer($jingle);\n    }\n\n    /**\n     * Callback invoked in response to a request to start a proxy connection.\n     * The passed in jingle element should contain an SDP offer.\n     *\n     * @param {Object} $jingle - The jingle element wrapped in jQuery.\n     * @private\n     * @returns {void}\n     */\n    _onSessionInitiate($jingle) {\n        if (this._peerConnection) {\n            logger.error('Received an offer when an offer was already sent.');\n\n            return;\n        }\n\n        this._peerConnection = this._createPeerConnection();\n\n        this._peerConnection.acceptOffer(\n            $jingle,\n            () => { /** no-op */ },\n            () => this._onError(\n                this._options.peerJid,\n                ACTIONS.CONNECTION_ERROR,\n                'session initiate error'\n            )\n        );\n    }\n\n    /**\n     * Callback invoked in response to a request to disconnect an active proxy\n     * connection. Cleans up tracks and the peer connection.\n     *\n     * @private\n     * @returns {void}\n     */\n    _onSessionTerminate() {\n        this._tracks.forEach(track => track.dispose());\n        this._tracks = [];\n\n        if (this._peerConnection) {\n            this._peerConnection.onTerminated();\n        }\n\n        if (this._rtc) {\n            this._rtc.removeListener(\n                RTCEvents.REMOTE_TRACK_ADDED,\n                this._onRemoteStream\n            );\n\n            this._rtc.destroy();\n        }\n    }\n\n    /**\n     * Callback invoked in response to ICE candidates from the remote peer.\n     * The passed in jingle element should contain an ICE candidate.\n     *\n     * @param {Object} $jingle - The jingle element wrapped in jQuery.\n     * @private\n     * @returns {void}\n     */\n    _onTransportInfo($jingle) {\n        this._peerConnection.addIceCandidates($jingle);\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $iq } from 'strophe.js';\n\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { getSourceNameForJitsiTrack } from '../../service/RTC/SignalingLayer';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport RTC from '../RTC/RTC';\n\nimport ProxyConnectionPC from './ProxyConnectionPC';\nimport { ACTIONS } from './constants';\n\nconst logger = getLogger(__filename);\n\n/**\n * Instantiates a new ProxyConnectionPC and ensures only one exists at a given\n * time. Currently it assumes ProxyConnectionPC is used only for screensharing\n * and assumes IQs to be used for communication.\n */\nexport default class ProxyConnectionService {\n    /**\n     * Initializes a new {@code ProxyConnectionService} instance.\n     *\n     * @param {Object} options - Values to initialize the instance with.\n     * @param {boolean} [options.convertVideoToDesktop] - Whether or not proxied video should be returned as a desktop\n     * stream. Defaults to false.\n     * @param {Object} [options.pcConfig] - The {@code RTCConfiguration} to use for the WebRTC peer connection.\n     * @param {JitsiConnection} [options.jitsiConnection] - The {@code JitsiConnection} which will be used to fetch\n     * TURN credentials for the P2P connection.\n     * @param {Function} options.onRemoteStream - Callback to invoke when a remote video stream has been received and\n     * converted to a {@code JitsiLocakTrack}. The {@code JitsiLocakTrack} will be passed in.\n     * @param {Function} options.onSendMessage - Callback to invoke when a message has to be sent (signaled) out. The\n     * arguments passed in are the jid to send the message to and the message.\n     */\n    constructor(options = {}) {\n        const {\n            jitsiConnection,\n            ...otherOptions\n        } = options;\n\n        /**\n         * Holds a reference to the collection of all callbacks.\n         *\n         * @type {Object}\n         */\n        this._options = {\n            pcConfig: jitsiConnection && jitsiConnection.xmpp.connection.jingle.p2pIceConfig,\n            ...otherOptions\n        };\n\n        /**\n         * The active instance of {@code ProxyConnectionService}.\n         *\n         * @type {ProxyConnectionPC|null}\n         */\n        this._peerConnection = null;\n\n        // Bind event handlers so they are only bound once for every instance.\n        this._onFatalError = this._onFatalError.bind(this);\n        this._onSendMessage = this._onSendMessage.bind(this);\n        this._onRemoteStream = this._onRemoteStream.bind(this);\n    }\n\n    /**\n     * Parses a message object regarding a proxy connection to create a new\n     * proxy connection or update and existing connection.\n     *\n     * @param {Object} message - A message object regarding establishing or\n     * updating a proxy connection.\n     * @param {Object} message.data - An object containing additional message\n     * details.\n     * @param {string} message.data.iq - The stringified iq which explains how\n     * and what to update regarding the proxy connection.\n     * @param {string} message.from - The message sender's full jid. Used for\n     * sending replies.\n     * @returns {void}\n     */\n    processMessage(message) {\n        const peerJid = message.from;\n\n        if (!peerJid) {\n            return;\n        }\n\n        // If a proxy connection has already been established and messages come\n        // from another peer jid then those messages should be replied to with\n        // a rejection.\n        if (this._peerConnection\n            && this._peerConnection.getPeerJid() !== peerJid) {\n            this._onFatalError(\n                peerJid,\n                ACTIONS.CONNECTION_ERROR,\n                'rejected'\n            );\n\n            return;\n        }\n\n        const iq = this._convertStringToXML(message.data.iq);\n        const $jingle = iq && iq.find('jingle');\n        const action = $jingle && $jingle.attr('action');\n\n        if (action === ACTIONS.INITIATE) {\n            this._peerConnection = this._createPeerConnection(peerJid, {\n                isInitiator: false,\n                receiveVideo: true\n            });\n        }\n\n        // Truthy check for peer connection added to protect against possibly\n        // receiving actions before an ACTIONS.INITIATE.\n        if (this._peerConnection) {\n            this._peerConnection.processMessage($jingle);\n        }\n\n        // Take additional steps to ensure the peer connection is cleaned up\n        // if it is to be closed.\n        if (action === ACTIONS.CONNECTION_ERROR\n            || action === ACTIONS.UNAVAILABLE\n            || action === ACTIONS.TERMINATE) {\n            this._selfCloseConnection();\n        }\n\n        return;\n    }\n\n    /**\n     * Instantiates and initiates a proxy peer connection.\n     *\n     * @param {string} peerJid - The jid of the remote client that should\n     * receive messages.\n     * @param {Array<JitsiLocalTrack>} localTracks - Initial media tracks to\n     * send through to the peer.\n     * @returns {void}\n     */\n    start(peerJid, localTracks = []) {\n        this._peerConnection = this._createPeerConnection(peerJid, {\n            isInitiator: true,\n            receiveVideo: false\n        });\n\n        localTracks.forEach((localTrack, localTrackIndex) => {\n            const localSourceNameTrack = getSourceNameForJitsiTrack('peer', localTrack.getType(), localTrackIndex);\n\n            localTrack.setSourceName(localSourceNameTrack);\n        });\n\n        this._peerConnection.start(localTracks);\n    }\n\n    /**\n     * Terminates any active proxy peer connection.\n     *\n     * @returns {void}\n     */\n    stop() {\n        if (this._peerConnection) {\n            this._peerConnection.stop();\n        }\n\n        this._peerConnection = null;\n    }\n\n    /**\n     * Transforms a stringified xML into a XML wrapped in jQuery.\n     *\n     * @param {string} xml - The XML in string form.\n     * @private\n     * @returns {Object|null} A jQuery version of the xml. Null will be returned\n     * if an error is encountered during transformation.\n     */\n    _convertStringToXML(xml) {\n        try {\n            const xmlDom = new DOMParser().parseFromString(xml, 'text/xml');\n\n            return $(xmlDom);\n        } catch (e) {\n            logger.error('Attempted to convert incorrectly formatted xml');\n\n            return null;\n        }\n    }\n\n    /**\n     * Helper for creating an instance of {@code ProxyConnectionPC}.\n     *\n     * @param {string} peerJid - The jid of the remote peer with which the\n     * {@code ProxyConnectionPC} will be established with.\n     * @param {Object} options - Additional defaults to instantiate the\n     * {@code ProxyConnectionPC} with. See the constructor of ProxyConnectionPC\n     * for more details.\n     * @private\n     * @returns {ProxyConnectionPC}\n     */\n    _createPeerConnection(peerJid, options = {}) {\n        if (!peerJid) {\n            throw new Error('Cannot create ProxyConnectionPC without a peer.');\n        }\n\n        const pcOptions = {\n            pcConfig: this._options.pcConfig,\n            onError: this._onFatalError,\n            onRemoteStream: this._onRemoteStream,\n            onSendMessage: this._onSendMessage,\n            peerJid,\n            ...options\n        };\n\n        return new ProxyConnectionPC(pcOptions);\n    }\n\n    /**\n     * Callback invoked when an error occurs that should cause\n     * {@code ProxyConnectionPC} to be closed if the peer is currently\n     * connected. Sends an error message/reply back to the peer.\n     *\n     * @param {string} peerJid - The peer jid with which the connection was\n     * attempted or started, and to which an iq with error details should be\n     * sent.\n     * @param {string} errorType - The constant indicating the type of the error\n     * that occured.\n     * @param {string} details - Optional additional data about the error.\n     * @private\n     * @returns {void}\n     */\n    _onFatalError(peerJid, errorType, details = '') {\n        logger.error(\n            'Received a proxy connection error', peerJid, errorType, details);\n\n        const iq = $iq({\n            to: peerJid,\n            type: 'set'\n        })\n            .c('jingle', {\n                xmlns: 'urn:xmpp:jingle:1',\n                action: errorType\n            })\n            .c('details')\n            .t(details)\n            .up();\n\n        this._onSendMessage(peerJid, iq);\n\n        if (this._peerConnection\n            && this._peerConnection.getPeerJid() === peerJid) {\n            this._selfCloseConnection();\n        }\n    }\n\n    /**\n     * Callback invoked when the remote peer of the {@code ProxyConnectionPC}\n     * has offered a media stream. The stream is converted into a\n     * {@code JitsiLocalTrack} for local usage if the {@code onRemoteStream}\n     * callback is defined.\n     *\n     * @param {JitsiRemoteTrack} jitsiRemoteTrack - The {@code JitsiRemoteTrack}\n     * for the peer's media stream.\n     * @private\n     * @returns {void}\n     */\n    _onRemoteStream(jitsiRemoteTrack) {\n        if (!this._options.onRemoteStream) {\n            logger.error('Remote track received without callback.');\n            jitsiRemoteTrack.dispose();\n\n            return;\n        }\n\n        const isVideo = jitsiRemoteTrack.isVideoTrack();\n        let videoType;\n\n        if (isVideo) {\n            videoType = this._options.convertVideoToDesktop\n                ? VideoType.DESKTOP : VideoType.CAMERA;\n        }\n\n        // Grab the webrtc media stream and pipe it through the same processing\n        // that would occur for a locally obtained media stream.\n        const mediaStream = jitsiRemoteTrack.getOriginalStream();\n        const jitsiLocalTracks = RTC.createLocalTracks(\n            [\n                {\n                    deviceId:\n                        `proxy:${this._peerConnection.getPeerJid()}`,\n                    mediaType: isVideo ? MediaType.VIDEO : MediaType.AUDIO,\n                    sourceType: 'proxy',\n                    stream: mediaStream,\n                    track: mediaStream.getVideoTracks()[0],\n                    videoType\n                }\n            ]);\n\n        this._options.onRemoteStream(jitsiLocalTracks[0]);\n    }\n\n    /**\n     * Formats and forwards a message an iq to be sent to a peer jid.\n     *\n     * @param {string} peerJid - The jid the iq should be sent to.\n     * @param {Object} iq - The iq which would be sent to the peer jid.\n     * @private\n     * @returns {void}\n     */\n    _onSendMessage(peerJid, iq) {\n        if (!this._options.onSendMessage) {\n            return;\n        }\n\n        try {\n            const stringifiedIq\n                = new XMLSerializer().serializeToString(iq.nodeTree || iq);\n\n            this._options.onSendMessage(peerJid, { iq: stringifiedIq });\n        } catch (e) {\n            logger.error('Attempted to send an incorrectly formatted iq.');\n        }\n    }\n\n    /**\n     * Invoked when preemptively closing the {@code ProxyConnectionPC}.\n     *\n     * @private\n     * @returns {void}\n     */\n    _selfCloseConnection() {\n        this.stop();\n\n        this._options.onConnectionClosed\n            && this._options.onConnectionClosed();\n    }\n}\n","import EventEmitter from 'events';\n\nimport browser from '../browser';\nimport Settings from '../settings/Settings';\nimport ScriptUtil from '../util/ScriptUtil';\n\nimport { CALLSTATS_SCRIPT_URL } from './constants';\n\nconst PRECALL_TEST_RESULTS = 'preCallTestResults';\nconst emitter = new EventEmitter();\nlet _initialized = false;\nlet api = null;\n\n/**\n * Loads the callstats io script.\n *\n * @returns {Promise<void>}\n */\nfunction _loadScript(options) {\n    if (browser.isReactNative()) {\n        return;\n    }\n\n    return new Promise(resolve => {\n        ScriptUtil.loadScript(\n            options.callStatsCustomScriptUrl || CALLSTATS_SCRIPT_URL,\n            /* async */ true,\n            /* prepend */ true,\n            /* relativeURL */ undefined,\n            /* loadCallback */ resolve);\n    });\n}\n\n/**\n * Initializes the callstats lib and registers a callback to be invoked\n * when there are 'preCallTestResults'.\n *\n * @typedef PrecallTestOptions\n * @type {Object}\n * @property {string} callStatsID - Callstats credentials - the id.\n * @property {string} callStatsSecret - Callstats credentials - the secret.\n * @property {string} statisticsId - The user name to use when initializing callstats.\n * @property {string} statisticsDisplayName - The user display name.\n *\n * @param { PrecallTestOptions} options - The init options.\n * @returns {Promise<void>}\n */\nfunction _initialize(options) {\n    return new Promise((resolve, reject) => {\n        const appId = options.callStatsID;\n        const appSecret = options.callStatsSecret;\n        const userId = options.statisticsId || options.statisticsDisplayName || Settings.callStatsUserName;\n\n        api.initialize(appId, appSecret, userId, (status, message) => {\n            if (status === 'success') {\n                api.on(PRECALL_TEST_RESULTS, (...args) => {\n                    emitter.emit(PRECALL_TEST_RESULTS, ...args);\n                });\n                _initialized = true;\n                resolve();\n            } else {\n                reject({\n                    status,\n                    message\n                });\n            }\n        }, null, { disablePrecalltest: true });\n    });\n}\n\n/**\n * Loads the callstats script and initializes the library.\n *\n * @param {Function} onResult - The callback to be invoked when results are received.\n * @returns {Promise<void>}\n */\nexport async function init(options) {\n    if (_initialized) {\n        throw new Error('Precall Test already initialized');\n    }\n\n    const { callStatsID, callStatsSecret, disableThirdPartyRequests } = options;\n\n    if (!callStatsID || !callStatsSecret || disableThirdPartyRequests) {\n        throw new Error('Callstats is disabled');\n    }\n\n    await _loadScript(options);\n    // eslint-disable-next-line new-cap\n    api = new window.callstats();\n\n    return _initialize(options);\n}\n\n/**\n * Executes a pre call test.\n *\n * @typedef PrecallTestResults\n * @type {Object}\n * @property {boolean} mediaConnectivity - If there is media connectivity or not.\n * @property {number} throughput  - The average throughput.\n * @property {number} fractionalLoss - The packet loss.\n * @property {number} rtt - The round trip time.\n * @property {string} provider - It is usually 'callstats'.\n *\n * @returns {Promise<{PrecallTestResults}>}\n */\nexport function execute() {\n    if (!_initialized) {\n        return Promise.reject('uninitialized');\n    }\n\n    return new Promise((resolve, reject) => {\n        emitter.on(PRECALL_TEST_RESULTS, (status, payload) => {\n            if (status === 'success') {\n                resolve(payload);\n            } else {\n                reject({\n                    status,\n                    payload\n                });\n            }\n\n        });\n\n        api.makePrecallTest();\n    });\n}\n\nexport default {\n    init,\n    execute\n};\n","import { getLogger } from '@jitsi/logger';\n\nimport { createAudioContext } from './WebAudioUtils';\n\nconst logger = getLogger(__filename);\n\n/**\n * The AudioMixer, as the name implies, mixes a number of MediaStreams containing audio tracks into a single\n * MediaStream.\n */\nexport default class AudioMixer {\n    /**\n     * Create AudioMixer instance.\n     */\n    constructor() {\n        this._started = false;\n        this._streamsToMix = [];\n        this._streamMSSArray = [];\n    }\n\n    /**\n     * Add audio MediaStream to be mixed, if the stream doesn't contain any audio tracks it will be ignored.\n     *\n     * @param {MediaStream} stream - MediaStream to be mixed.\n     */\n    addMediaStream(stream) {\n        if (!stream.getAudioTracks()) {\n            logger.warn('Added MediaStream doesn\\'t contain audio tracks.');\n        }\n\n        this._streamsToMix.push(stream);\n    }\n\n    /**\n     * At this point a WebAudio ChannelMergerNode is created and and the two associated MediaStreams are connected to\n     * it; the resulting mixed MediaStream is returned.\n     *\n     * @returns {MediaStream} - MediaStream containing added streams mixed together, or null if no MediaStream\n     * is added.\n     */\n    start() {\n        // If the mixer was already started just return the existing mixed stream.\n        if (this._started) {\n            return this._mixedMSD.stream;\n        }\n\n        this._audioContext = createAudioContext();\n\n        if (!this._streamsToMix.length) {\n            logger.warn('No MediaStream\\'s added to AudioMixer, nothing will happen.');\n\n            return null;\n        }\n\n        this._started = true;\n\n        this._mixedMSD = this._audioContext.createMediaStreamDestination();\n\n        for (const stream of this._streamsToMix) {\n            const streamMSS = this._audioContext.createMediaStreamSource(stream);\n\n            streamMSS.connect(this._mixedMSD);\n\n            // Maintain a list of MediaStreamAudioSourceNode so we can disconnect them on reset.\n            this._streamMSSArray.push(streamMSS);\n        }\n\n        return this._mixedMSD.stream;\n    }\n\n    /**\n     * Disconnect MediaStreamAudioSourceNode and clear references.\n     *\n     * @returns {void}\n     */\n    reset() {\n        this._started = false;\n        this._streamsToMix = [];\n\n        // Clean up created MediaStreamAudioSourceNode.\n        for (const streamMSS of this._streamMSSArray) {\n            streamMSS.disconnect();\n        }\n\n        this._streamMSSArray = [];\n\n        if (this._audioContext) {\n            this._audioContext = undefined;\n        }\n    }\n}\n","import Logger from '@jitsi/logger';\n\nimport * as JitsiConferenceErrors from './JitsiConferenceErrors';\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\nimport JitsiConnection from './JitsiConnection';\nimport * as JitsiConnectionErrors from './JitsiConnectionErrors';\nimport * as JitsiConnectionEvents from './JitsiConnectionEvents';\nimport JitsiMediaDevices from './JitsiMediaDevices';\nimport * as JitsiMediaDevicesEvents from './JitsiMediaDevicesEvents';\nimport JitsiTrackError from './JitsiTrackError';\nimport * as JitsiTrackErrors from './JitsiTrackErrors';\nimport * as JitsiTrackEvents from './JitsiTrackEvents';\nimport * as JitsiTranscriptionStatus from './JitsiTranscriptionStatus';\nimport RTC from './modules/RTC/RTC';\nimport browser from './modules/browser';\nimport NetworkInfo from './modules/connectivity/NetworkInfo';\nimport { TrackStreamingStatus } from './modules/connectivity/TrackStreamingStatus';\nimport getActiveAudioDevice from './modules/detection/ActiveDeviceDetector';\nimport * as DetectionEvents from './modules/detection/DetectionEvents';\nimport TrackVADEmitter from './modules/detection/TrackVADEmitter';\nimport FeatureFlags from './modules/flags/FeatureFlags';\nimport ProxyConnectionService\n    from './modules/proxyconnection/ProxyConnectionService';\nimport recordingConstants from './modules/recording/recordingConstants';\nimport Settings from './modules/settings/Settings';\nimport LocalStatsCollector from './modules/statistics/LocalStatsCollector';\nimport precallTest from './modules/statistics/PrecallTest';\nimport Statistics from './modules/statistics/statistics';\nimport AuthUtil from './modules/util/AuthUtil';\nimport GlobalOnErrorHandler from './modules/util/GlobalOnErrorHandler';\nimport ScriptUtil from './modules/util/ScriptUtil';\nimport * as VideoSIPGWConstants from './modules/videosipgw/VideoSIPGWConstants';\nimport AudioMixer from './modules/webaudio/AudioMixer';\nimport { MediaType } from './service/RTC/MediaType';\nimport * as ConnectionQualityEvents\n    from './service/connectivity/ConnectionQualityEvents';\nimport * as E2ePingEvents from './service/e2eping/E2ePingEvents';\nimport { createGetUserMediaEvent } from './service/statistics/AnalyticsEvents';\n\nconst logger = Logger.getLogger(__filename);\n\n/**\n * The amount of time to wait until firing\n * {@link JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN} event.\n */\nconst USER_MEDIA_SLOW_PROMISE_TIMEOUT = 1000;\n\n/**\n * Extracts from an 'options' objects with a specific format (TODO what IS the\n * format?) the attributes which are to be logged in analytics events.\n *\n * @param options gum options (???)\n * @returns {*} the attributes to attach to analytics events.\n */\nfunction getAnalyticsAttributesFromOptions(options) {\n    const attributes: any = {};\n\n    attributes['audio_requested'] = options.devices.includes('audio');\n    attributes['video_requested'] = options.devices.includes('video');\n    attributes['screen_sharing_requested'] = options.devices.includes('desktop');\n\n    if (attributes.video_requested) {\n        attributes.resolution = options.resolution;\n    }\n\n    return attributes;\n}\n\ninterface ICreateLocalTrackOptions {\n    cameraDeviceId?: string;\n    devices?: any[];\n    firePermissionPromptIsShownEvent?: boolean;\n    fireSlowPromiseEvent?: boolean;\n    micDeviceId?: string;\n    resolution?: string;\n}\n\ninterface IJitsiMeetJSOptions {\n    enableAnalyticsLogging?: boolean;\n    enableWindowOnErrorHandler?: boolean;\n    externalStorage?: Storage;\n    flags?: {\n        runInLiteMode?: boolean;\n        ssrcRewritingEnabled?: boolean;\n    }\n}\n\n/**\n * The public API of the Jitsi Meet library (a.k.a. {@code JitsiMeetJS}).\n */\nexport default {\n\n    version: '{#COMMIT_HASH#}',\n\n    JitsiConnection,\n\n    /**\n     * {@code ProxyConnectionService} is used to connect a remote peer to a\n     * local Jitsi participant without going through a Jitsi conference. It is\n     * currently used for room integration development, specifically wireless\n     * screensharing. Its API is experimental and will likely change; usage of\n     * it is advised against.\n     */\n    ProxyConnectionService,\n\n    constants: {\n        recording: recordingConstants,\n        sipVideoGW: VideoSIPGWConstants,\n        transcriptionStatus: JitsiTranscriptionStatus,\n        trackStreamingStatus: TrackStreamingStatus\n    },\n    events: {\n        conference: JitsiConferenceEvents,\n        connection: JitsiConnectionEvents,\n        detection: DetectionEvents,\n        track: JitsiTrackEvents,\n        mediaDevices: JitsiMediaDevicesEvents,\n        connectionQuality: ConnectionQualityEvents,\n        e2eping: E2ePingEvents\n    },\n    errors: {\n        conference: JitsiConferenceErrors,\n        connection: JitsiConnectionErrors,\n        track: JitsiTrackErrors\n    },\n    errorTypes: {\n        JitsiTrackError\n    },\n    logLevels: Logger.levels,\n    mediaDevices: JitsiMediaDevices as unknown,\n    analytics: Statistics.analytics as unknown,\n    init(options: IJitsiMeetJSOptions = {}) {\n        Settings.init(options.externalStorage);\n        Statistics.init(options);\n        const flags = options.flags || {};\n\n        // Configure the feature flags.\n        FeatureFlags.init(flags);\n\n        // Initialize global window.connectionTimes\n        // FIXME do not use 'window'\n        if (!window.connectionTimes) {\n            window.connectionTimes = {};\n        }\n\n        if (options.enableAnalyticsLogging !== true) {\n            logger.warn('Analytics disabled, disposing.');\n            this.analytics.dispose();\n        }\n\n        if (options.enableWindowOnErrorHandler) {\n            GlobalOnErrorHandler.addHandler(\n                this.getGlobalOnErrorHandler.bind(this));\n        }\n\n        if (this.version) {\n            const logObject = {\n                id: 'component_version',\n                component: 'lib-jitsi-meet',\n                version: this.version\n            };\n\n            Statistics.sendLog(JSON.stringify(logObject));\n        }\n\n        return RTC.init(options);\n    },\n\n    /**\n     * Returns whether the desktop sharing is enabled or not.\n     *\n     * @returns {boolean}\n     */\n    isDesktopSharingEnabled() {\n        return RTC.isDesktopSharingEnabled();\n    },\n\n    /**\n     * Returns whether the current execution environment supports WebRTC (for\n     * use within this library).\n     *\n     * @returns {boolean} {@code true} if WebRTC is supported in the current\n     * execution environment (for use within this library); {@code false},\n     * otherwise.\n     */\n    isWebRtcSupported() {\n        return RTC.isWebRtcSupported();\n    },\n\n    setLogLevel(level) {\n        Logger.setLogLevel(level);\n    },\n\n    /**\n     * Sets the log level to the <tt>Logger</tt> instance with given id.\n     *\n     * @param {Logger.levels} level the logging level to be set\n     * @param {string} id the logger id to which new logging level will be set.\n     * Usually it's the name of the JavaScript source file including the path\n     * ex. \"modules/xmpp/ChatRoom.js\"\n     */\n    setLogLevelById(level, id) {\n        Logger.setLogLevelById(level, id);\n    },\n\n    /**\n     * Registers new global logger transport to the library logging framework.\n     *\n     * @param globalTransport\n     * @see Logger.addGlobalTransport\n     */\n    addGlobalLogTransport(globalTransport) {\n        Logger.addGlobalTransport(globalTransport);\n    },\n\n    /**\n     * Removes global logging transport from the library logging framework.\n     *\n     * @param globalTransport\n     * @see Logger.removeGlobalTransport\n     */\n    removeGlobalLogTransport(globalTransport) {\n        Logger.removeGlobalTransport(globalTransport);\n    },\n\n    /**\n    * Sets global options which will be used by all loggers. Changing these\n    * works even after other loggers are created.\n    *\n    * @param options\n    * @see Logger.setGlobalOptions\n    */\n    setGlobalLogOptions(options) {\n        Logger.setGlobalOptions(options);\n    },\n\n    /**\n     * Creates the media tracks and returns them trough the callback.\n     *\n     * @param options Object with properties / settings specifying the tracks\n     * which should be created. should be created or some additional\n     * configurations about resolution for example.\n     * @param {Array} options.effects optional effects array for the track\n     * @param {boolean} options.firePermissionPromptIsShownEvent - if event\n     * JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN should be fired\n     * @param {boolean} options.fireSlowPromiseEvent - if event\n     * JitsiMediaDevicesEvents.USER_MEDIA_SLOW_PROMISE_TIMEOUT should be fired\n     * @param {Array} options.devices the devices that will be requested\n     * @param {string} options.resolution resolution constraints\n     * @param {string} options.cameraDeviceId\n     * @param {string} options.micDeviceId\n     * @param {intiger} interval - the interval (in ms) for\n     * checking whether the desktop sharing extension is installed or not\n     * @param {Function} checkAgain - returns boolean. While checkAgain()==true\n     * createLocalTracks will wait and check on every \"interval\" ms for the\n     * extension. If the desktop extension is not install and checkAgain()==true\n     * createLocalTracks will finish with rejected Promise.\n     * @param {Function} listener - The listener will be called to notify the\n     * user of lib-jitsi-meet that createLocalTracks is starting external\n     * extension installation process.\n     * NOTE: If the inline installation process is not possible and external\n     * installation is enabled the listener property will be called to notify\n     * the start of external installation process. After that createLocalTracks\n     * will start to check for the extension on every interval ms until the\n     * plugin is installed or until checkAgain return false. If the extension\n     * is found createLocalTracks will try to get the desktop sharing track and\n     * will finish the execution. If checkAgain returns false, createLocalTracks\n     * will finish the execution with rejected Promise.\n     *\n     * @deprecated old firePermissionPromptIsShownEvent\n     * @returns {Promise.<{Array.<JitsiTrack>}, JitsiConferenceError>} A promise\n     * that returns an array of created JitsiTracks if resolved, or a\n     * JitsiConferenceError if rejected.\n     */\n    createLocalTracks(options: ICreateLocalTrackOptions = {}, oldfirePermissionPromptIsShownEvent) {\n        let promiseFulfilled = false;\n\n        const { firePermissionPromptIsShownEvent, fireSlowPromiseEvent, ...restOptions } = options;\n        const firePermissionPrompt = firePermissionPromptIsShownEvent || oldfirePermissionPromptIsShownEvent;\n\n        if (firePermissionPrompt && !RTC.arePermissionsGrantedForAvailableDevices()) {\n            // @ts-ignore\n            JitsiMediaDevices.emitEvent(JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN, browser.getName());\n        } else if (fireSlowPromiseEvent) {\n            window.setTimeout(() => {\n                if (!promiseFulfilled) {\n                    JitsiMediaDevices.emitEvent(JitsiMediaDevicesEvents.SLOW_GET_USER_MEDIA);\n                }\n            }, USER_MEDIA_SLOW_PROMISE_TIMEOUT);\n        }\n\n        if (!window.connectionTimes) {\n            window.connectionTimes = {};\n        }\n        window.connectionTimes['obtainPermissions.start']\n            = window.performance.now();\n\n        return RTC.obtainAudioAndVideoPermissions(restOptions)\n            .then(tracks => {\n                promiseFulfilled = true;\n\n                window.connectionTimes['obtainPermissions.end']\n                    = window.performance.now();\n\n                Statistics.sendAnalytics(\n                    createGetUserMediaEvent(\n                        'success',\n                        getAnalyticsAttributesFromOptions(restOptions)));\n\n                if (this.isCollectingLocalStats()) {\n                    for (let i = 0; i < tracks.length; i++) {\n                        const track = tracks[i];\n\n                        if (track.getType() === MediaType.AUDIO) {\n                            Statistics.startLocalStats(track,\n                                track.setAudioLevel.bind(track));\n                        }\n                    }\n                }\n\n                // set real device ids\n                const currentlyAvailableMediaDevices\n                    = RTC.getCurrentlyAvailableMediaDevices();\n\n                if (currentlyAvailableMediaDevices) {\n                    for (let i = 0; i < tracks.length; i++) {\n                        const track = tracks[i];\n\n                        track._setRealDeviceIdFromDeviceList(\n                            currentlyAvailableMediaDevices);\n                    }\n                }\n\n                // set the contentHint to \"detail\" for desktop tracks\n                // eslint-disable-next-line prefer-const\n                for (const track of tracks) {\n                    if (track.type === MediaType.VIDEO\n                        && track.videoType === 'desktop') {\n                        this.setVideoTrackContentHints(track.track, 'detail');\n                    }\n                }\n\n                return tracks;\n            })\n            .catch(error => {\n                promiseFulfilled = true;\n\n                if (error.name === JitsiTrackErrors.SCREENSHARING_USER_CANCELED) {\n                    // User cancelled action is not really an error, so only\n                    // log it as an event to avoid having conference classified\n                    // as partially failed\n                    const logObject = {\n                        id: 'screensharing_user_canceled',\n                        message: error.message\n                    };\n\n                    Statistics.sendLog(JSON.stringify(logObject));\n\n                    Statistics.sendAnalytics(\n                        createGetUserMediaEvent(\n                            'warning',\n                            {\n                                reason: 'extension install user canceled'\n                            }));\n                } else if (error.name === JitsiTrackErrors.NOT_FOUND) {\n                    // logs not found devices with just application log to cs\n                    const logObject = {\n                        id: 'usermedia_missing_device',\n                        status: error.gum.devices\n                    };\n\n                    Statistics.sendLog(JSON.stringify(logObject));\n\n                    const attributes\n                        = getAnalyticsAttributesFromOptions(options);\n\n                    attributes.reason = 'device not found';\n                    attributes.devices = error.gum.devices.join('.');\n                    Statistics.sendAnalytics(\n                        createGetUserMediaEvent('error', attributes));\n                } else {\n                    // Report gUM failed to the stats\n                    Statistics.sendGetUserMediaFailed(error);\n\n                    const attributes\n                        = getAnalyticsAttributesFromOptions(options);\n\n                    attributes.reason = error.name;\n                    Statistics.sendAnalytics(\n                        createGetUserMediaEvent('error', attributes));\n                }\n\n                window.connectionTimes['obtainPermissions.end']\n                    = window.performance.now();\n\n                return Promise.reject(error);\n            });\n    },\n\n    /**\n     * Create a TrackVADEmitter service that connects an audio track to an VAD (voice activity detection) processor in\n     * order to obtain VAD scores for individual PCM audio samples.\n     * @param {string} localAudioDeviceId - The target local audio device.\n     * @param {number} sampleRate - Sample rate at which the emitter will operate. Possible values  256, 512, 1024,\n     * 4096, 8192, 16384. Passing other values will default to closes neighbor.\n     * I.e. Providing a value of 4096 means that the emitter will process 4096 PCM samples at a time, higher values mean\n     * longer calls, lowers values mean more calls but shorter.\n     * @param {Object} vadProcessor - VAD Processors that does the actual compute on a PCM sample.The processor needs\n     * to implement the following functions:\n     * - <tt>getSampleLength()</tt> - Returns the sample size accepted by calculateAudioFrameVAD.\n     * - <tt>getRequiredPCMFrequency()</tt> - Returns the PCM frequency at which the processor operates.\n     * i.e. (16KHz, 44.1 KHz etc.)\n     * - <tt>calculateAudioFrameVAD(pcmSample)</tt> - Process a 32 float pcm sample of getSampleLength size.\n     * @returns {Promise<TrackVADEmitter>}\n     */\n    createTrackVADEmitter(localAudioDeviceId, sampleRate, vadProcessor) {\n        return TrackVADEmitter.create(localAudioDeviceId, sampleRate, vadProcessor);\n    },\n\n    /**\n     * Create AudioMixer, which is essentially a wrapper over web audio ChannelMergerNode. It essentially allows the\n     * user to mix multiple MediaStreams into a single one.\n     *\n     * @returns {AudioMixer}\n     */\n    createAudioMixer() {\n        return new AudioMixer();\n    },\n\n    /**\n     * Go through all audio devices on the system and return one that is active, i.e. has audio signal.\n     *\n     * @returns Promise<Object> - Object containing information about the found device.\n     */\n    getActiveAudioDevice() {\n        return getActiveAudioDevice();\n    },\n\n    /**\n     * Checks if its possible to enumerate available cameras/microphones.\n     *\n     * @returns {Promise<boolean>} a Promise which will be resolved only once\n     * the WebRTC stack is ready, either with true if the device listing is\n     * available available or with false otherwise.\n     * @deprecated use JitsiMeetJS.mediaDevices.isDeviceListAvailable instead\n     */\n    isDeviceListAvailable() {\n        logger.warn('This method is deprecated, use '\n            + 'JitsiMeetJS.mediaDevices.isDeviceListAvailable instead');\n\n        return this.mediaDevices.isDeviceListAvailable();\n    },\n\n    /**\n     * Returns true if changing the input (camera / microphone) or output\n     * (audio) device is supported and false if not.\n     *\n     * @param {string} [deviceType] - type of device to change. Default is\n     * {@code undefined} or 'input', 'output' - for audio output device change.\n     * @returns {boolean} {@code true} if available; {@code false}, otherwise.\n     * @deprecated use JitsiMeetJS.mediaDevices.isDeviceChangeAvailable instead\n     */\n    isDeviceChangeAvailable(deviceType) {\n        logger.warn('This method is deprecated, use '\n            + 'JitsiMeetJS.mediaDevices.isDeviceChangeAvailable instead');\n\n        return this.mediaDevices.isDeviceChangeAvailable(deviceType);\n    },\n\n\n    /**\n     * Checks if the current environment supports having multiple audio\n     * input devices in use simultaneously.\n     *\n     * @returns {boolean} True if multiple audio input devices can be used.\n     */\n    isMultipleAudioInputSupported() {\n        return this.mediaDevices.isMultipleAudioInputSupported();\n    },\n\n    /**\n     * Checks if local tracks can collect stats and collection is enabled.\n     *\n     * @param {boolean} True if stats are being collected for local tracks.\n     */\n    isCollectingLocalStats() {\n        return Statistics.audioLevelsEnabled && LocalStatsCollector.isLocalStatsSupported();\n    },\n\n    /**\n     * Executes callback with list of media devices connected.\n     *\n     * @param {function} callback\n     * @deprecated use JitsiMeetJS.mediaDevices.enumerateDevices instead\n     */\n    enumerateDevices(callback) {\n        logger.warn('This method is deprecated, use '\n            + 'JitsiMeetJS.mediaDevices.enumerateDevices instead');\n        this.mediaDevices.enumerateDevices(callback);\n    },\n\n    /* eslint-disable max-params */\n\n    /**\n     * @returns function that can be used to be attached to window.onerror and\n     * if options.enableWindowOnErrorHandler is enabled returns\n     * the function used by the lib.\n     * (function(message, source, lineno, colno, error)).\n     */\n    getGlobalOnErrorHandler(message, source, lineno, colno, error) {\n        logger.error(\n            `UnhandledError: ${message}`,\n            `Script: ${source}`,\n            `Line: ${lineno}`,\n            `Column: ${colno}`,\n            'StackTrace: ', error);\n        Statistics.reportGlobalError(error);\n    },\n\n    /**\n     * Informs lib-jitsi-meet about the current network status.\n     *\n     * @param {object} state - The network info state.\n     * @param {boolean} state.isOnline - {@code true} if the internet connectivity is online or {@code false}\n     * otherwise.\n     */\n    setNetworkInfo({ isOnline }) {\n        NetworkInfo.updateNetworkInfo({ isOnline });\n    },\n\n    /**\n     * Set the contentHint on the transmitted stream track to indicate\n     * charaterstics in the video stream, which informs PeerConnection\n     * on how to encode the track (to prefer motion or individual frame detail)\n     * @param {MediaStreamTrack} track - the track that is transmitted\n     * @param {String} hint - contentHint value that needs to be set on the track\n     */\n    setVideoTrackContentHints(track, hint) {\n        if ('contentHint' in track) {\n            track.contentHint = hint;\n            if (track.contentHint !== hint) {\n                logger.debug('Invalid video track contentHint');\n            }\n        } else {\n            logger.debug('MediaStreamTrack contentHint attribute not supported');\n        }\n    },\n\n    precallTest,\n\n    /* eslint-enable max-params */\n\n    /**\n     * Represents a hub/namespace for utility functionality which may be of\n     * interest to lib-jitsi-meet clients.\n     */\n    util: {\n        AuthUtil,\n        ScriptUtil,\n        browser\n    }\n};\n","export default {\n    error: {\n        BUSY: 'busy',\n        ERROR: 'error',\n        RESOURCE_CONSTRAINT: 'resource-constraint',\n        UNEXPECTED_REQUEST: 'unexpected-request',\n        SERVICE_UNAVAILABLE: 'service-unavailable'\n    },\n    mode: {\n        FILE: 'file',\n        STREAM: 'stream'\n    },\n    status: {\n        OFF: 'off',\n        ON: 'on',\n        PENDING: 'pending'\n    }\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\tid: moduleId,\n\t\tloaded: false,\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Flag the module as loaded\n\tmodule.loaded = true;\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","__webpack_require__.amdO = {};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.nmd = (module) => {\n\tmodule.paths = [];\n\tif (!module.children) module.children = [];\n\treturn module;\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__(4449);\n"],"names":["root","factory","exports","module","define","amd","self","ljm","require","window","JitsiMeetJS","Object","assign","_mergeNamespaceAndModule","constructor","userId","displayName","isLocalStats","this","_userId","setDisplayName","_isLocalStats","setDominantSpeaker","totalDominantSpeakerTime","_dominantSpeakerStart","_isDominantSpeaker","_isSilent","_hasLeft","_faceLandmarks","getUserId","getDisplayName","newName","isDominantSpeaker","isNowDominantSpeaker","silence","Date","now","timeElapsed","getTotalDominantSpeakerTime","total","hasLeft","markAsHasLeft","getFaceLandmarks","setFaceLandmarks","faceLandmarks","addFaceLandmarks","push","getTokenAuthUrl","urlPattern","roomName","roleUpgrade","replace","EventEmitterForwarder","src","dest","addListener","emit","Error","prototype","forward","args","srcEvent","Function","bind","apply","handlers","oldOnErrorHandler","onerror","oldOnUnhandledRejection","onunhandledrejection","forEach","handler","event","reason","GlobalOnErrorHandler","addHandler","callErrorHandler","error","errHandler","callUnhandledRejectionHandler","randomInt","min","max","Math","floor","random","randomElement","arr","length","RandomUtil","randomHexDigit","randomHexString","len","ret","randomAlphanumStr","result","i","currentExecutingScript","ScriptUtil","loadScript","async","prepend","relativeURL","loadCallback","errorCallback","d","document","tagName","script","createElement","referenceNode","getElementsByTagName","scriptEl","scriptSrc","baseScriptSrc","substring","lastIndexOf","onload","parentNode","insertBefore","appendChild","names","generateUsername","Logger","LogCollector","logStorage","options","stringifyObjects","storeInterval","maxEntryLength","keys","levels","logLevel","_log","arguments","storeLogsIntervalID","queue","totalLen","outputCache","stringify","someObject","JSON","formatLogMessage","msg","arg","ERROR","timestamp","prevMessage","text","count","_flush","start","_reschedulePublishInterval","clearTimeout","setTimeout","flush","force","reschedule","isReady","cachedQueue","storeLogs","stop","consoleTransport","console","globalTransports","addGlobalTransport","transport","indexOf","removeGlobalTransport","transportIdx","splice","globalOptions","log","logger","level","Array","slice","call","callerInfo","disableCallerInfo","methodName","fileLocation","line","column","stack","split","m","match","substr","getCallerInfo","transports","concat","t","l","logPrefixes","toISOString","id","fullLogParts","methods","setGlobalOptions","setLevel","TRACE","DEBUG","INFO","LOG","WARN","idLoggers","loggers","curLevel","getLogger","setLogLevelById","setLogLevel","grammar","v","name","reg","o","format","s","u","e","p","z","r","c","b","a","encoding","rate","address","subtype","direction","config","sessionConfig","str","raddr","tcptype","generation","attribute","value","maxMessageSize","params","RegExp","dir2","clksrcExt","mediaClockValue","rateNumerator","rateDenominator","key","obj","parser","writer","write","parse","parseParams","parseFmtpConfig","parsePayloads","parseRemoteCandidates","parseImageAttributes","parseSimulcastStreamList","toIntIfInt","String","Number","parseReg","location","content","needsBlank","keyLocation","rawName","attachProperties","validLine","test","sdp","session","media","filter","type","rtp","fmtp","j","paramReducer","acc","expr","undefined","reduce","toString","map","candidates","parts","component","ip","port","item","stream","scid","paused","formatRegExp","formatStr","x","makeLine","n","defaultOuterOrder","defaultInnerOrder","opts","version","mLine","payloads","outerOrder","innerOrder","el","join","transform","transformUtils","parseSsrcs","writeSsrcs","DEFAULT_NUM_OF_LAYERS","getSsrcAttribute","ssrc","attributeName","ssrcs","ssrcInfo","Simulcast","numOfLayers","ssrcCache","processVideo","action","isArray","validateDescription","desc","clearSsrcCache","setSsrcCache","_parseSimLayers","simGroup","ssrcGroups","find","group","semantics","ssrcStr","parseInt","_buildNewToOldSsrcMap","newSsrcList","oldSsrcList","ssrcMap","newSsrc","oldSsrc","_fillInSourceDataFromCache","newSimSsrcs","newMsid","newCname","ssrcsToReplace","ssrcsToAdd","values","_generateSourceData","primarySsrc","addAssociatedStream","primarySsrcCname","primarySsrcMsid","usesUnifiedPlan","msid","simSsrcs","simSsrc","_restoreSimulcast","numSsrcs","index","array","numGroups","fidGroup","mungeRemoteDescription","enableConferenceFlag","explodeRemoteSimulcast","sources","order","simulcastSsrcs","cname","relatedGroup","relatedSsrcs","relatedSSRC","simulcastGroup","info","nuke","implodeRemoteSimulcast","invalid","some","assertGoogConference","xGoogleFlag","removeGoogConference","RTCSessionDescription","mungeLocalDescription","source","byteLength","b64","lens","getLens","validLen","placeHoldersLen","toByteArray","tmp","Arr","_byteLength","curByte","revLookup","charCodeAt","fromByteArray","uint8","extraBytes","maxChunkLength","len2","encodeChunk","lookup","Uint8Array","code","end","num","output","defineProperty","enumerable","get","Symbol","toStringTag","__esModule","create","default","hasOwnProperty","getFirstMatch","getSecondMatch","matchAndReturnConst","getWindowsVersionName","getMacOSVersionName","getAndroidVersionName","getVersionPrecision","compareVersions","reverse","getBrowserAlias","BROWSER_ALIASES_MAP","getBrowserTypeByAlias","BROWSER_MAP","ENGINE_MAP","OS_MAP","PLATFORMS_MAP","Bada","BlackBerry","Chrome","Chromium","Epiphany","Firefox","Focus","Generic","Googlebot","Maxthon","Opera","PhantomJS","Puffin","QupZilla","QQ","QQLite","Safari","Sailfish","SeaMonkey","Sleipnir","Swing","Tizen","Vivaldi","WeChat","Roku","amazon_silk","android","bada","blackberry","chrome","chromium","epiphany","firefox","focus","generic","googlebot","google_search","ie","k_meleon","maxthon","edge","mz","naver","opera","opera_coast","phantomjs","puffin","qupzilla","qq","qqlite","safari","sailfish","samsung_internet","seamonkey","sleipnir","swing","tizen","uc","vivaldi","webos","wechat","yandex","tablet","mobile","desktop","tv","WindowsPhone","Windows","MacOS","iOS","Android","WebOS","Linux","ChromeOS","PlayStation4","EdgeHTML","Blink","Trident","Presto","Gecko","WebKit","configurable","writable","getParser","getResult","_ua","parsedResult","getUA","parseBrowser","browser","describe","getBrowser","getBrowserName","toLowerCase","getBrowserVersion","getOS","os","parseOS","getOSName","getOSVersion","getPlatform","platform","parsePlatform","getPlatformType","getEngine","engine","parseEngine","getEngineName","satisfies","isOS","isPlatform","f","isBrowser","compareVersion","isEngine","is","search","versionName","vendor","model","scriptReadyRegex","fullPageUrl","href","pageUrl","scripts","supportsScriptReadyState","isNotOpera","hasNativeCurrentScriptAccessor","stackTraceLimit","Infinity","hasStackBeforeThrowing","hasStackAfterThrowing","getScriptUrlFromStack","skipStackDepth","matches","url","ignoreMessage","round","_nearestExecutingScript","eligibleScripts","readyState","err","getScriptFromUrl","hasAttribute","getSoleInlineScript","currentScript","thrownErr","near","far","origin","ReflectOwnKeys","R","Reflect","ReflectApply","target","receiver","ownKeys","getOwnPropertySymbols","getOwnPropertyNames","NumberIsNaN","isNaN","EventEmitter","init","once","emitter","Promise","resolve","reject","errorListener","removeListener","resolver","eventTargetAgnosticAddListener","flags","on","addErrorHandlerIfEventEmitter","_events","_eventsCount","_maxListeners","defaultMaxListeners","checkListener","listener","TypeError","_getMaxListeners","that","_addListener","events","existing","warning","newListener","unshift","warned","w","warn","onceWrapper","fired","wrapFn","_onceWrap","state","wrapped","_listeners","unwrap","evlistener","unwrapListeners","arrayClone","listenerCount","copy","addEventListener","wrapListener","removeEventListener","set","RangeError","getPrototypeOf","setMaxListeners","getMaxListeners","doError","er","message","context","listeners","prependListener","prependOnceListener","list","position","originalListener","shift","pop","spliceOne","off","removeAllListeners","rawListeners","eventNames","g","flat","y","nodeType","nonce","noModule","C","getAttribute","setAttribute","head","removeChild","T","E","fn","jquery","toArray","pushStack","merge","prevObject","each","first","eq","last","even","grep","odd","sort","extend","isPlainObject","expando","noop","isEmptyObject","globalEval","makeArray","inArray","guid","support","iterator","h","A","N","ue","S","k","D","L","q","O","P","H","I","B","M","W","F","$","_","U","V","X","Q","ID","CLASS","TAG","ATTR","PSEUDO","CHILD","bool","needsContext","Y","G","K","J","Z","ee","te","ne","fromCharCode","re","oe","ae","xe","disabled","nodeName","dir","next","childNodes","se","ownerDocument","exec","getElementById","getElementsByClassName","qsa","ye","scope","be","querySelectorAll","removeAttribute","cacheLength","le","ce","fe","attrHandle","de","sourceIndex","nextSibling","pe","he","ge","isDisabled","ve","isXML","namespaceURI","documentElement","setDocument","defaultView","top","attachEvent","attributes","className","createComment","getById","getElementsByName","getAttributeNode","innerHTML","matchesSelector","webkitMatchesSelector","mozMatchesSelector","oMatchesSelector","msMatchesSelector","disconnectedMatch","compareDocumentPosition","contains","sortDetached","attr","specified","escape","uniqueSort","detectDuplicates","sortStable","getText","textContent","firstChild","nodeValue","selectors","createPseudo","relative","preFilter","lastChild","uniqueID","pseudos","setFilters","not","has","lang","hash","activeElement","hasFocus","tabIndex","enabled","checked","selected","selectedIndex","empty","parent","header","input","button","lt","gt","nth","radio","checkbox","file","password","image","submit","reset","me","we","Ce","Te","Ee","filters","tokenize","compile","selector","select","defaultValue","unique","isXMLDoc","escapeSelector","parseHTML","ready","children","contents","prev","closest","prevAll","add","addBack","parents","parentsUntil","nextAll","nextUntil","prevUntil","siblings","contentDocument","promise","done","fail","then","Callbacks","stopOnFalse","memory","remove","disable","lock","locked","fireWith","fire","Deferred","always","pipe","progress","notify","notifyWith","resolveWith","exceptionHook","stackTrace","rejectWith","getStackHook","when","readyException","readyWait","doScroll","toUpperCase","uid","cache","access","hasData","data","removeData","_data","_removeData","dequeue","_queueHooks","clearQueue","composed","getRootNode","style","display","css","body","show","hide","toggle","createDocumentFragment","checkClone","cloneNode","noCloneChecked","option","thead","col","tr","td","_default","tbody","tfoot","colgroup","caption","th","optgroup","htmlPrefilter","createTextNode","namespace","isTrigger","special","delegateType","stopPropagation","stopImmediatePropagation","preventDefault","trigger","Event","global","handle","triggered","dispatch","bindType","origType","delegateCount","setup","teardown","removeEvent","fix","delegateTarget","preDispatch","isPropagationStopped","currentTarget","elem","isImmediatePropagationStopped","rnamespace","handleObj","postDispatch","addProp","originalEvent","load","noBubble","click","beforeunload","returnValue","isDefaultPrevented","defaultPrevented","relatedTarget","timeStamp","isSimulated","altKey","bubbles","cancelable","changedTouches","ctrlKey","detail","eventPhase","metaKey","pageX","pageY","shiftKey","view","charCode","keyCode","buttons","clientX","clientY","offsetX","offsetY","pointerId","pointerType","screenX","screenY","targetTouches","toElement","touches","which","blur","mouseenter","mouseleave","pointerenter","pointerleave","one","Ae","Ne","Se","ke","De","Le","je","qe","html","clone","_evalUrl","Oe","cleanData","detach","append","before","after","replaceWith","replaceChild","appendTo","prependTo","insertAfter","replaceAll","Pe","He","Ie","opener","getComputedStyle","Re","Be","Me","We","Fe","getPropertyValue","pixelBoxStyles","width","minWidth","maxWidth","$e","cssText","marginLeft","right","offsetWidth","parseFloat","backgroundClip","clearCloneStyle","boxSizingReliable","pixelPosition","reliableMarginLeft","scrollboxSize","reliableTrDimensions","height","borderTopWidth","borderBottomWidth","offsetHeight","ze","_e","Ue","Ve","cssProps","Xe","Qe","Ye","Ge","visibility","Ke","letterSpacing","fontWeight","Je","Ze","ceil","et","getClientRects","cssHooks","opacity","cssNumber","animationIterationCount","columnCount","fillOpacity","flexGrow","flexShrink","gridArea","gridColumn","gridColumnEnd","gridColumnStart","gridRow","gridRowEnd","gridRowStart","lineHeight","orphans","widows","zIndex","zoom","setProperty","isFinite","getBoundingClientRect","left","margin","padding","border","expand","delay","fx","speeds","checkOn","optSelected","radioValue","tt","nt","removeAttr","prop","attrHooks","rt","it","ot","at","st","removeProp","propFix","propHooks","addClass","removeClass","toggleClass","hasClass","ut","val","valHooks","focusin","ct","parentWindow","simulate","triggerHandler","parseXML","DOMParser","parseFromString","ft","dt","pt","ht","vt","param","encodeURIComponent","serialize","serializeArray","wrapAll","firstElementChild","wrapInner","wrap","hidden","visible","createHTMLDocument","implementation","offset","setOffset","using","pageYOffset","pageXOffset","offsetParent","scrollLeft","scrollTop","scrollTo","Height","Width","unbind","delegate","undelegate","hover","yt","proxy","holdReady","parseJSON","isFunction","isWindow","camelCase","isNumeric","trim","mt","jQuery","bt","noConflict","WINDOW","JS_MD5_NO_WINDOW","WEB_WORKER","NODE_JS","JS_MD5_NO_NODE_JS","process","versions","node","COMMON_JS","JS_MD5_NO_COMMON_JS","AMD","ARRAY_BUFFER","JS_MD5_NO_ARRAY_BUFFER","ArrayBuffer","HEX_CHARS","EXTRA","SHIFT","OUTPUT_TYPES","BASE64_ENCODE_CHAR","blocks","buffer8","buffer","Uint32Array","JS_MD5_NO_ARRAY_BUFFER_IS_VIEW","isView","createOutputMethod","outputType","Md5","update","createMethod","method","nodeWrap","crypto","eval","Buffer","nodeMethod","createHash","digest","sharedMemory","h0","h1","h2","h3","bytes","hBytes","finalized","hashed","notString","lastByteIndex","finalize","bc","da","hex","arrayBuffer","base64","v1","v2","v3","base64Str","md5","HASH_UNDEFINED","MAX_SAFE_INTEGER","argsTag","boolTag","dateTag","funcTag","genTag","mapTag","numberTag","objectTag","promiseTag","regexpTag","setTag","stringTag","symbolTag","weakMapTag","arrayBufferTag","dataViewTag","float32Tag","float64Tag","int8Tag","int16Tag","int32Tag","uint8Tag","uint8ClampedTag","uint16Tag","uint32Tag","reFlags","reIsHostCtor","reIsUint","cloneableTags","freeGlobal","freeSelf","freeExports","freeModule","moduleExports","addMapEntry","pair","addSetEntry","arrayReduce","iteratee","accumulator","initAccum","isHostObject","mapToArray","size","overArg","func","setToArray","arrayProto","funcProto","objectProto","coreJsData","maskSrcKey","IE_PROTO","funcToString","objectToString","reIsNative","getPrototype","objectCreate","propertyIsEnumerable","nativeGetSymbols","nativeIsBuffer","isBuffer","nativeKeys","DataView","getNative","Map","Set","WeakMap","nativeCreate","dataViewCtorString","toSource","mapCtorString","promiseCtorString","setCtorString","weakMapCtorString","symbolProto","symbolValueOf","valueOf","Hash","entries","clear","entry","ListCache","MapCache","Stack","__data__","assignValue","object","objValue","assocIndexOf","baseClone","isDeep","isFull","customizer","isObject","isArr","initCloneArray","copyArray","tag","getTag","isFunc","cloneBuffer","isPrototype","proto","initCloneObject","copyObject","getSymbols","copySymbols","baseAssign","cloneFunc","symbol","Ctor","cloneArrayBuffer","dataView","byteOffset","cloneDataView","typedArray","cloneTypedArray","cloneMap","regexp","lastIndex","cloneRegExp","cloneSet","initCloneByTag","stacked","props","keysFunc","symbolsFunc","arrayPush","baseGetAllKeys","getAllKeys","arrayEach","subValue","newValue","getMapData","getValue","baseIsNative","pairs","LARGE_ARRAY_SIZE","isIndex","other","ctorString","isArrayLike","isLength","inherited","isObjectLike","isArrayLikeObject","isArguments","baseTimes","skipIndexes","arrayLikeKeys","baseKeys","NAN","reTrim","reIsBadHex","reIsBinary","reIsOctal","freeParseInt","nativeMax","nativeMin","toNumber","isSymbol","isBinary","wait","lastArgs","lastThis","maxWait","timerId","lastCallTime","lastInvokeTime","leading","maxing","trailing","invokeFunc","time","thisArg","shouldInvoke","timeSinceLastCall","timerExpired","trailingEdge","remainingWait","debounced","isInvoking","leadingEdge","cancel","COMPARE_PARTIAL_FLAG","COMPARE_UNORDERED_FLAG","arrayTag","asyncTag","errorTag","nullTag","proxyTag","undefinedTag","typedArrayTags","freeProcess","nodeUtil","binding","nodeIsTypedArray","isTypedArray","arraySome","predicate","nativeObjectToString","symToStringTag","SetCache","baseGetTag","isOwn","unmasked","getRawTag","baseIsArguments","baseIsEqual","bitmask","equalFunc","objIsArr","othIsArr","objTag","othTag","objIsObj","othIsObj","isSameTag","equalArrays","convert","isPartial","equalByTag","objIsWrapped","othIsWrapped","objUnwrapped","othUnwrapped","objProps","objLength","skipCtor","othValue","compared","objCtor","othCtor","equalObjects","baseIsEqualDeep","arrLength","othLength","seen","arrValue","othIndex","isMasked","resIndex","arrayFilter","baseUnary","isArg","isBuff","isType","SDPUtils","localCName","generateIdentifier","splitLines","blob","splitSections","part","getDescription","sections","getMediaSections","matchPrefix","prefix","parseCandidate","candidate","foundation","protocol","priority","relatedAddress","relatedPort","tcpType","ufrag","usernameFragment","writeCandidate","parseIceOptions","parseRtpMap","parsed","payloadType","clockRate","channels","numChannels","writeRtpMap","codec","preferredPayloadType","parseExtmap","uri","writeExtmap","headerExtension","preferredId","parseFmtp","kv","writeFmtp","parameters","parseRtcpFb","parameter","writeRtcpFb","lines","rtcpFeedback","fb","parseSsrcMedia","sp","colon","parseSsrcGroup","getMid","mediaSection","mid","parseFingerprint","algorithm","getDtlsParameters","sessionpart","role","fingerprints","writeDtlsParameters","setupType","fp","parseCryptoLine","cryptoSuite","keyParams","sessionParams","writeCryptoLine","writeCryptoKeyParams","parseCryptoKeyParams","keyMethod","keySalt","lifeTime","mkiValue","mkiLength","getCryptoParameters","getIceParameters","pwd","writeIceParameters","iceLite","parseRtpParameters","description","codecs","headerExtensions","fecMechanisms","rtcp","mline","rtpmapline","fmtps","writeRtpDescription","kind","caps","maxptime","extension","parseRtpEncodingParameters","encodingParameters","hasRed","hasUlpfec","secondarySsrc","flows","apt","encParam","codecPayloadType","rtx","fec","mechanism","bandwidth","maxBitrate","parseRtcpParameters","rtcpParameters","remoteSsrc","rsize","reducedSize","compound","mux","writeRtcpParameters","parseMsid","spec","track","planB","msidParts","parseSctpDescription","parseMLine","maxSizeLine","sctpPort","fmt","sctpMapLines","writeSctpDescription","sctp","generateSessionId","writeSessionBoilerplate","sessId","sessVer","sessUser","sessionId","getDirection","getKind","isRejected","parseOLine","username","sessionVersion","netType","addressType","isValidSDP","charAt","global$1","WebSocket","WebSocketImplementation","getWebSocketImplementation","DOMParserImplementation","getDOMParserImplementation","getDummyXMLDOMDocument","createDocument","documentMode","doc","docStrings","ActiveXObject","_getIEXmlDom","safe_add$1","lsw","str2binl","bin","md5_cmn","cnt","md5_ff","md5_gg","md5_hh","md5_ii","core_md5","olda","oldb","oldc","oldd","MD5","hexdigest","binarray","hex_tab","binl2hex","binl2str","SASLMechanism","isClientFirst","mechname","onStart","connection","_connection","onChallenge","challenge","clientChallenge","onFailure","onSuccess","utils","out","cookies","cookieName","expires","domain","path","cookieObj","isObj","cookieValue","unescape","cookie","core_sha1","olde","rol","safe_add","sha1_ft","sha1_kt","core_hmac_sha1","bkey","str2binb","ipad","opad","binb2b64","triplet","binb2str","SHA1","b64_hmac_sha1","b64_sha1","str_hmac_sha1","str_sha1","keystr$1","atobLookup","chr","keystr","btoaLookup","abab","atob","accumulatedBits","btoa","groupsOfSix","$build","attrs","Strophe","Builder","$msg","$iq","$pres","VERSION","NS","HTTPBIND","BOSH","CLIENT","AUTH","ROSTER","PROFILE","DISCO_INFO","DISCO_ITEMS","MUC","SASL","STREAM","FRAMING","BIND","SESSION","STANZAS","XHTML_IM","XHTML","tags","validTag","validAttribute","validCSS","Status","CONNECTING","CONNFAIL","AUTHENTICATING","AUTHFAIL","CONNECTED","DISCONNECTED","DISCONNECTING","ATTACHED","REDIRECT","CONNTIMEOUT","BINDREQUIRED","ATTACHFAIL","ErrorCondition","BAD_FORMAT","CONFLICT","MISSING_JID_NODE","NO_AUTH_MECH","UNKNOWN_REASON","LogLevel","FATAL","ElementType","NORMAL","TEXT","CDATA","FRAGMENT","TIMEOUT","SECONDARY_TIMEOUT","addNamespace","forEachChild","elemName","childNode","isTagEqual","_xmlGenerator","xmlGenerator","xmlElement","xmlTextNode","xmlescape","xmlunescape","xmlHtmlNode","loadXML","copyElement","createHtml","cssAttrs","cssName","cssValue","escapeNode","unescapeNode","getNodeFromJid","jid","getDomainFromJid","bare","getBareJidFromJid","getResourceFromJid","_handleError","fatal","sourceURL","fileName","lineNumber","_console","debug","tree","getNamedItem","child","_requestId","_connectionPlugins","addConnectionPlugin","ptype","xmlns","nodeTree","up","moreattrs","cnode","impNode","xmlGen","importNode","newElem","fragment","xhtml","ns","from","matchBare","matchBareFromJid","user","Handler","getNamespace","elNamespace","ignoreNamespaceFragment","namespaceMatch","nsMatch","isMatch","elem_type","run","TimedHandler","period","lastCalled","getTime","Connection","service","setProtocol","features","_sasl_data","do_bind","do_session","mechanisms","timedHandlers","removeTimeds","removeHandlers","addTimeds","addHandlers","protocolErrorHandlers","_idleTimeout","_disconnectTimeout","authenticated","connected","disconnecting","do_authentication","restored","_uniqueId","_sasl_success_handler","_sasl_failure_handler","_sasl_challenge_handler","maxRetries","_onIdle","registerSASLMechanisms","iqFallbackHandler","iq","send","worker","_proto","WorkerWebsocket","Websocket","Bosh","_reset","_requests","pause","resume","getUniqueId","suffix","uuid","addProtocolErrorHandler","status_code","callback","connect","pass","hold","route","authcid","disconnection_timeout","authzid","connect_callback","_changeConnectStatus","_connect","attach","sid","rid","wind","_attach","restore","_sessionCachingSupported","_restore","sessionStorage","setItem","removeItem","xmlInput","xmlOutput","rawInput","rawOutput","nextValidRid","_queueData","_send","sendPresence","errback","timeout","timeoutHandler","stanza","deleteTimedHandler","addTimedHandler","deleteHandler","sendIQ","iqtype","element","_sendRestart","thand","handRef","hand","SASLAnonymous","SASLExternal","SASLOAuthBearer","SASLXOAuth2","SASLPlain","SASLSHA1","registerSASLMechanism","Mechanism","disconnect","pres","_addSysTimedHandler","_onDisconnectTimeout","_disconnect","_abortAllRequests","_doDisconnect","status","condition","plugin","statusChanged","_dataRecv","req","raw","_reqToData","strip","_emptyQueue","cond","conflict","UNKOWN_REASON","_connect_cb","_callback","bodyWrap","hasFeatures","getElementsByTagNameNS","_no_auth_received","matched","authenticate","sortMechanismsByPriority","higher","swap","_attemptSASLAuth","_attemptLegacyAuth","mechanism_found","_addSysHandler","_sasl_success_cb","_sasl_failure_cb","_sasl_challenge_cb","_sasl_mechanism","request_auth_exchange","response","_onLegacyAuthIQResult","_auth2_cb","serverSignature","attribMatch","streamfeature_handlers","wrapper","_onStreamFeaturesAfterSASL","explicitResourceBinding","_onResourceBindResultIQ","resource","jidNode","_establishSession","_onSessionResultIQ","newList","super","auth_str","salt","iter","Hi","U_old","responseText","authMessage","cnonce","clientKey","serverKey","clientSignature","test_cnonce","core","Request","sends","xmlData","origFunc","date","NaN","abort","dead","age","timeDead","xhr","_newXHR","getResponse","responseXML","querySelector","XMLHttpRequest","overrideMimeType","onreadystatechange","_conn","errors","inactivity","lastResponseHeaders","_buildBody","keepalive","_cacheSession","_onRequestStateChange","_throttledRequestHandler","getItem","typ","_sendTerminate","_callProtocolErrorHandlers","reqStatus","_getRequestStatus","err_callback","HTTP","_hitError","time_elapsed","def","getAllResponseHeaders","reqIs0","reqIs1","valid_request","too_many_retries","_removeRequest","_restartRequest","_processRequest","primary_timeout","secondary_timeout","server_error","content_type","contentType","open","sync","setRequestHeader","withCredentials","e2","sendFunc","customHeaders","headers","backoff","pow","abs","new_service","host","pathname","_buildStream","_checkStreamError","connectstatus","errorString","_closeSocket","socket","onopen","_onOpen","_onError","onclose","_onClose","onmessage","_onInitialMessage","_handleStreamStart","ver","streamStart","parsedMessage","see_uri","_replaceMessageHandler","string","_streamWrap","_onMessage","CLOSED","close","closeString","rawStanza","startString","lmap","SharedWorker","postMessage","_messageHandler","ev","_onWorkerMessage","_attachCallback","method_name","_identities","_features","_items","conn","_onDiscoInfo","_onDiscoItems","addIdentity","category","addFeature","var_name","removeFeature","addItem","call_back","success","to","items","_buildIQResult","query_attrs","iqresult","logging","autoSendCountOnEveryIncomingStanza","requestResponseInterval","_c","_NS","_isStreamManagementEnabled","_serverProcesssedStanzasCounter","_clientProcessedStanzasCounter","_clientSentStanzasCounter","_originalXMLOutput","_requestHandler","_incomingHandler","_requestResponseIntervalCount","_isSupported","_unacknowledgedStanzas","_acknowledgedStanzaListeners","addAcknowledgedStanzaListener","enable","_connectionStatus","getResumeToken","_resumeToken","isSupported","_resuming","_originalConnect","_connectArgs","requestAcknowledgement","getOutgoingCounter","getIncomingCounter","_interceptConnectArgs","_originalOnStreamFeaturesAfterSASL","_originalDoDisconnect","_interceptDoDisconnect","_originalDisconnect","_interceptDisconnect","_resumeState","_storedJid","previd","_handleServerRequestHandler","_ackHandler","_handleServerAck","_incomingStanzaHandler","_enabledHandler","_handleEnabled","_resumeFailedHandler","_handleResumeFailed","_resumedHandler","_handleResumed","_increaseSentStanzasCounter","handledCount","_handleAcknowledgedStanzas","_increaseReceivedStanzasCounter","_answerProcessedStanzas","reportedHandledCount","lastKnownHandledCount","delta","_throwError","byteToHex","buf","bth","_v","_v2","_v3","_v4","_interopRequireDefault","getOutputLength","inputLength8","safeAdd","md5cmn","md5ff","md5gg","md5hh","md5ii","length32","hexTab","md5ToHexEncodedArray","wordsToMd5","length8","bytesToWords","getRandomValues","rnds8","msCrypto","ROTL","_rng","_bytesToUuid","_nodeId","_clockseq","_lastMSecs","_lastNSecs","clockseq","seedBytes","rng","msecs","nsecs","tl","tmh","_md","hashfunc","generateUUID","stringToBytes","uuidToBytes","idx","DNS","URL","rnds","_sha","CAMERA","DESKTOP","DESKTOP_HIGH_FPS","NONE","ENVIRONMENT","USER","AV1","H264","OPUS","ULPFEC","VP8","VP9","RTCEvents","CREATE_ANSWER_FAILED","CREATE_OFFER_FAILED","DATA_CHANNEL_OPEN","DATA_CHANNEL_CLOSED","ENDPOINT_CONN_STATUS_CHANGED","DOMINANT_SPEAKER_CHANGED","FORWARDED_SOURCES_CHANGED","PERMISSIONS_CHANGED","SENDER_VIDEO_CONSTRAINTS_CHANGED","LASTN_VALUE_CHANGED","LOCAL_TRACK_SSRC_UPDATED","LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED","TRACK_ATTACHED","REMOTE_TRACK_ADDED","REMOTE_TRACK_MUTE","REMOTE_TRACK_REMOVED","REMOTE_TRACK_UNMUTE","SET_LOCAL_DESCRIPTION_FAILED","SET_REMOTE_DESCRIPTION_FAILED","AUDIO_OUTPUT_DEVICE_CHANGED","DEVICE_LIST_CHANGED","DEVICE_LIST_WILL_CHANGE","DEVICE_LIST_AVAILABLE","ENDPOINT_MESSAGE_RECEIVED","ENDPOINT_STATS_RECEIVED","LOCAL_UFRAG_CHANGED","REMOTE_UFRAG_CHANGED","VIDEO_SSRCS_REMAPPED","AUDIO_SSRCS_REMAPPED","VideoType","IDENTITY_UPDATED","LOCAL_JID","XMPPEvents","JitsiConferenceErrors","AUTHENTICATION_REQUIRED","CHAT_ERROR","SETTINGS_ERROR","CONFERENCE_DESTROYED","CONFERENCE_MAX_USERS","CONNECTION_ERROR","CONFERENCE_RESTARTED","NOT_ALLOWED_ERROR","MEMBERS_ONLY_ERROR","CONFERENCE_ACCESS_DENIED","FOCUS_DISCONNECTED","FOCUS_LEFT","GRACEFUL_SHUTDOWN","ICE_FAILED","INCOMPATIBLE_SERVER_VERSIONS","OFFER_ANSWER_FAILED","PASSWORD_NOT_SUPPORTED","PASSWORD_REQUIRED","REDIRECTED","RESERVATION_ERROR","VIDEOBRIDGE_NOT_AVAILABLE","JitsiConferenceEvents","AUDIO_INPUT_STATE_CHANGE","AUDIO_UNMUTE_PERMISSIONS_CHANGED","AUTH_STATUS_CHANGED","BEFORE_STATISTICS_DISPOSED","CONFERENCE_ERROR","CONFERENCE_FAILED","CONFERENCE_JOIN_IN_PROGRESS","CONFERENCE_JOINED","CONFERENCE_LEFT","CONFERENCE_UNIQUE_ID_SET","CONNECTION_ESTABLISHED","CONNECTION_INTERRUPTED","CONNECTION_RESTORED","DATA_CHANNEL_OPENED","DISPLAY_NAME_CHANGED","CONFERENCE_CREATED_TIMESTAMP","DTMF_SUPPORT_CHANGED","E2EE_VERIFICATION_AVAILABLE","E2EE_VERIFICATION_READY","E2EE_VERIFICATION_COMPLETED","JVB121_STATUS","KICKED","PARTICIPANT_KICKED","PARTICIPANT_SOURCE_UPDATED","LAST_N_ENDPOINTS_CHANGED","LOCK_STATE_CHANGED","SERVER_REGION_CHANGED","_MEDIA_SESSION_STARTED","_MEDIA_SESSION_ACTIVE_CHANGED","MEMBERS_ONLY_CHANGED","MESSAGE_RECEIVED","NO_AUDIO_INPUT","NOISY_MIC","NON_PARTICIPANT_MESSAGE_RECEIVED","PRIVATE_MESSAGE_RECEIVED","PARTCIPANT_FEATURES_CHANGED","PARTICIPANT_PROPERTY_CHANGED","P2P_STATUS","PHONE_NUMBER_CHANGED","PROPERTIES_CHANGED","RECORDER_STATE_CHANGED","VIDEO_SIP_GW_AVAILABILITY_CHANGED","VIDEO_SIP_GW_SESSION_STATE_CHANGED","START_MUTED_POLICY_CHANGED","STARTED_MUTED","SUBJECT_CHANGED","SUSPEND_DETECTED","TALK_WHILE_MUTED","TRACK_ADDED","TRACK_AUDIO_LEVEL_CHANGED","TRACK_MUTE_CHANGED","TRACK_REMOVED","TRACK_UNMUTE_REJECTED","TRANSCRIPTION_STATUS_CHANGED","USER_JOINED","USER_LEFT","USER_ROLE_CHANGED","USER_STATUS_CHANGED","VIDEO_UNMUTE_PERMISSIONS_CHANGED","BOT_TYPE_CHANGED","LOBBY_USER_JOINED","LOBBY_USER_UPDATED","LOBBY_USER_LEFT","AV_MODERATION_APPROVED","AV_MODERATION_REJECTED","AV_MODERATION_CHANGED","AV_MODERATION_PARTICIPANT_APPROVED","AV_MODERATION_PARTICIPANT_REJECTED","BREAKOUT_ROOMS_MOVE_TO_ROOM","BREAKOUT_ROOMS_UPDATED","METADATA_UPDATED","JitsiTrackEvents","LOCAL_TRACK_STOPPED","TRACK_AUDIO_OUTPUT_CHANGED","TRACK_VIDEOTYPE_CHANGED","NO_DATA_FROM_SOURCE","TRACK_STREAMING_STATUS_CHANGED","TRACK_OWNER_CHANGED","CALLSTATS_SCRIPT_URL","JitsiTrackErrors","CONSTRAINT_FAILED","ELECTRON_DESKTOP_PICKER_ERROR","ELECTRON_DESKTOP_PICKER_NOT_FOUND","GENERAL","NOT_FOUND","PERMISSION_DENIED","SCREENSHARING_GENERIC_ERROR","SCREENSHARING_USER_CANCELED","TRACK_IS_DISPOSED","TRACK_NO_STREAM_FOUND","UNSUPPORTED_RESOLUTION","TRACK_ERROR_TO_MESSAGE_MAP","JitsiTrackError","devices","gum","constraints","constraintName","constraint","video","failedConstraintName","mandatory","minHeight","getResolutionFromFailedConstraint","AnalyticsEvents","TYPE_OPERATIONAL","TYPE_PAGE","TYPE_TRACK","TYPE_UI","ACTION_JINGLE_RESTART","ACTION_JINGLE_SA_TIMEOUT","ACTION_JINGLE_SI_RECEIVED","ACTION_JINGLE_SI_TIMEOUT","ACTION_JINGLE_TERMINATE","ACTION_JINGLE_TR_RECEIVED","ACTION_JINGLE_TR_SUCCESS","ACTION_P2P_DECLINED","ACTION_P2P_ESTABLISHED","ACTION_P2P_FAILED","ACTION_P2P_SWITCH_TO_JVB","AVAILABLE_DEVICE","CONNECTION_DISCONNECTED","FEEDBACK","ICE_DURATION","ICE_ESTABLISHMENT_DURATION_DIFF","ICE_STATE_CHANGED","NO_BYTES_SENT","TRACK_UNMUTED","createConnectionFailedEvent","errorType","errorMessage","details","createConferenceEvent","createConnectionStageReachedEvent","stage","actionSubject","createGetUserMediaEvent","createJingleEvent","createP2PEvent","createRemotelyMutedEvent","mediaType","createRtpStatsEvent","Events","AUDIO_LEVEL","BEFORE_DISPOSED","BYTE_SENT_STATS","CONNECTION_STATS","LONG_TASKS_STATS","CHROME","OPERA","FIREFOX","INTERNET_EXPLORER","SAFARI","NWJS","ELECTRON","REACT_NATIVE","UNKNOWN","bowserNameToJitsiName","_detectElectron","userAgent","navigator","JitsiMeetElectron","_detectNWJS","_detectReactNative","product","BrowserDetection","browserInfo","_bowser","Bowser","detectedBrowserInfo","bowser","detectors","_detectChromiumBased","_detect","_name","_version","getName","isChrome","isOpera","isFirefox","isIExplorer","isSafari","isNWJS","isElectron","isReactNative","getVersion","_checkCondition","checkTree","isVersionGreaterThan","isVersionLessThan","isVersionEqualTo","DummyLocalStorage","_storage","keyName","keyValue","jitsiLocalStorage","localStorage","_localStorageDisabled","ignore","isLocalStorageDisabled","dontEmitChangedEvent","localStorageContent","doesVideoMuteByStreamRemove","isChromiumBased","isWebKitBased","isIosBrowser","maxTouchPoints","Boolean","mediaDevices","getUserMedia","RTCRtpTransceiver","isTwa","matchMedia","_getSafariVersion","_getChromiumBasedVersion","isSupportedAndroidBrowser","isSupportedIOSBrowser","_getIOSVersion","isUserInteractionRequiredForUnmute","supportsVideoMuteOnConnInterrupted","supportsBandwidthStatistics","supportsCodecPreferences","RTCRtpReceiver","getCapabilities","supportsDeviceChangeEvent","ondevicechange","supportsPerformanceObserver","PerformanceObserver","supportedEntryTypes","supportsReceiverStats","supportsRTTStatistics","supportsTrackBasedStats","supportsVP9","usesSdpMungingForSimulcast","usesRidsForSimulcast","supportsGetDisplayMedia","getDisplayMedia","supportsEncodedTransform","RTCRtpScriptTransform","supportsInsertableStreams","RTCRtpSender","createEncodedStreams","ReadableStream","supportsAudioRed","mimeType","supportsUnifiedPlan","supportsVADDetection","supportsRTX","ua","disposed","analyticsHandlers","permanentProperties","conferenceName","addPermanentProperties","dispose","setAnalyticsHandlers","_setUserProperties","_sendEvent","setUserProperties","properties","setConferenceName","sendEvent","eventName","_verifyRequiredFields","objectType","containerType","containerId","objectId","_maybeCacheEvent","wrtcFuncNames","reportType","_fabrics","CallStats","backend","backendInitialized","atLeastOneFabric","defaultInstance","callStatsInstance","fabrics","hasFabric","_addNewFabric","_emptyReportQueue","csInstance","defaultConfID","confID","defaultPC","peerconnection","report","reportsQueue","errorData","_reportError","pc","eventData","sendFabricEvent","associateMstWithUserID","callStatsId","usageLabel","cs","_error","reportError","theBackend","tryCatchMethods","originalMethod","theArguments","debugMethods","originalReportError","exception","CallStatsBackend","callstats","_traceAndCatchBackendCalls","userID","aliasName","userName","callStatsID","callStatsSecret","configParams","applicationName","applicationVersion","siteID","initialize","_initCallback","devicesData","_reportEvent","conferenceID","overall","comment","sendUserFeedback","mute","tpc","remoteUserID","fabricAttributes","remoteEndpointType","isP2P","endpointType","peer","server","addNewFabric","fabricUsage","multiplex","_addNewFabricCallback","associateStreamWithVideoTag","isLocal","streamEndpointId","sendDominantSpeakerEvent","sendTerminateEvent","fabricEvent","fabricTerminated","delete","sendIceConnectionFailedEvent","sendCreateOfferFailed","sendCreateAnswerFailed","sendResumeOrHoldEvent","isResume","sendScreenSharingEvent","sendSetLocalDescFailed","sendSetRemoteDescFailed","sendAddIceCandidateFailed","AudioContext","webkitAudioContext","LocalStatsCollector","interval","intervalId","intervalMilis","audioLevel","analyser","safeCounterIncrement","number","nextValue","calculateAverage","valueArray","filterPositiveValues","isLocalStatsSupported","createAnalyser","smoothingTimeConstant","fftSize","createMediaStreamSource","setInterval","frequencyBinCount","getByteTimeDomainData","samples","maxVolume","toFixed","timeDomainDataToAudioLevel","newLevel","lastLevel","diff","animateLevel","clearInterval","disconnectAudioContext","connectAudioContext","suspend","RunningAverage","average","addNext","getAverage","PerformanceObserverStats","statsInterval","eventEmitter","longTasks","maxDuration","performanceStatsInterval","stats","getLongTasksStats","avgRatePerMinute","maxDurationMs","startObserver","longTaskEventHandler","getEntries","task","duration","observer","observe","buffered","startTime","longTasksIntervalId","_lastTimeStamp","StatisticsEvents","stopObserver","MediaType","_runInLiteMode","runInLiteMode","_ssrcRewriting","ssrcRewritingEnabled","_joinAsVisitor","enableJoinAsVisitor","isMultiStreamSendSupportEnabled","isRunInLiteModeEnabled","isSsrcRewritingSupported","isJoinAsVisitorSupported","calculatePacketLoss","lostPackets","totalPackets","SsrcStats","loss","bitrate","download","upload","resolution","framerate","ConferenceStats","packetLoss","StatsCollector","audioLevelsInterval","currentStatsReport","previousStatsReport","audioLevelReportHistory","audioLevelsIntervalId","conferenceStats","audioLevelsIntervalMilis","speakerList","statsIntervalId","statsIntervalMilis","ssrc2stats","setLoss","setResolution","addBitrate","resetBitrate","setFramerate","setCodec","setSpeakerList","startAudioLevelStats","audioLevels","getAudioLevels","processStats","getStats","processStatsReport","catch","_processAndEmitReport","bitrateDownload","bitrateUpload","resolutions","framerates","audioBitrateDownload","audioBitrateUpload","videoBitrateDownload","videoBitrateUpload","ssrcStats","isDownloadStream","packetsTotal","packetsLost","getTrackBySSRC","audioCodec","videoCodec","isAudioTrack","participantId","getParticipantId","FeatureFlags","userCodecs","audio","isVideoTrack","userResolutions","doesTrueSimulcast","localSsrcs","getLocalVideoSSRCs","localSsrc","ssrcResolution","userFramerates","avgAudioLevels","localAvgAudioLevels","avgAudioLevel","sum","currentValue","getNonNegativeValue","_calculateBitrate","fieldName","bytesNow","bytesBefore","bytesProcessed","timeMs","bitrateKbps","_calculateFps","frameRate","byteSentStats","nominated","availableIncomingBitrate","availableOutgoingBitrate","remoteUsedCandidate","remoteCandidateId","localUsedCandidate","localCandidateId","localip","conferenceStatsTransport","p2p","localCandidateType","candidateType","remoteCandidateType","networkType","rtt","currentRoundTripTime","packetsNow","packetsBefore","packetsDiff","packetsLostNow","packetsLostBefore","packetsLostDiff","frameHeight","frameWidth","isStreamActive","active","framesPerSecond","bytesSent","codecId","codecShortType","VIDEO","remoteSource","localVideoTracks","getLocalTracks","getSsrcByTrackId","trackIdentifier","_instances","isCallstatsLoaded","_initCallStatsBackend","isBackendInitialized","initBackend","Statistics","xmpp","rtpStatsMap","callStatsIntegrationEnabled","disableThirdPartyRequests","callStatsApplicationLogsDisabled","customScriptUrl","loadCallStatsAPI","callsStatsInstances","instances","audioLevelsEnabled","disableAudioLevels","pcStatsInterval","longTasksStatsInterval","analytics","startRemoteStats","stopRemoteStats","rtpStats","RTPStats","localStats","startLocalStats","localStat","LocalStats","stopLocalStats","getOriginalStream","addAudioLevelListener","removeAudioLevelListener","addBeforeDisposedListener","removeBeforeDisposedListener","addConnectionStatsListener","removeConnectionStatsListener","addByteSentStatsListener","removeByteSentStatsListener","addLongTasksStatsListener","attachLongTasksStats","conference","performanceObserverStats","removeLongTasksStatsListener","callStats","stopCallStats","tpcId","_stopRemoteStats","startCallStats","endsWith","newInstance","_getAllCallStatsInstances","csInstances","statistics","isCallstatsEnabled","sendConnectionResumeOrHoldEvent","instance","sendMuteEvent","muted","roomJid","sendActiveDeviceListEvent","globalSet","sendGetUserMediaFailed","formatJitsiTrackErrorForCallStats","sendLog","globalSubSet","csPerStats","sendApplicationLog","sendFeedback","rating","reportGlobalError","sendAnalyticsAndLog","eventToLog","sendAnalytics","JitsiConferenceEventManager","xmppListeners","p2pJingleSession","jvbJingleSession","isMuted","getType","setupChatRoomListeners","chatRoom","room","chatRoomForwarder","jingleSession","rtc","closeBridgeChannel","participant","getParticipantById","setFeatures","offerIq","_setBridgeChannel","actor","AUDIO","mutedByFocusActor","setAudioMute","isMutedByFocus","mutedVideoByFocusActor","setVideoMute","isVideoMutedByFocus","_onMucJoined","isJvbConnectionInterrupted","connectionTimes","leave","_onConferenceRestarted","_onIceConnectionFailed","getStatus","setTerminator","setInitiator","setParticipantPropertyListener","onMemberKicked","onSuspendDetected","onMemberJoined","_onMemberBotTypeChanged","onMemberLeft","onDisplayNameChanged","onLocalRoleChanged","isModerator","recorderSession","logObject","getError","onUserRoleChanged","AuthenticationEvents","authEnabled","authIdentity","txt","myJid","ts","nick","isGuest","_status","payload","addPresenceListener","myUserId","startAudioMuted","startVideoMuted","updated","startMutedPolicy","setupRTCListeners","onRemoteTrackAdded","onRemoteTrackRemoved","dominant","previous","lastDominantSpeaker","dominantSpeakerIsSilent","roomjid","performance","getMediaSessions","processSourceMap","videoType","removeXMPPListeners","setupXMPPListeners","_addConferenceXMPPListener","onIncomingCall","onCallAccepted","onTransportInfo","onCallEnded","audioMuted","videoMuted","ignoreStartMuted","createdTimestamp","actorJid","actorParticipant","getParticipants","getJid","setupStatisticsListeners","setAudioLevel","startSilent","getLocalSSRC","onByteSentStatsReceived","JitsiParticipant","statsID","identity","isReplacing","isReplaced","_jid","_id","_conference","_displayName","_supportsDTMF","_tracks","_role","_hidden","_statsID","_properties","_identity","_isReplacing","_isReplaced","_sources","_isMediaTypeMuted","getTracks","_setSources","sourceName","sourceByMediaType","sourceInfo","getBotType","_botType","getConference","getConnectionJid","_connectionJid","getFeatures","getId","getProperty","getRole","getSources","getStatsID","getTracksByMediaType","hasFeature","feature","isAudioMuted","isHidden","isHiddenFromRecorder","isVideoMuted","setBotType","newBotType","setConnectionJid","newJid","newFeatures","setIsReplaced","newIsReplaced","setIsReplacing","newIsReplacing","oldValue","setRole","newRole","supportsDTMF","JitsiConnectionEvents","CONNECTION_FAILED","WRONG_STATE","DISPLAY_NAME_REQUIRED","JitsiConnectionErrors","CONNECTION_DROPPED_ERROR","OTHER_ERROR","SERVER_ERROR","clearRejectTimeout","_timeout","setRejectTimeout","ms","Listenable","kJitsiE2EE","E2EEcontext","sharedKey","baseUrl","workerUrl","workerBlob","Blob","createObjectURL","_worker","Worker","operation","cleanup","cleanupAll","handleReceiver","receiverStreams","readableStream","readable","writableStream","handleSender","sender","senderStreams","setKey","keyIndex","KeyHandler","e2eeCtx","E2EEContext","_enabling","_onMediaSessionStarted","_onLocalTrackAdded","_setupReceiverE2EEForTrack","_trackMuteChanged","isEnabled","_setEnabled","setLocalParticipantProperty","_restartMediaSessions","setEncryptionKey","_setupSenderE2EEForTrack","localTracks","findReceiverForTrack","findSenderForTrack","ExternallyManagedKeyHandler","keyInfo","encryptionKey","v4","E2EEErrors","emojiMapping","sasGenerators","decimal","sasBytes","emoji","REQ_TIMEOUT","OLM_MESSAGE_TYPE","OLM_MESSAGE_TYPES","OLM_KEY_VERIFICATION_MAC_INFO","OLM_KEY_VERIFICATION_MAC_KEY_IDS","kOlmData","OlmAdapterEvents","PARTICIPANT_E2EE_CHANNEL_READY","PARTICIPANT_SAS_AVAILABLE","PARTICIPANT_SAS_READY","PARTICIPANT_KEY_UPDATED","PARTICIPANT_VERIFICATION_COMPLETED","OlmAdapter","_conf","_init","_mediaKey","_mediaKeyIndex","_reqs","_sessionInitialization","_bootstrapOlm","_onEndpointMessageReceived","_onConferenceLeft","_onParticipantLeft","_onParticipantPropertyChanged","myId","promises","localParticipantId","FEATURE_E2EE","_sendSessionInit","allSettled","Olm","pId","olmData","_getParticipantOlmData","uuidv4","JITSI_MEET_MUC_TYPE","olm","ciphertext","_encryptKeyInfo","_sendMessage","updateCurrentMediaKey","clearParticipantSession","free","clearAllParticipantsSessions","markParticipantVerified","isVerified","sasVerification","E2EE_SAS_CHANNEL_VERIFICATION_FAILED","E2EE_SAS_INVALID_SAS_VERIFICATION","sas","sasMacSent","is_their_key_set","_sendSasMac","_olmAccount","Account","_idKeys","identity_keys","get_library_version","_onIdKeysReady","startVerification","SAS","transactionId","startContent","isInitiator","startMessage","idKeys","keyType","_onParticipantE2EEChannelReady","base64js","encrypt","_sendError","Session","create_outbound","idKey","otKey","ack","pendingSessionUuid","create_inbound","remove_one_time_keys","decrypt","json","safeJsonParse","lastKey","isEqual","pubKey","get_pubkey","commitment","_computeCommitment","acceptMessage","sasCommitment","keyMessage","keySent","theirKey","E2EE_SAS_COMMITMENT_MISMATCHED","set_their_key","myInfo","theirInfo","generatedSas","generateSas","generate_bytes","mac","baseInfo","calculate_mac","E2EE_SAS_KEYS_MAC_MISMATCH","ed25519","E2EE_SAS_MISSING_KEY","computedMac","E2EE_SAS_MAC_MISMATCH","isE2EEEnabled","sendMessage","generate_one_time_keys","otKeys","one_time_keys","curve25519","mark_keys_as_published","keyList","deviceKeyId","macMessage","olmUtil","Utility","sha256","ManagedKeyHandler","_key","_conferenceJoined","_olmAdapter","_rotateKey","debounce","_rotateKeyImpl","_ratchetKey","_ratchetKeyImpl","_onParticipantKeyUpdated","_onParticipantSasReady","_onParticipantSasAvailable","_onParticipantVerificationCompleted","_onParticipantJoined","initSessions","_generateKey","updateKey","material","keyBytes","subtle","importKey","newKey","textEncoder","TextEncoder","deriveBits","encode","ratchet","updateCurrentKey","E2EEncryption","e2ee","_externallyManaged","externallyManagedKey","_keyHandler","testing","disableE2EE","enableEncodedTransformSupport","setEnabled","IDENTITY_PROPERTIES","IDENTITY_PROPERTIES_FOR_COMPARE","compareIdentities","res","parseDiscoInfo","identities","Caps","disco","rooms","externalFeatures","emuc","_addChatRoom","_removeChatRoom","external","_generateVersion","_updateRoomWithExternalFeatures","removeFromPresence","addOrReplaceInPresence","getFeaturesAndIdentities","_getDiscoInfo","_fixChatRoomPresenceMap","_notifyVersionChanged","sortedIdentities","accumulatedValue","sortedFeatures","sha1","generateSha","NETWORK_INFO_EVENT","_current","isOnline","updateNetworkInfo","ResumeTask","stropheConnection","_stropheConn","_resumeRetryN","_retryDelay","retryDelay","schedule","_cancelResume","_networkOnlineListener","NetworkInfo","_scheduleResume","_resumeTimeout","retry","minDelay","base","getJitterDelay","_resumeConnection","streamManagement","resumeToken","pattern","oldToken","LastRequestTracker","_lastSuccess","_lastFailedMessage","startTracking","xmppConnection","originalRawInput","rawMessage","includes","getLastFailedMessage","getTimeSinceLastSuccess","getConnectionPluginDefinition","ConnectionPluginListenable","PingConnectionPlugin","ConnectionPlugin","getTimeSinceLastServerResponse","onPingThresholdExceeded","pingOptions","failedPings","_onPingThresholdExceeded","_getTimeSinceLastServerResponse","pingInterval","pingTimeout","pingThreshold","threshold","pingTimestampsToKeep","pingExecIntervals","ping","_addPingExecutionTimestamp","sendIQ2","startInterval","remoteJid","_lastServerCheck","errmsg","stopInterval","getPingSuspendTime","pingIntervals","maxInterval","previousTS","currentInterval","XmppConnection","CONN_STATUS_CHANGED","CONN_SHARD_CHANGED","enableWebsocketResume","websocketKeepAlive","websocketKeepAliveUrl","serviceUrl","shard","xmppPing","_options","_usesWebsocket","startsWith","_rawInputTracker","LastSuccessTracker","_resumeTask","_deferredIQs","_onPingErrorThresholdExceeded","_oneSuccessfulConnect","websocket","isUsingWebSocket","OPEN","pingDomain","_maybeStartWSKeepAlive","_stropheConnectionCb","targetCallback","blockCallback","_maybeEnableStreamResume","_keepAliveAndCheckShard","_processDeferredIQs","_tryResumingConnection","_wsKeepAlive","_clearDeferredIQs","deferred","closeWebsocket","intervalWithJitter","fetch","responseShard","timeLeft","sendUnavailableBeacon","sendBeacon","JitsiTranscriptionStatus","ON","OFF","AVModeration","_xmpp","_mainRoom","_moderationEnabledByType","_whitelistAudio","_whitelistVideo","avModerationComponentAddress","approve","jidToWhitelist","jidToBlacklist","removed","approved","whitelists","newWhitelists","oldList","FEATURE_KEY","BREAKOUT_ROOM_ACTIONS","ADD","REMOVE","MOVE_TO_ROOM","BREAKOUT_ROOM_EVENTS","BreakoutRooms","_handleMessages","_rooms","createBreakoutRoom","subject","removeBreakoutRoom","breakoutRoomJid","sendParticipantToRoom","participantJid","getComponentAddress","breakoutRoomsComponentAddress","_setIsBreakoutRoom","isBreakoutRoom","_isBreakoutRoom","myroomjid","_setMainRoomJid","_mainRoomJid","getMainRoomJid","filteredPayload","_filterUpdatePayload","hiddenDomain","filteredRooms","participants","filteredParticipants","EMAIL_COMMAND","Lobby","mainRoom","maybeJoinLobbyRoom","_maybeJoinLobbyRoom","lobbyRoomJid","lobbySupported","setMembersOnly","lobbyRoom","membersOnlyEnabled","sendPrivateMessage","getLocalId","addMessageListener","removeMessageHandler","setLobbyRoomJid","joined","email","customDomain","createRoom","disableDiscoInfo","disableFocus","enableLobby","isHiddenDomain","botType","members","getBreakoutRooms","avatar","clean","isSelfPresence","invitePassword","denyAccess","kick","approveAccess","mainRoomJid","memberRoomJid","msgToSend","RoomMetadata","_metadata","setMetadata","getMetadata","roomMetadataComponentAddress","metadata","_callStatsUserName","_machineId","externalStorage","callStatsUserName","UsernameGenerator","generateCallStatsUserName","machineId","amDid","jitsiMeetId","_p8","generateJitsiMeetId","createExpBackoffTimer","step","Moderator","Settings","getNextTimeout","getNextErrorTimeout","externalAuthEnabled","sipGatewayEnabled","targetJid","hosts","targetUrl","conferenceRequestUrl","mode","focusUserJids","focusUserJid","isFocusJid","focusJid","isExternalAuthEnabled","isSipGatewayEnabled","_createConferenceRequest","rtcstatsEnabled","conferenceRequest","machineUid","_createConferenceIq","_parseConferenceIq","resultIq","vnode","authentication","externalAuth","sendConferenceRequest","_handleIqSuccess","_handleIqError","ok","resultJson","_handleSuccess","statusText","sessionError","notAuthorized","authenticationEnabled","iAmRecorder","iAmSipGateway","waitMs","reservationErr","errorCode","errorTextNode","errorMsg","invalidSession","anonymousdomain","errorIq","getLoginUrl","urlCallback","failureCallback","_getLoginUrl","popup","urlCb","failureCb","decodeURIComponent","getPopupLoginUrl","logout","logoutUrl","packet2JSON","nodes","json2packet","packet","filterNodeFromPresenceJSON","MEMBERS_AFFILIATIONS","extractIdentityInformation","hiddenFromRecorderFeatureEnabled","userInfo","groupInfo","ChatRoom","replaceParticipant","presMap","presHandlers","_removeConnListeners","inProgressEmitted","focusMucJid","noBridgeAvailable","moderator","lobby","avModeration","breakoutRooms","roomMetadata","initPresenceMap","lastPresences","phoneNumber","phonePin","participantPropertyListener","transcriptionStatus","xns","statsId","presenceUpdateTime","onConnStatusChanged","fromJoin","billingId","presenceSyncTime","doLeave","discoRoomInfo","getInfo","meetingIdValEl","setMeetingId","membersOnly","lobbyRoomField","isBreakoutField","breakoutMainRoomField","roomMetadataEl","roomMetadataText","meetingId","createNonAnonymousRoom","getForm","form","formSubmit","onPresence","member","statusEl","hasStatusUpdate","hasVersionUpdate","xElement","mucUserItem","isReplaceParticipant","affiliation","isFocus","fromHiddenDomain","presence","xEl","_extractFeatures","_initFocus","memberOfThis","displayJids","restartByTerminateSupported","supportsRestartByTerminate","att","phone","pin","processNode","var","focusFeatures","tagHandlers","elementName","setSubject","onPresenceUnavailable","destroySelect","reasonSelect","isKick","membersKeys","actorSelect","actorNick","onMessage","settingsErrorMsg","subjectText","stamp","dateParts","invite","passwordSelect","jsonMessage","parsedJson","tryParseJSONAndVerify","nickEl","onPresenceError","lobbyRoomNode","lobbyRoomOldNode","setAffiliation","grantIQ","kickIQ","lockRoom","onError","onNotSupported","formsubmit","formToSubmit","addToPresence","matchingNodes","getFromPresence","removePresenceListener","handlerIdx","mucJid","onVisitorIQ","visitors","getMediaPresenceInfo","endpointId","mutedNode","codecTypeNode","videoTypeNode","codecType","getMemberRole","peerJid","getLastPresence","mucNick","dial","rayo","hangup","getLobby","getAVModeration","getMetadataHandler","getPhoneNumber","getPhonePin","getMeetingId","muteParticipant","iqToFocus","onMute","onMuteVideo","onMucLeft","doReject","endConferenceComponentAddress","MucConnectionPlugin","onVisitors","isRoomCreated","_createSourceExtension","owner","sourceCompactJson","_createSsrcGroupExtension","ssrcGroupCompactJson","_getOrCreateRtpDescription","jingle","expandSourcesFromJson","jsonMessageXml","audioRtpDescription","videoRtpDescription","ownerSources","videoSources","videoSsrcGroups","audioSources","audioSsrcGroups","MediaDirection","obtainStream","_createObtainStreamMethod","JitsiMeetNW","obtainDesktopStream","jitsiError","obtainScreenOnElectron","obtainScreenFromGetDisplayMediaRN","obtainScreenFromGetDisplayMedia","_getAudioConstraints","audioQuality","stereo","autoGainControl","channelCount","echoCancellation","noiseSuppression","JitsiMeetScreenObtainer","openDesktopPicker","desktopSharingFrameRate","desktopSharingResolution","desktopSharingSources","streamId","streamType","audioConstraints","optionalConstraints","optional","chromeMediaSource","chromeMediaSourceId","minFrameRate","maxFrameRate","screen","maxHeight","sourceId","sourceType","surfaceSwitching","cursor","errorDetails","errorName","errorStack","setDesktopSharingFrameRate","maxFps","SDPUtil","filterSpecialChars","iceparams","mediadesc","sessiondesc","findLine","parseICEUfrag","parseICEPwd","buildICEUfrag","frag","buildICEPwd","parseMID","parseMSIDAttribute","ssrcLines","msidLine","buildMLine","parseRTPMap","clockrate","parseSCTPMap","parseSCTPPort","buildRTPMap","parseCrypto","fingerprint","parseICECandidate","elems","network","buildICECandidate","cand","hasOwnAttribute","parseSSRC","parseSourceNameLine","sourceNameLine","ssrcSdpLine","parseVideoTypeLine","videoTypeLine","parseRTCPFB","haystack","needle","findLines","needles","candidateToJingle","candidateFromJingle","parsePrimaryVideoSsrc","videoMLine","generateSsrc","ssrcLine","parseGroupSsrcs","ssrcGroup","getMedia","getUfrag","ufragLines","preferCodec","codecName","matchingPayloadTypes","payloadTypes","payloadIndex","stripCodec","highProfile","h264Pts","removePts","stripH264HighCodec","CodecMimeType","rtxApts","rtxPts","keepPts","INACTIVE","rtcpFb","SDP","mediaI","arrayEquals","array1","array2","equals","SDPDiffer","mySDP","otherSDP","failICE","removeTcpCandidates","removeUdpCandidates","addMlineForNewLocalSource","clonedeep","RECVONLY","groups","mids","getMediaSsrcMap","mediaSSRCs","mediaindex","linessrc","containsSSRC","medias","toJingle","thecreator","assrcline","creator","amidline","initialLastN","rtpmap","afmtpline","fmtpParameters","rtcpFbToJingle","availableSsrc","ssrcParameters","ridLines","rids","ridLine","ridInfo","extmapLines","extmap","SENDONLY","senders","SENDRECV","transportToJingle","sctpport","sctpmap","sctpAttrs","streams","setupLine","iceParameters","payloadtype","feedback","rtcpFbFromJingle","feedbackElementTrrInt","fromJingle","jingle2media","__","hdrExt","userSources","nonUserSources","isUserSource","sourceStr","getNewMedia","myMedias","othersMedias","newMedia","othersMediaIdx","myMedia","othersMedia","otherSsrcGroup","mySsrcGroup","modify","sdpMediaSsrcs","modified","ssrcNum","mediaSsrc","hasQueueMicrotask","queueMicrotask","hasSetImmediate","setImmediate","hasNextTick","nextTick","fallback","defer","setImmediate$1","handlePromise","invokeCallback","isAsync","wrapAsync","asyncFn","awaitify","arity","cbArgs","applyEach","eachfn","fns","callArgs","cb","_asyncMap","results","counter","_iteratee","iterCb","breakLoop","callFn","onlyOnce","asyncEachOfLimit","generator","limit","canceled","awaiting","running","replenish","iterDone","iterateeCallback","handleError","eachOfLimit","asyncIterator","isAsyncIterable","nextElem","coll","createArrayIterator","okeys","getIterator","createES2015Iterator","createIterator","looping","eachOfLimit$2","eachOfArrayLike","completed","iteratorCallback","eachOfGeneric","eachOf$1","map$1","eachOfSeries$1","DLL","tail","removeLink","newNode","setInitial","cur","testFn","curr","dll","concurrency","numRunning","workersList","drain","saturated","unsaturated","processingScheduled","_insert","insertAtFront","rejectOnError","rej","promiseCallback","started","_tasks","_createCB","tasks","idle","_maybeDrain","eventMethod","handleAndRemove","isProcessing","datum","pushAsync","kill","unshiftAsync","defineProperties","memo","mapLimit$1","concatLimit$1","mapResults","_createTester","check","testResult","testPassed","consoleFunc","resultArgs","_withoutIndex","_fn","_test","truth","eachLimit$2","eachSeries$1","filterArray","truthValues","filterGeneric","_filter","innerArgs","ensureAsync","newObj","taskCb","Heap","heap","pushCount","MIN_SAFE_INTEGER","percUp","smaller","percDown","criteria","comparator","rest","taskIndex","nextTask","AsyncQueue","_queue","_processQueueTasks","_stopped","finishedCallback","shutdown","JingleSessionState","PENDING","ACTIVE","ENDED","JingleSession","localJid","mediaConstraints","pcConfig","usedrip","dripContainer","_signalingLayer","initiatorJid","responderJid","signalingLayer","doInitialize","addIceCandidates","getState","addSources","removeSources","terminate","failure","acceptOffer","MediaSessionEvents","IQ_TIMEOUT","_addSourceElement","ssrc_","JingleSessionPC","jingleContents","videoContents","receiverConstraints","sourceFrameHeightSel","_bridgeSessionId","_cachedOldLocalSdp","_cachedNewLocalSdp","_iceCheckingStartedTimestamp","_gatheringStartedTimestamp","_sourceReceiverConstraints","_localVideoActive","_remoteVideoActive","_gatheringReported","lasticecandidate","closed","remoteRecvMaxFrameHeight","numRemoteVideoSources","numRemoteAudioSources","remoteSourceMaxFrameHeights","modificationQueue","wasConnected","establishmentDuration","_xmppListeners","onXmppStatusChanged","_removeSenderVideoConstraintsChangeListener","_assertNotEnded","isReconnect","wasstable","webrtcIceUdpDisable","webrtcIceTcpDisable","pcOptions","disableRtx","gatherStats","maxstats","capScreenshareBitrate","codecSettings","enableInsertableStreams","videoQuality","forceTurnRelay","disableSimulcast","preferredCodec","createPeerConnection","onicecandidate","phase","initiator","sendIceCandidate","onsignalingstatechange","signalingState","connectionState","oniceconnectionstatechange","isStable","iceConnectionState","reconnect","usesTerminateForRestart","enableIceRestart","iceStarted","onconnectionstatechange","icestate","onnegotiationneeded","remoteDescription","workFunction","oldSdp","localDescription","_renegotiate","newSdp","notifyMySSRCUpdate","getRemoteRecvMaxFrameHeight","getRemoteSourcesRecvMaxFrameHeight","localSDP","ice","sdpMLineIndex","jcand","errorMesssage","sendIceCandidates","cands","sdpMid","fingerprintLine","required","newJingleErrorHandler","sendIceFailedNotification","sessionInfo","iceCandidates","rtcCandidate","RTCIceCandidate","iceCandidate","addIceCandidate","outerHTML","readSsrcInfo","ssrcElement","setTrackSourceName","setSSRCOwner","i3","ssrcInfoElement","jidOrEndpointId","generateRecvonlySsrc","getConfiguredVideoCodec","jingleOffer","setOfferAnswerCycle","sendSessionAccept","videoTracks","addTracks","addTrack","all","createOffer","offerSdp","setLocalDescription","processLocalSdpForTransceiverInfo","sendSessionInitiate","setAnswer","jingleAnswer","newRemoteSdp","_processNewJingleOfferIq","oldLocalSdp","setRemoteDescription","newLocalSdp","sendContentModify","jingleOfferAnswerIq","audioTracks","tracks","bridgeSessionId","_responderRenegotiate","setVideoCodecs","preferred","replaceTransport","jingleOfferElem","enableForcedReload","sendTransportAccept","originalOffer","newFingerprint","channelLastN","accept","responder","sessionModify","setReceiverVideoConstraint","sourceReceiverConstraints","transportAccept","medialines","sendTransportReject","transportReject","setSenderVideoConstraint","maxFrameHeight","jitsiLocalTrack","getLocalVideoTracks","getSourceName","getLocalVideoTrack","setSenderVideoConstraints","sendSessionTerminate","sessionTerminate","reasonDescription","restart","requestRestart","onTerminated","reasonCondition","reasonText","getRemoteTracks","_parseSsrcInfoFromSourceAdd","sourceAddElem","currentRemoteSdp","addSsrcInfo","i1","midFound","i2","addRemoteStream","_addOrRemoveRemoteStream","removeRemoteStream","newSources","mappedSources","addRemoteSsrc","setSourceName","setOwner","_setVideoType","peerMediaInfo","getPeerMediaInfo","_sourceMutedChanged","removeRemoteStreamsOnLeave","finishCallback","removeSsrcInfo","getRemoteSourceInfoByParticipant","_processRemoteRemoveSource","newLocalSDP","isAdd","logPrefix","errMsg","addOrRemoveSsrcInfo","_parseSsrcInfoFromSourceRemove","_processRemoteAddSource","remoteSdp","findIndex","desiredDirection","getDesiredMediaDirection","removeSSRCOwners","optionalRemoteSdp","_initiatorRenegotiate","createAnswer","answer","offer","replaceTracks","oldLocalSDP","recvOnlyTransceiver","getTransceivers","currentDirection","replaceTrack","setMediaTransferActive","tpcUtils","audioTransferActive","videoTransferActive","oldTrack","newTrack","clearRecvonlySsrc","shouldRenegotiate","sourceRemoveElem","_verifyNoSSRCChanged","operationName","oldSDP","currentLocalSDP","sdpDiff","addedMedia","removedMedia","addTrackToPc","_addRemoveTrack","configureSenderVideoEncodings","removeTrackFromPc","isRemove","setP2pVideoTransferActive","videoActive","logVideoStr","isSessionActive","setVideoTransferActive","modifyContents","newVideoSenders","parseVideoSenders","sourceMaxFrameHeights","parseSourceMaxFrameHeight","_modifyRemoteVideoActive","remoteVideoSenders","isRemoteVideoActive","newSDP","getSignaledSourceInfo","sdpDiffer","mediaIndex","signaledSsrcs","ctx","removedSsrcInfo","addedSsrcInfo","request","errResponse","errorElSel","errorReasonSel","errorMsgSel","getIceConnectionState","getConnectionState","_parseIceCandidates","parseCandidates","candidateAttrs","JingleConnectionPlugin","iceConfig","sessions","jvbIceConfig","jvb","p2pIceConfig","offerToReceiveAudio","offerToReceiveVideo","onJingle","fromJid","sess","jsonMessages","audioVideoSsrcs","logMessage","endpoint","startMuted","iceUfrag","icePwd","dtlsFingerprint","successTime","newP2PJingleSession","getStunAndTurnCredentials","v2Res","onReceiveStunAndTurnCredentials","v1Res","iceservers","dict","urls","credential","temp","useTurnUdp","iceServers","getLog","updateLog","StropheLogger","logIncoming","logOutgoing","RAYO_XMLNS","RayoConnectionPlugin","onRayo","roomPass","callResource","lastErrorStatus","resetLastErrorStatusRegExpr","lastErrorStatusRegExpr","FAILURE_REGEX","DEFAULT_STUN_SERVERS","FEATURE_JIGASI","XMPP","token","disconnectInProgress","authenticatedUser","deploymentInfo","_components","trace","errStatusCapture","createConnection","bosh","shard_changed","suspend_time","time_since_last_success","_initStrophePlugins","initFeaturesList","disableBeforeUnloadHandlers","enableOpusRed","enableRemb","enableTcc","enableLipSync","getConnection","connectionHandler","credentials","statusStr","_maybeSendDeploymentInfoStat","_sysMessageHandler","sendDiscoInfo","_resetState","sendDeploymentInfo","_processDiscoInfoIdentities","anonymousConnectionFailed","connectionFailed","lastErrorMsg","wasIntentionalDisconnect","_getConnectionFailedReasonDetails","lastFailedRawMessage","_parseConnectionFailedMessage","speakerStatsComponentAddress","conferenceDurationComponentAddress","processLobbyFeatures","fr","region","backendRelease","_onPrivateMessage","_onSystemMessage","foundIceServers","attaching","configDomain","hostname","onCreateResource","getRoomJid","mucNickname","muc","getJingleLog","getXmppLog","getSessions","disconnectListener","_cleanupXmppConnection","evType","p2pStunServers","stunServers","iceTransportPolicy","headersArr","sendFaceLandmarksEvent","faceExpression","jsonString","users","created_timestamp","acceptedStatuses","aprops","authenticateAndUpgradeRole","rejectPromise","onLoginSuccessful","allocateConferenceFocus","authenticationError","connectionError","CodecSelection","enforcePreferredCodec","p2pDisabledCodec","_isCodecSupported","jvbDisabledCodec","p2pPreferredCodec","jvbPreferredCodec","_selectPreferredCodec","mediaSession","disabledCodec","currentCodec","selectedCodec","remoteParticipants","nonPreferredCodecs","remote","isVideoCodecDisabled","getPreferredCodec","BridgeChannel","wsUrl","_channel","_connected","_eventEmitter","_mode","_areRetriesEnabled","_closedFromClient","datachannel","createDataChannel","_handleChannel","_wsUrl","_initWebSocket","ws","_startConnectionRetries","timeoutS","reload","isOpen","_retryTimeout","_stopConnectionRetries","_retryWebSocketConnection","closeEvent","createBridgeChannelClosedEvent","sendEndpointStatsMessage","colibriClass","msgPayload","sendSetLastNMessage","lastN","sendReceiverVideoConstraintsMessage","sendSourceVideoTypeMessage","channel","dominantSpeakerEndpoint","previousSpeakers","isActive","forwardedSources","getParticipantCount","jsonObject","logDisabled_","deprecationWarnings_","extractVersion","uastring","pos","wrapPeerConnectionEvent","eventNameToWrap","RTCPeerConnection","nativeAddEventListener","nativeEventName","wrappedCallback","modifiedEvent","handleEvent","_eventMap","nativeRemoveEventListener","unwrappedCb","disableLog","disableWarnings","deprecated","oldMethod","newMethod","compactObject","walkStats","resultSet","filterStats","outbound","streamStatsType","filteredResult","trackStats","trackStat","trackId","shimGetUserMedia","browserDetails","constraintsToChrome_","cc","ideal","exact","oldname_","oc","mix","advanced","shimConstraints_","remap","face","facingMode","getSupportedFacingModeLies","getSupportedConstraints","enumerateDevices","dev","label","deviceId","shimError_","PermissionDeniedError","PermissionDismissedError","InvalidStateError","DevicesNotFoundError","ConstraintNotSatisfiedError","TrackStartError","MediaDeviceFailedDueToShutdown","MediaDeviceKillSwitchOn","TabCaptureError","ScreenCaptureError","DeviceCaptureError","webkitGetUserMedia","origGetUserMedia","getAudioTracks","getVideoTracks","DOMException","shimGetDisplayMedia","getSourceId","widthSpecified","heightSpecified","frameRateSpecified","shimMediaStream","MediaStream","webkitMediaStream","shimOnTrack","_ontrack","origSetRemoteDescription","_ontrackpoly","getReceivers","transceiver","dispatchEvent","shimGetSendersWithDtmf","shimSenderWithDtmf","dtmf","_dtmf","createDTMFSender","_pc","getSenders","_senders","origAddTrack","origRemoveTrack","removeTrack","origAddStream","addStream","origRemoveStream","removeStream","origGetSenders","shimGetStats","origGetStats","onSucc","onErr","fixChromeStats_","standardReport","standardStats","localcandidate","remotecandidate","stat","makeMapStats","successCallbackWrapper_","shimSenderReceiverGetStats","origGetReceivers","receivers","srcElement","MediaStreamTrack","shimAddTrackRemoveTrackWithNative","getLocalStreams","_shimmedLocalStreams","existingSenders","newSenders","newSender","shimAddTrackRemoveTrack","origGetLocalStreams","nativeStreams","_reverseStreams","_streams","newStream","replaceInternalStreamId","internalId","externalStream","internalStream","oldStream","nativeMethod","methodObj","origSetLocalDescription","replaceExternalStreamId","origLocalDescription","getOwnPropertyDescriptor","streamid","shimPeerConnection","webkitRTCPeerConnection","fixNegotiationNeeded","getConfiguration","sdpSemantics","nativeGetUserMedia","getSettings","nativeGetSettings","applyConstraints","nativeApplyConstraints","preferredMediaSource","mediaSource","RTCTrackEvent","mozRTCPeerConnection","modernStatsTypes","inboundrtp","outboundrtp","candidatepair","nativeGetStats","shimSenderGetStats","shimReceiverGetStats","shimRemoveStream","shimRTCDataChannel","DataChannel","RTCDataChannel","shimAddTransceiver","origAddTransceiver","addTransceiver","setParametersPromises","initParameters","shouldPerformCheck","sendEncodings","encodingParam","scaleResolutionDownBy","maxFramerate","getParameters","encodings","setParameters","shimGetParameters","origGetParameters","shimCreateOffer","origCreateOffer","finally","shimCreateAnswer","origCreateAnswer","shimLocalStreamsAPI","_localStreams","_addTrack","shimRemoteStreamsAPI","getRemoteStreams","_remoteStreams","_onaddstream","_onaddstreampoly","shimCallbacksAPI","successCallback","withCallback","_getUserMedia","shimConstraints","errcb","shimRTCIceServerUrls","OrigPeerConnection","pcConstraints","newIceServers","generateCertificate","shimTrackEventTransceiver","shimCreateOfferLegacy","offerOptions","audioTransceiver","setDirection","videoTransceiver","shimAudioContext","shimRTCIceCandidate","NativeRTCIceCandidate","nativeCandidate","parsedCandidate","augmentedCandidate","toJSON","shimMaxMessageSize","_sctp","sctpInDescription","getRemoteFirefoxVersion","canSendMMS","remoteIsFirefox","canSendMaxMessageSize","getCanSendMaxMessageSize","remoteMMS","getMaxMessageSize","POSITIVE_INFINITY","shimSendThrowTypeError","wrapDcSend","dc","origDataChannelSend","origCreateDataChannel","dataChannel","shimConnectionState","checking","_onconnectionstatechange","origMethod","_connectionstatechangepoly","_lastConnectionState","newEvent","removeExtmapAllowMixed","nativeSRD","shimAddIceCandidateNullOrEmpty","nativeAddIceCandidate","shimParameterlessSetLocalDescription","nativeSetLocalDescription","shimChrome","shimFirefox","shimSafari","mozGetUserMedia","isSecureContext","RTCIceGatherer","adapter","commonShim","chromeShim","browserShim","firefoxShim","safariShim","adapterFactory","DEFAULT_CONSTRAINTS","audioOutputDeviceId","audioOutputChanged","disableAP","disableAEC","disableNS","disableAGC","featureDetectionAudioEl","isAudioOutputDeviceChangeAvailable","setSinkId","availableDevicesPollTimer","availableDevices","emptyFuncton","updateGrantedPermissions","um","audioTracksReceived","videoTracksReceived","grantedPermissions","sendDeviceListToAnalytics","deviceList","audioInputDeviceCount","audioOutputDeviceCount","videoInputDeviceCount","videoOutputDeviceCount","device","groupId","updateKnownDevices","pds","newDevices","mediaDeviceInfoToJSON","facing","compareAvailableMediaDevices","rtcUtils","origAttachMediaStream","attachMediaStream","srcObject","isDeviceChangeAvailable","getAudioOutputDevice","ex","screenObtainer","isDeviceListAvailable","ds","umDevices","gumTimeout","timeoutExpired","_getDesktopMedia","_getMissingTracks","requestedDevices","missingDevices","audioDeviceRequested","videoDeviceRequested","obtainAudioAndVideoPermissions","otherOptions","mediaStreamsMetaData","maybeRequestDesktopDevice","desktopSharingSourceDevice","matchingDevice","maybeRequestCaptureDevices","requestedCaptureDevices","Resolutions","cameraDeviceId","CameraFacingMode","micDeviceId","getConstraints","desktopStream","desktopAudioTracks","desktopAudioStream","desktopVideoTracks","desktopVideoStream","avStream","audioStream","effects","videoStream","stopMediaStream","deviceType","mediaStream","release","isDesktopSharingEnabled","setAudioOutputDevice","getCurrentlyAvailableMediaDevices","arePermissionsGrantedForAvailableDevices","getEventDataForActiveDevice","deviceData","trackHandler2Prop","JitsiTrack","streamInactiveHandler","trackMediaType","containers","_streamInactiveHandler","_setStream","_addMediaStreamInactiveHandler","onended","oninactive","_attachTTFMTracker","container","_maybeFireTrackAttached","_onTrackAttach","_onTrackDetach","_setHandler","_unregisterHandlers","videoTrack","RTCUtils","getStreamId","getMSID","getTrackId","getTrack","getTrackLabel","getUsageLabel","getVideoType","isLocalAudioTrack","isWebRTCTrackMuted","newAudioLevel","setAudioOutput","JitsiLocalTrack","rtcId","_setEffectInProgress","effect","_startStreamEffect","displaySurface","maxEnabledResolution","_constraints","_prevSetMuted","_facingMode","_trackEnded","_hasSentData","_testDataSent","_realDeviceId","_sourceName","_trackMutedTS","_onDeviceListWillChange","oldRealDeviceId","_setRealDeviceIdFromDeviceList","_onAudioOutputDeviceChanged","_initNoDataFromSourceHandlers","_addStreamToConferenceAsUnmute","_addLocalTrackToPc","_fireNoDataFromSourceEvent","isReceivingData","createNoDataFromSourceEvent","_isNoDataFromSourceEventsEnabled","_queueSetMuted","setMuted","_setMuted","_removeStreamFromConferenceAsMute","_removeLocalTrackFromPc","_sendMuteStatus","_setTrackMuteStatus","logMuteInfo","_streamEffect","_stopStreamEffect","stopStream","streamOptions","getDeviceId","getCameraFacingMode","streamsInfo","streamInfo","cont","_sendBridgeVideoTypeMessage","storedMSID","_originalStream","startEffect","stopEffect","_switchCamera","_switchStreamEffect","setEffect","trackSettings","getDuration","isEnded","_stopStreamInProgress","_effectEnabled","setConference","unmute","found","PLAN_B_MIDS","findSimGroup","grp","findFidGroup","addSimGroupSources","sourceGroups","sourceList","findSourcebyId","relatedFidGroup","relatedSsrc","addSourcesToMline","otherSsrc","simGroup2","checkIfMlineForSsrcExists","mlines","Interop","toPlanB","every","sessionMedia","bLine","bundle","msidSemantic","semantic","resStr","toUnifiedPlan","current","currentDesc","iceRestart","newDesc","oldDesc","newMLine","oldMLine","checkForIceRestart","newIceUfrag","newIcePwd","newMline","mLineForData","ssrc2group","createSourceGroupMap","bundleOnly","resultSdp","SignalingEvents","PEER_MUTED_CHANGED","PEER_VIDEO_TYPE_CHANGED","SOURCE_MUTED_CHANGED","SOURCE_UPDATED","SOURCE_VIDEO_TYPE_CHANGED","getSourceNameForJitsiTrack","trackIdx","getMediaTypeFromSourceName","firstLetterOfMediaTypeIdx","firstLetterOfMediaType","getSourceIndexFromSourceName","nameParts","SignalingLayer","getPeerSourceInfo","getSSRCOwner","getTrackSourceName","ssrcList","setTrackMuteStatus","setTrackVideoType","updateSsrcOwnersOnLeave","parsePrimarySSRC","parseSecondarySSRC","_getSSRCCount","MLineWrap","getSSRCAttrValue","ssrcNumber","attrName","ssrcObj","removeSSRC","addSSRCAttribute","findGroup","findGroups","findGroupByPrimarySSRC","primarySSRC","findSSRCByMSID","getSSRCCount","containsAnySSRCGroups","getPrimaryVideoSsrc","fecGroup","getRtxSSRC","getSSRCs","getPrimaryVideoSSRCs","videoSSRCs","ssrcGroupInfo","dumpSSRCGroups","removeGroupsWithSSRC","removeGroupsBySemantics","replaceSSRC","oldSSRC","newSSRC","addSSRCGroup","SdpTransformWrap","rawSDP","parsedSDP","selectMedia","selectedMLines","toRawSDP","LocalSdpMunger","localEndpointId","audioSourcesToMsidMap","videoSourcesToMsidMap","_addMutedLocalVideoTracksToSDP","transformer","localVideos","isCamera","isInPeerConnection","isMediaStreamInPc","requiredSSRCs","isSimulcastOn","simulcast","sdpConsistency","cachedPrimarySsrc","primaryCname","rtxModifier","modifyRtxSsrcs2","_generateMsidAttribute","pcId","_transformMediaIdentifiers","streamAndTrackIDs","mediaDirection","_hasHadVideoTrack","_hasHadAudioTrack","generatedMsid","maybeAddMutedLocalVideoTracksToSDP","transformStreamIdentifiers","sessionDesc","audioMLine","_injectSourceNames","videoMlines","_usesUnifiedPlan","nameExists","trackIndex","trackIndexParts","updateAssociatedRtxStream","primarySsrcInfo","rtxSsrc","previousRtxSSRC","RtxModifier","correspondingRtxSsrcs","ssrcMapping","modifyRtxSsrcs","sdpStr","sdpTransformer","videoMLines","primaryVideoSsrcs","correspondingRtxSsrc","stripRtx","fidGroups","SdpConsistency","clearVideoSsrcCache","injectRecvOnly","setPrimarySsrc","hasPrimarySsrcCached","makeVideoPrimarySsrcsConsistent","newPrimarySsrc","SdpSimulcast","_ssrcCache","_fillSsrcsFromCache","cachedSsrcs","newSsrcs","_getSsrcAttribute","_generateNewSsrcsForSimulcast","addAssociatedAttributes","_generateSsrc","TrackStreamingStatus","TrackStreamingStatusImpl","isInForwardedSources","isRestoringTimedout","isVideoTrackFrozen","INTERRUPTED","RESTORING","restoringTimer","rtcMutedTimestamp","streamingStatusMap","trackTimer","outOfForwardedSourcesTimeout","p2pRtcMuteTimeout","rtcMuteTimeout","_getVideoFrozenTimeout","isP2PActive","_onP2PStatus","figureOutStreamingStatus","_onUserLeft","onUserLeft","_onTrackRtcMuted","onTrackRtcMuted","_onTrackRtcUnmuted","onTrackRtcUnmuted","_onSignallingMuteChanged","onSignallingMuteChanged","_onTrackVideoTypeChanged","onTrackVideoTypeChanged","_onForwardedSourcesChanged","onForwardedSourcesChanged","_onLastNValueChanged","clearRtcMutedTimestamp","maybeSendTrackStreamingStatusEvent","_changeStreamingStatus","newStatus","getTrackStreamingStatus","_setTrackStreamingStatus","isVideoRTCMuted","inP2PMode","isRestoringTimedOut","_isRestoringTimedout","audioOnlyMode","getLastN","newState","_getNewStateForP2PMode","_getNewStateForJvbMode","_clearRestoringTimer","oldStreamingStatus","streamingStatus","nowMs","startedMs","trackStreamingStatus","createTrackStreamingStatusEvent","leavingForwardedSources","enteringForwardedSources","_clearEnteredForwardedSourcesTimestamp","_setEnteredForwardedSourcesTimestamp","rTimer","enteredForwardedSourcesTimestamp","_getEnteredForwardedSourcesTimestamp","_isCurrentTrack","ttfmTrackerAudioAttached","ttfmTrackerVideoAttached","containerEvents","JitsiRemoteTrack","ownerEndpointId","_trackStreamingStatus","_trackStreamingStatusImpl","_enteredForwardedSourcesTimestamp","_addEventListener","_removeEventListener","hasBeenMuted","_bindTrackHandlers","_containerHandlers","_containerEventHandler","_onTrackMute","_onTrackUnmute","_initTrackStreamingStatus","_disposeTrackStreamingStatus","setMute","getSSRC","_playCallback","getConnectionTimes","gumStart","gumEnd","gumDuration","ttfm","_getStatus","_p2pConnStatusRtcMuteTimeout","_peerConnStatusRtcMuteTimeout","_peerConnStatusOutOfLastNTimeout","HD_BITRATE","SIM_LAYER_RIDS","TPCUtils","bitrateSettings","maxBitratesVideo","standardBitrates","low","standard","high","ssHigh","videoBitrates","encodingBitrates","_getStreamEncodings","localTrack","_getVideoStreamEncodings","maxVideoBitrate","ensureCorrectOrderOfSsrcs","parsedSdp","reorderedSsrcs","findTransceiver","insertUnifiedPlanSimulcastReceive","simulcast_03","simulcastLine","transceiverInit","calculateEncodingsActiveState","localVideoTrack","newHeight","videoStreamEncodings","_capScreenshareBitrate","calculateEncodingsBitrates","desktopShareBitrate","desktopBitrate","lowFpsScreenshare","getConfiguredEncodeResolution","videoSender","isNewLocalSource","stopped","transceiverMid","_localTrackTransceiverMids","setEncodings","_updateVideoSenderParameters","setActivePromise","settledResult","transceivers","localTrackMids","updateEncodingsResolution","TraceablePeerConnection","_dtmfSender","_dtmfTonesQueue","remoteTracks","_addedStreams","localSSRCs","remoteSSRCs","localUfrag","remoteUfrag","_dtlsTransport","_peerVideoTypeChanged","_peerMutedChanged","_sourceVideoTypeChanged","safeConstraints","rtcStatsSFUP2P","statsinterval","_usesTransceiverCodecPreferences","interop","localSdpMunger","getLocalEndpointId","_senderVideoMaxHeight","_senderMaxHeights","what","onTrack","evt","_remoteTrackAdded","_remoteTrackRemoved","onaddstream","_remoteStreamAdded","onremovestream","_remoteStreamRemoved","ondatachannel","_processStat","_lastVideoSenderUpdatePromise","statValue","endTime","times","dumpSDP","isAddOperation","hasLocalSource","hasAnyTracksOfType","_getDesktopTrackMid","desktopTrack","_getReceiversByEndpointIds","endpoints","remoteTrackIds","getSynchronizationSources","endpointTracksByMediaType","primarySsrcs","fidLines","getTargetVideoBitrates","remoteTrack","findTrackById","RTC","isUserStreamById","onaddtrack","onremovetrack","streamAudioTracks","audioTrack","streamVideoTracks","remoteSDP","mediaLine","mls","trackSsrc","_createRemoteTrack","remoteTracksMap","userTracksByMediaType","jitsiTrack","isUserStream","toBeRemoved","_removeRemoteTrack","removeRemoteTracks","removedTracks","remoteTracksByMedia","_extractSSRCMap","groupsMap","groupSSRCs","groupSsrcs","_getSSRC","_injectSsrcGroupForUnifiedSimulcast","getters","audioMedia","changed","videoMedia","enforceSendRecv","_adjustRemoteMediaDirection","isSharingLowFpsScreen","_isSharingScreen","_mungeCodecOrder","mLines","webrtcStream","_addStream","generateNewStreamSSRCInfo","rtxSsrcMapping","promiseChain","_assertTrackBelongs","webRtcStream","_removeStream","doesBelong","defaultCodec","lowFps","findSenderByKind","localSdp","oldTrackSSRC","_ensureSimulcastGroupIsLast","videoStartIndex","simStartIndex","otherStartIndex","simEndIndex","simStr","otherEndIndex","sdpHead","simStrTrimmed","sdpTail","_adjustLocalMediaDirection","modifiedDirection","desiredAudioDirection","desiredVideoDirection","localSources","remoteSources","_mungeOpus","enableOpusDtx","opusMaxAverageBitrate","fmtpOpus","fmtpConfig","sdpChanged","maxaveragebitrate","usedtx","mungedConfig","_mungeInactive","_initializeDtlsTransport","onstatechange","_setVp9MaxBitrates","isLocalSdp","bitrates","hdBitrate","ssHdBitrate","isSharingScreen","currentDescription","firstSsrcs","newSsrcLines","filteredLines","ssrcId","cnameLine","replaceDefaultUnifiedPlanMsid","normalizePlanB","configuredResolution","_updateVideoSenderEncodings","nextPromise","preference","degradationPreference","encodingsEnabledState","maxBitrates","scaleFactor","layer","sendTones","tones","interToneGap","rtpSender","localAudioTrack","ontonechange","_onToneChange","toneBuffer","insertDTMF","tone","peerTracks","_removePeerConnection","_createOfferOrAnswer","isOffer","logName","handleSuccess","resolveFn","rejectFn","_processLocalSSRCsMap","handleFailure","eventType","capabilities","disabledCodecMimeType","preferredCodecMimeType","setCodecPreferences","oaPromise","_extractPrimarySSRC","sourceIdentifier","newSSRCNum","oldSSRCNum","getActiveSimulcastStreams","activeStreams","currNumSsrcs","ConnectionQualityEvents","peerConnectionIdCounter","rtcTrackIdCounter","_createLocalTracks","metaData","peerConnections","_lastN","_forwardedSources","_forwardedSourcesChangeListener","_onDeviceListChanged","_updateAudioOutputForAudioTracks","destroy","_channelOpenListener","tracksInfo","initializeBridgeChannel","logError","msgType","_receiverVideoConstraints","oldForwardedSources","setReceiverVideoConstraints","sendSourceVideoType","signaling","encodedInsertableStreams","bundlePolicy","newConnection","traceablePeerConnection","addLocalTrack","getForwardedSources","localVideo","getLocalAudioTrack","localAudio","pcRemoteTracks","mutePromises","removeLocalTrack","elSelector","sendChannelMessage","setLastN","remoteAudioTracks","LOCAL_STATS_UPDATED","REMOTE_STATS_UPDATED","kSimulcastFormats","layers","startBitrate","ConnectionQuality","_localStats","connectionQuality","jvbRTT","_lastConnectionQualityUpdate","_remoteStats","_timeIceConnected","_timeVideoUnmuted","ConferenceEvents","_updateLocalConnectionQuality","_broadcastLocalStats","ICE_CONNECTION_STATE_CHANGED","_updateRemoteStats","disableLocalStats","_updateLocalStats","_maybeUpdateUnmuteTime","serverRegion","bridgeCount","_calculateConnectionQuality","resolutionName","quality","activeTPC","getActivePeerConnection","videoQualitySettings","millisSinceStart","simulcastFormat","targetHeight","rampUp","getTarget","maxIncreasePerSecond","prevConnectionQuality","diffSeconds","updateLocalConnectionQuality","isConnectionInterrupted","IceFailedHandling","_actOnIceFailed","explicitlyDisabled","useTerminateForRestart","jvbConnection","jvbConnIceState","_canceled","_iceFailedTimeout","DetectionEvents","DETECTOR_STATE_CHANGE","VAD_NOISY_DEVICE","VAD_REPORT_PUBLISHED","VAD_SCORE_PUBLISHED","VAD_TALK_WHILE_MUTED","NoAudioSignalDetection","_timeoutTrigger","_hasAudioInput","_trackAdded","_clearTriggerTimeout","_handleAudioInputStateChange","_handleNoAudioInputDetection","_eventFired","_audioLevel","_audioTrack","P2PDominantSpeakerDetection","myUserID","createAudioContext","AudioContextImpl","TrackVADEmitter","procNodeSampleRate","vadProcessor","_procNodeSampleRate","_vadProcessor","_localTrack","_bufferResidue","Float32Array","_audioContext","sampleRate","getRequiredPCMFrequency","_vadSampleSize","getSampleLength","_onAudioProcess","_initializeAudioContext","_audioSource","_audioProcessingNode","createScriptProcessor","audioEvent","inData","inputBuffer","getChannelData","completeInData","sampleTimestamp","pcmSample","vadScore","calculateAudioFrameVAD","score","pcmData","_connectAudioGraph","onaudioprocess","destination","_disconnectAudioGraph","_cleanupResources","getDeviceLabel","_destroyed","VADAudioAnalyser","createVADProcessor","_createVADProcessor","_vadEmitter","_isVADEmitterRunning","_detectionServices","_vadInitTracker","_processVADScore","_trackRemoved","addVADDetectionService","vadService","detector","_stopVADEmitter","_startVADEmitter","processVADScore","_changeDetectorsMuteState","changeMuteState","vadEmitter","VADNoiseDetection","_processing","_scoreArray","_audioLvlArray","_active","_calculateNoisyScore","scoreAvg","audioLevelAvg","_setActiveState","_recordValues","avgAudioLvl","_processTimeout","posAudioLevels","VADTalkMutedDetection","_calculateVADScore","E2ePingEvents","E2E_RTT_CHANGED","E2E_PING_REQUEST","E2E_PING_RESPONSE","ParticipantWrapper","e2eping","requests","lastRequestId","sendRequest","handleResponse","maybeLogRttAndStop","scheduleNext","getDelay","removeParticipant","conferenceSize","totalSeconds","numRequests","maxMessagesPerSecond","requestId","requestMessage","timeSent","numRequestsWithResponses","totalNumRequests","JitsiE2EPingEvents","E2ePing","maxConferenceSize","participantJoined","participantLeft","messageReceived","conferenceJoined","handleRequest","participantWrapper","Jvb121EventGenerator","_jvb121","evaluateStatus","oldStatus","kJitsiLiteMode","LiteModeContext","_setupLiteModeForTrack","transformStream","TransformStream","pipeThrough","pipeTo","MAX_HEIGHT","ReceiverVideoConstraints","assumedBandwidthBps","_maxFrameHeight","_assumedBandwidthBps","defaultConstraints","updateAssumedBandwidthBps","updateLastN","updateReceiveResolution","updateReceiverVideoConstraints","videoConstraints","ReceiveVideoController","_rtc","startLastN","_getDefaultSourceReceiverConstraints","remoteVideoTracks","setAssumedBandwidthBps","setPreferredReceiveMaxFrameHeight","setReceiverConstraints","p2pSession","mappedConstraints","SendVideoController","_preferredSendMaxFrameHeight","_sourceSenderConstraints","_configureConstraintsForLocalSources","_onSenderConstraintsReceived","_propagateSendMaxFrameHeight","sourceConstraints","getActiveMediaSession","sendMaxFrameHeight","_selectSendMaxFrameHeight","setPreferredSendMaxFrameHeight","getFocusRecordingUpdate","jibriStatus","recordingMode","sessionID","getHiddenDomainUpdate","liveStreamViewURLContainer","liveStreamViewURL","modeContainer","sessionIDContainer","getSessionIdFromIq","jibri","getSessionId","sessionIdContainer","isFromFocus","JibriSession","_jibriJid","_statusFromJicofo","_setSessionID","setStatus","getID","_sessionID","getInitiator","_initiator","getLiveStreamViewURL","_liveStreamViewURL","getJibriJid","getTerminator","_terminator","getMode","setError","setLiveStreamViewURL","setStatusFromJicofo","setJibriJid","jibriJid","appData","broadcastId","_createIQ","recordingXMLUtils","_setErrorFromIq","_sessions","_chatRoom","getSession","getSessionByJibriJid","_handleFocusPresence","_handleJibriPresence","prevStatus","_emitSessionUpdate","startRecording","_addSession","stopRecording","_createSession","AudioOutputProblemDetector","_localAudioLevelCache","_reportedParticipants","_audioProblemCandidates","_numberOfRemoteAudioLevelsReceived","_onLocalAudioLevelsReport","_onRemoteAudioLevelReceived","_clearUserData","numberOfReports","localAudioLevels","remoteAudioLevels","localAudioLevelsString","createAudioOutputProblemEvent","AverageStatReport","calculate","appendReport","ConnectionAvgStats","avgRtpStatsReporter","_n","_sampleIdx","_avgRTT","_avgRemoteRTTMap","_avgRtpStatsReporter","_avgEnd2EndRTT","_onConnectionStats","_calculateAvgStats","_onRemoteStatsUpdated","_processRemoteStats","batchReport","jvbEnd2EndRTT","jvbStatsMonitor","avgRemoteRTT","_calculateAvgRemoteRTT","avgLocalRTT","_resetAvgStats","remoteAvg","avg","validData","rttAvg","AvgRTPStatsReporter","_avgAudioBitrateUp","_avgAudioBitrateDown","_avgVideoBitrateUp","_avgVideoBitrateDown","_avgBandwidthUp","_avgBandwidthDown","_avgPacketLossTotal","_avgPacketLossUp","_avgPacketLossDown","_avgRemoteFPS","_avgRemoteScreenFPS","_avgLocalFPS","_avgLocalScreenFPS","_avgRemoteCameraPixels","_avgRemoteScreenPixels","_avgLocalCameraPixels","_avgLocalScreenPixels","_avgCQ","_cachedTransportStats","_onLocalStatsUpdated","_maybeSendTransportAnalyticsEvent","_onP2PStatusChanged","p2pStatsMonitor","_onJvb121StatusChanged","_resetAvgJvbStats","confSize","_calculateAvgVideoFps","_calculateAvgVideoPixels","peerResolutions","peerPixelsSum","peerCount","myID","peerID","videosResolution","peerAvgPixels","_calculatePeerAvgVideoPixels","videos","peerSsrcCount","peerSsrcPixels","peerFpsSum","videosFps","peerAvgFPS","_calculatePeerAvgVideoFps","peerSsrcFps","transportStats","SpeakerStatsCollector","dominantSpeakerId","SpeakerStats","_onDominantSpeaker","_onUserJoin","_onUserLeave","_onDisplayNameChange","_onFaceLandmarkAdd","_updateStats","oldDominantSpeaker","newDominantSpeaker","savedUser","newStats","speakerStatsToUpdate","newParticipant","RecordingResult","wordArray","TrackRecorder","recorder","AUDIO_WEBM","AUDIO_OGG","startRecorder","trackRecorder","stopRecorder","determineCorrectFileType","MediaRecorder","isTypeSupported","AudioRecorder","jitsiConference","recorders","fileType","isRecording","instantiateTrackRecorder","updateNames","originalStream","ondataavailable","dataEvent","recorderToRemove","revokeObjectURL","getRecordingResults","getFileType","Word","word","begin","getWord","getBeginTime","getEndTime","TranscriptionService","recordingResult","verify","formatResponse","audioBlob","SphinxService","AbstractTranscriptionService","sphinxURL","toReturn","getURL","audioFileBlob","DONE","audioRecorder","objects","filler","BEFORE_STATE","RECORDING_STATE","TRANSCRIBING_STATE","FINISHED_STATE","Transcriber","transcriptionService","transcription","lineLength","blobCallBack","transcriber","getUTCMilliseconds","wordObject","maybeMerge","hasPopulatedArrays","twoDimensionalArray","callBack","arrays","potentialWords","pushWordToSortedArray","lowestWordArray","wordToAdd","updateTranscription","foundSmaller","wordToCompare","getTranscription","ComponentsVersions","addCommandListener","processVersions","VideoSIPGWStatusConstants","VideoSIPGWStateConstants","VideoSIPGWErrorConstants","mucResource","getComponentVersion","componentName","STATUS_AVAILABLE","STATUS_UNDEFINED","STATUS_BUSY","STATE_ON","STATE_OFF","STATE_PENDING","STATE_RETRYING","STATE_FAILED","ERROR_NO_CONNECTION","ERROR_SESSION_EXISTS","STATE_CHANGED","JitsiVideoSIPGWSession","sipAddress","VideoSIPGWConstants","_sendJibriIQ","setState","failureReason","oldState","addStateListener","removeStateListener","sipaddress","displayname","VideoSIPGW","sessionStateChangeListener","sessionStateChanged","handleJibriSIPState","Constants","failure_reason","createVideoSIPGWSession","SOURCE_INFO_PRESENCE_ELEMENT","SignalingLayerImpl","ssrcOwners","_localSourceState","_remoteSourceState","_sourceNames","_addLocalSourceInfoToPresence","_bindChatRoomEventHandlers","emitAudioMutedEvent","_audioMuteHandler","_doesEndpointSendNewSourceInfo","emitVideoMutedEvent","_videoMuteHandler","emitVideoTypeEvent","_videoTypeHandler","_sourceInfoHandler","sourceInfoJSON","emitEventsFromHere","endpointSourceState","sourceChanged","newMutedState","oldSourceState","newVideoType","newSourceNames","_memberLeftHandler","_logOwnerChangedMessage","lastPresence","legacyGetPeerMediaInfo","mediaInfo","setChatRoom","oldChatRoom","existingOwner","existingName","_getCodecMimeType","JitsiConference","eventManager","componentsVersions","dtmfManager","somebodySupportsDTMF","wasStopped","avgRtpStatsN","_audioOutputProblemDetector","speakerStatsCollector","deferredStartP2PTask","backToP2PDelay","isP2PConnectionInterrupted","videoSIPGWHandler","recordingManager","RecordingManager","_conferenceJoinAnalyticsEventSent","isE2EESupported","_e2eEncryption","_liteModeContext","_audioSenderLimitReached","_videoSenderLimitReached","JitsiConnection","appID","errType","ANALYTICS_CONNECTION_DISCONNECTED","JitsiMediaDevicesEvents","resourceCreator","isAuthenticatedUser","codecSelection","_statsCurrentId","statisticsId","_onIceConnectionInterrupted","_onIceConnectionRestored","_onIceConnectionEstablished","_updateProperties","_sendConferenceJoinAnalyticsEvent","_removeLocalSourceOnReject","_updateRoomPresence","_registerRtcListeners","receiveVideoController","sendVideoController","statisticsDisplayName","callStatsCustomScriptUrl","callStatsConfigParams","enableTalkWhileMuted","_audioAnalyser","vadTalkMutedDetection","enableNoisyMicDetection","vadNoiseDetection","enableNoAudioDetection","_noAudioSignalDetection","hasAudioSignal","jvb121Status","p2pDominantSpeakerDetection","userRegion","transcriptionLanguage","_maybeSetSITimeout","isJoined","isP2PEnabled","isP2PTestModeEnabled","p2pTestMode","onLocalTrackRemoved","_sendConferenceLeftAnalyticsEvent","_delayedIceFailed","_maybeClearSITimeout","leaveError","isEndConferenceSupported","localtrack","BridgeVideoType","_desktopSharingFrameRate","isAuthEnabled","isLoggedIn","getAuthLogin","getExternalAuthUrl","urlForPopup","getPerformanceStats","longTasksStats","eventId","command","removeCommandListener","sendTextMessage","sendPrivateTextMessage","sendCommand","sendCommandOnce","removeCommand","nickKey","getTranscriber","localAudioTracks","getTranscriptionStatus","addTrackPromises","_setupNewTrack","_fireMuteChangeEvent","_fireAudioLevelChangeEvent","activeTpc","actorId","_getInitialLocalTracks","trackType","isStartAudioMuted","isStartVideoMuted","muteHandler","audioLevelHandler","oldVideoType","oldTrackBelongsToConference","_doReplaceTrack","replaceTrackPromises","_suspendMediaTransferForJvbConnection","_setNewVideoType","videoTypeChanged","presenceChanged","addPromises","removePromises","unlock","isInteger","isVideoActive","countHidden","grantOwner","revokeOwner","isMyself","isMembersOnly","kickParticipant","_sessionInitiateTimeout","muteMediaType","fullJid","_updateFeatures","_maybeStartOrStopP2P","updateDTMFSupport","botParticipant","mediaSessions","tracksToBeRemoved","kickedParticipantId","kickedParticipant","transportInfo","removedTrack","_onIncomingCallP2P","rejectReason","contentName","_shouldBeInP2PMode","_rejectIncomingCall","_acceptP2PIncomingCall","_acceptJvbIncomingCall","ignoreDomain","bridgeChannel","preferSctp","sctpOffered","firstWsUrl","stopOptions","forceJvb121","p2pFailed","_stopP2PSession","isDTMFSupported","peerConnection","isSIPCallingSupported","startTranscriber","stopTranscriber","getMeetingUniqueId","setStartMutedPolicy","policy","getStartMutedPolicy","removeLocalParticipantProperty","getLocalParticipantProperty","property","overallFeedback","detailedFeedback","getSsrcByTrack","remoteUserId","_fireIncompatibleVersionsEvent","sendEndpointMessage","broadcastEndpointMessage","sendThroughVideobridge","messageType","messageToSend","remoteID","_addRemoteJVBTracks","_addRemoteTracks","_addRemoteP2PTracks","p2pEstablishmentDuration","jvbEstablishmentDuration","forceJVB121Ratio","establishmentDurationDiff","_setP2PStatus","_removeRemoteJVBTracks","audioLimitReached","videoLimitReached","_maybeClearDeferredStartP2P","_removeRemoteTracks","_removeRemoteP2PTracks","sessionNickname","_resumeMediaTransferForJvbConnection","_startP2PSession","userLeftEvent","peers","shouldBeInP2P","peersId","hasBotPeer","wasP2PEstablished","skip","muteStatusChanged","getP2PConnectionState","startP2PSession","stopP2PSession","getSpeakerStats","sendFaceLandmarks","perf","toggleE2EE","setMediaEncryptionKey","isLobbySupported","disableLobby","joinLobby","myLobbyUserId","sendLobbyMessage","addLobbyMessageListener","removeLobbyMessageHandler","lobbyDenyAccess","lobbyApproveAccess","isAVModerationSupported","enableAVModeration","disableAVModeration","avModerationApprove","avModerationReject","setToken","initJitsiConference","getLogs","PERMISSION_PROMPT_IS_SHOWN","SLOW_GET_USER_MEDIA","AUDIO_PERMISSION_NAME","VIDEO_PERMISSION_NAME","_permissions","_logOutputDevice","permissions","_handlePermissionsChange","_permissionsApiSupported","query","_parsePermissionState","onchange","supported","permissionStatus","deviceID","isDevicePermissionGranted","isMultipleAudioInputSupported","emitEvent","stopActiveDevices","CustomSignalingLayer","ACTIONS","ProxyConnectionPC","receiveAudio","receiveVideo","_peerConnection","_onRemoteStream","_onSendMessage","getPeerJid","processMessage","$jingle","ACCEPT","_onSessionAccept","INITIATE","_onSessionInitiate","TERMINATE","_onSessionTerminate","TRANSPORT_INFO","_onTransportInfo","_createPeerConnection","connectionStub","pcConfigStub","roomStub","jitsiRemoteTrack","onRemoteStream","onSendMessage","PRECALL_TEST_RESULTS","_initialized","api","_loadScript","appId","appSecret","disablePrecalltest","_initialize","execute","makePrecallTest","AudioMixer","_started","_streamsToMix","_streamMSSArray","addMediaStream","_mixedMSD","createMediaStreamDestination","streamMSS","getAnalyticsAttributesFromOptions","video_requested","ProxyConnectionService","jitsiConnection","_onFatalError","_convertStringToXML","UNAVAILABLE","_selfCloseConnection","localTrackIndex","localSourceNameTrack","xml","xmlDom","isVideo","convertVideoToDesktop","jitsiLocalTracks","createLocalTracks","stringifiedIq","XMLSerializer","serializeToString","onConnectionClosed","constants","recording","BUSY","RESOURCE_CONSTRAINT","UNEXPECTED_REQUEST","SERVICE_UNAVAILABLE","FILE","sipVideoGW","detection","errorTypes","logLevels","JitsiMediaDevices","enableAnalyticsLogging","enableWindowOnErrorHandler","getGlobalOnErrorHandler","isWebRtcSupported","addGlobalLogTransport","globalTransport","removeGlobalLogTransport","setGlobalLogOptions","oldfirePermissionPromptIsShownEvent","promiseFulfilled","firePermissionPromptIsShownEvent","fireSlowPromiseEvent","restOptions","isCollectingLocalStats","currentlyAvailableMediaDevices","setVideoTrackContentHints","createTrackVADEmitter","localAudioDeviceId","createAudioMixer","getActiveAudioDevice","audioDevices","devicePromiseArray","micDevice","devicePromise","outcomeArray","successfulPromises","rejectedPromises","rejectReasons","deviceLabel","lineno","colno","setNetworkInfo","hint","contentHint","precallTest","util","AuthUtil","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","loaded","__webpack_modules__","amdO","getter","definition","globalThis","nmd","paths","__webpack_exports__"],"sourceRoot":""}