{"version":3,"file":"lib-jitsi-meet.min.js","mappings":"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","sources":["webpack://JitsiMeetJS/webpack/universalModuleDefinition","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/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/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/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/flags/FeatureFlags.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/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/SphinxTranscriptionService.js","webpack://JitsiMeetJS/./modules/transcription/transcriptionServices/AbstractTranscriptionService.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/./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/StringUtils.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/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, function() {\nreturn ","/**\r\n * The errors for the conference.\r\n */\r\n\r\nexport enum JitsiConferenceErrors {\r\n    /**\r\n     * Indicates that client must be authenticated to create the conference.\r\n     */\r\n    AUTHENTICATION_REQUIRED = 'conference.authenticationRequired',\r\n\r\n    /**\r\n     * Indicates that chat error occurred.\r\n     */\r\n    CHAT_ERROR = 'conference.chatError',\r\n\r\n    /**\r\n     * Indicates that a settings error occurred.\r\n     */\r\n    SETTINGS_ERROR = 'conference.settingsError',\r\n\r\n    /**\r\n     * Indicates that conference has been destroyed.\r\n     */\r\n    CONFERENCE_DESTROYED = 'conference.destroyed',\r\n\r\n    /**\r\n     * Indicates that max users limit has been reached.\r\n     */\r\n    CONFERENCE_MAX_USERS = 'conference.max_users',\r\n\r\n    /**\r\n     * Indicates that a connection error occurred when trying to join a conference.\r\n     */\r\n    CONNECTION_ERROR = 'conference.connectionError',\r\n\r\n    /**\r\n     * Indicates that the client has been forced to restart by jicofo when the\r\n     * conference was migrated from one bridge to another.\r\n     */\r\n    CONFERENCE_RESTARTED = 'conference.restarted',\r\n\r\n    /**\r\n     * Indicates that a connection error is due to not allowed,\r\n     * occurred when trying to join a conference.\r\n     */\r\n    NOT_ALLOWED_ERROR = 'conference.connectionError.notAllowed',\r\n\r\n    /**\r\n     * Indicates that a connection error is due to not allowed,\r\n     * occurred when trying to join a conference, only approved members are allowed to join.\r\n     */\r\n    MEMBERS_ONLY_ERROR = 'conference.connectionError.membersOnly',\r\n\r\n    /**\r\n     * Indicates that a connection error is due to denied access to the room,\r\n     * occurred after joining a lobby room and access is denied by the room moderators.\r\n     */\r\n    CONFERENCE_ACCESS_DENIED = 'conference.connectionError.accessDenied',\r\n\r\n    /**\r\n     * Indicates that focus error happened.\r\n     */\r\n    FOCUS_DISCONNECTED = 'conference.focusDisconnected',\r\n\r\n    /**\r\n     * Indicates that focus left the conference.\r\n     */\r\n    FOCUS_LEFT = 'conference.focusLeft',\r\n\r\n    /**\r\n     * Indicates that graceful shutdown happened.\r\n     */\r\n    GRACEFUL_SHUTDOWN = 'conference.gracefulShutdown',\r\n\r\n    /**\r\n     * Indicates that the media connection has failed.\r\n     */\r\n    ICE_FAILED = 'conference.iceFailed',\r\n\r\n    /**\r\n     * Indicates that the versions of the server side components are incompatible\r\n     * with the client side.\r\n     */\r\n    INCOMPATIBLE_SERVER_VERSIONS = 'conference.incompatible_server_versions',\r\n\r\n    /**\r\n     * Indicates that offer/answer had failed.\r\n     */\r\n    OFFER_ANSWER_FAILED = 'conference.offerAnswerFailed',\r\n\r\n    /**\r\n     * Indicates that password cannot be set for this conference.\r\n     */\r\n    PASSWORD_NOT_SUPPORTED = 'conference.passwordNotSupported',\r\n\r\n    /**\r\n     * Indicates that a password is required in order to join the conference.\r\n     */\r\n    PASSWORD_REQUIRED = 'conference.passwordRequired',\r\n\r\n    /**\r\n     * Indicates that reservation system returned error.\r\n     */\r\n    RESERVATION_ERROR = 'conference.reservationError',\r\n\r\n    /**\r\n     * Indicates that there is no available videobridge.\r\n     */\r\n    VIDEOBRIDGE_NOT_AVAILABLE = 'conference.videobridgeNotAvailable'\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const AUTHENTICATION_REQUIRED = JitsiConferenceErrors.AUTHENTICATION_REQUIRED;\r\nexport const CHAT_ERROR = JitsiConferenceErrors.CHAT_ERROR;\r\nexport const SETTINGS_ERROR = JitsiConferenceErrors.SETTINGS_ERROR;\r\nexport const CONFERENCE_DESTROYED = JitsiConferenceErrors.CONFERENCE_DESTROYED;\r\nexport const CONFERENCE_MAX_USERS = JitsiConferenceErrors.CONFERENCE_MAX_USERS;\r\nexport const CONNECTION_ERROR = JitsiConferenceErrors.CONNECTION_ERROR;\r\nexport const CONFERENCE_RESTARTED = JitsiConferenceErrors.CONFERENCE_RESTARTED;\r\nexport const NOT_ALLOWED_ERROR = JitsiConferenceErrors.NOT_ALLOWED_ERROR;\r\nexport const MEMBERS_ONLY_ERROR = JitsiConferenceErrors.MEMBERS_ONLY_ERROR;\r\nexport const CONFERENCE_ACCESS_DENIED = JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED;\r\nexport const FOCUS_DISCONNECTED = JitsiConferenceErrors.FOCUS_DISCONNECTED;\r\nexport const FOCUS_LEFT = JitsiConferenceErrors.FOCUS_LEFT;\r\nexport const GRACEFUL_SHUTDOWN = JitsiConferenceErrors.GRACEFUL_SHUTDOWN;\r\nexport const ICE_FAILED = JitsiConferenceErrors.ICE_FAILED;\r\nexport const INCOMPATIBLE_SERVER_VERSIONS = JitsiConferenceErrors.INCOMPATIBLE_SERVER_VERSIONS;\r\nexport const OFFER_ANSWER_FAILED = JitsiConferenceErrors.OFFER_ANSWER_FAILED;\r\nexport const PASSWORD_NOT_SUPPORTED = JitsiConferenceErrors.PASSWORD_NOT_SUPPORTED;\r\nexport const PASSWORD_REQUIRED = JitsiConferenceErrors.PASSWORD_REQUIRED;\r\nexport const RESERVATION_ERROR = JitsiConferenceErrors.RESERVATION_ERROR;\r\nexport const VIDEOBRIDGE_NOT_AVAILABLE = JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE;\r\n","/**\r\n * The events for the conference.\r\n */\r\n\r\nexport enum JitsiConferenceEvents {\r\n    /**\r\n     * Event indicates that the current conference audio input switched between audio\r\n     * input states,i.e. with or without audio input.\r\n     */\r\n    AUDIO_INPUT_STATE_CHANGE = 'conference.audio_input_state_changed',\r\n\r\n    /**\r\n     * Event indicates that the permission for unmuting audio has changed based on the number of audio senders in the call\r\n     * and the audio sender limit configured in Jicofo.\r\n     */\r\n    AUDIO_UNMUTE_PERMISSIONS_CHANGED = 'conference.audio_unmute_permissions_changed',\r\n\r\n    /**\r\n     * Indicates that authentication status changed.\r\n     */\r\n    AUTH_STATUS_CHANGED = 'conference.auth_status_changed',\r\n\r\n    /**\r\n     * Fired just before the statistics module is disposed and it's the last chance\r\n     * to submit some logs to the statistics service (ex. CallStats if enabled),\r\n     * before it's disconnected.\r\n     */\r\n    BEFORE_STATISTICS_DISPOSED = 'conference.beforeStatisticsDisposed',\r\n\r\n    /**\r\n     * Indicates that an error occurred.\r\n     */\r\n    CONFERENCE_ERROR = 'conference.error',\r\n\r\n    /**\r\n     * Indicates that conference failed.\r\n     */\r\n    CONFERENCE_FAILED = 'conference.failed',\r\n\r\n    /**\r\n     * Indicates that conference is in progress of joining.\r\n     */\r\n    CONFERENCE_JOIN_IN_PROGRESS = 'conference.join_in_progress',\r\n\r\n    /**\r\n     * Indicates that conference has been joined. The event does NOT provide any\r\n     * parameters to its listeners.\r\n     */\r\n    CONFERENCE_JOINED = 'conference.joined',\r\n\r\n    /**\r\n     * Indicates that conference has been left.\r\n     */\r\n    CONFERENCE_LEFT = 'conference.left',\r\n\r\n    /**\r\n     * Indicates that the conference unique identifier has been set.\r\n     */\r\n    CONFERENCE_UNIQUE_ID_SET = 'conference.unique_id_set',\r\n\r\n    /**\r\n     * Indicates that the connection to the conference has been established\r\n     * XXX This is currently fired when the *ICE* connection enters 'connected'\r\n     * state for the first time.\r\n     */\r\n    CONNECTION_ESTABLISHED = 'conference.connectionEstablished',\r\n\r\n    /**\r\n     * Indicates that the connection to the conference has been interrupted for some\r\n     * reason.\r\n     * XXX This is currently fired when the *ICE* connection is interrupted.\r\n     */\r\n    CONNECTION_INTERRUPTED = 'conference.connectionInterrupted',\r\n\r\n    /**\r\n     * Indicates that the connection to the conference has been restored.\r\n     * XXX This is currently fired when the *ICE* connection is restored.\r\n     */\r\n    CONNECTION_RESTORED = 'conference.connectionRestored',\r\n\r\n    /**\r\n     * A connection to the video bridge's data channel has been established.\r\n     */\r\n    DATA_CHANNEL_OPENED = 'conference.dataChannelOpened',\r\n\r\n    /**\r\n     * A user has changed it display name\r\n     */\r\n    DISPLAY_NAME_CHANGED = 'conference.displayNameChanged',\r\n\r\n    /**\r\n     * The dominant speaker was changed.\r\n     */\r\n    DOMINANT_SPEAKER_CHANGED = 'conference.dominantSpeaker',\r\n\r\n    /**\r\n     * UTC conference timestamp when first participant joined.\r\n     */\r\n    CONFERENCE_CREATED_TIMESTAMP = 'conference.createdTimestamp',\r\n\r\n    /**\r\n     * Indicates that DTMF support changed.\r\n     */\r\n    DTMF_SUPPORT_CHANGED = 'conference.dtmfSupportChanged',\r\n\r\n    /**\r\n     * Indicates that a message from another participant is received on data\r\n     * channel.\r\n     */\r\n    ENDPOINT_MESSAGE_RECEIVED = 'conference.endpoint_message_received',\r\n\r\n    /**\r\n     * Indicates that a message for the remote endpoint statistics has been received on the bridge channel.\r\n     */\r\n    ENDPOINT_STATS_RECEIVED = 'conference.endpoint_stats_received',\r\n\r\n    /**\r\n     * NOTE This is lib-jitsi-meet internal event and can be removed at any time !\r\n     *\r\n     * Event emitted when conference transits, between one to one and multiparty JVB\r\n     * conference. If the conference switches to P2P it's neither one to one nor\r\n     * a multiparty JVB conference, but P2P (the status argument of this event will\r\n     * be <tt>false</tt>).\r\n     *\r\n     * The first argument is a boolean which carries the previous value and\r\n     * the seconds argument is a boolean with the new status. The event is emitted\r\n     * only if the previous and the new values are different.\r\n     *\r\n     * @type {string}\r\n     */\r\n    JVB121_STATUS = 'conference.jvb121Status',\r\n\r\n    /**\r\n     * You are kicked from the conference.\r\n     * @param {JitsiParticipant} the participant that initiated the kick.\r\n     */\r\n    KICKED = 'conference.kicked',\r\n\r\n    /**\r\n     * Participant was kicked from the conference.\r\n     * @param {JitsiParticipant} the participant that initiated the kick.\r\n     * @param {JitsiParticipant} the participant that was kicked.\r\n     */\r\n    PARTICIPANT_KICKED = 'conference.participant_kicked',\r\n\r\n    /**\r\n     * The Last N set is changed.\r\n     *\r\n     * @param {Array<string>|null} leavingEndpointIds the ids of all the endpoints\r\n     * which are leaving Last N\r\n     * @param {Array<string>|null} enteringEndpointIds the ids of all the endpoints\r\n     * which are entering Last N\r\n     */\r\n    LAST_N_ENDPOINTS_CHANGED = 'conference.lastNEndpointsChanged',\r\n\r\n    /**\r\n     * The forwarded sources set is changed.\r\n     *\r\n     * @param {Array<string>} leavingForwardedSources the sourceNames of all the tracks which are leaving forwarded\r\n     * sources\r\n     * @param {Array<string>} enteringForwardedSources the sourceNames of all the tracks which are entering forwarded\r\n     * sources\r\n     */\r\n    FORWARDED_SOURCES_CHANGED = 'conference.forwardedSourcesChanged',\r\n\r\n    /**\r\n     * Indicates that the room has been locked or unlocked.\r\n     */\r\n    LOCK_STATE_CHANGED = 'conference.lock_state_changed',\r\n\r\n    /**\r\n     * Indicates that the region of the media server (jitsi-videobridge) that we\r\n     * are connected to changed (or was initially set).\r\n     * @type {string} the region.\r\n     */\r\n    SERVER_REGION_CHANGED = 'conference.server_region_changed',\r\n\r\n    /**\r\n     * An event(library-private) fired when a new media session is added to the conference.\r\n     * @type {string}\r\n     * @private\r\n     */\r\n    _MEDIA_SESSION_STARTED = 'conference.media_session.started',\r\n\r\n    /**\r\n     * An event(library-private) fired when the conference switches the currently active media session.\r\n     * @type {string}\r\n     * @private\r\n     */\r\n    _MEDIA_SESSION_ACTIVE_CHANGED = 'conference.media_session.active_changed',\r\n\r\n    /**\r\n     * Indicates that the conference had changed to members only enabled/disabled.\r\n     * The first argument of this event is a <tt>boolean</tt> which when set to\r\n     * <tt>true</tt> means that the conference is running in members only mode.\r\n     * You may need to use Lobby if supported to ask for permissions to enter the conference.\r\n     */\r\n    MEMBERS_ONLY_CHANGED = 'conference.membersOnlyChanged',\r\n\r\n    /**\r\n     * New text message was received.\r\n     */\r\n    MESSAGE_RECEIVED = 'conference.messageReceived',\r\n\r\n    /**\r\n     * Event indicates that the current selected input device has no signal\r\n     */\r\n    NO_AUDIO_INPUT = 'conference.no_audio_input',\r\n\r\n    /**\r\n     * Event indicates that the current microphone used by the conference is noisy.\r\n     */\r\n    NOISY_MIC = 'conference.noisy_mic',\r\n\r\n    /**\r\n     * Indicates that a message from the local user or from the Prosody backend\r\n     * was received on the data channel.\r\n     */\r\n    NON_PARTICIPANT_MESSAGE_RECEIVED = 'conference.non_participant_message_received',\r\n\r\n    /**\r\n     * New private text message was received.\r\n     */\r\n    PRIVATE_MESSAGE_RECEIVED = 'conference.privateMessageReceived',\r\n\r\n    /**\r\n     * Indicates that the features of the participant has been changed.\r\n     * TODO: there is a spelling mistake in this event name and associated constants\r\n     */\r\n    PARTCIPANT_FEATURES_CHANGED = 'conference.partcipant_features_changed',\r\n\r\n    /**\r\n     * Indicates that a the value of a specific property of a specific participant\r\n     * has changed.\r\n     */\r\n    PARTICIPANT_PROPERTY_CHANGED = 'conference.participant_property_changed',\r\n\r\n    /**\r\n     * Indicates that the conference has switched between JVB and P2P connections.\r\n     * The first argument of this event is a <tt>boolean</tt> which when set to\r\n     * <tt>true</tt> means that the conference is running on the P2P connection.\r\n     */\r\n    P2P_STATUS = 'conference.p2pStatus',\r\n\r\n    /**\r\n     * Indicates that phone number changed.\r\n     */\r\n    PHONE_NUMBER_CHANGED = 'conference.phoneNumberChanged',\r\n\r\n    /**\r\n     * The conference properties changed.\r\n     * @type {string}\r\n     */\r\n    PROPERTIES_CHANGED = 'conference.propertiesChanged',\r\n\r\n    /**\r\n     * Indicates that recording state changed.\r\n     */\r\n    RECORDER_STATE_CHANGED = 'conference.recorderStateChanged',\r\n\r\n    /**\r\n     * Indicates that video SIP GW state changed.\r\n     * @param {VideoSIPGWConstants} status.\r\n     */\r\n    VIDEO_SIP_GW_AVAILABILITY_CHANGED = 'conference.videoSIPGWAvailabilityChanged',\r\n\r\n    /**\r\n     * Indicates that video SIP GW Session state changed.\r\n     * @param {options} event - {\r\n     *     {string} address,\r\n     *     {VideoSIPGWConstants} oldState,\r\n     *     {VideoSIPGWConstants} newState,\r\n     *     {string} displayName}\r\n     * }.\r\n     */\r\n    VIDEO_SIP_GW_SESSION_STATE_CHANGED = 'conference.videoSIPGWSessionStateChanged',\r\n\r\n    /**\r\n     * Indicates that start muted settings changed.\r\n     */\r\n    START_MUTED_POLICY_CHANGED = 'conference.start_muted_policy_changed',\r\n\r\n    /**\r\n     * Indicates that the local user has started muted.\r\n     */\r\n    STARTED_MUTED = 'conference.started_muted',\r\n\r\n    /**\r\n     * Indicates that subject of the conference has changed.\r\n     */\r\n    SUBJECT_CHANGED = 'conference.subjectChanged',\r\n\r\n    /**\r\n     * Indicates that DTMF support changed.\r\n     */\r\n    SUSPEND_DETECTED = 'conference.suspendDetected',\r\n\r\n    /**\r\n     * Event indicates that local user is talking while he muted himself\r\n     */\r\n    TALK_WHILE_MUTED = 'conference.talk_while_muted',\r\n\r\n    /**\r\n     * A new media track was added to the conference. The event provides the\r\n     * following parameters to its listeners:\r\n     *\r\n     * @param {JitsiTrack} track the added JitsiTrack\r\n     */\r\n    TRACK_ADDED = 'conference.trackAdded',\r\n\r\n    /**\r\n     * Audio levels of a media track ( attached to the conference) was changed.\r\n     */\r\n    TRACK_AUDIO_LEVEL_CHANGED = 'conference.audioLevelsChanged',\r\n\r\n    /**\r\n     * A media track ( attached to the conference) mute status was changed.\r\n     * @param {JitsiParticipant|null} the participant that initiated the mute\r\n     * if it is a remote mute.\r\n     */\r\n    TRACK_MUTE_CHANGED = 'conference.trackMuteChanged',\r\n\r\n    /**\r\n     * The media track was removed from the conference. The event provides the\r\n     * following parameters to its listeners:\r\n     *\r\n     * @param {JitsiTrack} track the removed JitsiTrack\r\n     */\r\n    TRACK_REMOVED = 'conference.trackRemoved',\r\n\r\n    /**\r\n     * The source-add for unmuting of a media track was rejected by Jicofo.\r\n     *\r\n     */\r\n    TRACK_UNMUTE_REJECTED = 'conference.trackUnmuteRejected',\r\n\r\n    /**\r\n     * Notifies for transcription status changes. The event provides the\r\n     * following parameters to its listeners:\r\n     *\r\n     * @param {String} status - The new status.\r\n     */\r\n    TRANSCRIPTION_STATUS_CHANGED = 'conference.transcriptionStatusChanged',\r\n\r\n    /**\r\n     * A new user joined the conference.\r\n     */\r\n    USER_JOINED = 'conference.userJoined',\r\n\r\n    /**\r\n     * A user has left the conference.\r\n     */\r\n    USER_LEFT = 'conference.userLeft',\r\n\r\n    /**\r\n     * User role changed.\r\n     */\r\n    USER_ROLE_CHANGED = 'conference.roleChanged',\r\n\r\n    /**\r\n     * User status changed.\r\n     */\r\n    USER_STATUS_CHANGED = 'conference.statusChanged',\r\n\r\n    /**\r\n     * Event indicates that the permission for unmuting video has changed based on the number of video senders in the call\r\n     * and the video sender limit configured in Jicofo.\r\n     */\r\n    VIDEO_UNMUTE_PERMISSIONS_CHANGED = 'conference.video_unmute_permissions_changed',\r\n\r\n    /**\r\n     * Event indicates that the bot participant type changed.\r\n     */\r\n    BOT_TYPE_CHANGED = 'conference.bot_type_changed',\r\n\r\n    /**\r\n     * A new user joined the lobby room.\r\n     */\r\n    LOBBY_USER_JOINED = 'conference.lobby.userJoined',\r\n\r\n    /**\r\n     * A user from the lobby room has been update.\r\n     */\r\n    LOBBY_USER_UPDATED = 'conference.lobby.userUpdated',\r\n\r\n    /**\r\n     * A user left the lobby room.\r\n     */\r\n    LOBBY_USER_LEFT = 'conference.lobby.userLeft',\r\n\r\n    /**\r\n     * The local participant was approved to be able to unmute.\r\n     * @param {options} event - {\r\n     *     {MediaType} mediaType\r\n     * }.\r\n     */\r\n    AV_MODERATION_APPROVED = 'conference.av_moderation.approved',\r\n\r\n    /**\r\n     * The local participant was blocked to be able to unmute.\r\n     * @param {options} event - {\r\n     *     {MediaType} mediaType\r\n     * }.\r\n     */\r\n    AV_MODERATION_REJECTED = 'conference.av_moderation.rejected',\r\n\r\n    /**\r\n     * AV Moderation was enabled/disabled. The actor is the participant that is currently in the meeting,\r\n     * or undefined if that participant has left the meeting.\r\n     *\r\n     * @param {options} event - {\r\n     *     {boolean} enabled,\r\n     *     {MediaType} mediaType,\r\n     *     {JitsiParticipant} actor\r\n     * }.\r\n     */\r\n    AV_MODERATION_CHANGED = 'conference.av_moderation.changed',\r\n\r\n    /**\r\n     * AV Moderation, report for user being approved to unmute.\r\n     * @param {options} event - {\r\n     *     {JitsiParticipant} participant,\r\n     *     {MediaType} mediaType\r\n     * }.\r\n     */\r\n    AV_MODERATION_PARTICIPANT_APPROVED = 'conference.av_moderation.participant.approved',\r\n\r\n    /**\r\n     * AV Moderation, report for user being blocked to unmute.\r\n     * @param {options} event - {\r\n     *     {JitsiParticipant} participant,\r\n     *     {MediaType} mediaType\r\n     * }.\r\n     */\r\n    AV_MODERATION_PARTICIPANT_REJECTED = 'conference.av_moderation.participant.rejected',\r\n\r\n    /**\r\n     * A new face landmark object is added for a participant\r\n     */\r\n    FACE_LANDMARK_ADDED = 'conference.face_landmark.added',\r\n\r\n    /**\r\n     * Event fired when a participant is requested to join a given (breakout) room.\r\n     */\r\n    BREAKOUT_ROOMS_MOVE_TO_ROOM = 'conference.breakout-rooms.move-to-room',\r\n\r\n    /**\r\n     * Event fired when the breakout rooms data was updated.\r\n     */\r\n    BREAKOUT_ROOMS_UPDATED = 'conference.breakout-rooms.updated',\r\n\r\n    /**\r\n     * Event fired when the conference metadata is updated.\r\n     */\r\n    METADATA_UPDATED = 'conference.metadata.updated'\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const AUDIO_INPUT_STATE_CHANGE = JitsiConferenceEvents.AUDIO_INPUT_STATE_CHANGE;\r\nexport const AUDIO_UNMUTE_PERMISSIONS_CHANGED = JitsiConferenceEvents.AUDIO_UNMUTE_PERMISSIONS_CHANGED;\r\nexport const AUTH_STATUS_CHANGED = JitsiConferenceEvents.AUTH_STATUS_CHANGED;\r\nexport const BEFORE_STATISTICS_DISPOSED = JitsiConferenceEvents.BEFORE_STATISTICS_DISPOSED;\r\nexport const CONFERENCE_ERROR = JitsiConferenceEvents.CONFERENCE_ERROR;\r\nexport const CONFERENCE_FAILED = JitsiConferenceEvents.CONFERENCE_FAILED;\r\nexport const CONFERENCE_JOIN_IN_PROGRESS = JitsiConferenceEvents.CONFERENCE_JOIN_IN_PROGRESS;\r\nexport const CONFERENCE_JOINED = JitsiConferenceEvents.CONFERENCE_JOINED;\r\nexport const CONFERENCE_LEFT = JitsiConferenceEvents.CONFERENCE_LEFT;\r\nexport const CONFERENCE_UNIQUE_ID_SET = JitsiConferenceEvents.CONFERENCE_UNIQUE_ID_SET;\r\nexport const CONNECTION_ESTABLISHED = JitsiConferenceEvents.CONNECTION_ESTABLISHED;\r\nexport const CONNECTION_INTERRUPTED = JitsiConferenceEvents.CONNECTION_INTERRUPTED;\r\nexport const CONNECTION_RESTORED = JitsiConferenceEvents.CONNECTION_RESTORED;\r\nexport const DATA_CHANNEL_OPENED = JitsiConferenceEvents.DATA_CHANNEL_OPENED;\r\nexport const DISPLAY_NAME_CHANGED = JitsiConferenceEvents.DISPLAY_NAME_CHANGED;\r\nexport const DOMINANT_SPEAKER_CHANGED = JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED;\r\nexport const CONFERENCE_CREATED_TIMESTAMP = JitsiConferenceEvents.CONFERENCE_CREATED_TIMESTAMP;\r\nexport const DTMF_SUPPORT_CHANGED = JitsiConferenceEvents.DTMF_SUPPORT_CHANGED;\r\nexport const ENDPOINT_MESSAGE_RECEIVED = JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED;\r\nexport const ENDPOINT_STATS_RECEIVED = JitsiConferenceEvents.ENDPOINT_STATS_RECEIVED;\r\nexport const JVB121_STATUS = JitsiConferenceEvents.JVB121_STATUS;\r\nexport const KICKED = JitsiConferenceEvents.KICKED;\r\nexport const PARTICIPANT_KICKED = JitsiConferenceEvents.PARTICIPANT_KICKED;\r\nexport const LAST_N_ENDPOINTS_CHANGED = JitsiConferenceEvents.LAST_N_ENDPOINTS_CHANGED;\r\nexport const FORWARDED_SOURCES_CHANGED = JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED;\r\nexport const LOCK_STATE_CHANGED = JitsiConferenceEvents.LOCK_STATE_CHANGED;\r\nexport const SERVER_REGION_CHANGED = JitsiConferenceEvents.SERVER_REGION_CHANGED;\r\nexport const _MEDIA_SESSION_STARTED = JitsiConferenceEvents._MEDIA_SESSION_STARTED;\r\nexport const _MEDIA_SESSION_ACTIVE_CHANGED = JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED;\r\nexport const MEMBERS_ONLY_CHANGED = JitsiConferenceEvents.MEMBERS_ONLY_CHANGED;\r\nexport const MESSAGE_RECEIVED = JitsiConferenceEvents.MESSAGE_RECEIVED;\r\nexport const NO_AUDIO_INPUT = JitsiConferenceEvents.NO_AUDIO_INPUT;\r\nexport const NOISY_MIC = JitsiConferenceEvents.NOISY_MIC;\r\nexport const NON_PARTICIPANT_MESSAGE_RECEIVED = JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED;\r\nexport const PRIVATE_MESSAGE_RECEIVED = JitsiConferenceEvents.PRIVATE_MESSAGE_RECEIVED;\r\nexport const PARTCIPANT_FEATURES_CHANGED = JitsiConferenceEvents.PARTCIPANT_FEATURES_CHANGED;\r\nexport const PARTICIPANT_PROPERTY_CHANGED = JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED;\r\nexport const P2P_STATUS = JitsiConferenceEvents.P2P_STATUS;\r\nexport const PHONE_NUMBER_CHANGED = JitsiConferenceEvents.PHONE_NUMBER_CHANGED;\r\nexport const PROPERTIES_CHANGED = JitsiConferenceEvents.PROPERTIES_CHANGED;\r\nexport const RECORDER_STATE_CHANGED = JitsiConferenceEvents.RECORDER_STATE_CHANGED;\r\nexport const VIDEO_SIP_GW_AVAILABILITY_CHANGED = JitsiConferenceEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED;\r\nexport const VIDEO_SIP_GW_SESSION_STATE_CHANGED = JitsiConferenceEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED;\r\nexport const START_MUTED_POLICY_CHANGED = JitsiConferenceEvents.START_MUTED_POLICY_CHANGED;\r\nexport const STARTED_MUTED = JitsiConferenceEvents.STARTED_MUTED;\r\nexport const SUBJECT_CHANGED = JitsiConferenceEvents.SUBJECT_CHANGED;\r\nexport const SUSPEND_DETECTED = JitsiConferenceEvents.SUSPEND_DETECTED;\r\nexport const TALK_WHILE_MUTED = JitsiConferenceEvents.TALK_WHILE_MUTED;\r\nexport const TRACK_ADDED = JitsiConferenceEvents.TRACK_ADDED;\r\nexport const TRACK_AUDIO_LEVEL_CHANGED = JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED;\r\nexport const TRACK_MUTE_CHANGED = JitsiConferenceEvents.TRACK_MUTE_CHANGED;\r\nexport const TRACK_REMOVED = JitsiConferenceEvents.TRACK_REMOVED;\r\nexport const TRACK_UNMUTE_REJECTED = JitsiConferenceEvents.TRACK_UNMUTE_REJECTED;\r\nexport const TRANSCRIPTION_STATUS_CHANGED = JitsiConferenceEvents.TRANSCRIPTION_STATUS_CHANGED;\r\nexport const USER_JOINED = JitsiConferenceEvents.USER_JOINED;\r\nexport const USER_LEFT = JitsiConferenceEvents.USER_LEFT;\r\nexport const USER_ROLE_CHANGED = JitsiConferenceEvents.USER_ROLE_CHANGED;\r\nexport const USER_STATUS_CHANGED = JitsiConferenceEvents.USER_STATUS_CHANGED;\r\nexport const VIDEO_UNMUTE_PERMISSIONS_CHANGED = JitsiConferenceEvents.VIDEO_UNMUTE_PERMISSIONS_CHANGED;\r\nexport const BOT_TYPE_CHANGED = JitsiConferenceEvents.BOT_TYPE_CHANGED;\r\nexport const LOBBY_USER_JOINED = JitsiConferenceEvents.LOBBY_USER_JOINED;\r\nexport const LOBBY_USER_UPDATED = JitsiConferenceEvents.LOBBY_USER_UPDATED;\r\nexport const LOBBY_USER_LEFT = JitsiConferenceEvents.LOBBY_USER_LEFT;\r\nexport const AV_MODERATION_APPROVED = JitsiConferenceEvents.AV_MODERATION_APPROVED;\r\nexport const AV_MODERATION_REJECTED = JitsiConferenceEvents.AV_MODERATION_REJECTED;\r\nexport const AV_MODERATION_CHANGED = JitsiConferenceEvents.AV_MODERATION_CHANGED;\r\nexport const AV_MODERATION_PARTICIPANT_APPROVED = JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_APPROVED;\r\nexport const AV_MODERATION_PARTICIPANT_REJECTED = JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_REJECTED;\r\nexport const FACE_LANDMARK_ADDED = JitsiConferenceEvents.FACE_LANDMARK_ADDED;\r\nexport const BREAKOUT_ROOMS_MOVE_TO_ROOM = JitsiConferenceEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM;\r\nexport const BREAKOUT_ROOMS_UPDATED = JitsiConferenceEvents.BREAKOUT_ROOMS_UPDATED;\r\nexport const METADATA_UPDATED = JitsiConferenceEvents.METADATA_UPDATED;\r\n","export enum JitsiTrackEvents {\r\n    /**\r\n     * The media track was removed to the conference.\r\n     */\r\n    LOCAL_TRACK_STOPPED = 'track.stopped',\r\n\r\n    /**\r\n     * Audio levels of a this track was changed.\r\n     * The first argument is a number with audio level value in range [0, 1].\r\n     * The second argument is a <tt>TraceablePeerConnection</tt> which is the peer\r\n     * connection which measured the audio level (one audio track can be added\r\n     * to multiple peer connection at the same time). This argument is optional for\r\n     * local tracks for which we can measure audio level without the peer\r\n     * connection (the value will be <tt>undefined</tt>).\r\n     *\r\n     * NOTE The second argument should be treated as library internal and can be\r\n     * removed at any time.\r\n     */\r\n    TRACK_AUDIO_LEVEL_CHANGED = 'track.audioLevelsChanged',\r\n\r\n    /**\r\n     * The audio output of the track was changed.\r\n     */\r\n    TRACK_AUDIO_OUTPUT_CHANGED = 'track.audioOutputChanged',\r\n\r\n    /**\r\n     * A media track mute status was changed.\r\n     */\r\n    TRACK_MUTE_CHANGED = 'track.trackMuteChanged',\r\n\r\n    /**\r\n     * The video type(\"camera\" or \"desktop\") of the track was changed.\r\n     */\r\n    TRACK_VIDEOTYPE_CHANGED = 'track.videoTypeChanged',\r\n\r\n    /**\r\n     * Indicates that the track is not receiving any data even though we expect it\r\n     * to receive data (i.e. the stream is not stopped).\r\n     */\r\n    NO_DATA_FROM_SOURCE = 'track.no_data_from_source',\r\n\r\n    /**\r\n     * Indicates that the local audio track is not receiving any audio input from\r\n     * the microphone that is currently selected.\r\n     */\r\n    NO_AUDIO_INPUT = 'track.no_audio_input',\r\n\r\n    /**\r\n     * Event fired whenever video track's streaming changes.\r\n     * First argument is the sourceName of the track and the second is a string indicating if the connection is currently\r\n     * - active - the connection is active.\r\n     * - inactive - the connection is inactive, was intentionally interrupted by the bridge because of low BWE or because\r\n     *   of the endpoint falling out of last N.\r\n     * - interrupted - a network problem occurred.\r\n     * - restoring - the connection was inactive and is restoring now.\r\n     *\r\n     * The current status value can be obtained by calling JitsiRemoteTrack.getTrackStreamingStatus().\r\n     */\r\n    TRACK_STREAMING_STATUS_CHANGED = 'track.streaming_status_changed',\r\n\r\n    /**\r\n     * An SSRC has been remapped. The track is now associated with a new participant.\r\n     */\r\n    TRACK_OWNER_CHANGED = 'track.owner_changed',\r\n\r\n    /**\r\n     * A track is being removed. Fired when a session terminates for tracks\r\n     * that persist in ssrc-rewriting mode.\r\n     */\r\n    TRACK_REMOVED = 'track.removed',\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const LOCAL_TRACK_STOPPED = JitsiTrackEvents.LOCAL_TRACK_STOPPED;\r\nexport const TRACK_AUDIO_LEVEL_CHANGED = JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED;\r\nexport const TRACK_AUDIO_OUTPUT_CHANGED = JitsiTrackEvents.TRACK_AUDIO_OUTPUT_CHANGED;\r\nexport const TRACK_MUTE_CHANGED = JitsiTrackEvents.TRACK_MUTE_CHANGED;\r\nexport const TRACK_VIDEOTYPE_CHANGED = JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED;\r\nexport const NO_DATA_FROM_SOURCE = JitsiTrackEvents.NO_DATA_FROM_SOURCE;\r\nexport const NO_AUDIO_INPUT = JitsiTrackEvents.NO_AUDIO_INPUT;\r\nexport const TRACK_STREAMING_STATUS_CHANGED = JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED;\r\nexport const TRACK_OWNER_CHANGED = JitsiTrackEvents.TRACK_OWNER_CHANGED;\r\nexport const TRACK_REMOVED = JitsiTrackEvents.TRACK_REMOVED;\r\n","export const CALLSTATS_SCRIPT_URL = 'https://api.callstats.io/static/callstats-ws.min.js';\r\n\r\n/**\r\n * The number of remote speakers for which the audio levels will be calculated using\r\n * RTCRtpReceiver#getSynchronizationSources. Limit the number of endpoints to save cpu on the client as this API call\r\n * is known to take longer to execute when there are many audio receivers.\r\n */\r\nexport const SPEAKERS_AUDIO_LEVELS = 5;\r\n","/**\r\n * The errors for the JitsiTrack objects.\r\n */\r\n\r\nexport enum JitsiTrackErrors {\r\n    /**\r\n     * An error which indicates that some of requested constraints in\r\n     * getUserMedia call were not satisfied.\r\n     */\r\n    CONSTRAINT_FAILED = 'gum.constraint_failed',\r\n\r\n    /**\r\n     * A generic error which indicates an error occurred while selecting\r\n     * a DesktopCapturerSource from the electron app.\r\n     */\r\n    ELECTRON_DESKTOP_PICKER_ERROR = 'gum.electron_desktop_picker_error',\r\n\r\n    /**\r\n     * An error which indicates a custom desktop picker could not be detected\r\n     * for the electron app.\r\n     */\r\n    ELECTRON_DESKTOP_PICKER_NOT_FOUND = 'gum.electron_desktop_picker_not_found',\r\n\r\n    /**\r\n     * Generic getUserMedia error.\r\n     */\r\n    GENERAL = 'gum.general',\r\n\r\n    /**\r\n     * An error which indicates that requested device was not found.\r\n     */\r\n    NOT_FOUND = 'gum.not_found',\r\n\r\n    /**\r\n     * An error which indicates that user denied permission to share requested\r\n     * device.\r\n     */\r\n    PERMISSION_DENIED = 'gum.permission_denied',\r\n\r\n    /**\r\n     * Generic error for screensharing failure.\r\n     */\r\n    SCREENSHARING_GENERIC_ERROR = 'gum.screensharing_generic_error',\r\n\r\n    /**\r\n     * An error which indicates that user canceled screen sharing window\r\n     * selection dialog.\r\n     */\r\n    SCREENSHARING_USER_CANCELED = 'gum.screensharing_user_canceled',\r\n\r\n    /**\r\n     * Indicates that the timeout passed to the obtainAudioAndVideoPermissions has expired without GUM resolving.\r\n     */\r\n    TIMEOUT = 'gum.timeout',\r\n\r\n    /**\r\n     * An error which indicates that track has been already disposed and cannot\r\n     * be longer used.\r\n     */\r\n    TRACK_IS_DISPOSED = 'track.track_is_disposed',\r\n\r\n    /**\r\n     * An error which indicates that track has no MediaStream associated.\r\n     */\r\n    TRACK_NO_STREAM_FOUND = 'track.no_stream_found',\r\n\r\n    /**\r\n     * An error which indicates that requested video resolution is not supported\r\n     * by a webcam.\r\n     */\r\n    UNSUPPORTED_RESOLUTION = 'gum.unsupported_resolution'\r\n}\r\n\r\n// exported for backward compatibility\r\nexport const CONSTRAINT_FAILED = JitsiTrackErrors.CONSTRAINT_FAILED;\r\nexport const ELECTRON_DESKTOP_PICKER_ERROR = JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_ERROR;\r\nexport const ELECTRON_DESKTOP_PICKER_NOT_FOUND = JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_NOT_FOUND;\r\nexport const GENERAL = JitsiTrackErrors.GENERAL;\r\nexport const NOT_FOUND = JitsiTrackErrors.NOT_FOUND;\r\nexport const PERMISSION_DENIED = JitsiTrackErrors.PERMISSION_DENIED;\r\nexport const SCREENSHARING_GENERIC_ERROR = JitsiTrackErrors.SCREENSHARING_GENERIC_ERROR;\r\nexport const SCREENSHARING_USER_CANCELED = JitsiTrackErrors.SCREENSHARING_USER_CANCELED;\r\nexport const TIMEOUT = JitsiTrackErrors.TIMEOUT;\r\nexport const TRACK_IS_DISPOSED = JitsiTrackErrors.TRACK_IS_DISPOSED;\r\nexport const TRACK_NO_STREAM_FOUND = JitsiTrackErrors.TRACK_NO_STREAM_FOUND;\r\nexport const UNSUPPORTED_RESOLUTION = JitsiTrackErrors.UNSUPPORTED_RESOLUTION;\r\n","import * as JitsiTrackErrors from './JitsiTrackErrors';\r\n\r\nconst TRACK_ERROR_TO_MESSAGE_MAP = {};\r\n\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.UNSUPPORTED_RESOLUTION]\r\n    = 'Video resolution is not supported: ';\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.SCREENSHARING_USER_CANCELED]\r\n    = 'User canceled screen sharing prompt';\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.SCREENSHARING_GENERIC_ERROR]\r\n    = 'Unknown error from screensharing';\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_ERROR]\r\n    = 'Unkown error from desktop picker';\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_NOT_FOUND]\r\n    = 'Failed to detect desktop picker';\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.GENERAL]\r\n    = 'Generic getUserMedia error';\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.PERMISSION_DENIED]\r\n    = 'User denied permission to use device(s): ';\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.NOT_FOUND]\r\n    = 'Requested device(s) was/were not found: ';\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.CONSTRAINT_FAILED]\r\n    = 'Constraint could not be satisfied: ';\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TIMEOUT]\r\n    = 'Could not start media source. Timeout occured!';\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_IS_DISPOSED]\r\n    = 'Track has been already disposed';\r\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_NO_STREAM_FOUND]\r\n    = 'Track does not have an associated Media Stream';\r\n\r\n// FIXME: Using prototype inheritance because otherwise instanceof is not\r\n// working properly (see https://github.com/babel/babel/issues/3083)\r\n\r\n/**\r\n *\r\n * Represents an error that occurred to a JitsiTrack. Can represent various\r\n * types of errors. For error descriptions (@see JitsiTrackErrors).\r\n *\r\n * @extends Error\r\n *\r\n *\r\n * @constructor\r\n * @param {Object|string} error - error object or error name\r\n * @param {Object|string} (options) - getUserMedia constraints object or\r\n * error message\r\n * @param {('audio'|'video'|'desktop'|'screen'|'audiooutput')[]} (devices) -\r\n * list of getUserMedia requested devices\r\n */\r\nfunction JitsiTrackError(error, options, devices) {\r\n    if (typeof error === 'object' && typeof error.name !== 'undefined') {\r\n        /**\r\n         * Additional information about original getUserMedia error\r\n         * and constraints.\r\n         * @type {{\r\n         *     error: Object,\r\n         *     constraints: Object,\r\n         *     devices: Array.<'audio'|'video'|'desktop'|'screen'>\r\n         * }}\r\n         */\r\n        this.gum = {\r\n            error,\r\n            constraints: options,\r\n            devices: devices && Array.isArray(devices)\r\n                ? devices.slice(0)\r\n                : undefined\r\n        };\r\n\r\n        switch (error.name) {\r\n        case 'NotAllowedError':\r\n        case 'PermissionDeniedError':\r\n        case 'SecurityError':\r\n            this.name = JitsiTrackErrors.PERMISSION_DENIED;\r\n            this.message\r\n                = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\r\n                    + (this.gum.devices || []).join(', ');\r\n            break;\r\n        case 'DevicesNotFoundError':\r\n        case 'NotFoundError':\r\n            this.name = JitsiTrackErrors.NOT_FOUND;\r\n            this.message\r\n                = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\r\n                    + (this.gum.devices || []).join(', ');\r\n            break;\r\n        case 'ConstraintNotSatisfiedError':\r\n        case 'OverconstrainedError': {\r\n            const constraintName = error.constraintName || error.constraint;\r\n\r\n            // we treat deviceId as unsupported resolution, as we want to\r\n            // retry and finally if everything fails to remove deviceId from\r\n            // mandatory constraints\r\n            if (options\r\n                    && options.video\r\n                    && (!devices || devices.indexOf('video') > -1)\r\n                    && (constraintName === 'minWidth'\r\n                        || constraintName === 'maxWidth'\r\n                        || constraintName === 'minHeight'\r\n                        || constraintName === 'maxHeight'\r\n                        || constraintName === 'width'\r\n                        || constraintName === 'height'\r\n                        || constraintName === 'deviceId')) {\r\n                this.name = JitsiTrackErrors.UNSUPPORTED_RESOLUTION;\r\n                this.message\r\n                    = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\r\n                        + getResolutionFromFailedConstraint(\r\n                            constraintName,\r\n                            options);\r\n            } else {\r\n                this.name = JitsiTrackErrors.CONSTRAINT_FAILED;\r\n                this.message\r\n                    = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\r\n                        + error.constraintName;\r\n            }\r\n            break;\r\n        }\r\n\r\n        default:\r\n            this.name = JitsiTrackErrors.GENERAL;\r\n            this.message\r\n                = error.message || TRACK_ERROR_TO_MESSAGE_MAP[this.name];\r\n            break;\r\n        }\r\n    } else if (typeof error === 'string') {\r\n        if (TRACK_ERROR_TO_MESSAGE_MAP[error]) {\r\n            this.name = error;\r\n            this.message = options || TRACK_ERROR_TO_MESSAGE_MAP[error];\r\n        } else {\r\n            // this is some generic error that do not fit any of our\r\n            // pre-defined errors, so don't give it any specific name, just\r\n            // store message\r\n            this.message = error;\r\n        }\r\n    } else {\r\n        throw new Error('Invalid arguments');\r\n    }\r\n\r\n    this.stack = error.stack || new Error().stack;\r\n}\r\n\r\nJitsiTrackError.prototype = Object.create(Error.prototype);\r\nJitsiTrackError.prototype.constructor = JitsiTrackError;\r\n\r\n/**\r\n * Gets failed resolution constraint from corresponding object.\r\n * @param {string} failedConstraintName\r\n * @param {Object} constraints\r\n * @returns {string|number}\r\n */\r\nfunction getResolutionFromFailedConstraint(failedConstraintName, constraints) {\r\n    if (constraints && constraints.video && constraints.video.mandatory) {\r\n        switch (failedConstraintName) {\r\n        case 'width':\r\n            return constraints.video.mandatory.minWidth;\r\n        case 'height':\r\n            return constraints.video.mandatory.minHeight;\r\n        default:\r\n            return constraints.video.mandatory[failedConstraintName] || '';\r\n        }\r\n    }\r\n\r\n    return '';\r\n}\r\n\r\nexport default JitsiTrackError;\r\n","/**\r\n * This class exports constants and factory methods related to the analytics\r\n * API provided by AnalyticsAdapter. In order for entries in a database to be\r\n * somewhat easily traceable back to the code which produced them, events sent\r\n * through analytics should be defined here.\r\n *\r\n * Since the AnalyticsAdapter API can be used in different ways, for some events\r\n * it is more convenient to just define the event name as a constant. For other\r\n * events a factory function is easier.\r\n *\r\n * A general approach for adding a new event:\r\n * 1. Determine the event type: track, UI, page, or operational. If in doubt use\r\n * operational.\r\n * 2. Determine whether the event is related to other existing events, and\r\n * which fields are desired to be set: name, action, actionSubject, source.\r\n * 3. If the name is sufficient (the other fields are not important), use a\r\n * constant. Otherwise use a factory function.\r\n *\r\n * Note that the AnalyticsAdapter uses the events passed to its functions for\r\n * its own purposes, and might modify them. Because of this, factory functions\r\n * should create new objects.\r\n *\r\n */\r\n\r\nexport enum AnalyticsEvents {\r\n    /**\r\n     * The constant which identifies an event of type \"operational\".\r\n     */\r\n    TYPE_OPERATIONAL = 'operational',\r\n\r\n    /**\r\n     * The constant which identifies an event of type \"page\".\r\n     */\r\n    TYPE_PAGE = 'page',\r\n\r\n    /**\r\n     * The constant which identifies an event of type \"track\".\r\n     */\r\n    TYPE_TRACK = 'track',\r\n\r\n    /**\r\n     * The constant which identifies an event of type \"ui\".\r\n     */\r\n    TYPE_UI = 'ui',\r\n\r\n    /**\r\n     * The \"action\" value for Jingle events which indicates that the Jingle session\r\n     * was restarted (TODO: verify/fix the documentation)\r\n     */\r\n    ACTION_JINGLE_RESTART = 'restart',\r\n\r\n    /**\r\n     * The \"action\" value for Jingle events which indicates that a session-accept\r\n     * timed out (TODO: verify/fix the documentation)\r\n     */\r\n    ACTION_JINGLE_SA_TIMEOUT = 'session-accept.timeout',\r\n\r\n    /**\r\n     * The \"action\" value for Jingle events which indicates that a session-initiate\r\n     * was received.\r\n     */\r\n    ACTION_JINGLE_SI_RECEIVED = 'session-initiate.received',\r\n\r\n    /**\r\n     * The \"action\" value for Jingle events which indicates that a session-initiate\r\n     * not arrived within a timeout (the value is specified in\r\n     * the {@link JingleSessionPC}.\r\n     */\r\n    ACTION_JINGLE_SI_TIMEOUT = 'session-initiate.timeout',\r\n\r\n    /**\r\n     * A constant for the \"terminate\" action for Jingle events. TODO: verify/fix\r\n     * the documentation)\r\n     */\r\n    ACTION_JINGLE_TERMINATE = 'terminate',\r\n\r\n    /**\r\n     * The \"action\" value for Jingle events which indicates that a transport-replace\r\n     * was received.\r\n     */\r\n    ACTION_JINGLE_TR_RECEIVED = 'transport-replace.received',\r\n\r\n    /**\r\n     * The \"action\" value for Jingle events which indicates that a transport-replace\r\n     * succeeded (TODO: verify/fix the documentation)\r\n     */\r\n    ACTION_JINGLE_TR_SUCCESS = 'transport-replace.success',\r\n\r\n    /**\r\n     * The \"action\" value for P2P events which indicates that P2P session initiate message has been rejected by the client\r\n     * because the mandatory requirements were not met.\r\n     */\r\n    ACTION_P2P_DECLINED = 'decline',\r\n\r\n    /**\r\n     * The \"action\" value for P2P events which indicates that a connection was\r\n     * established (TODO: verify/fix the documentation)\r\n     */\r\n    ACTION_P2P_ESTABLISHED = 'established',\r\n\r\n    /**\r\n     * The \"action\" value for P2P events which indicates that something failed.\r\n     */\r\n    ACTION_P2P_FAILED = 'failed',\r\n\r\n    /**\r\n     * The \"action\" value for P2P events which indicates that a switch to\r\n     * jitsi-videobridge happened.\r\n     */\r\n    ACTION_P2P_SWITCH_TO_JVB = 'switch.to.jvb',\r\n\r\n    /**\r\n     * The name of an event which indicates an available device. We send one such\r\n     * event per available device once when the available devices are first known,\r\n     * and every time that they change\r\n     *\r\n     * Properties:\r\n     *      audio_input_device_count: the number of audio input devices available at\r\n     *          the time the event was sent.\r\n     *      audio_output_device_count: the number of audio output devices available\r\n     *          at the time the event was sent.\r\n     *      video_input_device_count: the number of video input devices available at\r\n     *          the time the event was sent.\r\n     *      video_output_device_count: the number of video output devices available\r\n     *          at the time the event was sent.\r\n     *      device_id: an identifier of the device described in this event.\r\n     *      device_group_id:\r\n     *      device_kind: one of 'audioinput', 'audiooutput', 'videoinput' or\r\n     *          'videooutput'.\r\n     *      device_label: a string which describes the device.\r\n     */\r\n    AVAILABLE_DEVICE = 'available.device',\r\n\r\n    /**\r\n     * This appears to be fired only in certain cases when the XMPP connection\r\n     * disconnects (and it was intentional?). It is currently never observed to\r\n     * fire in production.\r\n     *\r\n     * TODO: document\r\n     *\r\n     * Properties:\r\n     *      message: an error message\r\n     */\r\n    CONNECTION_DISCONNECTED = 'connection.disconnected',\r\n\r\n    /**\r\n     * Indicates that the user of the application provided feedback in terms of a\r\n     * rating (an integer from 1 to 5) and an optional comment.\r\n     * Properties:\r\n     *      value: the user's rating (an integer from 1 to 5)\r\n     *      comment: the user's comment\r\n     */\r\n    FEEDBACK = 'feedback',\r\n\r\n    /**\r\n     * Indicates the duration of a particular phase of the ICE connectivity\r\n     * establishment.\r\n     *\r\n     * Properties:\r\n     *      phase: the ICE phase (e.g. 'gathering', 'checking', 'establishment')\r\n     *      value: the duration in milliseconds.\r\n     *      p2p: whether the associated ICE connection is p2p or towards a\r\n     *          jitsi-videobridge\r\n     *      initiator: whether the local Jingle peer is the initiator or responder\r\n     *          in the Jingle session. XXX we probably actually care about the ICE\r\n     *          role (controlling vs controlled), and we assume that this correlates\r\n     *          with the Jingle initiator.\r\n     */\r\n    ICE_DURATION = 'ice.duration',\r\n\r\n    /**\r\n     * Indicates the difference in milliseconds between the ICE establishment time\r\n     * for the P2P and JVB connections (e.g. a value of 10 would indicate that the\r\n     * P2P connection took 10ms more than JVB connection to establish).\r\n     *\r\n     * Properties:\r\n     *      value: the difference in establishment durations in milliseconds.\r\n     *\r\n     */\r\n    ICE_ESTABLISHMENT_DURATION_DIFF = 'ice.establishment.duration.diff',\r\n\r\n    /**\r\n     * Indicates that the ICE state has changed.\r\n     *\r\n     * Properties:\r\n     *      state: the ICE state which was entered (e.g. 'checking', 'connected',\r\n     *          'completed', etc).\r\n     *      value: the time in milliseconds (as reported by\r\n     *          window.performance.now()) that the state change occurred.\r\n     *      p2p: whether the associated ICE connection is p2p or towards a\r\n     *          jitsi-videobridge\r\n     *      signalingState: The signaling state of the associated PeerConnection\r\n     *      reconnect: whether the associated Jingle session is in the process of\r\n     *          reconnecting (or is it ICE? TODO: verify/fix the documentation)\r\n     */\r\n    ICE_STATE_CHANGED = 'ice.state.changed',\r\n\r\n    /**\r\n     * Indicates that no bytes have been sent for the track.\r\n     *\r\n     * Properties:\r\n     *      mediaType: the media type of the local track ('audio' or 'video').\r\n     */\r\n    NO_BYTES_SENT = 'track.no-bytes-sent',\r\n\r\n    /**\r\n     * Indicates that a track was unmuted (?).\r\n     *\r\n     * Properties:\r\n     *      mediaType: the media type of the local track ('audio' or 'video').\r\n     *      trackType: the type of the track ('local' or 'remote').\r\n     *      value: TODO: document\r\n     */\r\n    TRACK_UNMUTED = 'track.unmuted'\r\n}\r\n\r\n// exported for backward compatibility\r\nexport const TYPE_OPERATIONAL = AnalyticsEvents.TYPE_OPERATIONAL;\r\nexport const TYPE_PAGE = AnalyticsEvents.TYPE_PAGE;\r\nexport const TYPE_TRACK = AnalyticsEvents.TYPE_TRACK;\r\nexport const TYPE_UI = AnalyticsEvents.TYPE_UI;\r\nexport const ACTION_JINGLE_RESTART = AnalyticsEvents.ACTION_JINGLE_RESTART;\r\nexport const ACTION_JINGLE_SA_TIMEOUT = AnalyticsEvents.ACTION_JINGLE_SA_TIMEOUT;\r\nexport const ACTION_JINGLE_SI_RECEIVED = AnalyticsEvents.ACTION_JINGLE_SI_RECEIVED;\r\nexport const ACTION_JINGLE_SI_TIMEOUT = AnalyticsEvents.ACTION_JINGLE_SI_TIMEOUT;\r\nexport const ACTION_JINGLE_TERMINATE = AnalyticsEvents.ACTION_JINGLE_TERMINATE;\r\nexport const ACTION_JINGLE_TR_RECEIVED = AnalyticsEvents.ACTION_JINGLE_TR_RECEIVED;\r\nexport const ACTION_JINGLE_TR_SUCCESS = AnalyticsEvents.ACTION_JINGLE_TR_SUCCESS;\r\nexport const ACTION_P2P_DECLINED = AnalyticsEvents.ACTION_P2P_DECLINED;\r\nexport const ACTION_P2P_ESTABLISHED = AnalyticsEvents.ACTION_P2P_ESTABLISHED;\r\nexport const ACTION_P2P_FAILED = AnalyticsEvents.ACTION_P2P_FAILED;\r\nexport const ACTION_P2P_SWITCH_TO_JVB = AnalyticsEvents.ACTION_P2P_SWITCH_TO_JVB;\r\nexport const AVAILABLE_DEVICE = AnalyticsEvents.AVAILABLE_DEVICE;\r\nexport const CONNECTION_DISCONNECTED = AnalyticsEvents.CONNECTION_DISCONNECTED;\r\nexport const FEEDBACK = AnalyticsEvents.FEEDBACK;\r\nexport const ICE_DURATION = AnalyticsEvents.ICE_DURATION;\r\nexport const ICE_ESTABLISHMENT_DURATION_DIFF = AnalyticsEvents.ICE_ESTABLISHMENT_DURATION_DIFF;\r\nexport const ICE_STATE_CHANGED = AnalyticsEvents.ICE_STATE_CHANGED;\r\nexport const NO_BYTES_SENT = AnalyticsEvents.NO_BYTES_SENT;\r\nexport const TRACK_UNMUTED = AnalyticsEvents.TRACK_UNMUTED;\r\n\r\n/**\r\n * Creates an operational event which indicates that we have received a\r\n * \"bridge down\" event from jicofo.\r\n */\r\nexport const createBridgeDownEvent = () => ( {\r\n    action: 'bridge.down',\r\n    actionSubject: 'bridge.down',\r\n    type: TYPE_OPERATIONAL\r\n} );\r\n\r\n/**\r\n * Creates an event which indicates that the XMPP connection failed\r\n * @param errorType TODO\r\n * @param errorMessage TODO\r\n * @param detail connection failed details.\r\n */\r\nexport const createConnectionFailedEvent = ( errorType: unknown, errorMessage: unknown, details: object ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    action: 'connection.failed',\r\n    attributes: {\r\n        'error_type': errorType,\r\n        'error_message': errorMessage,\r\n        ...details\r\n    }\r\n} );\r\n\r\n/**\r\n * Creates a conference event.\r\n *\r\n * @param action - The action of the event.\r\n * @param attributes - The attributes to be added to the event.\r\n */\r\nexport const createConferenceEvent = ( action: string, attributes: object ) => ( {\r\n    action,\r\n    attributes,\r\n    source: 'conference',\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL\r\n} );\r\n\r\n/**\r\n * Creates an operational event which indicates that a particular connection\r\n * stage was reached (i.e. the XMPP connection transitioned to the \"connected\"\r\n * state).\r\n *\r\n * @param stage the stage which was reached\r\n * @param attributes additional attributes for the event. This should be an\r\n * object with a \"value\" property indicating a timestamp in milliseconds\r\n * relative to the beginning of the document's lifetime.\r\n *\r\n */\r\nexport const createConnectionStageReachedEvent = ( stage: unknown, attributes: object ) => ( {\r\n    action: 'connection.stage.reached',\r\n    actionSubject: stage,\r\n    attributes,\r\n    source: 'connection.stage.reached',\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL\r\n} );\r\n\r\n/**\r\n * Creates an operational event for the end-to-end round trip time to a\r\n * specific remote participant.\r\n * @param participantId the ID of the remote participant.\r\n * @param region the region of the remote participant\r\n * @param rtt the rtt\r\n */\r\nexport const createE2eRttEvent = ( participantId: unknown, region: unknown, rtt: unknown ) => ( {\r\n    attributes: {\r\n        'participant_id': participantId,\r\n        region,\r\n        rtt\r\n    },\r\n    name: 'e2e_rtt',\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL\r\n} );\r\n\r\n/**\r\n * Creates an event which indicates that the focus has left the MUC.\r\n */\r\nexport const createFocusLeftEvent = () => ( {\r\n    action: 'focus.left',\r\n    actionSubject: 'focus.left',\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL\r\n} );\r\n\r\n/**\r\n * Creates an event related to a getUserMedia call.\r\n *\r\n * @param action the type of the result that the event represents: 'error',\r\n * 'success', 'warning', etc.\r\n * @param attributes the attributes to attach to the event.\r\n */\r\nexport const createGetUserMediaEvent = ( action: 'error' | 'success' | 'warning' | string, attributes: object = {} ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    source: 'get.user.media',\r\n    action,\r\n    attributes\r\n} );\r\n\r\n/**\r\n * Creates an event related to remote participant connection status changes.\r\n *\r\n * @param attributes the attributes to attach to the event.\r\n */\r\nexport const createParticipantConnectionStatusEvent = ( attributes: object = {} ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    source: 'peer.conn.status',\r\n    action: 'duration',\r\n    attributes\r\n} );\r\n\r\n/**\r\n * Creates an event related to remote track streaming status changes.\r\n *\r\n * @param attributes the attributes to attach to the event.\r\n */\r\nexport const createTrackStreamingStatusEvent = ( attributes: object = {} ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    source: 'track.streaming.status',\r\n    action: 'duration',\r\n    attributes\r\n} );\r\n\r\n/**\r\n * Creates an event for a Jingle-related event.\r\n * @param action the action of the event\r\n * @param attributes attributes to add to the event.\r\n */\r\nexport const createJingleEvent = ( action: unknown, attributes: object = {} ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    action,\r\n    source: 'jingle',\r\n    attributes\r\n} );\r\n\r\n/**\r\n * Creates an event which indicates that a local track was not able to read\r\n * data from its source (a camera or a microphone).\r\n *\r\n * @param mediaType the media type of the local track ('audio' or\r\n * 'video').\r\n */\r\nexport const createNoDataFromSourceEvent = ( mediaType: 'audio' | 'video' | string, value: unknown ) => ( {\r\n    attributes: {\r\n        'media_type': mediaType,\r\n        value\r\n    },\r\n    action: 'track.no.data.from.source',\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL\r\n} );\r\n\r\n/**\r\n * Creates an event for a p2p-related event.\r\n * @param action the action of the event\r\n * @param attributes attributes to add to the event.\r\n */\r\nexport const createP2PEvent = ( action: unknown, attributes: object = {} ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    action,\r\n    source: 'p2p',\r\n    attributes\r\n} )\r\n\r\n/**\r\n * Indicates that we received a remote command to mute.\r\n */\r\nexport const createRemotelyMutedEvent = ( mediaType: unknown ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    action: 'remotely.muted',\r\n    mediaType\r\n} );\r\n\r\n/**\r\n * Creates an event which contains RTP statistics such as RTT and packet loss.\r\n *\r\n * All average RTP stats are currently reported under 1 event name, but with\r\n * different properties that allows to distinguish between a P2P call, a\r\n * call relayed through TURN or the JVB, and multiparty vs 1:1.\r\n *\r\n * The structure of the event is:\r\n *\r\n * {\r\n *      p2p: true,\r\n *      conferenceSize: 2,\r\n *      localCandidateType: \"relay\",\r\n *      remoteCandidateType: \"relay\",\r\n *      transportType: \"udp\",\r\n *\r\n *      // Average RTT of 200ms\r\n *      \"rtt.avg\": 200,\r\n *      \"rtt.samples\": \"[100, 200, 300]\",\r\n *\r\n *      // Average packet loss of 10%\r\n *      \"packet.loss.avg\": 10,\r\n *      \"packet.loss.samples\": '[5, 10, 15]'\r\n *\r\n *      // Difference in milliseconds in the end-to-end RTT between p2p and jvb.\r\n *      // The e2e RTT through jvb is 15ms shorter:\r\n *      \"rtt.diff\": 15,\r\n *\r\n *      // End-to-end RTT through JVB is ms.\r\n *      \"end2end.rtt.avg\" = 100\r\n * }\r\n *\r\n * Note that the value of the \"samples\" properties are (JSON encoded) strings,\r\n * and not JSON arrays, as events' attributes can not be nested. The samples are\r\n * currently included for debug purposes only and can be removed anytime soon\r\n * from the structure.\r\n *\r\n * Also note that not all of values are present in each event, as values are\r\n * obtained and calculated as part of different process/event pipe. For example\r\n * {@link ConnectionAvgStats} instances are doing the reports for each\r\n * {@link TraceablePeerConnection} and work independently from the main stats\r\n * pipe.\r\n */\r\nexport const createRtpStatsEvent = ( attributes: object ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    action: 'rtp.stats',\r\n    attributes\r\n} );\r\n\r\n/**\r\n * Creates an event which contains the round trip time (RTT) to a set of\r\n * regions.\r\n *\r\n * @param attributes\r\n */\r\nexport const createRttByRegionEvent = ( attributes: object ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    action: 'rtt.by.region',\r\n    attributes\r\n} );\r\n\r\n/**\r\n * Creates an event which contains the local and remote ICE candidate types\r\n * for the transport that is currently selected.\r\n *\r\n * @param attributes\r\n */\r\nexport const createTransportStatsEvent = ( attributes: object ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    action: 'transport.stats',\r\n    attributes\r\n} );\r\n\r\n/**\r\n * Creates an event which contains information about the audio output problem (the user id of the affected participant,\r\n * the local audio levels and the remote audio levels that triggered the event).\r\n *\r\n * @param userID - The user id of the affected participant.\r\n * @param localAudioLevels - The local audio levels.\r\n * @param remoteAudioLevels - The audio levels received from the participant.\r\n */\r\nexport const createAudioOutputProblemEvent = ( userID: string, localAudioLevels: unknown, remoteAudioLevels: unknown ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    action: 'audio.output.problem',\r\n    attributes: {\r\n        userID,\r\n        localAudioLevels,\r\n        remoteAudioLevels\r\n    }\r\n} );\r\n\r\n/**\r\n * Creates an event which contains an information related to the bridge channel close event.\r\n *\r\n * @param code - A code from {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}\r\n * @param reason - A string which describes the reason for closing the bridge channel.\r\n */\r\nexport const createBridgeChannelClosedEvent = ( code: string, reason: string ) => ( {\r\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\r\n    action: 'bridge-channel.error',\r\n    attributes: {\r\n        code,\r\n        reason\r\n    }\r\n} );\r\n\r\n/**\r\n * Creates an event which indicates the Time To First Media (TTFM).\r\n * It is measured in milliseconds relative to the beginning of the document's\r\n * lifetime (i.e. the origin used by window.performance.now()), and it excludes\r\n * the following:\r\n * 1. The delay due to getUserMedia()\r\n * 2. The period between the MUC being joined and the reception of the Jingle\r\n * session-initiate from jicofo. This is because jicofo will not start a Jingle\r\n * session until there are at least 2 participants in the room.\r\n *\r\n * @param attributes the attributes to add to the event. Currently used fields:\r\n *      mediaType: the media type of the local track ('audio' or 'video').\r\n *      muted: whether the track has ever been muted (?)\r\n *      value: the TTMF in milliseconds.\r\n */\r\nexport const createTtfmEvent = ( attributes: object ) => createConnectionStageReachedEvent( 'ttfm', attributes );\r\n","export enum Events {\r\n    /**\r\n     * Notifies about audio level in RTP statistics by SSRC.\r\n     *\r\n     * @param ssrc - The synchronization source identifier (SSRC) of the\r\n     * endpoint/participant whose audio level is being reported.\r\n     * @param {number} audioLevel - The audio level of <tt>ssrc</tt> according to\r\n     * RTP statistics.\r\n     * @param {boolean} isLocal - <tt>true</tt> if <tt>ssrc</tt> identifies the\r\n     * local endpoint/participant; otherwise, <tt>false</tt>.\r\n     */\r\n    AUDIO_LEVEL = 'statistics.audioLevel',\r\n\r\n    /**\r\n     * An event fired just before the statistics module gets disposes and it's\r\n     * the last chance to submit some logs that will end up in stats services like\r\n     * CallStats (if enabled).\r\n     */\r\n    BEFORE_DISPOSED = 'statistics.before_disposed',\r\n\r\n    /**\r\n     * An event carrying all statistics by ssrc.\r\n     */\r\n    BYTE_SENT_STATS = 'statistics.byte_sent_stats',\r\n\r\n    /**\r\n     * An event carrying connection statistics.\r\n     *\r\n     * @param {object} connectionStats - The connection statistics carried by the\r\n     * event such as <tt>bandwidth</tt>, <tt>bitrate</tt>, <tt>packetLoss</tt>,\r\n     * <tt>resolution</tt>, and <tt>transport</tt>.\r\n     */\r\n    CONNECTION_STATS = 'statistics.connectionstats',\r\n\r\n    /**\r\n     * An event carrying performance stats.\r\n     */\r\n    LONG_TASKS_STATS = 'statistics.long_tasks_stats'\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const AUDIO_LEVEL = Events.AUDIO_LEVEL;\r\nexport const BEFORE_DISPOSED = Events.BEFORE_DISPOSED;\r\nexport const BYTE_SENT_STATS = Events.BYTE_SENT_STATS;\r\nexport const CONNECTION_STATS = Events.CONNECTION_STATS;\r\nexport const LONG_TASKS_STATS = Events.LONG_TASKS_STATS;\r\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';\r\nimport { getLogger } from '@jitsi/logger';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/* Minimum required Chrome / Chromium version. This applies also to derivatives. */\r\nconst MIN_REQUIRED_CHROME_VERSION = 72;\r\nconst MIN_REQUIRED_SAFARI_VERSION = 14;\r\nconst MIN_REQUIRED_IOS_VERSION = 14;\r\n\r\n// TODO: Move this code to js-utils.\r\n\r\n// NOTE: Now we are extending BrowserDetection in order to preserve\r\n// RTCBrowserType interface but maybe it worth exporting BrowserCapabilities\r\n// and BrowserDetection as separate objects in future.\r\n\r\n/**\r\n * Implements browser capabilities for lib-jitsi-meet.\r\n */\r\nexport default class BrowserCapabilities extends BrowserDetection {\r\n    /**\r\n     * Creates new BrowserCapabilities instance.\r\n     */\r\n    constructor() {\r\n        super();\r\n        logger.info(\r\n            `This appears to be ${this.getName()}, ver: ${this.getVersion()}`);\r\n    }\r\n\r\n    /**\r\n     * Tells whether or not the <tt>MediaStream/tt> is removed from the <tt>PeerConnection</tt> and disposed on video\r\n     * mute (in order to turn off the camera device). This is needed on Firefox because of the following bug\r\n     * https://bugzilla.mozilla.org/show_bug.cgi?id=1735951\r\n     *\r\n     * @return {boolean} <tt>true</tt> if the current browser supports this strategy or <tt>false</tt> otherwise.\r\n     */\r\n    doesVideoMuteByStreamRemove() {\r\n        return this.isChromiumBased() || this.isWebKitBased() || this.isFirefox();\r\n    }\r\n\r\n    /**\r\n     * Checks if the current browser is Chromium based, i.e., it's either Chrome / Chromium or uses it as its engine,\r\n     * but doesn't identify as Chrome.\r\n     *\r\n     * This includes the following browsers:\r\n     * - Chrome and Chromium.\r\n     * - Other browsers which use the Chrome engine, but are detected as Chrome, such as Brave and Vivaldi.\r\n     * - Browsers which are NOT Chrome but use it as their engine, and have custom detection code: Opera, Electron\r\n     *   and NW.JS.\r\n     * This excludes\r\n     * - Chrome on iOS since it uses WKWebView.\r\n     */\r\n    isChromiumBased() {\r\n        return (this.isChrome()\r\n            || this.isElectron()\r\n            || this.isNWJS()\r\n            || this.isOpera())\r\n            && !this.isWebKitBased();\r\n    }\r\n\r\n    /**\r\n     * Checks if the current platform is iOS.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isIosBrowser() {\r\n        const { userAgent, maxTouchPoints, platform } = navigator;\r\n\r\n        return Boolean(userAgent.match(/iP(ad|hone|od)/i))\r\n            || (maxTouchPoints && maxTouchPoints > 2 && /MacIntel/.test(platform));\r\n    }\r\n\r\n    /**\r\n     * Checks if the current browser is WebKit based. It's either\r\n     * Safari or uses WebKit as its engine.\r\n     *\r\n     * This includes Chrome and Firefox on iOS\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isWebKitBased() {\r\n        // https://trac.webkit.org/changeset/236144/webkit/trunk/LayoutTests/webrtc/video-addLegacyTransceiver.html\r\n        return this._bowser.isEngine('webkit')\r\n            && typeof navigator.mediaDevices !== 'undefined'\r\n            && typeof navigator.mediaDevices.getUserMedia !== 'undefined'\r\n            && typeof window.RTCRtpTransceiver !== 'undefined'\r\n            // eslint-disable-next-line no-undef\r\n            && Object.keys(RTCRtpTransceiver.prototype).indexOf('currentDirection') > -1;\r\n    }\r\n\r\n    /**\r\n     * Checks whether current running context is a Trusted Web Application.\r\n     *\r\n     * @returns {boolean} Whether the current context is a TWA.\r\n     */\r\n    isTwa() {\r\n        return 'matchMedia' in window && window.matchMedia('(display-mode:standalone)').matches;\r\n    }\r\n\r\n    /**\r\n     * Checks if the current browser is supported.\r\n     *\r\n     * @returns {boolean} true if the browser is supported, false otherwise.\r\n     */\r\n    isSupported() {\r\n        if (this.isSafari() && this._getSafariVersion() < MIN_REQUIRED_SAFARI_VERSION) {\r\n            return false;\r\n        }\r\n\r\n        return (this.isChromiumBased() && this._getChromiumBasedVersion() >= MIN_REQUIRED_CHROME_VERSION)\r\n            || this.isFirefox()\r\n            || this.isReactNative()\r\n            || this.isWebKitBased();\r\n    }\r\n\r\n    /**\r\n     * Returns whether the browser is supported for Android\r\n     * @returns {boolean} true if the browser is supported for Android devices\r\n     */\r\n    isSupportedAndroidBrowser() {\r\n        return this.isChromiumBased() || this.isFirefox();\r\n    }\r\n\r\n    /**\r\n     * Returns whether the browser is supported for iOS\r\n     * @returns {boolean} true if the browser is supported for iOS devices\r\n     */\r\n    isSupportedIOSBrowser() {\r\n        return this._getIOSVersion() >= MIN_REQUIRED_IOS_VERSION;\r\n    }\r\n\r\n    /**\r\n     * Returns whether or not the current environment needs a user interaction\r\n     * with the page before any unmute can occur.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isUserInteractionRequiredForUnmute() {\r\n        return this.isFirefox() && this.isVersionLessThan('68');\r\n    }\r\n\r\n    /**\r\n     * Checks if the current browser triggers 'onmute'/'onunmute' events when\r\n     * user's connection is interrupted and the video stops playback.\r\n     * @returns {*|boolean} 'true' if the event is supported or 'false'\r\n     * otherwise.\r\n     */\r\n    supportsVideoMuteOnConnInterrupted() {\r\n        return this.isChromiumBased() || this.isReactNative();\r\n    }\r\n\r\n    /**\r\n     * Checks if the current browser reports upload and download bandwidth\r\n     * statistics.\r\n     * @return {boolean}\r\n     */\r\n    supportsBandwidthStatistics() {\r\n        // FIXME bandwidth stats are currently not implemented for FF on our\r\n        // side, but not sure if not possible ?\r\n        return !this.isFirefox() && !this.isWebKitBased();\r\n    }\r\n\r\n    /**\r\n     * Checks if the current browser supports setting codec preferences on the transceiver.\r\n     * @returns {boolean}\r\n     */\r\n    supportsCodecPreferences() {\r\n        return Boolean(window.RTCRtpTransceiver\r\n            && 'setCodecPreferences' in window.RTCRtpTransceiver.prototype\r\n            && window.RTCRtpReceiver\r\n            && typeof window.RTCRtpReceiver.getCapabilities !== 'undefined')\r\n\r\n            // this is not working on Safari because of the following bug\r\n            // https://bugs.webkit.org/show_bug.cgi?id=215567\r\n            && !this.isWebKitBased();\r\n    }\r\n\r\n    /**\r\n     * Checks if the current browser support the device change event.\r\n     * @return {boolean}\r\n     */\r\n    supportsDeviceChangeEvent() {\r\n        return navigator.mediaDevices\r\n            && typeof navigator.mediaDevices.ondevicechange !== 'undefined'\r\n            && typeof navigator.mediaDevices.addEventListener !== 'undefined';\r\n    }\r\n\r\n    /**\r\n     * Checks if the current browser supports the Long Tasks API that lets us observe\r\n     * performance measurement events and be notified of tasks that take longer than\r\n     * 50ms to execute on the main thread.\r\n     */\r\n    supportsPerformanceObserver() {\r\n        return typeof window.PerformanceObserver !== 'undefined'\r\n            && PerformanceObserver.supportedEntryTypes.indexOf('longtask') > -1;\r\n    }\r\n\r\n    /**\r\n     * Checks if the current browser supports audio level stats on the receivers.\r\n     */\r\n    supportsReceiverStats() {\r\n        return typeof window.RTCRtpReceiver !== 'undefined'\r\n            && Object.keys(RTCRtpReceiver.prototype).indexOf('getSynchronizationSources') > -1\r\n\r\n            // Disable this on Safari because it is reporting 0.000001 as the audio levels for all\r\n            // remote audio tracks.\r\n            && !this.isWebKitBased();\r\n    }\r\n\r\n    /**\r\n     * Checks if the current browser reports round trip time statistics for\r\n     * the ICE candidate pair.\r\n     * @return {boolean}\r\n     */\r\n    supportsRTTStatistics() {\r\n        // Firefox does not seem to report RTT for ICE candidate pair:\r\n        // eslint-disable-next-line max-len\r\n        // https://www.w3.org/TR/webrtc-stats/#dom-rtcicecandidatepairstats-currentroundtriptime\r\n        // It does report mozRTT for RTP streams, but at the time of this\r\n        // writing it's value does not make sense most of the time\r\n        // (is reported as 1):\r\n        // https://bugzilla.mozilla.org/show_bug.cgi?id=1241066\r\n        // For Chrome and others we rely on 'googRtt'.\r\n        return !this.isFirefox();\r\n    }\r\n\r\n    /**\r\n     * Returns true if VP9 is supported by the client on the browser. VP9 is currently disabled on Firefox and Safari\r\n     * because of issues with rendering. Please check https://bugzilla.mozilla.org/show_bug.cgi?id=1492500,\r\n     * https://bugs.webkit.org/show_bug.cgi?id=231071 and https://bugs.webkit.org/show_bug.cgi?id=231074 for details.\r\n     */\r\n    supportsVP9() {\r\n        return this.isChromiumBased() || this.isReactNative();\r\n    }\r\n\r\n    /**\r\n     * Checks if the browser uses SDP munging for turning on simulcast.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    usesSdpMungingForSimulcast() {\r\n        return this.isChromiumBased() || this.isReactNative() || this.isWebKitBased();\r\n    }\r\n\r\n    /**\r\n     * Checks if the browser uses RIDs/MIDs for siganling the simulcast streams\r\n     * to the bridge instead of the ssrcs.\r\n     */\r\n    usesRidsForSimulcast() {\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * Checks if the browser supports getDisplayMedia.\r\n     * @returns {boolean} {@code true} if the browser supports getDisplayMedia.\r\n     */\r\n    supportsGetDisplayMedia() {\r\n        return typeof navigator.getDisplayMedia !== 'undefined'\r\n            || (typeof navigator.mediaDevices !== 'undefined'\r\n                && typeof navigator.mediaDevices.getDisplayMedia\r\n                    !== 'undefined');\r\n    }\r\n\r\n    /**\r\n     * Checks if the browser supports WebRTC Encoded Transform, an alternative\r\n     * to insertable streams.\r\n     *\r\n     * NOTE: At the time of this writing the only browser supporting this is\r\n     * Safari / WebKit, behind a flag.\r\n     *\r\n     * @returns {boolean} {@code true} if the browser supports it.\r\n     */\r\n    supportsEncodedTransform() {\r\n        return Boolean(window.RTCRtpScriptTransform);\r\n    }\r\n\r\n    /**\r\n     * Checks if the browser supports insertable streams, needed for E2EE.\r\n     * @returns {boolean} {@code true} if the browser supports insertable streams.\r\n     */\r\n    supportsInsertableStreams() {\r\n        if (!(typeof window.RTCRtpSender !== 'undefined'\r\n            && window.RTCRtpSender.prototype.createEncodedStreams)) {\r\n            return false;\r\n        }\r\n\r\n        // Feature-detect transferable streams which we need to operate in a worker.\r\n        // See https://groups.google.com/a/chromium.org/g/blink-dev/c/1LStSgBt6AM/m/hj0odB8pCAAJ\r\n        const stream = new ReadableStream();\r\n\r\n        try {\r\n            window.postMessage(stream, '*', [ stream ]);\r\n\r\n            return true;\r\n        } catch {\r\n            return false;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Whether the browser supports the RED format for audio.\r\n     */\r\n    supportsAudioRed() {\r\n        return Boolean(window.RTCRtpSender\r\n            && window.RTCRtpSender.getCapabilities\r\n            && window.RTCRtpSender.getCapabilities('audio').codecs.some(codec => codec.mimeType === 'audio/red')\r\n            && window.RTCRtpReceiver\r\n            && window.RTCRtpReceiver.getCapabilities\r\n            && window.RTCRtpReceiver.getCapabilities('audio').codecs.some(codec => codec.mimeType === 'audio/red'));\r\n    }\r\n\r\n    /**\r\n     * Checks if the browser supports unified plan.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    supportsUnifiedPlan() {\r\n        // We do not want to enable unified plan on Electron clients that have Chromium version < 96 because of\r\n        // performance and screensharing issues.\r\n        return !(this.isReactNative() || (this.isElectron() && (this._getChromiumBasedVersion() < 96)));\r\n    }\r\n\r\n    /**\r\n     * Checks if the browser supports voice activity detection via the @type {VADAudioAnalyser} service.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    supportsVADDetection() {\r\n        return this.isChromiumBased();\r\n    }\r\n\r\n    /**\r\n     * Check if the browser supports the RTP RTX feature (and it is usable).\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    supportsRTX() {\r\n        // Disable RTX on Firefox up to 96 because we prefer simulcast over RTX\r\n        // see https://bugzilla.mozilla.org/show_bug.cgi?id=1738504\r\n        return !(this.isFirefox() && this.isVersionLessThan('96'));\r\n    }\r\n\r\n    /**\r\n     * Returns the version of a Chromium based browser.\r\n     *\r\n     * @returns {Number}\r\n     */\r\n    _getChromiumBasedVersion() {\r\n        if (this.isChromiumBased()) {\r\n            // NW.JS doesn't expose the Chrome version in the UA string.\r\n            if (this.isNWJS()) {\r\n                // eslint-disable-next-line no-undef\r\n                return Number.parseInt(process.versions.chromium, 10);\r\n            }\r\n\r\n            // Here we process all browsers which use the Chrome engine but\r\n            // don't necessarily identify as Chrome. We cannot use the version\r\n            // comparing functions because the Electron, Opera and NW.JS\r\n            // versions are inconsequential here, as we need to know the actual\r\n            // Chrome engine version.\r\n            const ua = navigator.userAgent;\r\n\r\n            if (ua.match(/Chrome/)) {\r\n                const version\r\n                    = Number.parseInt(ua.match(/Chrome\\/([\\d.]+)/)[1], 10);\r\n\r\n                return version;\r\n            }\r\n        }\r\n\r\n        return -1;\r\n    }\r\n\r\n    /**\r\n     * Returns the version of a Safari browser.\r\n     *\r\n     * @returns {Number}\r\n     */\r\n    _getSafariVersion() {\r\n        if (this.isSafari()) {\r\n            return Number.parseInt(this.getVersion(), 10);\r\n        }\r\n\r\n        return -1;\r\n    }\r\n\r\n    /**\r\n     * Returns the version of an ios browser.\r\n     *\r\n     * @returns {Number}\r\n     */\r\n    _getIOSVersion() {\r\n        if (this.isWebKitBased()) {\r\n            return Number.parseInt(this.getVersion(), 10);\r\n        }\r\n\r\n        return -1;\r\n    }\r\n}\r\n","import BrowserCapabilities from './BrowserCapabilities';\r\n\r\nexport default new BrowserCapabilities();\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport {\r\n    TYPE_OPERATIONAL,\r\n    TYPE_PAGE,\r\n    TYPE_TRACK,\r\n    TYPE_UI\r\n} from '../../service/statistics/AnalyticsEvents';\r\nimport browser from '../browser';\r\n\r\nconst MAX_CACHE_SIZE = 100;\r\n\r\n// eslist-disable-line no-undef\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * This class provides an API to lib-jitsi-meet and its users for sending\r\n * analytics events. It serves as a bridge to different backend implementations\r\n * (\"analytics handlers\") and a cache for events attempted to be sent before\r\n * the analytics handlers were enabled.\r\n *\r\n * The API is designed to be an easy replacement for the previous version of\r\n * this adapter, and is meant to be extended with more convenience methods.\r\n *\r\n *\r\n * The API calls are translated to objects with the following structure, which\r\n * are then passed to the sendEvent(event) function of the underlying handlers:\r\n *\r\n * {\r\n *    type,\r\n *\r\n *    action,\r\n *    actionSubject,\r\n *    actionSubjectId,\r\n *    attributes,\r\n *    categories,\r\n *    containerId,\r\n *    containerType,\r\n *    name,\r\n *    objectId,\r\n *    objectType,\r\n *    source,\r\n *    tags\r\n * }\r\n *\r\n * The 'type' is one of 'operational', 'page', 'track' or 'ui', and some of the\r\n * other properties are considered required according to the type.\r\n *\r\n * For events with type 'page', the required properties are: name.\r\n *\r\n * For events with type 'operational' and 'ui', the required properties are:\r\n * action, actionSubject, source\r\n *\r\n * For events with type 'page', the required properties are:\r\n * action, actionSubject, source, containerType, containerId, objectType,\r\n * objectId\r\n */\r\nclass AnalyticsAdapter {\r\n    /**\r\n     * Creates new AnalyticsAdapter instance.\r\n     */\r\n    constructor() {\r\n        this.reset();\r\n    }\r\n\r\n    /**\r\n     * Reset the state to the initial one.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    reset() {\r\n        /**\r\n         * Whether this AnalyticsAdapter has been disposed of or not. Once this\r\n         * is set to true, the AnalyticsAdapter is disabled and does not accept\r\n         * any more events, and it can not be re-enabled.\r\n         * @type {boolean}\r\n         */\r\n        this.disposed = false;\r\n\r\n        /**\r\n         * The set of handlers to which events will be sent.\r\n         * @type {Set<any>}\r\n         */\r\n        this.analyticsHandlers = new Set();\r\n\r\n        /**\r\n         * The cache of events which are not sent yet. The cache is enabled\r\n         * while this field is truthy, and disabled otherwise.\r\n         * @type {Array}\r\n         */\r\n        this.cache = [];\r\n\r\n        /**\r\n         * Map of properties that will be added to every event. Note that the\r\n         * keys will be prefixed with \"permanent.\".\r\n         */\r\n        this.permanentProperties = {};\r\n\r\n        /**\r\n         * The name of the conference that this AnalyticsAdapter is associated\r\n         * with.\r\n         * @type {null}\r\n         */\r\n        this.conferenceName = '';\r\n\r\n        this.addPermanentProperties({\r\n            'user_agent': navigator.userAgent,\r\n            'browser_name': browser.getName()\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Dispose analytics. Clears all handlers.\r\n     */\r\n    dispose() {\r\n        logger.warn('Disposing of analytics adapter.');\r\n\r\n        if (this.analyticsHandlers && this.analyticsHandlers.size > 0) {\r\n            this.analyticsHandlers.forEach(handler => {\r\n                if (typeof handler.dispose === 'function') {\r\n                    handler.dispose();\r\n                }\r\n            });\r\n        }\r\n\r\n        this.setAnalyticsHandlers([]);\r\n        this.disposed = true;\r\n    }\r\n\r\n    /**\r\n     * Sets the handlers that are going to be used to send analytics. Sends any\r\n     * cached events.\r\n     * @param {Array} handlers the handlers\r\n     */\r\n    setAnalyticsHandlers(handlers) {\r\n        if (this.disposed) {\r\n            return;\r\n        }\r\n\r\n        this.analyticsHandlers = new Set(handlers);\r\n\r\n        this._setUserProperties();\r\n\r\n        // Note that we disable the cache even if the set of handlers is empty.\r\n        const cache = this.cache;\r\n\r\n        this.cache = null;\r\n        if (cache) {\r\n            cache.forEach(event => this._sendEvent(event));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Set the user properties to the analytics handlers.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    _setUserProperties() {\r\n        this.analyticsHandlers.forEach(handler => {\r\n            try {\r\n                handler.setUserProperties(this.permanentProperties);\r\n            } catch (error) {\r\n                logger.warn('Error in setUserProperties method of one of the '\r\n                    + `analytics handlers: ${error}`);\r\n            }\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Adds a set of permanent properties to this this AnalyticsAdapter.\r\n     * Permanent properties will be added as \"attributes\" to events sent to\r\n     * the underlying \"analytics handlers\", and their keys will be prefixed\r\n     * by \"permanent_\", i.e. adding a permanent property {key: \"value\"} will\r\n     * result in {\"permanent_key\": \"value\"} object to be added to the\r\n     * \"attributes\" field of events.\r\n     *\r\n     * @param {Object} properties the properties to add\r\n     */\r\n    addPermanentProperties(properties) {\r\n        this.permanentProperties = {\r\n            ...this.permanentProperties,\r\n            ...properties\r\n        };\r\n\r\n        this._setUserProperties();\r\n    }\r\n\r\n    /**\r\n     * Sets the name of the conference that this AnalyticsAdapter is associated\r\n     * with.\r\n     * @param name the name to set.\r\n     */\r\n    setConferenceName(name) {\r\n        this.conferenceName = name;\r\n        this.addPermanentProperties({ 'conference_name': name });\r\n    }\r\n\r\n    /**\r\n     * Sends an event with a given name and given properties. The first\r\n     * parameter is either a string or an object. If it is a string, it is used\r\n     * as the event name and the second parameter is used at the attributes to\r\n     * attach to the event. If it is an object, it represents the whole event,\r\n     * including any desired attributes, and the second parameter is ignored.\r\n     *\r\n     * @param {String|Object} eventName either a string to be used as the name\r\n     * of the event, or an event object. If an event object is passed, the\r\n     * properties parameters is ignored.\r\n     * @param {Object} properties the properties/attributes to attach to the\r\n     * event, if eventName is a string.\r\n     */\r\n    sendEvent(eventName, properties = {}) {\r\n        if (this.disposed) {\r\n            return;\r\n        }\r\n\r\n        let event = null;\r\n\r\n        if (typeof eventName === 'string') {\r\n            event = {\r\n                type: TYPE_OPERATIONAL,\r\n                action: eventName,\r\n                actionSubject: eventName,\r\n                source: eventName,\r\n                attributes: properties\r\n            };\r\n        } else if (typeof eventName === 'object') {\r\n            event = eventName;\r\n        }\r\n\r\n        if (!this._verifyRequiredFields(event)) {\r\n            logger.error(\r\n                `Dropping a mis-formatted event: ${JSON.stringify(event)}`);\r\n\r\n            return;\r\n        }\r\n\r\n        this._sendEvent(event);\r\n    }\r\n\r\n    /**\r\n     * Checks whether an event has all of the required fields set, and tries\r\n     * to fill in some of the missing fields with reasonable default values.\r\n     * Returns true if after this operation the event has all of the required\r\n     * fields set, and false otherwise (if some of the required fields were not\r\n     * set and the attempt to fill them in with a default failed).\r\n     *\r\n     * @param event the event object.\r\n     * @return {boolean} true if the event (after the call to this function)\r\n     * contains all of the required fields, and false otherwise.\r\n     * @private\r\n     */\r\n    _verifyRequiredFields(event) {\r\n        if (!event) {\r\n            return false;\r\n        }\r\n\r\n        if (!event.type) {\r\n            event.type = TYPE_OPERATIONAL;\r\n        }\r\n\r\n        const type = event.type;\r\n\r\n        if (type !== TYPE_OPERATIONAL && type !== TYPE_PAGE\r\n            && type !== TYPE_UI && type !== TYPE_TRACK) {\r\n            logger.error(`Unknown event type: ${type}`);\r\n\r\n            return false;\r\n        }\r\n\r\n        if (type === TYPE_PAGE) {\r\n            return Boolean(event.name);\r\n        }\r\n\r\n        // Try to set some reasonable default values in case some of the\r\n        // parameters required by the handler API are missing.\r\n        event.action = event.action || event.name || event.actionSubject;\r\n        event.actionSubject = event.actionSubject || event.name || event.action;\r\n        event.source = event.source || event.name || event.action\r\n            || event.actionSubject;\r\n\r\n        if (!event.action || !event.actionSubject || !event.source) {\r\n            logger.error(\r\n                'Required field missing (action, actionSubject or source)');\r\n\r\n            return false;\r\n        }\r\n\r\n        // Track events have additional required fields.\r\n        if (type === TYPE_TRACK) {\r\n            event.objectType = event.objectType || 'generic-object-type';\r\n            event.containerType = event.containerType || 'conference';\r\n            if (event.containerType === 'conference' && !event.containerId) {\r\n                event.containerId = this.conferenceName;\r\n            }\r\n\r\n\r\n            if (!event.objectType || !event.objectId\r\n                || !event.containerType || !event.containerId) {\r\n                logger.error(\r\n                    'Required field missing (containerId, containerType, '\r\n                        + 'objectId or objectType)');\r\n\r\n                return false;\r\n            }\r\n        }\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * Saves an event to the cache, if the cache is enabled.\r\n     * @param event the event to save.\r\n     * @returns {boolean} true if the event was saved, and false otherwise (i.e.\r\n     * if the cache was disabled).\r\n     * @private\r\n     */\r\n    _maybeCacheEvent(event) {\r\n        if (this.cache) {\r\n            this.cache.push(event);\r\n\r\n            // We limit the size of the cache, in case the user fails to ever\r\n            // set the analytics handlers.\r\n            if (this.cache.length > MAX_CACHE_SIZE) {\r\n                this.cache.splice(0, 1);\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        return false;\r\n\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param event\r\n     * @private\r\n     */\r\n    _sendEvent(event) {\r\n        if (this._maybeCacheEvent(event)) {\r\n            // The event was consumed by the cache.\r\n        } else {\r\n            this.analyticsHandlers.forEach(handler => {\r\n                try {\r\n                    handler.sendEvent(event);\r\n                } catch (e) {\r\n                    logger.warn(`Error sending analytics event: ${e}`);\r\n                }\r\n            });\r\n        }\r\n    }\r\n}\r\n\r\nexport default new AnalyticsAdapter();\r\n","/* global callstats */\r\n\r\nimport browser from '../browser';\r\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\r\n\r\nconst logger = require('@jitsi/logger').getLogger(__filename);\r\n\r\n/**\r\n * We define enumeration of wrtcFuncNames as we need them before\r\n * callstats is initialized to queue events.\r\n * @const\r\n * @see http://www.callstats.io/api/#enumeration-of-wrtcfuncnames\r\n */\r\nconst wrtcFuncNames = {\r\n    createOffer: 'createOffer',\r\n    createAnswer: 'createAnswer',\r\n    setLocalDescription: 'setLocalDescription',\r\n    setRemoteDescription: 'setRemoteDescription',\r\n    addIceCandidate: 'addIceCandidate',\r\n    getUserMedia: 'getUserMedia',\r\n    iceConnectionFailure: 'iceConnectionFailure',\r\n    signalingError: 'signalingError',\r\n    applicationLog: 'applicationLog'\r\n};\r\n\r\n/**\r\n * We define enumeration of fabricEvent as we need them before\r\n * callstats is initialized to queue events.\r\n * @const\r\n * @see http://www.callstats.io/api/#enumeration-of-fabricevent\r\n */\r\nconst fabricEvent = {\r\n    fabricHold: 'fabricHold',\r\n    fabricResume: 'fabricResume',\r\n    audioMute: 'audioMute',\r\n    audioUnmute: 'audioUnmute',\r\n    videoPause: 'videoPause',\r\n    videoResume: 'videoResume',\r\n    fabricUsageEvent: 'fabricUsageEvent',\r\n    fabricStats: 'fabricStats',\r\n    fabricTerminated: 'fabricTerminated',\r\n    screenShareStart: 'screenShareStart',\r\n    screenShareStop: 'screenShareStop',\r\n    dominantSpeaker: 'dominantSpeaker',\r\n    activeDeviceList: 'activeDeviceList'\r\n};\r\n\r\n/**\r\n * The user id to report to callstats as destination.\r\n * @type {string}\r\n */\r\nconst DEFAULT_REMOTE_USER = 'jitsi';\r\n\r\n/**\r\n * Type of pending reports, can be event or an error.\r\n * @type {{ERROR: string, EVENT: string}}\r\n */\r\nconst reportType = {\r\n    ERROR: 'error',\r\n    EVENT: 'event',\r\n    MST_WITH_USERID: 'mstWithUserID'\r\n};\r\n\r\n/**\r\n * Set of currently existing {@link CallStats} instances.\r\n * @type {Set<CallStats>}\r\n */\r\nlet _fabrics;\r\n\r\n/**\r\n * An instance of this class is a wrapper for the CallStats API fabric. A fabric\r\n * reports one peer connection to the CallStats backend and is allocated with\r\n * {@link callstats.addNewFabric}. It has a bunch of instance methods for\r\n * reporting various events. A fabric is considered disposed when\r\n * {@link CallStats.sendTerminateEvent} is executed.\r\n *\r\n * Currently only one backend instance can be created ever and it's done using\r\n * {@link CallStats.initBackend}. At the time of this writing there is no way to\r\n * explicitly shutdown the backend, but it's supposed to close it's connection\r\n * automatically, after all fabrics have been terminated.\r\n */\r\nexport default class CallStats {\r\n    /**\r\n     * A callback passed to {@link callstats.addNewFabric}.\r\n     * @param {string} error 'success' means ok\r\n     * @param {string} msg some more details\r\n     * @private\r\n     */\r\n    static _addNewFabricCallback(error, msg) {\r\n        if (CallStats.backend && error !== 'success') {\r\n            logger.error(`Monitoring status: ${error} msg: ${msg}`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Callback passed to {@link callstats.initialize} (backend initialization)\r\n     * @param {string} error 'success' means ok\r\n     * @param {String} msg\r\n     * @private\r\n     */\r\n    static _initCallback(error, msg) {\r\n        logger.log(`CallStats Status: err=${error} msg=${msg}`);\r\n\r\n        // there is no lib, nothing to report to\r\n        if (error !== 'success') {\r\n            return;\r\n        }\r\n\r\n        CallStats.backendInitialized = true;\r\n\r\n        // I hate that\r\n        let atLeastOneFabric = false;\r\n        let defaultInstance = null;\r\n\r\n        for (const callStatsInstance of CallStats.fabrics.values()) {\r\n            if (!callStatsInstance.hasFabric) {\r\n                logger.debug('addNewFabric - initCallback');\r\n                if (callStatsInstance._addNewFabric()) {\r\n                    atLeastOneFabric = true;\r\n                    if (!defaultInstance) {\r\n                        defaultInstance = callStatsInstance;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        if (!atLeastOneFabric) {\r\n            return;\r\n        }\r\n\r\n        CallStats._emptyReportQueue(defaultInstance);\r\n    }\r\n\r\n    /**\r\n     * Empties report queue.\r\n     *\r\n     * @param {CallStats} csInstance - The callstats instance.\r\n     * @private\r\n     */\r\n    static _emptyReportQueue(csInstance) {\r\n        // There is no conference ID nor a PeerConnection available when some of\r\n        // the events are scheduled on the reportsQueue, so those will be\r\n        // reported on the first initialized fabric.\r\n        const defaultConfID = csInstance.confID;\r\n        const defaultPC = csInstance.peerconnection;\r\n\r\n        // notify callstats about failures if there were any\r\n        for (const report of CallStats.reportsQueue) {\r\n            if (report.type === reportType.ERROR) {\r\n                const errorData = report.data;\r\n\r\n                CallStats._reportError(\r\n                    csInstance,\r\n                    errorData.type,\r\n                    errorData.error,\r\n                    errorData.pc || defaultPC);\r\n            } else if (report.type === reportType.EVENT) {\r\n                // if we have and event to report and we failed to add\r\n                // fabric this event will not be reported anyway, returning\r\n                // an error\r\n                const eventData = report.data;\r\n\r\n                CallStats.backend.sendFabricEvent(\r\n                    report.pc || defaultPC,\r\n                    eventData.event,\r\n                    defaultConfID,\r\n                    eventData.eventData);\r\n            } else if (report.type === reportType.MST_WITH_USERID) {\r\n                const data = report.data;\r\n\r\n                CallStats.backend.associateMstWithUserID(\r\n                    report.pc || defaultPC,\r\n                    data.callStatsId,\r\n                    defaultConfID,\r\n                    data.ssrc,\r\n                    data.usageLabel,\r\n                    data.containerId\r\n                );\r\n            }\r\n        }\r\n        CallStats.reportsQueue.length = 0;\r\n    }\r\n\r\n    /* eslint-disable max-params */\r\n    /**\r\n     * Reports an error to callstats.\r\n     *\r\n     * @param {CallStats} [cs]\r\n     * @param type the type of the error, which will be one of the wrtcFuncNames\r\n     * @param error the error\r\n     * @param pc the peerconnection\r\n     * @private\r\n     */\r\n    static _reportError(cs, type, error, pc) {\r\n        let _error = error;\r\n\r\n        if (!_error) {\r\n            logger.warn('No error is passed!');\r\n            _error = new Error('Unknown error');\r\n        }\r\n        if (CallStats.backendInitialized && cs) {\r\n            CallStats.backend.reportError(pc, cs.confID, type, _error);\r\n        } else {\r\n            CallStats.reportsQueue.push({\r\n                type: reportType.ERROR,\r\n                data: {\r\n                    error: _error,\r\n                    pc,\r\n                    type\r\n                }\r\n            });\r\n        }\r\n\r\n        // else just ignore it\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * Reports an error to callstats.\r\n     *\r\n     * @param {CallStats} cs\r\n     * @param event the type of the event, which will be one of the fabricEvent\r\n     * @param eventData additional data to pass to event\r\n     * @private\r\n     */\r\n    static _reportEvent(cs, event, eventData) {\r\n        const pc = cs && cs.peerconnection;\r\n        const confID = cs && cs.confID;\r\n\r\n        if (CallStats.backendInitialized && cs) {\r\n            CallStats.backend.sendFabricEvent(pc, event, confID, eventData);\r\n        } else {\r\n            CallStats.reportsQueue.push({\r\n                confID,\r\n                pc,\r\n                type: reportType.EVENT,\r\n                data: { event,\r\n                    eventData }\r\n            });\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Wraps some of the CallStats API method and logs their calls with\r\n     * arguments on the debug logging level. Also wraps some of the backend\r\n     * methods execution into try catch blocks to not crash the app in case\r\n     * there is a problem with the backend itself.\r\n     * @param {callstats} theBackend\r\n     * @private\r\n     */\r\n    static _traceAndCatchBackendCalls(theBackend) {\r\n        const tryCatchMethods = [\r\n            'associateMstWithUserID',\r\n            'sendFabricEvent',\r\n            'sendUserFeedback'\r\n\r\n            // 'reportError', - this one needs special handling - see code below\r\n        ];\r\n\r\n        for (const methodName of tryCatchMethods) {\r\n            const originalMethod = theBackend[methodName];\r\n\r\n            theBackend[methodName] = function(...theArguments) {\r\n                try {\r\n                    return originalMethod.apply(theBackend, theArguments);\r\n                } catch (e) {\r\n                    GlobalOnErrorHandler.callErrorHandler(e);\r\n                }\r\n            };\r\n        }\r\n        const debugMethods = [\r\n            'associateMstWithUserID',\r\n            'sendFabricEvent',\r\n            'sendUserFeedback'\r\n\r\n            // 'reportError', - this one needs special handling - see code below\r\n        ];\r\n\r\n        for (const methodName of debugMethods) {\r\n            const originalMethod = theBackend[methodName];\r\n\r\n            theBackend[methodName] = function(...theArguments) {\r\n                logger.debug(methodName, theArguments);\r\n                originalMethod.apply(theBackend, theArguments);\r\n            };\r\n        }\r\n        const originalReportError = theBackend.reportError;\r\n\r\n        /* eslint-disable max-params */\r\n        theBackend.reportError = function(pc, cs, type, ...args) {\r\n            // Logs from the logger are submitted on the applicationLog event\r\n            // \"type\". Logging the arguments on the logger will create endless\r\n            // loop, because it will put all the logs to the logger queue again.\r\n            if (type === wrtcFuncNames.applicationLog) {\r\n                // NOTE otherArguments are not logged to the console on purpose\r\n                // to not log the whole log batch\r\n                // FIXME check the current logging level (currently not exposed\r\n                // by the logger implementation)\r\n                // NOTE it is not safe to log whole objects on react-native as\r\n                // those contain too many circular references and may crash\r\n                // the app.\r\n                if (!browser.isReactNative()) {\r\n                    console && console.debug('reportError', pc, cs, type);\r\n                }\r\n            } else {\r\n                logger.debug('reportError', pc, cs, type, ...args);\r\n            }\r\n            try {\r\n                originalReportError.call(theBackend, pc, cs, type, ...args);\r\n            } catch (exception) {\r\n                if (type === wrtcFuncNames.applicationLog) {\r\n                    console && console.error('reportError', exception);\r\n                } else {\r\n                    GlobalOnErrorHandler.callErrorHandler(exception);\r\n                }\r\n            }\r\n        };\r\n\r\n        /* eslint-enable max-params */\r\n    }\r\n\r\n    /**\r\n     * Returns the Set with the currently existing {@link CallStats} instances.\r\n     * Lazily initializes the Set to allow any Set polyfills to be applied.\r\n     * @type {Set<CallStats>}\r\n     */\r\n    static get fabrics() {\r\n        if (!_fabrics) {\r\n            _fabrics = new Set();\r\n        }\r\n\r\n        return _fabrics;\r\n    }\r\n\r\n    /**\r\n     * Initializes the CallStats backend. Should be called only if\r\n     * {@link CallStats.isBackendInitialized} returns <tt>false</tt>.\r\n     * @param {object} options\r\n     * @param {String} options.callStatsID CallStats credentials - ID\r\n     * @param {String} options.callStatsSecret CallStats credentials - secret\r\n     * @param {string} options.aliasName the <tt>aliasName</tt> part of\r\n     * the <tt>userID</tt> aka endpoint ID, see CallStats docs for more info.\r\n     * @param {string} options.userName the <tt>userName</tt> part of\r\n     * the <tt>userID</tt> aka display name, see CallStats docs for more info.\r\n     * @param {object} options.configParams the set of parameters\r\n     * to enable/disable certain features in the library. See CallStats docs for more info.\r\n     *\r\n     */\r\n    static initBackend(options) {\r\n        if (CallStats.backend) {\r\n            throw new Error('CallStats backend has been initialized already!');\r\n        }\r\n        try {\r\n            const CallStatsBackend = callstats;\r\n\r\n            CallStats.backend = new CallStatsBackend();\r\n            CallStats._traceAndCatchBackendCalls(CallStats.backend);\r\n            CallStats.userID = {\r\n                aliasName: options.aliasName,\r\n                userName: options.userName\r\n            };\r\n            CallStats.callStatsID = options.callStatsID;\r\n            CallStats.callStatsSecret = options.callStatsSecret;\r\n\r\n            const configParams = { ...options.configParams };\r\n\r\n            if (options.applicationName) {\r\n                configParams.applicationVersion = `${options.applicationName} (${browser.getName()})`;\r\n            }\r\n\r\n            if (options.confID) {\r\n                // we first check is there a tenant in the confID\r\n                const match = options.confID.match(/.*\\/(.*)\\/.*/);\r\n\r\n                // if there is no tenant, we will just set '/'\r\n                configParams.siteID = options.siteID || (match && match[1]) || '/';\r\n            }\r\n\r\n            // userID is generated or given by the origin server\r\n            CallStats.backend.initialize(\r\n                CallStats.callStatsID,\r\n                CallStats.callStatsSecret,\r\n                CallStats.userID,\r\n                CallStats._initCallback,\r\n                undefined,\r\n                configParams);\r\n\r\n            const getWiFiStatsMethod = options.getWiFiStatsMethod;\r\n\r\n            if (getWiFiStatsMethod) {\r\n                CallStats.backend.attachWifiStatsHandler(getWiFiStatsMethod);\r\n\r\n                getWiFiStatsMethod().then(result => {\r\n                    if (result) {\r\n                        logger.info('Reported wifi addresses:'\r\n                            , JSON.parse(result).addresses);\r\n                    }\r\n                })\r\n                .catch(() => {});// eslint-disable-line no-empty-function\r\n            }\r\n\r\n            return true;\r\n        } catch (e) {\r\n            // The callstats.io API failed to initialize (e.g. because its\r\n            // download did not succeed in general or on time). Further attempts\r\n            // to utilize it cannot possibly succeed.\r\n            GlobalOnErrorHandler.callErrorHandler(e);\r\n            CallStats.backend = null;\r\n            logger.error(e);\r\n\r\n            return false;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Checks if the CallStats backend has been created. It does not mean that\r\n     * it has been initialized, but only that the API instance has been\r\n     * allocated successfully.\r\n     * @return {boolean} <tt>true</tt> if backend exists or <tt>false</tt>\r\n     * otherwise\r\n     */\r\n    static isBackendInitialized() {\r\n        return Boolean(CallStats.backend);\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats about active device.\r\n     * @param {{deviceList: {String:String}}} devicesData list of devices with\r\n     * their data\r\n     * @param {CallStats} cs callstats instance related to the event\r\n     */\r\n    static sendActiveDeviceListEvent(devicesData, cs) {\r\n        CallStats._reportEvent(cs, fabricEvent.activeDeviceList, devicesData);\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats that there is a log we want to report.\r\n     *\r\n     * @param {Error} e error to send or {String} message\r\n     * @param {CallStats} cs callstats instance related to the error (optional)\r\n     */\r\n    static sendApplicationLog(e, cs) {\r\n        try {\r\n            CallStats._reportError(\r\n                cs,\r\n                wrtcFuncNames.applicationLog,\r\n                e,\r\n                cs && cs.peerconnection);\r\n        } catch (error) {\r\n            // If sendApplicationLog fails it should not be printed to\r\n            // the logger, because it will try to push the logs again\r\n            // (through sendApplicationLog) and an endless loop is created.\r\n            if (console && (typeof console.error === 'function')) {\r\n                // FIXME send analytics event as well\r\n                console.error('sendApplicationLog failed', error);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sends the given feedback through CallStats.\r\n     *\r\n     * @param {string} conferenceID the conference ID for which the feedback\r\n     * will be reported.\r\n     * @param overall an integer between 1 and 5 indicating the\r\n     * user feedback\r\n     * @param comment detailed feedback from the user.\r\n     */\r\n    static sendFeedback(conferenceID, overall, comment) {\r\n        return new Promise((resolve, reject) => {\r\n            if (CallStats.backend) {\r\n                CallStats.backend.sendUserFeedback(\r\n                    conferenceID,\r\n                    {\r\n                        userID: CallStats.userID,\r\n                        overall,\r\n                        comment\r\n                    },\r\n                    (status, message) => {\r\n                        if (status === 'success') {\r\n                            resolve(message);\r\n                        } else {\r\n                            reject(message);\r\n                        }\r\n                    });\r\n            } else {\r\n                const reason = 'Failed to submit feedback to CallStats - no backend';\r\n\r\n                logger.error(reason);\r\n                reject(reason);\r\n            }\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats that getUserMedia failed.\r\n     *\r\n     * @param {Error} e error to send\r\n     * @param {CallStats} cs callstats instance related to the error (optional)\r\n     */\r\n    static sendGetUserMediaFailed(e, cs) {\r\n        CallStats._reportError(cs, wrtcFuncNames.getUserMedia, e, null);\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats for mute events\r\n     * @param mute {boolean} true for muted and false for not muted\r\n     * @param type {String} \"audio\"/\"video\"\r\n     * @param {CallStats} cs callstats instance related to the event\r\n     */\r\n    static sendMuteEvent(mute, type, cs) {\r\n        let event;\r\n\r\n        if (type === 'video') {\r\n            event = mute ? fabricEvent.videoPause : fabricEvent.videoResume;\r\n        } else {\r\n            event = mute ? fabricEvent.audioMute : fabricEvent.audioUnmute;\r\n        }\r\n\r\n        CallStats._reportEvent(cs, event);\r\n    }\r\n\r\n    /**\r\n     * Creates new CallStats instance that handles all callstats API calls for\r\n     * given {@link TraceablePeerConnection}. Each instance is meant to handle\r\n     * one CallStats fabric added with 'addFabric' API method for the\r\n     * {@link TraceablePeerConnection} instance passed in the constructor.\r\n     * @param {TraceablePeerConnection} tpc\r\n     * @param {Object} options\r\n     * @param {string} options.confID the conference ID that wil be used to\r\n     * report the session.\r\n     * @param {string} [options.remoteUserID='jitsi'] the remote user ID to\r\n     * which given <tt>tpc</tt> is connected.\r\n     */\r\n    constructor(tpc, options) {\r\n        this.confID = options.confID;\r\n        this.tpc = tpc;\r\n        this.peerconnection = tpc.peerconnection;\r\n        this.remoteUserID = options.remoteUserID || DEFAULT_REMOTE_USER;\r\n        this.hasFabric = false;\r\n\r\n        CallStats.fabrics.add(this);\r\n\r\n        if (CallStats.backendInitialized) {\r\n            this._addNewFabric();\r\n\r\n            // if this is the first fabric let's try to empty the\r\n            // report queue. Reports all events that we recorded between\r\n            // backend initialization and receiving the first fabric\r\n            if (CallStats.fabrics.size === 1) {\r\n                CallStats._emptyReportQueue(this);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Initializes CallStats fabric by calling \"addNewFabric\" for\r\n     * the peer connection associated with this instance.\r\n     * @return {boolean} true if the call was successful or false otherwise.\r\n     */\r\n    _addNewFabric() {\r\n        logger.info('addNewFabric', this.remoteUserID);\r\n        try {\r\n            const fabricAttributes = {\r\n                remoteEndpointType:\r\n                    this.tpc.isP2P\r\n                        ? CallStats.backend.endpointType.peer\r\n                        : CallStats.backend.endpointType.server\r\n            };\r\n            const ret\r\n                = CallStats.backend.addNewFabric(\r\n                    this.peerconnection,\r\n                    this.remoteUserID,\r\n                    CallStats.backend.fabricUsage.multiplex,\r\n                    this.confID,\r\n                    fabricAttributes,\r\n                    CallStats._addNewFabricCallback);\r\n\r\n            this.hasFabric = true;\r\n\r\n            const success = ret.status === 'success';\r\n\r\n            if (!success) {\r\n                logger.error('callstats fabric not initilized', ret.message);\r\n            }\r\n\r\n            return success;\r\n\r\n        } catch (error) {\r\n            GlobalOnErrorHandler.callErrorHandler(error);\r\n\r\n            return false;\r\n        }\r\n    }\r\n\r\n    /* eslint-disable max-params */\r\n\r\n    /**\r\n     * Lets CallStats module know where is given SSRC rendered by providing\r\n     * renderer tag ID.\r\n     * If the lib is not initialized yet queue the call for later, when it's\r\n     * ready.\r\n     * @param {number} ssrc the SSRC of the stream\r\n     * @param {boolean} isLocal indicates whether this the stream is local\r\n     * @param {string|null} streamEndpointId if the stream is not local the it\r\n     * needs to contain the stream owner's ID\r\n     * @param {string} usageLabel meaningful usage label of this stream like\r\n     *        'microphone', 'camera' or 'screen'.\r\n     * @param {string} containerId  the id of media 'audio' or 'video' tag which\r\n     *        renders the stream.\r\n     */\r\n    associateStreamWithVideoTag(\r\n            ssrc,\r\n            isLocal,\r\n            streamEndpointId,\r\n            usageLabel,\r\n            containerId) {\r\n        if (!CallStats.backend) {\r\n            return;\r\n        }\r\n\r\n        const callStatsId = isLocal ? CallStats.userID : streamEndpointId;\r\n\r\n        if (CallStats.backendInitialized) {\r\n            CallStats.backend.associateMstWithUserID(\r\n                this.peerconnection,\r\n                callStatsId,\r\n                this.confID,\r\n                ssrc,\r\n                usageLabel,\r\n                containerId);\r\n        } else {\r\n            CallStats.reportsQueue.push({\r\n                type: reportType.MST_WITH_USERID,\r\n                pc: this.peerconnection,\r\n                data: {\r\n                    callStatsId,\r\n                    containerId,\r\n                    ssrc,\r\n                    usageLabel\r\n                }\r\n            });\r\n        }\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * Notifies CallStats that we are the new dominant speaker in the\r\n     * conference.\r\n     */\r\n    sendDominantSpeakerEvent() {\r\n        CallStats._reportEvent(this, fabricEvent.dominantSpeaker);\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats that the fabric for the underlying peerconnection was\r\n     * closed and no evens should be reported, after this call.\r\n     */\r\n    sendTerminateEvent() {\r\n        if (CallStats.backendInitialized) {\r\n            CallStats.backend.sendFabricEvent(\r\n                this.peerconnection,\r\n                CallStats.backend.fabricEvent.fabricTerminated,\r\n                this.confID);\r\n        }\r\n        CallStats.fabrics.delete(this);\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats for ice connection failed\r\n     */\r\n    sendIceConnectionFailedEvent() {\r\n        CallStats._reportError(\r\n            this,\r\n            wrtcFuncNames.iceConnectionFailure,\r\n            null,\r\n            this.peerconnection);\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats that peer connection failed to create offer.\r\n     *\r\n     * @param {Error} e error to send\r\n     */\r\n    sendCreateOfferFailed(e) {\r\n        CallStats._reportError(\r\n            this, wrtcFuncNames.createOffer, e, this.peerconnection);\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats that peer connection failed to create answer.\r\n     *\r\n     * @param {Error} e error to send\r\n     */\r\n    sendCreateAnswerFailed(e) {\r\n        CallStats._reportError(\r\n            this, wrtcFuncNames.createAnswer, e, this.peerconnection);\r\n    }\r\n\r\n    /**\r\n     * Sends either resume or hold event for the fabric associated with\r\n     * the underlying peerconnection.\r\n     * @param {boolean} isResume true to resume or false to hold\r\n     */\r\n    sendResumeOrHoldEvent(isResume) {\r\n        CallStats._reportEvent(\r\n            this,\r\n            isResume ? fabricEvent.fabricResume : fabricEvent.fabricHold);\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats for screen sharing events\r\n     * @param {boolean} start true for starting screen sharing and\r\n     * false for not stopping\r\n     * @param {string|null} ssrc - optional ssrc value, used only when\r\n     * starting screen sharing.\r\n     */\r\n    sendScreenSharingEvent(start, ssrc) {\r\n        let eventData;\r\n\r\n        if (ssrc) {\r\n            eventData = { ssrc };\r\n        }\r\n\r\n        CallStats._reportEvent(\r\n            this,\r\n            start ? fabricEvent.screenShareStart : fabricEvent.screenShareStop,\r\n            eventData);\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats that peer connection failed to set local description.\r\n     *\r\n     * @param {Error} e error to send\r\n     */\r\n    sendSetLocalDescFailed(e) {\r\n        CallStats._reportError(\r\n            this, wrtcFuncNames.setLocalDescription, e, this.peerconnection);\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats that peer connection failed to set remote description.\r\n     *\r\n     * @param {Error} e error to send\r\n     */\r\n    sendSetRemoteDescFailed(e) {\r\n        CallStats._reportError(\r\n            this, wrtcFuncNames.setRemoteDescription, e, this.peerconnection);\r\n    }\r\n\r\n    /**\r\n     * Notifies CallStats that peer connection failed to add ICE candidate.\r\n     *\r\n     * @param {Error} e error to send\r\n     */\r\n    sendAddIceCandidateFailed(e) {\r\n        CallStats._reportError(\r\n            this, wrtcFuncNames.addIceCandidate, e, this.peerconnection);\r\n    }\r\n}\r\n\r\n/**\r\n * The CallStats API backend instance\r\n * @type {callstats}\r\n */\r\nCallStats.backend = null;\r\n\r\n// some errors/events may happen before CallStats init\r\n// in this case we accumulate them in this array\r\n// and send them to callstats on init\r\nCallStats.reportsQueue = [];\r\n\r\n/**\r\n * Whether the library was successfully initialized(the backend) using its\r\n * initialize method.\r\n * @type {boolean}\r\n */\r\nCallStats.backendInitialized = false;\r\n\r\n/**\r\n * Part of the CallStats credentials - application ID\r\n * @type {string}\r\n */\r\nCallStats.callStatsID = null;\r\n\r\n/**\r\n * Part of the CallStats credentials - application secret\r\n * @type {string}\r\n */\r\nCallStats.callStatsSecret = null;\r\n\r\n/**\r\n * Local CallStats user ID structure. Can be set only once when\r\n * {@link backend} is initialized, so it's static for the time being.\r\n * See CallStats API for more info:\r\n * https://www.callstats.io/api/#userid\r\n * @type {object}\r\n */\r\nCallStats.userID = null;\r\n","/**\r\n * Provides statistics for the local stream.\r\n */\r\n\r\nconst logger = require('@jitsi/logger').getLogger(__filename);\r\n\r\n/**\r\n * Size of the webaudio analyzer buffer.\r\n * @type {number}\r\n */\r\nconst WEBAUDIO_ANALYZER_FFT_SIZE = 2048;\r\n\r\n/**\r\n * Value of the webaudio analyzer smoothing time parameter.\r\n * @type {number}\r\n */\r\nconst WEBAUDIO_ANALYZER_SMOOTING_TIME = 0.8;\r\n\r\nwindow.AudioContext = window.AudioContext || window.webkitAudioContext;\r\n\r\n/**\r\n * The audio context.\r\n * @type {AudioContext}\r\n */\r\nlet context = null;\r\n\r\n\r\n/**\r\n * Converts time domain data array to audio level.\r\n * @param samples the time domain data array.\r\n * @returns {number} the audio level\r\n */\r\nfunction timeDomainDataToAudioLevel(samples) {\r\n\r\n    let maxVolume = 0;\r\n\r\n    const length = samples.length;\r\n\r\n    for (let i = 0; i < length; i++) {\r\n        if (maxVolume < samples[i]) {\r\n            maxVolume = samples[i];\r\n        }\r\n    }\r\n\r\n    return parseFloat(((maxVolume - 127) / 128).toFixed(3));\r\n}\r\n\r\n/**\r\n * Animates audio level change\r\n * @param newLevel the new audio level\r\n * @param lastLevel the last audio level\r\n * @returns {Number} the audio level to be set\r\n */\r\nfunction animateLevel(newLevel, lastLevel) {\r\n    let value = 0;\r\n    const diff = lastLevel - newLevel;\r\n\r\n    if (diff > 0.2) {\r\n        value = lastLevel - 0.2;\r\n    } else if (diff < -0.4) {\r\n        value = lastLevel + 0.4;\r\n    } else {\r\n        value = newLevel;\r\n    }\r\n\r\n    return parseFloat(value.toFixed(3));\r\n}\r\n\r\n\r\n/**\r\n * <tt>LocalStatsCollector</tt> calculates statistics for the local stream.\r\n *\r\n * @param stream the local stream\r\n * @param interval stats refresh interval given in ms.\r\n * @param callback function that receives the audio levels.\r\n * @constructor\r\n */\r\nexport default function LocalStatsCollector(stream, interval, callback) {\r\n    this.stream = stream;\r\n    this.intervalId = null;\r\n    this.intervalMilis = interval;\r\n    this.audioLevel = 0;\r\n    this.callback = callback;\r\n    this.source = null;\r\n    this.analyser = null;\r\n}\r\n\r\n/**\r\n * Starts the collecting the statistics.\r\n */\r\nLocalStatsCollector.prototype.start = function() {\r\n    if (!LocalStatsCollector.isLocalStatsSupported()) {\r\n        return;\r\n    }\r\n\r\n    context.resume();\r\n    this.analyser = context.createAnalyser();\r\n\r\n    this.analyser.smoothingTimeConstant = WEBAUDIO_ANALYZER_SMOOTING_TIME;\r\n    this.analyser.fftSize = WEBAUDIO_ANALYZER_FFT_SIZE;\r\n\r\n    this.source = context.createMediaStreamSource(this.stream);\r\n\r\n    this.source.connect(this.analyser);\r\n\r\n    this.intervalId = setInterval(\r\n        () => {\r\n            const array = new Uint8Array(this.analyser.frequencyBinCount);\r\n\r\n            this.analyser.getByteTimeDomainData(array);\r\n            const audioLevel = timeDomainDataToAudioLevel(array);\r\n\r\n            // Set the audio levels always as NoAudioSignalDetection now\r\n            // uses audio levels from LocalStatsCollector and waits for\r\n            // atleast 4 secs for a no audio signal before displaying the\r\n            // notification on the UI.\r\n            this.audioLevel = animateLevel(audioLevel, this.audioLevel);\r\n            this.callback(this.audioLevel);\r\n        },\r\n        this.intervalMilis\r\n    );\r\n};\r\n\r\n/**\r\n * Stops collecting the statistics.\r\n */\r\nLocalStatsCollector.prototype.stop = function() {\r\n    if (this.intervalId) {\r\n        clearInterval(this.intervalId);\r\n        this.intervalId = null;\r\n    }\r\n\r\n    this.analyser?.disconnect();\r\n    this.analyser = null;\r\n    this.source?.disconnect();\r\n    this.source = null;\r\n};\r\n\r\n/**\r\n * Checks if the environment has the necessary conditions to support\r\n * collecting stats from local streams.\r\n *\r\n * @returns {boolean}\r\n */\r\nLocalStatsCollector.isLocalStatsSupported = function() {\r\n    return Boolean(window.AudioContext);\r\n};\r\n\r\n/**\r\n * Disconnects the audio context.\r\n */\r\nLocalStatsCollector.disconnectAudioContext = async function() {\r\n    if (context) {\r\n        logger.info('Disconnecting audio context');\r\n        await context.close();\r\n        context = null;\r\n    }\r\n};\r\n\r\n/**\r\n * Connects the audio context.\r\n */\r\nLocalStatsCollector.connectAudioContext = function() {\r\n    if (!LocalStatsCollector.isLocalStatsSupported()) {\r\n        return;\r\n    }\r\n\r\n    logger.info('Connecting audio context');\r\n    context = new AudioContext();\r\n\r\n    context.suspend();\r\n};\r\n\r\n/**\r\n * Initialize the audio context on startup.\r\n */\r\nLocalStatsCollector.connectAudioContext();\r\n","\r\n/**\r\n * The method will increase the given number by 1. If the given counter is equal\r\n * or greater to {@link Number.MAX_SAFE_INTEGER} then it will be rolled back to\r\n * 1.\r\n * @param {number} number - An integer counter value to be incremented.\r\n * @return {number} the next counter value increased by 1 (see the description\r\n * above for exception).\r\n */\r\nexport function safeCounterIncrement(number) {\r\n    let nextValue = number;\r\n\r\n    if (number >= Number.MAX_SAFE_INTEGER) {\r\n        nextValue = 0;\r\n    }\r\n\r\n    return nextValue + 1;\r\n}\r\n\r\n/**\r\n * Calculates the average value of am Array of numbers.\r\n *\r\n * @param {Float32Array} valueArray - Array of numbers.\r\n * @returns {number} - Number array average.\r\n */\r\nexport function calculateAverage(valueArray) {\r\n    return valueArray.length > 0 ? valueArray.reduce((a, b) => a + b) / valueArray.length : 0;\r\n}\r\n\r\n/**\r\n * Calculates a unique hash for a given string similar to Java's\r\n * implementation of String.hashCode()\r\n *\r\n * @param {String} string - String whose hash has to be calculated.\r\n * @returns {number} - Unique hash code calculated.\r\n */\r\nexport function hashString(string) {\r\n    let hash = 0;\r\n\r\n    for (let i = 0; i < string.length; i++) {\r\n        hash += Math.pow(string.charCodeAt(i) * 31, string.length - i);\r\n\r\n        /* eslint-disable no-bitwise */\r\n        hash = hash & hash; // Convert to 32bit integer\r\n    }\r\n\r\n    return Math.abs(hash);\r\n}\r\n\r\n/**\r\n * Returns only the positive values from an array of numbers.\r\n *\r\n * @param {Float32Array} valueArray - Array of vad scores.\r\n * @returns {Array} - Array of positive numbers.\r\n */\r\nexport function filterPositiveValues(valueArray) {\r\n    return valueArray.filter(value => value >= 0);\r\n}\r\n\r\n/**\r\n * This class calculates a simple running average that continually changes\r\n * as more data points are collected and added.\r\n */\r\nexport class RunningAverage {\r\n    /**\r\n     * Creates an instance of the running average calculator.\r\n     */\r\n    constructor() {\r\n        this.average = 0;\r\n        this.n = 0;\r\n    }\r\n\r\n    /**\r\n     * Adds a new data point to the existing set of values and recomputes\r\n     * the running average.\r\n     * @param {number} value\r\n     * @returns {void}\r\n     */\r\n    addNext(value) {\r\n        if (typeof value !== 'number') {\r\n            return;\r\n        }\r\n        this.n += 1;\r\n        this.average = this.average + ((value - this.average) / this.n);\r\n    }\r\n\r\n    /**\r\n     * Obtains the average value for the current subset of values.\r\n     * @returns {number} - computed average.\r\n     */\r\n    getAverage() {\r\n        return this.average;\r\n    }\r\n}\r\n","\r\nimport { getLogger } from '@jitsi/logger';\r\n\r\nimport * as StatisticsEvents from '../../service/statistics/Events';\r\nimport { RunningAverage } from '../util/MathUtil';\r\n\r\nconst logger = getLogger(__filename);\r\nconst MILLI_SECONDS = 1000;\r\nconst SECONDS = 60;\r\n\r\n/**\r\n * This class creates an observer that monitors browser's performance measurement events\r\n * as they are recorded in the browser's performance timeline and computes an average and\r\n * a maximum value for the long task events. Tasks are classified as long tasks if they take\r\n * longer than 50ms to execute on the main thread.\r\n */\r\nexport class PerformanceObserverStats {\r\n    /**\r\n     * Creates a new instance of Performance observer statistics.\r\n     *\r\n     * @param {*} emitter Event emitter for emitting stats periodically\r\n     * @param {*} statsInterval interval for calculating the stats\r\n     */\r\n    constructor(emitter, statsInterval) {\r\n        this.eventEmitter = emitter;\r\n        this.longTasks = 0;\r\n        this.maxDuration = 0;\r\n        this.performanceStatsInterval = statsInterval;\r\n        this.stats = new RunningAverage();\r\n    }\r\n\r\n    /**\r\n     * Obtains the average rate of long tasks observed per min and the\r\n     * duration of the longest task recorded by the observer.\r\n     * @returns {Object}\r\n     */\r\n    getLongTasksStats() {\r\n        return {\r\n            avgRatePerMinute: (this.stats.getAverage() * SECONDS).toFixed(2), // calc rate per min\r\n            maxDurationMs: this.maxDuration\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Starts the performance observer by registering the callback function\r\n     * that calculates the performance statistics periodically.\r\n     * @returns {void}\r\n     */\r\n    startObserver() {\r\n        // Create a handler for when the long task event is fired.\r\n        this.longTaskEventHandler = list => {\r\n            const entries = list.getEntries();\r\n\r\n            for (const task of entries) {\r\n                this.longTasks++;\r\n                this.maxDuration = Math.max(this.maxDuration, task.duration).toFixed(3);\r\n            }\r\n        };\r\n\r\n        // Create an observer for monitoring long tasks.\r\n        logger.info('Creating a Performance Observer for monitoring Long Tasks');\r\n        this.observer = new PerformanceObserver(this.longTaskEventHandler);\r\n        this.observer.observe({ type: 'longtask',\r\n            buffered: true });\r\n        const startTime = Date.now();\r\n\r\n        // Calculate the average # of events/sec and emit a stats event.\r\n        this.longTasksIntervalId = setInterval(() => {\r\n            const now = Date.now();\r\n            const interval = this._lastTimeStamp\r\n                ? (now - this._lastTimeStamp) / MILLI_SECONDS\r\n                : (now - startTime) / MILLI_SECONDS;\r\n            const rate = this.longTasks / interval;\r\n\r\n            this.stats.addNext(rate);\r\n            this.eventEmitter.emit(\r\n                StatisticsEvents.LONG_TASKS_STATS, this.getLongTasksStats());\r\n\r\n            // Reset the counter and start counting events again.\r\n            this.longTasks = 0;\r\n            this._lastTimeStamp = Date.now();\r\n        }, this.performanceStatsInterval);\r\n    }\r\n\r\n    /**\r\n     * Stops the performance observer.\r\n     * @returns {void}\r\n     */\r\n    stopObserver() {\r\n        this.observer && this.observer.disconnect();\r\n        this.longTaskEventHandler = null;\r\n        if (this.longTasksIntervalId) {\r\n            clearInterval(this.longTasksIntervalId);\r\n            this.longTasksIntervalId = null;\r\n        }\r\n    }\r\n}\r\n","export enum MediaType {\r\n    /**\r\n     * The audio type.\r\n     */\r\n    AUDIO = 'audio',\r\n\r\n    /**\r\n     * The video type.\r\n     */\r\n    VIDEO = 'video'\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport * as StatisticsEvents from '../../service/statistics/Events';\r\nimport browser from '../browser';\r\n\r\nconst GlobalOnErrorHandler = require('../util/GlobalOnErrorHandler');\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Calculates packet lost percent using the number of lost packets and the\r\n * number of all packet.\r\n * @param lostPackets the number of lost packets\r\n * @param totalPackets the number of all packets.\r\n * @returns {number} packet loss percent\r\n */\r\nfunction calculatePacketLoss(lostPackets, totalPackets) {\r\n    if (!totalPackets || totalPackets <= 0\r\n            || !lostPackets || lostPackets <= 0) {\r\n        return 0;\r\n    }\r\n\r\n    return Math.round((lostPackets / totalPackets) * 100);\r\n}\r\n\r\n/**\r\n * Holds \"statistics\" for a single SSRC.\r\n * @constructor\r\n */\r\nfunction SsrcStats() {\r\n    this.loss = {};\r\n    this.bitrate = {\r\n        download: 0,\r\n        upload: 0\r\n    };\r\n    this.resolution = {};\r\n    this.framerate = 0;\r\n    this.codec = '';\r\n}\r\n\r\n/**\r\n * Sets the \"loss\" object.\r\n * @param loss the value to set.\r\n */\r\nSsrcStats.prototype.setLoss = function(loss) {\r\n    this.loss = loss || {};\r\n};\r\n\r\n/**\r\n * Sets resolution that belong to the ssrc represented by this instance.\r\n * @param resolution new resolution value to be set.\r\n */\r\nSsrcStats.prototype.setResolution = function(resolution) {\r\n    this.resolution = resolution || {};\r\n};\r\n\r\n/**\r\n * Adds the \"download\" and \"upload\" fields from the \"bitrate\" parameter to\r\n * the respective fields of the \"bitrate\" field of this object.\r\n * @param bitrate an object holding the values to add.\r\n */\r\nSsrcStats.prototype.addBitrate = function(bitrate) {\r\n    this.bitrate.download += bitrate.download;\r\n    this.bitrate.upload += bitrate.upload;\r\n};\r\n\r\n/**\r\n * Resets the bit rate for given <tt>ssrc</tt> that belong to the peer\r\n * represented by this instance.\r\n */\r\nSsrcStats.prototype.resetBitrate = function() {\r\n    this.bitrate.download = 0;\r\n    this.bitrate.upload = 0;\r\n};\r\n\r\n/**\r\n * Sets the \"framerate\".\r\n * @param framerate the value to set.\r\n */\r\nSsrcStats.prototype.setFramerate = function(framerate) {\r\n    this.framerate = framerate || 0;\r\n};\r\n\r\nSsrcStats.prototype.setCodec = function(codec) {\r\n    this.codec = codec || '';\r\n};\r\n\r\n/**\r\n *\r\n */\r\nfunction ConferenceStats() {\r\n\r\n    /**\r\n     * The bandwidth\r\n     * @type {{}}\r\n     */\r\n    this.bandwidth = {};\r\n\r\n    /**\r\n     * The bit rate\r\n     * @type {{}}\r\n     */\r\n    this.bitrate = {};\r\n\r\n    /**\r\n     * The packet loss rate\r\n     * @type {{}}\r\n     */\r\n    this.packetLoss = null;\r\n\r\n    /**\r\n     * Array with the transport information.\r\n     * @type {Array}\r\n     */\r\n    this.transport = [];\r\n}\r\n\r\n/* eslint-disable max-params */\r\n\r\n/**\r\n * <tt>StatsCollector</tt> registers for stats updates of given\r\n * <tt>peerconnection</tt> in given <tt>interval</tt>. On each update particular\r\n * stats are extracted and put in {@link SsrcStats} objects. Once the processing\r\n * is done <tt>audioLevelsUpdateCallback</tt> is called with <tt>this</tt>\r\n * instance as an event source.\r\n *\r\n * @param peerconnection WebRTC PeerConnection object.\r\n * @param audioLevelsInterval\r\n * @param statsInterval stats refresh interval given in ms.\r\n * @param eventEmitter\r\n * @constructor\r\n */\r\nexport default function StatsCollector(peerconnection, audioLevelsInterval, statsInterval, eventEmitter) {\r\n    this.peerconnection = peerconnection;\r\n    this.baselineAudioLevelsReport = null;\r\n    this.currentAudioLevelsReport = null;\r\n    this.currentStatsReport = null;\r\n    this.previousStatsReport = null;\r\n    this.audioLevelReportHistory = {};\r\n    this.audioLevelsIntervalId = null;\r\n    this.eventEmitter = eventEmitter;\r\n    this.conferenceStats = new ConferenceStats();\r\n\r\n    // Updates stats interval\r\n    this.audioLevelsIntervalMilis = audioLevelsInterval;\r\n\r\n    this.speakerList = [];\r\n    this.statsIntervalId = null;\r\n    this.statsIntervalMilis = statsInterval;\r\n\r\n    /**\r\n     * Maps SSRC numbers to {@link SsrcStats}.\r\n     * @type {Map<number,SsrcStats}\r\n     */\r\n    this.ssrc2stats = new Map();\r\n}\r\n\r\n/**\r\n * Set the list of the remote speakers for which audio levels are to be calculated.\r\n *\r\n * @param {Array<string>} speakerList - Endpoint ids.\r\n * @returns {void}\r\n */\r\nStatsCollector.prototype.setSpeakerList = function(speakerList) {\r\n    this.speakerList = speakerList;\r\n};\r\n\r\n/**\r\n * Stops stats updates.\r\n */\r\nStatsCollector.prototype.stop = function() {\r\n    if (this.audioLevelsIntervalId) {\r\n        clearInterval(this.audioLevelsIntervalId);\r\n        this.audioLevelsIntervalId = null;\r\n    }\r\n\r\n    if (this.statsIntervalId) {\r\n        clearInterval(this.statsIntervalId);\r\n        this.statsIntervalId = null;\r\n    }\r\n};\r\n\r\n/**\r\n * Callback passed to <tt>getStats</tt> method.\r\n * @param error an error that occurred on <tt>getStats</tt> call.\r\n */\r\nStatsCollector.prototype.errorCallback = function(error) {\r\n    GlobalOnErrorHandler.callErrorHandler(error);\r\n    logger.error('Get stats error', error);\r\n    this.stop();\r\n};\r\n\r\n/**\r\n * Starts stats updates.\r\n */\r\nStatsCollector.prototype.start = function(startAudioLevelStats) {\r\n    if (startAudioLevelStats) {\r\n        if (browser.supportsReceiverStats()) {\r\n            logger.info('Using RTCRtpSynchronizationSource for remote audio levels');\r\n        }\r\n        this.audioLevelsIntervalId = setInterval(\r\n            () => {\r\n                if (browser.supportsReceiverStats()) {\r\n                    const audioLevels = this.peerconnection.getAudioLevels(this.speakerList);\r\n\r\n                    for (const ssrc in audioLevels) {\r\n                        if (audioLevels.hasOwnProperty(ssrc)) {\r\n                            // Use a scaling factor of 2.5 to report the same\r\n                            // audio levels that getStats reports.\r\n                            const audioLevel = audioLevels[ssrc] * 2.5;\r\n\r\n                            this.eventEmitter.emit(\r\n                                StatisticsEvents.AUDIO_LEVEL,\r\n                                this.peerconnection,\r\n                                Number.parseInt(ssrc, 10),\r\n                                audioLevel,\r\n                                false /* isLocal */);\r\n                        }\r\n                    }\r\n                } else {\r\n                    // Interval updates\r\n                    this.peerconnection.getStats()\r\n                        .then(report => {\r\n                            this.currentAudioLevelsReport = typeof report?.result === 'function'\r\n                                ? report.result()\r\n                                : report;\r\n                            this.processAudioLevelReport();\r\n                            this.baselineAudioLevelsReport = this.currentAudioLevelsReport;\r\n                        })\r\n                        .catch(error => this.errorCallback(error));\r\n                }\r\n            },\r\n            this.audioLevelsIntervalMilis\r\n        );\r\n    }\r\n\r\n    const processStats = () => {\r\n        // Interval updates\r\n        this.peerconnection.getStats()\r\n            .then(report => {\r\n                this.currentStatsReport = typeof report?.result === 'function'\r\n                    ? report.result()\r\n                    : report;\r\n\r\n                try {\r\n                    this.processStatsReport();\r\n                } catch (error) {\r\n                    GlobalOnErrorHandler.callErrorHandler(error);\r\n                    logger.error('Processing of RTP stats failed:', error);\r\n                }\r\n                this.previousStatsReport = this.currentStatsReport;\r\n            })\r\n            .catch(error => this.errorCallback(error));\r\n    };\r\n\r\n    processStats();\r\n    this.statsIntervalId = setInterval(processStats, this.statsIntervalMilis);\r\n};\r\n\r\n/**\r\n *\r\n */\r\nStatsCollector.prototype._processAndEmitReport = function() {\r\n    // process stats\r\n    const totalPackets = {\r\n        download: 0,\r\n        upload: 0\r\n    };\r\n    const lostPackets = {\r\n        download: 0,\r\n        upload: 0\r\n    };\r\n    let bitrateDownload = 0;\r\n    let bitrateUpload = 0;\r\n    const resolutions = {};\r\n    const framerates = {};\r\n    const codecs = {};\r\n    let audioBitrateDownload = 0;\r\n    let audioBitrateUpload = 0;\r\n    let videoBitrateDownload = 0;\r\n    let videoBitrateUpload = 0;\r\n\r\n    for (const [ ssrc, ssrcStats ] of this.ssrc2stats) {\r\n        // process packet loss stats\r\n        const loss = ssrcStats.loss;\r\n        const type = loss.isDownloadStream ? 'download' : 'upload';\r\n\r\n        totalPackets[type] += loss.packetsTotal;\r\n        lostPackets[type] += loss.packetsLost;\r\n\r\n        // process bitrate stats\r\n        bitrateDownload += ssrcStats.bitrate.download;\r\n        bitrateUpload += ssrcStats.bitrate.upload;\r\n\r\n        // collect resolutions and framerates\r\n        const track = this.peerconnection.getTrackBySSRC(ssrc);\r\n\r\n        if (track) {\r\n            let audioCodec;\r\n            let videoCodec;\r\n\r\n            if (track.isAudioTrack()) {\r\n                audioBitrateDownload += ssrcStats.bitrate.download;\r\n                audioBitrateUpload += ssrcStats.bitrate.upload;\r\n                audioCodec = ssrcStats.codec;\r\n            } else {\r\n                videoBitrateDownload += ssrcStats.bitrate.download;\r\n                videoBitrateUpload += ssrcStats.bitrate.upload;\r\n                videoCodec = ssrcStats.codec;\r\n            }\r\n\r\n            const participantId = track.getParticipantId();\r\n\r\n            if (participantId) {\r\n                const resolution = ssrcStats.resolution;\r\n\r\n                if (resolution.width\r\n                        && resolution.height\r\n                        && resolution.width !== -1\r\n                        && resolution.height !== -1) {\r\n                    const userResolutions = resolutions[participantId] || {};\r\n\r\n                    userResolutions[ssrc] = resolution;\r\n                    resolutions[participantId] = userResolutions;\r\n                }\r\n\r\n                if (ssrcStats.framerate > 0) {\r\n                    const userFramerates = framerates[participantId] || {};\r\n\r\n                    userFramerates[ssrc] = ssrcStats.framerate;\r\n                    framerates[participantId] = userFramerates;\r\n                }\r\n\r\n                const userCodecs = codecs[participantId] ?? { };\r\n\r\n                userCodecs[ssrc] = {\r\n                    audio: audioCodec,\r\n                    video: videoCodec\r\n                };\r\n\r\n                codecs[participantId] = userCodecs;\r\n            } else {\r\n                logger.error(`No participant ID returned by ${track}`);\r\n            }\r\n        }\r\n\r\n        ssrcStats.resetBitrate();\r\n    }\r\n\r\n    this.conferenceStats.bitrate = {\r\n        'upload': bitrateUpload,\r\n        'download': bitrateDownload\r\n    };\r\n\r\n    this.conferenceStats.bitrate.audio = {\r\n        'upload': audioBitrateUpload,\r\n        'download': audioBitrateDownload\r\n    };\r\n\r\n    this.conferenceStats.bitrate.video = {\r\n        'upload': videoBitrateUpload,\r\n        'download': videoBitrateDownload\r\n    };\r\n\r\n    this.conferenceStats.packetLoss = {\r\n        total:\r\n            calculatePacketLoss(\r\n                lostPackets.download + lostPackets.upload,\r\n                totalPackets.download + totalPackets.upload),\r\n        download:\r\n            calculatePacketLoss(lostPackets.download, totalPackets.download),\r\n        upload:\r\n            calculatePacketLoss(lostPackets.upload, totalPackets.upload)\r\n    };\r\n\r\n    const avgAudioLevels = {};\r\n    let localAvgAudioLevels;\r\n\r\n    Object.keys(this.audioLevelReportHistory).forEach(ssrc => {\r\n        const { data, isLocal } = this.audioLevelReportHistory[ssrc];\r\n        const avgAudioLevel = data.reduce((sum, currentValue) => sum + currentValue) / data.length;\r\n\r\n        if (isLocal) {\r\n            localAvgAudioLevels = avgAudioLevel;\r\n        } else {\r\n            const track = this.peerconnection.getTrackBySSRC(Number(ssrc));\r\n\r\n            if (track) {\r\n                const participantId = track.getParticipantId();\r\n\r\n                if (participantId) {\r\n                    avgAudioLevels[participantId] = avgAudioLevel;\r\n                }\r\n            }\r\n        }\r\n    });\r\n    this.audioLevelReportHistory = {};\r\n\r\n    this.eventEmitter.emit(\r\n        StatisticsEvents.CONNECTION_STATS,\r\n        this.peerconnection,\r\n        {\r\n            'bandwidth': this.conferenceStats.bandwidth,\r\n            'bitrate': this.conferenceStats.bitrate,\r\n            'packetLoss': this.conferenceStats.packetLoss,\r\n            'resolution': resolutions,\r\n            'framerate': framerates,\r\n            'codec': codecs,\r\n            'transport': this.conferenceStats.transport,\r\n            localAvgAudioLevels,\r\n            avgAudioLevels\r\n        });\r\n    this.conferenceStats.transport = [];\r\n};\r\n\r\n/**\r\n * Converts the value to a non-negative number.\r\n * If the value is either invalid or negative then 0 will be returned.\r\n * @param {*} v\r\n * @return {number}\r\n * @private\r\n */\r\nStatsCollector.prototype.getNonNegativeValue = function(v) {\r\n    let value = v;\r\n\r\n    if (typeof value !== 'number') {\r\n        value = Number(value);\r\n    }\r\n\r\n    if (isNaN(value)) {\r\n        return 0;\r\n    }\r\n\r\n    return Math.max(0, value);\r\n};\r\n\r\n/**\r\n * Calculates bitrate between before and now using a supplied field name and its\r\n * value in the stats.\r\n * @param {RTCInboundRtpStreamStats|RTCSentRtpStreamStats} now the current stats\r\n * @param {RTCInboundRtpStreamStats|RTCSentRtpStreamStats} before the\r\n * previous stats.\r\n * @param fieldName the field to use for calculations.\r\n * @return {number} the calculated bitrate between now and before.\r\n * @private\r\n */\r\nStatsCollector.prototype._calculateBitrate = function(now, before, fieldName) {\r\n    const bytesNow = this.getNonNegativeValue(now[fieldName]);\r\n    const bytesBefore = this.getNonNegativeValue(before[fieldName]);\r\n    const bytesProcessed = Math.max(0, bytesNow - bytesBefore);\r\n\r\n    const timeMs = now.timestamp - before.timestamp;\r\n    let bitrateKbps = 0;\r\n\r\n    if (timeMs > 0) {\r\n        // TODO is there any reason to round here?\r\n        bitrateKbps = Math.round((bytesProcessed * 8) / timeMs);\r\n    }\r\n\r\n    return bitrateKbps;\r\n};\r\n\r\n/**\r\n * Stats processing for spec-compliant RTCPeerConnection#getStats.\r\n */\r\nStatsCollector.prototype.processStatsReport = function() {\r\n    const byteSentStats = {};\r\n\r\n    this.currentStatsReport.forEach(now => {\r\n        const before = this.previousStatsReport ? this.previousStatsReport.get(now.id) : null;\r\n\r\n        // RTCIceCandidatePairStats - https://w3c.github.io/webrtc-stats/#candidatepair-dict*\r\n        if (now.type === 'candidate-pair' && now.nominated && now.state === 'succeeded') {\r\n            const availableIncomingBitrate = now.availableIncomingBitrate;\r\n            const availableOutgoingBitrate = now.availableOutgoingBitrate;\r\n\r\n            if (availableIncomingBitrate || availableOutgoingBitrate) {\r\n                this.conferenceStats.bandwidth = {\r\n                    'download': Math.round(availableIncomingBitrate / 1000),\r\n                    'upload': Math.round(availableOutgoingBitrate / 1000)\r\n                };\r\n            }\r\n\r\n            const remoteUsedCandidate = this.currentStatsReport.get(now.remoteCandidateId);\r\n            const localUsedCandidate = this.currentStatsReport.get(now.localCandidateId);\r\n\r\n            // RTCIceCandidateStats\r\n            // https://w3c.github.io/webrtc-stats/#icecandidate-dict*\r\n            if (remoteUsedCandidate && localUsedCandidate) {\r\n                const remoteIpAddress = browser.isChromiumBased()\r\n                    ? remoteUsedCandidate.ip\r\n                    : remoteUsedCandidate.address;\r\n                const remotePort = remoteUsedCandidate.port;\r\n                const ip = `${remoteIpAddress}:${remotePort}`;\r\n\r\n                const localIpAddress = browser.isChromiumBased()\r\n                    ? localUsedCandidate.ip\r\n                    : localUsedCandidate.address;\r\n                const localPort = localUsedCandidate.port;\r\n                const localip = `${localIpAddress}:${localPort}`;\r\n                const type = remoteUsedCandidate.protocol;\r\n\r\n                // Save the address unless it has been saved already.\r\n                const conferenceStatsTransport = this.conferenceStats.transport;\r\n\r\n                if (!conferenceStatsTransport.some(t =>\r\n                    t.ip === ip\r\n                    && t.type === type\r\n                    && t.localip === localip)) {\r\n                    conferenceStatsTransport.push({\r\n                        ip,\r\n                        type,\r\n                        localip,\r\n                        p2p: this.peerconnection.isP2P,\r\n                        localCandidateType: localUsedCandidate.candidateType,\r\n                        remoteCandidateType: remoteUsedCandidate.candidateType,\r\n                        networkType: localUsedCandidate.networkType,\r\n                        rtt: now.currentRoundTripTime * 1000\r\n                    });\r\n                }\r\n            }\r\n\r\n        // RTCReceivedRtpStreamStats\r\n        // https://w3c.github.io/webrtc-stats/#receivedrtpstats-dict*\r\n        // RTCSentRtpStreamStats\r\n        // https://w3c.github.io/webrtc-stats/#sentrtpstats-dict*\r\n        } else if (now.type === 'inbound-rtp' || now.type === 'outbound-rtp') {\r\n            const ssrc = this.getNonNegativeValue(now.ssrc);\r\n\r\n            if (!ssrc) {\r\n                return;\r\n            }\r\n\r\n            let ssrcStats = this.ssrc2stats.get(ssrc);\r\n\r\n            if (!ssrcStats) {\r\n                ssrcStats = new SsrcStats();\r\n                this.ssrc2stats.set(ssrc, ssrcStats);\r\n            }\r\n\r\n            let isDownloadStream = true;\r\n            let key = 'packetsReceived';\r\n\r\n            if (now.type === 'outbound-rtp') {\r\n                isDownloadStream = false;\r\n                key = 'packetsSent';\r\n            }\r\n\r\n            let packetsNow = now[key];\r\n\r\n            if (!packetsNow || packetsNow < 0) {\r\n                packetsNow = 0;\r\n            }\r\n\r\n            if (before) {\r\n                const packetsBefore = this.getNonNegativeValue(before[key]);\r\n                const packetsDiff = Math.max(0, packetsNow - packetsBefore);\r\n\r\n                const packetsLostNow = this.getNonNegativeValue(now.packetsLost);\r\n                const packetsLostBefore = this.getNonNegativeValue(before.packetsLost);\r\n                const packetsLostDiff = Math.max(0, packetsLostNow - packetsLostBefore);\r\n\r\n                ssrcStats.setLoss({\r\n                    packetsTotal: packetsDiff + packetsLostDiff,\r\n                    packetsLost: packetsLostDiff,\r\n                    isDownloadStream\r\n                });\r\n            }\r\n\r\n            // Get the resolution and framerate for only remote video sources here. For the local video sources,\r\n            // 'track' stats will be used since they have the updated resolution based on the simulcast streams\r\n            // currently being sent. Promise based getStats reports three 'outbound-rtp' streams and there will be\r\n            // more calculations needed to determine what is the highest resolution stream sent by the client if the\r\n            // 'outbound-rtp' stats are used.\r\n            if (now.type === 'inbound-rtp') {\r\n                const resolution = {\r\n                    height: now.frameHeight,\r\n                    width: now.frameWidth\r\n                };\r\n                const frameRate = now.framesPerSecond;\r\n\r\n                if (resolution.height && resolution.width) {\r\n                    ssrcStats.setResolution(resolution);\r\n                }\r\n                ssrcStats.setFramerate(Math.round(frameRate || 0));\r\n\r\n                if (before) {\r\n                    ssrcStats.addBitrate({\r\n                        'download': this._calculateBitrate(now, before, 'bytesReceived'),\r\n                        'upload': 0\r\n                    });\r\n                }\r\n            } else if (before) {\r\n                byteSentStats[ssrc] = this.getNonNegativeValue(now.bytesSent);\r\n                ssrcStats.addBitrate({\r\n                    'download': 0,\r\n                    'upload': this._calculateBitrate(now, before, 'bytesSent')\r\n                });\r\n            }\r\n\r\n            const codec = this.currentStatsReport.get(now.codecId);\r\n\r\n            if (codec) {\r\n                /**\r\n                 * The mime type has the following form: video/VP8 or audio/ISAC,\r\n                 * so we what to keep just the type after the '/', audio and video\r\n                 * keys will be added on the processing side.\r\n                 */\r\n                const codecShortType = codec.mimeType.split('/')[1];\r\n\r\n                codecShortType && ssrcStats.setCodec(codecShortType);\r\n            }\r\n\r\n        // Use track stats for resolution and framerate of the local video source.\r\n        // RTCVideoHandlerStats - https://w3c.github.io/webrtc-stats/#vststats-dict*\r\n        // RTCMediaHandlerStats - https://w3c.github.io/webrtc-stats/#mststats-dict*\r\n        } else if (now.type === 'track' && now.kind === MediaType.VIDEO && !now.remoteSource) {\r\n            const resolution = {\r\n                height: now.frameHeight,\r\n                width: now.frameWidth\r\n            };\r\n            const localVideoTracks = this.peerconnection.getLocalTracks(MediaType.VIDEO);\r\n\r\n            if (!localVideoTracks?.length) {\r\n                return;\r\n            }\r\n\r\n            const ssrc = this.peerconnection.getSsrcByTrackId(now.trackIdentifier);\r\n\r\n            if (!ssrc) {\r\n                return;\r\n            }\r\n            let ssrcStats = this.ssrc2stats.get(ssrc);\r\n\r\n            if (!ssrcStats) {\r\n                ssrcStats = new SsrcStats();\r\n                this.ssrc2stats.set(ssrc, ssrcStats);\r\n            }\r\n            if (resolution.height && resolution.width) {\r\n                ssrcStats.setResolution(resolution);\r\n            }\r\n\r\n            // Calculate the frame rate. 'framesSent' is the total aggregate value for all the simulcast streams.\r\n            // Therefore, it needs to be divided by the total number of active simulcast streams.\r\n            let frameRate = now.framesPerSecond;\r\n\r\n            if (!frameRate) {\r\n                if (before) {\r\n                    const timeMs = now.timestamp - before.timestamp;\r\n\r\n                    if (timeMs > 0 && now.framesSent) {\r\n                        const numberOfFramesSinceBefore = now.framesSent - before.framesSent;\r\n\r\n                        frameRate = (numberOfFramesSinceBefore / timeMs) * 1000;\r\n                    }\r\n                }\r\n\r\n                if (!frameRate) {\r\n                    return;\r\n                }\r\n            }\r\n\r\n            // Get the number of simulcast streams currently enabled from TPC.\r\n            const numberOfActiveStreams = this.peerconnection.getActiveSimulcastStreams();\r\n\r\n            // Reset frame rate to 0 when video is suspended as a result of endpoint falling out of last-n.\r\n            frameRate = numberOfActiveStreams ? Math.round(frameRate / numberOfActiveStreams) : 0;\r\n            ssrcStats.setFramerate(frameRate);\r\n        }\r\n    });\r\n\r\n    if (Object.keys(byteSentStats).length) {\r\n        this.eventEmitter.emit(StatisticsEvents.BYTE_SENT_STATS, this.peerconnection, byteSentStats);\r\n    }\r\n\r\n    this._processAndEmitReport();\r\n};\r\n\r\n/**\r\n * Stats processing logic.\r\n */\r\nStatsCollector.prototype.processAudioLevelReport = function() {\r\n    if (!this.baselineAudioLevelsReport) {\r\n        return;\r\n    }\r\n\r\n    this.currentAudioLevelsReport.forEach(now => {\r\n        if (now.type !== 'track') {\r\n            return;\r\n        }\r\n\r\n        // Audio level\r\n        const audioLevel = now.audioLevel;\r\n\r\n        if (!audioLevel) {\r\n            return;\r\n        }\r\n\r\n        const trackIdentifier = now.trackIdentifier;\r\n        const ssrc = this.peerconnection.getSsrcByTrackId(trackIdentifier);\r\n\r\n        if (ssrc) {\r\n            const isLocal\r\n                = ssrc === this.peerconnection.getLocalSSRC(\r\n                this.peerconnection.getLocalTracks(MediaType.AUDIO));\r\n\r\n            this.eventEmitter.emit(\r\n                StatisticsEvents.AUDIO_LEVEL,\r\n                this.peerconnection,\r\n                ssrc,\r\n                audioLevel,\r\n                isLocal);\r\n        }\r\n    });\r\n};\r\n","import EventEmitter from 'events';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\nimport JitsiTrackError from '../../JitsiTrackError';\r\nimport { JitsiTrackEvents } from '../../JitsiTrackEvents';\r\nimport { FEEDBACK } from '../../service/statistics/AnalyticsEvents';\r\nimport * as StatisticsEvents from '../../service/statistics/Events';\r\nimport browser from '../browser';\r\nimport ScriptUtil from '../util/ScriptUtil';\r\n\r\nimport analytics from './AnalyticsAdapter';\r\nimport CallStats from './CallStats';\r\nimport LocalStats from './LocalStatsCollector';\r\nimport { PerformanceObserverStats } from './PerformanceObserverStats';\r\nimport RTPStats from './RTPStatsCollector';\r\nimport { CALLSTATS_SCRIPT_URL } from './constants';\r\n\r\nconst logger = require('@jitsi/logger').getLogger(__filename);\r\n\r\n/**\r\n * Stores all active {@link Statistics} instances.\r\n * @type {Set<Statistics>}\r\n */\r\nlet _instances;\r\n\r\n/**\r\n * True if callstats API is loaded\r\n */\r\nlet isCallstatsLoaded = false;\r\n\r\n/**\r\n * Since callstats.io is a third party, we cannot guarantee the quality of their\r\n * service. More specifically, their server may take noticeably long time to\r\n * respond. Consequently, it is in our best interest (in the sense that the\r\n * intergration of callstats.io is pretty important to us but not enough to\r\n * allow it to prevent people from joining a conference) to (1) start\r\n * downloading their API as soon as possible and (2) do the downloading\r\n * asynchronously.\r\n *\r\n * @param {StatisticsOptions} options - Options to use for downloading and\r\n * initializing callstats backend.\r\n */\r\nfunction loadCallStatsAPI(options) {\r\n    if (!isCallstatsLoaded) {\r\n        ScriptUtil.loadScript(\r\n            options.customScriptUrl || CALLSTATS_SCRIPT_URL,\r\n            /* async */ true,\r\n            /* prepend */ true,\r\n            /* relativeURL */ undefined,\r\n            /* loadCallback */ () => _initCallStatsBackend(options)\r\n        );\r\n        isCallstatsLoaded = true;\r\n    }\r\n}\r\n\r\n/**\r\n * Initializes Callstats backend.\r\n *\r\n * @param {StatisticsOptions} options - The options to use for initializing\r\n * callstats backend.\r\n * @private\r\n */\r\nfunction _initCallStatsBackend(options) {\r\n    if (CallStats.isBackendInitialized()) {\r\n        return;\r\n    }\r\n\r\n    if (!CallStats.initBackend({\r\n        callStatsID: options.callStatsID,\r\n        callStatsSecret: options.callStatsSecret,\r\n        userName: options.userName,\r\n        aliasName: options.aliasName,\r\n        applicationName: options.applicationName,\r\n        getWiFiStatsMethod: options.getWiFiStatsMethod,\r\n        confID: options.confID,\r\n        siteID: options.siteID,\r\n        configParams: options.configParams\r\n    })) {\r\n        logger.error('CallStats Backend initialization failed bad');\r\n    }\r\n}\r\n\r\n/**\r\n * callstats strips any additional fields from Error except for \"name\", \"stack\",\r\n * \"message\" and \"constraintName\". So we need to bundle additional information\r\n * from JitsiTrackError into error passed to callstats to preserve valuable\r\n * information about error.\r\n * @param {JitsiTrackError} error\r\n */\r\nfunction formatJitsiTrackErrorForCallStats(error) {\r\n    const err = new Error();\r\n\r\n    // Just copy original stack from error\r\n    err.stack = error.stack;\r\n\r\n    // Combine name from error's name plus (possibly) name of original GUM error\r\n    err.name = (error.name || 'Unknown error') + (error.gum && error.gum.error\r\n        && error.gum.error.name ? ` - ${error.gum.error.name}` : '');\r\n\r\n    // Put all constraints into this field. For constraint failed errors we will\r\n    // still know which exactly constraint failed as it will be a part of\r\n    // message.\r\n    err.constraintName = error.gum && error.gum.constraints\r\n        ? JSON.stringify(error.gum.constraints) : '';\r\n\r\n    // Just copy error's message.\r\n    err.message = error.message;\r\n\r\n    return err;\r\n}\r\n\r\n/**\r\n * Init statistic options\r\n * @param options\r\n */\r\nStatistics.init = function(options) {\r\n    Statistics.audioLevelsEnabled = !options.disableAudioLevels;\r\n    if (typeof options.pcStatsInterval === 'number') {\r\n        Statistics.pcStatsInterval = options.pcStatsInterval;\r\n    }\r\n\r\n    if (typeof options.audioLevelsInterval === 'number') {\r\n        Statistics.audioLevelsInterval = options.audioLevelsInterval;\r\n    }\r\n\r\n    if (typeof options.longTasksStatsInterval === 'number') {\r\n        Statistics.longTasksStatsInterval = options.longTasksStatsInterval;\r\n    }\r\n\r\n    Statistics.disableThirdPartyRequests = options.disableThirdPartyRequests;\r\n};\r\n\r\n/**\r\n * The options to configure Statistics.\r\n * @typedef {Object} StatisticsOptions\r\n * @property {string} applicationName - The application name to pass to\r\n * callstats.\r\n * @property {string} aliasName - The alias name to use when initializing callstats.\r\n * @property {string} userName - The user name to use when initializing callstats.\r\n * @property {string} confID - The callstats conference ID to use.\r\n * @property {string} callStatsID - Callstats credentials - the id.\r\n * @property {string} callStatsSecret - Callstats credentials - the secret.\r\n * @property {string} customScriptUrl - A custom lib url to use when downloading\r\n * callstats library.\r\n * @property {string} roomName - The room name we are currently in.\r\n * @property {string} configParams - The set of parameters\r\n * to enable/disable certain features in the library. See CallStats docs for more info.\r\n */\r\n/**\r\n *\r\n * @param xmpp\r\n * @param {StatisticsOptions} options - The options to use creating the\r\n * Statistics.\r\n */\r\nexport default function Statistics(xmpp, options) {\r\n    /**\r\n     * {@link RTPStats} mapped by {@link TraceablePeerConnection.id} which\r\n     * collect RTP statistics for each peerconnection.\r\n     * @type {Map<string, RTPStats}\r\n     */\r\n    this.rtpStatsMap = new Map();\r\n    this.eventEmitter = new EventEmitter();\r\n    this.xmpp = xmpp;\r\n    this.options = options || {};\r\n\r\n    this.callStatsIntegrationEnabled\r\n        = this.options.callStatsID && this.options.callStatsSecret && this.options.enableCallStats\r\n\r\n            // Even though AppID and AppSecret may be specified, the integration\r\n            // of callstats.io may be disabled because of globally-disallowed\r\n            // requests to any third parties.\r\n            && (Statistics.disableThirdPartyRequests !== true);\r\n    if (this.callStatsIntegrationEnabled) {\r\n        this.callStatsApplicationLogsDisabled\r\n            = this.options.callStatsApplicationLogsDisabled;\r\n        if (browser.isReactNative()) {\r\n            _initCallStatsBackend(this.options);\r\n        } else {\r\n            loadCallStatsAPI(this.options);\r\n        }\r\n\r\n        if (!this.options.confID) {\r\n            logger.warn('\"confID\" is not defined');\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Stores {@link CallStats} instances for each\r\n     * {@link TraceablePeerConnection} (one {@link CallStats} instance serves\r\n     * one TPC). The instances are mapped by {@link TraceablePeerConnection.id}.\r\n     * @type {Map<number, CallStats>}\r\n     */\r\n    this.callsStatsInstances = new Map();\r\n\r\n    Statistics.instances.add(this);\r\n}\r\nStatistics.audioLevelsEnabled = false;\r\nStatistics.audioLevelsInterval = 200;\r\nStatistics.pcStatsInterval = 10000;\r\nStatistics.disableThirdPartyRequests = false;\r\nStatistics.analytics = analytics;\r\n\r\nObject.defineProperty(Statistics, 'instances', {\r\n    /**\r\n     * Returns the Set holding all active {@link Statistics} instances. Lazily\r\n     * initializes the Set to allow any Set polyfills to be applied.\r\n     * @type {Set<Statistics>}\r\n     */\r\n    get() {\r\n        if (!_instances) {\r\n            _instances = new Set();\r\n        }\r\n\r\n        return _instances;\r\n    }\r\n});\r\n\r\n/**\r\n * Starts collecting RTP stats for given peerconnection.\r\n * @param {TraceablePeerConnection} peerconnection\r\n */\r\nStatistics.prototype.startRemoteStats = function(peerconnection) {\r\n    this.stopRemoteStats(peerconnection);\r\n\r\n    try {\r\n        const rtpStats\r\n            = new RTPStats(\r\n                peerconnection,\r\n                Statistics.audioLevelsInterval,\r\n                Statistics.pcStatsInterval,\r\n                this.eventEmitter);\r\n\r\n        rtpStats.start(Statistics.audioLevelsEnabled);\r\n        this.rtpStatsMap.set(peerconnection.id, rtpStats);\r\n    } catch (e) {\r\n        logger.error(`Failed to start collecting remote statistics: ${e}`);\r\n    }\r\n};\r\n\r\nStatistics.localStats = [];\r\n\r\nStatistics.startLocalStats = function(track, callback) {\r\n    if (browser.isIosBrowser()) {\r\n        // On iOS browsers audio is lost if the audio input device is in use by another app\r\n        // https://bugs.webkit.org/show_bug.cgi?id=233473\r\n        // The culprit was using the AudioContext, so now we close the AudioContext during\r\n        // the track being muted, and re-instantiate it afterwards.\r\n        track.addEventListener(\r\n        JitsiTrackEvents.NO_DATA_FROM_SOURCE,\r\n\r\n        /**\r\n         * Closes AudioContext on no audio data, and enables it on data received again.\r\n         *\r\n         * @param {boolean} value - Whether we receive audio data or not.\r\n         */\r\n        async value => {\r\n            if (value) {\r\n                for (const localStat of Statistics.localStats) {\r\n                    localStat.stop();\r\n                }\r\n\r\n                await LocalStats.disconnectAudioContext();\r\n            } else {\r\n                LocalStats.connectAudioContext();\r\n                for (const localStat of Statistics.localStats) {\r\n                    localStat.start();\r\n                }\r\n            }\r\n        });\r\n    }\r\n\r\n    if (!Statistics.audioLevelsEnabled) {\r\n        return;\r\n    }\r\n\r\n    track.addEventListener(\r\n        JitsiTrackEvents.LOCAL_TRACK_STOPPED,\r\n        () => {\r\n            Statistics.stopLocalStats(track);\r\n        });\r\n\r\n    const stream = track.getOriginalStream();\r\n    const localStats = new LocalStats(stream, Statistics.audioLevelsInterval,\r\n        callback);\r\n\r\n    this.localStats.push(localStats);\r\n    localStats.start();\r\n};\r\n\r\nStatistics.prototype.addAudioLevelListener = function(listener) {\r\n    if (!Statistics.audioLevelsEnabled) {\r\n        return;\r\n    }\r\n    this.eventEmitter.on(StatisticsEvents.AUDIO_LEVEL, listener);\r\n};\r\n\r\nStatistics.prototype.removeAudioLevelListener = function(listener) {\r\n    if (!Statistics.audioLevelsEnabled) {\r\n        return;\r\n    }\r\n    this.eventEmitter.removeListener(StatisticsEvents.AUDIO_LEVEL, listener);\r\n};\r\n\r\nStatistics.prototype.addBeforeDisposedListener = function(listener) {\r\n    this.eventEmitter.on(StatisticsEvents.BEFORE_DISPOSED, listener);\r\n};\r\n\r\nStatistics.prototype.removeBeforeDisposedListener = function(listener) {\r\n    this.eventEmitter.removeListener(\r\n        StatisticsEvents.BEFORE_DISPOSED, listener);\r\n};\r\n\r\nStatistics.prototype.addConnectionStatsListener = function(listener) {\r\n    this.eventEmitter.on(StatisticsEvents.CONNECTION_STATS, listener);\r\n};\r\n\r\nStatistics.prototype.removeConnectionStatsListener = function(listener) {\r\n    this.eventEmitter.removeListener(\r\n        StatisticsEvents.CONNECTION_STATS,\r\n        listener);\r\n};\r\n\r\nStatistics.prototype.addByteSentStatsListener = function(listener) {\r\n    this.eventEmitter.on(StatisticsEvents.BYTE_SENT_STATS, listener);\r\n};\r\n\r\nStatistics.prototype.removeByteSentStatsListener = function(listener) {\r\n    this.eventEmitter.removeListener(StatisticsEvents.BYTE_SENT_STATS,\r\n        listener);\r\n};\r\n\r\n/**\r\n * Add a listener that would be notified on a LONG_TASKS_STATS event.\r\n *\r\n * @param {Function} listener a function that would be called when notified.\r\n * @returns {void}\r\n */\r\nStatistics.prototype.addLongTasksStatsListener = function(listener) {\r\n    this.eventEmitter.on(StatisticsEvents.LONG_TASKS_STATS, listener);\r\n};\r\n\r\n/**\r\n * Creates an instance of {@link PerformanceObserverStats} and starts the\r\n * observer that records the stats periodically.\r\n *\r\n * @returns {void}\r\n */\r\nStatistics.prototype.attachLongTasksStats = function(conference) {\r\n    if (!browser.supportsPerformanceObserver()) {\r\n        logger.warn('Performance observer for long tasks not supported by browser!');\r\n\r\n        return;\r\n    }\r\n\r\n    this.performanceObserverStats = new PerformanceObserverStats(\r\n        this.eventEmitter,\r\n        Statistics.longTasksStatsInterval);\r\n\r\n    conference.on(\r\n        JitsiConferenceEvents.CONFERENCE_JOINED,\r\n        () => this.performanceObserverStats.startObserver());\r\n    conference.on(\r\n        JitsiConferenceEvents.CONFERENCE_LEFT,\r\n        () => this.performanceObserverStats.stopObserver());\r\n};\r\n\r\n/**\r\n * Obtains the current value of the LongTasks event statistics.\r\n *\r\n * @returns {Object|null} stats object if the observer has been\r\n * created, null otherwise.\r\n */\r\nStatistics.prototype.getLongTasksStats = function() {\r\n    return this.performanceObserverStats\r\n        ? this.performanceObserverStats.getLongTasksStats()\r\n        : null;\r\n};\r\n\r\n/**\r\n * Removes the given listener for the LONG_TASKS_STATS event.\r\n *\r\n * @param {Function} listener the listener we want to remove.\r\n * @returns {void}\r\n */\r\nStatistics.prototype.removeLongTasksStatsListener = function(listener) {\r\n    this.eventEmitter.removeListener(StatisticsEvents.LONG_TASKS_STATS, listener);\r\n};\r\n\r\n/**\r\n * Updates the list of speakers for which the audio levels are to be calculated. This is needed for the jvb pc only.\r\n *\r\n * @param {Array<string>} speakerList The list of remote endpoint ids.\r\n * @returns {void}\r\n */\r\nStatistics.prototype.setSpeakerList = function(speakerList) {\r\n    for (const rtpStats of Array.from(this.rtpStatsMap.values())) {\r\n        if (!rtpStats.peerconnection.isP2P) {\r\n            rtpStats.setSpeakerList(speakerList);\r\n        }\r\n    }\r\n};\r\n\r\nStatistics.prototype.dispose = function() {\r\n    try {\r\n        // NOTE Before reading this please see the comment in stopCallStats...\r\n        //\r\n        // Here we prevent from emitting the event twice in case it will be\r\n        // triggered from stopCallStats.\r\n        // If the event is triggered from here it means that the logs will not\r\n        // be submitted anyway (because there is no CallStats instance), but\r\n        // we're doing that for the sake of some kind of consistency.\r\n        if (!this.callsStatsInstances.size) {\r\n            this.eventEmitter.emit(StatisticsEvents.BEFORE_DISPOSED);\r\n        }\r\n        for (const callStats of this.callsStatsInstances.values()) {\r\n            this.stopCallStats(callStats.tpc);\r\n        }\r\n        for (const tpcId of this.rtpStatsMap.keys()) {\r\n            this._stopRemoteStats(tpcId);\r\n        }\r\n        if (this.eventEmitter) {\r\n            this.eventEmitter.removeAllListeners();\r\n        }\r\n    } finally {\r\n        Statistics.instances.delete(this);\r\n    }\r\n};\r\n\r\nStatistics.stopLocalStats = function(track) {\r\n    if (!Statistics.audioLevelsEnabled) {\r\n        return;\r\n    }\r\n\r\n    const stream = track.getOriginalStream();\r\n\r\n    for (let i = 0; i < Statistics.localStats.length; i++) {\r\n        if (Statistics.localStats[i].stream === stream) {\r\n            const localStats = Statistics.localStats.splice(i, 1);\r\n\r\n            localStats[0].stop();\r\n            break;\r\n        }\r\n    }\r\n};\r\n\r\n/**\r\n * Stops remote RTP stats for given peerconnection ID.\r\n * @param {string} tpcId {@link TraceablePeerConnection.id}\r\n * @private\r\n */\r\nStatistics.prototype._stopRemoteStats = function(tpcId) {\r\n    const rtpStats = this.rtpStatsMap.get(tpcId);\r\n\r\n    if (rtpStats) {\r\n        rtpStats.stop();\r\n        this.rtpStatsMap.delete(tpcId);\r\n    }\r\n};\r\n\r\n/**\r\n * Stops collecting RTP stats for given peerconnection\r\n * @param {TraceablePeerConnection} tpc\r\n */\r\nStatistics.prototype.stopRemoteStats = function(tpc) {\r\n    this._stopRemoteStats(tpc.id);\r\n};\r\n\r\n// CALSTATS METHODS\r\n\r\n/**\r\n * Initializes the callstats.io API.\r\n * @param {TraceablePeerConnection} tpc the {@link TraceablePeerConnection}\r\n * instance for which CalStats will be started.\r\n * @param {string} remoteUserID\r\n */\r\nStatistics.prototype.startCallStats = function(tpc, remoteUserID) {\r\n    if (!this.callStatsIntegrationEnabled) {\r\n        return;\r\n    } else if (this.callsStatsInstances.has(tpc.id)) {\r\n        logger.error('CallStats instance for ${tpc} exists already');\r\n\r\n        return;\r\n    }\r\n    let confID = this.options.confID;\r\n\r\n    // confID - domain/tenant/roomName\r\n    // roomName - meeting name or breakout room ID\r\n    // For breakout rooms we change the conference ID used for callstats to use\r\n    // the room ID instead of the meeting name\r\n    if (!confID.endsWith(this.options.roomName)) {\r\n        confID = `${this.options.confID.slice(0, this.options.confID.lastIndexOf('/'))}/${this.options.roomName}`;\r\n    }\r\n\r\n    logger.info(`Starting CallStats for ${tpc}...`);\r\n    const newInstance\r\n        = new CallStats(\r\n            tpc,\r\n            {\r\n                confID,\r\n                remoteUserID\r\n            });\r\n\r\n    this.callsStatsInstances.set(tpc.id, newInstance);\r\n};\r\n\r\n/**\r\n * Obtains the list of *all* {@link CallStats} instances collected from every\r\n * valid {@link Statistics} instance.\r\n * @return {Set<CallStats>}\r\n * @private\r\n */\r\nStatistics._getAllCallStatsInstances = function() {\r\n    const csInstances = new Set();\r\n\r\n    for (const statistics of Statistics.instances) {\r\n        for (const cs of statistics.callsStatsInstances.values()) {\r\n            csInstances.add(cs);\r\n        }\r\n    }\r\n\r\n    return csInstances;\r\n};\r\n\r\n/**\r\n * Removes the callstats.io instances.\r\n */\r\nStatistics.prototype.stopCallStats = function(tpc) {\r\n    const callStatsInstance = this.callsStatsInstances.get(tpc.id);\r\n\r\n    if (callStatsInstance) {\r\n        // FIXME the original purpose of adding BEFORE_DISPOSED event was to be\r\n        // able to submit the last log batch from jitsi-meet to CallStats. After\r\n        // recent changes we dispose the CallStats earlier\r\n        // (before Statistics.dispose), so we need to emit this event here to\r\n        // give this last chance for final log batch submission.\r\n        //\r\n        // Eventually there should be a separate module called \"log storage\"\r\n        // which should emit proper events when it's underlying\r\n        // CallStats instance is going away.\r\n        if (this.callsStatsInstances.size === 1) {\r\n            this.eventEmitter.emit(StatisticsEvents.BEFORE_DISPOSED);\r\n        }\r\n        this.callsStatsInstances.delete(tpc.id);\r\n\r\n        // The fabric needs to be terminated when being stopped\r\n        callStatsInstance.sendTerminateEvent();\r\n    }\r\n};\r\n\r\n/**\r\n * Returns true if the callstats integration is enabled, otherwise returns\r\n * false.\r\n *\r\n * @returns true if the callstats integration is enabled, otherwise returns\r\n * false.\r\n */\r\nStatistics.prototype.isCallstatsEnabled = function() {\r\n    return this.callStatsIntegrationEnabled;\r\n};\r\n\r\n/**\r\n * Logs either resume or hold event for the given peer connection.\r\n * @param {TraceablePeerConnection} tpc the connection for which event will be\r\n * reported\r\n * @param {boolean} isResume true for resume or false for hold\r\n */\r\nStatistics.prototype.sendConnectionResumeOrHoldEvent = function(tpc, isResume) {\r\n    const instance = this.callsStatsInstances.get(tpc.id);\r\n\r\n    if (instance) {\r\n        instance.sendResumeOrHoldEvent(isResume);\r\n    }\r\n};\r\n\r\n/**\r\n * Notifies CallStats and analytics (if present) for ice connection failed\r\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\r\n */\r\nStatistics.prototype.sendIceConnectionFailedEvent = function(tpc) {\r\n    const instance = this.callsStatsInstances.get(tpc.id);\r\n\r\n    if (instance) {\r\n        instance.sendIceConnectionFailedEvent();\r\n    }\r\n};\r\n\r\n/**\r\n * Notifies CallStats for mute events\r\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\r\n * @param {boolean} muted true for muted and false for not muted\r\n * @param {String} type \"audio\"/\"video\"\r\n */\r\nStatistics.prototype.sendMuteEvent = function(tpc, muted, type) {\r\n    const instance = tpc && this.callsStatsInstances.get(tpc.id);\r\n\r\n    CallStats.sendMuteEvent(muted, type, instance);\r\n};\r\n\r\n/**\r\n * Notifies CallStats for screen sharing events\r\n * @param start {boolean} true for starting screen sharing and\r\n * false for not stopping\r\n * @param {string|null} ssrc - optional ssrc value, used only when\r\n * starting screen sharing.\r\n */\r\nStatistics.prototype.sendScreenSharingEvent\r\n    = function(start, ssrc) {\r\n        for (const cs of this.callsStatsInstances.values()) {\r\n            cs.sendScreenSharingEvent(start, ssrc);\r\n        }\r\n    };\r\n\r\n/**\r\n * Notifies the statistics module that we are now the dominant speaker of the\r\n * conference.\r\n * @param {String} roomJid - The room jid where the speaker event occurred.\r\n * @param {boolean} silence - Whether the dominant speaker is silent or not.\r\n */\r\nStatistics.prototype.sendDominantSpeakerEvent = function(roomJid, silence) {\r\n    for (const cs of this.callsStatsInstances.values()) {\r\n        cs.sendDominantSpeakerEvent();\r\n    }\r\n\r\n    // xmpp send dominant speaker event\r\n    this.xmpp.sendDominantSpeakerEvent(roomJid, silence);\r\n};\r\n\r\n/**\r\n * Notifies about active device.\r\n * @param {{deviceList: {String:String}}} devicesData - list of devices with\r\n *      their data\r\n */\r\nStatistics.sendActiveDeviceListEvent = function(devicesData) {\r\n    const globalSet = Statistics._getAllCallStatsInstances();\r\n\r\n    if (globalSet.size) {\r\n        for (const cs of globalSet) {\r\n            CallStats.sendActiveDeviceListEvent(devicesData, cs);\r\n        }\r\n    } else {\r\n        CallStats.sendActiveDeviceListEvent(devicesData, null);\r\n    }\r\n};\r\n\r\n/* eslint-disable max-params */\r\n\r\n/**\r\n * Lets the underlying statistics module know where is given SSRC rendered by\r\n * providing renderer tag ID.\r\n * @param {TraceablePeerConnection} tpc the connection to which the stream\r\n * belongs to\r\n * @param {number} ssrc the SSRC of the stream\r\n * @param {boolean} isLocal\r\n * @param {string} userId\r\n * @param {string} usageLabel  meaningful usage label of this stream like\r\n *        'microphone', 'camera' or 'screen'.\r\n * @param {string} containerId the id of media 'audio' or 'video' tag which\r\n *        renders the stream.\r\n */\r\nStatistics.prototype.associateStreamWithVideoTag = function(\r\n        tpc,\r\n        ssrc,\r\n        isLocal,\r\n        userId,\r\n        usageLabel,\r\n        containerId) {\r\n    const instance = this.callsStatsInstances.get(tpc.id);\r\n\r\n    if (instance) {\r\n        instance.associateStreamWithVideoTag(\r\n            ssrc,\r\n            isLocal,\r\n            userId,\r\n            usageLabel,\r\n            containerId);\r\n    }\r\n};\r\n\r\n/* eslint-enable max-params */\r\n\r\n/**\r\n * Notifies CallStats that getUserMedia failed.\r\n *\r\n * @param {Error} e error to send\r\n */\r\nStatistics.sendGetUserMediaFailed = function(e) {\r\n    const error\r\n        = e instanceof JitsiTrackError\r\n            ? formatJitsiTrackErrorForCallStats(e) : e;\r\n    const globalSet = Statistics._getAllCallStatsInstances();\r\n\r\n    if (globalSet.size) {\r\n        for (const cs of globalSet) {\r\n            CallStats.sendGetUserMediaFailed(error, cs);\r\n        }\r\n    } else {\r\n        CallStats.sendGetUserMediaFailed(error, null);\r\n    }\r\n};\r\n\r\n/**\r\n * Notifies CallStats that peer connection failed to create offer.\r\n *\r\n * @param {Error} e error to send\r\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\r\n */\r\nStatistics.prototype.sendCreateOfferFailed = function(e, tpc) {\r\n    const instance = this.callsStatsInstances.get(tpc.id);\r\n\r\n    if (instance) {\r\n        instance.sendCreateOfferFailed(e);\r\n    }\r\n};\r\n\r\n/**\r\n * Notifies CallStats that peer connection failed to create answer.\r\n *\r\n * @param {Error} e error to send\r\n * @param {TraceablePeerConnection} tpc connection on which failure occured.\r\n */\r\nStatistics.prototype.sendCreateAnswerFailed = function(e, tpc) {\r\n    const instance = this.callsStatsInstances.get(tpc.id);\r\n\r\n    if (instance) {\r\n        instance.sendCreateAnswerFailed(e);\r\n    }\r\n};\r\n\r\n/**\r\n * Notifies CallStats that peer connection failed to set local description.\r\n *\r\n * @param {Error} e error to send\r\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\r\n */\r\nStatistics.prototype.sendSetLocalDescFailed = function(e, tpc) {\r\n    const instance = this.callsStatsInstances.get(tpc.id);\r\n\r\n    if (instance) {\r\n        instance.sendSetLocalDescFailed(e);\r\n    }\r\n};\r\n\r\n/**\r\n * Notifies CallStats that peer connection failed to set remote description.\r\n *\r\n * @param {Error} e error to send\r\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\r\n */\r\nStatistics.prototype.sendSetRemoteDescFailed = function(e, tpc) {\r\n    const instance = this.callsStatsInstances.get(tpc.id);\r\n\r\n    if (instance) {\r\n        instance.sendSetRemoteDescFailed(e);\r\n    }\r\n};\r\n\r\n/**\r\n * Notifies CallStats that peer connection failed to add ICE candidate.\r\n *\r\n * @param {Error} e error to send\r\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\r\n */\r\nStatistics.prototype.sendAddIceCandidateFailed = function(e, tpc) {\r\n    const instance = this.callsStatsInstances.get(tpc.id);\r\n\r\n    if (instance) {\r\n        instance.sendAddIceCandidateFailed(e);\r\n    }\r\n};\r\n\r\n/**\r\n * Adds to CallStats an application log.\r\n *\r\n * @param {String} m a log message to send or an {Error} object to be reported\r\n */\r\nStatistics.sendLog = function(m) {\r\n    const globalSubSet = new Set();\r\n\r\n    // FIXME we don't want to duplicate logs over P2P instance, but\r\n    // here we should go over instances and call this method for each\r\n    // unique conference ID rather than selecting the first one.\r\n    // We don't have such use case though, so leaving as is for now.\r\n    for (const stats of Statistics.instances) {\r\n        if (stats.callStatsApplicationLogsDisabled) {\r\n            return;\r\n        }\r\n\r\n        if (stats.callsStatsInstances.size) {\r\n            globalSubSet.add(stats.callsStatsInstances.values().next().value);\r\n        }\r\n    }\r\n\r\n    if (globalSubSet.size) {\r\n        for (const csPerStats of globalSubSet) {\r\n            CallStats.sendApplicationLog(m, csPerStats);\r\n        }\r\n    } else {\r\n        CallStats.sendApplicationLog(m, null);\r\n    }\r\n};\r\n\r\n/**\r\n * Sends the given feedback through CallStats.\r\n *\r\n * @param overall an integer between 1 and 5 indicating the user's rating.\r\n * @param comment the comment from the user.\r\n * @returns {Promise} Resolves when callstats feedback has been submitted\r\n * successfully.\r\n */\r\nStatistics.prototype.sendFeedback = function(overall, comment) {\r\n    // Statistics.analytics.sendEvent is currently fire and forget, without\r\n    // confirmation of successful send.\r\n    Statistics.analytics.sendEvent(\r\n        FEEDBACK,\r\n        {\r\n            rating: overall,\r\n            comment\r\n        });\r\n\r\n    return CallStats.sendFeedback(this.options.confID, overall, comment);\r\n};\r\n\r\nStatistics.LOCAL_JID = require('../../service/statistics/constants').LOCAL_JID;\r\n\r\n/**\r\n * Reports global error to CallStats.\r\n *\r\n * @param {Error} error\r\n */\r\nStatistics.reportGlobalError = function(error) {\r\n    if (error instanceof JitsiTrackError && error.gum) {\r\n        Statistics.sendGetUserMediaFailed(error);\r\n    } else {\r\n        Statistics.sendLog(error);\r\n    }\r\n};\r\n\r\n/**\r\n * Sends event to analytics and logs a message to the logger/console. Console\r\n * messages might also be logged to callstats automatically.\r\n *\r\n * @param {string | Object} event the event name, or an object which\r\n * represents the entire event.\r\n * @param {Object} properties properties to attach to the event (if an event\r\n * name as opposed to an event object is provided).\r\n */\r\nStatistics.sendAnalyticsAndLog = function(event, properties = {}) {\r\n    if (!event) {\r\n        logger.warn('No event or event name given.');\r\n\r\n        return;\r\n    }\r\n\r\n    let eventToLog;\r\n\r\n    // Also support an API with a single object as an event.\r\n    if (typeof event === 'object') {\r\n        eventToLog = event;\r\n    } else {\r\n        eventToLog = {\r\n            name: event,\r\n            properties\r\n        };\r\n    }\r\n\r\n    logger.log(JSON.stringify(eventToLog));\r\n\r\n    // We do this last, because it may modify the object which is passed.\r\n    this.analytics.sendEvent(event, properties);\r\n};\r\n\r\n/**\r\n * Sends event to analytics.\r\n *\r\n * @param {string | Object} eventName the event name, or an object which\r\n * represents the entire event.\r\n * @param {Object} properties properties to attach to the event\r\n */\r\nStatistics.sendAnalytics = function(eventName, properties = {}) {\r\n    this.analytics.sendEvent(eventName, properties);\r\n};\r\n","import { getLogger } from '@jitsi/logger';\r\nimport { Strophe } from 'strophe.js';\r\n\r\nimport * as JitsiConferenceErrors from './JitsiConferenceErrors';\r\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\r\nimport * as JitsiTrackEvents from './JitsiTrackEvents';\r\nimport { SPEAKERS_AUDIO_LEVELS } from './modules/statistics/constants';\r\nimport Statistics from './modules/statistics/statistics';\r\nimport EventEmitterForwarder from './modules/util/EventEmitterForwarder';\r\nimport { MediaType } from './service/RTC/MediaType';\r\nimport RTCEvents from './service/RTC/RTCEvents';\r\nimport { VideoType } from './service/RTC/VideoType';\r\nimport AuthenticationEvents\r\n    from './service/authentication/AuthenticationEvents';\r\nimport {\r\n    ACTION_JINGLE_SA_TIMEOUT,\r\n    createBridgeDownEvent,\r\n    createConnectionStageReachedEvent,\r\n    createFocusLeftEvent,\r\n    createJingleEvent,\r\n    createRemotelyMutedEvent\r\n} from './service/statistics/AnalyticsEvents';\r\nimport { XMPPEvents } from './service/xmpp/XMPPEvents';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Setups all event listeners related to conference\r\n * @param conference {JitsiConference} the conference\r\n */\r\nexport default function JitsiConferenceEventManager(conference) {\r\n    this.conference = conference;\r\n    this.xmppListeners = {};\r\n\r\n    // Listeners related to the conference only\r\n    conference.on(JitsiConferenceEvents.TRACK_MUTE_CHANGED,\r\n        track => {\r\n            if (!track.isLocal() || !conference.statistics) {\r\n                return;\r\n            }\r\n            const session\r\n                = track.isP2P\r\n                    ? conference.p2pJingleSession : conference.jvbJingleSession;\r\n\r\n            // TPC will be null, before the conference starts, but the event\r\n            // still should be queued\r\n            const tpc = (session && session.peerconnection) || null;\r\n\r\n            conference.statistics.sendMuteEvent(\r\n                tpc,\r\n                track.isMuted(),\r\n                track.getType());\r\n        });\r\n}\r\n\r\n/**\r\n * Setups event listeners related to conference.chatRoom\r\n */\r\nJitsiConferenceEventManager.prototype.setupChatRoomListeners = function() {\r\n    const conference = this.conference;\r\n    const chatRoom = conference.room;\r\n\r\n    this.chatRoomForwarder = new EventEmitterForwarder(chatRoom,\r\n        this.conference.eventEmitter);\r\n\r\n    chatRoom.addListener(XMPPEvents.ICE_RESTARTING, jingleSession => {\r\n        if (!jingleSession.isP2P) {\r\n            // If using DataChannel as bridge channel, it must be closed\r\n            // before ICE restart, otherwise Chrome will not trigger \"opened\"\r\n            // event for the channel established with the new bridge.\r\n            // TODO: This may be bypassed when using a WebSocket as bridge\r\n            // channel.\r\n            conference.rtc.closeBridgeChannel();\r\n        }\r\n\r\n        // else: there are no DataChannels in P2P session (at least for now)\r\n    });\r\n\r\n    chatRoom.addListener(XMPPEvents.PARTICIPANT_FEATURES_CHANGED, (from, features) => {\r\n        const participant = conference.getParticipantById(Strophe.getResourceFromJid(from));\r\n\r\n        if (participant) {\r\n            participant.setFeatures(features);\r\n            conference.eventEmitter.emit(JitsiConferenceEvents.PARTCIPANT_FEATURES_CHANGED, participant);\r\n        }\r\n    });\r\n\r\n    chatRoom.addListener(\r\n        XMPPEvents.ICE_RESTART_SUCCESS,\r\n        (jingleSession, offerIq) => {\r\n            // The JVB data chanel needs to be reopened in case the conference\r\n            // has been moved to a new bridge.\r\n            !jingleSession.isP2P\r\n                && conference._setBridgeChannel(\r\n                    offerIq, jingleSession.peerconnection);\r\n        });\r\n\r\n\r\n    chatRoom.addListener(XMPPEvents.AUDIO_MUTED_BY_FOCUS,\r\n        actor => {\r\n            // TODO: Add a way to differentiate between commands which caused\r\n            // us to mute and those that did not change our state (i.e. we were\r\n            // already muted).\r\n            Statistics.sendAnalytics(createRemotelyMutedEvent(MediaType.AUDIO));\r\n\r\n            conference.mutedByFocusActor = actor;\r\n\r\n            // set isMutedByFocus when setAudioMute Promise ends\r\n            conference.rtc.setAudioMute(true).then(\r\n                () => {\r\n                    conference.isMutedByFocus = true;\r\n                    conference.mutedByFocusActor = null;\r\n                })\r\n                .catch(\r\n                    error => {\r\n                        conference.mutedByFocusActor = null;\r\n                        logger.warn(\r\n                            'Error while audio muting due to focus request', error);\r\n                    });\r\n        }\r\n    );\r\n\r\n    chatRoom.addListener(XMPPEvents.VIDEO_MUTED_BY_FOCUS,\r\n        actor => {\r\n            // TODO: Add a way to differentiate between commands which caused\r\n            // us to mute and those that did not change our state (i.e. we were\r\n            // already muted).\r\n            Statistics.sendAnalytics(createRemotelyMutedEvent(MediaType.VIDEO));\r\n\r\n            conference.mutedVideoByFocusActor = actor;\r\n\r\n            // set isVideoMutedByFocus when setVideoMute Promise ends\r\n            conference.rtc.setVideoMute(true).then(\r\n                () => {\r\n                    conference.isVideoMutedByFocus = true;\r\n                    conference.mutedVideoByFocusActor = null;\r\n                })\r\n                .catch(\r\n                    error => {\r\n                        conference.mutedVideoByFocusActor = null;\r\n                        logger.warn(\r\n                            'Error while video muting due to focus request', error);\r\n                    });\r\n        }\r\n    );\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.SUBJECT_CHANGED,\r\n        JitsiConferenceEvents.SUBJECT_CHANGED);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_JOINED,\r\n        JitsiConferenceEvents.CONFERENCE_JOINED);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_JOIN_IN_PROGRESS,\r\n        JitsiConferenceEvents.CONFERENCE_JOIN_IN_PROGRESS);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.MEETING_ID_SET,\r\n        JitsiConferenceEvents.CONFERENCE_UNIQUE_ID_SET);\r\n\r\n    // send some analytics events\r\n    chatRoom.addListener(XMPPEvents.MUC_JOINED,\r\n        () => {\r\n            this.conference._onMucJoined();\r\n\r\n            this.conference.isJvbConnectionInterrupted = false;\r\n\r\n            // TODO: Move all of the 'connectionTimes' logic to its own module.\r\n            Object.keys(chatRoom.connectionTimes).forEach(key => {\r\n                const event\r\n                    = createConnectionStageReachedEvent(\r\n                        `conference_${key}`,\r\n                        { value: chatRoom.connectionTimes[key] });\r\n\r\n                Statistics.sendAnalytics(event);\r\n            });\r\n\r\n            // TODO: Move all of the 'connectionTimes' logic to its own module.\r\n            Object.keys(chatRoom.xmpp.connectionTimes).forEach(key => {\r\n                const event\r\n                    = createConnectionStageReachedEvent(\r\n                        `xmpp_${key}`,\r\n                        { value: chatRoom.xmpp.connectionTimes[key] });\r\n\r\n                Statistics.sendAnalytics(event);\r\n            });\r\n        });\r\n\r\n    chatRoom.addListener(XMPPEvents.RENEGOTIATION_FAILED, (e, session) => {\r\n        if (!session.isP2P) {\r\n            conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\r\n                JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\r\n        }\r\n    });\r\n\r\n    chatRoom.addListener(JitsiTrackEvents.TRACK_REMOVED, track => {\r\n        conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);\r\n    });\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_JOIN_ERROR,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.CONNECTION_ERROR);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_CONNECT_ERROR,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.CONNECTION_ERROR);\r\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_CONNECT_NOT_ALLOWED_ERROR,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.NOT_ALLOWED_ERROR);\r\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_CONNECT_MEMBERS_ONLY_ERROR,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.MEMBERS_ONLY_ERROR);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_MAX_USERS_ERROR,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.CONFERENCE_MAX_USERS);\r\n    chatRoom.addListener(XMPPEvents.ROOM_MAX_USERS_ERROR, () => conference.leave());\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.PASSWORD_REQUIRED,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.PASSWORD_REQUIRED);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.AUTHENTICATION_REQUIRED,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.AUTHENTICATION_REQUIRED);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.BRIDGE_DOWN,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE);\r\n    chatRoom.addListener(\r\n        XMPPEvents.BRIDGE_DOWN,\r\n        () => Statistics.sendAnalytics(createBridgeDownEvent()));\r\n\r\n    chatRoom.addListener(XMPPEvents.CONNECTION_RESTARTED,\r\n        jingleSession => {\r\n            conference._onConferenceRestarted(jingleSession);\r\n        });\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.RESERVATION_ERROR,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.RESERVATION_ERROR);\r\n    chatRoom.addListener(XMPPEvents.RESERVATION_ERROR, () => conference.leave());\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.GRACEFUL_SHUTDOWN,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.GRACEFUL_SHUTDOWN);\r\n\r\n    chatRoom.addListener(XMPPEvents.CONNECTION_ICE_FAILED,\r\n        jingleSession => {\r\n            conference._onIceConnectionFailed(jingleSession);\r\n        });\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_DESTROYED,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.CONFERENCE_DESTROYED);\r\n    chatRoom.addListener(XMPPEvents.MUC_DESTROYED, () => conference.leave());\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.CHAT_ERROR_RECEIVED,\r\n        JitsiConferenceEvents.CONFERENCE_ERROR,\r\n        JitsiConferenceErrors.CHAT_ERROR);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.SETTINGS_ERROR_RECEIVED,\r\n        JitsiConferenceEvents.CONFERENCE_ERROR,\r\n        JitsiConferenceErrors.SETTINGS_ERROR);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.FOCUS_DISCONNECTED,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.FOCUS_DISCONNECTED);\r\n\r\n    chatRoom.addListener(XMPPEvents.FOCUS_LEFT,\r\n        () => {\r\n            Statistics.sendAnalytics(createFocusLeftEvent());\r\n            conference.eventEmitter.emit(\r\n                JitsiConferenceEvents.CONFERENCE_FAILED,\r\n                JitsiConferenceErrors.FOCUS_LEFT);\r\n        });\r\n\r\n    chatRoom.addListener(XMPPEvents.SESSION_ACCEPT_TIMEOUT,\r\n        jingleSession => {\r\n            Statistics.sendAnalyticsAndLog(\r\n                createJingleEvent(\r\n                    ACTION_JINGLE_SA_TIMEOUT,\r\n                    { p2p: jingleSession.isP2P }));\r\n        });\r\n\r\n    chatRoom.addListener(XMPPEvents.RECORDER_STATE_CHANGED,\r\n        (session, jid) => {\r\n\r\n            if (jid) {\r\n                const resource = Strophe.getResourceFromJid(jid);\r\n                const participant = conference.getParticipantById(resource) || resource;\r\n\r\n                if (session.getStatus() === 'off') {\r\n                    session.setTerminator(participant);\r\n                } else if (session.getStatus() === 'on') {\r\n                    session.setInitiator(participant);\r\n                }\r\n            }\r\n\r\n            conference.eventEmitter.emit(\r\n                JitsiConferenceEvents.RECORDER_STATE_CHANGED,\r\n                session);\r\n        });\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.TRANSCRIPTION_STATUS_CHANGED,\r\n        JitsiConferenceEvents.TRANSCRIPTION_STATUS_CHANGED);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED,\r\n        JitsiConferenceEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED);\r\n\r\n    this.chatRoomForwarder.forward(\r\n        XMPPEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED,\r\n        JitsiConferenceEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.PHONE_NUMBER_CHANGED,\r\n        JitsiConferenceEvents.PHONE_NUMBER_CHANGED);\r\n\r\n    chatRoom.setParticipantPropertyListener((node, from) => {\r\n        const participant = conference.getParticipantById(from);\r\n\r\n        if (!participant) {\r\n            return;\r\n        }\r\n\r\n        participant.setProperty(\r\n            node.tagName.substring('jitsi_participant_'.length),\r\n            node.value);\r\n    });\r\n\r\n    chatRoom.addListener(XMPPEvents.KICKED,\r\n        conference.onMemberKicked.bind(conference));\r\n    chatRoom.addListener(XMPPEvents.SUSPEND_DETECTED,\r\n        conference.onSuspendDetected.bind(conference));\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOCK_CHANGED,\r\n        JitsiConferenceEvents.LOCK_STATE_CHANGED);\r\n\r\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_MEMBERS_ONLY_CHANGED,\r\n        JitsiConferenceEvents.MEMBERS_ONLY_CHANGED);\r\n\r\n    chatRoom.addListener(XMPPEvents.MUC_MEMBER_JOINED,\r\n        conference.onMemberJoined.bind(conference));\r\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOBBY_MEMBER_JOINED,\r\n        JitsiConferenceEvents.LOBBY_USER_JOINED);\r\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOBBY_MEMBER_UPDATED,\r\n        JitsiConferenceEvents.LOBBY_USER_UPDATED);\r\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOBBY_MEMBER_LEFT,\r\n        JitsiConferenceEvents.LOBBY_USER_LEFT);\r\n    chatRoom.addListener(XMPPEvents.MUC_MEMBER_BOT_TYPE_CHANGED,\r\n        conference._onMemberBotTypeChanged.bind(conference));\r\n    chatRoom.addListener(XMPPEvents.MUC_MEMBER_LEFT,\r\n        conference.onMemberLeft.bind(conference));\r\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LEFT,\r\n        JitsiConferenceEvents.CONFERENCE_LEFT);\r\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_DENIED_ACCESS,\r\n        JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED);\r\n\r\n    chatRoom.addListener(XMPPEvents.DISPLAY_NAME_CHANGED,\r\n        conference.onDisplayNameChanged.bind(conference));\r\n\r\n    chatRoom.addListener(XMPPEvents.LOCAL_ROLE_CHANGED, role => {\r\n        conference.onLocalRoleChanged(role);\r\n\r\n        // log all events for the recorder operated by the moderator\r\n        if (conference.statistics && conference.isModerator()) {\r\n            conference.on(JitsiConferenceEvents.RECORDER_STATE_CHANGED,\r\n                recorderSession => {\r\n                    const logObject = {\r\n                        error: recorderSession.getError(),\r\n                        id: 'recorder_status',\r\n                        status: recorderSession.getStatus()\r\n                    };\r\n\r\n                    Statistics.sendLog(JSON.stringify(logObject));\r\n                });\r\n        }\r\n    });\r\n\r\n    chatRoom.addListener(XMPPEvents.MUC_ROLE_CHANGED,\r\n        conference.onUserRoleChanged.bind(conference));\r\n\r\n    chatRoom.addListener(AuthenticationEvents.IDENTITY_UPDATED,\r\n        (authEnabled, authIdentity) => {\r\n            conference.authEnabled = authEnabled;\r\n            conference.authIdentity = authIdentity;\r\n            conference.eventEmitter.emit(\r\n                JitsiConferenceEvents.AUTH_STATUS_CHANGED, authEnabled,\r\n                authIdentity);\r\n        });\r\n\r\n    chatRoom.addListener(\r\n        XMPPEvents.MESSAGE_RECEIVED,\r\n\r\n        // eslint-disable-next-line max-params\r\n        (jid, txt, myJid, ts) => {\r\n            const id = Strophe.getResourceFromJid(jid);\r\n\r\n            conference.eventEmitter.emit(\r\n                JitsiConferenceEvents.MESSAGE_RECEIVED,\r\n                id, txt, ts);\r\n        });\r\n\r\n    chatRoom.addListener(\r\n        XMPPEvents.PRIVATE_MESSAGE_RECEIVED,\r\n\r\n        // eslint-disable-next-line max-params\r\n        (jid, txt, myJid, ts) => {\r\n            const id = Strophe.getResourceFromJid(jid);\r\n\r\n            conference.eventEmitter.emit(\r\n                JitsiConferenceEvents.PRIVATE_MESSAGE_RECEIVED,\r\n                id, txt, ts);\r\n        });\r\n\r\n    chatRoom.addListener(XMPPEvents.PRESENCE_STATUS,\r\n        (jid, status) => {\r\n            const id = Strophe.getResourceFromJid(jid);\r\n            const participant = conference.getParticipantById(id);\r\n\r\n            if (!participant || participant._status === status) {\r\n                return;\r\n            }\r\n            participant._status = status;\r\n            conference.eventEmitter.emit(\r\n                JitsiConferenceEvents.USER_STATUS_CHANGED, id, status);\r\n        });\r\n\r\n    chatRoom.addListener(XMPPEvents.JSON_MESSAGE_RECEIVED,\r\n        (from, payload) => {\r\n            const id = Strophe.getResourceFromJid(from);\r\n            const participant = conference.getParticipantById(id);\r\n\r\n            if (participant) {\r\n                conference.eventEmitter.emit(\r\n                    JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\r\n                    participant, payload);\r\n            } else {\r\n                conference.eventEmitter.emit(\r\n                    JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED,\r\n                    id, payload);\r\n            }\r\n        });\r\n\r\n    chatRoom.addPresenceListener('startmuted', (data, from) => {\r\n        let isModerator = false;\r\n\r\n        if (conference.myUserId() === from && conference.isModerator()) {\r\n            isModerator = true;\r\n        } else {\r\n            const participant = conference.getParticipantById(from);\r\n\r\n            if (participant && participant.isModerator()) {\r\n                isModerator = true;\r\n            }\r\n        }\r\n\r\n        if (!isModerator) {\r\n            return;\r\n        }\r\n\r\n        const startAudioMuted = data.attributes.audio === 'true';\r\n        const startVideoMuted = data.attributes.video === 'true';\r\n\r\n        let updated = false;\r\n\r\n        if (startAudioMuted !== conference.startMutedPolicy.audio) {\r\n            conference.startMutedPolicy.audio = startAudioMuted;\r\n            updated = true;\r\n        }\r\n\r\n        if (startVideoMuted !== conference.startMutedPolicy.video) {\r\n            conference.startMutedPolicy.video = startVideoMuted;\r\n            updated = true;\r\n        }\r\n\r\n        if (updated) {\r\n            conference.eventEmitter.emit(\r\n                JitsiConferenceEvents.START_MUTED_POLICY_CHANGED,\r\n                conference.startMutedPolicy\r\n            );\r\n        }\r\n    });\r\n\r\n    if (conference.statistics) {\r\n        // FIXME ICE related events should end up in RTCEvents eventually\r\n        chatRoom.addListener(XMPPEvents.CONNECTION_ICE_FAILED,\r\n            session => {\r\n                conference.statistics.sendIceConnectionFailedEvent(\r\n                    session.peerconnection);\r\n            });\r\n\r\n        // FIXME XMPPEvents.ADD_ICE_CANDIDATE_FAILED is never emitted\r\n        chatRoom.addListener(XMPPEvents.ADD_ICE_CANDIDATE_FAILED,\r\n            (e, pc) => {\r\n                conference.statistics.sendAddIceCandidateFailed(e, pc);\r\n            });\r\n    }\r\n\r\n    // Breakout rooms.\r\n    this.chatRoomForwarder.forward(XMPPEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM,\r\n        JitsiConferenceEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM);\r\n    this.chatRoomForwarder.forward(XMPPEvents.BREAKOUT_ROOMS_UPDATED,\r\n        JitsiConferenceEvents.BREAKOUT_ROOMS_UPDATED);\r\n\r\n    // Room metadata.\r\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_METADATA_UPDATED,\r\n        JitsiConferenceEvents.METADATA_UPDATED);\r\n};\r\n\r\n/**\r\n * Setups event listeners related to conference.rtc\r\n */\r\nJitsiConferenceEventManager.prototype.setupRTCListeners = function() {\r\n    const conference = this.conference;\r\n    const rtc = conference.rtc;\r\n\r\n    rtc.addListener(\r\n        RTCEvents.REMOTE_TRACK_ADDED,\r\n        conference.onRemoteTrackAdded.bind(conference));\r\n\r\n    rtc.addListener(\r\n        RTCEvents.REMOTE_TRACK_REMOVED,\r\n        conference.onRemoteTrackRemoved.bind(conference));\r\n\r\n    rtc.addListener(RTCEvents.DOMINANT_SPEAKER_CHANGED,\r\n        (dominant, previous, silence) => {\r\n            if ((conference.lastDominantSpeaker !== dominant || conference.dominantSpeakerIsSilent !== silence)\r\n                    && conference.room) {\r\n                conference.lastDominantSpeaker = dominant;\r\n                conference.dominantSpeakerIsSilent = silence;\r\n                conference.eventEmitter.emit(\r\n                    JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED, dominant, previous, silence);\r\n                if (conference.statistics && conference.myUserId() === dominant) {\r\n                    // We are the new dominant speaker.\r\n                    conference.statistics.sendDominantSpeakerEvent(conference.room.roomjid, silence);\r\n                }\r\n                if (conference.lastDominantSpeaker !== dominant) {\r\n                    if (previous && previous.length) {\r\n                        const speakerList = previous.slice(0);\r\n\r\n                        // Add the dominant speaker to the top of the list (exclude self).\r\n                        if (conference.myUserId !== dominant) {\r\n                            speakerList.splice(0, 0, dominant);\r\n                        }\r\n\r\n                        // Trim the list to the top 5 speakers only.\r\n                        if (speakerList.length > SPEAKERS_AUDIO_LEVELS) {\r\n                            speakerList.splice(SPEAKERS_AUDIO_LEVELS, speakerList.length - SPEAKERS_AUDIO_LEVELS);\r\n                        }\r\n                        conference.statistics && conference.statistics.setSpeakerList(speakerList);\r\n                    }\r\n                }\r\n            }\r\n        });\r\n\r\n    rtc.addListener(RTCEvents.DATA_CHANNEL_OPEN, () => {\r\n        const now = window.performance.now();\r\n        const key = 'data.channel.opened';\r\n\r\n        // TODO: Move all of the 'connectionTimes' logic to its own module.\r\n        logger.log(`(TIME) ${key}:\\t`, now);\r\n        conference.room.connectionTimes[key] = now;\r\n        Statistics.sendAnalytics(\r\n            createConnectionStageReachedEvent(key, { value: now }));\r\n\r\n        conference.eventEmitter.emit(JitsiConferenceEvents.DATA_CHANNEL_OPENED);\r\n    });\r\n\r\n    rtc.addListener(RTCEvents.VIDEO_SSRCS_REMAPPED, msg => {\r\n        const sess = this.conference.getActiveMediaSession();\r\n\r\n        sess.videoSsrcsRemapped(msg);\r\n    });\r\n\r\n    rtc.addListener(RTCEvents.AUDIO_SSRCS_REMAPPED, msg => {\r\n        const sess = this.conference.getActiveMediaSession();\r\n\r\n        sess.audioSsrcsRemapped(msg);\r\n    });\r\n\r\n    rtc.addListener(RTCEvents.ENDPOINT_MESSAGE_RECEIVED,\r\n        (from, payload) => {\r\n            const participant = conference.getParticipantById(from);\r\n\r\n            if (participant) {\r\n                conference.eventEmitter.emit(\r\n                    JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\r\n                    participant, payload);\r\n            } else {\r\n                logger.warn(\r\n                    'Ignored ENDPOINT_MESSAGE_RECEIVED for not existing '\r\n                        + `participant: ${from}`,\r\n                    payload);\r\n            }\r\n        });\r\n\r\n    rtc.addListener(RTCEvents.ENDPOINT_STATS_RECEIVED,\r\n        (from, payload) => {\r\n            const participant = conference.getParticipantById(from);\r\n\r\n            if (participant) {\r\n                conference.eventEmitter.emit(JitsiConferenceEvents.ENDPOINT_STATS_RECEIVED, participant, payload);\r\n            } else {\r\n                logger.warn(`Ignoring ENDPOINT_STATS_RECEIVED for a non-existant participant: ${from}`);\r\n            }\r\n        });\r\n\r\n    rtc.addListener(RTCEvents.LOCAL_UFRAG_CHANGED,\r\n        (tpc, ufrag) => {\r\n            if (!tpc.isP2P) {\r\n                Statistics.sendLog(\r\n                    JSON.stringify({\r\n                        id: 'local_ufrag',\r\n                        value: ufrag\r\n                    }));\r\n            }\r\n        });\r\n    rtc.addListener(RTCEvents.REMOTE_UFRAG_CHANGED,\r\n        (tpc, ufrag) => {\r\n            if (!tpc.isP2P) {\r\n                Statistics.sendLog(\r\n                    JSON.stringify({\r\n                        id: 'remote_ufrag',\r\n                        value: ufrag\r\n                    }));\r\n            }\r\n        });\r\n\r\n    rtc.addListener(RTCEvents.CREATE_ANSWER_FAILED,\r\n        (e, tpc) => {\r\n            conference.statistics.sendCreateAnswerFailed(e, tpc);\r\n            if (!tpc.isP2P) {\r\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\r\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\r\n            }\r\n        });\r\n\r\n    rtc.addListener(RTCEvents.CREATE_OFFER_FAILED,\r\n        (e, tpc) => {\r\n            conference.statistics.sendCreateOfferFailed(e, tpc);\r\n            if (!tpc.isP2P) {\r\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\r\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\r\n            }\r\n        });\r\n\r\n    rtc.addListener(RTCEvents.SET_LOCAL_DESCRIPTION_FAILED,\r\n        (e, tpc) => {\r\n            conference.statistics.sendSetLocalDescFailed(e, tpc);\r\n            if (!tpc.isP2P) {\r\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\r\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\r\n            }\r\n        });\r\n\r\n    rtc.addListener(RTCEvents.SET_REMOTE_DESCRIPTION_FAILED,\r\n        (e, tpc) => {\r\n            conference.statistics.sendSetRemoteDescFailed(e, tpc);\r\n            if (!tpc.isP2P) {\r\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\r\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\r\n            }\r\n        });\r\n\r\n    rtc.addListener(RTCEvents.LOCAL_TRACK_SSRC_UPDATED,\r\n        (track, ssrc) => {\r\n            // when starting screen sharing, the track is created and when\r\n            // we do set local description and we process the ssrc we\r\n            // will be notified for it and we will report it with the event\r\n            // for screen sharing\r\n            if (track.isVideoTrack() && track.videoType === VideoType.DESKTOP) {\r\n                conference.statistics.sendScreenSharingEvent(true, ssrc);\r\n            }\r\n        });\r\n};\r\n\r\n/**\r\n * Removes event listeners related to conference.xmpp\r\n */\r\nJitsiConferenceEventManager.prototype.removeXMPPListeners = function() {\r\n    const conference = this.conference;\r\n\r\n    Object.keys(this.xmppListeners).forEach(eventName => {\r\n        conference.xmpp.removeListener(\r\n            eventName,\r\n            this.xmppListeners[eventName]);\r\n    });\r\n    this.xmppListeners = {};\r\n};\r\n\r\n\r\n/**\r\n * Setups event listeners related to conference.xmpp\r\n */\r\nJitsiConferenceEventManager.prototype.setupXMPPListeners = function() {\r\n    const conference = this.conference;\r\n\r\n    this._addConferenceXMPPListener(\r\n        XMPPEvents.CALL_INCOMING,\r\n        conference.onIncomingCall.bind(conference));\r\n    this._addConferenceXMPPListener(\r\n        XMPPEvents.CALL_ACCEPTED,\r\n        conference.onCallAccepted.bind(conference));\r\n    this._addConferenceXMPPListener(\r\n        XMPPEvents.TRANSPORT_INFO,\r\n        conference.onTransportInfo.bind(conference));\r\n    this._addConferenceXMPPListener(\r\n        XMPPEvents.CALL_ENDED,\r\n        conference.onCallEnded.bind(conference));\r\n\r\n    this._addConferenceXMPPListener(XMPPEvents.START_MUTED_FROM_FOCUS,\r\n        (audioMuted, videoMuted) => {\r\n            if (conference.options.config.ignoreStartMuted) {\r\n                return;\r\n            }\r\n\r\n            conference.startAudioMuted = audioMuted;\r\n            conference.startVideoMuted = videoMuted;\r\n\r\n            if (audioMuted) {\r\n                conference.isMutedByFocus = true;\r\n            }\r\n\r\n            if (videoMuted) {\r\n                conference.isVideoMutedByFocus = true;\r\n            }\r\n\r\n            // mute existing local tracks because this is initial mute from\r\n            // Jicofo\r\n            conference.getLocalTracks().forEach(track => {\r\n                switch (track.getType()) {\r\n                case MediaType.AUDIO:\r\n                    conference.startAudioMuted && track.mute();\r\n                    break;\r\n                case MediaType.VIDEO:\r\n                    conference.startVideoMuted && track.mute();\r\n                    break;\r\n                }\r\n            });\r\n\r\n            conference.eventEmitter.emit(JitsiConferenceEvents.STARTED_MUTED);\r\n        });\r\n\r\n    this._addConferenceXMPPListener(XMPPEvents.CONFERENCE_TIMESTAMP_RECEIVED,\r\n        createdTimestamp => {\r\n            conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_CREATED_TIMESTAMP, createdTimestamp);\r\n        });\r\n\r\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_CHANGED,\r\n        (value, mediaType, actorJid) => {\r\n            const actorParticipant = conference.getParticipants().find(p => p.getJid() === actorJid);\r\n\r\n            conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_CHANGED, {\r\n                enabled: value,\r\n                mediaType,\r\n                actor: actorParticipant\r\n            });\r\n        });\r\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_PARTICIPANT_APPROVED,\r\n        (mediaType, jid) => {\r\n            const participant = conference.getParticipantById(Strophe.getResourceFromJid(jid));\r\n\r\n            if (participant) {\r\n                conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_APPROVED, {\r\n                    participant,\r\n                    mediaType\r\n                });\r\n            }\r\n        });\r\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_PARTICIPANT_REJECTED,\r\n        (mediaType, jid) => {\r\n            const participant = conference.getParticipantById(Strophe.getResourceFromJid(jid));\r\n\r\n            if (participant) {\r\n                conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_REJECTED, {\r\n                    participant,\r\n                    mediaType\r\n                });\r\n            }\r\n        });\r\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_APPROVED,\r\n        value => conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_APPROVED, { mediaType: value }));\r\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_REJECTED,\r\n        value => {\r\n            conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_REJECTED, { mediaType: value });\r\n        });\r\n};\r\n\r\n/**\r\n * Add XMPP listener and save its reference for remove on leave conference.\r\n */\r\nJitsiConferenceEventManager.prototype._addConferenceXMPPListener = function(\r\n        eventName, listener) {\r\n    this.xmppListeners[eventName] = listener;\r\n    this.conference.xmpp.addListener(eventName, listener);\r\n};\r\n\r\n/**\r\n * Setups event listeners related to conference.statistics\r\n */\r\nJitsiConferenceEventManager.prototype.setupStatisticsListeners = function() {\r\n    const conference = this.conference;\r\n\r\n    if (!conference.statistics) {\r\n        return;\r\n    }\r\n\r\n    /* eslint-disable max-params */\r\n    conference.statistics.addAudioLevelListener((tpc, ssrc, level, isLocal) => {\r\n        conference.rtc.setAudioLevel(tpc, ssrc, level, isLocal);\r\n    });\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    // Forward the \"before stats disposed\" event\r\n    conference.statistics.addBeforeDisposedListener(() => {\r\n        conference.eventEmitter.emit(\r\n            JitsiConferenceEvents.BEFORE_STATISTICS_DISPOSED);\r\n    });\r\n\r\n    // if we are in startSilent mode we will not be sending/receiving so nothing to detect\r\n    if (!conference.options.config.startSilent) {\r\n        conference.statistics.addByteSentStatsListener((tpc, stats) => {\r\n            conference.getLocalTracks(MediaType.AUDIO).forEach(track => {\r\n                const ssrc = tpc.getLocalSSRC(track);\r\n\r\n                if (!ssrc || !stats.hasOwnProperty(ssrc)) {\r\n                    return;\r\n                }\r\n\r\n                track.onByteSentStatsReceived(tpc, stats[ssrc]);\r\n            });\r\n        });\r\n    }\r\n};\r\n","\r\nimport { Strophe } from 'strophe.js';\r\n\r\n\r\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\r\nimport { MediaType } from './service/RTC/MediaType';\r\n\r\n/**\r\n * Represents a participant in (i.e. a member of) a conference.\r\n */\r\nexport default class JitsiParticipant {\r\n\r\n    /* eslint-disable max-params */\r\n\r\n    /**\r\n     * Initializes a new JitsiParticipant instance.\r\n     *\r\n     * @constructor\r\n     * @param jid the conference XMPP jid\r\n     * @param conference\r\n     * @param displayName\r\n     * @param {Boolean} hidden - True if the new JitsiParticipant instance is to\r\n     * represent a hidden participant; otherwise, false.\r\n     * @param {string} statsID - optional participant statsID\r\n     * @param {string} status - the initial status if any.\r\n     * @param {object} identity - the xmpp identity\r\n     * @param {boolean?} isReplacing - whether this is a participant replacing another into the meeting.\r\n     * @param {boolean?} isReplaced - whether this is a participant to be kicked and replaced into the meeting.\r\n     */\r\n    constructor(jid, conference, displayName, hidden, statsID, status, identity, isReplacing, isReplaced) {\r\n        this._jid = jid;\r\n        this._id = Strophe.getResourceFromJid(jid);\r\n        this._conference = conference;\r\n        this._displayName = displayName;\r\n        this._supportsDTMF = false;\r\n        this._tracks = [];\r\n        this._role = 'none';\r\n        this._status = status;\r\n        this._hidden = hidden;\r\n        this._statsID = statsID;\r\n        this._properties = {};\r\n        this._identity = identity;\r\n        this._isReplacing = isReplacing;\r\n        this._isReplaced = isReplaced;\r\n        this._features = new Set();\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * @returns {JitsiConference} The conference that this participant belongs\r\n     * to.\r\n     */\r\n    getConference() {\r\n        return this._conference;\r\n    }\r\n\r\n    /**\r\n     * Gets the value of a property of this participant.\r\n     */\r\n    getProperty(name) {\r\n        return this._properties[name];\r\n    }\r\n\r\n    /**\r\n     * Checks whether this <tt>JitsiParticipant</tt> has any video tracks which\r\n     * are muted according to their underlying WebRTC <tt>MediaStreamTrack</tt>\r\n     * muted status.\r\n     * @return {boolean} <tt>true</tt> if this <tt>participant</tt> contains any\r\n     * video <tt>JitsiTrack</tt>s which are muted as defined in\r\n     * {@link JitsiTrack.isWebRTCTrackMuted}.\r\n     */\r\n    hasAnyVideoTrackWebRTCMuted() {\r\n        return (\r\n            this.getTracks().some(\r\n                jitsiTrack =>\r\n                    jitsiTrack.getType() === MediaType.VIDEO\r\n                        && jitsiTrack.isWebRTCTrackMuted()));\r\n    }\r\n\r\n    /**\r\n     * Sets the value of a property of this participant, and fires an event if\r\n     * the value has changed.\r\n     * @name the name of the property.\r\n     * @value the value to set.\r\n     */\r\n    setProperty(name, value) {\r\n        const oldValue = this._properties[name];\r\n\r\n        if (value !== oldValue) {\r\n            this._properties[name] = value;\r\n            this._conference.eventEmitter.emit(\r\n                JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,\r\n                this,\r\n                name,\r\n                oldValue,\r\n                value);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @returns {Array.<JitsiTrack>} The list of media tracks for this\r\n     * participant.\r\n     */\r\n    getTracks() {\r\n        return this._tracks.slice();\r\n    }\r\n\r\n    /**\r\n     * @param {MediaType} mediaType\r\n     * @returns {Array.<JitsiTrack>} an array of media tracks for this\r\n     * participant, for given media type.\r\n     */\r\n    getTracksByMediaType(mediaType) {\r\n        return this.getTracks().filter(track => track.getType() === mediaType);\r\n    }\r\n\r\n    /**\r\n     * @returns {String} The ID of this participant.\r\n     */\r\n    getId() {\r\n        return this._id;\r\n    }\r\n\r\n    /**\r\n     * @returns {String} The JID of this participant.\r\n     */\r\n    getJid() {\r\n        return this._jid;\r\n    }\r\n\r\n    /**\r\n     * @returns {String} The human-readable display name of this participant.\r\n     */\r\n    getDisplayName() {\r\n        return this._displayName;\r\n    }\r\n\r\n    /**\r\n     * @returns {String} The stats ID of this participant.\r\n     */\r\n    getStatsID() {\r\n        return this._statsID;\r\n    }\r\n\r\n    /**\r\n     * @returns {String} The status of the participant.\r\n     */\r\n    getStatus() {\r\n        return this._status;\r\n    }\r\n\r\n    /**\r\n     * @returns {Boolean} Whether this participant is a moderator or not.\r\n     */\r\n    isModerator() {\r\n        return this._role === 'moderator';\r\n    }\r\n\r\n    /**\r\n     * @returns {Boolean} Whether this participant is a hidden participant. Some\r\n     * special system participants may want to join hidden (like for example the\r\n     * recorder).\r\n     */\r\n    isHidden() {\r\n        return this._hidden;\r\n    }\r\n\r\n    /**\r\n     * @returns {Boolean} Whether this participant is a hidden participant. Some\r\n     * special system participants may want to join hidden (like for example the\r\n     * recorder).\r\n     */\r\n    isHiddenFromRecorder() {\r\n        return this._identity?.user?.['hidden-from-recorder'] === 'true';\r\n    }\r\n\r\n    /**\r\n     * @returns {Boolean} Whether this participant replaces another participant\r\n     * from the meeting.\r\n     */\r\n    isReplacing() {\r\n        return this._isReplacing;\r\n    }\r\n\r\n    /**\r\n     * @returns {Boolean} Wheter this participants will be replaced by another\r\n     * participant in the meeting.\r\n     */\r\n    isReplaced() {\r\n        return this._isReplaced;\r\n    }\r\n\r\n    /**\r\n     * @returns {Boolean} Whether this participant has muted their audio.\r\n     */\r\n    isAudioMuted() {\r\n        return this._isMediaTypeMuted(MediaType.AUDIO);\r\n    }\r\n\r\n    /**\r\n     * Determines whether all JitsiTracks which are of a specific MediaType and\r\n     * which belong to this JitsiParticipant are muted.\r\n     *\r\n     * @param {MediaType} mediaType - The MediaType of the JitsiTracks to be\r\n     * checked.\r\n     * @private\r\n     * @returns {Boolean} True if all JitsiTracks which are of the specified\r\n     * mediaType and which belong to this JitsiParticipant are muted; otherwise,\r\n     * false.\r\n     */\r\n    _isMediaTypeMuted(mediaType) {\r\n        return this.getTracks().reduce(\r\n            (muted, track) =>\r\n                muted && (track.getType() !== mediaType || track.isMuted()),\r\n            true);\r\n    }\r\n\r\n    /**\r\n     * @returns {Boolean} Whether this participant has muted their video.\r\n     */\r\n    isVideoMuted() {\r\n        return this._isMediaTypeMuted(MediaType.VIDEO);\r\n    }\r\n\r\n    /**\r\n     * @returns {String} The role of this participant.\r\n     */\r\n    getRole() {\r\n        return this._role;\r\n    }\r\n\r\n    /**\r\n     * Sets a new participant role.\r\n     * @param {String} newRole - the new role.\r\n     */\r\n    setRole(newRole) {\r\n        this._role = newRole;\r\n    }\r\n\r\n    /**\r\n     * Sets whether participant is replacing another based on jwt.\r\n     * @param {String} newIsReplacing - whether is replacing.\r\n     */\r\n    setIsReplacing(newIsReplacing) {\r\n        this._isReplacing = newIsReplacing;\r\n    }\r\n\r\n    /**\r\n     * Sets whether participant is being replaced by another based on jwt.\r\n     * @param {boolean} newIsReplaced - whether is being replaced.\r\n     */\r\n    setIsReplaced(newIsReplaced) {\r\n        this._isReplaced = newIsReplaced;\r\n    }\r\n\r\n    /**\r\n     *\r\n     */\r\n    supportsDTMF() {\r\n        return this._supportsDTMF;\r\n    }\r\n\r\n    /**\r\n     * Returns a set with the features for the participant.\r\n     * @returns {Promise<Set<String>, Error>}\r\n     */\r\n    getFeatures() {\r\n        return Promise.resolve(this._features);\r\n    }\r\n\r\n    /**\r\n     * Checks current set features.\r\n     * @param {String} feature - the feature to check.\r\n     * @return {boolean} <tt>true</tt> if this <tt>participant</tt> contains the\r\n     * <tt>feature</tt>.\r\n     */\r\n    hasFeature(feature) {\r\n        return this._features.has(feature);\r\n    }\r\n\r\n    /**\r\n     * Set new features.\r\n     * @param {Set<String>|undefined} newFeatures - Sets new features.\r\n     */\r\n    setFeatures(newFeatures) {\r\n        this._features = newFeatures || new Set();\r\n    }\r\n\r\n    /**\r\n     * Returns the bot type for the participant.\r\n     *\r\n     * @returns {string|undefined} - The bot type of the participant.\r\n     */\r\n    getBotType() {\r\n        return this._botType;\r\n    }\r\n\r\n    /**\r\n     * Sets the bot type for the participant.\r\n     * @param {String} newBotType - The new bot type to set.\r\n     */\r\n    setBotType(newBotType) {\r\n        this._botType = newBotType;\r\n    }\r\n\r\n    /**\r\n     * Returns the connection jid for the participant.\r\n     *\r\n     * @returns {string|undefined} - The connection jid of the participant.\r\n     */\r\n    getConnectionJid() {\r\n        return this._connectionJid;\r\n    }\r\n\r\n    /**\r\n     * Sets the connection jid for the participant.\r\n     * @param {String} newJid - The connection jid to set.\r\n     */\r\n    setConnectionJid(newJid) {\r\n        this._connectionJid = newJid;\r\n    }\r\n}\r\n","/**\r\n * The events for the connection.\r\n */\r\n\r\nexport enum JitsiConnectionEvents {\r\n    /**\r\n     * Indicates that the connection has been disconnected. The event provides\r\n     * the following parameters to its listeners:\r\n     *\r\n     * @param msg {string} a message associated with the disconnect such as the\r\n     * last (known) error message\r\n     */\r\n    CONNECTION_DISCONNECTED = 'connection.connectionDisconnected',\r\n\r\n    /**\r\n     * Indicates that the connection has been established. The event provides\r\n     * the following parameters to its listeners:\r\n     *\r\n     * @param id {string} the ID of the local endpoint/participant/peer (within\r\n     * the context of the established connection)\r\n     */\r\n    CONNECTION_ESTABLISHED = 'connection.connectionEstablished',\r\n\r\n    /**\r\n     * Indicates that the connection has been failed for some reason. The event\r\n     * provides the following parameters to its listeners:\r\n     *\r\n     * @param errType {JitsiConnectionErrors} the type of error associated with\r\n     * the failure\r\n     * @param errReason {string} the error (message) associated with the failure\r\n     * @param credentials {object} the credentials used to connect (if any)\r\n     * @param errReasonDetails {object} an optional object with details about\r\n     * the error, like shard moving, suspending. Used for analytics purposes.\r\n     */\r\n    CONNECTION_FAILED = 'connection.connectionFailed',\r\n\r\n    /**\r\n     * Indicates that the performed action cannot be executed because the\r\n     * connection is not in the correct state(connected, disconnected, etc.)\r\n     */\r\n    WRONG_STATE = 'connection.wrongState',\r\n\r\n    /**\r\n     * Indicates that the display name is required over this connection and need to be supplied when\r\n     * joining the room.\r\n     * There are cases like lobby room where display name is required.\r\n     */\r\n    DISPLAY_NAME_REQUIRED = 'connection.display_name_required'\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const CONNECTION_DISCONNECTED = JitsiConnectionEvents.CONNECTION_DISCONNECTED;\r\nexport const CONNECTION_ESTABLISHED = JitsiConnectionEvents.CONNECTION_ESTABLISHED;\r\nexport const CONNECTION_FAILED = JitsiConnectionEvents.CONNECTION_FAILED;\r\nexport const WRONG_STATE = JitsiConnectionEvents.WRONG_STATE;\r\nexport const DISPLAY_NAME_REQUIRED = JitsiConnectionEvents.DISPLAY_NAME_REQUIRED;\r\n","/**\r\n * The errors for the connection.\r\n */\r\n\r\nexport enum JitsiConnectionErrors {\r\n    /**\r\n     * Indicates that the connection was dropped with an error which was most likely\r\n     * caused by some networking issues. The dropped term in this context means that\r\n     * the connection was closed unexpectedly (not on user's request).\r\n     *\r\n     * One example is 'item-not-found' error thrown by Prosody when the BOSH session\r\n     * times out after 60 seconds of inactivity. On the other hand 'item-not-found'\r\n     * could also happen when BOSH request is sent to the server with the session-id\r\n     * that is not know to the server. But this should not happen in lib-jitsi-meet\r\n     * case as long as the service is configured correctly (there is no bug).\r\n     */\r\n    CONNECTION_DROPPED_ERROR = 'connection.droppedError',\r\n\r\n    /**\r\n     * Not specified errors.\r\n     */\r\n    OTHER_ERROR = 'connection.otherError',\r\n\r\n    /**\r\n     * Indicates that a password is required in order to join the conference.\r\n     */\r\n    PASSWORD_REQUIRED = 'connection.passwordRequired',\r\n\r\n    /**\r\n     * Indicates that the connection was dropped, because of too many 5xx HTTP\r\n     * errors on BOSH requests.\r\n     */\r\n    SERVER_ERROR = 'connection.serverError'\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const CONNECTION_DROPPED_ERROR = JitsiConnectionErrors.CONNECTION_DROPPED_ERROR;\r\nexport const OTHER_ERROR = JitsiConnectionErrors.OTHER_ERROR;\r\nexport const PASSWORD_REQUIRED = JitsiConnectionErrors.PASSWORD_REQUIRED;\r\nexport const SERVER_ERROR = JitsiConnectionErrors.SERVER_ERROR;\r\n","\r\n/**\r\n * Promise-like object which can be passed around for resolving it later. It\r\n * implements the \"thenable\" interface, so it can be used wherever a Promise\r\n * could be used.\r\n *\r\n * In addition a \"reject on timeout\" functionality is provided.\r\n */\r\nexport default class Deferred {\r\n    /**\r\n     * Instantiates a Deferred object.\r\n     */\r\n    constructor() {\r\n        this.promise = new Promise((resolve, reject) => {\r\n            this.resolve = (...args) => {\r\n                this.clearRejectTimeout();\r\n                resolve(...args);\r\n            };\r\n            this.reject = (...args) => {\r\n                this.clearRejectTimeout();\r\n                reject(...args);\r\n            };\r\n        });\r\n        this.then = this.promise.then.bind(this.promise);\r\n        this.catch = this.promise.catch.bind(this.promise);\r\n    }\r\n\r\n    /**\r\n     * Clears the reject timeout.\r\n     */\r\n    clearRejectTimeout() {\r\n        clearTimeout(this._timeout);\r\n    }\r\n\r\n    /**\r\n     * Rejects the promise after the given timeout.\r\n     */\r\n    setRejectTimeout(ms) {\r\n        this._timeout = setTimeout(() => {\r\n            this.reject(new Error('timeout'));\r\n        }, ms);\r\n    }\r\n}\r\n","import EventEmitter from 'events';\r\n\r\n/**\r\n * The class implements basic event operations - add/remove listener.\r\n * NOTE: The purpose of the class is to be extended in order to add\r\n * this functionality to other classes.\r\n */\r\nexport default class Listenable {\r\n    /**\r\n     * Creates new instance.\r\n     * @param {EventEmitter} eventEmitter\r\n     * @constructor\r\n     */\r\n    constructor(eventEmitter = new EventEmitter()) {\r\n        this.eventEmitter = eventEmitter;\r\n\r\n        // aliases for addListener/removeListener\r\n        this.addEventListener = this.on = this.addListener;\r\n        this.removeEventListener = this.off = this.removeListener;\r\n    }\r\n\r\n    /**\r\n     * Adds new listener.\r\n     * @param {String} eventName the name of the event\r\n     * @param {Function} listener the listener.\r\n     * @returns {Function} - The unsubscribe function.\r\n     */\r\n    addListener(eventName, listener) {\r\n        this.eventEmitter.addListener(eventName, listener);\r\n\r\n        return () => this.removeEventListener(eventName, listener);\r\n    }\r\n\r\n    /**\r\n     * Removes listener.\r\n     * @param {String} eventName the name of the event that triggers the\r\n     * listener\r\n     * @param {Function} listener the listener.\r\n     */\r\n    removeListener(eventName, listener) {\r\n        this.eventEmitter.removeListener(eventName, listener);\r\n    }\r\n}\r\n","/* global RTCRtpScriptTransform */\r\n\r\nimport { getLogger } from '@jitsi/logger';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n// Flag to set on senders / receivers to avoid setting up the encryption transform\r\n// more than once.\r\nconst kJitsiE2EE = Symbol('kJitsiE2EE');\r\n\r\n/**\r\n * Context encapsulating the cryptography bits required for E2EE.\r\n * This uses the WebRTC Insertable Streams API which is explained in\r\n *   https://github.com/alvestrand/webrtc-media-streams/blob/master/explainer.md\r\n * that provides access to the encoded frames and allows them to be transformed.\r\n *\r\n * The encoded frame format is explained below in the _encodeFunction method.\r\n * High level design goals were:\r\n * - do not require changes to existing SFUs and retain (VP8) metadata.\r\n * - allow the SFU to rewrite SSRCs, timestamp, pictureId.\r\n * - allow for the key to be rotated frequently.\r\n */\r\nexport default class E2EEcontext {\r\n    /**\r\n     * Build a new E2EE context instance, which will be used in a given conference.\r\n     * @param {boolean} [options.sharedKey] - whether there is a uniques key shared amoung all participants.\r\n     */\r\n    constructor({ sharedKey } = {}) {\r\n        // Determine the URL for the worker script. Relative URLs are relative to\r\n        // the entry point, not the script that launches the worker.\r\n        let baseUrl = '';\r\n        const ljm = document.querySelector('script[src*=\"lib-jitsi-meet\"]');\r\n\r\n        if (ljm) {\r\n            const idx = ljm.src.lastIndexOf('/');\r\n\r\n            baseUrl = `${ljm.src.substring(0, idx)}/`;\r\n        }\r\n\r\n        let workerUrl = `${baseUrl}lib-jitsi-meet.e2ee-worker.js`;\r\n\r\n        // If there is no baseUrl then we create the worker in a normal way\r\n        // as you cant load scripts inside blobs from relative paths.\r\n        // See: https://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers-loadingscripts\r\n        if (baseUrl && baseUrl !== '/') {\r\n            // Initialize the E2EE worker. In order to avoid CORS issues, start the worker and have it\r\n            // synchronously load the JS.\r\n            const workerBlob\r\n                = new Blob([ `importScripts(\"${workerUrl}\");` ], { type: 'application/javascript' });\r\n\r\n            workerUrl = window.URL.createObjectURL(workerBlob);\r\n        }\r\n\r\n        this._worker = new Worker(workerUrl, { name: 'E2EE Worker' });\r\n\r\n        this._worker.onerror = e => logger.error(e);\r\n\r\n        this._worker.postMessage({\r\n            operation: 'initialize',\r\n            sharedKey\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Cleans up all state associated with the given participant. This is needed when a\r\n     * participant leaves the current conference.\r\n     *\r\n     * @param {string} participantId - The participant that just left.\r\n     */\r\n    cleanup(participantId) {\r\n        this._worker.postMessage({\r\n            operation: 'cleanup',\r\n            participantId\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Cleans up all state associated with all participants in the conference. This is needed when disabling e2ee.\r\n     *\r\n     */\r\n    cleanupAll() {\r\n        this._worker.postMessage({\r\n            operation: 'cleanupAll'\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Handles the given {@code RTCRtpReceiver} by creating a {@code TransformStream} which will inject\r\n     * a frame decoder.\r\n     *\r\n     * @param {RTCRtpReceiver} receiver - The receiver which will get the decoding function injected.\r\n     * @param {string} kind - The kind of track this receiver belongs to.\r\n     * @param {string} participantId - The participant id that this receiver belongs to.\r\n     */\r\n    handleReceiver(receiver, kind, participantId) {\r\n        if (receiver[kJitsiE2EE]) {\r\n            return;\r\n        }\r\n        receiver[kJitsiE2EE] = true;\r\n\r\n        if (window.RTCRtpScriptTransform) {\r\n            const options = {\r\n                operation: 'decode',\r\n                participantId\r\n            };\r\n\r\n            receiver.transform = new RTCRtpScriptTransform(this._worker, options);\r\n        } else {\r\n            const receiverStreams = receiver.createEncodedStreams();\r\n\r\n            this._worker.postMessage({\r\n                operation: 'decode',\r\n                readableStream: receiverStreams.readable,\r\n                writableStream: receiverStreams.writable,\r\n                participantId\r\n            }, [ receiverStreams.readable, receiverStreams.writable ]);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Handles the given {@code RTCRtpSender} by creating a {@code TransformStream} which will inject\r\n     * a frame encoder.\r\n     *\r\n     * @param {RTCRtpSender} sender - The sender which will get the encoding function injected.\r\n     * @param {string} kind - The kind of track this sender belongs to.\r\n     * @param {string} participantId - The participant id that this sender belongs to.\r\n     */\r\n    handleSender(sender, kind, participantId) {\r\n        if (sender[kJitsiE2EE]) {\r\n            return;\r\n        }\r\n        sender[kJitsiE2EE] = true;\r\n\r\n        if (window.RTCRtpScriptTransform) {\r\n            const options = {\r\n                operation: 'encode',\r\n                participantId\r\n            };\r\n\r\n            sender.transform = new RTCRtpScriptTransform(this._worker, options);\r\n        } else {\r\n            const senderStreams = sender.createEncodedStreams();\r\n\r\n            this._worker.postMessage({\r\n                operation: 'encode',\r\n                readableStream: senderStreams.readable,\r\n                writableStream: senderStreams.writable,\r\n                participantId\r\n            }, [ senderStreams.readable, senderStreams.writable ]);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Set the E2EE key for the specified participant.\r\n     *\r\n     * @param {string} participantId - the ID of the participant who's key we are setting.\r\n     * @param {Uint8Array | boolean} key - they key for the given participant.\r\n     * @param {Number} keyIndex - the key index.\r\n     */\r\n    setKey(participantId, key, keyIndex) {\r\n        this._worker.postMessage({\r\n            operation: 'setKey',\r\n            key,\r\n            keyIndex,\r\n            participantId\r\n        });\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\nimport RTCEvents from '../../service/RTC/RTCEvents';\r\nimport browser from '../browser';\r\nimport Deferred from '../util/Deferred';\r\nimport Listenable from '../util/Listenable';\r\n\r\nimport E2EEContext from './E2EEContext';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Abstract class that integrates {@link E2EEContext} with a key management system.\r\n */\r\nexport class KeyHandler extends Listenable {\r\n    /**\r\n     * Build a new KeyHandler instance, which will be used in a given conference.\r\n     * @param {JitsiConference} conference - the current conference.\r\n     * @param {object} options - the options passed to {E2EEContext}, see implemention.\r\n     */\r\n    constructor(conference, options = {}) {\r\n        super();\r\n\r\n        this.conference = conference;\r\n        this.e2eeCtx = new E2EEContext(options);\r\n\r\n        this.enabled = false;\r\n        this._enabling = undefined;\r\n\r\n        // Conference media events in order to attach the encryptor / decryptor.\r\n        // FIXME add events to TraceablePeerConnection which will allow to see when there's new receiver or sender\r\n        // added instead of shenanigans around conference track events and track muted.\r\n        //\r\n\r\n        this.conference.on(\r\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\r\n            this._onMediaSessionStarted.bind(this));\r\n        this.conference.on(\r\n            JitsiConferenceEvents.TRACK_ADDED,\r\n            track => track.isLocal() && this._onLocalTrackAdded(track));\r\n        this.conference.rtc.on(\r\n            RTCEvents.REMOTE_TRACK_ADDED,\r\n            (track, tpc) => this._setupReceiverE2EEForTrack(tpc, track));\r\n        this.conference.on(\r\n            JitsiConferenceEvents.TRACK_MUTE_CHANGED,\r\n            this._trackMuteChanged.bind(this));\r\n    }\r\n\r\n    /**\r\n     * Indicates whether E2EE is currently enabled or not.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isEnabled() {\r\n        return this.enabled;\r\n    }\r\n\r\n    /**\r\n     * Enables / disables End-To-End encryption.\r\n     *\r\n     * @param {boolean} enabled - whether E2EE should be enabled or not.\r\n     * @returns {void}\r\n     */\r\n    async setEnabled(enabled) {\r\n        this._enabling && await this._enabling;\r\n\r\n        if (enabled === this.enabled) {\r\n            return;\r\n        }\r\n\r\n        this._enabling = new Deferred();\r\n\r\n        this.enabled = enabled;\r\n\r\n        if (!enabled) {\r\n            this.e2eeCtx.cleanupAll();\r\n        }\r\n\r\n        this._setEnabled && await this._setEnabled(enabled);\r\n\r\n        this.conference.setLocalParticipantProperty('e2ee.enabled', enabled);\r\n\r\n        this.conference._restartMediaSessions();\r\n\r\n        this._enabling.resolve();\r\n    }\r\n\r\n    /**\r\n     * Sets the key for End-to-End encryption.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    setEncryptionKey() {\r\n        throw new Error('Not implemented by subclass');\r\n    }\r\n\r\n    /**\r\n     * Setup E2EE on the new track that has been added to the conference, apply it on all the open peerconnections.\r\n     * @param {JitsiLocalTrack} track - the new track that's being added to the conference.\r\n     * @private\r\n     */\r\n    _onLocalTrackAdded(track) {\r\n        for (const session of this.conference.getMediaSessions()) {\r\n            this._setupSenderE2EEForTrack(session, track);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Setups E2E encryption for the new session.\r\n     * @param {JingleSessionPC} session - the new media session.\r\n     * @private\r\n     */\r\n    _onMediaSessionStarted(session) {\r\n        const localTracks = this.conference.getLocalTracks();\r\n\r\n        for (const track of localTracks) {\r\n            this._setupSenderE2EEForTrack(session, track);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Setup E2EE for the receiving side.\r\n     *\r\n     * @private\r\n     */\r\n    _setupReceiverE2EEForTrack(tpc, track) {\r\n        if (!this.enabled) {\r\n            return;\r\n        }\r\n\r\n        const receiver = tpc.findReceiverForTrack(track.track);\r\n\r\n        if (receiver) {\r\n            this.e2eeCtx.handleReceiver(receiver, track.getType(), track.getParticipantId());\r\n        } else {\r\n            logger.warn(`Could not handle E2EE for ${track}: receiver not found in: ${tpc}`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Setup E2EE for the sending side.\r\n     *\r\n     * @param {JingleSessionPC} session - the session which sends the media produced by the track.\r\n     * @param {JitsiLocalTrack} track - the local track for which e2e encoder will be configured.\r\n     * @private\r\n     */\r\n    _setupSenderE2EEForTrack(session, track) {\r\n        if (!this.enabled) {\r\n            return;\r\n        }\r\n\r\n        const pc = session.peerconnection;\r\n        const sender = pc && pc.findSenderForTrack(track.track);\r\n\r\n        if (sender) {\r\n            this.e2eeCtx.handleSender(sender, track.getType(), track.getParticipantId());\r\n        } else {\r\n            logger.warn(`Could not handle E2EE for ${track}: sender not found in ${pc}`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Setup E2EE on the sender that is created for the unmuted local video track.\r\n     * @param {JitsiLocalTrack} track - the track for which muted status has changed.\r\n     * @private\r\n     */\r\n    _trackMuteChanged(track) {\r\n        if (browser.doesVideoMuteByStreamRemove() && track.isLocal() && track.isVideoTrack() && !track.isMuted()) {\r\n            for (const session of this.conference.getMediaSessions()) {\r\n                this._setupSenderE2EEForTrack(session, track);\r\n            }\r\n        }\r\n    }\r\n}\r\n","import { KeyHandler } from './KeyHandler';\r\n\r\n/**\r\n * This module integrates {@link E2EEContext} with {external} in order to set the keys for encryption.\r\n */\r\nexport class ExternallyManagedKeyHandler extends KeyHandler {\r\n    /**\r\n     * Build a new ExternallyManagedKeyHandler instance, which will be used in a given conference.\r\n     * @param conference - the current conference.\r\n     */\r\n    constructor(conference) {\r\n        super(conference, { sharedKey: true });\r\n    }\r\n\r\n    /**\r\n     * Sets the key and index for End-to-End encryption.\r\n     *\r\n     * @param {CryptoKey} [keyInfo.encryptionKey] - encryption key.\r\n     * @param {Number} [keyInfo.index] - the index of the encryption key.\r\n     * @returns {void}\r\n     */\r\n    setKey(keyInfo) {\r\n        this.e2eeCtx.setKey(undefined, { encryptionKey: keyInfo.encryptionKey }, keyInfo.index);\r\n    }\r\n}\r\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","/* global Olm */\r\n\r\nimport { getLogger } from '@jitsi/logger';\r\nimport base64js from 'base64-js';\r\nimport isEqual from 'lodash.isequal';\r\nimport { v4 as uuidv4 } from 'uuid';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\nimport Deferred from '../util/Deferred';\r\nimport Listenable from '../util/Listenable';\r\nimport { FEATURE_E2EE, JITSI_MEET_MUC_TYPE } from '../xmpp/xmpp';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\nconst REQ_TIMEOUT = 5 * 1000;\r\nconst OLM_MESSAGE_TYPE = 'olm';\r\nconst OLM_MESSAGE_TYPES = {\r\n    ERROR: 'error',\r\n    KEY_INFO: 'key-info',\r\n    KEY_INFO_ACK: 'key-info-ack',\r\n    SESSION_ACK: 'session-ack',\r\n    SESSION_INIT: 'session-init'\r\n};\r\n\r\nconst kOlmData = Symbol('OlmData');\r\n\r\nconst OlmAdapterEvents = {\r\n    OLM_ID_KEY_READY: 'olm.id_key_ready',\r\n    PARTICIPANT_E2EE_CHANNEL_READY: 'olm.participant_e2ee_channel_ready',\r\n    PARTICIPANT_KEY_UPDATED: 'olm.partitipant_key_updated'\r\n};\r\n\r\n/**\r\n * This class implements an End-to-End Encrypted communication channel between every two peers\r\n * in the conference. This channel uses libolm to achieve E2EE.\r\n *\r\n * The created channel is then used to exchange the secret key that each participant will use\r\n * to encrypt the actual media (see {@link E2EEContext}).\r\n *\r\n * A simple JSON message based protocol is implemented, which follows a request - response model:\r\n * - session-init: Initiates an olm session establishment procedure. This message will be sent\r\n *                 by the participant who just joined, to everyone else.\r\n * - session-ack: Completes the olm session etablishment. This messsage may contain ancilliary\r\n *                encrypted data, more specifically the sender's current key.\r\n * - key-info: Includes the sender's most up to date key information.\r\n * - key-info-ack: Acknowledges the reception of a key-info request. In addition, it may contain\r\n *                 the sender's key information, if available.\r\n * - error: Indicates a request processing error has occurred.\r\n *\r\n * These requessts and responses are transport independent. Currently they are sent using XMPP\r\n * MUC private messages.\r\n */\r\nexport class OlmAdapter extends Listenable {\r\n    /**\r\n     * Creates an adapter instance for the given conference.\r\n     */\r\n    constructor(conference) {\r\n        super();\r\n\r\n        this._conf = conference;\r\n        this._init = new Deferred();\r\n        this._key = undefined;\r\n        this._keyIndex = -1;\r\n        this._reqs = new Map();\r\n        this._sessionInitialization = undefined;\r\n\r\n        if (OlmAdapter.isSupported()) {\r\n            this._bootstrapOlm();\r\n\r\n            this._conf.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, this._onEndpointMessageReceived.bind(this));\r\n            this._conf.on(JitsiConferenceEvents.CONFERENCE_LEFT, this._onConferenceLeft.bind(this));\r\n            this._conf.on(JitsiConferenceEvents.USER_LEFT, this._onParticipantLeft.bind(this));\r\n            this._conf.on(JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,\r\n                this._onParticipantPropertyChanged.bind(this));\r\n        } else {\r\n            this._init.reject(new Error('Olm not supported'));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Starts new olm sessions with every other participant that has the participantId \"smaller\" the localParticipantId.\r\n     */\r\n    async initSessions() {\r\n        if (this._sessionInitialization) {\r\n            throw new Error('OlmAdapter initSessions called multiple times');\r\n        } else {\r\n            this._sessionInitialization = new Deferred();\r\n\r\n            await this._init;\r\n\r\n            const promises = [];\r\n            const localParticipantId = this._conf.myUserId();\r\n\r\n            for (const participant of this._conf.getParticipants()) {\r\n                if (participant.hasFeature(FEATURE_E2EE) && localParticipantId < participant.getId()) {\r\n                    promises.push(this._sendSessionInit(participant));\r\n                }\r\n            }\r\n\r\n            await Promise.allSettled(promises);\r\n\r\n            // TODO: retry failed ones.\r\n\r\n            this._sessionInitialization.resolve();\r\n            this._sessionInitialization = undefined;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Indicates if olm is supported on the current platform.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    static isSupported() {\r\n        return typeof window.Olm !== 'undefined';\r\n    }\r\n\r\n    /**\r\n     * Updates the current participant key and distributes it to all participants in the conference\r\n     * by sending a key-info message.\r\n     *\r\n     * @param {Uint8Array|boolean} key - The new key.\r\n     * @retrns {Promise<Number>}\r\n     */\r\n    async updateKey(key) {\r\n        // Store it locally for new sessions.\r\n        this._key = key;\r\n        this._keyIndex++;\r\n\r\n        // Broadcast it.\r\n        const promises = [];\r\n\r\n        for (const participant of this._conf.getParticipants()) {\r\n            const pId = participant.getId();\r\n            const olmData = this._getParticipantOlmData(participant);\r\n\r\n            // TODO: skip those who don't support E2EE.\r\n            if (!olmData.session) {\r\n                logger.warn(`Tried to send key to participant ${pId} but we have no session`);\r\n\r\n                // eslint-disable-next-line no-continue\r\n                continue;\r\n            }\r\n\r\n            const uuid = uuidv4();\r\n            const data = {\r\n                [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\r\n                olm: {\r\n                    type: OLM_MESSAGE_TYPES.KEY_INFO,\r\n                    data: {\r\n                        ciphertext: this._encryptKeyInfo(olmData.session),\r\n                        uuid\r\n                    }\r\n                }\r\n            };\r\n            const d = new Deferred();\r\n\r\n            d.setRejectTimeout(REQ_TIMEOUT);\r\n            d.catch(() => {\r\n                this._reqs.delete(uuid);\r\n            });\r\n            this._reqs.set(uuid, d);\r\n            promises.push(d);\r\n\r\n            this._sendMessage(data, pId);\r\n        }\r\n\r\n        await Promise.allSettled(promises);\r\n\r\n        // TODO: retry failed ones?\r\n\r\n        return this._keyIndex;\r\n    }\r\n\r\n    /**\r\n     * Updates the current participant key.\r\n     * @param {Uint8Array|boolean} key - The new key.\r\n     * @returns {number}\r\n    */\r\n    updateCurrentKey(key) {\r\n        this._key = key;\r\n\r\n        return this._keyIndex;\r\n    }\r\n\r\n    /**\r\n     * Frees the olmData session for the given participant.\r\n     *\r\n     */\r\n    clearParticipantSession(participant) {\r\n        const olmData = this._getParticipantOlmData(participant);\r\n\r\n        if (olmData.session) {\r\n            olmData.session.free();\r\n            olmData.session = undefined;\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * Frees the olmData sessions for all participants.\r\n     *\r\n     */\r\n    clearAllParticipantsSessions() {\r\n        for (const participant of this._conf.getParticipants()) {\r\n            this.clearParticipantSession(participant);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Internal helper to bootstrap the olm library.\r\n     *\r\n     * @returns {Promise<void>}\r\n     * @private\r\n     */\r\n    async _bootstrapOlm() {\r\n        logger.debug('Initializing Olm...');\r\n\r\n        try {\r\n            await Olm.init();\r\n\r\n            this._olmAccount = new Olm.Account();\r\n            this._olmAccount.create();\r\n\r\n            const idKeys = JSON.parse(this._olmAccount.identity_keys());\r\n\r\n            this._idKey = idKeys.curve25519;\r\n\r\n            logger.debug(`Olm ${Olm.get_library_version().join('.')} initialized`);\r\n            this._init.resolve();\r\n            this._onIdKeyReady(this._idKey);\r\n        } catch (e) {\r\n            logger.error('Failed to initialize Olm', e);\r\n            this._init.reject(e);\r\n        }\r\n\r\n    }\r\n\r\n    /**\r\n     * Publishes our own Olmn id key in presence.\r\n     * @private\r\n     */\r\n    _onIdKeyReady(idKey) {\r\n        logger.debug(`Olm id key ready: ${idKey}`);\r\n\r\n        // Publish it in presence.\r\n        this._conf.setLocalParticipantProperty('e2ee.idKey', idKey);\r\n    }\r\n\r\n    /**\r\n     * Event posted when the E2EE signalling channel has been established with the given participant.\r\n     * @private\r\n     */\r\n    _onParticipantE2EEChannelReady(id) {\r\n        logger.debug(`E2EE channel with participant ${id} is ready`);\r\n    }\r\n\r\n    /**\r\n     * Internal helper for encrypting the current key information for a given participant.\r\n     *\r\n     * @param {Olm.Session} session - Participant's session.\r\n     * @returns {string} - The encrypted text with the key information.\r\n     * @private\r\n     */\r\n    _encryptKeyInfo(session) {\r\n        const keyInfo = {};\r\n\r\n        if (this._key !== undefined) {\r\n            keyInfo.key = this._key ? base64js.fromByteArray(this._key) : false;\r\n            keyInfo.keyIndex = this._keyIndex;\r\n        }\r\n\r\n        return session.encrypt(JSON.stringify(keyInfo));\r\n    }\r\n\r\n    /**\r\n     * Internal helper for getting the olm related data associated with a participant.\r\n     *\r\n     * @param {JitsiParticipant} participant - Participant whose data wants to be extracted.\r\n     * @returns {Object}\r\n     * @private\r\n     */\r\n    _getParticipantOlmData(participant) {\r\n        participant[kOlmData] = participant[kOlmData] || {};\r\n\r\n        return participant[kOlmData];\r\n    }\r\n\r\n    /**\r\n     * Handles leaving the conference, cleaning up olm sessions.\r\n     *\r\n     * @private\r\n     */\r\n    async _onConferenceLeft() {\r\n        logger.debug('Conference left');\r\n\r\n        await this._init;\r\n\r\n        for (const participant of this._conf.getParticipants()) {\r\n            this._onParticipantLeft(participant.getId(), participant);\r\n        }\r\n\r\n        if (this._olmAccount) {\r\n            this._olmAccount.free();\r\n            this._olmAccount = undefined;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Main message handler. Handles 1-to-1 messages received from other participants\r\n     * and send the appropriate replies.\r\n     *\r\n     * @private\r\n     */\r\n    async _onEndpointMessageReceived(participant, payload) {\r\n        if (payload[JITSI_MEET_MUC_TYPE] !== OLM_MESSAGE_TYPE) {\r\n            return;\r\n        }\r\n\r\n        if (!payload.olm) {\r\n            logger.warn('Incorrectly formatted message');\r\n\r\n            return;\r\n        }\r\n\r\n        await this._init;\r\n\r\n        const msg = payload.olm;\r\n        const pId = participant.getId();\r\n        const olmData = this._getParticipantOlmData(participant);\r\n\r\n        switch (msg.type) {\r\n        case OLM_MESSAGE_TYPES.SESSION_INIT: {\r\n            if (olmData.session) {\r\n                logger.warn(`Participant ${pId} already has a session`);\r\n\r\n                this._sendError(participant, 'Session already established');\r\n            } else {\r\n                // Create a session for communicating with this participant.\r\n\r\n                const session = new Olm.Session();\r\n\r\n                session.create_outbound(this._olmAccount, msg.data.idKey, msg.data.otKey);\r\n                olmData.session = session;\r\n\r\n                // Send ACK\r\n                const ack = {\r\n                    [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\r\n                    olm: {\r\n                        type: OLM_MESSAGE_TYPES.SESSION_ACK,\r\n                        data: {\r\n                            ciphertext: this._encryptKeyInfo(session),\r\n                            uuid: msg.data.uuid\r\n                        }\r\n                    }\r\n                };\r\n\r\n                this._sendMessage(ack, pId);\r\n                this._onParticipantE2EEChannelReady(pId);\r\n            }\r\n            break;\r\n        }\r\n        case OLM_MESSAGE_TYPES.SESSION_ACK: {\r\n            if (olmData.session) {\r\n                logger.warn(`Participant ${pId} already has a session`);\r\n\r\n                this._sendError(participant, 'No session found');\r\n            } else if (msg.data.uuid === olmData.pendingSessionUuid) {\r\n                const { ciphertext } = msg.data;\r\n                const d = this._reqs.get(msg.data.uuid);\r\n                const session = new Olm.Session();\r\n\r\n                session.create_inbound(this._olmAccount, ciphertext.body);\r\n\r\n                // Remove OT keys that have been used to setup this session.\r\n                this._olmAccount.remove_one_time_keys(session);\r\n\r\n                // Decrypt first message.\r\n                const data = session.decrypt(ciphertext.type, ciphertext.body);\r\n\r\n                olmData.session = session;\r\n                olmData.pendingSessionUuid = undefined;\r\n\r\n                this._onParticipantE2EEChannelReady(pId);\r\n\r\n                this._reqs.delete(msg.data.uuid);\r\n                d.resolve();\r\n\r\n                const json = safeJsonParse(data);\r\n\r\n                if (json.key) {\r\n                    const key = base64js.toByteArray(json.key);\r\n                    const keyIndex = json.keyIndex;\r\n\r\n                    olmData.lastKey = key;\r\n                    this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_KEY_UPDATED, pId, key, keyIndex);\r\n                }\r\n            } else {\r\n                logger.warn('Received ACK with the wrong UUID');\r\n\r\n                this._sendError(participant, 'Invalid UUID');\r\n            }\r\n            break;\r\n        }\r\n        case OLM_MESSAGE_TYPES.ERROR: {\r\n            logger.error(msg.data.error);\r\n\r\n            break;\r\n        }\r\n        case OLM_MESSAGE_TYPES.KEY_INFO: {\r\n            if (olmData.session) {\r\n                const { ciphertext } = msg.data;\r\n                const data = olmData.session.decrypt(ciphertext.type, ciphertext.body);\r\n                const json = safeJsonParse(data);\r\n\r\n                if (json.key !== undefined && json.keyIndex !== undefined) {\r\n                    const key = json.key ? base64js.toByteArray(json.key) : false;\r\n                    const keyIndex = json.keyIndex;\r\n\r\n                    if (!isEqual(olmData.lastKey, key)) {\r\n                        olmData.lastKey = key;\r\n                        this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_KEY_UPDATED, pId, key, keyIndex);\r\n                    }\r\n\r\n                    // Send ACK.\r\n                    const ack = {\r\n                        [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\r\n                        olm: {\r\n                            type: OLM_MESSAGE_TYPES.KEY_INFO_ACK,\r\n                            data: {\r\n                                ciphertext: this._encryptKeyInfo(olmData.session),\r\n                                uuid: msg.data.uuid\r\n                            }\r\n                        }\r\n                    };\r\n\r\n                    this._sendMessage(ack, pId);\r\n                }\r\n            } else {\r\n                logger.debug(`Received key info message from ${pId} but we have no session for them!`);\r\n\r\n                this._sendError(participant, 'No session found while processing key-info');\r\n            }\r\n            break;\r\n        }\r\n        case OLM_MESSAGE_TYPES.KEY_INFO_ACK: {\r\n            if (olmData.session) {\r\n                const { ciphertext } = msg.data;\r\n                const data = olmData.session.decrypt(ciphertext.type, ciphertext.body);\r\n                const json = safeJsonParse(data);\r\n\r\n                if (json.key !== undefined && json.keyIndex !== undefined) {\r\n                    const key = json.key ? base64js.toByteArray(json.key) : false;\r\n                    const keyIndex = json.keyIndex;\r\n\r\n                    if (!isEqual(olmData.lastKey, key)) {\r\n                        olmData.lastKey = key;\r\n                        this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_KEY_UPDATED, pId, key, keyIndex);\r\n                    }\r\n                }\r\n\r\n                const d = this._reqs.get(msg.data.uuid);\r\n\r\n                this._reqs.delete(msg.data.uuid);\r\n                d.resolve();\r\n            } else {\r\n                logger.debug(`Received key info ack message from ${pId} but we have no session for them!`);\r\n\r\n                this._sendError(participant, 'No session found while processing key-info-ack');\r\n            }\r\n            break;\r\n        }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Handles a participant leaving. When a participant leaves their olm session is destroyed.\r\n     *\r\n     * @private\r\n     */\r\n    _onParticipantLeft(id, participant) {\r\n        logger.debug(`Participant ${id} left`);\r\n\r\n        this.clearParticipantSession(participant);\r\n    }\r\n\r\n    /**\r\n    * Handles an update in a participant's presence property.\r\n    *\r\n    * @param {JitsiParticipant} participant - The participant.\r\n    * @param {string} name - The name of the property that changed.\r\n    * @param {*} oldValue - The property's previous value.\r\n    * @param {*} newValue - The property's new value.\r\n    * @private\r\n    */\r\n    async _onParticipantPropertyChanged(participant, name, oldValue, newValue) {\r\n        switch (name) {\r\n        case 'e2ee.enabled':\r\n            if (newValue && this._conf.isE2EEEnabled()) {\r\n                const localParticipantId = this._conf.myUserId();\r\n                const participantId = participant.getId();\r\n                const participantFeatures = await participant.getFeatures();\r\n\r\n                if (participantFeatures.has(FEATURE_E2EE) && localParticipantId < participantId) {\r\n                    if (this._sessionInitialization) {\r\n                        await this._sessionInitialization;\r\n                    }\r\n                    await this._sendSessionInit(participant);\r\n\r\n                    const olmData = this._getParticipantOlmData(participant);\r\n                    const uuid = uuidv4();\r\n\r\n                    const d = new Deferred();\r\n\r\n                    d.setRejectTimeout(REQ_TIMEOUT);\r\n                    d.catch(() => {\r\n                        this._reqs.delete(uuid);\r\n                        olmData.pendingSessionUuid = undefined;\r\n                    });\r\n                    this._reqs.set(uuid, d);\r\n\r\n                    const data = {\r\n                        [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\r\n                        olm: {\r\n                            type: OLM_MESSAGE_TYPES.KEY_INFO,\r\n                            data: {\r\n                                ciphertext: this._encryptKeyInfo(olmData.session),\r\n                                uuid\r\n                            }\r\n                        }\r\n                    };\r\n\r\n                    this._sendMessage(data, participantId);\r\n                }\r\n            }\r\n            break;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Builds and sends an error message to the target participant.\r\n     *\r\n     * @param {JitsiParticipant} participant - The target participant.\r\n     * @param {string} error - The error message.\r\n     * @returns {void}\r\n     */\r\n    _sendError(participant, error) {\r\n        const pId = participant.getId();\r\n        const err = {\r\n            [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\r\n            olm: {\r\n                type: OLM_MESSAGE_TYPES.ERROR,\r\n                data: {\r\n                    error\r\n                }\r\n            }\r\n        };\r\n\r\n        this._sendMessage(err, pId);\r\n    }\r\n\r\n    /**\r\n     * Internal helper to send the given object to the given participant ID.\r\n     * This function merely exists so the transport can be easily swapped.\r\n     * Currently messages are transmitted via XMPP MUC private messages.\r\n     *\r\n     * @param {object} data - The data that will be sent to the target participant.\r\n     * @param {string} participantId - ID of the target participant.\r\n     */\r\n    _sendMessage(data, participantId) {\r\n        this._conf.sendMessage(data, participantId);\r\n    }\r\n\r\n    /**\r\n     * Builds and sends the session-init request to the target participant.\r\n     *\r\n     * @param {JitsiParticipant} participant - Participant to whom we'll send the request.\r\n     * @returns {Promise} - The promise will be resolved when the session-ack is received.\r\n     * @private\r\n     */\r\n    _sendSessionInit(participant) {\r\n        const pId = participant.getId();\r\n        const olmData = this._getParticipantOlmData(participant);\r\n\r\n        if (olmData.session) {\r\n            logger.warn(`Tried to send session-init to ${pId} but we already have a session`);\r\n\r\n            return Promise.reject();\r\n        }\r\n\r\n        if (olmData.pendingSessionUuid !== undefined) {\r\n            logger.warn(`Tried to send session-init to ${pId} but we already have a pending session`);\r\n\r\n            return Promise.reject();\r\n        }\r\n\r\n        // Generate a One Time Key.\r\n        this._olmAccount.generate_one_time_keys(1);\r\n\r\n        const otKeys = JSON.parse(this._olmAccount.one_time_keys());\r\n        const otKey = Object.values(otKeys.curve25519)[0];\r\n\r\n        if (!otKey) {\r\n            return Promise.reject(new Error('No one-time-keys generated'));\r\n        }\r\n\r\n        // Mark the OT keys (one really) as published so they are not reused.\r\n        this._olmAccount.mark_keys_as_published();\r\n\r\n        const uuid = uuidv4();\r\n        const init = {\r\n            [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\r\n            olm: {\r\n                type: OLM_MESSAGE_TYPES.SESSION_INIT,\r\n                data: {\r\n                    idKey: this._idKey,\r\n                    otKey,\r\n                    uuid\r\n                }\r\n            }\r\n        };\r\n\r\n        const d = new Deferred();\r\n\r\n        d.setRejectTimeout(REQ_TIMEOUT);\r\n        d.catch(() => {\r\n            this._reqs.delete(uuid);\r\n            olmData.pendingSessionUuid = undefined;\r\n        });\r\n        this._reqs.set(uuid, d);\r\n\r\n        this._sendMessage(init, pId);\r\n\r\n        // Store the UUID for matching with the ACK.\r\n        olmData.pendingSessionUuid = uuid;\r\n\r\n        return d;\r\n    }\r\n}\r\n\r\n/**\r\n * Helper to ensure JSON parsing always returns an object.\r\n *\r\n * @param {string} data - The data that needs to be parsed.\r\n * @returns {object} - Parsed data or empty object in case of failure.\r\n */\r\nfunction safeJsonParse(data) {\r\n    try {\r\n        return JSON.parse(data);\r\n    } catch (e) {\r\n        return {};\r\n    }\r\n}\r\n\r\nOlmAdapter.events = OlmAdapterEvents;\r\n","import { getLogger } from '@jitsi/logger';\r\nimport debounce from 'lodash.debounce';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\n\r\nimport { KeyHandler } from './KeyHandler';\r\nimport { OlmAdapter } from './OlmAdapter';\r\nimport { importKey, ratchet } from './crypto-utils';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n// Period which we'll wait before updating / rotating our keys when a participant\r\n// joins or leaves.\r\nconst DEBOUNCE_PERIOD = 5000;\r\n\r\n/**\r\n * This module integrates {@link E2EEContext} with {@link OlmAdapter} in order to distribute the keys for encryption.\r\n */\r\nexport class ManagedKeyHandler extends KeyHandler {\r\n    /**\r\n     * Build a new AutomaticKeyHandler instance, which will be used in a given conference.\r\n     */\r\n    constructor(conference) {\r\n        super(conference);\r\n\r\n        this._key = undefined;\r\n        this._conferenceJoined = false;\r\n\r\n        this._olmAdapter = new OlmAdapter(conference);\r\n\r\n        this._rotateKey = debounce(this._rotateKeyImpl, DEBOUNCE_PERIOD);\r\n        this._ratchetKey = debounce(this._ratchetKeyImpl, DEBOUNCE_PERIOD);\r\n\r\n        // Olm signalling events.\r\n        this._olmAdapter.on(\r\n            OlmAdapter.events.PARTICIPANT_KEY_UPDATED,\r\n            this._onParticipantKeyUpdated.bind(this));\r\n\r\n        this.conference.on(\r\n            JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,\r\n            this._onParticipantPropertyChanged.bind(this));\r\n        this.conference.on(\r\n            JitsiConferenceEvents.USER_JOINED,\r\n            this._onParticipantJoined.bind(this));\r\n        this.conference.on(\r\n            JitsiConferenceEvents.USER_LEFT,\r\n            this._onParticipantLeft.bind(this));\r\n        this.conference.on(\r\n                JitsiConferenceEvents.CONFERENCE_JOINED,\r\n                () => {\r\n                    this._conferenceJoined = true;\r\n                });\r\n    }\r\n\r\n    /**\r\n     * When E2EE is enabled it initializes sessions and sets the key.\r\n     * Cleans up the sessions when disabled.\r\n     *\r\n     * @param {boolean} enabled - whether E2EE should be enabled or not.\r\n     * @returns {void}\r\n     */\r\n    async _setEnabled(enabled) {\r\n        if (enabled) {\r\n            await this._olmAdapter.initSessions();\r\n        } else {\r\n            this._olmAdapter.clearAllParticipantsSessions();\r\n        }\r\n\r\n        // Generate a random key in case we are enabling.\r\n        this._key = enabled ? this._generateKey() : false;\r\n\r\n        // Send it to others using the E2EE olm channel.\r\n        const index = await this._olmAdapter.updateKey(this._key);\r\n\r\n        // Set our key so we begin encrypting.\r\n        this.e2eeCtx.setKey(this.conference.myUserId(), this._key, index);\r\n    }\r\n\r\n    /**\r\n     * Handles an update in a participant's presence property.\r\n     *\r\n     * @param {JitsiParticipant} participant - The participant.\r\n     * @param {string} name - The name of the property that changed.\r\n     * @param {*} oldValue - The property's previous value.\r\n     * @param {*} newValue - The property's new value.\r\n     * @private\r\n     */\r\n    async _onParticipantPropertyChanged(participant, name, oldValue, newValue) {\r\n        switch (name) {\r\n        case 'e2ee.idKey':\r\n            logger.debug(`Participant ${participant.getId()} updated their id key: ${newValue}`);\r\n            break;\r\n        case 'e2ee.enabled':\r\n            if (!newValue && this.enabled) {\r\n                this._olmAdapter.clearParticipantSession(participant);\r\n            }\r\n            break;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Advances (using ratcheting) the current key when a new participant joins the conference.\r\n     * @private\r\n     */\r\n    _onParticipantJoined() {\r\n        if (this._conferenceJoined && this.enabled) {\r\n            this._ratchetKey();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Rotates the current key when a participant leaves the conference.\r\n     * @private\r\n     */\r\n    _onParticipantLeft(id) {\r\n        this.e2eeCtx.cleanup(id);\r\n\r\n        if (this.enabled) {\r\n            this._rotateKey();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Rotates the local key. Rotating the key implies creating a new one, then distributing it\r\n     * to all participants and once they all received it, start using it.\r\n     *\r\n     * @private\r\n     */\r\n    async _rotateKeyImpl() {\r\n        logger.debug('Rotating key');\r\n\r\n        this._key = this._generateKey();\r\n        const index = await this._olmAdapter.updateKey(this._key);\r\n\r\n        this.e2eeCtx.setKey(this.conference.myUserId(), this._key, index);\r\n    }\r\n\r\n    /**\r\n     * Advances the current key by using ratcheting.\r\n     *\r\n     * @private\r\n     */\r\n    async _ratchetKeyImpl() {\r\n        logger.debug('Ratchetting key');\r\n\r\n        const material = await importKey(this._key);\r\n        const newKey = await ratchet(material);\r\n\r\n        this._key = new Uint8Array(newKey);\r\n\r\n        const index = this._olmAdapter.updateCurrentKey(this._key);\r\n\r\n        this.e2eeCtx.setKey(this.conference.myUserId(), this._key, index);\r\n    }\r\n\r\n    /**\r\n     * Handles an update in a participant's key.\r\n     *\r\n     * @param {string} id - The participant ID.\r\n     * @param {Uint8Array | boolean} key - The new key for the participant.\r\n     * @param {Number} index - The new key's index.\r\n     * @private\r\n     */\r\n    _onParticipantKeyUpdated(id, key, index) {\r\n        logger.debug(`Participant ${id} updated their key`);\r\n\r\n        this.e2eeCtx.setKey(id, key, index);\r\n    }\r\n\r\n    /**\r\n     * Generates a new 256 bit random key.\r\n     *\r\n     * @returns {Uint8Array}\r\n     * @private\r\n     */\r\n    _generateKey() {\r\n        return window.crypto.getRandomValues(new Uint8Array(32));\r\n    }\r\n}\r\n","/**\r\n * Derives a set of keys from the master key.\r\n * @param {CryptoKey} material - master key to derive from\r\n *\r\n * See https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.1\r\n */\r\nexport async function deriveKeys(material) {\r\n    const info = new ArrayBuffer();\r\n    const textEncoder = new TextEncoder();\r\n\r\n    // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey#HKDF\r\n    // https://developer.mozilla.org/en-US/docs/Web/API/HkdfParams\r\n    const encryptionKey = await crypto.subtle.deriveKey({\r\n        name: 'HKDF',\r\n        salt: textEncoder.encode('JFrameEncryptionKey'),\r\n        hash: 'SHA-256',\r\n        info\r\n    }, material, {\r\n        name: 'AES-GCM',\r\n        length: 128\r\n    }, false, [ 'encrypt', 'decrypt' ]);\r\n\r\n    return {\r\n        material,\r\n        encryptionKey\r\n    };\r\n}\r\n\r\n/**\r\n * Ratchets a key. See\r\n * https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.5.1\r\n * @param {CryptoKey} material - base key material\r\n * @returns {Promise<ArrayBuffer>} - ratcheted key material\r\n */\r\nexport async function ratchet(material) {\r\n    const textEncoder = new TextEncoder();\r\n\r\n    // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveBits\r\n    return crypto.subtle.deriveBits({\r\n        name: 'HKDF',\r\n        salt: textEncoder.encode('JFrameRatchetKey'),\r\n        hash: 'SHA-256',\r\n        info: new ArrayBuffer()\r\n    }, material, 256);\r\n}\r\n\r\n/**\r\n * Converts a raw key into a WebCrypto key object with default options\r\n * suitable for our usage.\r\n * @param {ArrayBuffer} keyBytes - raw key\r\n * @param {Array} keyUsages - key usages, see importKey documentation\r\n * @returns {Promise<CryptoKey>} - the WebCrypto key.\r\n */\r\nexport async function importKey(keyBytes) {\r\n    // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey\r\n    return crypto.subtle.importKey('raw', keyBytes, 'HKDF', false, [ 'deriveBits', 'deriveKey' ]);\r\n}\r\n","import browser from '../browser';\r\n\r\nimport { ExternallyManagedKeyHandler } from './ExternallyManagedKeyHandler';\r\nimport { ManagedKeyHandler } from './ManagedKeyHandler';\r\nimport { OlmAdapter } from './OlmAdapter';\r\n\r\n/**\r\n * This module integrates {@link KeyHandler} with {@link JitsiConference} in order to enable E2E encryption.\r\n */\r\nexport class E2EEncryption {\r\n    /**\r\n     * A constructor.\r\n     * @param {JitsiConference} conference - The conference instance for which E2E encryption is to be enabled.\r\n     */\r\n    constructor(conference) {\r\n        const { e2ee = {} } = conference.options.config;\r\n\r\n        this._externallyManaged = e2ee.externallyManagedKey;\r\n\r\n        if (this._externallyManaged) {\r\n            this._keyHandler = new ExternallyManagedKeyHandler(conference);\r\n        } else {\r\n            this._keyHandler = new ManagedKeyHandler(conference);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Indicates if E2EE is supported in the current platform.\r\n     *\r\n     * @param {object} config - Global configuration.\r\n     * @returns {boolean}\r\n     */\r\n    static isSupported(config) {\r\n        const { e2ee = {} } = config;\r\n\r\n        if (!e2ee.externallyManagedKey && !OlmAdapter.isSupported()) {\r\n            return false;\r\n        }\r\n\r\n        return !(config.testing && config.testing.disableE2EE)\r\n            && (browser.supportsInsertableStreams()\r\n                || (config.enableEncodedTransformSupport && browser.supportsEncodedTransform()));\r\n    }\r\n\r\n    /**\r\n     * Indicates whether E2EE is currently enabled or not.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isEnabled() {\r\n        return this._keyHandler.isEnabled();\r\n    }\r\n\r\n    /**\r\n     * Enables / disables End-To-End encryption.\r\n     *\r\n     * @param {boolean} enabled - whether E2EE should be enabled or not.\r\n     * @returns {void}\r\n     */\r\n    async setEnabled(enabled) {\r\n        await this._keyHandler.setEnabled(enabled);\r\n    }\r\n\r\n    /**\r\n     * Sets the key and index for End-to-End encryption.\r\n     *\r\n     * @param {CryptoKey} [keyInfo.encryptionKey] - encryption key.\r\n     * @param {Number} [keyInfo.index] - the index of the encryption key.\r\n     * @returns {void}\r\n     */\r\n    setEncryptionKey(keyInfo) {\r\n        this._keyHandler.setKey(keyInfo);\r\n    }\r\n}\r\n","import $ from 'jquery';\r\nimport { Strophe, b64_sha1 } from 'strophe.js'; // eslint-disable-line camelcase\r\n\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\nimport Listenable from '../util/Listenable';\r\n\r\n/**\r\n * The property\r\n */\r\nconst IDENTITY_PROPERTIES = [ 'category', 'type', 'lang', 'name' ];\r\nconst IDENTITY_PROPERTIES_FOR_COMPARE = [ 'category', 'type', 'lang' ];\r\nconst HASH = 'sha-1';\r\n\r\n/**\r\n *\r\n * @param a\r\n * @param b\r\n */\r\nfunction compareIdentities(a, b) {\r\n    let res = 0;\r\n\r\n    IDENTITY_PROPERTIES_FOR_COMPARE.some(key =>\r\n        (res = ((a[key] > b[key]) && 1) || ((a[key] < b[key]) && -1)) !== 0\r\n    );\r\n\r\n    return res;\r\n}\r\n\r\n/**\r\n * Produces a sha-1 from provided identity and features values.\r\n *\r\n * @param {Array<Object>} identities - The identity objects.\r\n * @param {Array<string>} features - The features.\r\n * @returns {string}\r\n */\r\nfunction generateSha(identities, features) {\r\n    const sortedIdentities = identities.sort(compareIdentities).reduce(\r\n        (accumulatedValue, identity) => `${\r\n            IDENTITY_PROPERTIES.reduce(\r\n                (tmp, key, idx) =>\r\n                    tmp\r\n                        + (idx === 0 ? '' : '/')\r\n                        + (identity[key] ? identity[key] : ''),\r\n                '')\r\n        }<`, '');\r\n    const sortedFeatures = features.sort().reduce(\r\n        (tmp, feature) => `${tmp + feature}<`, '');\r\n\r\n    return b64_sha1(sortedIdentities + sortedFeatures);\r\n}\r\n\r\n/**\r\n * Parses the disco-info node and returns the sets of features and identities.\r\n * @param {String} node The node with results to parse.\r\n * @returns {{features: Set<any>, identities: Set<any>}}\r\n */\r\nexport function parseDiscoInfo(node) {\r\n    const features = new Set();\r\n    const identities = new Set();\r\n\r\n    $(node).find('>query>feature')\r\n        .each((_, el) => features.add(el.getAttribute('var')));\r\n    $(node).find('>query>identity')\r\n        .each((_, el) => identities.add({\r\n            type: el.getAttribute('type'),\r\n            name: el.getAttribute('name'),\r\n            category: el.getAttribute('category')\r\n        }));\r\n\r\n    return {\r\n        features,\r\n        identities\r\n    };\r\n}\r\n\r\n/**\r\n * Implements xep-0115 ( http://xmpp.org/extensions/xep-0115.html )\r\n */\r\nexport default class Caps extends Listenable {\r\n    /**\r\n     * Constructs new Caps instance.\r\n     * @param {Strophe.Connection} connection the strophe connection object\r\n     * @param {String} node the value of the node attribute of the \"c\" xml node\r\n     * that will be sent to the other participants\r\n     */\r\n    constructor(connection = {}, node = 'http://jitsi.org/jitsimeet') {\r\n        super();\r\n        this.node = node;\r\n        this.disco = connection.disco;\r\n        if (!this.disco) {\r\n            throw new Error(\r\n                'Missing strophe-plugins '\r\n                + '(disco plugin is required)!');\r\n        }\r\n\r\n        this.version = '';\r\n        this.rooms = new Set();\r\n\r\n        // We keep track of features added outside the library and we publish them\r\n        // in the presence of the participant for simplicity, avoiding the disco info request-response.\r\n        this.externalFeatures = new Set();\r\n\r\n        const emuc = connection.emuc;\r\n\r\n        emuc.addListener(XMPPEvents.EMUC_ROOM_ADDED,\r\n            room => this._addChatRoom(room));\r\n        emuc.addListener(XMPPEvents.EMUC_ROOM_REMOVED,\r\n            room => this._removeChatRoom(room));\r\n        Object.keys(emuc.rooms).forEach(jid => {\r\n            this._addChatRoom(emuc.rooms[jid]);\r\n        });\r\n\r\n        Strophe.addNamespace('CAPS', 'http://jabber.org/protocol/caps');\r\n        this.disco.addFeature(Strophe.NS.CAPS);\r\n    }\r\n\r\n    /**\r\n     * Adds new feature to the list of supported features for the local\r\n     * participant\r\n     * @param {String} feature the name of the feature.\r\n     * @param {boolean} submit if true - new presence with updated \"c\" node\r\n     * will be sent.\r\n     * @param {boolean} external whether this feature was added externally to the library.\r\n     * We put features used directly by the clients (is jibri, remote-control enabled etc.) in the presence\r\n     * to avoid additional disco-info queries by those clients.\r\n     */\r\n    addFeature(feature, submit = false, external = false) {\r\n        this.disco.addFeature(feature);\r\n        this._generateVersion();\r\n\r\n        if (external && !this.externalFeatures.has(feature)) {\r\n            this.externalFeatures.add(feature);\r\n            this.rooms.forEach(room => this._updateRoomWithExternalFeatures(room));\r\n        }\r\n\r\n        if (submit) {\r\n            this.submit();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Removes a feature from the list of supported features for the local\r\n     * participant\r\n     * @param {String} feature the name of the feature.\r\n     * @param {boolean} submit if true - new presence with updated \"c\" node\r\n     * will be sent.\r\n     * @param {boolean} external whether this feature was added externally to the library.\r\n     */\r\n    removeFeature(feature, submit = false, external = false) {\r\n        this.disco.removeFeature(feature);\r\n        this._generateVersion();\r\n\r\n        if (external && this.externalFeatures.has(feature)) {\r\n            this.externalFeatures.delete(feature);\r\n            this.rooms.forEach(room => this._updateRoomWithExternalFeatures(room));\r\n        }\r\n\r\n        if (submit) {\r\n            this.submit();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sends new presence stanza for every room from the list of rooms.\r\n     */\r\n    submit() {\r\n        this.rooms.forEach(room => room.sendPresence());\r\n    }\r\n\r\n    /**\r\n     * Updates the presences in the room based on the current values in externalFeatures.\r\n     * @param {ChatRoom} room the room to update.\r\n     * @private\r\n     */\r\n    _updateRoomWithExternalFeatures(room) {\r\n        if (this.externalFeatures.size === 0) {\r\n            room.removeFromPresence('features');\r\n        } else {\r\n            const children = [];\r\n\r\n            this.externalFeatures.forEach(f => {\r\n                children.push({\r\n                    'tagName': 'feature',\r\n                    attributes: { 'var': f }\r\n                });\r\n            });\r\n\r\n            room.addOrReplaceInPresence('features', { children });\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns a set with the features for a host.\r\n     * @param {String} jid the jid of the host\r\n     * @param {int} timeout the timeout in ms for reply from the host.\r\n     * @returns {Promise<Set<String>, Error>}\r\n     */\r\n    getFeaturesAndIdentities(jid, node, timeout = 5000) {\r\n        return this._getDiscoInfo(jid, node, timeout);\r\n    }\r\n\r\n    /**\r\n     * Returns a set with the features and identities for a host.\r\n     * @param {String} jid the jid of the host\r\n     * @param {String|null} node the node to query\r\n     * @param {int} timeout the timeout in ms for reply from the host.\r\n     * @returns {Promise<Object>}\r\n     * @private\r\n     */\r\n    _getDiscoInfo(jid, node, timeout) {\r\n        return new Promise((resolve, reject) =>\r\n            this.disco.info(jid, node, response => {\r\n                resolve(parseDiscoInfo(response));\r\n            }, reject, timeout)\r\n        );\r\n    }\r\n\r\n    /**\r\n     * Adds ChatRoom instance to the list of rooms. Adds listeners to the room\r\n     * and adds \"c\" element to the presences of the room.\r\n     * @param {ChatRoom} room the room.\r\n     */\r\n    _addChatRoom(room) {\r\n        this.rooms.add(room);\r\n        this._fixChatRoomPresenceMap(room);\r\n\r\n        this._updateRoomWithExternalFeatures(room);\r\n    }\r\n\r\n    /**\r\n     * Removes ChatRoom instance from the list of rooms. Removes listeners\r\n     * added from the Caps class.\r\n     * @param {ChatRoom} room the room.\r\n     */\r\n    _removeChatRoom(room) {\r\n        this.rooms.delete(room);\r\n    }\r\n\r\n    /**\r\n     * Creates/updates the \"c\" xml node into the presence of the passed room.\r\n     * @param {ChatRoom} room the room.\r\n     */\r\n    _fixChatRoomPresenceMap(room) {\r\n        room.addOrReplaceInPresence('c', {\r\n            attributes: {\r\n                xmlns: Strophe.NS.CAPS,\r\n                hash: HASH,\r\n                node: this.node,\r\n                ver: this.version\r\n            }\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Handles this.version changes.\r\n     */\r\n    _notifyVersionChanged() {\r\n        // update the version for all rooms\r\n        this.rooms.forEach(room => this._fixChatRoomPresenceMap(room));\r\n    }\r\n\r\n    /**\r\n     * Generates the value for the \"ver\" attribute.\r\n     */\r\n    _generateVersion() {\r\n        this.version\r\n            = generateSha(this.disco._identities, this.disco._features);\r\n\r\n        this._notifyVersionChanged();\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport Listenable from '../util/Listenable';\r\n\r\nexport const NETWORK_INFO_EVENT = 'NETWORK_INFO_CHANGED';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Module provides information about the current status of the internet\r\n * connection. Lib-jitsi-meet doesn't have any logic for detecting internet\r\n * online/offline, but rather it relies on the information supplied by the app\r\n * that uses it. By default the online state is assumed and the lib acts as if\r\n * it was connected. See {@link JitsiMeetJS.setNetworkInfo}.\r\n */\r\nexport class NetworkInfo extends Listenable {\r\n    /**\r\n     * Creates new {@link NetworkInfo} instance.\r\n     */\r\n    constructor() {\r\n        super();\r\n        this._current = {\r\n            isOnline: true\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Updates the network info state.\r\n     *\r\n     * @param {object} state - The network info state.\r\n     * @param {boolean} state.isOnline - {@code true} if the internet connectivity is online or {@code false}\r\n     * otherwise.\r\n     */\r\n    updateNetworkInfo({ isOnline }) {\r\n        logger.debug('updateNetworkInfo', { isOnline });\r\n        this._current = {\r\n            isOnline: isOnline === true\r\n        };\r\n        this.eventEmitter.emit(NETWORK_INFO_EVENT, this._current);\r\n    }\r\n\r\n    /**\r\n     * Returns the online/offline internet status. By default the value is {@code true} and changes only if\r\n     * the lib's user wires the state through {@link JitsiMeetJS.setNetworkInfo} like the jitsi-meet does. Because of\r\n     * that any logic should still assume that the internet may be offline and should handle the failure gracefully.\r\n     * It's only a good hint in the other way around: to pause internet operations until it comes back online.\r\n     * @returns {boolean}\r\n     */\r\n    isOnline() {\r\n        return this._current.isOnline === true;\r\n    }\r\n}\r\n\r\nconst networkInfo = new NetworkInfo();\r\n\r\nexport default networkInfo;\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport {\r\n    NETWORK_INFO_EVENT,\r\n    default as NetworkInfo\r\n} from '../connectivity/NetworkInfo';\r\nimport { getJitterDelay } from '../util/Retry';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * The class contains the logic for triggering connection resume via XEP-0198 stream management.\r\n * It does two things, the first one is it tracks the internet online/offline status and it makes sure that\r\n * the reconnect is attempted only while online. The seconds thing is that it tracks the retry attempts and extends\r\n * the retry interval using the full jitter pattern.\r\n */\r\nexport default class ResumeTask {\r\n    /**\r\n     * Initializes new {@code RetryTask}.\r\n     * @param {Strophe.Connection} stropheConnection - The Strophe connection instance.\r\n     */\r\n    constructor(stropheConnection) {\r\n        this._stropheConn = stropheConnection;\r\n\r\n        /**\r\n         * The counter increased before each resume retry attempt, used to calculate exponential backoff.\r\n         * @type {number}\r\n         * @private\r\n         */\r\n        this._resumeRetryN = 0;\r\n\r\n        this._retryDelay = undefined;\r\n    }\r\n\r\n    /**\r\n     * @returns {number|undefined} - How much the app will wait before trying to resume the XMPP connection. When\r\n     * 'undefined' it means that no resume task was not scheduled.\r\n     */\r\n    get retryDelay() {\r\n        return this._retryDelay;\r\n    }\r\n\r\n    /**\r\n     * Called by {@link XmppConnection} when the connection drops and it's a signal it wants to schedule a reconnect.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    schedule() {\r\n        this._cancelResume();\r\n\r\n        this._resumeRetryN += 1;\r\n\r\n        this._networkOnlineListener\r\n            = NetworkInfo.addEventListener(\r\n                NETWORK_INFO_EVENT,\r\n                ({ isOnline }) => {\r\n                    if (isOnline) {\r\n                        this._scheduleResume();\r\n                    } else {\r\n                        this._cancelResume();\r\n                    }\r\n                });\r\n\r\n        NetworkInfo.isOnline() && this._scheduleResume();\r\n    }\r\n\r\n    /**\r\n     * Schedules a delayed timeout which will execute the resume action.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _scheduleResume() {\r\n        if (this._resumeTimeout) {\r\n\r\n            // NO-OP\r\n            return;\r\n        }\r\n\r\n        // The retry delay will be:\r\n        //   1st retry: 1.5s - 3s\r\n        //   2nd retry: 3s - 9s\r\n        //   3rd and next retry: 4.5s - 27s\r\n        this._resumeRetryN = Math.min(3, this._resumeRetryN);\r\n        this._retryDelay = getJitterDelay(\r\n            /* retry */ this._resumeRetryN,\r\n            /* minDelay */ this._resumeRetryN * 1500,\r\n            3);\r\n\r\n        logger.info(`Will try to resume the XMPP connection in ${this.retryDelay}ms`);\r\n\r\n        this._resumeTimeout = setTimeout(() => this._resumeConnection(), this.retryDelay);\r\n    }\r\n\r\n    /**\r\n     * Cancels the delayed resume task.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _cancelResume() {\r\n        if (this._resumeTimeout) {\r\n            logger.info('Canceling connection resume task');\r\n            clearTimeout(this._resumeTimeout);\r\n            this._resumeTimeout = undefined;\r\n            this._retryDelay = undefined;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Resumes the XMPP connection using the stream management plugin.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _resumeConnection() {\r\n        const { streamManagement } = this._stropheConn;\r\n        const resumeToken = streamManagement.getResumeToken();\r\n\r\n        // Things may have changed since when the task was scheduled\r\n        if (!resumeToken) {\r\n            return;\r\n        }\r\n\r\n        logger.info('Trying to resume the XMPP connection');\r\n\r\n        const url = new URL(this._stropheConn.service);\r\n        let { search } = url;\r\n        const pattern = /(previd=)([\\w-]+)/;\r\n        const oldToken = search.match(pattern);\r\n\r\n        // Replace previd if the previd value has changed.\r\n        if (oldToken && oldToken.indexOf(resumeToken) === -1) {\r\n            search = search.replace(pattern, `$1${resumeToken}`);\r\n\r\n        // Append previd if it doesn't exist.\r\n        } else if (!oldToken) {\r\n            search += search.indexOf('?') === -1 ? `?previd=${resumeToken}` : `&previd=${resumeToken}`;\r\n        }\r\n\r\n        url.search = search;\r\n\r\n        this._stropheConn.service = url.toString();\r\n\r\n        streamManagement.resume();\r\n    }\r\n\r\n    /**\r\n     * Cancels the retry task. It's called by {@link XmppConnection} when it's no longer interested in reconnecting for\r\n     * example when the disconnect method is called.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    cancel() {\r\n        this._cancelResume();\r\n        this._resumeRetryN = 0;\r\n        if (this._networkOnlineListener) {\r\n            this._networkOnlineListener();\r\n            this._networkOnlineListener = null;\r\n        }\r\n    }\r\n}\r\n","/**\r\n* Gets next timeout using the full jitter pattern.\r\n*\r\n* NOTE that there are no checks for argument correctness, so either do the math or use defaults.\r\n*\r\n* @param {number} retry - The retry number.\r\n* @param {number} minDelay - The minimal delay in milliseconds.\r\n* @param {number} base - The exponent base.\r\n* @returns {number} - The amount of waiting before trying another time given in milliseconds.\r\n* @private\r\n*/\r\nexport function getJitterDelay(retry, minDelay = 500, base = 2) {\r\n    return Math.floor((Math.random() * ((Math.pow(base, retry) * 1000) - minDelay)) + minDelay);\r\n}\r\n","/**\r\n * Attaches to the {@link Strophe.Connection.rawInput} which is called whenever any data is received from the server.\r\n */\r\nexport default class LastRequestTracker {\r\n    /**\r\n     * Initializes new instance.\r\n     */\r\n    constructor() {\r\n        this._lastSuccess = null;\r\n        this._lastFailedMessage = null;\r\n    }\r\n\r\n    /**\r\n     * Starts tracking requests on the given connection.\r\n     *\r\n     * @param {XmppConnection} xmppConnection - The XMPP connection which manages the given {@code stropheConnection}.\r\n     * @param {Object} stropheConnection - Strophe connection instance.\r\n     */\r\n    startTracking(xmppConnection, stropheConnection) {\r\n        const originalRawInput = stropheConnection.rawInput;\r\n\r\n        stropheConnection.rawInput = (...args) => {\r\n            const rawMessage = args[0];\r\n\r\n            if (rawMessage.includes('failure')) {\r\n                this._lastFailedMessage = rawMessage;\r\n            }\r\n\r\n            // It's okay to use rawInput callback only once the connection has been established, otherwise it will\r\n            // treat 'item-not-found' or other connection error on websocket reconnect as successful stanza received.\r\n            if (xmppConnection.connected) {\r\n                this._lastSuccess = Date.now();\r\n            }\r\n            originalRawInput.apply(stropheConnection, args);\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Returns the last raw failed incoming message on the xmpp connection.\r\n     *\r\n     * @returns {string|null}\r\n     */\r\n    getLastFailedMessage() {\r\n        return this._lastFailedMessage;\r\n    }\r\n\r\n    /**\r\n     * Returns how many milliseconds have passed since the last successful BOSH request.\r\n     *\r\n     * @returns {number|null}\r\n     */\r\n    getTimeSinceLastSuccess() {\r\n        return this._lastSuccess\r\n            ? Date.now() - this._lastSuccess\r\n            : null;\r\n    }\r\n}\r\n","import Listenable from '../util/Listenable';\r\n\r\n/**\r\n * Creates ConnectionPlugin class that extends the passed class.\r\n * @param {Class} base the definition of the class that will be extended by\r\n * ConnectionPlugin\r\n */\r\nfunction getConnectionPluginDefinition(base = class {}) {\r\n    /**\r\n     * Base class for strophe connection plugins.\r\n     */\r\n    return class extends base {\r\n        /**\r\n         *\r\n         */\r\n        constructor(...args) {\r\n            super(...args);\r\n            this.connection = null;\r\n        }\r\n\r\n        /**\r\n         *\r\n         * @param connection\r\n         */\r\n        init(connection) {\r\n            this.connection = connection;\r\n        }\r\n    };\r\n}\r\n\r\n/**\r\n * ConnectionPlugin class.\r\n */\r\nexport default getConnectionPluginDefinition();\r\n\r\n/**\r\n * ConnectionPlugin class that extends Listenable.\r\n */\r\nexport const ConnectionPluginListenable\r\n    = getConnectionPluginDefinition(Listenable);\r\n","import { getLogger } from '@jitsi/logger';\r\nimport { $iq, Strophe } from 'strophe.js';\r\n\r\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\r\n\r\nimport ConnectionPlugin from './ConnectionPlugin';\r\n\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Default ping every 10 sec\r\n */\r\nconst PING_DEFAULT_INTERVAL = 10000;\r\n\r\n/**\r\n * Default ping timeout error after 5 sec of waiting.\r\n */\r\nconst PING_DEFAULT_TIMEOUT = 5000;\r\n\r\n/**\r\n * Default value for how many ping failures will be tolerated before the WebSocket connection is killed.\r\n * The worst case scenario in case of ping timing out without a response is (25 seconds at the time of this writing):\r\n * PING_THRESHOLD * PING_INTERVAL + PING_TIMEOUT\r\n */\r\nconst PING_DEFAULT_THRESHOLD = 2;\r\n\r\n/**\r\n * XEP-0199 ping plugin.\r\n *\r\n * Registers \"urn:xmpp:ping\" namespace under Strophe.NS.PING.\r\n */\r\nexport default class PingConnectionPlugin extends ConnectionPlugin {\r\n    /**\r\n     * Constructs new object\r\n     * @param {Object} options\r\n     * @param {Function} options.onPingThresholdExceeded - Callback called when ping fails too many times (controlled\r\n     * by the {@link PING_THRESHOLD} constant).\r\n     * @param {Function} options._getTimeSinceLastServerResponse - A function to obtain the last seen\r\n     * response from the server.\r\n     * @param {Object} options.pingOptions - The ping options if any.\r\n     * @constructor\r\n     */\r\n    constructor({ getTimeSinceLastServerResponse, onPingThresholdExceeded, pingOptions = {} }) {\r\n        super();\r\n        this.failedPings = 0;\r\n        this._onPingThresholdExceeded = onPingThresholdExceeded;\r\n        this._getTimeSinceLastServerResponse = getTimeSinceLastServerResponse;\r\n\r\n        this.pingInterval = typeof pingOptions.interval === 'number' ? pingOptions.interval : PING_DEFAULT_INTERVAL;\r\n        this.pingTimeout = typeof pingOptions.timeout === 'number' ? pingOptions.timeout : PING_DEFAULT_TIMEOUT;\r\n        this.pingThreshold = typeof pingOptions.threshold === 'number'\r\n            ? pingOptions.threshold : PING_DEFAULT_THRESHOLD;\r\n\r\n        // The number of timestamps of send pings to keep.\r\n        // The current value is 2 minutes.\r\n        this.pingTimestampsToKeep = Math.round(120000 / this.pingInterval);\r\n        this.pingExecIntervals = new Array(this.pingTimestampsToKeep);\r\n    }\r\n\r\n    /**\r\n     * Initializes the plugin. Method called by Strophe.\r\n     * @param connection Strophe connection instance.\r\n     */\r\n    init(connection) {\r\n        super.init(connection);\r\n        Strophe.addNamespace('PING', 'urn:xmpp:ping');\r\n    }\r\n\r\n    /* eslint-disable max-params */\r\n\r\n    /**\r\n     * Sends \"ping\" to given <tt>jid</tt>\r\n     * @param jid the JID to which ping request will be sent.\r\n     * @param success callback called on success.\r\n     * @param error callback called on error.\r\n     * @param timeout ms how long are we going to wait for the response. On\r\n     * timeout <tt>error<//t> callback is called with undefined error argument.\r\n     */\r\n    ping(jid, success, error, timeout) {\r\n        this._addPingExecutionTimestamp();\r\n\r\n        const iq = $iq({\r\n            type: 'get',\r\n            to: jid\r\n        });\r\n\r\n        iq.c('ping', { xmlns: Strophe.NS.PING });\r\n        this.connection.sendIQ2(iq, { timeout })\r\n            .then(success, error);\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * Starts to send ping in given interval to specified remote JID.\r\n     * This plugin supports only one such task and <tt>stopInterval</tt>\r\n     * must be called before starting a new one.\r\n     * @param remoteJid remote JID to which ping requests will be sent to.\r\n     */\r\n    startInterval(remoteJid) {\r\n        clearInterval(this.intervalId);\r\n        this.intervalId = window.setInterval(() => {\r\n\r\n            // when there were some server responses in the interval since the last time we checked (_lastServerCheck)\r\n            // let's skip the ping\r\n\r\n            const now = Date.now();\r\n\r\n            if (this._getTimeSinceLastServerResponse() < now - this._lastServerCheck) {\r\n                // do this just to keep in sync the intervals so we can detect suspended device\r\n                this._addPingExecutionTimestamp();\r\n\r\n                this._lastServerCheck = now;\r\n                this.failedPings = 0;\r\n\r\n                return;\r\n            }\r\n\r\n            this.ping(remoteJid, () => {\r\n                // server response is measured on raw input and ping response time is measured after all the xmpp\r\n                // processing is done in js, so there can be some misalignment when we do the check above.\r\n                // That's why we store the last time we got the response\r\n                this._lastServerCheck = this._getTimeSinceLastServerResponse() + Date.now();\r\n\r\n                this.failedPings = 0;\r\n            }, error => {\r\n                this.failedPings += 1;\r\n                const errmsg = `Ping ${error ? 'error' : 'timeout'}`;\r\n\r\n                if (this.failedPings >= this.pingThreshold) {\r\n                    GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\r\n                    logger.error(errmsg, error);\r\n                    this._onPingThresholdExceeded && this._onPingThresholdExceeded();\r\n                } else {\r\n                    logger.warn(errmsg, error);\r\n                }\r\n            }, this.pingTimeout);\r\n        }, this.pingInterval);\r\n        logger.info(`XMPP pings will be sent every ${this.pingInterval} ms`);\r\n    }\r\n\r\n    /**\r\n     * Stops current \"ping\"  interval task.\r\n     */\r\n    stopInterval() {\r\n        if (this.intervalId) {\r\n            window.clearInterval(this.intervalId);\r\n            this.intervalId = null;\r\n            this.failedPings = 0;\r\n            logger.info('Ping interval cleared');\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Adds the current time to the array of send ping timestamps.\r\n     * @private\r\n     */\r\n    _addPingExecutionTimestamp() {\r\n        this.pingExecIntervals.push(new Date().getTime());\r\n\r\n        // keep array length to PING_TIMESTAMPS_TO_KEEP\r\n        if (this.pingExecIntervals.length > this.pingTimestampsToKeep) {\r\n            this.pingExecIntervals.shift();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns the maximum time between the recent sent pings, if there is a\r\n     * big value it means the computer was inactive for some time(suspended).\r\n     * Checks the maximum gap between sending pings, considering and the\r\n     * current time. Trying to detect computer inactivity (sleep).\r\n     *\r\n     * @returns {int} the time ping was suspended, if it was not 0 is returned.\r\n     */\r\n    getPingSuspendTime() {\r\n        const pingIntervals = this.pingExecIntervals.slice();\r\n\r\n        // we need current time, as if ping was sent now\r\n        // if computer sleeps we will get correct interval after next\r\n        // scheduled ping, bet we sometimes need that interval before waiting\r\n        // for the next ping, on closing the connection on error.\r\n        pingIntervals.push(new Date().getTime());\r\n\r\n        let maxInterval = 0;\r\n        let previousTS = pingIntervals[0];\r\n\r\n        pingIntervals.forEach(e => {\r\n            const currentInterval = e - previousTS;\r\n\r\n            if (currentInterval > maxInterval) {\r\n                maxInterval = currentInterval;\r\n            }\r\n\r\n            previousTS = e;\r\n        });\r\n\r\n        // remove the interval between the ping sent\r\n        // this way in normal execution there is no suspend and the return\r\n        // will be 0 or close to 0.\r\n        maxInterval -= this.pingInterval;\r\n\r\n        // make sure we do not return less than 0\r\n        return Math.max(maxInterval, 0);\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport { $pres, Strophe } from 'strophe.js';\r\nimport 'strophejs-plugin-stream-management';\r\n\r\nimport Listenable from '../util/Listenable';\r\n\r\nimport ResumeTask from './ResumeTask';\r\nimport LastSuccessTracker from './StropheLastSuccess';\r\nimport PingConnectionPlugin from './strophe.ping';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * The lib-jitsi-meet layer for {@link Strophe.Connection}.\r\n */\r\nexport default class XmppConnection extends Listenable {\r\n    /**\r\n     * The list of {@link XmppConnection} events.\r\n     *\r\n     * @returns {Object}\r\n     */\r\n    static get Events() {\r\n        return {\r\n            CONN_STATUS_CHANGED: 'CONN_STATUS_CHANGED',\r\n            CONN_SHARD_CHANGED: 'CONN_SHARD_CHANGED'\r\n        };\r\n    }\r\n\r\n    /**\r\n     * The list of Xmpp connection statuses.\r\n     *\r\n     * @returns {Strophe.Status}\r\n     */\r\n    static get Status() {\r\n        return Strophe.Status;\r\n    }\r\n\r\n    /**\r\n     * Initializes new connection instance.\r\n     *\r\n     * @param {Object} options\r\n     * @param {String} options.serviceUrl - The BOSH or WebSocket service URL.\r\n     * @param {String} options.shard - The BOSH or WebSocket is connecting to this shard.\r\n     * Useful for detecting when shard changes.\r\n     * @param {String} [options.enableWebsocketResume=true] - True/false to control the stream resumption functionality.\r\n     * It will enable automatically by default if supported by the XMPP server.\r\n     * @param {Number} [options.websocketKeepAlive=60000] - The websocket keep alive interval.\r\n     * It's the interval + a up to a minute of jitter. Pass -1 to disable.\r\n     * The keep alive is HTTP GET request to {@link options.serviceUrl} or to {@link options.websocketKeepAliveUrl}.\r\n     * @param {Number} [options.websocketKeepAliveUrl] - The websocket keep alive url to use if any,\r\n     * if missing the serviceUrl url will be used.\r\n     * @param {Object} [options.xmppPing] - The xmpp ping settings.\r\n     */\r\n    constructor({ enableWebsocketResume, websocketKeepAlive, websocketKeepAliveUrl, serviceUrl, shard, xmppPing }) {\r\n        super();\r\n        this._options = {\r\n            enableWebsocketResume: typeof enableWebsocketResume === 'undefined' ? true : enableWebsocketResume,\r\n            pingOptions: xmppPing,\r\n            shard,\r\n            websocketKeepAlive: typeof websocketKeepAlive === 'undefined' ? 60 * 1000 : Number(websocketKeepAlive),\r\n            websocketKeepAliveUrl\r\n        };\r\n\r\n        this._stropheConn = new Strophe.Connection(serviceUrl);\r\n        this._usesWebsocket = serviceUrl.startsWith('ws:') || serviceUrl.startsWith('wss:');\r\n\r\n        // The default maxRetries is 5, which is too long.\r\n        this._stropheConn.maxRetries = 3;\r\n\r\n        this._rawInputTracker = new LastSuccessTracker();\r\n        this._rawInputTracker.startTracking(this, this._stropheConn);\r\n\r\n        this._resumeTask = new ResumeTask(this._stropheConn);\r\n\r\n        /**\r\n         * @typedef DeferredSendIQ Object\r\n         * @property {Element} iq - The IQ to send.\r\n         * @property {function} resolve - The resolve method of the deferred Promise.\r\n         * @property {function} reject - The reject method of the deferred Promise.\r\n         * @property {number} timeout - The ID of the timeout task that needs to be cleared, before sending the IQ.\r\n         */\r\n        /**\r\n         * Deferred IQs to be sent upon reconnect.\r\n         * @type {Array<DeferredSendIQ>}\r\n         * @private\r\n         */\r\n        this._deferredIQs = [];\r\n\r\n        // Ping plugin is mandatory for the Websocket mode to work correctly. It's used to detect when the connection\r\n        // is broken (WebSocket/TCP connection not closed gracefully).\r\n        this.addConnectionPlugin(\r\n            'ping',\r\n            new PingConnectionPlugin({\r\n                getTimeSinceLastServerResponse: () => this.getTimeSinceLastSuccess(),\r\n                onPingThresholdExceeded: () => this._onPingErrorThresholdExceeded(),\r\n                pingOptions: xmppPing\r\n            }));\r\n\r\n        // tracks whether this is the initial connection or a reconnect\r\n        this._oneSuccessfulConnect = false;\r\n    }\r\n\r\n    /**\r\n     * A getter for the connected state.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    get connected() {\r\n        const websocket = this._stropheConn && this._stropheConn._proto && this._stropheConn._proto.socket;\r\n\r\n        return (this._status === Strophe.Status.CONNECTED || this._status === Strophe.Status.ATTACHED)\r\n            && (!this.isUsingWebSocket || (websocket && websocket.readyState === WebSocket.OPEN));\r\n    }\r\n\r\n    /**\r\n     * Retrieves the feature discovery plugin instance.\r\n     *\r\n     * @returns {Strophe.Connection.disco}\r\n     */\r\n    get disco() {\r\n        return this._stropheConn.disco;\r\n    }\r\n\r\n    /**\r\n     * A getter for the disconnecting state.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    get disconnecting() {\r\n        return this._stropheConn.disconnecting === true;\r\n    }\r\n\r\n    /**\r\n     * A getter for the domain.\r\n     *\r\n     * @returns {string|null}\r\n     */\r\n    get domain() {\r\n        return this._stropheConn.domain;\r\n    }\r\n\r\n    /**\r\n     * Tells if Websocket is used as the transport for the current XMPP connection. Returns true for Websocket or false\r\n     * for BOSH.\r\n     * @returns {boolean}\r\n     */\r\n    get isUsingWebSocket() {\r\n        return this._usesWebsocket;\r\n    }\r\n\r\n    /**\r\n     * A getter for the JID.\r\n     *\r\n     * @returns {string|null}\r\n     */\r\n    get jid() {\r\n        return this._stropheConn.jid;\r\n    }\r\n\r\n    /**\r\n     * Returns headers for the last BOSH response received.\r\n     *\r\n     * @returns {string}\r\n     */\r\n    get lastResponseHeaders() {\r\n        return this._stropheConn._proto && this._stropheConn._proto.lastResponseHeaders;\r\n    }\r\n\r\n    /**\r\n     * A getter for the logger plugin instance.\r\n     *\r\n     * @returns {*}\r\n     */\r\n    get logger() {\r\n        return this._stropheConn.logger;\r\n    }\r\n\r\n    /**\r\n     * A getter for the connection options.\r\n     *\r\n     * @returns {*}\r\n     */\r\n    get options() {\r\n        return this._stropheConn.options;\r\n    }\r\n\r\n    /**\r\n     * A getter for the domain to be used for ping.\r\n     */\r\n    get pingDomain() {\r\n        return this._options.pingOptions?.domain || this.domain;\r\n    }\r\n\r\n    /**\r\n     * A getter for the service URL.\r\n     *\r\n     * @returns {string}\r\n     */\r\n    get service() {\r\n        return this._stropheConn.service;\r\n    }\r\n\r\n    /**\r\n     * Sets new value for shard.\r\n     * @param value the new shard value.\r\n     */\r\n    set shard(value) {\r\n        this._options.shard = value;\r\n\r\n        // shard setting changed so let's schedule a new keep-alive check if connected\r\n        if (this._oneSuccessfulConnect) {\r\n            this._maybeStartWSKeepAlive();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns the current connection status.\r\n     *\r\n     * @returns {Strophe.Status}\r\n     */\r\n    get status() {\r\n        return this._status;\r\n    }\r\n\r\n    /**\r\n     * Adds a connection plugin to this instance.\r\n     *\r\n     * @param {string} name - The name of the plugin or rather a key under which it will be stored on this connection\r\n     * instance.\r\n     * @param {ConnectionPluginListenable} plugin - The plugin to add.\r\n     */\r\n    addConnectionPlugin(name, plugin) {\r\n        this[name] = plugin;\r\n        plugin.init(this);\r\n    }\r\n\r\n    /**\r\n     * See {@link Strophe.Connection.addHandler}\r\n     *\r\n     * @returns {void}\r\n     */\r\n    addHandler(...args) {\r\n        this._stropheConn.addHandler(...args);\r\n    }\r\n\r\n    /* eslint-disable max-params */\r\n    /**\r\n     * Wraps {@link Strophe.Connection.attach} method in order to intercept the connection status updates.\r\n     * See {@link Strophe.Connection.attach} for the params description.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    attach(jid, sid, rid, callback, ...args) {\r\n        this._stropheConn.attach(jid, sid, rid, this._stropheConnectionCb.bind(this, callback), ...args);\r\n    }\r\n\r\n    /**\r\n     * Wraps Strophe.Connection.connect method in order to intercept the connection status updates.\r\n     * See {@link Strophe.Connection.connect} for the params description.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    connect(jid, pass, callback, ...args) {\r\n        this._stropheConn.connect(jid, pass, this._stropheConnectionCb.bind(this, callback), ...args);\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * Handles {@link Strophe.Status} updates for the current connection.\r\n     *\r\n     * @param {function} targetCallback - The callback passed by the {@link XmppConnection} consumer to one of\r\n     * the connect methods.\r\n     * @param {Strophe.Status} status - The new connection status.\r\n     * @param {*} args - The rest of the arguments passed by Strophe.\r\n     * @private\r\n     */\r\n    _stropheConnectionCb(targetCallback, status, ...args) {\r\n        this._status = status;\r\n\r\n        let blockCallback = false;\r\n\r\n        if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {\r\n            this._maybeEnableStreamResume();\r\n\r\n            // after connecting - immediately check whether shard changed,\r\n            // we need this only when using websockets as bosh checks headers from every response\r\n            if (this._usesWebsocket && this._oneSuccessfulConnect) {\r\n                this._keepAliveAndCheckShard();\r\n            }\r\n            this._oneSuccessfulConnect = true;\r\n\r\n            this._maybeStartWSKeepAlive();\r\n            this._processDeferredIQs();\r\n            this._resumeTask.cancel();\r\n            this.ping.startInterval(this._options.pingOptions?.domain || this.domain);\r\n        } else if (status === Strophe.Status.DISCONNECTED) {\r\n            this.ping.stopInterval();\r\n\r\n            // FIXME add RECONNECTING state instead of blocking the DISCONNECTED update\r\n            blockCallback = this._tryResumingConnection();\r\n            if (!blockCallback) {\r\n                clearTimeout(this._wsKeepAlive);\r\n            }\r\n        }\r\n\r\n        if (!blockCallback) {\r\n            targetCallback(status, ...args);\r\n            this.eventEmitter.emit(XmppConnection.Events.CONN_STATUS_CHANGED, status);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Clears the list of IQs and rejects deferred Promises with an error.\r\n     *\r\n     * @private\r\n     */\r\n    _clearDeferredIQs() {\r\n        for (const deferred of this._deferredIQs) {\r\n            deferred.reject(new Error('disconnect'));\r\n        }\r\n        this._deferredIQs = [];\r\n    }\r\n\r\n    /**\r\n     * The method is meant to be used for testing. It's a shortcut for closing the WebSocket.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    closeWebsocket() {\r\n        if (this._stropheConn && this._stropheConn._proto) {\r\n            this._stropheConn._proto._closeSocket();\r\n            this._stropheConn._proto._onClose(null);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * See {@link Strophe.Connection.disconnect}.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    disconnect(...args) {\r\n        this._resumeTask.cancel();\r\n        clearTimeout(this._wsKeepAlive);\r\n        this._clearDeferredIQs();\r\n        this._stropheConn.disconnect(...args);\r\n    }\r\n\r\n    /**\r\n     * See {@link Strophe.Connection.flush}.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    flush(...args) {\r\n        this._stropheConn.flush(...args);\r\n    }\r\n\r\n    /**\r\n     * See {@link LastRequestTracker.getTimeSinceLastSuccess}.\r\n     *\r\n     * @returns {number|null}\r\n     */\r\n    getTimeSinceLastSuccess() {\r\n        return this._rawInputTracker.getTimeSinceLastSuccess();\r\n    }\r\n\r\n    /**\r\n     * See {@link LastRequestTracker.getLastFailedMessage}.\r\n     *\r\n     * @returns {string|null}\r\n     */\r\n    getLastFailedMessage() {\r\n        return this._rawInputTracker.getLastFailedMessage();\r\n    }\r\n\r\n    /**\r\n     * Requests a resume token from the server if enabled and all requirements are met.\r\n     *\r\n     * @private\r\n     */\r\n    _maybeEnableStreamResume() {\r\n        if (!this._options.enableWebsocketResume) {\r\n\r\n            return;\r\n        }\r\n\r\n        const { streamManagement } = this._stropheConn;\r\n\r\n        if (!this.isUsingWebSocket) {\r\n            logger.warn('Stream resume enabled, but WebSockets are not enabled');\r\n        } else if (!streamManagement) {\r\n            logger.warn('Stream resume enabled, but Strophe streamManagement plugin is not installed');\r\n        } else if (!streamManagement.isSupported()) {\r\n            logger.warn('Stream resume enabled, but XEP-0198 is not supported by the server');\r\n        } else if (!streamManagement.getResumeToken()) {\r\n            logger.info('Enabling XEP-0198 stream management');\r\n            streamManagement.enable(/* resume */ true);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Starts the Websocket keep alive if enabled.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _maybeStartWSKeepAlive() {\r\n        const { websocketKeepAlive } = this._options;\r\n\r\n        if (this._usesWebsocket && websocketKeepAlive > 0) {\r\n            this._wsKeepAlive || logger.info(`WebSocket keep alive interval: ${websocketKeepAlive}ms`);\r\n            clearTimeout(this._wsKeepAlive);\r\n\r\n            const intervalWithJitter = /* base */ websocketKeepAlive + /* jitter */ (Math.random() * 60 * 1000);\r\n\r\n            logger.debug(`Scheduling next WebSocket keep-alive in ${intervalWithJitter}ms`);\r\n\r\n            this._wsKeepAlive = setTimeout(\r\n                () => this._keepAliveAndCheckShard()\r\n                    .then(() => this._maybeStartWSKeepAlive()),\r\n                intervalWithJitter);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Do a http GET to the shard and if shard change will throw an event.\r\n     *\r\n     * @private\r\n     * @returns {Promise}\r\n     */\r\n    _keepAliveAndCheckShard() {\r\n        const { shard, websocketKeepAliveUrl } = this._options;\r\n        const url = websocketKeepAliveUrl ? websocketKeepAliveUrl\r\n            : this.service.replace('wss://', 'https://').replace('ws://', 'http://');\r\n\r\n        return fetch(url)\r\n            .then(response => {\r\n\r\n                // skips header checking if there is no info in options\r\n                if (!shard) {\r\n                    return;\r\n                }\r\n\r\n                const responseShard = response.headers.get('x-jitsi-shard');\r\n\r\n                if (responseShard !== shard) {\r\n                    logger.error(\r\n                        `Detected that shard changed from ${shard} to ${responseShard}`);\r\n                    this.eventEmitter.emit(XmppConnection.Events.CONN_SHARD_CHANGED);\r\n                }\r\n            })\r\n            .catch(error => {\r\n                logger.error(`Websocket Keep alive failed for url: ${url}`, { error });\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Goes over the list of {@link DeferredSendIQ} tasks and sends them.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _processDeferredIQs() {\r\n        for (const deferred of this._deferredIQs) {\r\n            if (deferred.iq) {\r\n                clearTimeout(deferred.timeout);\r\n\r\n                const timeLeft = Date.now() - deferred.start;\r\n\r\n                this.sendIQ(\r\n                    deferred.iq,\r\n                    result => deferred.resolve(result),\r\n                    error => deferred.reject(error),\r\n                    timeLeft);\r\n            }\r\n        }\r\n\r\n        this._deferredIQs = [];\r\n    }\r\n\r\n    /**\r\n     * Send a stanza. This function is called to push data onto the send queue to go out over the wire.\r\n     *\r\n     * @param {Element|Strophe.Builder} stanza - The stanza to send.\r\n     * @returns {void}\r\n     */\r\n    send(stanza) {\r\n        if (!this.connected) {\r\n            throw new Error('Not connected');\r\n        }\r\n        this._stropheConn.send(stanza);\r\n    }\r\n\r\n    /**\r\n     * Helper function to send IQ stanzas.\r\n     *\r\n     * @param {Element} elem - The stanza to send.\r\n     * @param {Function} callback - The callback function for a successful request.\r\n     * @param {Function} errback - The callback function for a failed or timed out request.  On timeout, the stanza will\r\n     * be null.\r\n     * @param {number} timeout - The time specified in milliseconds for a timeout to occur.\r\n     * @returns {number} - The id used to send the IQ.\r\n     */\r\n    sendIQ(elem, callback, errback, timeout) {\r\n        if (!this.connected) {\r\n            errback('Not connected');\r\n\r\n            return;\r\n        }\r\n\r\n        return this._stropheConn.sendIQ(elem, callback, errback, timeout);\r\n    }\r\n\r\n    /**\r\n     * Sends an IQ immediately if connected or puts it on the send queue otherwise(in contrary to other send methods\r\n     * which would fail immediately if disconnected).\r\n     *\r\n     * @param {Element} iq - The IQ to send.\r\n     * @param {number} timeout - How long to wait for the response. The time when the connection is reconnecting is\r\n     * included, which means that the IQ may never be sent and still fail with a timeout.\r\n     */\r\n    sendIQ2(iq, { timeout }) {\r\n        return new Promise((resolve, reject) => {\r\n            if (this.connected) {\r\n                this.sendIQ(\r\n                    iq,\r\n                    result => resolve(result),\r\n                    error => reject(error),\r\n                    timeout);\r\n            } else {\r\n                const deferred = {\r\n                    iq,\r\n                    resolve,\r\n                    reject,\r\n                    start: Date.now(),\r\n                    timeout: setTimeout(() => {\r\n                        // clears the IQ on timeout and invalidates the deferred task\r\n                        deferred.iq = undefined;\r\n\r\n                        // Strophe calls with undefined on timeout\r\n                        reject(undefined);\r\n                    }, timeout)\r\n                };\r\n\r\n                this._deferredIQs.push(deferred);\r\n            }\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Called by the ping plugin when ping fails too many times.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    _onPingErrorThresholdExceeded() {\r\n        if (this.isUsingWebSocket) {\r\n            logger.warn('Ping error threshold exceeded - killing the WebSocket');\r\n            this.closeWebsocket();\r\n        }\r\n    }\r\n\r\n    /**\r\n     *  Helper function to send presence stanzas. The main benefit is for sending presence stanzas for which you expect\r\n     *  a responding presence stanza with the same id (for example when leaving a chat room).\r\n     *\r\n     * @param {Element} elem - The stanza to send.\r\n     * @param {Function} callback - The callback function for a successful request.\r\n     * @param {Function} errback - The callback function for a failed or timed out request. On timeout, the stanza will\r\n     * be null.\r\n     * @param {number} timeout - The time specified in milliseconds for a timeout to occur.\r\n     * @returns {number} - The id used to send the presence.\r\n     */\r\n    sendPresence(elem, callback, errback, timeout) {\r\n        if (!this.connected) {\r\n            errback('Not connected');\r\n\r\n            return;\r\n        }\r\n        this._stropheConn.sendPresence(elem, callback, errback, timeout);\r\n    }\r\n\r\n    /**\r\n     * The method gracefully closes the BOSH connection by using 'navigator.sendBeacon'.\r\n     *\r\n     * @returns {boolean} - true if the beacon was sent.\r\n     */\r\n    sendUnavailableBeacon() {\r\n        if (!navigator.sendBeacon || this._stropheConn.disconnecting || !this._stropheConn.connected) {\r\n            return false;\r\n        }\r\n\r\n        this._stropheConn._changeConnectStatus(Strophe.Status.DISCONNECTING);\r\n        this._stropheConn.disconnecting = true;\r\n\r\n        const body = this._stropheConn._proto._buildBody()\r\n            .attrs({\r\n                type: 'terminate'\r\n            });\r\n        const pres = $pres({\r\n            xmlns: Strophe.NS.CLIENT,\r\n            type: 'unavailable'\r\n        });\r\n\r\n        body.cnode(pres.tree());\r\n\r\n        const res = navigator.sendBeacon(\r\n            this.service.indexOf('https://') === -1 ? `https:${this.service}` : this.service,\r\n            Strophe.serialize(body.tree()));\r\n\r\n        logger.info(`Successfully send unavailable beacon ${res}`);\r\n\r\n        this._stropheConn._proto._abortAllRequests();\r\n        this._stropheConn._doDisconnect();\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * Tries to use stream management plugin to resume dropped XMPP connection. The streamManagement plugin clears\r\n     * the resume token if any connection error occurs which would put it in unrecoverable state, so as long as\r\n     * the token is present it means the connection can be resumed.\r\n     *\r\n     * @private\r\n     * @returns {boolean}\r\n     */\r\n    _tryResumingConnection() {\r\n        const { streamManagement } = this._stropheConn;\r\n        const resumeToken = streamManagement && streamManagement.getResumeToken();\r\n\r\n        if (resumeToken) {\r\n            this._resumeTask.schedule();\r\n\r\n            return true;\r\n        }\r\n\r\n        return false;\r\n    }\r\n}\r\n","export enum JitsiTranscriptionStatus {\r\n    /**\r\n     * The transcription is on.\r\n     */\r\n    ON = 'on',\r\n\r\n    /**\r\n     * The transcription is off.\r\n     */\r\n    OFF = 'off'\r\n}\r\n\r\n// exported for backward compatibility\r\nexport const ON = JitsiTranscriptionStatus.ON;\r\nexport const OFF = JitsiTranscriptionStatus.OFF;\r\n","import { getLogger } from '@jitsi/logger';\r\nimport { $msg } from 'strophe.js';\r\n\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * The AVModeration logic.\r\n */\r\nexport default class AVModeration {\r\n\r\n    /**\r\n     * Constructs AV moderation room.\r\n     *\r\n     * @param {ChatRoom} room the main room.\r\n     */\r\n    constructor(room) {\r\n        this._xmpp = room.xmpp;\r\n\r\n        this._mainRoom = room;\r\n\r\n        this._moderationEnabledByType = {\r\n            [MediaType.AUDIO]: false,\r\n            [MediaType.VIDEO]: false\r\n        };\r\n\r\n        this._whitelistAudio = [];\r\n        this._whitelistVideo = [];\r\n\r\n        this._onMessage = this._onMessage.bind(this);\r\n        this._xmpp.addListener(XMPPEvents.AV_MODERATION_RECEIVED, this._onMessage);\r\n    }\r\n\r\n    /**\r\n     * Stops listening for events.\r\n     */\r\n    dispose() {\r\n        this._xmpp.removeListener(XMPPEvents.AV_MODERATION_RECEIVED, this._onMessage);\r\n    }\r\n\r\n    /**\r\n     * Whether AV moderation is supported on backend.\r\n     *\r\n     * @returns {boolean} whether AV moderation is supported on backend.\r\n     */\r\n    isSupported() {\r\n        return Boolean(this._xmpp.avModerationComponentAddress);\r\n    }\r\n\r\n    /**\r\n     * Enables or disables AV Moderation by sending a msg with command to the component.\r\n     */\r\n    enable(state, mediaType) {\r\n        if (!this.isSupported() || !this._mainRoom.isModerator()) {\r\n            logger.error(`Cannot enable:${state} AV moderation supported:${this.isSupported()},\r\n                moderator:${this._mainRoom.isModerator()}`);\r\n\r\n            return;\r\n        }\r\n\r\n        if (state === this._moderationEnabledByType[mediaType]) {\r\n            logger.warn(`Moderation already in state:${state} for mediaType:${mediaType}`);\r\n\r\n            return;\r\n        }\r\n\r\n        // send the enable/disable message\r\n        const msg = $msg({ to: this._xmpp.avModerationComponentAddress });\r\n\r\n        msg.c('av_moderation', {\r\n            enable: state,\r\n            mediaType\r\n        }).up();\r\n\r\n        this._xmpp.connection.send(msg);\r\n    }\r\n\r\n    /**\r\n     * Approves that a participant can unmute by sending a msg with its jid to the component.\r\n     */\r\n    approve(mediaType, jid) {\r\n        if (!this.isSupported() || !this._mainRoom.isModerator()) {\r\n            logger.error(`Cannot approve in AV moderation supported:${this.isSupported()},\r\n                moderator:${this._mainRoom.isModerator()}`);\r\n\r\n            return;\r\n        }\r\n\r\n        // send a message to whitelist the jid and approve it to unmute\r\n        const msg = $msg({ to: this._xmpp.avModerationComponentAddress });\r\n\r\n        msg.c('av_moderation', {\r\n            mediaType,\r\n            jidToWhitelist: jid }).up();\r\n\r\n        this._xmpp.connection.send(msg);\r\n    }\r\n\r\n    /**\r\n     * Rejects that a participant can unmute by sending a msg with its jid to the component.\r\n     */\r\n    reject(mediaType, jid) {\r\n        if (!this.isSupported() || !this._mainRoom.isModerator()) {\r\n            logger.error(`Cannot reject in AV moderation supported:${this.isSupported()},\r\n                moderator:${this._mainRoom.isModerator()}`);\r\n\r\n            return;\r\n        }\r\n\r\n        // send a message to remove from whitelist the jid and reject it to unmute\r\n        const msg = $msg({ to: this._xmpp.avModerationComponentAddress });\r\n\r\n        msg.c('av_moderation', {\r\n            mediaType,\r\n            jidToBlacklist: jid\r\n        }).up();\r\n\r\n        this._xmpp.connection.send(msg);\r\n    }\r\n\r\n    /**\r\n     * Receives av_moderation parsed messages as json.\r\n     * @param obj the parsed json content of the message to process.\r\n     * @private\r\n     */\r\n    _onMessage(obj) {\r\n        const { removed, mediaType: media, enabled, approved, actor, whitelists: newWhitelists } = obj;\r\n\r\n        if (newWhitelists) {\r\n            const oldList = media === MediaType.AUDIO\r\n                ? this._whitelistAudio\r\n                : this._whitelistVideo;\r\n            const newList = Array.isArray(newWhitelists[media]) ? newWhitelists[media] : [];\r\n\r\n            if (removed) {\r\n                oldList.filter(x => !newList.includes(x))\r\n                    .forEach(jid => this._xmpp.eventEmitter\r\n                        .emit(XMPPEvents.AV_MODERATION_PARTICIPANT_REJECTED, media, jid));\r\n            } else {\r\n                newList.filter(x => !oldList.includes(x))\r\n                    .forEach(jid => this._xmpp.eventEmitter\r\n                        .emit(XMPPEvents.AV_MODERATION_PARTICIPANT_APPROVED, media, jid));\r\n            }\r\n\r\n            if (media === MediaType.AUDIO) {\r\n                this._whitelistAudio = newList;\r\n            } else {\r\n                this._whitelistVideo = newList;\r\n            }\r\n        } else if (enabled !== undefined && this._moderationEnabledByType[media] !== enabled) {\r\n            this._moderationEnabledByType[media] = enabled;\r\n\r\n            this._xmpp.eventEmitter.emit(XMPPEvents.AV_MODERATION_CHANGED, enabled, media, actor);\r\n        } else if (removed) {\r\n            this._xmpp.eventEmitter.emit(XMPPEvents.AV_MODERATION_REJECTED, media);\r\n        } else if (approved) {\r\n            this._xmpp.eventEmitter.emit(XMPPEvents.AV_MODERATION_APPROVED, media);\r\n        }\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport { $msg, Strophe } from 'strophe.js';\r\n\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\n\r\nconst FEATURE_KEY = 'features/breakout-rooms';\r\nconst BREAKOUT_ROOM_ACTIONS = {\r\n    ADD: `${FEATURE_KEY}/add`,\r\n    REMOVE: `${FEATURE_KEY}/remove`,\r\n    MOVE_TO_ROOM: `${FEATURE_KEY}/move-to-room`\r\n};\r\nconst BREAKOUT_ROOM_EVENTS = {\r\n    MOVE_TO_ROOM: `${FEATURE_KEY}/move-to-room`,\r\n    UPDATE: `${FEATURE_KEY}/update`\r\n};\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Helper class for handling breakout rooms.\r\n */\r\nexport default class BreakoutRooms {\r\n\r\n    /**\r\n     * Constructs lobby room.\r\n     *\r\n     * @param {ChatRoom} room the room we are in.\r\n     */\r\n    constructor(room) {\r\n        this.room = room;\r\n\r\n        this._handleMessages = this._handleMessages.bind(this);\r\n        this.room.xmpp.addListener(XMPPEvents.BREAKOUT_ROOMS_EVENT, this._handleMessages);\r\n\r\n        this._rooms = {};\r\n    }\r\n\r\n    /**\r\n     * Stops listening for events.\r\n     */\r\n    dispose() {\r\n        this.room.xmpp.removeListener(XMPPEvents.BREAKOUT_ROOMS_EVENT, this._handleMessages);\r\n    }\r\n\r\n    /**\r\n     * Creates a breakout room with the given subject.\r\n     *\r\n     * @param {string} subject - A subject for the breakout room.\r\n     */\r\n    createBreakoutRoom(subject) {\r\n        if (!this.isSupported() || !this.room.isModerator()) {\r\n            logger.error(`Cannot create breakout room - supported:${this.isSupported()},\r\n                moderator:${this.room.isModerator()}`);\r\n\r\n            return;\r\n        }\r\n\r\n        const message = {\r\n            type: BREAKOUT_ROOM_ACTIONS.ADD,\r\n            subject\r\n        };\r\n\r\n        this._sendMessage(message);\r\n    }\r\n\r\n    /**\r\n     * Removes a breakout room.\r\n     *\r\n     * @param {string} breakoutRoomJid - JID of the room to be removed.\r\n     */\r\n    removeBreakoutRoom(breakoutRoomJid) {\r\n        if (!this.isSupported() || !this.room.isModerator()) {\r\n            logger.error(`Cannot remove breakout room - supported:${this.isSupported()},\r\n                moderator:${this.room.isModerator()}`);\r\n\r\n            return;\r\n        }\r\n\r\n        const message = {\r\n            type: BREAKOUT_ROOM_ACTIONS.REMOVE,\r\n            breakoutRoomJid\r\n        };\r\n\r\n        this._sendMessage(message);\r\n    }\r\n\r\n    /**\r\n     * Sends the given participant to the given room.\r\n     *\r\n     * @param {string} participantJid - JID of the participant to be sent to a room.\r\n     * @param {string} roomJid - JID of the target room.\r\n     */\r\n    sendParticipantToRoom(participantJid, roomJid) {\r\n        if (!this.isSupported() || !this.room.isModerator()) {\r\n            logger.error(`Cannot send participant to room - supported:${this.isSupported()},\r\n                moderator:${this.room.isModerator()}`);\r\n\r\n            return;\r\n        }\r\n\r\n        const message = {\r\n            type: BREAKOUT_ROOM_ACTIONS.MOVE_TO_ROOM,\r\n            participantJid,\r\n            roomJid\r\n        };\r\n\r\n        this._sendMessage(message);\r\n    }\r\n\r\n    /**\r\n     * Whether Breakout Rooms support is enabled in the backend or not.\r\n     */\r\n    isSupported() {\r\n        return Boolean(this.getComponentAddress());\r\n    }\r\n\r\n    /**\r\n     * Gets the address of the Breakout Rooms XMPP component.\r\n     *\r\n     * @returns The address of the component.\r\n     */\r\n    getComponentAddress() {\r\n        return this.room.xmpp.breakoutRoomsComponentAddress;\r\n    }\r\n\r\n    /**\r\n     * Stores if the current room is a breakout room.\r\n     *\r\n     * @param {boolean} isBreakoutRoom - Whether this room is a breakout room.\r\n     */\r\n    _setIsBreakoutRoom(isBreakoutRoom) {\r\n        this._isBreakoutRoom = isBreakoutRoom;\r\n    }\r\n\r\n    /**\r\n     * Checks whether this room is a breakout room.\r\n     *\r\n     * @returns True if the room is a breakout room, false otherwise.\r\n     */\r\n    isBreakoutRoom() {\r\n        if (typeof this._isBreakoutRoom !== 'undefined') {\r\n            return this._isBreakoutRoom;\r\n        }\r\n\r\n        // Use heuristic, helpful for checking in the MUC_JOINED event.\r\n        return Strophe.getDomainFromJid(this.room.myroomjid) === this.getComponentAddress();\r\n    }\r\n\r\n    /**\r\n     * Sets the main room JID associated with this breakout room. Only applies when\r\n     * in a breakout room.\r\n     *\r\n     * @param {string} jid - The main room JID.\r\n     */\r\n    _setMainRoomJid(jid) {\r\n        this._mainRoomJid = jid;\r\n    }\r\n\r\n    /**\r\n     * Gets the main room's JID associated with this breakout room.\r\n     *\r\n     * @returns The main room JID.\r\n     */\r\n    getMainRoomJid() {\r\n        return this._mainRoomJid;\r\n    }\r\n\r\n    /**\r\n     * Handles a message for managing breakout rooms.\r\n     *\r\n     * @param {object} payload - Arbitrary data.\r\n     */\r\n    _handleMessages(payload) {\r\n        switch (payload.event) {\r\n        case BREAKOUT_ROOM_EVENTS.MOVE_TO_ROOM:\r\n            this.room.eventEmitter.emit(XMPPEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM, payload.roomJid);\r\n            break;\r\n        case BREAKOUT_ROOM_EVENTS.UPDATE: {\r\n            const filteredPayload = this._filterUpdatePayload(payload);\r\n\r\n            this._rooms = filteredPayload.rooms;\r\n            this.room.eventEmitter.emit(XMPPEvents.BREAKOUT_ROOMS_UPDATED, filteredPayload);\r\n            break;\r\n        }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Filters the hidden participants from the payload.\r\n     *\r\n     * @param {Object} payload - The payload of the update message.\r\n     * @return {Object} - The filtered payload.\r\n     */\r\n    _filterUpdatePayload(payload) {\r\n        const hiddenDomain = this.room.options.hiddenDomain;\r\n        const { rooms } = payload;\r\n        const filteredRooms = {};\r\n\r\n        Object.entries(rooms).forEach(([ key, room ]) => {\r\n            const { participants = {} } = room;\r\n            const filteredParticipants = {};\r\n\r\n            Object.entries(participants).forEach(([ k, participant ]) => {\r\n                if (Strophe.getDomainFromJid(participant.jid) !== hiddenDomain) {\r\n                    filteredParticipants[k] = participant;\r\n                }\r\n            });\r\n\r\n            filteredRooms[key] = {\r\n                ...room,\r\n                participants: filteredParticipants\r\n            };\r\n        });\r\n\r\n        return {\r\n            ...payload,\r\n            rooms: filteredRooms\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Helper to send a breakout rooms message to the component.\r\n     *\r\n     * @param {Object} message - Command that needs to be sent.\r\n     */\r\n    _sendMessage(message) {\r\n        const msg = $msg({ to: this.getComponentAddress() });\r\n\r\n        msg.c('breakout_rooms', message).up();\r\n\r\n        this.room.xmpp.connection.send(msg);\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport { $msg, Strophe } from 'strophe.js';\r\n\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * The command type for updating a lobby participant's e-mail address.\r\n *\r\n * @type {string}\r\n */\r\nconst EMAIL_COMMAND = 'email';\r\n\r\n/**\r\n * The Lobby room implementation. Setting a room to members only, joining the lobby room\r\n * approving or denying access to participants from the lobby room.\r\n */\r\nexport default class Lobby {\r\n\r\n    /**\r\n     * Constructs lobby room.\r\n     *\r\n     * @param {ChatRoom} room the main room.\r\n     */\r\n    constructor(room) {\r\n        this.xmpp = room.xmpp;\r\n        this.mainRoom = room;\r\n\r\n        const maybeJoinLobbyRoom = this._maybeJoinLobbyRoom.bind(this);\r\n\r\n        this.mainRoom.addEventListener(\r\n            XMPPEvents.LOCAL_ROLE_CHANGED,\r\n            maybeJoinLobbyRoom);\r\n\r\n        this.mainRoom.addEventListener(\r\n            XMPPEvents.MUC_MEMBERS_ONLY_CHANGED,\r\n            maybeJoinLobbyRoom);\r\n\r\n        this.mainRoom.addEventListener(\r\n            XMPPEvents.ROOM_CONNECT_MEMBERS_ONLY_ERROR,\r\n            jid => {\r\n                this.lobbyRoomJid = jid;\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Whether lobby is supported on backend.\r\n     *\r\n     * @returns {boolean} whether lobby is supported on backend.\r\n     */\r\n    isSupported() {\r\n        return this.xmpp.lobbySupported;\r\n    }\r\n\r\n    /**\r\n     * Enables lobby by setting the main room to be members only and joins the lobby chat room.\r\n     *\r\n     * @returns {Promise}\r\n     */\r\n    enable() {\r\n        if (!this.isSupported()) {\r\n            return Promise.reject(new Error('Lobby not supported!'));\r\n        }\r\n\r\n        return new Promise((resolve, reject) => {\r\n            this.mainRoom.setMembersOnly(true, resolve, reject);\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Disable lobby by setting the main room to be non members only and levaes the lobby chat room if joined.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    disable() {\r\n        if (!this.isSupported() || !this.mainRoom.isModerator()\r\n                || !this.lobbyRoom || !this.mainRoom.membersOnlyEnabled) {\r\n            return;\r\n        }\r\n\r\n        this.mainRoom.setMembersOnly(false);\r\n    }\r\n\r\n    /**\r\n     * Broadcast a message to all participants in the lobby room\r\n     * @param {Object} message The message to send\r\n     *\r\n     * @returns {void}\r\n     */\r\n    sendMessage(message) {\r\n        if (this.lobbyRoom) {\r\n            this.lobbyRoom.sendMessage(JSON.stringify(message), 'json-message');\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sends a private message to a participant in a lobby room.\r\n     * @param {string} id The message to send\r\n     * @param {Object} message The message to send\r\n     *\r\n     * @returns {void}\r\n     */\r\n    sendPrivateMessage(id, message) {\r\n        if (this.lobbyRoom) {\r\n            this.lobbyRoom.sendPrivateMessage(id, JSON.stringify(message), 'json-message');\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Gets the local id for a participant in a lobby room.\r\n     * This is used for lobby room private chat messages.\r\n     *\r\n     * @returns {string}\r\n     */\r\n    getLocalId() {\r\n        if (this.lobbyRoom) {\r\n            return Strophe.getResourceFromJid(this.lobbyRoom.myroomjid);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Adds a message listener to the lobby room.\r\n     * @param {Function} listener The listener function,\r\n     * called when a new message is received in the lobby room.\r\n     *\r\n     * @returns {Function} Handler returned to be able to remove it later.\r\n     */\r\n    addMessageListener(listener) {\r\n        if (this.lobbyRoom) {\r\n            const handler = (participantId, message) => {\r\n                listener(message, Strophe.getResourceFromJid(participantId));\r\n            };\r\n\r\n            this.lobbyRoom.on(XMPPEvents.JSON_MESSAGE_RECEIVED, handler);\r\n\r\n            return handler;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Remove a message handler from the lobby room.\r\n     * @param {Function} handler The handler function to remove.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    removeMessageHandler(handler) {\r\n        if (this.lobbyRoom) {\r\n            this.lobbyRoom.off(XMPPEvents.JSON_MESSAGE_RECEIVED, handler);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Leaves the lobby room.\r\n     *\r\n     * @returns {Promise}\r\n     */\r\n    leave() {\r\n        if (this.lobbyRoom) {\r\n            return this.lobbyRoom.leave()\r\n                .then(() => {\r\n                    this.lobbyRoom = undefined;\r\n                    logger.info('Lobby room left!');\r\n                })\r\n                .catch(() => {}); // eslint-disable-line no-empty-function\r\n        }\r\n\r\n        return Promise.reject(\r\n                new Error('The lobby has already been left'));\r\n    }\r\n\r\n    /**\r\n     * We had received a jid for the lobby room.\r\n     *\r\n     * @param jid the lobby room jid to join.\r\n     */\r\n    setLobbyRoomJid(jid) {\r\n        this.lobbyRoomJid = jid;\r\n    }\r\n\r\n    /**\r\n     * Checks the state of mainRoom, lobbyRoom and current user role to decide whether to join lobby room.\r\n     * @private\r\n     */\r\n    _maybeJoinLobbyRoom() {\r\n        if (!this.isSupported()) {\r\n            return;\r\n        }\r\n\r\n        const isModerator = this.mainRoom.joined && this.mainRoom.isModerator();\r\n\r\n        if (isModerator && this.mainRoom.membersOnlyEnabled && !this.lobbyRoom) {\r\n            // join the lobby\r\n            this.join()\r\n                .then(() => logger.info('Joined lobby room'))\r\n                .catch(e => logger.error('Failed joining lobby', e));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Joins a lobby room setting display name and eventually avatar(using the email provided).\r\n     *\r\n     * @param {string} username is required.\r\n     * @param {string} email is optional.\r\n     * @returns {Promise} resolves once we join the room.\r\n     */\r\n    join(displayName, email) {\r\n        const isModerator = this.mainRoom.joined && this.mainRoom.isModerator();\r\n\r\n        if (!this.lobbyRoomJid) {\r\n            return Promise.reject(new Error('Missing lobbyRoomJid, cannot join lobby room.'));\r\n        }\r\n\r\n        const roomName = Strophe.getNodeFromJid(this.lobbyRoomJid);\r\n        const customDomain = Strophe.getDomainFromJid(this.lobbyRoomJid);\r\n\r\n        this.lobbyRoom = this.xmpp.createRoom(\r\n            roomName, {\r\n                customDomain,\r\n                disableDiscoInfo: true,\r\n                disableFocus: true,\r\n                enableLobby: false\r\n            }\r\n        );\r\n\r\n        if (displayName) {\r\n            // remove previously set nickname\r\n            this.lobbyRoom.addOrReplaceInPresence('nick', {\r\n                attributes: { xmlns: 'http://jabber.org/protocol/nick' },\r\n                value: displayName\r\n            });\r\n        }\r\n\r\n        if (isModerator) {\r\n            this.lobbyRoom.addPresenceListener(EMAIL_COMMAND, (node, from) => {\r\n                this.mainRoom.eventEmitter.emit(XMPPEvents.MUC_LOBBY_MEMBER_UPDATED, from, { email: node.value });\r\n            });\r\n            this.lobbyRoom.addEventListener(\r\n                XMPPEvents.MUC_MEMBER_JOINED,\r\n                // eslint-disable-next-line max-params\r\n                (from, nick, role, isHiddenDomain, statsID, status, identity, botType, jid) => {\r\n                    // we need to ignore joins on lobby for participants that are already in the main room\r\n                    if (Object.values(this.mainRoom.members).find(m => m.jid === jid)) {\r\n                        return;\r\n                    }\r\n\r\n                    // Check if the user is a member if any breakout room.\r\n                    for (const room of Object.values(this.mainRoom.getBreakoutRooms()._rooms)) {\r\n                        if (Object.values(room.participants).find(p => p.jid === jid)) {\r\n                            return;\r\n                        }\r\n                    }\r\n\r\n                    // we emit the new event on the main room so we can propagate\r\n                    // events to the conference\r\n                    this.mainRoom.eventEmitter.emit(\r\n                        XMPPEvents.MUC_LOBBY_MEMBER_JOINED,\r\n                        Strophe.getResourceFromJid(from),\r\n                        nick,\r\n                        identity ? identity.avatar : undefined\r\n                    );\r\n                });\r\n            this.lobbyRoom.addEventListener(\r\n                XMPPEvents.MUC_MEMBER_LEFT, from => {\r\n                    // we emit the new event on the main room so we can propagate\r\n                    // events to the conference\r\n                    this.mainRoom.eventEmitter.emit(\r\n                        XMPPEvents.MUC_LOBBY_MEMBER_LEFT,\r\n                        Strophe.getResourceFromJid(from)\r\n                    );\r\n                });\r\n            this.lobbyRoom.addEventListener(\r\n                XMPPEvents.MUC_DESTROYED,\r\n                () => {\r\n                    // let's make sure we emit that all lobby users had left\r\n                    Object.keys(this.lobbyRoom.members)\r\n                        .forEach(j => this.mainRoom.eventEmitter.emit(\r\n                            XMPPEvents.MUC_LOBBY_MEMBER_LEFT, Strophe.getResourceFromJid(j)));\r\n\r\n                    this.lobbyRoom.clean();\r\n\r\n                    this.lobbyRoom = undefined;\r\n                    logger.info('Lobby room left(destroyed)!');\r\n                });\r\n        } else {\r\n            // this should only be handled by those waiting in lobby\r\n            this.lobbyRoom.addEventListener(XMPPEvents.KICKED, isSelfPresence => {\r\n                if (isSelfPresence) {\r\n                    this.mainRoom.eventEmitter.emit(XMPPEvents.MUC_DENIED_ACCESS);\r\n\r\n                    this.lobbyRoom.clean();\r\n\r\n                    return;\r\n                }\r\n            });\r\n\r\n            // As there is still reference of the main room\r\n            // the invite will be detected and addressed to its eventEmitter, even though we are not in it\r\n            // the invite message should be received directly to the xmpp conn in general\r\n            this.mainRoom.addEventListener(\r\n                XMPPEvents.INVITE_MESSAGE_RECEIVED,\r\n                (roomJid, from, txt, invitePassword) => {\r\n                    logger.debug(`Received approval to join ${roomJid} ${from} ${txt}`);\r\n                    if (roomJid === this.mainRoom.roomjid) {\r\n                        // we are now allowed, so let's join\r\n                        this.mainRoom.join(invitePassword);\r\n                    }\r\n                });\r\n            this.lobbyRoom.addEventListener(\r\n                XMPPEvents.MUC_DESTROYED,\r\n                (reason, jid) => {\r\n                    // we are receiving the jid of the main room\r\n                    // means we are invited to join, maybe lobby was disabled\r\n                    if (jid) {\r\n                        this.mainRoom.join();\r\n\r\n                        return;\r\n                    }\r\n\r\n                    this.lobbyRoom.clean();\r\n\r\n                    this.mainRoom.eventEmitter.emit(XMPPEvents.MUC_DESTROYED, reason);\r\n                });\r\n\r\n            // If participant retries joining shared password while waiting in the lobby\r\n            // and succeeds make sure we leave lobby\r\n            this.mainRoom.addEventListener(\r\n                XMPPEvents.MUC_JOINED,\r\n                () => {\r\n                    this.leave();\r\n                });\r\n        }\r\n\r\n        return new Promise((resolve, reject) => {\r\n            this.lobbyRoom.addEventListener(XMPPEvents.MUC_JOINED, () => {\r\n                resolve();\r\n\r\n                // send our email, as we do not handle this on initial presence we need a second one\r\n                if (email && !isModerator) {\r\n                    this.lobbyRoom.addOrReplaceInPresence(EMAIL_COMMAND, { value: email })\r\n                        && this.lobbyRoom.sendPresence();\r\n                }\r\n            });\r\n            this.lobbyRoom.addEventListener(XMPPEvents.ROOM_JOIN_ERROR, reject);\r\n            this.lobbyRoom.addEventListener(XMPPEvents.ROOM_CONNECT_NOT_ALLOWED_ERROR, reject);\r\n            this.lobbyRoom.addEventListener(XMPPEvents.ROOM_CONNECT_ERROR, reject);\r\n\r\n            this.lobbyRoom.join();\r\n        });\r\n\r\n    }\r\n\r\n    /**\r\n     * Should be possible only for moderators.\r\n     * @param id\r\n     */\r\n    denyAccess(id) {\r\n        if (!this.isSupported() || !this.mainRoom.isModerator()) {\r\n            return;\r\n        }\r\n\r\n        const jid = Object.keys(this.lobbyRoom.members)\r\n            .find(j => Strophe.getResourceFromJid(j) === id);\r\n\r\n        if (jid) {\r\n            this.lobbyRoom.kick(jid);\r\n        } else {\r\n            logger.error(`Not found member for ${id} in lobby room.`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Should be possible only for moderators.\r\n     * @param id\r\n     */\r\n    approveAccess(id) {\r\n        if (!this.isSupported() || !this.mainRoom.isModerator()) {\r\n            return;\r\n        }\r\n\r\n        // Get the main room JID. If we are in a breakout room we'll use the main\r\n        // room's lobby.\r\n        let mainRoomJid = this.mainRoom.roomjid;\r\n\r\n        if (this.mainRoom.getBreakoutRooms().isBreakoutRoom()) {\r\n            mainRoomJid = this.mainRoom.getBreakoutRooms().getMainRoomJid();\r\n        }\r\n\r\n        const memberRoomJid = Object.keys(this.lobbyRoom.members)\r\n            .find(j => Strophe.getResourceFromJid(j) === id);\r\n\r\n        if (memberRoomJid) {\r\n            const jid = this.lobbyRoom.members[memberRoomJid].jid;\r\n            const msgToSend\r\n                = $msg({ to: mainRoomJid })\r\n                    .c('x', { xmlns: 'http://jabber.org/protocol/muc#user' })\r\n                    .c('invite', { to: jid });\r\n\r\n            this.xmpp.connection.sendIQ(msgToSend,\r\n                () => { }, // eslint-disable-line no-empty-function\r\n                e => {\r\n                    logger.error(`Error sending invite for ${jid}`, e);\r\n                });\r\n        } else {\r\n            logger.error(`Not found member for ${memberRoomJid} in lobby room.`);\r\n        }\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport isEqual from 'lodash.isequal';\r\nimport { $msg } from 'strophe.js';\r\n\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\n\r\nimport { JITSI_MEET_MUC_TYPE } from './xmpp';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Helper class for handling room metadata.\r\n */\r\nexport default class RoomMetadata {\r\n    room: any;\r\n    _metadata: any;\r\n\r\n    /**\r\n     * Constructs lobby room.\r\n     *\r\n     * @param {ChatRoom} room the room we are in.\r\n     */\r\n    constructor(room) {\r\n        this.room = room;\r\n\r\n        this._handleMessages = this._handleMessages.bind(this);\r\n        this.room.xmpp.addListener(XMPPEvents.ROOM_METADATA_EVENT, this._handleMessages);\r\n\r\n        this._metadata = {};\r\n    }\r\n\r\n    /**\r\n     * Stops listening for events.\r\n     */\r\n    dispose() {\r\n        this.room.xmpp.removeListener(XMPPEvents.ROOM_METADATA_EVENT, this._handleMessages);\r\n    }\r\n\r\n    /**\r\n     * Sets metadata for the given key.\r\n     *\r\n     * @param {string} key - key under which the metadata will be stored.\r\n     * @param {object} data - data to be stored.\r\n     */\r\n    setMetadata(key, data) {\r\n        if (!this.isSupported() || !this.room.isModerator()) {\r\n            logger.error(`Cannot set room metadata - supported:${this.isSupported()},\r\n                moderator:${this.room.isModerator()}`);\r\n\r\n            return;\r\n        }\r\n\r\n        const message = {\r\n            key,\r\n            data\r\n        };\r\n\r\n        this._sendMessage(message);\r\n    }\r\n\r\n    /**\r\n     * Gets the stored metadata (all of it).\r\n     *\r\n     * @returns The stored metadata.\r\n     */\r\n    getMetadata() {\r\n        return this._metadata;\r\n    }\r\n\r\n    /**\r\n     * Whether Breakout Rooms support is enabled in the backend or not.\r\n     */\r\n    isSupported() {\r\n        return Boolean(this.getComponentAddress());\r\n    }\r\n\r\n    /**\r\n     * Gets the address of the Breakout Rooms XMPP component.\r\n     *\r\n     * @returns The address of the component.\r\n     */\r\n    getComponentAddress() {\r\n        return this.room.xmpp.roomMetadataComponentAddress;\r\n    }\r\n\r\n    /**\r\n     * Handles a message with metadata updates.\r\n     *\r\n     * @param {object} payload - Arbitrary data.\r\n     */\r\n    _handleMessages(payload) {\r\n        const { metadata } = payload;\r\n\r\n        if (!metadata || isEqual(this._metadata, metadata)) {\r\n            return;\r\n        }\r\n\r\n        this._metadata = metadata;\r\n        this.room.eventEmitter.emit(XMPPEvents.ROOM_METADATA_UPDATED, metadata);\r\n    }\r\n\r\n    /**\r\n     * Helper to send a breakout rooms message to the component.\r\n     *\r\n     * @param {Object} message - Command that needs to be sent.\r\n     */\r\n    _sendMessage(message) {\r\n        message[JITSI_MEET_MUC_TYPE] = 'room_metadata';\r\n\r\n        const msg = $msg({ to: this.getComponentAddress() });\r\n\r\n        msg.c('room_metadata', {\r\n            room: this.room.roomjid,\r\n            xmlns: 'http://jitsi.org/jitmeet'\r\n        }, JSON.stringify(message)).up();\r\n\r\n        this.room.xmpp.connection.send(msg);\r\n    }\r\n}\r\n","import { jitsiLocalStorage } from '@jitsi/js-utils';\r\nimport { getLogger } from '@jitsi/logger';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\nimport UsernameGenerator from '../util/UsernameGenerator';\r\n\r\nlet _callStatsUserName;\r\n\r\nlet _machineId;\r\n\r\n/**\r\n *\r\n */\r\nexport default {\r\n\r\n    /**\r\n     * The storage used to store the settings.\r\n     */\r\n    _storage: jitsiLocalStorage,\r\n\r\n    /**\r\n     * Initializes the Settings class.\r\n     *\r\n     * @param {Storage|undefined} externalStorage - Object that implements the Storage interface. This object will be\r\n     * used for storing data instead of jitsiLocalStorage if specified.\r\n     */\r\n    init(externalStorage) {\r\n        this._storage = externalStorage || jitsiLocalStorage;\r\n    },\r\n\r\n    /**\r\n     * Returns fake username for callstats\r\n     * @returns {string} fake username for callstats\r\n     */\r\n    get callStatsUserName() {\r\n        if (!_callStatsUserName) {\r\n            _callStatsUserName = this._storage.getItem('callStatsUserName');\r\n            if (!_callStatsUserName) {\r\n                _callStatsUserName = generateCallStatsUserName();\r\n                this._storage.setItem('callStatsUserName', _callStatsUserName);\r\n            }\r\n        }\r\n\r\n        return _callStatsUserName;\r\n    },\r\n\r\n    /**\r\n     * Returns current machine id.\r\n     * @returns {string} machine id\r\n     */\r\n    get machineId() {\r\n        if (!_machineId) {\r\n            const amDid = this._storage.getItem('billingId');\r\n\r\n            _machineId = amDid || this._storage.getItem('jitsiMeetId');\r\n\r\n            if (amDid) {\r\n                this._storage.setItem('jitsiMeetId', amDid);\r\n            } else if (!_machineId) {\r\n                _machineId = generateJitsiMeetId();\r\n                this._storage.setItem('jitsiMeetId', _machineId);\r\n            }\r\n        }\r\n\r\n        return _machineId;\r\n    },\r\n\r\n    /**\r\n     * Returns current session id.\r\n     * @returns {string} current session id\r\n     */\r\n    get sessionId() {\r\n        // We may update sessionId in localStorage from another JitsiConference\r\n        // instance and that's why we should always re-read it.\r\n        return this._storage.getItem('sessionId');\r\n    },\r\n\r\n    /**\r\n     * Save current session id.\r\n     * @param {string} sessionId session id\r\n     */\r\n    set sessionId(sessionId) {\r\n        if (sessionId) {\r\n            this._storage.setItem('sessionId', sessionId);\r\n        } else {\r\n            this._storage.removeItem('sessionId');\r\n        }\r\n    }\r\n};\r\n\r\n/**\r\n * Generate fake username for callstats.\r\n * @returns {string} fake random username\r\n */\r\nfunction generateCallStatsUserName() {\r\n    const username = UsernameGenerator.generateUsername();\r\n\r\n    logger.log('generated callstats uid', username);\r\n\r\n    return username;\r\n}\r\n\r\n/**\r\n * Generate unique id.\r\n * @returns {string} random unique id\r\n */\r\nfunction generateJitsiMeetId() {\r\n    const jitsiMeetId = generateUniqueId();\r\n\r\n    logger.log('generated id', jitsiMeetId);\r\n\r\n    return jitsiMeetId;\r\n}\r\n\r\n/**\r\n *\r\n */\r\nfunction generateUniqueId() {\r\n    return _p8() + _p8() + _p8() + _p8();\r\n}\r\n\r\n/**\r\n *\r\n */\r\nfunction _p8() {\r\n    return `${Math.random().toString(16)}000000000`.substr(2, 8);\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport $ from 'jquery';\r\nimport { $iq, Strophe } from 'strophe.js';\r\n\r\nimport Settings from '../settings/Settings';\r\n\r\nconst AuthenticationEvents\r\n    = require('../../service/authentication/AuthenticationEvents');\r\nconst { XMPPEvents } = require('../../service/xmpp/XMPPEvents');\r\nconst GlobalOnErrorHandler = require('../util/GlobalOnErrorHandler');\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n *\r\n * @param step\r\n */\r\nfunction createExpBackoffTimer(step) {\r\n    let count = 1;\r\n\r\n    return function(reset) {\r\n        // Reset call\r\n        if (reset) {\r\n            count = 1;\r\n\r\n            return;\r\n        }\r\n\r\n        // Calculate next timeout\r\n        const timeout = Math.pow(2, count - 1);\r\n\r\n        count += 1;\r\n\r\n        return timeout * step;\r\n    };\r\n}\r\n\r\n/* eslint-disable max-params */\r\n\r\n/**\r\n *\r\n * @param roomName\r\n * @param xmpp\r\n * @param emitter\r\n * @param options\r\n */\r\nexport default function Moderator(roomName, xmpp, emitter, options) {\r\n    this.roomName = roomName;\r\n    this.xmppService = xmpp;\r\n    this.getNextTimeout = createExpBackoffTimer(1000);\r\n    this.getNextErrorTimeout = createExpBackoffTimer(1000);\r\n\r\n    // External authentication stuff\r\n    this.externalAuthEnabled = false;\r\n    this.options = options;\r\n\r\n    // Whether SIP gateway (jigasi) support is enabled. This is set\r\n    // based on conference properties received in presence.\r\n    this.sipGatewayEnabled = false;\r\n\r\n    this.eventEmitter = emitter;\r\n\r\n    this.connection = this.xmppService.connection;\r\n\r\n    // FIXME: Message listener that talks to POPUP window\r\n    /**\r\n     *\r\n     * @param event\r\n     */\r\n    function listener(event) {\r\n        if (event.data && event.data.sessionId) {\r\n            if (event.origin !== window.location.origin) {\r\n                logger.warn(\r\n                    `Ignoring sessionId from different origin: ${\r\n                        event.origin}`);\r\n\r\n                return;\r\n            }\r\n            Settings.sessionId = event.data.sessionId;\r\n\r\n            // After popup is closed we will authenticate\r\n        }\r\n    }\r\n\r\n    // Register\r\n    if (window.addEventListener) {\r\n        window.addEventListener('message', listener, false);\r\n    } else {\r\n        window.attachEvent('onmessage', listener);\r\n    }\r\n}\r\n\r\n/* eslint-enable max-params */\r\n\r\nModerator.prototype.isExternalAuthEnabled = function() {\r\n    return this.externalAuthEnabled;\r\n};\r\n\r\nModerator.prototype.isSipGatewayEnabled = function() {\r\n    return this.sipGatewayEnabled;\r\n};\r\n\r\nModerator.prototype.onMucMemberLeft = function(jid) {\r\n    const resource = Strophe.getResourceFromJid(jid);\r\n\r\n    if (resource === 'focus') {\r\n        logger.info(\r\n            'Focus has left the room - leaving conference');\r\n        this.eventEmitter.emit(XMPPEvents.FOCUS_LEFT);\r\n    }\r\n};\r\n\r\nModerator.prototype.setFocusUserJid = function(focusJid) {\r\n    if (!this.focusUserJid) {\r\n        this.focusUserJid = focusJid;\r\n        logger.info(`Focus jid set to:  ${this.focusUserJid}`);\r\n    }\r\n};\r\n\r\nModerator.prototype.getFocusUserJid = function() {\r\n    return this.focusUserJid;\r\n};\r\n\r\nModerator.prototype.getFocusComponent = function() {\r\n    // Get focus component address\r\n    let focusComponent = this.options.connection.hosts.focus;\r\n\r\n    // If not specified use default:  'focus.domain'\r\n\r\n    if (!focusComponent) {\r\n        focusComponent = `focus.${this.options.connection.hosts.domain}`;\r\n    }\r\n\r\n    return focusComponent;\r\n};\r\n\r\nModerator.prototype.createConferenceIq = function() {\r\n    // Generate create conference IQ\r\n    const elem = $iq({ to: this.getFocusComponent(),\r\n        type: 'set' });\r\n\r\n    // Session Id used for authentication\r\n    const { sessionId } = Settings;\r\n    const machineUID = Settings.machineId;\r\n    const config = this.options.conference;\r\n\r\n    logger.info(`Session ID: ${sessionId} machine UID: ${machineUID}`);\r\n\r\n    elem.c('conference', {\r\n        xmlns: 'http://jitsi.org/protocol/focus',\r\n        room: this.roomName,\r\n        'machine-uid': machineUID\r\n    });\r\n\r\n    if (sessionId) {\r\n        elem.attrs({ 'session-id': sessionId });\r\n    }\r\n\r\n    elem.c(\r\n        'property', {\r\n            name: 'disableRtx',\r\n            value: Boolean(config.disableRtx)\r\n        }).up();\r\n\r\n    if (config.audioPacketDelay !== undefined) {\r\n        elem.c(\r\n            'property', {\r\n                name: 'audioPacketDelay',\r\n                value: config.audioPacketDelay\r\n            }).up();\r\n    }\r\n    if (config.startBitrate) {\r\n        elem.c(\r\n            'property', {\r\n                name: 'startBitrate',\r\n                value: config.startBitrate\r\n            }).up();\r\n    }\r\n    if (config.minBitrate) {\r\n        elem.c(\r\n            'property', {\r\n                name: 'minBitrate',\r\n                value: config.minBitrate\r\n            }).up();\r\n    }\r\n\r\n    if (this.options.conference.startAudioMuted !== undefined) {\r\n        elem.c(\r\n            'property', {\r\n                name: 'startAudioMuted',\r\n                value: this.options.conference.startAudioMuted\r\n            }).up();\r\n    }\r\n    if (this.options.conference.startVideoMuted !== undefined) {\r\n        elem.c(\r\n            'property', {\r\n                name: 'startVideoMuted',\r\n                value: this.options.conference.startVideoMuted\r\n            }).up();\r\n    }\r\n\r\n    // this flag determines whether the bridge will include this call in its\r\n    // rtcstats reporting or not. If the site admin hasn't set the flag in\r\n    // config.js, then the client defaults to false (see\r\n    // react/features/rtcstats/functions.js in jitsi-meet). The server-side\r\n    // components default to true to match the pre-existing behavior so we only\r\n    // signal if false.\r\n    const rtcstatsEnabled = this.options.conference?.analytics?.rtcstatsEnabled ?? false;\r\n\r\n    if (!rtcstatsEnabled) {\r\n        elem.c(\r\n            'property', {\r\n                name: 'rtcstatsEnabled',\r\n                value: rtcstatsEnabled\r\n            }).up();\r\n    }\r\n\r\n    const { callStatsID, callStatsSecret, disableThirdPartyRequests, enableCallStats } = this.options.conference;\r\n    const callstatsDisabled = !callStatsID || !callStatsSecret || !enableCallStats\r\n\r\n        // Even though AppID and AppSecret may be specified, the integration\r\n        // of callstats.io may be disabled because of globally-disallowed\r\n        // requests to any third parties.\r\n        || disableThirdPartyRequests === true;\r\n\r\n    // since the default is true across all the server-side components, only signal if false.\r\n    if (callstatsDisabled) {\r\n        elem.c(\r\n            'property', {\r\n                name: 'callstatsEnabled',\r\n                value: !callstatsDisabled\r\n            }).up();\r\n    }\r\n    elem.up();\r\n\r\n    return elem;\r\n};\r\n\r\n\r\nModerator.prototype.parseSessionId = function(resultIq) {\r\n    // eslint-disable-next-line newline-per-chained-call\r\n    const sessionId = $(resultIq).find('conference').attr('session-id');\r\n\r\n    if (sessionId) {\r\n        logger.info(`Received sessionId:  ${sessionId}`);\r\n        Settings.sessionId = sessionId;\r\n    }\r\n};\r\n\r\nModerator.prototype.parseConfigOptions = function(resultIq) {\r\n    // eslint-disable-next-line newline-per-chained-call\r\n    this.setFocusUserJid($(resultIq).find('conference').attr('focusjid'));\r\n\r\n    const authenticationEnabled\r\n        = $(resultIq).find(\r\n            '>conference>property'\r\n            + '[name=\\'authentication\\'][value=\\'true\\']').length > 0;\r\n\r\n    logger.info(`Authentication enabled: ${authenticationEnabled}`);\r\n\r\n    this.externalAuthEnabled = $(resultIq).find(\r\n        '>conference>property'\r\n            + '[name=\\'externalAuth\\'][value=\\'true\\']').length > 0;\r\n\r\n    logger.info(\r\n        `External authentication enabled: ${this.externalAuthEnabled}`);\r\n\r\n    if (!this.externalAuthEnabled) {\r\n        // We expect to receive sessionId in 'internal' authentication mode\r\n        this.parseSessionId(resultIq);\r\n    }\r\n\r\n    // eslint-disable-next-line newline-per-chained-call\r\n    const authIdentity = $(resultIq).find('>conference').attr('identity');\r\n\r\n    this.eventEmitter.emit(AuthenticationEvents.IDENTITY_UPDATED,\r\n        authenticationEnabled, authIdentity);\r\n\r\n    // Check if jicofo has jigasi support enabled.\r\n    if ($(resultIq).find(\r\n        '>conference>property'\r\n        + '[name=\\'sipGatewayEnabled\\'][value=\\'true\\']').length) {\r\n        this.sipGatewayEnabled = true;\r\n    }\r\n\r\n    logger.info(`Sip gateway enabled:  ${this.sipGatewayEnabled}`);\r\n};\r\n\r\n// FIXME We need to show the fact that we're waiting for the focus to the user\r\n// (or that the focus is not available)\r\n/**\r\n * Allocates the conference focus.\r\n *\r\n * @param {Function} callback - the function to be called back upon the\r\n * successful allocation of the conference focus\r\n * @returns {Promise} - Resolved when Jicofo allows to join the room. It's never\r\n * rejected and it'll keep on pinging Jicofo forever.\r\n */\r\nModerator.prototype.allocateConferenceFocus = function() {\r\n    return new Promise(resolve => {\r\n        // Try to use focus user JID from the config\r\n        this.setFocusUserJid(this.options.connection.focusUserJid);\r\n\r\n        // Send create conference IQ\r\n        this.connection.sendIQ(\r\n            this.createConferenceIq(),\r\n            result => this._allocateConferenceFocusSuccess(result, resolve),\r\n            error => this._allocateConferenceFocusError(error, resolve));\r\n\r\n        // XXX We're pressed for time here because we're beginning a complex\r\n        // and/or lengthy conference-establishment process which supposedly\r\n        // involves multiple RTTs. We don't have the time to wait for Strophe to\r\n        // decide to send our IQ.\r\n        this.connection.flush();\r\n    });\r\n};\r\n\r\n/**\r\n * Invoked by {@link #allocateConferenceFocus} upon its request receiving an\r\n * error result.\r\n *\r\n * @param error - the error result of the request that\r\n * {@link #allocateConferenceFocus} sent\r\n * @param {Function} callback - the function to be called back upon the\r\n * successful allocation of the conference focus\r\n */\r\nModerator.prototype._allocateConferenceFocusError = function(error, callback) {\r\n    // If the session is invalid, remove and try again without session ID to get\r\n    // a new one\r\n    const invalidSession\r\n        = $(error).find('>error>session-invalid').length\r\n            || $(error).find('>error>not-acceptable').length;\r\n\r\n    if (invalidSession) {\r\n        logger.info('Session expired! - removing');\r\n        Settings.sessionId = undefined;\r\n    }\r\n    if ($(error).find('>error>graceful-shutdown').length) {\r\n        this.eventEmitter.emit(XMPPEvents.GRACEFUL_SHUTDOWN);\r\n\r\n        return;\r\n    }\r\n\r\n    // Check for error returned by the reservation system\r\n    const reservationErr = $(error).find('>error>reservation-error');\r\n\r\n    if (reservationErr.length) {\r\n        // Trigger error event\r\n        const errorCode = reservationErr.attr('error-code');\r\n        const errorTextNode = $(error).find('>error>text');\r\n        let errorMsg;\r\n\r\n        if (errorTextNode) {\r\n            errorMsg = errorTextNode.text();\r\n        }\r\n        this.eventEmitter.emit(\r\n            XMPPEvents.RESERVATION_ERROR,\r\n            errorCode,\r\n            errorMsg);\r\n\r\n        return;\r\n    }\r\n\r\n    // Not authorized to create new room\r\n    if ($(error).find('>error>not-authorized').length) {\r\n        logger.warn('Unauthorized to start the conference', error);\r\n        const toDomain = Strophe.getDomainFromJid(error.getAttribute('to'));\r\n\r\n        if (toDomain !== this.options.connection.hosts.anonymousdomain) {\r\n            // FIXME \"is external\" should come either from the focus or\r\n            // config.js\r\n            this.externalAuthEnabled = true;\r\n        }\r\n        this.eventEmitter.emit(XMPPEvents.AUTHENTICATION_REQUIRED);\r\n\r\n        return;\r\n    }\r\n    const waitMs = this.getNextErrorTimeout();\r\n    const errmsg = `Focus error, retry after ${waitMs}`;\r\n\r\n    GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\r\n    logger.error(errmsg, error);\r\n\r\n    // Show message\r\n    const focusComponent = this.getFocusComponent();\r\n    const retrySec = waitMs / 1000;\r\n\r\n    // FIXME: message is duplicated ? Do not show in case of session invalid\r\n    // which means just a retry\r\n\r\n    if (!invalidSession) {\r\n        this.eventEmitter.emit(\r\n            XMPPEvents.FOCUS_DISCONNECTED,\r\n            focusComponent,\r\n            retrySec);\r\n    }\r\n\r\n    // Reset response timeout\r\n    this.getNextTimeout(true);\r\n    window.setTimeout(\r\n        () => this.allocateConferenceFocus().then(callback),\r\n        waitMs);\r\n};\r\n\r\n/**\r\n * Invoked by {@link #allocateConferenceFocus} upon its request receiving a\r\n * success (i.e. non-error) result.\r\n *\r\n * @param result - the success (i.e. non-error) result of the request that\r\n * {@link #allocateConferenceFocus} sent\r\n * @param {Function} callback - the function to be called back upon the\r\n * successful allocation of the conference focus\r\n */\r\nModerator.prototype._allocateConferenceFocusSuccess = function(\r\n        result,\r\n        callback) {\r\n    // Setup config options\r\n    this.parseConfigOptions(result);\r\n\r\n    // Reset the error timeout (because we haven't failed here).\r\n    this.getNextErrorTimeout(true);\r\n\r\n    // eslint-disable-next-line newline-per-chained-call\r\n    if ($(result).find('conference').attr('ready') === 'true') {\r\n        // Reset the non-error timeout (because we've succeeded here).\r\n        this.getNextTimeout(true);\r\n\r\n        // Exec callback\r\n        callback();\r\n    } else {\r\n        const waitMs = this.getNextTimeout();\r\n\r\n        logger.info(`Waiting for the focus... ${waitMs}`);\r\n        window.setTimeout(\r\n            () => this.allocateConferenceFocus().then(callback),\r\n            waitMs);\r\n    }\r\n};\r\n\r\nModerator.prototype.authenticate = function() {\r\n    return new Promise((resolve, reject) => {\r\n        this.connection.sendIQ(\r\n            this.createConferenceIq(),\r\n            result => {\r\n                this.parseSessionId(result);\r\n                resolve();\r\n            },\r\n            errorIq => reject({\r\n                error: $(errorIq).find('iq>error :first')\r\n                    .prop('tagName'),\r\n                message: $(errorIq).find('iq>error>text')\r\n                    .text()\r\n            })\r\n        );\r\n    });\r\n};\r\n\r\nModerator.prototype.getLoginUrl = function(urlCallback, failureCallback) {\r\n    this._getLoginUrl(/* popup */ false, urlCallback, failureCallback);\r\n};\r\n\r\n/**\r\n *\r\n * @param {boolean} popup false for {@link Moderator#getLoginUrl} or true for\r\n * {@link Moderator#getPopupLoginUrl}\r\n * @param urlCb\r\n * @param failureCb\r\n */\r\nModerator.prototype._getLoginUrl = function(popup, urlCb, failureCb) {\r\n    const iq = $iq({ to: this.getFocusComponent(),\r\n        type: 'get' });\r\n    const attrs = {\r\n        xmlns: 'http://jitsi.org/protocol/focus',\r\n        room: this.roomName,\r\n        'machine-uid': Settings.machineId\r\n    };\r\n    let str = 'auth url'; // for logger\r\n\r\n    if (popup) {\r\n        attrs.popup = true;\r\n        str = `POPUP ${str}`;\r\n    }\r\n    iq.c('login-url', attrs);\r\n\r\n    /**\r\n     * Implements a failure callback which reports an error message and an error\r\n     * through (1) GlobalOnErrorHandler, (2) logger, and (3) failureCb.\r\n     *\r\n     * @param {string} errmsg the error messsage to report\r\n     * @param {*} error the error to report (in addition to errmsg)\r\n     */\r\n    function reportError(errmsg, err) {\r\n        GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\r\n        logger.error(errmsg, err);\r\n        failureCb(err);\r\n    }\r\n    this.connection.sendIQ(\r\n        iq,\r\n        result => {\r\n            // eslint-disable-next-line newline-per-chained-call\r\n            let url = $(result).find('login-url').attr('url');\r\n\r\n            url = decodeURIComponent(url);\r\n            if (url) {\r\n                logger.info(`Got ${str}: ${url}`);\r\n                urlCb(url);\r\n            } else {\r\n                reportError(`Failed to get ${str} from the focus`, result);\r\n            }\r\n        },\r\n        reportError.bind(undefined, `Get ${str} error`)\r\n    );\r\n};\r\n\r\nModerator.prototype.getPopupLoginUrl = function(urlCallback, failureCallback) {\r\n    this._getLoginUrl(/* popup */ true, urlCallback, failureCallback);\r\n};\r\n\r\nModerator.prototype.logout = function(callback) {\r\n    const iq = $iq({ to: this.getFocusComponent(),\r\n        type: 'set' });\r\n    const { sessionId } = Settings;\r\n\r\n    if (!sessionId) {\r\n        callback();\r\n\r\n        return;\r\n    }\r\n    iq.c('logout', {\r\n        xmlns: 'http://jitsi.org/protocol/focus',\r\n        'session-id': sessionId\r\n    });\r\n    this.connection.sendIQ(\r\n        iq,\r\n        result => {\r\n            // eslint-disable-next-line newline-per-chained-call\r\n            let logoutUrl = $(result).find('logout').attr('logout-url');\r\n\r\n            if (logoutUrl) {\r\n                logoutUrl = decodeURIComponent(logoutUrl);\r\n            }\r\n            logger.info(`Log out OK, url: ${logoutUrl}`, result);\r\n            Settings.sessionId = undefined;\r\n            callback(logoutUrl);\r\n        },\r\n        error => {\r\n            const errmsg = 'Logout error';\r\n\r\n            GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\r\n            logger.error(errmsg, error);\r\n        }\r\n    );\r\n};\r\n","import { getLogger } from '@jitsi/logger';\r\nimport $ from 'jquery';\r\nimport isEqual from 'lodash.isequal';\r\nimport { $iq, $msg, $pres, Strophe } from 'strophe.js';\r\n\r\nimport * as JitsiTranscriptionStatus from '../../JitsiTranscriptionStatus';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport { VideoType } from '../../service/RTC/VideoType';\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\r\nimport Listenable from '../util/Listenable';\r\n\r\nimport AVModeration from './AVModeration';\r\nimport BreakoutRooms from './BreakoutRooms';\r\nimport Lobby from './Lobby';\r\nimport RoomMetadata from './RoomMetadata';\r\nimport XmppConnection from './XmppConnection';\r\nimport Moderator from './moderator';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\nexport const parser = {\r\n    packet2JSON(xmlElement, nodes) {\r\n        for (const child of Array.from(xmlElement.children)) {\r\n            const node = {\r\n                attributes: {},\r\n                children: [],\r\n                tagName: child.tagName\r\n            };\r\n\r\n            for (const attr of Array.from(child.attributes)) {\r\n                node.attributes[attr.name] = attr.value;\r\n            }\r\n            const text = Strophe.getText(child);\r\n\r\n            if (text) {\r\n                // Using Strophe.getText will do work for traversing all direct\r\n                // child text nodes but returns an escaped value, which is not\r\n                // desirable at this point.\r\n                node.value = Strophe.xmlunescape(text);\r\n            }\r\n            nodes.push(node);\r\n            this.packet2JSON(child, node.children);\r\n        }\r\n    },\r\n    json2packet(nodes, packet) {\r\n        for (let i = 0; i < nodes.length; i++) {\r\n            const node = nodes[i];\r\n\r\n            if (node) {\r\n                packet.c(node.tagName, node.attributes);\r\n                if (node.value) {\r\n                    packet.t(node.value);\r\n                }\r\n                if (node.children) {\r\n                    this.json2packet(node.children, packet);\r\n                }\r\n                packet.up();\r\n            }\r\n        }\r\n\r\n        // packet.up();\r\n    }\r\n};\r\n\r\n/**\r\n * Returns array of JS objects from the presence JSON associated with the passed\r\n / nodeName\r\n * @param pres the presence JSON\r\n * @param nodeName the name of the node (videomuted, audiomuted, etc)\r\n */\r\nexport function filterNodeFromPresenceJSON(pres, nodeName) {\r\n    const res = [];\r\n\r\n    for (let i = 0; i < pres.length; i++) {\r\n        if (pres[i].tagName === nodeName) {\r\n            res.push(pres[i]);\r\n        }\r\n    }\r\n\r\n    return res;\r\n}\r\n\r\n// XXX As ChatRoom constructs XMPP stanzas and Strophe is build around the idea\r\n// of chaining function calls, allow long function call chains.\r\n/* eslint-disable newline-per-chained-call */\r\n\r\n/**\r\n * Array of affiliations that are allowed in members only room.\r\n * @type {string[]}\r\n */\r\nconst MEMBERS_AFFILIATIONS = [ 'owner', 'admin', 'member' ];\r\n\r\n/**\r\n *\r\n */\r\nexport default class ChatRoom extends Listenable {\r\n\r\n    /* eslint-disable max-params */\r\n\r\n    /**\r\n     *\r\n     * @param {XmppConnection} connection - The XMPP connection instance.\r\n     * @param jid\r\n     * @param password\r\n     * @param XMPP\r\n     * @param options\r\n     * @param {boolean} options.disableFocus - when set to {@code false} will\r\n     * not invite Jicofo into the room.\r\n     * @param {boolean} options.disableDiscoInfo - when set to {@code false} will skip disco info.\r\n     * This is intended to be used only for lobby rooms.\r\n     * @param {boolean} options.enableLobby - when set to {@code false} will skip creating lobby room.\r\n     * @param {boolean} options.hiddenFromRecorderFeatureEnabled - when set to {@code true} we will check identity tag\r\n     * for node presence.\r\n     */\r\n    constructor(connection, jid, password, XMPP, options) {\r\n        super();\r\n        this.xmpp = XMPP;\r\n        this.connection = connection;\r\n        this.roomjid = Strophe.getBareJidFromJid(jid);\r\n        this.myroomjid = jid;\r\n        this.password = password;\r\n        this.replaceParticipant = false;\r\n        logger.info(`Joined MUC as ${this.myroomjid}`);\r\n        this.members = {};\r\n        this.presMap = {};\r\n        this.presHandlers = {};\r\n        this._removeConnListeners = [];\r\n        this.joined = false;\r\n        this.inProgressEmitted = false;\r\n        this.role = null;\r\n        this.focusMucJid = null;\r\n        this.noBridgeAvailable = false;\r\n        this.options = options || {};\r\n        this.moderator\r\n            = new Moderator(this.roomjid, this.xmpp, this.eventEmitter, {\r\n                connection: this.xmpp.options,\r\n                conference: this.options\r\n            });\r\n        if (typeof this.options.enableLobby === 'undefined' || this.options.enableLobby) {\r\n            this.lobby = new Lobby(this);\r\n        }\r\n        this.avModeration = new AVModeration(this);\r\n        this.breakoutRooms = new BreakoutRooms(this);\r\n        this.roomMetadata = new RoomMetadata(this);\r\n        this.initPresenceMap(options);\r\n        this.lastPresences = {};\r\n        this.phoneNumber = null;\r\n        this.phonePin = null;\r\n        this.connectionTimes = {};\r\n        this.participantPropertyListener = null;\r\n\r\n        this.locked = false;\r\n        this.transcriptionStatus = JitsiTranscriptionStatus.OFF;\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     *\r\n     */\r\n    initPresenceMap(options = {}) {\r\n        this.presMap.to = this.myroomjid;\r\n        this.presMap.xns = 'http://jabber.org/protocol/muc';\r\n        this.presMap.nodes = [];\r\n\r\n        if (options.statsId) {\r\n            this.presMap.nodes.push({\r\n                'tagName': 'stats-id',\r\n                'value': options.statsId\r\n            });\r\n        }\r\n\r\n        this.presenceUpdateTime = Date.now();\r\n    }\r\n\r\n    /**\r\n     * Joins the chat room.\r\n     * @param {string} password - Password to unlock room on joining.\r\n     * @returns {Promise} - resolved when join completes. At the time of this\r\n     * writing it's never rejected.\r\n     */\r\n    join(password, replaceParticipant) {\r\n        this.password = password;\r\n        this.replaceParticipant = replaceParticipant;\r\n\r\n        return new Promise(resolve => {\r\n            this.options.disableFocus\r\n                && logger.info(`Conference focus disabled for ${this.roomjid}`);\r\n\r\n            const preJoin\r\n                = this.options.disableFocus\r\n                    ? Promise.resolve()\r\n                    : this.moderator.allocateConferenceFocus();\r\n\r\n            preJoin.then(() => {\r\n                this.sendPresence(true);\r\n                this._removeConnListeners.push(\r\n                    this.connection.addEventListener(\r\n                        XmppConnection.Events.CONN_STATUS_CHANGED,\r\n                        this.onConnStatusChanged.bind(this))\r\n                );\r\n                resolve();\r\n            });\r\n        });\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param fromJoin - Whether this is initial presence to join the room.\r\n     */\r\n    sendPresence(fromJoin) {\r\n        const to = this.presMap.to;\r\n\r\n        if (!this.connection || !this.connection.connected || !to || (!this.joined && !fromJoin)) {\r\n            // Too early to send presence - not initialized\r\n            return;\r\n        }\r\n\r\n        const pres = $pres({ to });\r\n\r\n        // xep-0045 defines: \"including in the initial presence stanza an empty\r\n        // <x/> element qualified by the 'http://jabber.org/protocol/muc'\r\n        // namespace\" and subsequent presences should not include that or it can\r\n        // be considered as joining, and server can send us the message history\r\n        // for the room on every presence\r\n        if (fromJoin) {\r\n            if (this.replaceParticipant) {\r\n                pres.c('flip_device').up();\r\n            }\r\n\r\n            pres.c('x', { xmlns: this.presMap.xns });\r\n\r\n            if (this.password) {\r\n                pres.c('password').t(this.password).up();\r\n            }\r\n            if (this.options.billingId) {\r\n                pres.c('billingid').t(this.options.billingId).up();\r\n            }\r\n\r\n            pres.up();\r\n        }\r\n\r\n        parser.json2packet(this.presMap.nodes, pres);\r\n\r\n        // we store time we last synced presence state\r\n        this.presenceSyncTime = Date.now();\r\n\r\n        this.connection.send(pres);\r\n        if (fromJoin) {\r\n            // XXX We're pressed for time here because we're beginning a complex\r\n            // and/or lengthy conference-establishment process which supposedly\r\n            // involves multiple RTTs. We don't have the time to wait for\r\n            // Strophe to decide to send our IQ.\r\n            this.connection.flush();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sends the presence unavailable, signaling the server\r\n     * we want to leave the room.\r\n     */\r\n    doLeave(reason) {\r\n        logger.log('do leave', this.myroomjid);\r\n        const pres = $pres({\r\n            to: this.myroomjid,\r\n            type: 'unavailable'\r\n        });\r\n\r\n        if (reason) {\r\n            pres.c('status').t(reason).up();\r\n        }\r\n\r\n        this.presMap.length = 0;\r\n\r\n        // XXX Strophe is asynchronously sending by default. Unfortunately, that\r\n        // means that there may not be enough time to send the unavailable\r\n        // presence. Switching Strophe to synchronous sending is not much of an\r\n        // option because it may lead to a noticeable delay in navigating away\r\n        // from the current location. As a compromise, we will try to increase\r\n        // the chances of sending the unavailable presence within the short time\r\n        // span that we have upon unloading by invoking flush() on the\r\n        // connection. We flush() once before sending/queuing the unavailable\r\n        // presence in order to attemtp to have the unavailable presence at the\r\n        // top of the send queue. We flush() once more after sending/queuing the\r\n        // unavailable presence in order to attempt to have it sent as soon as\r\n        // possible.\r\n        // FIXME do not use Strophe.Connection in the ChatRoom directly\r\n        !this.connection.isUsingWebSocket && this.connection.flush();\r\n        this.connection.send(pres);\r\n        this.connection.flush();\r\n    }\r\n\r\n    /**\r\n     *\r\n     */\r\n    discoRoomInfo() {\r\n        // https://xmpp.org/extensions/xep-0045.html#disco-roominfo\r\n\r\n        const getInfo\r\n            = $iq({\r\n                type: 'get',\r\n                to: this.roomjid\r\n            })\r\n                .c('query', { xmlns: Strophe.NS.DISCO_INFO });\r\n\r\n        this.connection.sendIQ(getInfo, result => {\r\n            const locked\r\n                = $(result).find('>query>feature[var=\"muc_passwordprotected\"]')\r\n                    .length\r\n                    === 1;\r\n\r\n            if (locked !== this.locked) {\r\n                this.eventEmitter.emit(XMPPEvents.MUC_LOCK_CHANGED, locked);\r\n                this.locked = locked;\r\n            }\r\n\r\n            const meetingIdValEl\r\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_meetingId\"]>value');\r\n\r\n            if (meetingIdValEl.length) {\r\n                this.setMeetingId(meetingIdValEl.text());\r\n            } else {\r\n                logger.warn('No meeting ID from backend');\r\n            }\r\n\r\n            const membersOnly = $(result).find('>query>feature[var=\"muc_membersonly\"]').length === 1;\r\n\r\n            const lobbyRoomField\r\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_lobbyroom\"]>value');\r\n\r\n            if (this.lobby) {\r\n                this.lobby.setLobbyRoomJid(lobbyRoomField && lobbyRoomField.length ? lobbyRoomField.text() : undefined);\r\n            }\r\n\r\n            const isBreakoutField\r\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_isbreakout\"]>value');\r\n            const isBreakoutRoom = Boolean(isBreakoutField?.text());\r\n\r\n            this.breakoutRooms._setIsBreakoutRoom(isBreakoutRoom);\r\n\r\n            const breakoutMainRoomField\r\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_breakout_main_room\"]>value');\r\n\r\n            if (breakoutMainRoomField?.length) {\r\n                this.breakoutRooms._setMainRoomJid(breakoutMainRoomField.text());\r\n            }\r\n\r\n            if (membersOnly !== this.membersOnlyEnabled) {\r\n                this.membersOnlyEnabled = membersOnly;\r\n                this.eventEmitter.emit(XMPPEvents.MUC_MEMBERS_ONLY_CHANGED, membersOnly);\r\n            }\r\n\r\n            const roomMetadataEl\r\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_jitsimetadata\"]>value');\r\n            const roomMetadataText = roomMetadataEl?.text();\r\n\r\n            if (roomMetadataText) {\r\n                try {\r\n                    this.roomMetadata._handleMessages(JSON.parse(roomMetadataText));\r\n                } catch (e) {\r\n                    logger.warn('Failed to set room metadata', e);\r\n                }\r\n            }\r\n        }, error => {\r\n            GlobalOnErrorHandler.callErrorHandler(error);\r\n            logger.error('Error getting room info: ', error);\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Sets the meeting unique Id (received from the backend).\r\n     *\r\n     * @param {string} meetingId - The new meetings id.\r\n     * @returns {void}\r\n     */\r\n    setMeetingId(meetingId) {\r\n        if (this.meetingId !== meetingId) {\r\n            if (this.meetingId) {\r\n                logger.warn(`Meeting Id changed from:${this.meetingId} to:${meetingId}`);\r\n            }\r\n            this.meetingId = meetingId;\r\n            this.eventEmitter.emit(XMPPEvents.MEETING_ID_SET, meetingId);\r\n        }\r\n    }\r\n\r\n    /**\r\n     *\r\n     */\r\n    createNonAnonymousRoom() {\r\n        // http://xmpp.org/extensions/xep-0045.html#createroom-reserved\r\n\r\n        if (this.options.disableDiscoInfo) {\r\n            return;\r\n        }\r\n\r\n        const getForm = $iq({ type: 'get',\r\n            to: this.roomjid })\r\n            .c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' })\r\n            .c('x', { xmlns: 'jabber:x:data',\r\n                type: 'submit' });\r\n\r\n        this.connection.sendIQ(getForm, form => {\r\n            if (!$(form).find(\r\n                    '>query>x[xmlns=\"jabber:x:data\"]'\r\n                    + '>field[var=\"muc#roomconfig_whois\"]').length) {\r\n                const errmsg = 'non-anonymous rooms not supported';\r\n\r\n                GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\r\n                logger.error(errmsg);\r\n\r\n                return;\r\n            }\r\n\r\n            const formSubmit = $iq({ to: this.roomjid,\r\n                type: 'set' })\r\n                .c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' });\r\n\r\n            formSubmit.c('x', { xmlns: 'jabber:x:data',\r\n                type: 'submit' });\r\n\r\n            formSubmit.c('field', { 'var': 'FORM_TYPE' })\r\n                .c('value')\r\n                .t('http://jabber.org/protocol/muc#roomconfig').up().up();\r\n\r\n            formSubmit.c('field', { 'var': 'muc#roomconfig_whois' })\r\n                .c('value').t('anyone').up().up();\r\n\r\n            this.connection.sendIQ(formSubmit);\r\n\r\n        }, error => {\r\n            GlobalOnErrorHandler.callErrorHandler(error);\r\n            logger.error('Error getting room configuration form: ', error);\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Handles Xmpp Connection status updates.\r\n     *\r\n     * @param {Strophe.Status} status - The Strophe connection status.\r\n     */\r\n    onConnStatusChanged(status) {\r\n        // Send cached presence when the XMPP connection is re-established, only if needed\r\n        if (status === XmppConnection.Status.CONNECTED && this.presenceUpdateTime > this.presenceSyncTime) {\r\n            this.sendPresence();\r\n        }\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param pres\r\n     */\r\n    onPresence(pres) {\r\n        const from = pres.getAttribute('from');\r\n        const member = {};\r\n        const statusEl = pres.getElementsByTagName('status')[0];\r\n\r\n        if (statusEl) {\r\n            member.status = statusEl.textContent || '';\r\n        }\r\n        let hasStatusUpdate = false;\r\n        let hasVersionUpdate = false;\r\n        const xElement\r\n            = pres.getElementsByTagNameNS(\r\n                'http://jabber.org/protocol/muc#user', 'x')[0];\r\n        const mucUserItem\r\n            = xElement && xElement.getElementsByTagName('item')[0];\r\n\r\n        member.isReplaceParticipant\r\n            = pres.getElementsByTagName('flip_device').length;\r\n\r\n        member.affiliation\r\n            = mucUserItem && mucUserItem.getAttribute('affiliation');\r\n        member.role = mucUserItem && mucUserItem.getAttribute('role');\r\n\r\n        // Focus recognition\r\n        const jid = mucUserItem && mucUserItem.getAttribute('jid');\r\n\r\n        member.jid = jid;\r\n        member.isFocus\r\n            = jid && jid.indexOf(`${this.moderator.getFocusUserJid()}/`) === 0;\r\n        member.isHiddenDomain\r\n            = jid && jid.indexOf('@') > 0\r\n                && this.options.hiddenDomain\r\n                    === jid.substring(jid.indexOf('@') + 1, jid.indexOf('/'));\r\n\r\n        this.eventEmitter.emit(XMPPEvents.PRESENCE_RECEIVED, {\r\n            fromHiddenDomain: member.isHiddenDomain,\r\n            presence: pres\r\n        });\r\n\r\n        const xEl = pres.querySelector('x');\r\n\r\n        if (xEl) {\r\n            xEl.remove();\r\n        }\r\n\r\n        const nodes = [];\r\n\r\n        parser.packet2JSON(pres, nodes);\r\n        this.lastPresences[from] = nodes;\r\n\r\n        // process nodes to extract data needed for MUC_JOINED and\r\n        // MUC_MEMBER_JOINED events\r\n        const extractIdentityInformation = node => {\r\n            const identity = {};\r\n            const userInfo = node.children.find(c => c.tagName === 'user');\r\n\r\n            if (userInfo) {\r\n                identity.user = {};\r\n                const tags = [ 'id', 'name', 'avatar' ];\r\n\r\n                if (this.options.hiddenFromRecorderFeatureEnabled) {\r\n                    tags.push('hidden-from-recorder');\r\n                }\r\n\r\n                for (const tag of tags) {\r\n                    const child\r\n                        = userInfo.children.find(c => c.tagName === tag);\r\n\r\n                    if (child) {\r\n                        identity.user[tag] = child.value;\r\n                    }\r\n                }\r\n            }\r\n            const groupInfo = node.children.find(c => c.tagName === 'group');\r\n\r\n            if (groupInfo) {\r\n                identity.group = groupInfo.value;\r\n            }\r\n\r\n            return identity;\r\n        };\r\n\r\n        for (let i = 0; i < nodes.length; i++) {\r\n            const node = nodes[i];\r\n\r\n            switch (node.tagName) {\r\n            case 'bot': {\r\n                const { attributes } = node;\r\n\r\n                if (!attributes) {\r\n                    break;\r\n                }\r\n                const { type } = attributes;\r\n\r\n                member.botType = type;\r\n                break;\r\n            }\r\n            case 'nick':\r\n                member.nick = node.value;\r\n                break;\r\n            case 'userId':\r\n                member.id = node.value;\r\n                break;\r\n            case 'stats-id':\r\n                member.statsID = node.value;\r\n                break;\r\n            case 'identity':\r\n                member.identity = extractIdentityInformation(node);\r\n                break;\r\n            case 'features': {\r\n                member.features = this._extractFeatures(node);\r\n                break;\r\n            }\r\n            case 'stat': {\r\n                const { attributes } = node;\r\n\r\n                if (!attributes) {\r\n                    break;\r\n                }\r\n                const { name } = attributes;\r\n\r\n                if (name === 'version') {\r\n                    member.version = attributes.value;\r\n                }\r\n                break;\r\n            }\r\n            }\r\n        }\r\n\r\n        if (!this.joined && !this.inProgressEmitted) {\r\n            const now = this.connectionTimes['muc.join.started'] = window.performance.now();\r\n\r\n            logger.log('(TIME) MUC join started:\\t', now);\r\n\r\n            this.eventEmitter.emit(XMPPEvents.MUC_JOIN_IN_PROGRESS);\r\n            this.inProgressEmitted = true;\r\n        }\r\n\r\n        if (from === this.myroomjid) {\r\n            const newRole\r\n                = member.affiliation === 'owner' ? member.role : 'none';\r\n\r\n            if (this.role !== newRole) {\r\n                this.role = newRole;\r\n                this.eventEmitter.emit(\r\n                    XMPPEvents.LOCAL_ROLE_CHANGED,\r\n                    this.role);\r\n            }\r\n            if (!this.joined) {\r\n                this.joined = true;\r\n                const now = this.connectionTimes['muc.joined']\r\n                    = window.performance.now();\r\n\r\n                logger.log('(TIME) MUC joined:\\t', now);\r\n\r\n                // set correct initial state of locked\r\n                if (this.password) {\r\n                    this.locked = true;\r\n                }\r\n\r\n                // Re-send presence in case any presence updates were added,\r\n                // but blocked from sending, during the join process.\r\n                // send the presence only if there was a modification after we had synced it\r\n                if (this.presenceUpdateTime >= this.presenceSyncTime) {\r\n                    this.sendPresence();\r\n                }\r\n\r\n                this.eventEmitter.emit(XMPPEvents.MUC_JOINED);\r\n\r\n                // Now let's check the disco-info to retrieve the\r\n                // meeting Id if any\r\n                !this.options.disableDiscoInfo && this.discoRoomInfo();\r\n            }\r\n        } else if (jid === undefined) {\r\n            logger.info('Ignoring member with undefined JID');\r\n        } else if (this.members[from] === undefined) {\r\n            // new participant\r\n            this.members[from] = member;\r\n            logger.log('entered', from, member);\r\n            hasStatusUpdate = member.status !== undefined;\r\n            hasVersionUpdate = member.version !== undefined;\r\n            if (member.isFocus) {\r\n                this._initFocus(from, member.features);\r\n            } else {\r\n                // identity is being added to member joined, so external\r\n                // services can be notified for that (currently identity is\r\n                // not used inside library)\r\n                this.eventEmitter.emit(\r\n                    XMPPEvents.MUC_MEMBER_JOINED,\r\n                    from,\r\n                    member.nick,\r\n                    member.role,\r\n                    member.isHiddenDomain,\r\n                    member.statsID,\r\n                    member.status,\r\n                    member.identity,\r\n                    member.botType,\r\n                    member.jid,\r\n                    member.features,\r\n                    member.isReplaceParticipant);\r\n\r\n                // we are reporting the status with the join\r\n                // so we do not want a second event about status update\r\n                hasStatusUpdate = false;\r\n            }\r\n        } else {\r\n            // Presence update for existing participant\r\n            // Watch role change:\r\n            const memberOfThis = this.members[from];\r\n\r\n            if (memberOfThis.role !== member.role) {\r\n                memberOfThis.role = member.role;\r\n                this.eventEmitter.emit(\r\n                    XMPPEvents.MUC_ROLE_CHANGED, from, member.role);\r\n            }\r\n\r\n            // affiliation changed\r\n            if (memberOfThis.affiliation !== member.affiliation) {\r\n                memberOfThis.affiliation = member.affiliation;\r\n            }\r\n\r\n            // fire event that botType had changed\r\n            if (memberOfThis.botType !== member.botType) {\r\n                memberOfThis.botType = member.botType;\r\n                this.eventEmitter.emit(\r\n                    XMPPEvents.MUC_MEMBER_BOT_TYPE_CHANGED,\r\n                    from,\r\n                    member.botType);\r\n            }\r\n\r\n            if (member.isFocus) {\r\n                // From time to time first few presences of the focus are not\r\n                // containing it's jid. That way we can mark later the focus\r\n                // member instead of not marking it at all and not starting the\r\n                // conference.\r\n                // FIXME: Maybe there is a better way to handle this issue. It\r\n                // seems there is some period of time in prosody that the\r\n                // configuration form is received but not applied. And if any\r\n                // participant joins during that period of time the first\r\n                // presence from the focus won't contain\r\n                // <item jid=\"focus...\" />.\r\n                // By default we are disabling the waiting for form submission in order to use the room\r\n                // and we had enabled by default that jids are public in the room ,\r\n                // so this case should not happen, if public jid is turned off we will receive the jid\r\n                // when we become moderator in the room\r\n                memberOfThis.isFocus = true;\r\n                this._initFocus(from, member.features);\r\n            }\r\n\r\n            // store the new display name\r\n            if (member.displayName) {\r\n                memberOfThis.displayName = member.displayName;\r\n            }\r\n\r\n            // update stored status message to be able to detect changes\r\n            if (memberOfThis.status !== member.status) {\r\n                hasStatusUpdate = true;\r\n                memberOfThis.status = member.status;\r\n            }\r\n\r\n            if (memberOfThis.version !== member.version) {\r\n                hasVersionUpdate = true;\r\n                memberOfThis.version = member.version;\r\n            }\r\n\r\n            if (!isEqual(memberOfThis.features, member.features)) {\r\n                memberOfThis.features = member.features;\r\n                this.eventEmitter.emit(XMPPEvents.PARTICIPANT_FEATURES_CHANGED, from, member.features);\r\n            }\r\n        }\r\n\r\n        // after we had fired member or room joined events, lets fire events\r\n        // for the rest info we got in presence\r\n        for (let i = 0; i < nodes.length; i++) {\r\n            const node = nodes[i];\r\n\r\n            switch (node.tagName) {\r\n            case 'nick':\r\n                if (!member.isFocus) {\r\n                    const displayName\r\n                        = this.xmpp.options.displayJids\r\n                            ? Strophe.getResourceFromJid(from)\r\n                            : member.nick;\r\n\r\n                    this.eventEmitter.emit(\r\n                        XMPPEvents.DISPLAY_NAME_CHANGED,\r\n                        from,\r\n                        displayName);\r\n                }\r\n                break;\r\n            case 'bridgeNotAvailable':\r\n                if (member.isFocus && !this.noBridgeAvailable) {\r\n                    this.noBridgeAvailable = true;\r\n                    this.eventEmitter.emit(XMPPEvents.BRIDGE_DOWN);\r\n                }\r\n                break;\r\n            case 'conference-properties':\r\n                if (member.isFocus) {\r\n                    const properties = {};\r\n\r\n                    for (let j = 0; j < node.children.length; j++) {\r\n                        const { attributes } = node.children[j];\r\n\r\n                        if (attributes && attributes.key) {\r\n                            properties[attributes.key] = attributes.value;\r\n                        }\r\n                    }\r\n\r\n                    this.eventEmitter.emit(XMPPEvents.CONFERENCE_PROPERTIES_CHANGED, properties);\r\n\r\n                    // Log if Jicofo supports restart by terminate only once. This conference property does not change\r\n                    // during the call.\r\n                    if (typeof this.restartByTerminateSupported === 'undefined') {\r\n                        this.restartByTerminateSupported = properties['support-terminate-restart'] === 'true';\r\n                        logger.info(`Jicofo supports restart by terminate: ${this.supportsRestartByTerminate()}`);\r\n                    }\r\n                }\r\n                break;\r\n            case 'transcription-status': {\r\n                const { attributes } = node;\r\n\r\n                if (!attributes) {\r\n                    break;\r\n                }\r\n\r\n                const { status } = attributes;\r\n\r\n                if (status && status !== this.transcriptionStatus) {\r\n                    this.transcriptionStatus = status;\r\n                    this.eventEmitter.emit(\r\n                        XMPPEvents.TRANSCRIPTION_STATUS_CHANGED,\r\n                        status\r\n                    );\r\n                }\r\n\r\n\r\n                break;\r\n            }\r\n            case 'call-control': {\r\n                const att = node.attributes;\r\n\r\n                if (!att) {\r\n                    break;\r\n                }\r\n                this.phoneNumber = att.phone || null;\r\n                this.phonePin = att.pin || null;\r\n                this.eventEmitter.emit(XMPPEvents.PHONE_NUMBER_CHANGED);\r\n                break;\r\n            }\r\n            default:\r\n                this.processNode(node, from);\r\n            }\r\n        }\r\n\r\n        // Trigger status message update if necessary\r\n        if (hasStatusUpdate) {\r\n            this.eventEmitter.emit(\r\n                XMPPEvents.PRESENCE_STATUS,\r\n                from,\r\n                member.status);\r\n        }\r\n\r\n        if (hasVersionUpdate) {\r\n            logger.info(`Received version for ${jid}: ${member.version}`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Extracts the features from the presence.\r\n     * @param node the node to process.\r\n     * @return features the Set of features where extracted data is added.\r\n     * @private\r\n     */\r\n    _extractFeatures(node) {\r\n        const features = new Set();\r\n\r\n        for (let j = 0; j < node.children.length; j++) {\r\n            const { attributes } = node.children[j];\r\n\r\n            if (attributes && attributes.var) {\r\n                features.add(attributes.var);\r\n            }\r\n        }\r\n\r\n        return features;\r\n    }\r\n\r\n    /**\r\n     * Initialize some properties when the focus participant is verified.\r\n     * @param from jid of the focus\r\n     * @param features the features reported in jicofo presence\r\n     */\r\n    _initFocus(from, features) {\r\n        this.focusMucJid = from;\r\n        this.focusFeatures = features;\r\n    }\r\n\r\n    /**\r\n     * Sets the special listener to be used for \"command\"s whose name starts\r\n     * with \"jitsi_participant_\".\r\n     */\r\n    setParticipantPropertyListener(listener) {\r\n        this.participantPropertyListener = listener;\r\n    }\r\n\r\n    /**\r\n     * Checks if Jicofo supports restarting Jingle session after 'session-terminate'.\r\n     * @returns {boolean}\r\n     */\r\n    supportsRestartByTerminate() {\r\n        return this.restartByTerminateSupported;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param node\r\n     * @param from\r\n     */\r\n    processNode(node, from) {\r\n        // make sure we catch all errors coming from any handler\r\n        // otherwise we can remove the presence handler from strophe\r\n        try {\r\n            let tagHandlers = this.presHandlers[node.tagName];\r\n\r\n            if (node.tagName.startsWith('jitsi_participant_')) {\r\n                tagHandlers = [ this.participantPropertyListener ];\r\n            }\r\n\r\n            if (tagHandlers) {\r\n                tagHandlers.forEach(handler => {\r\n                    handler(node, Strophe.getResourceFromJid(from), from);\r\n                });\r\n            }\r\n        } catch (e) {\r\n            GlobalOnErrorHandler.callErrorHandler(e);\r\n            logger.error(`Error processing:${node.tagName} node.`, e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Send text message to the other participants in the conference\r\n     * @param message\r\n     * @param elementName\r\n     */\r\n    sendMessage(message, elementName) {\r\n        const msg = $msg({ to: this.roomjid,\r\n            type: 'groupchat' });\r\n\r\n        // We are adding the message in a packet extension. If this element\r\n        // is different from 'body', we add a custom namespace.\r\n        // e.g. for 'json-message' extension of message stanza.\r\n        if (elementName === 'body') {\r\n            msg.c(elementName, {}, message);\r\n        } else {\r\n            msg.c(elementName, { xmlns: 'http://jitsi.org/jitmeet' }, message);\r\n        }\r\n\r\n        this.connection.send(msg);\r\n        this.eventEmitter.emit(XMPPEvents.SENDING_CHAT_MESSAGE, message);\r\n    }\r\n\r\n    /* eslint-disable max-params */\r\n    /**\r\n     * Send private text message to another participant of the conference\r\n     * @param id id/muc resource of the receiver\r\n     * @param message\r\n     * @param elementName\r\n     */\r\n    sendPrivateMessage(id, message, elementName) {\r\n        const msg = $msg({ to: `${this.roomjid}/${id}`,\r\n            type: 'chat' });\r\n\r\n        // We are adding the message in packet. If this element is different\r\n        // from 'body', we add our custom namespace for the same.\r\n        // e.g. for 'json-message' message extension.\r\n        if (elementName === 'body') {\r\n            msg.c(elementName, message).up();\r\n        } else {\r\n            msg.c(elementName, { xmlns: 'http://jitsi.org/jitmeet' }, message)\r\n                .up();\r\n        }\r\n\r\n        this.connection.send(msg);\r\n        this.eventEmitter.emit(\r\n            XMPPEvents.SENDING_PRIVATE_CHAT_MESSAGE, message);\r\n    }\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     *\r\n     * @param subject\r\n     */\r\n    setSubject(subject) {\r\n        const msg = $msg({ to: this.roomjid,\r\n            type: 'groupchat' });\r\n\r\n        msg.c('subject', subject);\r\n        this.connection.send(msg);\r\n    }\r\n\r\n    /**\r\n     * Called when participant leaves.\r\n     * @param jid the jid of the participant that leaves\r\n     * @param skipEvents optional params to skip any events, including check\r\n     * whether this is the focus that left\r\n     * @param reason the reason for leaving (optional).\r\n     */\r\n    onParticipantLeft(jid, skipEvents, reason) {\r\n        delete this.lastPresences[jid];\r\n\r\n        if (skipEvents) {\r\n            return;\r\n        }\r\n\r\n        this.eventEmitter.emit(XMPPEvents.MUC_MEMBER_LEFT, jid, reason);\r\n\r\n        this.moderator.onMucMemberLeft(jid);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param pres\r\n     * @param from\r\n     */\r\n    onPresenceUnavailable(pres, from) {\r\n        // ignore presence\r\n        if ($(pres).find('>ignore[xmlns=\"http://jitsi.org/jitmeet/\"]').length) {\r\n            return true;\r\n        }\r\n\r\n        // room destroyed ?\r\n        const destroySelect = $(pres).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>destroy');\r\n\r\n        if (destroySelect.length) {\r\n            let reason;\r\n            const reasonSelect\r\n                = $(pres).find(\r\n                    '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\r\n                        + '>destroy>reason');\r\n\r\n            if (reasonSelect.length) {\r\n                reason = reasonSelect.text();\r\n            }\r\n\r\n            this.eventEmitter.emit(XMPPEvents.MUC_DESTROYED, reason, destroySelect.attr('jid'));\r\n            this.connection.emuc.doLeave(this.roomjid);\r\n\r\n            return true;\r\n        }\r\n\r\n        // Status code 110 indicates that this notification is \"self-presence\".\r\n        const isSelfPresence\r\n            = $(pres)\r\n                .find(\r\n                    '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>'\r\n                        + 'status[code=\"110\"]')\r\n                .length;\r\n        const isKick\r\n            = $(pres)\r\n                .find(\r\n                    '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\r\n                        + '>status[code=\"307\"]')\r\n                .length;\r\n        const membersKeys = Object.keys(this.members);\r\n        const isReplaceParticipant = $(pres).find('flip_device').length;\r\n\r\n        if (isKick) {\r\n            const actorSelect\r\n                = $(pres)\r\n                .find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>item>actor');\r\n            let actorNick;\r\n\r\n            if (actorSelect.length) {\r\n                actorNick = actorSelect.attr('nick');\r\n            }\r\n\r\n            let reason;\r\n            const reasonSelect\r\n                = $(pres).find(\r\n                '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\r\n                + '>item>reason');\r\n\r\n            if (reasonSelect.length) {\r\n                reason = reasonSelect.text();\r\n            }\r\n\r\n            // we first fire the kicked so we can show the participant\r\n            // who kicked, before notifying that participant left\r\n            // we fire kicked for us and for any participant kicked\r\n            this.eventEmitter.emit(\r\n                XMPPEvents.KICKED,\r\n                isSelfPresence,\r\n                actorNick,\r\n                Strophe.getResourceFromJid(from),\r\n                reason,\r\n                isReplaceParticipant);\r\n        }\r\n\r\n        if (isSelfPresence) {\r\n            // If the status code is 110 this means we're leaving and we would\r\n            // like to remove everyone else from our view, so we trigger the\r\n            // event.\r\n            membersKeys.forEach(jid => {\r\n                const member = this.members[jid];\r\n\r\n                delete this.members[jid];\r\n                this.onParticipantLeft(jid, member.isFocus);\r\n            });\r\n            this.connection.emuc.doLeave(this.roomjid);\r\n\r\n            // we fire muc_left only if this is not a kick,\r\n            // kick has both statuses 110 and 307.\r\n            if (!isKick) {\r\n                this.eventEmitter.emit(XMPPEvents.MUC_LEFT);\r\n            }\r\n        } else {\r\n            const reasonSelect = $(pres).find('>status');\r\n            let reason;\r\n\r\n            if (reasonSelect.length) {\r\n                reason = reasonSelect.text();\r\n            }\r\n\r\n            delete this.members[from];\r\n            this.onParticipantLeft(from, false, reason);\r\n        }\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param msg\r\n     * @param from\r\n     */\r\n    onMessage(msg, from) {\r\n        const type = msg.getAttribute('type');\r\n\r\n        if (type === 'error') {\r\n            const settingsErrorMsg = $(msg).find('>settings-error>text').text();\r\n\r\n            if (settingsErrorMsg.length) {\r\n                this.eventEmitter.emit(XMPPEvents.SETTINGS_ERROR_RECEIVED, settingsErrorMsg);\r\n\r\n                return true;\r\n            }\r\n            const errorMsg = $(msg).find('>error>text').text();\r\n\r\n            this.eventEmitter.emit(XMPPEvents.CHAT_ERROR_RECEIVED, errorMsg);\r\n\r\n            return true;\r\n        }\r\n\r\n        const txt = $(msg).find('>body').text();\r\n        const subject = $(msg).find('>subject');\r\n\r\n        if (subject.length) {\r\n            const subjectText = subject.text();\r\n\r\n            if (subjectText || subjectText === '') {\r\n                this.eventEmitter.emit(XMPPEvents.SUBJECT_CHANGED, subjectText);\r\n                logger.log(`Subject is changed to ${subjectText}`);\r\n            }\r\n        }\r\n\r\n        // xep-0203 delay\r\n        let stamp = $(msg).find('>delay').attr('stamp');\r\n\r\n        if (!stamp) {\r\n            // or xep-0091 delay, UTC timestamp\r\n            stamp = $(msg).find('>[xmlns=\"jabber:x:delay\"]').attr('stamp');\r\n\r\n            if (stamp) {\r\n                // the format is CCYYMMDDThh:mm:ss\r\n                const dateParts\r\n                    = stamp.match(/(\\d{4})(\\d{2})(\\d{2}T\\d{2}:\\d{2}:\\d{2})/);\r\n\r\n                stamp = `${dateParts[1]}-${dateParts[2]}-${dateParts[3]}Z`;\r\n            }\r\n        }\r\n\r\n        if (from === this.roomjid) {\r\n            let invite;\r\n\r\n            if ($(msg).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>status[code=\"104\"]').length) {\r\n                this.discoRoomInfo();\r\n            } else if ((invite = $(msg).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>invite'))\r\n                        && invite.length) {\r\n                const passwordSelect = $(msg).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>password');\r\n                let password;\r\n\r\n                if (passwordSelect && passwordSelect.length) {\r\n                    password = passwordSelect.text();\r\n                }\r\n\r\n                this.eventEmitter.emit(XMPPEvents.INVITE_MESSAGE_RECEIVED,\r\n                    from, invite.attr('from'), txt, password);\r\n            }\r\n        }\r\n\r\n        const jsonMessage = $(msg).find('>json-message').text();\r\n\r\n        if (jsonMessage) {\r\n            const parsedJson = this.xmpp.tryParseJSONAndVerify(jsonMessage);\r\n\r\n            // We emit this event if the message is a valid json, and is not\r\n            // delivered after a delay, i.e. stamp is undefined.\r\n            // e.g. - subtitles should not be displayed if delayed.\r\n            if (parsedJson && stamp === undefined) {\r\n                this.eventEmitter.emit(XMPPEvents.JSON_MESSAGE_RECEIVED,\r\n                    from, parsedJson);\r\n\r\n                return;\r\n            }\r\n        }\r\n\r\n        if (txt) {\r\n            if (type === 'chat') {\r\n                this.eventEmitter.emit(XMPPEvents.PRIVATE_MESSAGE_RECEIVED,\r\n                        from, txt, this.myroomjid, stamp);\r\n            } else if (type === 'groupchat') {\r\n                this.eventEmitter.emit(XMPPEvents.MESSAGE_RECEIVED,\r\n                        from, txt, this.myroomjid, stamp);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param pres\r\n     * @param from\r\n     */\r\n    onPresenceError(pres, from) {\r\n        if ($(pres)\r\n                .find(\r\n                    '>error[type=\"auth\"]'\r\n                        + '>not-authorized['\r\n                        + 'xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"]')\r\n                .length) {\r\n            logger.log('on password required', from);\r\n            this.eventEmitter.emit(XMPPEvents.PASSWORD_REQUIRED);\r\n        } else if ($(pres)\r\n                .find(\r\n                    '>error[type=\"cancel\"]'\r\n                        + '>not-allowed['\r\n                        + 'xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"]')\r\n                .length) {\r\n            const toDomain = Strophe.getDomainFromJid(pres.getAttribute('to'));\r\n\r\n            if (toDomain === this.xmpp.options.hosts.anonymousdomain) {\r\n                // enter the room by replying with 'not-authorized'. This would\r\n                // result in reconnection from authorized domain.\r\n                // We're either missing Jicofo/Prosody config for anonymous\r\n                // domains or something is wrong.\r\n                this.eventEmitter.emit(XMPPEvents.ROOM_JOIN_ERROR);\r\n\r\n            } else {\r\n                logger.warn('onPresError ', pres);\r\n                this.eventEmitter.emit(\r\n                    XMPPEvents.ROOM_CONNECT_NOT_ALLOWED_ERROR);\r\n            }\r\n        } else if ($(pres).find('>error>service-unavailable').length) {\r\n            logger.warn('Maximum users limit for the room has been reached',\r\n                pres);\r\n            this.eventEmitter.emit(XMPPEvents.ROOM_MAX_USERS_ERROR);\r\n        } else if ($(pres)\r\n            .find(\r\n                '>error[type=\"auth\"]'\r\n                + '>registration-required['\r\n                + 'xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"]').length) {\r\n\r\n            // let's extract the lobby jid from the custom field\r\n            const lobbyRoomNode = $(pres).find('>error[type=\"auth\"]>lobbyroom');\r\n            let lobbyRoomJid;\r\n\r\n            if (lobbyRoomNode.length) {\r\n                lobbyRoomJid = lobbyRoomNode.text();\r\n            } else {\r\n                // let's fallback to old location of lobbyroom node, TODO: to be removed in the future once\r\n                // everything is updated\r\n                const lobbyRoomOldNode = $(pres).find('>lobbyroom');\r\n\r\n                if (lobbyRoomOldNode.length) {\r\n                    lobbyRoomJid = lobbyRoomOldNode.text();\r\n                }\r\n            }\r\n\r\n            this.eventEmitter.emit(XMPPEvents.ROOM_CONNECT_MEMBERS_ONLY_ERROR, lobbyRoomJid);\r\n        } else {\r\n            logger.warn('onPresError ', pres);\r\n            this.eventEmitter.emit(XMPPEvents.ROOM_CONNECT_ERROR);\r\n        }\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param jid\r\n     * @param affiliation\r\n     */\r\n    setAffiliation(jid, affiliation) {\r\n        const grantIQ = $iq({\r\n            to: this.roomjid,\r\n            type: 'set'\r\n        })\r\n        .c('query', { xmlns: 'http://jabber.org/protocol/muc#admin' })\r\n        .c('item', {\r\n            affiliation,\r\n            jid: Strophe.getBareJidFromJid(jid)\r\n        })\r\n        .c('reason').t(`Your affiliation has been changed to '${affiliation}'.`)\r\n        .up().up().up();\r\n\r\n        this.connection.sendIQ(\r\n            grantIQ,\r\n            result => logger.log('Set affiliation of participant with jid: ', jid, 'to', affiliation, result),\r\n            error => logger.log('Set affiliation of participant error: ', error));\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param jid\r\n     * @param reason\r\n     */\r\n    kick(jid, reason = 'You have been kicked.') {\r\n        const kickIQ = $iq({ to: this.roomjid,\r\n            type: 'set' })\r\n            .c('query', { xmlns: 'http://jabber.org/protocol/muc#admin' })\r\n            .c('item', { nick: Strophe.getResourceFromJid(jid),\r\n                role: 'none' })\r\n            .c('reason').t(reason).up().up().up();\r\n\r\n        this.connection.sendIQ(\r\n            kickIQ,\r\n            result => logger.log('Kick participant with jid: ', jid, result),\r\n            error => logger.log('Kick participant error: ', error));\r\n    }\r\n\r\n    /* eslint-disable max-params */\r\n\r\n    /**\r\n     *\r\n     * @param key\r\n     * @param onSuccess\r\n     * @param onError\r\n     * @param onNotSupported\r\n     */\r\n    lockRoom(key, onSuccess, onError, onNotSupported) {\r\n        // http://xmpp.org/extensions/xep-0045.html#roomconfig\r\n        this.connection.sendIQ(\r\n            $iq({\r\n                to: this.roomjid,\r\n                type: 'get'\r\n            })\r\n                .c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' }),\r\n            res => {\r\n                if ($(res)\r\n                        .find(\r\n                            '>query>x[xmlns=\"jabber:x:data\"]'\r\n                                + '>field[var=\"muc#roomconfig_roomsecret\"]')\r\n                        .length) {\r\n                    const formsubmit\r\n                        = $iq({\r\n                            to: this.roomjid,\r\n                            type: 'set'\r\n                        })\r\n                            .c('query', {\r\n                                xmlns: 'http://jabber.org/protocol/muc#owner'\r\n                            });\r\n\r\n                    formsubmit.c('x', {\r\n                        xmlns: 'jabber:x:data',\r\n                        type: 'submit'\r\n                    });\r\n                    formsubmit\r\n                        .c('field', { 'var': 'FORM_TYPE' })\r\n                        .c('value')\r\n                        .t('http://jabber.org/protocol/muc#roomconfig')\r\n                        .up()\r\n                        .up();\r\n                    formsubmit\r\n                        .c('field', { 'var': 'muc#roomconfig_roomsecret' })\r\n                        .c('value')\r\n                        .t(key)\r\n                        .up()\r\n                        .up();\r\n                    formsubmit\r\n                        .c('field',\r\n                             { 'var': 'muc#roomconfig_passwordprotectedroom' })\r\n                        .c('value')\r\n                        .t(key === null || key.length === 0 ? '0' : '1')\r\n                        .up()\r\n                        .up();\r\n\r\n                    // if members only enabled\r\n                    if (this.membersOnlyEnabled) {\r\n                        formsubmit\r\n                            .c('field', { 'var': 'muc#roomconfig_membersonly' })\r\n                            .c('value')\r\n                            .t('true')\r\n                            .up()\r\n                            .up();\r\n                    }\r\n\r\n                    // Fixes a bug in prosody 0.9.+\r\n                    // https://prosody.im/issues/issue/373\r\n                    formsubmit\r\n                        .c('field', { 'var': 'muc#roomconfig_whois' })\r\n                        .c('value')\r\n                        .t('anyone')\r\n                        .up()\r\n                        .up();\r\n\r\n                    this.connection.sendIQ(\r\n                        formsubmit,\r\n                        () => {\r\n\r\n                            // we set the password in chat room so we can use it\r\n                            // later when dialing out\r\n                            this.password = key;\r\n                            onSuccess();\r\n                        },\r\n                        onError);\r\n                } else {\r\n                    onNotSupported();\r\n                }\r\n            },\r\n            onError);\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * Turns off or on the members only config for the main room.\r\n     *\r\n     * @param {boolean} enabled - Whether to turn it on or off.\r\n     * @param onSuccess - optional callback.\r\n     * @param onError - optional callback.\r\n     */\r\n    setMembersOnly(enabled, onSuccess, onError) {\r\n        if (enabled && Object.values(this.members).filter(m => !m.isFocus).length) {\r\n            // first grant membership to all that are in the room\r\n            // currently there is a bug in prosody where it handles only the first item\r\n            // that's why we will send iq per member\r\n            Object.values(this.members).forEach(m => {\r\n                if (m.jid && !MEMBERS_AFFILIATIONS.includes(m.affiliation)) {\r\n                    this.xmpp.connection.sendIQ(\r\n                        $iq({\r\n                            to: this.roomjid,\r\n                            type: 'set' })\r\n                        .c('query', {\r\n                            xmlns: 'http://jabber.org/protocol/muc#admin' })\r\n                        .c('item', {\r\n                            'affiliation': 'member',\r\n                            'jid': Strophe.getBareJidFromJid(m.jid)\r\n                        }).up().up());\r\n                }\r\n            });\r\n        }\r\n\r\n        const errorCallback = onError ? onError : () => {}; // eslint-disable-line no-empty-function\r\n\r\n        this.xmpp.connection.sendIQ(\r\n            $iq({\r\n                to: this.roomjid,\r\n                type: 'get'\r\n            }).c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' }),\r\n            res => {\r\n                if ($(res).find('>query>x[xmlns=\"jabber:x:data\"]>field[var=\"muc#roomconfig_membersonly\"]').length) {\r\n                    const formToSubmit\r\n                        = $iq({\r\n                            to: this.roomjid,\r\n                            type: 'set'\r\n                        }).c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' });\r\n\r\n                    formToSubmit.c('x', {\r\n                        xmlns: 'jabber:x:data',\r\n                        type: 'submit'\r\n                    });\r\n                    formToSubmit\r\n                        .c('field', { 'var': 'FORM_TYPE' })\r\n                        .c('value')\r\n                        .t('http://jabber.org/protocol/muc#roomconfig')\r\n                        .up()\r\n                        .up();\r\n                    formToSubmit\r\n                        .c('field', { 'var': 'muc#roomconfig_membersonly' })\r\n                        .c('value')\r\n                        .t(enabled ? 'true' : 'false')\r\n                        .up()\r\n                        .up();\r\n\r\n                    // if room is locked from other participant or we are locking it\r\n                    if (this.locked) {\r\n                        formToSubmit\r\n                            .c('field',\r\n                                { 'var': 'muc#roomconfig_passwordprotectedroom' })\r\n                            .c('value')\r\n                            .t('1')\r\n                            .up()\r\n                            .up();\r\n                    }\r\n\r\n                    this.xmpp.connection.sendIQ(formToSubmit, onSuccess, errorCallback);\r\n                } else {\r\n                    errorCallback(new Error('Setting members only room not supported!'));\r\n                }\r\n            },\r\n            errorCallback);\r\n    }\r\n\r\n    /**\r\n     * Adds the key to the presence map, overriding any previous value.\r\n     * This method is used by jibri.\r\n     *\r\n     * @param key The key to add or replace.\r\n     * @param values The new values.\r\n     * @returns {boolean|null} <tt>true</tt> if the operation succeeded or <tt>false</tt> when no add or replce was\r\n     * performed as the value was already there.\r\n     * @deprecated Use 'addOrReplaceInPresence' instead. TODO: remove it from here and jibri.\r\n     */\r\n    addToPresence(key, values) {\r\n        return this.addOrReplaceInPresence(key, values);\r\n    }\r\n\r\n    /**\r\n     * Adds the key to the presence map, overriding any previous value.\r\n     * @param key The key to add or replace.\r\n     * @param values The new values.\r\n     * @returns {boolean|null} <tt>true</tt> if the operation succeeded or <tt>false</tt> when no add or replace was\r\n     * performed as the value was already there.\r\n     */\r\n    addOrReplaceInPresence(key, values) {\r\n        values.tagName = key;\r\n\r\n        const matchingNodes = this.presMap.nodes.filter(node => key === node.tagName);\r\n\r\n        // if we have found just one, let's check is it the same\r\n        if (matchingNodes.length === 1 && isEqual(matchingNodes[0], values)) {\r\n            return false;\r\n        }\r\n\r\n        this.removeFromPresence(key);\r\n        this.presMap.nodes.push(values);\r\n        this.presenceUpdateTime = Date.now();\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * Retrieves a value from the presence map.\r\n     *\r\n     * @param {string} key - The key to find the value for.\r\n     * @returns {Object?}\r\n     */\r\n    getFromPresence(key) {\r\n        return this.presMap.nodes.find(node => key === node.tagName);\r\n    }\r\n\r\n    /**\r\n     * Removes a key from the presence map.\r\n     * @param key\r\n     */\r\n    removeFromPresence(key) {\r\n        const nodes = this.presMap.nodes.filter(node => key !== node.tagName);\r\n\r\n        this.presMap.nodes = nodes;\r\n        this.presenceUpdateTime = Date.now();\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param name\r\n     * @param handler\r\n     */\r\n    addPresenceListener(name, handler) {\r\n        if (typeof handler !== 'function') {\r\n            throw new Error('\"handler\" is not a function');\r\n        }\r\n        let tagHandlers = this.presHandlers[name];\r\n\r\n        if (!tagHandlers) {\r\n            this.presHandlers[name] = tagHandlers = [];\r\n        }\r\n        if (tagHandlers.indexOf(handler) === -1) {\r\n            tagHandlers.push(handler);\r\n        } else {\r\n            logger.warn(\r\n                `Trying to add the same handler more than once for: ${name}`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param name\r\n     * @param handler\r\n     */\r\n    removePresenceListener(name, handler) {\r\n        const tagHandlers = this.presHandlers[name];\r\n        const handlerIdx = tagHandlers ? tagHandlers.indexOf(handler) : -1;\r\n\r\n        // eslint-disable-next-line no-negated-condition\r\n        if (handlerIdx !== -1) {\r\n            tagHandlers.splice(handlerIdx, 1);\r\n        } else {\r\n            logger.warn(`Handler for: ${name} was not registered`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Checks if the user identified by given <tt>mucJid</tt> is the conference\r\n     * focus.\r\n     * @param mucJid the full MUC address of the user to be checked.\r\n     * @returns {boolean|null} <tt>true</tt> if MUC user is the conference focus\r\n     * or <tt>false</tt> if is not. When given <tt>mucJid</tt> does not exist in\r\n     * the MUC then <tt>null</tt> is returned.\r\n     */\r\n    isFocus(mucJid) {\r\n        const member = this.members[mucJid];\r\n\r\n        if (member) {\r\n            return member.isFocus;\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     *\r\n     */\r\n    isModerator() {\r\n        return this.role === 'moderator';\r\n    }\r\n\r\n    /**\r\n     * Obtains the info about given media advertised (in legacy format) in the MUC presence of the participant\r\n     * identified by the given endpoint JID. This is for mantining interop with endpoints that do not support\r\n     * source-name signaling (Jigasi and very old mobile clients).\r\n     *\r\n     * @param {string} endpointId the endpoint ID mapped to the participant which corresponds to MUC nickname.\r\n     * @param {MediaType} mediaType the type of the media for which presence info will be obtained.\r\n     * @return {PeerMediaInfo} presenceInfo an object with media presence info or <tt>null</tt> either if there\r\n     * is no presence available or if the media type given is invalid.\r\n     */\r\n    getMediaPresenceInfo(endpointId, mediaType) {\r\n        // Will figure out current muted status by looking up owner's presence\r\n        const pres = this.lastPresences[`${this.roomjid}/${endpointId}`];\r\n\r\n        if (!pres) {\r\n            // No presence available\r\n            return null;\r\n        }\r\n        const data = {\r\n            muted: true, // muted by default\r\n            videoType: mediaType === MediaType.VIDEO ? VideoType.CAMERA : undefined // 'camera' by default\r\n        };\r\n        let mutedNode = null;\r\n\r\n        if (mediaType === MediaType.AUDIO) {\r\n            mutedNode = filterNodeFromPresenceJSON(pres, 'audiomuted');\r\n        } else if (mediaType === MediaType.VIDEO) {\r\n            mutedNode = filterNodeFromPresenceJSON(pres, 'videomuted');\r\n            const codecTypeNode = filterNodeFromPresenceJSON(pres, 'jitsi_participant_codecType');\r\n            const videoTypeNode = filterNodeFromPresenceJSON(pres, 'videoType');\r\n\r\n            if (videoTypeNode.length > 0) {\r\n                data.videoType = videoTypeNode[0].value;\r\n            }\r\n            if (codecTypeNode.length > 0) {\r\n                data.codecType = codecTypeNode[0].value;\r\n            }\r\n        } else {\r\n            logger.error(`Unsupported media type: ${mediaType}`);\r\n\r\n            return null;\r\n        }\r\n\r\n        if (mutedNode.length > 0) {\r\n            data.muted = mutedNode[0].value === 'true';\r\n        }\r\n\r\n        return data;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param peerJid\r\n     */\r\n    getMemberRole(peerJid) {\r\n        if (this.members[peerJid]) {\r\n            return this.members[peerJid].role;\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * Returns the last presence advertised by a MUC member.\r\n     * @param {string} mucNick\r\n     * @returns {*}\r\n     */\r\n    getLastPresence(mucNick) {\r\n        return this.lastPresences[`${this.roomjid}/${mucNick}`];\r\n    }\r\n\r\n    /**\r\n     * Returns true if the SIP calls are supported and false otherwise\r\n     */\r\n    isSIPCallingSupported() {\r\n        if (this.moderator) {\r\n            return this.moderator.isSipGatewayEnabled();\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * Dials a number.\r\n     * @param number the number\r\n     */\r\n    dial(number) {\r\n        return this.connection.rayo.dial(number, 'fromnumber',\r\n            Strophe.getBareJidFromJid(this.myroomjid), this.password,\r\n            this.focusMucJid);\r\n    }\r\n\r\n    /**\r\n     * Hangup an existing call\r\n     */\r\n    hangup() {\r\n        return this.connection.rayo.hangup();\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @returns {Lobby}\r\n     */\r\n    getLobby() {\r\n        return this.lobby;\r\n    }\r\n\r\n    /**\r\n     * @returns {AVModeration}\r\n     */\r\n    getAVModeration() {\r\n        return this.avModeration;\r\n    }\r\n\r\n    /**\r\n     * @returns {BreakoutRooms}\r\n     */\r\n    getBreakoutRooms() {\r\n        return this.breakoutRooms;\r\n    }\r\n\r\n    /**\r\n     * @returns {RoomMetadata}\r\n     */\r\n    getMetadataHandler() {\r\n        return this.roomMetadata;\r\n    }\r\n\r\n    /**\r\n     * Returns the phone number for joining the conference.\r\n     */\r\n    getPhoneNumber() {\r\n        return this.phoneNumber;\r\n    }\r\n\r\n    /**\r\n     * Returns the pin for joining the conference with phone.\r\n     */\r\n    getPhonePin() {\r\n        return this.phonePin;\r\n    }\r\n\r\n    /**\r\n     * Returns the meeting unique ID if any came from backend.\r\n     *\r\n     * @returns {string} - The meeting ID.\r\n     */\r\n    getMeetingId() {\r\n        return this.meetingId;\r\n    }\r\n\r\n    /**\r\n     * Mutes remote participant.\r\n     * @param jid of the participant\r\n     * @param mute\r\n     * @param mediaType\r\n     */\r\n    muteParticipant(jid, mute, mediaType) {\r\n        logger.info('set mute', mute, jid);\r\n        const iqToFocus = $iq(\r\n            { to: this.focusMucJid,\r\n                type: 'set' })\r\n            .c('mute', {\r\n                xmlns: `http://jitsi.org/jitmeet/${mediaType}`,\r\n                jid\r\n            })\r\n            .t(mute.toString())\r\n            .up();\r\n\r\n        this.connection.sendIQ(\r\n            iqToFocus,\r\n            result => logger.log('set mute', result),\r\n            error => logger.log('set mute error', error));\r\n    }\r\n\r\n    /**\r\n     * TODO: Document\r\n     * @param iq\r\n     */\r\n    onMute(iq) {\r\n        const from = iq.getAttribute('from');\r\n\r\n        if (from !== this.focusMucJid) {\r\n            logger.warn('Ignored mute from non focus peer');\r\n\r\n            return;\r\n        }\r\n        const mute = $(iq).find('mute');\r\n\r\n        if (mute.length && mute.text() === 'true') {\r\n            this.eventEmitter.emit(XMPPEvents.AUDIO_MUTED_BY_FOCUS, mute.attr('actor'));\r\n        } else {\r\n            // XXX Why do we support anything but muting? Why do we encode the\r\n            // value in the text of the element? Why do we use a separate XML\r\n            // namespace?\r\n            logger.warn('Ignoring a mute request which does not explicitly '\r\n                + 'specify a positive mute command.');\r\n        }\r\n    }\r\n\r\n    /**\r\n     * TODO: Document\r\n     * @param iq\r\n     */\r\n    onMuteVideo(iq) {\r\n        const from = iq.getAttribute('from');\r\n\r\n        if (from !== this.focusMucJid) {\r\n            logger.warn('Ignored mute from non focus peer');\r\n\r\n            return;\r\n        }\r\n        const mute = $(iq).find('mute');\r\n\r\n        if (mute.length && mute.text() === 'true') {\r\n            this.eventEmitter.emit(XMPPEvents.VIDEO_MUTED_BY_FOCUS, mute.attr('actor'));\r\n        } else {\r\n            // XXX Why do we support anything but muting? Why do we encode the\r\n            // value in the text of the element? Why do we use a separate XML\r\n            // namespace?\r\n            logger.warn('Ignoring a mute request which does not explicitly '\r\n                + 'specify a positive mute command.');\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Clean any listeners or resources, executed on leaving.\r\n     */\r\n    clean() {\r\n        this._removeConnListeners.forEach(remove => remove());\r\n        this._removeConnListeners = [];\r\n\r\n        this.joined = false;\r\n        this.inProgressEmitted = false;\r\n    }\r\n\r\n    /**\r\n     * Leaves the room. Closes the jingle session.\r\n     * @returns {Promise} which is resolved if XMPPEvents.MUC_LEFT is received\r\n     * less than 5s after sending presence unavailable. Otherwise the promise is\r\n     * rejected.\r\n     */\r\n    leave(reason) {\r\n        this.avModeration.dispose();\r\n        this.breakoutRooms.dispose();\r\n        this.roomMetadata.dispose();\r\n\r\n        const promises = [];\r\n\r\n        this.lobby?.lobbyRoom && promises.push(this.lobby.leave());\r\n\r\n        promises.push(new Promise((resolve, reject) => {\r\n            let timeout = -1;\r\n\r\n            const onMucLeft = (doReject = false) => {\r\n                this.eventEmitter.removeListener(XMPPEvents.MUC_LEFT, onMucLeft);\r\n                clearTimeout(timeout);\r\n                if (doReject) {\r\n                    // The timeout expired. Make sure we clean the EMUC state.\r\n                    this.connection.emuc.doLeave(this.roomjid);\r\n                    reject(new Error('The timeout for the confirmation about leaving the room expired.'));\r\n                } else {\r\n                    resolve();\r\n                }\r\n            };\r\n\r\n            timeout = setTimeout(() => onMucLeft(true), 5000);\r\n\r\n            this.clean();\r\n            this.eventEmitter.on(XMPPEvents.MUC_LEFT, onMucLeft);\r\n            this.doLeave(reason);\r\n        }));\r\n\r\n        return Promise.allSettled(promises);\r\n    }\r\n\r\n    /**\r\n     * Ends the conference for all participants.\r\n     */\r\n    end() {\r\n        if (this.breakoutRooms.isBreakoutRoom()) {\r\n            logger.warn('Cannot end conference: this is a breakout room.');\r\n\r\n            return;\r\n        }\r\n\r\n        // Send the end conference message.\r\n        const msg = $msg({ to: this.xmpp.endConferenceComponentAddress });\r\n\r\n        msg.c('end_conference').up();\r\n\r\n        this.xmpp.connection.send(msg);\r\n    }\r\n}\r\n\r\n/* eslint-enable newline-per-chained-call */\r\n","import { getLogger } from '@jitsi/logger';\r\nimport $ from 'jquery';\r\nimport { Strophe } from 'strophe.js';\r\n\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\n\r\nimport ChatRoom from './ChatRoom';\r\nimport { ConnectionPluginListenable } from './ConnectionPlugin';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * MUC connection plugin.\r\n */\r\nexport default class MucConnectionPlugin extends ConnectionPluginListenable {\r\n    /**\r\n     *\r\n     * @param xmpp\r\n     */\r\n    constructor(xmpp) {\r\n        super();\r\n        this.xmpp = xmpp;\r\n        this.rooms = {};\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param connection\r\n     */\r\n    init(connection) {\r\n        super.init(connection);\r\n\r\n        // add handlers (just once)\r\n        this.connection.addHandler(this.onPresence.bind(this), null,\r\n            'presence', null, null, null, null);\r\n        this.connection.addHandler(this.onPresenceUnavailable.bind(this),\r\n            null, 'presence', 'unavailable', null);\r\n        this.connection.addHandler(this.onPresenceError.bind(this), null,\r\n            'presence', 'error', null);\r\n        this.connection.addHandler(this.onMessage.bind(this), null,\r\n            'message', null, null);\r\n        this.connection.addHandler(this.onMute.bind(this),\r\n            'http://jitsi.org/jitmeet/audio', 'iq', 'set', null, null);\r\n        this.connection.addHandler(this.onMuteVideo.bind(this),\r\n            'http://jitsi.org/jitmeet/video', 'iq', 'set', null, null);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param jid\r\n     * @param password\r\n     * @param options\r\n     */\r\n    createRoom(jid, password, options) {\r\n        const roomJid = Strophe.getBareJidFromJid(jid);\r\n\r\n        if (this.isRoomCreated(roomJid)) {\r\n            const errmsg = 'You are already in the room!';\r\n\r\n            logger.error(errmsg);\r\n            throw new Error(errmsg);\r\n        }\r\n        this.rooms[roomJid] = new ChatRoom(this.connection, jid,\r\n            password, this.xmpp, options);\r\n        this.eventEmitter.emit(\r\n            XMPPEvents.EMUC_ROOM_ADDED, this.rooms[roomJid]);\r\n\r\n        return this.rooms[roomJid];\r\n    }\r\n\r\n    /**\r\n     *  Check if a room with the passed JID is already created.\r\n     *\r\n     * @param {string} roomJid - The JID of the room.\r\n     * @returns {boolean}\r\n     */\r\n    isRoomCreated(roomJid) {\r\n        return roomJid in this.rooms;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param jid\r\n     */\r\n    doLeave(jid) {\r\n        this.eventEmitter.emit(\r\n            XMPPEvents.EMUC_ROOM_REMOVED, this.rooms[jid]);\r\n        delete this.rooms[jid];\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param pres\r\n     */\r\n    onPresence(pres) {\r\n        const from = pres.getAttribute('from');\r\n\r\n        // What is this for? A workaround for something?\r\n        if (pres.getAttribute('type')) {\r\n            return true;\r\n        }\r\n\r\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\r\n\r\n        if (!room) {\r\n            return true;\r\n        }\r\n\r\n        // Parse status.\r\n        if ($(pres).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\r\n            + '>status[code=\"201\"]').length) {\r\n            room.createNonAnonymousRoom();\r\n        }\r\n\r\n        room.onPresence(pres);\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param pres\r\n     */\r\n    onPresenceUnavailable(pres) {\r\n        const from = pres.getAttribute('from');\r\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\r\n\r\n        if (!room) {\r\n            return true;\r\n        }\r\n\r\n        room.onPresenceUnavailable(pres, from);\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param pres\r\n     */\r\n    onPresenceError(pres) {\r\n        const from = pres.getAttribute('from');\r\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\r\n\r\n        if (!room) {\r\n            return true;\r\n        }\r\n\r\n        room.onPresenceError(pres, from);\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param msg\r\n     */\r\n    onMessage(msg) {\r\n        // FIXME: this is a hack. but jingle on muc makes nickchanges hard\r\n        const from = msg.getAttribute('from');\r\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\r\n\r\n        if (!room) {\r\n            return true;\r\n        }\r\n\r\n        room.onMessage(msg, from);\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * TODO: Document\r\n     * @param iq\r\n     */\r\n    onMute(iq) {\r\n        const from = iq.getAttribute('from');\r\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\r\n\r\n        // Returning false would result in the listener being deregistered by Strophe\r\n        if (!room) {\r\n            return true;\r\n        }\r\n\r\n        room.onMute(iq);\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * TODO: Document\r\n     * @param iq\r\n     */\r\n    onMuteVideo(iq) {\r\n        const from = iq.getAttribute('from');\r\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\r\n\r\n        // Returning false would result in the listener being deregistered by Strophe\r\n        if (!room) {\r\n            return true;\r\n        }\r\n\r\n        room.onMuteVideo(iq);\r\n\r\n        return true;\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport $ from 'jquery';\r\nimport { $build } from 'strophe.js';\r\n\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Creates a \"source\" XML element for the source described in compact JSON format in [sourceCompactJson].\r\n * @param {*} owner the endpoint ID of the owner of the source.\r\n * @param {*} sourceCompactJson the compact JSON representation of the source.\r\n * @returns the created \"source\" XML element.\r\n */\r\nfunction _createSourceExtension(owner, sourceCompactJson) {\r\n    const node = $build('source', {\r\n        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\r\n        ssrc: sourceCompactJson.s,\r\n        name: sourceCompactJson.n\r\n    });\r\n\r\n    if (sourceCompactJson.m) {\r\n        node.c('parameter', {\r\n            name: 'msid',\r\n            value: sourceCompactJson.m\r\n        }).up();\r\n    }\r\n    node.c('ssrc-info', {\r\n        xmlns: 'http://jitsi.org/jitmeet',\r\n        owner\r\n    }).up();\r\n\r\n    return node.node;\r\n}\r\n\r\n/**\r\n * Creates an \"ssrc-group\" XML element for the SSRC group described in compact JSON format in [ssrcGroupCompactJson].\r\n * @param {*} ssrcGroupCompactJson the compact JSON representation of the SSRC group.\r\n * @returns the created \"ssrc-group\" element.\r\n */\r\nfunction _createSsrcGroupExtension(ssrcGroupCompactJson) {\r\n    const node = $build('ssrc-group', {\r\n        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\r\n        semantics: _getSemantics(ssrcGroupCompactJson[0])\r\n    });\r\n\r\n    for (let i = 1; i < ssrcGroupCompactJson.length; i++) {\r\n        node.c('source', {\r\n            xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\r\n            ssrc: ssrcGroupCompactJson[i]\r\n        }).up();\r\n    }\r\n\r\n    return node.node;\r\n}\r\n\r\n/**\r\n * Finds in a Jingle IQ the RTP description element with the given media type. If one does not exists, create it (as\r\n *  well as the required  \"content\" parent element) and adds it to the IQ.\r\n * @param {*} iq\r\n * @param {*} mediaType The media type, \"audio\" or \"video\".\r\n * @returns the RTP description element with the given media type.\r\n */\r\nfunction _getOrCreateRtpDescription(iq, mediaType) {\r\n    const jingle = $(iq).find('jingle')[0];\r\n    let content = $(jingle).find(`content[name=\"${mediaType}\"]`);\r\n    let description;\r\n\r\n    if (content.length) {\r\n        content = content[0];\r\n    } else {\r\n        // I'm not suree if \"creator\" and \"senders\" are required.\r\n        content = $build('content', {\r\n            name: mediaType\r\n        }).node;\r\n        jingle.appendChild(content);\r\n    }\r\n\r\n    description = $(content).find('description');\r\n\r\n    if (description.length) {\r\n        description = description[0];\r\n    } else {\r\n        description = $build('description', {\r\n            xmlns: 'urn:xmpp:jingle:apps:rtp:1',\r\n            media: mediaType\r\n        }).node;\r\n        content.appendChild(description);\r\n    }\r\n\r\n    return description;\r\n}\r\n\r\n/**\r\n * Converts the short string representing SSRC group semantics in compact JSON format to the standard representation\r\n * (i.e. convert \"f\" to \"FID\" and \"s\" to \"SIM\").\r\n * @param {*} str the compact JSON format representation of an SSRC group's semantics.\r\n * @returns the SSRC group semantics corresponding to [str].\r\n */\r\nfunction _getSemantics(str) {\r\n    if (str === 'f') {\r\n        return 'FID';\r\n    } else if (str === 's') {\r\n        return 'SIM';\r\n    }\r\n\r\n    return null;\r\n}\r\n\r\n/**\r\n * Reads a JSON-encoded message (from a \"json-message\" element) and extracts source descriptions. Adds the extracted\r\n * source descriptions to the given Jingle IQ in the standard Jingle format.\r\n *\r\n * Encoding sources in this compact JSON format instead of standard Jingle was introduced in order to reduce the\r\n * network traffic and load on the XMPP server. The format is described in Jicofo [TODO: insert link].\r\n *\r\n * @param {*} iq the IQ to which source descriptions will be added.\r\n * @param {*} jsonMessageXml The XML node for the \"json-message\" element.\r\n * @returns {Map<string, Array<string>} The audio and video ssrcs extracted from the JSON-encoded message with remote\r\n * endpoint id as the key.\r\n */\r\nexport function expandSourcesFromJson(iq, jsonMessageXml) {\r\n    let json;\r\n\r\n    try {\r\n        json = JSON.parse(jsonMessageXml.textContent);\r\n    } catch (error) {\r\n        logger.error(`json-message XML contained invalid JSON, ignoring: ${jsonMessageXml.textContent}`);\r\n\r\n        return null;\r\n    }\r\n\r\n    if (!json?.sources) {\r\n        // It might be a message of a different type, no need to log.\r\n        return null;\r\n    }\r\n\r\n    // This is where we'll add \"source\" and \"ssrc-group\" elements. Create them elements if they don't exist.\r\n    const audioRtpDescription = _getOrCreateRtpDescription(iq, MediaType.AUDIO);\r\n    const videoRtpDescription = _getOrCreateRtpDescription(iq, MediaType.VIDEO);\r\n    const ssrcMap = new Map();\r\n\r\n    for (const owner in json.sources) {\r\n        if (json.sources.hasOwnProperty(owner)) {\r\n            const ssrcs = [];\r\n            const ownerSources = json.sources[owner];\r\n\r\n            // The video sources, video ssrc-groups, audio sources and audio ssrc-groups are encoded in that order in\r\n            // the elements of the array.\r\n            const videoSources = ownerSources?.length && ownerSources[0];\r\n            const videoSsrcGroups = ownerSources?.length > 1 && ownerSources[1];\r\n            const audioSources = ownerSources?.length > 2 && ownerSources[2];\r\n            const audioSsrcGroups = ownerSources?.length > 3 && ownerSources[3];\r\n\r\n            if (videoSources?.length) {\r\n                for (let i = 0; i < videoSources.length; i++) {\r\n                    videoRtpDescription.appendChild(_createSourceExtension(owner, videoSources[i]));\r\n                    ssrcs.push(videoSources[i]?.s);\r\n                }\r\n            }\r\n\r\n            if (videoSsrcGroups?.length) {\r\n                for (let i = 0; i < videoSsrcGroups.length; i++) {\r\n                    videoRtpDescription.appendChild(_createSsrcGroupExtension(videoSsrcGroups[i]));\r\n                }\r\n            }\r\n            if (audioSources?.length) {\r\n                for (let i = 0; i < audioSources.length; i++) {\r\n                    audioRtpDescription.appendChild(_createSourceExtension(owner, audioSources[i]));\r\n                    ssrcs.push(audioSources[i]?.s);\r\n                }\r\n            }\r\n\r\n            if (audioSsrcGroups?.length) {\r\n                for (let i = 0; i < audioSsrcGroups.length; i++) {\r\n                    audioRtpDescription.appendChild(_createSsrcGroupExtension(audioSsrcGroups[i]));\r\n                }\r\n            }\r\n            ssrcMap.set(owner, ssrcs);\r\n        }\r\n    }\r\n\r\n    return ssrcMap;\r\n}\r\n","/**\r\n * Enumeration of the media direction types.\r\n */\r\nexport enum MediaDirection {\r\n    /**\r\n     * Media is send and receive is suspended.\r\n     */\r\n    INACTIVE = 'inactive',\r\n\r\n    /**\r\n     * Media is only received from remote peer.\r\n     */\r\n    RECVONLY = 'recvonly',\r\n\r\n    /**\r\n     * Media is only sent to the remote peer.\r\n     */\r\n    SENDONLY = 'sendonly',\r\n\r\n    /**\r\n     * Media is sent and received.\r\n     */\r\n    SENDRECV = 'sendrecv'\r\n};\r\n","\r\nimport JitsiTrackError from '../../JitsiTrackError';\r\nimport * as JitsiTrackErrors from '../../JitsiTrackErrors';\r\nimport browser from '../browser';\r\n\r\nconst logger = require('@jitsi/logger').getLogger(__filename);\r\n\r\n/**\r\n * The default frame rate for Screen Sharing.\r\n */\r\nexport const SS_DEFAULT_FRAME_RATE = 5;\r\n\r\n/**\r\n * Handles obtaining a stream from a screen capture on different browsers.\r\n */\r\nconst ScreenObtainer = {\r\n    /**\r\n     * If not <tt>null</tt> it means that the initialization process is still in\r\n     * progress. It is used to make desktop stream request wait and continue\r\n     * after it's done.\r\n     * {@type Promise|null}\r\n     */\r\n\r\n    obtainStream: null,\r\n\r\n    /**\r\n     * Initializes the function used to obtain a screen capture\r\n     * (this.obtainStream).\r\n     *\r\n     * @param {object} options\r\n     */\r\n    init(options = {}) {\r\n        this.options = options;\r\n        this.obtainStream = this._createObtainStreamMethod();\r\n\r\n        if (!this.obtainStream) {\r\n            logger.info('Desktop sharing disabled');\r\n        }\r\n    },\r\n\r\n    /**\r\n     * Returns a method which will be used to obtain the screen sharing stream\r\n     * (based on the browser type).\r\n     *\r\n     * @returns {Function}\r\n     * @private\r\n     */\r\n    _createObtainStreamMethod() {\r\n        if (browser.isNWJS()) {\r\n            return (onSuccess, onFailure) => {\r\n                window.JitsiMeetNW.obtainDesktopStream(\r\n                    onSuccess,\r\n                    (error, constraints) => {\r\n                        let jitsiError;\r\n\r\n                        // FIXME:\r\n                        // This is very very dirty fix for recognising that the\r\n                        // user have clicked the cancel button from the Desktop\r\n                        // sharing pick window. The proper solution would be to\r\n                        // detect this in the NWJS application by checking the\r\n                        // streamId === \"\". Even better solution would be to\r\n                        // stop calling GUM from the NWJS app and just pass the\r\n                        // streamId to lib-jitsi-meet. This way the desktop\r\n                        // sharing implementation for NWJS and chrome extension\r\n                        // will be the same and lib-jitsi-meet will be able to\r\n                        // control the constraints, check the streamId, etc.\r\n                        //\r\n                        // I cannot find documentation about \"InvalidStateError\"\r\n                        // but this is what we are receiving from GUM when the\r\n                        // streamId for the desktop sharing is \"\".\r\n\r\n                        if (error && error.name === 'InvalidStateError') {\r\n                            jitsiError = new JitsiTrackError(\r\n                                JitsiTrackErrors.SCREENSHARING_USER_CANCELED\r\n                            );\r\n                        } else {\r\n                            jitsiError = new JitsiTrackError(\r\n                                error, constraints, [ 'desktop' ]);\r\n                        }\r\n                        (typeof onFailure === 'function')\r\n                            && onFailure(jitsiError);\r\n                    });\r\n            };\r\n        } else if (browser.isElectron()) {\r\n            return this.obtainScreenOnElectron;\r\n        } else if (browser.isReactNative() && browser.supportsGetDisplayMedia()) {\r\n            return this.obtainScreenFromGetDisplayMediaRN;\r\n        } else if (browser.supportsGetDisplayMedia()) {\r\n            return this.obtainScreenFromGetDisplayMedia;\r\n        }\r\n        logger.log('Screen sharing not supported on ', browser.getName());\r\n\r\n        return null;\r\n    },\r\n\r\n    /**\r\n     * Gets the appropriate constraints for audio sharing.\r\n     *\r\n     * @returns {Object|boolean}\r\n     */\r\n    _getAudioConstraints() {\r\n        const { audioQuality } = this.options;\r\n        const audio = audioQuality?.stereo ? {\r\n            autoGainControl: false,\r\n            channelCount: 2,\r\n            echoCancellation: false,\r\n            noiseSuppression: false\r\n        } : true;\r\n\r\n        return audio;\r\n    },\r\n\r\n    /**\r\n     * Checks whether obtaining a screen capture is supported in the current\r\n     * environment.\r\n     * @returns {boolean}\r\n     */\r\n    isSupported() {\r\n        return this.obtainStream !== null;\r\n    },\r\n\r\n    /**\r\n     * Obtains a screen capture stream on Electron.\r\n     *\r\n     * @param onSuccess - Success callback.\r\n     * @param onFailure - Failure callback.\r\n     * @param {Object} options - Optional parameters.\r\n     */\r\n    obtainScreenOnElectron(onSuccess, onFailure, options = {}) {\r\n        if (window.JitsiMeetScreenObtainer && window.JitsiMeetScreenObtainer.openDesktopPicker) {\r\n            const { desktopSharingFrameRate, desktopSharingSources } = this.options;\r\n\r\n            window.JitsiMeetScreenObtainer.openDesktopPicker(\r\n                {\r\n                    desktopSharingSources:\r\n                        options.desktopSharingSources || desktopSharingSources || [ 'screen', 'window' ]\r\n                },\r\n                (streamId, streamType, screenShareAudio = false) => {\r\n                    if (streamId) {\r\n                        let audioConstraints = false;\r\n\r\n                        if (screenShareAudio) {\r\n                            audioConstraints = {};\r\n                            const optionalConstraints = this._getAudioConstraints();\r\n\r\n                            if (typeof optionalConstraints !== 'boolean') {\r\n                                audioConstraints = {\r\n                                    optional: optionalConstraints\r\n                                };\r\n                            }\r\n\r\n                            // Audio screen sharing for electron only works for screen type devices.\r\n                            // i.e. when the user shares the whole desktop.\r\n                            // Note. The documentation specifies that chromeMediaSourceId should not be present\r\n                            // which, in the case a users has multiple monitors, leads to them being shared all\r\n                            // at once. However we tested with chromeMediaSourceId present and it seems to be\r\n                            // working properly.\r\n                            if (streamType === 'screen') {\r\n                                audioConstraints.mandatory = {\r\n                                    chromeMediaSource: 'desktop'\r\n                                };\r\n                            }\r\n                        }\r\n\r\n                        const constraints = {\r\n                            audio: audioConstraints,\r\n                            video: {\r\n                                mandatory: {\r\n                                    chromeMediaSource: 'desktop',\r\n                                    chromeMediaSourceId: streamId,\r\n                                    minFrameRate: desktopSharingFrameRate?.min ?? SS_DEFAULT_FRAME_RATE,\r\n                                    maxFrameRate: desktopSharingFrameRate?.max ?? SS_DEFAULT_FRAME_RATE,\r\n                                    maxWidth: window.screen.width,\r\n                                    maxHeight: window.screen.height\r\n                                }\r\n                            }\r\n                        };\r\n\r\n                        // We have to use the old API on Electron to get a desktop stream.\r\n                        navigator.mediaDevices.getUserMedia(constraints)\r\n                            .then(stream => onSuccess({\r\n                                stream,\r\n                                sourceId: streamId,\r\n                                sourceType: streamType\r\n                            }), onFailure);\r\n                    } else {\r\n                        // As noted in Chrome Desktop Capture API:\r\n                        // If user didn't select any source (i.e. canceled the prompt)\r\n                        // then the callback is called with an empty streamId.\r\n                        onFailure(new JitsiTrackError(JitsiTrackErrors.SCREENSHARING_USER_CANCELED));\r\n                    }\r\n                },\r\n                err => onFailure(new JitsiTrackError(\r\n                    JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_ERROR,\r\n                    err\r\n                ))\r\n            );\r\n        } else {\r\n            onFailure(new JitsiTrackError(JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_NOT_FOUND));\r\n        }\r\n    },\r\n\r\n    /**\r\n     * Obtains a screen capture stream using getDisplayMedia.\r\n     *\r\n     * @param callback - The success callback.\r\n     * @param errorCallback - The error callback.\r\n     */\r\n    obtainScreenFromGetDisplayMedia(callback, errorCallback) {\r\n        let getDisplayMedia;\r\n\r\n        if (navigator.getDisplayMedia) {\r\n            getDisplayMedia = navigator.getDisplayMedia.bind(navigator);\r\n        } else {\r\n            // eslint-disable-next-line max-len\r\n            getDisplayMedia = navigator.mediaDevices.getDisplayMedia.bind(navigator.mediaDevices);\r\n        }\r\n\r\n        const { desktopSharingFrameRate } = this.options;\r\n        const setScreenSharingResolutionConstraints = browser.isChromiumBased()\r\n            && this.options?.testing?.setScreenSharingResolutionConstraints;\r\n        let video = {};\r\n\r\n        // Allow users to seamlessly switch which tab they are sharing without having to select the tab again.\r\n        if (browser.isChromiumBased() && browser.isVersionGreaterThan(106)) {\r\n            video.surfaceSwitching = 'include';\r\n        }\r\n\r\n        if (typeof desktopSharingFrameRate === 'object') {\r\n            video.frameRate = desktopSharingFrameRate;\r\n        }\r\n\r\n        // Capturing the screenshare at very high resolutions restricts the framerate. Therefore, skip this hack when\r\n        // the capture framerate is > 5 fps.\r\n        if (setScreenSharingResolutionConstraints && !(desktopSharingFrameRate?.max > SS_DEFAULT_FRAME_RATE)) {\r\n            // Set bogus resolution constraints to work around\r\n            // https://bugs.chromium.org/p/chromium/issues/detail?id=1056311\r\n            video.height = 99999;\r\n            video.width = 99999;\r\n        }\r\n\r\n        const audio = this._getAudioConstraints();\r\n\r\n        // At the time of this writing 'min' constraint for fps is not supported by getDisplayMedia.\r\n        video.frameRate && delete video.frameRate.min;\r\n\r\n        if (Object.keys(video).length === 0) {\r\n            video = true;\r\n        }\r\n\r\n        const constraints = {\r\n            video,\r\n            audio,\r\n            cursor: 'always'\r\n        };\r\n\r\n        logger.info('Using getDisplayMedia for screen sharing', constraints);\r\n\r\n        getDisplayMedia(constraints)\r\n            .then(stream => {\r\n                callback({\r\n                    stream,\r\n                    sourceId: stream.id\r\n                });\r\n            })\r\n            .catch(error => {\r\n                const errorDetails = {\r\n                    errorName: error && error.name,\r\n                    errorMsg: error && error.message,\r\n                    errorStack: error && error.stack\r\n                };\r\n\r\n                logger.error('getDisplayMedia error', constraints, errorDetails);\r\n\r\n                if (errorDetails.errorMsg && errorDetails.errorMsg.indexOf('denied by system') !== -1) {\r\n                    // On Chrome this is the only thing different between error returned when user cancels\r\n                    // and when no permission was given on the OS level.\r\n                    errorCallback(new JitsiTrackError(JitsiTrackErrors.PERMISSION_DENIED));\r\n\r\n                    return;\r\n                }\r\n\r\n                errorCallback(new JitsiTrackError(JitsiTrackErrors.SCREENSHARING_USER_CANCELED));\r\n            });\r\n    },\r\n\r\n    /**\r\n     * Obtains a screen capture stream using getDisplayMedia.\r\n     *\r\n     * @param callback - The success callback.\r\n     * @param errorCallback - The error callback.\r\n     */\r\n    obtainScreenFromGetDisplayMediaRN(callback, errorCallback) {\r\n        logger.info('Using getDisplayMedia for screen sharing');\r\n\r\n        navigator.mediaDevices.getDisplayMedia({ video: true })\r\n            .then(stream => {\r\n                callback({\r\n                    stream,\r\n                    sourceId: stream.id });\r\n            })\r\n            .catch(() => {\r\n                errorCallback(new JitsiTrackError(JitsiTrackErrors\r\n                    .SCREENSHARING_USER_CANCELED));\r\n            });\r\n    },\r\n\r\n    /**\r\n     * Sets the max frame rate to be used for a desktop track capture.\r\n     *\r\n     * @param {number} maxFps capture frame rate to be used for desktop tracks.\r\n     * @returns {void}\r\n     */\r\n    setDesktopSharingFrameRate(maxFps) {\r\n        logger.info(`Setting the desktop capture rate to ${maxFps}`);\r\n\r\n        this.options.desktopSharingFrameRate = {\r\n            min: SS_DEFAULT_FRAME_RATE,\r\n            max: maxFps\r\n        };\r\n    }\r\n};\r\n\r\nexport default ScreenObtainer;\r\n","\r\nimport browser from '../browser';\r\n\r\n/**\r\n * A global module for accessing information about different feature flags state.\r\n */\r\nclass FeatureFlags {\r\n    /**\r\n     * Configures the module.\r\n     *\r\n     * @param {object} flags - The feature flags.\r\n     * @param {boolean=} flags.runInLiteMode - Enables lite mode for testing to disable media decoding.\r\n     * @param {boolean=} flags.ssrcRewritingEnabled - Use SSRC rewriting. Requires sourceNameSignaling to be enabled.\r\n     */\r\n    init(flags) {\r\n        this._runInLiteMode = Boolean(flags.runInLiteMode);\r\n        this._ssrcRewriting = Boolean(flags.ssrcRewritingEnabled);\r\n    }\r\n\r\n    /**\r\n     * Checks if multiple local video streams support is enabled.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isMultiStreamSendSupportEnabled() {\r\n        return browser.supportsUnifiedPlan();\r\n    }\r\n\r\n    /**\r\n     * Checks if the run in lite mode is enabled.\r\n     * This will cause any media to be received and not decoded. (Directions are inactive and no ssrc and ssrc-groups\r\n     * are added to the remote description). This can be used for various test scenarios.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isRunInLiteModeEnabled() {\r\n        return this._runInLiteMode;\r\n    }\r\n\r\n    /**\r\n     * Checks if the clients supports re-writing of the SSRCs on the media streams by the bridge.\r\n     * @returns {boolean}\r\n     */\r\n    isSsrcRewritingSupported() {\r\n        return this._ssrcRewriting;\r\n    }\r\n}\r\n\r\nexport default new FeatureFlags();\r\n","import { getLogger } from '@jitsi/logger';\r\nconst logger = getLogger(__filename);\r\n\r\nimport CodecMimeType from '../../service/RTC/CodecMimeType';\r\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\r\nimport browser from '../browser';\r\nimport RandomUtil from '../util/RandomUtil';\r\n\r\nconst SDPUtil = {\r\n    filterSpecialChars(text) {\r\n        // XXX Neither one of the falsy values (e.g. null, undefined, false,\r\n        // \"\", etc.) \"contain\" special chars.\r\n        // eslint-disable-next-line no-useless-escape\r\n        return text ? text.replace(/[\\\\\\/\\{,\\}\\+]/g, '') : text;\r\n    },\r\n    iceparams(mediadesc, sessiondesc) {\r\n        let data = null;\r\n        let pwd, ufrag;\r\n\r\n        if ((ufrag = SDPUtil.findLine(mediadesc, 'a=ice-ufrag:', sessiondesc))\r\n                && (pwd\r\n                    = SDPUtil.findLine(\r\n                        mediadesc,\r\n                        'a=ice-pwd:',\r\n                        sessiondesc))) {\r\n            data = {\r\n                ufrag: SDPUtil.parseICEUfrag(ufrag),\r\n                pwd: SDPUtil.parseICEPwd(pwd)\r\n            };\r\n        }\r\n\r\n        return data;\r\n    },\r\n    parseICEUfrag(line) {\r\n        return line.substring(12);\r\n    },\r\n    buildICEUfrag(frag) {\r\n        return `a=ice-ufrag:${frag}`;\r\n    },\r\n    parseICEPwd(line) {\r\n        return line.substring(10);\r\n    },\r\n    buildICEPwd(pwd) {\r\n        return `a=ice-pwd:${pwd}`;\r\n    },\r\n    parseMID(line) {\r\n        return line.substring(6);\r\n    },\r\n\r\n    /**\r\n     * Finds the MSID attribute in the given array of SSRC attribute lines and returns the value.\r\n     *\r\n     * @param {string[]} ssrcLines - an array of lines similar to 'a:213123 msid:stream-id track-id'.\r\n     * @returns {undefined|string}\r\n     */\r\n    parseMSIDAttribute(ssrcLines) {\r\n        const msidLine = ssrcLines.find(line => line.indexOf(' msid:') > 0);\r\n\r\n        if (!msidLine) {\r\n            return undefined;\r\n        }\r\n\r\n        const v = msidLine.substring(msidLine.indexOf(' msid:') + 6 /* the length of ' msid:' */);\r\n\r\n        return SDPUtil.filterSpecialChars(v);\r\n    },\r\n    parseMLine(line) {\r\n        const data = {};\r\n        const parts = line.substring(2).split(' ');\r\n\r\n        data.media = parts.shift();\r\n        data.port = parts.shift();\r\n        data.proto = parts.shift();\r\n        if (parts[parts.length - 1] === '') { // trailing whitespace\r\n            parts.pop();\r\n        }\r\n        data.fmt = parts;\r\n\r\n        return data;\r\n    },\r\n    buildMLine(mline) {\r\n        return (\r\n            `m=${mline.media} ${mline.port} ${mline.proto} ${\r\n                mline.fmt.join(' ')}`);\r\n    },\r\n    parseRTPMap(line) {\r\n        const data = {};\r\n        let parts = line.substring(9).split(' ');\r\n\r\n        data.id = parts.shift();\r\n        parts = parts[0].split('/');\r\n        data.name = parts.shift();\r\n        data.clockrate = parts.shift();\r\n        data.channels = parts.length ? parts.shift() : '1';\r\n\r\n        return data;\r\n    },\r\n\r\n    /**\r\n     * Parses SDP line \"a=sctpmap:...\" and extracts SCTP port from it.\r\n     * @param line eg. \"a=sctpmap:5000 webrtc-datachannel\"\r\n     * @returns [SCTP port number, protocol, streams]\r\n     */\r\n    parseSCTPMap(line) {\r\n        const parts = line.substring(10).split(' ');\r\n        const sctpPort = parts[0];\r\n        const protocol = parts[1];\r\n\r\n        // Stream count is optional\r\n        const streamCount = parts.length > 2 ? parts[2] : null;\r\n\r\n\r\n        return [ sctpPort, protocol, streamCount ];// SCTP port\r\n    },\r\n    parseSCTPPort(line) {\r\n        return line.substring(12);\r\n    },\r\n    buildRTPMap(el) {\r\n        let line\r\n            = `a=rtpmap:${el.getAttribute('id')} ${el.getAttribute('name')}/${\r\n                el.getAttribute('clockrate')}`;\r\n\r\n        if (el.getAttribute('channels')\r\n            && el.getAttribute('channels') !== '1') {\r\n            line += `/${el.getAttribute('channels')}`;\r\n        }\r\n\r\n        return line;\r\n    },\r\n    parseCrypto(line) {\r\n        const data = {};\r\n        const parts = line.substring(9).split(' ');\r\n\r\n        data.tag = parts.shift();\r\n        data['crypto-suite'] = parts.shift();\r\n        data['key-params'] = parts.shift();\r\n        if (parts.length) {\r\n            data['session-params'] = parts.join(' ');\r\n        }\r\n\r\n        return data;\r\n    },\r\n    parseFingerprint(line) { // RFC 4572\r\n        const data = {};\r\n        const parts = line.substring(14).split(' ');\r\n\r\n        data.hash = parts.shift();\r\n        data.fingerprint = parts.shift();\r\n\r\n        // TODO assert that fingerprint satisfies 2UHEX *(\":\" 2UHEX) ?\r\n        return data;\r\n    },\r\n    parseFmtp(line) {\r\n        const data = [];\r\n        let parts = line.split(' ');\r\n\r\n        parts.shift();\r\n        parts = parts.join(' ').split(';');\r\n        for (let i = 0; i < parts.length; i++) {\r\n            let key = parts[i].split('=')[0];\r\n\r\n            while (key.length && key[0] === ' ') {\r\n                key = key.substring(1);\r\n            }\r\n            const value = parts[i].split('=')[1];\r\n\r\n            if (key && value) {\r\n                data.push({ name: key,\r\n                    value });\r\n            } else if (key) {\r\n                // rfc 4733 (DTMF) style stuff\r\n                data.push({ name: '',\r\n                    value: key });\r\n            }\r\n        }\r\n\r\n        return data;\r\n    },\r\n    parseICECandidate(line) {\r\n        const candidate = {};\r\n        const elems = line.split(' ');\r\n\r\n        candidate.foundation = elems[0].substring(12);\r\n        candidate.component = elems[1];\r\n        candidate.protocol = elems[2].toLowerCase();\r\n        candidate.priority = elems[3];\r\n        candidate.ip = elems[4];\r\n        candidate.port = elems[5];\r\n\r\n        // elems[6] => \"typ\"\r\n        candidate.type = elems[7];\r\n        candidate.generation = 0; // default value, may be overwritten below\r\n        for (let i = 8; i < elems.length; i += 2) {\r\n            switch (elems[i]) {\r\n            case 'raddr':\r\n                candidate['rel-addr'] = elems[i + 1];\r\n                break;\r\n            case 'rport':\r\n                candidate['rel-port'] = elems[i + 1];\r\n                break;\r\n            case 'generation':\r\n                candidate.generation = elems[i + 1];\r\n                break;\r\n            case 'tcptype':\r\n                candidate.tcptype = elems[i + 1];\r\n                break;\r\n            default: // TODO\r\n                logger.debug(\r\n                    `parseICECandidate not translating \"${\r\n                        elems[i]}\" = \"${elems[i + 1]}\"`);\r\n            }\r\n        }\r\n        candidate.network = '1';\r\n\r\n        // not applicable to SDP -- FIXME: should be unique, not just random\r\n        // eslint-disable-next-line newline-per-chained-call\r\n        candidate.id = Math.random().toString(36).substr(2, 10);\r\n\r\n        return candidate;\r\n    },\r\n    buildICECandidate(cand) {\r\n        let line = [\r\n            `a=candidate:${cand.foundation}`,\r\n            cand.component,\r\n            cand.protocol,\r\n            cand.priority,\r\n            cand.ip,\r\n            cand.port,\r\n            'typ',\r\n            cand.type\r\n        ].join(' ');\r\n\r\n        line += ' ';\r\n        switch (cand.type) {\r\n        case 'srflx':\r\n        case 'prflx':\r\n        case 'relay':\r\n            if (cand.hasOwnAttribute('rel-addr')\r\n                    && cand.hasOwnAttribute('rel-port')) {\r\n                line += 'raddr';\r\n                line += ' ';\r\n                line += cand['rel-addr'];\r\n                line += ' ';\r\n                line += 'rport';\r\n                line += ' ';\r\n                line += cand['rel-port'];\r\n                line += ' ';\r\n            }\r\n            break;\r\n        }\r\n        if (cand.hasOwnAttribute('tcptype')) {\r\n            line += 'tcptype';\r\n            line += ' ';\r\n            line += cand.tcptype;\r\n            line += ' ';\r\n        }\r\n        line += 'generation';\r\n        line += ' ';\r\n        line += cand.hasOwnAttribute('generation') ? cand.generation : '0';\r\n\r\n        return line;\r\n    },\r\n    parseSSRC(desc) {\r\n        // proprietary mapping of a=ssrc lines\r\n        // TODO: see \"Jingle RTP Source Description\" by Juberti and P. Thatcher\r\n        // on google docs and parse according to that\r\n        const data = new Map();\r\n        const lines = desc.split('\\r\\n');\r\n\r\n        for (let i = 0; i < lines.length; i++) {\r\n            if (lines[i].substring(0, 7) === 'a=ssrc:') {\r\n                // FIXME: Use regex to smartly find the ssrc.\r\n                const ssrc = lines[i].split('a=ssrc:')[1].split(' ')[0];\r\n\r\n                if (!data.get(ssrc)) {\r\n                    data.set(ssrc, []);\r\n                }\r\n\r\n                data.get(ssrc).push(lines[i]);\r\n            }\r\n        }\r\n\r\n        return data;\r\n    },\r\n\r\n    /**\r\n     * Gets the source name out of the name attribute \"a=ssrc:254321 name:name1\".\r\n     *\r\n     * @param {string[]} ssrcLines\r\n     * @returns {string | undefined}\r\n     */\r\n    parseSourceNameLine(ssrcLines) {\r\n        const sourceNameLine = ssrcLines.find(ssrcSdpLine => ssrcSdpLine.indexOf(' name:') > 0);\r\n\r\n        // Everything past the \"name:\" part\r\n        return sourceNameLine?.substring(sourceNameLine.indexOf(' name:') + 6);\r\n    },\r\n\r\n    /**\r\n     * Parse the \"videoType\" attribute encoded in a set of SSRC attributes (e.g.\r\n     * \"a=ssrc:1234 videoType:desktop\")\r\n     *\r\n     * @param {string[]} ssrcLines\r\n     * @returns {string | undefined}\r\n     */\r\n    parseVideoTypeLine(ssrcLines) {\r\n        const s = ' videoType:';\r\n        const videoTypeLine = ssrcLines.find(ssrcSdpLine => ssrcSdpLine.indexOf(s) > 0);\r\n\r\n        return videoTypeLine?.substring(videoTypeLine.indexOf(s) + s.length);\r\n    },\r\n    parseRTCPFB(line) {\r\n        const parts = line.substr(10).split(' ');\r\n        const data = {};\r\n\r\n        data.pt = parts.shift();\r\n        data.type = parts.shift();\r\n        data.params = parts;\r\n\r\n        return data;\r\n    },\r\n    parseExtmap(line) {\r\n        const parts = line.substr(9).split(' ');\r\n        const data = {};\r\n\r\n        data.value = parts.shift();\r\n        if (data.value.indexOf('/') === -1) {\r\n            data.direction = 'both';\r\n        } else {\r\n            data.direction = data.value.substr(data.value.indexOf('/') + 1);\r\n            data.value = data.value.substr(0, data.value.indexOf('/'));\r\n        }\r\n        data.uri = parts.shift();\r\n        data.params = parts;\r\n\r\n        return data;\r\n    },\r\n    findLine(haystack, needle, sessionpart) {\r\n        let lines = haystack.split('\\r\\n');\r\n\r\n        for (let i = 0; i < lines.length; i++) {\r\n            if (lines[i].substring(0, needle.length) === needle) {\r\n                return lines[i];\r\n            }\r\n        }\r\n        if (!sessionpart) {\r\n            return false;\r\n        }\r\n\r\n        // search session part\r\n        lines = sessionpart.split('\\r\\n');\r\n        for (let j = 0; j < lines.length; j++) {\r\n            if (lines[j].substring(0, needle.length) === needle) {\r\n                return lines[j];\r\n            }\r\n        }\r\n\r\n        return false;\r\n    },\r\n    findLines(haystack, needle, sessionpart) {\r\n        let lines = haystack.split('\\r\\n');\r\n        const needles = [];\r\n\r\n        for (let i = 0; i < lines.length; i++) {\r\n            if (lines[i].substring(0, needle.length) === needle) {\r\n                needles.push(lines[i]);\r\n            }\r\n        }\r\n        if (needles.length || !sessionpart) {\r\n            return needles;\r\n        }\r\n\r\n        // search session part\r\n        lines = sessionpart.split('\\r\\n');\r\n        for (let j = 0; j < lines.length; j++) {\r\n            if (lines[j].substring(0, needle.length) === needle) {\r\n                needles.push(lines[j]);\r\n            }\r\n        }\r\n\r\n        return needles;\r\n    },\r\n    candidateToJingle(line) {\r\n        // a=candidate:2979166662 1 udp 2113937151 192.168.2.100 57698 typ host\r\n        // generation 0\r\n        //      <candidate component=... foundation=... generation=... id=...\r\n        // ip=... network=... port=... priority=... protocol=... type=.../>\r\n        if (line.indexOf('candidate:') === 0) {\r\n            // eslint-disable-next-line no-param-reassign\r\n            line = `a=${line}`;\r\n        } else if (line.substring(0, 12) !== 'a=candidate:') {\r\n            logger.warn(\r\n                'parseCandidate called with a line that is not a candidate'\r\n                    + ' line');\r\n            logger.warn(line);\r\n\r\n            return null;\r\n        }\r\n        if (line.substring(line.length - 2) === '\\r\\n') { // chomp it\r\n            // eslint-disable-next-line no-param-reassign\r\n            line = line.substring(0, line.length - 2);\r\n        }\r\n        const candidate = {};\r\n        const elems = line.split(' ');\r\n\r\n        if (elems[6] !== 'typ') {\r\n            logger.warn('did not find typ in the right place');\r\n            logger.warn(line);\r\n\r\n            return null;\r\n        }\r\n        candidate.foundation = elems[0].substring(12);\r\n        candidate.component = elems[1];\r\n        candidate.protocol = elems[2].toLowerCase();\r\n        candidate.priority = elems[3];\r\n        candidate.ip = elems[4];\r\n        candidate.port = elems[5];\r\n\r\n        // elems[6] => \"typ\"\r\n        candidate.type = elems[7];\r\n\r\n        candidate.generation = '0'; // default, may be overwritten below\r\n        for (let i = 8; i < elems.length; i += 2) {\r\n            switch (elems[i]) {\r\n            case 'raddr':\r\n                candidate['rel-addr'] = elems[i + 1];\r\n                break;\r\n            case 'rport':\r\n                candidate['rel-port'] = elems[i + 1];\r\n                break;\r\n            case 'generation':\r\n                candidate.generation = elems[i + 1];\r\n                break;\r\n            case 'tcptype':\r\n                candidate.tcptype = elems[i + 1];\r\n                break;\r\n            default: // TODO\r\n                logger.debug(`not translating \"${elems[i]}\" = \"${elems[i + 1]}\"`);\r\n            }\r\n        }\r\n        candidate.network = '1';\r\n\r\n        // not applicable to SDP -- FIXME: should be unique, not just random\r\n        // eslint-disable-next-line newline-per-chained-call\r\n        candidate.id = Math.random().toString(36).substr(2, 10);\r\n\r\n        return candidate;\r\n    },\r\n    candidateFromJingle(cand) {\r\n        let line = 'a=candidate:';\r\n\r\n        line += cand.getAttribute('foundation');\r\n        line += ' ';\r\n        line += cand.getAttribute('component');\r\n        line += ' ';\r\n\r\n        let protocol = cand.getAttribute('protocol');\r\n\r\n        // use tcp candidates for FF\r\n\r\n        if (browser.isFirefox() && protocol.toLowerCase() === 'ssltcp') {\r\n            protocol = 'tcp';\r\n        }\r\n\r\n        line += protocol; // .toUpperCase(); // chrome M23 doesn't like this\r\n        line += ' ';\r\n        line += cand.getAttribute('priority');\r\n        line += ' ';\r\n        line += cand.getAttribute('ip');\r\n        line += ' ';\r\n        line += cand.getAttribute('port');\r\n        line += ' ';\r\n        line += 'typ';\r\n        line += ` ${cand.getAttribute('type')}`;\r\n        line += ' ';\r\n        switch (cand.getAttribute('type')) {\r\n        case 'srflx':\r\n        case 'prflx':\r\n        case 'relay':\r\n            if (cand.getAttribute('rel-addr')\r\n                    && cand.getAttribute('rel-port')) {\r\n                line += 'raddr';\r\n                line += ' ';\r\n                line += cand.getAttribute('rel-addr');\r\n                line += ' ';\r\n                line += 'rport';\r\n                line += ' ';\r\n                line += cand.getAttribute('rel-port');\r\n                line += ' ';\r\n            }\r\n            break;\r\n        }\r\n        if (protocol.toLowerCase() === 'tcp') {\r\n            line += 'tcptype';\r\n            line += ' ';\r\n            line += cand.getAttribute('tcptype');\r\n            line += ' ';\r\n        }\r\n        line += 'generation';\r\n        line += ' ';\r\n        line += cand.getAttribute('generation') || '0';\r\n\r\n        return `${line}\\r\\n`;\r\n    },\r\n\r\n    /**\r\n     * Parse the 'most' primary video ssrc from the given m line\r\n     * @param {object} mLine object as parsed from transform.parse\r\n     * @return {number} the primary video ssrc from the given m line\r\n     */\r\n    parsePrimaryVideoSsrc(videoMLine) {\r\n        const numSsrcs = videoMLine.ssrcs\r\n            .map(ssrcInfo => ssrcInfo.id)\r\n            .filter((ssrc, index, array) => array.indexOf(ssrc) === index)\r\n            .length;\r\n        const numGroups\r\n            = (videoMLine.ssrcGroups && videoMLine.ssrcGroups.length) || 0;\r\n\r\n        if (numSsrcs > 1 && numGroups === 0) {\r\n            // Ambiguous, can't figure out the primary\r\n            return;\r\n        }\r\n        let primarySsrc = null;\r\n\r\n        if (numSsrcs === 1) {\r\n            primarySsrc = videoMLine.ssrcs[0].id;\r\n        } else if (numSsrcs === 2) {\r\n            // Can figure it out if there's an FID group\r\n            const fidGroup\r\n                = videoMLine.ssrcGroups.find(\r\n                    group => group.semantics === 'FID');\r\n\r\n            if (fidGroup) {\r\n                primarySsrc = fidGroup.ssrcs.split(' ')[0];\r\n            }\r\n        } else if (numSsrcs >= 3) {\r\n            // Can figure it out if there's a sim group\r\n            const simGroup\r\n                = videoMLine.ssrcGroups.find(\r\n                    group => group.semantics === 'SIM');\r\n\r\n            if (simGroup) {\r\n                primarySsrc = simGroup.ssrcs.split(' ')[0];\r\n            }\r\n        }\r\n\r\n        return primarySsrc;\r\n    },\r\n\r\n    /**\r\n     * Generate an ssrc\r\n     * @returns {number} an ssrc\r\n     */\r\n    generateSsrc() {\r\n        return RandomUtil.randomInt(1, 0xffffffff);\r\n    },\r\n\r\n    /**\r\n     * Get an attribute for the given ssrc with the given attributeName\r\n     *  from the given mline\r\n     * @param {object} mLine an mLine object as parsed from transform.parse\r\n     * @param {number} ssrc the ssrc for which an attribute is desired\r\n     * @param {string} attributeName the name of the desired attribute\r\n     * @returns {string} the value corresponding to the given ssrc\r\n     *  and attributeName\r\n     */\r\n    getSsrcAttribute(mLine, ssrc, attributeName) {\r\n        for (let i = 0; i < mLine.ssrcs.length; ++i) {\r\n            const ssrcLine = mLine.ssrcs[i];\r\n\r\n            if (ssrcLine.id === ssrc\r\n                && ssrcLine.attribute === attributeName) {\r\n                return ssrcLine.value;\r\n            }\r\n        }\r\n    },\r\n\r\n    /**\r\n     * Parses the ssrcs from the group sdp line and\r\n     *  returns them as a list of numbers\r\n     * @param {object} the ssrcGroup object as parsed from\r\n     *  sdp-transform\r\n     * @returns {list<number>} a list of the ssrcs in the group\r\n     *  parsed as numbers\r\n     */\r\n    parseGroupSsrcs(ssrcGroup) {\r\n        return ssrcGroup\r\n            .ssrcs\r\n            .split(' ')\r\n            .map(ssrcStr => parseInt(ssrcStr, 10));\r\n    },\r\n\r\n    /**\r\n     * Get the mline of the given type from the given sdp\r\n     * @param {object} sdp sdp as parsed from transform.parse\r\n     * @param {string} type the type of the desired mline (e.g. \"video\")\r\n     * @returns {object} a media object\r\n     */\r\n    getMedia(sdp, type) {\r\n        return sdp.media.find(m => m.type === type);\r\n    },\r\n\r\n    /**\r\n     * Extracts the ICE username fragment from an SDP string.\r\n     * @param {string} sdp the SDP in raw text format\r\n     */\r\n    getUfrag(sdp) {\r\n        const ufragLines\r\n            = sdp.split('\\n').filter(line => line.startsWith('a=ice-ufrag:'));\r\n\r\n        if (ufragLines.length > 0) {\r\n            return ufragLines[0].substr('a=ice-ufrag:'.length);\r\n        }\r\n    },\r\n\r\n    /**\r\n     * Sets the given codecName as the preferred codec by moving it to the beginning\r\n     * of the payload types list (modifies the given mline in place). All instances\r\n     * of the codec are moved up.\r\n     * @param {object} mLine the mline object from an sdp as parsed by transform.parse\r\n     * @param {string} codecName the name of the preferred codec\r\n     */\r\n    preferCodec(mline, codecName) {\r\n        if (!mline || !codecName) {\r\n            return;\r\n        }\r\n\r\n        const matchingPayloadTypes = mline.rtp\r\n            .filter(rtp => rtp.codec && rtp.codec.toLowerCase() === codecName.toLowerCase())\r\n            .map(rtp => rtp.payload);\r\n\r\n        if (matchingPayloadTypes) {\r\n            // Call toString() on payloads to get around an issue within SDPTransform that sets\r\n            // payloads as a number, instead of a string, when there is only one payload.\r\n            const payloadTypes\r\n                = mline.payloads\r\n                .toString()\r\n                .split(' ')\r\n                .map(p => parseInt(p, 10));\r\n\r\n            for (const pt of matchingPayloadTypes.reverse()) {\r\n                const payloadIndex = payloadTypes.indexOf(pt);\r\n\r\n                payloadTypes.splice(payloadIndex, 1);\r\n                payloadTypes.unshift(pt);\r\n            }\r\n            mline.payloads = payloadTypes.join(' ');\r\n        }\r\n    },\r\n\r\n    /**\r\n     * Strips the given codec from the given mline. All related RTX payload\r\n     * types are also stripped. If the resulting mline would have no codecs,\r\n     * it's disabled.\r\n     *\r\n     * @param {object} mLine the mline object from an sdp as parsed by transform.parse.\r\n     * @param {string} codecName the name of the codec which will be stripped.\r\n     * @param {boolean} highProfile determines if only the high profile H264 codec needs to be\r\n     * stripped from the sdp when the passed codecName is H264.\r\n     */\r\n    stripCodec(mLine, codecName, highProfile = false) {\r\n        if (!mLine || !codecName) {\r\n            return;\r\n        }\r\n\r\n        const h264Pts = [];\r\n        let removePts = [];\r\n        const stripH264HighCodec = codecName.toLowerCase() === CodecMimeType.H264 && highProfile;\r\n\r\n        for (const rtp of mLine.rtp) {\r\n            if (rtp.codec\r\n                && rtp.codec.toLowerCase() === codecName.toLowerCase()) {\r\n                if (stripH264HighCodec) {\r\n                    h264Pts.push(rtp.payload);\r\n                } else {\r\n                    removePts.push(rtp.payload);\r\n                }\r\n            }\r\n        }\r\n\r\n        // high profile H264 codecs have 64 as the first two bytes of the profile-level-id.\r\n        if (stripH264HighCodec) {\r\n            removePts = mLine.fmtp\r\n                .filter(item => h264Pts.indexOf(item.payload) > -1 && item.config.includes('profile-level-id=64'))\r\n                .map(item => item.payload);\r\n        }\r\n\r\n        if (removePts.length > 0) {\r\n            // We also need to remove the payload types that are related to RTX\r\n            // for the codecs we want to disable.\r\n            const rtxApts = removePts.map(item => `apt=${item}`);\r\n            const rtxPts = mLine.fmtp.filter(\r\n                item => rtxApts.indexOf(item.config) !== -1);\r\n\r\n            removePts.push(...rtxPts.map(item => item.payload));\r\n\r\n            // Call toString() on payloads to get around an issue within\r\n            // SDPTransform that sets payloads as a number, instead of a string,\r\n            // when there is only one payload.\r\n            const allPts = mLine.payloads\r\n                .toString()\r\n                .split(' ')\r\n                .map(Number);\r\n            const keepPts = allPts.filter(pt => removePts.indexOf(pt) === -1);\r\n\r\n            if (keepPts.length === 0) {\r\n                // There are no other codecs, disable the stream.\r\n                mLine.port = 0;\r\n                mLine.direction = MediaDirection.INACTIVE;\r\n                mLine.payloads = '*';\r\n            } else {\r\n                mLine.payloads = keepPts.join(' ');\r\n            }\r\n\r\n            mLine.rtp = mLine.rtp.filter(\r\n                item => keepPts.indexOf(item.payload) !== -1);\r\n            mLine.fmtp = mLine.fmtp.filter(\r\n                item => keepPts.indexOf(item.payload) !== -1);\r\n            if (mLine.rtcpFb) {\r\n                mLine.rtcpFb = mLine.rtcpFb.filter(\r\n                    item => keepPts.indexOf(item.payload) !== -1);\r\n            }\r\n        }\r\n    }\r\n};\r\n\r\nexport default SDPUtil;\r\n","import $ from 'jquery';\r\nimport clonedeep from 'lodash.clonedeep';\r\nimport transform from 'sdp-transform';\r\n\r\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\r\nimport browser from '../browser';\r\n\r\nimport SDPUtil from './SDPUtil';\r\n\r\n/**\r\n *\r\n * @param sdp\r\n */\r\nexport default function SDP(sdp) {\r\n    const media = sdp.split('\\r\\nm=');\r\n\r\n    for (let i = 1, length = media.length; i < length; i++) {\r\n        let mediaI = `m=${media[i]}`;\r\n\r\n        if (i !== length - 1) {\r\n            mediaI += '\\r\\n';\r\n        }\r\n        media[i] = mediaI;\r\n    }\r\n    const session = `${media.shift()}\\r\\n`;\r\n\r\n    this.media = media;\r\n    this.raw = session + media.join('');\r\n    this.session = session;\r\n}\r\n\r\n/**\r\n * A flag will make {@link transportToJingle} and {@link jingle2media} replace\r\n * ICE candidates IPs with invalid value of '1.1.1.1' which will cause ICE\r\n * failure. The flag is used in the automated testing.\r\n * @type {boolean}\r\n */\r\nSDP.prototype.failICE = false;\r\n\r\n/**\r\n * Whether or not to remove TCP ice candidates when translating from/to jingle.\r\n * @type {boolean}\r\n */\r\nSDP.prototype.removeTcpCandidates = false;\r\n\r\n/**\r\n * Whether or not to remove UDP ice candidates when translating from/to jingle.\r\n * @type {boolean}\r\n */\r\nSDP.prototype.removeUdpCandidates = false;\r\n\r\n/**\r\n * Adds a new m-line to the description so that a new local source can then be attached to the transceiver that gets\r\n * added after a reneogtiation cycle.\r\n *\r\n * @param {MediaType} mediaType media type of the new source that is being added.\r\n */\r\nSDP.prototype.addMlineForNewLocalSource = function(mediaType) {\r\n    const mid = this.media.length;\r\n    const sdp = transform.parse(this.raw);\r\n    const mline = clonedeep(sdp.media.find(m => m.type === mediaType));\r\n\r\n    // Edit media direction, mid and remove the existing ssrc lines in the m-line.\r\n    mline.mid = mid;\r\n    mline.direction = MediaDirection.RECVONLY;\r\n\r\n    // Remove the ssrcs and source groups.\r\n    mline.msid = undefined;\r\n    mline.ssrcs = undefined;\r\n    mline.ssrcGroups = undefined;\r\n\r\n    sdp.media = sdp.media.concat(mline);\r\n\r\n    // We regenerate the BUNDLE group (since we added a new m-line)\r\n    sdp.groups.forEach(group => {\r\n        if (group.type === 'BUNDLE') {\r\n            const mids = group.mids.split(' ');\r\n\r\n            mids.push(mid);\r\n            group.mids = mids.join(' ');\r\n        }\r\n    });\r\n    this.raw = transform.write(sdp);\r\n};\r\n\r\n/**\r\n * Returns map of MediaChannel mapped per channel idx.\r\n */\r\nSDP.prototype.getMediaSsrcMap = function() {\r\n    const mediaSSRCs = {};\r\n\r\n    for (let mediaindex = 0; mediaindex < this.media.length; mediaindex++) {\r\n        const mid\r\n            = SDPUtil.parseMID(\r\n                SDPUtil.findLine(this.media[mediaindex], 'a=mid:'));\r\n        const media = {\r\n            mediaindex,\r\n            mid,\r\n            ssrcs: {},\r\n            ssrcGroups: []\r\n        };\r\n\r\n        mediaSSRCs[mediaindex] = media;\r\n\r\n        SDPUtil.findLines(this.media[mediaindex], 'a=ssrc:').forEach(line => {\r\n            const linessrc = line.substring(7).split(' ')[0];\r\n\r\n            // allocate new ChannelSsrc\r\n\r\n            if (!media.ssrcs[linessrc]) {\r\n                media.ssrcs[linessrc] = {\r\n                    ssrc: linessrc,\r\n                    lines: []\r\n                };\r\n            }\r\n            media.ssrcs[linessrc].lines.push(line);\r\n        });\r\n        SDPUtil.findLines(this.media[mediaindex], 'a=ssrc-group:').forEach(line => {\r\n            const idx = line.indexOf(' ');\r\n            const semantics = line.substr(0, idx).substr(13);\r\n            const ssrcs = line.substr(14 + semantics.length).split(' ');\r\n\r\n            if (ssrcs.length) {\r\n                media.ssrcGroups.push({\r\n                    semantics,\r\n                    ssrcs\r\n                });\r\n            }\r\n        });\r\n    }\r\n\r\n    return mediaSSRCs;\r\n};\r\n\r\n/**\r\n * Returns <tt>true</tt> if this SDP contains given SSRC.\r\n * @param ssrc the ssrc to check.\r\n * @returns {boolean} <tt>true</tt> if this SDP contains given SSRC.\r\n */\r\nSDP.prototype.containsSSRC = function(ssrc) {\r\n    // FIXME this code is really strange - improve it if you can\r\n    const medias = this.getMediaSsrcMap();\r\n    let result = false;\r\n\r\n    Object.keys(medias).forEach(mediaindex => {\r\n        if (result) {\r\n            return;\r\n        }\r\n        if (medias[mediaindex].ssrcs[ssrc]) {\r\n            result = true;\r\n        }\r\n    });\r\n\r\n    return result;\r\n};\r\n\r\n// add content's to a jingle element\r\nSDP.prototype.toJingle = function(elem, thecreator) {\r\n    // https://xmpp.org/extensions/xep-0338.html\r\n    SDPUtil.findLines(this.session, 'a=group:').forEach(line => {\r\n        const parts = line.split(' ');\r\n        const semantics = parts.shift().substr(8);\r\n\r\n        elem.c('group', { xmlns: 'urn:xmpp:jingle:apps:grouping:0',\r\n            semantics });\r\n        for (let j = 0; j < parts.length; j++) {\r\n            elem.c('content', { name: parts[j] }).up();\r\n        }\r\n        elem.up();\r\n    });\r\n\r\n    for (let i = 0; i < this.media.length; i++) {\r\n        const mline = SDPUtil.parseMLine(this.media[i].split('\\r\\n')[0]);\r\n\r\n        if (!(mline.media === 'audio'\r\n              || mline.media === 'video'\r\n              || mline.media === 'application')) {\r\n            continue; // eslint-disable-line no-continue\r\n        }\r\n\r\n        let ssrc;\r\n        const assrcline = SDPUtil.findLine(this.media[i], 'a=ssrc:');\r\n\r\n        if (assrcline) {\r\n            ssrc = assrcline.substring(7).split(' ')[0]; // take the first\r\n        } else {\r\n            ssrc = false;\r\n        }\r\n\r\n        elem.c('content', { creator: thecreator,\r\n            name: mline.media });\r\n        const amidline = SDPUtil.findLine(this.media[i], 'a=mid:');\r\n\r\n        if (amidline) {\r\n            // prefer identifier from a=mid if present\r\n            const mid = SDPUtil.parseMID(amidline);\r\n\r\n            elem.attrs({ name: mid });\r\n        }\r\n\r\n        if (mline.media === 'audio' || mline.media === 'video') {\r\n            elem.c('description',\r\n                { xmlns: 'urn:xmpp:jingle:apps:rtp:1',\r\n                    media: mline.media });\r\n            if (ssrc) {\r\n                elem.attrs({ ssrc });\r\n            }\r\n            for (let j = 0; j < mline.fmt.length; j++) {\r\n                const rtpmap\r\n                    = SDPUtil.findLine(\r\n                        this.media[i],\r\n                        `a=rtpmap:${mline.fmt[j]}`);\r\n\r\n                elem.c('payload-type', SDPUtil.parseRTPMap(rtpmap));\r\n\r\n                // put any 'a=fmtp:' + mline.fmt[j] lines into <param name=foo\r\n                // value=bar/>\r\n                const afmtpline\r\n                    = SDPUtil.findLine(\r\n                        this.media[i],\r\n                        `a=fmtp:${mline.fmt[j]}`);\r\n\r\n                if (afmtpline) {\r\n                    const fmtpParameters = SDPUtil.parseFmtp(afmtpline);\r\n\r\n                    // eslint-disable-next-line max-depth\r\n                    for (let k = 0; k < fmtpParameters.length; k++) {\r\n                        elem.c('parameter', fmtpParameters[k]).up();\r\n                    }\r\n                }\r\n\r\n                // XEP-0293 -- map a=rtcp-fb\r\n                this.rtcpFbToJingle(i, elem, mline.fmt[j]);\r\n\r\n                elem.up();\r\n            }\r\n\r\n            if (ssrc) {\r\n                const ssrcMap = SDPUtil.parseSSRC(this.media[i]);\r\n\r\n                for (const [ availableSsrc, ssrcParameters ] of ssrcMap) {\r\n                    const sourceName = SDPUtil.parseSourceNameLine(ssrcParameters);\r\n                    const videoType = SDPUtil.parseVideoTypeLine(ssrcParameters);\r\n\r\n                    elem.c('source', {\r\n                        ssrc: availableSsrc,\r\n                        name: sourceName,\r\n                        videoType,\r\n                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\r\n                    });\r\n\r\n                    const msid = SDPUtil.parseMSIDAttribute(ssrcParameters);\r\n\r\n                    // eslint-disable-next-line max-depth\r\n                    if (msid) {\r\n                        elem.c('parameter');\r\n                        elem.attrs({ name: 'msid' });\r\n                        elem.attrs({ value: msid });\r\n                        elem.up();\r\n                    }\r\n\r\n                    elem.up();\r\n                }\r\n\r\n                // XEP-0339 handle ssrc-group attributes\r\n                const ssrcGroupLines\r\n                    = SDPUtil.findLines(this.media[i], 'a=ssrc-group:');\r\n\r\n                ssrcGroupLines.forEach(line => {\r\n                    const idx = line.indexOf(' ');\r\n                    const semantics = line.substr(0, idx).substr(13);\r\n                    const ssrcs = line.substr(14 + semantics.length).split(' ');\r\n\r\n                    if (ssrcs.length) {\r\n                        elem.c('ssrc-group', { semantics,\r\n                            xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });\r\n                        ssrcs.forEach(s => elem.c('source', { ssrc: s }).up());\r\n                        elem.up();\r\n                    }\r\n                });\r\n            }\r\n\r\n            const ridLines = SDPUtil.findLines(this.media[i], 'a=rid:');\r\n\r\n            if (ridLines.length && browser.usesRidsForSimulcast()) {\r\n                // Map a line which looks like \"a=rid:2 send\" to just\r\n                // the rid (\"2\")\r\n                const rids = ridLines\r\n                    .map(ridLine => ridLine.split(':')[1])\r\n                    .map(ridInfo => ridInfo.split(' ')[0]);\r\n\r\n                rids.forEach(rid => {\r\n                    elem.c('source', {\r\n                        rid,\r\n                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\r\n                    });\r\n                    elem.up();\r\n                });\r\n                const unifiedSimulcast\r\n                    = SDPUtil.findLine(this.media[i], 'a=simulcast:');\r\n\r\n                if (unifiedSimulcast) {\r\n                    elem.c('rid-group', {\r\n                        semantics: 'SIM',\r\n                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\r\n                    });\r\n                    rids.forEach(rid => {\r\n                        elem.c('source', { rid }).up();\r\n                    });\r\n                    elem.up();\r\n                }\r\n            }\r\n\r\n            if (SDPUtil.findLine(this.media[i], 'a=rtcp-mux')) {\r\n                elem.c('rtcp-mux').up();\r\n            }\r\n\r\n            // XEP-0293 -- map a=rtcp-fb:*\r\n            this.rtcpFbToJingle(i, elem, '*');\r\n\r\n            // XEP-0294\r\n            const extmapLines = SDPUtil.findLines(this.media[i], 'a=extmap:');\r\n\r\n            for (let j = 0; j < extmapLines.length; j++) {\r\n                const extmap = SDPUtil.parseExtmap(extmapLines[j]);\r\n\r\n                elem.c('rtp-hdrext', {\r\n                    xmlns: 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0',\r\n                    uri: extmap.uri,\r\n                    id: extmap.value\r\n                });\r\n\r\n                // eslint-disable-next-line max-depth\r\n                if (extmap.hasOwnProperty('direction')) {\r\n\r\n                    // eslint-disable-next-line max-depth\r\n                    switch (extmap.direction) {\r\n                    case MediaDirection.SENDONLY:\r\n                        elem.attrs({ senders: 'responder' });\r\n                        break;\r\n                    case MediaDirection.RECVONLY:\r\n                        elem.attrs({ senders: 'initiator' });\r\n                        break;\r\n                    case MediaDirection.SENDRECV:\r\n                        elem.attrs({ senders: 'both' });\r\n                        break;\r\n                    case MediaDirection.INACTIVE:\r\n                        elem.attrs({ senders: 'none' });\r\n                        break;\r\n                    }\r\n                }\r\n\r\n                // TODO: handle params\r\n                elem.up();\r\n            }\r\n            elem.up(); // end of description\r\n        }\r\n\r\n        // map ice-ufrag/pwd, dtls fingerprint, candidates\r\n        this.transportToJingle(i, elem);\r\n\r\n        const m = this.media[i];\r\n\r\n        if (SDPUtil.findLine(m, `a=${MediaDirection.SENDRECV}`, this.session)) {\r\n            elem.attrs({ senders: 'both' });\r\n        } else if (SDPUtil.findLine(m, `a=${MediaDirection.SENDONLY}`, this.session)) {\r\n            elem.attrs({ senders: 'initiator' });\r\n        } else if (SDPUtil.findLine(m, `a=${MediaDirection.RECVONLY}`, this.session)) {\r\n            elem.attrs({ senders: 'responder' });\r\n        } else if (SDPUtil.findLine(m, `a=${MediaDirection.INACTIVE}`, this.session)) {\r\n            elem.attrs({ senders: 'none' });\r\n        }\r\n\r\n        // Reject an m-line only when port is 0 and a=bundle-only is not present in the section.\r\n        // The port is automatically set to 0 when bundle-only is used.\r\n        if (mline.port === '0' && !SDPUtil.findLine(m, 'a=bundle-only', this.session)) {\r\n            // estos hack to reject an m-line\r\n            elem.attrs({ senders: 'rejected' });\r\n        }\r\n        elem.up(); // end of content\r\n    }\r\n    elem.up();\r\n\r\n    return elem;\r\n};\r\n\r\nSDP.prototype.transportToJingle = function(mediaindex, elem) {\r\n    elem.c('transport');\r\n\r\n    // XEP-0343 DTLS/SCTP\r\n    const sctpport\r\n        = SDPUtil.findLine(this.media[mediaindex], 'a=sctp-port:', this.session);\r\n    const sctpmap\r\n        = SDPUtil.findLine(this.media[mediaindex], 'a=sctpmap:', this.session);\r\n\r\n    if (sctpport) {\r\n        const sctpAttrs = SDPUtil.parseSCTPPort(sctpport);\r\n\r\n        elem.c('sctpmap', {\r\n            xmlns: 'urn:xmpp:jingle:transports:dtls-sctp:1',\r\n            number: sctpAttrs, /* SCTP port */\r\n            protocol: 'webrtc-datachannel' /* protocol */\r\n        });\r\n\r\n        // The parser currently requires streams to be present\r\n        elem.attrs({ streams: 0 });\r\n        elem.up();\r\n    } else if (sctpmap) {\r\n        const sctpAttrs = SDPUtil.parseSCTPMap(sctpmap);\r\n\r\n        elem.c('sctpmap', {\r\n            xmlns: 'urn:xmpp:jingle:transports:dtls-sctp:1',\r\n            number: sctpAttrs[0], /* SCTP port */\r\n            protocol: sctpAttrs[1] /* protocol */\r\n        });\r\n\r\n        // Optional stream count attribute\r\n        if (sctpAttrs.length > 2) {\r\n            elem.attrs({ streams: sctpAttrs[2] });\r\n        } else {\r\n            elem.attrs({ streams: 0 });\r\n        }\r\n        elem.up();\r\n    }\r\n\r\n    // XEP-0320\r\n    const fingerprints\r\n        = SDPUtil.findLines(\r\n            this.media[mediaindex],\r\n            'a=fingerprint:',\r\n            this.session);\r\n\r\n    fingerprints.forEach(line => {\r\n        const fingerprint = SDPUtil.parseFingerprint(line);\r\n\r\n        fingerprint.xmlns = 'urn:xmpp:jingle:apps:dtls:0';\r\n        elem.c('fingerprint').t(fingerprint.fingerprint);\r\n        delete fingerprint.fingerprint;\r\n\r\n        const setupLine\r\n            = SDPUtil.findLine(\r\n                this.media[mediaindex],\r\n                'a=setup:',\r\n                this.session);\r\n\r\n        if (setupLine) {\r\n            fingerprint.setup = setupLine.substr(8);\r\n        }\r\n        elem.attrs(fingerprint);\r\n        elem.up(); // end of fingerprint\r\n    });\r\n    const iceParameters = SDPUtil.iceparams(this.media[mediaindex], this.session);\r\n\r\n    if (iceParameters) {\r\n        iceParameters.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';\r\n        elem.attrs(iceParameters);\r\n\r\n        // XEP-0176\r\n        const candidateLines\r\n            = SDPUtil.findLines(\r\n                this.media[mediaindex],\r\n                'a=candidate:',\r\n                this.session);\r\n\r\n        candidateLines.forEach(line => { // add any a=candidate lines\r\n            const candidate = SDPUtil.candidateToJingle(line);\r\n\r\n            if (this.failICE) {\r\n                candidate.ip = '1.1.1.1';\r\n            }\r\n            const protocol\r\n                = candidate && typeof candidate.protocol === 'string'\r\n                    ? candidate.protocol.toLowerCase()\r\n                    : '';\r\n\r\n            if ((this.removeTcpCandidates\r\n                    && (protocol === 'tcp' || protocol === 'ssltcp'))\r\n                || (this.removeUdpCandidates && protocol === 'udp')) {\r\n                return;\r\n            }\r\n            elem.c('candidate', candidate).up();\r\n        });\r\n    }\r\n    elem.up(); // end of transport\r\n};\r\n\r\n// XEP-0293\r\nSDP.prototype.rtcpFbToJingle = function(mediaindex, elem, payloadtype) {\r\n    const lines\r\n        = SDPUtil.findLines(\r\n            this.media[mediaindex],\r\n            `a=rtcp-fb:${payloadtype}`);\r\n\r\n    lines.forEach(line => {\r\n        const feedback = SDPUtil.parseRTCPFB(line);\r\n\r\n        if (feedback.type === 'trr-int') {\r\n            elem.c('rtcp-fb-trr-int', {\r\n                xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0',\r\n                value: feedback.params[0]\r\n            });\r\n            elem.up();\r\n        } else {\r\n            elem.c('rtcp-fb', {\r\n                xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0',\r\n                type: feedback.type\r\n            });\r\n            if (feedback.params.length > 0) {\r\n                elem.attrs({ 'subtype': feedback.params[0] });\r\n            }\r\n            elem.up();\r\n        }\r\n    });\r\n};\r\n\r\nSDP.prototype.rtcpFbFromJingle = function(elem, payloadtype) { // XEP-0293\r\n    let sdp = '';\r\n    const feedbackElementTrrInt\r\n        = elem.find(\r\n            '>rtcp-fb-trr-int[xmlns=\"urn:xmpp:jingle:apps:rtp:rtcp-fb:0\"]');\r\n\r\n    if (feedbackElementTrrInt.length) {\r\n        sdp += 'a=rtcp-fb:* trr-int ';\r\n        if (feedbackElementTrrInt.attr('value')) {\r\n            sdp += feedbackElementTrrInt.attr('value');\r\n        } else {\r\n            sdp += '0';\r\n        }\r\n        sdp += '\\r\\n';\r\n    }\r\n\r\n    const feedbackElements = elem.find('>rtcp-fb[xmlns=\"urn:xmpp:jingle:apps:rtp:rtcp-fb:0\"]');\r\n\r\n    feedbackElements.each((_, fb) => {\r\n        sdp += `a=rtcp-fb:${payloadtype} ${fb.getAttribute('type')}`;\r\n        if (fb.hasAttribute('subtype')) {\r\n            sdp += ` ${fb.getAttribute('subtype')}`;\r\n        }\r\n        sdp += '\\r\\n';\r\n    });\r\n\r\n    return sdp;\r\n};\r\n\r\n// construct an SDP from a jingle stanza\r\nSDP.prototype.fromJingle = function(jingle) {\r\n    const sessionId = Date.now();\r\n\r\n    // Use a unique session id for every TPC.\r\n    this.raw = 'v=0\\r\\n'\r\n        + `o=- ${sessionId} 2 IN IP4 0.0.0.0\\r\\n`\r\n        + 's=-\\r\\n'\r\n        + 't=0 0\\r\\n';\r\n\r\n    // http://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-04\r\n    // #section-8\r\n    const groups\r\n        = $(jingle).find('>group[xmlns=\"urn:xmpp:jingle:apps:grouping:0\"]');\r\n\r\n    if (groups.length) {\r\n        groups.each((idx, group) => {\r\n            const contents\r\n                = $(group)\r\n                    .find('>content')\r\n                    .map((_, content) => content.getAttribute('name'))\r\n                    .get();\r\n\r\n            if (contents.length > 0) {\r\n                this.raw\r\n                    += `a=group:${\r\n                        group.getAttribute('semantics')\r\n                            || group.getAttribute('type')} ${\r\n                        contents.join(' ')}\\r\\n`;\r\n            }\r\n        });\r\n    }\r\n\r\n    this.session = this.raw;\r\n    jingle.find('>content').each((_, content) => {\r\n        const m = this.jingle2media($(content));\r\n\r\n        this.media.push(m);\r\n    });\r\n\r\n    // reconstruct msid-semantic -- apparently not necessary\r\n    /*\r\n     var msid = SDPUtil.parseSSRC(this.raw);\r\n     if (msid.hasOwnProperty('mslabel')) {\r\n     this.session += \"a=msid-semantic: WMS \" + msid.mslabel + \"\\r\\n\";\r\n     }\r\n     */\r\n\r\n    this.raw = this.session + this.media.join('');\r\n};\r\n\r\n// translate a jingle content element into an an SDP media part\r\nSDP.prototype.jingle2media = function(content) {\r\n    const desc = content.find('>description');\r\n    const transport = content.find('>transport[xmlns=\"urn:xmpp:jingle:transports:ice-udp:1\"]');\r\n    let sdp = '';\r\n    const sctp = transport.find(\r\n        '>sctpmap[xmlns=\"urn:xmpp:jingle:transports:dtls-sctp:1\"]');\r\n\r\n    const media = { media: desc.attr('media') };\r\n\r\n    media.port = '9';\r\n    if (content.attr('senders') === 'rejected') {\r\n        // estos hack to reject an m-line.\r\n        media.port = '0';\r\n    }\r\n    if (transport.find('>fingerprint[xmlns=\"urn:xmpp:jingle:apps:dtls:0\"]').length) {\r\n        media.proto = sctp.length ? 'UDP/DTLS/SCTP' : 'UDP/TLS/RTP/SAVPF';\r\n    } else {\r\n        media.proto = 'UDP/TLS/RTP/SAVPF';\r\n    }\r\n    if (sctp.length) {\r\n        sdp += `m=application ${media.port} UDP/DTLS/SCTP webrtc-datachannel\\r\\n`;\r\n        sdp += `a=sctp-port:${sctp.attr('number')}\\r\\n`;\r\n        sdp += 'a=max-message-size:262144\\r\\n';\r\n    } else {\r\n        media.fmt\r\n            = desc\r\n                .find('>payload-type')\r\n                .map((_, payloadType) => payloadType.getAttribute('id'))\r\n                .get();\r\n        sdp += `${SDPUtil.buildMLine(media)}\\r\\n`;\r\n    }\r\n\r\n    sdp += 'c=IN IP4 0.0.0.0\\r\\n';\r\n    if (!sctp.length) {\r\n        sdp += 'a=rtcp:1 IN IP4 0.0.0.0\\r\\n';\r\n    }\r\n\r\n    // XEP-0176 ICE parameters\r\n    if (transport.length) {\r\n        if (transport.attr('ufrag')) {\r\n            sdp += `${SDPUtil.buildICEUfrag(transport.attr('ufrag'))}\\r\\n`;\r\n        }\r\n        if (transport.attr('pwd')) {\r\n            sdp += `${SDPUtil.buildICEPwd(transport.attr('pwd'))}\\r\\n`;\r\n        }\r\n        transport.find('>fingerprint[xmlns=\"urn:xmpp:jingle:apps:dtls:0\"]').each((_, fingerprint) => {\r\n            sdp += `a=fingerprint:${fingerprint.getAttribute('hash')}`;\r\n            sdp += ` ${$(fingerprint).text()}`;\r\n            sdp += '\\r\\n';\r\n            if (fingerprint.hasAttribute('setup')) {\r\n                sdp += `a=setup:${fingerprint.getAttribute('setup')}\\r\\n`;\r\n            }\r\n        });\r\n    }\r\n\r\n    // XEP-0176 ICE candidates\r\n    transport.find('>candidate')\r\n        .each((_, candidate) => {\r\n            let protocol = candidate.getAttribute('protocol');\r\n\r\n            protocol\r\n                = typeof protocol === 'string' ? protocol.toLowerCase() : '';\r\n\r\n            if ((this.removeTcpCandidates\r\n                    && (protocol === 'tcp' || protocol === 'ssltcp'))\r\n                || (this.removeUdpCandidates && protocol === 'udp')) {\r\n                return;\r\n            } else if (this.failICE) {\r\n                candidate.setAttribute('ip', '1.1.1.1');\r\n            }\r\n\r\n            sdp += SDPUtil.candidateFromJingle(candidate);\r\n        });\r\n\r\n    switch (content.attr('senders')) {\r\n    case 'initiator':\r\n        sdp += `a=${MediaDirection.SENDONLY}\\r\\n`;\r\n        break;\r\n    case 'responder':\r\n        sdp += `a=${MediaDirection.RECVONLY}\\r\\n`;\r\n        break;\r\n    case 'none':\r\n        sdp += `a=${MediaDirection.INACTIVE}\\r\\n`;\r\n        break;\r\n    case 'both':\r\n        sdp += `a=${MediaDirection.SENDRECV}\\r\\n`;\r\n        break;\r\n    }\r\n    sdp += `a=mid:${content.attr('name')}\\r\\n`;\r\n\r\n    // <description><rtcp-mux/></description>\r\n    // see http://code.google.com/p/libjingle/issues/detail?id=309 -- no spec\r\n    // though\r\n    // and http://mail.jabber.org/pipermail/jingle/2011-December/001761.html\r\n    if (desc.find('>rtcp-mux').length) {\r\n        sdp += 'a=rtcp-mux\\r\\n';\r\n    }\r\n\r\n    desc.find('>payload-type').each((_, payloadType) => {\r\n        sdp += `${SDPUtil.buildRTPMap(payloadType)}\\r\\n`;\r\n        if ($(payloadType).find('>parameter').length) {\r\n            sdp += `a=fmtp:${payloadType.getAttribute('id')} `;\r\n            sdp\r\n                += $(payloadType)\r\n                    .find('>parameter')\r\n                    .map((__, parameter) => {\r\n                        const name = parameter.getAttribute('name');\r\n\r\n                        return (\r\n                            (name ? `${name}=` : '')\r\n                                + parameter.getAttribute('value'));\r\n                    })\r\n                    .get()\r\n                    .join(';');\r\n            sdp += '\\r\\n';\r\n        }\r\n\r\n        // xep-0293\r\n        sdp += this.rtcpFbFromJingle($(payloadType), payloadType.getAttribute('id'));\r\n    });\r\n\r\n    // xep-0293\r\n    sdp += this.rtcpFbFromJingle(desc, '*');\r\n\r\n    // xep-0294\r\n    desc\r\n        .find('>rtp-hdrext[xmlns=\"urn:xmpp:jingle:apps:rtp:rtp-hdrext:0\"]')\r\n        .each((_, hdrExt) => {\r\n            sdp\r\n                += `a=extmap:${hdrExt.getAttribute('id')} ${\r\n                    hdrExt.getAttribute('uri')}\\r\\n`;\r\n        });\r\n\r\n    // XEP-0339 handle ssrc-group attributes\r\n    desc\r\n        .find('>ssrc-group[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\r\n        .each((_, ssrcGroup) => {\r\n            const semantics = ssrcGroup.getAttribute('semantics');\r\n            const ssrcs\r\n                = $(ssrcGroup)\r\n                    .find('>source')\r\n                    .map((__, source) => source.getAttribute('ssrc'))\r\n                    .get();\r\n\r\n            if (ssrcs.length) {\r\n                sdp += `a=ssrc-group:${semantics} ${ssrcs.join(' ')}\\r\\n`;\r\n            }\r\n        });\r\n\r\n    // XEP-0339 handle source attributes\r\n    let userSources = '';\r\n    let nonUserSources = '';\r\n\r\n    desc\r\n        .find('>source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\r\n        .each((_, source) => {\r\n            const ssrc = source.getAttribute('ssrc');\r\n            let isUserSource = true;\r\n            let sourceStr = '';\r\n\r\n            $(source)\r\n                .find('>parameter')\r\n                .each((__, parameter) => {\r\n                    const name = parameter.getAttribute('name');\r\n                    let value = parameter.getAttribute('value');\r\n\r\n                    value = SDPUtil.filterSpecialChars(value);\r\n                    sourceStr += `a=ssrc:${ssrc} ${name}`;\r\n\r\n                    if (value && value.length) {\r\n                        sourceStr += `:${value}`;\r\n                    }\r\n\r\n                    sourceStr += '\\r\\n';\r\n\r\n                    if (value?.includes('mixedmslabel')) {\r\n                        isUserSource = false;\r\n                    }\r\n                });\r\n\r\n            if (isUserSource) {\r\n                userSources += sourceStr;\r\n            } else {\r\n                nonUserSources += sourceStr;\r\n            }\r\n        });\r\n\r\n    // The sdp-interop package is relying the mixedmslabel m line to be the first one in order to set the direction\r\n    // to sendrecv.\r\n    sdp += nonUserSources + userSources;\r\n\r\n    return sdp;\r\n};\r\n","\r\nimport SDPUtil from './SDPUtil';\r\n\r\n// this could be useful in Array.prototype.\r\n/**\r\n *\r\n * @param array1\r\n * @param array2\r\n */\r\nfunction arrayEquals(array1, array2) {\r\n    // if the other array is a falsy value, return\r\n    if (!array2) {\r\n        return false;\r\n    }\r\n\r\n    // compare lengths - can save a lot of time\r\n    if (array1.length !== array2.length) {\r\n        return false;\r\n    }\r\n\r\n    for (let i = 0, l = array1.length; i < l; i++) {\r\n        // Check if we have nested arrays\r\n        if (array1[i] instanceof Array && array2[i] instanceof Array) {\r\n            // recurse into the nested arrays\r\n            if (!array1[i].equals(array2[i])) {\r\n                return false;\r\n            }\r\n        } else if (array1[i] !== array2[i]) {\r\n            // Warning - two different object instances will never be\r\n            // equal: {x:20} != {x:20}\r\n            return false;\r\n        }\r\n    }\r\n\r\n    return true;\r\n}\r\n\r\n/**\r\n *\r\n * @param mySDP\r\n * @param otherSDP\r\n */\r\nexport default function SDPDiffer(mySDP, otherSDP) {\r\n    this.mySDP = mySDP;\r\n    this.otherSDP = otherSDP;\r\n    if (!mySDP) {\r\n        throw new Error('\"mySDP\" is undefined!');\r\n    } else if (!otherSDP) {\r\n        throw new Error('\"otherSDP\" is undefined!');\r\n    }\r\n}\r\n\r\n/**\r\n * Returns map of MediaChannel that contains media contained in\r\n * 'mySDP', but not contained in 'otherSdp'. Mapped by channel idx.\r\n */\r\nSDPDiffer.prototype.getNewMedia = function() {\r\n\r\n    const myMedias = this.mySDP.getMediaSsrcMap();\r\n    const othersMedias = this.otherSDP.getMediaSsrcMap();\r\n    const newMedia = {};\r\n\r\n    Object.keys(othersMedias).forEach(othersMediaIdx => {\r\n        const myMedia = myMedias[othersMediaIdx];\r\n        const othersMedia = othersMedias[othersMediaIdx];\r\n\r\n        if (!myMedia && othersMedia) {\r\n            // Add whole channel\r\n            newMedia[othersMediaIdx] = othersMedia;\r\n\r\n            return;\r\n        }\r\n\r\n        // Look for new ssrcs across the channel\r\n        Object.keys(othersMedia.ssrcs).forEach(ssrc => {\r\n            if (Object.keys(myMedia.ssrcs).indexOf(ssrc) === -1) {\r\n                // Allocate channel if we've found ssrc that doesn't exist in\r\n                // our channel\r\n                if (!newMedia[othersMediaIdx]) {\r\n                    newMedia[othersMediaIdx] = {\r\n                        mediaindex: othersMedia.mediaindex,\r\n                        mid: othersMedia.mid,\r\n                        ssrcs: {},\r\n                        ssrcGroups: []\r\n                    };\r\n                }\r\n                newMedia[othersMediaIdx].ssrcs[ssrc] = othersMedia.ssrcs[ssrc];\r\n            } else if (othersMedia.ssrcs[ssrc].lines\r\n                        && myMedia.ssrcs[ssrc].lines) {\r\n                // we want to detect just changes in adding/removing msid\r\n                const myContainMsid = myMedia.ssrcs[ssrc].lines.find(\r\n                    line => line.indexOf('msid') !== -1) !== undefined;\r\n                const newContainMsid = othersMedia.ssrcs[ssrc].lines.find(\r\n                    line => line.indexOf('msid') !== -1) !== undefined;\r\n\r\n                if (myContainMsid !== newContainMsid) {\r\n                    if (!newMedia[othersMediaIdx]) {\r\n                        newMedia[othersMediaIdx] = {\r\n                            mediaindex: othersMedia.mediaindex,\r\n                            mid: othersMedia.mid,\r\n                            ssrcs: {},\r\n                            ssrcGroups: []\r\n                        };\r\n                    }\r\n                    newMedia[othersMediaIdx].ssrcs[ssrc]\r\n                        = othersMedia.ssrcs[ssrc];\r\n                }\r\n            }\r\n        });\r\n\r\n        // Look for new ssrc groups across the channels\r\n        othersMedia.ssrcGroups.forEach(otherSsrcGroup => {\r\n\r\n            // try to match the other ssrc-group with an ssrc-group of ours\r\n            let matched = false;\r\n\r\n            for (let i = 0; i < myMedia.ssrcGroups.length; i++) {\r\n                const mySsrcGroup = myMedia.ssrcGroups[i];\r\n\r\n                if (otherSsrcGroup.semantics === mySsrcGroup.semantics\r\n                    && arrayEquals(otherSsrcGroup.ssrcs, mySsrcGroup.ssrcs)) {\r\n\r\n                    matched = true;\r\n                    break;\r\n                }\r\n            }\r\n\r\n            if (!matched) {\r\n                // Allocate channel if we've found an ssrc-group that doesn't\r\n                // exist in our channel\r\n\r\n                if (!newMedia[othersMediaIdx]) {\r\n                    newMedia[othersMediaIdx] = {\r\n                        mediaindex: othersMedia.mediaindex,\r\n                        mid: othersMedia.mid,\r\n                        ssrcs: {},\r\n                        ssrcGroups: []\r\n                    };\r\n                }\r\n                newMedia[othersMediaIdx].ssrcGroups.push(otherSsrcGroup);\r\n            }\r\n        });\r\n    });\r\n\r\n    return newMedia;\r\n};\r\n\r\n/**\r\n * TODO: document!\r\n */\r\nSDPDiffer.prototype.toJingle = function(modify) {\r\n    const sdpMediaSsrcs = this.getNewMedia();\r\n\r\n    let modified = false;\r\n\r\n    Object.keys(sdpMediaSsrcs).forEach(mediaindex => {\r\n        modified = true;\r\n        const media = sdpMediaSsrcs[mediaindex];\r\n\r\n        modify.c('content', { name: media.mid });\r\n\r\n        modify.c('description',\r\n            { xmlns: 'urn:xmpp:jingle:apps:rtp:1',\r\n                media: media.mid });\r\n\r\n        // FIXME: not completely sure this operates on blocks and / or handles\r\n        // different ssrcs correctly\r\n        // generate sources from lines\r\n        Object.keys(media.ssrcs).forEach(ssrcNum => {\r\n            const mediaSsrc = media.ssrcs[ssrcNum];\r\n            const ssrcLines = mediaSsrc.lines;\r\n            const sourceName = SDPUtil.parseSourceNameLine(ssrcLines);\r\n            const videoType = SDPUtil.parseVideoTypeLine(ssrcLines);\r\n\r\n            modify.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });\r\n            modify.attrs({\r\n                name: sourceName,\r\n                videoType,\r\n                ssrc: mediaSsrc.ssrc\r\n            });\r\n\r\n            // Only MSID attribute is sent\r\n            const msid = SDPUtil.parseMSIDAttribute(ssrcLines);\r\n\r\n            if (msid) {\r\n                modify.c('parameter');\r\n                modify.attrs({ name: 'msid' });\r\n                modify.attrs({ value: msid });\r\n                modify.up();\r\n            }\r\n\r\n            modify.up(); // end of source\r\n        });\r\n\r\n        // generate source groups from lines\r\n        media.ssrcGroups.forEach(ssrcGroup => {\r\n            if (ssrcGroup.ssrcs.length) {\r\n\r\n                modify.c('ssrc-group', {\r\n                    semantics: ssrcGroup.semantics,\r\n                    xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\r\n                });\r\n\r\n                ssrcGroup.ssrcs.forEach(ssrc => {\r\n                    modify.c('source', { ssrc })\r\n                        .up(); // end of source\r\n                });\r\n                modify.up(); // end of ssrc-group\r\n            }\r\n        });\r\n\r\n        modify.up(); // end of description\r\n        modify.up(); // end of content\r\n    });\r\n\r\n    return modified;\r\n};\r\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';\r\nimport { queue } from 'async';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * A queue for async task execution.\r\n */\r\nexport default class AsyncQueue {\r\n    /**\r\n     * Creates new instance.\r\n     */\r\n    constructor() {\r\n        this._queue = queue(this._processQueueTasks.bind(this), 1);\r\n        this._stopped = false;\r\n    }\r\n\r\n    /**\r\n     * Removes any pending tasks from the queue.\r\n     */\r\n    clear() {\r\n        this._queue.kill();\r\n    }\r\n\r\n    /**\r\n     * Internal task processing implementation which makes things work.\r\n     */\r\n    _processQueueTasks(task, finishedCallback) {\r\n        try {\r\n            task(finishedCallback);\r\n        } catch (error) {\r\n            logger.error(`Task failed: ${error?.stack}`);\r\n            finishedCallback(error);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * The 'task' function will be given a callback it MUST call with either:\r\n     *  1) No arguments if it was successful or\r\n     *  2) An error argument if there was an error\r\n     * If the task wants to process the success or failure of the task, it\r\n     * should pass the {@code callback} to the push function, e.g.:\r\n     * queue.push(task, (err) => {\r\n     *     if (err) {\r\n     *         // error handling\r\n     *     } else {\r\n     *         // success handling\r\n     *     }\r\n     * });\r\n     *\r\n     * @param {function} task - The task to be executed. See the description above.\r\n     * @param {function} [callback] - Optional callback to be called after the task has been executed.\r\n     */\r\n    push(task, callback) {\r\n        if (this._stopped) {\r\n            callback && callback(new Error('The queue has been stopped'));\r\n\r\n            return;\r\n        }\r\n        this._queue.push(task, callback);\r\n    }\r\n\r\n    /**\r\n     * Shutdowns the queue. All already queued tasks will execute, but no future tasks can be added. If a task is added\r\n     * after the queue has been shutdown then the callback will be called with an error.\r\n     */\r\n    shutdown() {\r\n        this._stopped = true;\r\n    }\r\n}\r\n","export enum JingleSessionState {\r\n    /**\r\n     * The pending Jingle session state which means the session as defined in\r\n     * XEP-0166(before 'session-invite/session-accept' took place).\r\n     */\r\n    PENDING = 'pending',\r\n\r\n    /**\r\n     * The active Jingle session state as defined in XEP-0166\r\n     * (after 'session-invite'/'session-accept').\r\n     */\r\n    ACTIVE = 'active',\r\n\r\n    /**\r\n     * The ended Jingle session state as defined in XEP-0166\r\n     * (after 'session-terminate').\r\n     */\r\n    ENDED = 'ended'\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const PENDING = JingleSessionState.PENDING;\r\nexport const ACTIVE = JingleSessionState.ACTIVE;\r\nexport const ENDED = JingleSessionState.ENDED;\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport Listenable from '../util/Listenable';\r\n\r\nimport * as JingleSessionState from './JingleSessionState';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * JingleSession provides an API to manage a single Jingle session. We will\r\n * have different implementations depending on the underlying interface used\r\n * (i.e. WebRTC and ORTC) and here we hold the code common to all of them.\r\n */\r\nexport default class JingleSession extends Listenable {\r\n\r\n    /* eslint-disable max-params */\r\n\r\n    /**\r\n     * Creates new <tt>JingleSession</tt>.\r\n     * @param {string} sid the Jingle session identifier\r\n     * @param {string} localJid our JID\r\n     * @param {string} remoteJid the JID of the remote peer\r\n     * @param {XmppConnection} connection the XMPP connection\r\n     * @param {Object} mediaConstraints the media constraints object passed to the PeerConnection onCreateAnswer/Offer.\r\n     * @param {Object} pcConfig The {@code RTCConfiguration} object passed to the PeerConnection's constructor.\r\n     * @param {boolean} isInitiator indicates if it will be the side which initiates the session.\r\n     */\r\n    constructor(\r\n            sid,\r\n            localJid,\r\n            remoteJid,\r\n            connection,\r\n            mediaConstraints,\r\n            pcConfig,\r\n            isInitiator) {\r\n        super();\r\n        this.sid = sid;\r\n        this.localJid = localJid;\r\n        this.remoteJid = remoteJid;\r\n        this.connection = connection;\r\n        this.mediaConstraints = mediaConstraints;\r\n        this.pcConfig = pcConfig;\r\n\r\n        /**\r\n         * Indicates whether this instance is an initiator or an answerer of\r\n         * the Jingle session.\r\n         * @type {boolean}\r\n         */\r\n        this.isInitiator = isInitiator;\r\n\r\n        /**\r\n         * Whether to use dripping or not. Dripping is sending trickle\r\n         * candidates not one-by-one.\r\n         */\r\n        this.usedrip = true;\r\n\r\n        /**\r\n         *  When dripping is used, stores ICE candidates which are to be sent.\r\n         */\r\n        this.dripContainer = [];\r\n\r\n        /**\r\n         * The chat room instance associated with the session.\r\n         * @type {ChatRoom}\r\n         */\r\n        this.room = null;\r\n\r\n        /**\r\n         * The signaling layer.\r\n         * @type {SignalingLayerImpl | null}\r\n         * @private\r\n         */\r\n        this._signalingLayer = null;\r\n\r\n        /**\r\n         * Jingle session state - uninitialized until {@link initialize} is\r\n         * called @type {JingleSessionState}\r\n         */\r\n        this.state = null;\r\n\r\n        /**\r\n         * The RTC service instance\r\n         * @type {RTC}\r\n         */\r\n        this.rtc = null;\r\n    }\r\n\r\n    /**\r\n     * Returns XMPP address of this session's initiator.\r\n     * @return {string}\r\n     */\r\n    get initiatorJid() {\r\n        return this.isInitiator ? this.localJid : this.remoteJid;\r\n    }\r\n\r\n    /**\r\n     * Returns XMPP address of this session's responder.\r\n     * @return {string}\r\n     */\r\n    get responderJid() {\r\n        return this.isInitiator ? this.remoteJid : this.localJid;\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * Prepares this object to initiate a session.\r\n     * @param {ChatRoom} room the chat room for the conference associated with\r\n     * this session\r\n     * @param {RTC} rtc the RTC service instance\r\n     * @param {SignalingLayerImpl} signalingLayer - The signaling layer instance.\r\n     * @param {object} options - the options, see implementing class's\r\n     * {@link #doInitialize} description for more details.\r\n     */\r\n    initialize(room, rtc, signalingLayer, options) {\r\n        if (this.state !== null) {\r\n            const errmsg\r\n                = `attempt to initiate on session ${this.sid}\r\n                   in state ${this.state}`;\r\n\r\n            logger.error(errmsg);\r\n            throw new Error(errmsg);\r\n        }\r\n\r\n        // TODO decouple from room\r\n        this.room = room;\r\n        this.rtc = rtc;\r\n        this._signalingLayer = signalingLayer;\r\n        this.state = JingleSessionState.PENDING;\r\n        this.doInitialize(options);\r\n    }\r\n\r\n    /**\r\n     * The implementing class finishes initialization here. Called at the end of\r\n     * {@link initialize}.\r\n     * @param {Object} options - The options specific to the implementing class.\r\n     * @protected\r\n     */\r\n    doInitialize(options) { } // eslint-disable-line no-unused-vars, no-empty-function, max-len\r\n\r\n    /* eslint-disable no-unused-vars, no-empty-function */\r\n\r\n    /**\r\n     * Adds the ICE candidates found in the 'contents' array as remote\r\n     * candidates?\r\n     * Note: currently only used on transport-info\r\n     *\r\n     * @param contents\r\n     */\r\n    addIceCandidates(contents) {}\r\n\r\n    /* eslint-enable no-unused-vars, no-empty-function */\r\n\r\n    /**\r\n     * Returns current state of this <tt>JingleSession</tt> instance.\r\n     * @returns {JingleSessionState} the current state of this session instance.\r\n     */\r\n    getState() {\r\n        return this.state;\r\n    }\r\n\r\n    /* eslint-disable no-unused-vars, no-empty-function */\r\n\r\n    /**\r\n     * Handles an 'add-source' event.\r\n     *\r\n     * @param contents an array of Jingle 'content' elements.\r\n     */\r\n    addSources(contents) {}\r\n\r\n    /**\r\n     * Handles a 'remove-source' event.\r\n     *\r\n     * @param contents an array of Jingle 'content' elements.\r\n     */\r\n    removeSources(contents) {}\r\n\r\n    /**\r\n     * Terminates this Jingle session by sending session-terminate\r\n     * @param success a callback called once the 'session-terminate' packet has\r\n     * been acknowledged with RESULT.\r\n     * @param failure a callback called when either timeout occurs or ERROR\r\n     * response is received.\r\n     * @param {Object} options\r\n     * @param {string} [options.reason] XMPP Jingle error condition\r\n     * @param {string} [options.reasonDescription] some meaningful error message\r\n     * @param {boolean} [options.requestRestart=false] set to true to ask Jicofo to start a new session one this once is\r\n     * terminated.\r\n     * @param {boolean} [options.sendSessionTerminate=true] set to false to skip\r\n     * sending session-terminate. It may not make sense to send it if the XMPP\r\n     * connection has been closed already or if the remote peer has disconnected\r\n     */\r\n    terminate(success, failure, options) {}\r\n\r\n    /**\r\n     * Handles an offer from the remote peer (prepares to accept a session).\r\n     * @param jingle the 'jingle' XML element.\r\n     * @param success callback called when we the incoming session has been\r\n     * accepted\r\n     * @param failure callback called when we fail for any reason, will supply\r\n     * error object with details(which is meant more to be printed to the logger\r\n     * than analysed in the code, as the error is unrecoverable anyway)\r\n     */\r\n    acceptOffer(jingle, success, failure) {}\r\n\r\n    /**\r\n     * Returns the JID of the initiator of the jingle session.\r\n     */\r\n    _getInitiatorJid() {\r\n        return this.isInitiator ? this.localJid : this.remoteJid;\r\n    }\r\n\r\n    /* eslint-enable no-unused-vars, no-empty-function */\r\n}\r\n","enum MediaSessionEvents {\r\n    /**\r\n     * Event triggered when the remote party signals video max frame heights for its local sources.\r\n     */\r\n    REMOTE_SOURCE_CONSTRAINTS_CHANGED = 'media_session.REMOTE_SOURCE_CONSTRAINTS_CHANGED',\r\n\r\n    /**\r\n     * Event triggered when the remote party signals it's receive video max frame height.\r\n     */\r\n    REMOTE_VIDEO_CONSTRAINTS_CHANGED = 'media_session.REMOTE_VIDEO_CONSTRAINTS_CHANGED'\r\n};\r\n\r\nexport default MediaSessionEvents;","import { getLogger } from '@jitsi/logger';\r\nimport $ from 'jquery';\r\nimport { $build, $iq, Strophe } from 'strophe.js';\r\n\r\nimport { JitsiTrackEvents } from '../../JitsiTrackEvents';\r\nimport * as CodecMimeType from '../../service/RTC/CodecMimeType';\r\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport {\r\n    ICE_DURATION,\r\n    ICE_STATE_CHANGED\r\n} from '../../service/statistics/AnalyticsEvents';\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\nimport { SS_DEFAULT_FRAME_RATE } from '../RTC/ScreenObtainer';\r\nimport FeatureFlags from '../flags/FeatureFlags';\r\nimport SDP from '../sdp/SDP';\r\nimport SDPDiffer from '../sdp/SDPDiffer';\r\nimport SDPUtil from '../sdp/SDPUtil';\r\nimport Statistics from '../statistics/statistics';\r\nimport AsyncQueue from '../util/AsyncQueue';\r\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\r\nimport { integerHash } from '../util/StringUtils';\r\n\r\nimport browser from './../browser';\r\nimport JingleSession from './JingleSession';\r\nimport * as JingleSessionState from './JingleSessionState';\r\nimport MediaSessionEvents from './MediaSessionEvents';\r\nimport XmppConnection from './XmppConnection';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Constant tells how long we're going to wait for IQ response, before timeout\r\n * error is  triggered.\r\n * @type {number}\r\n */\r\nconst IQ_TIMEOUT = 10000;\r\n\r\n/*\r\n * The default number of samples (per stat) to keep when webrtc stats gathering\r\n * is enabled in TraceablePeerConnection.\r\n */\r\nconst DEFAULT_MAX_STATS = 300;\r\n\r\n/**\r\n * The time duration for which the client keeps gathering ICE candidates to be sent out in a single IQ.\r\n * @type {number} timeout in ms.\r\n */\r\nconst ICE_CAND_GATHERING_TIMEOUT = 150;\r\n\r\n/**\r\n * Reads the endpoint ID given a string which represents either the endpoint's full JID, or the endpoint ID itself.\r\n * @param {String} jidOrEndpointId A string which is either the full JID of a participant, or the ID of an\r\n * endpoint/participant.\r\n * @returns The endpoint ID associated with 'jidOrEndpointId'.\r\n */\r\nfunction getEndpointId(jidOrEndpointId) {\r\n    return Strophe.getResourceFromJid(jidOrEndpointId) || jidOrEndpointId;\r\n}\r\n\r\n/**\r\n * Add \"source\" element as a child of \"description\" element.\r\n * @param {Object} description The \"description\" element to add to.\r\n * @param {Object} s Contains properties of the source being added.\r\n * @param {Number} ssrc_ The SSRC.\r\n * @param {String} msid The \"msid\" attribute.\r\n */\r\nfunction _addSourceElement(description, s, ssrc_, msid) {\r\n\r\n    description.c('source', {\r\n        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\r\n        ssrc: ssrc_,\r\n        name: s.source\r\n    })\r\n        .c('parameter', {\r\n            name: 'msid',\r\n            value: msid\r\n        })\r\n        .up()\r\n        .c('ssrc-info', {\r\n            xmlns: 'http://jitsi.org/jitmeet',\r\n            owner: s.owner\r\n        })\r\n        .up()\r\n        .up();\r\n}\r\n\r\n/**\r\n * @typedef {Object} JingleSessionPCOptions\r\n * @property {Object} abTesting - A/B testing related options (ask George).\r\n * @property {boolean} abTesting.enableSuspendVideoTest - enables the suspend\r\n * video test ?(ask George).\r\n * @property {boolean} disableH264 - Described in the config.js[1].\r\n * @property {boolean} disableRtx - Described in the config.js[1].\r\n * @property {boolean} disableSimulcast - Described in the config.js[1].\r\n * @property {boolean} enableInsertableStreams - Set to true when the insertable streams constraints is to be enabled\r\n * on the PeerConnection.\r\n * @property {boolean} failICE - it's an option used in the tests. Set to\r\n * <tt>true</tt> to block any real candidates and make the ICE fail.\r\n * @property {boolean} gatherStats - Described in the config.js[1].\r\n * @property {object} p2p - Peer to peer related options (FIXME those could be\r\n * fetched from config.p2p on the upper level).\r\n * @property {boolean} preferH264 - Described in the config.js[1].\r\n * @property {Object} testing - Testing and/or experimental options.\r\n * @property {boolean} webrtcIceUdpDisable - Described in the config.js[1].\r\n * @property {boolean} webrtcIceTcpDisable - Described in the config.js[1].\r\n *\r\n * [1]: https://github.com/jitsi/jitsi-meet/blob/master/config.js\r\n */\r\n/**\r\n *\r\n */\r\nexport default class JingleSessionPC extends JingleSession {\r\n    /**\r\n     * Parses 'senders' attribute of the video content.\r\n     * @param {jQuery} jingleContents\r\n     * @return {string|null} one of the values of content \"senders\" attribute\r\n     * defined by Jingle. If there is no \"senders\" attribute or if the value is\r\n     * invalid then <tt>null</tt> will be returned.\r\n     * @private\r\n     */\r\n    static parseVideoSenders(jingleContents) {\r\n        const videoContents = jingleContents.find('>content[name=\"video\"]');\r\n\r\n        if (videoContents.length) {\r\n            const senders = videoContents[0].getAttribute('senders');\r\n\r\n            if (senders === 'both'\r\n                || senders === 'initiator'\r\n                || senders === 'responder'\r\n                || senders === 'none') {\r\n                return senders;\r\n            }\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * Parses the video max frame height value out of the 'content-modify' IQ.\r\n     *\r\n     * @param {jQuery} jingleContents - A jQuery selector pointing to the '>jingle' element.\r\n     * @returns {Number|null}\r\n     */\r\n    static parseMaxFrameHeight(jingleContents) {\r\n        const maxFrameHeightSel = jingleContents.find('>content[name=\"video\"]>max-frame-height');\r\n\r\n        return maxFrameHeightSel.length ? Number(maxFrameHeightSel.text()) : null;\r\n    }\r\n\r\n    /**\r\n     * Parses the source-name and max frame height value of the 'content-modify' IQ when source-name signaling\r\n     * is enabled.\r\n     *\r\n     * @param {jQuery} jingleContents - A jQuery selector pointing to the '>jingle' element.\r\n     * @returns {Object|null}\r\n     */\r\n    static parseSourceMaxFrameHeight(jingleContents) {\r\n        const receiverConstraints = [];\r\n        const sourceFrameHeightSel = jingleContents.find('>content[name=\"video\"]>source-frame-height');\r\n        let maxHeight, sourceName;\r\n\r\n        if (sourceFrameHeightSel.length) {\r\n            sourceFrameHeightSel.each((_, source) => {\r\n                sourceName = source.getAttribute('sourceName');\r\n                maxHeight = source.getAttribute('maxHeight');\r\n                receiverConstraints.push({\r\n                    maxHeight,\r\n                    sourceName\r\n                });\r\n            });\r\n\r\n            return receiverConstraints;\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    /* eslint-disable max-params */\r\n\r\n    /**\r\n     * Creates new <tt>JingleSessionPC</tt>\r\n     * @param {string} sid the Jingle Session ID - random string which identifies the session\r\n     * @param {string} localJid our JID\r\n     * @param {string} remoteJid remote peer JID\r\n     * @param {XmppConnection} connection - The XMPP connection instance.\r\n     * @param mediaConstraints the media constraints object passed to createOffer/Answer, as defined\r\n     * by the WebRTC standard\r\n     * @param pcConfig The {@code RTCConfiguration} to use for the WebRTC peer connection.\r\n     * @param {boolean} isP2P indicates whether this instance is meant to be used in a direct, peer to\r\n     * peer connection or <tt>false</tt> if it's a JVB connection.\r\n     * @param {boolean} isInitiator indicates if it will be the side which initiates the session.\r\n     * @constructor\r\n     *\r\n     * @implements {SignalingLayer}\r\n     */\r\n    constructor(\r\n            sid,\r\n            localJid,\r\n            remoteJid,\r\n            connection,\r\n            mediaConstraints,\r\n            pcConfig,\r\n            isP2P,\r\n            isInitiator) {\r\n        super(\r\n            sid,\r\n            localJid,\r\n            remoteJid, connection, mediaConstraints, pcConfig, isInitiator);\r\n\r\n        /**\r\n         * The bridge session's identifier. One Jingle session can during\r\n         * it's lifetime participate in multiple bridge sessions managed by\r\n         * Jicofo. A new bridge session is started whenever Jicofo sends\r\n         * 'session-initiate' or 'transport-replace'.\r\n         *\r\n         * @type {?string}\r\n         * @private\r\n         */\r\n        this._bridgeSessionId = null;\r\n\r\n        /**\r\n         * The oldest SDP passed to {@link notifyMySSRCUpdate} while the XMPP connection was offline that will be\r\n         * used to update Jicofo once the XMPP connection goes back online.\r\n         * @type {SDP|undefined}\r\n         * @private\r\n         */\r\n        this._cachedOldLocalSdp = undefined;\r\n\r\n        /**\r\n         * The latest SDP passed to {@link notifyMySSRCUpdate} while the XMPP connection was offline that will be\r\n         * used to update Jicofo once the XMPP connection goes back online.\r\n         * @type {SDP|undefined}\r\n         * @private\r\n         */\r\n        this._cachedNewLocalSdp = undefined;\r\n\r\n        /**\r\n         * Stores result of {@link window.performance.now()} at the time when\r\n         * ICE enters 'checking' state.\r\n         * @type {number|null} null if no value has been stored yet\r\n         * @private\r\n         */\r\n        this._iceCheckingStartedTimestamp = null;\r\n\r\n        /**\r\n         * Stores result of {@link window.performance.now()} at the time when\r\n         * first ICE candidate is spawned by the peerconnection to mark when\r\n         * ICE gathering started. That's, because ICE gathering state changed\r\n         * events are not supported by most of the browsers, so we try something\r\n         * that will work everywhere. It may not be as accurate, but given that\r\n         * 'host' candidate usually comes first, the delay should be minimal.\r\n         * @type {number|null} null if no value has been stored yet\r\n         * @private\r\n         */\r\n        this._gatheringStartedTimestamp = null;\r\n\r\n        /**\r\n         * Local preference for the receive video max frame height.\r\n         *\r\n         * @type {Number|undefined}\r\n         */\r\n        this.localRecvMaxFrameHeight = undefined;\r\n\r\n        /**\r\n         * Receiver constraints (max height) set by the application per remote source. Will be used for p2p connection\r\n         * in lieu of localRecvMaxFrameHeight when source-name signaling is enabled.\r\n         *\r\n         * @type {Map<string, number>}\r\n         */\r\n        this._sourceReceiverConstraints = undefined;\r\n\r\n        /**\r\n         * Indicates whether or not this session is willing to send/receive\r\n         * video media. When set to <tt>false</tt> the underlying peer\r\n         * connection will disable local video transfer and the remote peer will\r\n         * be will be asked to stop sending video via 'content-modify' IQ\r\n         * (the senders attribute of video contents will be adjusted\r\n         * accordingly). Note that this notification is sent only in P2P\r\n         * session, because Jicofo does not support it yet. Obviously when\r\n         * the value is changed from <tt>false</tt> to <tt>true</tt> another\r\n         * notification will be sent to resume video transfer on the remote\r\n         * side.\r\n         * @type {boolean}\r\n         * @private\r\n         */\r\n        this._localVideoActive = true;\r\n\r\n        /**\r\n         * Indicates whether or not the remote peer has video transfer active.\r\n         * When set to <tt>true</tt> it means that remote peer is neither\r\n         * sending nor willing to receive video. In such case we'll ask\r\n         * our peerconnection to stop sending video by calling\r\n         * {@link TraceablePeerConnection.setVideoTransferActive} with\r\n         * <tt>false</tt>.\r\n         * @type {boolean}\r\n         * @private\r\n         */\r\n        this._remoteVideoActive = true;\r\n\r\n        /**\r\n         * Marks that ICE gathering duration has been reported already. That\r\n         * prevents reporting it again, after eventual 'transport-replace' (JVB\r\n         * conference migration/ICE restart).\r\n         * @type {boolean}\r\n         * @private\r\n         */\r\n        this._gatheringReported = false;\r\n\r\n        this.lasticecandidate = false;\r\n        this.closed = false;\r\n\r\n        /**\r\n         * Indicates whether or not this <tt>JingleSessionPC</tt> is used in\r\n         * a peer to peer type of session.\r\n         * @type {boolean} <tt>true</tt> if it's a peer to peer\r\n         * session or <tt>false</tt> if it's a JVB session\r\n         */\r\n        this.isP2P = isP2P;\r\n\r\n        /**\r\n         * Remote preference for the receive video max frame height.\r\n         *\r\n         * @type {Number|undefined}\r\n         */\r\n        this.remoteRecvMaxFrameHeight = undefined;\r\n\r\n        /**\r\n         * Number of remote video sources, in SSRC rewriting mode.\r\n         * Used to generate next unique msid attribute.\r\n         *\r\n         * @type {Number}\r\n         */\r\n        this.numRemoteVideoSources = 0;\r\n\r\n        /**\r\n         * Number of remote audio sources, in SSRC rewriting mode.\r\n         * Used to generate next unique msid attribute.\r\n         *\r\n         * @type {Number}\r\n         */\r\n        this.numRemoteAudioSources = 0;\r\n\r\n        /**\r\n         * Remote preference for the receive video max frame heights when source-name signaling is enabled.\r\n         *\r\n         * @type {Map<string, number>|undefined}\r\n         */\r\n        this.remoteSourceMaxFrameHeights = undefined;\r\n\r\n        /**\r\n         * The queue used to serialize operations done on the peerconnection.\r\n         *\r\n         * @type {AsyncQueue}\r\n         */\r\n        this.modificationQueue = new AsyncQueue();\r\n\r\n        /**\r\n         * Flag used to guarantee that the connection established event is\r\n         * triggered just once.\r\n         * @type {boolean}\r\n         */\r\n        this.wasConnected = false;\r\n\r\n        /**\r\n         * Keeps track of how long (in ms) it took from ICE start to ICE\r\n         * connect.\r\n         *\r\n         * @type {number}\r\n         */\r\n        this.establishmentDuration = undefined;\r\n\r\n        this._xmppListeners = [];\r\n        this._xmppListeners.push(\r\n            connection.addEventListener(\r\n                XmppConnection.Events.CONN_STATUS_CHANGED,\r\n                this.onXmppStatusChanged.bind(this))\r\n        );\r\n\r\n        this._removeSenderVideoConstraintsChangeListener = undefined;\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * Checks whether or not this session instance is still operational.\r\n     * @private\r\n     * @returns {boolean} {@code true} if operation or {@code false} otherwise.\r\n     */\r\n    _assertNotEnded() {\r\n        return this.state !== JingleSessionState.ENDED;\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     * @param {JingleSessionPCOptions} options  - a set of config options.\r\n     */\r\n    doInitialize(options) {\r\n        this.failICE = Boolean(options.failICE);\r\n        this.lasticecandidate = false;\r\n        this.options = options;\r\n\r\n        /**\r\n         * {@code true} if reconnect is in progress.\r\n         * @type {boolean}\r\n         */\r\n        this.isReconnect = false;\r\n\r\n        /**\r\n         * Set to {@code true} if the connection was ever stable\r\n         * @type {boolean}\r\n         */\r\n        this.wasstable = false;\r\n        this.webrtcIceUdpDisable = Boolean(options.webrtcIceUdpDisable);\r\n        this.webrtcIceTcpDisable = Boolean(options.webrtcIceTcpDisable);\r\n\r\n        const pcOptions = { disableRtx: options.disableRtx };\r\n\r\n        if (options.gatherStats) {\r\n            pcOptions.maxstats = DEFAULT_MAX_STATS;\r\n        }\r\n        pcOptions.capScreenshareBitrate = false;\r\n        pcOptions.enableInsertableStreams = options.enableInsertableStreams;\r\n        pcOptions.videoQuality = options.videoQuality;\r\n        pcOptions.forceTurnRelay = options.forceTurnRelay;\r\n        pcOptions.audioQuality = options.audioQuality;\r\n        pcOptions.usesUnifiedPlan = this.usesUnifiedPlan\r\n            = browser.supportsUnifiedPlan()\r\n                && (browser.isFirefox()\r\n                    || browser.isWebKitBased()\r\n                    || (browser.isChromiumBased()\r\n\r\n                        // Provide a way to control the behavior for jvb and p2p connections independently.\r\n                        && this.isP2P\r\n                        ? options.p2p?.enableUnifiedOnChrome ?? true\r\n                        : options.enableUnifiedOnChrome ?? true));\r\n\r\n        if (this.isP2P) {\r\n            // simulcast needs to be disabled for P2P (121) calls\r\n            pcOptions.disableSimulcast = true;\r\n            const abtestSuspendVideo = this._abtestSuspendVideoEnabled(options);\r\n\r\n            if (typeof abtestSuspendVideo !== 'undefined') {\r\n                pcOptions.abtestSuspendVideo = abtestSuspendVideo;\r\n            }\r\n        } else {\r\n            // H264 does not support simulcast, so it needs to be disabled.\r\n            pcOptions.disableSimulcast\r\n                = options.disableSimulcast\r\n                    || (options.preferH264 && !options.disableH264)\r\n                    || (options.videoQuality && options.videoQuality.preferredCodec === CodecMimeType.H264);\r\n\r\n            // Disable simulcast for low fps screenshare and enable it for high fps screenshare.\r\n            // testing.capScreenshareBitrate config.js setting has now been deprecated.\r\n            pcOptions.capScreenshareBitrate = pcOptions.disableSimulcast\r\n                || !(typeof options.desktopSharingFrameRate?.max === 'number'\r\n                    && options.desktopSharingFrameRate?.max > SS_DEFAULT_FRAME_RATE);\r\n\r\n            // add the capScreenshareBitrate to the permanent properties so that it's included with every event that we\r\n            // send to the analytics backend.\r\n            Statistics.analytics.addPermanentProperties({ capScreenshareBitrate: pcOptions.capScreenshareBitrate });\r\n        }\r\n\r\n        if (options.startSilent) {\r\n            pcOptions.startSilent = true;\r\n        }\r\n\r\n        this.peerconnection\r\n            = this.rtc.createPeerConnection(\r\n                    this._signalingLayer,\r\n                    this.pcConfig,\r\n                    this.isP2P,\r\n                    pcOptions);\r\n\r\n        this.peerconnection.onicecandidate = ev => {\r\n            if (!ev) {\r\n                // There was an incomplete check for ev before which left\r\n                // the last line of the function unprotected from a potential\r\n                // throw of an exception. Consequently, it may be argued that\r\n                // the check is unnecessary. Anyway, I'm leaving it and making\r\n                // the check complete.\r\n                return;\r\n            }\r\n\r\n            // XXX this is broken, candidate is not parsed.\r\n            const candidate = ev.candidate;\r\n            const now = window.performance.now();\r\n\r\n            if (candidate) {\r\n                if (this._gatheringStartedTimestamp === null) {\r\n                    this._gatheringStartedTimestamp = now;\r\n                }\r\n\r\n                // Discard candidates of disabled protocols.\r\n                let protocol = candidate.protocol;\r\n\r\n                if (typeof protocol === 'string') {\r\n                    protocol = protocol.toLowerCase();\r\n                    if (protocol === 'tcp' || protocol === 'ssltcp') {\r\n                        if (this.webrtcIceTcpDisable) {\r\n                            return;\r\n                        }\r\n                    } else if (protocol === 'udp') {\r\n                        if (this.webrtcIceUdpDisable) {\r\n                            return;\r\n                        }\r\n                    }\r\n                }\r\n            } else if (!this._gatheringReported) {\r\n                // End of gathering\r\n                Statistics.sendAnalytics(\r\n                    ICE_DURATION,\r\n                    {\r\n                        phase: 'gathering',\r\n                        value: now - this._gatheringStartedTimestamp,\r\n                        p2p: this.isP2P,\r\n                        initiator: this.isInitiator\r\n                    });\r\n                this._gatheringReported = true;\r\n            }\r\n            if (this.isP2P) {\r\n                this.sendIceCandidate(candidate);\r\n            }\r\n        };\r\n\r\n        // Note there is a change in the spec about closed:\r\n        // This value moved into the RTCPeerConnectionState enum in\r\n        // the May 13, 2016 draft of the specification, as it reflects the state\r\n        // of the RTCPeerConnection, not the signaling connection. You now\r\n        // detect a closed connection by checking for connectionState to be\r\n        // \"closed\" instead.\r\n        // I suppose at some point this will be moved to onconnectionstatechange\r\n        this.peerconnection.onsignalingstatechange = () => {\r\n            if (this.peerconnection.signalingState === 'stable') {\r\n                this.wasstable = true;\r\n            } else if (this.peerconnection.signalingState === 'closed'\r\n                || this.peerconnection.connectionState === 'closed') {\r\n                this.room.eventEmitter.emit(XMPPEvents.SUSPEND_DETECTED, this);\r\n            }\r\n        };\r\n\r\n        /**\r\n         * The oniceconnectionstatechange event handler contains the code to\r\n         * execute when the iceconnectionstatechange event, of type Event,\r\n         * is received by this RTCPeerConnection. Such an event is sent when\r\n         * the value of RTCPeerConnection.iceConnectionState changes.\r\n         */\r\n        this.peerconnection.oniceconnectionstatechange = () => {\r\n            const now = window.performance.now();\r\n            let isStable = false;\r\n\r\n            if (!this.isP2P) {\r\n                this.room.connectionTimes[\r\n                    `ice.state.${this.peerconnection.iceConnectionState}`]\r\n                    = now;\r\n            }\r\n            logger.log(`(TIME) ICE ${this.peerconnection.iceConnectionState} ${this.isP2P ? 'P2P' : 'JVB'}:\\t`, now);\r\n\r\n            Statistics.sendAnalytics(\r\n                ICE_STATE_CHANGED,\r\n                {\r\n                    p2p: this.isP2P,\r\n                    state: this.peerconnection.iceConnectionState,\r\n                    'signaling_state': this.peerconnection.signalingState,\r\n                    reconnect: this.isReconnect,\r\n                    value: now\r\n                });\r\n\r\n            this.room.eventEmitter.emit(\r\n                XMPPEvents.ICE_CONNECTION_STATE_CHANGED,\r\n                this,\r\n                this.peerconnection.iceConnectionState);\r\n            switch (this.peerconnection.iceConnectionState) {\r\n            case 'checking':\r\n                this._iceCheckingStartedTimestamp = now;\r\n                break;\r\n            case 'connected':\r\n                // Informs interested parties that the connection has been restored. This includes the case when\r\n                // media connection to the bridge has been restored after an ICE failure by using session-terminate.\r\n                if (this.peerconnection.signalingState === 'stable') {\r\n                    isStable = true;\r\n                    const usesTerminateForRestart = !this.options.enableIceRestart\r\n                        && this.room.supportsRestartByTerminate();\r\n\r\n                    if (this.isReconnect || usesTerminateForRestart) {\r\n                        this.room.eventEmitter.emit(\r\n                            XMPPEvents.CONNECTION_RESTORED, this);\r\n                    }\r\n                }\r\n\r\n                // Add a workaround for an issue on chrome in Unified plan when the local endpoint is the offerer.\r\n                // The 'signalingstatechange' event for 'stable' is handled after the 'iceconnectionstatechange' event\r\n                // for 'completed' is handled by the client. This prevents the client from firing a\r\n                // CONNECTION_ESTABLISHED event for the p2p session. As a result, the offerer continues to stay on the\r\n                // jvb connection while the remote peer switches to the p2p connection breaking the media flow between\r\n                // the endpoints.\r\n                // TODO - file a chromium bug and add the information here.\r\n                if (!this.wasConnected\r\n                    && (this.wasstable\r\n                        || isStable\r\n                        || (this.usesUnifiedPlan && this.isInitiator && browser.isChromiumBased()))) {\r\n\r\n                    Statistics.sendAnalytics(\r\n                        ICE_DURATION,\r\n                        {\r\n                            phase: 'checking',\r\n                            value: now - this._iceCheckingStartedTimestamp,\r\n                            p2p: this.isP2P,\r\n                            initiator: this.isInitiator\r\n                        });\r\n\r\n                    // Switch between ICE gathering and ICE checking whichever\r\n                    // started first (scenarios are different for initiator\r\n                    // vs responder)\r\n                    const iceStarted\r\n                        = Math.min(\r\n                            this._iceCheckingStartedTimestamp,\r\n                            this._gatheringStartedTimestamp);\r\n\r\n                    this.establishmentDuration = now - iceStarted;\r\n\r\n                    Statistics.sendAnalytics(\r\n                        ICE_DURATION,\r\n                        {\r\n                            phase: 'establishment',\r\n                            value: this.establishmentDuration,\r\n                            p2p: this.isP2P,\r\n                            initiator: this.isInitiator\r\n                        });\r\n\r\n                    this.wasConnected = true;\r\n                    this.room.eventEmitter.emit(\r\n                        XMPPEvents.CONNECTION_ESTABLISHED, this);\r\n                }\r\n                this.isReconnect = false;\r\n                break;\r\n            case 'disconnected':\r\n                this.isReconnect = true;\r\n\r\n                // Informs interested parties that the connection has been\r\n                // interrupted.\r\n                if (this.wasstable) {\r\n                    this.room.eventEmitter.emit(\r\n                        XMPPEvents.CONNECTION_INTERRUPTED, this);\r\n                }\r\n                break;\r\n            case 'failed':\r\n                this.room.eventEmitter.emit(\r\n                    XMPPEvents.CONNECTION_ICE_FAILED, this);\r\n                break;\r\n            }\r\n        };\r\n\r\n\r\n        /**\r\n         * The connection state event is fired whenever the aggregate of underlying\r\n         * transports change their state.\r\n         */\r\n        this.peerconnection.onconnectionstatechange = () => {\r\n            const icestate = this.peerconnection.iceConnectionState;\r\n\r\n            switch (this.peerconnection.connectionState) {\r\n            case 'failed':\r\n                // Since version 76 Chrome no longer switches ICE connection\r\n                // state to failed (see\r\n                // https://bugs.chromium.org/p/chromium/issues/detail?id=982793\r\n                // for details) we use this workaround to recover from lost connections\r\n                if (icestate === 'disconnected') {\r\n                    this.room.eventEmitter.emit(\r\n                        XMPPEvents.CONNECTION_ICE_FAILED, this);\r\n                }\r\n                break;\r\n            }\r\n        };\r\n\r\n        /**\r\n         * The negotiationneeded event is fired whenever we shake the media on the\r\n         * RTCPeerConnection object.\r\n         */\r\n        this.peerconnection.onnegotiationneeded = () => {\r\n            const state = this.peerconnection.signalingState;\r\n            const remoteDescription = this.peerconnection.remoteDescription;\r\n\r\n            if (this.usesUnifiedPlan\r\n                && !this.isP2P\r\n                && state === 'stable'\r\n                && remoteDescription\r\n                && typeof remoteDescription.sdp === 'string') {\r\n                logger.info(`${this} onnegotiationneeded fired on ${this.peerconnection}`);\r\n\r\n                const workFunction = finishedCallback => {\r\n                    const oldSdp = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n                    this._renegotiate()\r\n                        .then(() => this.peerconnection.configureSenderVideoEncodings())\r\n                        .then(() => {\r\n                            const newSdp = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n                            this.notifyMySSRCUpdate(oldSdp, newSdp);\r\n                        })\r\n                        .then(() => finishedCallback(), error => finishedCallback(error));\r\n                };\r\n\r\n                this.modificationQueue.push(\r\n                    workFunction,\r\n                    error => {\r\n                        if (error) {\r\n                            logger.error(`${this} onnegotiationneeded error`, error);\r\n                        } else {\r\n                            logger.debug(`${this} onnegotiationneeded executed - OK`);\r\n                        }\r\n                    });\r\n            }\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Remote preference for receive video max frame height.\r\n     *\r\n     * @returns {Number|undefined}\r\n     */\r\n    getRemoteRecvMaxFrameHeight() {\r\n        if (this.isP2P) {\r\n            return this.remoteRecvMaxFrameHeight;\r\n        }\r\n\r\n        return undefined;\r\n    }\r\n\r\n    /**\r\n     * Remote preference for receive video max frame heights when source-name signaling is enabled.\r\n     *\r\n     * @returns {Map<string, number>|undefined}\r\n     */\r\n    getRemoteSourcesRecvMaxFrameHeight() {\r\n        if (this.isP2P) {\r\n            return this.remoteSourceMaxFrameHeights;\r\n        }\r\n\r\n        return undefined;\r\n    }\r\n\r\n    /**\r\n     * Sends given candidate in Jingle 'transport-info' message.\r\n     * @param {RTCIceCandidate} candidate the WebRTC ICE candidate instance\r\n     * @private\r\n     */\r\n    sendIceCandidate(candidate) {\r\n        const localSDP = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n        if (candidate && candidate.candidate.length && !this.lasticecandidate) {\r\n            const ice = SDPUtil.iceparams(localSDP.media[candidate.sdpMLineIndex], localSDP.session);\r\n            const jcand = SDPUtil.candidateToJingle(candidate.candidate);\r\n\r\n            if (!(ice && jcand)) {\r\n                const errorMesssage = 'failed to get ice && jcand';\r\n\r\n                GlobalOnErrorHandler.callErrorHandler(new Error(errorMesssage));\r\n                logger.error(errorMesssage);\r\n\r\n                return;\r\n            }\r\n            ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';\r\n\r\n            if (this.usedrip) {\r\n                if (this.dripContainer.length === 0) {\r\n                    setTimeout(() => {\r\n                        if (this.dripContainer.length === 0) {\r\n                            return;\r\n                        }\r\n                        this.sendIceCandidates(this.dripContainer);\r\n                        this.dripContainer = [];\r\n                    }, ICE_CAND_GATHERING_TIMEOUT);\r\n                }\r\n                this.dripContainer.push(candidate);\r\n            } else {\r\n                this.sendIceCandidates([ candidate ]);\r\n            }\r\n        } else {\r\n            logger.log(`${this} sendIceCandidate: last candidate`);\r\n\r\n            // FIXME: remember to re-think in ICE-restart\r\n            this.lasticecandidate = true;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sends given candidates in Jingle 'transport-info' message.\r\n     * @param {Array<RTCIceCandidate>} candidates an array of the WebRTC ICE\r\n     * candidate instances\r\n     * @private\r\n     */\r\n    sendIceCandidates(candidates) {\r\n        if (!this._assertNotEnded('sendIceCandidates')) {\r\n\r\n            return;\r\n        }\r\n\r\n        logger.log(`${this} sendIceCandidates ${JSON.stringify(candidates)}`);\r\n        const cand = $iq({ to: this.remoteJid,\r\n            type: 'set' })\r\n            .c('jingle', { xmlns: 'urn:xmpp:jingle:1',\r\n                action: 'transport-info',\r\n                initiator: this.initiatorJid,\r\n                sid: this.sid });\r\n\r\n        const localSDP = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n        for (let mid = 0; mid < localSDP.media.length; mid++) {\r\n            const cands = candidates.filter(el => el.sdpMLineIndex === mid);\r\n            const mline\r\n                = SDPUtil.parseMLine(localSDP.media[mid].split('\\r\\n')[0]);\r\n\r\n            if (cands.length > 0) {\r\n                const ice\r\n                    = SDPUtil.iceparams(localSDP.media[mid], localSDP.session);\r\n\r\n                ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';\r\n                cand.c('content', {\r\n                    creator: this.initiatorJid === this.localJid\r\n                        ? 'initiator' : 'responder',\r\n                    name: cands[0].sdpMid ? cands[0].sdpMid : mline.media\r\n                }).c('transport', ice);\r\n                for (let i = 0; i < cands.length; i++) {\r\n                    const candidate\r\n                        = SDPUtil.candidateToJingle(cands[i].candidate);\r\n\r\n                    // Mangle ICE candidate if 'failICE' test option is enabled\r\n\r\n                    if (this.failICE) {\r\n                        candidate.ip = '1.1.1.1';\r\n                    }\r\n                    cand.c('candidate', candidate).up();\r\n                }\r\n\r\n                // add fingerprint\r\n                const fingerprintLine\r\n                    = SDPUtil.findLine(\r\n                        localSDP.media[mid],\r\n                        'a=fingerprint:', localSDP.session);\r\n\r\n                if (fingerprintLine) {\r\n                    const tmp = SDPUtil.parseFingerprint(fingerprintLine);\r\n\r\n                    tmp.required = true;\r\n                    cand.c(\r\n                        'fingerprint',\r\n                        { xmlns: 'urn:xmpp:jingle:apps:dtls:0' })\r\n                        .t(tmp.fingerprint);\r\n                    delete tmp.fingerprint;\r\n                    cand.attrs(tmp);\r\n                    cand.up();\r\n                }\r\n                cand.up(); // transport\r\n                cand.up(); // content\r\n            }\r\n        }\r\n\r\n        // might merge last-candidate notification into this, but it is called\r\n        // a lot later. See webrtc issue #2340\r\n        // logger.log('was this the last candidate', this.lasticecandidate);\r\n        this.connection.sendIQ(\r\n            cand, null, this.newJingleErrorHandler(cand), IQ_TIMEOUT);\r\n    }\r\n\r\n    /**\r\n     * Sends Jingle 'session-info' message which includes custom Jitsi Meet\r\n     * 'ice-state' element with the text value 'failed' to let Jicofo know\r\n     * that the ICE connection has entered the failed state. It can then\r\n     * choose to re-create JVB channels and send 'transport-replace' to\r\n     * retry the connection.\r\n     */\r\n    sendIceFailedNotification() {\r\n        const sessionInfo\r\n            = $iq({\r\n                to: this.remoteJid,\r\n                type: 'set' })\r\n            .c('jingle', { xmlns: 'urn:xmpp:jingle:1',\r\n                action: 'session-info',\r\n                initiator: this.initiatorJid,\r\n                sid: this.sid })\r\n            .c('ice-state', { xmlns: 'http://jitsi.org/protocol/focus' })\r\n            .t('failed')\r\n            .up();\r\n\r\n        this._bridgeSessionId\r\n            && sessionInfo.c(\r\n                'bridge-session', {\r\n                    xmlns: 'http://jitsi.org/protocol/focus',\r\n                    id: this._bridgeSessionId\r\n                });\r\n\r\n        this.connection.sendIQ2(\r\n            sessionInfo, {\r\n                /*\r\n                 * This message will be often sent when there are connectivity\r\n                 * issues, so make it slightly longer than Prosody's default BOSH\r\n                 * inactivity timeout of 60 seconds.\r\n                 */\r\n                timeout: 65\r\n            })\r\n            .catch(this.newJingleErrorHandler(sessionInfo));\r\n    }\r\n\r\n    /**\r\n     * {@inheritDoc}\r\n     */\r\n    addIceCandidates(elem) {\r\n        if (this.peerconnection.signalingState === 'closed') {\r\n            logger.warn(`${this} Ignored add ICE candidate when in closed state`);\r\n\r\n            return;\r\n        }\r\n\r\n        const iceCandidates = [];\r\n\r\n        elem.find('>content>transport>candidate')\r\n            .each((idx, candidate) => {\r\n                let line = SDPUtil.candidateFromJingle(candidate);\r\n\r\n                line = line.replace('\\r\\n', '').replace('a=', '');\r\n\r\n                // FIXME this code does not care to handle\r\n                // non-bundle transport\r\n                const rtcCandidate = new RTCIceCandidate({\r\n                    sdpMLineIndex: 0,\r\n\r\n                    // FF comes up with more complex names like audio-23423,\r\n                    // Given that it works on both Chrome and FF without\r\n                    // providing it, let's leave it like this for the time\r\n                    // being...\r\n                    // sdpMid: 'audio',\r\n                    sdpMid: '',\r\n                    candidate: line\r\n                });\r\n\r\n                iceCandidates.push(rtcCandidate);\r\n            });\r\n\r\n        if (!iceCandidates.length) {\r\n            logger.error(`${this} No ICE candidates to add ?`, elem[0] && elem[0].outerHTML);\r\n\r\n            return;\r\n        }\r\n\r\n        // We want to have this task queued, so that we know it is executed,\r\n        // after the initial sRD/sLD offer/answer cycle was done (based on\r\n        // the assumption that candidates are spawned after the offer/answer\r\n        // and XMPP preserves order).\r\n        const workFunction = finishedCallback => {\r\n            for (const iceCandidate of iceCandidates) {\r\n                this.peerconnection.addIceCandidate(iceCandidate)\r\n                    .then(\r\n                        () => logger.debug(`${this} addIceCandidate ok!`),\r\n                        err => logger.error(`${this} addIceCandidate failed!`, err));\r\n            }\r\n\r\n            finishedCallback();\r\n            logger.debug(`${this} ICE candidates task finished`);\r\n        };\r\n\r\n        logger.debug(`${this} Queued add (${iceCandidates.length}) ICE candidates task`);\r\n        this.modificationQueue.push(workFunction);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param contents\r\n     */\r\n    readSsrcInfo(contents) {\r\n        const ssrcs = $(contents).find('>description>source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]');\r\n\r\n        ssrcs.each((i, ssrcElement) => {\r\n            const ssrc = Number(ssrcElement.getAttribute('ssrc'));\r\n\r\n            if (ssrcElement.hasAttribute('name')) {\r\n                const sourceName = ssrcElement.getAttribute('name');\r\n\r\n                this._signalingLayer.setTrackSourceName(ssrc, sourceName);\r\n            }\r\n\r\n            if (this.isP2P) {\r\n                // In P2P all SSRCs are owner by the remote peer\r\n                this._signalingLayer.setSSRCOwner(ssrc, Strophe.getResourceFromJid(this.remoteJid));\r\n            } else {\r\n                $(ssrcElement)\r\n                    .find('>ssrc-info[xmlns=\"http://jitsi.org/jitmeet\"]')\r\n                    .each((i3, ssrcInfoElement) => {\r\n                        const owner = ssrcInfoElement.getAttribute('owner');\r\n\r\n                        if (owner?.length) {\r\n                            if (isNaN(ssrc) || ssrc < 0) {\r\n                                logger.warn(`${this} Invalid SSRC ${ssrc} value received for ${owner}`);\r\n                            } else {\r\n                                this._signalingLayer.setSSRCOwner(ssrc, getEndpointId(owner));\r\n                            }\r\n                        }\r\n                    });\r\n            }\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Makes the underlying TraceablePeerConnection generate new SSRC for\r\n     * the recvonly video stream.\r\n     * @deprecated\r\n     */\r\n    generateRecvonlySsrc() {\r\n        if (this.peerconnection) {\r\n            this.peerconnection.generateRecvonlySsrc();\r\n        } else {\r\n            logger.error(`${this} Unable to generate recvonly SSRC - no peerconnection`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns the video codec configured as the preferred codec on the peerconnection.\r\n     */\r\n    getConfiguredVideoCodec() {\r\n        return this.peerconnection.getConfiguredVideoCodec();\r\n    }\r\n\r\n    /**\r\n     * Accepts incoming Jingle 'session-initiate' and should send 'session-accept' in result.\r\n     *\r\n     * @param jingleOffer jQuery selector pointing to the jingle element of the offer IQ\r\n     * @param success callback called when we accept incoming session successfully and receive RESULT packet to\r\n     * 'session-accept' sent.\r\n     * @param failure function(error) called if for any reason we fail to accept the incoming offer. 'error' argument\r\n     * can be used to log some details about the error.\r\n     * @param {Array<JitsiLocalTrack>} [localTracks] the optional list of the local tracks that will be added, before\r\n     * the offer/answer cycle executes. We allow the localTracks to optionally be passed in so that the addition of the\r\n     * local tracks and the processing of the initial offer can all be done atomically. We want to make sure that any\r\n     * other operations which originate in the XMPP Jingle messages related with this session to be executed with an\r\n     * assumption that the initial offer/answer cycle has been executed already.\r\n     */\r\n    acceptOffer(jingleOffer, success, failure, localTracks) {\r\n        this.setOfferAnswerCycle(\r\n            jingleOffer,\r\n            () => {\r\n                // FIXME we may not care about RESULT packet for session-accept\r\n                // then we should either call 'success' here immediately or\r\n                // modify sendSessionAccept method to do that\r\n                this.sendSessionAccept(() => {\r\n                    success();\r\n                    this.room.eventEmitter.emit(XMPPEvents.SESSION_ACCEPT, this);\r\n\r\n                    // The first video track is added to the peerconnection and signaled as part of the session-accept.\r\n                    // Add secondary video tracks (that were already added to conference) to the peerconnection here.\r\n                    // This will happen when someone shares a secondary source to a two people call, the other user\r\n                    // leaves and joins the call again, a new peerconnection is created for p2p/jvb connection. At this\r\n                    // point, there are 2 video tracks which need to be signaled to the remote peer.\r\n                    const videoTracks = localTracks.filter(track => track.getType() === MediaType.VIDEO);\r\n\r\n                    videoTracks.length && videoTracks.splice(0, 1);\r\n                    if (FeatureFlags.isMultiStreamSendSupportEnabled() && videoTracks.length) {\r\n                        this.addTracks(videoTracks);\r\n                    }\r\n                },\r\n                error => {\r\n                    failure(error);\r\n                    this.room.eventEmitter.emit(XMPPEvents.SESSION_ACCEPT_ERROR, this, error);\r\n                });\r\n            },\r\n            failure,\r\n            localTracks);\r\n    }\r\n\r\n    /**\r\n     * Creates an offer and sends Jingle 'session-initiate' to the remote peer.\r\n     *\r\n     * @param {Array<JitsiLocalTrack>} localTracks the local tracks that will be added, before the offer/answer cycle\r\n     * executes (for the local track addition to be an atomic operation together with the offer/answer).\r\n     */\r\n    invite(localTracks = []) {\r\n        if (!this.isInitiator) {\r\n            throw new Error('Trying to invite from the responder session');\r\n        }\r\n        const workFunction = finishedCallback => {\r\n            const addTracks = [];\r\n\r\n            for (const track of localTracks) {\r\n                addTracks.push(this.peerconnection.addTrack(track, this.isInitiator));\r\n            }\r\n\r\n            Promise.all(addTracks)\r\n                .then(() => this.peerconnection.createOffer(this.mediaConstraints))\r\n                .then(offerSdp => this.peerconnection.setLocalDescription(offerSdp))\r\n                .then(() => {\r\n                    this.peerconnection.processLocalSdpForTransceiverInfo(localTracks);\r\n\r\n                    // NOTE that the offer is obtained from the localDescription getter as it needs to go though\r\n                    // the transformation chain.\r\n                    this.sendSessionInitiate(this.peerconnection.localDescription.sdp);\r\n                })\r\n                .then(() => finishedCallback(), error => finishedCallback(error));\r\n        };\r\n\r\n        logger.debug(`${this} Queued invite task`);\r\n        this.modificationQueue.push(\r\n            workFunction,\r\n            error => {\r\n                if (error) {\r\n                    logger.error(`${this} invite error`, error);\r\n                } else {\r\n                    logger.debug(`${this} invite executed - OK`);\r\n                }\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Sends 'session-initiate' to the remote peer.\r\n     *\r\n     * NOTE this method is synchronous and we're not waiting for the RESULT\r\n     * response which would delay the startup process.\r\n     *\r\n     * @param {string} offerSdp  - The local session description which will be\r\n     * used to generate an offer.\r\n     * @private\r\n     */\r\n    sendSessionInitiate(offerSdp) {\r\n        let init = $iq({\r\n            to: this.remoteJid,\r\n            type: 'set'\r\n        }).c('jingle', {\r\n            xmlns: 'urn:xmpp:jingle:1',\r\n            action: 'session-initiate',\r\n            initiator: this.initiatorJid,\r\n            sid: this.sid\r\n        });\r\n\r\n        new SDP(offerSdp).toJingle(\r\n            init,\r\n            this.isInitiator ? 'initiator' : 'responder');\r\n        init = init.tree();\r\n        logger.debug(`${this} Session-initiate: `, init);\r\n        this.connection.sendIQ(init,\r\n            () => {\r\n                logger.info(`${this} Got RESULT for \"session-initiate\"`);\r\n            },\r\n            error => {\r\n                logger.error(`${this} \"session-initiate\" error`, error);\r\n            },\r\n            IQ_TIMEOUT);\r\n    }\r\n\r\n    /**\r\n     * Sets the answer received from the remote peer as the remote description.\r\n     *\r\n     * @param jingleAnswer\r\n     */\r\n    setAnswer(jingleAnswer) {\r\n        if (!this.isInitiator) {\r\n            throw new Error('Trying to set an answer on the responder session');\r\n        }\r\n\r\n        const workFunction = finishedCallback => {\r\n            const newRemoteSdp = this._processNewJingleOfferIq(jingleAnswer);\r\n            const oldLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\r\n            const remoteDescription = new RTCSessionDescription({\r\n                type: 'answer',\r\n                sdp: newRemoteSdp.raw\r\n            });\r\n\r\n            this.peerconnection.setRemoteDescription(remoteDescription)\r\n                .then(() => {\r\n                    if (this.state === JingleSessionState.PENDING) {\r\n                        this.state = JingleSessionState.ACTIVE;\r\n                        const newLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n                        this.sendContentModify();\r\n                        this.notifyMySSRCUpdate(oldLocalSdp, newLocalSdp);\r\n                    }\r\n                })\r\n                .then(() => finishedCallback(), error => finishedCallback(error));\r\n        };\r\n\r\n        logger.debug(`${this} Queued setAnswer task`);\r\n        this.modificationQueue.push(\r\n            workFunction,\r\n            error => {\r\n                if (error) {\r\n                    logger.error(`${this} setAnswer task failed: ${error}`);\r\n                } else {\r\n                    logger.debug(`${this} setAnswer task done`);\r\n                }\r\n            });\r\n    }\r\n\r\n    /**\r\n     * This is a setRemoteDescription/setLocalDescription cycle which starts at converting Strophe Jingle IQ into\r\n     * remote offer SDP. Once converted, setRemoteDescription, createAnswer and setLocalDescription calls follow.\r\n     *\r\n     * @param jingleOfferAnswerIq jQuery selector pointing to the jingle element of the offer (or answer) IQ\r\n     * @param success callback called when sRD/sLD cycle finishes successfully.\r\n     * @param failure callback called with an error object as an argument if we fail at any point during setRD,\r\n     * createAnswer, setLD.\r\n     * @param {Array<JitsiLocalTrack>} [localTracks] the optional list of the local tracks that will be added, before\r\n     * the offer/answer cycle executes (for the local track addition to be an atomic operation together with the\r\n     * offer/answer).\r\n     */\r\n    setOfferAnswerCycle(jingleOfferAnswerIq, success, failure, localTracks = []) {\r\n        const workFunction = finishedCallback => {\r\n            const addTracks = [];\r\n            const audioTracks = localTracks.filter(track => track.getType() === MediaType.AUDIO);\r\n            const videoTracks = localTracks.filter(track => track.getType() === MediaType.VIDEO);\r\n            let tracks = localTracks;\r\n\r\n            // Add only 1 video track at a time. Adding 2 or more video tracks to the peerconnection at the same time\r\n            // makes the browser go into a renegotiation loop by firing 'negotiationneeded' event after every\r\n            // renegotiation.\r\n            if (FeatureFlags.isMultiStreamSendSupportEnabled() && videoTracks.length > 1) {\r\n                tracks = [ ...audioTracks, videoTracks[0] ];\r\n            }\r\n            for (const track of tracks) {\r\n                addTracks.push(this.peerconnection.addTrack(track, this.isInitiator));\r\n            }\r\n            const newRemoteSdp = this._processNewJingleOfferIq(jingleOfferAnswerIq);\r\n            const oldLocalSdp = this.peerconnection.localDescription.sdp;\r\n\r\n            const bridgeSession = $(jingleOfferAnswerIq)\r\n                .find('>bridge-session[xmlns=\"http://jitsi.org/protocol/focus\"]');\r\n            const bridgeSessionId = bridgeSession.attr('id');\r\n\r\n            if (bridgeSessionId !== this._bridgeSessionId) {\r\n                this._bridgeSessionId = bridgeSessionId;\r\n            }\r\n            const remoteDescription = new RTCSessionDescription({\r\n                type: 'offer',\r\n                sdp: newRemoteSdp.raw\r\n            });\r\n\r\n            Promise.all(addTracks)\r\n                .then(() => this._responderRenegotiate(remoteDescription))\r\n                .then(() => {\r\n                    this.peerconnection.processLocalSdpForTransceiverInfo(tracks);\r\n                    if (this.state === JingleSessionState.PENDING) {\r\n                        this.state = JingleSessionState.ACTIVE;\r\n\r\n                        // #1 Sync up video transfer active/inactive only after the initial O/A cycle. We want to\r\n                        // adjust the video media direction only in the local SDP and the Jingle contents direction\r\n                        // included in the initial offer/answer is mapped to the remote SDP. Jingle 'content-modify'\r\n                        // IQ is processed in a way that it will only modify local SDP when remote peer is no longer\r\n                        // interested in receiving video content. Changing media direction in the remote SDP will mess\r\n                        // up our SDP translation chain (simulcast, video mute, RTX etc.)\r\n                        // #2 Sends the max frame height if it was set, before the session-initiate/accept\r\n                        if (this.isP2P\r\n                            && (!this._localVideoActive\r\n                                || this.localRecvMaxFrameHeight\r\n                                || this._sourceReceiverConstraints)) {\r\n                            this.sendContentModify();\r\n                        }\r\n                    }\r\n\r\n                    // Old local SDP will be available when we're setting answer for the first time, but not when offer\r\n                    // and it's fine since we're generating an answer now it will contain all our SSRCs.\r\n                    if (oldLocalSdp) {\r\n                        const newLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n                        this.notifyMySSRCUpdate(new SDP(oldLocalSdp), newLocalSdp);\r\n                    }\r\n                })\r\n                .then(() => finishedCallback(), error => finishedCallback(error));\r\n        };\r\n\r\n        logger.debug(`${this} Queued setOfferAnswerCycle task`);\r\n        this.modificationQueue.push(\r\n            workFunction,\r\n            error => {\r\n                if (error) {\r\n                    logger.error(`${this} setOfferAnswerCycle task failed: ${error}`);\r\n                    failure(error);\r\n                } else {\r\n                    logger.debug(`${this} setOfferAnswerCycle task done`);\r\n                    success();\r\n                }\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Updates the codecs on the peerconnection and initiates a renegotiation for the\r\n     * new codec config to take effect.\r\n     *\r\n     * @param {CodecMimeType} preferred the preferred codec.\r\n     * @param {CodecMimeType} disabled the codec that needs to be disabled.\r\n     */\r\n    setVideoCodecs(preferred = null, disabled = null) {\r\n        const current = this.peerconnection.getConfiguredVideoCodec();\r\n\r\n        if (this._assertNotEnded() && preferred !== current) {\r\n            logger.info(`${this} Switching video codec from ${current} to ${preferred}`);\r\n            this.peerconnection.setVideoCodecs(preferred, disabled);\r\n\r\n            // Initiate a renegotiate for the codec setting to take effect.\r\n            const workFunction = finishedCallback => {\r\n                this._renegotiate().then(\r\n                    () => {\r\n                        logger.debug(`${this} setVideoCodecs task is done`);\r\n\r\n                        return finishedCallback();\r\n                    }, error => {\r\n                        logger.error(`${this} setVideoCodecs task failed: ${error}`);\r\n\r\n                        return finishedCallback(error);\r\n                    });\r\n            };\r\n\r\n            logger.debug(`${this} Queued setVideoCodecs task`);\r\n\r\n            // Queue and execute\r\n            this.modificationQueue.push(workFunction);\r\n        }\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * Although it states \"replace transport\" it does accept full Jingle offer\r\n     * which should contain new ICE transport details.\r\n     * @param jingleOfferElem an element Jingle IQ that contains new offer and\r\n     *        transport info.\r\n     * @param success callback called when we succeed to accept new offer.\r\n     * @param failure function(error) called when we fail to accept new offer.\r\n     */\r\n    replaceTransport(jingleOfferElem, success, failure) {\r\n        if (this.options.enableForcedReload) {\r\n            const sdp = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n            this.sendTransportAccept(sdp, success, failure);\r\n            this.room.eventEmitter.emit(XMPPEvents.CONNECTION_RESTARTED, this);\r\n\r\n            return;\r\n        }\r\n        this.room.eventEmitter.emit(XMPPEvents.ICE_RESTARTING, this);\r\n\r\n        // We need to first reject the 'data' section to have the SCTP stack\r\n        // cleaned up to signal the known data channel is now invalid. After\r\n        // that the original offer is set to have the SCTP connection\r\n        // established with the new bridge.\r\n        const originalOffer = jingleOfferElem.clone();\r\n\r\n        jingleOfferElem\r\n            .find('>content[name=\\'data\\']')\r\n            .attr('senders', 'rejected');\r\n\r\n        // Remove all remote sources in order to reset the client's state\r\n        // for the remote MediaStreams. When a conference is moved to\r\n        // another bridge it will start streaming with a sequence number\r\n        // that is not in sync with the most recently seen by the client.\r\n        // The symptoms include frozen or black video and lots of \"failed to\r\n        // unprotect SRTP packets\" in Chrome logs.\r\n        jingleOfferElem\r\n            .find('>content>description>source')\r\n            .remove();\r\n        jingleOfferElem\r\n            .find('>content>description>ssrc-group')\r\n            .remove();\r\n\r\n        // On the JVB it's not a real ICE restart and all layers are re-initialized from scratch as Jicofo does\r\n        // the restart by re-allocating new channels. Chrome (or WebRTC stack) needs to have the DTLS transport layer\r\n        // reset to start a new handshake with fresh DTLS transport on the bridge. Make it think that the DTLS\r\n        // fingerprint has changed by setting an all zeros key.\r\n        const newFingerprint = jingleOfferElem.find('>content>transport>fingerprint');\r\n\r\n        newFingerprint.attr('hash', 'sha-1');\r\n        newFingerprint.text('00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00');\r\n\r\n        // First set an offer with a rejected 'data' section\r\n        this.setOfferAnswerCycle(\r\n            jingleOfferElem,\r\n            () => {\r\n                // Now set the original offer(with the 'data' section)\r\n                this.setOfferAnswerCycle(\r\n                    originalOffer,\r\n                    () => {\r\n                        const localSDP\r\n                            = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n                        this.sendTransportAccept(localSDP, success, failure);\r\n\r\n                        this.room.eventEmitter.emit(\r\n                            XMPPEvents.ICE_RESTART_SUCCESS,\r\n                            this,\r\n                            originalOffer);\r\n                    },\r\n                    failure);\r\n            },\r\n            failure\r\n        );\r\n    }\r\n\r\n    /**\r\n     * Sends Jingle 'session-accept' message.\r\n     * @param {function()} success callback called when we receive 'RESULT'\r\n     *        packet for the 'session-accept'\r\n     * @param {function(error)} failure called when we receive an error response\r\n     *        or when the request has timed out.\r\n     * @private\r\n     */\r\n    sendSessionAccept(success, failure) {\r\n        // NOTE: since we're just reading from it, we don't need to be within\r\n        //  the modification queue to access the local description\r\n        const localSDP = new SDP(this.peerconnection.localDescription.sdp);\r\n        const accept = $iq({ to: this.remoteJid,\r\n            type: 'set' })\r\n            .c('jingle', { xmlns: 'urn:xmpp:jingle:1',\r\n                action: 'session-accept',\r\n                initiator: this.initiatorJid,\r\n                responder: this.responderJid,\r\n                sid: this.sid });\r\n\r\n        if (this.webrtcIceTcpDisable) {\r\n            localSDP.removeTcpCandidates = true;\r\n        }\r\n        if (this.webrtcIceUdpDisable) {\r\n            localSDP.removeUdpCandidates = true;\r\n        }\r\n        if (this.failICE) {\r\n            localSDP.failICE = true;\r\n        }\r\n        localSDP.toJingle(\r\n            accept,\r\n            this.initiatorJid === this.localJid ? 'initiator' : 'responder');\r\n\r\n        logger.info(`${this} Sending session-accept`);\r\n        logger.debug(accept.tree());\r\n        this.connection.sendIQ(accept,\r\n            success,\r\n            this.newJingleErrorHandler(accept, error => {\r\n                failure(error);\r\n\r\n                // 'session-accept' is a critical timeout and we'll\r\n                // have to restart\r\n                this.room.eventEmitter.emit(\r\n                    XMPPEvents.SESSION_ACCEPT_TIMEOUT, this);\r\n            }),\r\n            IQ_TIMEOUT);\r\n\r\n        // XXX Videobridge needs WebRTC's answer (ICE ufrag and pwd, DTLS\r\n        // fingerprint and setup) ASAP in order to start the connection\r\n        // establishment.\r\n        //\r\n        // FIXME Flushing the connection at this point triggers an issue with\r\n        // BOSH request handling in Prosody on slow connections.\r\n        //\r\n        // The problem is that this request will be quite large and it may take\r\n        // time before it reaches Prosody. In the meantime Strophe may decide\r\n        // to send the next one. And it was observed that a small request with\r\n        // 'transport-info' usually follows this one. It does reach Prosody\r\n        // before the previous one was completely received. 'rid' on the server\r\n        // is increased and Prosody ignores the request with 'session-accept'.\r\n        // It will never reach Jicofo and everything in the request table is\r\n        // lost. Removing the flush does not guarantee it will never happen, but\r\n        // makes it much less likely('transport-info' is bundled with\r\n        // 'session-accept' and any immediate requests).\r\n        //\r\n        // this.connection.flush();\r\n    }\r\n\r\n    /**\r\n     * Will send 'content-modify' IQ in order to ask the remote peer to\r\n     * either stop or resume sending video media or to adjust sender's video constraints.\r\n     * @private\r\n     */\r\n    sendContentModify() {\r\n        const maxFrameHeight = this.localRecvMaxFrameHeight;\r\n        const senders = this._localVideoActive ? 'both' : 'none';\r\n\r\n        let sessionModify\r\n            = $iq({\r\n                to: this.remoteJid,\r\n                type: 'set'\r\n            })\r\n                .c('jingle', {\r\n                    xmlns: 'urn:xmpp:jingle:1',\r\n                    action: 'content-modify',\r\n                    initiator: this.initiatorJid,\r\n                    sid: this.sid\r\n                })\r\n                .c('content', {\r\n                    name: MediaType.VIDEO,\r\n                    senders\r\n                });\r\n\r\n        if (typeof maxFrameHeight !== 'undefined') {\r\n            sessionModify = sessionModify\r\n                .c('max-frame-height', { xmlns: 'http://jitsi.org/jitmeet/video' })\r\n                .t(maxFrameHeight);\r\n            logger.info(`${this} sending content-modify, video senders: ${senders},`\r\n                + ` max frame height: ${maxFrameHeight}`);\r\n        }\r\n\r\n        if (typeof this._sourceReceiverConstraints !== 'undefined') {\r\n            this._sourceReceiverConstraints.forEach((maxHeight, sourceName) => {\r\n                sessionModify\r\n                    .c('source-frame-height', { xmlns: 'http://jitsi.org/jitmeet/video' })\r\n                    .attrs({\r\n                        sourceName,\r\n                        maxHeight\r\n                    });\r\n\r\n                sessionModify.up();\r\n                logger.info(`${this} sending content-modify for source-name: ${sourceName}, maxHeight: ${maxHeight}`);\r\n            });\r\n        }\r\n\r\n        logger.debug(sessionModify.tree());\r\n\r\n        this.connection.sendIQ(\r\n            sessionModify,\r\n            null,\r\n            this.newJingleErrorHandler(sessionModify),\r\n            IQ_TIMEOUT);\r\n    }\r\n\r\n    /**\r\n     * Adjust the preference for max video frame height that the local party is willing to receive. Signals\r\n     * the remote party.\r\n     *\r\n     * @param {Number} maxFrameHeight - the new value to set.\r\n     * @param {Map<string, number>} sourceReceiverConstraints - The receiver constraints per source.\r\n     */\r\n    setReceiverVideoConstraint(maxFrameHeight, sourceReceiverConstraints) {\r\n        logger.info(`${this} setReceiverVideoConstraint - max frame height: ${maxFrameHeight}`\r\n            + ` sourceReceiverConstraints: ${sourceReceiverConstraints}`);\r\n\r\n        this._sourceReceiverConstraints = sourceReceiverConstraints;\r\n\r\n        if (this.isP2P) {\r\n            // Tell the remote peer about our receive constraint. If Jingle session is not yet active the state will\r\n            // be synced after offer/answer.\r\n            if (this.state === JingleSessionState.ACTIVE) {\r\n                this.sendContentModify();\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sends Jingle 'transport-accept' message which is a response to\r\n     * 'transport-replace'.\r\n     * @param localSDP the 'SDP' object with local session description\r\n     * @param success callback called when we receive 'RESULT' packet for\r\n     *        'transport-replace'\r\n     * @param failure function(error) called when we receive an error response\r\n     *        or when the request has timed out.\r\n     * @private\r\n     */\r\n    sendTransportAccept(localSDP, success, failure) {\r\n        const transportAccept = $iq({ to: this.remoteJid,\r\n            type: 'set' })\r\n            .c('jingle', {\r\n                xmlns: 'urn:xmpp:jingle:1',\r\n                action: 'transport-accept',\r\n                initiator: this.initiatorJid,\r\n                sid: this.sid\r\n            });\r\n\r\n        localSDP.media.forEach((medialines, idx) => {\r\n            const mline = SDPUtil.parseMLine(medialines.split('\\r\\n')[0]);\r\n\r\n            transportAccept.c('content',\r\n                {\r\n                    creator:\r\n                        this.initiatorJid === this.localJid\r\n                            ? 'initiator'\r\n                            : 'responder',\r\n                    name: mline.media\r\n                }\r\n            );\r\n            localSDP.transportToJingle(idx, transportAccept);\r\n            transportAccept.up();\r\n        });\r\n\r\n        logger.info(`${this} Sending transport-accept`);\r\n        logger.debug(transportAccept.tree());\r\n\r\n        this.connection.sendIQ(transportAccept,\r\n            success,\r\n            this.newJingleErrorHandler(transportAccept, failure),\r\n            IQ_TIMEOUT);\r\n    }\r\n\r\n    /**\r\n     * Sends Jingle 'transport-reject' message which is a response to\r\n     * 'transport-replace'.\r\n     * @param success callback called when we receive 'RESULT' packet for\r\n     *        'transport-replace'\r\n     * @param failure function(error) called when we receive an error response\r\n     *        or when the request has timed out.\r\n     *\r\n     * FIXME method should be marked as private, but there's some spaghetti that\r\n     *       needs to be fixed prior doing that\r\n     */\r\n    sendTransportReject(success, failure) {\r\n        // Send 'transport-reject', so that the focus will\r\n        // know that we've failed\r\n        const transportReject = $iq({ to: this.remoteJid,\r\n            type: 'set' })\r\n            .c('jingle', {\r\n                xmlns: 'urn:xmpp:jingle:1',\r\n                action: 'transport-reject',\r\n                initiator: this.initiatorJid,\r\n                sid: this.sid\r\n            });\r\n\r\n        logger.info(`${this} Sending 'transport-reject'`);\r\n        logger.debug(transportReject.tree());\r\n\r\n        this.connection.sendIQ(transportReject,\r\n            success,\r\n            this.newJingleErrorHandler(transportReject, failure),\r\n            IQ_TIMEOUT);\r\n    }\r\n\r\n    /**\r\n     * Sets the resolution constraint on the local camera track.\r\n     * @param {number} maxFrameHeight - The user preferred max frame height.\r\n     * @param {string} sourceName - The source name of the track.\r\n     * @returns {Promise} promise that will be resolved when the operation is\r\n     * successful and rejected otherwise.\r\n     */\r\n    setSenderVideoConstraint(maxFrameHeight, sourceName = null) {\r\n        if (this._assertNotEnded()) {\r\n            logger.info(`${this} setSenderVideoConstraint: ${maxFrameHeight}, sourceName: ${sourceName}`);\r\n\r\n            const jitsiLocalTrack = sourceName\r\n                ? this.rtc.getLocalVideoTracks().find(track => track.getSourceName() === sourceName)\r\n                : this.rtc.getLocalVideoTrack();\r\n\r\n            return this.peerconnection.setSenderVideoConstraints(maxFrameHeight, jitsiLocalTrack);\r\n        }\r\n\r\n        return Promise.resolve();\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    terminate(success, failure, options) {\r\n        if (this.state === JingleSessionState.ENDED) {\r\n            return;\r\n        }\r\n\r\n        if (!options || Boolean(options.sendSessionTerminate)) {\r\n            const sessionTerminate\r\n                = $iq({\r\n                    to: this.remoteJid,\r\n                    type: 'set'\r\n                })\r\n                    .c('jingle', {\r\n                        xmlns: 'urn:xmpp:jingle:1',\r\n                        action: 'session-terminate',\r\n                        initiator: this.initiatorJid,\r\n                        sid: this.sid\r\n                    })\r\n                    .c('reason')\r\n                    .c((options && options.reason) || 'success')\r\n                    .up();\r\n\r\n            if (options && options.reasonDescription) {\r\n                sessionTerminate\r\n                    .c('text')\r\n                    .t(options.reasonDescription)\r\n                    .up()\r\n                    .up();\r\n            } else {\r\n                sessionTerminate.up();\r\n            }\r\n\r\n            this._bridgeSessionId\r\n                && sessionTerminate.c(\r\n                    'bridge-session', {\r\n                        xmlns: 'http://jitsi.org/protocol/focus',\r\n                        id: this._bridgeSessionId,\r\n                        restart: options && options.requestRestart === true\r\n                    }).up();\r\n\r\n            logger.info(`${this} Sending session-terminate`);\r\n            logger.debug(sessionTerminate.tree());\r\n\r\n            this.connection.sendIQ(\r\n                sessionTerminate,\r\n                success,\r\n                this.newJingleErrorHandler(sessionTerminate, failure),\r\n                IQ_TIMEOUT);\r\n        } else {\r\n            logger.info(`${this} Skipped sending session-terminate`);\r\n        }\r\n\r\n        // this should result in 'onTerminated' being called by strope.jingle.js\r\n        this.connection.jingle.terminate(this.sid);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param reasonCondition\r\n     * @param reasonText\r\n     */\r\n    onTerminated(reasonCondition, reasonText) {\r\n        // Do something with reason and reasonCondition when we start to care\r\n        // this.reasonCondition = reasonCondition;\r\n        // this.reasonText = reasonText;\r\n        logger.info(`${this} Session terminated`, reasonCondition, reasonText);\r\n\r\n        this._xmppListeners.forEach(removeListener => removeListener());\r\n        this._xmppListeners = [];\r\n\r\n        if (this._removeSenderVideoConstraintsChangeListener) {\r\n            this._removeSenderVideoConstraintsChangeListener();\r\n        }\r\n\r\n        if (FeatureFlags.isSsrcRewritingSupported() && this.peerconnection) {\r\n            this.peerconnection.getRemoteTracks().forEach(track => {\r\n                this.room.eventEmitter.emit(JitsiTrackEvents.TRACK_REMOVED, track);\r\n            });\r\n        }\r\n\r\n        this.close();\r\n    }\r\n\r\n    /**\r\n     * Handles XMPP connection state changes.\r\n     *\r\n     * @param {XmppConnection.Status} status - The new status.\r\n     */\r\n    onXmppStatusChanged(status) {\r\n        if (status === XmppConnection.Status.CONNECTED && this._cachedOldLocalSdp) {\r\n            logger.info(`${this} Sending SSRC update on reconnect`);\r\n            this.notifyMySSRCUpdate(\r\n                this._cachedOldLocalSdp,\r\n                this._cachedNewLocalSdp);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Parse the information from the xml sourceAddElem and translate it\r\n     *  into sdp lines\r\n     * @param {jquery xml element} sourceAddElem the source-add\r\n     *  element from jingle\r\n     * @param {SDP object} currentRemoteSdp the current remote\r\n     *  sdp (as of this new source-add)\r\n     * @returns {list} a list of SDP line strings that should\r\n     *  be added to the remote SDP\r\n     */\r\n    _parseSsrcInfoFromSourceAdd(sourceAddElem, currentRemoteSdp) {\r\n        const addSsrcInfo = [];\r\n        const self = this;\r\n\r\n        $(sourceAddElem).each((i1, content) => {\r\n            const name = $(content).attr('name');\r\n            let lines = '';\r\n\r\n            $(content)\r\n                .find('ssrc-group[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\r\n                .each(function() {\r\n                    // eslint-disable-next-line no-invalid-this\r\n                    const semantics = this.getAttribute('semantics');\r\n                    const ssrcs\r\n                        = $(this) // eslint-disable-line no-invalid-this\r\n                            .find('>source')\r\n                            .map(function() {\r\n                                // eslint-disable-next-line no-invalid-this\r\n                                return this.getAttribute('ssrc');\r\n                            })\r\n                            .get();\r\n\r\n                    if (ssrcs.length) {\r\n                        lines += `a=ssrc-group:${semantics} ${ssrcs.join(' ')}\\r\\n`;\r\n                    }\r\n                });\r\n\r\n            // handles both >source and >description>source\r\n            const tmp\r\n                = $(content).find(\r\n                    'source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]');\r\n\r\n            /* eslint-disable no-invalid-this */\r\n            tmp.each(function() {\r\n                const ssrc = $(this).attr('ssrc');\r\n\r\n                if (currentRemoteSdp.containsSSRC(ssrc)) {\r\n\r\n                    // Do not print the warning for unified plan p2p case since ssrcs are never removed from the SDP.\r\n                    !(self.usesUnifiedPlan && self.isP2P)\r\n                        && logger.warn(`${self} Source-add request for existing SSRC: ${ssrc}`);\r\n\r\n                    return;\r\n                }\r\n\r\n                // eslint-disable-next-line newline-per-chained-call\r\n                $(this).find('>parameter').each(function() {\r\n                    lines += `a=ssrc:${ssrc} ${$(this).attr('name')}`;\r\n                    if ($(this).attr('value') && $(this).attr('value').length) {\r\n                        lines += `:${$(this).attr('value')}`;\r\n                    }\r\n                    lines += '\\r\\n';\r\n                });\r\n            });\r\n\r\n            let midFound = false;\r\n\r\n            /* eslint-enable no-invalid-this */\r\n            currentRemoteSdp.media.forEach((media, i2) => {\r\n                if (!SDPUtil.findLine(media, `a=mid:${name}`)) {\r\n                    return;\r\n                }\r\n                if (!addSsrcInfo[i2]) {\r\n                    addSsrcInfo[i2] = '';\r\n                }\r\n                addSsrcInfo[i2] += lines;\r\n                midFound = true;\r\n            });\r\n\r\n            // In p2p unified mode with multi-stream enabled, the new sources will have content name that doesn't exist\r\n            // in the current remote description. Add a new m-line for this newly signaled source.\r\n            if (!midFound && this.isP2P) {\r\n                addSsrcInfo[name] = lines;\r\n            }\r\n        });\r\n\r\n        return addSsrcInfo;\r\n    }\r\n\r\n    /**\r\n     * Handles a Jingle source-add message for this Jingle session.\r\n     * @param elem An array of Jingle \"content\" elements.\r\n     */\r\n    addRemoteStream(elem) {\r\n        this._addOrRemoveRemoteStream(true /* add */, elem);\r\n    }\r\n\r\n    /**\r\n     * Handles a Jingle source-remove message for this Jingle session.\r\n     * @param elem An array of Jingle \"content\" elements.\r\n     */\r\n    removeRemoteStream(elem) {\r\n        this._addOrRemoveRemoteStream(false /* remove */, elem);\r\n    }\r\n\r\n    /**\r\n     * Filter remapped SSRCs.\r\n     * Process owner change for existing SSRCs.\r\n     * Return new ones for further processing.\r\n     */\r\n    getNewSources(msg) {\r\n        const newSources = [];\r\n\r\n        for (const s of msg.mappedSources) {\r\n            if (this.peerconnection.addRemoteSsrc(s.ssrc)) {\r\n                logger.debug(`New SSRC ${s.ssrc}`);\r\n                newSources[newSources.length] = s;\r\n            } else {\r\n                const track = this.peerconnection.getTrackBySSRC(s.ssrc);\r\n\r\n                if (track) {\r\n                    logger.debug(`Existing SSRC ${s.ssrc}: new owner ${s.owner}. name=${s.source}`);\r\n\r\n                    if (s.videoType === 'CAMERA') {\r\n                        track._setVideoType('camera');\r\n                    } else if (s.videoType === 'DESKTOP') {\r\n                        track._setVideoType('desktop');\r\n                    }\r\n\r\n                    track.setNewSource(s.owner, s.source);\r\n                } else {\r\n                    logger.error(`Remapped SSRC ${s.ssrc} not found`);\r\n                }\r\n            }\r\n        }\r\n\r\n        return newSources;\r\n    }\r\n\r\n    /**\r\n     * Process SSRC remappings for video sources.\r\n     */\r\n    videoSsrcsRemapped(msg) {\r\n        const newSources = this.getNewSources(msg);\r\n\r\n        if (newSources.length > 0) {\r\n\r\n            let node = $build('content', {\r\n                xmlns: 'urn:xmpp:jingle:1',\r\n                name: 'video'\r\n            }).c('description', {\r\n                xmlns: 'urn:xmpp:jingle:apps:rtp:1',\r\n                media: MediaType.VIDEO\r\n            });\r\n\r\n            for (const s of newSources) {\r\n                const idx = ++this.numRemoteVideoSources;\r\n                const msid = `remote-video-${idx} remote-video-${idx}`;\r\n\r\n                _addSourceElement(node, s, s.ssrc, msid);\r\n                if (s.rtx !== '-1') {\r\n                    _addSourceElement(node, s, s.rtx, msid);\r\n                    node.c('ssrc-group', {\r\n                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\r\n                        semantics: 'FID'\r\n                    })\r\n                        .c('source', {\r\n                            xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\r\n                            ssrc: s.ssrc\r\n                        })\r\n                        .up()\r\n                        .c('source', {\r\n                            xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\r\n                            ssrc: s.rtx\r\n                        })\r\n                        .up()\r\n                        .up();\r\n                }\r\n            }\r\n\r\n            node = node.up();\r\n\r\n            this._addOrRemoveRemoteStream(true /* add */, node.node);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Process SSRC remappings for audio sources.\r\n     */\r\n    audioSsrcsRemapped(msg) {\r\n        const newSources = this.getNewSources(msg);\r\n\r\n        if (newSources.length > 0) {\r\n\r\n            let node = $build('content', {\r\n                xmlns: 'urn:xmpp:jingle:1',\r\n                name: 'audio'\r\n            }).c('description', {\r\n                xmlns: 'urn:xmpp:jingle:apps:rtp:1',\r\n                media: MediaType.AUDIO\r\n            });\r\n\r\n            for (const s of newSources) {\r\n                const idx = ++this.numRemoteAudioSources;\r\n                const msid = `remote-audio-${idx} remote-audio-${idx}`;\r\n\r\n                _addSourceElement(node, s, s.ssrc, msid);\r\n            }\r\n\r\n            node = node.up();\r\n\r\n            this._addOrRemoveRemoteStream(true /* add */, node.node);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Handles the deletion of SSRCs associated with a remote user from the remote description when the user leaves.\r\n     *\r\n     * @param {string} id Endpoint id of the participant that has left the call.\r\n     * @returns {void}\r\n     */\r\n    removeRemoteStreamsOnLeave(id) {\r\n        const workFunction = finishCallback => {\r\n            const removeSsrcInfo = this.peerconnection.getRemoteSourceInfoByParticipant(id);\r\n\r\n            if (removeSsrcInfo.length) {\r\n                const oldLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\r\n                const newRemoteSdp = this._processRemoteRemoveSource(removeSsrcInfo);\r\n\r\n                this._renegotiate(newRemoteSdp.raw)\r\n                    .then(() => {\r\n                        const newLocalSDP = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n                        this.notifyMySSRCUpdate(oldLocalSdp, newLocalSDP);\r\n                        finishCallback();\r\n                    })\r\n                    .catch(err => finishCallback(err));\r\n            } else {\r\n                finishCallback();\r\n            }\r\n        };\r\n\r\n        logger.debug(`${this} Queued removeRemoteStreamsOnLeave task for participant ${id}`);\r\n\r\n        this.modificationQueue.push(\r\n            workFunction,\r\n            error => {\r\n                if (error) {\r\n                    logger.error(`${this} removeRemoteStreamsOnLeave error:`, error);\r\n                } else {\r\n                    logger.info(`${this} removeRemoteStreamsOnLeave done!`);\r\n                }\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Handles either Jingle 'source-add' or 'source-remove' message for this\r\n     * Jingle session.\r\n     * @param {boolean} isAdd <tt>true</tt> for 'source-add' or <tt>false</tt>\r\n     * otherwise.\r\n     * @param {Array<Element>} elem an array of Jingle \"content\" elements.\r\n     * @private\r\n     */\r\n    _addOrRemoveRemoteStream(isAdd, elem) {\r\n        const logPrefix = isAdd ? 'addRemoteStream' : 'removeRemoteStream';\r\n\r\n        if (isAdd) {\r\n            this.readSsrcInfo(elem);\r\n        }\r\n\r\n        const workFunction = finishedCallback => {\r\n            if (!this.peerconnection.localDescription\r\n                || !this.peerconnection.localDescription.sdp) {\r\n                const errMsg = `${logPrefix} - localDescription not ready yet`;\r\n\r\n                logger.error(errMsg);\r\n                finishedCallback(errMsg);\r\n\r\n                return;\r\n            }\r\n\r\n            logger.log(`${this} Processing ${logPrefix}`);\r\n\r\n            const oldLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\r\n            const sdp = new SDP(this.peerconnection.remoteDescription.sdp);\r\n            const addOrRemoveSsrcInfo\r\n                = isAdd\r\n                    ? this._parseSsrcInfoFromSourceAdd(elem, sdp)\r\n                    : this._parseSsrcInfoFromSourceRemove(elem, sdp);\r\n            const newRemoteSdp\r\n                = isAdd\r\n                    ? this._processRemoteAddSource(addOrRemoveSsrcInfo)\r\n                    : this._processRemoteRemoveSource(addOrRemoveSsrcInfo);\r\n            const remoteDescription = new RTCSessionDescription({\r\n                type: 'offer',\r\n                sdp: newRemoteSdp.raw\r\n            });\r\n\r\n            // Always initiate a sRD->cA->sLD cycle when a remote source is added or removed irrespective of whether\r\n            // the local endpoint is an initiator or responder. Fixes bugs on Chromium where decoders are not created\r\n            // when sLD->cO->sRD cycle is initiated for p2p cases when remote sources are received.\r\n            this._responderRenegotiate(remoteDescription).then(() => {\r\n                const newLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n                logger.log(`${this} ${logPrefix} - OK`);\r\n                this.notifyMySSRCUpdate(oldLocalSdp, newLocalSdp);\r\n                finishedCallback();\r\n            }, error => {\r\n                logger.error(`${this} ${logPrefix} failed:`, error);\r\n                finishedCallback(error);\r\n            });\r\n        };\r\n\r\n        logger.debug(`${this} Queued ${logPrefix} task`);\r\n\r\n        // Queue and execute\r\n        this.modificationQueue.push(workFunction);\r\n    }\r\n\r\n    /**\r\n     * Takes in a jingle offer iq, returns the new sdp offer\r\n     * @param {jquery xml element} offerIq the incoming offer\r\n     * @returns {SDP object} the jingle offer translated to SDP\r\n     */\r\n    _processNewJingleOfferIq(offerIq) {\r\n        const remoteSdp = new SDP('');\r\n\r\n        if (this.webrtcIceTcpDisable) {\r\n            remoteSdp.removeTcpCandidates = true;\r\n        }\r\n        if (this.webrtcIceUdpDisable) {\r\n            remoteSdp.removeUdpCandidates = true;\r\n        }\r\n        if (this.failICE) {\r\n            remoteSdp.failICE = true;\r\n        }\r\n\r\n        remoteSdp.fromJingle(offerIq);\r\n        this.readSsrcInfo($(offerIq).find('>content'));\r\n\r\n        return remoteSdp;\r\n    }\r\n\r\n    /**\r\n     * Remove the given ssrc lines from the current remote sdp\r\n     * @param {list} removeSsrcInfo a list of SDP line strings that\r\n     *  should be removed from the remote SDP\r\n     * @returns type {SDP Object} the new remote SDP (after removing the lines\r\n     *  in removeSsrcInfo\r\n     */\r\n    _processRemoteRemoveSource(removeSsrcInfo) {\r\n        const remoteSdp = this.usesUnifiedPlan\r\n            ? new SDP(this.peerconnection.peerconnection.remoteDescription.sdp)\r\n            : new SDP(this.peerconnection.remoteDescription.sdp);\r\n\r\n        removeSsrcInfo.forEach((lines, idx) => {\r\n            // eslint-disable-next-line no-param-reassign\r\n            lines = lines.split('\\r\\n');\r\n            lines.pop(); // remove empty last element;\r\n            if (this.usesUnifiedPlan) {\r\n                let mid;\r\n\r\n                lines.forEach(line => {\r\n                    mid = remoteSdp.media.findIndex(mLine => mLine.includes(line));\r\n\r\n                    if (mid > -1) {\r\n                        remoteSdp.media[mid] = remoteSdp.media[mid].replace(`${line}\\r\\n`, '');\r\n                        if (this.isP2P) {\r\n                            const mediaType = SDPUtil.parseMLine(remoteSdp.media[mid].split('\\r\\n')[0])?.media;\r\n                            const desiredDirection = this.peerconnection.getDesiredMediaDirection(mediaType, false);\r\n\r\n                            [ MediaDirection.SENDRECV, MediaDirection.SENDONLY ].forEach(direction => {\r\n                                remoteSdp.media[mid] = remoteSdp.media[mid]\r\n                                    .replace(`a=${direction}`, `a=${desiredDirection}`);\r\n                            });\r\n                        } else {\r\n                            // Jvb connections will have direction set to 'sendonly' for the remote sources.\r\n                            remoteSdp.media[mid] = remoteSdp.media[mid]\r\n                                .replace(`a=${MediaDirection.SENDONLY}`, `a=${MediaDirection.INACTIVE}`);\r\n                        }\r\n                    }\r\n                });\r\n\r\n                // Reject the m-line so that the browser removes the associated transceiver from the list of available\r\n                // transceivers. This will prevent the client from trying to re-use these inactive transceivers when\r\n                // additional video sources are added to the peerconnection.\r\n                if (mid > -1 && !this.isP2P && FeatureFlags.isMultiStreamSendSupportEnabled()) {\r\n                    const { media, port } = SDPUtil.parseMLine(remoteSdp.media[mid].split('\\r\\n')[0]);\r\n\r\n                    remoteSdp.media[mid] = remoteSdp.media[mid].replace(`m=${media} ${port}`, `m=${media} 0`);\r\n                }\r\n            } else {\r\n                lines.forEach(line => {\r\n                    remoteSdp.media[idx] = remoteSdp.media[idx].replace(`${line}\\r\\n`, '');\r\n                });\r\n            }\r\n        });\r\n        remoteSdp.raw = remoteSdp.session + remoteSdp.media.join('');\r\n\r\n        return remoteSdp;\r\n    }\r\n\r\n    /**\r\n     * Add the given ssrc lines to the current remote sdp\r\n     * @param {list} addSsrcInfo a list of SDP line strings that\r\n     *  should be added to the remote SDP\r\n     * @returns type {SDP Object} the new remote SDP (after removing the lines\r\n     *  in removeSsrcInfo\r\n     */\r\n    _processRemoteAddSource(addSsrcInfo) {\r\n        let remoteSdp = new SDP(this.peerconnection.remoteDescription.sdp);\r\n\r\n        // Add a new m-line in the remote description if the source info for a secondary video source is recceived from\r\n        // the remote p2p peer when multi-stream support is enabled.\r\n        if (addSsrcInfo.length > remoteSdp.media.length\r\n            && this.isP2P\r\n            && this.usesUnifiedPlan) {\r\n            remoteSdp.addMlineForNewLocalSource(MediaType.VIDEO);\r\n            remoteSdp = new SDP(remoteSdp.raw);\r\n        }\r\n        addSsrcInfo.forEach((lines, idx) => {\r\n            remoteSdp.media[idx] += lines;\r\n\r\n            // Make sure to change the direction to 'sendrecv/sendonly' only for p2p connections. For jvb connections,\r\n            // a new m-line is added for the new remote sources.\r\n            if (this.isP2P && this.usesUnifiedPlan) {\r\n                const mediaType = SDPUtil.parseMLine(remoteSdp.media[idx].split('\\r\\n')[0])?.media;\r\n                const desiredDirection = this.peerconnection.getDesiredMediaDirection(mediaType, true);\r\n\r\n                [ MediaDirection.RECVONLY, MediaDirection.INACTIVE ].forEach(direction => {\r\n                    remoteSdp.media[idx] = remoteSdp.media[idx]\r\n                        .replace(`a=${direction}`, `a=${desiredDirection}`);\r\n                });\r\n            }\r\n        });\r\n        remoteSdp.raw = remoteSdp.session + remoteSdp.media.join('');\r\n\r\n        return remoteSdp;\r\n    }\r\n\r\n    /**\r\n     * Do a new o/a flow using the existing remote description\r\n     * @param {string} [optionalRemoteSdp] optional, raw remote sdp\r\n     *  to use.  If not provided, the remote sdp from the\r\n     *  peerconnection will be used\r\n     * @returns {Promise} promise which resolves when the\r\n     *  o/a flow is complete with no arguments or\r\n     *  rejects with an error {string}\r\n     */\r\n    _renegotiate(optionalRemoteSdp) {\r\n        if (this.peerconnection.signalingState === 'closed') {\r\n            const error = new Error('Attempted to renegotiate in state closed');\r\n\r\n            this.room.eventEmitter.emit(XMPPEvents.RENEGOTIATION_FAILED, error, this);\r\n\r\n            return Promise.reject(error);\r\n        }\r\n\r\n        const remoteSdp\r\n            = optionalRemoteSdp || this.peerconnection.remoteDescription.sdp;\r\n\r\n        if (!remoteSdp) {\r\n            const error = new Error(`Can not renegotiate without remote description, current state: ${this.state}`);\r\n\r\n            this.room.eventEmitter.emit(XMPPEvents.RENEGOTIATION_FAILED, error, this);\r\n\r\n            return Promise.reject(error);\r\n        }\r\n\r\n        const remoteDescription = new RTCSessionDescription({\r\n            type: this.isInitiator ? 'answer' : 'offer',\r\n            sdp: remoteSdp\r\n        });\r\n\r\n        if (this.isInitiator) {\r\n            return this._initiatorRenegotiate(remoteDescription);\r\n        }\r\n\r\n        return this._responderRenegotiate(remoteDescription);\r\n    }\r\n\r\n    /**\r\n     * Renegotiate cycle implementation for the responder case.\r\n     * @param {object} remoteDescription the SDP object as defined by the WebRTC\r\n     * which will be used as remote description in the cycle.\r\n     * @private\r\n     */\r\n    _responderRenegotiate(remoteDescription) {\r\n        logger.debug(`${this} Renegotiate: setting remote description`);\r\n\r\n        return this.peerconnection.setRemoteDescription(remoteDescription)\r\n            .then(() => {\r\n                logger.debug(`${this} Renegotiate: creating answer`);\r\n\r\n                return this.peerconnection.createAnswer(this.mediaConstraints)\r\n                    .then(answer => {\r\n                        logger.debug(`${this} Renegotiate: setting local description`);\r\n\r\n                        return this.peerconnection.setLocalDescription(answer);\r\n                    });\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Renegotiate cycle implementation for the initiator's case.\r\n     * @param {object} remoteDescription the SDP object as defined by the WebRTC\r\n     * which will be used as remote description in the cycle.\r\n     * @private\r\n     */\r\n    _initiatorRenegotiate(remoteDescription) {\r\n        logger.debug(`${this} Renegotiate: creating offer`);\r\n\r\n        return this.peerconnection.createOffer(this.mediaConstraints)\r\n            .then(offer => {\r\n                logger.debug(`${this} Renegotiate: setting local description`);\r\n\r\n                return this.peerconnection.setLocalDescription(offer)\r\n                    .then(() => {\r\n                        logger.debug(`${this} Renegotiate: setting remote description`);\r\n\r\n                        // eslint-disable-next-line max-len\r\n                        return this.peerconnection.setRemoteDescription(remoteDescription);\r\n                    });\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Adds a new track to the peerconnection. This method needs to be called only when a secondary JitsiLocalTrack is\r\n     * being added to the peerconnection for the first time.\r\n     *\r\n     * @param {Array<JitsiLocalTrack>} localTracks - Tracks to be added to the peer connection.\r\n     * @returns {Promise<void>} that resolves when the track is successfully added to the peerconnection, rejected\r\n     * otherwise.\r\n     */\r\n    addTracks(localTracks = null) {\r\n        if (!FeatureFlags.isMultiStreamSendSupportEnabled()\r\n            || !localTracks?.length\r\n            || localTracks.find(track => track.getType() !== MediaType.VIDEO)) {\r\n            return Promise.reject(new Error('Multiple tracks of the given media type are not supported'));\r\n        }\r\n\r\n        const replaceTracks = [];\r\n        const workFunction = finishedCallback => {\r\n            const oldLocalSDP = new SDP(this.peerconnection.localDescription.sdp);\r\n            const remoteSdp = new SDP(this.peerconnection.peerconnection.remoteDescription.sdp);\r\n            const recvOnlyTransceiver = this.peerconnection.peerconnection.getTransceivers()\r\n                    .find(t => t.receiver.track.kind === MediaType.VIDEO\r\n                        && t.direction === MediaDirection.RECVONLY\r\n                        && t.currentDirection === MediaDirection.RECVONLY);\r\n\r\n            // Add transceivers by adding a new mline in the remote description for each track. Do not create a new\r\n            // m-line if a recv-only transceiver exists in the p2p case. The new track will be attached to the\r\n            // existing one in that case.\r\n            for (const track of localTracks) {\r\n                if (!this.isP2P || !recvOnlyTransceiver) {\r\n                    remoteSdp.addMlineForNewLocalSource(track.getType());\r\n                }\r\n            }\r\n\r\n            const remoteDescription = new RTCSessionDescription({\r\n                type: 'offer',\r\n                sdp: remoteSdp.raw\r\n            });\r\n\r\n            // Always initiate a responder renegotiate since the new m-line is added to remote SDP.\r\n            this._responderRenegotiate(remoteDescription)\r\n                .then(() => {\r\n                    // Replace the tracks on the newly generated transceivers.\r\n                    for (const track of localTracks) {\r\n                        replaceTracks.push(this.peerconnection.replaceTrack(null, track));\r\n                    }\r\n\r\n                    return Promise.all(replaceTracks);\r\n                })\r\n\r\n                // Trigger a renegotiation here since renegotiations are suppressed at TPC.replaceTrack for screenshare\r\n                // tracks. This is done here so that presence for screenshare tracks is sent before signaling.\r\n                .then(() => this._renegotiate())\r\n                .then(() => {\r\n                    const newLocalSDP = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n                    // Signal the new sources to the peer.\r\n                    this.notifyMySSRCUpdate(oldLocalSDP, newLocalSDP);\r\n                    finishedCallback();\r\n                })\r\n                .catch(error => finishedCallback(error));\r\n        };\r\n\r\n        return new Promise((resolve, reject) => {\r\n            logger.debug(`${this} Queued renegotiation after addTrack`);\r\n\r\n            this.modificationQueue.push(\r\n                workFunction,\r\n                error => {\r\n                    if (error) {\r\n                        logger.error(`${this} renegotiation after addTrack error`, error);\r\n                        reject(error);\r\n                    } else {\r\n                        logger.debug(`${this} renegotiation after addTrack executed - OK`);\r\n                        resolve();\r\n                    }\r\n                });\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Replaces <tt>oldTrack</tt> with <tt>newTrack</tt> and performs a single\r\n     * offer/answer cycle after both operations are done. Either\r\n     * <tt>oldTrack</tt> or <tt>newTrack</tt> can be null; replacing a valid\r\n     * <tt>oldTrack</tt> with a null <tt>newTrack</tt> effectively just removes\r\n     * <tt>oldTrack</tt>\r\n     * @param {JitsiLocalTrack|null} oldTrack the current track in use to be\r\n     * replaced\r\n     * @param {JitsiLocalTrack|null} newTrack the new track to use\r\n     * @returns {Promise} which resolves once the replacement is complete\r\n     *  with no arguments or rejects with an error {string}\r\n     */\r\n    replaceTrack(oldTrack, newTrack) {\r\n        const workFunction = finishedCallback => {\r\n            logger.debug(`${this} replaceTrack worker started. oldTrack = ${oldTrack}, newTrack = ${newTrack}`);\r\n\r\n            const oldLocalSdp = this.peerconnection.localDescription.sdp;\r\n\r\n            if (!this.usesUnifiedPlan) {\r\n                // NOTE the code below assumes that no more than 1 video track\r\n                // can be added to the peer connection.\r\n                // Transition from camera to desktop share\r\n                // or transition from one camera source to another.\r\n                if (this.peerconnection.options.capScreenshareBitrate\r\n                    && oldTrack && newTrack && newTrack.isVideoTrack()) {\r\n                    // Clearing current primary SSRC will make\r\n                    // the SdpConsistency generate a new one which will result\r\n                    // with:\r\n                    // 1. source-remove for the old video stream.\r\n                    // 2. source-add for the new video stream.\r\n                    this.peerconnection.clearRecvonlySsrc();\r\n                }\r\n\r\n                // Transition from no video to video (unmute).\r\n                if (!oldTrack && newTrack && newTrack.isVideoTrack()) {\r\n                    // Clearing current primary SSRC will make\r\n                    // the SdpConsistency generate a new one which will result\r\n                    // with:\r\n                    // 1. source-remove for the recvonly\r\n                    // 2. source-add for the new video stream\r\n                    this.peerconnection.clearRecvonlySsrc();\r\n\r\n                // Transition from video to no video\r\n                } else if (oldTrack && oldTrack.isVideoTrack() && !newTrack) {\r\n                    // Clearing current primary SSRC and generating the recvonly\r\n                    // will result in:\r\n                    // 1. source-remove for the old video stream\r\n                    // 2. source-add for the recvonly stream\r\n                    this.peerconnection.clearRecvonlySsrc();\r\n                    this.peerconnection.generateRecvonlySsrc();\r\n                }\r\n            }\r\n\r\n            this.peerconnection.replaceTrack(oldTrack, newTrack)\r\n                .then(shouldRenegotiate => {\r\n                    let promise = Promise.resolve();\r\n\r\n                    logger.debug(`${this} TPC.replaceTrack finished. shouldRenegotiate = ${\r\n                        shouldRenegotiate}, JingleSessionState = ${this.state}`);\r\n\r\n                    if (shouldRenegotiate\r\n                        && (oldTrack || newTrack)\r\n                        && this.state === JingleSessionState.ACTIVE) {\r\n                        promise = this._renegotiate().then(() => {\r\n                            const newLocalSDP = new SDP(this.peerconnection.localDescription.sdp);\r\n\r\n                            this.notifyMySSRCUpdate(new SDP(oldLocalSdp), newLocalSDP);\r\n                        });\r\n                    }\r\n\r\n                    return promise.then(() => {\r\n                        // Set the source name of the new track.\r\n                        if (oldTrack\r\n                            && newTrack\r\n                            && oldTrack.isVideoTrack()) {\r\n                            newTrack.setSourceName(oldTrack.getSourceName());\r\n                        }\r\n\r\n                        if (newTrack?.isVideoTrack()) {\r\n                            logger.debug(`${this} replaceTrack worker: configuring video stream`);\r\n\r\n                            // Configure the video encodings after the track is replaced.\r\n                            return this.peerconnection.configureSenderVideoEncodings(newTrack);\r\n                        }\r\n                    });\r\n                })\r\n                .then(() => finishedCallback(), error => finishedCallback(error));\r\n        };\r\n\r\n        return new Promise((resolve, reject) => {\r\n            logger.debug(`${this} Queued replaceTrack task. Old track = ${oldTrack}, new track = ${newTrack}`);\r\n\r\n            this.modificationQueue.push(\r\n                workFunction,\r\n                error => {\r\n                    if (error) {\r\n                        logger.error(`${this} Replace track error:`, error);\r\n                        reject(error);\r\n                    } else {\r\n                        logger.info(`${this}  Replace track done!`);\r\n                        resolve();\r\n                    }\r\n                });\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Parse the information from the xml sourceRemoveElem and translate it\r\n     *  into sdp lines\r\n     * @param {jquery xml element} sourceRemoveElem the source-remove\r\n     *  element from jingle\r\n     * @param {SDP object} currentRemoteSdp the current remote\r\n     *  sdp (as of this new source-remove)\r\n     * @returns {list} a list of SDP line strings that should\r\n     *  be removed from the remote SDP\r\n     */\r\n    _parseSsrcInfoFromSourceRemove(sourceRemoveElem, currentRemoteSdp) {\r\n        const removeSsrcInfo = [];\r\n\r\n        $(sourceRemoveElem).each((i1, content) => {\r\n            const name = $(content).attr('name');\r\n            let lines = '';\r\n\r\n            $(content)\r\n                .find('ssrc-group[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\r\n                .each(function() {\r\n                    /* eslint-disable no-invalid-this */\r\n                    const semantics = this.getAttribute('semantics');\r\n                    const ssrcs\r\n                        = $(this)\r\n                            .find('>source')\r\n                            .map(function() {\r\n                                return this.getAttribute('ssrc');\r\n                            })\r\n                            .get();\r\n\r\n                    if (ssrcs.length) {\r\n                        lines\r\n                            += `a=ssrc-group:${semantics} ${\r\n                                ssrcs.join(' ')}\\r\\n`;\r\n                    }\r\n\r\n                    /* eslint-enable no-invalid-this */\r\n                });\r\n            const ssrcs = [];\r\n\r\n            // handles both >source and >description>source versions\r\n            const tmp\r\n                = $(content).find(\r\n                    'source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]');\r\n\r\n            tmp.each(function() {\r\n                // eslint-disable-next-line no-invalid-this\r\n                const ssrc = $(this).attr('ssrc');\r\n\r\n                ssrcs.push(ssrc);\r\n            });\r\n            currentRemoteSdp.media.forEach((media, i2) => {\r\n                if (!SDPUtil.findLine(media, `a=mid:${name}`)) {\r\n                    return;\r\n                }\r\n                if (!removeSsrcInfo[i2]) {\r\n                    removeSsrcInfo[i2] = '';\r\n                }\r\n                ssrcs.forEach(ssrc => {\r\n                    const ssrcLines\r\n                        = SDPUtil.findLines(media, `a=ssrc:${ssrc}`);\r\n\r\n                    if (ssrcLines.length) {\r\n                        removeSsrcInfo[i2] += `${ssrcLines.join('\\r\\n')}\\r\\n`;\r\n                    }\r\n                });\r\n                removeSsrcInfo[i2] += lines;\r\n            });\r\n        });\r\n\r\n        return removeSsrcInfo;\r\n    }\r\n\r\n    /**\r\n     * Will print an error if there is any difference, between the SSRCs given\r\n     * in the <tt>oldSDP</tt> and the ones currently described in\r\n     * the peerconnection's local description.\r\n     * @param {string} operationName the operation's name which will be printed\r\n     * in the error message.\r\n     * @param {SDP} oldSDP the old local SDP which will be compared with\r\n     * the current one.\r\n     * @return {boolean} <tt>true</tt> if there was any change or <tt>false</tt>\r\n     * otherwise.\r\n     * @private\r\n     */\r\n    _verifyNoSSRCChanged(operationName, oldSDP) {\r\n        const currentLocalSDP\r\n            = new SDP(this.peerconnection.localDescription.sdp);\r\n        let sdpDiff = new SDPDiffer(oldSDP, currentLocalSDP);\r\n        const addedMedia = sdpDiff.getNewMedia();\r\n\r\n        if (Object.keys(addedMedia).length) {\r\n            logger.error(`${this} - some SSRC were added on ${operationName}`, addedMedia);\r\n\r\n            return false;\r\n        }\r\n\r\n        sdpDiff = new SDPDiffer(currentLocalSDP, oldSDP);\r\n        const removedMedia = sdpDiff.getNewMedia();\r\n\r\n        if (Object.keys(removedMedia).length) {\r\n            logger.error(`${this} - some SSRCs were removed on ${operationName}`, removedMedia);\r\n\r\n            return false;\r\n        }\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * Adds local track back to the peerconnection associated with this session.\r\n     * @param {JitsiLocalTrack} track\r\n     * @return {Promise} a promise that will resolve once the local track is added back to this session and\r\n     * renegotiation succeeds (if its warranted). Will be rejected with a <tt>string</tt> that provides some error\r\n     * details in case something goes wrong.\r\n     */\r\n    addTrackToPc(track) {\r\n        return this._addRemoveTrack(false /* add */, track)\r\n            .then(() => {\r\n                // Configure the video encodings after the track is unmuted. If the user joins the call muted and\r\n                // unmutes it the first time, all the parameters need to be configured.\r\n                if (track.isVideoTrack()) {\r\n                    return this.peerconnection.configureSenderVideoEncodings(track);\r\n                }\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Remove local track as part of the mute operation.\r\n     * @param {JitsiLocalTrack} track the local track to be removed\r\n     * @return {Promise} a promise which will be resolved once the local track\r\n     * is removed from this session and the renegotiation is performed.\r\n     * The promise will be rejected with a <tt>string</tt> that the describes\r\n     * the error if anything goes wrong.\r\n     */\r\n    removeTrackFromPc(track) {\r\n        return this._addRemoveTrack(true /* remove */, track);\r\n    }\r\n\r\n    /**\r\n     * See {@link addTrackToPc} and {@link removeTrackFromPc}.\r\n     * @param {boolean} isRemove <tt>true</tt> for \"remove\" operation or <tt>false</tt> for \"add\" operation.\r\n     * @param {JitsiLocalTrack} track the track that will be added/removed\r\n     * @private\r\n     */\r\n    _addRemoveTrack(isRemove, track) {\r\n        if (!track) {\r\n            return Promise.reject('invalid \"track\" argument value');\r\n        }\r\n        const operationName = isRemove ? 'removeTrack' : 'addTrack';\r\n        const workFunction = finishedCallback => {\r\n            const tpc = this.peerconnection;\r\n\r\n            if (!tpc) {\r\n                finishedCallback(`Error:  tried ${operationName} track with no active peer connection`);\r\n\r\n                return;\r\n            }\r\n            const oldLocalSDP = tpc.localDescription.sdp;\r\n            const operationPromise\r\n                = isRemove\r\n                    ? tpc.removeTrackFromPc(track)\r\n                    : tpc.addTrackToPc(track);\r\n\r\n            operationPromise\r\n                .then(shouldRenegotiate => {\r\n                    if (shouldRenegotiate && oldLocalSDP && tpc.remoteDescription.sdp) {\r\n                        this._renegotiate()\r\n                            .then(() => {\r\n                                // The results are ignored, as this check failure is not enough to fail the whole\r\n                                // operation. It will log an error inside for plan-b.\r\n                                !this.usesUnifiedPlan && this._verifyNoSSRCChanged(operationName, new SDP(oldLocalSDP));\r\n                                const newLocalSdp = tpc.localDescription.sdp;\r\n\r\n                                // Signal the ssrc if an unmute operation results in a new ssrc being generated.\r\n                                this.notifyMySSRCUpdate(new SDP(oldLocalSDP), new SDP(newLocalSdp));\r\n                                finishedCallback();\r\n                            });\r\n                    } else {\r\n                        finishedCallback();\r\n                    }\r\n                },\r\n                finishedCallback /* will be called with an error */);\r\n        };\r\n\r\n        logger.debug(`${this} Queued ${operationName} task`);\r\n\r\n        return new Promise((resolve, reject) => {\r\n            this.modificationQueue.push(\r\n                workFunction,\r\n                error => {\r\n                    if (error) {\r\n                        logger.error(`${this} ${operationName} failed`);\r\n                        reject(error);\r\n                    } else {\r\n                        logger.debug(`${this} ${operationName} done`);\r\n                        resolve();\r\n                    }\r\n                });\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Resumes or suspends media transfer over the underlying peer connection.\r\n     * @param {boolean} audioActive <tt>true</tt> to enable audio media\r\n     * transfer or <tt>false</tt> to suspend audio media transmission.\r\n     * @param {boolean} videoActive <tt>true</tt> to enable video media\r\n     * transfer or <tt>false</tt> to suspend video media transmission.\r\n     * @return {Promise} a <tt>Promise</tt> which will resolve once\r\n     * the operation is done. It will be rejected with an error description as\r\n     * a string in case anything goes wrong.\r\n     */\r\n    setMediaTransferActive(audioActive, videoActive) {\r\n        if (!this.peerconnection) {\r\n            return Promise.reject(\r\n                'Can not modify transfer active state,'\r\n                    + ' before \"initialize\" is called');\r\n        }\r\n\r\n        const logAudioStr = audioActive ? 'audio active' : 'audio inactive';\r\n        const logVideoStr = videoActive ? 'video active' : 'video inactive';\r\n\r\n        logger.info(`${this} Queued make ${logVideoStr}, ${logAudioStr} task`);\r\n\r\n        const workFunction = finishedCallback => {\r\n            const isSessionActive = this.state === JingleSessionState.ACTIVE;\r\n\r\n            // Because the value is modified on the queue it's impossible to\r\n            // check it's final value reliably prior to submitting the task.\r\n            // The rule here is that the last submitted state counts.\r\n            // Check the values here to avoid unnecessary renegotiation cycle.\r\n            const audioActiveChanged\r\n                = this.peerconnection.setAudioTransferActive(audioActive);\r\n\r\n            if (this._localVideoActive !== videoActive) {\r\n                this._localVideoActive = videoActive;\r\n\r\n                // Do only for P2P - Jicofo will reply with 'bad-request'\r\n                // We don't want to send 'content-modify', before the initial\r\n                // O/A (state === JingleSessionState.ACTIVE), because that will\r\n                // mess up video media direction in the remote SDP.\r\n                // 'content-modify' when processed only affects the media\r\n                // direction in the local SDP. We're doing that, because setting\r\n                // 'inactive' on video media in remote SDP will mess up our SDP\r\n                // translation chain (simulcast, RTX, video mute etc.).\r\n                if (this.isP2P && isSessionActive) {\r\n                    this.sendContentModify();\r\n                }\r\n            }\r\n\r\n            const pcVideoActiveChanged\r\n                = this.peerconnection.setVideoTransferActive(\r\n                    this._localVideoActive && this._remoteVideoActive);\r\n\r\n            // Will do the sRD/sLD cycle to update SDPs and adjust the media\r\n            // direction\r\n            if (isSessionActive\r\n                    && (audioActiveChanged || pcVideoActiveChanged)) {\r\n                this._renegotiate()\r\n                    .then(\r\n                        finishedCallback,\r\n                        finishedCallback /* will be called with an error */);\r\n            } else {\r\n                finishedCallback();\r\n            }\r\n        };\r\n\r\n        return new Promise((resolve, reject) => {\r\n            this.modificationQueue.push(\r\n                workFunction,\r\n                error => {\r\n                    if (error) {\r\n                        logger.error(`${this} Make ${logVideoStr}, ${logAudioStr} task failed!`);\r\n                        reject(error);\r\n                    } else {\r\n                        logger.debug(`${this} Make ${logVideoStr}, ${logAudioStr} task done!`);\r\n                        resolve();\r\n                    }\r\n                });\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Will put and execute on the queue a session modify task. It checks if the sourceMaxFrameHeight (as requested by\r\n     * the p2p peer) or the senders attribute of the video content has changed and modifies the local video sources\r\n     * accordingly.\r\n     */\r\n    modifyContents(jingleContents) {\r\n        const newVideoSenders = JingleSessionPC.parseVideoSenders(jingleContents);\r\n        const newMaxFrameHeight = JingleSessionPC.parseMaxFrameHeight(jingleContents);\r\n        const sourceMaxFrameHeights = JingleSessionPC.parseSourceMaxFrameHeight(jingleContents);\r\n\r\n        // frame height is optional in our content-modify protocol\r\n        if (newMaxFrameHeight) {\r\n            logger.info(`${this} received remote max frame height: ${newMaxFrameHeight}`);\r\n            this.remoteRecvMaxFrameHeight = newMaxFrameHeight;\r\n            this.eventEmitter.emit(MediaSessionEvents.REMOTE_VIDEO_CONSTRAINTS_CHANGED, this);\r\n        }\r\n\r\n        if (sourceMaxFrameHeights) {\r\n            this.remoteSourceMaxFrameHeights = sourceMaxFrameHeights;\r\n            this.eventEmitter.emit(MediaSessionEvents.REMOTE_SOURCE_CONSTRAINTS_CHANGED, this, sourceMaxFrameHeights);\r\n        }\r\n\r\n        if (newVideoSenders === null) {\r\n            logger.error(`${this} - failed to parse video \"senders\" attribute in \"content-modify\" action`);\r\n\r\n            return;\r\n        }\r\n\r\n        const workFunction = finishedCallback => {\r\n            if (this._assertNotEnded() && this._modifyRemoteVideoActive(newVideoSenders)) {\r\n                // Will do the sRD/sLD cycle to update SDPs and adjust the media direction.\r\n                this._renegotiate()\r\n                    .then(finishedCallback, finishedCallback /* (error) */);\r\n            } else {\r\n                finishedCallback();\r\n            }\r\n        };\r\n\r\n        logger.debug(`${this} queued \"content-modify\" task(video senders=\"${newVideoSenders}\")`);\r\n\r\n        this.modificationQueue.push(\r\n            workFunction,\r\n            error => {\r\n                if (error) {\r\n                    logger.error(`${this} \"content-modify\" failed`, error);\r\n                } else {\r\n                    logger.debug(`${this} \"content-modify\" task(video senders=\"${newVideoSenders}\") done`);\r\n                }\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Processes new value of remote video \"senders\" Jingle attribute and tries\r\n     * to apply it for {@link _remoteVideoActive}.\r\n     * @param {string} remoteVideoSenders the value of \"senders\" attribute of\r\n     * Jingle video content element advertised by remote peer.\r\n     * @return {boolean} <tt>true</tt> if the change affected state of\r\n     * the underlying peerconnection and renegotiation is required for\r\n     * the changes to take effect.\r\n     * @private\r\n     */\r\n    _modifyRemoteVideoActive(remoteVideoSenders) {\r\n        const isRemoteVideoActive\r\n            = remoteVideoSenders === 'both'\r\n                || (remoteVideoSenders === 'initiator' && this.isInitiator)\r\n                || (remoteVideoSenders === 'responder' && !this.isInitiator);\r\n\r\n        if (isRemoteVideoActive !== this._remoteVideoActive) {\r\n            logger.debug(`${this} new remote video active: ${isRemoteVideoActive}`);\r\n            this._remoteVideoActive = isRemoteVideoActive;\r\n        }\r\n\r\n        return this.peerconnection.setVideoTransferActive(this._localVideoActive && this._remoteVideoActive);\r\n    }\r\n\r\n    /**\r\n     * Figures out added/removed ssrcs and send update IQs.\r\n     * @param oldSDP SDP object for old description.\r\n     * @param newSDP SDP object for new description.\r\n     */\r\n    notifyMySSRCUpdate(oldSDP, newSDP) {\r\n        if (this.state !== JingleSessionState.ACTIVE) {\r\n            logger.warn(`${this} Skipping SSRC update in '${this.state} ' state.`);\r\n\r\n            return;\r\n        }\r\n\r\n        if (!this.connection.connected) {\r\n            // The goal is to compare the oldest SDP with the latest one upon reconnect\r\n            if (!this._cachedOldLocalSdp) {\r\n                this._cachedOldLocalSdp = oldSDP;\r\n            }\r\n            this._cachedNewLocalSdp = newSDP;\r\n            logger.warn(`${this} Not sending SSRC update while the signaling is disconnected`);\r\n\r\n            return;\r\n        }\r\n\r\n        this._cachedOldLocalSdp = undefined;\r\n        this._cachedNewLocalSdp = undefined;\r\n\r\n        const getSignaledSourceInfo = sdpDiffer => {\r\n            const newMedia = sdpDiffer.getNewMedia();\r\n            let ssrcs = [];\r\n            let mediaType = null;\r\n\r\n            // It is assumed that sources are signaled one at a time.\r\n            Object.keys(newMedia).forEach(mediaIndex => {\r\n                const signaledSsrcs = Object.keys(newMedia[mediaIndex].ssrcs);\r\n\r\n                mediaType = newMedia[mediaIndex].mid;\r\n                if (signaledSsrcs?.length) {\r\n                    ssrcs = ssrcs.concat(signaledSsrcs);\r\n                }\r\n            });\r\n\r\n            return {\r\n                mediaType,\r\n                ssrcs\r\n            };\r\n        };\r\n\r\n        // send source-remove IQ.\r\n        let sdpDiffer = new SDPDiffer(newSDP, oldSDP);\r\n        const remove = $iq({ to: this.remoteJid,\r\n            type: 'set' })\r\n            .c('jingle', {\r\n                xmlns: 'urn:xmpp:jingle:1',\r\n                action: 'source-remove',\r\n                initiator: this.initiatorJid,\r\n                sid: this.sid\r\n            }\r\n            );\r\n\r\n        sdpDiffer.toJingle(remove);\r\n\r\n        // context a common object for one run of ssrc update (source-add and source-remove) so we can match them if we\r\n        // need to\r\n        const ctx = {};\r\n        const removedSsrcInfo = getSignaledSourceInfo(sdpDiffer);\r\n\r\n        if (removedSsrcInfo.ssrcs.length) {\r\n            // Log only the SSRCs instead of the full IQ.\r\n            logger.info(`${this} Sending source-remove for ${removedSsrcInfo.mediaType}`\r\n                + ` ssrcs=${removedSsrcInfo.ssrcs}`);\r\n            this.connection.sendIQ(\r\n                remove,\r\n                () => {\r\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_REMOVE, this, ctx);\r\n                },\r\n                this.newJingleErrorHandler(remove, error => {\r\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_REMOVE_ERROR, this, error, ctx);\r\n                }),\r\n                IQ_TIMEOUT);\r\n        }\r\n\r\n        // send source-add IQ.\r\n        sdpDiffer = new SDPDiffer(oldSDP, newSDP);\r\n        const add = $iq({ to: this.remoteJid,\r\n            type: 'set' })\r\n            .c('jingle', {\r\n                xmlns: 'urn:xmpp:jingle:1',\r\n                action: 'source-add',\r\n                initiator: this.initiatorJid,\r\n                sid: this.sid\r\n            }\r\n            );\r\n\r\n        sdpDiffer.toJingle(add);\r\n        const addedSsrcInfo = getSignaledSourceInfo(sdpDiffer);\r\n\r\n        if (addedSsrcInfo.ssrcs.length) {\r\n            // Log only the SSRCs instead of the full IQ.\r\n            logger.info(`${this} Sending source-add for ${addedSsrcInfo.mediaType} ssrcs=${addedSsrcInfo.ssrcs}`);\r\n            this.connection.sendIQ(\r\n                add,\r\n                () => {\r\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_ADD, this, ctx);\r\n                },\r\n                this.newJingleErrorHandler(add, error => {\r\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_ADD_ERROR, this, error, addedSsrcInfo.mediaType, ctx);\r\n                }),\r\n                IQ_TIMEOUT);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Method returns function(errorResponse) which is a callback to be passed\r\n     * to Strophe connection.sendIQ method. An 'error' structure is created that\r\n     * is passed as 1st argument to given <tt>failureCb</tt>. The format of this\r\n     * structure is as follows:\r\n     * {\r\n     *  code: {XMPP error response code}\r\n     *  reason: {the name of XMPP error reason element or 'timeout' if the\r\n      *          request has timed out within <tt>IQ_TIMEOUT</tt> milliseconds}\r\n     *  source: {request.tree() that provides original request}\r\n     *  session: {this JingleSessionPC.toString()}\r\n     * }\r\n     * @param request Strophe IQ instance which is the request to be dumped into\r\n     *        the error structure\r\n     * @param failureCb function(error) called when error response was returned\r\n     *        or when a timeout has occurred.\r\n     * @returns {function(this:JingleSessionPC)}\r\n     */\r\n    newJingleErrorHandler(request, failureCb) {\r\n        return errResponse => {\r\n\r\n            const error = {};\r\n\r\n            // Get XMPP error code and condition(reason)\r\n            const errorElSel = $(errResponse).find('error');\r\n\r\n            if (errorElSel.length) {\r\n                error.code = errorElSel.attr('code');\r\n                const errorReasonSel = $(errResponse).find('error :first');\r\n\r\n                if (errorReasonSel.length) {\r\n                    error.reason = errorReasonSel[0].tagName;\r\n                }\r\n\r\n                const errorMsgSel = errorElSel.find('>text');\r\n\r\n                if (errorMsgSel.length) {\r\n                    error.msg = errorMsgSel.text();\r\n                }\r\n            }\r\n\r\n            if (!errResponse) {\r\n                error.reason = 'timeout';\r\n            }\r\n\r\n            error.session = this.toString();\r\n\r\n            if (failureCb) {\r\n                failureCb(error);\r\n            } else if (this.state === JingleSessionState.ENDED\r\n                        && error.reason === 'item-not-found') {\r\n                // When remote peer decides to terminate the session, but it\r\n                // still have few messages on the queue for processing,\r\n                // it will first send us 'session-terminate' (we enter ENDED)\r\n                // and then follow with 'item-not-found' for the queued requests\r\n                // We don't want to have that logged on error level.\r\n                logger.debug(`${this} Jingle error: ${JSON.stringify(error)}`);\r\n            } else {\r\n                GlobalOnErrorHandler.callErrorHandler(\r\n                    new Error(\r\n                        `Jingle error: ${JSON.stringify(error)}`));\r\n            }\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Returns the ice connection state for the peer connection.\r\n     * @returns the ice connection state for the peer connection.\r\n     */\r\n    getIceConnectionState() {\r\n        return this.peerconnection.getConnectionState();\r\n    }\r\n\r\n    /**\r\n     * Closes the peerconnection.\r\n     */\r\n    close() {\r\n        this.state = JingleSessionState.ENDED;\r\n        this.establishmentDuration = undefined;\r\n\r\n        if (this.peerconnection) {\r\n            this.peerconnection.onicecandidate = null;\r\n            this.peerconnection.oniceconnectionstatechange = null;\r\n            this.peerconnection.onnegotiationneeded = null;\r\n            this.peerconnection.onsignalingstatechange = null;\r\n        }\r\n\r\n        logger.debug(`${this} Clearing modificationQueue`);\r\n\r\n        // Remove any pending tasks from the queue\r\n        this.modificationQueue.clear();\r\n\r\n        logger.debug(`${this} Queued PC close task`);\r\n        this.modificationQueue.push(finishCallback => {\r\n            // do not try to close if already closed.\r\n            this.peerconnection && this.peerconnection.close();\r\n            finishCallback();\r\n            logger.debug(`${this} PC close task done!`);\r\n        });\r\n\r\n        logger.debug(`${this} Shutdown modificationQueue!`);\r\n\r\n        // No more tasks can go in after the close task\r\n        this.modificationQueue.shutdown();\r\n    }\r\n\r\n    /**\r\n     * Converts to string with minor summary.\r\n     * @return {string}\r\n     */\r\n    toString() {\r\n        return `JingleSessionPC[session=${this.isP2P ? 'P2P' : 'JVB'},initiator=${this.isInitiator},sid=${this.sid}]`;\r\n    }\r\n\r\n    /**\r\n     * If the A/B test for suspend video is disabled according to the room's\r\n     * configuration, returns undefined. Otherwise returns a boolean which\r\n     * indicates whether the suspend video option should be enabled or disabled.\r\n     * @param {JingleSessionPCOptions} options - The config options.\r\n     */\r\n    _abtestSuspendVideoEnabled({ abTesting }) {\r\n        if (!abTesting || !abTesting.enableSuspendVideoTest) {\r\n            return;\r\n        }\r\n\r\n        // We want the two participants in a P2P call to agree on the value of\r\n        // the \"suspend\" option. We use the JID of the initiator, because it is\r\n        // both randomly selected and agreed upon by both participants.\r\n        const jid = this._getInitiatorJid();\r\n\r\n        return integerHash(jid) % 2 === 0;\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport $ from 'jquery';\r\nimport { $iq, Strophe } from 'strophe.js';\r\n\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport {\r\n    ACTION_JINGLE_TR_RECEIVED,\r\n    ACTION_JINGLE_TR_SUCCESS,\r\n    createJingleEvent\r\n} from '../../service/statistics/AnalyticsEvents';\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\nimport Statistics from '../statistics/statistics';\r\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\r\nimport RandomUtil from '../util/RandomUtil';\r\n\r\nimport ConnectionPlugin from './ConnectionPlugin';\r\nimport { expandSourcesFromJson } from './JingleHelperFunctions';\r\nimport JingleSessionPC from './JingleSessionPC';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n// XXX Strophe is build around the idea of chaining function calls so allow long\r\n// function call chains.\r\n/* eslint-disable newline-per-chained-call */\r\n\r\n/**\r\n * Parses the transport XML element and returns the list of ICE candidates formatted as text.\r\n *\r\n * @param {*} transport Transport XML element extracted from the IQ.\r\n * @returns {Array<string>}\r\n */\r\nfunction _parseIceCandidates(transport) {\r\n    const candidates = $(transport).find('>candidate');\r\n    const parseCandidates = [];\r\n\r\n    // Extract the candidate information from the IQ.\r\n    candidates.each((_, candidate) => {\r\n        const attributes = candidate.attributes;\r\n        const candidateAttrs = [];\r\n\r\n        for (let i = 0; i < attributes.length; i++) {\r\n            const attr = attributes[i];\r\n\r\n            candidateAttrs.push(`${attr.name}: ${attr.value}`);\r\n        }\r\n        parseCandidates.push(candidateAttrs.join(' '));\r\n    });\r\n\r\n    return parseCandidates;\r\n}\r\n\r\n/**\r\n *\r\n */\r\nexport default class JingleConnectionPlugin extends ConnectionPlugin {\r\n    /**\r\n     * Creates new <tt>JingleConnectionPlugin</tt>\r\n     * @param {XMPP} xmpp\r\n     * @param {EventEmitter} eventEmitter\r\n     * @param {Object} iceConfig an object that holds the iceConfig to be passed\r\n     * to the p2p and the jvb <tt>PeerConnection</tt>.\r\n     */\r\n    constructor(xmpp, eventEmitter, iceConfig) {\r\n        super();\r\n        this.xmpp = xmpp;\r\n        this.eventEmitter = eventEmitter;\r\n        this.sessions = {};\r\n        this.jvbIceConfig = iceConfig.jvb;\r\n        this.p2pIceConfig = iceConfig.p2p;\r\n        this.mediaConstraints = {\r\n            offerToReceiveAudio: true,\r\n            offerToReceiveVideo: true\r\n        };\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param connection\r\n     */\r\n    init(connection) {\r\n        super.init(connection);\r\n        this.connection.addHandler(this.onJingle.bind(this),\r\n            'urn:xmpp:jingle:1', 'iq', 'set', null, null);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param iq\r\n     */\r\n    onJingle(iq) {\r\n        const sid = $(iq).find('jingle').attr('sid');\r\n        const action = $(iq).find('jingle').attr('action');\r\n        const fromJid = iq.getAttribute('from');\r\n\r\n        // send ack first\r\n        const ack = $iq({ type: 'result',\r\n            to: fromJid,\r\n            id: iq.getAttribute('id')\r\n        });\r\n\r\n        let sess = this.sessions[sid];\r\n\r\n        if (action !== 'session-initiate') {\r\n            if (!sess) {\r\n                ack.attrs({ type: 'error' });\r\n                ack.c('error', { type: 'cancel' })\r\n                    .c('item-not-found', {\r\n                        xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'\r\n                    })\r\n                    .up()\r\n                    .c('unknown-session', {\r\n                        xmlns: 'urn:xmpp:jingle:errors:1'\r\n                    });\r\n                logger.warn(`invalid session id: ${sid}`);\r\n                logger.debug(iq);\r\n                this.connection.send(ack);\r\n\r\n                return true;\r\n            }\r\n\r\n            // local jid is not checked\r\n            if (fromJid !== sess.remoteJid) {\r\n                logger.warn(\r\n                    'jid mismatch for session id', sid, sess.remoteJid, iq);\r\n                ack.attrs({ type: 'error' });\r\n                ack.c('error', { type: 'cancel' })\r\n                    .c('item-not-found', {\r\n                        xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'\r\n                    })\r\n                    .up()\r\n                    .c('unknown-session', {\r\n                        xmlns: 'urn:xmpp:jingle:errors:1'\r\n                    });\r\n                this.connection.send(ack);\r\n\r\n                return true;\r\n            }\r\n        } else if (sess !== undefined) {\r\n            // Existing session with same session id. This might be out-of-order\r\n            // if the sess.remoteJid is the same as from.\r\n            ack.attrs({ type: 'error' });\r\n            ack.c('error', { type: 'cancel' })\r\n                .c('service-unavailable', {\r\n                    xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'\r\n                })\r\n                .up();\r\n            logger.warn('duplicate session id', sid, iq);\r\n            this.connection.send(ack);\r\n\r\n            return true;\r\n        }\r\n        const now = window.performance.now();\r\n\r\n        // FIXME that should work most of the time, but we'd have to\r\n        // think how secure it is to assume that user with \"focus\"\r\n        // nickname is Jicofo.\r\n        const isP2P = Strophe.getResourceFromJid(fromJid) !== 'focus';\r\n\r\n        // see http://xmpp.org/extensions/xep-0166.html#concepts-session\r\n\r\n        const jsonMessages = $(iq).find('jingle>json-message');\r\n\r\n        if (jsonMessages?.length) {\r\n            let audioVideoSsrcs;\r\n\r\n            logger.info(`Found a JSON-encoded element in ${action}, translating to standard Jingle.`);\r\n            for (let i = 0; i < jsonMessages.length; i++) {\r\n                // Currently there is always a single json-message in the IQ with the source information.\r\n                audioVideoSsrcs = expandSourcesFromJson(iq, jsonMessages[i]);\r\n            }\r\n\r\n            if (audioVideoSsrcs?.size) {\r\n                const logMessage = [];\r\n\r\n                for (const endpoint of audioVideoSsrcs.keys()) {\r\n                    logMessage.push(`${endpoint}:[${audioVideoSsrcs.get(endpoint)}]`);\r\n                }\r\n                logger.debug(`Received ${action} from ${fromJid} with sources=${logMessage.join(', ')}`);\r\n            }\r\n\r\n            // TODO: is there a way to remove the json-message elements once we've extracted the information?\r\n            // removeChild doesn't seem to work.\r\n        }\r\n\r\n        switch (action) {\r\n        case 'session-initiate': {\r\n            logger.log('(TIME) received session-initiate:\\t', now);\r\n            const startMuted = $(iq).find('jingle>startmuted');\r\n\r\n            isP2P && logger.debug(`Received ${action} from ${fromJid}`);\r\n            if (startMuted?.length) {\r\n                const audioMuted = startMuted.attr(MediaType.AUDIO);\r\n                const videoMuted = startMuted.attr(MediaType.VIDEO);\r\n\r\n                this.eventEmitter.emit(\r\n                    XMPPEvents.START_MUTED_FROM_FOCUS,\r\n                    audioMuted === 'true',\r\n                    videoMuted === 'true');\r\n            }\r\n            const pcConfig = isP2P ? this.p2pIceConfig : this.jvbIceConfig;\r\n\r\n            sess\r\n                = new JingleSessionPC(\r\n                    $(iq).find('jingle').attr('sid'),\r\n                    $(iq).attr('to'),\r\n                    fromJid,\r\n                    this.connection,\r\n                    this.mediaConstraints,\r\n\r\n                    // Makes a copy in order to prevent exception thrown on RN when either this.p2pIceConfig or\r\n                    // this.jvbIceConfig is modified and there's a PeerConnection instance holding a reference\r\n                    JSON.parse(JSON.stringify(pcConfig)),\r\n                    isP2P,\r\n                    /* initiator */ false);\r\n\r\n            this.sessions[sess.sid] = sess;\r\n            this.eventEmitter.emit(XMPPEvents.CALL_INCOMING, sess, $(iq).find('>jingle'), now);\r\n            break;\r\n        }\r\n        case 'session-accept': {\r\n            const ssrcs = [];\r\n            const contents = $(iq).find('jingle>content');\r\n\r\n            // Extract the SSRCs from the session-accept received from a p2p peer.\r\n            for (const content of contents) {\r\n                const ssrc = $(content).find('description').attr('ssrc');\r\n\r\n                ssrc && ssrcs.push(ssrc);\r\n            }\r\n            logger.debug(`Received ${action} from ${fromJid} with ssrcs=${ssrcs}`);\r\n            this.eventEmitter.emit(XMPPEvents.CALL_ACCEPTED, sess, $(iq).find('>jingle'));\r\n            break;\r\n        }\r\n        case 'content-modify': {\r\n            const height = $(iq).find('jingle>content[name=\"video\"]>max-frame-height');\r\n\r\n            logger.debug(`Received ${action} from ${fromJid} with a max-frame-height=${height?.text()}`);\r\n            sess.modifyContents($(iq).find('>jingle'));\r\n            break;\r\n        }\r\n        case 'transport-info': {\r\n            const candidates = _parseIceCandidates($(iq).find('jingle>content>transport'));\r\n\r\n            logger.debug(`Received ${action} from ${fromJid} for candidates=${candidates.join(', ')}`);\r\n            this.eventEmitter.emit(XMPPEvents.TRANSPORT_INFO, sess, $(iq).find('>jingle'));\r\n            break;\r\n        }\r\n        case 'session-terminate': {\r\n            logger.log('terminating...', sess.sid);\r\n            let reasonCondition = null;\r\n            let reasonText = null;\r\n\r\n            if ($(iq).find('>jingle>reason').length) {\r\n                reasonCondition\r\n                    = $(iq).find('>jingle>reason>:first')[0].tagName;\r\n                reasonText = $(iq).find('>jingle>reason>text').text();\r\n            }\r\n            logger.debug(`Received ${action} from ${fromJid} disconnect reason=${reasonText}`);\r\n            this.terminate(sess.sid, reasonCondition, reasonText);\r\n            this.eventEmitter.emit(XMPPEvents.CALL_ENDED, sess, reasonCondition, reasonText);\r\n            break;\r\n        }\r\n        case 'transport-replace': {\r\n            logger.info('(TIME) Start transport replace:\\t', now);\r\n            const transport = $(iq).find('jingle>content>transport');\r\n            const candidates = _parseIceCandidates(transport);\r\n            const iceUfrag = $(transport).attr('ufrag');\r\n            const icePwd = $(transport).attr('pwd');\r\n            const dtlsFingerprint = $(transport).find('>fingerprint')?.text();\r\n\r\n            logger.debug(`Received ${action} from ${fromJid} with iceUfrag=${iceUfrag},`\r\n            + ` icePwd=${icePwd}, DTLS fingerprint=${dtlsFingerprint}, candidates=${candidates.join(', ')}`);\r\n\r\n            Statistics.sendAnalytics(createJingleEvent(\r\n                ACTION_JINGLE_TR_RECEIVED,\r\n                {\r\n                    p2p: isP2P,\r\n                    value: now\r\n                }));\r\n\r\n            sess.replaceTransport($(iq).find('>jingle'), () => {\r\n                const successTime = window.performance.now();\r\n\r\n                logger.info('(TIME) Transport replace success:\\t', successTime);\r\n                Statistics.sendAnalytics(createJingleEvent(\r\n                    ACTION_JINGLE_TR_SUCCESS,\r\n                    {\r\n                        p2p: isP2P,\r\n                        value: successTime\r\n                    }));\r\n            }, error => {\r\n                GlobalOnErrorHandler.callErrorHandler(error);\r\n                logger.error('Transport replace failed', error);\r\n                sess.sendTransportReject();\r\n            });\r\n            break;\r\n        }\r\n        case 'source-add':\r\n            sess.addRemoteStream($(iq).find('>jingle>content'));\r\n            break;\r\n        case 'source-remove':\r\n            sess.removeRemoteStream($(iq).find('>jingle>content'));\r\n            break;\r\n        default:\r\n            logger.warn('jingle action not implemented', action);\r\n            ack.attrs({ type: 'error' });\r\n            ack.c('error', { type: 'cancel' })\r\n                .c('bad-request',\r\n                    { xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas' })\r\n                .up();\r\n            break;\r\n        }\r\n        this.connection.send(ack);\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * Creates new <tt>JingleSessionPC</tt> meant to be used in a direct P2P\r\n     * connection, configured as 'initiator'.\r\n     * @param {string} me our JID\r\n     * @param {string} peer remote participant's JID\r\n     * @return {JingleSessionPC}\r\n     */\r\n    newP2PJingleSession(me, peer) {\r\n        const sess\r\n            = new JingleSessionPC(\r\n                RandomUtil.randomHexString(12),\r\n                me,\r\n                peer,\r\n                this.connection,\r\n                this.mediaConstraints,\r\n                this.p2pIceConfig,\r\n                /* P2P */ true,\r\n                /* initiator */ true);\r\n\r\n        this.sessions[sess.sid] = sess;\r\n\r\n        return sess;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param sid\r\n     * @param reasonCondition\r\n     * @param reasonText\r\n     */\r\n    terminate(sid, reasonCondition, reasonText) {\r\n        if (this.sessions.hasOwnProperty(sid)) {\r\n            if (this.sessions[sid].state !== 'ended') {\r\n                this.sessions[sid].onTerminated(reasonCondition, reasonText);\r\n            }\r\n            delete this.sessions[sid];\r\n        }\r\n    }\r\n\r\n    /**\r\n     *\r\n     */\r\n    getStunAndTurnCredentials() {\r\n        // get stun and turn configuration from server via xep-0215\r\n        // uses time-limited credentials as described in\r\n        // http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00\r\n        //\r\n        // See https://modules.prosody.im/mod_turncredentials.html\r\n        // for a prosody module which implements this.\r\n        // Or the new implementation https://modules.prosody.im/mod_external_services which will be in prosody 0.12\r\n        //\r\n        // Currently, this doesn't work with updateIce and therefore credentials\r\n        // with a long validity have to be fetched before creating the\r\n        // peerconnection.\r\n        // TODO: implement refresh via updateIce as described in\r\n        //      https://code.google.com/p/webrtc/issues/detail?id=1650\r\n        this.connection.sendIQ(\r\n            $iq({ type: 'get',\r\n                to: this.xmpp.options.hosts.domain })\r\n                .c('services', { xmlns: 'urn:xmpp:extdisco:2' }),\r\n            v2Res => this.onReceiveStunAndTurnCredentials(v2Res),\r\n            () => {\r\n                logger.warn('getting turn credentials with extdisco:2 failed, trying extdisco:1');\r\n                this.connection.sendIQ(\r\n                    $iq({ type: 'get',\r\n                        to: this.xmpp.options.hosts.domain })\r\n                        .c('services', { xmlns: 'urn:xmpp:extdisco:1' }),\r\n                    v1Res => this.onReceiveStunAndTurnCredentials(v1Res),\r\n                    () => {\r\n                        logger.warn('getting turn credentials failed');\r\n                        logger.warn('is mod_turncredentials or similar installed and configured?');\r\n                    }\r\n                );\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Parses response when querying for services using urn:xmpp:extdisco:1 or urn:xmpp:extdisco:2.\r\n     * Stores results in jvbIceConfig and p2pIceConfig.\r\n     * @param res The response iq.\r\n     * @return {boolean} Whether something was processed from the supplied message.\r\n     */\r\n    onReceiveStunAndTurnCredentials(res) {\r\n        const iceservers = [];\r\n\r\n        $(res).find('>services>service').each((idx, el) => {\r\n            // eslint-disable-next-line no-param-reassign\r\n            el = $(el);\r\n            const dict = {};\r\n            const type = el.attr('type');\r\n\r\n            switch (type) {\r\n            case 'stun':\r\n                dict.urls = `stun:${el.attr('host')}`;\r\n                if (el.attr('port')) {\r\n                    dict.urls += `:${el.attr('port')}`;\r\n                }\r\n                iceservers.push(dict);\r\n                break;\r\n            case 'turn':\r\n            case 'turns': {\r\n                dict.urls = `${type}:`;\r\n                dict.username = el.attr('username');\r\n                dict.urls += el.attr('host');\r\n                const port = el.attr('port');\r\n\r\n                if (port) {\r\n                    dict.urls += `:${el.attr('port')}`;\r\n                }\r\n                const transport = el.attr('transport');\r\n\r\n                if (transport && transport !== 'udp') {\r\n                    dict.urls += `?transport=${transport}`;\r\n                }\r\n\r\n                dict.credential = el.attr('password')\r\n                        || dict.credential;\r\n                iceservers.push(dict);\r\n                break;\r\n            }\r\n            }\r\n        });\r\n\r\n        const options = this.xmpp.options;\r\n\r\n        // Shuffle ICEServers for loadbalancing\r\n        for (let i = iceservers.length - 1; i > 0; i--) {\r\n            const j = Math.floor(Math.random() * (i + 1));\r\n            const temp = iceservers[i];\r\n\r\n            iceservers[i] = iceservers[j];\r\n            iceservers[j] = temp;\r\n        }\r\n\r\n        let filter;\r\n\r\n        if (options.useTurnUdp) {\r\n            filter = s => s.urls.startsWith('turn');\r\n        } else {\r\n            // By default we filter out STUN and TURN/UDP and leave only TURN/TCP.\r\n            filter = s => s.urls.startsWith('turn') && (s.urls.indexOf('transport=tcp') >= 0);\r\n        }\r\n\r\n        this.jvbIceConfig.iceServers = iceservers.filter(filter);\r\n        this.p2pIceConfig.iceServers = iceservers;\r\n\r\n        return iceservers.length > 0;\r\n    }\r\n\r\n    /**\r\n     * Returns the data saved in 'updateLog' in a format to be logged.\r\n     */\r\n    getLog() {\r\n        const data = {};\r\n\r\n        Object.keys(this.sessions).forEach(sid => {\r\n            const session = this.sessions[sid];\r\n            const pc = session.peerconnection;\r\n\r\n            if (pc && pc.updateLog) {\r\n                // FIXME: should probably be a .dump call\r\n                data[`jingle_${sid}`] = {\r\n                    updateLog: pc.updateLog,\r\n                    stats: pc.stats,\r\n                    url: window.location.href\r\n                };\r\n            }\r\n        });\r\n\r\n        return data;\r\n    }\r\n}\r\n\r\n/* eslint-enable newline-per-chained-call */\r\n","import { Strophe } from 'strophe.js';\r\n\r\nimport ConnectionPlugin from './ConnectionPlugin';\r\n\r\n/**\r\n *  Logs raw stanzas and makes them available for download as JSON\r\n */\r\nclass StropheLogger extends ConnectionPlugin {\r\n    /**\r\n     *\r\n     */\r\n    constructor() {\r\n        super();\r\n        this.log = [];\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param connection\r\n     */\r\n    init(connection) {\r\n        super.init(connection);\r\n        this.connection.rawInput = this.logIncoming.bind(this);\r\n        this.connection.rawOutput = this.logOutgoing.bind(this);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param stanza\r\n     */\r\n    logIncoming(stanza) {\r\n        this.log.push([ new Date().getTime(), 'incoming', stanza ]);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param stanza\r\n     */\r\n    logOutgoing(stanza) {\r\n        this.log.push([ new Date().getTime(), 'outgoing', stanza ]);\r\n    }\r\n}\r\n\r\n/**\r\n *\r\n */\r\nexport default function() {\r\n    Strophe.addConnectionPlugin('logger', new StropheLogger());\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport $ from 'jquery';\r\nimport { $iq } from 'strophe.js';\r\n\r\nimport ConnectionPlugin from './ConnectionPlugin';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\nconst RAYO_XMLNS = 'urn:xmpp:rayo:1';\r\n\r\n/**\r\n *\r\n */\r\nexport default class RayoConnectionPlugin extends ConnectionPlugin {\r\n    /**\r\n     *\r\n     * @param connection\r\n     */\r\n    init(connection) {\r\n        super.init(connection);\r\n\r\n        this.connection.addHandler(\r\n            this.onRayo.bind(this), RAYO_XMLNS, 'iq', 'set', null, null);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param iq\r\n     */\r\n    onRayo(iq) {\r\n        logger.info('Rayo IQ', iq);\r\n    }\r\n\r\n    /* eslint-disable max-params */\r\n\r\n    /**\r\n     *\r\n     * @param to\r\n     * @param from\r\n     * @param roomName\r\n     * @param roomPass\r\n     * @param focusMucJid\r\n     */\r\n    dial(to, from, roomName, roomPass, focusMucJid) {\r\n        return new Promise((resolve, reject) => {\r\n            if (!focusMucJid) {\r\n                reject(new Error('Internal error!'));\r\n\r\n                return;\r\n            }\r\n            const req = $iq({\r\n                type: 'set',\r\n                to: focusMucJid\r\n            });\r\n\r\n            req.c('dial', {\r\n                xmlns: RAYO_XMLNS,\r\n                to,\r\n                from\r\n            });\r\n            req.c('header', {\r\n                name: 'JvbRoomName',\r\n                value: roomName\r\n            }).up();\r\n\r\n            if (roomPass && roomPass.length) {\r\n                req.c('header', {\r\n                    name: 'JvbRoomPassword',\r\n                    value: roomPass\r\n                }).up();\r\n            }\r\n\r\n            this.connection.sendIQ(\r\n                req,\r\n                result => {\r\n                    logger.info('Dial result ', result);\r\n\r\n                    // eslint-disable-next-line newline-per-chained-call\r\n                    const resource = $(result).find('ref').attr('uri');\r\n\r\n                    this.callResource = resource.substr('xmpp:'.length);\r\n                    logger.info(`Received call resource: ${this.callResource}`);\r\n                    resolve();\r\n                },\r\n                error => {\r\n                    logger.info('Dial error ', error);\r\n                    reject(error);\r\n                });\r\n        });\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     *\r\n     */\r\n    hangup() {\r\n        return new Promise((resolve, reject) => {\r\n            if (!this.callResource) {\r\n                reject(new Error('No call in progress'));\r\n                logger.warn('No call in progress');\r\n\r\n                return;\r\n            }\r\n\r\n            const req = $iq({\r\n                type: 'set',\r\n                to: this.callResource\r\n            });\r\n\r\n            req.c('hangup', {\r\n                xmlns: RAYO_XMLNS\r\n            });\r\n\r\n            this.connection.sendIQ(req, result => {\r\n                logger.info('Hangup result ', result);\r\n                this.callResource = null;\r\n                resolve();\r\n            }, error => {\r\n                logger.info('Hangup error ', error);\r\n                this.callResource = null;\r\n                reject(new Error('Hangup error '));\r\n            });\r\n        });\r\n    }\r\n}\r\n","/**\r\n * Strophe logger implementation. Logs from level WARN and above.\r\n */\r\nimport { getLogger } from '@jitsi/logger';\r\nimport { Strophe } from 'strophe.js';\r\n\r\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * This is the last HTTP error status captured from Strophe debug logs.\r\n * The purpose of storing it is to distinguish between the network and\r\n * infrastructure reason for connection being dropped (see connectionHandler in\r\n * xmpp.js). The value will be cleared (-1) if the subsequent request succeeds\r\n * which means that the failure could be transient.\r\n *\r\n * FIXME in the latest Strophe (not released on npm) there is API to handle\r\n * particular HTTP errors, but there is no way to learn if the subsequent\r\n * request succeeded in order to tell if the error was one time incident or if\r\n * it was the reason for dropping the connection by Strophe (the connection is\r\n * dropped after 5 subsequent failures). Ideally Strophe should provide more\r\n * details about the reason on why the connection stopped.\r\n *\r\n * @type {number}\r\n */\r\nlet lastErrorStatus = -1;\r\n\r\n/**\r\n * A regular expression used to catch Strophe's log message indicating that the\r\n * last BOSH request was successful. When there is such message seen the\r\n * {@link lastErrorStatus} will be set back to '-1'.\r\n * @type {RegExp}\r\n */\r\nconst resetLastErrorStatusRegExpr = /request id \\d+.\\d+ got 200/;\r\n\r\n/**\r\n * A regular expression used to capture the current value of the BOSH request\r\n * error status (HTTP error code or '0' or something else).\r\n * @type {RegExp}\r\n */\r\nconst lastErrorStatusRegExpr\r\n    = /request errored, status: (\\d+), number of errors: \\d+/;\r\n\r\n/**\r\n *\r\n */\r\nexport default function() {\r\n\r\n    Strophe.log = function(level, msg) {\r\n        // Our global handler reports uncaught errors to the stats which may\r\n        // interpret those as partial call failure.\r\n        // Strophe log entry about secondary request timeout does not mean that\r\n        // it's a final failure(the request will be restarted), so we lower it's\r\n        // level here to a warning.\r\n        logger.trace('Strophe', level, msg);\r\n        if (typeof msg === 'string'\r\n                && msg.indexOf('Request ') !== -1\r\n                && msg.indexOf('timed out (secondary), restarting') !== -1) {\r\n            // eslint-disable-next-line no-param-reassign\r\n            level = Strophe.LogLevel.WARN;\r\n        }\r\n\r\n        /* eslint-disable no-case-declarations */\r\n        switch (level) {\r\n        case Strophe.LogLevel.DEBUG:\r\n            // The log message which reports successful status is logged on\r\n            // Strophe's DEBUG level.\r\n            if (lastErrorStatus !== -1\r\n                    && resetLastErrorStatusRegExpr.test(msg)) {\r\n                logger.debug('Reset lastErrorStatus');\r\n                lastErrorStatus = -1;\r\n            }\r\n            break;\r\n        case Strophe.LogLevel.WARN:\r\n            logger.warn(`Strophe: ${msg}`);\r\n            const errStatusCapture = lastErrorStatusRegExpr.exec(msg);\r\n\r\n            if (errStatusCapture && errStatusCapture.length === 2) {\r\n                lastErrorStatus = parseInt(errStatusCapture[1], 10);\r\n                logger.debug(`lastErrorStatus set to: ${lastErrorStatus}`);\r\n            }\r\n            break;\r\n        case Strophe.LogLevel.ERROR:\r\n        case Strophe.LogLevel.FATAL:\r\n            // eslint-disable-next-line no-param-reassign\r\n            msg = `Strophe: ${msg}`;\r\n            GlobalOnErrorHandler.callErrorHandler(new Error(msg));\r\n            logger.error(msg);\r\n            break;\r\n        }\r\n\r\n        /* eslint-enable no-case-declarations */\r\n    };\r\n\r\n    /**\r\n     * Returns error status (HTTP error code) of the last BOSH request.\r\n     *\r\n     * @return {number} HTTP error code, '0' for unknown or \"god knows what\"\r\n     * (this is a hack).\r\n     */\r\n    Strophe.getLastErrorStatus = function() {\r\n        return lastErrorStatus;\r\n    };\r\n\r\n    Strophe.getStatusString = function(status) {\r\n        switch (status) {\r\n        case Strophe.Status.BINDREQUIRED:\r\n            return 'BINDREQUIRED';\r\n        case Strophe.Status.ERROR:\r\n            return 'ERROR';\r\n        case Strophe.Status.CONNECTING:\r\n            return 'CONNECTING';\r\n        case Strophe.Status.CONNFAIL:\r\n            return 'CONNFAIL';\r\n        case Strophe.Status.AUTHENTICATING:\r\n            return 'AUTHENTICATING';\r\n        case Strophe.Status.AUTHFAIL:\r\n            return 'AUTHFAIL';\r\n        case Strophe.Status.CONNECTED:\r\n            return 'CONNECTED';\r\n        case Strophe.Status.DISCONNECTED:\r\n            return 'DISCONNECTED';\r\n        case Strophe.Status.DISCONNECTING:\r\n            return 'DISCONNECTING';\r\n        case Strophe.Status.ATTACHED:\r\n            return 'ATTACHED';\r\n        default:\r\n            return 'unknown';\r\n        }\r\n    };\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport $ from 'jquery';\r\nimport { $msg, Strophe } from 'strophe.js';\r\nimport 'strophejs-plugin-disco';\r\n\r\nimport * as JitsiConnectionErrors from '../../JitsiConnectionErrors';\r\nimport * as JitsiConnectionEvents from '../../JitsiConnectionEvents';\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\nimport browser from '../browser';\r\nimport { E2EEncryption } from '../e2ee/E2EEncryption';\r\nimport Statistics from '../statistics/statistics';\r\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\r\nimport Listenable from '../util/Listenable';\r\nimport RandomUtil from '../util/RandomUtil';\r\n\r\nimport Caps, { parseDiscoInfo } from './Caps';\r\nimport XmppConnection from './XmppConnection';\r\nimport MucConnectionPlugin from './strophe.emuc';\r\nimport JingleConnectionPlugin from './strophe.jingle';\r\nimport initStropheLogger from './strophe.logger';\r\nimport RayoConnectionPlugin from './strophe.rayo';\r\nimport initStropheUtil from './strophe.util';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n* Regex to extract exact error message on jwt error.\r\n*/\r\nconst FAILURE_REGEX = /<failure.*><not-allowed\\/><text>(.*)<\\/text><\\/failure>/gi;\r\n\r\n/**\r\n * Creates XMPP connection.\r\n *\r\n * @param {Object} options\r\n * @param {string} [options.token] - JWT token used for authentication(JWT authentication module must be enabled in\r\n * Prosody).\r\n * @param {string} options.serviceUrl - The service URL for XMPP connection.\r\n * @param {string} options.shard - The shard where XMPP connection initially landed.\r\n * @param {string} options.enableWebsocketResume - True to enable stream resumption.\r\n * @param {number} [options.websocketKeepAlive] - See {@link XmppConnection} constructor.\r\n * @param {number} [options.websocketKeepAliveUrl] - See {@link XmppConnection} constructor.\r\n * @param {Object} [options.xmppPing] - See {@link XmppConnection} constructor.\r\n * @returns {XmppConnection}\r\n */\r\nfunction createConnection({\r\n    enableWebsocketResume,\r\n    serviceUrl = '/http-bind',\r\n    shard,\r\n    token,\r\n    websocketKeepAlive,\r\n    websocketKeepAliveUrl,\r\n    xmppPing }) {\r\n\r\n    // Append token as URL param\r\n    if (token) {\r\n        // eslint-disable-next-line no-param-reassign\r\n        serviceUrl += `${serviceUrl.indexOf('?') === -1 ? '?' : '&'}token=${token}`;\r\n    }\r\n\r\n    return new XmppConnection({\r\n        enableWebsocketResume,\r\n        serviceUrl,\r\n        websocketKeepAlive,\r\n        websocketKeepAliveUrl,\r\n        xmppPing,\r\n        shard\r\n    });\r\n}\r\n\r\n/**\r\n * Initializes Strophe plugins that need to work with Strophe.Connection directly rather than the lib-jitsi-meet's\r\n * {@link XmppConnection} wrapper.\r\n *\r\n * @returns {void}\r\n */\r\nfunction initStropheNativePlugins() {\r\n    initStropheUtil();\r\n    initStropheLogger();\r\n}\r\n\r\n// FIXME: remove once we have a default config template. -saghul\r\n/**\r\n * A list of ice servers to use by default for P2P.\r\n */\r\nexport const DEFAULT_STUN_SERVERS = [\r\n    { urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' }\r\n];\r\n\r\n/**\r\n * The name of the field used to recognize a chat message as carrying a JSON\r\n * payload from another endpoint.\r\n * If the json-message of a chat message contains a valid JSON object, and\r\n * the JSON has this key, then it is a valid json-message to be sent.\r\n */\r\nexport const JITSI_MEET_MUC_TYPE = 'type';\r\n\r\n/**\r\n * The feature used by jigasi participants.\r\n * @type {string}\r\n */\r\nexport const FEATURE_JIGASI = 'http://jitsi.org/protocol/jigasi';\r\n\r\n/**\r\n * The feature used by the lib to mark support for e2ee. We use the feature by putting it in the presence\r\n * to avoid additional signaling (disco-info).\r\n * @type {string}\r\n */\r\nexport const FEATURE_E2EE = 'https://jitsi.org/meet/e2ee';\r\n\r\n/**\r\n *\r\n */\r\nexport default class XMPP extends Listenable {\r\n    /**\r\n     * FIXME describe all options\r\n     * @param {Object} options\r\n     * @param {String} options.serviceUrl - URL passed to the XMPP client which will be used to establish XMPP\r\n     * connection with the server.\r\n     * @param {String} options.bosh - Deprecated, use {@code serviceUrl}.\r\n     * @param {boolean} options.enableWebsocketResume - Enables XEP-0198 stream management which will make the XMPP\r\n     * module try to resume the session in case the Websocket connection breaks.\r\n     * @param {number} [options.websocketKeepAlive] - The websocket keep alive interval. See {@link XmppConnection}\r\n     * constructor for more details.\r\n     * @param {number} [options.websocketKeepAliveUrl] - The websocket keep alive url. See {@link XmppConnection}\r\n     * constructor for more details.\r\n     * @param {Object} [options.xmppPing] - The xmpp ping settings.\r\n     * @param {Array<Object>} options.p2pStunServers see {@link JingleConnectionPlugin} for more details.\r\n     * @param token\r\n     */\r\n    constructor(options, token) {\r\n        super();\r\n        this.connection = null;\r\n        this.disconnectInProgress = false;\r\n        this.connectionTimes = {};\r\n        this.options = options;\r\n        this.token = token;\r\n        this.authenticatedUser = false;\r\n\r\n        if (!this.options.deploymentInfo) {\r\n            this.options.deploymentInfo = {};\r\n        }\r\n\r\n        // Cache of components used for certain features.\r\n        this._components = [];\r\n\r\n        initStropheNativePlugins();\r\n\r\n        const xmppPing = options.xmppPing || {};\r\n\r\n        // let's ping the main domain (in case a guest one is used for the connection)\r\n        xmppPing.domain = options.hosts.domain;\r\n\r\n        this.connection = createConnection({\r\n            enableWebsocketResume: options.enableWebsocketResume,\r\n\r\n            // FIXME remove deprecated bosh option at some point\r\n            serviceUrl: options.serviceUrl || options.bosh,\r\n            token,\r\n            websocketKeepAlive: options.websocketKeepAlive,\r\n            websocketKeepAliveUrl: options.websocketKeepAliveUrl,\r\n            xmppPing,\r\n            shard: options.deploymentInfo.shard\r\n        });\r\n\r\n        // forwards the shard changed event\r\n        this.connection.on(XmppConnection.Events.CONN_SHARD_CHANGED, () => {\r\n            /* eslint-disable camelcase */\r\n            const details = {\r\n                shard_changed: true,\r\n                suspend_time: this.connection.ping.getPingSuspendTime(),\r\n                time_since_last_success: this.connection.getTimeSinceLastSuccess()\r\n            };\r\n            /* eslint-enable camelcase */\r\n\r\n            this.eventEmitter.emit(\r\n                JitsiConnectionEvents.CONNECTION_FAILED,\r\n                JitsiConnectionErrors.OTHER_ERROR,\r\n                undefined,\r\n                undefined,\r\n                details);\r\n        });\r\n\r\n        this._initStrophePlugins();\r\n\r\n        this.caps = new Caps(this.connection, /* clientNode */ 'https://jitsi.org/jitsi-meet');\r\n\r\n        // Initialize features advertised in disco-info\r\n        this.initFeaturesList();\r\n\r\n        // Setup a disconnect on unload as a way to facilitate API consumers. It\r\n        // sounds like they would want that. A problem for them though may be if\r\n        // they wanted to utilize the connected connection in an unload handler\r\n        // of their own. However, it should be fairly easy for them to do that\r\n        // by registering their unload handler before us.\r\n        $(window).on(`${this.options.disableBeforeUnloadHandlers ? '' : 'beforeunload '}unload`, ev => {\r\n            this.disconnect(ev).catch(() => {\r\n                // ignore errors in order to not brake the unload.\r\n            });\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Initializes the list of feature advertised through the disco-info\r\n     * mechanism.\r\n     */\r\n    initFeaturesList() {\r\n        // http://xmpp.org/extensions/xep-0167.html#support\r\n        // http://xmpp.org/extensions/xep-0176.html#support\r\n        this.caps.addFeature('urn:xmpp:jingle:1');\r\n        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:1');\r\n        this.caps.addFeature('urn:xmpp:jingle:transports:ice-udp:1');\r\n        this.caps.addFeature('urn:xmpp:jingle:apps:dtls:0');\r\n        this.caps.addFeature('urn:xmpp:jingle:transports:dtls-sctp:1');\r\n        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:audio');\r\n        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:video');\r\n        this.caps.addFeature('http://jitsi.org/json-encoded-sources');\r\n\r\n        if (!(this.options.disableRtx || !browser.supportsRTX())) {\r\n            this.caps.addFeature('urn:ietf:rfc:4588');\r\n        }\r\n        if (this.options.enableOpusRed === true && browser.supportsAudioRed()) {\r\n            this.caps.addFeature('http://jitsi.org/opus-red');\r\n        }\r\n\r\n        if (typeof this.options.enableRemb === 'undefined' || this.options.enableRemb) {\r\n            this.caps.addFeature('http://jitsi.org/remb');\r\n        }\r\n\r\n        // Disable TCC on Firefox because of a known issue where BWE is halved on every renegotiation.\r\n        if (!browser.isFirefox() && (typeof this.options.enableTcc === 'undefined' || this.options.enableTcc)) {\r\n            this.caps.addFeature('http://jitsi.org/tcc');\r\n        }\r\n\r\n        // this is dealt with by SDP O/A so we don't need to announce this\r\n        // XEP-0293\r\n        // this.caps.addFeature('urn:xmpp:jingle:apps:rtp:rtcp-fb:0');\r\n        // XEP-0294\r\n        // this.caps.addFeature('urn:xmpp:jingle:apps:rtp:rtp-hdrext:0');\r\n\r\n        // this.caps.addFeature('urn:ietf:rfc:5576'); // a=ssrc\r\n\r\n        // Enable Lipsync ?\r\n        if (browser.isChromiumBased() && this.options.enableLipSync === true) {\r\n            logger.info('Lip-sync enabled !');\r\n            this.caps.addFeature('http://jitsi.org/meet/lipsync');\r\n        }\r\n\r\n        if (this.connection.rayo) {\r\n            this.caps.addFeature('urn:xmpp:rayo:client:1');\r\n        }\r\n\r\n        if (E2EEncryption.isSupported(this.options)) {\r\n            this.caps.addFeature(FEATURE_E2EE, false, true);\r\n        }\r\n\r\n        // Advertise source-name signaling when the endpoint supports it.\r\n        logger.debug('Source-name signaling is enabled');\r\n        this.caps.addFeature('http://jitsi.org/source-name');\r\n\r\n        logger.debug('Receiving multiple video streams is enabled');\r\n        this.caps.addFeature('http://jitsi.org/receive-multiple-video-streams');\r\n    }\r\n\r\n    /**\r\n     *\r\n     */\r\n    getConnection() {\r\n        return this.connection;\r\n    }\r\n\r\n    /**\r\n     * Receive connection status changes and handles them.\r\n     *\r\n     * @param {Object} credentials\r\n     * @param {string} credentials.jid - The user's XMPP ID passed to the\r\n     * connect method. For example, 'user@xmpp.com'.\r\n     * @param {string} credentials.password - The password passed to the connect\r\n     * method.\r\n     * @param {string} status - One of Strophe's connection status strings.\r\n     * @param {string} [msg] - The connection error message provided by Strophe.\r\n     */\r\n    connectionHandler(credentials = {}, status, msg) {\r\n        const now = window.performance.now();\r\n        const statusStr = Strophe.getStatusString(status).toLowerCase();\r\n\r\n        this.connectionTimes[statusStr] = now;\r\n        logger.log(\r\n            `(TIME) Strophe ${statusStr}${msg ? `[${msg}]` : ''}:\\t`,\r\n            now);\r\n\r\n        this.eventEmitter.emit(XMPPEvents.CONNECTION_STATUS_CHANGED, credentials, status, msg);\r\n        this._maybeSendDeploymentInfoStat();\r\n        if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {\r\n            // once connected or attached we no longer need this handle, drop it if it exist\r\n            if (this._sysMessageHandler) {\r\n                this.connection._stropheConn.deleteHandler(this._sysMessageHandler);\r\n                this._sysMessageHandler = null;\r\n            }\r\n\r\n            this.sendDiscoInfo && this.connection.jingle.getStunAndTurnCredentials();\r\n\r\n            logger.info(`My Jabber ID: ${this.connection.jid}`);\r\n\r\n            // XmppConnection emits CONNECTED again on reconnect - a good opportunity to clear any \"last error\" flags\r\n            this._resetState();\r\n\r\n            // make sure we will send the info after the features request succeeds or fails\r\n            this.sendDeploymentInfo = false;\r\n            this.sendDiscoInfo && this.caps.getFeaturesAndIdentities(this.options.hosts.domain)\r\n                .then(({ features, identities }) => {\r\n                    if (!features.has(Strophe.NS.PING)) {\r\n                        logger.error(`Ping NOT supported by ${\r\n                            this.options.hosts.domain} - please enable ping in your XMPP server config`);\r\n                    }\r\n\r\n                    this._processDiscoInfoIdentities(\r\n                        identities, undefined /* when querying we will query for features */);\r\n                })\r\n                .catch(error => {\r\n                    const errmsg = 'Feature discovery error';\r\n\r\n                    GlobalOnErrorHandler.callErrorHandler(\r\n                        new Error(`${errmsg}: ${error}`));\r\n                    logger.error(errmsg, error);\r\n\r\n                    this._maybeSendDeploymentInfoStat(true);\r\n                });\r\n\r\n            // make sure we don't query again\r\n            this.sendDiscoInfo = false;\r\n\r\n            if (credentials.password) {\r\n                this.authenticatedUser = true;\r\n            }\r\n            if (this.connection && this.connection.connected\r\n                && Strophe.getResourceFromJid(this.connection.jid)) {\r\n                // .connected is true while connecting?\r\n                // this.connection.send($pres());\r\n                this.eventEmitter.emit(\r\n                    JitsiConnectionEvents.CONNECTION_ESTABLISHED,\r\n                    Strophe.getResourceFromJid(this.connection.jid));\r\n            }\r\n        } else if (status === Strophe.Status.CONNFAIL) {\r\n            if (msg === 'x-strophe-bad-non-anon-jid') {\r\n                this.anonymousConnectionFailed = true;\r\n            } else {\r\n                this.connectionFailed = true;\r\n            }\r\n            this.lastErrorMsg = msg;\r\n            if (msg === 'giving-up') {\r\n                this.eventEmitter.emit(\r\n                    JitsiConnectionEvents.CONNECTION_FAILED,\r\n                    JitsiConnectionErrors.OTHER_ERROR, msg);\r\n            }\r\n        } else if (status === Strophe.Status.ERROR) {\r\n            this.lastErrorMsg = msg;\r\n        } else if (status === Strophe.Status.DISCONNECTED) {\r\n            // Stop ping interval\r\n            this.connection.ping.stopInterval();\r\n            const wasIntentionalDisconnect = Boolean(this.disconnectInProgress);\r\n            const errMsg = msg || this.lastErrorMsg;\r\n\r\n            if (this.anonymousConnectionFailed) {\r\n                // prompt user for username and password\r\n                this.eventEmitter.emit(\r\n                    JitsiConnectionEvents.CONNECTION_FAILED,\r\n                    JitsiConnectionErrors.PASSWORD_REQUIRED);\r\n            } else if (this.connectionFailed) {\r\n                this.eventEmitter.emit(\r\n                    JitsiConnectionEvents.CONNECTION_FAILED,\r\n                    JitsiConnectionErrors.OTHER_ERROR,\r\n                    errMsg,\r\n                    undefined, /* credentials */\r\n                    this._getConnectionFailedReasonDetails());\r\n            } else if (wasIntentionalDisconnect) {\r\n                this.eventEmitter.emit(\r\n                    JitsiConnectionEvents.CONNECTION_DISCONNECTED, errMsg);\r\n            } else {\r\n                // XXX if Strophe drops the connection while not being asked to,\r\n                // it means that most likely some serious error has occurred.\r\n                // One currently known case is when a BOSH request fails for\r\n                // more than 4 times. The connection is dropped without\r\n                // supplying a reason(error message/event) through the API.\r\n                logger.error('XMPP connection dropped!');\r\n\r\n                // XXX if the last request error is within 5xx range it means it\r\n                // was a server failure\r\n                const lastErrorStatus = Strophe.getLastErrorStatus();\r\n\r\n                if (lastErrorStatus >= 500 && lastErrorStatus < 600) {\r\n                    this.eventEmitter.emit(\r\n                        JitsiConnectionEvents.CONNECTION_FAILED,\r\n                        JitsiConnectionErrors.SERVER_ERROR,\r\n                        errMsg || 'server-error',\r\n                        /* credentials */ undefined,\r\n                        this._getConnectionFailedReasonDetails());\r\n                } else {\r\n                    this.eventEmitter.emit(\r\n                        JitsiConnectionEvents.CONNECTION_FAILED,\r\n                        JitsiConnectionErrors.CONNECTION_DROPPED_ERROR,\r\n                        errMsg || 'connection-dropped-error',\r\n                        /* credentials */ undefined,\r\n                        this._getConnectionFailedReasonDetails());\r\n                }\r\n            }\r\n        } else if (status === Strophe.Status.AUTHFAIL) {\r\n            const lastFailedRawMessage = this.getConnection().getLastFailedMessage();\r\n\r\n            // wrong password or username, prompt user\r\n            this.eventEmitter.emit(\r\n                JitsiConnectionEvents.CONNECTION_FAILED,\r\n                JitsiConnectionErrors.PASSWORD_REQUIRED,\r\n                msg || this._parseConnectionFailedMessage(lastFailedRawMessage),\r\n                credentials);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Process received identities.\r\n     * @param {Set<String>} identities The identities to process.\r\n     * @param {Set<String>} features The features to process, optional. If missing lobby component will be queried\r\n     * for more features.\r\n     * @private\r\n     */\r\n    _processDiscoInfoIdentities(identities, features) {\r\n        // check for speakerstats\r\n        identities.forEach(identity => {\r\n            if (identity.type === 'av_moderation') {\r\n                this.avModerationComponentAddress = identity.name;\r\n                this._components.push(this.avModerationComponentAddress);\r\n            }\r\n\r\n            if (identity.type === 'end_conference') {\r\n                this.endConferenceComponentAddress = identity.name;\r\n                this._components.push(this.endConferenceComponentAddress);\r\n            }\r\n\r\n            if (identity.type === 'speakerstats') {\r\n                this.speakerStatsComponentAddress = identity.name;\r\n                this._components.push(this.speakerStatsComponentAddress);\r\n            }\r\n\r\n            if (identity.type === 'conference_duration') {\r\n                this.conferenceDurationComponentAddress = identity.name;\r\n                this._components.push(this.conferenceDurationComponentAddress);\r\n            }\r\n\r\n            if (identity.type === 'lobbyrooms') {\r\n                this.lobbySupported = true;\r\n                const processLobbyFeatures = f => {\r\n                    f.forEach(fr => {\r\n                        if (fr.endsWith('#displayname_required')) {\r\n                            this.eventEmitter.emit(JitsiConnectionEvents.DISPLAY_NAME_REQUIRED);\r\n                        }\r\n                    });\r\n                };\r\n\r\n                if (features) {\r\n                    processLobbyFeatures(features);\r\n                } else {\r\n                    identity.name && this.caps.getFeaturesAndIdentities(identity.name, identity.type)\r\n                        .then(({ features: f }) => processLobbyFeatures(f))\r\n                        .catch(e => logger.warn('Error getting features from lobby.', e && e.message));\r\n                }\r\n            }\r\n\r\n            if (identity.type === 'shard') {\r\n                this.options.deploymentInfo.shard = this.connection.shard = identity.name;\r\n            }\r\n\r\n            if (identity.type === 'region') {\r\n                this.options.deploymentInfo.region = this.connection.region = identity.name;\r\n            }\r\n\r\n            if (identity.type === 'release') {\r\n                this.options.deploymentInfo.backendRelease = identity.name;\r\n            }\r\n\r\n            if (identity.type === 'breakout_rooms') {\r\n                this.breakoutRoomsComponentAddress = identity.name;\r\n                this._components.push(this.breakoutRoomsComponentAddress);\r\n            }\r\n\r\n            if (identity.type === 'room_metadata') {\r\n                this.roomMetadataComponentAddress = identity.name;\r\n                this._components.push(this.roomMetadataComponentAddress);\r\n            }\r\n        });\r\n\r\n        this._maybeSendDeploymentInfoStat(true);\r\n\r\n        if (this._components.length > 0) {\r\n            this.connection.addHandler(this._onPrivateMessage.bind(this), null, 'message', null, null);\r\n        }\r\n    }\r\n\r\n    /**\r\n    * Parses a raw failure xmpp xml message received on auth failed.\r\n    *\r\n    * @param {string} msg - The raw failure message from xmpp.\r\n    * @returns {string|null} - The parsed message from the raw xmpp message.\r\n    */\r\n    _parseConnectionFailedMessage(msg) {\r\n        if (!msg) {\r\n            return null;\r\n        }\r\n\r\n        const matches = FAILURE_REGEX.exec(msg);\r\n\r\n        return matches ? matches[1] : null;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param jid\r\n     * @param password\r\n     */\r\n    _connect(jid, password) {\r\n        // connection.connect() starts the connection process.\r\n        //\r\n        // As the connection process proceeds, the user supplied callback will\r\n        // be triggered multiple times with status updates. The callback should\r\n        // take two arguments - the status code and the error condition.\r\n        //\r\n        // The status code will be one of the values in the Strophe.Status\r\n        // constants. The error condition will be one of the conditions defined\r\n        // in RFC 3920 or the condition ‘strophe-parsererror’.\r\n        //\r\n        // The Parameters wait, hold and route are optional and only relevant\r\n        // for BOSH connections. Please see XEP 124 for a more detailed\r\n        // explanation of the optional parameters.\r\n        //\r\n        // Connection status constants for use by the connection handler\r\n        // callback.\r\n        //\r\n        //  Status.ERROR - An error has occurred (websockets specific)\r\n        //  Status.CONNECTING - The connection is currently being made\r\n        //  Status.CONNFAIL - The connection attempt failed\r\n        //  Status.AUTHENTICATING - The connection is authenticating\r\n        //  Status.AUTHFAIL - The authentication attempt failed\r\n        //  Status.CONNECTED - The connection has succeeded\r\n        //  Status.DISCONNECTED - The connection has been terminated\r\n        //  Status.DISCONNECTING - The connection is currently being terminated\r\n        //  Status.ATTACHED - The connection has been attached\r\n\r\n        this._resetState();\r\n\r\n        // we want to send this only on the initial connect\r\n        this.sendDiscoInfo = true;\r\n        this.sendDeploymentInfo = true;\r\n\r\n        if (this.connection._stropheConn && this.connection._stropheConn._addSysHandler) {\r\n            this._sysMessageHandler = this.connection._stropheConn._addSysHandler(\r\n                this._onSystemMessage.bind(this),\r\n                null,\r\n                'message'\r\n            );\r\n        } else {\r\n            logger.warn('Cannot attach strophe system handler, jiconop cannot operate');\r\n        }\r\n\r\n        this.connection.connect(\r\n            jid,\r\n            password,\r\n            this.connectionHandler.bind(this, {\r\n                jid,\r\n                password\r\n            }));\r\n    }\r\n\r\n    /**\r\n     * Receives system messages during the connect/login process and checks for services or\r\n     * @param msg The received message.\r\n     * @returns {void}\r\n     * @private\r\n     */\r\n    _onSystemMessage(msg) {\r\n        // proceed only if the message has any of the expected information\r\n        if ($(msg).find('>services').length === 0 && $(msg).find('>query').length === 0) {\r\n            return;\r\n        }\r\n\r\n        this.sendDiscoInfo = false;\r\n\r\n        const foundIceServers = this.connection.jingle.onReceiveStunAndTurnCredentials(msg);\r\n\r\n        const { features, identities } = parseDiscoInfo(msg);\r\n\r\n        this._processDiscoInfoIdentities(identities, features);\r\n\r\n        if (foundIceServers || identities.size > 0 || features.size > 0) {\r\n            this.connection._stropheConn.deleteHandler(this._sysMessageHandler);\r\n            this._sysMessageHandler = null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Attach to existing connection. Can be used for optimizations. For\r\n     * example: if the connection is created on the server we can attach to it\r\n     * and start using it.\r\n     *\r\n     * @param options {object} connecting options - rid, sid, jid and password.\r\n     */\r\n    attach(options) {\r\n        this._resetState();\r\n\r\n        // we want to send this only on the initial connect\r\n        this.sendDiscoInfo = true;\r\n\r\n        const now = this.connectionTimes.attaching = window.performance.now();\r\n\r\n        logger.log('(TIME) Strophe Attaching:\\t', now);\r\n        this.connection.attach(options.jid, options.sid,\r\n            parseInt(options.rid, 10) + 1,\r\n            this.connectionHandler.bind(this, {\r\n                jid: options.jid,\r\n                password: options.password\r\n            }));\r\n    }\r\n\r\n    /**\r\n     * Resets any state/flag before starting a new connection.\r\n     * @private\r\n     */\r\n    _resetState() {\r\n        this.anonymousConnectionFailed = false;\r\n        this.connectionFailed = false;\r\n        this.lastErrorMsg = undefined;\r\n        this.disconnectInProgress = undefined;\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param jid\r\n     * @param password\r\n     */\r\n    connect(jid, password) {\r\n        if (!jid) {\r\n            const { anonymousdomain, domain } = this.options.hosts;\r\n            let configDomain = anonymousdomain || domain;\r\n\r\n            // Force authenticated domain if room is appended with '?login=true'\r\n            // or if we're joining with the token\r\n\r\n            // FIXME Do not rely on window.location because (1) React Native\r\n            // does not have a window.location by default and (2) here we cannot\r\n            // know for sure that query/search has not be stripped from\r\n            // window.location by the time the following executes.\r\n            const { location } = window;\r\n\r\n            if (anonymousdomain) {\r\n                const search = location && location.search;\r\n\r\n                if ((search && search.indexOf('login=true') !== -1)\r\n                        || this.token) {\r\n                    configDomain = domain;\r\n                }\r\n            }\r\n\r\n            // eslint-disable-next-line no-param-reassign\r\n            jid = configDomain || (location && location.hostname);\r\n        }\r\n\r\n        return this._connect(jid, password);\r\n    }\r\n\r\n    /**\r\n     * Joins or creates a muc with the provided jid, created from the passed\r\n     * in room name and muc host and onCreateResource result.\r\n     *\r\n     * @param {string} roomName - The name of the muc to join.\r\n     * @param {Object} options - Configuration for how to join the muc.\r\n     * @param {Function} [onCreateResource] - Callback to invoke when a resource\r\n     * is to be added to the jid.\r\n     * @returns {Promise} Resolves with an instance of a strophe muc.\r\n     */\r\n    createRoom(roomName, options, onCreateResource) {\r\n        // Support passing the domain in a String object as part of the room name.\r\n        const domain = roomName.domain || options.customDomain;\r\n\r\n        // There are cases (when using subdomain) where muc can hold an uppercase part\r\n        let roomjid = `${this.getRoomJid(roomName, domain)}/`;\r\n        const mucNickname = onCreateResource\r\n            ? onCreateResource(this.connection.jid, this.authenticatedUser)\r\n            : RandomUtil.randomHexString(8).toLowerCase();\r\n\r\n        logger.info(`JID ${this.connection.jid} using MUC nickname ${mucNickname}`);\r\n        roomjid += mucNickname;\r\n\r\n        return this.connection.emuc.createRoom(roomjid, null, options);\r\n    }\r\n\r\n    /**\r\n     * Returns the room JID based on the passed room name and domain.\r\n     *\r\n     * @param {string} roomName - The room name.\r\n     * @param {string} domain - The domain.\r\n     * @returns {string} - The room JID.\r\n     */\r\n    getRoomJid(roomName, domain) {\r\n        return `${roomName}@${domain ? domain : this.options.hosts.muc.toLowerCase()}`;\r\n    }\r\n\r\n    /**\r\n     * Check if a room with the passed JID is already created.\r\n     *\r\n     * @param {string} roomJid - The JID of the room.\r\n     * @returns {boolean}\r\n     */\r\n    isRoomCreated(roomName, domain) {\r\n        return this.connection.emuc.isRoomCreated(this.getRoomJid(roomName, domain));\r\n    }\r\n\r\n    /**\r\n     * Returns the jid of the participant associated with the Strophe connection.\r\n     *\r\n     * @returns {string} The jid of the participant.\r\n     */\r\n    getJid() {\r\n        return this.connection.jid;\r\n    }\r\n\r\n    /**\r\n     * Returns the logs from strophe.jingle.\r\n     * @returns {Object}\r\n     */\r\n    getJingleLog() {\r\n        const jingle = this.connection.jingle;\r\n\r\n\r\n        return jingle ? jingle.getLog() : {};\r\n    }\r\n\r\n    /**\r\n     * Returns the logs from strophe.\r\n     */\r\n    getXmppLog() {\r\n        return (this.connection.logger || {}).log || null;\r\n    }\r\n\r\n    /**\r\n     *\r\n     */\r\n    dial(...args) {\r\n        this.connection.rayo.dial(...args);\r\n    }\r\n\r\n    /**\r\n     * Pings the server.\r\n     * @param timeout how many ms before a timeout should occur.\r\n     * @returns {Promise} resolved on ping success and reject on an error or\r\n     * a timeout.\r\n     */\r\n    ping(timeout) {\r\n        return new Promise((resolve, reject) => {\r\n            this.connection.ping.ping(this.connection.pingDomain, resolve, reject, timeout);\r\n        });\r\n    }\r\n\r\n    /**\r\n     *\r\n     */\r\n    getSessions() {\r\n        return this.connection.jingle.sessions;\r\n    }\r\n\r\n    /**\r\n     * Disconnects this from the XMPP server (if this is connected).\r\n     *\r\n     * @param {Object} ev - Optionally, the event which triggered the necessity to\r\n     * disconnect from the XMPP server (e.g. beforeunload, unload).\r\n     * @returns {Promise} - Resolves when the disconnect process is finished or rejects with an error.\r\n     */\r\n    disconnect(ev) {\r\n        if (this.disconnectInProgress) {\r\n            return this.disconnectInProgress;\r\n        } else if (!this.connection) {\r\n            return Promise.resolve();\r\n        }\r\n\r\n        this.disconnectInProgress = new Promise(resolve => {\r\n            const disconnectListener = (credentials, status) => {\r\n                if (status === Strophe.Status.DISCONNECTED) {\r\n                    resolve();\r\n                    this.eventEmitter.removeListener(XMPPEvents.CONNECTION_STATUS_CHANGED, disconnectListener);\r\n                }\r\n            };\r\n\r\n            this.eventEmitter.on(XMPPEvents.CONNECTION_STATUS_CHANGED, disconnectListener);\r\n        });\r\n\r\n        this._cleanupXmppConnection(ev);\r\n\r\n        return this.disconnectInProgress;\r\n    }\r\n\r\n    /**\r\n     * The method is supposed to gracefully close the XMPP connection and the main goal is to make sure that the current\r\n     * participant will be removed from the conference XMPP MUC, so that it doesn't leave a \"ghost\" participant behind.\r\n     *\r\n     * @param {Object} ev - Optionally, the event which triggered the necessity to disconnect from the XMPP server\r\n     * (e.g. beforeunload, unload).\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _cleanupXmppConnection(ev) {\r\n        // XXX Strophe is asynchronously sending by default. Unfortunately, that means that there may not be enough time\r\n        // to send an unavailable presence or disconnect at all. Switching Strophe to synchronous sending is not much of\r\n        // an option because it may lead to a noticeable delay in navigating away from the current location. As\r\n        // a compromise, we will try to increase the chances of sending an unavailable presence and/or disconnecting\r\n        // within the short time span that we have upon unloading by invoking flush() on the connection. We flush() once\r\n        // before disconnect() in order to attempt to have its unavailable presence at the top of the send queue. We\r\n        // flush() once more after disconnect() in order to attempt to have its unavailable presence sent as soon as\r\n        // possible.\r\n        !this.connection.isUsingWebSocket && this.connection.flush();\r\n\r\n        if (!this.connection.isUsingWebSocket && ev !== null && typeof ev !== 'undefined') {\r\n            const evType = ev.type;\r\n\r\n            if (evType === 'beforeunload' || evType === 'unload') {\r\n                // XXX Whatever we said above, synchronous sending is the best (known) way to properly disconnect from\r\n                // the XMPP server. Consequently, it may be fine to have the source code and comment it in or out\r\n                // depending on whether we want to run with it for some time.\r\n                this.connection.options.sync = true;\r\n\r\n                // This is needed in some browsers where sync xhr sending is disabled by default on unload.\r\n                if (this.connection.sendUnavailableBeacon()) {\r\n\r\n                    return;\r\n                }\r\n            }\r\n        }\r\n\r\n        this.connection.disconnect();\r\n\r\n        if (this.connection.options.sync !== true) {\r\n            this.connection.flush();\r\n        }\r\n    }\r\n\r\n    /**\r\n     *\r\n     */\r\n    _initStrophePlugins() {\r\n        const iceConfig = {\r\n            jvb: { iceServers: [ ] },\r\n            p2p: { iceServers: [ ] }\r\n        };\r\n\r\n        const p2pStunServers = (this.options.p2p\r\n            && this.options.p2p.stunServers) || DEFAULT_STUN_SERVERS;\r\n\r\n        if (Array.isArray(p2pStunServers)) {\r\n            logger.info('P2P STUN servers: ', p2pStunServers);\r\n            iceConfig.p2p.iceServers = p2pStunServers;\r\n        }\r\n\r\n        if (this.options.p2p && this.options.p2p.iceTransportPolicy) {\r\n            logger.info('P2P ICE transport policy: ',\r\n                this.options.p2p.iceTransportPolicy);\r\n\r\n            iceConfig.p2p.iceTransportPolicy\r\n                = this.options.p2p.iceTransportPolicy;\r\n        }\r\n\r\n        this.connection.addConnectionPlugin('emuc', new MucConnectionPlugin(this));\r\n        this.connection.addConnectionPlugin('jingle', new JingleConnectionPlugin(this, this.eventEmitter, iceConfig));\r\n        this.connection.addConnectionPlugin('rayo', new RayoConnectionPlugin());\r\n    }\r\n\r\n    /**\r\n     * Returns details about connection failure. Shard change or is it after\r\n     * suspend.\r\n     * @returns {object} contains details about a connection failure.\r\n     * @private\r\n     */\r\n    _getConnectionFailedReasonDetails() {\r\n        const details = {};\r\n\r\n        // check for moving between shard if information is available\r\n        if (this.options.deploymentInfo\r\n            && this.options.deploymentInfo.shard\r\n            && this.connection.lastResponseHeaders) {\r\n\r\n            // split headers by line\r\n            const headersArr = this.connection.lastResponseHeaders\r\n                .trim().split(/[\\r\\n]+/);\r\n            const headers = {};\r\n\r\n            headersArr.forEach(line => {\r\n                const parts = line.split(': ');\r\n                const header = parts.shift();\r\n                const value = parts.join(': ');\r\n\r\n                headers[header] = value;\r\n            });\r\n\r\n            /* eslint-disable camelcase */\r\n            details.shard_changed\r\n                = this.options.deploymentInfo.shard\r\n                    !== headers['x-jitsi-shard'];\r\n            /* eslint-enable camelcase */\r\n        }\r\n\r\n        /* eslint-disable camelcase */\r\n        // check for possible suspend\r\n        details.suspend_time = this.connection.ping.getPingSuspendTime();\r\n        details.time_since_last_success = this.connection.getTimeSinceLastSuccess();\r\n        /* eslint-enable camelcase */\r\n\r\n        return details;\r\n    }\r\n\r\n    /**\r\n     * Notifies speaker stats component if available that we are the new\r\n     * dominant speaker in the conference.\r\n     * @param {String} roomJid - The room jid where the speaker event occurred.\r\n     * @param {boolean} silence - Whether the dominant speaker is silent or not.\r\n     */\r\n    sendDominantSpeakerEvent(roomJid, silence) {\r\n        // no speaker stats component advertised\r\n        if (!this.speakerStatsComponentAddress || !roomJid) {\r\n            return;\r\n        }\r\n\r\n        const msg = $msg({ to: this.speakerStatsComponentAddress });\r\n\r\n        msg.c('speakerstats', {\r\n            xmlns: 'http://jitsi.org/jitmeet',\r\n            room: roomJid,\r\n            silence })\r\n            .up();\r\n\r\n        this.connection.send(msg);\r\n    }\r\n\r\n    /**\r\n     * Sends face expressions to speaker stats component.\r\n     * @param {String} roomJid - The room jid where the speaker event occurred.\r\n     * @param {Object} payload - The expression to be sent to the speaker stats.\r\n     */\r\n    sendFaceExpressionEvent(roomJid, payload) {\r\n        // no speaker stats component advertised\r\n        if (!this.speakerStatsComponentAddress || !roomJid) {\r\n            return;\r\n        }\r\n\r\n        const msg = $msg({ to: this.speakerStatsComponentAddress });\r\n\r\n        msg.c('faceExpression', {\r\n            xmlns: 'http://jitsi.org/jitmeet',\r\n            room: roomJid,\r\n            expression: payload.faceExpression,\r\n            duration: payload.duration\r\n        }).up();\r\n\r\n        this.connection.send(msg);\r\n    }\r\n\r\n    /**\r\n     * Check if the given argument is a valid JSON ENDPOINT_MESSAGE string by\r\n     * parsing it and checking if it has a field called 'type'.\r\n     *\r\n     * @param {string} jsonString check if this string is a valid json string\r\n     * and contains the special structure.\r\n     * @returns {boolean, object} if given object is a valid JSON string, return\r\n     * the json object. Otherwise, returns false.\r\n     */\r\n    tryParseJSONAndVerify(jsonString) {\r\n        // ignore empty strings, like message errors\r\n        if (!jsonString) {\r\n            return false;\r\n        }\r\n\r\n        try {\r\n            const json = JSON.parse(jsonString);\r\n\r\n            // Handle non-exception-throwing cases:\r\n            // Neither JSON.parse(false) or JSON.parse(1234) throw errors,\r\n            // hence the type-checking,\r\n            // but... JSON.parse(null) returns null, and\r\n            // typeof null === \"object\",\r\n            // so we must check for that, too.\r\n            // Thankfully, null is falsey, so this suffices:\r\n            if (json && typeof json === 'object') {\r\n                const type = json[JITSI_MEET_MUC_TYPE];\r\n\r\n                if (typeof type !== 'undefined') {\r\n                    return json;\r\n                }\r\n\r\n                logger.debug('parsing valid json but does not have correct '\r\n                    + 'structure', 'topic: ', type);\r\n            }\r\n        } catch (e) {\r\n            logger.error(`Error parsing json ${jsonString}`, e);\r\n\r\n            return false;\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * A private message is received, message that is not addressed to the muc.\r\n     * We expect private message coming from plugins component if it is\r\n     * enabled and running.\r\n     *\r\n     * @param {string} msg - The message.\r\n     */\r\n    _onPrivateMessage(msg) {\r\n        const from = msg.getAttribute('from');\r\n\r\n        if (!this._components.includes(from)) {\r\n            return true;\r\n        }\r\n\r\n        const jsonMessage = $(msg).find('>json-message')\r\n            .text();\r\n        const parsedJson = this.tryParseJSONAndVerify(jsonMessage);\r\n\r\n        if (!parsedJson) {\r\n            return true;\r\n        }\r\n\r\n        if (parsedJson[JITSI_MEET_MUC_TYPE] === 'speakerstats' && parsedJson.users) {\r\n            this.eventEmitter.emit(XMPPEvents.SPEAKER_STATS_RECEIVED, parsedJson.users);\r\n        } else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'conference_duration' && parsedJson.created_timestamp) {\r\n            this.eventEmitter.emit(XMPPEvents.CONFERENCE_TIMESTAMP_RECEIVED, parsedJson.created_timestamp);\r\n        } else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'av_moderation') {\r\n            this.eventEmitter.emit(XMPPEvents.AV_MODERATION_RECEIVED, parsedJson);\r\n        } else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'breakout_rooms') {\r\n            this.eventEmitter.emit(XMPPEvents.BREAKOUT_ROOMS_EVENT, parsedJson);\r\n        } else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'room_metadata') {\r\n            this.eventEmitter.emit(XMPPEvents.ROOM_METADATA_EVENT, parsedJson);\r\n        }\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * Sends deployment info to stats if not sent already.\r\n     * We want to try sending it on failure to connect\r\n     * or when we get a sys message(from jiconop2)\r\n     * or after success or failure of disco-info\r\n     * @param force Whether to force sending without checking anything.\r\n     * @private\r\n     */\r\n    _maybeSendDeploymentInfoStat(force) {\r\n        const acceptedStatuses = [\r\n            Strophe.Status.ERROR,\r\n            Strophe.Status.CONNFAIL,\r\n            Strophe.Status.AUTHFAIL,\r\n            Strophe.Status.DISCONNECTED,\r\n            Strophe.Status.CONNTIMEOUT\r\n        ];\r\n\r\n        if (!force && !(acceptedStatuses.includes(this.connection.status) && this.sendDeploymentInfo)) {\r\n            return;\r\n        }\r\n\r\n        // Log deployment-specific information, if available. Defined outside\r\n        // the application by individual deployments\r\n        const aprops = this.options.deploymentInfo;\r\n\r\n        if (aprops && Object.keys(aprops).length > 0) {\r\n            const logObject = {};\r\n\r\n            for (const attr in aprops) {\r\n                if (aprops.hasOwnProperty(attr)) {\r\n                    logObject[attr] = aprops[attr];\r\n                }\r\n            }\r\n\r\n            // Let's push to analytics any updates that may have come from the backend\r\n            Statistics.analytics.addPermanentProperties({ ...logObject });\r\n\r\n            logObject.id = 'deployment_info';\r\n            Statistics.sendLog(JSON.stringify(logObject));\r\n        }\r\n\r\n        this.sendDeploymentInfo = false;\r\n    }\r\n}\r\n","import {\r\n    CONNECTION_DISCONNECTED,\r\n    CONNECTION_ESTABLISHED,\r\n    CONNECTION_FAILED\r\n} from './JitsiConnectionEvents';\r\nimport XMPP from './modules/xmpp/xmpp';\r\n\r\n/**\r\n * @typedef {Object} UpgradeRoleError\r\n *\r\n * @property {JitsiConnectionErrors} [connectionError] - One of\r\n * {@link JitsiConnectionErrors} which occurred when trying to connect to the\r\n * XMPP server.\r\n * @property {String} [authenticationError] - One of XMPP error conditions\r\n * returned by Jicofo on authentication attempt. See\r\n * {@link https://xmpp.org/rfcs/rfc3920.html#streams-error}.\r\n * @property {String} [message] - More details about the error.\r\n * @property {Object} [credentials] - The credentials that failed the\r\n * authentication.\r\n * @property {String} [credentials.jid] - The XMPP ID part of the credentials\r\n * that failed the authentication.\r\n * @property {string} [credentials.password] - The password part of the\r\n * credentials that failed the authentication.\r\n *\r\n * NOTE If neither one of the errors is present, then the operation has been\r\n * canceled.\r\n */\r\n\r\n/* eslint-disable no-invalid-this */\r\n\r\n/**\r\n * Connects to the XMPP server using the specified credentials and contacts\r\n * Jicofo in order to obtain a session ID (which is then stored in the local\r\n * storage). The user's role of the parent conference will be upgraded to\r\n * moderator (by Jicofo). It's also used to join the conference when starting\r\n * from anonymous domain and only authenticated users are allowed to create new\r\n * rooms.\r\n *\r\n * @param {Object} options\r\n * @param {string} options.id - XMPP user's ID to log in. For example,\r\n * user@xmpp-server.com.\r\n * @param {string} options.password - XMPP user's password to log in with.\r\n * @param {Function} [options.onLoginSuccessful] - Callback called when logging\r\n * into the XMPP server was successful. The next step will be to obtain a new\r\n * session ID from Jicofo and join the MUC using it which will effectively\r\n * upgrade the user's role to moderator.\r\n * @returns {Object} A <tt>thenable</tt> which (1) settles when the process of\r\n * authenticating and upgrading the role of the specified XMPP user finishes and\r\n * (2) has a <tt>cancel</tt> method that allows the caller to interrupt the\r\n * process. If the process finishes successfully, the session ID has been stored\r\n * in the settings and the <tt>thenable</tt> is resolved. If the process\r\n * finishes with failure, the <tt>thenable</tt> is rejected with reason of type\r\n * {@link UpgradeRoleError} which will have either <tt>connectionError</tt> or\r\n * <tt>authenticationError</tt> property set depending on which of the steps has\r\n * failed. If <tt>cancel</tt> is called before the process finishes, then the\r\n * thenable will be rejected with an empty object (i.e. no error property will\r\n * be set on the rejection reason).\r\n */\r\nexport default function authenticateAndUpgradeRole({\r\n    // 1. Log the specified XMPP user in.\r\n    id,\r\n    password,\r\n    onCreateResource,\r\n\r\n    // 2. Let the API client/consumer know as soon as the XMPP user has been\r\n    //    successfully logged in.\r\n    onLoginSuccessful\r\n}) {\r\n    let canceled = false;\r\n    let rejectPromise;\r\n    let xmpp = new XMPP(this.connection.options);\r\n\r\n    const process = new Promise((resolve, reject) => {\r\n        // The process is represented by a Thenable with a cancel method. The\r\n        // Thenable is implemented using Promise and the cancel using the\r\n        // Promise's reject function.\r\n        rejectPromise = reject;\r\n\r\n\r\n        xmpp.addListener(\r\n            CONNECTION_DISCONNECTED,\r\n            () => {\r\n                xmpp = undefined;\r\n            });\r\n        xmpp.addListener(\r\n            CONNECTION_ESTABLISHED,\r\n            () => {\r\n                if (canceled) {\r\n                    return;\r\n                }\r\n\r\n                // Let the caller know that the XMPP login was successful.\r\n                onLoginSuccessful && onLoginSuccessful();\r\n\r\n                // Now authenticate with Jicofo and get a new session ID.\r\n                const room = xmpp.createRoom(\r\n                    this.options.name,\r\n                    this.options.config,\r\n                    onCreateResource\r\n                );\r\n\r\n                room.moderator.authenticate()\r\n                    .then(() => {\r\n                        xmpp && xmpp.disconnect();\r\n\r\n                        if (canceled) {\r\n                            return;\r\n                        }\r\n\r\n                        // At this point we should have the new session ID\r\n                        // stored in the settings. Send a new conference IQ.\r\n                        this.room.moderator.allocateConferenceFocus();\r\n\r\n                        resolve();\r\n                    })\r\n                    .catch(({ error, message }) => {\r\n                        xmpp.disconnect();\r\n\r\n                        reject({\r\n                            authenticationError: error,\r\n                            message\r\n                        });\r\n                    });\r\n            });\r\n        xmpp.addListener(\r\n            CONNECTION_FAILED,\r\n            (connectionError, message, credentials) => {\r\n                reject({\r\n                    connectionError,\r\n                    credentials,\r\n                    message\r\n                });\r\n                xmpp = undefined;\r\n            });\r\n\r\n        canceled || xmpp.connect(id, password);\r\n    });\r\n\r\n    /**\r\n     * Cancels the process, if it's in progress, of authenticating and upgrading\r\n     * the role of the local participant/user.\r\n     *\r\n     * @public\r\n     * @returns {void}\r\n     */\r\n    process.cancel = () => {\r\n        canceled = true;\r\n        rejectPromise({});\r\n        xmpp && xmpp.disconnect();\r\n    };\r\n\r\n    return process;\r\n}\r\n\r\n/* eslint-enable no-invalid-this */\r\n","\r\nimport { getLogger } from '@jitsi/logger';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\nimport CodecMimeType from '../../service/RTC/CodecMimeType';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport browser from '../browser';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * This class handles the codec selection mechanism for the conference based on the config.js settings.\r\n * The preferred codec is selected based on the settings and the list of codecs supported by the browser.\r\n * The preferred codec is published in presence which is then used by the other endpoints in the\r\n * conference to pick a supported codec at join time and when the call transitions between p2p and jvb\r\n * connections.\r\n */\r\nexport class CodecSelection {\r\n    /**\r\n     * Creates a new instance for a given conference.\r\n     *\r\n     * @param {JitsiConference} conference the conference instance\r\n     * @param {*} options\r\n     * @param {string} options.disabledCodec the codec that needs to be disabled.\r\n     * @param {boolean} options.enforcePreferredCodec whether codec preference has to be\r\n     * enforced even when an endpoints that doesn't support the preferred codec joins the call.\r\n     * Falling back to the standard codec will be skipped when this option is true, endpoints\r\n     * that do not support the preferred codec may not be able to encode/decode video when this happens.\r\n     * @param {string} options.jvbCodec the codec that is preferred on jvb connection.\r\n     * @param {string} options.p2pCodec the codec that is preferred on p2p connection.\r\n     */\r\n    constructor(conference, options) {\r\n        this.conference = conference;\r\n        this.options = options;\r\n\r\n        // VP8 cannot be disabled and it will be the default codec when no preference is set.\r\n        this.disabledCodec = options.disabledCodec === CodecMimeType.VP8\r\n            ? undefined\r\n            : this._getCodecMimeType(options.disabledCodec);\r\n\r\n        // Check if the codec values passed are valid.\r\n        const jvbCodec = this._getCodecMimeType(options.jvbCodec);\r\n        const p2pCodec = this._getCodecMimeType(options.p2pCodec);\r\n\r\n        this.jvbPreferredCodec = jvbCodec && this._isCodecSupported(jvbCodec) ? jvbCodec : CodecMimeType.VP8;\r\n        this.p2pPreferredCodec = p2pCodec && this._isCodecSupported(p2pCodec) ? p2pCodec : CodecMimeType.VP8;\r\n        logger.debug(`Codec preferences for the conference are JVB: ${this.jvbPreferredCodec},\r\n            P2P: ${this.p2pPreferredCodec}`);\r\n\r\n        if (this.jvbPreferredCodec === CodecMimeType.VP9 && !browser.supportsVP9()) {\r\n            this.jvbPreferredCodec = CodecMimeType.VP8;\r\n        }\r\n\r\n        this.conference.on(\r\n            JitsiConferenceEvents.USER_JOINED,\r\n            () => this._selectPreferredCodec());\r\n        this.conference.on(\r\n            JitsiConferenceEvents.USER_LEFT,\r\n            () => this._selectPreferredCodec());\r\n        this.conference.on(\r\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\r\n            session => this._onMediaSessionStarted(session));\r\n    }\r\n\r\n    /**\r\n     * Checks if a given string is a valid video codec mime type.\r\n     *\r\n     * @param {string} codec the codec string that needs to be validated.\r\n     * @returns {CodecMimeType|null} mime type if valid, null otherwise.\r\n     * @private\r\n     */\r\n    _getCodecMimeType(codec) {\r\n        if (typeof codec === 'string') {\r\n            return Object.values(CodecMimeType).find(value => value === codec.toLowerCase());\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * Checks if the given codec is supported by the browser.\r\n     *\r\n     * @param {CodecMimeType} preferredCodec codec to be checked.\r\n     * @returns {boolean} true if the given codec is supported, false otherwise.\r\n     * @private\r\n     */\r\n    _isCodecSupported(preferredCodec) {\r\n        // Skip the check on FF and RN because they do not support the getCapabilities API.\r\n        // It is safe to assume both of them support all the codecs supported by Chrome.\r\n        if (browser.isFirefox() || browser.isReactNative()) {\r\n            return true;\r\n        }\r\n\r\n        return window.RTCRtpReceiver\r\n            && window.RTCRtpReceiver.getCapabilities\r\n            && window.RTCRtpReceiver.getCapabilities('video').codecs\r\n            .some(codec => codec.mimeType.toLowerCase() === `video/${preferredCodec}`);\r\n    }\r\n\r\n    /**\r\n     * Handles the {@link JitsiConferenceEvents._MEDIA_SESSION_STARTED} event. Codecs need to be\r\n     * configured on the media session that is newly created.\r\n     *\r\n     * @param {JingleSessionPC} mediaSession media session that started.\r\n     * @returns {void}\r\n     * @private\r\n     */\r\n    _onMediaSessionStarted(mediaSession) {\r\n        const preferredCodec = mediaSession.isP2P ? this.p2pPreferredCodec : this.jvbPreferredCodec;\r\n        const disabledCodec = this.disabledCodec && this._isCodecSupported(this.disabledCodec)\r\n            ? this.disabledCodec\r\n            : null;\r\n\r\n        this._selectPreferredCodec(mediaSession, preferredCodec, disabledCodec);\r\n    }\r\n\r\n    /**\r\n     * Sets the codec on the media session based on the preferred codec setting and the supported codecs\r\n     * published by the remote participants in their presence.\r\n     *\r\n     * @param {JingleSessionPC} mediaSession session for which the codec selection has to be made.\r\n     * @param {CodecMimeType} preferredCodec preferred codec.\r\n     * @param {CodecMimeType} disabledCodec codec that needs to be disabled.\r\n     */\r\n    _selectPreferredCodec(mediaSession = null, preferredCodec = null, disabledCodec = null) {\r\n        const session = mediaSession ? mediaSession : this.conference.jvbJingleSession;\r\n        const currentCodec = preferredCodec ? preferredCodec : this.jvbPreferredCodec;\r\n        let selectedCodec = currentCodec;\r\n\r\n        if (session && !session.isP2P && !this.options.enforcePreferredCodec) {\r\n            const remoteParticipants = this.conference.getParticipants().map(participant => participant.getId());\r\n\r\n            for (const remote of remoteParticipants) {\r\n                const peerMediaInfo = session._signalingLayer.getPeerMediaInfo(remote, MediaType.VIDEO);\r\n                const peerCodec = peerMediaInfo?.codecType;\r\n\r\n                if (peerCodec\r\n                    && peerCodec !== currentCodec\r\n                    && (peerCodec !== CodecMimeType.VP9 || browser.supportsVP9())) {\r\n                    selectedCodec = peerCodec;\r\n                }\r\n            }\r\n        }\r\n        session && session.setVideoCodecs(selectedCodec, disabledCodec);\r\n    }\r\n\r\n    /**\r\n     * Returns the preferred codec for the conference. The preferred codec for the JVB media session\r\n     * is the one that gets published in presence and a comparision is made whenever a participant joins\r\n     * or leaves the call.\r\n     *\r\n     * @returns {CodecMimeType} preferred codec.\r\n     */\r\n    getPreferredCodec() {\r\n        return this.jvbPreferredCodec;\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport RTCEvents from '../../service/RTC/RTCEvents';\r\nimport { createBridgeChannelClosedEvent } from '../../service/statistics/AnalyticsEvents';\r\nimport Statistics from '../statistics/statistics';\r\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Handles a WebRTC RTCPeerConnection or a WebSocket instance to communicate\r\n * with the videobridge.\r\n */\r\nexport default class BridgeChannel {\r\n    /**\r\n     * Binds \"ondatachannel\" event listener on the given RTCPeerConnection\r\n     * instance, or creates a WebSocket connection with the videobridge.\r\n     * At least one of both, peerconnection or wsUrl parameters, must be\r\n     * given.\r\n     * @param {RTCPeerConnection} [peerconnection] WebRTC peer connection\r\n     * instance.\r\n     * @param {string} [wsUrl] WebSocket URL.\r\n     * @param {EventEmitter} emitter the EventEmitter instance to use for event emission.\r\n     */\r\n    constructor(peerconnection, wsUrl, emitter) {\r\n        if (!peerconnection && !wsUrl) {\r\n            throw new TypeError('At least peerconnection or wsUrl must be given');\r\n        } else if (peerconnection && wsUrl) {\r\n            throw new TypeError('Just one of peerconnection or wsUrl must be given');\r\n        }\r\n\r\n        if (peerconnection) {\r\n            logger.debug('constructor() with peerconnection');\r\n        } else {\r\n            logger.debug(`constructor() with wsUrl:\"${wsUrl}\"`);\r\n        }\r\n\r\n        // The underlying WebRTC RTCDataChannel or WebSocket instance.\r\n        // @type {RTCDataChannel|WebSocket}\r\n        this._channel = null;\r\n\r\n        // @type {EventEmitter}\r\n        this._eventEmitter = emitter;\r\n\r\n        // Whether a RTCDataChannel or WebSocket is internally used.\r\n        // @type {string} \"datachannel\" / \"websocket\"\r\n        this._mode = null;\r\n\r\n        // Indicates whether the connection retries are enabled or not.\r\n        this._areRetriesEnabled = false;\r\n\r\n        // Indicates whether the connection was closed from the client or not.\r\n        this._closedFromClient = false;\r\n\r\n        // If a RTCPeerConnection is given, listen for new RTCDataChannel\r\n        // event.\r\n        if (peerconnection) {\r\n            const datachannel\r\n                = peerconnection.createDataChannel(\r\n                    'JVB data channel', {\r\n                        protocol: 'http://jitsi.org/protocols/colibri'\r\n                    });\r\n\r\n            // Handle the RTCDataChannel.\r\n            this._handleChannel(datachannel);\r\n            this._mode = 'datachannel';\r\n\r\n        // Otherwise create a WebSocket connection.\r\n        } else if (wsUrl) {\r\n            this._areRetriesEnabled = true;\r\n            this._wsUrl = wsUrl;\r\n            this._initWebSocket();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Initializes the web socket channel.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    _initWebSocket() {\r\n        // Create a WebSocket instance.\r\n        const ws = new WebSocket(this._wsUrl);\r\n\r\n        // Handle the WebSocket.\r\n        this._handleChannel(ws);\r\n        this._mode = 'websocket';\r\n    }\r\n\r\n    /**\r\n     * Starts the websocket connection retries.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    _startConnectionRetries() {\r\n        let timeoutS = 1;\r\n\r\n        const reload = () => {\r\n            if (this.isOpen()) {\r\n                return;\r\n            }\r\n            this._initWebSocket(this._wsUrl);\r\n            timeoutS = Math.min(timeoutS * 2, 60);\r\n            this._retryTimeout = setTimeout(reload, timeoutS * 1000);\r\n        };\r\n\r\n        this._retryTimeout = setTimeout(reload, timeoutS * 1000);\r\n    }\r\n\r\n    /**\r\n     * Stops the websocket connection retries.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    _stopConnectionRetries() {\r\n        if (this._retryTimeout) {\r\n            clearTimeout(this._retryTimeout);\r\n            this._retryTimeout = undefined;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Retries to establish the websocket connection after the connection was closed by the server.\r\n     *\r\n     * @param {CloseEvent} closeEvent - The close event that triggered the retries.\r\n     * @returns {void}\r\n     */\r\n    _retryWebSocketConnection(closeEvent) {\r\n        if (!this._areRetriesEnabled) {\r\n            return;\r\n        }\r\n        const { code, reason } = closeEvent;\r\n\r\n        Statistics.sendAnalytics(createBridgeChannelClosedEvent(code, reason));\r\n        this._areRetriesEnabled = false;\r\n        this._eventEmitter.once(RTCEvents.DATA_CHANNEL_OPEN, () => {\r\n            this._stopConnectionRetries();\r\n            this._areRetriesEnabled = true;\r\n        });\r\n        this._startConnectionRetries();\r\n    }\r\n\r\n    /**\r\n     * The channel mode.\r\n     * @return {string} \"datachannel\" or \"websocket\" (or null if not yet set).\r\n     */\r\n    get mode() {\r\n        return this._mode;\r\n    }\r\n\r\n    /**\r\n     * Closes the currently opened channel.\r\n     */\r\n    close() {\r\n        this._closedFromClient = true;\r\n        this._stopConnectionRetries();\r\n        this._areRetriesEnabled = false;\r\n        if (this._channel) {\r\n            try {\r\n                this._channel.close();\r\n            } catch (error) {} // eslint-disable-line no-empty\r\n\r\n            this._channel = null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Whether there is an underlying RTCDataChannel or WebSocket and it's\r\n     * open.\r\n     * @return {boolean}\r\n     */\r\n    isOpen() {\r\n        return this._channel && (this._channel.readyState === 'open'\r\n            || this._channel.readyState === WebSocket.OPEN);\r\n    }\r\n\r\n    /**\r\n     * Sends local stats via the bridge channel.\r\n     * @param {Object} payload The payload of the message.\r\n     * @throws NetworkError/InvalidStateError/Error if the operation fails or if there is no data channel created.\r\n     */\r\n    sendEndpointStatsMessage(payload) {\r\n        this._send({\r\n            colibriClass: 'EndpointStats',\r\n            ...payload\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Sends message via the channel.\r\n     * @param {string} to The id of the endpoint that should receive the\r\n     * message. If \"\" the message will be sent to all participants.\r\n     * @param  {object} payload The payload of the message.\r\n     * @throws NetworkError or InvalidStateError from RTCDataChannel#send (@see\r\n     * {@link https://developer.mozilla.org/docs/Web/API/RTCDataChannel/send})\r\n     * or from WebSocket#send or Error with \"No opened channel\" message.\r\n     */\r\n    sendMessage(to, payload) {\r\n        this._send({\r\n            colibriClass: 'EndpointMessage',\r\n            msgPayload: payload,\r\n            to\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Sends a \"lastN value changed\" message via the channel.\r\n     * @param {number} value The new value for lastN. -1 means unlimited.\r\n     */\r\n    sendSetLastNMessage(value) {\r\n        logger.log(`Sending lastN=${value}.`);\r\n\r\n        this._send({\r\n            colibriClass: 'LastNChangedEvent',\r\n            lastN: value\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Sends a \"selected endpoints changed\" message via the channel.\r\n     *\r\n     * @param {Array<string>} endpointIds - The ids of the selected endpoints.\r\n     * @throws NetworkError or InvalidStateError from RTCDataChannel#send (@see\r\n     * {@link https://developer.mozilla.org/docs/Web/API/RTCDataChannel/send})\r\n     * or from WebSocket#send or Error with \"No opened channel\" message.\r\n     */\r\n    sendSelectedEndpointsMessage(endpointIds) {\r\n        logger.log(`Sending selected endpoints: ${endpointIds}.`);\r\n\r\n        this._send({\r\n            colibriClass: 'SelectedEndpointsChangedEvent',\r\n            selectedEndpoints: endpointIds\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Sends a \"receiver video constraint\" message via the channel.\r\n     * @param {Number} maxFrameHeightPixels the maximum frame height,\r\n     * in pixels, this receiver is willing to receive\r\n     */\r\n    sendReceiverVideoConstraintMessage(maxFrameHeightPixels) {\r\n        logger.log(`Sending ReceiverVideoConstraint with maxFrameHeight=${maxFrameHeightPixels}px`);\r\n        this._send({\r\n            colibriClass: 'ReceiverVideoConstraint',\r\n            maxFrameHeight: maxFrameHeightPixels\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Sends a 'ReceiverVideoConstraints' message via the bridge channel.\r\n     *\r\n     * @param {ReceiverVideoConstraints} constraints video constraints.\r\n     */\r\n    sendNewReceiverVideoConstraintsMessage(constraints) {\r\n        logger.log(`Sending ReceiverVideoConstraints with ${JSON.stringify(constraints)}`);\r\n        this._send({\r\n            colibriClass: 'ReceiverVideoConstraints',\r\n            ...constraints\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Sends a 'VideoTypeMessage' message via the bridge channel.\r\n     *\r\n     * @param {string} videoType 'camera', 'desktop' or 'none'.\r\n     * @deprecated to be replaced with sendSourceVideoTypeMessage\r\n     */\r\n    sendVideoTypeMessage(videoType) {\r\n        logger.debug(`Sending VideoTypeMessage with video type as ${videoType}`);\r\n        this._send({\r\n            colibriClass: 'VideoTypeMessage',\r\n            videoType\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Sends a 'VideoTypeMessage' message via the bridge channel.\r\n     *\r\n     * @param {BridgeVideoType} videoType - the video type.\r\n     * @param {SourceName} sourceName - the source name of the video track.\r\n     * @returns {void}\r\n     */\r\n    sendSourceVideoTypeMessage(sourceName, videoType) {\r\n        logger.info(`Sending SourceVideoTypeMessage with video type ${sourceName}: ${videoType}`);\r\n        this._send({\r\n            colibriClass: 'SourceVideoTypeMessage',\r\n            sourceName,\r\n            videoType\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Set events on the given RTCDataChannel or WebSocket instance.\r\n     */\r\n    _handleChannel(channel) {\r\n        const emitter = this._eventEmitter;\r\n\r\n        channel.onopen = () => {\r\n            logger.info(`${this._mode} channel opened`);\r\n\r\n            // Code sample for sending string and/or binary data.\r\n            // Sends string message to the bridge:\r\n            //     channel.send(\"Hello bridge!\");\r\n            // Sends 12 bytes binary message to the bridge:\r\n            //     channel.send(new ArrayBuffer(12));\r\n\r\n            emitter.emit(RTCEvents.DATA_CHANNEL_OPEN);\r\n        };\r\n\r\n        channel.onerror = event => {\r\n            // WS error events contain no information about the failure (this is available in the onclose event) and\r\n            // the event references the WS object itself, which causes hangs on mobile.\r\n            if (this._mode !== 'websocket') {\r\n                logger.error(`Channel error: ${event.message}`);\r\n            }\r\n        };\r\n\r\n        channel.onmessage = ({ data }) => {\r\n            // JSON object.\r\n            let obj;\r\n\r\n            try {\r\n                obj = JSON.parse(data);\r\n            } catch (error) {\r\n                GlobalOnErrorHandler.callErrorHandler(error);\r\n                logger.error('Failed to parse channel message as JSON: ', data, error);\r\n\r\n                return;\r\n            }\r\n\r\n            const colibriClass = obj.colibriClass;\r\n\r\n            switch (colibriClass) {\r\n            case 'DominantSpeakerEndpointChangeEvent': {\r\n                const { dominantSpeakerEndpoint, previousSpeakers = [], silence } = obj;\r\n\r\n                logger.debug(`Dominant speaker: ${dominantSpeakerEndpoint}, previous speakers: ${previousSpeakers}`);\r\n                emitter.emit(RTCEvents.DOMINANT_SPEAKER_CHANGED, dominantSpeakerEndpoint, previousSpeakers, silence);\r\n                break;\r\n            }\r\n            case 'EndpointConnectivityStatusChangeEvent': {\r\n                const endpoint = obj.endpoint;\r\n                const isActive = obj.active === 'true';\r\n\r\n                logger.info(`Endpoint connection status changed: ${endpoint} active=${isActive}`);\r\n                emitter.emit(RTCEvents.ENDPOINT_CONN_STATUS_CHANGED, endpoint, isActive);\r\n\r\n                break;\r\n            }\r\n            case 'EndpointMessage': {\r\n                emitter.emit(RTCEvents.ENDPOINT_MESSAGE_RECEIVED, obj.from, obj.msgPayload);\r\n\r\n                break;\r\n            }\r\n            case 'EndpointStats': {\r\n                emitter.emit(RTCEvents.ENDPOINT_STATS_RECEIVED, obj.from, obj);\r\n\r\n                break;\r\n            }\r\n            case 'ForwardedSources': {\r\n                const forwardedSources = obj.forwardedSources;\r\n\r\n                logger.info(`New forwarded sources: ${forwardedSources}`);\r\n                emitter.emit(RTCEvents.FORWARDED_SOURCES_CHANGED, forwardedSources);\r\n\r\n                break;\r\n            }\r\n            case 'SenderVideoConstraints': {\r\n                const videoConstraints = obj.videoConstraints;\r\n\r\n                if (videoConstraints) {\r\n                    logger.info(`SenderVideoConstraints: ${JSON.stringify(videoConstraints)}`);\r\n                    emitter.emit(RTCEvents.SENDER_VIDEO_CONSTRAINTS_CHANGED, videoConstraints);\r\n                }\r\n                break;\r\n            }\r\n            case 'SenderSourceConstraints': {\r\n                if (typeof obj.sourceName === 'string' && typeof obj.maxHeight === 'number') {\r\n                    logger.info(`SenderSourceConstraints: ${obj.sourceName} - ${obj.maxHeight}`);\r\n                    emitter.emit(RTCEvents.SENDER_VIDEO_CONSTRAINTS_CHANGED, obj);\r\n                } else {\r\n                    logger.error(`Invalid SenderSourceConstraints: ${obj.sourceName} - ${obj.maxHeight}`);\r\n                }\r\n                break;\r\n            }\r\n            case 'ServerHello': {\r\n                logger.info(`Received ServerHello, version=${obj.version}.`);\r\n                break;\r\n            }\r\n            case 'VideoSourcesMap': {\r\n                logger.info(`Received VideoSourcesMap: ${JSON.stringify(obj.mappedSources)}`);\r\n                emitter.emit(RTCEvents.VIDEO_SSRCS_REMAPPED, obj);\r\n                break;\r\n            }\r\n            case 'AudioSourcesMap': {\r\n                logger.info(`Received AudioSourcesMap: ${JSON.stringify(obj.mappedSources)}`);\r\n                emitter.emit(RTCEvents.AUDIO_SSRCS_REMAPPED, obj);\r\n                break;\r\n            }\r\n            default: {\r\n                logger.debug('Channel JSON-formatted message: ', obj);\r\n\r\n                // The received message appears to be appropriately formatted\r\n                // (i.e. is a JSON object which assigns a value to the\r\n                // mandatory property colibriClass) so don't just swallow it,\r\n                // expose it to public consumption.\r\n                emitter.emit(`rtc.datachannel.${colibriClass}`, obj);\r\n            }\r\n            }\r\n        };\r\n\r\n        channel.onclose = event => {\r\n            logger.info(`Channel closed by ${this._closedFromClient ? 'client' : 'server'}`);\r\n\r\n            if (this._mode === 'websocket') {\r\n                if (!this._closedFromClient) {\r\n                    logger.error(`Channel closed: ${event.code} ${event.reason}`);\r\n                    this._retryWebSocketConnection(event);\r\n                }\r\n            }\r\n\r\n            // Remove the channel.\r\n            this._channel = null;\r\n        };\r\n\r\n        // Store the channel.\r\n        this._channel = channel;\r\n    }\r\n\r\n    /**\r\n     * Sends passed object via the channel.\r\n     * @param {object} jsonObject The object that will be sent.\r\n     * @throws NetworkError or InvalidStateError from RTCDataChannel#send (@see\r\n     * {@link https://developer.mozilla.org/docs/Web/API/RTCDataChannel/send})\r\n     * or from WebSocket#send or Error with \"No opened channel\" message.\r\n     */\r\n    _send(jsonObject) {\r\n        const channel = this._channel;\r\n\r\n        if (!this.isOpen()) {\r\n            logger.error('Bridge Channel send: no opened channel.');\r\n            throw new Error('No opened channel');\r\n        }\r\n\r\n        channel.send(JSON.stringify(jsonObject));\r\n    }\r\n}\r\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';\r\nimport EventEmitter from 'events';\r\nimport clonedeep from 'lodash.clonedeep';\r\nimport 'webrtc-adapter';\r\n\r\nimport JitsiTrackError from '../../JitsiTrackError';\r\nimport * as JitsiTrackErrors from '../../JitsiTrackErrors';\r\nimport CameraFacingMode from '../../service/RTC/CameraFacingMode';\r\nimport RTCEvents from '../../service/RTC/RTCEvents';\r\nimport Resolutions from '../../service/RTC/Resolutions';\r\nimport { VideoType } from '../../service/RTC/VideoType';\r\nimport { AVAILABLE_DEVICE } from '../../service/statistics/AnalyticsEvents';\r\nimport browser from '../browser';\r\nimport Statistics from '../statistics/statistics';\r\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\r\nimport Listenable from '../util/Listenable';\r\n\r\nimport screenObtainer from './ScreenObtainer';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\nconst eventEmitter = new EventEmitter();\r\n\r\nconst AVAILABLE_DEVICES_POLL_INTERVAL_TIME = 3000; // ms\r\n\r\n/**\r\n * Default MediaStreamConstraints to use for calls to getUserMedia.\r\n *\r\n * @private\r\n */\r\nconst DEFAULT_CONSTRAINTS = {\r\n    video: {\r\n        height: {\r\n            ideal: 720,\r\n            max: 720,\r\n            min: 180\r\n        },\r\n        width: {\r\n            ideal: 1280,\r\n            max: 1280,\r\n            min: 320\r\n        }\r\n    }\r\n};\r\n\r\n// Currently audio output device change is supported only in Chrome and\r\n// default output always has 'default' device ID\r\nlet audioOutputDeviceId = 'default'; // default device\r\n// whether user has explicitly set a device to use\r\nlet audioOutputChanged = false;\r\n\r\n// Disables all audio processing\r\nlet disableAP = false;\r\n\r\n// Disables Acoustic Echo Cancellation\r\nlet disableAEC = false;\r\n\r\n// Disables Noise Suppression\r\nlet disableNS = false;\r\n\r\n// Disables Automatic Gain Control\r\nlet disableAGC = false;\r\n\r\n// Enables stereo.\r\nlet stereo = null;\r\n\r\nconst featureDetectionAudioEl = document.createElement('audio');\r\nconst isAudioOutputDeviceChangeAvailable\r\n    = typeof featureDetectionAudioEl.setSinkId !== 'undefined';\r\n\r\nlet availableDevices = [];\r\nlet availableDevicesPollTimer;\r\n\r\n/**\r\n * An empty function.\r\n */\r\nfunction emptyFuncton() {\r\n    // no-op\r\n}\r\n\r\n/**\r\n * Creates a constraints object to be passed into a call to getUserMedia.\r\n *\r\n * @param {Array} um - An array of user media types to get. The accepted types are \"video\", \"audio\", and \"desktop.\"\r\n * @param {Object} options - Various values to be added to the constraints.\r\n * @param {string} options.cameraDeviceId - The device id for the video capture device to get video from.\r\n * @param {Object} options.constraints - Default constraints object to use as a base for the returned constraints.\r\n * @param {Object} options.desktopStream - The desktop source id from which to capture a desktop sharing video.\r\n * @param {string} options.facingMode - Which direction the camera is pointing to (applicable on mobile)\r\n * @param {string} options.micDeviceId - The device id for the audio capture device to get audio from.\r\n * @private\r\n * @returns {Object}\r\n */\r\nfunction getConstraints(um = [], options = {}) {\r\n    // Create a deep copy of the constraints to avoid any modification of\r\n    // the passed in constraints object.\r\n    const constraints = clonedeep(options.constraints || DEFAULT_CONSTRAINTS);\r\n\r\n    if (um.indexOf('video') >= 0) {\r\n        // The \"resolution\" option is a shortcut and takes precendence.\r\n        if (Resolutions[options.resolution]) {\r\n            const r = Resolutions[options.resolution];\r\n\r\n            constraints.video.height = { ideal: r.height };\r\n            constraints.video.width = { ideal: r.width };\r\n        }\r\n\r\n        if (!constraints.video) {\r\n            constraints.video = {};\r\n        }\r\n\r\n        // Override the constraints on Safari because of the following webkit bug.\r\n        // https://bugs.webkit.org/show_bug.cgi?id=210932\r\n        // Camera doesn't start on older macOS versions if min/max constraints are specified.\r\n        // TODO: remove this hack when the bug fix is available on Mojave, Sierra and High Sierra.\r\n        if (browser.isWebKitBased()) {\r\n            if (constraints.video.height && constraints.video.height.ideal) {\r\n                constraints.video.height = { ideal: constraints.video.height.ideal };\r\n            } else {\r\n                logger.warn('Ideal camera height missing, camera may not start properly');\r\n            }\r\n            if (constraints.video.width && constraints.video.width.ideal) {\r\n                constraints.video.width = { ideal: constraints.video.width.ideal };\r\n            } else {\r\n                logger.warn('Ideal camera width missing, camera may not start properly');\r\n            }\r\n        }\r\n        if (options.cameraDeviceId) {\r\n            constraints.video.deviceId = options.cameraDeviceId;\r\n        } else {\r\n            const facingMode = options.facingMode || CameraFacingMode.USER;\r\n\r\n            constraints.video.facingMode = facingMode;\r\n        }\r\n    } else {\r\n        constraints.video = false;\r\n    }\r\n\r\n    if (um.indexOf('audio') >= 0) {\r\n        if (!constraints.audio || typeof constraints.audio === 'boolean') {\r\n            constraints.audio = {};\r\n        }\r\n\r\n        constraints.audio = {\r\n            autoGainControl: !disableAGC && !disableAP,\r\n            deviceId: { exact: options.micDeviceId },\r\n            echoCancellation: !disableAEC && !disableAP,\r\n            noiseSuppression: !disableNS && !disableAP\r\n        };\r\n\r\n        if (stereo) {\r\n            Object.assign(constraints.audio, { channelCount: 2 });\r\n        }\r\n    } else {\r\n        constraints.audio = false;\r\n    }\r\n\r\n    return constraints;\r\n}\r\n\r\n/**\r\n * Updates the granted permissions based on the options we requested and the\r\n * streams we received.\r\n * @param um the options we requested to getUserMedia.\r\n * @param stream the stream we received from calling getUserMedia.\r\n */\r\nfunction updateGrantedPermissions(um, stream) {\r\n    const audioTracksReceived\r\n        = Boolean(stream) && stream.getAudioTracks().length > 0;\r\n    const videoTracksReceived\r\n        = Boolean(stream) && stream.getVideoTracks().length > 0;\r\n    const grantedPermissions = {};\r\n\r\n    if (um.indexOf('video') !== -1) {\r\n        grantedPermissions.video = videoTracksReceived;\r\n    }\r\n    if (um.indexOf('audio') !== -1) {\r\n        grantedPermissions.audio = audioTracksReceived;\r\n    }\r\n\r\n    eventEmitter.emit(RTCEvents.PERMISSIONS_CHANGED, grantedPermissions);\r\n}\r\n\r\n/**\r\n * Checks if new list of available media devices differs from previous one.\r\n * @param {MediaDeviceInfo[]} newDevices - list of new devices.\r\n * @returns {boolean} - true if list is different, false otherwise.\r\n */\r\nfunction compareAvailableMediaDevices(newDevices) {\r\n    if (newDevices.length !== availableDevices.length) {\r\n        return true;\r\n    }\r\n\r\n    /* eslint-disable newline-per-chained-call */\r\n\r\n    return (\r\n        newDevices.map(mediaDeviceInfoToJSON).sort().join('')\r\n            !== availableDevices\r\n                .map(mediaDeviceInfoToJSON).sort().join(''));\r\n\r\n    /* eslint-enable newline-per-chained-call */\r\n\r\n    /**\r\n     *\r\n     * @param info\r\n     */\r\n    function mediaDeviceInfoToJSON(info) {\r\n        return JSON.stringify({\r\n            kind: info.kind,\r\n            deviceId: info.deviceId,\r\n            groupId: info.groupId,\r\n            label: info.label,\r\n            facing: info.facing\r\n        });\r\n    }\r\n}\r\n\r\n/**\r\n * Sends analytics event with the passed device list.\r\n *\r\n * @param {Array<MediaDeviceInfo>} deviceList - List with info about the\r\n * available devices.\r\n * @returns {void}\r\n */\r\nfunction sendDeviceListToAnalytics(deviceList) {\r\n    const audioInputDeviceCount\r\n        = deviceList.filter(d => d.kind === 'audioinput').length;\r\n    const audioOutputDeviceCount\r\n        = deviceList.filter(d => d.kind === 'audiooutput').length;\r\n    const videoInputDeviceCount\r\n        = deviceList.filter(d => d.kind === 'videoinput').length;\r\n    const videoOutputDeviceCount\r\n        = deviceList.filter(d => d.kind === 'videooutput').length;\r\n\r\n    deviceList.forEach(device => {\r\n        const attributes = {\r\n            'audio_input_device_count': audioInputDeviceCount,\r\n            'audio_output_device_count': audioOutputDeviceCount,\r\n            'video_input_device_count': videoInputDeviceCount,\r\n            'video_output_device_count': videoOutputDeviceCount,\r\n            'device_id': device.deviceId,\r\n            'device_group_id': device.groupId,\r\n            'device_kind': device.kind,\r\n            'device_label': device.label\r\n        };\r\n\r\n        Statistics.sendAnalytics(AVAILABLE_DEVICE, attributes);\r\n    });\r\n}\r\n\r\n\r\n/**\r\n * Update known devices.\r\n *\r\n * @param {Array<Object>} pds - The new devices.\r\n * @returns {void}\r\n *\r\n * NOTE: Use this function as a shared callback to handle both the devicechange event  and the polling implementations.\r\n * This prevents duplication and works around a chrome bug (verified to occur on 68) where devicechange fires twice in\r\n * a row, which can cause async post devicechange processing to collide.\r\n */\r\nfunction updateKnownDevices(pds) {\r\n    if (compareAvailableMediaDevices(pds)) {\r\n        onMediaDevicesListChanged(pds);\r\n    }\r\n}\r\n\r\n/**\r\n * Event handler for the 'devicechange' event.\r\n *\r\n * @param {MediaDeviceInfo[]} devices - list of media devices.\r\n * @emits RTCEvents.DEVICE_LIST_CHANGED\r\n */\r\nfunction onMediaDevicesListChanged(devicesReceived) {\r\n    availableDevices = devicesReceived.slice(0);\r\n    logger.info('list of media devices has changed:', availableDevices);\r\n\r\n    sendDeviceListToAnalytics(availableDevices);\r\n\r\n    // Used by tracks to update the real device id before the consumer of lib-jitsi-meet receives the new device list.\r\n    eventEmitter.emit(RTCEvents.DEVICE_LIST_WILL_CHANGE, availableDevices);\r\n\r\n    eventEmitter.emit(RTCEvents.DEVICE_LIST_CHANGED, availableDevices);\r\n}\r\n\r\n/**\r\n *\r\n */\r\nclass RTCUtils extends Listenable {\r\n    /**\r\n     *\r\n     */\r\n    constructor() {\r\n        super(eventEmitter);\r\n    }\r\n\r\n    /**\r\n     * Depending on the browser, sets difference instance methods for\r\n     * interacting with user media and adds methods to native WebRTC-related\r\n     * objects. Also creates an instance variable for peer connection\r\n     * constraints.\r\n     *\r\n     * @param {Object} options\r\n     * @returns {void}\r\n     */\r\n    init(options = {}) {\r\n        if (typeof options.disableAEC === 'boolean') {\r\n            disableAEC = options.disableAEC;\r\n            logger.info(`Disable AEC: ${disableAEC}`);\r\n        }\r\n        if (typeof options.disableNS === 'boolean') {\r\n            disableNS = options.disableNS;\r\n            logger.info(`Disable NS: ${disableNS}`);\r\n        }\r\n        if (typeof options.disableAP === 'boolean') {\r\n            disableAP = options.disableAP;\r\n            logger.info(`Disable AP: ${disableAP}`);\r\n        }\r\n        if (typeof options.disableAGC === 'boolean') {\r\n            disableAGC = options.disableAGC;\r\n            logger.info(`Disable AGC: ${disableAGC}`);\r\n        }\r\n        if (typeof options.audioQuality?.stereo === 'boolean') {\r\n            stereo = options.audioQuality.stereo;\r\n            logger.info(`Stereo: ${stereo}`);\r\n        }\r\n\r\n        window.clearInterval(availableDevicesPollTimer);\r\n        availableDevicesPollTimer = undefined;\r\n\r\n        if (!browser.isReactNative()) {\r\n            this.attachMediaStream\r\n                = wrapAttachMediaStream((element, stream) => {\r\n                    if (element) {\r\n                        element.srcObject = stream;\r\n                    }\r\n                });\r\n        }\r\n\r\n        this.pcConstraints = {};\r\n\r\n        screenObtainer.init(options);\r\n\r\n        if (this.isDeviceListAvailable()) {\r\n            this.enumerateDevices(ds => {\r\n                availableDevices = ds.slice(0);\r\n\r\n                logger.debug('Available devices: ', availableDevices);\r\n                sendDeviceListToAnalytics(availableDevices);\r\n\r\n                eventEmitter.emit(\r\n                    RTCEvents.DEVICE_LIST_AVAILABLE,\r\n                    availableDevices);\r\n\r\n                if (browser.supportsDeviceChangeEvent()) {\r\n                    navigator.mediaDevices.addEventListener(\r\n                        'devicechange',\r\n                        () => this.enumerateDevices(emptyFuncton));\r\n                } else {\r\n                    // Periodically poll enumerateDevices() method to check if\r\n                    // list of media devices has changed.\r\n                    availableDevicesPollTimer = window.setInterval(\r\n                        () => this.enumerateDevices(emptyFuncton),\r\n                        AVAILABLE_DEVICES_POLL_INTERVAL_TIME);\r\n                }\r\n            });\r\n        }\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param {Function} callback\r\n     */\r\n    enumerateDevices(callback) {\r\n        navigator.mediaDevices.enumerateDevices()\r\n            .then(devices => {\r\n                updateKnownDevices(devices);\r\n                callback(devices);\r\n            })\r\n            .catch(error => {\r\n                logger.warn(`Failed to  enumerate devices. ${error}`);\r\n                updateKnownDevices([]);\r\n                callback([]);\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Acquires a media stream via getUserMedia that\r\n     * matches the given constraints\r\n     *\r\n     * @param {array} umDevices which devices to acquire (e.g. audio, video)\r\n     * @param {Object} constraints - Stream specifications to use.\r\n     * @param {number} timeout - The timeout in ms for GUM.\r\n     * @returns {Promise}\r\n     */\r\n    _getUserMedia(umDevices, constraints = {}, timeout = 0) {\r\n        return new Promise((resolve, reject) => {\r\n            let gumTimeout, timeoutExpired = false;\r\n\r\n            if (typeof timeout === 'number' && !isNaN(timeout) && timeout > 0) {\r\n                gumTimeout = setTimeout(() => {\r\n                    timeoutExpired = true;\r\n                    gumTimeout = undefined;\r\n                    reject(new JitsiTrackError(JitsiTrackErrors.TIMEOUT));\r\n                }, timeout);\r\n            }\r\n\r\n            navigator.mediaDevices.getUserMedia(constraints)\r\n                .then(stream => {\r\n                    logger.log('onUserMediaSuccess');\r\n                    updateGrantedPermissions(umDevices, stream);\r\n                    if (!timeoutExpired) {\r\n                        if (typeof gumTimeout !== 'undefined') {\r\n                            clearTimeout(gumTimeout);\r\n                        }\r\n                        resolve(stream);\r\n                    }\r\n                })\r\n                .catch(error => {\r\n                    logger.warn(`Failed to get access to local media. ${error} ${JSON.stringify(constraints)}`);\r\n                    const jitsiError = new JitsiTrackError(error, constraints, umDevices);\r\n\r\n                    if (!timeoutExpired) {\r\n                        if (typeof gumTimeout !== 'undefined') {\r\n                            clearTimeout(gumTimeout);\r\n                        }\r\n                        reject(jitsiError);\r\n                    }\r\n\r\n                    if (jitsiError.name === JitsiTrackErrors.PERMISSION_DENIED) {\r\n                        updateGrantedPermissions(umDevices, undefined);\r\n                    }\r\n\r\n                    // else {\r\n                    // Probably the error is not caused by the lack of permissions and we don't need to update them.\r\n                    // }\r\n                });\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Acquire a display stream via the screenObtainer. This requires extra\r\n     * logic compared to use screenObtainer versus normal device capture logic\r\n     * in RTCUtils#_getUserMedia.\r\n     *\r\n     * @param {Object} options - Optional parameters.\r\n     * @returns {Promise} A promise which will be resolved with an object which\r\n     * contains the acquired display stream. If desktop sharing is not supported\r\n     * then a rejected promise will be returned.\r\n     */\r\n    _getDesktopMedia(options) {\r\n        if (!screenObtainer.isSupported()) {\r\n            return Promise.reject(new Error('Desktop sharing is not supported!'));\r\n        }\r\n\r\n        return new Promise((resolve, reject) => {\r\n            screenObtainer.obtainStream(\r\n                stream => {\r\n                    resolve(stream);\r\n                },\r\n                error => {\r\n                    reject(error);\r\n                },\r\n                options);\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Private utility for determining if the passed in MediaStream contains\r\n     * tracks of the type(s) specified in the requested devices.\r\n     *\r\n     * @param {string[]} requestedDevices - The track types that are expected to\r\n     * be includes in the stream.\r\n     * @param {MediaStream} stream - The MediaStream to check if it has the\r\n     * expected track types.\r\n     * @returns {string[]} An array of string with the missing track types. The\r\n     * array will be empty if all requestedDevices are found in the stream.\r\n     */\r\n    _getMissingTracks(requestedDevices = [], stream) {\r\n        const missingDevices = [];\r\n\r\n        const audioDeviceRequested = requestedDevices.includes('audio');\r\n        const audioTracksReceived\r\n            = stream && stream.getAudioTracks().length > 0;\r\n\r\n        if (audioDeviceRequested && !audioTracksReceived) {\r\n            missingDevices.push('audio');\r\n        }\r\n\r\n        const videoDeviceRequested = requestedDevices.includes('video');\r\n        const videoTracksReceived\r\n            = stream && stream.getVideoTracks().length > 0;\r\n\r\n        if (videoDeviceRequested && !videoTracksReceived) {\r\n            missingDevices.push('video');\r\n        }\r\n\r\n        return missingDevices;\r\n    }\r\n\r\n    /**\r\n     * Gets streams from specified device types. This function intentionally\r\n     * ignores errors for upstream to catch and handle instead.\r\n     *\r\n     * @param {Object} options - A hash describing what devices to get and\r\n     * relevant constraints.\r\n     * @param {string[]} options.devices - The types of media to capture. Valid\r\n     * values are \"desktop\", \"audio\", and \"video\".\r\n     * @param {Object} options.desktopSharingFrameRate\r\n     * @param {Object} options.desktopSharingFrameRate.min - Minimum fps\r\n     * @param {Object} options.desktopSharingFrameRate.max - Maximum fps\r\n     * @param {String} options.desktopSharingSourceDevice - The device id or\r\n     * label for a video input source that should be used for screensharing.\r\n     * @param {Array<string>} options.desktopSharingSources - The types of sources (\"screen\", \"window\", etc)\r\n     * from which the user can select what to share.\r\n     * @returns {Promise} The promise, when successful, will return an array of\r\n     * meta data for the requested device type, which includes the stream and\r\n     * track. If an error occurs, it will be deferred to the caller for\r\n     * handling.\r\n     */\r\n    obtainAudioAndVideoPermissions(options) {\r\n        const {\r\n            timeout,\r\n            ...otherOptions\r\n        } = options;\r\n\r\n        const mediaStreamsMetaData = [];\r\n\r\n        // Declare private functions to be used in the promise chain below.\r\n        // These functions are declared in the scope of this function because\r\n        // they are not being used anywhere else, so only this function needs to\r\n        // know about them.\r\n\r\n        /**\r\n         * Executes a request for desktop media if specified in options.\r\n         *\r\n         * @returns {Promise}\r\n         */\r\n        const maybeRequestDesktopDevice = function() {\r\n            const umDevices = otherOptions.devices || [];\r\n            const isDesktopDeviceRequested\r\n                = umDevices.indexOf('desktop') !== -1;\r\n\r\n            if (!isDesktopDeviceRequested) {\r\n                return Promise.resolve();\r\n            }\r\n\r\n            const {\r\n                desktopSharingSourceDevice,\r\n                desktopSharingSources\r\n            } = otherOptions;\r\n\r\n            // Attempt to use a video input device as a screenshare source if\r\n            // the option is defined.\r\n            if (desktopSharingSourceDevice) {\r\n                const matchingDevice\r\n                    = availableDevices && availableDevices.find(device =>\r\n                        device.kind === 'videoinput'\r\n                            && (device.deviceId === desktopSharingSourceDevice\r\n                            || device.label === desktopSharingSourceDevice));\r\n\r\n                if (!matchingDevice) {\r\n                    return Promise.reject(new JitsiTrackError(\r\n                        { name: 'ConstraintNotSatisfiedError' },\r\n                        {},\r\n                        [ desktopSharingSourceDevice ]\r\n                    ));\r\n                }\r\n\r\n                const requestedDevices = [ 'video' ];\r\n                const constraints = {\r\n                    video: {\r\n                        deviceId: matchingDevice.deviceId\r\n\r\n                        // frameRate is omited here on purpose since this is a device that we'll pretend is a screen.\r\n                    }\r\n                };\r\n\r\n                return this._getUserMedia(requestedDevices, constraints, timeout)\r\n                    .then(stream => {\r\n                        return {\r\n                            sourceType: 'device',\r\n                            stream\r\n                        };\r\n                    });\r\n            }\r\n\r\n            return this._getDesktopMedia({ desktopSharingSources });\r\n        }.bind(this);\r\n\r\n        /**\r\n         * Creates a meta data object about the passed in desktopStream and\r\n         * pushes the meta data to the internal array mediaStreamsMetaData to be\r\n         * returned later.\r\n         *\r\n         * @param {MediaStreamTrack} desktopStream - A track for a desktop\r\n         * capture.\r\n         * @returns {void}\r\n         */\r\n        const maybeCreateAndAddDesktopTrack = function(desktopStream) {\r\n            if (!desktopStream) {\r\n                return;\r\n            }\r\n\r\n            const { stream, sourceId, sourceType } = desktopStream;\r\n\r\n            const desktopAudioTracks = stream.getAudioTracks();\r\n\r\n            if (desktopAudioTracks.length) {\r\n                const desktopAudioStream = new MediaStream(desktopAudioTracks);\r\n\r\n                mediaStreamsMetaData.push({\r\n                    stream: desktopAudioStream,\r\n                    sourceId,\r\n                    sourceType,\r\n                    track: desktopAudioStream.getAudioTracks()[0]\r\n                });\r\n            }\r\n\r\n            const desktopVideoTracks = stream.getVideoTracks();\r\n\r\n            if (desktopVideoTracks.length) {\r\n                const desktopVideoStream = new MediaStream(desktopVideoTracks);\r\n\r\n                mediaStreamsMetaData.push({\r\n                    stream: desktopVideoStream,\r\n                    sourceId,\r\n                    sourceType,\r\n                    track: desktopVideoStream.getVideoTracks()[0],\r\n                    videoType: VideoType.DESKTOP\r\n                });\r\n            }\r\n        };\r\n\r\n        /**\r\n         * Executes a request for audio and/or video, as specified in options.\r\n         * By default both audio and video will be captured if options.devices\r\n         * is not defined.\r\n         *\r\n         * @returns {Promise}\r\n         */\r\n        const maybeRequestCaptureDevices = function() {\r\n            const umDevices = otherOptions.devices || [ 'audio', 'video' ];\r\n            const requestedCaptureDevices = umDevices.filter(device => device === 'audio' || device === 'video');\r\n\r\n            if (!requestedCaptureDevices.length) {\r\n                return Promise.resolve();\r\n            }\r\n\r\n            const constraints = getConstraints(requestedCaptureDevices, otherOptions);\r\n\r\n            logger.info('Got media constraints: ', JSON.stringify(constraints));\r\n\r\n            return this._getUserMedia(requestedCaptureDevices, constraints, timeout);\r\n        }.bind(this);\r\n\r\n        /**\r\n         * Splits the passed in media stream into separate audio and video\r\n         * streams and creates meta data objects for each and pushes them to the\r\n         * internal array mediaStreamsMetaData to be returned later.\r\n         *\r\n         * @param {MediaStreamTrack} avStream - A track for with audio and/or\r\n         * video track.\r\n         * @returns {void}\r\n         */\r\n        const maybeCreateAndAddAVTracks = function(avStream) {\r\n            if (!avStream) {\r\n                return;\r\n            }\r\n\r\n            const audioTracks = avStream.getAudioTracks();\r\n\r\n            if (audioTracks.length) {\r\n                const audioStream = new MediaStream(audioTracks);\r\n\r\n                mediaStreamsMetaData.push({\r\n                    stream: audioStream,\r\n                    track: audioStream.getAudioTracks()[0],\r\n                    effects: otherOptions.effects\r\n                });\r\n            }\r\n\r\n            const videoTracks = avStream.getVideoTracks();\r\n\r\n            if (videoTracks.length) {\r\n                const videoStream = new MediaStream(videoTracks);\r\n\r\n                mediaStreamsMetaData.push({\r\n                    stream: videoStream,\r\n                    track: videoStream.getVideoTracks()[0],\r\n                    videoType: VideoType.CAMERA,\r\n                    effects: otherOptions.effects\r\n                });\r\n            }\r\n        };\r\n\r\n        return maybeRequestDesktopDevice()\r\n            .then(maybeCreateAndAddDesktopTrack)\r\n            .then(maybeRequestCaptureDevices)\r\n            .then(maybeCreateAndAddAVTracks)\r\n            .then(() => mediaStreamsMetaData)\r\n            .catch(error => {\r\n                mediaStreamsMetaData.forEach(({ stream }) => {\r\n                    this.stopMediaStream(stream);\r\n                });\r\n\r\n                return Promise.reject(error);\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Checks whether it is possible to enumerate available cameras/microphones.\r\n     *\r\n     * @returns {boolean} {@code true} if the device listing is available;\r\n     * {@code false}, otherwise.\r\n     */\r\n    isDeviceListAvailable() {\r\n        return Boolean(\r\n            navigator.mediaDevices\r\n                && navigator.mediaDevices.enumerateDevices);\r\n    }\r\n\r\n    /**\r\n     * Returns true if changing the input (camera / microphone) or output\r\n     * (audio) device is supported and false if not.\r\n     * @params {string} [deviceType] - type of device to change. Default is\r\n     *      undefined or 'input', 'output' - for audio output device change.\r\n     * @returns {boolean} true if available, false otherwise.\r\n     */\r\n    isDeviceChangeAvailable(deviceType) {\r\n        if (deviceType === 'output' || deviceType === 'audiooutput') {\r\n            return isAudioOutputDeviceChangeAvailable;\r\n        }\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * A method to handle stopping of the stream.\r\n     * One point to handle the differences in various implementations.\r\n     * @param mediaStream MediaStream object to stop.\r\n     */\r\n    stopMediaStream(mediaStream) {\r\n        if (!mediaStream) {\r\n            return;\r\n        }\r\n\r\n        mediaStream.getTracks().forEach(track => {\r\n            if (track.stop) {\r\n                track.stop();\r\n            }\r\n        });\r\n\r\n        // leave stop for implementation still using it\r\n        if (mediaStream.stop) {\r\n            mediaStream.stop();\r\n        }\r\n\r\n        // The MediaStream implementation of the react-native-webrtc project has\r\n        // an explicit release method that is to be invoked in order to release\r\n        // used resources such as memory.\r\n        if (mediaStream.release) {\r\n            mediaStream.release();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns whether the desktop sharing is enabled or not.\r\n     * @returns {boolean}\r\n     */\r\n    isDesktopSharingEnabled() {\r\n        return screenObtainer.isSupported();\r\n    }\r\n\r\n    /**\r\n     * Sets current audio output device.\r\n     * @param {string} deviceId - id of 'audiooutput' device from\r\n     *      navigator.mediaDevices.enumerateDevices(), 'default' for default\r\n     *      device\r\n     * @returns {Promise} - resolves when audio output is changed, is rejected\r\n     *      otherwise\r\n     */\r\n    setAudioOutputDevice(deviceId) {\r\n        if (!this.isDeviceChangeAvailable('output')) {\r\n            return Promise.reject(\r\n                new Error('Audio output device change is not supported'));\r\n        }\r\n\r\n        return featureDetectionAudioEl.setSinkId(deviceId)\r\n            .then(() => {\r\n                audioOutputDeviceId = deviceId;\r\n                audioOutputChanged = true;\r\n\r\n                logger.log(`Audio output device set to ${deviceId}`);\r\n\r\n                eventEmitter.emit(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\r\n                    deviceId);\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Sets the capture frame rate for desktop tracks.\r\n     *\r\n     * @param {number} maxFps - max fps to be used as the capture frame rate.\r\n     * @returns {void}\r\n     */\r\n    setDesktopSharingFrameRate(maxFps) {\r\n        screenObtainer.setDesktopSharingFrameRate(maxFps);\r\n    }\r\n\r\n    /**\r\n     * Returns currently used audio output device id, '' stands for default\r\n     * device\r\n     * @returns {string}\r\n     */\r\n    getAudioOutputDevice() {\r\n        return audioOutputDeviceId;\r\n    }\r\n\r\n    /**\r\n     * Returns list of available media devices if its obtained, otherwise an\r\n     * empty array is returned/\r\n     * @returns {Array} list of available media devices.\r\n     */\r\n    getCurrentlyAvailableMediaDevices() {\r\n        return availableDevices;\r\n    }\r\n\r\n    /**\r\n     * Returns whether available devices have permissions granted\r\n     * @returns {Boolean}\r\n     */\r\n    arePermissionsGrantedForAvailableDevices() {\r\n        return availableDevices.some(device => Boolean(device.label));\r\n    }\r\n\r\n    /**\r\n     * Returns event data for device to be reported to stats.\r\n     * @returns {MediaDeviceInfo} device.\r\n     */\r\n    getEventDataForActiveDevice(device) {\r\n        const deviceList = [];\r\n        const deviceData = {\r\n            'deviceId': device.deviceId,\r\n            'kind': device.kind,\r\n            'label': device.label,\r\n            'groupId': device.groupId\r\n        };\r\n\r\n        deviceList.push(deviceData);\r\n\r\n        return { deviceList };\r\n    }\r\n}\r\n\r\nconst rtcUtils = new RTCUtils();\r\n\r\n/**\r\n * Wraps original attachMediaStream function to set current audio output device\r\n * if this is supported.\r\n * @param {Function} origAttachMediaStream\r\n * @returns {Function}\r\n */\r\nfunction wrapAttachMediaStream(origAttachMediaStream) {\r\n    return function(element, stream) {\r\n        // eslint-disable-next-line prefer-rest-params\r\n        const res = origAttachMediaStream.apply(rtcUtils, arguments);\r\n\r\n        if (stream\r\n                && rtcUtils.isDeviceChangeAvailable('output')\r\n                && stream.getAudioTracks\r\n                && stream.getAudioTracks().length\r\n\r\n                // we skip setting audio output if there was no explicit change\r\n                && audioOutputChanged) {\r\n            element.setSinkId(rtcUtils.getAudioOutputDevice())\r\n                .catch(function(ex) {\r\n                    const err\r\n                        = new JitsiTrackError(ex, null, [ 'audiooutput' ]);\r\n\r\n                    GlobalOnErrorHandler.callUnhandledRejectionHandler({\r\n                        promise: this, // eslint-disable-line no-invalid-this\r\n                        reason: err\r\n                    });\r\n\r\n                    logger.warn(\r\n                        'Failed to set audio output device for the element.'\r\n                            + ' Default audio output device will be used'\r\n                            + ' instead',\r\n                        element,\r\n                        err);\r\n                });\r\n        }\r\n\r\n        return res;\r\n    };\r\n}\r\n\r\nexport default rtcUtils;\r\n","import { getLogger } from '@jitsi/logger';\r\nimport EventEmitter from 'events';\r\n\r\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport browser from '../browser';\r\n\r\nimport RTCUtils from './RTCUtils';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Maps our handler types to MediaStreamTrack properties.\r\n */\r\nconst trackHandler2Prop = {\r\n    'track_mute': 'onmute', // Not supported on FF\r\n    'track_unmute': 'onunmute',\r\n    'track_ended': 'onended'\r\n};\r\n\r\n/**\r\n * Represents a single media track (either audio or video).\r\n */\r\nexport default class JitsiTrack extends EventEmitter {\r\n    /* eslint-disable max-params */\r\n    /**\r\n     * Represents a single media track (either audio or video).\r\n     * @constructor\r\n     * @param conference the rtc instance\r\n     * @param stream the WebRTC MediaStream instance\r\n     * @param track the WebRTC MediaStreamTrack instance, must be part of\r\n     * the given <tt>stream</tt>.\r\n     * @param streamInactiveHandler the function that will handle\r\n     *        onended/oninactive events of the stream.\r\n     * @param trackMediaType the media type of the JitsiTrack\r\n     * @param videoType the VideoType for this track if any\r\n     */\r\n    constructor(\r\n            conference,\r\n            stream,\r\n            track,\r\n            streamInactiveHandler,\r\n            trackMediaType,\r\n            videoType) {\r\n        super();\r\n\r\n        // aliases for addListener/removeListener\r\n        this.addEventListener = this.addListener;\r\n        this.removeEventListener = this.off = this.removeListener;\r\n\r\n        /**\r\n         * Array with the HTML elements that are displaying the streams.\r\n         * @type {Array}\r\n         */\r\n        this.containers = [];\r\n        this.conference = conference;\r\n        this.audioLevel = -1;\r\n        this.type = trackMediaType;\r\n        this.track = track;\r\n        this.videoType = videoType;\r\n        this.handlers = new Map();\r\n\r\n        /**\r\n         * Indicates whether this JitsiTrack has been disposed. If true, this\r\n         * JitsiTrack is to be considered unusable and operations involving it\r\n         * are to fail (e.g. {@link JitsiConference#addTrack(JitsiTrack)},\r\n         * {@link JitsiConference#removeTrack(JitsiTrack)}).\r\n         * @type {boolean}\r\n         */\r\n        this.disposed = false;\r\n\r\n        /**\r\n         * The inactive handler which will be triggered when the underlying\r\n         * <tt>MediaStream</tt> ends.\r\n         *\r\n         * @private\r\n         * @type {Function}\r\n         */\r\n        this._streamInactiveHandler = streamInactiveHandler;\r\n\r\n        this._setStream(stream);\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * Adds onended/oninactive handler to a MediaStream or a MediaStreamTrack.\r\n     * Firefox doesn't fire a inactive event on the MediaStream, instead it fires\r\n     * a onended event on the MediaStreamTrack.\r\n     * @param {Function} handler the handler\r\n     */\r\n    _addMediaStreamInactiveHandler(handler) {\r\n        if (browser.isFirefox()) {\r\n            this.track.onended = handler;\r\n        } else {\r\n            this.stream.oninactive = handler;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets handler to the WebRTC MediaStream or MediaStreamTrack object\r\n     * depending on the passed type.\r\n     * @param {string} type the type of the handler that is going to be set\r\n     * @param {Function} handler the handler.\r\n     */\r\n    _setHandler(type, handler) {\r\n        if (!trackHandler2Prop.hasOwnProperty(type)) {\r\n            logger.error(`Invalid handler type ${type}`);\r\n\r\n            return;\r\n        }\r\n        if (handler) {\r\n            this.handlers.set(type, handler);\r\n        } else {\r\n            this.handlers.delete(type);\r\n        }\r\n\r\n        if (this.stream) {\r\n            for (const track of this.stream.getTracks()) {\r\n                track[trackHandler2Prop[type]] = handler;\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Unregisters all event handlers bound to the underlying media stream/track\r\n     * @private\r\n     */\r\n    _unregisterHandlers() {\r\n        if (!this.stream) {\r\n            logger.warn(\r\n                `${this}: unable to unregister handlers - no stream object`);\r\n\r\n            return;\r\n        }\r\n\r\n        for (const type of this.handlers.keys()) {\r\n            // FIXME Why only video tracks?\r\n            for (const videoTrack of this.stream.getVideoTracks()) {\r\n                videoTrack[trackHandler2Prop[type]] = undefined;\r\n            }\r\n        }\r\n        if (this._streamInactiveHandler) {\r\n            this._addMediaStreamInactiveHandler(undefined);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets the stream property of JitsiTrack object and sets all stored\r\n     * handlers to it.\r\n     *\r\n     * @param {MediaStream} stream the new stream.\r\n     * @protected\r\n     */\r\n    _setStream(stream) {\r\n        if (this.stream === stream) {\r\n            return;\r\n        }\r\n\r\n        this.stream = stream;\r\n\r\n        // TODO Practically, that's like the opposite of _unregisterHandlers\r\n        // i.e. may be abstracted into a function/method called\r\n        // _registerHandlers for clarity and easing the maintenance of the two\r\n        // pieces of source code.\r\n        if (this.stream) {\r\n            for (const type of this.handlers.keys()) {\r\n                this._setHandler(type, this.handlers.get(type));\r\n            }\r\n            if (this._streamInactiveHandler) {\r\n                this._addMediaStreamInactiveHandler(this._streamInactiveHandler);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns the video type (camera or desktop) of this track.\r\n     */\r\n    getVideoType() {\r\n        return this.videoType;\r\n    }\r\n\r\n    /**\r\n     * Returns the type (audio or video) of this track.\r\n     */\r\n    getType() {\r\n        return this.type;\r\n    }\r\n\r\n    /**\r\n     * Check if this is an audio track.\r\n     */\r\n    isAudioTrack() {\r\n        return this.getType() === MediaType.AUDIO;\r\n    }\r\n\r\n    /**\r\n     * Checks whether the underlying WebRTC <tt>MediaStreamTrack</tt> is muted\r\n     * according to it's 'muted' field status.\r\n     * @return {boolean} <tt>true</tt> if the underlying\r\n     * <tt>MediaStreamTrack</tt> is muted or <tt>false</tt> otherwise.\r\n     */\r\n    isWebRTCTrackMuted() {\r\n        return this.track && this.track.muted;\r\n    }\r\n\r\n    /**\r\n     * Check if this is a video track.\r\n     */\r\n    isVideoTrack() {\r\n        return this.getType() === MediaType.VIDEO;\r\n    }\r\n\r\n    /**\r\n     * Checks whether this is a local track.\r\n     * @abstract\r\n     * @return {boolean} 'true' if it's a local track or 'false' otherwise.\r\n     */\r\n    isLocal() {\r\n        throw new Error('Not implemented by subclass');\r\n    }\r\n\r\n    /**\r\n     * Check whether this is a local audio track.\r\n     *\r\n     * @return {boolean} -  true if track represents a local audio track, false otherwise.\r\n     */\r\n    isLocalAudioTrack() {\r\n        return this.isAudioTrack() && this.isLocal();\r\n    }\r\n\r\n    /**\r\n     * Returns the WebRTC MediaStream instance.\r\n     */\r\n    getOriginalStream() {\r\n        return this.stream;\r\n    }\r\n\r\n    /**\r\n     * Returns the ID of the underlying WebRTC Media Stream(if any)\r\n     * @returns {String|null}\r\n     */\r\n    getStreamId() {\r\n        return this.stream ? this.stream.id : null;\r\n    }\r\n\r\n    /**\r\n     * Return the underlying WebRTC MediaStreamTrack\r\n     * @returns {MediaStreamTrack}\r\n     */\r\n    getTrack() {\r\n        return this.track;\r\n    }\r\n\r\n    /**\r\n     * Return the underlying WebRTC MediaStreamTrack label\r\n     * @returns {string}\r\n     */\r\n    getTrackLabel() {\r\n        return this.track.label;\r\n    }\r\n\r\n    /**\r\n     * Returns the ID of the underlying WebRTC MediaStreamTrack(if any)\r\n     * @returns {String|null}\r\n     */\r\n    getTrackId() {\r\n        return this.track ? this.track.id : null;\r\n    }\r\n\r\n    /**\r\n     * Return meaningful usage label for this track depending on it's media and\r\n     * eventual video type.\r\n     * @returns {string}\r\n     */\r\n    getUsageLabel() {\r\n        if (this.isAudioTrack()) {\r\n            return 'mic';\r\n        }\r\n\r\n        return this.videoType ? this.videoType : 'default';\r\n    }\r\n\r\n    /**\r\n     * Eventually will trigger RTCEvents.TRACK_ATTACHED event.\r\n     * @param container the video/audio container to which this stream is\r\n     *        attached and for which event will be fired.\r\n     * @private\r\n     */\r\n    _maybeFireTrackAttached(container) {\r\n        if (this.conference && container) {\r\n            this.conference._onTrackAttach(this, container);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Attaches the MediaStream of this track to an HTML container.\r\n     * Adds the container to the list of containers that are displaying the\r\n     * track.\r\n     *\r\n     * @param container the HTML container which can be 'video' or 'audio'\r\n     * element.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    attach(container) {\r\n        if (this.stream) {\r\n            this._onTrackAttach(container);\r\n            RTCUtils.attachMediaStream(container, this.stream);\r\n        }\r\n        this.containers.push(container);\r\n        this._maybeFireTrackAttached(container);\r\n        this._attachTTFMTracker(container);\r\n    }\r\n\r\n    /**\r\n     * Removes this JitsiTrack from the passed HTML container.\r\n     *\r\n     * @param container the HTML container to detach from this JitsiTrack. If\r\n     * <tt>null</tt> or <tt>undefined</tt>, all containers are removed. A\r\n     * container can be a 'video', 'audio' or 'object' HTML element instance to\r\n     * which this JitsiTrack is currently attached.\r\n     */\r\n    detach(container) {\r\n        for (let cs = this.containers, i = cs.length - 1; i >= 0; --i) {\r\n            const c = cs[i];\r\n\r\n            if (!container) {\r\n                this._onTrackDetach(c);\r\n                RTCUtils.attachMediaStream(c, null);\r\n            }\r\n            if (!container || c === container) {\r\n                cs.splice(i, 1);\r\n            }\r\n        }\r\n\r\n        if (container) {\r\n            this._onTrackDetach(container);\r\n            RTCUtils.attachMediaStream(container, null);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Called when the track has been attached to a new container.\r\n     *\r\n     * @param {HTMLElement} container the HTML container which can be 'video' or\r\n     * 'audio' element.\r\n     * @private\r\n     */\r\n    _onTrackAttach(container) { // eslint-disable-line no-unused-vars\r\n        // Should be defined by the classes that are extending JitsiTrack\r\n    }\r\n\r\n    /**\r\n     * Called when the track has been detached from a container.\r\n     *\r\n     * @param {HTMLElement} container the HTML container which can be 'video' or\r\n     * 'audio' element.\r\n     * @private\r\n     */\r\n    _onTrackDetach(container) { // eslint-disable-line no-unused-vars\r\n        // Should be defined by the classes that are extending JitsiTrack\r\n    }\r\n\r\n    /**\r\n     * Attach time to first media tracker only if there is conference and only\r\n     * for the first element.\r\n     *\r\n     * @param {HTMLElement} container the HTML container which can be 'video' or\r\n     * 'audio' element.\r\n     * @private\r\n     */\r\n    _attachTTFMTracker(container) { // eslint-disable-line no-unused-vars\r\n        // Should be defined by the classes that are extending JitsiTrack\r\n    }\r\n\r\n    /**\r\n     * Removes attached event listeners.\r\n     *\r\n     * @returns {Promise}\r\n     */\r\n    dispose() {\r\n        this.removeAllListeners();\r\n\r\n        this.disposed = true;\r\n\r\n        return Promise.resolve();\r\n    }\r\n\r\n    /**\r\n     * Returns id of the track.\r\n     * @returns {string|null} id of the track or null if this is fake track.\r\n     */\r\n    getId() {\r\n        return this.getStreamId();\r\n    }\r\n\r\n    /**\r\n     * Checks whether the MediaStream is active/not ended.\r\n     * When there is no check for active we don't have information and so\r\n     * will return that stream is active (in case of FF).\r\n     * @returns {boolean} whether MediaStream is active.\r\n     */\r\n    isActive() {\r\n        if (typeof this.stream.active !== 'undefined') {\r\n            return this.stream.active;\r\n        }\r\n\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * Sets the audio level for the stream\r\n     * @param {number} audioLevel value between 0 and 1\r\n     * @param {TraceablePeerConnection} [tpc] the peerconnection instance which\r\n     * is source for the audio level. It can be <tt>undefined</tt> for\r\n     * a local track if the audio level was measured outside of the\r\n     * peerconnection (see /modules/statistics/LocalStatsCollector.js).\r\n     */\r\n    setAudioLevel(audioLevel, tpc) {\r\n        let newAudioLevel = audioLevel;\r\n\r\n        // When using getSynchornizationSources on the audio receiver to gather audio levels for\r\n        // remote tracks, browser reports last known audio levels even when the remote user is\r\n        // audio muted, we need to reset the value to zero here so that the audio levels are cleared.\r\n        // Remote tracks have the tpc info present while local tracks do not.\r\n        if (browser.supportsReceiverStats() && typeof tpc !== 'undefined' && this.isMuted()) {\r\n            newAudioLevel = 0;\r\n        }\r\n\r\n        if (this.audioLevel !== newAudioLevel) {\r\n            this.audioLevel = newAudioLevel;\r\n            this.emit(\r\n                JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,\r\n                newAudioLevel,\r\n                tpc);\r\n\r\n        // LocalStatsCollector reports a value of 0.008 for muted mics\r\n        // and a value of 0 when there is no audio input.\r\n        } else if (this.audioLevel === 0\r\n            && newAudioLevel === 0\r\n            && this.isLocal()\r\n            && !this.isWebRTCTrackMuted()) {\r\n            this.emit(\r\n                JitsiTrackEvents.NO_AUDIO_INPUT,\r\n                newAudioLevel);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns the msid of the stream attached to the JitsiTrack object or null\r\n     * if no stream is attached.\r\n     */\r\n    getMSID() {\r\n        const streamId = this.getStreamId();\r\n        const trackId = this.getTrackId();\r\n\r\n        return streamId && trackId ? `${streamId} ${trackId}` : null;\r\n    }\r\n\r\n    /**\r\n     * Sets new audio output device for track's DOM elements. Video tracks are\r\n     * ignored.\r\n     * @param {string} audioOutputDeviceId - id of 'audiooutput' device from\r\n     *      navigator.mediaDevices.enumerateDevices(), '' for default device\r\n     * @emits JitsiTrackEvents.TRACK_AUDIO_OUTPUT_CHANGED\r\n     * @returns {Promise}\r\n     */\r\n    setAudioOutput(audioOutputDeviceId) {\r\n        if (!RTCUtils.isDeviceChangeAvailable('output')) {\r\n            return Promise.reject(\r\n                new Error('Audio output device change is not supported'));\r\n        }\r\n\r\n        // All audio communication is done through audio tracks, so ignore\r\n        // changing audio output for video tracks at all.\r\n        if (this.isVideoTrack()) {\r\n            return Promise.resolve();\r\n        }\r\n\r\n        return (\r\n            Promise.all(\r\n                this.containers.map(\r\n                    element =>\r\n                        element.setSinkId(audioOutputDeviceId)\r\n                            .catch(error => {\r\n                                logger.warn(\r\n                                    'Failed to change audio output device on'\r\n                                        + ' element. Default or previously set'\r\n                                        + ' audio output device will be used.',\r\n                                    element,\r\n                                    error);\r\n                                throw error;\r\n                            }))\r\n            )\r\n                .then(() => {\r\n                    this.emit(\r\n                        JitsiTrackEvents.TRACK_AUDIO_OUTPUT_CHANGED,\r\n                        audioOutputDeviceId);\r\n                }));\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport JitsiTrackError from '../../JitsiTrackError';\r\nimport {\r\n    TRACK_IS_DISPOSED,\r\n    TRACK_NO_STREAM_FOUND\r\n} from '../../JitsiTrackErrors';\r\nimport {\r\n    LOCAL_TRACK_STOPPED,\r\n    NO_DATA_FROM_SOURCE,\r\n    TRACK_MUTE_CHANGED\r\n} from '../../JitsiTrackEvents';\r\nimport CameraFacingMode from '../../service/RTC/CameraFacingMode';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport RTCEvents from '../../service/RTC/RTCEvents';\r\nimport { VideoType } from '../../service/RTC/VideoType';\r\nimport {\r\n    NO_BYTES_SENT,\r\n    TRACK_UNMUTED,\r\n    createNoDataFromSourceEvent\r\n} from '../../service/statistics/AnalyticsEvents';\r\nimport browser from '../browser';\r\nimport FeatureFlags from '../flags/FeatureFlags';\r\nimport Statistics from '../statistics/statistics';\r\n\r\nimport JitsiTrack from './JitsiTrack';\r\nimport RTCUtils from './RTCUtils';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Represents a single media track(either audio or video).\r\n * One <tt>JitsiLocalTrack</tt> corresponds to one WebRTC MediaStreamTrack.\r\n */\r\nexport default class JitsiLocalTrack extends JitsiTrack {\r\n    /**\r\n     * Constructs a new JitsiLocalTrack instance.\r\n     *\r\n     * @constructor\r\n     * @param {Object} trackInfo\r\n     * @param {number} trackInfo.rtcId - The ID assigned by the RTC module.\r\n     * @param {Object} trackInfo.stream - The WebRTC MediaStream, parent of the track.\r\n     * @param {Object} trackInfo.track - The underlying WebRTC MediaStreamTrack for new JitsiLocalTrack.\r\n     * @param {string} trackInfo.mediaType - The MediaType of the JitsiLocalTrack.\r\n     * @param {string} trackInfo.videoType - The VideoType of the JitsiLocalTrack.\r\n     * @param {Array<Object>} trackInfo.effects - The effects to be applied to the JitsiLocalTrack.\r\n     * @param {number} trackInfo.resolution - The the video resolution if it's a video track\r\n     * @param {string} trackInfo.deviceId - The ID of the local device for this track.\r\n     * @param {string} trackInfo.facingMode - Thehe camera facing mode used in getUserMedia call (for mobile only).\r\n     * @param {sourceId} trackInfo.sourceId - The id of the desktop sharing source. NOTE: defined for desktop sharing\r\n     * tracks only.\r\n     */\r\n    constructor({\r\n        deviceId,\r\n        facingMode,\r\n        mediaType,\r\n        resolution,\r\n        rtcId,\r\n        sourceId,\r\n        sourceType,\r\n        stream,\r\n        track,\r\n        videoType,\r\n        effects = []\r\n    }) {\r\n        super(\r\n            /* conference */ null,\r\n            stream,\r\n            track,\r\n            /* streamInactiveHandler */ () => this.emit(LOCAL_TRACK_STOPPED, this),\r\n            mediaType,\r\n            videoType);\r\n\r\n        this._setEffectInProgress = false;\r\n        const effect = effects.find(e => e.isEnabled(this));\r\n\r\n        if (effect) {\r\n            this._startStreamEffect(effect);\r\n        }\r\n\r\n        const displaySurface = videoType === VideoType.DESKTOP\r\n            ? track.getSettings().displaySurface\r\n            : null;\r\n\r\n        /**\r\n         * Track metadata.\r\n         */\r\n        this.metadata = {\r\n            timestamp: Date.now(),\r\n            ...displaySurface ? { displaySurface } : {}\r\n        };\r\n\r\n\r\n        /**\r\n         * The ID assigned by the RTC module on instance creation.\r\n         *\r\n         * @type {number}\r\n         */\r\n        this.rtcId = rtcId;\r\n        this.sourceId = sourceId;\r\n        this.sourceType = sourceType ?? displaySurface;\r\n\r\n        // Get the resolution from the track itself because it cannot be\r\n        // certain which resolution webrtc has fallen back to using.\r\n        this.resolution = track.getSettings().height;\r\n        this.maxEnabledResolution = resolution;\r\n\r\n        // Cache the constraints of the track in case of any this track\r\n        // model needs to call getUserMedia again, such as when unmuting.\r\n        this._constraints = track.getConstraints();\r\n\r\n        // Safari returns an empty constraints object, construct the constraints using getSettings.\r\n        if (!Object.keys(this._constraints).length && videoType === VideoType.CAMERA) {\r\n            this._constraints = {\r\n                height: track.getSettings().height,\r\n                width: track.getSettings().width\r\n            };\r\n        }\r\n\r\n        this.deviceId = deviceId;\r\n\r\n        /**\r\n         * The <tt>Promise</tt> which represents the progress of a previously\r\n         * queued/scheduled {@link _setMuted} (from the point of view of\r\n         * {@link _queueSetMuted}).\r\n         *\r\n         * @private\r\n         * @type {Promise}\r\n         */\r\n        this._prevSetMuted = Promise.resolve();\r\n\r\n        /**\r\n         * The facing mode of the camera from which this JitsiLocalTrack\r\n         * instance was obtained.\r\n         *\r\n         * @private\r\n         * @type {CameraFacingMode|undefined}\r\n         */\r\n        this._facingMode = facingMode;\r\n\r\n        // Currently there is no way to know the MediaStreamTrack ended due to\r\n        // to device disconnect in Firefox through e.g. \"readyState\" property.\r\n        // Instead we will compare current track's label with device labels from\r\n        // enumerateDevices() list.\r\n        this._trackEnded = false;\r\n\r\n        /**\r\n         * Indicates whether data has been sent or not.\r\n         */\r\n        this._hasSentData = false;\r\n\r\n        /**\r\n         * Used only for detection of audio problems. We want to check only once\r\n         * whether the track is sending data ot not. This flag is set to false\r\n         * after the check.\r\n         */\r\n        this._testDataSent = true;\r\n\r\n        // Currently there is no way to determine with what device track was\r\n        // created (until getConstraints() support), however we can associate\r\n        // tracks with real devices obtained from enumerateDevices() call as\r\n        // soon as it's called.\r\n        // NOTE: this.deviceId corresponds to the device id specified in GUM constraints and this._realDeviceId seems to\r\n        // correspond to the id of a matching device from the available device list.\r\n        this._realDeviceId = this.deviceId === '' ? undefined : this.deviceId;\r\n\r\n        // The source name that will be signaled for this track.\r\n        this._sourceName = null;\r\n\r\n        this._trackMutedTS = 0;\r\n\r\n        this._onDeviceListWillChange = devices => {\r\n            const oldRealDeviceId = this._realDeviceId;\r\n\r\n            this._setRealDeviceIdFromDeviceList(devices);\r\n\r\n            if (\r\n                // Mark track as ended for those browsers that do not support\r\n                // \"readyState\" property. We do not touch tracks created with\r\n                // default device ID \"\".\r\n                (typeof this.getTrack().readyState === 'undefined'\r\n                    && typeof this._realDeviceId !== 'undefined'\r\n                    && !devices.find(d => d.deviceId === this._realDeviceId))\r\n\r\n                // If there was an associated realDeviceID and after the device change the realDeviceId is undefined\r\n                // then the associated device has been disconnected and the _trackEnded flag needs to be set. In\r\n                // addition on some Chrome versions the readyState property is set after the device change event is\r\n                // triggered which causes issues in jitsi-meet with the selection of a new device because we don't\r\n                // detect that the old one was removed.\r\n                || (typeof oldRealDeviceId !== 'undefined' && typeof this._realDeviceId === 'undefined')\r\n            ) {\r\n                this._trackEnded = true;\r\n            }\r\n        };\r\n\r\n        // Subscribe each created local audio track to\r\n        // RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED event. This is different from\r\n        // handling this event for remote tracks (which are handled in RTC.js),\r\n        // because there might be local tracks not attached to a conference.\r\n        if (this.isAudioTrack() && RTCUtils.isDeviceChangeAvailable('output')) {\r\n            this._onAudioOutputDeviceChanged = this.setAudioOutput.bind(this);\r\n            RTCUtils.addListener(\r\n                RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\r\n                this._onAudioOutputDeviceChanged);\r\n        }\r\n\r\n        RTCUtils.addListener(RTCEvents.DEVICE_LIST_WILL_CHANGE, this._onDeviceListWillChange);\r\n\r\n        this._initNoDataFromSourceHandlers();\r\n    }\r\n\r\n    /**\r\n     * Adds stream to conference and marks it as \"unmute\" operation.\r\n     *\r\n     * @private\r\n     * @returns {Promise}\r\n     */\r\n    _addStreamToConferenceAsUnmute() {\r\n        if (!this.conference) {\r\n            return Promise.resolve();\r\n        }\r\n\r\n        // FIXME it would be good to not included conference as part of this process. Only TraceablePeerConnections to\r\n        // which the track is attached should care about this action. The TPCs to which the track is not attached can\r\n        // sync up when track is re-attached. A problem with that is that the \"modify sources\" queue is part of the\r\n        // JingleSessionPC and it would be excluded from the process. One solution would be to extract class between\r\n        // TPC and JingleSessionPC which would contain the queue and would notify the signaling layer when local SSRCs\r\n        // are changed. This would help to separate XMPP from the RTC module.\r\n        return new Promise((resolve, reject) => {\r\n            this.conference._addLocalTrackToPc(this)\r\n                .then(resolve, error => reject(new Error(error)));\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Fires NO_DATA_FROM_SOURCE event and logs it to analytics and callstats.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _fireNoDataFromSourceEvent() {\r\n        const value = !this.isReceivingData();\r\n\r\n        this.emit(NO_DATA_FROM_SOURCE, value);\r\n\r\n        // FIXME: Should we report all of those events\r\n        Statistics.sendAnalytics(createNoDataFromSourceEvent(this.getType(), value));\r\n        Statistics.sendLog(JSON.stringify({\r\n            name: NO_DATA_FROM_SOURCE,\r\n            log: value\r\n        }));\r\n    }\r\n\r\n    /**\r\n     * Sets handlers to the MediaStreamTrack object that will detect camera issues.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _initNoDataFromSourceHandlers() {\r\n        if (!this._isNoDataFromSourceEventsEnabled()) {\r\n            return;\r\n        }\r\n\r\n        this._setHandler('track_mute', () => {\r\n            this._trackMutedTS = window.performance.now();\r\n            this._fireNoDataFromSourceEvent();\r\n        });\r\n\r\n        this._setHandler('track_unmute', () => {\r\n            this._fireNoDataFromSourceEvent();\r\n            Statistics.sendAnalyticsAndLog(\r\n                TRACK_UNMUTED,\r\n                {\r\n                    'media_type': this.getType(),\r\n                    'track_type': 'local',\r\n                    value: window.performance.now() - this._trackMutedTS\r\n                });\r\n        });\r\n\r\n        if (this.isVideoTrack() && this.videoType === VideoType.CAMERA) {\r\n            this._setHandler('track_ended', () => {\r\n                if (!this.isReceivingData()) {\r\n                    this._fireNoDataFromSourceEvent();\r\n                }\r\n            });\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns true if no data from source events are enabled for this JitsiLocalTrack and false otherwise.\r\n     *\r\n     * @private\r\n     * @returns {boolean} - True if no data from source events are enabled for this JitsiLocalTrack and false otherwise.\r\n     */\r\n    _isNoDataFromSourceEventsEnabled() {\r\n        // Disable the events for screen sharing.\r\n        return !this.isVideoTrack() || this.videoType !== VideoType.DESKTOP;\r\n    }\r\n\r\n    /**\r\n     * Initializes a new Promise to execute {@link #_setMuted}. May be called multiple times in a row and the\r\n     * invocations of {@link #_setMuted} and, consequently, {@link #mute} and/or {@link #unmute} will be resolved in a\r\n     * serialized fashion.\r\n     *\r\n     * @param {boolean} muted - The value to invoke <tt>_setMuted</tt> with.\r\n     * @private\r\n     * @returns {Promise}\r\n     */\r\n    _queueSetMuted(muted) {\r\n        const setMuted = this._setMuted.bind(this, muted);\r\n\r\n        this._prevSetMuted = this._prevSetMuted.then(setMuted, setMuted);\r\n\r\n        return this._prevSetMuted;\r\n    }\r\n\r\n    /**\r\n     * Removes stream from conference and marks it as \"mute\" operation.\r\n     *\r\n     * @param {Function} successCallback - Callback that will be called when the operation is successful.\r\n     * @param {Function} errorCallback - Callback that will be called when the operation fails.\r\n     * @private\r\n     * @returns {Promise}\r\n     */\r\n    _removeStreamFromConferenceAsMute(successCallback, errorCallback) {\r\n        if (!this.conference) {\r\n            successCallback();\r\n\r\n            return;\r\n        }\r\n        this.conference._removeLocalTrackFromPc(this).then(\r\n            successCallback,\r\n            error => errorCallback(new Error(error)));\r\n    }\r\n\r\n    /**\r\n     * Sends mute status for a track to conference if any.\r\n     *\r\n     * @param {boolean} mute - If track is muted.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _sendMuteStatus(mute) {\r\n        if (this.conference) {\r\n            this.conference._setTrackMuteStatus(this.getType(), this, mute) && this.conference.room.sendPresence();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Mutes / unmutes this track.\r\n     *\r\n     * @param {boolean} muted - If <tt>true</tt>, this track will be muted; otherwise, this track will be unmuted.\r\n     * @private\r\n     * @returns {Promise}\r\n     */\r\n    _setMuted(muted) {\r\n        if (this.isMuted() === muted\r\n            && !(this.videoType === VideoType.DESKTOP && FeatureFlags.isMultiStreamSendSupportEnabled())) {\r\n            return Promise.resolve();\r\n        }\r\n\r\n        if (this.disposed) {\r\n            return Promise.reject(new JitsiTrackError(TRACK_IS_DISPOSED));\r\n        }\r\n\r\n        let promise = Promise.resolve();\r\n\r\n        // A function that will print info about muted status transition\r\n        const logMuteInfo = () => logger.info(`Mute ${this}: ${muted}`);\r\n\r\n        // In the multi-stream mode, desktop tracks are muted from jitsi-meet instead of being removed from the\r\n        // conference. This is needed because we don't want the client to signal a source-remove to the remote peer for\r\n        // the desktop track when screenshare is stopped. Later when screenshare is started again, the same sender will\r\n        // be re-used without the need for signaling a new ssrc through source-add.\r\n        if (this.isAudioTrack()\r\n                || (this.videoType === VideoType.DESKTOP && !FeatureFlags.isMultiStreamSendSupportEnabled())\r\n                || !browser.doesVideoMuteByStreamRemove()) {\r\n            logMuteInfo();\r\n\r\n            // If we have a stream effect that implements its own mute functionality, prioritize it before\r\n            // normal mute e.g. the stream effect that implements system audio sharing has a custom\r\n            // mute state in which if the user mutes, system audio still has to go through.\r\n            if (this._streamEffect && this._streamEffect.setMuted) {\r\n                this._streamEffect.setMuted(muted);\r\n            } else if (this.track) {\r\n                this.track.enabled = !muted;\r\n            }\r\n        } else if (muted) {\r\n            promise = new Promise((resolve, reject) => {\r\n                logMuteInfo();\r\n                this._removeStreamFromConferenceAsMute(\r\n                    () => {\r\n                        if (this._streamEffect) {\r\n                            this._stopStreamEffect();\r\n                        }\r\n\r\n                        // FIXME: Maybe here we should set the SRC for the\r\n                        // containers to something\r\n                        // We don't want any events to be fired on this stream\r\n                        this._unregisterHandlers();\r\n                        this.stopStream();\r\n                        this._setStream(null);\r\n\r\n                        resolve();\r\n                    },\r\n                    reject);\r\n            });\r\n        } else {\r\n            logMuteInfo();\r\n\r\n            // This path is only for camera.\r\n            const streamOptions = {\r\n                cameraDeviceId: this.getDeviceId(),\r\n                devices: [ MediaType.VIDEO ],\r\n                effects: this._streamEffect ? [ this._streamEffect ] : [],\r\n                facingMode: this.getCameraFacingMode()\r\n            };\r\n\r\n            promise\r\n                = RTCUtils.obtainAudioAndVideoPermissions(Object.assign(\r\n                    {},\r\n                    streamOptions,\r\n                    { constraints: { video: this._constraints } }));\r\n\r\n            promise = promise.then(streamsInfo => {\r\n                const streamInfo = streamsInfo.find(info => info.track.kind === this.getType());\r\n\r\n                if (streamInfo) {\r\n                    this._setStream(streamInfo.stream);\r\n                    this.track = streamInfo.track;\r\n\r\n                    // This is not good when video type changes after\r\n                    // unmute, but let's not crash here\r\n                    if (this.videoType !== streamInfo.videoType) {\r\n                        logger.warn(\r\n                            `${this}: video type has changed after unmute!`,\r\n                            this.videoType, streamInfo.videoType);\r\n                        this.videoType = streamInfo.videoType;\r\n                    }\r\n                } else {\r\n                    throw new JitsiTrackError(TRACK_NO_STREAM_FOUND);\r\n                }\r\n\r\n                if (this._streamEffect) {\r\n                    this._startStreamEffect(this._streamEffect);\r\n                }\r\n\r\n                this.containers.map(cont => RTCUtils.attachMediaStream(cont, this.stream));\r\n\r\n                return this._addStreamToConferenceAsUnmute();\r\n            });\r\n        }\r\n\r\n        return promise\r\n            .then(() => {\r\n                this._sendMuteStatus(muted);\r\n\r\n                // Send the videoType message to the bridge.\r\n                this.isVideoTrack() && this.conference && this.conference._sendBridgeVideoTypeMessage(this);\r\n                this.emit(TRACK_MUTE_CHANGED, this);\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Sets real device ID by comparing track information with device information. This is temporary solution until\r\n     * getConstraints() method will be implemented in browsers.\r\n     *\r\n     * @param {MediaDeviceInfo[]} devices - The list of devices obtained from enumerateDevices() call.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _setRealDeviceIdFromDeviceList(devices) {\r\n        const track = this.getTrack();\r\n        const kind = `${track.kind}input`;\r\n\r\n        // We need to match by deviceId as well, in case of multiple devices with the same label.\r\n        let device = devices.find(d => d.kind === kind && d.label === track.label && d.deviceId === this.deviceId);\r\n\r\n        if (!device && this._realDeviceId === 'default') { // the default device has been changed.\r\n            // If the default device was 'A' and the default device is changed to 'B' the label for the track will\r\n            // remain 'Default - A' but the label for the device in the device list will be updated to 'A'. That's\r\n            // why in order to match it we need to remove the 'Default - ' part.\r\n            const label = (track.label || '').replace('Default - ', '');\r\n\r\n            device = devices.find(d => d.kind === kind && d.label === label);\r\n        }\r\n\r\n        if (device) {\r\n            this._realDeviceId = device.deviceId;\r\n        } else {\r\n            this._realDeviceId = undefined;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets the stream property of JitsiLocalTrack object and sets all stored handlers to it.\r\n     *\r\n     * @param {MediaStream} stream - The new MediaStream.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _setStream(stream) {\r\n        super._setStream(stream);\r\n\r\n        if (stream) {\r\n            // Store the MSID for video mute/unmute purposes.\r\n            this.storedMSID = this.getMSID();\r\n            logger.debug(`Setting new MSID: ${this.storedMSID} on ${this}`);\r\n        } else {\r\n            logger.debug(`Setting 'null' stream on ${this}`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Starts the effect process and returns the modified stream.\r\n     *\r\n     * @param {Object} effect - Represents effect instance\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _startStreamEffect(effect) {\r\n        this._streamEffect = effect;\r\n        this._originalStream = this.stream;\r\n        this._setStream(this._streamEffect.startEffect(this._originalStream));\r\n        this.track = this.stream.getTracks()[0];\r\n    }\r\n\r\n    /**\r\n     * Stops the effect process and returns the original stream.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _stopStreamEffect() {\r\n        if (this._streamEffect) {\r\n            this._streamEffect.stopEffect();\r\n            this._setStream(this._originalStream);\r\n            this._originalStream = null;\r\n            this.track = this.stream ? this.stream.getTracks()[0] : null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Switches the camera facing mode if the WebRTC implementation supports the custom MediaStreamTrack._switchCamera\r\n     * method. Currently, the method in question is implemented in react-native-webrtc only. When such a WebRTC\r\n     * implementation is executing, the method is the preferred way to switch between the front/user-facing and the\r\n     * back/environment-facing cameras because it will likely be (as is the case of react-native-webrtc) noticeably\r\n     * faster that creating a new MediaStreamTrack via a new getUserMedia call with the switched facingMode constraint\r\n     * value. Moreover, the approach with a new getUserMedia call may not even work: WebRTC on Android and iOS is\r\n     * either very slow to open the camera a second time or plainly freezes attempting to do that.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    _switchCamera() {\r\n        if (this.isVideoTrack()\r\n                && this.videoType === VideoType.CAMERA\r\n                && typeof this.track._switchCamera === 'function') {\r\n            this.track._switchCamera();\r\n\r\n            this._facingMode\r\n                = this._facingMode === CameraFacingMode.ENVIRONMENT\r\n                    ? CameraFacingMode.USER\r\n                    : CameraFacingMode.ENVIRONMENT;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Stops the currently used effect (if there is one) and starts the passed effect (if there is one).\r\n     *\r\n     * @param {Object|undefined} effect - The new effect to be set.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _switchStreamEffect(effect) {\r\n        if (this._streamEffect) {\r\n            this._stopStreamEffect();\r\n            this._streamEffect = undefined;\r\n        }\r\n        if (effect) {\r\n            this._startStreamEffect(effect);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @inheritdoc\r\n     *\r\n     * Stops sending the media track. And removes it from the HTML. NOTE: Works for local tracks only.\r\n     *\r\n     * @extends JitsiTrack#dispose\r\n     * @returns {Promise}\r\n     */\r\n    async dispose() {\r\n\r\n        // Remove the effect instead of stopping it so that the original stream is restored\r\n        // on both the local track and on the peerconnection.\r\n        if (this._streamEffect) {\r\n            await this.setEffect();\r\n        }\r\n\r\n        if (this.conference) {\r\n            await this.conference.removeTrack(this);\r\n        }\r\n\r\n        if (this.stream) {\r\n            this.stopStream();\r\n            this.detach();\r\n        }\r\n\r\n        RTCUtils.removeListener(RTCEvents.DEVICE_LIST_WILL_CHANGE, this._onDeviceListWillChange);\r\n\r\n        if (this._onAudioOutputDeviceChanged) {\r\n            RTCUtils.removeListener(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\r\n                this._onAudioOutputDeviceChanged);\r\n        }\r\n\r\n        return super.dispose();\r\n    }\r\n\r\n    /**\r\n     * Returns facing mode for video track from camera. For other cases (e.g. audio track or 'desktop' video track)\r\n     * returns undefined.\r\n     *\r\n     * @returns {CameraFacingMode|undefined}\r\n     */\r\n    getCameraFacingMode() {\r\n        if (this.isVideoTrack() && this.videoType === VideoType.CAMERA) {\r\n            // MediaStreamTrack#getSettings() is not implemented in many\r\n            // browsers, so we need feature checking here. Progress on the\r\n            // respective browser's implementation can be tracked at\r\n            // https://bugs.chromium.org/p/webrtc/issues/detail?id=2481 for\r\n            // Chromium and https://bugzilla.mozilla.org/show_bug.cgi?id=1213517\r\n            // for Firefox. Even if a browser implements getSettings() already,\r\n            // it might still not return anything for 'facingMode'.\r\n            const trackSettings = this.track.getSettings?.();\r\n\r\n            if (trackSettings && 'facingMode' in trackSettings) {\r\n                return trackSettings.facingMode;\r\n            }\r\n\r\n            if (typeof this._facingMode !== 'undefined') {\r\n                return this._facingMode;\r\n            }\r\n\r\n            // In most cases we are showing a webcam. So if we've gotten here,\r\n            // it should be relatively safe to assume that we are probably\r\n            // showing the user-facing camera.\r\n            return CameraFacingMode.USER;\r\n        }\r\n\r\n        return undefined;\r\n    }\r\n\r\n    /**\r\n     * Returns device id associated with track.\r\n     *\r\n     * @returns {string}\r\n     */\r\n    getDeviceId() {\r\n        return this._realDeviceId || this.deviceId;\r\n    }\r\n\r\n    /**\r\n     * Get the duration of the track.\r\n     *\r\n     * @returns {Number} the duration of the track in seconds\r\n     */\r\n    getDuration() {\r\n        return (Date.now() / 1000) - (this.metadata.timestamp / 1000);\r\n    }\r\n\r\n    /**\r\n     * Returns the participant id which owns the track.\r\n     *\r\n     * @returns {string} the id of the participants. It corresponds to the\r\n     * Colibri endpoint id/MUC nickname in case of Jitsi-meet.\r\n     */\r\n    getParticipantId() {\r\n        return this.conference && this.conference.myUserId();\r\n    }\r\n\r\n    /**\r\n     * Returns the source name associated with the jitsi track.\r\n     *\r\n     * @returns {string | null} source name\r\n     */\r\n    getSourceName() {\r\n        return this._sourceName;\r\n    }\r\n\r\n    /**\r\n     * Returns if associated MediaStreamTrack is in the 'ended' state\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isEnded() {\r\n        if (this.isVideoTrack() && this.isMuted()) {\r\n            // If a video track is muted the readyState will be ended, that's why we need to rely only on the\r\n            // _trackEnded flag.\r\n            return this._trackEnded;\r\n        }\r\n\r\n        return this.getTrack().readyState === 'ended' || this._trackEnded;\r\n    }\r\n\r\n    /**\r\n     * Returns <tt>true</tt>.\r\n     *\r\n     * @returns {boolean} <tt>true</tt>\r\n     */\r\n    isLocal() {\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * Returns <tt>true</tt> - if the stream is muted and <tt>false</tt> otherwise.\r\n     *\r\n     * @returns {boolean} <tt>true</tt> - if the stream is muted and <tt>false</tt> otherwise.\r\n     */\r\n    isMuted() {\r\n        // this.stream will be null when we mute local video on Chrome\r\n        if (!this.stream) {\r\n            return true;\r\n        }\r\n        if (this.isVideoTrack() && !this.isActive()) {\r\n            return true;\r\n        }\r\n\r\n        // If currently used stream effect has its own muted state, use that.\r\n        if (this._streamEffect && this._streamEffect.isMuted) {\r\n            return this._streamEffect.isMuted();\r\n        }\r\n\r\n        return !this.track || !this.track.enabled;\r\n    }\r\n\r\n    /**\r\n     * Checks whether the attached MediaStream is receiving data from source or not. If the stream property is null\r\n     * (because of mute or another reason) this method will return false.\r\n     * NOTE: This method doesn't indicate problem with the streams directly. For example in case of video mute the\r\n     * method will return false or if the user has disposed the track.\r\n     *\r\n     * @returns {boolean} true if the stream is receiving data and false this otherwise.\r\n     */\r\n    isReceivingData() {\r\n        if (this.isVideoTrack()\r\n            && (this.isMuted() || this._stopStreamInProgress || this.videoType === VideoType.DESKTOP)) {\r\n            return true;\r\n        }\r\n\r\n        if (!this.stream) {\r\n            return false;\r\n        }\r\n\r\n        // In older version of the spec there is no muted property and readyState can have value muted. In the latest\r\n        // versions readyState can have values \"live\" and \"ended\" and there is muted boolean property. If the stream is\r\n        // muted that means that we aren't receiving any data from the source. We want to notify the users for error if\r\n        // the stream is muted or ended on it's creation.\r\n\r\n        // For video blur enabled use the original video stream\r\n        const stream = this._effectEnabled ? this._originalStream : this.stream;\r\n\r\n        return stream.getTracks().some(track =>\r\n            (!('readyState' in track) || track.readyState === 'live')\r\n                && (!('muted' in track) || track.muted !== true));\r\n    }\r\n\r\n    /**\r\n     * Asynchronously mutes this track.\r\n     *\r\n     * @returns {Promise}\r\n     */\r\n    mute() {\r\n        return this._queueSetMuted(true);\r\n    }\r\n\r\n    /**\r\n     * Handles bytes sent statistics. NOTE: used only for audio tracks to detect audio issues.\r\n     *\r\n     * @param {TraceablePeerConnection} tpc - The peerconnection that is reporting the bytes sent stat.\r\n     * @param {number} bytesSent - The new value.\r\n     * @returns {void}\r\n     */\r\n    onByteSentStatsReceived(tpc, bytesSent) {\r\n        if (bytesSent > 0) {\r\n            this._hasSentData = true;\r\n        }\r\n        const iceConnectionState = tpc.getConnectionState();\r\n\r\n        if (this._testDataSent && iceConnectionState === 'connected') {\r\n            setTimeout(() => {\r\n                if (!this._hasSentData) {\r\n                    logger.warn(`${this} 'bytes sent' <= 0: \\\r\n                        ${bytesSent}`);\r\n\r\n                    Statistics.analytics.sendEvent(NO_BYTES_SENT, { 'media_type': this.getType() });\r\n                }\r\n            }, 3000);\r\n            this._testDataSent = false;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets the JitsiConference object associated with the track. This is temp solution.\r\n     *\r\n     * @param conference - JitsiConference object.\r\n     * @returns {void}\r\n     */\r\n    setConference(conference) {\r\n        this.conference = conference;\r\n\r\n        // We want to keep up with postponed events which should have been fired\r\n        // on \"attach\" call, but for local track we not always have the\r\n        // conference before attaching. However this may result in duplicated\r\n        // events if they have been triggered on \"attach\" already.\r\n        for (let i = 0; i < this.containers.length; i++) {\r\n            this._maybeFireTrackAttached(this.containers[i]);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets the effect and switches between the modified stream and original one.\r\n     *\r\n     * @param {Object} effect - Represents the effect instance to be used.\r\n     * @returns {Promise}\r\n     */\r\n    setEffect(effect) {\r\n        if (typeof this._streamEffect === 'undefined' && typeof effect === 'undefined') {\r\n            return Promise.resolve();\r\n        }\r\n\r\n        if (typeof effect !== 'undefined' && !effect.isEnabled(this)) {\r\n            return Promise.reject(new Error('Incompatible effect instance!'));\r\n        }\r\n\r\n        if (this._setEffectInProgress === true) {\r\n            return Promise.reject(new Error('setEffect already in progress!'));\r\n        }\r\n\r\n        // In case we have an audio track that is being enhanced with an effect, we still want it to be applied,\r\n        // even if the track is muted. Where as for video the actual track doesn't exists if it's muted.\r\n        if (this.isMuted() && !this.isAudioTrack()) {\r\n            this._streamEffect = effect;\r\n\r\n            return Promise.resolve();\r\n        }\r\n\r\n        const conference = this.conference;\r\n\r\n        if (!conference) {\r\n            this._switchStreamEffect(effect);\r\n            if (this.isVideoTrack()) {\r\n                this.containers.forEach(cont => RTCUtils.attachMediaStream(cont, this.stream));\r\n            }\r\n\r\n            return Promise.resolve();\r\n        }\r\n\r\n        this._setEffectInProgress = true;\r\n\r\n        return conference._removeLocalTrackFromPc(this)\r\n            .then(() => {\r\n                this._switchStreamEffect(effect);\r\n                if (this.isVideoTrack()) {\r\n                    this.containers.forEach(cont => RTCUtils.attachMediaStream(cont, this.stream));\r\n                }\r\n\r\n                return conference._addLocalTrackToPc(this);\r\n            })\r\n            .then(() => {\r\n                this._setEffectInProgress = false;\r\n            })\r\n            .catch(error => {\r\n                // Any error will be not recovarable and will trigger CONFERENCE_FAILED event. But let's try to cleanup\r\n                // everyhting related to the effect functionality.\r\n                this._setEffectInProgress = false;\r\n                this._switchStreamEffect();\r\n                logger.error('Failed to switch to the new stream!', error);\r\n                throw error;\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Sets the source name to be used for signaling the jitsi track.\r\n     *\r\n     * @param {string} name The source name.\r\n     */\r\n    setSourceName(name) {\r\n        this._sourceName = name;\r\n    }\r\n\r\n    /**\r\n     * Stops the associated MediaStream.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    stopStream() {\r\n        /**\r\n         * Indicates that we are executing {@link #stopStream} i.e.\r\n         * {@link RTCUtils#stopMediaStream} for the <tt>MediaStream</tt>\r\n         * associated with this <tt>JitsiTrack</tt> instance.\r\n         *\r\n         * @private\r\n         * @type {boolean}\r\n         */\r\n        this._stopStreamInProgress = true;\r\n\r\n        try {\r\n            RTCUtils.stopMediaStream(this.stream);\r\n        } finally {\r\n            this._stopStreamInProgress = false;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Creates a text representation of this local track instance.\r\n     *\r\n     * @return {string}\r\n     */\r\n    toString() {\r\n        return `LocalTrack[${this.rtcId},${this.getType()}]`;\r\n    }\r\n\r\n    /**\r\n     * Asynchronously unmutes this track.\r\n     *\r\n     * @returns {Promise}\r\n     */\r\n    unmute() {\r\n        return this._queueSetMuted(false);\r\n    }\r\n}\r\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 {\r\n    /**\r\n     * Event triggered when participant's muted status changes.\r\n     *\r\n     * @param {string} endpointId the track owner's identifier (MUC nickname)\r\n     * @param {MediaType} mediaType \"audio\" or \"video\"\r\n     * @param {boolean} isMuted the new muted state\r\n     */\r\n    PEER_MUTED_CHANGED = 'signaling.peerMuted',\r\n\r\n    /**\r\n     * Event triggered when participant's video type changes.\r\n     *\r\n     * @param {string} endpointId the video owner's ID (MUC nickname)\r\n     * @param {VideoType} videoType the new value\r\n     */\r\n    PEER_VIDEO_TYPE_CHANGED = 'signaling.peerVideoType',\r\n\r\n    /**\r\n     * Event triggered when source's muted status changes.\r\n     *\r\n     * @param {string} sourceName - The name of the source.\r\n     * @param {boolean} isMuted - The new muted state.\r\n     */\r\n    SOURCE_MUTED_CHANGED = 'signaling.sourceMuted',\r\n\r\n    /**\r\n     * Event triggered when source's video type changes.\r\n     *\r\n     * @param {string} source - The name of the source.\r\n     * @param {VideoType} videoType - The new value.\r\n     */\r\n    SOURCE_VIDEO_TYPE_CHANGED = 'signaling.sourceVideoType'\r\n}\r\n\r\n// exported for backward compatibility\r\nexport const PEER_MUTED_CHANGED = SignalingEvents.PEER_MUTED_CHANGED;\r\nexport const PEER_VIDEO_TYPE_CHANGED = SignalingEvents.PEER_VIDEO_TYPE_CHANGED;\r\nexport const SOURCE_MUTED_CHANGED = SignalingEvents.SOURCE_MUTED_CHANGED;\r\nexport const SOURCE_VIDEO_TYPE_CHANGED = SignalingEvents.SOURCE_VIDEO_TYPE_CHANGED;\r\n","\r\nimport Listenable from '../../modules/util/Listenable';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\n\r\n/**\r\n * @typedef {string} EndpointId\r\n */\r\n/**\r\n * @typedef {string} SourceName\r\n */\r\n/**\r\n * @typedef {Object} SourceInfo\r\n *\r\n * @property {SourceName} sourceName - Name of the media source.\r\n * @property {boolean} [muted=false] - Tells if the source is muted (paused?).\r\n * @property {string} [videoType] - Type of the video for video type.\r\n */\r\n\r\n/**\r\n * Generates a source name.\r\n *\r\n * @param {EndpointId} endpointId - Jitsi Endpoint Id.\r\n * @param {MediaType} mediaType - the media type string.\r\n * @param {number} trackIdx - Track index (or sender idx? - to be figured out) starting from 0.\r\n * @returns {SourceName} eg. endpointA-v0\r\n */\r\nexport function getSourceNameForJitsiTrack(endpointId, mediaType, trackIdx) {\r\n    const firstLetterOfMediaType = mediaType.substring(0, 1);\r\n\r\n    return `${endpointId}-${firstLetterOfMediaType}${trackIdx}`;\r\n}\r\n\r\n/**\r\n * Extracts MediaType from give source name (must be in the correct format as generated by\r\n * {@link getSourceNameForJitsiTrack}).\r\n *\r\n * @param {SourceName} sourceName - the source name.\r\n * @returns {MediaType}\r\n */\r\nexport function getMediaTypeFromSourceName(sourceName) {\r\n    const firstLetterOfMediaTypeIdx = sourceName.lastIndexOf('-') + 1;\r\n\r\n    if (firstLetterOfMediaTypeIdx <= 0) {\r\n        throw new Error(`Invalid source name: ${sourceName}`);\r\n    }\r\n\r\n    const firstLetterOfMediaType = sourceName.substr(firstLetterOfMediaTypeIdx, 1);\r\n\r\n    for (const type of Object.values(MediaType)) {\r\n        if (type.substr(0, 1) === firstLetterOfMediaType) {\r\n            return type;\r\n        }\r\n    }\r\n\r\n    throw new Error(`Invalid source name: ${sourceName}`);\r\n}\r\n\r\n/**\r\n * Extracts source index (zero based) from a given source name (must be in the correct format as generated by\r\n * {@link getSourceNameForJitsiTrack}).\r\n *\r\n * @param {SourceName} sourceName - the source name, eg. endpointA-v0.\r\n * @returns {number}\r\n */\r\nexport function getSourceIndexFromSourceName(sourceName) {\r\n    const nameParts = sourceName.split('-');\r\n    const trackIdx = Number(nameParts[nameParts.length - 1].substring(1));\r\n\r\n    if (Number.isNaN(trackIdx)) {\r\n        throw new Error(`Failed to parse track idx for source name: ${sourceName}`);\r\n    }\r\n\r\n    return trackIdx;\r\n}\r\n\r\n/**\r\n * An object that carries the info about specific media type advertised by\r\n * participant in the signaling channel.\r\n * @typedef {Object} PeerMediaInfo\r\n * @property {boolean} muted indicates if the media is currently muted\r\n * @property {VideoType|undefined} videoType the type of the video if applicable\r\n */\r\n\r\n/**\r\n * Interface used to expose the information carried over the signaling channel\r\n * which is not available to the RTC module in the media SDP.\r\n *\r\n * @interface SignalingLayer\r\n */\r\nexport default class SignalingLayer extends Listenable {\r\n\r\n    /**\r\n     * Obtains the endpoint ID for given SSRC.\r\n     * @param {number} ssrc the SSRC number.\r\n     * @return {string|null} the endpoint ID for given media SSRC.\r\n     */\r\n    getSSRCOwner(ssrc) { // eslint-disable-line no-unused-vars\r\n        throw new Error('not implemented');\r\n    }\r\n\r\n    /**\r\n     * Obtains the info about given media advertised in the MUC presence of\r\n     * the participant identified by the given MUC JID.\r\n     * @param {string} owner the MUC jid of the participant for whom\r\n     * {@link PeerMediaInfo} will be obtained.\r\n     * @param {MediaType} mediaType the type of the media for which presence\r\n     * @param {SourceName} sourceName - The name of the source for which the info is to be obtained.\r\n     * info will be obtained.\r\n     * @return {PeerMediaInfo|null} presenceInfo an object with media presence\r\n     * info or <tt>null</tt> either if there is no presence available for given\r\n     * JID or if the media type given is invalid.\r\n     *\r\n     * @deprecated This method is to be replaced with getPeerSourceInfo.\r\n     */\r\n    getPeerMediaInfo(owner, mediaType, sourceName) { // eslint-disable-line no-unused-vars\r\n        throw new Error('not implemented');\r\n    }\r\n\r\n    /**\r\n     * Obtains the info about a source for given name and endpoint ID.\r\n     * @param {EndpointId} owner - The owner's endpoint ID.\r\n     * @param {SourceName} sourceName - The name of the source for which the info is to be obtained.\r\n     * @returns {SourceInfo | undefined}\r\n     */\r\n    getPeerSourceInfo(owner, sourceName) { // eslint-disable-line no-unused-vars\r\n        throw new Error('not implemented');\r\n    }\r\n\r\n    /**\r\n     * Obtains the source name for given SSRC.\r\n     * @param {number} ssrc the track's SSRC identifier.\r\n     * @returns {SourceName | undefined} the track's source name.\r\n     */\r\n    getTrackSourceName(ssrc) { // eslint-disable-line no-unused-vars\r\n        throw new Error('not implemented');\r\n    }\r\n\r\n    /**\r\n     * Set an SSRC owner.\r\n     * @param {number} ssrc an SSRC to be owned\r\n     * @param {string} endpointId owner's ID (MUC nickname)\r\n     * @throws TypeError if <tt>ssrc</tt> is not a number\r\n     */\r\n    setSSRCOwner(ssrc, endpointId) { // eslint-disable-line no-unused-vars\r\n    }\r\n\r\n\r\n    /**\r\n     * Adjusts muted status of given track.\r\n     *\r\n     * @param {SourceName} sourceName - the name of the track's source.\r\n     * @param {boolean} muted - the new muted status.\r\n     * @returns {boolean}\r\n     */\r\n    setTrackMuteStatus(sourceName, muted) { // eslint-disable-line no-unused-vars\r\n    }\r\n\r\n    /**\r\n     * Saves the source name for a track identified by it's ssrc.\r\n     * @param {number} ssrc the ssrc of the target track.\r\n     * @param {SourceName} sourceName the track's source name to save.\r\n     * @throws TypeError if <tt>ssrc</tt> is not a number\r\n     */\r\n    setTrackSourceName(ssrc, sourceName) { // eslint-disable-line no-unused-vars\r\n    }\r\n\r\n    /**\r\n     * Sets track's video type.\r\n     * @param {SourceName} sourceName - the track's source name.\r\n     * @param {VideoType} videoType - the new video type.\r\n     * @returns {boolean}\r\n     */\r\n    setTrackVideoType(sourceName, videoType) { // eslint-disable-line no-unused-vars\r\n    }\r\n}\r\n","import * as transform from 'sdp-transform';\r\n\r\n/**\r\n * Parses the primary SSRC of given SSRC group.\r\n * @param {object} group the SSRC group object as defined by the 'sdp-transform'\r\n * @return {Number} the primary SSRC number\r\n */\r\nexport function parsePrimarySSRC(group) {\r\n    return parseInt(group.ssrcs.split(' ')[0], 10);\r\n}\r\n\r\n/**\r\n * Parses the secondary SSRC of given SSRC group.\r\n * @param {object} group the SSRC group object as defined by the 'sdp-transform'\r\n * @return {Number} the secondary SSRC number\r\n */\r\nexport function parseSecondarySSRC(group) {\r\n    return parseInt(group.ssrcs.split(' ')[1], 10);\r\n}\r\n\r\n/**\r\n * Tells how many distinct SSRCs are contained in given media line.\r\n * @param {Object} mLine the media line object as defined by 'sdp-transform' lib\r\n * @return {number}\r\n */\r\nfunction _getSSRCCount(mLine) {\r\n    if (!mLine.ssrcs) {\r\n        return 0;\r\n    }\r\n\r\n    return mLine.ssrcs\r\n        .map(ssrcInfo => ssrcInfo.id)\r\n        .filter((ssrc, index, array) => array.indexOf(ssrc) === index)\r\n        .length;\r\n}\r\n\r\n/**\r\n * A wrapper around 'sdp-transform' media description object which provides\r\n * utility methods for common SDP/SSRC related operations.\r\n */\r\nclass MLineWrap {\r\n\r\n    /**\r\n     * Creates new <tt>MLineWrap</t>>\r\n     * @param {Object} mLine the media line object as defined by 'sdp-transform'\r\n     * lib.\r\n     */\r\n    constructor(mLine) {\r\n        if (!mLine) {\r\n            throw new Error('mLine is undefined');\r\n        }\r\n\r\n        this.mLine = mLine;\r\n    }\r\n\r\n    /**\r\n     * Getter for the mLine's \"ssrcs\" array. If the array was undefined an empty\r\n     * one will be preassigned.\r\n     *\r\n     * @return {Array<Object>} an array of 'sdp-transform' SSRC attributes\r\n     * objects.\r\n     */\r\n    get ssrcs() {\r\n        if (!this.mLine.ssrcs) {\r\n            this.mLine.ssrcs = [];\r\n        }\r\n\r\n        return this.mLine.ssrcs;\r\n    }\r\n\r\n    /**\r\n     * Setter for the mLine's \"ssrcs\" array.\r\n     *\r\n     * @param {Array<Object>} ssrcs an array of 'sdp-transform' SSRC attributes\r\n     * objects.\r\n     */\r\n    set ssrcs(ssrcs) {\r\n        this.mLine.ssrcs = ssrcs;\r\n    }\r\n\r\n    /**\r\n     * Returns the direction of the underlying media description.\r\n     * @return {string} the media direction name as defined in the SDP.\r\n     */\r\n    get direction() {\r\n        return this.mLine.direction;\r\n    }\r\n\r\n    /**\r\n     * Modifies the direction of the underlying media description.\r\n     * @param {string} direction the new direction to be set\r\n     */\r\n    set direction(direction) {\r\n        this.mLine.direction = direction;\r\n    }\r\n\r\n    /**\r\n     * Exposes the SSRC group array of the underlying media description object.\r\n     * @return {Array.<Object>}\r\n     */\r\n    get ssrcGroups() {\r\n        if (!this.mLine.ssrcGroups) {\r\n            this.mLine.ssrcGroups = [];\r\n        }\r\n\r\n        return this.mLine.ssrcGroups;\r\n    }\r\n\r\n    /**\r\n     * Modifies the SSRC groups array of the underlying media description\r\n     * object.\r\n     * @param {Array.<Object>} ssrcGroups\r\n     */\r\n    set ssrcGroups(ssrcGroups) {\r\n        this.mLine.ssrcGroups = ssrcGroups;\r\n    }\r\n\r\n    /**\r\n     * Obtains value from SSRC attribute.\r\n     * @param {number} ssrcNumber the SSRC number for which attribute is to be\r\n     * found\r\n     * @param {string} attrName the name of the SSRC attribute to be found.\r\n     * @return {string|undefined} the value of SSRC attribute or\r\n     * <tt>undefined</tt> if no such attribute exists.\r\n     */\r\n    getSSRCAttrValue(ssrcNumber, attrName) {\r\n        const attribute = this.ssrcs.find(\r\n            ssrcObj => ssrcObj.id === ssrcNumber\r\n            && ssrcObj.attribute === attrName);\r\n\r\n\r\n        return attribute && attribute.value;\r\n    }\r\n\r\n    /**\r\n     * Removes all attributes for given SSRC number.\r\n     * @param {number} ssrcNum the SSRC number for which all attributes will be\r\n     * removed.\r\n     */\r\n    removeSSRC(ssrcNum) {\r\n        if (!this.mLine.ssrcs || !this.mLine.ssrcs.length) {\r\n            return;\r\n        }\r\n\r\n        this.mLine.ssrcs\r\n            = this.mLine.ssrcs.filter(ssrcObj => ssrcObj.id !== ssrcNum);\r\n    }\r\n\r\n    /**\r\n     * Adds SSRC attribute\r\n     * @param {object} ssrcObj the SSRC attribute object as defined in\r\n     * the 'sdp-transform' lib.\r\n     */\r\n    addSSRCAttribute(ssrcObj) {\r\n        this.ssrcs.push(ssrcObj);\r\n    }\r\n\r\n    /**\r\n     * Finds a SSRC group matching both semantics and SSRCs in order.\r\n     * @param {string} semantics the name of the semantics\r\n     * @param {string} [ssrcs] group SSRCs as a string (like it's defined in\r\n     * SSRC group object of the 'sdp-transform' lib) e.g. \"1232546 342344 25434\"\r\n     * @return {object|undefined} the SSRC group object or <tt>undefined</tt> if\r\n     * not found.\r\n     */\r\n    findGroup(semantics, ssrcs) {\r\n        return this.ssrcGroups.find(\r\n            group =>\r\n                group.semantics === semantics\r\n                    && (!ssrcs || ssrcs === group.ssrcs));\r\n    }\r\n\r\n    /**\r\n     * Finds all groups matching given semantic's name.\r\n     * @param {string} semantics the name of the semantics\r\n     * @return {Array.<object>} an array of SSRC group objects as defined by\r\n     * the 'sdp-transform' lib.\r\n     */\r\n    findGroups(semantics) {\r\n        return this.ssrcGroups.filter(\r\n            group => group.semantics === semantics);\r\n    }\r\n\r\n    /**\r\n     * Finds all groups matching given semantic's name and group's primary SSRC.\r\n     * @param {string} semantics the name of the semantics\r\n     * @param {number} primarySSRC the primary SSRC number to be matched\r\n     * @return {Object} SSRC group object as defined by the 'sdp-transform' lib.\r\n     */\r\n    findGroupByPrimarySSRC(semantics, primarySSRC) {\r\n        return this.ssrcGroups.find(\r\n            group => group.semantics === semantics\r\n                && parsePrimarySSRC(group) === primarySSRC);\r\n    }\r\n\r\n    /**\r\n     * @param {string|null} msid the media stream id or <tt>null</tt> to match\r\n     * the first SSRC object with any 'msid' value.\r\n     * @return {Object|undefined} the SSRC object as defined by 'sdp-transform'\r\n     * lib.\r\n     */\r\n    findSSRCByMSID(msid) {\r\n        return this.ssrcs.find(\r\n            ssrcObj => ssrcObj.attribute === 'msid'\r\n                && (msid === null || ssrcObj.value === msid));\r\n    }\r\n\r\n    /**\r\n     * Gets the SSRC count for the underlying media description.\r\n     * @return {number}\r\n     */\r\n    getSSRCCount() {\r\n        return _getSSRCCount(this.mLine);\r\n    }\r\n\r\n    /**\r\n     * Checks whether the underlying media description contains any SSRC groups.\r\n     * @return {boolean} <tt>true</tt> if there are any SSRC groups or\r\n     * <tt>false</tt> otherwise.\r\n     */\r\n    containsAnySSRCGroups() {\r\n        return this.mLine.ssrcGroups !== undefined;\r\n    }\r\n\r\n    /**\r\n     * Finds the primary video SSRC.\r\n     * @returns {number|undefined} the primary video ssrc\r\n     * @throws Error if the underlying media description is not a video\r\n     */\r\n    getPrimaryVideoSsrc() {\r\n        const mediaType = this.mLine.type;\r\n\r\n        if (mediaType !== 'video') {\r\n            throw new Error(\r\n                `getPrimarySsrc doesn't work with '${mediaType}'`);\r\n        }\r\n\r\n        const numSsrcs = _getSSRCCount(this.mLine);\r\n\r\n        if (numSsrcs === 1) {\r\n            // Not using \"ssrcs\" getter on purpose here\r\n            return this.mLine.ssrcs[0].id;\r\n        }\r\n\r\n        // Look for a SIM, FID, or FEC-FR group\r\n        if (this.mLine.ssrcGroups) {\r\n            const simGroup = this.findGroup('SIM');\r\n\r\n            if (simGroup) {\r\n                return parsePrimarySSRC(simGroup);\r\n            }\r\n            const fidGroup = this.findGroup('FID');\r\n\r\n            if (fidGroup) {\r\n                return parsePrimarySSRC(fidGroup);\r\n            }\r\n            const fecGroup = this.findGroup('FEC-FR');\r\n\r\n            if (fecGroup) {\r\n                return parsePrimarySSRC(fecGroup);\r\n            }\r\n        }\r\n\r\n    }\r\n\r\n    /**\r\n     * Obtains RTX SSRC from the underlying video description (the\r\n     * secondary SSRC of the first \"FID\" group found)\r\n     * @param {number} primarySsrc the video ssrc for which to find the\r\n     * corresponding rtx ssrc\r\n     * @returns {number|undefined} the rtx ssrc (or undefined if there isn't\r\n     * one)\r\n     */\r\n    getRtxSSRC(primarySsrc) {\r\n        const fidGroup = this.findGroupByPrimarySSRC('FID', primarySsrc);\r\n\r\n\r\n        return fidGroup && parseSecondarySSRC(fidGroup);\r\n    }\r\n\r\n    /**\r\n     * Obtains all SSRCs contained in the underlying media description.\r\n     * @return {Array.<number>} an array with all SSRC as numbers.\r\n     */\r\n    getSSRCs() {\r\n        return this.ssrcs\r\n            .map(ssrcInfo => ssrcInfo.id)\r\n            .filter((ssrc, index, array) => array.indexOf(ssrc) === index);\r\n    }\r\n\r\n    /**\r\n     * Obtains primary video SSRCs.\r\n     * @return {Array.<number>} an array of all primary video SSRCs as numbers.\r\n     * @throws Error if the wrapped media description is not a video.\r\n     */\r\n    getPrimaryVideoSSRCs() {\r\n        const mediaType = this.mLine.type;\r\n\r\n        if (mediaType !== 'video') {\r\n            throw new Error(\r\n                `getPrimaryVideoSSRCs doesn't work with ${mediaType}`);\r\n        }\r\n\r\n        const videoSSRCs = this.getSSRCs();\r\n\r\n        for (const ssrcGroupInfo of this.ssrcGroups) {\r\n            // Right now, FID and FEC-FR groups are the only ones we parse to\r\n            // disqualify streams.  If/when others arise we'll\r\n            // need to add support for them here\r\n            if (ssrcGroupInfo.semantics === 'FID'\r\n                    || ssrcGroupInfo.semantics === 'FEC-FR') {\r\n                // secondary streams should be filtered out\r\n                const secondarySsrc = parseSecondarySSRC(ssrcGroupInfo);\r\n\r\n                videoSSRCs.splice(\r\n                    videoSSRCs.indexOf(secondarySsrc), 1);\r\n            }\r\n        }\r\n\r\n        return videoSSRCs;\r\n    }\r\n\r\n    /**\r\n     * Dumps all SSRC groups of this media description to JSON.\r\n     */\r\n    dumpSSRCGroups() {\r\n        return JSON.stringify(this.mLine.ssrcGroups);\r\n    }\r\n\r\n    /**\r\n     * Removes all SSRC groups which contain given SSRC number at any position.\r\n     * @param {number} ssrc the SSRC for which all matching groups are to be\r\n     * removed.\r\n     */\r\n    removeGroupsWithSSRC(ssrc) {\r\n        if (!this.mLine.ssrcGroups) {\r\n            return;\r\n        }\r\n\r\n        this.mLine.ssrcGroups = this.mLine.ssrcGroups\r\n            .filter(groupInfo => groupInfo.ssrcs.indexOf(`${ssrc}`) === -1);\r\n    }\r\n\r\n    /**\r\n     * Removes groups that match given semantics.\r\n     * @param {string} semantics e.g. \"SIM\" or \"FID\"\r\n     */\r\n    removeGroupsBySemantics(semantics) {\r\n        if (!this.mLine.ssrcGroups) {\r\n            return;\r\n        }\r\n\r\n        this.mLine.ssrcGroups\r\n            = this.mLine.ssrcGroups\r\n                .filter(groupInfo => groupInfo.semantics !== semantics);\r\n    }\r\n\r\n    /**\r\n     * Replaces SSRC (does not affect SSRC groups, but only attributes).\r\n     * @param {number} oldSSRC the old SSRC number\r\n     * @param {number} newSSRC the new SSRC number\r\n     */\r\n    replaceSSRC(oldSSRC, newSSRC) {\r\n        if (this.mLine.ssrcs) {\r\n            this.mLine.ssrcs.forEach(ssrcInfo => {\r\n                if (ssrcInfo.id === oldSSRC) {\r\n                    ssrcInfo.id = newSSRC;\r\n                }\r\n            });\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Adds given SSRC group to this media description.\r\n     * @param {object} group the SSRC group object as defined by\r\n     * the 'sdp-transform' lib.\r\n     */\r\n    addSSRCGroup(group) {\r\n        this.ssrcGroups.push(group);\r\n    }\r\n}\r\n\r\n/**\r\n * Utility class for SDP manipulation using the 'sdp-transform' library.\r\n *\r\n * Typical use usage scenario:\r\n *\r\n * const transformer = new SdpTransformWrap(rawSdp);\r\n * const videoMLine = transformer.selectMedia('video);\r\n * if (videoMLine) {\r\n *     videoMLiner.addSSRCAttribute({\r\n *         id: 2342343,\r\n *         attribute: \"cname\",\r\n *         value: \"someCname\"\r\n *     });\r\n *     rawSdp = transformer.toRawSdp();\r\n * }\r\n */\r\nexport class SdpTransformWrap {\r\n\r\n    /**\r\n     * Creates new instance and parses the raw SDP into objects using\r\n     * 'sdp-transform' lib.\r\n     * @param {string} rawSDP the SDP in raw text format.\r\n     */\r\n    constructor(rawSDP) {\r\n        this.parsedSDP = transform.parse(rawSDP);\r\n    }\r\n\r\n    /**\r\n     * Selects all the m-lines from the SDP for a given media type.\r\n     *\r\n     * @param {string} mediaType the name of the media e.g. 'audio', 'video', 'data'.\r\n     * @return {MLineWrap|null} return {@link MLineWrap} instance for the media line or <tt>null</tt> if not found. The\r\n     * object returned references the underlying SDP state held by this <tt>SdpTransformWrap</tt> instance (it's not a\r\n     * copy).\r\n     */\r\n    selectMedia(mediaType) {\r\n        const selectedMLines = this.parsedSDP.media\r\n            .filter(mLine => mLine.type === mediaType)\r\n            .map(mLine => new MLineWrap(mLine));\r\n\r\n        return selectedMLines ?? null;\r\n    }\r\n\r\n    /**\r\n     * Converts the currently stored SDP state in this instance to raw text SDP\r\n     * format.\r\n     * @return {string}\r\n     */\r\n    toRawSDP() {\r\n        return transform.write(this.parsedSDP);\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport { getSourceNameForJitsiTrack } from '../../service/RTC/SignalingLayer';\r\nimport { VideoType } from '../../service/RTC/VideoType';\r\nimport browser from '../browser';\r\nimport FeatureFlags from '../flags/FeatureFlags';\r\n\r\nimport { SdpTransformWrap } from './SdpTransformUtil';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Fakes local SDP exposed to {@link JingleSessionPC} through the local\r\n * description getter. Modifies the SDP, so that it will contain muted local\r\n * video tracks description, even though their underlying {MediaStreamTrack}s\r\n * are no longer in the WebRTC peerconnection. That prevents from SSRC updates\r\n * being sent to Jicofo/remote peer and prevents sRD/sLD cycle on the remote\r\n * side.\r\n */\r\nexport default class LocalSdpMunger {\r\n\r\n    /**\r\n     * Creates new <tt>LocalSdpMunger</tt> instance.\r\n     *\r\n     * @param {TraceablePeerConnection} tpc\r\n     * @param {string} localEndpointId - The endpoint id of the local user.\r\n     */\r\n    constructor(tpc, localEndpointId) {\r\n        this.tpc = tpc;\r\n        this.localEndpointId = localEndpointId;\r\n        this.audioSourcesToMsidMap = new Map();\r\n        this.videoSourcesToMsidMap = new Map();\r\n    }\r\n\r\n    /**\r\n     * Makes sure that muted local video tracks associated with the parent\r\n     * {@link TraceablePeerConnection} are described in the local SDP. It's done\r\n     * in order to prevent from sending 'source-remove'/'source-add' Jingle\r\n     * notifications when local video track is muted (<tt>MediaStream</tt> is\r\n     * removed from the peerconnection).\r\n     *\r\n     * NOTE 1 video track is assumed\r\n     *\r\n     * @param {SdpTransformWrap} transformer the transformer instance which will\r\n     * be used to process the SDP.\r\n     * @return {boolean} <tt>true</tt> if there were any modifications to\r\n     * the SDP wrapped by <tt>transformer</tt>.\r\n     * @private\r\n     */\r\n    _addMutedLocalVideoTracksToSDP(transformer) {\r\n        // Go over each video tracks and check if the SDP has to be changed\r\n        const localVideos = this.tpc.getLocalTracks(MediaType.VIDEO);\r\n\r\n        if (!localVideos.length) {\r\n            return false;\r\n        } else if (localVideos.length !== 1) {\r\n            logger.error(\r\n                `${this.tpc} there is more than 1 video track ! `\r\n                    + 'Strange things may happen !', localVideos);\r\n        }\r\n\r\n        const videoMLine = transformer.selectMedia(MediaType.VIDEO)?.[0];\r\n\r\n        if (!videoMLine) {\r\n            logger.debug(\r\n                `${this.tpc} unable to hack local video track SDP`\r\n                    + '- no \"video\" media');\r\n\r\n            return false;\r\n        }\r\n\r\n        let modified = false;\r\n\r\n        for (const videoTrack of localVideos) {\r\n            const muted = videoTrack.isMuted();\r\n            const mediaStream = videoTrack.getOriginalStream();\r\n            const isCamera = videoTrack.videoType === VideoType.CAMERA;\r\n\r\n            // During the mute/unmute operation there are periods of time when\r\n            // the track's underlying MediaStream is not added yet to\r\n            // the PeerConnection. The SDP needs to be munged in such case.\r\n            const isInPeerConnection\r\n                = mediaStream && this.tpc.isMediaStreamInPc(mediaStream);\r\n            const shouldFakeSdp = isCamera && (muted || !isInPeerConnection);\r\n\r\n            if (!shouldFakeSdp) {\r\n                continue; // eslint-disable-line no-continue\r\n            }\r\n\r\n            // Inject removed SSRCs\r\n            const requiredSSRCs\r\n                = this.tpc.isSimulcastOn()\r\n                    ? this.tpc.simulcast.ssrcCache\r\n                    : [ this.tpc.sdpConsistency.cachedPrimarySsrc ];\r\n\r\n            if (!requiredSSRCs.length) {\r\n                logger.error(`No SSRCs stored for: ${videoTrack} in ${this.tpc}`);\r\n\r\n                continue; // eslint-disable-line no-continue\r\n            }\r\n\r\n            modified = true;\r\n\r\n            // We need to fake sendrecv.\r\n            // NOTE the SDP produced here goes only to Jicofo and is never set\r\n            // as localDescription. That's why\r\n            // TraceablePeerConnection.mediaTransferActive is ignored here.\r\n            videoMLine.direction = MediaDirection.SENDRECV;\r\n\r\n            // Check if the recvonly has MSID\r\n            const primarySSRC = requiredSSRCs[0];\r\n\r\n            // FIXME The cname could come from the stream, but may turn out to\r\n            // be too complex. It is fine to come up with any value, as long as\r\n            // we only care about the actual SSRC values when deciding whether\r\n            // or not an update should be sent.\r\n            const primaryCname = `injected-${primarySSRC}`;\r\n\r\n            for (const ssrcNum of requiredSSRCs) {\r\n                // Remove old attributes\r\n                videoMLine.removeSSRC(ssrcNum);\r\n\r\n                // Inject\r\n                videoMLine.addSSRCAttribute({\r\n                    id: ssrcNum,\r\n                    attribute: 'cname',\r\n                    value: primaryCname\r\n                });\r\n                videoMLine.addSSRCAttribute({\r\n                    id: ssrcNum,\r\n                    attribute: 'msid',\r\n                    value: videoTrack.storedMSID\r\n                });\r\n            }\r\n            if (requiredSSRCs.length > 1) {\r\n                const group = {\r\n                    ssrcs: requiredSSRCs.join(' '),\r\n                    semantics: 'SIM'\r\n                };\r\n\r\n                if (!videoMLine.findGroup(group.semantics, group.ssrcs)) {\r\n                    // Inject the group\r\n                    videoMLine.addSSRCGroup(group);\r\n                }\r\n            }\r\n\r\n            // Insert RTX\r\n            // FIXME in P2P RTX is used by Chrome regardless of config option\r\n            // status. Because of that 'source-remove'/'source-add'\r\n            // notifications are still sent to remove/add RTX SSRC and FID group\r\n            if (!this.tpc.options.disableRtx) {\r\n                this.tpc.rtxModifier.modifyRtxSsrcs2(videoMLine);\r\n            }\r\n        }\r\n\r\n        return modified;\r\n    }\r\n\r\n    /**\r\n     * Returns a string that can be set as the MSID attribute for a source.\r\n     *\r\n     * @param {string} mediaType - Media type of the source.\r\n     * @param {string} trackId - Id of the MediaStreamTrack associated with the source.\r\n     * @param {string} streamId - Id of the MediaStream associated with the source.\r\n     * @returns {string|null}\r\n     */\r\n    _generateMsidAttribute(mediaType, trackId, streamId = null) {\r\n        if (!(mediaType && trackId)) {\r\n            logger.error(`Unable to munge local MSID - track id=${trackId} or media type=${mediaType} is missing`);\r\n\r\n            return null;\r\n        }\r\n        const pcId = this.tpc.id;\r\n\r\n        // Handle a case on Firefox when the browser doesn't produce a 'a:ssrc' line with the 'msid' attribute or has\r\n        // '-' for the stream id part of the msid line. Jicofo needs an unique identifier to be associated with a ssrc\r\n        // and uses the msid for that.\r\n        if (streamId === '-' || !streamId) {\r\n            return `${this.localEndpointId}-${mediaType}-${pcId} ${trackId}-${pcId}`;\r\n        }\r\n\r\n        return `${streamId}-${pcId} ${trackId}-${pcId}`;\r\n    }\r\n\r\n    /**\r\n     * Modifies 'cname', 'msid', 'label' and 'mslabel' by appending the id of {@link LocalSdpMunger#tpc} at the end,\r\n     * preceding by a dash sign.\r\n     *\r\n     * @param {MLineWrap} mediaSection - The media part (audio or video) of the session description which will be\r\n     * modified in place.\r\n     * @returns {void}\r\n     * @private\r\n     */\r\n    _transformMediaIdentifiers(mediaSection) {\r\n        const mediaType = mediaSection.mLine?.type;\r\n        const pcId = this.tpc.id;\r\n\r\n        for (const ssrcLine of mediaSection.ssrcs) {\r\n            switch (ssrcLine.attribute) {\r\n            case 'cname':\r\n            case 'label':\r\n            case 'mslabel':\r\n                ssrcLine.value = ssrcLine.value && `${ssrcLine.value}-${pcId}`;\r\n                break;\r\n            case 'msid': {\r\n                if (ssrcLine.value) {\r\n                    const streamAndTrackIDs = ssrcLine.value.split(' ');\r\n\r\n                    let streamId = streamAndTrackIDs[0];\r\n                    const trackId = streamAndTrackIDs[1];\r\n\r\n                    // Always overwrite streamId since we want the msid to be in this format even if the browser\r\n                    // generates one (in p2p mode).\r\n                    streamId = `${this.localEndpointId}-${mediaType}`;\r\n\r\n                    // eslint-disable-next-line max-depth\r\n                    if (mediaType === MediaType.VIDEO) {\r\n                        // eslint-disable-next-line max-depth\r\n                        if (!this.videoSourcesToMsidMap.has(trackId)) {\r\n                            streamId = `${streamId}-${this.videoSourcesToMsidMap.size}`;\r\n                            this.videoSourcesToMsidMap.set(trackId, streamId);\r\n                        }\r\n                    } else if (!this.audioSourcesToMsidMap.has(trackId)) {\r\n                        streamId = `${streamId}-${this.audioSourcesToMsidMap.size}`;\r\n                        this.audioSourcesToMsidMap.set(trackId, streamId);\r\n                    }\r\n\r\n                    streamId = mediaType === MediaType.VIDEO\r\n                        ? this.videoSourcesToMsidMap.get(trackId)\r\n                        : this.audioSourcesToMsidMap.get(trackId);\r\n\r\n                    ssrcLine.value = this._generateMsidAttribute(mediaType, trackId, streamId);\r\n                } else {\r\n                    logger.warn(`Unable to munge local MSID - weird format detected: ${ssrcLine.value}`);\r\n                }\r\n                break;\r\n            }\r\n            }\r\n        }\r\n\r\n        // Additional transformations related to MSID are applicable to Unified-plan implementation only.\r\n        if (!this.tpc.usesUnifiedPlan()) {\r\n            return;\r\n        }\r\n\r\n        const mediaDirection = mediaSection.mLine?.direction;\r\n\r\n        // On FF when the user has started muted create answer will generate a recv only SSRC. We don't want to signal\r\n        // this SSRC in order to reduce the load of the xmpp server for large calls. Therefore the SSRC needs to be\r\n        // removed from the SDP.\r\n        //\r\n        // For all other use cases (when the user has had media but then the user has stopped it) we want to keep the\r\n        // receive only SSRCs in the SDP. Otherwise source-remove will be triggered and the next time the user add a\r\n        // track we will reuse the SSRCs and send source-add with the same SSRCs. This is problematic because of issues\r\n        // on Chrome and FF (https://bugzilla.mozilla.org/show_bug.cgi?id=1768729) when removing and then adding the\r\n        // same SSRC in the remote sdp the remote track is not rendered.\r\n        if (browser.isFirefox()\r\n            && (mediaDirection === MediaDirection.RECVONLY || mediaDirection === MediaDirection.INACTIVE)\r\n            && (\r\n                (mediaType === MediaType.VIDEO && !this.tpc._hasHadVideoTrack)\r\n                || (mediaType === MediaType.AUDIO && !this.tpc._hasHadAudioTrack)\r\n            )\r\n        ) {\r\n            mediaSection.ssrcs = undefined;\r\n            mediaSection.ssrcGroups = undefined;\r\n        }\r\n\r\n        const msidLine = mediaSection.mLine?.msid;\r\n        const trackId = msidLine && msidLine.split(' ')[1];\r\n        const sources = [ ...new Set(mediaSection.mLine?.ssrcs?.map(s => s.id)) ];\r\n\r\n        for (const source of sources) {\r\n            const msidExists = mediaSection.ssrcs\r\n                .find(ssrc => ssrc.id === source && ssrc.attribute === 'msid');\r\n\r\n            if (!msidExists && trackId) {\r\n                const generatedMsid = this._generateMsidAttribute(mediaType, trackId);\r\n\r\n                mediaSection.ssrcs.push({\r\n                    id: source,\r\n                    attribute: 'msid',\r\n                    value: generatedMsid\r\n                });\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Maybe modifies local description to fake local video tracks SDP when\r\n     * those are muted.\r\n     *\r\n     * @param {object} desc the WebRTC SDP object instance for the local\r\n     * description.\r\n     * @returns {RTCSessionDescription}\r\n     */\r\n    maybeAddMutedLocalVideoTracksToSDP(desc) {\r\n        if (!desc) {\r\n            throw new Error('No local description passed in.');\r\n        }\r\n\r\n        const transformer = new SdpTransformWrap(desc.sdp);\r\n\r\n        if (this._addMutedLocalVideoTracksToSDP(transformer)) {\r\n            return new RTCSessionDescription({\r\n                type: desc.type,\r\n                sdp: transformer.toRawSDP()\r\n            });\r\n        }\r\n\r\n        return desc;\r\n    }\r\n\r\n    /**\r\n     * This transformation will make sure that stream identifiers are unique\r\n     * across all of the local PeerConnections even if the same stream is used\r\n     * by multiple instances at the same time.\r\n     * Each PeerConnection assigns different SSRCs to the same local\r\n     * MediaStream, but the MSID remains the same as it's used to identify\r\n     * the stream by the WebRTC backend. The transformation will append\r\n     * {@link TraceablePeerConnection#id} at the end of each stream's identifier\r\n     * (\"cname\", \"msid\", \"label\" and \"mslabel\").\r\n     *\r\n     * @param {RTCSessionDescription} sessionDesc - The local session\r\n     * description (this instance remains unchanged).\r\n     * @return {RTCSessionDescription} - Transformed local session description\r\n     * (a modified copy of the one given as the input).\r\n     */\r\n    transformStreamIdentifiers(sessionDesc) {\r\n        // FIXME similar check is probably duplicated in all other transformers\r\n        if (!sessionDesc || !sessionDesc.sdp || !sessionDesc.type) {\r\n            return sessionDesc;\r\n        }\r\n\r\n        const transformer = new SdpTransformWrap(sessionDesc.sdp);\r\n        const audioMLine = transformer.selectMedia(MediaType.AUDIO)?.[0];\r\n\r\n        if (audioMLine) {\r\n            this._transformMediaIdentifiers(audioMLine);\r\n            this._injectSourceNames(audioMLine);\r\n        }\r\n\r\n        const videoMlines = transformer.selectMedia(MediaType.VIDEO);\r\n\r\n        if (!FeatureFlags.isMultiStreamSendSupportEnabled()) {\r\n            videoMlines.splice(1);\r\n        }\r\n\r\n        for (const videoMLine of videoMlines) {\r\n            this._transformMediaIdentifiers(videoMLine);\r\n            this._injectSourceNames(videoMLine);\r\n        }\r\n\r\n        // Plan-b clients generate new SSRCs and trackIds whenever tracks are removed and added back to the\r\n        // peerconnection, therefore local track based map for msids needs to be reset after every transformation.\r\n        if (!this.tpc._usesUnifiedPlan) {\r\n            this.audioSourcesToMsidMap.clear();\r\n            this.videoSourcesToMsidMap.clear();\r\n        }\r\n\r\n        return new RTCSessionDescription({\r\n            type: sessionDesc.type,\r\n            sdp: transformer.toRawSDP()\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Injects source names. Source names are need to for multiple streams per endpoint support. The final plan is to\r\n     * use the \"mid\" attribute for source names, but because the SDP to Jingle conversion still operates in the Plan-B\r\n     * semantics (one source name per media), a custom \"name\" attribute is injected into SSRC lines..\r\n     *\r\n     * @param {MLineWrap} mediaSection - The media part (audio or video) of the session description which will be\r\n     * modified in place.\r\n     * @returns {void}\r\n     * @private\r\n     */\r\n    _injectSourceNames(mediaSection) {\r\n        const sources = [ ...new Set(mediaSection.mLine?.ssrcs?.map(s => s.id)) ];\r\n        const mediaType = mediaSection.mLine?.type;\r\n\r\n        if (!mediaType) {\r\n            throw new Error('_transformMediaIdentifiers - no media type in mediaSection');\r\n        }\r\n\r\n        for (const source of sources) {\r\n            const nameExists = mediaSection.ssrcs.find(ssrc => ssrc.id === source && ssrc.attribute === 'name');\r\n            const msid = mediaSection.ssrcs.find(ssrc => ssrc.id === source && ssrc.attribute === 'msid')?.value;\r\n            let trackIndex;\r\n\r\n            if (msid) {\r\n                const streamId = msid.split(' ')[0];\r\n\r\n                // Example stream id: d8ff91-video-8-1\r\n                // In the example above 8 is the track index\r\n                const trackIndexParts = streamId.split('-');\r\n\r\n                trackIndex = trackIndexParts[trackIndexParts.length - 2];\r\n            }\r\n\r\n            const sourceName = getSourceNameForJitsiTrack(this.localEndpointId, mediaType, trackIndex);\r\n\r\n            if (!nameExists) {\r\n                // Inject source names as a=ssrc:3124985624 name:endpointA-v0\r\n                mediaSection.ssrcs.push({\r\n                    id: source,\r\n                    attribute: 'name',\r\n                    value: sourceName\r\n                });\r\n            }\r\n\r\n            if (mediaType === MediaType.VIDEO) {\r\n                const videoType = this.tpc.getLocalVideoTracks().find(track => track.getSourceName() === sourceName)\r\n                    ?.getVideoType();\r\n\r\n                if (videoType) {\r\n                    // Inject videoType as a=ssrc:1234 videoType:desktop.\r\n                    mediaSection.ssrcs.push({\r\n                        id: source,\r\n                        attribute: 'videoType',\r\n                        value: videoType\r\n                    });\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\n\r\nimport SDPUtil from './SDPUtil';\r\nimport { SdpTransformWrap, parseSecondarySSRC } from './SdpTransformUtil';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Begin helper functions\r\n */\r\n/**\r\n * Updates or inserts the appropriate rtx information for primarySsrc with\r\n *  the given rtxSsrc.  If no rtx ssrc for primarySsrc currently exists, it will\r\n *  add the appropriate ssrc and ssrc group lines.  If primarySsrc already has\r\n *  an rtx ssrc, the appropriate ssrc and group lines will be updated\r\n * @param {MLineWrap} mLine\r\n * @param {object} primarySsrcInfo the info (ssrc, msid & cname) for the\r\n *  primary ssrc\r\n * @param {number} rtxSsrc the rtx ssrc to associate with the primary ssrc\r\n */\r\nfunction updateAssociatedRtxStream(mLine, primarySsrcInfo, rtxSsrc) {\r\n    const primarySsrc = primarySsrcInfo.id;\r\n    const primarySsrcMsid = primarySsrcInfo.msid;\r\n    const primarySsrcCname = primarySsrcInfo.cname;\r\n\r\n    const previousRtxSSRC = mLine.getRtxSSRC(primarySsrc);\r\n\r\n    if (previousRtxSSRC === rtxSsrc) {\r\n        return;\r\n    }\r\n    if (previousRtxSSRC) {\r\n        // Stream already had an rtx ssrc that is different than the one given,\r\n        //  remove all trace of the old one\r\n        mLine.removeSSRC(previousRtxSSRC);\r\n        mLine.removeGroupsWithSSRC(previousRtxSSRC);\r\n    }\r\n    mLine.addSSRCAttribute({\r\n        id: rtxSsrc,\r\n        attribute: 'cname',\r\n        value: primarySsrcCname\r\n    });\r\n    mLine.addSSRCAttribute({\r\n        id: rtxSsrc,\r\n        attribute: 'msid',\r\n        value: primarySsrcMsid\r\n    });\r\n    mLine.addSSRCGroup({\r\n        semantics: 'FID',\r\n        ssrcs: `${primarySsrc} ${rtxSsrc}`\r\n    });\r\n}\r\n\r\n/**\r\n * End helper functions\r\n */\r\n\r\n/**\r\n * Adds any missing RTX streams for video streams\r\n *  and makes sure that they remain consistent\r\n */\r\nexport default class RtxModifier {\r\n    /**\r\n     * Constructor\r\n     */\r\n    constructor() {\r\n        /**\r\n         * Map of video ssrc to corresponding RTX\r\n         *  ssrc\r\n         */\r\n        this.correspondingRtxSsrcs = new Map();\r\n    }\r\n\r\n    /**\r\n     * Clear the cached map of primary video ssrcs to\r\n     *  their corresponding rtx ssrcs so that they will\r\n     *  not be used for the next call to modifyRtxSsrcs\r\n     */\r\n    clearSsrcCache() {\r\n        this.correspondingRtxSsrcs.clear();\r\n    }\r\n\r\n    /**\r\n     * Explicitly set the primary video ssrc -> rtx ssrc\r\n     *  mapping to be used in modifyRtxSsrcs\r\n     * @param {Map} ssrcMapping a mapping of primary video\r\n     *  ssrcs to their corresponding rtx ssrcs\r\n     */\r\n    setSsrcCache(ssrcMapping) {\r\n        logger.debug('Setting ssrc cache to ', ssrcMapping);\r\n        this.correspondingRtxSsrcs = ssrcMapping;\r\n    }\r\n\r\n    /**\r\n     * Adds RTX ssrcs for any video ssrcs that don't already have them.  If the video ssrc has been seen before, and\r\n     * already had an RTX ssrc generated, the same RTX ssrc will be used again.\r\n     *\r\n     * @param {string} sdpStr sdp in raw string format\r\n     * @returns {string} The modified sdp in raw string format.\r\n     */\r\n    modifyRtxSsrcs(sdpStr) {\r\n        let modified = false;\r\n        const sdpTransformer = new SdpTransformWrap(sdpStr);\r\n        const videoMLines = sdpTransformer.selectMedia(MediaType.VIDEO);\r\n\r\n        if (!videoMLines?.length) {\r\n            logger.debug(`No 'video' media found in the sdp: ${sdpStr}`);\r\n\r\n            return sdpStr;\r\n        }\r\n\r\n        for (const videoMLine of videoMLines) {\r\n            if (this.modifyRtxSsrcs2(videoMLine)) {\r\n                modified = true;\r\n            }\r\n        }\r\n\r\n        return modified ? sdpTransformer.toRawSDP() : sdpStr;\r\n    }\r\n\r\n    /**\r\n     * Does the same thing as {@link modifyRtxSsrcs}, but takes the {@link MLineWrap} instance wrapping video media as\r\n     * an argument.\r\n     * @param {MLineWrap} videoMLine\r\n     * @return {boolean} <tt>true</tt> if the SDP wrapped by {@link SdpTransformWrap} has been modified or\r\n     * <tt>false</tt> otherwise.\r\n     */\r\n    modifyRtxSsrcs2(videoMLine) {\r\n        if (videoMLine.direction === MediaDirection.RECVONLY) {\r\n            return false;\r\n        }\r\n        if (videoMLine.getSSRCCount() < 1) {\r\n            return false;\r\n        }\r\n        const primaryVideoSsrcs = videoMLine.getPrimaryVideoSSRCs();\r\n\r\n        for (const ssrc of primaryVideoSsrcs) {\r\n            const msid = videoMLine.getSSRCAttrValue(ssrc, 'msid');\r\n            const cname = videoMLine.getSSRCAttrValue(ssrc, 'cname');\r\n            let correspondingRtxSsrc = this.correspondingRtxSsrcs.get(ssrc);\r\n\r\n            if (!correspondingRtxSsrc) {\r\n                // If there's one in the sdp already for it, we'll just set\r\n                //  that as the corresponding one\r\n                const previousAssociatedRtxStream = videoMLine.getRtxSSRC(ssrc);\r\n\r\n                if (previousAssociatedRtxStream) {\r\n                    correspondingRtxSsrc = previousAssociatedRtxStream;\r\n                } else {\r\n                    correspondingRtxSsrc = SDPUtil.generateSsrc();\r\n                }\r\n                this.correspondingRtxSsrcs.set(ssrc, correspondingRtxSsrc);\r\n            }\r\n            updateAssociatedRtxStream(\r\n                videoMLine,\r\n                {\r\n                    id: ssrc,\r\n                    cname,\r\n                    msid\r\n                },\r\n                correspondingRtxSsrc);\r\n        }\r\n\r\n        // FIXME we're not looking into much details whether the SDP has been\r\n        // modified or not once the precondition requirements are met.\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * Strip all rtx streams from the given sdp.\r\n     *\r\n     * @param {string} sdpStr sdp in raw string format\r\n     * @returns {string} sdp string with all rtx streams stripped\r\n     */\r\n    stripRtx(sdpStr) {\r\n        const sdpTransformer = new SdpTransformWrap(sdpStr);\r\n        const videoMLines = sdpTransformer.selectMedia(MediaType.VIDEO);\r\n\r\n        if (!videoMLines?.length) {\r\n            logger.debug(`No 'video' media found in the sdp: ${sdpStr}`);\r\n\r\n            return sdpStr;\r\n        }\r\n\r\n        for (const videoMLine of videoMLines) {\r\n            if (videoMLine.direction !== MediaDirection.RECVONLY\r\n                && videoMLine.getSSRCCount()\r\n                && videoMLine.containsAnySSRCGroups()) {\r\n                const fidGroups = videoMLine.findGroups('FID');\r\n\r\n                // Remove the fid groups from the mline\r\n                videoMLine.removeGroupsBySemantics('FID');\r\n\r\n                // Get the rtx ssrcs and remove them from the mline\r\n                for (const fidGroup of fidGroups) {\r\n                    const rtxSsrc = parseSecondarySSRC(fidGroup);\r\n\r\n                    videoMLine.removeSSRC(rtxSsrc);\r\n                }\r\n            }\r\n        }\r\n\r\n        return sdpTransformer.toRawSDP();\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\n\r\nimport {\r\n    SdpTransformWrap,\r\n    parsePrimarySSRC,\r\n    parseSecondarySSRC\r\n} from './SdpTransformUtil';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Handles the work of keeping video ssrcs consistent across multiple\r\n * o/a cycles, making it such that all stream operations can be\r\n * kept local and do not need to be signaled.\r\n * NOTE: This only keeps the 'primary' video ssrc consistent: meaning\r\n * the primary video stream\r\n */\r\nexport default class SdpConsistency {\r\n    /**\r\n     * Constructor\r\n     * @param {string} logPrefix the log prefix appended to every logged\r\n     * message, currently used to distinguish for which\r\n     * <tt>TraceablePeerConnection</tt> the instance works.\r\n     */\r\n    constructor(logPrefix) {\r\n        this.clearVideoSsrcCache();\r\n        this.logPrefix = logPrefix;\r\n    }\r\n\r\n    /**\r\n     * Clear the cached video primary and primary rtx ssrcs so that\r\n     *  they will not be used for the next call to\r\n     *  makeVideoPrimarySsrcsConsistent\r\n     */\r\n    clearVideoSsrcCache() {\r\n        this.cachedPrimarySsrc = null;\r\n        this.injectRecvOnly = false;\r\n    }\r\n\r\n    /**\r\n     * Explicitly set the primary ssrc to be used in\r\n     *  makeVideoPrimarySsrcsConsistent\r\n     * @param {number} primarySsrc the primarySsrc to be used\r\n     *  in future calls to makeVideoPrimarySsrcsConsistent\r\n     * @throws Error if <tt>primarySsrc</tt> is not a number\r\n     */\r\n    setPrimarySsrc(primarySsrc) {\r\n        if (typeof primarySsrc !== 'number') {\r\n            throw new Error('Primary SSRC must be a number!');\r\n        }\r\n        this.cachedPrimarySsrc = primarySsrc;\r\n    }\r\n\r\n    /**\r\n     * Checks whether or not there is a primary video SSRC cached already.\r\n     * @return {boolean}\r\n     */\r\n    hasPrimarySsrcCached() {\r\n        return Boolean(this.cachedPrimarySsrc);\r\n    }\r\n\r\n    /**\r\n     * Given an sdp string, either:\r\n     *  1) record the primary video and primary rtx ssrcs to be\r\n     *   used in future calls to makeVideoPrimarySsrcsConsistent or\r\n     *  2) change the primary and primary rtx ssrcs in the given sdp\r\n     *   to match the ones previously cached\r\n     * @param {string} sdpStr the sdp string to (potentially)\r\n     *  change to make the video ssrcs consistent\r\n     * @returns {string} a (potentially) modified sdp string\r\n     *  with ssrcs consistent with this class' cache\r\n     */\r\n    makeVideoPrimarySsrcsConsistent(sdpStr) {\r\n        const sdpTransformer = new SdpTransformWrap(sdpStr);\r\n        const videoMLine = sdpTransformer.selectMedia(MediaType.VIDEO)?.[0];\r\n\r\n        if (!videoMLine) {\r\n            logger.debug(`${this.logPrefix} no 'video' media found in the sdp: ${sdpStr}`);\r\n\r\n            return sdpStr;\r\n        }\r\n\r\n        if (videoMLine.direction === 'recvonly') {\r\n            // If the mline is recvonly, we'll add the primary\r\n            //  ssrc as a recvonly ssrc\r\n            if (this.cachedPrimarySsrc && this.injectRecvOnly) {\r\n                videoMLine.addSSRCAttribute({\r\n                    id: this.cachedPrimarySsrc,\r\n                    attribute: 'cname',\r\n                    value: `recvonly-${this.cachedPrimarySsrc}`\r\n                });\r\n            } else {\r\n                logger.info(`${this.logPrefix} no SSRC found for the recvonly video stream!`);\r\n            }\r\n        } else {\r\n            const newPrimarySsrc = videoMLine.getPrimaryVideoSsrc();\r\n\r\n            if (!newPrimarySsrc) {\r\n                logger.info(`${this.logPrefix} sdp-consistency couldn't parse new primary ssrc`);\r\n\r\n                return sdpStr;\r\n            }\r\n            if (this.cachedPrimarySsrc) {\r\n                videoMLine.replaceSSRC(newPrimarySsrc, this.cachedPrimarySsrc);\r\n                for (const group of videoMLine.ssrcGroups) {\r\n                    if (group.semantics === 'FID') {\r\n                        const primarySsrc = parsePrimarySSRC(group);\r\n                        const rtxSsrc = parseSecondarySSRC(group);\r\n\r\n                        // eslint-disable-next-line max-depth\r\n                        if (primarySsrc === newPrimarySsrc) {\r\n                            group.ssrcs\r\n                                = `${this.cachedPrimarySsrc} ${rtxSsrc}`;\r\n                        }\r\n                    }\r\n                }\r\n            } else {\r\n                this.cachedPrimarySsrc = newPrimarySsrc;\r\n            }\r\n            this.injectRecvOnly = true;\r\n        }\r\n\r\n        return sdpTransformer.toRawSDP();\r\n    }\r\n}\r\n","import { MediaDirection } from '../../service/RTC/MediaDirection';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\n\r\nimport * as transform from 'sdp-transform';\r\n\r\nconst DEFAULT_NUM_OF_LAYERS = 3;\r\n\r\ninterface Description {\r\n    type: RTCSdpType;\r\n    sdp: string;\r\n}\r\n\r\ninterface Options {\r\n    numOfLayers?: number\r\n}\r\n\r\n/**\r\n * This class handles SDP munging for enabling simulcast for local video streams in Unified plan. A set of random SSRCs\r\n * are generated for the higher layer streams and they are cached for a given mid. The cached SSRCs are then reused on\r\n * the subsequent iterations while munging the local description. This class also handles imploding of the simulcast\r\n * SSRCs for remote endpoints into the primary FID group in remote description since Jicofo signals all SSRCs relevant\r\n * to a given endpoint.\r\n */\r\nexport default class SdpSimulcast {\r\n    private _options: Options;\r\n    private _ssrcCache: Map<string, Array<number>>;\r\n\r\n    /**\r\n     * Creates a new instance.\r\n     *\r\n     * @param options\r\n     */\r\n    constructor(options: Options) {\r\n        this._options = options;\r\n        this._ssrcCache = new Map();\r\n\r\n        if (!this._options.numOfLayers) {\r\n            this._options.numOfLayers = DEFAULT_NUM_OF_LAYERS;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Updates the given media description using the SSRCs that were cached for the mid associated\r\n     * with the media description and returns the modified media description.\r\n     *\r\n     * @param mLine\r\n     * @returns\r\n     */\r\n     _fillSsrcsFromCache(mLine: transform.MediaDescription) : any {\r\n        const mid = mLine.mid;\r\n        const cachedSsrcs = this._ssrcCache.get(mid);\r\n        const newSsrcs = this._parseSimLayers(mLine);\r\n        const newMsid = this._getSsrcAttribute(mLine, newSsrcs[0], 'msid');\r\n        const newCname = this._getSsrcAttribute(mLine, newSsrcs[0], 'cname');\r\n\r\n        mLine.ssrcs = [];\r\n        mLine.ssrcGroups = [];\r\n\r\n        for (const ssrc of cachedSsrcs) {\r\n            mLine.ssrcs.push({\r\n                id: ssrc,\r\n                attribute: 'msid',\r\n                value: newMsid\r\n            });\r\n            mLine.ssrcs.push({\r\n                id: ssrc,\r\n                attribute: 'cname',\r\n                value: newCname\r\n            });\r\n        }\r\n\r\n        mLine.ssrcGroups.push({\r\n            semantics: 'SIM',\r\n            ssrcs: cachedSsrcs.join(' ')\r\n        });\r\n\r\n        return mLine;\r\n    }\r\n\r\n    /**\r\n     * Generates a new set of SSRCs for the higher simulcast layers/streams and adds the attributes and SIM group to\r\n     * the given media description and returns the modified media description.\r\n     *\r\n     * @param mLine\r\n     * @param primarySsrc\r\n     * @returns\r\n     */\r\n    _generateNewSsrcsForSimulcast(mLine: transform.MediaDescription, primarySsrc: number) : any {\r\n        const cname = this._getSsrcAttribute(mLine, primarySsrc, 'cname');\r\n        let msid = this._getSsrcAttribute(mLine, primarySsrc, 'msid');\r\n        const addAssociatedAttributes = (mLine: transform.MediaDescription, ssrc: number) => {\r\n            mLine.ssrcs.push({\r\n                id: ssrc,\r\n                attribute: 'cname',\r\n                value: cname\r\n            });\r\n            mLine.ssrcs.push({\r\n                id: ssrc,\r\n                attribute: 'msid',\r\n                value: msid\r\n            });\r\n        }\r\n\r\n        // In Unified-plan mode, the a=ssrc lines with the msid attribute are not present (only cname attributes are\r\n        // present) in the answers that Chrome and Safari generate for an offer received from Jicofo. Generate these\r\n        // a=ssrc lines using the msid values from the a=msid line.\r\n        if (!msid) {\r\n            msid = mLine.msid;\r\n            const primarySsrcs = mLine.ssrcs;\r\n\r\n            primarySsrcs.forEach(ssrc => {\r\n                mLine.ssrcs.push({\r\n                    id: ssrc.id,\r\n                    attribute: 'msid',\r\n                    value: msid\r\n                });\r\n            })\r\n        }\r\n\r\n        // Generate SIM layers.\r\n        const simSsrcs = [];\r\n\r\n        for (let i = 0; i < this._options.numOfLayers - 1; ++i) {\r\n            const simSsrc = this._generateSsrc();\r\n\r\n            addAssociatedAttributes(mLine, simSsrc);\r\n            simSsrcs.push(simSsrc);\r\n        }\r\n\r\n        mLine.ssrcGroups = mLine.ssrcGroups || [];\r\n        mLine.ssrcGroups.push({\r\n            semantics: 'SIM',\r\n            ssrcs: primarySsrc + ' ' + simSsrcs.join(' ')\r\n        });\r\n\r\n        return mLine;\r\n    }\r\n\r\n    /**\r\n     * Returns a random number to be used for the SSRC.\r\n     *\r\n     * @returns\r\n     */\r\n    _generateSsrc() : number {\r\n        const max = 0xffffffff;\r\n\r\n        return Math.floor(Math.random() * max);\r\n    }\r\n\r\n    /**\r\n     * Returns the requested attribute value for a SSRC from a given media description.\r\n     *\r\n     * @param mLine\r\n     * @param ssrc\r\n     * @param attributeName\r\n     * @returns\r\n     */\r\n    _getSsrcAttribute(mLine: transform.MediaDescription, ssrc: number, attributeName: string) : string | undefined {\r\n        return mLine.ssrcs?.find(\r\n            ssrcInfo => Number(ssrcInfo.id) === ssrc\r\n            && ssrcInfo.attribute === attributeName)?.value;\r\n    }\r\n\r\n    /**\r\n     * Returns an array of all the primary SSRCs in the SIM group for a given media description.\r\n     *\r\n     * @param mLine\r\n     * @returns\r\n     */\r\n    _parseSimLayers(mLine: transform.MediaDescription) : Array<number> | null {\r\n        const simGroup = mLine.ssrcGroups?.find(group => group.semantics === 'SIM');\r\n\r\n        if (simGroup) {\r\n            return simGroup.ssrcs.split(' ').map(ssrc => Number(ssrc));\r\n        }\r\n\r\n        if (mLine.ssrcs?.length) {\r\n            return [ Number(mLine.ssrcs[0].id) ];\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * Munges the given media description to enable simulcast for the video media sections that are in either have\r\n     * SENDRECV or SENDONLY as the media direction thereby ignoring all the RECVONLY transceivers created for remote\r\n     * endpoints.\r\n     * NOTE: This needs to be called only when simulcast is enabled.\r\n     *\r\n     * @param description\r\n     * @returns\r\n     */\r\n    mungeLocalDescription(description: Description) : Description {\r\n        if (!description || !description.sdp) {\r\n            return description;\r\n        }\r\n        const session = transform.parse(description.sdp);\r\n\r\n        for (let media of session.media) {\r\n            // Ignore recvonly and inactive transceivers created for remote sources.\r\n            if (media.direction === MediaDirection.RECVONLY || media.direction === MediaDirection.INACTIVE) {\r\n                continue;\r\n            }\r\n\r\n            // Ignore audio m-lines.\r\n            if (media.type !== MediaType.VIDEO) {\r\n                continue;\r\n            }\r\n            const mid = media.mid;\r\n            const numSsrcs = new Set(media.ssrcs?.map(ssrcInfo => ssrcInfo.id));\r\n            const numGroups = media.ssrcGroups?.length ?? 0;\r\n            let primarySsrc: number;\r\n\r\n            // Do not munge if the description has no ssrcs or if simulcast is already enabled.\r\n            if (numSsrcs.size === 0 || numSsrcs.size > 2 || (numSsrcs.size === 2 && numGroups === 0)) {\r\n                continue;\r\n            }\r\n            if (numSsrcs.size === 1) {\r\n                primarySsrc = Number(media.ssrcs[0]?.id);\r\n            } else {\r\n                const fidGroup = media.ssrcGroups.find(group => group.semantics === 'FID');\r\n\r\n                if (fidGroup) {\r\n                    primarySsrc = Number(fidGroup.ssrcs.split(' ')[0]);\r\n                }\r\n            }\r\n\r\n            if (this._ssrcCache.has(mid)) {\r\n                media = this._fillSsrcsFromCache(media);\r\n            } else {\r\n                media = this._generateNewSsrcsForSimulcast(media, primarySsrc);\r\n                const simulcastSsrcs = this._parseSimLayers(media);\r\n\r\n                // Update the SSRCs in the cache so that they can re-used for the same mid again.\r\n                this._ssrcCache.set(mid, simulcastSsrcs);\r\n            }\r\n        }\r\n\r\n        return new RTCSessionDescription({\r\n            type: description.type,\r\n            sdp: transform.write(session)\r\n        });\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport { JitsiConferenceEvents } from '../../JitsiConferenceEvents';\r\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\r\nimport RTCEvents from '../../service/RTC/RTCEvents';\r\nimport { createTrackStreamingStatusEvent } from '../../service/statistics/AnalyticsEvents';\r\nimport JitsiConference from '../../types/hand-crafted/JitsiConference';\r\nimport JitsiRemoteTrack from '../../types/hand-crafted/modules/RTC/JitsiRemoteTrack';\r\nimport RTC from '../../types/hand-crafted/modules/RTC/RTC';\r\nimport { VideoType } from '../../types/hand-crafted/service/RTC/VideoType';\r\nimport browser from '../browser';\r\nimport Statistics from '../statistics/statistics';\r\n\r\n/** Track streaming statuses. */\r\nexport enum TrackStreamingStatus {\r\n\r\n    /**\r\n     * Status indicating that streaming is currently active.\r\n     */\r\n    ACTIVE = 'active',\r\n\r\n    /**\r\n     * Status indicating that streaming is currently inactive.\r\n     * Inactive means the streaming was stopped on purpose from the bridge, like exiting forwarded sources or\r\n     * adaptivity decided to drop video because of not enough bandwidth.\r\n     */\r\n    INACTIVE = 'inactive',\r\n\r\n    /**\r\n     * Status indicating that streaming is currently interrupted.\r\n     */\r\n    INTERRUPTED = 'interrupted',\r\n\r\n    /**\r\n     * Status indicating that streaming is currently restoring.\r\n     */\r\n    RESTORING = 'restoring',\r\n  }\r\n\r\ntype StreamingStatusMap = {\r\n    // TODO: Replace this hand crafted VideoType when we convert VideoType.js to Typescript.\r\n    videoType?: VideoType, \r\n    startedMs?: number,\r\n    p2p?: boolean,\r\n    streamingStatus?: string,\r\n    value?: number\r\n};\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Default value of 500 milliseconds for {@link TrackStreamingStatusImpl.outOfForwardedSourcesTimeout}.\r\n */\r\nconst DEFAULT_NOT_IN_FORWARDED_SOURCES_TIMEOUT = 500;\r\n\r\n/**\r\n * Default value of 2500 milliseconds for {@link TrackStreamingStatusImpl.p2pRtcMuteTimeout}.\r\n */\r\nconst DEFAULT_P2P_RTC_MUTE_TIMEOUT = 2500;\r\n\r\n/**\r\n * Default value of 10000 milliseconds for {@link TrackStreamingStatusImpl.rtcMuteTimeout}.\r\n */\r\nconst DEFAULT_RTC_MUTE_TIMEOUT = 10000;\r\n\r\n/**\r\n * The time to wait a track to be restored. Track which was out of forwarded sources should be inactive and when\r\n * entering forwarded sources it becomes restoring and when data is received from bridge it will become active, but if\r\n * no data is received for some time we set status of that track streaming to interrupted.\r\n */\r\nconst DEFAULT_RESTORING_TIMEOUT = 10000;\r\n\r\n/**\r\n * Class is responsible for emitting JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED events.\r\n */\r\nexport class TrackStreamingStatusImpl {\r\n    rtc: RTC;\r\n    conference: JitsiConference;\r\n    track: JitsiRemoteTrack;\r\n\r\n    /**  This holds the timeout callback ID scheduled using window.setTimeout. */\r\n    trackTimer: number | null;\r\n\r\n    /**\r\n     * If video track frozen detection through RTC mute event is supported, we wait some time until video track is\r\n     * considered frozen. But because when the track falls out of forwarded sources it is expected for the video to\r\n     * freeze this timeout must be significantly reduced in \"out of forwarded sources\" case.\r\n     *\r\n     * Basically this value is used instead of {@link rtcMuteTimeout} when track is not in forwarded sources.\r\n     */\r\n    outOfForwardedSourcesTimeout: number;\r\n\r\n    /**\r\n     * How long we are going to wait for the corresponding signaling mute event after the RTC video track muted\r\n     * event is fired on the Media stream, before the connection interrupted is fired. The default value is\r\n     * {@link DEFAULT_P2P_RTC_MUTE_TIMEOUT}.\r\n     */\r\n    p2pRtcMuteTimeout: number;\r\n\r\n    /**\r\n     * How long we're going to wait after the RTC video track muted event for the corresponding signalling mute\r\n     * event, before the connection interrupted is fired. The default value is {@link DEFAULT_RTC_MUTE_TIMEOUT}.\r\n     *\r\n     * @returns amount of time in milliseconds\r\n     */\r\n    rtcMuteTimeout: number;\r\n\r\n    /**\r\n     * This holds a timestamp indicating  when remote video track was RTC muted. The purpose of storing the\r\n     * timestamp is to avoid the transition to disconnected status in case of legitimate video mute operation where\r\n     * the signalling video muted event can arrive shortly after RTC muted event.\r\n     *\r\n     * The timestamp is measured in milliseconds obtained with <tt>Date.now()</tt>.\r\n     *\r\n     * FIXME merge this logic with NO_DATA_FROM_SOURCE event implemented in JitsiLocalTrack by extending the event\r\n     * to the remote track and allowing to set different timeout for local and remote tracks.\r\n     */\r\n    rtcMutedTimestamp: number | null;\r\n\r\n    /** This holds the restoring timeout callback ID scheduled using window.setTimeout. */\r\n    restoringTimer: ReturnType<typeof setTimeout> | null;\r\n\r\n    /**\r\n     * This holds the current streaming status (along with all the internal events that happen while in that\r\n     * state).\r\n     *\r\n     * The goal is to send this information to the analytics backend for post-mortem analysis.\r\n     */\r\n    streamingStatusMap: StreamingStatusMap;\r\n\r\n    _onP2PStatus: () => void;\r\n    _onUserLeft: () => void;\r\n    _onTrackRtcMuted: () => void;\r\n    _onTrackRtcUnmuted: () => void;\r\n    _onSignallingMuteChanged: () => void;\r\n    _onTrackVideoTypeChanged: () => void;\r\n    _onLastNValueChanged: () => void;\r\n    _onForwardedSourcesChanged: () => void;\r\n\r\n    /* eslint-disable max-params*/\r\n    /**\r\n     * Calculates the new {@link TrackStreamingStatus} based on the values given for some specific remote track. It is\r\n     * assumed that the conference is currently in the JVB mode (in contrary to the P2P mode)\r\n     * @param isInForwardedSources - indicates whether the track is in the forwarded sources set. When set to\r\n     * false it means that JVB is not sending any video for the track.\r\n     * @param isRestoringTimedout - if true it means that the track has been outside of forwarded sources too\r\n     * long to be considered {@link TrackStreamingStatus.RESTORING}.\r\n     * @param isVideoMuted - true if the track is video muted and we should not expect to receive any video.\r\n     * @param isVideoTrackFrozen - if the current browser support video frozen detection then it will be set to\r\n     * true when the video track is frozen. If the current browser does not support frozen detection the it's always\r\n     * false.\r\n     * @return {TrackStreamingStatus} the new streaming status for the track for whom the values above were provided.\r\n     * @private\r\n     */\r\n    static _getNewStateForJvbMode(\r\n            isInForwardedSources: boolean,\r\n            isRestoringTimedout: boolean,\r\n            isVideoMuted: boolean,\r\n            isVideoTrackFrozen: boolean): TrackStreamingStatus {\r\n\r\n        // We are currently not checking the endpoint connection status received from the JVB.\r\n        if (isVideoMuted) {\r\n            // If the connection is active according to JVB and the track is video muted there is no way for the\r\n            // connection to be inactive, because the detection logic below only makes sense for video.\r\n            return TrackStreamingStatus.ACTIVE;\r\n        }\r\n\r\n        // Logic when isVideoTrackFrozen is supported\r\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\r\n            if (!isVideoTrackFrozen) {\r\n                // If the video is playing we're good\r\n                return TrackStreamingStatus.ACTIVE;\r\n            } else if (isInForwardedSources) {\r\n                return isRestoringTimedout ? TrackStreamingStatus.INTERRUPTED : TrackStreamingStatus.RESTORING;\r\n            }\r\n\r\n            return TrackStreamingStatus.INACTIVE;\r\n        }\r\n\r\n        // Because this browser is incapable of detecting frozen video we must rely on the forwarded sources value\r\n        return isInForwardedSources ? TrackStreamingStatus.ACTIVE : TrackStreamingStatus.INACTIVE;\r\n    }\r\n\r\n    /* eslint-enable max-params*/\r\n\r\n    /**\r\n     * In P2P mode we don't care about any values coming from the JVB and the streaming status can be only active or\r\n     * interrupted.\r\n     * @param isVideoMuted - true if video muted\r\n     * @param isVideoTrackFrozen - true if the video track for the remote track is currently frozen. If the\r\n     * current browser does not support video frozen detection then it's always false.\r\n     * @return {TrackStreamingStatus}\r\n     * @private\r\n     */\r\n    static _getNewStateForP2PMode(isVideoMuted: boolean, isVideoTrackFrozen: boolean): TrackStreamingStatus {\r\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\r\n            // There's no way to detect problems in P2P when there's no video track frozen detection...\r\n            return TrackStreamingStatus.ACTIVE;\r\n        }\r\n\r\n        return isVideoMuted || !isVideoTrackFrozen\r\n            ? TrackStreamingStatus.ACTIVE : TrackStreamingStatus.INTERRUPTED;\r\n    }\r\n\r\n    /**\r\n     * Creates new instance of <tt>TrackStreamingStatus</tt>.\r\n     *\r\n     * @constructor\r\n     * @param rtc - the RTC service instance\r\n     * @param conference - parent conference instance\r\n     * @param {Object} options\r\n     * @param {number} [options.p2pRtcMuteTimeout=2500] custom value for\r\n     * {@link TrackStreamingStatusImpl.p2pRtcMuteTimeout}.\r\n     * @param {number} [options.rtcMuteTimeout=2000] custom value for\r\n     * {@link TrackStreamingStatusImpl.rtcMuteTimeout}.\r\n     * @param {number} [options.outOfForwardedSourcesTimeout=500] custom value for\r\n     * {@link TrackStreamingStatusImpl.outOfForwardedSourcesTimeout}.\r\n     */\r\n    constructor(rtc: RTC, conference: JitsiConference, track: JitsiRemoteTrack, options: {\r\n        outOfForwardedSourcesTimeout: number,\r\n        p2pRtcMuteTimeout: number,\r\n        rtcMuteTimeout: number\r\n    }) {\r\n        this.rtc = rtc;\r\n        this.conference = conference;\r\n        this.track = track;\r\n\r\n        this.restoringTimer = null;\r\n        this.rtcMutedTimestamp = null;\r\n        this.streamingStatusMap = {};\r\n        this.trackTimer = null;\r\n\r\n        this.outOfForwardedSourcesTimeout = typeof options.outOfForwardedSourcesTimeout === 'number'\r\n            ? options.outOfForwardedSourcesTimeout : DEFAULT_NOT_IN_FORWARDED_SOURCES_TIMEOUT;\r\n\r\n        this.p2pRtcMuteTimeout = typeof options.p2pRtcMuteTimeout === 'number'\r\n            ? options.p2pRtcMuteTimeout : DEFAULT_P2P_RTC_MUTE_TIMEOUT;\r\n\r\n        this.rtcMuteTimeout = typeof options.rtcMuteTimeout === 'number'\r\n            ? options.rtcMuteTimeout : DEFAULT_RTC_MUTE_TIMEOUT;\r\n        logger.info(`RtcMuteTimeout set to: ${this.rtcMuteTimeout}`);\r\n    }\r\n\r\n    /**\r\n     * Gets the video frozen timeout for given source name.\r\n     * @return how long are we going to wait since RTC video muted even, before a video track is considered\r\n     * frozen.\r\n     * @private\r\n     */\r\n    _getVideoFrozenTimeout(): number {\r\n        const sourceName = this.track.getSourceName();\r\n\r\n        return this.rtc.isInForwardedSources(sourceName)\r\n            ? this.rtcMuteTimeout\r\n            : this.conference.isP2PActive() ? this.p2pRtcMuteTimeout : this.outOfForwardedSourcesTimeout;\r\n    }\r\n\r\n    /**\r\n     * Initializes <tt>TrackStreamingStatus</tt> and bind required event listeners.\r\n     */\r\n    init(): void {\r\n        // Handles P2P status changes\r\n        this._onP2PStatus = this.figureOutStreamingStatus.bind(this);\r\n        this.conference.on(JitsiConferenceEvents.P2P_STATUS, this._onP2PStatus);\r\n\r\n        // Used to send analytics events for the participant that left the call.\r\n        this._onUserLeft = this.onUserLeft.bind(this);\r\n        this.conference.on(JitsiConferenceEvents.USER_LEFT, this._onUserLeft);\r\n\r\n        // On some browsers MediaStreamTrack trigger \"onmute\"/\"onunmute\" events for video type tracks when they stop\r\n        // receiving data which is often a sign that remote user is having connectivity issues.\r\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\r\n\r\n            this._onTrackRtcMuted = this.onTrackRtcMuted.bind(this);\r\n            this.rtc.addListener(RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);\r\n\r\n            this._onTrackRtcUnmuted = this.onTrackRtcUnmuted.bind(this);\r\n            this.rtc.addListener(RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);\r\n\r\n            // Listened which will be bound to JitsiRemoteTrack to listen for signalling mute/unmute events.\r\n            this._onSignallingMuteChanged = this.onSignallingMuteChanged.bind(this);\r\n            this.track.on(JitsiTrackEvents.TRACK_MUTE_CHANGED, this._onSignallingMuteChanged);\r\n\r\n            // Used to send an analytics event when the video type changes.\r\n            this._onTrackVideoTypeChanged = this.onTrackVideoTypeChanged.bind(this);\r\n            this.track.on(JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED, this._onTrackVideoTypeChanged);\r\n        }\r\n\r\n        this._onForwardedSourcesChanged = this.onForwardedSourcesChanged.bind(this);\r\n        this.conference.on(JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED, this._onForwardedSourcesChanged);\r\n\r\n        this._onLastNValueChanged = this.figureOutStreamingStatus.bind(this);\r\n        this.rtc.on(RTCEvents.LASTN_VALUE_CHANGED, this._onLastNValueChanged);\r\n    }\r\n\r\n    /**\r\n     * Removes all event listeners and disposes of all resources held by this instance.\r\n     */\r\n    dispose(): void {\r\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\r\n            this.rtc.removeListener(RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);\r\n            this.rtc.removeListener(RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);\r\n\r\n            this.track.off(JitsiTrackEvents.TRACK_MUTE_CHANGED, this._onSignallingMuteChanged);\r\n        }\r\n\r\n        this.conference.off(JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED, this._onForwardedSourcesChanged);\r\n        this.conference.off(JitsiConferenceEvents.P2P_STATUS, this._onP2PStatus);\r\n        this.conference.off(JitsiConferenceEvents.USER_LEFT, this._onUserLeft);\r\n        this.rtc.removeListener(RTCEvents.LASTN_VALUE_CHANGED, this._onLastNValueChanged);\r\n\r\n        this.clearTimeout();\r\n        this.clearRtcMutedTimestamp();\r\n        this.maybeSendTrackStreamingStatusEvent(Date.now());\r\n        this.figureOutStreamingStatus();\r\n    }\r\n\r\n    /**\r\n     * Changes streaming status.\r\n     * @param newStatus\r\n     */\r\n    _changeStreamingStatus(newStatus: TrackStreamingStatus): void {\r\n        if (this.track.getTrackStreamingStatus() !== newStatus) {\r\n\r\n            const sourceName = this.track.getSourceName();\r\n\r\n            this.track._setTrackStreamingStatus(newStatus);\r\n\r\n            logger.debug(`Emit track streaming status(${Date.now()}) ${sourceName}: ${newStatus}`);\r\n\r\n            // Log the event on CallStats\r\n            Statistics.sendLog(\r\n                JSON.stringify({\r\n                    id: 'track.streaming.status',\r\n                    track: sourceName,\r\n                    status: newStatus\r\n                }));\r\n\r\n            // It's common for the event listeners to access the JitsiRemoteTrack. Thus pass it as a parameter here.\r\n            this.track.emit(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED, this.track, newStatus);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Reset the postponed \"streaming interrupted\" event which was previously scheduled as a timeout on RTC 'onmute'\r\n     * event.\r\n     */\r\n    clearTimeout(): void {\r\n        if (this.trackTimer) {\r\n            window.clearTimeout(this.trackTimer);\r\n            this.trackTimer = null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Clears the timestamp of the RTC muted event for remote video track.\r\n     */\r\n    clearRtcMutedTimestamp(): void {\r\n        this.rtcMutedTimestamp = null;\r\n    }\r\n\r\n    /**\r\n     * Checks if track is considered frozen.\r\n     * @return <tt>true</tt> if the video has frozen or <tt>false</tt> when it's either not considered frozen\r\n     * (yet) or if freeze detection is not supported by the current browser.\r\n     *\r\n     * FIXME merge this logic with NO_DATA_FROM_SOURCE event implemented in JitsiLocalTrack by extending the event to\r\n     *       the remote track and allowing to set different timeout for local and remote tracks.\r\n     */\r\n    isVideoTrackFrozen(): boolean {\r\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\r\n            return false;\r\n        }\r\n\r\n        const isVideoRTCMuted = this.track.isWebRTCTrackMuted();\r\n        const rtcMutedTimestamp = this.rtcMutedTimestamp;\r\n        const timeout = this._getVideoFrozenTimeout();\r\n\r\n        return isVideoRTCMuted && typeof rtcMutedTimestamp === 'number' && (Date.now() - rtcMutedTimestamp) >= timeout;\r\n    }\r\n\r\n    /**\r\n     * Figures out (and updates) the current streaming status for the track identified by the source name.\r\n     */\r\n    figureOutStreamingStatus(): void {\r\n        const sourceName = this.track.getSourceName();\r\n        const inP2PMode = this.conference.isP2PActive();\r\n        const isRestoringTimedOut = this._isRestoringTimedout();\r\n        const audioOnlyMode = this.conference.getLastN() === 0;\r\n\r\n        // NOTE Overriding videoMuted to true for audioOnlyMode should disable any detection based on video playback or\r\n        // forwarded sources.\r\n        const isVideoMuted = this.track.isMuted() || audioOnlyMode;\r\n        const isVideoTrackFrozen = this.isVideoTrackFrozen();\r\n        const isInForwardedSources = this.rtc.isInForwardedSources(sourceName);\r\n\r\n        const newState\r\n            = inP2PMode\r\n                ? TrackStreamingStatusImpl._getNewStateForP2PMode(\r\n                    isVideoMuted,\r\n                    isVideoTrackFrozen)\r\n                : TrackStreamingStatusImpl._getNewStateForJvbMode(\r\n                    isInForwardedSources,\r\n                    isRestoringTimedOut,\r\n                    isVideoMuted,\r\n                    isVideoTrackFrozen);\r\n\r\n        // if the new state is not restoring clear timers and timestamps that we use to track the restoring state\r\n        if (newState !== TrackStreamingStatus.RESTORING) {\r\n            this._clearRestoringTimer();\r\n        }\r\n\r\n        logger.debug(\r\n            `Figure out conn status for ${sourceName}, is video muted: ${\r\n                isVideoMuted} video track frozen: ${\r\n                isVideoTrackFrozen} p2p mode: ${\r\n                inP2PMode} is in forwarded sources: ${\r\n                isInForwardedSources} currentStatus => newStatus: ${\r\n                this.track.getTrackStreamingStatus()} => ${newState}`);\r\n\r\n        const oldStreamingStatus = this.streamingStatusMap || {};\r\n\r\n        // Send an analytics event (guard on either the p2p flag or the streaming status has changed since the last\r\n        // time this code block run).\r\n        if (!('p2p' in oldStreamingStatus)\r\n            || !('streamingStatus' in oldStreamingStatus)\r\n            || oldStreamingStatus.p2p !== inP2PMode\r\n            || oldStreamingStatus.streamingStatus !== newState) {\r\n\r\n            const nowMs = Date.now();\r\n\r\n            this.maybeSendTrackStreamingStatusEvent(nowMs);\r\n\r\n            this.streamingStatusMap = {\r\n                ...oldStreamingStatus,\r\n                streamingStatus: newState,\r\n                p2p: inP2PMode,\r\n                startedMs: nowMs\r\n            };\r\n\r\n            // sometimes (always?) we're late to hook the TRACK_VIDEOTYPE_CHANGED event and the video type is not in\r\n            // oldStreamingStatus.\r\n            if (!('videoType' in this.streamingStatusMap)) {\r\n                this.streamingStatusMap.videoType = this.track.getVideoType();\r\n            }\r\n        }\r\n        this._changeStreamingStatus(newState);\r\n    }\r\n\r\n    /**\r\n     * Computes the duration of the current streaming status for the track (i.e. 15 seconds in the INTERRUPTED state)\r\n     * and sends a track streaming status event.\r\n     * @param nowMs - The current time (in millis).\r\n     */\r\n    maybeSendTrackStreamingStatusEvent(nowMs: number): void {\r\n        const trackStreamingStatus = this.streamingStatusMap;\r\n\r\n        if (trackStreamingStatus\r\n            && 'startedMs' in trackStreamingStatus\r\n            && 'videoType' in trackStreamingStatus\r\n            && 'streamingStatus' in trackStreamingStatus\r\n            && 'p2p' in trackStreamingStatus) {\r\n            trackStreamingStatus.value = nowMs - trackStreamingStatus.startedMs;\r\n            Statistics.sendAnalytics(createTrackStreamingStatusEvent(trackStreamingStatus));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * On change in forwarded sources set check all leaving and entering track to change their corresponding statuses.\r\n     *\r\n     * @param leavingForwardedSources - The array of sourceName leaving forwarded sources.\r\n     * @param enteringForwardedSources - The array of sourceName entering forwarded sources.\r\n     * @param timestamp - The time in millis\r\n     * @private\r\n     */\r\n    onForwardedSourcesChanged(\r\n            leavingForwardedSources: string[] = [],\r\n            enteringForwardedSources: string[] = [],\r\n            timestamp: number): void {\r\n\r\n        const sourceName = this.track.getSourceName();\r\n\r\n        // If the browser doesn't fire the mute/onmute events when the remote peer stops/starts sending media,\r\n        // calculate the streaming status for all the tracks since it won't get triggered automatically on the track\r\n        // that has started/stopped receiving media.\r\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\r\n            this.figureOutStreamingStatus();\r\n        }\r\n\r\n        if (leavingForwardedSources.includes(sourceName)) {\r\n            this.track._clearEnteredForwardedSourcesTimestamp();\r\n            this._clearRestoringTimer();\r\n            browser.supportsVideoMuteOnConnInterrupted() && this.figureOutStreamingStatus();\r\n        }\r\n\r\n        if (enteringForwardedSources.includes(sourceName)) {\r\n            // store the timestamp this track is entering forwarded sources\r\n            this.track._setEnteredForwardedSourcesTimestamp(timestamp);\r\n            browser.supportsVideoMuteOnConnInterrupted() && this.figureOutStreamingStatus();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Clears the restoring timer for video track and the timestamp for entering forwarded sources.\r\n     */\r\n    _clearRestoringTimer(): void {\r\n        const rTimer = this.restoringTimer;\r\n\r\n        if (rTimer) {\r\n            clearTimeout(rTimer);\r\n            this.restoringTimer = null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Checks whether a track had stayed enough in restoring state, compares current time and the time the track\r\n     * entered in forwarded sources. If it hasn't timedout and there is no timer added, add new timer in order to give\r\n     * it more time to become active or mark it as interrupted on next check.\r\n     *\r\n     * @returns <tt>true</tt> if the track was in restoring state more than the timeout\r\n     * ({@link DEFAULT_RESTORING_TIMEOUT}.) in order to set its status to interrupted.\r\n     * @private\r\n     */\r\n    _isRestoringTimedout(): boolean {\r\n        const enteredForwardedSourcesTimestamp = this.track._getEnteredForwardedSourcesTimestamp();\r\n\r\n        if (enteredForwardedSourcesTimestamp\r\n            && (Date.now() - enteredForwardedSourcesTimestamp) >= DEFAULT_RESTORING_TIMEOUT) {\r\n            return true;\r\n        }\r\n\r\n        // still haven't reached timeout, if there is no timer scheduled, schedule one so we can track the restoring\r\n        // state and change it after reaching the timeout\r\n        const rTimer = this.restoringTimer;\r\n\r\n        if (!rTimer) {\r\n            this.restoringTimer = setTimeout(() => this.figureOutStreamingStatus(), DEFAULT_RESTORING_TIMEOUT);\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    /** Checks whether a track is the current track. */\r\n    _isCurrentTrack(track: JitsiRemoteTrack): boolean {\r\n        return track.getSourceName() === this.track.getSourceName();\r\n    }\r\n\r\n    /**\r\n     * Sends a last/final track streaming status event for the track of the user that left the conference.\r\n     * @param id - The id of the participant that left the conference.\r\n     */\r\n    onUserLeft(id: string): void {\r\n        if (this.track.getParticipantId() === id) {\r\n            this.maybeSendTrackStreamingStatusEvent(Date.now());\r\n            this.streamingStatusMap = {};\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Handles RTC 'onmute' event for the video track.\r\n     *\r\n     * @param track - The video track for which 'onmute' event will be processed.\r\n     */\r\n    onTrackRtcMuted(track: JitsiRemoteTrack): void {\r\n        if (!this._isCurrentTrack(track)) {\r\n            return;\r\n        }\r\n\r\n        const sourceName = track.getSourceName();\r\n\r\n        logger.debug(`Detector track RTC muted: ${sourceName}`, Date.now());\r\n\r\n        this.rtcMutedTimestamp = Date.now();\r\n        if (!track.isMuted()) {\r\n            // If the user is not muted according to the signalling we'll give it some time, before the streaming\r\n            // interrupted event is triggered.\r\n            this.clearTimeout();\r\n\r\n            // The timeout is reduced when track is not in the forwarded sources\r\n            const timeout = this._getVideoFrozenTimeout();\r\n\r\n            this.trackTimer = window.setTimeout(() => {\r\n                logger.debug(`Set RTC mute timeout for: ${sourceName} of ${timeout} ms`);\r\n                this.clearTimeout();\r\n                this.figureOutStreamingStatus();\r\n            }, timeout);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Handles RTC 'onunmute' event for the video track.\r\n     *\r\n     * @param track - The video track for which 'onunmute' event will be processed.\r\n     */\r\n    onTrackRtcUnmuted(track: JitsiRemoteTrack): void {\r\n        if (!this._isCurrentTrack(track)) {\r\n            return;\r\n        }\r\n\r\n        const sourceName = this.track.getSourceName();\r\n\r\n        logger.debug(`Detector track RTC unmuted: ${sourceName}`, Date.now());\r\n\r\n        this.clearTimeout();\r\n        this.clearRtcMutedTimestamp();\r\n\r\n        this.figureOutStreamingStatus();\r\n    }\r\n\r\n    /**\r\n     * Here the signalling \"mute\"/\"unmute\" events are processed.\r\n     *\r\n     * @param track - The remote video track for which the signalling mute/unmute event will be\r\n     * processed.\r\n     */\r\n    onSignallingMuteChanged(track: JitsiRemoteTrack): void {\r\n        if (!this._isCurrentTrack(track)) {\r\n            return;\r\n        }\r\n\r\n        const sourceName = this.track.getSourceName();\r\n\r\n        logger.debug(`Detector on track signalling mute changed: ${sourceName}`, track.isMuted());\r\n\r\n        this.figureOutStreamingStatus();\r\n    }\r\n\r\n    /**\r\n     * Sends a track streaming status event as a result of the video type changing.\r\n     * @deprecated this will go away with full multiple streams support\r\n     * @param type - The video type.\r\n     */\r\n    onTrackVideoTypeChanged(type: VideoType): void {\r\n        const nowMs = Date.now();\r\n\r\n        this.maybeSendTrackStreamingStatusEvent(nowMs);\r\n\r\n        this.streamingStatusMap = {\r\n            ...this.streamingStatusMap || {},\r\n            videoType: type,\r\n            startedMs: nowMs\r\n        };\r\n    }\r\n}\r\n\r\nexport default TrackStreamingStatusImpl;\r\n","import * as JitsiTrackEvents from '../../JitsiTrackEvents';\r\nimport { createTtfmEvent } from '../../service/statistics/AnalyticsEvents';\r\nimport TrackStreamingStatusImpl, { TrackStreamingStatus } from '../connectivity/TrackStreamingStatus';\r\nimport Statistics from '../statistics/statistics';\r\n\r\nimport JitsiTrack from './JitsiTrack';\r\n\r\nconst logger = require('@jitsi/logger').getLogger(__filename);\r\n\r\nconst RTCEvents = require('../../service/RTC/RTCEvents');\r\n\r\nlet ttfmTrackerAudioAttached = false;\r\nlet ttfmTrackerVideoAttached = false;\r\n\r\n/**\r\n * List of container events that we are going to process. _onContainerEventHandler will be added as listener to the\r\n * container for every event in the list.\r\n */\r\nconst containerEvents = [ 'abort', 'canplaythrough', 'ended', 'error' ];\r\n\r\n/* eslint-disable max-params */\r\n\r\n/**\r\n * Represents a single media track (either audio or video).\r\n */\r\nexport default class JitsiRemoteTrack extends JitsiTrack {\r\n    /**\r\n     * Creates new JitsiRemoteTrack instance.\r\n     * @param {RTC} rtc the RTC service instance.\r\n     * @param {JitsiConference} conference the conference to which this track\r\n     *        belongs to\r\n     * @param {string} ownerEndpointId the endpoint ID of the track owner\r\n     * @param {MediaStream} stream WebRTC MediaStream, parent of the track\r\n     * @param {MediaStreamTrack} track underlying WebRTC MediaStreamTrack for\r\n     *        the new JitsiRemoteTrack\r\n     * @param {MediaType} mediaType the type of the media\r\n     * @param {VideoType} videoType the type of the video if applicable\r\n     * @param {number} ssrc the SSRC number of the Media Stream\r\n     * @param {boolean} muted the initial muted state\r\n     * @param {boolean} isP2P indicates whether or not this track belongs to a\r\n     * P2P session\r\n     * @param {String} sourceName the source name signaled for the track\r\n     * @throws {TypeError} if <tt>ssrc</tt> is not a number.\r\n     * @constructor\r\n     */\r\n    constructor(\r\n            rtc,\r\n            conference,\r\n            ownerEndpointId,\r\n            stream,\r\n            track,\r\n            mediaType,\r\n            videoType,\r\n            ssrc,\r\n            muted,\r\n            isP2P,\r\n            sourceName) {\r\n        super(\r\n            conference,\r\n            stream,\r\n            track,\r\n            () => {\r\n                // Nothing to do if the track is inactive.\r\n            },\r\n            mediaType,\r\n            videoType);\r\n        this.rtc = rtc;\r\n\r\n        // Prevent from mixing up type of SSRC which should be a number\r\n        if (typeof ssrc !== 'number') {\r\n            throw new TypeError(`SSRC ${ssrc} is not a number`);\r\n        }\r\n        this.ssrc = ssrc;\r\n        this.ownerEndpointId = ownerEndpointId;\r\n        this.muted = muted;\r\n        this.isP2P = isP2P;\r\n        this._sourceName = sourceName;\r\n        this._trackStreamingStatus = null;\r\n        this._trackStreamingStatusImpl = null;\r\n\r\n        /**\r\n         * This holds the timestamp indicating when remote video track entered forwarded sources set. Track entering\r\n         * forwardedSources will have streaming status restoring and when we start receiving video will become active,\r\n         * but if video is not received for certain time {@link DEFAULT_RESTORING_TIMEOUT} that track streaming status\r\n         * will become interrupted.\r\n         */\r\n        this._enteredForwardedSourcesTimestamp = null;\r\n\r\n        this.addEventListener = this.on = this._addEventListener.bind(this);\r\n        this.removeEventListener = this.off = this._removeEventListener.bind(this);\r\n\r\n        logger.debug(`New remote track added: ${this}`);\r\n\r\n        // we want to mark whether the track has been ever muted\r\n        // to detect ttfm events for startmuted conferences, as it can\r\n        // significantly increase ttfm values\r\n        this.hasBeenMuted = muted;\r\n\r\n        // Bind 'onmute' and 'onunmute' event handlers\r\n        if (this.rtc && this.track) {\r\n            this._bindTrackHandlers();\r\n        }\r\n        this._containerHandlers = {};\r\n        containerEvents.forEach(event => {\r\n            this._containerHandlers[event] = this._containerEventHandler.bind(this, event);\r\n        });\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n    /**\r\n     * Attaches the track handlers.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    _bindTrackHandlers() {\r\n        this.track.addEventListener('mute', () => this._onTrackMute());\r\n        this.track.addEventListener('unmute', () => this._onTrackUnmute());\r\n        this.track.addEventListener('ended', () => {\r\n            logger.debug(`\"onended\" event(${Date.now()}): ${this}`);\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Overrides addEventListener method to init TrackStreamingStatus instance when there are listeners for the\r\n     * {@link JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED} event.\r\n     *\r\n     * @param {string} event - event name\r\n     * @param {function} handler - event handler\r\n     */\r\n    _addEventListener(event, handler) {\r\n        super.addListener(event, handler);\r\n\r\n        if (event === JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED\r\n            && this.listenerCount(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED)\r\n            && !this._trackStreamingStatusImpl\r\n        ) {\r\n            this._initTrackStreamingStatus();\r\n            logger.debug(`Initializing track streaming status: ${this._sourceName}`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Overrides removeEventListener method to dispose TrackStreamingStatus instance.\r\n     *\r\n     * @param {string} event - event name\r\n     * @param {function} handler - event handler\r\n     */\r\n    _removeEventListener(event, handler) {\r\n        super.removeListener(event, handler);\r\n\r\n        if (event === JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED\r\n            && !this.listenerCount(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED)\r\n        ) {\r\n            this._disposeTrackStreamingStatus();\r\n            logger.debug(`Disposing track streaming status: ${this._sourceName}`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Callback invoked when the track is muted. Emits an event notifying\r\n     * listeners of the mute event.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onTrackMute() {\r\n        logger.debug(`\"onmute\" event(${Date.now()}): ${this}`);\r\n\r\n        this.rtc.eventEmitter.emit(RTCEvents.REMOTE_TRACK_MUTE, this);\r\n    }\r\n\r\n    /**\r\n     * Callback invoked when the track is unmuted. Emits an event notifying\r\n     * listeners of the mute event.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onTrackUnmute() {\r\n        logger.debug(`\"onunmute\" event(${Date.now()}): ${this}`);\r\n\r\n        this.rtc.eventEmitter.emit(RTCEvents.REMOTE_TRACK_UNMUTE, this);\r\n    }\r\n\r\n    /**\r\n     * Removes attached event listeners and dispose TrackStreamingStatus .\r\n     *\r\n     * @returns {Promise}\r\n     */\r\n    dispose() {\r\n        this._disposeTrackStreamingStatus();\r\n\r\n        return super.dispose();\r\n    }\r\n\r\n    /**\r\n     * Sets current muted status and fires an events for the change.\r\n     * @param value the muted status.\r\n     */\r\n    setMute(value) {\r\n        if (this.muted === value) {\r\n            return;\r\n        }\r\n\r\n        if (value) {\r\n            this.hasBeenMuted = true;\r\n        }\r\n\r\n        // we can have a fake video stream\r\n        if (this.stream) {\r\n            this.stream.muted = value;\r\n        }\r\n\r\n        this.muted = value;\r\n        this.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED, this);\r\n    }\r\n\r\n    /**\r\n     * Returns the current muted status of the track.\r\n     * @returns {boolean|*|JitsiRemoteTrack.muted} <tt>true</tt> if the track is\r\n     * muted and <tt>false</tt> otherwise.\r\n     */\r\n    isMuted() {\r\n        return this.muted;\r\n    }\r\n\r\n    /**\r\n     * Returns the participant id which owns the track.\r\n     *\r\n     * @returns {string} the id of the participants. It corresponds to the\r\n     * Colibri endpoint id/MUC nickname in case of Jitsi-meet.\r\n     */\r\n    getParticipantId() {\r\n        return this.ownerEndpointId;\r\n    }\r\n\r\n    /**\r\n     * Return false;\r\n     */\r\n    isLocal() {\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * Returns the synchronization source identifier (SSRC) of this remote\r\n     * track.\r\n     *\r\n     * @returns {number} the SSRC of this remote track.\r\n     */\r\n    getSSRC() {\r\n        return this.ssrc;\r\n    }\r\n\r\n\r\n    /**\r\n     * Returns the tracks source name\r\n     *\r\n     * @returns {string} the track's source name\r\n     */\r\n    getSourceName() {\r\n        return this._sourceName;\r\n    }\r\n\r\n    /**\r\n     * Update the properties when the track is remapped to another source.\r\n     *\r\n     * @param {string} owner The endpoint ID of the new owner.\r\n     * @param {string} name The new source name.\r\n     */\r\n    setNewSource(owner, name) {\r\n        this.ownerEndpointId = owner;\r\n        this._sourceName = name;\r\n        this.emit(JitsiTrackEvents.TRACK_OWNER_CHANGED, owner);\r\n    }\r\n\r\n    /**\r\n     * Changes the video type of the track.\r\n     *\r\n     * @param {string} type - The new video type(\"camera\", \"desktop\").\r\n     */\r\n    _setVideoType(type) {\r\n        if (this.videoType === type) {\r\n            return;\r\n        }\r\n        this.videoType = type;\r\n        this.emit(JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED, type);\r\n    }\r\n\r\n    /**\r\n     * Handles track play events.\r\n     */\r\n    _playCallback() {\r\n        if (!this.conference.room) {\r\n            return;\r\n        }\r\n\r\n        const type = this.isVideoTrack() ? 'video' : 'audio';\r\n\r\n        const now = window.performance.now();\r\n\r\n        console.log(`(TIME) Render ${type}:\\t`, now);\r\n        this.conference.getConnectionTimes()[`${type}.render`] = now;\r\n\r\n        // The conference can be started without calling GUM\r\n        // FIXME if there would be a module for connection times this kind\r\n        // of logic (gumDuration or ttfm) should end up there\r\n        const gumStart = window.connectionTimes['obtainPermissions.start'];\r\n        const gumEnd = window.connectionTimes['obtainPermissions.end'];\r\n        const gumDuration\r\n            = !isNaN(gumEnd) && !isNaN(gumStart) ? gumEnd - gumStart : 0;\r\n\r\n        // Subtract the muc.joined-to-session-initiate duration because jicofo\r\n        // waits until there are 2 participants to start Jingle sessions.\r\n        const ttfm = now\r\n            - (this.conference.getConnectionTimes()['session.initiate']\r\n                - this.conference.getConnectionTimes()['muc.joined'])\r\n            - gumDuration;\r\n\r\n        this.conference.getConnectionTimes()[`${type}.ttfm`] = ttfm;\r\n        console.log(`(TIME) TTFM ${type}:\\t`, ttfm);\r\n\r\n        Statistics.sendAnalytics(createTtfmEvent(\r\n            {\r\n                'media_type': type,\r\n                muted: this.hasBeenMuted,\r\n                value: ttfm\r\n            }));\r\n\r\n    }\r\n\r\n    /**\r\n     * Attach time to first media tracker only if there is conference and only\r\n     * for the first element.\r\n     * @param container the HTML container which can be 'video' or 'audio'\r\n     * element.\r\n     * @private\r\n     */\r\n    _attachTTFMTracker(container) {\r\n        if ((ttfmTrackerAudioAttached && this.isAudioTrack())\r\n            || (ttfmTrackerVideoAttached && this.isVideoTrack())) {\r\n            return;\r\n        }\r\n\r\n        if (this.isAudioTrack()) {\r\n            ttfmTrackerAudioAttached = true;\r\n        }\r\n        if (this.isVideoTrack()) {\r\n            ttfmTrackerVideoAttached = true;\r\n        }\r\n\r\n        container.addEventListener('canplay', this._playCallback.bind(this));\r\n    }\r\n\r\n    /**\r\n     * Called when the track has been attached to a new container.\r\n     *\r\n     * @param {HTMLElement} container the HTML container which can be 'video' or 'audio' element.\r\n     * @private\r\n     */\r\n    _onTrackAttach(container) {\r\n        containerEvents.forEach(event => {\r\n            container.addEventListener(event, this._containerHandlers[event]);\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Called when the track has been detached from a container.\r\n     *\r\n     * @param {HTMLElement} container the HTML container which can be 'video' or 'audio' element.\r\n     * @private\r\n     */\r\n    _onTrackDetach(container) {\r\n        containerEvents.forEach(event => {\r\n            container.removeEventListener(event, this._containerHandlers[event]);\r\n        });\r\n    }\r\n\r\n    /**\r\n     * An event handler for events triggered by the attached container.\r\n     *\r\n     * @param {string} type - The type of the event.\r\n     */\r\n    _containerEventHandler(type) {\r\n        logger.debug(`${type} handler was called for a container with attached ${this}`);\r\n    }\r\n\r\n    /**\r\n     * Returns a string with a description of the current status of the track.\r\n     *\r\n     * @returns {string}\r\n     */\r\n    _getStatus() {\r\n        const { enabled, muted, readyState } = this.track;\r\n\r\n        return `readyState: ${readyState}, muted: ${muted}, enabled: ${enabled}`;\r\n    }\r\n\r\n    /**\r\n     * Initializes trackStreamingStatusImpl.\r\n     */\r\n    _initTrackStreamingStatus() {\r\n        const config = this.conference.options.config;\r\n\r\n        this._trackStreamingStatus = TrackStreamingStatus.ACTIVE;\r\n\r\n        this._trackStreamingStatusImpl = new TrackStreamingStatusImpl(\r\n            this.rtc,\r\n            this.conference,\r\n            this,\r\n            {\r\n                // These options are not public API, leaving it here only as an entry point through config for\r\n                // tuning up purposes. Default values should be adjusted as soon as optimal values are discovered.\r\n                p2pRtcMuteTimeout: config._p2pConnStatusRtcMuteTimeout,\r\n                rtcMuteTimeout: config._peerConnStatusRtcMuteTimeout,\r\n                outOfForwardedSourcesTimeout: config._peerConnStatusOutOfLastNTimeout\r\n            });\r\n\r\n        this._trackStreamingStatusImpl.init();\r\n\r\n        // In some edge cases, both browser 'unmute' and bridge's forwarded sources events are received before a\r\n        // LargeVideoUpdate is scheduled for auto-pinning a new screenshare track. If there are no layout changes and\r\n        // no further track events are received for the SS track, a black tile will be displayed for screenshare on\r\n        // stage. Fire a TRACK_STREAMING_STATUS_CHANGED event if the media is already being received for the remote\r\n        // track to prevent this from happening.\r\n        !this._trackStreamingStatusImpl.isVideoTrackFrozen()\r\n            && this.rtc.eventEmitter.emit(\r\n                JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED,\r\n                this,\r\n                this._trackStreamingStatus);\r\n    }\r\n\r\n    /**\r\n     * Disposes trackStreamingStatusImpl and clears trackStreamingStatus.\r\n     */\r\n    _disposeTrackStreamingStatus() {\r\n        if (this._trackStreamingStatusImpl) {\r\n            this._trackStreamingStatusImpl.dispose();\r\n            this._trackStreamingStatusImpl = null;\r\n            this._trackStreamingStatus = null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Updates track's streaming status.\r\n     *\r\n     * @param {string} state the current track streaming state. {@link TrackStreamingStatus}.\r\n     */\r\n    _setTrackStreamingStatus(status) {\r\n        this._trackStreamingStatus = status;\r\n    }\r\n\r\n    /**\r\n     * Returns track's streaming status.\r\n     *\r\n     * @returns {string} the streaming status <tt>TrackStreamingStatus</tt> of the track. Returns null\r\n     * if trackStreamingStatusImpl hasn't been initialized.\r\n     *\r\n     * {@link TrackStreamingStatus}.\r\n     */\r\n    getTrackStreamingStatus() {\r\n        return this._trackStreamingStatus;\r\n    }\r\n\r\n    /**\r\n     * Clears the timestamp of when the track entered forwarded sources.\r\n     */\r\n    _clearEnteredForwardedSourcesTimestamp() {\r\n        this._enteredForwardedSourcesTimestamp = null;\r\n    }\r\n\r\n    /**\r\n     * Updates the timestamp of when the track entered forwarded sources.\r\n     *\r\n     * @param {number} timestamp the time in millis\r\n     */\r\n    _setEnteredForwardedSourcesTimestamp(timestamp) {\r\n        this._enteredForwardedSourcesTimestamp = timestamp;\r\n    }\r\n\r\n    /**\r\n     * Returns the timestamp of when the track entered forwarded sources.\r\n     *\r\n     * @returns {number} the time in millis\r\n     */\r\n    _getEnteredForwardedSourcesTimestamp() {\r\n        return this._enteredForwardedSourcesTimestamp;\r\n    }\r\n\r\n    /**\r\n     * Creates a text representation of this remote track instance.\r\n     * @return {string}\r\n     */\r\n    toString() {\r\n        return `RemoteTrack[userID: ${this.getParticipantId()}, type: ${this.getType()}, ssrc: ${\r\n            this.getSSRC()}, p2p: ${this.isP2P}, sourceName: ${this._sourceName}, status: {${this._getStatus()}}]`;\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport transform from 'sdp-transform';\r\n\r\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport { getSourceIndexFromSourceName } from '../../service/RTC/SignalingLayer';\r\nimport { VideoType } from '../../service/RTC/VideoType';\r\nimport browser from '../browser';\r\nimport FeatureFlags from '../flags/FeatureFlags';\r\n\r\nconst logger = getLogger(__filename);\r\nconst DESKTOP_SHARE_RATE = 500000;\r\nconst LD_BITRATE = 200000;\r\nconst SD_BITRATE = 700000;\r\nconst SIM_LAYER_1_RID = '1';\r\nconst SIM_LAYER_2_RID = '2';\r\nconst SIM_LAYER_3_RID = '3';\r\n\r\nexport const HD_BITRATE = 2500000;\r\nexport const HD_SCALE_FACTOR = 1;\r\nexport const LD_SCALE_FACTOR = 4;\r\nexport const SD_SCALE_FACTOR = 2;\r\nexport const SIM_LAYER_RIDS = [ SIM_LAYER_1_RID, SIM_LAYER_2_RID, SIM_LAYER_3_RID ];\r\n\r\n/**\r\n * Handles track related operations on TraceablePeerConnection when browser is\r\n * running in unified plan mode.\r\n */\r\nexport class TPCUtils {\r\n    /**\r\n     * Creates a new instance for a given TraceablePeerConnection\r\n     *\r\n     * @param peerconnection - the tpc instance for which we have utility functions.\r\n     */\r\n    constructor(peerconnection) {\r\n        this.pc = peerconnection;\r\n        const bitrateSettings = this.pc.options?.videoQuality?.maxBitratesVideo;\r\n        const standardBitrates = {\r\n            low: LD_BITRATE,\r\n            standard: SD_BITRATE,\r\n            high: HD_BITRATE\r\n        };\r\n\r\n        // Check if the max. bitrates for video are specified through config.js videoQuality settings.\r\n        // Right now only VP8 bitrates are configured on the simulcast encodings, VP9 bitrates have to be\r\n        // configured on the SDP using b:AS line.\r\n        this.videoBitrates = bitrateSettings ?? standardBitrates;\r\n        const encodingBitrates = this.videoBitrates.VP8 ?? this.videoBitrates;\r\n\r\n        /**\r\n         * The startup configuration for the stream encodings that are applicable to\r\n         * the video stream when a new sender is created on the peerconnection. The initial\r\n         * config takes into account the differences in browser's simulcast implementation.\r\n         *\r\n         * Encoding parameters:\r\n         * active - determine the on/off state of a particular encoding.\r\n         * maxBitrate - max. bitrate value to be applied to that particular encoding\r\n         *  based on the encoding's resolution and config.js videoQuality settings if applicable.\r\n         * rid - Rtp Stream ID that is configured for a particular simulcast stream.\r\n         * scaleResolutionDownBy - the factor by which the encoding is scaled down from the\r\n         *  original resolution of the captured video.\r\n         */\r\n        this.localStreamEncodingsConfig = [\r\n            {\r\n                active: true,\r\n                maxBitrate: browser.isFirefox() ? encodingBitrates.high : encodingBitrates.low,\r\n                rid: SIM_LAYER_1_RID,\r\n                scaleResolutionDownBy: browser.isFirefox() ? HD_SCALE_FACTOR : LD_SCALE_FACTOR\r\n            },\r\n            {\r\n                active: true,\r\n                maxBitrate: encodingBitrates.standard,\r\n                rid: SIM_LAYER_2_RID,\r\n                scaleResolutionDownBy: SD_SCALE_FACTOR\r\n            },\r\n            {\r\n                active: true,\r\n                maxBitrate: browser.isFirefox() ? encodingBitrates.low : encodingBitrates.high,\r\n                rid: SIM_LAYER_3_RID,\r\n                scaleResolutionDownBy: browser.isFirefox() ? LD_SCALE_FACTOR : HD_SCALE_FACTOR\r\n            }\r\n        ];\r\n    }\r\n\r\n    /**\r\n     * Obtains stream encodings that need to be configured on the given track based\r\n     * on the track media type and the simulcast setting.\r\n     * @param {JitsiLocalTrack} localTrack\r\n     */\r\n    _getStreamEncodings(localTrack) {\r\n        if (this.pc.isSimulcastOn() && localTrack.isVideoTrack()) {\r\n            return this.localStreamEncodingsConfig;\r\n        }\r\n\r\n        return localTrack.isVideoTrack()\r\n            ? [ {\r\n                active: true,\r\n                maxBitrate: this.videoBitrates.high\r\n            } ]\r\n            : [ { active: true } ];\r\n    }\r\n\r\n    /**\r\n     * Ensures that the ssrcs associated with a FID ssrc-group appear in the correct order, i.e.,\r\n     * the primary ssrc first and the secondary rtx ssrc later. This is important for unified\r\n     * plan since we have only one FID group per media description.\r\n     * @param {Object} description the webRTC session description instance for the remote\r\n     * description.\r\n     * @private\r\n     */\r\n    ensureCorrectOrderOfSsrcs(description) {\r\n        const parsedSdp = transform.parse(description.sdp);\r\n\r\n        parsedSdp.media.forEach(mLine => {\r\n            if (mLine.type === MediaType.AUDIO) {\r\n                return;\r\n            }\r\n            if (!mLine.ssrcGroups || !mLine.ssrcGroups.length) {\r\n                return;\r\n            }\r\n            let reorderedSsrcs = [];\r\n\r\n            const ssrcs = new Set();\r\n\r\n            mLine.ssrcGroups.map(group =>\r\n                group.ssrcs\r\n                    .split(' ')\r\n                    .filter(Boolean)\r\n                    .forEach(ssrc => ssrcs.add(ssrc))\r\n            );\r\n\r\n            ssrcs.forEach(ssrc => {\r\n                const sources = mLine.ssrcs.filter(source => source.id.toString() === ssrc);\r\n\r\n                reorderedSsrcs = reorderedSsrcs.concat(sources);\r\n            });\r\n            mLine.ssrcs = reorderedSsrcs;\r\n        });\r\n\r\n        return new RTCSessionDescription({\r\n            type: description.type,\r\n            sdp: transform.write(parsedSdp)\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Returns the transceiver associated with a given RTCRtpSender/RTCRtpReceiver.\r\n     *\r\n     * @param {string} mediaType - type of track associated with the transceiver 'audio' or 'video'.\r\n     * @param {JitsiLocalTrack} localTrack - local track to be used for lookup.\r\n     * @returns {RTCRtpTransceiver}\r\n     */\r\n    findTransceiver(mediaType, localTrack = null) {\r\n        const transceiver = localTrack?.track && localTrack.getOriginalStream()\r\n            ? this.pc.peerconnection.getTransceivers().find(t => t.sender?.track?.id === localTrack.getTrackId())\r\n            : this.pc.peerconnection.getTransceivers().find(t => t.receiver?.track?.kind === mediaType);\r\n\r\n        return transceiver;\r\n    }\r\n\r\n    /**\r\n     * Takes in a *unified plan* offer and inserts the appropriate\r\n     * parameters for adding simulcast receive support.\r\n     * @param {Object} desc - A session description object\r\n     * @param {String} desc.type - the type (offer/answer)\r\n     * @param {String} desc.sdp - the sdp content\r\n     *\r\n     * @return {Object} A session description (same format as above) object\r\n     * with its sdp field modified to advertise simulcast receive support\r\n     */\r\n    insertUnifiedPlanSimulcastReceive(desc) {\r\n        // a=simulcast line is not needed on browsers where we SDP munging is used for enabling on simulcast.\r\n        // Remove this check when the client switches to RID/MID based simulcast on all browsers.\r\n        if (browser.usesSdpMungingForSimulcast()) {\r\n            return desc;\r\n        }\r\n        const sdp = transform.parse(desc.sdp);\r\n        const idx = sdp.media.findIndex(mline => mline.type === MediaType.VIDEO);\r\n\r\n        if (sdp.media[idx].rids && (sdp.media[idx].simulcast_03 || sdp.media[idx].simulcast)) {\r\n            // Make sure we don't have the simulcast recv line on video descriptions other than\r\n            // the first video description.\r\n            sdp.media.forEach((mline, i) => {\r\n                if (mline.type === MediaType.VIDEO && i !== idx) {\r\n                    sdp.media[i].rids = undefined;\r\n                    sdp.media[i].simulcast = undefined;\r\n\r\n                    // eslint-disable-next-line camelcase\r\n                    sdp.media[i].simulcast_03 = undefined;\r\n                }\r\n            });\r\n\r\n            return new RTCSessionDescription({\r\n                type: desc.type,\r\n                sdp: transform.write(sdp)\r\n            });\r\n        }\r\n\r\n        // In order of highest to lowest spatial quality\r\n        sdp.media[idx].rids = [\r\n            {\r\n                id: SIM_LAYER_1_RID,\r\n                direction: 'recv'\r\n            },\r\n            {\r\n                id: SIM_LAYER_2_RID,\r\n                direction: 'recv'\r\n            },\r\n            {\r\n                id: SIM_LAYER_3_RID,\r\n                direction: 'recv'\r\n            }\r\n        ];\r\n\r\n        // Firefox 72 has stopped parsing the legacy rid= parameters in simulcast attributes.\r\n        // eslint-disable-next-line max-len\r\n        // https://www.fxsitecompat.dev/en-CA/docs/2019/pt-and-rid-in-webrtc-simulcast-attributes-are-no-longer-supported/\r\n        const simulcastLine = browser.isFirefox() && browser.isVersionGreaterThan(71)\r\n            ? `recv ${SIM_LAYER_RIDS.join(';')}`\r\n            : `recv rid=${SIM_LAYER_RIDS.join(';')}`;\r\n\r\n        // eslint-disable-next-line camelcase\r\n        sdp.media[idx].simulcast_03 = {\r\n            value: simulcastLine\r\n        };\r\n\r\n        return new RTCSessionDescription({\r\n            type: desc.type,\r\n            sdp: transform.write(sdp)\r\n        });\r\n    }\r\n\r\n    /**\r\n    * Adds {@link JitsiLocalTrack} to the WebRTC peerconnection for the first time.\r\n    * @param {JitsiLocalTrack} track - track to be added to the peerconnection.\r\n    * @param {boolean} isInitiator - boolean that indicates if the endpoint is offerer in a p2p connection.\r\n    * @returns {void}\r\n    */\r\n    addTrack(localTrack, isInitiator) {\r\n        const track = localTrack.getTrack();\r\n\r\n        if (isInitiator) {\r\n            const streams = [];\r\n\r\n            if (localTrack.getOriginalStream()) {\r\n                streams.push(localTrack.getOriginalStream());\r\n            }\r\n\r\n            // Use pc.addTransceiver() for the initiator case when local tracks are getting added\r\n            // to the peerconnection before a session-initiate is sent over to the peer.\r\n            const transceiverInit = {\r\n                direction: MediaDirection.SENDRECV,\r\n                streams,\r\n                sendEncodings: []\r\n            };\r\n\r\n            if (!browser.isFirefox()) {\r\n                transceiverInit.sendEncodings = this._getStreamEncodings(localTrack);\r\n            }\r\n            this.pc.peerconnection.addTransceiver(track, transceiverInit);\r\n        } else {\r\n            // Use pc.addTrack() for responder case so that we can re-use the m-lines that were created\r\n            // when setRemoteDescription was called. pc.addTrack() automatically  attaches to any existing\r\n            // unused \"recv-only\" transceiver.\r\n            this.pc.peerconnection.addTrack(track);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns the calculated active state of the simulcast encodings based on the frame height requested for the send\r\n     * stream. All the encodings that have a resolution lower than the frame height requested will be enabled.\r\n     *\r\n     * @param {JitsiLocalTrack} localVideoTrack The local video track.\r\n     * @param {number} newHeight The resolution requested for the video track.\r\n     * @returns {Array<boolean>}\r\n     */\r\n    calculateEncodingsActiveState(localVideoTrack, newHeight) {\r\n        const localTrack = localVideoTrack.getTrack();\r\n        const { height } = localTrack.getSettings();\r\n        const encodingsState = this.localStreamEncodingsConfig\r\n        .map(encoding => height / encoding.scaleResolutionDownBy)\r\n        .map((frameHeight, idx) => {\r\n            let active = localVideoTrack.getVideoType() === VideoType.CAMERA\r\n\r\n                // Keep the LD stream enabled even when the LD stream's resolution is higher than of the requested\r\n                // resolution. This can happen when camera is captured at resolutions higher than 720p but the\r\n                // requested resolution is 180. Since getParameters doesn't give us information about the resolutions\r\n                // of the simulcast encodings, we have to rely on our initial config for the simulcast streams.\r\n                ? newHeight > 0 && this.localStreamEncodingsConfig[idx]?.scaleResolutionDownBy === LD_SCALE_FACTOR\r\n                    ? true\r\n                    : frameHeight <= newHeight\r\n\r\n                // Keep all the encodings for desktop track active.\r\n                : true;\r\n\r\n            // Disable the lower spatial layers for screensharing in Unified plan when low fps screensharing is in\r\n            // progress. Sending all three streams often results in the browser suspending the high resolution in low\r\n            // b/w and cpu cases, especially on the low end machines. Suspending the low resolution streams ensures\r\n            // that the highest resolution stream is available always. Safari is an exception here since it does not\r\n            // send the desktop stream at all if only the high resolution stream is enabled.\r\n            if (localVideoTrack.getVideoType() === VideoType.DESKTOP\r\n                && this.pc._capScreenshareBitrate\r\n                && this.pc.usesUnifiedPlan()\r\n                && !browser.isWebKitBased()\r\n                && this.localStreamEncodingsConfig[idx].scaleResolutionDownBy !== HD_SCALE_FACTOR) {\r\n                active = false;\r\n            }\r\n\r\n            return active;\r\n        });\r\n\r\n        return encodingsState;\r\n    }\r\n\r\n    /**\r\n     * Returns the calculates max bitrates that need to be configured on the simulcast encodings based on the video\r\n     * type and other considerations associated with screenshare.\r\n     *\r\n     * @param {JitsiLocalTrack} localVideoTrack The local video track.\r\n     * @returns {Array<number>}\r\n     */\r\n    calculateEncodingsBitrates(localVideoTrack) {\r\n        const videoType = localVideoTrack.getVideoType();\r\n        const desktopShareBitrate = this.pc.options?.videoQuality?.desktopBitrate || DESKTOP_SHARE_RATE;\r\n        const lowFpsScreenshare = localVideoTrack.getVideoType() === VideoType.DESKTOP\r\n            && this.pc._capScreenshareBitrate\r\n            && !browser.isWebKitBased();\r\n        const encodingsBitrates = this.localStreamEncodingsConfig\r\n        .map(encoding => {\r\n            const bitrate = lowFpsScreenshare\r\n                ? desktopShareBitrate\r\n\r\n                // For high fps screenshare, 'maxBitrate' setting must be cleared on Chrome in plan-b, because\r\n                // if simulcast is enabled for screen and maxBitrates are set then Chrome will not send the\r\n                // desktop stream.\r\n                : videoType === VideoType.DESKTOP && browser.isChromiumBased() && !this.pc.usesUnifiedPlan()\r\n                    ? undefined\r\n                    : encoding.maxBitrate;\r\n\r\n            return bitrate;\r\n        });\r\n\r\n        return encodingsBitrates;\r\n    }\r\n\r\n    /**\r\n     * Replaces the existing track on a RTCRtpSender with the given track.\r\n     *\r\n     * @param {JitsiLocalTrack} oldTrack - existing track on the sender that needs to be removed.\r\n     * @param {JitsiLocalTrack} newTrack - new track that needs to be added to the sender.\r\n     * @returns {Promise<RTCRtpTransceiver>} - resolved with the associated transceiver when done, rejected otherwise.\r\n     */\r\n    replaceTrack(oldTrack, newTrack) {\r\n        const mediaType = newTrack?.getType() ?? oldTrack?.getType();\r\n        const localTracks = this.pc.getLocalTracks(mediaType);\r\n        const track = newTrack?.getTrack() ?? null;\r\n        const isNewLocalSource = FeatureFlags.isMultiStreamSendSupportEnabled()\r\n            && localTracks?.length\r\n            && !oldTrack\r\n            && newTrack\r\n            && !localTracks.find(t => t === newTrack);\r\n        let transceiver;\r\n\r\n        // If old track exists, replace the track on the corresponding sender.\r\n        if (oldTrack && !oldTrack.isMuted()) {\r\n            transceiver = this.pc.peerconnection.getTransceivers().find(t => t.sender.track === oldTrack.getTrack());\r\n\r\n        // Find the first recvonly transceiver when more than one track of the same media type is being added to the pc.\r\n        // As part of the track addition, a new m-line was added to the remote description with direction set to\r\n        // recvonly.\r\n        } else if (isNewLocalSource) {\r\n            transceiver = this.pc.peerconnection.getTransceivers().find(\r\n                t => t.receiver.track.kind === mediaType\r\n                && t.direction === MediaDirection.RECVONLY\r\n\r\n                // Re-use any existing recvonly transceiver (if available) for p2p case.\r\n                && ((this.pc.isP2P && t.currentDirection === MediaDirection.RECVONLY)\r\n                    || (t.currentDirection === MediaDirection.INACTIVE && !t.stopped)));\r\n\r\n        // For mute/unmute operations, find the transceiver based on the track index in the source name if present,\r\n        // otherwise it is assumed to be the first local track that was added to the peerconnection.\r\n        } else {\r\n            transceiver = this.pc.peerconnection.getTransceivers().find(t => t.receiver.track.kind === mediaType);\r\n            const sourceName = newTrack?.getSourceName() ?? oldTrack?.getSourceName();\r\n\r\n            if (sourceName) {\r\n                const trackIndex = getSourceIndexFromSourceName(sourceName);\r\n\r\n                if (this.pc.isP2P) {\r\n                    transceiver = this.pc.peerconnection.getTransceivers()\r\n                        .filter(t => t.receiver.track.kind === mediaType)[trackIndex];\r\n                } else if (oldTrack) {\r\n                    const transceiverMid = this.pc._localTrackTransceiverMids.get(oldTrack.rtcId);\r\n\r\n                    transceiver = this.pc.peerconnection.getTransceivers().find(t => t.mid === transceiverMid);\r\n                } else if (trackIndex) {\r\n                    transceiver = this.pc.peerconnection.getTransceivers()\r\n                            .filter(t => t.receiver.track.kind === mediaType\r\n                                && t.direction !== MediaDirection.RECVONLY)[trackIndex];\r\n                }\r\n            }\r\n        }\r\n        if (!transceiver) {\r\n            return Promise.reject(\r\n                new Error(`Replace track failed - no transceiver for old: ${oldTrack}, new: ${newTrack}`));\r\n        }\r\n        logger.debug(`${this.pc} Replacing ${oldTrack} with ${newTrack}`);\r\n\r\n        return transceiver.sender.replaceTrack(track)\r\n            .then(() => Promise.resolve(transceiver));\r\n    }\r\n\r\n    /**\r\n    * Enables/disables audio transmission on the peer connection. When\r\n    * disabled the audio transceiver direction will be set to 'inactive'\r\n    * which means that no data will be sent nor accepted, but\r\n    * the connection should be kept alive.\r\n    * @param {boolean} active - true to enable audio media transmission or\r\n    * false to disable.\r\n    * @returns {void}\r\n    */\r\n    setAudioTransferActive(active) {\r\n        this.setMediaTransferActive(MediaType.AUDIO, active);\r\n    }\r\n\r\n    /**\r\n     * Set the simulcast stream encoding properties on the RTCRtpSender.\r\n     * @param {JitsiLocalTrack} track - the current track in use for which\r\n     * the encodings are to be set.\r\n     * @returns {Promise<void>} - resolved when done.\r\n     */\r\n    setEncodings(track) {\r\n        const mediaType = track.getType();\r\n        const transceiver = this.findTransceiver(mediaType, track);\r\n        const parameters = transceiver?.sender?.getParameters();\r\n\r\n        // Resolve if the encodings are not available yet. This happens immediately after the track is added to the\r\n        // peerconnection on chrome in unified-plan. It is ok to ignore and not report the error here since the\r\n        // action that triggers 'addTrack' (like unmute) will also configure the encodings and set bitrates after that.\r\n        if (!parameters?.encodings?.length) {\r\n            return Promise.resolve();\r\n        }\r\n        parameters.encodings = this._getStreamEncodings(track);\r\n\r\n        return transceiver.sender.setParameters(parameters);\r\n    }\r\n\r\n    /**\r\n     * Enables/disables media transmission on the peerconnection by changing the direction\r\n     * on the transceiver for the specified media type.\r\n     * @param {String} mediaType - 'audio' or 'video'\r\n     * @param {boolean} active - true to enable media transmission or false\r\n     * to disable.\r\n     * @returns {void}\r\n     */\r\n    setMediaTransferActive(mediaType, active) {\r\n        const transceivers = this.pc.peerconnection.getTransceivers()\r\n            .filter(t => t.receiver && t.receiver.track && t.receiver.track.kind === mediaType);\r\n\r\n        logger.info(`${this.pc} ${active ? 'Enabling' : 'Suspending'} ${mediaType} media transfer.`);\r\n        transceivers.forEach(transceiver => {\r\n            if (active) {\r\n                const localTrackMids = Array.from(this.pc._localTrackTransceiverMids);\r\n\r\n                if (localTrackMids.find(mids => mids[1] === transceiver.mid)) {\r\n                    transceiver.direction = MediaDirection.SENDRECV;\r\n                } else {\r\n                    transceiver.direction = MediaDirection.RECVONLY;\r\n                }\r\n            } else {\r\n                transceiver.direction = MediaDirection.INACTIVE;\r\n            }\r\n        });\r\n    }\r\n\r\n    /**\r\n    * Enables/disables video media transmission on the peer connection. When\r\n    * disabled the SDP video media direction in the local SDP will be adjusted to\r\n    * 'inactive' which means that no data will be sent nor accepted, but\r\n    * the connection should be kept alive.\r\n    * @param {boolean} active - true to enable video media transmission or\r\n    * false to disable.\r\n    * @returns {void}\r\n    */\r\n    setVideoTransferActive(active) {\r\n        this.setMediaTransferActive(MediaType.VIDEO, active);\r\n    }\r\n\r\n    /**\r\n     * Ensures that the resolution of the stream encodings are consistent with the values\r\n     * that were configured on the RTCRtpSender when the source was added to the peerconnection.\r\n     * This should prevent us from overriding the default values if the browser returns\r\n     * erroneous values when RTCRtpSender.getParameters is used for getting the encodings info.\r\n     * @param {Object} parameters - the RTCRtpEncodingParameters obtained from the browser.\r\n     * @returns {void}\r\n     */\r\n    updateEncodingsResolution(parameters) {\r\n        if (!(browser.isWebKitBased() && parameters.encodings && Array.isArray(parameters.encodings))) {\r\n            return;\r\n        }\r\n        const allEqualEncodings\r\n            = encodings => encodings.every(encoding => typeof encoding.scaleResolutionDownBy !== 'undefined'\r\n                && encoding.scaleResolutionDownBy === encodings[0].scaleResolutionDownBy);\r\n\r\n        // Implement the workaround only when all the encodings report the same resolution.\r\n        if (allEqualEncodings(parameters.encodings)) {\r\n            parameters.encodings.forEach((encoding, idx) => {\r\n                encoding.scaleResolutionDownBy = this.localStreamEncodingsConfig[idx].scaleResolutionDownBy;\r\n            });\r\n        }\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport { Interop } from '@jitsi/sdp-interop';\r\nimport transform from 'sdp-transform';\r\n\r\nimport * as CodecMimeType from '../../service/RTC/CodecMimeType';\r\nimport { MediaDirection } from '../../service/RTC/MediaDirection';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport RTCEvents from '../../service/RTC/RTCEvents';\r\nimport * as SignalingEvents from '../../service/RTC/SignalingEvents';\r\nimport {\r\n    getSourceIndexFromSourceName,\r\n    getSourceNameForJitsiTrack\r\n} from '../../service/RTC/SignalingLayer';\r\nimport { VideoType } from '../../service/RTC/VideoType';\r\nimport { SS_DEFAULT_FRAME_RATE } from '../RTC/ScreenObtainer';\r\nimport browser from '../browser';\r\nimport FeatureFlags from '../flags/FeatureFlags';\r\nimport LocalSdpMunger from '../sdp/LocalSdpMunger';\r\nimport RtxModifier from '../sdp/RtxModifier';\r\nimport SDP from '../sdp/SDP';\r\nimport SDPUtil from '../sdp/SDPUtil';\r\nimport SdpConsistency from '../sdp/SdpConsistency';\r\nimport SdpSimulcast from '../sdp/SdpSimulcast';\r\nimport { SdpTransformWrap } from '../sdp/SdpTransformUtil';\r\nimport * as GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\r\n\r\nimport JitsiRemoteTrack from './JitsiRemoteTrack';\r\nimport RTC from './RTC';\r\nimport {\r\n    HD_BITRATE,\r\n    HD_SCALE_FACTOR,\r\n    SIM_LAYER_RIDS,\r\n    TPCUtils\r\n} from './TPCUtils';\r\n\r\n// FIXME SDP tools should end up in some kind of util module\r\n\r\nconst logger = getLogger(__filename);\r\nconst DEGRADATION_PREFERENCE_CAMERA = 'maintain-framerate';\r\nconst DEGRADATION_PREFERENCE_DESKTOP = 'maintain-resolution';\r\n\r\n/* eslint-disable max-params */\r\n\r\n/**\r\n * Creates new instance of 'TraceablePeerConnection'.\r\n *\r\n * @param {RTC} rtc the instance of <tt>RTC</tt> service\r\n * @param {number} id the peer connection id assigned by the parent RTC module.\r\n * @param {SignalingLayer} signalingLayer the signaling layer instance\r\n * @param {object} pcConfig The {@code RTCConfiguration} to use for the WebRTC peer connection.\r\n * @param {object} constraints WebRTC 'PeerConnection' constraints\r\n * @param {boolean} isP2P indicates whether or not the new instance will be used in a peer to peer connection.\r\n * @param {object} options <tt>TracablePeerConnection</tt> config options.\r\n * @param {boolean} options.disableSimulcast if set to 'true' will disable the simulcast.\r\n * @param {boolean} options.disableRtx if set to 'true' will disable the RTX.\r\n * @param {string} options.disabledCodec the mime type of the code that should not be negotiated on the peerconnection.\r\n * @param {string} options.preferredCodec the mime type of the codec that needs to be made the preferred codec for the\r\n * peerconnection.\r\n * @param {boolean} options.startSilent If set to 'true' no audio will be sent or received.\r\n * @param {boolean} options.usesUnifiedPlan Indicates if the  browser is running in unified plan mode.\r\n *\r\n * FIXME: initially the purpose of TraceablePeerConnection was to be able to\r\n * debug the peer connection. Since many other responsibilities have been added\r\n * it would make sense to extract a separate class from it and come up with\r\n * a more suitable name.\r\n *\r\n * @constructor\r\n */\r\nexport default function TraceablePeerConnection(\r\n        rtc,\r\n        id,\r\n        signalingLayer,\r\n        pcConfig,\r\n        constraints,\r\n        isP2P,\r\n        options) {\r\n\r\n    /**\r\n     * Indicates whether or not this peer connection instance is actively\r\n     * sending/receiving audio media. When set to <tt>false</tt> the SDP audio\r\n     * media direction will be adjusted to 'inactive' in order to suspend\r\n     * the transmission.\r\n     * @type {boolean}\r\n     * @private\r\n     */\r\n    this.audioTransferActive = !(options.startSilent === true);\r\n\r\n    /**\r\n     * The DTMF sender instance used to send DTMF tones.\r\n     *\r\n     * @type {RTCDTMFSender|undefined}\r\n     * @private\r\n     */\r\n    this._dtmfSender = undefined;\r\n\r\n    /**\r\n     * @typedef {Object} TouchToneRequest\r\n     * @property {string} tones - The DTMF tones string as defined by\r\n     * {@code RTCDTMFSender.insertDTMF}, 'tones' argument.\r\n     * @property {number} duration - The amount of time in milliseconds that\r\n     * each DTMF should last.\r\n     * @property {string} interToneGap - The length of time in miliseconds to\r\n     * wait between tones.\r\n     */\r\n    /**\r\n     * TouchToneRequests which are waiting to be played. This queue is filled\r\n     * if there are touch tones currently being played.\r\n     *\r\n     * @type {Array<TouchToneRequest>}\r\n     * @private\r\n     */\r\n    this._dtmfTonesQueue = [];\r\n\r\n    /**\r\n     * Indicates whether or not this peer connection instance is actively\r\n     * sending/receiving video media. When set to <tt>false</tt> the SDP video\r\n     * media direction will be adjusted to 'inactive' in order to suspend\r\n     * the transmission.\r\n     * @type {boolean}\r\n     * @private\r\n     */\r\n    this.videoTransferActive = true;\r\n\r\n    /**\r\n     * The parent instance of RTC service which created this\r\n     * <tt>TracablePeerConnection</tt>.\r\n     * @type {RTC}\r\n     */\r\n    this.rtc = rtc;\r\n\r\n    /**\r\n     * The peer connection identifier assigned by the RTC module.\r\n     * @type {number}\r\n     */\r\n    this.id = id;\r\n\r\n    /**\r\n     * Indicates whether or not this instance is used in a peer to peer\r\n     * connection.\r\n     * @type {boolean}\r\n     */\r\n    this.isP2P = isP2P;\r\n\r\n    /**\r\n     * The map holds remote tracks associated with this peer connection. It maps user's JID to media type and a set of\r\n     * remote tracks.\r\n     * @type {Map<string, Map<MediaType, Set<JitsiRemoteTrack>>>}\r\n     */\r\n    this.remoteTracks = new Map();\r\n\r\n    /**\r\n     * A map which stores local tracks mapped by {@link JitsiLocalTrack.rtcId}\r\n     * @type {Map<number, JitsiLocalTrack>}\r\n     */\r\n    this.localTracks = new Map();\r\n\r\n    /**\r\n     * Keeps tracks of the WebRTC <tt>MediaStream</tt>s that have been added to\r\n     * the underlying WebRTC PeerConnection.\r\n     * @type {Array}\r\n     * @private\r\n     */\r\n    this._addedStreams = [];\r\n\r\n    /**\r\n     * @typedef {Object} TPCGroupInfo\r\n     * @property {string} semantics the SSRC groups semantics\r\n     * @property {Array<number>} ssrcs group's SSRCs in order where the first\r\n     * one is group's primary SSRC, the second one is secondary (RTX) and so\r\n     * on...\r\n     */\r\n    /**\r\n     * @typedef {Object} TPCSSRCInfo\r\n     * @property {Array<number>} ssrcs an array which holds all track's SSRCs\r\n     * @property {Array<TPCGroupInfo>} groups an array stores all track's SSRC\r\n     * groups\r\n     */\r\n    /**\r\n     * Holds the info about local track's SSRCs mapped per their\r\n     * {@link JitsiLocalTrack.rtcId}\r\n     * @type {Map<number, TPCSSRCInfo>}\r\n     */\r\n    this.localSSRCs = new Map();\r\n\r\n    /**\r\n     * The set of remote SSRCs seen so far.\r\n     * Distinguishes new SSRCs from those that have been remapped.\r\n     */\r\n    this.remoteSSRCs = new Set();\r\n\r\n    /**\r\n     * The local ICE username fragment for this session.\r\n     */\r\n    this.localUfrag = null;\r\n\r\n    /**\r\n     * The remote ICE username fragment for this session.\r\n     */\r\n    this.remoteUfrag = null;\r\n\r\n    /**\r\n     * The DTLS transport object for the PeerConnection.\r\n     * Note: this assume only one shared transport exists because we bundled\r\n     *       all streams on the same underlying transport.\r\n     */\r\n    this._dtlsTransport = null;\r\n\r\n    /**\r\n     * The signaling layer which operates this peer connection.\r\n     * @type {SignalingLayer}\r\n     */\r\n    this.signalingLayer = signalingLayer;\r\n\r\n    // SignalingLayer listeners\r\n    this._peerVideoTypeChanged = this._peerVideoTypeChanged.bind(this);\r\n    this.signalingLayer.on(SignalingEvents.PEER_VIDEO_TYPE_CHANGED, this._peerVideoTypeChanged);\r\n\r\n    this._peerMutedChanged = this._peerMutedChanged.bind(this);\r\n    this.signalingLayer.on(SignalingEvents.PEER_MUTED_CHANGED, this._peerMutedChanged);\r\n    this.options = options;\r\n\r\n    // Setup SignalingLayer listeners for source-name based events.\r\n    this.signalingLayer.on(SignalingEvents.SOURCE_MUTED_CHANGED,\r\n        (sourceName, isMuted) => this._sourceMutedChanged(sourceName, isMuted));\r\n    this.signalingLayer.on(SignalingEvents.SOURCE_VIDEO_TYPE_CHANGED,\r\n        (sourceName, videoType) => this._sourceVideoTypeChanged(sourceName, videoType));\r\n\r\n    // Make sure constraints is properly formatted in order to provide information about whether or not this\r\n    // connection is P2P to rtcstats.\r\n    const safeConstraints = constraints || {};\r\n\r\n    safeConstraints.optional = safeConstraints.optional || [];\r\n\r\n    // The `optional` parameter needs to be of type array, otherwise chrome will throw an error.\r\n    // Firefox and Safari just ignore it.\r\n    if (Array.isArray(safeConstraints.optional)) {\r\n        safeConstraints.optional.push({ rtcStatsSFUP2P: this.isP2P });\r\n    } else {\r\n        logger.warn('Optional param is not an array, rtcstats p2p data is omitted.');\r\n    }\r\n\r\n    this.peerconnection = new RTCPeerConnection(pcConfig, safeConstraints);\r\n\r\n    this.tpcUtils = new TPCUtils(this);\r\n    this.updateLog = [];\r\n    this.stats = {};\r\n    this.statsinterval = null;\r\n\r\n    /**\r\n     * Flag used to indicate if simulcast is turned off and a cap of 500 Kbps is applied on screensharing.\r\n     */\r\n    this._capScreenshareBitrate = this.options.capScreenshareBitrate;\r\n\r\n    /**\r\n    * Flag used to indicate if the browser is running in unified  plan mode.\r\n    */\r\n    this._usesUnifiedPlan = options.usesUnifiedPlan;\r\n\r\n    /**\r\n     * Flag used to indicate if RTCRtpTransceiver#setCodecPreferences is to be used instead of SDP\r\n     * munging for codec selection.\r\n     */\r\n    this._usesTransceiverCodecPreferences = browser.supportsCodecPreferences() && this._usesUnifiedPlan;\r\n    this._usesTransceiverCodecPreferences\r\n        && logger.info('Using RTCRtpTransceiver#setCodecPreferences for codec selection');\r\n\r\n    // We currently need these flags only for FF and that's why we are updating them only for unified plan.\r\n    if (this._usesUnifiedPlan) {\r\n        /**\r\n         * Indicates whether an audio track has ever been added to the peer connection.\r\n         */\r\n        this._hasHadAudioTrack = false;\r\n\r\n        /**\r\n         * Indicates whether a video track has ever been added to the peer connection.\r\n         */\r\n        this._hasHadVideoTrack = false;\r\n    }\r\n\r\n    /**\r\n     * @type {number} The max number of stats to keep in this.stats. Limit to\r\n     * 300 values, i.e. 5 minutes; set to 0 to disable\r\n     */\r\n    this.maxstats = options.maxstats;\r\n\r\n    this.interop = new Interop();\r\n\r\n    if (this._usesUnifiedPlan) {\r\n        this.simulcast = new SdpSimulcast({ numOfLayers: SIM_LAYER_RIDS.length });\r\n    } else {\r\n        const Simulcast = require('@jitsi/sdp-simulcast');\r\n\r\n        this.simulcast = new Simulcast(\r\n            {\r\n                numOfLayers: SIM_LAYER_RIDS.length,\r\n                explodeRemoteSimulcast: false,\r\n                usesUnifiedPlan: false\r\n            });\r\n    }\r\n\r\n    this.sdpConsistency = new SdpConsistency(this.toString());\r\n\r\n    /**\r\n     * Munges local SDP provided to the Jingle Session in order to prevent from\r\n     * sending SSRC updates on attach/detach and mute/unmute (for video).\r\n     * @type {LocalSdpMunger}\r\n     */\r\n    this.localSdpMunger = new LocalSdpMunger(this, this.rtc.getLocalEndpointId());\r\n\r\n    /**\r\n     * TracablePeerConnection uses RTC's eventEmitter\r\n     * @type {EventEmitter}\r\n     */\r\n    this.eventEmitter = rtc.eventEmitter;\r\n    this.rtxModifier = new RtxModifier();\r\n\r\n    /**\r\n     * The height constraint applied on the video sender. The default value is 2160 (4K) when layer suspension is\r\n     * explicitly disabled.\r\n     */\r\n    this._senderVideoMaxHeight = 2160;\r\n\r\n    /**\r\n     * The height constraints to be applied on the sender per local video source (source name as the key).\r\n     * @type {Map<string, number>}\r\n     */\r\n    this._senderMaxHeights = new Map();\r\n\r\n    /**\r\n     * Holds the RTCRtpTransceiver mids that the local tracks are attached to, mapped per their\r\n     * {@link JitsiLocalTrack.rtcId}.\r\n     * @type {Map<string, string>}\r\n     */\r\n    this._localTrackTransceiverMids = new Map();\r\n\r\n    // override as desired\r\n    this.trace = (what, info) => {\r\n        logger.debug(what, info);\r\n\r\n        this.updateLog.push({\r\n            time: new Date(),\r\n            type: what,\r\n            value: info || ''\r\n        });\r\n    };\r\n    this.onicecandidate = null;\r\n    this.peerconnection.onicecandidate = event => {\r\n        this.trace(\r\n            'onicecandidate',\r\n            JSON.stringify(event.candidate, null, ' '));\r\n\r\n        if (this.onicecandidate !== null) {\r\n            this.onicecandidate(event);\r\n        }\r\n    };\r\n\r\n    // Use track events when browser is running in unified plan mode and stream events in plan-b mode.\r\n    if (this._usesUnifiedPlan) {\r\n        this.onTrack = evt => {\r\n            const stream = evt.streams[0];\r\n\r\n            this._remoteTrackAdded(stream, evt.track, evt.transceiver);\r\n            stream.addEventListener('removetrack', e => {\r\n                this._remoteTrackRemoved(stream, e.track);\r\n            });\r\n        };\r\n        this.peerconnection.addEventListener('track', this.onTrack);\r\n    } else {\r\n        this.peerconnection.onaddstream = event => this._remoteStreamAdded(event.stream);\r\n        this.peerconnection.onremovestream = event => this._remoteStreamRemoved(event.stream);\r\n    }\r\n    this.onsignalingstatechange = null;\r\n    this.peerconnection.onsignalingstatechange = event => {\r\n        this.trace('onsignalingstatechange', this.signalingState);\r\n        if (this.onsignalingstatechange !== null) {\r\n            this.onsignalingstatechange(event);\r\n        }\r\n    };\r\n    this.oniceconnectionstatechange = null;\r\n    this.peerconnection.oniceconnectionstatechange = event => {\r\n        this.trace('oniceconnectionstatechange', this.iceConnectionState);\r\n        if (this.oniceconnectionstatechange !== null) {\r\n            this.oniceconnectionstatechange(event);\r\n        }\r\n    };\r\n    this.onnegotiationneeded = null;\r\n    this.peerconnection.onnegotiationneeded = event => {\r\n        this.trace('onnegotiationneeded');\r\n        if (this.onnegotiationneeded !== null) {\r\n            this.onnegotiationneeded(event);\r\n        }\r\n    };\r\n    this.onconnectionstatechange = null;\r\n    this.peerconnection.onconnectionstatechange = event => {\r\n        this.trace('onconnectionstatechange', this.connectionState);\r\n        if (this.onconnectionstatechange !== null) {\r\n            this.onconnectionstatechange(event);\r\n        }\r\n    };\r\n    this.ondatachannel = null;\r\n    this.peerconnection.ondatachannel = event => {\r\n        this.trace('ondatachannel');\r\n        if (this.ondatachannel !== null) {\r\n            this.ondatachannel(event);\r\n        }\r\n    };\r\n\r\n    if (this.maxstats) {\r\n        this.statsinterval = window.setInterval(() => {\r\n            this.getStats().then(stats => {\r\n                if (typeof stats?.result === 'function') {\r\n                    const results = stats.result();\r\n\r\n                    for (let i = 0; i < results.length; ++i) {\r\n                        const res = results[i];\r\n\r\n                        res.names().forEach(name => {\r\n                            this._processStat(res, name, res.stat(name));\r\n                        });\r\n                    }\r\n                } else {\r\n                    stats.forEach(r => this._processStat(r, '', r));\r\n                }\r\n            });\r\n        }, 1000);\r\n    }\r\n\r\n    logger.info(`Create new ${this}`);\r\n}\r\n\r\n/* eslint-enable max-params */\r\n\r\n/**\r\n * Process stat and adds it to the array of stats we store.\r\n * @param report the current stats report.\r\n * @param name the name of the report, if available\r\n * @param statValue the value to add.\r\n * @private\r\n */\r\nTraceablePeerConnection.prototype._processStat\r\n    = function(report, name, statValue) {\r\n        const id = `${report.id}-${name}`;\r\n        let s = this.stats[id];\r\n        const now = new Date();\r\n\r\n        if (!s) {\r\n            this.stats[id] = s = {\r\n                startTime: now,\r\n                endTime: now,\r\n                values: [],\r\n                times: []\r\n            };\r\n        }\r\n        s.values.push(statValue);\r\n        s.times.push(now.getTime());\r\n        if (s.values.length > this.maxstats) {\r\n            s.values.shift();\r\n            s.times.shift();\r\n        }\r\n        s.endTime = now;\r\n    };\r\n\r\n/**\r\n * Returns a string representation of a SessionDescription object.\r\n */\r\nconst dumpSDP = function(description) {\r\n    if (typeof description === 'undefined' || description === null) {\r\n        return '';\r\n    }\r\n\r\n    return `type: ${description.type}\\r\\n${description.sdp}`;\r\n};\r\n\r\n\r\n/**\r\n * Forwards the {@link peerconnection.iceConnectionState} state except that it\r\n * will convert \"completed\" into \"connected\" where both mean that the ICE has\r\n * succeeded and is up and running. We never see \"completed\" state for\r\n * the JVB connection, but it started appearing for the P2P one. This method\r\n * allows to adapt old logic to this new situation.\r\n * @return {string}\r\n */\r\nTraceablePeerConnection.prototype.getConnectionState = function() {\r\n    const state = this.peerconnection.iceConnectionState;\r\n\r\n    if (state === 'completed') {\r\n        return 'connected';\r\n    }\r\n\r\n    return state;\r\n};\r\n\r\n/**\r\n * Obtains the media direction for given {@link MediaType}. The method takes\r\n * into account whether or not there are any local tracks for media and\r\n * the {@link audioTransferActive} and {@link videoTransferActive} flags.\r\n * @param {MediaType} mediaType\r\n * @param {boolean} isAddOperation whether the direction is to be calculated after a source-add action.\r\n * @return {string} one of the SDP direction constants ('sendrecv, 'recvonly'\r\n * etc.) which should be used when setting local description on the peer\r\n * connection.\r\n * @private\r\n */\r\nTraceablePeerConnection.prototype.getDesiredMediaDirection = function(mediaType, isAddOperation = false) {\r\n    const hasLocalSource = this.hasAnyTracksOfType(mediaType);\r\n\r\n    if (this._usesUnifiedPlan) {\r\n        return isAddOperation\r\n            ? hasLocalSource ? MediaDirection.SENDRECV : MediaDirection.SENDONLY\r\n            : hasLocalSource ? MediaDirection.RECVONLY : MediaDirection.INACTIVE;\r\n    }\r\n\r\n    const mediaTransferActive = mediaType === MediaType.AUDIO ? this.audioTransferActive : this.videoTransferActive;\r\n\r\n    if (mediaTransferActive) {\r\n        return hasLocalSource ? MediaDirection.SENDRECV : MediaDirection.RECVONLY;\r\n    }\r\n\r\n    return MediaDirection.INACTIVE;\r\n};\r\n\r\n/**\r\n * Returns the MID of the m-line associated with the local desktop track (if it exists).\r\n *\r\n * @returns {Number|null}\r\n */\r\nTraceablePeerConnection.prototype._getDesktopTrackMid = function() {\r\n    const desktopTrack = this.getLocalVideoTracks().find(track => track.getVideoType() === VideoType.DESKTOP);\r\n\r\n    if (desktopTrack) {\r\n        return Number(this._localTrackTransceiverMids.get(desktopTrack.rtcId));\r\n    }\r\n\r\n    return null;\r\n};\r\n\r\n/**\r\n * Returns the list of RTCRtpReceivers created for the source of the given media type associated with\r\n * the set of remote endpoints specified.\r\n * @param {Array<string>} endpoints list of the endpoints\r\n * @param {string} mediaType 'audio' or 'video'\r\n * @returns {Array<RTCRtpReceiver>} list of receivers created by the peerconnection.\r\n */\r\nTraceablePeerConnection.prototype._getReceiversByEndpointIds = function(endpoints, mediaType) {\r\n    let remoteTracks = [];\r\n    let receivers = [];\r\n\r\n    for (const endpoint of endpoints) {\r\n        remoteTracks = remoteTracks.concat(this.getRemoteTracks(endpoint, mediaType));\r\n    }\r\n\r\n    // Get the ids of the MediaStreamTracks associated with each of these remote tracks.\r\n    const remoteTrackIds = remoteTracks.map(remote => remote.track?.id);\r\n\r\n    receivers = this.peerconnection.getReceivers()\r\n        .filter(receiver => receiver.track\r\n            && receiver.track.kind === mediaType\r\n            && remoteTrackIds.find(trackId => trackId === receiver.track.id));\r\n\r\n    return receivers;\r\n};\r\n\r\n/**\r\n * Tells whether or not this TPC instance is using Simulcast.\r\n * @return {boolean} <tt>true</tt> if simulcast is enabled and active or\r\n * <tt>false</tt> if it's turned off.\r\n */\r\nTraceablePeerConnection.prototype.isSimulcastOn = function() {\r\n    return !this.options.disableSimulcast;\r\n};\r\n\r\n/**\r\n * Handles {@link SignalingEvents.PEER_VIDEO_TYPE_CHANGED}\r\n * @param {string} endpointId the video owner's ID (MUC nickname)\r\n * @param {VideoType} videoType the new value\r\n * @private\r\n */\r\nTraceablePeerConnection.prototype._peerVideoTypeChanged = function(endpointId, videoType) {\r\n    // Check if endpointId has a value to avoid action on random track\r\n    if (!endpointId) {\r\n        logger.error(`${this} No endpointID on peerVideoTypeChanged`);\r\n\r\n        return;\r\n    }\r\n    const videoTrack = this.getRemoteTracks(endpointId, MediaType.VIDEO);\r\n\r\n    if (videoTrack.length) {\r\n        // NOTE 1 track per media type is assumed\r\n        videoTrack[0]._setVideoType(videoType);\r\n    }\r\n};\r\n\r\n/**\r\n * Handles remote track mute / unmute events.\r\n * @param {string} endpointId the track owner's identifier (MUC nickname)\r\n * @param {MediaType} mediaType \"audio\" or \"video\"\r\n * @param {boolean} isMuted the new mute state\r\n * @private\r\n */\r\nTraceablePeerConnection.prototype._peerMutedChanged = function(endpointId, mediaType, isMuted) {\r\n    // Check if endpointId is a value to avoid doing action on all remote tracks\r\n    if (!endpointId) {\r\n        logger.error(`${this} On peerMuteChanged - no endpoint ID`);\r\n\r\n        return;\r\n    }\r\n    const track = this.getRemoteTracks(endpointId, mediaType);\r\n\r\n    if (track.length) {\r\n        // NOTE 1 track per media type is assumed\r\n        track[0].setMute(isMuted);\r\n    }\r\n};\r\n\r\n/**\r\n * Handles remote source mute and unmute changed events.\r\n *\r\n * @param {string} sourceName - The name of the remote source.\r\n * @param {boolean} isMuted - The new mute state.\r\n */\r\nTraceablePeerConnection.prototype._sourceMutedChanged = function(sourceName, isMuted) {\r\n    const track = this.getRemoteTracks().find(t => t.getSourceName() === sourceName);\r\n\r\n    if (!track) {\r\n        return;\r\n    }\r\n\r\n    track.setMute(isMuted);\r\n};\r\n\r\n/**\r\n * Handles remote source videoType changed events.\r\n *\r\n * @param {string} sourceName - The name of the remote source.\r\n * @param {boolean} isMuted - The new value.\r\n */\r\nTraceablePeerConnection.prototype._sourceVideoTypeChanged = function(sourceName, videoType) {\r\n    const track = this.getRemoteTracks().find(t => t.getSourceName() === sourceName);\r\n\r\n    if (!track) {\r\n        return;\r\n    }\r\n\r\n    track._setVideoType(videoType);\r\n};\r\n\r\n/**\r\n * Obtains audio levels of the remote audio tracks by getting the source information on the RTCRtpReceivers.\r\n * The information relevant to the ssrc is updated each time a RTP packet constaining the ssrc is received.\r\n * @param {Array<string>} speakerList list of endpoint ids for which audio levels are to be gathered.\r\n * @returns {Object} containing ssrc and audio level information as a key-value pair.\r\n */\r\nTraceablePeerConnection.prototype.getAudioLevels = function(speakerList = []) {\r\n    const audioLevels = {};\r\n    const audioReceivers = speakerList.length\r\n        ? this._getReceiversByEndpointIds(speakerList, MediaType.AUDIO)\r\n        : this.peerconnection.getReceivers()\r\n            .filter(receiver => receiver.track && receiver.track.kind === MediaType.AUDIO && receiver.track.enabled);\r\n\r\n    audioReceivers.forEach(remote => {\r\n        const ssrc = remote.getSynchronizationSources();\r\n\r\n        if (ssrc && ssrc.length) {\r\n            // As per spec, this audiolevel is a value between 0..1 (linear), where 1.0\r\n            // represents 0 dBov, 0 represents silence, and 0.5 represents approximately\r\n            // 6 dBSPL change in the sound pressure level from 0 dBov.\r\n            // https://www.w3.org/TR/webrtc/#dom-rtcrtpcontributingsource-audiolevel\r\n            audioLevels[ssrc[0].source] = ssrc[0].audioLevel;\r\n        }\r\n    });\r\n\r\n    return audioLevels;\r\n};\r\n\r\n/**\r\n * Obtains local tracks for given {@link MediaType}. If the <tt>mediaType</tt>\r\n * argument is omitted the list of all local tracks will be returned.\r\n * @param {MediaType} [mediaType]\r\n * @return {Array<JitsiLocalTrack>}\r\n */\r\nTraceablePeerConnection.prototype.getLocalTracks = function(mediaType) {\r\n    let tracks = Array.from(this.localTracks.values());\r\n\r\n    if (mediaType !== undefined) {\r\n        tracks = tracks.filter(track => track.getType() === mediaType);\r\n    }\r\n\r\n    return tracks;\r\n};\r\n\r\n/**\r\n * Retrieves the local video tracks.\r\n *\r\n * @returns {Array<JitsiLocalTrack>} - local video tracks.\r\n */\r\nTraceablePeerConnection.prototype.getLocalVideoTracks = function() {\r\n    return this.getLocalTracks(MediaType.VIDEO);\r\n};\r\n\r\n/**\r\n * Checks whether or not this {@link TraceablePeerConnection} instance contains any local tracks for given\r\n * <tt>mediaType</tt>.\r\n *\r\n * @param {MediaType} mediaType - The media type.\r\n * @return {boolean}\r\n */\r\nTraceablePeerConnection.prototype.hasAnyTracksOfType = function(mediaType) {\r\n    if (!mediaType) {\r\n        throw new Error('\"mediaType\" is required');\r\n    }\r\n\r\n    return this.getLocalTracks(mediaType).length > 0;\r\n};\r\n\r\n/**\r\n * Obtains all remote tracks currently known to this PeerConnection instance.\r\n *\r\n * @param {string} [endpointId] - The track owner's identifier (MUC nickname)\r\n * @param {MediaType} [mediaType] - The remote tracks will be filtered by their media type if this argument is\r\n * specified.\r\n * @return {Array<JitsiRemoteTrack>}\r\n */\r\nTraceablePeerConnection.prototype.getRemoteTracks = function(endpointId, mediaType) {\r\n    let remoteTracks = [];\r\n    const endpoints = endpointId ? [ endpointId ] : this.remoteTracks.keys();\r\n\r\n    for (const endpoint of endpoints) {\r\n        const endpointTracksByMediaType = this.remoteTracks.get(endpoint);\r\n\r\n        if (endpointTracksByMediaType) {\r\n            for (const trackMediaType of endpointTracksByMediaType.keys()) {\r\n                // per media type filtering\r\n                if (!mediaType || mediaType === trackMediaType) {\r\n                    remoteTracks = remoteTracks.concat(Array.from(endpointTracksByMediaType.get(trackMediaType)));\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    return remoteTracks;\r\n};\r\n\r\n/**\r\n * Parses the remote description and returns the sdp lines of the sources associated with a remote participant.\r\n *\r\n * @param {string} id Endpoint id of the remote participant.\r\n * @returns {Array<string>} The sdp lines that have the ssrc information.\r\n */\r\nTraceablePeerConnection.prototype.getRemoteSourceInfoByParticipant = function(id) {\r\n    const removeSsrcInfo = [];\r\n    const remoteTracks = this.getRemoteTracks(id);\r\n\r\n    if (!remoteTracks?.length) {\r\n        return removeSsrcInfo;\r\n    }\r\n    const primarySsrcs = remoteTracks.map(track => track.getSSRC());\r\n    const sdp = new SDP(this.remoteDescription.sdp);\r\n\r\n    primarySsrcs.forEach((ssrc, idx) => {\r\n        for (const media of sdp.media) {\r\n            let lines = '';\r\n            let ssrcLines = SDPUtil.findLines(media, `a=ssrc:${ssrc}`);\r\n\r\n            if (ssrcLines.length) {\r\n                if (!removeSsrcInfo[idx]) {\r\n                    removeSsrcInfo[idx] = '';\r\n                }\r\n\r\n                // Check if there are any FID groups present for the primary ssrc.\r\n                const fidLines = SDPUtil.findLines(media, `a=ssrc-group:FID ${ssrc}`);\r\n\r\n                if (fidLines.length) {\r\n                    const secondarySsrc = fidLines[0].split(' ')[2];\r\n\r\n                    lines += `${fidLines[0]}\\r\\n`;\r\n                    ssrcLines = ssrcLines.concat(SDPUtil.findLines(media, `a=ssrc:${secondarySsrc}`));\r\n                }\r\n                removeSsrcInfo[idx] += `${ssrcLines.join('\\r\\n')}\\r\\n`;\r\n                removeSsrcInfo[idx] += lines;\r\n            }\r\n        }\r\n    });\r\n\r\n    return removeSsrcInfo;\r\n};\r\n\r\n/**\r\n * Returns the target bitrates configured for the local video source.\r\n *\r\n * @returns {Object}\r\n */\r\nTraceablePeerConnection.prototype.getTargetVideoBitrates = function() {\r\n    const currentCodec = this.getConfiguredVideoCodec();\r\n\r\n    return this.tpcUtils.videoBitrates[currentCodec.toUpperCase()] || this.tpcUtils.videoBitrates;\r\n};\r\n\r\n/**\r\n * Tries to find {@link JitsiTrack} for given SSRC number. It will search both\r\n * local and remote tracks bound to this instance.\r\n * @param {number} ssrc\r\n * @return {JitsiTrack|null}\r\n */\r\nTraceablePeerConnection.prototype.getTrackBySSRC = function(ssrc) {\r\n    if (typeof ssrc !== 'number') {\r\n        throw new Error(`SSRC ${ssrc} is not a number`);\r\n    }\r\n    for (const localTrack of this.localTracks.values()) {\r\n        if (this.getLocalSSRC(localTrack) === ssrc) {\r\n            return localTrack;\r\n        }\r\n    }\r\n    for (const remoteTrack of this.getRemoteTracks()) {\r\n        if (remoteTrack.getSSRC() === ssrc) {\r\n            return remoteTrack;\r\n        }\r\n    }\r\n\r\n    return null;\r\n};\r\n\r\n/**\r\n * Tries to find SSRC number for given {@link JitsiTrack} id. It will search\r\n * both local and remote tracks bound to this instance.\r\n * @param {string} id\r\n * @return {number|null}\r\n */\r\nTraceablePeerConnection.prototype.getSsrcByTrackId = function(id) {\r\n\r\n    const findTrackById = track => track.getTrack().id === id;\r\n    const localTrack = this.getLocalTracks().find(findTrackById);\r\n\r\n    if (localTrack) {\r\n        return this.getLocalSSRC(localTrack);\r\n    }\r\n\r\n    const remoteTrack = this.getRemoteTracks().find(findTrackById);\r\n\r\n    if (remoteTrack) {\r\n        return remoteTrack.getSSRC();\r\n    }\r\n\r\n    return null;\r\n};\r\n\r\n/**\r\n * Called when new remote MediaStream is added to the PeerConnection.\r\n * @param {MediaStream} stream the WebRTC MediaStream for remote participant\r\n */\r\nTraceablePeerConnection.prototype._remoteStreamAdded = function(stream) {\r\n    const streamId = stream.id;\r\n\r\n    if (!RTC.isUserStreamById(streamId)) {\r\n        logger.info(`${this} ignored remote 'stream added' event for non-user stream[id=${streamId}]`);\r\n\r\n        return;\r\n    }\r\n\r\n    // Bind 'addtrack'/'removetrack' event handlers\r\n    if (browser.isChromiumBased()) {\r\n        stream.onaddtrack = event => {\r\n            this._remoteTrackAdded(stream, event.track);\r\n        };\r\n        stream.onremovetrack = event => {\r\n            this._remoteTrackRemoved(stream, event.track);\r\n        };\r\n    }\r\n\r\n    // Call remoteTrackAdded for each track in the stream\r\n    const streamAudioTracks = stream.getAudioTracks();\r\n\r\n    for (const audioTrack of streamAudioTracks) {\r\n        this._remoteTrackAdded(stream, audioTrack);\r\n    }\r\n    const streamVideoTracks = stream.getVideoTracks();\r\n\r\n    for (const videoTrack of streamVideoTracks) {\r\n        this._remoteTrackAdded(stream, videoTrack);\r\n    }\r\n};\r\n\r\n\r\n/**\r\n * Called on \"track added\" and \"stream added\" PeerConnection events (because we\r\n * handle streams on per track basis). Finds the owner and the SSRC for\r\n * the track and passes that to ChatRoom for further processing.\r\n * @param {MediaStream} stream the WebRTC MediaStream instance which is\r\n * the parent of the track\r\n * @param {MediaStreamTrack} track the WebRTC MediaStreamTrack added for remote\r\n * participant.\r\n * @param {RTCRtpTransceiver} transceiver the WebRTC transceiver that is created\r\n * for the remote participant in unified plan.\r\n */\r\nTraceablePeerConnection.prototype._remoteTrackAdded = function(stream, track, transceiver = null) {\r\n    const streamId = stream.id;\r\n    const mediaType = track.kind;\r\n\r\n    if (!this.isP2P && !RTC.isUserStreamById(streamId)) {\r\n        logger.info(`${this} ignored remote 'stream added' event for non-user stream[id=${streamId}]`);\r\n\r\n        return;\r\n    }\r\n    logger.info(`${this} adding remote track for stream[id=${streamId},type=${mediaType}]`);\r\n\r\n    // look up an associated JID for a stream id\r\n    if (!mediaType) {\r\n        GlobalOnErrorHandler.callErrorHandler(\r\n            new Error(\r\n                `MediaType undefined for remote track, stream id: ${streamId}`\r\n            ));\r\n\r\n        // Abort\r\n        return;\r\n    }\r\n\r\n    const remoteSDP = this._usesUnifiedPlan\r\n        ? new SDP(this.peerconnection.remoteDescription.sdp)\r\n        : new SDP(this.remoteDescription.sdp);\r\n    let mediaLines;\r\n\r\n    // In unified plan mode, find the matching mline using 'mid' if its availble, otherwise use the\r\n    // 'msid' attribute of the stream.\r\n    if (this._usesUnifiedPlan) {\r\n        if (transceiver && transceiver.mid) {\r\n            const mid = transceiver.mid;\r\n\r\n            mediaLines = remoteSDP.media.filter(mls => SDPUtil.findLine(mls, `a=mid:${mid}`));\r\n        } else {\r\n            mediaLines = remoteSDP.media.filter(mls => {\r\n                const msid = SDPUtil.findLine(mls, 'a=msid:');\r\n\r\n                return typeof msid === 'string' && streamId === msid.substring(7).split(' ')[0];\r\n            });\r\n        }\r\n    } else {\r\n        mediaLines = remoteSDP.media.filter(mls => mls.startsWith(`m=${mediaType}`));\r\n    }\r\n\r\n    if (!mediaLines.length) {\r\n        GlobalOnErrorHandler.callErrorHandler(\r\n            new Error(`No media lines found in remote SDP for remote stream[id=${streamId},type=${mediaType}]`));\r\n\r\n        // Abort\r\n        return;\r\n    }\r\n\r\n    let ssrcLines = SDPUtil.findLines(mediaLines[0], 'a=ssrc:');\r\n\r\n    ssrcLines\r\n        = ssrcLines.filter(line => line.indexOf(`msid:${streamId}`) !== -1);\r\n    if (!ssrcLines.length) {\r\n        GlobalOnErrorHandler.callErrorHandler(\r\n            new Error(`No SSRC lines found in remote SDP for remote stream[msid=${streamId},type=${mediaType}]`));\r\n\r\n        // Abort\r\n        return;\r\n    }\r\n\r\n    // FIXME the length of ssrcLines[0] not verified, but it will fail\r\n    // with global error handler anyway\r\n    const ssrcStr = ssrcLines[0].substring(7).split(' ')[0];\r\n    const trackSsrc = Number(ssrcStr);\r\n    const ownerEndpointId = this.signalingLayer.getSSRCOwner(trackSsrc);\r\n\r\n    if (isNaN(trackSsrc) || trackSsrc < 0) {\r\n        GlobalOnErrorHandler.callErrorHandler(\r\n            new Error(\r\n                `Invalid SSRC for remote stream[ssrc=${trackSsrc},id=${streamId},type=${mediaType}]`));\r\n\r\n        // Abort\r\n        return;\r\n    } else if (!ownerEndpointId) {\r\n        GlobalOnErrorHandler.callErrorHandler(\r\n            new Error(\r\n                `No SSRC owner known for remote stream[ssrc=${trackSsrc},id=${streamId},type=${mediaType}]`));\r\n\r\n        // Abort\r\n        return;\r\n    }\r\n\r\n    let sourceName = this.signalingLayer.getTrackSourceName(trackSsrc);\r\n\r\n    // If source name was not signaled, we'll generate one which allows testing signaling\r\n    // when mixing legacy(mobile) with new clients.\r\n    if (!sourceName) {\r\n        sourceName = getSourceNameForJitsiTrack(ownerEndpointId, mediaType, 0);\r\n    }\r\n\r\n    // eslint-disable-next-line no-undef\r\n    logger.info(`${this} creating remote track[endpoint=${ownerEndpointId},ssrc=${trackSsrc},`\r\n        + `type=${mediaType},sourceName=${sourceName}]`);\r\n\r\n    const peerMediaInfo = this.signalingLayer.getPeerMediaInfo(ownerEndpointId, mediaType, sourceName);\r\n\r\n    if (!peerMediaInfo) {\r\n        GlobalOnErrorHandler.callErrorHandler(\r\n            new Error(`${this}: no peer media info available for ${ownerEndpointId}`));\r\n\r\n        return;\r\n    }\r\n\r\n    const muted = peerMediaInfo.muted;\r\n    const videoType = peerMediaInfo.videoType; // can be undefined\r\n\r\n    // eslint-disable-next-line no-undef\r\n    this._createRemoteTrack(\r\n        ownerEndpointId, stream, track, mediaType, videoType, trackSsrc, muted, sourceName);\r\n};\r\n\r\n// FIXME cleanup params\r\n/* eslint-disable max-params */\r\n\r\n/**\r\n * Initializes a new JitsiRemoteTrack instance with the data provided by\r\n * the signaling layer and SDP.\r\n *\r\n * @param {string} ownerEndpointId the owner's endpoint ID (MUC nickname)\r\n * @param {MediaStream} stream the WebRTC stream instance\r\n * @param {MediaStreamTrack} track the WebRTC track instance\r\n * @param {MediaType} mediaType the track's type of the media\r\n * @param {VideoType} [videoType] the track's type of the video (if applicable)\r\n * @param {number} ssrc the track's main SSRC number\r\n * @param {boolean} muted the initial muted status\r\n * @param {String} sourceName the track's source name\r\n */\r\nTraceablePeerConnection.prototype._createRemoteTrack = function(\r\n        ownerEndpointId,\r\n        stream,\r\n        track,\r\n        mediaType,\r\n        videoType,\r\n        ssrc,\r\n        muted,\r\n        sourceName) {\r\n    let remoteTracksMap = this.remoteTracks.get(ownerEndpointId);\r\n\r\n    if (!remoteTracksMap) {\r\n        remoteTracksMap = new Map();\r\n        remoteTracksMap.set(MediaType.AUDIO, new Set());\r\n        remoteTracksMap.set(MediaType.VIDEO, new Set());\r\n        this.remoteTracks.set(ownerEndpointId, remoteTracksMap);\r\n    }\r\n\r\n    const userTracksByMediaType = remoteTracksMap.get(mediaType);\r\n\r\n    if (userTracksByMediaType?.size\r\n        && Array.from(userTracksByMediaType).find(jitsiTrack => jitsiTrack.getTrack() === track)) {\r\n        // Ignore duplicated event which can originate either from 'onStreamAdded' or 'onTrackAdded'.\r\n        logger.info(`${this} ignored duplicated track event for track[endpoint=${ownerEndpointId},type=${mediaType}]`);\r\n\r\n        return;\r\n    }\r\n\r\n    const remoteTrack\r\n        = new JitsiRemoteTrack(\r\n                this.rtc,\r\n                this.rtc.conference,\r\n                ownerEndpointId,\r\n                stream,\r\n                track,\r\n                mediaType,\r\n                videoType,\r\n                ssrc,\r\n                muted,\r\n                this.isP2P,\r\n                sourceName);\r\n\r\n    userTracksByMediaType.add(remoteTrack);\r\n    this.eventEmitter.emit(RTCEvents.REMOTE_TRACK_ADDED, remoteTrack, this);\r\n};\r\n\r\n/* eslint-enable max-params */\r\n\r\n/**\r\n * Handles remote stream removal.\r\n * @param stream the WebRTC MediaStream object which is being removed from the\r\n * PeerConnection\r\n */\r\nTraceablePeerConnection.prototype._remoteStreamRemoved = function(stream) {\r\n    if (!RTC.isUserStream(stream)) {\r\n        logger.info(`Ignored remote 'stream removed' event for stream[id=${stream.id}]`);\r\n\r\n        return;\r\n    }\r\n\r\n    // Call remoteTrackRemoved for each track in the stream\r\n    const streamVideoTracks = stream.getVideoTracks();\r\n\r\n    for (const videoTrack of streamVideoTracks) {\r\n        this._remoteTrackRemoved(stream, videoTrack);\r\n    }\r\n    const streamAudioTracks = stream.getAudioTracks();\r\n\r\n    for (const audioTrack of streamAudioTracks) {\r\n        this._remoteTrackRemoved(stream, audioTrack);\r\n    }\r\n};\r\n\r\n/**\r\n * Handles remote media track removal.\r\n *\r\n * @param {MediaStream} stream - WebRTC MediaStream instance which is the parent of the track.\r\n * @param {MediaStreamTrack} track - WebRTC MediaStreamTrack which has been removed from the PeerConnection.\r\n * @returns {void}\r\n */\r\nTraceablePeerConnection.prototype._remoteTrackRemoved = function(stream, track) {\r\n    const streamId = stream.id;\r\n    const trackId = track?.id;\r\n\r\n    if (!RTC.isUserStreamById(streamId)) {\r\n        logger.info(`${this} ignored remote 'stream removed' event for non-user stream[id=${streamId}]`);\r\n\r\n        return;\r\n    }\r\n\r\n    if (!streamId) {\r\n        GlobalOnErrorHandler.callErrorHandler(new Error(`${this} remote track removal failed - no stream ID`));\r\n\r\n        return;\r\n    }\r\n\r\n    if (!trackId) {\r\n        GlobalOnErrorHandler.callErrorHandler(new Error(`${this} remote track removal failed - no track ID`));\r\n\r\n        return;\r\n    }\r\n\r\n    const toBeRemoved = this.getRemoteTracks().find(\r\n        remoteTrack => remoteTrack.getStreamId() === streamId\r\n        && remoteTrack.getTrackId() === trackId);\r\n\r\n    if (!toBeRemoved) {\r\n        GlobalOnErrorHandler.callErrorHandler(new Error(`${this} remote track removal failed - track not found`));\r\n\r\n        return;\r\n    }\r\n\r\n    logger.info(`${this} remote track removed stream[id=${streamId},trackId=${trackId}]`);\r\n    this._removeRemoteTrack(toBeRemoved);\r\n};\r\n\r\n/**\r\n * Removes all JitsiRemoteTracks associated with given MUC nickname (resource part of the JID).\r\n *\r\n * @param {string} owner - The resource part of the MUC JID.\r\n * @returns {JitsiRemoteTrack[]} - The array of removed tracks.\r\n */\r\nTraceablePeerConnection.prototype.removeRemoteTracks = function(owner) {\r\n    let removedTracks = [];\r\n    const remoteTracksByMedia = this.remoteTracks.get(owner);\r\n\r\n    if (remoteTracksByMedia) {\r\n        removedTracks = removedTracks.concat(Array.from(remoteTracksByMedia.get(MediaType.AUDIO)));\r\n        removedTracks = removedTracks.concat(Array.from(remoteTracksByMedia.get(MediaType.VIDEO)));\r\n        this.remoteTracks.delete(owner);\r\n    }\r\n    logger.debug(`${this} removed remote tracks[endpoint=${owner},count=${removedTracks.length}`);\r\n\r\n    return removedTracks;\r\n};\r\n\r\n/**\r\n * Removes and disposes given <tt>JitsiRemoteTrack</tt> instance. Emits {@link RTCEvents.REMOTE_TRACK_REMOVED}.\r\n *\r\n * @param {JitsiRemoteTrack} toBeRemoved - The remote track to be removed.\r\n * @returns {void}\r\n */\r\nTraceablePeerConnection.prototype._removeRemoteTrack = function(toBeRemoved) {\r\n    toBeRemoved.dispose();\r\n    const participantId = toBeRemoved.getParticipantId();\r\n    const userTracksByMediaType = this.remoteTracks.get(participantId);\r\n\r\n    if (!userTracksByMediaType) {\r\n        logger.error(`${this} removeRemoteTrack: no remote tracks map for endpoint=${participantId}`);\r\n    } else if (!userTracksByMediaType.get(toBeRemoved.getType())?.delete(toBeRemoved)) {\r\n        logger.error(`${this} Failed to remove ${toBeRemoved} - type mapping messed up ?`);\r\n    }\r\n    this.eventEmitter.emit(RTCEvents.REMOTE_TRACK_REMOVED, toBeRemoved);\r\n};\r\n\r\n/**\r\n * Returns a map with keys msid/mediaType and <tt>TrackSSRCInfo</tt> values.\r\n * @param {RTCSessionDescription} desc the local description.\r\n * @return {Map<string,TrackSSRCInfo>}\r\n */\r\nTraceablePeerConnection.prototype._extractSSRCMap = function(desc) {\r\n    /**\r\n     * Track SSRC infos mapped by stream ID (msid) or mediaType (unified-plan)\r\n     * @type {Map<string,TrackSSRCInfo>}\r\n     */\r\n    const ssrcMap = new Map();\r\n\r\n    /**\r\n     * Groups mapped by primary SSRC number\r\n     * @type {Map<number,Array<SSRCGroupInfo>>}\r\n     */\r\n    const groupsMap = new Map();\r\n\r\n    if (typeof desc !== 'object' || desc === null\r\n        || typeof desc.sdp !== 'string') {\r\n        logger.warn('An empty description was passed as an argument');\r\n\r\n        return ssrcMap;\r\n    }\r\n\r\n    const session = transform.parse(desc.sdp);\r\n\r\n    if (!Array.isArray(session.media)) {\r\n        return ssrcMap;\r\n    }\r\n\r\n    let media = session.media;\r\n\r\n    if (this._usesUnifiedPlan) {\r\n        media = media.filter(mline => mline.direction === MediaDirection.SENDONLY\r\n            || mline.direction === MediaDirection.SENDRECV);\r\n    } else {\r\n        media = [];\r\n        [ MediaType.AUDIO, MediaType.VIDEO ].forEach(mediaType => {\r\n            const mLine = session.media.find(m => m.type === mediaType);\r\n\r\n            mLine && media.push(mLine);\r\n        });\r\n    }\r\n\r\n    let index = 0;\r\n\r\n    for (const mLine of media) {\r\n        if (!Array.isArray(mLine.ssrcs)) {\r\n            continue; // eslint-disable-line no-continue\r\n        }\r\n\r\n        if (Array.isArray(mLine.ssrcGroups)) {\r\n            for (const group of mLine.ssrcGroups) {\r\n                if (typeof group.semantics !== 'undefined' && typeof group.ssrcs !== 'undefined') {\r\n                    // Parse SSRCs and store as numbers\r\n                    const groupSSRCs = group.ssrcs.split(' ').map(ssrcStr => parseInt(ssrcStr, 10));\r\n                    const primarySSRC = groupSSRCs[0];\r\n\r\n                    // Note that group.semantics is already present\r\n                    group.ssrcs = groupSSRCs;\r\n\r\n                    // eslint-disable-next-line max-depth\r\n                    if (!groupsMap.has(primarySSRC)) {\r\n                        groupsMap.set(primarySSRC, []);\r\n                    }\r\n                    groupsMap.get(primarySSRC).push(group);\r\n                }\r\n            }\r\n        }\r\n\r\n        let ssrcs = mLine.ssrcs;\r\n\r\n        // Filter the ssrcs with 'msid' attribute for plan-b clients and 'cname' for unified-plan clients.\r\n        ssrcs = this._usesUnifiedPlan\r\n            ? ssrcs.filter(s => s.attribute === 'cname')\r\n            : ssrcs.filter(s => s.attribute === 'msid');\r\n\r\n        for (const ssrc of ssrcs) {\r\n            // Use the mediaType as key for the source map for unified plan clients since msids are not part of\r\n            // the standard and the unified plan SDPs do not have a proper msid attribute for the sources.\r\n            // Also the ssrcs for sources do not change for Unified plan clients since RTCRtpSender#replaceTrack is\r\n            // used for switching the tracks so it is safe to use the mediaType as the key for the TrackSSRCInfo map.\r\n            const key = this._usesUnifiedPlan ? `${mLine.type}-${index}` : ssrc.value;\r\n            const ssrcNumber = ssrc.id;\r\n            let ssrcInfo = ssrcMap.get(key);\r\n\r\n            if (!ssrcInfo) {\r\n                ssrcInfo = {\r\n                    ssrcs: [],\r\n                    groups: [],\r\n                    msid: key\r\n                };\r\n                ssrcMap.set(key, ssrcInfo);\r\n            }\r\n            ssrcInfo.ssrcs.push(ssrcNumber);\r\n\r\n            if (groupsMap.has(ssrcNumber)) {\r\n                const ssrcGroups = groupsMap.get(ssrcNumber);\r\n\r\n                for (const group of ssrcGroups) {\r\n                    ssrcInfo.groups.push(group);\r\n                }\r\n            }\r\n        }\r\n\r\n        // Currently multi-stream is supported for video only.\r\n        mLine.type === MediaType.VIDEO && index++;\r\n    }\r\n\r\n    return ssrcMap;\r\n};\r\n\r\n/**\r\n * Takes a SessionDescription object and returns a \"normalized\" version.\r\n * Currently it takes care of ordering the a=ssrc lines and denoting receive\r\n * only SSRCs.\r\n */\r\nconst normalizePlanB = function(desc) {\r\n    if (typeof desc !== 'object' || desc === null\r\n        || typeof desc.sdp !== 'string') {\r\n        logger.warn('An empty description was passed as an argument');\r\n\r\n        return desc;\r\n    }\r\n\r\n    // eslint-disable-next-line no-shadow\r\n    const transform = require('sdp-transform');\r\n    const session = transform.parse(desc.sdp);\r\n\r\n    if (typeof session !== 'undefined'\r\n            && typeof session.media !== 'undefined'\r\n            && Array.isArray(session.media)) {\r\n        session.media.forEach(mLine => {\r\n\r\n            // Chrome appears to be picky about the order in which a=ssrc lines\r\n            // are listed in an m-line when rtx is enabled (and thus there are\r\n            // a=ssrc-group lines with FID semantics). Specifically if we have\r\n            // \"a=ssrc-group:FID S1 S2\" and the \"a=ssrc:S2\" lines appear before\r\n            // the \"a=ssrc:S1\" lines, SRD fails.\r\n            // So, put SSRC which appear as the first SSRC in an FID ssrc-group\r\n            // first.\r\n            const firstSsrcs = [];\r\n            const newSsrcLines = [];\r\n\r\n            if (typeof mLine.ssrcGroups !== 'undefined'\r\n                && Array.isArray(mLine.ssrcGroups)) {\r\n                mLine.ssrcGroups.forEach(group => {\r\n                    if (typeof group.semantics !== 'undefined'\r\n                        && group.semantics === 'FID') {\r\n                        if (typeof group.ssrcs !== 'undefined') {\r\n                            firstSsrcs.push(Number(group.ssrcs.split(' ')[0]));\r\n                        }\r\n                    }\r\n                });\r\n            }\r\n\r\n            if (Array.isArray(mLine.ssrcs)) {\r\n                let i;\r\n\r\n                for (i = 0; i < mLine.ssrcs.length; i++) {\r\n                    if (typeof mLine.ssrcs[i] === 'object'\r\n                        && typeof mLine.ssrcs[i].id !== 'undefined'\r\n                        && firstSsrcs.indexOf(mLine.ssrcs[i].id) >= 0) {\r\n                        newSsrcLines.push(mLine.ssrcs[i]);\r\n                        delete mLine.ssrcs[i];\r\n                    }\r\n                }\r\n\r\n                for (i = 0; i < mLine.ssrcs.length; i++) {\r\n                    if (typeof mLine.ssrcs[i] !== 'undefined') {\r\n                        newSsrcLines.push(mLine.ssrcs[i]);\r\n                    }\r\n                }\r\n\r\n                mLine.ssrcs = replaceDefaultUnifiedPlanMsid(newSsrcLines);\r\n            }\r\n        });\r\n    }\r\n\r\n    const resStr = transform.write(session);\r\n\r\n\r\n    return new RTCSessionDescription({\r\n        type: desc.type,\r\n        sdp: resStr\r\n    });\r\n};\r\n\r\n/**\r\n * Unified plan differentiates a remote track not associated with a stream using\r\n * the msid \"-\", which can incorrectly trigger an onaddstream event in plan-b.\r\n * For jitsi, these tracks are actually receive-only ssrcs. To prevent\r\n * onaddstream from firing, remove the ssrcs with msid \"-\" except the cname\r\n * line. Normally the ssrcs are not used by the client, as the bridge controls\r\n * media flow, but keep one reference to the ssrc for the p2p case.\r\n *\r\n * @param {Array<Object>} ssrcLines - The ssrc lines from a remote description.\r\n * @private\r\n * @returns {Array<Object>} ssrcLines with removed lines referencing msid \"-\".\r\n */\r\nfunction replaceDefaultUnifiedPlanMsid(ssrcLines = []) {\r\n    if (!browser.isChrome() || !browser.isVersionGreaterThan(70)) {\r\n        return ssrcLines;\r\n    }\r\n\r\n    let filteredLines = [ ...ssrcLines ];\r\n\r\n    const problematicSsrcIds = ssrcLines.filter(ssrcLine =>\r\n        ssrcLine.attribute === 'mslabel' && ssrcLine.value === '-')\r\n        .map(ssrcLine => ssrcLine.id);\r\n\r\n    problematicSsrcIds.forEach(ssrcId => {\r\n        // Find the cname which is to be modified and left in.\r\n        const cnameLine = filteredLines.find(line =>\r\n            line.id === ssrcId && line.attribute === 'cname');\r\n\r\n        cnameLine.value = `${MediaDirection.RECVONLY}-${ssrcId}`;\r\n\r\n        // Remove all of lines for the ssrc.\r\n        filteredLines\r\n            = filteredLines.filter(line => line.id !== ssrcId);\r\n\r\n        // But re-add the cname line so there is a reference kept to the ssrc\r\n        // in the SDP.\r\n        filteredLines.push(cnameLine);\r\n    });\r\n\r\n    return filteredLines;\r\n}\r\n\r\n/**\r\n * Makes sure that both audio and video directions are configured as 'sendrecv'.\r\n * @param {Object} localDescription the SDP object as defined by WebRTC.\r\n * @param {object} options <tt>TracablePeerConnection</tt> config options.\r\n */\r\nconst enforceSendRecv = function(localDescription, options) {\r\n    if (!localDescription) {\r\n        throw new Error('No local description passed in.');\r\n    }\r\n\r\n    const transformer = new SdpTransformWrap(localDescription.sdp);\r\n    const audioMedia = transformer.selectMedia(MediaType.AUDIO)?.[0];\r\n    let changed = false;\r\n\r\n    if (audioMedia && audioMedia.direction !== MediaDirection.SENDRECV) {\r\n        if (options.startSilent) {\r\n            audioMedia.direction = MediaDirection.INACTIVE;\r\n        } else {\r\n            audioMedia.direction = MediaDirection.SENDRECV;\r\n        }\r\n\r\n        changed = true;\r\n    }\r\n\r\n    const videoMedia = transformer.selectMedia(MediaType.VIDEO)?.[0];\r\n\r\n    if (videoMedia && videoMedia.direction !== MediaDirection.SENDRECV) {\r\n        videoMedia.direction = MediaDirection.SENDRECV;\r\n        changed = true;\r\n    }\r\n\r\n    if (changed) {\r\n        return new RTCSessionDescription({\r\n            type: localDescription.type,\r\n            sdp: transformer.toRawSDP()\r\n        });\r\n    }\r\n\r\n    return localDescription;\r\n};\r\n\r\n/**\r\n *\r\n * @param {JitsiLocalTrack} localTrack\r\n */\r\nTraceablePeerConnection.prototype.getLocalSSRC = function(localTrack) {\r\n    const ssrcInfo = this._getSSRC(localTrack.rtcId);\r\n\r\n    return ssrcInfo && ssrcInfo.ssrcs[0];\r\n};\r\n\r\n/**\r\n * When doing unified plan simulcast, we'll have a set of ssrcs but no ssrc-groups on Firefox. Unfortunately, Jicofo\r\n * will complain if it sees ssrcs with matching msids but no ssrc-group, so a ssrc-group line is injected to make\r\n * Jicofo happy.\r\n *\r\n * @param desc A session description object (with 'type' and 'sdp' fields)\r\n * @return A session description object with its sdp field modified to contain an inject ssrc-group for simulcast.\r\n */\r\nTraceablePeerConnection.prototype._injectSsrcGroupForUnifiedSimulcast = function(desc) {\r\n    const sdp = transform.parse(desc.sdp);\r\n    const video = sdp.media.find(mline => mline.type === 'video');\r\n\r\n    // Check if the browser supports RTX, add only the primary ssrcs to the SIM group if that is the case.\r\n    video.ssrcGroups = video.ssrcGroups || [];\r\n    const fidGroups = video.ssrcGroups.filter(group => group.semantics === 'FID');\r\n\r\n    if (video.simulcast || video.simulcast_03) {\r\n        const ssrcs = [];\r\n\r\n        if (fidGroups && fidGroups.length) {\r\n            fidGroups.forEach(group => {\r\n                ssrcs.push(group.ssrcs.split(' ')[0]);\r\n            });\r\n        } else {\r\n            video.ssrcs.forEach(ssrc => {\r\n                if (ssrc.attribute === 'msid') {\r\n                    ssrcs.push(ssrc.id);\r\n                }\r\n            });\r\n        }\r\n        if (video.ssrcGroups.find(group => group.semantics === 'SIM')) {\r\n            // Group already exists, no need to do anything\r\n            return desc;\r\n        }\r\n\r\n        // Add a SIM group for every 3 FID groups.\r\n        for (let i = 0; i < ssrcs.length; i += 3) {\r\n            const simSsrcs = ssrcs.slice(i, i + 3);\r\n\r\n            video.ssrcGroups.push({\r\n                semantics: 'SIM',\r\n                ssrcs: simSsrcs.join(' ')\r\n            });\r\n        }\r\n    }\r\n\r\n    return new RTCSessionDescription({\r\n        type: desc.type,\r\n        sdp: transform.write(sdp)\r\n    });\r\n};\r\n\r\n/* eslint-disable-next-line vars-on-top */\r\nconst getters = {\r\n    signalingState() {\r\n        return this.peerconnection.signalingState;\r\n    },\r\n    iceConnectionState() {\r\n        return this.peerconnection.iceConnectionState;\r\n    },\r\n    connectionState() {\r\n        return this.peerconnection.connectionState;\r\n    },\r\n    localDescription() {\r\n        let desc = this.peerconnection.localDescription;\r\n\r\n        if (!desc) {\r\n            logger.debug(`${this} getLocalDescription no localDescription found`);\r\n\r\n            return {};\r\n        }\r\n\r\n        this.trace('getLocalDescription::preTransform', dumpSDP(desc));\r\n\r\n        // If the browser is running in unified plan mode and this is a jvb connection,\r\n        // transform the SDP to Plan B first.\r\n        if (this._usesUnifiedPlan && !this.isP2P) {\r\n            desc = this.interop.toPlanB(desc);\r\n            this.trace('getLocalDescription::postTransform (Plan B)',\r\n                dumpSDP(desc));\r\n\r\n            desc = this._injectSsrcGroupForUnifiedSimulcast(desc);\r\n            this.trace('getLocalDescription::postTransform (inject ssrc group)',\r\n                dumpSDP(desc));\r\n        } else if (!this._usesUnifiedPlan) {\r\n            if (browser.doesVideoMuteByStreamRemove()) {\r\n                desc = this.localSdpMunger.maybeAddMutedLocalVideoTracksToSDP(desc);\r\n                logger.debug(\r\n                    'getLocalDescription::postTransform (munge local SDP)', desc);\r\n            }\r\n\r\n            // What comes out of this getter will be signalled over Jingle to\r\n            // the other peer, so we need to make sure the media direction is\r\n            // 'sendrecv' because we won't change the direction later and don't want\r\n            // the other peer to think we can't send or receive.\r\n            //\r\n            // Note that the description we set in chrome does have the accurate\r\n            // direction (e.g. 'recvonly'), since that is technically what is\r\n            // happening (check setLocalDescription impl).\r\n            desc = enforceSendRecv(desc, this.options);\r\n        }\r\n\r\n        // See the method's doc for more info about this transformation.\r\n        desc = this.localSdpMunger.transformStreamIdentifiers(desc);\r\n\r\n        return desc;\r\n    },\r\n    remoteDescription() {\r\n        let desc = this.peerconnection.remoteDescription;\r\n\r\n        if (!desc) {\r\n            logger.debug(`${this} getRemoteDescription no remoteDescription found`);\r\n\r\n            return {};\r\n        }\r\n        this.trace('getRemoteDescription::preTransform', dumpSDP(desc));\r\n\r\n        if (this._usesUnifiedPlan) {\r\n            if (this.isP2P) {\r\n                // Adjust the media direction for p2p based on whether a local source has been added.\r\n                desc = this._adjustRemoteMediaDirection(desc);\r\n            } else {\r\n                // If this is a jvb connection, transform the SDP to Plan B first.\r\n                desc = this.interop.toPlanB(desc);\r\n                this.trace('getRemoteDescription::postTransform (Plan B)', dumpSDP(desc));\r\n            }\r\n        }\r\n\r\n        return desc;\r\n    }\r\n};\r\n\r\nObject.keys(getters).forEach(prop => {\r\n    Object.defineProperty(\r\n        TraceablePeerConnection.prototype,\r\n        prop, {\r\n            get: getters[prop]\r\n        }\r\n    );\r\n});\r\n\r\nTraceablePeerConnection.prototype._getSSRC = function(rtcId) {\r\n    return this.localSSRCs.get(rtcId);\r\n};\r\n\r\n/**\r\n * Checks if low fps screensharing is in progress.\r\n *\r\n * @private\r\n * @returns {boolean} Returns true if 5 fps screensharing is in progress, false otherwise.\r\n */\r\nTraceablePeerConnection.prototype.isSharingLowFpsScreen = function() {\r\n    return this._isSharingScreen() && this._capScreenshareBitrate;\r\n};\r\n\r\n/**\r\n * Checks if screensharing is in progress.\r\n *\r\n * @returns {boolean}  Returns true if a desktop track has been added to the peerconnection, false otherwise.\r\n */\r\nTraceablePeerConnection.prototype._isSharingScreen = function() {\r\n    const tracks = this.getLocalVideoTracks();\r\n\r\n    return Boolean(tracks.find(track => track.videoType === VideoType.DESKTOP));\r\n};\r\n\r\n/**\r\n * Munges the order of the codecs in the SDP passed based on the preference\r\n * set through config.js settings. All instances of the specified codec are\r\n * moved up to the top of the list when it is preferred. The specified codec\r\n * is deleted from the list if the configuration specifies that the codec be\r\n * disabled.\r\n * @param {RTCSessionDescription} description that needs to be munged.\r\n * @returns {RTCSessionDescription} the munged description.\r\n */\r\nTraceablePeerConnection.prototype._mungeCodecOrder = function(description) {\r\n    if (!this.codecPreference) {\r\n        return description;\r\n    }\r\n\r\n    const parsedSdp = transform.parse(description.sdp);\r\n    const mLines = parsedSdp.media.filter(m => m.type === this.codecPreference.mediaType);\r\n\r\n    if (!mLines.length) {\r\n        return description;\r\n    }\r\n\r\n    for (const mLine of mLines) {\r\n        if (this.codecPreference.enable) {\r\n            SDPUtil.preferCodec(mLine, this.codecPreference.mimeType);\r\n\r\n            // Strip the high profile H264 codecs on mobile clients for p2p connection. High profile codecs give better\r\n            // quality at the expense of higher load which we do not want on mobile clients. Jicofo offers only the\r\n            // baseline code for the jvb connection and therefore this is not needed for jvb connection.\r\n            // TODO - add check for mobile browsers once js-utils provides that check.\r\n            if (this.codecPreference.mimeType === CodecMimeType.H264 && browser.isReactNative() && this.isP2P) {\r\n                SDPUtil.stripCodec(mLine, this.codecPreference.mimeType, true /* high profile */);\r\n            }\r\n        } else {\r\n            SDPUtil.stripCodec(mLine, this.codecPreference.mimeType);\r\n        }\r\n    }\r\n\r\n    return new RTCSessionDescription({\r\n        type: description.type,\r\n        sdp: transform.write(parsedSdp)\r\n    });\r\n};\r\n\r\n/**\r\n * Add {@link JitsiLocalTrack} to this TPC.\r\n * @param {JitsiLocalTrack} track\r\n * @param {boolean} isInitiator indicates if the endpoint is the offerer.\r\n * @returns {Promise<void>} - resolved when done.\r\n */\r\nTraceablePeerConnection.prototype.addTrack = function(track, isInitiator = false) {\r\n    const rtcId = track.rtcId;\r\n\r\n    logger.info(`${this} adding ${track}`);\r\n\r\n    if (this.localTracks.has(rtcId)) {\r\n\r\n        return Promise.reject(new Error(`${track} is already in ${this}`));\r\n    }\r\n\r\n    this.localTracks.set(rtcId, track);\r\n    const webrtcStream = track.getOriginalStream();\r\n\r\n    if (this._usesUnifiedPlan) {\r\n        logger.debug(`${this} TPC.addTrack using unified plan`);\r\n        try {\r\n            this.tpcUtils.addTrack(track, isInitiator);\r\n            if (track) {\r\n                if (track.isAudioTrack()) {\r\n                    this._hasHadAudioTrack = true;\r\n                } else {\r\n                    this._hasHadVideoTrack = true;\r\n                }\r\n            }\r\n        } catch (error) {\r\n            logger.error(`${this} Adding track=${track} failed: ${error?.message}`);\r\n\r\n            return Promise.reject(error);\r\n        }\r\n    } else {\r\n        // Use addStream API for the plan-b case.\r\n        if (webrtcStream) {\r\n            this._addStream(webrtcStream);\r\n\r\n        // It's not ok for a track to not have a WebRTC stream if:\r\n        } else if (!browser.doesVideoMuteByStreamRemove()\r\n                    || track.isAudioTrack()\r\n                    || (track.isVideoTrack() && !track.isMuted())) {\r\n            return Promise.reject(new Error(`${this} no WebRTC stream for track=${track}`));\r\n        }\r\n\r\n        // Muted video tracks do not have WebRTC stream\r\n        if (browser.doesVideoMuteByStreamRemove() && track.isVideoTrack() && track.isMuted()) {\r\n            const ssrcInfo = this.generateNewStreamSSRCInfo(track);\r\n\r\n            this.sdpConsistency.setPrimarySsrc(ssrcInfo.ssrcs[0]);\r\n            const simGroup\r\n                = ssrcInfo.groups.find(groupInfo => groupInfo.semantics === 'SIM');\r\n\r\n            if (simGroup) {\r\n                this.simulcast.setSsrcCache(simGroup.ssrcs);\r\n            }\r\n            const fidGroups\r\n                = ssrcInfo.groups.filter(\r\n                    groupInfo => groupInfo.semantics === 'FID');\r\n\r\n            if (fidGroups) {\r\n                const rtxSsrcMapping = new Map();\r\n\r\n                fidGroups.forEach(fidGroup => {\r\n                    const primarySsrc = fidGroup.ssrcs[0];\r\n                    const rtxSsrc = fidGroup.ssrcs[1];\r\n\r\n                    rtxSsrcMapping.set(primarySsrc, rtxSsrc);\r\n                });\r\n                this.rtxModifier.setSsrcCache(rtxSsrcMapping);\r\n            }\r\n        }\r\n    }\r\n    let promiseChain = Promise.resolve();\r\n\r\n    // On Firefox, the encodings have to be configured on the sender only after the transceiver is created.\r\n    if (browser.isFirefox()) {\r\n        promiseChain = promiseChain.then(() => webrtcStream && this.tpcUtils.setEncodings(track));\r\n    }\r\n\r\n    return promiseChain;\r\n};\r\n\r\n/**\r\n * Adds local track to the RTCPeerConnection.\r\n *\r\n * @param {JitsiLocalTrack} track the track to be added to the pc.\r\n * @return {Promise<boolean>} Promise that resolves to true if the underlying PeerConnection's state has changed and\r\n * renegotiation is required, false if no renegotiation is needed or Promise is rejected when something goes wrong.\r\n */\r\nTraceablePeerConnection.prototype.addTrackToPc = function(track) {\r\n    logger.info(`${this} Adding track=${track} to PC`);\r\n\r\n    if (!this._assertTrackBelongs('addTrackToPc', track)) {\r\n        // Abort\r\n\r\n        return Promise.reject('Track not found on the peerconnection');\r\n    }\r\n\r\n    const webRtcStream = track.getOriginalStream();\r\n\r\n    if (!webRtcStream) {\r\n        logger.error(`${this} Unable to add track=${track} to PC - no WebRTC stream`);\r\n\r\n        return Promise.reject('Stream not found');\r\n    }\r\n\r\n    if (this._usesUnifiedPlan) {\r\n        return this.tpcUtils.replaceTrack(null, track).then(() => {\r\n            if (track) {\r\n                if (track.isAudioTrack()) {\r\n                    this._hasHadAudioTrack = true;\r\n                } else {\r\n                    this._hasHadVideoTrack = true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        });\r\n    }\r\n\r\n    this._addStream(webRtcStream);\r\n\r\n    return Promise.resolve(true);\r\n};\r\n\r\n/**\r\n * Adds WebRTC media stream to the underlying PeerConnection\r\n * @param {MediaStream} mediaStream\r\n * @private\r\n */\r\nTraceablePeerConnection.prototype._addStream = function(mediaStream) {\r\n    this.peerconnection.addStream(mediaStream);\r\n    this._addedStreams.push(mediaStream);\r\n};\r\n\r\n/**\r\n * Removes WebRTC media stream from the underlying PeerConection\r\n * @param {MediaStream} mediaStream\r\n */\r\nTraceablePeerConnection.prototype._removeStream = function(mediaStream) {\r\n    this.peerconnection.removeStream(mediaStream);\r\n    this._addedStreams\r\n        = this._addedStreams.filter(stream => stream !== mediaStream);\r\n};\r\n\r\n/**\r\n * This method when called will check if given <tt>localTrack</tt> belongs to\r\n * this TPC (that it has been previously added using {@link addTrack}). If the\r\n * track does not belong an error message will be logged.\r\n * @param {string} methodName the method name that will be logged in an error\r\n * message\r\n * @param {JitsiLocalTrack} localTrack\r\n * @return {boolean} <tt>true</tt> if given local track belongs to this TPC or\r\n * <tt>false</tt> otherwise.\r\n * @private\r\n */\r\nTraceablePeerConnection.prototype._assertTrackBelongs = function(\r\n        methodName,\r\n        localTrack) {\r\n    const doesBelong = this.localTracks.has(localTrack?.rtcId);\r\n\r\n    if (!doesBelong) {\r\n        logger.error(`${this} ${methodName}: track=${localTrack} does not belong to pc`);\r\n    }\r\n\r\n    return doesBelong;\r\n};\r\n\r\n/**\r\n * Returns the codec that is configured on the client as the preferred video codec.\r\n * This takes into account the current order of codecs in the local description sdp.\r\n *\r\n * @returns {CodecMimeType} The codec that is set as the preferred codec to receive\r\n * video in the local SDP.\r\n */\r\nTraceablePeerConnection.prototype.getConfiguredVideoCodec = function() {\r\n    const sdp = this.peerconnection.localDescription?.sdp;\r\n    const defaultCodec = CodecMimeType.VP8;\r\n\r\n    if (!sdp) {\r\n        return defaultCodec;\r\n    }\r\n    const parsedSdp = transform.parse(sdp);\r\n    const mLine = parsedSdp.media.find(m => m.type === MediaType.VIDEO);\r\n    const codec = mLine.rtp[0].codec;\r\n\r\n    if (codec) {\r\n        return Object.values(CodecMimeType).find(value => value === codec.toLowerCase());\r\n    }\r\n\r\n    return defaultCodec;\r\n};\r\n\r\n/**\r\n * Enables or disables simulcast for screenshare based on the frame rate requested for desktop track capture.\r\n *\r\n * @param {number} maxFps framerate to be used for desktop track capture.\r\n */\r\nTraceablePeerConnection.prototype.setDesktopSharingFrameRate = function(maxFps) {\r\n    const lowFps = maxFps <= SS_DEFAULT_FRAME_RATE;\r\n\r\n    this._capScreenshareBitrate = this.isSimulcastOn() && lowFps;\r\n};\r\n\r\n/**\r\n * Sets the codec preference on the peerconnection. The codec preference goes into effect when\r\n * the next renegotiation happens.\r\n *\r\n * @param {CodecMimeType} preferredCodec the preferred codec.\r\n * @param {CodecMimeType} disabledCodec the codec that needs to be disabled.\r\n * @returns {void}\r\n */\r\nTraceablePeerConnection.prototype.setVideoCodecs = function(preferredCodec = null, disabledCodec = null) {\r\n    // If both enable and disable are set, disable settings will prevail.\r\n    const enable = disabledCodec === null;\r\n    const mimeType = disabledCodec ? disabledCodec : preferredCodec;\r\n\r\n    if (this.codecPreference && (preferredCodec || disabledCodec)) {\r\n        this.codecPreference.enable = enable;\r\n        this.codecPreference.mimeType = mimeType;\r\n    } else if (preferredCodec || disabledCodec) {\r\n        this.codecPreference = {\r\n            enable,\r\n            mediaType: MediaType.VIDEO,\r\n            mimeType\r\n        };\r\n    } else {\r\n        logger.warn(`${this} Invalid codec settings[preferred=${preferredCodec},disabled=${disabledCodec}],\r\n            atleast one value is needed`);\r\n    }\r\n};\r\n\r\n/**\r\n * Tells if the given WebRTC <tt>MediaStream</tt> has been added to\r\n * the underlying WebRTC PeerConnection.\r\n * @param {MediaStream} mediaStream\r\n * @returns {boolean}\r\n */\r\nTraceablePeerConnection.prototype.isMediaStreamInPc = function(mediaStream) {\r\n    return this._addedStreams.indexOf(mediaStream) > -1;\r\n};\r\n\r\n/**\r\n * Remove local track from this TPC.\r\n * @param {JitsiLocalTrack} localTrack the track to be removed from this TPC.\r\n *\r\n * FIXME It should probably remove a boolean just like {@link removeTrackFromPc}\r\n *       The same applies to addTrack.\r\n */\r\nTraceablePeerConnection.prototype.removeTrack = function(localTrack) {\r\n    const webRtcStream = localTrack.getOriginalStream();\r\n\r\n    this.trace(\r\n        'removeStream',\r\n        localTrack.rtcId, webRtcStream ? webRtcStream.id : undefined);\r\n\r\n    if (!this._assertTrackBelongs('removeStream', localTrack)) {\r\n        // Abort - nothing to be done here\r\n        return;\r\n    }\r\n    this.localTracks.delete(localTrack.rtcId);\r\n    this.localSSRCs.delete(localTrack.rtcId);\r\n\r\n    if (webRtcStream) {\r\n        this.peerconnection.removeStream(webRtcStream);\r\n    }\r\n};\r\n\r\n/**\r\n * Returns the sender corresponding to the given media type.\r\n * @param {MEDIA_TYPE} mediaType - The media type 'audio' or 'video' to be used for the search.\r\n * @returns {RTPSender|undefined} - The found sender or undefined if no sender\r\n * was found.\r\n */\r\nTraceablePeerConnection.prototype.findSenderByKind = function(mediaType) {\r\n    if (this.peerconnection.getSenders) {\r\n        return this.peerconnection.getSenders().find(s => s.track && s.track.kind === mediaType);\r\n    }\r\n};\r\n\r\n/**\r\n * Returns the receiver corresponding to the given MediaStreamTrack.\r\n *\r\n * @param {MediaSreamTrack} track - The media stream track used for the search.\r\n * @returns {RTCRtpReceiver|undefined} - The found receiver or undefined if no receiver\r\n * was found.\r\n */\r\nTraceablePeerConnection.prototype.findReceiverForTrack = function(track) {\r\n    return this.peerconnection.getReceivers().find(r => r.track === track);\r\n};\r\n\r\n/**\r\n * Returns the sender corresponding to the given MediaStreamTrack.\r\n *\r\n * @param {MediaSreamTrack} track - The media stream track used for the search.\r\n * @returns {RTCRtpSender|undefined} - The found sender or undefined if no sender\r\n * was found.\r\n */\r\nTraceablePeerConnection.prototype.findSenderForTrack = function(track) {\r\n    if (this.peerconnection.getSenders) {\r\n        return this.peerconnection.getSenders().find(s => s.track === track);\r\n    }\r\n};\r\n\r\n/**\r\n * Processes the local description SDP and caches the mids of the mlines associated with the given tracks.\r\n *\r\n * @param {Array<JitsiLocalTrack>} localTracks - local tracks that are added to the peerconnection.\r\n * @returns {void}\r\n */\r\nTraceablePeerConnection.prototype.processLocalSdpForTransceiverInfo = function(localTracks) {\r\n    const localSdp = this.peerconnection.localDescription?.sdp;\r\n\r\n    if (!localSdp) {\r\n        return;\r\n    }\r\n\r\n    [ MediaType.AUDIO, MediaType.VIDEO ].forEach(mediaType => {\r\n        const tracks = localTracks.filter(t => t.getType() === mediaType);\r\n        const parsedSdp = transform.parse(localSdp);\r\n        const mLines = parsedSdp.media.filter(mline => mline.type === mediaType);\r\n\r\n        tracks.forEach((track, idx) => {\r\n            if (!this._localTrackTransceiverMids.has(track.rtcId)) {\r\n                this._localTrackTransceiverMids.set(track.rtcId, mLines[idx].mid.toString());\r\n            }\r\n        });\r\n    });\r\n};\r\n\r\n/**\r\n * Replaces <tt>oldTrack</tt> with <tt>newTrack</tt> from the peer connection.\r\n * Either <tt>oldTrack</tt> or <tt>newTrack</tt> can be null; replacing a valid\r\n * <tt>oldTrack</tt> with a null <tt>newTrack</tt> effectively just removes\r\n * <tt>oldTrack</tt>\r\n *\r\n * @param {JitsiLocalTrack|null} oldTrack - The current track in use to be replaced on the pc.\r\n * @param {JitsiLocalTrack|null} newTrack - The new track to be used.\r\n *\r\n * @returns {Promise<boolean>} - If the promise resolves with true, renegotiation will be needed.\r\n * Otherwise no renegotiation is needed.\r\n */\r\nTraceablePeerConnection.prototype.replaceTrack = function(oldTrack, newTrack) {\r\n    if (!(oldTrack || newTrack)) {\r\n        logger.info(`${this} replaceTrack called with no new track and no old track`);\r\n\r\n        return Promise.resolve();\r\n    }\r\n\r\n    if (this._usesUnifiedPlan) {\r\n        logger.debug(`${this} TPC.replaceTrack using unified plan`);\r\n        const mediaType = newTrack?.getType() ?? oldTrack?.getType();\r\n\r\n        return this.tpcUtils.replaceTrack(oldTrack, newTrack)\r\n            .then(transceiver => {\r\n                if (oldTrack) {\r\n                    this.localTracks.delete(oldTrack.rtcId);\r\n                    this._localTrackTransceiverMids.delete(oldTrack.rtcId);\r\n                }\r\n\r\n                if (newTrack) {\r\n                    if (newTrack.isAudioTrack()) {\r\n                        this._hasHadAudioTrack = true;\r\n                    } else {\r\n                        this._hasHadVideoTrack = true;\r\n                    }\r\n                    this._localTrackTransceiverMids.set(newTrack.rtcId, transceiver?.mid?.toString());\r\n                    this.localTracks.set(newTrack.rtcId, newTrack);\r\n                }\r\n\r\n                // Update the local SSRC cache for the case when one track gets replaced with another and no\r\n                // renegotiation is triggered as a result of this.\r\n                if (oldTrack && newTrack) {\r\n                    const oldTrackSSRC = this.localSSRCs.get(oldTrack.rtcId);\r\n\r\n                    if (oldTrackSSRC) {\r\n                        this.localSSRCs.delete(oldTrack.rtcId);\r\n                        this.localSSRCs.set(newTrack.rtcId, oldTrackSSRC);\r\n                    }\r\n                }\r\n                const mediaActive = mediaType === MediaType.AUDIO\r\n                    ? this.audioTransferActive\r\n                    : this.videoTransferActive;\r\n\r\n                // Set the transceiver direction only if media is not suspended on the connection. This happens when\r\n                // the client is using the p2p connection. Transceiver direction is updated when media is resumed on\r\n                // this connection again.\r\n                if (transceiver && mediaActive) {\r\n                    // In the scenario where we remove the oldTrack (oldTrack is not null and newTrack is null) on FF\r\n                    // if we change the direction to RECVONLY, create answer will generate SDP with only 1 receive\r\n                    // only ssrc instead of keeping all 6 ssrcs that we currently have. Stopping the screen sharing\r\n                    // and then starting it again will trigger 2 rounds of source-remove and source-add replacing\r\n                    // the 6 ssrcs for the screen sharing with 1 receive only ssrc and then removing the receive\r\n                    // only ssrc and adding the same 6 ssrcs. On the remote participant's side the same ssrcs will\r\n                    // be reused on a new m-line and if the remote participant is FF due to\r\n                    // https://bugzilla.mozilla.org/show_bug.cgi?id=1768729 the video stream won't be rendered.\r\n                    // That's why we need keep the direction to SENDRECV for FF.\r\n                    //\r\n                    // NOTE: If we return back to the approach of not removing the track for FF and instead using the\r\n                    // enabled property for mute or stopping screensharing we may need to change the direction to\r\n                    // RECVONLY if FF still sends the media even though the enabled flag is set to false.\r\n                    transceiver.direction\r\n                        = newTrack || browser.isFirefox() ? MediaDirection.SENDRECV : MediaDirection.RECVONLY;\r\n                } else if (transceiver) {\r\n                    transceiver.direction = MediaDirection.INACTIVE;\r\n                }\r\n\r\n                // Avoid configuring the encodings on Chromium/Safari until simulcast is configured\r\n                // for the newly added track using SDP munging which happens during the renegotiation.\r\n                const configureEncodingsPromise = browser.usesSdpMungingForSimulcast() || !newTrack\r\n                    ? Promise.resolve()\r\n                    : this.tpcUtils.setEncodings(newTrack);\r\n\r\n                return configureEncodingsPromise.then(() => this.isP2P);\r\n            });\r\n    }\r\n\r\n    logger.debug(`${this} TPC.replaceTrack using plan B`);\r\n\r\n    let promiseChain = Promise.resolve();\r\n\r\n    if (oldTrack) {\r\n        this.removeTrack(oldTrack);\r\n    }\r\n    if (newTrack) {\r\n        promiseChain = this.addTrack(newTrack);\r\n    }\r\n\r\n    return promiseChain.then(() => true);\r\n};\r\n\r\n/**\r\n * Removes local track from the RTCPeerConnection.\r\n *\r\n * @param {JitsiLocalTrack} localTrack the local track to be removed.\r\n * @return {Promise<boolean>} Promise that resolves to true if the underlying PeerConnection's state has changed and\r\n * renegotiation is required, false if no renegotiation is needed or Promise is rejected when something goes wrong.\r\n */\r\nTraceablePeerConnection.prototype.removeTrackFromPc = function(localTrack) {\r\n    const webRtcStream = localTrack.getOriginalStream();\r\n\r\n    this.trace('removeTrack', localTrack.rtcId, webRtcStream ? webRtcStream.id : null);\r\n\r\n    if (!this._assertTrackBelongs('removeTrack', localTrack)) {\r\n        // Abort - nothing to be done here\r\n        return Promise.reject('Track not found in the peerconnection');\r\n    }\r\n\r\n    if (this._usesUnifiedPlan) {\r\n        return this.tpcUtils.replaceTrack(localTrack, null).then(() => false);\r\n    }\r\n\r\n    if (webRtcStream) {\r\n        logger.info(`${this} Removing track=${localTrack} from PC`);\r\n        this._removeStream(webRtcStream);\r\n\r\n        return Promise.resolve(true);\r\n    }\r\n\r\n    logger.error(`${this} removeTrack - no WebRTC stream for track=${localTrack}`);\r\n\r\n    return Promise.reject('Stream not found');\r\n};\r\n\r\nTraceablePeerConnection.prototype.createDataChannel = function(label, opts) {\r\n    this.trace('createDataChannel', label, opts);\r\n\r\n    return this.peerconnection.createDataChannel(label, opts);\r\n};\r\n\r\n/**\r\n * Ensures that the simulcast ssrc-group appears after any other ssrc-groups\r\n * in the SDP so that simulcast is properly activated.\r\n *\r\n * @param {Object} localSdp the WebRTC session description instance for\r\n * the local description.\r\n * @private\r\n */\r\nTraceablePeerConnection.prototype._ensureSimulcastGroupIsLast = function(localSdp) {\r\n    let sdpStr = localSdp.sdp;\r\n\r\n    const videoStartIndex = sdpStr.indexOf('m=video');\r\n    const simStartIndex = sdpStr.indexOf('a=ssrc-group:SIM', videoStartIndex);\r\n    let otherStartIndex = sdpStr.lastIndexOf('a=ssrc-group');\r\n\r\n    if (simStartIndex === -1\r\n        || otherStartIndex === -1\r\n        || otherStartIndex === simStartIndex) {\r\n        return localSdp;\r\n    }\r\n\r\n    const simEndIndex = sdpStr.indexOf('\\r\\n', simStartIndex);\r\n    const simStr = sdpStr.substring(simStartIndex, simEndIndex + 2);\r\n\r\n    sdpStr = sdpStr.replace(simStr, '');\r\n    otherStartIndex = sdpStr.lastIndexOf('a=ssrc-group');\r\n    const otherEndIndex = sdpStr.indexOf('\\r\\n', otherStartIndex);\r\n    const sdpHead = sdpStr.slice(0, otherEndIndex);\r\n    const simStrTrimmed = simStr.trim();\r\n    const sdpTail = sdpStr.slice(otherEndIndex);\r\n\r\n    sdpStr = `${sdpHead}\\r\\n${simStrTrimmed}${sdpTail}`;\r\n\r\n    return new RTCSessionDescription({\r\n        type: localSdp.type,\r\n        sdp: sdpStr\r\n    });\r\n};\r\n\r\n/**\r\n * Will adjust audio and video media direction in the given SDP object to\r\n * reflect the current status of the {@link audioTransferActive} and\r\n * {@link videoTransferActive} flags.\r\n * @param {RTCSessionDescription} localDescription the WebRTC session description instance for\r\n * the local description.\r\n * @private\r\n */\r\nTraceablePeerConnection.prototype._adjustLocalMediaDirection = function(localDescription) {\r\n    const transformer = new SdpTransformWrap(localDescription.sdp);\r\n    let modifiedDirection = false;\r\n    const audioMedia = transformer.selectMedia(MediaType.AUDIO)?.[0];\r\n\r\n    if (audioMedia) {\r\n        const desiredAudioDirection = this.getDesiredMediaDirection(MediaType.AUDIO);\r\n\r\n        if (audioMedia.direction !== desiredAudioDirection) {\r\n            audioMedia.direction = desiredAudioDirection;\r\n            logger.info(`${this} Adjusted local audio direction to ${desiredAudioDirection}`);\r\n            modifiedDirection = true;\r\n        }\r\n    } else {\r\n        logger.warn(`${this} No \"audio\" media found in the local description`);\r\n    }\r\n\r\n    const videoMedia = transformer.selectMedia(MediaType.VIDEO)?.[0];\r\n\r\n    if (videoMedia) {\r\n        const desiredVideoDirection = this.getDesiredMediaDirection(MediaType.VIDEO);\r\n\r\n        if (videoMedia.direction !== desiredVideoDirection) {\r\n            videoMedia.direction = desiredVideoDirection;\r\n            logger.info(`${this} Adjusted local video direction to ${desiredVideoDirection}`);\r\n            modifiedDirection = true;\r\n        }\r\n    } else {\r\n        logger.warn(`${this} No \"video\" media found in the local description`);\r\n    }\r\n\r\n    if (modifiedDirection) {\r\n        return new RTCSessionDescription({\r\n            type: localDescription.type,\r\n            sdp: transformer.toRawSDP()\r\n        });\r\n    }\r\n\r\n    return localDescription;\r\n};\r\n\r\n/**\r\n * Adjusts the media direction on the remote description based on availability of local and remote sources in a p2p\r\n * media connection.\r\n *\r\n * @param {RTCSessionDescription} remoteDescription the WebRTC session description instance for the remote description.\r\n * @returns the transformed remoteDescription.\r\n * @private\r\n */\r\nTraceablePeerConnection.prototype._adjustRemoteMediaDirection = function(remoteDescription) {\r\n    const transformer = new SdpTransformWrap(remoteDescription.sdp);\r\n\r\n    [ MediaType.AUDIO, MediaType.VIDEO ].forEach(mediaType => {\r\n        const media = transformer.selectMedia(mediaType);\r\n        const localSources = this.getLocalTracks(mediaType).length;\r\n        const remoteSources = this.getRemoteTracks(null, mediaType).length;\r\n\r\n        media.forEach((mLine, idx) => {\r\n            if (localSources && localSources === remoteSources) {\r\n                mLine.direction = MediaDirection.SENDRECV;\r\n            } else if (!localSources && !remoteSources) {\r\n                mLine.direction = MediaDirection.INACTIVE;\r\n            } else if (!localSources) {\r\n                mLine.direction = MediaDirection.SENDONLY;\r\n            } else if (!remoteSources) {\r\n                mLine.direction = MediaDirection.RECVONLY;\r\n\r\n            // When there are 2 local sources and 1 remote source, the first m-line should be set to 'sendrecv' while\r\n            // the second one needs to be set to 'recvonly'.\r\n            } else if (localSources > remoteSources) {\r\n                mLine.direction = idx ? MediaDirection.RECVONLY : MediaDirection.SENDRECV;\r\n\r\n            // When there are 2 remote sources and 1 local source, the first m-line should be set to 'sendrecv' while\r\n            // the second one needs to be set to 'sendonly'.\r\n            } else {\r\n                mLine.direction = idx ? MediaDirection.SENDONLY : MediaDirection.SENDRECV;\r\n            }\r\n        });\r\n    });\r\n\r\n    return new RTCSessionDescription({\r\n        type: remoteDescription.type,\r\n        sdp: transformer.toRawSDP()\r\n    });\r\n};\r\n\r\n/**\r\n * Munges the stereo flag as well as the opusMaxAverageBitrate in the SDP, based\r\n * on values set through config.js, if present.\r\n *\r\n * @param {RTCSessionDescription} description that needs to be munged.\r\n * @returns {RTCSessionDescription} the munged description.\r\n */\r\nTraceablePeerConnection.prototype._mungeOpus = function(description) {\r\n    const { audioQuality } = this.options;\r\n\r\n    if (!audioQuality?.enableOpusDtx && !audioQuality?.stereo && !audioQuality?.opusMaxAverageBitrate) {\r\n        return description;\r\n    }\r\n\r\n    const parsedSdp = transform.parse(description.sdp);\r\n    const mLines = parsedSdp.media;\r\n\r\n    for (const mLine of mLines) {\r\n        if (mLine.type === 'audio') {\r\n            const { payload } = mLine.rtp.find(protocol => protocol.codec === CodecMimeType.OPUS);\r\n\r\n            if (!payload) {\r\n                // eslint-disable-next-line no-continue\r\n                continue;\r\n            }\r\n\r\n            let fmtpOpus = mLine.fmtp.find(protocol => protocol.payload === payload);\r\n\r\n            if (!fmtpOpus) {\r\n                fmtpOpus = {\r\n                    payload,\r\n                    config: ''\r\n                };\r\n            }\r\n\r\n            const fmtpConfig = transform.parseParams(fmtpOpus.config);\r\n            let sdpChanged = false;\r\n\r\n            if (audioQuality?.stereo) {\r\n                fmtpConfig.stereo = 1;\r\n                sdpChanged = true;\r\n            }\r\n\r\n            if (audioQuality?.opusMaxAverageBitrate) {\r\n                fmtpConfig.maxaveragebitrate = audioQuality.opusMaxAverageBitrate;\r\n                sdpChanged = true;\r\n            }\r\n\r\n            // On Firefox, the OpusDtx enablement has no effect\r\n            if (!browser.isFirefox() && audioQuality?.enableOpusDtx) {\r\n                fmtpConfig.usedtx = 1;\r\n                sdpChanged = true;\r\n            }\r\n\r\n            if (!sdpChanged) {\r\n                // eslint-disable-next-line no-continue\r\n                continue;\r\n            }\r\n\r\n            let mungedConfig = '';\r\n\r\n            for (const key of Object.keys(fmtpConfig)) {\r\n                mungedConfig += `${key}=${fmtpConfig[key]}; `;\r\n            }\r\n\r\n            fmtpOpus.config = mungedConfig.trim();\r\n        }\r\n    }\r\n\r\n    return new RTCSessionDescription({\r\n        type: description.type,\r\n        sdp: transform.write(parsedSdp)\r\n    });\r\n};\r\n\r\n/**\r\n * Munges the SDP to set all directions to inactive and drop all ssrc and ssrc-groups.\r\n *\r\n * @param {RTCSessionDescription} description that needs to be munged.\r\n * @returns {RTCSessionDescription} the munged description.\r\n */\r\nTraceablePeerConnection.prototype._mungeInactive = function(description) {\r\n    const parsedSdp = transform.parse(description.sdp);\r\n    const mLines = parsedSdp.media;\r\n\r\n    for (const mLine of mLines) {\r\n        mLine.direction = MediaDirection.INACTIVE;\r\n        mLine.ssrcs = undefined;\r\n        mLine.ssrcGroups = undefined;\r\n    }\r\n\r\n    return new RTCSessionDescription({\r\n        type: description.type,\r\n        sdp: transform.write(parsedSdp)\r\n    });\r\n};\r\n\r\n/**\r\n * Sets up the _dtlsTransport object and initializes callbacks for it.\r\n */\r\nTraceablePeerConnection.prototype._initializeDtlsTransport = function() {\r\n    // We are assuming here that we only have one bundled transport here\r\n    if (!this.peerconnection.getSenders || this._dtlsTransport) {\r\n        return;\r\n    }\r\n\r\n    const senders = this.peerconnection.getSenders();\r\n\r\n    if (senders.length !== 0 && senders[0].transport) {\r\n        this._dtlsTransport = senders[0].transport;\r\n\r\n        this._dtlsTransport.onerror = error => {\r\n            logger.error(`${this} DtlsTransport error: ${error}`);\r\n        };\r\n\r\n        this._dtlsTransport.onstatechange = () => {\r\n            this.trace('dtlsTransport.onstatechange', this._dtlsTransport.state);\r\n        };\r\n    }\r\n};\r\n\r\n/**\r\n * Sets the max bitrates on the video m-lines when VP9 is the selected codec.\r\n *\r\n * @param {RTCSessionDescription} description - The local description that needs to be munged.\r\n * @param {boolean} isLocalSdp - Whether the max bitrate (via b=AS line in SDP) is set on local SDP.\r\n * @returns RTCSessionDescription\r\n */\r\nTraceablePeerConnection.prototype._setVp9MaxBitrates = function(description, isLocalSdp = false) {\r\n    if (!this.codecPreference) {\r\n        return description;\r\n    }\r\n\r\n    const parsedSdp = transform.parse(description.sdp);\r\n\r\n    // Find all the m-lines associated with the local sources.\r\n    const direction = isLocalSdp ? MediaDirection.RECVONLY : MediaDirection.SENDONLY;\r\n    const mLines = parsedSdp.media.filter(m => m.type === MediaType.VIDEO && m.direction !== direction);\r\n\r\n    for (const mLine of mLines) {\r\n        if (this.codecPreference.mimeType === CodecMimeType.VP9) {\r\n            const bitrates = this.tpcUtils.videoBitrates.VP9 || this.tpcUtils.videoBitrates;\r\n            const hdBitrate = bitrates.high ? bitrates.high : HD_BITRATE;\r\n            const mid = mLine.mid;\r\n            const isSharingScreen = FeatureFlags.isMultiStreamSendSupportEnabled()\r\n                ? mid === this._getDesktopTrackMid()\r\n                : this._isSharingScreen();\r\n            const limit = Math.floor((isSharingScreen ? HD_BITRATE : hdBitrate) / 1000);\r\n\r\n            // Use only the HD bitrate for now as there is no API available yet for configuring\r\n            // the bitrates on the individual SVC layers.\r\n            mLine.bandwidth = [ {\r\n                type: 'AS',\r\n                limit\r\n            } ];\r\n        } else {\r\n            // Clear the bandwidth limit in SDP when VP9 is no longer the preferred codec.\r\n            // This is needed on react native clients as react-native-webrtc returns the\r\n            // SDP that the application passed instead of returning the SDP off the native side.\r\n            // This line automatically gets cleared on web on every renegotiation.\r\n            mLine.bandwidth = undefined;\r\n        }\r\n    }\r\n\r\n    return new RTCSessionDescription({\r\n        type: description.type,\r\n        sdp: transform.write(parsedSdp)\r\n    });\r\n};\r\n\r\n/**\r\n * Configures the stream encodings depending on the video type and the bitrates configured.\r\n *\r\n * @param {JitsiLocalTrack} - The local track for which the sender encodings have to configured.\r\n * @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.\r\n */\r\nTraceablePeerConnection.prototype.configureSenderVideoEncodings = function(localVideoTrack = null) {\r\n    if (localVideoTrack) {\r\n        return this.setSenderVideoConstraints(\r\n            this._senderMaxHeights.get(localVideoTrack.getSourceName()),\r\n            localVideoTrack);\r\n    }\r\n    const promises = [];\r\n\r\n    for (const track of this.getLocalVideoTracks()) {\r\n        promises.push(this.setSenderVideoConstraints(this._senderMaxHeights.get(track.getSourceName()), track));\r\n    }\r\n\r\n    return Promise.allSettled(promises);\r\n};\r\n\r\nTraceablePeerConnection.prototype.setLocalDescription = function(description) {\r\n    let localDescription = description;\r\n\r\n    this.trace('setLocalDescription::preTransform', dumpSDP(localDescription));\r\n\r\n    // Munge stereo flag and opusMaxAverageBitrate based on config.js\r\n    localDescription = this._mungeOpus(localDescription);\r\n\r\n    if (!this._usesUnifiedPlan) {\r\n        localDescription = this._adjustLocalMediaDirection(localDescription);\r\n        localDescription = this._ensureSimulcastGroupIsLast(localDescription);\r\n    }\r\n\r\n    // Munge the order of the codecs based on the preferences set through config.js.\r\n    localDescription = this._mungeCodecOrder(localDescription);\r\n    localDescription = this._setVp9MaxBitrates(localDescription, true);\r\n\r\n    this.trace('setLocalDescription::postTransform', dumpSDP(localDescription));\r\n\r\n    return new Promise((resolve, reject) => {\r\n        this.peerconnection.setLocalDescription(localDescription)\r\n            .then(() => {\r\n                this.trace('setLocalDescriptionOnSuccess');\r\n                const localUfrag = SDPUtil.getUfrag(localDescription.sdp);\r\n\r\n                if (localUfrag !== this.localUfrag) {\r\n                    this.localUfrag = localUfrag;\r\n                    this.eventEmitter.emit(RTCEvents.LOCAL_UFRAG_CHANGED, this, localUfrag);\r\n                }\r\n\r\n                this._initializeDtlsTransport();\r\n\r\n                resolve();\r\n            }, err => {\r\n                this.trace('setLocalDescriptionOnFailure', err);\r\n                this.eventEmitter.emit(RTCEvents.SET_LOCAL_DESCRIPTION_FAILED, err, this);\r\n                reject(err);\r\n            });\r\n    });\r\n};\r\n\r\n/**\r\n * Enables/disables audio media transmission on this peer connection. When\r\n * disabled the SDP audio media direction in the local SDP will be adjusted to\r\n * 'inactive' which means that no data will be sent nor accepted, but\r\n * the connection should be kept alive.\r\n * @param {boolean} active <tt>true</tt> to enable audio media transmission or\r\n * <tt>false</tt> to disable. If the value is not a boolean the call will have\r\n * no effect.\r\n * @return {boolean} <tt>true</tt> if the value has changed and sRD/sLD cycle\r\n * needs to be executed in order for the changes to take effect or\r\n * <tt>false</tt> if the given value was the same as the previous one.\r\n * @public\r\n */\r\nTraceablePeerConnection.prototype.setAudioTransferActive = function(active) {\r\n    logger.debug(`${this} audio transfer active: ${active}`);\r\n    const changed = this.audioTransferActive !== active;\r\n\r\n    this.audioTransferActive = active;\r\n\r\n    if (this._usesUnifiedPlan) {\r\n        this.tpcUtils.setAudioTransferActive(active);\r\n\r\n        // false means no renegotiation up the chain which is not needed in the Unified mode\r\n        return false;\r\n    }\r\n\r\n    return changed;\r\n};\r\n\r\nTraceablePeerConnection.prototype.setRemoteDescription = function(description) {\r\n    let remoteDescription = description;\r\n\r\n    this.trace('setRemoteDescription::preTransform', dumpSDP(description));\r\n\r\n    // Munge stereo flag and opusMaxAverageBitrate based on config.js\r\n    remoteDescription = this._mungeOpus(remoteDescription);\r\n\r\n    if (this._usesUnifiedPlan) {\r\n        // Translate the SDP to Unified plan format first for the jvb case, p2p case will only have 2 m-lines.\r\n        if (!this.isP2P) {\r\n            const currentDescription = this.peerconnection.remoteDescription;\r\n\r\n            remoteDescription = this.interop.toUnifiedPlan(remoteDescription, currentDescription);\r\n            this.trace('setRemoteDescription::postTransform (Unified)', dumpSDP(remoteDescription));\r\n\r\n            if (FeatureFlags.isRunInLiteModeEnabled()) {\r\n                remoteDescription = this._mungeInactive(remoteDescription);\r\n            }\r\n        }\r\n        if (this.isSimulcastOn()) {\r\n            remoteDescription = this.tpcUtils.insertUnifiedPlanSimulcastReceive(remoteDescription);\r\n            this.trace('setRemoteDescription::postTransform (sim receive)', dumpSDP(remoteDescription));\r\n        }\r\n        remoteDescription = this.tpcUtils.ensureCorrectOrderOfSsrcs(remoteDescription);\r\n        this.trace('setRemoteDescription::postTransform (correct ssrc order)', dumpSDP(remoteDescription));\r\n    } else {\r\n        if (this.isSimulcastOn()) {\r\n            // Implode the simulcast ssrcs so that the remote sdp has only the first ssrc in the SIM group.\r\n            remoteDescription = this.simulcast.mungeRemoteDescription(\r\n                remoteDescription,\r\n                true /* add x-google-conference flag */);\r\n            this.trace('setRemoteDescription::postTransform (simulcast)', dumpSDP(remoteDescription));\r\n        }\r\n        remoteDescription = normalizePlanB(remoteDescription);\r\n    }\r\n\r\n    // Munge the order of the codecs based on the preferences set through config.js.\r\n    remoteDescription = this._mungeCodecOrder(remoteDescription);\r\n    remoteDescription = this._setVp9MaxBitrates(remoteDescription);\r\n    this.trace('setRemoteDescription::postTransform (munge codec order)', dumpSDP(remoteDescription));\r\n\r\n    return new Promise((resolve, reject) => {\r\n        this.peerconnection.setRemoteDescription(remoteDescription)\r\n            .then(() => {\r\n                this.trace('setRemoteDescriptionOnSuccess');\r\n                const remoteUfrag = SDPUtil.getUfrag(remoteDescription.sdp);\r\n\r\n                if (remoteUfrag !== this.remoteUfrag) {\r\n                    this.remoteUfrag = remoteUfrag;\r\n                    this.eventEmitter.emit(RTCEvents.REMOTE_UFRAG_CHANGED, this, remoteUfrag);\r\n                }\r\n\r\n                this._initializeDtlsTransport();\r\n\r\n                resolve();\r\n            }, err => {\r\n                this.trace('setRemoteDescriptionOnFailure', err);\r\n                this.eventEmitter.emit(RTCEvents.SET_REMOTE_DESCRIPTION_FAILED, err, this);\r\n                reject(err);\r\n            });\r\n    });\r\n};\r\n\r\n/**\r\n * Changes the resolution of the video stream that is sent to the peer based on the resolution requested by the peer\r\n * and user preference, sets the degradation preference on the sender based on the video type, configures the maximum\r\n * bitrates on the send stream.\r\n *\r\n * @param {number} frameHeight - The max frame height to be imposed on the outgoing video stream.\r\n * @param {JitsiLocalTrack} - The local track for which the sender constraints have to be applied.\r\n * @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.\r\n */\r\nTraceablePeerConnection.prototype.setSenderVideoConstraints = function(frameHeight, localVideoTrack) {\r\n    if (frameHeight < 0) {\r\n        throw new Error(`Invalid frameHeight: ${frameHeight}`);\r\n    }\r\n\r\n    // XXX: This is not yet supported on mobile.\r\n    if (browser.isReactNative()) {\r\n        return Promise.resolve();\r\n    }\r\n\r\n    const sourceName = localVideoTrack.getSourceName();\r\n\r\n    if (this._senderMaxHeights.get(sourceName) === frameHeight) {\r\n        return Promise.resolve();\r\n    }\r\n    this._senderMaxHeights.set(sourceName, frameHeight);\r\n\r\n    if (!localVideoTrack || localVideoTrack.isMuted()) {\r\n        return Promise.resolve();\r\n    }\r\n    const videoSender = this.findSenderForTrack(localVideoTrack.getTrack());\r\n\r\n    if (!videoSender) {\r\n        return Promise.resolve();\r\n    }\r\n    const parameters = videoSender.getParameters();\r\n\r\n    if (!parameters?.encodings?.length) {\r\n        return Promise.resolve();\r\n    }\r\n\r\n    const isSharingLowFpsScreen = localVideoTrack.getVideoType() === VideoType.DESKTOP && this._capScreenshareBitrate;\r\n\r\n    // Set the degradation preference.\r\n    const preference = isSharingLowFpsScreen\r\n        ? DEGRADATION_PREFERENCE_DESKTOP // Prefer resolution for low fps share.\r\n        : DEGRADATION_PREFERENCE_CAMERA; // Prefer frame-rate for high fps share and camera.\r\n\r\n    parameters.degradationPreference = preference;\r\n    logger.info(`${this} Setting degradation preference [preference=${preference},track=${localVideoTrack}`);\r\n\r\n    // Calculate the encodings active state based on the resolution requested by the bridge.\r\n    this.encodingsEnabledState = this.tpcUtils.calculateEncodingsActiveState(localVideoTrack, frameHeight);\r\n    const maxBitrates = this.tpcUtils.calculateEncodingsBitrates(localVideoTrack);\r\n    const videoType = localVideoTrack.getVideoType();\r\n\r\n    if (this.isSimulcastOn()) {\r\n        for (const encoding in parameters.encodings) {\r\n            if (parameters.encodings.hasOwnProperty(encoding)) {\r\n                parameters.encodings[encoding].active = this.encodingsEnabledState[encoding];\r\n\r\n                // Firefox doesn't follow the spec and lets application specify the degradation preference on the\r\n                // encodings.\r\n                browser.isFirefox() && (parameters.encodings[encoding].degradationPreference = preference);\r\n\r\n                if (this.getConfiguredVideoCodec() === CodecMimeType.VP8\r\n                    && (this.options?.videoQuality?.maxBitratesVideo\r\n                        || isSharingLowFpsScreen\r\n                        || this._usesUnifiedPlan)) {\r\n                    parameters.encodings[encoding].maxBitrate = maxBitrates[encoding];\r\n                }\r\n            }\r\n        }\r\n        this.tpcUtils.updateEncodingsResolution(parameters);\r\n\r\n    // For p2p and cases and where simulcast is explicitly disabled.\r\n    } else if (frameHeight > 0) {\r\n        let scaleFactor = HD_SCALE_FACTOR;\r\n\r\n        // Do not scale down encodings for desktop tracks for non-simulcast case.\r\n        if (videoType === VideoType.CAMERA && localVideoTrack.resolution > frameHeight) {\r\n            scaleFactor = Math.floor(localVideoTrack.resolution / frameHeight);\r\n        }\r\n\r\n        parameters.encodings[0].active = true;\r\n        parameters.encodings[0].scaleResolutionDownBy = scaleFactor;\r\n\r\n        // Firefox doesn't follow the spec and lets application specify the degradation preference on the encodings.\r\n        browser.isFirefox() && (parameters.encodings[0].degradationPreference = preference);\r\n\r\n        // Configure the bitrate.\r\n        if (this.getConfiguredVideoCodec() === CodecMimeType.VP8 && this.options?.videoQuality?.maxBitratesVideo) {\r\n            let bitrate = this.getTargetVideoBitrates()?.high;\r\n\r\n            if (videoType === VideoType.CAMERA) {\r\n                bitrate = this.tpcUtils.localStreamEncodingsConfig\r\n                    .find(layer => layer.scaleResolutionDownBy === scaleFactor)?.maxBitrate ?? bitrate;\r\n            }\r\n            parameters.encodings[0].maxBitrate = bitrate;\r\n        }\r\n    } else {\r\n        parameters.encodings[0].active = false;\r\n    }\r\n\r\n    logger.info(`${this} setting max height=${frameHeight},encodings=${JSON.stringify(parameters.encodings)}`);\r\n\r\n    return videoSender.setParameters(parameters).then(() => {\r\n        localVideoTrack.maxEnabledResolution = frameHeight;\r\n        this.eventEmitter.emit(RTCEvents.LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED, localVideoTrack);\r\n    });\r\n};\r\n\r\n/**\r\n * Enables/disables video media transmission on this peer connection. When\r\n * disabled the SDP video media direction in the local SDP will be adjusted to\r\n * 'inactive' which means that no data will be sent nor accepted, but\r\n * the connection should be kept alive.\r\n * @param {boolean} active <tt>true</tt> to enable video media transmission or\r\n * <tt>false</tt> to disable. If the value is not a boolean the call will have\r\n * no effect.\r\n * @return {boolean} <tt>true</tt> if the value has changed and sRD/sLD cycle\r\n * needs to be executed in order for the changes to take effect or\r\n * <tt>false</tt> if the given value was the same as the previous one.\r\n * @public\r\n */\r\nTraceablePeerConnection.prototype.setVideoTransferActive = function(active) {\r\n    logger.debug(`${this} video transfer active: ${active}`);\r\n    const changed = this.videoTransferActive !== active;\r\n\r\n    this.videoTransferActive = active;\r\n\r\n    if (this._usesUnifiedPlan) {\r\n        this.tpcUtils.setVideoTransferActive(active);\r\n\r\n        // false means no renegotiation up the chain which is not needed in the Unified mode\r\n        return false;\r\n    }\r\n\r\n    return changed;\r\n};\r\n\r\n/**\r\n * Sends DTMF tones if possible.\r\n *\r\n * @param {string} tones - The DTMF tones string as defined by {@code RTCDTMFSender.insertDTMF}, 'tones' argument.\r\n * @param {number} duration - The amount of time in milliseconds that each DTMF should last. It's 200ms by default.\r\n * @param {number} interToneGap - The length of time in miliseconds to wait between tones. It's 200ms by default.\r\n *\r\n * @returns {void}\r\n */\r\nTraceablePeerConnection.prototype.sendTones = function(tones, duration = 200, interToneGap = 200) {\r\n    if (!this._dtmfSender) {\r\n        if (this.peerconnection.getSenders) {\r\n            const rtpSender = this.peerconnection.getSenders().find(s => s.dtmf);\r\n\r\n            this._dtmfSender = rtpSender && rtpSender.dtmf;\r\n            this._dtmfSender && logger.info(`${this} initialized DTMFSender using getSenders`);\r\n        }\r\n\r\n        if (!this._dtmfSender) {\r\n            const localAudioTrack = Array.from(this.localTracks.values()).find(t => t.isAudioTrack());\r\n\r\n            if (this.peerconnection.createDTMFSender && localAudioTrack) {\r\n                this._dtmfSender = this.peerconnection.createDTMFSender(localAudioTrack.getTrack());\r\n            }\r\n            this._dtmfSender && logger.info(`${this} initialized DTMFSender using deprecated createDTMFSender`);\r\n        }\r\n\r\n        if (this._dtmfSender) {\r\n            this._dtmfSender.ontonechange = this._onToneChange.bind(this);\r\n        }\r\n    }\r\n\r\n    if (this._dtmfSender) {\r\n        if (this._dtmfSender.toneBuffer) {\r\n            this._dtmfTonesQueue.push({\r\n                tones,\r\n                duration,\r\n                interToneGap\r\n            });\r\n\r\n            return;\r\n        }\r\n\r\n        this._dtmfSender.insertDTMF(tones, duration, interToneGap);\r\n    } else {\r\n        logger.warn(`${this} sendTones - failed to select DTMFSender`);\r\n    }\r\n};\r\n\r\n/**\r\n * Callback ivoked by {@code this._dtmfSender} when it has finished playing\r\n * a single tone.\r\n *\r\n * @param {Object} event - The tonechange event which indicates what characters\r\n * are left to be played for the current tone.\r\n * @private\r\n * @returns {void}\r\n */\r\nTraceablePeerConnection.prototype._onToneChange = function(event) {\r\n    // An empty event.tone indicates the current tones have finished playing.\r\n    // Automatically start playing any queued tones on finish.\r\n    if (this._dtmfSender && event.tone === '' && this._dtmfTonesQueue.length) {\r\n        const { tones, duration, interToneGap } = this._dtmfTonesQueue.shift();\r\n\r\n        this._dtmfSender.insertDTMF(tones, duration, interToneGap);\r\n    }\r\n};\r\n\r\n/**\r\n * Makes the underlying TraceablePeerConnection generate new SSRC for\r\n * the recvonly video stream.\r\n */\r\nTraceablePeerConnection.prototype.generateRecvonlySsrc = function() {\r\n    const newSSRC = SDPUtil.generateSsrc();\r\n\r\n    logger.info(`${this} generated new recvonly SSRC=${newSSRC}`);\r\n    this.sdpConsistency.setPrimarySsrc(newSSRC);\r\n};\r\n\r\n/**\r\n * Makes the underlying TraceablePeerConnection forget the current primary video\r\n * SSRC.\r\n */\r\nTraceablePeerConnection.prototype.clearRecvonlySsrc = function() {\r\n    logger.info(`${this} Clearing primary video SSRC!`);\r\n    this.sdpConsistency.clearVideoSsrcCache();\r\n};\r\n\r\n/**\r\n * Closes underlying WebRTC PeerConnection instance and removes all remote\r\n * tracks by emitting {@link RTCEvents.REMOTE_TRACK_REMOVED} for each one of\r\n * them.\r\n */\r\nTraceablePeerConnection.prototype.close = function() {\r\n    this.trace('stop');\r\n\r\n    // Off SignalingEvents\r\n    this.signalingLayer.off(SignalingEvents.PEER_MUTED_CHANGED, this._peerMutedChanged);\r\n    this.signalingLayer.off(SignalingEvents.PEER_VIDEO_TYPE_CHANGED, this._peerVideoTypeChanged);\r\n    this._usesUnifiedPlan && this.peerconnection.removeEventListener('track', this.onTrack);\r\n\r\n    for (const peerTracks of this.remoteTracks.values()) {\r\n        for (const remoteTracks of peerTracks.values()) {\r\n            for (const remoteTrack of remoteTracks) {\r\n                this._removeRemoteTrack(remoteTrack);\r\n            }\r\n        }\r\n    }\r\n    this.remoteTracks.clear();\r\n\r\n    this._addedStreams = [];\r\n\r\n    this._dtmfSender = null;\r\n    this._dtmfTonesQueue = [];\r\n\r\n    if (!this.rtc._removePeerConnection(this)) {\r\n        logger.error(`${this} RTC._removePeerConnection returned false`);\r\n    }\r\n    if (this.statsinterval !== null) {\r\n        window.clearInterval(this.statsinterval);\r\n        this.statsinterval = null;\r\n    }\r\n    logger.info(`${this} Closing peerconnection`);\r\n    this.peerconnection.close();\r\n};\r\n\r\nTraceablePeerConnection.prototype.createAnswer = function(constraints) {\r\n    return this._createOfferOrAnswer(false /* answer */, constraints);\r\n};\r\n\r\nTraceablePeerConnection.prototype.createOffer = function(constraints) {\r\n    return this._createOfferOrAnswer(true /* offer */, constraints);\r\n};\r\n\r\nTraceablePeerConnection.prototype._createOfferOrAnswer = function(\r\n        isOffer,\r\n        constraints) {\r\n    const logName = isOffer ? 'Offer' : 'Answer';\r\n\r\n    this.trace(`create${logName}`, JSON.stringify(constraints, null, ' '));\r\n\r\n    const handleSuccess = (resultSdp, resolveFn, rejectFn) => {\r\n        try {\r\n            this.trace(\r\n                `create${logName}OnSuccess::preTransform`, dumpSDP(resultSdp));\r\n\r\n            if (!this._usesUnifiedPlan) {\r\n                // If there are no local video tracks, then a \"recvonly\"\r\n                // SSRC needs to be generated\r\n                if (!this.hasAnyTracksOfType(MediaType.VIDEO)\r\n                    && !this.sdpConsistency.hasPrimarySsrcCached()) {\r\n                    this.generateRecvonlySsrc();\r\n                }\r\n\r\n                // eslint-disable-next-line no-param-reassign\r\n                resultSdp = new RTCSessionDescription({\r\n                    type: resultSdp.type,\r\n                    sdp: this.sdpConsistency.makeVideoPrimarySsrcsConsistent(\r\n                        resultSdp.sdp)\r\n                });\r\n\r\n                this.trace(\r\n                    `create${logName}OnSuccess::postTransform `\r\n                         + '(make primary audio/video ssrcs consistent)',\r\n                    dumpSDP(resultSdp));\r\n            }\r\n\r\n            const localVideoTrack = this.getLocalVideoTracks()[0];\r\n\r\n            // Configure simulcast for camera tracks and for desktop tracks that need simulcast.\r\n            if (this.isSimulcastOn() && browser.usesSdpMungingForSimulcast()\r\n                && (localVideoTrack?.getVideoType() === VideoType.CAMERA\r\n                || this._usesUnifiedPlan)) {\r\n                // eslint-disable-next-line no-param-reassign\r\n                resultSdp = this.simulcast.mungeLocalDescription(resultSdp);\r\n                this.trace(`create${logName} OnSuccess::postTransform (simulcast)`, dumpSDP(resultSdp));\r\n            }\r\n\r\n            if (!this.options.disableRtx && browser.usesSdpMungingForSimulcast()) {\r\n                // eslint-disable-next-line no-param-reassign\r\n                resultSdp = new RTCSessionDescription({\r\n                    type: resultSdp.type,\r\n                    sdp: this.rtxModifier.modifyRtxSsrcs(resultSdp.sdp)\r\n                });\r\n\r\n                this.trace(\r\n                    `create${logName}`\r\n                         + 'OnSuccess::postTransform (rtx modifier)',\r\n                    dumpSDP(resultSdp));\r\n            }\r\n\r\n            const ssrcMap = this._extractSSRCMap(resultSdp);\r\n\r\n            this._processLocalSSRCsMap(ssrcMap);\r\n\r\n            resolveFn(resultSdp);\r\n        } catch (e) {\r\n            this.trace(`create${logName}OnError`, e);\r\n            this.trace(`create${logName}OnError`, dumpSDP(resultSdp));\r\n            logger.error(`${this} create${logName}OnError`, e, dumpSDP(resultSdp));\r\n\r\n            rejectFn(e);\r\n        }\r\n    };\r\n\r\n    const handleFailure = (err, rejectFn) => {\r\n        this.trace(`create${logName}OnFailure`, err);\r\n        const eventType\r\n            = isOffer\r\n                ? RTCEvents.CREATE_OFFER_FAILED\r\n                : RTCEvents.CREATE_ANSWER_FAILED;\r\n\r\n        this.eventEmitter.emit(eventType, err, this);\r\n\r\n        rejectFn(err);\r\n    };\r\n\r\n    // Set the codec preference before creating an offer or answer so that the generated SDP will have\r\n    // the correct preference order.\r\n    if (this._usesTransceiverCodecPreferences) {\r\n        const transceiver = this.peerconnection.getTransceivers()\r\n            .find(t => t.receiver && t.receiver?.track?.kind === MediaType.VIDEO);\r\n\r\n        if (transceiver) {\r\n            let capabilities = RTCRtpReceiver.getCapabilities(MediaType.VIDEO)?.codecs;\r\n            const mimeType = this.codecPreference?.mimeType;\r\n            const enable = this.codecPreference?.enable;\r\n\r\n            if (capabilities && mimeType && enable) {\r\n                // Move the desired codec (all variations of it as well) to the beginning of the list.\r\n                /* eslint-disable-next-line arrow-body-style */\r\n                capabilities.sort(caps => {\r\n                    return caps.mimeType.toLowerCase() === `${MediaType.VIDEO}/${mimeType}` ? -1 : 1;\r\n                });\r\n            } else if (capabilities && mimeType) {\r\n                capabilities = capabilities\r\n                    .filter(caps => caps.mimeType.toLowerCase() !== `${MediaType.VIDEO}/${mimeType}`);\r\n            }\r\n\r\n            // Disable ulpfec on Google Chrome and derivatives because\r\n            // https://bugs.chromium.org/p/chromium/issues/detail?id=1276427\r\n            if (browser.isChromiumBased()) {\r\n                capabilities = capabilities\r\n                    .filter(caps => caps.mimeType.toLowerCase() !== `${MediaType.VIDEO}/${CodecMimeType.ULPFEC}`);\r\n            }\r\n\r\n            try {\r\n                transceiver.setCodecPreferences(capabilities);\r\n            } catch (err) {\r\n                logger.warn(`${this} Setting codec[preference=${mimeType},enable=${enable}] failed`, err);\r\n            }\r\n        }\r\n    }\r\n\r\n    return new Promise((resolve, reject) => {\r\n        let oaPromise;\r\n\r\n        if (isOffer) {\r\n            oaPromise = this.peerconnection.createOffer(constraints);\r\n        } else {\r\n            oaPromise = this.peerconnection.createAnswer(constraints);\r\n        }\r\n\r\n        oaPromise\r\n            .then(\r\n                sdp => handleSuccess(sdp, resolve, reject),\r\n                error => handleFailure(error, reject));\r\n    });\r\n};\r\n\r\n/**\r\n * Extract primary SSRC from given {@link TrackSSRCInfo} object.\r\n * @param {TrackSSRCInfo} ssrcObj\r\n * @return {number|null} the primary SSRC or <tt>null</tt>\r\n */\r\nTraceablePeerConnection.prototype._extractPrimarySSRC = function(ssrcObj) {\r\n    if (ssrcObj && ssrcObj.groups && ssrcObj.groups.length) {\r\n        return ssrcObj.groups[0].ssrcs[0];\r\n    } else if (ssrcObj && ssrcObj.ssrcs && ssrcObj.ssrcs.length) {\r\n        return ssrcObj.ssrcs[0];\r\n    }\r\n\r\n    return null;\r\n};\r\n\r\n/**\r\n * Goes over the SSRC map extracted from the latest local description and tries\r\n * to match them with the local tracks (by MSID). Will update the values\r\n * currently stored in the {@link TraceablePeerConnection.localSSRCs} map.\r\n * @param {Map<string,TrackSSRCInfo>} ssrcMap\r\n * @private\r\n */\r\nTraceablePeerConnection.prototype._processLocalSSRCsMap = function(ssrcMap) {\r\n    for (const track of this.localTracks.values()) {\r\n        const sourceName = track.getSourceName();\r\n        const sourceIndex = getSourceIndexFromSourceName(sourceName);\r\n        const sourceIdentifier = this._usesUnifiedPlan\r\n            ? `${track.getType()}-${sourceIndex}`\r\n            : track.storedMSID;\r\n\r\n        if (ssrcMap.has(sourceIdentifier)) {\r\n            const newSSRC = ssrcMap.get(sourceIdentifier);\r\n\r\n            if (!newSSRC) {\r\n                logger.error(`${this} No SSRC found for stream=${sourceIdentifier}`);\r\n\r\n                return;\r\n            }\r\n            const oldSSRC = this.localSSRCs.get(track.rtcId);\r\n            const newSSRCNum = this._extractPrimarySSRC(newSSRC);\r\n            const oldSSRCNum = this._extractPrimarySSRC(oldSSRC);\r\n\r\n            // eslint-disable-next-line no-negated-condition\r\n            if (newSSRCNum !== oldSSRCNum) {\r\n                oldSSRCNum && logger.error(`${this} Overwriting SSRC for track=${track}] with ssrc=${newSSRC}`);\r\n                this.localSSRCs.set(track.rtcId, newSSRC);\r\n                this.eventEmitter.emit(RTCEvents.LOCAL_TRACK_SSRC_UPDATED, track, newSSRCNum);\r\n            }\r\n        } else if (!track.isVideoTrack() && !track.isMuted()) {\r\n            // It is normal to find no SSRCs for a muted video track in\r\n            // the local SDP as the recv-only SSRC is no longer munged in.\r\n            // So log the warning only if it's not a muted video track.\r\n            logger.warn(`${this} No SSRCs found in the local SDP for track=${track}, stream=${sourceIdentifier}`);\r\n        }\r\n    }\r\n};\r\n\r\n/**\r\n * Track the SSRCs seen so far.\r\n * @param {number} ssrc - SSRC.\r\n * @return {boolean} - Whether this is a new SSRC.\r\n */\r\nTraceablePeerConnection.prototype.addRemoteSsrc = function(ssrc) {\r\n    const existing = this.remoteSSRCs.has(ssrc);\r\n\r\n    if (!existing) {\r\n        this.remoteSSRCs.add(ssrc);\r\n    }\r\n\r\n    return !existing;\r\n};\r\n\r\nTraceablePeerConnection.prototype.addIceCandidate = function(candidate) {\r\n    this.trace('addIceCandidate', JSON.stringify({\r\n        candidate: candidate.candidate,\r\n        sdpMid: candidate.sdpMid,\r\n        sdpMLineIndex: candidate.sdpMLineIndex,\r\n        usernameFragment: candidate.usernameFragment\r\n    }, null, ' '));\r\n\r\n    return this.peerconnection.addIceCandidate(candidate);\r\n};\r\n\r\n/**\r\n * Returns the number of simulcast streams that are currently enabled on the peerconnection.\r\n *\r\n * @returns {number} The number of simulcast streams currently enabled or 1 when simulcast is disabled.\r\n */\r\nTraceablePeerConnection.prototype.getActiveSimulcastStreams = function() {\r\n    let activeStreams = 1;\r\n\r\n    if (this.isSimulcastOn() && this.encodingsEnabledState) {\r\n        activeStreams = this.encodingsEnabledState.filter(stream => Boolean(stream))?.length;\r\n    } else if (this.isSimulcastOn()) {\r\n        activeStreams = SIM_LAYER_RIDS.length;\r\n    }\r\n\r\n    return activeStreams;\r\n};\r\n\r\n/**\r\n * Obtains call-related stats from the peer connection.\r\n *\r\n * @returns {Promise<Object>} Promise which resolves with data providing statistics about\r\n * the peerconnection.\r\n */\r\nTraceablePeerConnection.prototype.getStats = function() {\r\n    return this.peerconnection.getStats();\r\n};\r\n\r\n/**\r\n * Generates and stores new SSRC info object for given local track.\r\n * The method should be called only for a video track being added to this TPC\r\n * in the muted state (given that the current browser uses this strategy).\r\n * @param {JitsiLocalTrack} track\r\n * @return {TPCSSRCInfo}\r\n */\r\nTraceablePeerConnection.prototype.generateNewStreamSSRCInfo = function(track) {\r\n    const rtcId = track.rtcId;\r\n    let ssrcInfo = this._getSSRC(rtcId);\r\n\r\n    if (ssrcInfo) {\r\n        logger.error(`${this} Overwriting local SSRCs for track id=${rtcId}`);\r\n    }\r\n\r\n    // Configure simulcast for camera tracks and desktop tracks that need simulcast.\r\n    if (this.isSimulcastOn()\r\n        && (track.getVideoType() === VideoType.CAMERA || !this.isSharingLowFpsScreen())) {\r\n        ssrcInfo = {\r\n            ssrcs: [],\r\n            groups: []\r\n        };\r\n        for (let i = 0; i < SIM_LAYER_RIDS.length; i++) {\r\n            ssrcInfo.ssrcs.push(SDPUtil.generateSsrc());\r\n        }\r\n        ssrcInfo.groups.push({\r\n            ssrcs: ssrcInfo.ssrcs.slice(),\r\n            semantics: 'SIM'\r\n        });\r\n    } else {\r\n        ssrcInfo = {\r\n            ssrcs: [ SDPUtil.generateSsrc() ],\r\n            groups: []\r\n        };\r\n    }\r\n    if (!this.options.disableRtx) {\r\n        // Specifically use a for loop here because we'll\r\n        //  be adding to the list we're iterating over, so we\r\n        //  only want to iterate through the items originally\r\n        //  on the list\r\n        const currNumSsrcs = ssrcInfo.ssrcs.length;\r\n\r\n        for (let i = 0; i < currNumSsrcs; ++i) {\r\n            const primarySsrc = ssrcInfo.ssrcs[i];\r\n            const rtxSsrc = SDPUtil.generateSsrc();\r\n\r\n            ssrcInfo.ssrcs.push(rtxSsrc);\r\n            ssrcInfo.groups.push({\r\n                ssrcs: [ primarySsrc, rtxSsrc ],\r\n                semantics: 'FID'\r\n            });\r\n        }\r\n    }\r\n    ssrcInfo.msid = track.storedMSID;\r\n    this.localSSRCs.set(rtcId, ssrcInfo);\r\n\r\n    return ssrcInfo;\r\n};\r\n\r\n/**\r\n * Returns if the peer connection uses Unified plan implementation.\r\n *\r\n * @returns {boolean} True if the pc uses Unified plan, false otherwise.\r\n */\r\nTraceablePeerConnection.prototype.usesUnifiedPlan = function() {\r\n    return this._usesUnifiedPlan;\r\n};\r\n\r\n/**\r\n * Creates a text representation of this <tt>TraceablePeerConnection</tt>\r\n * instance.\r\n * @return {string}\r\n */\r\nTraceablePeerConnection.prototype.toString = function() {\r\n    return `TPC[id=${this.id},type=${this.isP2P ? 'P2P' : 'JVB'}]`;\r\n};\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\nimport BridgeVideoType from '../../service/RTC/BridgeVideoType';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport RTCEvents from '../../service/RTC/RTCEvents';\r\nimport browser from '../browser';\r\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\r\nimport Listenable from '../util/Listenable';\r\nimport { safeCounterIncrement } from '../util/MathUtil';\r\n\r\nimport BridgeChannel from './BridgeChannel';\r\nimport JitsiLocalTrack from './JitsiLocalTrack';\r\nimport RTCUtils from './RTCUtils';\r\nimport TraceablePeerConnection from './TraceablePeerConnection';\r\n\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * The counter used to generated id numbers assigned to peer connections\r\n * @type {number}\r\n */\r\nlet peerConnectionIdCounter = 0;\r\n\r\n/**\r\n * The counter used to generate id number for the local\r\n * <code>MediaStreamTrack</code>s.\r\n * @type {number}\r\n */\r\nlet rtcTrackIdCounter = 0;\r\n\r\n/**\r\n * Creates {@code JitsiLocalTrack} instances from the passed in meta information\r\n * about MedieaTracks.\r\n *\r\n * @param {Object[]} mediaStreamMetaData - An array of meta information with\r\n * MediaTrack instances. Each can look like:\r\n * {{\r\n *     stream: MediaStream instance that holds a track with audio or video,\r\n *     track: MediaTrack within the MediaStream,\r\n *     videoType: \"camera\" or \"desktop\" or falsy,\r\n *     sourceId: ID of the desktopsharing source,\r\n *     sourceType: The desktopsharing source type,\r\n *     effects: Array of effect types\r\n * }}\r\n */\r\nfunction _createLocalTracks(mediaStreamMetaData = []) {\r\n    return mediaStreamMetaData.map(metaData => {\r\n        const {\r\n            sourceId,\r\n            sourceType,\r\n            stream,\r\n            track,\r\n            videoType,\r\n            effects\r\n        } = metaData;\r\n\r\n        const { deviceId, facingMode } = track.getSettings();\r\n\r\n        // FIXME Move rtcTrackIdCounter to a static method in JitsiLocalTrack\r\n        // so RTC does not need to handle ID management. This move would be\r\n        // safer to do once the old createLocalTracks is removed.\r\n        rtcTrackIdCounter = safeCounterIncrement(rtcTrackIdCounter);\r\n\r\n        return new JitsiLocalTrack({\r\n            deviceId,\r\n            facingMode,\r\n            mediaType: track.kind,\r\n            rtcId: rtcTrackIdCounter,\r\n            sourceId,\r\n            sourceType,\r\n            stream,\r\n            track,\r\n            videoType: videoType || null,\r\n            effects\r\n        });\r\n    });\r\n}\r\n\r\n/**\r\n *\r\n */\r\nexport default class RTC extends Listenable {\r\n    /**\r\n     *\r\n     * @param conference\r\n     * @param options\r\n     */\r\n    constructor(conference, options = {}) {\r\n        super();\r\n        this.conference = conference;\r\n\r\n        /**\r\n         * A map of active <tt>TraceablePeerConnection</tt>.\r\n         * @type {Map.<number, TraceablePeerConnection>}\r\n         */\r\n        this.peerConnections = new Map();\r\n\r\n        this.localTracks = [];\r\n\r\n        this.options = options;\r\n\r\n        // BridgeChannel instance.\r\n        // @private\r\n        // @type {BridgeChannel}\r\n        this._channel = null;\r\n\r\n        /**\r\n         * The value specified to the last invocation of setLastN before the\r\n         * channel completed opening. If non-null, the value will be sent\r\n         * through a channel (once) as soon as it opens and will then be\r\n         * discarded.\r\n         * @private\r\n         * @type {number}\r\n         */\r\n        this._lastN = undefined;\r\n\r\n        /**\r\n         * Defines the last N endpoints list. It can be null or an array once\r\n         * initialised with a channel last N event.\r\n         * @type {Array<string>|null}\r\n         * @private\r\n         */\r\n        this._lastNEndpoints = null;\r\n\r\n        /**\r\n         * Defines the forwarded sources list. It can be null or an array once initialised with a channel forwarded\r\n         * sources event.\r\n         *\r\n         * @type {Array<string>|null}\r\n         * @private\r\n         */\r\n        this._forwardedSources = null;\r\n\r\n        /**\r\n         * The number representing the maximum video height the local client\r\n         * should receive from the bridge.\r\n         *\r\n         * @type {number|undefined}\r\n         * @private\r\n         */\r\n        this._maxFrameHeight = undefined;\r\n\r\n        /**\r\n         * The endpoint IDs of currently selected participants.\r\n         *\r\n         * @type {Array}\r\n         * @private\r\n         */\r\n        this._selectedEndpoints = null;\r\n\r\n        // The forwarded sources change listener.\r\n        this._forwardedSourcesChangeListener = this._onForwardedSourcesChanged.bind(this);\r\n\r\n        this._onDeviceListChanged = this._onDeviceListChanged.bind(this);\r\n        this._updateAudioOutputForAudioTracks\r\n            = this._updateAudioOutputForAudioTracks.bind(this);\r\n\r\n        /**\r\n         * The default video type assumed by the bridge.\r\n         * @deprecated this will go away with multiple streams support\r\n         * @type {BridgeVideoType}\r\n         * @private\r\n         */\r\n        this._videoType = BridgeVideoType.NONE;\r\n\r\n        // Switch audio output device on all remote audio tracks. Local audio\r\n        // tracks handle this event by themselves.\r\n        if (RTCUtils.isDeviceChangeAvailable('output')) {\r\n            RTCUtils.addListener(\r\n                RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\r\n                this._updateAudioOutputForAudioTracks\r\n            );\r\n\r\n            RTCUtils.addListener(\r\n                RTCEvents.DEVICE_LIST_CHANGED,\r\n                this._onDeviceListChanged\r\n            );\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Removes any listeners and stored state from this {@code RTC} instance.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    destroy() {\r\n        RTCUtils.removeListener(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED, this._updateAudioOutputForAudioTracks);\r\n        RTCUtils.removeListener(RTCEvents.DEVICE_LIST_CHANGED, this._onDeviceListChanged);\r\n\r\n        if (this._channelOpenListener) {\r\n            this.removeListener(RTCEvents.DATA_CHANNEL_OPEN, this._channelOpenListener);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Exposes the private helper for converting a WebRTC MediaStream to a\r\n     * JitsiLocalTrack.\r\n     *\r\n     * @param {Array<Object>} tracksInfo\r\n     * @returns {Array<JitsiLocalTrack>}\r\n     */\r\n    static createLocalTracks(tracksInfo) {\r\n        return _createLocalTracks(tracksInfo);\r\n    }\r\n\r\n    /**\r\n     * Creates the local MediaStreams.\r\n     * @param {object} [options] Optional parameters.\r\n     * @param {Array=} options.devices The devices that will be requested.\r\n     * @param {string=} options.resolution Resolution constraints.\r\n     * @param {string=} options.cameraDeviceId\r\n     * @param {string=} options.micDeviceId\r\n     * @returns {*} Promise object that will receive the new JitsiTracks\r\n     */\r\n    static obtainAudioAndVideoPermissions(options) {\r\n        return RTCUtils.obtainAudioAndVideoPermissions(options)\r\n            .then(tracksInfo => _createLocalTracks(tracksInfo));\r\n    }\r\n\r\n    /**\r\n     * Initializes the bridge channel of this instance.\r\n     * At least one of both, peerconnection or wsUrl parameters, must be\r\n     * given.\r\n     * @param {RTCPeerConnection} [peerconnection] WebRTC peer connection\r\n     * instance.\r\n     * @param {string} [wsUrl] WebSocket URL.\r\n     */\r\n    initializeBridgeChannel(peerconnection, wsUrl) {\r\n        this._channel = new BridgeChannel(peerconnection, wsUrl, this.eventEmitter);\r\n\r\n        this._channelOpenListener = () => {\r\n            const logError = (error, msgType, value) => {\r\n                GlobalOnErrorHandler.callErrorHandler(error);\r\n                logger.error(`Cannot send ${msgType}(${JSON.stringify(value)}) endpoint message`, error);\r\n            };\r\n\r\n            // When the channel becomes available, tell the bridge about video selections so that it can do adaptive\r\n            // simulcast, we want the notification to trigger even if userJid is undefined, or null.\r\n            if (this._receiverVideoConstraints) {\r\n                try {\r\n                    this._channel.sendNewReceiverVideoConstraintsMessage(this._receiverVideoConstraints);\r\n                } catch (error) {\r\n                    logError(error, 'ReceiverVideoConstraints', this._receiverVideoConstraints);\r\n                }\r\n            }\r\n            if (this._selectedEndpoints) {\r\n                try {\r\n                    this._channel.sendSelectedEndpointsMessage(this._selectedEndpoints);\r\n                } catch (error) {\r\n                    logError(error, 'SelectedEndpointsChangedEvent', this._selectedEndpoints);\r\n                }\r\n            }\r\n            if (typeof this._maxFrameHeight !== 'undefined') {\r\n                try {\r\n                    this._channel.sendReceiverVideoConstraintMessage(this._maxFrameHeight);\r\n                } catch (error) {\r\n                    logError(error, 'ReceiverVideoConstraint', this._maxFrameHeight);\r\n                }\r\n            }\r\n            if (typeof this._lastN !== 'undefined' && this._lastN !== -1) {\r\n                try {\r\n                    this._channel.sendSetLastNMessage(this._lastN);\r\n                } catch (error) {\r\n                    logError(error, 'LastNChangedEvent', this._lastN);\r\n                }\r\n            }\r\n        };\r\n        this.addListener(RTCEvents.DATA_CHANNEL_OPEN, this._channelOpenListener);\r\n\r\n        // Add forwarded sources change listener.\r\n        this.addListener(RTCEvents.FORWARDED_SOURCES_CHANGED, this._forwardedSourcesChangeListener);\r\n    }\r\n\r\n    /**\r\n     * Callback invoked when the list of known audio and video devices has\r\n     * been updated. Attempts to update the known available audio output\r\n     * devices.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onDeviceListChanged() {\r\n        this._updateAudioOutputForAudioTracks(RTCUtils.getAudioOutputDevice());\r\n    }\r\n\r\n    /**\r\n     * Receives events when forwarded sources had changed.\r\n     *\r\n     * @param {array} forwardedSources The new forwarded sources.\r\n     * @private\r\n     */\r\n    _onForwardedSourcesChanged(forwardedSources = []) {\r\n        const oldForwardedSources = this._forwardedSources || [];\r\n        let leavingForwardedSources = [];\r\n        let enteringForwardedSources = [];\r\n        const timestamp = Date.now();\r\n\r\n        this._forwardedSources = forwardedSources;\r\n\r\n        leavingForwardedSources = oldForwardedSources.filter(sourceName => !this.isInForwardedSources(sourceName));\r\n\r\n        enteringForwardedSources = forwardedSources.filter(\r\n            sourceName => oldForwardedSources.indexOf(sourceName) === -1);\r\n\r\n        logger.debug(`Fowarded sources changed leaving=${leavingForwardedSources}, entering=`\r\n            + `${enteringForwardedSources} at ${timestamp}`);\r\n        this.conference.eventEmitter.emit(\r\n            JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED,\r\n            leavingForwardedSources,\r\n            enteringForwardedSources,\r\n            timestamp);\r\n    }\r\n\r\n    /**\r\n     * Should be called when current media session ends and after the\r\n     * PeerConnection has been closed using PeerConnection.close() method.\r\n     */\r\n    onCallEnded() {\r\n        if (this._channel) {\r\n            // The BridgeChannel is not explicitly closed as the PeerConnection\r\n            // is closed on call ended which triggers datachannel onclose\r\n            // events. If using a WebSocket, the channel must be closed since\r\n            // it is not managed by the PeerConnection.\r\n            // The reference is cleared to disable any logic related to the\r\n            // channel.\r\n            if (this._channel && this._channel.mode === 'websocket') {\r\n                this._channel.close();\r\n            }\r\n\r\n            this._channel = null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets the capture frame rate to be used for desktop tracks.\r\n     *\r\n     * @param {number} maxFps framerate to be used for desktop track capture.\r\n     */\r\n    setDesktopSharingFrameRate(maxFps) {\r\n        RTCUtils.setDesktopSharingFrameRate(maxFps);\r\n    }\r\n\r\n    /**\r\n     * Sets the receiver video constraints that determine how bitrate is allocated to each of the video streams\r\n     * requested from the bridge. The constraints are cached and sent through the bridge channel once the channel\r\n     * is established.\r\n     * @param {*} constraints\r\n     */\r\n    setNewReceiverVideoConstraints(constraints) {\r\n        this._receiverVideoConstraints = constraints;\r\n\r\n        if (this._channel && this._channel.isOpen()) {\r\n            this._channel.sendNewReceiverVideoConstraintsMessage(constraints);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets the maximum video size the local participant should receive from\r\n     * remote participants. Will cache the value and send it through the channel\r\n     * once it is created.\r\n     *\r\n     * @param {number} maxFrameHeightPixels the maximum frame height, in pixels,\r\n     * this receiver is willing to receive.\r\n     * @returns {void}\r\n     */\r\n    setReceiverVideoConstraint(maxFrameHeight) {\r\n        this._maxFrameHeight = maxFrameHeight;\r\n\r\n        if (this._channel && this._channel.isOpen()) {\r\n            this._channel.sendReceiverVideoConstraintMessage(maxFrameHeight);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets the video type and availability for the local video source.\r\n     *\r\n     * @param {string} videoType 'camera' for camera, 'desktop' for screenshare and\r\n     * 'none' for when local video source is muted or removed from the peerconnection.\r\n     * @returns {void}\r\n     */\r\n    setVideoType(videoType) {\r\n        if (this._videoType !== videoType) {\r\n            this._videoType = videoType;\r\n\r\n            if (this._channel && this._channel.isOpen()) {\r\n                this._channel.sendVideoTypeMessage(videoType);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sends the track's  video type to the JVB.\r\n     * @param {SourceName} sourceName - the track's source name.\r\n     * @param {BridgeVideoType} videoType - the track's video type.\r\n     */\r\n    sendSourceVideoType(sourceName, videoType) {\r\n        if (this._channel && this._channel.isOpen()) {\r\n            this._channel.sendSourceVideoTypeMessage(sourceName, videoType);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Elects the participants with the given ids to be the selected\r\n     * participants in order to always receive video for this participant (even\r\n     * when last n is enabled). If there is no channel we store it and send it\r\n     * through the channel once it is created.\r\n     *\r\n     * @param {Array<string>} ids - The user ids.\r\n     * @throws NetworkError or InvalidStateError or Error if the operation\r\n     * fails.\r\n     * @returns {void}\r\n     */\r\n    selectEndpoints(ids) {\r\n        this._selectedEndpoints = ids;\r\n\r\n        if (this._channel && this._channel.isOpen()) {\r\n            this._channel.sendSelectedEndpointsMessage(ids);\r\n        }\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param eventType\r\n     * @param listener\r\n     */\r\n    static addListener(eventType, listener) {\r\n        RTCUtils.addListener(eventType, listener);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param eventType\r\n     * @param listener\r\n     */\r\n    static removeListener(eventType, listener) {\r\n        RTCUtils.removeListener(eventType, listener);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param options\r\n     */\r\n    static init(options = {}) {\r\n        this.options = options;\r\n\r\n        return RTCUtils.init(this.options);\r\n    }\r\n\r\n    /* eslint-disable max-params */\r\n\r\n    /**\r\n     * Creates new <tt>TraceablePeerConnection</tt>\r\n     * @param {SignalingLayer} signaling The signaling layer that will provide information about the media or\r\n     * participants which is not carried over SDP.\r\n     * @param {object} pcConfig The {@code RTCConfiguration} to use for the WebRTC peer connection.\r\n     * @param {boolean} isP2P Indicates whether or not the new TPC will be used in a peer to peer type of session.\r\n     * @param {object} options The config options.\r\n     * @param {boolean} options.enableInsertableStreams - Set to true when the insertable streams constraints is to be\r\n     * enabled on the PeerConnection.\r\n     * @param {boolean} options.disableSimulcast If set to 'true' will disable the simulcast.\r\n     * @param {boolean} options.disableRtx If set to 'true' will disable the RTX.\r\n     * @param {boolean} options.startSilent If set to 'true' no audio will be sent or received.\r\n     * @return {TraceablePeerConnection}\r\n     */\r\n    createPeerConnection(signaling, pcConfig, isP2P, options) {\r\n        const pcConstraints = JSON.parse(JSON.stringify(RTCUtils.pcConstraints));\r\n\r\n        if (options.enableInsertableStreams) {\r\n            logger.debug('E2EE - setting insertable streams constraints');\r\n            pcConfig.encodedInsertableStreams = true;\r\n        }\r\n\r\n        const supportsSdpSemantics = browser.isReactNative()\r\n            || (browser.isChromiumBased() && !options.usesUnifiedPlan);\r\n\r\n        if (supportsSdpSemantics) {\r\n            logger.debug('WebRTC application is running in plan-b mode');\r\n            pcConfig.sdpSemantics = 'plan-b';\r\n        }\r\n\r\n        if (options.forceTurnRelay) {\r\n            pcConfig.iceTransportPolicy = 'relay';\r\n        }\r\n\r\n        // Set the RTCBundlePolicy to max-bundle so that only one set of ice candidates is generated.\r\n        // The default policy generates separate ice candidates for audio and video connections.\r\n        // This change is necessary for Unified plan to work properly on Chrome and Safari.\r\n        pcConfig.bundlePolicy = 'max-bundle';\r\n\r\n        peerConnectionIdCounter = safeCounterIncrement(peerConnectionIdCounter);\r\n\r\n        const newConnection\r\n            = new TraceablePeerConnection(\r\n                this,\r\n                peerConnectionIdCounter,\r\n                signaling,\r\n                pcConfig, pcConstraints,\r\n                isP2P, options);\r\n\r\n        this.peerConnections.set(newConnection.id, newConnection);\r\n\r\n        return newConnection;\r\n    }\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * Removed given peer connection from this RTC module instance.\r\n     * @param {TraceablePeerConnection} traceablePeerConnection\r\n     * @return {boolean} <tt>true</tt> if the given peer connection was removed\r\n     * successfully or <tt>false</tt> if there was no peer connection mapped in\r\n     * this RTC instance.\r\n     */\r\n    _removePeerConnection(traceablePeerConnection) {\r\n        const id = traceablePeerConnection.id;\r\n\r\n        if (this.peerConnections.has(id)) {\r\n            // NOTE Remote tracks are not removed here.\r\n            this.peerConnections.delete(id);\r\n\r\n            return true;\r\n        }\r\n\r\n        return false;\r\n\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param track\r\n     */\r\n    addLocalTrack(track) {\r\n        if (!track) {\r\n            throw new Error('track must not be null nor undefined');\r\n        }\r\n\r\n        this.localTracks.push(track);\r\n\r\n        track.conference = this.conference;\r\n    }\r\n\r\n    /**\r\n     * Get forwarded sources list.\r\n     * @returns {Array<string>|null}\r\n     */\r\n    getForwardedSources() {\r\n        return this._forwardedSources;\r\n    }\r\n\r\n    /**\r\n     * Get local video track.\r\n     * @returns {JitsiLocalTrack|undefined}\r\n     */\r\n    getLocalVideoTrack() {\r\n        const localVideo = this.getLocalTracks(MediaType.VIDEO);\r\n\r\n\r\n        return localVideo.length ? localVideo[0] : undefined;\r\n    }\r\n\r\n    /**\r\n     * Returns all the local video tracks.\r\n     * @returns {Array<JitsiLocalTrack>}\r\n     */\r\n    getLocalVideoTracks() {\r\n        return this.getLocalTracks(MediaType.VIDEO);\r\n    }\r\n\r\n    /**\r\n     * Get local audio track.\r\n     * @returns {JitsiLocalTrack|undefined}\r\n     */\r\n    getLocalAudioTrack() {\r\n        const localAudio = this.getLocalTracks(MediaType.AUDIO);\r\n\r\n\r\n        return localAudio.length ? localAudio[0] : undefined;\r\n    }\r\n\r\n    /**\r\n     * Returns the endpoint id for the local user.\r\n     * @returns {string}\r\n     */\r\n    getLocalEndpointId() {\r\n        return this.conference.myUserId();\r\n    }\r\n\r\n    /**\r\n     * Returns the local tracks of the given media type, or all local tracks if\r\n     * no specific type is given.\r\n     * @param {MediaType} [mediaType] Optional media type filter.\r\n     * (audio or video).\r\n     */\r\n    getLocalTracks(mediaType) {\r\n        let tracks = this.localTracks.slice();\r\n\r\n        if (mediaType !== undefined) {\r\n            tracks = tracks.filter(\r\n                track => track.getType() === mediaType);\r\n        }\r\n\r\n        return tracks;\r\n    }\r\n\r\n    /**\r\n     * Obtains all remote tracks currently known to this RTC module instance.\r\n     * @param {MediaType} [mediaType] The remote tracks will be filtered\r\n     *      by their media type if this argument is specified.\r\n     * @return {Array<JitsiRemoteTrack>}\r\n     */\r\n    getRemoteTracks(mediaType) {\r\n        let remoteTracks = [];\r\n\r\n        for (const tpc of this.peerConnections.values()) {\r\n            const pcRemoteTracks = tpc.getRemoteTracks(undefined, mediaType);\r\n\r\n            if (pcRemoteTracks) {\r\n                remoteTracks = remoteTracks.concat(pcRemoteTracks);\r\n            }\r\n        }\r\n\r\n        return remoteTracks;\r\n    }\r\n\r\n    /**\r\n     * Set mute for all local audio streams attached to the conference.\r\n     * @param value The mute value.\r\n     * @returns {Promise}\r\n     */\r\n    setAudioMute(value) {\r\n        const mutePromises = [];\r\n\r\n        this.getLocalTracks(MediaType.AUDIO).forEach(audioTrack => {\r\n            // this is a Promise\r\n            mutePromises.push(value ? audioTrack.mute() : audioTrack.unmute());\r\n        });\r\n\r\n        // We return a Promise from all Promises so we can wait for their\r\n        // execution.\r\n        return Promise.all(mutePromises);\r\n    }\r\n\r\n    /**\r\n    * Set mute for all local video streams attached to the conference.\r\n    * @param value The mute value.\r\n    * @returns {Promise}\r\n    */\r\n    setVideoMute(value) {\r\n        const mutePromises = [];\r\n\r\n        this.getLocalTracks(MediaType.VIDEO)\r\n            .forEach(videoTrack => {\r\n                // this is a Promise\r\n                mutePromises.push(value ? videoTrack.mute() : videoTrack.unmute());\r\n            });\r\n\r\n        // We return a Promise from all Promises so we can wait for their\r\n        // execution.\r\n        return Promise.all(mutePromises);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param track\r\n     */\r\n    removeLocalTrack(track) {\r\n        const pos = this.localTracks.indexOf(track);\r\n\r\n        if (pos === -1) {\r\n            return;\r\n        }\r\n\r\n        this.localTracks.splice(pos, 1);\r\n    }\r\n\r\n    /**\r\n     *\r\n     * @param elSelector\r\n     * @param stream\r\n     */\r\n    static attachMediaStream(elSelector, stream) {\r\n        return RTCUtils.attachMediaStream(elSelector, stream);\r\n    }\r\n\r\n    /**\r\n     * Returns true if retrieving the list of input devices is supported\r\n     * and false if not.\r\n     */\r\n    static isDeviceListAvailable() {\r\n        return RTCUtils.isDeviceListAvailable();\r\n    }\r\n\r\n    /**\r\n     * Returns true if changing the input (camera / microphone) or output\r\n     * (audio) device is supported and false if not.\r\n     * @param {string} [deviceType] Type of device to change. Default is\r\n     *      undefined or 'input', 'output' - for audio output device change.\r\n     * @returns {boolean} true if available, false otherwise.\r\n     */\r\n    static isDeviceChangeAvailable(deviceType) {\r\n        return RTCUtils.isDeviceChangeAvailable(deviceType);\r\n    }\r\n\r\n    /**\r\n     * Returns whether the current execution environment supports WebRTC (for\r\n     * use within this library).\r\n     *\r\n     * @returns {boolean} {@code true} if WebRTC is supported in the current\r\n     * execution environment (for use within this library); {@code false},\r\n     * otherwise.\r\n     */\r\n    static isWebRtcSupported() {\r\n        return browser.isSupported();\r\n    }\r\n\r\n    /**\r\n     * Returns currently used audio output device id, '' stands for default\r\n     * device\r\n     * @returns {string}\r\n     */\r\n    static getAudioOutputDevice() {\r\n        return RTCUtils.getAudioOutputDevice();\r\n    }\r\n\r\n    /**\r\n     * Returns list of available media devices if its obtained, otherwise an\r\n     * empty array is returned/\r\n     * @returns {array} list of available media devices.\r\n     */\r\n    static getCurrentlyAvailableMediaDevices() {\r\n        return RTCUtils.getCurrentlyAvailableMediaDevices();\r\n    }\r\n\r\n    /**\r\n     * Returns whether available devices have permissions granted\r\n     * @returns {Boolean}\r\n     */\r\n    static arePermissionsGrantedForAvailableDevices() {\r\n        return RTCUtils.arePermissionsGrantedForAvailableDevices();\r\n    }\r\n\r\n    /**\r\n     * Returns event data for device to be reported to stats.\r\n     * @returns {MediaDeviceInfo} device.\r\n     */\r\n    static getEventDataForActiveDevice(device) {\r\n        return RTCUtils.getEventDataForActiveDevice(device);\r\n    }\r\n\r\n    /**\r\n     * Sets current audio output device.\r\n     * @param {string} deviceId Id of 'audiooutput' device from\r\n     *      navigator.mediaDevices.enumerateDevices().\r\n     * @returns {Promise} resolves when audio output is changed, is rejected\r\n     *      otherwise\r\n     */\r\n    static setAudioOutputDevice(deviceId) {\r\n        return RTCUtils.setAudioOutputDevice(deviceId);\r\n    }\r\n\r\n    /**\r\n     * Returns <tt>true<tt/> if given WebRTC MediaStream is considered a valid\r\n     * \"user\" stream which means that it's not a \"receive only\" stream nor a\r\n     * \"mixed\" JVB stream.\r\n     *\r\n     * Clients that implement Unified Plan, such as Firefox use recvonly\r\n     * \"streams/channels/tracks\" for receiving remote stream/tracks, as opposed\r\n     * to Plan B where there are only 3 channels: audio, video and data.\r\n     *\r\n     * @param {MediaStream} stream The WebRTC MediaStream instance.\r\n     * @returns {boolean}\r\n     */\r\n    static isUserStream(stream) {\r\n        return RTC.isUserStreamById(stream.id);\r\n    }\r\n\r\n    /**\r\n     * Returns <tt>true<tt/> if a WebRTC MediaStream identified by given stream\r\n     * ID is considered a valid \"user\" stream which means that it's not a\r\n     * \"receive only\" stream nor a \"mixed\" JVB stream.\r\n     *\r\n     * Clients that implement Unified Plan, such as Firefox use recvonly\r\n     * \"streams/channels/tracks\" for receiving remote stream/tracks, as opposed\r\n     * to Plan B where there are only 3 channels: audio, video and data.\r\n     *\r\n     * @param {string} streamId The id of WebRTC MediaStream.\r\n     * @returns {boolean}\r\n     */\r\n    static isUserStreamById(streamId) {\r\n        return streamId && streamId !== 'mixedmslabel'\r\n            && streamId !== 'default';\r\n    }\r\n\r\n    /**\r\n     * Allows to receive list of available cameras/microphones.\r\n     * @param {function} callback Would receive array of devices as an\r\n     *      argument.\r\n     */\r\n    static enumerateDevices(callback) {\r\n        RTCUtils.enumerateDevices(callback);\r\n    }\r\n\r\n    /**\r\n     * A method to handle stopping of the stream.\r\n     * One point to handle the differences in various implementations.\r\n     * @param {MediaStream} mediaStream MediaStream object to stop.\r\n     */\r\n    static stopMediaStream(mediaStream) {\r\n        RTCUtils.stopMediaStream(mediaStream);\r\n    }\r\n\r\n    /**\r\n     * Returns whether the desktop sharing is enabled or not.\r\n     * @returns {boolean}\r\n     */\r\n    static isDesktopSharingEnabled() {\r\n        return RTCUtils.isDesktopSharingEnabled();\r\n    }\r\n\r\n    /**\r\n     * Closes the currently opened bridge channel.\r\n     */\r\n    closeBridgeChannel() {\r\n        if (this._channel) {\r\n            this._channel.close();\r\n            this._channel = null;\r\n        }\r\n    }\r\n\r\n    /* eslint-disable max-params */\r\n    /**\r\n     *\r\n     * @param {TraceablePeerConnection} tpc\r\n     * @param {number} ssrc\r\n     * @param {number} audioLevel\r\n     * @param {boolean} isLocal\r\n     */\r\n    setAudioLevel(tpc, ssrc, audioLevel, isLocal) {\r\n        const track = tpc.getTrackBySSRC(ssrc);\r\n\r\n        if (!track) {\r\n            return;\r\n        } else if (!track.isAudioTrack()) {\r\n            logger.warn(`Received audio level for non-audio track: ${ssrc}`);\r\n\r\n            return;\r\n        } else if (track.isLocal() !== isLocal) {\r\n            logger.error(\r\n                `${track} was expected to ${isLocal ? 'be' : 'not be'} local`);\r\n        }\r\n\r\n        track.setAudioLevel(audioLevel, tpc);\r\n    }\r\n\r\n    /**\r\n     * Sends message via the bridge channel.\r\n     * @param {string} to The id of the endpoint that should receive the\r\n     *      message. If \"\" the message will be sent to all participants.\r\n     * @param {object} payload The payload of the message.\r\n     * @throws NetworkError or InvalidStateError or Error if the operation\r\n     * fails or there is no data channel created.\r\n     */\r\n    sendChannelMessage(to, payload) {\r\n        if (this._channel) {\r\n            this._channel.sendMessage(to, payload);\r\n        } else {\r\n            throw new Error('Channel support is disabled!');\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sends the local stats via the bridge channel.\r\n     * @param {Object} payload The payload of the message.\r\n     * @throws NetworkError/InvalidStateError/Error if the operation fails or if there is no data channel created.\r\n     */\r\n    sendEndpointStatsMessage(payload) {\r\n        if (this._channel && this._channel.isOpen()) {\r\n            this._channel.sendEndpointStatsMessage(payload);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Selects a new value for \"lastN\". The requested amount of videos are going\r\n     * to be delivered after the value is in effect. Set to -1 for unlimited or\r\n     * all available videos.\r\n     * @param {number} value the new value for lastN.\r\n     */\r\n    setLastN(value) {\r\n        if (this._lastN !== value) {\r\n            this._lastN = value;\r\n            if (this._channel && this._channel.isOpen()) {\r\n                this._channel.sendSetLastNMessage(value);\r\n            }\r\n            this.eventEmitter.emit(RTCEvents.LASTN_VALUE_CHANGED, value);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Indicates if the source name is currently included in the forwarded sources.\r\n     *\r\n     * @param {string} sourceName The source name that we check for forwarded sources.\r\n     * @returns {boolean} true if the source name is in the forwarded sources or if we don't have bridge channel\r\n     * support, otherwise we return false.\r\n     */\r\n    isInForwardedSources(sourceName) {\r\n        return !this._forwardedSources // forwardedSources not initialised yet.\r\n            || this._forwardedSources.indexOf(sourceName) > -1;\r\n    }\r\n\r\n    /**\r\n     * Updates the target audio output device for all remote audio tracks.\r\n     *\r\n     * @param {string} deviceId - The device id of the audio ouput device to\r\n     * use for all remote tracks.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _updateAudioOutputForAudioTracks(deviceId) {\r\n        const remoteAudioTracks = this.getRemoteTracks(MediaType.AUDIO);\r\n\r\n        for (const track of remoteAudioTracks) {\r\n            track.setAudioOutput(deviceId);\r\n        }\r\n    }\r\n}\r\n","export enum ConnectionQualityEvents {\r\n    /**\r\n     * Indicates that the local connection statistics were updated.\r\n     */\r\n    LOCAL_STATS_UPDATED = 'cq.local_stats_updated',\r\n\r\n    /**\r\n     * Indicates that the connection statistics for a particular remote participant\r\n     * were updated.\r\n     */\r\n    REMOTE_STATS_UPDATED = 'cq.remote_stats_updated'\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const LOCAL_STATS_UPDATED = ConnectionQualityEvents.LOCAL_STATS_UPDATED;\r\nexport const REMOTE_STATS_UPDATED = ConnectionQualityEvents.REMOTE_STATS_UPDATED;\r\n\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport * as ConferenceEvents from '../../JitsiConferenceEvents';\r\nimport CodecMimeType from '../../service/RTC/CodecMimeType';\r\nimport * as RTCEvents from '../../service/RTC/RTCEvents';\r\nimport * as ConnectionQualityEvents from '../../service/connectivity/ConnectionQualityEvents';\r\nimport browser from '../browser';\r\n\r\nconst Resolutions = require('../../service/RTC/Resolutions');\r\nconst { VideoType } = require('../../service/RTC/VideoType');\r\nconst { XMPPEvents } = require('../../service/xmpp/XMPPEvents');\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * The value to use for the \"type\" field for messages sent by ConnectionQuality\r\n * over the data channel.\r\n */\r\nconst STATS_MESSAGE_TYPE = 'stats';\r\n\r\n/**\r\n * The value to use for the \"type\" field for messages sent\r\n * over the data channel that contain a face landmark.\r\n */\r\nconst FACE_LANDMARK_MESSAGE_TYPE = 'face_landmark';\r\n\r\nconst kSimulcastFormats = [\r\n    { width: 1920,\r\n        height: 1080,\r\n        layers: 3,\r\n        target: 'high',\r\n        targetRN: 4000000 },\r\n    { width: 1280,\r\n        height: 720,\r\n        layers: 3,\r\n        target: 'high',\r\n        targetRN: 2500000 },\r\n    { width: 960,\r\n        height: 540,\r\n        layers: 3,\r\n        target: 'standard',\r\n        targetRN: 900000 },\r\n    { width: 640,\r\n        height: 360,\r\n        layers: 2,\r\n        target: 'standard',\r\n        targetRN: 500000 },\r\n    { width: 480,\r\n        height: 270,\r\n        layers: 2,\r\n        target: 'low',\r\n        targetRN: 350000 },\r\n    { width: 320,\r\n        height: 180,\r\n        layers: 1,\r\n        target: 'low',\r\n        targetRN: 150000 }\r\n];\r\n\r\n/**\r\n * The maximum bitrate to use as a measurement against the participant's current\r\n * bitrate. This cap helps in the cases where the participant's bitrate is high\r\n * but not enough to fulfill high targets, such as with 1080p.\r\n */\r\nconst MAX_TARGET_BITRATE = 2500;\r\n\r\n/**\r\n * The initial bitrate for video in kbps.\r\n */\r\nlet startBitrate = 800;\r\n\r\n/**\r\n * Gets the expected bitrate (in kbps) in perfect network conditions.\r\n * @param simulcast {boolean} whether simulcast is enabled or not.\r\n * @param resolution {Resolution} the resolution.\r\n * @param millisSinceStart {number} the number of milliseconds since sending video started.\r\n * @param videoQualitySettings {Object} the bitrate and codec settings for the local video source.\r\n */\r\nfunction getTarget(simulcast, resolution, millisSinceStart, videoQualitySettings) {\r\n    let target = 0;\r\n    let height = Math.min(resolution.height, resolution.width);\r\n\r\n    // Find the first format with height no bigger than ours.\r\n    let simulcastFormat = kSimulcastFormats.find(f => f.height <= height);\r\n\r\n    if (simulcastFormat && simulcast && videoQualitySettings.codec === CodecMimeType.VP8) {\r\n        // Sum the target fields from all simulcast layers for the given\r\n        // resolution (e.g. 720p + 360p + 180p) for VP8 simulcast.\r\n        for (height = simulcastFormat.height; height >= 180; height /= 2) {\r\n            const targetHeight = height;\r\n\r\n            simulcastFormat = kSimulcastFormats.find(f => f.height === targetHeight);\r\n            if (simulcastFormat) {\r\n                target += browser.isReactNative()\r\n                    ? simulcastFormat.targetRN\r\n                    : videoQualitySettings[simulcastFormat.target];\r\n            } else {\r\n                break;\r\n            }\r\n        }\r\n    } else if (simulcastFormat) {\r\n        // For VP9 SVC, H.264 (simulcast automatically disabled) and p2p, target bitrate will be\r\n        // same as that of the individual stream bitrate.\r\n        target = browser.isReactNative()\r\n            ? simulcastFormat.targetRN\r\n            : videoQualitySettings[simulcastFormat.target];\r\n    }\r\n\r\n    // Allow for an additional 1 second for ramp up -- delay any initial drop\r\n    // of connection quality by 1 second. Convert target from bps to kbps.\r\n    return Math.min(target / 1000, rampUp(Math.max(0, millisSinceStart - 1000)));\r\n}\r\n\r\n/**\r\n * Gets the bitrate to which GCC would have ramped up in perfect network\r\n * conditions after millisSinceStart milliseconds.\r\n * @param millisSinceStart {number} the number of milliseconds since sending\r\n * video was enabled.\r\n */\r\nfunction rampUp(millisSinceStart) {\r\n    if (millisSinceStart > 60000) {\r\n        return Number.MAX_SAFE_INTEGER;\r\n    }\r\n\r\n    // According to GCC the send side bandwidth estimation grows with at most\r\n    // 8% per second.\r\n    // https://tools.ietf.org/html/draft-ietf-rmcat-gcc-02#section-5.5\r\n    return startBitrate * Math.pow(1.08, millisSinceStart / 1000);\r\n}\r\n\r\n/**\r\n * A class which monitors the local statistics coming from the RTC modules, and\r\n * calculates a \"connection quality\" value, in percent, for the media\r\n * connection. A value of 100% indicates a very good network connection, and a\r\n * value of 0% indicates a poor connection.\r\n */\r\nexport default class ConnectionQuality {\r\n    /**\r\n     *\r\n     * @param conference\r\n     * @param eventEmitter\r\n     * @param options\r\n     */\r\n    constructor(conference, eventEmitter, options) {\r\n        this.eventEmitter = eventEmitter;\r\n\r\n        /**\r\n         * The owning JitsiConference.\r\n         */\r\n        this._conference = conference;\r\n\r\n        /**\r\n         * Holds statistics about the local connection quality.\r\n         */\r\n        this._localStats = {\r\n            connectionQuality: 100,\r\n            jvbRTT: undefined\r\n        };\r\n\r\n        /**\r\n         * The time this._localStats.connectionQuality was last updated.\r\n         */\r\n        this._lastConnectionQualityUpdate = -1;\r\n\r\n        /**\r\n         * Conference options.\r\n         */\r\n        this._options = options;\r\n\r\n        /**\r\n         * Maps a participant ID to an object holding connection quality\r\n         * statistics received from this participant.\r\n         */\r\n        this._remoteStats = {};\r\n\r\n        /**\r\n         * The time that the ICE state last changed to CONNECTED. We use this\r\n         * to calculate how much time we as a sender have had to ramp-up.\r\n         */\r\n        this._timeIceConnected = -1;\r\n\r\n        /**\r\n         * The time that local video was unmuted. We use this to calculate how\r\n         * much time we as a sender have had to ramp-up.\r\n         */\r\n        this._timeVideoUnmuted = -1;\r\n\r\n        // We assume a global startBitrate value for the sake of simplicity.\r\n        if (this._options.config?.startBitrate > 0) {\r\n            startBitrate = this._options.config.startBitrate;\r\n        }\r\n\r\n        // TODO: consider ignoring these events and letting the user of\r\n        // lib-jitsi-meet handle these separately.\r\n        conference.on(\r\n            ConferenceEvents.CONNECTION_INTERRUPTED,\r\n            () => {\r\n                this._updateLocalConnectionQuality(0);\r\n                this.eventEmitter.emit(\r\n                    ConnectionQualityEvents.LOCAL_STATS_UPDATED,\r\n                    this._localStats);\r\n                this._broadcastLocalStats();\r\n            });\r\n\r\n        conference.room.addListener(\r\n            XMPPEvents.ICE_CONNECTION_STATE_CHANGED,\r\n            (jingleSession, newState) => {\r\n                if (!jingleSession.isP2P && newState === 'connected') {\r\n                    this._timeIceConnected = window.performance.now();\r\n                }\r\n            });\r\n\r\n        // Listen to DataChannel message from other participants in the\r\n        // conference, and update the _remoteStats field accordingly.\r\n        // TODO - Delete this when all the mobile endpoints switch to using the new Colibri\r\n        // message format for sending the endpoint stats.\r\n        conference.on(\r\n            ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\r\n            (participant, payload) => {\r\n                if (payload.type === STATS_MESSAGE_TYPE) {\r\n                    this._updateRemoteStats(\r\n                        participant.getId(), payload.values);\r\n                }\r\n            });\r\n\r\n        conference.on(\r\n            ConferenceEvents.ENDPOINT_STATS_RECEIVED,\r\n            (participant, payload) => {\r\n                this._updateRemoteStats(participant.getId(), payload);\r\n            });\r\n\r\n        conference.on(\r\n            ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\r\n            (participant, payload) => {\r\n                if (payload.type === FACE_LANDMARK_MESSAGE_TYPE) {\r\n                    this.eventEmitter.emit(\r\n                        ConferenceEvents.FACE_LANDMARK_ADDED,\r\n                        participant.getId(),\r\n                        payload);\r\n                }\r\n            });\r\n\r\n        // Listen to local statistics events originating from the RTC module and update the _localStats field.\r\n        conference.statistics.addConnectionStatsListener(this._updateLocalStats.bind(this));\r\n\r\n        // Save the last time we were unmuted.\r\n        conference.on(\r\n            ConferenceEvents.TRACK_MUTE_CHANGED,\r\n            track => {\r\n                if (track.isVideoTrack()) {\r\n                    if (track.isMuted()) {\r\n                        this._timeVideoUnmuted = -1;\r\n                    } else {\r\n                        this._maybeUpdateUnmuteTime();\r\n                    }\r\n                }\r\n            });\r\n        conference.on(\r\n            ConferenceEvents.TRACK_ADDED,\r\n            track => {\r\n                if (track.isVideoTrack() && !track.isMuted()) {\r\n                    this._maybeUpdateUnmuteTime();\r\n                }\r\n            });\r\n        conference.rtc.on(\r\n            RTCEvents.LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED,\r\n            track => {\r\n                this._localStats.maxEnabledResolution = track.maxEnabledResolution;\r\n            });\r\n\r\n        conference.on(\r\n            ConferenceEvents.SERVER_REGION_CHANGED,\r\n            serverRegion => {\r\n                this._localStats.serverRegion = serverRegion;\r\n            });\r\n\r\n        conference.on(\r\n            ConferenceEvents.PROPERTIES_CHANGED,\r\n            properties => {\r\n                this._localStats.bridgeCount\r\n                    = Number((properties || {})['bridge-count']);\r\n            }\r\n        );\r\n    }\r\n\r\n    /**\r\n     * Sets _timeVideoUnmuted if it was previously unset. If it was already set,\r\n     * doesn't change it.\r\n     */\r\n    _maybeUpdateUnmuteTime() {\r\n        if (this._timeVideoUnmuted < 0) {\r\n            this._timeVideoUnmuted = window.performance.now();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Calculates a new \"connection quality\" value.\r\n     * @param videoType {VideoType} the type of the video source (camera or a screen capture).\r\n     * @param isMuted {boolean} whether the local video is muted.\r\n     * @param resolutionName {Resolution} the input resolution used by the camera.\r\n     * @returns {*} the newly calculated connection quality.\r\n     */\r\n    _calculateConnectionQuality(videoType, isMuted, resolutionName) {\r\n\r\n        // resolutionName is an index into Resolutions (where \"720\" is\r\n        // \"1280x720\" and \"960\" is \"960x720\" ...).\r\n        const resolution = Resolutions[resolutionName];\r\n\r\n        let quality = 100;\r\n        let packetLoss;\r\n\r\n        // TODO: take into account packet loss for received streams\r\n\r\n        if (this._localStats.packetLoss) {\r\n            packetLoss = this._localStats.packetLoss.upload;\r\n\r\n            // Ugly Hack Alert (UHA):\r\n            // The packet loss for the upload direction is calculated based on\r\n            // incoming RTCP Receiver Reports. Since we don't have RTCP\r\n            // termination for audio, these reports come from the actual\r\n            // receivers in the conference and therefore the reported packet\r\n            // loss includes loss from the bridge to the receiver.\r\n            // When we are sending video this effect is small, because the\r\n            // number of video packets is much larger than the number of audio\r\n            // packets (and our calculation is based on the total number of\r\n            // received and lost packets).\r\n            // When video is muted, however, the effect might be significant,\r\n            // but we don't know what it is. We do know that it is positive, so\r\n            // as a temporary solution, until RTCP termination is implemented\r\n            // for the audio streams, we relax the packet loss checks here.\r\n            if (isMuted) {\r\n                packetLoss *= 0.5;\r\n            }\r\n        }\r\n\r\n        if (isMuted || !resolution || videoType === VideoType.DESKTOP\r\n            || this._timeIceConnected < 0\r\n            || this._timeVideoUnmuted < 0) {\r\n\r\n            // Calculate a value based on packet loss only.\r\n            if (packetLoss === undefined) {\r\n                logger.error('Cannot calculate connection quality, unknown '\r\n                    + 'packet loss.');\r\n                quality = 100;\r\n            } else if (packetLoss <= 2) {\r\n                quality = 100; // Full 5 bars.\r\n            } else if (packetLoss <= 4) {\r\n                quality = 70; // 4 bars\r\n            } else if (packetLoss <= 6) {\r\n                quality = 50; // 3 bars\r\n            } else if (packetLoss <= 8) {\r\n                quality = 30; // 2 bars\r\n            } else if (packetLoss <= 12) {\r\n                quality = 10; // 1 bars\r\n            } else {\r\n                quality = 0; // Still 1 bar, but slower climb-up.\r\n            }\r\n        } else {\r\n            // Calculate a value based on the send video bitrate on the active TPC.\r\n            const activeTPC = this._conference.getActivePeerConnection();\r\n\r\n            if (activeTPC) {\r\n                const isSimulcastOn = activeTPC.isSimulcastOn();\r\n                const videoQualitySettings = activeTPC.getTargetVideoBitrates();\r\n\r\n                // Add the codec info as well.\r\n                videoQualitySettings.codec = activeTPC.getConfiguredVideoCodec();\r\n\r\n                // Time since sending of video was enabled.\r\n                const millisSinceStart = window.performance.now()\r\n                    - Math.max(this._timeVideoUnmuted, this._timeIceConnected);\r\n                const statsInterval = this._options.config?.pcStatsInterval ?? 10000;\r\n\r\n                // Expected sending bitrate in perfect conditions.\r\n                let target = getTarget(isSimulcastOn, resolution, millisSinceStart, videoQualitySettings);\r\n\r\n                target = Math.min(target, MAX_TARGET_BITRATE);\r\n\r\n                // Calculate the quality only after the stats are available (after video was enabled).\r\n                if (millisSinceStart > statsInterval) {\r\n                    quality = 100 * this._localStats.bitrate.upload / target;\r\n                }\r\n            }\r\n\r\n            // Whatever the bitrate, drop early if there is significant loss\r\n            if (packetLoss && packetLoss >= 10) {\r\n                quality = Math.min(quality, 30);\r\n            }\r\n        }\r\n\r\n        // Make sure that the quality doesn't climb quickly\r\n        if (this._lastConnectionQualityUpdate > 0) {\r\n            const maxIncreasePerSecond = 2;\r\n            const prevConnectionQuality = this._localStats.connectionQuality;\r\n            const diffSeconds = (window.performance.now() - this._lastConnectionQualityUpdate) / 1000;\r\n\r\n            quality = Math.min(quality, prevConnectionQuality + (diffSeconds * maxIncreasePerSecond));\r\n        }\r\n\r\n        return Math.min(100, quality);\r\n    }\r\n\r\n    /**\r\n     * Updates the localConnectionQuality value\r\n     * @param values {number} the new value. Should be in [0, 100].\r\n     */\r\n    _updateLocalConnectionQuality(value) {\r\n        this._localStats.connectionQuality = value;\r\n        this._lastConnectionQualityUpdate = window.performance.now();\r\n    }\r\n\r\n    /**\r\n     * Broadcasts the local statistics to all other participants in the\r\n     * conference.\r\n     */\r\n    _broadcastLocalStats() {\r\n        // Send only the data that remote participants care about.\r\n        const data = {\r\n            bitrate: this._localStats.bitrate,\r\n            packetLoss: this._localStats.packetLoss,\r\n            connectionQuality: this._localStats.connectionQuality,\r\n            jvbRTT: this._localStats.jvbRTT,\r\n            serverRegion: this._localStats.serverRegion,\r\n            maxEnabledResolution: this._localStats.maxEnabledResolution,\r\n            avgAudioLevels: this._localStats.localAvgAudioLevels\r\n        };\r\n\r\n        try {\r\n            this._conference.sendEndpointStatsMessage(data);\r\n        } catch (err) {\r\n            // Ignore the error as we might hit it in the beginning of the call before the channel is ready.\r\n            // The statistics will be sent again after few seconds and error is logged elseware as well.\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Updates the local statistics\r\n     * @param {TraceablePeerConnection} tpc the peerconnection which emitted\r\n     * the stats\r\n     * @param data new statistics\r\n     */\r\n    _updateLocalStats(tpc, data) {\r\n        // Update jvbRTT\r\n        if (!tpc.isP2P) {\r\n            const jvbRTT\r\n                = data.transport\r\n                    && data.transport.length && data.transport[0].rtt;\r\n\r\n            this._localStats.jvbRTT = jvbRTT ? jvbRTT : undefined;\r\n        }\r\n\r\n        // Do not continue with processing of other stats if they do not\r\n        // originate from the active peerconnection\r\n        if (tpc !== this._conference.getActivePeerConnection()) {\r\n            return;\r\n        }\r\n\r\n        let key;\r\n        const updateLocalConnectionQuality\r\n            = !this._conference.isConnectionInterrupted();\r\n        const localVideoTrack\r\n            = this._conference.getLocalVideoTrack();\r\n        const videoType\r\n            = localVideoTrack ? localVideoTrack.videoType : undefined;\r\n        const isMuted = localVideoTrack ? localVideoTrack.isMuted() : true;\r\n        const resolution = localVideoTrack\r\n            ? Math.min(localVideoTrack.resolution, localVideoTrack.maxEnabledResolution) : null;\r\n\r\n        if (!isMuted) {\r\n            this._maybeUpdateUnmuteTime();\r\n        }\r\n\r\n        // Copy the fields already in 'data'.\r\n        for (key in data) {\r\n            if (data.hasOwnProperty(key)) {\r\n                this._localStats[key] = data[key];\r\n            }\r\n        }\r\n\r\n        // And re-calculate the connectionQuality field.\r\n        if (updateLocalConnectionQuality) {\r\n            this._updateLocalConnectionQuality(\r\n                this._calculateConnectionQuality(\r\n                    videoType,\r\n                    isMuted,\r\n                    resolution));\r\n        }\r\n\r\n        this.eventEmitter.emit(\r\n            ConnectionQualityEvents.LOCAL_STATS_UPDATED,\r\n            this._localStats);\r\n        this._broadcastLocalStats();\r\n    }\r\n\r\n    /**\r\n     * Updates remote statistics\r\n     * @param id the id of the remote participant\r\n     * @param data the statistics received\r\n     */\r\n    _updateRemoteStats(id, data) {\r\n        // Use only the fields we need\r\n        this._remoteStats[id] = {\r\n            bitrate: data.bitrate,\r\n            packetLoss: data.packetLoss,\r\n            connectionQuality: data.connectionQuality,\r\n            jvbRTT: data.jvbRTT,\r\n            serverRegion: data.serverRegion,\r\n            maxEnabledResolution: data.maxEnabledResolution,\r\n            avgAudioLevels: data.avgAudioLevels\r\n        };\r\n\r\n        this.eventEmitter.emit(\r\n            ConnectionQualityEvents.REMOTE_STATS_UPDATED,\r\n            id,\r\n            this._remoteStats[id]);\r\n    }\r\n\r\n    /**\r\n     * Returns the local statistics.\r\n     * Exported only for use in jitsi-meet-torture.\r\n     */\r\n    getStats() {\r\n        return this._localStats;\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport * as JitsiConferenceErrors from '../../JitsiConferenceErrors';\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * This class deals with shenanigans around JVB media session's ICE failed status handling.\r\n *\r\n * If ICE restarts are NOT explicitly enabled by the {@code enableIceRestart} config option, then the conference will\r\n * delay emitting the {@JitsiConferenceErrors.ICE_FAILED} event by 15 seconds. If the network info module reports\r\n * the internet offline status then the time will start counting after the internet comes back online.\r\n *\r\n * If ICE restart are enabled, then a delayed ICE failed notification to Jicofo will be sent, only if the ICE connection\r\n * does not recover soon after or before the XMPP connection is restored (if it was ever broken). If ICE fails while\r\n * the XMPP connection is not broken then the notifications will be sent after 2 seconds delay.\r\n */\r\nexport default class IceFailedHandling {\r\n    /**\r\n     * Creates new {@code DelayedIceFailed} task.\r\n     * @param {JitsiConference} conference\r\n     */\r\n    constructor(conference) {\r\n        this._conference = conference;\r\n    }\r\n\r\n    /**\r\n     * After making sure there's no way for the ICE connection to recover this method either sends ICE failed\r\n     * notification to Jicofo or emits the ice failed conference event.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _actOnIceFailed() {\r\n        if (!this._conference.room) {\r\n            return;\r\n        }\r\n\r\n        const { enableForcedReload, enableIceRestart } = this._conference.options.config;\r\n        const explicitlyDisabled = typeof enableIceRestart !== 'undefined' && !enableIceRestart;\r\n        const supportsRestartByTerminate = this._conference.room.supportsRestartByTerminate();\r\n        const useTerminateForRestart = supportsRestartByTerminate && !enableIceRestart;\r\n\r\n        logger.info('ICE failed,'\r\n            + ` enableForcedReload: ${enableForcedReload},`\r\n            + ` enableIceRestart: ${enableIceRestart},`\r\n            + ` supports restart by terminate: ${supportsRestartByTerminate}`);\r\n\r\n        if (explicitlyDisabled || (!enableIceRestart && !supportsRestartByTerminate) || enableForcedReload) {\r\n            logger.info('ICE failed, but ICE restarts are disabled');\r\n            const reason = enableForcedReload\r\n                ? JitsiConferenceErrors.CONFERENCE_RESTARTED\r\n                : JitsiConferenceErrors.ICE_FAILED;\r\n\r\n            this._conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED, reason);\r\n\r\n            return;\r\n        }\r\n\r\n        const jvbConnection = this._conference.jvbJingleSession;\r\n        const jvbConnIceState = jvbConnection && jvbConnection.getIceConnectionState();\r\n\r\n        if (!jvbConnection) {\r\n            logger.warn('Not sending ICE failed - no JVB connection');\r\n        } else if (jvbConnIceState === 'connected') {\r\n            logger.info('ICE connection restored - not sending ICE failed');\r\n        } else {\r\n            logger.info('Sending ICE failed - the connection did not recover, '\r\n                + `ICE state: ${jvbConnIceState}, `\r\n                + `use 'session-terminate': ${useTerminateForRestart}`);\r\n            if (useTerminateForRestart) {\r\n                this._conference.jvbJingleSession.terminate(\r\n                    () => {\r\n                        logger.info('session-terminate for ice restart - done');\r\n                    },\r\n                    error => {\r\n                        logger.error(`session-terminate for ice restart - error: ${error.message}`);\r\n                    }, {\r\n                        reason: 'connectivity-error',\r\n                        reasonDescription: 'ICE FAILED',\r\n                        requestRestart: true,\r\n                        sendSessionTerminate: true\r\n                    });\r\n            } else {\r\n                this._conference.jvbJingleSession.sendIceFailedNotification();\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Starts the task.\r\n     */\r\n    start() {\r\n        //  Using xmpp.ping allows to handle both XMPP being disconnected and internet offline cases. The ping function\r\n        // uses sendIQ2 method which is resilient to XMPP connection disconnected state and will patiently wait until it\r\n        // gets reconnected.\r\n        //  This also handles the case about waiting for the internet to come back online, because ping\r\n        // will only succeed when the internet is online and then there's a chance for the ICE to recover from FAILED to\r\n        // CONNECTED which is the extra 2 second timeout after ping.\r\n        //  The 65 second timeout is given on purpose as there's no chance for XMPP to recover after 65 seconds of no\r\n        // communication with the server. Such resume attempt will result in unrecoverable conference failed event due\r\n        // to 'item-not-found' error returned by the server.\r\n        this._conference.xmpp.ping(65000).then(\r\n            () => {\r\n                if (!this._canceled) {\r\n                    this._iceFailedTimeout = window.setTimeout(() => {\r\n                        this._iceFailedTimeout = undefined;\r\n                        this._actOnIceFailed();\r\n                    }, 2000);\r\n                }\r\n            },\r\n            error => {\r\n                logger.error('PING error/timeout - not sending ICE failed', error);\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Cancels the task.\r\n     */\r\n    cancel() {\r\n        this._canceled = true;\r\n        window.clearTimeout(this._iceFailedTimeout);\r\n    }\r\n}\r\n","export enum DetectionEvents {\r\n    /**\r\n     * Event triggered by a audio detector indicating that its active state has changed from active to inactive or vice\r\n     * versa.\r\n     * @event\r\n     * @type {boolean} - true when service has changed to active false otherwise.\r\n     */\r\n    DETECTOR_STATE_CHANGE = 'detector_state_change',\r\n\r\n    /** Event triggered by {@link NoAudioSignalDetector} when the local audio device associated with a JitsiConference\r\n     * starts receiving audio levels with the value of 0 meaning no audio is being captured on that device, or when\r\n     * it starts receiving audio levels !== 0 after being in a state of no audio.\r\n     * @event\r\n     * @type {boolean} - true when the current conference audio track has audio input false otherwise.\r\n     */\r\n    AUDIO_INPUT_STATE_CHANGE = 'audio_input_state_changed',\r\n\r\n    /** Event triggered by NoAudioSignalDetector when the local audio device associated with a JitsiConference goes silent\r\n     * for a period of time, meaning that the device is either broken or hardware/software muted.\r\n     * @event\r\n     * @type {void}\r\n     */\r\n    NO_AUDIO_INPUT = 'no_audio_input_detected',\r\n\r\n    /**\r\n     *  Event generated by {@link VADNoiseDetection} when the tracked device is considered noisy.\r\n     *  @event\r\n     *  @type {Object}\r\n     */\r\n    VAD_NOISY_DEVICE = 'detection.vad_noise_device',\r\n\r\n    /**\r\n     * Event generated by VADReportingService when if finishes creating a VAD report for the monitored devices.\r\n     * The generated objects are of type Array<Object>, one score for each monitored device.\r\n     * @event VAD_REPORT_PUBLISHED\r\n     * @type Array<Object> with the following structure:\r\n     * @property {Date} timestamp - Timestamp at which the compute took place.\r\n     * @property {number} avgVAD - Average VAD score over monitored period of time.\r\n     * @property {string} deviceId - Associate local audio device ID.\r\n     */\r\n    VAD_REPORT_PUBLISHED = 'vad-report-published',\r\n\r\n    /**\r\n     * Event generated by {@link TrackVADEmitter} when PCM sample VAD score is available.\r\n     *\r\n     * @event\r\n     * @type {Object}\r\n     * @property {Date}   timestamp - Exact time at which processed PCM sample was generated.\r\n     * @property {number} score - VAD score on a scale from 0 to 1 (i.e. 0.7)\r\n     * @property {Float32Array} pcmData - Raw PCM data with which the VAD score was calculated.\r\n     * @property {string} deviceId - Device id of the associated track.\r\n     */\r\n    VAD_SCORE_PUBLISHED = 'detection.vad_score_published',\r\n\r\n    /**\r\n     *  Event generated by {@link VADTalkMutedDetection} when a user is talking while the mic is muted.\r\n     *\r\n     *  @event\r\n     *  @type {Object}\r\n     */\r\n    VAD_TALK_WHILE_MUTED = 'detection.vad_talk_while_muted'\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const DETECTOR_STATE_CHANGE = DetectionEvents.DETECTOR_STATE_CHANGE;\r\nexport const AUDIO_INPUT_STATE_CHANGE = DetectionEvents.AUDIO_INPUT_STATE_CHANGE;\r\nexport const NO_AUDIO_INPUT = DetectionEvents.NO_AUDIO_INPUT;\r\nexport const VAD_NOISY_DEVICE = DetectionEvents.VAD_NOISY_DEVICE;\r\nexport const VAD_REPORT_PUBLISHED = DetectionEvents.VAD_REPORT_PUBLISHED;\r\nexport const VAD_SCORE_PUBLISHED = DetectionEvents.VAD_SCORE_PUBLISHED;\r\nexport const VAD_TALK_WHILE_MUTED = DetectionEvents.VAD_TALK_WHILE_MUTED;\r\n","import EventEmitter from 'events';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\r\nimport browser from '../browser';\r\n\r\nimport * as DetectionEvents from './DetectionEvents';\r\n\r\n// We wait a certain time interval for constant silence input from the current device to account for\r\n// potential abnormalities and for a better use experience i.e. don't generate event the instant\r\n// an audio track is added to the tcr.\r\n// Potential improvement - add this as a configurable parameter.\r\nconst SILENCE_PERIOD_MS = 4000;\r\n\r\n/**\r\n * Detect if there is no audio input on the current TraceAblePeerConnection selected track. The no audio\r\n * state must be constant for a configured amount of time in order for the event to be triggered.\r\n * @fires DetectionEvents.AUDIO_INPUT_STATE_CHANGE\r\n * @fires DetectionEvents.NO_AUDIO_INPUT\r\n */\r\nexport default class NoAudioSignalDetection extends EventEmitter {\r\n    /**\r\n     * Creates new NoAudioSignalDetection.\r\n     *\r\n     * @param conference the JitsiConference instance that created us.\r\n     * @constructor\r\n     */\r\n    constructor(conference) {\r\n        super();\r\n\r\n        this._conference = conference;\r\n        this._timeoutTrigger = null;\r\n        this._hasAudioInput = null;\r\n\r\n        if (!browser.supportsReceiverStats()) {\r\n            conference.statistics.addAudioLevelListener(this._audioLevel.bind(this));\r\n        }\r\n        conference.on(JitsiConferenceEvents.TRACK_ADDED, this._trackAdded.bind(this));\r\n    }\r\n\r\n    /**\r\n     * Clear the timeout state.\r\n     */\r\n    _clearTriggerTimeout() {\r\n        clearTimeout(this._timeoutTrigger);\r\n        this._timeoutTrigger = null;\r\n    }\r\n\r\n\r\n    /**\r\n     * Generated event triggered by a change in the current conference audio input state.\r\n     *\r\n     * @param {*} audioLevel - The audio level of the ssrc.\r\n     * @fires DetectionEvents.AUDIO_INPUT_STATE_CHANGE\r\n     */\r\n    _handleAudioInputStateChange(audioLevel) {\r\n        // Current audio input state of the active local track in the conference, true for audio input false for no\r\n        // audio input.\r\n        const status = audioLevel !== 0;\r\n\r\n        // If this is the first audio event picked up or the current status is different from the previous trigger\r\n        // the event.\r\n        if (this._hasAudioInput === null || this._hasAudioInput !== status) {\r\n            this._hasAudioInput = status;\r\n            this.emit(DetectionEvents.AUDIO_INPUT_STATE_CHANGE, this._hasAudioInput);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Generate event triggered by a prolonged period of no audio input.\r\n     *\r\n     * @param {number} audioLevel - The audio level of the ssrc.\r\n     * @fires DetectionEvents.NO_AUDIO_INPUT\r\n     */\r\n    _handleNoAudioInputDetection(audioLevel) {\r\n        if (this._eventFired) {\r\n            return;\r\n        }\r\n\r\n        if (audioLevel === 0 && !this._timeoutTrigger) {\r\n            this._timeoutTrigger = setTimeout(() => {\r\n                this._eventFired = true;\r\n\r\n                this.emit(DetectionEvents.NO_AUDIO_INPUT);\r\n            }, SILENCE_PERIOD_MS);\r\n        } else if (audioLevel !== 0 && this._timeoutTrigger) {\r\n            this._clearTriggerTimeout();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Receives audio level events for all send and receive streams on the current TraceablePeerConnection.\r\n     *\r\n     * @param {TraceablePeerConnection} tpc - TraceablePeerConnection of the owning conference.\r\n     * @param {number} ssrc - The synchronization source identifier (SSRC) of the endpoint/participant/stream\r\n     * being reported.\r\n     * @param {number} audioLevel - The audio level of the ssrc.\r\n     * @param {boolean} isLocal - true for local/send streams or false for remote/receive streams.\r\n     */\r\n    _audioLevel(tpc, ssrc, audioLevel, isLocal) {\r\n        // We are interested in the local audio streams\r\n        if (!isLocal || !this._audioTrack) {\r\n            return;\r\n        }\r\n\r\n        // Get currently active local tracks from the TraceablePeerConnection\r\n        const localSSRCs = tpc.localSSRCs.get(this._audioTrack.rtcId);\r\n\r\n        // Only target the current active track in the tpc. For some reason audio levels for previous\r\n        // devices are also picked up from the PeerConnection so we filter them out.\r\n        if (!localSSRCs || !localSSRCs.ssrcs.includes(ssrc)) {\r\n            return;\r\n        }\r\n\r\n        // First handle audio input state change. In case the state changed to no input the no audio input event\r\n        // can try to fire again.\r\n        this._handleAudioInputStateChange(audioLevel);\r\n        this._handleNoAudioInputDetection(audioLevel);\r\n    }\r\n\r\n    /**\r\n     * Notifies NoAudioSignalDetection that a JitsiTrack was added to the associated JitsiConference.\r\n     * Only take into account local audio tracks.\r\n     *\r\n     * @param {JitsiTrack} track - The added JitsiTrack.\r\n     */\r\n    _trackAdded(track) {\r\n        if (track.isLocalAudioTrack()) {\r\n            // Reset state for the new track.\r\n            this._audioTrack = track;\r\n            this._eventFired = false;\r\n            this._clearTriggerTimeout();\r\n\r\n            // Listen for the audio levels on the newly added audio track\r\n            if (browser.supportsReceiverStats()) {\r\n                track.on(\r\n                    JitsiTrackEvents.NO_AUDIO_INPUT,\r\n                    audioLevel => {\r\n                        this._handleNoAudioInputDetection(audioLevel);\r\n                    }\r\n                );\r\n                track.on(\r\n                    JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,\r\n                    audioLevel => {\r\n                        this._handleNoAudioInputDetection(audioLevel);\r\n                        this._handleAudioInputStateChange(audioLevel);\r\n                    }\r\n                );\r\n            }\r\n        }\r\n    }\r\n}\r\n","import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\nimport RTCEvents from '../../service/RTC/RTCEvents';\r\n\r\n/**\r\n * The value which we use to say, every sound over this threshold\r\n * is talking on the mic.\r\n * @type {number}\r\n */\r\nconst SPEECH_DETECT_THRESHOLD = 0.6;\r\n\r\n/**\r\n * The <tt>P2PDominantSpeakerDetection</tt> is activated only when p2p is\r\n * currently used.\r\n * Listens for changes in the audio level changes of the local p2p audio track\r\n * or remote p2p one and fires dominant speaker events to be able to use\r\n * features depending on those events (speaker stats), to make them work without\r\n * the video bridge.\r\n */\r\nexport default class P2PDominantSpeakerDetection {\r\n    /**\r\n     * Creates P2PDominantSpeakerDetection\r\n     * @param conference the JitsiConference instance that created us.\r\n     * @constructor\r\n     */\r\n    constructor(conference) {\r\n        this.conference = conference;\r\n\r\n        conference.addEventListener(\r\n            JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,\r\n            this._audioLevel.bind(this));\r\n\r\n        this.myUserID = this.conference.myUserId();\r\n    }\r\n\r\n    /**\r\n     * Receives audio level events for all streams in the conference.\r\n     *\r\n     * @param {String} id - The participant id\r\n     * @param {number} audioLevel - The audio level.\r\n     */\r\n    _audioLevel(id, audioLevel) {\r\n\r\n        // we do not process if p2p is not active\r\n        // or audio level is under certain threshold\r\n        // or if the audio level is for local audio track which is muted\r\n        if (!this.conference.isP2PActive()\r\n            || audioLevel <= SPEECH_DETECT_THRESHOLD\r\n            || (id === this.myUserID\r\n                    && this.conference.getLocalAudioTrack().isMuted())) {\r\n            return;\r\n        }\r\n\r\n        this.conference.rtc.eventEmitter.emit(\r\n            RTCEvents.DOMINANT_SPEAKER_CHANGED,\r\n            id);\r\n    }\r\n}\r\n","/**\r\n * Adapter that creates AudioContext objects depending on the browser.\r\n *\r\n * @returns {AudioContext} - Return a new AudioContext or undefined if the browser does not support it.\r\n */\r\nexport function createAudioContext(options) {\r\n    const AudioContextImpl = window.AudioContext || window.webkitAudioContext;\r\n\r\n    if (!AudioContextImpl) {\r\n        return undefined;\r\n    }\r\n\r\n    return new AudioContextImpl(options);\r\n}\r\n","import EventEmitter from 'events';\r\n\r\nimport RTC from '../RTC/RTC';\r\nimport { createAudioContext } from '../webaudio/WebAudioUtils';\r\n\r\nimport { VAD_SCORE_PUBLISHED } from './DetectionEvents';\r\n\r\n/**\r\n * Connects an audio JitsiLocalTrack to a vadProcessor using WebAudio ScriptProcessorNode.\r\n * Once an object is created audio from the local track flows through the ScriptProcessorNode as raw PCM.\r\n * The PCM is processed by the injected vad module and a voice activity detection score is obtained, the\r\n * score is published to consumers via an EventEmitter.\r\n * After work is done with this service the destroy method needs to be called for a proper cleanup.\r\n *\r\n * @fires VAD_SCORE_PUBLISHED\r\n */\r\nexport default class TrackVADEmitter extends EventEmitter {\r\n    /**\r\n     * Constructor.\r\n     *\r\n     * @param {number} procNodeSampleRate - Sample rate of the ScriptProcessorNode. Possible values  256, 512, 1024,\r\n     *  2048, 4096, 8192, 16384. Passing other values will default to closes neighbor.\r\n     * @param {Object} vadProcessor - VAD processor that allows us to calculate VAD score for PCM samples.\r\n     * @param {JitsiLocalTrack} jitsiLocalTrack - JitsiLocalTrack corresponding to micDeviceId.\r\n     */\r\n    constructor(procNodeSampleRate, vadProcessor, jitsiLocalTrack) {\r\n        super();\r\n\r\n        /**\r\n         * Sample rate of the ScriptProcessorNode.\r\n         */\r\n        this._procNodeSampleRate = procNodeSampleRate;\r\n\r\n        /**\r\n         * VAD Processor that allows us to calculate VAD score for PCM samples\r\n         */\r\n        this._vadProcessor = vadProcessor;\r\n\r\n        /**\r\n         * The JitsiLocalTrack instance.\r\n         */\r\n        this._localTrack = jitsiLocalTrack;\r\n\r\n        /**\r\n         * Buffer to hold residue PCM resulting after a ScriptProcessorNode callback\r\n         */\r\n        this._bufferResidue = new Float32Array([]);\r\n\r\n        /**\r\n         * The AudioContext instance with the preferred sample frequency.\r\n         */\r\n        this._audioContext = createAudioContext({ sampleRate: vadProcessor.getRequiredPCMFrequency() });\r\n\r\n        /**\r\n         * PCM Sample size expected by the VAD Processor instance. We cache it here as this value is used extensively,\r\n         * saves a couple of function calls.\r\n         */\r\n        this._vadSampleSize = vadProcessor.getSampleLength();\r\n\r\n        /**\r\n         * Event listener function that will be called by the ScriptProcessNode with raw PCM data, depending on the set\r\n         * sample rate.\r\n         */\r\n        this._onAudioProcess = this._onAudioProcess.bind(this);\r\n\r\n        this._initializeAudioContext();\r\n    }\r\n\r\n    /**\r\n     * Factory method that sets up all the necessary components for the creation of the TrackVADEmitter.\r\n     *\r\n     * @param {string} micDeviceId - Target microphone device id.\r\n     * @param {number} procNodeSampleRate - Sample rate of the proc node.\r\n     * @param {Object} vadProcessor -Module that calculates the voice activity score for a certain audio PCM sample.\r\n     * The processor needs to implement the following functions:\r\n     * - <tt>getSampleLength()</tt> - Returns the sample size accepted by getSampleLength.\r\n     * - <tt>getRequiredPCMFrequency()</tt> - Returns the PCM frequency at which the processor operates.\r\n     * - <tt>calculateAudioFrameVAD(pcmSample)</tt> - Process a 32 float pcm sample of getSampleLength size.\r\n     * @returns {Promise<TrackVADEmitter>} - Promise resolving in a new instance of TrackVADEmitter.\r\n     */\r\n    static create(micDeviceId, procNodeSampleRate, vadProcessor) {\r\n        return RTC.obtainAudioAndVideoPermissions({\r\n            devices: [ 'audio' ],\r\n            micDeviceId\r\n        }).then(localTrack => {\r\n            // We only expect one audio track when specifying a device id.\r\n            if (!localTrack[0]) {\r\n                throw new Error(`Failed to create jitsi local track for device id: ${micDeviceId}`);\r\n            }\r\n\r\n            return new TrackVADEmitter(procNodeSampleRate, vadProcessor, localTrack[0]);\r\n\r\n            // We have no exception handling at this point as there is nothing to clean up, the vadProcessor\r\n            // life cycle is handled by whoever created this instance.\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Sets up the audio graph in the AudioContext.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    _initializeAudioContext() {\r\n        this._audioSource = this._audioContext.createMediaStreamSource(this._localTrack.stream);\r\n\r\n        // TODO AudioProcessingNode is deprecated in the web audio specifications and the recommended replacement\r\n        // is audio worklet, however at the point of implementation AudioProcessingNode was still de de facto way\r\n        // of achieving this functionality and supported in all major browsers as opposed to audio worklet which\r\n        // was only available in Chrome. This todo is just a reminder that we should replace AudioProcessingNode\r\n        // with audio worklet when it's mature enough and has more browser support.\r\n        // We don't need stereo for determining the VAD score so we create a single channel processing node.\r\n        this._audioProcessingNode = this._audioContext.createScriptProcessor(this._procNodeSampleRate, 1, 1);\r\n    }\r\n\r\n    /**\r\n     * ScriptProcessorNode callback, the input parameters contains the PCM audio that is then sent to rnnoise.\r\n     * Rnnoise only accepts PCM samples of 480 bytes whereas the webaudio processor node can't sample at a multiple\r\n     * of 480 thus after each _onAudioProcess callback there will remain and PCM buffer residue equal\r\n     * to _procNodeSampleRate / 480 which will be added to the next sample buffer and so on.\\\r\n     *\r\n     *\r\n     * @param {AudioProcessingEvent} audioEvent - Audio event.\r\n     * @returns {void}\r\n     * @fires VAD_SCORE_PUBLISHED\r\n     */\r\n    _onAudioProcess(audioEvent) {\r\n        // Prepend the residue PCM buffer from the previous process callback.\r\n        const inData = audioEvent.inputBuffer.getChannelData(0);\r\n        const completeInData = [ ...this._bufferResidue, ...inData ];\r\n        const sampleTimestamp = Date.now();\r\n\r\n        let i = 0;\r\n\r\n        for (; i + this._vadSampleSize < completeInData.length; i += this._vadSampleSize) {\r\n            const pcmSample = completeInData.slice(i, i + this._vadSampleSize);\r\n\r\n            // The VAD processor might change the values inside the array so we make a copy.\r\n            const vadScore = this._vadProcessor.calculateAudioFrameVAD(pcmSample.slice());\r\n\r\n            this.emit(VAD_SCORE_PUBLISHED, {\r\n                timestamp: sampleTimestamp,\r\n                score: vadScore,\r\n                pcmData: pcmSample,\r\n                deviceId: this._localTrack.getDeviceId()\r\n            });\r\n        }\r\n\r\n        this._bufferResidue = completeInData.slice(i, completeInData.length);\r\n    }\r\n\r\n    /**\r\n     * Connects the nodes in the AudioContext to start the flow of audio data.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    _connectAudioGraph() {\r\n        this._audioProcessingNode.onaudioprocess = this._onAudioProcess;\r\n        this._audioSource.connect(this._audioProcessingNode);\r\n        this._audioProcessingNode.connect(this._audioContext.destination);\r\n    }\r\n\r\n    /**\r\n     * Disconnects the nodes in the AudioContext.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    _disconnectAudioGraph() {\r\n        // Even thought we disconnect the processing node it seems that some callbacks remain queued,\r\n        // resulting in calls with and uninitialized context.\r\n        // eslint-disable-next-line no-empty-function\r\n        this._audioProcessingNode.onaudioprocess = () => {};\r\n        this._audioProcessingNode.disconnect();\r\n        this._audioSource.disconnect();\r\n    }\r\n\r\n    /**\r\n     * Cleanup potentially acquired resources.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    _cleanupResources() {\r\n        this._disconnectAudioGraph();\r\n        this._localTrack.stopStream();\r\n    }\r\n\r\n    /**\r\n     * Get the associated track device ID.\r\n     *\r\n     * @returns {string}\r\n     */\r\n    getDeviceId() {\r\n        return this._localTrack.getDeviceId();\r\n    }\r\n\r\n\r\n    /**\r\n     * Get the associated track label.\r\n     *\r\n     * @returns {string}\r\n     */\r\n    getTrackLabel() {\r\n        return this._localTrack.getDeviceLabel();\r\n    }\r\n\r\n    /**\r\n     * Start the emitter by connecting the audio graph.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    start() {\r\n        this._connectAudioGraph();\r\n    }\r\n\r\n    /**\r\n     * Stops the emitter by disconnecting the audio graph.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    stop() {\r\n        this._disconnectAudioGraph();\r\n        this._bufferResidue = [];\r\n    }\r\n\r\n    /**\r\n     * Destroy TrackVADEmitter instance (release resources and stop callbacks).\r\n     *\r\n     * @returns {void}\r\n     */\r\n    destroy() {\r\n        if (this._destroyed) {\r\n            return;\r\n        }\r\n\r\n        this._cleanupResources();\r\n        this._destroyed = true;\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport { EventEmitter } from 'events';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\n\r\nimport { DETECTOR_STATE_CHANGE, VAD_SCORE_PUBLISHED } from './DetectionEvents';\r\nimport TrackVADEmitter from './TrackVADEmitter';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Sample rate of TrackVADEmitter, it defines how many audio samples are processed at a time.\r\n * @type {number}\r\n */\r\nconst VAD_EMITTER_SAMPLE_RATE = 4096;\r\n\r\n/**\r\n * Connects a TrackVADEmitter to the target conference local audio track and manages various services that use\r\n * the data to produce audio analytics (VADTalkMutedDetection and VADNoiseDetection).\r\n */\r\nexport default class VADAudioAnalyser extends EventEmitter {\r\n    /**\r\n     * Creates <tt>VADAudioAnalyser</tt>\r\n     * @param {JitsiConference} conference - JitsiConference instance that created us.\r\n     * @param {Object} createVADProcessor - Function that creates a Voice activity detection processor. The processor\r\n     * needs to implement the following functions:\r\n     * - <tt>getSampleLength()</tt> - Returns the sample size accepted by getSampleLength.\r\n     * - <tt>getRequiredPCMFrequency()</tt> - Returns the PCM frequency at which the processor operates.\r\n     * - <tt>calculateAudioFrameVAD(pcmSample)</tt> - Process a 32 float pcm sample of getSampleLength size.\r\n     * @constructor\r\n     */\r\n    constructor(conference, createVADProcessor) {\r\n        super();\r\n\r\n        /**\r\n         * Member function that instantiates a VAD processor.\r\n         */\r\n        this._createVADProcessor = createVADProcessor;\r\n\r\n        /**\r\n         * Current {@link TrackVADEmitter}. VAD Emitter uses a {@link JitsiLocalTrack} and VAD processor to generate\r\n         * period voice probability scores.\r\n         */\r\n        this._vadEmitter = null;\r\n\r\n        /**\r\n         * Current state of the _vadEmitter\r\n         */\r\n        this._isVADEmitterRunning = false;\r\n\r\n        /**\r\n         * Array of currently attached VAD processing services.\r\n         */\r\n        this._detectionServices = [];\r\n\r\n        /**\r\n         * Promise used to chain create and destroy operations associated with TRACK_ADDED and TRACK_REMOVED events\r\n         * coming from the conference.\r\n         * Because we have an async created component (VAD Processor) we need to make sure that it's initialized before\r\n         * we destroy it ( when changing the device for instance), or when we use it from an external point of entry\r\n         * i.e. (TRACK_MUTE_CHANGED event callback).\r\n         */\r\n        this._vadInitTracker = Promise.resolve();\r\n\r\n        /**\r\n         * Listens for {@link TrackVADEmitter} events and processes them.\r\n         */\r\n        this._processVADScore = this._processVADScore.bind(this);\r\n\r\n        conference.on(JitsiConferenceEvents.TRACK_ADDED, this._trackAdded.bind(this));\r\n        conference.on(JitsiConferenceEvents.TRACK_REMOVED, this._trackRemoved.bind(this));\r\n        conference.on(JitsiConferenceEvents.TRACK_MUTE_CHANGED, this._trackMuteChanged.bind(this));\r\n    }\r\n\r\n    /**\r\n     * Attach a VAD detector service to the analyser and handle it's state changes.\r\n     *\r\n     * @param {Object} vadTMDetector\r\n     */\r\n    addVADDetectionService(vadService) {\r\n        this._detectionServices.push(vadService);\r\n        vadService.on(DETECTOR_STATE_CHANGE, () => {\r\n            // When the state of a detector changes check if there are any active detectors attached so that\r\n            // the _vadEmitter doesn't run needlessly.\r\n            const activeDetector = this._detectionServices.filter(detector => detector.isActive() === true);\r\n\r\n            // If there are no active detectors running and the vadEmitter is running then stop the emitter as it is\r\n            // uses a considerable amount of CPU. Otherwise start the service if it's stopped and there is a detector\r\n            // that needs it.\r\n            if (!activeDetector.length && this._isVADEmitterRunning) {\r\n                this._stopVADEmitter();\r\n            } else if (!this._isVADEmitterRunning) {\r\n                this._startVADEmitter();\r\n            }\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Start the {@link TrackVADEmitter} and attach the event listener.\r\n     * @returns {void}\r\n     */\r\n    _startVADEmitter() {\r\n        if (this._vadEmitter) {\r\n            this._vadEmitter.on(VAD_SCORE_PUBLISHED, this._processVADScore);\r\n            this._vadEmitter.start();\r\n            this._isVADEmitterRunning = true;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Stop the {@link TrackVADEmitter} and detach the event listener.\r\n     * @returns {void}\r\n     */\r\n    _stopVADEmitter() {\r\n        if (this._vadEmitter) {\r\n            this._vadEmitter.removeListener(VAD_SCORE_PUBLISHED, this._processVADScore);\r\n            this._vadEmitter.stop();\r\n        }\r\n        this._isVADEmitterRunning = false;\r\n    }\r\n\r\n    /**\r\n     * Listens for {@link TrackVADEmitter} events and directs them to attached services as needed.\r\n     *\r\n     * @param {Object} vadScore -VAD score emitted by {@link TrackVADEmitter}\r\n     * @param {Date}   vadScore.timestamp - Exact time at which processed PCM sample was generated.\r\n     * @param {number} vadScore.score - VAD score on a scale from 0 to 1 (i.e. 0.7)\r\n     * @param {Float32Array} pcmData - Raw PCM data with which the VAD score was calculated.\r\n     * @param {string} vadScore.deviceId - Device id of the associated track.\r\n     * @listens VAD_SCORE_PUBLISHED\r\n     */\r\n    _processVADScore(vadScore) {\r\n        for (const detector of this._detectionServices) {\r\n            detector.processVADScore(vadScore);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Change the isMuted state of all attached detection services.\r\n     *\r\n     * @param {boolean} isMuted\r\n     */\r\n    _changeDetectorsMuteState(isMuted) {\r\n        for (const detector of this._detectionServices) {\r\n            detector.changeMuteState(isMuted);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Notifies the detector that a track was added to the associated {@link JitsiConference}.\r\n     * Only take into account local audio tracks.\r\n     * @param {JitsiTrack} track - The added track.\r\n     * @returns {void}\r\n     * @listens TRACK_ADDED\r\n     */\r\n    _trackAdded(track) {\r\n        if (track.isLocalAudioTrack()) {\r\n            // Keep a track promise so we take into account successive TRACK_ADD events being generated so that we\r\n            // destroy/create the processing context in the proper order.\r\n            this._vadInitTracker = this._vadInitTracker.then(() => this._createVADProcessor())\r\n                .then(vadProcessor =>\r\n                    TrackVADEmitter.create(track.getDeviceId(), VAD_EMITTER_SAMPLE_RATE, vadProcessor)\r\n                )\r\n                .then(vadEmitter => {\r\n                    logger.debug('Created VAD emitter for track: ', track.getTrackLabel());\r\n\r\n                    this._vadEmitter = vadEmitter;\r\n\r\n                    // Iterate through the detection services and set their appropriate mute state, depending on\r\n                    // service this will trigger a DETECTOR_STATE_CHANGE which in turn might start the _vadEmitter.\r\n                    this._changeDetectorsMuteState(track.isMuted());\r\n                })\r\n                .catch(error => {\r\n                    logger.warn('Failed to start VADAudioAnalyser', error);\r\n                });\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Notifies the detector that the mute state of a {@link JitsiConference} track has changed. Only takes into account\r\n     * local audio tracks.\r\n     * @param {JitsiTrack} track - The track whose mute state has changed.\r\n     * @returns {void}\r\n     * @listens TRACK_MUTE_CHANGED\r\n     */\r\n    _trackMuteChanged(track) {\r\n        if (track.isLocalAudioTrack()) {\r\n            // On a mute toggle reset the state.\r\n            this._vadInitTracker = this._vadInitTracker.then(() => {\r\n                // Set mute status for the attached detection services.\r\n                this._changeDetectorsMuteState(track.isMuted());\r\n            });\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Notifies the detector that a track associated with the {@link JitsiConference} was removed. Only takes into\r\n     * account local audio tracks. Cleans up resources associated with the track and resets the processing context.\r\n     *\r\n     * @param {JitsiTrack} track - The removed track.\r\n     * @returns {void}\r\n     * @listens TRACK_REMOVED\r\n     */\r\n    _trackRemoved(track) {\r\n        if (track.isLocalAudioTrack()) {\r\n            // Use the promise to make sure operations are in sequence.\r\n            this._vadInitTracker = this._vadInitTracker.then(() => {\r\n                logger.debug('Removing track from VAD detection - ', track.getTrackLabel());\r\n\r\n                // Track was removed, clean up and set appropriate states.\r\n                if (this._vadEmitter) {\r\n                    this._stopVADEmitter();\r\n                    this._vadEmitter.destroy();\r\n                    this._vadEmitter = null;\r\n                }\r\n\r\n                // Reset state of detectors when active track is removed.\r\n                for (const detector of this._detectionServices) {\r\n                    detector.reset();\r\n                }\r\n            });\r\n        }\r\n    }\r\n\r\n\r\n}\r\n","import { EventEmitter } from 'events';\r\n\r\nimport { calculateAverage, filterPositiveValues } from '../util/MathUtil';\r\n\r\nimport { DETECTOR_STATE_CHANGE, VAD_NOISY_DEVICE } from './DetectionEvents';\r\n\r\n/**\r\n * The average value VAD needs to be under over a period of time to be considered noise.\r\n * @type {number}\r\n */\r\nconst VAD_NOISE_AVG_THRESHOLD = 0.2;\r\n\r\n/**\r\n * The average values that audio input need to be over to be considered loud.\r\n * @type {number}\r\n */\r\nconst NOISY_AUDIO_LEVEL_THRESHOLD = 0.040;\r\n\r\n/**\r\n * The value that a VAD score needs to be under in order for processing to begin.\r\n * @type {number}\r\n */\r\nconst VAD_SCORE_TRIGGER = 0.2;\r\n\r\n/**\r\n * The value that a VAD score needs to be under in order for processing to begin.\r\n * @type {number}\r\n */\r\nconst AUDIO_LEVEL_SCORE_TRIGGER = 0.020;\r\n\r\n/**\r\n * Time span over which we calculate an average score used to determine if we trigger the event.\r\n * @type {number}\r\n */\r\nconst PROCESS_TIME_FRAME_SPAN_MS = 1500;\r\n\r\n/**\r\n * Detect if provided VAD score and PCM data is considered noise.\r\n */\r\nexport default class VADNoiseDetection extends EventEmitter {\r\n    /**\r\n     * Creates <tt>VADNoiseDetection</tt>\r\n     *\r\n     * @constructor\r\n     */\r\n    constructor() {\r\n        super();\r\n\r\n        /**\r\n         * Flag which denotes the current state of the detection service i.e.if there is already a processing operation\r\n         * ongoing.\r\n         */\r\n        this._processing = false;\r\n\r\n        /**\r\n         * Buffer that keeps the VAD scores for a period of time.\r\n         */\r\n        this._scoreArray = [];\r\n\r\n        /**\r\n         * Buffer that keeps audio level samples for a period of time.\r\n         */\r\n        this._audioLvlArray = [];\r\n\r\n        /**\r\n         * Current state of the service, if it's not active no processing will occur.\r\n         */\r\n        this._active = false;\r\n\r\n        this._calculateNoisyScore = this._calculateNoisyScore.bind(this);\r\n    }\r\n\r\n    /**\r\n     * Compute cumulative VAD score and PCM audio levels once the PROCESS_TIME_FRAME_SPAN_MS timeout has elapsed.\r\n     * If the score is above the set threshold fire the event.\r\n     * @returns {void}\r\n     * @fires VAD_NOISY_DEVICE\r\n     */\r\n    _calculateNoisyScore() {\r\n        const scoreAvg = calculateAverage(this._scoreArray);\r\n        const audioLevelAvg = calculateAverage(this._audioLvlArray);\r\n\r\n        if (scoreAvg < VAD_NOISE_AVG_THRESHOLD && audioLevelAvg > NOISY_AUDIO_LEVEL_THRESHOLD) {\r\n            this.emit(VAD_NOISY_DEVICE);\r\n\r\n            this._setActiveState(false);\r\n        }\r\n\r\n        // We reset the context in case a new process phase needs to be triggered.\r\n        this.reset();\r\n    }\r\n\r\n    /**\r\n     * Record the vad score and average volume in the appropriate buffers.\r\n     *\r\n     * @param {number} vadScore\r\n     * @param {number} avgAudioLvl - average audio level of the PCM sample associated with the VAD score.s\r\n     */\r\n    _recordValues(vadScore, avgAudioLvl) {\r\n        this._scoreArray.push(vadScore);\r\n        this._audioLvlArray.push(avgAudioLvl);\r\n    }\r\n\r\n    /**\r\n     * Set the active state of the detection service and notify any listeners.\r\n     *\r\n     * @param {boolean} active\r\n     * @fires DETECTOR_STATE_CHANGE\r\n     */\r\n    _setActiveState(active) {\r\n        this._active = active;\r\n        this.emit(DETECTOR_STATE_CHANGE, this._active);\r\n    }\r\n\r\n    /**\r\n     * Change the state according to the muted status of the tracked device.\r\n     *\r\n     * @param {boolean} isMuted - Is the device muted or not.\r\n     */\r\n    changeMuteState(isMuted) {\r\n        // This service only needs to run when the microphone is not muted.\r\n        this._setActiveState(!isMuted);\r\n        this.reset();\r\n    }\r\n\r\n    /**\r\n     * Check whether or not the service is active or not.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isActive() {\r\n        return this._active;\r\n    }\r\n\r\n    /**\r\n     * Reset the processing context, clear buffers, cancel the timeout trigger.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    reset() {\r\n        this._processing = false;\r\n        this._scoreArray = [];\r\n        this._audioLvlArray = [];\r\n        clearTimeout(this._processTimeout);\r\n    }\r\n\r\n    /**\r\n     * Listens for {@link TrackVADEmitter} events and processes them.\r\n     *\r\n     * @param {Object} vadScore -VAD score emitted by {@link TrackVADEmitter}\r\n     * @param {Date}   vadScore.timestamp - Exact time at which processed PCM sample was generated.\r\n     * @param {number} vadScore.score - VAD score on a scale from 0 to 1 (i.e. 0.7)\r\n     * @param {Float32Array} vadScore.pcmData - Raw PCM Data associated with the VAD score.\r\n     * @param {string} vadScore.deviceId - Device id of the associated track.\r\n     * @listens VAD_SCORE_PUBLISHED\r\n     */\r\n    processVADScore(vadScore) {\r\n        if (!this._active) {\r\n            return;\r\n        }\r\n\r\n        // There is a processing phase on going, add score to buffer array.\r\n        if (this._processing) {\r\n            // Filter and calculate sample average so we don't have to process one large array at a time.\r\n            const posAudioLevels = filterPositiveValues(vadScore.pcmData);\r\n\r\n            this._recordValues(vadScore.score, calculateAverage(posAudioLevels));\r\n\r\n            return;\r\n        }\r\n\r\n        // If the VAD score for the sample is low and audio level has a high enough level we can start listening for\r\n        // noise\r\n        if (vadScore.score < VAD_SCORE_TRIGGER) {\r\n            const posAudioLevels = filterPositiveValues(vadScore.pcmData);\r\n            const avgAudioLvl = calculateAverage(posAudioLevels);\r\n\r\n            if (avgAudioLvl > AUDIO_LEVEL_SCORE_TRIGGER) {\r\n                this._processing = true;\r\n                this._recordValues(vadScore.score, avgAudioLvl);\r\n\r\n                // Once the preset timeout executes the final score will be calculated.\r\n                this._processTimeout = setTimeout(this._calculateNoisyScore, PROCESS_TIME_FRAME_SPAN_MS);\r\n            }\r\n        }\r\n    }\r\n}\r\n","import { EventEmitter } from 'events';\r\n\r\nimport { calculateAverage } from '../util/MathUtil';\r\n\r\nimport { DETECTOR_STATE_CHANGE, VAD_TALK_WHILE_MUTED } from './DetectionEvents';\r\n\r\n\r\n/**\r\n * The threshold which the average VAD values for a span of time needs to exceed to trigger an event.\r\n * @type {number}\r\n */\r\nconst VAD_AVG_THRESHOLD = 0.6;\r\n\r\n/**\r\n * The VAD score needed to trigger the processing algorithm, i.e. if a sample has the VAD score >= VAD_VOICE_LEVEL\r\n * we start processing all scores for a time span defined by const PROCESS_TIME_FRAME_SPAN_MS.\r\n * @type {number}\r\n */\r\nconst VAD_VOICE_LEVEL = 0.9;\r\n\r\n/**\r\n * Sample rate of TrackVADEmitter, it defines how many audio samples are processed at a time.\r\n * @type {number}\r\n */\r\n\r\n/**\r\n * Time span over which we calculate an average score used to determine if we trigger the event.\r\n * @type {number}\r\n */\r\nconst PROCESS_TIME_FRAME_SPAN_MS = 700;\r\n\r\n/**\r\n * Detect if provided VAD score which is generated on a muted device is voice and fires an event.\r\n */\r\nexport default class VADTalkMutedDetection extends EventEmitter {\r\n    /**\r\n     * Creates <tt>VADTalkMutedDetection</tt>\r\n     * @constructor\r\n     */\r\n    constructor() {\r\n        super();\r\n\r\n        /**\r\n         * Flag which denotes the current state of the detection service i.e.if there is already a processing operation\r\n         * ongoing.\r\n         */\r\n        this._processing = false;\r\n\r\n        /**\r\n         * Buffer that keeps the VAD scores for a period of time.\r\n         */\r\n        this._scoreArray = [];\r\n\r\n        /**\r\n         * Current mute state of the audio track being monitored.\r\n         */\r\n        this._active = false;\r\n\r\n        this._calculateVADScore = this._calculateVADScore.bind(this);\r\n    }\r\n\r\n    /**\r\n     * Compute cumulative VAD score function called once the PROCESS_TIME_FRAME_SPAN_MS timeout has elapsed.\r\n     * @returns {void}\r\n     * @fires VAD_TALK_WHILE_MUTED\r\n     */\r\n    _calculateVADScore() {\r\n        const score = calculateAverage(this._scoreArray);\r\n\r\n        if (score > VAD_AVG_THRESHOLD) {\r\n            this.emit(VAD_TALK_WHILE_MUTED);\r\n\r\n            // Event was fired. Stop event emitter and remove listeners so no residue events kick off after this point\r\n            // and a single VAD_TALK_WHILE_MUTED is generated per mic muted state.\r\n            this._setActiveState(false);\r\n        }\r\n\r\n        // We reset the context in case a new process phase needs to be triggered.\r\n        this.reset();\r\n    }\r\n\r\n    /**\r\n     * Set the active state of the detection service and notify any listeners.\r\n     *\r\n     * @param {boolean} active\r\n     * @fires DETECTOR_STATE_CHANGE\r\n     */\r\n    _setActiveState(active) {\r\n        this._active = active;\r\n        this.emit(DETECTOR_STATE_CHANGE, this._active);\r\n    }\r\n\r\n    /**\r\n     * Change the state according to the muted status of the tracked device.\r\n     *\r\n     * @param {boolean} isMuted - Is the device muted or not.\r\n     */\r\n    changeMuteState(isMuted) {\r\n        // This service only needs to run when the microphone is muted.\r\n        this._setActiveState(isMuted);\r\n        this.reset();\r\n    }\r\n\r\n    /**\r\n     * Check whether or not the service is active or not.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isActive() {\r\n        return this._active;\r\n    }\r\n\r\n    /**\r\n     * Listens for {@link TrackVADEmitter} events and processes them.\r\n     *\r\n     * @param {Object} vadScore -VAD score emitted by {@link TrackVADEmitter}\r\n     * @param {Date}   vadScore.timestamp - Exact time at which processed PCM sample was generated.\r\n     * @param {number} vadScore.score - VAD score on a scale from 0 to 1 (i.e. 0.7)\r\n     * @param {string} vadScore.deviceId - Device id of the associated track.\r\n     * @listens VAD_SCORE_PUBLISHED\r\n     */\r\n    processVADScore(vadScore) {\r\n        if (!this._active) {\r\n            return;\r\n        }\r\n\r\n        // There is a processing phase on going, add score to buffer array.\r\n        if (this._processing) {\r\n            this._scoreArray.push(vadScore.score);\r\n\r\n            return;\r\n        }\r\n\r\n        // Because we remove all listeners on the vadEmitter once the main event is triggered,\r\n        // there is no need to check for rogue events.\r\n        if (vadScore.score > VAD_VOICE_LEVEL) {\r\n            this._processing = true;\r\n            this._scoreArray.push(vadScore.score);\r\n\r\n            // Start gathering VAD scores for the configured period of time.\r\n            this._processTimeout = setTimeout(this._calculateVADScore, PROCESS_TIME_FRAME_SPAN_MS);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Reset the processing context, clear buffer, cancel the timeout trigger.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    reset() {\r\n        this._processing = false;\r\n        this._scoreArray = [];\r\n        clearTimeout(this._processTimeout);\r\n    }\r\n}\r\n","export enum E2ePingEvents {\r\n    /**\r\n     * Indicates that the end-to-end round-trip-time for a participant has changed.\r\n     */\r\n    E2E_RTT_CHANGED = 'e2eping.e2e_rtt_changed'\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const E2E_RTT_CHANGED = E2ePingEvents.E2E_RTT_CHANGED;\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\nimport * as JitsiE2EPingEvents from '../../service/e2eping/E2ePingEvents';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * The 'type' of a message which designates an e2e ping request.\r\n * @type {string}\r\n */\r\nconst E2E_PING_REQUEST = 'e2e-ping-request';\r\n\r\n/**\r\n * The 'type' of a message which designates an e2e ping response.\r\n * @type {string}\r\n */\r\nconst E2E_PING_RESPONSE = 'e2e-ping-response';\r\n\r\n/**\r\n * The number of requests to wait for before emitting an RTT value.\r\n */\r\nconst DEFAULT_NUM_REQUESTS = 5;\r\n\r\n/**\r\n * The maximum number of messages per second to aim for. This is for the entire\r\n * conference, with the assumption that all endpoints join at once.\r\n */\r\nconst DEFAULT_MAX_MESSAGES_PER_SECOND = 250;\r\n\r\n/**\r\n * The conference size beyond which e2e pings will be disabled.\r\n */\r\nconst DEFAULT_MAX_CONFERENCE_SIZE = 200;\r\n\r\n/**\r\n * Saves e2e ping related state for a single JitsiParticipant.\r\n */\r\nclass ParticipantWrapper {\r\n    /**\r\n     * Creates a ParticipantWrapper\r\n     * @param {JitsiParticipant} participant - The remote participant that this\r\n     * object wraps.\r\n     * @param {E2ePing} e2eping\r\n     */\r\n    constructor(participant, e2eping) {\r\n        // The JitsiParticipant\r\n        this.participant = participant;\r\n\r\n        // The E2ePing\r\n        this.e2eping = e2eping;\r\n\r\n        // Caches the ID\r\n        this.id = participant.getId();\r\n\r\n        // Recently sent requests\r\n        this.requests = {};\r\n\r\n        // The ID of the last sent request. We just increment it for each new\r\n        // request. Start at 1 so we can consider only thruthy values valid.\r\n        this.lastRequestId = 1;\r\n\r\n        this.sendRequest = this.sendRequest.bind(this);\r\n        this.handleResponse = this.handleResponse.bind(this);\r\n        this.maybeLogRttAndStop = this.maybeLogRttAndStop.bind(this);\r\n        this.scheduleNext = this.scheduleNext.bind(this);\r\n        this.stop = this.stop.bind(this);\r\n        this.getDelay = this.getDelay.bind(this);\r\n        this.timeout = this.scheduleNext();\r\n    }\r\n\r\n    /**\r\n     * Schedule the next ping to be sent.\r\n     */\r\n    scheduleNext() {\r\n        return window.setTimeout(this.sendRequest, this.getDelay());\r\n    }\r\n\r\n    /**\r\n     * Stop pinging this participant, canceling a scheduled ping, if any.\r\n     */\r\n    stop() {\r\n        if (this.timeout) {\r\n            window.clearTimeout(this.timeout);\r\n        }\r\n        this.e2eping.removeParticipant(this.id);\r\n    }\r\n\r\n    /**\r\n     * Get the delay until the next ping in milliseconds.\r\n     */\r\n    getDelay() {\r\n        const conferenceSize = this.e2eping.conference.getParticipants().length;\r\n        const endpointPairs = conferenceSize * (conferenceSize - 1) / 2;\r\n        const totalMessages = endpointPairs * this.e2eping.numRequests;\r\n        const totalSeconds = totalMessages / this.e2eping.maxMessagesPerSecond;\r\n\r\n        // Randomize between .5 and 1.5\r\n        const r = 1.5 - Math.random();\r\n        const delayBetweenMessages = r * Math.max(1000 * (totalSeconds / this.e2eping.numRequests), 1000);\r\n\r\n        return delayBetweenMessages;\r\n    }\r\n\r\n    /**\r\n     * Sends the next ping request.\r\n     * @type {*}\r\n     */\r\n    sendRequest() {\r\n        const requestId = this.lastRequestId++;\r\n        const requestMessage = {\r\n            type: E2E_PING_REQUEST,\r\n            id: requestId\r\n        };\r\n\r\n        this.e2eping.sendMessage(requestMessage, this.id);\r\n        this.requests[requestId] = {\r\n            id: requestId,\r\n            timeSent: window.performance.now()\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Handles a response from this participant.\r\n     * @type {*}\r\n     */\r\n    handleResponse(response) {\r\n        const request = this.requests[response.id];\r\n\r\n        if (request) {\r\n            request.rtt = window.performance.now() - request.timeSent;\r\n        }\r\n        this.maybeLogRttAndStop();\r\n    }\r\n\r\n    /**\r\n     * Check if we've received the pre-configured number of responses, and if\r\n     * so log the measured RTT and stop sending requests.\r\n     * @type {*}\r\n     */\r\n    maybeLogRttAndStop() {\r\n        // The RTT we'll report is the minimum RTT measured\r\n        let rtt = Infinity;\r\n        let request, requestId;\r\n        let numRequestsWithResponses = 0;\r\n        let totalNumRequests = 0;\r\n\r\n        for (requestId in this.requests) {\r\n            if (this.requests.hasOwnProperty(requestId)) {\r\n                request = this.requests[requestId];\r\n\r\n                totalNumRequests++;\r\n                if (request.rtt) {\r\n                    numRequestsWithResponses++;\r\n                    rtt = Math.min(rtt, request.rtt);\r\n                }\r\n            }\r\n        }\r\n\r\n        if (numRequestsWithResponses >= this.e2eping.numRequests) {\r\n            logger.info(`Measured RTT=${rtt} ms to ${this.id} (in ${this.participant.getProperty('region')})`);\r\n            this.stop();\r\n\r\n            this.e2eping.conference.eventEmitter.emit(\r\n                JitsiE2EPingEvents.E2E_RTT_CHANGED, this.participant, rtt);\r\n\r\n            return;\r\n        } else if (totalNumRequests > 2 * this.e2eping.numRequests) {\r\n            logger.info(`Stopping e2eping for ${this.id} because we sent ${totalNumRequests} with only `\r\n                + `${numRequestsWithResponses} responses.`);\r\n            this.stop();\r\n\r\n            return;\r\n        }\r\n\r\n        this.timeout = this.scheduleNext();\r\n    }\r\n}\r\n\r\n/**\r\n * Implements end-to-end ping (from one conference participant to another) via\r\n * the jitsi-videobridge channel (either WebRTC data channel or web socket).\r\n *\r\n * TODO: use a broadcast message instead of individual pings to each remote\r\n * participant.\r\n *\r\n * This class:\r\n * 1. Sends periodic ping requests to all other participants in the\r\n * conference.\r\n * 2. Responds to ping requests from other participants.\r\n * 3. Fires events with the end-to-end RTT to each participant whenever a\r\n * response is received.\r\n * 4. Fires analytics events with the end-to-end RTT periodically.\r\n */\r\nexport default class E2ePing {\r\n    /**\r\n     * @param {JitsiConference} conference - The conference.\r\n     * @param {Function} sendMessage - The function to use to send a message.\r\n     * @param {Object} options\r\n     */\r\n    constructor(conference, options, sendMessage) {\r\n        this.conference = conference;\r\n        this.eventEmitter = conference.eventEmitter;\r\n        this.sendMessage = sendMessage;\r\n\r\n        // Maps a participant ID to its ParticipantWrapper\r\n        this.participants = {};\r\n\r\n        this.numRequests = DEFAULT_NUM_REQUESTS;\r\n        this.maxConferenceSize = DEFAULT_MAX_CONFERENCE_SIZE;\r\n        this.maxMessagesPerSecond = DEFAULT_MAX_MESSAGES_PER_SECOND;\r\n\r\n        if (options && options.e2eping) {\r\n            if (typeof options.e2eping.numRequests === 'number') {\r\n                this.numRequests = options.e2eping.numRequests;\r\n            }\r\n            if (typeof options.e2eping.maxConferenceSize === 'number') {\r\n                this.maxConferenceSize = options.e2eping.maxConferenceSize;\r\n            }\r\n            if (typeof options.e2eping.maxMessagesPerSecond === 'number') {\r\n                this.maxMessagesPerSecond = options.e2eping.maxMessagesPerSecond;\r\n            }\r\n        }\r\n        logger.info(\r\n            `Initializing e2e ping with numRequests=${this.numRequests}, maxConferenceSize=${this.maxConferenceSize}, `\r\n            + `maxMessagesPerSecond=${this.maxMessagesPerSecond}.`);\r\n\r\n        this.participantJoined = this.participantJoined.bind(this);\r\n\r\n        this.participantLeft = this.participantLeft.bind(this);\r\n        conference.on(JitsiConferenceEvents.USER_LEFT, this.participantLeft);\r\n\r\n        this.messageReceived = this.messageReceived.bind(this);\r\n        conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, this.messageReceived);\r\n\r\n        this.conferenceJoined = this.conferenceJoined.bind(this);\r\n        conference.on(JitsiConferenceEvents.CONFERENCE_JOINED, this.conferenceJoined);\r\n    }\r\n\r\n    /**\r\n     * Delay processing USER_JOINED events until the MUC is fully joined,\r\n     * otherwise the apparent conference size will be wrong.\r\n     */\r\n    conferenceJoined() {\r\n        this.conference.getParticipants().forEach(p => this.participantJoined(p.getId(), p));\r\n        this.conference.on(JitsiConferenceEvents.USER_JOINED, this.participantJoined);\r\n    }\r\n\r\n    /**\r\n     * Handles a message that was received.\r\n     *\r\n     * @param participant - The message sender.\r\n     * @param payload - The payload of the message.\r\n     */\r\n    messageReceived(participant, payload) {\r\n        // Listen to E2E PING requests and responses from other participants\r\n        // in the conference.\r\n        if (payload.type === E2E_PING_REQUEST) {\r\n            this.handleRequest(participant.getId(), payload);\r\n        } else if (payload.type === E2E_PING_RESPONSE) {\r\n            this.handleResponse(participant.getId(), payload);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Handles a participant joining the conference. Starts to send ping\r\n     * requests to the participant.\r\n     *\r\n     * @param {String} id - The ID of the participant.\r\n     * @param {JitsiParticipant} participant - The participant that joined.\r\n     */\r\n    participantJoined(id, participant) {\r\n        if (this.participants[id]) {\r\n            logger.info(`Participant wrapper already exists for ${id}. Clearing.`);\r\n            this.participants[id].stop();\r\n        }\r\n\r\n        if (this.conference.getParticipants().length > this.maxConferenceSize) {\r\n            return;\r\n        }\r\n\r\n        // We don't need to send e2eping in both directions for a pair of\r\n        // endpoints. Force only one direction with just string comparison of\r\n        // the IDs.\r\n        if (this.conference.myUserId() > id) {\r\n            logger.info(`Starting e2eping for participant ${id}`);\r\n            this.participants[id] = new ParticipantWrapper(participant, this);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Remove a participant without calling \"stop\".\r\n     */\r\n    removeParticipant(id) {\r\n        if (this.participants[id]) {\r\n            delete this.participants[id];\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Handles a participant leaving the conference. Stops sending requests.\r\n     *\r\n     * @param {String} id - The ID of the participant.\r\n     */\r\n    participantLeft(id) {\r\n        if (this.participants[id]) {\r\n            this.participants[id].stop();\r\n            delete this.participants[id];\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Handles a ping request coming from another participant.\r\n     *\r\n     * @param {string} participantId - The ID of the participant who sent the\r\n     * request.\r\n     * @param {Object} request - The request.\r\n     */\r\n    handleRequest(participantId, request) {\r\n        // If it's a valid request, just send a response.\r\n        if (request && request.id) {\r\n            const response = {\r\n                type: E2E_PING_RESPONSE,\r\n                id: request.id\r\n            };\r\n\r\n            this.sendMessage(response, participantId);\r\n        } else {\r\n            logger.info(`Received an invalid e2e ping request from ${participantId}.`);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Handles a ping response coming from another participant\r\n     * @param {string} participantId - The ID of the participant who sent the\r\n     * response.\r\n     * @param {Object} response - The response.\r\n     */\r\n    handleResponse(participantId, response) {\r\n        const participantWrapper = this.participants[participantId];\r\n\r\n        if (participantWrapper) {\r\n            participantWrapper.handleResponse(response);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Stops this E2ePing (i.e. stop sending requests).\r\n     */\r\n    stop() {\r\n        logger.info('Stopping e2eping');\r\n\r\n        this.conference.off(JitsiConferenceEvents.USER_JOINED, this.participantJoined);\r\n        this.conference.off(JitsiConferenceEvents.USER_LEFT, this.participantLeft);\r\n        this.conference.off(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, this.messageReceived);\r\n\r\n        for (const id in this.participants) {\r\n            if (this.participants.hasOwnProperty(id)) {\r\n                this.participants[id].stop();\r\n            }\r\n        }\r\n\r\n        this.participants = {};\r\n    }\r\n}\r\n\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Emits {@link JitsiConferenceEvents.JVB121_STATUS} events based on the current\r\n * P2P status and the conference participants count. See the event description\r\n * for more info.\r\n */\r\nexport default class Jvb121EventGenerator {\r\n    /**\r\n     * Creates new <tt>Jvb121EventGenerator</tt> for the given conference.\r\n     * @param {JitsiConference} conference\r\n     */\r\n    constructor(conference) {\r\n        this._conference = conference;\r\n\r\n        /**\r\n         * Indicates whether it's a one to one JVB conference (<tt>true</tt>)\r\n         * or a multiparty (<tt>false</tt>). Will be also <tt>false</tt> if\r\n         * the conference is currently in the P2P mode.\r\n         * @type {boolean}\r\n         * @private\r\n         */\r\n        this._jvb121 = true;\r\n\r\n        this._conference.addEventListener(\r\n            JitsiConferenceEvents.USER_JOINED, () => this.evaluateStatus());\r\n        this._conference.addEventListener(\r\n            JitsiConferenceEvents.USER_LEFT, () => this.evaluateStatus());\r\n        this._conference.addEventListener(\r\n            JitsiConferenceEvents.P2P_STATUS, () => this.evaluateStatus());\r\n    }\r\n\r\n    /**\r\n     * Checks whether the JVB121 value should be updated and a new event\r\n     * emitted.\r\n     */\r\n    evaluateStatus() {\r\n        const oldStatus = this._jvb121;\r\n        const newStatus\r\n            = !this._conference.isP2PActive()\r\n                && this._conference.getParticipantCount() <= 2;\r\n\r\n        if (oldStatus !== newStatus) {\r\n            this._jvb121 = newStatus;\r\n            logger.debug(`JVB121 status ${oldStatus} => ${newStatus}`);\r\n            this._conference.eventEmitter.emit(\r\n                JitsiConferenceEvents.JVB121_STATUS, oldStatus, newStatus);\r\n        }\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport isEqual from 'lodash.isequal';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\n\r\nconst logger = getLogger(__filename);\r\nconst MAX_HEIGHT_ONSTAGE = 2160;\r\nconst MAX_HEIGHT_THUMBNAIL = 180;\r\nconst LASTN_UNLIMITED = -1;\r\n\r\n/**\r\n * This class translates the legacy signaling format between the client and the bridge (that affects bandwidth\r\n * allocation) to the new format described here https://github.com/jitsi/jitsi-videobridge/blob/master/doc/allocation.md\r\n */\r\nclass ReceiverVideoConstraints {\r\n    /**\r\n     * Creates a new instance.\r\n     */\r\n    constructor() {\r\n        // Default constraints used for endpoints that are not explicitly included in constraints.\r\n        // These constraints are used for endpoints that are thumbnails in the stage view.\r\n        this._defaultConstraints = { 'maxHeight': MAX_HEIGHT_THUMBNAIL };\r\n\r\n        // The number of videos requested from the bridge.\r\n        this._lastN = LASTN_UNLIMITED;\r\n\r\n        // The number representing the maximum video height the local client should receive from the bridge.\r\n        this._maxFrameHeight = MAX_HEIGHT_ONSTAGE;\r\n\r\n        // The endpoint IDs of the participants that are currently selected.\r\n        this._selectedEndpoints = [];\r\n\r\n        this._receiverVideoConstraints = {\r\n            constraints: {},\r\n            defaultConstraints: this.defaultConstraints,\r\n            lastN: this._lastN,\r\n            onStageEndpoints: [],\r\n            selectedEndpoints: this._selectedEndpoints\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Returns the receiver video constraints that need to be sent on the bridge channel.\r\n     */\r\n    get constraints() {\r\n        this._receiverVideoConstraints.lastN = this._lastN;\r\n\r\n        if (!this._selectedEndpoints.length) {\r\n            return this._receiverVideoConstraints;\r\n        }\r\n\r\n        // The client is assumed to be in TileView if it has selected more than one endpoint, otherwise it is\r\n        // assumed to be in StageView.\r\n        this._receiverVideoConstraints.constraints = {};\r\n        if (this._selectedEndpoints.length > 1) {\r\n            /**\r\n             * Tile view.\r\n             * Only the default constraints are specified here along with lastN (if it is set).\r\n             * {\r\n             *  'colibriClass': 'ReceiverVideoConstraints',\r\n             *  'defaultConstraints': { 'maxHeight': 360 }\r\n             * }\r\n             */\r\n            this._receiverVideoConstraints.defaultConstraints = { 'maxHeight': this._maxFrameHeight };\r\n            this._receiverVideoConstraints.onStageEndpoints = [];\r\n            this._receiverVideoConstraints.selectedEndpoints = [];\r\n        } else {\r\n            /**\r\n             * Stage view.\r\n             * The participant on stage is specified in onStageEndpoints and a higher maxHeight is specified\r\n             * for that endpoint while a default maxHeight of 180 is applied to all the other endpoints.\r\n             * {\r\n             *  'colibriClass': 'ReceiverVideoConstraints',\r\n             *  'onStageEndpoints': ['A'],\r\n             *  'defaultConstraints': { 'maxHeight':  180 },\r\n             *  'constraints': {\r\n             *      'A': { 'maxHeight': 720 }\r\n             *   }\r\n             * }\r\n             */\r\n            this._receiverVideoConstraints.constraints[this._selectedEndpoints[0]] = {\r\n                'maxHeight': this._maxFrameHeight\r\n            };\r\n            this._receiverVideoConstraints.defaultConstraints = this._defaultConstraints;\r\n            this._receiverVideoConstraints.onStageEndpoints = this._selectedEndpoints;\r\n            this._receiverVideoConstraints.selectedEndpoints = [];\r\n        }\r\n\r\n        return this._receiverVideoConstraints;\r\n    }\r\n\r\n    /**\r\n     * Updates the lastN field of the ReceiverVideoConstraints sent to the bridge.\r\n     *\r\n     * @param {number} value\r\n     * @returns {boolean} Returns true if the the value has been updated, false otherwise.\r\n     */\r\n    updateLastN(value) {\r\n        const changed = this._lastN !== value;\r\n\r\n        if (changed) {\r\n            this._lastN = value;\r\n            logger.debug(`Updating ReceiverVideoConstraints lastN(${value})`);\r\n        }\r\n\r\n        return changed;\r\n    }\r\n\r\n    /**\r\n     * Updates the resolution (height requested) in the contraints field of the ReceiverVideoConstraints\r\n     * sent to the bridge.\r\n     *\r\n     * @param {number} maxFrameHeight\r\n     * @requires {boolean} Returns true if the the value has been updated, false otherwise.\r\n     */\r\n    updateReceiveResolution(maxFrameHeight) {\r\n        const changed = this._maxFrameHeight !== maxFrameHeight;\r\n\r\n        if (changed) {\r\n            this._maxFrameHeight = maxFrameHeight;\r\n            logger.debug(`Updating receive maxFrameHeight: ${maxFrameHeight}`);\r\n        }\r\n\r\n        return changed;\r\n    }\r\n\r\n    /**\r\n     * Updates the receiver constraints sent to the bridge.\r\n     *\r\n     * @param {Object} videoConstraints\r\n     * @returns {boolean} Returns true if the the value has been updated, false otherwise.\r\n     */\r\n    updateReceiverVideoConstraints(videoConstraints) {\r\n        const changed = !isEqual(this._receiverVideoConstraints, videoConstraints);\r\n\r\n        if (changed) {\r\n            this._receiverVideoConstraints = videoConstraints;\r\n            logger.debug(`Updating ReceiverVideoConstraints ${JSON.stringify(videoConstraints)}`);\r\n        }\r\n\r\n        return changed;\r\n    }\r\n\r\n    /**\r\n     * Updates the list of selected endpoints.\r\n     *\r\n     * @param {Array<string>} ids\r\n     * @returns {void}\r\n     */\r\n    updateSelectedEndpoints(ids) {\r\n        logger.debug(`Updating selected endpoints: ${JSON.stringify(ids)}`);\r\n        this._selectedEndpoints = ids;\r\n    }\r\n}\r\n\r\n/**\r\n * This class manages the receive video contraints for a given {@link JitsiConference}. These constraints are\r\n * determined by the application based on how the remote video streams need to be displayed. This class is responsible\r\n * for communicating these constraints to the bridge over the bridge channel.\r\n */\r\nexport default class ReceiveVideoController {\r\n    /**\r\n     * Creates a new instance for a given conference.\r\n     *\r\n     * @param {JitsiConference} conference the conference instance for which the new instance will be managing\r\n     * the receive video quality constraints.\r\n     * @param {RTC} rtc the rtc instance which is responsible for initializing the bridge channel.\r\n     */\r\n    constructor(conference, rtc) {\r\n        this._conference = conference;\r\n        this._rtc = rtc;\r\n\r\n        const { config } = conference.options;\r\n\r\n        // The number of videos requested from the bridge, -1 represents unlimited or all available videos.\r\n        this._lastN = config?.startLastN ?? (config?.channelLastN || LASTN_UNLIMITED);\r\n\r\n        // The number representing the maximum video height the local client should receive from the bridge.\r\n        this._maxFrameHeight = MAX_HEIGHT_ONSTAGE;\r\n\r\n        /**\r\n         * The map that holds the max frame height requested for each remote source when source-name signaling is\r\n         * enabled.\r\n         *\r\n         * @type Map<string, number>\r\n         */\r\n        this._sourceReceiverConstraints = new Map();\r\n\r\n        // Enable new receiver constraints by default unless it is explicitly disabled through config.js.\r\n        const useNewReceiverConstraints = config?.useNewBandwidthAllocationStrategy ?? true;\r\n\r\n        if (useNewReceiverConstraints) {\r\n            this._receiverVideoConstraints = new ReceiverVideoConstraints();\r\n            const lastNUpdated = this._receiverVideoConstraints.updateLastN(this._lastN);\r\n\r\n            lastNUpdated && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\r\n        } else {\r\n            this._rtc.setLastN(this._lastN);\r\n        }\r\n\r\n        // The endpoint IDs of the participants that are currently selected.\r\n        this._selectedEndpoints = [];\r\n\r\n        this._conference.on(\r\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\r\n            session => this._onMediaSessionStarted(session));\r\n    }\r\n\r\n    /**\r\n     * Returns a map of all the remote source names and the corresponding max frame heights.\r\n     *\r\n     * @param {number} maxFrameHeight\r\n     * @returns\r\n     */\r\n    _getDefaultSourceReceiverConstraints(mediaSession, maxFrameHeight) {\r\n        const remoteVideoTracks = mediaSession.peerconnection?.getRemoteTracks(null, MediaType.VIDEO) || [];\r\n        const receiverConstraints = new Map();\r\n\r\n        for (const track of remoteVideoTracks) {\r\n            receiverConstraints.set(track.getSourceName(), maxFrameHeight);\r\n        }\r\n\r\n        return receiverConstraints;\r\n    }\r\n\r\n    /**\r\n     * Handles the {@link JitsiConferenceEvents.MEDIA_SESSION_STARTED}, that is when the conference creates new media\r\n     * session. The preferred receive frameHeight is applied on the media session.\r\n     *\r\n     * @param {JingleSessionPC} mediaSession - the started media session.\r\n     * @returns {void}\r\n     * @private\r\n     */\r\n    _onMediaSessionStarted(mediaSession) {\r\n        if (mediaSession.isP2P || !this._receiverVideoConstraints) {\r\n            mediaSession.setReceiverVideoConstraint(this._maxFrameHeight, this._sourceReceiverConstraints);\r\n        } else {\r\n            this._receiverVideoConstraints.updateReceiveResolution(this._maxFrameHeight);\r\n            this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns the lastN value for the conference.\r\n     *\r\n     * @returns {number}\r\n     */\r\n    getLastN() {\r\n        return this._lastN;\r\n    }\r\n\r\n    /**\r\n     * Elects the participants with the given ids to be the selected participants in order to always receive video\r\n     * for this participant (even when last n is enabled).\r\n     *\r\n     * @param {Array<string>} ids - The user ids.\r\n     * @returns {void}\r\n     */\r\n    selectEndpoints(ids) {\r\n        this._selectedEndpoints = ids;\r\n\r\n        if (this._receiverVideoConstraints) {\r\n            // Filter out the local endpointId from the list of selected endpoints.\r\n            const remoteEndpointIds = ids.filter(id => id !== this._conference.myUserId());\r\n            const oldConstraints = JSON.parse(JSON.stringify(this._receiverVideoConstraints.constraints));\r\n\r\n            remoteEndpointIds.length && this._receiverVideoConstraints.updateSelectedEndpoints(remoteEndpointIds);\r\n            const newConstraints = this._receiverVideoConstraints.constraints;\r\n\r\n            // Send bridge message only when the constraints change.\r\n            if (!isEqual(newConstraints, oldConstraints)) {\r\n                this._rtc.setNewReceiverVideoConstraints(newConstraints);\r\n            }\r\n\r\n            return;\r\n        }\r\n        this._rtc.selectEndpoints(ids);\r\n    }\r\n\r\n    /**\r\n     * Selects a new value for \"lastN\". The requested amount of videos are going to be delivered after the value is\r\n     * in effect. Set to -1 for unlimited or all available videos.\r\n     *\r\n     * @param {number} value the new value for lastN.\r\n     * @returns {void}\r\n     */\r\n    setLastN(value) {\r\n        if (this._lastN !== value) {\r\n            this._lastN = value;\r\n\r\n            if (this._receiverVideoConstraints) {\r\n                const lastNUpdated = this._receiverVideoConstraints.updateLastN(value);\r\n\r\n                // Send out the message on the bridge channel if lastN was updated.\r\n                lastNUpdated && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\r\n\r\n                return;\r\n            }\r\n            this._rtc.setLastN(value);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets the maximum video resolution the local participant should receive from remote participants.\r\n     *\r\n     * @param {number|undefined} maxFrameHeight - the new value.\r\n     * @returns {void}\r\n     */\r\n    setPreferredReceiveMaxFrameHeight(maxFrameHeight) {\r\n        this._maxFrameHeight = maxFrameHeight;\r\n\r\n        for (const session of this._conference.getMediaSessions()) {\r\n            if (session.isP2P || !this._receiverVideoConstraints) {\r\n                session.setReceiverVideoConstraint(\r\n                    maxFrameHeight,\r\n                    this._getDefaultSourceReceiverConstraints(this._maxFrameHeight));\r\n            } else {\r\n                const resolutionUpdated = this._receiverVideoConstraints.updateReceiveResolution(maxFrameHeight);\r\n\r\n                resolutionUpdated\r\n                    && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets the receiver constraints for the conference.\r\n     *\r\n     * @param {Object} constraints The video constraints.\r\n     */\r\n    setReceiverConstraints(constraints) {\r\n        if (!constraints) {\r\n            return;\r\n        }\r\n        const isEndpointsFormat = Object.keys(constraints).includes('onStageEndpoints', 'selectedEndpoints');\r\n\r\n        if (isEndpointsFormat) {\r\n            throw new Error(\r\n                '\"onStageEndpoints\" and \"selectedEndpoints\" are not supported when sourceNameSignaling is enabled.'\r\n            );\r\n        }\r\n        const constraintsChanged = this._receiverVideoConstraints.updateReceiverVideoConstraints(constraints);\r\n\r\n        if (constraintsChanged) {\r\n            this._lastN = constraints.lastN ?? this._lastN;\r\n            this._selectedEndpoints = constraints.selectedEndpoints ?? this._selectedEndpoints;\r\n            this._rtc.setNewReceiverVideoConstraints(constraints);\r\n\r\n            const p2pSession = this._conference.getMediaSessions().find(session => session.isP2P);\r\n\r\n            if (!p2pSession) {\r\n                return;\r\n            }\r\n\r\n            const mappedConstraints = Array.from(Object.entries(constraints.constraints))\r\n                .map(constraint => {\r\n                    constraint[1] = constraint[1].maxHeight;\r\n\r\n                    return constraint;\r\n                });\r\n\r\n            this._sourceReceiverConstraints = new Map(mappedConstraints);\r\n\r\n            // Send the receiver constraints to the peer through a \"content-modify\" message.\r\n            p2pSession.setReceiverVideoConstraint(null, this._sourceReceiverConstraints);\r\n        }\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\nimport RTCEvents from '../../service/RTC/RTCEvents';\r\nimport MediaSessionEvents from '../xmpp/MediaSessionEvents';\r\n\r\nconst logger = getLogger(__filename);\r\nconst MAX_LOCAL_RESOLUTION = 2160;\r\n\r\n/**\r\n * The class manages send video constraints across media sessions({@link JingleSessionPC}) which belong to\r\n * {@link JitsiConference}. It finds the lowest common value, between the local user's send preference and\r\n * the remote party's receive preference. Also this module will consider only the active session's receive value,\r\n * because local tracks are shared and while JVB may have no preference, the remote p2p may have and they may be totally\r\n * different.\r\n */\r\nexport default class SendVideoController {\r\n    /**\r\n     * Creates new instance for a given conference.\r\n     *\r\n     * @param {JitsiConference} conference - the conference instance for which the new instance will be managing\r\n     * the send video quality constraints.\r\n     * @param {RTC} rtc - the rtc instance that is responsible for sending the messages on the bridge channel.\r\n     */\r\n    constructor(conference, rtc) {\r\n        this._conference = conference;\r\n        this._preferredSendMaxFrameHeight = MAX_LOCAL_RESOLUTION;\r\n        this._rtc = rtc;\r\n\r\n        /**\r\n         * Source name based sender constraints.\r\n         * @type {Map<string, number>};\r\n         */\r\n\r\n        this._sourceSenderConstraints = new Map();\r\n        this._conference.on(\r\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\r\n            session => this._onMediaSessionStarted(session));\r\n        this._conference.on(\r\n            JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED,\r\n            () => this._configureConstraintsForLocalSources());\r\n        this._rtc.on(\r\n            RTCEvents.SENDER_VIDEO_CONSTRAINTS_CHANGED,\r\n            videoConstraints => this._onSenderConstraintsReceived(videoConstraints));\r\n    }\r\n\r\n    /**\r\n     * Configures the video encodings on the local sources when a media connection is established or becomes active.\r\n     *\r\n     * @returns {Promise<void[]>}\r\n     * @private\r\n     */\r\n    _configureConstraintsForLocalSources() {\r\n        for (const track of this._rtc.getLocalVideoTracks()) {\r\n            const sourceName = track.getSourceName();\r\n\r\n            sourceName && this._propagateSendMaxFrameHeight(sourceName);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Handles the {@link JitsiConferenceEvents.MEDIA_SESSION_STARTED}, that is when the conference creates new media\r\n     * session. It doesn't mean it's already active though. For example the JVB connection may be created after\r\n     * the conference has entered the p2p mode already.\r\n     *\r\n     * @param {JingleSessionPC} mediaSession - the started media session.\r\n     * @private\r\n     */\r\n    _onMediaSessionStarted(mediaSession) {\r\n        mediaSession.addListener(\r\n            MediaSessionEvents.REMOTE_SOURCE_CONSTRAINTS_CHANGED,\r\n            (session, sourceConstraints) => {\r\n                session === this._conference.getActiveMediaSession()\r\n                    && sourceConstraints.forEach(constraint => this._onSenderConstraintsReceived(constraint));\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Propagates the video constraints if they have changed.\r\n     *\r\n     * @param {Object} videoConstraints - The sender video constraints received from the bridge.\r\n     * @returns {Promise<void[]>}\r\n     * @private\r\n     */\r\n    _onSenderConstraintsReceived(videoConstraints) {\r\n        const { maxHeight, sourceName } = videoConstraints;\r\n        const localVideoTracks = this._conference.getLocalVideoTracks() ?? [];\r\n\r\n        for (const track of localVideoTracks) {\r\n            // Propagate the sender constraint only if it has changed.\r\n            if (track.getSourceName() === sourceName\r\n                && this._sourceSenderConstraints.get(sourceName) !== maxHeight) {\r\n                this._sourceSenderConstraints.set(\r\n                    sourceName,\r\n                    maxHeight === -1\r\n                        ? Math.min(MAX_LOCAL_RESOLUTION, this._preferredSendMaxFrameHeight)\r\n                        : maxHeight);\r\n                logger.debug(`Sender constraints for source:${sourceName} changed to maxHeight:${maxHeight}`);\r\n                this._propagateSendMaxFrameHeight(sourceName);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Figures out the send video constraint as specified by {@link _selectSendMaxFrameHeight} and sets it on all media\r\n     * sessions for the reasons mentioned in this class description.\r\n     *\r\n     * @param {string} sourceName - The source for which sender constraints have changed.\r\n     * @returns {Promise<void[]>}\r\n     * @private\r\n     */\r\n    _propagateSendMaxFrameHeight(sourceName) {\r\n        if (!sourceName) {\r\n            throw new Error('sourceName missing for calculating the sendMaxHeight for video tracks');\r\n        }\r\n        const sendMaxFrameHeight = this._selectSendMaxFrameHeight(sourceName);\r\n        const promises = [];\r\n\r\n        if (sendMaxFrameHeight >= 0) {\r\n            for (const session of this._conference.getMediaSessions()) {\r\n                promises.push(session.setSenderVideoConstraint(sendMaxFrameHeight, sourceName));\r\n            }\r\n        }\r\n\r\n        return Promise.all(promises);\r\n    }\r\n\r\n    /**\r\n     * Selects the lowest common value for the local video send constraint by looking at local user's preference and\r\n     * the active media session's receive preference set by the remote party.\r\n     *\r\n     * @param {string} sourceName - The source for which sender constraints have changed.\r\n     * @returns {number|undefined}\r\n     * @private\r\n     */\r\n    _selectSendMaxFrameHeight(sourceName) {\r\n        if (!sourceName) {\r\n            throw new Error('sourceName missing for calculating the sendMaxHeight for video tracks');\r\n        }\r\n        const activeMediaSession = this._conference.getActiveMediaSession();\r\n        const remoteRecvMaxFrameHeight = activeMediaSession\r\n            ? this._sourceSenderConstraints.get(sourceName)\r\n            : undefined;\r\n\r\n        if (this._preferredSendMaxFrameHeight >= 0 && remoteRecvMaxFrameHeight >= 0) {\r\n            return Math.min(this._preferredSendMaxFrameHeight, remoteRecvMaxFrameHeight);\r\n        } else if (remoteRecvMaxFrameHeight >= 0) {\r\n            return remoteRecvMaxFrameHeight;\r\n        }\r\n\r\n        return this._preferredSendMaxFrameHeight;\r\n    }\r\n\r\n    /**\r\n     * Sets local preference for max send video frame height.\r\n     *\r\n     * @param {number} maxFrameHeight - the new value to set.\r\n     * @returns {Promise<void[]>} - resolved when the operation is complete.\r\n     */\r\n    setPreferredSendMaxFrameHeight(maxFrameHeight) {\r\n        this._preferredSendMaxFrameHeight = maxFrameHeight;\r\n        const promises = [];\r\n\r\n        for (const sourceName of this._sourceSenderConstraints.keys()) {\r\n            promises.push(this._propagateSendMaxFrameHeight(sourceName));\r\n        }\r\n\r\n        return Promise.allSettled(promises);\r\n    }\r\n}\r\n","/**\r\n * A collection of utility functions for taking in XML and parsing it to return\r\n * certain values.\r\n */\r\nexport default {\r\n    /**\r\n     * Parses the presence update of the focus and returns an object with the\r\n     * statuses related to recording.\r\n     *\r\n     * @param {Node} presence - An XMPP presence update.\r\n     * @returns {Object} The current presence values related to recording.\r\n     */\r\n    getFocusRecordingUpdate(presence) {\r\n        const jibriStatus = presence\r\n            && presence.getElementsByTagName('jibri-recording-status')[0];\r\n\r\n        if (!jibriStatus) {\r\n            return;\r\n        }\r\n\r\n        return {\r\n            error: jibriStatus.getAttribute('failure_reason'),\r\n            initiator: jibriStatus.getAttribute('initiator'),\r\n            recordingMode: jibriStatus.getAttribute('recording_mode'),\r\n            sessionID: jibriStatus.getAttribute('session_id'),\r\n            status: jibriStatus.getAttribute('status')\r\n        };\r\n    },\r\n\r\n    /**\r\n     * Parses the presence update from a hidden domain participant and returns\r\n     * an object with the statuses related to recording.\r\n     *\r\n     * @param {Node} presence - An XMPP presence update.\r\n     * @returns {Object} The current presence values related to recording.\r\n     */\r\n    getHiddenDomainUpdate(presence) {\r\n        const liveStreamViewURLContainer\r\n            = presence.getElementsByTagName('live-stream-view-url')[0];\r\n        const liveStreamViewURL = liveStreamViewURLContainer\r\n            && liveStreamViewURLContainer.textContent;\r\n        const modeContainer\r\n            = presence.getElementsByTagName('mode')[0];\r\n        const mode = modeContainer\r\n            && modeContainer.textContent\r\n            && modeContainer.textContent.toLowerCase();\r\n        const sessionIDContainer\r\n            = presence.getElementsByTagName('session_id')[0];\r\n        const sessionID\r\n            = sessionIDContainer && sessionIDContainer.textContent;\r\n\r\n        return {\r\n            liveStreamViewURL,\r\n            mode,\r\n            sessionID\r\n        };\r\n    },\r\n\r\n    /**\r\n     * Returns the recording session ID from a successful IQ.\r\n     *\r\n     * @param {Node} response - The response from the IQ.\r\n     * @returns {string} The session ID of the recording session.\r\n     */\r\n    getSessionIdFromIq(response) {\r\n        const jibri = response && response.getElementsByTagName('jibri')[0];\r\n\r\n        return jibri && jibri.getAttribute('session_id');\r\n    },\r\n\r\n    /**\r\n     * Returns the recording session ID from a presence, if it exists.\r\n     *\r\n     * @param {Node} presence - An XMPP presence update.\r\n     * @returns {string|undefined} The session ID of the recording session.\r\n     */\r\n    getSessionId(presence) {\r\n        const sessionIdContainer\r\n            = presence.getElementsByTagName('session_id')[0];\r\n        const sessionId = sessionIdContainer && sessionIdContainer.textContent;\r\n\r\n        return sessionId;\r\n    },\r\n\r\n    /**\r\n     * Returns whether or not a presence is from the focus.\r\n     *\r\n     * @param {Node} presence - An XMPP presence update.\r\n     * @returns {boolean} True if the presence is from the focus.\r\n     */\r\n    isFromFocus(presence) {\r\n        return presence.getAttribute('from').includes('focus');\r\n    }\r\n};\r\n","import { $iq } from 'strophe.js';\r\n\r\nimport recordingXMLUtils from './recordingXMLUtils';\r\n\r\n/**\r\n * Represents a recording session.\r\n */\r\nexport default class JibriSession {\r\n    /**\r\n     * Initializes a new JibriSession instance.\r\n     *\r\n     * @constructor\r\n     */\r\n    constructor(options = {}) {\r\n        this._connection = options.connection;\r\n        this._mode = options.mode;\r\n        this._jibriJid = null;\r\n        this._statusFromJicofo = '';\r\n\r\n        this._setSessionID(options.sessionID);\r\n        this.setStatus(options.status);\r\n    }\r\n\r\n    /**\r\n     * Returns the error related to the session instance, if any.\r\n     *\r\n     * @returns {string|undefined}\r\n     */\r\n    getError() {\r\n        return this._error;\r\n    }\r\n\r\n    /**\r\n     * Returns the session ID of the session instance.\r\n     *\r\n     * @returns {string|undefined}\r\n     */\r\n    getID() {\r\n        return this._sessionID;\r\n    }\r\n\r\n    /**\r\n     * Returns the initiator of the session instance.\r\n     *\r\n     * @returns {JitsiParticipant|string} The participant that started the session.\r\n     */\r\n    getInitiator() {\r\n        return this._initiator;\r\n    }\r\n\r\n    /**\r\n     * Returns the streaming URL of the session.\r\n     *\r\n     * @returns {string|undefined}\r\n     */\r\n    getLiveStreamViewURL() {\r\n        return this._liveStreamViewURL;\r\n    }\r\n\r\n    /**\r\n     * Returns the current status of the session.\r\n     *\r\n     * @returns {string|undefined}\r\n     */\r\n    getStatus() {\r\n        // If _status is not set fallback to the status reported by jicofo.\r\n        if (this._status) {\r\n            return this._status;\r\n        }\r\n\r\n        return this._statusFromJicofo;\r\n    }\r\n\r\n    /**\r\n     * @returns {string|undefined} the JID of jibri associated with this session.\r\n     */\r\n    getJibriJid() {\r\n        return this._jibriJid;\r\n    }\r\n\r\n    /**\r\n     * Returns the jid of the participant that stopped the session.\r\n     *\r\n     * @returns {JitsiParticipant|string} The participant that stopped the session.\r\n     */\r\n    getTerminator() {\r\n        return this._terminator;\r\n    }\r\n\r\n    /**\r\n     * Returns the current recording mode of the session, such as \"file\".\r\n     *\r\n     * @returns {string}\r\n     */\r\n    getMode() {\r\n        return this._mode;\r\n    }\r\n\r\n    /**\r\n     * Sets the last known error message related to the session.\r\n     *\r\n     * @param {string} error - The error string explaining why the session\r\n     * entered an error state.\r\n     * @returns {void}\r\n     */\r\n    setError(error) {\r\n        this._error = error;\r\n    }\r\n\r\n    /**\r\n     * Sets the last live stream URL for the session instance. Usually this is\r\n     * a YouTube URL and usually this is only set for \"stream\" sessions.\r\n     *\r\n     * @param {string} url - The live stream URL associated with the session.\r\n     * @returns {void}\r\n     */\r\n    setLiveStreamViewURL(url) {\r\n        this._liveStreamViewURL = url;\r\n    }\r\n\r\n    /**\r\n     * Sets the last known status for this recording session.\r\n     *\r\n     * @param {string} status - The new status to set.\r\n     * @returns {void}\r\n     */\r\n    setStatus(status) {\r\n        this._status = status;\r\n    }\r\n\r\n    /**\r\n     * Set the session status reported by jicofo. If a jibri is present in the room,\r\n     * the status is always 'on'. Otherwise, we fallback to the status reported by jicofo.\r\n     *\r\n     * @param {string} status\r\n     */\r\n    setStatusFromJicofo(status) {\r\n        this._statusFromJicofo = status;\r\n    }\r\n\r\n    /**\r\n     * Set the JID of the jibri associated with this session.\r\n     *\r\n     * @param {*} jibriJid\r\n     */\r\n    setJibriJid(jibriJid) {\r\n        this._jibriJid = jibriJid;\r\n    }\r\n\r\n    /**\r\n     * Sets the participant that started the session.\r\n     * @param {JitsiParticipant | string} participant - The participant or resource id\r\n     * if local participant.\r\n     */\r\n    setInitiator(participant) {\r\n        this._initiator = participant;\r\n    }\r\n\r\n    /**\r\n     * Sets the participant that stopped the session.\r\n     * @param {JitsiParticipant | string} participant - The participant or the resource id\r\n     * if local participant.\r\n     */\r\n    setTerminator(participant) {\r\n        this._terminator = participant;\r\n    }\r\n\r\n    /**\r\n     * Sends a message to start the actual recording.\r\n     *\r\n     * @param {Object} options - Additional arguments for starting the\r\n     * recording.\r\n     * @param {string} [options.appData] - Data specific to the app/service that\r\n     * the result file will be uploaded.\r\n     * @param {string} [options.broadcastId] - The broadcast ID of an\r\n     * associated YouTube stream, used for knowing the URL from which the stream\r\n     * can be viewed.\r\n     * @param {string} options.focusMucJid - The JID of the focus participant\r\n     * that controls recording.\r\n     * @param {streamId} options.streamId - Necessary for live streaming, this\r\n     * is the stream key needed to start a live streaming session with the\r\n     * streaming service provider.\r\n     * @returns Promise\r\n     */\r\n    start({ appData, broadcastId, focusMucJid, streamId }) {\r\n        return new Promise((resolve, reject) => {\r\n            this._connection.sendIQ(\r\n                this._createIQ({\r\n                    action: 'start',\r\n                    appData,\r\n                    focusMucJid,\r\n                    broadcastId,\r\n                    streamId\r\n                }),\r\n                result => {\r\n                    // All users will eventually receive the 'pending' status\r\n                    // from the backend, but for the user initiating the session\r\n                    // it's better to give some instant feedback that recording\r\n                    // is starting so fire 'pending' here manually.\r\n                    this.setStatus('pending');\r\n                    this._setSessionID(\r\n                        recordingXMLUtils.getSessionIdFromIq(result));\r\n\r\n                    resolve();\r\n                },\r\n                error => {\r\n                    this._setErrorFromIq(error);\r\n\r\n                    reject(error);\r\n                });\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Sends a message to actually stop the recording session.\r\n     *\r\n     * @param {Object} options - Additional arguments for stopping the\r\n     * recording.\r\n     * @param {Object} options.focusMucJid - The JID of the focus participant\r\n     * that controls recording.\r\n     * @returns Promise\r\n     */\r\n    stop({ focusMucJid }) {\r\n        return new Promise((resolve, reject) => {\r\n            this._connection.sendIQ(\r\n                this._createIQ({\r\n                    action: 'stop',\r\n                    focusMucJid\r\n                }),\r\n                resolve,\r\n                reject);\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Generates the message to change the status of the recording session.\r\n     *\r\n     * @param {string} status - The new status to which the recording session\r\n     * should transition.\r\n     * @param {string} [options.appData] - Data specific to the app/service that\r\n     * the result file will be uploaded.\r\n     * @param {string} [options.broadcastId] - The broadcast ID of an\r\n     * associated YouTube stream, used for knowing the URL from which the stream\r\n     * can be viewed.\r\n     * @param {string} options.focusMucJid - The JID of the focus participant\r\n     * that controls recording.\r\n     * @param {streamId} options.streamId - Necessary for live streaming, this\r\n     * is the stream key needed to start a live streaming session with the\r\n     * streaming service provider.\r\n     * @returns Object - The XMPP IQ message.\r\n     */\r\n    _createIQ({ action, appData, broadcastId, focusMucJid, streamId }) {\r\n        return $iq({\r\n            to: focusMucJid,\r\n            type: 'set'\r\n        })\r\n        .c('jibri', {\r\n            'xmlns': 'http://jitsi.org/protocol/jibri',\r\n            'action': action,\r\n            'app_data': appData,\r\n            'recording_mode': this._mode,\r\n            'streamid': streamId,\r\n            'you_tube_broadcast_id': broadcastId\r\n        })\r\n        .up();\r\n    }\r\n\r\n    /**\r\n     * Handles the error from an iq and stores the error.\r\n     *\r\n     * @param {Node} errorIq - The error response from an Iq.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _setErrorFromIq(errorIq) {\r\n        const error = errorIq.getElementsByTagName('error')[0];\r\n\r\n        this.setError(error.children[0].tagName);\r\n    }\r\n\r\n    /**\r\n     * Sets the known session ID for this recording session.\r\n     *\r\n     * @param {string} sessionID\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _setSessionID(sessionID) {\r\n        this._sessionID = sessionID;\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\n\r\nimport JibriSession from './JibriSession';\r\nimport recordingXMLUtils from './recordingXMLUtils';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * A class responsible for starting and stopping recording sessions and emitting\r\n * state updates for them.\r\n */\r\nclass RecordingManager {\r\n    /**\r\n     * Initialize {@code RecordingManager} with other objects that are necessary\r\n     * for starting a recording.\r\n     *\r\n     * @param {ChatRoom} chatRoom - The chat room to handle.\r\n     * @returns {void}\r\n     */\r\n    constructor(chatRoom) {\r\n        /**\r\n         * All known recording sessions from the current conference.\r\n         */\r\n        this._sessions = {};\r\n\r\n        this._chatRoom = chatRoom;\r\n\r\n        this.onPresence = this.onPresence.bind(this);\r\n\r\n        this.onMemberLeft = this.onMemberLeft.bind(this);\r\n\r\n        this._chatRoom.eventEmitter.addListener(\r\n            XMPPEvents.PRESENCE_RECEIVED, this.onPresence);\r\n        this._chatRoom.eventEmitter.addListener(\r\n            XMPPEvents.MUC_MEMBER_LEFT, this.onMemberLeft);\r\n    }\r\n\r\n    /**\r\n     * Finds an existing recording session by session ID.\r\n     *\r\n     * @param {string} sessionID - The session ID associated with the recording.\r\n     * @returns {JibriSession|undefined}\r\n     */\r\n    getSession(sessionID) {\r\n        return this._sessions[sessionID];\r\n    }\r\n\r\n    /**\r\n     * Find a session with a specific jibri JID.\r\n     *\r\n     * @param {string} jibriJid the JID to search for.\r\n     * @returns\r\n     */\r\n    getSessionByJibriJid(jibriJid) {\r\n        let s;\r\n\r\n        Object.values(this._sessions).forEach(session => {\r\n            if (session.getJibriJid() === jibriJid) {\r\n                s = session;\r\n            }\r\n        });\r\n\r\n        return s;\r\n    }\r\n\r\n    /**\r\n     * Callback to invoke to parse through a presence update to find recording\r\n     * related updates (from Jibri participant doing the recording and the\r\n     * focus which controls recording).\r\n     *\r\n     * @param {Object} event - The presence data from the pubsub event.\r\n     * @param {Node} event.presence - An XMPP presence update.\r\n     * @param {boolean} event.fromHiddenDomain - Whether or not the update comes\r\n     * from a participant that is trusted but not visible, as would be the case\r\n     * with the Jibri recorder participant.\r\n     * @returns {void}\r\n     */\r\n    onPresence({ fromHiddenDomain, presence }) {\r\n        if (recordingXMLUtils.isFromFocus(presence)) {\r\n            this._handleFocusPresence(presence);\r\n        } else if (fromHiddenDomain) {\r\n            this._handleJibriPresence(presence);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Handle a participant leaving the room.\r\n     * @param {string} jid the JID of the participant that left.\r\n     */\r\n    onMemberLeft(jid) {\r\n        const session = this.getSessionByJibriJid(jid);\r\n\r\n        if (session) {\r\n\r\n            const prevStatus = session.getStatus();\r\n\r\n            // Setting to ''\r\n            session.setStatus('');\r\n            session.setJibriJid(null);\r\n\r\n            if (session.getStatus() !== prevStatus) {\r\n                this._emitSessionUpdate(session);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Start a recording session.\r\n     *\r\n     * @param {Object} options - Configuration for the recording.\r\n     * @param {string} [options.appData] - Data specific to the app/service that\r\n     * the result file will be uploaded.\r\n     * @param {string} [optional] options.broadcastId - The channel on which a\r\n     * live stream will occur.\r\n     * @param {string} options.mode - The mode in which recording should be\r\n     * started. Recognized values are \"file\" and \"stream\".\r\n     * @param {string} [optional] options.streamId - The stream key to be used\r\n     * for live stream broadcasting. Required for live streaming.\r\n     * @returns {Promise} A promise for starting a recording, which will pass\r\n     * back the session on success. The promise resolves after receiving an\r\n     * acknowledgment of the start request success or fail.\r\n     */\r\n    startRecording(options) {\r\n        const session = new JibriSession({\r\n            ...options,\r\n            connection: this._chatRoom.connection\r\n        });\r\n\r\n        return session.start({\r\n            appData: options.appData,\r\n            broadcastId: options.broadcastId,\r\n            focusMucJid: this._chatRoom.focusMucJid,\r\n            streamId: options.streamId\r\n        })\r\n            .then(() => {\r\n                // Only store the session and emit if the session has not been\r\n                // added already. This is a workaround for the session getting\r\n                // created due to a presence update to announce a \"pending\"\r\n                // recording being received before JibriSession#start finishes.\r\n                if (!this.getSession(session.getID())) {\r\n                    this._addSession(session);\r\n                    this._emitSessionUpdate(session);\r\n                }\r\n\r\n                return session;\r\n            })\r\n            .catch(error => {\r\n                this._emitSessionUpdate(session);\r\n\r\n                return Promise.reject(error);\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Stop a recording session.\r\n     *\r\n     * @param {string} sessionID - The ID associated with the recording session\r\n     * to be stopped.\r\n     * @returns {Promise} The promise resolves after receiving an\r\n     * acknowledgment of the stop request success or fail.\r\n     */\r\n    stopRecording(sessionID) {\r\n        const session = this.getSession(sessionID);\r\n\r\n        if (session) {\r\n            return session.stop({ focusMucJid: this._chatRoom.focusMucJid });\r\n        }\r\n\r\n        return Promise.reject(new Error('Could not find session'));\r\n    }\r\n\r\n    /**\r\n     * Stores a reference to the passed in JibriSession.\r\n     *\r\n     * @param {string} session - The JibriSession instance to store.\r\n     * @returns {void}\r\n     */\r\n    _addSession(session) {\r\n        this._sessions[session.getID()] = session;\r\n    }\r\n\r\n    /**\r\n     * Create a new instance of a recording session and stores a reference to\r\n     * it.\r\n     *\r\n     * @param {string} sessionID - The session ID of the recording in progress.\r\n     * @param {string} status - The current status of the recording session.\r\n     * @param {string} mode - The recording mode of the session.\r\n     * @returns {JibriSession}\r\n     */\r\n    _createSession(sessionID, status, mode) {\r\n        const session = new JibriSession({\r\n            connection: this._chatRoom.connection,\r\n            focusMucJid: this._chatRoom.focusMucJid,\r\n            mode,\r\n            sessionID,\r\n            status\r\n        });\r\n\r\n        this._addSession(session);\r\n\r\n        return session;\r\n    }\r\n\r\n    /**\r\n     * Notifies listeners of an update to a recording session.\r\n     *\r\n     * @param {JibriSession} session - The session that has been updated.\r\n     * @param {string|undefined} initiator - The jid of the initiator of the update.\r\n     */\r\n    _emitSessionUpdate(session, initiator) {\r\n        this._chatRoom.eventEmitter.emit(\r\n            XMPPEvents.RECORDER_STATE_CHANGED, session, initiator);\r\n    }\r\n\r\n    /**\r\n     * Parses presence to update an existing JibriSession or to create a new\r\n     * JibriSession.\r\n     *\r\n     * @param {Node} presence - An XMPP presence update.\r\n     * @returns {void}\r\n     */\r\n    _handleFocusPresence(presence) {\r\n        const jibriStatus = recordingXMLUtils.getFocusRecordingUpdate(presence);\r\n\r\n        if (!jibriStatus) {\r\n            return;\r\n        }\r\n\r\n        const { error, initiator, recordingMode, sessionID, status } = jibriStatus;\r\n\r\n        // We'll look for an existing session or create one (in case we're a\r\n        // participant joining a call with an existing recording going on).\r\n        let session = this.getSession(sessionID);\r\n\r\n        // Handle the case where a status update is received in presence but\r\n        // the local participant has joined while the JibriSession has already\r\n        // ended.\r\n        if (!session && status === 'off') {\r\n            logger.warn(\r\n                'Ignoring recording presence update',\r\n                'Received a new session with status off.');\r\n\r\n            return;\r\n        }\r\n\r\n        // Jicofo sends updates via presence, and any extension in presence\r\n        // is sent until it is explicitly removed.  It's difficult for\r\n        // Jicofo to know when a presence has been sent once, so it won't\r\n        // remove jibri status extension.  This means we may receive the same\r\n        // status update more than once, so check for that here\r\n        if (session\r\n            && session.getStatus() === status\r\n            && session.getError() === error) {\r\n            logger.warn('Ignoring duplicate presence update: ',\r\n                JSON.stringify(jibriStatus));\r\n\r\n            return;\r\n        }\r\n\r\n        if (!session) {\r\n            session = this._createSession(sessionID, status, recordingMode);\r\n        }\r\n\r\n        session.setStatusFromJicofo(status);\r\n\r\n        if (error) {\r\n            session.setError(error);\r\n        }\r\n\r\n        this._emitSessionUpdate(session, initiator);\r\n    }\r\n\r\n    /**\r\n     * Handles updates from the Jibri which can broadcast a YouTube URL that\r\n     * needs to be updated in a JibriSession.\r\n     *\r\n     * @param {Node} presence - An XMPP presence update.\r\n     * @returns {void}\r\n     */\r\n    _handleJibriPresence(presence) {\r\n        const { liveStreamViewURL, mode, sessionID }\r\n            = recordingXMLUtils.getHiddenDomainUpdate(presence);\r\n\r\n        if (!sessionID) {\r\n            logger.warn(\r\n                'Ignoring potential jibri presence due to no session id.');\r\n\r\n            return;\r\n        }\r\n\r\n        let session = this.getSession(sessionID);\r\n\r\n        if (!session) {\r\n            session = this._createSession(sessionID, 'on', mode);\r\n        }\r\n\r\n        // When a jibri is present the status is always 'on';\r\n        session.setStatus('on');\r\n        session.setJibriJid(presence.getAttribute('from'));\r\n        session.setLiveStreamViewURL(liveStreamViewURL);\r\n\r\n        this._emitSessionUpdate(session);\r\n    }\r\n}\r\n\r\nexport default RecordingManager;\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport * as ConferenceEvents from '../../JitsiConferenceEvents';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport * as ConnectionQualityEvents from '../../service/connectivity/ConnectionQualityEvents';\r\nimport { createAudioOutputProblemEvent } from '../../service/statistics/AnalyticsEvents';\r\n\r\nimport Statistics from './statistics';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Number of local samples that will be used for comparison before and after the remote sample is received.\r\n */\r\nconst NUMBER_OF_LOCAL_SAMPLES = 2;\r\n\r\n/**\r\n * Collects the average audio levels per participant from the local stats and the stats received by every remote\r\n * participant and compares them to detect potential audio problem for a participant.\r\n */\r\nexport default class AudioOutputProblemDetector {\r\n\r\n    /**\r\n     * Creates new <tt>AudioOutputProblemDetector</tt> instance.\r\n     *\r\n     * @param {JitsiConference} conference - The conference instance to be monitored.\r\n     */\r\n    constructor(conference) {\r\n        this._conference = conference;\r\n        this._localAudioLevelCache = {};\r\n        this._reportedParticipants = [];\r\n        this._audioProblemCandidates = {};\r\n        this._numberOfRemoteAudioLevelsReceived = {};\r\n        this._onLocalAudioLevelsReport = this._onLocalAudioLevelsReport.bind(this);\r\n        this._onRemoteAudioLevelReceived = this._onRemoteAudioLevelReceived.bind(this);\r\n        this._clearUserData = this._clearUserData.bind(this);\r\n        this._conference.on(ConnectionQualityEvents.REMOTE_STATS_UPDATED, this._onRemoteAudioLevelReceived);\r\n        this._conference.statistics.addConnectionStatsListener(this._onLocalAudioLevelsReport);\r\n        this._conference.on(ConferenceEvents.USER_LEFT, this._clearUserData);\r\n    }\r\n\r\n    /**\r\n     * A listener for audio level data received by a remote participant.\r\n     *\r\n     * @param {string} userID - The user id of the participant that sent the data.\r\n     * @param {number} audioLevel - The average audio level value.\r\n     * @returns {void}\r\n     */\r\n    _onRemoteAudioLevelReceived(userID, { avgAudioLevels }) {\r\n        const numberOfReports = (this._numberOfRemoteAudioLevelsReceived[userID] + 1) || 0;\r\n\r\n        this._numberOfRemoteAudioLevelsReceived[userID] = numberOfReports;\r\n\r\n        if (this._reportedParticipants.indexOf(userID) !== -1 || (userID in this._audioProblemCandidates)\r\n                || avgAudioLevels <= 0 || numberOfReports < 3) {\r\n            return;\r\n        }\r\n\r\n        const participant = this._conference.getParticipantById(userID);\r\n\r\n        if (participant) {\r\n            const tracks = participant.getTracksByMediaType(MediaType.AUDIO);\r\n\r\n            if (tracks.length > 0 && participant.isAudioMuted()) {\r\n                // We don't need to report an error if everything seems fine with the participant and its tracks but\r\n                // the participant is audio muted. Since those are average audio levels we potentially can receive non\r\n                // zero values for muted track.\r\n                return;\r\n            }\r\n        }\r\n\r\n        const localAudioLevels = this._localAudioLevelCache[userID];\r\n\r\n        if (!Array.isArray(localAudioLevels) || localAudioLevels.every(audioLevel => audioLevel === 0)) {\r\n            this._audioProblemCandidates[userID] = {\r\n                remoteAudioLevels: avgAudioLevels,\r\n                localAudioLevels: []\r\n            };\r\n        }\r\n    }\r\n\r\n    /**\r\n     * A listener for audio level data retrieved by the local stats.\r\n     *\r\n     * @param {TraceablePeerConnection} tpc - The <tt>TraceablePeerConnection</tt> instance used to gather the data.\r\n     * @param {Object} avgAudioLevels - The average audio levels per participant.\r\n     * @returns {void}\r\n     */\r\n    _onLocalAudioLevelsReport(tpc, { avgAudioLevels }) {\r\n        if (tpc !== this._conference.getActivePeerConnection()) {\r\n            return;\r\n        }\r\n\r\n        Object.keys(avgAudioLevels).forEach(userID => {\r\n            if (this._reportedParticipants.indexOf(userID) !== -1) {\r\n                return;\r\n            }\r\n\r\n            const localAudioLevels = this._localAudioLevelCache[userID];\r\n\r\n            if (!Array.isArray(localAudioLevels)) {\r\n                this._localAudioLevelCache[userID] = [ ];\r\n            } else if (localAudioLevels.length >= NUMBER_OF_LOCAL_SAMPLES) {\r\n                localAudioLevels.shift();\r\n            }\r\n\r\n            this._localAudioLevelCache[userID].push(avgAudioLevels[userID]);\r\n        });\r\n\r\n\r\n        Object.keys(this._audioProblemCandidates).forEach(userID => {\r\n            const { localAudioLevels, remoteAudioLevels } = this._audioProblemCandidates[userID];\r\n\r\n            localAudioLevels.push(avgAudioLevels[userID]);\r\n\r\n            if (localAudioLevels.length === NUMBER_OF_LOCAL_SAMPLES) {\r\n                if (localAudioLevels.every(audioLevel => typeof audioLevel === 'undefined' || audioLevel === 0)) {\r\n                    const localAudioLevelsString = JSON.stringify(localAudioLevels);\r\n\r\n                    Statistics.sendAnalytics(\r\n                        createAudioOutputProblemEvent(userID, localAudioLevelsString, remoteAudioLevels));\r\n                    logger.warn(`A potential problem is detected with the audio output for participant ${\r\n                        userID}, local audio levels: ${localAudioLevelsString}, remote audio levels: ${\r\n                        remoteAudioLevels}`);\r\n                    this._reportedParticipants.push(userID);\r\n                    this._clearUserData(userID);\r\n                }\r\n\r\n                delete this._audioProblemCandidates[userID];\r\n            }\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Clears the data stored for a participant.\r\n     *\r\n     * @param {string} userID - The id of the participant.\r\n     * @returns {void}\r\n     */\r\n    _clearUserData(userID) {\r\n        delete this._localAudioLevelCache[userID];\r\n    }\r\n\r\n    /**\r\n     * Disposes the allocated resources.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    dispose() {\r\n        this._conference.off(ConnectionQualityEvents.REMOTE_STATS_UPDATED, this._onRemoteAudioLevelReceived);\r\n        this._conference.off(ConferenceEvents.USER_LEFT, this._clearUserData);\r\n        this._conference.statistics.removeConnectionStatsListener(this._onLocalAudioLevelsReport);\r\n        this._localAudioLevelCache = undefined;\r\n        this._audioProblemCandidates = undefined;\r\n        this._reportedParticipants = undefined;\r\n        this._numberOfRemoteAudioLevelsReceived = undefined;\r\n        this._conference = undefined;\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport isEqual from 'lodash.isequal';\r\n\r\nimport * as ConferenceEvents from '../../JitsiConferenceEvents';\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport { VideoType } from '../../service/RTC/VideoType';\r\nimport * as ConnectionQualityEvents\r\n    from '../../service/connectivity/ConnectionQualityEvents';\r\nimport {\r\n    createRtpStatsEvent,\r\n    createTransportStatsEvent\r\n} from '../../service/statistics/AnalyticsEvents';\r\nimport browser from '../browser';\r\n\r\nimport Statistics from './statistics';\r\n\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * This will calculate an average for one, named stat and submit it to\r\n * the analytics module when requested. It automatically counts the samples.\r\n */\r\nclass AverageStatReport {\r\n    /**\r\n     * Creates new <tt>AverageStatReport</tt> for given name.\r\n     * @param {string} name that's the name of the event that will be reported\r\n     * to the analytics module.\r\n     */\r\n    constructor(name) {\r\n        this.name = name;\r\n        this.count = 0;\r\n        this.sum = 0;\r\n        this.samples = [];\r\n    }\r\n\r\n    /**\r\n     * Adds the next value that will be included in the average when\r\n     * {@link calculate} is called.\r\n     * @param {number} nextValue\r\n     */\r\n    addNext(nextValue) {\r\n        if (typeof nextValue === 'undefined') {\r\n            return;\r\n        }\r\n\r\n        if (typeof nextValue !== 'number') {\r\n            logger.error(`${this.name} - invalid value for idx: ${this.count}`, nextValue);\r\n        } else if (!isNaN(nextValue)) {\r\n            this.sum += nextValue;\r\n            this.samples.push(nextValue);\r\n            this.count += 1;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Calculates an average for the samples collected using {@link addNext}.\r\n     * @return {number|NaN} an average of all collected samples or <tt>NaN</tt>\r\n     * if no samples were collected.\r\n     */\r\n    calculate() {\r\n        return this.sum / this.count;\r\n    }\r\n\r\n    /**\r\n     * Appends the report to the analytics \"data\" object. The object will be\r\n     * set under <tt>prefix</tt> + {@link this.name} key.\r\n     * @param {Object} report the analytics \"data\" object\r\n     */\r\n    appendReport(report) {\r\n        report[`${this.name}_avg`] = this.calculate();\r\n        report[`${this.name}_samples`] = JSON.stringify(this.samples);\r\n    }\r\n\r\n    /**\r\n     * Clears all memory of any samples collected, so that new average can be\r\n     * calculated using this instance.\r\n     */\r\n    reset() {\r\n        this.samples = [];\r\n        this.sum = 0;\r\n        this.count = 0;\r\n    }\r\n}\r\n\r\n/**\r\n * Class gathers the stats that are calculated and reported for a\r\n * {@link TraceablePeerConnection} even if it's not currently active. For\r\n * example we want to monitor RTT for the JVB connection while in P2P mode.\r\n */\r\nclass ConnectionAvgStats {\r\n    /**\r\n     * Creates new <tt>ConnectionAvgStats</tt>\r\n     * @param {AvgRTPStatsReporter} avgRtpStatsReporter\r\n     * @param {boolean} isP2P\r\n     * @param {number} n the number of samples, before arithmetic mean is to be\r\n     * calculated and values submitted to the analytics module.\r\n     */\r\n    constructor(avgRtpStatsReporter, isP2P, n) {\r\n        /**\r\n         * Is this instance for JVB or P2P connection ?\r\n         * @type {boolean}\r\n         */\r\n        this.isP2P = isP2P;\r\n\r\n        /**\r\n         * How many samples are to be included in arithmetic mean calculation.\r\n         * @type {number}\r\n         * @private\r\n         */\r\n        this._n = n;\r\n\r\n        /**\r\n         * The current sample index. Starts from 0 and goes up to {@link _n})\r\n         * when analytics report will be submitted.\r\n         * @type {number}\r\n         * @private\r\n         */\r\n        this._sampleIdx = 0;\r\n\r\n        /**\r\n         * Average round trip time reported by the ICE candidate pair.\r\n         * @type {AverageStatReport}\r\n         */\r\n        this._avgRTT = new AverageStatReport('rtt');\r\n\r\n        /**\r\n         * Map stores average RTT to the JVB reported by remote participants.\r\n         * Mapped per participant id {@link JitsiParticipant.getId}.\r\n         *\r\n         * This is used only when {@link ConnectionAvgStats.isP2P} equals to\r\n         * <tt>false</tt>.\r\n         *\r\n         * @type {Map<string,AverageStatReport>}\r\n         * @private\r\n         */\r\n        this._avgRemoteRTTMap = new Map();\r\n\r\n        /**\r\n         * The conference for which stats will be collected and reported.\r\n         * @type {JitsiConference}\r\n         * @private\r\n         */\r\n        this._avgRtpStatsReporter = avgRtpStatsReporter;\r\n\r\n        /**\r\n         * The latest average E2E RTT for the JVB connection only.\r\n         *\r\n         * This is used only when {@link ConnectionAvgStats.isP2P} equals to\r\n         * <tt>false</tt>.\r\n         *\r\n         * @type {number}\r\n         */\r\n        this._avgEnd2EndRTT = undefined;\r\n\r\n        this._onConnectionStats = (tpc, stats) => {\r\n            if (this.isP2P === tpc.isP2P) {\r\n                this._calculateAvgStats(stats);\r\n            }\r\n        };\r\n\r\n        const conference = avgRtpStatsReporter._conference;\r\n\r\n        conference.statistics.addConnectionStatsListener(\r\n            this._onConnectionStats);\r\n\r\n        if (!this.isP2P) {\r\n            this._onUserLeft = id => this._avgRemoteRTTMap.delete(id);\r\n            conference.on(ConferenceEvents.USER_LEFT, this._onUserLeft);\r\n\r\n            this._onRemoteStatsUpdated\r\n                = (id, data) => this._processRemoteStats(id, data);\r\n            conference.on(\r\n                ConnectionQualityEvents.REMOTE_STATS_UPDATED,\r\n                this._onRemoteStatsUpdated);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Processes next batch of stats.\r\n     * @param {go figure} data\r\n     * @private\r\n     */\r\n    _calculateAvgStats(data) {\r\n        if (!data) {\r\n            logger.error('No stats');\r\n\r\n            return;\r\n        }\r\n\r\n        if (browser.supportsRTTStatistics()) {\r\n            if (data.transport && data.transport.length) {\r\n                this._avgRTT.addNext(data.transport[0].rtt);\r\n            }\r\n        }\r\n\r\n        this._sampleIdx += 1;\r\n\r\n        if (this._sampleIdx >= this._n) {\r\n            if (browser.supportsRTTStatistics()) {\r\n                const conference = this._avgRtpStatsReporter._conference;\r\n\r\n                const batchReport = {\r\n                    p2p: this.isP2P,\r\n                    'conference_size': conference.getParticipantCount()\r\n                };\r\n\r\n                if (data.transport && data.transport.length) {\r\n                    Object.assign(batchReport, {\r\n                        'local_candidate_type':\r\n                            data.transport[0].localCandidateType,\r\n                        'remote_candidate_type':\r\n                            data.transport[0].remoteCandidateType,\r\n                        'transport_type': data.transport[0].type\r\n                    });\r\n                }\r\n\r\n                this._avgRTT.appendReport(batchReport);\r\n\r\n                if (this.isP2P) {\r\n                    // Report RTT diff only for P2P.\r\n                    const jvbEnd2EndRTT = this\r\n                        ._avgRtpStatsReporter.jvbStatsMonitor._avgEnd2EndRTT;\r\n\r\n                    if (!isNaN(jvbEnd2EndRTT)) {\r\n                        // eslint-disable-next-line dot-notation\r\n                        batchReport['rtt_diff']\r\n                            = this._avgRTT.calculate() - jvbEnd2EndRTT;\r\n                    }\r\n                } else {\r\n                    // Report end to end RTT only for JVB.\r\n                    const avgRemoteRTT = this._calculateAvgRemoteRTT();\r\n                    const avgLocalRTT = this._avgRTT.calculate();\r\n\r\n                    this._avgEnd2EndRTT = avgLocalRTT + avgRemoteRTT;\r\n\r\n                    if (!isNaN(avgLocalRTT) && !isNaN(avgRemoteRTT)) {\r\n                        // eslint-disable-next-line dot-notation\r\n                        batchReport['end2end_rtt_avg'] = this._avgEnd2EndRTT;\r\n                    }\r\n                }\r\n\r\n                Statistics.sendAnalytics(createRtpStatsEvent(batchReport));\r\n            }\r\n\r\n            this._resetAvgStats();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Calculates arithmetic mean of all RTTs towards the JVB reported by\r\n     * participants.\r\n     * @return {number|NaN} NaN if not available (not enough data)\r\n     * @private\r\n     */\r\n    _calculateAvgRemoteRTT() {\r\n        let count = 0, sum = 0;\r\n\r\n        // FIXME should we ignore RTT for participant\r\n        // who \"is having connectivity issues\" ?\r\n        for (const remoteAvg of this._avgRemoteRTTMap.values()) {\r\n            const avg = remoteAvg.calculate();\r\n\r\n            if (!isNaN(avg)) {\r\n                sum += avg;\r\n                count += 1;\r\n                remoteAvg.reset();\r\n            }\r\n        }\r\n\r\n        return sum / count;\r\n    }\r\n\r\n    /**\r\n     * Processes {@link ConnectionQualityEvents.REMOTE_STATS_UPDATED} to analyse\r\n     * RTT towards the JVB reported by each participant.\r\n     * @param {string} id {@link JitsiParticipant.getId}\r\n     * @param {go figure in ConnectionQuality.js} data\r\n     * @private\r\n     */\r\n    _processRemoteStats(id, data) {\r\n        const validData = typeof data.jvbRTT === 'number';\r\n        let rttAvg = this._avgRemoteRTTMap.get(id);\r\n\r\n        if (!rttAvg && validData) {\r\n            rttAvg = new AverageStatReport(`${id}_stat_rtt`);\r\n            this._avgRemoteRTTMap.set(id, rttAvg);\r\n        }\r\n\r\n        if (validData) {\r\n            rttAvg.addNext(data.jvbRTT);\r\n        } else if (rttAvg) {\r\n            this._avgRemoteRTTMap.delete(id);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Reset cache of all averages and {@link _sampleIdx}.\r\n     * @private\r\n     */\r\n    _resetAvgStats() {\r\n        this._avgRTT.reset();\r\n        if (this._avgRemoteRTTMap) {\r\n            this._avgRemoteRTTMap.clear();\r\n        }\r\n        this._sampleIdx = 0;\r\n    }\r\n\r\n    /**\r\n     *\r\n     */\r\n    dispose() {\r\n\r\n        const conference = this._avgRtpStatsReporter._conference;\r\n\r\n        conference.statistics.removeConnectionStatsListener(\r\n            this._onConnectionStats);\r\n        if (!this.isP2P) {\r\n            conference.off(\r\n                ConnectionQualityEvents.REMOTE_STATS_UPDATED,\r\n                this._onRemoteStatsUpdated);\r\n            conference.off(\r\n                ConferenceEvents.USER_LEFT,\r\n                this._onUserLeft);\r\n        }\r\n    }\r\n}\r\n\r\n/**\r\n * Reports average RTP statistics values (arithmetic mean) to the analytics\r\n * module for things like bit rate, bandwidth, packet loss etc. It keeps track\r\n * of the P2P vs JVB conference modes and submits the values under different\r\n * namespaces (the events for P2P mode have 'p2p.' prefix). Every switch between\r\n * P2P mode resets the data collected so far and averages are calculated from\r\n * scratch.\r\n */\r\nexport default class AvgRTPStatsReporter {\r\n    /**\r\n     * Creates new instance of <tt>AvgRTPStatsReporter</tt>\r\n     * @param {JitsiConference} conference\r\n     * @param {number} n the number of samples, before arithmetic mean is to be\r\n     * calculated and values submitted to the analytics module.\r\n     */\r\n    constructor(conference, n) {\r\n        /**\r\n         * How many {@link ConnectionQualityEvents.LOCAL_STATS_UPDATED} samples\r\n         * are to be included in arithmetic mean calculation.\r\n         * @type {number}\r\n         * @private\r\n         */\r\n        this._n = n;\r\n\r\n        if (n > 0) {\r\n            logger.info(`Avg RTP stats will be calculated every ${n} samples`);\r\n        } else {\r\n            logger.info('Avg RTP stats reports are disabled.');\r\n\r\n            // Do not initialize\r\n            return;\r\n        }\r\n\r\n        /**\r\n         * The current sample index. Starts from 0 and goes up to {@link _n})\r\n         * when analytics report will be submitted.\r\n         * @type {number}\r\n         * @private\r\n         */\r\n        this._sampleIdx = 0;\r\n\r\n        /**\r\n         * The conference for which stats will be collected and reported.\r\n         * @type {JitsiConference}\r\n         * @private\r\n         */\r\n        this._conference = conference;\r\n\r\n        /**\r\n         * Average audio upload bitrate\r\n         * XXX What are the units?\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgAudioBitrateUp\r\n            = new AverageStatReport('bitrate_audio_upload');\r\n\r\n        /**\r\n         * Average audio download bitrate\r\n         * XXX What are the units?\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgAudioBitrateDown\r\n            = new AverageStatReport('bitrate_audio_download');\r\n\r\n        /**\r\n         * Average video upload bitrate\r\n         * XXX What are the units?\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgVideoBitrateUp\r\n            = new AverageStatReport('bitrate_video_upload');\r\n\r\n        /**\r\n         * Average video download bitrate\r\n         * XXX What are the units?\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgVideoBitrateDown\r\n            = new AverageStatReport('bitrate_video_download');\r\n\r\n        /**\r\n         * Average upload bandwidth\r\n         * XXX What are the units?\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgBandwidthUp\r\n            = new AverageStatReport('bandwidth_upload');\r\n\r\n        /**\r\n         * Average download bandwidth\r\n         * XXX What are the units?\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgBandwidthDown\r\n            = new AverageStatReport('bandwidth_download');\r\n\r\n        /**\r\n         * Average total packet loss\r\n         * XXX What are the units?\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgPacketLossTotal\r\n            = new AverageStatReport('packet_loss_total');\r\n\r\n        /**\r\n         * Average upload packet loss\r\n         * XXX What are the units?\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgPacketLossUp\r\n            = new AverageStatReport('packet_loss_upload');\r\n\r\n        /**\r\n         * Average download packet loss\r\n         * XXX What are the units?\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgPacketLossDown\r\n            = new AverageStatReport('packet_loss_download');\r\n\r\n        /**\r\n         * Average FPS for remote videos\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgRemoteFPS = new AverageStatReport('framerate_remote');\r\n\r\n        /**\r\n         * Average FPS for remote screen streaming videos (reported only if not\r\n         * a <tt>NaN</tt>).\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgRemoteScreenFPS\r\n            = new AverageStatReport('framerate_screen_remote');\r\n\r\n        /**\r\n         * Average FPS for local video (camera)\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgLocalFPS = new AverageStatReport('framerate_local');\r\n\r\n        /**\r\n         * Average FPS for local screen streaming video (reported only if not\r\n         * a <tt>NaN</tt>).\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgLocalScreenFPS\r\n            = new AverageStatReport('framerate_screen_local');\r\n\r\n        /**\r\n         * Average pixels for remote screen streaming videos (reported only if\r\n         * not a <tt>NaN</tt>).\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgRemoteCameraPixels\r\n            = new AverageStatReport('pixels_remote');\r\n\r\n        /**\r\n         * Average pixels for remote screen streaming videos (reported only if\r\n         * not a <tt>NaN</tt>).\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgRemoteScreenPixels\r\n            = new AverageStatReport('pixels_screen_remote');\r\n\r\n        /**\r\n         * Average pixels for local video (camera)\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgLocalCameraPixels\r\n            = new AverageStatReport('pixels_local');\r\n\r\n        /**\r\n         * Average pixels for local screen streaming video (reported only if not\r\n         * a <tt>NaN</tt>).\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgLocalScreenPixels\r\n            = new AverageStatReport('pixels_screen_local');\r\n\r\n        /**\r\n         * Average connection quality as defined by\r\n         * the {@link ConnectionQuality} module.\r\n         * @type {AverageStatReport}\r\n         * @private\r\n         */\r\n        this._avgCQ = new AverageStatReport('connection_quality');\r\n\r\n        this._cachedTransportStats = undefined;\r\n\r\n        this._onLocalStatsUpdated = data => {\r\n            this._calculateAvgStats(data);\r\n            this._maybeSendTransportAnalyticsEvent(data);\r\n        };\r\n        conference.on(\r\n            ConnectionQualityEvents.LOCAL_STATS_UPDATED,\r\n            this._onLocalStatsUpdated);\r\n\r\n        this._onP2PStatusChanged = () => {\r\n            logger.debug('Resetting average stats calculation');\r\n            this._resetAvgStats();\r\n            this.jvbStatsMonitor._resetAvgStats();\r\n            this.p2pStatsMonitor._resetAvgStats();\r\n        };\r\n        conference.on(\r\n            ConferenceEvents.P2P_STATUS,\r\n            this._onP2PStatusChanged);\r\n\r\n        this._onJvb121StatusChanged = (oldStatus, newStatus) => {\r\n            // We want to reset only on the transition from false => true,\r\n            // because otherwise those stats are resetted on JVB <=> P2P\r\n            // transition.\r\n            if (newStatus === true) {\r\n                logger.info('Resetting JVB avg RTP stats');\r\n                this._resetAvgJvbStats();\r\n            }\r\n        };\r\n        conference.on(\r\n            ConferenceEvents.JVB121_STATUS,\r\n            this._onJvb121StatusChanged);\r\n\r\n        this.jvbStatsMonitor\r\n            = new ConnectionAvgStats(this, false /* JVB */, n);\r\n\r\n        this.p2pStatsMonitor\r\n            = new ConnectionAvgStats(this, true /* P2P */, n);\r\n    }\r\n\r\n    /**\r\n     * Processes next batch of stats reported on\r\n     * {@link ConnectionQualityEvents.LOCAL_STATS_UPDATED}.\r\n     * @param {go figure} data\r\n     * @private\r\n     */\r\n    _calculateAvgStats(data) {\r\n\r\n        if (!data) {\r\n            logger.error('No stats');\r\n\r\n            return;\r\n        }\r\n\r\n        const isP2P = this._conference.isP2PActive();\r\n        const confSize = this._conference.getParticipantCount();\r\n\r\n        if (!isP2P && confSize < 2) {\r\n\r\n            // There's no point in collecting stats for a JVB conference of 1.\r\n            // That happens for short period of time after everyone leaves\r\n            // the room, until Jicofo terminates the session.\r\n            return;\r\n        }\r\n\r\n        /* Uncomment to figure out stats structure\r\n        for (const key in data) {\r\n            if (data.hasOwnProperty(key)) {\r\n                logger.info(`local stat ${key}: `, data[key]);\r\n            }\r\n        } */\r\n\r\n        const bitrate = data.bitrate;\r\n        const bandwidth = data.bandwidth;\r\n        const packetLoss = data.packetLoss;\r\n        const frameRate = data.framerate;\r\n        const resolution = data.resolution;\r\n\r\n        if (!bitrate) {\r\n            logger.error('No \"bitrate\"');\r\n\r\n            return;\r\n        } else if (!bandwidth) {\r\n            logger.error('No \"bandwidth\"');\r\n\r\n            return;\r\n        } else if (!packetLoss) {\r\n            logger.error('No \"packetloss\"');\r\n\r\n            return;\r\n        } else if (!frameRate) {\r\n            logger.error('No \"framerate\"');\r\n\r\n            return;\r\n        } else if (!resolution) {\r\n            logger.error('No resolution');\r\n\r\n            return;\r\n        }\r\n\r\n        this._avgAudioBitrateUp.addNext(bitrate.audio.upload);\r\n        this._avgAudioBitrateDown.addNext(bitrate.audio.download);\r\n\r\n        this._avgVideoBitrateUp.addNext(bitrate.video.upload);\r\n        this._avgVideoBitrateDown.addNext(bitrate.video.download);\r\n\r\n        if (browser.supportsBandwidthStatistics()) {\r\n            this._avgBandwidthUp.addNext(bandwidth.upload);\r\n            this._avgBandwidthDown.addNext(bandwidth.download);\r\n        }\r\n\r\n        this._avgPacketLossUp.addNext(packetLoss.upload);\r\n        this._avgPacketLossDown.addNext(packetLoss.download);\r\n        this._avgPacketLossTotal.addNext(packetLoss.total);\r\n\r\n        this._avgCQ.addNext(data.connectionQuality);\r\n\r\n        if (frameRate) {\r\n            this._avgRemoteFPS.addNext(\r\n                this._calculateAvgVideoFps(\r\n                    frameRate, false /* remote */, VideoType.CAMERA));\r\n            this._avgRemoteScreenFPS.addNext(\r\n                this._calculateAvgVideoFps(\r\n                    frameRate, false /* remote */, VideoType.DESKTOP));\r\n\r\n            this._avgLocalFPS.addNext(\r\n                this._calculateAvgVideoFps(\r\n                    frameRate, true /* local */, VideoType.CAMERA));\r\n            this._avgLocalScreenFPS.addNext(\r\n                this._calculateAvgVideoFps(\r\n                    frameRate, true /* local */, VideoType.DESKTOP));\r\n        }\r\n\r\n        if (resolution) {\r\n            this._avgRemoteCameraPixels.addNext(\r\n                this._calculateAvgVideoPixels(\r\n                    resolution, false /* remote */, VideoType.CAMERA));\r\n\r\n            this._avgRemoteScreenPixels.addNext(\r\n                this._calculateAvgVideoPixels(\r\n                    resolution, false /* remote */, VideoType.DESKTOP));\r\n\r\n            this._avgLocalCameraPixels.addNext(\r\n                this._calculateAvgVideoPixels(\r\n                    resolution, true /* local */, VideoType.CAMERA));\r\n\r\n            this._avgLocalScreenPixels.addNext(\r\n                this._calculateAvgVideoPixels(\r\n                    resolution, true /* local */, VideoType.DESKTOP));\r\n        }\r\n\r\n        this._sampleIdx += 1;\r\n\r\n        if (this._sampleIdx >= this._n) {\r\n\r\n            const batchReport = {\r\n                p2p: isP2P,\r\n                'conference_size': confSize\r\n            };\r\n\r\n            if (data.transport && data.transport.length) {\r\n                Object.assign(batchReport, {\r\n                    'local_candidate_type':\r\n                        data.transport[0].localCandidateType,\r\n                    'remote_candidate_type':\r\n                        data.transport[0].remoteCandidateType,\r\n                    'transport_type': data.transport[0].type\r\n                });\r\n            }\r\n\r\n            this._avgAudioBitrateUp.appendReport(batchReport);\r\n            this._avgAudioBitrateDown.appendReport(batchReport);\r\n\r\n            this._avgVideoBitrateUp.appendReport(batchReport);\r\n            this._avgVideoBitrateDown.appendReport(batchReport);\r\n\r\n            if (browser.supportsBandwidthStatistics()) {\r\n                this._avgBandwidthUp.appendReport(batchReport);\r\n                this._avgBandwidthDown.appendReport(batchReport);\r\n            }\r\n            this._avgPacketLossUp.appendReport(batchReport);\r\n            this._avgPacketLossDown.appendReport(batchReport);\r\n            this._avgPacketLossTotal.appendReport(batchReport);\r\n\r\n            this._avgRemoteFPS.appendReport(batchReport);\r\n            if (!isNaN(this._avgRemoteScreenFPS.calculate())) {\r\n                this._avgRemoteScreenFPS.appendReport(batchReport);\r\n            }\r\n            this._avgLocalFPS.appendReport(batchReport);\r\n            if (!isNaN(this._avgLocalScreenFPS.calculate())) {\r\n                this._avgLocalScreenFPS.appendReport(batchReport);\r\n            }\r\n\r\n            this._avgRemoteCameraPixels.appendReport(batchReport);\r\n            if (!isNaN(this._avgRemoteScreenPixels.calculate())) {\r\n                this._avgRemoteScreenPixels.appendReport(batchReport);\r\n            }\r\n            this._avgLocalCameraPixels.appendReport(batchReport);\r\n            if (!isNaN(this._avgLocalScreenPixels.calculate())) {\r\n                this._avgLocalScreenPixels.appendReport(batchReport);\r\n            }\r\n\r\n            this._avgCQ.appendReport(batchReport);\r\n\r\n            Statistics.sendAnalytics(createRtpStatsEvent(batchReport));\r\n\r\n            this._resetAvgStats();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Calculates average number of pixels for the report\r\n     *\r\n     * @param {map} peerResolutions a map of peer resolutions\r\n     * @param {boolean} isLocal if the average is to be calculated for the local\r\n     * video or <tt>false</tt> if for remote videos.\r\n     * @param {VideoType} videoType\r\n     * @return {number|NaN} average number of pixels or <tt>NaN</tt> if there\r\n     * are no samples.\r\n     * @private\r\n     */\r\n    _calculateAvgVideoPixels(peerResolutions, isLocal, videoType) {\r\n        let peerPixelsSum = 0;\r\n        let peerCount = 0;\r\n        const myID = this._conference.myUserId();\r\n\r\n        for (const peerID of Object.keys(peerResolutions)) {\r\n            if (isLocal ? peerID === myID : peerID !== myID) {\r\n                const participant\r\n                    = isLocal\r\n                        ? null\r\n                        : this._conference.getParticipantById(peerID);\r\n                const videosResolution = peerResolutions[peerID];\r\n\r\n                // Do not continue without participant for non local peerID\r\n                if ((isLocal || participant) && videosResolution) {\r\n                    const peerAvgPixels = this._calculatePeerAvgVideoPixels(\r\n                        videosResolution, participant, videoType);\r\n\r\n                    if (!isNaN(peerAvgPixels)) {\r\n                        peerPixelsSum += peerAvgPixels;\r\n                        peerCount += 1;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        return peerPixelsSum / peerCount;\r\n    }\r\n\r\n    /**\r\n     * Calculate average pixels for either remote or local participant\r\n     * @param {object} videos maps resolution per video SSRC\r\n     * @param {JitsiParticipant|null} participant remote participant or\r\n     * <tt>null</tt> for local video pixels calculation.\r\n     * @param {VideoType} videoType the type of the video for which an average\r\n     * will be calculated.\r\n     * @return {number|NaN} average video pixels of all participant's videos or\r\n     * <tt>NaN</tt> if currently not available\r\n     * @private\r\n     */\r\n    _calculatePeerAvgVideoPixels(videos, participant, videoType) {\r\n        let ssrcs = Object.keys(videos).map(ssrc => Number(ssrc));\r\n        let videoTracks = null;\r\n\r\n        // NOTE that this method is supposed to be called for the stats\r\n        // received from the current peerconnection.\r\n        const tpc = this._conference.getActivePeerConnection();\r\n\r\n        if (participant) {\r\n            videoTracks = participant.getTracksByMediaType(MediaType.VIDEO);\r\n            if (videoTracks) {\r\n                ssrcs\r\n                    = ssrcs.filter(\r\n                        ssrc => videoTracks.find(\r\n                            track =>\r\n                                !track.isMuted()\r\n                                    && track.getSSRC() === ssrc\r\n                                    && track.videoType === videoType));\r\n            }\r\n        } else {\r\n            videoTracks = this._conference.getLocalTracks(MediaType.VIDEO);\r\n            ssrcs\r\n                = ssrcs.filter(\r\n                    ssrc => videoTracks.find(\r\n                        track =>\r\n                            !track.isMuted()\r\n                                && tpc.getLocalSSRC(track) === ssrc\r\n                                && track.videoType === videoType));\r\n        }\r\n\r\n        let peerPixelsSum = 0;\r\n        let peerSsrcCount = 0;\r\n\r\n        for (const ssrc of ssrcs) {\r\n            const peerSsrcPixels\r\n                = Number(videos[ssrc].height) * Number(videos[ssrc].width);\r\n\r\n            // FPS is reported as 0 for users with no video\r\n            if (!isNaN(peerSsrcPixels) && peerSsrcPixels > 0) {\r\n                peerPixelsSum += peerSsrcPixels;\r\n                peerSsrcCount += 1;\r\n            }\r\n        }\r\n\r\n        return peerPixelsSum / peerSsrcCount;\r\n    }\r\n\r\n\r\n    /**\r\n     * Calculates average FPS for the report\r\n     * @param {go figure} frameRate\r\n     * @param {boolean} isLocal if the average is to be calculated for the local\r\n     * video or <tt>false</tt> if for remote videos.\r\n     * @param {VideoType} videoType\r\n     * @return {number|NaN} average FPS or <tt>NaN</tt> if there are no samples.\r\n     * @private\r\n     */\r\n    _calculateAvgVideoFps(frameRate, isLocal, videoType) {\r\n        let peerFpsSum = 0;\r\n        let peerCount = 0;\r\n        const myID = this._conference.myUserId();\r\n\r\n        for (const peerID of Object.keys(frameRate)) {\r\n            if (isLocal ? peerID === myID : peerID !== myID) {\r\n                const participant\r\n                    = isLocal\r\n                        ? null : this._conference.getParticipantById(peerID);\r\n                const videosFps = frameRate[peerID];\r\n\r\n                // Do not continue without participant for non local peerID\r\n                if ((isLocal || participant) && videosFps) {\r\n                    const peerAvgFPS\r\n                        = this._calculatePeerAvgVideoFps(\r\n                            videosFps, participant, videoType);\r\n\r\n                    if (!isNaN(peerAvgFPS)) {\r\n                        peerFpsSum += peerAvgFPS;\r\n                        peerCount += 1;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        return peerFpsSum / peerCount;\r\n    }\r\n\r\n    /**\r\n     * Calculate average FPS for either remote or local participant\r\n     * @param {object} videos maps FPS per video SSRC\r\n     * @param {JitsiParticipant|null} participant remote participant or\r\n     * <tt>null</tt> for local FPS calculation.\r\n     * @param {VideoType} videoType the type of the video for which an average\r\n     * will be calculated.\r\n     * @return {number|NaN} average FPS of all participant's videos or\r\n     * <tt>NaN</tt> if currently not available\r\n     * @private\r\n     */\r\n    _calculatePeerAvgVideoFps(videos, participant, videoType) {\r\n        let ssrcs = Object.keys(videos).map(ssrc => Number(ssrc));\r\n        let videoTracks = null;\r\n\r\n        // NOTE that this method is supposed to be called for the stats\r\n        // received from the current peerconnection.\r\n        const tpc = this._conference.getActivePeerConnection();\r\n\r\n        if (participant) {\r\n            videoTracks = participant.getTracksByMediaType(MediaType.VIDEO);\r\n            if (videoTracks) {\r\n                ssrcs\r\n                    = ssrcs.filter(\r\n                        ssrc => videoTracks.find(\r\n                            track => !track.isMuted()\r\n                                && track.getSSRC() === ssrc\r\n                                && track.videoType === videoType));\r\n            }\r\n        } else {\r\n            videoTracks = this._conference.getLocalTracks(MediaType.VIDEO);\r\n            ssrcs\r\n                = ssrcs.filter(\r\n                    ssrc => videoTracks.find(\r\n                        track => !track.isMuted()\r\n                            && tpc.getLocalSSRC(track) === ssrc\r\n                            && track.videoType === videoType));\r\n        }\r\n\r\n        let peerFpsSum = 0;\r\n        let peerSsrcCount = 0;\r\n\r\n        for (const ssrc of ssrcs) {\r\n            const peerSsrcFps = Number(videos[ssrc]);\r\n\r\n            // FPS is reported as 0 for users with no video\r\n            if (!isNaN(peerSsrcFps) && peerSsrcFps > 0) {\r\n                peerFpsSum += peerSsrcFps;\r\n                peerSsrcCount += 1;\r\n            }\r\n        }\r\n\r\n        return peerFpsSum / peerSsrcCount;\r\n    }\r\n\r\n    /**\r\n     * Sends the 'transport.stats' analytics event whenever we detect that\r\n     * there is a change in the local or remote candidate type on the transport\r\n     * that is currently selected.\r\n     * @param {*} data\r\n     * @private\r\n     */\r\n    _maybeSendTransportAnalyticsEvent(data) {\r\n        if (!data || !data.transport || !data.transport.length) {\r\n            return;\r\n        }\r\n        const transportStats = {\r\n            p2p: data.transport[0].p2p,\r\n            'local_candidate_type': data.transport[0].localCandidateType,\r\n            'remote_candidate_type': data.transport[0].remoteCandidateType,\r\n            'transport_type': data.transport[0].type\r\n        };\r\n\r\n        if (!this._cachedTransportStats || !isEqual(transportStats, this._cachedTransportStats)) {\r\n            this._cachedTransportStats = transportStats;\r\n            Statistics.sendAnalytics(createTransportStatsEvent(transportStats));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Resets the stats related to JVB connection. Must not be called when in\r\n     * P2P mode, because then the {@link AverageStatReport} instances are\r\n     * tracking P2P stats. Note that this should never happen unless something\r\n     * is wrong with the P2P and JVB121 events.\r\n     * @private\r\n     */\r\n    _resetAvgJvbStats() {\r\n        this._resetAvgStats();\r\n        this.jvbStatsMonitor._resetAvgStats();\r\n    }\r\n\r\n    /**\r\n     * Reset cache of all averages and {@link _sampleIdx}.\r\n     * @private\r\n     */\r\n    _resetAvgStats() {\r\n        this._avgAudioBitrateUp.reset();\r\n        this._avgAudioBitrateDown.reset();\r\n\r\n        this._avgVideoBitrateUp.reset();\r\n        this._avgVideoBitrateDown.reset();\r\n\r\n        this._avgBandwidthUp.reset();\r\n        this._avgBandwidthDown.reset();\r\n\r\n        this._avgPacketLossUp.reset();\r\n        this._avgPacketLossDown.reset();\r\n        this._avgPacketLossTotal.reset();\r\n\r\n        this._avgRemoteFPS.reset();\r\n        this._avgRemoteScreenFPS.reset();\r\n        this._avgLocalFPS.reset();\r\n        this._avgLocalScreenFPS.reset();\r\n\r\n        this._avgRemoteCameraPixels.reset();\r\n        this._avgRemoteScreenPixels.reset();\r\n        this._avgLocalCameraPixels.reset();\r\n        this._avgLocalScreenPixels.reset();\r\n\r\n        this._avgCQ.reset();\r\n\r\n        this._sampleIdx = 0;\r\n    }\r\n\r\n    /**\r\n     * Unregisters all event listeners and stops working.\r\n     */\r\n    dispose() {\r\n        this._conference.off(\r\n            ConferenceEvents.P2P_STATUS,\r\n            this._onP2PStatusChanged);\r\n        this._conference.off(\r\n            ConnectionQualityEvents.LOCAL_STATS_UPDATED,\r\n            this._onLocalStatsUpdated);\r\n        this._conference.off(\r\n            ConferenceEvents.JVB121_STATUS,\r\n            this._onJvb121StatusChanged);\r\n        this.jvbStatsMonitor.dispose();\r\n        this.p2pStatsMonitor.dispose();\r\n    }\r\n}\r\n","import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\n\r\nimport SpeakerStats from './SpeakerStats';\r\n\r\n/**\r\n * A collection for tracking speaker stats. Attaches listeners\r\n * to the conference to automatically update on tracked events.\r\n */\r\nexport default class SpeakerStatsCollector {\r\n    /**\r\n     * Initializes a new SpeakerStatsCollector instance.\r\n     *\r\n     * @constructor\r\n     * @param {JitsiConference} conference - The conference to track.\r\n     * @returns {void}\r\n     */\r\n    constructor(conference) {\r\n        this.stats = {\r\n            users: {\r\n\r\n                // userId: SpeakerStats\r\n            },\r\n            dominantSpeakerId: null\r\n        };\r\n\r\n        const userId = conference.myUserId();\r\n\r\n        this.stats.users[userId] = new SpeakerStats(userId, null, true);\r\n        this.conference = conference;\r\n\r\n        conference.addEventListener(\r\n            JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,\r\n            this._onDominantSpeaker.bind(this));\r\n        conference.addEventListener(\r\n            JitsiConferenceEvents.USER_JOINED,\r\n            this._onUserJoin.bind(this));\r\n        conference.addEventListener(\r\n            JitsiConferenceEvents.USER_LEFT,\r\n            this._onUserLeave.bind(this));\r\n        conference.addEventListener(\r\n            JitsiConferenceEvents.DISPLAY_NAME_CHANGED,\r\n            this._onDisplayNameChange.bind(this));\r\n        conference.addEventListener(\r\n            JitsiConferenceEvents.FACE_LANDMARK_ADDED,\r\n            this._onFaceLandmarkAdd.bind(this));\r\n        if (conference.xmpp) {\r\n            conference.xmpp.addListener(\r\n                XMPPEvents.SPEAKER_STATS_RECEIVED,\r\n                this._updateStats.bind(this));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Reacts to dominant speaker change events by changing its speaker stats\r\n     * models to reflect the current dominant speaker.\r\n     *\r\n     * @param {string} dominantSpeakerId - The user id of the new dominant speaker.\r\n     * @param {Array[string]} previous - The array with previous speakers.\r\n     * @param {boolean} silence - Indecates whether the dominant speaker is silent or not.\r\n     * @returns {void}\r\n     * @private\r\n     */\r\n    _onDominantSpeaker(dominantSpeakerId, previous, silence) {\r\n        const oldDominantSpeaker\r\n            = this.stats.users[this.stats.dominantSpeakerId];\r\n        const newDominantSpeaker = this.stats.users[dominantSpeakerId];\r\n\r\n        oldDominantSpeaker && oldDominantSpeaker.setDominantSpeaker(false);\r\n        newDominantSpeaker && newDominantSpeaker.setDominantSpeaker(true, silence);\r\n        this.stats.dominantSpeakerId = dominantSpeakerId;\r\n    }\r\n\r\n    /**\r\n     * Reacts to user join events by creating a new SpeakerStats model.\r\n     *\r\n     * @param {string} userId - The user id of the new user.\r\n     * @param {JitsiParticipant} - The JitsiParticipant model for the new user.\r\n     * @returns {void}\r\n     * @private\r\n     */\r\n    _onUserJoin(userId, participant) {\r\n        if (participant.isHidden()) {\r\n            return;\r\n        }\r\n\r\n        if (!this.stats.users[userId]) {\r\n            this.stats.users[userId] = new SpeakerStats(userId, participant.getDisplayName());\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Reacts to user leave events by updating the associated user's\r\n     * SpeakerStats model.\r\n     *\r\n     * @param {string} userId - The user id of the user that left.\r\n     * @returns {void}\r\n     * @private\r\n     */\r\n    _onUserLeave(userId) {\r\n        const savedUser = this.stats.users[userId];\r\n\r\n        if (savedUser) {\r\n            savedUser.markAsHasLeft();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Reacts to user name change events by updating the last known name\r\n     * tracked in the associated SpeakerStats model.\r\n     *\r\n     * @param {string} userId - The user id of the user that left.\r\n     * @returns {void}\r\n     * @private\r\n     */\r\n    _onDisplayNameChange(userId, newName) {\r\n        const savedUser = this.stats.users[userId];\r\n\r\n        if (savedUser) {\r\n            savedUser.setDisplayName(newName);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Processes a new face landmark object of a remote user.\r\n     *\r\n     * @param {string} userId - The user id of the user that left.\r\n     * @param {Object} data - The face landmark object.\r\n     * @returns {void}\r\n     * @private\r\n     */\r\n    _onFaceLandmarkAdd(userId, data) {\r\n        const savedUser = this.stats.users[userId];\r\n\r\n        if (savedUser && data.faceExpression) {\r\n            savedUser.addFaceExpression(data.faceExpression, data.duration);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Return a copy of the tracked SpeakerStats models.\r\n     *\r\n     * @returns {Object} The keys are the user ids and the values are the\r\n     * associated user's SpeakerStats model.\r\n     */\r\n    getStats() {\r\n        return this.stats.users;\r\n    }\r\n\r\n    /**\r\n     * Updates of the current stats is requested, passing the new values.\r\n     *\r\n     * @param {Object} newStats - The new values used to update current one.\r\n     * @private\r\n     */\r\n    _updateStats(newStats) {\r\n        for (const userId in newStats) { // eslint-disable-line guard-for-in\r\n            let speakerStatsToUpdate;\r\n            const newParticipant = this.conference.getParticipantById(userId);\r\n\r\n            // we want to ignore hidden participants\r\n            if (!newParticipant || !newParticipant.isHidden()) {\r\n                if (this.stats.users[userId]) {\r\n                    speakerStatsToUpdate = this.stats.users[userId];\r\n\r\n                    if (!speakerStatsToUpdate.getDisplayName()) {\r\n                        speakerStatsToUpdate\r\n                            .setDisplayName(newStats[userId].displayName);\r\n                    }\r\n                } else {\r\n                    speakerStatsToUpdate = new SpeakerStats(\r\n                        userId, newStats[userId].displayName);\r\n                    this.stats.users[userId] = speakerStatsToUpdate;\r\n                    speakerStatsToUpdate.markAsHasLeft();\r\n                }\r\n\r\n                speakerStatsToUpdate.totalDominantSpeakerTime\r\n                    = newStats[userId].totalDominantSpeakerTime;\r\n\r\n                speakerStatsToUpdate.setFaceExpressions(newStats[userId].faceExpressions);\r\n            }\r\n        }\r\n    }\r\n}\r\n","/* eslint-disable max-params */\r\n\r\n/**\r\n * This object stores variables needed around the recording of an audio stream\r\n * and passing this recording along with additional information along to\r\n * different processes\r\n */\r\nexport default class RecordingResult {\r\n    /**\r\n     * @param blob the recording audio stream as a single blob\r\n     * @param name the name of the person of the audio stream\r\n     * @param startTime the time in UTC when recording of the audiostream started\r\n     * @param wordArray the recorder audio stream transcribed as an array of Word objects\r\n     */\r\n    constructor(blob, name, startTime, wordArray) {\r\n        this.blob = blob;\r\n        this.name = name;\r\n        this.startTime = startTime;\r\n        this.wordArray = wordArray;\r\n    }\r\n}\r\n","/**\r\n * A TrackRecorder object holds all the information needed for recording a\r\n * single JitsiTrack (either remote or local)\r\n * @param track The JitsiTrack the object is going to hold\r\n */\r\nexport default class TrackRecorder {\r\n    /**\r\n     * @param track The JitsiTrack the object is going to hold\r\n     */\r\n    constructor(track) {\r\n        // The JitsiTrack holding the stream\r\n        this.track = track;\r\n\r\n        // The MediaRecorder recording the stream\r\n        this.recorder = null;\r\n\r\n        // The array of data chunks recorded from the stream\r\n        // acts as a buffer until the data is stored on disk\r\n        this.data = null;\r\n\r\n        // the name of the person of the JitsiTrack. This can be undefined and/or\r\n        // not unique\r\n        this.name = null;\r\n\r\n        // the time of the start of the recording\r\n        this.startTime = null;\r\n    }\r\n}\r\n","import RecordingResult from './recordingResult';\r\nimport TrackRecorder from './trackRecorder';\r\n\r\n/**\r\n * Possible audio formats MIME types\r\n */\r\nconst AUDIO_WEBM = 'audio/webm'; // Supported in chrome\r\nconst AUDIO_OGG = 'audio/ogg'; // Supported in firefox\r\n\r\n/**\r\n * Starts the recording of a JitsiTrack in a TrackRecorder object.\r\n * This will also define the timestamp and try to update the name\r\n * @param trackRecorder the TrackRecorder to start\r\n */\r\nfunction startRecorder(trackRecorder) {\r\n    if (trackRecorder.recorder === undefined) {\r\n        throw new Error('Passed an object to startRecorder which is not a '\r\n            + 'TrackRecorder object');\r\n    }\r\n    trackRecorder.recorder.start();\r\n    trackRecorder.startTime = new Date();\r\n}\r\n\r\n/**\r\n * Stops the recording of a JitsiTrack in a TrackRecorder object.\r\n * This will also try to update the name\r\n * @param trackRecorder the TrackRecorder to stop\r\n */\r\nfunction stopRecorder(trackRecorder) {\r\n    if (trackRecorder.recorder === undefined) {\r\n        throw new Error('Passed an object to stopRecorder which is not a '\r\n            + 'TrackRecorder object');\r\n    }\r\n    trackRecorder.recorder.stop();\r\n}\r\n\r\n/**\r\n * Determines which kind of audio recording the browser supports\r\n * chrome supports \"audio/webm\" and firefox supports \"audio/ogg\"\r\n */\r\nfunction determineCorrectFileType() {\r\n    if (MediaRecorder.isTypeSupported(AUDIO_WEBM)) {\r\n        return AUDIO_WEBM;\r\n    } else if (MediaRecorder.isTypeSupported(AUDIO_OGG)) {\r\n        return AUDIO_OGG;\r\n    }\r\n    throw new Error(\r\n        'unable to create a MediaRecorder with the right mimetype!');\r\n}\r\n\r\n/**\r\n * main exported object of the file, holding all\r\n * relevant functions and variables for the outside world\r\n * @param jitsiConference the jitsiConference which this object\r\n * is going to record\r\n */\r\nfunction AudioRecorder(jitsiConference) {\r\n    // array of TrackRecorders, where each trackRecorder\r\n    // holds the JitsiTrack, MediaRecorder and recorder data\r\n    this.recorders = [];\r\n\r\n    // get which file type is supported by the current browser\r\n    this.fileType = determineCorrectFileType();\r\n\r\n    // boolean flag for active recording\r\n    this.isRecording = false;\r\n\r\n    // the jitsiconference the object is recording\r\n    this.jitsiConference = jitsiConference;\r\n}\r\n\r\n/**\r\n * Add the exported module so that it can be accessed by other files\r\n */\r\nAudioRecorder.determineCorrectFileType = determineCorrectFileType;\r\n\r\n/**\r\n * Adds a new TrackRecorder object to the array.\r\n *\r\n * @param track the track potentially holding an audio stream\r\n */\r\nAudioRecorder.prototype.addTrack = function(track) {\r\n    if (track.isAudioTrack()) {\r\n        // create the track recorder\r\n        const trackRecorder = this.instantiateTrackRecorder(track);\r\n\r\n        // push it to the local array of all recorders\r\n\r\n        this.recorders.push(trackRecorder);\r\n\r\n        // update the name of the trackRecorders\r\n        this.updateNames();\r\n\r\n        // If we're already recording, immediately start recording this new\r\n        // track.\r\n        if (this.isRecording) {\r\n            startRecorder(trackRecorder);\r\n        }\r\n    }\r\n};\r\n\r\n/**\r\n * Creates a TrackRecorder object. Also creates the MediaRecorder and\r\n * data array for the trackRecorder.\r\n * @param track the JitsiTrack holding the audio MediaStream(s)\r\n */\r\nAudioRecorder.prototype.instantiateTrackRecorder = function(track) {\r\n    const trackRecorder = new TrackRecorder(track);\r\n\r\n    // Create a new stream which only holds the audio track\r\n    const originalStream = trackRecorder.track.getOriginalStream();\r\n    const stream = new MediaStream();\r\n\r\n    originalStream.getAudioTracks().forEach(t => stream.addTrack(t));\r\n\r\n    // Create the MediaRecorder\r\n    trackRecorder.recorder = new MediaRecorder(stream,\r\n        { mimeType: this.fileType });\r\n\r\n    // array for holding the recorder data. Resets it when\r\n    // audio already has been recorder once\r\n    trackRecorder.data = [];\r\n\r\n    // function handling a dataEvent, e.g the stream gets new data\r\n    trackRecorder.recorder.ondataavailable = function(dataEvent) {\r\n        if (dataEvent.data.size > 0) {\r\n            trackRecorder.data.push(dataEvent.data);\r\n        }\r\n    };\r\n\r\n    return trackRecorder;\r\n};\r\n\r\n/**\r\n * Notifies the module that a specific track has stopped, e.g participant left\r\n * the conference.\r\n * if the recording has not started yet, the TrackRecorder will be removed from\r\n * the array. If the recording has started, the recorder will stop recording\r\n * but not removed from the array so that the recorded stream can still be\r\n * accessed\r\n *\r\n * @param {JitsiTrack} track the JitsiTrack to remove from the recording session\r\n */\r\nAudioRecorder.prototype.removeTrack = function(track) {\r\n    if (track.isVideoTrack()) {\r\n        return;\r\n    }\r\n\r\n    const array = this.recorders;\r\n    let i;\r\n\r\n    for (i = 0; i < array.length; i++) {\r\n        if (array[i].track.getParticipantId() === track.getParticipantId()) {\r\n            const recorderToRemove = array[i];\r\n\r\n            if (this.isRecording) {\r\n                stopRecorder(recorderToRemove);\r\n            } else {\r\n                // remove the TrackRecorder from the array\r\n                array.splice(i, 1);\r\n            }\r\n        }\r\n    }\r\n\r\n    // make sure the names are up to date\r\n    this.updateNames();\r\n};\r\n\r\n/**\r\n * Tries to update the name value of all TrackRecorder in the array.\r\n * If it hasn't changed,it will keep the exiting name. If it changes to a\r\n * undefined value, the old value will also be kept.\r\n */\r\nAudioRecorder.prototype.updateNames = function() {\r\n    const conference = this.jitsiConference;\r\n\r\n    this.recorders.forEach(trackRecorder => {\r\n        if (trackRecorder.track.isLocal()) {\r\n            trackRecorder.name = 'the transcriber';\r\n        } else {\r\n            const id = trackRecorder.track.getParticipantId();\r\n            const participant = conference.getParticipantById(id);\r\n            const newName = participant.getDisplayName();\r\n\r\n            if (newName !== 'undefined') {\r\n                trackRecorder.name = newName;\r\n            }\r\n        }\r\n    });\r\n};\r\n\r\n/**\r\n * Starts the audio recording of every local and remote track\r\n */\r\nAudioRecorder.prototype.start = function() {\r\n    if (this.isRecording) {\r\n        throw new Error('audiorecorder is already recording');\r\n    }\r\n\r\n    // set boolean isRecording flag to true so if new participants join the\r\n    // conference, that track can instantly start recording as well\r\n    this.isRecording = true;\r\n\r\n    // start all the mediaRecorders\r\n    this.recorders.forEach(trackRecorder => startRecorder(trackRecorder));\r\n\r\n    // log that recording has started\r\n    console.log(\r\n        `Started the recording of the audio. There are currently ${\r\n            this.recorders.length} recorders active.`);\r\n};\r\n\r\n/**\r\n * Stops the audio recording of every local and remote track\r\n */\r\nAudioRecorder.prototype.stop = function() {\r\n    // set the boolean flag to false\r\n    this.isRecording = false;\r\n\r\n    // stop all recorders\r\n    this.recorders.forEach(trackRecorder => stopRecorder(trackRecorder));\r\n    console.log('stopped recording');\r\n};\r\n\r\n/**\r\n * link hacking to download all recorded audio streams\r\n */\r\nAudioRecorder.prototype.download = function() {\r\n    this.recorders.forEach(trackRecorder => {\r\n        const blob = new Blob(trackRecorder.data, { type: this.fileType });\r\n        const url = URL.createObjectURL(blob);\r\n        const a = document.createElement('a');\r\n\r\n        document.body.appendChild(a);\r\n        a.style = 'display: none';\r\n        a.href = url;\r\n        a.download = `test.${this.fileType.split('/')[1]}`;\r\n        a.click();\r\n        window.URL.revokeObjectURL(url);\r\n    });\r\n};\r\n\r\n/**\r\n * returns the audio files of all recorders as an array of objects,\r\n * which include the name of the owner of the track and the starting time stamp\r\n * @returns {Array} an array of RecordingResult objects\r\n */\r\nAudioRecorder.prototype.getRecordingResults = function() {\r\n    if (this.isRecording) {\r\n        throw new Error(\r\n            'cannot get blobs because the AudioRecorder is still recording!');\r\n    }\r\n\r\n    // make sure the names are up to date before sending them off\r\n    this.updateNames();\r\n\r\n    const array = [];\r\n\r\n    this.recorders.forEach(\r\n        recorder =>\r\n            array.push(\r\n                new RecordingResult(\r\n                    new Blob(recorder.data, { type: this.fileType }),\r\n                    recorder.name,\r\n                    recorder.startTime)));\r\n\r\n    return array;\r\n};\r\n\r\n/**\r\n * Gets the mime type of the recorder audio\r\n * @returns {String} the mime type of the recorder audio\r\n */\r\nAudioRecorder.prototype.getFileType = function() {\r\n    return this.fileType;\r\n};\r\n\r\n/**\r\n * export the main object AudioRecorder\r\n */\r\nexport default AudioRecorder;\r\n","/**\r\n * An object representing a transcribed word, with some additional information\r\n * @param word the word\r\n * @param begin the time the word was started being uttered\r\n * @param end the time the word stopped being uttered\r\n */\r\nexport default class Word {\r\n    /**\r\n     * @param word the word\r\n     * @param begin the time the word was started being uttered\r\n     * @param end the time the word stopped being uttered\r\n     */\r\n    constructor(word, begin, end) {\r\n        this.word = word;\r\n        this.begin = begin;\r\n        this.end = end;\r\n    }\r\n\r\n    /**\r\n     * Get the string representation of the word\r\n     * @returns {*} the word as a string\r\n     */\r\n    getWord() {\r\n        return this.word;\r\n    }\r\n\r\n    /**\r\n     * Get the time the word started being uttered\r\n     * @returns {*} the start time as an integer\r\n     */\r\n    getBeginTime() {\r\n        return this.begin;\r\n    }\r\n\r\n    /**\r\n     * Get the time the word stopped being uttered\r\n     * @returns {*} the end time as an integer\r\n     */\r\n    getEndTime() {\r\n        return this.end;\r\n    }\r\n}\r\n","/* global config */\r\n\r\nimport Word from '../word';\r\n\r\nimport audioRecorder from './../audioRecorder';\r\nimport AbstractTranscriptionService from './AbstractTranscriptionService';\r\n\r\n/**\r\n * Implements a TranscriptionService for a Sphinx4 http server\r\n */\r\nexport default class SphinxService extends AbstractTranscriptionService {\r\n    /**\r\n     * Implements a TranscriptionService for a Sphinx4 http server\r\n     */\r\n    constructor() {\r\n        super();\r\n\r\n        // set the correct url\r\n        this.url = getURL();\r\n    }\r\n\r\n    /**\r\n     * Overrides the sendRequest method from AbstractTranscriptionService\r\n     * it will send the audio stream the a Sphinx4 server to get the transcription\r\n     *\r\n     * @param audioFileBlob the recorder audio stream an a single Blob\r\n     * @param callback the callback function retrieving the server response\r\n     */\r\n    sendRequest(audioFileBlob, callback) {\r\n        console.log(`sending an audio file  to ${this.url}`);\r\n        console.log(`the audio file being sent: ${audioFileBlob}`);\r\n        const request = new XMLHttpRequest();\r\n\r\n        request.onreadystatechange = function() {\r\n            if (request.readyState === XMLHttpRequest.DONE\r\n                && request.status === 200) {\r\n                callback(request.responseText);\r\n            } else if (request.readyState === XMLHttpRequest.DONE) {\r\n                throw new Error(\r\n                    `unable to accept response from sphinx server. status: ${request.status}`);\r\n            }\r\n\r\n            // if not ready no point to throw an error\r\n        };\r\n        request.open('POST', this.url);\r\n        request.setRequestHeader('Content-Type',\r\n            audioRecorder.determineCorrectFileType());\r\n        request.send(audioFileBlob);\r\n        console.log(`send ${audioFileBlob}`);\r\n    }\r\n\r\n    /**\r\n     * Overrides the formatResponse method from AbstractTranscriptionService\r\n     * It will parse the answer from the server in the expected format\r\n     *\r\n     * @param response the JSON body retrieved from the Sphinx4 server\r\n     */\r\n    formatResponse(response) {\r\n        const result = JSON.parse(response).objects;\r\n\r\n        // make sure to delete the session id object, which is always\r\n        // the first value in the JSON array\r\n        result.shift();\r\n        const array = [];\r\n\r\n        result.forEach(\r\n            word => word.filler\r\n                || array.push(new Word(word.word, word.start, word.end)));\r\n\r\n        return array;\r\n    }\r\n\r\n    /**\r\n     * checks wether the reply is empty, or doesn't contain a correct JSON object\r\n     * @param response the server response\r\n     * @return {boolean} whether the response is valid\r\n     */\r\n    verify(response) {\r\n        console.log(`response from server:${response.toString()}`);\r\n\r\n        // test if server responded with a string object\r\n        if (typeof response !== 'string') {\r\n            return false;\r\n        }\r\n\r\n        // test if the string can be parsed into valid JSON\r\n        let json;\r\n\r\n        try {\r\n            json = JSON.parse(response);\r\n        } catch (error) {\r\n            console.log(error);\r\n\r\n            return false;\r\n        }\r\n\r\n        // check if the JSON has a \"objects\" value\r\n        if (json.objects === undefined) {\r\n            return false;\r\n        }\r\n\r\n        // get the \"objects\" value and check for a session ID\r\n        const array = json.objects;\r\n\r\n        if (!(array[0] && array[0]['session-id'])) {\r\n            return false;\r\n        }\r\n\r\n        // everything seems to be in order\r\n        return true;\r\n    }\r\n}\r\n\r\n/**\r\n * Gets the URL to the Sphinx4 server from the config file. If it's not there,\r\n * it will throw an error\r\n *\r\n * @returns {string} the URL to the sphinx4 server\r\n */\r\nfunction getURL() {\r\n    const message = 'config does not contain an url to a Sphinx4 https server';\r\n\r\n    if (config.sphinxURL === undefined) {\r\n        console.log(message);\r\n    } else {\r\n        const toReturn = config.sphinxURL;\r\n\r\n        if (toReturn.includes !== undefined && toReturn.includes('https://')) {\r\n            return toReturn;\r\n        }\r\n        console.log(message);\r\n\r\n    }\r\n}\r\n","/**\r\n * Abstract class representing an interface to implement a speech-to-text\r\n * service on.\r\n */\r\nexport default class TranscriptionService {\r\n    /**\r\n     * Abstract class representing an interface to implement a speech-to-text\r\n     * service on.\r\n     */\r\n    constructor() {\r\n        throw new Error('TranscriptionService is abstract and cannot be created');\r\n    }\r\n\r\n    /**\r\n     * This method can be used to send the recorder audio stream and\r\n     * retrieve the answer from the transcription service from the callback\r\n     *\r\n     * @param {RecordingResult} recordingResult a recordingResult object which\r\n     * includes the recorded audio stream as a blob\r\n     * @param {Function} callback  which will retrieve the a RecordingResult with\r\n     *        the answer as a WordArray\r\n     */\r\n    send(recordingResult, callback) {\r\n        this.sendRequest(recordingResult.blob, response => {\r\n            if (this.verify(response)) {\r\n                recordingResult.wordArray = this.formatResponse(response);\r\n            } else {\r\n                console.log('the retrieved response from the server is not valid!');\r\n                recordingResult.wordArray = [];\r\n            }\r\n            callback(recordingResult);\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Abstract method which will rend the recorder audio stream to the implemented\r\n     * transcription service and will retrieve an answer, which will be\r\n     * called on the given callback method\r\n     *\r\n     * @param {Blob} audioBlob the recorded audio stream as a single Blob\r\n     * @param {function} callback function which will retrieve the answer\r\n     *                            from the service\r\n     */\r\n    sendRequest(audioBlob, callback) { // eslint-disable-line no-unused-vars\r\n        throw new Error('TranscriptionService.sendRequest is abstract');\r\n    }\r\n\r\n    /**\r\n     * Abstract method which will parse the output from the implemented\r\n     * transcription service to the expected format\r\n     *\r\n     * The transcriber class expect an array of word objects, where each word\r\n     * object is one transcribed word by the service.\r\n     *\r\n     * The expected output of this method is an array of word objects, in\r\n     * the correct order. That is, the first object in the array is the first word\r\n     * being said, and the last word in the array is the last word being said\r\n     *\r\n     * @param response the answer from the speech-to-text server which needs to be\r\n     *                 formatted\r\n     * @return {Array<Word>} an array of Word objects\r\n     */\r\n    formatResponse(response) { // eslint-disable-line no-unused-vars\r\n        throw new Error('TranscriptionService.format is abstract');\r\n    }\r\n\r\n    /**\r\n     * Abstract method which will verify that the response from the server is valid\r\n     *\r\n     * @param response the response from the server\r\n     * @return {boolean} true if response is valid, false otherwise\r\n     */\r\n    verify(response) { // eslint-disable-line no-unused-vars\r\n        throw new Error('TranscriptionService.verify is abstract');\r\n    }\r\n}\r\n","import AudioRecorder from './audioRecorder';\r\nimport SphinxService from './transcriptionServices/SphinxTranscriptionService';\r\n\r\nconst BEFORE_STATE = 'before';\r\nconst RECORDING_STATE = 'recording';\r\nconst TRANSCRIBING_STATE = 'transcribing';\r\nconst FINISHED_STATE = 'finished';\r\n\r\n// the amount of characters each line in the transcription will have\r\nconst MAXIMUM_SENTENCE_LENGTH = 80;\r\n\r\n/**\r\n * This is the main object for handing the Transcription. It interacts with\r\n * the audioRecorder to record every person in a conference and sends the\r\n * recorder audio to a transcriptionService. The returned speech-to-text result\r\n * will be merged to create a transcript\r\n * @param {AudioRecorder} audioRecorder An audioRecorder recording a conference\r\n */\r\nfunction Transcriber() {\r\n    // the object which can record all audio in the conference\r\n    this.audioRecorder = new AudioRecorder();\r\n\r\n    // this object can send the recorder audio to a speech-to-text service\r\n    this.transcriptionService = new SphinxService();\r\n\r\n    // holds a counter to keep track if merging can start\r\n    this.counter = null;\r\n\r\n    // holds the date when transcription started which makes it possible\r\n    // to calculate the offset between recordings\r\n    this.startTime = null;\r\n\r\n    // will hold the transcription once it is completed\r\n    this.transcription = null;\r\n\r\n    // this will be a method which will be called once the transcription is done\r\n    // with the transcription as parameter\r\n    this.callback = null;\r\n\r\n    // stores all the retrieved speech-to-text results to merge together\r\n    // this value will store an Array<Word> object\r\n    this.results = [];\r\n\r\n    // Stores the current state of the transcription process\r\n    this.state = BEFORE_STATE;\r\n\r\n    // Used in the updateTranscription method to add a new line when the\r\n    // sentence becomes to long\r\n    this.lineLength = 0;\r\n}\r\n\r\n/**\r\n * Method to start the transcription process. It will tell the audioRecorder\r\n * to start storing all audio streams and record the start time for merging\r\n * purposes\r\n */\r\nTranscriber.prototype.start = function start() {\r\n    if (this.state !== BEFORE_STATE) {\r\n        throw new Error(\r\n            `The transcription can only start when it's in the \"${\r\n                BEFORE_STATE}\" state. It's currently in the \"${\r\n                this.state}\" state`);\r\n    }\r\n    this.state = RECORDING_STATE;\r\n    this.audioRecorder.start();\r\n    this.startTime = new Date();\r\n};\r\n\r\n/**\r\n * Method to stop the transcription process. It will tell the audioRecorder to\r\n * stop, and get all the recorded audio to send it to the transcription service\r\n\r\n * @param callback a callback which will receive the transcription\r\n */\r\nTranscriber.prototype.stop = function stop(callback) {\r\n    if (this.state !== RECORDING_STATE) {\r\n        throw new Error(\r\n            `The transcription can only stop when it's in the \"${\r\n                RECORDING_STATE}\" state. It's currently in the \"${\r\n                this.state}\" state`);\r\n    }\r\n\r\n    // stop the recording\r\n    console.log('stopping recording and sending audio files');\r\n    this.audioRecorder.stop();\r\n\r\n    // and send all recorded audio to the transcription service\r\n    const callBack = blobCallBack.bind(null, this);\r\n\r\n    this.audioRecorder.getRecordingResults().forEach(recordingResult => {\r\n        this.transcriptionService.send(recordingResult, callBack);\r\n        this.counter++;\r\n    });\r\n\r\n    // set the state to \"transcribing\" so that maybeMerge() functions correctly\r\n    this.state = TRANSCRIBING_STATE;\r\n\r\n    // and store the callback for later\r\n    this.callback = callback;\r\n};\r\n\r\n/**\r\n * This method gets the answer from the transcription service, calculates the\r\n * offset and adds is to every Word object. It will also start the merging\r\n * when every send request has been received\r\n *\r\n * note: Make sure to bind this as a Transcription object\r\n * @param {Transcriber} transcriber the transcriber instance\r\n * @param {RecordingResult} answer a RecordingResult object with a defined\r\n * WordArray\r\n */\r\nfunction blobCallBack(transcriber, answer) {\r\n    console.log(\r\n        'retrieved an answer from the transcription service. The answer has an'\r\n            + ` array of length: ${answer.wordArray.length}`);\r\n\r\n    // first add the offset between the start of the transcription and\r\n    // the start of the recording to all start and end times\r\n    if (answer.wordArray.length > 0) {\r\n        let offset = answer.startTime.getUTCMilliseconds()\r\n            - transcriber.startTime.getUTCMilliseconds();\r\n\r\n        // transcriber time will always be earlier\r\n\r\n        if (offset < 0) {\r\n            offset = 0; // presume 0 if it somehow not earlier\r\n        }\r\n\r\n        let array = '[';\r\n\r\n        answer.wordArray.forEach(wordObject => {\r\n            wordObject.begin += offset;\r\n            wordObject.end += offset;\r\n            array += `${wordObject.word},`;\r\n        });\r\n        array += ']';\r\n        console.log(array);\r\n\r\n        // give a name value to the Array object so that the merging can access\r\n        // the name value without having to use the whole recordingResult object\r\n        // in the algorithm\r\n        answer.wordArray.name = answer.name;\r\n    }\r\n\r\n    // then store the array and decrease the counter\r\n    transcriber.results.push(answer.wordArray);\r\n    transcriber.counter--;\r\n    console.log(`current counter: ${transcriber.counter}`);\r\n\r\n    // and check if all results have been received.\r\n    transcriber.maybeMerge();\r\n}\r\n\r\n/**\r\n * this method will check if the counter is zero. If it is, it will call\r\n * the merging method\r\n */\r\nTranscriber.prototype.maybeMerge = function() {\r\n    if (this.state === TRANSCRIBING_STATE && this.counter === 0) {\r\n        // make sure to include the events in the result arrays before\r\n        // merging starts\r\n        this.merge();\r\n    }\r\n};\r\n\r\n/**\r\n * This method will merge all speech-to-text arrays together in one\r\n * readable transcription string\r\n */\r\nTranscriber.prototype.merge = function() {\r\n    console.log(\r\n        `starting merge process!\\n The length of the array: ${\r\n            this.results.length}`);\r\n    this.transcription = '';\r\n\r\n    // the merging algorithm will look over all Word objects who are at pos 0 in\r\n    // every array. It will then select the one closest in time to the\r\n    // previously placed word, while removing the selected word from its array\r\n    // note: words can be skipped the skipped word's begin and end time somehow\r\n    // end up between the closest word start and end time\r\n    const arrays = this.results;\r\n\r\n    // arrays of Word objects\r\n    const potentialWords = []; // array of the first Word objects\r\n    // check if any arrays are already empty and remove them\r\n\r\n    hasPopulatedArrays(arrays);\r\n\r\n    // populate all the potential Words for a first time\r\n    arrays.forEach(array => pushWordToSortedArray(potentialWords, array));\r\n\r\n    // keep adding words to transcription until all arrays are exhausted\r\n    while (hasPopulatedArrays(arrays)) {\r\n        // first select the lowest array;\r\n        let lowestWordArray = arrays[0];\r\n\r\n        arrays.forEach(wordArray => {\r\n            if (wordArray[0].begin < lowestWordArray[0].begin) {\r\n                lowestWordArray = wordArray;\r\n            }\r\n        });\r\n\r\n        // put the word in the transcription\r\n        let wordToAdd = lowestWordArray.shift();\r\n\r\n        this.updateTranscription(wordToAdd, lowestWordArray.name);\r\n\r\n        // keep going until a word in another array has a smaller time\r\n        // or the array is empty\r\n        while (lowestWordArray.length > 0) {\r\n            let foundSmaller = false;\r\n            const wordToCompare = lowestWordArray[0].begin;\r\n\r\n            arrays.forEach(wordArray => {\r\n                if (wordArray[0].begin < wordToCompare) {\r\n                    foundSmaller = true;\r\n                }\r\n            });\r\n\r\n            // add next word if no smaller time has been found\r\n            if (foundSmaller) {\r\n                break;\r\n            }\r\n\r\n            wordToAdd = lowestWordArray.shift();\r\n            this.updateTranscription(wordToAdd, null);\r\n        }\r\n\r\n    }\r\n\r\n    // set the state to finished and do the necessary left-over tasks\r\n    this.state = FINISHED_STATE;\r\n    if (this.callback) {\r\n        this.callback(this.transcription);\r\n    }\r\n};\r\n\r\n/**\r\n * Appends a word object to the transcription. It will make a new line with a\r\n * name if a name is specified\r\n * @param {Word} word the Word object holding the word to append\r\n * @param {String|null} name the name of a new speaker. Null if not applicable\r\n */\r\nTranscriber.prototype.updateTranscription = function(word, name) {\r\n    if (name !== undefined && name !== null) {\r\n        this.transcription += `\\n${name}:`;\r\n        this.lineLength = name.length + 1; // +1 for the semi-colon\r\n    }\r\n    if (this.lineLength + word.word.length > MAXIMUM_SENTENCE_LENGTH) {\r\n        this.transcription += '\\n    ';\r\n        this.lineLength = 4; // because of the 4 spaces after the new line\r\n    }\r\n    this.transcription += ` ${word.word}`;\r\n    this.lineLength += word.word.length + 1; // +1 for the space\r\n};\r\n\r\n/**\r\n * Check if the given 2 dimensional array has any non-zero Word-arrays in them.\r\n * All zero-element arrays inside will be removed\r\n * If any non-zero-element arrays are found, the method will return true.\r\n * otherwise it will return false\r\n * @param {Array<Array>} twoDimensionalArray the array to check\r\n * @returns {boolean} true if any non-zero arrays inside, otherwise false\r\n */\r\nfunction hasPopulatedArrays(twoDimensionalArray) {\r\n    for (let i = 0; i < twoDimensionalArray.length; i++) {\r\n        if (twoDimensionalArray[i].length === 0) {\r\n            twoDimensionalArray.splice(i, 1);\r\n        }\r\n    }\r\n\r\n    return twoDimensionalArray.length > 0;\r\n}\r\n\r\n/**\r\n * Push a word to the right location in a sorted array. The array is sorted\r\n * from lowest to highest start time. Every word is stored in an object which\r\n * includes the name of the person saying the word.\r\n *\r\n * @param {Array<Word>} array the sorted array to push to\r\n * @param {Word} word the word to push into the array\r\n */\r\nfunction pushWordToSortedArray(array, word) {\r\n    if (array.length === 0) {\r\n        array.push(word);\r\n    } else {\r\n        if (array[array.length - 1].begin <= word.begin) {\r\n            array.push(word);\r\n\r\n            return;\r\n        }\r\n\r\n        for (let i = 0; i < array.length; i++) {\r\n            if (word.begin < array[i].begin) {\r\n                array.splice(i, 0, word);\r\n\r\n                return;\r\n            }\r\n        }\r\n        array.push(word); // fail safe\r\n    }\r\n}\r\n\r\n/**\r\n * Gives the transcriber a JitsiTrack holding an audioStream to transcribe.\r\n * The JitsiTrack is given to the audioRecorder. If it doesn't hold an\r\n * audiostream, it will not be added by the audioRecorder\r\n * @param {JitsiTrack} track the track to give to the audioRecorder\r\n */\r\nTranscriber.prototype.addTrack = function(track) {\r\n    this.audioRecorder.addTrack(track);\r\n};\r\n\r\n/**\r\n * Remove the given track from the auioRecorder\r\n * @param track\r\n */\r\nTranscriber.prototype.removeTrack = function(track) {\r\n    this.audioRecorder.removeTrack(track);\r\n};\r\n\r\n/**\r\n * Will return the created transcription if it's avialable or throw an error\r\n * when it's not done yet\r\n * @returns {String} the transcription as a String\r\n */\r\nTranscriber.prototype.getTranscription = function() {\r\n    if (this.state !== FINISHED_STATE) {\r\n        throw new Error(\r\n            `The transcription can only be retrieved when it's in the \"${\r\n                FINISHED_STATE}\" state. It's currently in the \"${\r\n                this.state}\" state`);\r\n    }\r\n\r\n    return this.transcription;\r\n};\r\n\r\n/**\r\n * Returns the current state of the transcription process\r\n */\r\nTranscriber.prototype.getState = function() {\r\n    return this.state;\r\n};\r\n\r\n/**\r\n * Resets the state to the \"before\" state, such that it's again possible to\r\n * call the start method\r\n */\r\nTranscriber.prototype.reset = function() {\r\n    this.state = BEFORE_STATE;\r\n    this.counter = null;\r\n    this.transcription = null;\r\n    this.startTime = null;\r\n    this.callback = null;\r\n    this.results = [];\r\n    this.lineLength = 0;\r\n};\r\n\r\nexport default Transcriber;\r\n","import Statistics from '../statistics/statistics';\r\n\r\nconst logger = require('@jitsi/logger').getLogger(__filename);\r\n\r\n/**\r\n * Creates new instance of <tt>ComponentsVersions</tt> which will be discovering\r\n * the versions of conferencing system components in given\r\n * <tt>JitsiConference</tt>.\r\n * @param conference <tt>JitsiConference</tt> instance which will be used to\r\n *        listen for focus presence updates.\r\n * @constructor\r\n */\r\nexport default function ComponentsVersions(conference) {\r\n\r\n    this.versions = {};\r\n\r\n    this.conference = conference;\r\n    this.conference.addCommandListener(\r\n        'versions', this.processVersions.bind(this));\r\n}\r\n\r\nComponentsVersions.prototype.processVersions\r\n    = function(versions, mucResource, mucJid) {\r\n        if (!this.conference.isFocus(mucJid)) {\r\n            logger.warn(\r\n                `Received versions not from the focus user: ${versions}`,\r\n                mucJid);\r\n\r\n            return;\r\n        }\r\n\r\n        const log = [];\r\n\r\n        versions.children.forEach(component => {\r\n\r\n            const name = component.attributes.name;\r\n            const version = component.value;\r\n\r\n            if (this.versions[name] !== version) {\r\n                this.versions[name] = version;\r\n                logger.info(`Got ${name} version: ${version}`);\r\n\r\n                log.push({\r\n                    id: 'component_version',\r\n                    component: name,\r\n                    version\r\n                });\r\n            }\r\n        });\r\n\r\n        // logs versions to stats\r\n        if (log.length > 0) {\r\n            Statistics.sendLog(JSON.stringify(log));\r\n        }\r\n    };\r\n\r\n/**\r\n * Obtains the version of conferencing system component.\r\n * @param componentName the name of the component for which we want to obtain\r\n *        the version.\r\n * @returns {String} which describes the version of the component identified by\r\n *          given <tt>componentName</tt> or <tt>undefined</tt> if not found.\r\n */\r\nComponentsVersions.prototype.getComponentVersion = function(componentName) {\r\n    return this.versions[componentName];\r\n};\r\n","export enum VideoSIPGWStatusConstants {\r\n    /**\r\n     * Status that video SIP GW service is available.\r\n     */\r\n    STATUS_AVAILABLE = 'available',\r\n\r\n    /**\r\n     * Status that video SIP GW service is not available.\r\n     */\r\n    STATUS_UNDEFINED = 'undefined',\r\n\r\n    /**\r\n     * Status that video SIP GW service is available but there are no free nodes\r\n     * at the moment to serve new requests.\r\n     */\r\n    STATUS_BUSY = 'busy'\r\n};\r\n\r\nexport enum VideoSIPGWStateConstants {\r\n    /**\r\n     * Video SIP GW session state, currently running.\r\n     */\r\n    STATE_ON = 'on',\r\n\r\n    /**\r\n     * Video SIP GW session state, currently stopped and not running.\r\n     */\r\n    STATE_OFF = 'off',\r\n\r\n    /**\r\n     * Video SIP GW session state, currently is starting.\r\n     */\r\n    STATE_PENDING = 'pending',\r\n\r\n    /**\r\n     * Video SIP GW session state, has observed some issues and is retrying at the\r\n     * moment.\r\n     */\r\n    STATE_RETRYING = 'retrying',\r\n\r\n    /**\r\n     * Video SIP GW session state, tried to start but it failed.\r\n     */\r\n    STATE_FAILED = 'failed'\r\n};\r\n\r\nexport enum VideoSIPGWErrorConstants {\r\n    /**\r\n     * Error on trying to create video SIP GW session in conference where\r\n     * there is no room connection (hasn't joined or has left the room).\r\n     */\r\n    ERROR_NO_CONNECTION = 'error_no_connection',\r\n\r\n    /**\r\n     * Error on trying to create video SIP GW session with address for which\r\n     * there is an already created session.\r\n     */\r\n    ERROR_SESSION_EXISTS = 'error_session_already_exists'\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const STATUS_AVAILABLE = VideoSIPGWStatusConstants.STATUS_AVAILABLE;\r\nexport const STATUS_UNDEFINED = VideoSIPGWStatusConstants.STATUS_UNDEFINED;\r\nexport const STATUS_BUSY = VideoSIPGWStatusConstants.STATUS_BUSY;\r\n\r\nexport const STATE_ON = VideoSIPGWStateConstants.STATE_ON;\r\nexport const STATE_OFF = VideoSIPGWStateConstants.STATE_OFF;\r\nexport const STATE_PENDING = VideoSIPGWStateConstants.STATE_PENDING;\r\nexport const STATE_RETRYING = VideoSIPGWStateConstants.STATE_RETRYING;\r\nexport const STATE_FAILED = VideoSIPGWStateConstants.STATE_FAILED;\r\n\r\nexport const ERROR_NO_CONNECTION = VideoSIPGWErrorConstants.ERROR_NO_CONNECTION;\r\nexport const ERROR_SESSION_EXISTS = VideoSIPGWErrorConstants.ERROR_SESSION_EXISTS;\r\n","import { getLogger } from '@jitsi/logger';\r\nimport { $iq } from 'strophe.js';\r\n\r\nimport Listenable from '../util/Listenable';\r\n\r\nimport * as VideoSIPGWConstants from './VideoSIPGWConstants';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * The event name for current sip video session state changed.\r\n * @type {string} event name for sip video session state changed.\r\n */\r\nconst STATE_CHANGED = 'STATE_CHANGED';\r\n\r\n/**\r\n * Jitsi video SIP GW session. Holding its state and able to start/stop it.\r\n * When session is in OFF or FAILED stated it cannot be used anymore.\r\n */\r\nexport default class JitsiVideoSIPGWSession extends Listenable {\r\n\r\n    /**\r\n     * Creates new session with the desired sip address and display name.\r\n     *\r\n     * @param {string} sipAddress - The sip address to use when\r\n     * starting the session.\r\n     * @param {string} displayName - The display name to use for\r\n     * that participant.\r\n     * @param {ChatRoom} chatRoom - The chat room this session is bound to.\r\n     */\r\n    constructor(sipAddress, displayName, chatRoom) {\r\n        super();\r\n\r\n        this.sipAddress = sipAddress;\r\n        this.displayName = displayName;\r\n        this.chatRoom = chatRoom;\r\n\r\n        /*\r\n         * The initial state is undefined. Initial state cannot be STATE_OFF,\r\n         * the session enters this state when it was in STATE_ON and was stopped\r\n         * and such session cannot be used anymore.\r\n         *\r\n         * @type {VideoSIPGWConstants|undefined}\r\n         */\r\n        this.state = undefined;\r\n    }\r\n\r\n    /**\r\n     * Stops the current session.\r\n     */\r\n    stop() {\r\n        if (this.state === VideoSIPGWConstants.STATE_OFF\r\n            || this.state === VideoSIPGWConstants.STATE_FAILED) {\r\n            logger.warn('Video SIP GW session already stopped or failed!');\r\n\r\n            return;\r\n        }\r\n\r\n        this._sendJibriIQ('stop');\r\n    }\r\n\r\n    /**\r\n     * Starts a new session. Sends an iq to the focus.\r\n     */\r\n    start() {\r\n        // if state is off, this session was active for some reason\r\n        // and we should create new one, rather than reusing it\r\n        if (this.state === VideoSIPGWConstants.STATE_ON\r\n            || this.state === VideoSIPGWConstants.STATE_OFF\r\n            || this.state === VideoSIPGWConstants.STATE_PENDING\r\n            || this.state === VideoSIPGWConstants.STATE_RETRYING) {\r\n            logger.warn('Video SIP GW session already started!');\r\n\r\n            return;\r\n        }\r\n\r\n        this._sendJibriIQ('start');\r\n    }\r\n\r\n    /**\r\n     * Changes the state of this session.\r\n     *\r\n     * @param {string} newState - The new {VideoSIPGWConstants} state to set.\r\n     * @param {string} [optional] failureReason - The reason why a failure state\r\n     * was entered.\r\n     * @returns {void}\r\n     */\r\n    setState(newState, failureReason) {\r\n        if (newState === this.state) {\r\n            return;\r\n        }\r\n\r\n        const oldState = this.state;\r\n\r\n        this.state = newState;\r\n        this.eventEmitter.emit(STATE_CHANGED,\r\n            {\r\n                address: this.sipAddress,\r\n                failureReason,\r\n                oldState,\r\n                newState: this.state,\r\n                displayName: this.displayName\r\n            }\r\n        );\r\n    }\r\n\r\n    /**\r\n     * Subscribes the passed listener to the event for state change of this\r\n     * session.\r\n     *\r\n     * @param {Function} listener - The function that will receive the event.\r\n     */\r\n    addStateListener(listener) {\r\n        this.addListener(STATE_CHANGED, listener);\r\n    }\r\n\r\n    /**\r\n     * Unsubscribes the passed handler.\r\n     *\r\n     * @param {Function} listener - The function to be removed.\r\n     */\r\n    removeStateListener(listener) {\r\n        this.removeListener(STATE_CHANGED, listener);\r\n    }\r\n\r\n    /**\r\n     * Sends a jibri command using an iq.\r\n     *\r\n     * @private\r\n     * @param {string} action - The action to send ('start' or 'stop').\r\n     */\r\n    _sendJibriIQ(action) {\r\n        const attributes = {\r\n            'xmlns': 'http://jitsi.org/protocol/jibri',\r\n            'action': action,\r\n            sipaddress: this.sipAddress\r\n        };\r\n\r\n        attributes.displayname = this.displayName;\r\n\r\n        const iq = $iq({\r\n            to: this.chatRoom.focusMucJid,\r\n            type: 'set' })\r\n            .c('jibri', attributes)\r\n            .up();\r\n\r\n        logger.debug(`${action} video SIP GW session`, iq.nodeTree);\r\n        this.chatRoom.connection.sendIQ(\r\n            iq,\r\n            () => {}, // eslint-disable-line no-empty-function\r\n            error => {\r\n                logger.error(\r\n                    `Failed to ${action} video SIP GW session, error: `, error);\r\n                this.setState(VideoSIPGWConstants.STATE_FAILED);\r\n            });\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nconst logger = getLogger(__filename);\r\n\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\n\r\nimport JitsiVideoSIPGWSession from './JitsiVideoSIPGWSession';\r\nimport * as Constants from './VideoSIPGWConstants';\r\n\r\n/**\r\n * Main video SIP GW handler. Stores references of all created sessions.\r\n */\r\nexport default class VideoSIPGW {\r\n\r\n    /**\r\n     * Creates new handler.\r\n     *\r\n     * @param {ChatRoom} chatRoom - Tha chat room to handle.\r\n     */\r\n    constructor(chatRoom) {\r\n        this.chatRoom = chatRoom;\r\n        this.eventEmitter = chatRoom.eventEmitter;\r\n        logger.debug('creating VideoSIPGW');\r\n        this.sessions = {};\r\n\r\n        this.sessionStateChangeListener = this.sessionStateChanged.bind(this);\r\n\r\n        // VideoSIPGW, JitsiConference and ChatRoom are not reusable and no\r\n        // more than one VideoSIPGW can be created per JitsiConference,\r\n        // so we don't bother to cleanup\r\n        chatRoom.addPresenceListener('jibri-sip-call-state',\r\n            this.handleJibriSIPState.bind(this));\r\n    }\r\n\r\n    /**\r\n     * Handles presence nodes with name: jibri-sip-call-state.\r\n     *\r\n     * @param {Object} node the presence node Object to handle.\r\n     * Object representing part of the presence received over xmpp.\r\n     */\r\n    handleJibriSIPState(node) {\r\n        const attributes = node.attributes;\r\n\r\n        if (!attributes) {\r\n            return;\r\n        }\r\n\r\n        logger.debug('Handle video sip gw state : ', attributes);\r\n\r\n        const newState = attributes.state;\r\n\r\n        if (newState === this.state) {\r\n            return;\r\n        }\r\n\r\n        switch (newState) {\r\n        case Constants.STATE_ON:\r\n        case Constants.STATE_OFF:\r\n        case Constants.STATE_PENDING:\r\n        case Constants.STATE_RETRYING:\r\n        case Constants.STATE_FAILED: {\r\n            const address = attributes.sipaddress;\r\n\r\n            if (!address) {\r\n                return;\r\n            }\r\n\r\n            // find the corresponding session and set its state\r\n            const session = this.sessions[address];\r\n\r\n            if (session) {\r\n                session.setState(newState, attributes.failure_reason);\r\n            } else {\r\n                logger.warn('Video SIP GW session not found:', address);\r\n            }\r\n        }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Creates new session and stores its reference if it does not exist or\r\n     * returns an error otherwise.\r\n     *\r\n     * @param {string} sipAddress - The sip address to use.\r\n     * @param {string} displayName - The display name to use.\r\n     * @returns {JitsiVideoSIPGWSession|Error}\r\n     */\r\n    createVideoSIPGWSession(sipAddress, displayName) {\r\n        if (this.sessions[sipAddress]) {\r\n            logger.warn('There was already a Video SIP GW session for address',\r\n                sipAddress);\r\n\r\n            return new Error(Constants.ERROR_SESSION_EXISTS);\r\n        }\r\n\r\n        const session = new JitsiVideoSIPGWSession(\r\n            sipAddress, displayName, this.chatRoom);\r\n\r\n        session.addStateListener(this.sessionStateChangeListener);\r\n\r\n        this.sessions[sipAddress] = session;\r\n\r\n        return session;\r\n    }\r\n\r\n    /**\r\n     * Listener for session state changed. When a session goes to off or failed\r\n     * we delete its reference.\r\n     *\r\n     * @param {options} event - { address, oldState, newState, displayName }\r\n     */\r\n    sessionStateChanged(event) {\r\n        const address = event.address;\r\n\r\n        if (event.newState === Constants.STATE_OFF\r\n            || event.newState === Constants.STATE_FAILED) {\r\n            const session = this.sessions[address];\r\n\r\n            if (!session) {\r\n                logger.error('Missing Video SIP GW session with address:',\r\n                    address);\r\n\r\n                return;\r\n            }\r\n\r\n            session.removeStateListener(this.sessionStateChangeListener);\r\n            delete this.sessions[address];\r\n        }\r\n\r\n        this.eventEmitter.emit(\r\n            XMPPEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED,\r\n            event);\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport { Strophe } from 'strophe.js';\r\n\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport * as SignalingEvents from '../../service/RTC/SignalingEvents';\r\nimport SignalingLayer, { getMediaTypeFromSourceName } from '../../service/RTC/SignalingLayer';\r\nimport { VideoType } from '../../service/RTC/VideoType';\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\n\r\nimport { filterNodeFromPresenceJSON } from './ChatRoom';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\nexport const SOURCE_INFO_PRESENCE_ELEMENT = 'SourceInfo';\r\n\r\n/**\r\n * Default XMPP implementation of the {@link SignalingLayer} interface. Obtains\r\n * the data from the MUC presence.\r\n */\r\nexport default class SignalingLayerImpl extends SignalingLayer {\r\n    /**\r\n     * Creates new instance.\r\n     */\r\n    constructor() {\r\n        super();\r\n\r\n        /**\r\n         * A map that stores SSRCs of remote streams. And is used only locally\r\n         * We store the mapping when jingle is received, and later is used\r\n         * onaddstream webrtc event where we have only the ssrc\r\n         * FIXME: This map got filled and never cleaned and can grow during long\r\n         * conference\r\n         * @type {Map<number, string>} maps SSRC number to jid\r\n         */\r\n        this.ssrcOwners = new Map();\r\n\r\n        /**\r\n         *\r\n         * @type {ChatRoom|null}\r\n         */\r\n        this.chatRoom = null;\r\n\r\n        /**\r\n         * @type {Map<SourceName, SourceInfo>}\r\n         * @private\r\n         */\r\n        this._localSourceState = { };\r\n\r\n        /**\r\n         * @type {Map<EndpointId, Map<SourceName, SourceInfo>>}\r\n         * @private\r\n         */\r\n        this._remoteSourceState = { };\r\n\r\n        /**\r\n         * A map that stores the source name of a track identified by it's ssrc.\r\n         * We store the mapping when jingle is received, and later is used\r\n         * onaddstream webrtc event where we have only the ssrc\r\n         * FIXME: This map got filled and never cleaned and can grow during long\r\n         * conference\r\n         * @type {Map<number, string>} maps SSRC number to source name\r\n         */\r\n        this._sourceNames = new Map();\r\n    }\r\n\r\n    /**\r\n     * Adds <SourceInfo> element to the local presence.\r\n     *\r\n     * @returns {void}\r\n     * @private\r\n     */\r\n    _addLocalSourceInfoToPresence() {\r\n        if (this.chatRoom) {\r\n            return this.chatRoom.addOrReplaceInPresence(\r\n                SOURCE_INFO_PRESENCE_ELEMENT,\r\n                { value: JSON.stringify(this._localSourceState) });\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * Check is given endpoint has advertised <SourceInfo/> in it's presence which means that the source name signaling\r\n     * is used by this endpoint.\r\n     *\r\n     * @param {EndpointId} endpointId\r\n     * @returns {boolean}\r\n     */\r\n    _doesEndpointSendNewSourceInfo(endpointId) {\r\n        const presence = this.chatRoom?.getLastPresence(endpointId);\r\n\r\n        return Boolean(presence && presence.find(node => node.tagName === SOURCE_INFO_PRESENCE_ELEMENT));\r\n    }\r\n\r\n    /**\r\n     * Sets the <tt>ChatRoom</tt> instance used and binds presence listeners.\r\n     * @param {ChatRoom} room\r\n     */\r\n    setChatRoom(room) {\r\n        const oldChatRoom = this.chatRoom;\r\n\r\n        this.chatRoom = room;\r\n        if (oldChatRoom) {\r\n            oldChatRoom.removePresenceListener(\r\n                'audiomuted', this._audioMuteHandler);\r\n            oldChatRoom.removePresenceListener(\r\n                'videomuted', this._videoMuteHandler);\r\n            oldChatRoom.removePresenceListener(\r\n                'videoType', this._videoTypeHandler);\r\n            this._sourceInfoHandler\r\n                && oldChatRoom.removePresenceListener(SOURCE_INFO_PRESENCE_ELEMENT, this._sourceInfoHandler);\r\n            this._memberLeftHandler\r\n                && oldChatRoom.removeEventListener(XMPPEvents.MUC_MEMBER_LEFT, this._memberLeftHandler);\r\n        }\r\n        if (room) {\r\n            this._bindChatRoomEventHandlers(room);\r\n            this._addLocalSourceInfoToPresence();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Binds event listeners to the chat room instance.\r\n     * @param {ChatRoom} room\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _bindChatRoomEventHandlers(room) {\r\n        // Add handlers for 'audiomuted', 'videomuted' and 'videoType' fields in presence in order to support interop\r\n        // with very old versions of mobile clients and jigasi that do not support source-name signaling.\r\n        const emitAudioMutedEvent = (endpointId, muted) => {\r\n            this.eventEmitter.emit(\r\n                SignalingEvents.PEER_MUTED_CHANGED,\r\n                endpointId,\r\n                MediaType.AUDIO,\r\n                muted);\r\n        };\r\n\r\n        this._audioMuteHandler = (node, from) => {\r\n            if (!this._doesEndpointSendNewSourceInfo(from)) {\r\n                emitAudioMutedEvent(from, node.value === 'true');\r\n            }\r\n        };\r\n        room.addPresenceListener('audiomuted', this._audioMuteHandler);\r\n\r\n        const emitVideoMutedEvent = (endpointId, muted) => {\r\n            this.eventEmitter.emit(\r\n                SignalingEvents.PEER_MUTED_CHANGED,\r\n                endpointId,\r\n                MediaType.VIDEO,\r\n                muted);\r\n        };\r\n\r\n        this._videoMuteHandler = (node, from) => {\r\n            if (!this._doesEndpointSendNewSourceInfo(from)) {\r\n                emitVideoMutedEvent(from, node.value === 'true');\r\n            }\r\n        };\r\n        room.addPresenceListener('videomuted', this._videoMuteHandler);\r\n\r\n        const emitVideoTypeEvent = (endpointId, videoType) => {\r\n            this.eventEmitter.emit(\r\n                SignalingEvents.PEER_VIDEO_TYPE_CHANGED,\r\n                endpointId, videoType);\r\n        };\r\n\r\n        this._videoTypeHandler = (node, from) => {\r\n            if (!this._doesEndpointSendNewSourceInfo(from)) {\r\n                emitVideoTypeEvent(from, node.value);\r\n            }\r\n        };\r\n        room.addPresenceListener('videoType', this._videoTypeHandler);\r\n\r\n        // Add handlers for presence in the new format.\r\n        this._sourceInfoHandler = (node, mucNick) => {\r\n            const endpointId = mucNick;\r\n            const { value } = node;\r\n            const sourceInfoJSON = JSON.parse(value);\r\n            const emitEventsFromHere = this._doesEndpointSendNewSourceInfo(endpointId);\r\n            const endpointSourceState\r\n                = this._remoteSourceState[endpointId] || (this._remoteSourceState[endpointId] = {});\r\n\r\n            for (const sourceName of Object.keys(sourceInfoJSON)) {\r\n                const mediaType = getMediaTypeFromSourceName(sourceName);\r\n                const newMutedState = Boolean(sourceInfoJSON[sourceName].muted);\r\n                const oldSourceState = endpointSourceState[sourceName]\r\n                    || (endpointSourceState[sourceName] = { sourceName });\r\n\r\n                if (oldSourceState.muted !== newMutedState) {\r\n                    oldSourceState.muted = newMutedState;\r\n                    if (emitEventsFromHere && !this._localSourceState[sourceName]) {\r\n                        this.eventEmitter.emit(SignalingEvents.SOURCE_MUTED_CHANGED, sourceName, newMutedState);\r\n                    }\r\n                }\r\n\r\n                // Assume a default videoType of 'camera' for video sources.\r\n                const newVideoType = mediaType === MediaType.VIDEO\r\n                    ? sourceInfoJSON[sourceName].videoType ?? VideoType.CAMERA\r\n                    : undefined;\r\n\r\n                if (oldSourceState.videoType !== newVideoType) {\r\n                    oldSourceState.videoType = newVideoType;\r\n\r\n                    // Since having a mix of eps that do/don't support multi-stream in the same call is supported, emit\r\n                    // SOURCE_VIDEO_TYPE_CHANGED event when the remote source changes videoType.\r\n                    if (emitEventsFromHere && !this._localSourceState[sourceName]) {\r\n                        this.eventEmitter.emit(SignalingEvents.SOURCE_VIDEO_TYPE_CHANGED, sourceName, newVideoType);\r\n                    }\r\n                }\r\n            }\r\n\r\n            // Cleanup removed source names\r\n            const newSourceNames = Object.keys(sourceInfoJSON);\r\n\r\n            for (const sourceName of Object.keys(endpointSourceState)) {\r\n                if (newSourceNames.indexOf(sourceName) === -1) {\r\n                    delete endpointSourceState[sourceName];\r\n                }\r\n            }\r\n        };\r\n        room.addPresenceListener('SourceInfo', this._sourceInfoHandler);\r\n\r\n        // Cleanup when participant leaves\r\n        this._memberLeftHandler = jid => {\r\n            const endpointId = Strophe.getResourceFromJid(jid);\r\n\r\n            delete this._remoteSourceState[endpointId];\r\n\r\n            for (const [ key, value ] of this.ssrcOwners.entries()) {\r\n                if (value === endpointId) {\r\n                    delete this._sourceNames[key];\r\n                }\r\n            }\r\n        };\r\n        room.addEventListener(XMPPEvents.MUC_MEMBER_LEFT, this._memberLeftHandler);\r\n    }\r\n\r\n    /**\r\n     * Finds the first source of given media type for the given endpoint.\r\n     * @param endpointId\r\n     * @param mediaType\r\n     * @returns {SourceInfo|null}\r\n     * @private\r\n     */\r\n    _findEndpointSourceInfoForMediaType(endpointId, mediaType) {\r\n        const remoteSourceState = this._remoteSourceState[endpointId];\r\n\r\n        if (!remoteSourceState) {\r\n            return null;\r\n        }\r\n\r\n        for (const sourceInfo of Object.values(remoteSourceState)) {\r\n            const _mediaType = getMediaTypeFromSourceName(sourceInfo.sourceName);\r\n\r\n            if (_mediaType === mediaType) {\r\n                return sourceInfo;\r\n            }\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    getPeerMediaInfo(owner, mediaType, sourceName) {\r\n        const legacyGetPeerMediaInfo = () => {\r\n            if (this.chatRoom) {\r\n                return this.chatRoom.getMediaPresenceInfo(owner, mediaType);\r\n            }\r\n            logger.warn('Requested peer media info, before room was set');\r\n        };\r\n\r\n        const lastPresence = this.chatRoom?.getLastPresence(owner);\r\n\r\n        if (!lastPresence) {\r\n            logger.warn(`getPeerMediaInfo - no presence stored for: ${owner}`);\r\n\r\n            return;\r\n        }\r\n        if (!this._doesEndpointSendNewSourceInfo(owner)) {\r\n            return legacyGetPeerMediaInfo();\r\n        }\r\n\r\n        if (sourceName) {\r\n            return this.getPeerSourceInfo(owner, sourceName);\r\n        }\r\n\r\n        const mediaInfo = {\r\n            muted: true\r\n        };\r\n\r\n        if (mediaType === MediaType.VIDEO) {\r\n            mediaInfo.videoType = undefined;\r\n            const codecTypeNode = filterNodeFromPresenceJSON(lastPresence, 'jitsi_participant_codecType');\r\n\r\n            if (codecTypeNode.length > 0) {\r\n                mediaInfo.codecType = codecTypeNode[0].value;\r\n            }\r\n        }\r\n\r\n        return mediaInfo;\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    getPeerSourceInfo(owner, sourceName) {\r\n        const mediaInfo = {\r\n            muted: true, // muted by default\r\n            videoType: VideoType.CAMERA // 'camera' by default\r\n        };\r\n\r\n        return this._remoteSourceState[owner]\r\n            ? this._remoteSourceState[owner][sourceName] ?? mediaInfo\r\n            : undefined;\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    getSSRCOwner(ssrc) {\r\n        return this.ssrcOwners.get(ssrc);\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    setSSRCOwner(ssrc, endpointId) {\r\n        if (typeof ssrc !== 'number') {\r\n            throw new TypeError(`SSRC(${ssrc}) must be a number`);\r\n        }\r\n\r\n        // Now signaling layer instance is shared between different JingleSessionPC instances, so although very unlikely\r\n        // an SSRC conflict could potentially occur. Log a message to make debugging easier.\r\n        const existingOwner = this.ssrcOwners.get(ssrc);\r\n\r\n        if (existingOwner && existingOwner !== endpointId) {\r\n            logger.error(`SSRC owner re-assigned from ${existingOwner} to ${endpointId}`);\r\n        }\r\n        this.ssrcOwners.set(ssrc, endpointId);\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    setTrackMuteStatus(sourceName, muted) {\r\n        if (!this._localSourceState[sourceName]) {\r\n            this._localSourceState[sourceName] = {};\r\n        }\r\n\r\n        this._localSourceState[sourceName].muted = muted;\r\n\r\n        if (this.chatRoom) {\r\n            return this._addLocalSourceInfoToPresence();\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    setTrackVideoType(sourceName, videoType) {\r\n        if (!this._localSourceState[sourceName]) {\r\n            this._localSourceState[sourceName] = {};\r\n        }\r\n\r\n        if (this._localSourceState[sourceName].videoType !== videoType) {\r\n            // Include only if not a camera (default)\r\n            this._localSourceState[sourceName].videoType = videoType === VideoType.CAMERA ? undefined : videoType;\r\n\r\n            return this._addLocalSourceInfoToPresence();\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    getTrackSourceName(ssrc) {\r\n        return this._sourceNames.get(ssrc);\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    setTrackSourceName(ssrc, sourceName) {\r\n        if (typeof ssrc !== 'number') {\r\n            throw new TypeError(`SSRC(${ssrc}) must be a number`);\r\n        }\r\n\r\n        // Now signaling layer instance is shared between different JingleSessionPC instances, so although very unlikely\r\n        // an SSRC conflict could potentially occur. Log a message to make debugging easier.\r\n        const existingName = this._sourceNames.get(ssrc);\r\n\r\n        if (existingName && existingName !== sourceName) {\r\n            logger.error(`SSRC(${ssrc}) sourceName re-assigned from ${existingName} to ${sourceName}`);\r\n        }\r\n\r\n        this._sourceNames.set(ssrc, sourceName);\r\n    }\r\n\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport EventEmitter from 'events';\r\nimport $ from 'jquery';\r\nimport isEqual from 'lodash.isequal';\r\nimport { Strophe } from 'strophe.js';\r\n\r\nimport * as JitsiConferenceErrors from './JitsiConferenceErrors';\r\nimport JitsiConferenceEventManager from './JitsiConferenceEventManager';\r\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\r\nimport JitsiParticipant from './JitsiParticipant';\r\nimport JitsiTrackError from './JitsiTrackError';\r\nimport * as JitsiTrackErrors from './JitsiTrackErrors';\r\nimport * as JitsiTrackEvents from './JitsiTrackEvents';\r\nimport authenticateAndUpgradeRole from './authenticateAndUpgradeRole';\r\nimport { CodecSelection } from './modules/RTC/CodecSelection';\r\nimport RTC from './modules/RTC/RTC';\r\nimport { SS_DEFAULT_FRAME_RATE } from './modules/RTC/ScreenObtainer';\r\nimport browser from './modules/browser';\r\nimport ConnectionQuality from './modules/connectivity/ConnectionQuality';\r\nimport IceFailedHandling from './modules/connectivity/IceFailedHandling';\r\nimport * as DetectionEvents from './modules/detection/DetectionEvents';\r\nimport NoAudioSignalDetection from './modules/detection/NoAudioSignalDetection';\r\nimport P2PDominantSpeakerDetection from './modules/detection/P2PDominantSpeakerDetection';\r\nimport VADAudioAnalyser from './modules/detection/VADAudioAnalyser';\r\nimport VADNoiseDetection from './modules/detection/VADNoiseDetection';\r\nimport VADTalkMutedDetection from './modules/detection/VADTalkMutedDetection';\r\nimport { E2EEncryption } from './modules/e2ee/E2EEncryption';\r\nimport E2ePing from './modules/e2eping/e2eping';\r\nimport Jvb121EventGenerator from './modules/event/Jvb121EventGenerator';\r\nimport FeatureFlags from './modules/flags/FeatureFlags';\r\nimport ReceiveVideoController from './modules/qualitycontrol/ReceiveVideoController';\r\nimport SendVideoController from './modules/qualitycontrol/SendVideoController';\r\nimport RecordingManager from './modules/recording/RecordingManager';\r\nimport Settings from './modules/settings/Settings';\r\nimport AudioOutputProblemDetector from './modules/statistics/AudioOutputProblemDetector';\r\nimport AvgRTPStatsReporter from './modules/statistics/AvgRTPStatsReporter';\r\nimport SpeakerStatsCollector from './modules/statistics/SpeakerStatsCollector';\r\nimport Statistics from './modules/statistics/statistics';\r\nimport Transcriber from './modules/transcription/transcriber';\r\nimport GlobalOnErrorHandler from './modules/util/GlobalOnErrorHandler';\r\nimport RandomUtil from './modules/util/RandomUtil';\r\nimport ComponentsVersions from './modules/version/ComponentsVersions';\r\nimport VideoSIPGW from './modules/videosipgw/VideoSIPGW';\r\nimport * as VideoSIPGWConstants from './modules/videosipgw/VideoSIPGWConstants';\r\nimport SignalingLayerImpl from './modules/xmpp/SignalingLayerImpl';\r\nimport {\r\n    FEATURE_E2EE,\r\n    FEATURE_JIGASI,\r\n    JITSI_MEET_MUC_TYPE\r\n} from './modules/xmpp/xmpp';\r\nimport BridgeVideoType from './service/RTC/BridgeVideoType';\r\nimport CodecMimeType from './service/RTC/CodecMimeType';\r\nimport { MediaType } from './service/RTC/MediaType';\r\nimport RTCEvents from './service/RTC/RTCEvents';\r\nimport { getSourceNameForJitsiTrack } from './service/RTC/SignalingLayer';\r\nimport { VideoType } from './service/RTC/VideoType';\r\nimport {\r\n    ACTION_JINGLE_RESTART,\r\n    ACTION_JINGLE_SI_RECEIVED,\r\n    ACTION_JINGLE_SI_TIMEOUT,\r\n    ACTION_JINGLE_TERMINATE,\r\n    ACTION_P2P_DECLINED,\r\n    ACTION_P2P_ESTABLISHED,\r\n    ACTION_P2P_FAILED,\r\n    ACTION_P2P_SWITCH_TO_JVB,\r\n    ICE_ESTABLISHMENT_DURATION_DIFF,\r\n    createConferenceEvent,\r\n    createJingleEvent,\r\n    createP2PEvent\r\n} from './service/statistics/AnalyticsEvents';\r\nimport { XMPPEvents } from './service/xmpp/XMPPEvents';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * How long since Jicofo is supposed to send a session-initiate, before\r\n * {@link ACTION_JINGLE_SI_TIMEOUT} analytics event is sent (in ms).\r\n * @type {number}\r\n */\r\nconst JINGLE_SI_TIMEOUT = 5000;\r\n\r\n/**\r\n * Creates a JitsiConference object with the given name and properties.\r\n * Note: this constructor is not a part of the public API (objects should be\r\n * created using JitsiConnection.createConference).\r\n * @param options.config properties / settings related to the conference that\r\n * will be created.\r\n * @param options.name the name of the conference\r\n * @param options.connection the JitsiConnection object for this\r\n * JitsiConference.\r\n * @param {number} [options.config.avgRtpStatsN=15] how many samples are to be\r\n * collected by {@link AvgRTPStatsReporter}, before arithmetic mean is\r\n * calculated and submitted to the analytics module.\r\n * @param {boolean} [options.config.enableIceRestart=false] - enables the ICE\r\n * restart logic.\r\n * @param {boolean} [options.config.p2p.enabled] when set to <tt>true</tt>\r\n * the peer to peer mode will be enabled. It means that when there are only 2\r\n * participants in the conference an attempt to make direct connection will be\r\n * made. If the connection succeeds the conference will stop sending data\r\n * through the JVB connection and will use the direct one instead.\r\n * @param {number} [options.config.p2p.backToP2PDelay=5] a delay given in\r\n * seconds, before the conference switches back to P2P, after the 3rd\r\n * participant has left the room.\r\n * @param {number} [options.config.channelLastN=-1] The requested amount of\r\n * videos are going to be delivered after the value is in effect. Set to -1 for\r\n * unlimited or all available videos.\r\n * @param {number} [options.config.forceJVB121Ratio]\r\n * \"Math.random() < forceJVB121Ratio\" will determine whether a 2 people\r\n * conference should be moved to the JVB instead of P2P. The decision is made on\r\n * the responder side, after ICE succeeds on the P2P connection.\r\n * @constructor\r\n *\r\n * FIXME Make all methods which are called from lib-internal classes\r\n *       to non-public (use _). To name a few:\r\n *       {@link JitsiConference.onLocalRoleChanged}\r\n *       {@link JitsiConference.onUserRoleChanged}\r\n *       {@link JitsiConference.onMemberLeft}\r\n *       and so on...\r\n */\r\nexport default function JitsiConference(options) {\r\n    if (!options.name || options.name.toLowerCase() !== options.name.toString()) {\r\n        const errmsg\r\n            = 'Invalid conference name (no conference name passed or it '\r\n                + 'contains invalid characters like capital letters)!';\r\n\r\n        logger.error(errmsg);\r\n        throw new Error(errmsg);\r\n    }\r\n    this.connection = options.connection;\r\n    this.xmpp = this.connection?.xmpp;\r\n\r\n    if (this.xmpp.isRoomCreated(options.name, options.customDomain)) {\r\n        const errmsg = 'A conference with the same name has already been created!';\r\n\r\n        delete this.connection;\r\n        delete this.xmpp;\r\n        logger.error(errmsg);\r\n        throw new Error(errmsg);\r\n    }\r\n    this.eventEmitter = new EventEmitter();\r\n    this.options = options;\r\n    this.eventManager = new JitsiConferenceEventManager(this);\r\n    this.participants = {};\r\n\r\n    /**\r\n     * The signaling layer instance.\r\n     * @type {SignalingLayerImpl}\r\n     * @private\r\n     */\r\n    this._signalingLayer = new SignalingLayerImpl();\r\n\r\n    this._init(options);\r\n    this.componentsVersions = new ComponentsVersions(this);\r\n\r\n    /**\r\n     * Jingle session instance for the JVB connection.\r\n     * @type {JingleSessionPC}\r\n     */\r\n    this.jvbJingleSession = null;\r\n    this.lastDominantSpeaker = null;\r\n    this.dtmfManager = null;\r\n    this.somebodySupportsDTMF = false;\r\n    this.authEnabled = false;\r\n    this.startAudioMuted = false;\r\n    this.startVideoMuted = false;\r\n    this.startMutedPolicy = {\r\n        audio: false,\r\n        video: false\r\n    };\r\n    this.isMutedByFocus = false;\r\n\r\n    // when muted by focus we receive the jid of the initiator of the mute\r\n    this.mutedByFocusActor = null;\r\n\r\n    this.isVideoMutedByFocus = false;\r\n\r\n    // when video muted by focus we receive the jid of the initiator of the mute\r\n    this.mutedVideoByFocusActor = null;\r\n\r\n    // Flag indicates if the 'onCallEnded' method was ever called on this\r\n    // instance. Used to log extra analytics event for debugging purpose.\r\n    // We need to know if the potential issue happened before or after\r\n    // the restart.\r\n    this.wasStopped = false;\r\n\r\n    // Conference properties, maintained by jicofo.\r\n    this.properties = {};\r\n\r\n    /**\r\n     * The object which monitors local and remote connection statistics (e.g.\r\n     * sending bitrate) and calculates a number which represents the connection\r\n     * quality.\r\n     */\r\n    this.connectionQuality\r\n        = new ConnectionQuality(this, this.eventEmitter, options);\r\n\r\n    /**\r\n     * Reports average RTP statistics to the analytics module.\r\n     * @type {AvgRTPStatsReporter}\r\n     */\r\n    this.avgRtpStatsReporter\r\n        = new AvgRTPStatsReporter(this, options.config.avgRtpStatsN || 15);\r\n\r\n    /**\r\n     * Detects issues with the audio of remote participants.\r\n     * @type {AudioOutputProblemDetector}\r\n     */\r\n    if (!options.config.disableAudioLevels) {\r\n        this._audioOutputProblemDetector = new AudioOutputProblemDetector(this);\r\n    }\r\n\r\n    /**\r\n     * Indicates whether the connection is interrupted or not.\r\n     */\r\n    this.isJvbConnectionInterrupted = false;\r\n\r\n    /**\r\n     * The object which tracks active speaker times\r\n     */\r\n    this.speakerStatsCollector = new SpeakerStatsCollector(this);\r\n\r\n    /* P2P related fields below: */\r\n\r\n    /**\r\n     * Stores reference to deferred start P2P task. It's created when 3rd\r\n     * participant leaves the room in order to avoid ping pong effect (it\r\n     * could be just a page reload).\r\n     * @type {number|null}\r\n     */\r\n    this.deferredStartP2PTask = null;\r\n\r\n    const delay\r\n        = parseInt(options.config.p2p && options.config.p2p.backToP2PDelay, 10);\r\n\r\n    /**\r\n     * A delay given in seconds, before the conference switches back to P2P\r\n     * after the 3rd participant has left.\r\n     * @type {number}\r\n     */\r\n    this.backToP2PDelay = isNaN(delay) ? 5 : delay;\r\n    logger.info(`backToP2PDelay: ${this.backToP2PDelay}`);\r\n\r\n    /**\r\n     * If set to <tt>true</tt> it means the P2P ICE is no longer connected.\r\n     * When <tt>false</tt> it means that P2P ICE (media) connection is up\r\n     * and running.\r\n     * @type {boolean}\r\n     */\r\n    this.isP2PConnectionInterrupted = false;\r\n\r\n    /**\r\n     * Flag set to <tt>true</tt> when P2P session has been established\r\n     * (ICE has been connected) and this conference is currently in the peer to\r\n     * peer mode (P2P connection is the active one).\r\n     * @type {boolean}\r\n     */\r\n    this.p2p = false;\r\n\r\n    /**\r\n     * A JingleSession for the direct peer to peer connection.\r\n     * @type {JingleSessionPC}\r\n     */\r\n    this.p2pJingleSession = null;\r\n\r\n    this.videoSIPGWHandler = new VideoSIPGW(this.room);\r\n    this.recordingManager = new RecordingManager(this.room);\r\n\r\n    /**\r\n     * If the conference.joined event has been sent this will store the timestamp when it happened.\r\n     *\r\n     * @type {undefined|number}\r\n     * @private\r\n     */\r\n    this._conferenceJoinAnalyticsEventSent = undefined;\r\n\r\n    /**\r\n     * End-to-End Encryption. Make it available if supported.\r\n     */\r\n    if (this.isE2EESupported()) {\r\n        logger.info('End-to-End Encryption is supported');\r\n\r\n        this._e2eEncryption = new E2EEncryption(this);\r\n    }\r\n\r\n    /**\r\n     * Flag set to <tt>true</tt> when Jicofo sends a presence message indicating that the max audio sender limit has\r\n     * been reached for the call. Once this is set, unmuting audio will be disabled from the client until it gets reset\r\n     * again by Jicofo.\r\n     */\r\n    this._audioSenderLimitReached = undefined;\r\n\r\n    /**\r\n     * Flag set to <tt>true</tt> when Jicofo sends a presence message indicating that the max video sender limit has\r\n     * been reached for the call. Once this is set, unmuting video will be disabled from the client until it gets reset\r\n     * again by Jicofo.\r\n     */\r\n    this._videoSenderLimitReached = undefined;\r\n}\r\n\r\n// FIXME convert JitsiConference to ES6 - ASAP !\r\nJitsiConference.prototype.constructor = JitsiConference;\r\n\r\n/**\r\n * Create a resource for the a jid. We use the room nickname (the resource part\r\n * of the occupant JID, see XEP-0045) as the endpoint ID in colibri. We require\r\n * endpoint IDs to be 8 hex digits because in some cases they get serialized\r\n * into a 32bit field.\r\n *\r\n * @param {string} jid - The id set onto the XMPP connection.\r\n * @param {boolean} isAuthenticatedUser - Whether or not the user has connected\r\n * to the XMPP service with a password.\r\n * @returns {string}\r\n * @static\r\n */\r\nJitsiConference.resourceCreator = function(jid, isAuthenticatedUser) {\r\n    let mucNickname;\r\n\r\n    if (isAuthenticatedUser) {\r\n        // For authenticated users generate a random ID.\r\n        mucNickname = RandomUtil.randomHexString(8).toLowerCase();\r\n    } else {\r\n        // We try to use the first part of the node (which for anonymous users\r\n        // on prosody is a UUID) to match the previous behavior (and maybe make\r\n        // debugging easier).\r\n        mucNickname = Strophe.getNodeFromJid(jid)?.substr(0, 8)\r\n            .toLowerCase();\r\n\r\n        // But if this doesn't have the required format we just generate a new\r\n        // random nickname.\r\n        const re = /[0-9a-f]{8}/g;\r\n\r\n        if (!mucNickname || !re.test(mucNickname)) {\r\n            mucNickname = RandomUtil.randomHexString(8).toLowerCase();\r\n        }\r\n    }\r\n\r\n    return mucNickname;\r\n};\r\n\r\n/**\r\n * Initializes the conference object properties\r\n * @param options {object}\r\n * @param options.connection {JitsiConnection} overrides this.connection\r\n */\r\nJitsiConference.prototype._init = function(options = {}) {\r\n    this.eventManager.setupXMPPListeners();\r\n\r\n    const { config } = this.options;\r\n\r\n    // Get the codec preference settings from config.js.\r\n    // 'preferH264' and 'disableH264' settings have been deprecated for a while,\r\n    // 'preferredCodec' and 'disabledCodec' will have precedence over them.\r\n    const codecSettings = {\r\n        disabledCodec: config.videoQuality\r\n            ? config.videoQuality.disabledCodec\r\n            : config.p2p && config.p2p.disableH264 && CodecMimeType.H264,\r\n        enforcePreferredCodec: config.videoQuality && config.videoQuality.enforcePreferredCodec,\r\n        jvbCodec: (config.videoQuality && config.videoQuality.preferredCodec)\r\n            || (config.preferH264 && CodecMimeType.H264),\r\n        p2pCodec: config.p2p\r\n            ? config.p2p.preferredCodec || (config.p2p.preferH264 && CodecMimeType.H264)\r\n            : CodecMimeType.VP8\r\n    };\r\n\r\n    this.codecSelection = new CodecSelection(this, codecSettings);\r\n    this._statsCurrentId = config.statisticsId ? config.statisticsId : Settings.callStatsUserName;\r\n    this.room = this.xmpp.createRoom(\r\n        this.options.name, {\r\n            ...config,\r\n            statsId: this._statsCurrentId\r\n        },\r\n        JitsiConference.resourceCreator\r\n    );\r\n\r\n    this._signalingLayer.setChatRoom(this.room);\r\n\r\n    // Connection interrupted/restored listeners\r\n    this._onIceConnectionInterrupted\r\n        = this._onIceConnectionInterrupted.bind(this);\r\n    this.room.addListener(\r\n        XMPPEvents.CONNECTION_INTERRUPTED, this._onIceConnectionInterrupted);\r\n\r\n    this._onIceConnectionRestored = this._onIceConnectionRestored.bind(this);\r\n    this.room.addListener(\r\n        XMPPEvents.CONNECTION_RESTORED, this._onIceConnectionRestored);\r\n\r\n    this._onIceConnectionEstablished\r\n        = this._onIceConnectionEstablished.bind(this);\r\n    this.room.addListener(\r\n        XMPPEvents.CONNECTION_ESTABLISHED, this._onIceConnectionEstablished);\r\n\r\n    this._updateProperties = this._updateProperties.bind(this);\r\n    this.room.addListener(XMPPEvents.CONFERENCE_PROPERTIES_CHANGED,\r\n        this._updateProperties);\r\n\r\n    this._sendConferenceJoinAnalyticsEvent = this._sendConferenceJoinAnalyticsEvent.bind(this);\r\n    this.room.addListener(XMPPEvents.MEETING_ID_SET, this._sendConferenceJoinAnalyticsEvent);\r\n\r\n    this._removeLocalSourceOnReject = this._removeLocalSourceOnReject.bind(this);\r\n    this._updateRoomPresence = this._updateRoomPresence.bind(this);\r\n    this.room.addListener(XMPPEvents.SESSION_ACCEPT, this._updateRoomPresence);\r\n    this.room.addListener(XMPPEvents.SOURCE_ADD, this._updateRoomPresence);\r\n    this.room.addListener(XMPPEvents.SOURCE_ADD_ERROR, this._removeLocalSourceOnReject);\r\n    this.room.addListener(XMPPEvents.SOURCE_REMOVE, this._updateRoomPresence);\r\n\r\n    if (config.e2eping?.enabled) {\r\n        this.e2eping = new E2ePing(\r\n            this,\r\n            config,\r\n            (message, to) => {\r\n                try {\r\n                    this.sendMessage(message, to, true /* sendThroughVideobridge */);\r\n                } catch (error) {\r\n                    logger.warn('Failed to send E2E ping request or response.', error && error.msg);\r\n                }\r\n            });\r\n    }\r\n\r\n    if (!this.rtc) {\r\n        this.rtc = new RTC(this, options);\r\n        this.eventManager.setupRTCListeners();\r\n        this._registerRtcListeners(this.rtc);\r\n    }\r\n\r\n    this.receiveVideoController = new ReceiveVideoController(this, this.rtc);\r\n    this.sendVideoController = new SendVideoController(this, this.rtc);\r\n\r\n    // Add the ability to enable callStats only on a percentage of users based on config.js settings.\r\n    let enableCallStats = true;\r\n\r\n    if (config.testing && config.testing.callStatsThreshold) {\r\n        enableCallStats = (Math.random() * 100) <= config.testing.callStatsThreshold;\r\n    }\r\n\r\n    if (!this.statistics) {\r\n        this.statistics = new Statistics(this.xmpp, {\r\n            aliasName: this._statsCurrentId,\r\n            userName: config.statisticsDisplayName ? config.statisticsDisplayName : this.myUserId(),\r\n            confID: config.confID || `${this.connection.options.hosts.domain}/${this.options.name}`,\r\n            siteID: config.siteID,\r\n            customScriptUrl: config.callStatsCustomScriptUrl,\r\n            callStatsID: config.callStatsID,\r\n            callStatsSecret: config.callStatsSecret,\r\n            callStatsApplicationLogsDisabled: config.callStatsApplicationLogsDisabled,\r\n            enableCallStats,\r\n            roomName: this.options.name,\r\n            applicationName: config.applicationName,\r\n            getWiFiStatsMethod: config.getWiFiStatsMethod,\r\n            configParams: config.callStatsConfigParams\r\n        });\r\n        Statistics.analytics.addPermanentProperties({\r\n            'callstats_name': this._statsCurrentId\r\n        });\r\n\r\n        // Start performance observer for monitoring long tasks\r\n        if (config.longTasksStatsInterval) {\r\n            this.statistics.attachLongTasksStats(this);\r\n        }\r\n    }\r\n\r\n    this.eventManager.setupChatRoomListeners();\r\n\r\n    // Always add listeners because on reload we are executing leave and the\r\n    // listeners are removed from statistics module.\r\n    this.eventManager.setupStatisticsListeners();\r\n\r\n    // Disable VAD processing on Safari since it causes audio input to\r\n    // fail on some of the mobile devices.\r\n    if (config.enableTalkWhileMuted && browser.supportsVADDetection()) {\r\n        // If VAD processor factory method is provided uses VAD based detection, otherwise fallback to audio level\r\n        // based detection.\r\n        if (config.createVADProcessor) {\r\n            logger.info('Using VAD detection for generating talk while muted events');\r\n\r\n            if (!this._audioAnalyser) {\r\n                this._audioAnalyser = new VADAudioAnalyser(this, config.createVADProcessor);\r\n            }\r\n\r\n            const vadTalkMutedDetection = new VADTalkMutedDetection();\r\n\r\n            vadTalkMutedDetection.on(DetectionEvents.VAD_TALK_WHILE_MUTED, () =>\r\n                this.eventEmitter.emit(JitsiConferenceEvents.TALK_WHILE_MUTED));\r\n\r\n            this._audioAnalyser.addVADDetectionService(vadTalkMutedDetection);\r\n        } else {\r\n            logger.warn('No VAD Processor was provided. Talk while muted detection service was not initialized!');\r\n        }\r\n    }\r\n\r\n    // Disable noisy mic detection on safari since it causes the audio input to\r\n    // fail on Safari on iPadOS.\r\n    if (config.enableNoisyMicDetection && browser.supportsVADDetection()) {\r\n        if (config.createVADProcessor) {\r\n            if (!this._audioAnalyser) {\r\n                this._audioAnalyser = new VADAudioAnalyser(this, config.createVADProcessor);\r\n            }\r\n\r\n            const vadNoiseDetection = new VADNoiseDetection();\r\n\r\n            vadNoiseDetection.on(DetectionEvents.VAD_NOISY_DEVICE, () =>\r\n                this.eventEmitter.emit(JitsiConferenceEvents.NOISY_MIC));\r\n\r\n            this._audioAnalyser.addVADDetectionService(vadNoiseDetection);\r\n        } else {\r\n            logger.warn('No VAD Processor was provided. Noisy microphone detection service was not initialized!');\r\n        }\r\n    }\r\n\r\n    // Generates events based on no audio input detector.\r\n    if (config.enableNoAudioDetection) {\r\n        this._noAudioSignalDetection = new NoAudioSignalDetection(this);\r\n        this._noAudioSignalDetection.on(DetectionEvents.NO_AUDIO_INPUT, () => {\r\n            this.eventEmitter.emit(JitsiConferenceEvents.NO_AUDIO_INPUT);\r\n        });\r\n        this._noAudioSignalDetection.on(DetectionEvents.AUDIO_INPUT_STATE_CHANGE, hasAudioSignal => {\r\n            this.eventEmitter.emit(JitsiConferenceEvents.AUDIO_INPUT_STATE_CHANGE, hasAudioSignal);\r\n        });\r\n    }\r\n\r\n\r\n    if ('channelLastN' in config) {\r\n        this.setLastN(config.channelLastN);\r\n    }\r\n\r\n    /**\r\n     * Emits {@link JitsiConferenceEvents.JVB121_STATUS}.\r\n     * @type {Jvb121EventGenerator}\r\n     */\r\n    this.jvb121Status = new Jvb121EventGenerator(this);\r\n\r\n    // creates dominant speaker detection that works only in p2p mode\r\n    this.p2pDominantSpeakerDetection = new P2PDominantSpeakerDetection(this);\r\n\r\n    if (config && config.deploymentInfo && config.deploymentInfo.userRegion) {\r\n        this.setLocalParticipantProperty(\r\n            'region', config.deploymentInfo.userRegion);\r\n    }\r\n\r\n    // Publish the codec type to presence.\r\n    this.setLocalParticipantProperty('codecType', this.codecSelection.getPreferredCodec());\r\n\r\n    // Set transcription language presence extension.\r\n    // In case the language config is undefined or has the default value that the transcriber uses\r\n    // (in our case Jigasi uses 'en-US'), don't set the participant property in order to avoid\r\n    // needlessly polluting the presence stanza.\r\n    if (config && config.transcriptionLanguage && config.transcriptionLanguage !== 'en-US') {\r\n        this.setLocalParticipantProperty('transcription_language', config.transcriptionLanguage);\r\n    }\r\n};\r\n\r\n/**\r\n * Joins the conference.\r\n * @param password {string} the password\r\n * @param replaceParticipant {boolean} whether the current join replaces\r\n * an existing participant with same jwt from the meeting.\r\n */\r\nJitsiConference.prototype.join = function(password, replaceParticipant = false) {\r\n    if (this.room) {\r\n        this.room.join(password, replaceParticipant).then(() => this._maybeSetSITimeout());\r\n    }\r\n};\r\n\r\n/**\r\n * Authenticates and upgrades the role of the local participant/user.\r\n *\r\n * @returns {Object} A <tt>thenable</tt> which (1) settles when the process of\r\n * authenticating and upgrading the role of the local participant/user finishes\r\n * and (2) has a <tt>cancel</tt> method that allows the caller to interrupt the\r\n * process.\r\n */\r\nJitsiConference.prototype.authenticateAndUpgradeRole = function(options) {\r\n    return authenticateAndUpgradeRole.call(this, {\r\n        ...options,\r\n        onCreateResource: JitsiConference.resourceCreator\r\n    });\r\n};\r\n\r\n/**\r\n * Check if joined to the conference.\r\n */\r\nJitsiConference.prototype.isJoined = function() {\r\n    return this.room && this.room.joined;\r\n};\r\n\r\n/**\r\n * Tells whether or not the P2P mode is enabled in the configuration.\r\n * @return {boolean}\r\n */\r\nJitsiConference.prototype.isP2PEnabled = function() {\r\n    return Boolean(this.options.config.p2p && this.options.config.p2p.enabled)\r\n\r\n        // FIXME: remove once we have a default config template. -saghul\r\n        || typeof this.options.config.p2p === 'undefined';\r\n};\r\n\r\n/**\r\n * When in P2P test mode, the conference will not automatically switch to P2P\r\n * when there 2 participants.\r\n * @return {boolean}\r\n */\r\nJitsiConference.prototype.isP2PTestModeEnabled = function() {\r\n    return Boolean(this.options.config.testing\r\n        && this.options.config.testing.p2pTestMode);\r\n};\r\n\r\n/**\r\n * Leaves the conference.\r\n * @param reason {string|undefined} The reason for leaving the conference.\r\n * @returns {Promise}\r\n */\r\nJitsiConference.prototype.leave = async function(reason) {\r\n    if (this.avgRtpStatsReporter) {\r\n        this.avgRtpStatsReporter.dispose();\r\n        this.avgRtpStatsReporter = null;\r\n    }\r\n\r\n    if (this._audioOutputProblemDetector) {\r\n        this._audioOutputProblemDetector.dispose();\r\n        this._audioOutputProblemDetector = null;\r\n    }\r\n\r\n    if (this.e2eping) {\r\n        this.e2eping.stop();\r\n        this.e2eping = null;\r\n    }\r\n\r\n    this.getLocalTracks().forEach(track => this.onLocalTrackRemoved(track));\r\n\r\n    this.rtc.closeBridgeChannel();\r\n\r\n    this._sendConferenceLeftAnalyticsEvent();\r\n\r\n    if (this.statistics) {\r\n        this.statistics.dispose();\r\n    }\r\n\r\n    this._delayedIceFailed && this._delayedIceFailed.cancel();\r\n\r\n    this._maybeClearSITimeout();\r\n\r\n    // Close both JVb and P2P JingleSessions\r\n    if (this.jvbJingleSession) {\r\n        this.jvbJingleSession.close();\r\n        this.jvbJingleSession = null;\r\n    }\r\n    if (this.p2pJingleSession) {\r\n        this.p2pJingleSession.close();\r\n        this.p2pJingleSession = null;\r\n    }\r\n\r\n    // Leave the conference. If this.room == null we are calling second time leave().\r\n    if (!this.room) {\r\n        throw new Error('You have already left the conference');\r\n    }\r\n\r\n    const room = this.room;\r\n\r\n    // Unregister connection state listeners\r\n    room.removeListener(\r\n        XMPPEvents.CONNECTION_INTERRUPTED,\r\n        this._onIceConnectionInterrupted);\r\n    room.removeListener(\r\n        XMPPEvents.CONNECTION_RESTORED,\r\n        this._onIceConnectionRestored);\r\n    room.removeListener(\r\n        XMPPEvents.CONNECTION_ESTABLISHED,\r\n        this._onIceConnectionEstablished);\r\n\r\n    room.removeListener(\r\n        XMPPEvents.CONFERENCE_PROPERTIES_CHANGED,\r\n        this._updateProperties);\r\n\r\n    room.removeListener(XMPPEvents.MEETING_ID_SET, this._sendConferenceJoinAnalyticsEvent);\r\n    room.removeListener(XMPPEvents.SESSION_ACCEPT, this._updateRoomPresence);\r\n    room.removeListener(XMPPEvents.SOURCE_ADD, this._updateRoomPresence);\r\n    room.removeListener(XMPPEvents.SOURCE_ADD_ERROR, this._removeLocalSourceOnReject);\r\n    room.removeListener(XMPPEvents.SOURCE_REMOVE, this._updateRoomPresence);\r\n\r\n    this.eventManager.removeXMPPListeners();\r\n\r\n    this._signalingLayer.setChatRoom(null);\r\n\r\n    this.room = null;\r\n\r\n    let leaveError;\r\n\r\n    try {\r\n        await room.leave(reason);\r\n    } catch (err) {\r\n        leaveError = err;\r\n\r\n        // Remove all participants because currently the conference\r\n        // won't be usable anyway. This is done on success automatically\r\n        // by the ChatRoom instance.\r\n        this.getParticipants().forEach(\r\n            participant => this.onMemberLeft(participant.getJid()));\r\n    }\r\n\r\n    if (this.rtc) {\r\n        this.rtc.destroy();\r\n    }\r\n\r\n    if (leaveError) {\r\n        throw leaveError;\r\n    }\r\n};\r\n\r\n/**\r\n * Returns <tt>true</tt> if end conference support is enabled in the backend.\r\n *\r\n * @returns {boolean} whether end conference is supported in the backend.\r\n */\r\nJitsiConference.prototype.isEndConferenceSupported = function() {\r\n    return Boolean(this.room && this.room.xmpp.endConferenceComponentAddress);\r\n};\r\n\r\n/**\r\n * Ends the conference.\r\n */\r\nJitsiConference.prototype.end = function() {\r\n    if (!this.isEndConferenceSupported()) {\r\n        logger.warn('Cannot end conference: is not supported.');\r\n\r\n        return;\r\n    }\r\n    if (!this.room) {\r\n        throw new Error('You have already left the conference');\r\n    }\r\n\r\n    this.room.end();\r\n};\r\n\r\n/**\r\n * Returns the currently active media session if any.\r\n *\r\n * @returns {JingleSessionPC|undefined}\r\n */\r\nJitsiConference.prototype.getActiveMediaSession = function() {\r\n    return this.isP2PActive() ? this.p2pJingleSession : this.jvbJingleSession;\r\n};\r\n\r\n/**\r\n * Returns an array containing all media sessions existing in this conference.\r\n *\r\n * @returns {Array<JingleSessionPC>}\r\n */\r\nJitsiConference.prototype.getMediaSessions = function() {\r\n    const sessions = [];\r\n\r\n    this.jvbJingleSession && sessions.push(this.jvbJingleSession);\r\n    this.p2pJingleSession && sessions.push(this.p2pJingleSession);\r\n\r\n    return sessions;\r\n};\r\n\r\n/**\r\n * Registers event listeners on the RTC instance.\r\n * @param {RTC} rtc - the RTC module instance used by this conference.\r\n * @private\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype._registerRtcListeners = function(rtc) {\r\n    rtc.addListener(RTCEvents.DATA_CHANNEL_OPEN, () => {\r\n        for (const localTrack of this.rtc.localTracks) {\r\n            localTrack.isVideoTrack() && this._sendBridgeVideoTypeMessage(localTrack);\r\n        }\r\n    });\r\n};\r\n\r\n/**\r\n * Sends the 'VideoTypeMessage' to the bridge on the bridge channel so that the bridge can make bitrate allocation\r\n * decisions based on the video type of the local source.\r\n *\r\n * @param {JitsiLocalTrack} localtrack - The track associated with the local source signaled to the bridge.\r\n * @returns {void}\r\n * @private\r\n */\r\nJitsiConference.prototype._sendBridgeVideoTypeMessage = function(localtrack) {\r\n    let videoType = !localtrack || localtrack.isMuted() ? BridgeVideoType.NONE : localtrack.getVideoType();\r\n\r\n    if (videoType === BridgeVideoType.DESKTOP && this._desktopSharingFrameRate > SS_DEFAULT_FRAME_RATE) {\r\n        videoType = BridgeVideoType.DESKTOP_HIGH_FPS;\r\n    }\r\n\r\n    localtrack && this.rtc.sendSourceVideoType(localtrack.getSourceName(), videoType);\r\n};\r\n\r\n/**\r\n * Returns name of this conference.\r\n */\r\nJitsiConference.prototype.getName = function() {\r\n    return this.options.name.toString();\r\n};\r\n\r\n/**\r\n * Returns the {@link JitsiConnection} used by this this conference.\r\n */\r\nJitsiConference.prototype.getConnection = function() {\r\n    return this.connection;\r\n};\r\n\r\n/**\r\n * Check if authentication is enabled for this conference.\r\n */\r\nJitsiConference.prototype.isAuthEnabled = function() {\r\n    return this.authEnabled;\r\n};\r\n\r\n/**\r\n * Check if user is logged in.\r\n */\r\nJitsiConference.prototype.isLoggedIn = function() {\r\n    return Boolean(this.authIdentity);\r\n};\r\n\r\n/**\r\n * Get authorized login.\r\n */\r\nJitsiConference.prototype.getAuthLogin = function() {\r\n    return this.authIdentity;\r\n};\r\n\r\n/**\r\n * Check if external authentication is enabled for this conference.\r\n */\r\nJitsiConference.prototype.isExternalAuthEnabled = function() {\r\n    return this.room && this.room.moderator.isExternalAuthEnabled();\r\n};\r\n\r\n/**\r\n * Get url for external authentication.\r\n * @param {boolean} [urlForPopup] if true then return url for login popup,\r\n *                                else url of login page.\r\n * @returns {Promise}\r\n */\r\nJitsiConference.prototype.getExternalAuthUrl = function(urlForPopup) {\r\n    return new Promise((resolve, reject) => {\r\n        if (!this.isExternalAuthEnabled()) {\r\n            reject();\r\n\r\n            return;\r\n        }\r\n        if (urlForPopup) {\r\n            this.room.moderator.getPopupLoginUrl(resolve, reject);\r\n        } else {\r\n            this.room.moderator.getLoginUrl(resolve, reject);\r\n        }\r\n    });\r\n};\r\n\r\n/**\r\n * Returns the local tracks of the given media type, or all local tracks if no\r\n * specific type is given.\r\n * @param {MediaType} [mediaType] Optional media type (audio or video).\r\n */\r\nJitsiConference.prototype.getLocalTracks = function(mediaType) {\r\n    let tracks = [];\r\n\r\n    if (this.rtc) {\r\n        tracks = this.rtc.getLocalTracks(mediaType);\r\n    }\r\n\r\n    return tracks;\r\n};\r\n\r\n/**\r\n * Obtains local audio track.\r\n * @return {JitsiLocalTrack|null}\r\n */\r\nJitsiConference.prototype.getLocalAudioTrack = function() {\r\n    return this.rtc ? this.rtc.getLocalAudioTrack() : null;\r\n};\r\n\r\n/**\r\n * Obtains local video track.\r\n * @return {JitsiLocalTrack|null}\r\n */\r\nJitsiConference.prototype.getLocalVideoTrack = function() {\r\n    return this.rtc ? this.rtc.getLocalVideoTrack() : null;\r\n};\r\n\r\n/**\r\n * Returns all the local video tracks.\r\n * @returns {Array<JitsiLocalTrack>}\r\n */\r\nJitsiConference.prototype.getLocalVideoTracks = function() {\r\n    return this.rtc ? this.rtc.getLocalVideoTracks() : null;\r\n};\r\n\r\n/**\r\n * Obtains the performance statistics.\r\n * @returns {Object|null}\r\n */\r\nJitsiConference.prototype.getPerformanceStats = function() {\r\n    return {\r\n        longTasksStats: this.statistics.getLongTasksStats()\r\n    };\r\n};\r\n\r\n/**\r\n * Attaches a handler for events(For example - \"participant joined\".) in the\r\n * conference. All possible event are defined in JitsiConferenceEvents.\r\n * @param eventId the event ID.\r\n * @param handler handler for the event.\r\n *\r\n * Note: consider adding eventing functionality by extending an EventEmitter\r\n * impl, instead of rolling ourselves\r\n */\r\nJitsiConference.prototype.on = function(eventId, handler) {\r\n    if (this.eventEmitter) {\r\n        this.eventEmitter.on(eventId, handler);\r\n    }\r\n};\r\n\r\n/**\r\n * Removes event listener\r\n * @param eventId the event ID.\r\n * @param [handler] optional, the specific handler to unbind\r\n *\r\n * Note: consider adding eventing functionality by extending an EventEmitter\r\n * impl, instead of rolling ourselves\r\n */\r\nJitsiConference.prototype.off = function(eventId, handler) {\r\n    if (this.eventEmitter) {\r\n        this.eventEmitter.removeListener(eventId, handler);\r\n    }\r\n};\r\n\r\n// Common aliases for event emitter\r\nJitsiConference.prototype.addEventListener = JitsiConference.prototype.on;\r\nJitsiConference.prototype.removeEventListener = JitsiConference.prototype.off;\r\n\r\n/**\r\n * Receives notifications from other participants about commands / custom events\r\n * (sent by sendCommand or sendCommandOnce methods).\r\n * @param command {String} the name of the command\r\n * @param handler {Function} handler for the command\r\n */\r\nJitsiConference.prototype.addCommandListener = function(command, handler) {\r\n    if (this.room) {\r\n        this.room.addPresenceListener(command, handler);\r\n    }\r\n};\r\n\r\n/**\r\n  * Removes command  listener\r\n  * @param command {String} the name of the command\r\n  * @param handler {Function} handler to remove for the command\r\n  */\r\nJitsiConference.prototype.removeCommandListener = function(command, handler) {\r\n    if (this.room) {\r\n        this.room.removePresenceListener(command, handler);\r\n    }\r\n};\r\n\r\n/**\r\n * Sends text message to the other participants in the conference\r\n * @param message the text message.\r\n * @param elementName the element name to encapsulate the message.\r\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\r\n */\r\nJitsiConference.prototype.sendTextMessage = function(message, elementName = 'body') {\r\n    if (this.room) {\r\n        this.room.sendMessage(message, elementName);\r\n    }\r\n};\r\n\r\n/**\r\n * Send private text message to another participant of the conference\r\n * @param id the id of the participant to send a private message.\r\n * @param message the text message.\r\n * @param elementName the element name to encapsulate the message.\r\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\r\n */\r\nJitsiConference.prototype.sendPrivateTextMessage = function(id, message, elementName = 'body') {\r\n    if (this.room) {\r\n        this.room.sendPrivateMessage(id, message, elementName);\r\n    }\r\n};\r\n\r\n/**\r\n * Send presence command.\r\n * @param name {String} the name of the command.\r\n * @param values {Object} with keys and values that will be sent.\r\n **/\r\nJitsiConference.prototype.sendCommand = function(name, values) {\r\n    if (this.room) {\r\n        this.room.addOrReplaceInPresence(name, values) && this.room.sendPresence();\r\n    } else {\r\n        logger.warn('Not sending a command, room not initialized.');\r\n    }\r\n\r\n};\r\n\r\n/**\r\n * Send presence command one time.\r\n * @param name {String} the name of the command.\r\n * @param values {Object} with keys and values that will be sent.\r\n **/\r\nJitsiConference.prototype.sendCommandOnce = function(name, values) {\r\n    this.sendCommand(name, values);\r\n    this.removeCommand(name);\r\n};\r\n\r\n/**\r\n * Removes presence command.\r\n * @param name {String} the name of the command.\r\n **/\r\nJitsiConference.prototype.removeCommand = function(name) {\r\n    if (this.room) {\r\n        this.room.removeFromPresence(name);\r\n    }\r\n};\r\n\r\n/**\r\n * Sets the display name for this conference.\r\n * @param name the display name to set\r\n */\r\nJitsiConference.prototype.setDisplayName = function(name) {\r\n    if (this.room) {\r\n        const nickKey = 'nick';\r\n\r\n        // if there is no display name already set, avoid setting an empty one\r\n        if (!name && !this.room.getFromPresence(nickKey)) {\r\n            return;\r\n        }\r\n\r\n        this.room.addOrReplaceInPresence(nickKey, {\r\n            attributes: { xmlns: 'http://jabber.org/protocol/nick' },\r\n            value: name\r\n        }) && this.room.sendPresence();\r\n    }\r\n};\r\n\r\n/**\r\n * Set new subject for this conference. (available only for moderator)\r\n * @param {string} subject new subject\r\n */\r\nJitsiConference.prototype.setSubject = function(subject) {\r\n    if (this.room && this.isModerator()) {\r\n        this.room.setSubject(subject);\r\n    } else {\r\n        logger.warn(`Failed to set subject, ${this.room ? '' : 'not in a room, '}${\r\n            this.isModerator() ? '' : 'participant is not a moderator'}`);\r\n    }\r\n};\r\n\r\n/**\r\n * Get a transcriber object for all current participants in this conference\r\n * @return {Transcriber} the transcriber object\r\n */\r\nJitsiConference.prototype.getTranscriber = function() {\r\n    if (this.transcriber === undefined) {\r\n        this.transcriber = new Transcriber();\r\n\r\n        // add all existing local audio tracks to the transcriber\r\n        const localAudioTracks = this.getLocalTracks(MediaType.AUDIO);\r\n\r\n        for (const localAudio of localAudioTracks) {\r\n            this.transcriber.addTrack(localAudio);\r\n        }\r\n\r\n        // and all remote audio tracks\r\n        const remoteAudioTracks = this.rtc.getRemoteTracks(MediaType.AUDIO);\r\n\r\n        for (const remoteTrack of remoteAudioTracks) {\r\n            this.transcriber.addTrack(remoteTrack);\r\n        }\r\n    }\r\n\r\n    return this.transcriber;\r\n};\r\n\r\n/**\r\n * Returns the transcription status.\r\n *\r\n * @returns {String} \"on\" or \"off\".\r\n */\r\nJitsiConference.prototype.getTranscriptionStatus = function() {\r\n    return this.room.transcriptionStatus;\r\n};\r\n\r\n/**\r\n * Adds JitsiLocalTrack object to the conference.\r\n * @param {JitsiLocalTrack} track the JitsiLocalTrack object.\r\n * @returns {Promise<JitsiLocalTrack>}\r\n * @throws {Error} if the specified track is a video track and there is already\r\n * another video track in the conference.\r\n */\r\nJitsiConference.prototype.addTrack = function(track) {\r\n    const mediaType = track.getType();\r\n    const localTracks = this.rtc.getLocalTracks(mediaType);\r\n\r\n    // Ensure there's exactly 1 local track of each media type in the conference.\r\n    if (localTracks.length > 0) {\r\n        // Don't be excessively harsh and severe if the API client happens to attempt to add the same local track twice.\r\n        if (track === localTracks[0]) {\r\n            return Promise.resolve(track);\r\n        }\r\n\r\n        // Currently, only adding multiple video streams of different video types is supported.\r\n        // TODO - remove this limitation once issues with jitsi-meet trying to add multiple camera streams is fixed.\r\n        if (FeatureFlags.isMultiStreamSendSupportEnabled()\r\n            && mediaType === MediaType.VIDEO\r\n            && !localTracks.find(t => t.getVideoType() === track.getVideoType())) {\r\n            const sourceName = getSourceNameForJitsiTrack(\r\n                this.myUserId(),\r\n                mediaType,\r\n                this.getLocalTracks(mediaType)?.length);\r\n\r\n            track.setSourceName(sourceName);\r\n            const addTrackPromises = [];\r\n\r\n            this.p2pJingleSession && addTrackPromises.push(this.p2pJingleSession.addTracks([ track ]));\r\n            this.jvbJingleSession && addTrackPromises.push(this.jvbJingleSession.addTracks([ track ]));\r\n\r\n            return Promise.all(addTrackPromises)\r\n                .then(() => {\r\n                    this._setupNewTrack(track);\r\n                    this._sendBridgeVideoTypeMessage(track);\r\n                    this._updateRoomPresence(this.getActiveMediaSession());\r\n\r\n                    if (this.isMutedByFocus || this.isVideoMutedByFocus) {\r\n                        this._fireMuteChangeEvent(track);\r\n                    }\r\n                });\r\n        }\r\n\r\n        return Promise.reject(new Error(`Cannot add second ${mediaType} track to the conference`));\r\n    }\r\n\r\n    return this.replaceTrack(null, track)\r\n        .then(() => {\r\n            // Presence needs to be sent here for desktop track since we need the presence to reach the remote peer\r\n            // before signaling so that a fake participant tile is created for screenshare. Otherwise, presence will\r\n            // only be sent after a session-accept or source-add is ack'ed.\r\n            if (track.getVideoType() === VideoType.DESKTOP && FeatureFlags.isMultiStreamSendSupportEnabled()) {\r\n                this._updateRoomPresence(this.getActiveMediaSession());\r\n            }\r\n        });\r\n};\r\n\r\n/**\r\n * Fires TRACK_AUDIO_LEVEL_CHANGED change conference event (for local tracks).\r\n * @param {number} audioLevel the audio level\r\n * @param {TraceablePeerConnection} [tpc]\r\n */\r\nJitsiConference.prototype._fireAudioLevelChangeEvent = function(audioLevel, tpc) {\r\n    const activeTpc = this.getActivePeerConnection();\r\n\r\n    // There will be no TraceablePeerConnection if audio levels do not come from\r\n    // a peerconnection. LocalStatsCollector.js measures audio levels using Web\r\n    // Audio Analyser API and emits local audio levels events through\r\n    // JitsiTrack.setAudioLevel, but does not provide TPC instance which is\r\n    // optional.\r\n    if (!tpc || activeTpc === tpc) {\r\n        this.eventEmitter.emit(\r\n            JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,\r\n            this.myUserId(), audioLevel);\r\n    }\r\n};\r\n\r\n/**\r\n * Fires TRACK_MUTE_CHANGED change conference event.\r\n * @param track the JitsiTrack object related to the event.\r\n */\r\nJitsiConference.prototype._fireMuteChangeEvent = function(track) {\r\n    // check if track was muted by focus and now is unmuted by user\r\n    if (this.isMutedByFocus && track.isAudioTrack() && !track.isMuted()) {\r\n        this.isMutedByFocus = false;\r\n\r\n        // unmute local user on server\r\n        this.room.muteParticipant(this.room.myroomjid, false, MediaType.AUDIO);\r\n    } else if (this.isVideoMutedByFocus && track.isVideoTrack() && !track.isMuted()) {\r\n        this.isVideoMutedByFocus = false;\r\n\r\n        // unmute local user on server\r\n        this.room.muteParticipant(this.room.myroomjid, false, MediaType.VIDEO);\r\n    }\r\n\r\n    let actorParticipant;\r\n\r\n    if (this.mutedByFocusActor && track.isAudioTrack()) {\r\n        const actorId = Strophe.getResourceFromJid(this.mutedByFocusActor);\r\n\r\n        actorParticipant = this.participants[actorId];\r\n    } else if (this.mutedVideoByFocusActor && track.isVideoTrack()) {\r\n        const actorId = Strophe.getResourceFromJid(this.mutedVideoByFocusActor);\r\n\r\n        actorParticipant = this.participants[actorId];\r\n    }\r\n\r\n    // Send the video type message to the bridge if the track is not removed/added to the pc as part of\r\n    // the mute/unmute operation. This currently happens only on Firefox.\r\n    if (track.isVideoTrack() && !browser.doesVideoMuteByStreamRemove()) {\r\n        this._sendBridgeVideoTypeMessage(track);\r\n    }\r\n\r\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track, actorParticipant);\r\n};\r\n\r\n/**\r\n * Returns the list of local tracks that need to be added to the peerconnection on join.\r\n * This takes the startAudioMuted/startVideoMuted flags into consideration since we do not\r\n * want to add the tracks if the user joins the call audio/video muted. The tracks will be\r\n * added when the user unmutes for the first time.\r\n * @returns {Array<JitsiLocalTrack>} - list of local tracks that are unmuted.\r\n */\r\nJitsiConference.prototype._getInitialLocalTracks = function() {\r\n    // Always add the audio track on certain platforms:\r\n    //  * Safari / WebKit: because of a known issue where audio playout doesn't happen\r\n    //    if the user joins audio and video muted.\r\n    //  * React Native: after iOS 15, if a user joins muted they won't be able to unmute.\r\n    return this.getLocalTracks()\r\n        .filter(track => {\r\n            const trackType = track.getType();\r\n\r\n            if (trackType === MediaType.AUDIO\r\n                    && (!this.isStartAudioMuted() || browser.isWebKitBased() || browser.isReactNative())) {\r\n                return true;\r\n            } else if (trackType === MediaType.VIDEO && !this.isStartVideoMuted()) {\r\n                return true;\r\n            }\r\n\r\n            return false;\r\n        });\r\n};\r\n\r\n/**\r\n * Clear JitsiLocalTrack properties and listeners.\r\n * @param track the JitsiLocalTrack object.\r\n */\r\nJitsiConference.prototype.onLocalTrackRemoved = function(track) {\r\n    track.setConference(null);\r\n    this.rtc.removeLocalTrack(track);\r\n    track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, track.muteHandler);\r\n    if (track.isAudioTrack()) {\r\n        track.removeEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, track.audioLevelHandler);\r\n    }\r\n\r\n    // send event for stopping screen sharing\r\n    // FIXME: we assume we have only one screen sharing track\r\n    // if we change this we need to fix this check\r\n    if (track.isVideoTrack() && track.videoType === VideoType.DESKTOP) {\r\n        this.statistics.sendScreenSharingEvent(false);\r\n    }\r\n\r\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);\r\n};\r\n\r\n/**\r\n * Removes JitsiLocalTrack from the conference and performs\r\n * a new offer/answer cycle.\r\n * @param {JitsiLocalTrack} track\r\n * @returns {Promise}\r\n */\r\nJitsiConference.prototype.removeTrack = function(track) {\r\n    return this.replaceTrack(track, null);\r\n};\r\n\r\n/**\r\n * Replaces oldTrack with newTrack and performs a single offer/answer\r\n *  cycle after both operations are done.  Either oldTrack or newTrack\r\n *  can be null; replacing a valid 'oldTrack' with a null 'newTrack'\r\n *  effectively just removes 'oldTrack'\r\n * @param {JitsiLocalTrack} oldTrack the current stream in use to be replaced\r\n * @param {JitsiLocalTrack} newTrack the new stream to use\r\n * @returns {Promise} resolves when the replacement is finished\r\n */\r\nJitsiConference.prototype.replaceTrack = function(oldTrack, newTrack) {\r\n    const oldVideoType = oldTrack?.getVideoType();\r\n    const mediaType = oldTrack?.getType() || newTrack?.getType();\r\n    const newVideoType = newTrack?.getVideoType();\r\n\r\n    if (FeatureFlags.isMultiStreamSendSupportEnabled() && oldTrack && newTrack && oldVideoType !== newVideoType) {\r\n        throw new Error(`Replacing a track of videoType=${oldVideoType} with a track of videoType=${newVideoType} is`\r\n            + ' not supported in this mode.');\r\n    }\r\n\r\n    if (newTrack) {\r\n        const sourceName = oldTrack\r\n            ? oldTrack.getSourceName()\r\n            : getSourceNameForJitsiTrack(\r\n                this.myUserId(),\r\n                mediaType,\r\n                this.getLocalTracks(mediaType)?.length);\r\n\r\n        newTrack.setSourceName(sourceName);\r\n    }\r\n    const oldTrackBelongsToConference = this === oldTrack?.conference;\r\n\r\n    if (oldTrackBelongsToConference && oldTrack.disposed) {\r\n        return Promise.reject(new JitsiTrackError(JitsiTrackErrors.TRACK_IS_DISPOSED));\r\n    }\r\n    if (newTrack?.disposed) {\r\n        return Promise.reject(new JitsiTrackError(JitsiTrackErrors.TRACK_IS_DISPOSED));\r\n    }\r\n\r\n    if (oldTrack && !oldTrackBelongsToConference) {\r\n        logger.warn(`JitsiConference.replaceTrack oldTrack (${oldTrack} does not belong to this conference`);\r\n    }\r\n\r\n    // Now replace the stream at the lower levels\r\n    return this._doReplaceTrack(oldTrackBelongsToConference ? oldTrack : null, newTrack)\r\n        .then(() => {\r\n            oldTrackBelongsToConference && this.onLocalTrackRemoved(oldTrack);\r\n            newTrack && this._setupNewTrack(newTrack);\r\n\r\n            // Send 'VideoTypeMessage' on the bridge channel when a video track is added/removed.\r\n            if ((oldTrackBelongsToConference && oldTrack?.isVideoTrack()) || newTrack?.isVideoTrack()) {\r\n                this._sendBridgeVideoTypeMessage(newTrack);\r\n            }\r\n            this._updateRoomPresence(this.getActiveMediaSession());\r\n            if (newTrack !== null && (this.isMutedByFocus || this.isVideoMutedByFocus)) {\r\n                this._fireMuteChangeEvent(newTrack);\r\n            }\r\n\r\n            return Promise.resolve();\r\n        })\r\n        .catch(error => {\r\n            logger.error(`replaceTrack failed: ${error?.stack}`);\r\n\r\n            return Promise.reject(error);\r\n        });\r\n};\r\n\r\n/**\r\n * Replaces the tracks at the lower level by going through the Jingle session\r\n * and WebRTC peer connection. The method will resolve immediately if there is\r\n * currently no JingleSession started.\r\n * @param {JitsiLocalTrack|null} oldTrack the track to be removed during\r\n * the process or <tt>null</t> if the method should act as \"add track\"\r\n * @param {JitsiLocalTrack|null} newTrack the new track to be added or\r\n * <tt>null</tt> if the method should act as \"remove track\"\r\n * @return {Promise} resolved when the process is done or rejected with a string\r\n * which describes the error.\r\n * @private\r\n */\r\nJitsiConference.prototype._doReplaceTrack = function(oldTrack, newTrack) {\r\n    const replaceTrackPromises = [];\r\n\r\n    if (this.jvbJingleSession) {\r\n        replaceTrackPromises.push(this.jvbJingleSession.replaceTrack(oldTrack, newTrack));\r\n    } else {\r\n        logger.info('_doReplaceTrack - no JVB JingleSession');\r\n    }\r\n\r\n    if (this.p2pJingleSession) {\r\n        replaceTrackPromises.push(this.p2pJingleSession.replaceTrack(oldTrack, newTrack));\r\n    } else {\r\n        logger.info('_doReplaceTrack - no P2P JingleSession');\r\n    }\r\n\r\n    return Promise.all(replaceTrackPromises);\r\n};\r\n\r\n/**\r\n * Handler for when a source-add for a local source is rejected by Jicofo.\r\n *\r\n * @param {JingleSessionPC} jingleSession - The media session.\r\n * @param {Error} error - The error message.\r\n * @param {MediaType} mediaType - The media type of the track associated with the source that was rejected.\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype._removeLocalSourceOnReject = function(jingleSession, error, mediaType) {\r\n    if (!jingleSession) {\r\n        return;\r\n    }\r\n    logger.warn(`Source-add rejected on ${jingleSession}, reason=\"${error?.reason}\", message=\"${error?.msg}\"`);\r\n    const track = this.getLocalTracks(mediaType)[0];\r\n\r\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_UNMUTE_REJECTED, track);\r\n};\r\n\r\n/**\r\n * Operations related to creating a new track\r\n * @param {JitsiLocalTrack} newTrack the new track being created\r\n */\r\nJitsiConference.prototype._setupNewTrack = function(newTrack) {\r\n    const mediaType = newTrack.getType();\r\n\r\n    if (newTrack.isAudioTrack() || (newTrack.isVideoTrack() && newTrack.videoType !== VideoType.DESKTOP)) {\r\n        // Report active device to statistics\r\n        const devices = RTC.getCurrentlyAvailableMediaDevices();\r\n        const device = devices\r\n            .find(d => d.kind === `${newTrack.getTrack().kind}input` && d.label === newTrack.getTrack().label);\r\n\r\n        if (device) {\r\n            Statistics.sendActiveDeviceListEvent(RTC.getEventDataForActiveDevice(device));\r\n        }\r\n    }\r\n\r\n    // Create a source name for this track if it doesn't exist.\r\n    if (!newTrack.getSourceName()) {\r\n        const sourceName = getSourceNameForJitsiTrack(\r\n            this.myUserId(),\r\n            mediaType,\r\n            this.getLocalTracks(mediaType)?.length);\r\n\r\n        newTrack.setSourceName(sourceName);\r\n    }\r\n\r\n    this.rtc.addLocalTrack(newTrack);\r\n    newTrack.setConference(this);\r\n\r\n    // Add event handlers.\r\n    newTrack.muteHandler = this._fireMuteChangeEvent.bind(this, newTrack);\r\n    newTrack.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, newTrack.muteHandler);\r\n\r\n    if (newTrack.isAudioTrack()) {\r\n        newTrack.audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);\r\n        newTrack.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, newTrack.audioLevelHandler);\r\n    }\r\n\r\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, newTrack);\r\n};\r\n\r\n/**\r\n * Sets the video type.\r\n * @param track\r\n * @return <tt>true</tt> if video type was changed in presence.\r\n * @private\r\n */\r\nJitsiConference.prototype._setNewVideoType = function(track) {\r\n    let videoTypeChanged = false;\r\n\r\n    if (track) {\r\n        videoTypeChanged = this._signalingLayer.setTrackVideoType(track.getSourceName(), track.videoType);\r\n    }\r\n\r\n    return videoTypeChanged;\r\n};\r\n\r\n/**\r\n * Sets mute status.\r\n * @param mediaType\r\n * @param localTrack\r\n * @param isMuted\r\n * @param <tt>true</tt> when presence was changed, <tt>false</tt> otherwise.\r\n * @private\r\n */\r\nJitsiConference.prototype._setTrackMuteStatus = function(mediaType, localTrack, isMuted) {\r\n    let presenceChanged = false;\r\n\r\n    if (localTrack) {\r\n        presenceChanged = this._signalingLayer.setTrackMuteStatus(localTrack.getSourceName(), isMuted);\r\n    }\r\n\r\n    return presenceChanged;\r\n};\r\n\r\n/**\r\n * Method called by the {@link JitsiLocalTrack} in order to add the underlying MediaStream to the RTCPeerConnection.\r\n *\r\n * @param {JitsiLocalTrack} track the local track that will be added to the pc.\r\n * @return {Promise} resolved when the process is done or rejected with a string which describes the error.\r\n */\r\nJitsiConference.prototype._addLocalTrackToPc = function(track) {\r\n    const addPromises = [];\r\n\r\n    if (this.jvbJingleSession) {\r\n        addPromises.push(this.jvbJingleSession.addTrackToPc(track));\r\n    } else {\r\n        logger.debug('Add local MediaStream - no JVB Jingle session started yet');\r\n    }\r\n\r\n    if (this.p2pJingleSession) {\r\n        addPromises.push(this.p2pJingleSession.addTrackToPc(track));\r\n    } else {\r\n        logger.debug('Add local MediaStream - no P2P Jingle session started yet');\r\n    }\r\n\r\n    return Promise.allSettled(addPromises);\r\n};\r\n\r\n/**\r\n * Method called by the {@link JitsiLocalTrack} in order to remove the underlying MediaStream from the\r\n * RTCPeerConnection.\r\n *\r\n * @param {JitsiLocalTrack} track the local track that will be removed.\r\n * @return {Promise} resolved when the process is done or rejected with a string which describes the error.\r\n */\r\nJitsiConference.prototype._removeLocalTrackFromPc = function(track) {\r\n    const removePromises = [];\r\n\r\n    if (this.jvbJingleSession) {\r\n        removePromises.push(this.jvbJingleSession.removeTrackFromPc(track));\r\n    } else {\r\n        logger.debug('Remove local MediaStream - no JVB JingleSession started yet');\r\n    }\r\n    if (this.p2pJingleSession) {\r\n        removePromises.push(this.p2pJingleSession.removeTrackFromPc(track));\r\n    } else {\r\n        logger.debug('Remove local MediaStream - no P2P JingleSession started yet');\r\n    }\r\n\r\n    return Promise.allSettled(removePromises);\r\n};\r\n\r\n/**\r\n * Get role of the local user.\r\n * @returns {string} user role: 'moderator' or 'none'\r\n */\r\nJitsiConference.prototype.getRole = function() {\r\n    return this.room.role;\r\n};\r\n\r\n/**\r\n * Returns whether or not the current conference has been joined as a hidden\r\n * user.\r\n *\r\n * @returns {boolean|null} True if hidden, false otherwise. Will return null if\r\n * no connection is active.\r\n */\r\nJitsiConference.prototype.isHidden = function() {\r\n    if (!this.connection) {\r\n        return null;\r\n    }\r\n\r\n    return Strophe.getDomainFromJid(this.connection.getJid())\r\n        === this.options.config.hiddenDomain;\r\n};\r\n\r\n/**\r\n * Check if local user is moderator.\r\n * @returns {boolean|null} true if local user is moderator, false otherwise. If\r\n * we're no longer in the conference room then <tt>null</tt> is returned.\r\n */\r\nJitsiConference.prototype.isModerator = function() {\r\n    return this.room ? this.room.isModerator() : null;\r\n};\r\n\r\n/**\r\n * Set password for the room.\r\n * @param {string} password new password for the room.\r\n * @returns {Promise}\r\n */\r\nJitsiConference.prototype.lock = function(password) {\r\n    if (!this.isModerator()) {\r\n        return Promise.reject(new Error('You are not moderator.'));\r\n    }\r\n\r\n    return new Promise((resolve, reject) => {\r\n        this.room.lockRoom(\r\n            password || '',\r\n            () => resolve(),\r\n            err => reject(err),\r\n            () => reject(JitsiConferenceErrors.PASSWORD_NOT_SUPPORTED));\r\n    });\r\n};\r\n\r\n/**\r\n * Remove password from the room.\r\n * @returns {Promise}\r\n */\r\nJitsiConference.prototype.unlock = function() {\r\n    return this.lock();\r\n};\r\n\r\n/**\r\n * Elects the participant with the given id to be the selected participant in\r\n * order to receive higher video quality (if simulcast is enabled).\r\n * Or cache it if channel is not created and send it once channel is available.\r\n * @param participantId the identifier of the participant\r\n * @throws NetworkError or InvalidStateError or Error if the operation fails.\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype.selectParticipant = function(participantId) {\r\n    this.selectParticipants([ participantId ]);\r\n};\r\n\r\n/*\r\n * Elects participants with given ids to be the selected participants in order\r\n * to receive higher video quality (if simulcast is enabled). The argument\r\n * should be an array of participant id strings or an empty array; an error will\r\n * be thrown if a non-array is passed in. The error is thrown as a layer of\r\n * protection against passing an invalid argument, as the error will happen in\r\n * the bridge and may not be visible in the client.\r\n *\r\n * @param {Array<strings>} participantIds - An array of identifiers for\r\n * participants.\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype.selectParticipants = function(participantIds) {\r\n    if (!Array.isArray(participantIds)) {\r\n        throw new Error('Invalid argument; participantIds must be an array.');\r\n    }\r\n\r\n    this.receiveVideoController.selectEndpoints(participantIds);\r\n};\r\n\r\n/**\r\n * Obtains the current value for \"lastN\". See {@link setLastN} for more info.\r\n * @returns {number}\r\n */\r\nJitsiConference.prototype.getLastN = function() {\r\n    return this.receiveVideoController.getLastN();\r\n};\r\n\r\n/**\r\n * Obtains the forwarded sources list in this conference.\r\n * @return {Array<string>|null}\r\n */\r\nJitsiConference.prototype.getForwardedSources = function() {\r\n    return this.rtc.getForwardedSources();\r\n};\r\n\r\n/**\r\n * Selects a new value for \"lastN\". The requested amount of videos are going\r\n * to be delivered after the value is in effect. Set to -1 for unlimited or\r\n * all available videos.\r\n * @param lastN the new number of videos the user would like to receive.\r\n * @throws Error or RangeError if the given value is not a number or is smaller\r\n * than -1.\r\n */\r\nJitsiConference.prototype.setLastN = function(lastN) {\r\n    if (!Number.isInteger(lastN) && !Number.parseInt(lastN, 10)) {\r\n        throw new Error(`Invalid value for lastN: ${lastN}`);\r\n    }\r\n    const n = Number(lastN);\r\n\r\n    if (n < -1) {\r\n        throw new RangeError('lastN cannot be smaller than -1');\r\n    }\r\n    this.receiveVideoController.setLastN(n);\r\n\r\n    // If the P2P session is not fully established yet, we wait until it gets\r\n    // established.\r\n    if (this.p2pJingleSession) {\r\n        const isVideoActive = n !== 0;\r\n\r\n        this.p2pJingleSession\r\n            .setMediaTransferActive(true, isVideoActive)\r\n            .catch(error => {\r\n                logger.error(\r\n                    `Failed to adjust video transfer status (${isVideoActive})`,\r\n                    error);\r\n            });\r\n    }\r\n};\r\n\r\n/**\r\n * @return Array<JitsiParticipant> an array of all participants in this\r\n * conference.\r\n */\r\nJitsiConference.prototype.getParticipants = function() {\r\n    return Object.values(this.participants);\r\n};\r\n\r\n/**\r\n * Returns the number of participants in the conference, including the local\r\n * participant.\r\n * @param countHidden {boolean} Whether or not to include hidden participants\r\n * in the count. Default: false.\r\n **/\r\nJitsiConference.prototype.getParticipantCount = function(countHidden = false) {\r\n    let participants = this.getParticipants();\r\n\r\n    if (!countHidden) {\r\n        participants = participants.filter(p => !p.isHidden());\r\n    }\r\n\r\n    // Add one for the local participant.\r\n    return participants.length + 1;\r\n};\r\n\r\n/**\r\n * @returns {JitsiParticipant} the participant in this conference with the\r\n * specified id (or undefined if there isn't one).\r\n * @param id the id of the participant.\r\n */\r\nJitsiConference.prototype.getParticipantById = function(id) {\r\n    return this.participants[id];\r\n};\r\n\r\n/**\r\n * Grant owner rights to the participant.\r\n * @param {string} id id of the participant to grant owner rights to.\r\n */\r\nJitsiConference.prototype.grantOwner = function(id) {\r\n    const participant = this.getParticipantById(id);\r\n\r\n    if (!participant) {\r\n        return;\r\n    }\r\n    this.room.setAffiliation(participant.getConnectionJid(), 'owner');\r\n};\r\n\r\n/**\r\n * Revoke owner rights to the participant or local Participant as\r\n * the user might want to refuse to be a moderator.\r\n * @param {string} id id of the participant to revoke owner rights to.\r\n */\r\nJitsiConference.prototype.revokeOwner = function(id) {\r\n    const participant = this.getParticipantById(id);\r\n    const isMyself = this.myUserId() === id;\r\n    const role = this.isMembersOnly() ? 'member' : 'none';\r\n\r\n    if (isMyself) {\r\n        this.room.setAffiliation(this.connection.getJid(), role);\r\n    } else if (participant) {\r\n        this.room.setAffiliation(participant.getConnectionJid(), role);\r\n    }\r\n};\r\n\r\n/**\r\n * Kick participant from this conference.\r\n * @param {string} id id of the participant to kick\r\n * @param {string} reason reason of the participant to kick\r\n */\r\nJitsiConference.prototype.kickParticipant = function(id, reason) {\r\n    const participant = this.getParticipantById(id);\r\n\r\n    if (!participant) {\r\n        return;\r\n    }\r\n    this.room.kick(participant.getJid(), reason);\r\n};\r\n\r\n/**\r\n * Maybe clears the timeout which emits {@link ACTION_JINGLE_SI_TIMEOUT}\r\n * analytics event.\r\n * @private\r\n */\r\nJitsiConference.prototype._maybeClearSITimeout = function() {\r\n    if (this._sessionInitiateTimeout\r\n            && (this.jvbJingleSession || this.getParticipantCount() < 2)) {\r\n        window.clearTimeout(this._sessionInitiateTimeout);\r\n        this._sessionInitiateTimeout = null;\r\n    }\r\n};\r\n\r\n/**\r\n * Sets a timeout which will emit {@link ACTION_JINGLE_SI_TIMEOUT} analytics\r\n * event.\r\n * @private\r\n */\r\nJitsiConference.prototype._maybeSetSITimeout = function() {\r\n    // Jicofo is supposed to invite if there are at least 2 participants\r\n    if (!this.jvbJingleSession\r\n            && this.getParticipantCount() >= 2\r\n            && !this._sessionInitiateTimeout) {\r\n        this._sessionInitiateTimeout = window.setTimeout(() => {\r\n            this._sessionInitiateTimeout = null;\r\n            Statistics.sendAnalytics(createJingleEvent(\r\n                ACTION_JINGLE_SI_TIMEOUT,\r\n                {\r\n                    p2p: false,\r\n                    value: JINGLE_SI_TIMEOUT\r\n                }));\r\n        }, JINGLE_SI_TIMEOUT);\r\n    }\r\n};\r\n\r\n/**\r\n * Mutes a participant.\r\n * @param {string} id The id of the participant to mute.\r\n */\r\nJitsiConference.prototype.muteParticipant = function(id, mediaType) {\r\n    const muteMediaType = mediaType ? mediaType : MediaType.AUDIO;\r\n\r\n    if (muteMediaType !== MediaType.AUDIO && muteMediaType !== MediaType.VIDEO) {\r\n        logger.error(`Unsupported media type: ${muteMediaType}`);\r\n\r\n        return;\r\n    }\r\n\r\n    const participant = this.getParticipantById(id);\r\n\r\n    if (!participant) {\r\n        return;\r\n    }\r\n    this.room.muteParticipant(participant.getJid(), true, muteMediaType);\r\n};\r\n\r\n/* eslint-disable max-params */\r\n\r\n/**\r\n * Notifies this JitsiConference that a new member has joined its chat room.\r\n *\r\n * FIXME This should NOT be exposed!\r\n *\r\n * @param jid the jid of the participant in the MUC\r\n * @param nick the display name of the participant\r\n * @param role the role of the participant in the MUC\r\n * @param isHidden indicates if this is a hidden participant (system\r\n * participant for example a recorder).\r\n * @param statsID the participant statsID (optional)\r\n * @param status the initial status if any\r\n * @param identity the member identity, if any\r\n * @param botType the member botType, if any\r\n * @param fullJid the member full jid, if any\r\n * @param features the member botType, if any\r\n * @param isReplaceParticipant whether this join replaces a participant with\r\n * the same jwt.\r\n */\r\nJitsiConference.prototype.onMemberJoined = function(\r\n        jid, nick, role, isHidden, statsID, status, identity, botType, fullJid, features, isReplaceParticipant) {\r\n    const id = Strophe.getResourceFromJid(jid);\r\n\r\n    if (id === 'focus' || this.myUserId() === id) {\r\n        return;\r\n    }\r\n\r\n    const participant\r\n        = new JitsiParticipant(jid, this, nick, isHidden, statsID, status, identity);\r\n\r\n    participant.setConnectionJid(fullJid);\r\n    participant.setRole(role);\r\n    participant.setBotType(botType);\r\n    participant.setFeatures(features);\r\n    participant.setIsReplacing(isReplaceParticipant);\r\n\r\n    this.participants[id] = participant;\r\n    this.eventEmitter.emit(\r\n        JitsiConferenceEvents.USER_JOINED,\r\n        id,\r\n        participant);\r\n\r\n    this._updateFeatures(participant);\r\n\r\n    // maybeStart only if we had finished joining as then we will have information for the number of participants\r\n    if (this.isJoined()) {\r\n        this._maybeStartOrStopP2P();\r\n    }\r\n\r\n    this._maybeSetSITimeout();\r\n};\r\n\r\n/* eslint-enable max-params */\r\n\r\n/**\r\n * Get notified when we joined the room.\r\n *\r\n * FIXME This should NOT be exposed!\r\n *\r\n * @private\r\n */\r\nJitsiConference.prototype._onMucJoined = function() {\r\n    this._maybeStartOrStopP2P();\r\n};\r\n\r\n/**\r\n * Updates features for a participant.\r\n * @param {JitsiParticipant} participant - The participant to query for features.\r\n * @returns {void}\r\n * @private\r\n */\r\nJitsiConference.prototype._updateFeatures = function(participant) {\r\n    participant.getFeatures()\r\n        .then(features => {\r\n            participant._supportsDTMF = features.has('urn:xmpp:jingle:dtmf:0');\r\n            this.updateDTMFSupport();\r\n\r\n            if (features.has(FEATURE_JIGASI)) {\r\n                participant.setProperty('features_jigasi', true);\r\n            }\r\n\r\n            if (features.has(FEATURE_E2EE)) {\r\n                participant.setProperty('features_e2ee', true);\r\n            }\r\n        })\r\n        .catch(() => false);\r\n};\r\n\r\n/**\r\n * Get notified when member bot type had changed.\r\n * @param jid the member jid\r\n * @param botType the new botType value\r\n * @private\r\n */\r\nJitsiConference.prototype._onMemberBotTypeChanged = function(jid, botType) {\r\n\r\n    // find the participant and mark it as non bot, as the real one will join\r\n    // in a moment\r\n    const peers = this.getParticipants();\r\n    const botParticipant = peers.find(p => p.getJid() === jid);\r\n\r\n    if (botParticipant) {\r\n        botParticipant.setBotType(botType);\r\n        const id = Strophe.getResourceFromJid(jid);\r\n\r\n        this.eventEmitter.emit(\r\n            JitsiConferenceEvents.BOT_TYPE_CHANGED,\r\n            id,\r\n            botType);\r\n    }\r\n\r\n    // if botType changed to undefined, botType was removed, in case of\r\n    // poltergeist mode this is the moment when the poltergeist had exited and\r\n    // the real participant had already replaced it.\r\n    // In this case we can check and try p2p\r\n    if (!botParticipant.getBotType()) {\r\n        this._maybeStartOrStopP2P();\r\n    }\r\n};\r\n\r\nJitsiConference.prototype.onMemberLeft = function(jid, reason) {\r\n    const id = Strophe.getResourceFromJid(jid);\r\n\r\n    if (id === 'focus' || this.myUserId() === id) {\r\n        return;\r\n    }\r\n\r\n    if (!FeatureFlags.isSsrcRewritingSupported()) {\r\n        const mediaSessions = this.getMediaSessions();\r\n        let tracksToBeRemoved = [];\r\n\r\n        for (const session of mediaSessions) {\r\n            const remoteTracks = session.peerconnection.getRemoteTracks(id);\r\n\r\n            remoteTracks && (tracksToBeRemoved = [ ...tracksToBeRemoved, ...remoteTracks ]);\r\n\r\n            // Remove the ssrcs from the remote description and renegotiate.\r\n            session.removeRemoteStreamsOnLeave(id);\r\n        }\r\n\r\n        // Fire the event before renegotiation is done so that the thumbnails can be removed immediately.\r\n        tracksToBeRemoved.forEach(track => {\r\n            this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);\r\n        });\r\n    }\r\n\r\n    const participant = this.participants[id];\r\n\r\n    if (participant) {\r\n        delete this.participants[id];\r\n        this.eventEmitter.emit(JitsiConferenceEvents.USER_LEFT, id, participant, reason);\r\n    }\r\n\r\n    if (this.room !== null) { // Skip if we have left the room already.\r\n        this._maybeStartOrStopP2P(true /* triggered by user left event */);\r\n        this._maybeClearSITimeout();\r\n    }\r\n};\r\n\r\n/* eslint-disable max-params */\r\n\r\n/**\r\n * Designates an event indicating that we were kicked from the XMPP MUC.\r\n * @param {boolean} isSelfPresence - whether it is for local participant\r\n * or another participant.\r\n * @param {string} actorId - the id of the participant who was initiator\r\n * of the kick.\r\n * @param {string?} kickedParticipantId - when it is not a kick for local participant,\r\n * this is the id of the participant which was kicked.\r\n * @param {string} reason - reason of the participant to kick\r\n * @param {boolean?} isReplaceParticipant - whether this is a server initiated kick in order\r\n * to replace it with a participant with same jwt.\r\n */\r\nJitsiConference.prototype.onMemberKicked = function(\r\n        isSelfPresence,\r\n        actorId,\r\n        kickedParticipantId,\r\n        reason,\r\n        isReplaceParticipant) {\r\n    // This check which be true when we kick someone else. With the introduction of lobby\r\n    // the ChatRoom KICKED event is now also emitted for ourselves (the kicker) so we want to\r\n    // avoid emitting an event where `undefined` kicked someone.\r\n    if (actorId === this.myUserId()) {\r\n        return;\r\n    }\r\n\r\n    const actorParticipant = this.participants[actorId];\r\n\r\n    if (isSelfPresence) {\r\n        this.eventEmitter.emit(\r\n            JitsiConferenceEvents.KICKED, actorParticipant, reason, isReplaceParticipant);\r\n\r\n        this.leave();\r\n\r\n        return;\r\n    }\r\n\r\n    const kickedParticipant = this.participants[kickedParticipantId];\r\n\r\n    kickedParticipant.setIsReplaced(isReplaceParticipant);\r\n\r\n    this.eventEmitter.emit(\r\n        JitsiConferenceEvents.PARTICIPANT_KICKED, actorParticipant, kickedParticipant, reason);\r\n};\r\n\r\n/**\r\n * Method called on local MUC role change.\r\n * @param {string} role the name of new user's role as defined by XMPP MUC.\r\n */\r\nJitsiConference.prototype.onLocalRoleChanged = function(role) {\r\n    // Emit role changed for local  JID\r\n    this.eventEmitter.emit(\r\n        JitsiConferenceEvents.USER_ROLE_CHANGED, this.myUserId(), role);\r\n};\r\n\r\nJitsiConference.prototype.onUserRoleChanged = function(jid, role) {\r\n    const id = Strophe.getResourceFromJid(jid);\r\n    const participant = this.getParticipantById(id);\r\n\r\n    if (!participant) {\r\n        return;\r\n    }\r\n    participant.setRole(role);\r\n    this.eventEmitter.emit(JitsiConferenceEvents.USER_ROLE_CHANGED, id, role);\r\n};\r\n\r\nJitsiConference.prototype.onDisplayNameChanged = function(jid, displayName) {\r\n    const id = Strophe.getResourceFromJid(jid);\r\n    const participant = this.getParticipantById(id);\r\n\r\n    if (!participant) {\r\n        return;\r\n    }\r\n\r\n    if (participant._displayName === displayName) {\r\n        return;\r\n    }\r\n\r\n    participant._displayName = displayName;\r\n    this.eventEmitter.emit(\r\n        JitsiConferenceEvents.DISPLAY_NAME_CHANGED,\r\n        id,\r\n        displayName);\r\n};\r\n\r\n/**\r\n * Notifies this JitsiConference that a JitsiRemoteTrack was added to the conference.\r\n *\r\n * @param {JitsiRemoteTrack} track the JitsiRemoteTrack which was added to this JitsiConference.\r\n */\r\nJitsiConference.prototype.onRemoteTrackAdded = function(track) {\r\n    if (track.isP2P && !this.isP2PActive()) {\r\n        logger.info('Trying to add remote P2P track, when not in P2P - IGNORED');\r\n\r\n        return;\r\n    } else if (!track.isP2P && this.isP2PActive()) {\r\n        logger.info('Trying to add remote JVB track, when in P2P - IGNORED');\r\n\r\n        return;\r\n    }\r\n\r\n    const id = track.getParticipantId();\r\n    const participant = this.getParticipantById(id);\r\n\r\n    if (!participant) {\r\n        logger.error(`No participant found for id: ${id}`);\r\n\r\n        return;\r\n    }\r\n\r\n    // Add track to JitsiParticipant.\r\n    participant._tracks.push(track);\r\n\r\n    if (this.transcriber) {\r\n        this.transcriber.addTrack(track);\r\n    }\r\n\r\n    const emitter = this.eventEmitter;\r\n\r\n    track.addEventListener(\r\n        JitsiTrackEvents.TRACK_MUTE_CHANGED,\r\n        () => emitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track));\r\n    track.isAudioTrack() && track.addEventListener(\r\n        JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,\r\n        (audioLevel, tpc) => {\r\n            const activeTPC = this.getActivePeerConnection();\r\n\r\n            if (activeTPC === tpc) {\r\n                emitter.emit(JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED, id, audioLevel);\r\n            }\r\n        }\r\n    );\r\n\r\n    emitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);\r\n};\r\n\r\n/**\r\n * Callback called by the Jingle plugin when 'session-answer' is received.\r\n * @param {JingleSessionPC} session the Jingle session for which an answer was\r\n * received.\r\n * @param {jQuery} answer a jQuery selector pointing to 'jingle' IQ element\r\n */\r\n// eslint-disable-next-line no-unused-vars\r\nJitsiConference.prototype.onCallAccepted = function(session, answer) {\r\n    if (this.p2pJingleSession === session) {\r\n        logger.info('P2P setAnswer');\r\n\r\n        this.p2pJingleSession.setAnswer(answer);\r\n        this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_STARTED, this.p2pJingleSession);\r\n    }\r\n};\r\n\r\n/**\r\n * Callback called by the Jingle plugin when 'transport-info' is received.\r\n * @param {JingleSessionPC} session the Jingle session for which the IQ was\r\n * received\r\n * @param {jQuery} transportInfo a jQuery selector pointing to 'jingle' IQ\r\n * element\r\n */\r\n// eslint-disable-next-line no-unused-vars\r\nJitsiConference.prototype.onTransportInfo = function(session, transportInfo) {\r\n    if (this.p2pJingleSession === session) {\r\n        logger.info('P2P addIceCandidates');\r\n        this.p2pJingleSession.addIceCandidates(transportInfo);\r\n    }\r\n};\r\n\r\n/**\r\n * Notifies this JitsiConference that a JitsiRemoteTrack was removed from\r\n * the conference.\r\n *\r\n * @param {JitsiRemoteTrack} removedTrack\r\n */\r\nJitsiConference.prototype.onRemoteTrackRemoved = function(removedTrack) {\r\n    this.getParticipants().forEach(participant => {\r\n        const tracks = participant.getTracks();\r\n\r\n        for (let i = 0; i < tracks.length; i++) {\r\n            if (tracks[i] === removedTrack) {\r\n                // Since the tracks have been compared and are\r\n                // considered equal the result of splice can be ignored.\r\n                participant._tracks.splice(i, 1);\r\n\r\n                this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, removedTrack);\r\n\r\n                if (this.transcriber) {\r\n                    this.transcriber.removeTrack(removedTrack);\r\n                }\r\n\r\n                break;\r\n            }\r\n        }\r\n    }, this);\r\n};\r\n\r\n/**\r\n * Handles an incoming call event for the P2P jingle session.\r\n */\r\nJitsiConference.prototype._onIncomingCallP2P = function(jingleSession, jingleOffer) {\r\n    let rejectReason;\r\n    const usesUnifiedPlan = browser.supportsUnifiedPlan()\r\n        && (!browser.isChromiumBased() || (this.options.config.enableUnifiedOnChrome ?? true));\r\n    const contentName = jingleOffer.find('>content').attr('name');\r\n    const peerUsesUnifiedPlan = contentName === '0' || contentName === '1';\r\n\r\n    // Reject P2P between endpoints that are not running in the same mode w.r.t to SDPs (plan-b and unified plan).\r\n    if (usesUnifiedPlan !== peerUsesUnifiedPlan) {\r\n        rejectReason = {\r\n            reason: 'decline',\r\n            reasonDescription: 'P2P disabled',\r\n            errorMsg: 'P2P across two endpoints in different SDP modes is disabled'\r\n        };\r\n    } else if ((!this.isP2PEnabled() && !this.isP2PTestModeEnabled())\r\n        || browser.isFirefox()\r\n        || browser.isWebKitBased()) {\r\n        rejectReason = {\r\n            reason: 'decline',\r\n            reasonDescription: 'P2P disabled',\r\n            errorMsg: 'P2P mode disabled in the configuration or browser unsupported'\r\n        };\r\n    } else if (this.p2pJingleSession) {\r\n        // Reject incoming P2P call (already in progress)\r\n        rejectReason = {\r\n            reason: 'busy',\r\n            reasonDescription: 'P2P already in progress',\r\n            errorMsg: 'Duplicated P2P \"session-initiate\"'\r\n        };\r\n    } else if (!this._shouldBeInP2PMode()) {\r\n        rejectReason = {\r\n            reason: 'decline',\r\n            reasonDescription: 'P2P requirements not met',\r\n            errorMsg: 'Received P2P \"session-initiate\" when should not be in P2P mode'\r\n        };\r\n        Statistics.sendAnalytics(createJingleEvent(ACTION_P2P_DECLINED));\r\n    }\r\n\r\n    if (rejectReason) {\r\n        this._rejectIncomingCall(jingleSession, rejectReason);\r\n    } else {\r\n        this._acceptP2PIncomingCall(jingleSession, jingleOffer);\r\n    }\r\n};\r\n\r\n/**\r\n * Handles an incoming call event.\r\n */\r\nJitsiConference.prototype.onIncomingCall = function(jingleSession, jingleOffer, now) {\r\n    // Handle incoming P2P call\r\n    if (jingleSession.isP2P) {\r\n        this._onIncomingCallP2P(jingleSession, jingleOffer);\r\n    } else {\r\n        if (!this.isFocus(jingleSession.remoteJid)) {\r\n            const description = 'Rejecting session-initiate from non-focus.';\r\n\r\n            this._rejectIncomingCall(\r\n                jingleSession, {\r\n                    reason: 'security-error',\r\n                    reasonDescription: description,\r\n                    errorMsg: description\r\n                });\r\n\r\n            return;\r\n        }\r\n        this._acceptJvbIncomingCall(jingleSession, jingleOffer, now);\r\n    }\r\n};\r\n\r\n/**\r\n * Accepts an incoming call event for the JVB jingle session.\r\n */\r\nJitsiConference.prototype._acceptJvbIncomingCall = function(jingleSession, jingleOffer, now) {\r\n\r\n    // Accept incoming call\r\n    this.jvbJingleSession = jingleSession;\r\n    this.room.connectionTimes['session.initiate'] = now;\r\n    this._sendConferenceJoinAnalyticsEvent();\r\n\r\n    if (this.wasStopped) {\r\n        Statistics.sendAnalyticsAndLog(createJingleEvent(ACTION_JINGLE_RESTART, { p2p: false }));\r\n    }\r\n\r\n    const serverRegion\r\n        = $(jingleOffer)\r\n            .find('>bridge-session[xmlns=\"http://jitsi.org/protocol/focus\"]')\r\n            .attr('region');\r\n\r\n    this.eventEmitter.emit(JitsiConferenceEvents.SERVER_REGION_CHANGED, serverRegion);\r\n\r\n    this._maybeClearSITimeout();\r\n    Statistics.sendAnalytics(createJingleEvent(\r\n        ACTION_JINGLE_SI_RECEIVED,\r\n        {\r\n            p2p: false,\r\n            value: now\r\n        }));\r\n\r\n    try {\r\n        jingleSession.initialize(\r\n            this.room,\r\n            this.rtc,\r\n            this._signalingLayer,\r\n            {\r\n                ...this.options.config,\r\n                enableInsertableStreams: this.isE2EEEnabled()\r\n            });\r\n    } catch (error) {\r\n        GlobalOnErrorHandler.callErrorHandler(error);\r\n        logger.error(error);\r\n\r\n        return;\r\n    }\r\n\r\n    // Open a channel with the videobridge.\r\n    this._setBridgeChannel(jingleOffer, jingleSession.peerconnection);\r\n\r\n    const localTracks = this._getInitialLocalTracks();\r\n\r\n    try {\r\n        jingleSession.acceptOffer(\r\n            jingleOffer,\r\n            () => {\r\n                // If for any reason invite for the JVB session arrived after\r\n                // the P2P has been established already the media transfer needs\r\n                // to be turned off here.\r\n                if (this.isP2PActive() && this.jvbJingleSession) {\r\n                    this._suspendMediaTransferForJvbConnection();\r\n                }\r\n\r\n                this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_STARTED, jingleSession);\r\n                if (!this.isP2PActive()) {\r\n                    this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED, jingleSession);\r\n                }\r\n            },\r\n            error => {\r\n                GlobalOnErrorHandler.callErrorHandler(error);\r\n                logger.error('Failed to accept incoming Jingle session', error);\r\n            },\r\n            localTracks\r\n        );\r\n\r\n        // Enable or disable simulcast for plan-b screensharing based on the capture fps if it is set through the UI.\r\n        this._desktopSharingFrameRate\r\n            && jingleSession.peerconnection.setDesktopSharingFrameRate(this._desktopSharingFrameRate);\r\n\r\n        // Start callstats as soon as peerconnection is initialized,\r\n        // do not wait for XMPPEvents.PEERCONNECTION_READY, as it may never\r\n        // happen in case if user doesn't have or denied permission to\r\n        // both camera and microphone.\r\n        logger.info('Starting CallStats for JVB connection...');\r\n        this.statistics.startCallStats(\r\n            this.jvbJingleSession.peerconnection,\r\n            'jitsi' /* Remote user ID for JVB is 'jitsi' */);\r\n        this.statistics.startRemoteStats(this.jvbJingleSession.peerconnection);\r\n    } catch (e) {\r\n        GlobalOnErrorHandler.callErrorHandler(e);\r\n        logger.error(e);\r\n    }\r\n};\r\n\r\n/**\r\n * Sets the BridgeChannel.\r\n *\r\n * @param {jQuery} offerIq a jQuery selector pointing to the jingle element of\r\n * the offer IQ which may carry the WebSocket URL for the 'websocket'\r\n * BridgeChannel mode.\r\n * @param {TraceablePeerConnection} pc the peer connection which will be used\r\n * to listen for new WebRTC Data Channels (in the 'datachannel' mode).\r\n */\r\nJitsiConference.prototype._setBridgeChannel = function(offerIq, pc) {\r\n    let wsUrl = null;\r\n    const webSocket\r\n        = $(offerIq)\r\n            .find('>content>transport>web-socket')\r\n            .first();\r\n\r\n    if (webSocket.length === 1) {\r\n        wsUrl = webSocket[0].getAttribute('url');\r\n    }\r\n\r\n    if (wsUrl) {\r\n        // If the offer contains a websocket use it.\r\n        this.rtc.initializeBridgeChannel(null, wsUrl);\r\n    } else {\r\n        // Otherwise, fall back to an attempt to use SCTP.\r\n        this.rtc.initializeBridgeChannel(pc, null);\r\n    }\r\n};\r\n\r\n/**\r\n * Rejects incoming Jingle call.\r\n * @param {JingleSessionPC} jingleSession the session instance to be rejected.\r\n * @param {object} [options]\r\n * @param {string} options.reason the name of the reason element as defined\r\n * by Jingle\r\n * @param {string} options.reasonDescription the reason description which will\r\n * be included in Jingle 'session-terminate' message.\r\n * @param {string} options.errorMsg an error message to be logged on global\r\n * error handler\r\n * @private\r\n */\r\nJitsiConference.prototype._rejectIncomingCall = function(jingleSession, options) {\r\n    if (options?.errorMsg) {\r\n        logger.warn(options.errorMsg);\r\n    }\r\n\r\n    // Terminate the jingle session with a reason\r\n    jingleSession.terminate(\r\n        null /* success callback => we don't care */,\r\n        error => {\r\n            logger.warn(\r\n                'An error occurred while trying to terminate'\r\n                    + ' invalid Jingle session', error);\r\n        }, {\r\n            reason: options && options.reason,\r\n            reasonDescription: options && options.reasonDescription,\r\n            sendSessionTerminate: true\r\n        });\r\n};\r\n\r\n/**\r\n * Handles the call ended event.\r\n * XXX is this due to the remote side terminating the Jingle session?\r\n *\r\n * @param {JingleSessionPC} jingleSession the jingle session which has been\r\n * terminated.\r\n * @param {String} reasonCondition the Jingle reason condition.\r\n * @param {String|null} reasonText human readable reason text which may provide\r\n * more details about why the call has been terminated.\r\n */\r\nJitsiConference.prototype.onCallEnded = function(jingleSession, reasonCondition, reasonText) {\r\n    logger.info(\r\n        `Call ended: ${reasonCondition} - ${reasonText} P2P ?${\r\n            jingleSession.isP2P}`);\r\n    if (jingleSession === this.jvbJingleSession) {\r\n        this.wasStopped = true;\r\n\r\n        Statistics.sendAnalytics(\r\n            createJingleEvent(ACTION_JINGLE_TERMINATE, { p2p: false }));\r\n\r\n        // Stop the stats\r\n        if (this.statistics) {\r\n            this.statistics.stopRemoteStats(\r\n                this.jvbJingleSession.peerconnection);\r\n            logger.info('Stopping JVB CallStats');\r\n            this.statistics.stopCallStats(\r\n                this.jvbJingleSession.peerconnection);\r\n        }\r\n\r\n        // Current JVB JingleSession is no longer valid, so set it to null\r\n        this.jvbJingleSession = null;\r\n\r\n        // Let the RTC service do any cleanups\r\n        this.rtc.onCallEnded();\r\n    } else if (jingleSession === this.p2pJingleSession) {\r\n        const stopOptions = {};\r\n\r\n        // It's the responder who decides to enforce JVB mode, so that both\r\n        // initiator and responder are aware if it was intentional.\r\n        if (reasonCondition === 'decline' && reasonText === 'force JVB121') {\r\n            logger.info('In forced JVB 121 mode...');\r\n            Statistics.analytics.addPermanentProperties({ forceJvb121: true });\r\n        } else if (reasonCondition === 'connectivity-error'\r\n            && reasonText === 'ICE FAILED') {\r\n            // It can happen that the other peer detects ICE failed and\r\n            // terminates the session, before we get the event on our side.\r\n            // But we are able to parse the reason and mark it here.\r\n            Statistics.analytics.addPermanentProperties({ p2pFailed: true });\r\n        } else if (reasonCondition === 'success' && reasonText === 'restart') {\r\n            // When we are restarting media sessions we don't want to switch the tracks\r\n            // to the JVB just yet.\r\n            stopOptions.requestRestart = true;\r\n        }\r\n        this._stopP2PSession(stopOptions);\r\n    } else {\r\n        logger.error(\r\n            'Received onCallEnded for invalid session',\r\n            jingleSession.sid,\r\n            jingleSession.remoteJid,\r\n            reasonCondition,\r\n            reasonText);\r\n    }\r\n};\r\n\r\n/**\r\n * Handles the suspend detected event. Leaves the room and fires suspended.\r\n * @param {JingleSessionPC} jingleSession\r\n */\r\nJitsiConference.prototype.onSuspendDetected = function(jingleSession) {\r\n    if (!jingleSession.isP2P) {\r\n        this.leave();\r\n        this.eventEmitter.emit(JitsiConferenceEvents.SUSPEND_DETECTED);\r\n    }\r\n};\r\n\r\nJitsiConference.prototype.updateDTMFSupport = function() {\r\n    let somebodySupportsDTMF = false;\r\n    const participants = this.getParticipants();\r\n\r\n    // check if at least 1 participant supports DTMF\r\n    for (let i = 0; i < participants.length; i += 1) {\r\n        if (participants[i].supportsDTMF()) {\r\n            somebodySupportsDTMF = true;\r\n            break;\r\n        }\r\n    }\r\n    if (somebodySupportsDTMF !== this.somebodySupportsDTMF) {\r\n        this.somebodySupportsDTMF = somebodySupportsDTMF;\r\n        this.eventEmitter.emit(\r\n            JitsiConferenceEvents.DTMF_SUPPORT_CHANGED,\r\n            somebodySupportsDTMF);\r\n    }\r\n};\r\n\r\n/**\r\n * Allows to check if there is at least one user in the conference\r\n * that supports DTMF.\r\n * @returns {boolean} true if somebody supports DTMF, false otherwise\r\n */\r\nJitsiConference.prototype.isDTMFSupported = function() {\r\n    return this.somebodySupportsDTMF;\r\n};\r\n\r\n/**\r\n * Returns the local user's ID\r\n * @return {string} local user's ID\r\n */\r\nJitsiConference.prototype.myUserId = function() {\r\n    return (\r\n        this.room && this.room.myroomjid\r\n            ? Strophe.getResourceFromJid(this.room.myroomjid)\r\n            : null);\r\n};\r\n\r\nJitsiConference.prototype.sendTones = function(tones, duration, pause) {\r\n    const peerConnection = this.getActivePeerConnection();\r\n\r\n    if (peerConnection) {\r\n        peerConnection.sendTones(tones, duration, pause);\r\n    } else {\r\n        logger.warn('cannot sendTones: no peer connection');\r\n    }\r\n};\r\n\r\n/**\r\n * Starts recording the current conference.\r\n *\r\n * @param {Object} options - Configuration for the recording. See\r\n * {@link Chatroom#startRecording} for more info.\r\n * @returns {Promise} See {@link Chatroom#startRecording} for more info.\r\n */\r\nJitsiConference.prototype.startRecording = function(options) {\r\n    if (this.room) {\r\n        return this.recordingManager.startRecording(options);\r\n    }\r\n\r\n    return Promise.reject(new Error('The conference is not created yet!'));\r\n};\r\n\r\n/**\r\n * Stop a recording session.\r\n *\r\n * @param {string} sessionID - The ID of the recording session that\r\n * should be stopped.\r\n * @returns {Promise} See {@link Chatroom#stopRecording} for more info.\r\n */\r\nJitsiConference.prototype.stopRecording = function(sessionID) {\r\n    if (this.room) {\r\n        return this.recordingManager.stopRecording(sessionID);\r\n    }\r\n\r\n    return Promise.reject(new Error('The conference is not created yet!'));\r\n};\r\n\r\n/**\r\n * Returns true if the SIP calls are supported and false otherwise\r\n */\r\nJitsiConference.prototype.isSIPCallingSupported = function() {\r\n    if (this.room) {\r\n        return this.room.isSIPCallingSupported();\r\n    }\r\n\r\n    return false;\r\n};\r\n\r\n/**\r\n * Dials a number.\r\n * @param number the number\r\n */\r\nJitsiConference.prototype.dial = function(number) {\r\n    if (this.room) {\r\n        return this.room.dial(number);\r\n    }\r\n\r\n    return new Promise((resolve, reject) => {\r\n        reject(new Error('The conference is not created yet!'));\r\n    });\r\n};\r\n\r\n/**\r\n * Hangup an existing call\r\n */\r\nJitsiConference.prototype.hangup = function() {\r\n    if (this.room) {\r\n        return this.room.hangup();\r\n    }\r\n\r\n    return new Promise((resolve, reject) => {\r\n        reject(new Error('The conference is not created yet!'));\r\n    });\r\n};\r\n\r\n/**\r\n * Starts the transcription service.\r\n */\r\nJitsiConference.prototype.startTranscriber = function() {\r\n    return this.dial('jitsi_meet_transcribe');\r\n};\r\n\r\n\r\n/**\r\n * Stops the transcription service.\r\n */\r\nJitsiConference.prototype.stopTranscriber = JitsiConference.prototype.hangup;\r\n\r\n/**\r\n * Returns the phone number for joining the conference.\r\n */\r\nJitsiConference.prototype.getPhoneNumber = function() {\r\n    if (this.room) {\r\n        return this.room.getPhoneNumber();\r\n    }\r\n\r\n    return null;\r\n};\r\n\r\n/**\r\n * Returns the pin for joining the conference with phone.\r\n */\r\nJitsiConference.prototype.getPhonePin = function() {\r\n    if (this.room) {\r\n        return this.room.getPhonePin();\r\n    }\r\n\r\n    return null;\r\n};\r\n\r\n/**\r\n * Returns the meeting unique ID if any.\r\n *\r\n * @returns {string|undefined}\r\n */\r\nJitsiConference.prototype.getMeetingUniqueId = function() {\r\n    if (this.room) {\r\n        return this.room.getMeetingId();\r\n    }\r\n};\r\n\r\n/**\r\n * Will return P2P or JVB <tt>TraceablePeerConnection</tt> depending on\r\n * which connection is currently active.\r\n *\r\n * @return {TraceablePeerConnection|null} null if there isn't any active\r\n * <tt>TraceablePeerConnection</tt> currently available.\r\n * @public (FIXME how to make package local ?)\r\n */\r\nJitsiConference.prototype.getActivePeerConnection = function() {\r\n    const session = this.isP2PActive() ? this.p2pJingleSession : this.jvbJingleSession;\r\n\r\n    return session ? session.peerconnection : null;\r\n};\r\n\r\n/**\r\n * Returns the connection state for the current room. Its ice connection state\r\n * for its session.\r\n * NOTE that \"completed\" ICE state which can appear on the P2P connection will\r\n * be converted to \"connected\".\r\n * @return {string|null} ICE state name or <tt>null</tt> if there is no active\r\n * peer connection at this time.\r\n */\r\nJitsiConference.prototype.getConnectionState = function() {\r\n    const peerConnection = this.getActivePeerConnection();\r\n\r\n    return peerConnection ? peerConnection.getConnectionState() : null;\r\n};\r\n\r\n/**\r\n * Make all new participants mute their audio/video on join.\r\n * @param policy {Object} object with 2 boolean properties for video and audio:\r\n * @param {boolean} audio if audio should be muted.\r\n * @param {boolean} video if video should be muted.\r\n */\r\nJitsiConference.prototype.setStartMutedPolicy = function(policy) {\r\n    if (!this.isModerator()) {\r\n        logger.warn(`Failed to set start muted policy, ${this.room ? '' : 'not in a room, '}${\r\n            this.isModerator() ? '' : 'participant is not a moderator'}`);\r\n\r\n        return;\r\n    }\r\n    this.startMutedPolicy = policy;\r\n    this.room.addOrReplaceInPresence('startmuted', {\r\n        attributes: {\r\n            audio: policy.audio,\r\n            video: policy.video,\r\n            xmlns: 'http://jitsi.org/jitmeet/start-muted'\r\n        }\r\n    }) && this.room.sendPresence();\r\n};\r\n\r\n/**\r\n * Returns current start muted policy\r\n * @returns {Object} with 2 properties - audio and video.\r\n */\r\nJitsiConference.prototype.getStartMutedPolicy = function() {\r\n    return this.startMutedPolicy;\r\n};\r\n\r\n/**\r\n * Check if audio is muted on join.\r\n */\r\nJitsiConference.prototype.isStartAudioMuted = function() {\r\n    return this.startAudioMuted;\r\n};\r\n\r\n/**\r\n * Check if video is muted on join.\r\n */\r\nJitsiConference.prototype.isStartVideoMuted = function() {\r\n    return this.startVideoMuted;\r\n};\r\n\r\n/**\r\n * Returns measured connectionTimes.\r\n */\r\nJitsiConference.prototype.getConnectionTimes = function() {\r\n    return this.room.connectionTimes;\r\n};\r\n\r\n/**\r\n * Sets a property for the local participant.\r\n */\r\nJitsiConference.prototype.setLocalParticipantProperty = function(name, value) {\r\n    this.sendCommand(`jitsi_participant_${name}`, { value });\r\n};\r\n\r\n/**\r\n *  Removes a property for the local participant and sends the updated presence.\r\n */\r\nJitsiConference.prototype.removeLocalParticipantProperty = function(name) {\r\n    this.removeCommand(`jitsi_participant_${name}`);\r\n    this.room.sendPresence();\r\n};\r\n\r\n/**\r\n * Gets a local participant property.\r\n *\r\n * @return value of the local participant property if the tagName exists in the\r\n * list of properties, otherwise returns undefined.\r\n */\r\nJitsiConference.prototype.getLocalParticipantProperty = function(name) {\r\n    const property = this.room.presMap.nodes.find(prop =>\r\n        prop.tagName === `jitsi_participant_${name}`\r\n    );\r\n\r\n    return property ? property.value : undefined;\r\n};\r\n\r\n/**\r\n * Sends the given feedback through CallStats if enabled.\r\n *\r\n * @param overallFeedback an integer between 1 and 5 indicating the\r\n * user feedback\r\n * @param detailedFeedback detailed feedback from the user. Not yet used\r\n * @returns {Promise} Resolves if feedback is submitted successfully.\r\n */\r\nJitsiConference.prototype.sendFeedback = function(overallFeedback, detailedFeedback) {\r\n    return this.statistics.sendFeedback(overallFeedback, detailedFeedback);\r\n};\r\n\r\n/**\r\n * Returns true if the callstats integration is enabled, otherwise returns\r\n * false.\r\n *\r\n * @returns true if the callstats integration is enabled, otherwise returns\r\n * false.\r\n */\r\nJitsiConference.prototype.isCallstatsEnabled = function() {\r\n    return this.statistics.isCallstatsEnabled();\r\n};\r\n\r\n/**\r\n * Finds the SSRC of a given track\r\n *\r\n * @param track\r\n * @returns {number|undefined} the SSRC of the specificed track, otherwise undefined.\r\n */\r\nJitsiConference.prototype.getSsrcByTrack = function(track) {\r\n    return track.isLocal() ? this.getActivePeerConnection()?.getLocalSSRC(track) : track.getSSRC();\r\n};\r\n\r\n/**\r\n * Handles track attached to container (Calls associateStreamWithVideoTag method\r\n * from statistics module)\r\n * @param {JitsiLocalTrack|JitsiRemoteTrack} track the track\r\n * @param container the container\r\n */\r\nJitsiConference.prototype._onTrackAttach = function(track, container) {\r\n    const isLocal = track.isLocal();\r\n    let ssrc = null;\r\n    const isP2P = track.isP2P;\r\n    const remoteUserId = isP2P ? track.getParticipantId() : 'jitsi';\r\n    const peerConnection\r\n        = isP2P\r\n            ? this.p2pJingleSession && this.p2pJingleSession.peerconnection\r\n            : this.jvbJingleSession && this.jvbJingleSession.peerconnection;\r\n\r\n    if (isLocal) {\r\n        // Local tracks have SSRC stored on per peer connection basis.\r\n        if (peerConnection) {\r\n            ssrc = peerConnection.getLocalSSRC(track);\r\n        }\r\n    } else {\r\n        ssrc = track.getSSRC();\r\n    }\r\n    if (!container.id || !ssrc || !peerConnection) {\r\n        return;\r\n    }\r\n\r\n    this.statistics.associateStreamWithVideoTag(\r\n        peerConnection,\r\n        ssrc,\r\n        isLocal,\r\n        remoteUserId,\r\n        track.getUsageLabel(),\r\n        container.id);\r\n};\r\n\r\n/**\r\n * Logs an \"application log\" message.\r\n * @param message {string} The message to log. Note that while this can be a\r\n * generic string, the convention used by lib-jitsi-meet and jitsi-meet is to\r\n * log valid JSON strings, with an \"id\" field used for distinguishing between\r\n * message types. E.g.: {id: \"recorder_status\", status: \"off\"}\r\n */\r\nJitsiConference.prototype.sendApplicationLog = function(message) {\r\n    Statistics.sendLog(message);\r\n};\r\n\r\n/**\r\n * Checks if the user identified by given <tt>mucJid</tt> is the conference focus.\r\n * @param mucJid the full MUC address of the user to be checked.\r\n * @returns {boolean|null} <tt>true</tt> if MUC user is the conference focus,\r\n * <tt>false</tt> when is not. <tt>null</tt> if we're not in the MUC anymore and\r\n * are unable to figure out the status or if given <tt>mucJid</tt> is invalid.\r\n */\r\nJitsiConference.prototype.isFocus = function(mucJid) {\r\n    return this.room ? this.room.isFocus(mucJid) : null;\r\n};\r\n\r\n/**\r\n * Fires CONFERENCE_FAILED event with INCOMPATIBLE_SERVER_VERSIONS parameter\r\n */\r\nJitsiConference.prototype._fireIncompatibleVersionsEvent = function() {\r\n    this.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\r\n        JitsiConferenceErrors.INCOMPATIBLE_SERVER_VERSIONS);\r\n};\r\n\r\n/**\r\n * Sends a message via the data channel.\r\n * @param to {string} the id of the endpoint that should receive the message.\r\n * If \"\" the message will be sent to all participants.\r\n * @param payload {object} the payload of the message.\r\n * @throws NetworkError or InvalidStateError or Error if the operation fails.\r\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\r\n */\r\nJitsiConference.prototype.sendEndpointMessage = function(to, payload) {\r\n    this.rtc.sendChannelMessage(to, payload);\r\n};\r\n\r\n/**\r\n * Sends local stats via the bridge channel which then forwards to other endpoints selectively.\r\n * @param {Object} payload The payload of the message.\r\n * @throws NetworkError/InvalidStateError/Error if the operation fails or if there is no data channel created.\r\n */\r\nJitsiConference.prototype.sendEndpointStatsMessage = function(payload) {\r\n    this.rtc.sendEndpointStatsMessage(payload);\r\n};\r\n\r\n/**\r\n * Sends a broadcast message via the data channel.\r\n * @param payload {object} the payload of the message.\r\n * @throws NetworkError or InvalidStateError or Error if the operation fails.\r\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\r\n */\r\nJitsiConference.prototype.broadcastEndpointMessage = function(payload) {\r\n    this.sendEndpointMessage('', payload);\r\n};\r\n\r\n/**\r\n * Sends a message to a given endpoint (if 'to' is a non-empty string), or\r\n * broadcasts it to all endpoints in the conference.\r\n * @param {string} to The ID of the endpoint/participant which is to receive\r\n * the message, or '' to broadcast the message to all endpoints in the\r\n * conference.\r\n * @param {string|object} message the message to send. If this is of type\r\n * 'string' it will be sent as a chat message. If it is of type 'object', it\r\n * will be encapsulated in a format recognized by jitsi-meet and converted to\r\n * JSON before being sent.\r\n * @param {boolean} sendThroughVideobridge Whether to send the message through\r\n * jitsi-videobridge (via the COLIBRI data channel or web socket), or through\r\n * the XMPP MUC. Currently only objects can be sent through jitsi-videobridge.\r\n */\r\nJitsiConference.prototype.sendMessage = function(message, to = '', sendThroughVideobridge = false) {\r\n    const messageType = typeof message;\r\n\r\n    // Through videobridge we support only objects. Through XMPP we support\r\n    // objects (encapsulated in a specific JSON format) and strings (i.e.\r\n    // regular chat messages).\r\n    if (messageType !== 'object'\r\n            && (sendThroughVideobridge || messageType !== 'string')) {\r\n        logger.error(`Can not send a message of type ${messageType}`);\r\n\r\n        return;\r\n    }\r\n\r\n    if (sendThroughVideobridge) {\r\n        this.sendEndpointMessage(to, message);\r\n    } else {\r\n        let messageToSend = message;\r\n\r\n        // Name of packet extension of message stanza to send the required\r\n        // message in.\r\n        let elementName = 'body';\r\n\r\n        if (messageType === 'object') {\r\n            elementName = 'json-message';\r\n\r\n            // Mark as valid JSON message if not already\r\n            if (!messageToSend.hasOwnProperty(JITSI_MEET_MUC_TYPE)) {\r\n                messageToSend[JITSI_MEET_MUC_TYPE] = '';\r\n            }\r\n\r\n            try {\r\n                messageToSend = JSON.stringify(messageToSend);\r\n            } catch (e) {\r\n                logger.error('Can not send a message, stringify failed: ', e);\r\n\r\n                return;\r\n            }\r\n        }\r\n\r\n        if (to) {\r\n            this.sendPrivateTextMessage(to, messageToSend, elementName);\r\n        } else {\r\n            // Broadcast\r\n            this.sendTextMessage(messageToSend, elementName);\r\n        }\r\n    }\r\n\r\n};\r\n\r\nJitsiConference.prototype.isConnectionInterrupted = function() {\r\n    return this.isP2PActive()\r\n        ? this.isP2PConnectionInterrupted : this.isJvbConnectionInterrupted;\r\n};\r\n\r\n/**\r\n * Handles {@link XMPPEvents.CONNECTION_RESTARTED} event. This happens when the bridge goes down\r\n * and Jicofo moves conferences away to a different bridge.\r\n * @param {JingleSessionPC} session\r\n * @private\r\n */\r\nJitsiConference.prototype._onConferenceRestarted = function(session) {\r\n    if (!session.isP2P && this.options.config.enableForcedReload) {\r\n        this.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED, JitsiConferenceErrors.CONFERENCE_RESTARTED);\r\n    }\r\n};\r\n\r\n/**\r\n * Handles {@link XMPPEvents.CONNECTION_INTERRUPTED}\r\n * @param {JingleSessionPC} session\r\n * @private\r\n */\r\nJitsiConference.prototype._onIceConnectionInterrupted = function(session) {\r\n    if (session.isP2P) {\r\n        this.isP2PConnectionInterrupted = true;\r\n    } else {\r\n        this.isJvbConnectionInterrupted = true;\r\n    }\r\n    if (session.isP2P === this.isP2PActive()) {\r\n        this.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_INTERRUPTED);\r\n    }\r\n};\r\n\r\n/**\r\n * Handles {@link XMPPEvents.CONNECTION_ICE_FAILED}\r\n * @param {JingleSessionPC} session\r\n * @private\r\n */\r\nJitsiConference.prototype._onIceConnectionFailed = function(session) {\r\n    // We do nothing for the JVB connection, because it's up to the Jicofo to\r\n    // eventually come up with the new offer (at least for the time being).\r\n    if (session.isP2P) {\r\n        // Add p2pFailed property to analytics to distinguish, between \"good\"\r\n        // and \"bad\" connection\r\n        Statistics.analytics.addPermanentProperties({ p2pFailed: true });\r\n\r\n        if (this.p2pJingleSession) {\r\n            Statistics.sendAnalyticsAndLog(\r\n                createP2PEvent(\r\n                    ACTION_P2P_FAILED,\r\n                    {\r\n                        initiator: this.p2pJingleSession.isInitiator\r\n                    }));\r\n\r\n        }\r\n        this._stopP2PSession({\r\n            reason: 'connectivity-error',\r\n            reasonDescription: 'ICE FAILED'\r\n        });\r\n    } else if (session && this.jvbJingleSession === session) {\r\n        this._delayedIceFailed = new IceFailedHandling(this);\r\n        this._delayedIceFailed.start(session);\r\n    }\r\n};\r\n\r\n/**\r\n * Handles {@link XMPPEvents.CONNECTION_RESTORED}\r\n * @param {JingleSessionPC} session\r\n * @private\r\n */\r\nJitsiConference.prototype._onIceConnectionRestored = function(session) {\r\n    if (session.isP2P) {\r\n        this.isP2PConnectionInterrupted = false;\r\n    } else {\r\n        this.isJvbConnectionInterrupted = false;\r\n        this._delayedIceFailed && this._delayedIceFailed.cancel();\r\n    }\r\n\r\n    if (session.isP2P === this.isP2PActive()) {\r\n        this.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_RESTORED);\r\n    }\r\n};\r\n\r\n/**\r\n * Accept incoming P2P Jingle call.\r\n * @param {JingleSessionPC} jingleSession the session instance\r\n * @param {jQuery} jingleOffer a jQuery selector pointing to 'jingle' IQ element\r\n * @private\r\n */\r\nJitsiConference.prototype._acceptP2PIncomingCall = function(jingleSession, jingleOffer) {\r\n    this.isP2PConnectionInterrupted = false;\r\n\r\n    // Accept the offer\r\n    this.p2pJingleSession = jingleSession;\r\n    this._sendConferenceJoinAnalyticsEvent();\r\n\r\n    this.p2pJingleSession.initialize(\r\n        this.room,\r\n        this.rtc,\r\n        this._signalingLayer,\r\n        {\r\n            ...this.options.config,\r\n            enableInsertableStreams: this.isE2EEEnabled()\r\n        });\r\n\r\n    logger.info('Starting CallStats for P2P connection...');\r\n\r\n    let remoteID = Strophe.getResourceFromJid(this.p2pJingleSession.remoteJid);\r\n\r\n    const participant = this.participants[remoteID];\r\n\r\n    if (participant) {\r\n        remoteID = participant.getStatsID() || remoteID;\r\n    }\r\n\r\n    this.statistics.startCallStats(\r\n        this.p2pJingleSession.peerconnection,\r\n        remoteID);\r\n\r\n    const localTracks = this.getLocalTracks();\r\n\r\n    this.p2pJingleSession.acceptOffer(\r\n        jingleOffer,\r\n        () => {\r\n            logger.debug('Got RESULT for P2P \"session-accept\"');\r\n\r\n            this.eventEmitter.emit(\r\n                JitsiConferenceEvents._MEDIA_SESSION_STARTED,\r\n                jingleSession);\r\n        },\r\n        error => {\r\n            logger.error(\r\n                'Failed to accept incoming P2P Jingle session', error);\r\n        },\r\n        localTracks);\r\n};\r\n\r\n/**\r\n * Adds remote tracks to the conference associated with the JVB session.\r\n * @private\r\n */\r\nJitsiConference.prototype._addRemoteJVBTracks = function() {\r\n    this._addRemoteTracks('JVB', this.jvbJingleSession.peerconnection.getRemoteTracks());\r\n};\r\n\r\n/**\r\n * Adds remote tracks to the conference associated with the P2P session.\r\n * @private\r\n */\r\nJitsiConference.prototype._addRemoteP2PTracks = function() {\r\n    this._addRemoteTracks('P2P', this.p2pJingleSession.peerconnection.getRemoteTracks());\r\n};\r\n\r\n/**\r\n * Generates fake \"remote track added\" events for given Jingle session.\r\n * @param {string} logName the session's nickname which will appear in log\r\n * messages.\r\n * @param {Array<JitsiRemoteTrack>} remoteTracks the tracks that will be added\r\n * @private\r\n */\r\nJitsiConference.prototype._addRemoteTracks = function(logName, remoteTracks) {\r\n    for (const track of remoteTracks) {\r\n        logger.info(`Adding remote ${logName} track: ${track}`);\r\n        this.onRemoteTrackAdded(track);\r\n    }\r\n};\r\n\r\n/**\r\n * Called when {@link XMPPEvents.CONNECTION_ESTABLISHED} event is\r\n * triggered for a {@link JingleSessionPC}. Switches the conference to use\r\n * the P2P connection if the event comes from the P2P session.\r\n * @param {JingleSessionPC} jingleSession the session instance.\r\n * @private\r\n */\r\nJitsiConference.prototype._onIceConnectionEstablished = function(jingleSession) {\r\n    if (this.p2pJingleSession !== null) {\r\n        // store the establishment time of the p2p session as a field of the\r\n        // JitsiConference because the p2pJingleSession might get disposed (thus\r\n        // the value is lost).\r\n        this.p2pEstablishmentDuration\r\n            = this.p2pJingleSession.establishmentDuration;\r\n    }\r\n\r\n    if (this.jvbJingleSession !== null) {\r\n        this.jvbEstablishmentDuration\r\n            = this.jvbJingleSession.establishmentDuration;\r\n    }\r\n\r\n    let done = false;\r\n    const forceJVB121Ratio = this.options.config.forceJVB121Ratio;\r\n\r\n    // We don't care about the JVB case, there's nothing to be done\r\n    if (!jingleSession.isP2P) {\r\n        done = true;\r\n    } else if (this.p2pJingleSession !== jingleSession) {\r\n        logger.error('CONNECTION_ESTABLISHED - wrong P2P session instance ?!');\r\n\r\n        done = true;\r\n    } else if (!jingleSession.isInitiator\r\n        && typeof forceJVB121Ratio === 'number'\r\n        && Math.random() < forceJVB121Ratio) {\r\n        logger.info(`Forcing JVB 121 mode (ratio=${forceJVB121Ratio})...`);\r\n        Statistics.analytics.addPermanentProperties({ forceJvb121: true });\r\n        this._stopP2PSession({\r\n            reason: 'decline',\r\n            reasonDescription: 'force JVB121'\r\n        });\r\n\r\n        done = true;\r\n    }\r\n\r\n    if (!isNaN(this.p2pEstablishmentDuration)\r\n        && !isNaN(this.jvbEstablishmentDuration)) {\r\n        const establishmentDurationDiff\r\n            = this.p2pEstablishmentDuration - this.jvbEstablishmentDuration;\r\n\r\n        Statistics.sendAnalytics(\r\n            ICE_ESTABLISHMENT_DURATION_DIFF,\r\n            { value: establishmentDurationDiff });\r\n    }\r\n\r\n    if (jingleSession.isP2P === this.isP2PActive()) {\r\n        this.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_ESTABLISHED);\r\n    }\r\n\r\n    if (done) {\r\n\r\n        return;\r\n    }\r\n\r\n    // Update P2P status and emit events\r\n    this._setP2PStatus(true);\r\n\r\n    // Remove remote tracks\r\n    if (this.jvbJingleSession) {\r\n        this._removeRemoteJVBTracks();\r\n    } else {\r\n        logger.info('Not removing remote JVB tracks - no session yet');\r\n    }\r\n\r\n    this._addRemoteP2PTracks();\r\n\r\n    // Stop media transfer over the JVB connection\r\n    if (this.jvbJingleSession) {\r\n        this._suspendMediaTransferForJvbConnection();\r\n    }\r\n\r\n    logger.info('Starting remote stats with p2p connection');\r\n    this.statistics.startRemoteStats(this.p2pJingleSession.peerconnection);\r\n\r\n    Statistics.sendAnalyticsAndLog(\r\n        createP2PEvent(\r\n            ACTION_P2P_ESTABLISHED,\r\n            {\r\n                initiator: this.p2pJingleSession.isInitiator\r\n            }));\r\n\r\n};\r\n\r\n/**\r\n * Called when the chat room reads a new list of properties from jicofo's\r\n * presence. The properties may have changed, but they don't have to.\r\n *\r\n * @param {Object} properties - The properties keyed by the property name\r\n * ('key').\r\n * @private\r\n */\r\nJitsiConference.prototype._updateProperties = function(properties = {}) {\r\n    const changed = !isEqual(properties, this.properties);\r\n\r\n    this.properties = properties;\r\n    if (changed) {\r\n        this.eventEmitter.emit(JitsiConferenceEvents.PROPERTIES_CHANGED, this.properties);\r\n\r\n        const audioLimitReached = this.properties['audio-limit-reached'] === 'true';\r\n        const videoLimitReached = this.properties['video-limit-reached'] === 'true';\r\n\r\n        if (this._audioSenderLimitReached !== audioLimitReached) {\r\n            this._audioSenderLimitReached = audioLimitReached;\r\n            this.eventEmitter.emit(JitsiConferenceEvents.AUDIO_UNMUTE_PERMISSIONS_CHANGED, audioLimitReached);\r\n            logger.info(`Audio unmute permissions set by Jicofo to ${audioLimitReached}`);\r\n        }\r\n\r\n        if (this._videoSenderLimitReached !== videoLimitReached) {\r\n            this._videoSenderLimitReached = videoLimitReached;\r\n            this.eventEmitter.emit(JitsiConferenceEvents.VIDEO_UNMUTE_PERMISSIONS_CHANGED, videoLimitReached);\r\n            logger.info(`Video unmute permissions set by Jicofo to ${videoLimitReached}`);\r\n        }\r\n\r\n        // Some of the properties need to be added to analytics events.\r\n        const analyticsKeys = [\r\n\r\n            // The number of jitsi-videobridge instances currently used for the\r\n            // conference.\r\n            'bridge-count',\r\n\r\n            // The conference creation time (set by jicofo).\r\n            'created-ms'\r\n        ];\r\n\r\n        analyticsKeys.forEach(key => {\r\n            if (properties[key] !== undefined) {\r\n                Statistics.analytics.addPermanentProperties({\r\n                    [key.replace('-', '_')]: properties[key]\r\n                });\r\n            }\r\n        });\r\n    }\r\n};\r\n\r\n/**\r\n * Gets a conference property with a given key.\r\n *\r\n * @param {string} key - The key.\r\n * @returns {*} The value\r\n */\r\nJitsiConference.prototype.getProperty = function(key) {\r\n    return this.properties[key];\r\n};\r\n\r\n/**\r\n * Clears the deferred start P2P task if it has been scheduled.\r\n * @private\r\n */\r\nJitsiConference.prototype._maybeClearDeferredStartP2P = function() {\r\n    if (this.deferredStartP2PTask) {\r\n        logger.info('Cleared deferred start P2P task');\r\n        clearTimeout(this.deferredStartP2PTask);\r\n        this.deferredStartP2PTask = null;\r\n    }\r\n};\r\n\r\n/**\r\n * Removes from the conference remote tracks associated with the JVB\r\n * connection.\r\n * @private\r\n */\r\nJitsiConference.prototype._removeRemoteJVBTracks = function() {\r\n    this._removeRemoteTracks(\r\n        'JVB', this.jvbJingleSession.peerconnection.getRemoteTracks());\r\n};\r\n\r\n/**\r\n * Removes from the conference remote tracks associated with the P2P\r\n * connection.\r\n * @private\r\n */\r\nJitsiConference.prototype._removeRemoteP2PTracks = function() {\r\n    this._removeRemoteTracks(\r\n        'P2P', this.p2pJingleSession.peerconnection.getRemoteTracks());\r\n};\r\n\r\n/**\r\n * Generates fake \"remote track removed\" events for given Jingle session.\r\n * @param {string} sessionNickname the session's nickname which will appear in\r\n * log messages.\r\n * @param {Array<JitsiRemoteTrack>} remoteTracks the tracks that will be removed\r\n * @private\r\n */\r\nJitsiConference.prototype._removeRemoteTracks = function(sessionNickname, remoteTracks) {\r\n    for (const track of remoteTracks) {\r\n        logger.info(`Removing remote ${sessionNickname} track: ${track}`);\r\n        this.onRemoteTrackRemoved(track);\r\n    }\r\n};\r\n\r\n/**\r\n * Resumes media transfer over the JVB connection.\r\n * @private\r\n */\r\nJitsiConference.prototype._resumeMediaTransferForJvbConnection = function() {\r\n    logger.info('Resuming media transfer over the JVB connection...');\r\n    this.jvbJingleSession.setMediaTransferActive(true, true).then(\r\n        () => {\r\n            logger.info('Resumed media transfer over the JVB connection!');\r\n        },\r\n        error => {\r\n            logger.error(\r\n                'Failed to resume media transfer over the JVB connection:',\r\n                error);\r\n        });\r\n};\r\n\r\n/**\r\n * Sets new P2P status and updates some events/states hijacked from\r\n * the <tt>JitsiConference</tt>.\r\n * @param {boolean} newStatus the new P2P status value, <tt>true</tt> means that\r\n * P2P is now in use, <tt>false</tt> means that the JVB connection is now in use\r\n * @private\r\n */\r\nJitsiConference.prototype._setP2PStatus = function(newStatus) {\r\n    if (this.p2p === newStatus) {\r\n        logger.debug(`Called _setP2PStatus with the same status: ${newStatus}`);\r\n\r\n        return;\r\n    }\r\n    this.p2p = newStatus;\r\n    if (newStatus) {\r\n        logger.info('Peer to peer connection established!');\r\n\r\n        // When we end up in a valid P2P session need to reset the properties\r\n        // in case they have persisted, after session with another peer.\r\n        Statistics.analytics.addPermanentProperties({\r\n            p2pFailed: false,\r\n            forceJvb121: false\r\n        });\r\n\r\n        // Sync up video transfer active in case p2pJingleSession not existed\r\n        // when the lastN value was being adjusted.\r\n        const isVideoActive = this.getLastN() !== 0;\r\n\r\n        this.p2pJingleSession\r\n            .setMediaTransferActive(true, isVideoActive)\r\n            .catch(error => {\r\n                logger.error(\r\n                    'Failed to sync up P2P video transfer status'\r\n                        + `(${isVideoActive})`, error);\r\n            });\r\n    } else {\r\n        logger.info('Peer to peer connection closed!');\r\n    }\r\n\r\n    // Put the JVB connection on hold/resume\r\n    if (this.jvbJingleSession) {\r\n        this.statistics.sendConnectionResumeOrHoldEvent(\r\n            this.jvbJingleSession.peerconnection, !newStatus);\r\n    }\r\n\r\n    // Clear dtmfManager, so that it can be recreated with new connection\r\n    this.dtmfManager = null;\r\n\r\n    // Update P2P status\r\n    this.eventEmitter.emit(\r\n        JitsiConferenceEvents.P2P_STATUS,\r\n        this,\r\n        this.p2p);\r\n    this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED, this.getActiveMediaSession());\r\n\r\n    // Refresh connection interrupted/restored\r\n    this.eventEmitter.emit(\r\n        this.isConnectionInterrupted()\r\n            ? JitsiConferenceEvents.CONNECTION_INTERRUPTED\r\n            : JitsiConferenceEvents.CONNECTION_RESTORED);\r\n};\r\n\r\n/**\r\n * Starts new P2P session.\r\n * @param {string} remoteJid the JID of the remote participant\r\n * @private\r\n */\r\nJitsiConference.prototype._startP2PSession = function(remoteJid) {\r\n    this._maybeClearDeferredStartP2P();\r\n    if (this.p2pJingleSession) {\r\n        logger.error('P2P session already started!');\r\n\r\n        return;\r\n    }\r\n\r\n    this.isP2PConnectionInterrupted = false;\r\n    this.p2pJingleSession\r\n        = this.xmpp.connection.jingle.newP2PJingleSession(\r\n            this.room.myroomjid,\r\n            remoteJid);\r\n    logger.info(\r\n        'Created new P2P JingleSession', this.room.myroomjid, remoteJid);\r\n    this._sendConferenceJoinAnalyticsEvent();\r\n\r\n    this.p2pJingleSession.initialize(\r\n        this.room,\r\n        this.rtc,\r\n        this._signalingLayer,\r\n        {\r\n            ...this.options.config,\r\n            enableInsertableStreams: this.isE2EEEnabled()\r\n        });\r\n\r\n    logger.info('Starting CallStats for P2P connection...');\r\n\r\n    let remoteID = Strophe.getResourceFromJid(this.p2pJingleSession.remoteJid);\r\n\r\n    const participant = this.participants[remoteID];\r\n\r\n    if (participant) {\r\n        remoteID = participant.getStatsID() || remoteID;\r\n    }\r\n\r\n    this.statistics.startCallStats(\r\n        this.p2pJingleSession.peerconnection,\r\n        remoteID);\r\n\r\n    const localTracks = this.getLocalTracks();\r\n\r\n    this.p2pJingleSession.invite(localTracks);\r\n};\r\n\r\n/**\r\n * Suspends media transfer over the JVB connection.\r\n * @private\r\n */\r\nJitsiConference.prototype._suspendMediaTransferForJvbConnection = function() {\r\n    logger.info('Suspending media transfer over the JVB connection...');\r\n    this.jvbJingleSession.setMediaTransferActive(false, false).then(\r\n        () => {\r\n            logger.info('Suspended media transfer over the JVB connection !');\r\n        },\r\n        error => {\r\n            logger.error(\r\n                'Failed to suspend media transfer over the JVB connection:',\r\n                error);\r\n        });\r\n};\r\n\r\n/**\r\n * Method when called will decide whether it's the time to start or stop\r\n * the P2P session.\r\n * @param {boolean} userLeftEvent if <tt>true</tt> it means that the call\r\n * originates from the user left event.\r\n * @private\r\n */\r\nJitsiConference.prototype._maybeStartOrStopP2P = function(userLeftEvent) {\r\n    if (!this.isP2PEnabled()\r\n            || this.isP2PTestModeEnabled()\r\n            || browser.isFirefox()\r\n            || browser.isWebKitBased()\r\n            || this.isE2EEEnabled()) {\r\n        logger.info('Auto P2P disabled');\r\n\r\n        return;\r\n    }\r\n    const peers = this.getParticipants();\r\n    const peerCount = peers.length;\r\n\r\n    // FIXME 1 peer and it must *support* P2P switching\r\n    const shouldBeInP2P = this._shouldBeInP2PMode();\r\n\r\n    // Clear deferred \"start P2P\" task\r\n    if (!shouldBeInP2P && this.deferredStartP2PTask) {\r\n        this._maybeClearDeferredStartP2P();\r\n    }\r\n\r\n    // Start peer to peer session\r\n    if (!this.p2pJingleSession && shouldBeInP2P) {\r\n        const peer = peerCount && peers[0];\r\n\r\n\r\n        const myId = this.myUserId();\r\n        const peersId = peer.getId();\r\n\r\n        if (myId > peersId) {\r\n            logger.debug(\r\n                'I\\'m the bigger peersId - '\r\n                + 'the other peer should start P2P', myId, peersId);\r\n\r\n            return;\r\n        } else if (myId === peersId) {\r\n            logger.error('The same IDs ? ', myId, peersId);\r\n\r\n            return;\r\n        }\r\n\r\n        const jid = peer.getJid();\r\n\r\n        if (userLeftEvent) {\r\n            if (this.deferredStartP2PTask) {\r\n                logger.error('Deferred start P2P task\\'s been set already!');\r\n\r\n                return;\r\n            }\r\n            logger.info(\r\n                `Will start P2P with: ${jid} after ${\r\n                    this.backToP2PDelay} seconds...`);\r\n            this.deferredStartP2PTask = setTimeout(\r\n                this._startP2PSession.bind(this, jid),\r\n                this.backToP2PDelay * 1000);\r\n        } else {\r\n            logger.info(`Will start P2P with: ${jid}`);\r\n            this._startP2PSession(jid);\r\n        }\r\n    } else if (this.p2pJingleSession && !shouldBeInP2P) {\r\n        logger.info(`Will stop P2P with: ${this.p2pJingleSession.remoteJid}`);\r\n\r\n        // Log that there will be a switch back to the JVB connection\r\n        if (this.p2pJingleSession.isInitiator && peerCount > 1) {\r\n            Statistics.sendAnalyticsAndLog(\r\n                createP2PEvent(ACTION_P2P_SWITCH_TO_JVB));\r\n        }\r\n        this._stopP2PSession();\r\n    }\r\n};\r\n\r\n/**\r\n * Tells whether or not this conference should be currently in the P2P mode.\r\n *\r\n * @private\r\n * @returns {boolean}\r\n */\r\nJitsiConference.prototype._shouldBeInP2PMode = function() {\r\n    const peers = this.getParticipants();\r\n    const peerCount = peers.length;\r\n    const hasBotPeer = peers.find(p => p.getBotType() === 'poltergeist' || p.hasFeature(FEATURE_JIGASI)) !== undefined;\r\n    const shouldBeInP2P = peerCount === 1 && !hasBotPeer;\r\n\r\n    logger.debug(`P2P? peerCount: ${peerCount}, hasBotPeer: ${hasBotPeer} => ${shouldBeInP2P}`);\r\n\r\n    return shouldBeInP2P;\r\n};\r\n\r\n/**\r\n * Stops the current P2P session.\r\n * @param {Object} options - Options for stopping P2P.\r\n * @param {string} options.reason - One of the Jingle \"reason\" element\r\n * names as defined by https://xmpp.org/extensions/xep-0166.html#def-reason\r\n * @param {string} options.reasonDescription - Text\r\n * description that will be included in the session terminate message\r\n * @param {boolean} requestRestart - Whether this is due to a session restart, in which case\r\n * media will not be resumed on the JVB.\r\n * @private\r\n */\r\nJitsiConference.prototype._stopP2PSession = function(options = {}) {\r\n    const {\r\n        reason = 'success',\r\n        reasonDescription = 'Turning off P2P session',\r\n        requestRestart = false\r\n    } = options;\r\n\r\n    if (!this.p2pJingleSession) {\r\n        logger.error('No P2P session to be stopped!');\r\n\r\n        return;\r\n    }\r\n\r\n    const wasP2PEstablished = this.isP2PActive();\r\n\r\n    // Swap remote tracks, but only if the P2P has been fully established\r\n    if (wasP2PEstablished) {\r\n        if (this.jvbJingleSession && !requestRestart) {\r\n            this._resumeMediaTransferForJvbConnection();\r\n        }\r\n\r\n        // Remove remote P2P tracks\r\n        this._removeRemoteP2PTracks();\r\n    }\r\n\r\n    // Stop P2P stats\r\n    logger.info('Stopping remote stats for P2P connection');\r\n    this.statistics.stopRemoteStats(this.p2pJingleSession.peerconnection);\r\n    logger.info('Stopping CallStats for P2P connection');\r\n    this.statistics.stopCallStats(this.p2pJingleSession.peerconnection);\r\n\r\n    this.p2pJingleSession.terminate(\r\n        () => {\r\n            logger.info('P2P session terminate RESULT');\r\n        },\r\n        error => {\r\n            // Because both initiator and responder are simultaneously\r\n            // terminating their JingleSessions in case of the 'to JVB switch'\r\n            // when 3rd participant joins, both will dispose their sessions and\r\n            // reply with 'item-not-found' (see strophe.jingle.js). We don't\r\n            // want to log this as an error since it's expected behaviour.\r\n            //\r\n            // We want them both to terminate, because in case of initiator's\r\n            // crash the responder would stay in P2P mode until ICE fails which\r\n            // could take up to 20 seconds.\r\n            //\r\n            // NOTE: whilst this is an error callback,  'success' as a reason is\r\n            // considered as graceful session terminate\r\n            // where both initiator and responder terminate their sessions\r\n            // simultaneously.\r\n            if (reason !== 'success') {\r\n                logger.error('An error occurred while trying to terminate P2P Jingle session', error);\r\n            }\r\n        }, {\r\n            reason,\r\n            reasonDescription,\r\n            sendSessionTerminate: this.room\r\n                && this.getParticipantById(\r\n                    Strophe.getResourceFromJid(this.p2pJingleSession.remoteJid))\r\n        });\r\n\r\n    this.p2pJingleSession = null;\r\n\r\n    // Update P2P status and other affected events/states\r\n    this._setP2PStatus(false);\r\n\r\n    if (wasP2PEstablished) {\r\n        // Add back remote JVB tracks\r\n        if (this.jvbJingleSession && !requestRestart) {\r\n            this._addRemoteJVBTracks();\r\n        } else {\r\n            logger.info('Not adding remote JVB tracks - no session yet');\r\n        }\r\n    }\r\n};\r\n\r\n/**\r\n * Updates room presence if needed and send the packet in case of a modification.\r\n * @param {JingleSessionPC} jingleSession the session firing the event, contains the peer connection which\r\n * tracks we will check.\r\n * @param {Object|null} ctx a context object we can distinguish multiple calls of the same pass of updating tracks.\r\n */\r\nJitsiConference.prototype._updateRoomPresence = function(jingleSession, ctx) {\r\n    if (!jingleSession) {\r\n        return;\r\n    }\r\n\r\n    // skips sending presence twice for the same pass of updating ssrcs\r\n    if (ctx) {\r\n        if (ctx.skip) {\r\n            return;\r\n        }\r\n        ctx.skip = true;\r\n    }\r\n\r\n    let presenceChanged = false;\r\n    let muteStatusChanged, videoTypeChanged;\r\n    const localTracks = jingleSession.peerconnection.getLocalTracks();\r\n\r\n    // Set presence for all the available local tracks.\r\n    for (const track of localTracks) {\r\n        muteStatusChanged = this._setTrackMuteStatus(track.getType(), track, track.isMuted());\r\n        if (track.getType() === MediaType.VIDEO) {\r\n            videoTypeChanged = this._setNewVideoType(track);\r\n        }\r\n        presenceChanged = presenceChanged || muteStatusChanged || videoTypeChanged;\r\n    }\r\n\r\n    presenceChanged && this.room.sendPresence();\r\n};\r\n\r\n/**\r\n * Checks whether or not the conference is currently in the peer to peer mode.\r\n * Being in peer to peer mode means that the direct connection has been\r\n * established and the P2P connection is being used for media transmission.\r\n * @return {boolean} <tt>true</tt> if in P2P mode or <tt>false</tt> otherwise.\r\n */\r\nJitsiConference.prototype.isP2PActive = function() {\r\n    return this.p2p;\r\n};\r\n\r\n/**\r\n * Returns the current ICE state of the P2P connection.\r\n * NOTE: method is used by the jitsi-meet-torture tests.\r\n * @return {string|null} an ICE state or <tt>null</tt> if there's currently\r\n * no P2P connection.\r\n */\r\nJitsiConference.prototype.getP2PConnectionState = function() {\r\n    if (this.isP2PActive()) {\r\n        return this.p2pJingleSession.peerconnection.getConnectionState();\r\n    }\r\n\r\n    return null;\r\n};\r\n\r\n/**\r\n * Configures the peerconnection so that a given framre rate can be achieved for desktop share.\r\n *\r\n * @param {number} maxFps The capture framerate to be used for desktop tracks.\r\n * @returns {boolean} true if the operation is successful, false otherwise.\r\n */\r\nJitsiConference.prototype.setDesktopSharingFrameRate = function(maxFps) {\r\n    if (typeof maxFps !== 'number' || isNaN(maxFps)) {\r\n        logger.error(`Invalid value ${maxFps} specified for desktop capture frame rate`);\r\n\r\n        return false;\r\n    }\r\n\r\n    this._desktopSharingFrameRate = maxFps;\r\n\r\n    // Enable or disable simulcast for plan-b screensharing based on the capture fps.\r\n    this.jvbJingleSession && this.jvbJingleSession.peerconnection.setDesktopSharingFrameRate(maxFps);\r\n\r\n    // Set the capture rate for desktop sharing.\r\n    this.rtc.setDesktopSharingFrameRate(maxFps);\r\n\r\n    return true;\r\n};\r\n\r\n/**\r\n * Manually starts new P2P session (should be used only in the tests).\r\n */\r\nJitsiConference.prototype.startP2PSession = function() {\r\n    const peers = this.getParticipants();\r\n\r\n    // Start peer to peer session\r\n    if (peers.length === 1) {\r\n        const peerJid = peers[0].getJid();\r\n\r\n        this._startP2PSession(peerJid);\r\n    } else {\r\n        throw new Error(\r\n            'There must be exactly 1 participant to start the P2P session !');\r\n    }\r\n};\r\n\r\n/**\r\n * Manually stops the current P2P session (should be used only in the tests).\r\n */\r\nJitsiConference.prototype.stopP2PSession = function(options) {\r\n    this._stopP2PSession(options);\r\n};\r\n\r\n/**\r\n * Get a summary of how long current participants have been the dominant speaker\r\n * @returns {object}\r\n */\r\nJitsiConference.prototype.getSpeakerStats = function() {\r\n    return this.speakerStatsCollector.getStats();\r\n};\r\n\r\n/**\r\n * Sends a face landmarks object to the xmpp server.\r\n * @param {Object} payload\r\n */\r\nJitsiConference.prototype.sendFaceLandmarks = function(payload) {\r\n    if (payload.faceExpression) {\r\n        this.xmpp.sendFaceExpressionEvent(this.room.roomjid, payload);\r\n    }\r\n};\r\n\r\n/**\r\n * Sets the constraints for the video that is requested from the bridge.\r\n *\r\n * @param {Object} videoConstraints The constraints which are specified in the\r\n * following format. The message updates the fields that are present and leaves the\r\n * rest unchanged on the bridge. Therefore, any field that is not applicable anymore\r\n * should be cleared by passing an empty object or list (whatever is applicable).\r\n * {\r\n *      'lastN': 20,\r\n *      'selectedEndpoints': ['A', 'B', 'C'],\r\n *      'onStageEndpoints': ['A'],\r\n *      'defaultConstraints': { 'maxHeight': 180 },\r\n *      'constraints': {\r\n *          'A': { 'maxHeight': 720 }\r\n *      }\r\n * }\r\n */\r\nJitsiConference.prototype.setReceiverConstraints = function(videoConstraints) {\r\n    this.receiveVideoController.setReceiverConstraints(videoConstraints);\r\n};\r\n\r\n/**\r\n * Sets the maximum video size the local participant should receive from remote\r\n * participants.\r\n *\r\n * @param {number} maxFrameHeight - the maximum frame height, in pixels,\r\n * this receiver is willing to receive.\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype.setReceiverVideoConstraint = function(maxFrameHeight) {\r\n    this.receiveVideoController.setPreferredReceiveMaxFrameHeight(maxFrameHeight);\r\n};\r\n\r\n/**\r\n * Sets the maximum video size the local participant should send to remote\r\n * participants.\r\n * @param {number} maxFrameHeight - The user preferred max frame height.\r\n * @returns {Promise} promise that will be resolved when the operation is\r\n * successful and rejected otherwise.\r\n */\r\nJitsiConference.prototype.setSenderVideoConstraint = function(maxFrameHeight) {\r\n    return this.sendVideoController.setPreferredSendMaxFrameHeight(maxFrameHeight);\r\n};\r\n\r\n/**\r\n * Creates a video SIP GW session and returns it if service is enabled. Before\r\n * creating a session one need to check whether video SIP GW service is\r\n * available in the system {@link JitsiConference.isVideoSIPGWAvailable}. Even\r\n * if there are available nodes to serve this request, after creating the\r\n * session those nodes can be taken and the request about using the\r\n * created session can fail.\r\n *\r\n * @param {string} sipAddress - The sip address to be used.\r\n * @param {string} displayName - The display name to be used for this session.\r\n * @returns {JitsiVideoSIPGWSession|Error} Returns null if conference is not\r\n * initialised and there is no room.\r\n */\r\nJitsiConference.prototype.createVideoSIPGWSession = function(sipAddress, displayName) {\r\n    if (!this.room) {\r\n        return new Error(VideoSIPGWConstants.ERROR_NO_CONNECTION);\r\n    }\r\n\r\n    return this.videoSIPGWHandler\r\n        .createVideoSIPGWSession(sipAddress, displayName);\r\n};\r\n\r\n/**\r\n * Sends a conference.join analytics event.\r\n *\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype._sendConferenceJoinAnalyticsEvent = function() {\r\n    const meetingId = this.getMeetingUniqueId();\r\n\r\n    if (this._conferenceJoinAnalyticsEventSent || !meetingId || this.getActivePeerConnection() === null) {\r\n        return;\r\n    }\r\n\r\n    Statistics.sendAnalytics(createConferenceEvent('joined', {\r\n        meetingId,\r\n        participantId: `${meetingId}.${this._statsCurrentId}`\r\n    }));\r\n    this._conferenceJoinAnalyticsEventSent = Date.now();\r\n};\r\n\r\n/**\r\n * Sends conference.left analytics event.\r\n * @private\r\n */\r\nJitsiConference.prototype._sendConferenceLeftAnalyticsEvent = function() {\r\n    const meetingId = this.getMeetingUniqueId();\r\n\r\n    if (!meetingId || !this._conferenceJoinAnalyticsEventSent) {\r\n\r\n        return;\r\n    }\r\n\r\n    Statistics.sendAnalytics(createConferenceEvent('left', {\r\n        meetingId,\r\n        participantId: `${meetingId}.${this._statsCurrentId}`,\r\n        stats: {\r\n            duration: Math.floor((Date.now() - this._conferenceJoinAnalyticsEventSent) / 1000),\r\n            perf: this.getPerformanceStats()\r\n        }\r\n    }));\r\n};\r\n\r\n/**\r\n * Restarts all active media sessions.\r\n *\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype._restartMediaSessions = function() {\r\n    if (this.p2pJingleSession) {\r\n        this._stopP2PSession({\r\n            reasonDescription: 'restart',\r\n            requestRestart: true\r\n        });\r\n    }\r\n\r\n    if (this.jvbJingleSession) {\r\n        this.jvbJingleSession.terminate(\r\n            null /* success callback => we don't care */,\r\n            error => {\r\n                logger.warn('An error occurred while trying to terminate the JVB session', error);\r\n            }, {\r\n                reason: 'success',\r\n                reasonDescription: 'restart required',\r\n                requestRestart: true,\r\n                sendSessionTerminate: true\r\n            });\r\n    }\r\n\r\n    this._maybeStartOrStopP2P(false);\r\n};\r\n\r\n/**\r\n * Returns whether End-To-End encryption is enabled.\r\n *\r\n * @returns {boolean}\r\n */\r\nJitsiConference.prototype.isE2EEEnabled = function() {\r\n    return Boolean(this._e2eEncryption && this._e2eEncryption.isEnabled());\r\n};\r\n\r\n/**\r\n * Returns whether End-To-End encryption is supported. Note that not all participants\r\n * in the conference may support it.\r\n *\r\n * @returns {boolean}\r\n */\r\nJitsiConference.prototype.isE2EESupported = function() {\r\n    return E2EEncryption.isSupported(this.options.config);\r\n};\r\n\r\n/**\r\n * Enables / disables End-to-End encryption.\r\n *\r\n * @param {boolean} enabled whether to enable E2EE or not.\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype.toggleE2EE = function(enabled) {\r\n    if (!this.isE2EESupported()) {\r\n        logger.warn('Cannot enable / disable E2EE: platform is not supported.');\r\n\r\n        return;\r\n    }\r\n\r\n    this._e2eEncryption.setEnabled(enabled);\r\n};\r\n\r\n/**\r\n * Sets the key and index for End-to-End encryption.\r\n *\r\n * @param {CryptoKey} [keyInfo.encryptionKey] - encryption key.\r\n * @param {Number} [keyInfo.index] - the index of the encryption key.\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype.setMediaEncryptionKey = function(keyInfo) {\r\n    this._e2eEncryption.setEncryptionKey(keyInfo);\r\n};\r\n\r\n/**\r\n * Returns <tt>true</tt> if lobby support is enabled in the backend.\r\n *\r\n * @returns {boolean} whether lobby is supported in the backend.\r\n */\r\nJitsiConference.prototype.isLobbySupported = function() {\r\n    return Boolean(this.room && this.room.getLobby().isSupported());\r\n};\r\n\r\n/**\r\n * Returns <tt>true</tt> if the room has members only enabled.\r\n *\r\n * @returns {boolean} whether conference room is members only.\r\n */\r\nJitsiConference.prototype.isMembersOnly = function() {\r\n    return Boolean(this.room && this.room.membersOnlyEnabled);\r\n};\r\n\r\n/**\r\n * Enables lobby by moderators\r\n *\r\n * @returns {Promise} resolves when lobby room is joined or rejects with the error.\r\n */\r\nJitsiConference.prototype.enableLobby = function() {\r\n    if (this.room && this.isModerator()) {\r\n        return this.room.getLobby().enable();\r\n    }\r\n\r\n    return Promise.reject(\r\n        new Error('The conference not started or user is not moderator'));\r\n};\r\n\r\n/**\r\n * Disabled lobby by moderators\r\n *\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype.disableLobby = function() {\r\n    if (this.room && this.isModerator()) {\r\n        this.room.getLobby().disable();\r\n    } else {\r\n        logger.warn(`Failed to disable lobby, ${this.room ? '' : 'not in a room, '}${\r\n            this.isModerator() ? '' : 'participant is not a moderator'}`);\r\n    }\r\n};\r\n\r\n/**\r\n * Joins the lobby room with display name and optional email or with a shared password to skip waiting.\r\n *\r\n * @param {string} displayName Display name should be set to show it to moderators.\r\n * @param {string} email Optional email is used to present avatar to the moderator.\r\n * @returns {Promise<never>}\r\n */\r\nJitsiConference.prototype.joinLobby = function(displayName, email) {\r\n    if (this.room) {\r\n        return this.room.getLobby().join(displayName, email);\r\n    }\r\n\r\n    return Promise.reject(new Error('The conference not started'));\r\n};\r\n\r\n/**\r\n * Gets the local id for a participant in a lobby room.\r\n * Returns undefined when current participant is not in the lobby room.\r\n * This is used for lobby room private chat messages.\r\n *\r\n * @returns {string}\r\n */\r\nJitsiConference.prototype.myLobbyUserId = function() {\r\n    if (this.room) {\r\n        return this.room.getLobby().getLocalId();\r\n    }\r\n};\r\n\r\n/**\r\n * Sends a message to a lobby room.\r\n * When id is specified it sends a private message.\r\n * Otherwise it sends the message to all moderators.\r\n * @param {message} Object The message to send\r\n * @param {string} id The participant id.\r\n *\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype.sendLobbyMessage = function(message, id) {\r\n    if (this.room) {\r\n        if (id) {\r\n            return this.room.getLobby().sendPrivateMessage(id, message);\r\n        }\r\n\r\n        return this.room.getLobby().sendMessage(message);\r\n    }\r\n};\r\n\r\n/**\r\n * Adds a message listener to the lobby room\r\n * @param {Function} listener The listener function,\r\n * called when a new message is received in the lobby room.\r\n *\r\n * @returns {Function} Handler returned to be able to remove it later.\r\n */\r\nJitsiConference.prototype.addLobbyMessageListener = function(listener) {\r\n    if (this.room) {\r\n        return this.room.getLobby().addMessageListener(listener);\r\n    }\r\n};\r\n\r\n/**\r\n * Removes a message handler from the lobby room\r\n * @param {Function} handler The handler function  to remove.\r\n *\r\n * @returns {void}\r\n */\r\nJitsiConference.prototype.removeLobbyMessageHandler = function(handler) {\r\n    if (this.room) {\r\n        return this.room.getLobby().removeMessageHandler(handler);\r\n    }\r\n};\r\n\r\n/**\r\n * Denies an occupant in the lobby room access to the conference.\r\n * @param {string} id The participant id.\r\n */\r\nJitsiConference.prototype.lobbyDenyAccess = function(id) {\r\n    if (this.room) {\r\n        this.room.getLobby().denyAccess(id);\r\n    }\r\n};\r\n\r\n/**\r\n * Approves the request to join the conference to a participant waiting in the lobby.\r\n *\r\n * @param {string} id The participant id.\r\n */\r\nJitsiConference.prototype.lobbyApproveAccess = function(id) {\r\n    if (this.room) {\r\n        this.room.getLobby().approveAccess(id);\r\n    }\r\n};\r\n\r\n/**\r\n * Returns <tt>true</tt> if AV Moderation support is enabled in the backend.\r\n *\r\n * @returns {boolean} whether AV Moderation is supported in the backend.\r\n */\r\nJitsiConference.prototype.isAVModerationSupported = function() {\r\n    return Boolean(this.room && this.room.getAVModeration().isSupported());\r\n};\r\n\r\n/**\r\n * Enables AV Moderation.\r\n * @param {MediaType} mediaType \"audio\" or \"video\"\r\n */\r\nJitsiConference.prototype.enableAVModeration = function(mediaType) {\r\n    if (this.room && this.isModerator()\r\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\r\n        this.room.getAVModeration().enable(true, mediaType);\r\n    } else {\r\n        logger.warn(`Failed to enable AV moderation, ${this.room ? '' : 'not in a room, '}${\r\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\r\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\r\n    }\r\n};\r\n\r\n/**\r\n * Disables AV Moderation.\r\n * @param {MediaType} mediaType \"audio\" or \"video\"\r\n */\r\nJitsiConference.prototype.disableAVModeration = function(mediaType) {\r\n    if (this.room && this.isModerator()\r\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\r\n        this.room.getAVModeration().enable(false, mediaType);\r\n    } else {\r\n        logger.warn(`Failed to disable AV moderation, ${this.room ? '' : 'not in a room, '}${\r\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\r\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\r\n    }\r\n};\r\n\r\n/**\r\n * Approve participant access to certain media, allows unmuting audio or video.\r\n *\r\n * @param {MediaType} mediaType \"audio\" or \"video\"\r\n * @param id the id of the participant.\r\n */\r\nJitsiConference.prototype.avModerationApprove = function(mediaType, id) {\r\n    if (this.room && this.isModerator()\r\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\r\n\r\n        const participant = this.getParticipantById(id);\r\n\r\n        if (!participant) {\r\n            return;\r\n        }\r\n\r\n        this.room.getAVModeration().approve(mediaType, participant.getJid());\r\n    } else {\r\n        logger.warn(`AV moderation approve skipped , ${this.room ? '' : 'not in a room, '}${\r\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\r\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\r\n    }\r\n};\r\n\r\n/**\r\n * Reject participant access to certain media, blocks unmuting audio or video.\r\n *\r\n * @param {MediaType} mediaType \"audio\" or \"video\"\r\n * @param id the id of the participant.\r\n */\r\nJitsiConference.prototype.avModerationReject = function(mediaType, id) {\r\n    if (this.room && this.isModerator()\r\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\r\n\r\n        const participant = this.getParticipantById(id);\r\n\r\n        if (!participant) {\r\n            return;\r\n        }\r\n\r\n        this.room.getAVModeration().reject(mediaType, participant.getJid());\r\n    } else {\r\n        logger.warn(`AV moderation reject skipped , ${this.room ? '' : 'not in a room, '}${\r\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\r\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\r\n    }\r\n};\r\n\r\n/**\r\n * Returns the breakout rooms manager object.\r\n *\r\n * @returns {Object} the breakout rooms manager.\r\n */\r\nJitsiConference.prototype.getBreakoutRooms = function() {\r\n    return this.room?.getBreakoutRooms();\r\n};\r\n\r\n/**\r\n * Returns the metadata handler object.\r\n *\r\n * @returns {Object} the room metadata handler.\r\n */\r\nJitsiConference.prototype.getMetadataHandler = function() {\r\n    return this.room?.getMetadataHandler();\r\n};\r\n","import JitsiConference from './JitsiConference';\r\nimport * as JitsiConnectionEvents from './JitsiConnectionEvents';\r\nimport Statistics from './modules/statistics/statistics';\r\nimport XMPP from './modules/xmpp/xmpp';\r\nimport {\r\n    CONNECTION_DISCONNECTED as ANALYTICS_CONNECTION_DISCONNECTED,\r\n    createConnectionFailedEvent\r\n} from './service/statistics/AnalyticsEvents';\r\n\r\n/**\r\n * Creates a new connection object for the Jitsi Meet server side video\r\n * conferencing service. Provides access to the JitsiConference interface.\r\n * @param appID identification for the provider of Jitsi Meet video conferencing\r\n * services.\r\n * @param token the JWT token used to authenticate with the server(optional)\r\n * @param options Object with properties / settings related to connection with\r\n * the server.\r\n * @constructor\r\n */\r\nexport default function JitsiConnection(appID, token, options) {\r\n    this.appID = appID;\r\n    this.token = token;\r\n    this.options = options;\r\n    this.xmpp = new XMPP(options, token);\r\n\r\n    /* eslint-disable max-params */\r\n    this.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED,\r\n        (errType, msg, credentials, details) => {\r\n            Statistics.sendAnalyticsAndLog(\r\n                createConnectionFailedEvent(errType, msg, details));\r\n        });\r\n    /* eslint-enable max-params */\r\n\r\n    this.addEventListener(JitsiConnectionEvents.CONNECTION_DISCONNECTED,\r\n        msg => {\r\n            // we can see disconnects from normal tab closing of the browser\r\n            // and then there are no msgs, but we want to log only disconnects\r\n            // when there is real error\r\n            // XXX Do we need the difference in handling between the log and\r\n            // analytics event here?\r\n            if (msg) {\r\n                Statistics.sendAnalytics(\r\n                    ANALYTICS_CONNECTION_DISCONNECTED,\r\n                    { message: msg });\r\n            }\r\n            Statistics.sendLog(\r\n                JSON.stringify(\r\n                    {\r\n                        id: ANALYTICS_CONNECTION_DISCONNECTED,\r\n                        msg\r\n                    }));\r\n        });\r\n}\r\n\r\n/**\r\n * Connect the client with the server.\r\n * @param options {object} connecting options\r\n * (for example authentications parameters).\r\n */\r\nJitsiConnection.prototype.connect = function(options = {}) {\r\n    this.xmpp.connect(options.id, options.password);\r\n};\r\n\r\n/**\r\n * Attach to existing connection. Can be used for optimizations. For example:\r\n * if the connection is created on the server we can attach to it and start\r\n * using it.\r\n *\r\n * @param options {object} connecting options - rid, sid and jid.\r\n */\r\nJitsiConnection.prototype.attach = function(options) {\r\n    this.xmpp.attach(options);\r\n};\r\n\r\n/**\r\n * Disconnect the client from the server.\r\n * @returns {Promise} - Resolves when the disconnect process is finished or rejects with an error.\r\n */\r\nJitsiConnection.prototype.disconnect = function(...args) {\r\n    // XXX Forward any arguments passed to JitsiConnection.disconnect to\r\n    // XMPP.disconnect. For example, the caller of JitsiConnection.disconnect\r\n    // may optionally pass the event which triggered the disconnect in order to\r\n    // provide the implementation with finer-grained context.\r\n    return this.xmpp.disconnect(...args);\r\n};\r\n\r\n/**\r\n * Returns the jid of the participant associated with the XMPP connection.\r\n *\r\n * @returns {string} The jid of the participant.\r\n */\r\nJitsiConnection.prototype.getJid = function() {\r\n    return this.xmpp.getJid();\r\n};\r\n\r\n/**\r\n * This method allows renewal of the tokens if they are expiring.\r\n * @param token the new token.\r\n */\r\nJitsiConnection.prototype.setToken = function(token) {\r\n    this.token = token;\r\n};\r\n\r\n/**\r\n * Creates and joins new conference.\r\n * @param name the name of the conference; if null - a generated name will be\r\n * provided from the api\r\n * @param options Object with properties / settings related to the conference\r\n * that will be created.\r\n * @returns {JitsiConference} returns the new conference object.\r\n */\r\nJitsiConnection.prototype.initJitsiConference = function(name, options) {\r\n    return new JitsiConference({\r\n        name,\r\n        config: options,\r\n        connection: this\r\n    });\r\n};\r\n\r\n/**\r\n * Subscribes the passed listener to the event.\r\n * @param event {JitsiConnectionEvents} the connection event.\r\n * @param listener {Function} the function that will receive the event\r\n */\r\nJitsiConnection.prototype.addEventListener = function(event, listener) {\r\n    this.xmpp.addListener(event, listener);\r\n};\r\n\r\n/**\r\n * Unsubscribes the passed handler.\r\n * @param event {JitsiConnectionEvents} the connection event.\r\n * @param listener {Function} the function that will receive the event\r\n */\r\nJitsiConnection.prototype.removeEventListener = function(event, listener) {\r\n    this.xmpp.removeListener(event, listener);\r\n};\r\n\r\n/**\r\n * Returns measured connectionTimes.\r\n */\r\nJitsiConnection.prototype.getConnectionTimes = function() {\r\n    return this.xmpp.connectionTimes;\r\n};\r\n\r\n/**\r\n * Adds new feature to the list of supported features for the local\r\n * participant.\r\n * @param {String} feature the name of the feature.\r\n * @param {boolean} submit if true - the new list of features will be\r\n * immediately submitted to the others.\r\n */\r\nJitsiConnection.prototype.addFeature = function(feature, submit = false) {\r\n    this.xmpp.caps.addFeature(feature, submit, true);\r\n};\r\n\r\n/**\r\n * Removes a feature from the list of supported features for the local\r\n * participant\r\n * @param {String} feature the name of the feature.\r\n * @param {boolean} submit if true - the new list of features will be\r\n * immediately submitted to the others.\r\n */\r\nJitsiConnection.prototype.removeFeature = function(feature, submit = false) {\r\n    this.xmpp.caps.removeFeature(feature, submit, true);\r\n};\r\n\r\n/**\r\n * Get object with internal logs.\r\n */\r\nJitsiConnection.prototype.getLogs = function() {\r\n    const data = this.xmpp.getJingleLog();\r\n\r\n    const metadata = {};\r\n\r\n    metadata.time = new Date();\r\n    metadata.url = window.location.href;\r\n    metadata.ua = navigator.userAgent;\r\n\r\n    const log = this.xmpp.getXmppLog();\r\n\r\n    if (log) {\r\n        metadata.xmpp = log;\r\n    }\r\n\r\n    data.metadata = metadata;\r\n\r\n    return data;\r\n};\r\n","/**\r\n * The events for the media devices.\r\n */\r\n\r\nexport enum JitsiMediaDevicesEvents {\r\n    /**\r\n     * Indicates that the list of available media devices has been changed. The\r\n     * event provides the following parameters to its listeners:\r\n     *\r\n     * @param {MediaDeviceInfo[]} devices - array of MediaDeviceInfo or\r\n     *  MediaDeviceInfo-like objects that are currently connected.\r\n     *  @see https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo\r\n     */\r\n    DEVICE_LIST_CHANGED = 'mediaDevices.devicechange',\r\n\r\n    /**\r\n     * Event emitted when the user granted/blocked a permission for the camera / mic.\r\n     * Used to keep track of the granted permissions on browsers which don't\r\n     * support the Permissions API.\r\n     */\r\n    PERMISSIONS_CHANGED = 'rtc.permissions_changed',\r\n\r\n    /**\r\n     * Indicates that the environment is currently showing permission prompt to\r\n     * access camera and/or microphone. The event provides the following\r\n     * parameters to its listeners:\r\n     *\r\n     * @param {'chrome'|'opera'|'firefox'|'safari'|'nwjs'\r\n     *  |'react-native'|'android'} environmentType - type of browser or\r\n     *  other execution environment.\r\n     */\r\n    PERMISSION_PROMPT_IS_SHOWN = 'mediaDevices.permissionPromptIsShown',\r\n\r\n    SLOW_GET_USER_MEDIA = 'mediaDevices.slowGetUserMedia'\r\n};\r\n\r\n// exported for backward compatibility\r\nexport const DEVICE_LIST_CHANGED = JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED;\r\nexport const PERMISSIONS_CHANGED = JitsiMediaDevicesEvents.PERMISSIONS_CHANGED;\r\nexport const PERMISSION_PROMPT_IS_SHOWN = JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN;\r\nexport const SLOW_GET_USER_MEDIA = JitsiMediaDevicesEvents.SLOW_GET_USER_MEDIA;\r\n","import EventEmitter from 'events';\r\n\r\nimport * as JitsiMediaDevicesEvents from './JitsiMediaDevicesEvents';\r\nimport RTC from './modules/RTC/RTC';\r\nimport browser from './modules/browser';\r\nimport Statistics from './modules/statistics/statistics';\r\nimport { MediaType } from './service/RTC/MediaType';\r\nimport RTCEvents from './service/RTC/RTCEvents';\r\n\r\nconst AUDIO_PERMISSION_NAME = 'microphone';\r\nconst PERMISSION_GRANTED_STATUS = 'granted';\r\nconst VIDEO_PERMISSION_NAME = 'camera';\r\n\r\n/**\r\n * Media devices utilities for Jitsi.\r\n */\r\nclass JitsiMediaDevices {\r\n    /**\r\n     * Initializes a {@code JitsiMediaDevices} object. There will be a single\r\n     * instance of this class.\r\n     */\r\n    constructor() {\r\n        this._eventEmitter = new EventEmitter();\r\n        this._permissions = {};\r\n\r\n        RTC.addListener(\r\n            RTCEvents.DEVICE_LIST_CHANGED,\r\n            devices =>\r\n                this._eventEmitter.emit(\r\n                    JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED,\r\n                    devices));\r\n        RTC.addListener(\r\n            RTCEvents.DEVICE_LIST_AVAILABLE,\r\n            devices =>\r\n                this._logOutputDevice(\r\n                    this.getAudioOutputDevice(),\r\n                    devices));\r\n\r\n        // We would still want to update the permissions cache in case the permissions API is not supported.\r\n        RTC.addListener(\r\n            RTCEvents.PERMISSIONS_CHANGED,\r\n            permissions => this._handlePermissionsChange(permissions));\r\n\r\n        // Test if the W3C Permissions API is implemented and the 'camera' and 'microphone' permissions are\r\n        // implemented. If supported add onchange listeners.\r\n        this._permissionsApiSupported = new Promise(resolve => {\r\n            if (!navigator.permissions) {\r\n                resolve(false);\r\n\r\n                return;\r\n            }\r\n\r\n            const self = this;\r\n\r\n            const promises = [];\r\n\r\n            promises.push(navigator.permissions.query({ name: VIDEO_PERMISSION_NAME })\r\n                .then(status => {\r\n                    this._handlePermissionsChange({\r\n                        [MediaType.VIDEO]: this._parsePermissionState(status)\r\n                    });\r\n                    status.onchange = function() {\r\n                        try {\r\n                            self._handlePermissionsChange({\r\n                                [MediaType.VIDEO]: self._parsePermissionState(this)\r\n                            });\r\n                        } catch (error) {\r\n                            // Nothing to do.\r\n                        }\r\n                    };\r\n\r\n                    return true;\r\n                })\r\n                .catch(() => false));\r\n\r\n            promises.push(navigator.permissions.query({ name: AUDIO_PERMISSION_NAME })\r\n                .then(status => {\r\n                    this._handlePermissionsChange({\r\n                        [MediaType.AUDIO]: this._parsePermissionState(status)\r\n                    });\r\n                    status.onchange = function() {\r\n                        try {\r\n                            self._handlePermissionsChange({\r\n                                [MediaType.AUDIO]: self._parsePermissionState(this)\r\n                            });\r\n                        } catch (error) {\r\n                            // Nothing to do.\r\n                        }\r\n                    };\r\n\r\n                    return true;\r\n                })\r\n                .catch(() => false));\r\n\r\n            Promise.all(promises).then(results => resolve(results.every(supported => supported)));\r\n\r\n        });\r\n    }\r\n\r\n\r\n    /**\r\n     * Parses a PermissionState object and returns true for granted and false otherwise.\r\n     *\r\n     * @param {PermissionState} permissionStatus - The PermissionState object retrieved from the Permissions API.\r\n     * @returns {boolean} - True for granted and false for denied.\r\n     * @throws {TypeError}\r\n     */\r\n    _parsePermissionState(permissionStatus = {}) {\r\n        // The status attribute is deprecated, and state\r\n        // should be used instead, but check both for now\r\n        // for backwards compatibility.\r\n        const status = permissionStatus.state || permissionStatus.status;\r\n\r\n        if (typeof status !== 'string') {\r\n            throw new TypeError();\r\n        }\r\n\r\n        return status === PERMISSION_GRANTED_STATUS;\r\n    }\r\n\r\n    /**\r\n     * Updates the local granted/denied permissions cache. A permissions might be\r\n     * granted, denied, or undefined. This is represented by having its media\r\n     * type key set to {@code true} or {@code false} respectively.\r\n     *\r\n     * @param {Object} permissions - Object with the permissions.\r\n     */\r\n    _handlePermissionsChange(permissions) {\r\n        const hasPermissionsChanged\r\n            = [ MediaType.AUDIO, MediaType.VIDEO ]\r\n                .some(type => type in permissions && permissions[type] !== this._permissions[type]);\r\n\r\n        if (hasPermissionsChanged) {\r\n            this._permissions = {\r\n                ...this._permissions,\r\n                ...permissions\r\n            };\r\n            this._eventEmitter.emit(JitsiMediaDevicesEvents.PERMISSIONS_CHANGED, this._permissions);\r\n\r\n            if (this._permissions[MediaType.AUDIO] || this._permissions[MediaType.VIDEO]) {\r\n                // Triggering device list update when the permissiions are granted in order to update\r\n                // the labels the devices.\r\n                // eslint-disable-next-line no-empty-function\r\n                this.enumerateDevices(() => {});\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Gathers data and sends it to statistics.\r\n     * @param deviceID the device id to log\r\n     * @param devices list of devices\r\n     */\r\n    _logOutputDevice(deviceID, devices) {\r\n        const device\r\n            = devices.find(\r\n                d => d.kind === 'audiooutput' && d.deviceId === deviceID);\r\n\r\n        if (device) {\r\n            Statistics.sendActiveDeviceListEvent(\r\n                RTC.getEventDataForActiveDevice(device));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Executes callback with list of media devices connected.\r\n     * @param {function} callback\r\n     */\r\n    enumerateDevices(callback) {\r\n        RTC.enumerateDevices(callback);\r\n    }\r\n\r\n    /**\r\n     * Checks if its possible to enumerate available cameras/micropones.\r\n     * @returns {Promise<boolean>} a Promise which will be resolved only once\r\n     * the WebRTC stack is ready, either with true if the device listing is\r\n     * available available or with false otherwise.\r\n     */\r\n    isDeviceListAvailable() {\r\n        return RTC.isDeviceListAvailable();\r\n    }\r\n\r\n    /**\r\n     * Returns true if changing the input (camera / microphone) or output\r\n     * (audio) device is supported and false if not.\r\n     * @param {string} [deviceType] - type of device to change. Default is\r\n     *      undefined or 'input', 'output' - for audio output device change.\r\n     * @returns {boolean} true if available, false otherwise.\r\n     */\r\n    isDeviceChangeAvailable(deviceType) {\r\n        return RTC.isDeviceChangeAvailable(deviceType);\r\n    }\r\n\r\n    /**\r\n     * Checks if the permission for the given device was granted.\r\n     *\r\n     * @param {'audio'|'video'} [type] - type of devices to check,\r\n     *      undefined stands for both 'audio' and 'video' together\r\n     * @returns {Promise<boolean>}\r\n     */\r\n    isDevicePermissionGranted(type) {\r\n        return new Promise(resolve => {\r\n            // Shortcut: first check if we already know the permission was\r\n            // granted.\r\n            if (type in this._permissions) {\r\n                resolve(this._permissions[type]);\r\n\r\n                return;\r\n            }\r\n\r\n            // Check using the Permissions API.\r\n            this._permissionsApiSupported.then(supported => {\r\n                if (!supported) {\r\n                    resolve(false);\r\n\r\n                    return;\r\n                }\r\n\r\n                const promises = [];\r\n\r\n                switch (type) {\r\n                case MediaType.VIDEO:\r\n                    promises.push(\r\n                        navigator.permissions.query({\r\n                            name: VIDEO_PERMISSION_NAME\r\n                        }));\r\n                    break;\r\n                case MediaType.AUDIO:\r\n                    promises.push(\r\n                        navigator.permissions.query({\r\n                            name: AUDIO_PERMISSION_NAME\r\n                        }));\r\n                    break;\r\n                default:\r\n                    promises.push(\r\n                        navigator.permissions.query({\r\n                            name: VIDEO_PERMISSION_NAME\r\n                        }));\r\n                    promises.push(\r\n                        navigator.permissions.query({\r\n                            name: AUDIO_PERMISSION_NAME\r\n                        }));\r\n                }\r\n\r\n                Promise.all(promises).then(\r\n                    results => resolve(results.every(permissionStatus => {\r\n                        try {\r\n                            return this._parsePermissionState(permissionStatus);\r\n                        } catch {\r\n                            return false;\r\n                        }\r\n                    })),\r\n                    () => resolve(false)\r\n                );\r\n            });\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Returns true if it is possible to be simultaneously capturing audio from more than one device.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isMultipleAudioInputSupported() {\r\n        return !(\r\n            (browser.isFirefox() && browser.isVersionLessThan('101'))\r\n            || browser.isIosBrowser()\r\n        );\r\n    }\r\n\r\n    /**\r\n     * Returns currently used audio output device id, 'default' stands\r\n     * for default device\r\n     * @returns {string}\r\n     */\r\n    getAudioOutputDevice() {\r\n        return RTC.getAudioOutputDevice();\r\n    }\r\n\r\n    /**\r\n     * Sets current audio output device.\r\n     * @param {string} deviceId - id of 'audiooutput' device from\r\n     *      navigator.mediaDevices.enumerateDevices(), 'default' is for\r\n     *      default device\r\n     * @returns {Promise} - resolves when audio output is changed, is rejected\r\n     *      otherwise\r\n     */\r\n    setAudioOutputDevice(deviceId) {\r\n        const availableDevices = RTC.getCurrentlyAvailableMediaDevices();\r\n\r\n        if (availableDevices.length > 0) {\r\n            // if we have devices info report device to stats\r\n            // normally this will not happen on startup as this method is called\r\n            // too early. This will happen only on user selection of new device\r\n            this._logOutputDevice(\r\n                deviceId, RTC.getCurrentlyAvailableMediaDevices());\r\n        }\r\n\r\n        return RTC.setAudioOutputDevice(deviceId);\r\n    }\r\n\r\n    /**\r\n     * Adds an event handler.\r\n     * @param {string} event - event name\r\n     * @param {function} handler - event handler\r\n     */\r\n    addEventListener(event, handler) {\r\n        this._eventEmitter.addListener(event, handler);\r\n    }\r\n\r\n    /**\r\n     * Removes event handler.\r\n     * @param {string} event - event name\r\n     * @param {function} handler - event handler\r\n     */\r\n    removeEventListener(event, handler) {\r\n        this._eventEmitter.removeListener(event, handler);\r\n    }\r\n\r\n    /**\r\n     * Emits an event.\r\n     * @param {string} event - event name\r\n     */\r\n    emitEvent(event, ...args) {\r\n        this._eventEmitter.emit(event, ...args);\r\n    }\r\n}\r\n\r\nexport default new JitsiMediaDevices();\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\r\nimport RTC from '../RTC/RTC';\r\nimport Statistics from '../statistics/statistics';\r\n\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n// If after 3000 ms the detector did not find any active devices consider that there aren't any usable ones available\r\n// i.e. audioLevel > 0.008\r\nconst DETECTION_TIMEOUT = 3000;\r\n\r\n\r\n/**\r\n * Go through all audio devices on the system and return one that is active, i.e. has audio signal.\r\n *\r\n * @returns Promise<Object> - Object containing information about the found device.\r\n */\r\nexport default function getActiveAudioDevice() {\r\n\r\n    return new Promise(resolve => {\r\n        RTC.enumerateDevices(devices => {\r\n            const audioDevices = devices.filter(device => device.kind === 'audioinput');\r\n            const devicePromiseArray = [];\r\n\r\n\r\n            for (const micDevice of audioDevices) {\r\n                const devicePromise = RTC.obtainAudioAndVideoPermissions({ devices: [ 'audio' ],\r\n                    micDeviceId: micDevice.deviceId }).then(tracks => {\r\n\r\n                    // We expect a single device to be available when obtained from obtainAudioAndVideoPermissions\r\n                    // that's  why only take p.value[0].\r\n                    const track = tracks[0];\r\n\r\n                    Statistics.startLocalStats(track, track.setAudioLevel.bind(track));\r\n\r\n                    return track;\r\n                });\r\n\r\n                devicePromiseArray.push(devicePromise);\r\n            }\r\n\r\n            Promise.allSettled(devicePromiseArray).then(outcomeArray => {\r\n                const successfulPromises = outcomeArray.filter(p => p.status === 'fulfilled');\r\n                const rejectedPromises = outcomeArray.filter(p => p.status === 'rejected');\r\n\r\n\r\n                const availableDevices = successfulPromises.map(p => p.value);\r\n                const rejectReasons = rejectedPromises.map(p => p.value);\r\n\r\n                for (const reason of rejectReasons) {\r\n                    logger.error('Failed to acquire audio device with error: ', reason);\r\n                }\r\n\r\n                // Setup event handlers for monitored devices.\r\n                for (const device of availableDevices) {\r\n                    device.on(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevel => {\r\n                        // This is a very naive approach but works, a more accurate one would be to use rnnoise in\r\n                        // order to limit  the number of false positives. The 0.008 constant is due to how\r\n                        // LocalStatsCollector from lib-jitsi-meet publishes audio-levels, in this case 0.008 denotes //\r\n                        // no input.\r\n                        if (audioLevel > 0.008) {\r\n                            stopActiveDevices(availableDevices);\r\n                            resolve({ deviceId: device.deviceId,\r\n                                deviceLabel: device.track.label });\r\n                        }\r\n                    });\r\n                }\r\n\r\n                // Cancel the detection in case no devices was found with audioLevel > 0 in the set timeout.\r\n                setTimeout(() => {\r\n                    stopActiveDevices(availableDevices);\r\n                    resolve({\r\n                        deviceId: '',\r\n                        deviceLabel: '' }\r\n                    );\r\n                }, DETECTION_TIMEOUT);\r\n\r\n            });\r\n\r\n        });\r\n    });\r\n}\r\n\r\n/**\r\n * Stop the streams of the provided JitsiLocalTracks.\r\n *\r\n * @param {Array<JitsiLocalTrack>} deviceList - Array of JitsiLocalTracks to stop.\r\n * @returns {void}\r\n */\r\nfunction stopActiveDevices(deviceList) {\r\n    for (const device of deviceList) {\r\n        device.stopStream();\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport SignalingLayer from '../../service/RTC/SignalingLayer';\r\n\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n\r\n/**\r\n * Custom semi-mock implementation for the Proxy connection service.\r\n */\r\nexport default class CustomSignalingLayer extends SignalingLayer {\r\n    /**\r\n     * Creates new instance.\r\n     */\r\n    constructor() {\r\n        super();\r\n\r\n        /**\r\n         * A map that stores SSRCs of remote streams.\r\n         * @type {Map<number, string>} maps SSRC number to jid\r\n         */\r\n        this.ssrcOwners = new Map();\r\n\r\n        /**\r\n         *\r\n         * @type {ChatRoom|null}\r\n         */\r\n        this.chatRoom = null;\r\n    }\r\n\r\n    /**\r\n     * Sets the <tt>ChatRoom</tt> instance used.\r\n     * @param {ChatRoom} room\r\n     */\r\n    setChatRoom(room) {\r\n        this.chatRoom = room;\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    getPeerMediaInfo(owner, mediaType, sourceName) { // eslint-disable-line no-unused-vars\r\n        return {};\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    getPeerSourceInfo(owner, sourceName) { // eslint-disable-line no-unused-vars\r\n        return undefined;\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    getSSRCOwner(ssrc) {\r\n        return this.ssrcOwners.get(ssrc);\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    setSSRCOwner(ssrc, endpointId) {\r\n        if (typeof ssrc !== 'number') {\r\n            throw new TypeError(`SSRC(${ssrc}) must be a number`);\r\n        }\r\n\r\n        // Now signaling layer instance is shared between different JingleSessionPC instances, so although very unlikely\r\n        // an SSRC conflict could potentially occur. Log a message to make debugging easier.\r\n        const existingOwner = this.ssrcOwners.get(ssrc);\r\n\r\n        if (existingOwner && existingOwner !== endpointId) {\r\n            logger.error(`SSRC owner re-assigned from ${existingOwner} to ${endpointId}`);\r\n        }\r\n        this.ssrcOwners.set(ssrc, endpointId);\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    setTrackMuteStatus(sourceName, muted) { // eslint-disable-line no-unused-vars\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    setTrackVideoType(sourceName, videoType) { // eslint-disable-line no-unused-vars\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    getTrackSourceName(ssrc) { // eslint-disable-line no-unused-vars\r\n        return undefined;\r\n    }\r\n\r\n    /**\r\n     * @inheritDoc\r\n     */\r\n    setTrackSourceName(ssrc, sourceName) { // eslint-disable-line no-unused-vars\r\n    }\r\n}\r\n","/**\r\n * The know jingle actions that can be sent and should be acted upon by\r\n * {@code ProxyConnectionService} and {@code ProxyConnectionPC}.\r\n */\r\nexport enum ACTIONS {\r\n    ACCEPT = 'session-accept',\r\n    CONNECTION_ERROR = 'connection-error-encountered',\r\n    INITIATE = 'session-initiate',\r\n    TERMINATE = 'session-terminate',\r\n    TRANSPORT_INFO = 'transport-info',\r\n    UNAVAILABLE = 'unavailable'\r\n};\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport RTCEvents from '../../service/RTC/RTCEvents';\r\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\r\nimport RTC from '../RTC/RTC';\r\nimport JingleSessionPC from '../xmpp/JingleSessionPC';\r\nimport { DEFAULT_STUN_SERVERS } from '../xmpp/xmpp';\r\n\r\nimport CustomSignalingLayer from './CustomSignalingLayer';\r\nimport { ACTIONS } from './constants';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * An adapter around {@code JingleSessionPC} so its logic can be re-used without\r\n * an XMPP connection. It is being re-used for consistency with the rest of the\r\n * codebase and to leverage existing peer connection event handling. Also\r\n * this class provides a facade to hide most of the API for\r\n * {@code JingleSessionPC}.\r\n */\r\nexport default class ProxyConnectionPC {\r\n    /**\r\n     * Initializes a new {@code ProxyConnectionPC} instance.\r\n     *\r\n     * @param {Object} options - Values to initialize the instance with.\r\n     * @param {Object} [options.pcConfig] - The {@code RTCConfiguration} to use for the WebRTC peer connection.\r\n     * @param {boolean} [options.isInitiator] - If true, the local client should send offers. If false, the local\r\n     * client should send answers. Defaults to false.\r\n     * @param {Function} options.onRemoteStream - Callback to invoke when a remote media stream has been received\r\n     * through the peer connection.\r\n     * @param {string} options.peerJid - The jid of the remote client with which the peer connection is being establish\r\n     * and which should receive direct messages regarding peer connection updates.\r\n     * @param {boolean} [options.receiveVideo] - Whether or not the peer connection should accept incoming video\r\n     * streams. Defaults to false.\r\n     * @param {Function} options.onSendMessage - Callback to invoke when a message has to be sent (signaled) out.\r\n     */\r\n    constructor(options = {}) {\r\n        this._options = {\r\n            pcConfig: {},\r\n            isInitiator: false,\r\n            receiveAudio: false,\r\n            receiveVideo: false,\r\n            ...options\r\n        };\r\n\r\n        /**\r\n         * Instances of {@code JitsiTrack} associated with this instance of\r\n         * {@code ProxyConnectionPC}.\r\n         *\r\n         * @type {Array<JitsiTrack>}\r\n         */\r\n        this._tracks = [];\r\n\r\n        /**\r\n         * The active instance of {@code JingleSessionPC}.\r\n         *\r\n         * @type {JingleSessionPC|null}\r\n         */\r\n        this._peerConnection = null;\r\n\r\n        // Bind event handlers so they are only bound once for every instance.\r\n        this._onError = this._onError.bind(this);\r\n        this._onRemoteStream = this._onRemoteStream.bind(this);\r\n        this._onSendMessage = this._onSendMessage.bind(this);\r\n    }\r\n\r\n    /**\r\n     * Returns the jid of the remote peer with which this peer connection should\r\n     * be established with.\r\n     *\r\n     * @returns {string}\r\n     */\r\n    getPeerJid() {\r\n        return this._options.peerJid;\r\n    }\r\n\r\n    /**\r\n     * Updates the peer connection based on the passed in jingle.\r\n     *\r\n     * @param {Object} $jingle - An XML jingle element, wrapped in query,\r\n     * describing how the peer connection should be updated.\r\n     * @returns {void}\r\n     */\r\n    processMessage($jingle) {\r\n        switch ($jingle.attr('action')) {\r\n        case ACTIONS.ACCEPT:\r\n            this._onSessionAccept($jingle);\r\n            break;\r\n\r\n        case ACTIONS.INITIATE:\r\n            this._onSessionInitiate($jingle);\r\n            break;\r\n\r\n        case ACTIONS.TERMINATE:\r\n            this._onSessionTerminate($jingle);\r\n            break;\r\n\r\n        case ACTIONS.TRANSPORT_INFO:\r\n            this._onTransportInfo($jingle);\r\n            break;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Instantiates a peer connection and starts the offer/answer cycle to\r\n     * establish a connection with a remote peer.\r\n     *\r\n     * @param {Array<JitsiLocalTrack>} localTracks - Initial local tracks to add\r\n     * to add to the peer connection.\r\n     * @returns {void}\r\n     */\r\n    start(localTracks = []) {\r\n        if (this._peerConnection) {\r\n            return;\r\n        }\r\n\r\n        this._tracks = this._tracks.concat(localTracks);\r\n\r\n        this._peerConnection = this._createPeerConnection();\r\n\r\n        this._peerConnection.invite(localTracks);\r\n    }\r\n\r\n    /**\r\n     * Begins the process of disconnecting from a remote peer and cleaning up\r\n     * the peer connection.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    stop() {\r\n        if (this._peerConnection) {\r\n            this._peerConnection.terminate();\r\n        }\r\n\r\n        this._onSessionTerminate();\r\n    }\r\n\r\n    /**\r\n     * Instantiates a new {@code JingleSessionPC} by stubbing out the various\r\n     * dependencies of {@code JingleSessionPC}.\r\n     *\r\n     * @private\r\n     * @returns {JingleSessionPC}\r\n     */\r\n    _createPeerConnection() {\r\n        /**\r\n         * {@code JingleSessionPC} takes in the entire jitsi-meet config.js\r\n         * object, which may not be accessible from the caller.\r\n         *\r\n         * @type {Object}\r\n         */\r\n        const configStub = {};\r\n\r\n        /**\r\n         * {@code JingleSessionPC} assumes an XMPP/Strophe connection object is\r\n         * passed through, which also has the jingle plugin initialized on it.\r\n         * This connection object is used to signal out peer connection updates\r\n         * via iqs, and those updates need to be piped back out to the remote\r\n         * peer.\r\n         *\r\n         * @type {Object}\r\n         */\r\n        const connectionStub = {\r\n            // At the time this is used for Spot and it's okay to say the connection is always connected, because if\r\n            // spot has no signalling it will not be in a meeting where this is used.\r\n            connected: true,\r\n            jingle: {\r\n                terminate: () => { /** no-op */ }\r\n            },\r\n            sendIQ: this._onSendMessage,\r\n\r\n            // Returns empty function, because it does not add any listeners for real\r\n            // eslint-disable-next-line no-empty-function\r\n            addEventListener: () => () => { }\r\n        };\r\n\r\n        /**\r\n         * {@code JingleSessionPC} can take in a custom ice configuration,\r\n         * depending on the peer connection type, peer-to-peer or other.\r\n         * However, {@code ProxyConnectionPC} always assume a peer-to-peer\r\n         * connection so the ice configuration is hard-coded with defaults.\r\n         *\r\n         * @type {Object}\r\n         */\r\n        const pcConfigStub = {\r\n            iceServers: DEFAULT_STUN_SERVERS,\r\n            ...this._options.pcConfig\r\n        };\r\n\r\n        /**\r\n         * {@code JingleSessionPC} expects an instance of\r\n         * {@code JitsiConference}, which has an event emitter that is used\r\n         * to signal various connection updates that the local client should\r\n         * act upon. The conference instance is not a dependency of a proxy\r\n         * connection, but the emitted events can be relevant to the proxy\r\n         * connection so the event emitter is stubbed.\r\n         *\r\n         * @param {string} event - The constant for the event type.\r\n         * @type {Function}\r\n         * @returns {void}\r\n         */\r\n        const emitter = event => {\r\n            switch (event) {\r\n            case XMPPEvents.CONNECTION_ICE_FAILED:\r\n            case XMPPEvents.CONNECTION_FAILED:\r\n                this._onError(ACTIONS.CONNECTION_ERROR, event);\r\n                break;\r\n            }\r\n        };\r\n\r\n        /**\r\n         * {@link JingleSessionPC} expects an instance of\r\n         * {@link ChatRoom} to be passed in. {@link ProxyConnectionPC}\r\n         * is instantiated outside of the {@code JitsiConference}, so it must be\r\n         * stubbed to prevent errors.\r\n         *\r\n         * @type {Object}\r\n         */\r\n        const roomStub = {\r\n            addEventListener: () => { /* no op */ },\r\n            addPresenceListener: () => { /* no-op */ },\r\n            connectionTimes: [],\r\n            eventEmitter: { emit: emitter },\r\n            removeEventListener: () => { /* no op */ },\r\n            removePresenceListener: () => { /* no-op */ },\r\n            supportsRestartByTerminate: () => false\r\n        };\r\n\r\n        /**\r\n         * A {@code JitsiConference} stub passed to the {@link RTC} module.\r\n         * @type {Object}\r\n         */\r\n        const conferenceStub = {\r\n            myUserId: () => ''\r\n        };\r\n\r\n        /**\r\n         * Create an instance of {@code RTC} as it is required for peer\r\n         * connection creation by {@code JingleSessionPC}. An existing instance\r\n         * of {@code RTC} from elsewhere should not be re-used because it is\r\n         * a stateful grouping of utilities.\r\n         */\r\n        this._rtc = new RTC(conferenceStub, {});\r\n\r\n        /**\r\n         * Add the remote track listener here as {@code JingleSessionPC} has\r\n         * {@code TraceablePeerConnection} which uses {@code RTC}'s event\r\n         * emitter.\r\n         */\r\n        this._rtc.addListener(\r\n            RTCEvents.REMOTE_TRACK_ADDED,\r\n            this._onRemoteStream\r\n        );\r\n\r\n        const peerConnection = new JingleSessionPC(\r\n            undefined, // sid\r\n            undefined, // localJid\r\n            this._options.peerJid, // remoteJid\r\n            connectionStub, // connection\r\n            {\r\n                offerToReceiveAudio: this._options.receiveAudio,\r\n                offerToReceiveVideo: this._options.receiveVideo\r\n            }, // mediaConstraints\r\n            pcConfigStub, // pcConfig\r\n            true, // isP2P\r\n            this._options.isInitiator // isInitiator\r\n        );\r\n\r\n        const signalingLayer = new CustomSignalingLayer();\r\n\r\n        signalingLayer.setChatRoom(roomStub);\r\n\r\n        /**\r\n         * An additional initialize call is necessary to properly set instance\r\n         * variable for calling.\r\n         */\r\n        peerConnection.initialize(roomStub, this._rtc, signalingLayer, configStub);\r\n\r\n        return peerConnection;\r\n    }\r\n\r\n    /**\r\n     * Invoked when a connection related issue has been encountered.\r\n     *\r\n     * @param {string} errorType - The constant indicating the type of the error\r\n     * that occured.\r\n     * @param {string} details - Optional additional data about the error.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onError(errorType, details = '') {\r\n        this._options.onError(this._options.peerJid, errorType, details);\r\n    }\r\n\r\n    /**\r\n     * Callback invoked when the peer connection has received a remote media\r\n     * stream.\r\n     *\r\n     * @param {JitsiRemoteTrack} jitsiRemoteTrack - The remote media stream\r\n     * wrapped in {@code JitsiRemoteTrack}.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onRemoteStream(jitsiRemoteTrack) {\r\n        this._tracks.push(jitsiRemoteTrack);\r\n\r\n        this._options.onRemoteStream(jitsiRemoteTrack);\r\n    }\r\n\r\n    /**\r\n     * Callback invoked when {@code JingleSessionPC} needs to signal a message\r\n     * out to the remote peer.\r\n     *\r\n     * @param {XML} iq - The message to signal out.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onSendMessage(iq) {\r\n        this._options.onSendMessage(this._options.peerJid, iq);\r\n    }\r\n\r\n    /**\r\n     * Callback invoked in response to an agreement to start a proxy connection.\r\n     * The passed in jingle element should contain an SDP answer to a previously\r\n     * sent SDP offer.\r\n     *\r\n     * @param {Object} $jingle - The jingle element wrapped in jQuery.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onSessionAccept($jingle) {\r\n        if (!this._peerConnection) {\r\n            logger.error('Received an answer when no peer connection exists.');\r\n\r\n            return;\r\n        }\r\n\r\n        this._peerConnection.setAnswer($jingle);\r\n    }\r\n\r\n    /**\r\n     * Callback invoked in response to a request to start a proxy connection.\r\n     * The passed in jingle element should contain an SDP offer.\r\n     *\r\n     * @param {Object} $jingle - The jingle element wrapped in jQuery.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onSessionInitiate($jingle) {\r\n        if (this._peerConnection) {\r\n            logger.error('Received an offer when an offer was already sent.');\r\n\r\n            return;\r\n        }\r\n\r\n        this._peerConnection = this._createPeerConnection();\r\n\r\n        this._peerConnection.acceptOffer(\r\n            $jingle,\r\n            () => { /** no-op */ },\r\n            () => this._onError(\r\n                this._options.peerJid,\r\n                ACTIONS.CONNECTION_ERROR,\r\n                'session initiate error'\r\n            )\r\n        );\r\n    }\r\n\r\n    /**\r\n     * Callback invoked in response to a request to disconnect an active proxy\r\n     * connection. Cleans up tracks and the peer connection.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onSessionTerminate() {\r\n        this._tracks.forEach(track => track.dispose());\r\n        this._tracks = [];\r\n\r\n        if (this._peerConnection) {\r\n            this._peerConnection.onTerminated();\r\n        }\r\n\r\n        if (this._rtc) {\r\n            this._rtc.removeListener(\r\n                RTCEvents.REMOTE_TRACK_ADDED,\r\n                this._onRemoteStream\r\n            );\r\n\r\n            this._rtc.destroy();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Callback invoked in response to ICE candidates from the remote peer.\r\n     * The passed in jingle element should contain an ICE candidate.\r\n     *\r\n     * @param {Object} $jingle - The jingle element wrapped in jQuery.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onTransportInfo($jingle) {\r\n        this._peerConnection.addIceCandidates($jingle);\r\n    }\r\n}\r\n","import { getLogger } from '@jitsi/logger';\r\nimport $ from 'jquery';\r\nimport { $iq } from 'strophe.js';\r\n\r\nimport { MediaType } from '../../service/RTC/MediaType';\r\nimport { VideoType } from '../../service/RTC/VideoType';\r\nimport RTC from '../RTC/RTC';\r\n\r\nimport ProxyConnectionPC from './ProxyConnectionPC';\r\nimport { ACTIONS } from './constants';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * Instantiates a new ProxyConnectionPC and ensures only one exists at a given\r\n * time. Currently it assumes ProxyConnectionPC is used only for screensharing\r\n * and assumes IQs to be used for communication.\r\n */\r\nexport default class ProxyConnectionService {\r\n    /**\r\n     * Initializes a new {@code ProxyConnectionService} instance.\r\n     *\r\n     * @param {Object} options - Values to initialize the instance with.\r\n     * @param {boolean} [options.convertVideoToDesktop] - Whether or not proxied video should be returned as a desktop\r\n     * stream. Defaults to false.\r\n     * @param {Object} [options.pcConfig] - The {@code RTCConfiguration} to use for the WebRTC peer connection.\r\n     * @param {JitsiConnection} [options.jitsiConnection] - The {@code JitsiConnection} which will be used to fetch\r\n     * TURN credentials for the P2P connection.\r\n     * @param {Function} options.onRemoteStream - Callback to invoke when a remote video stream has been received and\r\n     * converted to a {@code JitsiLocakTrack}. The {@code JitsiLocakTrack} will be passed in.\r\n     * @param {Function} options.onSendMessage - Callback to invoke when a message has to be sent (signaled) out. The\r\n     * arguments passed in are the jid to send the message to and the message.\r\n     */\r\n    constructor(options = {}) {\r\n        const {\r\n            jitsiConnection,\r\n            ...otherOptions\r\n        } = options;\r\n\r\n        /**\r\n         * Holds a reference to the collection of all callbacks.\r\n         *\r\n         * @type {Object}\r\n         */\r\n        this._options = {\r\n            pcConfig: jitsiConnection && jitsiConnection.xmpp.connection.jingle.p2pIceConfig,\r\n            ...otherOptions\r\n        };\r\n\r\n        /**\r\n         * The active instance of {@code ProxyConnectionService}.\r\n         *\r\n         * @type {ProxyConnectionPC|null}\r\n         */\r\n        this._peerConnection = null;\r\n\r\n        // Bind event handlers so they are only bound once for every instance.\r\n        this._onFatalError = this._onFatalError.bind(this);\r\n        this._onSendMessage = this._onSendMessage.bind(this);\r\n        this._onRemoteStream = this._onRemoteStream.bind(this);\r\n    }\r\n\r\n    /**\r\n     * Parses a message object regarding a proxy connection to create a new\r\n     * proxy connection or update and existing connection.\r\n     *\r\n     * @param {Object} message - A message object regarding establishing or\r\n     * updating a proxy connection.\r\n     * @param {Object} message.data - An object containing additional message\r\n     * details.\r\n     * @param {string} message.data.iq - The stringified iq which explains how\r\n     * and what to update regarding the proxy connection.\r\n     * @param {string} message.from - The message sender's full jid. Used for\r\n     * sending replies.\r\n     * @returns {void}\r\n     */\r\n    processMessage(message) {\r\n        const peerJid = message.from;\r\n\r\n        if (!peerJid) {\r\n            return;\r\n        }\r\n\r\n        // If a proxy connection has already been established and messages come\r\n        // from another peer jid then those messages should be replied to with\r\n        // a rejection.\r\n        if (this._peerConnection\r\n            && this._peerConnection.getPeerJid() !== peerJid) {\r\n            this._onFatalError(\r\n                peerJid,\r\n                ACTIONS.CONNECTION_ERROR,\r\n                'rejected'\r\n            );\r\n\r\n            return;\r\n        }\r\n\r\n        const iq = this._convertStringToXML(message.data.iq);\r\n        const $jingle = iq && iq.find('jingle');\r\n        const action = $jingle && $jingle.attr('action');\r\n\r\n        if (action === ACTIONS.INITIATE) {\r\n            this._peerConnection = this._createPeerConnection(peerJid, {\r\n                isInitiator: false,\r\n                receiveVideo: true\r\n            });\r\n        }\r\n\r\n        // Truthy check for peer connection added to protect against possibly\r\n        // receiving actions before an ACTIONS.INITIATE.\r\n        if (this._peerConnection) {\r\n            this._peerConnection.processMessage($jingle);\r\n        }\r\n\r\n        // Take additional steps to ensure the peer connection is cleaned up\r\n        // if it is to be closed.\r\n        if (action === ACTIONS.CONNECTION_ERROR\r\n            || action === ACTIONS.UNAVAILABLE\r\n            || action === ACTIONS.TERMINATE) {\r\n            this._selfCloseConnection();\r\n        }\r\n\r\n        return;\r\n    }\r\n\r\n    /**\r\n     * Instantiates and initiates a proxy peer connection.\r\n     *\r\n     * @param {string} peerJid - The jid of the remote client that should\r\n     * receive messages.\r\n     * @param {Array<JitsiLocalTrack>} localTracks - Initial media tracks to\r\n     * send through to the peer.\r\n     * @returns {void}\r\n     */\r\n    start(peerJid, localTracks = []) {\r\n        this._peerConnection = this._createPeerConnection(peerJid, {\r\n            isInitiator: true,\r\n            receiveVideo: false\r\n        });\r\n\r\n        this._peerConnection.start(localTracks);\r\n    }\r\n\r\n    /**\r\n     * Terminates any active proxy peer connection.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    stop() {\r\n        if (this._peerConnection) {\r\n            this._peerConnection.stop();\r\n        }\r\n\r\n        this._peerConnection = null;\r\n    }\r\n\r\n    /**\r\n     * Transforms a stringified xML into a XML wrapped in jQuery.\r\n     *\r\n     * @param {string} xml - The XML in string form.\r\n     * @private\r\n     * @returns {Object|null} A jQuery version of the xml. Null will be returned\r\n     * if an error is encountered during transformation.\r\n     */\r\n    _convertStringToXML(xml) {\r\n        try {\r\n            const xmlDom = new DOMParser().parseFromString(xml, 'text/xml');\r\n\r\n            return $(xmlDom);\r\n        } catch (e) {\r\n            logger.error('Attempted to convert incorrectly formatted xml');\r\n\r\n            return null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Helper for creating an instance of {@code ProxyConnectionPC}.\r\n     *\r\n     * @param {string} peerJid - The jid of the remote peer with which the\r\n     * {@code ProxyConnectionPC} will be established with.\r\n     * @param {Object} options - Additional defaults to instantiate the\r\n     * {@code ProxyConnectionPC} with. See the constructor of ProxyConnectionPC\r\n     * for more details.\r\n     * @private\r\n     * @returns {ProxyConnectionPC}\r\n     */\r\n    _createPeerConnection(peerJid, options = {}) {\r\n        if (!peerJid) {\r\n            throw new Error('Cannot create ProxyConnectionPC without a peer.');\r\n        }\r\n\r\n        const pcOptions = {\r\n            pcConfig: this._options.pcConfig,\r\n            onError: this._onFatalError,\r\n            onRemoteStream: this._onRemoteStream,\r\n            onSendMessage: this._onSendMessage,\r\n            peerJid,\r\n            ...options\r\n        };\r\n\r\n        return new ProxyConnectionPC(pcOptions);\r\n    }\r\n\r\n    /**\r\n     * Callback invoked when an error occurs that should cause\r\n     * {@code ProxyConnectionPC} to be closed if the peer is currently\r\n     * connected. Sends an error message/reply back to the peer.\r\n     *\r\n     * @param {string} peerJid - The peer jid with which the connection was\r\n     * attempted or started, and to which an iq with error details should be\r\n     * sent.\r\n     * @param {string} errorType - The constant indicating the type of the error\r\n     * that occured.\r\n     * @param {string} details - Optional additional data about the error.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onFatalError(peerJid, errorType, details = '') {\r\n        logger.error(\r\n            'Received a proxy connection error', peerJid, errorType, details);\r\n\r\n        const iq = $iq({\r\n            to: peerJid,\r\n            type: 'set'\r\n        })\r\n            .c('jingle', {\r\n                xmlns: 'urn:xmpp:jingle:1',\r\n                action: errorType\r\n            })\r\n            .c('details')\r\n            .t(details)\r\n            .up();\r\n\r\n        this._onSendMessage(peerJid, iq);\r\n\r\n        if (this._peerConnection\r\n            && this._peerConnection.getPeerJid() === peerJid) {\r\n            this._selfCloseConnection();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Callback invoked when the remote peer of the {@code ProxyConnectionPC}\r\n     * has offered a media stream. The stream is converted into a\r\n     * {@code JitsiLocalTrack} for local usage if the {@code onRemoteStream}\r\n     * callback is defined.\r\n     *\r\n     * @param {JitsiRemoteTrack} jitsiRemoteTrack - The {@code JitsiRemoteTrack}\r\n     * for the peer's media stream.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onRemoteStream(jitsiRemoteTrack) {\r\n        if (!this._options.onRemoteStream) {\r\n            logger.error('Remote track received without callback.');\r\n            jitsiRemoteTrack.dispose();\r\n\r\n            return;\r\n        }\r\n\r\n        const isVideo = jitsiRemoteTrack.isVideoTrack();\r\n        let videoType;\r\n\r\n        if (isVideo) {\r\n            videoType = this._options.convertVideoToDesktop\r\n                ? VideoType.DESKTOP : VideoType.CAMERA;\r\n        }\r\n\r\n        // Grab the webrtc media stream and pipe it through the same processing\r\n        // that would occur for a locally obtained media stream.\r\n        const mediaStream = jitsiRemoteTrack.getOriginalStream();\r\n        const jitsiLocalTracks = RTC.createLocalTracks(\r\n            [\r\n                {\r\n                    deviceId:\r\n                        `proxy:${this._peerConnection.getPeerJid()}`,\r\n                    mediaType: isVideo ? MediaType.VIDEO : MediaType.AUDIO,\r\n                    sourceType: 'proxy',\r\n                    stream: mediaStream,\r\n                    track: mediaStream.getVideoTracks()[0],\r\n                    videoType\r\n                }\r\n            ]);\r\n\r\n        this._options.onRemoteStream(jitsiLocalTracks[0]);\r\n    }\r\n\r\n    /**\r\n     * Formats and forwards a message an iq to be sent to a peer jid.\r\n     *\r\n     * @param {string} peerJid - The jid the iq should be sent to.\r\n     * @param {Object} iq - The iq which would be sent to the peer jid.\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _onSendMessage(peerJid, iq) {\r\n        if (!this._options.onSendMessage) {\r\n            return;\r\n        }\r\n\r\n        try {\r\n            const stringifiedIq\r\n                = new XMLSerializer().serializeToString(iq.nodeTree || iq);\r\n\r\n            this._options.onSendMessage(peerJid, { iq: stringifiedIq });\r\n        } catch (e) {\r\n            logger.error('Attempted to send an incorrectly formatted iq.');\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Invoked when preemptively closing the {@code ProxyConnectionPC}.\r\n     *\r\n     * @private\r\n     * @returns {void}\r\n     */\r\n    _selfCloseConnection() {\r\n        this.stop();\r\n\r\n        this._options.onConnectionClosed\r\n            && this._options.onConnectionClosed();\r\n    }\r\n}\r\n","import EventEmitter from 'events';\r\n\r\nimport browser from '../browser';\r\nimport Settings from '../settings/Settings';\r\nimport ScriptUtil from '../util/ScriptUtil';\r\n\r\nimport { CALLSTATS_SCRIPT_URL } from './constants';\r\n\r\nconst PRECALL_TEST_RESULTS = 'preCallTestResults';\r\nconst emitter = new EventEmitter();\r\nlet _initialized = false;\r\nlet api = null;\r\n\r\n/**\r\n * Loads the callstats io script.\r\n *\r\n * @returns {Promise<void>}\r\n */\r\nfunction _loadScript(options) {\r\n    if (browser.isReactNative()) {\r\n        return;\r\n    }\r\n\r\n    return new Promise(resolve => {\r\n        ScriptUtil.loadScript(\r\n            options.callStatsCustomScriptUrl || CALLSTATS_SCRIPT_URL,\r\n            /* async */ true,\r\n            /* prepend */ true,\r\n            /* relativeURL */ undefined,\r\n            /* loadCallback */ resolve);\r\n    });\r\n}\r\n\r\n/**\r\n * Initializes the callstats lib and registers a callback to be invoked\r\n * when there are 'preCallTestResults'.\r\n *\r\n * @typedef PrecallTestOptions\r\n * @type {Object}\r\n * @property {string} callStatsID - Callstats credentials - the id.\r\n * @property {string} callStatsSecret - Callstats credentials - the secret.\r\n * @property {string} statisticsId - The user name to use when initializing callstats.\r\n * @property {string} statisticsDisplayName - The user display name.\r\n *\r\n * @param { PrecallTestOptions} options - The init options.\r\n * @returns {Promise<void>}\r\n */\r\nfunction _initialize(options) {\r\n    return new Promise((resolve, reject) => {\r\n        const appId = options.callStatsID;\r\n        const appSecret = options.callStatsSecret;\r\n        const userId = options.statisticsId || options.statisticsDisplayName || Settings.callStatsUserName;\r\n\r\n        api.initialize(appId, appSecret, userId, (status, message) => {\r\n            if (status === 'success') {\r\n                api.on(PRECALL_TEST_RESULTS, (...args) => {\r\n                    emitter.emit(PRECALL_TEST_RESULTS, ...args);\r\n                });\r\n                _initialized = true;\r\n                resolve();\r\n            } else {\r\n                reject({\r\n                    status,\r\n                    message\r\n                });\r\n            }\r\n        }, null, { disablePrecalltest: true });\r\n    });\r\n}\r\n\r\n/**\r\n * Loads the callstats script and initializes the library.\r\n *\r\n * @param {Function} onResult - The callback to be invoked when results are received.\r\n * @returns {Promise<void>}\r\n */\r\nexport async function init(options) {\r\n    if (_initialized) {\r\n        throw new Error('Precall Test already initialized');\r\n    }\r\n\r\n    const { callStatsID, callStatsSecret, disableThirdPartyRequests } = options;\r\n\r\n    if (!callStatsID || !callStatsSecret || disableThirdPartyRequests) {\r\n        throw new Error('Callstats is disabled');\r\n    }\r\n\r\n    await _loadScript(options);\r\n    // eslint-disable-next-line new-cap\r\n    api = new window.callstats();\r\n\r\n    return _initialize(options);\r\n}\r\n\r\n/**\r\n * Executes a pre call test.\r\n *\r\n * @typedef PrecallTestResults\r\n * @type {Object}\r\n * @property {boolean} mediaConnectivity - If there is media connectivity or not.\r\n * @property {number} throughput  - The average throughput.\r\n * @property {number} fractionalLoss - The packet loss.\r\n * @property {number} rtt - The round trip time.\r\n * @property {string} provider - It is usually 'callstats'.\r\n *\r\n * @returns {Promise<{PrecallTestResults}>}\r\n */\r\nexport function execute() {\r\n    if (!_initialized) {\r\n        return Promise.reject('uninitialized');\r\n    }\r\n\r\n    return new Promise((resolve, reject) => {\r\n        emitter.on(PRECALL_TEST_RESULTS, (status, payload) => {\r\n            if (status === 'success') {\r\n                resolve(payload);\r\n            } else {\r\n                reject({\r\n                    status,\r\n                    payload\r\n                });\r\n            }\r\n\r\n        });\r\n\r\n        api.makePrecallTest();\r\n    });\r\n}\r\n\r\nexport default {\r\n    init,\r\n    execute\r\n};\r\n","import { getLogger } from '@jitsi/logger';\r\n\r\nimport { createAudioContext } from './WebAudioUtils';\r\n\r\nconst logger = getLogger(__filename);\r\n\r\n/**\r\n * The AudioMixer, as the name implies, mixes a number of MediaStreams containing audio tracks into a single\r\n * MediaStream.\r\n */\r\nexport default class AudioMixer {\r\n    /**\r\n     * Create AudioMixer instance.\r\n     */\r\n    constructor() {\r\n        this._started = false;\r\n        this._streamsToMix = [];\r\n        this._streamMSSArray = [];\r\n    }\r\n\r\n    /**\r\n     * Add audio MediaStream to be mixed, if the stream doesn't contain any audio tracks it will be ignored.\r\n     *\r\n     * @param {MediaStream} stream - MediaStream to be mixed.\r\n     */\r\n    addMediaStream(stream) {\r\n        if (!stream.getAudioTracks()) {\r\n            logger.warn('Added MediaStream doesn\\'t contain audio tracks.');\r\n        }\r\n\r\n        this._streamsToMix.push(stream);\r\n    }\r\n\r\n    /**\r\n     * At this point a WebAudio ChannelMergerNode is created and and the two associated MediaStreams are connected to\r\n     * it; the resulting mixed MediaStream is returned.\r\n     *\r\n     * @returns {MediaStream} - MediaStream containing added streams mixed together, or null if no MediaStream\r\n     * is added.\r\n     */\r\n    start() {\r\n        // If the mixer was already started just return the existing mixed stream.\r\n        if (this._started) {\r\n            return this._mixedMSD.stream;\r\n        }\r\n\r\n        this._audioContext = createAudioContext();\r\n\r\n        if (!this._streamsToMix.length) {\r\n            logger.warn('No MediaStream\\'s added to AudioMixer, nothing will happen.');\r\n\r\n            return null;\r\n        }\r\n\r\n        this._started = true;\r\n\r\n        this._mixedMSD = this._audioContext.createMediaStreamDestination();\r\n\r\n        for (const stream of this._streamsToMix) {\r\n            const streamMSS = this._audioContext.createMediaStreamSource(stream);\r\n\r\n            streamMSS.connect(this._mixedMSD);\r\n\r\n            // Maintain a list of MediaStreamAudioSourceNode so we can disconnect them on reset.\r\n            this._streamMSSArray.push(streamMSS);\r\n        }\r\n\r\n        return this._mixedMSD.stream;\r\n    }\r\n\r\n    /**\r\n     * Disconnect MediaStreamAudioSourceNode and clear references.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    reset() {\r\n        this._started = false;\r\n        this._streamsToMix = [];\r\n\r\n        // Clean up created MediaStreamAudioSourceNode.\r\n        for (const streamMSS of this._streamMSSArray) {\r\n            streamMSS.disconnect();\r\n        }\r\n\r\n        this._streamMSSArray = [];\r\n\r\n        if (this._audioContext) {\r\n            this._audioContext = undefined;\r\n        }\r\n    }\r\n}\r\n","import Logger from '@jitsi/logger';\r\n\r\nimport * as JitsiConferenceErrors from './JitsiConferenceErrors';\r\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\r\nimport JitsiConnection from './JitsiConnection';\r\nimport * as JitsiConnectionErrors from './JitsiConnectionErrors';\r\nimport * as JitsiConnectionEvents from './JitsiConnectionEvents';\r\nimport JitsiMediaDevices from './JitsiMediaDevices';\r\nimport * as JitsiMediaDevicesEvents from './JitsiMediaDevicesEvents';\r\nimport JitsiTrackError from './JitsiTrackError';\r\nimport * as JitsiTrackErrors from './JitsiTrackErrors';\r\nimport * as JitsiTrackEvents from './JitsiTrackEvents';\r\nimport * as JitsiTranscriptionStatus from './JitsiTranscriptionStatus';\r\nimport RTC from './modules/RTC/RTC';\r\nimport browser from './modules/browser';\r\nimport NetworkInfo from './modules/connectivity/NetworkInfo';\r\nimport { TrackStreamingStatus } from './modules/connectivity/TrackStreamingStatus';\r\nimport getActiveAudioDevice from './modules/detection/ActiveDeviceDetector';\r\nimport * as DetectionEvents from './modules/detection/DetectionEvents';\r\nimport TrackVADEmitter from './modules/detection/TrackVADEmitter';\r\nimport FeatureFlags from './modules/flags/FeatureFlags';\r\nimport ProxyConnectionService\r\n    from './modules/proxyconnection/ProxyConnectionService';\r\nimport recordingConstants from './modules/recording/recordingConstants';\r\nimport Settings from './modules/settings/Settings';\r\nimport LocalStatsCollector from './modules/statistics/LocalStatsCollector';\r\nimport precallTest from './modules/statistics/PrecallTest';\r\nimport Statistics from './modules/statistics/statistics';\r\nimport AuthUtil from './modules/util/AuthUtil';\r\nimport GlobalOnErrorHandler from './modules/util/GlobalOnErrorHandler';\r\nimport ScriptUtil from './modules/util/ScriptUtil';\r\nimport * as VideoSIPGWConstants from './modules/videosipgw/VideoSIPGWConstants';\r\nimport AudioMixer from './modules/webaudio/AudioMixer';\r\nimport { MediaType } from './service/RTC/MediaType';\r\nimport * as ConnectionQualityEvents\r\n    from './service/connectivity/ConnectionQualityEvents';\r\nimport * as E2ePingEvents from './service/e2eping/E2ePingEvents';\r\nimport { createGetUserMediaEvent } from './service/statistics/AnalyticsEvents';\r\n\r\nconst logger = Logger.getLogger(__filename);\r\n\r\n/**\r\n * The amount of time to wait until firing\r\n * {@link JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN} event.\r\n */\r\nconst USER_MEDIA_SLOW_PROMISE_TIMEOUT = 1000;\r\n\r\n/**\r\n * Extracts from an 'options' objects with a specific format (TODO what IS the\r\n * format?) the attributes which are to be logged in analytics events.\r\n *\r\n * @param options gum options (???)\r\n * @returns {*} the attributes to attach to analytics events.\r\n */\r\nfunction getAnalyticsAttributesFromOptions(options) {\r\n    const attributes: any = {};\r\n\r\n    attributes['audio_requested'] = options.devices.includes('audio');\r\n    attributes['video_requested'] = options.devices.includes('video');\r\n    attributes['screen_sharing_requested'] = options.devices.includes('desktop');\r\n\r\n    if (attributes.video_requested) {\r\n        attributes.resolution = options.resolution;\r\n    }\r\n\r\n    return attributes;\r\n}\r\n\r\ninterface ICreateLocalTrackOptions {\r\n    cameraDeviceId?: string;\r\n    devices?: any[];\r\n    firePermissionPromptIsShownEvent?: boolean;\r\n    fireSlowPromiseEvent?: boolean;\r\n    micDeviceId?: string;\r\n    resolution?: string;\r\n}\r\n\r\ninterface IJitsiMeetJSOptions {\r\n    enableAnalyticsLogging?: boolean;\r\n    enableUnifiedOnChrome?: boolean;\r\n    enableWindowOnErrorHandler?: boolean;\r\n    externalStorage?: Storage;\r\n    flags?: {\r\n        runInLiteMode?: boolean;\r\n        ssrcRewritingEnabled?: boolean;\r\n    }\r\n}\r\n\r\n/**\r\n * The public API of the Jitsi Meet library (a.k.a. {@code JitsiMeetJS}).\r\n */\r\nexport default {\r\n\r\n    version: '{#COMMIT_HASH#}',\r\n\r\n    JitsiConnection,\r\n\r\n    /**\r\n     * {@code ProxyConnectionService} is used to connect a remote peer to a\r\n     * local Jitsi participant without going through a Jitsi conference. It is\r\n     * currently used for room integration development, specifically wireless\r\n     * screensharing. Its API is experimental and will likely change; usage of\r\n     * it is advised against.\r\n     */\r\n    ProxyConnectionService,\r\n\r\n    constants: {\r\n        recording: recordingConstants,\r\n        sipVideoGW: VideoSIPGWConstants,\r\n        transcriptionStatus: JitsiTranscriptionStatus,\r\n        trackStreamingStatus: TrackStreamingStatus\r\n    },\r\n    events: {\r\n        conference: JitsiConferenceEvents,\r\n        connection: JitsiConnectionEvents,\r\n        detection: DetectionEvents,\r\n        track: JitsiTrackEvents,\r\n        mediaDevices: JitsiMediaDevicesEvents,\r\n        connectionQuality: ConnectionQualityEvents,\r\n        e2eping: E2ePingEvents\r\n    },\r\n    errors: {\r\n        conference: JitsiConferenceErrors,\r\n        connection: JitsiConnectionErrors,\r\n        track: JitsiTrackErrors\r\n    },\r\n    errorTypes: {\r\n        JitsiTrackError\r\n    },\r\n    logLevels: Logger.levels,\r\n    mediaDevices: JitsiMediaDevices as unknown,\r\n    analytics: Statistics.analytics as unknown,\r\n    init(options: IJitsiMeetJSOptions = {}) {\r\n        Settings.init(options.externalStorage);\r\n        Statistics.init(options);\r\n        const flags = options.flags || {};\r\n\r\n        // Configure the feature flags.\r\n        FeatureFlags.init(flags);\r\n\r\n        // Initialize global window.connectionTimes\r\n        // FIXME do not use 'window'\r\n        if (!window.connectionTimes) {\r\n            window.connectionTimes = {};\r\n        }\r\n\r\n        if (options.enableAnalyticsLogging !== true) {\r\n            logger.warn('Analytics disabled, disposing.');\r\n            this.analytics.dispose();\r\n        }\r\n\r\n        if (options.enableWindowOnErrorHandler) {\r\n            GlobalOnErrorHandler.addHandler(\r\n                this.getGlobalOnErrorHandler.bind(this));\r\n        }\r\n\r\n        if (this.version) {\r\n            const logObject = {\r\n                id: 'component_version',\r\n                component: 'lib-jitsi-meet',\r\n                version: this.version\r\n            };\r\n\r\n            Statistics.sendLog(JSON.stringify(logObject));\r\n        }\r\n\r\n        return RTC.init(options);\r\n    },\r\n\r\n    /**\r\n     * Returns whether the desktop sharing is enabled or not.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isDesktopSharingEnabled() {\r\n        return RTC.isDesktopSharingEnabled();\r\n    },\r\n\r\n    /**\r\n     * Returns whether the current execution environment supports WebRTC (for\r\n     * use within this library).\r\n     *\r\n     * @returns {boolean} {@code true} if WebRTC is supported in the current\r\n     * execution environment (for use within this library); {@code false},\r\n     * otherwise.\r\n     */\r\n    isWebRtcSupported() {\r\n        return RTC.isWebRtcSupported();\r\n    },\r\n\r\n    setLogLevel(level) {\r\n        Logger.setLogLevel(level);\r\n    },\r\n\r\n    /**\r\n     * Sets the log level to the <tt>Logger</tt> instance with given id.\r\n     *\r\n     * @param {Logger.levels} level the logging level to be set\r\n     * @param {string} id the logger id to which new logging level will be set.\r\n     * Usually it's the name of the JavaScript source file including the path\r\n     * ex. \"modules/xmpp/ChatRoom.js\"\r\n     */\r\n    setLogLevelById(level, id) {\r\n        Logger.setLogLevelById(level, id);\r\n    },\r\n\r\n    /**\r\n     * Registers new global logger transport to the library logging framework.\r\n     *\r\n     * @param globalTransport\r\n     * @see Logger.addGlobalTransport\r\n     */\r\n    addGlobalLogTransport(globalTransport) {\r\n        Logger.addGlobalTransport(globalTransport);\r\n    },\r\n\r\n    /**\r\n     * Removes global logging transport from the library logging framework.\r\n     *\r\n     * @param globalTransport\r\n     * @see Logger.removeGlobalTransport\r\n     */\r\n    removeGlobalLogTransport(globalTransport) {\r\n        Logger.removeGlobalTransport(globalTransport);\r\n    },\r\n\r\n    /**\r\n    * Sets global options which will be used by all loggers. Changing these\r\n    * works even after other loggers are created.\r\n    *\r\n    * @param options\r\n    * @see Logger.setGlobalOptions\r\n    */\r\n    setGlobalLogOptions(options) {\r\n        Logger.setGlobalOptions(options);\r\n    },\r\n\r\n    /**\r\n     * Creates the media tracks and returns them trough the callback.\r\n     *\r\n     * @param options Object with properties / settings specifying the tracks\r\n     * which should be created. should be created or some additional\r\n     * configurations about resolution for example.\r\n     * @param {Array} options.effects optional effects array for the track\r\n     * @param {boolean} options.firePermissionPromptIsShownEvent - if event\r\n     * JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN should be fired\r\n     * @param {boolean} options.fireSlowPromiseEvent - if event\r\n     * JitsiMediaDevicesEvents.USER_MEDIA_SLOW_PROMISE_TIMEOUT should be fired\r\n     * @param {Array} options.devices the devices that will be requested\r\n     * @param {string} options.resolution resolution constraints\r\n     * @param {string} options.cameraDeviceId\r\n     * @param {string} options.micDeviceId\r\n     * @param {intiger} interval - the interval (in ms) for\r\n     * checking whether the desktop sharing extension is installed or not\r\n     * @param {Function} checkAgain - returns boolean. While checkAgain()==true\r\n     * createLocalTracks will wait and check on every \"interval\" ms for the\r\n     * extension. If the desktop extension is not install and checkAgain()==true\r\n     * createLocalTracks will finish with rejected Promise.\r\n     * @param {Function} listener - The listener will be called to notify the\r\n     * user of lib-jitsi-meet that createLocalTracks is starting external\r\n     * extension installation process.\r\n     * NOTE: If the inline installation process is not possible and external\r\n     * installation is enabled the listener property will be called to notify\r\n     * the start of external installation process. After that createLocalTracks\r\n     * will start to check for the extension on every interval ms until the\r\n     * plugin is installed or until checkAgain return false. If the extension\r\n     * is found createLocalTracks will try to get the desktop sharing track and\r\n     * will finish the execution. If checkAgain returns false, createLocalTracks\r\n     * will finish the execution with rejected Promise.\r\n     *\r\n     * @deprecated old firePermissionPromptIsShownEvent\r\n     * @returns {Promise.<{Array.<JitsiTrack>}, JitsiConferenceError>} A promise\r\n     * that returns an array of created JitsiTracks if resolved, or a\r\n     * JitsiConferenceError if rejected.\r\n     */\r\n    createLocalTracks(options: ICreateLocalTrackOptions = {}, oldfirePermissionPromptIsShownEvent) {\r\n        let promiseFulfilled = false;\r\n\r\n        const { firePermissionPromptIsShownEvent, fireSlowPromiseEvent, ...restOptions } = options;\r\n        const firePermissionPrompt = firePermissionPromptIsShownEvent || oldfirePermissionPromptIsShownEvent;\r\n\r\n        if (firePermissionPrompt && !RTC.arePermissionsGrantedForAvailableDevices()) {\r\n            // @ts-ignore\r\n            JitsiMediaDevices.emitEvent(JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN, browser.getName());\r\n        } else if (fireSlowPromiseEvent) {\r\n            window.setTimeout(() => {\r\n                if (!promiseFulfilled) {\r\n                    JitsiMediaDevices.emitEvent(JitsiMediaDevicesEvents.SLOW_GET_USER_MEDIA);\r\n                }\r\n            }, USER_MEDIA_SLOW_PROMISE_TIMEOUT);\r\n        }\r\n\r\n        if (!window.connectionTimes) {\r\n            window.connectionTimes = {};\r\n        }\r\n        window.connectionTimes['obtainPermissions.start']\r\n            = window.performance.now();\r\n\r\n        return RTC.obtainAudioAndVideoPermissions(restOptions)\r\n            .then(tracks => {\r\n                promiseFulfilled = true;\r\n\r\n                window.connectionTimes['obtainPermissions.end']\r\n                    = window.performance.now();\r\n\r\n                Statistics.sendAnalytics(\r\n                    createGetUserMediaEvent(\r\n                        'success',\r\n                        getAnalyticsAttributesFromOptions(restOptions)));\r\n\r\n                if (!RTC.options.disableAudioLevels) {\r\n                    for (let i = 0; i < tracks.length; i++) {\r\n                        const track = tracks[i];\r\n\r\n                        if (track.getType() === MediaType.AUDIO) {\r\n                            Statistics.startLocalStats(track,\r\n                                track.setAudioLevel.bind(track));\r\n                        }\r\n                    }\r\n                }\r\n\r\n                // set real device ids\r\n                const currentlyAvailableMediaDevices\r\n                    = RTC.getCurrentlyAvailableMediaDevices();\r\n\r\n                if (currentlyAvailableMediaDevices) {\r\n                    for (let i = 0; i < tracks.length; i++) {\r\n                        const track = tracks[i];\r\n\r\n                        track._setRealDeviceIdFromDeviceList(\r\n                            currentlyAvailableMediaDevices);\r\n                    }\r\n                }\r\n\r\n                // set the contentHint to \"detail\" for desktop tracks\r\n                // eslint-disable-next-line prefer-const\r\n                for (const track of tracks) {\r\n                    if (track.type === MediaType.VIDEO\r\n                        && track.videoType === 'desktop') {\r\n                        this.setVideoTrackContentHints(track.track, 'detail');\r\n                    }\r\n                }\r\n\r\n                return tracks;\r\n            })\r\n            .catch(error => {\r\n                promiseFulfilled = true;\r\n\r\n                if (error.name === JitsiTrackErrors.SCREENSHARING_USER_CANCELED) {\r\n                    // User cancelled action is not really an error, so only\r\n                    // log it as an event to avoid having conference classified\r\n                    // as partially failed\r\n                    const logObject = {\r\n                        id: 'screensharing_user_canceled',\r\n                        message: error.message\r\n                    };\r\n\r\n                    Statistics.sendLog(JSON.stringify(logObject));\r\n\r\n                    Statistics.sendAnalytics(\r\n                        createGetUserMediaEvent(\r\n                            'warning',\r\n                            {\r\n                                reason: 'extension install user canceled'\r\n                            }));\r\n                } else if (error.name === JitsiTrackErrors.NOT_FOUND) {\r\n                    // logs not found devices with just application log to cs\r\n                    const logObject = {\r\n                        id: 'usermedia_missing_device',\r\n                        status: error.gum.devices\r\n                    };\r\n\r\n                    Statistics.sendLog(JSON.stringify(logObject));\r\n\r\n                    const attributes\r\n                        = getAnalyticsAttributesFromOptions(options);\r\n\r\n                    attributes.reason = 'device not found';\r\n                    attributes.devices = error.gum.devices.join('.');\r\n                    Statistics.sendAnalytics(\r\n                        createGetUserMediaEvent('error', attributes));\r\n                } else {\r\n                    // Report gUM failed to the stats\r\n                    Statistics.sendGetUserMediaFailed(error);\r\n\r\n                    const attributes\r\n                        = getAnalyticsAttributesFromOptions(options);\r\n\r\n                    attributes.reason = error.name;\r\n                    Statistics.sendAnalytics(\r\n                        createGetUserMediaEvent('error', attributes));\r\n                }\r\n\r\n                window.connectionTimes['obtainPermissions.end']\r\n                    = window.performance.now();\r\n\r\n                return Promise.reject(error);\r\n            });\r\n    },\r\n\r\n    /**\r\n     * Create a TrackVADEmitter service that connects an audio track to an VAD (voice activity detection) processor in\r\n     * order to obtain VAD scores for individual PCM audio samples.\r\n     * @param {string} localAudioDeviceId - The target local audio device.\r\n     * @param {number} sampleRate - Sample rate at which the emitter will operate. Possible values  256, 512, 1024,\r\n     * 4096, 8192, 16384. Passing other values will default to closes neighbor.\r\n     * I.e. Providing a value of 4096 means that the emitter will process 4096 PCM samples at a time, higher values mean\r\n     * longer calls, lowers values mean more calls but shorter.\r\n     * @param {Object} vadProcessor - VAD Processors that does the actual compute on a PCM sample.The processor needs\r\n     * to implement the following functions:\r\n     * - <tt>getSampleLength()</tt> - Returns the sample size accepted by calculateAudioFrameVAD.\r\n     * - <tt>getRequiredPCMFrequency()</tt> - Returns the PCM frequency at which the processor operates.\r\n     * i.e. (16KHz, 44.1 KHz etc.)\r\n     * - <tt>calculateAudioFrameVAD(pcmSample)</tt> - Process a 32 float pcm sample of getSampleLength size.\r\n     * @returns {Promise<TrackVADEmitter>}\r\n     */\r\n    createTrackVADEmitter(localAudioDeviceId, sampleRate, vadProcessor) {\r\n        return TrackVADEmitter.create(localAudioDeviceId, sampleRate, vadProcessor);\r\n    },\r\n\r\n    /**\r\n     * Create AudioMixer, which is essentially a wrapper over web audio ChannelMergerNode. It essentially allows the\r\n     * user to mix multiple MediaStreams into a single one.\r\n     *\r\n     * @returns {AudioMixer}\r\n     */\r\n    createAudioMixer() {\r\n        return new AudioMixer();\r\n    },\r\n\r\n    /**\r\n     * Go through all audio devices on the system and return one that is active, i.e. has audio signal.\r\n     *\r\n     * @returns Promise<Object> - Object containing information about the found device.\r\n     */\r\n    getActiveAudioDevice() {\r\n        return getActiveAudioDevice();\r\n    },\r\n\r\n    /**\r\n     * Checks if its possible to enumerate available cameras/microphones.\r\n     *\r\n     * @returns {Promise<boolean>} a Promise which will be resolved only once\r\n     * the WebRTC stack is ready, either with true if the device listing is\r\n     * available available or with false otherwise.\r\n     * @deprecated use JitsiMeetJS.mediaDevices.isDeviceListAvailable instead\r\n     */\r\n    isDeviceListAvailable() {\r\n        logger.warn('This method is deprecated, use '\r\n            + 'JitsiMeetJS.mediaDevices.isDeviceListAvailable instead');\r\n\r\n        return this.mediaDevices.isDeviceListAvailable();\r\n    },\r\n\r\n    /**\r\n     * Returns true if changing the input (camera / microphone) or output\r\n     * (audio) device is supported and false if not.\r\n     *\r\n     * @param {string} [deviceType] - type of device to change. Default is\r\n     * {@code undefined} or 'input', 'output' - for audio output device change.\r\n     * @returns {boolean} {@code true} if available; {@code false}, otherwise.\r\n     * @deprecated use JitsiMeetJS.mediaDevices.isDeviceChangeAvailable instead\r\n     */\r\n    isDeviceChangeAvailable(deviceType) {\r\n        logger.warn('This method is deprecated, use '\r\n            + 'JitsiMeetJS.mediaDevices.isDeviceChangeAvailable instead');\r\n\r\n        return this.mediaDevices.isDeviceChangeAvailable(deviceType);\r\n    },\r\n\r\n\r\n    /**\r\n     * Checks if the current environment supports having multiple audio\r\n     * input devices in use simultaneously.\r\n     *\r\n     * @returns {boolean} True if multiple audio input devices can be used.\r\n     */\r\n    isMultipleAudioInputSupported() {\r\n        return this.mediaDevices.isMultipleAudioInputSupported();\r\n    },\r\n\r\n    /**\r\n     * Checks if local tracks can collect stats and collection is enabled.\r\n     *\r\n     * @param {boolean} True if stats are being collected for local tracks.\r\n     */\r\n    isCollectingLocalStats() {\r\n        return Statistics.audioLevelsEnabled\r\n            && LocalStatsCollector.isLocalStatsSupported();\r\n    },\r\n\r\n    /**\r\n     * Executes callback with list of media devices connected.\r\n     *\r\n     * @param {function} callback\r\n     * @deprecated use JitsiMeetJS.mediaDevices.enumerateDevices instead\r\n     */\r\n    enumerateDevices(callback) {\r\n        logger.warn('This method is deprecated, use '\r\n            + 'JitsiMeetJS.mediaDevices.enumerateDevices instead');\r\n        this.mediaDevices.enumerateDevices(callback);\r\n    },\r\n\r\n    /* eslint-disable max-params */\r\n\r\n    /**\r\n     * @returns function that can be used to be attached to window.onerror and\r\n     * if options.enableWindowOnErrorHandler is enabled returns\r\n     * the function used by the lib.\r\n     * (function(message, source, lineno, colno, error)).\r\n     */\r\n    getGlobalOnErrorHandler(message, source, lineno, colno, error) {\r\n        logger.error(\r\n            `UnhandledError: ${message}`,\r\n            `Script: ${source}`,\r\n            `Line: ${lineno}`,\r\n            `Column: ${colno}`,\r\n            'StackTrace: ', error);\r\n        Statistics.reportGlobalError(error);\r\n    },\r\n\r\n    /**\r\n     * Informs lib-jitsi-meet about the current network status.\r\n     *\r\n     * @param {object} state - The network info state.\r\n     * @param {boolean} state.isOnline - {@code true} if the internet connectivity is online or {@code false}\r\n     * otherwise.\r\n     */\r\n    setNetworkInfo({ isOnline }) {\r\n        NetworkInfo.updateNetworkInfo({ isOnline });\r\n    },\r\n\r\n    /**\r\n     * Set the contentHint on the transmitted stream track to indicate\r\n     * charaterstics in the video stream, which informs PeerConnection\r\n     * on how to encode the track (to prefer motion or individual frame detail)\r\n     * @param {MediaStreamTrack} track - the track that is transmitted\r\n     * @param {String} hint - contentHint value that needs to be set on the track\r\n     */\r\n    setVideoTrackContentHints(track, hint) {\r\n        if ('contentHint' in track) {\r\n            track.contentHint = hint;\r\n            if (track.contentHint !== hint) {\r\n                logger.debug('Invalid video track contentHint');\r\n            }\r\n        } else {\r\n            logger.debug('MediaStreamTrack contentHint attribute not supported');\r\n        }\r\n    },\r\n\r\n    precallTest,\r\n\r\n    /* eslint-enable max-params */\r\n\r\n    /**\r\n     * Represents a hub/namespace for utility functionality which may be of\r\n     * interest to lib-jitsi-meet clients.\r\n     */\r\n    util: {\r\n        AuthUtil,\r\n        ScriptUtil,\r\n        browser\r\n    }\r\n};\r\n","export default {\r\n    error: {\r\n        BUSY: 'busy',\r\n        ERROR: 'error',\r\n        RESOURCE_CONSTRAINT: 'resource-constraint',\r\n        UNEXPECTED_REQUEST: 'unexpected-request',\r\n        SERVICE_UNAVAILABLE: 'service-unavailable'\r\n    },\r\n    mode: {\r\n        FILE: 'file',\r\n        STREAM: 'stream'\r\n    },\r\n    status: {\r\n        OFF: 'off',\r\n        ON: 'on',\r\n        PENDING: 'pending'\r\n    }\r\n};\r\n","const ljm = require('./JitsiMeetJS').default;\r\n\r\n/**\r\n * Tries to deal with the following problem: {@code JitsiMeetJS} is not only\r\n * this module, it's also a global (i.e. attached to {@code window}) namespace\r\n * for all globals of the projects in the Jitsi Meet family. If lib-jitsi-meet\r\n * is loaded through an HTML {@code script} tag, {@code JitsiMeetJS} will\r\n * automatically be attached to {@code window} by webpack. Unfortunately,\r\n * webpack's source code does not check whether the global variable has already\r\n * been assigned and overwrites it. Which is OK for the module\r\n * {@code JitsiMeetJS} but is not OK for the namespace {@code JitsiMeetJS}\r\n * because it may already contain the values of other projects in the Jitsi Meet\r\n * family. The solution offered here works around webpack by merging all\r\n * existing values of the namespace {@code JitsiMeetJS} into the module\r\n * {@code JitsiMeetJS}.\r\n *\r\n * @param {Object} module - The module {@code JitsiMeetJS} (which will be\r\n * exported and may be attached to {@code window} by webpack later on).\r\n * @private\r\n * @returns {Object} - A {@code JitsiMeetJS} module which contains all existing\r\n * value of the namespace {@code JitsiMeetJS} (if any).\r\n */\r\nfunction _mergeNamespaceAndModule(module) {\r\n    return (\r\n        typeof window.JitsiMeetJS === 'object'\r\n            ? Object.assign({}, window.JitsiMeetJS, module)\r\n            : module);\r\n}\r\n\r\nmodule.exports = _mergeNamespaceAndModule(ljm);\r\n","/**\r\n * A model for keeping track of each user's total\r\n * time as a dominant speaker. The model also\r\n * keeps track of the user's last known name\r\n * in case the user has left the meeting,\r\n * which is also tracked.\r\n */\r\nclass SpeakerStats {\r\n    /**\r\n     * Initializes a new SpeakerStats instance.\r\n     *\r\n     * @constructor\r\n     * @param {string} userId - The id of the user being tracked.\r\n     * @param {string} displayName - The name of the user being tracked.\r\n     * @param {boolean} isLocalStats - True if the stats model tracks\r\n     * the local user.\r\n     * @returns {void}\r\n     */\r\n    constructor(userId, displayName, isLocalStats) {\r\n        this._userId = userId;\r\n        this.setDisplayName(displayName);\r\n        this._isLocalStats = isLocalStats || false;\r\n        this.setDominantSpeaker(false);\r\n        this.totalDominantSpeakerTime = 0;\r\n        this._dominantSpeakerStart = 0;\r\n        this._isDominantSpeaker = false;\r\n        this._isSilent = false;\r\n        this._hasLeft = false;\r\n        this._faceExpressions = {\r\n            happy: 0,\r\n            neutral: 0,\r\n            surprised: 0,\r\n            angry: 0,\r\n            fearful: 0,\r\n            disgusted: 0,\r\n            sad: 0\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Get the user id being tracked.\r\n     *\r\n     * @returns {string} The user id.\r\n     */\r\n    getUserId() {\r\n        return this._userId;\r\n    }\r\n\r\n    /**\r\n     * Get the name of the user being tracked.\r\n     *\r\n     * @returns {string} The user name.\r\n     */\r\n    getDisplayName() {\r\n        return this.displayName;\r\n    }\r\n\r\n    /**\r\n     * Updates the last known name of the user being tracked.\r\n     *\r\n     * @param {string} - The user name.\r\n     * @returns {void}\r\n     */\r\n    setDisplayName(newName) {\r\n        this.displayName = newName;\r\n    }\r\n\r\n    /**\r\n     * Returns true if the stats are tracking the local user.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isLocalStats() {\r\n        return this._isLocalStats;\r\n    }\r\n\r\n    /**\r\n     * Returns true if the tracked user is currently a dominant speaker.\r\n     *\r\n     * @returns {boolean}\r\n     */\r\n    isDominantSpeaker() {\r\n        return this._isDominantSpeaker;\r\n    }\r\n\r\n    /**\r\n     * Returns true if the tracked user is currently a dominant speaker.\r\n     *\r\n     * @param {boolean} isNowDominantSpeaker - If true, the user will be accumulating time\r\n     * as dominant speaker. If false, the user will not accumulate time\r\n     * and will record any time accumulated since starting as dominant speaker.\r\n     * @param {boolean} silence - Indecates whether the dominant speaker is silent or not.\r\n     * @returns {void}\r\n     */\r\n    setDominantSpeaker(isNowDominantSpeaker, silence) {\r\n        if (!this.isDominantSpeaker() && isNowDominantSpeaker && !silence) {\r\n            this._dominantSpeakerStart = Date.now();\r\n        } else if (this.isDominantSpeaker()) {\r\n            if (!isNowDominantSpeaker) {\r\n                if (!this._isSilent) {\r\n                    const now = Date.now();\r\n                    const timeElapsed = now - this._dominantSpeakerStart;\r\n\r\n                    this.totalDominantSpeakerTime += timeElapsed;\r\n                    this._dominantSpeakerStart = 0;\r\n                }\r\n            } else if (this._isSilent && !silence) {\r\n                this._dominantSpeakerStart = Date.now();\r\n            } else if (!this._isSilent && silence) {\r\n                const now = Date.now();\r\n                const timeElapsed = now - this._dominantSpeakerStart;\r\n\r\n                this.totalDominantSpeakerTime += timeElapsed;\r\n                this._dominantSpeakerStart = 0;\r\n            }\r\n        }\r\n\r\n        this._isDominantSpeaker = isNowDominantSpeaker;\r\n        this._isSilent = silence;\r\n    }\r\n\r\n    /**\r\n     * Get how long the tracked user has been dominant speaker.\r\n     *\r\n     * @returns {number} - The speaker time in milliseconds.\r\n     */\r\n    getTotalDominantSpeakerTime() {\r\n        let total = this.totalDominantSpeakerTime;\r\n\r\n        if (this.isDominantSpeaker() && !this._isSilent) {\r\n            total += Date.now() - this._dominantSpeakerStart;\r\n        }\r\n\r\n        return total;\r\n    }\r\n\r\n    /**\r\n     * Get whether or not the user is still in the meeting.\r\n     *\r\n     * @returns {boolean} True if the user is no longer in the meeting.\r\n     */\r\n    hasLeft() {\r\n        return this._hasLeft;\r\n    }\r\n\r\n    /**\r\n     * Set the user as having left the meeting.\r\n     *\r\n     * @returns {void}\r\n     */\r\n    markAsHasLeft() {\r\n        this._hasLeft = true;\r\n        this.setDominantSpeaker(false);\r\n    }\r\n\r\n    /**\r\n     * Gets the face expressions of the user.\r\n     *\r\n     * @returns {Object}\r\n     */\r\n    getFaceExpressions() {\r\n        return this._faceExpressions;\r\n    }\r\n\r\n    /**\r\n     * Sets the face expressions of the user.\r\n     *\r\n     * @param {Object} faceExpressions - object with face expressions.\r\n     * @returns {void}\r\n     */\r\n    setFaceExpressions(faceExpressions) {\r\n        this._faceExpressions = faceExpressions;\r\n    }\r\n\r\n    /**\r\n     * Adds a new face expression to speaker stats.\r\n     *\r\n     * @param  {string} faceExpression\r\n     * @param {number} duration\r\n     */\r\n    addFaceExpression(faceExpression, duration) {\r\n        this._faceExpressions[faceExpression] += duration;\r\n    }\r\n}\r\n\r\nmodule.exports = SpeakerStats;\r\n","const AuthUtil = {\r\n    /**\r\n     * Creates the URL pointing to JWT token authentication service. It is\r\n     * formatted from the 'urlPattern' argument which can contain the following\r\n     * constants:\r\n     * '{room}' - name of the conference room passed as <tt>roomName</tt>\r\n     * argument to this method.\r\n     * '{roleUpgrade}' - will contain 'true' if the URL will be used for\r\n     * the role upgrade scenario, where user connects from anonymous domain and\r\n     * then gets upgraded to the moderator by logging-in from the popup window.\r\n     *\r\n     * @param urlPattern a URL pattern pointing to the login service\r\n     * @param roomName the name of the conference room for which the user will\r\n     * be authenticated\r\n     * @param {boolean} roleUpgrade <tt>true</tt> if the URL will be used for role\r\n     * upgrade scenario, where the user logs-in from the popup window in order\r\n     * to have the moderator rights granted\r\n     *\r\n     * @returns {string|null} the URL pointing to JWT login service or\r\n     * <tt>null</tt> if 'urlPattern' is not a string and the URL can not be\r\n     * constructed.\r\n     */\r\n    getTokenAuthUrl(urlPattern, roomName, roleUpgrade) {\r\n        const url = urlPattern;\r\n\r\n        if (typeof url !== 'string') {\r\n            return null;\r\n        }\r\n\r\n        return url.replace('{room}', roomName)\r\n            .replace('{roleUpgrade}', roleUpgrade === true);\r\n    }\r\n};\r\n\r\nmodule.exports = AuthUtil;\r\n","/**\r\n * Implements utility to forward events from one eventEmitter to another.\r\n * @param src {object} instance of EventEmitter or another class that implements\r\n * addListener method which will register listener to EventEmitter instance.\r\n * @param dest {object} instance of EventEmitter or another class that\r\n * implements emit method which will emit an event.\r\n */\r\nfunction EventEmitterForwarder(src, dest) {\r\n    if (!src || !dest || typeof src.addListener !== 'function'\r\n        || typeof dest.emit !== 'function') {\r\n        throw new Error('Invalid arguments passed to EventEmitterForwarder');\r\n    }\r\n    this.src = src;\r\n    this.dest = dest;\r\n}\r\n\r\n/**\r\n * Adds event to be forwarded from src to dest.\r\n * @param srcEvent {string} the event that EventEmitterForwarder is listening\r\n * for.\r\n * @param dstEvent {string} the event that will be fired from dest.\r\n * @param arguments all other passed arguments are going to be fired with\r\n * dstEvent.\r\n */\r\nEventEmitterForwarder.prototype.forward = function(...args) {\r\n    const srcEvent = args[0];\r\n\r\n    // This will be the \"this\" value for emit function.\r\n\r\n    args[0] = this.dest;\r\n\r\n    // Using bind.apply to pass the arguments as Array-like object (\"arguments\")\r\n    this.src.addListener(\r\n        srcEvent,\r\n        Function.prototype.bind.apply(this.dest.emit, args));\r\n};\r\n\r\nmodule.exports = EventEmitterForwarder;\r\n","/**\r\n * This utility class defines custom onerror and onunhandledrejection functions.\r\n * The custom error handlers respect the previously-defined error handlers.\r\n * GlobalOnErrorHandler class provides utilities to add many custom error\r\n * handlers and to execute the error handlers directly.\r\n */\r\n\r\n\r\n/**\r\n * List with global error handlers that will be executed.\r\n */\r\nconst handlers = [];\r\n\r\n// If an old handler exists, also fire its events.\r\nconst oldOnErrorHandler = window.onerror;\r\n\r\n/**\r\n * Custom error handler that calls the old global error handler and executes\r\n * all handlers that were previously added.\r\n */\r\nfunction JitsiGlobalErrorHandler(...args) {\r\n    handlers.forEach(handler => handler(...args));\r\n    oldOnErrorHandler && oldOnErrorHandler(...args);\r\n}\r\n\r\n// If an old handler exists, also fire its events.\r\nconst oldOnUnhandledRejection = window.onunhandledrejection;\r\n\r\n/**\r\n * Custom handler that calls the old global handler and executes all handlers\r\n * that were previously added. This handler handles rejected Promises.\r\n */\r\nfunction JitsiGlobalUnhandledRejection(event) {\r\n    handlers.forEach(handler => handler(null, null, null, null, event.reason));\r\n    oldOnUnhandledRejection && oldOnUnhandledRejection(event);\r\n}\r\n\r\n// Setting the custom error handlers.\r\nwindow.onerror = JitsiGlobalErrorHandler;\r\nwindow.onunhandledrejection = JitsiGlobalUnhandledRejection;\r\n\r\nconst GlobalOnErrorHandler = {\r\n    /**\r\n     * Adds new error handlers.\r\n     * @param handler the new handler.\r\n     */\r\n    addHandler(handler) {\r\n        handlers.push(handler);\r\n    },\r\n\r\n    /**\r\n     * Calls the global error handler if there is one.\r\n     * @param error the error to pass to the error handler\r\n     */\r\n    callErrorHandler(error) {\r\n        const errHandler = window.onerror;\r\n\r\n        if (!errHandler) {\r\n            return;\r\n        }\r\n        errHandler(null, null, null, null, error);\r\n    },\r\n\r\n    /**\r\n     * Calls the global rejection handler if there is one.\r\n     * @param error the error to pass to the rejection handler.\r\n     */\r\n    callUnhandledRejectionHandler(error) {\r\n        const errHandler = window.onunhandledrejection;\r\n\r\n        if (!errHandler) {\r\n            return;\r\n        }\r\n        errHandler(error);\r\n    }\r\n};\r\n\r\n\r\nmodule.exports = GlobalOnErrorHandler;\r\n","/**\r\n * @const\r\n */\r\nconst ALPHANUM\r\n    = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\r\n\r\n/**\r\n * Hexadecimal digits.\r\n * @const\r\n */\r\nconst HEX_DIGITS = '0123456789abcdef';\r\n\r\n/**\r\n * Generates random int within the range [min, max]\r\n * @param min the minimum value for the generated number\r\n * @param max the maximum value for the generated number\r\n * @returns random int number\r\n */\r\nfunction randomInt(min, max) {\r\n    return Math.floor(Math.random() * (max - min + 1)) + min;\r\n}\r\n\r\n/**\r\n * Get random element from array or string.\r\n * @param {Array|string} arr source\r\n * @returns array element or string character\r\n */\r\nfunction randomElement(arr) {\r\n    return arr[randomInt(0, arr.length - 1)];\r\n}\r\n\r\n/**\r\n * Generate random alphanumeric string.\r\n * @param {number} length expected string length\r\n * @returns {string} random string of specified length\r\n */\r\nfunction randomAlphanumStr(length) {\r\n    let result = '';\r\n\r\n    for (let i = 0; i < length; i += 1) {\r\n        result += randomElement(ALPHANUM);\r\n    }\r\n\r\n    return result;\r\n}\r\n\r\n/**\r\n * Exported interface.\r\n */\r\nconst RandomUtil = {\r\n    /**\r\n     * Returns a random hex digit.\r\n     * @returns {*}\r\n     */\r\n    randomHexDigit() {\r\n        return randomElement(HEX_DIGITS);\r\n    },\r\n\r\n    /**\r\n     * Returns a random string of hex digits with length 'len'.\r\n     * @param len the length.\r\n     */\r\n    randomHexString(len) {\r\n        let ret = '';\r\n\r\n        while (len--) { // eslint-disable-line no-param-reassign\r\n            ret += this.randomHexDigit();\r\n        }\r\n\r\n        return ret;\r\n    },\r\n    randomElement,\r\n    randomAlphanumStr,\r\n    randomInt\r\n};\r\n\r\nmodule.exports = RandomUtil;\r\n","const currentExecutingScript = require('current-executing-script');\r\n\r\n/* eslint-disable max-params */\r\n\r\n/**\r\n * Implements utility functions which facilitate the dealing with scripts such\r\n * as the download and execution of a JavaScript file.\r\n */\r\nconst ScriptUtil = {\r\n    /**\r\n     * Loads a script from a specific source.\r\n     *\r\n     * @param src the source from the which the script is to be (down)loaded\r\n     * @param async true to asynchronously load the script or false to\r\n     * synchronously load the script\r\n     * @param prepend true to schedule the loading of the script as soon as\r\n     * possible or false to schedule the loading of the script at the end of the\r\n     * scripts known at the time\r\n     * @param relativeURL whether we need load the library from url relative\r\n     * to the url that lib-jitsi-meet was loaded. Useful when sourcing the\r\n     * library from different location than the app that is using it\r\n     * @param loadCallback on load callback function\r\n     * @param errorCallback callback to be called on error loading the script\r\n     */\r\n    loadScript(\r\n            src,\r\n            async,\r\n            prepend,\r\n            relativeURL,\r\n            loadCallback,\r\n            errorCallback) {\r\n        const d = document;\r\n        const tagName = 'script';\r\n        const script = d.createElement(tagName);\r\n        const referenceNode = d.getElementsByTagName(tagName)[0];\r\n\r\n        script.async = async;\r\n\r\n        if (relativeURL) {\r\n            // finds the src url of the current loaded script\r\n            // and use it as base of the src supplied argument\r\n            const scriptEl = currentExecutingScript();\r\n\r\n            if (scriptEl) {\r\n                const scriptSrc = scriptEl.src;\r\n                const baseScriptSrc\r\n                    = scriptSrc.substring(0, scriptSrc.lastIndexOf('/') + 1);\r\n\r\n                if (scriptSrc && baseScriptSrc) {\r\n                    // eslint-disable-next-line no-param-reassign\r\n                    src = baseScriptSrc + src;\r\n                }\r\n            }\r\n        }\r\n\r\n        if (loadCallback) {\r\n            script.onload = loadCallback;\r\n        }\r\n        if (errorCallback) {\r\n            script.onerror = errorCallback;\r\n        }\r\n\r\n        script.src = src;\r\n        if (prepend) {\r\n            referenceNode.parentNode.insertBefore(script, referenceNode);\r\n        } else {\r\n            referenceNode.parentNode.appendChild(script);\r\n        }\r\n    }\r\n};\r\n\r\n/* eslint-enable max-params */\r\n\r\nmodule.exports = ScriptUtil;\r\n","/**\r\n * Implements a simple hash code for a string (see\r\n * https://en.wikipedia.org/wiki/Java_hashCode()).\r\n *\r\n * @param {string} The string to return a hash of.\r\n * @return {Number} the integer hash code of the string.\r\n */\r\nfunction integerHash(string) {\r\n    if (!string) {\r\n        return 0;\r\n    }\r\n\r\n    let char, hash = 0, i;\r\n\r\n    for (i = 0; i < string.length; i++) {\r\n        char = string.charCodeAt(i);\r\n        hash += char * Math.pow(31, string.length - 1 - i);\r\n        hash = Math.abs(hash | 0); // eslint-disable-line no-bitwise\r\n    }\r\n\r\n    return hash;\r\n}\r\n\r\nmodule.exports = { integerHash };\r\n","const RandomUtil = require('./RandomUtil');\r\n\r\n/**\r\n * from faker.js - Copyright (c) 2014-2015 Matthew Bergman & Marak Squires\r\n * MIT License\r\n * http://github.com/marak/faker.js/\r\n *\r\n * @const\r\n */\r\nconst names = [\r\n    'Aaliyah', 'Aaron', 'Abagail', 'Abbey', 'Abbie', 'Abbigail', 'Abby',\r\n    'Abdiel', 'Abdul', 'Abdullah', 'Abe', 'Abel', 'Abelardo', 'Abigail',\r\n    'Abigale', 'Abigayle', 'Abner', 'Abraham', 'Ada', 'Adah', 'Adalberto',\r\n    'Adaline', 'Adam', 'Adan', 'Addie', 'Addison', 'Adela', 'Adelbert', 'Adele',\r\n    'Adelia', 'Adeline', 'Adell', 'Adella', 'Adelle', 'Aditya', 'Adolf',\r\n    'Adolfo', 'Adolph', 'Adolphus', 'Adonis', 'Adrain', 'Adrian', 'Adriana',\r\n    'Adrianna', 'Adriel', 'Adrien', 'Adrienne', 'Afton', 'Aglae', 'Agnes',\r\n    'Agustin', 'Agustina', 'Ahmad', 'Ahmed', 'Aida', 'Aidan', 'Aiden', 'Aileen',\r\n    'Aisha', 'Aiyana', 'Akeem', 'Al', 'Alaina', 'Alan', 'Alana', 'Alanis',\r\n    'Alanna', 'Alayna', 'Alba', 'Albert', 'Alberta', 'Albertha', 'Alberto',\r\n    'Albin', 'Albina', 'Alda', 'Alden', 'Alec', 'Aleen', 'Alejandra',\r\n    'Alejandrin', 'Alek', 'Alena', 'Alene', 'Alessandra', 'Alessandro',\r\n    'Alessia', 'Aletha', 'Alex', 'Alexa', 'Alexander', 'Alexandra', 'Alexandre',\r\n    'Alexandrea', 'Alexandria', 'Alexandrine', 'Alexandro', 'Alexane',\r\n    'Alexanne', 'Alexie', 'Alexis', 'Alexys', 'Alexzander', 'Alf', 'Alfonso',\r\n    'Alfonzo', 'Alford', 'Alfred', 'Alfreda', 'Alfredo', 'Ali', 'Alia', 'Alice',\r\n    'Alicia', 'Alisa', 'Alisha', 'Alison', 'Alivia', 'Aliya', 'Aliyah', 'Aliza',\r\n    'Alize', 'Allan', 'Allen', 'Allene', 'Allie', 'Allison', 'Ally', 'Alphonso',\r\n    'Alta', 'Althea', 'Alva', 'Alvah', 'Alvena', 'Alvera', 'Alverta', 'Alvina',\r\n    'Alvis', 'Alyce', 'Alycia', 'Alysa', 'Alysha', 'Alyson', 'Alysson',\r\n    'Amalia', 'Amanda', 'Amani', 'Amara', 'Amari', 'Amaya', 'Amber', 'Ambrose',\r\n    'Amelia', 'Amelie', 'Amely', 'America', 'Americo', 'Amie', 'Amina', 'Amir',\r\n    'Amira', 'Amiya', 'Amos', 'Amparo', 'Amy', 'Amya', 'Ana', 'Anabel',\r\n    'Anabelle', 'Anahi', 'Anais', 'Anastacio', 'Anastasia', 'Anderson', 'Andre',\r\n    'Andreane', 'Andreanne', 'Andres', 'Andrew', 'Andy', 'Angel', 'Angela',\r\n    'Angelica', 'Angelina', 'Angeline', 'Angelita', 'Angelo', 'Angie', 'Angus',\r\n    'Anibal', 'Anika', 'Anissa', 'Anita', 'Aniya', 'Aniyah', 'Anjali', 'Anna',\r\n    'Annabel', 'Annabell', 'Annabelle', 'Annalise', 'Annamae', 'Annamarie',\r\n    'Anne', 'Annetta', 'Annette', 'Annie', 'Ansel', 'Ansley', 'Anthony',\r\n    'Antoinette', 'Antone', 'Antonetta', 'Antonette', 'Antonia', 'Antonietta',\r\n    'Antonina', 'Antonio', 'Antwan', 'Antwon', 'Anya', 'April', 'Ara',\r\n    'Araceli', 'Aracely', 'Arch', 'Archibald', 'Ardella', 'Arden', 'Ardith',\r\n    'Arely', 'Ari', 'Ariane', 'Arianna', 'Aric', 'Ariel', 'Arielle', 'Arjun',\r\n    'Arlene', 'Arlie', 'Arlo', 'Armand', 'Armando', 'Armani', 'Arnaldo', 'Arne',\r\n    'Arno', 'Arnold', 'Arnoldo', 'Arnulfo', 'Aron', 'Art', 'Arthur', 'Arturo',\r\n    'Arvel', 'Arvid', 'Arvilla', 'Aryanna', 'Asa', 'Asha', 'Ashlee', 'Ashleigh',\r\n    'Ashley', 'Ashly', 'Ashlynn', 'Ashton', 'Ashtyn', 'Asia', 'Assunta',\r\n    'Astrid', 'Athena', 'Aubree', 'Aubrey', 'Audie', 'Audra', 'Audreanne',\r\n    'Audrey', 'August', 'Augusta', 'Augustine', 'Augustus', 'Aurelia',\r\n    'Aurelie', 'Aurelio', 'Aurore', 'Austen', 'Austin', 'Austyn', 'Autumn',\r\n    'Ava', 'Avery', 'Avis', 'Axel', 'Ayana', 'Ayden', 'Ayla', 'Aylin', 'Baby',\r\n    'Bailee', 'Bailey', 'Barbara', 'Barney', 'Baron', 'Barrett', 'Barry',\r\n    'Bart', 'Bartholome', 'Barton', 'Baylee', 'Beatrice', 'Beau', 'Beaulah',\r\n    'Bell', 'Bella', 'Belle', 'Ben', 'Benedict', 'Benjamin', 'Bennett',\r\n    'Bennie', 'Benny', 'Benton', 'Berenice', 'Bernadette', 'Bernadine',\r\n    'Bernard', 'Bernardo', 'Berneice', 'Bernhard', 'Bernice', 'Bernie',\r\n    'Berniece', 'Bernita', 'Berry', 'Bert', 'Berta', 'Bertha', 'Bertram',\r\n    'Bertrand', 'Beryl', 'Bessie', 'Beth', 'Bethany', 'Bethel', 'Betsy',\r\n    'Bette', 'Bettie', 'Betty', 'Bettye', 'Beulah', 'Beverly', 'Bianka', 'Bill',\r\n    'Billie', 'Billy', 'Birdie', 'Blair', 'Blaise', 'Blake', 'Blanca',\r\n    'Blanche', 'Blaze', 'Bo', 'Bobbie', 'Bobby', 'Bonita', 'Bonnie', 'Boris',\r\n    'Boyd', 'Brad', 'Braden', 'Bradford', 'Bradley', 'Bradly', 'Brady',\r\n    'Braeden', 'Brain', 'Brandi', 'Brando', 'Brandon', 'Brandt', 'Brandy',\r\n    'Brandyn', 'Brannon', 'Branson', 'Brant', 'Braulio', 'Braxton', 'Brayan',\r\n    'Breana', 'Breanna', 'Breanne', 'Brenda', 'Brendan', 'Brenden', 'Brendon',\r\n    'Brenna', 'Brennan', 'Brennon', 'Brent', 'Bret', 'Brett', 'Bria', 'Brian',\r\n    'Briana', 'Brianne', 'Brice', 'Bridget', 'Bridgette', 'Bridie', 'Brielle',\r\n    'Brigitte', 'Brionna', 'Brisa', 'Britney', 'Brittany', 'Brock', 'Broderick',\r\n    'Brody', 'Brook', 'Brooke', 'Brooklyn', 'Brooks', 'Brown', 'Bruce',\r\n    'Bryana', 'Bryce', 'Brycen', 'Bryon', 'Buck', 'Bud', 'Buddy', 'Buford',\r\n    'Bulah', 'Burdette', 'Burley', 'Burnice', 'Buster', 'Cade', 'Caden',\r\n    'Caesar', 'Caitlyn', 'Cale', 'Caleb', 'Caleigh', 'Cali', 'Calista',\r\n    'Callie', 'Camden', 'Cameron', 'Camila', 'Camilla', 'Camille', 'Camren',\r\n    'Camron', 'Camryn', 'Camylle', 'Candace', 'Candelario', 'Candice',\r\n    'Candida', 'Candido', 'Cara', 'Carey', 'Carissa', 'Carlee', 'Carleton',\r\n    'Carley', 'Carli', 'Carlie', 'Carlo', 'Carlos', 'Carlotta', 'Carmel',\r\n    'Carmela', 'Carmella', 'Carmelo', 'Carmen', 'Carmine', 'Carol', 'Carolanne',\r\n    'Carole', 'Carolina', 'Caroline', 'Carolyn', 'Carolyne', 'Carrie',\r\n    'Carroll', 'Carson', 'Carter', 'Cary', 'Casandra', 'Casey', 'Casimer',\r\n    'Casimir', 'Casper', 'Cassandra', 'Cassandre', 'Cassidy', 'Cassie',\r\n    'Catalina', 'Caterina', 'Catharine', 'Catherine', 'Cathrine', 'Cathryn',\r\n    'Cathy', 'Cayla', 'Ceasar', 'Cecelia', 'Cecil', 'Cecile', 'Cecilia',\r\n    'Cedrick', 'Celestine', 'Celestino', 'Celia', 'Celine', 'Cesar', 'Chad',\r\n    'Chadd', 'Chadrick', 'Chaim', 'Chance', 'Chandler', 'Chanel', 'Chanelle',\r\n    'Charity', 'Charlene', 'Charles', 'Charley', 'Charlie', 'Charlotte',\r\n    'Chase', 'Chasity', 'Chauncey', 'Chaya', 'Chaz', 'Chelsea', 'Chelsey',\r\n    'Chelsie', 'Chesley', 'Chester', 'Chet', 'Cheyanne', 'Cheyenne', 'Chloe',\r\n    'Chris', 'Christ', 'Christa', 'Christelle', 'Christian', 'Christiana',\r\n    'Christina', 'Christine', 'Christop', 'Christophe', 'Christopher',\r\n    'Christy', 'Chyna', 'Ciara', 'Cicero', 'Cielo', 'Cierra', 'Cindy',\r\n    'Citlalli', 'Clair', 'Claire', 'Clara', 'Clarabelle', 'Clare', 'Clarissa',\r\n    'Clark', 'Claud', 'Claude', 'Claudia', 'Claudie', 'Claudine', 'Clay',\r\n    'Clemens', 'Clement', 'Clementina', 'Clementine', 'Clemmie', 'Cleo',\r\n    'Cleora', 'Cleta', 'Cletus', 'Cleve', 'Cleveland', 'Clifford', 'Clifton',\r\n    'Clint', 'Clinton', 'Clotilde', 'Clovis', 'Cloyd', 'Clyde', 'Coby', 'Cody',\r\n    'Colby', 'Cole', 'Coleman', 'Colin', 'Colleen', 'Collin', 'Colt', 'Colten',\r\n    'Colton', 'Columbus', 'Concepcion', 'Conner', 'Connie', 'Connor', 'Conor',\r\n    'Conrad', 'Constance', 'Constantin', 'Consuelo', 'Cooper', 'Cora',\r\n    'Coralie', 'Corbin', 'Cordelia', 'Cordell', 'Cordia', 'Cordie', 'Corene',\r\n    'Corine', 'Cornelius', 'Cornell', 'Corrine', 'Cortez', 'Cortney', 'Cory',\r\n    'Coty', 'Courtney', 'Coy', 'Craig', 'Crawford', 'Creola', 'Cristal',\r\n    'Cristian', 'Cristina', 'Cristobal', 'Cristopher', 'Cruz', 'Crystal',\r\n    'Crystel', 'Cullen', 'Curt', 'Curtis', 'Cydney', 'Cynthia', 'Cyril',\r\n    'Cyrus', 'Dagmar', 'Dahlia', 'Daija', 'Daisha', 'Daisy', 'Dakota', 'Dale',\r\n    'Dallas', 'Dallin', 'Dalton', 'Damaris', 'Dameon', 'Damian', 'Damien',\r\n    'Damion', 'Damon', 'Dan', 'Dana', 'Dandre', 'Dane', 'D\\'angelo', 'Dangelo',\r\n    'Danial', 'Daniela', 'Daniella', 'Danielle', 'Danika', 'Dannie', 'Danny',\r\n    'Dante', 'Danyka', 'Daphne', 'Daphnee', 'Daphney', 'Darby', 'Daren',\r\n    'Darian', 'Dariana', 'Darien', 'Dario', 'Darion', 'Darius', 'Darlene',\r\n    'Daron', 'Darrel', 'Darrell', 'Darren', 'Darrick', 'Darrin', 'Darrion',\r\n    'Darron', 'Darryl', 'Darwin', 'Daryl', 'Dashawn', 'Dasia', 'Dave', 'David',\r\n    'Davin', 'Davion', 'Davon', 'Davonte', 'Dawn', 'Dawson', 'Dax', 'Dayana',\r\n    'Dayna', 'Dayne', 'Dayton', 'Dean', 'Deangelo', 'Deanna', 'Deborah',\r\n    'Declan', 'Dedric', 'Dedrick', 'Dee', 'Deion', 'Deja', 'Dejah', 'Dejon',\r\n    'Dejuan', 'Delaney', 'Delbert', 'Delfina', 'Delia', 'Delilah', 'Dell',\r\n    'Della', 'Delmer', 'Delores', 'Delpha', 'Delphia', 'Delphine', 'Delta',\r\n    'Demarco', 'Demarcus', 'Demario', 'Demetris', 'Demetrius', 'Demond', 'Dena',\r\n    'Denis', 'Dennis', 'Deon', 'Deondre', 'Deontae', 'Deonte', 'Dereck',\r\n    'Derek', 'Derick', 'Deron', 'Derrick', 'Deshaun', 'Deshawn', 'Desiree',\r\n    'Desmond', 'Dessie', 'Destany', 'Destin', 'Destinee', 'Destiney', 'Destini',\r\n    'Destiny', 'Devan', 'Devante', 'Deven', 'Devin', 'Devon', 'Devonte',\r\n    'Devyn', 'Dewayne', 'Dewitt', 'Dexter', 'Diamond', 'Diana', 'Dianna',\r\n    'Diego', 'Dillan', 'Dillon', 'Dimitri', 'Dina', 'Dino', 'Dion', 'Dixie',\r\n    'Dock', 'Dolly', 'Dolores', 'Domenic', 'Domenica', 'Domenick', 'Domenico',\r\n    'Domingo', 'Dominic', 'Dominique', 'Don', 'Donald', 'Donato', 'Donavon',\r\n    'Donna', 'Donnell', 'Donnie', 'Donny', 'Dora', 'Dorcas', 'Dorian', 'Doris',\r\n    'Dorothea', 'Dorothy', 'Dorris', 'Dortha', 'Dorthy', 'Doug', 'Douglas',\r\n    'Dovie', 'Doyle', 'Drake', 'Drew', 'Duane', 'Dudley', 'Dulce', 'Duncan',\r\n    'Durward', 'Dustin', 'Dusty', 'Dwight', 'Dylan', 'Earl', 'Earlene',\r\n    'Earline', 'Earnest', 'Earnestine', 'Easter', 'Easton', 'Ebba', 'Ebony',\r\n    'Ed', 'Eda', 'Edd', 'Eddie', 'Eden', 'Edgar', 'Edgardo', 'Edison', 'Edmond',\r\n    'Edmund', 'Edna', 'Eduardo', 'Edward', 'Edwardo', 'Edwin', 'Edwina',\r\n    'Edyth', 'Edythe', 'Effie', 'Efrain', 'Efren', 'Eileen', 'Einar', 'Eino',\r\n    'Eladio', 'Elaina', 'Elbert', 'Elda', 'Eldon', 'Eldora', 'Eldred',\r\n    'Eldridge', 'Eleanora', 'Eleanore', 'Eleazar', 'Electa', 'Elena', 'Elenor',\r\n    'Elenora', 'Eleonore', 'Elfrieda', 'Eli', 'Elian', 'Eliane', 'Elias',\r\n    'Eliezer', 'Elijah', 'Elinor', 'Elinore', 'Elisa', 'Elisabeth', 'Elise',\r\n    'Eliseo', 'Elisha', 'Elissa', 'Eliza', 'Elizabeth', 'Ella', 'Ellen',\r\n    'Ellie', 'Elliot', 'Elliott', 'Ellis', 'Ellsworth', 'Elmer', 'Elmira',\r\n    'Elmo', 'Elmore', 'Elna', 'Elnora', 'Elody', 'Eloisa', 'Eloise', 'Elouise',\r\n    'Eloy', 'Elroy', 'Elsa', 'Else', 'Elsie', 'Elta', 'Elton', 'Elva', 'Elvera',\r\n    'Elvie', 'Elvis', 'Elwin', 'Elwyn', 'Elyse', 'Elyssa', 'Elza', 'Emanuel',\r\n    'Emelia', 'Emelie', 'Emely', 'Emerald', 'Emerson', 'Emery', 'Emie', 'Emil',\r\n    'Emile', 'Emilia', 'Emiliano', 'Emilie', 'Emilio', 'Emily', 'Emma',\r\n    'Emmalee', 'Emmanuel', 'Emmanuelle', 'Emmet', 'Emmett', 'Emmie', 'Emmitt',\r\n    'Emmy', 'Emory', 'Ena', 'Enid', 'Enoch', 'Enola', 'Enos', 'Enrico',\r\n    'Enrique', 'Ephraim', 'Era', 'Eriberto', 'Eric', 'Erica', 'Erich', 'Erick',\r\n    'Ericka', 'Erik', 'Erika', 'Erin', 'Erling', 'Erna', 'Ernest', 'Ernestina',\r\n    'Ernestine', 'Ernesto', 'Ernie', 'Ervin', 'Erwin', 'Eryn', 'Esmeralda',\r\n    'Esperanza', 'Esta', 'Esteban', 'Estefania', 'Estel', 'Estell', 'Estella',\r\n    'Estelle', 'Estevan', 'Esther', 'Estrella', 'Etha', 'Ethan', 'Ethel',\r\n    'Ethelyn', 'Ethyl', 'Ettie', 'Eudora', 'Eugene', 'Eugenia', 'Eula', 'Eulah',\r\n    'Eulalia', 'Euna', 'Eunice', 'Eusebio', 'Eva', 'Evalyn', 'Evan',\r\n    'Evangeline', 'Evans', 'Eve', 'Eveline', 'Evelyn', 'Everardo', 'Everett',\r\n    'Everette', 'Evert', 'Evie', 'Ewald', 'Ewell', 'Ezekiel', 'Ezequiel',\r\n    'Ezra', 'Fabian', 'Fabiola', 'Fae', 'Fannie', 'Fanny', 'Fatima', 'Faustino',\r\n    'Fausto', 'Favian', 'Fay', 'Faye', 'Federico', 'Felicia', 'Felicita',\r\n    'Felicity', 'Felipa', 'Felipe', 'Felix', 'Felton', 'Fermin', 'Fern',\r\n    'Fernando', 'Ferne', 'Fidel', 'Filiberto', 'Filomena', 'Finn', 'Fiona',\r\n    'Flavie', 'Flavio', 'Fleta', 'Fletcher', 'Flo', 'Florence', 'Florencio',\r\n    'Florian', 'Florida', 'Florine', 'Flossie', 'Floy', 'Floyd', 'Ford',\r\n    'Forest', 'Forrest', 'Foster', 'Frances', 'Francesca', 'Francesco',\r\n    'Francis', 'Francisca', 'Francisco', 'Franco', 'Frank', 'Frankie', 'Franz',\r\n    'Fred', 'Freda', 'Freddie', 'Freddy', 'Frederic', 'Frederick', 'Frederik',\r\n    'Frederique', 'Fredrick', 'Fredy', 'Freeda', 'Freeman', 'Freida', 'Frida',\r\n    'Frieda', 'Friedrich', 'Fritz', 'Furman', 'Gabe', 'Gabriel', 'Gabriella',\r\n    'Gabrielle', 'Gaetano', 'Gage', 'Gail', 'Gardner', 'Garett', 'Garfield',\r\n    'Garland', 'Garnet', 'Garnett', 'Garret', 'Garrett', 'Garrick', 'Garrison',\r\n    'Garry', 'Garth', 'Gaston', 'Gavin', 'Gay', 'Gayle', 'Gaylord', 'Gene',\r\n    'General', 'Genesis', 'Genevieve', 'Gennaro', 'Genoveva', 'Geo', 'Geoffrey',\r\n    'George', 'Georgette', 'Georgiana', 'Georgianna', 'Geovanni', 'Geovanny',\r\n    'Geovany', 'Gerald', 'Geraldine', 'Gerard', 'Gerardo', 'Gerda', 'Gerhard',\r\n    'Germaine', 'German', 'Gerry', 'Gerson', 'Gertrude', 'Gia', 'Gianni',\r\n    'Gideon', 'Gilbert', 'Gilberto', 'Gilda', 'Giles', 'Gillian', 'Gina',\r\n    'Gino', 'Giovani', 'Giovanna', 'Giovanni', 'Giovanny', 'Gisselle',\r\n    'Giuseppe', 'Gladyce', 'Gladys', 'Glen', 'Glenda', 'Glenna', 'Glennie',\r\n    'Gloria', 'Godfrey', 'Golda', 'Golden', 'Gonzalo', 'Gordon', 'Grace',\r\n    'Gracie', 'Graciela', 'Grady', 'Graham', 'Grant', 'Granville', 'Grayce',\r\n    'Grayson', 'Green', 'Greg', 'Gregg', 'Gregoria', 'Gregorio', 'Gregory',\r\n    'Greta', 'Gretchen', 'Greyson', 'Griffin', 'Grover', 'Guadalupe', 'Gudrun',\r\n    'Guido', 'Guillermo', 'Guiseppe', 'Gunnar', 'Gunner', 'Gus', 'Gussie',\r\n    'Gust', 'Gustave', 'Guy', 'Gwen', 'Gwendolyn', 'Hadley', 'Hailee', 'Hailey',\r\n    'Hailie', 'Hal', 'Haleigh', 'Haley', 'Halie', 'Halle', 'Hallie', 'Hank',\r\n    'Hanna', 'Hannah', 'Hans', 'Hardy', 'Harley', 'Harmon', 'Harmony', 'Harold',\r\n    'Harrison', 'Harry', 'Harvey', 'Haskell', 'Hassan', 'Hassie', 'Hattie',\r\n    'Haven', 'Hayden', 'Haylee', 'Hayley', 'Haylie', 'Hazel', 'Hazle', 'Heath',\r\n    'Heather', 'Heaven', 'Heber', 'Hector', 'Heidi', 'Helen', 'Helena',\r\n    'Helene', 'Helga', 'Hellen', 'Helmer', 'Heloise', 'Henderson', 'Henri',\r\n    'Henriette', 'Henry', 'Herbert', 'Herman', 'Hermann', 'Hermina', 'Herminia',\r\n    'Herminio', 'Hershel', 'Herta', 'Hertha', 'Hester', 'Hettie', 'Hilario',\r\n    'Hilbert', 'Hilda', 'Hildegard', 'Hillard', 'Hillary', 'Hilma', 'Hilton',\r\n    'Hipolito', 'Hiram', 'Hobart', 'Holden', 'Hollie', 'Hollis', 'Holly',\r\n    'Hope', 'Horace', 'Horacio', 'Hortense', 'Hosea', 'Houston', 'Howard',\r\n    'Howell', 'Hoyt', 'Hubert', 'Hudson', 'Hugh', 'Hulda', 'Humberto', 'Hunter',\r\n    'Hyman', 'Ian', 'Ibrahim', 'Icie', 'Ida', 'Idell', 'Idella', 'Ignacio',\r\n    'Ignatius', 'Ike', 'Ila', 'Ilene', 'Iliana', 'Ima', 'Imani', 'Imelda',\r\n    'Immanuel', 'Imogene', 'Ines', 'Irma', 'Irving', 'Irwin', 'Isaac', 'Isabel',\r\n    'Isabell', 'Isabella', 'Isabelle', 'Isac', 'Isadore', 'Isai', 'Isaiah',\r\n    'Isaias', 'Isidro', 'Ismael', 'Isobel', 'Isom', 'Israel', 'Issac', 'Itzel',\r\n    'Iva', 'Ivah', 'Ivory', 'Ivy', 'Izabella', 'Izaiah', 'Jabari', 'Jace',\r\n    'Jacey', 'Jacinthe', 'Jacinto', 'Jack', 'Jackeline', 'Jackie', 'Jacklyn',\r\n    'Jackson', 'Jacky', 'Jaclyn', 'Jacquelyn', 'Jacques', 'Jacynthe', 'Jada',\r\n    'Jade', 'Jaden', 'Jadon', 'Jadyn', 'Jaeden', 'Jaida', 'Jaiden', 'Jailyn',\r\n    'Jaime', 'Jairo', 'Jakayla', 'Jake', 'Jakob', 'Jaleel', 'Jalen', 'Jalon',\r\n    'Jalyn', 'Jamaal', 'Jamal', 'Jamar', 'Jamarcus', 'Jamel', 'Jameson',\r\n    'Jamey', 'Jamie', 'Jamil', 'Jamir', 'Jamison', 'Jammie', 'Jan', 'Jana',\r\n    'Janae', 'Jane', 'Janelle', 'Janessa', 'Janet', 'Janice', 'Janick', 'Janie',\r\n    'Janis', 'Janiya', 'Jannie', 'Jany', 'Jaquan', 'Jaquelin', 'Jaqueline',\r\n    'Jared', 'Jaren', 'Jarod', 'Jaron', 'Jarred', 'Jarrell', 'Jarret',\r\n    'Jarrett', 'Jarrod', 'Jarvis', 'Jasen', 'Jasmin', 'Jason', 'Jasper',\r\n    'Jaunita', 'Javier', 'Javon', 'Javonte', 'Jay', 'Jayce', 'Jaycee', 'Jayda',\r\n    'Jayde', 'Jayden', 'Jaydon', 'Jaylan', 'Jaylen', 'Jaylin', 'Jaylon',\r\n    'Jayme', 'Jayne', 'Jayson', 'Jazlyn', 'Jazmin', 'Jazmyn', 'Jazmyne', 'Jean',\r\n    'Jeanette', 'Jeanie', 'Jeanne', 'Jed', 'Jedediah', 'Jedidiah', 'Jeff',\r\n    'Jefferey', 'Jeffery', 'Jeffrey', 'Jeffry', 'Jena', 'Jenifer', 'Jennie',\r\n    'Jennifer', 'Jennings', 'Jennyfer', 'Jensen', 'Jerad', 'Jerald', 'Jeramie',\r\n    'Jeramy', 'Jerel', 'Jeremie', 'Jeremy', 'Jermain', 'Jermaine', 'Jermey',\r\n    'Jerod', 'Jerome', 'Jeromy', 'Jerrell', 'Jerrod', 'Jerrold', 'Jerry',\r\n    'Jess', 'Jesse', 'Jessica', 'Jessie', 'Jessika', 'Jessy', 'Jessyca',\r\n    'Jesus', 'Jett', 'Jettie', 'Jevon', 'Jewel', 'Jewell', 'Jillian', 'Jimmie',\r\n    'Jimmy', 'Jo', 'Joan', 'Joana', 'Joanie', 'Joanne', 'Joannie', 'Joanny',\r\n    'Joany', 'Joaquin', 'Jocelyn', 'Jodie', 'Jody', 'Joe', 'Joel', 'Joelle',\r\n    'Joesph', 'Joey', 'Johan', 'Johann', 'Johanna', 'Johathan', 'John',\r\n    'Johnathan', 'Johnathon', 'Johnnie', 'Johnny', 'Johnpaul', 'Johnson',\r\n    'Jolie', 'Jon', 'Jonas', 'Jonatan', 'Jonathan', 'Jonathon', 'Jordan',\r\n    'Jordane', 'Jordi', 'Jordon', 'Jordy', 'Jordyn', 'Jorge', 'Jose', 'Josefa',\r\n    'Josefina', 'Joseph', 'Josephine', 'Josh', 'Joshua', 'Joshuah', 'Josiah',\r\n    'Josiane', 'Josianne', 'Josie', 'Josue', 'Jovan', 'Jovani', 'Jovanny',\r\n    'Jovany', 'Joy', 'Joyce', 'Juana', 'Juanita', 'Judah', 'Judd', 'Jude',\r\n    'Judge', 'Judson', 'Judy', 'Jules', 'Julia', 'Julian', 'Juliana',\r\n    'Julianne', 'Julie', 'Julien', 'Juliet', 'Julio', 'Julius', 'June',\r\n    'Junior', 'Junius', 'Justen', 'Justice', 'Justina', 'Justine', 'Juston',\r\n    'Justus', 'Justyn', 'Juvenal', 'Juwan', 'Kacey', 'Kaci', 'Kacie', 'Kade',\r\n    'Kaden', 'Kadin', 'Kaela', 'Kaelyn', 'Kaia', 'Kailee', 'Kailey', 'Kailyn',\r\n    'Kaitlin', 'Kaitlyn', 'Kale', 'Kaleb', 'Kaleigh', 'Kaley', 'Kali', 'Kallie',\r\n    'Kameron', 'Kamille', 'Kamren', 'Kamron', 'Kamryn', 'Kane', 'Kara',\r\n    'Kareem', 'Karelle', 'Karen', 'Kari', 'Kariane', 'Karianne', 'Karina',\r\n    'Karine', 'Karl', 'Karlee', 'Karley', 'Karli', 'Karlie', 'Karolann',\r\n    'Karson', 'Kasandra', 'Kasey', 'Kassandra', 'Katarina', 'Katelin',\r\n    'Katelyn', 'Katelynn', 'Katharina', 'Katherine', 'Katheryn', 'Kathleen',\r\n    'Kathlyn', 'Kathryn', 'Kathryne', 'Katlyn', 'Katlynn', 'Katrina', 'Katrine',\r\n    'Kattie', 'Kavon', 'Kay', 'Kaya', 'Kaycee', 'Kayden', 'Kayla', 'Kaylah',\r\n    'Kaylee', 'Kayleigh', 'Kayley', 'Kayli', 'Kaylie', 'Kaylin', 'Keagan',\r\n    'Keanu', 'Keara', 'Keaton', 'Keegan', 'Keeley', 'Keely', 'Keenan', 'Keira',\r\n    'Keith', 'Kellen', 'Kelley', 'Kelli', 'Kellie', 'Kelly', 'Kelsi', 'Kelsie',\r\n    'Kelton', 'Kelvin', 'Ken', 'Kendall', 'Kendra', 'Kendrick', 'Kenna',\r\n    'Kennedi', 'Kennedy', 'Kenneth', 'Kennith', 'Kenny', 'Kenton', 'Kenya',\r\n    'Kenyatta', 'Kenyon', 'Keon', 'Keshaun', 'Keshawn', 'Keven', 'Kevin',\r\n    'Kevon', 'Keyon', 'Keyshawn', 'Khalid', 'Khalil', 'Kian', 'Kiana', 'Kianna',\r\n    'Kiara', 'Kiarra', 'Kiel', 'Kiera', 'Kieran', 'Kiley', 'Kim', 'Kimberly',\r\n    'King', 'Kip', 'Kira', 'Kirk', 'Kirsten', 'Kirstin', 'Kitty', 'Kobe',\r\n    'Koby', 'Kody', 'Kolby', 'Kole', 'Korbin', 'Korey', 'Kory', 'Kraig', 'Kris',\r\n    'Krista', 'Kristian', 'Kristin', 'Kristina', 'Kristofer', 'Kristoffer',\r\n    'Kristopher', 'Kristy', 'Krystal', 'Krystel', 'Krystina', 'Kurt', 'Kurtis',\r\n    'Kyla', 'Kyle', 'Kylee', 'Kyleigh', 'Kyler', 'Kylie', 'Kyra', 'Lacey',\r\n    'Lacy', 'Ladarius', 'Lafayette', 'Laila', 'Laisha', 'Lamar', 'Lambert',\r\n    'Lamont', 'Lance', 'Landen', 'Lane', 'Laney', 'Larissa', 'Laron', 'Larry',\r\n    'Larue', 'Laura', 'Laurel', 'Lauren', 'Laurence', 'Lauretta', 'Lauriane',\r\n    'Laurianne', 'Laurie', 'Laurine', 'Laury', 'Lauryn', 'Lavada', 'Lavern',\r\n    'Laverna', 'Laverne', 'Lavina', 'Lavinia', 'Lavon', 'Lavonne', 'Lawrence',\r\n    'Lawson', 'Layla', 'Layne', 'Lazaro', 'Lea', 'Leann', 'Leanna', 'Leanne',\r\n    'Leatha', 'Leda', 'Lee', 'Leif', 'Leila', 'Leilani', 'Lela', 'Lelah',\r\n    'Leland', 'Lelia', 'Lempi', 'Lemuel', 'Lenna', 'Lennie', 'Lenny', 'Lenora',\r\n    'Lenore', 'Leo', 'Leola', 'Leon', 'Leonard', 'Leonardo', 'Leone', 'Leonel',\r\n    'Leonie', 'Leonor', 'Leonora', 'Leopold', 'Leopoldo', 'Leora', 'Lera',\r\n    'Lesley', 'Leslie', 'Lesly', 'Lessie', 'Lester', 'Leta', 'Letha', 'Letitia',\r\n    'Levi', 'Lew', 'Lewis', 'Lexi', 'Lexie', 'Lexus', 'Lia', 'Liam', 'Liana',\r\n    'Libbie', 'Libby', 'Lila', 'Lilian', 'Liliana', 'Liliane', 'Lilla',\r\n    'Lillian', 'Lilliana', 'Lillie', 'Lilly', 'Lily', 'Lilyan', 'Lina',\r\n    'Lincoln', 'Linda', 'Lindsay', 'Lindsey', 'Linnea', 'Linnie', 'Linwood',\r\n    'Lionel', 'Lisa', 'Lisandro', 'Lisette', 'Litzy', 'Liza', 'Lizeth',\r\n    'Lizzie', 'Llewellyn', 'Lloyd', 'Logan', 'Lois', 'Lola', 'Lolita', 'Loma',\r\n    'Lon', 'London', 'Lonie', 'Lonnie', 'Lonny', 'Lonzo', 'Lora', 'Loraine',\r\n    'Loren', 'Lorena', 'Lorenz', 'Lorenza', 'Lorenzo', 'Lori', 'Lorine',\r\n    'Lorna', 'Lottie', 'Lou', 'Louie', 'Louisa', 'Lourdes', 'Louvenia',\r\n    'Lowell', 'Loy', 'Loyal', 'Loyce', 'Lucas', 'Luciano', 'Lucie', 'Lucienne',\r\n    'Lucile', 'Lucinda', 'Lucio', 'Lucious', 'Lucius', 'Lucy', 'Ludie',\r\n    'Ludwig', 'Lue', 'Luella', 'Luigi', 'Luis', 'Luisa', 'Lukas', 'Lula',\r\n    'Lulu', 'Luna', 'Lupe', 'Lura', 'Lurline', 'Luther', 'Luz', 'Lyda', 'Lydia',\r\n    'Lyla', 'Lynn', 'Lyric', 'Lysanne', 'Mabel', 'Mabelle', 'Mable', 'Mac',\r\n    'Macey', 'Maci', 'Macie', 'Mack', 'Mackenzie', 'Macy', 'Madaline',\r\n    'Madalyn', 'Maddison', 'Madeline', 'Madelyn', 'Madelynn', 'Madge', 'Madie',\r\n    'Madilyn', 'Madisen', 'Madison', 'Madisyn', 'Madonna', 'Madyson', 'Mae',\r\n    'Maegan', 'Maeve', 'Mafalda', 'Magali', 'Magdalen', 'Magdalena', 'Maggie',\r\n    'Magnolia', 'Magnus', 'Maia', 'Maida', 'Maiya', 'Major', 'Makayla',\r\n    'Makenna', 'Makenzie', 'Malachi', 'Malcolm', 'Malika', 'Malinda', 'Mallie',\r\n    'Mallory', 'Malvina', 'Mandy', 'Manley', 'Manuel', 'Manuela', 'Mara',\r\n    'Marc', 'Marcel', 'Marcelina', 'Marcelino', 'Marcella', 'Marcelle',\r\n    'Marcellus', 'Marcelo', 'Marcia', 'Marco', 'Marcos', 'Marcus', 'Margaret',\r\n    'Margarete', 'Margarett', 'Margaretta', 'Margarette', 'Margarita', 'Marge',\r\n    'Margie', 'Margot', 'Margret', 'Marguerite', 'Maria', 'Mariah', 'Mariam',\r\n    'Marian', 'Mariana', 'Mariane', 'Marianna', 'Marianne', 'Mariano',\r\n    'Maribel', 'Marie', 'Mariela', 'Marielle', 'Marietta', 'Marilie', 'Marilou',\r\n    'Marilyne', 'Marina', 'Mario', 'Marion', 'Marisa', 'Marisol', 'Maritza',\r\n    'Marjolaine', 'Marjorie', 'Marjory', 'Mark', 'Markus', 'Marlee', 'Marlen',\r\n    'Marlene', 'Marley', 'Marlin', 'Marlon', 'Marques', 'Marquis', 'Marquise',\r\n    'Marshall', 'Marta', 'Martin', 'Martina', 'Martine', 'Marty', 'Marvin',\r\n    'Mary', 'Maryam', 'Maryjane', 'Maryse', 'Mason', 'Mateo', 'Mathew',\r\n    'Mathias', 'Mathilde', 'Matilda', 'Matilde', 'Matt', 'Matteo', 'Mattie',\r\n    'Maud', 'Maude', 'Maudie', 'Maureen', 'Maurice', 'Mauricio', 'Maurine',\r\n    'Maverick', 'Mavis', 'Max', 'Maxie', 'Maxime', 'Maximilian', 'Maximillia',\r\n    'Maximillian', 'Maximo', 'Maximus', 'Maxine', 'Maxwell', 'May', 'Maya',\r\n    'Maybell', 'Maybelle', 'Maye', 'Maymie', 'Maynard', 'Mayra', 'Mazie',\r\n    'Mckayla', 'Mckenna', 'Mckenzie', 'Meagan', 'Meaghan', 'Meda', 'Megane',\r\n    'Meggie', 'Meghan', 'Mekhi', 'Melany', 'Melba', 'Melisa', 'Melissa',\r\n    'Mellie', 'Melody', 'Melvin', 'Melvina', 'Melyna', 'Melyssa', 'Mercedes',\r\n    'Meredith', 'Merl', 'Merle', 'Merlin', 'Merritt', 'Mertie', 'Mervin',\r\n    'Meta', 'Mia', 'Micaela', 'Micah', 'Michael', 'Michaela', 'Michale',\r\n    'Micheal', 'Michel', 'Michele', 'Michelle', 'Miguel', 'Mikayla', 'Mike',\r\n    'Mikel', 'Milan', 'Miles', 'Milford', 'Miller', 'Millie', 'Milo', 'Milton',\r\n    'Mina', 'Minerva', 'Minnie', 'Miracle', 'Mireille', 'Mireya', 'Misael',\r\n    'Missouri', 'Misty', 'Mitchel', 'Mitchell', 'Mittie', 'Modesta', 'Modesto',\r\n    'Mohamed', 'Mohammad', 'Mohammed', 'Moises', 'Mollie', 'Molly', 'Mona',\r\n    'Monica', 'Monique', 'Monroe', 'Monserrat', 'Monserrate', 'Montana',\r\n    'Monte', 'Monty', 'Morgan', 'Moriah', 'Morris', 'Mortimer', 'Morton',\r\n    'Mose', 'Moses', 'Moshe', 'Mossie', 'Mozell', 'Mozelle', 'Muhammad',\r\n    'Muriel', 'Murl', 'Murphy', 'Murray', 'Mustafa', 'Mya', 'Myah', 'Mylene',\r\n    'Myles', 'Myra', 'Myriam', 'Myrl', 'Myrna', 'Myron', 'Myrtice', 'Myrtie',\r\n    'Myrtis', 'Myrtle', 'Nadia', 'Nakia', 'Name', 'Nannie', 'Naomi', 'Naomie',\r\n    'Napoleon', 'Narciso', 'Nash', 'Nasir', 'Nat', 'Natalia', 'Natalie',\r\n    'Natasha', 'Nathan', 'Nathanael', 'Nathanial', 'Nathaniel', 'Nathen',\r\n    'Nayeli', 'Neal', 'Ned', 'Nedra', 'Neha', 'Neil', 'Nelda', 'Nella', 'Nelle',\r\n    'Nellie', 'Nels', 'Nelson', 'Neoma', 'Nestor', 'Nettie', 'Neva', 'Newell',\r\n    'Newton', 'Nia', 'Nicholas', 'Nicholaus', 'Nichole', 'Nick', 'Nicklaus',\r\n    'Nickolas', 'Nico', 'Nicola', 'Nicolas', 'Nicole', 'Nicolette', 'Nigel',\r\n    'Nikita', 'Nikki', 'Nikko', 'Niko', 'Nikolas', 'Nils', 'Nina', 'Noah',\r\n    'Noble', 'Noe', 'Noel', 'Noelia', 'Noemi', 'Noemie', 'Noemy', 'Nola',\r\n    'Nolan', 'Nona', 'Nora', 'Norbert', 'Norberto', 'Norene', 'Norma', 'Norris',\r\n    'Norval', 'Norwood', 'Nova', 'Novella', 'Nya', 'Nyah', 'Nyasia', 'Obie',\r\n    'Oceane', 'Ocie', 'Octavia', 'Oda', 'Odell', 'Odessa', 'Odie', 'Ofelia',\r\n    'Okey', 'Ola', 'Olaf', 'Ole', 'Olen', 'Oleta', 'Olga', 'Olin', 'Oliver',\r\n    'Ollie', 'Oma', 'Omari', 'Omer', 'Ona', 'Onie', 'Opal', 'Ophelia', 'Ora',\r\n    'Oral', 'Oran', 'Oren', 'Orie', 'Orin', 'Orion', 'Orland', 'Orlando',\r\n    'Orlo', 'Orpha', 'Orrin', 'Orval', 'Orville', 'Osbaldo', 'Osborne', 'Oscar',\r\n    'Osvaldo', 'Oswald', 'Oswaldo', 'Otha', 'Otho', 'Otilia', 'Otis', 'Ottilie',\r\n    'Ottis', 'Otto', 'Ova', 'Owen', 'Ozella', 'Pablo', 'Paige', 'Palma',\r\n    'Pamela', 'Pansy', 'Paolo', 'Paris', 'Parker', 'Pascale', 'Pasquale', 'Pat',\r\n    'Patience', 'Patricia', 'Patrick', 'Patsy', 'Pattie', 'Paul', 'Paula',\r\n    'Pauline', 'Paxton', 'Payton', 'Pearl', 'Pearlie', 'Pearline', 'Pedro',\r\n    'Peggie', 'Penelope', 'Percival', 'Percy', 'Perry', 'Pete', 'Peter',\r\n    'Petra', 'Peyton', 'Philip', 'Phoebe', 'Phyllis', 'Pierce', 'Pierre',\r\n    'Pietro', 'Pink', 'Pinkie', 'Piper', 'Polly', 'Porter', 'Precious',\r\n    'Presley', 'Preston', 'Price', 'Prince', 'Princess', 'Priscilla',\r\n    'Providenci', 'Prudence', 'Queen', 'Queenie', 'Quentin', 'Quincy', 'Quinn',\r\n    'Quinten', 'Quinton', 'Rachael', 'Rachel', 'Rachelle', 'Rae', 'Raegan',\r\n    'Rafael', 'Rafaela', 'Raheem', 'Rahsaan', 'Rahul', 'Raina', 'Raleigh',\r\n    'Ralph', 'Ramiro', 'Ramon', 'Ramona', 'Randal', 'Randall', 'Randi', 'Randy',\r\n    'Ransom', 'Raoul', 'Raphael', 'Raphaelle', 'Raquel', 'Rashad', 'Rashawn',\r\n    'Rasheed', 'Raul', 'Raven', 'Ray', 'Raymond', 'Raymundo', 'Reagan',\r\n    'Reanna', 'Reba', 'Rebeca', 'Rebecca', 'Rebeka', 'Rebekah', 'Reece', 'Reed',\r\n    'Reese', 'Regan', 'Reggie', 'Reginald', 'Reid', 'Reilly', 'Reina',\r\n    'Reinhold', 'Remington', 'Rene', 'Renee', 'Ressie', 'Reta', 'Retha',\r\n    'Retta', 'Reuben', 'Reva', 'Rex', 'Rey', 'Reyes', 'Reymundo', 'Reyna',\r\n    'Reynold', 'Rhea', 'Rhett', 'Rhianna', 'Rhiannon', 'Rhoda', 'Ricardo',\r\n    'Richard', 'Richie', 'Richmond', 'Rick', 'Rickey', 'Rickie', 'Ricky',\r\n    'Rico', 'Rigoberto', 'Riley', 'Rita', 'River', 'Robb', 'Robbie', 'Robert',\r\n    'Roberta', 'Roberto', 'Robin', 'Robyn', 'Rocio', 'Rocky', 'Rod', 'Roderick',\r\n    'Rodger', 'Rodolfo', 'Rodrick', 'Rodrigo', 'Roel', 'Rogelio', 'Roger',\r\n    'Rogers', 'Rolando', 'Rollin', 'Roma', 'Romaine', 'Roman', 'Ron', 'Ronaldo',\r\n    'Ronny', 'Roosevelt', 'Rory', 'Rosa', 'Rosalee', 'Rosalia', 'Rosalind',\r\n    'Rosalinda', 'Rosalyn', 'Rosamond', 'Rosanna', 'Rosario', 'Roscoe', 'Rose',\r\n    'Rosella', 'Roselyn', 'Rosemarie', 'Rosemary', 'Rosendo', 'Rosetta',\r\n    'Rosie', 'Rosina', 'Roslyn', 'Ross', 'Rossie', 'Rowan', 'Rowena', 'Rowland',\r\n    'Roxane', 'Roxanne', 'Roy', 'Royal', 'Royce', 'Rozella', 'Ruben', 'Rubie',\r\n    'Ruby', 'Rubye', 'Rudolph', 'Rudy', 'Rupert', 'Russ', 'Russel', 'Russell',\r\n    'Rusty', 'Ruth', 'Ruthe', 'Ruthie', 'Ryan', 'Ryann', 'Ryder', 'Rylan',\r\n    'Rylee', 'Ryleigh', 'Ryley', 'Sabina', 'Sabrina', 'Sabryna', 'Sadie',\r\n    'Sadye', 'Sage', 'Saige', 'Sallie', 'Sally', 'Salma', 'Salvador',\r\n    'Salvatore', 'Sam', 'Samanta', 'Samantha', 'Samara', 'Samir', 'Sammie',\r\n    'Sammy', 'Samson', 'Sandra', 'Sandrine', 'Sandy', 'Sanford', 'Santa',\r\n    'Santiago', 'Santina', 'Santino', 'Santos', 'Sarah', 'Sarai', 'Sarina',\r\n    'Sasha', 'Saul', 'Savanah', 'Savanna', 'Savannah', 'Savion', 'Scarlett',\r\n    'Schuyler', 'Scot', 'Scottie', 'Scotty', 'Seamus', 'Sean', 'Sebastian',\r\n    'Sedrick', 'Selena', 'Selina', 'Selmer', 'Serena', 'Serenity', 'Seth',\r\n    'Shad', 'Shaina', 'Shakira', 'Shana', 'Shane', 'Shanel', 'Shanelle',\r\n    'Shania', 'Shanie', 'Shaniya', 'Shanna', 'Shannon', 'Shanny', 'Shanon',\r\n    'Shany', 'Sharon', 'Shaun', 'Shawn', 'Shawna', 'Shaylee', 'Shayna',\r\n    'Shayne', 'Shea', 'Sheila', 'Sheldon', 'Shemar', 'Sheridan', 'Sherman',\r\n    'Sherwood', 'Shirley', 'Shyann', 'Shyanne', 'Sibyl', 'Sid', 'Sidney',\r\n    'Sienna', 'Sierra', 'Sigmund', 'Sigrid', 'Sigurd', 'Silas', 'Sim', 'Simeon',\r\n    'Simone', 'Sincere', 'Sister', 'Skye', 'Skyla', 'Skylar', 'Sofia',\r\n    'Soledad', 'Solon', 'Sonia', 'Sonny', 'Sonya', 'Sophia', 'Sophie',\r\n    'Spencer', 'Stacey', 'Stacy', 'Stan', 'Stanford', 'Stanley', 'Stanton',\r\n    'Stefan', 'Stefanie', 'Stella', 'Stephan', 'Stephania', 'Stephanie',\r\n    'Stephany', 'Stephen', 'Stephon', 'Sterling', 'Steve', 'Stevie', 'Stewart',\r\n    'Stone', 'Stuart', 'Summer', 'Sunny', 'Susan', 'Susana', 'Susanna', 'Susie',\r\n    'Suzanne', 'Sven', 'Syble', 'Sydnee', 'Sydney', 'Sydni', 'Sydnie', 'Sylvan',\r\n    'Sylvester', 'Sylvia', 'Tabitha', 'Tad', 'Talia', 'Talon', 'Tamara',\r\n    'Tamia', 'Tania', 'Tanner', 'Tanya', 'Tara', 'Taryn', 'Tate', 'Tatum',\r\n    'Tatyana', 'Taurean', 'Tavares', 'Taya', 'Taylor', 'Teagan', 'Ted', 'Telly',\r\n    'Terence', 'Teresa', 'Terrance', 'Terrell', 'Terrence', 'Terrill', 'Terry',\r\n    'Tess', 'Tessie', 'Tevin', 'Thad', 'Thaddeus', 'Thalia', 'Thea', 'Thelma',\r\n    'Theo', 'Theodora', 'Theodore', 'Theresa', 'Therese', 'Theresia', 'Theron',\r\n    'Thomas', 'Thora', 'Thurman', 'Tia', 'Tiana', 'Tianna', 'Tiara', 'Tierra',\r\n    'Tiffany', 'Tillman', 'Timmothy', 'Timmy', 'Timothy', 'Tina', 'Tito',\r\n    'Titus', 'Tobin', 'Toby', 'Tod', 'Tom', 'Tomas', 'Tomasa', 'Tommie',\r\n    'Toney', 'Toni', 'Tony', 'Torey', 'Torrance', 'Torrey', 'Toy', 'Trace',\r\n    'Tracey', 'Tracy', 'Travis', 'Travon', 'Tre', 'Tremaine', 'Tremayne',\r\n    'Trent', 'Trenton', 'Tressa', 'Tressie', 'Treva', 'Trever', 'Trevion',\r\n    'Trevor', 'Trey', 'Trinity', 'Trisha', 'Tristian', 'Tristin', 'Triston',\r\n    'Troy', 'Trudie', 'Trycia', 'Trystan', 'Turner', 'Twila', 'Tyler', 'Tyra',\r\n    'Tyree', 'Tyreek', 'Tyrel', 'Tyrell', 'Tyrese', 'Tyrique', 'Tyshawn',\r\n    'Tyson', 'Ubaldo', 'Ulices', 'Ulises', 'Una', 'Unique', 'Urban', 'Uriah',\r\n    'Uriel', 'Ursula', 'Vada', 'Valentin', 'Valentina', 'Valentine', 'Valerie',\r\n    'Vallie', 'Van', 'Vance', 'Vanessa', 'Vaughn', 'Veda', 'Velda', 'Vella',\r\n    'Velma', 'Velva', 'Vena', 'Verda', 'Verdie', 'Vergie', 'Verla', 'Verlie',\r\n    'Vern', 'Verna', 'Verner', 'Vernice', 'Vernie', 'Vernon', 'Verona',\r\n    'Veronica', 'Vesta', 'Vicenta', 'Vicente', 'Vickie', 'Vicky', 'Victor',\r\n    'Victoria', 'Vida', 'Vidal', 'Vilma', 'Vince', 'Vincent', 'Vincenza',\r\n    'Vincenzo', 'Vinnie', 'Viola', 'Violet', 'Violette', 'Virgie', 'Virgil',\r\n    'Virginia', 'Virginie', 'Vita', 'Vito', 'Viva', 'Vivian', 'Viviane',\r\n    'Vivianne', 'Vivien', 'Vivienne', 'Vladimir', 'Wade', 'Waino', 'Waldo',\r\n    'Walker', 'Wallace', 'Walter', 'Walton', 'Wanda', 'Ward', 'Warren',\r\n    'Watson', 'Wava', 'Waylon', 'Wayne', 'Webster', 'Weldon', 'Wellington',\r\n    'Wendell', 'Wendy', 'Werner', 'Westley', 'Weston', 'Whitney', 'Wilber',\r\n    'Wilbert', 'Wilburn', 'Wiley', 'Wilford', 'Wilfred', 'Wilfredo', 'Wilfrid',\r\n    'Wilhelm', 'Wilhelmine', 'Will', 'Willa', 'Willard', 'William', 'Willie',\r\n    'Willis', 'Willow', 'Willy', 'Wilma', 'Wilmer', 'Wilson', 'Wilton',\r\n    'Winfield', 'Winifred', 'Winnifred', 'Winona', 'Winston', 'Woodrow',\r\n    'Wyatt', 'Wyman', 'Xander', 'Xavier', 'Xzavier', 'Yadira', 'Yasmeen',\r\n    'Yasmin', 'Yasmine', 'Yazmin', 'Yesenia', 'Yessenia', 'Yolanda', 'Yoshiko',\r\n    'Yvette', 'Yvonne', 'Zachariah', 'Zachary', 'Zachery', 'Zack', 'Zackary',\r\n    'Zackery', 'Zakary', 'Zander', 'Zane', 'Zaria', 'Zechariah', 'Zelda',\r\n    'Zella', 'Zelma', 'Zena', 'Zetta', 'Zion', 'Zita', 'Zoe', 'Zoey', 'Zoie',\r\n    'Zoila', 'Zola', 'Zora', 'Zula'\r\n];\r\n\r\n/**\r\n * Generate random username.\r\n * @returns {string} random username\r\n */\r\nfunction generateUsername() {\r\n    const name = RandomUtil.randomElement(names);\r\n    const suffix = RandomUtil.randomAlphanumStr(3);\r\n\r\n    return `${name}-${suffix}`;\r\n}\r\n\r\nmodule.exports = {\r\n    generateUsername\r\n};\r\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' ? module.exports = factory() :\n            typeof define === 'function' && define.amd ? define(factory) :\n            (global = global || self, global.strophe = factory());\n}(this, function () { 'use strict';\n\n            var global$1 = (typeof global !== \"undefined\" ? global :\n                        typeof self !== \"undefined\" ? self :\n                        typeof window !== \"undefined\" ? window : {});\n\n            function _typeof(obj) {\n              if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") {\n                _typeof = function (obj) {\n                  return typeof obj;\n                };\n              } else {\n                _typeof = function (obj) {\n                  return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n                };\n              }\n\n              return _typeof(obj);\n            }\n\n            function _toConsumableArray(arr) {\n              return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();\n            }\n\n            function _arrayWithoutHoles(arr) {\n              if (Array.isArray(arr)) {\n                for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];\n\n                return arr2;\n              }\n            }\n\n            function _iterableToArray(iter) {\n              if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter);\n            }\n\n            function _nonIterableSpread() {\n              throw new TypeError(\"Invalid attempt to spread non-iterable instance\");\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            var safe_add = 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            var bit_rol = function bit_rol(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            var str2binl = function str2binl(str) {\n              if (typeof str !== \"string\") {\n                throw new Error(\"str2binl was passed a non-string\");\n              }\n\n              var bin = [];\n\n              for (var 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            var binl2str = function binl2str(bin) {\n              var str = \"\";\n\n              for (var 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            var binl2hex = function binl2hex(binarray) {\n              var hex_tab = \"0123456789abcdef\";\n              var str = \"\";\n\n              for (var 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            var md5_cmn = function md5_cmn(q, a, b, x, s, t) {\n              return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);\n            };\n\n            var md5_ff = function md5_ff(a, b, c, d, x, s, t) {\n              return md5_cmn(b & c | ~b & d, a, b, x, s, t);\n            };\n\n            var md5_gg = function md5_gg(a, b, c, d, x, s, t) {\n              return md5_cmn(b & d | c & ~d, a, b, x, s, t);\n            };\n\n            var md5_hh = function md5_hh(a, b, c, d, x, s, t) {\n              return md5_cmn(b ^ c ^ d, a, b, x, s, t);\n            };\n\n            var md5_ii = function md5_ii(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            var core_md5 = function core_md5(x, len) {\n              /* append padding */\n              x[len >> 5] |= 0x80 << len % 32;\n              x[(len + 64 >>> 9 << 4) + 14] = len;\n              var a = 1732584193;\n              var b = -271733879;\n              var c = -1732584194;\n              var d = 271733878;\n              var olda, oldb, oldc, oldd;\n\n              for (var 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(a, olda);\n                b = safe_add(b, oldb);\n                c = safe_add(c, oldc);\n                d = safe_add(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            var MD5 = {\n              hexdigest: function hexdigest(s) {\n                return binl2hex(core_md5(str2binl(s), s.length * 8));\n              },\n              hash: function hash(s) {\n                return binl2str(core_md5(str2binl(s), s.length * 8));\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$1(safe_add$1(rol(a, 5), sha1_ft(j, b, c, d)), safe_add$1(safe_add$1(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$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                e = safe_add$1(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$1(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            var SHA1 = {\n              b64_hmac_sha1: function b64_hmac_sha1(key, data) {\n                return binb2b64(core_hmac_sha1(key, data));\n              },\n              b64_sha1: function b64_sha1(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 str_hmac_sha1(key, data) {\n                return binb2str(core_hmac_sha1(key, data));\n              },\n              str_sha1: function str_sha1(s) {\n                return binb2str(core_sha1(str2binb(s), s.length * 8));\n              }\n            };\n\n            var utils = {\n              utf16to8: function utf16to8(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 addCookies(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 (var cookieName in cookies) {\n                  if (Object.prototype.hasOwnProperty.call(cookies, cookieName)) {\n                    var expires = '';\n                    var domain = '';\n                    var path = '';\n                    var cookieObj = cookies[cookieName];\n                    var isObj = _typeof(cookieObj) === \"object\";\n                    var 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            /** 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\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\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\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\n            var Strophe = {\n              /** Constant: VERSION */\n              VERSION: \"@VERSION@\",\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: function validTag(tag) {\n                  for (var 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: function validAttribute(tag, attribute) {\n                  if (typeof Strophe.XHTML.attributes[tag] !== 'undefined' && Strophe.XHTML.attributes[tag].length > 0) {\n                    for (var 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                validCSS: function validCSS(style) {\n                  for (var 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              /** 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              },\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: function 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: function forEachChild(elem, elemName, func) {\n                for (var i = 0; i < elem.childNodes.length; i++) {\n                  var 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: function 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              /** PrivateFunction: _makeGenerator\n               *  _Private_ function that creates a dummy XML DOM document to serve as\n               *  an element and text node generator.\n               */\n              _makeGenerator: function _makeGenerator() {\n                var doc; // IE9 does implement createDocument(); however, using it will cause the browser to leak memory on page unload.\n                // Here, we test for presence of createDocument() plus IE's proprietary documentMode attribute, which would be\n                // less than 10 in the case of IE9 and below.\n\n                if (document.implementation.createDocument === undefined || document.implementation.createDocument && document.documentMode && document.documentMode < 10) {\n                  doc = this._getIEXmlDom();\n                  doc.appendChild(doc.createElement('strophe'));\n                } else {\n                  doc = document.implementation.createDocument('jabber:client', 'strophe', null);\n                }\n\n                return doc;\n              },\n\n              /** Function: xmlGenerator\n               *  Get the DOM document to generate elements.\n               *\n               *  Returns:\n               *    The currently used DOM document.\n               */\n              xmlGenerator: function xmlGenerator() {\n                if (!Strophe._xmlGenerator) {\n                  Strophe._xmlGenerator = Strophe._makeGenerator();\n                }\n\n                return Strophe._xmlGenerator;\n              },\n\n              /** PrivateFunction: _getIEXmlDom\n               *  Gets IE xml doc object\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              _getIEXmlDom: function _getIEXmlDom() {\n                var doc = null;\n                var 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 (var d = 0; d < docStrings.length; d++) {\n                  if (doc === null) {\n                    try {\n                      doc = new ActiveXObject(docStrings[d]);\n                    } catch (e) {\n                      doc = null;\n                    }\n                  } else {\n                    break;\n                  }\n                }\n\n                return doc;\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: function xmlElement(name) {\n                if (!name) {\n                  return null;\n                }\n\n                var 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 (var a = 1; a < arguments.length; a++) {\n                  var 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 (var i = 0; i < arg.length; i++) {\n                      var 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 (var 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: function 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: function 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: function 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: function xmlHtmlNode(html) {\n                var node; //ensure text is escaped\n\n                if (DOMParser) {\n                  var 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: function getText(elem) {\n                if (!elem) {\n                  return null;\n                }\n\n                var str = \"\";\n\n                if (elem.childNodes.length === 0 && elem.nodeType === Strophe.ElementType.TEXT) {\n                  str += elem.nodeValue;\n                }\n\n                for (var 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: function copyElement(elem) {\n                var el;\n\n                if (elem.nodeType === Strophe.ElementType.NORMAL) {\n                  el = Strophe.xmlElement(elem.tagName);\n\n                  for (var i = 0; i < elem.attributes.length; i++) {\n                    el.setAttribute(elem.attributes[i].nodeName, elem.attributes[i].value);\n                  }\n\n                  for (var _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: function createHtml(elem) {\n                var el;\n\n                if (elem.nodeType === Strophe.ElementType.NORMAL) {\n                  var 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 (var i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {\n                        var attribute = Strophe.XHTML.attributes[tag][i];\n                        var 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                          var css = [];\n                          var cssAttrs = value.split(';');\n\n                          for (var j = 0; j < cssAttrs.length; j++) {\n                            var attr = cssAttrs[j].split(':');\n                            var cssName = attr[0].replace(/^\\s*/, \"\").replace(/\\s*$/, \"\").toLowerCase();\n\n                            if (Strophe.XHTML.validCSS(cssName)) {\n                              var 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 (var _i2 = 0; _i2 < elem.childNodes.length; _i2++) {\n                        el.appendChild(Strophe.createHtml(elem.childNodes[_i2]));\n                      }\n                    } catch (e) {\n                      // invalid elements\n                      el = Strophe.xmlTextNode('');\n                    }\n                  } else {\n                    el = Strophe.xmlGenerator().createDocumentFragment();\n\n                    for (var _i3 = 0; _i3 < elem.childNodes.length; _i3++) {\n                      el.appendChild(Strophe.createHtml(elem.childNodes[_i3]));\n                    }\n                  }\n                } else if (elem.nodeType === Strophe.ElementType.FRAGMENT) {\n                  el = Strophe.xmlGenerator().createDocumentFragment();\n\n                  for (var _i4 = 0; _i4 < elem.childNodes.length; _i4++) {\n                    el.appendChild(Strophe.createHtml(elem.childNodes[_i4]));\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: function 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: function 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: function 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: function getDomainFromJid(jid) {\n                var bare = Strophe.getBareJidFromJid(jid);\n\n                if (bare.indexOf(\"@\") < 0) {\n                  return bare;\n                } else {\n                  var 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: function getResourceFromJid(jid) {\n                if (!jid) {\n                  return null;\n                }\n\n                var 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: function 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: function _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: function log(level, msg) {\n                if (level === this.LogLevel.FATAL && _typeof(window.console) === 'object' && typeof window.console.error === 'function') {\n                  window.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: function 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: function 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: function 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: function 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: function 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: function serialize(elem) {\n                if (!elem) {\n                  return null;\n                }\n\n                if (typeof elem.tree === \"function\") {\n                  elem = elem.tree();\n                }\n\n                var names = _toConsumableArray(Array(elem.attributes.length).keys()).map(function (i) {\n                  return elem.attributes[i].nodeName;\n                });\n\n                names.sort();\n                var result = names.reduce(function (a, n) {\n                  return \"\".concat(a, \" \").concat(n, \"=\\\"\").concat(Strophe.xmlescape(elem.attributes.getNamedItem(n).value), \"\\\"\");\n                }, \"<\".concat(elem.nodeName));\n\n                if (elem.childNodes.length > 0) {\n                  result += \">\";\n\n                  for (var i = 0; i < elem.childNodes.length; i++) {\n                    var 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: function addConnectionPlugin(name, ptype) {\n                Strophe._connectionPlugins[name] = ptype;\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 = function (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\n            Strophe.Builder.prototype = {\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              tree: function tree() {\n                return this.nodeTree;\n              },\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              toString: function toString() {\n                return Strophe.serialize(this.nodeTree);\n              },\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              up: function up() {\n                this.node = this.node.parentNode;\n                return this;\n              },\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              root: function root() {\n                this.node = this.nodeTree;\n                return this;\n              },\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              attrs: function attrs(moreattrs) {\n                for (var 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\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              c: function c(name, attrs, text) {\n                var 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\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              cnode: function cnode(elem) {\n                var impNode;\n                var xmlGen = Strophe.xmlGenerator();\n\n                try {\n                  impNode = xmlGen.importNode !== undefined;\n                } catch (e) {\n                  impNode = false;\n                }\n\n                var newElem = impNode ? xmlGen.importNode(elem, true) : Strophe.copyElement(elem);\n                this.node.appendChild(newElem);\n                this.node = newElem;\n                return this;\n              },\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              t: function t(text) {\n                var child = Strophe.xmlTextNode(text);\n                this.node.appendChild(child);\n                return this;\n              },\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              h: function h(html) {\n                var fragment = document.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                var 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            /** 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: function getNamespace(elem) {\n                var 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: function namespaceMatch(elem) {\n                var _this = this;\n\n                var nsMatch = false;\n\n                if (!this.ns) {\n                  return true;\n                } else {\n                  Strophe.forEachChild(elem, null, function (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: function isMatch(elem) {\n                var from = elem.getAttribute('from');\n\n                if (this.options.matchBareFromJid) {\n                  from = Strophe.getBareJidFromJid(from);\n                }\n\n                var 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: function run(elem) {\n                var 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: function toString() {\n                return \"{Handler: \" + this.handler + \"(\" + this.name + \",\" + this.id + \",\" + this.ns + \")}\";\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            /** 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\n            Strophe.TimedHandler = function (period, handler) {\n              this.period = period;\n              this.handler = handler;\n              this.lastCalled = new Date().getTime();\n              this.user = true;\n            };\n\n            Strophe.TimedHandler.prototype = {\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              run: function run() {\n                this.lastCalled = new Date().getTime();\n                return this.handler();\n              },\n\n              /** PrivateFunction: reset\n               *  Reset the last called time for the Strophe.TimedHandler.\n               */\n              reset: function reset() {\n                this.lastCalled = new Date().getTime();\n              },\n\n              /** PrivateFunction: toString\n               *  Get a string representation of the Strophe.TimedHandler object.\n               *\n               *  Returns:\n               *    The string representation.\n               */\n              toString: function toString() {\n                return \"{TimedHandler: \" + this.handler + \"(\" + this.period + \")}\";\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 DIGEST-MD5, SASL SCRAM-SHA1\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-SHA1 - 70\n             *      DIGEST-MD5 - 60\n             *      PLAIN - 50\n             *      OAUTH-BEARER - 40\n             *      OAUTH-2 - 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             *  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             *  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 = function (service, options) {\n              var _this2 = this;\n\n              // The service URL\n              this.service = service; // Configuration options\n\n              this.options = options || {};\n              var proto = this.options.protocol || \"\"; // Select protocal based on service or options\n\n              if (service.indexOf(\"ws:\") === 0 || 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              /* The connected JID. */\n\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_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.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(function () {\n                return _this2._onIdle();\n              }, 100);\n              utils.addCookies(this.options.cookies);\n              this.registerSASLMechanisms(this.options.mechanisms); // initialize plugins\n\n              for (var k in Strophe._connectionPlugins) {\n                if (Object.prototype.hasOwnProperty.call(Strophe._connectionPlugins, k)) {\n                  var F = function F() {};\n\n                  F.prototype = Strophe._connectionPlugins[k];\n                  this[k] = new F();\n                  this[k].init(this);\n                }\n              }\n            };\n\n            Strophe.Connection.prototype = {\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              reset: function 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\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              pause: function pause() {\n                this.paused = true;\n              },\n\n              /** Function: resume\n               *  Resume the request manager.\n               *\n               *  This resumes after pause() has been called.\n               */\n              resume: function resume() {\n                this.paused = false;\n              },\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              getUniqueId: function getUniqueId(suffix) {\n                var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n                  var 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\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              addProtocolErrorHandler: function addProtocolErrorHandler(protocol, status_code, callback) {\n                this.protocolErrorHandlers[protocol][status_code] = callback;\n              },\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               */\n              connect: function connect(jid, pass, callback, wait, hold, route, authcid) {\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                /** Variable: servtype\n                 *  Digest MD5 compatibility.\n                 */\n\n                this.servtype = \"xmpp\";\n                this.connect_callback = callback;\n                this.disconnecting = false;\n                this.connected = false;\n                this.authenticated = false;\n                this.restored = false; // 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\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              attach: function attach(jid, sid, rid, callback, wait, hold, wind) {\n                if (this._proto instanceof Strophe.Bosh) {\n                  this._proto._attach(jid, sid, rid, callback, wait, hold, wind);\n                } else {\n                  var error = new Error('The \"attach\" method can only be used with a BOSH connection.');\n                  error.name = 'StropheSessionError';\n                  throw error;\n                }\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              restore: function restore(jid, callback, wait, hold, wind) {\n                if (this._sessionCachingSupported()) {\n                  this._proto._restore(jid, callback, wait, hold, wind);\n                } else {\n                  var error = new Error('The \"restore\" method can only be used with a BOSH connection.');\n                  error.name = 'StropheSessionError';\n                  throw error;\n                }\n              },\n\n              /** PrivateFunction: _sessionCachingSupported\n               * Checks whether sessionStorage and JSON are supported and whether we're\n               * using BOSH.\n               */\n              _sessionCachingSupported: function _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\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              xmlInput: function xmlInput(elem) {\n                return;\n              },\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              xmlOutput: function xmlOutput(elem) {\n                return;\n              },\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              rawInput: function rawInput(data) {\n                return;\n              },\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              rawOutput: function rawOutput(data) {\n                return;\n              },\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              nextValidRid: function nextValidRid(rid) {\n                return;\n              },\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              send: function send(elem) {\n                if (elem === null) {\n                  return;\n                }\n\n                if (typeof elem.sort === \"function\") {\n                  for (var 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\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              flush: function flush() {\n                // cancel the pending idle period and run the idle function\n                // immediately\n                clearTimeout(this._idleTimeout);\n\n                this._onIdle();\n              },\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              sendPresence: function sendPresence(elem, callback, errback, timeout) {\n                var _this3 = this;\n\n                var timeoutHandler = null;\n\n                if (typeof elem.tree === \"function\") {\n                  elem = elem.tree();\n                }\n\n                var 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                  var handler = this.addHandler(function (stanza) {\n                    // remove timeout handler if there is one\n                    if (timeoutHandler) {\n                      _this3.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, function () {\n                      // get rid of normal handler\n                      _this3.deleteHandler(handler); // call errback on timeout with null stanza\n\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\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              sendIQ: function sendIQ(elem, callback, errback, timeout) {\n                var _this4 = this;\n\n                var timeoutHandler = null;\n\n                if (typeof elem.tree === \"function\") {\n                  elem = elem.tree();\n                }\n\n                var 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                  var handler = this.addHandler(function (stanza) {\n                    // remove timeout handler if there is one\n                    if (timeoutHandler) {\n                      _this4.deleteTimedHandler(timeoutHandler);\n                    }\n\n                    var 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                      var error = new Error(\"Got bad IQ type of \".concat(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, function () {\n                      // get rid of normal handler\n                      _this4.deleteHandler(handler); // call errback on timeout with null stanza\n\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\n              /** PrivateFunction: _queueData\n               *  Queue outgoing data for later sending.  Also ensures that the data\n               *  is a DOMElement.\n               */\n              _queueData: function _queueData(element) {\n                if (element === null || !element.tagName || !element.childNodes) {\n                  var error = new Error(\"Cannot queue non-DOMElement.\");\n                  error.name = \"StropheError\";\n                  throw error;\n                }\n\n                this._data.push(element);\n              },\n\n              /** PrivateFunction: _sendRestart\n               *  Send an xmpp:restart stanza.\n               */\n              _sendRestart: function _sendRestart() {\n                var _this5 = this;\n\n                this._data.push(\"restart\");\n\n                this._proto._sendRestart();\n\n                this._idleTimeout = setTimeout(function () {\n                  return _this5._onIdle();\n                }, 100);\n              },\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              addTimedHandler: function addTimedHandler(period, handler) {\n                var thand = new Strophe.TimedHandler(period, handler);\n                this.addTimeds.push(thand);\n                return thand;\n              },\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              deleteTimedHandler: function 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\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              addHandler: function addHandler(handler, ns, name, type, id, from, options) {\n                var hand = new Strophe.Handler(handler, ns, name, type, id, from, options);\n                this.addHandlers.push(hand);\n                return hand;\n              },\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              deleteHandler: function 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                var i = this.addHandlers.indexOf(handRef);\n\n                if (i >= 0) {\n                  this.addHandlers.splice(i, 1);\n                }\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              registerSASLMechanisms: function registerSASLMechanisms(mechanisms) {\n                this.mechanisms = {};\n                mechanisms = mechanisms || [Strophe.SASLAnonymous, Strophe.SASLExternal, Strophe.SASLMD5, Strophe.SASLOAuthBearer, Strophe.SASLXOAuth2, Strophe.SASLPlain, Strophe.SASLSHA1];\n                mechanisms.forEach(this.registerSASLMechanism.bind(this));\n              },\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              registerSASLMechanism: function registerSASLMechanism(mechanism) {\n                this.mechanisms[mechanism.prototype.name] = mechanism;\n              },\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              disconnect: function disconnect(reason) {\n                this._changeConnectStatus(Strophe.Status.DISCONNECTING, reason);\n\n                Strophe.warn(\"Disconnect was called because: \" + reason);\n\n                if (this.connected) {\n                  var 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(3000, 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\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              _changeConnectStatus: function _changeConnectStatus(status, condition, elem) {\n                // notify all plugins listening for status changes\n                for (var k in Strophe._connectionPlugins) {\n                  if (Object.prototype.hasOwnProperty.call(Strophe._connectionPlugins, k)) {\n                    var plugin = this[k];\n\n                    if (plugin.statusChanged) {\n                      try {\n                        plugin.statusChanged(status, condition);\n                      } catch (err) {\n                        Strophe.error(\"\".concat(k, \" plugin caused an exception changing status: \").concat(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: \".concat(e));\n                  }\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              _doDisconnect: function _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\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              _dataRecv: function _dataRecv(req, raw) {\n                var _this6 = this;\n\n                Strophe.debug(\"_dataRecv called\");\n\n                var 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                  var hand = this.removeHandlers.pop();\n                  var 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                var 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                  var cond = elem.getAttribute(\"condition\");\n                  var 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, function (child) {\n                  // process handlers\n                  var newList = _this6.handlers;\n                  _this6.handlers = [];\n\n                  for (var _i5 = 0; _i5 < newList.length; _i5++) {\n                    var _hand = newList[_i5]; // encapsulate 'handler.run' not to lose the whole handler list if\n                    // one of the handlers throws an exception\n\n                    try {\n                      if (_hand.isMatch(child) && (_this6.authenticated || !_hand.user)) {\n                        if (_hand.run(child)) {\n                          _this6.handlers.push(_hand);\n                        }\n                      } else {\n                        _this6.handlers.push(_hand);\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                });\n              },\n\n              /** Attribute: mechanisms\n               *  SASL Mechanisms available for Connection.\n               */\n              mechanisms: {},\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              _connect_cb: function _connect_cb(req, _callback, raw) {\n                Strophe.debug(\"_connect_cb was called\");\n                this.connected = true;\n                var 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                var 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                var 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                var matched = [];\n                var mechanisms = bodyWrap.getElementsByTagName(\"mechanism\");\n\n                if (mechanisms.length > 0) {\n                  for (var i = 0; i < mechanisms.length; i++) {\n                    var mech = Strophe.getText(mechanisms[i]);\n                    if (this.mechanisms[mech]) matched.push(this.mechanisms[mech]);\n                  }\n                }\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\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              sortMechanismsByPriority: function sortMechanismsByPriority(mechanisms) {\n                // Sorting mechanisms according to priority.\n                for (var i = 0; i < mechanisms.length - 1; ++i) {\n                  var higher = i;\n\n                  for (var j = i + 1; j < mechanisms.length; ++j) {\n                    if (mechanisms[j].prototype.priority > mechanisms[higher].prototype.priority) {\n                      higher = j;\n                    }\n                  }\n\n                  if (higher !== i) {\n                    var swap = mechanisms[i];\n                    mechanisms[i] = mechanisms[higher];\n                    mechanisms[higher] = swap;\n                  }\n                }\n\n                return mechanisms;\n              },\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              authenticate: function authenticate(matched) {\n                if (!this._attemptSASLAuth(matched)) {\n                  this._attemptLegacyAuth();\n                }\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              _attemptSASLAuth: function _attemptSASLAuth(mechanisms) {\n                mechanisms = this.sortMechanismsByPriority(mechanisms || []);\n                var mechanism_found = false;\n\n                for (var i = 0; i < mechanisms.length; ++i) {\n                  if (!mechanisms[i].prototype.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 = new mechanisms[i]();\n\n                  this._sasl_mechanism.onStart(this);\n\n                  var request_auth_exchange = $build(\"auth\", {\n                    'xmlns': Strophe.NS.SASL,\n                    'mechanism': this._sasl_mechanism.name\n                  });\n\n                  if (this._sasl_mechanism.isClientFirst) {\n                    var response = this._sasl_mechanism.onChallenge(this, null);\n\n                    request_auth_exchange.t(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\n              /** PrivateFunction: _sasl_challenge_cb\n               *  _Private_ handler for the SASL challenge\n               *\n               */\n              _sasl_challenge_cb: function _sasl_challenge_cb(elem) {\n                var challenge = atob(Strophe.getText(elem));\n\n                var response = this._sasl_mechanism.onChallenge(this, challenge);\n\n                var stanza = $build('response', {\n                  'xmlns': Strophe.NS.SASL\n                });\n\n                if (response !== \"\") {\n                  stanza.t(btoa(response));\n                }\n\n                this.send(stanza.tree());\n                return true;\n              },\n\n              /** PrivateFunction: _attemptLegacyAuth\n               *\n               *  Attempt legacy (i.e. non-SASL) authentication.\n               */\n              _attemptLegacyAuth: function _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\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              _onLegacyAuthIQResult: function _onLegacyAuthIQResult(elem) {\n                // build plaintext auth iq\n                var 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\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              _sasl_success_cb: function _sasl_success_cb(elem) {\n                var _this7 = this;\n\n                if (this._sasl_data[\"server-signature\"]) {\n                  var serverSignature;\n                  var success = atob(Strophe.getText(elem));\n                  var attribMatch = /([a-z]+)=([^,]+)(,|$)/;\n                  var 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                var streamfeature_handlers = [];\n\n                var wrapper = function wrapper(handlers, elem) {\n                  while (handlers.length) {\n                    _this7.deleteHandler(handlers.pop());\n                  }\n\n                  _this7._onStreamFeaturesAfterSASL(elem);\n\n                  return false;\n                };\n\n                streamfeature_handlers.push(this._addSysHandler(function (elem) {\n                  return wrapper(streamfeature_handlers, elem);\n                }, null, \"stream:features\", null, null));\n                streamfeature_handlers.push(this._addSysHandler(function (elem) {\n                  return wrapper(streamfeature_handlers, elem);\n                }, Strophe.NS.STREAM, \"features\", null, null)); // we must send an xmpp:restart now\n\n                this._sendRestart();\n\n                return false;\n              },\n\n              /** PrivateFunction: _onStreamFeaturesAfterSASL\n               *  Parameters:\n               *    (XMLElement) elem - The matching stanza.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n              _onStreamFeaturesAfterSASL: function _onStreamFeaturesAfterSASL(elem) {\n                // save stream:features for future usage\n                this.features = elem;\n\n                for (var i = 0; i < elem.childNodes.length; i++) {\n                  var 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\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              bind: function 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                var 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\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              _onResourceBindResultIQ: function _onResourceBindResultIQ(elem) {\n                if (elem.getAttribute(\"type\") === \"error\") {\n                  Strophe.warn(\"Resource binding failed.\");\n                  var conflict = elem.getElementsByTagName(\"conflict\");\n                  var 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                var bind = elem.getElementsByTagName(\"bind\");\n\n                if (bind.length > 0) {\n                  var jidNode = bind[0].getElementsByTagName(\"jid\");\n\n                  if (jidNode.length > 0) {\n                    this.jid = Strophe.getText(jidNode[0]);\n\n                    if (this.do_session) {\n                      this._establishSession();\n                    } else {\n                      this.authenticated = true;\n\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\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              _establishSession: function _establishSession() {\n                if (!this.do_session) {\n                  throw new Error(\"Strophe.Connection.prototype._establishSession \" + \"called but apparently \".concat(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\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              _onSessionResultIQ: function _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                  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\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              _sasl_failure_cb: function _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\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              _auth2_cb: function _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\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              _addSysTimedHandler: function _addSysTimedHandler(period, handler) {\n                var thand = new Strophe.TimedHandler(period, handler);\n                thand.user = false;\n                this.addTimeds.push(thand);\n                return thand;\n              },\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              _addSysHandler: function _addSysHandler(handler, ns, name, type, id) {\n                var hand = new Strophe.Handler(handler, ns, name, type, id);\n                hand.user = false;\n                this.addHandlers.push(hand);\n                return hand;\n              },\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              _onDisconnectTimeout: function _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\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              _onIdle: function _onIdle() {\n                var _this8 = this;\n\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                  var thand = this.removeTimeds.pop();\n                  var 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                var now = new Date().getTime();\n                var newList = [];\n\n                for (var _i6 = 0; _i6 < this.timedHandlers.length; _i6++) {\n                  var _thand = this.timedHandlers[_i6];\n\n                  if (this.authenticated || !_thand.user) {\n                    var 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(function () {\n                    return _this8._onIdle();\n                  }, 100);\n                }\n              }\n            };\n            /** Class: Strophe.SASLMechanism\n             *\n             *  encapsulates SASL authentication mechanisms.\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             *      OAUTHBEARER - 60\n             *      SCRAM-SHA1 - 50\n             *      DIGEST-MD5 - 40\n             *      PLAIN - 30\n             *      ANONYMOUS - 20\n             *      EXTERNAL - 10\n             *\n             *  See: Strophe.Connection.addSupportedSASLMechanisms\n             */\n\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\n            Strophe.SASLMechanism = function (name, isClientFirst, priority) {\n              /** PrivateVariable: name\n               *  Mechanism name.\n               */\n              this.name = 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               *  In the default configuration the priorities are\n               *\n               *  SCRAM-SHA1 - 40\n               *  DIGEST-MD5 - 30\n               *  Plain - 20\n               *\n               *  Example: (This will cause Strophe to choose the mechanism that the server sent first)\n               *\n               *  > Strophe.SASLMD5.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            Strophe.SASLMechanism.prototype = {\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              test: function test(connection) {\n                return true;\n              },\n\n              /** PrivateFunction: onStart\n               *  Called before starting mechanism on some connection.\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - Target Connection.\n               */\n              onStart: function onStart(connection) {\n                this._connection = connection;\n              },\n\n              /** PrivateFunction: onChallenge\n               *  Called by protocol implementation on incoming challenge. If client is\n               *  first (isClientFirst === true) challenge will be null on the first call.\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              onChallenge: function onChallenge(connection, challenge) {\n                throw new Error(\"You should implement challenge handling!\");\n              },\n\n              /** PrivateFunction: onFailure\n               *  Protocol informs mechanism implementation about SASL failure.\n               */\n              onFailure: function onFailure() {\n                this._connection = null;\n              },\n\n              /** PrivateFunction: onSuccess\n               *  Protocol informs mechanism implementation about SASL success.\n               */\n              onSuccess: function onSuccess() {\n                this._connection = null;\n              }\n            };\n            /** Constants: SASL mechanisms\n             *  Available authentication mechanisms\n             *\n             *  Strophe.SASLAnonymous - SASL ANONYMOUS authentication.\n             *  Strophe.SASLPlain - SASL PLAIN authentication.\n             *  Strophe.SASLMD5 - SASL DIGEST-MD5 authentication\n             *  Strophe.SASLSHA1 - SASL SCRAM-SHA1 authentication\n             *  Strophe.SASLOAuthBearer - SASL OAuth Bearer authentication\n             *  Strophe.SASLExternal - SASL EXTERNAL authentication\n             *  Strophe.SASLXOAuth2 - SASL X-OAuth2 authentication\n             */\n            // Building SASL callbacks\n\n            /** PrivateConstructor: SASLAnonymous\n             *  SASL ANONYMOUS authentication.\n             */\n\n            Strophe.SASLAnonymous = function () {};\n\n            Strophe.SASLAnonymous.prototype = new Strophe.SASLMechanism(\"ANONYMOUS\", false, 20);\n\n            Strophe.SASLAnonymous.prototype.test = function (connection) {\n              return connection.authcid === null;\n            };\n            /** PrivateConstructor: SASLPlain\n             *  SASL PLAIN authentication.\n             */\n\n\n            Strophe.SASLPlain = function () {};\n\n            Strophe.SASLPlain.prototype = new Strophe.SASLMechanism(\"PLAIN\", true, 50);\n\n            Strophe.SASLPlain.prototype.test = function (connection) {\n              return connection.authcid !== null;\n            };\n\n            Strophe.SASLPlain.prototype.onChallenge = function (connection) {\n              var auth_str = connection.authzid;\n              auth_str = auth_str + \"\\0\";\n              auth_str = auth_str + connection.authcid;\n              auth_str = auth_str + \"\\0\";\n              auth_str = auth_str + connection.pass;\n              return utils.utf16to8(auth_str);\n            };\n            /** PrivateConstructor: SASLSHA1\n             *  SASL SCRAM SHA 1 authentication.\n             */\n\n\n            Strophe.SASLSHA1 = function () {};\n\n            Strophe.SASLSHA1.prototype = new Strophe.SASLMechanism(\"SCRAM-SHA-1\", true, 70);\n\n            Strophe.SASLSHA1.prototype.test = function (connection) {\n              return connection.authcid !== null;\n            };\n\n            Strophe.SASLSHA1.prototype.onChallenge = function (connection, challenge, test_cnonce) {\n              var cnonce = test_cnonce || MD5.hexdigest(\"\" + Math.random() * 1234567890);\n              var 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\n              this.onChallenge = function (connection, challenge) {\n                var nonce, salt, iter, Hi, U, U_old, i, k;\n                var responseText = \"c=biws,\";\n                var authMessage = \"\".concat(connection._sasl_data[\"client-first-message-bare\"], \",\").concat(challenge, \",\");\n                var cnonce = connection._sasl_data.cnonce;\n                var attribMatch = /([a-z]+)=([^,]+)(,|$)/;\n\n                while (challenge.match(attribMatch)) {\n                  var 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.substr(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                var 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                var clientKey = SHA1.core_hmac_sha1(Hi, \"Client Key\");\n                var serverKey = SHA1.str_hmac_sha1(Hi, \"Server Key\");\n                var 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              return auth_str;\n            };\n            /** PrivateConstructor: SASLMD5\n             *  SASL DIGEST MD5 authentication.\n             */\n\n\n            Strophe.SASLMD5 = function () {};\n\n            Strophe.SASLMD5.prototype = new Strophe.SASLMechanism(\"DIGEST-MD5\", false, 60);\n\n            Strophe.SASLMD5.prototype.test = function (connection) {\n              return connection.authcid !== null;\n            };\n            /** PrivateFunction: _quote\n             *  _Private_ utility function to backslash escape and quote strings.\n             *\n             *  Parameters:\n             *    (String) str - The string to be quoted.\n             *\n             *  Returns:\n             *    quoted string\n             */\n\n\n            Strophe.SASLMD5.prototype._quote = function (str) {\n              return '\"' + str.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"') + '\"'; //\" end string workaround for emacs\n            };\n\n            Strophe.SASLMD5.prototype.onChallenge = function (connection, challenge, test_cnonce) {\n              var attribMatch = /([a-z]+)=(\"[^\"]+\"|[^,\"]+)(?:,|$)/;\n              var cnonce = test_cnonce || MD5.hexdigest(\"\" + Math.random() * 1234567890);\n              var realm = \"\";\n              var host = null;\n              var nonce = \"\";\n              var qop = \"\";\n\n              while (challenge.match(attribMatch)) {\n                var matches = challenge.match(attribMatch);\n                challenge = challenge.replace(matches[0], \"\");\n                matches[2] = matches[2].replace(/^\"(.+)\"$/, \"$1\");\n\n                switch (matches[1]) {\n                  case \"realm\":\n                    realm = matches[2];\n                    break;\n\n                  case \"nonce\":\n                    nonce = matches[2];\n                    break;\n\n                  case \"qop\":\n                    qop = matches[2];\n                    break;\n\n                  case \"host\":\n                    host = matches[2];\n                    break;\n                }\n              }\n\n              var digest_uri = connection.servtype + \"/\" + connection.domain;\n\n              if (host !== null) {\n                digest_uri = digest_uri + \"/\" + host;\n              }\n\n              var cred = utils.utf16to8(connection.authcid + \":\" + realm + \":\" + this._connection.pass);\n              var A1 = MD5.hash(cred) + \":\" + nonce + \":\" + cnonce;\n              var A2 = 'AUTHENTICATE:' + digest_uri;\n              var responseText = \"\";\n              responseText += 'charset=utf-8,';\n              responseText += 'username=' + this._quote(utils.utf16to8(connection.authcid)) + ',';\n              responseText += 'realm=' + this._quote(realm) + ',';\n              responseText += 'nonce=' + this._quote(nonce) + ',';\n              responseText += 'nc=00000001,';\n              responseText += 'cnonce=' + this._quote(cnonce) + ',';\n              responseText += 'digest-uri=' + this._quote(digest_uri) + ',';\n              responseText += 'response=' + MD5.hexdigest(MD5.hexdigest(A1) + \":\" + nonce + \":00000001:\" + cnonce + \":auth:\" + MD5.hexdigest(A2)) + \",\";\n              responseText += 'qop=auth';\n\n              this.onChallenge = function () {\n                return \"\";\n              };\n\n              return responseText;\n            };\n            /** PrivateConstructor: SASLOAuthBearer\n             *  SASL OAuth Bearer authentication.\n             */\n\n\n            Strophe.SASLOAuthBearer = function () {};\n\n            Strophe.SASLOAuthBearer.prototype = new Strophe.SASLMechanism(\"OAUTHBEARER\", true, 40);\n\n            Strophe.SASLOAuthBearer.prototype.test = function (connection) {\n              return connection.pass !== null;\n            };\n\n            Strophe.SASLOAuthBearer.prototype.onChallenge = function (connection) {\n              var 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 + \"\\x01\";\n              auth_str = auth_str + 'auth=Bearer ';\n              auth_str = auth_str + connection.pass;\n              auth_str = auth_str + \"\\x01\";\n              auth_str = auth_str + \"\\x01\";\n              return utils.utf16to8(auth_str);\n            };\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\n\n            Strophe.SASLExternal = function () {};\n\n            Strophe.SASLExternal.prototype = new Strophe.SASLMechanism(\"EXTERNAL\", true, 10);\n\n            Strophe.SASLExternal.prototype.onChallenge = function (connection) {\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            /** PrivateConstructor: SASLXOAuth2\n             *  SASL X-OAuth2 authentication.\n             */\n\n\n            Strophe.SASLXOAuth2 = function () {};\n\n            Strophe.SASLXOAuth2.prototype = new Strophe.SASLMechanism(\"X-OAUTH2\", true, 30);\n\n            Strophe.SASLXOAuth2.prototype.test = function (connection) {\n              return connection.pass !== null;\n            };\n\n            Strophe.SASLXOAuth2.prototype.onChallenge = function (connection) {\n              var auth_str = \"\\0\";\n\n              if (connection.authcid !== null) {\n                auth_str = auth_str + connection.authzid;\n              }\n\n              auth_str = auth_str + \"\\0\";\n              auth_str = auth_str + connection.pass;\n              return utils.utf16to8(auth_str);\n            };\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            var Strophe$1 = core.Strophe;\n            var $build$1 = core.$build;\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            /** 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\n            Strophe$1.Request = function (elem, func, rid, sends) {\n              this.id = ++Strophe$1._requestId;\n              this.xmlData = elem;\n              this.data = Strophe$1.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                var 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                var now = new Date();\n                return (now - this.dead) / 1000;\n              };\n\n              this.xhr = this._newXHR();\n            };\n\n            Strophe$1.Request.prototype = {\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              getResponse: function getResponse() {\n                var 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$1.error(\"invalid response received\");\n                    Strophe$1.error(\"responseText: \" + this.xhr.responseText);\n                    Strophe$1.error(\"responseXML: \" + Strophe$1.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$1.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$1.error(\"invalid response received: \" + node.querySelector('parsererror').textContent);\n                    Strophe$1.error(\"responseText: \" + this.xhr.responseText);\n                    var error = new Error();\n                    error.name = Strophe$1.ErrorCondition.BAD_FORMAT;\n                    throw error;\n                  }\n                }\n\n                return node;\n              },\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              _newXHR: function _newXHR() {\n                var 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            /** 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$1.Bosh = function (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\n            Strophe$1.Bosh.prototype = {\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              strip: null,\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              _buildBody: function _buildBody() {\n                var bodyWrap = $build$1('body', {\n                  'rid': this.rid++,\n                  'xmlns': Strophe$1.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\n              /** PrivateFunction: _reset\n               *  Reset the connection.\n               *\n               *  This function is called by the reset function of the Strophe Connection\n               */\n              _reset: function _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\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              _connect: function _connect(wait, hold, route) {\n                this.wait = wait || this.wait;\n                this.hold = hold || this.hold;\n                this.errors = 0;\n\n                var 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$1.NS.BOSH\n                });\n\n                if (route) {\n                  body.attrs({\n                    'route': route\n                  });\n                }\n\n                var _connect_cb = this._conn._connect_cb;\n\n                this._requests.push(new Strophe$1.Request(body.tree(), this._onRequestStateChange.bind(this, _connect_cb.bind(this._conn)), body.tree().getAttribute(\"rid\")));\n\n                this._throttledRequestHandler();\n              },\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              _attach: function _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$1.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$1.Status.ATTACHED, null);\n              },\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              _restore: function _restore(jid, callback, wait, hold, wind) {\n                var 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$1.getBareJidFromJid(session.jid) === Strophe$1.getBareJidFromJid(jid) || // If authcid is null, then it's an anonymous login, so\n                // we compare only the domains:\n                Strophe$1.getNodeFromJid(jid) === null && Strophe$1.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                  var error = new Error(\"_restore: no restoreable session.\");\n                  error.name = \"StropheSessionError\";\n                  throw error;\n                }\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              _cacheSession: function _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\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              _connect_cb: function _connect_cb(bodyWrap) {\n                var typ = bodyWrap.getAttribute(\"type\");\n\n                if (typ !== null && typ === \"terminate\") {\n                  // an error occurred\n                  var cond = bodyWrap.getAttribute(\"condition\");\n                  Strophe$1.error(\"BOSH-Connection failed: \" + cond);\n                  var 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$1.Status.CONNFAIL, cond);\n                  } else {\n                    this._conn._changeConnectStatus(Strophe$1.Status.CONNFAIL, \"unknown\");\n                  }\n\n                  this._conn._doDisconnect(cond);\n\n                  return Strophe$1.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                var wind = bodyWrap.getAttribute('requests');\n\n                if (wind) {\n                  this.window = parseInt(wind, 10);\n                }\n\n                var hold = bodyWrap.getAttribute('hold');\n\n                if (hold) {\n                  this.hold = parseInt(hold, 10);\n                }\n\n                var wait = bodyWrap.getAttribute('wait');\n\n                if (wait) {\n                  this.wait = parseInt(wait, 10);\n                }\n\n                var inactivity = bodyWrap.getAttribute('inactivity');\n\n                if (inactivity) {\n                  this.inactivity = parseInt(inactivity, 10);\n                }\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              _disconnect: function _disconnect(pres) {\n                this._sendTerminate(pres);\n              },\n\n              /** PrivateFunction: _doDisconnect\n               *  _Private_ function to disconnect.\n               *\n               *  Resets the SID and RID.\n               */\n              _doDisconnect: function _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\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              _emptyQueue: function _emptyQueue() {\n                return this._requests.length === 0;\n              },\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              _callProtocolErrorHandlers: function _callProtocolErrorHandlers(req) {\n                var reqStatus = this._getRequestStatus(req);\n\n                var err_callback = this._conn.protocolErrorHandlers.HTTP[reqStatus];\n\n                if (err_callback) {\n                  err_callback.call(this, reqStatus);\n                }\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              _hitError: function _hitError(reqStatus) {\n                this.errors++;\n                Strophe$1.warn(\"request errored, status: \" + reqStatus + \", number of errors: \" + this.errors);\n\n                if (this.errors > 4) {\n                  this._conn._onDisconnectTimeout();\n                }\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              _no_auth_received: function _no_auth_received(callback) {\n                Strophe$1.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                var body = this._buildBody();\n\n                this._requests.push(new Strophe$1.Request(body.tree(), this._onRequestStateChange.bind(this, callback), body.tree().getAttribute(\"rid\")));\n\n                this._throttledRequestHandler();\n              },\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              _onDisconnectTimeout: function _onDisconnectTimeout() {\n                this._abortAllRequests();\n              },\n\n              /** PrivateFunction: _abortAllRequests\n               *  _Private_ helper function that makes sure all pending requests are aborted.\n               */\n              _abortAllRequests: function _abortAllRequests() {\n                while (this._requests.length > 0) {\n                  var req = this._requests.pop();\n\n                  req.abort = true;\n                  req.xhr.abort();\n\n                  req.xhr.onreadystatechange = function () {};\n                }\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              _onIdle: function _onIdle() {\n                var 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$1.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                  var body = this._buildBody();\n\n                  for (var 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$1.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$1.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                  var time_elapsed = this._requests[0].age();\n\n                  if (this._requests[0].dead !== null) {\n                    if (this._requests[0].timeDead() > Math.floor(Strophe$1.SECONDARY_TIMEOUT * this.wait)) {\n                      this._throttledRequestHandler();\n                    }\n                  }\n\n                  if (time_elapsed > Math.floor(Strophe$1.TIMEOUT * this.wait)) {\n                    Strophe$1.warn(\"Request \" + this._requests[0].id + \" timed out, over \" + Math.floor(Strophe$1.TIMEOUT * this.wait) + \" seconds since last activity\");\n\n                    this._throttledRequestHandler();\n                  }\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              _getRequestStatus: function _getRequestStatus(req, def) {\n                var 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$1.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\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              _onRequestStateChange: function _onRequestStateChange(func, req) {\n                Strophe$1.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                var reqStatus = this._getRequestStatus(req);\n\n                this.lastResponseHeaders = req.xhr.getAllResponseHeaders();\n\n                if (this.disconnecting && reqStatus >= 400) {\n                  this._hitError(reqStatus);\n\n                  this._callProtocolErrorHandlers(req);\n\n                  return;\n                }\n\n                var valid_request = reqStatus > 0 && reqStatus < 500;\n                var 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$1.debug(\"request id \" + req.id + \" should now be removed\");\n                }\n\n                if (reqStatus === 200) {\n                  // request succeeded\n                  var reqIs0 = this._requests[0] === req;\n                  var reqIs1 = this._requests[1] === req; // 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\n                  if (reqIs1 || reqIs0 && this._requests.length > 0 && this._requests[0].age() > Math.floor(Strophe$1.SECONDARY_TIMEOUT * this.wait)) {\n                    this._restartRequest(0);\n                  }\n\n                  this._conn.nextValidRid(Number(req.rid) + 1);\n\n                  Strophe$1.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$1.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$1.Status.DISCONNECTING, null);\n\n                    this._conn._doDisconnect();\n                  }\n                } else {\n                  Strophe$1.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$1.Status.CONNFAIL, \"giving-up\");\n                }\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              _processRequest: function _processRequest(i) {\n                var _this = this;\n\n                var req = this._requests[i];\n\n                var reqStatus = this._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                var time_elapsed = req.age();\n                var primary_timeout = !isNaN(time_elapsed) && time_elapsed > Math.floor(Strophe$1.TIMEOUT * this.wait);\n                var secondary_timeout = req.dead !== null && req.timeDead() > Math.floor(Strophe$1.SECONDARY_TIMEOUT * this.wait);\n                var 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$1.error(\"Request \".concat(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$1.Request(req.xmlData, req.origFunc, req.rid, req.sends);\n                  req = this._requests[i];\n                }\n\n                if (req.xhr.readyState === 0) {\n                  Strophe$1.debug(\"request id \" + req.id + \".\" + req.sends + \" posting\");\n\n                  try {\n                    var 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$1.error(\"XHR open failed: \" + e2.toString());\n\n                    if (!this._conn.connected) {\n                      this._conn._changeConnectStatus(Strophe$1.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                  var sendFunc = function sendFunc() {\n                    req.date = new Date();\n\n                    if (_this._conn.options.customHeaders) {\n                      var headers = _this._conn.options.customHeaders;\n\n                      for (var 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                    var backoff = Math.min(Math.floor(Strophe$1.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$1.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$1.Connection.prototype.rawOutput) {\n                    this._conn.rawOutput(req.data);\n                  }\n                } else {\n                  Strophe$1.debug(\"_processRequest: \" + (i === 0 ? \"first\" : \"second\") + \" request has readyState of \" + req.xhr.readyState);\n                }\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              _removeRequest: function _removeRequest(req) {\n                Strophe$1.debug(\"removing request\");\n\n                for (var 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\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              _restartRequest: function _restartRequest(i) {\n                var req = this._requests[i];\n\n                if (req.dead === null) {\n                  req.dead = new Date();\n                }\n\n                this._processRequest(i);\n              },\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              _reqToData: function _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\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              _sendTerminate: function _sendTerminate(pres) {\n                Strophe$1.debug(\"_sendTerminate was called\");\n\n                var body = this._buildBody().attrs({\n                  type: \"terminate\"\n                });\n\n                if (pres) {\n                  body.cnode(pres.tree());\n                }\n\n                var req = new Strophe$1.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\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              _send: function _send() {\n                var _this2 = this;\n\n                clearTimeout(this._conn._idleTimeout);\n\n                this._throttledRequestHandler();\n\n                this._conn._idleTimeout = setTimeout(function () {\n                  return _this2._conn._onIdle();\n                }, 100);\n              },\n\n              /** PrivateFunction: _sendRestart\n               *\n               *  Send an xmpp:restart stanza.\n               */\n              _sendRestart: function _sendRestart() {\n                this._throttledRequestHandler();\n\n                clearTimeout(this._conn._idleTimeout);\n              },\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              _throttledRequestHandler: function _throttledRequestHandler() {\n                if (!this._requests) {\n                  Strophe$1.debug(\"_throttledRequestHandler called with \" + \"undefined requests\");\n                } else {\n                  Strophe$1.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            /*\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            var Strophe$2 = core.Strophe;\n            var $build$2 = core.$build;\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            /** 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\n            Strophe$2.Websocket = function (connection) {\n              this._conn = connection;\n              this.strip = \"wrapper\";\n              var 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                var 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\n            Strophe$2.Websocket.prototype = {\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              _buildStream: function _buildStream() {\n                return $build$2(\"open\", {\n                  \"xmlns\": Strophe$2.NS.FRAMING,\n                  \"to\": this._conn.domain,\n                  \"version\": '1.0'\n                });\n              },\n\n              /** PrivateFunction: _check_streamerror\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              _check_streamerror: function _check_streamerror(bodyWrap, connectstatus) {\n                var errors;\n\n                if (bodyWrap.getElementsByTagNameNS) {\n                  errors = bodyWrap.getElementsByTagNameNS(Strophe$2.NS.STREAM, \"error\");\n                } else {\n                  errors = bodyWrap.getElementsByTagName(\"stream:error\");\n                }\n\n                if (errors.length === 0) {\n                  return false;\n                }\n\n                var error = errors[0];\n                var condition = \"\";\n                var text = \"\";\n                var ns = \"urn:ietf:params:xml:ns:xmpp-streams\";\n\n                for (var i = 0; i < error.childNodes.length; i++) {\n                  var 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                var 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$2.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\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              _reset: function _reset() {\n                return;\n              },\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              _connect: function _connect() {\n                // Ensure that there is no open WebSocket from a previous Connection.\n                this._closeSocket(); // Create the new WobSocket\n\n\n                this.socket = new WebSocket(this._conn.service, \"xmpp\");\n                this.socket.onopen = this._onOpen.bind(this);\n                this.socket.onerror = this._onError.bind(this);\n                this.socket.onclose = this._onClose.bind(this);\n                this.socket.onmessage = this._connect_cb_wrapper.bind(this);\n              },\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              _connect_cb: function _connect_cb(bodyWrap) {\n                var error = this._check_streamerror(bodyWrap, Strophe$2.Status.CONNFAIL);\n\n                if (error) {\n                  return Strophe$2.Status.CONNFAIL;\n                }\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              _handleStreamStart: function _handleStreamStart(message) {\n                var error = false; // Check for errors in the <open /> tag\n\n                var ns = message.getAttribute(\"xmlns\");\n\n                if (typeof ns !== \"string\") {\n                  error = \"Missing xmlns in <open />\";\n                } else if (ns !== Strophe$2.NS.FRAMING) {\n                  error = \"Wrong xmlns in <open />: \" + ns;\n                }\n\n                var 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$2.Status.CONNFAIL, error);\n\n                  this._conn._doDisconnect();\n\n                  return false;\n                }\n\n                return true;\n              },\n\n              /** PrivateFunction: _connect_cb_wrapper\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              _connect_cb_wrapper: function _connect_cb_wrapper(message) {\n                if (message.data.indexOf(\"<open \") === 0 || message.data.indexOf(\"<?xml\") === 0) {\n                  // Strip the XML Declaration, if there is one\n                  var data = message.data.replace(/^(<\\?.*?\\?>\\s*)*/, \"\");\n                  if (data === '') return;\n                  var 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                  var 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                  var see_uri = parsedMessage.getAttribute(\"see-other-uri\");\n\n                  if (see_uri) {\n                    var service = this._conn.service; // Valid scenarios: WSS->WSS, WS->ANY\n\n                    var isSecureRedirect = service.indexOf(\"wss:\") >= 0 && see_uri.indexOf(\"wss:\") >= 0 || service.indexOf(\"ws:\") >= 0;\n\n                    if (isSecureRedirect) {\n                      this._conn._changeConnectStatus(Strophe$2.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$2.Status.CONNFAIL, \"Received closing stream\");\n\n                    this._conn._doDisconnect();\n                  }\n                } else {\n                  var string = this._streamWrap(message.data);\n\n                  var elem = new DOMParser().parseFromString(string, \"text/xml\").documentElement;\n                  this.socket.onmessage = this._onMessage.bind(this);\n\n                  this._conn._connect_cb(elem, null, message.data);\n                }\n              },\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              _disconnect: function _disconnect(pres) {\n                if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {\n                  if (pres) {\n                    this._conn.send(pres);\n                  }\n\n                  var close = $build$2(\"close\", {\n                    \"xmlns\": Strophe$2.NS.FRAMING\n                  });\n\n                  this._conn.xmlOutput(close.tree());\n\n                  var closeString = Strophe$2.serialize(close);\n\n                  this._conn.rawOutput(closeString);\n\n                  try {\n                    this.socket.send(closeString);\n                  } catch (e) {\n                    Strophe$2.warn(\"Couldn't send <close /> tag.\");\n                  }\n                }\n\n                this._conn._doDisconnect();\n              },\n\n              /** PrivateFunction: _doDisconnect\n               *  _Private_ function to disconnect.\n               *\n               *  Just closes the Socket for WebSockets\n               */\n              _doDisconnect: function _doDisconnect() {\n                Strophe$2.debug(\"WebSockets _doDisconnect was called\");\n\n                this._closeSocket();\n              },\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              _streamWrap: function _streamWrap(stanza) {\n                return \"<wrapper>\" + stanza + '</wrapper>';\n              },\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              _closeSocket: function _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$2.debug(e.message);\n                  }\n                }\n\n                this.socket = null;\n              },\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              _emptyQueue: function _emptyQueue() {\n                return true;\n              },\n\n              /** PrivateFunction: _onClose\n               * _Private_ function to handle websockets closing.\n               *\n               * Nothing to do here for WebSockets\n               */\n              _onClose: function _onClose(e) {\n                if (this._conn.connected && !this._conn.disconnecting) {\n                  Strophe$2.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$2.error(\"Websocket closed unexcectedly\");\n\n                  this._conn._changeConnectStatus(Strophe$2.Status.CONNFAIL, \"The WebSocket connection could not be established or was disconnected.\");\n\n                  this._conn._doDisconnect();\n                } else {\n                  Strophe$2.debug(\"Websocket closed\");\n                }\n              },\n\n              /** PrivateFunction: _no_auth_received\n               *\n               * Called on stream start/restart when no stream:features\n               * has been received.\n               */\n              _no_auth_received: function _no_auth_received(callback) {\n                Strophe$2.error(\"Server did not offer a supported authentication mechanism\");\n\n                this._conn._changeConnectStatus(Strophe$2.Status.CONNFAIL, Strophe$2.ErrorCondition.NO_AUTH_MECH);\n\n                if (callback) {\n                  callback.call(this._conn);\n                }\n\n                this._conn._doDisconnect();\n              },\n\n              /** PrivateFunction: _onDisconnectTimeout\n               *  _Private_ timeout handler for handling non-graceful disconnection.\n               *\n               *  This does nothing for WebSockets\n               */\n              _onDisconnectTimeout: function _onDisconnectTimeout() {},\n\n              /** PrivateFunction: _abortAllRequests\n               *  _Private_ helper function that makes sure all pending requests are aborted.\n               */\n              _abortAllRequests: function _abortAllRequests() {},\n\n              /** PrivateFunction: _onError\n               * _Private_ function to handle websockets errors.\n               *\n               * Parameters:\n               * (Object) error - The websocket error.\n               */\n              _onError: function _onError(error) {\n                Strophe$2.error(\"Websocket error \" + error);\n\n                this._conn._changeConnectStatus(Strophe$2.Status.CONNFAIL, \"The WebSocket connection could not be established or was disconnected.\");\n\n                this._disconnect();\n              },\n\n              /** PrivateFunction: _onIdle\n               *  _Private_ function called by Strophe.Connection._onIdle\n               *\n               *  sends all queued stanzas\n               */\n              _onIdle: function _onIdle() {\n                var data = this._conn._data;\n\n                if (data.length > 0 && !this._conn.paused) {\n                  for (var i = 0; i < data.length; i++) {\n                    if (data[i] !== null) {\n                      var stanza = void 0;\n\n                      if (data[i] === \"restart\") {\n                        stanza = this._buildStream().tree();\n                      } else {\n                        stanza = data[i];\n                      }\n\n                      var rawStanza = Strophe$2.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\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              _onMessage: function _onMessage(message) {\n                var elem; // check for closing stream\n\n                var 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                  var data = this._streamWrap(message.data);\n\n                  elem = new DOMParser().parseFromString(data, \"text/xml\").documentElement;\n                }\n\n                if (this._check_streamerror(elem, Strophe$2.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$2.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\n              /** PrivateFunction: _onOpen\n               * _Private_ function to handle websockets connection setup.\n               *\n               * The opening stream tag is sent here.\n               */\n              _onOpen: function _onOpen() {\n                Strophe$2.debug(\"Websocket open\");\n\n                var start = this._buildStream();\n\n                this._conn.xmlOutput(start.tree());\n\n                var startString = Strophe$2.serialize(start);\n\n                this._conn.rawOutput(startString);\n\n                this.socket.send(startString);\n              },\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              _reqToData: function _reqToData(stanza) {\n                return stanza;\n              },\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              _send: function _send() {\n                this._conn.flush();\n              },\n\n              /** PrivateFunction: _sendRestart\n               *\n               *  Send an xmpp:restart stanza.\n               */\n              _sendRestart: function _sendRestart() {\n                clearTimeout(this._conn._idleTimeout);\n\n                this._conn._onIdle.bind(this._conn)();\n              }\n            };\n\n            global$1.Strophe = core.Strophe;\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\n            return core;\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 property in this._resumeState) {\n\t\t\t\tthis._c[property] = this._resumeState[property];\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 && elem.firstElementChild && elem.firstElementChild.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;","/**\r\n * Enumeration of the video types that are signaled to the bridge\r\n * @type {{CAMERA: string, DESKTOP: string, DESKTOP_HIGH_FPS: string, NONE: string}}\r\n */\r\nconst BridgeVideoType = {\r\n    /**\r\n     * The camera video type.\r\n     */\r\n    CAMERA: 'camera',\r\n\r\n    /**\r\n     * The low fps desktop video type.\r\n     */\r\n    DESKTOP: 'desktop',\r\n\r\n    /**\r\n     * The high fps desktop video type.\r\n     */\r\n    DESKTOP_HIGH_FPS: 'desktop_high_fps',\r\n\r\n    /**\r\n     * Video type when no local source is present.\r\n     */\r\n    NONE: 'none'\r\n};\r\n\r\nmodule.exports = BridgeVideoType;\r\n","/**\r\n * The possible camera facing modes. For now support only 'user' and\r\n * 'environment' because 'left' and 'right' are not used anywhere in our\r\n * projects at the time of this writing. For more information please refer to\r\n * https://w3c.github.io/mediacapture-main/getusermedia.html\r\n * #def-constraint-facingMode.\r\n *\r\n * @enum {string}\r\n */\r\nconst CameraFacingMode = {\r\n    /**\r\n     * The mode which specifies the environment-facing camera.\r\n     */\r\n    ENVIRONMENT: 'environment',\r\n\r\n    /**\r\n     * The mode which specifies the user-facing camera.\r\n     */\r\n    USER: 'user'\r\n};\r\n\r\nmodule.exports = CameraFacingMode;\r\n","/**\r\n * Enumeration of the codec mime types\r\n * @type {{H264: string, OPUS: string, ULPFEC: string, VP8: string, VP9: string}}\r\n */\r\nconst CodecMimeType = {\r\n    /**\r\n     * AV1 codec mime type.\r\n     */\r\n    AV1: 'av1',\r\n\r\n    /**\r\n     * The h264 codec mime type.\r\n     */\r\n    H264: 'h264',\r\n\r\n    /**\r\n     * The opus codec mime type.\r\n     */\r\n    OPUS: 'opus',\r\n\r\n    /**\r\n     * The ulpfec codec mime type.\r\n     */\r\n    ULPFEC: 'ulpfec',\r\n\r\n    /**\r\n     * The vp8 codec mime type.\r\n     */\r\n    VP8: 'vp8',\r\n\r\n    /**\r\n     * The vp9 codec mime type.\r\n     */\r\n    VP9: 'vp9'\r\n\r\n};\r\n\r\nmodule.exports = CodecMimeType;\r\n","export enum RTCEvents {\r\n    /**\r\n     * Indicates error while create answer call.\r\n     */\r\n    CREATE_ANSWER_FAILED = 'rtc.create_answer_failed',\r\n\r\n    /**\r\n     * Indicates error while create offer call.\r\n     */\r\n    CREATE_OFFER_FAILED = 'rtc.create_offer_failed',\r\n    DATA_CHANNEL_OPEN = 'rtc.data_channel_open',\r\n    ENDPOINT_CONN_STATUS_CHANGED = 'rtc.endpoint_conn_status_changed',\r\n    DOMINANT_SPEAKER_CHANGED = 'rtc.dominant_speaker_changed',\r\n    FORWARDED_SOURCES_CHANGED = 'rtc.forwarded_sources_changed',\r\n\r\n    /**\r\n     * Event emitted when the user granted/blocked a permission for the camera / mic.\r\n     * Used to keep track of the granted permissions on browsers which don't\r\n     * support the Permissions API.\r\n     */\r\n    PERMISSIONS_CHANGED = 'rtc.permissions_changed',\r\n\r\n    SENDER_VIDEO_CONSTRAINTS_CHANGED = 'rtc.sender_video_constraints_changed',\r\n\r\n    /**\r\n     * Event emitted when {@link RTC.setLastN} method is called to update with\r\n     * the new value set.\r\n     * The first argument is the value passed to {@link RTC.setLastN}.\r\n     */\r\n    LASTN_VALUE_CHANGED = 'rtc.lastn_value_changed',\r\n\r\n    /**\r\n     * Event emitted when ssrc for a local track is extracted and stored\r\n     * in {@link TraceablePeerConnection}.\r\n     * @param {JitsiLocalTrack} track which ssrc was updated\r\n     * @param {string} ssrc that was stored\r\n     */\r\n    LOCAL_TRACK_SSRC_UPDATED = 'rtc.local_track_ssrc_updated',\r\n\r\n    /**\r\n     * The max enabled resolution of a local video track was changed.\r\n     */\r\n    LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED = 'rtc.local_track_max_enabled_resolution_changed',\r\n\r\n    TRACK_ATTACHED = 'rtc.track_attached',\r\n\r\n    /**\r\n     * Event fired when we remote track is added to the conference.\r\n     * 1st event argument is the added <tt>JitsiRemoteTrack</tt> instance.\r\n     **/\r\n    REMOTE_TRACK_ADDED = 'rtc.remote_track_added',\r\n\r\n    // FIXME get rid of this event in favour of NO_DATA_FROM_SOURCE event\r\n    // (currently implemented for local tracks only)\r\n    REMOTE_TRACK_MUTE = 'rtc.remote_track_mute',\r\n\r\n    /**\r\n     * Indicates that the remote track has been removed from the conference.\r\n     * 1st event argument is the removed {@link JitsiRemoteTrack} instance.\r\n     */\r\n    REMOTE_TRACK_REMOVED = 'rtc.remote_track_removed',\r\n\r\n    // FIXME get rid of this event in favour of NO_DATA_FROM_SOURCE event\r\n    // (currently implemented for local tracks only)\r\n    REMOTE_TRACK_UNMUTE = 'rtc.remote_track_unmute',\r\n\r\n    /**\r\n     * Indicates error while set local description.\r\n     */\r\n    SET_LOCAL_DESCRIPTION_FAILED = 'rtc.set_local_description_failed',\r\n\r\n    /**\r\n     * Indicates error while set remote description.\r\n     */\r\n    SET_REMOTE_DESCRIPTION_FAILED = 'rtc.set_remote_description_failed',\r\n    AUDIO_OUTPUT_DEVICE_CHANGED = 'rtc.audio_output_device_changed',\r\n    DEVICE_LIST_CHANGED = 'rtc.device_list_changed',\r\n\r\n    /**\r\n     * Indicates that the list with available devices will change.\r\n     */\r\n    DEVICE_LIST_WILL_CHANGE = 'rtc.device_list_will_change',\r\n    DEVICE_LIST_AVAILABLE = 'rtc.device_list_available',\r\n\r\n    /**\r\n     * Indicates that a message from another participant is received on\r\n     * data channel.\r\n     */\r\n    ENDPOINT_MESSAGE_RECEIVED = 'rtc.endpoint_message_received',\r\n\r\n    /**\r\n     * Indicates that the remote endpoint stats have been received on data channel.\r\n     */\r\n    ENDPOINT_STATS_RECEIVED = 'rtc.endpoint_stats_received',\r\n\r\n    /**\r\n     * Designates an event indicating that the local ICE username fragment of\r\n     * the jingle session has changed.\r\n     * The first argument of the vent is <tt>TraceablePeerConnection</tt> which\r\n     * is the source of the event.\r\n     * The second argument is the actual \"ufrag\" string.\r\n     */\r\n    LOCAL_UFRAG_CHANGED = 'rtc.local_ufrag_changed',\r\n\r\n    /**\r\n     * Designates an event indicating that the local ICE username fragment of\r\n     * the jingle session has changed.\r\n     * The first argument of the vent is <tt>TraceablePeerConnection</tt> which\r\n     * is the source of the event.\r\n     * The second argument is the actual \"ufrag\" string.\r\n     */\r\n    REMOTE_UFRAG_CHANGED = 'rtc.remote_ufrag_changed',\r\n\r\n    /**\r\n     * Designates an event indicating that some received video SSRCs will now map to\r\n     * new remote sources.\r\n     */\r\n    VIDEO_SSRCS_REMAPPED = 'rtc.video_ssrcs_remapped',\r\n\r\n    /**\r\n     * Designates an event indicating that some received audio SSRCs will now map to\r\n     * new remote sources.\r\n     */\r\n    AUDIO_SSRCS_REMAPPED = 'rtc.audio_ssrcs_remapped'\r\n};\r\n\r\nexport const CREATE_ANSWER_FAILED = RTCEvents.CREATE_ANSWER_FAILED;\r\nexport const CREATE_OFFER_FAILED = RTCEvents.CREATE_OFFER_FAILED;\r\nexport const DATA_CHANNEL_OPEN = RTCEvents.DATA_CHANNEL_OPEN;\r\nexport const ENDPOINT_CONN_STATUS_CHANGED = RTCEvents.ENDPOINT_CONN_STATUS_CHANGED;\r\nexport const DOMINANT_SPEAKER_CHANGED = RTCEvents.DOMINANT_SPEAKER_CHANGED;\r\nexport const FORWARDED_SOURCES_CHANGED = RTCEvents.FORWARDED_SOURCES_CHANGED;\r\nexport const PERMISSIONS_CHANGED = RTCEvents.PERMISSIONS_CHANGED;\r\nexport const SENDER_VIDEO_CONSTRAINTS_CHANGED = RTCEvents.SENDER_VIDEO_CONSTRAINTS_CHANGED;\r\nexport const LASTN_VALUE_CHANGED = RTCEvents.LASTN_VALUE_CHANGED;\r\nexport const LOCAL_TRACK_SSRC_UPDATED = RTCEvents.LOCAL_TRACK_SSRC_UPDATED;\r\nexport const LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED = RTCEvents.LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED;\r\nexport const TRACK_ATTACHED = RTCEvents.TRACK_ATTACHED;\r\nexport const REMOTE_TRACK_ADDED = RTCEvents.REMOTE_TRACK_ADDED;\r\nexport const REMOTE_TRACK_MUTE = RTCEvents.REMOTE_TRACK_MUTE;\r\nexport const REMOTE_TRACK_REMOVED = RTCEvents.REMOTE_TRACK_REMOVED;\r\nexport const REMOTE_TRACK_UNMUTE = RTCEvents.REMOTE_TRACK_UNMUTE;\r\nexport const SET_LOCAL_DESCRIPTION_FAILED = RTCEvents.SET_LOCAL_DESCRIPTION_FAILED;\r\nexport const SET_REMOTE_DESCRIPTION_FAILED = RTCEvents.SET_REMOTE_DESCRIPTION_FAILED;\r\nexport const AUDIO_OUTPUT_DEVICE_CHANGED = RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED;\r\nexport const DEVICE_LIST_CHANGED = RTCEvents.DEVICE_LIST_CHANGED;\r\nexport const DEVICE_LIST_WILL_CHANGE = RTCEvents.DEVICE_LIST_WILL_CHANGE;\r\nexport const DEVICE_LIST_AVAILABLE = RTCEvents.DEVICE_LIST_AVAILABLE;\r\nexport const ENDPOINT_MESSAGE_RECEIVED = RTCEvents.ENDPOINT_MESSAGE_RECEIVED;\r\nexport const ENDPOINT_STATS_RECEIVED = RTCEvents.ENDPOINT_STATS_RECEIVED;\r\nexport const LOCAL_UFRAG_CHANGED = RTCEvents.LOCAL_UFRAG_CHANGED;\r\nexport const REMOTE_UFRAG_CHANGED = RTCEvents.REMOTE_UFRAG_CHANGED;\r\nexport const VIDEO_SSRCS_REMAPPED = RTCEvents.VIDEO_SSRCS_REMAPPED;\r\nexport const AUDIO_SSRCS_REMAPPED = RTCEvents.AUDIO_SSRCS_REMAPPED;\r\n\r\n// TODO: this was a pre-ES6 module using module.exports = RTCEvents which doesn't translate well\r\n// it is used in a number of places and should be updated to use the named export\r\n\r\nexport default RTCEvents;","const Resolutions = {\r\n    '2160': {\r\n        width: 3840,\r\n        height: 2160\r\n    },\r\n    '4k': {\r\n        width: 3840,\r\n        height: 2160\r\n    },\r\n    '1080': {\r\n        width: 1920,\r\n        height: 1080\r\n    },\r\n    'fullhd': {\r\n        width: 1920,\r\n        height: 1080\r\n    },\r\n    '720': {\r\n        width: 1280,\r\n        height: 720\r\n    },\r\n    'hd': {\r\n        width: 1280,\r\n        height: 720\r\n    },\r\n    '540': {\r\n        width: 960,\r\n        height: 540\r\n    },\r\n    'qhd': {\r\n        width: 960,\r\n        height: 540\r\n    },\r\n    '480': {\r\n        width: 640,\r\n        height: 480\r\n    },\r\n    'vga': {\r\n        width: 640,\r\n        height: 480\r\n    },\r\n    '360': {\r\n        width: 640,\r\n        height: 360\r\n    },\r\n    '240': {\r\n        width: 320,\r\n        height: 240\r\n    },\r\n    '180': {\r\n        width: 320,\r\n        height: 180\r\n    }\r\n};\r\n\r\nmodule.exports = Resolutions;\r\n","/**\r\n * Enumeration of the video types\r\n */\r\nexport enum VideoType {\r\n    /**\r\n     * The camera video type.\r\n     */\r\n    CAMERA = 'camera',\r\n\r\n    /**\r\n     * The desktop video type.\r\n     */\r\n    DESKTOP = 'desktop'\r\n};\r\n","const AuthenticationEvents = {\r\n    /**\r\n     * Event callback arguments:\r\n     * function(authenticationEnabled, userIdentity)\r\n     * authenticationEnabled - indicates whether authentication has been enabled\r\n     *                         in this session\r\n     * userIdentity - if user has been logged in then it contains user name. If\r\n     *                contains 'null' or 'undefined' then user is not logged in.\r\n     */\r\n    IDENTITY_UPDATED: 'authentication.identity_updated'\r\n};\r\n\r\nmodule.exports = AuthenticationEvents;\r\n","export const LOCAL_JID = 'local'\r\n","export enum XMPPEvents {\r\n    /**\r\n     * Indicates error while adding ice candidate.\r\n     */\r\n    ADD_ICE_CANDIDATE_FAILED = 'xmpp.add_ice_candidate_failed',\r\n\r\n    // Designates an event indicating that the focus has asked us to mute our\r\n    // audio.\r\n    AUDIO_MUTED_BY_FOCUS = 'xmpp.audio_muted_by_focus',\r\n\r\n    // Designates an event indicating that the focus has asked us to disable our\r\n    // camera.\r\n    VIDEO_MUTED_BY_FOCUS = 'xmpp.video_muted_by_focus',\r\n    AUTHENTICATION_REQUIRED = 'xmpp.authentication_required',\r\n    BRIDGE_DOWN = 'xmpp.bridge_down',\r\n\r\n    /**\r\n     * Triggered when 'session-accept' is received from the responder.\r\n     */\r\n    CALL_ACCEPTED = 'xmpp.callaccepted.jingle',\r\n\r\n    // Designates an event indicating that an offer (e.g. Jingle\r\n    // session-initiate) was received.\r\n    CALL_INCOMING = 'xmpp.callincoming.jingle',\r\n\r\n    // Triggered when Jicofo kills our media session, this can happen while\r\n    // we're still in the MUC, when it decides to terminate the media session.\r\n    // For example when the session is idle for too long, because we're the only\r\n    // person in the conference room.\r\n    CALL_ENDED = 'xmpp.callended.jingle',\r\n    CHAT_ERROR_RECEIVED = 'xmpp.chat_error_received',\r\n    SETTINGS_ERROR_RECEIVED = 'xmpp.settings_error_received',\r\n\r\n    // The conference properties (as advertised by jicofo) have changed\r\n    CONFERENCE_PROPERTIES_CHANGED = 'xmpp.conference_properties_changed',\r\n\r\n    /**\r\n     * This event is triggered when the ICE connects for the first time.\r\n     */\r\n    CONNECTION_ESTABLISHED = 'xmpp.connection.connected',\r\n\r\n    // Designates an event indicating that the connection to the XMPP server\r\n    // failed.\r\n    CONNECTION_FAILED = 'xmpp.connection.failed',\r\n\r\n    // Designates an event indicating that the media (ICE) connection was\r\n    // interrupted. This should go to the RTC module.\r\n    CONNECTION_INTERRUPTED = 'xmpp.connection.interrupted',\r\n\r\n    // Designates an event indicating that the media (ICE) connection was\r\n    // restored. This should go to the RTC module.\r\n    CONNECTION_RESTORED = 'xmpp.connection.restored',\r\n\r\n    // Designates an event indicating that the media (ICE) connection failed.\r\n    // This should go to the RTC module.\r\n    CONNECTION_ICE_FAILED = 'xmpp.connection.ice.failed',\r\n\r\n    // Designates an event indicating that the call has been migrated to a different\r\n    // bridge and that the client needs to be restarted for a successful transition.\r\n    CONNECTION_RESTARTED = 'xmpp.connection.restart',\r\n\r\n    /**\r\n     * Designates an event indicating connection status changes.\r\n     */\r\n    CONNECTION_STATUS_CHANGED = 'xmpp.connection.status.changed',\r\n\r\n    // Designates an event indicating that the display name of a participant\r\n    // has changed.\r\n    DISPLAY_NAME_CHANGED = 'xmpp.display_name_changed',\r\n\r\n    /**\r\n     * Chat room instance have been added to Strophe.emuc plugin.\r\n     */\r\n    EMUC_ROOM_ADDED = 'xmpp.emuc_room_added',\r\n\r\n    /**\r\n     * Chat room instance have been removed from Strophe.emuc plugin.\r\n     */\r\n    EMUC_ROOM_REMOVED = 'xmpp.emuc_room_removed',\r\n    ETHERPAD = 'xmpp.etherpad',\r\n    FOCUS_DISCONNECTED = 'xmpp.focus_disconnected',\r\n    FOCUS_LEFT = 'xmpp.focus_left',\r\n    GRACEFUL_SHUTDOWN = 'xmpp.graceful_shutdown',\r\n\r\n    /**\r\n     * Event fired when 'transport-replace' Jingle message has been received,\r\n     * before the new offer is set on the PeerConnection.\r\n     */\r\n    ICE_RESTARTING = 'rtc.ice_restarting',\r\n\r\n    /**\r\n     * Event fired after the 'transport-replace' message has been processed\r\n     * and the new offer has been set successfully.\r\n     */\r\n    ICE_RESTART_SUCCESS = 'rtc.ice_restart_success',\r\n\r\n    /**\r\n     * Designates an event indicating that we were kicked from the XMPP MUC.\r\n     * @param {boolean} isSelfPresence - whether it is for local participant\r\n     * or another participant.\r\n     * @param {string} actorJid - the jid of the participant who was initiator\r\n     * of the kick.\r\n     * @param {?string} participantJid - when it is not a kick for local participant,\r\n     * this is the jid of the participant which was kicked.\r\n     */\r\n    KICKED = 'xmpp.kicked',\r\n\r\n    // Designates an event indicating that our role in the XMPP MUC has changed.\r\n    LOCAL_ROLE_CHANGED = 'xmpp.localrole_changed',\r\n\r\n    /**\r\n     * Event fired when the unique meeting id is set.\r\n     */\r\n    MEETING_ID_SET = 'xmpp.meeting_id_set',\r\n\r\n    // Designates an event indicating that an XMPP message in the MUC was\r\n    // received.\r\n    MESSAGE_RECEIVED = 'xmpp.message_received',\r\n\r\n    // Designates an event indicating that an invite XMPP message in the MUC was\r\n    // received.\r\n    INVITE_MESSAGE_RECEIVED = 'xmpp.invite_message_received',\r\n\r\n    // Designates an event indicating that a private XMPP message in the MUC was\r\n    // received.\r\n    PRIVATE_MESSAGE_RECEIVED = 'xmpp.private_message_received',\r\n\r\n    // Designates an event indicating that a bot participant type had changed\r\n    MUC_MEMBER_BOT_TYPE_CHANGED = 'xmpp.muc_member_bot_type_changed',\r\n\r\n    // Designates an event indicating that the XMPP MUC was destroyed.\r\n    MUC_DESTROYED = 'xmpp.muc_destroyed',\r\n\r\n    // Designates an event indicating that we are currently in process of joining the XMPP MUC.\r\n    MUC_JOIN_IN_PROGRESS = 'xmpp.muc_join_in_progress',\r\n\r\n    // Designates an event indicating that we have joined the XMPP MUC.\r\n    MUC_JOINED = 'xmpp.muc_joined',\r\n\r\n    // Designates an event indicating that a participant joined the XMPP MUC.\r\n    MUC_MEMBER_JOINED = 'xmpp.muc_member_joined',\r\n\r\n    // Designates an event indicating that a participant left the XMPP MUC.\r\n    MUC_MEMBER_LEFT = 'xmpp.muc_member_left',\r\n\r\n    // Designates an event indicating that a participant joined the lobby XMPP MUC.\r\n    MUC_LOBBY_MEMBER_JOINED = 'xmpp.muc_lobby_member_joined',\r\n\r\n    // Designates an event indicating that a participant in the lobby XMPP MUC has been updated\r\n    MUC_LOBBY_MEMBER_UPDATED = 'xmpp.muc_lobby_member_updated',\r\n\r\n    // Designates an event indicating that a participant left the XMPP MUC.\r\n    MUC_LOBBY_MEMBER_LEFT = 'xmpp.muc_lobby_member_left',\r\n\r\n    // Designates an event indicating that a participant was denied access to a conference from the lobby XMPP MUC.\r\n    MUC_DENIED_ACCESS = 'xmpp.muc_denied access',\r\n\r\n    // Designates an event indicating that local participant left the muc\r\n    MUC_LEFT = 'xmpp.muc_left',\r\n\r\n    // Designates an event indicating that the MUC role of a participant has\r\n    // changed.\r\n    MUC_ROLE_CHANGED = 'xmpp.muc_role_changed',\r\n\r\n    // Designates an event indicating that the MUC has been locked or unlocked.\r\n    MUC_LOCK_CHANGED = 'xmpp.muc_lock_changed',\r\n\r\n    // Designates an event indicating that the MUC members only config has changed.\r\n    MUC_MEMBERS_ONLY_CHANGED = 'xmpp.muc_members_only_changed',\r\n\r\n    // Designates an event indicating that a participant in the XMPP MUC has\r\n    // advertised that they have audio muted (or unmuted).\r\n    PARTICIPANT_AUDIO_MUTED = 'xmpp.audio_muted',\r\n\r\n    // Designates an event indicating that a participant in the XMPP MUC has\r\n    // advertised that they have video muted (or unmuted).\r\n    PARTICIPANT_VIDEO_MUTED = 'xmpp.video_muted',\r\n\r\n    // Designates an event indicating that the video type (e.g. 'camera' or\r\n    // 'screen') for a participant has changed.\r\n    // Note = currently this event fires every time we receive presence from\r\n    // someone (regardless of whether or not the \"video type\" changed).\r\n    PARTICIPANT_VIDEO_TYPE_CHANGED = 'xmpp.video_type',\r\n\r\n    /**\r\n     * Indicates that the features of the participant has been changed.\r\n     */\r\n    PARTICIPANT_FEATURES_CHANGED = 'xmpp.participant_features_changed',\r\n    PASSWORD_REQUIRED = 'xmpp.password_required',\r\n\r\n    /**\r\n     * Indicates that phone number changed.\r\n     */\r\n    PHONE_NUMBER_CHANGED = 'conference.phoneNumberChanged',\r\n    PRESENCE_RECEIVED = 'xmpp.presence_received',\r\n    PRESENCE_STATUS = 'xmpp.presence_status',\r\n    PROMPT_FOR_LOGIN = 'xmpp.prompt_for_login',\r\n\r\n    // xmpp is connected and obtained user media\r\n    READY_TO_JOIN = 'xmpp.ready_to_join',\r\n\r\n    /**\r\n     * Indicates that recording state changed.\r\n     */\r\n    RECORDER_STATE_CHANGED = 'xmpp.recorderStateChanged',\r\n\r\n    // Designates an event indicating that we received statistics from a\r\n    // participant in the MUC.\r\n    REMOTE_STATS = 'xmpp.remote_stats',\r\n\r\n    /**\r\n     * Indicates that the offer / answer renegotiation has failed.\r\n     */\r\n    RENEGOTIATION_FAILED = 'xmpp.renegotiation_failed',\r\n    RESERVATION_ERROR = 'xmpp.room_reservation_error',\r\n    ROOM_CONNECT_ERROR = 'xmpp.room_connect_error',\r\n    ROOM_CONNECT_NOT_ALLOWED_ERROR = 'xmpp.room_connect_error.not_allowed',\r\n    ROOM_JOIN_ERROR = 'xmpp.room_join_error',\r\n    ROOM_CONNECT_MEMBERS_ONLY_ERROR = 'xmpp.room_connect_error.members_only',\r\n\r\n    /**\r\n     * Indicates that max users limit has been reached.\r\n     */\r\n    ROOM_MAX_USERS_ERROR = 'xmpp.room_max_users_error',\r\n\r\n    // Designates an event indicating that we sent an XMPP message to the MUC.\r\n    SENDING_CHAT_MESSAGE = 'xmpp.sending_chat_message',\r\n\r\n    // Designates an event indicating that we sent a private XMPP message to\r\n    // a specific user of the muc.\r\n    SENDING_PRIVATE_CHAT_MESSAGE = 'xmpp.sending_private_chat_message',\r\n\r\n    /**\r\n     * Event fired after receiving the confirmation about session accept.\r\n     */\r\n    SESSION_ACCEPT = 'xmpp.session_accept',\r\n\r\n    /**\r\n     * Event fired if we receive an error after sending the session accept.\r\n     */\r\n    SESSION_ACCEPT_ERROR = 'xmpp.session_accept_error',\r\n\r\n    /**\r\n     * Event fired when we do not get our 'session-accept' acknowledged by\r\n     * Jicofo. It most likely means that there is serious problem with our\r\n     * connection or XMPP server and we should reload the conference.\r\n     *\r\n     * We have seen that to happen in BOSH requests race condition when the BOSH\r\n     * request table containing the 'session-accept' was discarded by Prosody.\r\n     * Jicofo does send the RESULT immediately without any condition, so missing\r\n     * packets means that most likely it has never seen our IQ.\r\n     */\r\n    SESSION_ACCEPT_TIMEOUT = 'xmpp.session_accept_timeout',\r\n\r\n    /**\r\n     * Event fired after successful sending of jingle source-add.\r\n     */\r\n    SOURCE_ADD = 'xmpp.source_add',\r\n\r\n    /**\r\n     * Event fired after receiving an error sending of jingle source-add.\r\n     */\r\n    SOURCE_ADD_ERROR = 'xmpp.source_add_error',\r\n\r\n    /**\r\n     * Event fired after successful sending of jingle source-remove.\r\n     */\r\n    SOURCE_REMOVE = 'xmpp.source_remove',\r\n\r\n    /**\r\n     * Event fired after receiving an error sending of jingle source-remove.\r\n     */\r\n    SOURCE_REMOVE_ERROR = 'xmpp.source_remove_error',\r\n\r\n    /**\r\n     * Event fired when speaker stats update message is received.\r\n     */\r\n    SPEAKER_STATS_RECEIVED = 'xmpp.speaker_stats_received',\r\n\r\n    /**\r\n     * Event fired when conference creation timestamp is received.\r\n     */\r\n    CONFERENCE_TIMESTAMP_RECEIVED = 'xmpp.conference_timestamp_received',\r\n\r\n    /**\r\n     * Event fired when we receive a message for AV moderation approved for the local participant.\r\n     */\r\n    AV_MODERATION_APPROVED = 'xmpp.av_moderation.approved',\r\n\r\n    /**\r\n    * Event fired when we receive a message for AV moderation rejected for the local participant.\r\n    */\r\n    AV_MODERATION_REJECTED = 'xmpp.av_moderation.rejected',\r\n\r\n    /**\r\n     * Event fired when we receive a message for AV moderation.\r\n     */\r\n    AV_MODERATION_RECEIVED = 'xmpp.av_moderation.received',\r\n\r\n    /**\r\n     * Event fired when the moderation enable/disable changes.\r\n     */\r\n    AV_MODERATION_CHANGED = 'xmpp.av_moderation.changed',\r\n\r\n    /**\r\n     * Event fired when we receive message that a new jid was approved.\r\n     */\r\n    AV_MODERATION_PARTICIPANT_APPROVED = 'xmpp.av_moderation.participant.approved',\r\n\r\n    /**\r\n     * Event fired when we receive message that a new jid was approved.\r\n     */\r\n    AV_MODERATION_PARTICIPANT_REJECTED = 'xmpp.av_moderation.participant.rejected',\r\n\r\n    /**\r\n     * Event fired when a participant is requested to join a given (breakout) room.\r\n     */\r\n    BREAKOUT_ROOMS_MOVE_TO_ROOM = 'xmpp.breakout-rooms.move-to-room',\r\n\r\n    /**\r\n     * Event fired when we receive a message for breakout rooms.\r\n     */\r\n    BREAKOUT_ROOMS_EVENT = 'xmpp.breakout-rooms.event',\r\n\r\n    /**\r\n     * Event fired when the breakout rooms data was updated.\r\n     */\r\n    BREAKOUT_ROOMS_UPDATED = 'xmpp.breakout-rooms.updated',\r\n\r\n    /**\r\n     * Event fired when we receive a message related to room metadata.\r\n     */\r\n    ROOM_METADATA_EVENT = 'xmpp.room-metadata.event',\r\n\r\n    /**\r\n     * Event fired when we receive a message related to room metadata.\r\n     */\r\n    ROOM_METADATA_UPDATED = 'xmpp.room-metadata.updated',\r\n\r\n    // Designates an event indicating that we should join the conference with\r\n    // audio and/or video muted.\r\n    START_MUTED_FROM_FOCUS = 'xmpp.start_muted_from_focus',\r\n\r\n    // Designates an event indicating that the subject of the XMPP MUC has\r\n    // changed.\r\n    SUBJECT_CHANGED = 'xmpp.subject_changed',\r\n\r\n    // FIXME: how does it belong to XMPP ? - it's detected by the PeerConnection\r\n    // suspending detected\r\n    SUSPEND_DETECTED = 'xmpp.suspend_detected',\r\n\r\n    /**\r\n     * Notifies for transcription status changes. The event provides the\r\n     * following parameters to its listeners:\r\n     *\r\n     * @param {String} status - The new status.\r\n     */\r\n    TRANSCRIPTION_STATUS_CHANGED = 'xmpp.transcription_status_changed',\r\n\r\n    /**\r\n     * Event fired when 'transport-info' with new ICE candidates is received.\r\n     */\r\n    TRANSPORT_INFO = 'xmpp.transportinfo.jingle',\r\n\r\n    /**\r\n     * Indicates that video SIP GW state changed.\r\n     *\r\n     * @param {VideoSIPGWStatusConstants} status - Any of the following statuses:\r\n     * STATUS_BUSY, STATUS_AVAILABLE or STATUS_UNDEFINED.\r\n     */\r\n    VIDEO_SIP_GW_AVAILABILITY_CHANGED = 'xmpp.videoSIPGWAvailabilityChanged',\r\n\r\n    /**\r\n     * Indicates that video SIP GW Session state changed.\r\n     * The statuses are any of the following statuses:\r\n     * STATE_ON, STATE_OFF, STATE_PENDING, STATE_RETRYING, STATE_FAILED.\r\n     * {@see VideoSIPGWStateConstants}\r\n     *\r\n     * @param {options} event - {address, oldState, newState, displayName}.\r\n     */\r\n    VIDEO_SIP_GW_SESSION_STATE_CHANGED = 'xmpp.videoSIPGWSessionStateChanged',\r\n\r\n    // Designates an event indicating that the local ICE connection state has\r\n    // changed.\r\n    ICE_CONNECTION_STATE_CHANGED = 'xmpp.ice_connection_state_changed',\r\n\r\n    /**\r\n     * Event which is emitted when the body in an XMPP message in the MUC\r\n     * contains JSON\r\n     * TODO: this event contains a typo (xmmp vs xmpp) but it's unlikely this can be changed now\r\n     */\r\n    JSON_MESSAGE_RECEIVED = 'xmmp.json_message_received'\r\n};\r\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","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","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","DOMINANT_SPEAKER_CHANGED","CONFERENCE_CREATED_TIMESTAMP","DTMF_SUPPORT_CHANGED","ENDPOINT_MESSAGE_RECEIVED","ENDPOINT_STATS_RECEIVED","JVB121_STATUS","KICKED","PARTICIPANT_KICKED","LAST_N_ENDPOINTS_CHANGED","FORWARDED_SOURCES_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","FACE_LANDMARK_ADDED","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","TIMEOUT","TRACK_IS_DISPOSED","TRACK_NO_STREAM_FOUND","UNSUPPORTED_RESOLUTION","TRACK_ERROR_TO_MESSAGE_MAP","JitsiTrackError","error","options","devices","name","this","gum","constraints","Array","isArray","slice","undefined","message","join","constraintName","constraint","video","indexOf","failedConstraintName","mandatory","minWidth","minHeight","getResolutionFromFailedConstraint","Error","stack","prototype","Object","create","constructor","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","createConferenceEvent","action","attributes","source","type","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","match","version","window","JitsiMeetElectron","_detectNWJS","_detectReactNative","product","length","DummyLocalStorage","EventEmitter","clear","_storage","keys","getItem","keyName","setItem","keyValue","removeItem","key","n","serialize","JSON","stringify","jitsiLocalStorage","super","localStorage","_localStorageDisabled","ignore","console","warn","isLocalStorageDisabled","emit","dontEmitChangedEvent","i","localStorageContent","logger","getLogger","browserInfo","_bowser","Bowser","detectedBrowserInfo","bowser","detectors","getBrowserName","getBrowserVersion","Number","parseInt","_detectChromiumBased","_detect","_name","_version","getName","isChrome","isOpera","isFirefox","isIExplorer","isSafari","isNWJS","isElectron","isReactNative","getVersion","_checkCondition","checkTree","satisfies","isVersionGreaterThan","isVersionLessThan","isVersionEqualTo","info","doesVideoMuteByStreamRemove","isChromiumBased","isWebKitBased","isIosBrowser","maxTouchPoints","platform","Boolean","test","isEngine","mediaDevices","getUserMedia","RTCRtpTransceiver","isTwa","matchMedia","matches","isSupported","_getSafariVersion","_getChromiumBasedVersion","isSupportedAndroidBrowser","isSupportedIOSBrowser","_getIOSVersion","isUserInteractionRequiredForUnmute","supportsVideoMuteOnConnInterrupted","supportsBandwidthStatistics","supportsCodecPreferences","RTCRtpReceiver","getCapabilities","supportsDeviceChangeEvent","ondevicechange","addEventListener","supportsPerformanceObserver","PerformanceObserver","supportedEntryTypes","supportsReceiverStats","supportsRTTStatistics","supportsVP9","usesSdpMungingForSimulcast","usesRidsForSimulcast","supportsGetDisplayMedia","getDisplayMedia","supportsEncodedTransform","RTCRtpScriptTransform","supportsInsertableStreams","RTCRtpSender","createEncodedStreams","stream","ReadableStream","postMessage","supportsAudioRed","codecs","some","codec","mimeType","supportsUnifiedPlan","supportsVADDetection","supportsRTX","process","versions","chromium","ua","reset","disposed","analyticsHandlers","Set","cache","permanentProperties","conferenceName","addPermanentProperties","browser","dispose","size","forEach","handler","setAnalyticsHandlers","handlers","_setUserProperties","event","_sendEvent","setUserProperties","properties","setConferenceName","sendEvent","eventName","_verifyRequiredFields","objectType","containerType","containerId","objectId","_maybeCacheEvent","push","splice","e","require","wrtcFuncNames","reportType","_fabrics","CallStats","msg","backend","log","backendInitialized","atLeastOneFabric","defaultInstance","callStatsInstance","fabrics","values","hasFabric","debug","_addNewFabric","_emptyReportQueue","csInstance","defaultConfID","confID","defaultPC","peerconnection","report","reportsQueue","errorData","data","_reportError","pc","eventData","sendFabricEvent","associateMstWithUserID","callStatsId","ssrc","usageLabel","cs","_error","reportError","theBackend","tryCatchMethods","methodName","originalMethod","theArguments","apply","GlobalOnErrorHandler","debugMethods","originalReportError","args","call","exception","CallStatsBackend","callstats","_traceAndCatchBackendCalls","userID","aliasName","userName","callStatsID","callStatsSecret","configParams","applicationName","applicationVersion","siteID","initialize","_initCallback","getWiFiStatsMethod","attachWifiStatsHandler","then","result","parse","addresses","catch","devicesData","_reportEvent","conferenceID","overall","comment","Promise","resolve","reject","sendUserFeedback","status","reason","mute","tpc","remoteUserID","add","fabricAttributes","remoteEndpointType","isP2P","endpointType","peer","server","ret","addNewFabric","fabricUsage","multiplex","_addNewFabricCallback","success","associateStreamWithVideoTag","isLocal","streamEndpointId","sendDominantSpeakerEvent","sendTerminateEvent","fabricEvent","fabricTerminated","delete","sendIceConnectionFailedEvent","sendCreateOfferFailed","sendCreateAnswerFailed","sendResumeOrHoldEvent","isResume","sendScreenSharingEvent","start","sendSetLocalDescFailed","sendSetRemoteDescFailed","sendAddIceCandidateFailed","AudioContext","webkitAudioContext","context","LocalStatsCollector","interval","callback","intervalId","intervalMilis","audioLevel","analyser","safeCounterIncrement","number","nextValue","MAX_SAFE_INTEGER","calculateAverage","valueArray","reduce","a","b","filterPositiveValues","filter","value","isLocalStatsSupported","resume","createAnalyser","smoothingTimeConstant","fftSize","createMediaStreamSource","connect","setInterval","array","Uint8Array","frequencyBinCount","getByteTimeDomainData","samples","maxVolume","parseFloat","toFixed","timeDomainDataToAudioLevel","newLevel","lastLevel","diff","animateLevel","stop","clearInterval","disconnect","disconnectAudioContext","async","close","connectAudioContext","suspend","RunningAverage","average","addNext","getAverage","PerformanceObserverStats","emitter","statsInterval","eventEmitter","longTasks","maxDuration","performanceStatsInterval","stats","getLongTasksStats","avgRatePerMinute","maxDurationMs","startObserver","longTaskEventHandler","list","entries","getEntries","task","Math","max","duration","observer","observe","buffered","startTime","Date","now","longTasksIntervalId","_lastTimeStamp","rate","StatisticsEvents","stopObserver","MediaType","calculatePacketLoss","lostPackets","totalPackets","round","SsrcStats","loss","bitrate","download","upload","resolution","framerate","ConferenceStats","bandwidth","packetLoss","transport","StatsCollector","audioLevelsInterval","baselineAudioLevelsReport","currentAudioLevelsReport","currentStatsReport","previousStatsReport","audioLevelReportHistory","audioLevelsIntervalId","conferenceStats","audioLevelsIntervalMilis","speakerList","statsIntervalId","statsIntervalMilis","ssrc2stats","Map","setLoss","setResolution","addBitrate","resetBitrate","setFramerate","setCodec","setSpeakerList","errorCallback","callErrorHandler","startAudioLevelStats","audioLevels","getAudioLevels","hasOwnProperty","getStats","processAudioLevelReport","processStats","processStatsReport","_processAndEmitReport","bitrateDownload","bitrateUpload","resolutions","framerates","audioBitrateDownload","audioBitrateUpload","videoBitrateDownload","videoBitrateUpload","ssrcStats","isDownloadStream","packetsTotal","packetsLost","track","getTrackBySSRC","audioCodec","videoCodec","isAudioTrack","participantId","getParticipantId","width","height","userResolutions","userFramerates","userCodecs","audio","total","avgAudioLevels","localAvgAudioLevels","avgAudioLevel","sum","currentValue","getNonNegativeValue","v","isNaN","_calculateBitrate","before","fieldName","bytesNow","bytesBefore","bytesProcessed","timeMs","timestamp","bitrateKbps","byteSentStats","get","id","nominated","state","availableIncomingBitrate","availableOutgoingBitrate","remoteUsedCandidate","remoteCandidateId","localUsedCandidate","localCandidateId","ip","address","port","localip","protocol","conferenceStatsTransport","t","p2p","localCandidateType","candidateType","remoteCandidateType","networkType","rtt","currentRoundTripTime","set","packetsNow","packetsBefore","packetsDiff","packetsLostNow","packetsLostBefore","packetsLostDiff","frameHeight","frameWidth","frameRate","framesPerSecond","bytesSent","codecId","codecShortType","split","kind","VIDEO","remoteSource","localVideoTracks","getLocalTracks","getSsrcByTrackId","trackIdentifier","framesSent","numberOfActiveStreams","getActiveSimulcastStreams","getLocalSSRC","AUDIO","_instances","isCallstatsLoaded","_initCallStatsBackend","isBackendInitialized","initBackend","Statistics","xmpp","rtpStatsMap","callStatsIntegrationEnabled","enableCallStats","disableThirdPartyRequests","callStatsApplicationLogsDisabled","ScriptUtil","customScriptUrl","loadCallStatsAPI","callsStatsInstances","instances","init","audioLevelsEnabled","disableAudioLevels","pcStatsInterval","longTasksStatsInterval","analytics","defineProperty","startRemoteStats","stopRemoteStats","rtpStats","RTPStats","localStats","startLocalStats","localStat","LocalStats","stopLocalStats","getOriginalStream","addAudioLevelListener","listener","on","removeAudioLevelListener","removeListener","addBeforeDisposedListener","removeBeforeDisposedListener","addConnectionStatsListener","removeConnectionStatsListener","addByteSentStatsListener","removeByteSentStatsListener","addLongTasksStatsListener","attachLongTasksStats","conference","performanceObserverStats","removeLongTasksStatsListener","from","callStats","stopCallStats","tpcId","_stopRemoteStats","removeAllListeners","startCallStats","has","endsWith","roomName","lastIndexOf","newInstance","_getAllCallStatsInstances","csInstances","statistics","isCallstatsEnabled","sendConnectionResumeOrHoldEvent","instance","sendMuteEvent","muted","roomJid","silence","sendActiveDeviceListEvent","globalSet","userId","sendGetUserMediaFailed","err","formatJitsiTrackErrorForCallStats","sendLog","m","globalSubSet","next","csPerStats","sendApplicationLog","sendFeedback","rating","LOCAL_JID","reportGlobalError","sendAnalyticsAndLog","eventToLog","sendAnalytics","JitsiConferenceEventManager","xmppListeners","session","p2pJingleSession","jvbJingleSession","isMuted","getType","setupChatRoomListeners","chatRoom","room","chatRoomForwarder","EventEmitterForwarder","addListener","XMPPEvents","jingleSession","rtc","closeBridgeChannel","features","participant","getParticipantById","Strophe","setFeatures","offerIq","_setBridgeChannel","actor","mutedByFocusActor","setAudioMute","isMutedByFocus","mutedVideoByFocusActor","setVideoMute","isVideoMutedByFocus","forward","_onMucJoined","isJvbConnectionInterrupted","connectionTimes","leave","_onConferenceRestarted","_onIceConnectionFailed","jid","resource","getStatus","setTerminator","setInitiator","setParticipantPropertyListener","node","setProperty","tagName","substring","onMemberKicked","bind","onSuspendDetected","onMemberJoined","_onMemberBotTypeChanged","onMemberLeft","onDisplayNameChanged","role","onLocalRoleChanged","isModerator","recorderSession","logObject","getError","onUserRoleChanged","AuthenticationEvents","authEnabled","authIdentity","txt","myJid","ts","_status","payload","addPresenceListener","myUserId","startAudioMuted","startVideoMuted","updated","startMutedPolicy","setupRTCListeners","RTCEvents","onRemoteTrackAdded","onRemoteTrackRemoved","dominant","previous","lastDominantSpeaker","dominantSpeakerIsSilent","roomjid","performance","getActiveMediaSession","videoSsrcsRemapped","audioSsrcsRemapped","ufrag","isVideoTrack","videoType","VideoType","removeXMPPListeners","setupXMPPListeners","_addConferenceXMPPListener","onIncomingCall","onCallAccepted","onTransportInfo","onCallEnded","audioMuted","videoMuted","config","ignoreStartMuted","createdTimestamp","actorJid","actorParticipant","getParticipants","find","p","getJid","enabled","setupStatisticsListeners","level","setAudioLevel","startSilent","onByteSentStatsReceived","JitsiParticipant","displayName","hidden","statsID","identity","isReplacing","isReplaced","_jid","_id","_conference","_displayName","_supportsDTMF","_tracks","_role","_hidden","_statsID","_properties","_identity","_isReplacing","_isReplaced","_features","getConference","getProperty","hasAnyVideoTrackWebRTCMuted","getTracks","jitsiTrack","isWebRTCTrackMuted","oldValue","getTracksByMediaType","getId","getDisplayName","getStatsID","isHidden","isHiddenFromRecorder","user","isAudioMuted","_isMediaTypeMuted","isVideoMuted","getRole","setRole","newRole","setIsReplacing","newIsReplacing","setIsReplaced","newIsReplaced","supportsDTMF","getFeatures","hasFeature","feature","newFeatures","getBotType","_botType","setBotType","newBotType","getConnectionJid","_connectionJid","setConnectionJid","newJid","JitsiConnectionEvents","CONNECTION_FAILED","WRONG_STATE","DISPLAY_NAME_REQUIRED","JitsiConnectionErrors","CONNECTION_DROPPED_ERROR","OTHER_ERROR","SERVER_ERROR","Deferred","promise","clearRejectTimeout","clearTimeout","_timeout","setRejectTimeout","ms","setTimeout","Listenable","removeEventListener","off","kJitsiE2EE","Symbol","E2EEcontext","sharedKey","baseUrl","ljm","document","querySelector","idx","src","workerUrl","workerBlob","Blob","URL","createObjectURL","_worker","Worker","onerror","operation","cleanup","cleanupAll","handleReceiver","receiver","transform","receiverStreams","readableStream","readable","writableStream","writable","handleSender","sender","senderStreams","setKey","keyIndex","KeyHandler","e2eeCtx","E2EEContext","_enabling","_onMediaSessionStarted","_onLocalTrackAdded","_setupReceiverE2EEForTrack","_trackMuteChanged","isEnabled","_setEnabled","setLocalParticipantProperty","_restartMediaSessions","setEncryptionKey","getMediaSessions","_setupSenderE2EEForTrack","localTracks","findReceiverForTrack","findSenderForTrack","ExternallyManagedKeyHandler","keyInfo","encryptionKey","index","v4","REQ_TIMEOUT","OLM_MESSAGE_TYPE","OLM_MESSAGE_TYPES","kOlmData","OlmAdapterEvents","OLM_ID_KEY_READY","PARTICIPANT_E2EE_CHANNEL_READY","PARTICIPANT_KEY_UPDATED","OlmAdapter","_conf","_init","_key","_keyIndex","_reqs","_sessionInitialization","_bootstrapOlm","_onEndpointMessageReceived","_onConferenceLeft","_onParticipantLeft","_onParticipantPropertyChanged","promises","localParticipantId","FEATURE_E2EE","_sendSessionInit","allSettled","Olm","pId","olmData","_getParticipantOlmData","uuid","uuidv4","JITSI_MEET_MUC_TYPE","olm","ciphertext","_encryptKeyInfo","d","_sendMessage","updateCurrentKey","clearParticipantSession","free","clearAllParticipantsSessions","_olmAccount","Account","idKeys","identity_keys","_idKey","curve25519","get_library_version","_onIdKeyReady","idKey","_onParticipantE2EEChannelReady","base64js","encrypt","_sendError","Session","create_outbound","otKey","ack","pendingSessionUuid","create_inbound","body","remove_one_time_keys","decrypt","json","safeJsonParse","lastKey","isEqual","newValue","isE2EEEnabled","sendMessage","generate_one_time_keys","otKeys","one_time_keys","mark_keys_as_published","events","ManagedKeyHandler","_conferenceJoined","_olmAdapter","_rotateKey","debounce","_rotateKeyImpl","_ratchetKey","_ratchetKeyImpl","_onParticipantKeyUpdated","_onParticipantJoined","initSessions","_generateKey","updateKey","material","keyBytes","crypto","subtle","importKey","newKey","textEncoder","TextEncoder","deriveBits","salt","encode","hash","ArrayBuffer","ratchet","getRandomValues","E2EEncryption","e2ee","_externallyManaged","externallyManagedKey","_keyHandler","testing","disableE2EE","enableEncodedTransformSupport","setEnabled","IDENTITY_PROPERTIES","IDENTITY_PROPERTIES_FOR_COMPARE","compareIdentities","res","parseDiscoInfo","identities","$","each","_","el","getAttribute","category","Caps","connection","disco","rooms","externalFeatures","emuc","_addChatRoom","_removeChatRoom","addFeature","submit","external","_generateVersion","_updateRoomWithExternalFeatures","removeFeature","sendPresence","removeFromPresence","children","f","addOrReplaceInPresence","getFeaturesAndIdentities","timeout","_getDiscoInfo","response","_fixChatRoomPresenceMap","xmlns","ver","_notifyVersionChanged","sortedIdentities","sort","accumulatedValue","tmp","sortedFeatures","b64_sha1","generateSha","_identities","NETWORK_INFO_EVENT","_current","isOnline","updateNetworkInfo","ResumeTask","stropheConnection","_stropheConn","_resumeRetryN","_retryDelay","retryDelay","schedule","_cancelResume","_networkOnlineListener","NetworkInfo","_scheduleResume","_resumeTimeout","min","retry","minDelay","base","floor","random","pow","getJitterDelay","_resumeConnection","streamManagement","resumeToken","getResumeToken","url","service","search","pattern","oldToken","replace","toString","cancel","LastRequestTracker","_lastSuccess","_lastFailedMessage","startTracking","xmppConnection","originalRawInput","rawInput","rawMessage","includes","connected","getLastFailedMessage","getTimeSinceLastSuccess","getConnectionPluginDefinition","ConnectionPluginListenable","PingConnectionPlugin","ConnectionPlugin","getTimeSinceLastServerResponse","onPingThresholdExceeded","pingOptions","failedPings","_onPingThresholdExceeded","_getTimeSinceLastServerResponse","pingInterval","pingTimeout","pingThreshold","threshold","pingTimestampsToKeep","pingExecIntervals","ping","_addPingExecutionTimestamp","iq","$iq","to","c","sendIQ2","startInterval","remoteJid","_lastServerCheck","errmsg","stopInterval","getTime","shift","getPingSuspendTime","pingIntervals","maxInterval","previousTS","currentInterval","XmppConnection","CONN_STATUS_CHANGED","CONN_SHARD_CHANGED","Status","enableWebsocketResume","websocketKeepAlive","websocketKeepAliveUrl","serviceUrl","shard","xmppPing","_options","_usesWebsocket","startsWith","maxRetries","_rawInputTracker","LastSuccessTracker","_resumeTask","_deferredIQs","addConnectionPlugin","_onPingErrorThresholdExceeded","_oneSuccessfulConnect","websocket","_proto","socket","isUsingWebSocket","readyState","WebSocket","OPEN","disconnecting","domain","lastResponseHeaders","pingDomain","_maybeStartWSKeepAlive","plugin","addHandler","attach","sid","rid","_stropheConnectionCb","pass","targetCallback","blockCallback","_maybeEnableStreamResume","_keepAliveAndCheckShard","_processDeferredIQs","_tryResumingConnection","_wsKeepAlive","_clearDeferredIQs","deferred","closeWebsocket","_closeSocket","_onClose","flush","enable","intervalWithJitter","fetch","responseShard","headers","timeLeft","sendIQ","send","stanza","elem","errback","sendUnavailableBeacon","sendBeacon","_changeConnectStatus","_buildBody","attrs","pres","$pres","cnode","tree","_abortAllRequests","_doDisconnect","JitsiTranscriptionStatus","ON","OFF","AVModeration","_xmpp","_mainRoom","_moderationEnabledByType","_whitelistAudio","_whitelistVideo","_onMessage","avModerationComponentAddress","$msg","up","approve","jidToWhitelist","jidToBlacklist","obj","removed","media","approved","whitelists","newWhitelists","oldList","newList","x","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","k","EMAIL_COMMAND","Lobby","mainRoom","maybeJoinLobbyRoom","_maybeJoinLobbyRoom","lobbyRoomJid","lobbySupported","setMembersOnly","disable","lobbyRoom","membersOnlyEnabled","sendPrivateMessage","getLocalId","addMessageListener","removeMessageHandler","setLobbyRoomJid","joined","email","customDomain","createRoom","disableDiscoInfo","disableFocus","enableLobby","nick","isHiddenDomain","botType","members","getBreakoutRooms","avatar","j","clean","isSelfPresence","invitePassword","denyAccess","kick","approveAccess","mainRoomJid","memberRoomJid","msgToSend","RoomMetadata","_metadata","setMetadata","getMetadata","roomMetadataComponentAddress","metadata","_callStatsUserName","_machineId","externalStorage","callStatsUserName","username","UsernameGenerator","generateCallStatsUserName","machineId","amDid","jitsiMeetId","_p8","generateJitsiMeetId","sessionId","substr","createExpBackoffTimer","step","count","Moderator","origin","location","Settings","xmppService","getNextTimeout","getNextErrorTimeout","externalAuthEnabled","sipGatewayEnabled","attachEvent","isExternalAuthEnabled","isSipGatewayEnabled","onMucMemberLeft","setFocusUserJid","focusJid","focusUserJid","getFocusUserJid","getFocusComponent","focusComponent","hosts","focus","createConferenceIq","machineUID","disableRtx","audioPacketDelay","startBitrate","minBitrate","rtcstatsEnabled","callstatsDisabled","parseSessionId","resultIq","attr","parseConfigOptions","authenticationEnabled","IDENTITY_UPDATED","allocateConferenceFocus","_allocateConferenceFocusSuccess","_allocateConferenceFocusError","invalidSession","reservationErr","errorCode","errorTextNode","errorMsg","text","anonymousdomain","waitMs","retrySec","authenticate","errorIq","prop","getLoginUrl","urlCallback","failureCallback","_getLoginUrl","popup","urlCb","failureCb","str","decodeURIComponent","getPopupLoginUrl","logout","logoutUrl","parser","packet2JSON","xmlElement","nodes","child","json2packet","packet","filterNodeFromPresenceJSON","nodeName","MEMBERS_AFFILIATIONS","ChatRoom","password","XMPP","replaceParticipant","presMap","presHandlers","_removeConnListeners","inProgressEmitted","focusMucJid","noBridgeAvailable","moderator","lobby","avModeration","breakoutRooms","roomMetadata","initPresenceMap","lastPresences","phoneNumber","phonePin","participantPropertyListener","locked","transcriptionStatus","xns","statsId","presenceUpdateTime","onConnStatusChanged","fromJoin","billingId","presenceSyncTime","doLeave","discoRoomInfo","getInfo","meetingIdValEl","setMeetingId","membersOnly","lobbyRoomField","isBreakoutField","breakoutMainRoomField","roomMetadataEl","roomMetadataText","meetingId","createNonAnonymousRoom","getForm","form","formSubmit","CONNECTED","onPresence","member","statusEl","getElementsByTagName","textContent","hasStatusUpdate","hasVersionUpdate","xElement","getElementsByTagNameNS","mucUserItem","isReplaceParticipant","affiliation","isFocus","fromHiddenDomain","presence","xEl","remove","extractIdentityInformation","userInfo","tags","hiddenFromRecorderFeatureEnabled","tag","groupInfo","group","_extractFeatures","_initFocus","memberOfThis","displayJids","restartByTerminateSupported","supportsRestartByTerminate","att","phone","pin","processNode","var","focusFeatures","tagHandlers","elementName","setSubject","onParticipantLeft","skipEvents","onPresenceUnavailable","destroySelect","reasonSelect","isKick","membersKeys","actorSelect","actorNick","onMessage","settingsErrorMsg","subjectText","stamp","dateParts","invite","passwordSelect","jsonMessage","parsedJson","tryParseJSONAndVerify","onPresenceError","lobbyRoomNode","lobbyRoomOldNode","setAffiliation","grantIQ","kickIQ","lockRoom","onSuccess","onError","onNotSupported","formsubmit","formToSubmit","addToPresence","matchingNodes","getFromPresence","removePresenceListener","handlerIdx","mucJid","getMediaPresenceInfo","endpointId","mutedNode","codecTypeNode","videoTypeNode","codecType","getMemberRole","peerJid","getLastPresence","mucNick","isSIPCallingSupported","dial","rayo","hangup","getLobby","getAVModeration","getMetadataHandler","getPhoneNumber","getPhonePin","getMeetingId","muteParticipant","iqToFocus","onMute","onMuteVideo","onMucLeft","doReject","end","endConferenceComponentAddress","MucConnectionPlugin","isRoomCreated","_createSourceExtension","owner","sourceCompactJson","$build","s","_createSsrcGroupExtension","ssrcGroupCompactJson","semantics","_getOrCreateRtpDescription","jingle","description","content","appendChild","expandSourcesFromJson","jsonMessageXml","sources","audioRtpDescription","videoRtpDescription","ssrcMap","ssrcs","ownerSources","videoSources","videoSsrcGroups","audioSources","audioSsrcGroups","MediaDirection","ScreenObtainer","obtainStream","_createObtainStreamMethod","onFailure","JitsiMeetNW","obtainDesktopStream","jitsiError","obtainScreenOnElectron","obtainScreenFromGetDisplayMediaRN","obtainScreenFromGetDisplayMedia","_getAudioConstraints","audioQuality","stereo","autoGainControl","channelCount","echoCancellation","noiseSuppression","JitsiMeetScreenObtainer","openDesktopPicker","desktopSharingFrameRate","desktopSharingSources","streamId","streamType","screenShareAudio","audioConstraints","optionalConstraints","optional","chromeMediaSource","chromeMediaSourceId","minFrameRate","maxFrameRate","maxWidth","screen","maxHeight","sourceId","sourceType","setScreenSharingResolutionConstraints","surfaceSwitching","cursor","errorDetails","errorName","errorStack","setDesktopSharingFrameRate","maxFps","flags","_runInLiteMode","runInLiteMode","_ssrcRewriting","ssrcRewritingEnabled","isMultiStreamSendSupportEnabled","isRunInLiteModeEnabled","isSsrcRewritingSupported","SDPUtil","filterSpecialChars","iceparams","mediadesc","sessiondesc","pwd","findLine","parseICEUfrag","parseICEPwd","line","buildICEUfrag","frag","buildICEPwd","parseMID","parseMSIDAttribute","ssrcLines","msidLine","parseMLine","parts","proto","pop","fmt","buildMLine","mline","parseRTPMap","clockrate","channels","parseSCTPMap","parseSCTPPort","buildRTPMap","parseCrypto","parseFingerprint","fingerprint","parseFmtp","parseICECandidate","candidate","elems","foundation","component","toLowerCase","priority","generation","tcptype","network","buildICECandidate","cand","hasOwnAttribute","parseSSRC","desc","lines","parseSourceNameLine","sourceNameLine","ssrcSdpLine","parseVideoTypeLine","videoTypeLine","parseRTCPFB","pt","params","parseExtmap","direction","uri","haystack","needle","sessionpart","findLines","needles","candidateToJingle","candidateFromJingle","parsePrimaryVideoSsrc","videoMLine","numSsrcs","map","ssrcInfo","numGroups","ssrcGroups","primarySsrc","fidGroup","simGroup","generateSsrc","RandomUtil","getSsrcAttribute","mLine","attributeName","ssrcLine","attribute","parseGroupSsrcs","ssrcGroup","ssrcStr","getMedia","sdp","getUfrag","ufragLines","preferCodec","codecName","matchingPayloadTypes","rtp","payloadTypes","payloads","reverse","payloadIndex","unshift","stripCodec","highProfile","h264Pts","removePts","stripH264HighCodec","CodecMimeType","fmtp","item","rtxApts","rtxPts","keepPts","INACTIVE","rtcpFb","SDP","mediaI","raw","arrayEquals","array1","array2","l","equals","SDPDiffer","mySDP","otherSDP","failICE","removeTcpCandidates","removeUdpCandidates","addMlineForNewLocalSource","mid","clonedeep","RECVONLY","msid","concat","groups","mids","getMediaSsrcMap","mediaSSRCs","mediaindex","linessrc","containsSSRC","medias","toJingle","thecreator","assrcline","creator","amidline","rtpmap","afmtpline","fmtpParameters","rtcpFbToJingle","availableSsrc","ssrcParameters","sourceName","ridLines","rids","ridLine","ridInfo","extmapLines","extmap","SENDONLY","senders","SENDRECV","transportToJingle","sctpport","sctpmap","sctpAttrs","streams","setupLine","setup","iceParameters","payloadtype","feedback","rtcpFbFromJingle","feedbackElementTrrInt","fb","hasAttribute","fromJingle","contents","jingle2media","sctp","payloadType","setAttribute","__","parameter","hdrExt","userSources","nonUserSources","isUserSource","sourceStr","getNewMedia","myMedias","othersMedias","newMedia","othersMediaIdx","myMedia","othersMedia","otherSsrcGroup","matched","mySsrcGroup","modify","sdpMediaSsrcs","modified","ssrcNum","mediaSsrc","hasQueueMicrotask","queueMicrotask","hasSetImmediate","setImmediate","hasNextTick","nextTick","fallback","fn","wrap","defer","setImmediate$1","handlePromise","invokeCallback","isAsync","toStringTag","wrapAsync","asyncFn","func","awaitify","arity","cbArgs","applyEach","eachfn","fns","callArgs","that","cb","_asyncMap","arr","iteratee","results","counter","_iteratee","iterCb","isArrayLike","breakLoop","once","wrapper","callFn","assign","onlyOnce","asyncEachOfLimit","generator","limit","done","canceled","awaiting","running","replenish","iterDone","iterateeCallback","handleError","eachOfLimit","RangeError","asyncIterator","isAsyncIterable","nextElem","coll","len","createArrayIterator","okeys","iterator","getIterator","createES2015Iterator","createIterator","looping","eachOfLimit$2","eachOfArrayLike","completed","iteratorCallback","eachOfGeneric","Infinity","eachOf$1","map$1","eachOfSeries$1","DLL","head","tail","removeLink","prev","empty","insertAfter","newNode","insertBefore","setInitial","toArray","cur","testFn","curr","dll","queue","worker","concurrency","numRunning","workersList","drain","saturated","unsaturated","ev","trigger","processingScheduled","_insert","insertAtFront","rejectOnError","rej","promiseCallback","q","started","_tasks","_createCB","tasks","buffer","idle","_maybeDrain","eventMethod","handleAndRemove","isProcessing","paused","datum","pushAsync","kill","unshiftAsync","pause","defineProperties","memo","mapLimit$1","concatLimit$1","val","mapResults","_createTester","check","getResult","testResult","testPassed","consoleFunc","resultArgs","_withoutIndex","bool","_fn","_test","truth","eachLimit$2","eachSeries$1","filterArray","truthValues","filterGeneric","_filter","sync","innerArgs","ensureAsync","newObj","taskCb","TypeError","criteria","comparator","left","right","rest","taskIndex","nextTask","AsyncQueue","_queue","_processQueueTasks","items","_stopped","finishedCallback","shutdown","JingleSessionState","PENDING","ACTIVE","ENDED","JingleSession","localJid","mediaConstraints","pcConfig","isInitiator","usedrip","dripContainer","_signalingLayer","initiatorJid","responderJid","signalingLayer","doInitialize","addIceCandidates","getState","addSources","removeSources","terminate","failure","acceptOffer","_getInitiatorJid","MediaSessionEvents","IQ_TIMEOUT","_addSourceElement","ssrc_","JingleSessionPC","jingleContents","videoContents","maxFrameHeightSel","receiverConstraints","sourceFrameHeightSel","_bridgeSessionId","_cachedOldLocalSdp","_cachedNewLocalSdp","_iceCheckingStartedTimestamp","_gatheringStartedTimestamp","localRecvMaxFrameHeight","_sourceReceiverConstraints","_localVideoActive","_remoteVideoActive","_gatheringReported","lasticecandidate","closed","remoteRecvMaxFrameHeight","numRemoteVideoSources","numRemoteAudioSources","remoteSourceMaxFrameHeights","modificationQueue","wasConnected","establishmentDuration","_xmppListeners","onXmppStatusChanged","_removeSenderVideoConstraintsChangeListener","_assertNotEnded","isReconnect","wasstable","webrtcIceUdpDisable","webrtcIceTcpDisable","pcOptions","gatherStats","maxstats","capScreenshareBitrate","enableInsertableStreams","videoQuality","forceTurnRelay","usesUnifiedPlan","enableUnifiedOnChrome","disableSimulcast","abtestSuspendVideo","_abtestSuspendVideoEnabled","preferH264","disableH264","preferredCodec","H264","createPeerConnection","onicecandidate","phase","initiator","sendIceCandidate","onsignalingstatechange","signalingState","connectionState","oniceconnectionstatechange","isStable","iceConnectionState","reconnect","usesTerminateForRestart","enableIceRestart","iceStarted","onconnectionstatechange","icestate","onnegotiationneeded","remoteDescription","workFunction","oldSdp","localDescription","_renegotiate","configureSenderVideoEncodings","newSdp","notifyMySSRCUpdate","getRemoteRecvMaxFrameHeight","getRemoteSourcesRecvMaxFrameHeight","localSDP","ice","sdpMLineIndex","jcand","errorMesssage","sendIceCandidates","candidates","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","FeatureFlags","addTracks","addTrack","all","createOffer","offerSdp","setLocalDescription","processLocalSdpForTransceiverInfo","sendSessionInitiate","setAnswer","jingleAnswer","newRemoteSdp","_processNewJingleOfferIq","oldLocalSdp","RTCSessionDescription","setRemoteDescription","newLocalSdp","sendContentModify","jingleOfferAnswerIq","audioTracks","tracks","bridgeSessionId","_responderRenegotiate","setVideoCodecs","preferred","disabled","current","replaceTransport","jingleOfferElem","enableForcedReload","sendTransportAccept","originalOffer","clone","newFingerprint","accept","responder","maxFrameHeight","sessionModify","setReceiverVideoConstraint","sourceReceiverConstraints","transportAccept","medialines","sendTransportReject","transportReject","setSenderVideoConstraint","jitsiLocalTrack","getLocalVideoTracks","getSourceName","getLocalVideoTrack","setSenderVideoConstraints","sendSessionTerminate","sessionTerminate","reasonDescription","restart","requestRestart","onTerminated","reasonCondition","reasonText","getRemoteTracks","_parseSsrcInfoFromSourceAdd","sourceAddElem","currentRemoteSdp","addSsrcInfo","i1","midFound","i2","addRemoteStream","_addOrRemoveRemoteStream","removeRemoteStream","getNewSources","newSources","mappedSources","addRemoteSsrc","_setVideoType","setNewSource","rtx","removeRemoteStreamsOnLeave","finishCallback","removeSsrcInfo","getRemoteSourceInfoByParticipant","_processRemoteRemoveSource","newLocalSDP","isAdd","logPrefix","errMsg","addOrRemoveSsrcInfo","_parseSsrcInfoFromSourceRemove","_processRemoteAddSource","remoteSdp","findIndex","desiredDirection","getDesiredMediaDirection","optionalRemoteSdp","_initiatorRenegotiate","createAnswer","answer","offer","replaceTracks","oldLocalSDP","recvOnlyTransceiver","getTransceivers","currentDirection","replaceTrack","oldTrack","newTrack","clearRecvonlySsrc","shouldRenegotiate","setSourceName","sourceRemoveElem","_verifyNoSSRCChanged","operationName","oldSDP","currentLocalSDP","sdpDiff","addedMedia","removedMedia","addTrackToPc","_addRemoveTrack","removeTrackFromPc","isRemove","setMediaTransferActive","audioActive","videoActive","logAudioStr","logVideoStr","isSessionActive","audioActiveChanged","setAudioTransferActive","pcVideoActiveChanged","setVideoTransferActive","modifyContents","newVideoSenders","parseVideoSenders","newMaxFrameHeight","parseMaxFrameHeight","sourceMaxFrameHeights","parseSourceMaxFrameHeight","_modifyRemoteVideoActive","remoteVideoSenders","isRemoteVideoActive","newSDP","getSignaledSourceInfo","sdpDiffer","mediaIndex","signaledSsrcs","ctx","removedSsrcInfo","addedSsrcInfo","request","errResponse","errorElSel","code","errorReasonSel","errorMsgSel","getIceConnectionState","getConnectionState","abTesting","enableSuspendVideoTest","integerHash","_parseIceCandidates","parseCandidates","candidateAttrs","JingleConnectionPlugin","iceConfig","sessions","jvbIceConfig","jvb","p2pIceConfig","offerToReceiveAudio","offerToReceiveVideo","onJingle","fromJid","sess","jsonMessages","audioVideoSsrcs","logMessage","endpoint","startMuted","iceUfrag","icePwd","dtlsFingerprint","successTime","newP2PJingleSession","me","getStunAndTurnCredentials","v2Res","onReceiveStunAndTurnCredentials","v1Res","iceservers","dict","urls","credential","temp","useTurnUdp","iceServers","getLog","updateLog","href","StropheLogger","logIncoming","rawOutput","logOutgoing","RAYO_XMLNS","RayoConnectionPlugin","onRayo","roomPass","req","callResource","lastErrorStatus","resetLastErrorStatusRegExpr","lastErrorStatusRegExpr","FAILURE_REGEX","DEFAULT_STUN_SERVERS","FEATURE_JIGASI","token","disconnectInProgress","authenticatedUser","deploymentInfo","_components","trace","errStatusCapture","exec","createConnection","bosh","details","shard_changed","suspend_time","time_since_last_success","_initStrophePlugins","caps","initFeaturesList","disableBeforeUnloadHandlers","enableOpusRed","enableRemb","enableTcc","enableLipSync","getConnection","connectionHandler","credentials","statusStr","_maybeSendDeploymentInfoStat","_sysMessageHandler","deleteHandler","sendDiscoInfo","_resetState","sendDeploymentInfo","_processDiscoInfoIdentities","anonymousConnectionFailed","connectionFailed","lastErrorMsg","wasIntentionalDisconnect","_getConnectionFailedReasonDetails","lastFailedRawMessage","_parseConnectionFailedMessage","speakerStatsComponentAddress","conferenceDurationComponentAddress","processLobbyFeatures","fr","region","backendRelease","_onPrivateMessage","_connect","_addSysHandler","_onSystemMessage","foundIceServers","attaching","configDomain","hostname","onCreateResource","getRoomJid","mucNickname","muc","getJingleLog","getXmppLog","getSessions","disconnectListener","_cleanupXmppConnection","evType","p2pStunServers","stunServers","iceTransportPolicy","headersArr","trim","header","sendFaceExpressionEvent","expression","faceExpression","jsonString","users","created_timestamp","force","acceptedStatuses","aprops","authenticateAndUpgradeRole","rejectPromise","onLoginSuccessful","authenticationError","connectionError","CodecSelection","disabledCodec","_getCodecMimeType","jvbCodec","p2pCodec","jvbPreferredCodec","_isCodecSupported","p2pPreferredCodec","_selectPreferredCodec","mediaSession","currentCodec","selectedCodec","enforcePreferredCodec","remoteParticipants","remote","peerMediaInfo","getPeerMediaInfo","peerCodec","getPreferredCodec","BridgeChannel","wsUrl","_channel","_eventEmitter","_mode","_areRetriesEnabled","_closedFromClient","datachannel","createDataChannel","_handleChannel","_wsUrl","_initWebSocket","ws","_startConnectionRetries","timeoutS","reload","isOpen","_retryTimeout","_stopConnectionRetries","_retryWebSocketConnection","closeEvent","createBridgeChannelClosedEvent","mode","sendEndpointStatsMessage","_send","colibriClass","msgPayload","sendSetLastNMessage","lastN","sendSelectedEndpointsMessage","endpointIds","selectedEndpoints","sendReceiverVideoConstraintMessage","maxFrameHeightPixels","sendNewReceiverVideoConstraintsMessage","sendVideoTypeMessage","sendSourceVideoTypeMessage","channel","onopen","onmessage","dominantSpeakerEndpoint","previousSpeakers","isActive","active","forwardedSources","videoConstraints","onclose","jsonObject","logDisabled_","deprecationWarnings_","extractVersion","uastring","expr","pos","wrapPeerConnectionEvent","eventNameToWrap","RTCPeerConnection","nativeAddEventListener","nativeEventName","arguments","wrappedCallback","modifiedEvent","handleEvent","_eventMap","nativeRemoveEventListener","unwrappedCb","enumerable","configurable","disableLog","disableWarnings","deprecated","oldMethod","newMethod","detectBrowser","mozGetUserMedia","webkitGetUserMedia","isSecureContext","webkitRTCPeerConnection","RTCIceGatherer","isObject","compactObject","accumulator","isObj","isEmptyObject","walkStats","resultSet","filterStats","outbound","streamStatsType","filteredResult","trackStats","trackStat","trackId","logging","utils","shimGetUserMedia","browserDetails","constraintsToChrome_","cc","r","ideal","exact","oldname_","prefix","charAt","toUpperCase","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","origGetUserMedia","getAudioTracks","getVideoTracks","DOMException","shimGetDisplayMedia","getSourceId","widthSpecified","heightSpecified","frameRateSpecified","shimMediaStream","MediaStream","webkitMediaStream","shimOnTrack","_ontrack","origSetRemoteDescription","_ontrackpoly","te","getReceivers","Event","transceiver","dispatchEvent","shimGetSendersWithDtmf","shimSenderWithDtmf","dtmf","_dtmf","createDTMFSender","_pc","getSenders","_senders","origAddTrack","origRemoveTrack","removeTrack","origAddStream","addStream","origRemoveStream","removeStream","origGetSenders","shimGetStats","origGetStats","selector","onSucc","onErr","fixChromeStats_","standardReport","standardStats","localcandidate","remotecandidate","names","stat","makeMapStats","successCallbackWrapper_","shimSenderReceiverGetStats","origGetReceivers","receivers","srcElement","MediaStreamTrack","shimAddTrackRemoveTrackWithNative","getLocalStreams","_shimmedLocalStreams","existingSenders","newSenders","newSender","shimAddTrackRemoveTrack","origGetLocalStreams","nativeStreams","_reverseStreams","_streams","newStream","replaceInternalStreamId","internalId","externalStream","internalStream","RegExp","replaceExternalStreamId","alreadyExists","oldStream","method","nativeMethod","methodObj","origSetLocalDescription","origLocalDescription","getOwnPropertyDescriptor","streamid","shimPeerConnection","fixNegotiationNeeded","target","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","SDPUtils","augmentedCandidate","toJSON","usernameFragment","shimMaxMessageSize","_sctp","sctpInDescription","sections","mediaSection","getRemoteFirefoxVersion","getCanSendMaxMessageSize","remoteIsFirefox","canSendMaxMessageSize","getMaxMessageSize","maxMessageSize","canSendMMS","remoteMMS","POSITIVE_INFINITY","shimSendThrowTypeError","wrapDcSend","dc","origDataChannelSend","byteLength","origCreateDataChannel","dataChannel","shimConnectionState","checking","_onconnectionstatechange","origMethod","_connectionstatechangepoly","_lastConnectionState","newEvent","removeExtmapAllowMixed","nativeSRD","shimAddIceCandidateNullOrEmpty","nativeAddIceCandidate","shimParameterlessSetLocalDescription","nativeSetLocalDescription","shimChrome","shimFirefox","shimSafari","adapter","commonShim","chromeShim","browserShim","firefoxShim","safariShim","adapterFactory","DEFAULT_CONSTRAINTS","audioOutputDeviceId","audioOutputChanged","disableAP","disableAEC","disableNS","disableAGC","featureDetectionAudioEl","createElement","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","element","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","_setHandler","_unregisterHandlers","videoTrack","getVideoType","isLocalAudioTrack","getStreamId","getTrack","getTrackLabel","getTrackId","getUsageLabel","_maybeFireTrackAttached","container","_onTrackAttach","RTCUtils","_attachTTFMTracker","detach","_onTrackDetach","newAudioLevel","getMSID","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","opts","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","currentDesc","iceRestart","newDesc","oldDesc","newMLine","oldMLine","checkForIceRestart","newIceUfrag","newIcePwd","newMline","mLineForData","ssrc2group","createSourceGroupMap","bundleOnly","sessionVersion","resultSdp","SignalingEvents","PEER_MUTED_CHANGED","PEER_VIDEO_TYPE_CHANGED","SOURCE_MUTED_CHANGED","SOURCE_VIDEO_TYPE_CHANGED","getSourceNameForJitsiTrack","trackIdx","getMediaTypeFromSourceName","firstLetterOfMediaTypeIdx","firstLetterOfMediaType","getSourceIndexFromSourceName","nameParts","SignalingLayer","getSSRCOwner","getPeerSourceInfo","getTrackSourceName","setTrackMuteStatus","setTrackVideoType","parsePrimarySSRC","parseSecondarySSRC","_getSSRCCount","MLineWrap","getSSRCAttrValue","ssrcNumber","attrName","ssrcObj","removeSSRC","addSSRCAttribute","findGroup","findGroups","findGroupByPrimarySSRC","primarySSRC","findSSRCByMSID","getSSRCCount","containsAnySSRCGroups","getPrimaryVideoSsrc","fecGroup","getRtxSSRC","getSSRCs","getPrimaryVideoSSRCs","videoSSRCs","ssrcGroupInfo","secondarySsrc","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","ssrcCache","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","primarySsrcMsid","primarySsrcCname","cname","previousRtxSSRC","RtxModifier","correspondingRtxSsrcs","clearSsrcCache","setSsrcCache","ssrcMapping","modifyRtxSsrcs","sdpStr","sdpTransformer","videoMLines","primaryVideoSsrcs","correspondingRtxSsrc","stripRtx","fidGroups","SdpConsistency","clearVideoSsrcCache","injectRecvOnly","setPrimarySsrc","hasPrimarySsrcCached","makeVideoPrimarySsrcsConsistent","newPrimarySsrc","SdpSimulcast","_ssrcCache","numOfLayers","_fillSsrcsFromCache","cachedSsrcs","newSsrcs","_parseSimLayers","newMsid","_getSsrcAttribute","newCname","_generateNewSsrcsForSimulcast","addAssociatedAttributes","simSsrcs","simSsrc","_generateSsrc","mungeLocalDescription","simulcastSsrcs","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","listenerCount","_initTrackStreamingStatus","_disposeTrackStreamingStatus","REMOTE_TRACK_MUTE","REMOTE_TRACK_UNMUTE","setMute","getSSRC","_playCallback","getConnectionTimes","gumStart","gumEnd","gumDuration","ttfm","_getStatus","_p2pConnStatusRtcMuteTimeout","_peerConnStatusRtcMuteTimeout","_peerConnStatusOutOfLastNTimeout","HD_BITRATE","SIM_LAYER_RIDS","TPCUtils","bitrateSettings","maxBitratesVideo","standardBitrates","low","standard","high","videoBitrates","encodingBitrates","VP8","localStreamEncodingsConfig","maxBitrate","_getStreamEncodings","localTrack","ensureCorrectOrderOfSsrcs","parsedSdp","reorderedSsrcs","findTransceiver","insertUnifiedPlanSimulcastReceive","simulcast_03","simulcastLine","transceiverInit","calculateEncodingsActiveState","localVideoTrack","newHeight","encoding","_capScreenshareBitrate","calculateEncodingsBitrates","desktopShareBitrate","desktopBitrate","lowFpsScreenshare","isNewLocalSource","stopped","transceiverMid","_localTrackTransceiverMids","setEncodings","parameters","transceivers","updateEncodingsResolution","TraceablePeerConnection","audioTransferActive","_dtmfSender","_dtmfTonesQueue","videoTransferActive","remoteTracks","_addedStreams","localSSRCs","remoteSSRCs","localUfrag","remoteUfrag","_dtlsTransport","_peerVideoTypeChanged","_peerMutedChanged","_sourceMutedChanged","_sourceVideoTypeChanged","safeConstraints","rtcStatsSFUP2P","tpcUtils","statsinterval","_usesTransceiverCodecPreferences","interop","Simulcast","explodeRemoteSimulcast","localSdpMunger","getLocalEndpointId","_senderVideoMaxHeight","_senderMaxHeights","what","time","onTrack","evt","_remoteTrackAdded","_remoteTrackRemoved","onaddstream","_remoteStreamAdded","onremovestream","_remoteStreamRemoved","ondatachannel","_processStat","statValue","endTime","times","dumpSDP","isAddOperation","hasLocalSource","hasAnyTracksOfType","mediaTransferActive","_getDesktopTrackMid","desktopTrack","_getReceiversByEndpointIds","endpoints","remoteTrackIds","audioReceivers","getSynchronizationSources","endpointTracksByMediaType","primarySsrcs","fidLines","getTargetVideoBitrates","remoteTrack","findTrackById","RTC","isUserStreamById","onaddtrack","onremovetrack","streamAudioTracks","audioTrack","streamVideoTracks","remoteSDP","mediaLines","mls","trackSsrc","_createRemoteTrack","remoteTracksMap","userTracksByMediaType","isUserStream","toBeRemoved","_removeRemoteTrack","removeRemoteTracks","removedTracks","remoteTracksByMedia","_extractSSRCMap","groupsMap","groupSSRCs","_getSSRC","_injectSsrcGroupForUnifiedSimulcast","getters","audioMedia","changed","videoMedia","enforceSendRecv","_adjustRemoteMediaDirection","isSharingLowFpsScreen","_isSharingScreen","_mungeCodecOrder","codecPreference","mLines","webrtcStream","_addStream","generateNewStreamSSRCInfo","rtxSsrcMapping","promiseChain","_assertTrackBelongs","webRtcStream","_removeStream","doesBelong","defaultCodec","lowFps","findSenderByKind","localSdp","oldTrackSSRC","mediaActive","_ensureSimulcastGroupIsLast","videoStartIndex","simStartIndex","otherStartIndex","simEndIndex","simStr","otherEndIndex","sdpHead","simStrTrimmed","sdpTail","_adjustLocalMediaDirection","modifiedDirection","desiredAudioDirection","desiredVideoDirection","localSources","remoteSources","_mungeOpus","enableOpusDtx","opusMaxAverageBitrate","OPUS","fmtpOpus","fmtpConfig","sdpChanged","maxaveragebitrate","usedtx","mungedConfig","_mungeInactive","_initializeDtlsTransport","onstatechange","_setVp9MaxBitrates","isLocalSdp","VP9","bitrates","hdBitrate","isSharingScreen","currentDescription","mungeRemoteDescription","firstSsrcs","newSsrcLines","filteredLines","ssrcId","cnameLine","replaceDefaultUnifiedPlanMsid","write","normalizePlanB","videoSender","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","ULPFEC","setCodecPreferences","oaPromise","_extractPrimarySSRC","sourceIndex","sourceIdentifier","newSSRCNum","oldSSRCNum","existing","activeStreams","currNumSsrcs","ConnectionQualityEvents","peerConnectionIdCounter","rtcTrackIdCounter","_createLocalTracks","mediaStreamMetaData","metaData","peerConnections","_lastN","_lastNEndpoints","_forwardedSources","_maxFrameHeight","_selectedEndpoints","_forwardedSourcesChangeListener","_onDeviceListChanged","_updateAudioOutputForAudioTracks","_videoType","BridgeVideoType","destroy","_channelOpenListener","tracksInfo","initializeBridgeChannel","logError","msgType","_receiverVideoConstraints","oldForwardedSources","setNewReceiverVideoConstraints","setVideoType","sendSourceVideoType","selectEndpoints","ids","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","targetRN","ConnectionQuality","_localStats","connectionQuality","jvbRTT","_lastConnectionQualityUpdate","_remoteStats","_timeIceConnected","_timeVideoUnmuted","ConferenceEvents","_updateLocalConnectionQuality","_broadcastLocalStats","ICE_CONNECTION_STATE_CHANGED","_updateRemoteStats","_updateLocalStats","_maybeUpdateUnmuteTime","LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED","serverRegion","bridgeCount","_calculateConnectionQuality","resolutionName","quality","DESKTOP","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","_audioLevel","_trackAdded","_clearTriggerTimeout","_handleAudioInputStateChange","_handleNoAudioInputDetection","_eventFired","_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","getParticipantCount","ReceiverVideoConstraints","_defaultConstraints","defaultConstraints","onStageEndpoints","updateLastN","updateReceiveResolution","updateReceiverVideoConstraints","updateSelectedEndpoints","ReceiveVideoController","_rtc","startLastN","channelLastN","useNewBandwidthAllocationStrategy","_getDefaultSourceReceiverConstraints","remoteVideoTracks","remoteEndpointIds","oldConstraints","newConstraints","setPreferredReceiveMaxFrameHeight","setReceiverConstraints","p2pSession","mappedConstraints","SendVideoController","_preferredSendMaxFrameHeight","_sourceSenderConstraints","_configureConstraintsForLocalSources","_onSenderConstraintsReceived","_propagateSendMaxFrameHeight","sourceConstraints","sendMaxFrameHeight","_selectSendMaxFrameHeight","setPreferredSendMaxFrameHeight","getFocusRecordingUpdate","jibriStatus","recordingMode","sessionID","getHiddenDomainUpdate","liveStreamViewURLContainer","liveStreamViewURL","modeContainer","sessionIDContainer","getSessionIdFromIq","jibri","getSessionId","sessionIdContainer","isFromFocus","JibriSession","_connection","_jibriJid","_statusFromJicofo","_setSessionID","setStatus","getID","_sessionID","getInitiator","_initiator","getLiveStreamViewURL","_liveStreamViewURL","getJibriJid","getTerminator","_terminator","getMode","setError","setLiveStreamViewURL","setStatusFromJicofo","setJibriJid","jibriJid","appData","broadcastId","_createIQ","recordingXMLUtils","_setErrorFromIq","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","setDominantSpeaker","savedUser","markAsHasLeft","newName","setDisplayName","addFaceExpression","newStats","speakerStatsToUpdate","newParticipant","totalDominantSpeakerTime","setFaceExpressions","faceExpressions","RecordingResult","blob","wordArray","TrackRecorder","recorder","AUDIO_WEBM","AUDIO_OGG","startRecorder","trackRecorder","stopRecorder","determineCorrectFileType","MediaRecorder","isTypeSupported","AudioRecorder","jitsiConference","recorders","fileType","isRecording","instantiateTrackRecorder","updateNames","originalStream","ondataavailable","dataEvent","recorderToRemove","style","click","revokeObjectURL","getRecordingResults","getFileType","Word","word","begin","getWord","getBeginTime","getEndTime","SphinxService","recordingResult","verify","formatResponse","audioBlob","sphinxURL","toReturn","getURL","audioFileBlob","XMLHttpRequest","onreadystatechange","DONE","responseText","open","setRequestHeader","audioRecorder","objects","filler","BEFORE_STATE","RECORDING_STATE","TRANSCRIBING_STATE","FINISHED_STATE","Transcriber","transcriptionService","transcription","lineLength","blobCallBack","transcriber","offset","getUTCMilliseconds","wordObject","maybeMerge","hasPopulatedArrays","twoDimensionalArray","callBack","merge","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","nodeTree","VideoSIPGW","sessionStateChangeListener","sessionStateChanged","handleJibriSIPState","Constants","failure_reason","createVideoSIPGWSession","SOURCE_INFO_PRESENCE_ELEMENT","SignalingLayerImpl","ssrcOwners","_localSourceState","_remoteSourceState","_sourceNames","_addLocalSourceInfoToPresence","_doesEndpointSendNewSourceInfo","setChatRoom","oldChatRoom","_audioMuteHandler","_videoMuteHandler","_videoTypeHandler","_sourceInfoHandler","_memberLeftHandler","_bindChatRoomEventHandlers","emitAudioMutedEvent","emitVideoMutedEvent","emitVideoTypeEvent","sourceInfoJSON","emitEventsFromHere","endpointSourceState","newMutedState","oldSourceState","newVideoType","newSourceNames","_findEndpointSourceInfoForMediaType","remoteSourceState","sourceInfo","lastPresence","legacyGetPeerMediaInfo","mediaInfo","existingOwner","existingName","JitsiConference","eventManager","componentsVersions","dtmfManager","somebodySupportsDTMF","wasStopped","avgRtpStatsN","_audioOutputProblemDetector","speakerStatsCollector","deferredStartP2PTask","delay","backToP2PDelay","isP2PConnectionInterrupted","videoSIPGWHandler","recordingManager","_sessions","_chatRoom","getSession","getSessionByJibriJid","_handleFocusPresence","_handleJibriPresence","prevStatus","_emitSessionUpdate","startRecording","_addSession","stopRecording","_createSession","_conferenceJoinAnalyticsEventSent","isE2EESupported","_e2eEncryption","_audioSenderLimitReached","_videoSenderLimitReached","JitsiConnection","appID","errType","errorType","errorMessage","createConnectionFailedEvent","ANALYTICS_CONNECTION_DISCONNECTED","JitsiMediaDevicesEvents","resourceCreator","isAuthenticatedUser","re","codecSettings","codecSelection","_statsCurrentId","statisticsId","_onIceConnectionInterrupted","_onIceConnectionRestored","_onIceConnectionEstablished","_updateProperties","_sendConferenceJoinAnalyticsEvent","_removeLocalSourceOnReject","_updateRoomPresence","_registerRtcListeners","receiveVideoController","sendVideoController","callStatsThreshold","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","_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","_setNewVideoType","videoTypeChanged","presenceChanged","addPromises","removePromises","lock","unlock","selectParticipant","selectParticipants","participantIds","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","_suspendMediaTransferForJvbConnection","webSocket","first","stopOptions","forceJvb121","p2pFailed","_stopP2PSession","isDTMFSupported","peerConnection","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","myId","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","DEVICE_LIST_CHANGED","PERMISSIONS_CHANGED","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","_onError","_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","Logger","getAnalyticsAttributesFromOptions","video_requested","ProxyConnectionService","jitsiConnection","_onFatalError","_convertStringToXML","UNAVAILABLE","_selfCloseConnection","xml","xmlDom","DOMParser","parseFromString","isVideo","convertVideoToDesktop","jitsiLocalTracks","createLocalTracks","stringifiedIq","XMLSerializer","serializeToString","onConnectionClosed","constants","recording","BUSY","ERROR","RESOURCE_CONSTRAINT","UNEXPECTED_REQUEST","SERVICE_UNAVAILABLE","FILE","STREAM","sipVideoGW","detection","errors","errorTypes","logLevels","JitsiMediaDevices","enableAnalyticsLogging","enableWindowOnErrorHandler","getGlobalOnErrorHandler","isWebRtcSupported","setLogLevel","setLogLevelById","addGlobalLogTransport","globalTransport","removeGlobalLogTransport","setGlobalLogOptions","oldfirePermissionPromptIsShownEvent","promiseFulfilled","firePermissionPromptIsShownEvent","fireSlowPromiseEvent","restOptions","currentlyAvailableMediaDevices","setVideoTrackContentHints","createTrackVADEmitter","localAudioDeviceId","createAudioMixer","getActiveAudioDevice","audioDevices","devicePromiseArray","micDevice","devicePromise","outcomeArray","successfulPromises","rejectedPromises","rejectReasons","deviceLabel","isCollectingLocalStats","lineno","colno","setNetworkInfo","hint","contentHint","precallTest","util","AuthUtil","JitsiMeetJS","_mergeNamespaceAndModule","isLocalStats","_userId","_isLocalStats","_dominantSpeakerStart","_isDominantSpeaker","_isSilent","_hasLeft","_faceExpressions","happy","neutral","surprised","angry","fearful","disgusted","sad","getUserId","isDominantSpeaker","isNowDominantSpeaker","timeElapsed","getTotalDominantSpeakerTime","hasLeft","getFaceExpressions","getTokenAuthUrl","urlPattern","roleUpgrade","dest","srcEvent","Function","oldOnErrorHandler","oldOnUnhandledRejection","onunhandledrejection","errHandler","callUnhandledRejectionHandler","randomInt","randomElement","randomHexDigit","randomHexString","randomAlphanumStr","currentExecutingScript","loadScript","prepend","relativeURL","loadCallback","script","referenceNode","scriptEl","scriptSrc","baseScriptSrc","onload","parentNode","string","char","charCodeAt","abs","generateUsername","LogCollector","logStorage","stringifyObjects","storeInterval","maxEntryLength","levels","logLevel","_log","storeLogsIntervalID","totalLen","outputCache","someObject","formatLogMessage","arg","prevMessage","prevMessageText","_flush","_reschedulePublishInterval","reschedule","isReady","cachedQueue","storeLogs","consoleTransport","globalTransports","addGlobalTransport","removeGlobalTransport","transportIdx","globalOptions","getCallerInfo","callerInfo","fileLocation","column","disableCallerInfo","transports","logPrefixes","toISOString","fullLogParts","methods","setGlobalOptions","setLevel","TRACE","DEBUG","INFO","LOG","WARN","idLoggers","loggers","curLevel","grammar","reg","o","format","u","z","subtype","sessionConfig","raddr","dir2","clksrcExt","mediaClockValue","rateNumerator","rateDenominator","writer","parseParams","parseFmtpConfig","parsePayloads","parseRemoteCandidates","parseImageAttributes","parseSimulcastStreamList","toIntIfInt","String","parseReg","needsBlank","keyLocation","rawName","attachProperties","validLine","paramReducer","acc","scid","formatRegExp","formatStr","makeLine","defaultOuterOrder","defaultInnerOrder","outerOrder","innerOrder","transformUtils","parseSsrcs","writeSsrcs","processVideo","validateDescription","_buildNewToOldSsrcMap","newSsrcList","oldSsrcList","newSsrc","oldSsrc","_fillInSourceDataFromCache","newSimSsrcs","ssrcsToReplace","ssrcsToAdd","_generateSourceData","addAssociatedStream","_restoreSimulcast","enableConferenceFlag","order","relatedGroup","relatedSsrcs","relatedSSRC","simulcastGroup","nuke","implodeRemoteSimulcast","invalid","assertGoogConference","xGoogleFlag","removeGoogConference","b64","lens","getLens","validLen","placeHoldersLen","toByteArray","Arr","_byteLength","curByte","revLookup","fromByteArray","uint8","extraBytes","maxChunkLength","len2","encodeChunk","lookup","num","output","__esModule","default","getFirstMatch","getSecondMatch","matchAndReturnConst","getWindowsVersionName","getMacOSVersionName","getAndroidVersionName","getVersionPrecision","compareVersions","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","epiphany","firefox","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","getParser","_ua","parsedResult","getUA","parseBrowser","describe","getBrowser","getOS","os","parseOS","getOSName","getOSVersion","getPlatform","parsePlatform","getPlatformType","getEngine","engine","parseEngine","getEngineName","isOS","isPlatform","isBrowser","compareVersion","is","versionName","vendor","model","scriptReadyRegex","fullPageUrl","pageUrl","scripts","supportsScriptReadyState","isNotOpera","hasNativeCurrentScriptAccessor","stackTraceLimit","hasStackBeforeThrowing","hasStackAfterThrowing","getScriptUrlFromStack","skipStackDepth","ignoreMessage","_nearestExecutingScript","eligibleScripts","getScriptFromUrl","getSoleInlineScript","currentScript","thrownErr","near","far","ReflectOwnKeys","R","Reflect","ReflectApply","ownKeys","getOwnPropertySymbols","getOwnPropertyNames","NumberIsNaN","errorListener","resolver","eventTargetAgnosticAddListener","addErrorHandlerIfEventEmitter","_events","_eventsCount","_maxListeners","defaultMaxListeners","checkListener","_getMaxListeners","_addListener","warning","newListener","warned","w","onceWrapper","fired","wrapFn","_onceWrap","wrapped","_listeners","unwrap","evlistener","unwrapListeners","arrayClone","copy","wrapListener","getPrototypeOf","setMaxListeners","getMaxListeners","doError","er","listeners","prependListener","prependOnceListener","position","originalListener","spliceOne","rawListeners","eventNames","g","flat","y","nodeType","nonce","noModule","C","removeChild","T","E","jquery","pushStack","prevObject","eq","last","even","grep","odd","extend","isPlainObject","expando","noop","globalEval","makeArray","inArray","guid","support","h","A","N","ue","S","D","L","O","P","H","I","B","M","W","F","U","V","X","Q","ID","CLASS","TAG","ATTR","PSEUDO","CHILD","needsContext","Y","G","K","J","Z","ee","ne","fromCharCode","oe","ae","xe","dir","childNodes","se","ownerDocument","getElementById","getElementsByClassName","qsa","ye","scope","be","querySelectorAll","removeAttribute","cacheLength","le","ce","fe","attrHandle","de","nextSibling","pe","he","ge","isDisabled","ve","isXML","namespaceURI","documentElement","setDocument","defaultView","top","className","createComment","getById","getElementsByName","getAttributeNode","innerHTML","matchesSelector","webkitMatchesSelector","mozMatchesSelector","oMatchesSelector","msMatchesSelector","disconnectedMatch","compareDocumentPosition","contains","sortDetached","specified","escape","uniqueSort","detectDuplicates","sortStable","getText","firstChild","nodeValue","selectors","createPseudo","relative","preFilter","lastChild","uniqueID","pseudos","setFilters","not","lang","activeElement","hasFocus","tabIndex","checked","selected","selectedIndex","parent","input","button","lt","gt","nth","radio","checkbox","file","image","we","Ce","Te","Ee","filters","tokenize","compile","select","defaultValue","unique","isXMLDoc","escapeSelector","parseHTML","ready","closest","prevAll","addBack","parents","parentsUntil","nextAll","nextUntil","prevUntil","siblings","contentDocument","fail","Callbacks","stopOnFalse","memory","fireWith","fire","always","pipe","progress","notify","notifyWith","resolveWith","exceptionHook","stackTrace","rejectWith","getStackHook","when","readyException","readyWait","doScroll","uid","access","hasData","removeData","_data","_removeData","dequeue","_queueHooks","clearQueue","composed","getRootNode","display","css","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","global","handle","triggered","dispatch","bindType","origType","delegateCount","teardown","removeEvent","fix","delegateTarget","preDispatch","isPropagationStopped","currentTarget","isImmediatePropagationStopped","rnamespace","handleObj","postDispatch","addProp","originalEvent","load","noBubble","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","_evalUrl","Oe","cleanData","append","after","replaceWith","replaceChild","appendTo","prependTo","replaceAll","Pe","He","Ie","opener","getComputedStyle","Re","Be","Me","We","Fe","getPropertyValue","pixelBoxStyles","$e","cssText","marginLeft","offsetWidth","backgroundClip","clearCloneStyle","boxSizingReliable","pixelPosition","reliableMarginLeft","scrollboxSize","reliableTrDimensions","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","isFinite","getBoundingClientRect","margin","padding","border","expand","fx","speeds","checkOn","optSelected","radioValue","tt","nt","removeAttr","attrHooks","rt","it","ot","at","st","removeProp","propFix","propHooks","addClass","removeClass","toggleClass","hasClass","ut","valHooks","focusin","ct","parentWindow","simulate","triggerHandler","parseXML","ft","dt","ht","vt","param","encodeURIComponent","serializeArray","wrapAll","firstElementChild","wrapInner","visible","createHTMLDocument","implementation","setOffset","using","pageYOffset","pageXOffset","offsetParent","scrollLeft","scrollTop","scrollTo","Height","Width","unbind","delegate","undelegate","hover","yt","proxy","holdReady","parseJSON","isFunction","isWindow","camelCase","isNumeric","mt","jQuery","bt","noConflict","WINDOW","JS_MD5_NO_WINDOW","WEB_WORKER","NODE_JS","JS_MD5_NO_NODE_JS","COMMON_JS","JS_MD5_NO_COMMON_JS","AMD","ARRAY_BUFFER","JS_MD5_NO_ARRAY_BUFFER","HEX_CHARS","EXTRA","SHIFT","OUTPUT_TYPES","BASE64_ENCODE_CHAR","blocks","buffer8","Uint32Array","JS_MD5_NO_ARRAY_BUFFER_IS_VIEW","isView","createOutputMethod","outputType","Md5","update","createMethod","nodeWrap","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","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","initAccum","isHostObject","mapToArray","overArg","setToArray","arrayProto","funcProto","objectProto","coreJsData","maskSrcKey","IE_PROTO","funcToString","objectToString","reIsNative","getPrototype","objectCreate","propertyIsEnumerable","nativeGetSymbols","nativeIsBuffer","isBuffer","nativeKeys","DataView","getNative","WeakMap","nativeCreate","dataViewCtorString","toSource","mapCtorString","promiseCtorString","setCtorString","weakMapCtorString","symbolProto","symbolValueOf","valueOf","Hash","entry","ListCache","MapCache","Stack","__data__","assignValue","object","objValue","assocIndexOf","baseClone","isDeep","isFull","customizer","isArr","initCloneArray","copyArray","getTag","isFunc","cloneBuffer","isPrototype","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","getMapData","getValue","baseIsNative","pairs","LARGE_ARRAY_SIZE","isIndex","other","ctorString","isLength","inherited","isObjectLike","isArrayLikeObject","isArguments","baseTimes","skipIndexes","arrayLikeKeys","baseKeys","reTrim","reIsBadHex","reIsBinary","reIsOctal","freeParseInt","nativeMax","nativeMin","toNumber","isSymbol","isBinary","wait","lastArgs","lastThis","maxWait","timerId","lastCallTime","lastInvokeTime","leading","maxing","trailing","invokeFunc","thisArg","leadingEdge","timerExpired","shouldInvoke","timeSinceLastCall","trailingEdge","remainingWait","debounced","isInvoking","arrayTag","errorTag","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","localCName","generateIdentifier","splitLines","splitSections","part","getDescription","getMediaSections","matchPrefix","parseCandidate","relatedAddress","relatedPort","tcpType","writeCandidate","parseIceOptions","parseRtpMap","parsed","clockRate","numChannels","writeRtpMap","preferredPayloadType","writeExtmap","headerExtension","preferredId","kv","writeFmtp","parseRtcpFb","writeRtcpFb","rtcpFeedback","parseSsrcMedia","sp","colon","parseSsrcGroup","getMid","algorithm","getDtlsParameters","fingerprints","writeDtlsParameters","setupType","fp","parseCryptoLine","cryptoSuite","keyParams","sessionParams","writeCryptoLine","writeCryptoKeyParams","parseCryptoKeyParams","keyMethod","keySalt","lifeTime","mkiValue","mkiLength","getCryptoParameters","getIceParameters","writeIceParameters","iceLite","parseRtpParameters","headerExtensions","fecMechanisms","rtcp","rtpmapline","fmtps","writeRtpDescription","maxptime","extension","parseRtpEncodingParameters","encodingParameters","hasRed","hasUlpfec","flows","apt","encParam","codecPayloadType","fec","mechanism","parseRtcpParameters","rtcpParameters","remoteSsrc","rsize","reducedSize","compound","mux","writeRtcpParameters","parseMsid","spec","planB","msidParts","parseSctpDescription","maxSizeLine","sctpPort","sctpMapLines","writeSctpDescription","generateSessionId","writeSessionBoilerplate","sessId","sessVer","sessUser","getDirection","getKind","isRejected","parseOLine","netType","addressType","isValidSDP","global$1","_typeof","_toConsumableArray","arr2","_arrayWithoutHoles","iter","_iterableToArray","_nonIterableSpread","safe_add","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","core_sha1","olde","rol","safe_add$1","sha1_ft","sha1_kt","core_hmac_sha1","bkey","str2binb","ipad","opad","binb2b64","triplet","binb2str","SHA1","b64_hmac_sha1","str_hmac_sha1","str_sha1","out","cookies","cookieName","expires","path","cookieObj","cookieValue","unescape","cookie","Builder","VERSION","NS","HTTPBIND","BOSH","CLIENT","AUTH","ROSTER","PROFILE","DISCO_INFO","DISCO_ITEMS","MUC","SASL","FRAMING","BIND","SESSION","STANZAS","XHTML_IM","XHTML","validTag","validAttribute","validCSS","CONNECTING","CONNFAIL","AUTHENTICATING","AUTHFAIL","DISCONNECTED","DISCONNECTING","ATTACHED","REDIRECT","CONNTIMEOUT","BINDREQUIRED","ErrorCondition","BAD_FORMAT","CONFLICT","MISSING_JID_NODE","NO_AUTH_MECH","UNKNOWN_REASON","LogLevel","FATAL","ElementType","NORMAL","TEXT","CDATA","FRAGMENT","SECONDARY_TIMEOUT","addNamespace","forEachChild","elemName","childNode","isTagEqual","_xmlGenerator","_makeGenerator","doc","createDocument","documentMode","_getIEXmlDom","xmlGenerator","docStrings","ActiveXObject","xmlTextNode","xmlescape","xmlunescape","xmlHtmlNode","loadXML","copyElement","_i","createHtml","cssAttrs","cssName","cssValue","_i2","_i3","_i4","escapeNode","unescapeNode","getNodeFromJid","getDomainFromJid","bare","getBareJidFromJid","getResourceFromJid","_handleError","fatal","sourceURL","fileName","lineNumber","getNamedItem","_requestId","_connectionPlugins","ptype","moreattrs","impNode","xmlGen","importNode","newElem","fragment","xhtml","Handler","ns","matchBare","matchBareFromJid","getNamespace","elNamespace","ignoreNamespaceFragment","namespaceMatch","_this","nsMatch","isMatch","elem_type","run","TimedHandler","period","lastCalled","Connection","_this2","Websocket","Bosh","_sasl_data","do_session","do_bind","timedHandlers","removeTimeds","removeHandlers","addTimeds","addHandlers","protocolErrorHandlers","_idleTimeout","_disconnectTimeout","authenticated","do_authentication","restored","_uniqueId","_sasl_success_handler","_sasl_failure_handler","_sasl_challenge_handler","_onIdle","registerSASLMechanisms","mechanisms","_reset","_requests","getUniqueId","suffix","addProtocolErrorHandler","status_code","hold","route","authcid","authzid","servtype","connect_callback","wind","_attach","restore","_sessionCachingSupported","_restore","sessionStorage","xmlInput","xmlOutput","nextValidRid","_queueData","_this3","timeoutHandler","deleteTimedHandler","addTimedHandler","_this4","iqtype","_sendRestart","_this5","thand","handRef","hand","SASLAnonymous","SASLExternal","SASLMD5","SASLOAuthBearer","SASLXOAuth2","SASLPlain","SASLSHA1","registerSASLMechanism","_addSysTimedHandler","_onDisconnectTimeout","_disconnect","condition","statusChanged","_dataRecv","_this6","_reqToData","strip","_emptyQueue","cond","conflict","UNKOWN_REASON","_i5","_hand","_connect_cb","_callback","bodyWrap","mech","_no_auth_received","sortMechanismsByPriority","higher","swap","_attemptSASLAuth","_attemptLegacyAuth","mechanism_found","_sasl_success_cb","_sasl_failure_cb","_sasl_challenge_cb","_sasl_mechanism","onStart","request_auth_exchange","isClientFirst","onChallenge","btoa","challenge","atob","_onLegacyAuthIQResult","_auth2_cb","_this7","serverSignature","streamfeature_handlers","_onStreamFeaturesAfterSASL","explicitResourceBinding","_onResourceBindResultIQ","jidNode","_establishSession","_onSessionResultIQ","_this8","_i6","_thand","SASLMechanism","auth_str","test_cnonce","cnonce","Hi","U_old","authMessage","attribMatch","clientKey","serverKey","clientSignature","_quote","realm","host","digest_uri","cred","A1","A2","core","Strophe$1","$build$1","Request","sends","xmlData","origFunc","date","NaN","abort","dead","age","timeDead","xhr","_newXHR","getResponse","responseXML","overrideMimeType","_conn","inactivity","keepalive","_cacheSession","_onRequestStateChange","_throttledRequestHandler","typ","_sendTerminate","_callProtocolErrorHandlers","reqStatus","_getRequestStatus","err_callback","HTTP","_hitError","time_elapsed","def","getAllResponseHeaders","valid_request","too_many_retries","_removeRequest","reqIs0","_restartRequest","_processRequest","primary_timeout","secondary_timeout","server_error","content_type","contentType","withCredentials","e2","sendFunc","customHeaders","backoff","Strophe$2","$build$2","new_service","pathname","_buildStream","_check_streamerror","connectstatus","errorString","_onOpen","_connect_cb_wrapper","_handleStreamStart","streamStart","parsedMessage","see_uri","_streamWrap","CLOSED","closeString","rawStanza","startString","_items","conn","_onDiscoInfo","_onDiscoItems","addIdentity","var_name","addItem","call_back","_buildIQResult","query_attrs","iqresult","autoSendCountOnEveryIncomingStanza","requestResponseInterval","_c","_NS","_isStreamManagementEnabled","_serverProcesssedStanzasCounter","_clientProcessedStanzasCounter","_clientSentStanzasCounter","_originalXMLOutput","_requestHandler","_incomingHandler","_requestResponseIntervalCount","_isSupported","_unacknowledgedStanzas","_acknowledgedStanzaListeners","addAcknowledgedStanzaListener","_connectionStatus","_resumeToken","_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","rnds8","msCrypto","ROTL","_rng","_bytesToUuid","_nodeId","_clockseq","_lastMSecs","_lastNSecs","clockseq","seedBytes","rng","msecs","nsecs","tl","tmh","_md","hashfunc","generateUUID","stringToBytes","uuidToBytes","DNS","rnds","_sha","CAMERA","DESKTOP_HIGH_FPS","NONE","ENVIRONMENT","USER","AV1","CREATE_ANSWER_FAILED","CREATE_OFFER_FAILED","DATA_CHANNEL_OPEN","ENDPOINT_CONN_STATUS_CHANGED","SENDER_VIDEO_CONSTRAINTS_CHANGED","LASTN_VALUE_CHANGED","LOCAL_TRACK_SSRC_UPDATED","TRACK_ATTACHED","REMOTE_TRACK_ADDED","REMOTE_TRACK_REMOVED","SET_LOCAL_DESCRIPTION_FAILED","SET_REMOTE_DESCRIPTION_FAILED","AUDIO_OUTPUT_DEVICE_CHANGED","DEVICE_LIST_WILL_CHANGE","DEVICE_LIST_AVAILABLE","LOCAL_UFRAG_CHANGED","REMOTE_UFRAG_CHANGED","VIDEO_SSRCS_REMAPPED","AUDIO_SSRCS_REMAPPED","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","loaded","__webpack_modules__","amdO","getter","definition","globalThis","nmd","paths","__webpack_exports__"],"sourceRoot":""}