/** @file automatically generated, do not edit it. */
(() => { // webpackBootstrap
	const __webpack_modules__ = {

3:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  Fj: () => EXPANDED_FLAG,
  g: () => MODE,
  ZE: () => TYPE,
  gR: () => VIEW,
  Ay: () => Call,
  dQ: () => inProgressAlert,
  P: () => isGuest
});

// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
const esm_extends = REQ_(168);
// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
// EXTERNAL MODULE: ./js/chat/ui/meetings/stream.jsx + 7 modules
const stream = REQ_(415);
// EXTERNAL MODULE: ./js/chat/ui/composedTextArea.jsx + 1 modules
const composedTextArea = REQ_(77);
// EXTERNAL MODULE: ./js/chat/ui/historyPanel.jsx + 7 modules
const historyPanel = REQ_(814);
// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
const ui_contacts = REQ_(251);
// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
const perfectScrollbar = REQ_(486);
;// ./js/chat/ui/meetings/collapse.jsx

class Collapse extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.state = {
      expanded: true
    };
  }
  render() {
    const {
      expanded
    } = this.state;
    const {
      heading,
      badge,
      children
    } = this.props;
    return REaCt().createElement("div", {
      className: "collapse"
    }, heading && REaCt().createElement("div", {
      className: "collapse-head",
      onClick: () => this.setState(state => ({
        expanded: !state.expanded
      }))
    }, REaCt().createElement("i", {
      className: `
                                sprite-fm-mono
                                ${expanded ? 'icon-arrow-down' : 'icon-arrow-up'}
                            `
    }), REaCt().createElement("h5", null, heading), badge !== undefined && badge > 0 && REaCt().createElement("span", {
      className: "participants-count"
    }, badge)), expanded && children);
  }
}
// EXTERNAL MODULE: ./js/ui/utils.jsx
const utils = REQ_(314);
// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
const meetings_button = REQ_(959);
// EXTERNAL MODULE: ./js/chat/ui/contactsPanel/contactsPanel.jsx + 20 modules
const contactsPanel = REQ_(173);
// EXTERNAL MODULE: ./js/chat/ui/meetings/videoNodeMenu.jsx
const videoNodeMenu = REQ_(539);
// EXTERNAL MODULE: ./js/chat/ui/meetings/videoNode.jsx
const videoNode = REQ_(414);
;// ./js/chat/ui/meetings/participants.jsx












class Participant extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.raisedHandListener = undefined;
    this.baseIconClass = 'sprite-fm-mono';
    this.state = {
      raisedHandPeers: []
    };
    this.state.raisedHandPeers = this.props.raisedHandPeers || [];
  }
  componentDidMount() {
    super.componentDidMount();
    this.props.source.registerConsumer(this);
    this.raisedHandListener = mBroadcaster.addListener('meetings:raisedHand', raisedHandPeers => this.setState({
      raisedHandPeers
    }, () => this.safeForceUpdate()));
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    this.props.source.deregisterConsumer(this);
    mBroadcaster.removeListener(this.raisedHandListener);
  }
  onAvChange() {
    this.safeForceUpdate();
  }
  render() {
    const {
      call,
      mode,
      chatRoom,
      source,
      contact,
      handle,
      name,
      recorderCid,
      onCallMinimize,
      onSpeakerChange,
      onModeChange
    } = this.props;
    const {
      isOnHold,
      videoMuted,
      audioMuted,
      clientId
    } = source;
    const hasRelationship = contactsPanel.A.hasRelationship(contact);
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "participant-wrapper"
    }, this.state.raisedHandPeers.includes(handle) && !isOnHold ? REaCt().createElement("div", {
      className: "participant-signifier"
    }, REaCt().createElement("i", {
      className: "sprite-fm-uni icon-raise-hand"
    })) : REaCt().createElement(ui_contacts.Avatar, {
      contact: M.u[handle]
    }), REaCt().createElement("div", {
      className: "name"
    }, handle === u_handle ? REaCt().createElement(utils.zT, null, `${name} ${l.me}`) : REaCt().createElement(ui_contacts.ContactAwareName, {
      contact: M.u[handle],
      emoji: true
    }), Call.isModerator(chatRoom, handle) && REaCt().createElement("span", null, REaCt().createElement("i", {
      className: `${this.baseIconClass} icon-admin-outline`
    }))), REaCt().createElement("div", {
      className: "status"
    }, recorderCid === clientId || recorderCid === call.sfuClient.cid && handle === u_handle ? REaCt().createElement("div", {
      className: "recording-status"
    }, REaCt().createElement("span", null)) : null, REaCt().createElement("i", {
      className: `
                            ${this.baseIconClass}
                            ${videoMuted ? 'icon-video-off-thin-outline inactive' : 'icon-video-thin-outline'}
                        `
    }), REaCt().createElement(videoNode.Gz, {
      source
    }), REaCt().createElement("div", {
      className: "participants-menu theme-dark-forced"
    }, REaCt().createElement("div", {
      className: "participants-menu-toggle"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-side-menu"
    })), REaCt().createElement("div", {
      className: "participants-menu-content"
    }, REaCt().createElement("ul", null, hasRelationship ? REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
      icon: "sprite-fm-mono icon-info",
      onClick: () => {
        onCallMinimize();
        loadSubPage(`fm/chat/contacts/${handle}`);
      }
    }, REaCt().createElement("span", null, l[6859]))) : null, chatRoom.iAmOperator() && u_handle !== handle && !audioMuted && REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
      icon: "sprite-fm-mono icon-mic-off-thin-outline",
      onClick: () => {
        call.sfuClient.mutePeer(clientId);
        megaChat.plugins.userHelper.getUserNickname(handle).catch(dump).always(name => {
          ChatToast.quick(l.you_muted_peer.replace('%NAME', name || ''));
        });
      }
    }, REaCt().createElement("span", null, l[16214]))), hasRelationship ? REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
      icon: "sprite-fm-mono icon-chat",
      onClick: () => {
        onCallMinimize();
        loadSubPage(`fm/chat/p/${handle}`);
      }
    }, REaCt().createElement("span", null, l.send_message))) : null, chatRoom.iAmOperator() && u_handle !== handle && REaCt().createElement("li", null, REaCt().createElement(videoNodeMenu.EH, {
      stream: source,
      chatRoom
    })), REaCt().createElement("li", null, REaCt().createElement(videoNodeMenu.yU, {
      mode,
      stream: source,
      onSpeakerChange,
      onModeChange
    })), call.isPublic && chatRoom.iAmOperator() && u_handle !== handle && REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
      icon: "sprite-fm-mono icon-disabled-filled",
      onClick: () => chatRoom.trigger('onRemoveUserRequest', handle)
    }, REaCt().createElement("span", null, l[8867]))))))));
  }
}
class Participants extends mixins.w9 {
  get allPeersMuted() {
    return Object.values(this.props.peers).filter(p => p instanceof CallManager2.Peer).every(p => p.audioMuted);
  }
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.muteRef = REaCt().createRef();
    this.NAMESPACE = 'participants';
    this.FILTER = {
      IN_CALL: 0,
      CHAT_PARTICIPANTS: 1
    };
    this.state = {
      filter: this.FILTER.IN_CALL,
      noResponsePeers: [],
      ringingPeers: [],
      allPeersMuted: undefined
    };
    this.doHangUp = handle => {
      if (handle) {
        const {
          call,
          chatRoom
        } = this.props;
        return this.isMounted() && this.setState(state => ({
          ringingPeers: state.ringingPeers.filter(p => p !== handle)
        }), () => chatRoom.ringUser(handle, call.callId, 0));
      }
    };
    this.doCall = handle => {
      if (handle) {
        const {
          call,
          chatRoom
        } = this.props;
        this.setState(state => ({
          ringingPeers: [...state.ringingPeers, handle]
        }), () => {
          chatRoom.ringUser(handle, call.callId, 1);
          if (chatRoom.options.w) {
            let _call$sfuClient;
            call == null || (_call$sfuClient = call.sfuClient) == null || _call$sfuClient.wrAllowJoin([handle]);
          }
          tSleep(40).then(() => {
            this.doHangUp(handle);
            return Object.keys(chatRoom.uniqueCallParts).includes(handle) ? null : this.setState(state => ({
              noResponsePeers: [...state.noResponsePeers, handle]
            }));
          });
        });
      }
    };
    this.getCallState = handle => {
      const {
        noResponsePeers,
        ringingPeers
      } = this.state;
      if (this.props.initialCallRinging || ringingPeers.includes(handle)) {
        return l.call_state_calling;
      }
      if (noResponsePeers.includes(handle)) {
        return l.call_state_no_response;
      }
      return l.call_state_not_in_call;
    };
    this.getCallParticipants = () => {
      const {
        call,
        mode,
        chatRoom,
        recorderCid,
        raisedHandPeers,
        onCallMinimize,
        onSpeakerChange,
        onModeChange
      } = this.props;
      const peers = Object.values(this.props.peers);
      const $$PEER = peer => peer && REaCt().createElement("li", {
        key: `${peer.clientId || ''}-${peer.userHandle}`
      }, REaCt().createElement(Participant, {
        call,
        mode,
        chatRoom,
        source: peer.userHandle ? peer : call.getLocalStream(),
        contact: M.u[peer.userHandle] || undefined,
        handle: peer.userHandle || u_handle,
        name: peer.name || M.getNameByHandle(u_handle),
        recorderCid,
        raisedHandPeers,
        onCallMinimize,
        onSpeakerChange,
        onModeChange
      }));
      let $$RAISED = [];
      for (const userHandle of call.sfuClient.raisedHands) {
        const peer = peers.find(p => (p.userHandle || p.localPeerStream.userHandle) === userHandle);
        $$RAISED = [...$$RAISED, $$PEER(peer)];
      }
      const $$REST = peers.filter(p => ![...call.sfuClient.raisedHands].includes(p.userHandle || p.localPeerStream.userHandle)).sort((a, b) => !!a.userHandle - !!b.userHandle).map(peer => $$PEER(peer));
      return REaCt().createElement("ul", null, $$RAISED, $$REST);
    };
    this.getChatParticipants = () => {
      const {
        chatRoom,
        initialCallRinging
      } = this.props;
      const {
        ringingPeers
      } = this.state;
      const callParticipants = Object.keys(chatRoom.uniqueCallParts);
      const chatParticipants = chatRoom.getParticipantsExceptMe().filter(h => !callParticipants.includes(h));
      if (chatParticipants != null && chatParticipants.length) {
        return REaCt().createElement(REaCt().Fragment, null, chatParticipants.length > 1 ? (() => {
          const isRingingAll = initialCallRinging || JSON.stringify(ringingPeers) === JSON.stringify(chatParticipants);
          return REaCt().createElement(meetings_button.A, {
            className: `
                                        mega-button
                                        action
                                        neutral
                                        call-control-all
                                        ${isRingingAll ? 'disabled' : ''}
                                    `,
            icon: "sprite-fm-mono phone-call-01",
            onClick: () => isRingingAll ? null : chatParticipants.map(handle => this.doCall(handle))
          }, l.call_all_button);
        })() : null, REaCt().createElement("ul", null, chatParticipants.map(handle => {
          const contact = M.u[handle];
          const isRinging = initialCallRinging || ringingPeers.includes(handle);
          return REaCt().createElement("li", {
            key: handle
          }, REaCt().createElement(ui_contacts.Avatar, {
            contact
          }), REaCt().createElement("div", {
            className: "name"
          }, REaCt().createElement(ui_contacts.ContactAwareName, {
            contact: M.u[handle],
            emoji: true
          }), REaCt().createElement("span", {
            className: `
                                            user-card-presence
                                            ${megaChat.userPresenceToCssClass(contact.presence)}
                                        `
          }), Call.isModerator(chatRoom, handle) && REaCt().createElement("span", null, REaCt().createElement("i", {
            className: "sprite-fm-mono icon-admin-outline"
          })), REaCt().createElement("div", {
            className: "call-state"
          }, this.getCallState(handle))), isRinging ? null : REaCt().createElement("div", {
            className: "call-control"
          }, REaCt().createElement(meetings_button.A, {
            className: "mega-button action neutral",
            onClick: () => this.doCall(handle)
          }, l.call_button)));
        })));
      }
      return REaCt().createElement("div", {
        className: "participants-empty"
      }, REaCt().createElement("span", {
        className: "empty-check-icon"
      }), REaCt().createElement("h3", null, l.all_participants_in_call));
    };
    this.renderParticipantsList = () => {
      const {
        filter,
        raisedHandPeers
      } = this.state;
      return REaCt().createElement("div", {
        className: `
                    participants-list
                    ${filter === this.FILTER.IN_CALL ? '' : 'with-chat-participants'}
                    ${this.props.guest ? 'guest' : ''}
                `
      }, REaCt().createElement(perfectScrollbar.O, {
        filter,
        raisedHandPeers,
        options: {
          'suppressScrollX': true
        }
      }, filter === this.FILTER.IN_CALL ? this.getCallParticipants() : this.getChatParticipants()));
    };
    this.renderMuteAllControl = () => {
      const {
        allPeersMuted
      } = this.state;
      const simpletip = {
        label: l.mute_all_tooltip,
        position: 'top',
        className: 'theme-dark-forced'
      };
      return REaCt().createElement(meetings_button.A, {
        ref: this.muteRef,
        simpletip: allPeersMuted ? null : simpletip,
        className: `
                    mega-button
                    action
                    ${this.NAMESPACE}-mute
                    ${allPeersMuted ? 'disabled' : ''}
                `,
        icon: "sprite-fm-mono icon-mic-off-thin-outline",
        onClick: () => {
          let _this$muteRef, _muteRef$buttonRef;
          const muteRef = (_this$muteRef = this.muteRef) == null ? void 0 : _this$muteRef.current;
          const buttonRef = (_muteRef$buttonRef = muteRef.buttonRef) == null ? void 0 : _muteRef$buttonRef.current;
          return allPeersMuted ? null : this.setState({
            allPeersMuted: true
          }, () => {
            this.props.call.sfuClient.mutePeer();
            ChatToast.quick(l.you_muted_all_peers);
            if (buttonRef) {
              $(buttonRef).trigger('simpletipClose');
            }
          });
        }
      }, allPeersMuted ? l.all_muted : l.mute_all);
    };
    this.state.allPeersMuted = this.allPeersMuted;
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    ['onCallPeerJoined', 'onPeerAvChange'].map(event => this.props.chatRoom.off(`${event}.${this.NAMESPACE}`));
  }
  componentDidMount() {
    super.componentDidMount();
    this.props.chatRoom.rebind(`onCallPeerJoined.${this.NAMESPACE}`, (ev, userHandle) => {
      const {
        noResponsePeers,
        ringingPeers
      } = this.state;
      this.setState({
        noResponsePeers: noResponsePeers.includes(userHandle) ? noResponsePeers.filter(h => h !== userHandle) : noResponsePeers,
        ringingPeers: ringingPeers.includes(userHandle) ? ringingPeers.filter(h => h !== userHandle) : ringingPeers
      });
    }).rebind(`onPeerAvChange.${this.NAMESPACE}`, () => this.isMounted() && this.setState({
      allPeersMuted: this.allPeersMuted
    }));
  }
  render() {
    const {
      IN_CALL,
      CHAT_PARTICIPANTS
    } = this.FILTER;
    const {
      withInvite,
      chatRoom,
      peers,
      onInviteToggle
    } = this.props;
    const {
      filter
    } = this.state;
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: this.NAMESPACE
    }, chatRoom.type === 'private' ? null : REaCt().createElement("div", {
      className: `${this.NAMESPACE}-nav`
    }, REaCt().createElement(meetings_button.A, {
      className: filter === IN_CALL ? 'active' : '',
      onClick: () => this.setState({
        filter: IN_CALL
      })
    }, l.call_heading_in_call), REaCt().createElement(meetings_button.A, {
      className: filter === CHAT_PARTICIPANTS ? 'active' : '',
      onClick: () => this.setState({
        filter: CHAT_PARTICIPANTS
      })
    }, l.call_heading_not_in_call)), filter === IN_CALL ? REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
      className: `${this.NAMESPACE}-actions`
    }, withInvite && REaCt().createElement(meetings_button.A, {
      className: `
                                        mega-button
                                        action
                                        ${this.NAMESPACE}-invite
                                    `,
      icon: "sprite-fm-mono icon-user-plus-thin-outline",
      onClick: onInviteToggle
    }, l[8726]), chatRoom.iAmOperator() && this.renderMuteAllControl()), REaCt().createElement(Collapse, (0,esm_extends.A)({}, this.props, {
      filter,
      heading: l[16217],
      badge: (peers == null ? void 0 : peers.length) + 1
    }), this.renderParticipantsList())) : this.renderParticipantsList());
  }
}
;// ./js/chat/ui/meetings/guest.jsx


class Guest extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.state = {
      copy: ''
    };
  }
  componentDidMount() {
    this.setState({
      copy: `${l.free_storage_info__call.replace('%s', bytesToSize(mega.bstrg, 0))}`
    });
  }
  render() {
    const {
      copy
    } = this.state;
    return REaCt().createElement("div", {
      className: "guest-register"
    }, REaCt().createElement("div", {
      className: "guest-register-content"
    }, REaCt().createElement(meetings_button.A, {
      className: "close-guest-register",
      icon: "icon-close-component",
      onClick: this.props.onGuestClose
    }, REaCt().createElement("span", null, l[148])), REaCt().createElement("div", null, REaCt().createElement("i", {
      className: "sprite-fm-illustration-wide registration"
    }), REaCt().createElement("span", null, copy)), REaCt().createElement(meetings_button.A, {
      className: "mega-button positive register-button",
      onClick: () => loadSubPage('register')
    }, l.sign_up_btn)));
  }
}
;// ./js/chat/ui/meetings/sidebar.jsx








const inviteAllowed = chatRoom => {
  if (chatRoom) {
    return chatRoom.type !== 'private' && !!(chatRoom.options[MCO_FLAGS.OPEN_INVITE] || Call.isModerator(chatRoom, u_handle) || chatRoom.publicLink);
  }
  return false;
};
class Sidebar extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.historyPanel = null;
    this.renderHead = ({
      title,
      children
    }) => {
      return REaCt().createElement("div", {
        className: "sidebar-head"
      }, REaCt().createElement(meetings_button.A, {
        simpletip: {
          label: l.close_sidebar,
          className: 'theme-dark-forced'
        },
        className: "mega-button action small left",
        icon: "icon-collapse-right",
        onClick: this.props.onSidebarClose
      }, REaCt().createElement("span", null, l.close_sidebar)), REaCt().createElement("h2", null, title), children || null);
    };
    this.renderParticipantsView = () => {
      const {
        call,
        mode,
        peers,
        initialCallRinging,
        chatRoom,
        guest,
        recorderCid,
        raisedHandPeers,
        onInviteToggle,
        onCallMinimize,
        onSpeakerChange,
        onModeChange
      } = this.props;
      const withInvite = inviteAllowed(chatRoom);
      return REaCt().createElement(REaCt().Fragment, null, this.renderHead({
        title: l[16217]
      }), REaCt().createElement(Participants, {
        withInvite,
        call,
        mode,
        peers,
        initialCallRinging,
        chatRoom,
        guest,
        recorderCid,
        raisedHandPeers,
        onInviteToggle,
        onCallMinimize,
        onSpeakerChange,
        onModeChange
      }));
    };
    this.renderChatView = () => {
      const {
        chatRoom,
        typingAreaText,
        onDeleteMessage,
        onTypingAreaChanged
      } = this.props;
      return REaCt().createElement(REaCt().Fragment, null, this.renderHead({
        title: l.chats
      }), REaCt().createElement(historyPanel.A, {
        ref: ref => {
          this.historyPanel = ref;
        },
        chatRoom,
        className: "in-call",
        onDeleteClicked: onDeleteMessage
      }), REaCt().createElement(composedTextArea.A, {
        chatRoom,
        parent: this,
        containerRef: this.domRef,
        typingAreaText,
        onTypingAreaChanged
      }));
    };
  }
  render() {
    const {
      view,
      guest,
      onGuestClose
    } = this.props;
    return REaCt().createElement("div", {
      className: "sidebar-wrapper theme-dark-forced"
    }, REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                        sidebar
                        ${view === VIEW.CHAT ? 'chat-opened' : 'theme-dark-forced'}
                    `
    }, view === VIEW.PARTICIPANTS && this.renderParticipantsView(), view === VIEW.CHAT && this.renderChatView(), guest && view !== VIEW.CHAT && REaCt().createElement(Guest, {
      onGuestClose
    })));
  }
}
// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
const modalDialogs = REQ_(318);
;// ./js/chat/ui/meetings/workflow/invite/search.jsx
let _Search;


class Search extends REaCt().Component {
  render() {
    const {
      value,
      placeholder,
      onChange
    } = this.props;
    return REaCt().createElement("div", {
      className: `${Invite.NAMESPACE}-field`
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-preview-reveal"
    }), REaCt().createElement("input", {
      type: "text",
      autoFocus: true,
      placeholder: l[23750].replace('[X]', placeholder),
      ref: Search.inputRef,
      value,
      onChange
    }));
  }
}
_Search = Search;
Search.inputRef = REaCt().createRef();
Search.focus = () => {
  return _Search.inputRef && _Search.inputRef.current && _Search.inputRef.current.focus();
};
;// ./js/chat/ui/meetings/workflow/invite/footer.jsx


const Footer = ({
  selected,
  onClose,
  onAdd
}) => {
  return REaCt().createElement("footer", null, REaCt().createElement("div", {
    className: "footer-container"
  }, REaCt().createElement(meetings_button.A, {
    className: "mega-button",
    onClick: onClose
  }, l.msg_dlg_cancel), REaCt().createElement(meetings_button.A, {
    className: `
                        mega-button
                        positive
                        ${selected.length > 0 ? '' : 'disabled'}
                    `,
    onClick: onAdd
  }, l.add)));
};
const footer = Footer;
;// ./js/chat/ui/meetings/workflow/invite/nil.jsx


const Nil = () => {
  return REaCt().createElement("div", {
    className: `${Invite.NAMESPACE}-nil`
  }, REaCt().createElement("div", {
    className: "fm-empty-contacts-bg"
  }), REaCt().createElement("h2", null, HAS_CONTACTS() ? l[8674] : l[784]));
};
const nil = Nil;
// EXTERNAL MODULE: ./js/chat/ui/link.jsx
const ui_link = REQ_(280);
;// ./js/chat/ui/meetings/workflow/invite/invite.jsx











const HAS_CONTACTS = () => {
  const keys = M.u.keys();
  for (let i = 0; i < keys.length; i++) {
    if (M.u[keys[i]].c === 1) {
      return true;
    }
  }
};
class Invite extends REaCt().Component {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.wrapperRef = REaCt().createRef();
    this.state = {
      loading: true,
      value: '',
      searching: false,
      contacts: [],
      contactsInitial: [],
      frequents: [],
      frequentsInitial: [],
      selected: [],
      excluded: [],
      input: false
    };
    this.getSortedContactsList = (frequents, excluded) => {
      frequents = frequents || this.state.frequents;
      excluded = excluded || this.state.excluded;
      const filteredContacts = [];
      (this.props.contacts || M.u).forEach(contact => {
        if (contact.c === 1 && !frequents.includes(contact.u) && !excluded.includes(contact.u)) {
          filteredContacts.push(contact);
        }
      });
      const sortFn = M.getSortByNameFn2(1);
      filteredContacts.sort((a, b) => sortFn(a, b));
      return filteredContacts;
    };
    this.doMatch = (value, collection) => {
      value = value.toLowerCase();
      return collection.filter(contact => {
        contact = typeof contact === 'string' ? M.getUserByHandle(contact) : contact;
        const name = M.getNameByHandle(contact.u || contact).toLowerCase();
        const email = contact.m && contact.m.toLowerCase();
        return name.includes(value) || email.includes(value);
      });
    };
    this.handleSearch = ev => {
      const {
        value
      } = ev.target;
      const searching = value.length >= 2;
      const frequents = searching ? this.doMatch(value, this.state.frequentsInitial) : this.state.frequentsInitial;
      const contacts = searching ? this.doMatch(value, this.state.contactsInitial) : this.state.contactsInitial;
      this.setState({
        value,
        searching,
        frequents,
        contacts
      }, () => {
        const wrapperRef = this.wrapperRef && this.wrapperRef.current;
        if (wrapperRef && searching) {
          wrapperRef.reinitialise();
          wrapperRef.scrollToY(0);
        }
      });
    };
    this.handleSelect = userHandle => {
      this.setState(state => ({
        selected: state.selected.includes(userHandle) ? state.selected.filter(c => c !== userHandle) : [...state.selected, userHandle]
      }), () => Search.focus());
    };
    this.handleAdd = () => {
      const {
        selected
      } = this.state;
      const {
        call,
        chatRoom,
        onClose
      } = this.props;
      if (selected.length > 0) {
        if (chatRoom.options.w) {
          let _call$sfuClient;
          call == null || (_call$sfuClient = call.sfuClient) == null || _call$sfuClient.wrAllowJoin(selected);
        }
        chatRoom == null || chatRoom.trigger('onAddUserRequest', [selected]);
        onClose == null || onClose();
      }
    };
    this.getFrequentContacts = () => megaChat.getFrequentContacts().then(response => {
      if (!this.domRef.current) {
        return;
      }
      const frequents = [];
      const maxFreq = Math.max(response.length - ui_contacts.MAX_FREQUENTS, 0);
      for (let i = response.length - 1; i >= maxFreq; i--) {
        const contact = response[i];
        if (!this.state.excluded.includes(contact.userId)) {
          frequents.push(contact.userId);
        }
      }
      this.setState({
        frequents,
        frequentsInitial: frequents,
        contacts: this.getSortedContactsList(frequents),
        loading: false
      });
    });
    this.getFilteredFrequents = () => {
      const {
        frequents,
        selected
      } = this.state;
      if (frequents.length === 0) {
        return false;
      }
      return frequents.map(userHandle => {
        return REaCt().createElement(ui_contacts.ContactCard, {
          key: userHandle,
          contact: M.u[userHandle],
          chatRoom: false,
          className: `
                        contacts-search
                        short
                        ${selected.includes(userHandle) ? 'selected' : ''}
                    `,
          noContextButton: true,
          noContextMenu: true,
          selectable: true,
          onClick: () => this.handleSelect(userHandle)
        });
      });
    };
    this.getFilteredContacts = () => {
      const {
        contacts,
        frequents,
        excluded,
        selected
      } = this.state;
      const $$CONTACTS = [];
      for (let i = 0; i < contacts.length; i++) {
        const contact = contacts[i];
        const {
          u: userHandle
        } = contact;
        if (!frequents.includes(userHandle) && !excluded.includes(userHandle)) {
          $$CONTACTS.push(REaCt().createElement(ui_contacts.ContactCard, {
            key: userHandle,
            contact,
            chatRoom: false,
            className: `
                            contacts-search
                            short
                            ${selected.includes(userHandle) ? 'selected' : ''}
                        `,
            noContextButton: true,
            noContextMenu: true,
            selectable: true,
            onClick: () => this.handleSelect(userHandle)
          }));
        }
      }
      return $$CONTACTS.length === 0 ? false : $$CONTACTS;
    };
    this.renderContent = () => {
      const frequentContacts = this.getFilteredFrequents();
      const contactsFiltered = this.getFilteredContacts();
      if (HAS_CONTACTS()) {
        const {
          contacts,
          frequents
        } = this.state;
        const $$RESULT_TABLE = (header, children) => REaCt().createElement("div", {
          className: "contacts-search-subsection"
        }, REaCt().createElement("div", {
          className: "contacts-list-header"
        }, header), REaCt().createElement("div", {
          className: "contacts-search-list"
        }, children));
        if (frequents.length === 0 && contacts.length === 0) {
          return REaCt().createElement(nil, null);
        }
        return REaCt().createElement(perfectScrollbar.O, {
          ref: this.wrapperRef,
          options: {
            'suppressScrollX': true
          }
        }, frequentContacts ? $$RESULT_TABLE(l[20141], frequentContacts) : '', contactsFiltered ? $$RESULT_TABLE(l[165], contactsFiltered) : '');
      }
      return REaCt().createElement(nil, null);
    };
    this.renderLoading = () => {
      return REaCt().createElement("div", {
        className: `${Invite.NAMESPACE}-loading`
      }, REaCt().createElement("h2", null, l[1456]));
    };
    this.state.excluded = this.props.chatRoom ? this.props.chatRoom.getParticipantsExceptMe() : [];
    this.state.contacts = this.state.contactsInitial = this.getSortedContactsList();
  }
  componentDidMount() {
    this.getFrequentContacts();
  }
  render() {
    const {
      NAMESPACE
    } = Invite;
    const {
      value,
      loading,
      selected,
      contactsInitial
    } = this.state;
    const {
      chatRoom,
      call,
      onClose
    } = this.props;
    const {
      isMeeting,
      publicLink
    } = chatRoom || {};
    const callPartsLength = chatRoom.getCallParticipants().length;
    return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
      ref: this.domRef,
      name: NAMESPACE,
      className: `
                    ${NAMESPACE}
                    dialog-template-tool
                `,
      callPartsLength,
      hideOverlay: true,
      onClose
    }), REaCt().createElement("div", {
      className: `${NAMESPACE}-head`
    }, REaCt().createElement("h2", null, isMeeting ? l.invite_participants : l[8726]), isMeeting && publicLink && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("p", null, l.copy_and_share), REaCt().createElement("div", {
      className: "link-input-container"
    }, REaCt().createElement(meetings_button.A, {
      className: `mega-button large positive ${publicLink ? '' : 'disabled'}`,
      onClick: () => publicLink && copyToClipboard(`${getBaseUrl()}/${publicLink}`, l[371])
    }, !publicLink ? l[7006] : l[1394]))), HAS_CONTACTS() && REaCt().createElement(Search, {
      value,
      placeholder: contactsInitial.length,
      onChange: this.handleSearch
    }), call.sfuClient.callLimits && call.sfuClient.callLimits.usr && callPartsLength >= call.sfuClient.callLimits.usr && REaCt().createElement("div", {
      className: `${NAMESPACE}-user-limit-banner`
    }, call.organiser === u_handle ? (0,utils.lI)(l.invite_limit_banner_organiser, '[A]', ui_link.A, {
      className: 'invite-limit-link',
      onClick() {
        window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
        eventlog(500260);
      }
    }) : l.invite_limit_banner_host)), REaCt().createElement("div", {
      className: "fm-dialog-body"
    }, REaCt().createElement("div", {
      className: `${NAMESPACE}-contacts`
    }, loading ? this.renderLoading() : this.renderContent())), REaCt().createElement(footer, {
      selected,
      onAdd: this.handleAdd,
      onClose
    }));
  }
}
Invite.NAMESPACE = 'invite-meeting';
;// ./js/chat/ui/meetings/workflow/ephemeral.jsx



const Ephemeral = ({
  ephemeralAccounts,
  onClose
}) => {
  const ephemeralAccount = ephemeralAccounts && ephemeralAccounts[ephemeralAccounts.length - 1];
  return REaCt().createElement(modalDialogs.A.ModalDialog, {
    name: "ephemeral-dialog",
    dialogType: "message",
    icon: "sprite-fm-uni icon-info",
    title: REaCt().createElement(ui_contacts.ContactAwareName, {
      emoji: true,
      contact: M.u[ephemeralAccount]
    }),
    noCloseOnClickOutside: true,
    buttons: [{
      key: 'ok',
      label: l[81],
      onClick: onClose
    }],
    onClose
  }, REaCt().createElement("p", null, l.ephemeral_info));
};
const workflow_ephemeral = Ephemeral;
;// ./js/chat/ui/meetings/offline.jsx


const Offline = ({
  onCallEnd,
  onClose
}) => {
  return REaCt().createElement(modalDialogs.A.ModalDialog, {
    name: "reconnect-dialog",
    dialogType: "message",
    icon: "sprite-fm-uni icon-warning",
    title: l.no_internet,
    noCloseOnClickOutside: true,
    buttons: [{
      key: 'ok',
      label: l.msg_dlg_cancel,
      onClick: onClose
    }, {
      key: 'leave',
      label: l[5883],
      className: 'negative',
      onClick: onCallEnd
    }],
    onClose
  }, REaCt().createElement("p", null, l.no_connection));
};
const meetings_offline = Offline;
// EXTERNAL MODULE: ./js/chat/ui/conversationpanel.jsx + 15 modules
const conversationpanel = REQ_(438);
// EXTERNAL MODULE: ./js/chat/ui/meetings/streamControls.jsx
const streamControls = REQ_(489);
;// ./js/chat/ui/meetings/sidebarControls.jsx



const SidebarControls = ({
  npeers,
  view,
  sidebar,
  call,
  chatRoom,
  onChatToggle,
  onParticipantsToggle,
  onInviteToggle
}) => {
  const notifications = chatRoom.getUnreadCount();
  const isOnHold = !!((call == null ? void 0 : call.av) & Av.onHold);
  const canInvite = chatRoom.type !== 'private' && !!(chatRoom.iAmOperator() || chatRoom.options[MCO_FLAGS.OPEN_INVITE] || chatRoom.publicLink);
  return REaCt().createElement("div", {
    className: "sidebar-controls"
  }, REaCt().createElement("ul", {
    className: isOnHold ? 'disabled' : ''
  }, canInvite && REaCt().createElement("li", {
    onClick: isOnHold ? null : onInviteToggle
  }, REaCt().createElement(meetings_button.A, {
    className: `
                            mega-button
                            theme-dark-forced
                            call-action
                            round
                        `,
    icon: "icon-user-plus-thin-outline"
  }), REaCt().createElement("span", {
    className: "control-label"
  }, l[8726])), REaCt().createElement("li", {
    onClick: isOnHold ? null : onChatToggle
  }, REaCt().createElement(meetings_button.A, {
    className: `
                            mega-button
                            theme-dark-forced
                            call-action
                            round
                            ${sidebar && view === VIEW.CHAT ? 'selected' : ''}
                            ${isOnHold ? 'disabled' : ''}
                        `,
    icon: sidebar && view === VIEW.CHAT ? 'icon-chat-filled' : 'icon-message-chat-circle-thin'
  }), REaCt().createElement("span", {
    className: "control-label"
  }, l.chat_call_button), notifications > 0 && REaCt().createElement("span", {
    className: "notification-badge notifications-count"
  }, notifications > 9 ? '9+' : notifications)), REaCt().createElement("li", {
    onClick: isOnHold ? null : onParticipantsToggle
  }, REaCt().createElement(meetings_button.A, {
    className: `
                            mega-button
                            theme-dark-forced
                            call-action
                            round
                            ${sidebar && view === VIEW.PARTICIPANTS ? 'selected' : ''}
                            ${isOnHold ? 'disabled' : ''}
                        `,
    icon: sidebar && view === VIEW.PARTICIPANTS ? 'icon-users-thin-solid' : 'icon-users-thin-outline'
  }), REaCt().createElement("span", {
    className: "control-label"
  }, l.participants_call_button), REaCt().createElement("span", {
    className: `
                                notification-badge
                                participants-count
                                theme-dark-forced
                                ${npeers + 1 > 99 ? 'large' : ''}
                            `
  }, npeers + 1))));
};
const sidebarControls = SidebarControls;
// EXTERNAL MODULE: ./js/chat/ui/inviteParticipantsPanel.jsx
const inviteParticipantsPanel = REQ_(815);
// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
const dropdowns = REQ_(911);
;// ./js/chat/ui/meetings/call.jsx

















const NAMESPACE = 'meetings-call';
const EXPANDED_FLAG = 'in-call';
const MOUSE_OUT_DELAY = 2500;
const MODE = {
  THUMBNAIL: 1,
  MAIN: 2,
  MINI: 3
};
const VIEW = {
  DEFAULT: 0,
  CHAT: 1,
  PARTICIPANTS: 2
};
const TYPE = {
  AUDIO: 1,
  VIDEO: 2
};
const isGuest = () => !u_type;
const inProgressAlert = (isJoin, chatRoom) => {
  return new Promise((resolve, reject) => {
    if (megaChat.haveAnyActiveCall()) {
      if (window.sfuClient) {
        const {
          chatRoom: activeCallRoom
        } = megaChat.activeCall;
        const peers = activeCallRoom ? activeCallRoom.getParticipantsExceptMe(activeCallRoom.getCallParticipants()).map(h => M.getNameByHandle(h)) : [];
        let body = isJoin ? l.cancel_to_join : l.cancel_to_start;
        if (peers.length) {
          body = mega.utils.trans.listToString(peers, isJoin ? l.cancel_with_to_join : l.cancel_with_to_start);
        }
        msgDialog('warningb', null, l.call_in_progress, body, null, 1);
        return reject();
      }
      if (chatRoom.getCallParticipants().includes(u_handle)) {
        return resolve();
      }
      return msgDialog(`warningb:!^${l[2005]}!${isJoin ? l.join_call_anyway : l.start_call_anyway}`, null, isJoin ? l.join_multiple_calls_title : l.start_multiple_calls_title, isJoin ? l.join_multiple_calls_text : l.start_multiple_calls_text, join => {
        if (join) {
          return resolve();
        }
        return reject();
      }, 1);
    }
    resolve();
  });
};
window.inProgressAlert = inProgressAlert;
class RecordingConsentDialog extends REaCt().Component {
  componentWillUnmount() {
    if ($.dialog && $.dialog === RecordingConsentDialog.dialogName) {
      closeDialog();
    }
  }
  render() {
    const {
      peers,
      recorderCid,
      onCallEnd,
      onClose
    } = this.props;
    const recordingPeer = peers[recorderCid];
    const recorderName = nicknames.getNickname(recordingPeer).substr(0, ChatToastIntegration.MAX_NAME_CHARS);
    return REaCt().createElement(modalDialogs.A.ModalDialog, {
      dialogName: RecordingConsentDialog.dialogName,
      className: `
                    mega-dialog
                    dialog-template-message
                    info
                `,
      stopKeyPropagation: true,
      noCloseOnClickOutside: true
    }, REaCt().createElement("header", null, REaCt().createElement("div", {
      className: "graphic"
    }, REaCt().createElement("i", {
      className: "info sprite-fm-uni icon-info"
    })), REaCt().createElement("div", {
      className: "info-container"
    }, REaCt().createElement("h3", {
      id: "msgDialog-title"
    }, l.call_recorded_heading), REaCt().createElement("p", {
      className: "text"
    }, REaCt().createElement(utils.P9, null, l.call_recorded_body.replace('[A]', `<a href="https://mega.io/privacy" target="_blank" class="clickurl">`).replace('[/A]', '</a>'))))), REaCt().createElement("footer", null, REaCt().createElement("div", {
      className: "footer-container"
    }, REaCt().createElement("div", {
      className: "space-between"
    }, REaCt().createElement(meetings_button.A, {
      className: "mega-button",
      onClick: onCallEnd
    }, REaCt().createElement("span", null, l[5883])), REaCt().createElement(meetings_button.A, {
      className: "mega-button positive",
      onClick: () => {
        onClose();
        ChatToast.quick(l.user_recording_toast.replace('%NAME', recorderName));
      }
    }, REaCt().createElement("span", null, l.ok_button))))));
  }
}
RecordingConsentDialog.dialogName = `${"meetings-call"}-consent`;
class Call extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.recordingConsentDialog = `${NAMESPACE}-consent`;
    this.ephemeralAddListener = undefined;
    this.delayProcID = null;
    this.pCallTimer = null;
    this.offlineDelayed = undefined;
    this.callStartTimeout = undefined;
    this.flagMap = attribCache.bitMapsManager.exists('obv4') ? attribCache.bitMapsManager.get('obv4') : undefined;
    this.timeoutBannerRef = REaCt().createRef();
    this.state = {
      mode: undefined,
      view: VIEW.PARTICIPANTS,
      sidebar: false,
      forcedLocal: false,
      hovered: false,
      invite: false,
      ephemeral: false,
      offline: false,
      ephemeralAccounts: [],
      everHadPeers: false,
      guest: isGuest(),
      waitingRoomPeers: [],
      raisedHandPeers: [],
      raisedHandToast: false,
      initialCallRinging: false,
      onboardingUI: false,
      onboardingRecording: false,
      onboardingRaise: false,
      recorderCid: undefined,
      recordingConsentDialog: false,
      recordingConsented: false,
      recordingActivePeer: undefined,
      recordingTooltip: false,
      invitePanel: false,
      presenterThumbSelected: false,
      timeoutBanner: false,
      showTimeoutUpgrade: false,
      activeElement: false
    };
    this.handleRetryTimeout = () => {
      const {
        call,
        chatRoom
      } = this.props;
      if ((call == null ? void 0 : call.sfuClient.connState) === SfuClient.ConnState.kDisconnectedRetrying) {
        this.handleCallEnd();
        chatRoom.trigger('onRetryTimeout');
        megaChat.playSound(megaChat.SOUNDS.CALL_END);
      }
    };
    this.handleCallOnline = () => {
      if (this.pCallTimer) {
        this.pCallTimer.abort();
        this.pCallTimer = null;
      }
      this.setState({
        offline: false,
        raisedHandPeers: [...this.props.call.sfuClient.raisedHands]
      });
    };
    this.customIsEventuallyVisible = () => true;
    this.renderRaisedHandToast = () => {
      const {
        raisedHandPeers
      } = this.state;
      window.toaster.main.hideAll();
      toaster.main.show({
        buttons: [{
          text: l[16797],
          onClick: () => this.setState({
            sidebar: true,
            view: VIEW.PARTICIPANTS,
            raisedHandToast: false
          }, () => window.toaster.main.hideAll())
        }],
        onClose: () => this.setState({
          raisedHandToast: false
        }, () => window.toaster.main.hideAll()),
        classes: ['theme-dark-forced', 'call-toast'],
        icons: ['sprite-fm-uni icon-raise-hand'],
        timeout: 0,
        content: (() => {
          const peerName = M.getNameByHandle(raisedHandPeers[0]);
          const peersCount = raisedHandPeers.length;
          const withCurrentPeer = raisedHandPeers.includes(u_handle);
          const CONTENT = {
            1: () => l.raise_peer_raised.replace('%s', peerName),
            2: () => {
              const message = withCurrentPeer ? l.raise_self_peers_raised : l.raise_two_raised;
              return mega.icu.format(message, peersCount - 1).replace('%s', peerName);
            },
            rest: () => {
              const message = withCurrentPeer ? l.raise_self_peers_raised : l.raise_peers_raised;
              return mega.icu.format(message, withCurrentPeer ? peersCount - 1 : peersCount);
            }
          };
          return (CONTENT[peersCount] || CONTENT.rest)();
        })()
      });
    };
    this.bindCallEvents = () => {
      const {
        chatRoom
      } = this.props;
      chatRoom.rebind(`onCallPeerLeft.${NAMESPACE}`, (ev, {
        userHandle,
        clientId
      }) => {
        const {
          minimized,
          peers,
          call,
          chatRoom
        } = this.props;
        if (clientId === this.state.recorderCid) {
          chatRoom.trigger('onRecordingStopped', {
            userHandle,
            clientId
          });
        }
        if (minimized) {
          this.setState({
            mode: peers.length === 0 ? MODE.THUMBNAIL : MODE.MINI
          }, () => {
            call.setViewMode(this.state.mode);
          });
        }
      });
      chatRoom.rebind(`onCallPeerJoined.${NAMESPACE}`, () => {
        const {
          minimized,
          peers,
          call
        } = this.props;
        if (minimized) {
          this.setState({
            mode: peers.length === 0 ? MODE.THUMBNAIL : MODE.MINI
          }, () => {
            call.setViewMode(this.state.mode);
          });
        }
        if (call.hasOtherParticipant()) {
          if (!this.state.everHadPeers) {
            this.setState({
              everHadPeers: true
            });
          }
          clearTimeout(this.callStartTimeout);
        }
      });
      chatRoom.rebind(`onCallLeft.${NAMESPACE}`, () => this.props.minimized && this.props.onCallEnd());
      chatRoom.rebind(`wrOnUsersEntered.${NAMESPACE}`, (ev, users) => Object.entries(users).forEach(([handle, host]) => {
        return host || this.state.waitingRoomPeers.includes(handle) ? null : this.isMounted() && this.setState({
          waitingRoomPeers: [...this.state.waitingRoomPeers, handle]
        }, () => {
          const {
            waitingRoomPeers
          } = this.state;
          if (waitingRoomPeers && waitingRoomPeers.length === 1) {
            megaChat.playSound(megaChat.SOUNDS.CALL_JOIN_WAITING);
          }
          mBroadcaster.sendMessage('meetings:peersWaiting', waitingRoomPeers);
        });
      }));
      const usrwr = (e, users) => {
        users = typeof users === 'string' ? [users] : users;
        return this.isMounted() && this.setState({
          waitingRoomPeers: this.state.waitingRoomPeers.filter(h => !users.includes(h))
        }, () => mBroadcaster.sendMessage('meetings:peersWaiting', this.state.waitingRoomPeers));
      };
      chatRoom.rebind(`wrOnUserLeft.${NAMESPACE}`, usrwr);
      chatRoom.rebind(`wrOnUsersAllow.${NAMESPACE}`, usrwr);
      chatRoom.rebind(`wrOnUserDump.${NAMESPACE}`, (ev, users) => Object.entries(users).forEach(([handle, host]) => {
        return host || this.state.waitingRoomPeers.includes(handle) ? null : this.isMounted() && this.setState({
          waitingRoomPeers: [...this.state.waitingRoomPeers, handle]
        });
      }));
      chatRoom.rebind(`onRecordingStarted.${NAMESPACE}`, (ev, {
        userHandle,
        clientId
      }) => {
        if (!this.state.recorderCid) {
          return this.state.recordingConsented ? this.setState({
            recorderCid: clientId
          }, () => {
            ChatToast.quick(l.user_recording_toast.replace('%NAME', nicknames.getNickname(userHandle).substr(0, ChatToastIntegration.MAX_NAME_CHARS)));
          }) : (() => {
            closeDialog();
            M.safeShowDialog(RecordingConsentDialog.dialogName, () => this.setState({
              recorderCid: clientId,
              recordingConsentDialog: true
            }));
          })();
        }
      });
      chatRoom.rebind(`onRecordingStopped.${NAMESPACE}`, (ev, {
        userHandle,
        clientId
      }) => {
        const {
          recorderCid
        } = this.state;
        this.setState({
          recordingConsentDialog: false,
          recorderCid: clientId === recorderCid ? false : recorderCid
        }, () => window.sfuClient && clientId === recorderCid && ChatToast.quick(l.user_recording_nop_toast.replace('%NAME', nicknames.getNickname(userHandle).substr(0, ChatToastIntegration.MAX_NAME_CHARS))));
      });
      chatRoom.rebind(`onMutedBy.${NAMESPACE}`, (ev, {
        cid
      }) => {
        megaChat.plugins.userHelper.getUserNickname(this.props.peers[cid]).catch(dump).always(name => {
          ChatToast.quick(l.muted_by.replace('%NAME', name || ''));
        });
      });
      chatRoom.rebind(`onCallEndTimeUpdated.${NAMESPACE}`, ({
        data
      }) => {
        this.setState({
          timeoutBanner: !!data,
          showTimeoutUpgrade: this.props.call.organiser === u_handle && data - Date.now() >= 120e3
        }, () => {
          if (this.state.timeoutBanner) {
            this.timeoutBannerInterval = this.timeoutBannerInterval || setInterval(() => this.updateTimeoutDuration(), 1000);
          } else {
            clearInterval(this.timeoutBannerInterval);
            delete this.timeoutBannerInterval;
          }
        });
      });
      chatRoom.rebind(`onRaisedHandAdd.${NAMESPACE}`, (ev, {
        userHandle
      }) => this.isMounted() && this.setState(state => ({
        raisedHandPeers: [...state.raisedHandPeers, userHandle]
      }), () => {
        const {
          raisedHandPeers
        } = this.state;
        if (userHandle !== u_handle && !this.props.minimized) {
          this.setState({
            raisedHandToast: true
          }, () => this.renderRaisedHandToast());
        }
        mBroadcaster.sendMessage('meetings:raisedHand', raisedHandPeers);
      }));
      chatRoom.rebind(`onRaisedHandDel.${NAMESPACE}`, (ev, {
        userHandle
      }) => this.isMounted() && this.setState(state => ({
        raisedHandPeers: state.raisedHandPeers.filter(h => h !== userHandle)
      }), () => {
        const {
          raisedHandPeers,
          raisedHandToast
        } = this.state;
        mBroadcaster.sendMessage('meetings:raisedHand', raisedHandPeers);
        if (raisedHandPeers && raisedHandPeers.length) {
          return raisedHandToast ? this.renderRaisedHandToast() : null;
        }
        return this.setState({
          raisedHandToast: false
        }, () => window.toaster.main.hideAll());
      }));
      chatRoom.rebind(`onRecordingActivePeer.${NAMESPACE}`, (ev, {
        userHandle
      }) => this.setState({
        recordingActivePeer: userHandle
      }));
    };
    this.unbindCallEvents = () => ['onCallPeerLeft', 'onCallPeerJoined', 'onCallLeft', 'wrOnUsersAllow', 'wrOnUsersEntered', 'wrOnUserLeft', 'alterUserPrivilege', 'onCallState', 'onRecordingStarted', 'onRecordingStopped', 'onRecordingActivePeer', 'onCallEndTimeUpdated', 'onRaisedHandAdd', 'onRaisedHandDel'].map(event => this.props.chatRoom.off(`${event}.${NAMESPACE}`));
    this.handleCallMinimize = () => {
      const {
        call,
        peers,
        onCallMinimize
      } = this.props;
      const {
        mode,
        sidebar,
        view
      } = this.state;
      const {
        callToutId,
        stayOnEnd,
        presenterStreams
      } = call;
      Call.STATE.PREVIOUS = mode !== MODE.MINI ? {
        mode,
        sidebar,
        view
      } : Call.STATE.PREVIOUS;
      const doMinimize = () => {
        onCallMinimize();
        window.toaster.main.hideAll();
      };
      mega.ui.mInfoPanel.hide();
      return peers.length > 0 || presenterStreams.has(u_handle) ? this.setState({
        mode: MODE.MINI,
        sidebar: false
      }, () => {
        doMinimize();
        call.setViewMode(MODE.MINI);
      }) : (() => {
        doMinimize();
        if (typeof callToutId !== 'undefined' && !stayOnEnd) {
          onIdle(() => call.showTimeoutDialog());
        }
      })();
    };
    this.handleCallExpand = async () => {
      mega.ui.mInfoPanel.hide();
      return new Promise(resolve => {
        this.setState({
          ...Call.STATE.PREVIOUS
        }, () => {
          this.props.onCallExpand();
          resolve();
        });
      });
    };
    this.handleStreamToggle = action => {
      const {
        peers
      } = this.props;
      if (action === stream.hK.ADD && peers.length === stream.$A) {
        return;
      }
      return action === stream.hK.ADD ? peers.addFakeDupStream() : peers.removeFakeDupStream();
    };
    this.handleSpeakerChange = (source, presenterThumbSelected) => {
      if (source) {
        this.handleModeChange(MODE.MAIN);
        const sourceId = source.isLocal ? 0 : source.clientId;
        if (sourceId !== this.props.call.pinnedCid) {
          this.props.call.setPinnedCid(sourceId);
        } else {
          this.props.call.setPinnedCid(sourceId, !source.hasScreen || presenterThumbSelected === this.state.presenterThumbSelected);
        }
        const {
          pinnedCid
        } = this.props.call;
        this.setState({
          forcedLocal: !!(source.isLocal && pinnedCid !== null),
          presenterThumbSelected: pinnedCid === null ? false : !!presenterThumbSelected && source.hasScreen
        });
      } else if (source === null) {
        this.setState({
          presenterThumbSelected: !!presenterThumbSelected
        });
      }
    };
    this.handleModeChange = mode => {
      this.props.call.setViewMode(mode);
      this.setState({
        mode,
        forcedLocal: false
      });
    };
    this.handleChatToggle = () => {
      if (this.state.sidebar && this.state.view === VIEW.CHAT) {
        return this.setState({
          ...Call.STATE.DEFAULT
        });
      }
      return this.setState({
        sidebar: true,
        view: VIEW.CHAT
      });
    };
    this.handleParticipantsToggle = forceOpen => {
      if (forceOpen !== true) {
        forceOpen = false;
      }
      if (this.state.sidebar && this.state.view === VIEW.CHAT) {
        return this.setState({
          sidebar: true,
          view: VIEW.PARTICIPANTS
        });
      }
      return this.setState({
        sidebar: forceOpen ? true : !this.state.sidebar,
        view: VIEW.PARTICIPANTS
      });
    };
    this.handleInviteToggle = () => {
      if (Object.values(M.u.toJS()).some(u => u.c === 1)) {
        const participants = (0,conversationpanel.zV)(this.props.chatRoom);
        if ((0,conversationpanel.e4)(participants)) {
          msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.all_contacts_added}`, `${l.all_contacts_added_to_chat}`, res => {
            if (res) {
              contactAddDialog(null, false);
            }
          });
        } else {
          this.setState({
            invite: !this.state.invite
          });
        }
      } else {
        msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.no_contacts}`, `${l.no_contacts_text}`, resp => {
          if (resp) {
            contactAddDialog(null, false);
          }
        });
      }
    };
    this.handleHoldToggle = async () => {
      await this.props.call.toggleHold();
      mBroadcaster.sendMessage('meetings:toggleHold');
    };
    this.handleScreenSharingToggle = () => {
      const {
        call
      } = this.props;
      const userAgent = navigator.userAgent.match(/Chrom(e|ium)\/(\d+)\./);
      const version = parseInt(userAgent[2], 10);
      if (version === 92) {
        return msgDialog('info', undefined, l[47], l.chrome_screensharing);
      }
      return call.toggleScreenSharing();
    };
    this.handleCallEnd = () => {
      let _this$props$call;
      mega.ui.mInfoPanel.hide();
      (_this$props$call = this.props.call) == null || _this$props$call.destroy(SfuClient.TermCode.kUserHangup);
    };
    this.handleEphemeralAdd = handle => handle && this.setState(state => ({
      ephemeral: true,
      ephemeralAccounts: [...state.ephemeralAccounts, handle]
    }));
    this.handleStayConfirm = () => {
      const {
        call
      } = this.props;
      call.handleStayConfirm();
      onIdle(() => this.safeForceUpdate());
    };
    this.handleRecordingToggle = () => {
      const {
        call,
        chatRoom
      } = this.props;
      if (chatRoom.isMeeting) {
        eventlog(500286);
      } else {
        eventlog(500287);
      }
      if (this.state.recorderCid) {
        return msgDialog(`confirmation:!^${l.stop_recording_dialog_cta}!${l.stop_recording_nop_dialog_cta}`, undefined, l.stop_recording_dialog_heading, l.stop_recording_dialog_body, cb => cb && sfuClient.recordingStop(), 1);
      }
      msgDialog(`warningb:!^${l.start_recording_dialog_cta}!${l.msg_dlg_cancel}`, null, l.notify_participants_dialog_heading, l.notify_participants_dialog_body, cb => {
        if (cb || cb === null) {
          return;
        }
        call.sfuClient.recordingStart(this.onWeStoppedRecording).then(() => {
          call.recorderCid = this.state.recorderCid;
          this.setState({
            recorderCid: call.sfuClient.cid
          });
          this.handleModeChange(MODE.MAIN);
          call.recordActiveStream();
          ChatToast.quick(l.started_recording_toast);
        }).catch(dump);
      }, 1);
    };
    this.onWeStoppedRecording = err => this.isMounted() && this.setState({
      recorderCid: undefined,
      recordingActivePeer: undefined
    }, () => err ? ChatToast.quick(`${l.stopped_recording_toast} Error: ${err.message || err}`) : ChatToast.quick(l.stopped_recording_toast));
    this.renderRecordingControl = () => {
      const {
        chatRoom,
        call,
        peers
      } = this.props;
      const {
        recorderCid,
        recordingTooltip,
        recordingActivePeer
      } = this.state;
      const isModerator = Call.isModerator(chatRoom, u_handle);
      const $$CONTAINER = ({
        className,
        onClick,
        children
      }) => REaCt().createElement("div", {
        className: `
                    recording-control
                    ${localStorage.callDebug ? 'with-offset' : ''}
                    ${className || ''}
                `,
        onClick
      }, children);
      if (recorderCid) {
        const isRecorder = isModerator && recorderCid === call.sfuClient.cid;
        const recordingPeer = peers[recorderCid];
        return REaCt().createElement($$CONTAINER, {
          recordingTooltip,
          className: "recording-fixed"
        }, REaCt().createElement("div", (0,esm_extends.A)({
          className: `
                            recording-ongoing
                            simpletip
                            ${isRecorder ? '' : 'plain-background'}
                        `
        }, recorderCid !== call.sfuClient.cid && {
          'data-simpletip': l.host_recording.replace('%NAME', nicknames.getNickname(recordingPeer) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER),
          'data-simpletipposition': 'top',
          'data-simpletipoffset': 5,
          'data-simpletip-class': 'theme-dark-forced'
        }), REaCt().createElement("span", {
          className: `
                                recording-icon
                                button
                                ${recordingTooltip ? 'active-dropdown' : ''}
                                ${isRecorder ? 'clickable' : ''}
                            `,
          onMouseEnter: () => isRecorder && this.setState({
            recordingTooltip: true
          }),
          onMouseOut: () => isRecorder && delay('meetings-rec-hover', () => this.setState({
            recordingTooltip: false
          }), 1250)
        }, "REC ", REaCt().createElement("i", null), REaCt().createElement(dropdowns.Dropdown, {
          className: "recording-info theme-dark-forced",
          active: recordingTooltip,
          noArrow: false,
          positionMy: "center top",
          positionAt: "center bottom",
          vertOffset: 40,
          horizOffset: 30
        }, REaCt().createElement("div", null, "Currently recording: ", nicknames.getNickname(recordingActivePeer)))), isRecorder && REaCt().createElement("span", {
          className: "recording-toggle",
          onClick: this.handleRecordingToggle
        }, l.record_stop_button)));
      }
      const isOnHold = !!((call == null ? void 0 : call.av) & Av.onHold);
      return isModerator && REaCt().createElement($$CONTAINER, {
        className: isOnHold ? 'disabled' : '',
        onClick: () => {
          this.setState({
            onboardingRecording: false,
            hovered: false
          }, () => {
            this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_RECORDING, 1);
            this.flagMap.safeCommit();
          });
          return isOnHold || recorderCid && recorderCid !== call.sfuClient.cid ? null : this.handleRecordingToggle();
        }
      }, REaCt().createElement(meetings_button.A, {
        className: `
                        mega-button
                        theme-dark-forced
                        call-action
                        round
                        recording-start
                        ${isOnHold ? 'disabled' : ''}
                    `
      }, REaCt().createElement("div", null, REaCt().createElement("i", null))), REaCt().createElement("span", {
        className: "record-label"
      }, l.record_start_button));
    };
    this.setActiveElement = activeElement => this.setState({
      activeElement
    });
    const {
      SOUNDS
    } = megaChat;
    [SOUNDS.RECONNECT, SOUNDS.CALL_END, SOUNDS.CALL_JOIN_WAITING].map(sound => ion.sound.preload(sound));
    this.state.mode = props.call.viewMode;
    this.setOnboarding();
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.handleMouseOut = this.handleMouseOut.bind(this);
  }
  handleMouseMove() {
    this.setState({
      hovered: true
    });
    if (this.delayProcID) {
      delay.cancel(this.delayProcID);
      this.delayProcID = null;
    }
  }
  handleMouseOut() {
    if (this.state.hovered) {
      this.delayProcID = delay('meetings-call-hover', () => {
        if (this.isMounted()) {
          this.setState({
            hovered: false
          });
        }
      }, MOUSE_OUT_DELAY);
    }
  }
  handleCallOffline() {
    if (!this.pCallTimer) {
      (this.pCallTimer = tSleep(30)).then(() => {
        this.setState({
          offline: true
        });
      });
    }
  }
  setOnboarding() {
    this.state.onboardingUI = this.state.hovered = this.flagMap && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_UI);
    if (!this.state.onboardingUI) {
      this.state.onboardingRecording = this.state.hovered = this.flagMap && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RECORDING);
    }
    if (!this.state.onboardingUI && !this.state.onboardingRecording) {
      this.state.onboardingRaise = this.state.hovered = this.flagMap && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RAISE);
    }
  }
  handleInvitePanelToggle() {
    delay('chat-event-inv-call', () => eventlog(99962));
    this.setState({
      invitePanel: !this.state.invitePanel
    });
  }
  handleInviteOrAdd() {
    const {
      chatRoom
    } = this.props;
    if (chatRoom.type === 'group') {
      return this.handleInviteToggle();
    }
    loadingDialog.show('fetchchatlink');
    chatRoom.updatePublicHandle(false, false, true).catch(dump).always(() => {
      loadingDialog.hide('fetchchatlink');
      if (!this.isMounted()) {
        return;
      }
      if (!chatRoom.iAmOperator() && chatRoom.options[MCO_FLAGS.OPEN_INVITE] && !chatRoom.publicLink) {
        this.handleInviteToggle();
      } else if (chatRoom.type === 'public' && !chatRoom.topic) {
        this.handleInviteToggle();
      } else {
        this.handleInvitePanelToggle();
      }
    });
  }
  renderTimeLimitBanner() {
    return REaCt().createElement("div", {
      className: "call-time-limit-banner theme-dark-forced"
    }, REaCt().createElement("span", {
      ref: this.timeoutBannerRef
    }, this.timeoutString), REaCt().createElement("span", {
      className: "call-limit-banner-action",
      onClick: () => {
        clearInterval(this.timeoutBannerInterval);
        delete this.timeoutBannerInterval;
        this.setState({
          timeoutBanner: false
        });
      }
    }, l[2005]), this.state.showTimeoutUpgrade && REaCt().createElement(ui_link.A, {
      className: "call-limit-banner-action",
      onClick: () => {
        window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
        eventlog(500262);
      }
    }, l.upgrade_now));
  }
  get timeoutString() {
    const {
      call
    } = this.props;
    if (call.callEndTime === 0) {
      return '';
    }
    const remainSeconds = Math.max(0, Math.ceil((call.callEndTime - Date.now()) / 1000));
    if (call.organiser === u_handle) {
      if (remainSeconds < 60) {
        return mega.icu.format(l.free_call_banner_organiser_ending_sec, remainSeconds);
      }
      if (remainSeconds <= 120) {
        return mega.icu.format(l.free_call_banner_organiser_ending, Math.ceil(remainSeconds / 60));
      }
      return mega.icu.format(l.free_call_banner_organiser_warning, Math.ceil(remainSeconds / 60));
    }
    if (remainSeconds < 60) {
      return mega.icu.format(l.free_call_banner_ending_sec, remainSeconds);
    }
    if (remainSeconds <= 120) {
      return mega.icu.format(l.free_call_banner_ending, Math.ceil(remainSeconds / 60));
    }
    return mega.icu.format(l.free_call_banner_warning, Math.ceil(remainSeconds / 60));
  }
  updateTimeoutDuration() {
    if (this.timeoutBannerRef) {
      const {
        current
      } = this.timeoutBannerRef;
      const newStr = this.timeoutString;
      if (newStr && current && current.innerText !== newStr) {
        current.innerText = newStr;
      }
      if (this.state.showTimeoutUpgrade && this.props.call.callEndTime - Date.now() <= 12e4) {
        this.setState({
          showTimeoutUpgrade: false
        });
      }
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    const {
      minimized,
      willUnmount,
      chatRoom
    } = this.props;
    chatRoom.megaChat.off(`sfuConnClose.${NAMESPACE}`);
    chatRoom.megaChat.off(`sfuConnOpen.${NAMESPACE}`);
    chatRoom.megaChat.off(`onSpeakerChange.${NAMESPACE}`);
    chatRoom.megaChat.off(`onPeerAvChange.${NAMESPACE}`);
    mBroadcaster.removeListener(this.ephemeralAddListener);
    mBroadcaster.removeListener(this.pageChangeListener);
    clearTimeout(this.callStartTimeout);
    delay.cancel('callOffline');
    if ($.dialog) {
      closeDialog();
    }
    if (this.timeoutBannerInterval) {
      clearInterval(this.timeoutBannerInterval);
    }
    window.toaster.main.hideAll();
    this.unbindCallEvents();
    willUnmount == null || willUnmount(minimized);
  }
  componentDidMount() {
    super.componentDidMount();
    const {
      call,
      didMount,
      chatRoom
    } = this.props;
    this.ephemeralAddListener = mBroadcaster.addListener('meetings:ephemeralAdd', handle => this.handleEphemeralAdd(handle));
    this.pageChangeListener = mBroadcaster.addListener('pagechange', () => {
      const currentRoom = megaChat.getCurrentRoom();
      if (Call.isExpanded() && (!M.chat || currentRoom && currentRoom.chatId !== chatRoom.chatId)) {
        this.handleCallMinimize();
      }
    });
    chatRoom.megaChat.rebind(`sfuConnOpen.${NAMESPACE}`, () => this.handleCallOnline());
    chatRoom.megaChat.rebind(`sfuConnClose.${NAMESPACE}`, () => this.handleCallOffline());
    chatRoom.rebind(`onCallState.${NAMESPACE}`, (ev, {
      arg
    }) => this.setState({
      initialCallRinging: arg
    }));
    const {
      tresizer
    } = $;
    chatRoom.rebind(`onPeerAvChange.${NAMESPACE}`, tresizer);
    chatRoom.rebind(`onSpeakerChange.${NAMESPACE}`, tresizer);
    this.callStartTimeout = setTimeout(() => {
      if (!mega.config.get('callemptytout') && !call.hasOtherParticipant()) {
        call.left = true;
        call.initCallTimeout();
      }
    }, 300000);
    setTimeout(() => {
      let _call$peers;
      return ((_call$peers = call.peers) == null ? void 0 : _call$peers.length) && !call.hasOtherParticipant() && this.setState({
        everHadPeers: true
      });
    }, 2e3);
    if (sessionStorage.previewMedia) {
      const {
        audio,
        video
      } = JSON.parse(sessionStorage.previewMedia);
      sessionStorage.removeItem('previewMedia');
      tSleep(2).then(() => audio && call.sfuClient.muteAudio()).then(() => video && call.sfuClient.muteCamera()).catch(dump);
    }
    this.bindCallEvents();
    didMount == null || didMount();
  }
  componentDidUpdate() {
    if (typeof psa !== 'undefined') {
      psa.repositionMeetingsCall();
    }
  }
  render() {
    let _ref;
    const {
      minimized,
      peers,
      call,
      chatRoom,
      parent,
      typingAreaText,
      onDeleteMessage,
      onTypingAreaChanged
    } = this.props;
    const {
      mode,
      view,
      sidebar,
      hovered,
      forcedLocal,
      invite,
      ephemeral,
      ephemeralAccounts,
      guest,
      offline,
      onboardingUI,
      onboardingRecording,
      onboardingRaise,
      everHadPeers,
      initialCallRinging,
      waitingRoomPeers,
      recorderCid,
      raisedHandPeers,
      recordingConsentDialog,
      invitePanel,
      presenterThumbSelected,
      timeoutBanner,
      activeElement
    } = this.state;
    const {
      stayOnEnd
    } = call;
    const hasOnboarding = onboardingUI || onboardingRecording || onboardingRaise;
    const STREAM_PROPS = {
      mode,
      peers,
      sidebar,
      hovered: hasOnboarding || hovered,
      forcedLocal,
      call,
      view,
      chatRoom,
      parent,
      stayOnEnd,
      everHadPeers,
      waitingRoomPeers,
      recorderCid,
      presenterThumbSelected,
      raisedHandPeers,
      activeElement,
      hasOtherParticipants: call.hasOtherParticipant(),
      isOnHold: call.sfuClient.isOnHold,
      isFloatingPresenter: (_ref = mode === MODE.MINI && !forcedLocal ? call.getActiveStream() : call.getLocalStream()) == null ? void 0 : _ref.hasScreen,
      onSpeakerChange: this.handleSpeakerChange,
      onModeChange: this.handleModeChange,
      onInviteToggle: this.handleInviteToggle,
      onStayConfirm: this.handleStayConfirm
    };
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                    meetings-call
                    ${minimized ? 'minimized' : ''}
                    ${timeoutBanner ? 'with-timeout-banner' : ''}
                    ${activeElement ? 'with-active-element' : ''}
                `,
      onMouseMove: hasOnboarding ? null : this.handleMouseMove,
      onMouseOut: hasOnboarding ? null : this.handleMouseOut
    }, timeoutBanner && this.renderTimeLimitBanner(), REaCt().createElement(stream.Ay, (0,esm_extends.A)({}, STREAM_PROPS, {
      minimized,
      ephemeralAccounts,
      onCallMinimize: this.handleCallMinimize,
      onCallExpand: this.handleCallExpand,
      onCallEnd: this.handleCallEnd,
      onStreamToggle: this.handleStreamToggle,
      onRecordingToggle: () => call.sfuClient.recordingStop(),
      onChatToggle: this.handleChatToggle,
      onParticipantsToggle: this.handleParticipantsToggle,
      onAudioClick: () => call.toggleAudio(),
      onVideoClick: () => call.toggleVideo(),
      onScreenSharingClick: this.handleScreenSharingToggle,
      onHoldClick: this.handleHoldToggle,
      onVideoDoubleClick: this.handleSpeakerChange,
      setActiveElement: this.setActiveElement
    })), sidebar && REaCt().createElement(Sidebar, (0,esm_extends.A)({}, STREAM_PROPS, {
      guest,
      initialCallRinging,
      typingAreaText,
      onGuestClose: () => this.setState({
        guest: false
      }),
      onSidebarClose: () => this.setState({
        ...Call.STATE.DEFAULT
      }),
      onDeleteMessage,
      onCallMinimize: this.handleCallMinimize,
      onInviteToggle: () => this.handleInviteOrAdd(),
      onTypingAreaChanged
    })), minimized ? null : REaCt().createElement(REaCt().Fragment, null, this.renderRecordingControl(), REaCt().createElement(streamControls.Ay, {
      call,
      minimized,
      peers,
      chatRoom,
      recorderCid,
      hovered,
      raisedHandPeers,
      onboardingRaise,
      onOnboardingRaiseDismiss: () => {
        this.setState({
          onboardingRaise: false,
          hovered: false
        }, () => {
          this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_RAISE, 1);
          this.flagMap.safeCommit();
        });
      },
      onRecordingToggle: () => this.setState({
        recorderCid: undefined
      }, () => call.sfuClient.recordingStop()),
      onAudioClick: () => call.toggleAudio(),
      onVideoClick: () => call.toggleVideo(),
      onScreenSharingClick: this.handleScreenSharingToggle,
      onCallEnd: this.handleCallEnd,
      onStreamToggle: this.handleStreamToggle,
      onHoldClick: this.handleHoldToggle,
      setActiveElement: this.setActiveElement
    }), REaCt().createElement(sidebarControls, {
      call,
      chatRoom,
      npeers: peers.length,
      mode,
      view,
      sidebar,
      onChatToggle: this.handleChatToggle,
      onParticipantsToggle: this.handleParticipantsToggle,
      onInviteToggle: () => this.handleInviteOrAdd()
    })), invite && REaCt().createElement(Invite, {
      contacts: M.u,
      call,
      chatRoom,
      onClose: () => this.setState({
        invite: false
      })
    }), ephemeral && REaCt().createElement(workflow_ephemeral, {
      ephemeralAccounts,
      onClose: () => this.setState({
        ephemeral: false
      })
    }), offline && REaCt().createElement(meetings_offline, {
      onClose: () => {
        if (offline) {
          this.setState({
            offline: false
          }, () => delay('call:timeout', this.handleRetryTimeout, 3e4));
        }
      },
      onCallEnd: () => {
        this.setState({
          offline: false
        }, () => this.handleRetryTimeout());
      }
    }), onboardingUI && REaCt().createElement("div", {
      className: `${NAMESPACE}-onboarding`
    }, REaCt().createElement("div", {
      className: "mega-dialog mega-onboarding-dialog dialog-template-message onboarding-UI",
      id: "ob-dialog",
      role: "dialog",
      "aria-labelledby": "ob-dialog-title",
      "aria-modal": "true"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow top",
      id: "ob-dialog-arrow"
    }), REaCt().createElement("header", null, REaCt().createElement("div", null, REaCt().createElement("h2", {
      id: "ob-dialog-title"
    }, l.onboarding_call_title), REaCt().createElement("p", {
      id: "ob-dialog-text"
    }, l.onboarding_call_body))), REaCt().createElement("footer", null, REaCt().createElement("div", {
      className: "footer-container"
    }, REaCt().createElement("button", {
      className: "mega-button js-next small theme-light-forced",
      onClick: () => {
        this.setState({
          onboardingUI: false,
          onboardingRecording: chatRoom.iAmOperator() && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RECORDING)
        }, () => {
          this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_UI, 1);
          this.flagMap.safeCommit();
          this.setState({
            onboardingRaise: !this.state.onboardingRecording && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RAISE)
          });
        });
      }
    }, REaCt().createElement("span", null, l.ok_button)))))), onboardingRecording && Call.isModerator(chatRoom, u_handle) && REaCt().createElement("div", {
      className: `${NAMESPACE}-onboarding`
    }, REaCt().createElement("div", {
      className: "mega-dialog mega-onboarding-dialog dialog-template-message onboarding-recording",
      id: "ob-dialog",
      role: "dialog",
      "aria-labelledby": "ob-dialog-title",
      "aria-modal": "true"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow bottom",
      id: "ob-dialog-arrow"
    }), REaCt().createElement("header", null, REaCt().createElement("div", null, REaCt().createElement("h2", {
      id: "ob-dialog-title"
    }, l.recording_onboarding_title), REaCt().createElement("p", {
      id: "ob-dialog-text"
    }, l.recording_onboarding_body_intro), REaCt().createElement("p", {
      id: "ob-dialog-text"
    }, l.recording_onboarding_body_details))), REaCt().createElement("footer", null, REaCt().createElement("div", {
      className: "footer-container"
    }, REaCt().createElement(ui_link.A, {
      className: "link-button",
      to: "https://help.mega.io/chats-meetings/chats/call-recording",
      target: "_blank"
    }, l[8742]), REaCt().createElement("button", {
      className: "mega-button js-next small theme-light-forced",
      onClick: () => {
        this.setState({
          onboardingRecording: false,
          onboardingRaise: true
        }, () => {
          this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_RECORDING, 1);
          this.flagMap.safeCommit();
        });
      }
    }, REaCt().createElement("span", null, l.ok_button)))))), recordingConsentDialog && REaCt().createElement(RecordingConsentDialog, {
      peers,
      recorderCid,
      onClose: () => this.setState({
        recordingConsentDialog: false,
        recordingConsented: true
      }),
      onCallEnd: this.handleCallEnd
    }), invitePanel && REaCt().createElement(modalDialogs.A.ModalDialog, {
      className: "theme-dark-forced",
      onClose: () => {
        this.setState({
          invitePanel: false
        });
      },
      dialogName: "chat-link-dialog",
      chatRoom
    }, REaCt().createElement(inviteParticipantsPanel.Q, {
      chatRoom,
      onAddParticipants: () => {
        this.setState({
          invitePanel: false
        }, () => this.handleInviteToggle());
      }
    })));
  }
}
Call.STATE = {
  DEFAULT: {
    sidebar: false
  },
  PREVIOUS: {
    mode: null,
    sidebar: null,
    view: null
  }
};
Call.isModerator = (chatRoom, handle) => {
  if (chatRoom && handle) {
    return chatRoom.members[handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR;
  }
  return false;
};
Call.isExpanded = () => document.body.classList.contains(EXPANDED_FLAG);
Call.getUnsupportedBrowserMessage = () => navigator.userAgent.match(/Chrom(e|ium)\/(\d+)\./) ? l.alert_unsupported_browser_version : l.alert_unsupported_browser;

},

77:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  A: () => composedTextArea
});

// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
;// ./js/chat/ui/whosTyping.jsx

class WhosTyping extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.state = {
      currentlyTyping: {}
    };
  }
  componentDidMount() {
    const {
      chatRoom
    } = this.props;
    chatRoom.rebind('onParticipantTyping.whosTyping', (e, user_handle, bCastCode) => {
      if (user_handle === u_handle) {
        return;
      }
      const u_h = user_handle;
      if (u_h === u_handle) {
        return;
      } else if (!M.u[u_h]) {
        return;
      }
      const currentlyTyping = {
        ...this.state.currentlyTyping
      };
      if (currentlyTyping[u_h]) {
        currentlyTyping[u_h].abort();
      }
      if (bCastCode === 1) {
        const timer = tSleep(5);
        timer.then(() => {
          this.stoppedTyping(u_h);
        });
        currentlyTyping[u_h] = timer;
        this.setState({
          currentlyTyping
        });
      } else {
        this.stoppedTyping(u_h);
      }
      this.forceUpdate();
    });
  }
  componentWillUnmount() {
    this.props.chatRoom.off('onParticipantTyping.whosTyping');
  }
  stoppedTyping(u_h) {
    if (this.domRef.current) {
      const {
        currentlyTyping
      } = this.state;
      if (currentlyTyping[u_h]) {
        const newState = {
          ...currentlyTyping
        };
        if (!newState[u_h].aborted) {
          newState[u_h].abort();
        }
        delete newState[u_h];
        this.setState({
          currentlyTyping: newState
        });
      }
    }
  }
  render() {
    const users = Object.keys(this.state.currentlyTyping);
    if (users.length > 0) {
      const names = users.map(u_h => M.getNameByHandle(u_h)).filter(String);
      let namesDisplay = "";
      let areMultipleUsersTyping = false;
      if (names.length > 1) {
        areMultipleUsersTyping = true;
        namesDisplay = [names.splice(0, names.length - 1).join(", "), names[0]];
      } else {
        areMultipleUsersTyping = false;
        namesDisplay = [names[0]];
      }
      return REaCt().createElement("div", {
        ref: this.domRef,
        className: "typing-block"
      }, REaCt().createElement("div", {
        className: "typing-text"
      }, areMultipleUsersTyping ? l[8872].replace("%1", namesDisplay[0]).replace("%2", namesDisplay[1]) : l[8629].replace("%1", namesDisplay[0])), REaCt().createElement("div", {
        className: "typing-bounce"
      }, REaCt().createElement("div", {
        className: "typing-bounce1"
      }), REaCt().createElement("div", {
        className: "typing-bounce2"
      }), REaCt().createElement("div", {
        className: "typing-bounce3"
      })));
    }
    return null;
  }
}
// EXTERNAL MODULE: ./js/chat/ui/typingArea.jsx + 1 modules
const typingArea = REQ_(795);
// EXTERNAL MODULE: ./js/ui/buttons.jsx
const buttons = REQ_(994);
// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
const dropdowns = REQ_(911);
;// ./js/chat/ui/composedTextArea.jsx





const ComposedTextArea = ({
  chatRoom,
  parent,
  containerRef,
  typingAreaText,
  onTypingAreaChanged
}) => REaCt().createElement("div", {
  className: "chat-textarea-block"
}, REaCt().createElement(WhosTyping, {
  chatRoom
}), REaCt().createElement(typingArea.T, {
  chatRoom,
  className: "main-typing-area",
  containerRef,
  disabled: chatRoom.isReadOnly(),
  persist: true,
  text: typingAreaText,
  onValueChanged: onTypingAreaChanged,
  onUpEditPressed: () => {
    const keys = chatRoom.messagesBuff.messages.keys();
    for (let i = keys.length; i--;) {
      const message = chatRoom.messagesBuff.messages[keys[i]];
      const contact = M.u[message.userId];
      if (!contact) {
        continue;
      }
      if (message.isEditable() && !message.requiresManualRetry && !message.deleted && (!message.type || message instanceof Message) && (!message.isManagement || !message.isManagement())) {
        parent.historyPanel.editMessage(message.messageId);
        return true;
      }
    }
    return false;
  },
  onResized: () => {
    parent.historyPanel.handleWindowResize();
  },
  onConfirm: messageContents => {
    const {
      messagesListScrollable
    } = parent.historyPanel;
    if (messageContents && messageContents.length > 0) {
      if (!chatRoom.scrolledToBottom) {
        chatRoom.scrolledToBottom = true;
        parent.lastScrollPosition = 0;
        chatRoom.rebind('onMessagesBuffAppend.pull', () => {
          if (messagesListScrollable) {
            messagesListScrollable.scrollToBottom(false);
            delay('messagesListScrollable', () => {
              messagesListScrollable.enable();
            }, 1500);
          }
        });
        chatRoom.sendMessage(messageContents);
        messagesListScrollable == null || messagesListScrollable.disable();
        messagesListScrollable == null || messagesListScrollable.scrollToBottom(true);
      } else {
        chatRoom.sendMessage(messageContents);
      }
    }
  }
}, REaCt().createElement(buttons.$, {
  className: "popup-button left",
  icon: "sprite-fm-mono icon-add",
  disabled: chatRoom.isReadOnly()
}, REaCt().createElement(dropdowns.Dropdown, {
  className: "wide-dropdown attach-to-chat-popup light",
  noArrow: "true",
  positionMy: "left top",
  positionAt: "left bottom",
  vertOffset: 4,
  wrapper: "#fmholder"
}, REaCt().createElement("div", {
  className: "dropdown info-txt"
}, l[23753] || 'Send...'), REaCt().createElement(dropdowns.DropdownItem, {
  className: "link-button",
  icon: "sprite-fm-mono icon-cloud",
  label: l[19794] || 'My Cloud Drive',
  disabled: mega.paywall,
  onClick: () => chatRoom.trigger('openAttachCloudDialog')
}), REaCt().createElement(dropdowns.DropdownItem, {
  className: "link-button",
  icon: "sprite-fm-mono icon-session-history",
  label: l[19795] || 'My computer',
  disabled: mega.paywall,
  onClick: () => chatRoom.uploadFromComputer()
}), !is_eplusplus && !is_chatlink && !chatRoom.isNote && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
  className: "link-button",
  icon: "sprite-fm-mono icon-send-contact",
  label: l.share_contact_button,
  onClick: () => chatRoom.trigger('openSendContactDialog')
}))))));
const composedTextArea = ComposedTextArea;

},

110:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
PS: () => addMonths,
We: () => stringToTime,
XH: () => stringToDate,
a4: () => getTimeIntervals,
cK: () => isToday,
dB: () => getUserTimezone,
ef: () => isTomorrow,
i_: () => getNearestHalfHour,
ro: () => isSameDay
});

const stringToDate = string => {
  return moment(string, ['DD MMM YYYY', 'DD-MM-YYYY', 'DD.MM.YYYY', 'MMM DD YYYY', 'YYYY MMM DD', 'YYYY DD MMM']);
};
const stringToTime = string => moment(string, ['HH:mm', 'hh:mm A']);
const isSameDay = (a, b) => {
  return new Date(a).toDateString() === new Date(b).toDateString();
};
const isToday = timestamp => {
  return new Date(timestamp).toDateString() === new Date().toDateString();
};
const isTomorrow = timestamp => {
  const tomorrow = new Date();
  tomorrow.setDate(tomorrow.getDate() + 1);
  return tomorrow.toDateString() === new Date(timestamp).toDateString();
};
const getDaysInMonth = (year, month) => {
  return new Date(year, month, 0).getDate();
};
const addMonths = (timestamp, months) => {
  const date = new Date(timestamp);
  return new Date(date.setMonth(date.getMonth() + months)).getTime();
};
const getNearestHalfHour = (timestamp = Date.now()) => {
  const {
    SCHEDULED_MEETINGS_INTERVAL
  } = ChatRoom;
  return new Date(Math.ceil(timestamp / SCHEDULED_MEETINGS_INTERVAL) * SCHEDULED_MEETINGS_INTERVAL).getTime();
};
const getUserTimezone = () => {
  return Intl.DateTimeFormat().resolvedOptions().timeZone;
};
const getTimeIntervals = (timestamp, offsetFrom, interval = 30) => {
  const increments = [];
  if (timestamp) {
    const [targetDate, initialDate] = [new Date(timestamp), new Date(timestamp)].map(date => {
      date.setHours(0);
      date.setMinutes(0);
      return date;
    });
    while (targetDate.getDate() === initialDate.getDate()) {
      const timestamp = targetDate.getTime();
      const diff = offsetFrom && timestamp - offsetFrom;
      increments.push({
        value: timestamp,
        label: toLocaleTime(timestamp),
        duration: diff && diff > 0 ? diff : undefined
      });
      targetDate.setMinutes(targetDate.getMinutes() + interval);
    }
  }
  return increments;
};

},

137:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
LP: () => getUniqueId,
N9: () => timing,
Zz: () => compose,
hG: () => SoonFcWrap,
u9: () => ContactAwareComponent,
w9: () => MegaRenderMixin
});

const _applyDecoratedDescriptor0__ = REQ_(793);
const react_dom1__ = REQ_(206);
const react_dom1 = REQ_.n(react_dom1__);
const react2__ = REQ_(594);
const react2 = REQ_.n(react2__);

let _dec, _dec2, _dec3, _dec4, _dec5, _class;


const INTERSECTION_OBSERVER_AVAILABLE = typeof IntersectionObserver !== 'undefined';
const RESIZE_OBSERVER_AVAILABLE = typeof ResizeObserver !== 'undefined';
function shallowEqual(objA, objB) {
  if (objA === objB) {
    return true;
  }
  for (var key in objA) {
    if (key === "children") {
      continue;
    }
    if (objA.hasOwnProperty(key)) {
      if (!objB.hasOwnProperty(key)) {
        return false;
      } else if (objA[key] !== objB[key]) {
        if (typeof objA[key] === 'function' && typeof objB[key] === 'function') {
          if (objA[key].toString() !== objB[key].toString()) {
            return false;
          }
        } else {
          return false;
        }
      }
    }
  }
  for (key in objB) {
    if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
      return false;
    }
  }
  return true;
}
window.shallowEqual = shallowEqual;
const MAX_ALLOWED_DEBOUNCED_UPDATES = 5;
const DEBOUNCED_UPDATE_TIMEOUT = 60;
const REENABLE_UPDATES_AFTER_TIMEOUT = 300;
const MAX_TRACK_CHANGES_RECURSIVE_DEPTH = 1;
let _propertyTrackChangesVars = Object.create(null);
_propertyTrackChangesVars._listenersMap = Object.create(null);
_propertyTrackChangesVars._dataChangedHistory = Object.create(null);
if (window._propertyTrackChangesVars) {
  _propertyTrackChangesVars = window._propertyTrackChangesVars;
} else {
  window._propertyTrackChangesVars = _propertyTrackChangesVars;
}
window.megaRenderMixinId = window.megaRenderMixinId ? window.megaRenderMixinId : 0;
const FUNCTIONS = ['render', 'shouldComponentUpdate', 'doProgramaticScroll', 'componentDidMount', 'componentDidUpdate', 'componentWillUnmount', 'refreshUI', 'eventuallyInit', 'handleWindowResize', 'focusTypeArea', 'initScrolling', 'updateScroll', 'isActive', 'onMessagesScrollReinitialise', 'specShouldComponentUpdate', 'attachAnimationEvents', 'eventuallyReinitialise', 'reinitialise', 'reinitialised', 'getContentHeight', 'getScrollWidth', 'isAtBottom', 'onResize', 'isComponentEventuallyVisible', 'getCursorPosition', 'getTextareaMaxHeight'];
const localStorageProfileRenderFns = localStorage.profileRenderFns;
if (localStorageProfileRenderFns) {
  window.REACT_RENDER_CALLS = {};
}
let ID_CURRENT = 1;
const DEBUG_THIS = d > 1 ? d : false;
const scheduler = (func, name, debug) => {
  const dbug = debug !== false && DEBUG_THIS;
  let idnt = null;
  let task = null;
  const fire = () => {
    if (dbug) {
      console.warn('Dispatching scheduled task for %s.%s...', idnt, name);
    }
    if (task) {
      queueMicrotask(task);
      task = null;
    }
  };
  const _scheduler = function () {
    if (dbug) {
      if (!idnt) {
        idnt = name[0] === '(' && this.getReactId && this.getReactId() || this;
      }
      console.warn('Scheduling task from %s.%s...', idnt, name, [this], !!task);
    }
    if (!task) {
      queueMicrotask(fire);
    }
    let idx = arguments.length;
    const args = new Array(idx);
    while (idx--) {
      args[idx] = arguments[idx];
    }
    task = () => {
      func.apply(this, args);
    };
  };
  if (DEBUG_THIS) {
    Object.defineProperty(_scheduler, smbl(name), {
      value: func
    });
  }
  return _scheduler;
};
const timing = (min, max) => {
  return function (target, key, de) {
    if (DEBUG_THIS > 2) {
      de[key] = de.value;
      _timing(de, min, max);
      de.value = de[key];
    }
    return de;
  };
};
const logcall = () => {
  return function (target, key, descriptor) {
    if (DEBUG_THIS > 3) {
      const func = descriptor.value;
      descriptor.value = function () {
        console.group('[logcall] Entering into %s.%s...', this, key);
        const r = func.apply(this, arguments);
        console.info('[logcall] Leaving %s.%s...', this, key);
        console.groupEnd();
        return r;
      };
    }
    return descriptor;
  };
};
const schedule = (local, debug) => {
  return function (target, property, descriptor) {
    if (local) {
      const func = descriptor.value;
      descriptor = {
        configurable: true,
        get: function _unusedScheduler() {
          Object.defineProperty(this, property, {
            value: scheduler(func, `(${  property  })`, debug)
          });
          return this[property];
        }
      };
    } else {
      descriptor.value = scheduler(descriptor.value, property, debug);
    }
    return descriptor;
  };
};
const compose = (...funcs) => funcs.reduce((a, b) => (...args) => a(b(...args)), arg => arg);
const replaceAt = (i, o, n) => `${o.slice(0, i)}<strong>${n}</strong>${o.slice(i + n.length)}`;
const SoonFcWrap = (milliseconds, local) => {
  return function (target, propertyKey, descriptor) {
    descriptor.value = SoonFc(descriptor.value, !local, milliseconds);
    return descriptor;
  };
};
const rAFWrap = () => {
  return function (target, propertyKey, descriptor) {
    const old = descriptor.value;
    descriptor.value = function () {
      return old.apply(this, arguments);
    };
    return descriptor;
  };
};
const trycatcher = () => (t, p, d) => (d.value = tryCatch(d.value)) && d;
const getUniqueId = () => makeUUID().slice(-12);
const MegaRenderMixin = (_dec = logcall(), _dec2 = SoonFcWrap(50, true), _dec3 = logcall(), _dec4 = SoonFcWrap(80, true), _dec5 = SoonFcWrap(350, true), _class = class MegaRenderMixin extends react2().Component {
  constructor(props) {
    super(props);
    lazy(this, '__internalReactID', function () {
      let key = '';
      let fib = DEBUG_THIS && this._reactInternalFiber;
      while (fib) {
        let tmp = fib.key;
        if (tmp && tmp[0] !== '.' && key.indexOf(tmp) < 0) {
          key += `${tmp  }/`;
        }
        if (tmp = fib.memoizedProps) {
          if (tmp.contact) {
            tmp = tmp.contact.u + (tmp.chatRoom ? `@${  tmp.chatRoom.roomId}` : '');
          } else if (tmp.chatRoom) {
            tmp = tmp.chatRoom.roomId;
          } else {
            tmp = 0;
          }
          if (tmp && key.indexOf(tmp) < 0) {
            key += `${tmp  }/`;
          }
        }
        fib = fib._debugOwner;
      }
      key = key ? `[${  key.substr(0, key.length - 1)  }]` : '';
      return `::${  this.constructor.name  }[${  `000${  ID_CURRENT++}`.slice(-4)  }]${  key}`;
    });
    lazy(this, '__internalUniqueID', function () {
      return (this.__internalReactID + makeUUID().substr(-12)).replace(/[^a-zA-Z0-9]/g, '');
    });
    Object.defineProperty(this, 'isMounted', {
      value: function MegaRenderMixin_isMounted() {
        return !!this.__isMounted;
      }
    });
    if (DEBUG_THIS > 2) {
      Object.defineProperty(this, 'safeForceUpdate', {
        value: function MegaRenderMixin_safeForceUpdate_debug() {
          console.group('%s.safeForceUpdate: mounted:%s, visible:%s', this.getReactId(), this.__isMounted, this.isComponentEventuallyVisible());
          if (this.__isMounted) {
            this.forceUpdate(() => {
              console.warn('%s.safeForceUpdate finished.', this.getReactId());
              console.groupEnd();
            });
          }
        }
      });
      Object.keys(this).forEach(k => {
        if (this[k] && this[k].apply) {
          const orig = this[k];
          this[k] = function () {
            let s = performance.now();
            const r = orig.apply(this, arguments);
            s = performance.now() - s;
            if (s > 30) {
              console.error(k, this, "took", s, "ms", 'returned', r);
            }
            return r;
          };
        }
      });
    }
    if (DEBUG_THIS) {
      if (!megaChat.__components) {
        megaChat.__components = new WeakMap();
      }
      megaChat.__components.set(this, Object.getPrototypeOf(this));
    }
  }
  componentWillUnmount() {
    if (super.componentWillUnmount) {
      super.componentWillUnmount();
    }
    this.__isMounted = false;
    chatGlobalEventManager.removeEventListener('resize', `megaRenderMixing${  this.getUniqueId()}`);
    chatGlobalEventManager.removeEventListener('hashchange', `hc${  this.getUniqueId()}`);
    const node = this.findDOMNode();
    if (this.__intersectionObserverInstance) {
      if (node) {
        this.__intersectionObserverInstance.unobserve(node);
      }
      this.__intersectionObserverInstance.disconnect();
      this.__intersectionObserverInstance = undefined;
    }
    if (this.onResizeObserved) {
      if (!RESIZE_OBSERVER_AVAILABLE) {
        $(document.body).unbind(`resize.resObs${  this.getUniqueId()}`);
      } else {
        this.__resizeObserverInstance.unobserve(node);
        this.__resizeObserverInstance.disconnect();
        this.__resizeObserverInstance = undefined;
      }
    }
    const instanceId = this.getUniqueId();
    const listeners = _propertyTrackChangesVars._listenersMap[instanceId];
    if (listeners) {
      for (const k in listeners) {
        const v = listeners[k];
        v[0].removeChangeListener(v[1]);
      }
    }
    _propertyTrackChangesVars._listenersMap[instanceId] = null;
    _propertyTrackChangesVars._dataChangedHistory[instanceId] = null;
    if (this._dataStructListeners) {
      this._internalDetachRenderCallbacks();
    }
    if (this.detachRerenderCallbacks) {
      this.detachRerenderCallbacks();
    }
  }
  getReactId() {
    return this.__internalReactID;
  }
  getUniqueId() {
    return this.__internalUniqueID;
  }
  debouncedForceUpdate() {
    this.eventuallyUpdate();
  }
  componentDidMount() {
    if (super.componentDidMount) {
      super.componentDidMount();
    }
    this.__isMounted = true;
    this._wasRendered = true;
    if (this.props.requiresUpdateOnResize || this.requiresUpdateOnResize || !this.props.skipQueuedUpdatesOnResize) {
      chatGlobalEventManager.addEventListener('resize', `megaRenderMixing${  this.getUniqueId()}`, () => this.onResizeDoUpdate());
    }
    chatGlobalEventManager.addEventListener('hashchange', `hc${  this.getUniqueId()}`, () => this.onResizeDoUpdate());
    if (this.props) {
      this._recurseAddListenersIfNeeded("p", this.props);
    }
    if (this.state) {
      this._recurseAddListenersIfNeeded("s", this.state);
    }
    const node = this.findDOMNode();
    if (INTERSECTION_OBSERVER_AVAILABLE && !this.customIsEventuallyVisible && node && node.nodeType) {
      this.__intersectionVisibility = false;
      onIdle(() => {
        this.__intersectionObserverInstance = new IntersectionObserver(entries => {
          const entry = entries.pop();
          if (entry.intersectionRatio < 0.2 && !entry.isIntersecting) {
            this.__intersectionVisibility = false;
          } else {
            this.__intersectionVisibility = true;
            if (this._requiresUpdateOnResize) {
              this.debouncedForceUpdate();
            }
          }
          if (this.onVisibilityChange) {
            this.onVisibilityChange(this.__intersectionVisibility);
          }
        }, {
          threshold: 0.1
        });
        this.__intersectionObserverInstance.observe(node);
      });
    }
    if (this.onResizeObserved) {
      if (!RESIZE_OBSERVER_AVAILABLE) {
        $(document.body).rebind(`resize.resObs${  this.getUniqueId()}`, () => {
          this.onResizeObserved(node.offsetWidth, node.offsetHeight);
        });
      } else {
        this.__resizeObserverInstance = new ResizeObserver(entries => {
          this.onResizeObserved(entries[0].contentRect.width, entries[0].contentRect.height);
        });
        this.__resizeObserverInstance.observe(node);
      }
    }
    if (this.attachRerenderCallbacks) {
      this.attachRerenderCallbacks();
    }
  }
  findDOMNode() {
    if (!this.domNode) {
      let _this$domRef;
      this.domNode = (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current;
    }
    return this.domNode;
  }
  isComponentVisible() {
    if (!this.__isMounted) {
      return false;
    }
    if (this.customIsEventuallyVisible) {
      const ciev = this.customIsEventuallyVisible;
      const result = typeof ciev === "function" ? ciev.call(this) : ciev;
      if (result !== -1) {
        return result;
      }
    }
    if (this.__intersectionVisibility === false) {
      return false;
    } else if (this.__intersectionVisibility === true) {
      return true;
    }
    const domNode = this.findDOMNode();
    if (!this.props.hideable && (!domNode || domNode.offsetParent === null)) {
      return false;
    }
    if (!$(domNode).is(":visible")) {
      return false;
    }
    return verge.inViewport(domNode);
  }
  isComponentEventuallyVisible() {
    if (!this.__isMounted) {
      return false;
    }
    if (this.customIsEventuallyVisible) {
      const ciev = this.customIsEventuallyVisible;
      return typeof ciev === "function" ? ciev.call(this) : !!ciev;
    }
    if (typeof this.props.isVisible !== 'undefined') {
      return this.props.isVisible;
    }
    return this.__intersectionVisibility !== false;
  }
  eventuallyUpdate() {
    if (!window.megaChat || megaChat.isLoggingOut || this._updatesDisabled || !this._wasRendered || !this.__isMounted) {
      return;
    }
    if (!this.isComponentEventuallyVisible()) {
      this._requiresUpdateOnResize = true;
      return;
    }
    if (this._requiresUpdateOnResize) {
      this._requiresUpdateOnResize = false;
    }
    this.forceUpdate();
  }
  tempDisableUpdates(forHowLong) {
    const self = this;
    self._updatesDisabled = true;
    if (self._updatesReenableTimer) {
      clearTimeout(self._updatesReenableTimer);
    }
    const timeout = forHowLong ? forHowLong : self.REENABLE_UPDATES_AFTER_TIMEOUT ? self.REENABLE_UPDATES_AFTER_TIMEOUT : REENABLE_UPDATES_AFTER_TIMEOUT;
    self._updatesReenableTimer = setTimeout(() => {
      self.tempEnableUpdates();
    }, timeout);
  }
  tempEnableUpdates() {
    clearTimeout(this._updatesReenableTimer);
    this._updatesDisabled = false;
    this.eventuallyUpdate();
  }
  onResizeDoUpdate() {
    this.eventuallyUpdate();
  }
  _getUniqueIDForMap(map, payload) {
    return `${map  }.${  payload}`;
  }
  _recurseAddListenersIfNeeded(idx, map, depth) {
    depth |= 0;
    if (map instanceof MegaDataMap && !(this._contactChangeListeners && this._contactChangeListeners.includes(map))) {
      const cacheKey = this._getUniqueIDForMap(map, idx);
      const instanceId = this.getUniqueId();
      if (!_propertyTrackChangesVars._listenersMap[instanceId]) {
        _propertyTrackChangesVars._listenersMap[instanceId] = Object.create(null);
      }
      if (!_propertyTrackChangesVars._listenersMap[instanceId][cacheKey]) {
        _propertyTrackChangesVars._listenersMap[instanceId][cacheKey] = [map, map.addChangeListener(() => this.onPropOrStateUpdated())];
      }
    }
    if (depth++ < MAX_TRACK_CHANGES_RECURSIVE_DEPTH && !this.props.manualDataChangeTracking) {
      const mapKeys = map instanceof MegaDataMap ? map.keys() : Object.keys(map);
      for (let i = 0; i < mapKeys.length; i++) {
        const k = mapKeys[i];
        if (map[k]) {
          this._recurseAddListenersIfNeeded(`${idx  }_${  k}`, map[k], depth);
        }
      }
    }
  }
  _checkDataStructForChanges(idx, v, rv, depth) {
    if (!v && v === rv) {
      return false;
    }
    if (!rv && v) {
      return true;
    }
    if (v === null) {
      return rv !== null;
    }
    if (v instanceof MegaDataMap) {
      const cacheKey = this._getUniqueIDForMap(v, idx);
      const dataChangeHistory = _propertyTrackChangesVars._dataChangedHistory;
      const instanceId = this.getUniqueId();
      if (!dataChangeHistory[instanceId]) {
        dataChangeHistory[instanceId] = Object.create(null);
      }
      if (dataChangeHistory[instanceId][cacheKey] !== v._dataChangeIndex) {
        if (window.RENDER_DEBUG) {
          console.error("changed: ", this.getElementName(), cacheKey, v._dataChangeTrackedId, v._dataChangeIndex, v);
        }
        dataChangeHistory[instanceId][cacheKey] = v._dataChangeIndex;
        return true;
      }
      return false;
    }
    return depth < MAX_TRACK_CHANGES_RECURSIVE_DEPTH && v && v.byteLength === undefined && typeof v === "object" && this._recursiveSearchForDataChanges(idx, v, rv, depth + 1) === true;
  }
  _recursiveSearchForDataChanges(idx, map, referenceMap, depth) {
    const self = this;
    depth = depth || 0;
    if (!this.isMounted() || this._updatesDisabled === true) {
      return;
    }
    if (!this._wasRendered) {
      if (window.RENDER_DEBUG) console.error("First time render", self.getElementName(), map, referenceMap);
      this._wasRendered = true;
      return true;
    }
    if (idx === "p_children") {
      if (map.map && referenceMap.map) {
        const oldKeys = map.map((child) => {
          return child ? child.key : child;
        });
        const newKeys = referenceMap.map((child) => {
          return child ? child.key : child;
        });
        if (!shallowEqual(oldKeys, newKeys)) {
          return true;
        }
      } else if (!map && referenceMap || map && !referenceMap) {
        return true;
      } else if (map.$$typeof && referenceMap.$$typeof) {
        if (!shallowEqual(map.props, referenceMap.props) || !shallowEqual(map.state, referenceMap.state)) {
          return true;
        }
      }
    } else if (map && !referenceMap || !map && referenceMap || map && referenceMap && !shallowEqual(map, referenceMap)) {
      return true;
    }
    const mapKeys = map instanceof MegaDataMap ? map.keys() : Object.keys(map);
    for (let i = mapKeys.length; i--;) {
      const k = mapKeys[i];
      if (this._checkDataStructForChanges(`${idx  }_${  k}`, map[k], referenceMap[k], depth)) {
        return true;
      }
    }
    return false;
  }
  shouldComponentUpdate(nextProps, nextState) {
    let shouldRerender = false;
    if (megaChat && megaChat.isLoggingOut) {
      return false;
    }
    if (!this.isMounted() || this._updatesDisabled === true) {
      if (window.RENDER_DEBUG) {
        console.error("shouldUpdate? No.", "F1", this.getElementName(), this.props, nextProps, this.state, nextState);
      }
      return false;
    }
    if (this.customIsEventuallyVisible) {
      let ciev = this.customIsEventuallyVisible;
      ciev = typeof ciev === "function" ? ciev.call(this) : !!ciev;
      if (!this._queueUpdateWhenVisible && !ciev) {
        this._queueUpdateWhenVisible = true;
        if (window.RENDER_DEBUG) {
          console.error("shouldUpdate? No.", "F1.1", this.getElementName(), this.props, nextProps, this.state, nextState);
        }
      } else if (this._queueUpdateWhenVisible && ciev) {
        delete this._queueUpdateWhenVisible;
        return true;
      }
    }
    if (this.specShouldComponentUpdate) {
      const r = this.specShouldComponentUpdate(nextProps, nextState);
      if (r === false) {
        if (window.RENDER_DEBUG) {
          console.error("shouldUpdate? No.", "F2", this.getElementName(), this.props, nextProps, this.state, nextState);
        }
        this._requiresUpdateOnResize = true;
        return false;
      } else if (r === true) {
        return true;
      }
    }
    if (!this.props.disableCheckingVisibility && !this.isComponentEventuallyVisible()) {
      if (window.RENDER_DEBUG) {
        console.error("shouldUpdate? No.", "FVis", this.getElementName(), this.props, nextProps, this.state, nextState);
      }
      this._requiresUpdateOnResize = true;
      return false;
    }
    if (this.props !== null) {
      shouldRerender = this._recursiveSearchForDataChanges("p", nextProps, this.props);
    }
    if (shouldRerender === false) {
      if (window.RENDER_DEBUG) {
        console.error("shouldUpdate? No.", "F3", this.getElementName(), this.props, nextProps, this.state, nextState);
      }
    }
    if (shouldRerender === false && this.state !== null) {
      shouldRerender = this._recursiveSearchForDataChanges("s", nextState, this.state);
    }
    if (window.RENDER_DEBUG) {
      if (shouldRerender) {}
      console.error("shouldRerender?", shouldRerender, "rendered: ", this.getElementName(), "props:", this.props, "nextProps:", this.props, "state:", this.state);
    }
    if (shouldRerender === true) {
      if (this.props) {
        this._recurseAddListenersIfNeeded("p", this.props);
      }
      if (this.state) {
        this._recurseAddListenersIfNeeded("s", this.state);
      }
    } else {
      if (window.RENDER_DEBUG) {
        console.error("shouldUpdate? No.", "F4", this.getElementName(), this.props, nextProps, this.state, nextState);
      }
    }
    return shouldRerender;
  }
  onPropOrStateUpdated() {
    this.eventuallyUpdate();
  }
  getElementName() {
    return this._reactInternalFiber.elementType.name;
  }
  safeForceUpdate() {
    if (this.__isMounted) {
      this.forceUpdate();
    }
  }
  componentDidUpdate() {
    if (window.RENDER_DEBUG) {
      const self = this;
      const getElementName = function () {
        if (!self.constructor) {
          return "unknown";
        }
        return self.constructor.name;
      };
      console.error("renderedX: ", getElementName(), "props:", this.props, "state:", this.state);
    }
    if (this.domNode && !this.domNode.isConnected) {
      delete this.domNode;
    }
  }
  UNSAFE_componentWillReceiveProps(nextProps, nextContext) {
    if (localStorageProfileRenderFns) {
      const self = this;
      const componentName = self.constructor ? self.constructor.name : "unknown";
      if (!this._wrappedRender) {
        FUNCTIONS.forEach((fnName) => {
          const _origFn = self[fnName];
          if (_origFn) {
            self[fnName] = function () {
              const start = performance.now();
              const res = _origFn.apply(this, arguments);
              REACT_RENDER_CALLS[`${componentName  }.${  fnName}`] = REACT_RENDER_CALLS[`${componentName  }.${  fnName}`] || 0;
              REACT_RENDER_CALLS[`${componentName  }.${  fnName}`] += performance.now() - start;
              return res;
            };
          }
        });
        self._wrappedRender = true;
      }
      REACT_RENDER_CALLS.sorted = function () {
        const sorted = [];
        Object.keys(REACT_RENDER_CALLS).sort((a, b) => {
          if (REACT_RENDER_CALLS[a] < REACT_RENDER_CALLS[b]) {
            return 1;
          } else if (REACT_RENDER_CALLS[a] > REACT_RENDER_CALLS[b]) {
            return -1;
          } else {
            return 0;
          }
        }).forEach((k) => {
          if (typeof REACT_RENDER_CALLS[k] !== 'function') {
            sorted.push([k, REACT_RENDER_CALLS[k]]);
          }
        });
        return sorted;
      };
      REACT_RENDER_CALLS.clear = function () {
        Object.keys(REACT_RENDER_CALLS).forEach((k) => {
          if (typeof REACT_RENDER_CALLS[k] !== 'function') {
            delete REACT_RENDER_CALLS[k];
          }
        });
      };
    }
  }
  _internalDetachRenderCallbacks() {
    const items = this._dataStructListeners || false;
    for (let i = items.length; i--;) {
      const item = items[i];
      if (item[0] === 'dsprops') {
        console.assert(item[2].removeChangeListener(item[1]), 'listener not found..');
      }
    }
  }
  addDataStructListenerForProperties(obj, properties) {
    if (!(obj instanceof MegaDataMap)) {
      return;
    }
    if (!this._dataStructListeners) {
      this._dataStructListeners = [];
    }
    properties = array.to.object(properties);
    const id = obj.addChangeListener((obj, data, k) => properties[k] && this.onPropOrStateUpdated());
    this._dataStructListeners.push(['dsprops', id, obj]);
  }
}, (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "componentWillUnmount", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "componentWillUnmount"), _class.prototype), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "debouncedForceUpdate", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "debouncedForceUpdate"), _class.prototype), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "componentDidMount", [_dec3], Object.getOwnPropertyDescriptor(_class.prototype, "componentDidMount"), _class.prototype), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "eventuallyUpdate", [_dec4], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyUpdate"), _class.prototype), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "onResizeDoUpdate", [_dec5], Object.getOwnPropertyDescriptor(_class.prototype, "onResizeDoUpdate"), _class.prototype), _class);
class ContactAwareComponent extends MegaRenderMixin {
  constructor(props) {
    super(props);
    this.loadContactInfo();
  }
  _validContact() {
    const {
      contact
    } = this.props;
    if (!contact) {
      return false;
    }
    return (contact.h || contact.u) in M.u;
  }
  _attachRerenderCbContacts(others) {
    if (!this._validContact()) {
      return;
    }
    this.addDataStructListenerForProperties(this.props.contact, ['name', 'firstName', 'lastName', 'nickname', 'm', 'avatar'].concat(Array.isArray(others) ? others : []));
  }
  attachRerenderCallbacks() {
    this._attachRerenderCbContacts();
  }
  loadContactInfo() {
    let _contact$avatar;
    if (!this._validContact()) {
      return;
    }
    const {
      contact,
      chatRoom
    } = this.props;
    const contactHandle = contact.h || contact.u;
    const syncName = !ContactAwareComponent.unavailableNames[contactHandle] && !contact.firstName && !contact.lastName;
    const syncMail = megaChat.FORCE_EMAIL_LOADING || (contact.c === 1 || contact.c === 2) && !contact.m && !is_chatlink;
    const syncAvtr = (is_chatlink && (!contact.avatar || ((_contact$avatar = contact.avatar) == null ? void 0 : _contact$avatar.type) === "text") || !contact.avatar) && !avatars[contactHandle] && !ContactAwareComponent.unavailableAvatars[contactHandle];
    const loader = () => {
      if (!this.isComponentEventuallyVisible()) {
        this.__isLoadingContactInfo = null;
        this._requiresUpdateOnResize = true;
        return;
      }
      const promises = [];
      const chatHandle = is_chatlink.ph || chatRoom && chatRoom.publicChatHandle;
      if (syncName) {
        promises.push(megaChat.plugins.userHelper.getUserName(contactHandle, chatHandle));
      }
      if (syncMail) {
        promises.push(M.syncContactEmail(contactHandle));
      }
      if (syncAvtr) {
        promises.push(useravatar.loadAvatar(contactHandle, chatHandle).catch(() => {
          ContactAwareComponent.unavailableAvatars[contactHandle] = true;
        }));
      }
      return Promise.allSettled(promises).always(() => {
        this.eventuallyUpdate();
        this.__isLoadingContactInfo = false;
        if (!contact.firstName && !contact.lastName) {
          ContactAwareComponent.unavailableNames[contactHandle] = true;
        }
      });
    };
    if (syncName || syncMail || syncAvtr) {
      (this.__isLoadingContactInfo = tSleep(0.3)).then(loader).catch(dump);
    }
  }
  componentDidUpdate() {
    super.componentDidUpdate();
    if (this.__isLoadingContactInfo === null) {
      this.loadContactInfo();
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    if (this.__isLoadingContactInfo) {
      this.__isLoadingContactInfo.abort();
      this.__isLoadingContactInfo = false;
    }
  }
  isLoadingContactInfo() {
    return !!this.__isLoadingContactInfo;
  }
}
ContactAwareComponent.unavailableAvatars = Object.create(null);
ContactAwareComponent.unavailableNames = Object.create(null);

},

161:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
$: () => ColumnFavIcon
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);
const _genericNodePropsComponent1__ = REQ_(984);


class ColumnFavIcon extends _genericNodePropsComponent1__.B {
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {
      node
    } = nodeAdapter.props;
    const isFavouritable = node.r === 2;
    return react0().createElement("td", {
      megatype: ColumnFavIcon.megatype,
      className: ColumnFavIcon.megatype
    }, react0().createElement("span", {
      className: `grid-status-icon sprite-fm-mono ${  missingkeys[node.h] ? " icon-info" : nodeAdapter.nodeProps.fav ? " icon-favourite-filled" : " icon-dot"  }${!isFavouritable && " disabled" || ""}`,
      onClick: () => {
        if (isFavouritable) {
          M.favourite([node.h], !node.fav);
        }
      }
    }));
  }
}
ColumnFavIcon.sortable = true;
ColumnFavIcon.id = "fav";
ColumnFavIcon.label = "";
ColumnFavIcon.icon = "icon-favourite-filled";
ColumnFavIcon.megatype = "fav";
ColumnFavIcon.headerClassName = "grid-first-th fav";

},

168:
(__webpack_module__, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
A: () => _extends
});
function _extends() {
  return _extends = Object.assign ? Object.assign.bind() : function (n) {
    for (let e = 1; e < arguments.length; e++) {
      const t = arguments[e];
      for (const r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
    }
    return n;
  }, _extends.apply(null, arguments);
}


},

173:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  A: () => ContactsPanel
});

// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
// EXTERNAL MODULE: ./js/ui/buttons.jsx
const buttons = REQ_(994);
;// ./js/chat/ui/contactsPanel/navigation.jsx



const Navigation = ({
  view,
  receivedRequestsCount
}) => {
  const {
    VIEW,
    LABEL
  } = ContactsPanel;
  return REaCt().createElement("div", {
    className: "contacts-navigation"
  }, REaCt().createElement("ul", null, Object.keys(VIEW).map(key => {
    let activeClass = view === VIEW[key] ? 'active' : '';
    if (view === VIEW.PROFILE && VIEW[key] === VIEW.CONTACTS) {
      activeClass = 'active';
    }
    if (VIEW[key] !== VIEW.PROFILE) {
      return REaCt().createElement("li", {
        key,
        onClick: () => {
          let page = key.toLowerCase().split("_")[0];
          page = page === 'contacts' ? '' : page;
          loadSubPage(`fm/chat/contacts/${page}`);
        }
      }, REaCt().createElement(buttons.$, {
        className: `
                                        mega-button
                                        action
                                        ${activeClass}
                                    `,
        receivedRequestsCount
      }, REaCt().createElement("span", null, LABEL[key]), receivedRequestsCount > 0 && VIEW[key] === VIEW.RECEIVED_REQUESTS && REaCt().createElement("div", {
        className: "notifications-count"
      }, receivedRequestsCount > 9 ? '9+' : receivedRequestsCount)));
    }
    return null;
  })));
};
const navigation = Navigation;
// EXTERNAL MODULE: ./js/ui/utils.jsx
const utils = REQ_(314);
;// ./js/chat/ui/contactsPanel/nil.jsx



class Nil extends REaCt().Component {
  componentDidMount() {
    setContactLink();
  }
  render() {
    const {
      title
    } = this.props;
    return REaCt().createElement("div", {
      className: "fm-empty-section fm-empty-contacts"
    }, REaCt().createElement("div", {
      className: "fm-empty-pad"
    }, REaCt().createElement("i", {
      className: "section-icon sprite-fm-mono icon-contacts"
    }), REaCt().createElement("div", {
      className: "fm-empty-cloud-txt"
    }, title), REaCt().createElement("div", {
      className: "fm-empty-description"
    }, l[19115]), REaCt().createElement(buttons.$, {
      className: "mega-button positive large fm-empty-button",
      onClick: () => contactAddDialog()
    }, REaCt().createElement("span", null, l[71])), REaCt().createElement("div", {
      className: "empty-share-public"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-link-circle"
    }), REaCt().createElement(utils.P9, null, l[19111]))));
  }
}
// EXTERNAL MODULE: ./js/ui/jsx/fm/fmView.jsx + 10 modules
const fmView = REQ_(701);
// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
const contacts = REQ_(251);
// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/genericNodePropsComponent.jsx + 1 modules
const genericNodePropsComponent = REQ_(984);
;// ./js/ui/jsx/fm/nodes/columns/columnContactName.jsx




class ColumnContactName extends genericNodePropsComponent.B {
  constructor(...args) {
    super(...args);
    this.Mail = (0,utils.T9)(() => REaCt().createElement("span", {
      className: "contact-item-email"
    }, this.props.nodeAdapter.props.node.m));
  }
  static get label() {
    return l[86];
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {
      node
    } = nodeAdapter.props;
    return REaCt().createElement("td", null, REaCt().createElement(contacts.Avatar, {
      contact: node,
      className: "avatar-wrapper box-avatar"
    }), REaCt().createElement("div", {
      className: "contact-item"
    }, REaCt().createElement("div", {
      className: "contact-item-user"
    }, REaCt().createElement(utils.sp, null, nodeAdapter.nodeProps.title)), REaCt().createElement(this.Mail, null)), REaCt().createElement("div", {
      className: "clear"
    }));
  }
}
ColumnContactName.sortable = true;
ColumnContactName.id = "name";
ColumnContactName.megatype = "name";
;// ./js/ui/jsx/fm/nodes/columns/columnContactStatus.jsx


class ColumnContactStatus extends genericNodePropsComponent.B {
  static get label() {
    return l[89];
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {onlineStatus} = nodeAdapter.nodeProps;
    return REaCt().createElement("td", {
      megatype: ColumnContactStatus.megatype,
      className: ColumnContactStatus.megatype
    }, REaCt().createElement("div", {
      className: "contact-item"
    }, REaCt().createElement("div", {
      className: "contact-item-status"
    }, REaCt().createElement("div", {
      className: `user-card-presence ${  onlineStatus[1]}`
    }), onlineStatus[0])));
  }
}
ColumnContactStatus.sortable = true;
ColumnContactStatus.id = "status";
ColumnContactStatus.megatype = "status";
;// ./js/ui/jsx/fm/nodes/columns/columnContactLastInteraction.jsx


class ColumnContactLastInteraction extends genericNodePropsComponent.B {
  constructor(...args) {
    super(...args);
    this.getLastInteractionIcon = handle => {
      const {
        interactions
      } = this.props;
      const interaction = interactions[handle];
      const {
        type,
        time
      } = interaction || {
        type: undefined,
        time: undefined
      };
      return REaCt().createElement("i", {
        className: `
                    sprite-fm-mono
                    ${parseInt(type, 10) === 0 ? 'icon-cloud' : ''}
                    ${parseInt(type, 10) === 1 ? 'icon-chat' : ''}
                    ${!time ? 'icon-minimise' : ''}
                `
      });
    };
    this.getLastInteractionTime = handle => {
      const {
        interactions
      } = this.props;
      const interaction = interactions[handle];
      return interaction ? time2last(interaction.time) : l[1051];
    };
  }
  static get label() {
    return l[5904];
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {
      node
    } = nodeAdapter.props;
    return REaCt().createElement("td", {
      megatype: ColumnContactLastInteraction.megatype,
      className: ColumnContactLastInteraction.megatype
    }, REaCt().createElement("div", {
      className: "contact-item"
    }, REaCt().createElement("div", {
      className: "contact-item-time"
    }, this.getLastInteractionIcon(node.h), this.getLastInteractionTime(node.h))));
  }
}
ColumnContactLastInteraction.sortable = true;
ColumnContactLastInteraction.id = "interaction";
ColumnContactLastInteraction.megatype = "interaction";
;// ./js/ui/jsx/fm/nodes/columns/columnContactVerifiedStatus.jsx



class ColumnContactVerifiedStatus extends genericNodePropsComponent.B {
  constructor(...args) {
    super(...args);
    this.getFingerPrintDialogLink = handle => {
      const onVerifyContactClicked = handle => {
        ContactsPanel.verifyCredentials(this.props.contacts[handle]);
      };
      return REaCt().createElement("div", {
        className: "verify-contact-link-container"
      }, REaCt().createElement("div", {
        className: "verify-contact-link",
        onClick: () => onVerifyContactClicked(handle)
      }, l.verify_credentials));
    };
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {
      node
    } = nodeAdapter.props;
    return REaCt().createElement("td", {
      megatype: ColumnContactVerifiedStatus.megatype,
      className: ColumnContactVerifiedStatus.megatype
    }, REaCt().createElement("div", {
      className: "contact-item"
    }, REaCt().createElement("div", {
      className: "contact-item-verification"
    }, ContactsPanel.isVerified(this.props.contacts[node.h]) ? ColumnContactVerifiedStatus.verifiedLabel : this.getFingerPrintDialogLink(node.h))));
  }
}
ColumnContactVerifiedStatus.sortable = true;
ColumnContactVerifiedStatus.id = "verification";
ColumnContactVerifiedStatus.megatype = "verification";
ColumnContactVerifiedStatus.label = REaCt().createElement(REaCt().Fragment, null, l.contact_ver_verification, "\xA0", REaCt().createElement("i", {
  className: "simpletip sprite-fm-mono contacts-verification-icon icon-info",
  "data-simpletip": l.contact_ver_tooltip_content,
  "data-simpletip-class": "contacts-verification-icon-simpletip"
}));
ColumnContactVerifiedStatus.verifiedLabel = REaCt().createElement("div", {
  className: "verified-contact-label-container"
}, REaCt().createElement("i", {
  className: "small-icon icons-sprite tiny-green-tick"
}), l[6776]);
// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
const dropdowns = REQ_(911);
// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
const call = REQ_(3);
// EXTERNAL MODULE: ./js/chat/ui/conversations.jsx + 21 modules
const conversations = REQ_(732);
;// ./js/chat/ui/contactsPanel/contextMenu.jsx







class ContextMenu extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.EVENT_CLOSE = new Event('closeDropdowns');
    this.close = callback => {
      if (callback && typeof callback === 'function' && !M.isInvalidUserStatus()) {
        callback();
      }
      document.dispatchEvent(this.EVENT_CLOSE);
    };
    this.handleSetNickname = handle => this.close(() => nicknames.setNicknameDialog.init(handle));
    this.handleAddContact = handle => {
      M.syncContactEmail(handle, true).then(email => {
        const OPC = Object.values(M.opc);
        const ALREADY_SENT = OPC && OPC.length && OPC.some(opc => opc.m === email);
        this.close(() => {
          if (ALREADY_SENT) {
            return msgDialog('warningb', '', l[17545]);
          }
          msgDialog('info', l[150], l[5898]);
          M.inviteContact(M.u[u_handle].m, email);
        });
      }).catch(nop);
    };
  }
  render() {
    const {
      contact,
      selected,
      withProfile
    } = this.props;
    if (ContactsPanel.hasRelationship(contact)) {
      return REaCt().createElement(REaCt().Fragment, null, withProfile && REaCt().createElement("div", {
        className: "dropdown-avatar rounded",
        onClick: e => {
          e.stopPropagation();
          loadSubPage(`fm/chat/contacts/${contact.h}`);
        }
      }, REaCt().createElement(contacts.Avatar, {
        contact,
        className: "avatar-wrapper context-avatar"
      }), REaCt().createElement("div", {
        className: "dropdown-profile"
      }, REaCt().createElement("span", null, REaCt().createElement(utils.zT, null, M.getNameByHandle(contact.u))), REaCt().createElement(contacts.ContactPresence, {
        contact
      }))), REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-chat",
        label: l[8632],
        onClick: () => this.close(() => {
          if (selected && selected.length) {
            return megaChat.createAndShowGroupRoomFor(selected, '', {
              keyRotation: true,
              createChatLink: false
            });
          }
          loadSubPage(`fm/chat/p/${contact.u}`);
          megaChat.trigger(conversations.qY.NAV_RENDER_VIEW, conversations.Vw.CHATS);
        })
      }), REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-send-files",
        label: l[6834],
        onClick: () => this.close(() => megaChat.openChatAndSendFilesDialog(contact.u))
      }), REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-folder-outgoing-share",
        label: l[5631],
        onClick: () => this.close(() => openCopyShareDialog(contact.u))
      }), REaCt().createElement("div", {
        "data-simpletipposition": "top",
        className: "simpletip",
        "data-simpletip": !megaChat.hasSupportForCalls ? l.call_not_suported : ''
      }, REaCt().createElement(dropdowns.DropdownItem, {
        submenu: megaChat.hasSupportForCalls,
        disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
        icon: "sprite-fm-mono icon-phone",
        className: "sprite-fm-mono-before icon-arrow-right-before",
        label: l[19125]
      }), REaCt().createElement("div", {
        className: "dropdown body submenu"
      }, REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-phone",
        disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
        label: l[5896],
        onClick: () => (0,call.dQ)().then(() => this.close(() => megaChat.createAndShowPrivateRoom(contact.u).then(room => {
          room.setActive();
          room.startAudioCall();
        }))).catch(() => d && console.warn('Already in a call.'))
      }), REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-video-call-filled",
        disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
        label: l[5897],
        onClick: () => (0,call.dQ)().then(() => this.close(() => megaChat.createAndShowPrivateRoom(contact.u).then(room => {
          room.setActive();
          room.startVideoCall();
        }))).catch(() => d && console.warn('Already in a call.'))
      }))), REaCt().createElement("hr", null), withProfile && REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-my-account",
        label: l[5868],
        onClick: () => loadSubPage(`fm/chat/contacts/${contact.u}`)
      }), REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-rename",
        label: contact.nickname === '' ? l.set_nickname_label : l.edit_nickname_label,
        onClick: () => this.handleSetNickname(contact.u)
      }), REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
        submenu: true,
        icon: "sprite-fm-mono icon-key",
        className: "sprite-fm-mono-before icon-arrow-right-before",
        label: l[6872]
      }), REaCt().createElement("div", {
        className: "dropdown body white-context-menu submenu"
      }, ContactsPanel.isVerified(contact) ? REaCt().createElement(dropdowns.DropdownItem, {
        label: l[742],
        onClick: () => this.close(() => ContactsPanel.resetCredentials(contact))
      }) : REaCt().createElement(dropdowns.DropdownItem, {
        label: l[1960],
        onClick: () => this.close(() => ContactsPanel.verifyCredentials(contact))
      })), REaCt().createElement("div", {
        className: "dropdown-credentials"
      }, ContactsPanel.getUserFingerprint(contact.u)), REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-disable",
        label: l[1001],
        disabled: !!contact.b,
        className: "",
        onClick: () => this.close(() => fmremove(contact.u))
      }));
    }
    return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(dropdowns.DropdownItem, {
      icon: "sprite-fm-mono icon-disabled-filled",
      label: l[71],
      onClick: () => this.handleAddContact(contact.u)
    }), REaCt().createElement(dropdowns.DropdownItem, {
      icon: "sprite-fm-mono icon-rename",
      label: contact.nickname === '' ? l.set_nickname_label : l.edit_nickname_label,
      onClick: () => this.handleSetNickname(contact.u)
    }));
  }
}
;// ./js/ui/jsx/fm/nodes/columns/columnContactButtons.jsx







class ColumnContactButtons extends genericNodePropsComponent.B {
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {
      node,
      selected
    } = nodeAdapter.props;
    const handle = node.h;
    return REaCt().createElement("td", {
      megatype: ColumnContactButtons.megatype,
      className: ColumnContactButtons.megatype
    }, REaCt().createElement("div", {
      className: "contact-item"
    }, REaCt().createElement("div", {
      className: "contact-item-controls"
    }, REaCt().createElement(buttons.$, {
      className: "mega-button action simpletip",
      icon: "sprite-fm-mono icon-phone",
      attrs: {
        'data-simpletip': !megaChat.hasSupportForCalls ? l.unsupported_browser_audio : l[5896]
      },
      disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
      onClick: () => (0,call.dQ)().then(() => megaChat.createAndShowPrivateRoom(handle).then(room => {
        room.setActive();
        room.startAudioCall();
      })).catch(() => d && console.warn('Already in a call.'))
    }), REaCt().createElement(buttons.$, {
      className: "mega-button action simpletip",
      icon: "sprite-fm-mono icon-chat",
      attrs: {
        'data-simpletip': l[8632]
      },
      onClick: () => {
        loadSubPage(`fm/chat/p/${handle}`);
        megaChat.trigger(conversations.qY.NAV_RENDER_VIEW, conversations.Vw.CHATS);
      }
    }), REaCt().createElement(buttons.$, {
      className: "mega-button action simpletip",
      icon: "sprite-fm-mono icon-send-files",
      attrs: {
        'data-simpletip': l[6834]
      },
      onClick: () => megaChat.openChatAndSendFilesDialog(handle)
    }), REaCt().createElement(buttons.$, {
      ref: node => {
        this.props.onContextMenuRef(handle, node);
      },
      className: "mega-button action contact-more",
      icon: "sprite-fm-mono icon-options"
    }, REaCt().createElement(dropdowns.Dropdown, {
      className: "context",
      noArrow: true,
      positionMy: "left bottom",
      positionAt: "right bottom",
      positionLeft: this.props.contextMenuPosition || null,
      horizOffset: 4,
      onActiveChange: opened => {
        this.props.onActiveChange(opened);
      }
    }, REaCt().createElement(ContextMenu, {
      contact: node,
      selected,
      withProfile: true
    }))))));
  }
}
ColumnContactButtons.sortable = false;
ColumnContactButtons.id = "grid-url-header-nw";
ColumnContactButtons.label = "";
ColumnContactButtons.megatype = "grid-url-header-nw";
// EXTERNAL MODULE: ./js/chat/ui/updateObserver.jsx
const updateObserver = REQ_(501);
;// ./js/chat/ui/contactsPanel/contactList.jsx










class ContactList extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.contextMenuRefs = [];
    this.state = {
      selected: [],
      searchValue: null,
      interactions: {},
      contextMenuPosition: null
    };
    this.onSelected = this.onSelected.bind(this);
    this.onHighlighted = this.onHighlighted.bind(this);
    this.onExpand = this.onExpand.bind(this);
    this.onAttachClicked = this.onAttachClicked.bind(this);
    this.getLastInteractions = this.getLastInteractions.bind(this);
  }
  getLastInteractions() {
    const {
      contacts
    } = this.props;
    const promises = [];
    const push = handle => {
      promises.push(Promise.resolve(getLastInteractionWith(handle, true, true)).then(ts => [ts, handle]));
    };
    for (const handle in contacts) {
      if (contacts[handle].c === 1) {
        push(handle);
      }
    }
    Promise.allSettled(promises).then(res => {
      if (this.isMounted()) {
        const interactions = {};
        for (let i = res.length; i--;) {
          if (res[i].status !== 'fulfilled') {
            if (d && res[i].reason !== false) {
              console.warn('getLastInteractions', res[i].reason);
            }
          } else {
            const [ts, u] = res[i].value;
            const [type, time] = ts.split(':');
            interactions[u] = {
              u,
              type,
              time
            };
          }
        }
        this.setState({
          interactions
        });
      }
    }).catch(ex => {
      console.error("Failed to handle last interactions!", ex);
    });
  }
  handleContextMenu(ev, handle) {
    ev.preventDefault();
    ev.persist();
    if (this.state.selected.length > 1) {
      return null;
    }
    const $$REF = this.contextMenuRefs[handle];
    if ($$REF && $$REF.isMounted()) {
      let _$$REF$domRef;
      const refNodePosition = ((_$$REF$domRef = $$REF.domRef) == null ? void 0 : _$$REF$domRef.current) && $$REF.domRef.current.getBoundingClientRect().x;
      this.setState({
        contextMenuPosition: ev.clientX > refNodePosition ? null : ev.clientX
      }, () => $$REF.onClick(ev));
    }
  }
  onSelected(handle) {
    this.setState({
      'selected': handle
    });
  }
  onHighlighted(handle) {
    this.setState({
      'highlighted': handle
    });
  }
  onExpand(handle) {
    loadSubPage(`/fm/chat/contacts/${  handle}`);
  }
  onAttachClicked() {
    if (this.state.selected[0]) {
      this.onExpand(this.state.selected[0]);
    }
  }
  componentDidMount() {
    super.componentDidMount();
    this.getLastInteractions();
  }
  render() {
    const {
      contacts
    } = this.props;
    if (contacts && contacts.length > 1) {
      return REaCt().createElement("div", {
        ref: this.domRef,
        className: "contacts-list"
      }, REaCt().createElement(fmView.A, {
        dataSource: contacts,
        customFilterFn: r => {
          return r.c === 1;
        },
        currentlyViewedEntry: "contacts",
        onSelected: this.onSelected,
        onHighlighted: this.onHighlighted,
        searchValue: this.state.searchValue,
        onExpand: this.onExpand,
        onAttachClicked: this.onAttachClicked,
        viewMode: 0,
        currentdirid: "contacts",
        megaListItemHeight: 59,
        headerContainerClassName: "contacts-table contacts-table-head",
        containerClassName: "contacts-table contacts-table-results",
        onContextMenu: (ev, handle) => this.handleContextMenu(ev, handle),
        listAdapterColumns: [ColumnContactName, ColumnContactStatus, [ColumnContactLastInteraction, {
          interactions: this.state.interactions
        }], [ColumnContactVerifiedStatus, {
          contacts
        }], [ColumnContactButtons, {
          onContextMenuRef: (handle, node) => {
            this.contextMenuRefs[handle] = node;
          },
          onActiveChange: opened => {
            if (!opened) {
              this.setState({
                contextMenuPosition: null
              });
            }
          },
          contextMenuPosition: this.state.contextMenuPosition
        }]],
        initialSortBy: ['status', 'asc'],
        fmConfigSortEnabled: true,
        fmConfigSortId: "contacts",
        NilComponent: REaCt().createElement(Nil, {
          title: l[5737]
        })
      }));
    }
    return REaCt().createElement(Nil, {
      title: l[5737]
    });
  }
}
ContactList.updateListener = 'getLastInteractions';
ContactList.updateInterval = 6e4;
const contactList = (0,mixins.Zz)(updateObserver.Y)(ContactList);
;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsEmail.jsx



class ColumnContactRequestsEmail extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
  }
  static get label() {
    return l[95];
  }
  render() {
    const {
      nodeAdapter,
      currView
    } = this.props;
    const {
      node
    } = nodeAdapter.props;
    return REaCt().createElement("td", {
      ref: this.domRef
    }, currView && currView === 'opc' ? REaCt().createElement("span", null, REaCt().createElement("i", {
      className: "sprite-fm-uni icon-send-requests"
    })) : REaCt().createElement(utils.P9, null, useravatar.contact(node.m, 'box-avatar')), REaCt().createElement("div", {
      className: "contact-item"
    }, REaCt().createElement("div", {
      className: "contact-item-user"
    }, node.m)), REaCt().createElement("div", {
      className: "clear"
    }));
  }
}
ColumnContactRequestsEmail.sortable = true;
ColumnContactRequestsEmail.id = "email";
ColumnContactRequestsEmail.megatype = "email";
;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsTs.jsx


class ColumnContactRequestsTs extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
  }
  static get label() {
    return l[19506];
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {
      node
    } = nodeAdapter.props;
    let timestamp = node.rts || node.ts;
    if (timestamp) {
      timestamp = time2last(timestamp);
    } else {
      timestamp = node.dts ? l[6112] : "";
    }
    return REaCt().createElement("td", {
      ref: this.domRef
    }, REaCt().createElement("div", {
      className: "contact-item"
    }, REaCt().createElement("div", {
      className: "contact-item-time"
    }, timestamp)), REaCt().createElement("div", {
      className: "clear"
    }));
  }
}
ColumnContactRequestsTs.sortable = true;
ColumnContactRequestsTs.id = "ts";
ColumnContactRequestsTs.megatype = "ts";
;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsRcvdBtns.jsx



class ColumnContactRequestsRcvdBtns extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {
      node
    } = nodeAdapter.props;
    return REaCt().createElement("td", {
      ref: this.domRef,
      megatype: ColumnContactRequestsRcvdBtns.megatype,
      className: ColumnContactRequestsRcvdBtns.megatype
    }, REaCt().createElement("div", {
      className: "contact-item-controls"
    }, REaCt().createElement(buttons.$, {
      className: "mega-button action contact-reject",
      icon: "sprite-fm-mono icon-close-component",
      label: l[20981],
      onClick: () => this.props.onReject(node.p)
    }), REaCt().createElement(buttons.$, {
      className: "mega-button action contact-block",
      icon: "sprite-fm-mono icon-disable",
      label: l[20980],
      onClick: () => this.props.onBlock(node.p)
    }), REaCt().createElement(buttons.$, {
      className: "mega-button action contact-accept",
      icon: "sprite-fm-mono icon-check",
      label: l[5856],
      onClick: () => this.props.onAccept(node.p)
    })));
  }
}
ColumnContactRequestsRcvdBtns.sortable = true;
ColumnContactRequestsRcvdBtns.id = "grid-url-header-nw";
ColumnContactRequestsRcvdBtns.label = "";
ColumnContactRequestsRcvdBtns.megatype = "grid-url-header-nw contact-controls-container";
;// ./js/chat/ui/contactsPanel/receivedRequests.jsx






const ReceivedRequests = ({
  received
}) => {
  return REaCt().createElement("div", {
    className: "contacts-list"
  }, REaCt().createElement(fmView.A, {
    sortFoldersFirst: false,
    dataSource: received,
    customFilterFn: r => {
      return !r.dts;
    },
    currentlyViewedEntry: "ipc",
    onSelected: nop,
    onHighlighted: nop,
    onExpand: nop,
    onAttachClicked: nop,
    viewMode: 0,
    currentdirid: "ipc",
    megaListItemHeight: 59,
    headerContainerClassName: "contacts-table requests-table contacts-table-head",
    containerClassName: "contacts-table requests-table contacts-table-results",
    listAdapterColumns: [[ColumnContactRequestsEmail, {
      currView: "ipc"
    }], [ColumnContactRequestsTs, {
      label: l[19505]
    }], [ColumnContactRequestsRcvdBtns, {
      onReject: handle => {
        M.denyPendingContactRequest(handle).catch(dump);
      },
      onBlock: handle => {
        M.ignorePendingContactRequest(handle).catch(dump);
      },
      onAccept: handle => {
        M.acceptPendingContactRequest(handle).catch(dump);
      }
    }]],
    keyProp: "p",
    nodeAdapterProps: {
      'className': node => {
        return `
                        ${node.dts || node.s && node.s === 3 ? 'deleted' : ''}
                        ${node.s && node.s === 1 ? 'ignored' : ''}
                    `;
      }
    },
    NilComponent: () => {
      return REaCt().createElement(Nil, {
        title: l[6196]
      });
    },
    initialSortBy: ['email', 'asc'],
    fmConfigSortEnabled: true,
    fmConfigSortId: "ipc"
  }));
};
const receivedRequests = ReceivedRequests;
;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsSentBtns.jsx



class ColumnContactRequestsSentBtns extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.reinviteAllowed = rts => {
      const UTC_DATE_NOW = Math.floor(Date.now() / 1000);
      return UTC_DATE_NOW > rts + 1209600;
    };
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {
      node
    } = nodeAdapter.props;
    return REaCt().createElement("td", {
      ref: this.domRef,
      megatype: ColumnContactRequestsSentBtns.megatype,
      className: ColumnContactRequestsSentBtns.megatype
    }, REaCt().createElement("div", {
      className: "contact-item-controls contact-request-sent"
    }, !node.dts && this.reinviteAllowed(node.rts) && REaCt().createElement(buttons.$, {
      className: "mega-button action",
      icon: "sprite-fm-mono icon-rewind",
      label: l[5861],
      onClick: () => this.props.onReinvite(node.m)
    }), !node.dts && REaCt().createElement(buttons.$, {
      className: "mega-button action contact-reject",
      icon: "sprite-fm-mono icon-close-component",
      label: l.msg_dlg_cancel,
      onClick: () => this.props.onReject(node.m)
    })));
  }
}
ColumnContactRequestsSentBtns.sortable = true;
ColumnContactRequestsSentBtns.id = "grid-url-header-nw";
ColumnContactRequestsSentBtns.label = "";
ColumnContactRequestsSentBtns.megatype = "grid-url-header-nw contact-controls-container";
;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsRts.jsx


class ColumnContactRequestsRts extends ColumnContactRequestsTs {
  static get label() {
    return l[19506];
  }
}
ColumnContactRequestsRts.sortable = true;
ColumnContactRequestsRts.id = "rts";
ColumnContactRequestsRts.megatype = "rts";
;// ./js/chat/ui/contactsPanel/sentRequests.jsx






const SentRequests = ({
  sent
}) => {
  return REaCt().createElement("div", {
    className: "contacts-list"
  }, REaCt().createElement(fmView.A, {
    sortFoldersFirst: false,
    dataSource: sent,
    currentlyViewedEntry: "opc",
    onSelected: nop,
    onHighlighted: nop,
    onExpand: nop,
    onAttachClicked: nop,
    viewMode: 0,
    currentdirid: "opc",
    megaListItemHeight: 59,
    headerContainerClassName: "contacts-table requests-table contacts-table-head",
    containerClassName: "contacts-table requests-table contacts-table-results",
    listAdapterColumns: [[ColumnContactRequestsEmail, {
      currView: "opc"
    }], ColumnContactRequestsRts, [ColumnContactRequestsSentBtns, {
      onReject: email => {
        M.cancelPendingContactRequest(email).catch(ex => {
          if (ex === EARGS) {
            msgDialog('info', '', 'This pending contact is already deleted.');
          } else {
            tell(ex);
          }
        });
      },
      onReinvite: email => {
        M.reinvitePendingContactRequest(email).then(() => contactsInfoDialog(l[19126], email, l[19127])).catch(tell);
      }
    }]],
    NilComponent: () => {
      return REaCt().createElement(Nil, {
        title: l[6196]
      });
    },
    listAdapterOpts: {
      'className': node => node.dts && ' disabled'
    },
    keyProp: "p",
    initialSortBy: ['email', 'asc'],
    fmConfigSortEnabled: true,
    fmConfigSortMap: {
      'rts': 'rTimeStamp'
    },
    fmConfigSortId: "opc"
  }));
};
const sentRequests = SentRequests;
// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/columns/columnFavIcon.jsx
const columnFavIcon = REQ_(161);
;// ./js/ui/jsx/fm/nodes/columns/columnSharedFolderName.jsx


class ColumnSharedFolderName extends genericNodePropsComponent.B {
  static get label() {
    return l[86];
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {
      node
    } = nodeAdapter.props;
    return REaCt().createElement("td", {
      megatype: ColumnSharedFolderName.megatype,
      className: ColumnSharedFolderName.megatype
    }, REaCt().createElement("div", {
      className: "item-type-icon-90 icon-folder-incoming-90 sprite-fm-uni-after icon-warning-after"
    }), REaCt().createElement("div", {
      className: "shared-folder-info-block"
    }, REaCt().createElement("div", {
      className: "shared-folder-name"
    }, missingkeys[node.h] ? l[8686] : nodeAdapter.nodeProps.title), REaCt().createElement("div", {
      className: "shared-folder-info"
    }, fm_contains(node.tf, node.td))));
  }
}
ColumnSharedFolderName.sortable = true;
ColumnSharedFolderName.id = "name";
ColumnSharedFolderName.megatype = "name";
;// ./js/ui/jsx/fm/nodes/columns/columnSharedFolderAccess.jsx


class ColumnSharedFolderAccess extends genericNodePropsComponent.B {
  static get label() {
    return l[5906];
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    return REaCt().createElement("td", {
      megatype: ColumnSharedFolderAccess.megatype,
      className: ColumnSharedFolderAccess.megatype
    }, REaCt().createElement("div", {
      className: "shared-folder-access"
    }, REaCt().createElement("i", {
      className: `
                            sprite-fm-mono
                            ${nodeAdapter.nodeProps.incomingShareData.accessIcon}
                        `
    }), REaCt().createElement("span", null, nodeAdapter.nodeProps.incomingShareData.accessLabel)));
  }
}
ColumnSharedFolderAccess.sortable = true;
ColumnSharedFolderAccess.id = 'access';
ColumnSharedFolderAccess.megatype = 'access';
;// ./js/ui/jsx/fm/nodes/columns/columnSharedFolderButtons.jsx



class ColumnSharedFolderButtons extends genericNodePropsComponent.B {
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {
      node
    } = nodeAdapter.props;
    const handle = node.h;
    return REaCt().createElement("td", {
      megatype: ColumnSharedFolderButtons.megatype,
      className: ColumnSharedFolderButtons.megatype
    }, REaCt().createElement("div", {
      className: "contact-item"
    }, REaCt().createElement("div", {
      className: "contact-item-controls"
    }, REaCt().createElement(buttons.$, {
      className: "mega-button action contact-more",
      icon: "sprite-fm-mono icon-options",
      onClick: (button, e) => {
        e.persist();
        $.selected = [handle];
        e.preventDefault();
        e.stopPropagation();
        e.delegateTarget = $(e.target).parents('td')[0];
        e.currentTarget = $(e.target).parents('tr');
        if (!$(e.target).hasClass('active')) {
          M.contextMenuUI(e, 1);
          $(this).addClass('active');
        } else {
          $.hideContextMenu();
          $(e.target).removeClass('active');
        }
      }
    }))));
  }
}
ColumnSharedFolderButtons.sortable = true;
ColumnSharedFolderButtons.id = "grid-url-header-nw";
ColumnSharedFolderButtons.label = "";
ColumnSharedFolderButtons.megatype = "grid-url-header-nw";
// EXTERNAL MODULE: ./js/chat/ui/link.jsx
const ui_link = REQ_(280);
;// ./js/chat/ui/contactsPanel/contactProfile.jsx
















class ContactProfile extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.state = {
      selected: [],
      loading: true
    };
    this.onAttachClicked = () => {
      const {
        selected
      } = this.state;
      if (selected[0]) {
        this.onExpand(selected[0]);
      }
    };
    this.onExpand = handle => loadSubPage(`fm/${handle}`);
    this.Breadcrumb = () => {
      const {
        handle
      } = this.props;
      return REaCt().createElement("div", {
        className: "profile-breadcrumb"
      }, REaCt().createElement("ul", null, REaCt().createElement("li", null, REaCt().createElement(ui_link.A, {
        to: "/fm/chat/contacts"
      }, ContactsPanel.LABEL.CONTACTS), REaCt().createElement("i", {
        className: "sprite-fm-mono icon-arrow-right"
      })), REaCt().createElement("li", null, REaCt().createElement(utils.zT, null, M.getNameByHandle(handle)))));
    };
    this.Credentials = () => {
      const {
        handle
      } = this.props;
      const contact = M.u[handle];
      if (handle && contact && contact.c === 1) {
        const IS_VERIFIED = ContactsPanel.isVerified(contact);
        return REaCt().createElement("div", {
          className: "profile-credentials"
        }, REaCt().createElement("span", {
          className: "credentials-head"
        }, l[6872]), REaCt().createElement("div", {
          className: "credentials-fingerprints"
        }, ContactsPanel.getUserFingerprint(handle)), REaCt().createElement("button", {
          className: `
                            mega-button
                            small
                            ${IS_VERIFIED ? '' : 'positive'}
                        `,
          onClick: () => ContactsPanel[IS_VERIFIED ? 'resetCredentials' : 'verifyCredentials'](contact)
        }, IS_VERIFIED ? l[742] : l.verify_credentials));
      }
      return null;
    };
    this.handleContextMenu = (e, handle) => {
      e.persist();
      e.preventDefault();
      e.stopPropagation();
      e.delegateTarget = e.target.tagName === "TR" ? e.target : $(e.target).parents('tr')[0];
      e.currentTarget = $(e.delegateTarget);
      $.selected = [handle];
      M.contextMenuUI(e, 1);
    };
  }
  UNSAFE_componentWillMount() {
    if (super.UNSAFE_componentWillMount) {
      super.UNSAFE_componentWillMount();
    }
    const {
      handle
    } = this.props;
    if (handle) {
      const contact = M.u[handle];
      if (contact) {
        this._listener = contact.addChangeListener(() => {
          if (contact && contact.c === 1) {
            this.safeForceUpdate();
          } else {
            loadSubPage("/fm/chat/contacts");
            return 0xDEAD;
          }
        });
      }
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    if (this._listener) {
      const {
        handle
      } = this.props;
      const contact = M.u[handle];
      contact.removeChangeListener(this._listener);
    }
  }
  componentDidMount() {
    super.componentDidMount();
    dbfetch.geta(Object.keys(M.c.shares || {}), new MegaPromise()).finally(() => {
      if (this.isMounted()) {
        this.setState({
          'loading': false
        });
      }
    });
  }
  getSharedFoldersView() {
    return this.state.loading ? null : REaCt().createElement(fmView.A, {
      currentlyViewedEntry: this.props.handle,
      onSelected: handle => this.setState({
        selected: handle
      }),
      onHighlighted: nop,
      searchValue: this.state.searchValue,
      onExpand: this.onExpand,
      onAttachClicked: this.onAttachClicked,
      viewMode: 0,
      currentdirid: "shares",
      megaListItemHeight: 65,
      headerContainerClassName: "grid-table-header",
      containerClassName: "grid-table shared-with-me",
      onContextMenu: (ev, handle) => this.handleContextMenu(ev, handle),
      listAdapterColumns: [columnFavIcon.$, [ColumnSharedFolderName, {
        'label': `${l.shared_folders_from.replace('%NAME', M.getNameByHandle(this.props.handle))}`
      }], ColumnSharedFolderAccess, ColumnSharedFolderButtons]
    });
  }
  render() {
    const {
      handle
    } = this.props;
    if (handle) {
      const contact = M.u[handle];
      if (!contact || contact.c !== 1) {
        return REaCt().createElement(Nil, {
          title: l.contact_not_found
        });
      }
      const HAS_RELATIONSHIP = ContactsPanel.hasRelationship(contact);
      return REaCt().createElement("div", {
        ref: this.domRef,
        className: "contacts-profile"
      }, REaCt().createElement(this.Breadcrumb, null), REaCt().createElement("div", {
        className: "profile-content"
      }, REaCt().createElement("div", {
        className: "profile-head"
      }, HAS_RELATIONSHIP && REaCt().createElement(this.Credentials, null), REaCt().createElement(contacts.Avatar, {
        contact,
        className: "profile-photo avatar-wrapper contacts-medium-avatar"
      }), REaCt().createElement("div", {
        className: "profile-info"
      }, REaCt().createElement("h2", null, REaCt().createElement(utils.zT, null, M.getNameByHandle(handle)), REaCt().createElement(contacts.ContactPresence, {
        contact
      })), REaCt().createElement("span", null, contact.m)), HAS_RELATIONSHIP && REaCt().createElement("div", {
        className: "profile-controls"
      }, REaCt().createElement(buttons.$, {
        className: "mega-button round simpletip",
        icon: "sprite-fm-mono icon-chat-filled",
        attrs: {
          'data-simpletip': l[8632]
        },
        onClick: () => {
          loadSubPage(`fm/chat/p/${handle}`);
          megaChat.trigger(conversations.qY.NAV_RENDER_VIEW, conversations.Vw.CHATS);
        }
      }), REaCt().createElement(buttons.$, {
        className: "mega-button round simpletip",
        icon: "sprite-fm-mono icon-send-files",
        attrs: {
          'data-simpletip': l[6834]
        },
        onClick: () => {
          if (M.isInvalidUserStatus()) {
            return;
          }
          megaChat.openChatAndSendFilesDialog(handle);
        }
      }), REaCt().createElement(buttons.$, {
        className: "mega-button round",
        icon: "sprite-fm-mono icon-options"
      }, REaCt().createElement(dropdowns.Dropdown, {
        className: "context",
        noArrow: true,
        positionMy: "left bottom",
        positionAt: "right bottom",
        horizOffset: 4
      }, REaCt().createElement(ContextMenu, {
        contact
      }))))), REaCt().createElement("div", {
        className: "profile-shared-folders"
      }, this.getSharedFoldersView())));
    }
    return null;
  }
}
;// ./js/chat/ui/contactsPanel/contactsPanel.jsx







class ContactsPanel extends mixins.w9 {
  get view() {
    switch (megaChat.routingSubSection) {
      case null:
        return ContactsPanel.VIEW.CONTACTS;
      case "contact":
        return ContactsPanel.VIEW.PROFILE;
      case "received":
        return ContactsPanel.VIEW.RECEIVED_REQUESTS;
      case "sent":
        return ContactsPanel.VIEW.SENT_REQUESTS;
      default:
        console.error("Shouldn't happen.");
        return false;
    }
  }
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.requestReceivedListener = null;
    this.state = {
      receivedRequestsCount: 0
    };
    this.handleToggle = ({
      keyCode
    }) => {
      if (keyCode === 27) {
        const HAS_DIALOG_OPENED = $.dialog || ['.contact-nickname-dialog', '.fingerprint-dialog', '.context'].some(selector => {
          const dialog = document.querySelector(selector);
          return dialog && dialog.offsetHeight > 0;
        });
        return HAS_DIALOG_OPENED ? keyCode : loadSubPage('fm/chat');
      }
    };
    this.handleAcceptAllRequests = () => {
      const {
        received
      } = this.props;
      const receivedKeys = Object.keys(received || {});
      if (receivedKeys.length) {
        for (let i = receivedKeys.length; i--;) {
          M.acceptPendingContactRequest(receivedKeys[i]).catch(dump);
        }
      }
    };
    this.renderView = () => {
      const {
        contacts,
        received,
        sent
      } = this.props;
      const {
        view
      } = this;
      switch (view) {
        case ContactsPanel.VIEW.CONTACTS:
          return REaCt().createElement(contactList, {
            contacts
          });
        case ContactsPanel.VIEW.PROFILE:
          return REaCt().createElement(ContactProfile, {
            handle: view === ContactsPanel.VIEW.PROFILE && megaChat.routingParams
          });
        case ContactsPanel.VIEW.RECEIVED_REQUESTS:
          return REaCt().createElement(receivedRequests, {
            received
          });
        case ContactsPanel.VIEW.SENT_REQUESTS:
          return REaCt().createElement(sentRequests, {
            sent
          });
      }
    };
    this.state.receivedRequestsCount = Object.keys(M.ipc).length;
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    document.documentElement.removeEventListener(ContactsPanel.EVENTS.KEYDOWN, this.handleToggle);
    if (this.requestReceivedListener) {
      mBroadcaster.removeListener(this.requestReceivedListener);
    }
  }
  componentDidMount() {
    super.componentDidMount();
    document.documentElement.addEventListener(ContactsPanel.EVENTS.KEYDOWN, this.handleToggle);
    this.requestReceivedListener = mBroadcaster.addListener('fmViewUpdate:ipc', () => this.setState({
      receivedRequestsCount: Object.keys(M.ipc).length
    }));
  }
  render() {
    const {
      view,
      state
    } = this;
    const {
      receivedRequestsCount
    } = state;
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "contacts-panel"
    }, REaCt().createElement(navigation, {
      view,
      contacts: this.props.contacts,
      receivedRequestsCount
    }), view !== ContactsPanel.VIEW.PROFILE && REaCt().createElement("div", {
      className: "contacts-actions"
    }, view === ContactsPanel.VIEW.RECEIVED_REQUESTS && receivedRequestsCount > 1 && REaCt().createElement("button", {
      className: "mega-button action",
      onClick: this.handleAcceptAllRequests
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-check"
    }), REaCt().createElement("span", null, l[19062]))), REaCt().createElement("div", {
      className: "contacts-content"
    }, this.renderView()));
  }
}
ContactsPanel.EVENTS = {
  KEYDOWN: 'keydown'
};
ContactsPanel.VIEW = {
  CONTACTS: 0x00,
  RECEIVED_REQUESTS: 0x01,
  SENT_REQUESTS: 0x02,
  PROFILE: 0x03
};
ContactsPanel.LABEL = {
  CONTACTS: l[165],
  RECEIVED_REQUESTS: l[5863],
  SENT_REQUESTS: l[5862]
};
ContactsPanel.hasContacts = () => M.u.some(contact => contact.c === 1);
ContactsPanel.hasRelationship = contact => contact && contact.c === 1;
ContactsPanel.isVerified = contact => {
  if (contact && contact.u) {
    const {
      u: handle
    } = contact;
    const verificationState = u_authring.Ed25519[handle] || {};
    return verificationState.method >= authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON;
  }
  return null;
};
ContactsPanel.verifyCredentials = contact => {
  if (contact.c === 1 && u_authring && u_authring.Ed25519) {
    const verifyState = u_authring.Ed25519[contact.u] || {};
    if (typeof verifyState.method === "undefined" || verifyState.method < authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON) {
      fingerprintDialog(contact.u);
    }
  }
};
ContactsPanel.resetCredentials = contact => {
  if (M.isInvalidUserStatus()) {
    return;
  }
  authring.resetFingerprintsForUser(contact.u).then(() => contact.trackDataChange()).catch(dump);
};
ContactsPanel.getUserFingerprint = handle => {
  const $$FINGERPRINT = [];
  userFingerprint(handle, fingerprints => {
    for (let i = 0; i < fingerprints.length; i++) {
      $$FINGERPRINT.push(REaCt().createElement("span", {
        key: i
      }, fingerprints[i]));
    }
  });
  return $$FINGERPRINT;
};

},

206:
(module) => {

"use strict";
module.exports = ReactDOM;

},

251:
(_, EXP_, REQ_) => {

"use strict";
REQ_.r(EXP_);
REQ_.d(EXP_, {
Avatar: () => Avatar,
ContactAwareName: () => ContactAwareName,
ContactButton: () => ContactButton,
ContactCard: () => ContactCard,
ContactFingerprint: () => ContactFingerprint,
ContactItem: () => ContactItem,
ContactPickerDialog: () => ContactPickerDialog,
ContactPickerWidget: () => ContactPickerWidget,
ContactPresence: () => ContactPresence,
ContactVerified: () => ContactVerified,
LastActivity: () => LastActivity,
MAX_FREQUENTS: () => MAX_FREQUENTS,
MembersAmount: () => MembersAmount
});
const _extends0__ = REQ_(168);
const react1__ = REQ_(594);
const react1 = REQ_.n(react1__);
const _mixins2__ = REQ_(137);
const _ui_utils_jsx3__ = REQ_(314);
const _ui_perfectScrollbar_jsx4__ = REQ_(486);
const _ui_buttons_jsx5__ = REQ_(994);
const _ui_dropdowns_jsx6__ = REQ_(911);
const _contactsPanel_contactsPanel_jsx7__ = REQ_(173);
const _ui_modalDialogs8__ = REQ_(318);
const _link_jsx9__ = REQ_(280);
const _updateObserver_jsx10__ = REQ_(501);












const MAX_FREQUENTS = 3;
const closeDropdowns = () => {
  document.dispatchEvent(new Event('closeDropdowns'));
};
class ContactButton extends _mixins2__.u9 {
  constructor(props) {
    super(props);
    this.dropdownItemGenerator = this.dropdownItemGenerator.bind(this);
  }
  customIsEventuallyVisible() {
    if (this.props.chatRoom) {
      return this.props.chatRoom.isCurrentlyActive;
    }
    return -1;
  }
  dropdownItemGenerator() {
    let {
      contact,
      dropdowns,
      chatRoom,
      dropdownRemoveButton
    } = this.props;
    dropdowns = dropdowns ? dropdowns : [];
    const moreDropdowns = [];
    moreDropdowns.push(react1().createElement("div", {
      className: "dropdown-avatar rounded",
      key: "mainContactInfo",
      onClick: () => {
        if (contact.c === 2) {
          loadSubPage('fm/account');
        }
        if (contact.c === 1) {
          loadSubPage(`fm/chat/contacts/${  contact.u}`);
        }
      }
    }, react1().createElement(Avatar, {
      className: "avatar-wrapper context-avatar",
      chatRoom,
      contact,
      hideVerifiedBadge: "true"
    }), react1().createElement("div", {
      className: "dropdown-user-name"
    }, react1().createElement("div", {
      className: "name"
    }, react1().createElement(ContactAwareName, {
      overflow: true,
      contact
    }), react1().createElement(ContactPresence, {
      className: "small",
      contact
    })), contact && (megaChat.FORCE_EMAIL_LOADING || contact.c === 1 || contact.c === 2) && react1().createElement("span", {
      className: "email"
    }, contact.m))));
    moreDropdowns.push(react1().createElement(ContactFingerprint, {
      key: "fingerprint",
      contact
    }));
    if (dropdowns.length && contact.c !== 2) {
      moreDropdowns.push(dropdowns);
      moreDropdowns.push(react1().createElement("hr", {
        key: "top-separator"
      }));
    }
    if (contact.u === u_handle) {
      moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
        key: "view0",
        icon: "sprite-fm-mono icon-user-filled",
        label: l[187],
        onClick: () => loadSubPage('fm/account')
      }));
    }
    if (contact.c === 1) {
      const startAudioCall = () => {
        megaChat.createAndShowPrivateRoom(contact.u).then(room => {
          room.setActive();
          room.startAudioCall();
        });
      };
      if (megaChat.currentlyOpenedChat && megaChat.currentlyOpenedChat === contact.u) {
        moreDropdowns.push(react1().createElement("div", {
          key: "startAudioVideoCall",
          "data-simpletipposition": "top",
          className: "simpletip",
          "data-simpletip": !megaChat.hasSupportForCalls ? l.call_not_suported : ''
        }, react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
          disabled: !megaChat.hasSupportForCalls,
          key: "startCall",
          className: "sprite-fm-mono-before icon-arrow-right-before",
          icon: "sprite-fm-mono icon-phone",
          submenu: megaChat.hasSupportForCalls,
          label: l[19125]
        }), react1().createElement("div", {
          className: "dropdown body submenu",
          key: "dropdownGroup"
        }, react1().createElement("div", null, react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
          key: "startAudio",
          icon: "sprite-fm-mono icon-phone",
          disabled: !megaChat.hasSupportForCalls,
          label: l[1565],
          onClick: startAudioCall
        })), react1().createElement("div", null, react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
          key: "startVideo",
          icon: "sprite-fm-mono icon-video-call-filled",
          disabled: !megaChat.hasSupportForCalls,
          label: l[1566],
          onClick: () => {
            megaChat.createAndShowPrivateRoom(contact.u).then(room => {
              room.setActive();
              room.startVideoCall();
            });
          }
        })))));
      } else {
        moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
          key: "startChat",
          icon: "sprite-fm-mono icon-chat",
          label: l[5885],
          onClick: () => {
            loadSubPage(`fm/chat/p/${  contact.u}`);
          }
        }));
      }
      moreDropdowns.push(react1().createElement("hr", {
        key: "files-separator"
      }));
      moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
        key: "send-files-item",
        icon: "sprite-fm-mono icon-send-files",
        label: l[6834],
        disabled: mega.paywall,
        onClick: () => {
          megaChat.openChatAndSendFilesDialog(contact.u);
        }
      }));
      moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
        key: "share-item",
        icon: "sprite-fm-mono icon-folder-outgoing-share",
        label: l[6775],
        onClick: () => {
          openCopyShareDialog(contact.u);
        }
      }));
    } else if (!is_chatlink && !is_eplusplus && (!contact.c || contact.c === 2 && contact.u !== u_handle)) {
      moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
        key: "view2",
        icon: "sprite-fm-mono icon-add",
        label: l[101],
        onClick: () => {
          const isAnonymousUser = !u_handle || u_type !== 3;
          const ADD_CONTACT = 'addContact';
          if (is_chatlink && isAnonymousUser) {
            megaChat.loginOrRegisterBeforeJoining(undefined, undefined, undefined, true);
            if (localStorage.getItem(ADD_CONTACT) === null) {
              localStorage.setItem(ADD_CONTACT, JSON.stringify({
                u: contact.u,
                unixTime: unixtime()
              }));
            }
          } else {
            loadingDialog.show();
            M.syncContactEmail(contact.u, true).then(email => {
              if (Object.values(M.opc || {}).some(cr => cr.m === email)) {
                closeDialog();
                msgDialog('warningb', '', l[17545]);
              } else {
                M.inviteContact(M.u[u_handle].m, email);
                const title = l[150];
                const msg = l[5898].replace('[X]', email);
                closeDialog();
                msgDialog('info', title, msg.replace('[X]', email));
              }
            }).catch(() => {
              const {
                chatRoom
              } = this.props;
              const {
                u: userHandle
              } = contact;
              if (chatRoom.call) {
                return mBroadcaster.sendMessage('meetings:ephemeralAdd', userHandle);
              }
              const name = M.getNameByHandle(userHandle);
              return msgDialog('info', '', l.ephemeral_title ? l.ephemeral_title.replace('%1', name) : `${name} is using an ephemeral session.`, l.ephemeral_info);
            }).finally(() => loadingDialog.hide());
          }
        }
      }));
    }
    if (u_attr && contact.u !== u_handle) {
      if (moreDropdowns.length > 0 && !(moreDropdowns.length === 2 && moreDropdowns[1] && moreDropdowns[1].key === "fingerprint")) {
        moreDropdowns.push(react1().createElement("hr", {
          key: "nicknames-separator"
        }));
      }
      moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
        key: "set-nickname",
        icon: "sprite-fm-mono icon-rename",
        label: contact.nickname === '' ? l.set_nickname_label : l.edit_nickname_label,
        onClick: () => nicknames.setNicknameDialog.init(contact.u)
      }));
    }
    if (dropdownRemoveButton && dropdownRemoveButton.length) {
      moreDropdowns.push(react1().createElement("hr", {
        key: "remove-separator"
      }));
      moreDropdowns.push(dropdownRemoveButton);
    }
    return moreDropdowns;
  }
  render() {
    let {
      label = '',
      className = '',
      contact,
      dropdownIconClasses = [],
      verticalOffset,
      dropdownDisabled,
      noLoading,
      noContextMenu
    } = this.props;
    let dropdownPosition = "left top";
    let vertOffset = 0;
    let horizOffset = -30;
    if (!contact) {
      return null;
    }
    if (label) {
      className = `user-card-name ${className}${className.includes('message') ? '' : ' selectable-txt'}`;
      dropdownIconClasses = '';
      dropdownPosition = 'left bottom';
      vertOffset = 25;
      horizOffset = 0;
    }
    if (typeof verticalOffset !== 'undefined') {
      vertOffset = verticalOffset;
    }
    if (!contact.name && !contact.m && !noLoading && this.isLoadingContactInfo()) {
      label = react1().createElement("em", {
        className: "contact-name-loading"
      });
      className = `contact-button-loading ${className}`;
    }
    return noContextMenu ? react1().createElement("div", {
      className: "user-card-name light selectable-txt"
    }, label) : react1().createElement(_ui_buttons_jsx5__.$, {
      className,
      icon: dropdownIconClasses,
      disabled: dropdownDisabled,
      label
    }, react1().createElement(_ui_dropdowns_jsx6__.Dropdown, {
      className: "context contact-card-dropdown",
      positionMy: dropdownPosition,
      positionAt: dropdownPosition,
      vertOffset,
      horizOffset,
      dropdownItemGenerator: this.dropdownItemGenerator,
      noArrow: true
    }));
  }
}
ContactButton.defaultProps = {
  'manualDataChangeTracking': true,
  'skipQueuedUpdatesOnResize': true
};
class ContactVerified extends _mixins2__.w9 {
  attachRerenderCallbacks() {
    this.addDataStructListenerForProperties(this.props.contact, ['fingerprint']);
  }
  render() {
    if (is_chatlink) {
      return null;
    }
    const {contact} = this.props;
    if (!contact) {
      return null;
    }
    if (u_authring && u_authring.Ed25519) {
      const verifyState = u_authring.Ed25519[contact.u] || {};
      if (verifyState.method >= authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON) {
        return react1().createElement("div", {
          className: `
                            user-card-verified
                            ${this.props.className || ''}
                        `
        });
      }
    } else if (!pubEd25519[contact.u]) {
      crypt.getPubEd25519(contact.u).then(() => {
        if (pubEd25519[contact.u]) {
          this.safeForceUpdate();
        }
      });
    }
    return null;
  }
}
ContactVerified.defaultProps = {
  'manualDataChangeTracking': true,
  'skipQueuedUpdatesOnResize': true
};
class ContactPresence extends _mixins2__.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = react1().createRef();
  }
  attachRerenderCallbacks() {
    this.addDataStructListenerForProperties(this.props.contact, ['presence']);
  }
  render() {
    const {
      contact,
      className
    } = this.props;
    if (!contact || !contact.c) {
      return null;
    }
    return react1().createElement("div", {
      ref: this.domRef,
      className: `
                    user-card-presence
                    ${megaChat.userPresenceToCssClass(contact.presence)}
                    ${className || ''}
                `
    });
  }
}
ContactPresence.defaultProps = {
  manualDataChangeTracking: true,
  skipQueuedUpdatesOnResize: true
};
const LastActivity = (0,_mixins2__.Zz)(_updateObserver_jsx10__.Y)((() => class LastActivity extends _mixins2__.u9 {
  attachRerenderCallbacks() {
    this._attachRerenderCbContacts(['ats', 'lastGreen', 'presence']);
  }
  shouldComponentUpdate() {
    return true;
  }
  render() {
    const {
      contact,
      showLastGreen
    } = this.props;
    if (!contact) {
      return null;
    }
    const lastActivity = !contact.ats || contact.lastGreen > contact.ats ? contact.lastGreen : contact.ats;
    const SECONDS = Date.now() / 1000 - lastActivity;
    const timeToLast = SECONDS > 3888000 ? l[20673] : time2last(lastActivity, true);
    const hasActivityStatus = showLastGreen && contact.presence <= 2 && lastActivity;
    return react1().createElement("span", null, hasActivityStatus ? (l[19994] || 'Last seen %s').replace('%s', timeToLast) : M.onlineStatusClass(contact.presence)[0]);
  }
})());
class ContactAwareName extends _mixins2__.u9 {
  render() {
    const {
      contact,
      emoji,
      overflow
    } = this.props;
    if (!contact || !M.u[contact.u || contact.h]) {
      return null;
    }
    const name = M.getNameByHandle(contact.u || contact.h);
    if (emoji || overflow) {
      const EmojiComponent = overflow ? _ui_utils_jsx3__.sp : _ui_utils_jsx3__.zT;
      return react1().createElement(EmojiComponent, this.props, name);
    }
    return react1().createElement("span", null, name);
  }
}
class MembersAmount extends _mixins2__.u9 {
  render() {
    const {
      chatRoom
    } = this.props;
    return react1().createElement("span", null, mega.icu.format(l[20233], Object.keys(chatRoom.members).length));
  }
}
class ContactFingerprint extends _mixins2__.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = react1().createRef();
  }
  attachRerenderCallbacks() {
    this.addDataStructListenerForProperties(this.props.contact, ['fingerprint']);
  }
  render() {
    const {
      contact,
      className
    } = this.props;
    if (!contact || !contact.u || is_chatlink) {
      return null;
    }
    const infoBlocks = [];
    userFingerprint(contact.u, (fingerprints) => {
      fingerprints.forEach((v, k) => {
        infoBlocks.push(react1().createElement("span", {
          key: `fingerprint-${  k}`
        }, v));
      });
    });
    let verifyButton = null;
    if (contact.c === 1 && u_authring && u_authring.Ed25519) {
      const verifyState = u_authring.Ed25519[contact.u] || {};
      if (typeof verifyState.method === "undefined" || verifyState.method < authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON) {
        verifyButton = react1().createElement(_ui_buttons_jsx5__.$, {
          className: "dropdown-verify active",
          label: l.verify_credentials,
          icon: "sprite-fm-mono icon-key",
          onClick: () => {
            closeDropdowns();
            fingerprintDialog(contact.u);
          }
        });
      }
    }
    return infoBlocks.length ? react1().createElement("div", {
      ref: this.domRef,
      className: `
                        dropdown-fingerprint
                        ${className || ''}
                    `
    }, react1().createElement("div", {
      className: "contact-fingerprint-title"
    }, react1().createElement("span", null, l[6872])), react1().createElement("div", {
      className: "contact-fingerprint-txt selectable-txt"
    }, infoBlocks), verifyButton) : null;
  }
}
ContactFingerprint.defaultProps = {
  'manualDataChangeTracking': true,
  'skipQueuedUpdatesOnResize': true
};
class Avatar extends _mixins2__.u9 {
  render() {
    const self = this;
    const {contact} = this.props;
    if (!contact) {
      return null;
    }
    if (!contact.m && contact.email) {
      contact.m = contact.email;
    }
    const avatarMeta = useravatar.generateContactAvatarMeta(contact);
    let classes = `${this.props.className ? this.props.className : ' avatar-wrapper small-rounded-avatar'  } ${  contact.u  } in-chat`;
    classes += " chat-avatar";
    let displayedAvatar;
    let verifiedElement = null;
    if (!this.props.hideVerifiedBadge && !is_chatlink) {
      verifiedElement = react1().createElement(ContactVerified, {
        contact: this.props.contact,
        className: this.props.verifiedClassName
      });
    }
    const extraProps = {};
    if (this.props.simpletip) {
      classes += " simpletip";
      if (this.props.simpletip === true) {
        extraProps['data-simpletip'] = M.getNameByHandle(contact.h || contact.u) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER;
      } else {
        extraProps['data-simpletip'] = this.props.simpletip;
      }
      if (this.props.simpletipWrapper) {
        extraProps['data-simpletipwrapper'] = this.props.simpletipWrapper;
      }
      if (this.props.simpletipOffset) {
        extraProps['data-simpletipoffset'] = this.props.simpletipOffset;
      }
      if (this.props.simpletipPosition) {
        extraProps['data-simpletipposition'] = this.props.simpletipPosition;
      }
      if (this.props.simpletipClass) {
        extraProps['data-simpletip-class'] = this.props.simpletipClass;
      }
    }
    if (avatarMeta.type === "image") {
      displayedAvatar = react1().createElement("div", (0,_extends0__.A)({
        className: classes,
        style: this.props.style
      }, extraProps, {
        onClick: self.props.onClick ? e => {
          closeDropdowns();
          self.props.onClick(e);
        } : self.onClick
      }), verifiedElement, react1().createElement("img", {
        src: avatarMeta.avatar,
        style: this.props.imgStyles
      }));
    } else {
      classes += ` color${  avatarMeta.avatar.colorIndex}`;
      const isLoading = self.isLoadingContactInfo();
      if (isLoading) {
        classes += " default-bg";
      }
      displayedAvatar = react1().createElement("div", (0,_extends0__.A)({
        className: classes,
        style: this.props.style
      }, extraProps, {
        onClick: self.props.onClick ? e => {
          closeDropdowns();
          self.props.onClick(e);
        } : self.onClick
      }), verifiedElement, react1().createElement("span", null, isLoading ? "" : avatarMeta.avatar.letters));
    }
    return displayedAvatar;
  }
}
Avatar.defaultProps = {
  'manualDataChangeTracking': true,
  'skipQueuedUpdatesOnResize': true
};
class ContactCard extends _mixins2__.u9 {
  attachRerenderCallbacks() {
    this._attachRerenderCbContacts(['presence']);
  }
  specShouldComponentUpdate(nextProps, nextState) {
    const foundKeys = Object.keys(this.props);
    if (foundKeys.includes('dropdowns')) {
      array.remove(foundKeys, 'dropdowns', true);
    }
    let shouldUpdate;
    if (foundKeys.length) {
      const k = foundKeys[0];
      shouldUpdate = shallowEqual(nextProps[k], this.props[k]);
    }
    if (!shouldUpdate) {
      shouldUpdate = shallowEqual(nextState, this.state);
    }
    if (!shouldUpdate && this.state.props.dropdowns && nextProps.state.dropdowns && this.state.props.dropdowns.map && nextProps.state.dropdowns.map) {
      const oldKeys = this.state.props.dropdowns.map(child => child.key);
      const newKeys = nextProps.state.dropdowns.map(child => child.key);
      if (!shallowEqual(oldKeys, newKeys)) {
        shouldUpdate = true;
      }
    }
    return shouldUpdate;
  }
  render() {
    let _this$props$chatRoom;
    const {
      contact
    } = this.props;
    if (!contact) {
      return null;
    }
    const pres = megaChat.userPresenceToCssClass(contact.presence);
    let username = (this.props.namePrefix || '') + (M.getNameByHandle(contact.u) || contact.m);
    if (contact.u === u_handle) {
      username += ` (${escapeHTML(l[8885])})`;
    }
    let escapedUsername = react1().createElement(_ui_utils_jsx3__.sp, null, username);
    const dropdowns = this.props.dropdowns || [];
    const noContextMenu = this.props.noContextMenu || '';
    const noContextButton = this.props.noContextButton || '';
    const dropdownRemoveButton = this.props.dropdownRemoveButton || [];
    const highlightSearchValue = this.props.highlightSearchValue || false;
    const emailTooltips = this.props.emailTooltips || false;
    const searchValue = this.props.searchValue || "";
    let usernameBlock;
    if (!noContextMenu) {
      usernameBlock = react1().createElement(ContactButton, {
        key: "lnk",
        dropdowns,
        noContextMenu,
        contact,
        className: "light",
        label: escapedUsername,
        chatRoom: this.props.chatRoom,
        dropdownRemoveButton,
        verticalOffset: 0
      });
    } else {
      if (highlightSearchValue && searchValue.length > 0) {
        const matches = [];
        const regex = new RegExp(RegExpEscape(searchValue), 'gi');
        let result;
        while (result = regex.exec(username)) {
          matches.push({
            idx: result.index,
            str: result[0]
          });
        }
        if (matches.length > 0) {
          escapedUsername = react1().createElement(_ui_utils_jsx3__.P9, null, megaChat.highlight(megaChat.html(username), matches, true));
        }
      }
      usernameBlock = emailTooltips ? react1().createElement("div", {
        className: "user-card-name light simpletip selectable-txt",
        "data-simpletip": contact.m,
        "data-simpletipposition": "top"
      }, escapedUsername) : react1().createElement("div", {
        className: "user-card-name light selectable-txt"
      }, escapedUsername);
    }
    let userCard = null;
    const className = this.props.className || '';
    userCard = className.includes('short') ? react1().createElement("div", {
      className: "user-card-data"
    }, usernameBlock, react1().createElement("div", {
      className: "user-card-status"
    }, this.props.isInCall ? react1().createElement("div", {
      className: "audio-call"
    }, react1().createElement("i", {
      className: "sprite-fm-mono icon-phone"
    })) : null, react1().createElement(LastActivity, {
      contact,
      showLastGreen: this.props.showLastGreen
    }))) : react1().createElement("div", {
      className: "user-card-data"
    }, usernameBlock, react1().createElement(ContactPresence, {
      contact,
      className: this.props.presenceClassName
    }), this.props.isInCall ? react1().createElement("div", {
      className: "audio-call"
    }, react1().createElement("i", {
      className: "sprite-fm-mono icon-phone"
    })) : null, react1().createElement("div", {
      className: "user-card-email selectable-txt"
    }, contact.m));
    return react1().createElement("div", {
      className: `
                    contacts-info body
                    ${pres === 'offline' ? 'offline' : ''}
                    ${className || ''}
                `,
      style: this.props.style,
      onClick: ev => {
        let _this$props$onClick, _this$props;
        return (_this$props$onClick = (_this$props = this.props).onClick) == null ? void 0 : _this$props$onClick.call(_this$props, contact, ev);
      },
      onDoubleClick: ev => {
        let _this$props$onDoubleC, _this$props2;
        return (_this$props$onDoubleC = (_this$props2 = this.props).onDoubleClick) == null ? void 0 : _this$props$onDoubleC.call(_this$props2, contact, ev);
      }
    }, this.props.withSelfNote ? react1().createElement("div", {
      className: `
                            note-chat-signifier
                            ${(_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.hasMessages() ? '' : 'note-chat-empty'}
                        `
    }, react1().createElement("i", {
      className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
    })) : react1().createElement(Avatar, {
      className: "avatar-wrapper small-rounded-avatar",
      contact,
      chatRoom: this.props.chatRoom
    }), is_chatlink || noContextButton ? null : react1().createElement(ContactButton, {
      key: "button",
      dropdowns,
      dropdownIconClasses: this.props.dropdownIconClasses || '',
      disabled: this.props.dropdownDisabled,
      noContextMenu,
      contact,
      className: this.props.dropdownButtonClasses,
      dropdownRemoveButton,
      noLoading: this.props.noLoading,
      chatRoom: this.props.chatRoom,
      verticalOffset: 0
    }), this.props.selectable ? react1().createElement("div", {
      className: "user-card-tick-wrap"
    }, react1().createElement("i", {
      className: "sprite-fm-mono icon-check"
    })) : null, megaChat.WITH_SELF_NOTE && this.props.withSelfNote ? react1().createElement("div", {
      className: "user-card-data"
    }, react1().createElement("div", {
      className: "user-card-name light selectable-txt note-chat-label"
    }, l.note_label), react1().createElement("div", {
      className: "user-card-status"
    })) : userCard);
  }
}
ContactCard.defaultProps = {
  dropdownButtonClasses: "tiny-button",
  dropdownIconClasses: "tiny-icon icons-sprite grey-dots",
  presenceClassName: '',
  manualDataChangeTracking: true,
  skipQueuedUpdatesOnResize: true
};
class ContactItem extends _mixins2__.u9 {
  render() {
    const self = this;
    const {contact} = this.props;
    if (!contact) {
      return null;
    }
    const username = this.props.namePrefix ? this.props.namePrefix : `${  M.getNameByHandle(contact.u)}`;
    return react1().createElement("div", {
      className: "selected-contact-card short"
    }, react1().createElement("div", {
      className: "remove-contact-bttn",
      onClick: e => {
        if (self.props.onClick) {
          self.props.onClick(contact, e);
        }
      }
    }, react1().createElement("i", {
      className: "tiny-icon small-cross"
    })), react1().createElement(Avatar, {
      contact,
      className: "avatar-wrapper small-rounded-avatar",
      hideVerifiedBadge: true,
      chatRoom: this.props.chatRoom
    }), react1().createElement("div", {
      className: "user-card-data simpletip",
      "data-simpletip": username || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER,
      "data-simpletipposition": "top"
    }, react1().createElement(ContactButton, {
      noContextMenu: this.props.noContextMenu,
      contact,
      className: "light",
      label: react1().createElement(_ui_utils_jsx3__.zT, null, username),
      chatRoom: this.props.chatRoom
    })));
  }
}
ContactItem.defaultProps = {
  'manualDataChangeTracking': true,
  'skipQueuedUpdatesOnResize': true
};
class ContactPickerWidget extends _mixins2__.w9 {
  constructor(...args) {
    super(...args);
    this.contactLinkListener = null;
    this.domRef = react1().createRef();
    this.state = {
      searchValue: '',
      selected: this.props.selected || [],
      publicLink: M.account && M.account.contactLink || undefined
    };
    this.normalize = input => ChatSearch._normalize_str(String(input || '').toLowerCase());
    this.onSearchChange = ev => {
      this.setState({
        searchValue: ev.target.value
      });
    };
    this.renderParticipantsList = () => {
      const {
        contacts,
        emailTooltips,
        onSelected
      } = this.props;
      const {
        selected
      } = this.state;
      const $$list = contacts.map(handle => {
        const added = selected.includes(handle);
        return react1().createElement(ContactCard, {
          key: handle,
          className: `
                            contacts-search short
                            ${added ? 'selected' : ''}
                        `,
          contact: M.u[handle],
          selectable: true,
          emailTooltips,
          noContextButton: true,
          noContextMenu: true,
          onClick: () => {
            this.setState({
              selected: added ? selected.filter(h => h !== handle) : [...selected, handle]
            }, () => onSelected(this.state.selected));
          }
        });
      });
      return react1().createElement(_ui_perfectScrollbar_jsx4__.O, {
        className: "contacts-search-scroll",
        selected,
        contacts
      }, react1().createElement("div", {
        className: "contacts-search-subsection"
      }, react1().createElement("div", {
        className: "contacts-list-header"
      }, megaChat.activeCall ? l.call_participants : l[16217]), react1().createElement("div", {
        className: "contacts-search-list"
      }, $$list)));
    };
  }
  renderInviteWarning() {
    const {
      chatRoom
    } = this.props;
    const {
      activeCall
    } = megaChat;
    if (!activeCall || activeCall.chatRoom.chatId !== chatRoom.chatId || !activeCall.sfuClient.callLimits || !activeCall.sfuClient.callLimits.usr || chatRoom.getCallParticipants().length < activeCall.sfuClient.callLimits.usr) {
      return null;
    }
    return react1().createElement("div", {
      className: "picker-user-limit-banner"
    }, activeCall.organiser === u_handle ? (0,_ui_utils_jsx3__.lI)(l.invite_limit_banner_organiser, '[A]', _link_jsx9__.A, {
      onClick() {
        window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
        eventlog(500263);
      }
    }) : l.invite_limit_banner_host);
  }
  componentDidMount() {
    super.componentDidMount();
    setContactLink(this.domRef && this.domRef.current);
    this.contactLinkListener = mBroadcaster.addListener('contact:setContactLink', publicLink => this.state.publicLink ? null : this.setState({
      publicLink
    }));
  }
  componentDidUpdate() {
    const self = this;
    if (self.scrollToLastSelected && self.psSelected) {
      self.scrollToLastSelected = false;
      self.psSelected.scrollToPercentX(100, false);
    }
    if (self.searchContactsScroll) {
      self.searchContactsScroll.reinitialise();
    }
  }
  UNSAFE_componentWillMount() {
    if (super.UNSAFE_componentWillMount) {
      super.UNSAFE_componentWillMount();
    }
    const self = this;
    if (self.props.multiple) {
      $(document.body).rebind(`keypress.contactPicker${  self.getUniqueId()}`, (e) => {
        const keyCode = e.which || e.keyCode;
        if (keyCode === 13) {
          if (self.state.selected) {
            e.preventDefault();
            e.stopPropagation();
            closeDropdowns();
            if (self.props.onSelectDone) {
              self.props.onSelectDone(self.state.selected);
            }
          }
        }
      });
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    const self = this;
    delete self._foundFrequents;
    if (self.props.multiple) {
      $(document.body).off(`keypress.contactPicker${  self.getUniqueId()}`);
    }
    if (this.contactLinkListener) {
      mBroadcaster.removeListener(this.contactLinkListener);
    }
  }
  _eventuallyAddContact(v, contacts, selectableContacts, forced) {
    const self = this;
    const withSelfNote = this.props.withSelfNote && v.u === u_handle;
    if (v.u === u_handle && !this.props.step && !withSelfNote) {
      return false;
    }
    if (!forced && v.c !== 1 && v.u !== u_handle) {
      return false;
    }
    if (self.props.exclude && self.props.exclude.indexOf(v.u) > -1) {
      return false;
    }
    let isDisabled = false;
    if (!self.wasMissingKeysForContacts) {
      self.wasMissingKeysForContacts = {};
    }
    if (!self.wasMissingKeysForContacts[v.u] && (!pubCu25519[v.u] || !pubEd25519[v.u])) {
      self.wasMissingKeysForContacts[v.u] = true;
      ChatdIntegration._ensureKeysAreLoaded(undefined, [v.u]).always(() => {
        if (self.isMounted()) {
          self.safeForceUpdate();
        }
      });
      isDisabled = true;
      return true;
    } else if (self.wasMissingKeysForContacts[v.u] && (!pubCu25519[v.u] || !pubEd25519[v.u])) {
      return false;
    }
    if (self.state.searchValue && self.state.searchValue.length > 0) {
      const searchValue = this.normalize(this.state.searchValue);
      const {
        name,
        nickname,
        fullname,
        u,
        m
      } = {
        ...v,
        name: withSelfNote ? l.note_label : v.name
      };
      const matches = [name, nickname, fullname, M.getNameByHandle(u), !this.props.skipMailSearch && m].some(field => this.normalize(field).includes(searchValue));
      if (!matches) {
        return false;
      }
    }
    let selectedClass = "";
    if (self.state.selected && self.state.selected.indexOf(v.u) !== -1) {
      selectedClass = "selected";
    }
    contacts.push(react1().createElement(ContactCard, {
      withSelfNote,
      disabled: isDisabled,
      contact: v,
      chatRoom: withSelfNote && megaChat.getNoteChat(),
      className: `contacts-search short ${  selectedClass  }${isDisabled ? " disabled" : ""}`,
      noContextButton: "true",
      selectable: selectableContacts,
      onClick: self.props.readOnly ? () => {} : contact => {
        if (isDisabled) {
          return false;
        }
        const contactHash = contact.u;
        if (contactHash === self.lastClicked && new Date() - self.clickTime < 500 && !self.props.disableDoubleClick || !self.props.multiple) {
          if (self.props.onSelected) {
            self.props.onSelected([contactHash]);
          }
          self.props.onSelectDone([contactHash]);
          closeDropdowns();
          return;
        } else {
          const selected = clone(self.state.selected || []);
          if (selected.indexOf(contactHash) === -1) {
            selected.push(contactHash);
            self.scrollToLastSelected = true;
            if (self.props.onSelected) {
              self.props.onSelected(selected);
            }
          } else {
            if (selected.indexOf(contactHash) >= 0) {
              array.remove(selected, contactHash);
            }
            if (self.props.onSelected) {
              self.props.onSelected(selected);
            }
          }
          self.setState({
            selected
          });
          if (self.props.selectCleanSearchRes) {
            self.setState({
              'searchValue': ''
            });
          }
          if (self.props.autoFocusSearchField) {
            let _self$contactSearchFi;
            (_self$contactSearchFi = self.contactSearchField) == null || _self$contactSearchFi.focus();
          }
        }
        self.clickTime = new Date();
        self.lastClicked = contactHash;
      },
      noContextMenu: true,
      searchValue: self.state.searchValue,
      highlightSearchValue: self.props.highlightSearchValue,
      emailTooltips: self.props.emailTooltips,
      key: v.u
    }));
    if (typeof this.props.onEventuallyUpdated === 'function') {
      this.props.onEventuallyUpdated();
    }
    return true;
  }
  render() {
    const self = this;
    let contacts = [];
    const frequentContacts = [];
    let extraClasses = "";
    const contactsSelected = [];
    let multipleContacts = null;
    let selectableContacts = false;
    let selectFooter = null;
    let selectedContacts = false;
    const isSearching = !!self.state.searchValue;
    megaChat.getNoteChat();
    const onAddContact = e => {
      e.preventDefault();
      e.stopPropagation();
      contactAddDialog();
      if (this.props.onClose) {
        this.props.onClose();
      }
    };
    if (self.props.readOnly) {
      const sel = self.state.selected || [];
      for (let i = 0; i < sel.length; i++) {
        const v = sel[i];
        contactsSelected.push(react1().createElement(ContactItem, {
          contact: M.u[v],
          key: v,
          chatRoom: self.props.chatRoom
        }));
      }
    } else if (self.props.multiple) {
      selectableContacts = true;
      const onSelectDoneCb = e => {
        e.preventDefault();
        e.stopPropagation();
        closeDropdowns();
        if (self.props.onSelectDone) {
          self.props.onSelectDone(self.state.selected);
        }
      };
      let onContactSelectDoneCb = contact => {
        const contactHash = contact.u;
        if (contactHash === self.lastClicked && new Date() - self.clickTime < 500) {
          if (self.props.onSelected) {
            self.props.onSelected([contactHash]);
          }
          self.props.onSelectDone([contactHash]);
          return;
        } else {
          const selected = clone(self.state.selected || []);
          if (selected.indexOf(contactHash) === -1) {
            selected.push(contactHash);
            self.scrollToLastSelected = true;
            if (self.props.onSelected) {
              self.props.onSelected(selected);
            }
          } else {
            if (selected.indexOf(contactHash) >= 0) {
              array.remove(selected, contactHash);
            }
            if (self.props.onSelected) {
              self.props.onSelected(selected);
            }
          }
          self.setState({
            selected
          });
          if (self.props.selectCleanSearchRes) {
            self.setState({
              'searchValue': ''
            });
          }
          if (self.props.autoFocusSearchField) {
            let _self$contactSearchFi2;
            (_self$contactSearchFi2 = self.contactSearchField) == null || _self$contactSearchFi2.focus();
          }
        }
        self.clickTime = new Date();
        self.lastClicked = contactHash;
      };
      const selectedWidthSize = self.props.selectedWidthSize || 54;
      const selectedWidth = self.state.selected.length * selectedWidthSize;
      if (!self.state.selected || self.state.selected.length === 0) {
        selectedContacts = false;
        const emptySelectionMsg = self.props.emptySelectionMsg || l[8889];
        multipleContacts = react1().createElement("div", {
          className: "horizontal-contacts-list"
        }, react1().createElement("div", {
          className: "contacts-list-empty-txt"
        }, self.props.nothingSelectedButtonLabel ? self.props.nothingSelectedButtonLabel : emptySelectionMsg));
      } else {
        selectedContacts = true;
        onContactSelectDoneCb = onContactSelectDoneCb.bind(self);
        const sel2 = self.state.selected || [];
        for (let i2 = 0; i2 < sel2.length; i2++) {
          const v2 = sel2[i2];
          contactsSelected.push(react1().createElement(ContactItem, {
            key: v2,
            chatRoom: self.props.chatRoom || false,
            contact: M.u[v2],
            noContextMenu: true,
            onClick: onContactSelectDoneCb
          }));
        }
        multipleContacts = react1().createElement("div", {
          className: "horizontal-contacts-list"
        }, react1().createElement(_ui_perfectScrollbar_jsx4__.O, {
          className: "perfectScrollbarContainer selected-contact-block horizontal-only",
          selected: this.state.selected,
          ref (psSelected) {
            self.psSelected = psSelected;
          }
        }, react1().createElement("div", {
          className: "select-contact-centre",
          style: {
            width: selectedWidth
          }
        }, contactsSelected)));
      }
      if (self.props.selectFooter) {
        selectFooter = react1().createElement("footer", null, react1().createElement("button", {
          className: "mega-button",
          onClick: onAddContact.bind(self)
        }, react1().createElement("span", null, l[71])), react1().createElement("div", {
          className: "footer-spacing"
        }), react1().createElement("button", {
          className: `mega-button ${selectedContacts ? '' : 'disabled'}`,
          onClick (e) {
            if (self.state.selected.length > 0) {
              onSelectDoneCb(e);
            }
          }
        }, react1().createElement("span", null, this.props.multipleSelectedButtonLabel ? this.props.multipleSelectedButtonLabel : l[8890])));
      }
    }
    const alreadyAdded = {};
    let hideFrequents = !self.props.readOnly && !self.state.searchValue && frequentContacts.length > 0;
    let frequentsLoading = false;
    if (this.props.readOnly || this.props.disableFrequents) {
      hideFrequents = true;
      this._foundFrequents = [];
    } else if (!self._foundFrequents) {
      frequentsLoading = true;
      this._foundFrequents = [];
      megaChat.getFrequentContacts().then(res => {
        this._foundFrequents = res.slice(Math.max(res.length - 30, 0), res.length).reverse();
      }).catch(dump).finally(() => {
        if (this.isMounted()) {
          this.safeForceUpdate();
        }
      });
    }
    for (let i = this._foundFrequents.length, total = 0; total < MAX_FREQUENTS && i--;) {
      const v = this._foundFrequents[i];
      if (v.userId in M.u && this._eventuallyAddContact(M.u[v.userId], frequentContacts, selectableContacts)) {
        alreadyAdded[v.userId] = 1;
        total++;
      }
    }
    self.props.contacts.forEach((v) => {
      alreadyAdded[v.h] || self._eventuallyAddContact(v, contacts, selectableContacts);
    });
    const sortFn = M.getSortByNameFn2(1);
    contacts.sort((a, b) => {
      return b.props.withSelfNote - a.props.withSelfNote || sortFn(a.props.contact, b.props.contact);
    });
    if (Object.keys(alreadyAdded).length === 0) {
      hideFrequents = true;
    }
    const innerDivStyles = {};
    if (this.props.showMeAsSelected) {
      self._eventuallyAddContact(M.u[u_handle], contacts, selectableContacts, true);
    }
    let noOtherContacts = false;
    if (contacts.length === 0 || !_contactsPanel_contactsPanel_jsx7__.A.hasContacts() && this.props.step !== 1) {
      noOtherContacts = true;
      let noContactsMsg = "";
      if (M.u.length < 2) {
        noContactsMsg = l[8877];
      } else {
        noContactsMsg = l[8878];
      }
      if (hideFrequents) {
        contacts = react1().createElement("em", null, noContactsMsg);
      }
    }
    const haveContacts = isSearching || frequentContacts.length !== 0 || !noOtherContacts;
    let contactsList;
    if (haveContacts) {
      if (frequentContacts.length === 0 && noOtherContacts) {
        if (self.props.newEmptySearchResult) {
          contactsList = react1().createElement("div", {
            className: "chat-contactspicker-no-contacts flex flex-column flex-center searching mt-2"
          }, react1().createElement("div", {
            className: "section-icon sprite-fm-mono icon-contacts"
          }), react1().createElement("div", {
            className: "fm-empty-cloud-txt small"
          }, l[8674]));
        } else {
          contactsList = react1().createElement("div", {
            className: "chat-contactspicker-no-contacts flex flex-column mt-2"
          }, react1().createElement("div", {
            className: "contacts-list-header"
          }, l[165]), react1().createElement("div", {
            className: "flex flex-1 flex-column flex-center"
          }, react1().createElement("div", {
            className: "section-icon sprite-fm-mono icon-contacts"
          }), react1().createElement("div", {
            className: "fm-empty-cloud-txt small"
          }, l[784]), react1().createElement("div", {
            className: "fm-empty-description small"
          }, l[19115])));
        }
      } else {
        contactsList = react1().createElement(_ui_perfectScrollbar_jsx4__.O, {
          ref: ref => {
            self.searchContactsScroll = ref;
          },
          className: "contacts-search-scroll",
          selected: this.state.selected,
          changedHashProp: this.props.changedHashProp,
          contacts,
          frequentContacts,
          searchValue: this.state.searchValue
        }, react1().createElement(react1().Fragment, null, react1().createElement("div", {
          className: "contacts-search-subsection",
          style: {
            display: hideFrequents ? 'none' : ''
          }
        }, react1().createElement("div", {
          className: "contacts-list-header"
        }, l[20141]), frequentsLoading ? react1().createElement("div", {
          className: "loading-spinner"
        }, "...") : react1().createElement("div", {
          className: "contacts-search-list",
          style: innerDivStyles
        }, frequentContacts)), contacts.length > 0 ? react1().createElement("div", {
          className: "contacts-search-subsection"
        }, react1().createElement("div", {
          className: "contacts-list-header"
        }, frequentContacts && frequentContacts.length === 0 ? this.props.readOnly ? l[16217] : l[165] : l[165]), react1().createElement("div", {
          className: "contacts-search-list",
          style: innerDivStyles
        }, contacts)) : null));
      }
    } else if (self.props.newNoContact) {
      multipleContacts = "";
      contactsList = react1().createElement("div", {
        className: "chat-contactspicker-no-contacts flex flex-column flex-center mt-2"
      }, react1().createElement("div", {
        className: "section-icon sprite-fm-mono icon-contacts"
      }), react1().createElement("div", {
        className: "fm-empty-cloud-txt small"
      }, l[784]), react1().createElement("div", {
        className: "fm-empty-description small"
      }, l[19115]));
      extraClasses += " no-contacts";
    } else {
      contactsList = react1().createElement("div", {
        className: "chat-contactspicker-no-contacts flex flex-column flex-center mt-16"
      }, react1().createElement("div", {
        className: "section-icon sprite-fm-mono icon-contacts"
      }), react1().createElement("div", {
        className: "fm-empty-cloud-txt small"
      }, l[784]), react1().createElement("div", {
        className: "fm-empty-description small"
      }, l[19115]), react1().createElement("button", {
        className: "mega-button positive large fm-empty-button",
        onClick: () => {
          contactAddDialog();
          self.props.onClose == null || self.props.onClose();
        }
      }, react1().createElement("span", null, l[101])), react1().createElement("div", {
        className: `
                            ${this.state.publicLink ? '' : 'loading'}
                            empty-share-public
                        `
      }, react1().createElement("i", {
        className: "sprite-fm-mono icon-link-circle"
      }), react1().createElement(_ui_utils_jsx3__.P9, null, l[19111])));
      extraClasses += " no-contacts";
    }
    const totalContactsNum = contacts.length + frequentContacts.length;
    const searchPlaceholderMsg = mega.icu.format(l.search_contact_placeholder, totalContactsNum);
    return react1().createElement("div", {
      ref: this.domRef,
      className: `
                    ${this.props.className || ''}
                    ${extraClasses}
                `
    }, this.props.topButtons && react1().createElement("div", {
      className: "contacts-search-buttons"
    }, this.props.topButtons.map(button => {
      const {
        key,
        icon,
        className,
        title,
        onClick
      } = button || {};
      return react1().createElement("div", {
        key,
        className: "button-wrapper",
        onClick: e => {
          closeDropdowns();
          onClick(e);
        }
      }, react1().createElement(_ui_buttons_jsx5__.$, {
        className: `
                                            ${className || ''}
                                            ${key === 'newChatLink' ? 'branded-blue' : ''}
                                            mega-button
                                        `,
        icon,
        label: title
      }));
    })), multipleContacts, !this.props.readOnly && haveContacts && !this.props.hideSearch && react1().createElement(react1().Fragment, null, react1().createElement("div", {
      className: `
                                contacts-search-header
                                ${this.props.headerClasses}
                            `
    }, react1().createElement("i", {
      className: "sprite-fm-mono icon-preview-reveal"
    }), react1().createElement("input", {
      autoFocus: true,
      type: "search",
      placeholder: searchPlaceholderMsg,
      ref: nodeRef => {
        this.contactSearchField = nodeRef;
      },
      onChange: this.onSearchChange,
      value: this.state.searchValue
    }), react1().createElement("div", {
      className: `
                                    search-result-clear
                                    ${this.state.searchValue && this.state.searchValue.length > 0 ? '' : 'hidden'}
                                `,
      onClick: () => {
        this.setState({
          searchValue: ''
        }, () => {
          let _this$contactSearchFi;
          return (_this$contactSearchFi = this.contactSearchField) == null ? void 0 : _this$contactSearchFi.focus();
        });
      }
    }, react1().createElement("i", {
      className: "sprite-fm-mono icon-close-component"
    })))), this.props.inviteWarningLabel && this.props.chatRoom && this.renderInviteWarning(), !this.props.readOnly && haveContacts && !this.props.hideSearch && react1().createElement("div", {
      className: "contacts-search-header-separator"
    }), this.props.participantsList ? this.renderParticipantsList() : contactsList, selectFooter, this.props.showAddContact && _contactsPanel_contactsPanel_jsx7__.A.hasContacts() ? react1().createElement("div", {
      className: "contacts-search-bottom"
    }, react1().createElement(_ui_buttons_jsx5__.$, {
      className: "mega-button action positive",
      icon: "sprite-fm-mono icon-add-circle",
      label: l[71],
      onClick: () => {
        let _this$props$onAddCont, _this$props3;
        contactAddDialog();
        closeDropdowns();
        (_this$props$onAddCont = (_this$props3 = this.props).onAddContact) == null || _this$props$onAddCont.call(_this$props3);
      }
    })) : null);
  }
}
ContactPickerWidget.defaultProps = {
  multipleSelectedButtonLabel: false,
  singleSelectedButtonLabel: false,
  nothingSelectedButtonLabel: false,
  allowEmpty: false,
  disableFrequents: false,
  skipMailSearch: false,
  autoFocusSearchField: true,
  selectCleanSearchRes: true,
  disableDoubleClick: false,
  newEmptySearchResult: false,
  newNoContact: false,
  emailTooltips: false
};
class ContactPickerDialog extends _mixins2__.w9 {
  constructor(...args) {
    super(...args);
    this.dialogName = 'contact-picker-dialog';
  }
  componentDidMount() {
    super.componentDidMount();
    M.safeShowDialog(this.dialogName, () => $(`.${this.dialogName}`));
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    if ($.dialog === this.dialogName) {
      closeDialog();
    }
  }
  render() {
    const {
      active,
      allowEmpty,
      className,
      exclude,
      megaChat,
      multiple,
      multipleSelectedButtonLabel,
      name,
      nothingSelectedButtonLabel,
      selectFooter,
      singleSelectedButtonLabel,
      inviteWarningLabel,
      chatRoom,
      onClose,
      onSelectDone
    } = this.props;
    return react1().createElement(_ui_modalDialogs8__.A.ModalDialog, {
      name,
      className: `
                    ${className}
                    ${this.dialogName}
                    contacts-search
                `,
      onClose
    }, react1().createElement(ContactPickerWidget, {
      active,
      allowEmpty,
      className: "popup contacts-search small-footer",
      contacts: M.u,
      exclude,
      megaChat,
      multiple,
      multipleSelectedButtonLabel,
      nothingSelectedButtonLabel,
      selectFooter,
      singleSelectedButtonLabel,
      inviteWarningLabel,
      chatRoom,
      onClose,
      onSelectDone
    }));
  }
}

},

269:
(_, EXP_, REQ_) => {

"use strict";
REQ_.r(EXP_);
REQ_.d(EXP_, {
"default": () => Incoming
});
const _extends0__ = REQ_(168);
const react1__ = REQ_(594);
const react1 = REQ_.n(react1__);
const _contacts_jsx2__ = REQ_(251);
const _ui_modalDialogs_jsx3__ = REQ_(318);
const _button_jsx4__ = REQ_(959);
const _call_jsx5__ = REQ_(3);
const _ui_utils_jsx6__ = REQ_(314);







class Incoming extends react1().Component {
  constructor(props) {
    super(props);
    this.state = {
      video: false,
      unsupported: undefined,
      hoveredSwitch: true,
      hideOverlay: false
    };
    this.renderSwitchControls = () => {
      const className = `mega-button large round switch ${this.state.hoveredSwitch ? 'hovered' : ''}`;
      const toggleHover = () => this.setState(state => ({
        hoveredSwitch: !state.hoveredSwitch
      }));
      return react1().createElement("div", {
        className: "switch-button"
      }, react1().createElement("div", {
        className: "switch-button-container simpletip",
        "data-simpletip": l.end_and_answer,
        "data-simpletipposition": "top",
        onMouseEnter: toggleHover,
        onMouseLeave: toggleHover,
        onClick: ev => {
          ev.stopPropagation();
          this.props.onSwitch();
        }
      }, react1().createElement(_button_jsx4__.A, {
        className: `${className} negative`,
        icon: "icon-end-call"
      }), react1().createElement(_button_jsx4__.A, {
        className: `${className} positive`,
        icon: "icon-phone"
      })));
    };
    this.renderAnswerControls = () => {
      const {
        video,
        unsupported
      } = this.state;
      const {
        onAnswer,
        onToggleVideo
      } = this.props;
      return react1().createElement(react1().Fragment, null, react1().createElement(_button_jsx4__.A, {
        className: `
                        mega-button
                        positive
                        answer
                        ${unsupported ? 'disabled' : ''}
                    `,
        icon: "icon-phone",
        simpletip: unsupported ? null : {
          position: 'top',
          label: l[7205]
        },
        onClick: unsupported ? null : onAnswer
      }, react1().createElement("span", null, l[7205])), react1().createElement(_button_jsx4__.A, {
        className: `
                        mega-button
                        large
                        round
                        video
                        ${video ? '' : 'negative'}
                        ${unsupported ? 'disabled' : ''}
                    `,
        icon: video ? 'icon-video-call-filled' : 'icon-video-off',
        simpletip: unsupported ? null : {
          position: 'top',
          label: video ? l[22894] : l[22893]
        },
        onClick: () => unsupported ? null : this.setState({
          video: !video
        }, () => onToggleVideo(video))
      }, react1().createElement("span", null, video ? l[22894] : l[22893])));
    };
    this.state.unsupported = !megaChat.hasSupportForCalls;
    this.state.hideOverlay = document.body.classList.contains('overlayed') && !$.msgDialog;
  }
  componentDidMount() {
    this._old$dialog = $.dialog;
    $.dialog = "chat-incoming-call";
  }
  componentWillUnmount() {
    $.dialog = this._old$dialog;
  }
  render() {
    const {
      chatRoom
    } = this.props;
    if (chatRoom) {
      const {
        NAMESPACE
      } = Incoming;
      const {
        callerId,
        onClose,
        onReject
      } = this.props;
      const {
        unsupported
      } = this.state;
      const CALL_IN_PROGRESS = window.sfuClient;
      const isPrivateRoom = chatRoom.type === 'private';
      const rejectLabel = isPrivateRoom ? l[20981] : l.msg_dlg_cancel;
      return react1().createElement(_ui_modalDialogs_jsx3__.A.ModalDialog, (0,_extends0__.A)({}, this.state, {
        name: NAMESPACE,
        className: NAMESPACE,
        roomName: chatRoom.getRoomTitle(),
        onClose: () => onClose()
      }), react1().createElement("div", {
        className: "fm-dialog-body"
      }, react1().createElement("div", {
        className: `${NAMESPACE}-avatar`
      }, react1().createElement(_contacts_jsx2__.Avatar, {
        contact: M.u[callerId]
      })), react1().createElement("div", {
        className: `${NAMESPACE}-info`
      }, react1().createElement("h1", null, react1().createElement(_ui_utils_jsx6__.zT, null, chatRoom.getRoomTitle())), react1().createElement("span", null, isPrivateRoom ? l[17878] : l[19995])), react1().createElement("div", {
        className: `
                                ${NAMESPACE}-controls
                                ${CALL_IN_PROGRESS ? 'call-in-progress' : ''}
                            `
      }, react1().createElement(_button_jsx4__.A, {
        className: `
                                    mega-button
                                    large
                                    round
                                    negative
                                `,
        icon: "icon-end-call",
        simpletip: {
          position: 'top',
          label: rejectLabel
        },
        onClick: onReject
      }, react1().createElement("span", null, rejectLabel)), CALL_IN_PROGRESS ? this.renderSwitchControls() : this.renderAnswerControls()), unsupported && react1().createElement("div", {
        className: `${NAMESPACE}-unsupported`
      }, react1().createElement("div", {
        className: "unsupported-message"
      }, _call_jsx5__.Ay.getUnsupportedBrowserMessage()))));
    }
    console.error('Incoming dialog received missing chatRoom prop.');
    return null;
  }
}
Incoming.NAMESPACE = 'incoming-dialog';
window.ChatCallIncomingDialog = Incoming;

},

280:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
A: () => Link
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);

class Link extends react0().Component {
  constructor(props) {
    super(props);
    this.IS_CLICK_URL = undefined;
    this.IS_CLICK_URL = this.props.to && (this.props.to.startsWith('/') || this.props.to.includes('mega.io'));
  }
  componentDidMount() {
    if (this.IS_CLICK_URL) {
      clickURLs();
    }
  }
  render() {
    const {
      className,
      to,
      target,
      children,
      onClick
    } = this.props;
    if (this.IS_CLICK_URL) {
      return react0().createElement("a", {
        className: `
                        clickurl
                        ${className || ''}
                    `,
        href: to,
        target
      }, children);
    }
    return react0().createElement("a", {
      className,
      href: "#",
      onClick: ev => {
        if (onClick) {
          ev.preventDefault();
          return onClick(ev);
        }
        return null;
      }
    }, children);
  }
}

},

314:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
Ay: () => __WEBPACK_DEFAULT_EXPORT__,
P9: () => ParsedHTML,
T9: () => withOverflowObserver,
lI: () => reactStringWrap,
oM: () => OFlowParsedHTML,
sp: () => OFlowEmoji,
zT: () => Emoji
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);
const react_dom1__ = REQ_(206);
const react_dom1 = REQ_.n(react_dom1__);
const _chat_mixins_js2__ = REQ_(137);



class RenderTo extends react0().Component {
  constructor(...args) {
    super(...args);
    this.$$rootRef = undefined;
    this.popupElement = undefined;
  }
  _setClassNames() {
    this.popupElement.className = this.props.className || '';
  }
  _renderLayer() {
    this.$$rootRef.render(this.props.children);
    queueMicrotask(() => {
      let _this$props$popupDidM, _this$props;
      return (_this$props$popupDidM = (_this$props = this.props).popupDidMount) == null ? void 0 : _this$props$popupDidM.call(_this$props, this.popupElement);
    });
  }
  componentDidUpdate() {
    this._setClassNames();
    this._renderLayer();
  }
  componentWillUnmount() {
    let _this$props$popupWill, _this$props2;
    onIdle(() => this.$$rootRef.unmount());
    (_this$props$popupWill = (_this$props2 = this.props).popupWillUnmount) == null || _this$props$popupWill.call(_this$props2, this.popupElement);
    this.props.element.removeChild(this.popupElement);
  }
  componentDidMount() {
    this.popupElement = document.createElement('div');
    this.$$rootRef = (0,react_dom1__.createRoot)(this.popupElement);
    this._setClassNames();
    if (this.props.style) {
      $(this.popupElement).css(this.props.style);
    }
    this.props.element.appendChild(this.popupElement);
    this._renderLayer();
  }
  render() {
    return null;
  }
}
const withOverflowObserver = Component => class extends _chat_mixins_js2__.u9 {
  constructor(props) {
    super(props);
    this.displayName = 'OverflowObserver';
    this.ref = react0().createRef();
    this.state = {
      overflowed: false
    };
    this.handleMouseEnter = this.handleMouseEnter.bind(this);
  }
  handleMouseEnter() {
    const element = this.ref && this.ref.current;
    if (element) {
      this.setState({
        overflowed: element.scrollWidth > element.offsetWidth
      });
    }
  }
  shouldComponentUpdate(nextProps, nextState) {
    return nextState.overflowed !== this.state.overflowed || nextProps.children !== this.props.children || nextProps.content !== this.props.content;
  }
  render() {
    const {
      simpletip
    } = this.props;
    return react0().createElement("div", {
      ref: this.ref,
      className: `
                        overflow-observer
                        ${this.state.overflowed ? 'simpletip simpletip-tc' : ''}
                    `,
      "data-simpletipposition": (simpletip == null ? void 0 : simpletip.position) || 'top',
      "data-simpletipoffset": simpletip == null ? void 0 : simpletip.offset,
      "data-simpletip-class": (simpletip == null ? void 0 : simpletip.className) || 'medium-width center-align',
      onMouseEnter: this.handleMouseEnter
    }, react0().createElement(Component, this.props));
  }
};
const Emoji = ({
  children
}) => {
  return react0().createElement(ParsedHTML, {
    content: megaChat.html(children)
  });
};
class ParsedHTML extends react0().Component {
  constructor(...args) {
    super(...args);
    this.ref = react0().createRef();
  }
  updateInternalState() {
    const {
      children,
      content
    } = this.props;
    const ref = this.ref && this.ref.current;
    if (!children && !content) {
      return d > 1 && console.warn('Emoji: No content passed.');
    }
    if (ref) {
      if (ref.childNodes.length) {
        while (ref.firstChild) {
          ref.removeChild(ref.firstChild);
        }
      }
      ref.appendChild(parseHTML(children || content));
    }
  }
  shouldComponentUpdate(nextProps) {
    return nextProps && (nextProps.children !== this.props.children || nextProps.content !== this.props.content);
  }
  componentDidUpdate() {
    this.updateInternalState();
  }
  componentDidMount() {
    this.updateInternalState();
  }
  render() {
    const {
      className,
      onClick,
      tag
    } = this.props;
    return react0().createElement(tag || 'span', {
      ref: this.ref,
      className,
      onClick
    });
  }
}
const reactStringWrap = (src, find, WrapClass, wrapProps) => {
  const endTag = find.replace('[', '[/');
  return react0().createElement(react0().Fragment, null, src.split(find)[0], react0().createElement(WrapClass, wrapProps, src.substring(src.indexOf(find) + find.length, src.indexOf(endTag))), src.split(endTag)[1]);
};
const OFlowEmoji = withOverflowObserver(Emoji);
const OFlowParsedHTML = withOverflowObserver(ParsedHTML);
const __WEBPACK_DEFAULT_EXPORT__ = {
  RenderTo,
  SoonFcWrap: _chat_mixins_js2__.hG,
  OFlowEmoji,
  OFlowParsedHTML
};

},

318:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  A: () => modalDialogs
});

// UNUSED EXPORTS: ExtraFooterElement

// EXTERNAL MODULE: ./js/ui/utils.jsx
const utils = REQ_(314);
// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
;// ./js/ui/forms.jsx
const React = REQ_(594);

class Checkbox extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = React.createRef();
    this.state = {
      checked: this.props.checked ? this.props.checked : false
    };
    this.onLabelClick = this.onLabelClick.bind(this);
    this.onChange = this.onChange.bind(this);
  }
  onLabelClick(e) {
    const state = !this.state.checked;
    this.setState({
      'checked': state
    });
    if (this.props.onLabelClick) {
      this.props.onLabelClick(e, state);
    }
    this.onChange(e);
  }
  onChange(e) {
    if (this.props.onChange) {
      this.props.onChange(e, this.state.checked);
    }
  }
  render() {
    const {
      name,
      id,
      children
    } = this.props;
    const className = this.state.checked ? 'checkboxOn' : 'checkboxOff';
    return React.createElement("div", {
      ref: this.domRef,
      className: "formsCheckbox"
    }, React.createElement("div", {
      className: `
                        checkdiv
                        ${className}
                    `,
      onClick: this.onLabelClick
    }, React.createElement("input", {
      type: "checkbox",
      name,
      id,
      className,
      checked: this.state.checked,
      onChange: this.onChange
    })), React.createElement("label", {
      htmlFor: id,
      className: "radio-txt"
    }, children));
  }
}
const ui_forms = {
  Checkbox
};
;// ./js/ui/modalDialogs.jsx
const modalDialogs_React = REQ_(594);



const ContactsUI = REQ_(251);
class ExtraFooterElement extends modalDialogs_React.Component {
  render() {
    return this.props.children;
  }
}
class SafeShowDialogController extends mixins.w9 {
  constructor(props) {
    super(props);
    this.dialogName = 'unnamed-dialog';
    this.dialogBecameVisible = null;
    const {
      render
    } = this;
    this.render = () => {
      if (this.dialogBecameVisible) {
        console.assert($.dialog === this.dialogName, `${this.dialogName} state overridden.`);
        return render.call(this);
      }
      return null;
    };
  }
  shouldComponentUpdate(nextProps, nextState) {
    if (!this.dialogBecameVisible) {
      return false;
    }
    return super.shouldComponentUpdate(nextProps, nextState);
  }
  componentDidMount() {
    super.componentDidMount();
    M.safeShowDialog(this.dialogName, () => {
      if (!this.isMounted()) {
        throw new Error(`${this.dialogName} component is no longer mounted.`);
      }
      this.dialogBecameVisible = 1;
      this.forceUpdate();
    });
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    if (this.dialogBecameVisible) {
      this.dialogBecameVisible = false;
      console.assert($.dialog === this.dialogName);
      if ($.dialog === this.dialogName) {
        closeDialog();
      }
    }
  }
  componentDidUpdate() {
    assert(this.dialogBecameVisible);
    super.componentDidUpdate();
    if (++this.dialogBecameVisible === 2) {
      requestAnimationFrame(() => {
        const dialog = document.querySelectorAll(`.${this.dialogName}`);
        console.assert(dialog.length === 1, `Unexpected ${this.dialogName} state.`);
        console.assert($.dialog === this.dialogName, `${this.dialogName} state overridden.`);
        if (dialog.length === 1 && $.dialog === this.dialogName) {
          dialog[0].classList.remove('hidden', 'arrange-to-back');
        }
      });
    }
  }
}
class ModalDialog extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = modalDialogs_React.createRef();
    this.onBlur = this.onBlur.bind(this);
    this.onCloseClicked = this.onCloseClicked.bind(this);
    this.onPopupDidMount = this.onPopupDidMount.bind(this);
  }
  componentDidMount() {
    super.componentDidMount();
    if (!this.props.hideOverlay) {
      $(document.body).addClass('overlayed');
      $('.fm-dialog-overlay').removeClass('hidden');
    }
    $('textarea:focus').trigger("blur");
    if (!this.props.noCloseOnClickOutside) {
      const convApp = document.querySelector('.conversationsApp');
      if (convApp) {
        convApp.removeEventListener('click', this.onBlur);
        convApp.addEventListener('click', this.onBlur);
      }
      $('.fm-modal-dialog').rebind(`click.modalDialogOv${  this.getUniqueId()}`, ({
        target
      }) => {
        if ($(target).is('.fm-modal-dialog')) {
          this.onBlur();
        }
      });
      $('.fm-dialog-overlay').rebind(`click.modalDialog${  this.getUniqueId()}`, () => {
        if (this.props.closeDlgOnClickOverlay) {
          this.onBlur();
        }
        return false;
      });
    }
    $(document).rebind(`keyup.modalDialog${  this.getUniqueId()}`, ({
      keyCode
    }) => {
      if (!this.props.stopKeyPropagation && keyCode === 27) {
        this.onBlur();
      }
    });
  }
  onBlur(e) {
    let _this$domRef;
    const $element = $((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
    if (!e || !$(e.target).closest('.mega-dialog').is($element)) {
      const convApp = document.querySelector('.conversationsApp');
      if (convApp) {
        convApp.removeEventListener('click', this.onBlur);
      }
      this.onCloseClicked();
    }
  }
  componentWillUnmount() {
    let _this$props$popupWill, _this$props;
    super.componentWillUnmount();
    if (!this.props.noCloseOnClickOutside) {
      const convApp = document.querySelector('.conversationsApp');
      if (convApp) {
        convApp.removeEventListener('click', this.onBlur);
      }
      $('.fm-dialog-overlay').off(`click.modalDialog${  this.getUniqueId()}`);
    }
    if (!this.props.hideOverlay) {
      $(document.body).removeClass('overlayed');
      $('.fm-dialog-overlay').addClass('hidden');
    }
    $(this.domNode).off(`dialog-closed.modalDialog${  this.getUniqueId()}`);
    $(document).off(`keyup.modalDialog${  this.getUniqueId()}`);
    (_this$props$popupWill = (_this$props = this.props).popupWillUnmount) == null || _this$props$popupWill.call(_this$props);
  }
  onCloseClicked() {
    const self = this;
    if (self.props.onClose) {
      self.props.onClose(self);
    }
  }
  onPopupDidMount(elem) {
    this.domNode = elem;
    $(elem).rebind(`dialog-closed.modalDialog${  this.getUniqueId()}`, () => this.onCloseClicked());
    if (this.props.popupDidMount) {
      this.props.popupDidMount(elem);
    }
  }
  render() {
    const self = this;
    let classes = 'mega-dialog';
    let selectedNumEle = null;
    let footer = null;
    const extraFooterElements = [];
    const otherElements = [];
    let x = 0;
    modalDialogs_React.Children.forEach(self.props.children, (child) => {
      if (!child) {
        return;
      }
      if (child.type.name === 'ExtraFooterElement') {
        extraFooterElements.push(modalDialogs_React.cloneElement(child, {
          key: x++
        }));
      } else {
        otherElements.push(modalDialogs_React.cloneElement(child, {
          key: x++
        }));
      }
    });
    if (self.props.className) {
      classes += ` ${self.props.className}`;
    }
    if (self.props.dialogType) {
      classes += ` dialog-template-${self.props.dialogType}`;
    }
    if (self.props.dialogName) {
      classes += ` ${self.props.dialogName}`;
    }
    if (self.props.showSelectedNum && self.props.selectedNum) {
      selectedNumEle = modalDialogs_React.createElement("div", {
        className: "selected-num"
      }, modalDialogs_React.createElement("span", null, self.props.selectedNum));
    }
    let buttons;
    if (self.props.buttons) {
      buttons = [];
      self.props.buttons.forEach((v, i) => {
        if (v) {
          buttons.push(modalDialogs_React.createElement("button", {
            className: (v.defaultClassname ? v.defaultClassname : "mega-button") + (v.className ? ` ${  v.className}` : "") + (self.props.dialogType === "action" ? "large" : ""),
            onClick: e => {
              if ($(e.target).is(".disabled")) {
                return false;
              }
              if (v.onClick) {
                v.onClick(e, self);
              }
            },
            key: v.key + i
          }, v.iconBefore ? modalDialogs_React.createElement("div", null, modalDialogs_React.createElement("i", {
            className: v.iconBefore
          })) : null, modalDialogs_React.createElement("span", null, v.label), v.iconAfter ? modalDialogs_React.createElement("div", null, modalDialogs_React.createElement("i", {
            className: v.iconAfter
          })) : null));
        }
      });
      if (buttons && buttons.length > 0 || extraFooterElements && extraFooterElements.length > 0) {
        footer = modalDialogs_React.createElement("footer", null, buttons && buttons.length > 0 ? modalDialogs_React.createElement("div", {
          className: "footer-container"
        }, buttons) : null, extraFooterElements && extraFooterElements.length > 0 ? modalDialogs_React.createElement("aside", null, extraFooterElements) : null);
      }
    }
    return modalDialogs_React.createElement(utils.Ay.RenderTo, {
      element: document.body,
      className: "fm-modal-dialog",
      popupDidMount: this.onPopupDidMount
    }, modalDialogs_React.createElement("div", {
      ref: this.domRef,
      id: self.props.id,
      className: classes,
      "aria-labelledby": self.props.dialogName ? `${self.props.dialogName  }-title` : null,
      role: "dialog",
      "aria-modal": "true",
      onClick: self.props.onClick
    }, modalDialogs_React.createElement("button", {
      className: "close",
      onClick: self.onCloseClicked
    }, modalDialogs_React.createElement("i", {
      className: "sprite-fm-mono icon-dialog-close"
    })), self.props.title ? self.props.dialogType === "message" ? modalDialogs_React.createElement("header", null, self.props.icon ? modalDialogs_React.createElement("i", {
      className: `graphic ${self.props.icon}`
    }) : self.props.iconElement, modalDialogs_React.createElement("div", null, modalDialogs_React.createElement("h3", {
      id: self.props.dialogName ? `${self.props.dialogName  }-title` : null
    }, self.props.title, selectedNumEle), self.props.subtitle ? modalDialogs_React.createElement("p", null, self.props.subtitle) : null, otherElements)) : modalDialogs_React.createElement("header", null, self.props.icon ? modalDialogs_React.createElement("i", {
      className: `graphic ${self.props.icon}`
    }) : self.props.iconElement, modalDialogs_React.createElement("h2", {
      id: self.props.dialogName ? `${self.props.dialogName  }-title` : null
    }, self.props.title, selectedNumEle), self.props.subtitle ? modalDialogs_React.createElement("p", null, self.props.subtitle) : null) : null, self.props.dialogType !== "message" ? otherElements : null, buttons || extraFooterElements ? footer : null));
  }
}
ModalDialog.defaultProps = {
  'hideable': true,
  'noCloseOnClickOutside': false,
  'closeDlgOnClickOverlay': true,
  'showSelectedNum': false,
  'selectedNum': 0
};
class SelectContactDialog extends mixins.w9 {
  constructor(props) {
    super(props);
    this.dialogName = 'send-contact-dialog';
    this.state = {
      selected: []
    };
    this.state.selected = this.props.selected || [];
    this.onSelected = this.onSelected.bind(this);
  }
  onSelected(nodes) {
    let _this$props$onSelecte, _this$props2;
    this.setState({
      selected: nodes
    });
    (_this$props$onSelecte = (_this$props2 = this.props).onSelected) == null || _this$props$onSelecte.call(_this$props2, nodes);
  }
  componentDidMount() {
    super.componentDidMount();
    M.safeShowDialog(this.dialogName, () => $(`.${this.dialogName}`));
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    if ($.dialog === this.dialogName) {
      closeDialog();
    }
  }
  render() {
    return modalDialogs_React.createElement(ModalDialog, {
      title: l.share_contact_title,
      className: `
                    send-contact
                    contrast
                    small-footer
                    dialog-template-tool
                    ${this.props.className}
                    ${this.dialogName}
                `,
      selected: this.state.selected,
      buttons: [{
        key: "cancel",
        label: this.props.cancelLabel,
        onClick: ev => {
          this.props.onClose();
          ev.preventDefault();
          ev.stopPropagation();
        }
      }, {
        key: "select",
        label: this.props.selectLabel,
        className: this.state.selected.length === 0 ? 'positive disabled' : 'positive',
        onClick: ev => {
          if (this.state.selected.length > 0) {
            let _this$props$onSelecte2, _this$props3;
            (_this$props$onSelecte2 = (_this$props3 = this.props).onSelected) == null || _this$props$onSelecte2.call(_this$props3, this.state.selected);
            this.props.onSelectClicked(this.state.selected);
          }
          ev.preventDefault();
          ev.stopPropagation();
        }
      }],
      onClose: this.props.onClose
    }, modalDialogs_React.createElement("section", {
      className: "content"
    }, modalDialogs_React.createElement("div", {
      className: "content-block"
    }, modalDialogs_React.createElement(ContactsUI.ContactPickerWidget, {
      megaChat: this.props.megaChat,
      exclude: this.props.exclude,
      selectableContacts: "true",
      onSelectDone: this.props.onSelectClicked,
      onSelected: this.onSelected,
      onClose: this.props.onClose,
      selected: this.state.selected,
      contacts: M.u,
      headerClasses: "left-aligned",
      multiple: true
    }))));
  }
}
SelectContactDialog.clickTime = 0;
SelectContactDialog.defaultProps = {
  selectLabel: l.share_contact_action,
  cancelLabel: l.msg_dlg_cancel,
  hideable: true
};
class ConfirmDialog extends mixins.w9 {
  static saveState(o) {
    const state = mega.config.get('xcod') >>> 0;
    mega.config.set('xcod', state | 1 << o.props.pref);
  }
  static clearState(o) {
    const state = mega.config.get('xcod') >>> 0;
    mega.config.set('xcod', state & ~(1 << o.props.pref));
  }
  static autoConfirm(o) {
    console.assert(o.props.pref > 0);
    const state = mega.config.get('xcod') >>> 0;
    return !!(state & 1 << o.props.pref);
  }
  constructor(props) {
    super(props);
    this.dialogName = 'confirm-dialog';
    this._wasAutoConfirmed = undefined;
    this._keyUpEventName = `keyup.confirmDialog${  this.getUniqueId()}`;
    this.dialogName = this.props.name || this.dialogName;
    lazy(this, '_autoConfirm', () => this.props.onConfirmClicked && this.props.dontShowAgainCheckbox && ConfirmDialog.autoConfirm(this));
  }
  unbindEvents() {
    $(document).off(this._keyUpEventName);
  }
  componentDidMount() {
    super.componentDidMount();
    M.safeShowDialog(this.dialogName, () => {
      queueMicrotask(() => {
        if (!this.isMounted()) {
          return;
        }
        if (this._autoConfirm) {
          if (!this._wasAutoConfirmed) {
            this._wasAutoConfirmed = 1;
            queueMicrotask(() => {
              this.onConfirmClicked();
            });
          }
          return;
        }
        $(document).rebind(this._keyUpEventName, e => {
          if (e.which === 13 || e.keyCode === 13) {
            if (!this.isMounted()) {
              this.unbindEvents();
              return;
            }
            this.onConfirmClicked();
            return false;
          }
        });
      });
    });
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    this.unbindEvents();
    if ($.dialog === this.dialogName) {
      closeDialog();
    }
    delete this._wasAutoConfirmed;
  }
  onConfirmClicked() {
    this.unbindEvents();
    if (this.props.onConfirmClicked) {
      this.props.onConfirmClicked();
    }
  }
  render() {
    const self = this;
    if (this._autoConfirm) {
      return null;
    }
    const classes = `delete-message${  self.props.name ? ` ${self.props.name}` : ""  }${self.props.className ? ` ${self.props.className}` : ""}`;
    let dontShowCheckbox = null;
    if (self.props.dontShowAgainCheckbox) {
      dontShowCheckbox = modalDialogs_React.createElement("div", {
        className: "footer-checkbox"
      }, modalDialogs_React.createElement(ui_forms.Checkbox, {
        name: "delete-confirm",
        id: "delete-confirm",
        onLabelClick: (e, state) => {
          if (state === true) {
            ConfirmDialog.saveState(self);
          } else {
            ConfirmDialog.clearState(self);
          }
        }
      }, l[7039]));
    }
    return modalDialogs_React.createElement(ModalDialog, {
      title: this.props.title,
      subtitle: this.props.subtitle,
      className: classes,
      dialogId: this.props.name,
      dialogType: this.props.dialogType,
      icon: this.props.icon,
      onClose: () => {
        self.props.onClose(self);
      },
      buttons: [{
        "label": self.props.cancelLabel,
        "key": "cancel",
        "onClick" (e) {
          ConfirmDialog.clearState(self);
          self.props.onClose(self);
          e.preventDefault();
          e.stopPropagation();
        }
      }, {
        "label": self.props.confirmLabel,
        "key": "select",
        "className": "positive",
        "onClick" (e) {
          self.onConfirmClicked();
          e.preventDefault();
          e.stopPropagation();
        }
      }]
    }, self.props.children, dontShowCheckbox ? modalDialogs_React.createElement(ExtraFooterElement, null, dontShowCheckbox) : null);
  }
}
lazy(ConfirmDialog, 'defaultProps', () => {
  return freeze({
    'confirmLabel': l[6826],
    'cancelLabel': l.msg_dlg_cancel,
    'dontShowAgainCheckbox': true,
    'hideable': true,
    'dialogType': 'message'
  });
});
const modalDialogs = {
  ModalDialog,
  SelectContactDialog,
  SafeShowDialogController,
  ConfirmDialog
};

},

326:
(_, EXP_, REQ_) => {

"use strict";

// UNUSED EXPORTS: default

// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
// EXTERNAL MODULE: external "ReactDOM"
const ReactDOM_ = REQ_(206);
// EXTERNAL MODULE: ./js/chat/ui/conversations.jsx + 21 modules
const conversations = REQ_(732);
;// ./js/chat/chatRouting.jsx
let _ChatRouting;
class ChatRouting {
  constructor(megaChatInstance) {
    this.megaChat = megaChatInstance;
  }
  openCustomView(sectionName) {
    const {megaChat} = this;
    megaChat.routingSection = sectionName;
    megaChat.hideAllChats();
    delete megaChat.lastOpenedChat;
  }
  route(resolve, reject, location, event, isLandingPage) {
    if (!M.chat) {
      console.error('This function is meant to navigate within the chat...');
      return;
    }
    const args = String(location || '').split('/').map(String.trim).filter(String);
    if (args[0] === 'fm') {
      args.shift();
    }
    if (args[0] === 'chat') {
      args.shift();
    }
    if (args[0] && args[0].length > 8 && args[0].substring(0, 8) === 'contacts') {
      location = location.replace(args[0], 'contacts');
      args[0] = 'contacts';
    }
    const [section] = args;
    const {
      megaChat
    } = this;
    if (d) {
      megaChat.logger.warn('navigate(%s)', location, args);
    }
    args.route = {
      location,
      section,
      args
    };
    if (isLandingPage) {
      megaChat.eventuallyInitMeetingUI();
    }
    megaChat.routingSection = 'chat';
    megaChat.routingSubSection = null;
    megaChat.routingParams = null;
    const handler = ChatRouting.gPageHandlers[section || 'start'];
    if (handler) {
      handler.call(this, args.route).then(resolve).catch(reject);
      resolve = null;
    } else {
      let roomId = String(args[(section === 'c' || section === 'g' || section === 'p') | 0] || '');
      if (roomId.includes('#')) {
        let key = roomId.split('#');
        roomId = key[0];
        key = key[1];
        megaChat.publicChatKeys[roomId] = key;
        roomId = megaChat.handleToId[roomId] || roomId;
      }
      const room = megaChat.getChatById(roomId);
      if (room) {
        room.show();
        args.route.location = room.getRoomUrl();
      } else if (!roomId || roomId === u_handle || roomId.length !== 11 && !is_chatlink) {
        ChatRouting.gPageHandlers.redirect(args.route, 'fm/chat').then(resolve).catch(reject);
        resolve = null;
      } else if (section === 'p') {
        megaChat.smartOpenChat([u_handle, roomId], 'private', undefined, undefined, undefined, true).then(resolve).catch(reject);
        resolve = null;
      } else {
        megaChat.plugins.chatdIntegration.openChat(roomId).then(chatId => {
          megaChat.getChatById(chatId).show();
          return chatId;
        }).catch(ex => {
          if (d && ex !== ENOENT) {
            console.warn('If "%s" is a chat, something went wrong..', roomId, ex);
          }
          if (page !== location) {
            return EEXPIRED;
          }
          megaChat.cleanup(true);
          if (ex === ENOENT || ex === EBLOCKED && megaChat.publicChatKeys[roomId]) {
            msgDialog('warninga', '', l[20641], l[20642], () => {
              loadSubPage(is_chatlink ? 'start' : 'fm/chat', event);
            });
          } else {
            if (String(location).startsWith('chat')) {
              location = 'fm/chat';
            }
            loadSubPage(location, location.includes('chat') ? 'override' : event);
          }
          return EACCESS;
        }).then(resolve).catch(reject);
        resolve = null;
      }
    }
    if (resolve) {
      onIdle(resolve);
    }
    if (args.route.location !== location) {
      location = args.route.location;
    }
    const method = page === 'chat' || page === 'fm/chat' || page === location || event && event.type === 'popstate' ? 'replaceState' : 'pushState';
    mBroadcaster.sendMessage('beforepagechange', location);
    M.currentdirid = String(page = location).replace('fm/', '');
    if (location.substr(0, 13) === "chat/contacts") {
      location = `fm/${  location}`;
    }
    if (location === 'chat') {
      location = 'fm/chat';
    }
    history[method]({
      subpage: location
    }, "", (hashLogic ? '#' : '/') + location);
    mBroadcaster.sendMessage('pagechange', page);
  }
  initFmAndChat(targetChatId) {
    assert(!fminitialized);
    return new Promise((res, rej) => {
      M.currentdirid = targetChatId ? `fm/chat/${  targetChatId}` : undefined;
      loadSubPage('fm');
      mBroadcaster.once('chat_initialized', () => {
        authring.onAuthringReady().then(res, rej);
      });
    });
  }
  reinitAndOpenExistingChat(chatId, publicChatHandle = false, cbBeforeOpen = undefined) {
    const chatUrl = `fm/chat/c/${  chatId}`;
    publicChatHandle = publicChatHandle || megaChat.initialPubChatHandle;
    megaChat.destroy();
    is_chatlink = false;
    loadingDialog.pshow();
    return new Promise((resolve, reject) => {
      this.initFmAndChat(chatId).always(() => {
        megaChat.initialPubChatHandle = publicChatHandle;
        megaChat.initialChatId = chatId;
        const next = () => {
          mBroadcaster.once('pagechange', () => {
            onIdle(() => {
              loadingDialog.phide();
              megaChat.renderListing(chatUrl, true).catch(ex => {
                console.error("Failed to megaChat.renderListing:", ex);
                reject(ex);
              }).always(() => {
                megaChat.updateKeysInProtocolHandlers();
                const chatRoom = megaChat.getChatById(chatId);
                assert(chatRoom);
                if (chatRoom.state === ChatRoom.STATE.READY) {
                  resolve(chatRoom);
                } else {
                  chatRoom.rebind('onMessagesHistoryDone.reinitAndOpenExistingChat', () => {
                    if (chatRoom.state === ChatRoom.STATE.READY) {
                      resolve(chatRoom);
                      chatRoom.unbind('onMessagesHistoryDone.reinitAndOpenExistingChat');
                    }
                  });
                }
              });
            });
          });
          loadSubPage(chatUrl);
        };
        if (cbBeforeOpen) {
          cbBeforeOpen().then(next, ex => {
            console.error("Failed to execute `cbBeforeOpen`, got a reject of the returned promise:", ex);
          });
        } else {
          next();
        }
      }).catch(ex => reject(ex));
    });
  }
  reinitAndJoinPublicChat(chatId, initialPubChatHandle, publicChatKey) {
    initialPubChatHandle = initialPubChatHandle || megaChat.initialPubChatHandle;
    megaChat.destroy();
    is_chatlink = false;
    loadingDialog.pshow();
    return new Promise((res, rej) => {
      this.initFmAndChat(chatId).then(() => {
        megaChat.initialPubChatHandle = initialPubChatHandle;
        megaChat.initialChatId = chatId;
        const mciphReq = megaChat.plugins.chatdIntegration.getMciphReqFromHandleAndKey(initialPubChatHandle, publicChatKey);
        const isReady = chatRoom => {
          if (chatRoom.state === ChatRoom.STATE.READY) {
            res(chatRoom);
            loadingDialog.phide();
          } else {
            chatRoom.rebind('onMessagesHistoryDone.reinitAndOpenExistingChat', () => {
              if (chatRoom.state === ChatRoom.STATE.READY) {
                res(chatRoom);
                loadingDialog.phide();
                chatRoom.unbind('onMessagesHistoryDone.reinitAndOpenExistingChat');
              }
            });
          }
        };
        const join = () => {
          const existingRoom = megaChat.getChatById(chatId);
          if (!existingRoom) {
            megaChat.rebind('onRoomInitialized.reinitAndJoinPublicChat', (e, megaRoom) => {
              if (megaRoom.chatId === chatId) {
                megaRoom.setActive();
                isReady(megaRoom);
                megaChat.unbind('onRoomInitialized.reinitAndJoinPublicChat');
              }
            });
          } else {
            existingRoom.setActive();
            isReady(existingRoom);
          }
        };
        join();
        asyncApiReq(mciphReq).then(join).catch(ex => {
          if (ex === EEXIST) {
            join();
          } else {
            loadingDialog.phide();
            console.error("Bad response for mciphReq:", mciphReq, ex);
            rej(ex);
          }
        });
      });
    });
  }
}
_ChatRouting = ChatRouting;
ChatRouting.gPageHandlers = {
  async start({
    location
  }) {
    return megaChat.onChatsHistoryReady(15e3).then(() => {
      return page === location ? megaChat.renderListing() : EACCESS;
    });
  },
  async redirect(target, path = 'fm/chat') {
    target.location = path;
    return _ChatRouting.gPageHandlers.start(target);
  },
  async new_meeting(target) {
    megaChat.trigger('onStartNewMeeting');
    return _ChatRouting.gPageHandlers.redirect(target);
  },
  async contacts({
    section,
    args
  }) {
    this.openCustomView(section);
    const [, target = ''] = args;
    if (target.length === 11) {
      megaChat.routingSubSection = "contact";
      megaChat.routingParams = target;
    } else if (target === "received" || target === "sent") {
      megaChat.routingSubSection = target;
    }
  }
};
// EXTERNAL MODULE: ./js/chat/ui/messages/scheduleMetaChange.jsx
const scheduleMetaChange = REQ_(757);
// EXTERNAL MODULE: ./js/chat/chatRoom.jsx + 1 modules
const chat_chatRoom = REQ_(553);
// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/helpers.jsx
const helpers = REQ_(110);
;// ./js/chat/meetingsManager.jsx



class Occurrence {
  constructor(megaChat, occurrence) {
    const {
      decodeData
    } = megaChat.plugins.meetingsManager;
    this.megaChat = megaChat;
    this.id = occurrence.id;
    this.uid = `${occurrence.cid}-${occurrence.o || occurrence.s}`;
    this.chatId = occurrence.cid;
    this.parentId = occurrence.p;
    this.start = occurrence.s * 1000;
    this.startInitial = parseInt(occurrence.o) * 1000 || undefined;
    this.end = occurrence.e * 1000;
    this.timezone = decodeData(occurrence.tz);
    this.title = decodeData(occurrence.t);
    this.description = decodeData(occurrence.d);
    this.ownerHandle = occurrence.u;
    this.flags = occurrence.f;
    this.canceled = occurrence.c;
    this.scheduledMeeting = occurrence.scheduledMeeting;
  }
  get isUpcoming() {
    return !this.canceled && this.end > Date.now();
  }
  cancel() {
    const {
      encodeData
    } = this.megaChat.plugins.meetingsManager;
    const req = {
      a: 'mcsmp',
      p: this.parentId || this.id,
      ...this.parentId && {
        id: this.id
      },
      cid: this.chatId,
      o: this.start / 1000,
      s: this.start / 1000,
      e: this.end / 1000,
      tz: encodeData(this.timezone),
      t: encodeData(this.title),
      d: encodeData(this.description) || '',
      f: this.scheduledMeeting.flags,
      c: 1
    };
    asyncApiReq(req).catch(ex => console.error('Occurrence > cancel ->', ex));
  }
  update(startDateTime, endDateTime) {
    const {
      encodeData
    } = this.megaChat.plugins.meetingsManager;
    const req = {
      a: 'mcsmp',
      cid: this.chatId,
      p: this.parentId || this.id,
      ...this.parentId && {
        id: this.id
      },
      o: this.start / 1000,
      s: startDateTime / 1000,
      e: endDateTime / 1000,
      tz: encodeData(this.timezone),
      t: encodeData(this.title),
      d: encodeData(this.description) || '',
      f: this.scheduledMeeting.flags
    };
    asyncApiReq(req).catch(ex => console.error('Occurrence > update ->', ex));
  }
}
class ScheduledMeeting {
  constructor(megaChat, meetingInfo, fromActionPacket) {
    const {
      decodeData
    } = megaChat.plugins.meetingsManager;
    this.megaChat = megaChat;
    this.id = meetingInfo.id;
    this.chatId = meetingInfo.cid;
    this.parentId = meetingInfo.p;
    this.start = meetingInfo.s * 1000;
    this.startInitial = parseInt(meetingInfo.o) * 1000 || undefined;
    this.end = meetingInfo.e * 1000;
    this.timezone = decodeData(meetingInfo.tz);
    this.title = decodeData(meetingInfo.t);
    this.description = decodeData(meetingInfo.d);
    this.flags = meetingInfo.f;
    this.canceled = meetingInfo.c;
    this.recurring = meetingInfo.r && {
      frequency: meetingInfo.r.f || undefined,
      interval: meetingInfo.r.i || 0,
      end: meetingInfo.r.u * 1000 || undefined,
      weekDays: meetingInfo.r.wd || [],
      monthDays: meetingInfo.r.md || [],
      offset: meetingInfo.r.mwd && meetingInfo.r.mwd.length ? {
        value: meetingInfo.r.mwd[0][0],
        weekDay: meetingInfo.r.mwd[0][1]
      } : []
    };
    this.occurrences = new MegaDataMap();
    this.nextOccurrenceStart = this.start;
    this.nextOccurrenceEnd = this.end;
    this.isCompleted = false;
    this.ownerHandle = meetingInfo.u;
    this.chatRoom = meetingInfo.chatRoom;
    this.chatRoom.scheduledMeeting = this.isRoot ? this : this.parent;
    if (fromActionPacket) {
      this.initializeFromActionPacket();
    }
  }
  get isRoot() {
    return !this.parentId;
  }
  get isCanceled() {
    return !!this.canceled;
  }
  get isPast() {
    return (this.isRecurring ? this.recurring.end : this.end) < Date.now();
  }
  get isUpcoming() {
    return !(this.isCanceled || this.isPast || this.isCompleted);
  }
  get isRecurring() {
    return !!this.recurring;
  }
  get isNear() {
    return this.start - Date.now() < ChatRoom.SCHEDULED_MEETINGS_INTERVAL;
  }
  get iAmOwner() {
    if (this.ownerHandle) {
      return this.ownerHandle === u_handle;
    }
    return null;
  }
  get parent() {
    return this.isRoot ? null : this.megaChat.plugins.meetingsManager.getMeetingById(this.parentId);
  }
  setNextOccurrence() {
    const upcomingOccurrences = Object.values(this.occurrences).filter(o => o.isUpcoming);
    if (!upcomingOccurrences || !upcomingOccurrences.length) {
      this.isCompleted = this.isRecurring;
      return;
    }
    const sortedOccurrences = upcomingOccurrences.sort((a, b) => a.start - b.start);
    this.nextOccurrenceStart = sortedOccurrences[0].start;
    this.nextOccurrenceEnd = sortedOccurrences[0].end;
  }
  async getOccurrences(options) {
    const {
      from,
      to,
      count
    } = options || {};
    const {
      meetingsManager
    } = this.megaChat.plugins;
    const req = {
      a: 'mcsmfo',
      cid: this.chatId,
      ...from && {
        cf: Math.round(from / 1000)
      },
      ...to && {
        ct: Math.round(to / 1000)
      },
      ...count && {
        cc: count
      }
    };
    if (is_chatlink) {
      req.ph = is_chatlink.ph;
      delete req.cid;
    }
    const occurrences = await asyncApiReq(req);
    if (Array.isArray(occurrences)) {
      if (!options) {
        this.occurrences.clear();
      }
      for (let i = 0; i < occurrences.length; i++) {
        const occurrence = new Occurrence(this.megaChat, {
          scheduledMeeting: this,
          ...occurrences[i]
        });
        this.occurrences.set(occurrence.uid, occurrence);
      }
      this.isCompleted = false;
      this.setNextOccurrence();
      this.megaChat.trigger(meetingsManager.EVENTS.OCCURRENCES_UPDATE, this);
    }
    return this.occurrences;
  }
  getOccurrencesById(occurrenceId) {
    const occurrences = Object.values(this.occurrences.toJS()).filter(o => o.id === occurrenceId);
    return occurrences.length ? occurrences : false;
  }
  initializeFromActionPacket() {
    const {
      megaChat,
      isUpcoming,
      isCanceled,
      isRecurring,
      parent
    } = this;
    if (isUpcoming && isRecurring || parent) {
      return parent ? (() => {
        const occurrences = Object.values(parent.occurrences);
        if (occurrences.length <= 20) {
          return parent.getOccurrences().catch(nop);
        }
        occurrences.sort((a, b) => a.start - b.start);
        const {
          chatId,
          start,
          startInitial
        } = this;
        const currentIndex = occurrences.findIndex(o => o.uid === `${chatId}-${(startInitial || start) / 1000}`);
        const previous = occurrences[currentIndex - 1];
        if (!previous) {
          return parent.getOccurrences().catch(nop);
        }
        const movedBack = start <= previous.start;
        let tmp = 0;
        let newStart = movedBack ? Date.now() : previous.end;
        const maxIdx = movedBack ? currentIndex + 1 : occurrences.length;
        const startIdx = movedBack ? 0 : currentIndex;
        for (let i = startIdx; i < maxIdx; i++) {
          if (++tmp % 20 === 0) {
            parent.getOccurrences({
              from: newStart,
              to: occurrences[i].end,
              count: 20
            }).catch(dump);
            newStart = occurrences[i].end;
            tmp = 0;
          }
          parent.occurrences.remove(occurrences[i].uid);
        }
        if (tmp) {
          parent.getOccurrences({
            from: newStart,
            count: tmp,
            to: movedBack ? occurrences[currentIndex].end : occurrences[occurrences.length - 1].end
          }).catch(dump);
        }
      })() : this.getOccurrences().catch(nop);
    }
    megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS[isCanceled ? 'CANCEL' : 'INITIALIZE'], this);
  }
  isSameAsOpts(opts) {
    const {
      timezone,
      startDateTime,
      endDateTime,
      topic,
      description,
      f,
      recurring
    } = opts;
    if (this.timezone !== timezone || this.start !== startDateTime || this.end !== endDateTime) {
      return false;
    }
    if (this.title !== topic) {
      return false;
    }
    if (this.description !== description) {
      return false;
    }
    if (this.flags !== f) {
      return false;
    }
    if (!!this.recurring ^ !!recurring) {
      return false;
    }
    if (this.recurring) {
      if (this.recurring.frequency !== recurring.frequency || this.recurring.interval !== (recurring.interval || 0)) {
        return false;
      }
      if (this.recurring.end !== recurring.end) {
        return false;
      }
      let diff = array.diff(this.recurring.weekDays, recurring.weekDays || []);
      if (diff.removed.length + diff.added.length) {
        return false;
      }
      diff = array.diff(this.recurring.monthDays, recurring.monthDays || []);
      if (diff.removed.length + diff.added.length) {
        return false;
      }
      if (Array.isArray(this.recurring.offset) && !Array.isArray(recurring.offset) || !Array.isArray(this.recurring.offset) && Array.isArray(recurring.offset)) {
        return false;
      }
      if ((this.recurring.offset.value || 0) !== (recurring.offset.value || 0) || (this.recurring.offset.weekDay || 0) !== (recurring.offset.weekDay || 0)) {
        return false;
      }
    }
    return true;
  }
}
class MeetingsManager {
  constructor(megaChat) {
    this.EVENTS = {
      INITIALIZE: 'onMeetingInitialize',
      EDIT: 'onMeetingEdit',
      CANCEL: 'onMeetingCancel',
      LEAVE: 'onMeetingLeave',
      OCCURRENCES_UPDATE: 'onOccurrencesUpdate'
    };
    this.startDayStrings = [l.schedule_occur_sun, l.schedule_occur_mon, l.schedule_occur_tue, l.schedule_occur_wed, l.schedule_occur_thu, l.schedule_occur_fri, l.schedule_occur_sat];
    this.midDayStrings = [l.schedule_occur_sun_mid, l.schedule_occur_mon_mid, l.schedule_occur_tue_mid, l.schedule_occur_wed_mid, l.schedule_occur_thu_mid, l.schedule_occur_fri_mid, l.schedule_occur_sat_mid];
    this.NOTIF_TITLES = {
      recur: {
        desc: {
          update: l.schedule_notif_update_desc
        },
        name: {
          update: l.schedule_mgmt_title
        },
        time: {
          occur: l.schedule_mgmt_update_occur,
          all: l.schedule_mgmt_update_recur
        },
        convert: l.schedule_mgmt_update_convert_recur,
        inv: l.schedule_notif_invite_recur,
        multi: l.schedule_notif_update_multi,
        cancel: {
          occur: l.schedule_mgmt_cancel_occur,
          all: l.schedule_mgmt_cancel_recur
        }
      },
      once: {
        desc: {
          update: l.schedule_notif_update_desc
        },
        name: {
          update: l.schedule_mgmt_title
        },
        time: {
          occur: '',
          all: l.schedule_mgmt_update
        },
        convert: l.schedule_mgmt_update_convert,
        inv: l.schedule_notif_invite,
        multi: l.schedule_notif_update_multi,
        cancel: {
          occur: '',
          all: l.schedule_mgmt_cancel
        }
      }
    };
    this.OCCUR_STRINGS = {
      recur: {
        daily: {
          continuous: {
            occur: l.schedule_recur_time_daily_cont,
            skip: l.scheduled_recur_time_daily_skip_cont
          },
          limited: {
            occur: l.schedule_recur_time_daily,
            skip: l.scheduled_recur_time_daily_skip
          }
        },
        weekly: {
          continuous: {
            list: l.schedule_recur_time_week_cont_list,
            spec: l.schedule_recur_time_week_cont
          },
          limited: {
            list: l.schedule_recur_time_week_list,
            spec: l.schedule_recur_time_week
          }
        },
        monthly: {
          continuous: {
            num: l.schedule_recur_time_num_day_month_cont,
            pos: [[l.schedule_recur_time_first_day_month_6_cont, l.schedule_recur_time_first_day_month_0_cont, l.schedule_recur_time_first_day_month_1_cont, l.schedule_recur_time_first_day_month_2_cont, l.schedule_recur_time_first_day_month_3_cont, l.schedule_recur_time_first_day_month_4_cont, l.schedule_recur_time_first_day_month_5_cont], [l.schedule_recur_time_second_day_month_6_cont, l.schedule_recur_time_second_day_month_0_cont, l.schedule_recur_time_second_day_month_1_cont, l.schedule_recur_time_second_day_month_2_cont, l.schedule_recur_time_second_day_month_3_cont, l.schedule_recur_time_second_day_month_4_cont, l.schedule_recur_time_second_day_month_5_cont], [l.schedule_recur_time_third_day_month_6_cont, l.schedule_recur_time_third_day_month_0_cont, l.schedule_recur_time_third_day_month_1_cont, l.schedule_recur_time_third_day_month_2_cont, l.schedule_recur_time_third_day_month_3_cont, l.schedule_recur_time_third_day_month_4_cont, l.schedule_recur_time_third_day_month_5_cont], [l.schedule_recur_time_fourth_day_month_6_cont, l.schedule_recur_time_fourth_day_month_0_cont, l.schedule_recur_time_fourth_day_month_1_cont, l.schedule_recur_time_fourth_day_month_2_cont, l.schedule_recur_time_fourth_day_month_3_cont, l.schedule_recur_time_fourth_day_month_4_cont, l.schedule_recur_time_fourth_day_month_5_cont], [l.schedule_recur_time_fifth_day_month_6_cont, l.schedule_recur_time_fifth_day_month_0_cont, l.schedule_recur_time_fifth_day_month_1_cont, l.schedule_recur_time_fifth_day_month_2_cont, l.schedule_recur_time_fifth_day_month_3_cont, l.schedule_recur_time_fifth_day_month_4_cont, l.schedule_recur_time_fifth_day_month_5_cont]],
            last: [l.schedule_recur_time_fifth_day_month_6_cont, l.schedule_recur_time_fifth_day_month_0_cont, l.schedule_recur_time_fifth_day_month_1_cont, l.schedule_recur_time_fifth_day_month_2_cont, l.schedule_recur_time_fifth_day_month_3_cont, l.schedule_recur_time_fifth_day_month_4_cont, l.schedule_recur_time_fifth_day_month_5_cont]
          },
          limited: {
            num: l.schedule_recur_time_num_day_month,
            pos: [[l.schedule_recur_time_first_day_month_6, l.schedule_recur_time_first_day_month_0, l.schedule_recur_time_first_day_month_1, l.schedule_recur_time_first_day_month_2, l.schedule_recur_time_first_day_month_3, l.schedule_recur_time_first_day_month_4, l.schedule_recur_time_first_day_month_5], [l.schedule_recur_time_second_day_month_6, l.schedule_recur_time_second_day_month_0, l.schedule_recur_time_second_day_month_1, l.schedule_recur_time_second_day_month_2, l.schedule_recur_time_second_day_month_3, l.schedule_recur_time_second_day_month_4, l.schedule_recur_time_second_day_month_5], [l.schedule_recur_time_third_day_month_6, l.schedule_recur_time_third_day_month_0, l.schedule_recur_time_third_day_month_1, l.schedule_recur_time_third_day_month_2, l.schedule_recur_time_third_day_month_3, l.schedule_recur_time_third_day_month_4, l.schedule_recur_time_third_day_month_5], [l.schedule_recur_time_fourth_day_month_6, l.schedule_recur_time_fourth_day_month_0, l.schedule_recur_time_fourth_day_month_1, l.schedule_recur_time_fourth_day_month_2, l.schedule_recur_time_fourth_day_month_3, l.schedule_recur_time_fourth_day_month_4, l.schedule_recur_time_fourth_day_month_5], [l.schedule_recur_time_fifth_day_month_6, l.schedule_recur_time_fifth_day_month_0, l.schedule_recur_time_fifth_day_month_1, l.schedule_recur_time_fifth_day_month_2, l.schedule_recur_time_fifth_day_month_3, l.schedule_recur_time_fifth_day_month_4, l.schedule_recur_time_fifth_day_month_5]],
            last: [l.schedule_recur_time_last_day_month_6, l.schedule_recur_time_last_day_month_0, l.schedule_recur_time_last_day_month_1, l.schedule_recur_time_last_day_month_2, l.schedule_recur_time_last_day_month_3, l.schedule_recur_time_last_day_month_4, l.schedule_recur_time_last_day_month_5]
          }
        },
        [scheduleMetaChange.A.MODE.CANCELLED]: {
          occur: l.schedule_occurrence_time,
          all: ''
        }
      },
      once: {
        [scheduleMetaChange.A.MODE.CREATED]: {
          occur: l.schedule_occurrence_time
        },
        [scheduleMetaChange.A.MODE.EDITED]: {
          occur: l.schedule_occurrence_time_recur
        },
        [scheduleMetaChange.A.MODE.CANCELLED]: {
          occur: ''
        }
      }
    };
    this.megaChat = megaChat;
    this.scheduledMeetings = megaChat.scheduledMeetings || new MegaDataMap();
    this._goneOccurrences = {};
    this.megaChat.rebind(this.EVENTS.CANCEL, ({
      data
    }) => this.archiveMeeting(data));
    this.megaChat.rebind(this.EVENTS.LEAVE, ({
      data
    }) => this.detachMeeting(data));
    this.megaChat.rebind(`${this.EVENTS.OCCURRENCES_UPDATE}.tracker`, ({
      data
    }) => {
      if (!this._goneOccurrences[data.chatId]) {
        return;
      }
      const {
        chatId
      } = data;
      for (const scheduledId of Object.keys(this._goneOccurrences[chatId])) {
        if (this._goneOccurrences[chatId][scheduledId] === -1) {
          this._goneOccurrences[chatId][scheduledId] = this.scheduledMeetings[scheduledId] ? 0 : 1;
        }
      }
    });
  }
  checkForNotifications() {
    const time = Date.now();
    const upcomingMeetings = Object.values(this.scheduledMeetings.toJS()).filter(c => c.isUpcoming);
    for (const meeting of upcomingMeetings) {
      if (pushNotificationSettings.isAllowedForChatId(meeting.chatId)) {
        if (meeting.nextOccurrenceStart >= time + 9e5 && meeting.nextOccurrenceStart <= time + 96e4) {
          const ss = Math.floor(meeting.nextOccurrenceStart / 1000);
          const ns = Math.floor(time / 1000) + 900;
          if (ss - ns <= 10) {
            this.megaChat.trigger('onScheduleUpcoming', meeting);
          } else {
            tSleep(ss - ns).always(() => {
              this.megaChat.trigger('onScheduleUpcoming', meeting);
            });
          }
        } else if (meeting.nextOccurrenceStart >= time && meeting.nextOccurrenceStart < time + 6e4) {
          const ss = Math.floor(meeting.nextOccurrenceStart / 1000);
          const ns = Math.floor(time / 1000);
          tSleep(ss - ns).always(() => {
            this.megaChat.trigger('onScheduleStarting', meeting);
          });
        }
      }
    }
  }
  encodeData(data) {
    return data && base64urlencode(to8(data));
  }
  decodeData(data) {
    return data && from8(base64urldecode(data));
  }
  getMeetingById(meetingId) {
    return this.scheduledMeetings[meetingId];
  }
  getMeetingOrOccurrenceParent(meetingId) {
    const meeting = this.scheduledMeetings[meetingId];
    if (!meeting) {
      return false;
    }
    if (meeting.parentId) {
      return this.getMeetingOrOccurrenceParent(meeting.parentId);
    }
    return meeting;
  }
  getRoomByMeetingId() {}
  async createMeeting(meetingInfo) {
    await this.megaChat.createAndShowGroupRoomFor(meetingInfo.participants, meetingInfo.topic, {
      keyRotation: false,
      createChatLink: meetingInfo.link,
      isMeeting: true,
      openInvite: meetingInfo.openInvite,
      waitingRoom: meetingInfo.waitingRoom,
      scheduledMeeting: {
        a: 'mcsmp',
        s: meetingInfo.startDateTime / 1000,
        e: meetingInfo.endDateTime / 1000,
        tz: this.encodeData(meetingInfo.timezone),
        t: this.encodeData(meetingInfo.topic),
        d: this.encodeData(meetingInfo.description),
        f: meetingInfo.sendInvite ? 0x01 : 0x00,
        ...meetingInfo.recurring && {
          r: {
            f: meetingInfo.recurring.frequency,
            wd: meetingInfo.recurring.weekDays,
            md: meetingInfo.recurring.monthDays,
            mwd: meetingInfo.recurring.offset,
            ...meetingInfo.recurring.end && {
              u: meetingInfo.recurring.end / 1000
            },
            ...meetingInfo.recurring.interval && {
              i: meetingInfo.recurring.interval
            }
          }
        }
      }
    });
  }
  async updateMeeting(meetingInfo, chatRoom) {
    const {
      scheduledMeeting,
      chatId,
      publicLink,
      options
    } = chatRoom;
    await megaChat.plugins.chatdIntegration.updateScheduledMeeting(meetingInfo, scheduledMeeting.id, chatId);
    const nextParticipants = meetingInfo.participants;
    const prevParticipants = chatRoom.getParticipantsExceptMe();
    const participantsDiff = JSON.stringify(nextParticipants) !== JSON.stringify(prevParticipants);
    if (participantsDiff) {
      const removed = prevParticipants.filter(h => !nextParticipants.includes(h));
      const added = nextParticipants.filter(h => !prevParticipants.includes(h));
      if (removed.length) {
        for (let i = removed.length; i--;) {
          chatRoom.trigger('onRemoveUserRequest', [removed[i]]);
        }
      }
      if (added.length) {
        chatRoom.trigger('onAddUserRequest', [added]);
      }
    }
    if (!!meetingInfo.link !== !!publicLink) {
      chatRoom.updatePublicHandle(!meetingInfo.link, meetingInfo.link);
    }
    if (meetingInfo.waitingRoom !== options[chat_chatRoom.MCO_FLAGS.WAITING_ROOM]) {
      chatRoom.toggleWaitingRoom();
    }
    if (meetingInfo.openInvite !== options[chat_chatRoom.MCO_FLAGS.OPEN_INVITE]) {
      chatRoom.toggleOpenInvite();
    }
  }
  cancelMeeting(scheduledMeeting, chatId) {
    return this.megaChat.plugins.chatdIntegration.cancelScheduledMeeting(scheduledMeeting, chatId);
  }
  deleteMeeting(scheduledMeetingId, chatId) {
    return this.megaChat.plugins.chatdIntegration.deleteScheduledMeeting(scheduledMeetingId, chatId);
  }
  attachMeeting(meetingInfo, fromActionPacket) {
    const chatRoom = meetingInfo.chatRoom || this.megaChat.getChatById(meetingInfo.cid);
    if (chatRoom) {
      const scheduledMeeting = new ScheduledMeeting(this.megaChat, {
        chatRoom,
        ...meetingInfo
      }, fromActionPacket);
      this.scheduledMeetings.set(meetingInfo.id, scheduledMeeting);
      return scheduledMeeting;
    }
  }
  detachMeeting(scheduledMeeting) {
    if (scheduledMeeting) {
      this.archiveMeeting(scheduledMeeting);
      scheduledMeeting.chatRoom.scheduledMeeting = null;
      this.scheduledMeetings.remove(scheduledMeeting.id);
      if (fmdb) {
        fmdb.del('mcsm', scheduledMeeting.id);
      }
    }
  }
  archiveMeeting(scheduledMeeting) {
    const {
      chatRoom
    } = scheduledMeeting;
    tSleep(2).then(() => chatRoom.hasMessages(true) ? null : chatRoom.archive());
  }
  filterUpcomingMeetings(conversations) {
    const upcomingMeetings = Object.values(conversations || {}).filter(c => {
      return c.isDisplayable() && c.isMeeting && c.scheduledMeeting && c.scheduledMeeting.isUpcoming && c.iAmInRoom() && !c.havePendingCall();
    }).sort((a, b) => a.scheduledMeeting.nextOccurrenceStart - b.scheduledMeeting.nextOccurrenceStart || a.ctime - b.ctime);
    const nextOccurrences = upcomingMeetings.reduce((nextOccurrences, chatRoom) => {
      const {
        nextOccurrenceStart
      } = chatRoom.scheduledMeeting;
      if ((0,helpers.cK)(nextOccurrenceStart)) {
        nextOccurrences.today.push(chatRoom);
      } else if ((0,helpers.ef)(nextOccurrenceStart)) {
        nextOccurrences.tomorrow.push(chatRoom);
      } else {
        const date = time2date(nextOccurrenceStart / 1000, 19);
        if (!nextOccurrences.rest[date]) {
          nextOccurrences.rest[date] = [];
        }
        nextOccurrences.rest[date].push(chatRoom);
      }
      return nextOccurrences;
    }, {
      today: [],
      tomorrow: [],
      rest: {}
    });
    return {
      upcomingMeetings,
      nextOccurrences
    };
  }
  getOccurrenceStrings(meta) {
    const res = [];
    const {
      prevTiming,
      timeRules,
      mode,
      occurrence,
      recurring,
      converted
    } = meta;
    const {
      MODE
    } = scheduleMetaChange.A;
    if (!mode) {
      return res;
    }
    const {
      OCCUR_STRINGS
    } = this;
    let string;
    if (recurring) {
      res.push(this._parseOccurrence(timeRules, mode, occurrence));
      if (prevTiming && !(occurrence && mode === MODE.CANCELLED)) {
        res.push(this._parseOccurrence(prevTiming, mode, occurrence));
      }
    } else {
      const {
        startTime,
        endTime
      } = timeRules;
      string = OCCUR_STRINGS.once[mode].occur;
      res.push(string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%6', time2date(startTime, 20)).replace('%s', time2date(startTime, 11)));
      if (prevTiming) {
        const {
          startTime: pStartTime,
          endTime: pEndTime
        } = prevTiming;
        if (converted) {
          res.push(this._parseOccurrence(prevTiming, mode, occurrence));
        } else {
          res.push(string.replace('%1', toLocaleTime(pStartTime)).replace('%2', toLocaleTime(pEndTime)).replace('%6', time2date(pStartTime, 20)).replace('%s', time2date(pStartTime, 11)));
        }
      }
    }
    return res;
  }
  _parseOccurrence(timeRules, mode, occurrence) {
    const {
      startTime,
      endTime,
      days,
      dayInt,
      interval,
      month,
      recurEnd,
      skipDay
    } = timeRules;
    const {
      recur,
      once
    } = this.OCCUR_STRINGS;
    const occurrenceEnd = recurEnd ? 'limited' : 'continuous';
    let string = '';
    if (recur[mode]) {
      return occurrence ? recur[mode].occur.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%s', time2date(startTime, 11)) : recur[mode].all;
    } else if (month) {
      const {
        count,
        occur
      } = month;
      string = count < 0 ? mega.icu.format(recur.monthly[occurrenceEnd].last[occur], interval) : mega.icu.format(recur.monthly[occurrenceEnd].pos[count][occur], interval);
      return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
    } else if (days) {
      if (days.length > 1) {
        if (days.length === 7) {
          return recur.daily[occurrenceEnd].occur.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
        }
        const weekDays = days.map((day, idx) => {
          if (idx) {
            return this.midDayStrings[day];
          }
          return this.startDayStrings[day];
        });
        string = mega.icu.format(recur.weekly[occurrenceEnd].list, interval);
        string = mega.utils.trans.listToString(weekDays, string);
      } else {
        string = mega.icu.format(recur.weekly[occurrenceEnd].spec, interval).replace('%s', this.startDayStrings[days[0]]);
      }
      return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
    } else if (dayInt) {
      string = mega.icu.format(recur.monthly[occurrenceEnd].num, interval);
      return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2)).replace('%5', dayInt);
    } else if (skipDay) {
      string = mega.icu.format(recur.daily[occurrenceEnd].skip, interval);
      return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
    }
    string = once[mode].occur;
    return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%6', time2date(startTime, 20)).replace('%s', time2date(startTime, 11));
  }
  getFormattingMeta(scheduledId, data, chatRoom) {
    const {
      MODE
    } = scheduleMetaChange.A;
    const meta = {
      userId: data.sender || false,
      timeRules: {},
      mode: MODE.EDITED,
      handle: scheduledId,
      cid: chatRoom.chatId
    };
    const changeSet = data.schedChange || data.cs || false;
    if (changeSet) {
      const {
        s,
        e,
        c,
        r,
        t,
        d: desc
      } = changeSet;
      let onlyTitle = typeof t !== 'undefined';
      if (Array.isArray(c) && c[1]) {
        meta.mode = MODE.CANCELLED;
      }
      if (Array.isArray(s)) {
        meta.prevTiming = {
          startTime: s[0]
        };
        meta.timeRules.startTime = s[1] || s[0];
      }
      const meeting = this.getMeetingOrOccurrenceParent(scheduledId);
      if (Array.isArray(e)) {
        if (!meta.prevTiming) {
          meta.prevTiming = {
            startTime: meeting ? Math.floor(meeting.start / 1000) : 0
          };
          meta.timeRules.startTime = meta.prevTiming.startTime;
        }
        meta.prevTiming.endTime = e[0];
        meta.timeRules.endTime = e[1] || e[0];
        onlyTitle = false;
      }
      if (desc) {
        meta.description = true;
        onlyTitle = false;
      }
      if (Array.isArray(r)) {
        const parseR = r => r ? typeof r === 'string' ? JSON.parse(r) : r : false;
        const prev = parseR(r[0]);
        const next = parseR(r[1]);
        if (r.length === 1) {
          meta.converted = false;
          meta.timeRules = this._recurringTimings(prev, meta.timeRules || {});
          meta.prevTiming = this._recurringTimings(prev, meta.prevTiming);
          meta.recurring = r[0] !== '';
        } else {
          meta.converted = !!(!!prev ^ !!next);
          if (prev) {
            meta.prevTiming = this._recurringTimings(prev, meta.prevTiming || {});
          }
          meta.timeRules = this._recurringTimings(next, meta.timeRules || {});
          meta.recurring = next !== false;
        }
        onlyTitle = false;
      }
      if (!meeting || meeting.id !== scheduledId) {
        meta.occurrence = true;
        meta.recurring = true;
      }
      if (Array.isArray(t)) {
        meta.topicChange = true;
        meta.onlyTitle = onlyTitle;
        meta.topic = this.decodeData(t[1]);
        meta.oldTopic = this.decodeData(t[0]);
      }
      return meta;
    }
    return this.noCsMeta(scheduledId, data, chatRoom);
  }
  _recurringTimings(meta, obj) {
    if (!meta) {
      return obj;
    }
    obj.recurEnd = meta.u || false;
    obj.interval = meta.i || 1;
    if (meta.wd) {
      obj.days = meta.wd.sort((a, b) => a - b).map(wd => wd === 7 ? 0 : wd);
    }
    if (meta.md) {
      obj.dayInt = meta.md[0];
    }
    if (meta.mwd) {
      obj.month = meta.mwd.map(oc => {
        return {
          count: (oc[0] || 1) - 1,
          occur: oc[1] ? oc[1] === 7 ? 0 : oc[1] : 1
        };
      })[0];
    }
    if (meta.f === 'd' && meta.i > 1) {
      obj.skipDay = true;
    } else if (meta.f === 'd' && meta.i === 1) {
      obj.days = [1, 2, 3, 4, 5, 6, 0];
    }
    return obj;
  }
  noCsMeta(scheduledId, data, chatRoom) {
    const meta = {
      timeRules: {},
      userId: data.sender || false,
      ap: data,
      handle: scheduledId,
      cid: chatRoom.chatId
    };
    if (!this.getMeetingOrOccurrenceParent(scheduledId) && !chatRoom.scheduledMeeting) {
      const res = this._checkOccurrenceAwait(chatRoom, scheduledId, meta);
      if (res) {
        return res;
      }
    }
    const meeting = this.getMeetingOrOccurrenceParent(scheduledId) || chatRoom.scheduledMeeting;
    assert(meeting, `Invalid scheduled meeting state for ${scheduledId} msg`);
    const toS = ms => Math.floor(ms / 1000);
    const {
      MODE
    } = scheduleMetaChange.A;
    meta.timeRules.startTime = toS(meeting.start);
    meta.timeRules.endTime = toS(meeting.end);
    meta.topic = meeting.title;
    meta.recurring = !!meeting.recurring;
    meta.mode = meeting.canceled ? MODE.CANCELLED : MODE.CREATED;
    meta.occurrence = meta.recurring && meeting.id !== scheduledId;
    if (!meta.occurrence && !meeting.canceled) {
      meta.mode = MODE.CREATED;
    }
    const cal = ms => {
      const date = new Date(ms);
      return {
        date: date.getDate(),
        month: time2date(toS(ms), 12)
      };
    };
    if (meta.occurrence) {
      const occurrences = meeting.getOccurrencesById(scheduledId);
      if (!occurrences) {
        meta.mode = MODE.EDITED;
        const res = this._checkOccurrenceAwait(chatRoom, scheduledId, meta);
        if (res) {
          return res;
        }
        meta.ap = data;
        return meta;
      }
      meta.mode = occurrences.some(o => o.canceled) ? MODE.CANCELLED : MODE.EDITED;
      meta.calendar = cal(occurrences[0].start);
      const timeDiff = meta.timeRules.endTime - meta.timeRules.startTime;
      meta.timeRules.startTime = toS(occurrences[0].start);
      meta.timeRules.endTime = toS(occurrences[0].end);
      if (occurrences.length === 1 && occurrences[0].startInitial) {
        meta.prevTiming = {
          startTime: toS(occurrences[0].startInitial)
        };
        meta.prevTiming.endTime = meta.prevTiming.startTime + timeDiff;
      }
    } else if (meta.recurring) {
      const {
        end,
        weekDays = [],
        interval,
        monthDays = [],
        offset,
        frequency
      } = meeting.recurring;
      meta.recurring = true;
      meta.timeRules.recurEnd = end ? toS(end) : false;
      meta.timeRules.interval = interval || 1;
      if (frequency === 'd' && interval > 1) {
        meta.timeRules.skipDay = true;
      } else if (frequency === 'd' && interval === 1) {
        meta.timeRules.days = [1, 2, 3, 4, 5, 6, 0];
      }
      if (weekDays.length) {
        meta.timeRules.days = weekDays.sort((a, b) => a - b).map(wd => wd === 7 ? 0 : wd);
      }
      if (monthDays.length) {
        meta.timeRules.dayInt = monthDays[0];
      }
      if (!Array.isArray(offset)) {
        meta.timeRules.month = {
          count: (offset.value || 1) - 1,
          occur: offset.weekDay ? offset.weekDay === 7 ? 0 : offset.weekDay : 1
        };
      }
      meta.calendar = cal(meeting.start);
    } else {
      meta.calendar = cal(meeting.start);
    }
    if (!meta.occurrence && meeting.canceled && $.len(meta.timeRules)) {
      meta.mode = MODE.CREATED;
    }
    delete meta.ap;
    return meta;
  }
  _checkOccurrenceAwait(chatRoom, scheduledId, meta) {
    if (!this._goneOccurrences[chatRoom.chatId]) {
      this._goneOccurrences[chatRoom.chatId] = {};
    }
    if (typeof this._goneOccurrences[chatRoom.chatId][scheduledId] === 'undefined') {
      this._goneOccurrences[chatRoom.chatId][scheduledId] = -1;
      return meta;
    }
    const datum = this._goneOccurrences[chatRoom.chatId];
    if (datum[scheduledId] === -1) {
      return meta;
    } else if (datum[scheduledId] === 1) {
      meta.gone = true;
      return meta;
    }
    return false;
  }
  areMetaObjectsSame(obj1, obj2) {
    if (obj1 && !obj2 || !obj1 && obj2) {
      return false;
    }
    const keys = Object.keys(obj1);
    if (keys.length !== $.len(obj2)) {
      return false;
    }
    const diff = array.diff(keys, Object.keys(obj2));
    if (diff.removed.length + diff.added.length) {
      return false;
    }
    for (const key of keys) {
      if (!obj2.hasOwnProperty(key)) {
        return false;
      }
      if (obj1[key] instanceof Object && obj2[key] instanceof Object) {
        if (!this.areMetaObjectsSame(obj1[key], obj2[key])) {
          return false;
        }
      } else if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {
        const keyDiff = array.diff(obj1[key], obj2[key]);
        if (keyDiff.removed.length + keyDiff.added.length) {
          return false;
        }
      } else if (obj1[key] !== obj2[key]) {
        return false;
      }
    }
    return true;
  }
}
const meetingsManager = MeetingsManager;
window.MeetingsManager = MeetingsManager;
// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
const applyDecoratedDescriptor = REQ_(793);
// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
;// ./js/chat/chatOnboarding.jsx

let _dec, _class;


const ChatOnboarding = (_dec = (0,mixins.hG)(1000), _class = class ChatOnboarding {
  constructor(megaChat) {
    this.finished = false;
    if (u_type === 3 && !is_mobile) {
      this.state = {
        [OBV4_FLAGS.CHAT]: -1
      };
      this.megaChat = megaChat;
      this.flagMap = attribCache.bitMapsManager.exists('obv4') ? attribCache.bitMapsManager.get('obv4') : new MegaDataBitMap('obv4', false, Object.values(OBV4_FLAGS));
      const keys = Object.keys(this.state);
      const promises = keys.map(key => this.flagMap.get(key));
      Promise.allSettled(promises).then(res => {
        for (let i = 0; i < res.length; ++i) {
          const v = res[i];
          if (v.status === 'fulfilled') {
            this.handleFlagChange(null, null, keys[i], v.value);
          }
        }
      });
      this.interval = setInterval(() => {
        if (!$.dialog) {
          this._checkAndShowStep();
        }
      }, 10000);
      this.initListeners();
    }
  }
  initListeners() {
    this.flagMap.addChangeListener((...args) => this.handleFlagChange(...args));
    this.megaChat.chatUIFlags.addChangeListener(SoonFc(200, () => {
      if (this.megaChat.chatUIFlags.convPanelCollapse && $.dialog === 'onboardingDialog') {
        closeDialog();
      }
      this._checkAndShowStep();
    }));
    this.megaChat.addChangeListener(() => {
      const room = this.megaChat.getCurrentRoom();
      if (!room) {
        return;
      }
      this.checkAndShowStep();
    });
  }
  checkAndShowStep() {
    this._checkAndShowStep();
  }
  _shouldSkipShow() {
    if (!M.chat || !mega.ui.onboarding || $.dialog || loadingDialog.active || u_type < 3 || is_mobile || $.msgDialog) {
      return true;
    }
    this.$topRightMenu = this.$topRightMenu || $('.top-menu-popup', '#topmenu');
    if (!this.$topRightMenu.hasClass('o-hidden')) {
      return true;
    }
    this.$topAccDropdown = this.$topAccDropdown || $('.js-dropdown-account', '#topmenu');
    if (this.$topAccDropdown.hasClass('show')) {
      return true;
    }
    this.$topNotifDropdown = this.$topNotifDropdown || $('.js-dropdown-notification', '#topmenu');
    if (this.$topNotifDropdown.hasClass('show')) {
      return true;
    }
    this.$searchPanel = this.$searchPanel || $('.search-panel', '.conversationsApp');
    return this.$searchPanel.hasClass('expanded');
  }
  _checkAndShowStep() {
    if (this._shouldSkipShow()) {
      return;
    }
    const {
      sections
    } = mega.ui.onboarding;
    if (!sections) {
      return;
    }
    const {
      chat: obChat
    } = sections;
    if (!obChat) {
      return;
    }
    if (this.state[OBV4_FLAGS.CHAT]) {
      return;
    }
    this.showDefaultNextStep(obChat);
  }
  showDefaultNextStep(obChat) {
    const nextIdx = obChat.searchNextOpenStep();
    if (nextIdx !== false && (!this.$obDialog || !this.$obDialog.is(':visible')) && (this.obToggleDrawn || $('.conversations-category', '.conversationsApp').length)) {
      this.obToggleDrawn = true;
      if (obChat.steps && obChat.steps[nextIdx] && obChat.steps[nextIdx].isComplete) {
        return;
      }
      obChat.startNextOpenSteps(nextIdx);
      this.$obDialog = this.$obDialog || $('#ob-dialog');
    }
  }
  handleFlagChange(...args) {
    if (args.length >= 4 && typeof args[2] === 'string' && typeof args[3] === 'number' && this.state.hasOwnProperty(args[2])) {
      if (d) {
        console.debug(`Chat onboarding flag ${args[2]}: ${this.state[args[2]]} -> ${args[3]}`);
      }
      this.state[args[2]] = args[3];
      if (args[2] === OBV4_FLAGS.CHAT && args[3] === 1 && this.interval) {
        clearInterval(this.interval);
        delete this.interval;
      }
    }
  }
  destroy() {
    if (this.interval) {
      clearInterval(this.interval);
      delete this.interval;
    }
  }
}, (0,applyDecoratedDescriptor.A)(_class.prototype, "checkAndShowStep", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "checkAndShowStep"), _class.prototype), _class);

// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
const call = REQ_(3);
;// ./js/chat/chat.jsx



REQ_(623);
REQ_(553);
REQ_(269);




const EMOJI_DATASET_VERSION = 5;
const CHAT_ONHISTDECR_RECNT = "onHistoryDecrypted.recent";
const LOAD_ORIGINALS = {
  'image/gif': 25e6,
  'image/png': 2e5,
  'image/webp': 2e5
};
const CHATUIFLAGS_MAPPING = {
  'convPanelCollapse': 'cPC'
};
function Chat() {
  const self = this;
  this.is_initialized = false;
  this.logger = MegaLogger.getLogger("chat");
  this.mbListeners = [];
  this.chats = new MegaDataMap();
  this.scheduledMeetings = new MegaDataMap();
  this.chatUIFlags = new MegaDataMap();
  this.$chatTreePanePs = [];
  this.initChatUIFlagsManagement();
  this.currentlyOpenedChat = null;
  this.currentlyOpenedView = null;
  this.lastOpenedChat = null;
  this.archivedChatsCount = 0;
  this.FORCE_EMAIL_LOADING = localStorage.fel;
  this.WITH_SELF_NOTE = mega.flags.ff_n2s || localStorage.withSelfNote;
  this._imageLoadCache = Object.create(null);
  this._imagesToBeLoaded = Object.create(null);
  this._imageAttributeCache = Object.create(null);
  this._queuedMccPackets = [];
  this._queuedMcsmPackets = {};
  this._queuedMessageUpdates = [];
  this._queuedChatRoomEvents = Object.create(null);
  this.handleToId = Object.create(null);
  this.publicChatKeys = Object.create(null);
  this.SOUNDS = {
    ALERT: 'alert_info_message',
    INCOMING_MSG: 'incoming_chat_message',
    INCOMING_CALL: 'incoming_voice_video_call',
    CALL_JOIN: 'user_join_call',
    CALL_LEFT: 'user_left_call',
    CALL_END: 'end_call',
    CALL_JOIN_WAITING: 'user_join_waiting',
    RECONNECT: 'reconnecting',
    SPEAKER_TEST: 'test_speaker'
  };
  this.options = {
    'delaySendMessageIfRoomNotAvailableTimeout': 3000,
    'plugins': {
      'chatdIntegration': ChatdIntegration,
      'callManager2': CallManager2,
      'urlFilter': UrlFilter,
      'emoticonShortcutsFilter': EmoticonShortcutsFilter,
      'emoticonsFilter': EmoticonsFilter,
      'callFeedback': CallFeedback,
      'presencedIntegration': PresencedIntegration,
      'persistedTypeArea': PersistedTypeArea,
      'btRtfFilter': BacktickRtfFilter,
      'rtfFilter': RtfFilter,
      'richpreviewsFilter': RichpreviewsFilter,
      'chatToastIntegration': ChatToastIntegration,
      'chatStats': ChatStats,
      'geoLocationLinks': GeoLocationLinks,
      meetingsManager,
      'chatOnboarding': ChatOnboarding,
      'userHelper': ChatUserHelper
    },
    'chatNotificationOptions': {
      'textMessages': {
        'incoming-chat-message': {
          title: l.notif_title_incoming_msg,
          'icon' (notificationObj) {
            return notificationObj.options.icon;
          },
          'body' (notificationObj, params) {
            if (params.type === 'private') {
              return l.notif_body_incoming_msg.replace('%s', params.from);
            }
            return l.notif_body_incoming_msg_group.replace('%1', params.from).replace('%2', params.roomTitle);
          }
        },
        'incoming-voice-video-call': {
          'title': l[17878] || "Incoming call",
          'icon' (notificationObj) {
            return notificationObj.options.icon;
          },
          'body' (notificationObj, params) {
            return l[5893].replace('[X]', params.from);
          }
        },
        'screen-share-error': {
          title: l.screenshare_failed_notif || 'You are no longer sharing your screen',
          icon: notificationObj => {
            return notificationObj.options.icon;
          },
          body: ''
        },
        'upcoming-scheduled-occurrence': {
          title: ({
            options
          }) => {
            return options.meeting.title;
          },
          icon: `${staticpath}/images/mega/mega-icon.svg`,
          body: l.notif_body_scheduled_upcoming
        },
        'starting-scheduled-occurrence': {
          title: ({
            options
          }) => {
            return options.meeting.title;
          },
          icon: `${staticpath}/images/mega/mega-icon.svg`,
          body: l.notif_body_scheduled_starting
        }
      },
      sounds: Object.values(this.SOUNDS)
    },
    'chatStoreOptions': {
      'autoPurgeMaxMessagesPerRoom': 1024
    }
  };
  this.SOUNDS.buffers = Object.create(null);
  this.plugins = {};
  self.filePicker = null;
  self._chatsAwaitingAps = {};
  MegaDataObject.call(this, {
    "currentlyOpenedChat": null,
    "activeCall": null,
    'routingSection': null,
    'routingSubSection': null,
    'routingParams': null
  });
  this.routing = new ChatRouting(this);
  Object.defineProperty(this, 'hasSupportForCalls', {
    get () {
      return typeof SfuClient !== 'undefined' && typeof TransformStream !== 'undefined' && window.RTCRtpSender && !!RTCRtpSender.prototype.createEncodedStreams;
    }
  });
  this.minuteClockInterval = setInterval(() => this._syncChats(), 6e4);
  return this;
}
inherits(Chat, MegaDataObject);
Object.defineProperty(Chat, 'mcf', {
  value: Object.create(null)
});
Object.defineProperty(Chat, 'mcsm', {
  value: Object.create(null)
});
Chat.prototype.init = promisify(function (resolve, reject) {
  const self = this;
  if (self.is_initialized) {
    self.destroy();
  }
  if (d) {
    console.time('megachat:plugins:init');
  }
  self.plugins = Object.create(null);
  self.plugins.chatNotifications = new ChatNotifications(self, self.options.chatNotificationOptions);
  self.plugins.chatNotifications.notifications.rebind('onAfterNotificationCreated.megaChat', () => {
    self.updateSectionUnreadCount();
  });
  Object.keys(self.options.plugins).forEach(plugin => {
    self.plugins[plugin] = new self.options.plugins[plugin](self);
  });
  if (d) {
    console.timeEnd('megachat:plugins:init');
  }
  $(document.body);
  if (!is_chatlink) {
    $(mega.ui.header.setStatus).rebind('mousedown.megachat', '.sub-menu.status button', function () {
      const presence = $(this).data("presence");
      self._myPresence = presence;
      const targetPresence = PresencedIntegration.cssClassToPresence(presence);
      self.plugins.presencedIntegration.setPresence(targetPresence);
      if (targetPresence !== UserPresence.PRESENCE.OFFLINE) {
        Object.keys(self.plugins.chatdIntegration.chatd.shards).forEach(k => {
          const v = self.plugins.chatdIntegration.chatd.shards[k];
          v.connectionRetryManager.requiresConnection();
        });
      }
    });
  }
  self.$container = $('.fm-chat-block');
  if (M.chat && !is_chatlink) {
    $('.activity-status-block, .activity-status').removeClass('hidden');
    $('.js-dropdown-account .status-dropdown').removeClass('hidden');
  }
  if (is_chatlink) {
    const {
      ph,
      key
    } = is_chatlink;
    Chat.mcf[ph] = key;
    this.publicChatKeys[ph] = key;
  }
  const promises = [];
  const rooms = Object.keys(Chat.mcf);
  for (let i = rooms.length; i--;) {
    const roomId = rooms[i];
    const room = Chat.mcf[roomId];
    if (!this.publicChatKeys[rooms[i]]) {
      promises.push(self.plugins.chatdIntegration.openChat(room, true));
    }
    delete Chat.mcf[rooms[i]];
  }
  Promise.allSettled(promises).then(res => {
    const pub = Object.keys(this.publicChatKeys);
    return Promise.allSettled([res].concat(pub.map(pch => {
      return this.plugins.chatdIntegration.openChat(pch, true);
    })));
  }).then(res => {
    res = res[0].value.concat(res.slice(1));
    this.logger.info('chats settled...', res);
    if (is_mobile) {
      return;
    }
    if (is_chatlink) {
      const start = document.getElementById('startholder');
      this.flyoutStartHolder = document.createElement('div');
      this.flyoutStartHolder.className = 'flyout-holder';
      start.appendChild(this.flyoutStartHolder);
    }
    const selector = is_chatlink ? '.chat-links-preview > .chat-app-container' : '.section.conversations';
    const rootDOMNode = this.rootDOMNode = document.querySelector(selector);
    const $$root = this.$$root = (0,ReactDOM_.createRoot)(rootDOMNode);
    $$root.render(REaCt().createElement(conversations.Ay.ConversationsApp, {
      megaChat: this,
      routingSection: this.routingSection,
      routingSubSection: this.routingSubSection,
      routingParams: this.routingParams
    }));
    this.onChatsHistoryReady().then(() => {
      const room = this.getCurrentRoom();
      if (room) {
        room.scrollToChat();
      }
      return room;
    }).dump('on-chat-history-loaded');
    this.is_initialized = true;
    this.registerUploadListeners();
    this.trigger('onInit');
    mBroadcaster.sendMessage('chat_initialized');
    setInterval(this.removeMessagesByRetentionTime.bind(this, null), 2e4);
    this.autoJoinIfNeeded();
    const scheduledMeetings = Object.values(Chat.mcsm);
    if (scheduledMeetings && scheduledMeetings.length) {
      for (let i = scheduledMeetings.length; i--;) {
        const scheduledMeeting = scheduledMeetings[i];
        this.plugins.meetingsManager.attachMeeting(scheduledMeeting);
        delete Chat.mcsm[scheduledMeeting.id];
      }
    }
    if (notify) {
      notify.countAndShowNewNotifications();
    }
    return true;
  }).then(resolve).catch(reject);
});
Chat.prototype.showUpgradeDialog = function () {
  return is_extension ? msgDialog('warningb', l[1900], l[8841]) : msgDialog('confirmation', l[1900], l[8840], '', cb => cb && location.reload());
};
Chat.prototype._syncChats = function () {
  if (!this.is_initialized) {
    return;
  }
  this.plugins.meetingsManager.checkForNotifications();
  const {
    chats,
    logger
  } = this;
  if (chats && chats.length) {
    chats.forEach(({
      chatId,
      scheduledMeeting
    }) => {
      const dnd = pushNotificationSettings.getDnd(chatId);
      if (dnd && dnd < unixtime()) {
        pushNotificationSettings.disableDnd(chatId);
        if (logger) {
          logger.debug(`Chat.prototype._syncDnd chatId=${chatId}`);
        }
      }
      const {
        isUpcoming,
        chatRoom,
        id
      } = scheduledMeeting || {};
      if (isUpcoming) {
        scheduledMeeting.setNextOccurrence();
        chatRoom.trackDataChange();
        if (logger) {
          logger.debug(`Chat.prototype.__syncScheduledMeetings id=${id} chatId=${chatId}`);
        }
      }
    });
  }
};
Chat.prototype.loadChatUIFlagsFromConfig = function (val) {
  let hadChanged = false;
  let flags = val || mega.config.get("cUIF");
  if (flags) {
    if (typeof flags !== 'object') {
      flags = {};
    }
    Object.keys(CHATUIFLAGS_MAPPING).forEach(k => {
      const v = flags[CHATUIFLAGS_MAPPING[k]];
      hadChanged = v !== undefined && this.chatUIFlags.set(k, v) !== false || hadChanged;
    });
  }
  return hadChanged;
};
Chat.prototype.cleanup = function (clean) {
  const room = this.getCurrentRoom();
  if (room) {
    room.hide();
  }
  M.chat = false;
  this.routingParams = null;
  this.routingSection = null;
  this.routingSubSection = null;
  if (clean) {
    M.currentdirid = page = false;
  }
};
Chat.prototype.initChatUIFlagsManagement = function () {
  const self = this;
  self.loadChatUIFlagsFromConfig();
  this.chatUIFlags.addChangeListener((hashmap, extraArg) => {
    const flags = mega.config.get("cUIF") || {};
    let hadChanged = false;
    let hadLocalChanged = false;
    Object.keys(CHATUIFLAGS_MAPPING).forEach((k) => {
      if (flags[CHATUIFLAGS_MAPPING[k]] !== self.chatUIFlags[k]) {
        if (extraArg === 0xDEAD) {
          self.chatUIFlags._data[k] = flags[CHATUIFLAGS_MAPPING[k]];
          hadLocalChanged = true;
        } else {
          flags[CHATUIFLAGS_MAPPING[k]] = self.chatUIFlags[k];
          hadChanged = true;
        }
      }
    });
    if (hadLocalChanged) {
      if (extraArg !== 0xDEAD) {
        self.chatUIFlags.trackDataChange(0xDEAD);
      }
      $.tresizer();
    }
    if (extraArg === 0xDEAD) {
      return;
    }
    if (hadChanged) {
      mega.config.set("cUIF", flags);
    }
  });
  this.mbListeners.push(mBroadcaster.addListener('fmconfig:cUIF', tryCatch(v => {
    if (self.loadChatUIFlagsFromConfig(v)) {
      self.chatUIFlags.trackDataChange(0xDEAD);
    }
  })), mBroadcaster.addListener('statechange', state => {
    this.trigger('viewstateChange', state);
  }));
};
Chat.prototype.unregisterUploadListeners = function (destroy) {
  'use strict';

  const self = this;
  mBroadcaster.removeListener(self._uplDone);
  mBroadcaster.removeListener(self._uplError);
  mBroadcaster.removeListener(self._uplAbort);
  mBroadcaster.removeListener(self._uplFAError);
  mBroadcaster.removeListener(self._uplFAReady);
  if (destroy) {
    mBroadcaster.removeListener(self._uplStart);
  }
  delete self._uplError;
};
Chat.prototype.registerUploadListeners = function () {
  'use strict';

  const self = this;
  const logger = d && MegaLogger.getLogger('chatUploadListener', false, self.logger);
  self.unregisterUploadListeners(true);
  const forEachChat = function (chats, callback) {
    let result = 0;
    if (!Array.isArray(chats)) {
      chats = [chats];
    }
    for (let i = chats.length; i--;) {
      const room = self.getRoomFromUrlHash(chats[i]);
      if (room) {
        callback(room, ++result);
      }
    }
    return result;
  };
  const lookupPendingUpload = function (id) {
    console.assert((id | 0) > 0 || String(id).length === 8, 'Invalid lookupPendingUpload arguments...');
    for (const uid in ulmanager.ulEventData) {
      if (ulmanager.ulEventData[uid].faid === id || ulmanager.ulEventData[uid].h === id) {
        return uid;
      }
    }
  };
  const unregisterListeners = function () {
    if (!$.len(ulmanager.ulEventData)) {
      self.unregisterUploadListeners();
    }
  };
  const onUploadComplete = function (ul) {
    if (ulmanager.ulEventData[ul && ul.uid]) {
      forEachChat(ul.chat, (room) => {
        if (d) {
          logger.debug('Attaching node[%s] to chat room[%s]...', ul.h, room.chatId, ul.uid, ul, M.d[ul.h]);
        }
        room.attachNodes([ul.h]).catch(dump);
      });
      delete ulmanager.ulEventData[ul.uid];
      unregisterListeners();
    }
  };
  const onUploadCompletion = function (uid, handle, faid, chat) {
    if (!chat) {
      if (d > 1) {
        logger.debug('ignoring upload:completion that is unrelated to chat.', arguments);
      }
      return;
    }
    const n = M.getNodeByHandle(handle);
    const ul = ulmanager.ulEventData[uid] || false;
    if (d) {
      logger.info('upload:completion', uid, handle, faid, ul, n);
    }
    if (!ul) {
      if (d) {
        logger.error('Upload event data store missing...', uid, n, ul);
      }
    } else {
      ul.h = handle;
      if (ul.efa && !n) {
        if (d) {
          logger.error('Invalid state, efa set on deduplication?', ul.efa, ul);
        }
        ul.efa = 0;
      }
      if (ul.efa && (!n.fa || String(n.fa).split('/').length < ul.efa)) {
        ul.faid = faid;
        if (d) {
          logger.info('Waiting for file attribute to arrive.', handle, ul);
        }
      } else {
        onUploadComplete(ul);
      }
    }
  };
  const onUploadError = function (uid, error) {
    const ul = ulmanager.ulEventData[uid];
    if (d) {
      logger.debug(error === -0xDEADBEEF ? 'upload:abort' : 'upload.error', uid, error, [ul]);
    }
    if (ul) {
      delete ulmanager.ulEventData[uid];
      unregisterListeners();
    }
  };
  const onAttributeReady = function (handle, fa) {
    delay(`chat:fa-ready:${  handle}`, () => {
      const uid = lookupPendingUpload(handle);
      const ul = ulmanager.ulEventData[uid] || false;
      if (d) {
        logger.debug('fa:ready', handle, fa, uid, ul);
      }
      if (ul.h && String(fa).split('/').length >= ul.efa) {
        onUploadComplete(ul);
      } else if (d) {
        logger.debug('Not enough file attributes yet, holding...', ul);
      }
    });
  };
  const onAttributeError = function (faid, error, onStorageAPIError, nFAiled) {
    const uid = lookupPendingUpload(faid);
    const ul = ulmanager.ulEventData[uid] || false;
    if (d) {
      logger.debug('fa:error', faid, error, onStorageAPIError, uid, ul, nFAiled, ul.efa);
    }
    if (ul) {
      ul.efa = Math.max(0, ul.efa - nFAiled) | 0;
      if (ul.h) {
        const n = M.getNodeByHandle(ul.h);
        if (!ul.efa || n.fa && String(n.fa).split('/').length >= ul.efa) {
          onUploadComplete(ul);
        }
      }
    }
  };
  const registerLocalListeners = function () {
    self._uplError = mBroadcaster.addListener('upload:error', onUploadError);
    self._uplAbort = mBroadcaster.addListener('upload:abort', onUploadError);
    self._uplFAReady = mBroadcaster.addListener('fa:ready', onAttributeReady);
    self._uplFAError = mBroadcaster.addListener('fa:error', onAttributeError);
    self._uplDone = mBroadcaster.addListener('upload:completion', onUploadCompletion);
  };
  self._uplStart = mBroadcaster.addListener('upload:start', (data) => {
    if (d) {
      logger.info('onUploadStart', [data]);
    }
    const notify = function (room) {
      room.onUploadStart(data);
    };
    for (const k in data) {
      const chats = data[k].chat;
      if (chats && forEachChat(chats, notify) && !self._uplError) {
        registerLocalListeners();
      }
    }
  });
};
Chat.prototype.getRoomFromUrlHash = function (urlHash) {
  if (urlHash.indexOf("#") === 0) {
    urlHash = urlHash.subtr(1, urlHash.length);
  }
  if (urlHash.indexOf("chat/g/") > -1 || urlHash.indexOf("chat/c/") > -1) {
    var foundRoom = null;
    urlHash = urlHash.replace("chat/g/", "").replace("chat/c/", "");
    megaChat.chats.forEach((room) => {
      if (!foundRoom && room.chatId === urlHash) {
        foundRoom = room;
      }
    });
    return foundRoom;
  } else if (urlHash.indexOf("chat/p/") > -1) {
    const contactHash = urlHash.replace("chat/p/", "");
    if (!contactHash) {
      return;
    }
    const chatRoom = this.getPrivateRoom(contactHash);
    return chatRoom;
  } else if (urlHash.indexOf("chat/") > -1 && urlHash[13] === "#") {
    var foundRoom = null;
    const pubHandle = urlHash.replace("chat/", "").split("#")[0];
    urlHash = urlHash.replace("chat/g/", "");
    const chatIds = megaChat.chats.keys();
    for (let i = 0; i < chatIds.length; i++) {
      const cid = chatIds[i];
      const room = megaChat.chats[cid];
      if (room.publicChatHandle === pubHandle) {
        foundRoom = room;
        break;
      }
    }
    return foundRoom;
  } else {
    return null;
  }
};
Chat.prototype.updateSectionUnreadCount = SoonFc(function () {
  if (!this.is_initialized) {
    return;
  }
  let unreadCount = 0;
  const notificationsCount = {
    unreadChats: 0,
    unreadMeetings: 0,
    unreadUpcoming: 0,
    chatsCall: false,
    meetingCall: false
  };
  let havePendingCall = false;
  let haveAdHocMessage = false;
  this.chats.forEach(chatRoom => {
    if (chatRoom.isArchived() || chatRoom.state === ChatRoom.STATE.LEFT) {
      return;
    }
    const unreads = parseInt(chatRoom.messagesBuff.getUnreadCount(), 10);
    unreadCount += unreads;
    if (unreads) {
      notificationsCount[chatRoom.isMeeting ? 'unreadMeetings' : 'unreadChats'] += unreads;
      if (chatRoom.scheduledMeeting && chatRoom.scheduledMeeting.isUpcoming) {
        notificationsCount.unreadUpcoming += unreads;
      }
    }
    if (chatRoom.havePendingCall() && chatRoom.uniqueCallParts && !chatRoom.uniqueCallParts[u_handle]) {
      havePendingCall = true;
      if (chatRoom.isMeeting) {
        notificationsCount.meetingCall = true;
        if (!chatRoom.scheduledMeeting && unreads) {
          haveAdHocMessage = true;
        }
      } else {
        notificationsCount.chatsCall = true;
      }
    }
  });
  unreadCount = unreadCount > 9 ? "9+" : unreadCount;
  if (!is_chatlink && mega.ui.header) {
    if (notificationsCount.unreadChats || notificationsCount.unreadUpcoming || haveAdHocMessage) {
      mega.ui.header.chatsButton.addClass('decorated');
    } else {
      mega.ui.header.chatsButton.removeClass('decorated');
    }
    const phoneIcon = mega.ui.header.domNode.querySelector('.top-chats-call');
    if (phoneIcon) {
      phoneIcon.classList[havePendingCall ? 'remove' : 'add']('hidden');
    }
  }
  if (this._lastUnreadCount !== unreadCount) {
    this._lastUnreadCount = unreadCount;
    notify.updateNotificationIndicator();
  }
  if (!this._lastNotifications || !shallowEqual(this._lastNotifications, notificationsCount)) {
    this._lastNotifications = notificationsCount;
    megaChat.trigger('onUnreadCountUpdate', notificationsCount);
  }
}, 100);
Chat.prototype.dropAllDatabases = promisify(function (resolve, reject) {
  const chatd = this.plugins.chatdIntegration.chatd || false;
  const promises = [];
  if (chatd.chatdPersist) {
    promises.push(chatd.chatdPersist.drop());
  }
  if ('messagesQueueKvStorage' in chatd) {
    promises.push(chatd.messagesQueueKvStorage.destroy());
  }
  if (Reactions.ready) {
    promises.push(Reactions._db.destroy());
  }
  if (PersistedTypeArea.ready) {
    promises.push(PersistedTypeArea._db.destroy());
  }
  Promise.allSettled(promises).then(resolve).catch(reject);
});
Chat.prototype.destroy = function (isLogout) {
  if (!this.is_initialized) {
    return;
  }
  this.isLoggingOut = isLogout;
  for (let i = 0; i < this.mbListeners.length; i++) {
    mBroadcaster.removeListener(this.mbListeners[i]);
  }
  this.unregisterUploadListeners(true);
  this.trigger('onDestroy', [isLogout]);
  tryCatch(() => this.$$root.unmount())();
  this.chats.forEach((chatRoom, chatId) => {
    if (!isLogout) {
      chatRoom.destroy(false, true);
    }
    this.chats.remove(chatId);
  });
  this.is_initialized = false;
  if (this.plugins.chatdIntegration && this.plugins.chatdIntegration.chatd && this.plugins.chatdIntegration.chatd.shards) {
    const {
      shards
    } = this.plugins.chatdIntegration.chatd;
    Object.keys(shards).forEach(shard => shards[shard].connectionRetryManager.options.functions.forceDisconnect());
  }
  for (const pluginName in this.plugins) {
    const plugin = this.plugins[pluginName];
    if (plugin.destroy) {
      plugin.destroy();
    }
  }
  if (this.minuteClockInterval) {
    clearInterval(this.minuteClockInterval);
  }
  if (megaChat.flyoutStartHolder && mega.ui.flyout) {
    mega.ui.flyout.reinit(megaChat.flyoutStartHolder);
    delete megaChat.flyoutStartHolder;
  }
};
Chat.prototype.getContacts = function () {
  const results = [];
  M.u.forEach((k, v) => {
    if (v.c == 1 || v.c == 2) {
      results.push(v);
    }
  });
  return results;
};
Chat.prototype.userPresenceToCssClass = function (presence) {
  if (presence === UserPresence.PRESENCE.ONLINE) {
    return 'online';
  } else if (presence === UserPresence.PRESENCE.AWAY) {
    return 'away';
  } else if (presence === UserPresence.PRESENCE.DND) {
    return 'busy';
  } else if (presence === UserPresence.PRESENCE.OFFLINE) {
    return 'offline';
  } else {
    return 'black';
  }
};
Chat.prototype._renderMyStatus = function () {
  const self = this;
  if (!self.is_initialized) {
    return;
  }
  if (typeof megaChat.userPresence === 'undefined') {
    return;
  }
  const $status = $('.activity-status-block .activity-status', 'body');
  $('.top-user-status-popup .dropdown-item').removeClass("active");
  $status.removeClass('online').removeClass('away').removeClass('busy').removeClass('offline').removeClass('black');
  const actualPresence = self.plugins.presencedIntegration.getMyPresenceSetting();
  const userPresenceConRetMan = megaChat.userPresence.connectionRetryManager;
  const presence = self.plugins.presencedIntegration.getMyPresence();
  let cssClass = PresencedIntegration.presenceToCssClass(presence);
  if (userPresenceConRetMan.getConnectionState() !== ConnectionRetryManager.CONNECTION_STATE.CONNECTED) {
    cssClass = "offline";
  }
  const $activityStatus = $('.activity-text', '.js-topbar');
  if (actualPresence === UserPresence.PRESENCE.ONLINE) {
    $('.top-user-status-popup .dropdown-item[data-presence="chat"]').addClass("active");
    $activityStatus.text(l[5923]);
  } else if (actualPresence === UserPresence.PRESENCE.AWAY) {
    $('.top-user-status-popup .dropdown-item[data-presence="away"]').addClass("active");
    $activityStatus.text(l[5924]);
  } else if (actualPresence === UserPresence.PRESENCE.DND) {
    $('.top-user-status-popup .dropdown-item[data-presence="dnd"]').addClass("active");
    $activityStatus.text(l[5925]);
  } else if (actualPresence === UserPresence.PRESENCE.OFFLINE) {
    $('.top-user-status-popup .dropdown-item[data-presence="unavailable"]').addClass("active");
    $activityStatus.text(l[5926]);
  } else {
    $('.top-user-status-popup .dropdown-item[data-presence="unavailable"]').addClass("active");
    $activityStatus.text(l[5926]);
  }
  $status.addClass(cssClass);
  if (userPresenceConRetMan.getConnectionState() === ConnectionRetryManager.CONNECTION_STATE.CONNECTING) {
    $status.parent().addClass("fadeinout");
  } else {
    $status.parent().removeClass("fadeinout");
  }
};
Chat.prototype.renderMyStatus = SoonFc(Chat.prototype._renderMyStatus, 100);
Chat.prototype.openChat = function (userHandles, type, chatId, chatShard, chatdUrl, setAsActive, chatHandle, publicChatKey, ck, isMeeting, mcoFlags, organiser) {
  const self = this;
  let room = false;
  type = type || "private";
  setAsActive = setAsActive === true;
  let roomId = chatId;
  if (!publicChatKey && chatHandle && self.publicChatKeys[chatHandle]) {
    if (type !== "public") {
      console.error("this should never happen.", type);
      type = "public";
    }
    publicChatKey = self.publicChatKeys[chatHandle];
  }
  const $promise = new MegaPromise();
  if (type === "private") {
    this.initContacts(userHandles, 2);
    roomId = userHandles.length > 1 ? array.one(userHandles, u_handle) : u_handle;
    if (self.chats[roomId]) {
      $promise.resolve(roomId, self.chats[roomId]);
      return [roomId, self.chats[roomId], $promise];
    }
  } else {
    assert(roomId, 'Tried to create a group chat, without passing the chatId.');
    roomId = chatId;
  }
  if (type === "group" || type === "public") {
    if (d) {
      console.time(`openchat:${  chatId  }.${  type}`);
    }
    const newUsers = this.initContacts(userHandles);
    if (newUsers.length) {
      const chats = self.chats._data;
      if (d) {
        console.debug('openchat:%s.%s: processing %s new users...', chatId, type, newUsers.length);
      }
      for (const k in chats) {
        const chatRoom = self.chats[k];
        const participants = array.to.object(chatRoom.getParticipantsExceptMe());
        for (let j = newUsers.length; j--;) {
          const u = newUsers[j];
          if (participants[u]) {
            chatRoom.trackDataChange();
            break;
          }
        }
      }
      self.renderMyStatus();
    }
    if (d) {
      console.timeEnd(`openchat:${  chatId  }.${  type}`);
    }
    if (type === "group") {
      ChatdIntegration._ensureKeysAreLoaded([], userHandles, chatHandle).catch(dump);
    }
    ChatdIntegration._ensureContactExists(userHandles, chatHandle);
  }
  if (self.chats[roomId]) {
    room = self.chats[roomId];
    if (setAsActive) {
      room.show();
    }
    $promise.resolve(roomId, room);
    return [roomId, room, $promise];
  }
  if (setAsActive && self.currentlyOpenedChat && self.currentlyOpenedChat !== roomId) {
    self.hideChat(self.currentlyOpenedChat);
    self.currentlyOpenedChat = null;
  }
  room = new ChatRoom(self, roomId, type, userHandles, unixtime(), undefined, chatId, chatShard, chatdUrl, null, chatHandle, publicChatKey, ck, isMeeting, 0, mcoFlags, organiser);
  self.chats.set(room.roomId, room);
  if (setAsActive && !self.currentlyOpenedChat || self.currentlyOpenedChat === room.roomId) {
    room.setActive();
  }
  room.showAfterCreation = setAsActive !== false;
  return [roomId, room, new Promise((resolve, reject) => {
    this.trigger('onRoomInitialized', [room, resolve, reject]);
    room.setState(ChatRoom.STATE.JOINING);
    const q = this._queuedChatRoomEvents[chatId];
    if (q) {
      delete this._queuedChatRoomEvents[chatId];
      for (let i = 0; i < q.length; ++i) {
        const [event, data] = q[i];
        if (d) {
          this.logger.debug(`Dispatching deferred event '${event}'`, data);
        }
        room.trigger(event, data);
      }
      q.timer.abort();
    }
    this.processQueuedMcsmPackets();
  })];
};
Chat.prototype.initContacts = function (userHandles, c) {
  const newUsers = [];
  for (let i = userHandles.length; i--;) {
    const u = userHandles[i];
    const e = u in M.u;
    M.addUser(e ? {
      u
    } : {
      u,
      c
    }, e || !newUsers.push(u));
  }
  return newUsers;
};
Chat.prototype.smartOpenChat = function (...args) {
  const self = this;
  if (typeof args[0] === 'string') {
    args[0] = [u_handle, args[0]];
    if (args.length < 2) {
      args.push('private');
    }
  }
  return new Promise((resolve, reject) => {
    const waitForReadyState = function (aRoom, aShow) {
      const verify = function () {
        return aRoom.state === ChatRoom.STATE.READY;
      };
      const ready = function () {
        if (aShow) {
          aRoom.show();
        }
        resolve(aRoom);
      };
      if (verify()) {
        return ready();
      }
      const {
        roomId
      } = aRoom;
      createTimeoutPromise(verify, 300, 3e4, false, `waitForReadyState(${roomId})`).then(ready).catch(reject);
    };
    const [members, type] = args;
    if (members.length === 2 && type === 'private') {
      const chatRoom = self.chats[members.every(h => h === members[0]) ? u_handle : array.one(members, u_handle)];
      if (chatRoom) {
        if (args[5]) {
          chatRoom.show();
        }
        return waitForReadyState(chatRoom, args[5]);
      }
    }
    const result = self.openChat.apply(self, args);
    if (result instanceof MegaPromise) {
      result.then(reject).catch(reject);
    } else if (!Array.isArray(result)) {
      reject(EINTERNAL);
    } else {
      const room = result[1];
      const roomId = result[0];
      const promise = result[2];
      if (!(promise instanceof Promise)) {
        self.logger.error('Unexpected openChat() response...');
        return reject(EINTERNAL);
      }
      self.logger.debug('Waiting for chat "%s" to be ready...', roomId, [room]);
      promise.then(aRoom => {
        const aRoomId = aRoom && aRoom.roomId;
        if (aRoomId !== roomId || room && room !== aRoom || !(aRoom instanceof ChatRoom)) {
          self.logger.error('Unexpected openChat() procedure...', aRoomId, [aRoom]);
          return reject(EINTERNAL);
        }
        waitForReadyState(aRoom);
      }).catch(ex => {
        if (ex === EACCESS) {
          room.destroy();
        }
        reject(ex);
      });
    }
  });
};
Chat.prototype.hideAllChats = function () {
  const self = this;
  self.chats.forEach(chatRoom => {
    if (chatRoom.isCurrentlyActive) {
      chatRoom.hide();
    }
  });
};
Chat.prototype.retrieveSharedFilesHistory = async function (len = 47, chatRoom = null) {
  chatRoom = len instanceof ChatRoom ? len : chatRoom || this.getCurrentRoom();
  return chatRoom.messagesBuff.retrieveSharedFilesHistory(len);
};
Chat.prototype.getCurrentRoom = function () {
  return this.chats[this.currentlyOpenedChat];
};
Chat.prototype.getCurrentMeeting = function () {
  const chatRoom = this.getCurrentRoom();
  return chatRoom && chatRoom.scheduledMeeting || null;
};
Chat.prototype.getCurrentRoomJid = function () {
  return this.currentlyOpenedChat;
};
Chat.prototype.hideChat = function (roomJid) {
  const self = this;
  const room = self.chats[roomJid];
  if (room) {
    room.hide();
  } else {
    self.logger.warn("Room not found: ", roomJid);
  }
};
Chat.prototype.sendMessage = function (roomJid, val) {
  const fail = ex => {
    this.logger.error(`sendMessage(${roomJid}) failed.`, ex);
  };
  if (!this.chats[roomJid]) {
    this.logger.warn("Queueing message for room: ", roomJid, val);
    const timeout = this.options.delaySendMessageIfRoomNotAvailableTimeout;
    return createTimeoutPromise(() => !!this.chats[roomJid], 500, timeout).then(() => {
      return this.chats[roomJid].sendMessage(val);
    }).catch(fail);
  }
  return this.chats[roomJid].sendMessage(val).catch(fail);
};
Chat.prototype.processNewUser = function (u, isNewChat) {
  const self = this;
  if (self.plugins.presencedIntegration) {
    const user = M.u[u] || false;
    if (user.c === 1) {
      self.plugins.presencedIntegration.addContact(u, isNewChat);
    }
  }
  self.chats.forEach((chatRoom) => {
    if (chatRoom.getParticipantsExceptMe().indexOf(u) > -1) {
      chatRoom.trackDataChange();
    }
  });
  self.renderMyStatus();
};
Chat.prototype.processRemovedUser = function (u) {
  const self = this;
  if (self.plugins.presencedIntegration) {
    self.plugins.presencedIntegration.removeContact(u);
  }
  self.chats.forEach((chatRoom) => {
    if (chatRoom.getParticipantsExceptMe().indexOf(u) > -1) {
      chatRoom.trackDataChange();
    }
  });
  self.renderMyStatus();
};
Chat.prototype.refreshConversations = function () {
  const self = this;
  if (!u_type && !self.$container && !megaChatIsReady) {
    $('.fm-chat-block').hide();
    return false;
  }
  $('.section.conversations .fm-chat-is-loading').addClass('hidden');
  if (self.$container.parent('.section.conversations .fm-right-files-block').length == 0) {
    $('.section.conversations .fm-right-files-block').append(self.$container);
  }
  self.$leftPane = self.$leftPane || $('.conversationsApp .fm-left-panel');
  if (is_chatlink || megaChat._joinDialogIsShown) {
    self.$leftPane.addClass('hidden');
  } else {
    self.$leftPane.removeClass('hidden');
  }
};
Chat.prototype.navigate = function megaChatNavigate(location, event, isLandingPage) {
  return new Promise((resolve, reject) => {
    this.routing.route(resolve, reject, location, event, isLandingPage);
  });
};
if (is_mobile) {
  Chat.prototype.navigate = function (location, event, isLandingPage) {
    if (d) {
      this.logger.warn('mobile-nop navigate(%s)', location, event, isLandingPage);
    }
    if (is_chatlink) {
      mobile.chatlink.show(is_chatlink.ph, is_chatlink.key);
    } else {
      loadSubPage('fm', event);
    }
    return Promise.resolve();
  };
}
Chat.prototype.renderListing = async function megaChatRenderListing(location, isInitial) {
  if (!isInitial && !M.chat) {
    console.debug('renderListing: Not in chat.');
    throw EACCESS;
  }
  M.hideEmptyGrids();
  this.refreshConversations();
  this.hideAllChats();
  if (!is_chatlink && mega.ui.flyout && (mega.ui.flyout.name.startsWith('contact') || mega.ui.flyout.name === 'chat')) {
    mega.ui.flyout.hide();
  }
  $('.files-grid-view').addClass('hidden');
  $('.fm-blocks-view').addClass('hidden');
  $('.fm-chat-block').addClass('hidden');
  $('.fm-right-files-block').addClass('hidden');
  $('.fm-right-files-block.in-chat').removeClass('hidden');
  $('.nw-conversations-item').removeClass('selected');
  $('.fm-empty-conversations').removeClass('hidden');
  M.onSectionUIOpen('conversations');
  let room;
  if (!location && this.chats.length) {
    const valid = room => room && room._leaving !== true && !room.isNote && room.isDisplayable() && room;
    room = valid(this.chats[this.lastOpenedChat]);
    if (!room) {
      let idx = 0;
      const rooms = Object.values(this.chats).filter(r => this.currentlyOpenedView === null || r.isMeeting === !!this.currentlyOpenedView).sort(M.sortObjFn('lastActivity', -1));
      do {
        room = valid(rooms[idx]);
      } while (!room && ++idx < rooms.length);
    }
    if (room) {
      location = room.getRoomUrl();
    }
  }
  if (location) {
    $('.fm-empty-conversations').addClass('hidden');
    return this.navigate(location, undefined, isInitial).catch(ex => {
      if (d) {
        this.logger.warn('Failed to navigate to %s...', location, room, ex);
      }
      if (!room) {
        return this.renderListing(null);
      }
      onIdle(() => {
        room.destroy();
      });
      throw ex;
    });
  }
  return ENOENT;
};
Chat.prototype.setAttachments = function (roomId) {
  'use strict';

  if (M.chat) {
    if (d) {
      console.assert(this.chats[roomId] && this.chats[roomId].isCurrentlyActive, 'check this...');
    }
    M.v = Object.values(M.chc[roomId] || {});
    if (M.v.length) {
      let _this$chats$roomId;
      const sv = (_this$chats$roomId = this.chats[roomId]) == null || (_this$chats$roomId = _this$chats$roomId.messagesBuff) == null || (_this$chats$roomId = _this$chats$roomId.sharedFiles) == null ? void 0 : _this$chats$roomId._sortedVals;
      if (sv && sv.length === M.v.length) {
        M.v.sort((a, b) => sv.indexOf(a.m) - sv.indexOf(b.m));
      } else {
        if (d) {
          this.logger.info('falling back to order-value sorting.', sv);
        }
        M.v.sort(M.sortObjFn('co'));
      }
      for (let i = M.v.length; i--;) {
        const n = M.v[i];
        if (!n.revoked && !n.seen) {
          n.seen = -1;
          if (String(n.fa).indexOf(':1*') > 0) {
            this._enqueueImageLoad(n);
          }
        }
      }
      if ($.triggerSlideShow) {
        delay('chat:refresh-slideshow-on-single-entry', () => {
          const {
            slideshowid: id
          } = window;
          if (id && $.triggerSlideShow === id) {
            slideshow(id);
          }
          delete $.triggerSlideShow;
        });
      }
    }
  } else if (d) {
    console.warn('Not in chat...');
  }
};
Chat.prototype._enqueueMessageUpdate = function (message) {
  this._queuedMessageUpdates.push(message);
  delay('chat:enqueue-message-updates', () => {
    const queue = this._queuedMessageUpdates;
    this._queuedMessageUpdates = [];
    for (let i = queue.length; i--;) {
      queue[i].trackDataChange();
    }
  }, 400);
};
Chat.prototype._enqueueImageLoad = function (n) {
  'use strict';
  let cc = previews[n.h] || previews[n.hash];
  if (cc) {
    if (cc.poster) {
      n.src = cc.poster;
    } else {
      if (cc.full && n.mime !== 'image/png' && n.mime !== 'image/webp') {
        cc = cc.prev || false;
      }
      if (String(cc.type).startsWith('image/')) {
        n.src = cc.src;
      }
    }
  }
  let cached = n.src;
  if (String(n.fa).indexOf(':1*') > 0) {
    let load = false;
    let dedup = true;
    if (this._imageAttributeCache[n.fa]) {
      this._imageAttributeCache[n.fa].push(n.ch);
    } else {
      this._imageAttributeCache[n.fa] = [n.ch];
      load = !cached;
    }
    if (this._imageLoadCache[n.fa]) {
      this._imageLoadCache[n.fa].push(n.ch);
    } else {
      this._imageLoadCache[n.fa] = [n.ch];
      if (load) {
        this._imagesToBeLoaded[n.fa] = n;
        dedup = false;
      }
    }
    if (dedup) {
      cached = true;
    } else {
      delay('chat:enqueue-image-load', this._doLoadImages.bind(this), 350);
    }
  }
  if (cached) {
    this._doneLoadingImage(n.fa);
  }
};
Chat.prototype._doLoadImages = function () {
  "use strict";

  const self = this;
  const originals = Object.create(null);
  let imagesToBeLoaded = self._imagesToBeLoaded;
  self._imagesToBeLoaded = Object.create(null);
  const chatImageParser = function (h, data) {
    const n = M.chd[(self._imageLoadCache[h] || [])[0]] || false;
    if (n && data !== 0xDEAD) {
      n.src = mObjectURL([data.buffer || data], 'image/jpeg');
      n.srcBuffer = data;
    } else if (d) {
      console.warn('Failed to load image for %s', h, n);
    }
    self._doneLoadingImage(h);
  };
  for (const k in imagesToBeLoaded) {
    const node = imagesToBeLoaded[k];
    const mime = filemime(node);
    if (node.s < LOAD_ORIGINALS[mime]) {
      originals[node.fa] = node;
      delete imagesToBeLoaded[k];
    }
  }
  const onSuccess = function (ctx, origNodeHandle, data) {
    chatImageParser(origNodeHandle, data);
  };
  const onError = function (origNodeHandle) {
    chatImageParser(origNodeHandle, 0xDEAD);
  };
  const loadOriginal = function (n) {
    const origFallback = ex => {
      const type = String(n.fa).indexOf(':1*') > 0 ? 1 : 0;
      if (d) {
        console.debug('Failed to load original image on chat.', n.h, n, ex);
      }
      imagesToBeLoaded[n.fa] = originals[n.fa];
      delete originals[n.fa];
      delay(`ChatRoom[${  self.roomId  }]:origFallback${  type}`, () => {
        api_getfileattr(imagesToBeLoaded, type, onSuccess, onError);
      });
    };
    M.gfsfetch(n.h, 0, -1).then((data) => {
      const handler = is_image(n);
      if (typeof handler === 'function') {
        handler(data, buffer => {
          if (buffer) {
            chatImageParser(n.fa, buffer);
          } else {
            origFallback(EFAILED);
          }
        });
      } else {
        chatImageParser(n.fa, data);
      }
    }).catch(origFallback);
  };
  if ($.len(originals)) {
    Object.values(originals).map(loadOriginal);
  }
  api_getfileattr(imagesToBeLoaded, 1, onSuccess, onError);
  [imagesToBeLoaded, originals].forEach((obj) => {
    Object.keys(obj).forEach((handle) => {
      self._startedLoadingImage(handle);
    });
  });
  imagesToBeLoaded = Object.create(null);
};
Chat.prototype._getImageNodes = function (h, src) {
  let nodes = this._imageLoadCache[h] || [];
  let handles = [].concat(nodes);
  for (let i = nodes.length; i--;) {
    const n = M.chd[nodes[i]] || false;
    if (this._imageAttributeCache[n.fa]) {
      handles = handles.concat(this._imageAttributeCache[n.fa]);
    }
  }
  handles = array.unique(handles);
  nodes = handles.map((ch) => {
    const n = M.chd[ch] || false;
    if (src && n.src) {
      Object.assign(src, n);
    }
    return n;
  });
  return nodes;
};
Chat.prototype._startedLoadingImage = function (h) {
  "use strict";

  const nodes = this._getImageNodes(h);
  for (let i = nodes.length; i--;) {
    const n = nodes[i];
    if (!n.src && n.seen !== 2) {
      let imgNode = document.getElementById(n.ch);
      if (imgNode && (imgNode = imgNode.querySelector('img'))) {
        imgNode.parentNode.parentNode.classList.add('thumb-loading');
      }
    }
  }
};
Chat.prototype._doneLoadingImage = function (h) {
  const self = this;
  const setSource = function (n, img, src) {
    const message = n.mo;
    img.onload = function () {
      img.onload = null;
      n.srcWidth = this.naturalWidth;
      n.srcHeight = this.naturalHeight;
      if (message) {
        self._enqueueMessageUpdate(message);
      }
    };
    img.setAttribute('src', src);
  };
  const root = {};
  const nodes = this._getImageNodes(h, root);
  const {src} = root;
  for (let i = nodes.length; i--;) {
    const n = nodes[i];
    let imgNode = document.getElementById(n.ch);
    if (imgNode && (imgNode = imgNode.querySelector('img'))) {
      const parent = imgNode.parentNode;
      const container = parent.parentNode;
      if (src) {
        container.classList.add('thumb');
        parent.classList.remove('no-thumb');
      } else {
        container.classList.add('thumb-failed');
      }
      n.seen = 2;
      container.classList.remove('thumb-loading');
      setSource(n, imgNode, src || window.noThumbURI || '');
    }
    if (src) {
      n.src = src;
      if (root.srcBuffer && root.srcBuffer.byteLength) {
        n.srcBuffer = root.srcBuffer;
      }
      if (n.srcBuffer && !previews[n.h] && is_image3(n)) {
        preqs[n.h] = 1;
        previewimg(n.h, n.srcBuffer, 'image/jpeg');
        previews[n.h].fromChat = Date.now();
      }
    }
    delete n.mo;
  }
  if (src) {
    mBroadcaster.sendMessage('chat_image_preview');
  }
};
Chat.prototype.onChatsHistoryReady = promisify(function (resolve, reject, timeout) {
  if (this.allChatsHadInitialLoadedHistory()) {
    return resolve();
  }
  let timer = null;
  const {chatd} = this.plugins.chatdIntegration;
  const eventName = `onMessagesHistoryDone.ochr${  makeid(16)}`;
  const ready = () => {
    queueMicrotask(resolve);
    chatd.off(eventName);
    if (timer) {
      timer.abort();
      timer = null;
    }
  };
  chatd.on(eventName, () => {
    if (this.allChatsHadInitialLoadedHistory()) {
      ready();
    }
  });
  if (timeout > 0) {
    (timer = tSleep(timeout / 1e3)).then(ready);
  }
});
Chat.prototype.allChatsHadLoadedHistory = function () {
  const chatIds = this.chats.keys();
  for (let i = chatIds.length; i--;) {
    const room = this.chats[chatIds[i]];
    if (room.isLoading()) {
      return false;
    }
  }
  return true;
};
Chat.prototype.allChatsHadInitialLoadedHistory = function () {
  const self = this;
  const chatIds = self.chats.keys();
  for (let i = chatIds.length; i--;) {
    const room = self.chats[chatIds[i]];
    if (room.chatId && room.initialMessageHistLoaded === false) {
      return false;
    }
  }
  return true;
};
Chat.prototype.getPrivateRoom = function (h) {
  'use strict';

  return this.chats[h] || false;
};
Chat.prototype.createAndShowPrivateRoom = promisify(function (resolve, reject, h) {
  M.openFolder(`chat/p/${  h}`).then(() => {
    const room = this.getPrivateRoom(h);
    assert(room, 'room not found..');
    resolve(room);
  }).catch(reject);
});
Chat.prototype.createAndShowGroupRoomFor = function (contactHashes, topic = '', opts = {}) {
  this.trigger('onNewGroupChatRequest', [contactHashes, {
    topic,
    ...opts
  }]);
};
Chat.prototype.createAndStartMeeting = function (topic, audio, video) {
  megaChat.createAndShowGroupRoomFor([], topic, {
    keyRotation: false,
    createChatLink: true,
    isMeeting: true
  });
  megaChat.rebind('onRoomInitialized.meetingCreate', (e, room) => {
    room.rebind('onNewMeetingReady.meetingCreate', () => {
      room.startCall(audio, video);
    });
  });
};
Chat.prototype._destroyAllChatsFromChatd = function () {
  const self = this;
  asyncApiReq({
    'a': 'mcf',
    'v': Chatd.VERSION
  }).then(r => {
    r.c.forEach((chatRoomMeta) => {
      if (chatRoomMeta.g === 1) {
        chatRoomMeta.u.forEach((u) => {
          if (u.u !== u_handle) {
            api_req({
              a: 'mcr',
              id: chatRoomMeta.id,
              u: u.u,
              v: Chatd.VERSION
            });
          }
        });
        api_req({
          a: 'mcr',
          id: chatRoomMeta.id,
          u: u_handle,
          v: Chatd.VERSION
        });
      }
    });
  });
};
Chat.prototype._leaveAllGroupChats = function () {
  asyncApiReq({
    'a': 'mcf',
    'v': Chatd.VERSION
  }).then(r => {
    r.c.forEach((chatRoomMeta) => {
      if (chatRoomMeta.g === 1) {
        asyncApiReq({
          "a": "mcr",
          "id": chatRoomMeta.id,
          "v": Chatd.VERSION
        });
      }
    });
  });
};
Chat.prototype.getEmojiDataSet = async function (name) {
  assert(name === "categories" || name === "emojis", "Invalid emoji dataset name passed.");
  if (!this._emojiDataLoading) {
    this._emojiDataLoading = Object.create(null);
  }
  if (!this._emojiData) {
    this._emojiData = {
      'emojisUtf': Object.create(null),
      'emojisSlug': Object.create(null)
    };
  }
  if (this._emojiData[name]) {
    return this._emojiData[name];
  }
  if (this._emojiDataLoading[name]) {
    return this._emojiDataLoading[name];
  }
  if (name === "categories") {
    this._emojiData[name] = ["people", "nature", "food", "activity", "travel", "objects", "symbols", "flags"];
    return this._emojiData[name];
  }
  const {
    promise
  } = mega;
  this._emojiDataLoading[name] = promise;
  M.xhr({
    type: 'json',
    url: `${staticpath}js/chat/emojidata/${name}_v${EMOJI_DATASET_VERSION}.json`
  }).then((ev, data) => {
    if (!data) {
      promise.reject(EFAILED);
      return;
    }
    this._emojiData[name] = data;
    delete this._emojiDataLoading[name];
    if (name === "emojis") {
      this._mapEmojisToAliases();
    }
    promise.resolve(data);
  }).catch((ex, error) => {
    if (d) {
      this.logger.warn('Failed to load emoji data "%s": %s', name, error, [ex]);
    }
    delete this._emojiDataLoading[name];
    promise.reject(error || ex);
  });
  return promise;
};
Chat.prototype._mapEmojisToAliases = function () {
  const {
    emojis
  } = this._emojiData;
  if (emojis) {
    this._emojiData.emojisUtf = Object.create(null);
    this._emojiData.emojisSlug = Object.create(null);
    for (let i = emojis.length; i--;) {
      const emoji = emojis[i];
      this._emojiData.emojisUtf[emoji.u] = emoji;
      this._emojiData.emojisSlug[emoji.n] = emoji;
    }
  }
};
Chat.prototype.isValidEmojiSlug = function (slug) {
  const self = this;
  const emojiData = self._emojiData.emojis;
  if (!emojiData) {
    self.getEmojiDataSet('emojis');
    return false;
  }
  for (let i = 0; i < emojiData.length; i++) {
    if (emojiData[i].n === slug) {
      return true;
    }
  }
};
Chat.prototype.getPresence = function (user_handle) {
  if (user_handle && this.plugins.presencedIntegration) {
    return this.plugins.presencedIntegration.getPresence(user_handle);
  }
};
Chat.prototype.getPresenceAsCssClass = function (user_handle) {
  const presence = this.getPresence(user_handle);
  return this.presenceStringToCssClass(presence);
};
Chat.prototype.presenceStringToCssClass = function (presence) {
  if (presence === UserPresence.PRESENCE.ONLINE) {
    return 'online';
  } else if (presence === UserPresence.PRESENCE.AWAY) {
    return 'away';
  } else if (presence === UserPresence.PRESENCE.DND) {
    return 'busy';
  } else if (!presence || presence === UserPresence.PRESENCE.OFFLINE) {
    return 'offline';
  } else {
    return 'black';
  }
};
Chat.prototype.generateTempMessageId = function (roomId, messageAndMeta) {
  let messageIdHash = u_handle + roomId;
  if (messageAndMeta) {
    messageIdHash += messageAndMeta;
  }
  return `m${  fastHashFunction(messageIdHash)  }_${  unixtime()}`;
};
Chat.prototype.getChatById = function (chatdId) {
  const self = this;
  if (self.chats[chatdId]) {
    return self.chats[chatdId];
  } else if (self.chatIdToRoomId && self.chatIdToRoomId[chatdId] && self.chats[self.chatIdToRoomId[chatdId]]) {
    return self.chats[self.chatIdToRoomId[chatdId]];
  }
  if (this.chats[this.handleToId[chatdId]]) {
    return this.chats[this.handleToId[chatdId]];
  }
  let found = false;
  self.chats.forEach((chatRoom) => {
    if (!found && chatRoom.chatId === chatdId) {
      found = chatRoom;
      return false;
    }
  });
  return found;
};
Chat.prototype.getNoteChat = function () {
  return Object.values(this.chats).find(c => c.isNote);
};
Chat.prototype.getMessageByMessageId = async function (chatId, messageId) {
  const chatRoom = this.getChatById(chatId);
  const msg = chatRoom.messagesBuff.getMessageById(messageId);
  if (msg) {
    return msg;
  }
  const {
    chatdPersist
  } = this.plugins.chatdIntegration.chatd;
  if (chatdPersist) {
    const [msg] = await chatdPersist.getMessageByMessageId(chatId, messageId).catch(dump) || [];
    if (msg) {
      return Message.fromPersistableObject(chatRoom, msg);
    }
  }
  if (d) {
    this.logger.debug('getMessageByMessageId: Cannot find %s on %s', messageId, chatId);
  }
  return Promise.reject(ENOENT);
};
Chat.prototype.haveAnyActiveCall = function () {
  const self = this;
  const chatIds = self.chats.keys();
  for (let i = 0; i < chatIds.length; i++) {
    if (self.chats[chatIds[i]].haveActiveCall()) {
      return true;
    }
  }
  return false;
};
Chat.prototype.haveAnyOnHoldCall = function () {
  const self = this;
  const chatIds = self.chats.keys();
  for (let i = 0; i < chatIds.length; i++) {
    if (self.chats[chatIds[i]].haveActiveOnHoldCall()) {
      return true;
    }
  }
  return false;
};
Chat.prototype.openChatAndSendFilesDialog = function (user_handle) {
  'use strict';

  this.smartOpenChat(user_handle).then((room) => {
    if (room.$rConversationPanel && room.$rConversationPanel.isMounted()) {
      room.trigger('openSendFilesDialog');
    } else {
      room.one('onComponentDidMount.sendFilesDialog', () => {
        onIdle(() => room.trigger('openSendFilesDialog'));
      });
    }
    room.setActive();
  }).catch(this.logger.error.bind(this.logger));
};
Chat.prototype.openChatAndAttachNodes = async function (targets, nodes, silent) {
  const promises = [];
  if (d) {
    console.group('Attaching nodes to chat room(s)...', targets, nodes);
  }
  const attachNodes = roomId => this.smartOpenChat(roomId).then(room => {
    return room.attachNodes(nodes).then(res => {
      if (res !== EBLOCKED && res !== ENOENT) {
        return room;
      }
    });
  }).catch(ex => {
    if (d) {
      this.logger.warn('Cannot openChat for %s and hence nor attach nodes to it.', roomId, ex);
    }
    throw ex;
  });
  if (!Array.isArray(targets)) {
    targets = [targets];
  }
  for (let i = targets.length; i--;) {
    promises.push(attachNodes(targets[i]));
  }
  const result = (await Promise.allSettled(promises)).map(e => e.value).filter(Boolean);
  let folderCount = 0;
  let fileCount = 0;
  for (let i = nodes.length; i--;) {
    const {
      t
    } = M.getNodeByHandle(nodes[i]) || {};
    if (t === 1) {
      folderCount++;
    } else {
      fileCount++;
    }
  }
  let message = mega.icu.format(l.toast_send_chat_items, nodes.length);
  if (fileCount === 0 && folderCount) {
    message = mega.icu.format(l.toast_send_chat_folders, folderCount);
  } else if (folderCount === 0 && fileCount) {
    message = mega.icu.format(l.toast_send_chat_files, fileCount);
  }
  for (let i = result.length; i--;) {
    if (result[i] instanceof ChatRoom) {
      const room = result[i];
      mega.ui.toast.show(message);
      if (!silent) {
        await M.openFolder(room.getRoomUrl().replace('fm/', '')).catch(dump);
      }
      break;
    }
  }
  if (d) {
    console.groupEnd();
  }
  return result;
};
Chat.prototype.toggleUIFlag = function (name) {
  this.chatUIFlags.set(name, this.chatUIFlags[name] ? 0 : 1);
};
Chat.prototype.onSnActionPacketReceived = function () {
  if (this._queuedMccPackets.length > 0) {
    const aps = this._queuedMccPackets;
    this._queuedMccPackets = [];
    for (let i = 0; i < aps.length; i++) {
      mBroadcaster.sendMessage('onChatdChatUpdatedActionPacket', aps[i]);
    }
  }
  this.processQueuedMcsmPackets();
};
Chat.prototype.processQueuedMcsmPackets = function () {
  const aps = Object.values(this._queuedMcsmPackets);
  if (aps.length) {
    for (let i = 0; i < aps.length; i++) {
      const ap = aps[i];
      const {
        type,
        data
      } = ap;
      const {
        meetingsManager
      } = this.plugins;
      if (type === 'mcsmp') {
        const chatRoom = this.getChatById(data.cid);
        if (chatRoom) {
          const scheduledMeeting = meetingsManager.attachMeeting(data, true);
          delete this._queuedMcsmPackets[scheduledMeeting.id];
          return scheduledMeeting.iAmOwner ? null : notify.notifyFromActionPacket({
            ...data,
            a: type
          });
        }
      }
      if (type === 'mcsmr') {
        meetingsManager.detachMeeting(data);
        delete this._queuedMcsmPackets[data.id];
      }
    }
  }
};
Chat.prototype.getFrequentContacts = function () {
  if (Chat._frequentsCache) {
    return Chat._frequentsCache;
  }
  const {chats} = this;
  const recentContacts = {};
  const promises = [];
  const finishedLoadingChats = {};
  const loadingMoreChats = {};
  const _calculateLastTsFor = function (r, maxMessages) {
    const mb = r.messagesBuff;
    const len = mb.messages.length;
    const msgs = mb.messages.slice(Math.max(0, len - maxMessages), len);
    for (let i = 0; i < msgs.length; i++) {
      const msg = msgs[i];
      let contactHandle = msg.userId === mega.BID && msg.meta ? msg.meta.userId : msg.userId;
      if (r.type === "private" && contactHandle === u_handle) {
        contactHandle = contactHandle || r.getParticipantsExceptMe()[0];
      }
      if (contactHandle !== mega.BID && contactHandle !== strongvelope.COMMANDER && contactHandle in M.u && M.u[contactHandle].c === 1 && contactHandle !== u_handle) {
        if (!recentContacts[contactHandle] || recentContacts[contactHandle].ts < msg.delay) {
          recentContacts[contactHandle] = {
            'userId': contactHandle,
            'ts': msg.delay
          };
        }
      }
    }
  };
  const _histDecryptedCb = function () {
    const mb = this.messagesBuff;
    if (!loadingMoreChats[this.chatId] && mb.messages.length < 32 && mb.haveMoreHistory()) {
      loadingMoreChats[this.chatId] = true;
      mb.retrieveChatHistory(false);
    } else {
      this.unbind(CHAT_ONHISTDECR_RECNT);
      _calculateLastTsFor(this, 32);
      delete loadingMoreChats[this.chatId];
      finishedLoadingChats[this.chatId] = true;
      mb.detachMessages();
    }
  };
  const _checkFinished = function (chatId) {
    return function () {
      return finishedLoadingChats[chatId] === true;
    };
  };
  chats.forEach(chatRoom => {
    const name = `getFrequentContacts(${chatRoom.roomId})`;
    if (chatRoom.isLoading()) {
      finishedLoadingChats[chatRoom.chatId] = false;
      chatRoom.rebind(CHAT_ONHISTDECR_RECNT, _histDecryptedCb);
      promises.push(createTimeoutPromise(_checkFinished(chatRoom.chatId), 300, 10000, false, name));
    } else if (chatRoom.messagesBuff.messages.length < 32 && chatRoom.messagesBuff.haveMoreHistory()) {
      loadingMoreChats[chatRoom.chatId] = true;
      finishedLoadingChats[chatRoom.chatId] = false;
      chatRoom.messagesBuff.retrieveChatHistory(false);
      chatRoom.rebind(CHAT_ONHISTDECR_RECNT, _histDecryptedCb);
      promises.push(createTimeoutPromise(_checkFinished(chatRoom.chatId), 300, 15000, false, name));
    } else {
      _calculateLastTsFor(chatRoom, 32);
    }
  });
  Chat._frequentsCache = new Promise((resolve, reject) => {
    Promise.allSettled(promises).then(() => {
      const result = Object.values(recentContacts).sort((a, b) => a.ts < b.ts ? 1 : b.ts < a.ts ? -1 : 0).reverse();
      tSleep(300).then(() => {
        delete Chat._frequentsCache;
      });
      return result;
    }).then(resolve).catch(reject);
  });
  return Chat._frequentsCache;
};
Chat.prototype.lastRoomContacts = async function (chatRoom) {
  let timeout;
  let loaded = false;
  let loadMore = false;
  const {
    promise
  } = mega;
  const proc = () => {
    if (timeout) {
      timeout.abort();
    }
    const {
      messages
    } = chatRoom.messagesBuff;
    const arr = messages.slice(Math.max(0, messages.length - 32));
    let first = '';
    let second = '';
    for (let i = arr.length; i--;) {
      const message = arr[i];
      const h = message.userId === mega.BID && message.meta ? message.meta.userId : message.userId;
      if (h !== mega.BID && h !== strongvelope.COMMANDER && h !== u_handle && h in M.u && M.u[h].c === 1) {
        if (first && first !== h) {
          second = h;
          break;
        }
        first = h;
      }
    }
    if (second) {
      promise.resolve([first, second]);
    } else if (first) {
      promise.resolve([first]);
    } else {
      promise.resolve([]);
    }
    chatRoom.messagesBuff.detachMessages();
  };
  const next = () => {
    if (!loadMore && chatRoom.messagesBuff.messages.length < 32 && chatRoom.messagesBuff.haveMoreHistory()) {
      if (timeout) {
        timeout.restart();
      }
      loadMore = true;
      chatRoom.messagesBuff.retrieveChatHistory(false);
    } else {
      chatRoom.off('onHistoryDecrypted.lrc');
      proc();
    }
  };
  if (chatRoom.isLoading()) {
    loaded = false;
    chatRoom.rebind('onHistoryDecrypted.lrc', next);
    timeout = tSleep(10);
  } else if (chatRoom.messagesBuff.messages.length < 32 && chatRoom.messagesBuff.haveMoreHistory()) {
    loaded = false;
    loadMore = true;
    chatRoom.rebind('onHistoryDecrypted.lrc', next);
    chatRoom.messagesBuff.retrieveChatHistory(false);
    timeout = tSleep(10);
  } else {
    proc();
  }
  if (timeout) {
    timeout.then(() => {
      if (!loaded) {
        chatRoom.off('onHistoryDecrypted.lrc');
        promise.resolve([]);
      }
    });
  }
  return promise;
};
Chat.prototype.eventuallyAddDldTicketToReq = function (req) {
  if (!u_handle) {
    return;
  }
  const currentRoom = this.getCurrentRoom();
  if (currentRoom && currentRoom.type === "public" && currentRoom.publicChatHandle && (is_chatlink || currentRoom.membersSetFromApi && !currentRoom.membersSetFromApi.members[u_handle])) {
    req.cauth = currentRoom.publicChatHandle;
  }
};
Chat.prototype.removeMessagesByRetentionTime = function (chatId) {
  if (this.chats.length > 0) {
    if (chatId) {
      if (this.logger && d > 3) {
        this.logger.debug(`Chat.prototype.removeMessagesByRetentionTime chatId=${chatId}`);
      }
      const room = this.getChatById(chatId);
      if (room) {
        room.removeMessagesByRetentionTime();
      }
      return;
    }
    const chatIds = this.chats.keys();
    for (let i = 0; i < chatIds.length; i++) {
      const chatRoom = this.chats[chatIds[i]];
      if (chatRoom.retentionTime > 0 && chatRoom.state === ChatRoom.STATE.READY) {
        if (this.logger && d > 3) {
          this.logger.debug(`Chat.prototype.removeMessagesByRetentionTime roomId=${chatRoom.roomId}`);
        }
        chatRoom.removeMessagesByRetentionTime();
      }
    }
  }
};
Chat.prototype.loginOrRegisterBeforeJoining = function (chatHandle, forceRegister, forceLogin, notJoinReq, onLoginSuccessCb) {
  if (!chatHandle && page !== 'securechat' && (page === 'chat' || page.indexOf('chat') > -1)) {
    chatHandle = getSitePath().split("chat/")[1].split("#")[0];
  }
  assert(chatHandle, 'missing chat handle when calling megaChat.loginOrRegisterBeforeJoining');
  const chatRoom = megaChat.getCurrentRoom();
  const chatKey = `#${  window.location.hash.split("#").pop()}`;
  const finish = function (stay) {
    if (!notJoinReq) {
      localStorage.autoJoinOnLoginChat = JSON.stringify([chatHandle, unixtime(), chatKey, chatRoom.chatId]);
    }
    if (!stay) {
      window.location.reload();
    }
    return stay;
  };
  const doShowLoginDialog = function () {
    mega.ui.showLoginRequiredDialog({
      minUserType: 3,
      skipInitialDialog: 1,
      onLoginSuccessCb
    }).done(() => {
      if (page !== 'login' && onLoginSuccessCb) {
        onLoginSuccessCb();
      }
    });
  };
  const doShowRegisterDialog = function () {
    mega.ui.showRegisterDialog({
      title: l[5840],
      onCreatingAccount () {},
      onLoginAttemptFailed () {
        msgDialog(`warninga:${  l[171]}`, l[1578], l[218], null, (e) => {
          if (e) {
            $('.pro-register-dialog').addClass('hidden');
            if (signupPromptDialog) {
              signupPromptDialog.hide();
            }
            doShowLoginDialog();
          }
        });
      },
      onAccountCreated (gotLoggedIn, registerData) {
        if (finish(!gotLoggedIn)) {
          security.register.cacheRegistrationData(registerData);
          mega.ui.sendSignupLinkDialog(registerData);
          megaChat.destroy();
        }
      },
      onLoginSuccessCb
    });
  };
  if (u_handle && u_handle !== "AAAAAAAAAAA") {
    return finish();
  }
  if (forceRegister) {
    return doShowRegisterDialog();
  } else if (forceLogin) {
    return doShowLoginDialog();
  }
  if (u_wasloggedin()) {
    doShowLoginDialog();
  } else {
    doShowRegisterDialog();
  }
};
Chat.prototype.highlight = (text, matches, dontEscape) => {
  if (text && matches) {
    text = dontEscape ? text : escapeHTML(text);
    const tags = [];
    text = text.replace(/<[^>]+>/g, match => `@@!${  tags.push(match) - 1  }!@@`).split(' ');
    const done = [];
    for (let i = 0; i < matches.length; i++) {
      const match = matches[i].str;
      if (!done.includes(match)) {
        done.push(match);
        for (let j = 0; j < text.length; j++) {
          const word = text[j];
          const wordNormalized = ChatSearch._normalize_str(word);
          const matchPos = wordNormalized.indexOf(match);
          if (matchPos > -1) {
            const split = wordNormalized.split(match);
            text[j] = wordNormalized === word ? split.join(`[$]${match}[/$]`) : megaChat._highlightDiacritics(word, matchPos, split, match);
          }
        }
      }
    }
    text = text.join(' ').replace(/\@\@\!\d+\!\@\@/g, match => {
      return tags[parseInt(match.replace("@@!", "").replace("!@@"), 10)];
    });
    return text.replace(/\[\$]/g, '<strong>').replace(/\[\/\$]/g, '</strong>');
  }
  return null;
};
Chat.prototype._highlightDiacritics = function (word, matchPos, split, match) {
  const parts = [];
  const origMatch = word.substring(matchPos, matchPos + match.length);
  let pos = 0;
  for (let k = 0; k < split.length; k++) {
    parts.push(word.substring(pos, pos + split[k].length));
    pos = pos + split[k].length + match.length;
  }
  return parts.join(`[$]${origMatch}[/$]`);
};
Chat.prototype.html = function (content) {
  if (content) {
    return this.plugins.emoticonsFilter.processHtmlMessage(escapeHTML(content));
  }
  return '';
};
Chat.prototype.updateKeysInProtocolHandlers = function () {
  this.chats.forEach(r => {
    const ph = r.protocolHandler;
    if (ph) {
      ph.reinitWithNewData(u_handle, u_privCu25519, u_privEd25519, u_pubEd25519, ph.chatMode);
    }
  });
};
Chat.prototype.eventuallyInitMeetingUI = function () {
  if (!window.location.hash) {
    return;
  }
  let loc = page.split("#")[0];
  loc = loc.replace("fm/", "/");
  if (loc.indexOf("chat/") === 0) {
    this.initialPubChatHandle = loc.substr(5).split("?")[0];
  }
};
Chat.prototype.enqueueChatRoomEvent = function (eventName, eventData) {
  if (!this.is_initialized) {
    return;
  }
  const {
    chatId
  } = eventData;
  if (!this._queuedChatRoomEvents[chatId]) {
    this._queuedChatRoomEvents[chatId] = [];
    (this._queuedChatRoomEvents[chatId].timer = tSleep(15)).then(() => {
      if (d) {
        this.logger.warn('Timer ran out, events lost...', this._queuedChatRoomEvents[chatId]);
      }
      delete this._queuedChatRoomEvents[chatId];
    });
  }
  this._queuedChatRoomEvents[chatId].push([eventName, eventData]);
};
Chat.prototype.autoJoinIfNeeded = function () {
  const rawAutoLoginInfo = localStorage.autoJoinOnLoginChat;
  if (u_type && rawAutoLoginInfo) {
    const autoLoginChatInfo = tryCatch(JSON.parse.bind(JSON))(rawAutoLoginInfo) || false;
    if (unixtime() - 7200 < autoLoginChatInfo[1]) {
      const req = this.plugins.chatdIntegration.getMciphReqFromHandleAndKey(autoLoginChatInfo[0], autoLoginChatInfo[2].substr(1));
      megaChat.rebind('onRoomInitialized.autoJoin', (e, megaRoom) => {
        if (megaRoom.chatId === autoLoginChatInfo[3]) {
          megaRoom.setActive();
          megaChat.unbind('onRoomInitialized.autoJoin');
          localStorage.removeItem("autoJoinOnLoginChat");
        }
      });
      asyncApiReq(req).catch(dump);
    } else {
      localStorage.removeItem("autoJoinOnLoginChat");
    }
  }
};
Chat.prototype.openScheduledMeeting = function (meetingId, toCall) {
  const meeting = this.scheduledMeetings[meetingId];
  if (!meeting) {
    console.warn('Meeting does not exist', meetingId);
    return;
  }
  window.focus();
  meeting.chatRoom.activateWindow();
  meeting.chatRoom.show();
  if (toCall && this.hasSupportForCalls) {
    this.openScheduledMeeting._queue = this.openScheduledMeeting._queue || [];
    this.openScheduledMeeting._queue.push(meetingId);
    delay('megachat:openScheduledMeetingCall', () => {
      const meetingId = this.openScheduledMeeting._queue[0];
      delete this.openScheduledMeeting._queue;
      const meetingRoom = this.scheduledMeetings[meetingId].chatRoom;
      meetingRoom.activateWindow();
      meetingRoom.show();
      const haveCall = this.haveAnyActiveCall();
      if (haveCall && window.sfuClient) {
        const {
          chatRoom
        } = this.activeCall;
        if (chatRoom && chatRoom.chatId === meetingRoom.chatId) {
          const peers = chatRoom.getCallParticipants();
          if (peers.includes(u_handle)) {
            return d && console.warn('Already in this call');
          }
        }
      }
      (0,call.dQ)(true, meetingRoom).then(() => meetingRoom.startAudioCall(true)).catch(ex => d && console.warn('Already in a call.', ex));
    });
  }
};
Chat.prototype.playSound = tryCatch((sound, options, stop) => {
  if (options === true) {
    stop = true;
    options = undefined;
  }
  if (stop) {
    ion.sound.stop(sound);
  }
  return ion.sound.play(sound, options);
});
Chat.prototype.fetchSoundBuffer = async function (sound) {
  if (this.SOUNDS.buffers[sound]) {
    return this.SOUNDS.buffers[sound].slice();
  }
  let res = await M.xhr({
    url: `${staticpath}media/${sound}.mp3`,
    type: 'arraybuffer'
  }).catch(() => {
    console.warn('Failed to fetch sound .mp3 file', sound);
  });
  if (!res) {
    res = await M.xhr({
      url: `${staticpath}media/${sound}.ogg`,
      type: 'arraybuffer'
    }).catch(() => {
      console.error('Failed to fetch sound .ogg file', sound);
    });
  }
  if (!res) {
    throw ENOENT;
  }
  this.SOUNDS.buffers[sound] = res.target.response.slice();
  return res.target.response;
};
window.Chat = Chat;
if (false) // removed by dead control flow
{}
const chat = {
  Chat
};

},

414:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
Cn: () => LocalVideoHiRes,
Gz: () => AudioLevelIndicator,
Qs: () => PeerVideoThumbFixed,
Vm: () => LocalVideoHiResCloned,
au: () => PeerVideoThumb,
bJ: () => LocalVideoThumb,
ob: () => PeerVideoHiResCloned,
zu: () => PeerVideoHiRes
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);
const _mixins1__ = REQ_(137);
const _contacts_jsx2__ = REQ_(251);
const _call_jsx3__ = REQ_(3);
const _ui_utils4__ = REQ_(314);





class VideoNode extends _mixins1__.w9 {
  constructor(props, source) {
    super(props);
    this.domRef = react0().createRef();
    this.contRef = react0().createRef();
    this.audioLevelRef = react0().createRef();
    this.statsHudRef = react0().createRef();
    this.raisedHandListener = undefined;
    this.state = {
      raisedHandPeers: []
    };
    this.source = source;
    this.state.raisedHandPeers = this.props.raisedHandPeers || [];
  }
  componentDidMount() {
    let _this$props$didMount, _this$props, _this$domRef;
    super.componentDidMount();
    this.source.registerConsumer(this);
    (_this$props$didMount = (_this$props = this.props).didMount) == null || _this$props$didMount.call(_this$props, (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
    this.requestVideo(true);
    this.raisedHandListener = mBroadcaster.addListener('meetings:raisedHand', raisedHandPeers => this.setState({
      raisedHandPeers
    }, () => this.safeForceUpdate()));
  }
  onVisibilityChange(isVisible) {
    this.requestVideo(isVisible);
  }
  componentDidUpdate() {
    super.componentDidUpdate();
    if (this.props.didUpdate) {
      let _this$domRef2;
      this.props.didUpdate((_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current);
    }
    this.requestVideo();
  }
  onAvChange() {
    this.safeForceUpdate();
  }
  displayVideoElement(video, container) {
    this.attachVideoElemHandlers(video);
    this.video = video;
    container.replaceChildren(video);
  }
  attachVideoElemHandlers(video) {
    if (video._snSetup) {
      return;
    }
    video.autoplay = true;
    video.controls = false;
    video.muted = true;
    video.ondblclick = e => {
      const {
        onDoubleClick,
        toggleFullScreen
      } = this.props;
      onDoubleClick == null || onDoubleClick(this.source, e);
      if (toggleFullScreen && !document.fullscreenElement && this.domRef.current) {
        if (typeof toggleFullScreen === 'function') {
          toggleFullScreen(this);
        }
        this.domRef.current.requestFullscreen({
          navigationUI: 'hide'
        });
      }
    };
    video.onloadeddata = ev => {
      if (this.props.onLoadedData) {
        this.props.onLoadedData(ev);
      }
    };
    video._snSetup = true;
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    delete this.video;
    this.detachVideoElemHandlers();
    this.source.deregisterConsumer(this);
    mBroadcaster.removeListener(this.raisedHandListener);
    if (this.props.willUnmount) {
      this.props.willUnmount();
    }
  }
  detachVideoElemHandlers() {
    let _this$contRef$current;
    const video = (_this$contRef$current = this.contRef.current) == null ? void 0 : _this$contRef$current.firstChild;
    if (!video || !video._snSetup) {
      return;
    }
    video.onloadeddata = null;
    video.ondblclick = null;
    delete video._snSetup;
  }
  isVideoCropped() {
    let _this$video;
    return (_this$video = this.video) == null ? void 0 : _this$video.classList.contains("video-crop");
  }
  cropVideo() {
    let _this$video2;
    (_this$video2 = this.video) == null || _this$video2.classList.add("video-crop");
  }
  uncropVideo() {
    let _this$video3;
    (_this$video3 = this.video) == null || _this$video3.classList.remove("video-crop");
  }
  displayStats(stats) {
    const elem = this.statsHudRef.current;
    if (!elem) {
      return;
    }
    elem.textContent = stats ? `${stats} (${this.ownVideo ? "cloned" : "ref"})` : "";
  }
  renderVideoDebugMode() {
    if (this.source.isFake) {
      return null;
    }
    let className = "video-rtc-stats";
    let title;
    if (this.isLocal) {
      if (window.sfuClient) {
        title = new URL(window.sfuClient.url).host;
      }
      if (this.props.isSelfOverlay) {
        className += " video-rtc-stats-ralign";
      }
    }
    if (!title) {
      title = "";
    }
    return react0().createElement("div", {
      ref: this.statsHudRef,
      className,
      title
    });
  }
  renderContent() {
    const {
      source,
      contRef
    } = this;
    if (this.props.isPresenterNode || source.av & Av.Camera) {
      return react0().createElement("div", {
        ref: contRef,
        className: "video-node-holder video-node-loading"
      });
    }
    delete this._lastResizeHeight;
    return react0().createElement(_contacts_jsx2__.Avatar, {
      contact: M.u[source.userHandle]
    });
  }
  getStatusIcon(icon, label) {
    return react0().createElement("span", {
      className: "simpletip",
      "data-simpletip-class": "theme-dark-forced",
      "data-simpletipposition": "top",
      "data-simpletipoffset": "5",
      "data-simpletip": label
    }, react0().createElement("i", {
      className: icon
    }));
  }
  renderStatus() {
    const {
      chatRoom,
      isPresenterNode,
      minimized
    } = this.props;
    const {
      raisedHandPeers
    } = this.state;
    const {
      source
    } = this;
    const {
      sfuClient
    } = chatRoom.call;
    const {
      userHandle,
      isOnHold
    } = source;
    const $$CONTAINER = ({
      children
    }) => react0().createElement("div", {
      className: "video-node-status theme-dark-forced"
    }, children);
    const name = react0().createElement("div", {
      className: "video-status-name"
    }, isPresenterNode ? react0().createElement(_ui_utils4__.zT, null, l.presenter_nail.replace('%s', M.getNameByHandle(userHandle))) : react0().createElement(_contacts_jsx2__.ContactAwareName, {
      contact: M.u[userHandle],
      emoji: true
    }));
    if (isOnHold) {
      return react0().createElement($$CONTAINER, null, name, this.getStatusIcon('sprite-fm-mono icon-pause', l[23542].replace('%s', M.getNameByHandle(userHandle) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER)));
    }
    return react0().createElement(react0().Fragment, null, !minimized && react0().createElement("div", {
      className: "stream-signifiers"
    }, raisedHandPeers && raisedHandPeers.length && raisedHandPeers.includes(userHandle) ? this.getStatusIcon('sprite-fm-uni stream-signifier-icon icon-raise-hand') : null), react0().createElement($$CONTAINER, null, name, react0().createElement(AudioLevelIndicator, {
      source
    }), sfuClient.haveBadNetwork ? this.getStatusIcon('sprite-fm-mono icon-call-offline', l.poor_connection) : null));
  }
  render() {
    const {
      mode,
      chatRoom,
      simpletip,
      className,
      children,
      onClick
    } = this.props;
    const {
      domRef,
      source,
      isLocal,
      isLocalScreen
    } = this;
    if (!chatRoom.call) {
      return null;
    }
    const {
      call
    } = chatRoom;
    const isActiveSpeaker = !source.audioMuted && call.speakerCid === source.clientId;
    return react0().createElement("div", {
      ref: domRef,
      className: `
                    video-node
                    ${onClick ? 'clickable' : ''}
                    ${className || ''}
                    ${isLocal && !isLocalScreen ? ' local-stream-mirrored' : ''}
                    ${simpletip ? 'simpletip' : ''}
                    ${isActiveSpeaker && mode === _call_jsx3__.g.THUMBNAIL ? 'active-speaker' : ''}
                `,
      "data-simpletip": simpletip == null ? void 0 : simpletip.label,
      "data-simpletipposition": simpletip == null ? void 0 : simpletip.position,
      "data-simpletipoffset": simpletip == null ? void 0 : simpletip.offset,
      "data-simpletip-class": simpletip == null ? void 0 : simpletip.className,
      onClick: evt => onClick == null ? void 0 : onClick(source, evt)
    }, source && react0().createElement(react0().Fragment, null, children || null, react0().createElement("div", {
      className: "video-node-content"
    }, CallManager2.Call.VIDEO_DEBUG_MODE ? this.renderVideoDebugMode() : null, this.renderContent(), this.renderStatus())));
  }
}
class DynVideo extends VideoNode {
  onAvChange() {
    this._lastResizeHeight = null;
    super.onAvChange();
  }
  dynRequestVideo() {
    const {
      source,
      domRef
    } = this;
    if (source.isFake || source.isDestroyed) {
      return;
    }
    if (source.isStreaming() && this.isMounted()) {
      const node = domRef == null ? void 0 : domRef.current;
      this.dynRequestVideoBySize(node.offsetHeight);
    } else {
      this.dynRequestVideoBySize(0);
      this.displayStats(null);
    }
  }
  dynRequestVideoQuality(quality) {
    this.requestedQ = quality && CallManager2.FORCE_LOWQ ? 1 : quality;
    if (!this.source.dynUpdateVideoQuality()) {
      this.dynUpdateVideoElem();
    }
  }
  dynRequestVideoBySize(h) {
    if (h === 0) {
      this._lastResizeHeight = 0;
      this.dynRequestVideoQuality(CallManager2.VIDEO_QUALITY.NO_VIDEO);
      return;
    }
    if (this.contRef.current) {
      if (this._lastResizeHeight === h) {
        return;
      }
      this._lastResizeHeight = h;
    } else {
      this._lastResizeHeight = null;
    }
    let newQ;
    if (h > 360) {
      newQ = CallManager2.VIDEO_QUALITY.HIGH;
    } else if (h > 180) {
      newQ = CallManager2.VIDEO_QUALITY.MEDIUM;
    } else if (h > 90 || this.noThumb) {
      newQ = CallManager2.VIDEO_QUALITY.LOW;
    } else {
      newQ = CallManager2.VIDEO_QUALITY.THUMB;
    }
    this.dynRequestVideoQuality(newQ);
  }
  dynUpdateVideoElem() {
    let _this$source$hiResPla;
    const vidCont = this.contRef.current;
    if (!this.isMounted() || !vidCont) {
      return;
    }
    const player = this.noThumb ? (_this$source$hiResPla = this.source.hiResPlayer) == null || (_this$source$hiResPla = _this$source$hiResPla.gui) == null ? void 0 : _this$source$hiResPla.video : this.source.player;
    if (!player) {
      vidCont.replaceChildren();
      return;
    }
    this.dynSetVideoSource(player, vidCont);
  }
}
class DynVideoDirect extends DynVideo {
  constructor(props, source) {
    super(props, source);
    this.isDirect = true;
    this.requestVideo = this.dynRequestVideo;
  }
  dynSetVideoSource(srcPlayer, vidCont) {
    if (vidCont.firstChild !== srcPlayer) {
      this.displayVideoElement(srcPlayer, vidCont);
    }
    if (srcPlayer.paused) {
      srcPlayer.play().catch(nop);
    }
  }
}
class PeerVideoHiRes extends DynVideoDirect {
  constructor(props) {
    super(props, props.source);
  }
}
class DynVideoCloned extends DynVideo {
  constructor(props, source) {
    super(props, source);
    this.ownVideo = CallManager2.createVideoElement();
  }
  dynSetVideoSource(srcPlayer, vidCont) {
    const cloned = this.ownVideo;
    const currVideo = vidCont.firstChild;
    if (!currVideo) {
      this.displayVideoElement(cloned, vidCont);
    } else {
      assert(currVideo === cloned);
    }
    if (cloned.paused || cloned.srcObject !== srcPlayer.srcObject) {
      cloned.srcObject = srcPlayer.srcObject;
      Promise.resolve(cloned.play()).catch(nop);
    }
  }
}
class PeerVideoThumb extends DynVideoCloned {
  constructor(props) {
    super(props, props.source);
    this.requestVideo = this.dynRequestVideo;
  }
}
class PeerVideoThumbFixed extends VideoNode {
  constructor(props) {
    super(props, props.source);
    assert(props.source.hasScreenAndCam);
    this.ownVideo = CallManager2.createVideoElement();
    if (CallManager2.Call.VIDEO_DEBUG_MODE) {
      this.onRxStats = this._onRxStats;
    }
  }
  addVideo() {
    assert(this.source.hasScreenAndCam);
    const vidCont = this.contRef.current;
    assert(vidCont);
    if (vidCont.firstChild !== this.ownVideo) {
      this.displayVideoElement(this.ownVideo, vidCont);
    }
  }
  delVideo() {
    SfuClient.playerStop(this.ownVideo);
    const vidCont = this.contRef.current;
    if (!vidCont) {
      return;
    }
    vidCont.replaceChildren();
  }
  requestVideo(forceVisible) {
    if (!this.isComponentVisible() && !forceVisible) {
      return;
    }
    if (this.player) {
      this.playVideo();
    } else {
      this.addVideo();
      this.player = this.source.sfuPeer.getThumbVideo(() => {
        return this;
      });
    }
  }
  playVideo() {
    let _this$player$slot;
    const track = (_this$player$slot = this.player.slot) == null ? void 0 : _this$player$slot.inTrack;
    if (!track) {
      return;
    }
    SfuClient.playerPlay(this.ownVideo, track, true);
  }
  attachToTrack(track) {
    if (!this.source.hasScreenAndCam) {
      return;
    }
    SfuClient.playerPlay(this.ownVideo, track);
  }
  detachFromTrack() {
    this.delVideo();
  }
  onPlayerDestroy() {
    delete this.player;
  }
  componentWillUnmount() {
    if (this.player) {
      this.player.destroy();
    }
    super.componentWillUnmount();
  }
  _onRxStats(track, info, raw) {
    if (this.player) {
      this.displayStats(CallManager2.Call.rxStatsToText(track, info, raw));
    }
  }
}
class PeerVideoHiResCloned extends DynVideoCloned {
  constructor(props) {
    super(props, props.source);
    this.noThumb = true;
    this.requestVideo = this.dynRequestVideo;
  }
}
class LocalVideoHiResCloned extends VideoNode {
  constructor(props) {
    super(props, props.chatRoom.call.getLocalStream());
    this.isLocal = true;
    this.ownVideo = CallManager2.createVideoElement();
  }
  get isLocalScreen() {
    return this.source.av & Av.Screen;
  }
  requestVideo(forceVisible) {
    if (d > 1 && forceVisible) {
      console.debug('ignoring forceVisible');
    }
    const vidCont = this.contRef.current;
    if (!vidCont) {
      return;
    }
    const track = this.source.sfuClient.localScreenTrack();
    if (!track) {
      vidCont.replaceChildren();
    } else {
      if (vidCont.firstChild !== this.ownVideo) {
        this.displayVideoElement(this.ownVideo, vidCont);
      }
      SfuClient.playerPlay(this.ownVideo, track, true);
    }
  }
}
class LocalVideoHiRes extends DynVideoDirect {
  constructor(props) {
    super(props, props.chatRoom.call.getLocalStream());
    this.isLocal = true;
  }
  get isLocalScreen() {
    return this.source.av & Av.Screen;
  }
}
class LocalVideoThumb extends VideoNode {
  constructor(props) {
    const source = props.chatRoom.call.getLocalStream();
    super(props, source);
    this.isLocal = true;
    this.isLocalScreen = source.av & Av.Screen && !(source.av & Av.Camera);
    this.sfuClient = props.chatRoom.call.sfuClient;
    this.ownVideo = CallManager2.createVideoElement();
  }
  requestVideo() {
    const vidCont = this.contRef.current;
    if (!vidCont) {
      return;
    }
    const currVideo = vidCont.firstChild;
    const track = this.isLocalScreen ? this.sfuClient.localScreenTrack() : this.sfuClient.localCameraTrack();
    if (!track) {
      if (currVideo) {
        vidCont.replaceChildren();
      }
    } else {
      if (!currVideo) {
        this.displayVideoElement(this.ownVideo, vidCont);
      } else {
        assert(currVideo === this.ownVideo);
      }
      SfuClient.playerPlay(this.ownVideo, track, true);
    }
  }
  onAvChange() {
    const av = this.sfuClient.availAv;
    this.isLocalScreen = av & Av.Screen && !(av & Av.Camera);
    super.onAvChange();
  }
}
class AudioLevelIndicator extends react0().Component {
  constructor(props) {
    super(props);
    this.source = props.source;
    this.indicatorRef = react0().createRef();
    this.updateAudioLevel = this.updateAudioLevel.bind(this);
  }
  componentDidMount() {
    this.source.registerVuLevelConsumer(this);
  }
  componentWillUnmount() {
    this.source.unregisterVuLevelConsumer(this);
  }
  updateAudioLevel(level) {
    const levelInd = this.indicatorRef.current;
    if (!levelInd) {
      return;
    }
    level = Math.round(level * 400);
    if (level > 90) {
      level = 90;
    }
    levelInd.style.height = `${level + 10}%`;
  }
  render() {
    const {
      audioMuted
    } = this.source;
    return react0().createElement("span", {
      className: "simpletip",
      "data-simpletip-class": "theme-dark-forced",
      "data-simpletipposition": "top",
      "data-simpletipoffset": "5",
      "data-simpletip": audioMuted ? l.muted : ''
    }, react0().createElement("i", {
      className: `
                        sprite-fm-mono
                        ${audioMuted ? 'icon-mic-off-thin-outline inactive' : 'icon-mic-thin-outline speaker-indicator'}
                    `
    }, audioMuted ? null : react0().createElement("div", {
      ref: this.indicatorRef,
      className: "mic-fill"
    })));
  }
}

},

415:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  $A: () => MAX_STREAMS,
  Bq: () => PAGINATION,
  gh: () => STREAMS_PER_PAGE,
  hK: () => STREAM_ACTIONS,
  ro: () => chunkNodes,
  Ay: () => stream_Stream,
  iv: () => filterAndSplitSources
});

// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
const esm_extends = REQ_(168);
// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
const meetings_call = REQ_(3);
// EXTERNAL MODULE: ./js/chat/ui/meetings/videoNode.jsx
const videoNode = REQ_(414);
// EXTERNAL MODULE: ./js/ui/utils.jsx
const utils = REQ_(314);
// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
const meetings_button = REQ_(959);
// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
const dropdowns = REQ_(911);
// EXTERNAL MODULE: ./js/ui/buttons.jsx
const buttons = REQ_(994);
;// ./js/chat/ui/meetings/floatExtendedControls.jsx



class FloatExtendedControls extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.isActive = type => {
      return !!(this.props.call.av & type);
    };
  }
  render() {
    const {
      hasToRenderPermissionsWarning,
      renderPermissionsWarning,
      resetError,
      showScreenDialog,
      onScreenSharingClick,
      onHoldClick
    } = this.props;
    const {
      onHold,
      Screen
    } = SfuClient.Av;
    const isOnHold = this.isActive(onHold);
    const callHoldLabel = isOnHold ? l[23459] : l[23460];
    const screenSharingLabel = this.isActive(Screen) ? l[22890] : l[22889];
    return REaCt().createElement(buttons.$, {
      className: "mega-button theme-light-forced round large button-group",
      icon: "sprite-fm-mono icon-options",
      showScreenDialog
    }, this.isActive(Screen) && REaCt().createElement("div", {
      className: "info-indicator active"
    }), REaCt().createElement(dropdowns.Dropdown, {
      className: "button-group-menu theme-dark-forced",
      noArrow: true,
      positionAt: "center top",
      collision: "none",
      vertOffset: -90,
      ref: r => {
        this.dropdownRef = r;
      },
      onBeforeActiveChange: e => {
        if (e) {
          $(document.body).trigger('closeAllDropdownsExcept', this.dropdownRef);
        }
      },
      showScreenDialog
    }, REaCt().createElement(dropdowns.DropdownItem, {
      key: "call-hold",
      className: `
                            theme-dark-forced
                            ${isOnHold ? 'active' : ''}
                        `,
      label: callHoldLabel,
      icon: `
                            sprite-fm-mono
                            ${isOnHold ? 'icon-play-small-regular-outline' : 'icon-pause-small-regular-outline'}
                        `,
      onClick: onHoldClick
    }), REaCt().createElement(dropdowns.DropdownItem, {
      key: "screen-sharing",
      className: `
                            theme-dark-forced
                            ${isOnHold ? 'disabled' : ''}
                            ${this.isActive(Screen) ? 'active' : ''}
                        `,
      label: screenSharingLabel,
      icon: `
                            sprite-fm-mono
                            ${this.isActive(Screen) ? 'icon-monitor-off' : 'icon-monitor'}
                        `,
      onClick: () => {
        resetError(Av.Screen);
        onScreenSharingClick();
      }
    }), hasToRenderPermissionsWarning(Screen) ? renderPermissionsWarning(Screen, this) : null));
  }
}
FloatExtendedControls.NAMESPACE = 'stream-extended-controls';
// EXTERNAL MODULE: ./js/chat/ui/meetings/micObserver.jsx
const micObserver = REQ_(772);
// EXTERNAL MODULE: ./js/chat/ui/meetings/permissionsObserver.jsx
const permissionsObserver = REQ_(542);
// EXTERNAL MODULE: ./js/chat/ui/meetings/hostsObserver.jsx
const hostsObserver = REQ_(972);
// EXTERNAL MODULE: ./js/chat/ui/meetings/streamControls.jsx
const streamControls = REQ_(489);
;// ./js/chat/ui/meetings/float.jsx












class FloatingVideo extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.collapseListener = null;
    this.state = {
      collapsed: false
    };
    this.toggleCollapsedMode = () => {
      return this.setState(state => ({
        collapsed: !state.collapsed
      }));
    };
  }
  componentWillUnmount() {
    mBroadcaster.removeListener(this.collapseListener);
  }
  componentDidMount() {
    this.collapseListener = mBroadcaster.addListener('meetings:collapse', () => this.setState({
      collapsed: true
    }));
  }
  componentDidUpdate() {
    if (typeof psa !== 'undefined') {
      psa.repositionMeetingsCall();
    }
  }
  render() {
    const {
      peers,
      minimized,
      call,
      floatDetached
    } = this.props;
    if (peers.length === 0 && !minimized && !call.isSharingScreen()) {
      return null;
    }
    const STREAM_PROPS = {
      ...this.props,
      collapsed: this.state.collapsed,
      toggleCollapsedMode: this.toggleCollapsedMode,
      onLoadedData: this.onLoadedData
    };
    if (minimized) {
      return REaCt().createElement(utils.Ay.RenderTo, {
        element: document.body
      }, REaCt().createElement(Stream, STREAM_PROPS));
    }
    return floatDetached ? REaCt().createElement(Stream, STREAM_PROPS) : null;
  }
}
FloatingVideo.NAMESPACE = 'float-video';
FloatingVideo.POSITION_MODIFIER = 'with-sidebar';
class Stream extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.DRAGGABLE = {
      POSITION: {
        top: undefined,
        left: undefined
      },
      OPTIONS: {
        scroll: 'false',
        cursor: 'move',
        opacity: 1,
        start: () => {
          if (this.state.options) {
            this.handleOptionsToggle();
          }
          $(document.body).trigger('closeAllDropdownsExcept');
        },
        stop: (event, ui) => {
          this.DRAGGABLE.POSITION = ui.position;
          const {
            clientWidth,
            clientHeight
          } = document.body;
          const {
            helper
          } = ui;
          const {
            left,
            top
          } = this.DRAGGABLE.POSITION;
          if (left < clientWidth / 2) {
            helper.css('left', `${left / clientWidth * 100}%`).css('right', 'unset');
          } else {
            helper.css('left', 'unset').css('right', `${clientWidth - left - helper.width()}px`);
          }
          if (top < clientHeight / 2) {
            helper.css('top', `${top / clientHeight * 100}%`).css('bottom', 'unset');
          } else {
            helper.css('top', 'unset').css('bottom', `${clientHeight - top - helper.height()}px`);
          }
        }
      }
    };
    this.EVENTS = {
      MINIMIZE: ['slideshow:open', 'contact:open', 'textEditor:open', 'chat:open'],
      EXPAND: ['slideshow:close', 'textEditor:close']
    };
    this.LISTENERS = [];
    this.PREV_STATE = {};
    this.state = {
      options: false
    };
    this.getStreamSource = () => {
      const {
        call,
        mode,
        forcedLocal
      } = this.props;
      return mode === meetings_call.g.MINI && !forcedLocal ? call.getActiveStream() : call.getLocalStream();
    };
    this.unbindEvents = () => {
      const events = [...this.EVENTS.MINIMIZE, ...this.EVENTS.EXPAND];
      for (let i = events.length; i--;) {
        const event = events[i];
        mBroadcaster.removeListener(this.LISTENERS[event]);
      }
      document.removeEventListener('click', this.handleOptionsClose);
    };
    this.bindEvents = () => {
      for (let i = this.EVENTS.MINIMIZE.length; i--;) {
        const event = this.EVENTS.MINIMIZE[i];
        this.LISTENERS[event] = mBroadcaster.addListener(event, () => {
          this.PREV_STATE.minimised = this.props.minimized;
          return this.props.onCallMinimize();
        });
      }
      for (let i = this.EVENTS.EXPAND.length; i--;) {
        const event = this.EVENTS.EXPAND[i];
        this.LISTENERS[event] = mBroadcaster.addListener(event, () => {
          if (this.PREV_STATE.minimised) {
            delete this.PREV_STATE.minimised;
            return;
          }
          delete this.PREV_STATE.minimised;
          return this.props.view === meetings_call.gR.CHAT && this.props.onCallExpand();
        });
      }
      document.addEventListener('click', this.handleOptionsClose);
    };
    this.initDraggable = () => {
      let _this$domRef;
      const {
        minimized,
        wrapperRef
      } = this.props;
      const containerEl = (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current;
      if (containerEl) {
        $(containerEl).draggable({
          ...this.DRAGGABLE.OPTIONS,
          containment: minimized ? 'body' : wrapperRef == null ? void 0 : wrapperRef.current
        });
      }
    };
    this.repositionDraggable = () => {
      let _this$props$wrapperRe, _this$domRef2;
      const wrapperEl = (_this$props$wrapperRe = this.props.wrapperRef) == null ? void 0 : _this$props$wrapperRe.current;
      const localEl = (_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current;
      if (localEl.offsetLeft + localEl.offsetWidth > wrapperEl.offsetWidth) {
        localEl.style.left = 'unset';
        localEl.style.removeProperty("right");
      }
    };
    this.handleOptionsClose = ({
      target
    }) => {
      if (this.state.options && !target.classList.contains('icon-options')) {
        this.setState({
          options: false
        });
      }
    };
    this.handleOptionsToggle = () => this.setState({
      options: !this.state.options
    });
    this.renderOnHoldVideoNode = () => REaCt().createElement(videoNode.Cn, {
      chatRoom: this.props.chatRoom
    });
    this.renderOptionsDialog = () => {
      const {
        call,
        mode,
        forcedLocal,
        onScreenSharingClick,
        onSpeakerChange,
        onModeChange,
        toggleCollapsedMode,
        onMoveIntoGrid
      } = this.props;
      const IS_SPEAKER_VIEW = mode === meetings_call.g.MAIN && forcedLocal;
      const {
        POSITION
      } = this.DRAGGABLE;
      return REaCt().createElement("div", {
        className: `
                     ${FloatingVideo.NAMESPACE}-options
                     ${POSITION.left < 200 ? 'options-top' : ''}
                     ${POSITION.left < 200 && POSITION.top < 100 ? 'options-bottom' : ''}
                     theme-dark-forced
                 `
      }, REaCt().createElement("ul", null, REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
        icon: `
                                sprite-fm-mono
                                ${IS_SPEAKER_VIEW ? 'grid-9' : 'grid-main'}
                            `,
        onClick: () => this.setState({
          options: false
        }, () => {
          if (IS_SPEAKER_VIEW) {
            return onModeChange(meetings_call.g.THUMBNAIL);
          }
          onSpeakerChange(call.getLocalStream());
        })
      }, REaCt().createElement("div", null, IS_SPEAKER_VIEW ? l.switch_to_thumb_view : l.display_in_main_view))), REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
        icon: "sprite-fm-mono icon-collapse-up",
        onClick: onMoveIntoGrid
      }, REaCt().createElement("div", null, l.move_into_grid_button))), REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
        icon: "sprite-fm-mono icon-download-standard",
        onClick: () => this.setState({
          options: false
        }, () => toggleCollapsedMode())
      }, REaCt().createElement("div", null, l.collapse_self_video)))), !!(call.av & SfuClient.Av.Screen) && REaCt().createElement("ul", {
        className: "has-separator"
      }, REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
        className: "end-screen-share",
        icon: "icon-end-screenshare",
        onClick: () => {
          this.setState({
            options: false
          });
          onScreenSharingClick();
        }
      }, REaCt().createElement("div", null, l[22890])))));
    };
    this.renderMiniMode = source => {
      const {
        call,
        chatRoom,
        mode,
        minimized,
        isPresenterNode,
        onLoadedData
      } = this.props;
      if (call.isOnHold) {
        return this.renderOnHoldVideoNode();
      }
      const VideoClass = source.isLocal ? isPresenterNode ? videoNode.Cn : videoNode.bJ : videoNode.zu;
      return REaCt().createElement(VideoClass, {
        key: source,
        source,
        chatRoom,
        mode,
        minimized,
        isPresenterNode,
        onLoadedData
      });
    };
    this.renderSelfView = () => {
      const {
        isOnHold,
        raisedHandPeers,
        minimized,
        chatRoom,
        isPresenterNode,
        call,
        onLoadedData
      } = this.props;
      const {
        options
      } = this.state;
      if (isOnHold) {
        return this.renderOnHoldVideoNode();
      }
      const VideoNode = call.isSharingScreen() ? videoNode.Vm : videoNode.bJ;
      return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(VideoNode, {
        isSelfOverlay: true,
        raisedHandPeers,
        minimized,
        chatRoom,
        isPresenterNode,
        onLoadedData
      }), REaCt().createElement("div", {
        className: `${FloatingVideo.NAMESPACE}-self-overlay`
      }, minimized ? null : REaCt().createElement(meetings_button.A, {
        className: `
                                mega-button
                                theme-light-forced
                                action
                                small
                                float-video-options-control
                                ${options ? 'active' : ''}
                            `,
        icon: "sprite-fm-mono icon-options",
        onClick: () => this.handleOptionsToggle()
      }), options && this.renderOptionsDialog()));
    };
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    this.unbindEvents();
  }
  componentDidUpdate(prevProps) {
    super.componentDidUpdate();
    if (this.props.mode !== prevProps.mode) {
      this.initDraggable();
    }
    if (this.props.sidebar !== prevProps.sidebar && this.props.sidebar) {
      this.repositionDraggable();
    }
  }
  componentDidMount() {
    super.componentDidMount();
    this.bindEvents();
    this.initDraggable();
  }
  render() {
    const {
      NAMESPACE,
      POSITION_MODIFIER
    } = FloatingVideo;
    const {
      call,
      mode,
      minimized,
      sidebar,
      collapsed,
      toggleCollapsedMode,
      onCallExpand
    } = this.props;
    const IS_MINI_MODE = mode === meetings_call.g.MINI;
    if (collapsed) {
      return REaCt().createElement("div", {
        ref: this.domRef,
        className: `
                        ${NAMESPACE}
                        collapsed
                        theme-dark-forced
                        ${sidebar && !minimized ? POSITION_MODIFIER : ''}
                    `,
        onClick: toggleCollapsedMode
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-arrow-up icon-collapse"
      }), REaCt().createElement("div", {
        className: "collapsed-audio-indicator"
      }, REaCt().createElement(videoNode.Gz, {
        source: call.getLocalStream()
      })));
    }
    const source = this.getStreamSource() || call.getLocalStream();
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                    ${NAMESPACE}
                    ${IS_MINI_MODE ? 'mini' : ''}
                    ${minimized ? 'minimized' : ''}
                    ${this.state.options ? 'active' : ''}
                    ${sidebar && !minimized ? POSITION_MODIFIER : ''}
                `,
      onClick: ({
        target
      }) => minimized && target.classList.contains(`${NAMESPACE}-overlay`) && onCallExpand()
    }, IS_MINI_MODE && this.renderMiniMode(source), !IS_MINI_MODE && this.renderSelfView(), minimized && REaCt().createElement(__Minimized, (0,esm_extends.A)({}, this.props, {
      onOptionsToggle: this.handleOptionsToggle
    })));
  }
}
class Minimized extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.SIMPLETIP_PROPS = {
      position: 'top',
      offset: 5,
      className: 'theme-dark-forced'
    };
    this.waitingPeersListener = undefined;
    this.raisedHandListener = undefined;
    this.state = {
      unread: 0,
      waitingRoomPeers: [],
      raisedHandPeers: [],
      hideWrList: false,
      hideHandsList: false
    };
    this.isActive = type => {
      return this.props.call.av & type;
    };
    this.getUnread = () => {
      const {
        chatRoom
      } = this.props;
      chatRoom.rebind(Minimized.UNREAD_EVENT, () => this.setState({
        unread: chatRoom.getUnreadCount()
      }, () => this.safeForceUpdate()));
    };
    this.renderSignalWarning = () => this.props.signal ? null : this.props.renderSignalWarning();
    this.renderPermissionsWarning = type => {
      const {
        hasToRenderPermissionsWarning,
        renderPermissionsWarning
      } = this.props;
      if (hasToRenderPermissionsWarning(type)) {
        return renderPermissionsWarning(type, this);
      }
      return null;
    };
    this.renderStreamControls = () => {
      const {
        call,
        chatRoom,
        recorderCid,
        hasToRenderPermissionsWarning,
        renderPermissionsWarning,
        resetError,
        onRecordingToggle,
        onAudioClick,
        onVideoClick,
        onScreenSharingClick,
        onHoldClick,
        onCallEnd
      } = this.props;
      const audioLabel = this.isActive(SfuClient.Av.Audio) ? l[16214] : l[16708];
      const videoLabel = this.isActive(SfuClient.Av.Camera) ? l[22894] : l[22893];
      const LeaveButton = (0,hostsObserver.C)(({
        hasHost,
        chatRoom,
        confirmLeave,
        onLeave
      }) => {
        return REaCt().createElement(meetings_button.A, {
          simpletip: {
            ...this.SIMPLETIP_PROPS,
            label: l[5884]
          },
          className: "mega-button theme-dark-forced round large end-call",
          icon: "icon-phone-02",
          onClick: ev => {
            ev.stopPropagation();
            const callParticipants = chatRoom.getCallParticipants();
            const doLeave = () => !chatRoom.iAmOperator() || hasHost(chatRoom.call ? chatRoom.call.peers.map(a => a.userHandle) : []) || callParticipants.length === 1 ? onLeave() : confirmLeave({
              title: l.assign_host_leave_call,
              body: l.assign_host_leave_call_details,
              cta: l.assign_host_button,
              altCta: l.leave_anyway
            });
            return recorderCid && recorderCid === call.sfuClient.cid ? (0,streamControls.sX)(doLeave, onRecordingToggle) : doLeave();
          }
        }, REaCt().createElement("span", null, l[5884]));
      });
      return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
        className: `${FloatingVideo.NAMESPACE}-controls`
      }, REaCt().createElement("div", {
        className: "meetings-signal-container"
      }, REaCt().createElement(meetings_button.A, {
        simpletip: {
          ...this.SIMPLETIP_PROPS,
          label: audioLabel
        },
        className: `
                                mega-button
                                theme-light-forced
                                round
                                ${this.isActive(SfuClient.Av.onHold) ? 'disabled' : ''}
                                ${this.isActive(SfuClient.Av.Audio) ? '' : 'with-fill'}
                            `,
        icon: this.isActive(SfuClient.Av.Audio) ? 'icon-mic-thin-outline' : 'icon-mic-off-thin-outline',
        onClick: ev => {
          ev.stopPropagation();
          resetError(Av.Audio);
          onAudioClick();
        }
      }, REaCt().createElement("span", null, audioLabel)), this.renderSignalWarning(), this.renderPermissionsWarning(Av.Audio)), REaCt().createElement("div", {
        className: "meetings-signal-container"
      }, REaCt().createElement(meetings_button.A, {
        simpletip: {
          ...this.SIMPLETIP_PROPS,
          label: videoLabel
        },
        className: `
                                mega-button
                                theme-light-forced
                                round
                                ${this.isActive(SfuClient.Av.onHold) ? 'disabled' : ''}
                                ${this.isActive(SfuClient.Av.Camera) ? '' : 'with-fill'}
                            `,
        icon: this.isActive(SfuClient.Av.Camera) ? 'icon-video-thin-outline' : 'icon-video-off-thin-outline',
        onClick: ev => {
          ev.stopPropagation();
          resetError(Av.Camera);
          onVideoClick();
        }
      }, REaCt().createElement("span", null, videoLabel)), this.renderPermissionsWarning(Av.Camera)), REaCt().createElement("div", {
        className: "meetings-signal-container"
      }, REaCt().createElement(FloatExtendedControls, {
        call,
        chatRoom,
        onScreenSharingClick,
        onHoldClick,
        hasToRenderPermissionsWarning,
        renderPermissionsWarning,
        resetError,
        showScreenDialog: !!this.props[`dialog-${Av.Screen}`]
      }), this.renderPermissionsWarning(Av.Screen)), REaCt().createElement(LeaveButton, {
        chatRoom,
        participants: chatRoom.getCallParticipants(),
        onLeave: onCallEnd,
        onConfirmDenied: onCallEnd
      })), REaCt().createElement("span", {
        className: `${FloatingVideo.NAMESPACE}-fade`
      }));
    };
    this.renderPeersList = () => {
      const {
        onCallExpand,
        onParticipantsToggle,
        onWrListToggle
      } = this.props;
      const {
        waitingRoomPeers,
        raisedHandPeers,
        hideHandsList,
        hideWrList
      } = this.state;
      if (hideHandsList && hideWrList) {
        return null;
      }
      const showRaised = hideHandsList || !hideWrList && waitingRoomPeers.length ? false : !!raisedHandPeers.length;
      if (!showRaised && hideWrList) {
        return null;
      }
      const showButton = !showRaised || showRaised && raisedHandPeers.length > 1;
      return REaCt().createElement("div", {
        className: `
                    ${FloatingVideo.NAMESPACE}-alert
                    alert--waiting-peers
                    theme-dark-forced
                `,
        onClick: onCallExpand
      }, REaCt().createElement(meetings_button.A, {
        className: "close js-close",
        icon: "sprite-fm-mono icon-dialog-close",
        hideWrList,
        hideHandsList,
        onClick: ev => {
          ev.stopPropagation();
          this.setState({
            hideHandsList: hideWrList || showRaised,
            hideWrList: true
          });
        }
      }), REaCt().createElement("div", {
        className: `alert-label ${showButton ? '' : 'label-only'}`
      }, showRaised && REaCt().createElement("i", {
        className: "sprite-fm-uni icon-raise-hand"
      }), !hideWrList && !!waitingRoomPeers.length && mega.icu.format(l.wr_peers_waiting, waitingRoomPeers.length), showRaised && (raisedHandPeers.length > 1 ? raisedHandPeers.includes(u_handle) ? mega.icu.format(l.raise_self_peers_raised, raisedHandPeers.length - 1) : mega.icu.format(l.raise_peers_raised, raisedHandPeers.length) : REaCt().createElement(utils.P9, {
        tag: "span",
        content: raisedHandPeers[0] === u_handle ? l.raise_self_raised : l.raise_peer_raised.replace('%s', megaChat.html(M.getNameByHandle(raisedHandPeers[0])))
      }))), showButton && REaCt().createElement(meetings_button.A, {
        className: "show-people",
        label: showRaised ? l[16797] : l.wr_see_waiting,
        onClick: ev => {
          ev.stopPropagation();
          const promise = onCallExpand().catch(dump);
          if (showRaised) {
            promise.then(() => onParticipantsToggle(true));
          } else if (waitingRoomPeers.length > 1) {
            promise.then(() => onWrListToggle(true));
          }
        }
      }, showRaised ? l[16797] : l.wr_see_waiting));
    };
    this.state.waitingRoomPeers = this.props.waitingRoomPeers || [];
    this.state.raisedHandPeers = this.props.raisedHandPeers || [];
  }
  componentDidMount() {
    super.componentDidMount();
    this.getUnread();
    this.waitingPeersListener = mBroadcaster.addListener('meetings:peersWaiting', waitingRoomPeers => this.setState({
      waitingRoomPeers,
      hideWrList: false,
      hideHandsList: false
    }, () => this.safeForceUpdate()));
    this.raisedHandListener = mBroadcaster.addListener('meetings:raisedHand', raisedHandPeers => this.setState({
      raisedHandPeers,
      hideWrList: false,
      hideHandsList: false
    }, () => this.safeForceUpdate()));
    ['onCallPeerJoined', 'onCallPeerLeft'].map(event => this.props.chatRoom.rebind(`${event}.${Minimized.NAMESPACE}`, (ev, {
      userHandle
    }) => this.isMounted() && this.setState(state => ({
      raisedHandPeers: state.raisedHandPeers.includes(userHandle) ? state.raisedHandPeers.filter(h => h !== userHandle) : [...this.props.call.sfuClient.raisedHands]
    }), this.safeForceUpdate)));
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    this.props.chatRoom.unbind(Minimized.UNREAD_EVENT);
    [this.waitingPeersListener, this.raisedHandListener].map(listener => mBroadcaster.removeListener(listener));
    ['onCallPeerJoined', 'onCallPeerLeft'].map(event => this.props.chatRoom.off(`${event}.${Minimized.NAMESPACE}`));
  }
  render() {
    const {
      onCallExpand
    } = this.props;
    const {
      unread,
      raisedHandPeers,
      waitingRoomPeers
    } = this.state;
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `${FloatingVideo.NAMESPACE}-wrapper`
    }, REaCt().createElement("div", {
      className: `${FloatingVideo.NAMESPACE}-overlay`
    }, REaCt().createElement(meetings_button.A, {
      simpletip: {
        ...this.SIMPLETIP_PROPS,
        label: l.expand_mini_call
      },
      className: "mega-button theme-light-forced action small expand",
      icon: "sprite-fm-mono icon-fullscreen-enter",
      onClick: ev => {
        ev.stopPropagation();
        onCallExpand();
      }
    }), this.renderStreamControls()), waitingRoomPeers && waitingRoomPeers.length || raisedHandPeers && raisedHandPeers.length ? this.renderPeersList() : null, unread ? REaCt().createElement("div", {
      className: `${FloatingVideo.NAMESPACE}-notifications`
    }, REaCt().createElement(meetings_button.A, {
      className: "mega-button round large chat-control",
      icon: "icon-chat-filled"
    }, REaCt().createElement("span", null, l.chats)), REaCt().createElement("span", null, unread > 9 ? '9+' : unread)) : null);
  }
}
Minimized.NAMESPACE = 'float-video-minimized';
Minimized.UNREAD_EVENT = 'onUnreadCountUpdate.localStreamNotifications';
const __Minimized = (0,mixins.Zz)(micObserver.Q, permissionsObserver.$)(Minimized);
// EXTERNAL MODULE: ./js/chat/ui/inviteParticipantsPanel.jsx
const inviteParticipantsPanel = REQ_(815);
;// ./js/chat/ui/meetings/participantsNotice.jsx






class ParticipantsNotice extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.renderUserAlone = () => REaCt().createElement("div", {
      className: `
                ${ParticipantsNotice.NAMESPACE}
                theme-dark-forced
                user-alone
            `
    }, this.props.stayOnEnd ? REaCt().createElement("div", {
      className: `${ParticipantsNotice.NAMESPACE}-heading`
    }, REaCt().createElement("h1", null, this.props.everHadPeers ? l.only_one_here : l.waiting_for_others)) : REaCt().createElement("div", {
      className: `${ParticipantsNotice.NAMESPACE}-content user-alone`
    }, REaCt().createElement("h3", null, l.only_one_here), REaCt().createElement("p", {
      className: "theme-dark-forced"
    }, REaCt().createElement(utils.P9, null, l.empty_call_dlg_text.replace('%s', '2'))), REaCt().createElement("div", {
      className: "notice-footer"
    }, REaCt().createElement(meetings_button.A, {
      className: "mega-button large stay-on-call",
      onClick: this.props.onStayConfirm
    }, REaCt().createElement("span", null, l.empty_call_stay_button)), REaCt().createElement(meetings_button.A, {
      className: "mega-button positive large stay-on-call",
      onClick: this.props.onCallEnd
    }, REaCt().createElement("span", null, l.empty_call_dlg_end)))));
    this.renderUserWaiting = () => {
      const {
        chatRoom,
        onInviteToggle
      } = this.props;
      return REaCt().createElement("div", {
        className: `
                    ${ParticipantsNotice.NAMESPACE}
                    ${chatRoom.isMeeting ? '' : 'user-alone'}
                    theme-dark-forced
                `
      }, REaCt().createElement("div", {
        className: `${ParticipantsNotice.NAMESPACE}-heading`
      }, chatRoom.type === 'private' ? REaCt().createElement("h1", null, REaCt().createElement(utils.zT, null, l.waiting_for_peer.replace('%NAME', chatRoom.getRoomTitle()))) : REaCt().createElement("h1", null, l.waiting_for_others)), chatRoom.isMeeting && chatRoom.publicLink && REaCt().createElement("div", {
        className: `${ParticipantsNotice.NAMESPACE}-content-invite`
      }, REaCt().createElement(inviteParticipantsPanel.Q, {
        chatRoom,
        disableLinkToggle: true,
        onAddParticipants: () => {
          this.setState({
            inviteDialog: false
          }, () => onInviteToggle());
        }
      })));
    };
    this.av = this.props.call.sfuClient.availAv;
  }
  specShouldComponentUpdate(newProps) {
    const {
      stayOnEnd,
      hasLeft,
      isOnHold,
      call
    } = this.props;
    const currAv = this.av;
    this.av = call.sfuClient.availAv;
    return newProps.stayOnEnd !== stayOnEnd || newProps.hasLeft !== hasLeft || newProps.isOnHold !== isOnHold || this.av !== currAv;
  }
  render() {
    const {
      call,
      hasLeft,
      streamContainer,
      chatRoom
    } = this.props;
    if (call.isDestroyed) {
      return null;
    }
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `${ParticipantsNotice.NAMESPACE}-container`
    }, call.isSharingScreen() ? null : REaCt().createElement(videoNode.Cn, {
      className: "local-stream-mirrored",
      chatRoom,
      source: call.getLocalStream()
    }), streamContainer(hasLeft ? this.renderUserAlone() : this.renderUserWaiting()));
  }
}
ParticipantsNotice.NAMESPACE = 'participants-notice';
// EXTERNAL MODULE: ./js/chat/ui/chatToaster.jsx
const chatToaster = REQ_(424);
;// ./js/chat/ui/meetings/participantsBlock.jsx






const MAX_STREAMS_PER_PAGE = 10;
const SIMPLE_TIP = {
  position: 'top',
  offset: 5,
  className: 'theme-dark-forced'
};
class ParticipantsBlock extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.nodeMenuRef = REaCt().createRef();
    this.dupNodeMenuRef = REaCt().createRef();
    this.state = {
      page: 0
    };
    this.movePage = direction => this.setState(state => ({
      page: direction === PAGINATION.NEXT ? state.page + 1 : state.page - 1
    }));
    this.renderLocalNode = isPresenterNode => {
      const {
        call,
        peers,
        mode,
        raisedHandPeers,
        chatRoom,
        forcedLocal,
        presenterThumbSelected,
        onSeparate,
        onSpeakerChange,
        onModeChange
      } = this.props;
      const localStream = call.getLocalStream();
      if (localStream) {
        const IS_SPEAKER_VIEW = mode === meetings_call.g.MAIN && forcedLocal;
        const VideoClass = isPresenterNode ? videoNode.Vm : videoNode.bJ;
        let isActive = false;
        if (isPresenterNode) {
          isActive = forcedLocal && !presenterThumbSelected;
        } else if (call.pinnedCid === 0 || forcedLocal) {
          if (presenterThumbSelected) {
            isActive = !isPresenterNode;
          } else if (localStream.hasScreen) {
            isActive = isPresenterNode;
          } else {
            isActive = true;
          }
        }
        return REaCt().createElement(VideoClass, {
          key: `${u_handle}${isPresenterNode ? '_block' : ''}`,
          className: `
                        local-stream-node
                        ${call.isSharingScreen() ? '' : 'local-stream-mirrored'}
                        ${isActive ? 'active' : ''}
                        ${call.speakerCid === 0 ? 'active-speaker' : ''}
                    `,
          simpletip: {
            ...SIMPLE_TIP,
            label: l[8885]
          },
          mode,
          raisedHandPeers,
          chatRoom,
          source: localStream,
          localAudioMuted: !(call.av & SfuClient.Av.Audio),
          isPresenterNode,
          onClick: (source, ev) => {
            const nodeMenuRef = isPresenterNode ? this.nodeMenuRef && this.nodeMenuRef.current : this.dupNodeMenuRef && this.dupNodeMenuRef.current;
            if (nodeMenuRef && nodeMenuRef.contains(ev.target)) {
              ev.preventDefault();
              ev.stopPropagation();
              return;
            }
            return onSpeakerChange(localStream, !isPresenterNode);
          }
        }, (peers == null ? void 0 : peers.length) && REaCt().createElement("div", {
          ref: isPresenterNode ? this.nodeMenuRef : this.dupNodeMenuRef,
          className: "node-menu theme-dark-forced"
        }, REaCt().createElement("div", {
          className: "node-menu-toggle"
        }, REaCt().createElement("i", {
          className: "sprite-fm-mono icon-more-horizontal-thin-outline"
        })), REaCt().createElement("div", {
          className: "node-menu-content"
        }, REaCt().createElement("ul", null, REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
          icon: `
                                                sprite-fm-mono
                                                ${IS_SPEAKER_VIEW ? 'grid-9' : 'grid-main'}
                                            `,
          onClick: () => {
            if (IS_SPEAKER_VIEW) {
              return onModeChange(meetings_call.g.THUMBNAIL);
            }
            return onSpeakerChange(localStream);
          }
        }, REaCt().createElement("span", null, IS_SPEAKER_VIEW ? l.switch_to_thumb_view : l.display_in_main_view))), REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
          icon: "sprite-fm-mono grid-separate",
          onClick: onSeparate
        }, REaCt().createElement("span", null, l.separate_from_grid_button)))))));
      }
      return null;
    };
    this.onScroll = (chunks, evt) => {
      const {
        page
      } = this.state;
      if (evt.deltaY < 0) {
        if (page > 0) {
          this.movePage(PAGINATION.PREV);
        }
      } else if (evt.deltaY > 0) {
        if (page < Object.values(chunks).length - 1) {
          this.movePage(PAGINATION.NEXT);
        }
      }
    };
  }
  shouldComponentUpdate() {
    const {
      peers
    } = this.props;
    return peers && peers.length;
  }
  render() {
    const {
      call,
      mode,
      peers,
      floatDetached,
      chatRoom,
      raisedHandPeers,
      presenterThumbSelected,
      onSpeakerChange
    } = this.props;
    if (peers && peers.length) {
      const {
        screen,
        video,
        rest
      } = filterAndSplitSources(peers, call);
      const sources = [...screen, ...video, ...rest];
      const $$PEER = (peer, i) => {
        const {
          clientId,
          userHandle,
          hasScreenAndCam,
          hasScreen,
          isLocal
        } = peer;
        if (screen.length && (screen[0].clientId === clientId || screen[0].isLocal && isLocal)) {
          screen.shift();
        }
        if (!(peer instanceof CallManager2.Peer)) {
          const isPresenterNode = screen.length && screen[0].isLocal;
          if (floatDetached && !isPresenterNode) {
            return;
          }
          return this.renderLocalNode(!floatDetached && isPresenterNode);
        }
        const presenterCid = screen.length && screen[0].clientId === clientId;
        let PeerClass;
        if (hasScreenAndCam) {
          PeerClass = presenterCid ? videoNode.ob : videoNode.Qs;
        } else {
          PeerClass = videoNode.au;
        }
        assert(!presenterCid || hasScreen);
        const isActiveSpeaker = !peer.audioMuted && call.speakerCid === peer.clientId;
        let isActive = false;
        if (call.pinnedCid === clientId) {
          if (presenterThumbSelected) {
            isActive = !presenterCid;
          } else if (hasScreen) {
            isActive = presenterCid;
          } else {
            isActive = true;
          }
        }
        const name = M.getNameByHandle(userHandle);
        let label = name;
        if (presenterCid) {
          label = name ? l.presenter_nail.replace('%s', name) : megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER;
        } else {
          label = name || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER;
        }
        return REaCt().createElement(PeerClass, {
          key: `${userHandle}-${i}-${clientId}`,
          className: `
                            video-crop
                            ${isActive ? 'active' : ''}
                            ${isActiveSpeaker ? 'active-speaker' : ''}
                        `,
          simpletip: {
            ...SIMPLE_TIP,
            label
          },
          raisedHandPeers,
          mode,
          chatRoom,
          source: peer,
          isPresenterNode: !!presenterCid,
          onSpeakerChange: node => onSpeakerChange(node, !presenterCid),
          onClick: node => onSpeakerChange(node, !presenterCid)
        });
      };
      if (sources.length <= (floatDetached ? MAX_STREAMS_PER_PAGE : 9)) {
        return REaCt().createElement("div", {
          ref: this.domRef,
          className: "stream-participants-block theme-dark-forced"
        }, REaCt().createElement("div", {
          className: "participants-container"
        }, REaCt().createElement("div", {
          className: `
                                    participants-grid
                                    ${floatDetached && sources.length === 1 || sources.length === 0 ? 'single-column' : ''}
                                `
        }, sources.map((p, i) => $$PEER(p, i)))));
      }
      const {
        page
      } = this.state;
      const chunks = chunkNodes(sources, MAX_STREAMS_PER_PAGE);
      return REaCt().createElement("div", {
        ref: this.domRef,
        className: "carousel"
      }, REaCt().createElement("div", {
        className: "carousel-container",
        onWheel: evt => this.onScroll(chunks, evt)
      }, REaCt().createElement("div", {
        className: "stream-participants-block theme-dark-forced"
      }, REaCt().createElement("div", {
        className: "participants-container"
      }, Object.values(chunks).map((chunk, i) => {
        const {
          id,
          nodes
        } = chunk;
        return REaCt().createElement("div", {
          key: id,
          className: `
                                                carousel-page
                                                ${i === page ? 'active' : ''}
                                            `
        }, page === 0 ? null : REaCt().createElement("button", {
          className: "carousel-control carousel-button-prev theme-dark-forced",
          onClick: () => this.movePage(PAGINATION.PREV)
        }, REaCt().createElement("i", {
          className: "sprite-fm-mono icon-arrow-up"
        })), REaCt().createElement("div", {
          className: `
                                                    participants-grid
                                                    ${nodes.length === 1 ? 'single-column' : ''}
                                                `
        }, nodes.map((peer, j) => $$PEER(peer, j + i * MAX_STREAMS_PER_PAGE))), page >= Object.values(chunks).length - 1 ? null : REaCt().createElement("button", {
          className: "carousel-control carousel-button-next theme-dark-forced",
          onClick: () => this.movePage(PAGINATION.NEXT)
        }, REaCt().createElement("i", {
          className: "sprite-fm-mono icon-arrow-down"
        })));
      })))));
    }
    return null;
  }
}
// EXTERNAL MODULE: ./js/chat/ui/meetings/videoNodeMenu.jsx
const videoNodeMenu = REQ_(539);
// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
const modalDialogs = REQ_(318);
;// ./js/chat/ui/meetings/modeSwitch.jsx





class ModeSwitch extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.state = {
      expanded: false,
      settings: false
    };
    this.handleMousedown = ({
      target
    }) => {
      if (this.state.expanded || this.state.settings) {
        let _this$domRef;
        return (_this$domRef = this.domRef) != null && (_this$domRef = _this$domRef.current) != null && _this$domRef.contains(target) ? null : this.doClose();
      }
    };
    this.handleKeydown = ({
      keyCode
    }) => keyCode && keyCode === 27 && this.doClose();
    this.doClose = () => this.isMounted() && this.setState({
      expanded: false,
      settings: false
    }, () => this.props.setActiveElement(this.state.expanded));
    this.doToggle = () => this.isMounted() && this.setState(state => ({
      expanded: !state.expanded
    }), () => this.props.setActiveElement(this.state.expanded || this.state.settings));
    this.setStreamsPerPage = streamsPerPage => {
      if (streamsPerPage) {
        let _this$props$onStreams, _this$props;
        (_this$props$onStreams = (_this$props = this.props).onStreamsPerPageChange) == null || _this$props$onStreams.call(_this$props, streamsPerPage);
        this.doClose();
      }
    };
    this.getModeIcon = mode => {
      switch (mode) {
        case meetings_call.g.THUMBNAIL:
          return 'grid-9';
        case meetings_call.g.MAIN:
          return 'grid-main';
        default:
          return null;
      }
    };
    this.Toggle = () => {
      const {
        mode
      } = this.props;
      return REaCt().createElement("div", {
        className: `${ModeSwitch.BASE_CLASS}-toggle`,
        onClick: this.doToggle
      }, REaCt().createElement(meetings_button.A, null, REaCt().createElement("i", {
        className: `sprite-fm-mono ${this.getModeIcon(mode)}`
      }), mode === meetings_call.g.THUMBNAIL && REaCt().createElement("div", null, l.thumbnail_view), mode === meetings_call.g.MAIN && REaCt().createElement("div", null, l.main_view)), REaCt().createElement("i", {
        className: "sprite-fm-mono icon-arrow-down"
      }));
    };
    this.Option = ({
      label,
      mode
    }) => {
      return REaCt().createElement("div", {
        className: `
                    ${ModeSwitch.BASE_CLASS}-option
                    ${mode === this.props.mode ? 'active' : ''}
                `,
        onClick: () => {
          this.doToggle();
          this.props.onModeChange(mode);
        }
      }, REaCt().createElement(meetings_button.A, null, REaCt().createElement("i", {
        className: `sprite-fm-mono ${this.getModeIcon(mode)}`
      }), REaCt().createElement("div", null, label)));
    };
    this.Settings = () => {
      const {
        streamsPerPage
      } = this.props;
      return REaCt().createElement("div", {
        className: `${ModeSwitch.BASE_CLASS}-settings`
      }, REaCt().createElement("div", {
        className: "settings-wrapper"
      }, REaCt().createElement("strong", null, l.layout_settings_heading), REaCt().createElement("span", null, l.layout_settings_info), REaCt().createElement("div", {
        className: "recurring-radio-buttons"
      }, REaCt().createElement("div", {
        className: "recurring-label-wrap"
      }, REaCt().createElement("div", {
        className: `
                                    uiTheme
                                    ${streamsPerPage === STREAMS_PER_PAGE.MIN ? 'radioOn' : 'radioOff'}
                                `
      }, REaCt().createElement("input", {
        type: "radio",
        name: "9",
        onClick: () => this.setStreamsPerPage(STREAMS_PER_PAGE.MIN)
      })), REaCt().createElement("div", {
        className: "radio-txt"
      }, REaCt().createElement("span", {
        className: "recurring-radio-label",
        onClick: () => this.setStreamsPerPage(STREAMS_PER_PAGE.MIN)
      }, "9"))), REaCt().createElement("div", {
        className: "recurring-label-wrap"
      }, REaCt().createElement("div", {
        className: `
                                    uiTheme
                                    ${streamsPerPage === STREAMS_PER_PAGE.MED ? 'radioOn' : 'radioOff'}
                                `
      }, REaCt().createElement("input", {
        type: "radio",
        name: "21",
        onClick: () => {
          this.setStreamsPerPage(STREAMS_PER_PAGE.MED);
        }
      })), REaCt().createElement("div", {
        className: "radio-txt"
      }, REaCt().createElement("span", {
        className: "recurring-radio-label",
        onClick: () => this.setStreamsPerPage(STREAMS_PER_PAGE.MED)
      }, "21"))), REaCt().createElement("div", {
        className: "recurring-label-wrap"
      }, REaCt().createElement("div", {
        className: `
                                    uiTheme
                                    ${streamsPerPage === STREAMS_PER_PAGE.MAX ? 'radioOn' : 'radioOff'}
                                `
      }, REaCt().createElement("input", {
        type: "radio",
        name: "49",
        onClick: () => {
          this.setStreamsPerPage(STREAMS_PER_PAGE.MAX);
        }
      })), REaCt().createElement("div", {
        className: "radio-txt"
      }, REaCt().createElement("span", {
        className: "recurring-radio-label",
        onClick: () => this.setStreamsPerPage(STREAMS_PER_PAGE.MAX)
      }, "49")))), REaCt().createElement("small", null, l.layout_settings_warning)), REaCt().createElement("div", {
        className: "settings-close"
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-dialog-close",
        onClick: this.doClose
      })));
    };
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    document.removeEventListener('mousedown', this.handleMousedown);
    document.removeEventListener('keydown', this.handleKeydown);
  }
  componentDidMount() {
    super.componentDidMount();
    document.addEventListener('mousedown', this.handleMousedown);
    document.addEventListener('keydown', this.handleKeydown);
  }
  render() {
    const {
      Toggle,
      Option,
      Settings,
      domRef,
      state,
      doToggle
    } = this;
    return REaCt().createElement("div", {
      ref: domRef,
      className: ModeSwitch.BASE_CLASS
    }, REaCt().createElement(Toggle, null), REaCt().createElement("div", {
      className: `
                        ${ModeSwitch.BASE_CLASS}-menu
                        ${state.expanded ? 'expanded' : ''}
                    `
    }, REaCt().createElement(Option, {
      label: l.main_view,
      mode: meetings_call.g.MAIN
    }), REaCt().createElement(Option, {
      label: l.thumbnail_view,
      mode: meetings_call.g.THUMBNAIL
    }), REaCt().createElement("div", {
      className: `${ModeSwitch.BASE_CLASS}-option`,
      onClick: () => this.setState({
        settings: true
      }, doToggle)
    }, REaCt().createElement(meetings_button.A, null, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-settings"
    }), REaCt().createElement("div", null, l.layout_settings_button)))), state.settings && REaCt().createElement(Settings, null));
  }
}
ModeSwitch.NAMESPACE = 'modeSwitch';
ModeSwitch.BASE_CLASS = 'mode';
;// ./js/chat/ui/meetings/streamHead.jsx









class StreamHead extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.delayProcID = null;
    this.domRef = REaCt().createRef();
    this.durationRef = REaCt().createRef();
    this.dialogRef = REaCt().createRef();
    this.topicRef = REaCt().createRef();
    this.interval = undefined;
    this.state = {
      dialog: false,
      duration: undefined,
      banner: false,
      modeSwitch: false
    };
    this.updateDurationDOM = () => {
      if (this.durationRef) {
        this.durationRef.current.innerText = this.durationString;
      }
    };
    this.closeTooltips = () => {
      for (const node of this.domRef.current.querySelectorAll('.simpletip')) {
        node.dispatchEvent(StreamHead.EVENTS.SIMPLETIP);
      }
    };
    this.toggleFullscreen = () => this.fullscreen ? document.exitFullscreen() : document.documentElement.requestFullscreen();
    this.toggleBanner = callback => this.setState(state => ({
      banner: !state.banner
    }), () => callback && callback());
    this.handleDialogClose = ({
      target
    }) => {
      if (this.state.dialog) {
        let _targetDialog$domRef;
        const {
          topicRef,
          dialogRef,
          delayProcID
        } = this;
        const topicElement = topicRef && topicRef.current;
        const targetDialog = dialogRef && dialogRef.current && dialogRef.current;
        const dialogElement = (_targetDialog$domRef = targetDialog.domRef) == null ? void 0 : _targetDialog$domRef.current;
        if (topicElement.contains(target)) {
          return;
        }
        return (target.classList.contains('icon-dialog-close') || !dialogElement.contains(target)) && this.setState({
          dialog: false
        }, () => delayProcID && delay.cancel(delayProcID));
      }
    };
    this.getModerators = () => {
      let _this$props$chatRoom;
      const members = (_this$props$chatRoom = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom.members;
      if (members) {
        const moderators = [];
        for (const [handle, role] of Object.entries(members)) {
          if (role === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR) {
            moderators.push(M.getNameByHandle(handle));
          }
        }
        return mega.utils.trans.listToString(moderators, mega.icu.format(l.meeting_moderators, moderators.length));
      }
    };
    this.Dialog = () => {
      const link = `${getBaseUrl()}/${this.props.chatRoom.publicLink}`;
      const mods = this.getModerators();
      return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({
        ref: this.dialogRef
      }, this.state, {
        mods,
        name: "meeting-info-dialog",
        title: l[18132],
        className: "group-chat-link dialog-template-main theme-dark-forced in-call-info",
        hideOverlay: true
      }), REaCt().createElement("section", {
        className: "content"
      }, REaCt().createElement("div", {
        className: "content-block"
      }, REaCt().createElement(utils.zT, {
        className: "info"
      }, mods), REaCt().createElement("div", {
        className: "info"
      }, l.copy_and_share), REaCt().createElement("div", {
        className: "link-input-container"
      }, REaCt().createElement("div", {
        className: "mega-input with-icon box-style"
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-link"
      }), REaCt().createElement("input", {
        type: "text",
        className: "megaInputs",
        readOnly: true,
        value: link
      })), REaCt().createElement(meetings_button.A, {
        className: "mega-button positive copy-to-clipboard",
        onClick: () => {
          if (copyToClipboard(link)) {
            this.toggleBanner(() => {
              this.delayProcID = delay(`${StreamHead.NAMESPACE}-banner`, this.toggleBanner, 10000);
            });
          }
        }
      }, REaCt().createElement("span", null, l[63]))), this.state.banner && REaCt().createElement("div", {
        className: "banner-copy-success"
      }, l[7654]))), REaCt().createElement("footer", null, REaCt().createElement("div", {
        className: "footer-container"
      })));
    };
    this.Pagination = () => {
      const {
        mode,
        peers,
        page,
        streamsPerPage,
        floatDetached,
        chunksLength,
        call,
        onMovePage
      } = this.props;
      if (mode !== meetings_call.g.THUMBNAIL || !peers) {
        return null;
      }
      const {
        screen,
        video,
        rest
      } = filterAndSplitSources(peers, call);
      if (screen.length + video.length + rest.length > (floatDetached ? streamsPerPage + 1 : streamsPerPage)) {
        return REaCt().createElement("div", {
          className: `${StreamHead.NAMESPACE}-pagination`
        }, REaCt().createElement(meetings_button.A, {
          className: `
                            carousel-button-prev
                            theme-dark-forced
                            ${page !== 0 ? '' : 'disabled'}
                        `,
          icon: "sprite-fm-mono icon-arrow-left",
          onClick: () => page !== 0 && onMovePage(PAGINATION.PREV)
        }), REaCt().createElement("div", null, page + 1, "/", chunksLength), REaCt().createElement(meetings_button.A, {
          className: `
                            carousel-button-next
                            theme-dark-forced
                            ${page < chunksLength - 1 ? '' : 'disabled'}
                        `,
          icon: "sprite-fm-mono icon-arrow-right",
          onClick: () => page < chunksLength - 1 && onMovePage(PAGINATION.NEXT)
        }));
      }
      return null;
    };
  }
  get fullscreen() {
    return document.fullscreenElement;
  }
  get duration() {
    return (Date.now() - this.props.call.ts) / 1000;
  }
  get durationString() {
    return this.duration ? secondsToTimeShort(this.duration) : '--:--:--';
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    clearInterval(this.durationInterval);
    document.removeEventListener(StreamHead.EVENTS.FULLSCREEN, this.closeTooltips);
    document.removeEventListener(StreamHead.EVENTS.CLICK_DIALOG, this.handleDialogClose);
  }
  componentDidMount() {
    super.componentDidMount();
    this.durationInterval = setInterval(this.updateDurationDOM, 1000);
    document.addEventListener(StreamHead.EVENTS.FULLSCREEN, this.closeTooltips);
    document.addEventListener(StreamHead.EVENTS.CLICK_DIALOG, this.handleDialogClose);
  }
  render() {
    const {
      NAMESPACE
    } = StreamHead;
    const {
      mode,
      streamsPerPage,
      chatRoom,
      onStreamsPerPageChange,
      onCallMinimize,
      onModeChange,
      setActiveElement
    } = this.props;
    const {
      dialog
    } = this.state;
    const SIMPLETIP = {
      position: 'bottom',
      offset: 5,
      className: 'theme-dark-forced'
    };
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `${NAMESPACE}`
    }, dialog && REaCt().createElement(this.Dialog, null), REaCt().createElement("div", {
      className: `${NAMESPACE}-content theme-dark-forced`
    }, REaCt().createElement("div", {
      className: `${NAMESPACE}-info`
    }, REaCt().createElement("div", {
      ref: this.durationRef,
      className: "stream-duration"
    }, this.durationString), REaCt().createElement("div", {
      ref: this.topicRef,
      className: `
                                stream-topic
                                ${chatRoom.isMeeting && chatRoom.publicLink ? 'has-meeting-link' : ''}
                            `,
      onClick: () => chatRoom.isMeeting && chatRoom.publicLink && this.setState({
        dialog: !dialog,
        banner: false
      }, () => setActiveElement(this.state.dialog))
    }, REaCt().createElement(utils.zT, null, chatRoom.getRoomTitle()), chatRoom.isMeeting && chatRoom.publicLink && REaCt().createElement("i", {
      className: `
                                        sprite-fm-mono
                                        ${dialog ? 'icon-arrow-up' : 'icon-arrow-down'}
                                    `
    }))), REaCt().createElement(this.Pagination, null), REaCt().createElement("div", {
      className: `${NAMESPACE}-controls`
    }, REaCt().createElement(ModeSwitch, {
      mode,
      streamsPerPage,
      onStreamsPerPageChange,
      onModeChange,
      setActiveElement
    }), REaCt().createElement(meetings_button.A, {
      className: "head-control",
      simpletip: {
        ...SIMPLETIP,
        label: this.fullscreen ? l.exit_fullscreen : l[17803]
      },
      icon: this.fullscreen ? 'icon-fullscreen-leave' : 'icon-fullscreen-enter',
      onClick: this.toggleFullscreen
    }, REaCt().createElement("span", null, this.fullscreen ? l.exit_fullscreen : l[17803])), REaCt().createElement(meetings_button.A, {
      className: "head-control",
      simpletip: {
        ...SIMPLETIP,
        label: l.minimize
      },
      icon: "icon-call-min-mode",
      onClick: () => {
        onCallMinimize();
        eventlog(500305);
      }
    }, REaCt().createElement("div", null, l.minimize)))));
  }
}
StreamHead.NAMESPACE = 'stream-head';
StreamHead.EVENTS = {
  FULLSCREEN: 'fullscreenchange',
  SIMPLETIP: new Event('simpletipClose'),
  CLICK_DIALOG: 'click'
};
// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
const contacts = REQ_(251);
// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
const perfectScrollbar = REQ_(486);
// EXTERNAL MODULE: ./js/chat/ui/link.jsx
const ui_link = REQ_(280);
;// ./js/chat/ui/meetings/waitingRoom/admit.jsx







const NAMESPACE = 'admit';
class Admit extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.peersWaitingRef = REaCt().createRef();
    this.state = {
      expanded: false
    };
    this.doAdmit = peers => {
      let _this$props$call;
      return (_this$props$call = this.props.call) == null || (_this$props$call = _this$props$call.sfuClient) == null ? void 0 : _this$props$call.wrAllowJoin([peers]);
    };
    this.doDeny = peers => {
      let _this$props$call2;
      return (_this$props$call2 = this.props.call) == null || (_this$props$call2 = _this$props$call2.sfuClient) == null ? void 0 : _this$props$call2.wrKickOut([peers]);
    };
    this.Icon = ({
      icon,
      label,
      onClick
    }) => REaCt().createElement("i", {
      className: `
                sprite-fm-mono
                simpletip
                ${icon}
            `,
      "data-simpletip": label,
      "data-simpletipposition": "top",
      "data-simpletipoffset": "5",
      "data-simpletip-class": "theme-dark-forced",
      onClick
    });
    this.CallLimitBanner = ({
      call
    }) => REaCt().createElement("div", {
      className: `${NAMESPACE}-user-limit-banner`
    }, call.organiser === u_handle ? (0,utils.lI)(l.admit_limit_banner_organiser, '[A]', ui_link.A, {
      onClick() {
        window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
        eventlog(500259);
      }
    }) : l.admit_limit_banner_host);
    this.renderPeersList = () => {
      const {
        peers,
        call,
        chatRoom
      } = this.props;
      const disableAdding = call.sfuClient.callLimits && call.sfuClient.callLimits.usr && chatRoom.getCallParticipants().length >= call.sfuClient.callLimits.usr;
      return REaCt().createElement(perfectScrollbar.O, {
        ref: this.peersWaitingRef,
        options: {
          'suppressScrollX': true
        }
      }, REaCt().createElement("div", {
        className: "peers-waiting"
      }, this.isUserLimited && REaCt().createElement(this.CallLimitBanner, {
        call
      }), peers.map(handle => {
        return REaCt().createElement("div", {
          key: handle,
          className: "peers-waiting-card"
        }, REaCt().createElement("div", {
          className: "peer-avatar"
        }, REaCt().createElement(contacts.Avatar, {
          contact: M.u[handle]
        })), REaCt().createElement("div", {
          className: "peer-name"
        }, REaCt().createElement(contacts.ContactAwareName, {
          contact: M.u[handle],
          emoji: true
        })), REaCt().createElement("div", {
          className: "peer-controls"
        }, REaCt().createElement(this.Icon, {
          icon: "icon-close-component",
          label: l.wr_deny,
          onClick: () => this.doDeny(handle)
        }), REaCt().createElement(this.Icon, {
          icon: `icon-check ${disableAdding ? 'disabled' : ''}`,
          label: l.wr_admit,
          onClick: () => !disableAdding && this.doAdmit(handle)
        })));
      })));
    };
    this.renderMultiplePeersWaiting = () => {
      const {
        call,
        peers,
        expanded,
        onWrListToggle
      } = this.props;
      if (peers && peers.length) {
        const disableAddAll = this.isUserLimited;
        return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
          className: `${NAMESPACE}-head`
        }, REaCt().createElement("h3", null, mega.icu.format(l.wr_peers_waiting, peers.length)), expanded ? REaCt().createElement(this.Icon, {
          icon: "icon-arrow-up",
          onClick: () => onWrListToggle(false)
        }) : null), !expanded && disableAddAll && REaCt().createElement(this.CallLimitBanner, {
          call
        }), expanded && REaCt().createElement("div", {
          className: `${NAMESPACE}-content`
        }, this.renderPeersList()), REaCt().createElement("div", {
          className: `${NAMESPACE}-controls`
        }, expanded ? null : REaCt().createElement(meetings_button.A, {
          className: "mega-button theme-dark-forced",
          onClick: () => onWrListToggle(true)
        }, REaCt().createElement("span", null, l.wr_see_waiting)), REaCt().createElement(meetings_button.A, {
          peers,
          className: `mega-button positive theme-dark-forced ${disableAddAll ? 'disabled' : ''}`,
          onClick: () => !disableAddAll && call.sfuClient.wrAllowJoin(peers)
        }, REaCt().createElement("span", null, l.wr_admit_all))));
      }
      return null;
    };
    this.renderSinglePeerWaiting = () => {
      const {
        peers,
        call
      } = this.props;
      const peer = peers[0];
      const disableAdding = this.isUserLimited;
      if (peer) {
        return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(utils.P9, {
          tag: "h3",
          content: l.wr_peer_waiting.replace('%s', megaChat.html(M.getNameByHandle(peer)))
        }), disableAdding && REaCt().createElement(this.CallLimitBanner, {
          call
        }), REaCt().createElement("div", {
          className: `${NAMESPACE}-controls`
        }, REaCt().createElement(meetings_button.A, {
          className: "mega-button theme-dark-forced",
          onClick: () => this.doDeny(peer)
        }, REaCt().createElement("span", null, l.wr_deny)), REaCt().createElement(meetings_button.A, {
          className: `mega-button positive theme-dark-forced ${disableAdding ? 'disabled' : ''}`,
          onClick: () => !disableAdding && this.doAdmit(peer)
        }, REaCt().createElement("span", null, l.wr_admit))));
      }
      return null;
    };
  }
  get isUserLimited() {
    const {
      call,
      chatRoom,
      peers
    } = this.props;
    return call.sfuClient.callLimits && call.sfuClient.callLimits.usr && chatRoom.getCallParticipants().length + (peers ? peers.length : 0) > call.sfuClient.callLimits.usr;
  }
  render() {
    const {
      chatRoom,
      peers
    } = this.props;
    if (chatRoom.iAmOperator()) {
      return REaCt().createElement("div", {
        ref: this.domRef,
        className: `
                        ${NAMESPACE}
                        theme-dark-forced
                    `
      }, REaCt().createElement("div", {
        className: `${NAMESPACE}-wrapper`
      }, peers && peers.length > 1 ? this.renderMultiplePeersWaiting() : this.renderSinglePeerWaiting()));
    }
    return null;
  }
}
;// ./js/chat/ui/meetings/stream.jsx













const stream_NAMESPACE = 'stream';
const STREAM_ACTIONS = {
  ADD: 1,
  REMOVE: 2
};
const PAGINATION = {
  PREV: -1,
  NEXT: 1
};
const MAX_STREAMS = 99;
const STREAMS_PER_PAGE = {
  MIN: 9,
  MED: 21,
  MAX: 49
};
const chunkNodes = (nodes, size) => {
  if (nodes && nodes.length && size) {
    const chunked = [];
    let index = 0;
    while (index < nodes.length) {
      chunked.push({
        id: index,
        nodes: nodes.slice(index, index + size)
      });
      index += size;
    }
    return chunked;
  }
  return null;
};
const filterAndSplitSources = (sources, call) => {
  const screen = [];
  const video = [];
  const rest = [];
  for (const peer of Object.values(sources.toJS())) {
    if (peer instanceof CallManager2.Peer) {
      if (peer.hasScreen) {
        screen.push(peer, peer);
      } else if (peer.videoMuted) {
        rest.push(peer);
      } else {
        video.push(peer);
      }
    }
  }
  const local = call.getLocalStream();
  if (local.hasScreen) {
    const presenters = [...call.presenterStreams];
    if (presenters.pop() === u_handle) {
      screen.unshift(local, local);
    } else {
      screen.push(local, local);
    }
  } else if (local.av & Av.Camera) {
    video.unshift(local);
  } else {
    rest.push(local);
  }
  return {
    screen,
    video,
    rest
  };
};
class stream_Stream extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.containerRef = REaCt().createRef();
    this.nodeRefs = [];
    this.chunks = [];
    this.chunksLength = 0;
    this.lastRescaledCache = undefined;
    this.state = {
      page: 0,
      overlayed: false,
      streamsPerPage: STREAMS_PER_PAGE.MED,
      floatDetached: false,
      wrToggled: false
    };
    this.toggleFloatDetachment = () => {
      this.setState(state => ({
        floatDetached: !state.floatDetached
      }));
    };
    this.toggleWaitingRoomList = state => {
      this.setState({
        wrToggled: state
      });
    };
  }
  movePage(direction) {
    return this.setState(state => ({
      page: direction === PAGINATION.NEXT ? state.page + 1 : state.page - 1
    }));
  }
  getColumns(streamsCount) {
    switch (true) {
      case streamsCount >= 43:
        return 7;
      case streamsCount >= 26:
        return 6;
      case streamsCount >= 17:
        return 5;
      case streamsCount >= 13:
        return 4;
      case streamsCount === 1:
        return 1;
      case streamsCount >= 7:
        return 3;
      default:
        return 2;
    }
  }
  scaleNodes(columns, forced = false) {
    let _Object$values$page;
    const {
      peers,
      minimized,
      mode,
      call
    } = this.props;
    const {
      screen,
      video,
      rest
    } = filterAndSplitSources(peers, call);
    let presenter = false;
    const sources = [...screen, ...video, ...rest].filter(source => {
      if (!source.isLocal) {
        return true;
      }
      if (source.hasScreen && !presenter) {
        presenter = true;
        return true;
      }
      return false;
    });
    presenter = false;
    const container = this.containerRef.current;
    this.lastRescaledCache = forced ? null : this.lastRescaledCache;
    if (minimized || !container) {
      return;
    }
    const {
      floatDetached,
      streamsPerPage,
      page
    } = this.state;
    const parentRef = container.parentNode;
    const parentStyle = getComputedStyle(parentRef);
    const extraVerticalMargin = parseInt(parentStyle.paddingTop) + parseInt(parentStyle.paddingBottom);
    let containerWidth = parentRef.offsetWidth;
    let containerHeight = parentRef.offsetHeight - extraVerticalMargin;
    const nodesPerPage = floatDetached ? streamsPerPage : streamsPerPage - 1;
    const streamsInUI = sources.length > nodesPerPage ? (_Object$values$page = Object.values(this.chunks)[page]) == null ? void 0 : _Object$values$page.nodes : sources;
    if (streamsInUI) {
      const streamCountInUI = sources.length > nodesPerPage || floatDetached ? streamsInUI.length : streamsInUI.length + 1;
      let rows;
      if (mode === meetings_call.g.THUMBNAIL) {
        columns = typeof columns === 'number' ? columns : this.getColumns(streamCountInUI);
        rows = Math.ceil(streamCountInUI / columns);
      } else {
        rows = 1;
        columns = 1;
      }
      containerWidth -= columns * 6 * 2;
      containerHeight -= rows * 6 * 2;
      let targetWidth = Math.floor(containerWidth / columns);
      let targetHeight = targetWidth / 16 * 9;
      if (targetHeight * rows > containerHeight) {
        targetHeight = Math.floor(containerHeight / rows);
        targetWidth = targetHeight / 9 * 16;
      }
      const nodeRefs = this.nodeRefs.flat();
      const nodeRefsLength = nodeRefs.length;
      const viewMode = mode || meetings_call.g.MAIN;
      let cache = `${viewMode}:${targetWidth}:${targetHeight}:${nodeRefsLength}:${rows}:${streamCountInUI}:${columns}`;
      for (let i = 0; i < nodeRefsLength; i++) {
        cache += `${nodeRefs[i].cacheKey}:`;
      }
      if (this.lastRescaledCache === cache) {
        return;
      }
      this.lastRescaledCache = cache;
      for (let i = 0; i < nodeRefsLength; i++) {
        const node = nodeRefs[i];
        if (node && node.ref) {
          node.ref.style.width = `${targetWidth}px`;
          node.ref.style.height = `${targetHeight}px`;
        }
      }
      container.style.width = `${(targetWidth + 12) * columns}px`;
    }
  }
  renderNodes() {
    const {
      mode,
      peers,
      call,
      raisedHandPeers,
      chatRoom,
      onVideoDoubleClick,
      onModeChange
    } = this.props;
    const {
      page,
      streamsPerPage,
      floatDetached
    } = this.state;
    const {
      screen,
      video,
      rest
    } = filterAndSplitSources(peers, call);
    const sources = [...screen, ...video, ...rest];
    if (mode === meetings_call.g.THUMBNAIL) {
      const nodesPerPage = floatDetached ? streamsPerPage : streamsPerPage - 1;
      if (sources.length <= nodesPerPage) {
        const $$PEER = (peer, i) => {
          const {
            clientId,
            hasScreenAndCam,
            hasScreen,
            isLocal
          } = peer;
          if (screen.length && (screen[0].clientId === clientId || screen[0].isLocal && isLocal)) {
            screen.shift();
          }
          if (!(peer instanceof CallManager2.Peer)) {
            const isPresenterNode = screen.length && screen[0].isLocal;
            if (floatDetached && !isPresenterNode) {
              return;
            }
            if (floatDetached || !isPresenterNode) {
              return REaCt().createElement(videoNode.bJ, {
                key: `${mode}_thumb_${u_handle}`,
                chatRoom,
                isPresenterNode: false,
                raisedHandPeers,
                source: peer,
                didMount: ref => {
                  this.nodeRefs.push({
                    clientId: u_handle,
                    cacheKey: `${mode}_${u_handle}_thumb`,
                    ref
                  });
                  this.scaleNodes(undefined, true);
                },
                willUnmount: () => {
                  this.nodeRefs = this.nodeRefs.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}_thumb`);
                }
              }, this.renderSelfViewMenu());
            }
            return REaCt().createElement(videoNode.Cn, {
              key: `${mode}_${u_handle}`,
              chatRoom,
              isPresenterNode,
              source: isPresenterNode && peer,
              raisedHandPeers,
              didMount: ref => {
                this.nodeRefs.push({
                  clientId: u_handle,
                  cacheKey: `${mode}_${u_handle}`,
                  ref
                });
                this.scaleNodes(undefined, true);
              },
              willUnmount: () => {
                this.nodeRefs = this.nodeRefs.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}`);
              }
            }, hasScreen ? this.renderNodeMenu(peer, {
              isPresenterNode
            }) : this.renderSelfViewMenu());
          }
          const presenterCid = screen.length && screen[0].clientId === clientId;
          let PeerClass = videoNode.au;
          if (hasScreenAndCam) {
            PeerClass = presenterCid ? videoNode.zu : videoNode.Qs;
          }
          const cacheKey = `${mode}_${clientId}_${i}_${hasScreenAndCam ? 1 : 0}`;
          return REaCt().createElement(PeerClass, {
            key: cacheKey,
            mode,
            chatRoom,
            menu: true,
            source: peer,
            raisedHandPeers,
            isPresenterNode: !!presenterCid,
            onDoubleClick: (peer, e) => {
              e.preventDefault();
              e.stopPropagation();
              onVideoDoubleClick(peer, !presenterCid);
            },
            didMount: ref => {
              this.nodeRefs.push({
                clientId: presenterCid || clientId,
                cacheKey,
                ref
              });
            },
            willUnmount: () => {
              this.nodeRefs = this.nodeRefs.filter(nodeRef => nodeRef.cacheKey !== cacheKey);
            }
          }, this.renderNodeMenu(peer, {
            isPresenterNode: !!presenterCid
          }));
        };
        return sources.map((p, i) => $$PEER(p, i));
      }
      if (floatDetached) {
        for (let i = 0; i < sources.length; i++) {
          if (sources[i].isLocal) {
            sources.splice(i, 1);
            break;
          }
        }
      }
      this.chunks = chunkNodes(sources, streamsPerPage);
      this.chunksLength = Object.values(this.chunks).length;
      return REaCt().createElement("div", {
        className: "carousel"
      }, REaCt().createElement("div", {
        className: "carousel-container"
      }, Object.values(this.chunks).map((chunk, i) => {
        const {
          id,
          nodes
        } = chunk;
        return REaCt().createElement("div", {
          key: id,
          className: `
                                        carousel-page
                                        ${i === page ? 'active' : ''}
                                    `
        }, nodes.map((peer, j) => {
          const {
            clientId,
            hasScreenAndCam,
            hasScreen,
            isLocal
          } = peer;
          if (screen.length && (screen[0].clientId === clientId || screen[0].isLocal && isLocal)) {
            screen.shift();
          }
          if (peer instanceof CallManager2.Peer) {
            const presenterCid = screen.length && screen[0].clientId === clientId;
            const cacheKey = `${mode}_${clientId}_${j + i * streamsPerPage}_${hasScreenAndCam ? 1 : 0}`;
            let PeerClass = videoNode.au;
            if (hasScreenAndCam) {
              PeerClass = presenterCid ? videoNode.zu : videoNode.Qs;
            }
            return REaCt().createElement(PeerClass, {
              key: cacheKey,
              mode,
              source: peer,
              chatRoom,
              isPresenterNode: !!presenterCid,
              raisedHandPeers,
              onDoubleClick: (peer, e) => {
                e.preventDefault();
                e.stopPropagation();
                onVideoDoubleClick(peer);
              },
              didMount: ref => {
                if (!this.nodeRefs[id]) {
                  this.nodeRefs[id] = [];
                }
                this.nodeRefs[id].push({
                  clientId: presenterCid || clientId,
                  ref,
                  cacheKey
                });
                this.scaleNodes(undefined, true);
              },
              willUnmount: () => {
                this.nodeRefs = this.nodeRefs.map(chunk => chunk.filter(nodeRef => nodeRef.cacheKey !== cacheKey));
              }
            }, this.renderNodeMenu(peer, {
              isPresenterNode: !!presenterCid
            }));
          }
          const isPresenterNode = screen.length && screen[0].isLocal;
          if (floatDetached && !isPresenterNode) {
            return null;
          }
          if (floatDetached || !isPresenterNode) {
            return REaCt().createElement(videoNode.bJ, {
              key: `${mode}_thumb_${u_handle}`,
              chatRoom,
              source: peer,
              isPresenterNode: false,
              didMount: ref => {
                if (!this.nodeRefs[id]) {
                  this.nodeRefs[id] = [];
                }
                this.nodeRefs[id].push({
                  clientId: u_handle,
                  cacheKey: `${mode}_${u_handle}_thumb`,
                  ref
                });
                this.scaleNodes(undefined, true);
              },
              willUnmount: () => {
                this.nodeRefs = this.nodeRefs.map(chunk => chunk.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}_thumb`));
              }
            }, this.renderSelfViewMenu());
          }
          return REaCt().createElement(videoNode.Cn, {
            key: `${mode}_${u_handle}`,
            chatRoom,
            raisedHandPeers,
            isPresenterNode,
            source: isPresenterNode && peer,
            didMount: ref => {
              if (!this.nodeRefs[id]) {
                this.nodeRefs[id] = [];
              }
              this.nodeRefs[id].push({
                clientId: u_handle,
                ref,
                cacheKey: `${mode}_${u_handle}`
              });
              this.scaleNodes(undefined, true);
            },
            willUnmount: () => {
              this.nodeRefs = this.nodeRefs.map(chunk => chunk.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}`));
            }
          }, hasScreen ? this.renderNodeMenu(peer, {
            isPresenterNode
          }) : this.renderSelfViewMenu());
        }));
      })));
    }
    const source = call.getActiveStream();
    if (!source) {
      return null;
    }
    const VideoType = source.isLocal ? videoNode.Cn : videoNode.zu;
    const videoNodeRef = REaCt().createRef();
    return REaCt().createElement(VideoType, {
      key: source.clientId,
      chatRoom,
      raisedHandPeers,
      source,
      isPresenterNode: source.hasScreen,
      toggleFullScreen: () => {
        call.setPinnedCid(source.clientId);
      },
      onSpeakerChange: () => {
        onModeChange(meetings_call.g.THUMBNAIL);
      },
      ref: node => {
        videoNodeRef.current = node;
      }
    }, this.renderNodeMenu(source, {
      key: `${source.clientId}-main`,
      isMain: true,
      videoNodeRef,
      isPresenterNode: source.hasScreen
    }));
  }
  renderNodeMenu(peer, props) {
    const {
      mode,
      chatRoom,
      ephemeralAccounts,
      onCallMinimize,
      onSpeakerChange,
      onModeChange
    } = this.props;
    return REaCt().createElement(videoNodeMenu.Ay, (0,esm_extends.A)({
      mode,
      privilege: chatRoom.members[peer.userHandle],
      chatRoom,
      stream: peer,
      ephemeralAccounts,
      onCallMinimize,
      onSpeakerChange,
      onModeChange
    }, props));
  }
  renderSelfViewMenu() {
    const {
      call,
      onSpeakerChange
    } = this.props;
    return REaCt().createElement("div", {
      className: "node-menu theme-dark-forced"
    }, REaCt().createElement("div", {
      className: "node-menu-toggle"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-more-horizontal-thin-outline"
    })), REaCt().createElement("div", {
      className: "node-menu-content"
    }, REaCt().createElement("ul", null, REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
      icon: "sprite-fm-mono grid-main",
      onClick: () => onSpeakerChange(call.getLocalStream())
    }, REaCt().createElement("span", null, l.display_in_main_view))), REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
      icon: "sprite-fm-mono grid-separate",
      onClick: this.toggleFloatDetachment
    }, REaCt().createElement("span", null, l.separate_from_grid_button))))));
  }
  renderOnHold() {
    return REaCt().createElement("div", {
      className: "on-hold-overlay"
    }, REaCt().createElement("div", {
      className: "stream-on-hold theme-light-forced",
      onClick: this.props.onHoldClick
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-play"
    }), REaCt().createElement("span", null, l[23459])));
  }
  renderStreamContainer() {
    const {
      call,
      chatRoom,
      peers,
      stayOnEnd,
      everHadPeers,
      isOnHold,
      mode,
      hasOtherParticipants,
      onInviteToggle,
      onStayConfirm,
      onCallEnd
    } = this.props;
    const {
      screen,
      video,
      rest
    } = filterAndSplitSources(peers, call);
    const sources = [...screen, ...video, ...rest];
    const showNotice = sources.length === 0 || !hasOtherParticipants && !call.presenterStreams.has(u_handle);
    const streamContainer = content => REaCt().createElement("div", {
      ref: this.containerRef,
      className: `
                    ${stream_NAMESPACE}-container
                    ${showNotice ? 'with-notice' : ''}
                    ${sources.length === 1 && mode === meetings_call.g.THUMBNAIL ? `${this.state.floatDetached ? 'single' : 'dual'}-stream` : ''}
                `
    }, content);
    if (showNotice) {
      return REaCt().createElement(ParticipantsNotice, {
        call,
        hasLeft: call.left,
        chatRoom,
        everHadPeers,
        streamContainer,
        stayOnEnd,
        isOnHold,
        onInviteToggle,
        onStayConfirm,
        onCallEnd: () => onCallEnd(1)
      });
    }
    return streamContainer(this.renderNodes());
  }
  renderToaster() {
    return REaCt().createElement(chatToaster.A, {
      showDualNotifications: true,
      hidden: this.props.minimized,
      onShownToast: toast => {
        if (toast.options && toast.options.persistent) {
          this.setState({
            overlayed: true
          });
        }
      },
      onHideToast: toast => {
        if (this.state.overlayed && toast.options && toast.options.persistent) {
          this.setState({
            overlayed: false
          });
        }
      }
    });
  }
  specShouldComponentUpdate(nextProps) {
    if (nextProps.minimized !== this.props.minimized || nextProps.mode !== this.props.mode || nextProps.isFloatingPresenter !== this.props.isFloatingPresenter) {
      return true;
    }
    return null;
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    chatGlobalEventManager.removeEventListener('resize', this.getUniqueId());
    mBroadcaster.removeListener(this.callHoldListener);
  }
  componentDidMount() {
    super.componentDidMount();
    this.scaleNodes();
    chatGlobalEventManager.addEventListener('resize', this.getUniqueId(), () => this.scaleNodes());
    this.callHoldListener = mBroadcaster.addListener('meetings:toggleHold', () => this.scaleNodes(undefined, true));
  }
  componentDidUpdate() {
    super.componentDidMount();
    const {
      call,
      mode,
      forcedLocal,
      onSpeakerChange,
      onModeChange
    } = this.props;
    this.scaleNodes();
    if (this.chunksLength > 0 && this.state.page + 1 > this.chunksLength) {
      this.movePage(PAGINATION.PREV);
    }
    if (mode === meetings_call.g.THUMBNAIL && call.pinnedCid !== null) {
      this.hasPresenter = true;
      onSpeakerChange(call.getActiveStream());
    } else if (mode === meetings_call.g.MAIN && call.pinnedCid === null && !call.presenterStreams.size && this.hasPresenter) {
      this.hasPresenter = false;
      onModeChange(meetings_call.g.THUMBNAIL);
    } else if (mode === meetings_call.g.MAIN && forcedLocal && call.pinnedCid !== 0) {
      onSpeakerChange(call.getActiveStream());
    } else if (!call.presenterStreams.size) {
      this.hasPresenter = false;
    }
  }
  render() {
    const {
      overlayed,
      page,
      streamsPerPage,
      floatDetached,
      wrToggled
    } = this.state;
    const {
      mode,
      call,
      chatRoom,
      minimized,
      peers,
      sidebar,
      hovered,
      forcedLocal,
      view,
      isOnHold,
      waitingRoomPeers,
      recorderCid,
      raisedHandPeers,
      isFloatingPresenter,
      onRecordingToggle,
      onCallMinimize,
      onCallExpand,
      onModeChange,
      onAudioClick,
      onVideoClick,
      onCallEnd,
      onScreenSharingClick,
      onHoldClick,
      onSpeakerChange,
      onParticipantsToggle,
      setActiveElement
    } = this.props;
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                    ${stream_NAMESPACE}
                    ${sidebar ? '' : 'full'}
                    ${hovered ? 'hovered' : ''}
                `
    }, waitingRoomPeers && waitingRoomPeers.length ? REaCt().createElement(Admit, {
      chatRoom,
      call,
      peers: waitingRoomPeers,
      expanded: wrToggled,
      onWrListToggle: this.toggleWaitingRoomList
    }) : null, this.renderToaster(), minimized ? null : REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
      className: `
                                ${stream_NAMESPACE}-wrapper
                                ${mode === meetings_call.g.MAIN ? 'with-participants-block' : ''}
                            `
    }, isOnHold ? this.renderOnHold() : overlayed && REaCt().createElement("div", {
      className: "call-overlay"
    }), this.renderStreamContainer()), mode === meetings_call.g.MAIN && REaCt().createElement(ParticipantsBlock, (0,esm_extends.A)({}, this.props, {
      floatDetached,
      onSeparate: this.toggleFloatDetachment
    })), REaCt().createElement(StreamHead, {
      disableCheckingVisibility: true,
      mode,
      peers,
      page,
      streamsPerPage,
      floatDetached,
      chunksLength: this.chunksLength,
      call,
      chatRoom,
      onCallMinimize,
      onModeChange,
      onStreamsPerPageChange: streamsPerPage => this.setState({
        streamsPerPage
      }),
      onMovePage: direction => this.movePage(direction),
      setActiveElement
    })), REaCt().createElement(FloatingVideo, {
      call,
      peers,
      mode,
      view,
      floatDetached,
      isOnHold,
      chatRoom,
      minimized,
      sidebar,
      forcedLocal,
      isPresenterNode: isFloatingPresenter,
      wrapperRef: this.domRef,
      waitingRoomPeers,
      recorderCid,
      raisedHandPeers,
      onRecordingToggle,
      onAudioClick,
      onVideoClick,
      onCallEnd,
      onScreenSharingClick,
      onCallMinimize,
      onMoveIntoGrid: this.toggleFloatDetachment,
      onCallExpand: async () => {
        await onCallExpand();
        this.scaleNodes(undefined, true);
      },
      onSpeakerChange,
      onModeChange,
      onHoldClick,
      onParticipantsToggle,
      onWrListToggle: this.toggleWaitingRoomList
    }));
  }
}

},

424:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
A: () => ChatToaster
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);
const _mixins1__ = REQ_(137);
const _meetings_call_jsx2__ = REQ_(3);
const _ui_buttons3__ = REQ_(994);




const NAMESPACE = 'chat-toast';
class ChatToaster extends react0().Component {
  constructor(props) {
    super(props);
    this.uid = `${this.constructor.name}--${(0,_mixins1__.LP)()}`;
    this.domRef = react0().createRef();
    this.state = {
      toast: null,
      endTime: 0,
      fmToastId: null,
      persistentToast: null
    };
    this.toasts = [];
    this.persistentToasts = [];
  }
  enqueueToast(e) {
    if (this.props.showDualNotifications && e.data.options && e.data.options.persistent) {
      this.persistentToasts.push(e.data);
    } else {
      this.toasts.push(e.data);
    }
    this.pollToasts();
  }
  pollToasts() {
    const {
      toast: shownToast,
      persistentToast: shownPersistentToast
    } = this.state;
    const {
      isRootToaster,
      showDualNotifications,
      onShownToast
    } = this.props;
    const now = Date.now();
    if (this.toasts.length + this.persistentToasts.length) {
      if (this.domRef.current && (!isRootToaster && _meetings_call_jsx2__.Ay.isExpanded() || M.chat)) {
        if (this.toasts.length && !shownToast) {
          this.dispatchToast(this.toasts.shift(), now);
        }
        if (showDualNotifications && this.persistentToasts.length && !shownPersistentToast) {
          const persistentToast = this.persistentToasts.shift();
          this.setState({
            persistentToast
          }, () => this.pollToasts());
          if (typeof onShownToast === 'function') {
            onShownToast(persistentToast);
          }
        }
      } else if (isRootToaster && this.toasts.length && !shownToast) {
        const toast = this.toasts.shift();
        this.dispatchToast(toast, now, {
          fmToastId: 'tmp'
        });
        this.dispatchFMToast(toast);
      }
    }
  }
  dispatchFMToast(toast, redraw) {
    window.toaster.alerts.medium(...toast.renderFM()).then(fmToastId => {
      if (!redraw) {
        toast.onShown(fmToastId);
      }
      this.setState({
        fmToastId
      });
      if (toast.updater && typeof toast.updater === 'function') {
        toast.updater();
        toast.updateInterval = setInterval(() => {
          toast.updater();
          const value = toast.render();
          if (!value) {
            window.toaster.alerts.hide(fmToastId);
            return this.onClose(toast.options && toast.options.persistent);
          }
          if (value !== $('span', `#${fmToastId}`).text()) {
            $('span', `#${fmToastId}`).text(value);
          }
        }, 250);
      }
    });
  }
  dispatchToast(toast, now, options = {}) {
    const {
      fmToastId,
      endTime,
      silent
    } = options;
    const {
      onShownToast,
      onHideToast
    } = this.props;
    this.setState({
      toast,
      endTime: endTime || now + toast.getTTL(),
      fmToastId
    }, () => {
      if (!silent) {
        toast.onShown();
      }
      this.timeout = setTimeout(() => {
        delete this.timeout;
        this.setState({
          toast: null,
          endTime: 0
        }, () => this.pollToasts());
        if (typeof toast.onEnd === 'function') {
          toast.onEnd();
        }
        if (typeof onHideToast === 'function') {
          onHideToast(toast);
        }
        if (toast.updateInterval) {
          clearInterval(toast.updateInterval);
          delete toast.updateInterval;
        }
      }, endTime ? endTime - now : toast.getTTL());
    });
    if (typeof onShownToast === 'function') {
      onShownToast(toast);
    }
  }
  onClose(persistent) {
    const {
      showDualNotifications,
      onHideToast
    } = this.props;
    const {
      toast,
      persistentToast
    } = this.state;
    if (showDualNotifications && persistent) {
      if (typeof persistentToast.onEnd === 'function') {
        persistentToast.onEnd();
      }
      this.setState({
        persistentToast: null
      }, () => this.pollToasts());
      if (typeof onHideToast === 'function') {
        onHideToast(persistentToast);
      }
      return;
    }
    if (toast.updateInterval) {
      clearInterval(toast.updateInterval);
      delete toast.updateInterval;
    }
    clearTimeout(this.timeout);
    delete this.timeout;
    if (typeof toast.onEnd === 'function') {
      toast.onEnd();
    }
    if (typeof onHideToast === 'function') {
      onHideToast(toast);
    }
    this.setState({
      toast: null,
      endTime: 0
    }, () => this.pollToasts());
  }
  flush() {
    const {
      toast,
      persistentToast,
      fmToastId
    } = this.state;
    this.endToastIntervals();
    if (fmToastId && fmToastId !== 'tmp') {
      window.toaster.alerts.hide(fmToastId);
    }
    this.toasts = [];
    this.persistentToasts = [];
    if (this.timeout) {
      clearTimeout(this.timeout);
      delete this.timeout;
    }
    if (toast) {
      this.onClose(toast.persistent);
    }
    if (persistentToast) {
      this.onClose(true);
    }
    this.setState({
      toast: null,
      endTime: 0,
      fmToastId: null,
      persistentToast: null
    });
  }
  endToastIntervals() {
    if (!this.props.isRootToaster) {
      return;
    }
    for (const toast of this.toasts) {
      if (toast.updateInterval) {
        clearInterval(toast.updateInterval);
      }
    }
    for (const toast of this.persistentToasts) {
      if (toast.updateInterval) {
        clearInterval(toast.updateInterval);
      }
    }
  }
  componentDidMount() {
    megaChat.rebind(`onChatToast.toaster${this.uid}`, e => this.enqueueToast(e));
    megaChat.rebind(`onChatToastFlush.toaster${this.uid}`, () => this.flush());
    onIdle(() => this.pollToasts());
    if (this.props.isRootToaster) {
      this.bpcListener = mBroadcaster.addListener('beforepagechange', tpage => {
        const {
          toast,
          endTime,
          fmToastId
        } = this.state;
        const now = Date.now();
        if (toast && endTime - 500 > now) {
          const toChat = tpage.includes('chat') && tpage !== 'securechat';
          if (toChat && !M.chat) {
            clearTimeout(this.timeout);
            window.toaster.alerts.hide(fmToastId);
            if (toast.updateInterval) {
              clearInterval(toast.updateInterval);
              delete toast.updateInterval;
            }
            this.dispatchToast(toast, now, {
              endTime,
              silent: true
            });
          } else if (!toChat && M.chat) {
            clearTimeout(this.timeout);
            this.dispatchToast(toast, now, {
              fmToastId: 'tmp',
              endTime,
              silent: true
            });
            this.dispatchFMToast(toast, true);
          }
        } else if (toast && typeof toast.onEnd === 'function') {
          toast.onEnd();
        }
      });
    }
  }
  componentWillUnmount() {
    megaChat.off(`onChatToast.toaster${this.uid}`);
    megaChat.off(`onChatToastFlush.toaster${this.uid}`);
    if (this.bpcListener) {
      mBroadcaster.removeListener(this.bpcListener);
    }
    if (this.timeout) {
      clearTimeout(this.timeout);
    }
    this.endToastIntervals();
  }
  render() {
    const {
      hidden,
      isRootToaster,
      showDualNotifications
    } = this.props;
    const {
      toast,
      fmToastId,
      persistentToast
    } = this.state;
    return !hidden && !fmToastId && react0().createElement("div", {
      ref: this.domRef,
      className: `chat-toast-bar ${isRootToaster ? 'toaster-root' : ''}`
    }, showDualNotifications && persistentToast && react0().createElement(ChatToastMsg, {
      toast: persistentToast,
      isRootToaster,
      usePersistentStyle: true,
      onClose: p => this.onClose(p)
    }), toast && react0().createElement(ChatToastMsg, {
      toast,
      isRootToaster,
      isDualToast: !!persistentToast,
      onClose: p => this.onClose(p)
    }));
  }
}
class ChatToastMsg extends react0().Component {
  constructor(...args) {
    super(...args);
    this.state = {
      value: ''
    };
  }
  componentDidMount() {
    const {
      toast,
      onClose
    } = this.props;
    if (toast.updater && typeof toast.updater === 'function') {
      toast.updater();
      this.updateInterval = setInterval(() => {
        toast.updater();
        const value = toast.render();
        if (!value) {
          return onClose(toast.options && toast.options.persistent);
        }
        if (value !== this.state.value) {
          this.setState({
            value
          });
        }
      }, 250);
    }
    const value = toast.render();
    if (value) {
      this.setState({
        value
      });
    } else {
      onClose(toast.options && toast.options.persistent);
    }
  }
  componentWillUnmount() {
    if (this.updateInterval) {
      clearInterval(this.updateInterval);
    }
  }
  render() {
    const {
      toast,
      isRootToaster,
      isDualToast,
      usePersistentStyle,
      onClose
    } = this.props;
    const {
      value
    } = this.state;
    if (usePersistentStyle && toast.options.persistent) {
      return react0().createElement("div", {
        className: `${NAMESPACE} chat-persistent-toast`
      }, value || toast.render());
    }
    const closeButton = toast.close && react0().createElement(_ui_buttons3__.$, {
      className: "chat-toast-close",
      icon: "sprite-fm-mono icon-close-component",
      onClick: onClose
    });
    const icon = toast.icon && react0().createElement("i", {
      className: toast.icon
    });
    if (isRootToaster) {
      return react0().createElement("div", {
        className: `${NAMESPACE} chat-toast-wrapper root-toast`
      }, react0().createElement("div", {
        className: "toast-value-wrapper"
      }, icon, react0().createElement("div", {
        className: "toast-value"
      }, value || toast.render())), closeButton);
    }
    return react0().createElement("div", {
      className: `${NAMESPACE} chat-toast-wrapper theme-light-forced ${isDualToast ? 'dual-toast' : ''}`
    }, react0().createElement("div", {
      className: "toast-value"
    }, value || toast.render()));
  }
}

},

438:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  $h: () => ConversationPanels,
  Yk: () => EmptyConvPanel,
  e4: () => allContactsInChat,
  zV: () => excludedParticipants
});

// UNUSED EXPORTS: ConversationPanel, ConversationRightArea, JoinCallNotification

// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
const applyDecoratedDescriptor = REQ_(793);
// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
const esm_extends = REQ_(168);
// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
// EXTERNAL MODULE: ./js/ui/utils.jsx
const utils = REQ_(314);
// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
// EXTERNAL MODULE: ./js/ui/buttons.jsx
const buttons = REQ_(994);
// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
const modalDialogs = REQ_(318);
;// ./js/ui/jsx/fm/viewModeSelector.jsx

const VIEW_MODE = {
  'GRID': 1,
  'LIST': undefined
};
const ViewModeSelector = ({
  viewMode,
  onChange
}) => {
  return REaCt().createElement("div", {
    className: "chat-fm-view-mode-selector"
  }, REaCt().createElement("i", {
    className: `
                    sprite-fm-mono
                    icon-view-medium-list
                    ${viewMode ? '' : 'active'}
                `,
    title: l[5553],
    onClick: () => onChange == null ? void 0 : onChange(VIEW_MODE.LIST)
  }), REaCt().createElement("i", {
    className: `
                    sprite-fm-mono
                    icon-view-grid
                    ${viewMode ? " active" : ""}
                `,
    title: l[5552],
    onClick: () => onChange == null ? void 0 : onChange(VIEW_MODE.GRID)
  }));
};
const viewModeSelector = ViewModeSelector;
;// ./js/ui/jsx/fm/breadcrumbs.jsx


class Breadcrumbs extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.state = {
      'breadcrumbDropdownVisible': false
    };
    this.onGlobalClickHandler = this.onGlobalClickHandler.bind(this);
    this.onBreadcrumbNodeClick = this.onBreadcrumbNodeClick.bind(this);
  }
  getBreadcrumbNodeText(nodeId, prevNodeId) {
    const backupsId = M.BackupsId || 'backups';
    switch (nodeId) {
      case M.RootID:
        return l[164];
      case M.RubbishID:
        return l[167];
      case backupsId:
        return l.restricted_folder_button;
      case 'shares':
        return prevNodeId && M.d[prevNodeId] ? M.d[prevNodeId].m : l[5589];
      default:
        return M.d[nodeId] && M.d[nodeId].name;
    }
  }
  getBreadcrumbDropdownContents(items) {
    const contents = [];
    for (const item of items) {
      if (!item.name) {
        continue;
      }
      contents.push(REaCt().createElement("a", {
        className: "crumb-drop-link",
        key: `drop_link_${  item.nodeId}`,
        onClick: e => this.onBreadcrumbNodeClick(e, item.nodeId)
      }, REaCt().createElement("i", {
        className: `sprite-fm-mono icon24 ${{
          'cloud-drive': 'icon-cloud',
          'backups': 'icon-database-filled',
          's4-object-storage': 'icon-bucket-triangle-thin-solid',
          's4-buckets': 'icon-bucket-outline'
        }[item.type] || 'folder'}`
      }), REaCt().createElement("span", null, item.name)));
    }
    return contents;
  }
  onBreadcrumbNodeClick(e, nodeId) {
    e.preventDefault();
    e.stopPropagation();
    if (this._clickToHideListener) {
      this.removeGlobalClickHandler();
      this.setState({
        'breadcrumbDropdownVisible': false
      });
    }
    this.props.onNodeClick(nodeId);
  }
  customIsEventuallyVisible() {
    return true;
  }
  onGlobalClickHandler(e) {
    let _this$domRef;
    const node = (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current;
    if (node.contains(e.target) || node === e.target) {
      return;
    }
    if (this._clickToHideListener) {
      this.removeGlobalClickHandler();
    }
    this.setState({
      'breadcrumbDropdownVisible': false
    });
  }
  removeGlobalClickHandler() {
    this._clickToHideListener = false;
    document.body.removeEventListener("click", this.onGlobalClickHandler);
  }
  componentDidUpdate() {
    super.componentDidUpdate();
    if (this.state.breadcrumbDropdownVisible) {
      if (!this._clickToHideListener) {
        this._clickToHideListener = true;
        document.body.addEventListener("click", this.onGlobalClickHandler);
      }
    } else if (this._clickToHideListener) {
      this.removeGlobalClickHandler();
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    this.removeGlobalClickHandler();
  }
  render() {
    const {
      className,
      highlighted,
      currentlyViewedEntry,
      isSearch,
      path
    } = this.props;
    const breadcrumb = [];
    const extraPathItems = [];
    let breadcrumbDropdownContents = [];
    const entryId = isSearch ? highlighted[0] : currentlyViewedEntry;
    if (entryId !== undefined) {
      (path || M.getPath(entryId)).forEach((nodeId, k, path) => {
        let breadcrumbClasses = '';
        let folderType = 'folder';
        if (nodeId === M.RootID) {
          breadcrumbClasses += " cloud-drive";
        } else {
          breadcrumbClasses += " folder";
        }
        if (nodeId.length === 11 && M.u[nodeId]) {
          return;
        }
        if (nodeId === "shares") {
          breadcrumbClasses += " shared-with-me";
        }
        const prevNodeId = path[k - 1];
        let nodeName = this.getBreadcrumbNodeText(nodeId, prevNodeId);
        if ('utils' in s4) {
          const data = s4.utils.getBreadcrumbsData(nodeId);
          if (data) {
            ({
              type: folderType,
              localeName: nodeName
            } = data);
          }
        }
        if (!nodeName) {
          return;
        }
        ((nodeId, k) => {
          if (k < 4) {
            breadcrumb.unshift(REaCt().createElement("a", {
              className: `fm-breadcrumbs contains-directories ${  breadcrumbClasses}`,
              key: nodeId,
              onClick: e => this.onBreadcrumbNodeClick(e, nodeId)
            }, REaCt().createElement("span", {
              className: `right-arrow-bg simpletip`,
              "data-simpletip": nodeName
            }, REaCt().createElement("span", {
              className: "selectable-txt"
            }, nodeName)), k !== 0 && REaCt().createElement("i", {
              className: "next-arrow sprite-fm-mono icon-arrow-right icon16"
            })));
          } else {
            folderType = nodeId === M.RootID ? 'cloud-drive' : folderType;
            if (M.BackupsId && nodeId === M.BackupsId) {
              folderType = 'backups';
            }
            extraPathItems.push({
              name: nodeName,
              type: folderType,
              nodeId
            });
          }
        })(nodeId, k);
      });
      if (extraPathItems.length > 0) {
        breadcrumbDropdownContents = this.getBreadcrumbDropdownContents(extraPathItems);
      }
    }
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                    fm-breadcrumbs-wrapper
                    ${className || ''}
                `
    }, REaCt().createElement("div", {
      className: "fm-breadcrumbs-block"
    }, breadcrumbDropdownContents.length ? REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
      className: "crumb-overflow-link"
    }, REaCt().createElement("a", {
      className: "breadcrumb-dropdown-link dropdown",
      onClick: () => {
        this.setState({
          breadcrumbDropdownVisible: !this.state.breadcrumbDropdownVisible
        });
      }
    }, REaCt().createElement("i", {
      className: "menu-icon sprite-fm-mono icon-options icon16"
    })), REaCt().createElement("i", {
      className: "sprite-fm-mono icon-arrow-right icon16"
    })), breadcrumb) : breadcrumb), breadcrumbDropdownContents.length ? REaCt().createElement("div", {
      className: this.state.breadcrumbDropdownVisible ? 'breadcrumb-dropdown active' : 'breadcrumb-dropdown'
    }, breadcrumbDropdownContents) : '');
  }
}
// EXTERNAL MODULE: ./js/ui/jsx/fm/fmView.jsx + 10 modules
const fmView = REQ_(701);
;// ./js/ui/cloudBrowserModalDialog.jsx





const MIN_SEARCH_LENGTH = 2;
class CloudBrowserDialog extends modalDialogs.A.SafeShowDialogController {
  static getFilterFunction(customFilterFn) {
    return tryCatch(n => {
      if (n.s4 && n.p === M.RootID && M.getS4NodeType(n) === 'container') {
        return false;
      }
      if (!n.name || missingkeys[n.h] || M.getNodeShare(n).down) {
        return false;
      }
      return !customFilterFn || customFilterFn(n);
    });
  }
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.dialogName = 'attach-cloud-dialog';
    this.state = {
      'isActiveSearch': false,
      'selected': [],
      'highlighted': [],
      'currentlyViewedEntry': M.RootID,
      'selectedTab': M.RootID,
      'searchValue': '',
      'searchText': ''
    };
    this.onAttachClicked = this.onAttachClicked.bind(this);
    this.onClearSearchIconClick = this.onClearSearchIconClick.bind(this);
    this.onPopupDidMount = this.onPopupDidMount.bind(this);
    this.onSearchChange = this.onSearchChange.bind(this);
    this.onSearchIconClick = this.onSearchIconClick.bind(this);
    this.onSelected = this.onSelected.bind(this);
    this.onHighlighted = this.onHighlighted.bind(this);
    this.handleTabChange = this.handleTabChange.bind(this);
    this.onViewModeSwitch = this.onViewModeSwitch.bind(this);
    this.onBreadcrumbNodeClick = this.onBreadcrumbNodeClick.bind(this);
    this.onExpand = this.onExpand.bind(this);
  }
  onViewModeSwitch(newMode) {
    const currentViewMode = mega.config.get('cbvm') | 0;
    if (newMode === currentViewMode) {
      return;
    }
    mega.config.set('cbvm', newMode);
    this.forceUpdate();
  }
  getHeaderButtonsClass() {
    const classes = ['fm-header-buttons'];
    if (this.state.isActiveSearch) {
      classes.push('active-search');
    }
    return classes.join(' ');
  }
  getSearchIconClass() {
    const classes = ['sprite-fm-mono', 'icon-preview-reveal'];
    if (this.state.isActiveSearch && this.state.searchText.length > 0) {
      classes.push('disabled');
    }
    return classes.join(' ');
  }
  onSearchIconClick() {
    const isActiveSearch = !this.state.isActiveSearch;
    if (isActiveSearch) {
      this.searchInput.focus();
      this.setState({
        isActiveSearch
      });
    }
  }
  onClearSearchIconClick() {
    this.setState({
      'isActiveSearch': false,
      'searchValue': '',
      'searchText': '',
      'currentlyViewedEntry': this.state.selectedTab
    });
  }
  handleTabChange(selectedTab) {
    const s4Cn = selectedTab === 's4' && M.tree.s4 && Object.keys(M.tree.s4);
    this.clearSelectionAndHighlight();
    this.setState({
      selectedTab,
      currentlyViewedEntry: s4Cn && s4Cn.length === 1 ? s4Cn[0] : selectedTab,
      searchValue: '',
      searchText: '',
      isLoading: false
    });
  }
  onSearchBlur() {
    if (this.state.searchText === '') {
      this.setState({
        'isActiveSearch': false
      });
    }
  }
  onSearchChange(e) {
    const searchValue = e.target.value;
    const newState = {
      searchText: searchValue,
      nodeLoading: searchValue.length >= MIN_SEARCH_LENGTH
    };
    if (searchValue && searchValue.length >= MIN_SEARCH_LENGTH) {
      this.setState(newState);
      delay('cbd:search-proc', this.searchProc.bind(this), 500);
      return;
    }
    if (this.state.currentlyViewedEntry === 'search' && (!searchValue || searchValue.length < MIN_SEARCH_LENGTH)) {
      newState.currentlyViewedEntry = this.state.selectedTab;
      newState.searchValue = undefined;
    }
    this.setState(newState);
    this.clearSelectionAndHighlight();
  }
  searchProc() {
    const {
      searchText
    } = this.state;
    const newState = {
      nodeLoading: true
    };
    if (searchText && searchText.length >= MIN_SEARCH_LENGTH) {
      this.setState(newState);
      M.fmSearchNodes(searchText).then(() => {
        newState.nodeLoading = false;
        newState.searchValue = searchText;
        newState.currentlyViewedEntry = 'search';
        this.setState(newState);
        this.clearSelectionAndHighlight();
      });
    }
  }
  onSelected(nodes) {
    this.setState({
      'selected': nodes
    });
    this.props.onSelected(nodes);
  }
  onHighlighted(nodes) {
    this.setState({
      'highlighted': nodes
    });
    if (this.props.onHighlighted) {
      this.props.onHighlighted(nodes);
    }
  }
  clearSelectionAndHighlight() {
    this.onSelected([]);
    this.onHighlighted([]);
    if (selectionManager) {
      selectionManager.clear_selection();
    }
  }
  onPopupDidMount(elem) {
    this.domNode = elem;
  }
  onAttachClicked() {
    this.props.onAttachClicked();
  }
  onBreadcrumbNodeClick(nodeId) {
    if (nodeId === 'shares' || nodeId === 's4') {
      return this.handleTabChange(nodeId);
    }
    if (M.getNodeByHandle(nodeId).t) {
      const nodeRoot = M.getNodeRoot(nodeId);
      this.setState({
        selectedTab: nodeRoot === "contacts" ? 'shares' : nodeRoot,
        currentlyViewedEntry: nodeId,
        selected: [],
        searchValue: '',
        searchText: ''
      });
    }
  }
  onExpand(nodeId) {
    this.setState({
      'currentlyViewedEntry': nodeId,
      'searchValue': '',
      'searchText': '',
      'selected': [],
      'highlighted': []
    });
  }
  render() {
    assert(this.dialogBecameVisible);
    const self = this;
    const viewMode = mega.config.get('cbvm') | 0;
    const classes = `add-from-cloud ${self.props.className} dialog-template-tool `;
    let folderIsHighlighted = false;
    let share = false;
    let isS4Cn = false;
    const isSearch = this.state.currentlyViewedEntry === 'search';
    const entryId = isSearch ? self.state.highlighted[0] : self.state.currentlyViewedEntry;
    const filterFn = CloudBrowserDialog.getFilterFunction(this.props.customFilterFn);
    const isIncomingShare = M.getNodeRoot(entryId) === "shares";
    this.state.highlighted.forEach(nodeId => {
      if (M.getNodeByHandle(nodeId).t) {
        folderIsHighlighted = true;
        if (M.tree.s4 && M.tree.s4[nodeId]) {
          isS4Cn = true;
        }
      }
      share = M.getNodeShare(nodeId);
    });
    const buttons = [{
      "label": this.props.cancelLabel,
      "key": "cancel",
      "onClick": e => {
        e.preventDefault();
        e.stopPropagation();
        if (this.props.onCancel) {
          this.props.onCancel(this);
        }
        this.props.onClose(this);
      }
    }];
    if (folderIsHighlighted) {
      const {
        highlighted
      } = this.state;
      const className = `${share && share.down ? 'disabled' : ''}`;
      const highlightedNode = highlighted && highlighted.length && highlighted[0];
      const allowAttachFolders = this.props.allowAttachFolders && !isIncomingShare && !isS4Cn;
      buttons.push({
        "label": this.props.openLabel,
        "key": "select",
        className: `positive ${className} ${highlighted.length > 1 ? 'disabled' : ''}`,
        onClick: e => {
          e.preventDefault();
          e.stopPropagation();
          if (highlighted.length > 1) {
            return;
          }
          this.setState({
            currentlyViewedEntry: highlightedNode
          });
          this.clearSelectionAndHighlight();
          this.setState({
            selected: [],
            searchValue: '',
            searchText: '',
            highlighted: []
          });
        }
      }, allowAttachFolders ? {
        "label": l[8023],
        "key": "attach",
        className: `positive ${  className}`,
        onClick: () => {
          this.props.onClose();
          onIdle(() => {
            const createPublicLink = h => {
              M.createPublicLink(h).then(({
                link
              }) => this.props.room.sendMessage(link));
            };
            const frs = [];
            const files = [];
            for (let i = 0; i < highlighted.length; i++) {
              const node = M.getNodeByHandle(highlighted[i]);
              if (node && M.isFileNode(node)) {
                if (!M.getNodeShare(node).down) {
                  files.push(node);
                }
              } else if (mega.fileRequestCommon.storage.isDropExist(highlighted[i]).length) {
                frs.push(highlighted[i]);
              } else {
                createPublicLink(highlighted[i]);
              }
            }
            if (files.length) {
              this.props.onSelected(files);
              this.props.onAttachClicked();
            }
            if (frs.length) {
              const fldName = frs.length > 1 ? l[17626] : l[17403].replace('%1', escapeHTML(M.getNameByHandle(frs[0])) || l[1049]);
              msgDialog('confirmation', l[1003], fldName, l[18229], e => {
                if (e) {
                  mega.fileRequest.removeList(frs).then(() => {
                    for (let i = 0; i < frs.length; i++) {
                      createPublicLink(frs[i]);
                    }
                  }).catch(dump);
                }
              });
            }
          });
        }
      } : null);
    }
    if (!folderIsHighlighted || this.props.folderSelectable && (!this.props.noShareFolderAttach || !(isIncomingShare && folderIsHighlighted))) {
      buttons.push({
        "label": this.props.selectLabel,
        "key": "select",
        "className": `positive ${  this.state.selected.length === 0 || share && share.down || isS4Cn ? "disabled" : ""}`,
        "onClick": e => {
          if (this.state.selected.length > 0) {
            this.props.onSelected(this.state.selected);
            this.props.onAttachClicked();
          }
          e.preventDefault();
          e.stopPropagation();
        }
      });
    }
    let clearSearchBtn = null;
    if (self.state.searchText.length >= MIN_SEARCH_LENGTH) {
      clearSearchBtn = REaCt().createElement("i", {
        className: "sprite-fm-mono icon-close-component",
        onClick: () => {
          self.onClearSearchIconClick();
        }
      });
    }
    const breadcrumbPath = M.getPath(entryId);
    return REaCt().createElement(modalDialogs.A.ModalDialog, {
      title: self.props.title || l[8011],
      className: classes + (isSearch && this.state.selected.length > 0 ? 'has-breadcrumbs-bottom' : '') + this.dialogName,
      onClose: () => {
        self.props.onClose(self);
      },
      dialogName: "add-from-cloud-dialog dialog-template-tool",
      popupDidMount: self.onPopupDidMount,
      buttons
    }, REaCt().createElement("section", {
      ref: this.domRef,
      className: "content"
    }, REaCt().createElement("div", {
      className: "content-block"
    }, REaCt().createElement("div", {
      className: "fm-dialog-tabs"
    }, REaCt().createElement("div", {
      className: `
                                    fm-dialog-tab cloud
                                    ${self.state.selectedTab === M.RootID ? 'active' : ''}
                                `,
      onClick: () => self.handleTabChange(M.RootID)
    }, l[164]), REaCt().createElement("div", {
      className: `
                                    fm-dialog-tab incoming
                                    ${self.state.selectedTab === 'shares' ? 'active' : ''}
                                `,
      onClick: () => self.handleTabChange('shares')
    }, l[5542]), REaCt().createElement("div", {
      className: `
                                    fm-dialog-tab s4
                                    ${self.state.selectedTab === 's4' ? 'active' : ''}
                                    ${u_attr.s4 ? '' : 'hidden'}
                                `,
      onClick: () => self.handleTabChange('s4')
    }, l.obj_storage), REaCt().createElement("div", {
      className: "clear"
    })), REaCt().createElement("div", {
      className: "fm-picker-header"
    }, REaCt().createElement("div", {
      className: self.getHeaderButtonsClass()
    }, REaCt().createElement(viewModeSelector, {
      viewMode,
      onChange: this.onViewModeSwitch
    }), REaCt().createElement("div", {
      className: "fm-files-search"
    }, REaCt().createElement("i", {
      className: self.getSearchIconClass(),
      onClick: () => {
        self.onSearchIconClick();
      }
    }), REaCt().createElement("input", {
      ref: input => {
        this.searchInput = input;
      },
      type: "search",
      placeholder: l[102],
      value: self.state.searchText,
      onChange: self.onSearchChange,
      onBlur: () => {
        self.onSearchBlur();
      }
    }), clearSearchBtn), REaCt().createElement("div", {
      className: "clear"
    })), !isSearch && REaCt().createElement(Breadcrumbs, {
      className: "add-from-cloud",
      nodeId: entryId,
      path: breadcrumbPath,
      onNodeClick: this.onBreadcrumbNodeClick,
      isSearch,
      highlighted: this.state.highlighted,
      currentlyViewedEntry: this.state.currentlyViewedEntry
    })), REaCt().createElement(fmView.A, {
      nodeLoading: this.state.nodeLoading,
      sortFoldersFirst: true,
      currentlyViewedEntry: this.state.currentlyViewedEntry,
      customFilterFn: filterFn,
      folderSelectNotAllowed: this.props.folderSelectNotAllowed,
      folderSelectable: this.props.folderSelectable,
      onSelected: this.onSelected,
      onHighlighted: this.onHighlighted,
      onAttachClicked: this.onAttachClicked,
      initialSelected: this.state.selected,
      initialHighlighted: this.state.highlighted,
      searchValue: this.state.searchValue,
      minSearchLength: MIN_SEARCH_LENGTH,
      onExpand: this.onExpand,
      viewMode,
      initialSortBy: ['name', 'asc'],
      fmConfigSortEnabled: true,
      fmConfigSortId: "cbd"
    }), isSearch && breadcrumbPath.length > 0 && REaCt().createElement("div", {
      className: `
                            fm-breadcrumbs-wrapper add-from-cloud breadcrumbs-bottom
                        `
    }, REaCt().createElement("div", {
      className: "fm-breadcrumbs-block"
    }, REaCt().createElement(Breadcrumbs, {
      nodeId: entryId,
      path: breadcrumbPath,
      onNodeClick: this.onBreadcrumbNodeClick,
      isSearch,
      highlighted: this.state.highlighted,
      currentlyViewedEntry: this.state.currentlyViewedEntry
    }), REaCt().createElement("div", {
      className: "clear"
    }))))));
  }
}
CloudBrowserDialog.defaultProps = {
  'selectLabel': l[8023],
  'openLabel': l[1710],
  'cancelLabel': l.msg_dlg_cancel,
  'hideable': true,
  'className': ''
};
Object.defineProperty(mega, 'CloudBrowserDialog', {
  value: CloudBrowserDialog
});
const cloudBrowserModalDialog = {
  CloudBrowserDialog
};
// EXTERNAL MODULE: ./js/chat/chatRoom.jsx + 1 modules
const chat_chatRoom = REQ_(553);
;// ./js/ui/historyRetentionDialog.jsx




const LIMIT = {
  CHARS: 2,
  HOURS: 24,
  DAYS: 31,
  WEEKS: 4,
  MONTHS: 12
};
class HistoryRetentionDialog extends React_.Component {
  constructor(props) {
    super(props);
    this.dialogName = 'msg-retention-dialog';
    this.inputRef = REaCt().createRef();
    this.state = {
      selectedTimeFormat: chat_chatRoom.RETENTION_FORMAT.HOURS,
      timeRange: undefined
    };
    this.handleRadioChange = e => {
      const selectedTimeFormat = e.target.value;
      this.setState(prevState => ({
        selectedTimeFormat,
        timeRange: this.filterTimeRange(prevState.timeRange, selectedTimeFormat)
      }));
    };
    this.handleOnTimeCheck = e => {
      const checkingValue = e.type === 'paste' ? e.clipboardData.getData('text') : e.key;
      if (e.keyCode !== 8 && isNaN(checkingValue)) {
        e.preventDefault();
      }
    };
    this.handleOnTimeChange = e => {
      const timeValue = e.target.value;
      this.setState(prevState => ({
        timeRange: this.filterTimeRange(timeValue, prevState.selectedTimeFormat)
      }));
    };
    const {
      chatRoom
    } = props;
    this.state.timeRange = chatRoom.getRetentionTimeFormatted();
    if (this.state.timeRange === 0) {
      this.state.timeRange = '';
    }
    this.state.selectedTimeFormat = chatRoom.getRetentionFormat();
    this.state.selectedTimeFormat = this.state.selectedTimeFormat === chat_chatRoom.RETENTION_FORMAT.DISABLED ? chat_chatRoom.RETENTION_FORMAT.HOURS : this.state.selectedTimeFormat;
  }
  hasInput() {
    return this.state.timeRange && parseInt(this.state.timeRange, 10) >= 1;
  }
  getMaxTimeRange(selectedTimeFormat) {
    switch (selectedTimeFormat) {
      case chat_chatRoom.RETENTION_FORMAT.HOURS:
        return LIMIT.HOURS;
      case chat_chatRoom.RETENTION_FORMAT.DAYS:
        return LIMIT.DAYS;
      case chat_chatRoom.RETENTION_FORMAT.WEEKS:
        return LIMIT.WEEKS;
      case chat_chatRoom.RETENTION_FORMAT.MONTHS:
        return LIMIT.MONTHS;
    }
  }
  getParsedLabel(label, timeRange) {
    timeRange = timeRange ? parseInt(timeRange, 10) : this.getMaxTimeRange(label);
    switch (label) {
      case chat_chatRoom.RETENTION_FORMAT.HOURS:
        return mega.icu.format(l.plural_hour, timeRange);
      case chat_chatRoom.RETENTION_FORMAT.DAYS:
        return mega.icu.format(l.plural_day, timeRange);
      case chat_chatRoom.RETENTION_FORMAT.WEEKS:
        return mega.icu.format(l.plural_week, timeRange);
      case chat_chatRoom.RETENTION_FORMAT.MONTHS:
        return mega.icu.format(l.plural_month, timeRange);
    }
  }
  filterTimeRange(timeRange, selectedTimeFormat) {
    if (timeRange.length > LIMIT.CHARS) {
      return timeRange.substring(0, LIMIT.CHARS);
    }
    timeRange = parseInt(timeRange, 10);
    if (timeRange === 0 || isNaN(timeRange)) {
      return '';
    }
    return Math.min(this.getMaxTimeRange(selectedTimeFormat), timeRange);
  }
  handleOnSubmit(e) {
    if (!this.hasInput()) {
      return;
    }
    e.preventDefault();
    e.stopPropagation();
    const {
      chatRoom,
      onClose
    } = this.props;
    const {
      selectedTimeFormat,
      timeRange
    } = this.state;
    let time = 0;
    switch (selectedTimeFormat) {
      case chat_chatRoom.RETENTION_FORMAT.HOURS:
        time = hoursToSeconds(Number(timeRange));
        break;
      case chat_chatRoom.RETENTION_FORMAT.DAYS:
        time = daysToSeconds(Number(timeRange));
        break;
      case chat_chatRoom.RETENTION_FORMAT.WEEKS:
        time = daysToSeconds(Number(timeRange) * 7);
        break;
      case chat_chatRoom.RETENTION_FORMAT.MONTHS:
        time = daysToSeconds(Number(timeRange) * 30);
        break;
    }
    chatRoom.setRetention(time);
    onClose();
  }
  renderCustomRadioButton() {
    return [chat_chatRoom.RETENTION_FORMAT.HOURS, chat_chatRoom.RETENTION_FORMAT.DAYS, chat_chatRoom.RETENTION_FORMAT.WEEKS, chat_chatRoom.RETENTION_FORMAT.MONTHS].map(label => {
      return REaCt().createElement(CustomRadioButton, {
        checked: this.state.selectedTimeFormat === label,
        label: this.getParsedLabel(label, this.state.timeRange),
        name: "time-selector",
        value: label,
        onChange: this.handleRadioChange,
        key: label
      });
    });
  }
  componentDidMount() {
    M.safeShowDialog(this.dialogName, () => {
      $(document.body).rebind('keydown.historyRetentionDialog', e => {
        const key = e.keyCode || e.which;
        if (key === 13) {
          this.handleOnSubmit(e);
        }
      });
    });
  }
  componentWillUnmount() {
    $(document.body).off('keydown.historyRetentionDialog');
    if ($.dialog === this.dialogName) {
      closeDialog();
    }
  }
  render() {
    const {
      chatRoom,
      onClose
    } = this.props;
    const {
      selectedTimeFormat,
      timeRange
    } = this.state;
    return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
      chatRoom,
      onClose,
      dialogName: this.dialogName,
      dialogType: "tool",
      onClick: () => this.inputRef.current.focus()
    }), REaCt().createElement("header", null, REaCt().createElement("h2", {
      id: "msg-retention-dialog-title"
    }, l[23434])), REaCt().createElement("section", {
      className: "content"
    }, REaCt().createElement("div", {
      className: "content-block"
    }, REaCt().createElement("p", null, l[23435])), REaCt().createElement("div", {
      className: "content-block form"
    }, REaCt().createElement("div", {
      className: "form-section"
    }, REaCt().createElement("span", {
      className: "form-section-placeholder"
    }, this.getParsedLabel(selectedTimeFormat, timeRange)), REaCt().createElement("input", {
      type: "number",
      min: "0",
      step: "1",
      max: this.getMaxTimeRange(selectedTimeFormat),
      className: "form-section-time",
      placeholder: this.getMaxTimeRange(selectedTimeFormat),
      ref: this.inputRef,
      autoFocus: true,
      value: timeRange,
      onChange: this.handleOnTimeChange,
      onKeyPress: this.handleOnTimeCheck,
      onPaste: this.handleOnTimeCheck
    })), REaCt().createElement("div", {
      className: "form-section"
    }, REaCt().createElement("div", {
      className: "form-section-radio"
    }, this.renderCustomRadioButton())))), REaCt().createElement("footer", null, REaCt().createElement("div", {
      className: "footer-container"
    }, REaCt().createElement("button", {
      className: "mega-button",
      onClick: onClose
    }, REaCt().createElement("span", null, l.msg_dlg_cancel)), REaCt().createElement("button", {
      className: `
                                mega-button positive
                                ${this.hasInput() ? '' : 'disabled'}
                            `,
      onClick: e => this.handleOnSubmit(e)
    }, REaCt().createElement("span", null, l[726])))));
  }
}
function CustomRadioButton({
  checked = false,
  label,
  name,
  value,
  onChange
}) {
  return REaCt().createElement("label", {
    key: value,
    className: "radio-txt"
  }, label, REaCt().createElement("div", {
    className: `custom-radio small green-active ${  checked ? "radioOn" : "radioOff"}`
  }, REaCt().createElement("input", {
    type: "radio",
    name,
    value,
    checked,
    onChange
  })));
}
// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
const dropdowns = REQ_(911);
// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
const ui_contacts = REQ_(251);
// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
const perfectScrollbar = REQ_(486);
;// ./js/ui/accordion.jsx
const React = REQ_(594);

class AccordionPanel extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = React.createRef();
  }
  render() {
    const {
      accordionClass,
      expanded,
      title,
      className,
      children,
      onToggle
    } = this.props;
    return React.createElement("div", {
      ref: this.domRef,
      className: `
                    chat-dropdown
                    container
                    ${accordionClass || ''}
                `
    }, React.createElement("div", {
      className: `
                        chat-dropdown
                        header
                        ${expanded ? 'expanded' : ''}
                    `,
      onClick: onToggle
    }, React.createElement("span", null, title), React.createElement("i", {
      className: "sprite-fm-mono icon-arrow-down"
    })), expanded ? React.createElement("div", {
      className: `
                            chat-dropdown
                            content
                            have-animation
                            ${className | ''}
                        `
    }, children) : null);
  }
}
class Accordion extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = React.createRef();
    this.state = {
      expandedPanel: this.props.expandedPanel
    };
  }
  onToggle(e, key) {
    const obj = {};
    obj[key] = !(this.state.expandedPanel || {})[key];
    this.setState({
      'expandedPanel': obj
    });
    this.props.onToggle && this.props.onToggle(key);
  }
  render() {
    const self = this;
    const classes = `accordion-panels ${  self.props.className ? self.props.className : ''}`;
    const accordionPanels = [];
    let x = 0;
    React.Children.forEach(self.props.children, child => {
      if (!child) {
        return;
      }
      if (child.type.name === 'AccordionPanel' || child.type.name && child.type.name.indexOf('AccordionPanel') > -1) {
        accordionPanels.push(React.cloneElement(child, {
          key: child.key,
          expanded: !!self.state.expandedPanel[child.key],
          accordion: self,
          onToggle (e) {
            self.onToggle(e, child.key);
          }
        }));
      } else {
        accordionPanels.push(React.cloneElement(child, {
          key: x++,
          accordion: self
        }));
      }
    });
    return React.createElement("div", {
      ref: this.domRef,
      className: classes
    }, accordionPanels);
  }
}

;// ./js/chat/ui/participantsList.jsx


const DropdownsUI = REQ_(911);
const ContactsUI = REQ_(251);
const PerfectScrollbar = REQ_(486).O;
class ParticipantsList extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.state = {
      'scrollPositionY': 0,
      'scrollHeight': 144
    };
    this.doResizesOnComponentUpdate = SoonFc(10, function () {
      let _self$domRef;
      const self = this;
      if (!self.isMounted()) {
        return;
      }
      let fitHeight = self.contactsListScroll.getContentHeight();
      if (!fitHeight) {
        return null;
      }
      const $node = $((_self$domRef = self.domRef) == null ? void 0 : _self$domRef.current);
      const $parentContainer = $node.closest('.chat-right-pad');
      const maxHeight = $parentContainer.outerHeight(true) - $('.chat-right-head', $parentContainer).outerHeight(true) - 72;
      if (fitHeight < $('.buttons-block', $parentContainer).outerHeight(true)) {
        fitHeight = Math.max(fitHeight, 53);
      } else if (maxHeight < fitHeight) {
        fitHeight = Math.max(maxHeight, 53);
      }
      fitHeight = Math.min(self.calculateListHeight($parentContainer), fitHeight);
      const $contactsList = $('.chat-contacts-list', $parentContainer);
      if ($contactsList.height() !== fitHeight) {
        $('.chat-contacts-list', $parentContainer).height(fitHeight);
        if (self.contactsListScroll) {
          self.contactsListScroll.reinitialise();
        }
      }
      if (self.state.scrollHeight !== fitHeight) {
        self.setState({
          'scrollHeight': fitHeight
        });
      }
      self.onUserScroll();
    });
  }
  onUserScroll() {
    if (!this.contactsListScroll) {
      return;
    }
    const scrollPosY = this.contactsListScroll.getScrollPositionY();
    if (this.state.scrollPositionY !== scrollPosY) {
      this.setState({
        'scrollPositionY': scrollPosY
      });
    }
  }
  calculateListHeight($parentContainer) {
    const room = this.props.chatRoom;
    return ($parentContainer ? $parentContainer : $('.conversationsApp')).outerHeight() - 144 - 10 - (room.type === "public" && room.observers > 0 ? 48 : 0) - (room.isReadOnly() ? 12 : 0);
  }
  componentDidUpdate() {
    const self = this;
    if (!self.isMounted()) {
      return;
    }
    if (!self.contactsListScroll) {
      return null;
    }
    self.doResizesOnComponentUpdate();
  }
  render() {
    const {
      chatRoom
    } = this.props;
    if (!chatRoom) {
      return null;
    }
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "chat-contacts-list"
    }, REaCt().createElement(PerfectScrollbar, {
      chatRoom,
      members: chatRoom.members,
      ref: ref => {
        this.contactsListScroll = ref;
      },
      disableCheckingVisibility: true,
      onUserScroll: SoonFc(this.onUserScroll.bind(this), 76),
      requiresUpdateOnResize: true,
      isVisible: chatRoom.isCurrentlyActive,
      options: {
        suppressScrollX: true
      }
    }, REaCt().createElement(ParticipantsListInner, {
      chatRoom,
      members: chatRoom.members,
      scrollPositionY: this.state.scrollPositionY,
      scrollHeight: this.state.scrollHeight,
      disableCheckingVisibility: true
    })));
  }
}
ParticipantsList.defaultProps = {
  'requiresUpdateOnResize': true,
  'contactCardHeight': 36
};
class ParticipantsListInner extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
  }
  render() {
    const room = this.props.chatRoom;
    const {contactCardHeight} = this.props;
    const {scrollPositionY} = this.props;
    const {scrollHeight} = this.props;
    const {
      OPERATOR,
      FULL,
      READONLY
    } = ChatRoom.MembersSet.PRIVILEGE_STATE;
    if (!room) {
      return null;
    }
    if (!room.isCurrentlyActive) {
      return false;
    }
    const contacts = room.getParticipantsExceptMe();
    const contactsList = [];
    const firstVisibleUserNum = Math.floor(scrollPositionY / contactCardHeight);
    const visibleUsers = Math.ceil(scrollHeight / contactCardHeight);
    const contactListInnerStyles = {
      'height': contacts.length * contactCardHeight
    };
    if ((room.type === "group" || room.type === "public") && !room.stateIsLeftOrLeaving() && room.members.hasOwnProperty(u_handle)) {
      contacts.unshift(u_handle);
      contactListInnerStyles.height += contactCardHeight;
    }
    const onRemoveClicked = contactHash => {
      room.trigger('onRemoveUserRequest', [contactHash]);
    };
    const onSetPrivClicked = (contactHash, priv) => {
      if (room.members[contactHash] !== priv) {
        room.trigger('alterUserPrivilege', [contactHash, priv]);
      }
    };
    for (let i = 0; i < contacts.length; i++) {
      const contactHash = contacts[i];
      if (!(contactHash in M.u)) {
        continue;
      }
      const contact = M.u[contactHash];
      if (i < firstVisibleUserNum || i > firstVisibleUserNum + visibleUsers) {
        continue;
      }
      const dropdowns = [];
      let dropdownIconClasses = "small-icon tiny-icon icons-sprite grey-dots";
      const dropdownRemoveButton = [];
      if (room.type === "public" || room.type === "group" && room.members) {
        if (room.iAmOperator() && contactHash !== u_handle) {
          dropdownRemoveButton.push(REaCt().createElement(DropdownsUI.DropdownItem, {
            className: "red",
            key: "remove",
            icon: "sprite-fm-mono icon-disabled-filled",
            label: l[8867],
            onClick: onRemoveClicked.bind(this, contactHash)
          }));
        }
        if (room.iAmOperator()) {
          dropdowns.push(REaCt().createElement("div", {
            key: "setPermLabel",
            className: "dropdown-items-info"
          }, l[8868]));
          dropdowns.push(REaCt().createElement(DropdownsUI.DropdownItem, {
            key: "privOperator",
            icon: "sprite-fm-mono icon-admin-outline",
            label: l[8875],
            className: `
                                tick-item
                                ${room.members[contactHash] === OPERATOR ? 'active' : ''}
                            `,
            disabled: contactHash === u_handle,
            onClick: () => onSetPrivClicked(contactHash, OPERATOR)
          }));
          dropdowns.push(REaCt().createElement(DropdownsUI.DropdownItem, {
            key: "privFullAcc",
            icon: "sprite-fm-mono icon-chat",
            className: `
                                tick-item
                                ${room.members[contactHash] === FULL ? 'active' : ''}
                            `,
            disabled: contactHash === u_handle,
            label: l[8874],
            onClick: () => onSetPrivClicked(contactHash, FULL)
          }));
          dropdowns.push(REaCt().createElement(DropdownsUI.DropdownItem, {
            key: "privReadOnly",
            icon: "sprite-fm-mono icon-read-only",
            className: `
                                tick-item
                                ${room.members[contactHash] === READONLY ? 'active' : ''}
                            `,
            disabled: contactHash === u_handle,
            label: l[8873],
            onClick: () => onSetPrivClicked(contactHash, READONLY)
          }));
        }
        const baseClassName = 'sprite-fm-mono';
        switch (room.members[contactHash]) {
          case OPERATOR:
            dropdownIconClasses = `${baseClassName} icon-admin`;
            break;
          case FULL:
            dropdownIconClasses = `${baseClassName} icon-chat-filled`;
            break;
          case READONLY:
            dropdownIconClasses = `${baseClassName} icon-read-only`;
            break;
          default:
            break;
        }
        contactsList.push(REaCt().createElement(ContactsUI.ContactCard, {
          key: contact.u,
          contact,
          chatRoom: room,
          className: "right-chat-contact-card",
          dropdownPositionMy: "left top",
          dropdownPositionAt: "left top",
          dropdowns,
          dropdownDisabled: contactHash === u_handle || is_chatlink || is_eplusplus,
          dropdownButtonClasses: "contacts-icon",
          dropdownRemoveButton,
          dropdownIconClasses,
          noLoading: true,
          isInCall: room.uniqueCallParts && room.uniqueCallParts[contactHash],
          style: {
            width: 234,
            position: 'absolute',
            top: i * contactCardHeight
          }
        }));
      }
    }
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "chat-contacts-list-inner default-bg",
      style: contactListInnerStyles
    }, contactsList);
  }
}
ParticipantsListInner.defaultProps = {
  requiresUpdateOnResize: true,
  contactCardHeight: 32,
  scrollPositionY: 0,
  scrollHeight: 128,
  chatRoom: undefined
};

// EXTERNAL MODULE: ./js/chat/ui/messages/generic.jsx + 14 modules
const generic = REQ_(890);
;// ./js/chat/ui/sharedFilesAccordionPanel.jsx

let _dec, _class;
const sharedFilesAccordionPanel_React = REQ_(594);


class SharedFileItem extends mixins.u9 {
  render() {
    const self = this;
    const {message} = this.props;
    const contact = Message.getContactForMessage(message);
    const name = M.getNameByHandle(contact.u);
    const timestamp = time2date(message.delay);
    const {node} = this.props;
    const {icon} = this.props;
    return sharedFilesAccordionPanel_React.createElement("div", {
      className: `chat-shared-block ${  self.props.isLoading ? "is-loading" : ""}`,
      key: `${message.messageId  }_${  node.h}`,
      onClick: () => this.props.isPreviewable ? M.viewMediaFile(node) : M.addDownload([node]),
      onDoubleClick: () => M.addDownload([node])
    }, sharedFilesAccordionPanel_React.createElement("div", {
      className: `icon-or-thumb ${thumbnails.has(node.fa) ? "thumb" : ""}`
    }, sharedFilesAccordionPanel_React.createElement("div", {
      className: `item-type-icon-90 icon-${icon}-90`
    }), sharedFilesAccordionPanel_React.createElement("div", {
      className: "img-wrapper",
      id: this.props.imgId
    }, sharedFilesAccordionPanel_React.createElement("img", {
      alt: "",
      src: thumbnails.get(node.fa) || ""
    }))), sharedFilesAccordionPanel_React.createElement("div", {
      className: "chat-shared-info"
    }, sharedFilesAccordionPanel_React.createElement("span", {
      className: "txt"
    }, node.name), sharedFilesAccordionPanel_React.createElement("span", {
      className: "txt small"
    }, sharedFilesAccordionPanel_React.createElement(utils.zT, null, name)), sharedFilesAccordionPanel_React.createElement("span", {
      className: "txt small grey"
    }, timestamp)));
  }
}
const SharedFilesAccordionPanel = (_dec = utils.Ay.SoonFcWrap(350), _class = class SharedFilesAccordionPanel extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = sharedFilesAccordionPanel_React.createRef();
  }
  eventuallyRenderThumbnails() {
    if (this.allShownNodes) {
      const pending = [];
      const nodes = new Map(this.allShownNodes);
      const render = n => {
        if (thumbnails.has(n.fa)) {
          const src = thumbnails.get(n.fa);
          const batch = [...nodes.get(n.fa)];
          for (let i = batch.length; i--;) {
            const n = batch[i];
            let img = document.getElementById(`sharedFiles!${n.ch}`);
            if (img && (img = img.querySelector('img'))) {
              img.src = src;
              if (img = Object(img.parentNode).parentNode) {
                img.classList.add('thumb');
              }
            }
          }
          return true;
        }
      };
      for (const [, [n]] of nodes) {
        if (!render(n)) {
          pending.push(n);
        }
      }
      this.allShownNodes.clear();
      if (pending.length) {
        fm_thumbnails('standalone', pending, render);
      }
    }
  }
  UNSAFE_componentWillMount() {
    this.allShownNodes = new MapSet();
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    delete this.allShownNodes;
  }
  componentDidUpdate() {
    this.eventuallyRenderThumbnails();
  }
  render() {
    const self = this;
    const room = self.props.chatRoom;
    const mb = room.messagesBuff;
    let contents = null;
    let currentPage = mb.sharedFilesPage;
    const startPos = currentPage * 12;
    const endPos = startPos + 12;
    let totalPages = mb.haveMoreSharedFiles ? "..." : Math.ceil(mb.sharedFiles.length / 12);
    totalPages = mb.sharedFiles.length && !totalPages ? 1 : totalPages;
    const haveMore = mb.haveMoreSharedFiles || currentPage + 1 < totalPages;
    const files = [];
    if (!mb.haveMoreSharedFiles && currentPage === totalPages) {
      currentPage = mb.sharedFilesPage = Math.max(totalPages - 1, 0);
    }
    if (this.props.expanded) {
      let prev = null;
      let next = null;
      if (currentPage > 0) {
        prev = sharedFilesAccordionPanel_React.createElement("div", {
          className: "chat-share-nav button prev",
          onClick () {
            mb.sharedFilesPage--;
            self.safeForceUpdate();
          }
        });
      }
      if (haveMore) {
        next = sharedFilesAccordionPanel_React.createElement("div", {
          className: "chat-share-nav button next",
          onClick () {
            if (self.isLoadingMore) {
              return;
            }
            if (mb.sharedFiles.length < endPos + 12) {
              self.isLoadingMore = true;
              mb.retrieveSharedFilesHistory(12).catch(dump).finally(() => {
                self.isLoadingMore = false;
                mb.sharedFilesPage++;
                if (!mb.haveMoreSharedFiles && mb.sharedFilesPage > totalPages) {
                  mb.sharedFilesPage = totalPages - 1;
                }
                Soon(() => {
                  self.safeForceUpdate();
                });
              });
            } else {
              mb.sharedFilesPage++;
            }
            Soon(() => {
              self.safeForceUpdate();
            });
          }
        });
      }
      if (!mb.sharedFilesLoadedOnce) {
        mb.retrieveSharedFilesHistory(12).then(() => this.safeForceUpdate()).catch(dump);
      }
      let sharedNodesContainer = null;
      if (mb.isRetrievingSharedFiles && !self.isLoadingMore) {
        sharedNodesContainer = sharedFilesAccordionPanel_React.createElement("div", {
          className: "chat-dropdown empty-txt loading-initial"
        }, sharedFilesAccordionPanel_React.createElement("div", {
          className: "loading-spinner light small"
        }, sharedFilesAccordionPanel_React.createElement("div", {
          className: "main-loader"
        })));
      } else if (!mb.haveMoreSharedFiles && !mb.sharedFiles.length) {
        sharedNodesContainer = sharedFilesAccordionPanel_React.createElement("div", {
          className: "chat-dropdown empty-txt"
        }, l[19985]);
      } else {
        const keys = clone(mb.sharedFiles.keys()).reverse();
        for (let i = startPos; i < endPos; i++) {
          var message = mb.sharedFiles[keys[i]];
          if (!message) {
            continue;
          }
          const nodes = message.getAttachmentMeta();
          nodes.forEach((node) => {
            const imgId = `sharedFiles!${  node.ch}`;
            const {
              icon,
              showThumbnail,
              isPreviewable
            } = M.getMediaProperties(node);
            files.push(sharedFilesAccordionPanel_React.createElement(SharedFileItem, {
              message,
              key: `${node.h}_${message.messageId}`,
              isLoading: self.isLoadingMore,
              node,
              icon,
              imgId,
              showThumbnail,
              isPreviewable,
              chatRoom: room,
              contact: Message.getContactForMessage(message)
            }));
            if (showThumbnail) {
              self.allShownNodes.set(node.fa, node);
            }
          });
        }
        sharedNodesContainer = sharedFilesAccordionPanel_React.createElement("div", null, files);
      }
      contents = sharedFilesAccordionPanel_React.createElement("div", {
        className: "chat-dropdown content have-animation"
      }, room.hasMessages() ? sharedNodesContainer : sharedFilesAccordionPanel_React.createElement("div", {
        className: "chat-dropdown empty-txt"
      }, l[19985]), self.isLoadingMore ? sharedFilesAccordionPanel_React.createElement("div", {
        className: "loading-spinner light small"
      }, sharedFilesAccordionPanel_React.createElement("div", {
        className: "main-loader"
      })) : null, files.length > 0 ? sharedFilesAccordionPanel_React.createElement("div", {
        className: "chat-share-nav body"
      }, prev, next, sharedFilesAccordionPanel_React.createElement("div", {
        className: "chat-share-nav pages"
      }, (l[19988] ? l[19988] : "Page %1").replace("%1", currentPage + 1))) : null);
    }
    return sharedFilesAccordionPanel_React.createElement("div", {
      ref: this.domRef,
      className: "chat-dropdown container"
    }, sharedFilesAccordionPanel_React.createElement("div", {
      className: `
                        chat-dropdown
                        header
                        ${this.props.expanded ? 'expanded' : ''}
                    `,
      onClick: this.props.onToggle
    }, sharedFilesAccordionPanel_React.createElement("span", null, this.props.title), sharedFilesAccordionPanel_React.createElement("i", {
      className: "sprite-fm-mono icon-arrow-down"
    })), sharedFilesAccordionPanel_React.createElement("div", {
      className: `
                        chat-shared-files-container
                        ${this.isLoadingMore ? 'is-loading' : ''}
                    `
    }, contents));
  }
}, (0,applyDecoratedDescriptor.A)(_class.prototype, "eventuallyRenderThumbnails", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyRenderThumbnails"), _class.prototype), _class);

;// ./js/chat/ui/incomingSharesAccordionPanel.jsx
const incomingSharesAccordionPanel_React = REQ_(594);

const SharedFolderItem = ({
  node,
  isLoading
}) => {
  return incomingSharesAccordionPanel_React.createElement("div", {
    key: node.h,
    className: `
                chat-shared-block
                incoming
                ${isLoading ? 'is-loading' : ''}
            `,
    onClick: () => M.openFolder(node.h),
    onDoubleClick: () => M.openFolder(node.h)
  }, incomingSharesAccordionPanel_React.createElement("div", {
    className: "item-type-icon-90 icon-folder-incoming-90"
  }), incomingSharesAccordionPanel_React.createElement("div", {
    className: "chat-shared-info"
  }, incomingSharesAccordionPanel_React.createElement("span", {
    className: "txt"
  }, node.name), incomingSharesAccordionPanel_React.createElement("span", {
    className: "txt small"
  }, fm_contains(node.tf, node.td))));
};
class IncSharesAccordionPanel extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = incomingSharesAccordionPanel_React.createRef();
  }
  UNSAFE_componentWillMount() {
    this.hadLoaded = false;
  }
  getContactHandle() {
    const self = this;
    const room = self.props.chatRoom;
    const contactHandle = room.getParticipantsExceptMe()[0];
    if (!contactHandle || room.type !== "private") {
      return {};
    }
    return contactHandle;
  }
  render() {
    const self = this;
    const room = self.props.chatRoom;
    const contactHandle = self.getContactHandle();
    let contents = null;
    if (this.props.expanded) {
      if (!this.hadLoaded) {
        this.hadLoaded = true;
        self.isLoadingMore = true;
        dbfetch.geta(Object.keys(M.c.shares || {}), new MegaPromise()).always(() => {
          self.isLoadingMore = false;
          Soon(() => {
            if (self.isComponentEventuallyVisible()) {
              self.safeForceUpdate();
            }
          }, 5000);
        });
      }
      let incomingSharesContainer = null;
      const sharedFolders = M.c[contactHandle] && Object.keys(M.c[contactHandle]) || [];
      if (!self.isLoadingMore && (!sharedFolders || sharedFolders.length === 0)) {
        incomingSharesContainer = incomingSharesAccordionPanel_React.createElement("div", {
          className: "chat-dropdown empty-txt"
        }, l[19986]);
      } else {
        const haveMore = sharedFolders.length > 10;
        const defSortFn = M.getSortByNameFn();
        sharedFolders.sort((a, b) => {
          const nodeA = M.d[a];
          const nodeB = M.d[b];
          return defSortFn(nodeA, nodeB, -1);
        });
        const renderNodes = [];
        for (let i = 0; i < Math.min(sharedFolders.length, 10); i++) {
          const nodeHandle = sharedFolders[i];
          const node = M.d[nodeHandle];
          if (!node) {
            continue;
          }
          renderNodes.push(incomingSharesAccordionPanel_React.createElement(SharedFolderItem, {
            key: node.h,
            isLoading: self.isLoadingMore,
            node,
            chatRoom: room
          }));
        }
        incomingSharesContainer = incomingSharesAccordionPanel_React.createElement("div", null, renderNodes, haveMore ? incomingSharesAccordionPanel_React.createElement("div", {
          className: "chat-share-nav body"
        }, incomingSharesAccordionPanel_React.createElement("div", {
          className: "chat-share-nav show-all",
          onClick () {
            M.openFolder(contactHandle);
          }
        }, incomingSharesAccordionPanel_React.createElement("span", {
          className: "item-type-icon icon-folder-incoming-24"
        }, incomingSharesAccordionPanel_React.createElement("span", {
          className: "item-type-icon icon-folder-incoming-24"
        })), incomingSharesAccordionPanel_React.createElement("span", {
          className: "txt"
        }, l[19797] ? l[19797] : "Show All"))) : null);
      }
      contents = incomingSharesAccordionPanel_React.createElement("div", {
        className: "chat-dropdown content have-animation"
      }, incomingSharesContainer, self.isLoadingMore ? incomingSharesAccordionPanel_React.createElement("div", {
        className: "chat-dropdown empty-txt"
      }, incomingSharesAccordionPanel_React.createElement("div", {
        className: "loading-spinner light small"
      }, incomingSharesAccordionPanel_React.createElement("div", {
        className: "main-loader"
      }))) : null);
    }
    return incomingSharesAccordionPanel_React.createElement("div", {
      ref: this.domRef,
      className: "chat-dropdown container"
    }, incomingSharesAccordionPanel_React.createElement("div", {
      className: `
                        chat-dropdown
                        header
                        ${this.props.expanded ? 'expanded' : ''}
                    `,
      onClick: this.props.onToggle
    }, incomingSharesAccordionPanel_React.createElement("span", null, this.props.title), incomingSharesAccordionPanel_React.createElement("i", {
      className: "sprite-fm-mono icon-arrow-down"
    })), incomingSharesAccordionPanel_React.createElement("div", {
      className: `
                        chat-shared-files-container
                        ${this.isLoadingMore ? 'is-loading' : ''}
                    `
    }, contents));
  }
}

;// ./js/chat/ui/chatlinkDialog.jsx




class ChatlinkDialog extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.state = {
      link: l[5533],
      newTopic: ''
    };
    this.onClose = () => {
      if (this.props.onClose) {
        this.props.onClose();
      }
    };
  }
  retrieveChatLink(forced) {
    const {
      chatRoom
    } = this.props;
    if (is_chatlink) {
      return this.setState({
        link: `${getBaseUrl()}/chat/${is_chatlink.ph}#${is_chatlink.key}`
      });
    }
    if (!chatRoom.topic && !forced) {
      delete this.loading;
      return;
    }
    this.loading = chatRoom.updatePublicHandle(false, true).always(() => {
      this.loading = false;
      if (this.domRef.current) {
        this.setState({
          link: chatRoom.publicLink ? `${getBaseUrl()}/${chatRoom.publicLink}` : l[20660]
        });
      }
    });
  }
  componentDidMount() {
    this.retrieveChatLink();
    M.safeShowDialog(ChatlinkDialog.NAMESPACE, () => {
      if (!this.domRef.current) {
        throw new Error(`${ChatlinkDialog.NAMESPACE} dialog: component not mounted.`);
      }
      return $(`#${ChatlinkDialog.NAMESPACE}`);
    });
  }
  componentWillUnmount() {
    if ($.dialog === ChatlinkDialog.NAMESPACE) {
      closeDialog();
    }
  }
  render() {
    const {
      chatRoom
    } = this.props;
    const {
      newTopic,
      link
    } = this.state;
    const closeButton = this.loading ? null : REaCt().createElement("button", {
      key: "close",
      className: "mega-button negative links-button",
      onClick: this.onClose
    }, REaCt().createElement("span", null, l[148]));
    const publicLinkDetails = chatRoom.isMeeting ? l.meeting_link_details : l[20644];
    return REaCt().createElement("div", {
      ref: this.domRef
    }, REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
      id: ChatlinkDialog.NAMESPACE,
      title: chatRoom.iAmOperator() && !chatRoom.topic ? chatRoom.isMeeting ? l.rename_meeting : l[9080] : '',
      className: `
                        chat-rename-dialog
                        export-chat-links-dialog
                        group-chat-link
                        ${chatRoom.topic ? '' : 'requires-topic'}
                    `,
      onClose: this.onClose,
      dialogName: "chat-link-dialog",
      dialogType: chatRoom.iAmOperator() && !chatRoom.topic ? 'main' : 'graphic',
      chatRoom,
      popupDidMount: this.onPopupDidMount
    }), chatRoom.iAmOperator() && !chatRoom.topic ? REaCt().createElement("section", {
      className: "content"
    }, REaCt().createElement("div", {
      className: "content-block"
    }, REaCt().createElement("div", {
      className: "export-chat-ink-warning"
    }, l[20617]), REaCt().createElement("div", {
      className: "rename-input-bl",
      style: {
        margin: '10px auto 20px auto'
      }
    }, REaCt().createElement("input", {
      type: "text",
      name: "newTopic",
      value: newTopic,
      style: {
        paddingLeft: 8
      },
      onChange: ev => this.setState({
        newTopic: ev.target.value
      }),
      onKeyPress: ev => ev.which === 13 && chatRoom.setRoomTopic(newTopic).then(() => this.retrieveChatLink(true)).catch(dump),
      placeholder: l[20616],
      maxLength: ChatRoom.TOPIC_MAX_LENGTH
    })))) : REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("header", null, chatRoom.isMeeting ? REaCt().createElement("div", {
      className: "chat-topic-icon meeting-icon"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-video-call-filled"
    })) : REaCt().createElement("i", {
      className: "sprite-fm-uni icon-chat-group"
    }), REaCt().createElement("h2", {
      id: "chat-link-dialog-title"
    }, REaCt().createElement(utils.zT, null, chatRoom.getRoomTitle()))), REaCt().createElement("section", {
      className: "content"
    }, REaCt().createElement("div", {
      className: "content-block"
    }, REaCt().createElement("div", {
      className: "chat-link-input"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-link-small"
    }), REaCt().createElement("input", {
      type: "text",
      readOnly: true,
      value: this.loading ? l[5533] : !chatRoom.topic ? l[20660] : link
    })), REaCt().createElement("div", {
      className: "info"
    }, chatRoom.publicLink || is_chatlink ? publicLinkDetails : null)))), REaCt().createElement("footer", null, REaCt().createElement("div", {
      className: "footer-container"
    }, chatRoom.iAmOperator() && chatRoom.publicLink && REaCt().createElement("button", {
      key: "deleteLink",
      className: `
                                        mega-button
                                        links-button
                                        ${this.loading ? 'disabled' : ''}
                                    `,
      onClick: () => {
        chatRoom.updatePublicHandle(1);
        this.onClose();
      }
    }, REaCt().createElement("span", null, chatRoom.isMeeting ? l.meeting_link_delete : l[20487])), chatRoom.topic ? chatRoom.publicLink || is_chatlink ? REaCt().createElement("button", {
      className: `
                                            mega-button
                                            positive
                                            copy-to-clipboard
                                            ${this.loading ? 'disabled' : ''}
                                        `,
      onClick: () => {
        copyToClipboard(link, l[7654]);
        if (chatRoom.isMeeting) {
          eventlog(500231);
        }
      }
    }, REaCt().createElement("span", null, l[63])) : closeButton : chatRoom.iAmOperator() ? REaCt().createElement("button", {
      key: "setTopic",
      className: `
                                            mega-button
                                            positive
                                            links-button
                                            ${newTopic && newTopic.trim() ? '' : 'disabled'}
                                        `,
      onClick: () => chatRoom.setRoomTopic(newTopic).then(() => this.retrieveChatLink(true)).catch(dump)
    }, REaCt().createElement("span", null, l[20615])) : closeButton))));
  }
}
ChatlinkDialog.defaultProps = {
  requiresUpdateOnResize: true,
  disableCheckingVisibility: true
};
ChatlinkDialog.NAMESPACE = 'chat-link-dialog';
;// ./js/chat/ui/pushSettingsDialog.jsx

let _PushSettingsDialog;


class PushSettingsDialog extends REaCt().Component {
  constructor(props) {
    super(props);
    this.renderOptions = () => {
      return Object.keys(PushSettingsDialog.options).map(key => {
        key = parseInt(key, 10) || Infinity;
        return REaCt().createElement("label", {
          key,
          className: "radio-txt"
        }, PushSettingsDialog.options[key], REaCt().createElement("div", {
          className: `custom-radio small green-active ${  this.state.pushSettingsValue === key ? "radioOn" : "radioOff"}`
        }, REaCt().createElement("input", {
          type: "radio",
          name: "time-selector",
          value: key,
          checked: this.state.pushSettingsValue === key,
          onChange: () => this.setState({
            pushSettingsValue: key
          })
        })));
      });
    };
    this.state = {
      pushSettingsValue: this.props.pushSettingsValue || Infinity
    };
  }
  render() {
    return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
      name: "push-settings",
      title: l.dnd_mute_title,
      subtitle: this.props.room.isMeeting ? l.meeting_dnd_subtitle : l[22015],
      className: "push-settings-dialog",
      dialogName: "push-settings-chat-dialog",
      dialogType: "tool",
      onClose: this.props.onClose
    }), REaCt().createElement("section", {
      className: "content"
    }, REaCt().createElement("div", {
      className: "content-block"
    }, REaCt().createElement("div", null, this.renderOptions()))), REaCt().createElement("footer", null, REaCt().createElement("div", {
      className: "footer-container"
    }, REaCt().createElement("button", {
      className: "mega-button",
      onClick: this.props.onClose
    }, REaCt().createElement("span", null, l.msg_dlg_cancel)), REaCt().createElement("button", {
      className: "mega-button positive",
      onClick: () => this.props.onConfirm(this.state.pushSettingsValue)
    }, REaCt().createElement("span", null, l[726])))));
  }
}
_PushSettingsDialog = PushSettingsDialog;
PushSettingsDialog.options = {
  30: l[22012],
  60: l[19048],
  360: l[22013],
  1440: l[22014],
  Infinity: l[22011]
};
PushSettingsDialog.default = _PushSettingsDialog.options[_PushSettingsDialog.options.length - 1];
// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
const call = REQ_(3);
// EXTERNAL MODULE: ./js/chat/ui/historyPanel.jsx + 7 modules
const historyPanel = REQ_(814);
// EXTERNAL MODULE: ./js/chat/ui/composedTextArea.jsx + 1 modules
const composedTextArea = REQ_(77);
;// ./js/chat/ui/meetings/workflow/loading.jsx

class Loading extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.PERMISSIONS = {
      VIDEO: 'camera',
      AUDIO: 'microphone'
    };
    this.state = {
      pendingPermissions: false
    };
    this.queryPermissions = name => {
      navigator.permissions.query({
        name
      }).then(status => {
        const {
          name,
          state
        } = status;
        status.onchange = () => name === 'audio_capture' && this.queryPermissions(this.PERMISSIONS.VIDEO);
        if (state === 'prompt') {
          return this.domRef.current && this.setState({
            pendingPermissions: name
          });
        }
      }).catch(ex => console.warn(`Failed to get permissions state: ${ex}`));
    };
    this.renderLoading = () => {
      return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("span", null, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-video-call-filled"
      })), REaCt().createElement("h3", null, this.props.title || l[5533]), REaCt().createElement("div", {
        className: "loading-container"
      }, REaCt().createElement("div", {
        className: "loading-indication"
      })));
    };
    this.renderDebug = () => {
      const {
        chatRoom
      } = this.props;
      if (chatRoom && chatRoom.call) {
        return REaCt().createElement("div", {
          className: `${Loading.NAMESPACE}-debug`
        }, REaCt().createElement("div", null, "callId: ", chatRoom.call.callId), REaCt().createElement("div", null, "roomId: ", chatRoom.roomId), REaCt().createElement("div", null, "isMeeting: ", chatRoom.isMeeting ? 'true' : 'false'));
      }
    };
  }
  componentWillUnmount() {
    megaChat.unbind(`onLocalMediaQueryError.${Loading.NAMESPACE}`);
  }
  componentDidMount() {
    let _notify, _alarm;
    document.dispatchEvent(new Event('closeDropdowns'));
    if ($.dialog) {
      closeDialog == null || closeDialog();
    }
    mega.ui.mInfoPanel.hide();
    (_notify = notify) == null || _notify.closePopup();
    (_alarm = alarm) == null || _alarm.hideAllWarningPopups();
    document.querySelectorAll('.js-dropdown-account').forEach(({
      classList
    }) => classList.contains('show') && classList.remove('show'));
    const {
      chatRoom
    } = this.props;
    const {
      audio,
      video
    } = chatRoom.meetingsLoading;
    const isVideoCall = audio && video;
    if (audio && !video) {
      this.queryPermissions(this.PERMISSIONS.AUDIO);
    }
    if (isVideoCall) {
      Object.values(this.PERMISSIONS).forEach(name => this.queryPermissions(name));
    }
    megaChat.rebind(`onLocalMediaQueryError.${Loading.NAMESPACE}`, (ev, {
      type,
      err
    }) => {
      if (isVideoCall && type === 'mic' && String(err).includes('dismissed')) {
        this.queryPermissions(this.PERMISSIONS.VIDEO);
      }
    });
  }
  render() {
    const {
      pendingPermissions
    } = this.state;
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: Loading.NAMESPACE
    }, REaCt().createElement("div", {
      className: `${Loading.NAMESPACE}-content`
    }, pendingPermissions ? REaCt().createElement("h2", null, pendingPermissions === 'audio_capture' ? l.permissions_allow_mic : l.permissions_allow_camera) : this.renderLoading()), d ? this.renderDebug() : '');
  }
}
Loading.NAMESPACE = 'meetings-loading';
// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
const meetings_button = REQ_(959);
// EXTERNAL MODULE: ./js/chat/ui/meetings/workflow/preview.jsx
const preview = REQ_(485);
// EXTERNAL MODULE: ./js/chat/ui/link.jsx
const ui_link = REQ_(280);
;// ./js/chat/ui/meetings/workflow/join.jsx







class Join extends REaCt().Component {
  constructor(props) {
    super(props);
    this.state = {
      preview: false,
      view: Join.VIEW.INITIAL,
      firstName: '',
      lastName: '',
      previewAudio: true,
      previewVideo: false,
      ephemeralDialog: false
    };
    this.handleKeyDown = ({
      key
    }) => {
      let _this$props$onClose, _this$props;
      return key && key === 'Escape' ? (_this$props$onClose = (_this$props = this.props).onClose) == null ? void 0 : _this$props$onClose.call(_this$props) : true;
    };
    this.showPanels = () => {
      return [document.querySelector('.nw-fm-left-icons-panel'), document.querySelector('.chat-app-container')].map(el => el && el.classList.remove('hidden'));
    };
    this.hidePanels = () => {
      return [document.querySelector('.nw-fm-left-icons-panel'), document.querySelector('.chat-app-container')].map(el => el && el.classList.add('hidden'));
    };
    this.showConfirmationDialog = () => {
      megaChat.destroy();
      return mega.ui.sendSignupLinkDialog(JSON.parse(localStorage.awaitingConfirmationAccount), () => {
        delete localStorage.awaitingConfirmationAccount;
        u_logout(true).then(() => location.reload());
      });
    };
    this.Ephemeral = () => {
      const onCancel = () => this.setState({
        ephemeralDialog: false
      });
      const msgFragments = l.ephemeral_data_lost.split(/\[A]|\[\/A]/);
      return REaCt().createElement(modalDialogs.A.ModalDialog, {
        name: "end-ephemeral",
        dialogType: "message",
        icon: "sprite-fm-uni icon-warning",
        title: l.ephemeral_data_lost_title,
        noCloseOnClickOutside: true,
        buttons: [{
          key: 'cancel',
          label: l.msg_dlg_cancel,
          onClick: onCancel
        }, {
          key: 'continue',
          label: l[507],
          className: 'positive',
          onClick: () => {
            u_logout(true).then(() => location.reload());
            sessionStorage.guestForced = true;
          }
        }],
        onClose: onCancel
      }, REaCt().createElement("p", null, msgFragments[0], REaCt().createElement(ui_link.A, {
        to: "/register",
        onClick: () => loadSubPage('register')
      }, msgFragments[1]), msgFragments[2]));
    };
    this.Head = () => {
      let _this$props$chatRoom;
      return REaCt().createElement("div", {
        className: `${Join.NAMESPACE}-head`
      }, REaCt().createElement("div", {
        className: `${Join.NAMESPACE}-logo`
      }, REaCt().createElement("i", {
        className: `
                            sprite-fm-illustration-wide
                            ${mega.ui.isDarkTheme() ? 'mega-logo-dark' : 'img-mega-logo-light'}
                        `
      })), REaCt().createElement("h1", null, REaCt().createElement(utils.zT, null, l.you_have_invitation.replace('%1', (_this$props$chatRoom = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom.topic))), isEphemeral() && REaCt().createElement("div", {
        className: "ephemeral-info"
      }, REaCt().createElement("i", {
        className: "sprite-fm-uni icon-warning"
      }), REaCt().createElement("p", null, l.ephemeral_data_store_lost)));
    };
    this.Intro = () => {
      const $$CONTAINER = ({
        children
      }) => REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
        className: `${Join.NAMESPACE}-content`
      }, children), this.Chat());
      if (isEphemeral()) {
        return REaCt().createElement($$CONTAINER, null, REaCt().createElement(meetings_button.A, {
          className: "mega-button positive",
          onClick: () => this.setState({
            ephemeralDialog: true
          })
        }, l.join_as_guest), REaCt().createElement(meetings_button.A, {
          className: "mega-button",
          onClick: () => loadSubPage('register')
        }, l[5582]), REaCt().createElement("span", null, l[5585], REaCt().createElement("a", {
          href: "#",
          onClick: () => mega.ui.showLoginRequiredDialog({
            minUserType: 3,
            skipInitialDialog: 1
          }).done(() => this.setState({
            view: Join.VIEW.ACCOUNT
          }))
        }, l[171])));
      }
      return REaCt().createElement($$CONTAINER, null, REaCt().createElement(meetings_button.A, {
        className: "mega-button positive",
        onClick: () => this.setState({
          view: Join.VIEW.GUEST
        })
      }, l.join_as_guest), REaCt().createElement(meetings_button.A, {
        className: "mega-button",
        onClick: () => {
          let _this$props$chatRoom2;
          megaChat.loginOrRegisterBeforeJoining((_this$props$chatRoom2 = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom2.publicChatHandle, false, true, undefined, () => this.setState({
            view: Join.VIEW.ACCOUNT
          }));
        }
      }, l[171]), REaCt().createElement("p", null, REaCt().createElement(utils.P9, {
        onClick: e => {
          e.preventDefault();
          megaChat.loginOrRegisterBeforeJoining(this.props.chatRoom.publicChatHandle, true, undefined, undefined, () => this.setState({
            view: Join.VIEW.ACCOUNT
          }));
        }
      }, l[20635])));
    };
    this.Chat = () => {
      const {
        chatRoom
      } = this.props;
      const {
        preview
      } = this.state;
      return REaCt().createElement("div", {
        className: `
                    ${Join.NAMESPACE}-chat
                    ${preview ? 'expanded' : ''}
                `
      }, REaCt().createElement("div", {
        className: "chat-content"
      }, REaCt().createElement("div", {
        className: "chat-content-head",
        onClick: () => this.setState({
          preview: !preview
        })
      }, REaCt().createElement(utils.zT, null, chatRoom.topic), REaCt().createElement(meetings_button.A, {
        icon: "icon-minimise"
      })), preview && REaCt().createElement("div", {
        className: "chat-body"
      }, REaCt().createElement(historyPanel.A, {
        chatRoom,
        onMount: cmp => {
          let _cmp$messagesListScro;
          return (_cmp$messagesListScro = cmp.messagesListScrollable) == null ? void 0 : _cmp$messagesListScro.scrollToBottom();
        }
      }))));
    };
    this.Card = ({
      children
    }) => {
      const {
        previewAudio,
        previewVideo
      } = this.state;
      return REaCt().createElement("div", {
        className: "card"
      }, REaCt().createElement("div", {
        className: "card-body"
      }, children, REaCt().createElement("div", null, REaCt().createElement(ui_link.A, {
        to: "https://mega.io/chatandmeetings",
        target: "_blank"
      }, l.how_meetings_work))), REaCt().createElement("div", {
        className: "card-preview"
      }, REaCt().createElement(preview.A, {
        audio: previewAudio,
        video: previewVideo,
        context: Join.NAMESPACE,
        onToggle: (audio, video) => this.setState({
          previewAudio: audio,
          previewVideo: video
        })
      })));
    };
    this.Field = ({
      name,
      children
    }) => {
      let _this$state$name;
      return REaCt().createElement("div", {
        className: `
                    mega-input
                    title-ontop
                    ${(_this$state$name = this.state[name]) != null && _this$state$name.length ? 'valued' : ''}
                `
      }, REaCt().createElement("div", {
        className: "mega-input-title"
      }, children, REaCt().createElement("span", {
        className: "required-red"
      }, "*")), REaCt().createElement("input", {
        type: "text",
        name,
        className: "titleTop required megaInputs",
        placeholder: children,
        value: this.state[name] || '',
        maxLength: 40,
        onChange: ev => this.setState({
          [name]: ev.target.value
        })
      }));
    };
    this.Guest = () => REaCt().createElement(this.Card, null, REaCt().createElement("h2", null, l.enter_name_join_meeting), REaCt().createElement("div", {
      className: "card-fields"
    }, REaCt().createElement(this.Field, {
      name: "firstName"
    }, l[1096]), REaCt().createElement(this.Field, {
      name: "lastName"
    }, l[1097])), REaCt().createElement(meetings_button.A, {
      className: `
                    mega-button
                    positive
                    large
                    ${this.state.firstName.length && this.state.lastName.length ? '' : 'disabled'}
                    ${this.state.joining && " loading disabled"}
                `,
      onClick: () => {
        if (this.state.joining) {
          return;
        }
        let {
          firstName,
          lastName,
          previewAudio,
          previewVideo
        } = this.state;
        firstName = firstName && firstName.trim();
        lastName = lastName && lastName.trim();
        if (firstName && lastName && firstName.length > 0 && lastName.length > 0) {
          this.setState({
            'joining': true
          });
          if (this.props.chatRoom.scheduledMeeting) {
            delay('chat-event-sm-guest-join', () => eventlog(99929));
          }
          this.props.onJoinGuestClick(firstName, lastName, previewAudio, previewVideo);
        }
      }
    }, l.join_chat_button));
    this.Account = () => REaCt().createElement(this.Card, null, REaCt().createElement("h4", null, l.join_meeting), REaCt().createElement(meetings_button.A, {
      className: `mega-button positive large ${this.state.joining && " loading disabled"}`,
      onClick: () => {
        if (!this.state.joining) {
          this.setState({
            'joining': true
          });
          this.props.onJoinClick(this.state.previewAudio, this.state.previewVideo);
        }
      }
    }, l.join_chat_button));
    this.Unsupported = () => REaCt().createElement("div", {
      className: "meetings-unsupported-container"
    }, REaCt().createElement("i", {
      className: "sprite-fm-uni icon-error"
    }), REaCt().createElement("div", {
      className: "unsupported-info"
    }, REaCt().createElement("h3", null, l.heading_unsupported_browser), REaCt().createElement("h3", null, l.join_meeting_methods), REaCt().createElement("ul", null, REaCt().createElement("li", null, l.join_via_link), REaCt().createElement("li", null, REaCt().createElement(utils.P9, null, l.join_via_mobile.replace('[A]', '<a href="https://mega.io/mobile" target="_blank" class="clickurl">').replace('[/A]', '</a>'))))));
    this.View = view => {
      switch (view) {
        default:
          return this.Intro();
        case Join.VIEW.GUEST:
          return this.Guest();
        case Join.VIEW.ACCOUNT:
          return this.Account();
        case Join.VIEW.UNSUPPORTED:
          return this.Unsupported();
      }
    };
    this.state.view = sessionStorage.guestForced ? Join.VIEW.GUEST : props.initialView || this.state.view;
    if (localStorage.awaitingConfirmationAccount) {
      this.showConfirmationDialog();
    }
  }
  componentDidMount() {
    document.addEventListener('keydown', this.handleKeyDown);
    this.hidePanels();
    megaChat._joinDialogIsShown = true;
    alarm.hideAllWarningPopups();
    sessionStorage.removeItem('guestForced');
    if (!megaChat.hasSupportForCalls) {
      this.setState({
        view: Join.VIEW.UNSUPPORTED
      });
    }
  }
  componentWillUnmount() {
    document.removeEventListener('keydown', this.handleKeyDown);
    this.showPanels();
    megaChat._joinDialogIsShown = false;
    if (this.props.onClose) {
      this.props.onClose();
    }
  }
  render() {
    const {
      view,
      ephemeralDialog
    } = this.state;
    return REaCt().createElement(utils.Ay.RenderTo, {
      element: document.body
    }, REaCt().createElement("div", {
      className: Join.NAMESPACE
    }, this.Head(), this.View(view), ephemeralDialog && REaCt().createElement(this.Ephemeral, null)));
  }
}
Join.NAMESPACE = 'join-meeting';
Join.VIEW = {
  INITIAL: 0,
  GUEST: 1,
  ACCOUNT: 2,
  UNSUPPORTED: 4
};
;// ./js/chat/ui/meetings/workflow/alert.jsx


const NAMESPACE = 'meetings-alert';
class Alert extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
  }
  componentWillUnmount() {
    let _this$props$onTransit, _this$props;
    super.componentWillUnmount();
    (_this$props$onTransit = (_this$props = this.props).onTransition) == null || _this$props$onTransit.call(_this$props);
  }
  componentDidUpdate() {
    let _this$props$onTransit2, _this$props2;
    super.componentDidUpdate();
    (_this$props$onTransit2 = (_this$props2 = this.props).onTransition) == null || _this$props$onTransit2.call(_this$props2, this.domRef);
  }
  componentDidMount() {
    let _this$props$onTransit3, _this$props3;
    super.componentDidMount();
    (_this$props$onTransit3 = (_this$props3 = this.props).onTransition) == null || _this$props$onTransit3.call(_this$props3, this.domRef);
  }
  render() {
    const {
      type,
      className,
      content,
      children,
      offset,
      onClose
    } = this.props;
    if (content || children) {
      return REaCt().createElement("div", {
        ref: this.domRef,
        className: `
                        ${NAMESPACE}
                        ${type ? `${NAMESPACE}-${type}` : ''}
                        ${className || ''}
                    `,
        style: offset ? {
          marginTop: `${offset}px`
        } : undefined
      }, REaCt().createElement("div", {
        className: `${NAMESPACE}-content`
      }, content || children), onClose && REaCt().createElement("span", {
        className: `${NAMESPACE}-close`,
        onClick: onClose
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-close-component"
      })));
    }
    return null;
  }
}
Alert.TYPE = {
  LIGHT: 'light',
  NEUTRAL: 'neutral',
  MEDIUM: 'medium',
  HIGH: 'high',
  ERROR: 'error'
};
// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/helpers.jsx
const helpers = REQ_(110);
// EXTERNAL MODULE: ./js/chat/ui/meetings/hostsObserver.jsx
const hostsObserver = REQ_(972);
;// ./js/chat/ui/meetings/waitingRoom/waitingRoom.jsx






const waitingRoom_NAMESPACE = 'waiting-room';
const VIEW = {
  INTRO: 0,
  ACCOUNT: 1,
  GUEST: 2,
  AWAIT: 3,
  UNSUPPORTED: 4,
  REDIRECT: 5
};
class WaitingRoom extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.redirectInterval = undefined;
    this.state = {
      view: VIEW.ACCOUNT,
      call: false,
      audio: false,
      video: false,
      firstName: '',
      lastName: '',
      countdown: 4,
      loading: false
    };
    this.renderLeaveDialog = () => msgDialog(`confirmation:!^${l.wr_leave}!${l.wr_do_not_leave}`, null, l.wr_leave_confirmation, '', cb => {
      if (cb) {
        delay('chat-event-wr-leave', () => eventlog(99938));
        this.doLeave();
      }
    }, 1);
    this.renderDeniedDialog = () => msgDialog('error', '', l.wr_denied, l.wr_denied_details, this.doLeave);
    this.renderTimeoutDialog = () => msgDialog('error', '', l.wr_timeout, l.wr_timeout_details, this.doLeave);
    this.renderWaitingRoomInfo = () => {
      const {
        chatRoom
      } = this.props;
      const {
        nextOccurrenceStart,
        nextOccurrenceEnd
      } = chatRoom.scheduledMeeting || {};
      return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(utils.P9, {
        tag: "h2",
        content: megaChat.html(chatRoom.topic)
      }), REaCt().createElement("div", {
        className: `${waitingRoom_NAMESPACE}-schedule`
      }, REaCt().createElement("span", null, time2date(nextOccurrenceStart / 1000, 20)), REaCt().createElement("span", null, toLocaleTime(nextOccurrenceStart), " - ", toLocaleTime(nextOccurrenceEnd))));
    };
    this.doLeave = () => this.setState({
      view: VIEW.REDIRECT
    }, () => {
      tSleep(this.state.countdown).then(() => this.props.onWaitingRoomLeave());
      this.redirectInterval = setInterval(() => this.setState(({
        countdown
      }) => ({
        countdown: countdown > 0 ? countdown - 1 : 0
      })), 1e3);
      sessionStorage.removeItem('previewMedia');
    });
    this.setInitialView = () => {
      if (u_type || is_eplusplus) {
        let _this$props$chatRoom;
        return (_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.iAmInRoom() ? VIEW.AWAIT : VIEW.ACCOUNT;
      }
      return VIEW.INTRO;
    };
    this.requestJoin = () => {
      let _this$props$chatRoom2;
      const {
        audio,
        video
      } = this.state;
      (_this$props$chatRoom2 = this.props.chatRoom) == null || _this$props$chatRoom2.joinCall(audio, video);
    };
    this.Field = ({
      name,
      children
    }) => {
      let _this$state$name;
      return REaCt().createElement("div", {
        className: `
                    mega-input
                    title-ontop
                    ${(_this$state$name = this.state[name]) != null && _this$state$name.length ? 'valued' : ''}
                `
      }, REaCt().createElement("div", {
        className: "mega-input-title"
      }, children, REaCt().createElement("span", {
        className: "required-red"
      }, "*")), REaCt().createElement("input", {
        type: "text",
        name,
        className: "titleTop required megaInputs",
        placeholder: children,
        value: this.state[name] || '',
        maxLength: 40,
        onChange: ev => this.setState({
          [name]: ev.target.value
        })
      }));
    };
    this.Card = ({
      className,
      children
    }) => {
      const {
        audio,
        video
      } = this.state;
      return REaCt().createElement("div", {
        className: `
                    card
                    ${className || ''}
                 `
      }, REaCt().createElement("div", {
        className: "card-body"
      }, children), REaCt().createElement("div", {
        className: "card-preview"
      }, REaCt().createElement(preview.A, {
        audio,
        video,
        onToggle: (audio, video) => {
          this.setState({
            audio,
            video
          }, () => {
            sessionStorage.previewMedia = JSON.stringify({
              audio,
              video
            });
          });
        }
      })));
    };
    this.Head = ({
      title
    }) => {
      let _this$props$chatRoom3;
      return REaCt().createElement("div", {
        className: `${waitingRoom_NAMESPACE}-head`
      }, REaCt().createElement("div", {
        className: `${waitingRoom_NAMESPACE}-logo`
      }, REaCt().createElement("i", {
        className: `
                        sprite-fm-illustration-wide
                        ${mega.ui.isDarkTheme() ? 'mega-logo-dark' : 'img-mega-logo-light'}
                    `
      })), REaCt().createElement("h1", {
        className: (megaChat.initialChatId || is_chatlink) && this.state.view !== VIEW.INTRO ? 'hidden' : ''
      }, REaCt().createElement(utils.zT, null, title || l.you_have_invitation.replace('%1', (_this$props$chatRoom3 = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom3.topic))));
    };
    this.Await = () => {
      return REaCt().createElement(REaCt().Fragment, null, megaChat.initialChatId ? REaCt().createElement(this.Head, null) : null, REaCt().createElement(this.Card, {
        className: megaChat.initialChatId ? '' : 'fit-spacing'
      }, this.renderWaitingRoomInfo(), REaCt().createElement("div", {
        className: `${waitingRoom_NAMESPACE}-message`
      }, this.state.call ? l.wr_wait_to_admit : l.wr_wait_to_start), REaCt().createElement(meetings_button.A, {
        icon: "sprite-fm-mono icon-log-out-thin-solid",
        className: `${waitingRoom_NAMESPACE}-leave`,
        onClick: () => this.renderLeaveDialog()
      }, l.wr_leave)));
    };
    this.Account = () => {
      const {
        loading,
        audio,
        video
      } = this.state;
      return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(this.Head, null), REaCt().createElement(this.Card, null, this.renderWaitingRoomInfo(), REaCt().createElement(meetings_button.A, {
        className: `
                           mega-button
                           positive
                           large
                           ${loading ? 'disabled' : ''}
                        `,
        onClick: () => {
          return loading ? null : this.setState({
            loading: true
          }, () => {
            const {
              chatRoom
            } = this.props;
            const {
              chatId,
              publicChatHandle,
              publicChatKey
            } = chatRoom;
            if (chatRoom.iAmInRoom()) {
              return megaChat.routing.reinitAndOpenExistingChat(chatId, publicChatHandle).then(() => {
                megaChat.getChatById(chatId).joinCall(audio, video);
              }).catch(ex => console.error(`Failed to open existing room and join call: ${ex}`));
            }
            megaChat.routing.reinitAndJoinPublicChat(chatId, publicChatHandle, publicChatKey).then(() => {
              delete megaChat.initialPubChatHandle;
            }).catch(ex => console.error(`Failed to join room: ${ex}`));
          });
        }
      }, l.wr_ask_to_join), REaCt().createElement("div", null, REaCt().createElement(ui_link.A, {
        to: "https://mega.io/chatandmeetings",
        target: "_blank"
      }, l.how_meetings_work))));
    };
    this.Redirect = () => REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(this.Head, {
      title: l.wr_left_heading
    }), REaCt().createElement("h5", null, l.wr_left_countdown.replace('%1', this.state.countdown)));
    this.Guest = () => {
      const {
        chatRoom
      } = this.props;
      const {
        loading,
        firstName,
        lastName
      } = this.state;
      const isDisabled = !firstName.length || !lastName.length;
      return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(this.Head, null), REaCt().createElement(this.Card, null, this.renderWaitingRoomInfo(), REaCt().createElement("div", {
        className: "card-fields"
      }, REaCt().createElement(this.Field, {
        name: "firstName"
      }, l[1096]), REaCt().createElement(this.Field, {
        name: "lastName"
      }, l[1097])), REaCt().createElement(meetings_button.A, {
        className: `
                            mega-button
                            positive
                            large
                            ${isDisabled || loading ? 'disabled' : ''}
                        `,
        onClick: () => {
          if (isDisabled || loading) {
            return false;
          }
          return this.setState({
            loading: true
          }, () => {
            u_eplusplus(this.state.firstName, this.state.lastName).then(() => {
              return megaChat.routing.reinitAndJoinPublicChat(chatRoom.chatId, chatRoom.publicChatHandle, chatRoom.publicChatKey);
            }).catch(ex => d && console.error(`E++ account failure: ${ex}`));
          });
        }
      }, l.wr_ask_to_join), REaCt().createElement("div", null, REaCt().createElement(ui_link.A, {
        to: "https://mega.io/chatandmeetings",
        target: "_blank"
      }, l.how_meetings_work))));
    };
    this.Intro = () => {
      const {
        chatRoom
      } = this.props;
      return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(this.Head, null), REaCt().createElement("div", {
        className: "join-meeting-content"
      }, REaCt().createElement(meetings_button.A, {
        className: "mega-button positive",
        onClick: () => {
          megaChat.loginOrRegisterBeforeJoining(chatRoom.publicChatHandle, false, true, undefined, () => this.setState({
            view: VIEW.ACCOUNT
          }));
        }
      }, l[171]), REaCt().createElement(meetings_button.A, {
        className: "mega-button",
        onClick: () => this.setState({
          view: VIEW.GUEST
        })
      }, l.join_as_guest), REaCt().createElement("p", null, REaCt().createElement(utils.P9, {
        onClick: e => {
          e.preventDefault();
          megaChat.loginOrRegisterBeforeJoining(chatRoom.publicChatHandle, true, undefined, undefined, () => this.setState({
            view: VIEW.ACCOUNT
          }));
        }
      }, l[20635]))));
    };
    this.Unsupported = () => {
      let _this$props$chatRoom4;
      return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(this.Head, null), REaCt().createElement("h1", null, l.you_have_invitation.replace('%1', (_this$props$chatRoom4 = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom4.topic)), REaCt().createElement("div", {
        className: "meetings-unsupported-container"
      }, REaCt().createElement("i", {
        className: "sprite-fm-uni icon-error"
      }), REaCt().createElement("div", {
        className: "unsupported-info"
      }, REaCt().createElement("h3", null, l.heading_unsupported_browser), REaCt().createElement("h3", null, l.join_meeting_methods), REaCt().createElement("ul", null, REaCt().createElement("li", null, l.join_via_link), REaCt().createElement("li", null, REaCt().createElement(utils.P9, null, l.join_via_mobile.replace('[A]', '<a href="https://mega.io/mobile" target="_blank" class="clickurl">').replace('[/A]', '</a>')))))));
    };
    this.renderView = view => {
      switch (view) {
        default:
          return this.Await();
        case VIEW.INTRO:
          return this.Intro();
        case VIEW.GUEST:
          return this.Guest();
        case VIEW.ACCOUNT:
          return this.Account();
        case VIEW.REDIRECT:
          return this.Redirect();
        case VIEW.UNSUPPORTED:
          return this.Unsupported();
      }
    };
    this.state.call = this.props.havePendingCall;
    this.state.view = megaChat.hasSupportForCalls ? this.setInitialView() : VIEW.UNSUPPORTED;
    if (sessionStorage.previewMedia) {
      const {
        audio,
        video
      } = JSON.parse(sessionStorage.previewMedia);
      this.state.audio = audio;
      this.state.video = video;
      sessionStorage.removeItem('previewMedia');
    }
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (this.props.havePendingCall !== nextProps.havePendingCall) {
      this.setState({
        call: nextProps.havePendingCall
      }, () => this.state.view === VIEW.AWAIT && nextProps.havePendingCall && this.requestJoin());
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    clearInterval(this.redirectInterval);
    this.props.chatRoom.unbind(`onCallLeft.${waitingRoom_NAMESPACE}`);
    this.props.chatRoom.unbind(`onModeratorAdd.${waitingRoom_NAMESPACE}`);
  }
  componentDidMount() {
    super.componentDidMount();
    const {
      chatRoom
    } = this.props;
    const {
      call,
      view
    } = this.state;
    if (call && view === VIEW.AWAIT) {
      this.requestJoin();
    }
    chatRoom.rebind(`onCallLeft.${waitingRoom_NAMESPACE}`, (ev, {
      termCode
    }) => {
      if (termCode === SfuClient.TermCode.kKickedFromWaitingRoom) {
        return this.renderDeniedDialog();
      }
      if (termCode === SfuClient.TermCode.kWaitingRoomAllowTimeout) {
        delay('chat-event-wr-timeout', () => eventlog(99939));
        return this.renderTimeoutDialog();
      }
    });
    chatRoom.rebind(`onModeratorAdd.${waitingRoom_NAMESPACE}`, (ev, user) => {
      if (user === u_handle) {
        chatRoom.meetingsLoading = false;
        this.requestJoin();
      }
    });
  }
  render() {
    const {
      view
    } = this.state;
    return REaCt().createElement(utils.Ay.RenderTo, {
      element: document.body
    }, REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                        ${waitingRoom_NAMESPACE}
                        join-meeting
                        ${view === VIEW.AWAIT ? `${waitingRoom_NAMESPACE}--await` : ''}
                        ${view === VIEW.AWAIT && !megaChat.initialChatId ? 'theme-dark-forced' : ''}
                        ${view === VIEW.REDIRECT ? `${waitingRoom_NAMESPACE}--redirect` : ''}
                        ${megaChat.initialChatId || is_chatlink ? `${waitingRoom_NAMESPACE}--chatlink-landing` : ''}
                    `
    }, this.renderView(view)));
  }
}
// EXTERNAL MODULE: ./js/chat/ui/meetings/streamControls.jsx
const streamControls = REQ_(489);
// EXTERNAL MODULE: ./js/chat/ui/inviteParticipantsPanel.jsx
const inviteParticipantsPanel = REQ_(815);
;// ./js/chat/ui/chatOverlay.jsx



const chatOverlay_NAMESPACE = 'chat-overlay';
const ChatOverlays = {
  PARTICIPANT_LIMIT: 'participants-limit'
};
class ChatOverlay extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.MegaLogo = () => REaCt().createElement("div", {
      className: `${chatOverlay_NAMESPACE}-logo`
    }, REaCt().createElement("i", {
      className: `sprite-fm-illustration-wide ${mega.ui.isDarkTheme() ? 'mega-logo-dark' : 'img-mega-logo-light'}`
    }));
  }
  renderParticipantsLimit() {
    return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
      className: `${chatOverlay_NAMESPACE}-head`
    }, REaCt().createElement(this.MegaLogo, null), REaCt().createElement("h1", null, l.join_call_user_limit_title)), REaCt().createElement("div", {
      className: `${chatOverlay_NAMESPACE}-body`
    }, REaCt().createElement("p", null, l.call_join_user_limit_banner), REaCt().createElement(buttons.$, {
      className: "mega-button positive",
      onClick: () => {
        let _this$props$onClose, _this$props;
        (_this$props$onClose = (_this$props = this.props).onClose) == null || _this$props$onClose.call(_this$props);
      }
    }, l.call_link_user_limit_button)));
  }
  render() {
    const {
      overlayType
    } = this.props;
    let body = null;
    if (overlayType === ChatOverlays.PARTICIPANT_LIMIT) {
      body = this.renderParticipantsLimit();
    }
    if (!body) {
      if (d) {
        console.error('Invalid ChatOverlay', overlayType);
      }
      return null;
    }
    return REaCt().createElement(utils.Ay.RenderTo, {
      element: document.body
    }, REaCt().createElement("div", {
      className: `${chatOverlay_NAMESPACE} ${overlayType}`
    }, body));
  }
}

;// ./js/chat/ui/conversationpanel.jsx


let conversationpanel_dec, _dec2, conversationpanel_class;






























const ENABLE_GROUP_CALLING_FLAG = true;
const MAX_USERS_CHAT_PRIVATE = 100;
const ALERTS_BASE_OFFSET = 4;
const DISMISS_TRANSITIONS = {
  NOT_SHOWN: 0,
  SHOWN: 1,
  DISMISSED: 2
};
class EndCallButton extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.IS_MODERATOR = call.Ay.isModerator(this.props.chatRoom, u_handle);
    this.LeaveButton = (0,hostsObserver.C)(({
      hasHost,
      chatRoom,
      confirmLeave,
      onLeave
    }) => {
      return REaCt().createElement(dropdowns.DropdownItem, {
        className: "link-button",
        icon: "sprite-fm-mono icon-leave-call",
        label: l.leave,
        persistent: true,
        onClick: () => {
          const doLeave = () => hasHost(chatRoom.call ? chatRoom.call.peers.map(a => a.userHandle) : []) ? onLeave() : confirmLeave({
            title: l.assign_host_leave_call,
            body: l.assign_host_leave_call_details,
            cta: l.assign_host_button,
            altCta: l.leave_anyway
          });
          const {
            recorderCid,
            sfuClient
          } = chatRoom.call;
          return recorderCid && recorderCid === sfuClient.cid ? (0,streamControls.sX)(doLeave, () => sfuClient.recordingStop()) : doLeave();
        }
      });
    });
  }
  renderButton({
    label,
    onClick,
    children = null,
    disabled
  }) {
    return REaCt().createElement(buttons.$, {
      className: `
                    link-button
                    light
                    red
                    dropdown-element
                    ${disabled ? 'disabled' : ''}
                `,
      icon: "small-icon colorized horizontal-red-handset",
      label,
      onClick: disabled ? null : onClick
    }, children);
  }
  render() {
    const {
      chatRoom
    } = this.props;
    const {
      type,
      call
    } = chatRoom;
    if (call) {
      const peers = call.peers && call.peers.length;
      if (type === 'private') {
        return this.renderButton({
          label: l[5884],
          onClick: () => call.hangUp()
        });
      }
      if (this.IS_MODERATOR) {
        const doEnd = () => chatRoom.endCallForAll();
        return this.renderButton({
          label: l[5884],
          onClick: peers ? null : () => call.hangUp(),
          children: peers && REaCt().createElement(dropdowns.Dropdown, {
            className: "wide-dropdown light end-call-selector",
            noArrow: "true",
            vertOffset: 4,
            horizOffset: 0
          }, REaCt().createElement(this.LeaveButton, {
            chatRoom,
            participants: chatRoom.getCallParticipants(),
            onLeave: () => call.hangUp(),
            onConfirmDenied: () => call.hangUp()
          }), REaCt().createElement(dropdowns.DropdownItem, {
            className: "link-button",
            icon: "sprite-fm-mono icon-contacts",
            label: l.end_for_all,
            onClick: () => {
              const {
                recorderCid,
                sfuClient
              } = call;
              return recorderCid && recorderCid === u_handle ? (0,streamControls._F)(doEnd, () => sfuClient.recordingStop()) : doEnd();
            }
          }))
        });
      }
      return this.renderButton({
          label: peers ? l[5883] : l[5884],
          onClick: () => call.hangUp()
        })
      ;
    }
    if (chatRoom.havePendingGroupCall()) {
      return this.IS_MODERATOR ? this.renderButton({
        label: l.end_call_for_all,
        onClick: () => msgDialog('confirmation', null, l.end_call_for_all_title, l.end_call_for_all_text, cb => cb ? chatRoom.endCallForAll() : 0xDEAD),
        disabled: !chatRoom.iAmInRoom()
      }) : null;
    }
    return null;
  }
}
const StartMeetingNotification = ({
  chatRoom,
  offset,
  onWaitingRoomJoin,
  onStartCall
}) => {
  if (chatRoom.call || !megaChat.hasSupportForCalls) {
    return null;
  }
  return REaCt().createElement("div", {
    className: "in-call-notif neutral start",
    style: {
      marginTop: offset
    },
    onClick: () => {
      eventlog(500288);
      if (chatRoom.options.w && !chatRoom.iAmOperator()) {
        return onWaitingRoomJoin();
      }
      return onStartCall(call.ZE.AUDIO);
    }
  }, REaCt().createElement("button", {
    className: "mega-button positive small"
  }, l.schedule_start_aot));
};
const JoinCallNotification = ({
  chatRoom,
  offset,
  rhpCollapsed
}) => {
  if (chatRoom.call) {
    return null;
  }
  if (!megaChat.hasSupportForCalls) {
    return REaCt().createElement(Alert, {
      className: `
                    ${rhpCollapsed ? 'full-span' : ''}
                    ${offset === ALERTS_BASE_OFFSET ? 'single-alert' : ''}
                    unsupported-call-alert-progress
                `,
      offset: offset === ALERTS_BASE_OFFSET ? 0 : offset,
      type: Alert.TYPE.MEDIUM,
      content: l.active_call_not_supported
    });
  }
  if (chatRoom.callUserLimited && !chatRoom.canJoinLimitedCall()) {
    return REaCt().createElement("div", {
      className: "call-user-limit-banner",
      style: {
        marginTop: offset
      }
    }, l.call_join_user_limit_banner);
  }
  return REaCt().createElement("div", {
    className: "in-call-notif neutral join",
    style: {
      marginTop: offset
    }
  }, REaCt().createElement("i", {
    className: "sprite-fm-mono icon-phone"
  }), REaCt().createElement(utils.P9, {
    onClick: () => {
      return (0,call.dQ)(true, chatRoom).then(() => chatRoom.joinCall()).catch(ex => d && console.warn('Already in a call.', ex));
    }
  }, (l[20460] || 'There is an active group call. [A]Join[/A]').replace('[A]', '<button class="mega-button positive joinActiveCall small">').replace('[/A]', '</button>')));
};
const allContactsInChat = participants => {
  const currentContacts = M.u.keys();
  for (let i = 0; i < currentContacts.length; i++) {
    const k = currentContacts[i];
    if (M.u[k].c === 1 && !participants.includes(k)) {
      return false;
    }
  }
  return true;
};
const excludedParticipants = room => {
  const excParticipants = room.type === "group" || room.type === "public" ? room.members && Object.keys(room.members).length > 0 ? Object.keys(room.members) : room.getParticipants() : room.getParticipants();
  if (excParticipants.includes(u_handle)) {
    array.remove(excParticipants, u_handle, false);
  }
  return excParticipants;
};
class Occurrences extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.loadingMore = false;
    this.state = {
      editDialog: false,
      occurrenceId: undefined
    };
  }
  loadOccurrences() {
    if (!this.loadingMore) {
      const {
        scheduledMeeting,
        occurrences
      } = this.props;
      const occurrenceItems = Object.values(occurrences || {});
      const lastOccurrence = occurrenceItems[occurrenceItems.length - 1];
      if (lastOccurrence) {
        this.loadingMore = true;
        scheduledMeeting.getOccurrences({
          from: lastOccurrence.start
        }).catch(dump).finally(() => {
          this.loadingMore = false;
        });
      }
    }
  }
  renderCancelConfirmation(occurrence) {
    const {
      scheduledMeeting,
      chatRoom
    } = this.props;
    const nextOccurrences = Object.values(scheduledMeeting.occurrences).filter(o => o.isUpcoming);
    if (nextOccurrences.length > 1) {
      return msgDialog(`confirmation:!^${l.cancel_meeting_occurrence_button}!${l.schedule_cancel_abort}`, 'cancel-occurrence', l.schedule_cancel_occur_dlg_title, l.schedule_cancel_occur_dlg_text, cb => cb && occurrence.cancel(), 1);
    }
    return chatRoom.hasMessages(true) ? msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, 'cancel-occurrence', l.schedule_cancel_all_dialog_title, l.schedule_cancel_all_dialog_move, cb => cb && megaChat.plugins.meetingsManager.cancelMeeting(scheduledMeeting, scheduledMeeting.chatId), 1) : msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, 'cancel-occurrence', l.schedule_cancel_all_dialog_title, l.schedule_cancel_all_dialog_archive, cb => cb && megaChat.plugins.meetingsManager.cancelMeeting(scheduledMeeting, scheduledMeeting.chatId), 1);
  }
  renderLoading() {
    return REaCt().createElement("div", {
      className: "loading-sketch"
    }, Array.from({
      length: 10
    }, (el, i) => {
      return REaCt().createElement("div", {
        key: i,
        className: "chat-occurrence"
      }, REaCt().createElement("div", {
        className: "chat-occurrence-date"
      }), REaCt().createElement("div", {
        className: "chat-occurrence-content"
      }, REaCt().createElement("div", {
        className: "chat-occurrence-title"
      }), REaCt().createElement("div", {
        className: "chat-occurrence-time"
      })));
    }));
  }
  renderOccurrences() {
    const {
      chatRoom,
      occurrences,
      occurrencesLoading,
      scheduledMeeting
    } = this.props;
    if (occurrencesLoading) {
      return this.renderLoading();
    }
    if (occurrences && occurrences.length > 0) {
      const sortedOccurrences = Object.values(occurrences).sort((a, b) => a.start - b.start);
      return REaCt().createElement(REaCt().Fragment, null, sortedOccurrences.map(occurrence => occurrence.isUpcoming ? REaCt().createElement("div", {
        key: occurrence.uid,
        className: `
                                    chat-occurrence
                                    ${occurrence.uid}
                                `
      }, REaCt().createElement("div", {
        className: "chat-occurrence-date"
      }, (0,helpers.cK)(occurrence.start) && REaCt().createElement("span", null, l.today_occurrence_label, " -"), (0,helpers.ef)(occurrence.start) && REaCt().createElement("span", null, l.tomorrow_occurrence_label, " -"), REaCt().createElement("span", null, time2date(occurrence.start / 1000, 19))), REaCt().createElement("div", {
        className: "chat-occurrence-content"
      }, REaCt().createElement("div", {
        className: "chat-occurrence-title"
      }, scheduledMeeting.title), REaCt().createElement("div", {
        className: "chat-occurrence-time"
      }, toLocaleTime(occurrence.start), " - \xA0", toLocaleTime(occurrence.end)), chatRoom.iAmOperator() && REaCt().createElement("div", {
        className: "chat-occurrence-controls"
      }, REaCt().createElement("div", {
        className: "chat-occurrence-control simpletip",
        "data-simpletip": l[1342],
        "data-simpletipposition": "top",
        "data-simpletipoffset": "5"
      }, REaCt().createElement(buttons.$, {
        icon: "sprite-fm-mono icon-rename",
        onClick: () => {
          megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS.EDIT, occurrence);
        }
      })), REaCt().createElement("div", {
        className: "chat-occurrence-control simpletip",
        "data-simpletip": l.msg_dlg_cancel,
        "data-simpletipposition": "top",
        "data-simpletipoffset": "5"
      }, REaCt().createElement(buttons.$, {
        icon: "sprite-fm-mono icon-bin",
        onClick: () => this.renderCancelConfirmation(occurrence)
      }))))) : null));
    }
    return REaCt().createElement("span", null, l.no_occurrences_remain);
  }
  render() {
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "chat-occurrences-list"
    }, REaCt().createElement(perfectScrollbar.O, {
      chatRoom: this.props.chatRoom,
      ref: ref => {
        this.contactsListScroll = ref;
      },
      disableCheckingVisibility: true,
      onUserScroll: ps => ps.isCloseToBottom(30) && this.loadOccurrences(),
      isVisible: this.isCurrentlyActive,
      options: {
        suppressScrollX: true
      }
    }, REaCt().createElement("div", {
      className: "chat-occurrences-list-inner"
    }, this.renderOccurrences())));
  }
}
class ConversationRightArea extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.state = {
      contactPickerDialog: false,
      inviteDialog: false
    };
    this.LeaveButton = (0,hostsObserver.C)(({
      chatRoom,
      hasHost,
      confirmLeave,
      onLeave
    }) => {
      const isDisabled = chatRoom.call || is_chatlink || !chatRoom.iAmInRoom();
      const participants = chatRoom.getParticipantsExceptMe();
      return REaCt().createElement("div", {
        className: `
                        link-button
                        light
                        ${isDisabled ? 'disabled' : ''}
                    `,
        onClick: isDisabled ? null : () => hasHost(participants) || !participants.length ? onLeave() : confirmLeave({
          title: chatRoom.isMeeting ? l.assign_host_to_leave : l.assign_host_to_leave_group,
          body: chatRoom.isMeeting ? l.assign_host_to_details : l.assign_host_to_details_group,
          cta: l.assign_host_button
        })
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-disabled-filled"
      }), REaCt().createElement("span", null, chatRoom.isMeeting ? l.meeting_leave : l[8633]));
    });
    this.OptionsButton = ({
      icon,
      label,
      secondLabel,
      toggled,
      disabled,
      onClick
    }) => {
      const {
        chatRoom
      } = this.props;
      const isDisabled = !chatRoom.iAmOperator() || disabled;
      return REaCt().createElement(buttons.$, {
        className: `
                    link-button
                    light
                    room-settings-button
                `,
        disabled: isDisabled,
        icon: `
                    sprite-fm-mono
                    ${icon}
                `,
        label,
        secondLabel,
        secondLabelClass: "label--green",
        toggle: {
          enabled: toggled,
          onClick: isDisabled ? null : onClick
        },
        onClick: isDisabled ? null : onClick
      });
    };
    this.handleCancelMeeting = () => {
      const {
        chatRoom
      } = this.props;
      const {
        scheduledMeeting,
        chatId
      } = chatRoom || {};
      if (scheduledMeeting) {
        const {
          isRecurring,
          title
        } = scheduledMeeting;
        const doConfirm = res => {
          if (res) {
            megaChat.plugins.meetingsManager.cancelMeeting(scheduledMeeting, chatId);
            delay('chat-event-sm-cancel', () => eventlog(99925));
          }
        };
        if (isRecurring) {
          return chatRoom.hasMessages(true) ? msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_move_recurring, doConfirm, 1) : msgDialog(`confirmation:!^${l.schedule_cancel_dialog_confirm}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_archive_recurring, doConfirm, 1);
        }
        return chatRoom.hasMessages(true) ? msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_move_single, doConfirm, 1) : msgDialog(`confirmation:!^${l.schedule_cancel_dialog_confirm}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_archive_single, doConfirm, 1);
      }
    };
  }
  customIsEventuallyVisible() {
    return this.props.chatRoom.isCurrentlyActive;
  }
  setRetention(chatRoom, retentionTime) {
    chatRoom.setRetention(retentionTime);
    $(document).trigger('closeDropdowns');
  }
  renderOptionsBanner() {
    const {
      chatRoom
    } = this.props;
    return !!chatRoom.options[MCO_FLAGS.WAITING_ROOM] && !!chatRoom.options[MCO_FLAGS.OPEN_INVITE] ? REaCt().createElement("div", {
      className: "room-settings-banner"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-info"
    }), REaCt().createElement(utils.P9, null, l.waiting_room_invite.replace('[A]', `<a
                                href="${l.mega_help_host}/wp-admin/post.php?post=3005&action=edit"
                                target="_blank"
                                class="ulickurl">`).replace('[/A]', '</a>'))) : null;
  }
  handleAddParticipants() {
    if (Object.values(M.u.toJS()).some(u => u.c === 1)) {
      if (allContactsInChat(excludedParticipants(this.props.chatRoom))) {
        return msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.all_contacts_added}`, `${l.all_contacts_added_to_chat}`, res => {
          if (res) {
            contactAddDialog(null, false);
          }
        }, 1);
      }
      return this.setState({
        contactPickerDialog: true
      });
    }
    msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.no_contacts}`, `${l.no_contacts_text}`, resp => {
      if (resp) {
        contactAddDialog(null, false);
      }
    }, 1);
  }
  renderPushSettingsButton() {
    const {
      pushSettingsValue,
      chatRoom,
      onPushSettingsToggled,
      onPushSettingsClicked
    } = this.props;
    const icon = pushSettingsValue || pushSettingsValue === 0 ? 'icon-notification-off-filled' : 'icon-notification-filled';
    return REaCt().createElement("div", {
      className: "push-settings"
    }, REaCt().createElement("div", {
      className: "chat-button-separator"
    }), REaCt().createElement(buttons.$, {
      className: `
                        link-button
                        light
                        push-settings-button
                        ${chatRoom.isReadOnly() ? 'disabled' : ''}
                    `,
      icon: `
                        sprite-fm-mono
                        ${icon}
                    `,
      label: chatRoom.isMeeting ? l.meeting_notifications : l[16709],
      secondLabel: (() => {
        if (pushSettingsValue !== null && pushSettingsValue !== undefined) {
          return pushSettingsValue === 0 ? PushSettingsDialog.options[Infinity] : l[23539].replace('%s', toLocaleTime(pushSettingsValue));
        }
      })(),
      secondLabelClass: "label--green",
      toggle: chatRoom.isReadOnly() ? null : {
        enabled: !pushSettingsValue && pushSettingsValue !== 0,
        onClick: () => !pushSettingsValue && pushSettingsValue !== 0 ? onPushSettingsClicked() : onPushSettingsToggled()
      },
      onClick: () => chatRoom.isReadOnly() ? null : onPushSettingsClicked()
    }), REaCt().createElement("div", {
      className: "chat-button-separator"
    }));
  }
  componentDidMount() {
    super.componentDidMount();
    megaChat.rebind(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`, () => {
      if (this.isMounted()) {
        this.safeForceUpdate();
      }
    });
    megaChat.rebind(`onPrepareIncomingCallDialog.${this.getUniqueId()}`, () => {
      if (this.isMounted() && this.state.inviteDialog) {
        this.setState({
          inviteDialog: false
        });
      }
    });
  }
  render() {
    let _room$messagesBuff, _room$messagesBuff2, _room$messagesBuff3, _room$messagesBuff4, _room$messagesBuff5;
    const self = this;
    const {
      chatRoom: room,
      onStartCall,
      occurrencesLoading,
      onShowScheduledDescription
    } = self.props;
    if (!room || !room.roomId) {
      return null;
    }
    if (!room.isCurrentlyActive && !self._wasAppendedEvenOnce) {
      return null;
    }
    self._wasAppendedEvenOnce = true;
    const startCallDisabled = isStartCallDisabled(room) || room.iAmWaitingRoomPeer();
    let startAudioCallButton;
    let startVideoCallButton;
    const isInCall = !!room.call;
    if (isInCall) {
      startAudioCallButton = startVideoCallButton = null;
    }
    if (room.type === "group" || room.type === "public") {
      if (room.getCallParticipants().length > 0 && !isInCall) {
        startAudioCallButton = startVideoCallButton = null;
      }
    }
    if (startAudioCallButton !== null) {
      startAudioCallButton = REaCt().createElement("div", {
        "data-simpletip": l.unsupported_browser_audio,
        "data-simpletipposition": "top",
        "data-simpletipoffset": "7",
        className: `
                        link-button light
                        ${megaChat.hasSupportForCalls ? '' : 'simpletip'}
                        ${startCallDisabled ? 'disabled' : ''}
                    `,
        onClick: () => onStartCall(call.ZE.AUDIO)
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-phone"
      }), REaCt().createElement("span", null, l[5896]));
    }
    if (startVideoCallButton !== null) {
      startVideoCallButton = REaCt().createElement("div", {
        "data-simpletip": l.unsupported_browser_video,
        "data-simpletipposition": "top",
        "data-simpletipoffset": "7",
        className: `
                        link-button light
                        ${megaChat.hasSupportForCalls ? '' : 'simpletip'}
                        ${startCallDisabled ? 'disabled' : ''}
                    `,
        onClick: () => onStartCall(call.ZE.VIDEO)
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-video-call-filled"
      }), REaCt().createElement("span", null, l[5897]));
    }
    const AVseperator = REaCt().createElement("div", {
      className: "chat-button-separator"
    });
    let isReadOnlyElement = null;
    if (room.isReadOnly()) {
      isReadOnlyElement = REaCt().createElement("center", {
        className: "center",
        style: {
          margin: "6px"
        }
      }, l.read_only_chat);
    }
    const exParticipants = excludedParticipants(room);
    let dontShowTruncateButton = false;
    if (!room.iAmOperator() || room.isReadOnly() || ((_room$messagesBuff = room.messagesBuff) == null ? void 0 : _room$messagesBuff.messages.length) === 0 || ((_room$messagesBuff2 = room.messagesBuff) == null ? void 0 : _room$messagesBuff2.messages.length) === 1 && ((_room$messagesBuff3 = room.messagesBuff) == null ? void 0 : _room$messagesBuff3.messages.getItem(0).dialogType) === "truncated") {
      dontShowTruncateButton = true;
    }
    const renameButtonClass = `
            link-button
            light
            ${(0,call.P)() || room.isReadOnly() || !room.iAmOperator() ? 'disabled' : ''}
        `;
    const getChatLinkClass = `
            link-button
            light
            ${(0,call.P)() || room.isReadOnly() ? 'disabled' : ''}
        `;
    let participantsList = null;
    if (room.type === "group" || room.type === "public") {
      participantsList = REaCt().createElement("div", null, isReadOnlyElement, REaCt().createElement(buttons.$, {
        className: "mega-button action invite-dialog-btn",
        icon: "sprite-fm-mono icon-user-plus-thin-outline",
        label: l[8726],
        disabled: (0,call.P)() || room.isReadOnly() || !room.iAmOperator() && !room.publicLink && !room.options[MCO_FLAGS.OPEN_INVITE],
        onClick: () => {
          delay('chat-event-inv-rhp', () => eventlog(99963));
          if (room.type === 'group') {
            return this.handleAddParticipants();
          }
          loadingDialog.show('fetchchatlink');
          room.updatePublicHandle(false, false, true).catch(dump).always(() => {
            loadingDialog.hide('fetchchatlink');
            if (!this.isMounted()) {
              return;
            }
            if (!room.iAmOperator() && room.options[MCO_FLAGS.OPEN_INVITE] && !room.publicLink) {
              this.handleAddParticipants();
            } else if (room.type === 'public' && !room.topic) {
              this.handleAddParticipants();
            } else {
              this.setState({
                inviteDialog: true
              });
            }
          });
        }
      }), REaCt().createElement(ParticipantsList, {
        ref (r) {
          self.participantsListRef = r;
        },
        chatRoom: room,
        members: room.members,
        isCurrentlyActive: room.isCurrentlyActive
      }));
    }
    const addParticipantBtn = room.type === 'private' && REaCt().createElement(buttons.$, {
      className: "link-button light",
      icon: "sprite-fm-mono icon-add-small",
      label: l[8007],
      disabled: (0,call.P)() || room.isReadOnly() || !(room.iAmOperator() || room.type !== 'private' && room.options[MCO_FLAGS.OPEN_INVITE]),
      onClick: () => Object.values(M.u.toJS()).some(u => u.c === 1) ? !allContactsInChat(exParticipants) ? this.setState({
        contactPickerDialog: true
      }) : msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.all_contacts_added}`, `${l.all_contacts_added_to_chat}`, res => {
        if (res) {
          contactAddDialog(null, false);
        }
      }, 1) : msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.no_contacts}`, `${l.no_contacts_text}`, resp => {
        if (resp) {
          contactAddDialog(null, false);
        }
      }, 1)
    });
    const waitingRoomButton = {
      icon: 'icon-clock-user-thin-solid',
      label: l.waiting_room,
      secondLabel: l.waiting_room_info,
      toggled: room.options[MCO_FLAGS.WAITING_ROOM],
      disabled: room.havePendingCall(),
      onClick: () => {
        room.toggleWaitingRoom();
        delay('chat-event-wr-create-button', () => eventlog(99937));
      }
    };
    const openInviteButton = {
      icon: 'icon-user-filled',
      label: room.isMeeting ? l.meeting_open_invite_label : l.chat_open_invite_label,
      secondLabel: l.open_invite_desc,
      toggled: room.options[MCO_FLAGS.OPEN_INVITE],
      onClick: () => {
        room.toggleOpenInvite();
        if (room.scheduledMeeting) {
          delay('chat-event-sm-allow-non-hosts', () => eventlog(99928));
        }
      }
    };
    const retentionTime = room.retentionTime ? secondsToDays(room.retentionTime) : 0;
    const ICON_ACTIVE = REaCt().createElement("i", {
      className: "sprite-fm-mono icon-check"
    });
    const retentionHistoryBtn = REaCt().createElement(buttons.$, {
      className: "link-button light history-retention-btn",
      icon: "sprite-fm-mono icon-recents-filled",
      label: l[23436],
      disabled: !room.iAmOperator() || room.isReadOnly() || (0,call.P)(),
      secondLabel: room.getRetentionLabel(),
      secondLabelClass: "label--red",
      chatRoom: room
    }, room.iAmOperator() ? REaCt().createElement(dropdowns.Dropdown, {
      className: "retention-history-menu light",
      noArrow: "false",
      vertOffset: -53,
      horizOffset: -205
    }, REaCt().createElement("div", {
      className: "retention-history-menu__list"
    }, REaCt().createElement("div", {
      className: "dropdown-item link-button retention-history-menu__list__elem",
      onClick: () => this.setRetention(room, 0)
    }, REaCt().createElement("span", null, l.disabled_chat_history_cleaning_status), retentionTime === 0 && ICON_ACTIVE), REaCt().createElement("div", {
      className: "dropdown-item link-button retention-history-menu__list__elem",
      onClick: () => this.setRetention(room, daysToSeconds(1))
    }, REaCt().createElement("span", null, l[23437]), retentionTime === 1 && ICON_ACTIVE), REaCt().createElement("div", {
      className: "dropdown-item link-button retention-history-menu__list__elem",
      onClick: () => this.setRetention(room, daysToSeconds(7))
    }, REaCt().createElement("span", null, l[23438]), retentionTime === 7 && ICON_ACTIVE), REaCt().createElement("div", {
      className: "dropdown-item link-button retention-history-menu__list__elem",
      onClick: () => this.setRetention(room, daysToSeconds(30))
    }, REaCt().createElement("span", null, l[23439]), retentionTime === 30 && ICON_ACTIVE), REaCt().createElement("div", {
      className: "dropdown-item link-button retention-history-menu__list__elem",
      onClick: () => {
        $(document).trigger('closeDropdowns');
        self.props.onHistoryRetentionConfig();
      }
    }, REaCt().createElement("span", null, l[23440]), [0, 1, 7, 30].indexOf(retentionTime) === -1 && ICON_ACTIVE))) : null);
    const MEMBERS_LIMITED = Object.keys(room.members).length > MAX_USERS_CHAT_PRIVATE;
    const {
      scheduledMeeting,
      isMeeting
    } = room;
    const {
      isRecurring,
      isUpcoming,
      occurrences
    } = scheduledMeeting || {};
    let archiveText = room.isMeeting ? l.archive_meeting_btn : l.archive_chat_btn;
    if (room.isArchived()) {
      archiveText = room.isMeeting ? l.unarchive_meeting_btn : l[19065];
    }
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "chat-right-area"
    }, REaCt().createElement(perfectScrollbar.O, {
      className: "chat-right-area conversation-details-scroll",
      options: {
        'suppressScrollX': true
      },
      ref: ref => {
        this.rightScroll = ref;
      },
      triggerGlobalResize: true,
      isVisible: room.isCurrentlyActive,
      chatRoom: room
    }, REaCt().createElement("div", {
      className: "chat-right-pad"
    }, REaCt().createElement(Accordion, (0,esm_extends.A)({}, this.state, {
      chatRoom: room,
      onToggle: SoonFc(20, () => {
        if (this.rightScroll) {
          this.rightScroll.reinitialise();
        }
        if (this.participantsListRef) {
          let _this$participantsLis, _this$participantsLis2;
          (_this$participantsLis = (_this$participantsLis2 = this.participantsListRef).safeForceUpdate) == null || _this$participantsLis.call(_this$participantsLis2);
        }
      }),
      expandedPanel: {
        participants: false,
        options: false,
        occurrences: isMeeting && scheduledMeeting && isRecurring
      }
    }), participantsList ? REaCt().createElement(AccordionPanel, {
      className: "small-pad",
      title: room.isMeeting ? l.meeting_participants : l.chat_participants,
      chatRoom: room,
      key: "participants"
    }, participantsList) : null, room.type === 'public' && room.observers > 0 && !room.options.w ? REaCt().createElement("div", {
      className: "accordion-text observers"
    }, l[20466], REaCt().createElement("span", {
      className: "observers-count"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-eye-reveal"
    }), room.observers)) : REaCt().createElement("div", null), isRecurring && isUpcoming && scheduledMeeting.occurrences.some(o => o.isUpcoming) && REaCt().createElement(AccordionPanel, {
      key: "occurrences",
      className: "chat-occurrences-panel",
      accordionClass: "chatroom-occurrences-panel",
      title: l.occurrences_heading,
      chatRoom: room,
      scheduledMeeting,
      occurrences
    }, REaCt().createElement(Occurrences, {
      chatRoom: room,
      scheduledMeeting,
      occurrences,
      occurrencesLoading
    })), REaCt().createElement(AccordionPanel, {
      key: "options",
      className: "have-animation buttons",
      accordionClass: "chatroom-options-panel",
      title: l[7537],
      chatRoom: room,
      sfuClient: window.sfuClient
    }, REaCt().createElement(REaCt().Fragment, null, room.isNote ? null : REaCt().createElement(REaCt().Fragment, null, addParticipantBtn, startAudioCallButton, startVideoCallButton, REaCt().createElement(EndCallButton, {
      call: room.havePendingGroupCall() || room.haveActiveCall(),
      chatRoom: room
    }), scheduledMeeting && REaCt().createElement("div", {
      className: `
                                                        link-button light
                                                        schedule-view-desc
                                                        ${room.isReadOnly() || !scheduledMeeting.description ? 'disabled' : ''}
                                                    `,
      onClick: () => {
        if (!room.isReadOnly() && scheduledMeeting.description) {
          onShowScheduledDescription();
        }
      }
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-description"
    }), REaCt().createElement("span", null, l.schedule_view_desc)), (room.type === 'group' || room.type === 'public') && !scheduledMeeting ? REaCt().createElement("div", {
      className: renameButtonClass,
      onClick: e => {
        if ($(e.target).closest('.disabled').length > 0) {
          return false;
        }
        if (this.props.onRenameClicked) {
          this.props.onRenameClicked();
        }
      }
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-rename"
    }), REaCt().createElement("span", null, room.isMeeting ? l.rename_meeting : l[9080])) : null, scheduledMeeting ? REaCt().createElement("div", {
      className: `
                                                        link-button
                                                        light
                                                        ${room.iAmOperator() ? '' : 'disabled'}
                                                    `,
      onClick: () => room.iAmOperator() ? megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS.EDIT, room) : null
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-rename"
    }), scheduledMeeting.isRecurring ? REaCt().createElement("span", null, l.edit_meeting_series_button) : REaCt().createElement("span", null, l.edit_meeting_button)) : null, room.type === 'public' && !room.isMeeting ? REaCt().createElement("div", {
      className: getChatLinkClass,
      onClick: e => {
        if ($(e.target).closest('.disabled').length > 0) {
          return false;
        }
        this.props.onGetManageChatLinkClicked();
      }
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-link-filled"
    }), REaCt().createElement("span", null, l[20481])) : null, scheduledMeeting ? REaCt().createElement("div", {
      className: `
                                                        link-button
                                                        light
                                                        ${room.iAmOperator() && !scheduledMeeting.canceled ? '' : 'disabled'}
                                                    `,
      onClick: () => {
        if (room.iAmOperator() && !scheduledMeeting.canceled) {
          this.handleCancelMeeting();
        }
      }
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-bin-filled"
    }), scheduledMeeting.isRecurring ? REaCt().createElement("span", null, l.cancel_meeting_series_button) : REaCt().createElement("span", null, l.cancel_meeting_button)) : null, !room.membersSetFromApi.members.hasOwnProperty(u_handle) && room.type === 'public' && !is_chatlink && room.publicChatHandle && room.publicChatKey ? REaCt().createElement("div", {
      className: "link-button light",
      onClick: e => {
        if ($(e.target).closest('.disabled').length > 0) {
          return false;
        }
        this.props.onJoinViaPublicLinkClicked();
      }
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-rename"
    }), REaCt().createElement("span", null, l[20597])) : null, scheduledMeeting ? null : REaCt().createElement(REaCt().Fragment, null, AVseperator, REaCt().createElement(buttons.$, {
      className: "link-button light dropdown-element",
      icon: "sprite-fm-mono icon-upload-filled",
      label: l[23753],
      disabled: room.isReadOnly()
    }, REaCt().createElement(dropdowns.Dropdown, {
      className: "wide-dropdown send-files-selector light",
      noArrow: "true",
      vertOffset: 4,
      onClick: () => false
    }, REaCt().createElement("div", {
      className: "dropdown info-txt"
    }, l[23753] || 'Send...'), REaCt().createElement(dropdowns.DropdownItem, {
      className: "link-button",
      icon: "sprite-fm-mono icon-cloud-drive",
      label: l[19794] || 'My Cloud Drive',
      disabled: mega.paywall,
      onClick: () => {
        this.props.onAttachFromCloudClicked();
      }
    }), REaCt().createElement(dropdowns.DropdownItem, {
      className: "link-button",
      icon: "sprite-fm-mono icon-session-history",
      label: l[19795] || 'My computer',
      disabled: mega.paywall,
      onClick: () => {
        this.props.onAttachFromComputerClicked();
      }
    })))), this.renderPushSettingsButton()), room.type === 'private' ? null : REaCt().createElement(REaCt().Fragment, null, room.scheduledMeeting && this.OptionsButton(waitingRoomButton), this.OptionsButton(openInviteButton), this.renderOptionsBanner(), AVseperator), REaCt().createElement(buttons.$, {
      className: "link-button light export-chat-button",
      disabled: ((_room$messagesBuff4 = room.messagesBuff) == null ? void 0 : _room$messagesBuff4.messages.length) === 0 || room.exportIo,
      onClick: () => {
        room.exportToFile();
      }
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-export-chat-filled"
    }), REaCt().createElement("span", null, room.isMeeting ? l.export_meeting_rhp : l.export_chat_rhp)), REaCt().createElement(buttons.$, {
      className: "link-button light clear-history-button",
      disabled: dontShowTruncateButton || !room.members.hasOwnProperty(u_handle),
      onClick: () => {
        if (this.props.onTruncateClicked) {
          this.props.onTruncateClicked();
        }
      }
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-remove"
    }), REaCt().createElement("span", {
      className: "accordion-clear-history-text"
    }, room.isMeeting ? l.meeting_clear_hist : l[8871])), retentionHistoryBtn, room.iAmOperator() && room.type === 'public' && !scheduledMeeting ? REaCt().createElement("div", {
      className: "chat-enable-key-rotation-paragraph"
    }, AVseperator, REaCt().createElement("div", {
      className: `
                                                    link-button
                                                    light
                                                    ${MEMBERS_LIMITED ? 'disabled' : ''}
                                                `,
      onClick: e => {
        if (MEMBERS_LIMITED || $(e.target).closest('.disabled').length > 0) {
          return false;
        }
        this.props.onMakePrivateClicked();
      }
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-key"
    }), REaCt().createElement("span", null, l[20623])), REaCt().createElement("p", null, REaCt().createElement("span", null, l[20454]))) : null, AVseperator, REaCt().createElement("div", {
      className: `
                                                link-button
                                                light
                                                ${(room.members.hasOwnProperty(u_handle) || room.state === ChatRoom.STATE.LEFT) && !is_chatlink ? '' : 'disabled'}
                                            `,
      onClick: e => {
        if ($(e.target).closest('.disabled').length > 0) {
          return false;
        }
        if (room.isArchived()) {
          if (this.props.onUnarchiveClicked) {
            this.props.onUnarchiveClicked();
          }
        } else if (this.props.onArchiveClicked) {
          this.props.onArchiveClicked();
        }
      }
    }, REaCt().createElement("i", {
      className: `
                                                sprite-fm-mono
                                                ${room.isArchived() ? 'icon-unarchive' : 'icon-archive'}
                                            `
    }), REaCt().createElement("span", null, archiveText)), room.type === 'private' ? null : REaCt().createElement(this.LeaveButton, {
      chatRoom: room,
      participants: room.getParticipantsExceptMe(),
      onLeave: () => room.leave(true)
    }))), REaCt().createElement(SharedFilesAccordionPanel, {
      key: "sharedFiles",
      title: l[19796] || 'Shared Files',
      chatRoom: room,
      sharedFiles: (_room$messagesBuff5 = room.messagesBuff) == null ? void 0 : _room$messagesBuff5.sharedFiles
    }), room.type === 'private' && !room.isNote ? REaCt().createElement(IncSharesAccordionPanel, {
      key: "incomingShares",
      title: l[5542],
      chatRoom: room
    }) : null))), this.state.contactPickerDialog && REaCt().createElement(ui_contacts.ContactPickerDialog, {
      exclude: exParticipants,
      megaChat: room.megaChat,
      multiple: true,
      className: "popup add-participant-selector",
      singleSelectedButtonLabel: room.isMeeting ? l.meeting_add_participant : l[8869],
      multipleSelectedButtonLabel: room.isMeeting ? l.meeting_add_participant : l[8869],
      nothingSelectedButtonLabel: l[8870],
      inviteWarningLabel: room.haveActiveCall(),
      chatRoom: room,
      onSelectDone: selected => {
        this.props.onAddParticipantSelected(selected);
        this.setState({
          contactPickerDialog: false
        });
      },
      onClose: () => this.setState({
        contactPickerDialog: false
      }),
      selectFooter: true
    }), this.state.inviteDialog && REaCt().createElement(modalDialogs.A.ModalDialog, {
      onClose: () => {
        this.setState({
          inviteDialog: false
        });
      },
      dialogName: "chat-link-dialog",
      chatRoom: room
    }, REaCt().createElement(inviteParticipantsPanel.Q, {
      chatRoom: room,
      onAddParticipants: () => {
        this.setState({
          inviteDialog: false
        }, () => this.handleAddParticipants());
      }
    })));
  }
}
ConversationRightArea.defaultProps = {
  'requiresUpdateOnResize': true
};
const ConversationPanel = (conversationpanel_dec = utils.Ay.SoonFcWrap(360), _dec2 = (0,mixins.N9)(0.7, 9), conversationpanel_class = class ConversationPanel extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.messagesBlockRef = REaCt().createRef();
    this.$container = undefined;
    this.$messages = undefined;
    this.selectedNodes = [];
    this.state = {
      startCallPopupIsActive: false,
      localVideoIsMinimized: false,
      isFullscreenModeEnabled: false,
      mouseOverDuringCall: false,
      attachCloudDialog: false,
      sendContactDialog: false,
      confirmDeleteDialog: false,
      pasteImageConfirmDialog: false,
      nonLoggedInJoinChatDialog: false,
      pushSettingsDialog: false,
      pushSettingsValue: null,
      messageToBeDeleted: null,
      callMinimized: false,
      editing: false,
      showHistoryRetentionDialog: false,
      setNonLoggedInJoinChatDlgTrue: null,
      hasInvalidKeys: null,
      invalidKeysBanner: null,
      descriptionDialog: false,
      occurrencesLoading: false,
      waitingRoom: false,
      callUserLimit: false,
      historyTimeOutBanner: DISMISS_TRANSITIONS.NOT_SHOWN,
      renameDialog: false,
      renameDialogValue: undefined,
      typingAreaText: ''
    };
    this.RenameDialog = () => {
      const {
        chatRoom
      } = this.props;
      const {
        renameDialogValue
      } = this.state;
      const isDisabled = renameDialogValue === chatRoom.getRoomTitle() || !$.trim(renameDialogValue).length;
      const onSubmit = () => chatRoom.setRoomTopic(renameDialogValue).then(() => this.setState({
        renameDialog: false,
        renameDialogValue: undefined
      })).catch(dump);
      return REaCt().createElement(modalDialogs.A.ModalDialog, {
        chatRoom,
        title: chatRoom.isMeeting ? l.rename_meeting : l[9080],
        name: "rename-group",
        className: "chat-rename-dialog dialog-template-main",
        onClose: () => this.setState({
          renameDialog: false,
          renameDialogValue: undefined
        }),
        buttons: [{
          label: l.msg_dlg_cancel,
          onClick: () => this.setState({
            renameDialog: false,
            renameDialogValue: undefined
          })
        }, {
          label: l[61],
          className: `
                            positive
                            ${isDisabled ? 'disabled' : ''}
                        `,
          onClick: isDisabled ? null : onSubmit
        }]
      }, REaCt().createElement("section", {
        className: "content"
      }, REaCt().createElement("div", {
        className: "content-block"
      }, REaCt().createElement("div", {
        className: "dialog secondary-header"
      }, REaCt().createElement("div", {
        className: "rename-input-bl"
      }, REaCt().createElement("input", {
        type: "text",
        name: "newTopic",
        className: "chat-rename-group-dialog",
        value: renameDialogValue === undefined ? chatRoom.getRoomTitle() : renameDialogValue,
        maxLength: ChatRoom.TOPIC_MAX_LENGTH,
        onChange: ev => this.setState({
          renameDialogValue: ev.target.value.substr(0, 30)
        }),
        onKeyUp: ev => isDisabled ? null : ev.which === 13 && onSubmit()
      }))))));
    };
    this.CloudBrowserDialog = () => {
      const {
        chatRoom
      } = this.props;
      return REaCt().createElement(cloudBrowserModalDialog.CloudBrowserDialog, {
        room: chatRoom,
        allowAttachFolders: true,
        onSelected: nodes => {
          this.selectedNodes = nodes;
        },
        onAttachClicked: () => {
          this.setState({
            attachCloudDialog: false
          }, () => {
            chatRoom.scrolledToBottom = true;
            chatRoom.attachNodes(this.selectedNodes).catch(dump);
          });
        },
        onClose: () => {
          this.setState({
            attachCloudDialog: false
          }, () => {
            this.selectedNodes = [];
          });
        }
      });
    };
    this.SelectContactDialog = () => {
      const {
        chatRoom
      } = this.props;
      const excludedContacts = chatRoom.getParticipantsExceptMe().filter(userHandle => userHandle in M.u);
      return REaCt().createElement(modalDialogs.A.SelectContactDialog, {
        chatRoom,
        exclude: excludedContacts,
        onSelectClicked: selected => this.setState({
          sendContactDialog: false
        }, () => chatRoom.attachContacts(selected)),
        onClose: () => this.setState({
          sendContactDialog: false
        })
      });
    };
    this.DescriptionDialog = () => {
      const {
        chatRoom
      } = this.props;
      const dialogName = 'scheduled-description-dialog';
      return REaCt().createElement(modalDialogs.A.ModalDialog, {
        className: "scheduled-description-dialog",
        meeting: chatRoom.scheduledMeeting,
        popupDidMount: () => M.safeShowDialog(dialogName, () => $(`.${dialogName}`)),
        popupWillUnmount: () => $.dialog === dialogName && closeDialog(),
        onClose: () => this.setState({
          descriptionDialog: false
        })
      }, REaCt().createElement("header", null, REaCt().createElement("h3", null, l.schedule_desc_dlg_title)), REaCt().createElement("section", {
        className: "content"
      }, REaCt().createElement(perfectScrollbar.O, {
        className: "description-scroller"
      }, REaCt().createElement(utils.P9, {
        content: megaChat.html(chatRoom.scheduledMeeting.description).replace(/\n/g, '<br>') || l.schedule_no_desc
      }))));
    };
    this.PushSettingsDialog = () => {
      const {
        chatRoom
      } = this.props;
      const {
        pushSettingsValue
      } = this.state;
      const state = {
        pushSettingsDialog: false,
        pushSettingsValue: null
      };
      return REaCt().createElement(PushSettingsDialog, {
        room: chatRoom,
        pushSettingsValue,
        onClose: () => this.setState({
          ...state,
          pushSettingsValue
        }, () => $.dialog === 'push-settings-dialog' && closeDialog()),
        onConfirm: pushSettingsValue => this.setState({
          ...state,
          pushSettingsValue
        }, () => pushNotificationSettings.setDnd(chatRoom.chatId, pushSettingsValue === Infinity ? 0 : unixtime() + pushSettingsValue * 60))
      });
    };
    this.updateTypingAreaText = value => {
      this.setState({
        typingAreaText: value
      });
    };
    const {
      chatRoom: _chatRoom
    } = this.props;
    const uniqueId = this.getUniqueId();
    _chatRoom.rebind(`openAttachCloudDialog.${uniqueId}`, () => this.setState({
      attachCloudDialog: true
    }));
    _chatRoom.rebind(`openSendContactDialog.${uniqueId}`, () => this.setState({
      sendContactDialog: true
    }));
    _chatRoom.rebind(`openDescriptionDialog.${uniqueId}`, () => this.setState({
      descriptionDialog: true
    }));
    this.handleKeyDown = SoonFc(120, ev => this._handleKeyDown(ev));
    this.state.waitingRoom = _chatRoom.options.w && (_chatRoom.isAnonymous() || megaChat.initialChatId || is_eplusplus);
  }
  customIsEventuallyVisible() {
    return this.props.chatRoom.isCurrentlyActive;
  }
  onMouseMove() {
    if (this.isComponentEventuallyVisible()) {
      this.props.chatRoom.trigger("onChatIsFocused");
    }
  }
  _handleKeyDown() {
    if (this.__isMounted) {
      const {chatRoom} = this.props;
      if (chatRoom.isActive() && !chatRoom.isReadOnly()) {
        chatRoom.trigger("onChatIsFocused");
      }
    }
  }
  handleDeleteDialog(msg) {
    if (msg) {
      this.setState({
        editing: false,
        confirmDeleteDialog: true,
        messageToBeDeleted: msg
      });
    }
  }
  toggleExpandedFlag() {
    if (this.props.onToggleExpandedFlag) {
      this.props.onToggleExpandedFlag();
    }
    return document.body.classList[call.Ay.isExpanded() ? 'remove' : 'add'](call.Fj);
  }
  startCall(type, scheduled) {
    const {
      chatRoom
    } = this.props;
    if (isStartCallDisabled(chatRoom) || chatRoom.iAmWaitingRoomPeer()) {
      return false;
    }
    return type === call.ZE.AUDIO ? chatRoom.startAudioCall(scheduled) : chatRoom.startVideoCall(scheduled);
  }
  renderUpcomingInfo() {
    const {
      scheduledMeeting
    } = this.props.chatRoom;
    if (scheduledMeeting) {
      const {
        recurring,
        nextOccurrenceStart,
        nextOccurrenceEnd,
        isUpcoming
      } = scheduledMeeting;
      const until = `${(0,helpers.ro)(nextOccurrenceStart, nextOccurrenceEnd) ? '' : time2date(nextOccurrenceEnd / 1000, 4)} ${toLocaleTime(nextOccurrenceEnd)}`;
      return REaCt().createElement(REaCt().Fragment, null, isUpcoming && recurring && REaCt().createElement("span", null, l.next_meeting), REaCt().createElement("span", null, (l.schedule_formatted_date || '%1 from %2 to %3').replace('%1', time2date(nextOccurrenceStart / 1000, 4)).replace('%2', toLocaleTime(nextOccurrenceStart)).replace('%3', until)));
    }
    return null;
  }
  componentDidMount() {
    super.componentDidMount();
    const {
      chatRoom
    } = this.props;
    this.$container = $('.conversation-panel', '#fmholder');
    this.$messages = $('.messages.scroll-area > .perfectScrollbarContainer', this.$container);
    window.addEventListener('keydown', this.handleKeyDown);
    chatRoom.rebind('onSendMessage.scrollToBottom', () => {
      chatRoom.scrolledToBottom = true;
      if (this.messagesListScrollable) {
        this.messagesListScrollable.scrollToBottom();
      }
    });
    chatRoom.rebind('openSendFilesDialog.cpanel', () => this.setState({
      attachCloudDialog: true
    }));
    chatRoom.rebind('showGetChatLinkDialog.ui', () => {
      createTimeoutPromise(() => chatRoom.topic && chatRoom.state === ChatRoom.STATE.READY, 350, 15000).always(() => {
        return chatRoom.isCurrentlyActive ? this.setState({
          chatLinkDialog: true
        }) : chatRoom.updatePublicHandle(false, true);
      });
    });
    if (chatRoom.type === 'private') {
      const otherContactHash = chatRoom.getParticipantsExceptMe()[0];
      if (otherContactHash in M.u) {
        this._privateChangeListener = M.u[otherContactHash].addChangeListener(() => {
          if (!this.isMounted()) {
            return 0xDEAD;
          }
          this.safeForceUpdate();
        });
      }
    }
    if (is_chatlink && !chatRoom.isMeeting) {
      this.state.setNonLoggedInJoinChatDlgTrue = setTimeout(() => {
        M.safeShowDialog('chat-links-preview-desktop', () => {
          if (this.isMounted()) {
            this.setState({
              nonLoggedInJoinChatDialog: true
            });
          }
        });
      }, rand_range(5, 10) * 1000);
    }
    if (is_chatlink && chatRoom.isMeeting && u_type !== false && u_type < 3) {
      eventlog(99747, JSON.stringify([1, u_type | 0]), true);
    }
    chatRoom._uiIsMounted = true;
    chatRoom.$rConversationPanel = this;
    onIdle(() => this.isMounted() && chatRoom.trigger('onComponentDidMount'));
    ChatdIntegration._waitForProtocolHandler(chatRoom, () => {
      if (this.isMounted()) {
        const hasInvalidKeys = chatRoom.hasInvalidKeys();
        this.setState({
          hasInvalidKeys,
          invalidKeysBanner: hasInvalidKeys
        }, () => this.safeForceUpdate());
      }
    });
    megaChat.rebind(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`, () => {
      return this.isMounted() && this.setState({
        occurrencesLoading: false
      });
    });
    chatRoom.rebind(`wrOnJoinNotAllowed.${this.getUniqueId()}`, () => {
      return this.isMounted() && this.setState({
        waitingRoom: true
      });
    });
    chatRoom.rebind(`wrOnJoinAllowed.${this.getUniqueId()}`, () => {
      return this.isMounted() && this.setState({
        waitingRoom: false
      });
    });
    chatRoom.rebind(`onCallUserLimitExceeded.${this.getUniqueId()}`, () => {
      if (!this.isMounted()) {
        return;
      }
      if (megaChat.initialChatId || is_eplusplus) {
        this.setState({
          callUserLimit: true
        });
      }
    });
    chatRoom.rebind(`onHistTimeoutChange.${this.getUniqueId()}`, () => {
      if (this.state.historyTimeOutBanner === DISMISS_TRANSITIONS.NOT_SHOWN && chatRoom.historyTimedOut) {
        this.setState({
          historyTimeOutBanner: DISMISS_TRANSITIONS.SHOWN
        });
      } else if (this.state.historyTimeOutBanner && !chatRoom.historyTimedOut) {
        this.setState({
          historyTimeOutBanner: DISMISS_TRANSITIONS.NOT_SHOWN
        });
      }
    });
    if (chatRoom.options.w) {
      chatRoom.rebind(`onMembersUpdated.${this.getUniqueId()}`, (ev, {
        userId,
        priv
      }) => {
        if (userId === u_handle && priv !== ChatRoom.MembersSet.PRIVILEGE_STATE.LEFT) {
          chatRoom.unbind(`onMembersUpdated.${this.getUniqueId()}`);
          if (is_chatlink) {
            return megaChat.routing.reinitAndOpenExistingChat(chatRoom.chatId, chatRoom.publicChatHandle).then(chatRoom => chatRoom.havePendingCall() && priv === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR && chatRoom.joinCall()).catch(dump);
          }
          return this.state.waitingRoom && this.setState({
            waitingRoom: priv !== ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR
          });
        }
      });
    }
    this.pageChangeListener = mBroadcaster.addListener('beforepagechange', () => M.chat && this.state.waitingRoom && this.setState({
      waitingRoom: false
    }, () => this.safeForceUpdate()));
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    const self = this;
    const {chatRoom} = self.props;
    chatRoom._uiIsMounted = true;
    if (this._privateChangeListener) {
      const otherContactHash = self.props.chatRoom.getParticipantsExceptMe()[0];
      if (otherContactHash in M.u) {
        M.u[otherContactHash].removeChangeListener(this._privateChangeListener);
        delete this._privateChangeListener;
      }
    }
    mBroadcaster.removeListener(this.pageChangeListener);
    this.props.chatRoom.unbind(`openAttachCloudDialog.${this.getUniqueId()}`);
    this.props.chatRoom.unbind(`openSendContactDialog.${this.getUniqueId()}`);
    this.props.chatRoom.unbind(`openDescriptionDialog.${this.getUniqueId()}`);
    window.removeEventListener('keydown', self.handleKeyDown);
    $(document).off(`fullscreenchange.megaChat_${chatRoom.roomId}`);
    $(document).off(`keydown.keyboardScroll_${chatRoom.roomId}`);
    this.props.chatRoom.unbind(`wrOnJoinNotAllowed.${this.getUniqueId()}`);
    this.props.chatRoom.unbind(`wrOnJoinAllowed.${this.getUniqueId()}`);
    megaChat.unbind(`onIncomingCall.${this.getUniqueId()}`);
    this.props.chatRoom.unbind(`onHistTimeoutChange.${this.getUniqueId()}`);
  }
  componentDidUpdate(prevProps, prevState) {
    const self = this;
    const room = this.props.chatRoom;
    room.megaChat.updateSectionUnreadCount();
    if (prevProps.isActive === false && self.props.isActive === true) {
      const $typeArea = $('.messages-textarea:visible:first', this.$container);
      if ($typeArea.length === 1) {
        $typeArea.trigger("focus");
        moveCursortoToEnd($typeArea[0]);
      }
    }
    if (!prevState.renameDialog && self.state.renameDialog === true) {
      Soon(() => {
        const $input = $('.chat-rename-dialog input');
        if ($input && $input[0] && !$($input[0]).is(":focus")) {
          $input.trigger("focus");
          $input[0].selectionStart = 0;
          $input[0].selectionEnd = $input.val().length;
        }
      });
    }
    if (self.$messages && self.isComponentEventuallyVisible()) {
      $(window).rebind('pastedimage.chatRoom', (e, blob, fileName) => {
        if (self.$messages && self.isComponentEventuallyVisible()) {
          self.setState({
            'pasteImageConfirmDialog': [blob, fileName, URL.createObjectURL(blob)]
          });
          e.preventDefault();
        }
      });
      self.props.chatRoom.trigger("onComponentDidUpdate");
    }
  }
  isActive() {
    return document.hasFocus() && this.$messages && this.$messages.is(":visible");
  }
  render() {
    const self = this;
    const room = this.props.chatRoom;
    if (!room || !room.roomId) {
      return null;
    }
    const contacts = room.getParticipantsExceptMe();
    let contactHandle;
    let contact;
    let nonLoggedInJoinChatDialog = null;
    if (self.state.nonLoggedInJoinChatDialog === true) {
      const usersCount = Object.keys(room.members).length;
      const closeJoinDialog = () => {
        onIdle(() => {
          if ($.dialog === 'chat-links-preview-desktop') {
            closeDialog();
          }
        });
        self.setState({
          'nonLoggedInJoinChatDialog': false
        });
      };
      nonLoggedInJoinChatDialog = REaCt().createElement(modalDialogs.A.ModalDialog, {
        title: l[20596],
        className: "mega-dialog chat-links-preview-desktop dialog-template-graphic",
        chatRoom: room,
        onClose: closeJoinDialog
      }, REaCt().createElement("section", {
        className: "content"
      }, REaCt().createElement("div", {
        className: "chatlink-contents"
      }, REaCt().createElement("div", {
        className: "huge-icon group-chat"
      }), REaCt().createElement("h3", null, REaCt().createElement(utils.zT, null, room.getRoomTitle())), REaCt().createElement("h5", null, usersCount ? mega.icu.format(l[20233], usersCount) : ''), REaCt().createElement("p", null, l[20595]))), REaCt().createElement("footer", null, REaCt().createElement("div", {
        className: "bottom-buttons"
      }, REaCt().createElement("button", {
        className: "mega-button positive",
        onClick: () => {
          closeJoinDialog();
          megaChat.loginOrRegisterBeforeJoining(room.publicChatHandle, false, false, false, () => {
            megaChat.routing.reinitAndJoinPublicChat(room.chatId, room.publicChatHandle, room.publicChatKey).then(() => {
              delete megaChat.initialPubChatHandle;
            }, ex => {
              console.error("Failed to join room:", ex);
            });
          });
        }
      }, l[20597]), REaCt().createElement("button", {
        className: "mega-button",
        onClick: closeJoinDialog
      }, l[18682]))));
    }
    let privateChatDialog;
    if (self.state.privateChatDialog === true) {
      const onClose = () => this.setState({
        privateChatDialog: false
      });
      privateChatDialog = REaCt().createElement(modalDialogs.A.ModalDialog, {
        title: l[20594],
        className: "mega-dialog create-private-chat",
        chatRoom: room,
        onClose,
        dialogType: "action",
        dialogName: "create-private-chat-dialog"
      }, REaCt().createElement("section", {
        className: "content"
      }, REaCt().createElement("div", {
        className: "content-block"
      }, REaCt().createElement("i", {
        className: "huge-icon lock"
      }), REaCt().createElement("div", {
        className: "dialog-body-text"
      }, REaCt().createElement("strong", null, l[20590]), REaCt().createElement("br", null), REaCt().createElement("span", null, l[20591])))), REaCt().createElement("footer", null, REaCt().createElement("div", {
        className: "footer-container"
      }, REaCt().createElement("button", {
        className: "mega-button positive large",
        onClick: () => {
          this.props.chatRoom.switchOffPublicMode();
          onClose();
        }
      }, REaCt().createElement("span", null, l[20593])))));
    }
    let confirmDeleteDialog = null;
    if (self.state.confirmDeleteDialog === true) {
      confirmDeleteDialog = REaCt().createElement(modalDialogs.A.ConfirmDialog, {
        chatRoom: room,
        dialogType: "main",
        title: l[8004],
        subtitle: l[8879],
        name: "delete-message",
        pref: "1",
        onClose: () => {
          self.setState({
            'confirmDeleteDialog': false
          });
        },
        onConfirmClicked: () => {
          const msg = self.state.messageToBeDeleted;
          if (!msg) {
            return;
          }
          const chatdint = room.megaChat.plugins.chatdIntegration;
          if (msg.getState() === Message.STATE.SENT || msg.getState() === Message.STATE.DELIVERED || msg.getState() === Message.STATE.NOT_SENT) {
            const textContents = msg.textContents || '';
            if (textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.VOICE_CLIP) {
              const attachmentMetadata = msg.getAttachmentMeta() || [];
              Promise.all(attachmentMetadata.map(v => M.moveToRubbish(v.h))).catch(dump);
            }
            chatdint.deleteMessage(room, msg.internalId ? msg.internalId : msg.orderValue);
            msg.deleted = true;
            msg.textContents = "";
          } else if (msg.getState() === Message.STATE.NOT_SENT_EXPIRED) {
            chatdint.discardMessage(room, msg.internalId ? msg.internalId : msg.orderValue);
          }
          self.setState({
            'confirmDeleteDialog': false,
            'messageToBeDeleted': false
          });
          if (msg.getState && msg.getState() === Message.STATE.NOT_SENT && !msg.requiresManualRetry) {
            msg.message = "";
            msg.textContents = "";
            msg.messageHtml = "";
            msg.deleted = true;
            msg.trigger('onChange', [msg, "deleted", false, true]);
          }
        }
      }, REaCt().createElement("section", {
        className: "content"
      }, REaCt().createElement("div", {
        className: "content-block"
      }, REaCt().createElement(generic.A, {
        className: " dialog-wrapper",
        message: self.state.messageToBeDeleted,
        hideActionButtons: true,
        initTextScrolling: true,
        dialog: true,
        chatRoom: self.props.chatRoom
      }))));
    }
    if (self.state.pasteImageConfirmDialog) {
      confirmDeleteDialog = REaCt().createElement(modalDialogs.A.ConfirmDialog, {
        chatRoom: room,
        title: l[20905],
        subtitle: l[20906],
        icon: "sprite-fm-uni icon-question",
        name: "paste-image-chat",
        pref: "2",
        onClose: () => {
          self.setState({
            'pasteImageConfirmDialog': false
          });
        },
        onConfirmClicked: () => {
          const meta = self.state.pasteImageConfirmDialog;
          if (!meta) {
            return;
          }
          try {
            Object.defineProperty(meta[0], 'name', {
              configurable: true,
              writeable: true,
              value: `${Date.now()  }.${  M.getSafeName(meta[1] || meta[0].name)}`
            });
          } catch (e) {}
          self.props.chatRoom.scrolledToBottom = true;
          M.addUpload([meta[0]]);
          self.setState({
            'pasteImageConfirmDialog': false
          });
          URL.revokeObjectURL(meta[2]);
        }
      }, REaCt().createElement("img", {
        src: self.state.pasteImageConfirmDialog[2],
        style: {
          maxWidth: "90%",
          height: "auto",
          maxHeight: $(document).outerHeight() * 0.3,
          margin: '10px auto',
          display: 'block',
          border: '1px solid #ccc',
          borderRadius: '4px'
        },
        onLoad (e) {
          $(e.target).parents('.paste-image-chat').position({
            of: $(document.body)
          });
        }
      }));
    }
    if (self.state.truncateDialog === true) {
      confirmDeleteDialog = REaCt().createElement(modalDialogs.A.ConfirmDialog, {
        chatRoom: room,
        title: room.isMeeting ? l.meeting_clear_hist : l[8871],
        subtitle: room.isMeeting ? l.meeting_trunc_txt : l[8881],
        icon: "sprite-fm-uni icon-question",
        name: "truncate-conversation",
        pref: "3",
        dontShowAgainCheckbox: false,
        onClose: () => {
          self.setState({
            'truncateDialog': false
          });
        },
        onConfirmClicked: () => {
          self.props.chatRoom.scrolledToBottom = true;
          room.truncate();
          self.setState({
            'truncateDialog': false
          });
        }
      });
    }
    if (self.state.archiveDialog === true) {
      confirmDeleteDialog = REaCt().createElement(modalDialogs.A.ConfirmDialog, {
        chatRoom: room,
        title: room.isMeeting ? l.meeting_archive_dlg : l[19068],
        subtitle: room.isMeeting ? l.meeting_archive_dlg_text : l[19069],
        icon: "sprite-fm-uni icon-question",
        name: "archive-conversation-dialog",
        pref: "4",
        onClose: () => {
          self.setState({
            'archiveDialog': false
          });
        },
        onConfirmClicked: () => {
          self.props.chatRoom.scrolledToBottom = true;
          room.archive();
          self.setState({
            'archiveDialog': false
          });
        }
      });
    }
    if (self.state.unarchiveDialog === true) {
      confirmDeleteDialog = REaCt().createElement(modalDialogs.A.ConfirmDialog, {
        chatRoom: room,
        title: room.isMeeting ? l.meeting_unarchive_dlg : l[19063],
        subtitle: room.isMeeting ? l.meeting_unarchive_dlg_text : l[19064],
        icon: "sprite-fm-uni icon-question",
        name: "unarchive-conversation-dialog",
        pref: "5",
        onClose: () => {
          self.setState({
            'unarchiveDialog': false
          });
        },
        onConfirmClicked: () => {
          self.props.chatRoom.scrolledToBottom = true;
          room.unarchive();
          self.setState({
            'unarchiveDialog': false
          });
        }
      });
    }
    let topicInfo = null;
    const isUpcoming = room.scheduledMeeting && room.scheduledMeeting.isUpcoming;
    const isRecurring = room.scheduledMeeting && room.scheduledMeeting.isRecurring;
    if (room.type === 'group' || room.type === 'public') {
      topicInfo = REaCt().createElement("div", {
        className: "chat-topic-info"
      }, REaCt().createElement("div", {
        className: `
                            chat-topic-icon
                            ${room.isMeeting ? 'meeting-icon' : ''}
                        `
      }, REaCt().createElement("i", {
        className: room.isMeeting ? 'sprite-fm-mono icon-video-call-filled' : 'sprite-fm-uni icon-chat-group'
      })), REaCt().createElement("div", {
        className: "chat-topic-text"
      }, REaCt().createElement("span", {
        className: "txt"
      }, REaCt().createElement(utils.zT, null, room.getRoomTitle()), isUpcoming && isRecurring && REaCt().createElement("i", {
        className: "sprite-fm-mono recurring-meeting icon-repeat-thin-solid"
      })), REaCt().createElement("span", {
        className: "txt small"
      }, is_chatlink && isUpcoming && !isRecurring ? this.renderUpcomingInfo() : REaCt().createElement(ui_contacts.MembersAmount, {
        chatRoom: room
      }))));
    } else {
      contactHandle = contacts[0];
      contact = M.u[contactHandle || u_handle];
      topicInfo = megaChat.WITH_SELF_NOTE && room.isNote ? REaCt().createElement("div", {
        className: "note-chat-topic"
      }, REaCt().createElement("div", {
        className: "note-chat-signifier"
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
      })), REaCt().createElement("span", {
        className: "note-chat-label"
      }, l.note_label)) : REaCt().createElement(ui_contacts.ContactCard, {
        key: contact.u,
        className: "short",
        chatRoom: room,
        contact,
        noContextButton: true,
        showLastGreen: true
      });
    }
    let historyRetentionDialog = null;
    if (self.state.showHistoryRetentionDialog === true) {
      historyRetentionDialog = REaCt().createElement(HistoryRetentionDialog, {
        chatRoom: room,
        title: '',
        name: "rename-group",
        className: "",
        onClose: () => {
          self.setState({
            showHistoryRetentionDialog: false
          });
        }
      });
    }
    if (this.state.waitingRoom) {
      return REaCt().createElement(WaitingRoom, {
        chatRoom: room,
        havePendingCall: room.havePendingCall(),
        onWaitingRoomLeave: () => {
          let _room$call;
          (_room$call = room.call) == null || _room$call.destroy();
          if (is_eplusplus) {
            room.leave(true);
            return onIdle(M.logout);
          }
          return this.setState({
            waitingRoom: false
          }, () => {
            onIdle(() => {
              if (megaChat.initialChatId) {
                megaChat.initialChatId = undefined;
                loadSubPage(getLandingPage());
              }
            });
          });
        }
      });
    }
    if (this.state.callUserLimit) {
      return REaCt().createElement(ChatOverlay, {
        overlayType: ChatOverlays.PARTICIPANT_LIMIT,
        onClose: () => {
          if (is_eplusplus) {
            location.replace('https://mega.io');
          } else {
            this.setState({
              callUserLimit: false
            });
          }
        }
      });
    }
    const startCallDisabled = isStartCallDisabled(room) || room.iAmWaitingRoomPeer();
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                    conversation-panel
                    ${room.type === 'public' ? 'group-chat ' : ''}
                    ${room.type}-chat
                    ${!room.isCurrentlyActive || megaChat._joinDialogIsShown ? 'hidden' : ''}
                `,
      onMouseMove: () => self.onMouseMove(),
      "data-room-id": self.props.chatRoom.chatId
    }, room.meetingsLoading && REaCt().createElement(Loading, {
      chatRoom: room,
      title: room.meetingsLoading.title
    }), room.call && REaCt().createElement(call.Ay, {
      chatRoom: room,
      peers: room.call.peers,
      call: room.call,
      minimized: this.state.callMinimized,
      typingAreaText: this.state.typingAreaText,
      onCallMinimize: () => {
        return this.state.callMinimized ? null : this.setState({
          callMinimized: true
        }, () => {
          this.toggleExpandedFlag();
          this.safeForceUpdate();
        });
      },
      onCallExpand: () => {
        return this.state.callMinimized && this.setState({
          callMinimized: false
        }, () => {
          $.hideTopMenu();
          if ($.dialog) {
            closeDialog();
          }
          loadSubPage('fm/chat');
          room.show();
          this.toggleExpandedFlag();
        });
      },
      didMount: () => {
        this.toggleExpandedFlag();
        if (room.isMeeting) {
          room.updatePublicHandle().catch(dump);
        }
      },
      willUnmount: minimised => this.setState({
        callMinimized: false
      }, () => minimised ? null : this.toggleExpandedFlag()),
      onCallEnd: () => this.safeForceUpdate(),
      onDeleteMessage: msg => this.handleDeleteDialog(msg),
      onTypingAreaChanged: this.updateTypingAreaText,
      parent: this
    }), megaChat.initialPubChatHandle && room.publicChatHandle === megaChat.initialPubChatHandle && !room.call && room.isMeeting && !room.call && room.activeCallIds.length > 0 && REaCt().createElement(Join, {
      initialView: u_type || is_eplusplus ? Join.VIEW.ACCOUNT : Join.VIEW.INITIAL,
      chatRoom: room,
      onJoinGuestClick: (firstName, lastName, audioFlag, videoFlag) => {
        room.meetingsLoading = l.joining;
        u_eplusplus(firstName, lastName).then(() => {
          return megaChat.routing.reinitAndJoinPublicChat(room.chatId, room.publicChatHandle, room.publicChatKey);
        }).then(() => {
          delete megaChat.initialPubChatHandle;
          return megaChat.getChatById(room.chatId).joinCall(audioFlag, videoFlag);
        }).catch(ex => {
          if (d) {
            console.error('E++ account failure!', ex);
          }
          setTimeout(() => {
            msgDialog('warninga', l[135], l.eplusplus_create_failed, escapeHTML(api_strerror(ex) || ex));
          }, 1234);
          eventlog(99745, JSON.stringify([1, String(ex).split('\n')[0]]));
        });
      },
      onJoinClick: (audioFlag, videoFlag) => {
        const {chatId} = room;
        if (room.members[u_handle]) {
          delete megaChat.initialPubChatHandle;
          megaChat.routing.reinitAndOpenExistingChat(chatId, room.publicChatHandle).then(() => {
            return megaChat.getChatById(chatId).joinCall(audioFlag, videoFlag);
          }).catch(ex => {
            console.error("Failed to open existing room and join call:", ex);
          });
        } else {
          megaChat.routing.reinitAndJoinPublicChat(chatId, room.publicChatHandle, room.publicChatKey).then(() => {
            delete megaChat.initialPubChatHandle;
            return megaChat.getChatById(chatId).joinCall(audioFlag, videoFlag);
          }).catch(ex => {
            console.error("Failed to join room:", ex);
          });
        }
      }
    }), REaCt().createElement("div", {
      className: `
                        chat-content-block
                        ${room.megaChat.chatUIFlags.convPanelCollapse ? 'no-pane' : 'with-pane'}
                    `
    }, room.megaChat.chatUIFlags.convPanelCollapse ? null : REaCt().createElement(ConversationRightArea, {
      isVisible: this.props.chatRoom.isCurrentlyActive,
      chatRoom: this.props.chatRoom,
      roomFlags: this.props.chatRoom.flags,
      members: this.props.chatRoom.membersSetFromApi,
      messagesBuff: room.messagesBuff,
      pushSettingsValue: pushNotificationSettings.getDnd(this.props.chatRoom.chatId),
      occurrencesLoading: this.state.occurrencesLoading,
      onStartCall: mode => (0,call.dQ)(room.haveActiveCall(), room).then(() => this.startCall(mode)).catch(() => d && console.warn('Already in a call.')),
      onAttachFromComputerClicked: () => this.props.chatRoom.uploadFromComputer(),
      onTruncateClicked: () => this.setState({
        truncateDialog: true
      }),
      onArchiveClicked: () => this.setState({
        archiveDialog: true
      }),
      onUnarchiveClicked: () => this.setState({
        unarchiveDialog: true
      }),
      onRenameClicked: () => {
        this.setState({
          renameDialog: true,
          renameDialogValue: this.props.chatRoom.getRoomTitle()
        });
      },
      onGetManageChatLinkClicked: () => this.setState({
        chatLinkDialog: true
      }),
      onMakePrivateClicked: () => this.setState({
        privateChatDialog: true
      }),
      onCloseClicked: () => room.destroy(),
      onJoinViaPublicLinkClicked: () => room.joinViaPublicHandle(),
      onSwitchOffPublicMode: topic => room.switchOffPublicMode(topic),
      onAttachFromCloudClicked: () => this.setState({
        attachCloudDialog: true
      }),
      onPushSettingsClicked: () => M.safeShowDialog('push-settings-dialog', () => this.setState({
        pushSettingsDialog: true
      })),
      onPushSettingsToggled: () => {
        return room.dnd || room.dnd === 0 ? this.setState({
          pushSettingsValue: null
        }, () => pushNotificationSettings.disableDnd(room.chatId)) : pushNotificationSettings.setDnd(room.chatId, 0);
      },
      onHistoryRetentionConfig: () => this.setState({
        showHistoryRetentionDialog: true
      }),
      onAddParticipantSelected: contactHashes => {
        room.scrolledToBottom = true;
        if (room.type === 'group' || room.type === 'public') {
          if (room.options.w && room.call) {
            let _room$call$sfuClient;
            (_room$call$sfuClient = room.call.sfuClient) == null || _room$call$sfuClient.wrAllowJoin(contactHashes);
          }
          return room.trigger('onAddUserRequest', [contactHashes]);
        }
        loadingDialog.show();
        megaChat.trigger('onNewGroupChatRequest', [[...room.getParticipantsExceptMe(), ...contactHashes], {
          keyRotation: false,
          topic: ''
        }]);
      },
      onShowScheduledDescription: room.scheduledMeeting ? () => this.setState({
        descriptionDialog: true
      }) : null
    }), this.state.attachCloudDialog && REaCt().createElement(this.CloudBrowserDialog, null), this.state.sendContactDialog && REaCt().createElement(this.SelectContactDialog, null), this.state.descriptionDialog && REaCt().createElement(this.DescriptionDialog, null), this.state.pushSettingsDialog && REaCt().createElement(this.PushSettingsDialog, null), privateChatDialog, nonLoggedInJoinChatDialog, confirmDeleteDialog, historyRetentionDialog, null, this.state.renameDialog && REaCt().createElement(this.RenameDialog, null), this.state.chatLinkDialog && REaCt().createElement(ChatlinkDialog, {
      chatRoom: this.props.chatRoom,
      onClose: () => this.setState({
        chatLinkDialog: false
      })
    }), REaCt().createElement("div", {
      className: `
                            chat-topic-block
                            ${room.isNote ? 'is-note' : ''}
                        `
    }, REaCt().createElement("div", {
      className: "chat-topic-buttons"
    }, room.type === 'public' && room.isMeeting && REaCt().createElement(buttons.$, {
      className: "mega-button small share-meeting-button",
      label: l.share_meeting_button,
      onClick: () => this.setState({
        chatLinkDialog: true
      }, () => eventlog(500230))
    }), REaCt().createElement(buttons.$, {
      className: "right",
      disableCheckingVisibility: true,
      icon: "sprite-fm-mono icon-info-filled",
      onClick: () => room.megaChat.toggleUIFlag('convPanelCollapse')
    }), room.isNote ? null : REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
      "data-simpletip": l.unsupported_browser_video,
      "data-simpletipposition": "top",
      "data-simpletipoffset": "5",
      className: `
                                            ${!megaChat.hasSupportForCalls ? 'simpletip' : ''}
                                            right
                                            ${startCallDisabled ? 'disabled' : ''}
                                        `
    }, REaCt().createElement(buttons.$, {
      icon: "sprite-fm-mono icon-video-call-filled",
      onClick: () => startCallDisabled ? false : (0,call.dQ)(room.haveActiveCall(), room).then(() => this.startCall(call.ZE.VIDEO)).catch(() => d && console.warn('Already in a call.')).then(() => room.isMeeting ? eventlog(500289) : eventlog(500290))
    })), REaCt().createElement("div", {
      "data-simpletip": l.unsupported_browser_audio,
      "data-simpletipposition": "top",
      "data-simpletipoffset": "5",
      className: `
                                            ${!megaChat.hasSupportForCalls ? 'simpletip' : ''}
                                            right
                                            ${startCallDisabled ? 'disabled' : ''}
                                        `
    }, REaCt().createElement(buttons.$, {
      icon: "sprite-fm-mono icon-phone",
      onClick: () => startCallDisabled ? false : (0,call.dQ)(room.haveActiveCall(), room).then(() => this.startCall(call.ZE.AUDIO)).catch(() => d && console.warn('Already in a call.')).then(() => room.isMeeting ? eventlog(500291) : eventlog(500292))
    })))), topicInfo), REaCt().createElement("div", {
      ref: this.messagesBlockRef,
      className: `
                            messages-block
                            ${""}
                        `
    }, this.state.hasInvalidKeys && this.state.invalidKeysBanner && REaCt().createElement(Alert, {
      type: Alert.TYPE.HIGH,
      className: `
                                    ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
                                    ${this.props.offset === ALERTS_BASE_OFFSET ? 'single-alert' : ''}
                                `,
      offset: this.props.offset === ALERTS_BASE_OFFSET ? 0 : this.props.offset,
      content: REaCt().createElement(REaCt().Fragment, null, l.chat_key_failed_banner.split('[A]')[0], REaCt().createElement("a", {
        onClick: () => M.reload()
      }, l.chat_key_failed_banner.substring(l.chat_key_failed_banner.indexOf('[A]') + 3, l.chat_key_failed_banner.indexOf('[/A]'))), l.chat_key_failed_banner.split('[/A]')[1]),
      onClose: () => this.setState({
        invalidKeysBanner: false
      })
    }), this.state.historyTimeOutBanner === DISMISS_TRANSITIONS.SHOWN && REaCt().createElement(Alert, {
      type: Alert.TYPE.ERROR,
      className: `
                                    ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
                                    ${this.props.offset === ALERTS_BASE_OFFSET ? 'single_alert' : ''}
                                    history-timeout-banner
                                `,
      offset: this.props.offset === ALERTS_BASE_OFFSET ? 0 : this.props.offset,
      content: REaCt().createElement(REaCt().Fragment, null, l.chat_timeout_banner, REaCt().createElement("a", {
        onClick: () => location.reload()
      }, l[85])),
      onClose: () => this.setState({
        historyTimeOutBanner: DISMISS_TRANSITIONS.DISMISSED
      })
    }), REaCt().createElement(historyPanel.A, (0,esm_extends.A)({}, this.props, {
      onMessagesListScrollableMount: mls => {
        this.messagesListScrollable = mls;
      },
      ref: historyPanel => {
        this.historyPanel = historyPanel;
      },
      onDeleteClicked: msg => this.handleDeleteDialog(msg)
    })), !is_chatlink && room.state !== ChatRoom.STATE.LEFT && navigator.onLine && room.scheduledMeeting && !room.isArchived() && !this.state.hasInvalidKeys && !isStartCallDisabled(room) ? REaCt().createElement(StartMeetingNotification, {
      chatRoom: room,
      offset: this.props.offset,
      onWaitingRoomJoin: () => this.setState({
        waitingRoom: true
      }),
      onStartCall: mode => {
        return isStartCallDisabled(room) ? null : (0,call.dQ)(true, room).then(() => this.startCall(mode, true)).catch(ex => d && console.warn(`Already in a call. ${ex}`));
      }
    }) : null, !is_chatlink && room.state !== ChatRoom.STATE.LEFT && (room.havePendingGroupCall() || room.havePendingCall()) && !this.state.hasInvalidKeys && navigator.onLine ? REaCt().createElement(JoinCallNotification, {
      rhpCollapsed: megaChat.chatUIFlags.convPanelCollapse,
      chatRoom: room,
      offset: this.props.offset
    }) : null, room.isAnonymous() ? REaCt().createElement("div", {
      className: "join-chat-block"
    }, REaCt().createElement("div", {
      className: "mega-button large positive",
      onClick: () => {
        const join = () => {
          megaChat.routing.reinitAndJoinPublicChat(room.chatId, room.publicChatHandle, room.publicChatKey).then(() => delete megaChat.initialPubChatHandle, ex => console.error("Failed to join room:", ex));
        };
        if (u_type === 0) {
          return loadSubPage('register');
        }
        if (u_type === false) {
          clearTimeout(self.state.setNonLoggedInJoinChatDlgTrue);
          megaChat.loginOrRegisterBeforeJoining(room.publicChatHandle, false, false, false, join);
          return;
        }
        clearTimeout(self.state.setNonLoggedInJoinChatDlgTrue);
        join();
      }
    }, l[20597])) : REaCt().createElement(composedTextArea.A, {
      chatRoom: room,
      parent: this,
      containerRef: this.messagesBlockRef,
      typingAreaText: this.state.typingAreaText,
      onTypingAreaChanged: this.updateTypingAreaText
    }))));
  }
}, (0,applyDecoratedDescriptor.A)(conversationpanel_class.prototype, "onMouseMove", [conversationpanel_dec], Object.getOwnPropertyDescriptor(conversationpanel_class.prototype, "onMouseMove"), conversationpanel_class.prototype), (0,applyDecoratedDescriptor.A)(conversationpanel_class.prototype, "render", [_dec2], Object.getOwnPropertyDescriptor(conversationpanel_class.prototype, "render"), conversationpanel_class.prototype), conversationpanel_class);
class ConversationPanels extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.notificationListener = 'meetings:notificationPermissions';
    this.notificationGranted = undefined;
    this.notificationHelpURL = `${l.mega_help_host}/chats-meetings/meetings/enable-notification-browser-system-permission`;
    this.state = {
      supportAlert: undefined,
      notificationsPermissions: undefined,
      alertsOffset: ALERTS_BASE_OFFSET
    };
    this.closeSupportAlert = () => this.setState({
      supportAlert: false
    }, () => mega.config.set('nocallsup', 1));
    this.onNotificationsGranted = () => {
      msgDialog('info', '', l.notifications_permissions_granted_title, l.notifications_permissions_granted_info.replace('[A]', `<a href="${this.notificationHelpURL}" target="_blank" class="clickurl">`).replace('[/A]', '</a>'));
      this.notificationGranted = new Notification(l.notification_granted_title, {
        body: l.notification_granted_body
      });
    };
    this.state.supportAlert = !megaChat.hasSupportForCalls;
    this.state.notificationsPermissions = window.Notification ? Notification.permission : 'granted';
  }
  renderNotificationsPending() {
    return REaCt().createElement(Alert, {
      type: Alert.TYPE.LIGHT,
      className: `
                    ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
                    ${this.props.isEmpty ? 'empty-state' : ''}
                `,
      ref: ref => {
        this.notifPendingRef = ref;
      },
      onTransition: ref => this.setState({
        alertsOffset: ref ? ref.current.offsetHeight : ALERTS_BASE_OFFSET
      }),
      onClose: () => {
        this.setState({
          notificationsPermissions: undefined
        }, () => {
          showToast('success', l.notifications_permissions_toast_title, l.notifications_permissions_toast_control, '', () => loadSubPage('fm/account/notifications'));
        });
      }
    }, l.notifications_permissions_pending, REaCt().createElement("div", {
      className: "meetings-alert-control"
    }, REaCt().createElement("a", {
      href: "#",
      onClick: ev => {
        ev.preventDefault();
        Notification.requestPermission().then(status => {
          this.setState({
            notificationsPermissions: status
          }, () => onIdle(() => this.state.notificationsPermissions === 'granted' && this.onNotificationsGranted()));
        }).catch(ex => d && console.warn(`Failed to retrieve permissions: ${ex}`));
      }
    }, l.notifications_permissions_enable)));
  }
  renderNotificationsBlocked() {
    return REaCt().createElement(Alert, {
      type: Alert.TYPE.MEDIUM,
      className: `
                    ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
                    ${this.props.isEmpty ? 'empty-state' : ''}
                `,
      ref: ref => {
        this.notifBlockedRef = ref;
      },
      onTransition: ref => this.setState({
        alertsOffset: ref ? ref.current.offsetHeight : ALERTS_BASE_OFFSET
      }),
      onClose: () => this.setState({
        notificationsPermissions: undefined
      })
    }, REaCt().createElement(utils.P9, {
      content: l.notifications_permissions_denied_info.replace('[A]', `<a href="${this.notificationHelpURL}" target="_blank" class="clickurl">`).replace('[/A]', '</a>')
    }));
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    mBroadcaster.removeListener(this.notificationListener);
  }
  componentDidMount() {
    let _this$props$onMount, _this$props;
    super.componentDidMount();
    (_this$props$onMount = (_this$props = this.props).onMount) == null || _this$props$onMount.call(_this$props);
    megaChat.chats.forEach(chatRoom => {
      const {
        scheduledMeeting
      } = chatRoom;
      if (scheduledMeeting && !scheduledMeeting.isPast && scheduledMeeting.isRecurring) {
        scheduledMeeting.getOccurrences().catch(nop);
      }
    });
    mBroadcaster.addListener(this.notificationListener, notificationsPermissions => this.isMounted() && this.setState({
      notificationsPermissions
    }));
    window.addEventListener('resize', () => {
      delay('conv-panels-resize', () => {
        if (!M.chat || !this.isMounted()) {
          return;
        }
        const {
          alertsOffset
        } = this.state;
        if (alertsOffset !== ALERTS_BASE_OFFSET) {
          let _this$notifBlockedRef, _this$notifPendingRef, _this$noSupportRef;
          const state = {};
          if ((_this$notifBlockedRef = this.notifBlockedRef) != null && _this$notifBlockedRef.current) {
            state.alertsOffset = this.notifBlockedRef.current.offsetHeight;
          } else if ((_this$notifPendingRef = this.notifPendingRef) != null && _this$notifPendingRef.current) {
            state.alertsOffset = this.notifPendingRef.current.offsetHeight;
          } else if ((_this$noSupportRef = this.noSupportRef) != null && _this$noSupportRef.current) {
            state.alertsOffset = this.noSupportRef.current.offsetHeight;
          }
          if (state.alertsOffset !== alertsOffset) {
            this.setState(state);
          }
        }
      });
    });
  }
  render() {
    const {
      routingSection,
      chatUIFlags,
      isEmpty,
      onToggleExpandedFlag
    } = this.props;
    const {
      notificationsPermissions,
      supportAlert,
      alertsOffset
    } = this.state;
    const now = Date.now();
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "conversation-panels"
    }, routingSection === 'contacts' || is_chatlink ? null : window.Notification && notificationsPermissions !== 'granted' && REaCt().createElement(REaCt().Fragment, null, notificationsPermissions === 'default' && this.renderNotificationsPending(), notificationsPermissions === 'denied' && this.renderNotificationsBlocked()), routingSection === 'contacts' ? null : supportAlert && !mega.config.get('nocallsup') && REaCt().createElement(Alert, {
      type: Alert.TYPE.MEDIUM,
      className: `
                                ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
                                ${isEmpty ? 'empty-state' : ''}
                                unsupported-call-alert
                            `,
      content: call.Ay.getUnsupportedBrowserMessage(),
      ref: ref => {
        this.noSupportRef = ref;
      },
      onTransition: ref => this.setState({
        alertsOffset: ref ? ref.current.offsetHeight : ALERTS_BASE_OFFSET
      }),
      onClose: this.closeSupportAlert
    }), megaChat.chats.map(chatRoom => {
      if (chatRoom.isCurrentlyActive || now - chatRoom.lastShownInUI < 900000) {
        return REaCt().createElement(ConversationPanel, {
          key: `${chatRoom.roomId}_${chatRoom.instanceIndex}`,
          chatRoom,
          roomType: chatRoom.type,
          isExpanded: chatRoom.megaChat.chatUIFlags.convPanelCollapse,
          isActive: chatRoom.isCurrentlyActive,
          messagesBuff: chatRoom.messagesBuff,
          chatUIFlags,
          offset: alertsOffset,
          onToggleExpandedFlag
        });
      }
      return null;
    }));
  }
}
class EmptyConvPanel extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.state = {
      linkData: ''
    };
    this.Tile = ({
      title,
      desc,
      imgClass,
      buttonPrimary,
      buttonSecondary,
      onClickPrimary,
      onClickSecondary
    }) => REaCt().createElement("div", {
      className: "conversations-empty-tile"
    }, REaCt().createElement("span", {
      className: `chat-tile-img ${imgClass}`
    }), REaCt().createElement("div", {
      className: "tile-content"
    }, REaCt().createElement("h2", null, title), REaCt().createElement("div", null, desc), REaCt().createElement(buttons.$, {
      className: "mega-button positive",
      label: buttonPrimary,
      onClick: onClickPrimary
    }), buttonSecondary && REaCt().createElement(buttons.$, {
      className: "mega-button action positive",
      icon: "sprite-fm-mono icon-link",
      label: buttonSecondary,
      onClick: onClickSecondary
    })));
  }
  componentDidMount() {
    (M.account && M.account.contactLink ? Promise.resolve(M.account.contactLink) : api.send('clc')).then(res => {
      let _this$domRef;
      if ((_this$domRef = this.domRef) != null && _this$domRef.current && typeof res === 'string') {
        const prefix = res.startsWith('C!') ? '' : 'C!';
        this.setState({
          linkData: `${getBaseUrl()}/${prefix}${res}`
        });
      }
    }).catch(dump);
  }
  render() {
    const {
      isMeeting,
      onNewChat,
      onStartMeeting,
      onScheduleMeeting
    } = this.props;
    const {
      linkData
    } = this.state;
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "conversations-empty"
    }, REaCt().createElement("div", {
      className: "conversations-empty-header"
    }, REaCt().createElement("h1", null, isMeeting ? l.meetings_empty_header : l.chat_empty_header), REaCt().createElement("h3", null, (0,utils.lI)(isMeeting ? l.meetings_empty_subheader : l.chat_empty_subheader, '[A]', ui_link.A, {
      onClick: () => {
        window.open('https://mega.io/chatandmeetings', '_blank', 'noopener,noreferrer');
        eventlog(this.props.isMeeting ? 500281 : 500280);
      }
    }))), REaCt().createElement("div", {
      className: "conversations-empty-content"
    }, REaCt().createElement(this.Tile, {
      title: isMeeting ? l.meetings_empty_calls_head : l.invite_friend_btn,
      desc: isMeeting ? l.meetings_empty_calls_desc : l.chat_empty_contact_desc,
      imgClass: isMeeting ? 'empty-meetings-call' : 'empty-chat-contacts',
      buttonPrimary: isMeeting ? l.new_meeting_start : l[71],
      buttonSecondary: !isMeeting && linkData && l.copy_contact_link_btn,
      onClickPrimary: () => {
        if (isMeeting) {
          onStartMeeting();
          eventlog(500275);
        } else {
          contactAddDialog();
          eventlog(500276);
        }
      },
      onClickSecondary: () => {
        copyToClipboard(linkData, `${l[371]}<span class="link-text">${linkData}</span>`);
        delay('chat-event-copy-contact-link', () => eventlog(500277));
      }
    }), REaCt().createElement(this.Tile, {
      title: isMeeting ? l.meetings_empty_schedule_head : l.chat_empty_add_chat_header,
      desc: isMeeting ? l.meetings_empty_schedule_desc : l.chat_empty_add_chat_desc,
      imgClass: isMeeting ? 'empty-meetings-schedule' : 'empty-chat-new',
      buttonPrimary: isMeeting ? l.schedule_meeting_start : l.add_chat,
      onClickPrimary: () => {
        if (isMeeting) {
          onScheduleMeeting();
          eventlog(500278);
        } else {
          onNewChat();
          eventlog(500279);
        }
      }
    })));
  }
}
function isStartCallDisabled(room) {
  if ((0,call.P)()) {
    return true;
  }
  if (!megaChat.hasSupportForCalls) {
    return true;
  }
  return !room.isOnlineForCalls() || room.isReadOnly() || !room.chatId || room.call || (room.type === "group" || room.type === "public") && false || room.getCallParticipants().length > 0;
}

},

446:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
M: () => ConversationMessageMixin
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);
const _mixins1__ = REQ_(137);
const _ui_buttons_jsx2__ = REQ_(994);
const _ui_emojiDropdown_jsx3__ = REQ_(844);




class ConversationMessageMixin extends _mixins1__.u9 {
  constructor(props) {
    super(props);
    this.attachRerenderCallbacks = false;
    this._reactionContactHandles = [];
    this.__cmmUpdateTickCount = 0;
    this._contactChangeListeners = false;
    this.onAfterRenderWasTriggered = false;
    lazy(this, '__cmmId', () => {
      return `${this.getUniqueId()  }--${  String(Math.random()).slice(-7)}`;
    });
    this._emojiOnActiveStateChange = this._emojiOnActiveStateChange.bind(this);
    this.emojiSelected = this.emojiSelected.bind(this);
    const {
      message: msg
    } = this.props;
    if (msg instanceof Message && msg._reactions && msg.messageId.length === 11 && msg.isSentOrReceived() && !Object.hasOwnProperty.call(msg, 'reacts')) {
      msg.reacts.forceLoad().then(() => {
        this.addContactListenerIfMissing(this._reactionContacts());
      }).catch(dump.bind(null, `reactions.load.${msg.messageId}`));
    }
  }
  UNSAFE_componentWillMount() {
    if (super.UNSAFE_componentWillMount) {
      super.UNSAFE_componentWillMount();
    }
    const {chatRoom} = this.props;
    if (chatRoom) {
      chatRoom.rebind(`onChatShown.${  this.__cmmId}`, () => {
        if (!this._contactChangeListeners) {
          this.addContactListeners();
        }
      }).rebind(`onChatHidden.${  this.__cmmId}`, () => {
        if (this._contactChangeListeners) {
          this.removeContactListeners();
        }
      });
    }
    this.addContactListeners();
  }
  haveMeetingsCall() {
    return document.querySelector('.meetings-call') && document.querySelector('.chat-opened');
  }
  removeContactListeners() {
    const users = this._contactChangeListeners;
    if (d > 3) {
      console.warn('%s.removeContactListeners', this.getReactId(), [this], users);
    }
    for (let i = users.length; i--;) {
      users[i].removeEventHandler(this);
    }
    this._contactChangeListeners = false;
  }
  _reactionContacts() {
    const {
      message
    } = this.props;
    const {
      reacts
    } = message;
    const handles = [];
    const reactions = Object.values(reacts.reactions);
    for (let i = 0; i < reactions.length; i++) {
      handles.push(...Object.keys(reactions[i]));
    }
    this._reactionContactHandles = array.unique(handles);
    return this._reactionContactHandles;
  }
  addContactListeners() {
    const users = this._contactChangeListeners || [];
    const addUser = user => {
      if (user instanceof MegaDataMap && users.indexOf(user) < 0) {
        users.push(user);
      }
    };
    addUser(this.getContact());
    if (this.haveMoreContactListeners) {
      const moreIds = this.haveMoreContactListeners();
      if (moreIds) {
        for (let i = moreIds.length; i--;) {
          const handle = moreIds[i];
          addUser(handle in M.u && M.u[handle]);
        }
      }
    }
    for (let i = this._reactionContactHandles.length; i--;) {
      addUser(this._reactionContactHandles[i] in M.u && M.u[this._reactionContactHandles[i]]);
    }
    if (d > 3) {
      console.warn('%s.addContactListeners', this.getReactId(), [this], users);
    }
    for (let i = users.length; i--;) {
      users[i].addChangeListener(this);
    }
    this._contactChangeListeners = users;
  }
  addContactListenerIfMissing(contacts) {
    if (!this._contactChangeListeners) {
      return false;
    }
    if (!Array.isArray(contacts)) {
      contacts = [contacts];
    }
    const added = [];
    for (let i = 0; i < contacts.length; i++) {
      const user = M.u[contacts[i]];
      if (user && !this._contactChangeListeners.includes(user)) {
        this._contactChangeListeners.push(user);
        user.addChangeListener(this);
        added.push(user.h);
      }
    }
    if (d > 1) {
      console.warn('%s.addContactListenerIfMissing', this.getReactId(), [this], added);
    }
  }
  eventuallyUpdate() {
    super.eventuallyUpdate();
    this.__cmmUpdateTickCount = -2;
  }
  handleChangeEvent(x, z, k) {
    if (k === 'ts' || k === 'ats') {
      return;
    }
    if (this.isComponentEventuallyVisible()) {
      if (++this.__cmmUpdateTickCount > 5) {
        this.eventuallyUpdate();
        delay.cancel(this.__cmmId);
      } else {
        delay(this.__cmmId, () => this.eventuallyUpdate(), 90);
      }
    } else {
      this._requiresUpdateOnResize = true;
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    const {chatRoom} = this.props;
    if (chatRoom) {
      chatRoom.off(`onChatShown.${  this.__cmmId}`).off(`onChatHidden.${  this.__cmmId}`);
    }
    if (this._contactChangeListeners) {
      this.removeContactListeners();
    }
  }
  getContact() {
    if (this.props.contact) {
      return this.props.contact;
    }
    const {message} = this.props;
    return Message.getContactForMessage(message);
  }
  getTimestampAsString() {
    return toLocaleTime(this.getTimestamp());
  }
  getTimestamp(forUpdated) {
    const {
      message
    } = this.props;
    const timestamp = (message.getDelay == null ? void 0 : message.getDelay()) || message.delay || unixtime();
    return forUpdated && message.updated > 0 ? timestamp + message.updated : timestamp;
  }
  componentDidUpdate() {
    const self = this;
    const {chatRoom} = self.props.message;
    if (!self.onAfterRenderWasTriggered) {
      const msg = self.props.message;
      let shouldRender = true;
      if (msg.isManagement && msg.isManagement() === true && msg.isRenderableManagement() === false) {
        shouldRender = false;
      }
      if (shouldRender) {
        chatRoom.trigger("onAfterRenderMessage", self.props.message);
        self.onAfterRenderWasTriggered = true;
      }
    }
  }
  getCurrentUserReactions() {
    const {
      reactions
    } = this.props.message.reacts;
    return Object.keys(reactions).filter(utf => {
      let _reactions$utf;
      return (_reactions$utf = reactions[utf]) == null ? void 0 : _reactions$utf[u_handle];
    });
  }
  emojiSelected(e, slug, meta) {
    const {
      chatRoom,
      message,
      onEmojiBarChange
    } = this.props;
    if (chatRoom.isReadOnly()) {
      return false;
    }
    const {
      reactions
    } = this.props.message.reacts;
    const CURRENT_USER_REACTIONS = this.getCurrentUserReactions().length;
    const REACTIONS_LIMIT = {
      TOTAL: 50,
      PER_PERSON: 24
    };
    const addReaction = () => chatRoom.messagesBuff.userAddReaction(message.messageId, slug, meta);
    const emoji = megaChat._emojiData.emojisSlug[slug] || meta;
    if (emoji && message.reacts.getReaction(u_handle, emoji.u)) {
      if (onEmojiBarChange && Object.keys(reactions).length === 1 && Object.keys(reactions[emoji.u]).length === 1) {
        onEmojiBarChange(false);
      }
      return chatRoom.messagesBuff.userDelReaction(message.messageId, slug, meta);
    }
    if (emoji && reactions[emoji.u] && CURRENT_USER_REACTIONS < REACTIONS_LIMIT.PER_PERSON) {
      return addReaction();
    }
    if (CURRENT_USER_REACTIONS >= REACTIONS_LIMIT.PER_PERSON) {
      return msgDialog('info', '', l[24205].replace('%1', REACTIONS_LIMIT.PER_PERSON));
    }
    if (Object.keys(reactions).length >= REACTIONS_LIMIT.TOTAL) {
      return msgDialog('info', '', l[24206].replace('%1', REACTIONS_LIMIT.TOTAL));
    } else if (onEmojiBarChange && Object.keys(reactions).length === 0) {
      onEmojiBarChange(true);
    }
    return addReaction();
  }
  _emojiOnActiveStateChange(newVal) {
    this.setState(() => {
      return {
        reactionsDropdownActive: newVal
      };
    });
  }
  getEmojisImages() {
    const {
      chatRoom,
      message
    } = this.props;
    const isReadOnlyClass = chatRoom.isReadOnly() ? " disabled" : "";
    let emojisImages = message._reactions && message.reacts.reactions && Object.keys(message.reacts.reactions).map(utf => {
      const reaction = message.reacts.reactions[utf];
      const count = Object.keys(reaction).length;
      if (!count) {
        return null;
      }
      const filename = twemoji.convert.toCodePoint(utf);
      const currentUserReacted = !!reaction[u_handle];
      const names = [];
      if (reaction) {
        ChatdIntegration._ensureContactExists(Object.keys(reaction));
        const rKeys = Object.keys(reaction);
        for (let i = 0; i < rKeys.length; i++) {
          const uid = rKeys[i];
          if (reaction[uid]) {
            if (uid === u_handle) {
              names.push(l[24071] || 'You');
            } else if (uid in M.u) {
              names.push(M.getNameByHandle(uid) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER);
            }
          }
        }
      }
      let emojiData = megaChat._emojiData.emojisUtf[utf];
      if (!emojiData) {
        emojiData = Object.create(null);
        emojiData.u = utf;
      }
      let slug = emojiData && emojiData.n || "";
      let tipText;
      slug = slug ? `:${slug}:` : utf;
      if (Object.keys(reaction).length === 1 && reaction[u_handle]) {
        tipText = (l[24068] || "You (click to remove) [G]reacted with %s[/G]").replace("%s", slug);
      } else {
        tipText = mega.utils.trans.listToString(names, (l[24069] || "%s [G]reacted with %s2[/G]").replace("%s2", slug));
      }
      const notFoundEmoji = slug && slug[0] !== ":";
      return react0().createElement("div", {
        key: slug,
        onClick: ((e, slug, meta) => () => this.emojiSelected(e, slug, meta))(null, slug, emojiData),
        className: `
                            reactions-bar__reaction
                            simpletip
                            ${currentUserReacted ? 'user-reacted' : ''}
                            ${notFoundEmoji ? 'emoji-loading-error' : ''}
                            ${isReadOnlyClass}
                        `,
        "data-simpletip": tipText,
        "data-simpletipoffset": "3",
        "data-simpletipposition": "top"
      }, react0().createElement("img", {
        width: "10",
        height: "10",
        className: "emoji emoji-loading",
        draggable: "false",
        onError: e => {
          const textNode = document.createElement("em");
          textNode.classList.remove('emoji-loading');
          textNode.append(document.createTextNode(utf));
          e.target.replaceWith(textNode);
          textNode.parentNode.classList.add('emoji-loading-error');
        },
        onLoad: e => {
          e.target.classList.remove('emoji-loading');
        },
        src: `${staticpath  }images/mega/twemojis/2_v2/72x72/${  filename  }.png`
      }), react0().createElement("span", {
        className: "message text-block"
      }, count));
    });
    emojisImages = emojisImages && emojisImages.filter((v) => {
      return !!v;
    });
    if (emojisImages && emojisImages.length > 0) {
      const reactionBtn = !chatRoom.isReadOnly() ? react0().createElement(_ui_buttons_jsx2__.$, {
        className: "popup-button reactions-button hover-colorized simpletip",
        icon: "sprite-fm-theme icon-emoji-reactions reactions-icon",
        disabled: false,
        key: "add-reaction-button",
        attrs: {
          'data-simpletip': l[24070] || "Add reaction...",
          'data-simpletipoffset': "3",
          'data-simpletipposition': "top"
        }
      }, react0().createElement(_ui_emojiDropdown_jsx3__.L, {
        horizOffset: this.haveMeetingsCall() ? -150 : 0,
        onActiveChange: this._emojiOnActiveStateChange,
        className: "popup emoji reactions-dropdown",
        onClick: this.emojiSelected
      })) : null;
      emojisImages.push(reactionBtn);
    }
    return emojisImages ? react0().createElement("div", {
      className: "reactions-bar",
      id: "reactions-bar",
      onMouseEnter: () => {
        if (this._loadedReacts) {
          return false;
        }
        this._loadedReacts = megaChat.plugins.userHelper.fetchAllNames(this._reactionContacts(), chatRoom).catch(dump).finally(() => {
          this._loadedReacts = true;
          this.safeForceUpdate();
        });
      }
    }, emojisImages) : null;
  }
  getMessageActionButtons() {
    const {
      chatRoom,
      message
    } = this.props;
    return message instanceof Message && message.isSentOrReceived() && !chatRoom.isReadOnly() ? react0().createElement(_ui_buttons_jsx2__.$, {
      className: "popup-button reactions-button tiny-button simpletip",
      icon: `${"sprite-fm-theme reactions-icon"} icon-emoji-reactions`,
      iconHovered: `${"sprite-fm-theme reactions-icon"} icon-emoji-reactions-active`,
      disabled: false,
      key: "add-reaction-button",
      attrs: {
        'data-simpletip': l[24070] || "Add reaction...",
        'data-simpletipoffset': "3",
        'data-simpletipposition': "top"
      }
    }, react0().createElement(_ui_emojiDropdown_jsx3__.L, {
      horizOffset: this.haveMeetingsCall() ? -110 : 0,
      noArrow: true,
      onActiveChange: this._emojiOnActiveStateChange,
      className: "popup emoji reactions-dropdown",
      onClick: this.emojiSelected
    })) : null;
  }
}


},

485:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
A: () => __WEBPACK_DEFAULT_EXPORT__
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);
const _mixins_js1__ = REQ_(137);
const _contacts_jsx2__ = REQ_(251);
const _call_jsx3__ = REQ_(3);
const _button_jsx4__ = REQ_(959);
const _permissionsObserver_jsx5__ = REQ_(542);






class Preview extends react0().Component {
  constructor(props) {
    super(props);
    this.domRef = react0().createRef();
    this.videoRef = react0().createRef();
    this.stream = null;
    this.state = {
      audio: false,
      video: false,
      avatarMeta: undefined
    };
    this.getTrackType = type => !type ? 'getTracks' : type === Preview.STREAMS.AUDIO ? 'getAudioTracks' : 'getVideoTracks';
    this.startStream = type => {
      this.stopStream();
      const {
        audio,
        video
      } = this.state;
      navigator.mediaDevices.getUserMedia({
        audio,
        video
      }).then(stream => {
        const videoRef = this.videoRef.current;
        if (videoRef) {
          videoRef.srcObject = stream;
          this.stream = stream;
          if (this.props.onToggle) {
            this.props.onToggle(this.state.audio, this.state.video);
          }
        }
      }).catch(ex => {
        const stream = type === Preview.STREAMS.AUDIO ? 'audio' : 'video';
        return this.domRef.current && this.setState(state => ({
          [stream]: !state[stream]
        }), () => {
          megaChat.trigger('onLocalMediaError', {
            [type === Preview.STREAMS.AUDIO ? 'mic' : 'camera']: `${ex.name}: ${ex.message}`
          });
          console.error(`${ex.name}: ${ex.message}`);
        });
      });
    };
    this.stopStream = type => {
      if (this.stream) {
        const trackType = this.getTrackType(type);
        const tracks = this.stream[trackType]();
        for (const track of tracks) {
          track.stop();
        }
      }
    };
    this.toggleStream = type => {
      let _this$props$resetErro, _this$props;
      const stream = type === Preview.STREAMS.AUDIO ? 'audio' : 'video';
      this.setState(state => ({
        [stream]: !state[stream]
      }), () => {
        if (this.props.onToggle) {
          this.props.onToggle(this.state.audio, this.state.video);
        }
        return this.state[stream] ? this.startStream(type) : this.stopStream(type);
      });
      (_this$props$resetErro = (_this$props = this.props).resetError) == null || _this$props$resetErro.call(_this$props, type === Preview.STREAMS.AUDIO ? Av.Audio : Av.Camera);
    };
    this.renderAvatar = () => {
      if ((0,_call_jsx3__.P)()) {
        return react0().createElement("div", {
          className: "avatar-guest"
        }, react0().createElement("i", {
          className: "sprite-fm-uni icon-owner"
        }));
      }
      if (is_chatlink) {
        const {
          avatarUrl,
          color,
          shortName
        } = this.state.avatarMeta || {};
        return react0().createElement("div", {
          className: `
                        avatar-wrapper
                        ${color ? `color${color}` : ''}
                    `
        }, avatarUrl && react0().createElement("img", {
          src: avatarUrl,
          alt: ""
        }), color && react0().createElement("span", null, shortName));
      }
      return react0().createElement(_contacts_jsx2__.Avatar, {
        contact: M.u[u_handle]
      });
    };
    this.state.audio = this.props.audio || this.state.audio;
    if (this.props.video) {
      this.state.video = this.props.video;
      this.startStream(Preview.STREAMS.VIDEO);
      this.props.onToggle(this.state.audio, this.state.video);
    }
  }
  componentWillUnmount() {
    this.stopStream();
  }
  componentDidMount() {
    if (this.props.onToggle) {
      this.props.onToggle(this.state.audio, this.state.video);
    }
    this.setState({
      avatarMeta: is_chatlink ? generateAvatarMeta(u_handle) : undefined
    });
  }
  render() {
    const {
      NAMESPACE
    } = Preview;
    const {
      hasToRenderPermissionsWarning,
      renderPermissionsWarning
    } = this.props;
    const {
      audio,
      video
    } = this.state;
    const SIMPLETIP_PROPS = {
      label: undefined,
      position: 'top',
      className: 'theme-dark-forced'
    };
    return react0().createElement("div", {
      ref: this.domRef,
      className: `
                    ${NAMESPACE}
                    local-stream-mirrored
                `
    }, video && react0().createElement("div", {
      className: `${NAMESPACE}-video-overlay`
    }), react0().createElement("video", {
      className: video ? 'streaming' : '',
      muted: true,
      autoPlay: true,
      ref: this.videoRef
    }), !video && this.renderAvatar(), react0().createElement("div", {
      className: `${NAMESPACE}-controls`
    }, react0().createElement("div", {
      className: "preview-control-wrapper"
    }, react0().createElement(_button_jsx4__.A, {
      simpletip: {
        ...SIMPLETIP_PROPS,
        label: audio ? l[16214] : l[16708]
      },
      className: `
                                mega-button
                                round
                                theme-light-forced
                                ${NAMESPACE}-control
                                ${audio ? '' : 'with-fill'}
                            `,
      icon: audio ? 'icon-mic-thin-outline' : 'icon-mic-off-thin-outline',
      onClick: () => {
        this.toggleStream(Preview.STREAMS.AUDIO);
      }
    }), react0().createElement("span", null, l.mic_button), hasToRenderPermissionsWarning(Av.Audio) ? renderPermissionsWarning(Av.Audio) : null), react0().createElement("div", {
      className: "preview-control-wrapper"
    }, react0().createElement(_button_jsx4__.A, {
      simpletip: {
        ...SIMPLETIP_PROPS,
        label: video ? l[22894] : l[22893]
      },
      className: `
                                mega-button
                                round
                                theme-light-forced
                                ${NAMESPACE}-control
                                ${video ? '' : 'with-fill'}
                            `,
      icon: video ? 'icon-video-thin-outline' : 'icon-video-off-thin-outline',
      onClick: () => this.toggleStream(Preview.STREAMS.VIDEO)
    }), react0().createElement("span", null, l.camera_button), hasToRenderPermissionsWarning(Av.Camera) ? renderPermissionsWarning(Av.Camera) : null)));
  }
}
Preview.NAMESPACE = 'preview-meeting';
Preview.STREAMS = {
  AUDIO: 1,
  VIDEO: 2
};
const __WEBPACK_DEFAULT_EXPORT__ = (0,_mixins_js1__.Zz)(_permissionsObserver_jsx5__.$)(Preview);

},

486:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
O: () => PerfectScrollbar
});
const _applyDecoratedDescriptor0__ = REQ_(793);
const _chat_mixins1__ = REQ_(137);

let _dec, _dec2, _class, _PerfectScrollbar;
const React = REQ_(594);

const PerfectScrollbar = (_dec = (0,_chat_mixins1__.hG)(30, true), _dec2 = (0,_chat_mixins1__.hG)(30, true), _class = (_PerfectScrollbar = class PerfectScrollbar extends _chat_mixins1__.w9 {
  constructor(props) {
    super(props);
    this.domRef = React.createRef();
    this.isUserScroll = true;
    this.scrollEventIncId = 0;
  }
  get$Node() {
    if (!this.$Node) {
      let _this$domRef;
      this.$Node = $((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
    }
    return this.$Node;
  }
  doProgramaticScroll(newPos, forced, isX, skipReinitialised) {
    if (!this.isMounted()) {
      return;
    }
    const self = this;
    const $elem = self.get$Node();
    let animFrameInner = false;
    const prop = !isX ? 'scrollTop' : 'scrollLeft';
    const event = `scroll.progscroll${  self.scrollEventIncId++}`;
    $elem.rebind(event, () => {
      if (animFrameInner) {
        cancelAnimationFrame(animFrameInner);
        animFrameInner = false;
      }
      $elem.off(event);
      if (!skipReinitialised) {
        self.reinitialised(true);
      } else if (typeof skipReinitialised === 'function') {
        onIdle(skipReinitialised);
      }
      self.isUserScroll = true;
    });
    self.isUserScroll = false;
    $elem[0][prop] = Math.round(newPos);
    Ps.update($elem[0]);
    animFrameInner = requestAnimationFrame(() => {
      animFrameInner = false;
      self.isUserScroll = true;
      $elem.off(event);
    });
    return true;
  }
  componentDidMount() {
    let _this$props$didMount, _this$props;
    super.componentDidMount();
    const self = this;
    const $elem = self.get$Node();
    $elem.height('100%');
    const options = Object.assign({}, {
      'handlers': ['click-rail', 'drag-thumb', 'keyboard', 'wheel', 'touch'],
      'minScrollbarLength': 20
    }, self.props.options);
    Ps.initialize($elem[0], options);
    if (self.props.onFirstInit) {
      self.props.onFirstInit(self, $elem);
    }
    $elem.rebind(`ps-scroll-y.ps${  self.getUniqueId()}`, (e) => {
      if ($elem.attr('data-scroll-disabled') === "true") {
        e.stopPropagation();
        e.preventDefault();
        e.originalEvent.stopPropagation();
        e.originalEvent.preventDefault();
        return false;
      }
      if (self.props.onUserScroll && self.isUserScroll === true && $elem.is(e.target)) {
        self.props.onUserScroll(self, $elem, e);
      }
    });
    $elem.rebind(`disable-scroll.ps${  self.getUniqueId()}`, () => {
      Ps.destroy($elem[0]);
    });
    $elem.rebind(`enable-scroll.ps${  self.getUniqueId()}`, () => {
      Ps.initialize($elem[0], options);
    });
    $elem.rebind(`forceResize.ps${  self.getUniqueId()}`, (e, forced, scrollPositionYPerc, scrollToElement) => {
      self.onResize(forced, scrollPositionYPerc, scrollToElement);
    });
    self.onResize();
    this.attachAnimationEvents();
    (_this$props$didMount = (_this$props = this.props).didMount) == null || _this$props$didMount.call(_this$props, this.getUniqueId(), this);
  }
  componentWillUnmount() {
    let _this$props$willUnmou, _this$props2;
    super.componentWillUnmount();
    const $elem = this.get$Node();
    $elem.off(`ps-scroll-y.ps${  this.getUniqueId()}`);
    const ns = `.ps${  this.getUniqueId()}`;
    $elem.parents('.have-animation').unbind(`animationend${  ns  } webkitAnimationEnd${  ns  } oAnimationEnd${  ns}`);
    (_this$props$willUnmou = (_this$props2 = this.props).willUnmount) == null || _this$props$willUnmou.call(_this$props2, this.getUniqueId(), this);
  }
  attachAnimationEvents() {}
  eventuallyReinitialise(forced, scrollPositionYPerc, scrollToElement) {
    const self = this;
    if (!self.isComponentEventuallyVisible()) {
      return;
    }
    const $elem = self.get$Node();
    const h = self.getContentHeight();
    if (forced || self._currHeight !== h) {
      self._currHeight = h;
      self._doReinit(scrollPositionYPerc, scrollToElement, forced, $elem);
    }
  }
  _doReinit(scrollPositionYPerc, scrollToElement, forced, $elem) {
    let fired = false;
    if (this.props.onReinitialise) {
      fired = this.props.onReinitialise(this, $elem, forced, scrollPositionYPerc, scrollToElement);
    }
    if (fired === false) {
      if (scrollPositionYPerc) {
        if (scrollPositionYPerc === -1) {
          this.scrollToBottom(true);
        } else {
          this.scrollToPercentY(scrollPositionYPerc, true);
        }
      } else if (scrollToElement) {
        this.scrollToElement(scrollToElement, true);
      }
    }
  }
  scrollToBottom(skipReinitialised) {
    this.reinitialise(skipReinitialised, true);
  }
  reinitialise(skipReinitialised, bottom) {
    let _this$domRef2;
    const $elem = (_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current;
    if (!$elem) {
      return;
    }
    this.isUserScroll = false;
    if (bottom) {
      $elem.scrollTop = this.getScrollHeight();
    }
    Ps.update($elem);
    this.isUserScroll = true;
    if (!skipReinitialised) {
      this.reinitialised(true);
    }
  }
  getDOMRect(node) {
    let _this$domRef3;
    node = node || ((_this$domRef3 = this.domRef) == null ? void 0 : _this$domRef3.current);
    return node && node.getBoundingClientRect();
  }
  getScrollOffset(value) {
    let _this$domRef4;
    const $elem = (_this$domRef4 = this.domRef) == null ? void 0 : _this$domRef4.current;
    if ($elem) {
      return this.getDOMRect($elem.children[0])[value] - this.getDOMRect($elem)[value];
    }
    return 0;
  }
  getScrollHeight() {
    const res = this.getScrollOffset('height');
    if (res < 1) {
      return this._lastKnownScrollHeight || 0;
    }
    this._lastKnownScrollHeight = res;
    return res;
  }
  getScrollWidth() {
    const res = this.getScrollOffset('width');
    if (res < 1) {
      return this._lastKnownScrollWidth || 0;
    }
    this._lastKnownScrollWidth = res;
    return res;
  }
  getContentHeight() {
    const $elem = this.get$Node();
    return $elem[0].scrollHeight;
  }
  getContentWidth() {
    const $elem = this.get$Node();
    return $elem[0].scrollWidth;
  }
  setCssContentHeight(h) {
    const $elem = this.get$Node();
    return $elem.css('height', h);
  }
  isAtTop() {
    let _this$domRef5;
    return ((_this$domRef5 = this.domRef) == null ? void 0 : _this$domRef5.current.scrollTop) === 0;
  }
  isAtBottom() {
    return Math.round(this.getScrollPositionY()) === Math.round(this.getScrollHeight());
  }
  isCloseToBottom(minPixelsOff) {
    return this.getScrollHeight() - this.getScrollPositionY() <= minPixelsOff;
  }
  getScrolledPercentY() {
    return 100 / this.getScrollHeight() * this.getScrollPositionY();
  }
  getScrollPositionY() {
    let _this$domRef6;
    return (_this$domRef6 = this.domRef) == null ? void 0 : _this$domRef6.current.scrollTop;
  }
  getScrollPositionX() {
    let _this$domRef7;
    return (_this$domRef7 = this.domRef) == null ? void 0 : _this$domRef7.current.scrollLeft;
  }
  getClientWidth() {
    let _this$domRef8;
    return (_this$domRef8 = this.domRef) == null ? void 0 : _this$domRef8.current.clientWidth;
  }
  getClientHeight() {
    let _this$domRef9;
    return (_this$domRef9 = this.domRef) == null ? void 0 : _this$domRef9.current.clientHeight;
  }
  scrollToPercentY(posPerc, skipReinitialised) {
    const $elem = this.get$Node();
    const targetPx = this.getScrollHeight() / 100 * posPerc;
    if ($elem[0].scrollTop !== targetPx) {
      this.doProgramaticScroll(targetPx, 0, 0, skipReinitialised);
    }
  }
  scrollToPercentX(posPerc, skipReinitialised) {
    const $elem = this.get$Node();
    const targetPx = this.getScrollWidth() / 100 * posPerc;
    if ($elem[0].scrollLeft !== targetPx) {
      this.doProgramaticScroll(targetPx, false, true, skipReinitialised);
    }
  }
  scrollToY(posY, skipReinitialised) {
    const $elem = this.get$Node();
    if ($elem[0].scrollTop !== posY) {
      this.doProgramaticScroll(posY, 0, 0, skipReinitialised);
    }
  }
  scrollToElement(element, skipReinitialised) {
    if (element && element.offsetParent) {
      this.doProgramaticScroll(element.offsetTop, 0, 0, skipReinitialised);
    }
  }
  disable() {
    if (this.isMounted()) {
      const $elem = this.get$Node();
      $elem.attr('data-scroll-disabled', true);
      $elem.addClass('ps-disabled');
      Ps.disable($elem[0]);
    }
  }
  enable() {
    if (this.isMounted()) {
      const $elem = this.get$Node();
      $elem.removeAttr('data-scroll-disabled');
      $elem.removeClass('ps-disabled');
      Ps.enable($elem[0]);
    }
  }
  reinitialised(forced) {
    if (this.props.onReinitialise) {
      this.props.onReinitialise(this, this.get$Node(), forced ? forced : false);
    }
  }
  onResize(forced, scrollPositionYPerc, scrollToElement) {
    if (forced && forced.originalEvent) {
      forced = true;
      scrollPositionYPerc = undefined;
    }
    this.eventuallyReinitialise(forced, scrollPositionYPerc, scrollToElement);
  }
  inViewport(domNode) {
    return verge.inViewport(domNode);
  }
  componentDidUpdate() {
    if (this.props.requiresUpdateOnResize || this.requiresUpdateOnResize) {
      this.onResize(true);
    }
    this.attachAnimationEvents();
  }
  customIsEventuallyVisible() {
    const {chatRoom} = this.props;
    return !chatRoom || chatRoom.isCurrentlyActive;
  }
  render() {
    const {
      style,
      className,
      children
    } = this.props;
    return React.createElement("div", {
      ref: this.domRef,
      style,
      className
    }, children);
  }
}, _PerfectScrollbar.defaultProps = {
  className: "perfectScrollbarContainer",
  requiresUpdateOnResize: true
}, _PerfectScrollbar), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "eventuallyReinitialise", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyReinitialise"), _class.prototype), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "onResize", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "onResize"), _class.prototype), _class);

},

489:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
Ay: () => __WEBPACK_DEFAULT_EXPORT__,
_F: () => renderEndConfirm,
sX: () => renderLeaveConfirm
});
const _extends0__ = REQ_(168);
const react1__ = REQ_(594);
const react1 = REQ_.n(react1__);
const _mixins2__ = REQ_(137);
const _button_jsx3__ = REQ_(959);
const _stream_jsx4__ = REQ_(415);
const _micObserver_jsx5__ = REQ_(772);
const _permissionsObserver_jsx6__ = REQ_(542);
const _call_jsx7__ = REQ_(3);
const _hostsObserver_jsx8__ = REQ_(972);
const _ui_dropdowns_jsx9__ = REQ_(911);
const _ui_utils_jsx10__ = REQ_(314);











const renderLeaveConfirm = (onConfirm, onRecordingToggle) => msgDialog(`confirmation:!^${l.leave_call_recording_dialog_cta}!${l.leave_call_recording_dialog_nop_cta}`, undefined, l.leave_call_recording_dialog_heading, l.leave_call_recording_dialog_body, cb => {
  if (cb) {
    onRecordingToggle();
    onConfirm();
  }
}, 1);
const renderEndConfirm = (onConfirm, onRecordingToggle) => msgDialog(`confirmation:!^${l.end_call_recording_dialog_cta}!${l.end_call_recording_dialog_nop_cta}`, undefined, l.end_call_recording_dialog_heading, l.end_call_recording_dialog_body, cb => {
  if (cb) {
    onRecordingToggle();
    onConfirm();
  }
}, 1);
class StreamControls extends _mixins2__.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = react1().createRef();
    this.endContainerRef = react1().createRef();
    this.endButtonRef = react1().createRef();
    this.SIMPLETIP = {
      position: 'top',
      offset: 8,
      className: 'theme-dark-forced'
    };
    this.state = {
      endCallOptions: false,
      endCallPending: false,
      devices: {},
      audioSelectDropdown: false,
      videoSelectDropdown: false,
      loading: false,
      muteSpeak: false
    };
    this.LeaveButton = (0,_hostsObserver_jsx8__.C)(({
      hasHost,
      chatRoom,
      confirmLeave,
      onLeave
    }) => {
      const doLeave = () => hasHost(chatRoom.call ? chatRoom.call.peers.map(a => a.userHandle) : []) ? onLeave() : confirmLeave({
        title: l.assign_host_leave_call,
        body: l.assign_host_leave_call_details,
        cta: l.assign_host_button,
        altCta: l.leave_anyway
      });
      return react1().createElement(_button_jsx3__.A, {
        className: "mega-button",
        onClick: () => {
          const {
            recorderCid,
            call,
            onRecordingToggle
          } = this.props;
          return recorderCid && recorderCid === call.sfuClient.cid ? renderLeaveConfirm(doLeave, onRecordingToggle) : doLeave();
        }
      }, react1().createElement("span", null, l.leave));
    });
    this.setActiveElement = forced => this.props.setActiveElement(forced || this.state.audioSelectDropdown || this.state.videoSelectDropdown || this.state.endCallOptions);
    this.handleMousedown = ({
      target
    }) => {
      if (this.isMounted()) {
        const {
          audioSelectDropdown,
          videoSelectDropdown,
          endCallOptions
        } = this.state;
        return (audioSelectDropdown || videoSelectDropdown || endCallOptions) && ['audio-sources', 'video-sources', 'meetings-end-options'].some(selector => {
          let _document$querySelect;
          return (_document$querySelect = document.querySelector(`.${selector}`)) == null ? void 0 : _document$querySelect.contains(target);
        }) ? 0x4B1D : this.setState({
          audioSelectDropdown: false,
          videoSelectDropdown: false,
          endCallOptions: false
        }, this.setActiveElement);
      }
    };
    this.renderDebug = () => {
      return react1().createElement("div", {
        className: "stream-debug",
        style: {
          position: 'absolute',
          left: 25,
          bottom: 36,
          display: 'flex',
          alignItems: 'center',
          color: 'tomato'
        }
      }, react1().createElement(_button_jsx3__.A, {
        className: "mega-button round small theme-dark-forced positive",
        simpletip: {
          ...this.SIMPLETIP,
          label: 'Add Stream'
        },
        onClick: () => this.props.onStreamToggle(_stream_jsx4__.hK.ADD)
      }, react1().createElement("span", null, l.add)), react1().createElement(_button_jsx3__.A, {
        className: "mega-button round small theme-dark-forced negative",
        simpletip: {
          ...this.SIMPLETIP,
          label: 'Remove Stream'
        },
        onClick: () => this.props.peers.length > 1 && this.props.onStreamToggle(_stream_jsx4__.hK.REMOVE)
      }, react1().createElement("span", null, l[83])), react1().createElement("span", null, this.props.peers.length + 1));
    };
    this.renderEndCallOptions = () => {
      let _this$endContainerRef;
      const {
        call,
        chatRoom,
        recorderCid,
        onRecordingToggle,
        onCallEnd
      } = this.props;
      const {
        endCallOptions,
        endCallPending
      } = this.state;
      const doEnd = () => this.setState({
        endCallPending: true
      }, () => chatRoom.endCallForAll());
      const endContainerRef = (_this$endContainerRef = this.endContainerRef) == null ? void 0 : _this$endContainerRef.current;
      return react1().createElement("div", (0,_extends0__.A)({}, endCallOptions && {
        style: (({
          left,
          top
        }) => ({
          left,
          top
        }))(endContainerRef.getBoundingClientRect())
      }, {
        className: `
                    meetings-end-options
                    theme-dark-forced
                    ${endCallOptions ? '' : 'hidden'}
                `
      }), react1().createElement("div", {
        className: "meetings-end-options-content"
      }, react1().createElement(this.LeaveButton, {
        chatRoom,
        recorderCid,
        participants: chatRoom.getCallParticipants(),
        onLeave: onCallEnd,
        onConfirmDenied: onCallEnd
      }), react1().createElement(_button_jsx3__.A, {
        className: `
                            mega-button
                            positive
                            ${endCallPending ? 'disabled' : ''}
                        `,
        onClick: () => {
          if (recorderCid && recorderCid === call.sfuClient.cid) {
            return renderEndConfirm(doEnd, onRecordingToggle);
          }
          return doEnd();
        }
      }, react1().createElement("span", null, l.end_for_all))));
    };
    this.renderEndCall = () => {
      const {
        call,
        chatRoom,
        peers,
        recorderCid,
        onRecordingToggle,
        onCallEnd
      } = this.props;
      return react1().createElement("div", {
        ref: this.endContainerRef,
        className: "end-call-container",
        onClick: () => {
          if (chatRoom.type !== 'private' && peers.length && _call_jsx7__.Ay.isModerator(chatRoom, u_handle)) {
            return this.setState(state => ({
              endCallOptions: !state.endCallOptions
            }), () => {
              if (this.endButtonRef) {
                $(this.endButtonRef.current).trigger('simpletipClose');
              }
              this.setActiveElement();
            });
          }
          if (recorderCid && recorderCid === call.sfuClient.cid) {
            return chatRoom.type === 'private' ? renderEndConfirm(onCallEnd, onRecordingToggle) : renderLeaveConfirm(onCallEnd, onRecordingToggle);
          }
          return onCallEnd();
        }
      }, react1().createElement(_ui_utils_jsx10__.Ay.RenderTo, {
        element: document.body
      }, this.renderEndCallOptions()), react1().createElement(_button_jsx3__.A, {
        simpletip: {
          ...this.SIMPLETIP,
          label: l[5884]
        },
        className: "mega-button theme-dark-forced round negative end-call call-action",
        icon: "icon-phone-02",
        didMount: button => {
          this.endButtonRef = button.buttonRef;
        }
      }), react1().createElement("span", null, l.end_button));
    };
    this.renderSourceOpener = ({
      type,
      eventId
    }) => {
      return react1().createElement("div", {
        className: `
                    input-source-opener
                    button
                    ${this.state[type] ? 'active-dropdown' : ''}
                `,
        onClick: async ev => {
          ev.stopPropagation();
          this.setState(() => ({
            loading: true
          }), async () => {
            const devices = await this.updateMediaDevices();
            const updated = JSON.stringify(devices) !== JSON.stringify(this.state.devices);
            this.setState(state => ({
              loading: false,
              audioSelectDropdown: false,
              videoSelectDropdown: false,
              devices: updated ? devices : this.state.devices,
              [type]: !state[type]
            }), () => {
              const {
                audioSelectDropdown,
                videoSelectDropdown
              } = this.state;
              this.props.setActiveElement(audioSelectDropdown || videoSelectDropdown);
              eventlog(eventId);
            });
          });
        }
      }, react1().createElement("i", {
        className: "sprite-fm-mono icon-arrow-up"
      }));
    };
    this.handleDeviceChange = () => {
      this.micDefaultRenamed = false;
      this.updateMediaDevices().always(devices => {
        let _sfuClient$localAudio, _oldDevices$audioIn;
        if (!this.isMounted()) {
          return;
        }
        const {
          devices: oldDevices
        } = this.state;
        const {
          sfuClient,
          av
        } = this.props.call;
        if (av & Av.Audio && !SfuClient.micDeviceId && ((_sfuClient$localAudio = sfuClient.localAudioTrack()) == null ? void 0 : _sfuClient$localAudio.getCapabilities().deviceId) === 'default' && oldDevices != null && (_oldDevices$audioIn = oldDevices.audioIn) != null && _oldDevices$audioIn.default && devices.audioIn.default && oldDevices.audioIn.default !== devices.audioIn.default) {
          for (const [key, value] of Object.entries(devices.audioIn)) {
            if (key !== 'default' && devices.audioIn.default.indexOf(value) > -1) {
              sfuClient.setMicDevice(key).then(() => SfuClient.persistMicDevice(null));
              break;
            }
          }
        }
        this.setState({
          devices,
          audioSelectDropdown: false,
          videoSelectDropdown: false
        }, this.setActiveElement);
      });
    };
    this.renderOnboardingRaise = () => {
      const {
        chatRoom,
        onOnboardingRaiseDismiss
      } = this.props;
      return react1().createElement("div", {
        className: "meetings-call-onboarding"
      }, react1().createElement("div", {
        className: "mega-dialog mega-onboarding-dialog dialog-template-message onboarding-raise",
        id: "ob-dialog",
        role: "dialog",
        "aria-labelledby": "ob-dialog-title",
        "aria-modal": "true"
      }, react1().createElement("i", {
        className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow bottom",
        id: "ob-dialog-arrow"
      }), react1().createElement("header", null, react1().createElement("div", null, react1().createElement("h2", {
        id: "ob-dialog-title"
      }, l.raise_onboarding_title), react1().createElement("p", {
        id: "ob-dialog-text"
      }, chatRoom.isMeeting ? l.raise_onboarding_body : l.raise_onboarding_group_body))), react1().createElement("footer", null, react1().createElement("div", {
        className: "footer-container"
      }, react1().createElement("button", {
        className: "mega-button js-next small theme-light-forced",
        onClick: onOnboardingRaiseDismiss
      }, react1().createElement("span", null, l.ok_button))))));
    };
    this.renderRaiseButton = () => {
      const {
        call,
        raisedHandPeers,
        onboardingRaise
      } = this.props;
      const isOnHold = call.av & Av.onHold;
      const hasRaisedHand = raisedHandPeers.includes(u_handle);
      return react1().createElement("li", {
        className: isOnHold ? 'disabled' : ''
      }, onboardingRaise && this.renderOnboardingRaise(), react1().createElement(_button_jsx3__.A, {
        className: `
                        mega-button
                        theme-light-forced
                        call-action
                        round
                        ${isOnHold ? 'disabled' : ''}
                        ${hasRaisedHand ? 'with-fill' : ''}
                    `,
        icon: "icon-raise-hand",
        onClick: isOnHold ? null : () => {
          if (hasRaisedHand) {
            call.sfuClient.lowerHand();
            eventlog(500311);
            return;
          }
          call.sfuClient.raiseHand();
          eventlog(500249);
        }
      }), react1().createElement("span", null, l.raise_button));
    };
  }
  renderSoundDropdown() {
    const {
      call
    } = this.props;
    const {
      micDeviceId,
      audioOutDeviceId
    } = SfuClient;
    const {
      audioIn = {},
      audioOut = {}
    } = this.state.devices;
    let selectedIn;
    const inTrack = call.sfuClient.localAudioTrack();
    if (inTrack) {
      const {
        deviceId
      } = inTrack.getCapabilities();
      selectedIn = deviceId in audioIn ? deviceId : 'default';
      if (deviceId === 'default' && inTrack.label !== audioIn.default) {
        this.micDefaultRenamed = inTrack.label;
      }
    } else if (micDeviceId) {
      selectedIn = micDeviceId in audioIn ? micDeviceId : 'default';
    } else {
      selectedIn = 'default';
    }
    if (this.micDefaultRenamed) {
      audioIn.default = this.micDefaultRenamed;
    }
    let selectedOut;
    let peerPlayer;
    if (call.sfuClient.peers.size) {
      peerPlayer = call.sfuClient.peers.values().next().audioPlayer;
    }
    if (peerPlayer && peerPlayer.playerElem && peerPlayer.playerElem.sinkId) {
      const {
        sinkId
      } = peerPlayer.playerElem;
      selectedOut = sinkId in audioOut ? sinkId : 'default';
    } else if (audioOutDeviceId) {
      selectedOut = audioOutDeviceId in audioOut ? audioOutDeviceId : 'default';
    } else {
      selectedOut = 'default';
    }
    const mics = Object.entries(audioIn).map(([id, name]) => {
      return react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
        key: id,
        onClick: () => {
          call.sfuClient.setMicDevice(id === 'default' ? null : id);
          this.setState({
            audioSelectDropdown: false
          }, this.setActiveElement);
        }
      }, react1().createElement(react1().Fragment, null, react1().createElement("div", {
        className: "av-device-name"
      }, name), selectedIn === id && react1().createElement("i", {
        className: "sprite-fm-mono icon-check-small-regular-outline"
      })));
    });
    const speakers = Object.entries(audioOut).map(([id, name]) => {
      return react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
        key: id,
        onClick: () => {
          Promise.resolve(call.sfuClient.setAudioOutDevice(id === 'default' ? null : id)).catch(dump);
          this.setState({
            audioSelectDropdown: false
          }, this.setActiveElement);
        }
      }, react1().createElement(react1().Fragment, null, react1().createElement("div", {
        className: "av-device-name"
      }, name), selectedOut === id && react1().createElement("i", {
        className: "sprite-fm-mono icon-check-small-regular-outline"
      })));
    });
    return react1().createElement(_ui_dropdowns_jsx9__.Dropdown, {
      className: "input-sources audio-sources theme-dark-forced",
      active: true,
      noArrow: true,
      positionMy: "center top",
      positionAt: "center bottom",
      horizOffset: -50,
      vertOffset: 16,
      closeDropdown: () => this.setState({
        audioSelectDropdown: false
      }, this.setActiveElement)
    }, react1().createElement("div", {
      className: "source-label"
    }, l.microphone), mics.length ? mics : react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
      label: l.no_mics
    }), react1().createElement("hr", null), react1().createElement("div", {
      className: "source-label"
    }, l.speaker), speakers.length ? speakers : react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
      label: l.no_speakers
    }), react1().createElement("hr", null), react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
      icon: "sprite-fm-mono icon-volume-max-small-regular-outline",
      label: l.test_speaker,
      disabled: speakers.length === 0,
      onClick: () => {
        delay('call-test-speaker', () => {
          this.testAudioOut().catch(ex => {
            console.error('Failed to test audio on the selected device', ex, audioOutDeviceId);
          });
        });
      }
    }));
  }
  renderVideoDropdown() {
    const {
      call
    } = this.props;
    const {
      videoIn = {}
    } = this.state.devices;
    const {
      camDeviceId
    } = SfuClient;
    let selectedCam;
    if (call.sfuClient.localCameraTrack()) {
      const {
        deviceId
      } = call.sfuClient.localCameraTrack().getCapabilities();
      selectedCam = deviceId in videoIn ? deviceId : 'default';
    } else if (camDeviceId) {
      selectedCam = camDeviceId in videoIn ? camDeviceId : 'default';
    } else {
      selectedCam = 'default';
    }
    const cameras = Object.entries(videoIn).map(([id, name]) => {
      return react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
        key: id,
        onClick: () => {
          call.sfuClient.setCameraDevice(id === 'default' ? null : id);
          this.setState({
            videoSelectDropdown: false
          }, this.setActiveElement);
        }
      }, react1().createElement(react1().Fragment, null, react1().createElement("div", {
        className: "av-device-name"
      }, name), selectedCam === id && react1().createElement("i", {
        className: "sprite-fm-mono icon-check-small-regular-outline"
      })));
    });
    return react1().createElement(_ui_dropdowns_jsx9__.Dropdown, {
      className: "input-sources video-sources theme-dark-forced",
      active: true,
      noArrow: true,
      positionMy: "center top",
      positionAt: "center bottom",
      horizOffset: -50,
      vertOffset: 16,
      closeDropdown: () => this.setState({
        videoSelectDropdown: false
      }, this.setActiveElement)
    }, react1().createElement("div", {
      className: "source-label"
    }, l.camera_button), cameras.length ? cameras : react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
      label: l.no_cameras
    }));
  }
  async updateMediaDevices() {
    let devices = await SfuClient.enumMediaDevices().catch(dump);
    devices = devices || {
      audioIn: {},
      audioOut: {},
      videoIn: {}
    };
    const removeEmptyDevices = devices => {
      for (const key of Object.keys(devices)) {
        if (!key || !devices[key]) {
          delete devices[key];
        }
      }
    };
    removeEmptyDevices(devices.audioIn);
    removeEmptyDevices(devices.audioOut);
    removeEmptyDevices(devices.videoIn);
    if (devices.audioIn.communications) {
      delete devices.audioIn.communications;
    }
    return devices;
  }
  async testAudioOut() {
    if (!SfuClient.audioOutDeviceId) {
      return megaChat.playSound(megaChat.SOUNDS.SPEAKER_TEST);
    }
    const currentDevices = await this.updateMediaDevices();
    if (currentDevices.audioOut && !(SfuClient.audioOutDeviceId in currentDevices.audioOut)) {
      return megaChat.playSound(megaChat.SOUNDS.SPEAKER_TEST);
    }
    const ctx = new AudioContext({
      sinkId: SfuClient.audioOutDeviceId
    });
    if (ctx.state !== 'running') {
      throw new Error('The audio context failed to start');
    }
    const soundBuffer = await megaChat.fetchSoundBuffer(megaChat.SOUNDS.SPEAKER_TEST);
    const buffer = await ctx.decodeAudioData(soundBuffer);
    const gain = ctx.createGain();
    const source = ctx.createBufferSource();
    source.buffer = buffer;
    source.connect(gain);
    gain.connect(ctx.destination);
    gain.gain.value = 0.07;
    source.start();
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    document.removeEventListener('mousedown', this.handleMousedown);
    navigator.mediaDevices.removeEventListener('devicechange', this.handleDeviceChange);
    this.props.chatRoom.off(`onLocalSpeechDetected.${StreamControls.NAMESPACE}`);
  }
  componentDidMount() {
    super.componentDidMount();
    document.addEventListener('mousedown', this.handleMousedown);
    navigator.mediaDevices.addEventListener('devicechange', this.handleDeviceChange);
    this.props.chatRoom.rebind(`onLocalSpeechDetected.${StreamControls.NAMESPACE}`, () => this.setState({
      muteSpeak: true
    }, () => this.setActiveElement(true)));
  }
  render() {
    const {
      call,
      signal,
      chatRoom,
      renderSignalWarning,
      hasToRenderPermissionsWarning,
      renderPermissionsWarning,
      resetError,
      blocked,
      renderBlockedWarning,
      onAudioClick,
      onVideoClick,
      onScreenSharingClick,
      onHoldClick
    } = this.props;
    const {
      audioSelectDropdown,
      videoSelectDropdown,
      muteSpeak
    } = this.state;
    const avFlags = call.av;
    const isOnHold = avFlags & Av.onHold;
    return react1().createElement(react1().Fragment, null, blocked && renderBlockedWarning(), react1().createElement("div", {
      ref: this.domRef,
      className: StreamControls.NAMESPACE
    }, d && localStorage.callDebug ? this.renderDebug() : '', react1().createElement("ul", null, react1().createElement("li", {
      className: `
                                ${isOnHold ? 'disabled' : ''}
                                with-input-selector
                            `,
      onClick: () => isOnHold ? null : this.setState({
        muteSpeak: false
      }, () => {
        resetError(Av.Audio);
        onAudioClick();
      })
    }, muteSpeak && react1().createElement("div", {
      className: "mic-muted-tip theme-light-forced",
      onClick: ev => ev.stopPropagation()
    }, react1().createElement("span", null, l.mic_still_muted), react1().createElement(_button_jsx3__.A, {
      className: "mic-muted-tip-btn",
      onClick: () => {
        this.setState({
          muteSpeak: false
        }, () => {
          this.setActiveElement();
          eventlog(500509);
        });
      }
    }, l[148]), react1().createElement("i", {
      className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow bottom"
    })), react1().createElement(_button_jsx3__.A, {
      className: `
                                    mega-button
                                    theme-light-forced
                                    call-action
                                    round
                                    ${isOnHold ? 'disabled' : ''}
                                    ${avFlags & Av.Audio || isOnHold ? '' : 'with-fill'}
                                `,
      icon: avFlags & Av.Audio ? 'icon-mic-thin-outline' : 'icon-mic-off-thin-outline'
    }), react1().createElement("span", null, l.mic_button), signal ? null : renderSignalWarning(), hasToRenderPermissionsWarning(Av.Audio) ? renderPermissionsWarning(Av.Audio) : null, this.renderSourceOpener({
      type: 'audioSelectDropdown',
      eventId: chatRoom.isMeeting ? 500299 : 500300
    })), audioSelectDropdown && react1().createElement("div", {
      ref: this.audioDropdownRef
    }, this.renderSoundDropdown()), react1().createElement("li", {
      className: `
                                ${isOnHold ? 'disabled' : ''}
                                with-input-selector
                            `,
      onClick: () => {
        if (isOnHold) {
          return;
        }
        resetError(Av.Camera);
        onVideoClick();
      }
    }, react1().createElement(_button_jsx3__.A, {
      className: `
                                    mega-button
                                    theme-light-forced
                                    call-action
                                    round
                                    ${isOnHold ? 'disabled' : ''}
                                    ${avFlags & Av.Camera || isOnHold ? '' : 'with-fill'}
                                `,
      icon: avFlags & Av.Camera ? 'icon-video-thin-outline' : 'icon-video-off-thin-outline'
    }), react1().createElement("span", null, l.camera_button), hasToRenderPermissionsWarning(Av.Camera) ? renderPermissionsWarning(Av.Camera) : null, this.renderSourceOpener({
      type: 'videoSelectDropdown',
      eventId: chatRoom.isMeeting ? 500301 : 500302
    })), videoSelectDropdown && react1().createElement("div", {
      ref: this.videoDropdownRef
    }, this.renderVideoDropdown()), react1().createElement("li", {
      className: isOnHold ? 'disabled' : '',
      onClick: () => {
        if (isOnHold) {
          return;
        }
        resetError(Av.Screen);
        onScreenSharingClick();
        if (chatRoom.isMeeting) {
          eventlog(500303);
        } else {
          eventlog(500304);
        }
      }
    }, react1().createElement(_button_jsx3__.A, {
      className: `
                                    mega-button
                                    theme-light-forced
                                    call-action
                                    round
                                    ${isOnHold ? 'disabled' : ''}
                                    ${avFlags & Av.Screen ? 'with-fill' : ''}
                                `,
      icon: avFlags & Av.Screen ? 'icon-monitor-off' : 'icon-monitor'
    }), react1().createElement("span", null, avFlags & Av.Screen ? l.screenshare_stop_button : l.screenshare_button), hasToRenderPermissionsWarning(Av.Screen) ? renderPermissionsWarning(Av.Screen, this) : null), chatRoom.type === 'private' ? null : this.renderRaiseButton(), react1().createElement("li", {
      onClick: onHoldClick
    }, react1().createElement(_button_jsx3__.A, {
      className: `
                                    mega-button
                                    theme-light-forced
                                    call-action
                                    round
                                    ${isOnHold ? 'with-fill' : ''}
                                `,
      icon: isOnHold ? 'icon-play-small-regular-outline' : 'icon-pause-small-regular-outline'
    }), react1().createElement("span", null, isOnHold ? l.resume_call_button : l.hold_button)), react1().createElement("li", null, this.renderEndCall()))));
  }
}
StreamControls.NAMESPACE = 'stream-controls';
const __WEBPACK_DEFAULT_EXPORT__ = (0,_mixins2__.Zz)(_micObserver_jsx5__.Q, _permissionsObserver_jsx6__.$)(StreamControls);

},

501:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
Y: () => withUpdateObserver
});
const _extends0__ = REQ_(168);
const react1__ = REQ_(594);
const react1 = REQ_.n(react1__);
const _mixins_js2__ = REQ_(137);



const withUpdateObserver = Component => class extends _mixins_js2__.w9 {
  constructor(...args) {
    super(...args);
    this.updateInterval = 600000;
    this.instanceRef = react1().createRef();
    this.intervalRef = undefined;
    this.state = {
      updated: 0
    };
    this.updateListener = () => {
      return this.isComponentVisible() && document.visibilityState === 'visible' && this.setState(state => ({
        updated: ++state.updated
      }), () => this.safeForceUpdate());
    };
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    document.removeEventListener('visibilitychange', this.updateListener);
    clearInterval(this.intervalRef);
  }
  componentDidMount() {
    super.componentDidMount();
    document.addEventListener('visibilitychange', this.updateListener);
    this.intervalRef = setInterval(this.instanceRef.current[Component.updateListener] || this.updateListener, Component.updateInterval || this.updateInterval);
  }
  render() {
    return react1().createElement(Component, (0,_extends0__.A)({
      ref: this.instanceRef
    }, this.state, this.props));
  }
};

},

539:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
Ay: () => VideoNodeMenu,
EH: () => Privilege,
yU: () => Pin
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);
const _mixins1__ = REQ_(137);
const _button_jsx2__ = REQ_(959);
const _call_jsx3__ = REQ_(3);





const Privilege = ({
  chatRoom,
  stream
}) => {
  const {
    call,
    userHandle
  } = stream || {};
  if (call && call.isPublic) {
    const {
      OPERATOR,
      FULL
    } = ChatRoom.MembersSet.PRIVILEGE_STATE;
    const currentUserModerator = chatRoom.members[u_handle] === OPERATOR;
    const targetUserModerator = chatRoom.members[userHandle] === OPERATOR;
    return currentUserModerator && react0().createElement(_button_jsx2__.A, {
      targetUserModerator,
      icon: "sprite-fm-mono icon-admin-outline",
      onClick: () => {
        ['alterUserPrivilege', 'onCallPrivilegeChange'].map(event => chatRoom.trigger(event, [userHandle, targetUserModerator ? FULL : OPERATOR]));
      }
    }, react0().createElement("span", null, targetUserModerator ? l.remove_moderator : l.make_moderator));
  }
  return null;
};
const Contact = ({
  stream,
  ephemeralAccounts,
  onCallMinimize
}) => {
  const {
    userHandle
  } = stream;
  const IS_GUEST = (0,_call_jsx3__.P)() || ephemeralAccounts && ephemeralAccounts.includes(userHandle);
  const HAS_RELATIONSHIP = M.u[userHandle].c === 1;
  if (HAS_RELATIONSHIP) {
    return react0().createElement(_button_jsx2__.A, {
      icon: "sprite-fm-mono icon-chat",
      onClick: () => {
        onCallMinimize();
        loadSubPage(`fm/chat/p/${userHandle}`);
      }
    }, react0().createElement("span", null, l[7997]));
  }
  return react0().createElement(_button_jsx2__.A, {
    className: IS_GUEST ? 'disabled' : '',
    icon: "sprite-fm-mono icon-add",
    onClick: () => {
      return IS_GUEST ? false : M.syncContactEmail(userHandle, true).then(email => {
        const OPC = Object.values(M.opc);
        if (OPC && OPC.length && OPC.some(opc => opc.m === email)) {
          return msgDialog('warningb', '', l[17545]);
        }
        msgDialog('info', l[150], l[5898]);
        M.inviteContact(M.u[u_handle].m, email);
      }).catch(() => mBroadcaster.sendMessage('meetings:ephemeralAdd', userHandle));
    }
  }, react0().createElement("span", null, l[24581]));
};
const Pin = ({
  stream,
  mode,
  onSpeakerChange,
  onModeChange
}) => {
  return react0().createElement(_button_jsx2__.A, {
    icon: "sprite-fm-mono grid-main",
    onClick: () => mode === _call_jsx3__.g.THUMBNAIL ? onSpeakerChange == null ? void 0 : onSpeakerChange(stream) : onModeChange == null ? void 0 : onModeChange(_call_jsx3__.g.THUMBNAIL)
  }, react0().createElement("span", null, mode === _call_jsx3__.g.THUMBNAIL ? l.display_in_main_view : l.switch_to_thumb_view));
};
class VideoNodeMenu extends _mixins1__.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = react0().createRef();
    this.ToggleCrop = ({
      videoNodeRef
    }) => {
      const videoNode = videoNodeRef == null ? void 0 : videoNodeRef.current;
      if (!videoNode) {
        return null;
      }
      return videoNode.isVideoCropped() ? react0().createElement(_button_jsx2__.A, {
        icon: "sprite-fm-mono grid-main",
        onClick: () => {
          videoNode.uncropVideo();
          this.forceUpdate();
        }
      }, react0().createElement("span", null, "Uncrop video")) : react0().createElement(_button_jsx2__.A, {
        icon: "sprite-fm-mono grid-main",
        onClick: () => {
          videoNode.cropVideo();
          this.forceUpdate();
        }
      }, react0().createElement("span", null, "Crop video"));
    };
  }
  render() {
    const {
      NAMESPACE
    } = VideoNodeMenu;
    const {
      stream,
      isPresenterNode,
      mode,
      onSpeakerChange,
      onModeChange
    } = this.props;
    const {
      userHandle,
      clientId
    } = stream;
    if (isPresenterNode) {
      return react0().createElement("div", {
        ref: this.domRef,
        className: `
                        ${NAMESPACE}
                        theme-dark-forced
                        ${mode === _call_jsx3__.g.THUMBNAIL ? '' : 'presenter'}
                    `
      }, react0().createElement("div", {
        className: `${NAMESPACE}-toggle`
      }, react0().createElement("i", {
        className: `sprite-fm-mono call-node-pin icon-pin${mode === _call_jsx3__.g.MAIN ? '-off' : ''}`,
        onClick: () => mode === _call_jsx3__.g.THUMBNAIL ? onSpeakerChange == null ? void 0 : onSpeakerChange(stream) : onModeChange == null ? void 0 : onModeChange(_call_jsx3__.g.THUMBNAIL)
      })));
    }
    if (userHandle !== u_handle) {
      const $$CONTROLS = {
        Contact,
        Pin,
        Privilege
      };
      return react0().createElement("div", {
        ref: this.domRef,
        className: `
                        ${NAMESPACE}
                        theme-dark-forced
                    `
      }, react0().createElement("div", {
        className: `${NAMESPACE}-toggle`
      }, react0().createElement("i", {
        className: "sprite-fm-mono icon-more-horizontal-thin-outline"
      })), react0().createElement("div", {
        className: `${NAMESPACE}-content`
      }, react0().createElement("ul", null, Object.values($$CONTROLS).map(($$CONTROL, i) => react0().createElement("li", {
        key: `${Object.keys($$CONTROLS)[i]}-${clientId}-${userHandle}`
      }, react0().createElement($$CONTROL, this.props))))));
    }
    return null;
  }
}
VideoNodeMenu.NAMESPACE = 'node-menu';

},

542:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
$: () => withPermissionsObserver
});
const _extends0__ = REQ_(168);
const react1__ = REQ_(594);
const react1 = REQ_.n(react1__);
const _mixins_js2__ = REQ_(137);
const _ui_modalDialogs_jsx3__ = REQ_(318);
const _ui_utils_jsx4__ = REQ_(314);





const errors = {
  browser: 'NotAllowedError: Permission denied',
  system: 'NotAllowedError: Permission denied by system',
  dismissed: 'NotAllowedError: Permission dismissed',
  nil: 'NotFoundError: Requested device not found',
  sharedCam: 'NotReadableError: Could not start video source',
  sharedMic: 'NotReadableError: Could not start audio source',
  sharedGeneric: 'NotReadableError: Device in use'
};
const isUserActionError = error => {
  return error && error === errors.browser;
};
const withPermissionsObserver = Component => {
  return class extends _mixins_js2__.w9 {
    constructor(props) {
      super(props);
      this.namespace = `PO-${Component.NAMESPACE}`;
      this.observer = `onLocalMediaError.${this.namespace}`;
      this.childRef = undefined;
      this.platform = ua.details.os;
      this.helpURL = `${l.mega_help_host}/chats-meetings/meetings/enable-audio-video-call-permissions`;
      this.macURI = 'x-apple.systempreferences:com.apple.preference.security';
      this.winURI = 'ms-settings';
      this.CONTENT = {
        [Av.Audio]: {
          system: {
            title: l.no_mic_title,
            info: this.platform === 'Windows' ? l.no_mic_system_windows.replace('[A]', `<a href=${this.helpURL} target="_blank" class="clickurl">`).replace('[/A]', '</a>') : l.no_mic_system_mac.replace('[A]', `<a href="${this.helpURL}" target="_blank" class="clickurl">`).replace('[/A]', '</a>'),
            buttons: [this.platform === 'Apple' || this.platform === 'Windows' ? {
              key: 'open-settings',
              label: l.open_system_settings,
              className: 'positive',
              onClick: () => {
                window.open(this.platform === 'Apple' ? `${this.macURI}?Privacy_Microphone` : `${this.winURI}:privacy-microphone`, '_blank', 'noopener,noreferrer');
                this.closePermissionsDialog(Av.Audio);
              }
            } : {
              key: 'ok',
              label: l.ok_button,
              className: 'positive',
              onClick: () => this.closePermissionsDialog(Av.Audio)
            }]
          },
          browser: {
            title: l.no_mic_title,
            cover: 'permissions-mic',
            info: l.allow_mic_access.replace('[X]', '<i class="sprite-fm-theme icon-mic-disabled"></i>'),
            buttons: [{
              key: 'ok',
              label: l.ok_button,
              className: 'positive',
              onClick: () => this.closePermissionsDialog(Av.Audio)
            }]
          },
          nil: {
            title: l.no_mic_detected_title,
            info: l.no_mic_detected_info,
            buttons: [{
              key: 'ok',
              label: l.ok_button,
              className: 'positive',
              onClick: () => this.closePermissionsDialog(Av.Audio)
            }]
          },
          shared: {
            title: l.no_mic_title,
            info: l.shared_mic_err_info.replace('[A]', `<a href="${this.helpURL}" target="_blank" class="clickurl">`).replace('[/A]', '</a>'),
            buttons: [{
              key: 'ok',
              label: l.ok_button,
              className: 'positive',
              onClick: () => this.closePermissionsDialog(Av.Audio)
            }]
          }
        },
        [Av.Camera]: {
          system: {
            title: l.no_camera_title,
            info: this.platform === 'Windows' ? l.no_camera_system_windows.replace('[A]', `<a href="${this.helpURL}" target="_blank" class="clickurl">`).replace('[/A]', '</a>') : l.no_camera_system_mac.replace('[A]', `<a href="${this.helpURL}" target="_blank" class="clickurl">`).replace('[/A]', '</a>'),
            buttons: [this.platform === 'Apple' || this.platform === 'Windows' ? {
              key: 'open-settings',
              label: l.open_system_settings,
              className: 'positive',
              onClick: () => {
                window.open(this.platform === 'Apple' ? `${this.macURI}?Privacy_Camera` : `${this.winURI}:privacy-webcam`, '_blank', 'noopener,noreferrer');
                this.closePermissionsDialog(Av.Camera);
              }
            } : {
              key: 'ok',
              label: l.ok_button,
              className: 'positive',
              onClick: () => this.closePermissionsDialog(Av.Camera)
            }]
          },
          browser: {
            title: l.no_camera_title,
            cover: 'permissions-camera',
            info: l.allow_camera_access.replace('[X]', '<i class="sprite-fm-theme icon-camera-disabled"></i>'),
            buttons: [{
              key: 'ok',
              label: l.ok_button,
              className: 'positive',
              onClick: () => this.closePermissionsDialog(Av.Camera)
            }]
          },
          nil: {
            title: l.no_camera_detected_title,
            info: l.no_camera_detected_info,
            buttons: [{
              key: 'ok',
              label: l.ok_button,
              className: 'positive',
              onClick: () => this.closePermissionsDialog(Av.Camera)
            }]
          },
          shared: {
            title: l.no_camera_title,
            info: l.shared_cam_err_info.replace('[A]', `<a href="${this.helpURL}" target="_blank" class="clickurl">`).replace('[/A]', '</a>'),
            buttons: [{
              key: 'ok',
              label: l.ok_button,
              className: 'positive',
              onClick: () => this.closePermissionsDialog(Av.Camera)
            }]
          }
        },
        [Av.Screen]: {
          title: l.no_screen_title,
          info: l.no_screen_system.replace('[A]', `<a href="${this.helpURL}" target="_blank" class="clickurl">`).replace('[/A]', '</a>'),
          buttons: [{
            key: 'open-settings',
            label: l.open_system_settings,
            className: 'positive',
            onClick: () => {
              window.open(`${this.macURI}?Privacy_ScreenCapture`, '_blank', 'noopener,noreferrer');
              this.closePermissionsDialog(Av.Screen);
            }
          }]
        }
      };
      this.state = {
        errMic: '',
        errCamera: '',
        errScreen: '',
        [`dialog-${Av.Audio}`]: null,
        [`dialog-${Av.Camera}`]: null,
        [`dialog-${Av.Screen}`]: null
      };
      this.getPermissionsDialogContent = () => {
        const {
          CONTENT,
          state
        } = this;
        const {
          errMic,
          errCamera
        } = state;
        const {
          browser,
          system,
          nil,
          sharedCam,
          sharedMic,
          sharedGeneric
        } = errors;
        return {
          [Av.Audio]: {
            ...errMic === browser && CONTENT[Av.Audio].browser,
            ...errMic === system && CONTENT[Av.Audio].system,
            ...errMic === nil && CONTENT[Av.Audio].nil,
            ...errMic === sharedMic && CONTENT[Av.Audio].shared,
            ...errMic === sharedGeneric && CONTENT[Av.Audio].shared
          },
          [Av.Camera]: {
            ...errCamera === browser && CONTENT[Av.Camera].browser,
            ...errCamera === system && CONTENT[Av.Camera].system,
            ...errCamera === nil && CONTENT[Av.Camera].nil,
            ...errCamera === sharedCam && CONTENT[Av.Camera].shared,
            ...errCamera === sharedGeneric && CONTENT[Av.Camera].shared
          },
          [Av.Screen]: CONTENT[Av.Screen]
        };
      };
      this.resetError = av => {
        this.setState({
          errMic: av === Av.Audio ? '' : this.state.errMic,
          errCamera: av === Av.Camera ? '' : this.state.errCamera,
          errScreen: av === Av.Screen ? '' : this.state.errScreen
        });
      };
      this.hasToRenderPermissionsWarning = this.hasToRenderPermissionsWarning.bind(this);
      this.renderPermissionsWarning = this.renderPermissionsWarning.bind(this);
    }
    hasToRenderPermissionsWarning(av) {
      const CONFIG = {
        [Av.Audio]: {
          showOnUserActionError: true,
          err: this.state.errMic
        },
        [Av.Camera]: {
          showOnUserActionError: true,
          err: this.state.errCamera
        },
        [Av.Screen]: {
          showOnUserActionError: false,
          err: this.state.errScreen
        }
      };
      const current = CONFIG[av];
      if (current) {
        return isUserActionError(current.err) ? current.showOnUserActionError : current.err;
      }
      return false;
    }
    closePermissionsDialog(av) {
      this.setState({
        [`dialog-${av}`]: false
      }, () => {
        let _this$childRef;
        return (_this$childRef = this.childRef) == null ? void 0 : _this$childRef.safeForceUpdate();
      });
    }
    renderPermissionsDialog(av, child) {
      const content = this.getPermissionsDialogContent();
      const {
        title,
        info,
        buttons,
        cover
      } = content[av] || {};
      return react1().createElement(_ui_modalDialogs_jsx3__.A.ModalDialog, {
        dialogName: `${this.namespace}-permissions-${av}`,
        className: `
                        meetings-permissions-dialog
                        dialog-template-message
                        with-close-btn
                        warning
                    `,
        buttons,
        hideOverlay: Component.NAMESPACE === 'preview-meeting' && !document.body.classList.contains('not-logged'),
        onClose: () => {
          this.setState({
            [`dialog-${av}`]: false
          }, () => child && child.safeForceUpdate());
        }
      }, react1().createElement("header", null, cover ? null : react1().createElement("div", {
        className: "graphic"
      }, react1().createElement("i", {
        className: "warning sprite-fm-uni icon-warning"
      })), react1().createElement("div", {
        className: "info-container"
      }, react1().createElement("h3", {
        id: "msgDialog-title"
      }, title || l[47]), cover && react1().createElement("div", {
        className: "permissions-warning-cover"
      }, react1().createElement("span", {
        className: cover
      })), react1().createElement(_ui_utils_jsx4__.P9, {
        tag: "p",
        className: "permissions-warning-info",
        content: info
      }))));
    }
    renderPermissionsWarning(av, child) {
      const {
        errMic,
        errCamera
      } = this.state;
      const dismissed = errMic === errors.dismissed || errCamera === errors.dismissed;
      return react1().createElement("div", {
        className: `
                        ${this.namespace}
                        meetings-signal-issue
                        simpletip
                        ${dismissed ? 'with-small-area' : ''}
                    `,
        "data-simpletip": l.show_info,
        "data-simpletipposition": "top",
        "data-simpletipoffset": "5",
        "data-simpletip-class": "theme-dark-forced",
        onClick: () => dismissed ? null : this.setState({
          [`dialog-${av}`]: true
        }, () => {
          if (child) {
            this.childRef = child;
          }
        })
      }, react1().createElement("span", {
        className: "signal-issue-background"
      }), react1().createElement("i", {
        className: "sprite-fm-mono icon-exclamation-filled"
      }), this.state[`dialog-${av}`] && this.renderPermissionsDialog(av, child));
    }
    componentWillUnmount() {
      super.componentWillUnmount();
      megaChat.unbind(this.observer);
    }
    componentDidMount() {
      super.componentDidMount();
      megaChat.rebind(this.observer, (ev, errAv) => {
        this.setState({
          errMic: errAv && errAv.mic ? String(errAv.mic) : this.state.errMic,
          errCamera: errAv && errAv.camera ? String(errAv.camera) : this.state.errCamera,
          errScreen: errAv && errAv.screen ? String(errAv.screen) : this.state.errScreen
        });
      });
      megaChat.rebind(`onLocalMediaQueryError.${this.namespace}`, (ev, {
        type,
        err
      }) => {
        if (type === 'screen' && String(err) === errors.system) {
          this.setState({
            [`dialog-${Av.Screen}`]: true
          }, () => this.safeForceUpdate());
        }
      });
    }
    render() {
      return react1().createElement(Component, (0,_extends0__.A)({}, this.props, this.state, {
        errMic: this.state.errMic,
        errCamera: this.state.errCamera,
        errScreen: this.state.errScreen,
        hasToRenderPermissionsWarning: this.hasToRenderPermissionsWarning,
        resetError: this.resetError,
        renderPermissionsWarning: this.renderPermissionsWarning
      }));
    }
  };
};

},

553:
(_, EXP_, REQ_) => {

"use strict";
// ESM COMPAT FLAG
REQ_.r(EXP_);

// EXPORTS
REQ_.d(EXP_, {
  MCO_FLAGS: () => MCO_FLAGS,
  RETENTION_FORMAT: () => RETENTION_FORMAT,
  "default": () => chatRoom
});

;// ./js/chat/utils.jsx
async function prepareExportIo(dl) {
  const {
    zname,
    size
  } = dl;
  if (window.isSecureContext && typeof showSaveFilePicker === 'function' && typeof FileSystemFileHandle !== 'undefined' && 'createWritable' in FileSystemFileHandle.prototype && typeof FileSystemWritableFileStream !== 'undefined' && 'seek' in FileSystemWritableFileStream.prototype) {
    const file = await window.showSaveFilePicker({
      suggestedName: zname
    }).catch(ex => {
      if (String(ex).includes('aborted')) {
        throw new Error('Aborted');
      }
      dump(ex);
    });
    if (file) {
      const stream = await file.createWritable().catch(dump);
      if (stream) {
        return {
          stream,
          write (data, position, done) {
            this.stream.write({
              type: 'write',
              position,
              data
            }).then(done).catch(dump);
          },
          download () {
            this.abort();
          },
          abort () {
            this.stream.close();
          },
          setCredentials () {
            this.begin();
          }
        };
      }
    }
  }
  if (MemoryIO.usable() && Math.min(MemoryIO.fileSizeLimit, 94371840) > size) {
    return new MemoryIO('chat_0', dl);
  } else if (window.requestFileSystem) {
    return new FileSystemAPI('chat_0', dl);
  }
  throw new Error('Download methods are unsupported');
}
function prepareExportStreams(attachNodes, onEmpty) {
  return attachNodes.map(node => {
    return {
      name: node.name,
      lastModified: new Date((node.mtime || node.ts) * 1000),
      input: M.gfsfetch.getReadableStream(node, {
        error(ex, n) {
          if (d) {
            console.error(`${n.h}: ${ex}`);
          }
          onEmpty(n.s);
        }
      })
    };
  });
}
;// ./js/chat/chatRoom.jsx

const RETENTION_FORMAT = {
  HOURS: 'hour',
  DAYS: 'day',
  WEEKS: 'week',
  MONTHS: 'month',
  DISABLED: 'none'
};
const MCO_FLAGS = {
  OPEN_INVITE: 'oi',
  SPEAK_REQUEST: 'sr',
  WAITING_ROOM: 'w'
};
window.RETENTION_FORMAT = RETENTION_FORMAT;
window.MCO_FLAGS = MCO_FLAGS;
const ChatRoom = function (megaChat, roomId, type, users, ctime, lastActivity, chatId, chatShard, chatdUrl, noUI, publicChatHandle, publicChatKey, ck, isMeeting, retentionTime, mcoFlags, organiser) {
  const self = this;
  this.logger = MegaLogger.getLogger(`room[${  roomId  }]`, {}, megaChat.logger);
  this.megaChat = megaChat;
  MegaDataObject.call(this, {
    state: null,
    users: [],
    roomId: null,
    type: null,
    messages: [],
    ctime: 0,
    lastActivity: 0,
    callRequest: null,
    isCurrentlyActive: false,
    _messagesQueue: [],
    unreadCount: 0,
    chatId: undefined,
    chatdUrl: undefined,
    chatShard: undefined,
    members: {},
    membersSet: false,
    membersLoaded: false,
    topic: '',
    flags: 0x00,
    publicLink: null,
    observers: 0,
    dnd: null,
    alwaysNotify: null,
    retentionTime: 0,
    activeCallIds: null,
    meetingsLoading: null,
    options: {},
    scheduledMeeting: undefined,
    historyTimedOut: false
  });
  this.roomId = roomId;
  this.instanceIndex = ChatRoom.INSTANCE_INDEX++;
  this.type = type;
  this.ctime = ctime;
  this.lastActivity = lastActivity ? lastActivity : 0;
  this.chatd = megaChat.plugins.chatdIntegration.chatd;
  this.chatId = chatId;
  this.chatIdBin = chatId ? base64urldecode(chatId) : "";
  this.chatShard = chatShard;
  this.chatdUrl = chatdUrl;
  this.publicLink = null;
  this.publicChatHandle = publicChatHandle;
  this.publicChatKey = publicChatKey;
  this.ck = ck;
  this.scrolledToBottom = 1;
  this.callRequest = null;
  this.shownMessages = {};
  this.retentionTime = retentionTime;
  this.activeSearches = 0;
  this.activeCallIds = new MegaDataMap(this);
  this.ringingCalls = new MegaDataMap(this);
  this.isMeeting = isMeeting;
  this.isNote = type === 'private' && roomId === u_handle;
  this.callUserLimited = false;
  this.members = Object.create(null);
  Object.defineProperty(this.members, 'hasOwnProperty', {
    value(p) {
      return p in this;
    }
  });
  if (type === "private") {
    users.forEach((userHandle) => {
      self.members[userHandle] = 3;
    });
  } else {
    users.forEach((userHandle) => {
      self.members[userHandle] = 0;
    });
  }
  this.options = {};
  mcoFlags = mcoFlags || {};
  for (const flag of Object.values(MCO_FLAGS)) {
    this.options[flag] = mcoFlags[flag] || 0;
  }
  this.organiser = organiser;
  this.setState(ChatRoom.STATE.INITIALIZED);
  this.isCurrentlyActive = false;
  if (d) {
    this.rebind('onStateChange.chatRoomDebug', (e, oldState, newState) => {
      self.logger.debug("Will change state from: ", ChatRoom.stateToText(oldState), " to ", ChatRoom.stateToText(newState));
    });
  }
  self.rebind('onStateChange.chatRoom', (e, oldState, newState) => {
    if (newState === ChatRoom.STATE.READY && !self.isReadOnly() && self.chatd && self.isOnline() && self.chatIdBin) {
      if (d > 2) {
        self.logger.warn('Restoring persisted messages...', self.type, self.isCurrentlyActive);
      }
      const cim = self.getChatIdMessages();
      cim.restore(true);
    }
  });
  self.rebind('onMessagesBuffAppend.lastActivity', (e, msg) => {
    if (is_chatlink || self.isNote) {
      return;
    }
    const ts = msg.delay ? msg.delay : msg.ts;
    if (!ts) {
      return;
    }
    const contactForMessage = msg && Message.getContactForMessage(msg);
    if (contactForMessage && contactForMessage.u !== u_handle) {
      if (!contactForMessage.ats || contactForMessage.ats < ts) {
        contactForMessage.ats = ts;
      }
    }
    if (self.lastActivity && self.lastActivity >= ts) {
      if (msg.deleted) {
        const {
          delay,
          ts
        } = self.messagesBuff.getLastMessageFromServer();
        self.lastActivity = delay || ts;
      }
      return;
    }
    self.lastActivity = ts;
    if (msg.userId === u_handle) {
      self.didInteraction(u_handle, ts);
      return;
    }
    if (self.type === "private") {
      const targetUserId = self.getParticipantsExceptMe()[0];
      let targetUserNode;
      if (M.u[targetUserId]) {
        targetUserNode = M.u[targetUserId];
      } else if (msg.userId) {
        targetUserNode = M.u[msg.userId];
      } else {
        console.error("Missing participant in a 1on1 room.");
        return;
      }
      assert(targetUserNode && targetUserNode.u, 'No hash found for participant');
      assert(M.u[targetUserNode.u], 'User not found in M.u');
      if (targetUserNode) {
        self.didInteraction(targetUserNode.u, self.lastActivity);
      }
    } else if (self.type === "group" || self.type === "public") {
      let contactHash;
      if (msg.authorContact) {
        contactHash = msg.authorContact.u;
      } else if (msg.userId) {
        contactHash = msg.userId;
      }
      if (contactHash && M.u[contactHash]) {
        self.didInteraction(contactHash, self.lastActivity);
      }
      assert(contactHash, 'Invalid hash for user (extracted from inc. message)');
    } else {
      throw new Error("Not implemented");
    }
  });
  self.rebind('onMembersUpdated.coreRoomDataMngmt', (e, eventData) => {
    if (self.state === ChatRoom.STATE.LEFT && eventData.priv >= 0 && eventData.priv < 255) {
      self.membersLoaded = false;
      self.setState(ChatRoom.STATE.JOINING, true);
    }
    let queuedMembersUpdatedEvent = false;
    if (self.membersLoaded === false) {
      if (eventData.priv >= 0 && eventData.priv < 255) {
        const addParticipant = function addParticipant() {
          self.protocolHandler.addParticipant(eventData.userId);
          self.members[eventData.userId] = eventData.priv;
          ChatdIntegration._ensureContactExists([eventData.userId]);
          self.trigger('onMembersUpdatedUI', eventData);
        };
        if (is_chatlink) {
          megaChat.initContacts([eventData.userId]);
        }
        ChatdIntegration._waitForProtocolHandler(self, addParticipant);
        queuedMembersUpdatedEvent = true;
      }
    } else if (eventData.priv === 255 || eventData.priv === -1) {
      const deleteParticipant = function deleteParticipant() {
        if (eventData.userId === u_handle) {
          Object.keys(self.members).forEach((userId) => {
            self.protocolHandler.removeParticipant(userId);
            self.members[userId] = userId === u_handle ? ChatRoom.MembersSet.PRIVILEGE_STATE.LEFT : ChatRoom.MembersSet.PRIVILEGE_STATE.READONLY;
          });
        } else {
          self.protocolHandler.removeParticipant(eventData.userId);
          delete self.members[eventData.userId];
        }
        self.trigger('onMembersUpdatedUI', eventData);
      };
      ChatdIntegration._waitForProtocolHandler(self, deleteParticipant);
      queuedMembersUpdatedEvent = true;
    }
    if (eventData.userId === u_handle) {
      self.membersLoaded = true;
    }
    if (!queuedMembersUpdatedEvent) {
      self.members[eventData.userId] = eventData.priv;
      self.trigger('onMembersUpdatedUI', eventData);
    }
  });
  if (is_chatlink && !is_chatlink.callId && !this.options.w) {
    const unbind = () => {
      self.unbind('onMessagesHistoryDone.chatlinkAlreadyIn');
      self.unbind('onMembersUpdated.chatlinkAlreadyIn');
    };
    self.rebind('onMembersUpdated.chatlinkAlreadyIn', (e, eventData) => {
      if (eventData.userId === u_handle && eventData.priv >= 0) {
        unbind();
        return this.megaChat.routing.reinitAndOpenExistingChat(this.chatId, this.publicChatHandle);
      }
    });
    self.rebind('onMessagesHistoryDone.chatlinkAlreadyIn', (e, data) => {
      if (!data.chatdPersist) {
        unbind();
      }
    });
  }
  self.rebind('onMembersUpdatedUI.chatRoomMembersSync', (e, eventData) => {
    if (eventData.userId === u_handle) {
      self.messagesBuff.joined = true;
      if (eventData.priv === 255 || eventData.priv === -1) {
        if (self.state === ChatRoom.STATE.JOINING) {
          self.setState(ChatRoom.STATE.LEFT);
        }
      } else {
        if (self.state === ChatRoom.STATE.JOINING) {
          self.setState(ChatRoom.STATE.READY);
        }
      }
    }
    self.trackDataChange();
  });
  self.getParticipantsExceptMe().forEach((userHandle) => {
    const contact = M.u[userHandle];
    if (contact && contact.c) {
      getLastInteractionWith(contact.u);
    }
  });
  self.megaChat.trigger('onRoomCreated', [self]);
  if (this.type === "public" && self.megaChat.publicChatKeys[self.chatId]) {
    self.publicChatKey = self.megaChat.publicChatKeys[self.chatId];
  }
  $(window).rebind(`focus.${  self.roomId}`, () => {
    if (self.isCurrentlyActive) {
      self.trigger("onChatShown");
    }
  });
  self.megaChat.rebind(`onRoomDestroy.${  self.roomId}`, (e, room) => {
    if (room.roomId == self.roomId) {
      $(window).off(`focus.${  self.roomId}`);
    }
  });
  self.initialMessageHistLoaded = false;
  let timer = null;
  const _historyIsAvailable = ev => {
    self.initialMessageHistLoaded = ev ? true : -1;
    if (timer) {
      timer.abort();
      timer = null;
    }
    self.unbind('onMarkAsJoinRequested.initHist');
    self.unbind('onHistoryDecrypted.initHist');
    self.unbind('onMessagesHistoryDone.initHist');
  };
  self.rebind('onHistoryDecrypted.initHist', _historyIsAvailable);
  self.rebind('onMessagesHistoryDone.initHist', _historyIsAvailable);
  self.rebind('onMarkAsJoinRequested.initHist', () => {
    (timer = tSleep(300)).then(() => {
      if (d) {
        self.logger.warn("Timed out waiting to load hist for:", self.chatId || self.roomId);
      }
      this.historyTimedOut = true;
      this.trigger('onHistTimeoutChange');
      timer = null;
      _historyIsAvailable(false);
    });
  });
  self.rebind('onRoomDisconnected', () => {
    if (!self.call) {
      for (const activeCallId of self.activeCallIds.keys()) {
        self.activeCallIds.remove(activeCallId);
      }
      megaChat.updateSectionUnreadCount();
    }
  });
  this.rebind(`onCallUserLimitExceeded.${chatId}`, () => {
    if (this.callUserLimited) {
      return;
    }
    (this.callUserLimited = tSleep(60)).always(() => {
      this.callUserLimited = false;
      this.trackDataChange();
    });
  });
  this.membersSetFromApi = new ChatRoom.MembersSet(this);
  if (publicChatHandle) {
    this.onPublicChatRoomInitialized();
  }
  return this;
};
inherits(ChatRoom, MegaDataObject);
ChatRoom.STATE = {
  'INITIALIZED': 5,
  'JOINING': 10,
  'JOINED': 20,
  'READY': 150,
  'ENDED': 190,
  'LEAVING': 200,
  'LEFT': 250
};
ChatRoom.INSTANCE_INDEX = 0;
ChatRoom.ANONYMOUS_PARTICIPANT = mega.BID;
ChatRoom.ARCHIVED = 0x01;
ChatRoom.TOPIC_MAX_LENGTH = 30;
ChatRoom.SCHEDULED_MEETINGS_INTERVAL = 1.8e6;
ChatRoom._fnRequireParticipantKeys = function (fn, scope) {
  return function (...args) {
    const participants = this.protocolHandler.getTrackedParticipants();
    return ChatdIntegration._ensureKeysAreLoaded(undefined, participants).then(() => {
      return fn.apply(scope || this, args);
    }).catch(ex => {
      this.logger.error("Failed to retrieve keys..", ex);
    });
  };
};
ChatRoom.MembersSet = function (chatRoom) {
  this.chatRoom = chatRoom;
  this.members = {};
};
ChatRoom.MembersSet.PRIVILEGE_STATE = {
  NOT_AVAILABLE: -5,
  OPERATOR: 3,
  FULL: 2,
  READONLY: 0,
  LEFT: -1
};
ChatRoom.encryptTopic = function (protocolHandler, newTopic, participants, isPublic = false) {
  if (protocolHandler instanceof strongvelope.ProtocolHandler && participants.size > 0) {
    const topic = protocolHandler.embeddedEncryptTo(newTopic, strongvelope.MESSAGE_TYPES.TOPIC_CHANGE, participants, undefined, isPublic);
    if (topic) {
      return base64urlencode(topic);
    }
  }
  return false;
};
ChatRoom.MembersSet.prototype.trackFromActionPacket = function (ap, isMcf) {
  const self = this;
  const apMembers = {};
  (ap.u || []).forEach((r) => {
    apMembers[r.u] = r.p;
  });
  Object.keys(self.members).forEach((u_h) => {
    if (typeof apMembers[u_h] === 'undefined') {
      self.remove(u_h);
    } else if (apMembers[u_h] !== self.members[u_h]) {
      self.update(u_h, apMembers[u_h]);
    }
  });
  Object.keys(apMembers).forEach((u_h) => {
    if (typeof self.members[u_h] === 'undefined') {
      const priv2 = apMembers[u_h];
      !isMcf ? self.add(u_h, priv2) : self.init(u_h, priv2);
    } else if (apMembers[u_h] !== self.members[u_h]) {
      self.update(u_h, apMembers[u_h]);
    }
  });
  if (!isMcf && ap.m === 1 && !ap.n && ap.url && ap.ou !== u_handle && typeof ap.p === 'undefined' && !ap.topicChange) {
    self.chatRoom.trigger('onMeAdded', ap.ou);
  }
};
ChatRoom.MembersSet.prototype.init = function (handle, privilege) {
  this.members[handle] = privilege;
  this.chatRoom.trackDataChange();
};
ChatRoom.MembersSet.prototype.update = function (handle, privilege) {
  this.members[handle] = privilege;
  this.chatRoom.trackDataChange();
};
ChatRoom.MembersSet.prototype.add = function (handle, privilege) {
  this.members[handle] = privilege;
  if (handle === u_handle) {
    this.chatRoom.trigger('onMeJoined');
  }
  this.chatRoom.trackDataChange();
};
ChatRoom.MembersSet.prototype.remove = function (handle) {
  delete this.members[handle];
  if (handle === u_handle) {
    this.chatRoom.trigger('onMeLeft');
  }
  this.chatRoom.trackDataChange();
};
ChatRoom.prototype.trackMemberUpdatesFromActionPacket = function (ap, isMcf) {
  if (!ap.u) {
    return;
  }
  if (this.membersSetFromApi) {
    this.membersSetFromApi.trackFromActionPacket(ap, isMcf);
  }
};
ChatRoom.prototype.getCallParticipants = function () {
  const ids = this.activeCallIds.keys();
  if (ids.length === 0) {
    return [];
  }
  return this.activeCallIds[ids[0]];
};
ChatRoom.prototype.getChatIdMessages = function () {
  return this.chatd.chatIdMessages[this.chatIdBin];
};
ChatRoom.prototype.getRetentionFormat = function (retentionTime) {
  retentionTime = retentionTime || this.retentionTime;
  switch (true) {
    case retentionTime === 0:
      return RETENTION_FORMAT.DISABLED;
    case retentionTime % daysToSeconds(30) === 0 || retentionTime >= 31536000:
      return RETENTION_FORMAT.MONTHS;
    case retentionTime % daysToSeconds(7) === 0:
      return RETENTION_FORMAT.WEEKS;
    case retentionTime % daysToSeconds(1) === 0:
      return RETENTION_FORMAT.DAYS;
    default:
      return RETENTION_FORMAT.HOURS;
  }
};
ChatRoom.prototype.getRetentionTimeFormatted = function (retentionTime) {
  retentionTime = retentionTime || this.retentionTime;
  switch (this.getRetentionFormat(retentionTime)) {
    case RETENTION_FORMAT.MONTHS:
      return Math.floor(secondsToDays(retentionTime) / 30);
    case RETENTION_FORMAT.WEEKS:
      return secondsToDays(retentionTime) / 7;
    case RETENTION_FORMAT.DAYS:
      return secondsToDays(retentionTime);
    case RETENTION_FORMAT.HOURS:
      return secondsToHours(retentionTime);
    case RETENTION_FORMAT.DISABLED:
      return 0;
  }
};
ChatRoom.prototype.getRetentionLabel = function (retentionTime) {
  retentionTime = retentionTime || this.retentionTime;
  const days = secondsToDays(retentionTime);
  const months = Math.floor(days / 30);
  const hours = secondsToHours(retentionTime);
  switch (this.getRetentionFormat(retentionTime)) {
    case RETENTION_FORMAT.DISABLED:
      return l.disabled_chat_history_cleaning_status;
    case RETENTION_FORMAT.MONTHS:
      return mega.icu.format(l.months_chat_history_plural, months);
    case RETENTION_FORMAT.WEEKS:
      return mega.icu.format(l.weeks_chat_history_plural, days / 7);
    case RETENTION_FORMAT.DAYS:
      return mega.icu.format(l.days_chat_history_plural, days);
    case RETENTION_FORMAT.HOURS:
      return mega.icu.format(l.hours_chat_history_plural, hours);
  }
};
ChatRoom.prototype.setRetention = function (time) {
  asyncApiReq({
    "a": "mcsr",
    "id": this.chatId,
    "d": time,
    "ds": 1
  });
};
ChatRoom.prototype.removeMessagesByRetentionTime = function () {
  const self = this;
  const {messages} = self.messagesBuff;
  if (messages.length === 0 || this.retentionTime === 0) {
    return;
  }
  const newest = messages.getItem(messages.length - 1);
  let lowestValue = newest.orderValue;
  let deleteFrom = null;
  let lastMessage = null;
  const deletePreviousTo = (new Date() - self.retentionTime * 1000) / 1000;
  const cp = self.megaChat.plugins.chatdIntegration.chatd.chatdPersist;
  let finished = false;
  if (typeof cp !== 'undefined') {
    const done = function (message) {
      if (message) {
        if (self.retentionTime > 0 && self.messagesBuff.messages.length > 0) {
          self.messagesBuff._removeMessagesBefore(message.messageId);
        }
        cp.removeMessagesBefore(self.chatId, message.orderValue);
      }
    };
    if (newest.delay < deletePreviousTo) {
      cp.clearChatHistoryForChat(self.chatId);
      return;
    }
    const removeMsgs = function () {
      cp._paginateMessages(lowestValue, Chatd.MESSAGE_HISTORY_LOAD_COUNT, self.chatId).then((messages) => {
        messages = messages[0];
        if (messages.length) {
          for (let i = 0; i < messages.length; i++) {
            const message = messages[i];
            if (message.msgObject.delay < deletePreviousTo) {
              deleteFrom = lastMessage || message;
              break;
            }
            lastMessage = message;
            lowestValue = message.orderValue;
          }
        } else {
          finished = true;
        }
        if (!finished && !deleteFrom) {
          onIdle(removeMsgs);
        } else {
          done(deleteFrom);
        }
      });
    };
    removeMsgs();
  }
  if (self.retentionTime > 0 && self.messagesBuff.messages.length > 0) {
    let message;
    while (message = self.messagesBuff.messages.getItem(0)) {
      if (message.delay < deletePreviousTo) {
        if (!self.messagesBuff.messages.removeByKey(message.messageId)) {
          break;
        }
      } else {
        break;
      }
    }
  }
};
ChatRoom.prototype.isOnline = function () {
  const shard = this.chatd.shards[this.chatShard];
  return shard ? shard.isOnline() : false;
};
ChatRoom.prototype.isOnlineForCalls = function () {
  const chatdChat = this.getChatIdMessages();
  if (!chatdChat) {
    return false;
  }
  return chatdChat.loginState() >= LoginState.HISTDONE;
};
ChatRoom.prototype.isArchived = function () {
  const self = this;
  return self.flags & ChatRoom.ARCHIVED;
};
ChatRoom.prototype.isAnonymous = function () {
  return is_chatlink && this.type === "public" && this.publicChatHandle && this.publicChatKey && this.publicChatHandle === megaChat.initialPubChatHandle;
};
ChatRoom.prototype.isDisplayable = function () {
  return !this.isArchived() || this.call;
};
ChatRoom.prototype.isMuted = function () {
  return pushNotificationSettings.getDnd(this.chatId) || pushNotificationSettings.getDnd(this.chatId) === 0;
};
ChatRoom.prototype.persistToFmdb = function () {
  const self = this;
  if (fmdb) {
    const users = [];
    if (self.members) {
      Object.keys(self.members).forEach((user_handle) => {
        users.push({
          u: user_handle,
          p: self.members[user_handle]
        });
      });
    }
    if (self.chatId && self.chatShard !== undefined) {
      const roomInfo = {
        'id': self.chatId,
        'cs': self.chatShard,
        'g': self.type === "group" || self.type === "public" ? 1 : 0,
        'u': users,
        'ts': self.ctime,
        'ct': self.ct,
        'ck': self.ck ? self.ck : null,
        'f': self.flags,
        'm': self.type === "public" ? 1 : 0
      };
      fmdb.add('mcf', {
        id: roomInfo.id,
        d: roomInfo
      });
    }
  }
};
ChatRoom.prototype.updateFlags = function (f, updateUI) {
  const self = this;
  const flagChange = self.flags !== f;
  self.flags = f;
  if (self.isArchived()) {
    megaChat.archivedChatsCount++;
  } else {
    megaChat.archivedChatsCount--;
  }
  self.persistToFmdb();
  if (updateUI && flagChange) {
    if (megaChat.currentlyOpenedChat && megaChat.chats[megaChat.currentlyOpenedChat] && megaChat.chats[megaChat.currentlyOpenedChat].chatId === self.chatId) {
      loadSubPage('fm/chat/');
    } else {
      megaChat.refreshConversations();
    }
  }
  this.trackDataChange();
};
ChatRoom.stateToText = function (state) {
  let txt = null;
  $.each(ChatRoom.STATE, (k, v) => {
    if (state === v) {
      txt = k;
      return false;
    }
  });
  return txt;
};
ChatRoom.prototype.setState = function (newState, isRecover) {
  const self = this;
  assert(newState, 'Missing state');
  if (newState === self.state) {
    self.logger.debug("Ignoring .setState, newState === oldState, current state: ", self.getStateAsText());
    return;
  }
  if (self.state) {
    assert(newState === ChatRoom.STATE.JOINING && isRecover || newState === ChatRoom.STATE.INITIALIZED && isRecover || newState > self.state, `Invalid state change. Current:${  ChatRoom.stateToText(self.state)  }to${  ChatRoom.stateToText(newState)}`);
  }
  const oldState = self.state;
  self.state = newState;
  self.trigger('onStateChange', [oldState, newState]);
};
ChatRoom.prototype.getStateAsText = function () {
  const self = this;
  return ChatRoom.stateToText(self.state);
};
ChatRoom.prototype.getParticipants = function () {
  const self = this;
  return Object.keys(self.members);
};
ChatRoom.prototype.getParticipantsExceptMe = function (userHandles) {
  const res = clone(userHandles || this.getParticipants());
  array.remove(res, u_handle, true);
  return res;
};
ChatRoom.prototype.getParticipantsTruncated = function (maxMembers = 5, maxLength = ChatRoom.TOPIC_MAX_LENGTH) {
  const truncatedParticipantNames = [];
  const members = Object.keys(this.members);
  for (let i = 0; i < members.length; i++) {
    const handle = members[i];
    const name = M.getNameByHandle(handle);
    if (!handle || !name || handle === u_handle) {
      continue;
    }
    if (i > maxMembers) {
      break;
    }
    truncatedParticipantNames.push(name.length > maxLength ? `${name.substr(0, maxLength)  }...` : name);
  }
  if (truncatedParticipantNames.length === maxMembers) {
    truncatedParticipantNames.push('...');
  }
  return truncatedParticipantNames.join(', ');
};
ChatRoom.prototype.getRoomTitle = function () {
  const formattedDate = l[19077].replace('%s1', new Date(this.ctime * 1000).toLocaleString());
  if (this.isNote) {
    return l.note_label;
  }
  if (this.type === 'private') {
    const participants = this.getParticipantsExceptMe();
    return participants && Array.isArray(participants) ? M.getNameByHandle(participants[0]) : formattedDate;
  }
  if (this.topic === '' || !this.topic) {
    return this.getParticipantsTruncated() || formattedDate;
  }
  const formattedTopic = this.getTruncatedRoomTopic();
  const isCanceled = this.scheduledMeeting && this.scheduledMeeting.isCanceled;
  return isCanceled ? `${formattedTopic} ${l.canceled_meeting}` : formattedTopic;
};
ChatRoom.prototype.getTruncatedRoomTopic = function (maxLength = ChatRoom.TOPIC_MAX_LENGTH) {
  return this.topic && this.topic.length > maxLength ? `${this.topic.substr(0, maxLength)  }...` : this.topic;
};
ChatRoom.prototype.setRoomTopic = async function (newTopic) {
  if (newTopic && newTopic.trim().length && newTopic !== this.getRoomTitle()) {
    this.scrolledToBottom = true;
    const participants = this.protocolHandler.getTrackedParticipants();
    await ChatdIntegration._ensureKeysAreLoaded(undefined, participants);
    const topic = this.protocolHandler.embeddedEncryptTo(newTopic, strongvelope.MESSAGE_TYPES.TOPIC_CHANGE, participants, undefined, this.type === 'public');
    if (topic) {
      return api.req({
        a: 'mcst',
        id: this.chatId,
        ct: base64urlencode(topic),
        v: Chatd.VERSION
      });
    }
  }
};
ChatRoom.prototype.leave = function (notify) {
  const valid = this.type === 'group' || this.type === 'public';
  console.assert(valid, `Can't leave room "${this.roomId}" of type "${this.type}"`);
  if (!valid) {
    return;
  }
  this._leaving = true;
  this.topic = '';
  if (notify) {
    this.trigger('onLeaveChatRequested');
  }
  if (this.state !== ChatRoom.STATE.LEFT) {
    this.setState(ChatRoom.STATE.LEAVING);
    this.setState(ChatRoom.STATE.LEFT);
  }
  if (this.activeCallIds.length) {
    for (const activeCallId of this.activeCallIds.keys()) {
      this.activeCallIds.remove(activeCallId);
    }
    megaChat.updateSectionUnreadCount();
  }
};
ChatRoom.prototype.archive = function () {
  const self = this;
  const mask = 0x01;
  const flags = ChatRoom.ARCHIVED;
  asyncApiReq({
    'a': 'mcsf',
    'id': self.chatId,
    'm': 1,
    'f': flags,
    'v': Chatd.VERSION
  }).then(r => {
    if (r === 0) {
      self.updateFlags(flags, true);
    }
  });
};
ChatRoom.prototype.unarchive = function () {
  const self = this;
  const mask = 0x01;
  const flags = 0x00;
  asyncApiReq({
    'a': 'mcsf',
    'id': self.chatId,
    'm': 1,
    'f': 0,
    'v': Chatd.VERSION
  }).then(res => {
    if (res === 0) {
      self.updateFlags(0, true);
    }
  });
};
ChatRoom.prototype.destroy = function (notifyOtherDevices, noRedirect) {
  const self = this;
  self.megaChat.trigger('onRoomDestroy', [self]);
  const mc = self.megaChat;
  const roomJid = self.roomId;
  if (!self.stateIsLeftOrLeaving()) {
    self.leave(notifyOtherDevices);
  } else if (self.type === "public" && self.publicChatHandle) {
    if (typeof self.members[u_handle] === 'undefined') {
      self.megaChat.plugins.chatdIntegration.handleLeave(self);
    }
  }
  if (self.isCurrentlyActive) {
    self.isCurrentlyActive = false;
  }
  Soon(() => {
    mc.chats.remove(roomJid);
    if (!noRedirect && u_type === 3) {
      loadSubPage('fm/chat');
    }
  });
};
ChatRoom.prototype.updatePublicHandle = async function (remove, cim, force) {
  if (force) {
    this.publicLink = null;
  }
  if (!remove && this.publicLink) {
    return this.publicLink;
  }
  return asyncApiReq({
    a: 'mcph',
    id: this.chatId,
    v: Chatd.VERSION,
    cim: cim ? 1 : 0,
    d: remove ? 1 : undefined
  }).then(res => {
    assert(remove && res === 0 || Array.isArray(res) && res[1].length === 8);
    this.publicLink = remove ? null : `chat/${res[1]}#${this.protocolHandler.getUnifiedKey()}`;
  }).catch(ex => {
    this.logger.warn('updatePublicHandle', ex);
    this.publicLink = null;
  });
};
ChatRoom.prototype.iAmInRoom = function () {
  return !(!this.members.hasOwnProperty(u_handle) || this.members[u_handle] === -1);
};
ChatRoom.prototype.joinViaPublicHandle = function () {
  const self = this;
  if (!fminitialized && is_chatlink) {
    if (u_type) {
      return new Promise((res, rej) => {
        self.megaChat.plugins.chatdIntegration.joinChatViaPublicHandle(self).then(() => {
          self.megaChat.routing.reinitAndOpenExistingChat(self.chatId, self.publicChatHandle).then(res, rej);
        }, ex => {
          console.error("Failed joining a chat room (u_type)", ex);
          rej(ex);
        });
      });
    }
    return;
  }
  if (!self.iAmInRoom() && self.type === "public" && self.publicChatHandle) {
    return megaChat.plugins.chatdIntegration.joinChatViaPublicHandle(self);
  }
  return Promise.reject();
};
ChatRoom.prototype.switchOffPublicMode = ChatRoom._fnRequireParticipantKeys(function () {
  let {
    topic,
    protocolHandler,
    chatId
  } = this;
  if (topic) {
    topic = protocolHandler.embeddedEncryptTo(topic, strongvelope.MESSAGE_TYPES.TOPIC_CHANGE, protocolHandler.getTrackedParticipants(), true, false);
    topic = base64urlencode(topic);
  }
  return asyncApiReq({
    a: 'mcscm',
    id: chatId,
    ct: topic || undefined,
    v: Chatd.VERSION
  }).then(() => {
    protocolHandler.switchOffOpenMode();
  });
});
ChatRoom.prototype.show = function () {
  if (this.isCurrentlyActive) {
    return false;
  }
  this.megaChat.hideAllChats();
  if (d) {
    this.logger.debug(' ---- show');
  }
  $.tresizer();
  onIdle(() => {
    this.scrollToChat();
    this.trackDataChange();
  });
  this.isCurrentlyActive = true;
  this.lastShownInUI = Date.now();
  this.megaChat.setAttachments(this.roomId);
  this.megaChat.lastOpenedChat = this.roomId;
  this.megaChat.currentlyOpenedChat = this.roomId;
  this.trigger('activity');
  this.trigger('onChatShown');
  let tmp = this.megaChat.rootDOMNode;
  if (tmp = tmp.querySelector('.conversation-panels')) {
    tmp.classList.remove('hidden');
    if (tmp = tmp.querySelector(`.conversation-panel[data-room-id="${this.chatId}"]`)) {
      tmp.classList.remove('hidden');
    }
  }
  if (tmp = document.getElementById(`conversation_${this.roomId}`)) {
    tmp.classList.add('active');
  }
  if (mega.ui.mInfoPanel) {
    mega.ui.mInfoPanel.hide();
  }
};
ChatRoom.prototype.scrollToChat = function () {
  this._scrollToOnUpdate = true;
  const {
    $chatTreePanePs
  } = megaChat;
  if ($chatTreePanePs && $chatTreePanePs.length) {
    const li = document.querySelector(`ul.conversations-pane li#conversation_${this.roomId}`);
    if (li && !verge.inViewport(li, -72)) {
      Object.values($chatTreePanePs).forEach(({
        ref
      }) => {
        if (ref.domNode) {
          const wrapOuterHeight = $(ref.domNode).outerHeight();
          const itemOuterHeight = $('li:first', ref.domNode).outerHeight();
          const pos = li.offsetTop;
          if (ref.domNode.contains(li)) {
            ref.doProgramaticScroll == null || ref.doProgramaticScroll(Math.max(0, pos - wrapOuterHeight / 2 + itemOuterHeight), true);
          }
        }
      });
      this._scrollToOnUpdate = false;
    }
  }
};
ChatRoom.prototype.isActive = function () {
  return document.hasFocus() && this.isCurrentlyActive;
};
ChatRoom.prototype.setActive = function () {
  loadSubPage(this.getRoomUrl());
};
ChatRoom.prototype.isLoading = function () {
  const mb = this.messagesBuff;
  return mb.messagesHistoryIsLoading() || mb.isDecrypting;
};
ChatRoom.prototype.getRoomUrl = function (getRawLink) {
  const self = this;
  if (self.type === "private") {
    const participants = self.getParticipantsExceptMe();
    const contact = M.u[participants[0] || u_handle];
    if (contact) {
      return `fm/chat/p/${  contact.u}`;
    }
  } else if (!getRawLink && is_chatlink && self.type === "public" && self.publicChatHandle && self.publicChatKey) {
    return `chat/${  self.publicChatHandle  }#${  self.publicChatKey}`;
  } else if (self.type === "public") {
    return `fm/chat/c/${  self.roomId}`;
  } else if (self.type === "group" || self.type === "public") {
    return `fm/chat/g/${  self.roomId}`;
  } else {
    throw new Error("Can't get room url for unknown room type.");
  }
};
ChatRoom.prototype.activateWindow = function () {
  const self = this;
  loadSubPage(self.getRoomUrl());
};
ChatRoom.prototype.hide = function () {
  let _tmp;
  if (d) {
    this.logger.debug(' ---- hide', this.isCurrentlyActive);
  }
  this.isCurrentlyActive = false;
  this.lastShownInUI = Date.now();
  if (this.megaChat.currentlyOpenedChat === this.roomId) {
    this.megaChat.currentlyOpenedChat = null;
  }
  let tmp = this.megaChat.rootDOMNode.querySelector(`.conversation-panel[data-room-id="${this.chatId}"]`);
  (_tmp = tmp) == null || _tmp.classList.add('hidden');
  if (tmp = document.getElementById(`conversation_${this.roomId}`)) {
    tmp.classList.remove('active');
  }
  this.trigger('onChatHidden', this.isCurrentlyActive);
};
ChatRoom.prototype.appendMessage = function (message) {
  const self = this;
  if (message.deleted) {
    return false;
  }
  if (self.shownMessages[message.messageId]) {
    return false;
  }
  if (!message.orderValue) {
    const mb = self.messagesBuff;
    if (mb.messages.length > 0) {
      const prevMsg = mb.messages.getItem(mb.messages.length - 1);
      if (!prevMsg) {
        self.logger.error("self.messages got out of sync...maybe there are some previous JS exceptions that caused that? note that messages may be displayed OUT OF ORDER in the UI.");
      } else {
        let nextVal = prevMsg.orderValue + 0.1;
        if (!prevMsg.sent) {
          const cid = megaChat.plugins.chatdIntegration.chatd.chatIdMessages[self.chatIdBin];
          if (cid && cid.highnum) {
            nextVal = ++cid.highnum;
          }
        }
        message.orderValue = nextVal;
      }
    }
  }
  message.source = Message.SOURCE.SENT;
  self.trigger('onMessageAppended', message);
  self.messagesBuff.messages.push(message);
  self.shownMessages[message.messageId] = true;
};
ChatRoom.prototype.getNavElement = function () {
  const self = this;
  return $(`.nw-conversations-item[data-room-id="${  self.chatId  }"]`);
};
ChatRoom.prototype.sendMessage = function (message) {
  const self = this;
  const {megaChat} = this;
  const messageId = megaChat.generateTempMessageId(self.roomId, message);
  const msgObject = new Message(self, self.messagesBuff, {
    messageId,
    'userId': u_handle,
    message,
    'textContents': message,
    'delay': unixtime(),
    'sent': Message.STATE.NOT_SENT
  });
  self.trigger('onSendMessage');
  self.appendMessage(msgObject);
  return self._sendMessageToTransport(msgObject).then(internalId => {
    if (!internalId) {
      this.logger.warn(`Got unexpected(?) 'sendingnum'...`, internalId);
    }
    msgObject.internalId = internalId;
    msgObject.orderValue = internalId;
    return internalId || -0xBADF;
  }).catch(ex => {
    this.logger.error(`sendMessage failed..`, msgObject, ex);
  });
};
ChatRoom.prototype._sendMessageToTransport = function (messageObject) {
  const self = this;
  const {megaChat} = this;
  megaChat.trigger('onPreBeforeSendMessage', messageObject);
  megaChat.trigger('onBeforeSendMessage', messageObject);
  megaChat.trigger('onPostBeforeSendMessage', messageObject);
  return megaChat.plugins.chatdIntegration.sendMessage(self, messageObject);
};
ChatRoom.prototype._sendNodes = async function (nodeids, users) {
  const u = this.type === 'public' ? [strongvelope.COMMANDER] : users;
  const promises = nodeids.map(nodeId => asyncApiReq({
    a: 'mcga',
    n: [nodeId],
    u,
    id: this.chatId,
    v: Chatd.VERSION
  }));
  const res = await Promise.allSettled(promises);
  const sent = [];
  for (let i = res.length; i--;) {
    if (res[i].status === 'fulfilled') {
      sent.push(nodeids[i]);
    }
  }
  if (!sent.length) {
    throw ENOENT;
  }
  return sent;
};
ChatRoom.prototype.attachNodes = async function (nodes, names) {
  if (!Array.isArray(nodes)) {
    nodes = [nodes];
  }
  const handles = new Set();
  for (let i = nodes.length; i--;) {
    const n = nodes[i];
    const h = String(crypto_keyok(n) && n.h || n);
    if (!M.getNodeByHandle(h)) {
      handles.add(h);
    }
  }
  if (handles.size) {
    await dbfetch.acquire([...handles]);
  }
  return this._attachNodes(nodes, names);
};
ChatRoom.prototype._attachNodes = mutex('chatroom-attach-nodes', function _(resolve, reject, nodes, names) {
  let i;
  let step = 0;
  const users = [];
  const self = this;
  let result = null;
  let copy = Object.create(null);
  let send = Object.create(null);
  let link = Object.create(null);
  let nmap = Object.create(null);
  const members = self.getParticipantsExceptMe();
  const sendMessage = nodes => {
    return new Promise(resolve => {
      for (let i = nodes.length; i--;) {
        const n = nmap[nodes[i]] || M.getNodeByHandle(nodes[i]);
        console.assert(n.h, `Node not found... ${nodes[i]}`);
        if (n.h) {
          const name = names && (names[n.hash] || names[n.h]) || n.name;
          this.sendMessage(Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT + Message.MANAGEMENT_MESSAGE_TYPES.ATTACHMENT + JSON.stringify([{
            h: n.h,
            k: n.k,
            t: n.t,
            s: n.s,
            fa: n.fa,
            ts: n.ts,
            hash: n.hash,
            name,
            des: n.des
          }]));
        }
      }
      resolve();
    });
  };
  const attach = nodes => {
    console.assert(this.type === 'public' || users.length || this.isNote, 'No users to send to?!');
    return this.isNote ? sendMessage(nodes) : this._sendNodes(nodes, users).then(res => sendMessage(res));
  };
  const done = function () {
    if (--step < 1) {
      nmap = null;
      resolve(result);
    }
  };
  const fail = function (ex) {
    if (ex === EBLOCKED) {
      result = ex;
    } else if (ex === ENOENT) {
      result = result || ex;
    } else if (d) {
      _.logger.error(ex);
    }
    done();
  };
  if (d && !_.logger) {
    _.logger = new MegaLogger('attachNodes', {}, self.logger);
  }
  for (i = members.length; i--;) {
    const usr = M.getUserByHandle(members[i]);
    if (usr.u) {
      users.push(usr.u);
    }
  }
  for (i = nodes.length; i--;) {
    const h = nodes[i];
    const n = crypto_keyok(h) ? h : M.getNodeByHandle(h);
    if (n.t) {
      link[n.h] = 1;
      continue;
    }
    if (n.hash) {
      nmap[n.hash] = n;
      if (names && names[n.h]) {
        names[n.hash] = names[n.h];
      }
    }
    let op = send;
    if (n.u !== u_handle || M.getNodeRoot(n.h) === 'shares') {
      op = copy;
    }
    op[n.h] = 1;
    nmap[n.h] = n;
  }
  copy = Object.keys(copy);
  send = Object.keys(send);
  link = Object.keys(link);
  if (d) {
    _.logger.debug('copy:%d, send:%d, link:%d', copy.length, send.length, link.length, copy, send, link);
  }
  if (link.length) {
    ++step;
    Promise.resolve(mega.fileRequestCommon.storage.isDropExist(link)).then(res => {
      if (res.length) {
        return mega.fileRequest.showRemoveWarning(res);
      }
    }).then(() => {
      const createLink = h => M.createPublicLink(h).then(({
        link
      }) => this.sendMessage(link));
      return Promise.all(link.map(createLink));
    }).then(done).catch(fail);
  }
  if (send.length) {
    step++;
    attach(send).then(done).catch(fail);
  }
  if (copy.length) {
    step++;
    this._copyNodesToAttach(copy, nmap).then(res => attach(res)).then(done).catch(fail);
  }
  if (!step) {
    if (d) {
      _.logger.warn('Nothing to do here...');
    }
    queueMicrotask(done);
  }
});
ChatRoom.prototype._copyNodesToAttach = async function (copy, nmap) {
  const {
    h: target
  } = await M.myChatFilesFolder.get(true);
  if (!M.c[target]) {
    await dbfetch.get(target);
  }
  const dir = Object.keys(M.c[target] || {});
  const rem = [];
  for (let i = copy.length; i--;) {
    const n = nmap[copy[i]] || M.getNodeByHandle(copy[i]);
    console.assert(n.h, `Node not found.. ${copy[i]}`);
    for (let y = dir.length; y--;) {
      const b = M.getNodeByHandle(dir[y]);
      if (n.h === b.h || b.hash === n.hash) {
        if (d) {
          this.logger.info('deduplication %s:%s', n.h, b.h, [n], [b]);
        }
        rem.push(n.h);
        copy.splice(i, 1);
        break;
      }
    }
  }
  let res = [];
  if (copy.length) {
    res = await M.copyNodes(copy, target, false, false, {
      targetChatId: this.chatId
    });
  } else if (d) {
    this.logger.info('No new nodes to copy.', rem);
  }
  assert(Array.isArray(res), `Unexpected response, ${res && res.message || res}`, res);
  const [h] = res;
  res = [...rem, ...res];
  assert(res.length, 'Unexpected condition... nothing to attach ?!');
  for (let i = res.length; i--;) {
    const n = nmap[res[i]] || M.getNodeByHandle(res[i]);
    if (n.fv) {
      if (d) {
        this.logger.info('Skipping file-version %s', n.h, n);
      }
      res.splice(i, 1);
    }
  }
  if (h && !res.length) {
    if (d) {
      this.logger.info('Adding nothing but a file-version?..', h);
    }
    res = [h];
  }
  return res;
};
ChatRoom.prototype.onUploadStart = function (data) {
  const self = this;
  if (d) {
    self.logger.debug('onUploadStart', data);
  }
};
ChatRoom.prototype.uploadFromComputer = function () {
  this.scrolledToBottom = true;
  $('#fileselect1').trigger('click');
};
ChatRoom.prototype.attachContacts = function (ids) {
  for (let i = 0; i < ids.length; i++) {
    const nodeId = ids[i];
    const node = M.u[nodeId];
    this.sendMessage(Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT + Message.MANAGEMENT_MESSAGE_TYPES.CONTACT + JSON.stringify([{
      u: node.u,
      email: node.m,
      name: node.name || node.m
    }]));
  }
};
ChatRoom.prototype.getMessageById = function (messageId) {
  const self = this;
  const msgs = self.messagesBuff.messages;
  const msgKeys = msgs.keys();
  for (let i = 0; i < msgKeys.length; i++) {
    const k = msgKeys[i];
    const v = msgs[k];
    if (v && v.messageId === messageId) {
      return v;
    }
  }
  return false;
};
ChatRoom.prototype.hasMessages = function (userMessagesOnly = false) {
  return this.messagesBuff.messages.some(m => !userMessagesOnly || m.messageHtml);
};
ChatRoom.prototype.renderContactTree = function () {
  const self = this;
  const $navElement = self.getNavElement();
  const $count = $('.nw-conversations-unread', $navElement);
  const count = self.messagesBuff.getUnreadCount();
  if (count > 0) {
    $count.text(count > 9 ? "9+" : count);
    $navElement.addClass("unread");
  } else if (count === 0) {
    $count.text("");
    $navElement.removeClass("unread");
  }
  $navElement.data('chatroom', self);
};
ChatRoom.prototype.getUnreadCount = function () {
  const self = this;
  return self.messagesBuff.getUnreadCount();
};
ChatRoom.prototype.recover = function () {
  const self = this;
  self.callRequest = null;
  if (self.state !== ChatRoom.STATE.LEFT) {
    self.membersLoaded = false;
    self.setState(ChatRoom.STATE.JOINING, true);
    self.megaChat.trigger("onRoomCreated", [self]);
    return MegaPromise.resolve();
  } else {
    return MegaPromise.reject();
  }
};
ChatRoom.prototype.showMissingUnifiedKeyDialog = function () {
  return msgDialog(`warningb:!^${l.msg_dlg_cancel}!${l[23433]}`, null, l[200], l.chat_key_failed_dlg_text, reload => reload ? M.reload() : null, 1);
};
ChatRoom.prototype.hasInvalidKeys = function () {
  if (!is_chatlink && this.type === 'public') {
    const {
      unifiedKey
    } = this.protocolHandler || {};
    if (!unifiedKey || unifiedKey && unifiedKey.length !== 16 || !this.ck || this.ck && this.ck.length !== 32) {
      console.error('Error instantiating room/call -- missing `unifiedKey`/malformed `ck` for public chat.');
      const {
        owner,
        actors
      } = mBroadcaster.crossTab;
      eventlog(99751, JSON.stringify([1, buildVersion.website || 'dev', String(this.chatId).length | 0, this.type | 0, this.isMeeting | 0, typeof unifiedKey, String(unifiedKey || '').length | 0, typeof this.ck, String(this.ck).length | 0, !!owner | 0, Object(actors).length | 0]));
      return true;
    }
  }
  return false;
};
ChatRoom.prototype.joinCall = ChatRoom._fnRequireParticipantKeys(function (audio, video, callId) {
  if (!megaChat.hasSupportForCalls || this.activeCallIds.length === 0 || this.meetingsLoading) {
    return;
  }
  if (this.hasInvalidKeys()) {
    return this.showMissingUnifiedKeyDialog();
  }
  this.meetingsLoading = {
    title: l.joining,
    audio,
    video
  };
  callId = callId || this.activeCallIds.keys()[0];
  return asyncApiReq({
    'a': 'mcmj',
    'cid': this.chatId,
    "mid": callId
  }).then(r => {
    this.startOrJoinCall(callId, r.url, audio, video, r.organiser);
  });
});
ChatRoom.prototype.startOrJoinCall = function (callId, url, audio, video, organiser) {
  tryCatch(() => {
    const call = this.call = megaChat.activeCall = megaChat.plugins.callManager2.createCall(this, callId, this.protocolHandler.chatMode === strongvelope.CHAT_MODE.PUBLIC && str_to_ab(this.protocolHandler.unifiedKey));
    call.setOrganiser(organiser);
    return call.connect(url, audio, video);
  }, ex => {
    let _this$call;
    (_this$call = this.call) == null || _this$call.destroy();
    this.call = megaChat.activeCall = null;
    this.meetingsLoading = false;
    console.error('Failed to start/join call:', ex);
  })();
};
ChatRoom.prototype.rejectCall = function (callId) {
  if (this.activeCallIds.length === 0) {
    return;
  }
  callId = callId || this.activeCallIds.keys()[0];
  if (this.type === "private") {
    return asyncApiReq({
      'a': 'mcme',
      'cid': this.chatId,
      'mid': callId
    });
  }
  const shard = this.chatd.shards[this.chatShard];
  if (shard) {
    shard.sendCallReject(base64urldecode(this.chatId), base64urldecode(callId));
  }
  return Promise.resolve();
};
ChatRoom.prototype.ringUser = function (userId, callId, callstate) {
  assert(userId, 'Missing user handle.');
  assert(callId, 'Missing chat handle.');
  assert(this.type !== 'private', 'Unexpected chat type.');
  const shard = this.chatd.shards[this.chatShard];
  if (shard) {
    api.req({
      a: 'mcru',
      u: userId,
      cid: this.chatId
    }).then(() => shard.ringUser(this.chatIdBin, base64urldecode(userId), base64urldecode(callId), callstate)).catch(dump);
  }
};
ChatRoom.prototype.endCallForAll = function (callId) {
  if (this.activeCallIds.length && this.type !== 'private') {
    callId = callId || this.activeCallIds.keys()[0];
    asyncApiReq({
      'a': 'mcme',
      'cid': this.chatId,
      'mid': callId
    });
    eventlog(99761, JSON.stringify([this.chatId, callId, this.isMeeting | 0]));
  }
};
ChatRoom.prototype.startAudioCall = function (scheduled) {
  return this.startCall(true, false, scheduled);
};
ChatRoom.prototype.startVideoCall = function (scheduled) {
  return this.startCall(true, true, scheduled);
};
ChatRoom.prototype.startCall = ChatRoom._fnRequireParticipantKeys(function (audio, video, scheduled) {
  if (!megaChat.hasSupportForCalls || this.meetingsLoading) {
    return;
  }
  if (this.activeCallIds.length > 0) {
    this.joinCall(this.activeCallIds.keys()[0]);
    return;
  }
  if (this.hasInvalidKeys()) {
    return this.showMissingUnifiedKeyDialog();
  }
  this.meetingsLoading = {
    title: l.starting,
    audio,
    video
  };
  const opts = {
    a: 'mcms',
    cid: this.chatId,
    sm: scheduled && this.scheduledMeeting && this.scheduledMeeting.id
  };
  if (localStorage.sfuId) {
    opts.sfu = parseInt(localStorage.sfuId, 10);
  }
  return asyncApiReq(opts).then(r => {
    this.startOrJoinCall(r.callId, r.sfu, audio, video, r.organiser);
  }).catch(ex => {
    this.meetingsLoading = false;
    this.logger.error(`Failed to start call: ${ex}`);
  });
});
ChatRoom.prototype.subscribeForCallEvents = function () {
  const callMgr = megaChat.plugins.callManager2;
  this.rebind("onChatdPeerJoinedCall.callManager", (e, data) => {
    if (!this.activeCallIds.exists(data.callId)) {
      this.activeCallIds.set(data.callId, []);
    }
    this.activeCallIds.set(data.callId, [...this.activeCallIds[data.callId], ...data.participants]);
    const parts = data.participants;
    for (let i = 0; i < parts.length; i++) {
      if (this.type === "private" || parts[i] === u_handle && this.ringingCalls.exists(data.callId)) {
        this.ringingCalls.remove(data.callId);
        callMgr.trigger("onRingingStopped", {
          callId: data.callId,
          chatRoom: this
        });
      }
    }
    megaChat.updateSectionUnreadCount();
    this.callParticipantsUpdated();
  });
  this.rebind("onChatdPeerLeftCall.callManager", (e, data) => {
    if (!this.activeCallIds[data.callId]) {
      return;
    }
    const parts = data.participants;
    for (let i = 0; i < parts.length; i++) {
      array.remove(this.activeCallIds[data.callId], parts[i], true);
      if (parts[i] === u_handle && this.ringingCalls.exists(data.callId)) {
        this.ringingCalls.remove(data.callId);
        callMgr.trigger("onRingingStopped", {
          callId: data.callId,
          chatRoom: this
        });
      }
    }
    this.callParticipantsUpdated();
  });
  this.rebind("onCallLeft.callManager", (e, data) => {
    console.warn("onCallLeft:", JSON.stringify(data));
    const {
      call
    } = this;
    if (!call || call.callId !== data.callId) {
      if (d) {
        console.warn("... no active call or event not for it");
      }
      return;
    }
    this.meetingsLoading = false;
    call.hangUp(data.reason);
    megaChat.activeCall = this.call = null;
  });
  this.rebind("onChatdCallEnd.callManager", (e, data) => {
    if (d) {
      console.warn("onChatdCallEnd:", JSON.stringify(data));
    }
    this.meetingsLoading = false;
    this.activeCallIds.remove(data.callId);
    if (this.callUserLimited) {
      this.callUserLimited.abort();
    }
    this.callUserLimited = false;
    this.stopRinging(data.callId);
    this.callParticipantsUpdated();
    megaChat.updateSectionUnreadCount();
  });
  this.rebind('onCallState.callManager', function (e, data) {
    const ac = this.activeCallIds[data.callId];
    console.assert(ac, `unknown call: ${data.callId}`);
    if (ac) {
      callMgr.onCallState(data, this);
      this.callParticipantsUpdated();
    }
  });
  this.rebind('onRoomDisconnected.callManager', function () {
    this.activeCallIds.clear();
    megaChat.updateSectionUnreadCount();
    if (navigator.onLine) {
      return;
    }
    if (this.call) {
      this.trigger('ChatDisconnected', this);
    }
    this.callParticipantsUpdated();
  });
  this.rebind('onStateChange.callManager', function (e, oldState, newState) {
    if (newState === ChatRoom.STATE.LEFT && this.call) {
      this.call.hangUp(SfuClient.TermCode.kLeavingRoom);
    }
  });
  this.rebind('onCallPeerLeft.callManager', (e, data) => {
    const {
      call
    } = this;
    if (!call || call.isDestroyed || call.hasOtherParticipant() || SfuClient.isTermCodeRetriable(data.reason)) {
      return;
    }
    if (this.type === 'private') {
      return this.trigger('onCallLeft', {
        callId: call.callId
      });
    }
    setTimeout(() => {
      if (this.call === call) {
        this.call.initCallTimeout();
      }
    }, 3000);
  });
  this.rebind('onMeAdded', (e, addedBy) => {
    if (this.activeCallIds.length > 0) {
      const callId = this.activeCallIds.keys()[0];
      if (this.ringingCalls.exists(callId)) {
        return;
      }
      this.ringingCalls.set(callId, addedBy);
      this.megaChat.trigger('onIncomingCall', [this, callId, addedBy, callMgr]);
      this.fakedLocalRing = true;
      setTimeout(() => {
        delete this.fakedLocalRing;
        if (this.ringingCalls.exists(callId)) {
          callMgr.trigger("onRingingStopped", {
            callId,
            chatRoom: this
          });
        }
      }, 30e3);
    }
  });
};
ChatRoom.prototype.stateIsLeftOrLeaving = function () {
  return this.state == ChatRoom.STATE.LEFT || this.state == ChatRoom.STATE.LEAVING || (!is_chatlink && this.state === ChatRoom.STATE.READY && this.membersSetFromApi && !this.membersSetFromApi.members.hasOwnProperty(u_handle) || is_chatlink && !this.members.hasOwnProperty(u_handle));
};
ChatRoom.prototype._clearChatMessagesFromChatd = function () {
  this.chatd.shards[this.chatShard].retention(base64urldecode(this.chatId), 1);
};
ChatRoom.prototype.isReadOnly = function () {
  if (this.type === "private") {
    const members = this.getParticipantsExceptMe();
    if (members[0] && !M.u[members[0]].c) {
      return true;
    }
  }
  return this.members && this.members[u_handle] <= 0 || !this.members.hasOwnProperty(u_handle) || this.privateReadOnlyChat || this.state === ChatRoom.STATE.LEAVING || this.state === ChatRoom.STATE.LEFT;
};
ChatRoom.prototype.iAmOperator = function () {
  return this.type === 'private' || this.members && this.members[u_handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR;
};
ChatRoom.prototype.iAmReadOnly = function () {
  return this.type !== 'private' && this.members && this.members[u_handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.READONLY;
};
ChatRoom.prototype.iAmWaitingRoomPeer = function () {
  return this.options.w && !this.iAmOperator();
};
ChatRoom.prototype.didInteraction = function (user_handle, ts) {
  const self = this;
  const newTs = ts || unixtime();
  if (user_handle === u_handle) {
    Object.keys(self.members).forEach((user_handle) => {
      const contact = M.u[user_handle];
      if (contact && user_handle !== u_handle && contact.c === 1) {
        setLastInteractionWith(contact.u, `1:${  newTs}`);
      }
    });
  } else {
    const contact = M.u[user_handle];
    if (contact && user_handle !== u_handle && contact.c === 1) {
      setLastInteractionWith(contact.u, `1:${  newTs}`);
    }
  }
};
ChatRoom.prototype.retrieveAllHistory = function () {
  const self = this;
  self.messagesBuff.retrieveChatHistory().done(() => {
    if (self.messagesBuff.haveMoreHistory()) {
      self.retrieveAllHistory();
    }
  });
};
ChatRoom.prototype.seedRoomKeys = async function (keys) {
  assert(Array.isArray(keys) && keys.length, `Invalid keys parameter for seedRoomKeys.`, keys);
  if (d > 2) {
    this.logger.warn('Seeding room keys...', keys);
  }
  const promises = [ChatdIntegration._ensureKeysAreLoaded(keys, undefined, this.publicChatHandle)];
  if (!this.protocolHandler) {
    promises.push(ChatdIntegration._waitForProtocolHandler(this));
  }
  if (!this.notDecryptedKeys) {
    this.notDecryptedKeys = Object.create(null);
  }
  for (let i = keys.length; i--;) {
    const {
      key,
      keyid,
      keylen,
      userId
    } = keys[i];
    this.notDecryptedKeys[`${userId}-${keyid}`] = {
      userId,
      keyid,
      keylen,
      key
    };
  }
  const promise = this._keysAreSeeding = Promise.all(promises).then(() => {
    const res = this.protocolHandler.seedKeys(keys);
    for (let i = res.length; i--;) {
      delete this.notDecryptedKeys[res[i]];
    }
    return res;
  }).catch(ex => {
    this.logger.error('Failed to seed room keys!', ex, keys);
    throw ex;
  }).finally(() => {
    if (promise === this._keysAreSeeding) {
      delete this._keysAreSeeding;
    }
  });
  return promise;
};
ChatRoom.prototype.truncate = function () {
  const self = this;
  const chatMessages = self.messagesBuff.messages;
  if (chatMessages.length > 0) {
    let lastChatMessageId = null;
    let i = chatMessages.length - 1;
    while (lastChatMessageId == null && i >= 0) {
      const message = chatMessages.getItem(i);
      if (message instanceof Message && message.dialogType !== "truncated") {
        lastChatMessageId = message.messageId;
      }
      i--;
    }
    if (lastChatMessageId) {
      asyncApiReq({
        a: 'mct',
        id: self.chatId,
        m: lastChatMessageId,
        v: Chatd.VERSION
      }).catch(ex => {
        if (ex === -2) {
          msgDialog('warninga', l[135], l[8880]);
        }
      });
    }
  }
};
ChatRoom.prototype.getActiveCalls = function () {
  return this.activeCallIds.map((parts, id) => {
    return parts.indexOf(u_handle) > -1 ? id : undefined;
  });
};
ChatRoom.prototype.haveActiveCall = function () {
  return this.getActiveCalls().length > 0;
};
ChatRoom.prototype.haveActiveOnHoldCall = function () {
  const activeCallIds = this.getActiveCalls();
  for (let i = 0; i < activeCallIds.length; i++) {
    const call = megaChat.plugins.callManager2.calls[`${this.chatId  }_${  activeCallIds[i]}`];
    if (call && call.av & SfuClient.Av.onHold) {
      return true;
    }
  }
  return false;
};
ChatRoom.prototype.havePendingGroupCall = function () {
  if (this.type !== "group" && this.type !== "public") {
    return false;
  }
  return this.activeCallIds.length > 0;
};
ChatRoom.prototype.havePendingCall = function () {
  return this.activeCallIds.length > 0;
};
ChatRoom.prototype.getActiveCallMessageId = function (ignoreActive) {
  const self = this;
  if (!ignoreActive && !self.havePendingCall() && !self.haveActiveCall()) {
    return false;
  }
  const msgs = self.messagesBuff.messages;
  for (let i = msgs.length - 1; i >= 0; i--) {
    const msg = msgs.getItem(i);
    if (msg.dialogType === "remoteCallEnded") {
      return false;
    }
    if (msg.dialogType === "remoteCallStarted") {
      return msg.messageId;
    }
  }
};
ChatRoom.prototype.stopRinging = function (callId) {
  if (this.ringingCalls.exists(callId)) {
    this.ringingCalls.remove(callId);
  }
  megaChat.plugins.callManager2.trigger("onRingingStopped", {
    callId,
    chatRoom: this
  });
};
ChatRoom.prototype.callParticipantsUpdated = function () {
  const self = this;
  let msgId = self.getActiveCallMessageId();
  if (!msgId) {
    msgId = self.getActiveCallMessageId(true);
  }
  const callParts = self.getCallParticipants() || [];
  self.uniqueCallParts = {};
  for (let i = 0; i < callParts.length; i++) {
    self.uniqueCallParts[callParts[i]] = true;
  }
  if (this.callUserLimited && this.canJoinLimitedCall()) {
    this.callUserLimited.abort();
    this.callUserLimited = false;
  }
  const msg = self.messagesBuff.getMessageById(msgId);
  msg && msg.wrappedChatDialogMessage && msg.wrappedChatDialogMessage.trackDataChange();
  self.trackDataChange();
};
ChatRoom.prototype.onPublicChatRoomInitialized = function () {
  const self = this;
  if (self.type !== "public" || !localStorage.autoJoinOnLoginChat) {
    return;
  }
  const autoLoginChatInfo = tryCatch(JSON.parse.bind(JSON))(localStorage.autoJoinOnLoginChat) || false;
  if (autoLoginChatInfo[0] === self.publicChatHandle) {
    localStorage.removeItem("autoJoinOnLoginChat");
    if (unixtime() - 7200 < autoLoginChatInfo[1]) {
      const doJoinEventually = function (state) {
        if (state === ChatRoom.STATE.READY) {
          self.joinViaPublicHandle();
          self.unbind(`onStateChange.${  self.publicChatHandle}`);
        }
      };
      self.rebind(`onStateChange.${  self.publicChatHandle}`, (e, oldState, newState) => {
        doJoinEventually(newState);
      });
      doJoinEventually(self.state);
    }
  }
};
ChatRoom.prototype.isUIMounted = function () {
  return this._uiIsMounted;
};
ChatRoom.prototype.attachSearch = function () {
  this.activeSearches++;
};
ChatRoom.prototype.detachSearch = function () {
  if (--this.activeSearches === 0) {
    this.messagesBuff.detachMessages();
  }
  this.activeSearches = Math.max(this.activeSearches, 0);
  this.trackDataChange();
};
ChatRoom.prototype.scrollToMessageId = function (msgId, index, retryActive) {
  const self = this;
  if (!self.isCurrentlyActive && !retryActive) {
    tSleep(1.5).then(() => {
      self.scrollToMessageId(msgId, index, true);
    });
    return;
  }
  assert(self.isCurrentlyActive, 'chatRoom is not visible');
  self.isScrollingToMessageId = true;
  if (!self.$rConversationPanel) {
    self.one(`onHistoryPanelComponentDidMount.scrollToMsgId${  msgId}`, () => {
      self.scrollToMessageId(msgId, index);
    });
    return;
  }
  const ps = self.$rConversationPanel.messagesListScrollable;
  assert(ps);
  const msgObj = self.messagesBuff.getMessageById(msgId);
  if (msgObj) {
    const elem = $(`.${  msgId  }.message.body`)[0];
    self.scrolledToBottom = false;
    ps.scrollToElement(elem, true);
    self.$rConversationPanel.lastScrollPosition = undefined;
    self.isScrollingToMessageId = false;
  } else if (self.messagesBuff.isRetrievingHistory) {
    self.one(`onHistoryDecrypted.scrollToMsgId${  msgId}`, () => {
      self.one(`onComponentDidUpdate.scrollToMsgId${  msgId}`, () => {
        self.scrollToMessageId(msgId, index);
      });
    });
  } else if (self.messagesBuff.haveMoreHistory()) {
    self.messagesBuff.retrieveChatHistory(!index || index <= 0 ? undefined : index);
    ps.doProgramaticScroll(0, true);
    self.one(`onHistoryDecrypted.scrollToMsgId${  msgId}`, () => {
      self.one(`onComponentDidUpdate.scrollToMsgId${  msgId}`, () => {
        self.scrollToMessageId(msgId);
      });
    });
  } else {
    self.isScrollingToMessageId = false;
  }
};
ChatRoom.prototype.setMcoFlags = function (flags) {
  const req = {
    a: 'mco',
    cid: this.chatId,
    ...flags
  };
  asyncApiReq(req).dump('roomSetCallFlags');
};
ChatRoom.prototype.toggleOpenInvite = function () {
  if (this.type === 'private' || !this.iAmOperator()) {
    return;
  }
  this.setMcoFlags({
    [MCO_FLAGS.OPEN_INVITE]: Math.abs(this.options[MCO_FLAGS.OPEN_INVITE] - 1)
  });
};
ChatRoom.prototype.toggleWaitingRoom = function () {
  if (this.type === 'private' || !this.iAmOperator()) {
    return;
  }
  this.setMcoFlags({
    [MCO_FLAGS.WAITING_ROOM]: Math.abs(this.options[MCO_FLAGS.WAITING_ROOM] - 1)
  });
};
ChatRoom.prototype.exportToFile = function () {
  if (this.messagesBuff.messages.length === 0 || this.exportIo) {
    return;
  }
  loadingDialog.show('chat_export');
  eventlog(99874);
  this._exportChat().then(() => {
    eventlog(99875, JSON.stringify([1]));
  }).catch(ex => {
    if (d) {
      console.warn('Chat export: ', ex);
    }
    const report = [String(ex && ex.message || ex).replace(/\s+/g, '').substring(0, 64)];
    report.unshift(report[0] === 'Aborted' ? 1 : 0);
    if (!report[0]) {
      msgDialog('error', '', l.export_chat_failed, '', undefined, 1);
    }
    eventlog(99875, JSON.stringify(report));
  }).finally(() => {
    loadingDialog.hide('chat_export');
    this.isScrollingToMessageId = false;
    onIdle(() => this.messagesBuff.detachMessages());
  });
};
ChatRoom.prototype._exportChat = async function () {
  this.isScrollingToMessageId = true;
  while (this.messagesBuff.haveMoreHistory()) {
    await this.messagesBuff.retrieveChatHistory(100);
  }
  await Promise.allSettled([this.messagesBuff.isDecrypting || Promise.resolve(), this.messagesBuff.$sharedFilesLoading || Promise.resolve(), this.messagesBuff.$isDecryptingSharedFiles || Promise.resolve()]);
  do {
    await this.messagesBuff.retrieveSharedFilesHistory(100);
  } while (this.messagesBuff.haveMoreSharedFiles);
  let withMedia = !!M.v.length;
  if (withMedia) {
    withMedia = await asyncMsgDialog(`*confirmation:!^${l.export_chat_media_dlg_conf}!${l.export_chat_media_dlg_rej}`, '', l.export_chat_media_dlg_title, l.export_chat_media_dlg_text);
    if (withMedia === null) {
      throw new Error('Aborted');
    }
  }
  let {
    attachNodes,
    stringNodes
  } = this.messagesBuff.getExportContent(withMedia);
  stringNodes = stringNodes.join('\n');
  const basename = M.getSafeName(this.getRoomTitle());
  const zname = l.export_chat_zip_file.replace('%s', basename);
  const bufferName = l.export_chat_text_file.replace('%s', basename);
  if (attachNodes.length) {
    const p = [];
    const n = [];
    let s = 0;
    for (const node of attachNodes) {
      s += node.s;
      if (node.ph) {
        p.push(node.ph);
      } else {
        n.push(node.h);
      }
    }
    const res = await asyncApiReq({
      a: 'qbq',
      s,
      n,
      p
    });
    if (res === 1 || res === 2) {
      const fallback = await asyncMsgDialog('confirmation', '', l.export_chat_media_obq_title, l.export_chat_media_obq_text);
      if (fallback) {
        return M.saveAs(stringNodes, bufferName);
      }
    } else if (res === 0) {
      await M.require('clientzip_js');
      const data = new TextEncoder().encode(stringNodes);
      const dl = {
        size: data.byteLength + s,
        n: bufferName,
        t: unixtime(),
        id: this.chatId,
        p: '',
        io: Object.create(null),
        writer: Object.create(null),
        offset: 0,
        zname
      };
      const io = await prepareExportIo(dl);
      const t = new Date((this.lastActivity || this.ctime) * 1000);
      let failedCount = 0;
      const src = prepareExportStreams(attachNodes, size => {
        failedCount++;
        dl.done += size;
      });
      src.unshift({
        name: bufferName,
        lastModified: t,
        input: data.buffer
      });
      dl.done = 0;
      const reader = clientZip.downloadZip(src).body.getReader();
      dl.nextChunk = async () => {
        const read = await reader.read().catch(dump);
        if (!read) {
          reader.cancel().catch(ex => {
            if (ex !== EOVERQUOTA) {
              msgDialog('error', '', l.export_chat_failed, ex < 0 ? api_strerror(ex) : ex, undefined, 1);
            }
          });
          io.abort();
          delete this.exportIo;
          loadingDialog.hideProgress();
          return;
        }
        if (read.done) {
          loadingDialog.hideProgress();
          io.download(zname);
          delete this.exportIo;
          if (failedCount) {
            msgDialog('error', '', l.export_chat_failed, l.export_chat_partial_fail, undefined, 1);
          }
        } else {
          dl.done += read.value.byteLength;
          loadingDialog.showProgress(dl.done / dl.size * 100);
          io.write(read.value, dl.offset, dl.nextChunk);
          dl.offset += read.value.length;
        }
      };
      io.begin = dl.nextChunk;
      io.setCredentials(false, dl.size, zname);
      this.exportIo = io;
    } else {
      throw new Error(`Unexpected qbq response ${res}`);
    }
  } else {
    return M.saveAs(stringNodes, bufferName);
  }
};
ChatRoom.prototype.canJoinLimitedCall = function () {
  const callParts = this.getCallParticipants();
  return this.iAmOperator() && callParts.length < CallManager2.CALL_USER_LIMIT || callParts.length < CallManager2.CALL_USER_LIMIT - 1;
};
window.ChatRoom = ChatRoom;
const chatRoom = {
  ChatRoom
};

},

594:
(module) => {

"use strict";
module.exports = React;

},

623:
() => {

(function () {
  const ChatGlobalEventManager = function () {};
  lazy(ChatGlobalEventManager.prototype, 'listeners', function () {
    window.addEventListener('hashchange', ev => this.triggered(ev));
    $(window).rebind('resize.chatGlobalEventManager', ev => this.triggered(ev));
    const listeners = Object.create(null);
    listeners.resize = Object.create(null);
    listeners.hashchange = Object.create(null);
    return listeners;
  });
  ChatGlobalEventManager.prototype.addEventListener = function (eventName, namespace, cb) {
    this.listeners[eventName][namespace] = this.listeners[namespace] || cb;
  };
  ChatGlobalEventManager.prototype.removeEventListener = function (eventName, namespace) {
    delete this.listeners[eventName][namespace];
  };
  ChatGlobalEventManager.prototype.triggered = SoonFc(140, function _chatEVDispatcher(ev) {
    if (M.chat) {
      const listeners = this.listeners[ev.type];
      for (const k in listeners) {
        listeners[k](ev);
      }
    }
  });
  window.chatGlobalEventManager = new ChatGlobalEventManager();
})();

},

691:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  nC: () => API,
  kg: () => LABELS,
  Ay: () => GifPanel
});

// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
const perfectScrollbar = REQ_(486);
;// ./js/chat/ui/gifPanel/searchField.jsx
let _SearchField;


class SearchField extends REaCt().Component {
  render() {
    const {
      value,
      searching,
      onChange,
      onReset,
      onBack
    } = this.props;
    return REaCt().createElement("div", {
      className: "gif-panel-search"
    }, REaCt().createElement("div", {
      className: "gif-search-field"
    }, searching ? REaCt().createElement("i", {
      className: "sprite-fm-mono icon-left",
      onClick: onBack
    }) : REaCt().createElement("i", {
      className: "sprite-fm-mono icon-preview-reveal"
    }), REaCt().createElement("input", {
      ref: SearchField.inputRef,
      type: "text",
      placeholder: LABELS.SEARCH,
      autoFocus: true,
      value,
      onChange
    }), searching && REaCt().createElement("i", {
      className: "sprite-fm-mono icon-close-component",
      onClick: onReset
    })), REaCt().createElement("div", {
      className: "giphy-logo"
    }, REaCt().createElement("img", {
      src: `${staticpath  }images/mega/giphy.gif`,
      alt: "PWRD BY GIPHY"
    })));
  }
}
_SearchField = SearchField;
SearchField.inputRef = REaCt().createRef();
SearchField.focus = () => _SearchField.inputRef && _SearchField.inputRef.current && _SearchField.inputRef.current.focus();
SearchField.hasValue = () => _SearchField.inputRef && _SearchField.inputRef.current && !!_SearchField.inputRef.current.value.length;
;// ./js/chat/ui/gifPanel/result.jsx


class Result extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.resultRef = REaCt().createRef();
  }
  componentDidMount() {
    let _this$props$onMount, _this$props;
    (_this$props$onMount = (_this$props = this.props).onMount) == null || _this$props$onMount.call(_this$props, this.resultRef.current);
  }
  componentWillUnmount() {
    let _this$props$onUnmount, _this$props2;
    (_this$props$onUnmount = (_this$props2 = this.props).onUnmount) == null || _this$props$onUnmount.call(_this$props2, this.resultRef.current, 'unobserve');
  }
  render() {
    const {
      image,
      title,
      onClick
    } = this.props;
    return REaCt().createElement("div", {
      className: `
                    ${NODE_CONTAINER_CLASS}
                    ${onClick ? 'clickable' : ''}
                `,
      style: {
        height: parseInt(image.height)
      }
    }, REaCt().createElement("div", {
      ref: this.resultRef,
      className: NODE_CLASS,
      style: {
        backgroundImage: HAS_INTERSECTION_OBSERVER ? '' : `url(${image.url})`
      },
      "data-url": image.url,
      onClick
    }, REaCt().createElement("span", null, title)));
  }
}
;// ./js/chat/ui/gifPanel/resultContainer.jsx



const HAS_INTERSECTION_OBSERVER = typeof IntersectionObserver !== 'undefined';
const NODE_CONTAINER_CLASS = 'node-container';
const NODE_CLASS = 'node';
const RESULT_CONTAINER_CLASS = 'gif-panel-results';
const RESULTS_END_CLASS = 'results-end';
const Nil = ({
  children
}) => REaCt().createElement("div", {
  className: "no-results-container"
}, REaCt().createElement("div", {
  className: "no-results-content"
}, REaCt().createElement("i", {
  className: "huge-icon sad-smile"
}), REaCt().createElement("span", null, children)));
class ResultContainer extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.intersectionObserver = null;
    this.initializeIntersectionObserver = () => {
      if (HAS_INTERSECTION_OBSERVER) {
        this.intersectionObserver = new IntersectionObserver(entries => {
          for (let i = 0; i < entries.length; i++) {
            var _target$classList, _target$classList2;
            const entry = entries[i];
            const {target} = entry;
            if ((_target$classList = target.classList) != null && _target$classList.contains(NODE_CLASS)) {
              target.style.backgroundImage = entry.isIntersecting ? `url(${target.dataset.url})` : null;
            }
            if (entry.isIntersecting && (_target$classList2 = target.classList) != null && _target$classList2.contains(RESULTS_END_CLASS)) {
              this.props.onPaginate();
            }
          }
        });
      }
    };
    this.toggleIntersectionObserver = (node, action = 'observe') => {
      if (node && this.intersectionObserver) {
        this.intersectionObserver[action](node);
      }
    };
  }
  componentDidMount() {
    this.initializeIntersectionObserver();
  }
  componentWillUnmount() {
    if (this.intersectionObserver) {
      this.intersectionObserver.disconnect();
      this.intersectionObserver = null;
    }
  }
  render() {
    const {
      loading,
      results,
      bottom,
      unavailable,
      onClick
    } = this.props;
    if (unavailable) {
      return REaCt().createElement(Nil, null, LABELS.NOT_AVAILABLE);
    }
    if (loading && results.length < 1) {
      return REaCt().createElement("div", {
        className: RESULT_CONTAINER_CLASS
      }, Array.from({
        length: API.LIMIT
      }, (element, index) => REaCt().createElement("div", {
        key: index,
        className: NODE_CONTAINER_CLASS
      }, REaCt().createElement("div", {
        className: NODE_CLASS,
        style: {
          height: Math.floor(Math.random() * 150) + 100
        }
      }))));
    }
    if (!loading && results.length < 1) {
      return REaCt().createElement(Nil, null, LABELS.NO_RESULTS);
    }
    if (results.length) {
      return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
        className: RESULT_CONTAINER_CLASS
      }, results.map(({
        slug,
        images: {
          fixed_width_downsampled
        },
        title
      }, index) => {
        return REaCt().createElement(Result, {
          key: `${slug}--${index}`,
          image: fixed_width_downsampled,
          title,
          onClick: () => onClick(results[index]),
          onMount: this.toggleIntersectionObserver,
          onUnmount: this.toggleIntersectionObserver
        });
      })), REaCt().createElement("div", {
        className: RESULTS_END_CLASS,
        ref: node => this.toggleIntersectionObserver(node),
        style: {
          visibility: bottom ? 'visible' : 'hidden'
        }
      }, REaCt().createElement("img", {
        className: "emoji",
        alt: "\\ud83d\\ude10",
        src: `${staticpath}/images/mega/twemojis/2_v2/72x72/1f610.png`
      }), REaCt().createElement("strong", null, LABELS.END_OF_RESULTS)));
    }
    return null;
  }
}
;// ./js/chat/ui/gifPanel/gifPanel.jsx




const GIF_PANEL_CLASS = 'gif-panel-wrapper';
const MAX_HEIGHT = 550;
const API = {
  HOSTNAME: 'https://giphy.mega.nz/',
  ENDPOINT: 'v1/gifs',
  SCHEME: 'giphy://',
  convert: path => {
    if (path && typeof path === 'string') {
      const FORMAT = [API.SCHEME, API.HOSTNAME];
      if (path.indexOf(API.SCHEME) === 0 || path.indexOf(API.HOSTNAME) === 0) {
        return String.prototype.replace.apply(path, path.indexOf(API.SCHEME) === 0 ? FORMAT : FORMAT.reverse());
      }
    }
  },
  LIMIT: 50,
  OFFSET: 50
};
const LABELS = freeze({
  get SEARCH() {
    return l[24025];
  },
  get NO_RESULTS() {
    return l[24050];
  },
  get NOT_AVAILABLE() {
    return l[24512];
  },
  get END_OF_RESULTS() {
    return l[24156];
  }
});
class GifPanel extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.pathRef = '';
    this.controllerRef = null;
    this.fetchRef = null;
    this.delayProcID = null;
    this.defaultState = {
      value: '',
      searching: false,
      results: [],
      loading: true,
      offset: 0,
      bottom: false,
      unavailable: false
    };
    this.state = {
      ...this.defaultState
    };
    this.getContainerHeight = () => window.innerHeight * 0.6 > MAX_HEIGHT ? MAX_HEIGHT : window.innerHeight * 0.6;
    this.getFormattedPath = path => {
      const PATH = path + (path.indexOf('?') === -1 ? '?' : '&');
      const LIMIT = `limit=${API.LIMIT}`;
      return `${API.HOSTNAME + API.ENDPOINT}/${PATH + LIMIT}`;
    };
    this.clickedOutsideComponent = ev => {
      const $target = ev && $(ev.target);
      return $target.parents(`.${GIF_PANEL_CLASS}`).length === 0 && ['.small-icon.tiny-reset', '.small-icon.gif'].every(outsideElement => !$target.is(outsideElement));
    };
    this.bindEvents = () => {
      $(document).rebind('mousedown.gifPanel', ev => {
        if (this.clickedOutsideComponent(ev)) {
          this.props.onToggle();
        }
      }).rebind('keydown.gifPanel', ({
        keyCode
      }) => {
        if (keyCode && keyCode === 27) {
          return SearchField.hasValue() ? this.doReset() : this.props.onToggle();
        }
      });
    };
    this.unbindEvents = () => {
      if (this.delayProcID) {
        delay.cancel(this.delayProcID);
      }
      $(document).unbind('.gifPanel');
    };
    this.doFetch = path => {
      this.setState({
        loading: true,
        unavailable: false
      }, () => {
        this.pathRef = path;
        this.controllerRef = typeof AbortController === 'function' && new AbortController();
        this.fetchRef = fetch(this.getFormattedPath(path), {
          signal: this.controllerRef.signal
        }).then(response => response.json()).then(({
          data
        }) => {
          this.fetchRef = this.pathRef = null;
          if (this.domRef.current) {
            if (data && data.length) {
              return this.setState(state => ({
                results: [...state.results, ...data],
                loading: false
              }));
            }
            return this.setState({
              bottom: true,
              loading: false
            }, () => this.resultContainerRef && this.resultContainerRef.reinitialise());
          }
        }).catch(ex => {
          return ex.name === 'AbortError' ? null : this.setState({
            unavailable: true
          });
        });
      });
    };
    this.doPaginate = () => {
      const {
        value,
        loading,
        searching
      } = this.state;
      if (!loading) {
        this.setState(state => ({
          offset: state.offset + API.OFFSET
        }), () => {
          this.doFetch(searching ? `search?q=${escape(value)}&offset=${this.state.offset}` : `trending?offset=${this.state.offset}`);
        });
      }
    };
    this.doReset = () => {
      this.setState({
        ...this.defaultState
      }, () => {
        this.doFetch('trending');
        onIdle(() => SearchField.focus());
        this.resultContainerRef.scrollToY(0);
      });
    };
    this.handleChange = ev => {
      const {
        value
      } = ev.target;
      const searching = value.length >= 2;
      if (value.length === 0) {
        return this.doReset();
      }
      if (this.fetchRef !== null && this.pathRef === 'trending' && this.controllerRef) {
        this.controllerRef.abort();
        this.fetchRef = this.pathRef = null;
      }
      this.setState(state => ({
        ...this.defaultState,
        value,
        searching,
        results: searching ? [] : state.results
      }), () => {
        this.resultContainerRef.scrollToY(0);
        this.delayProcID = searching ? delay('gif-search', () => this.doFetch(`search?q=${escape(value)}`), 1600) : null;
      });
    };
    this.handleBack = () => this.doReset();
    this.doSend = result => {
      const {
        mp4,
        webp,
        mp4_size,
        webp_size,
        width,
        height
      } = result.images.fixed_height;
      const message = Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT + Message.MANAGEMENT_MESSAGE_TYPES.CONTAINS_META + Message.MESSAGE_META_TYPE.GIPHY + JSON.stringify({
        textMessage: result.title,
        src: API.convert(mp4),
        src_webp: API.convert(webp),
        s: mp4_size,
        s_webp: webp_size,
        w: width,
        h: height
      });
      this.props.chatRoom.sendMessage(message);
      this.props.onToggle();
    };
  }
  componentDidMount() {
    if (this.state.results && this.state.results.length === 0) {
      this.doFetch('trending');
    }
    this.bindEvents();
  }
  componentWillUnmount() {
    this.unbindEvents();
  }
  render() {
    const {
      value,
      searching,
      results,
      loading,
      bottom,
      unavailable
    } = this.state;
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "gif-panel-wrapper"
    }, REaCt().createElement("div", {
      className: "gif-panel",
      style: {
        height: this.getContainerHeight()
      }
    }, REaCt().createElement("div", {
      className: "gif-panel-header"
    }, REaCt().createElement(SearchField, {
      value,
      searching,
      onChange: this.handleChange,
      onReset: this.doReset,
      onBack: this.handleBack
    })), REaCt().createElement("div", {
      className: "gif-panel-content"
    }, REaCt().createElement(perfectScrollbar.O, {
      ref: container => {
        this.resultContainerRef = container;
      },
      options: {
        'suppressScrollX': true
      }
    }, REaCt().createElement(ResultContainer, {
      results,
      loading,
      bottom,
      unavailable,
      onPaginate: this.doPaginate,
      onClick: this.doSend
    })))));
  }
}

},

701:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  A: () => FMView
});

// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
const esm_extends = REQ_(168);
// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
const applyDecoratedDescriptor = REQ_(793);
// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
const perfectScrollbar = REQ_(486);
;// ./js/ui/jsx/megaList/megaList2.jsx


let _dec, _class;



const MegaList2 = (_dec = (0,mixins.hG)(30, true), _class = class MegaList2 extends mixins.w9 {
  constructor(props) {
    super(props);
    this._calculated = false;
    this._firstRender = true;
    this.customIsEventuallyVisible = true;
    this.requiresUpdateOnResize = true;
    this.adapterChangedDoRepaint = false;
    assert(props.listAdapter, 'missing `listAdapter` for MegaList2');
    assert(props.nodeAdapter, 'missing `nodeAdapter` for MegaList2');
    assert(props.entries, 'missing `entries` for MegaList2');
    this.options = {
      extraRows: 8,
      batchPages: 0,
      perfectScrollOptions: {
        'handlers': ['click-rail', 'drag-thumb', 'wheel', 'touch'],
        'minScrollbarLength': 20
      }
    };
    this.onPsUserScroll = this.onPsUserScroll.bind(this);
    this.thumbsLoadingHandlers = new MapSet();
    this.thumbsThatRequireLoading = new MapSet();
    this.requestThumbnailCb = this.requestThumbnailCb.bind(this);
  }
  specShouldComponentUpdate(nextProps) {
    let invalidate = false;
    if (nextProps.listAdapter.prototype.constructor.name !== this.props.listAdapter.prototype.constructor.name || nextProps.entries !== this.props.entries || nextProps.viewMode !== this.props.viewMode) {
      invalidate = true;
    }
    if (nextProps.sortBy !== this.props.sortBy || nextProps.currentlyViewedEntry !== this.props.currentlyViewedEntry) {
      invalidate = true;
      this.domRef.scrollToY(0);
    }
    if (invalidate) {
      this._calculated = false;
      this.adapterChangedDoRepaint = true;
      return true;
    }
    return null;
  }
  _recalculate() {
    if (this._calculated) {
      return this._calculated;
    }
    const calculated = this._calculated = Object.create(null);
    lazy(calculated, 'scrollWidth', () => {
      return this.domRef.getClientWidth();
    });
    lazy(calculated, 'scrollHeight', () => this.domRef.getClientHeight() - calculated.headerHeight);
    lazy(calculated, 'itemWidth', () => {
      if (this.props.listAdapter.itemWidth === false) {
        return calculated.scrollWidth;
      }
      return this.props.listAdapter.itemWidth;
    });
    lazy(calculated, 'itemHeight', () => {
      return this.props.itemHeight || this.props.listAdapter.itemHeight;
    });
    lazy(calculated, 'headerHeight', () => this.props.headerHeight || 0);
    lazy(calculated, 'contentWidth', () => {
      const contentWidth = this.domRef.getContentWidth();
      if (contentWidth) {
        return contentWidth;
      }
      return calculated.itemWidth;
    });
    lazy(calculated, 'itemsPerRow', () => {
      if (this.props.listAdapter.itemsPerRow) {
        return this.props.listAdapter.itemsPerRow;
      }
      return Math.max(1, Math.floor(calculated.contentWidth / calculated.itemWidth));
    });
    lazy(calculated, 'contentHeight', () => {
      return Math.ceil(this.props.entries.length / calculated.itemsPerRow) * calculated.itemHeight;
    });
    lazy(calculated, 'scrollLeft', () => {
      return this.domRef.getScrollPositionX();
    });
    lazy(calculated, 'scrollTop', () => {
      if (this.adapterChangedDoRepaint) {
        return 0;
      }
      return this.domRef.getScrollPositionY();
    });
    lazy(calculated, 'scrolledPercentX', () => {
      return 100 / calculated.scrollWidth * calculated.scrollLeft;
    });
    lazy(calculated, 'scrolledPercentY', () => {
      return 100 / calculated.scrollHeight * calculated.scrollTop;
    });
    lazy(calculated, 'isAtTop', () => {
      return calculated.scrollTop === 0;
    });
    lazy(calculated, 'isAtBottom', () => {
      return calculated.scrollTop === calculated.scrollHeight;
    });
    lazy(calculated, 'itemsPerPage', () => {
      return Math.ceil(calculated.scrollHeight / calculated.itemHeight) * calculated.itemsPerRow;
    });
    lazy(calculated, 'visibleFirstItemNum', () => {
      let value = 0;
      value = Math.floor(Math.floor(calculated.scrollTop / calculated.itemHeight) * calculated.itemsPerRow);
      if (value > 0) {
        value = Math.max(0, value - this.options.extraRows * calculated.itemsPerRow);
      }
      return value;
    });
    lazy(calculated, 'visibleLastItemNum', () => {
      let value = Math.min(this.props.entries.length, Math.ceil(Math.ceil(calculated.scrollTop / calculated.itemHeight) * calculated.itemsPerRow + calculated.itemsPerPage));
      if (value < this.props.entries.length) {
        value = Math.min(this.props.entries.length, value + this.options.extraRows * calculated.itemsPerRow);
      }
      return value;
    });
    if (this.options.batchPages > 0) {
      const perPage = calculated.itemsPerPage;
      const visibleF = calculated.visibleFirstItemNum;
      calculated.visibleFirstItemNum = Math.max(0, ((visibleF - visibleF % perPage) / perPage - 1 - this.options.batchPages) * perPage);
      const visibleL = calculated.visibleLastItemNum;
      calculated.visibleLastItemNum = Math.min(this.props.entries.length, ((visibleL - visibleL % perPage) / perPage + 1 + this.options.batchPages) * perPage);
    }
    Object.defineProperty(M, 'rmItemsInView', {
      get: () => {
        const c = this.domRef && this._calculated || !1;
        return c.itemsPerPage + c.itemsPerRow | 0;
      },
      configurable: true
    });
  }
  _contentUpdated() {
    this._calculated = false;
    this._recalculate();
    if (this.listContent && this._lastContentHeight !== this._calculated.contentHeight) {
      this._lastContentHeight = this._calculated.contentHeight;
      this.listContent.style.height = `${this._calculated.contentHeight  }px`;
    }
    if (this.domRef && this._calculated.scrollHeight + this._calculated.scrollTop > this._calculated.contentHeight) {
      this.domRef.scrollToY(this._calculated.contentHeight - this._calculated.scrollHeight);
    }
    if (this.listAdapterInstance && this.listAdapterInstance.onContentUpdated) {
      this.listAdapterInstance.onContentUpdated();
    }
  }
  _getCalcsThatTriggerChange() {
    return [this.props.entries.length, this._calculated.scrollHeight, this._calculated.itemWidth, this._calculated.itemHeight, this._calculated.contentWidth, this._calculated.itemsPerRow, this._calculated.contentHeight, this._calculated.visibleFirstItemNum, this._calculated.visibleLastItemNum];
  }
  indexOfEntry(nodeHandle, prop) {
    prop = prop || 'h';
    for (let i = 0; i < this.props.entries.length; i++) {
      const entry = this.props.entries[i];
      if (entry[prop] === nodeHandle) {
        return i;
      }
    }
    return -1;
  }
  scrollToItem(nodeHandle) {
    const elementIndex = this.indexOfEntry(nodeHandle);
    if (elementIndex === -1) {
      return false;
    }
    let shouldScroll = false;
    const itemOffsetTop = Math.floor(elementIndex / this._calculated.itemsPerRow) * this._calculated.itemHeight;
    const itemOffsetTopPlusHeight = itemOffsetTop + this._calculated.itemHeight;
    if (itemOffsetTop < this._calculated.scrollTop || itemOffsetTopPlusHeight > this._calculated.scrollTop + this._calculated.scrollHeight) {
      shouldScroll = true;
    }
    if (shouldScroll) {
      this.domRef.scrollToY(itemOffsetTop);
      onIdle(() => {
        this.safeForceUpdate();
      });
      return true;
    }
    return false;
  }
  onPsUserScroll() {
    if (!this.isMounted()) {
      return;
    }
    const oldCalc = JSON.stringify(this._getCalcsThatTriggerChange());
    this._contentUpdated();
    const newCalc = JSON.stringify(this._getCalcsThatTriggerChange());
    if (oldCalc !== newCalc) {
      this.forceUpdate();
    }
  }
  onResizeDoUpdate() {
    super.onResizeDoUpdate();
    this._contentUpdated();
  }
  componentDidMount() {
    super.componentDidMount();
    this._contentUpdated();
    this.forceUpdate();
  }
  componentDidUpdate() {
    super.componentDidUpdate();
    this._contentUpdated();
    if (this.adapterChangedDoRepaint) {
      this.adapterChangedDoRepaint = false;
      this._calculated = false;
      this._recalculate();
    }
    if (this.thumbsThatRequireLoading.size) {
      delay('chat:mega-list2:thumb-loader', () => this.enqueueThumbnailRetrieval(), 20);
    }
    this._firstRender = this._firstRender || this.props.viewmode !== M.viewmode;
    if (this._firstRender && this.domRef) {
      let _this$domRef;
      this._firstRender = false;
      Ps.update((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.$Node);
    }
  }
  enqueueThumbnailRetrieval() {
    const loaders = new Map(this.thumbsLoadingHandlers);
    const nodes = new Map(this.thumbsThatRequireLoading);
    const pending = [];
    const defaultCallback = (n, src, id) => {
      let img = document.getElementById(id || `chat_${n.h}`);
      if (img && (img = img.querySelector('img'))) {
        let _img$parentNode$paren;
        img.src = src;
        (_img$parentNode$paren = img.parentNode.parentNode) == null || _img$parentNode$paren.classList.add('thumb');
      }
    };
    const setSource = n => {
      if (thumbnails.has(n.fa)) {
        const src = thumbnails.get(n.fa);
        const batch = [...nodes.get(n.fa)];
        for (let i = batch.length; i--;) {
          const n = batch[i];
          const handlers = [...loaders.get(n.h)];
          for (let i = handlers.length; i--;) {
            let callback = handlers[i];
            if (typeof callback !== 'function') {
              callback = defaultCallback;
            }
            tryCatch(() => {
              const id = callback(n, src);
              if (id) {
                defaultCallback(n, src, id);
              }
            })();
          }
        }
        return true;
      }
    };
    for (const [, [n]] of nodes) {
      if (!setSource(n)) {
        pending.push(n);
      }
    }
    if (pending.length) {
      fm_thumbnails('standalone', pending, setSource);
    }
    this.thumbsLoadingHandlers.clear();
    this.thumbsThatRequireLoading.clear();
  }
  requestThumbnailCb(node, immediate, callback) {
    if (node && node.fa) {
      if (typeof immediate === 'function') {
        callback = immediate;
        immediate = 0;
      }
      node.seen = node.seen || -7;
      this.thumbsLoadingHandlers.set(node.h, callback);
      this.thumbsThatRequireLoading.set(node.fa, node);
      delay('chat:mega-list2:thumb-loader', () => this.enqueueThumbnailRetrieval(), immediate || 480);
    }
  }
  render() {
    if (this.isMounted() && !this._calculated) {
      this._recalculate();
    }
    const {
      listAdapter,
      listAdapterOpts,
      entries,
      nodeAdapterProps,
      viewMode,
      header,
      onContextMenu
    } = this.props;
    const className = `${listAdapter.containerClassName  } megaList megaList2`;
    const first = this._calculated.visibleFirstItemNum;
    const last = this._calculated.visibleLastItemNum;
    const nodes = [];
    for (let i = first; i < last; i++) {
      const node = entries[i];
      nodes.push(REaCt().createElement(this.props.nodeAdapter, (0,esm_extends.A)({
        key: `${i  }_${  node[this.props.keyProp]}`,
        h: node[this.props.keyProp],
        index: i,
        megaList: this,
        listAdapter,
        node,
        calculated: this._calculated,
        listAdapterOpts,
        onContextMenu,
        selected: this.props.selected ? this.props.selected.indexOf(node[this.props.keyProp]) > -1 : false,
        highlighted: this.props.highlighted ? this.props.highlighted.indexOf(node[this.props.keyProp]) > -1 : false,
        requestThumbnailCb: this.requestThumbnailCb,
        keyProp: this.props.keyProp || 'h'
      }, nodeAdapterProps)));
    }
    const listAdapterName = listAdapter.prototype.constructor.name;
    return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(perfectScrollbar.O, {
      key: `ps_${  listAdapterName  }_${  viewMode}`,
      options: this.options.perfectScrollOptions,
      onUserScroll: this.onPsUserScroll,
      className,
      style: {
        'position': 'relative'
      },
      ref: instance => {
        this.domRef = instance;
      }
    }, REaCt().createElement(this.props.listAdapter, (0,esm_extends.A)({
      containerClassName: this.props.containerClassName,
      key: `ps_${  listAdapterName  }_${  this.props.viewMode  }_la`,
      ref: listAdapterInstance => {
        this.listAdapterInstance = listAdapterInstance;
      },
      listContentRef: listContent => {
        this.listContent = listContent;
      },
      header,
      megaList: this,
      calculated: this._calculated
    }, listAdapterOpts), nodes)));
  }
}, (0,applyDecoratedDescriptor.A)(_class.prototype, "onPsUserScroll", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "onPsUserScroll"), _class.prototype), _class);
// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/genericNodePropsComponent.jsx + 1 modules
const genericNodePropsComponent = REQ_(984);
;// ./js/ui/jsx/fm/nodes/genericGrid.jsx


class GenericGrid extends genericNodePropsComponent.B {
  render() {
    const {
      node,
      calculated,
      index,
      listAdapter,
      className,
      keyProp
    } = this.props;
    const style = {};
    listAdapter.repositionItem(node, calculated, index, style);
    const toApplySensitive = !!mega.sensitives.isSensitive(node) && (mega.sensitives.showGlobally ? 1 : 2);
    let image = null;
    let src = null;
    let isThumbClass = "";
    if (node.fa && (is_image2(node) || is_video(node))) {
      src = thumbnails.get(node.fa);
      if (!src) {
        this.props.requestThumbnailCb(node);
        src = window.noThumbURI || '';
      }
      image = src ? REaCt().createElement("img", {
        alt: "",
        src
      }) : REaCt().createElement("img", {
        alt: ""
      });
      isThumbClass = " thumb";
    } else {
      image = REaCt().createElement("img", null);
    }
    let fileStatusClass = "";
    if (node.fav) {
      fileStatusClass += " icon-favourite-filled";
    }
    return REaCt().createElement("a", {
      className: `data-block-view megaListItem ui-droppable ui-draggable ui-draggable-handle ${  this.nodeProps.classNames.join(" ")  }${className && className(node) || ""  }${toApplySensitive ? toApplySensitive === 1 ? ' is-sensitive' : ' hidden-as-sensitive' : ''}`,
      id: `chat_${  node[keyProp]}`,
      onClick: e => {
        this.props.onClick(e, this.props.node);
      },
      onDoubleClick: e => {
        this.props.onDoubleClick(e, this.props.node);
      },
      title: this.nodeProps.title,
      style
    }, REaCt().createElement("span", {
      className: `data-block-bg ${  isThumbClass}`
    }, REaCt().createElement("span", {
      className: "data-block-indicators"
    }, REaCt().createElement("span", {
      className: `file-status-icon indicator sprite-fm-mono${  fileStatusClass}`
    }), REaCt().createElement("span", {
      className: "versioning-indicator"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-versions-previous"
    })), REaCt().createElement("i", {
      className: "sprite-fm-mono icon-link"
    })), REaCt().createElement("span", {
      className: `item-type-icon-90 icon-${  this.nodeProps.icon  }-90`
    }, image), REaCt().createElement("div", {
      className: "video-thumb-details"
    }, REaCt().createElement("i", {
      className: "small-icon small-play-icon"
    }), REaCt().createElement("span", null, "00:00"))), REaCt().createElement("span", {
      className: "file-block-title"
    }, this.nodeProps.title));
  }
}
;// ./js/ui/jsx/fm/nodes/genericTable.jsx



class GenericTableHeader extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
  }
  render() {
    const {
      sortBy,
      columns
    } = this.props;
    const columnsRendered = [];
    for (let i = 0; i < columns.length; i++) {
      var _colProps;
      let col = columns[i];
      let colProps;
      if (Array.isArray(col)) {
        colProps = col[1];
        col = col[0];
      }
      let sortable;
      if (col.sortable) {
        let classes = "";
        if (sortBy[0] === col.id) {
          const ordClass = sortBy[1] === "desc" ? "icon-arrow-down" : "icon-arrow-up";
          classes = `${classes} ${ordClass}`;
        }
        if (col.id === 'fav') {
          classes += ' hidden';
        }
        sortable = REaCt().createElement("i", {
          className: `sprite-fm-mono ${col.id} ${classes}`
        });
      }
      columnsRendered.push(REaCt().createElement("th", {
        megatype: col.megatype,
        className: col.headerClassName || col.megatype || "",
        key: `${col.id  }_${  i}`,
        onClick: e => {
          e.preventDefault();
          if (col.sortable) {
            this.props.onClick(col.id);
          }
        }
      }, REaCt().createElement("span", null, ((_colProps = colProps) == null ? void 0 : _colProps.label) || col.label), col.icon && REaCt().createElement("i", {
        className: `sprite-fm-mono ${  col.icon}`
      }), sortable));
    }
    return REaCt().createElement("thead", {
      ref: this.domRef
    }, REaCt().createElement("tr", null, columnsRendered));
  }
}
class GenericTable extends genericNodePropsComponent.B {
  render() {
    let _this$nodeProps;
    const {
      node,
      index,
      listAdapterOpts,
      className,
      keyProp
    } = this.props;
    const toApplySensitive = !!mega.sensitives.isSensitive(node) && (mega.sensitives.showGlobally ? 1 : 2);
    const columns = [];
    for (let i = 0; i < listAdapterOpts.columns.length; i++) {
      const customColumn = listAdapterOpts.columns[i];
      if (Array.isArray(customColumn)) {
        columns.push(REaCt().createElement(customColumn[0], {
          ...customColumn[1],
          'nodeAdapter': this,
          'h': node[keyProp],
          node,
          'key': `${i  }_${  customColumn[0].prototype.constructor.name}`,
          keyProp
        }));
      } else {
        columns.push(REaCt().createElement(customColumn, {
          'nodeAdapter': this,
          'h': node[keyProp],
          node,
          'key': `${i  }_${  customColumn.prototype.constructor.name}`,
          keyProp
        }));
      }
    }
    const listClassName = listAdapterOpts.className;
    return REaCt().createElement("tr", {
      className: `node_${  node[keyProp]  } ${  className && className(node) || ""  } ${  listClassName && listClassName(node) || ""  } ${  (_this$nodeProps = this.nodeProps) == null ? void 0 : _this$nodeProps.classNames.join(" ")  }${toApplySensitive ? toApplySensitive === 1 ? ' is-sensitive' : ' hidden-as-sensitive' : ''}`,
      id: node[keyProp],
      onContextMenu: ev => {
        if (this.props.onContextMenu) {
          this.props.onContextMenu(ev, node[keyProp]);
        }
      },
      onClick: e => {
        this.props.onClick(e, this.props.node);
      },
      onDoubleClick: e => {
        this.props.onDoubleClick(e, this.props.node);
      },
      key: `${index  }_${  node[keyProp]}`
    }, columns);
  }
}
;// ./js/ui/jsx/megaList/adapters.jsx


class GenericListAdapter extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.customIsEventuallyVisible = true;
  }
}
class Grid extends GenericListAdapter {
  static repositionItem(node, calculated, index, style) {
    style.position = "absolute";
    style.top = calculated.itemHeight * Math.floor(index / calculated.itemsPerRow);
    if (calculated.itemsPerRow > 1) {
      style.left = index % calculated.itemsPerRow * calculated.itemWidth;
    }
  }
  render() {
    return REaCt().createElement("div", {
      className: "megaList-content",
      ref: this.props.listContentRef,
      style: {
        'position': 'relative'
      }
    }, this.props.children);
  }
}
Grid.itemWidth = 212;
Grid.itemHeight = 212;
Grid.containerClassName = "file-block-scrolling megaListContainer";
class Table extends GenericListAdapter {
  onContentUpdated() {
    const {
      calculated
    } = this.props;
    const pusherHeight = calculated.visibleFirstItemNum * calculated.itemHeight | 0;
    if (this.topPusher) {
      this.topPusher.style.height = `${pusherHeight  }px`;
    }
    if (this.bottomPusher) {
      this.bottomPusher.style.height = `${calculated.contentHeight - pusherHeight - (calculated.visibleLastItemNum - calculated.visibleFirstItemNum) * calculated.itemHeight | 0  }px`;
    }
  }
  componentDidUpdate() {
    super.componentDidUpdate();
    this.onContentUpdated();
  }
  render() {
    return REaCt().createElement("table", {
      width: "100%",
      className: this.props.containerClassName || "grid-table table-hover fm-dialog-table"
    }, this.props.header, REaCt().createElement("tbody", {
      ref: this.props.listContentRef
    }, REaCt().createElement("tr", {
      className: "megalist-pusher top",
      ref: r => {
        this.topPusher = r;
      }
    }), this.props.children, REaCt().createElement("tr", {
      className: "megalist-pusher bottom",
      ref: r => {
        this.bottomPusher = r;
      }
    })));
  }
}
Table.itemHeight = 32;
Table.itemsPerRow = 1;
Table.containerClassName = "grid-scrolling-table megaListContainer";
// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/columns/columnFavIcon.jsx
const columnFavIcon = REQ_(161);
;// ./js/ui/tooltips.jsx
const React = REQ_(594);

class Handler extends React.Component {
  render() {
    const {
      className,
      onMouseOver,
      onMouseOut,
      children
    } = this.props;
    return React.createElement("span", {
      className: `
                    tooltip-handler
                    ${className || ''}
                `,
      onMouseOver,
      onMouseOut
    }, children);
  }
}
class Contents extends React.Component {
  render() {
    let className = `tooltip-contents dropdown body tooltip ${  this.props.className ? this.props.className : ""}`;
    if (this.props.active) {
      className += " visible";
      return React.createElement("div", {
        className
      }, this.props.withArrow ? React.createElement("i", {
        className: "dropdown-white-arrow"
      }) : null, this.props.children);
    } else {
      return null;
    }
  }
}
class Tooltip extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = React.createRef();
    this.state = {
      'active': false
    };
  }
  componentDidUpdate(oldProps, oldState) {
    const self = this;
    if (oldState.active === true && this.state.active === false) {
      chatGlobalEventManager.removeEventListener('resize', `tooltip${  this.getUniqueId()}`);
    }
    if (self.state.active === true) {
      self.repositionTooltip();
      chatGlobalEventManager.addEventListener('resize', `tooltip${  this.getUniqueId()}`, () => {
        self.repositionTooltip();
      });
      if (this.props.onShown) {
        this.props.onShown();
      }
    }
  }
  repositionTooltip() {
    let _this$domRef;
    let elLeftPos, elTopPos, elWidth, elHeight;
    let tooltipLeftPos, tooltipTopPos, tooltipWidth, tooltipHeight;
    let docHeight;
    let arrowClass;
    if (!this.isMounted()) {
      return;
    }
    const $container = $((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
    const $el = $('.tooltip-handler', $container);
    const $tooltip = $('.tooltip-contents', $container);
    let {tooltipOffset} = this.props;
    const arrow = this.props.withArrow;
    if ($el && $tooltip) {
      elWidth = $el.outerWidth();
      elHeight = $el.outerHeight();
      elLeftPos = $el.offset().left;
      elTopPos = $el.offset().top;
      tooltipWidth = $tooltip.outerWidth();
      tooltipHeight = $tooltip.outerHeight();
      docHeight = $(window).height();
      $tooltip.removeClass('dropdown-arrow left-arrow right-arrow up-arrow down-arrow').removeAttr('style');
      if (!tooltipOffset) {
        tooltipOffset = 7;
      }
      if (elTopPos - tooltipHeight - tooltipOffset > 10) {
        tooltipLeftPos = elLeftPos + elWidth / 2 - tooltipWidth / 2;
        tooltipTopPos = elTopPos - tooltipHeight - tooltipOffset;
        arrowClass = arrow ? 'dropdown-arrow down-arrow' : '';
      } else if (docHeight - (elTopPos + elHeight + tooltipHeight + tooltipOffset) > 10) {
        tooltipLeftPos = elLeftPos + elWidth / 2 - tooltipWidth / 2;
        tooltipTopPos = elTopPos + elHeight + tooltipOffset;
        arrowClass = arrow ? 'dropdown-arrow up-arrow' : '';
      } else if (elLeftPos - tooltipWidth - tooltipOffset > 10) {
        tooltipLeftPos = elLeftPos - tooltipWidth - tooltipOffset;
        tooltipTopPos = elTopPos + elHeight / 2 - tooltipHeight / 2;
        arrowClass = arrow ? 'dropdown-arrow right-arrow' : '';
      } else {
        tooltipLeftPos = elLeftPos + elWidth + tooltipOffset;
        tooltipTopPos = elTopPos + elHeight / 2 - tooltipHeight / 2;
        arrowClass = arrow ? 'dropdown-arrow left-arrow' : '';
      }
      $tooltip.css({
        'left': tooltipLeftPos,
        'top': tooltipTopPos - 5
      });
      $tooltip.addClass(arrowClass);
    }
  }
  onHandlerMouseOver() {
    this.setState({
      'active': true
    });
  }
  onHandlerMouseOut() {
    this.setState({
      'active': false
    });
  }
  render() {
    const self = this;
    const others = [];
    let handler = null;
    let contents = null;
    let x = 0;
    React.Children.forEach(this.props.children, (child) => {
      if (child.type.name === 'Handler') {
        handler = React.cloneElement(child, {
          onMouseOver () {
            self.onHandlerMouseOver();
          },
          onMouseOut () {
            self.onHandlerMouseOut();
          }
        });
      } else if (child.type.name === 'Contents') {
        contents = React.cloneElement(child, {
          active: self.state.active,
          withArrow: self.props.withArrow
        });
      } else {
        const tmp = React.cloneElement(child, {
          key: x++
        });
        others.push(tmp);
      }
    });
    return React.createElement("span", {
      ref: this.domRef,
      className: this.props.className || ''
    }, handler, contents, others);
  }
}
Tooltip.defaultProps = {
  'hideable': true
};
const tooltips = {
  Tooltip,
  Handler,
  Contents
};
;// ./js/ui/jsx/fm/nodes/columns/columnNodeName.jsx



class ColumnNodeName extends genericNodePropsComponent.B {
  constructor(...args) {
    super(...args);
    this.state = {
      src: null
    };
  }
  static get label() {
    return l[86];
  }
  componentDidMount() {
    super.componentDidMount();
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    const {
      node,
      requestThumbnailCb
    } = nodeAdapter.props;
    const src = this.state.src || thumbnails.get(node.fa);
    return REaCt().createElement("td", {
      megatype: ColumnNodeName.megatype
    }, src || is_image2(node) || is_video(node) ? REaCt().createElement(tooltips.Tooltip, {
      withArrow: true,
      className: "tooltip-handler-container",
      onShown: () => {
        if (!src) {
          requestThumbnailCb(node, true, (n, src) => {
            this.setState({
              src
            });
            return `preview_${n.h}`;
          });
        }
      }
    }, REaCt().createElement(tooltips.Handler, {
      className: `item-type-icon icon-${fileIcon(node)}-24`
    }), REaCt().createElement(tooltips.Contents, {
      className: "img-preview"
    }, REaCt().createElement("div", {
      className: "dropdown img-wrapper img-block",
      id: `preview_${node.h}`
    }, REaCt().createElement("img", {
      alt: "",
      className: `thumbnail-placeholder ${node.h}`,
      src: node.fa || src ? src || `${staticpath}/images/mega/ajax-loader-tiny.gif` : window.noThumbURI
    })))) : REaCt().createElement("span", {
      className: `
                            item-type-icon icon-${fileIcon(node)}-24
                        `
    }), REaCt().createElement("span", {
      className: "tranfer-filetype-txt"
    }, nodeAdapter.nodeProps.title));
  }
}
ColumnNodeName.sortable = true;
ColumnNodeName.id = 'name';
ColumnNodeName.megatype = 'fname';
;// ./js/ui/jsx/fm/nodes/columns/columnSize.jsx


class ColumnSize extends genericNodePropsComponent.B {
  static get label() {
    return l[87];
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    return REaCt().createElement("td", {
      megatype: ColumnSize.megatype,
      className: "size"
    }, nodeAdapter.nodeProps.size);
  }
}
ColumnSize.sortable = true;
ColumnSize.id = "size";
ColumnSize.megatype = "size";
;// ./js/ui/jsx/fm/nodes/columns/columnTimeAdded.jsx


class ColumnTimeAdded extends genericNodePropsComponent.B {
  static get label() {
    return l[16169];
  }
  render() {
    const {
      nodeAdapter
    } = this.props;
    return REaCt().createElement("td", {
      megatype: ColumnTimeAdded.megatype,
      className: "time ad"
    }, nodeAdapter.nodeProps.timestamp);
  }
}
ColumnTimeAdded.sortable = true;
ColumnTimeAdded.id = "ts";
ColumnTimeAdded.megatype = "timeAd";
;// ./js/ui/jsx/fm/nodes/columns/columnExtras.jsx


class ColumnExtras extends genericNodePropsComponent.B {
  render() {
    return REaCt().createElement("td", {
      megatype: ColumnExtras.megatype,
      className: "grid-url-field own-data extras-column"
    }, REaCt().createElement("span", {
      className: "versioning-indicator"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-versions-previous"
    })), REaCt().createElement("i", {
      className: "sprite-fm-mono icon-link"
    }));
  }
}
ColumnExtras.sortable = false;
ColumnExtras.id = "extras";
ColumnExtras.label = "";
ColumnExtras.megatype = "extras";
ColumnExtras.headerClassName = "grid-url-header";
;// ./js/ui/jsx/fm/browserEntries.jsx











class BrowserEntries extends mixins.w9 {
  constructor(props) {
    super(props);
    this.state = {
      'sortBy': props.sortBy || ['name', 'asc']
    };
    this.toggleSortBy = this.toggleSortBy.bind(this);
  }
  UNSAFE_componentWillMount() {
    this.lastCharKeyPressed = false;
    this.lastCharKeyIndex = -1;
  }
  componentDidMount() {
    super.componentDidMount();
    this.bindEvents();
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    this.unbindEvents();
  }
  componentDidUpdate(oldProps) {
    if (oldProps.sortBy && (oldProps.sortBy[0] !== this.props.sortBy[0] || oldProps.sortBy[1] !== this.props.sortBy[1])) {
      this.setState({
        'sortBy': this.props.sortBy
      });
    }
  }
  handleKeyNavigation(selectionManager, shiftKey, keyCode, viewMode) {
    let curr;
    const {
      folderSelectNotAllowed
    } = this.props;
    if (shiftKey && folderSelectNotAllowed) {
      curr = selectionManager.last_selected;
    }
    const {KEYS} = BrowserEntries;
    if (viewMode) {
      if (keyCode === KEYS.LEFT) {
        selectionManager.select_prev(shiftKey, true);
      } else if (keyCode === KEYS.RIGHT) {
        selectionManager.select_next(shiftKey, true);
      } else if (keyCode === KEYS.UP) {
        selectionManager.select_grid_up(shiftKey, true);
      } else {
        selectionManager.select_grid_down(shiftKey, true);
      }
    } else if (keyCode === KEYS.UP) {
      selectionManager.select_prev(shiftKey, true);
    } else {
      selectionManager.select_next(shiftKey, true);
    }
    if (shiftKey && folderSelectNotAllowed && $.selected.length > 1) {
      const folderNodes = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
      if (folderNodes.length > 1) {
        if (!M.isFileNode(M.getNodeByHandle(curr))) {
          array.remove(folderNodes, curr);
        }
        if (folderNodes.length) {
          const newCurr = selectionManager.last_selected;
          for (let i = 0; i < folderNodes.length; i++) {
            selectionManager.remove_from_selection(folderNodes[i]);
          }
          if (M.isFileNode(M.getNodeByHandle(newCurr))) {
            selectionManager.set_currently_selected(curr);
          } else if (curr && $.selected.includes(curr)) {
            selectionManager.set_currently_selected(curr);
          } else if ($.selected.length) {
            selectionManager.set_currently_selected($.selected[0]);
          }
        }
      }
    }
  }
  _invalidKeydownTarget(e) {
    return e.target && (e.target.tagName === 'INPUT' || e.target.tagName === 'BUTTON' || e.target.tagName === 'TEXTAREA' && !e.target.classList.contains('messages-textarea') || e.target.tagName === 'SELECT');
  }
  _isNavigationKeyDown(e, keyCode) {
    const {
      KEYS
    } = BrowserEntries;
    const {
      viewMode
    } = this.props;
    return !e.metaKey && (!viewMode && (keyCode === KEYS.UP || keyCode === KEYS.DOWN) || viewMode && (keyCode === KEYS.UP || keyCode === KEYS.DOWN || keyCode === KEYS.LEFT || keyCode === KEYS.RIGHT));
  }
  bindEvents() {
    const {
      KEYS
    } = BrowserEntries;
    $(document.body).rebind(`keydown.be${this.getUniqueId()}`, e => {
      let charTyped = false;
      const keyCode = e.which || e.keyCode;
      const $searchField = $('div.fm-files-search input');
      const $typingArea = $('textarea.messages-textarea');
      const {
        selectionManager,
        viewMode
      } = this.props;
      if (this._invalidKeydownTarget(e)) {
        return;
      }
      if ($searchField.is(':focus')) {
        return;
      }
      if ($typingArea.is(':focus')) {
        $typingArea.trigger('blur');
      }
      if (keyCode === KEYS.A && (e.ctrlKey || e.metaKey)) {
        this.handleSelectAll();
        e.preventDefault();
        e.stopPropagation();
      } else if (e.metaKey && keyCode === KEYS.UP || keyCode === KEYS.BACKSPACE) {
        this.handleKeyBack();
      } else if (this._isNavigationKeyDown(e, keyCode)) {
        this.handleKeyNavigation(selectionManager, e.shiftKey, keyCode, viewMode);
      } else if (keyCode >= 48 && keyCode <= 57 || keyCode >= 65 && keyCode <= 123 || keyCode > 255) {
        charTyped = String.fromCharCode(keyCode).toLowerCase();
        this.handleCharTyped(charTyped);
      } else if (keyCode === KEYS.ENTER || e.metaKey && keyCode === KEYS.DOWN) {
        this.handleAttach();
      }
      mega.ui.mInfoPanel.reRenderIfVisible($.selected);
      if (!charTyped) {
        this.lastCharKeyPressed = false;
        this.lastCharKeyIndex = -1;
      }
    });
  }
  handleSelectAll() {
    const {
      selectionManager,
      folderSelectNotAllowed,
      entries
    } = this.props;
    selectionManager.select_all();
    if (folderSelectNotAllowed) {
      const folders = entries.filter(h => !M.isFileNode(M.getNodeByHandle(h)));
      for (let i = 0; i < folders.length; i++) {
        selectionManager.remove_from_selection(folders[i].h);
      }
    }
  }
  handleKeyBack() {
    const {
      viewMode,
      currentlyViewedEntry
    } = this.props;
    if (!viewMode) {
      const currentFolder = M.getNode(currentlyViewedEntry);
      if (currentFolder.p) {
        this.expandFolder(currentFolder.p);
      }
    }
  }
  handleCharTyped(charTyped) {
    const {
      entries,
      keyProp,
      selectionManager
    } = this.props;
    const foundMatchingNodes = entries.filter(node => {
      return node.name && node.name.substring(0, 1).toLowerCase() === charTyped;
    });
    if (this.lastCharKeyPressed === charTyped) {
      this.lastCharKeyIndex++;
    }
    this.lastCharKeyPressed = charTyped;
    if (foundMatchingNodes.length > 0) {
      if (!foundMatchingNodes[this.lastCharKeyIndex]) {
        this.lastCharKeyIndex = 0;
      }
      const foundNode = foundMatchingNodes[this.lastCharKeyIndex];
      selectionManager.clear_selection();
      selectionManager.set_currently_selected(foundNode[keyProp], true);
    }
  }
  handleAttach() {
    const {
      highlighted,
      folderSelectNotAllowed,
      entries,
      keyProp,
      onAttachClicked
    } = this.props;
    let selectedNodes = highlighted;
    if (folderSelectNotAllowed) {
      selectedNodes = highlighted.filter(h => {
        const node = entries.find(e => e[keyProp] === h);
        return node && node.t === 0;
      });
      if (selectedNodes.length === 0) {
        const cursorNode = highlighted[0] && M.getNodeByHandle(highlighted[0]);
        if (cursorNode.t === 1) {
          this.expandFolder(cursorNode[keyProp]);
          return;
        } else if (highlighted.length > 0) {
          this.expandFolder(highlighted[0]);
          return;
        }
        return;
      }
    }
    onAttachClicked(selectedNodes);
  }
  unbindEvents() {
    $(document.body).off(`keydown.be${  this.getUniqueId()}`);
  }
  onEntryClick(e, node) {
    const {
      selectionManager,
      keyProp,
      folderSelectNotAllowed,
      highlighted = []
    } = this.props;
    this.lastCharKeyPressed = false;
    this.lastCharKeyIndex = -1;
    e.stopPropagation();
    e.preventDefault();
    if (!e.shiftKey && !e.ctrlKey && !e.metaKey) {
      selectionManager.clear_selection();
      selectionManager.set_currently_selected(node[keyProp]);
    } else if (e.shiftKey) {
      if ($.selected && $.selected.length) {
        let selFolders;
        if (folderSelectNotAllowed) {
          selFolders = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
        }
        selectionManager.shift_select_to(node[keyProp], false, true, false);
        if (folderSelectNotAllowed && $.selected.length > 1) {
          const folderNodes = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
          if (folderNodes.length > 1) {
            array.remove(folderNodes, selFolders[0] || folderNodes[0]);
            for (let i = 0; i < folderNodes.length; i++) {
              selectionManager.remove_from_selection(folderNodes[i]);
            }
          }
        }
      } else {
        selectionManager.set_currently_selected(node[keyProp]);
      }
    } else if (e.ctrlKey || e.metaKey) {
      if (!highlighted || !highlighted.includes(node[keyProp])) {
        if (folderSelectNotAllowed) {
          if (node.t === 1 && highlighted.length > 0) {
            return;
          } else if (highlighted.some(nodeId => {
            const node = M.getNodeByHandle(nodeId);
            return node && node.t === 1;
          })) {
            selectionManager.clear_selection();
          }
        }
        selectionManager.add_to_selection(node[keyProp]);
      } else if (highlighted && highlighted.includes(node[keyProp])) {
        if (folderSelectNotAllowed) {
          if (node.t === 1) {
            return;
          } else if (highlighted.some(nodeId => {
            const node = M.getNodeByHandle(nodeId);
            return node && node.t === 1;
          })) {
            selectionManager.clear();
          }
        }
        selectionManager.remove_from_selection(node[keyProp]);
      }
    }
  }
  expandFolder(nodeId) {
    const self = this;
    const node = M.getNodeByHandle(nodeId);
    if (node) {
      self.lastCharKeyPressed = false;
      self.lastCharKeyIndex = -1;
      self.setState({
        'selected': [],
        'highlighted': [],
        'cursor': false
      });
      self.props.onExpand(node);
      self.forceUpdate();
    }
  }
  onEntryDoubleClick(e, node) {
    const self = this;
    self.lastCharKeyPressed = false;
    self.lastCharKeyIndex = -1;
    e.stopPropagation();
    e.preventDefault();
    const share = M.getNodeShare(node);
    if (share && share.down) {
      return;
    }
    if (node.t) {
      self.props.onExpand(node);
      self.forceUpdate();
    } else {
      self.onEntryClick(e, node);
      self.props.onAttachClicked();
    }
  }
  customIsEventuallyVisible() {
    return true;
  }
  toggleSortBy(colId) {
    const newState = {};
    if (this.state.sortBy[0] === colId) {
      newState.sortBy = [colId, this.state.sortBy[1] === "asc" ? "desc" : "asc"];
    } else {
      newState.sortBy = [colId, "asc"];
    }
    this.setState(newState);
    this.props.onSortByChanged(newState.sortBy);
  }
  render() {
    const {viewMode} = this.props;
    const listAdapterOpts = this.props.listAdapterOpts || {};
    if (!viewMode) {
      listAdapterOpts.columns = [columnFavIcon.$, ColumnNodeName, ColumnSize, ColumnTimeAdded, ColumnExtras];
    }
    if (this.props.listAdapterColumns) {
      listAdapterOpts.columns = this.props.listAdapterColumns;
    }
    if (this.props.isLoading) {
      return REaCt().createElement("div", {
        className: "dialog-empty-block active dialog-fm folder"
      }, REaCt().createElement("div", {
        className: "dialog-empty-pad"
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-cloud-drive"
      }), REaCt().createElement("div", {
        className: "dialog-empty-header"
      }, l[5533])));
    } else if (!this.props.entries.length && this.props.currentlyViewedEntry === 'search') {
      return REaCt().createElement("div", {
        className: "dialog-empty-block active dialog-fm folder"
      }, REaCt().createElement("div", {
        className: "dialog-empty-pad"
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-preview-reveal"
      }), REaCt().createElement("div", {
        className: "dialog-empty-header"
      }, l[978])));
    } else if (!this.props.entries.length) {
      const nilComp = this.props.NilComponent;
      return nilComp && (typeof nilComp === "function" ? nilComp() : nilComp) || REaCt().createElement("div", {
        className: "dialog-empty-block active dialog-fm folder"
      }, this.props.currentlyViewedEntry === 'shares' ? REaCt().createElement("div", {
        className: "dialog-empty-pad"
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-folder-incoming-share-filled"
      }), REaCt().createElement("div", {
        className: "dialog-empty-header"
      }, l[6871])) : REaCt().createElement("div", {
        className: "dialog-empty-pad"
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-folder-filled"
      }), REaCt().createElement("div", {
        className: "dialog-empty-header"
      }, this.props.currentlyViewedEntry === M.RootID ? l[1343] : M.u[this.props.currentlyViewedEntry] ? l[6787] : l[782])));
    }
    return REaCt().createElement(MegaList2, {
      viewMode,
      sortBy: this.state.sortBy,
      currentlyViewedEntry: this.props.currentlyViewedEntry,
      selected: this.props.selected,
      highlighted: this.props.highlighted,
      containerClassName: this.props.containerClassName,
      nodeAdapterProps: {
        'onClick': (e, node) => {
          this.onEntryClick(e, node);
          mega.ui.mInfoPanel.reRenderIfVisible($.selected);
        },
        'onDoubleClick': (e, node) => {
          this.onEntryDoubleClick(e, node);
        },
        'className': node => {
          return this.props.highlighted.indexOf(node[this.props.keyProp]) > -1 ? " ui-selected" : "";
        }
      },
      ref: r => {
        this.megaList = r;
      },
      listAdapter: viewMode ? Grid : Table,
      nodeAdapter: viewMode ? GenericGrid : GenericTable,
      listAdapterOpts,
      entries: this.props.entries,
      itemHeight: this.props.megaListItemHeight,
      headerHeight: viewMode ? 0 : 56,
      header: !viewMode && REaCt().createElement(GenericTableHeader, {
        columns: listAdapterOpts.columns,
        sortBy: this.state.sortBy,
        onClick: this.toggleSortBy,
        headerContainerClassName: this.props.headerContainerClassName
      }),
      currentdirid: this.props.currentdirid,
      onContextMenu: this.props.onContextMenu,
      keyProp: this.props.keyProp
    });
  }
}
BrowserEntries.KEYS = {
  A: 65,
  UP: 38,
  DOWN: 40,
  LEFT: 37,
  RIGHT: 39,
  ENTER: 13,
  BACKSPACE: 8
};
BrowserEntries.defaultProps = {
  'hideable': true,
  'requiresUpdateOnResize': true
};
;// ./js/ui/jsx/fm/fmView.jsx



class FMView extends mixins.w9 {
  constructor(props) {
    let _this$dataSource;
    super(props);
    this.domRef = REaCt().createRef();
    let initialSortBy = props.initialSortBy || ['name', 'asc'];
    if (props.fmConfigSortEnabled) {
      let _fmconfig$sortmodes;
      const sortId = props.fmConfigSortId;
      assert(sortId, 'missing fmConfigSortId');
      if ((_fmconfig$sortmodes = fmconfig.sortmodes) != null && (_fmconfig$sortmodes = _fmconfig$sortmodes[sortId]) != null && _fmconfig$sortmodes.n) {
        let _fmconfig$sortmodes2;
        initialSortBy = this._translateFmConfigSortMode((_fmconfig$sortmodes2 = fmconfig.sortmodes) == null ? void 0 : _fmconfig$sortmodes2[sortId]);
      }
    }
    this.state = {
      'sortBy': initialSortBy,
      'selected': [],
      'highlighted': [],
      'entries': null
    };
    this.dataSource = this.props.dataSource;
    this.state.entries = this.getEntries();
    this.onAttachClicked = this.onAttachClicked.bind(this);
    this.onContextMenu = this.onContextMenu.bind(this);
    if ((_this$dataSource = this.dataSource) != null && _this$dataSource.addChangeListener) {
      this._listener = this.dataSource.addChangeListener(() => {
        if (!this.isMounted()) {
          return;
        }
        this.setState({
          'entries': this.getEntries()
        });
      });
    }
    this.initSelectionManager();
  }
  getDataSourceNode(h) {
    return this.dataSource && this.dataSource[h] || M.getNodeByHandle(h);
  }
  _translateFmConfigSortMode(currentSortModes) {
    const sortId = this.props.fmConfigSortId;
    assert(sortId, 'missing fmConfigSortId');
    const sortByArr = [];
    if (currentSortModes != null && currentSortModes.n) {
      sortByArr[0] = currentSortModes.n;
      const sortMap = this.props.fmConfigSortMap;
      const aliasKeys = sortMap && Object.keys(sortMap) || [];
      for (const alias of aliasKeys) {
        if (sortByArr[0] === sortMap[alias]) {
          sortByArr[0] = alias;
          break;
        }
      }
      sortByArr[1] = currentSortModes.d === 1 ? "asc" : "desc";
    }
    return sortByArr;
  }
  initSelectionManager(entries) {
    this.selectionManager = new SelectionManager2_React(entries || this.state.entries, this.props.currentdirid || "cloud-drive", () => {
      let _this$browserEntries;
      return (_this$browserEntries = this.browserEntries) == null || (_this$browserEntries = _this$browserEntries.megaList) == null || (_this$browserEntries = _this$browserEntries._calculated) == null ? void 0 : _this$browserEntries.itemsPerRow;
    }, nodeHandle => {
      if (this.browserEntries && this.browserEntries.megaList) {
        this.browserEntries.megaList.scrollToItem(nodeHandle);
      }
    }, {
      'onSelectedUpdated': selectedList => {
        this.onSelectionUpdated(selectedList);
      }
    });
  }
  onSelectionUpdated(selectedList) {
    selectedList = [...selectedList];
    const highlighted = selectedList;
    if (this.props.folderSelectNotAllowed && !this.props.folderSelectable) {
      selectedList = selectedList.filter(nodeId => !this.getDataSourceNode(nodeId).t);
    }
    this.setState({
      'selected': selectedList,
      highlighted
    });
    this.props.onSelected(selectedList);
    this.props.onHighlighted(highlighted);
    $.selected = highlighted;
  }
  getEntries(newState) {
    const self = this;
    const sortBy = newState && newState.sortBy || self.state.sortBy;
    const order = sortBy[1] === "asc" ? 1 : -1;
    const entries = [];
    let sortFunc, filterFunc, dataSource;
    const minSearchLength = self.props.minSearchLength || 3;
    const showSen = mega.sensitives.showGlobally;
    if (self.props.currentlyViewedEntry === "search" && self.props.searchValue && self.props.searchValue.length >= minSearchLength) {
      dataSource = this.dataSource || {
        ...M.tnd,
        ...M.d
      };
      filterFunc = M.getFilterBySearchFn(self.props.searchValue);
    } else {
      const tmp = M.getChildren(self.props.currentlyViewedEntry) || M.tree[self.props.currentlyViewedEntry] || this.props.dataSource;
      dataSource = Object.create(null);
      for (const h in tmp) {
        const n = this.getDataSourceNode(h);
        if (n) {
          dataSource[h] = n;
        }
      }
    }
    const {
      customFilterFn
    } = this.props;
    for (const h in dataSource) {
      const n = dataSource[h];
      const e = n && (!n.h || n.h.length === 8 && crypto_keyok(n) || n.h.length === 11);
      const s = e && !n.fv && (showSen || !mega.sensitives.isSensitive(n));
      if (s && (!customFilterFn || customFilterFn(n)) && (!filterFunc || filterFunc(n))) {
        entries.push(n);
      }
    }
    if (sortBy[0] === "name") {
      sortFunc = M.getSortByNameFn();
    } else if (sortBy[0] === "size") {
      sortFunc = M.getSortBySizeFn();
    } else if (sortBy[0] === "ts") {
      sortFunc = M.getSortByDateTimeFn();
    } else if (sortBy[0] === "rts") {
      sortFunc = M.getSortByRtsFn();
    } else if (sortBy[0] === "status") {
      sortFunc = M.getSortByStatusFn();
    } else if (sortBy[0] === "interaction") {
      sortFunc = M.getSortByInteractionFn();
    } else if (sortBy[0] === "verification") {
      sortFunc = M.getSortByVerificationFn();
    } else if (sortBy[0] === "email") {
      sortFunc = M.getSortByEmail();
    } else if (sortBy[0] === 'access') {
      sortFunc = (a, b, o) => typeof a.r !== 'undefined' && typeof b.r !== 'undefined' && (a.r < b.r ? -1 : 1) * o;
    } else {
        sortFunc = M.sortByFavFn(order);
      }
    const folders = [];
    if (this.props.sortFoldersFirst) {
      for (let i = entries.length; i--;) {
        if (entries[i] && entries[i].t) {
          folders.unshift(entries[i]);
          entries.splice(i, 1);
        }
      }
    }
    folders.sort((a, b) => {
      return sortFunc(a, b, order);
    });
    entries.sort((a, b) => {
      return sortFunc(a, b, order);
    });
    return folders.concat(entries);
  }
  onHighlighted(nodes) {
    this.setState({
      'highlighted': nodes
    });
    if (this.props.onHighlighted) {
      this.props.onHighlighted(nodes);
    }
  }
  finishedLoading(newState) {
    newState.isLoading = false;
    newState.entries = this.getEntries();
    this.initSelectionManager(newState.entries);
    this.setState(newState);
  }
  addOrUpdRawListener() {
    if (this._rawListener) {
      mBroadcaster.removeListener(this._rawListener);
    }
    this._rawListener = mBroadcaster.addListener(`fmViewUpdate:${  this.props.currentlyViewedEntry}`, () => {
      this.setState({
        'entries': this.getEntries()
      }, () => {
        if (this.browserEntries.isMounted()) {
          this.browserEntries.forceUpdate();
        }
      });
    });
  }
  componentDidMount() {
    let _this$dataSource2;
    super.componentDidMount();
    if (!((_this$dataSource2 = this.dataSource) != null && _this$dataSource2.addChangeListener)) {
      this.addOrUpdRawListener();
    }
    if (this.props.fmConfigSortEnabled) {
      this._sortModeListener = mBroadcaster.addListener("fmconfig:sortmodes", sortModes => {
        this.onFmConfigSortModeChanged(sortModes);
      });
    }
  }
  componentDidUpdate(prevProps) {
    const {
      currentlyViewedEntry: currEntry,
      searchValue: currSearch
    } = this.props;
    const {
      currentlyViewedEntry: prevEntry,
      searchValue: prevSearch
    } = prevProps;
    if (prevEntry !== currEntry || currSearch !== prevSearch) {
      let _this$dataSource3;
      const newState = {
        'selected': [],
        'highlighted': []
      };
      if (!((_this$dataSource3 = this.dataSource) != null && _this$dataSource3.addChangeListener)) {
        this.addOrUpdRawListener();
      }
      const handle = currEntry;
      if (handle === 'shares') {
        newState.isLoading = true;
        this.setState(newState);
        dbfetch.geta(Object.keys(M.c.shares || {})).always(() => {
          this.finishedLoading(newState);
        });
        return;
      }
      if (this.getDataSourceNode(handle).t && !M.getChildren(handle)) {
        this.setState({
          'isLoading': true
        });
        dbfetch.get(handle).always(() => {
          this.finishedLoading(newState);
        });
        return;
      }
      const entries = this.getEntries();
      this.initSelectionManager(entries);
      this.setState({
        entries
      });
    }
  }
  onAttachClicked() {
    this.props.onAttachClicked();
  }
  onContextMenu() {}
  componentWillUnmount() {
    super.componentWillUnmount();
    if (this._listener) {
      let _this$dataSource4;
      (_this$dataSource4 = this.dataSource) == null || _this$dataSource4.removeChangeListener(this._listener);
    }
    if (this._rawListener) {
      mBroadcaster.removeListener(this._rawListener);
    }
    if (this._sortModeListener) {
      mBroadcaster.removeListener(this._sortModeListener);
    }
    $.selected = [];
    this.selectionManager.destroy();
    this.selectionManager = undefined;
    $('.dropdown.body.files-menu.context').css('z-index', '');
  }
  onSortByChanged(newState) {
    if (newState[0] === this.state.sortBy[0] && newState[1] === this.state.sortBy[1]) {
      return;
    }
    const entries = this.getEntries({
      'sortBy': newState
    });
    this.setState({
      'sortBy': newState,
      entries,
      'selected': [],
      'highlighted': []
    }, () => {
      if (this.props.onSortByChanged) {
        this.props.onSortByChanged(newState);
      }
      if (this.props.fmConfigSortEnabled) {
        const sortId = this.props.fmConfigSortId;
        assert(sortId, 'fmConfigSortId missing');
        if (newState[0] === this.props.initialSortBy[0] && newState[1] === this.props.initialSortBy[1]) {
          const sortModes = typeof fmconfig.sortmodes !== 'undefined' ? fmconfig.sortmodes : Object.create(null);
          delete sortModes[sortId];
          mega.config.set('sortmodes', sortModes);
          return;
        }
        const map = this.props.fmConfigSortMap || Object.create(null);
        const name = map[newState[0]] || newState[0];
        const direction = newState[1] === "asc" ? 1 : -1;
        fmsortmode(sortId, name, direction);
      }
    });
    this.initSelectionManager(entries);
  }
  onFmConfigSortModeChanged(sortModes) {
    const currentSortMode = sortModes[this.props.fmConfigSortId];
    if (!currentSortMode) {
      this.onSortByChanged(this.props.initialSortBy || ['name', 'asc']);
    } else {
      const newSortMode = this._translateFmConfigSortMode(currentSortMode);
      if (this.state.sortBy[0] !== newSortMode[0] || this.state.sortBy[1] !== newSortMode[1]) {
        this.onSortByChanged(newSortMode);
      }
    }
  }
  render() {
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "content-container",
      onClick: ev => {
        $.hideContextMenu(ev);
      }
    }, REaCt().createElement(BrowserEntries, {
      isLoading: this.state.isLoading || this.props.nodeLoading,
      currentlyViewedEntry: this.props.currentlyViewedEntry,
      entries: this.state.entries || [],
      onExpand: node => {
        this.setState({
          'selected': [],
          'highlighted': []
        });
        this.props.onExpand(node[this.props.keyProp || 'h']);
      },
      sortBy: this.state.sortBy,
      folderSelectNotAllowed: this.props.folderSelectNotAllowed,
      onAttachClicked: this.onAttachClicked,
      viewMode: this.props.viewMode,
      selected: this.state.selected,
      highlighted: this.state.highlighted,
      onContextMenu: this.props.onContextMenu || this.onContextMenu,
      selectionManager: this.selectionManager,
      ref: browserEntries => {
        this.browserEntries = browserEntries;
      },
      onSortByChanged: newState => {
        this.onSortByChanged(newState);
      },
      listAdapterColumns: this.props.listAdapterColumns,
      currentdirid: this.props.currentdirid,
      containerClassName: this.props.containerClassName,
      headerContainerClassName: this.props.headerContainerClassName,
      megaListItemHeight: this.props.megaListItemHeight,
      keyProp: this.props.keyProp || 'h',
      NilComponent: this.props.NilComponent,
      listAdapterOpts: this.props.listAdapterOpts
    }));
  }
}

},

707:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
a: () => MetaRichpreviewLoading
});
const React = REQ_(594);
const ConversationMessageMixin = REQ_(446).M;
class MetaRichpreviewLoading extends ConversationMessageMixin {
  render() {
    return React.createElement("div", {
      className: "loading-spinner light small"
    }, React.createElement("div", {
      className: "main-loader"
    }));
  }
}


},

732:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  qY: () => conversations_EVENTS,
  Vw: () => VIEWS,
  Ay: () => conversations
});

// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
const esm_extends = REQ_(168);
// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
// EXTERNAL MODULE: ./js/chat/ui/conversationpanel.jsx + 15 modules
const conversationpanel = REQ_(438);
// EXTERNAL MODULE: ./js/chat/ui/contactsPanel/contactsPanel.jsx + 20 modules
const contactsPanel = REQ_(173);
// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
const modalDialogs = REQ_(318);
// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
const meetings_button = REQ_(959);
// EXTERNAL MODULE: ./js/chat/ui/meetings/workflow/preview.jsx
const preview = REQ_(485);
// EXTERNAL MODULE: ./js/chat/ui/link.jsx
const ui_link = REQ_(280);
// EXTERNAL MODULE: ./js/ui/utils.jsx
const utils = REQ_(314);
;// ./js/chat/ui/meetings/workflow/start.jsx

let _Start;






class Start extends REaCt().Component {
  constructor(props) {
    super(props);
    this.inputRef = REaCt().createRef();
    this.defaultTopic = l.default_meeting_topic.replace('%NAME', M.getNameByHandle(u_handle));
    this.state = {
      audio: false,
      video: false,
      editing: false,
      previousTopic: undefined,
      topic: undefined
    };
    this.handleChange = ev => this.setState({
      topic: ev.target.value
    });
    this.toggleEdit = () => {
      this.setState(state => {
        const topic = state.topic.trim() || this.defaultTopic;
        return {
          editing: !state.editing,
          topic,
          previousTopic: topic
        };
      }, () => onIdle(this.doFocus));
    };
    this.doFocus = () => {
      if (this.state.editing) {
        const input = this.inputRef.current;
        input.focus();
        input.setSelectionRange(0, input.value.length);
      }
    };
    this.doReset = () => this.setState(state => ({
      editing: false,
      topic: state.previousTopic,
      previousTopic: undefined
    }));
    this.bindEvents = () => $(document).rebind(`mousedown.${Start.NAMESPACE}`, ev => {
      if (this.state.editing && !ev.target.classList.contains(Start.CLASS_NAMES.EDIT) && !ev.target.classList.contains(Start.CLASS_NAMES.INPUT)) {
        this.toggleEdit();
      }
    }).rebind(`keyup.${Start.NAMESPACE}`, ({
      keyCode
    }) => {
      if (this.state.editing) {
        const [ENTER, ESCAPE] = [13, 27];
        return keyCode === ENTER ? this.toggleEdit() : keyCode === ESCAPE ? this.doReset() : null;
      }
    });
    this.Input = () => REaCt().createElement("input", {
      type: "text",
      ref: this.inputRef,
      className: Start.CLASS_NAMES.INPUT,
      value: this.state.topic,
      maxLength: ChatRoom.TOPIC_MAX_LENGTH,
      onChange: this.handleChange
    });
    this.onStreamToggle = (audio, video) => this.setState({
      audio,
      video
    });
    this.startMeeting = () => {
      const {
        onStart
      } = this.props;
      const {
        topic,
        audio,
        video
      } = this.state;
      if (onStart) {
        onStart(topic.trim() || this.defaultTopic, audio, video);
      }
    };
    this.state.topic = this.defaultTopic;
  }
  componentDidMount() {
    this.bindEvents();
    if ($.dialog === 'onboardingDialog') {
      closeDialog();
    }
    M.safeShowDialog(Start.dialogName, () => $(`#${Start.NAMESPACE}`));
  }
  componentWillUnmount() {
    $(document).unbind(`.${Start.NAMESPACE}`);
    if ($.dialog === Start.dialogName) {
      closeDialog();
    }
  }
  render() {
    const {
      NAMESPACE,
      CLASS_NAMES
    } = Start;
    const {
      editing,
      topic
    } = this.state;
    return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
      id: NAMESPACE,
      dialogName: NAMESPACE,
      className: NAMESPACE,
      stopKeyPropagation: editing,
      onClose: () => this.props.onClose()
    }), REaCt().createElement("div", {
      className: `${NAMESPACE}-preview`
    }, REaCt().createElement(preview.A, {
      context: NAMESPACE,
      onToggle: this.onStreamToggle
    })), REaCt().createElement("div", {
      className: "fm-dialog-body"
    }, REaCt().createElement("div", {
      className: `${NAMESPACE}-title`
    }, editing ? REaCt().createElement(this.Input, null) : REaCt().createElement("h2", {
      onClick: this.toggleEdit
    }, REaCt().createElement(utils.zT, null, topic)), REaCt().createElement(meetings_button.A, {
      className: `
                                mega-button
                                action
                                small
                                ${CLASS_NAMES.EDIT}
                                ${editing ? 'editing' : ''}
                            `,
      icon: "icon-rename",
      simpletip: {
        label: l[1342],
        position: 'top'
      },
      onClick: this.toggleEdit
    }, REaCt().createElement("span", null, l[1342]))), REaCt().createElement(meetings_button.A, {
      className: "mega-button positive large start-meeting-button",
      onClick: () => {
        this.startMeeting();
        eventlog(500235);
      }
    }, REaCt().createElement("span", null, l[7315])), REaCt().createElement(ui_link.A, {
      to: "https://mega.io/chatandmeetings",
      target: "_blank"
    }, l.how_meetings_work)));
  }
}
_Start = Start;
Start.NAMESPACE = 'start-meeting';
Start.dialogName = `${_Start.NAMESPACE}-dialog`;
Start.CLASS_NAMES = {
  EDIT: 'call-title-edit',
  INPUT: 'call-title-input'
};
Start.STREAMS = {
  AUDIO: 1,
  VIDEO: 2
};
window.StartMeetingDialogUI = {
  Start
};
// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
const perfectScrollbar = REQ_(486);
// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
const ui_contacts = REQ_(251);
;// ./js/chat/ui/meetings/schedule/invite.jsx




class Invite extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.wrapperRef = REaCt().createRef();
    this.inputRef = REaCt().createRef();
    this.state = {
      value: '',
      expanded: false,
      loading: true,
      frequents: [],
      frequentsInitial: [],
      contacts: [],
      contactsInitial: [],
      selected: []
    };
    this.handleMousedown = ({
      target
    }) => this.domRef && this.domRef.current && this.domRef.current.contains(target) ? null : this.setState({
      expanded: false
    });
    this.getSortedContactsList = frequents => {
      const filteredContacts = [];
      M.u.forEach(contact => {
        if (contact.c === 1 && !frequents.includes(contact.u) && !this.state.selected.includes(contact.u)) {
          filteredContacts.push(contact);
        }
      });
      const sortFn = M.getSortByNameFn2(1);
      filteredContacts.sort((a, b) => sortFn(a, b));
      return filteredContacts;
    };
    this.doMatch = (value, collection) => {
      value = value.toLowerCase();
      return collection.filter(contact => {
        contact = typeof contact === 'string' ? M.getUserByHandle(contact) : contact;
        const name = M.getNameByHandle(contact.u).toLowerCase();
        const email = contact.m && contact.m.toLowerCase();
        return name.includes(value) || email.includes(value);
      });
    };
    this.handleSearch = this.handleSearch.bind(this);
    this.state.selected = this.props.participants || [];
  }
  reinitializeWrapper() {
    const wrapperRef = this.wrapperRef && this.wrapperRef.current;
    if (wrapperRef) {
      wrapperRef.reinitialise();
      wrapperRef.scrollToY(0);
    }
  }
  buildContactsList() {
    megaChat.getFrequentContacts().then(frequentContacts => {
      if (this.isMounted()) {
        const frequents = frequentContacts.slice(-ui_contacts.MAX_FREQUENTS).map(c => c.userId);
        const contacts = this.getSortedContactsList(frequents);
        this.setState({
          frequents,
          frequentsInitial: frequents,
          contacts,
          contactsInitial: contacts,
          loading: false
        });
      }
    });
  }
  handleSearch(ev) {
    const {
      value
    } = ev.target;
    const searching = value.length >= 2;
    const frequents = searching ? this.doMatch(value, this.state.frequentsInitial) : this.state.frequentsInitial;
    const contacts = searching ? this.doMatch(value, this.state.contactsInitial) : this.state.contactsInitial;
    this.setState({
      value,
      contacts,
      frequents
    }, () => this.reinitializeWrapper());
  }
  handleSelect({
    userHandle,
    expanded = false
  }) {
    this.setState(state => ({
      value: '',
      expanded,
      selected: state.selected.includes(userHandle) ? state.selected.filter(c => c !== userHandle) : [...state.selected, userHandle]
    }), () => {
      let _this$inputRef$curren;
      this.props.onSelect(this.state.selected);
      this.buildContactsList();
      this.reinitializeWrapper();
      (_this$inputRef$curren = this.inputRef.current) == null || _this$inputRef$curren.focus();
    });
  }
  getFilteredContacts(contacts) {
    if (contacts && contacts.length) {
      return contacts.map(contact => {
        contact = contact instanceof MegaDataMap ? contact : M.u[contact];
        return this.state.selected.includes(contact.u) ? null : REaCt().createElement("div", {
          key: contact.u,
          className: "invite-section-item",
          onClick: () => {
            this.handleSelect({
              userHandle: contact.u,
              expanded: true
            });
          }
        }, REaCt().createElement(ui_contacts.Avatar, {
          contact
        }), REaCt().createElement("div", {
          className: "invite-item-data"
        }, REaCt().createElement("div", {
          className: "invite-item-name"
        }, REaCt().createElement(ui_contacts.ContactAwareName, {
          overflow: true,
          simpletip: {
            offset: 10
          },
          contact
        })), REaCt().createElement("div", {
          className: "invite-item-mail"
        }, contact.m)));
      });
    }
    return null;
  }
  renderContent() {
    const {
      frequents,
      contacts,
      selected
    } = this.state;
    const hasMoreFrequents = frequents.length && frequents.some(h => !selected.includes(h));
    const $$SECTION = (title, children) => REaCt().createElement("div", {
      className: "invite-section"
    }, REaCt().createElement("div", {
      className: "invite-section-title"
    }, title), children && REaCt().createElement("div", {
      className: "invite-section-list"
    }, children));
    if (hasMoreFrequents || contacts.length) {
      return REaCt().createElement(perfectScrollbar.O, {
        ref: this.wrapperRef,
        className: "invite-scroll-wrapper",
        options: {
          'suppressScrollX': true
        }
      }, hasMoreFrequents ? $$SECTION(l.recent_contact_label, this.getFilteredContacts(frequents)) : '', contacts.length ? $$SECTION(l.all_contact_label, this.getFilteredContacts(contacts)) : '', frequents.length === 0 && contacts.length === 0 && $$SECTION(l.invite_no_results_found, null));
    }
    return $$SECTION(l.invite_no_contacts_to_add, null);
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    document.removeEventListener('mousedown', this.handleMousedown);
  }
  componentDidMount() {
    super.componentDidMount();
    document.addEventListener('mousedown', this.handleMousedown);
    this.buildContactsList();
  }
  render() {
    const {
      className,
      isLoading
    } = this.props;
    const {
      value,
      expanded,
      loading,
      selected
    } = this.state;
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                    ${Invite.NAMESPACE}
                    ${className || ''}
                `
    }, REaCt().createElement("div", {
      className: "multiple-input"
    }, REaCt().createElement("ul", {
      className: "token-input-list-mega",
      onClick: ({
        target
      }) => isLoading ? null : target.classList.contains('token-input-list-mega') && this.setState({
        expanded: true
      })
    }, selected.map(handle => {
      return REaCt().createElement("li", {
        key: handle,
        className: "token-input-token-mega"
      }, REaCt().createElement("div", {
        className: "contact-tag-item"
      }, REaCt().createElement(ui_contacts.Avatar, {
        contact: M.u[handle],
        className: "avatar-wrapper box-avatar"
      }), REaCt().createElement(ui_contacts.ContactAwareName, {
        contact: M.u[handle],
        overflow: true
      }), REaCt().createElement("i", {
        className: "sprite-fm-mono icon-close-component",
        onClick: () => isLoading ? null : this.handleSelect({
          userHandle: handle
        })
      })));
    }), REaCt().createElement("li", {
      className: "token-input-input-token-mega"
    }, REaCt().createElement("input", {
      ref: this.inputRef,
      type: "text",
      name: "participants",
      className: `${Invite.NAMESPACE}-input`,
      disabled: isLoading,
      autoComplete: "off",
      placeholder: selected.length ? '' : l.schedule_participant_input,
      value,
      onClick: () => this.setState({
        expanded: true
      }),
      onChange: this.handleSearch,
      onKeyDown: ({
        target,
        keyCode
      }) => {
        const {
          selected
        } = this.state;
        return keyCode === 8 && target.value === '' && selected.length && this.handleSelect({
          userHandle: selected[selected.length - 1]
        });
      }
    })))), loading ? null : REaCt().createElement("div", {
      className: `mega-input-dropdown ${expanded ? '' : 'hidden'}`
    }, this.renderContent()));
  }
}
Invite.NAMESPACE = 'meetings-invite';
// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/helpers.jsx
const helpers = REQ_(110);
;// ./js/chat/ui/meetings/schedule/dateObserver.jsx


const withDateObserver = Component => class extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.listener = undefined;
    this.state = {
      timestamp: undefined
    };
  }
  componentWillUnmount() {
    mBroadcaster.removeListener(this.listener);
  }
  componentDidMount() {
    this.listener = mBroadcaster.addListener(withDateObserver.NAMESPACE, timestamp => this.setState({
      timestamp
    }));
  }
  render() {
    return REaCt().createElement(Component, (0,esm_extends.A)({}, this.props, {
      timestamp: this.state.timestamp
    }));
  }
};
withDateObserver.NAMESPACE = 'meetings:onSelectDate';
;// ./js/chat/ui/meetings/schedule/datepicker.jsx



class Datepicker extends REaCt().Component {
  constructor(props) {
    super(props);
    this.OPTIONS = {
      classes: 'meetings-datepicker-calendar',
      dateFormat: '@',
      minDate: null,
      startDate: null,
      selectedDates: [],
      prevHtml: '<i class="sprite-fm-mono icon-arrow-right"></i>',
      nextHtml: '<i class="sprite-fm-mono icon-arrow-right"></i>',
      altField: null,
      firstDay: 0,
      autoClose: true,
      toggleSelected: false,
      position: 'bottom left',
      language: {
        daysMin: [l[8763], l[8764], l[8765], l[8766], l[8767], l[8768], l[8769]],
        months: [l[408], l[409], l[410], l[411], l[412], l[413], l[414], l[415], l[416], l[417], l[418], l[419]],
        monthsShort: [l[24035], l[24037], l[24036], l[24038], l[24047], l[24039], l[24040], l[24041], l[24042], l[24043], l[24044], l[24045]]
      },
      onSelect: dateText => {
        const prevDate = new Date(+this.props.value);
        const nextDate = new Date(+dateText);
        nextDate.setHours(prevDate.getHours(), prevDate.getMinutes());
        this.props.onSelect(nextDate.getTime());
        mBroadcaster.sendMessage(withDateObserver.NAMESPACE, nextDate.getTime());
      }
    };
    this.domRef = REaCt().createRef();
    this.inputRef = REaCt().createRef();
    this.datepicker = null;
    this.formatValue = value => {
      if (typeof value === 'number') {
        return time2date(value / 1000, 18);
      }
      return value;
    };
    this.OPTIONS.startDate = new Date(this.props.startDate);
    this.OPTIONS.selectedDates = this.props.selectedDates || [this.OPTIONS.startDate];
    this.OPTIONS.minDate = this.props.minDate ? new Date(this.props.minDate) : new Date();
    this.OPTIONS.position = this.props.position || this.OPTIONS.position;
    this.OPTIONS.altField = `input.${this.props.altField}`;
  }
  initialize() {
    const inputRef = this.inputRef && this.inputRef.current;
    if (inputRef) {
      let _this$props$onMount, _this$props;
      $(inputRef).datepicker(this.OPTIONS);
      this.datepicker = $(inputRef).data('datepicker');
      (_this$props$onMount = (_this$props = this.props).onMount) == null || _this$props$onMount.call(_this$props, this.datepicker);
    }
  }
  componentWillUnmount() {
    if (this.domRef && this.domRef.current) {
      $(this.domRef.current).unbind(`keyup.${Datepicker.NAMESPACE}`);
    }
  }
  componentDidMount() {
    M.require('datepicker_js').done(() => this.initialize());
    if (this.domRef && this.domRef.current) {
      $(this.domRef.current).rebind(`keyup.${Datepicker.NAMESPACE}`, ({
        keyCode
      }) => {
        if (keyCode === 13) {
          this.datepicker.hide();
          return false;
        }
      });
    }
  }
  render() {
    const {
      NAMESPACE
    } = Datepicker;
    const {
      value,
      name,
      className,
      placeholder,
      isLoading,
      onFocus,
      onChange,
      onBlur
    } = this.props;
    const formattedValue = this.formatValue(value);
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: NAMESPACE
    }, REaCt().createElement("div", {
      className: "mega-input datepicker-input"
    }, REaCt().createElement("input", {
      ref: this.inputRef,
      type: "text",
      name,
      className: `
                            dialog-input
                            ${className || ''}
                        `,
      autoComplete: "off",
      disabled: isLoading,
      placeholder: placeholder || '',
      value: formattedValue,
      onFocus: ev => onFocus == null ? void 0 : onFocus(ev),
      onChange: ev => onChange == null ? void 0 : onChange(ev),
      onBlur: ev => onBlur == null ? void 0 : onBlur(ev)
    }), REaCt().createElement("i", {
      className: "sprite-fm-mono icon-calendar1",
      onClick: isLoading ? null : () => {
        if (this.datepicker) {
          let _this$inputRef$curren;
          this.datepicker.show();
          (_this$inputRef$curren = this.inputRef.current) == null || _this$inputRef$curren.focus();
        }
      }
    })));
  }
}
Datepicker.NAMESPACE = 'meetings-datepicker';
const datepicker = (0,mixins.Zz)(withDateObserver)(Datepicker);
;// ./js/chat/ui/meetings/schedule/select.jsx





class Select extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.inputRef = REaCt().createRef();
    this.menuRef = REaCt().createRef();
    this.optionRefs = {};
    this.state = {
      expanded: false,
      manualTimeInput: '',
      timestamp: ''
    };
    this.handleMousedown = ({
      target
    }) => {
      let _this$domRef;
      return (_this$domRef = this.domRef) != null && _this$domRef.current.contains(target) ? null : this.setState({
        expanded: false
      });
    };
    this.handleToggle = ({
      target
    } = {}) => {
      let _this$menuRef, _menuRef$domRef;
      const menuRef = (_this$menuRef = this.menuRef) == null ? void 0 : _this$menuRef.current;
      const menuElement = (_menuRef$domRef = menuRef.domRef) == null ? void 0 : _menuRef$domRef.current;
      if (target !== menuElement) {
        const {
          value
        } = this.props;
        this.setState(state => ({
          expanded: !state.expanded
        }), () => {
          if (value && this.optionRefs[value]) {
            menuRef.scrollToElement(this.optionRefs[value]);
          }
        });
      }
    };
  }
  getFormattedDuration(duration) {
    duration = moment.duration(duration);
    const days = duration.get('days');
    const hours = duration.get('hours');
    const minutes = duration.get('minutes');
    if (!hours && !minutes && !days) {
      return '';
    }
    const totalHours = days ? ~~duration.asHours() : hours;
    if (!hours && minutes) {
      return days ? `(${totalHours}\u00a0h ${minutes}\u00a0m)` : `(${minutes}\u00a0m)`;
    }
    return minutes ? `(${totalHours}\u00a0h ${minutes}\u00a0m)` : `(${totalHours}\u00a0h)`;
  }
  componentWillUnmount() {
    document.removeEventListener('mousedown', this.handleMousedown);
    if (this.inputRef && this.inputRef.current) {
      $(this.inputRef.current).unbind(`keyup.${Select.NAMESPACE}`);
    }
  }
  componentDidMount() {
    let _this$inputRef;
    document.addEventListener('mousedown', this.handleMousedown);
    const inputRef = (_this$inputRef = this.inputRef) == null ? void 0 : _this$inputRef.current;
    if (inputRef) {
      $(inputRef).rebind(`keyup.${Select.NAMESPACE}`, ({
        keyCode
      }) => {
        if (keyCode === 13) {
          this.handleToggle();
          inputRef.blur();
          return false;
        }
      });
    }
  }
  render() {
    const {
      NAMESPACE
    } = Select;
    const {
      name,
      className,
      icon,
      typeable,
      options,
      value,
      format,
      isLoading,
      onChange,
      onBlur,
      onSelect
    } = this.props;
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                    ${NAMESPACE}
                    ${className || ''}
                `
    }, REaCt().createElement("div", {
      className: `
                        mega-input
                        dropdown-input
                        ${typeable ? 'typeable' : ''}
                    `,
      onClick: isLoading ? null : this.handleToggle
    }, typeable ? null : value && REaCt().createElement("span", null, format ? format(value) : value), REaCt().createElement("input", {
      ref: this.inputRef,
      type: "text",
      className: `
                            ${NAMESPACE}-input
                            ${name}
                        `,
      value: (() => {
        if (this.state.manualTimeInput) {
          return this.state.manualTimeInput;
        }
        return format ? format(value) : value;
      })(),
      onFocus: ({
        target
      }) => {
        this.setState({
          manualTimeInput: '',
          timestamp: ''
        }, () => target.select());
      },
      onChange: ({
        target
      }) => {
        const {
          value: manualTimeInput
        } = target;
        const {
          value
        } = this.props;
        const prevDate = moment(value);
        const inputTime = (0,helpers.We)(manualTimeInput);
        prevDate.set({
          hours: inputTime.get('hours'),
          minutes: inputTime.get('minutes')
        });
        const timestamp = prevDate.valueOf();
        onChange == null || onChange(timestamp);
        if (this.optionRefs[value]) {
          this.menuRef.current.scrollToElement(this.optionRefs[value]);
        }
        this.setState({
          manualTimeInput,
          timestamp
        });
      },
      onBlur: () => {
        onBlur(this.state.timestamp);
        this.setState({
          manualTimeInput: '',
          timestamp: ''
        });
      }
    }), icon && REaCt().createElement("i", {
      className: "sprite-fm-mono icon-dropdown"
    }), options && REaCt().createElement("div", {
      className: `
                                mega-input-dropdown
                                ${this.state.expanded ? '' : 'hidden'}
                            `
    }, REaCt().createElement(perfectScrollbar.O, {
      ref: this.menuRef,
      options: {
        suppressScrollX: true
      }
    }, options.map(option => {
      return REaCt().createElement("div", {
        ref: ref => {
          this.optionRefs[option.value] = ref;
        },
        key: option.value,
        className: `
                                                option
                                                ${option.value === value || option.label === value ? 'active' : ''}
                                            `,
        onClick: () => onSelect(option)
      }, option.label, "\xA0", option.duration && this.getFormattedDuration(option.duration));
    })))));
  }
}
Select.NAMESPACE = 'meetings-select';
const schedule_select = (0,mixins.Zz)(withDateObserver)(Select);
;// ./js/chat/ui/meetings/schedule/datetime.jsx




class DateTime extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.state = {
      datepickerRef: undefined,
      manualDateInput: '',
      manualTimeInput: '',
      initialDate: ''
    };
    this.handleChange = ev => {
      const {
        onChange
      } = this.props;
      const {
        datepickerRef,
        initialDate
      } = this.state;
      if (!datepickerRef) {
        return;
      }
      const {
        value
      } = ev.target;
      const date = (0,helpers.XH)(value);
      const timestamp = date.valueOf();
      const dateObj = new Date(timestamp);
      dateObj.setHours(initialDate.getHours(), initialDate.getMinutes());
      datepickerRef.selectedDates = [dateObj];
      datepickerRef.currentDate = dateObj;
      datepickerRef.nav._render();
      datepickerRef.views.days._render();
      onChange == null || onChange(value);
      this.setState({
        manualDateInput: dateObj.getTime()
      });
    };
  }
  render() {
    const {
      name,
      startDate,
      altField,
      value,
      minDate,
      filteredTimeIntervals,
      label,
      isLoading,
      onMount,
      onSelectDate,
      onSelectTime,
      onBlur
    } = this.props;
    return REaCt().createElement(REaCt().Fragment, null, label && REaCt().createElement("span", null, label), REaCt().createElement(datepicker, {
      name: `${datepicker.NAMESPACE}-${name}`,
      className: isLoading ? 'disabled' : '',
      isLoading,
      startDate,
      altField: `${schedule_select.NAMESPACE}-${altField}`,
      value,
      minDate,
      onMount: datepickerRef => this.setState({
        datepickerRef
      }, () => onMount(datepickerRef)),
      onSelect: onSelectDate,
      onFocus: ({
        target
      }) => {
        this.setState({
          manualDateInput: undefined,
          manualTimeInput: undefined,
          initialDate: new Date(value)
        }, () => target.select());
      },
      onChange: this.handleChange,
      onBlur: () => onBlur(this.state.manualDateInput)
    }), REaCt().createElement(schedule_select, {
      name: `${schedule_select.NAMESPACE}-${altField}`,
      className: isLoading ? 'disabled' : '',
      isLoading,
      typeable: true,
      options: filteredTimeIntervals,
      value: (() => typeof value === 'number' ? value : this.state.datepickerRef.currentDate.getTime())(),
      format: toLocaleTime,
      onSelect: onSelectTime,
      onChange: () => false,
      onBlur: timestamp => {
        if (timestamp) {
          onSelectTime({
            value: timestamp
          });
        }
      }
    }));
  }
}
;// ./js/chat/ui/meetings/schedule/recurring.jsx












class Recurring extends mixins.w9 {
  constructor(props) {
    let _Object$values$find;
    super(props);
    this.domRef = REaCt().createRef();
    this.VIEWS = {
      DAILY: 0x00,
      WEEKLY: 0x01,
      MONTHLY: 0x02
    };
    this.FREQUENCIES = {
      DAILY: 'd',
      WEEKLY: 'w',
      MONTHLY: 'm'
    };
    this.WEEK_DAYS = {
      MONDAY: {
        value: 1,
        label: l.schedule_day_control_mon
      },
      TUESDAY: {
        value: 2,
        label: l.schedule_day_control_tue
      },
      WEDNESDAY: {
        value: 3,
        label: l.schedule_day_control_wed
      },
      THURSDAY: {
        value: 4,
        label: l.schedule_day_control_thu
      },
      FRIDAY: {
        value: 5,
        label: l.schedule_day_control_fri
      },
      SATURDAY: {
        value: 6,
        label: l.schedule_day_control_sat
      },
      SUNDAY: {
        value: 7,
        label: l.schedule_day_control_sun
      }
    };
    this.OFFSETS = [[l.recur_freq_offset_first_mon || '[A]first[/A][B]Monday[/B]', l.recur_freq_offset_first_tue || '[A]first[/A][B]Tuesday[/B]', l.recur_freq_offset_first_wed || '[A]first[/A][B]Wednesday[/B]', l.recur_freq_offset_first_thu || '[A]first[/A][B]Thursday[/B]', l.recur_freq_offset_first_fri || '[A]first[/A][B]Friday[/B]', l.recur_freq_offset_first_sat || '[A]first[/A][B]Saturday[/B]', l.recur_freq_offset_first_sun || '[A]first[/A][B]Sunday[/B]'], [l.recur_freq_offset_second_mon || '[A]second[/A][B]Monday[/B]', l.recur_freq_offset_second_tue || '[A]second[/A][B]Tuesday[/B]', l.recur_freq_offset_second_wed || '[A]second[/A][B]Wednesday[/B]', l.recur_freq_offset_second_thu || '[A]second[/A][B]Thursday[/B]', l.recur_freq_offset_second_fri || '[A]second[/A][B]Friday[/B]', l.recur_freq_offset_second_sat || '[A]second[/A][B]Saturday[/B]', l.recur_freq_offset_second_sun || '[A]second[/A][B]Sunday[/B]'], [l.recur_freq_offset_third_mon || '[A]third[/A][B]Monday[/B]', l.recur_freq_offset_third_tue || '[A]third[/A][B]Tuesday[/B]', l.recur_freq_offset_third_wed || '[A]third[/A][B]Wednesday[/B]', l.recur_freq_offset_third_thu || '[A]third[/A][B]Thursday[/B]', l.recur_freq_offset_third_fri || '[A]third[/A][B]Friday[/B]', l.recur_freq_offset_third_sat || '[A]third[/A][B]Saturday[/B]', l.recur_freq_offset_third_sun || '[A]third[/A][B]Sunday[/B]'], [l.recur_freq_offset_fourth_mon || '[A]fourth[/A][B]Monday[/B]', l.recur_freq_offset_fourth_tue || '[A]fourth[/A][B]Tuesday[/B]', l.recur_freq_offset_fourth_wed || '[A]fourth[/A][B]Wednesday[/B]', l.recur_freq_offset_fourth_thu || '[A]fourth[/A][B]Thursday[/B]', l.recur_freq_offset_fourth_fri || '[A]fourth[/A][B]Friday[/B]', l.recur_freq_offset_fourth_sat || '[A]fourth[/A][B]Saturday[/B]', l.recur_freq_offset_fourth_sun || '[A]fourth[/A][B]Sunday[/B]'], [l.recur_freq_offset_fifth_mon || '[A]fifth[/A][B]Monday[/B]', l.recur_freq_offset_fifth_tue || '[A]fifth[/A][B]Tuesday[/B]', l.recur_freq_offset_fifth_wed || '[A]fifth[/A][B]Wednesday[/B]', l.recur_freq_offset_fifth_thu || '[A]fifth[/A][B]Thursday[/B]', l.recur_freq_offset_fifth_fri || '[A]fifth[/A][B]Friday[/B]', l.recur_freq_offset_fifth_sat || '[A]fifth[/A][B]Saturday[/B]', l.recur_freq_offset_fifth_sun || '[A]fifth[/A][B]Sunday[/B]']];
    this.OFFSET_POS_REGEX = /\[A]([^[]+)\[\/A]/;
    this.OFFSET_DAY_REGEX = /\[B]([^[]+)\[\/B]/;
    this.MONTH_RULES = {
      DAY: 'day',
      OFFSET: 'offset'
    };
    this.initialEnd = (0,helpers.PS)(this.props.startDateTime, 6);
    this.initialWeekDays = Object.values(this.WEEK_DAYS).map(d => d.value);
    this.initialMonthDay = this.props.startDateTime ? new Date(this.props.startDateTime).getDate() : undefined;
    this.state = {
      view: this.VIEWS.DAILY,
      frequency: this.FREQUENCIES.DAILY,
      end: this.initialEnd,
      prevEnd: undefined,
      interval: 0,
      weekDays: this.initialWeekDays,
      monthRule: this.MONTH_RULES.DAY,
      monthDays: [this.initialMonthDay],
      offset: {
        value: 1,
        weekDay: 1
      },
      monthDaysWarning: this.initialMonthDay > 28
    };
    this.toggleView = (view, frequency, state) => this.props.isLoading ? null : this.setState({
      view,
      frequency,
      ...state
    });
    this.MonthDaySelect = ({
      offset
    }) => {
      const dayIdx = (offset && offset.weekDay || 1) - 1;
      const posIdx = (offset && offset.value || 1) - 1;
      const dayValues = this.OFFSETS[posIdx].map((part, idx) => ({
        value: idx + 1,
        label: this.OFFSET_DAY_REGEX.exec(part)[1]
      }));
      const posValues = [];
      for (let i = 0; i < this.OFFSETS.length; i++) {
        posValues.push({
          value: i + 1,
          label: this.OFFSET_POS_REGEX.exec(this.OFFSETS[i][dayIdx])[1]
        });
      }
      const posFirst = this.OFFSETS[posIdx][dayIdx].indexOf('[A]') < this.OFFSETS[posIdx][dayIdx].indexOf('[B]');
      const pos = REaCt().createElement(schedule_select, {
        name: "recurring-offset-value",
        className: "inline",
        icon: true,
        value: posValues[posIdx].label,
        isLoading: this.props.isLoading,
        options: posValues,
        onSelect: option => {
          this.setState(state => ({
            monthRule: this.MONTH_RULES.OFFSET,
            offset: {
              value: option.value,
              weekDay: state.offset.weekDay || this.WEEK_DAYS.MONDAY.value
            }
          }));
        }
      });
      return REaCt().createElement(REaCt().Fragment, null, posFirst && pos, REaCt().createElement(schedule_select, {
        name: "recurring-offset-day",
        className: "inline",
        icon: true,
        value: dayValues[dayIdx].label,
        isLoading: this.props.isLoading,
        options: dayValues,
        onSelect: option => {
          this.setState(state => ({
            monthRule: this.MONTH_RULES.OFFSET,
            offset: {
              value: state.offset.value || 1,
              weekDay: option.value
            }
          }));
        }
      }), !posFirst && pos);
    };
    this.IntervalSelect = () => {
      const {
        interval,
        view
      } = this.state;
      return REaCt().createElement("div", {
        className: "mega-input inline recurring-interval"
      }, REaCt().createElement(schedule_select, {
        name: `${Recurring.NAMESPACE}-interval`,
        value: interval > 0 ? interval : 1,
        icon: true,
        isLoading: this.props.isLoading,
        options: [...Array(view === this.VIEWS.WEEKLY ? 52 : 12).keys()].map(value => {
          value += 1;
          return {
            value,
            label: value
          };
        }),
        onSelect: ({
          value
        }) => {
          this.setState({
            interval: value === 1 ? 0 : value
          });
        }
      }));
    };
    const {
      chatRoom,
      startDateTime
    } = this.props;
    const weekDay = new Date(startDateTime).getDay();
    this.state.offset.weekDay = ((_Object$values$find = Object.values(this.WEEK_DAYS).find(d => d.value === weekDay)) == null ? void 0 : _Object$values$find.value) || this.WEEK_DAYS.SUNDAY.value;
    if (chatRoom && chatRoom.scheduledMeeting && chatRoom.scheduledMeeting.isRecurring) {
      const {
        frequency,
        interval,
        end,
        weekDays,
        monthDays,
        offset
      } = chatRoom.scheduledMeeting.recurring;
      this.state.view = frequency === 'd' ? this.VIEWS.DAILY : frequency === 'w' ? this.VIEWS.WEEKLY : this.VIEWS.MONTHLY;
      this.state.frequency = frequency;
      this.state.end = end;
      this.state.interval = interval;
      this.state.weekDays = weekDays && weekDays.length ? weekDays : this.initialWeekDays;
      this.state.monthRule = monthDays && monthDays.length ? this.MONTH_RULES.DAY : this.MONTH_RULES.OFFSET;
      this.state.monthDays = monthDays && monthDays.length ? [monthDays[0]] : [this.initialMonthDay];
      this.state.offset = offset && Object.keys(offset).length ? offset : this.state.offset;
    }
  }
  getFormattedState(state) {
    const {
      frequency,
      end,
      interval,
      weekDays,
      monthRule,
      monthDays,
      offset
    } = state;
    switch (true) {
      case frequency === this.FREQUENCIES.DAILY:
        return {
          frequency,
          end,
          weekDays
        };
      case frequency === this.FREQUENCIES.WEEKLY:
        return {
          frequency,
          end,
          ...interval && {
            interval
          },
          weekDays
        };
      case frequency === this.FREQUENCIES.MONTHLY:
        return {
          frequency,
          end,
          ...interval && {
            interval
          },
          ...monthRule === this.MONTH_RULES.DAY ? {
            monthDays
          } : {
            offset: [[offset.value, offset.weekDay]]
          }
        };
    }
  }
  renderDayControls() {
    const {
      weekDays,
      view
    } = this.state;
    const handleWeeklySelection = (weekDay, remove) => {
      this.setState(state => {
        if (remove) {
          return {
            weekDays: state.weekDays.length === 1 ? state.weekDays : state.weekDays.filter(d => d !== weekDay)
          };
        }
        return {
          weekDays: [...state.weekDays, weekDay]
        };
      }, () => {
        const {
          weekDays
        } = this.state;
        if (weekDays.length === Object.keys(this.WEEK_DAYS).length) {
          this.toggleView(this.VIEWS.DAILY, this.FREQUENCIES.DAILY);
        }
      });
    };
    const handleDailySelection = weekDay => {
      this.toggleView(this.VIEWS.WEEKLY, this.FREQUENCIES.WEEKLY, {
        weekDays: weekDays.filter(d => d !== weekDay)
      });
    };
    return REaCt().createElement("div", {
      className: "recurring-field-row"
    }, Object.values(this.WEEK_DAYS).map(({
      value,
      label
    }) => {
      const isCurrentlySelected = weekDays.includes(value);
      return REaCt().createElement(meetings_button.A, {
        key: value,
        className: `
                                mega-button
                                action
                                recurring-toggle-button
                                ${isCurrentlySelected ? 'active' : ''}
                                ${weekDays.length === 1 && isCurrentlySelected ? 'disabled' : ''}
                            `,
        onClick: this.props.isLoading ? null : () => {
          if (view === this.VIEWS.WEEKLY) {
            return handleWeeklySelection(value, isCurrentlySelected);
          }
          return handleDailySelection(value);
        }
      }, label);
    }));
  }
  renderIntervalControls() {
    const {
      view,
      interval
    } = this.state;
    return REaCt().createElement("div", {
      className: "recurring-field-row"
    }, (0,utils.lI)(mega.icu.format(view === this.VIEWS.MONTHLY ? l.recur_rate_monthly : l.recur_rate_weekly, interval > 0 ? interval : 1), "[S]", this.IntervalSelect));
  }
  renderEndControls() {
    const {
      isLoading,
      onMount
    } = this.props;
    const {
      end,
      prevEnd
    } = this.state;
    return REaCt().createElement("div", {
      className: "recurring-field-row"
    }, REaCt().createElement("div", {
      className: "recurring-title-heading"
    }, l.recurring_ends), REaCt().createElement("div", {
      className: "recurring-radio-buttons"
    }, REaCt().createElement("div", {
      className: "recurring-label-wrap"
    }, REaCt().createElement("div", {
      className: `
                                uiTheme
                                ${end ? 'radioOff' : 'radioOn'}
                            `
    }, REaCt().createElement("input", {
      type: "radio",
      name: `${Recurring.NAMESPACE}-radio-end`,
      disabled: isLoading,
      className: `
                                    uiTheme
                                    ${end ? 'radioOff' : 'radioOn'}
                                `,
      onChange: () => {
        this.setState(state => ({
          end: undefined,
          prevEnd: state.end || state.prevEnd
        }));
      }
    })), REaCt().createElement("div", {
      className: "radio-txt"
    }, REaCt().createElement("span", {
      className: "recurring-radio-label",
      onClick: () => isLoading ? null : this.setState(state => ({
        end: undefined,
        prevEnd: state.end || state.prevEnd
      }))
    }, l.recurring_never))), REaCt().createElement("div", {
      className: "recurring-label-wrap"
    }, REaCt().createElement("div", {
      className: `
                                uiTheme
                                ${end ? 'radioOn' : 'radioOff'}
                            `
    }, REaCt().createElement("input", {
      type: "radio",
      name: `${Recurring.NAMESPACE}-radio-end`,
      disabled: isLoading,
      className: `
                                    uiTheme
                                    ${end ? 'radioOn' : 'radioOff'}
                                `,
      onChange: () => isLoading ? null : this.setState({
        end: prevEnd || this.initialEnd
      })
    })), REaCt().createElement("div", {
      className: "radio-txt"
    }, REaCt().createElement("span", {
      className: "recurring-radio-label",
      onClick: () => isLoading || end ? null : this.setState({
        end: prevEnd || this.initialEnd
      })
    }, l.recurring_on), REaCt().createElement(datepicker, {
      name: `${Recurring.NAMESPACE}-endDateTime`,
      position: "top left",
      startDate: end || this.initialEnd,
      selectedDates: [new Date(end)],
      isLoading,
      value: end || prevEnd || '',
      placeholder: time2date(end || prevEnd || this.initialEnd / 1000, 18),
      onMount,
      onSelect: timestamp => this.setState({
        end: timestamp
      }, () => this.safeForceUpdate())
    })))));
  }
  renderDaily() {
    return REaCt().createElement("div", {
      className: `${Recurring.NAMESPACE}-daily`
    }, this.renderDayControls(), this.renderEndControls());
  }
  renderWeekly() {
    return REaCt().createElement("div", {
      className: `${Recurring.NAMESPACE}-weekly`
    }, this.renderIntervalControls(), this.renderDayControls(), this.renderEndControls());
  }
  renderMonthly() {
    const {
      isLoading
    } = this.props;
    const {
      monthRule,
      monthDays,
      monthDaysWarning,
      offset
    } = this.state;
    return REaCt().createElement("div", {
      className: `${Recurring.NAMESPACE}-monthly`
    }, this.renderIntervalControls(), REaCt().createElement("div", {
      className: "recurring-field-row"
    }, REaCt().createElement("div", {
      className: "recurring-radio-buttons",
      onClick: isLoading ? null : ev => {
        const {
          name,
          value
        } = ev.target;
        if (name === `${Recurring.NAMESPACE}-radio-monthRule`) {
          this.setState({
            monthRule: value
          });
        }
      }
    }, REaCt().createElement("div", {
      className: "recurring-label-wrap"
    }, REaCt().createElement("div", {
      className: `
                                    uiTheme
                                    ${monthRule === 'day' ? 'radioOn' : 'radioOff'}
                                `
    }, REaCt().createElement("input", {
      type: "radio",
      name: `${Recurring.NAMESPACE}-radio-monthRule`,
      value: "day",
      disabled: isLoading,
      className: `
                                        uiTheme
                                        ${monthRule === 'day' ? 'radioOn' : 'radioOff'}
                                    `
    })), REaCt().createElement("div", {
      className: "radio-txt"
    }, REaCt().createElement("span", {
      className: "recurring-radio-label",
      onClick: () => isLoading ? null : this.setState({
        monthRule: this.MONTH_RULES.DAY
      })
    }, l.recurring_frequency_day), REaCt().createElement("div", {
      className: "mega-input inline recurring-day"
    }, REaCt().createElement(schedule_select, {
      name: `${Recurring.NAMESPACE}-monthDay`,
      icon: true,
      value: monthDays[0],
      isLoading,
      options: [...Array(31).keys()].map(value => {
        value += 1;
        return {
          value,
          label: value
        };
      }),
      onSelect: ({
        value
      }) => {
        this.setState({
          monthRule: this.MONTH_RULES.DAY,
          monthDays: [value],
          monthDaysWarning: value > 28
        });
      }
    })))), monthDaysWarning && REaCt().createElement("div", {
      className: "recurring-label-wrap"
    }, REaCt().createElement("div", {
      className: "mega-banner body with-btn"
    }, REaCt().createElement("div", {
      className: "green-notification cell text-cell"
    }, REaCt().createElement("div", {
      className: "versioning-body-text"
    }, mega.icu.format(l.recurring_monthdays_warning, monthDays[0]))))), REaCt().createElement("div", {
      className: "recurring-label-wrap"
    }, REaCt().createElement("div", {
      className: `
                                    uiTheme
                                    ${monthRule === this.MONTH_RULES.OFFSET ? 'radioOn' : 'radioOff'}
                                `
    }, REaCt().createElement("input", {
      type: "radio",
      name: `${Recurring.NAMESPACE}-radio-monthRule`,
      value: "offset",
      disabled: isLoading,
      className: `
                                        uiTheme
                                        ${monthRule === this.MONTH_RULES.OFFSET ? 'radioOn' : 'radioOff'}
                                    `
    })), REaCt().createElement("div", {
      className: "radio-txt"
    }, REaCt().createElement(this.MonthDaySelect, {
      offset
    }))))), this.renderEndControls());
  }
  renderNavigation(view) {
    return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(meetings_button.A, {
      className: `
                        mega-button
                        action
                        recurring-nav-button
                        ${view === this.VIEWS.DAILY ? 'active' : ''}
                    `,
      onClick: () => this.toggleView(this.VIEWS.DAILY, this.FREQUENCIES.DAILY)
    }, l.recurring_daily), REaCt().createElement(meetings_button.A, {
      className: `
                        mega-button
                        action
                        recurring-nav-button
                        ${view === this.VIEWS.WEEKLY ? 'active' : ''}
                    `,
      onClick: () => this.toggleView(this.VIEWS.WEEKLY, this.FREQUENCIES.WEEKLY)
    }, l.recurring_weekly), REaCt().createElement(meetings_button.A, {
      className: `
                        mega-button
                        action
                        recurring-nav-button
                        ${view === this.VIEWS.MONTHLY ? 'active' : ''}
                    `,
      onClick: () => this.toggleView(this.VIEWS.MONTHLY, this.FREQUENCIES.MONTHLY)
    }, l.recurring_monthly));
  }
  renderContent(view) {
    switch (view) {
      case this.VIEWS.DAILY:
        return this.renderDaily();
      case this.VIEWS.WEEKLY:
        return this.renderWeekly();
      case this.VIEWS.MONTHLY:
        return this.renderMonthly();
    }
  }
  UNSAFE_componentWillUpdate(nextProps, nextState) {
    if (this.state.view !== this.VIEWS.DAILY && nextState.view === this.VIEWS.DAILY) {
      nextState.weekDays = this.initialWeekDays;
    }
    if (nextState.weekDays.length === Object.keys(this.WEEK_DAYS).length && this.state.view !== this.VIEWS.WEEKLY && nextState.view === this.VIEWS.WEEKLY || !(0,helpers.ro)(nextProps.startDateTime, this.props.startDateTime) && this.state.view === this.VIEWS.WEEKLY) {
      const weekday = new Date(nextProps.startDateTime).getDay();
      nextState.weekDays = [weekday === 0 ? 7 : weekday];
    }
    if (!(0,helpers.ro)(nextProps.startDateTime, this.props.startDateTime) && this.state.view === this.VIEWS.MONTHLY) {
      let _Object$values$find2;
      const nextDate = new Date(nextProps.startDateTime);
      nextState.monthDays = [nextDate.getDate()];
      nextState.offset.weekDay = ((_Object$values$find2 = Object.values(this.WEEK_DAYS).find(d => d.value === nextDate.getDay())) == null ? void 0 : _Object$values$find2.value) || this.WEEK_DAYS.SUNDAY.value;
      nextState.monthDaysWarning = nextState.monthDays > 28;
    }
    if (nextState.view === this.VIEWS.MONTHLY && this.state.interval > 12) {
      nextState.interval = 12;
    }
    this.props.onUpdate(this.getFormattedState(nextState));
  }
  componentDidMount() {
    super.componentDidMount();
    this.props.onUpdate(this.getFormattedState(this.state));
  }
  render() {
    const {
      NAMESPACE
    } = Recurring;
    const {
      view
    } = this.state;
    return REaCt().createElement(Row, null, REaCt().createElement(Column, null), REaCt().createElement(Column, null, REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                            ${NAMESPACE}
                            ${this.props.isLoading ? 'disabled' : ''}
                        `
    }, REaCt().createElement("div", {
      className: `${NAMESPACE}-container`
    }, REaCt().createElement("div", {
      className: `${NAMESPACE}-navigation`
    }, this.renderNavigation(view)), REaCt().createElement("div", {
      className: `${NAMESPACE}-content`
    }, this.renderContent(view))))));
  }
}
Recurring.NAMESPACE = 'meetings-recurring';
class Edit extends mixins.w9 {
  constructor(props) {
    super(props);
    this.occurrenceRef = null;
    this.datepickerRefs = [];
    this.interval = ChatRoom.SCHEDULED_MEETINGS_INTERVAL;
    this.incomingCallListener = 'onPrepareIncomingCallDialog.recurringEdit';
    this.state = {
      startDateTime: undefined,
      endDateTime: undefined,
      isDirty: false,
      closeDialog: false,
      overlayed: false
    };
    this.onStartDateSelect = startDateTime => {
      this.setState({
        startDateTime,
        isDirty: true
      }, () => {
        this.datepickerRefs.endDateTime.selectDate(new Date(startDateTime + this.interval));
      });
    };
    this.onEndDateSelect = endDateTime => {
      this.setState({
        endDateTime,
        isDirty: true
      }, () => {
        const {
          startDateTime,
          endDateTime
        } = this.state;
        if (endDateTime < startDateTime) {
          if (endDateTime < Date.now()) {
            return this.setState({
              endDateTime: startDateTime + this.interval
            });
          }
          this.handleTimeSelect({
            startDateTime: endDateTime - this.interval
          });
        }
      });
    };
    this.handleTimeSelect = ({
      startDateTime,
      endDateTime
    }) => {
      startDateTime = startDateTime || this.state.startDateTime;
      endDateTime = endDateTime || this.state.endDateTime;
      this.setState(state => {
        return {
          startDateTime: endDateTime <= state.startDateTime ? endDateTime - this.interval : startDateTime,
          endDateTime: startDateTime >= state.endDateTime ? startDateTime + this.interval : endDateTime,
          isDirty: true
        };
      });
    };
    const {
      scheduledMeeting,
      occurrenceId
    } = this.props;
    this.occurrenceRef = scheduledMeeting.occurrences[occurrenceId];
    if (this.occurrenceRef) {
      this.state.startDateTime = this.occurrenceRef.start;
      this.state.endDateTime = this.occurrenceRef.end;
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    if (this.incomingCallListener) {
      megaChat.off(this.incomingCallListener);
    }
    if ($.dialog === Schedule.dialogName) {
      closeDialog();
    }
  }
  componentDidMount() {
    super.componentDidMount();
    M.safeShowDialog(Schedule.dialogName, () => {
      if (!this.isMounted()) {
        throw Error(`Edit dialog: component not mounted.`);
      }
      megaChat.rebind(this.incomingCallListener, () => {
        if (this.isMounted()) {
          this.setState({
            overlayed: true,
            closeDialog: false
          });
          megaChat.plugins.callManager2.rebind('onRingingStopped.recurringEdit', () => {
            megaChat.plugins.callManager2.off('onRingingStopped.recurringEdit');
            this.setState({
              overlayed: false
            });
            fm_showoverlay();
          });
        }
      });
      return $(`#${Schedule.NAMESPACE}`);
    });
  }
  componentDidUpdate(prevProps) {
    if (prevProps.callExpanded && !this.props.callExpanded) {
      if (!$.dialog) {
        M.safeShowDialog(Schedule.dialogName, `#${Schedule.NAMESPACE}`);
      }
      fm_showoverlay();
      this.setState({
        closeDialog: false
      });
    }
    if (!prevProps.callExpanded && this.props.callExpanded) {
      this.setState({
        closeDialog: false
      });
    }
  }
  render() {
    const {
      chatRoom,
      callExpanded,
      onClose
    } = this.props;
    const {
      startDateTime,
      endDateTime,
      isDirty,
      closeDialog,
      overlayed
    } = this.state;
    const dialogClasses = ['fluid'];
    if (closeDialog) {
      dialogClasses.push('with-confirmation-dialog');
    }
    if (callExpanded || overlayed) {
      dialogClasses.push('hidden');
    }
    const withUpgrade = !u_attr.p && endDateTime - startDateTime > 36e5;
    if (withUpgrade) {
      dialogClasses.push('upgrade');
    }
    return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
      id: Schedule.NAMESPACE,
      className: dialogClasses.join(' '),
      dialogName: Schedule.dialogName,
      dialogType: "main",
      onClose: () => {
        return isDirty ? this.setState({
          closeDialog: true
        }) : onClose();
      }
    }), REaCt().createElement("header", null, REaCt().createElement("h2", null, l.edit_meeting_title)), REaCt().createElement("div", {
      className: "fm-dialog-body"
    }, REaCt().createElement(Row, null, REaCt().createElement("div", {
      className: "mega-banner body recurring-edit-banner"
    }, REaCt().createElement("div", {
      className: "cell"
    }, (0,utils.lI)(l.scheduled_edit_occurrence_note, '[A]', ui_link.A, {
      onClick: () => {
        onClose();
        megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS.EDIT, chatRoom);
      }
    })))), REaCt().createElement(Row, {
      className: "start-aligned"
    }, REaCt().createElement(Column, null, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-recents-filled"
    })), REaCt().createElement("div", {
      className: "schedule-date-container"
    }, REaCt().createElement(DateTime, {
      name: "startDateTime",
      altField: "startTime",
      datepickerRef: this.datepickerRefs.startDateTime,
      startDate: startDateTime,
      value: startDateTime,
      filteredTimeIntervals: (0,helpers.a4)(startDateTime),
      label: l.schedule_start_date,
      onMount: datepicker => {
        this.datepickerRefs.startDateTime = datepicker;
      },
      onSelectDate: startDateTime => this.onStartDateSelect(startDateTime),
      onSelectTime: ({
        value: startDateTime
      }) => this.handleTimeSelect({
        startDateTime
      }),
      onChange: value => this.setState({
        startDateTime: value
      }),
      onBlur: timestamp => {
        if (timestamp) {
          timestamp = timestamp < Date.now() ? this.occurrenceRef.start : timestamp;
          this.onStartDateSelect(timestamp);
        }
      }
    }), REaCt().createElement(DateTime, {
      name: "endDateTime",
      altField: "endTime",
      datepickerRef: this.datepickerRefs.endDateTime,
      startDate: endDateTime,
      value: endDateTime,
      filteredTimeIntervals: (0,helpers.a4)(endDateTime, startDateTime),
      label: l.schedule_end_date,
      onMount: datepicker => {
        this.datepickerRefs.endDateTime = datepicker;
      },
      onSelectDate: endDateTime => this.onEndDateSelect(endDateTime),
      onSelectTime: ({
        value: endDateTime
      }) => this.handleTimeSelect({
        endDateTime
      }),
      onChange: timestamp => this.setState({
        endDateTime: timestamp
      }),
      onBlur: timestamp => timestamp && this.onEndDateSelect(timestamp)
    }))), withUpgrade && REaCt().createElement(UpgradeNotice, {
      onUpgradeClicked: () => {
        onClose();
        loadSubPage('pro');
        eventlog(500257);
      }
    })), REaCt().createElement("footer", null, REaCt().createElement("div", {
      className: "footer-container"
    }, REaCt().createElement(meetings_button.A, {
      className: "mega-button positive",
      onClick: () => {
        const {
          startDateTime,
          endDateTime
        } = this.state;
        if (startDateTime !== this.occurrenceRef.start || endDateTime !== this.occurrenceRef.end) {
          delay('chat-event-sm-edit-meeting', () => eventlog(99923));
          this.occurrenceRef.update(startDateTime, endDateTime);
        }
        onClose();
      }
    }, REaCt().createElement("span", null, l.update_meeting_button)))), !(overlayed || callExpanded) && closeDialog && REaCt().createElement(CloseDialog, {
      onToggle: () => this.setState({
        closeDialog: false
      }),
      onClose
    }));
  }
}
// EXTERNAL MODULE: ./js/chat/chatRoom.jsx + 1 modules
const chat_chatRoom = REQ_(553);
;// ./js/chat/ui/meetings/schedule/schedule.jsx

let _Schedule;












class Schedule extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.scheduledMeetingRef = null;
    this.localStreamRef = '.float-video';
    this.datepickerRefs = [];
    this.incomingCallListener = 'onPrepareIncomingCallDialog.scheduleDialog';
    this.ringingStoppedListener = 'onRingingStopped.scheduleDialog';
    this.interval = ChatRoom.SCHEDULED_MEETINGS_INTERVAL;
    this.nearestHalfHour = (0,helpers.i_)();
    this.state = {
      topic: '',
      startDateTime: this.nearestHalfHour,
      endDateTime: this.nearestHalfHour + this.interval,
      timezone: (0,helpers.dB)(),
      recurring: false,
      participants: [],
      link: false,
      sendInvite: false,
      waitingRoom: false,
      openInvite: false,
      description: '',
      closeDialog: false,
      isEdit: false,
      isDirty: false,
      isLoading: false,
      topicInvalid: false,
      invalidTopicMsg: '',
      descriptionInvalid: false,
      overlayed: false
    };
    this.onTopicChange = value => {
      if (value.length > ChatRoom.TOPIC_MAX_LENGTH) {
        this.setState({
          invalidTopicMsg: l.err_schedule_title_long,
          topicInvalid: true
        });
        value = value.substring(0, ChatRoom.TOPIC_MAX_LENGTH);
      } else if (value.length === 0) {
        this.setState({
          invalidTopicMsg: l.schedule_title_missing,
          topicInvalid: true
        });
      } else if (this.state.invalidTopicMsg) {
        this.setState({
          invalidTopicMsg: '',
          topicInvalid: false
        });
      }
      this.handleChange('topic', value);
    };
    this.onTextareaChange = value => {
      if (value.length > 3000) {
        this.setState({
          descriptionInvalid: true
        });
        value = value.substring(0, 3000);
      } else if (this.state.descriptionInvalid) {
        this.setState({
          descriptionInvalid: false
        });
      }
      this.handleChange('description', value);
    };
    this.onStartDateSelect = () => {
      this.datepickerRefs.endDateTime.selectDate(new Date(this.state.startDateTime + this.interval));
    };
    this.onEndDateSelect = () => {
      const {
        startDateTime,
        endDateTime
      } = this.state;
      if (endDateTime < startDateTime) {
        if (endDateTime < Date.now()) {
          return this.setState({
            endDateTime: startDateTime + this.interval
          });
        }
        this.handleDateSelect({
          startDateTime: endDateTime - this.interval
        });
      }
    };
    this.handleToggle = prop => {
      return Object.keys(this.state).includes(prop) && this.setState(state => ({
        [prop]: !state[prop],
        isDirty: true
      }));
    };
    this.handleChange = (prop, value) => {
      return Object.keys(this.state).includes(prop) && this.setState({
        [prop]: value,
        isDirty: true
      });
    };
    this.handleDateSelect = ({
      startDateTime,
      endDateTime
    }, callback) => {
      this.setState(state => ({
        startDateTime: startDateTime || state.startDateTime,
        endDateTime: endDateTime || state.endDateTime,
        isDirty: true
      }), () => {
        const {
          recurring
        } = this.state;
        if (recurring && recurring.end) {
          const recurringEnd = (0,helpers.PS)(this.state.startDateTime, 6);
          this.datepickerRefs.recurringEnd.selectDate(new Date(recurringEnd));
        }
        if (callback) {
          callback();
        }
      });
    };
    this.handleTimeSelect = ({
      startDateTime,
      endDateTime
    }) => {
      startDateTime = startDateTime || this.state.startDateTime;
      endDateTime = endDateTime || this.state.endDateTime;
      this.setState(state => {
        return {
          startDateTime: endDateTime <= state.startDateTime ? endDateTime - this.interval : startDateTime,
          endDateTime: startDateTime >= state.endDateTime ? startDateTime + this.interval : endDateTime,
          isDirty: true
        };
      });
    };
    this.handleParticipantSelect = participants => {
      return participants && Array.isArray(participants) && this.setState({
        participants,
        isDirty: true
      }, () => {
        const domRef = this.domRef && this.domRef.current;
        if (domRef) {
          domRef.reinitialise();
        }
      });
    };
    this.handleSubmit = () => {
      if (this.state.topic) {
        return this.setState({
          isLoading: true
        }, async () => {
          const {
            chatRoom,
            onClose
          } = this.props;
          const params = [this.state, chatRoom];
          if (chatRoom) {
            delay('chat-event-sm-edit-meeting', () => eventlog(99923));
          } else {
            delay('chat-event-sm-button-create', () => eventlog(99922));
          }
          delay('chat-events-sm-settings', () => this.submitStateEvents({
            ...this.state
          }));
          await megaChat.plugins.meetingsManager[chatRoom ? 'updateMeeting' : 'createMeeting'](...params);
          this.setState({
            isLoading: false
          }, () => {
            onClose();
            megaChat.trigger(conversations_EVENTS.NAV_RENDER_VIEW, VIEWS.MEETINGS);
          });
        });
      }
      return this.setState({
        topicInvalid: true,
        invalidTopicMsg: l.schedule_title_missing
      });
    };
  }
  syncPublicLink() {
    if (this.state.isEdit) {
      const {
        chatRoom
      } = this.props;
      chatRoom.updatePublicHandle().then(() => this.isMounted() && this.setState({
        link: !!chatRoom.publicLink
      })).catch(dump);
    }
  }
  getFilteredTimeIntervals(timestamp, offsetFrom) {
    const timeIntervals = (0,helpers.a4)(timestamp, offsetFrom);
    const {
      end
    } = this.scheduledMeetingRef || {};
    if (this.state.isEdit && end < Date.now()) {
      return timeIntervals;
    }
    return timeIntervals.filter(o => {
      return offsetFrom ? o.value > this.nearestHalfHour : o.value > Date.now();
    });
  }
  submitStateEvents(state) {
    if (state.link) {
      eventlog(500162);
    }
    if (state.sendInvite) {
      eventlog(500163);
    }
    if (state.waitingRoom) {
      eventlog(500164);
    }
    if (state.openInvite) {
      eventlog(500165);
    }
    if (state.description) {
      eventlog(500166);
    }
    if (state.recurring) {
      eventlog(500167);
    } else {
      eventlog(500168);
    }
    eventlog(500169, state.topic.length);
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    if ($.dialog === Schedule.dialogName) {
      closeDialog();
    }
    [document, this.localStreamRef].map(el => $(el).unbind(`.${Schedule.NAMESPACE}`));
    megaChat.off(this.incomingCallListener);
  }
  UNSAFE_componentWillMount() {
    const {
      chatRoom
    } = this.props;
    if (chatRoom) {
      const {
        scheduledMeeting,
        publicLink,
        options
      } = chatRoom;
      this.state.topic = scheduledMeeting.title;
      this.state.startDateTime = scheduledMeeting.start;
      this.state.endDateTime = scheduledMeeting.end;
      this.state.timezone = scheduledMeeting.timezone || (0,helpers.dB)();
      this.state.recurring = scheduledMeeting.recurring;
      this.state.participants = chatRoom.getParticipantsExceptMe();
      this.state.link = !!publicLink;
      this.state.description = scheduledMeeting.description || '';
      this.state.sendInvite = scheduledMeeting.flags;
      this.state.waitingRoom = options[chat_chatRoom.MCO_FLAGS.WAITING_ROOM];
      this.state.openInvite = options[chat_chatRoom.MCO_FLAGS.OPEN_INVITE];
      this.state.isEdit = true;
      this.scheduledMeetingRef = scheduledMeeting;
    }
  }
  componentDidMount() {
    super.componentDidMount();
    this.syncPublicLink();
    if ($.dialog === 'onboardingDialog') {
      closeDialog();
    }
    M.safeShowDialog(Schedule.dialogName, () => {
      if (!this.isMounted()) {
        throw new Error(`${Schedule.dialogName} dialog: component ${Schedule.NAMESPACE} not mounted.`);
      }
      $(document).rebind(`keyup.${Schedule.NAMESPACE}`, ({
        keyCode,
        target
      }) => {
        return this.state.closeDialog || target instanceof HTMLTextAreaElement ? null : keyCode === 13 && this.handleSubmit();
      });
      $(this.localStreamRef).rebind(`click.${Schedule.NAMESPACE}`, () => {
        if (this.state.isDirty) {
          this.handleToggle('closeDialog');
          return false;
        }
      });
      megaChat.rebind(this.incomingCallListener, () => {
        if (this.isMounted()) {
          this.setState({
            overlayed: true,
            closeDialog: false
          });
          megaChat.plugins.callManager2.rebind(this.ringingStoppedListener, () => {
            megaChat.plugins.callManager2.off(this.ringingStoppedListener);
            this.setState({
              overlayed: false
            });
            fm_showoverlay();
          });
        }
      });
      return $(`#${Schedule.NAMESPACE}`);
    });
  }
  componentDidUpdate(prevProps) {
    if (prevProps.callExpanded && !this.props.callExpanded) {
      if (!$.dialog) {
        M.safeShowDialog(Schedule.dialogName, `#${Schedule.NAMESPACE}`);
      }
      fm_showoverlay();
      this.setState({
        closeDialog: false
      });
    }
    if (!prevProps.callExpanded && this.props.callExpanded) {
      this.setState({
        closeDialog: false
      });
    }
  }
  render() {
    let _this$props$chatRoom;
    const {
      topic,
      startDateTime,
      endDateTime,
      recurring,
      participants,
      link,
      sendInvite,
      waitingRoom,
      openInvite,
      description,
      closeDialog,
      isEdit,
      isDirty,
      isLoading,
      topicInvalid,
      invalidTopicMsg,
      descriptionInvalid,
      overlayed
    } = this.state;
    return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
      id: Schedule.NAMESPACE,
      className: `
                    ${closeDialog ? 'with-confirmation-dialog' : ''}
                    ${this.props.callExpanded || overlayed ? 'hidden' : ''}
                `,
      dialogName: Schedule.dialogName,
      dialogType: "main",
      onClose: () => isDirty ? this.handleToggle('closeDialog') : this.props.onClose()
    }), REaCt().createElement(Header, {
      chatRoom: isEdit && this.props.chatRoom
    }), REaCt().createElement(perfectScrollbar.O, {
      ref: this.domRef,
      className: "fm-dialog-body",
      options: {
        suppressScrollX: true
      }
    }, REaCt().createElement(Input, {
      name: "topic",
      placeholder: l.schedule_title_input,
      value: topic,
      invalid: topicInvalid,
      invalidMessage: invalidTopicMsg,
      autoFocus: true,
      isLoading,
      onFocus: () => topicInvalid && this.setState({
        topicInvalid: false
      }),
      onChange: this.onTopicChange
    }), REaCt().createElement(Row, {
      className: `unencrypted-warning-row ${topicInvalid ? 'with-topic-err' : ''}`
    }, REaCt().createElement(Column, null), REaCt().createElement(Column, null, REaCt().createElement("div", {
      className: "unencrypted-warning"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-info"
    }), REaCt().createElement("span", null, l.schedule_encryption_note)))), REaCt().createElement(Row, {
      className: "start-aligned"
    }, REaCt().createElement(Column, null, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-recents-filled"
    })), REaCt().createElement("div", {
      className: "schedule-date-container"
    }, REaCt().createElement(DateTime, {
      name: "startDateTime",
      altField: "startTime",
      datepickerRef: this.datepickerRefs.startDateTime,
      startDate: startDateTime,
      value: startDateTime,
      filteredTimeIntervals: this.getFilteredTimeIntervals(startDateTime),
      label: l.schedule_start_date,
      isLoading,
      onMount: datepicker => {
        this.datepickerRefs.startDateTime = datepicker;
      },
      onSelectDate: startDateTime => {
        this.handleDateSelect({
          startDateTime
        }, this.onStartDateSelect);
      },
      onSelectTime: ({
        value: startDateTime
      }) => this.handleTimeSelect({
        startDateTime
      }),
      onChange: value => this.handleChange('startDateTime', value),
      onBlur: timestamp => {
        if (timestamp) {
          const startDateTime = timestamp < Date.now() ? this.nearestHalfHour : timestamp;
          this.handleDateSelect({
            startDateTime
          }, this.onStartDateSelect);
        }
      }
    }), REaCt().createElement(DateTime, {
      name: "endDateTime",
      altField: "endTime",
      datepickerRef: this.datepickerRefs.endDateTime,
      isLoading,
      startDate: endDateTime,
      value: endDateTime,
      filteredTimeIntervals: this.getFilteredTimeIntervals(endDateTime, startDateTime),
      label: l.schedule_end_date,
      onMount: datepicker => {
        this.datepickerRefs.endDateTime = datepicker;
      },
      onSelectDate: endDateTime => {
        this.handleDateSelect({
          endDateTime
        }, this.onEndDateSelect);
      },
      onSelectTime: ({
        value: endDateTime
      }) => this.handleTimeSelect({
        endDateTime
      }),
      onChange: value => this.handleChange('endDateTime', value),
      onBlur: timestamp => {
        this.handleDateSelect({
          endDateTime: timestamp
        }, this.onEndDateSelect);
      }
    }))), !u_attr.p && endDateTime - startDateTime > 36e5 && REaCt().createElement(UpgradeNotice, {
      onUpgradeClicked: () => {
        this.props.onClose();
        loadSubPage('pro');
        eventlog(500258);
      }
    }), REaCt().createElement(Checkbox, {
      name: "recurring",
      checked: recurring,
      label: l.schedule_recurring_label,
      isLoading,
      onToggle: prop => {
        this.handleToggle(prop);
        delay('chat-event-sm-recurring', () => eventlog(99919));
      }
    }), recurring && REaCt().createElement(Recurring, {
      chatRoom: this.props.chatRoom,
      startDateTime,
      endDateTime,
      isLoading,
      onMount: datepicker => {
        this.datepickerRefs.recurringEnd = datepicker;
      },
      onUpdate: state => {
        this.setState({
          recurring: state
        });
      }
    }), REaCt().createElement(Row, null, REaCt().createElement(Column, null, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-contacts"
    })), REaCt().createElement(Column, null, REaCt().createElement(Invite, {
      className: isLoading ? 'disabled' : '',
      isLoading,
      participants,
      onSelect: this.handleParticipantSelect
    }))), REaCt().createElement(Switch, {
      name: "link",
      toggled: link,
      label: l.schedule_link_label,
      isLoading,
      subLabel: l.schedule_link_info,
      onToggle: prop => {
        this.handleToggle(prop);
        delay('chat-event-sm-meeting-link', () => eventlog(99920));
      }
    }), REaCt().createElement(Checkbox, {
      name: "sendInvite",
      checked: sendInvite,
      label: l.schedule_invite_label,
      isLoading,
      onToggle: prop => {
        this.handleToggle(prop);
        delay('chat-event-sm-calendar-invite', () => eventlog(99921));
      }
    }), REaCt().createElement(Checkbox, {
      name: "waitingRoom",
      className: (_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.havePendingCall() ? 'disabled' : '',
      checked: waitingRoom,
      label: l.waiting_room,
      subLabel: l.waiting_room_info,
      isLoading,
      onToggle: waitingRoom => {
        let _this$props$chatRoom2;
        if ((_this$props$chatRoom2 = this.props.chatRoom) != null && _this$props$chatRoom2.havePendingCall()) {
          return;
        }
        this.handleToggle(waitingRoom);
        delay('chat-event-sm-waiting-room', () => eventlog(500297));
      }
    }), REaCt().createElement(Checkbox, {
      name: "openInvite",
      checked: openInvite,
      label: l.open_invite_desc,
      isLoading,
      onToggle: ev => {
        this.handleToggle(ev);
        delay('chat-event-sm-open-invite', () => eventlog(500298));
      }
    }), waitingRoom && openInvite ? REaCt().createElement(Row, null, REaCt().createElement("div", {
      className: "schedule-dialog-banner warn"
    }, REaCt().createElement(utils.P9, null, l.waiting_room_invite.replace('[A]', `<a
                                                href="${l.mega_help_host}/wp-admin/post.php?post=3005&action=edit"
                                                target="_blank"
                                                class="clickurl">
                                            `).replace('[/A]', '</a>')))) : null, REaCt().createElement(Textarea, {
      name: "description",
      isLoading,
      invalid: descriptionInvalid,
      placeholder: l.schedule_description_input,
      value: description,
      onFocus: () => descriptionInvalid && this.setState({
        descriptionInvalid: false
      }),
      onChange: this.onTextareaChange
    })), REaCt().createElement(Footer, {
      isLoading,
      isEdit,
      topic,
      onSubmit: this.handleSubmit
    }), !(overlayed || this.props.callExpanded) && closeDialog && REaCt().createElement(CloseDialog, {
      onToggle: this.handleToggle,
      onClose: this.props.onClose
    }));
  }
}
_Schedule = Schedule;
Schedule.NAMESPACE = 'schedule-dialog';
Schedule.dialogName = `meetings-${_Schedule.NAMESPACE}`;
window.ScheduleMeetingDialogUI = {
  Schedule
};
const CloseDialog = ({
  onToggle,
  onClose
}) => {
  return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(modalDialogs.A.ModalDialog, {
    name: `${Schedule.NAMESPACE}-confirmation`,
    dialogType: "message",
    className: `
                    with-close-btn
                    ${Schedule.NAMESPACE}-confirmation
                `,
    title: l.schedule_discard_dlg_title,
    icon: "sprite-fm-uni icon-question",
    buttons: [{
      key: 'n',
      label: l.schedule_discard_cancel,
      onClick: () => onToggle('closeDialog')
    }, {
      key: 'y',
      label: l.schedule_discard_confirm,
      className: 'positive',
      onClick: onClose
    }],
    noCloseOnClickOutside: true,
    stopKeyPropagation: true,
    hideOverlay: true,
    onClose: () => onToggle('closeDialog')
  }), REaCt().createElement("div", {
    className: `${Schedule.NAMESPACE}-confirmation-overlay`,
    onClick: () => onToggle('closeDialog')
  }));
};
const Row = ({
  children,
  className
}) => REaCt().createElement("div", {
  className: `
            ${Schedule.NAMESPACE}-row
            ${className || ''}
        `
}, children);
const Column = ({
  children,
  className
}) => REaCt().createElement("div", {
  className: `
            ${Schedule.NAMESPACE}-column
            ${className || ''}
        `
}, children);
const Header = ({
  chatRoom
}) => {
  const $$container = title => REaCt().createElement("header", null, REaCt().createElement("h2", null, title));
  if (chatRoom) {
    const {
      scheduledMeeting
    } = chatRoom;
    return $$container(scheduledMeeting.isRecurring ? l.edit_meeting_series_title : l.edit_meeting_title);
  }
  return $$container(l.schedule_meeting_title);
};
const Input = ({
  name,
  placeholder,
  value,
  invalid,
  invalidMessage,
  autoFocus,
  isLoading,
  onFocus,
  onChange
}) => {
  return REaCt().createElement(Row, {
    className: invalid ? 'invalid-aligned' : ''
  }, REaCt().createElement(Column, null, REaCt().createElement("i", {
    className: "sprite-fm-mono icon-rename"
  })), REaCt().createElement(Column, null, REaCt().createElement("div", {
    className: `
                        mega-input
                        ${invalid ? 'error msg' : ''}
                    `
  }, REaCt().createElement("input", {
    type: "text",
    name: `${Schedule.NAMESPACE}-${name}`,
    className: isLoading ? 'disabled' : '',
    disabled: isLoading,
    autoFocus,
    autoComplete: "off",
    placeholder,
    value,
    onFocus,
    onChange: ({
      target
    }) => onChange(target.value)
  }), invalid && REaCt().createElement("div", {
    className: "message-container mega-banner"
  }, invalidMessage))));
};
const Checkbox = ({
  name,
  className,
  checked,
  label,
  subLabel,
  isLoading,
  onToggle
}) => {
  return REaCt().createElement(Row, {
    className: `
                ${subLabel ? 'start-aligned' : ''}
                ${className || ''}
            `
  }, REaCt().createElement(Column, null, REaCt().createElement("div", {
    className: `
                        checkdiv
                        ${checked ? 'checkboxOn' : 'checkboxOff'}
                        ${isLoading ? 'disabled' : ''}
                    `
  }, REaCt().createElement("input", {
    name: `${Schedule.NAMESPACE}-${name}`,
    disabled: isLoading,
    type: "checkbox",
    onChange: () => onToggle(name)
  }))), REaCt().createElement(Column, {
    className: subLabel ? 'with-sub-label' : ''
  }, REaCt().createElement("label", {
    htmlFor: `${Schedule.NAMESPACE}-${name}`,
    className: isLoading ? 'disabled' : '',
    onClick: () => isLoading ? null : onToggle(name)
  }, label), subLabel && REaCt().createElement("div", {
    className: "sub-label"
  }, subLabel)));
};
const Switch = ({
  name,
  toggled,
  label,
  isLoading,
  subLabel,
  onToggle
}) => {
  const className = `${Schedule.NAMESPACE}-switch`;
  return REaCt().createElement(Row, null, REaCt().createElement(Column, null, REaCt().createElement("i", {
    className: "sprite-fm-uni icon-mega-logo"
  })), REaCt().createElement(Column, {
    className: subLabel ? `with-sub-label ${className}` : className
  }, REaCt().createElement("span", {
    className: `
                        schedule-label
                        ${isLoading ? 'disabled' : ''}
                    `,
    onClick: () => isLoading ? null : onToggle(name)
  }, label), REaCt().createElement("div", {
    className: `
                        mega-switch
                        ${toggled ? 'toggle-on' : ''}
                        ${isLoading ? 'disabled' : ''}
                    `,
    onClick: () => isLoading ? null : onToggle(name)
  }, REaCt().createElement("div", {
    className: `
                            mega-feature-switch
                            sprite-fm-mono-after
                            ${toggled ? 'icon-check-after' : 'icon-minimise-after'}
                        `
  })), subLabel && REaCt().createElement("div", {
    className: "sub-label"
  }, subLabel)));
};
const Textarea = ({
  name,
  placeholder,
  isLoading,
  value,
  invalid,
  onChange,
  onFocus
}) => {
  return REaCt().createElement(Row, {
    className: "start-aligned"
  }, REaCt().createElement(Column, null, REaCt().createElement("i", {
    className: "sprite-fm-mono icon-description"
  })), REaCt().createElement(Column, null, REaCt().createElement("div", {
    className: `mega-input box-style textarea ${invalid ? 'error' : ''}`
  }, REaCt().createElement("textarea", {
    name: `${Schedule.NAMESPACE}-${name}`,
    className: isLoading ? 'disabled' : '',
    placeholder,
    value,
    readOnly: isLoading,
    onChange: ({
      target
    }) => onChange(target.value),
    onFocus
  })), invalid && REaCt().createElement("div", {
    className: "mega-input error msg textarea-error"
  }, REaCt().createElement("div", {
    className: "message-container mega-banner"
  }, l.err_schedule_desc_long))));
};
const Footer = ({
  isLoading,
  isEdit,
  topic,
  onSubmit
}) => {
  return REaCt().createElement("footer", null, REaCt().createElement("div", {
    className: "footer-container"
  }, REaCt().createElement(meetings_button.A, {
    className: `
                        mega-button
                        positive
                        ${isLoading ? 'disabled' : ''}
                    `,
    onClick: () => isLoading ? null : onSubmit(),
    topic
  }, REaCt().createElement("span", null, isEdit ? l.update_meeting_button : l.schedule_meeting_button))));
};
const UpgradeNotice = ({
  onUpgradeClicked
}) => {
  return !!mega.flags.ff_chmon && REaCt().createElement(Row, {
    className: "schedule-upgrade-notice"
  }, REaCt().createElement("h3", null, l.schedule_limit_title), REaCt().createElement("div", null, l.schedule_limit_upgrade_features), REaCt().createElement(meetings_button.A, {
    className: "mega-button positive",
    onClick: onUpgradeClicked
  }, REaCt().createElement("span", null, l.upgrade_now)));
};
// EXTERNAL MODULE: ./js/ui/miniui.jsx
const miniui = REQ_(818);
;// ./js/chat/ui/startGroupChatWizard.jsx
const React = REQ_(594);




class StartGroupChatWizard extends mixins.w9 {
  constructor(props) {
    super(props);
    this.dialogName = 'start-group-chat';
    this.domRef = React.createRef();
    this.inputContainerRef = React.createRef();
    this.inputRef = React.createRef();
    let haveContacts = false;
    const keys = M.u.keys();
    for (let i = 0; i < keys.length; i++) {
      if (M.u[keys[i]].c === 1) {
        haveContacts = true;
        break;
      }
    }
    this.state = {
      'selected': this.props.selected ? this.props.selected : [],
      haveContacts,
      'step': this.props.flowType === 2 || !haveContacts ? 1 : 0,
      'keyRotation': false,
      'createChatLink': this.props.flowType === 2,
      'groupName': '',
      openInvite: 1
    };
    this.onFinalizeClick = this.onFinalizeClick.bind(this);
    this.onSelectClicked = this.onSelectClicked.bind(this);
    this.onSelected = this.onSelected.bind(this);
  }
  onSelected(nodes) {
    this.setState({
      'selected': nodes
    });
    if (this.props.onSelected) {
      this.props.onSelected(nodes);
    }
  }
  onSelectClicked() {
    if (this.props.onSelectClicked) {
      this.props.onSelectClicked();
    }
  }
  onFinalizeClick(e) {
    if (e) {
      e.preventDefault();
      e.stopPropagation();
    }
    const {
      groupName,
      selected,
      keyRotation,
      createChatLink,
      openInvite
    } = this.state;
    megaChat.createAndShowGroupRoomFor(selected, groupName.trim(), {
      keyRotation,
      createChatLink: keyRotation ? false : createChatLink,
      openInvite
    });
    this.props.onClose(this);
    eventlog(500236);
  }
  componentDidMount() {
    super.componentDidMount();
    if (!this.props.subDialog) {
      M.safeShowDialog(this.dialogName, nop);
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    if ($.dialog === this.dialogName) {
      closeDialog();
    }
  }
  render() {
    const self = this;
    const classes = `new-group-chat contrast small-footer contact-picker-widget ${  self.props.className}`;
    let contacts = M.u;
    const {haveContacts} = self.state;
    const buttons = [];
    let allowNext = false;
    let failedToEnableChatlink = self.state.failedToEnableChatlink && self.state.createChatLink === true && !self.state.groupName;
    if (self.state.keyRotation) {
      failedToEnableChatlink = false;
    }
    let extraContent;
    if (this.props.extraContent) {
      self.state.step = 0;
      extraContent = React.createElement("div", {
        className: "content-block imported"
      });
    } else if (self.state.step === 0 && haveContacts) {
      allowNext = true;
      buttons.push({
        "label": self.props.cancelLabel,
        "key": "cancel",
        "onClick" (e) {
          self.props.onClose(self);
          e.preventDefault();
          e.stopPropagation();
        }
      });
      buttons.push({
        "label": l[556],
        "key": "next",
        "className": !allowNext ? "disabled positive" : "positive",
        "onClick" (e) {
          e.preventDefault();
          e.stopPropagation();
          self.setState({
            'step': 1
          });
        }
      });
    } else if (self.state.step === 1) {
      allowNext = self.state.createChatLink ? !failedToEnableChatlink : true;
      contacts = [];
      self.state.selected.forEach((h) => {
        if (h in M.u) {
          contacts.push(M.u[h]);
        }
      });
      if (!haveContacts || this.props.flowType === 2) {
        buttons.push({
          "label": self.props.cancelLabel,
          "key": "cancel",
          "onClick" (e) {
            self.props.onClose(self);
            e.preventDefault();
            e.stopPropagation();
          }
        });
      } else {
        buttons.push({
          "label": l[822],
          "key": "back",
          "onClick" (e) {
            e.preventDefault();
            e.stopPropagation();
            self.setState({
              'step': 0
            });
          }
        });
      }
      buttons.push({
        "label": l[726],
        "key": "done",
        "className": !allowNext ? "positive disabled" : "positive",
        "onClick" (e) {
          if (self.state.createChatLink === true && !self.state.groupName) {
            self.setState({
              'failedToEnableChatlink': true
            });
          } else {
            self.onFinalizeClick(e);
          }
        }
      });
    }
    let chatInfoElements;
    if (self.state.step === 1) {
      let _this$state$groupName;
      let checkboxClassName = self.state.createChatLink ? "checkboxOn" : "checkboxOff";
      if (failedToEnableChatlink && self.state.createChatLink) {
        checkboxClassName += " intermediate-state";
      }
      if (self.state.keyRotation) {
        checkboxClassName = "checkboxOff";
      }
      chatInfoElements = React.createElement(React.Fragment, null, React.createElement("div", {
        className: `
                            contacts-search-header left-aligned top-pad
                            ${failedToEnableChatlink ? 'failed' : ''}
                        `
      }, React.createElement("div", {
        className: `
                                mega-input
                                with-icon
                                box-style
                                ${((_this$state$groupName = this.state.groupName) == null ? void 0 : _this$state$groupName.length) > 0 ? 'valued' : ''}
                                ${failedToEnableChatlink ? 'error msg' : ''}
                            `,
        ref: this.inputContainerRef
      }, React.createElement("i", {
        className: "sprite-fm-mono icon-channel-new"
      }), React.createElement("input", {
        autoFocus: true,
        className: "megaInputs",
        type: "text",
        ref: this.inputRef,
        placeholder: l[18509],
        value: this.state.groupName,
        maxLength: ChatRoom.TOPIC_MAX_LENGTH,
        onKeyDown: e => {
          const code = e.which || e.keyCode;
          if (allowNext && code === 13 && self.state.step === 1) {
            this.onFinalizeClick();
          }
        },
        onChange: e => {
          const containerRef = this.inputContainerRef.current;
          const {
            value
          } = e.target;
          containerRef.classList[value.length > 0 ? 'add' : 'remove']('valued');
          this.setState({
            groupName: value,
            failedToEnableChatlink: false
          });
        }
      }))), this.props.flowType === 2 ? null : React.createElement("div", {
        className: "group-chat-dialog content"
      }, React.createElement(miniui.A.ToggleCheckbox, {
        className: "rotation-toggle",
        checked: this.state.keyRotation,
        onToggle: keyRotation => this.setState({
          keyRotation
        }, () => this.inputRef.current.focus())
      }), React.createElement("div", {
        className: "group-chat-dialog header"
      }, l[20576]), React.createElement("div", {
        className: "group-chat-dialog description"
      }, l[20484]), React.createElement(miniui.A.ToggleCheckbox, {
        className: "open-invite-toggle",
        checked: this.state.openInvite,
        value: this.state.openInvite,
        onToggle: openInvite => this.setState({
          openInvite
        }, () => this.inputRef.current.focus())
      }), React.createElement("div", {
        className: "group-chat-dialog header"
      }, l.open_invite_label), React.createElement("div", {
        className: "group-chat-dialog description"
      }, l.open_invite_desc), React.createElement("div", {
        className: `
                                    group-chat-dialog checkbox
                                    ${this.state.keyRotation ? 'disabled' : ''}
                                    ${failedToEnableChatlink ? 'failed' : ''}
                                `,
        onClick: () => {
          delay('chatWizard-createChatLink', () => {
            this.setState(state => ({
              createChatLink: !state.createChatLink
            }));
            this.inputRef.current.focus();
          }, 100);
        }
      }, React.createElement("div", {
        className: `checkdiv ${checkboxClassName}`
      }, React.createElement("input", {
        type: "checkbox",
        name: "group-encryption",
        id: "group-encryption",
        className: "checkboxOn hidden"
      })), React.createElement("label", {
        htmlFor: "group-encryption",
        className: "radio-txt lato mid"
      }, l[20575]), React.createElement("div", {
        className: "clear"
      }))), failedToEnableChatlink ? React.createElement("div", {
        className: "group-chat-dialog description chatlinks-intermediate-msg"
      }, l[20573]) : null);
    }
    return React.createElement(modalDialogs.A.ModalDialog, {
      step: self.state.step,
      title: this.props.flowType === 2 && self.state.createChatLink ? l[20638] : this.props.customDialogTitle || l[19483],
      className: classes,
      dialogType: "tool",
      dialogName: "group-chat-dialog",
      showSelectedNum: self.props.showSelectedNum,
      selectedNum: self.state.selected.length,
      closeDlgOnClickOverlay: self.props.closeDlgOnClickOverlay,
      onClose: () => {
        self.props.onClose(self);
      },
      popupDidMount: elem => {
        if (this.props.extraContent) {
          let _elem$querySelector;
          (_elem$querySelector = elem.querySelector('.content-block.imported')) == null || _elem$querySelector.appendChild(this.props.extraContent);
        }
        if (this.props.onExtraContentDidMount) {
          this.props.onExtraContentDidMount(elem);
        }
      },
      triggerResizeOnUpdate: true,
      buttons
    }, React.createElement("div", {
      ref: this.domRef,
      className: "content-block"
    }, chatInfoElements, React.createElement(ui_contacts.ContactPickerWidget, {
      step: self.state.step,
      exclude: self.props.exclude,
      contacts,
      selectableContacts: "true",
      onSelectDone: self.onSelectClicked,
      onSelected: self.onSelected,
      selected: self.state.selected,
      headerClasses: "left-aligned",
      multiple: true,
      readOnly: self.state.step !== 0,
      allowEmpty: true,
      showMeAsSelected: self.state.step === 1,
      className: self.props.pickerClassName,
      disableFrequents: self.props.disableFrequents,
      skipMailSearch: self.props.skipMailSearch,
      autoFocusSearchField: self.props.autoFocusSearchField,
      selectCleanSearchRes: self.props.selectCleanSearchRes,
      disableDoubleClick: self.props.disableDoubleClick,
      selectedWidthSize: self.props.selectedWidthSize,
      emptySelectionMsg: self.props.emptySelectionMsg,
      newEmptySearchResult: self.props.newEmptySearchResult,
      newNoContact: self.props.newNoContact,
      highlightSearchValue: self.props.highlightSearchValue,
      emailTooltips: self.props.emailTooltips
    })), extraContent);
  }
}
StartGroupChatWizard.clickTime = 0;
StartGroupChatWizard.defaultProps = {
  'selectLabel': l[1940],
  'cancelLabel': l.msg_dlg_cancel,
  'hideable': true,
  'flowType': 1,
  'pickerClassName': '',
  'showSelectedNum': false,
  'disableFrequents': false,
  'skipMailSearch': false,
  'autoFocusSearchField': true,
  'selectCleanSearchRes': true,
  'disableDoubleClick': false,
  'newEmptySearchResult': false,
  'newNoContact': false,
  'closeDlgOnClickOverlay': true,
  'emailTooltips': false
};
window.StartGroupChatDialogUI = {
  StartGroupChatWizard
};
const startGroupChatWizard = {
  StartGroupChatWizard
};
// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
const call = REQ_(3);
// EXTERNAL MODULE: ./js/chat/ui/chatToaster.jsx
const chatToaster = REQ_(424);
;// ./js/chat/ui/searchPanel/resultTable.jsx

const ResultTable = ({
  heading,
  children
}) => {
  return REaCt().createElement("div", {
    className: `result-table ${heading ? '' : 'nil'}`
  }, heading ? REaCt().createElement("div", {
    className: "result-table-heading"
  }, heading) : null, children);
};
const resultTable = ResultTable;
;// ./js/chat/ui/searchPanel/resultRow.jsx








const RESULT_ROW_CLASS = 'result-table-row';
const USER_CARD_CLASS = 'user-card';
const roomIsGroup = room => room && room.type === 'group' || room.type === 'public';
const openResult = ({
  room,
  messageId,
  index
}, callback) => {
  document.dispatchEvent(new Event(EVENTS.RESULT_OPEN));
  if (isString(room)) {
    loadSubPage(`fm/chat/p/${room}`);
  } else if (room && room.chatId && !messageId) {
    const chatRoom = megaChat.getChatById(room.chatId);
    if (chatRoom) {
      loadSubPage(chatRoom.getRoomUrl());
    } else {
      loadSubPage(`/fm/chat/contacts/${room.chatId}`);
    }
  } else {
    loadSubPage(room.getRoomUrl());
    if (messageId) {
      room.scrollToMessageId(messageId, index);
    }
  }
  return callback && typeof callback === 'function' && callback();
};
const lastActivity = room => {
  if (!room.lastActivity || !room.ctime) {
    room = megaChat.getChatById(room.chatId);
  }
  if (room && room.lastActivity || room.ctime) {
    return room.lastActivity ? todayOrYesterday(room.lastActivity * 1000) ? getTimeMarker(room.lastActivity) : time2date(room.lastActivity, 17) : todayOrYesterday(room.ctime * 1000) ? getTimeMarker(room.ctime) : time2date(room.ctime, 17);
  }
  return l[8000];
};
class MessageRow extends mixins.w9 {
  render() {
    const {
      data,
      matches,
      room,
      index,
      onResultOpen
    } = this.props;
    const isGroup = roomIsGroup(room);
    const contact = room.getParticipantsExceptMe();
    const summary = room.messagesBuff.getRenderableSummary(data);
    const date = todayOrYesterday(data.delay * 1000) ? getTimeMarker(data.delay) : time2date(data.delay, 17);
    return REaCt().createElement("div", {
      ref: node => {
        this.domRef = node;
      },
      className: `
                    ${RESULT_ROW_CLASS}
                    message
                `,
      onClick: () => openResult({
        room,
        messageId: data.messageId,
        index
      }, () => onResultOpen(this.domRef))
    }, REaCt().createElement("div", {
      className: "message-result-avatar"
    }, isGroup && REaCt().createElement("div", {
      className: "chat-topic-icon"
    }, REaCt().createElement("i", {
      className: "sprite-fm-uni icon-chat-group"
    })), room.isNote && REaCt().createElement("div", {
      className: "note-chat-signifier"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
    })), room.type === 'private' && REaCt().createElement(ui_contacts.Avatar, {
      contact: M.u[contact]
    })), REaCt().createElement("div", {
      className: "user-card"
    }, REaCt().createElement("span", {
      className: "title"
    }, isGroup && REaCt().createElement(utils.sp, null, room.getRoomTitle()), room.isNote && REaCt().createElement("span", null, l.note_label), room.type === 'private' && REaCt().createElement(ui_contacts.ContactAwareName, {
      contact: M.u[contact],
      overflow: true
    })), isGroup ? null : REaCt().createElement(ui_contacts.ContactPresence, {
      contact: M.u[contact]
    }), REaCt().createElement("div", {
      className: "clear"
    }), REaCt().createElement("div", {
      className: "message-result-info"
    }, REaCt().createElement("div", {
      className: "summary"
    }, REaCt().createElement(utils.oM, {
      content: megaChat.highlight(summary, matches, true)
    })), REaCt().createElement("div", {
      className: "result-separator"
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-dot"
    })), REaCt().createElement("span", {
      className: "date"
    }, date))));
  }
}
class ChatRow extends mixins.w9 {
  render() {
    const {
      room,
      matches,
      onResultOpen
    } = this.props;
    const result = megaChat.highlight(megaChat.html(room.getRoomTitle()), matches, true);
    return REaCt().createElement("div", {
      ref: node => {
        this.domRef = node;
      },
      className: RESULT_ROW_CLASS,
      onClick: () => openResult({
        room
      }, () => onResultOpen(this.domRef))
    }, REaCt().createElement("div", {
      className: "chat-topic-icon"
    }, REaCt().createElement("i", {
      className: "sprite-fm-uni icon-chat-group"
    })), REaCt().createElement("div", {
      className: USER_CARD_CLASS
    }, REaCt().createElement("div", {
      className: "graphic"
    }, REaCt().createElement(utils.oM, null, result)), REaCt().createElement("div", {
      className: "result-last-activity"
    }, lastActivity(room))), REaCt().createElement("div", {
      className: "clear"
    }));
  }
}
class MemberRow extends mixins.w9 {
  render() {
    const {
      data,
      matches,
      room,
      contact,
      onResultOpen
    } = this.props;
    const isGroup = room && roomIsGroup(room);
    return REaCt().createElement("div", {
      ref: node => {
        this.domRef = node;
      },
      className: RESULT_ROW_CLASS,
      onClick: () => openResult({
        room: room || contact.h
      }, () => onResultOpen(this.domRef))
    }, isGroup ? REaCt().createElement("div", {
      className: "chat-topic-icon"
    }, REaCt().createElement("i", {
      className: "sprite-fm-uni icon-chat-group"
    })) : REaCt().createElement(ui_contacts.Avatar, {
      contact
    }), REaCt().createElement("div", {
      className: USER_CARD_CLASS
    }, REaCt().createElement("div", {
      className: "graphic"
    }, isGroup ? REaCt().createElement(utils.oM, null, megaChat.highlight(megaChat.html(room.getRoomTitle()), matches, true)) : REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(utils.oM, null, megaChat.highlight(megaChat.html(nicknames.getNickname(data)), matches, true)), REaCt().createElement(ui_contacts.ContactPresence, {
      contact
    }))), lastActivity(room)), REaCt().createElement("div", {
      className: "clear"
    }));
  }
}
const NilRow = ({
  onSearchMessages,
  isFirstQuery
}) => {
  const label = LABEL.SEARCH_MESSAGES_INLINE.replace('[A]', '<a>').replace('[/A]', '</a>');
  return REaCt().createElement("div", {
    className: `
                ${RESULT_ROW_CLASS}
                nil
            `
  }, REaCt().createElement("div", {
    className: "nil-container"
  }, REaCt().createElement("i", {
    className: "sprite-fm-mono icon-preview-reveal"
  }), REaCt().createElement("span", null, LABEL.NO_RESULTS), isFirstQuery && REaCt().createElement("div", {
    className: "search-messages",
    onClick: onSearchMessages
  }, REaCt().createElement(utils.oM, {
    tag: "div",
    content: label
  }))));
};
class ResultRow extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.setActive = nodeRef => {
      if (nodeRef) {
        const elements = document.querySelectorAll(`.${RESULT_ROW_CLASS}.${"active"}`);
        for (let i = elements.length; i--;) {
          elements[i].classList.remove('active');
        }
        nodeRef.classList.add("active");
      }
    };
  }
  render() {
    const {
      type,
      result,
      children,
      onSearchMessages,
      isFirstQuery
    } = this.props;
    if (result) {
      const {
        data,
        index,
        matches,
        room
      } = result;
      const PROPS = {
        data,
        index,
        matches,
        room,
        onResultOpen: this.setActive
      };
      switch (type) {
        case TYPE.MESSAGE:
          return REaCt().createElement(MessageRow, PROPS);
        case TYPE.CHAT:
          return REaCt().createElement(ChatRow, PROPS);
        case TYPE.MEMBER:
          return REaCt().createElement(MemberRow, (0,esm_extends.A)({}, PROPS, {
            contact: M.u[data]
          }));
        default:
          return REaCt().createElement("div", {
            className: RESULT_ROW_CLASS
          }, children);
      }
    }
    return REaCt().createElement(NilRow, {
      onSearchMessages,
      isFirstQuery
    });
  }
}
;// ./js/chat/ui/searchPanel/resultContainer.jsx




const TYPE = {
  MESSAGE: 1,
  CHAT: 2,
  MEMBER: 3,
  NIL: 4
};
const LABEL = {
  MESSAGES: l[6868],
  CONTACTS_AND_CHATS: l[20174],
  NO_RESULTS: l[8674],
  SEARCH_MESSAGES_CTA: l[23547],
  SEARCH_MESSAGES_INLINE: l[23548],
  DECRYPTING_RESULTS: l[23543],
  PAUSE_SEARCH: l[23544],
  SEARCH_PAUSED: l[23549],
  SEARCH_COMPLETE: l[23546]
};
class ResultContainer extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.renderResults = (results, status, isFirstQuery, onSearchMessages) => {
      if (status === STATUS.COMPLETED && results.length < 1) {
        return REaCt().createElement(resultTable, null, REaCt().createElement(ResultRow, {
          type: TYPE.NIL,
          isFirstQuery,
          onSearchMessages
        }));
      }
      const RESULT_TABLE = {
        CONTACTS_AND_CHATS: [],
        MESSAGES: []
      };
      for (const resultTypeGroup in results) {
        if (results.hasOwnProperty(resultTypeGroup)) {
          const len = results[resultTypeGroup].length;
          for (let i = 0; i < len; i++) {
            const result = results[resultTypeGroup].getItem(i);
            const {
              MESSAGE,
              MEMBER,
              CHAT
            } = TYPE;
            const {
              resultId,
              type
            } = result;
            const table = type === MESSAGE ? 'MESSAGES' : 'CONTACTS_AND_CHATS';
            RESULT_TABLE[table] = [...RESULT_TABLE[table], REaCt().createElement(ResultRow, {
              key: resultId,
              type: type === MESSAGE ? MESSAGE : type === MEMBER ? MEMBER : CHAT,
              result
            })];
          }
        }
      }
      return Object.keys(RESULT_TABLE).map((key, index) => {
        const table = {
          ref: RESULT_TABLE[key],
          hasRows: RESULT_TABLE[key] && RESULT_TABLE[key].length,
          isEmpty: RESULT_TABLE[key] && RESULT_TABLE[key].length < 1,
          props: {
            key: index,
            heading: key === 'MESSAGES' ? LABEL.MESSAGES : LABEL.CONTACTS_AND_CHATS
          }
        };
        if (table.hasRows) {
          return REaCt().createElement(resultTable, table.props, table.ref.map(row => row));
        }
        if (status === STATUS.COMPLETED && key === 'MESSAGES') {
          const SEARCH_MESSAGES = REaCt().createElement("button", {
            className: "search-messages mega-button",
            onClick: onSearchMessages
          }, REaCt().createElement("span", null, LABEL.SEARCH_MESSAGES_CTA));
          const NO_RESULTS = REaCt().createElement(ResultRow, {
            type: TYPE.NIL,
            isFirstQuery,
            onSearchMessages
          });
          return REaCt().createElement(resultTable, table.props, isFirstQuery ? SEARCH_MESSAGES : NO_RESULTS);
        }
        return null;
      });
    };
  }
  render() {
    const {
      results,
      status,
      isFirstQuery,
      onSearchMessages
    } = this.props;
    return this.renderResults(results, status, isFirstQuery, onSearchMessages);
  }
}
;// ./js/chat/ui/searchPanel/searchField.jsx
let _SearchField;




const SEARCH_STATUS_CLASS = 'search-field-status';
const BASE_ICON_CLASS = 'sprite-fm-mono';
class SearchField extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.state = {
      hovered: false
    };
    this.renderStatusBanner = () => {
      switch (this.props.status) {
        case STATUS.IN_PROGRESS:
          return REaCt().createElement("div", {
            className: `${SEARCH_STATUS_CLASS} searching info`
          }, LABEL.DECRYPTING_RESULTS);
        case STATUS.PAUSED:
          return REaCt().createElement("div", {
            className: `${SEARCH_STATUS_CLASS} paused info`
          }, LABEL.SEARCH_PAUSED);
        case STATUS.COMPLETED:
          return REaCt().createElement("div", {
            className: `${SEARCH_STATUS_CLASS} complete success`
          }, LABEL.SEARCH_COMPLETE);
        default:
          return null;
      }
    };
    this.renderStatusControls = () => {
      const {
        status,
        onToggle
      } = this.props;
      const handleHover = () => this.setState(state => ({
        hovered: !state.hovered
      }));
      switch (status) {
        case STATUS.IN_PROGRESS:
          return REaCt().createElement("div", {
            className: "progress-controls",
            onClick: onToggle
          }, REaCt().createElement("i", {
            className: `${BASE_ICON_CLASS} icon-pause`
          }));
        case STATUS.PAUSED:
          return REaCt().createElement("i", {
            className: `${BASE_ICON_CLASS} icon-resume`,
            onClick: onToggle,
            onMouseOver: handleHover,
            onMouseOut: handleHover
          });
        case STATUS.COMPLETED:
          return null;
        default:
          return null;
      }
    };
  }
  componentDidMount() {
    super.componentDidMount();
    SearchField.focus();
  }
  render() {
    const {
      value,
      searching,
      status,
      onChange,
      onReset
    } = this.props;
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "search-field"
    }, REaCt().createElement("i", {
      className: `${BASE_ICON_CLASS} icon-preview-reveal search-icon-find`
    }), REaCt().createElement("input", {
      type: "search",
      autoComplete: "off",
      placeholder: l[102],
      ref: SearchField.inputRef,
      value,
      onChange: ev => {
        if (this.state.hovered) {
          this.setState({
            hovered: false
          });
        }
        onChange(ev);
      }
    }), searching && REaCt().createElement("i", {
      className: `
                            ${BASE_ICON_CLASS}
                            icon-close-component
                            search-icon-reset
                        `,
      onClick: onReset
    }), searching && status && REaCt().createElement(REaCt().Fragment, null, this.renderStatusControls(), this.renderStatusBanner()));
  }
}
_SearchField = SearchField;
SearchField.inputRef = REaCt().createRef();
SearchField.select = () => {
  const inputElement = _SearchField.inputRef && _SearchField.inputRef.current;
  const value = inputElement && inputElement.value;
  if (inputElement && value) {
    inputElement.selectionStart = 0;
    inputElement.selectionEnd = value.length;
  }
};
SearchField.focus = () => _SearchField.inputRef && _SearchField.inputRef.current && _SearchField.inputRef.current.focus();
SearchField.hasValue = () => _SearchField.inputRef && _SearchField.inputRef.current && !!_SearchField.inputRef.current.value.length;
SearchField.isVisible = () => _SearchField.inputRef && _SearchField.inputRef.current && elementIsVisible(_SearchField.inputRef.current);
;// ./js/chat/ui/searchPanel/searchPanel.jsx





const STATUS = {
  IN_PROGRESS: 1,
  PAUSED: 2,
  COMPLETED: 3
};
const EVENTS = {
  RESULT_OPEN: 'chatSearchResultOpen',
  KEYDOWN: 'keydown'
};
const ACTIONS = {
  PAUSE: 'pause',
  RESUME: 'resume'
};
const SEARCH_PANEL_CLASS = `search-panel`;
class SearchPanel extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.wrapperRef = null;
    this.state = {
      value: '',
      searching: false,
      status: undefined,
      isFirstQuery: true,
      results: []
    };
    this.unbindEvents = () => {
      if (this.pageChangeListener) {
        mBroadcaster.removeListener(this.pageChangeListener);
      }
      document.removeEventListener(EVENTS.RESULT_OPEN, this.doPause);
      document.removeEventListener(EVENTS.KEYDOWN, this.handleKeyDown);
      megaChat.plugins.chatdIntegration.chatd.off('onClose.search');
      megaChat.plugins.chatdIntegration.chatd.off('onOpen.search');
    };
    this.bindEvents = () => {
      this.pageChangeListener = mBroadcaster.addListener('pagechange', this.doPause);
      document.addEventListener(EVENTS.RESULT_OPEN, this.doPause);
      document.addEventListener(EVENTS.KEYDOWN, this.handleKeyDown);
      megaChat.plugins.chatdIntegration.chatd.rebind('onClose.search', () => this.state.searching && this.doToggle(ACTIONS.PAUSE));
      megaChat.plugins.chatdIntegration.chatd.rebind('onOpen.search', () => this.state.searching && this.doToggle(ACTIONS.RESUME));
    };
    this.doPause = () => {
      if (this.state.status === STATUS.IN_PROGRESS) {
        this.doToggle(ACTIONS.PAUSE);
      }
    };
    this.doSearch = (s, searchMessages) => {
      return ChatSearch.doSearch(s, (room, result, results) => this.setState({
        results
      }), searchMessages).catch(ex => d && console.error('Search failed (or was reset)', ex)).always(() => this.setState({
        status: STATUS.COMPLETED
      }));
    };
    this.doToggle = (action) => {
      const {
        IN_PROGRESS,
        PAUSED,
        COMPLETED
      } = STATUS;
      const searching = this.state.status === IN_PROGRESS || this.state.status === PAUSED;
      if (action && searching) {
        const chatSearch = ChatSearch.doSearch.cs;
        if (!chatSearch) {
          return delay('chat-toggle', () => this.doToggle(action), 600);
        }
        this.setState({
          status: action === ACTIONS.PAUSE ? PAUSED : action === ACTIONS.RESUME ? IN_PROGRESS : COMPLETED
        }, () => chatSearch[action]());
      }
    };
    this.doDestroy = () => ChatSearch && ChatSearch.doSearch && ChatSearch.doSearch.cs && ChatSearch.doSearch.cs.destroy();
    this.handleKeyDown = ev => {
      const {
        keyCode
      } = ev;
      if (keyCode && keyCode === 27) {
        return SearchField.hasValue() ? this.handleReset() : this.doPause();
      }
    };
    this.handleChange = ev => {
      if (SearchField.isVisible()) {
        const {
          value
        } = ev.target;
        const searching = value.length > 0;
        this.doDestroy();
        this.setState({
          value,
          searching,
          status: undefined,
          isFirstQuery: true,
          results: []
        }, () => {
          if (searching) {
            delay('chat-search', () => this.doSearch(value, false), 1600);
            if ($.dialog === 'onboardingDialog') {
              closeDialog();
            }
          } else {
            megaChat.plugins.chatOnboarding.checkAndShowStep();
          }
        });
        this.wrapperRef.scrollToY(0);
      }
    };
    this.handleToggle = () => {
      const inProgress = this.state.status === STATUS.IN_PROGRESS;
      this.setState({
        status: inProgress ? STATUS.PAUSED : STATUS.IN_PROGRESS
      }, () => {
        delay('chat-toggled', () => SearchField.focus());
        return this.doToggle(inProgress ? ACTIONS.PAUSE : ACTIONS.RESUME);
      });
    };
    this.handleReset = () => this.setState({
      value: '',
      searching: false,
      status: undefined,
      results: []
    }, () => {
      this.wrapperRef.scrollToY(0);
      onIdle(() => SearchField.focus());
      this.doDestroy();
    });
    this.handleSearchMessages = () => SearchField.hasValue() && this.setState({
      status: STATUS.IN_PROGRESS,
      isFirstQuery: false
    }, () => {
      this.doSearch(this.state.value, true);
      SearchField.focus();
      SearchField.select();
    });
  }
  componentDidMount() {
    super.componentDidMount();
    this.bindEvents();
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    this.unbindEvents();
  }
  render() {
    const {
      value,
      searching,
      status,
      isFirstQuery,
      results
    } = this.state;
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                    ${SEARCH_PANEL_CLASS}
                    ${searching ? 'expanded' : ''}
                `
    }, REaCt().createElement(SearchField, {
      value,
      searching,
      status,
      onChange: this.handleChange,
      onToggle: this.handleToggle,
      onReset: this.handleReset
    }), REaCt().createElement(perfectScrollbar.O, {
      className: "search-results-wrapper",
      ref: wrapper => {
        this.wrapperRef = wrapper;
      },
      options: {
        'suppressScrollX': true
      }
    }, searching && REaCt().createElement(ResultContainer, {
      status,
      results,
      isFirstQuery,
      onSearchMessages: this.handleSearchMessages
    })));
  }
}
;// ./js/chat/ui/leftPanel/navigation.jsx



const Navigation = ({
  view,
  views: {
    CHATS,
    MEETINGS
  },
  routingSection,
  unreadChats,
  unreadMeetings,
  contactRequests,
  renderView
}) => REaCt().createElement("div", {
  className: `${NAMESPACE}-nav`
}, REaCt().createElement("div", {
  className: `
                    ${NAMESPACE}-nav-container
                    ${NAMESPACE}-chats-tab
                    ${view === CHATS && routingSection === 'chat' ? 'active' : ''}
                `,
  onClick: () => {
    renderView(CHATS);
    eventlog(500233);
  }
}, REaCt().createElement(meetings_button.A, {
  unreadChats,
  className: `${NAMESPACE}-nav-button`,
  icon: "icon-chat-filled"
}, !!unreadChats && REaCt().createElement("div", {
  className: "notifications-count"
})), REaCt().createElement("span", null, l.chats)), REaCt().createElement("div", {
  className: `
                    ${NAMESPACE}-nav-container
                    ${NAMESPACE}-meetings-tab
                    ${view === MEETINGS && routingSection === 'chat' ? 'active' : ''}
                `,
  onClick: () => {
    renderView(MEETINGS);
    eventlog(500234);
  }
}, REaCt().createElement(meetings_button.A, {
  unreadMeetings,
  className: `${NAMESPACE}-nav-button`,
  icon: "icon-video-call-filled"
}, !!unreadMeetings && REaCt().createElement("div", {
  className: "notifications-count"
})), REaCt().createElement("span", null, l.meetings)), is_eplusplus || is_chatlink ? null : REaCt().createElement("div", {
  className: `
                        ${NAMESPACE}-nav-container
                        ${NAMESPACE}-contacts-tab
                        ${routingSection === 'contacts' ? 'active' : ''}
                    `,
  onClick: () => {
    loadSubPage('fm/chat/contacts');
    eventlog(500296);
  }
}, REaCt().createElement(meetings_button.A, {
  className: `${NAMESPACE}-nav-button`,
  contactRequests,
  icon: "icon-contacts"
}, !!contactRequests && REaCt().createElement("div", {
  className: "notifications-count"
})), REaCt().createElement("span", null, l[165])));
// EXTERNAL MODULE: ./js/ui/buttons.jsx
const buttons = REQ_(994);
// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
const dropdowns = REQ_(911);
;// ./js/chat/ui/leftPanel/actions.jsx




const Actions = ({
  view,
  views,
  filter,
  routingSection,
  startMeeting,
  scheduleMeeting,
  createNewChat,
  onFilter
}) => {
  const {
    CHATS,
    MEETINGS,
    LOADING
  } = views;
  if (is_eplusplus || is_chatlink) {
    return null;
  }
  return REaCt().createElement("div", {
    className: `${NAMESPACE}-action-buttons`
  }, view === LOADING && REaCt().createElement(buttons.$, {
    className: "mega-button action loading-sketch"
  }, REaCt().createElement("i", null), REaCt().createElement("span", null)), view === CHATS && routingSection !== 'contacts' && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(buttons.$, {
    className: "mega-button small positive new-chat-action",
    label: l.add_chat,
    onClick: () => {
      createNewChat();
      eventlog(500284);
    }
  }), REaCt().createElement("div", {
    className: "lhp-filter"
  }, REaCt().createElement("div", {
    className: "lhp-filter-control"
  }, REaCt().createElement(buttons.$, {
    icon: "sprite-fm-mono icon-sort-thin-solid"
  }, REaCt().createElement(dropdowns.Dropdown, {
    className: "light",
    noArrow: "true"
  }, REaCt().createElement(dropdowns.DropdownItem, {
    className: "link-button",
    icon: "sprite-fm-mono icon-eye-reveal",
    label: l.filter_unread,
    onClick: () => onFilter(FILTER.UNREAD)
  }), REaCt().createElement(dropdowns.DropdownItem, {
    className: "link-button",
    icon: "sprite-fm-mono icon-notification-off",
    label: view === MEETINGS ? l.filter_muted__meetings : l.filter_muted__chats,
    onClick: () => onFilter(FILTER.MUTED)
  })))), filter && REaCt().createElement(REaCt().Fragment, null, filter === FILTER.MUTED && REaCt().createElement("div", {
    className: "lhp-filter-tag",
    onClick: () => onFilter(FILTER.MUTED)
  }, REaCt().createElement("span", null, view === MEETINGS ? l.filter_muted__meetings : l.filter_muted__chats), REaCt().createElement("i", {
    className: "sprite-fm-mono icon-close-component"
  })), filter === FILTER.UNREAD && REaCt().createElement("div", {
    className: "lhp-filter-tag",
    onClick: () => onFilter(FILTER.UNREAD)
  }, REaCt().createElement("span", null, l.filter_unread), REaCt().createElement("i", {
    className: "sprite-fm-mono icon-close-component"
  }))))), view === MEETINGS && routingSection !== 'contacts' && REaCt().createElement(buttons.$, {
    className: "mega-button small positive new-meeting-action",
    label: l.new_meeting
  }, REaCt().createElement("i", {
    className: "dropdown-indicator sprite-fm-mono icon-arrow-down"
  }), REaCt().createElement(dropdowns.Dropdown, {
    className: "light",
    noArrow: "true",
    vertOffset: 4,
    positionMy: "left top",
    positionAt: "left bottom"
  }, REaCt().createElement(dropdowns.DropdownItem, {
    className: "link-button",
    icon: "sprite-fm-mono icon-video-plus",
    label: l.new_meeting_start,
    onClick: startMeeting
  }), REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
    className: "link-button",
    icon: "sprite-fm-mono icon-calendar2",
    label: l.schedule_meeting_start,
    onClick: scheduleMeeting
  }))), routingSection === 'contacts' && REaCt().createElement(buttons.$, {
    className: "mega-button small positive",
    label: l[71],
    onClick: () => {
      contactAddDialog();
      eventlog(500285);
    }
  }));
};
const actions = Actions;
// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
const applyDecoratedDescriptor = REQ_(793);
;// ./js/chat/ui/leftPanel/conversationsListItem.jsx

let _dec, _dec2, _class;




const ConversationsListItem = (_dec = utils.Ay.SoonFcWrap(40, true), _dec2 = (0,mixins.N9)(0.7, 8), _class = class ConversationsListItem extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
    this.state = {
      isLoading: true
    };
  }
  isLoading() {
    const mb = this.props.chatRoom.messagesBuff;
    if (mb.haveMessages) {
      return false;
    }
    return mb.messagesHistoryIsLoading() || mb.joined === false && mb.isDecrypting;
  }
  specShouldComponentUpdate() {
    return !this.state.isLoading;
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    this.props.chatRoom.unbind('onUnreadCountUpdate.conversationsListItem');
  }
  componentDidMount() {
    super.componentDidMount();
    this.eventuallyScrollTo();
    const promise = this.isLoading();
    if (promise && promise.always) {
      promise.always(() => {
        if (this.isMounted()) {
          this.setState({
            isLoading: false
          });
        }
      });
    } else if (promise === false) {
      this.setState({
        isLoading: false
      });
    }
    this.props.chatRoom.rebind('onUnreadCountUpdate.conversationsListItem', () => {
      this.safeForceUpdate();
    });
  }
  componentDidUpdate() {
    super.componentDidUpdate();
    this.eventuallyScrollTo();
  }
  eventuallyScrollTo() {
    const chatRoom = this.props.chatRoom || false;
    if (chatRoom._scrollToOnUpdate) {
      if (chatRoom.isCurrentlyActive) {
        chatRoom.scrollToChat();
      } else {
        chatRoom._scrollToOnUpdate = false;
      }
    }
  }
  getConversationTimestamp() {
    const {
      chatRoom
    } = this.props;
    if (chatRoom) {
      const lastMessage = chatRoom.messagesBuff.getLatestTextMessage();
      const timestamp = lastMessage && lastMessage.delay || chatRoom.ctime;
      return todayOrYesterday(timestamp * 1000) ? getTimeMarker(timestamp) : time2date(timestamp, 17);
    }
    return null;
  }
  getScheduledDateTime() {
    const {
      scheduledMeeting
    } = this.props.chatRoom;
    if (scheduledMeeting) {
      const {
        nextOccurrenceStart,
        nextOccurrenceEnd
      } = scheduledMeeting;
      return {
        date: time2date(nextOccurrenceStart / 1000, 19),
        startTime: toLocaleTime(nextOccurrenceStart),
        endTime: toLocaleTime(nextOccurrenceEnd)
      };
    }
  }
  render() {
    let classString = "";
    const {chatRoom} = this.props;
    if (!chatRoom || !chatRoom.chatId) {
      return null;
    }
    const roomId = chatRoom.chatId;
    if (chatRoom.isCurrentlyActive) {
      classString += " active";
    }
    let nameClassString = "user-card-name conversation-name selectable-txt";
    let contactId;
    let id;
    let contact;
    if (chatRoom.type === 'private') {
      const handle = chatRoom.getParticipantsExceptMe()[0];
      contact = handle ? M.u[handle] : M.u[u_handle];
      id = `conversation_${htmlentities(contact.u)}`;
    } else if (chatRoom.type === 'group') {
      contactId = roomId;
      id = `conversation_${contactId}`;
      classString += ' groupchat';
    } else if (chatRoom.type === 'public') {
      contactId = roomId;
      id = `conversation_${contactId}`;
      classString += ' groupchat public';
    } else {
      return `Unknown room type for ${chatRoom.roomId}`;
    }
    const unreadCount = chatRoom.messagesBuff.getUnreadCount();
    let isUnread = false;
    const notificationItems = [];
    if (chatRoom.havePendingCall() && chatRoom.state !== ChatRoom.STATE.LEFT) {
      notificationItems.push(REaCt().createElement("i", {
        className: "tiny-icon white-handset",
        key: "callIcon"
      }));
    }
    if (unreadCount > 0) {
      notificationItems.push(REaCt().createElement("span", {
        key: "unreadCounter"
      }, unreadCount > 9 ? "9+" : unreadCount));
      isUnread = true;
    }
    let lastMessageDiv = null;
    const showHideMsg = mega.config.get('showHideChat');
    const lastMessage = showHideMsg ? '' : chatRoom.messagesBuff.getLatestTextMessage();
    let lastMsgDivClasses;
    if (lastMessage) {
      lastMsgDivClasses = `conversation-message${  isUnread ? " unread" : ""}`;
      const renderableSummary = chatRoom.messagesBuff.getRenderableSummary(lastMessage);
      if (chatRoom.havePendingCall() || chatRoom.haveActiveCall()) {
        lastMsgDivClasses += " call";
        classString += " call-exists";
      }
      lastMessageDiv = REaCt().createElement("div", {
        className: lastMsgDivClasses
      }, REaCt().createElement(utils.P9, null, renderableSummary));
      if (lastMessage.textContents && lastMessage.textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.VOICE_CLIP && lastMessage.getAttachmentMeta()[0]) {
        const playTime = secondsToTimeShort(lastMessage.getAttachmentMeta()[0].playtime);
        lastMessageDiv = REaCt().createElement("div", {
          className: lastMsgDivClasses
        }, REaCt().createElement("i", {
          className: "sprite-fm-mono icon-audio-filled voice-message-icon"
        }), playTime);
      }
      if (lastMessage.metaType && lastMessage.metaType === Message.MESSAGE_META_TYPE.GEOLOCATION) {
        lastMessageDiv = REaCt().createElement("div", {
          className: lastMsgDivClasses
        }, REaCt().createElement("i", {
          className: "sprite-fm-mono icon-location geolocation-icon"
        }), l[20789]);
      }
    } else {
      lastMsgDivClasses = "conversation-message";
      lastMessageDiv = showHideMsg ? '' : REaCt().createElement("div", {
        className: lastMsgDivClasses
      }, this.state.isLoading ? l[7006] : l[8000]);
    }
    if (chatRoom.type !== 'public') {
      nameClassString += ' privateChat';
    }
    let roomTitle = REaCt().createElement(utils.oM, null, megaChat.html(chatRoom.getRoomTitle()));
    if (chatRoom.type === 'private') {
      roomTitle = megaChat.WITH_SELF_NOTE && chatRoom.isNote ? REaCt().createElement("span", {
        className: "note-chat-label"
      }, l.note_label) : REaCt().createElement("span", null, REaCt().createElement("div", {
        className: "user-card-wrapper"
      }, REaCt().createElement(utils.oM, null, megaChat.html(chatRoom.getRoomTitle()))));
    }
    nameClassString += chatRoom.type === "private" || chatRoom.type === "group" ? ' badge-pad' : '';
    const {
      scheduledMeeting,
      isMeeting
    } = chatRoom;
    const isUpcoming = scheduledMeeting && scheduledMeeting.isUpcoming;
    const {
      startTime,
      endTime
    } = this.getScheduledDateTime() || {};
    const isEmptyNote = chatRoom.isNote && !chatRoom.hasMessages();
    return REaCt().createElement("li", {
      ref: this.domRef,
      id,
      className: `
                    ${classString}
                    ${isUpcoming ? 'upcoming-conversation' : ''}
                    ${this.props.className || ''}
                `,
      "data-room-id": roomId,
      "data-jid": contactId,
      onClick: ev => {
        let _this$props$onConvers, _this$props;
        return ((_this$props$onConvers = (_this$props = this.props).onConversationClick) == null ? void 0 : _this$props$onConvers.call(_this$props, ev)) || loadSubPage(chatRoom.getRoomUrl(false));
      }
    }, REaCt().createElement("div", {
      className: "conversation-avatar"
    }, (chatRoom.type === 'group' || chatRoom.type === 'public') && REaCt().createElement("div", {
      className: `
                                chat-topic-icon
                                ${isMeeting ? 'meeting-icon' : ''}
                            `
    }, REaCt().createElement("i", {
      className: isMeeting ? 'sprite-fm-mono icon-video-call-filled' : 'sprite-fm-uni icon-chat-group'
    })), chatRoom.type === 'private' && contact && chatRoom.isNote ? REaCt().createElement("div", {
      className: `
                                    note-chat-signifier
                                    ${isEmptyNote ? 'note-chat-empty' : ''}
                                `
    }, REaCt().createElement("i", {
      className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
    })) : REaCt().createElement(ui_contacts.Avatar, {
      contact
    })), REaCt().createElement("div", {
      className: "conversation-data"
    }, REaCt().createElement("div", {
      className: "conversation-data-top"
    }, REaCt().createElement("div", {
      className: `conversation-data-name ${nameClassString}`
    }, roomTitle, chatRoom.isMuted() ? REaCt().createElement("i", {
      className: "sprite-fm-mono icon-notification-off-filled muted-conversation-icon"
    }) : null), chatRoom.isNote ? null : REaCt().createElement("div", {
      className: "conversation-data-badges"
    }, chatRoom.type === 'private' ? REaCt().createElement(ui_contacts.ContactPresence, {
      contact
    }) : null, chatRoom.type === 'group' || chatRoom.type === 'private' ? REaCt().createElement("i", {
      className: "sprite-fm-uni icon-ekr-key simpletip",
      "data-simpletip": l[20935]
    }) : null, scheduledMeeting && scheduledMeeting.isUpcoming && scheduledMeeting.isRecurring && REaCt().createElement("i", {
      className: "sprite-fm-mono icon-repeat-thin-solid"
    }))), REaCt().createElement("div", {
      className: "clear"
    }), isUpcoming ? REaCt().createElement("div", {
      className: "conversation-message-info"
    }, REaCt().createElement("div", {
      className: "conversation-scheduled-data"
    }, REaCt().createElement("span", null, startTime), REaCt().createElement("span", null, "\xA0 - \xA0"), REaCt().createElement("span", null, endTime)), REaCt().createElement("div", {
      className: "conversation-scheduled-data"
    }, notificationItems.length > 0 ? REaCt().createElement("div", {
      className: `
                                            unread-messages
                                            items-${notificationItems.length}
                                            unread-upcoming
                                            ${unreadCount > 9 && notificationItems.length > 1 ? 'unread-spaced' : ''}
                                        `
    }, notificationItems) : null)) : REaCt().createElement("div", {
      className: "conversation-message-info"
    }, isEmptyNote ? null : lastMessageDiv)), isUpcoming || isEmptyNote ? null : REaCt().createElement("div", {
      className: "date-time-wrapper"
    }, REaCt().createElement("div", {
      className: "date-time"
    }, this.getConversationTimestamp()), notificationItems.length > 0 ? REaCt().createElement("div", {
      className: `
                                    unread-messages-container
                                    ${unreadCount > 9 && notificationItems.length > 1 ? 'unread-spaced' : ''}
                                `
    }, REaCt().createElement("div", {
      className: `unread-messages items-${notificationItems.length}`
    }, notificationItems)) : null));
  }
}, (0,applyDecoratedDescriptor.A)(_class.prototype, "eventuallyScrollTo", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyScrollTo"), _class.prototype), (0,applyDecoratedDescriptor.A)(_class.prototype, "render", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "render"), _class.prototype), _class);

;// ./js/chat/ui/leftPanel/conversationsList.jsx







const ConversationsList = ({
  conversations,
  className,
  children
}) => {
  return REaCt().createElement(perfectScrollbar.O, {
    className: "chat-lp-scroll-area",
    didMount: (id, ref) => {
      megaChat.$chatTreePanePs = [...megaChat.$chatTreePanePs, {
        id,
        ref
      }];
    },
    willUnmount: id => {
      megaChat.$chatTreePanePs = megaChat.$chatTreePanePs.filter(ref => ref.id !== id);
    },
    conversations
  }, REaCt().createElement("ul", {
    className: `
                    conversations-pane
                    ${className || ''}
                `
  }, children || conversations.map(c => c.roomId && REaCt().createElement(ConversationsListItem, (0,esm_extends.A)({
    key: c.roomId,
    chatRoom: c
  }, c.type === 'private' && {
    contact: M.u[c.getParticipantsExceptMe()[0]]
  })))));
};
const Chats = ({
  conversations,
  onArchivedClicked,
  filter
}) => {
  conversations = Object.values(conversations || {}).filter(c => !c.isMeeting && c.isDisplayable() && (!filter || filter === FILTER.UNREAD && c.messagesBuff.getUnreadCount() > 0 || filter === FILTER.MUTED && c.isMuted())).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
  const noteChat = megaChat.getNoteChat();
  return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
    className: "conversations-holder"
  }, filter ? null : REaCt().createElement("div", {
    className: "conversations-category"
  }, REaCt().createElement("span", null, l.filter_heading__recent)), conversations && conversations.length >= 1 ? REaCt().createElement(ConversationsList, {
    conversations
  }, megaChat.WITH_SELF_NOTE && noteChat && noteChat.isDisplayable() ? filter ? null : REaCt().createElement(ConversationsListItem, {
    chatRoom: noteChat
  }) : null, conversations.map(c => c.roomId && !c.isNote && REaCt().createElement(ConversationsListItem, (0,esm_extends.A)({
    key: c.roomId,
    chatRoom: c
  }, c.type === 'private' && {
    contact: M.u[c.getParticipantsExceptMe()[0]]
  })))) : REaCt().createElement("div", {
    className: `
                            ${NAMESPACE}-nil
                            ${filter ? `${NAMESPACE}-nil--chats` : ''}
                        `
  }, filter ? REaCt().createElement(REaCt().Fragment, null, filter === FILTER.MUTED && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("i", {
    className: "sprite-fm-mono icon-notification-off-filled"
  }), REaCt().createElement("h3", null, l.filter_nil__muted_chats)), filter === FILTER.UNREAD && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("i", {
    className: "sprite-fm-mono icon-eye-thin-solid"
  }), REaCt().createElement("h3", null, l.filter_nil__unread_messages))) : REaCt().createElement("span", null, l.no_chats_lhp)), megaChat.WITH_SELF_NOTE && conversations && conversations.length === 1 && noteChat && REaCt().createElement(ConversationsList, {
    conversations
  }, REaCt().createElement(ConversationsListItem, {
    chatRoom: noteChat
  }))), REaCt().createElement("div", {
    className: `${NAMESPACE}-bottom`
  }, REaCt().createElement("div", {
    className: `${NAMESPACE}-bottom-control`
  }, REaCt().createElement("div", {
    className: "conversations-category",
    onClick: onArchivedClicked
  }, REaCt().createElement("span", null, l.filter_archived__chats), REaCt().createElement("i", {
    className: "sprite-fm-mono icon-arrow-right"
  })))));
};
const Archived = ({
  conversations,
  archivedUnmounting,
  onClose
}) => {
  const archivedChats = Object.values(conversations || {}).filter(c => !c.isMeeting && c.isArchived()).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
  return REaCt().createElement("div", {
    className: `
                ${NAMESPACE}-archived
                ${archivedUnmounting ? 'with-unmount-animation' : ''}
            `
  }, REaCt().createElement("div", {
    className: `${NAMESPACE}-archived-head`
  }, REaCt().createElement(meetings_button.A, {
    className: "mega-button round",
    icon: "sprite-fm-mono icon-arrow-left-regular-outline",
    onClick: onClose
  }), REaCt().createElement("h2", null, l.filter_archived__chats)), REaCt().createElement("div", {
    className: `${NAMESPACE}-archived-content`
  }, archivedChats && archivedChats.length ? REaCt().createElement(ConversationsList, {
    conversations: archivedChats
  }) : REaCt().createElement("div", {
    className: `${NAMESPACE}-archived-empty`
  }, REaCt().createElement("i", {
    className: "sprite-fm-mono icon-archive"
  }), REaCt().createElement("h3", null, l.filter_archived__nil_chats))));
};
class Meetings extends mixins.w9 {
  constructor(props) {
    let _megaChat$getCurrentM;
    super(props);
    this.TABS = {
      UPCOMING: 0x00,
      PAST: 0x01
    };
    this.domRef = REaCt().createRef();
    this.ongoingRef = REaCt().createRef();
    this.navigationRef = REaCt().createRef();
    this.state = {
      tab: this.TABS.UPCOMING
    };
    this.Navigation = ({
      conversations
    }) => {
      const {
        UPCOMING,
        PAST
      } = this.TABS;
      const {
        tab
      } = this.state;
      const unreadMeetings = Object.values(conversations || {}).reduce((acc, curr) => {
        if (curr.isDisplayable() && curr.isMeeting && curr.messagesBuff.getUnreadCount()) {
          let _curr$scheduledMeetin;
          acc[(_curr$scheduledMeetin = curr.scheduledMeeting) != null && _curr$scheduledMeetin.isUpcoming ? UPCOMING : PAST]++;
        }
        return acc;
      }, {
        [UPCOMING]: 0,
        [PAST]: 0
      });
      return REaCt().createElement("div", {
        ref: this.navigationRef,
        className: `
                    ${NAMESPACE}-meetings--navigation
                    ${this.props.leftPaneWidth < 230 ? 'narrow-width' : ''}
                `
      }, REaCt().createElement(meetings_button.A, {
        converstaions: conversations,
        className: `
                        mega-button
                        action
                        ${tab === UPCOMING ? 'is-active' : ''}
                    `,
        onClick: () => this.setState({
          tab: UPCOMING
        })
      }, REaCt().createElement("span", null, l.meetings_tab_upcoming, !!unreadMeetings[UPCOMING] && REaCt().createElement("div", {
        className: "notification-indication"
      }))), REaCt().createElement(meetings_button.A, {
        converstaions: conversations,
        className: `
                        mega-button
                        action
                        ${tab === PAST ? 'is-active' : ''}
                    `,
        onClick: () => this.setState({
          tab: PAST
        }, () => eventlog(500254))
      }, REaCt().createElement("span", null, l.meetings_tab_past, !!unreadMeetings[PAST] && REaCt().createElement("div", {
        className: "notification-indication"
      }))));
    };
    this.Holder = ({
      heading,
      className,
      children
    }) => REaCt().createElement("div", {
      className: `
                conversations-holder
                ${className || ''}
            `
    }, REaCt().createElement("div", {
      className: `
                    conversations-category
                `
    }, heading && REaCt().createElement("span", null, heading)), children);
    this.Ongoing = ({
      ongoingMeetings
    }) => ongoingMeetings != null && ongoingMeetings.length ? REaCt().createElement("div", {
      ref: this.ongoingRef,
      className: `${NAMESPACE}-meetings--ongoing`
    }, REaCt().createElement("strong", null, l.happening_now), REaCt().createElement(ConversationsList, {
      conversations: ongoingMeetings
    })) : null;
    this.Upcoming = () => {
      const {
        upcomingMeetings,
        nextOccurrences
      } = megaChat.plugins.meetingsManager.filterUpcomingMeetings(this.props.conversations);
      const upcomingItem = chatRoom => REaCt().createElement(ConversationsListItem, {
        key: chatRoom.roomId,
        chatRoom
      });
      return REaCt().createElement(this.Holder, null, upcomingMeetings && upcomingMeetings.length ? REaCt().createElement(ConversationsList, {
        conversations: upcomingMeetings
      }, nextOccurrences.today && nextOccurrences.today.length ? REaCt().createElement("div", {
        className: "conversations-group"
      }, REaCt().createElement("div", {
        className: "conversations-category category--label"
      }, REaCt().createElement("span", null, l.upcoming__today)), nextOccurrences.today.map(upcomingItem)) : null, nextOccurrences.tomorrow && nextOccurrences.tomorrow.length ? REaCt().createElement("div", {
        className: "conversations-group"
      }, REaCt().createElement("div", {
        className: "conversations-category category--label"
      }, REaCt().createElement("span", null, l.upcoming__tomorrow)), nextOccurrences.tomorrow.map(upcomingItem)) : null, Object.keys(nextOccurrences.rest).length ? Object.keys(nextOccurrences.rest).map(date => REaCt().createElement("div", {
        key: date,
        className: "conversations-group"
      }, REaCt().createElement("div", {
        className: "conversations-category category--label"
      }, REaCt().createElement("span", null, date)), nextOccurrences.rest[date].map(upcomingItem))) : null) : REaCt().createElement("div", {
        className: `${NAMESPACE}-nil`
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-calendar-plus-thin-solid"
      }), REaCt().createElement("span", null, l.meetings_upcoming_nil)));
    };
    this.Past = () => {
      const conversations = Object.values(this.props.conversations || {});
      const pastMeetings = conversations.filter(c => {
        const {
          isCanceled,
          isPast,
          isCompleted
        } = c.scheduledMeeting || {};
        return c.isMeeting && c.isDisplayable() && (!c.scheduledMeeting || isCanceled || isPast || isCompleted) && !c.havePendingCall();
      }).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
      const archivedMeetings = conversations.filter(c => c.isMeeting && c.isArchived()).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
      return REaCt().createElement(this.Holder, null, REaCt().createElement(ConversationsList, {
        conversations: pastMeetings
      }, pastMeetings.length ? pastMeetings.map(chatRoom => chatRoom.roomId && REaCt().createElement(ConversationsListItem, {
        key: chatRoom.roomId,
        chatRoom
      })) : REaCt().createElement("div", {
        className: `
                                ${NAMESPACE}-nil
                                ${archivedMeetings.length ? 'half-sized' : ''}
                            `
      }, archivedMeetings.length ? REaCt().createElement("strong", null, l.meetings_past_nil_heading) : null, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-video-thin-solid"
      }), REaCt().createElement("span", null, l.meetings_past_nil)), archivedMeetings.length ? REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
        className: "archived-separator"
      }), REaCt().createElement("div", {
        className: "conversations-category category--label"
      }, REaCt().createElement("span", null, l.meetings_label_archived)), archivedMeetings.map(chatRoom => chatRoom.roomId && REaCt().createElement(ConversationsListItem, {
        key: chatRoom.roomId,
        chatRoom
      }))) : null));
    };
    this.getContainerStyles = ongoingMeetings => {
      if (ongoingMeetings != null && ongoingMeetings.length) {
        let _this$ongoingRef, _this$navigationRef;
        const ongoingHeight = (_this$ongoingRef = this.ongoingRef) == null || (_this$ongoingRef = _this$ongoingRef.current) == null ? void 0 : _this$ongoingRef.clientHeight;
        const navigationHeight = (_this$navigationRef = this.navigationRef) == null || (_this$navigationRef = _this$navigationRef.current) == null ? void 0 : _this$navigationRef.clientHeight;
        return {
          style: {
            maxHeight: `calc(100% - ${ongoingHeight + navigationHeight + 30}px)`
          }
        };
      }
      return null;
    };
    this.state.tab = this.TABS[(_megaChat$getCurrentM = megaChat.getCurrentMeeting()) != null && _megaChat$getCurrentM.isPast ? 'PAST' : 'UPCOMING'];
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    megaChat.off(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`);
  }
  componentDidMount() {
    super.componentDidMount();
    megaChat.rebind(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`, () => this.safeForceUpdate());
    megaChat.rebind(megaChat.plugins.meetingsManager.EVENTS.INITIALIZE, (ev, scheduledMeeting) => this.isMounted() && this.setState({
      tab: this.TABS[scheduledMeeting != null && scheduledMeeting.isPast ? 'PAST' : 'UPCOMING']
    }));
  }
  render() {
    const {
      UPCOMING,
      PAST
    } = this.TABS;
    const {
      tab
    } = this.state;
    const ongoingMeetings = Object.values(this.props.conversations || {}).filter(c => c.isDisplayable() && c.isMeeting && c.havePendingCall());
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `${NAMESPACE}-meetings`
    }, REaCt().createElement(this.Ongoing, {
      ongoingMeetings
    }), REaCt().createElement(this.Navigation, {
      conversations: this.props.conversations
    }), REaCt().createElement("div", (0,esm_extends.A)({
      className: `
                        ${NAMESPACE}-meetings--content
                        ${tab === UPCOMING ? 'is-upcoming' : ''}
                        ${tab === PAST ? 'is-past' : ''}
                    `
    }, this.getContainerStyles(ongoingMeetings)), tab === UPCOMING && REaCt().createElement(this.Upcoming, null), tab === PAST && REaCt().createElement(this.Past, null)));
  }
}
// EXTERNAL MODULE: ./js/chat/ui/updateObserver.jsx
const updateObserver = REQ_(501);
;// ./js/chat/ui/leftPanel/leftPanel.jsx








const NAMESPACE = 'lhp';
const FILTER = {
  MUTED: 'muted',
  UNREAD: 'unread'
};
class LeftPanel extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.contactRequestsListener = undefined;
    this.fmConfigLeftPaneListener = undefined;
    this.state = {
      leftPaneWidth: Math.min(mega.config.get('leftPaneWidth') | 0, 400) || 384,
      archived: false,
      archivedUnmounting: false,
      filter: '',
      unreadChats: 0,
      unreadMeetings: 0,
      contactRequests: 0
    };
    this.toggleFilter = filter => {
      this.setState(state => ({
        filter: state.filter === filter ? '' : filter
      }), () => {
        Object.values(megaChat.$chatTreePanePs).map(({
          ref
        }) => ref.reinitialise == null ? void 0 : ref.reinitialise());
      });
    };
    this.state.contactRequests = Object.keys(M.ipc).length;
  }
  customIsEventuallyVisible() {
    return M.chat;
  }
  renderLoading() {
    return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("span", {
      className: "heading loading-sketch"
    }), REaCt().createElement("ul", {
      className: "conversations-pane loading-sketch"
    }, Array.from({
      length: this.props.conversations.length
    }, (el, i) => {
      return REaCt().createElement("li", {
        key: i
      }, REaCt().createElement("div", {
        className: "conversation-avatar"
      }, REaCt().createElement("div", {
        className: "chat-topic-icon"
      })), REaCt().createElement("div", {
        className: "conversation-data"
      }, REaCt().createElement("div", {
        className: "conversation-data-top"
      }), REaCt().createElement("div", {
        className: "conversation-message-info"
      }, REaCt().createElement("div", {
        className: "conversation-message"
      }))));
    })));
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    megaChat.unbind(`onUnreadCountUpdate.${NAMESPACE}`);
    mBroadcaster.removeListener(this.contactRequestsListener);
    mBroadcaster.removeListener(this.fmConfigLeftPaneListener);
  }
  componentDidMount() {
    let _$$leftPaneResizable;
    super.componentDidMount();
    megaChat.rebind(`onUnreadCountUpdate.${NAMESPACE}`, (ev, {
      unreadChats,
      unreadMeetings
    }) => {
      this.setState({
        unreadChats,
        unreadMeetings
      }, () => this.safeForceUpdate());
    });
    this.contactRequestsListener = mBroadcaster.addListener('fmViewUpdate:ipc', () => this.setState({
      contactRequests: Object.keys(M.ipc).length
    }));
    $.leftPaneResizableChat = new FMResizablePane(this.domRef.current, {
      ...(_$$leftPaneResizable = $.leftPaneResizable) == null ? void 0 : _$$leftPaneResizable.options,
      minWidth: mega.flags.ab_ads ? 260 : 200
    });
    this.fmConfigLeftPaneListener = mBroadcaster.addListener('fmconfig:leftPaneWidth', value => this.setState(state => ({
      leftPaneWidth: value || state.leftPaneWidth
    })));
  }
  render() {
    const {
      view,
      views,
      conversations,
      routingSection,
      renderView,
      startMeeting,
      scheduleMeeting,
      createNewChat
    } = this.props;
    const {
      CHATS,
      MEETINGS,
      LOADING
    } = views;
    return REaCt().createElement("div", (0,esm_extends.A)({
      ref: this.domRef,
      className: `
                    fm-left-panel
                    chat-lp-body
                    ${NAMESPACE}-container
                    ${is_chatlink && 'hidden' || ''}
                    ${megaChat._joinDialogIsShown && 'hidden' || ''}
                `
    }, this.state.leftPaneWidth && {
      width: this.state.leftPaneWidth
    }), REaCt().createElement("div", {
      className: "left-pane-drag-handle"
    }), REaCt().createElement(SearchPanel, null), REaCt().createElement(Navigation, {
      view,
      views,
      routingSection,
      unreadChats: this.state.unreadChats,
      unreadMeetings: this.state.unreadMeetings,
      contactRequests: this.state.contactRequests,
      renderView: view => this.setState({
        filter: false
      }, () => renderView(view))
    }), REaCt().createElement(actions, {
      view,
      views,
      filter: this.state.filter,
      routingSection,
      startMeeting,
      scheduleMeeting,
      createNewChat,
      onFilter: this.toggleFilter
    }), this.state.archived && REaCt().createElement(Archived, {
      conversations,
      archivedUnmounting: this.state.archivedUnmounting,
      onClose: () => this.setState({
        archivedUnmounting: true
      }, () => tSleep(0.3).then(() => this.setState({
        archivedUnmounting: false,
        archived: false
      })))
    }), REaCt().createElement("div", {
      className: `
                        ${NAMESPACE}-conversations
                        ${view === MEETINGS ? 'meetings-view' : ''}
                        ${view === CHATS ? 'chats-view' : ''}
                        conversations
                        content-panel
                        active
                    `
    }, view === LOADING ? this.renderLoading() : REaCt().createElement(REaCt().Fragment, null, view === MEETINGS && REaCt().createElement(Meetings, {
      conversations,
      leftPaneWidth: this.state.leftPaneWidth
    }), view === CHATS && REaCt().createElement(Chats, {
      conversations,
      filter: this.state.filter,
      onArchivedClicked: () => this.setState({
        archived: true,
        filter: false
      })
    }))));
  }
}
const leftPanel = (0,mixins.Zz)(updateObserver.Y)(LeftPanel);
;// ./js/chat/ui/meetings/workflow/freeCallEnded.jsx


const freeCallEnded_NAMESPACE = 'free-call-ended-dlg';
class FreeCallEnded extends REaCt().Component {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
  }
  componentWillUnmount() {
    if ($.dialog === freeCallEnded_NAMESPACE) {
      closeDialog();
    }
  }
  componentDidMount() {
    M.safeShowDialog(freeCallEnded_NAMESPACE, () => {
      if (!this.domRef.current) {
        throw new Error(`${freeCallEnded_NAMESPACE} dialog: component ${freeCallEnded_NAMESPACE} not mounted.`);
      }
      eventlog(500295);
      return $(`#${freeCallEnded_NAMESPACE}`);
    });
  }
  render() {
    const {
      onClose
    } = this.props;
    return REaCt().createElement(modalDialogs.A.ModalDialog, {
      id: freeCallEnded_NAMESPACE,
      ref: this.domRef,
      className: "mega-dialog",
      dialogType: "action",
      dialogName: freeCallEnded_NAMESPACE,
      onClose
    }, REaCt().createElement("header", null, REaCt().createElement("div", {
      className: "free-call-ended graphic"
    }, REaCt().createElement("img", {
      src: `${staticpath}images/mega/chat-upgrade-rocket.png`
    }))), REaCt().createElement("section", {
      className: "content"
    }, REaCt().createElement("div", {
      className: "content-block"
    }, REaCt().createElement("div", {
      className: "dialog-body-text"
    }, REaCt().createElement("h3", null, l.free_call_ended_dlg_text), REaCt().createElement("span", null, l.free_call_ended_dlg_subtext)))), REaCt().createElement("footer", null, REaCt().createElement("div", {
      className: "footer-container"
    }, REaCt().createElement("button", {
      className: "mega-button positive large",
      onClick: () => {
        loadSubPage('pro');
        eventlog(500261);
        onClose();
      }
    }, REaCt().createElement("span", null, l.upgrade_now)))));
  }
}
;// ./js/chat/ui/contactSelectorDialog.jsx




class ContactSelectorDialog extends mixins.w9 {
  constructor(...args) {
    super(...args);
    this.dialogName = 'contact-selector-dialog';
  }
  componentDidMount() {
    super.componentDidMount();
    M.safeShowDialog(this.dialogName, () => $(`.${this.dialogName}`));
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    if ($.dialog === this.dialogName) {
      closeDialog();
    }
  }
  render() {
    const {
      active,
      selectFooter,
      exclude,
      allowEmpty,
      multiple,
      topButtons,
      showAddContact,
      className,
      multipleSelectedButtonLabel,
      singleSelectedButtonLabel,
      nothingSelectedButtonLabel,
      onClose,
      onSelectDone
    } = this.props;
    return REaCt().createElement(modalDialogs.A.ModalDialog, {
      className: `
                    popup
                    contacts-search
                    ${className}
                    ${this.dialogName}
                `,
      onClose
    }, REaCt().createElement(ui_contacts.ContactPickerWidget, {
      active,
      className: "popup contacts-search small-footer",
      contacts: M.u,
      selectFooter,
      megaChat,
      withSelfNote: megaChat.WITH_SELF_NOTE,
      exclude,
      allowEmpty,
      multiple,
      topButtons,
      showAddContact,
      multipleSelectedButtonLabel,
      singleSelectedButtonLabel,
      nothingSelectedButtonLabel,
      onClose,
      onAddContact: () => {
        eventlog(500237);
        onClose();
      },
      onSelected: () => {
        eventlog(500238);
        onClose();
      },
      onSelectDone
    }));
  }
}
window.ContactSelectorDialogUI = {
  ContactSelectorDialog
};
const ui_contactSelectorDialog = ContactSelectorDialog;
;// ./js/chat/ui/conversations.jsx















const VIEWS = {
  CHATS: 0x00,
  MEETINGS: 0x01,
  LOADING: 0x02
};
const conversations_EVENTS = {
  NAV_RENDER_VIEW: 'navRenderView'
};
window.convAppConstants = {
  VIEWS,
  EVENTS: conversations_EVENTS
};
class ConversationsApp extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.chatRoomRef = null;
    this.occurrenceRef = null;
    this.state = {
      startGroupChatDialog: false,
      startMeetingDialog: false,
      scheduleMeetingDialog: false,
      scheduleOccurrenceDialog: false,
      freeCallEndedDialog: false,
      contactSelectorDialog: false,
      view: VIEWS.LOADING,
      callExpanded: false
    };
    this._cacheRouting();
    megaChat.rebind('onStartNewMeeting.convApp', () => this.startMeeting());
  }
  startMeeting() {
    if (megaChat.hasSupportForCalls) {
      return (0,call.dQ)().then(() => this.setState({
        startMeetingDialog: true
      })).catch(() => d && console.warn('Already in a call.'));
    }
    return showToast('warning', l[7211]);
  }
  _cacheRouting() {
    this.routingSection = this.props.megaChat.routingSection;
    this.routingSubSection = this.props.megaChat.routingSubSection;
    this.routingParams = this.props.megaChat.routingParams;
  }
  hasOpenDialog() {
    return [...document.querySelectorAll('.mega-dialog')].some(dialog => !!(dialog.offsetParent || dialog.offsetWidth || dialog.offsetHeight));
  }
  specShouldComponentUpdate() {
    if (this.routingSection !== this.props.megaChat.routingSection || this.routingSubSection !== this.props.megaChat.routingSubSection || this.routingParams !== this.props.megaChat.routingParams) {
      this._cacheRouting();
      return true;
    }
  }
  componentDidMount() {
    super.componentDidMount();
    $(document).rebind('keydown.megaChatTextAreaFocus', e => {
      if (!M.chat || e.megaChatHandled) {
        return;
      }
      const {
        currentlyOpenedChat
      } = megaChat;
      const currentRoom = megaChat.getCurrentRoom();
      if (currentlyOpenedChat) {
        if (currentRoom && currentRoom.isReadOnly() || $(e.target).is(".messages-textarea, input, textarea") || (e.ctrlKey || e.metaKey || e.which === 19) && e.keyCode === 67 || e.keyCode === 91 || e.keyCode === 17 || e.keyCode === 27 || e.altKey || e.metaKey || e.ctrlKey || e.shiftKey || this.hasOpenDialog() || document.querySelector('textarea:focus,select:focus,input:focus')) {
          return;
        }
        const $typeArea = $('.messages-textarea:visible:first');
        moveCursortoToEnd($typeArea);
        e.megaChatHandled = true;
        $typeArea.triggerHandler(e);
        e.preventDefault();
        e.stopPropagation();
        return false;
      }
    });
    $(document).rebind('mouseup.megaChatTextAreaFocus', e => {
      if (!M.chat || e.megaChatHandled || slideshowid) {
        return;
      }
      const $target = $(e.target);
      if (megaChat.currentlyOpenedChat) {
        if ($target.is(".messages-textarea,a,input,textarea,select,button") || $target.is('i') && $target.parent().is('a,input,select,button') || $target.closest('.messages.scroll-area').length > 0 || $target.closest('.mega-dialog').length > 0 || this.hasOpenDialog() || document.querySelector('textarea:focus,select:focus,input:focus') || window.getSelection().toString()) {
          return;
        }
        const $typeArea = $('.messages-textarea:visible:first');
        if ($typeArea.length === 1 && !$typeArea.is(":focus")) {
          $typeArea.trigger("focus");
          e.megaChatHandled = true;
        }
      }
    });
    megaChat.rebind(megaChat.plugins.meetingsManager.EVENTS.EDIT, (ev, chatOrOccurrence) => {
      if (chatOrOccurrence instanceof ChatRoom || !chatOrOccurrence) {
        this.chatRoomRef = chatOrOccurrence;
        this.setState({
          scheduleMeetingDialog: true
        });
      } else {
        this.occurrenceRef = chatOrOccurrence;
        this.setState({
          scheduleOccurrenceDialog: true
        });
      }
    });
    megaChat.rebind(conversations_EVENTS.NAV_RENDER_VIEW, ({
      data
    }) => {
      if (Object.values(VIEWS).includes(data)) {
        this.renderView(data);
      }
    });
    megaChat.rebind('onCallTimeLimitExceeded', () => {
      this.setState({
        freeCallEndedDialog: true
      });
    });
    if (megaChat.WITH_SELF_NOTE && !megaChat.getNoteChat() && !is_chatlink) {
      api.req({
        a: 'mcc',
        u: [],
        m: 0,
        g: 0,
        v: Chatd.VERSION
      }).catch(dump);
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    $(document).off('keydown.megaChatTextAreaFocus');
  }
  componentDidUpdate() {
    this.handleOnboardingStep();
  }
  handleOnboardingStep() {
    if (this.state.view === VIEWS.LOADING) {
      return;
    }
    megaChat.plugins.chatOnboarding.checkAndShowStep();
  }
  renderView(view) {
    this.setState({
      view
    }, () => {
      const {
        $chatTreePanePs,
        routingSection,
        currentlyOpenedChat
      } = megaChat;
      Object.values($chatTreePanePs).forEach(ref => ref.reinitialise == null ? void 0 : ref.reinitialise());
      if (routingSection !== 'chat') {
        loadSubPage('fm/chat');
      }
      megaChat.currentlyOpenedView = view;
      if (!currentlyOpenedChat) {
        megaChat.renderListing(null, false).catch(dump);
      }
    });
  }
  render() {
    const {
      CHATS,
      MEETINGS
    } = VIEWS;
    const {
      routingSection,
      chatUIFlags,
      currentlyOpenedChat,
      chats
    } = megaChat;
    const {
      view,
      startGroupChatDialog,
      startMeetingDialog,
      scheduleMeetingDialog,
      scheduleOccurrenceDialog,
      callExpanded,
      freeCallEndedDialog,
      contactSelectorDialog
    } = this.state;
    const isEmpty = chats && routingSection === 'chat' && !currentlyOpenedChat && !is_chatlink;
    const isLoading = !currentlyOpenedChat && megaChat.allChatsHadInitialLoadedHistory() === false && routingSection !== 'contacts';
    const rightPane = REaCt().createElement("div", {
      className: `
                    fm-right-files-block
                    in-chat
                    ${is_chatlink ? 'chatlink' : ''}
                `
    }, !isLoading && REaCt().createElement(chatToaster.A, {
      isRootToaster: true
    }), !isLoading && routingSection === 'contacts' && REaCt().createElement(contactsPanel.A, {
      megaChat,
      contacts: M.u,
      received: M.ipc,
      sent: M.opc
    }), !isLoading && routingSection === 'notFound' && REaCt().createElement("span", null, REaCt().createElement("center", null, "Section not found")), !isLoading && isEmpty && REaCt().createElement(conversationpanel.Yk, {
      isMeeting: view === MEETINGS,
      onNewChat: () => this.setState({
        contactSelectorDialog: true
      }),
      onStartMeeting: () => this.startMeeting(),
      onScheduleMeeting: () => this.setState({
        scheduleMeetingDialog: true
      })
    }), !isLoading && REaCt().createElement(conversationpanel.$h, (0,esm_extends.A)({}, this.props, {
      className: routingSection === 'chat' ? '' : 'hidden',
      routingSection,
      currentlyOpenedChat,
      isEmpty,
      chatUIFlags,
      onToggleExpandedFlag: () => this.setState(() => ({
        callExpanded: call.Ay.isExpanded()
      })),
      onMount: () => {
        const chatRoom = megaChat.getCurrentRoom();
        const view = chatRoom && chatRoom.isMeeting ? MEETINGS : CHATS;
        this.setState({
          view
        }, () => {
          megaChat.currentlyOpenedView = view;
        });
      }
    })));
    const noteChat = megaChat.getNoteChat();
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "conversationsApp"
    }, contactSelectorDialog && REaCt().createElement(ui_contactSelectorDialog, {
      className: `main-start-chat-dropdown ${leftPanel.NAMESPACE}-contact-selector`,
      multiple: false,
      topButtons: [{
        key: 'newGroupChat',
        title: l[19483],
        className: 'positive',
        onClick: () => this.setState({
          startGroupChatDialog: true,
          contactSelectorDialog: false
        })
      }, ...megaChat.WITH_SELF_NOTE ? contactsPanel.A.hasContacts() || noteChat && noteChat.hasMessages() ? [] : [{
        key: 'noteChat',
        title: l.note_label,
        icon: 'sprite-fm-mono icon-file-text-thin-outline note-chat-icon',
        onClick: () => {
          closeDialog();
          loadSubPage(`fm/chat/p/${u_handle}`);
        }
      }] : []],
      showAddContact: contactsPanel.A.hasContacts(),
      onClose: () => this.setState({
        contactSelectorDialog: false
      }),
      onSelectDone: selected => {
        if (selected.length === 1) {
          return megaChat.createAndShowPrivateRoom(selected[0]).then(room => room.setActive());
        }
        megaChat.createAndShowGroupRoomFor(selected);
      }
    }), startGroupChatDialog && REaCt().createElement(StartGroupChatWizard, {
      name: "start-group-chat",
      flowType: 1,
      onClose: () => this.setState({
        startGroupChatDialog: false
      }),
      onConfirmClicked: () => this.setState({
        startGroupChatDialog: false
      })
    }), startMeetingDialog && REaCt().createElement(Start, {
      onStart: (topic, audio, video) => {
        megaChat.createAndStartMeeting(topic, audio, video);
        this.setState({
          startMeetingDialog: false
        });
      },
      onClose: () => this.setState({
        startMeetingDialog: false
      })
    }), scheduleMeetingDialog && REaCt().createElement(Schedule, {
      chatRoom: this.chatRoomRef,
      callExpanded,
      onClose: () => {
        this.setState({
          scheduleMeetingDialog: false
        }, () => {
          this.chatRoomRef = null;
        });
      }
    }), scheduleOccurrenceDialog && REaCt().createElement(Edit, {
      chatRoom: this.occurrenceRef.scheduledMeeting.chatRoom,
      scheduledMeeting: this.occurrenceRef.scheduledMeeting,
      occurrenceId: this.occurrenceRef.uid,
      callExpanded,
      onClose: () => {
        this.setState({
          scheduleOccurrenceDialog: false
        }, () => {
          this.occurrenceRef = null;
        });
      }
    }), freeCallEndedDialog && REaCt().createElement(FreeCallEnded, {
      onClose: () => {
        this.setState({
          freeCallEndedDialog: false
        });
      }
    }), REaCt().createElement(leftPanel, {
      view,
      views: VIEWS,
      routingSection,
      conversations: chats,
      renderView: view => this.renderView(view),
      startMeeting: () => {
        this.startMeeting();
        eventlog(500293);
      },
      scheduleMeeting: () => {
        this.setState({
          scheduleMeetingDialog: true
        });
        delay('chat-event-sm-button-main', () => eventlog(99918));
      },
      createNewChat: () => this.setState({
        contactSelectorDialog: true
      })
    }), rightPane);
  }
}
if (false) // removed by dead control flow
{}
const conversations = {
  ConversationsApp
};

},

757:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
A: () => ScheduleMetaChange
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);
const _mixin_jsx1__ = REQ_(446);
const _contacts_jsx2__ = REQ_(251);
const _ui_utils_jsx3__ = REQ_(314);
const _ui_buttons_jsx4__ = REQ_(994);





class ScheduleMetaChange extends _mixin_jsx1__.M {
  constructor(...args) {
    super(...args);
    this.state = {
      link: ''
    };
  }
  componentDidMount() {
    super.componentDidMount();
    if (this.props.mode === ScheduleMetaChange.MODE.CREATED) {
      if (is_chatlink) {
        this.setState({
          link: `${getBaseUrl()}/chat/${is_chatlink.ph}#${is_chatlink.key}`
        });
      } else {
        const {
          chatRoom
        } = this.props;
        chatRoom.updatePublicHandle().then(() => {
          if (this.isMounted() && !this.state.link && chatRoom.publicLink) {
            this.setState({
              link: `${getBaseUrl()}/${chatRoom.publicLink}`
            });
          }
        }).catch(dump);
      }
    }
    if (this.props.message.meta.ap) {
      const {
        meetingsManager
      } = megaChat.plugins;
      this.redrawListener = `${meetingsManager.EVENTS.OCCURRENCES_UPDATE}.redraw${this.getUniqueId()}`;
      megaChat.rebind(this.redrawListener, () => {
        onIdle(() => {
          const {
            meta
          } = this.props.message;
          if (!meta.ap) {
            return;
          }
          this.props.message.meta = meetingsManager.noCsMeta(meta.handle, meta.ap, megaChat.chats[meta.cid]);
          this.safeForceUpdate();
        });
        megaChat.off(this.redrawListener);
        delete this.redrawListener;
      });
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    if (this.redrawListener) {
      megaChat.off(this.redrawListener);
    }
  }
  specShouldComponentUpdate(nextProps) {
    if (this.props.mode === ScheduleMetaChange.MODE.CREATED && this.props.link !== nextProps.link) {
      return true;
    }
    return null;
  }
  componentDidUpdate(prevProps) {
    if (this.props.mode === ScheduleMetaChange.MODE.CREATED && prevProps.link !== this.props.link) {
      this.setState({
        link: this.props.link ? `${getBaseUrl()}/${this.props.link}` : ''
      });
    }
  }
  onAddToCalendar() {
    const {
      chatRoom
    } = this.props;
    const {
      id,
      title
    } = chatRoom && chatRoom.scheduledMeeting || {};
    if (id) {
      delay(`fetchical${id}`, () => {
        eventlog(500038);
        asyncApiReq({
          a: 'mcsmfical',
          id
        }).then(([, res]) => {
          delay(`saveical${id}`, () => {
            M.saveAs(base64urldecode(res), `${title.replace(/\W/g, '')}.ics`).then(nop).catch(() => {
              msgDialog('error', '', l.calendar_add_failed, '');
            });
          }, 1000);
        }).catch(() => {
          msgDialog('error', '', l.calendar_add_failed, '');
        });
      }, 250);
    }
  }
  static getTitleText(meta) {
    const {
      mode,
      recurring,
      occurrence,
      converted,
      prevTiming
    } = meta;
    const {
      MODE
    } = ScheduleMetaChange;
    switch (mode) {
      case MODE.CREATED:
        {
          return recurring ? l.schedule_mgmt_new_recur : l.schedule_mgmt_new;
        }
      case MODE.EDITED:
        {
          if (converted) {
            return recurring ? l.schedule_mgmt_update_convert_recur : l.schedule_mgmt_update_convert;
          }
          if (occurrence) {
            return l.schedule_mgmt_update_occur;
          }
          if (prevTiming) {
            return recurring ? l.schedule_mgmt_update_recur : l.schedule_mgmt_update;
          }
          return l.schedule_mgmt_update_desc;
        }
      case MODE.CANCELLED:
        {
          if (recurring) {
            return occurrence ? l.schedule_mgmt_cancel_occur : l.schedule_mgmt_cancel_recur;
          }
          return l.schedule_mgmt_cancel;
        }
    }
    return '';
  }
  renderTimingBlock() {
    const {
      message,
      mode
    } = this.props;
    const {
      meta
    } = message;
    const {
      MODE
    } = ScheduleMetaChange;
    if (mode === MODE.CANCELLED && !meta.occurrence) {
      return null;
    }
    const [now, prev] = megaChat.plugins.meetingsManager.getOccurrenceStrings(meta);
    return react0().createElement("div", {
      className: "schedule-timing-block"
    }, meta.prevTiming && react0().createElement("s", null, prev || ''), now);
  }
  checkAndFakeOccurrenceMeta(meta) {
    const {
      MODE
    } = ScheduleMetaChange;
    if (meta.occurrence && meta.mode === MODE.CANCELLED && !meta.calendar) {
      const meeting = megaChat.plugins.meetingsManager.getMeetingOrOccurrenceParent(meta.handle);
      if (meeting) {
        const occurrences = meeting.getOccurrencesById(meta.handle);
        if (occurrences) {
          meta.calendar = {
            date: new Date(occurrences[0].start).getDate(),
            month: time2date(Math.floor(occurrences[0].start / 1000), 12)
          };
          meta.timeRules.startTime = Math.floor(occurrences[0].start / 1000);
          meta.timeRules.endTime = Math.floor(occurrences[0].end / 1000);
        }
      }
    }
  }
  render() {
    const {
      chatRoom,
      message,
      mode,
      contact
    } = this.props;
    const {
      meta,
      messageId
    } = message;
    const {
      scheduledMeeting
    } = chatRoom;
    const {
      MODE
    } = ScheduleMetaChange;
    const {
      link
    } = this.state;
    if (meta.gone) {
      return null;
    }
    this.checkAndFakeOccurrenceMeta(meta);
    return react0().createElement("div", null, react0().createElement("div", {
      className: "message body",
      "data-id": `id${messageId}`,
      key: messageId
    }, react0().createElement(_contacts_jsx2__.Avatar, {
      contact: contact.u,
      className: "message avatar-wrapper small-rounded-avatar",
      chatRoom
    }), react0().createElement("div", {
      className: "message schedule-message content-area small-info-txt selectable-txt"
    }, react0().createElement(_contacts_jsx2__.ContactButton, {
      className: "message",
      chatRoom,
      contact,
      label: react0().createElement(_ui_utils_jsx3__.zT, null, M.getNameByHandle(contact.u))
    }), react0().createElement("div", {
      className: "message date-time simpletip",
      "data-simpletip": time2date(this.getTimestamp())
    }, this.getTimestampAsString()), react0().createElement("div", {
      className: "message text-block"
    }, ScheduleMetaChange.getTitleText(meta), " ", !!d && meta.handle), react0().createElement("div", {
      className: "message body-block"
    }, (meta.prevTiming || meta.calendar || meta.topic && meta.onlyTitle || meta.recurring) && react0().createElement("div", {
      className: "schedule-detail-block"
    }, meta.calendar && scheduledMeeting && (meta.recurring && !scheduledMeeting.recurring || meta.occurrence && meta.mode === MODE.CANCELLED || !meta.recurring) && react0().createElement("div", {
      className: "schedule-calendar-icon"
    }, react0().createElement("div", {
      className: "schedule-date"
    }, meta.calendar.date), react0().createElement("div", {
      className: "schedule-month"
    }, meta.calendar.month)), react0().createElement("div", {
      className: "schedule-detail-main"
    }, react0().createElement("div", {
      className: "schedule-meeting-title"
    }, mode === MODE.CANCELLED ? react0().createElement("s", null, meta.topic || chatRoom.topic) : meta.topic || chatRoom.topic), this.renderTimingBlock()), chatRoom.iAmInRoom() && scheduledMeeting && mode !== MODE.CANCELLED && react0().createElement(_ui_buttons_jsx4__.$, {
      className: "mega-button",
      onClick: () => this.onAddToCalendar()
    }, react0().createElement("span", null, mode === MODE.CREATED && !meta.occurrence ? l.schedule_add_calendar : l.schedule_update_calendar))), mode === MODE.CREATED && scheduledMeeting && scheduledMeeting.description && react0().createElement("div", {
      className: "schedule-description"
    }, react0().createElement(_ui_utils_jsx3__.P9, null, megaChat.html(scheduledMeeting.description).replace(/\n/g, '<br>'))), link && react0().createElement("div", null, react0().createElement("div", {
      className: "schedule-link-instruction"
    }, l.schedule_mgmt_link_instruct), react0().createElement("div", {
      className: "schedule-meeting-link"
    }, react0().createElement("span", null, link), react0().createElement(_ui_buttons_jsx4__.$, {
      className: "mega-button positive",
      onClick: () => {
        copyToClipboard(link, l[7654]);
        delay('chat-event-sm-copy-link', () => eventlog(500039));
      }
    }, react0().createElement("span", null, l[63]))), react0().createElement("span", null, l.schedule_link_note))))));
  }
}
ScheduleMetaChange.MODE = {
  CREATED: 1,
  EDITED: 2,
  CANCELLED: 3
};
window.ScheduleMetaChange = ScheduleMetaChange;

},

772:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
Q: () => withMicObserver
});
const _extends0__ = REQ_(168);
const react1__ = REQ_(594);
const react1 = REQ_.n(react1__);
const _mixins2__ = REQ_(137);
const _button_jsx3__ = REQ_(959);




const withMicObserver = Component => class extends _mixins2__.w9 {
  constructor(props) {
    super(props);
    this.namespace = `SO-${Component.NAMESPACE}`;
    this.inputObserver = `onNoMicInput.${this.namespace}`;
    this.sendObserver = `onAudioSendDenied.${this.namespace}`;
    this.state = {
      signal: true,
      blocked: false
    };
    this.renderSignalWarning = this.renderSignalWarning.bind(this);
    this.renderBlockedWarning = this.renderBlockedWarning.bind(this);
  }
  bindObservers() {
    this.props.chatRoom.rebind(this.inputObserver, () => this.setState({
      signal: false
    })).rebind(this.sendObserver, () => {
      this.setState({
        blocked: true
      }, () => {
        if (this.props.minimized) {
          const toast = new ChatToast(l.max_speakers_toast, {
            icon: 'sprite-fm-uni icon-hazard',
            close: true
          });
          toast.dispatch();
        }
      });
    });
  }
  renderSignalDialog() {
    return msgDialog('warningb', null, l.no_mic_title, l.chat_mic_off_tooltip, null, 1);
  }
  renderSignalWarning() {
    return react1().createElement("div", {
      className: `
                    ${this.namespace}
                        meetings-signal-issue
                        simpletip
                    `,
      "data-simpletip": l.show_info,
      "data-simpletipposition": "top",
      "data-simpletipoffset": "5",
      "data-simpletip-class": "theme-dark-forced",
      onClick: () => this.renderSignalDialog()
    }, react1().createElement("i", {
      className: "sprite-fm-mono icon-exclamation-filled"
    }));
  }
  renderBlockedWarning() {
    return react1().createElement("div", {
      className: "stream-toast theme-dark-forced"
    }, react1().createElement("div", {
      className: "stream-toast-content"
    }, react1().createElement("i", {
      className: "stream-toast-icon sprite-fm-uni icon-warning"
    }), react1().createElement("div", {
      className: "stream-toast-message"
    }, l.max_speakers_toast), react1().createElement(_button_jsx3__.A, {
      className: "mega-button action stream-toast-close",
      icon: "sprite-fm-mono icon-close-component",
      onClick: () => this.setState({
        blocked: false
      })
    })));
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    this.props.chatRoom.unbind(this.inputObserver);
  }
  componentDidMount() {
    super.componentDidMount();
    this.bindObservers();
  }
  render() {
    return react1().createElement(Component, (0,_extends0__.A)({}, this.props, {
      signal: this.state.signal,
      renderSignalWarning: this.renderSignalWarning,
      blocked: this.state.blocked,
      renderBlockedWarning: this.renderBlockedWarning
    }));
  }
};

},

793:
(__webpack_module__, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
A: () => _applyDecoratedDescriptor
});
function _applyDecoratedDescriptor(i, e, r, n, l) {
  let a = {};
  return Object.keys(n).forEach((i) => {
    a[i] = n[i];
  }), a.enumerable = !!a.enumerable, a.configurable = !!a.configurable, ("value" in a || a.initializer) && (a.writable = !0), a = r.slice().reverse().reduce((r, n) => {
    return n(i, e, r) || r;
  }, a), l && void 0 !== a.initializer && (a.value = a.initializer ? a.initializer.call(l) : void 0, a.initializer = void 0), void 0 === a.initializer ? (Object.defineProperty(i, e, a), null) : a;
}


},

795:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  T: () => TypingArea
});

// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
const applyDecoratedDescriptor = REQ_(793);
// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
// EXTERNAL MODULE: ./js/ui/utils.jsx
const utils = REQ_(314);
// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
// EXTERNAL MODULE: ./js/ui/emojiDropdown.jsx
const emojiDropdown = REQ_(844);
// EXTERNAL MODULE: ./js/ui/buttons.jsx
const ui_buttons = REQ_(994);
;// ./js/chat/ui/emojiAutocomplete.jsx



class EmojiAutocomplete extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.state = {
      'selected': 0
    };
    this.loading = false;
    this.data_emojis = [];
  }
  preload_emojis() {
    if (this.loading === false) {
      this.loading = true;
      megaChat.getEmojiDataSet('emojis').then(emojis => {
        this.loading = 0;
        this.data_emojis = emojis;
        this.safeForceUpdate();
      });
    }
  }
  unbindKeyEvents() {
    $(document).off(`keydown.emojiAutocomplete${  this.getUniqueId()}`);
  }
  bindKeyEvents() {
    const self = this;
    $(document).rebind(`keydown.emojiAutocomplete${  self.getUniqueId()}`, (e) => {
      if (!self.props.emojiSearchQuery) {
        self.unbindKeyEvents();
        return;
      }
      let key = e.keyCode || e.which;
      if (!$(e.target).is("textarea")) {
        console.error("this should never happen.");
        return;
      }
      if (e.altKey || e.metaKey) {
        return;
      }
      let selected = $.isNumeric(self.state.selected) ? self.state.selected : 0;
      if (document.body.classList.contains('rtl') && (key === 37 || key === 39)) {
        key = key === 37 ? 39 : 37;
      }
      let handled = false;
      if (!e.shiftKey && (key === 37 || key === 38)) {
        selected = selected - 1;
        selected = selected < 0 ? self.maxFound - 1 : selected;
        if (self.found[selected] && self.state.selected !== selected) {
          self.setState({
            selected,
            'prefilled': true
          });
          handled = true;
          self.props.onPrefill(false, `:${  self.found[selected].n  }:`);
        }
      } else if (!e.shiftKey && (key === 39 || key === 40 || key === 9)) {
        selected = selected + (key === 9 ? e.shiftKey ? -1 : 1 : 1);
        selected = selected < 0 ? Object.keys(self.found).length - 1 : selected;
        selected = selected >= self.props.maxEmojis || selected >= Object.keys(self.found).length ? 0 : selected;
        if (self.found[selected] && (key === 9 || self.state.selected !== selected)) {
          self.setState({
            selected,
            'prefilled': true
          });
          self.props.onPrefill(false, `:${  self.found[selected].n  }:`);
          handled = true;
        }
      } else if (key === 13) {
        self.unbindKeyEvents();
        if (selected === -1) {
          if (self.found.length > 0) {
            for (let i = 0; i < self.found.length; i++) {
              if (`:${  self.found[i].n  }:` === `${self.props.emojiSearchQuery  }:`) {
                self.props.onSelect(false, `:${  self.found[0].n  }:`);
                handled = true;
              }
            }
          }
          if (!handled && key === 13) {
            self.props.onCancel();
          }
          return;
        } else if (self.found.length > 0 && self.found[selected]) {
          self.props.onSelect(false, `:${  self.found[selected].n  }:`);
          handled = true;
        } else {
          self.props.onCancel();
        }
      } else if (key === 27) {
        self.unbindKeyEvents();
        self.props.onCancel();
        handled = true;
      }
      if (handled) {
        e.preventDefault();
        e.stopPropagation();
        return false;
      } else {
        if (self.isMounted()) {
          self.setState({
            'prefilled': false
          });
        }
      }
    });
  }
  componentDidUpdate() {
    if (!this.props.emojiSearchQuery) {
      this.unbindKeyEvents();
    } else {
      this.bindKeyEvents();
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    this.unbindKeyEvents();
  }
  render() {
    const self = this;
    if (!self.props.emojiSearchQuery) {
      return null;
    }
    self.preload_emojis();
    if (self.loading) {
      return REaCt().createElement("div", {
        className: "textarea-autofill-bl"
      }, REaCt().createElement("div", {
        className: "textarea-autofill-info"
      }, l[5533]));
    }
    const q = self.props.emojiSearchQuery.substr(1, self.props.emojiSearchQuery.length);
    let exactMatch = [];
    let partialMatch = [];
    const emojis = self.data_emojis || [];
    for (var i = 0; i < emojis.length; i++) {
      const emoji = emojis[i];
      const match = emoji.n.indexOf(q);
      if (match !== -1) {
        if (match === 0) {
          exactMatch.push(emoji);
        } else if (partialMatch.length < self.props.maxEmojis - exactMatch.length) {
          partialMatch.push(emoji);
        }
      }
      if (exactMatch.length >= self.props.maxEmojis) {
        break;
      }
    }
    exactMatch.sort((a, b) => {
      if (a.n === q) {
        return -1;
      } else if (b.n === q) {
        return 1;
      } else {
        return 0;
      }
    });
    const found = exactMatch.concat(partialMatch).slice(0, self.props.maxEmojis);
    exactMatch = partialMatch = null;
    this.maxFound = found.length;
    this.found = found;
    if (!found || found.length === 0) {
      queueMicrotask(() => {
        self.props.onCancel();
      });
      return null;
    }
    const emojisDomList = [];
    for (var i = 0; i < found.length; i++) {
      const meta = found[i];
      const filename = twemoji.convert.toCodePoint(meta.u);
      emojisDomList.push(REaCt().createElement("div", {
        className: `emoji-preview shadow ${  this.state.selected === i ? "active" : ""}`,
        key: `${meta.n  }_${  this.state.selected === i ? "selected" : "inselected"}`,
        title: `:${  meta.n  }:`,
        onClick (e) {
          self.props.onSelect(e, e.target.title);
          self.unbindKeyEvents();
        }
      }, REaCt().createElement("img", {
        width: "20",
        height: "20",
        className: "emoji emoji-loading",
        draggable: "false",
        alt: meta.u,
        onLoad: e => {
          e.target.classList.remove('emoji-loading');
        },
        onError: e => {
          e.target.classList.remove('emoji-loading');
          e.target.classList.add('emoji-loading-error');
        },
        src: `${staticpath  }images/mega/twemojis/2_v2/72x72/${  filename  }.png`
      }), REaCt().createElement("div", {
        className: "emoji title"
      }, `:${  meta.n  }:`)));
    }
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "textarea-autofill-bl"
    }, REaCt().createElement(utils.P9, {
      tag: "div",
      className: "textarea-autofill-info"
    }, l.emoji_suggestion_instruction), REaCt().createElement("div", {
      className: "textarea-autofill-emoji"
    }, emojisDomList));
  }
}
EmojiAutocomplete.defaultProps = {
  'requiresUpdateOnResize': true,
  'emojiSearchQuery': false,
  'disableCheckingVisibility': true,
  'maxEmojis': 12
};
// EXTERNAL MODULE: ./js/chat/ui/gifPanel/gifPanel.jsx + 3 modules
const gifPanel = REQ_(691);
// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
const perfectScrollbar = REQ_(486);
;// ./js/chat/ui/typingArea.jsx

let _dec, _class;








const TypingArea = (_dec = (0,mixins.hG)(54, true), _class = class TypingArea extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.state = {
      emojiSearchQuery: false,
      textareaHeight: 20,
      gifPanelActive: false
    };
    this.getTextareaMaxHeight = () => {
      const {
        containerRef
      } = this.props;
      if (containerRef && containerRef.current) {
        return this.isMounted() ? containerRef.current.offsetHeight * 0.4 : 100;
      }
      return 100;
    };
    const {
      chatRoom
    } = props;
    this.logger = d && MegaLogger.getLogger("TypingArea", {}, chatRoom && chatRoom.logger || megaChat.logger);
    this.onEmojiClicked = this.onEmojiClicked.bind(this);
    this.onTypeAreaKeyUp = this.onTypeAreaKeyUp.bind(this);
    this.onTypeAreaKeyDown = this.onTypeAreaKeyDown.bind(this);
    this.onTypeAreaBlur = this.onTypeAreaBlur.bind(this);
    this.onTypeAreaChange = this.onTypeAreaChange.bind(this);
    this.onCopyCapture = this.onCopyCapture.bind(this);
    this.onPasteCapture = this.onPasteCapture.bind(this);
    this.onCutCapture = this.onCutCapture.bind(this);
    this.state.typedMessage = this.props.initialText || '';
  }
  onEmojiClicked(e, slug) {
    if (this.props.disabled) {
      e.preventDefault();
      e.stopPropagation();
      return;
    }
    slug = slug[0] === ':' || slug.substr(-1) === ':' ? slug : `:${slug}:`;
    const textarea = $('.messages-textarea', this.domRef.current)[0];
    const cursorPosition = this.getCursorPosition(textarea);
    const {
      text,
      onValueChanged
    } = this.props;
    const val = text.slice(0, cursorPosition) + slug + text.slice(cursorPosition);
    onValueChanged(val);
    textarea.selectionEnd = cursorPosition + slug.length;
    this.onTypeAreaChange(e, val);
  }
  stoppedTyping() {
    if (this.props.disabled || !this.props.chatRoom) {
      return;
    }
    this.iAmTyping = false;
    this.props.chatRoom.trigger('stoppedTyping');
  }
  typing() {
    if (this.props.disabled || !this.props.chatRoom) {
      return;
    }
    const self = this;
    const now = Date.now();
    delay(this.getReactId(), () => self.iAmTyping && self.stoppedTyping(), 4e3);
    if (!self.iAmTyping || now - self.lastTypingStamp > 4e3) {
      self.iAmTyping = true;
      self.lastTypingStamp = now;
      self.props.chatRoom.trigger('typing');
    }
  }
  triggerOnUpdate(forced) {
    const self = this;
    if (!self.props.onUpdate || !self.isMounted()) {
      return;
    }
    let shouldTriggerUpdate = forced ? forced : false;
    if (!shouldTriggerUpdate && self.props.text !== self.lastTypedMessage) {
      self.lastTypedMessage = self.props.text;
      shouldTriggerUpdate = true;
    }
    if (!shouldTriggerUpdate) {
      const $textarea = $('.chat-textarea:visible textarea:visible', self.domRef.current);
      if (!self._lastTextareaHeight || self._lastTextareaHeight !== $textarea.height()) {
        self._lastTextareaHeight = $textarea.height();
        shouldTriggerUpdate = true;
        if (self.props.onResized) {
          self.props.onResized();
        }
      }
    }
    if (shouldTriggerUpdate) {
      self.props.onUpdate();
    }
  }
  onCancelClicked() {
    const self = this;
    self.props.onValueChanged('');
    if (self.props.chatRoom && self.iAmTyping) {
      self.stoppedTyping();
    }
    self.onConfirmTrigger(false);
    self.triggerOnUpdate();
  }
  onSaveClicked() {
    const self = this;
    if (self.props.disabled || !self.isMounted()) {
      return;
    }
    const val = $.trim($('.chat-textarea:visible textarea:visible', this.domRef.current).val());
    if (self.onConfirmTrigger(val) !== true) {
      self.props.onValueChanged('');
    }
    if (self.props.chatRoom && self.iAmTyping) {
      self.stoppedTyping();
    }
    self.triggerOnUpdate();
  }
  onConfirmTrigger(val) {
    const {
      onConfirm,
      persist,
      chatRoom
    } = this.props;
    const result = onConfirm(val);
    if (val !== false && result !== false) {
      $('.textarea-scroll', this.domRef.current).scrollTop(0);
    }
    if (persist) {
      const {
        persistedTypeArea
      } = chatRoom.megaChat.plugins;
      if (persistedTypeArea) {
        if (d > 2) {
          this.logger.info('Removing persisted-typed value...');
        }
        persistedTypeArea.removePersistedTypedValue(chatRoom);
      }
    }
    return result;
  }
  onTypeAreaKeyDown(e) {
    if (this.props.disabled) {
      e.preventDefault();
      e.stopPropagation();
      return;
    }
    const self = this;
    const key = e.keyCode || e.which;
    const element = e.target;
    const val = $.trim(element.value);
    if (self.state.emojiSearchQuery) {
      return;
    }
    if (key === 13 && !e.shiftKey && !e.ctrlKey && !e.altKey) {
      if (e.isPropagationStopped() || e.isDefaultPrevented()) {
        return;
      }
      if (self.onConfirmTrigger(val) !== true) {
        self.props.onValueChanged('');
        $(document).trigger('closeDropdowns');
      }
      e.preventDefault();
      e.stopPropagation();
      if (self.props.chatRoom && self.iAmTyping) {
        self.stoppedTyping();
      }
    }
  }
  onTypeAreaKeyUp(e) {
    if (this.props.disabled) {
      e.preventDefault();
      e.stopPropagation();
      return;
    }
    const self = this;
    const key = e.keyCode || e.which;
    const element = e.target;
    const val = $.trim(element.value);
    if (key === 13 && !e.shiftKey && !e.ctrlKey && !e.altKey) {
      e.preventDefault();
      e.stopPropagation();
    } else if (key === 13) {
      if (self.state.emojiSearchQuery) {
        return;
      }
      if (e.altKey) {
        let content = element.value;
        const cursorPos = self.getCursorPosition(element);
        content = `${content.substring(0, cursorPos)  }\n${  content.substring(cursorPos, content.length)}`;
        self.props.onValueChanged(content);
        self.onUpdateCursorPosition = cursorPos + 1;
        e.preventDefault();
      } else if ($.trim(val).length === 0) {
        e.preventDefault();
      }
    } else if (key === 38) {
      if (self.state.emojiSearchQuery) {
        return;
      }
      if ($.trim(val).length === 0) {
        if (self.props.onUpEditPressed && self.props.onUpEditPressed() === true) {
          e.preventDefault();
        }
      }
    } else if (key === 27) {
      if (self.state.emojiSearchQuery) {
        return;
      }
      if (self.props.showButtons === true) {
        e.preventDefault();
        self.onCancelClicked(e);
      }
    } else {
      if (self.prefillMode && (key === 8 || key === 32 || key === 186 || key === 13)) {
        self.prefillMode = false;
      }
      const currentContent = element.value;
      const currentCursorPos = self.getCursorPosition(element) - 1;
      if (self.prefillMode && (currentCursorPos > self.state.emojiEndPos || currentCursorPos < self.state.emojiStartPos)) {
        self.prefillMode = false;
        self.setState({
          'emojiSearchQuery': false,
          'emojiStartPos': false,
          'emojiEndPos': false
        });
        return;
      }
      if (self.prefillMode) {
        return;
      }
      const char = String.fromCharCode(key);
      if (key === 16 || key === 17 || key === 18 || key === 91 || key === 8 || key === 37 || key === 39 || key === 40 || key === 38 || key === 9 || /[\w:-]/.test(char)) {
        const parsedResult = mega.utils.emojiCodeParser(currentContent, currentCursorPos);
        self.setState({
          'emojiSearchQuery': parsedResult[0],
          'emojiStartPos': parsedResult[1],
          'emojiEndPos': parsedResult[2]
        });
        return;
      }
      if (self.state.emojiSearchQuery) {
        self.setState({
          'emojiSearchQuery': false
        });
      }
    }
  }
  onTypeAreaBlur(e) {
    if (this.props.disabled) {
      e.preventDefault();
      e.stopPropagation();
      return;
    }
    const self = this;
    if (self.state.emojiSearchQuery) {
      setTimeout(() => {
        if (self.isMounted()) {
          self.setState({
            'emojiSearchQuery': false,
            'emojiStartPos': false,
            'emojiEndPos': false
          });
        }
      }, 300);
    }
  }
  onTypeAreaChange(e, value) {
    if (this.props.disabled) {
      e.preventDefault();
      e.stopPropagation();
      return;
    }
    const self = this;
    value = String(value || e.target.value || '').replace(/^\s+/, '');
    if (self.props.text !== value) {
      self.props.onValueChanged(value);
      self.forceUpdate();
    }
    if (value.length) {
      self.typing();
    } else {
      self.stoppedTyping();
    }
    if (this.props.persist) {
      const {
        chatRoom
      } = this.props;
      const {
        megaChat
      } = chatRoom;
      const {
        persistedTypeArea
      } = megaChat.plugins;
      if (persistedTypeArea) {
        if (d > 2) {
          this.logger.debug('%s persisted-typed value...', value.length ? 'Updating' : 'Removing');
        }
        if (value.length) {
          persistedTypeArea.updatePersistedTypedValue(chatRoom, value);
        } else {
          persistedTypeArea.removePersistedTypedValue(chatRoom);
        }
      }
    }
    self.updateScroll();
  }
  focusTypeArea() {
    if (this.props.disabled) {
      return;
    }
    if ($('.chat-textarea:visible textarea:visible', this.domRef.current).length > 0 && !$('.chat-textarea:visible textarea:visible:first', this.domRef.current).is(":focus")) {
      moveCursortoToEnd($('.chat-textarea:visible:first textarea', this.domRef.current)[0]);
    }
  }
  componentDidMount() {
    super.componentDidMount();
    this._lastTextareaHeight = 20;
    this.lastTypedMessage = this.props.initialText || this.lastTypedMessage;
    chatGlobalEventManager.addEventListener('resize', `typingArea${this.getUniqueId()}`, () => this.handleWindowResize());
    this.triggerOnUpdate(true);
    this.updateScroll();
    megaChat.rebind(`viewstateChange.gifpanel${this.getUniqueId()}`, e => {
      const {
        gifPanelActive
      } = this.state;
      const {
        state
      } = e.data;
      if (state === 'active' && !gifPanelActive && this.gifResume) {
        this.setState({
          gifPanelActive: true
        });
        delete this.gifResume;
      } else if (state !== 'active' && gifPanelActive && !this.gifResume) {
        this.gifResume = true;
        this.setState({
          gifPanelActive: false
        });
      }
    });
  }
  UNSAFE_componentWillMount() {
    const {
      chatRoom,
      initialText,
      persist,
      onValueChanged
    } = this.props;
    const {
      megaChat,
      roomId
    } = chatRoom;
    const {
      persistedTypeArea
    } = megaChat.plugins;
    if (persist && persistedTypeArea) {
      if (!initialText) {
        persistedTypeArea.getPersistedTypedValue(chatRoom).then(res => {
          if (res && this.isMounted() && !this.props.text) {
            onValueChanged(res);
          }
        }).catch(ex => {
          if (this.logger && ex !== undefined) {
            this.logger.warn(`Failed to retrieve persistedTypeArea for ${roomId}: ${ex}`, [ex]);
          }
        });
      }
      persistedTypeArea.addChangeListener(this.getUniqueId(), (e, k, v) => {
        if (roomId === k) {
          onValueChanged(v || '');
          this.triggerOnUpdate(true);
        }
      });
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    const self = this;
    self.triggerOnUpdate();
    if (megaChat.plugins.persistedTypeArea) {
      megaChat.plugins.persistedTypeArea.removeChangeListener(self.getUniqueId());
    }
    chatGlobalEventManager.removeEventListener('resize', `typingArea${  self.getUniqueId()}`);
    megaChat.off(`viewstateChange.gifpanel${this.getUniqueId()}`);
  }
  componentDidUpdate() {
    if (this.isComponentEventuallyVisible() && !window.getSelection().toString() && $('textarea:focus,select:focus,input:focus').filter(":visible").length === 0) {
      this.focusTypeArea();
    }
    this.updateScroll();
    if (this.onUpdateCursorPosition) {
      const el = $('.chat-textarea:visible:first textarea:visible', this.domRef.current)[0];
      el.selectionStart = el.selectionEnd = this.onUpdateCursorPosition;
      this.onUpdateCursorPosition = false;
    }
  }
  updateScroll() {
    if (!this.isComponentEventuallyVisible() || !this.$node && !this.domRef && !this.domRef.current) {
      return;
    }
    const $node = this.$node = this.$node || this.domRef.current;
    const $textarea = this.$textarea = this.$textarea || $('textarea:first', $node);
    const $scrollBlock = this.$scrollBlock = this.$scrollBlock || $textarea.closest('.textarea-scroll');
    const $preview = $('.message-preview', $scrollBlock).safeHTML(`${escapeHTML(this.props.text).replace(/\n/g, '<br />')} <br>`);
    const textareaHeight = $preview.height();
    $scrollBlock.height(Math.min(textareaHeight, this.getTextareaMaxHeight()));
    if (textareaHeight !== this._lastTextareaHeight) {
      this._lastTextareaHeight = textareaHeight;
      this.setState({
        textareaHeight
      });
      if (this.props.onResized) {
        this.props.onResized();
      }
      $textarea.height(textareaHeight);
    }
    if (this.textareaScroll) {
      this.textareaScroll.reinitialise();
    }
  }
  getCursorPosition(el) {
    let pos = 0;
    if ('selectionStart' in el) {
      pos = el.selectionStart;
    } else if ('selection' in document) {
      el.focus();
      const sel = document.selection.createRange(),
        selLength = document.selection.createRange().text.length;
      sel.moveStart('character', -el.value.length);
      pos = sel.text.length - selLength;
    }
    return pos;
  }
  customIsEventuallyVisible() {
    return this.props.chatRoom.isCurrentlyActive;
  }
  handleWindowResize(e) {
    if (!this.isComponentEventuallyVisible()) {
      return;
    }
    if (e) {
      this.updateScroll();
    }
    this.triggerOnUpdate();
  }
  isActive() {
    return document.hasFocus() && this.$messages && this.$messages.is(":visible");
  }
  resetPrefillMode() {
    this.prefillMode = false;
  }
  onCopyCapture() {
    this.resetPrefillMode();
  }
  onCutCapture() {
    this.resetPrefillMode();
  }
  onPasteCapture() {
    this.resetPrefillMode();
  }
  render() {
    const self = this;
    const room = this.props.chatRoom;
    let buttons = null;
    if (self.props.showButtons === true) {
      buttons = [REaCt().createElement(ui_buttons.$, {
        key: "save",
        className: `${"mega-button right"} positive`,
        label: l[776],
        onClick: self.onSaveClicked.bind(self)
      }), REaCt().createElement(ui_buttons.$, {
        key: "cancel",
        className: "mega-button right",
        label: l.msg_dlg_cancel,
        onClick: self.onCancelClicked.bind(self)
      })];
    }
    const textareaStyles = {
      height: self.state.textareaHeight
    };
    const textareaScrollBlockStyles = {};
    const newHeight = Math.min(self.state.textareaHeight, self.getTextareaMaxHeight());
    if (newHeight > 0) {
      textareaScrollBlockStyles.height = newHeight;
    }
    let emojiAutocomplete = null;
    if (self.state.emojiSearchQuery) {
      emojiAutocomplete = REaCt().createElement(EmojiAutocomplete, {
        emojiSearchQuery: self.state.emojiSearchQuery,
        emojiStartPos: self.state.emojiStartPos,
        emojiEndPos: self.state.emojiEndPos,
        typedMessage: self.props.text,
        onPrefill (e, emojiAlias) {
          if ($.isNumeric(self.state.emojiStartPos) && $.isNumeric(self.state.emojiEndPos)) {
            const msg = self.props.text;
            const pre = msg.substr(0, self.state.emojiStartPos);
            let post = msg.substr(self.state.emojiEndPos + 1, msg.length);
            const startPos = self.state.emojiStartPos;
            const fwdPos = startPos + emojiAlias.length;
            let endPos = fwdPos;
            self.onUpdateCursorPosition = fwdPos;
            self.prefillMode = true;
            if (post.substr(0, 2) == "::" && emojiAlias.substr(-1) == ":") {
              emojiAlias = emojiAlias.substr(0, emojiAlias.length - 1);
              endPos -= 1;
            } else {
              post = post ? post.substr(0, 1) !== " " ? ` ${  post}` : post : " ";
              self.onUpdateCursorPosition++;
            }
            self.setState({
              'emojiEndPos': endPos
            });
            self.props.onValueChanged(pre + emojiAlias + post);
          }
        },
        onSelect (e, emojiAlias, forceSend) {
          if ($.isNumeric(self.state.emojiStartPos) && $.isNumeric(self.state.emojiEndPos)) {
            const msg = self.props.text;
            const pre = msg.substr(0, self.state.emojiStartPos);
            let post = msg.substr(self.state.emojiEndPos + 1, msg.length);
            if (post.substr(0, 2) == "::" && emojiAlias.substr(-1) == ":") {
              emojiAlias = emojiAlias.substr(0, emojiAlias.length - 1);
            } else {
              post = post ? post.substr(0, 1) !== " " ? ` ${  post}` : post : " ";
            }
            const val = pre + emojiAlias + post;
            self.prefillMode = false;
            self.setState({
              'emojiSearchQuery': false,
              'emojiStartPos': false,
              'emojiEndPos': false
            });
            self.props.onValueChanged(val);
            if (forceSend) {
              if (self.onConfirmTrigger($.trim(val)) !== true) {
                self.props.onValueChanged('');
              }
            }
          }
        },
        onCancel () {
          self.prefillMode = false;
          self.setState({
            'emojiSearchQuery': false,
            'emojiStartPos': false,
            'emojiEndPos': false
          });
        }
      });
    }
    const disabledTextarea = !!(room.pubCu25519KeyIsMissing === true || this.props.disabled);
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                    typingarea-component
                    ${this.props.className}
                `
    }, this.state.gifPanelActive && REaCt().createElement(gifPanel.Ay, {
      chatRoom: this.props.chatRoom,
      onToggle: () => {
        this.setState({
          gifPanelActive: false
        });
        delete this.gifResume;
      }
    }), REaCt().createElement("div", {
      className: `
                        chat-textarea
                        ${this.props.className}
                    `
    }, emojiAutocomplete, self.props.children, self.props.editing ? null : REaCt().createElement(ui_buttons.$, {
      className: `
                                popup-button
                                gif-button
                                ${this.state.gifPanelActive ? 'active' : ''}
                            `,
      icon: "small-icon gif",
      disabled: this.props.disabled,
      onClick: () => this.setState(state => {
        delete this.gifResume;
        return {
          gifPanelActive: !state.gifPanelActive
        };
      })
    }), REaCt().createElement(ui_buttons.$, {
      className: "popup-button emoji-button",
      icon: "sprite-fm-theme icon-emoji",
      iconHovered: "sprite-fm-theme icon-emoji-active",
      disabled: this.props.disabled
    }, REaCt().createElement(emojiDropdown.L, {
      className: "popup emoji",
      vertOffset: 17,
      onClick: this.onEmojiClicked
    })), REaCt().createElement("hr", null), REaCt().createElement(perfectScrollbar.O, {
      chatRoom: self.props.chatRoom,
      className: "chat-textarea-scroll textarea-scroll",
      options: {
        'suppressScrollX': true
      },
      style: textareaScrollBlockStyles,
      ref: ref => {
        self.textareaScroll = ref;
      }
    }, REaCt().createElement("div", {
      className: "messages-textarea-placeholder"
    }, self.props.text ? null : REaCt().createElement(utils.zT, null, (l[18763] || `Write message to \u201c%s\u201d\u2026`).replace('%s', room.getRoomTitle()))), REaCt().createElement("textarea", {
      className: `
                                ${"messages-textarea"}
                                ${disabledTextarea ? 'disabled' : ''}
                            `,
      onKeyUp: this.onTypeAreaKeyUp,
      onKeyDown: this.onTypeAreaKeyDown,
      onBlur: this.onTypeAreaBlur,
      onChange: this.onTypeAreaChange,
      onCopyCapture: this.onCopyCapture,
      onPasteCapture: this.onPasteCapture,
      onCutCapture: this.onCutCapture,
      value: self.props.text,
      style: textareaStyles,
      disabled: disabledTextarea,
      readOnly: disabledTextarea
    }), REaCt().createElement("div", {
      className: "message-preview"
    }))), buttons);
  }
}, (0,applyDecoratedDescriptor.A)(_class.prototype, "handleWindowResize", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "handleWindowResize"), _class.prototype), _class);

},

814:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  A: () => HistoryPanel
});

// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
const applyDecoratedDescriptor = REQ_(793);
// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
// EXTERNAL MODULE: ./js/ui/utils.jsx
const utils = REQ_(314);
;// ./js/chat/ui/messages/alterParticipants.jsx
const React = REQ_(594);
const ContactsUI = REQ_(251);
const ConversationMessageMixin = REQ_(446).M;

class AltPartsConvMessage extends ConversationMessageMixin {
  haveMoreContactListeners() {
    if (!this.props.message || !this.props.message.meta) {
      return false;
    }
    const {
      included,
      excluded
    } = this.props.message.meta;
    return array.unique([...included || [], ...excluded || []]);
  }
  render() {
    const self = this;
    const {message} = this.props;
    const contact = self.getContact();
    const timestampInt = self.getTimestamp();
    const timestamp = self.getTimestampAsString();
    const datetime = React.createElement("div", {
      className: "message date-time simpletip",
      "data-simpletip": time2date(timestampInt, 17)
    }, timestamp);
    let displayName;
    if (contact) {
      displayName = M.getNameByHandle(contact.u);
    } else {
      displayName = contact;
    }
    const messages = [];
    message.meta.included.forEach((h) => {
      const otherContact = M.u[h] ? M.u[h] : {
        'u': h,
        h,
        'c': 0
      };
      const avatar = React.createElement(ContactsUI.Avatar, {
        contact: otherContact,
        chatRoom: self.props.chatRoom,
        className: "message avatar-wrapper small-rounded-avatar"
      });
      const otherDisplayName = M.getNameByHandle(otherContact.u);
      const isSelfJoin = h === contact.u;
      let text = isSelfJoin ? l[23756] : l[8907];
      if (self.props.chatRoom.isMeeting) {
        text = isSelfJoin ? l.meeting_mgmt_user_joined : l.meeting_mgmt_user_added;
      }
      text = text.replace('%1', megaChat.html(otherDisplayName));
      if (!isSelfJoin) {
        text = text.replace('%2', `<strong>${megaChat.html(displayName)}</strong>`);
      }
      messages.push(React.createElement("div", {
        className: "message body",
        "data-id": `id${  message.messageId}`,
        key: `${message.messageId  }_${  h}`
      }, avatar, React.createElement("div", {
        className: "message content-area small-info-txt selectable-txt"
      }, React.createElement(ContactsUI.ContactButton, {
        className: "message",
        contact: otherContact,
        chatRoom: self.props.chatRoom,
        label: React.createElement(utils.zT, null, otherDisplayName)
      }), datetime, React.createElement("div", {
        className: "message text-block"
      }, React.createElement(utils.P9, null, text)))));
    });
    message.meta.excluded.forEach((h) => {
      const otherContact = M.u[h] ? M.u[h] : {
        'u': h,
        h,
        'c': 0
      };
      const avatar = React.createElement(ContactsUI.Avatar, {
        contact: otherContact,
        chatRoom: self.props.chatRoom,
        className: "message avatar-wrapper small-rounded-avatar"
      });
      const otherDisplayName = M.getNameByHandle(otherContact.u);
      let text;
      if (otherContact.u === contact.u) {
        text = self.props.chatRoom.isMeeting ? l.meeting_mgmt_left : l[8908];
      } else {
        text = (self.props.chatRoom.isMeeting ? l.meeting_mgmt_kicked : l[8906]).replace("%s", `<strong>${megaChat.html(displayName)}</strong>`);
      }
      messages.push(React.createElement("div", {
        className: "message body",
        "data-id": `id${  message.messageId}`,
        key: `${message.messageId  }_${  h}`
      }, avatar, React.createElement("div", {
        className: "message content-area small-info-txt selectable-txt"
      }, React.createElement(ContactsUI.ContactButton, {
        className: "message",
        chatRoom: self.props.chatRoom,
        contact: otherContact,
        label: React.createElement(utils.zT, null, otherDisplayName)
      }), datetime, React.createElement("div", {
        className: "message text-block"
      }, React.createElement(utils.P9, null, text)))));
    });
    return React.createElement("div", null, messages);
  }
}

;// ./js/chat/ui/messages/truncated.jsx
const truncated_React = REQ_(594);
const truncated_ContactsUI = REQ_(251);
const truncated_ConversationMessageMixin = REQ_(446).M;

class TruncatedMessage extends truncated_ConversationMessageMixin {
  render() {
    const self = this;
    let cssClasses = "message body";
    const {message} = this.props;
    const {chatRoom} = this.props.message;
    const contact = self.getContact();
    const timestampInt = self.getTimestamp();
    const timestamp = self.getTimestampAsString();
    let datetime = truncated_React.createElement("div", {
      className: "message date-time simpletip",
      "data-simpletip": time2date(timestampInt, 17)
    }, timestamp);
    let displayName;
    if (contact) {
      displayName = M.getNameByHandle(contact.u);
    } else {
      displayName = contact;
    }
    let avatar = null;
    if (this.props.grouped) {
      cssClasses += " grouped";
    } else {
      avatar = truncated_React.createElement(truncated_ContactsUI.Avatar, {
        contact,
        className: "message avatar-wrapper small-rounded-avatar",
        chatRoom
      });
      datetime = truncated_React.createElement("div", {
        className: "message date-time simpletip",
        "data-simpletip": time2date(timestampInt, 17)
      }, timestamp);
    }
    return truncated_React.createElement("div", {
      className: cssClasses,
      "data-id": `id${  message.messageId}`,
      key: message.messageId
    }, avatar, truncated_React.createElement("div", {
      className: "message content-area small-info-txt selectable-txt"
    }, truncated_React.createElement(truncated_ContactsUI.ContactButton, {
      contact,
      className: "message",
      label: truncated_React.createElement(utils.zT, null, displayName),
      chatRoom
    }), datetime, truncated_React.createElement("div", {
      className: "message text-block"
    }, l[8905])));
  }
}

;// ./js/chat/ui/messages/privilegeChange.jsx
const privilegeChange_React = REQ_(594);
const privilegeChange_ContactsUI = REQ_(251);
const privilegeChange_ConversationMessageMixin = REQ_(446).M;

class PrivilegeChange extends privilegeChange_ConversationMessageMixin {
  haveMoreContactListeners() {
    if (!this.props.message.meta || !this.props.message.meta.targetUserId) {
      return false;
    }
    const uid = this.props.message.meta.targetUserId;
    if (uid && M.u[uid]) {
      return uid;
    }
    return false;
  }
  render() {
    const self = this;
    const {message} = this.props;
    const {chatRoom} = this.props.message;
    const contact = self.getContact();
    const timestampInt = self.getTimestamp();
    const timestamp = self.getTimestampAsString();
    const datetime = privilegeChange_React.createElement("div", {
      className: "message date-time simpletip",
      "data-simpletip": time2date(timestampInt, 17)
    }, timestamp);
    let displayName;
    if (contact) {
      displayName = M.getNameByHandle(contact.u);
    } else {
      displayName = contact;
    }
    const messages = [];
    const otherContact = M.u[message.meta.targetUserId] ? M.u[message.meta.targetUserId] : {
      'u': message.meta.targetUserId,
      'h': message.meta.targetUserId,
      'c': 0
    };
    const avatar = privilegeChange_React.createElement(privilegeChange_ContactsUI.Avatar, {
      contact: otherContact,
      className: "message avatar-wrapper small-rounded-avatar",
      chatRoom
    });
    const otherDisplayName = M.getNameByHandle(otherContact.u);
    let newPrivilegeText = "";
    if (message.meta.privilege === 3) {
      newPrivilegeText = l.priv_change_to_op;
    } else if (message.meta.privilege === 2) {
      newPrivilegeText = l.priv_change_to_std;
    } else if (message.meta.privilege === 0) {
      newPrivilegeText = l.priv_change_to_ro;
    }
    const text = newPrivilegeText.replace('[S]', '<strong>').replace('[/S]', '</strong>').replace('%s', `<strong>${megaChat.html(displayName)}</strong>`);
    messages.push(privilegeChange_React.createElement("div", {
      className: "message body",
      "data-id": `id${  message.messageId}`,
      key: message.messageId
    }, avatar, privilegeChange_React.createElement("div", {
      className: "message content-area small-info-txt selectable-txt"
    }, privilegeChange_React.createElement(privilegeChange_ContactsUI.ContactButton, {
      className: "message",
      chatRoom: self.props.chatRoom,
      contact: otherContact,
      label: privilegeChange_React.createElement(utils.zT, null, otherDisplayName)
    }), datetime, privilegeChange_React.createElement("div", {
      className: "message text-block"
    }, privilegeChange_React.createElement(utils.P9, null, text)))));
    return privilegeChange_React.createElement("div", null, messages);
  }
}

;// ./js/chat/ui/messages/topicChange.jsx
const topicChange_React = REQ_(594);
const topicChange_ContactsUI = REQ_(251);
const topicChange_ConversationMessageMixin = REQ_(446).M;

class TopicChange extends topicChange_ConversationMessageMixin {
  render() {
    const self = this;
    const {message} = this.props;
    const {megaChat} = this.props.message.chatRoom;
    const {chatRoom} = this.props.message;
    if (message.meta.isScheduled) {
      return null;
    }
    const contact = self.getContact();
    const timestampInt = self.getTimestamp();
    const timestamp = self.getTimestampAsString();
    const datetime = topicChange_React.createElement("div", {
      className: "message date-time simpletip",
      "data-simpletip": time2date(timestampInt, 17)
    }, timestamp);
    let displayName;
    if (contact) {
      displayName = M.getNameByHandle(contact.u);
    } else {
      displayName = contact;
    }
    const messages = [];
    const avatar = topicChange_React.createElement(topicChange_ContactsUI.Avatar, {
      contact,
      chatRoom,
      className: "message avatar-wrapper small-rounded-avatar"
    });
    const topic = megaChat.html(message.meta.topic);
    const oldTopic = megaChat.html(message.meta.oldTopic) || '';
    messages.push(topicChange_React.createElement("div", {
      className: "message body",
      "data-id": `id${  message.messageId}`,
      key: message.messageId
    }, avatar, topicChange_React.createElement("div", {
      className: "message content-area small-info-txt selectable-txt"
    }, topicChange_React.createElement(topicChange_ContactsUI.ContactButton, {
      className: "message",
      chatRoom,
      contact,
      label: topicChange_React.createElement(utils.zT, null, displayName)
    }), datetime, topicChange_React.createElement("div", {
      className: "message text-block"
    }, topicChange_React.createElement(utils.P9, null, (chatRoom.scheduledMeeting ? l.schedule_mgmt_title.replace('%1', `<strong>${oldTopic}</strong>`) : l[9081]).replace('%s', `<strong>${topic}</strong>`))))));
    return topicChange_React.createElement("div", null, messages);
  }
}

;// ./js/chat/ui/messages/closeOpenMode.jsx
const closeOpenMode_React = REQ_(594);
const closeOpenMode_ContactsUI = REQ_(251);
const closeOpenMode_ConversationMessageMixin = REQ_(446).M;

class CloseOpenModeMessage extends closeOpenMode_ConversationMessageMixin {
  render() {
    const self = this;
    let cssClasses = "message body";
    const {message} = this.props;
    const contact = self.getContact();
    const timestampInt = self.getTimestamp();
    const timestamp = self.getTimestampAsString();
    let datetime = closeOpenMode_React.createElement("div", {
      className: "message date-time",
      title: time2date(timestampInt)
    }, timestamp);
    let displayName;
    if (contact) {
      displayName = M.getNameByHandle(contact.u);
    } else {
      displayName = contact;
    }
    let avatar = null;
    if (this.props.grouped) {
      cssClasses += " grouped";
    } else {
      avatar = closeOpenMode_React.createElement(closeOpenMode_ContactsUI.Avatar, {
        contact,
        className: "message  avatar-wrapper small-rounded-avatar",
        chatRoom: this.props.chatRoom
      });
      datetime = closeOpenMode_React.createElement("div", {
        className: "message date-time",
        title: time2date(timestampInt)
      }, timestamp);
    }
    return closeOpenMode_React.createElement("div", {
      className: cssClasses,
      "data-id": `id${  message.messageId}`,
      key: message.messageId
    }, avatar, closeOpenMode_React.createElement("div", {
      className: "message content-area small-info-txt selectable-txt"
    }, closeOpenMode_React.createElement("div", {
      className: "message user-card-name"
    }, closeOpenMode_React.createElement(utils.zT, null, displayName)), datetime, closeOpenMode_React.createElement("div", {
      className: "message text-block"
    }, l[20569])));
  }
}

;// ./js/chat/ui/messages/chatHandle.jsx
const chatHandle_React = REQ_(594);
const chatHandle_ContactsUI = REQ_(251);
const chatHandle_ConversationMessageMixin = REQ_(446).M;

class ChatHandleMessage extends chatHandle_ConversationMessageMixin {
  render() {
    const self = this;
    let cssClasses = "message body";
    const {message} = this.props;
    const contact = self.getContact();
    const timestampInt = self.getTimestamp();
    const timestamp = self.getTimestampAsString();
    let datetime = chatHandle_React.createElement("div", {
      className: "message date-time",
      title: time2date(timestampInt)
    }, timestamp);
    let displayName;
    if (contact) {
      displayName = M.getNameByHandle(contact.u);
    } else {
      displayName = contact;
    }
    let avatar = null;
    if (this.props.grouped) {
      cssClasses += " grouped";
    } else {
      avatar = chatHandle_React.createElement(chatHandle_ContactsUI.Avatar, {
        contact,
        className: "message  avatar-wrapper small-rounded-avatar",
        chatRoom: this.props.chatRoom
      });
      datetime = chatHandle_React.createElement("div", {
        className: "message date-time",
        title: time2date(timestampInt)
      }, timestamp);
    }
    return chatHandle_React.createElement("div", {
      className: cssClasses,
      "data-id": `id${  message.messageId}`,
      key: message.messageId
    }, avatar, chatHandle_React.createElement("div", {
      className: "message content-area small-info-txt selectable-txt"
    }, chatHandle_React.createElement("div", {
      className: "message user-card-name"
    }, chatHandle_React.createElement(utils.zT, null, displayName)), datetime, chatHandle_React.createElement("div", {
      className: "message text-block"
    }, message.meta.handleUpdate === 1 ? l[20570] : l[20571])));
  }
}

// EXTERNAL MODULE: ./js/chat/ui/messages/generic.jsx + 14 modules
const generic = REQ_(890);
// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
const perfectScrollbar = REQ_(486);
// EXTERNAL MODULE: ./js/chat/ui/messages/mixin.jsx
const mixin = REQ_(446);
// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
const contacts = REQ_(251);
;// ./js/chat/ui/messages/retentionChange.jsx




class RetentionChange extends mixin.M {
  render() {
    const {
      message
    } = this.props;
    const contact = this.getContact();
    return REaCt().createElement("div", {
      className: "message body",
      "data-id": `id${  message.messageId}`,
      key: message.messageId
    }, REaCt().createElement(contacts.Avatar, {
      contact,
      className: "message avatar-wrapper small-rounded-avatar"
    }), REaCt().createElement("div", {
      className: "message content-area small-info-txt selectable-txt"
    }, REaCt().createElement(contacts.ContactButton, {
      contact,
      className: "message",
      label: REaCt().createElement(utils.zT, null, M.getNameByHandle(contact.u))
    }), REaCt().createElement("div", {
      className: "message date-time simpletip",
      "data-simpletip": time2date(this.getTimestamp(), 17)
    }, this.getTimestampAsString()), REaCt().createElement("div", {
      className: "message text-block"
    }, message.getMessageRetentionSummary())));
  }
}
// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
const call = REQ_(3);
// EXTERNAL MODULE: ./js/chat/ui/messages/scheduleMetaChange.jsx
const scheduleMetaChange = REQ_(757);
;// ./js/chat/ui/historyPanel.jsx

let _dec, _class;














const HistoryPanel = (_dec = (0,mixins.hG)(450, true), _class = class HistoryPanel extends mixins.w9 {
  constructor(props) {
    super(props);
    this.$container = null;
    this.$messages = null;
    this.domRef = REaCt().createRef();
    this.state = {
      editing: false,
      toast: false
    };
    this.renderNotice = label => REaCt().createElement("div", {
      className: "dropdown body dropdown-arrow down-arrow tooltip not-sent-notification-cancel hidden"
    }, REaCt().createElement("i", {
      className: "dropdown-white-arrow"
    }), REaCt().createElement("div", {
      className: "dropdown notification-text"
    }, REaCt().createElement("i", {
      className: "small-icon conversations"
    }), label));
    this.renderLoadingSpinner = () => REaCt().createElement("div", {
      style: {
        top: '50%'
      },
      className: `
                loading-spinner
                js-messages-loading
                light
                manual-management
                ${this.loadingShown ? '' : 'hidden'}
            `
    }, REaCt().createElement("div", {
      className: "main-loader",
      style: {
        position: 'fixed',
        top: '50%',
        left: '50%'
      }
    }));
    this.renderNavigationToast = () => {
      const {
        chatRoom
      } = this.props;
      const unreadCount = chatRoom.messagesBuff.getUnreadCount();
      return REaCt().createElement("div", {
        className: `
                    theme-dark-forced
                    messages-toast
                    ${this.state.toast ? 'active' : ''}
                `,
        onClick: () => {
          this.setState({
            toast: false
          }, () => {
            this.messagesListScrollable.scrollToBottom();
            chatRoom.scrolledToBottom = true;
          });
        }
      }, REaCt().createElement("i", {
        className: "sprite-fm-mono icon-down"
      }), unreadCount > 0 && REaCt().createElement("span", null, unreadCount > 9 ? '9+' : unreadCount));
    };
    this.onKeyboardScroll = ({
      keyCode
    }) => {
      let _scrollbar$domRef;
      const scrollbar = this.messagesListScrollable;
      const domNode = scrollbar == null || (_scrollbar$domRef = scrollbar.domRef) == null ? void 0 : _scrollbar$domRef.current;
      if (domNode && this.isComponentEventuallyVisible() && !this.state.attachCloudDialog) {
        const scrollPositionY = scrollbar.getScrollPositionY();
        const offset = parseInt(domNode.style.height);
        const PAGE = {
          UP: 33,
          DOWN: 34
        };
        switch (keyCode) {
          case PAGE.UP:
            scrollbar.scrollToY(scrollPositionY - offset, true);
            this.onMessagesScrollUserScroll(scrollbar, 100);
            break;
          case PAGE.DOWN:
            if (!scrollbar.isAtBottom()) {
              scrollbar.scrollToY(scrollPositionY + offset, true);
            }
            break;
        }
      }
    };
    this.onMessagesScrollUserScroll = (ps, offset = 5) => {
      const {
        chatRoom
      } = this.props;
      const {
        messagesBuff
      } = chatRoom;
      const scrollPositionY = ps.getScrollPositionY();
      if (messagesBuff.messages.length === 0) {
        chatRoom.scrolledToBottom = true;
        return;
      }
      if (ps.isCloseToBottom(30) === true) {
        if (!chatRoom.scrolledToBottom) {
          messagesBuff.detachMessages();
        }
        chatRoom.scrolledToBottom = true;
      } else {
        chatRoom.scrolledToBottom = false;
      }
      if (!this.scrollPullHistoryRetrieval && !messagesBuff.isRetrievingHistory && (ps.isAtTop() || scrollPositionY < offset && ps.getScrollHeight() > 500) && messagesBuff.haveMoreHistory()) {
        ps.disable();
        this.scrollPullHistoryRetrieval = true;
        this.lastScrollPosition = scrollPositionY;
        let msgAppended = 0;
        const scrYOffset = ps.getScrollHeight();
        chatRoom.one('onMessagesBuffAppend.pull', () => {
          msgAppended++;
        });
        chatRoom.off('onHistoryDecrypted.pull');
        chatRoom.one('onHistoryDecrypted.pull', () => {
          chatRoom.off('onMessagesBuffAppend.pull');
          if (msgAppended > 0) {
            this._reposOnUpdate = scrYOffset;
          }
          this.scrollPullHistoryRetrieval = -1;
        });
        messagesBuff.retrieveChatHistory();
      }
      if (this.lastScrollPosition !== scrollPositionY) {
        this.lastScrollPosition = scrollPositionY;
      }
      delay('chat-toast', this.initToast, 200);
    };
    this.initToast = () => {
      let _this$messagesListScr;
      const {
        chatRoom
      } = this.props;
      return this.isMounted() && this.setState({
        toast: !chatRoom.scrolledToBottom && !((_this$messagesListScr = this.messagesListScrollable) != null && _this$messagesListScr.isCloseToBottom != null && _this$messagesListScr.isCloseToBottom(30))
      }, () => this.state.toast ? null : chatRoom.trigger('onChatIsFocused'));
    };
    this.handleWindowResize = this._handleWindowResize.bind(this);
  }
  customIsEventuallyVisible() {
    return this.props.chatRoom.isCurrentlyActive;
  }
  UNSAFE_componentWillMount() {
    let _chatRoom$messagesBuf;
    const {
      chatRoom
    } = this.props;
    chatRoom.rebind('onHistoryDecrypted.cp', () => this.eventuallyUpdate());
    this._messagesBuffChangeHandler = (_chatRoom$messagesBuf = chatRoom.messagesBuff) == null ? void 0 : _chatRoom$messagesBuf.addChangeListener(SoonFc(() => {
      if (this.isComponentEventuallyVisible()) {
        let _this$domRef;
        $('.js-messages-scroll-area', (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current).trigger('forceResize', [true]);
      }
      this.refreshUI();
    }));
  }
  componentDidMount() {
    super.componentDidMount();
    const {
      chatRoom,
      onMount
    } = this.props;
    window.addEventListener('resize', this.handleWindowResize);
    window.addEventListener('keydown', this.handleKeyDown);
    this.$container = $(`.conversation-panel[data-room-id="${chatRoom.chatId}"]`);
    this.eventuallyInit();
    chatRoom.trigger('onHistoryPanelComponentDidMount');
    if (onMount) {
      onMount(this);
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    const {
      chatRoom
    } = this.props;
    if (this._messagesBuffChangeHandler) {
      let _chatRoom$messagesBuf2;
      (_chatRoom$messagesBuf2 = chatRoom.messagesBuff) == null || _chatRoom$messagesBuf2.removeChangeListener(this._messagesBuffChangeHandler);
      delete this._messagesBuffChangeHandler;
    }
    window.removeEventListener('resize', this.handleWindowResize);
    window.removeEventListener('keydown', this.handleKeyDown);
    $(document).off(`fullscreenchange.megaChat_${chatRoom.roomId}`);
    $(document).off(`keydown.keyboardScroll_${chatRoom.roomId}`);
  }
  componentDidUpdate(prevProps, prevState) {
    let _self$domRef;
    const self = this;
    self.eventuallyInit(false);
    const domNode = (_self$domRef = self.domRef) == null ? void 0 : _self$domRef.current;
    const jml = domNode && domNode.querySelector('.js-messages-loading');
    if (jml) {
      if (self.loadingShown) {
        jml.classList.remove('hidden');
      } else {
        jml.classList.add('hidden');
      }
    }
    self.handleWindowResize();
    if (prevState.editing === false && self.state.editing !== false && self.messagesListScrollable) {
      self.messagesListScrollable.reinitialise(false);
      Soon(() => {
        if (self.editDomElement && self.editDomElement.length === 1) {
          self.messagesListScrollable.scrollToElement(self.editDomElement[0], false);
        }
      });
    }
    if (self._reposOnUpdate !== undefined) {
      const ps = self.messagesListScrollable;
      ps.__prevPosY = ps.getScrollHeight() - self._reposOnUpdate + self.lastScrollPosition;
      ps.scrollToY(ps.__prevPosY, true);
    }
  }
  eventuallyInit(doResize) {
    let _this$domRef2;
    if (this.initialised) {
      return;
    }
    const domNode = (_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current;
    if (domNode) {
      this.initialised = true;
    } else {
      return;
    }
    this.$messages = $('.messages.scroll-area > .perfectScrollbarContainer', this.$container);
    this.$messages.droppable({
      tolerance: 'pointer',
      drop(e, ui) {
        $.doDD(e, ui, 'drop', 1);
      },
      over(e, ui) {
        $.doDD(e, ui, 'over', 1);
      },
      out(e, ui) {
        $.doDD(e, ui, 'out', 1);
      }
    });
    this.lastScrollPosition = null;
    this.props.chatRoom.scrolledToBottom = true;
    if (doResize !== false) {
      this.handleWindowResize();
    }
  }
  _handleWindowResize(e, scrollToBottom) {
    if (!M.chat) {
      return;
    }
    if (!this.isMounted()) {
      this.componentWillUnmount();
      return;
    }
    if (!this.isComponentEventuallyVisible()) {
      return;
    }
    const self = this;
    self.eventuallyInit(false);
    if (!self.$messages) {
      return;
    }
    if (call.Ay.isExpanded()) {
      const $container = $('.meetings-call');
      const $messages = $('.js-messages-scroll-area', $container);
      const $textarea = $('.chat-textarea-block', $container);
      const $sidebar = $('.sidebar', $container);
      const scrollBlockHeight = parseInt($sidebar.outerHeight(), 10) - parseInt($textarea.outerHeight(), 10) - 72;
      if ($sidebar.hasClass('chat-opened') && scrollBlockHeight !== $messages.outerHeight()) {
        $messages.css('height', scrollBlockHeight);
        self.refreshUI(true);
      }
      return;
    }
    const scrollBlockHeight = $('.chat-content-block', self.$container).outerHeight() - ($('.chat-topic-block', self.$container).outerHeight() || 0) - (is_chatlink ? $('.join-chat-block', self.$container).outerHeight() : $('.messages-block .chat-textarea-block', self.$container).outerHeight());
    if (scrollBlockHeight !== self.$messages.outerHeight()) {
      self.$messages.css('height', scrollBlockHeight);
      $('.messages.main-pad', self.$messages).css('min-height', scrollBlockHeight);
      self.refreshUI(true);
    } else {
      self.refreshUI(scrollToBottom);
    }
  }
  refreshUI() {
    if (this.isComponentEventuallyVisible()) {
      const room = this.props.chatRoom;
      room.renderContactTree();
      room.megaChat.refreshConversations();
      room.trigger('RefreshUI');
      if (room.scrolledToBottom) {
        delay(`hp:reinit-scroll:${this.getUniqueId()}`, () => {
          if (this.messagesListScrollable) {
            this.messagesListScrollable.reinitialise(true, true);
          }
        }, 30);
      }
    }
  }
  isLoading() {
    const {chatRoom} = this.props;
    if (chatRoom.historyTimedOut) {
      return false;
    }
    const mb = chatRoom.messagesBuff;
    return this.scrollPullHistoryRetrieval === true || chatRoom.activeSearches || mb.messagesHistoryIsLoading() || mb.joined === false || mb.isDecrypting;
  }
  specShouldComponentUpdate() {
    return !this.loadingShown && this.isComponentEventuallyVisible();
  }
  enableScrollbar() {
    const ps = this.messagesListScrollable;
    ps.enable();
    this._reposOnUpdate = undefined;
    this.lastScrollPosition = ps.__prevPosY | 0;
  }
  editMessage(messageId) {
    const self = this;
    self.setState({
      'editing': messageId
    });
    self.props.chatRoom.scrolledToBottom = false;
  }
  onMessageEditDone(v, messageContents) {
    const self = this;
    const room = this.props.chatRoom;
    room.scrolledToBottom = true;
    self.editDomElement = null;
    const currentContents = v.textContents;
    v.edited = false;
    if (messageContents === false || messageContents === currentContents) {
      let _self$messagesListScr;
      (_self$messagesListScr = self.messagesListScrollable) == null || _self$messagesListScr.scrollToBottom(true);
    } else if (messageContents) {
      let _self$messagesListScr2;
      room.trigger('onMessageUpdating', v);
      room.megaChat.plugins.chatdIntegration.updateMessage(room, v.internalId ? v.internalId : v.orderValue, messageContents);
      if (v.getState && (v.getState() === Message.STATE.NOT_SENT || v.getState() === Message.STATE.SENT) && !v.requiresManualRetry) {
        if (v.textContents) {
          v.textContents = messageContents;
        }
        if (v.emoticonShortcutsProcessed) {
          v.emoticonShortcutsProcessed = false;
        }
        if (v.emoticonsProcessed) {
          v.emoticonsProcessed = false;
        }
        if (v.messageHtml) {
          delete v.messageHtml;
        }
        v.trigger('onChange', [v, "textContents", "", messageContents]);
        megaChat.plugins.richpreviewsFilter.processMessage({}, v, false, true);
      }
      (_self$messagesListScr2 = self.messagesListScrollable) == null || _self$messagesListScr2.scrollToBottom(true);
    } else if (messageContents.length === 0) {
      this.props.onDeleteClicked(v);
    }
    self.setState({
      'editing': false
    });
    self.refreshUI();
    Soon(() => {
      $('.chat-textarea-block:visible textarea').focus();
    }, 300);
  }
  render() {
    const self = this;
    const room = this.props.chatRoom;
    if (!room || !room.roomId) {
      return null;
    }
    const contacts = room.getParticipantsExceptMe();
    let contactHandle;
    let contact;
    let avatarMeta;
    let contactName = "";
    if (contacts && contacts.length === 1) {
      contactHandle = contacts[0];
      contact = M.u[contactHandle];
      avatarMeta = contact ? generateAvatarMeta(contact.u) : {};
      contactName = avatarMeta.fullName;
    } else if (contacts && contacts.length > 1) {
      contactName = room.getRoomTitle();
    }
    let messagesList = [];
    if (this.isLoading()) {
      self.loadingShown = true;
    } else {
      const mb = room.messagesBuff;
      if (this.scrollPullHistoryRetrieval < 0) {
        this.scrollPullHistoryRetrieval = false;
        self.enableScrollbar();
      }
      delete self.loadingShown;
      if (room.historyTimedOut || mb.joined === true && !self.scrollPullHistoryRetrieval && mb.haveMoreHistory() === false) {
        const $$WELCOME_MESSAGE = ({
          heading,
          title,
          info,
          className
        }) => REaCt().createElement("div", {
          className: `
                            messages
                            welcome-message
                            ${className || ''}
                        `
        }, REaCt().createElement(utils.P9, {
          tag: "h1",
          content: heading
        }), title && REaCt().createElement("span", null, title), info);
        messagesList = [...messagesList, room.isNote ? $$WELCOME_MESSAGE({
          heading: l.note_heading,
          info: REaCt().createElement("p", null, REaCt().createElement("i", {
            className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
          }), l.note_description),
          className: 'note-chat-info'
        }) : $$WELCOME_MESSAGE({
          heading: room.scheduledMeeting || !contactName ? megaChat.html(room.getRoomTitle()) : l[8002].replace('%s', `<span>${megaChat.html(contactName)}</span>`),
          title: l[8080],
          info: REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("p", null, REaCt().createElement("i", {
            className: "sprite-fm-mono icon-lock"
          }), REaCt().createElement(utils.P9, {
            content: l[8540].replace("[S]", "<strong>").replace("[/S]", "</strong>")
          })), REaCt().createElement("p", null, REaCt().createElement("i", {
            className: "sprite-fm-mono icon-accept"
          }), REaCt().createElement(utils.P9, {
            content: l[8539].replace("[S]", "<strong>").replace("[/S]", "</strong>")
          })))
        })];
      }
    }
    let lastTimeMarker;
    let lastMessageFrom = null;
    let lastGroupedMessageTimeStamp = null;
    let grouped = false;
    for (let i = 0; i < room.messagesBuff.messages.length; i++) {
      let v = room.messagesBuff.messages.getItem(i);
      if (!v.protocol && v.revoked !== true) {
        let shouldRender = true;
        if (v.isManagement && v.isManagement() === true && v.isRenderableManagement() === false || v.deleted === true) {
          shouldRender = false;
        }
        const timestamp = v.delay;
        const curTimeMarker = getTimeMarker(timestamp);
        if (shouldRender === true && curTimeMarker && lastTimeMarker !== curTimeMarker) {
          lastTimeMarker = curTimeMarker;
          messagesList.push(REaCt().createElement("div", {
            className: "message date-divider selectable-txt",
            key: `${v.messageId  }_marker`,
            title: time2date(timestamp)
          }, curTimeMarker));
          grouped = false;
          lastMessageFrom = null;
          lastGroupedMessageTimeStamp = null;
        }
        if (shouldRender === true) {
          let {userId} = v;
          if (!userId && contact && contact.u) {
            userId = contact.u;
          }
          if (v instanceof Message && v.dialogType !== "truncated") {
            if (!lastMessageFrom || userId && lastMessageFrom === userId) {
              if (timestamp - lastGroupedMessageTimeStamp < 300) {
                grouped = true;
              } else {
                grouped = false;
                lastMessageFrom = userId;
                lastGroupedMessageTimeStamp = timestamp;
              }
            } else {
              grouped = false;
              lastMessageFrom = userId;
              if (lastMessageFrom === userId) {
                lastGroupedMessageTimeStamp = timestamp;
              } else {
                lastGroupedMessageTimeStamp = null;
              }
            }
          } else {
            grouped = false;
            lastMessageFrom = null;
            lastGroupedMessageTimeStamp = null;
          }
        }
        if ((v.dialogType === "remoteCallEnded" || v.dialogType === "remoteCallStarted") && v && v.wrappedChatDialogMessage) {
          v = v.wrappedChatDialogMessage;
        }
        if (v.dialogType) {
          let messageInstance = null;
          if (v.dialogType === 'alterParticipants') {
            messageInstance = REaCt().createElement(AltPartsConvMessage, {
              message: v,
              key: v.messageId,
              contact: Message.getContactForMessage(v),
              grouped,
              chatRoom: room
            });
          } else if (v.dialogType === 'truncated') {
            messageInstance = REaCt().createElement(TruncatedMessage, {
              message: v,
              key: v.messageId,
              contact: Message.getContactForMessage(v),
              grouped,
              chatRoom: room
            });
          } else if (v.dialogType === 'privilegeChange') {
            messageInstance = REaCt().createElement(PrivilegeChange, {
              message: v,
              key: v.messageId,
              contact: Message.getContactForMessage(v),
              grouped,
              chatRoom: room
            });
          } else if (v.dialogType === 'topicChange') {
            messageInstance = REaCt().createElement(TopicChange, {
              message: v,
              key: v.messageId,
              contact: Message.getContactForMessage(v),
              grouped,
              chatRoom: room
            });
          } else if (v.dialogType === 'openModeClosed') {
            messageInstance = REaCt().createElement(CloseOpenModeMessage, {
              message: v,
              key: v.messageId,
              contact: Message.getContactForMessage(v),
              grouped,
              chatRoom: room
            });
          } else if (v.dialogType === 'chatHandleUpdate') {
            messageInstance = REaCt().createElement(ChatHandleMessage, {
              message: v,
              key: v.messageId,
              contact: Message.getContactForMessage(v),
              grouped,
              chatRoom: room
            });
          } else if (v.dialogType === 'messageRetention') {
            messageInstance = REaCt().createElement(RetentionChange, {
              message: v,
              key: v.messageId,
              contact: Message.getContactForMessage(v)
            });
          } else if (v.dialogType === 'scheduleMeta') {
            if (v.meta.onlyTitle) {
              messageInstance = REaCt().createElement(TopicChange, {
                message: v,
                key: v.messageId,
                contact: Message.getContactForMessage(v),
                grouped,
                chatRoom: v.chatRoom
              });
            } else {
              if (v.meta.topicChange) {
                messagesList.push(REaCt().createElement(TopicChange, {
                  message: v,
                  key: `${v.messageId}-topic`,
                  contact: Message.getContactForMessage(v),
                  grouped,
                  chatRoom: v.chatRoom
                }));
              }
              messageInstance = REaCt().createElement(scheduleMetaChange.A, {
                message: v,
                key: v.messageId,
                mode: v.meta.mode,
                chatRoom: room,
                grouped,
                link: v.chatRoom.publicLink,
                contact: Message.getContactForMessage(v)
              });
            }
          }
          messagesList.push(messageInstance);
        } else {
          if (!v.chatRoom) {
            v.chatRoom = room;
          }
          messagesList.push(REaCt().createElement(generic.A, {
            message: v,
            state: v.state,
            key: v.messageId,
            contact: Message.getContactForMessage(v),
            grouped,
            onUpdate: () => {
              self.onResizeDoUpdate();
            },
            editing: self.state.editing === v.messageId || self.state.editing === v.pendingMessageId,
            onEditStarted: ((v, $domElement) => {
              self.editDomElement = $domElement;
              self.setState({
                'editing': v.messageId
              });
              self.forceUpdate();
            }).bind(this, v),
            chatRoom: room,
            onEditDone: this.onMessageEditDone.bind(this, v),
            onDeleteClicked: msg => {
              if (this.props.onDeleteClicked) {
                this.props.onDeleteClicked(msg);
              }
            },
            onResized: () => {
              this.handleWindowResize();
            },
            onEmojiBarChange: () => {
              this.handleWindowResize();
            }
          }));
        }
      }
    }
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: `
                    messages
                    scroll-area
                    ${this.props.className || ''}
                `
    }, REaCt().createElement(perfectScrollbar.O, {
      className: "js-messages-scroll-area perfectScrollbarContainer",
      ref: ref => {
        let _this$props$onMessage, _this$props;
        this.messagesListScrollable = ref;
        $(document).rebind(`keydown.keyboardScroll_${room.roomId}`, this.onKeyboardScroll);
        (_this$props$onMessage = (_this$props = this.props).onMessagesListScrollableMount) == null || _this$props$onMessage.call(_this$props, ref);
      },
      chatRoom: room,
      messagesBuff: room.messagesBuff,
      editDomElement: this.state.editDomElement,
      editingMessageId: this.state.editing,
      confirmDeleteDialog: this.state.confirmDeleteDialog,
      renderedMessagesCount: messagesList.length,
      options: {
        suppressScrollX: true
      },
      isLoading: room.messagesBuff.messagesHistoryIsLoading() || room.activeSearches > 0 || this.loadingShown,
      onFirstInit: ps => {
        ps.scrollToBottom(true);
        room.scrolledToBottom = 1;
      },
      onUserScroll: this.onMessagesScrollUserScroll
    }, REaCt().createElement("div", {
      className: "messages main-pad"
    }, REaCt().createElement("div", {
      className: "messages content-area"
    }, this.renderLoadingSpinner(), messagesList))), this.renderNavigationToast());
  }
}, (0,applyDecoratedDescriptor.A)(_class.prototype, "enableScrollbar", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "enableScrollbar"), _class.prototype), _class);


},

815:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
Q: () => InviteParticipantsPanel
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);
const _meetings_call_jsx1__ = REQ_(3);
const _ui_miniui_jsx2__ = REQ_(818);
const _ui_buttons_jsx3__ = REQ_(994);
const _ui_dropdowns_jsx4__ = REQ_(911);





const NAMESPACE = 'invite-panel';
class InviteParticipantsPanel extends react0().Component {
  constructor(props) {
    super(props);
    this.domRef = react0().createRef();
    this.state = {
      link: '',
      copied: false
    };
    this.retrieveChatLink();
  }
  retrieveChatLink(cim) {
    const {
      chatRoom
    } = this.props;
    if (!chatRoom.topic) {
      return;
    }
    this.loading = chatRoom.updatePublicHandle(false, cim).always(() => {
      delete this.loading;
      if (this.domRef.current) {
        if (chatRoom.publicLink) {
          this.setState({
            link: `${getBaseUrl()}/${chatRoom.publicLink}`
          });
        } else {
          this.setState({
            link: false
          });
        }
      }
    });
  }
  getInviteBody(encode) {
    const {
      chatRoom
    } = this.props;
    const {
      link
    } = this.state;
    const {
      scheduledMeeting
    } = chatRoom;
    let body = l.invite_body_text;
    if (scheduledMeeting) {
      const {
        nextOccurrenceStart
      } = chatRoom.scheduledMeeting;
      body = l.invite_body_text_scheduled.replace('%4', time2date(nextOccurrenceStart / 1000, 20)).replace('%5', toLocaleTime(nextOccurrenceStart));
    }
    body = body.replace(/\[BR]/g, '\n').replace('%1', u_attr.name).replace('%2', chatRoom.getRoomTitle()).replace('%3', link);
    if (encode) {
      return typeof body.toWellFormatted === 'function' ? body.toWellFormatted() : body.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '').replace(/[\uD800-\uDBFF]/g, '\uFFFD').replace(/[\uDC00-\uDFFF]/g, '\uFFFD');
    }
    return body;
  }
  render() {
    const {
      chatRoom,
      disableLinkToggle,
      onAddParticipants
    } = this.props;
    const {
      link,
      copied
    } = this.state;
    const inCall = _meetings_call_jsx1__.Ay.isExpanded();
    if (this.loading) {
      return react0().createElement("div", {
        ref: this.domRef,
        className: `
                        ${NAMESPACE}
                        ${inCall ? 'theme-dark-forced' : ''}
                    `
      }, react0().createElement("header", null), react0().createElement("section", {
        className: "content"
      }, react0().createElement("div", {
        className: "content-block"
      })));
    }
    const canInvite = !!(chatRoom.iAmOperator() || chatRoom.options[MCO_FLAGS.OPEN_INVITE]) && onAddParticipants;
    const canToggleLink = !disableLinkToggle && chatRoom.iAmOperator() && (chatRoom.isMeeting || chatRoom.topic);
    const mailto = `mailto:?to=&subject=${l.invite_subject_text}&body=${this.getInviteBody(true)}`;
    const copyText = chatRoom.isMeeting ? l.copy_meeting_link : l[1394];
    return react0().createElement("div", {
      ref: this.domRef,
      className: `
                    ${NAMESPACE}
                    ${inCall ? 'theme-dark-forced' : ''}
                `
    }, react0().createElement("header", null, react0().createElement("h3", null, l.invite_participants)), react0().createElement("section", {
      className: "content"
    }, canToggleLink && chatRoom.type !== 'group' && react0().createElement("div", {
      className: "content-block link-block"
    }, react0().createElement("div", {
      className: "text-wrapper"
    }, react0().createElement("span", {
      className: "link-label"
    }, l.invite_toggle_link_label), react0().createElement("div", {
      className: `link-description ${inCall ? '' : 'hidden'}`
    }, l.invite_toggle_link_desc)), react0().createElement(_ui_miniui_jsx2__.A.ToggleCheckbox, {
      className: "meeting-link-toggle",
      checked: !!link,
      value: !!link,
      onToggle: () => {
        if (this.loading) {
          return;
        }
        if (link) {
          this.loading = chatRoom.updatePublicHandle(true).always(() => {
            delete this.loading;
            if (this.domRef.current) {
              this.setState({
                link: false
              });
            }
          });
        } else {
          this.retrieveChatLink(true);
        }
      }
    })), link && react0().createElement("div", {
      className: "content-block"
    }, react0().createElement(_ui_buttons_jsx3__.$, {
      className: "flat-button",
      icon: `sprite-fm-mono icon-${copied ? 'check' : 'link-thin-outline'}`,
      label: copied ? l.copied : copyText,
      onClick: () => {
        if (copied) {
          return;
        }
        delay('chat-event-inv-copylink', () => eventlog(99964));
        copyToClipboard(link);
        this.setState({
          copied: true
        }, () => {
          tSleep(3).then(() => {
            if (this.domRef.current) {
              this.setState({
                copied: false
              });
            }
          });
        });
      }
    })), link && react0().createElement("div", {
      className: "content-block"
    }, react0().createElement(_ui_buttons_jsx3__.$, {
      className: "flat-button",
      label: l.share_chat_link,
      icon: "sprite-fm-mono icon-share-02-thin-outline"
    }, react0().createElement(_ui_dropdowns_jsx4__.Dropdown, {
      className: `
                                    button-group-menu
                                    invite-dropdown
                                    ${inCall ? 'theme-dark-forced' : ''}
                                `,
      noArrow: true,
      positionAt: "left bottom",
      collision: "none",
      horizOffset: 79,
      vertOffset: 6,
      ref: r => {
        this.dropdownRef = r;
      },
      onBeforeActiveChange: e => {
        if (e) {
          delay('chat-event-inv-dropdown', () => eventlog(99965));
          $(document.body).trigger('closeAllDropdownsExcept', this.dropdownRef);
        }
      }
    }, react0().createElement(_ui_dropdowns_jsx4__.DropdownItem, {
      key: "send-invite",
      className: `
                                        ${inCall ? 'theme-dark-forced' : ''}
                                    `,
      icon: "sprite-fm-mono icon-mail-thin-outline",
      label: l.share_chat_link_invite,
      onClick: () => {
        delay('chat-event-inv-email', () => eventlog(99966));
        window.open(mailto, '_self', 'noopener,noreferrer');
      }
    }), react0().createElement(_ui_dropdowns_jsx4__.DropdownItem, {
      key: "copy-invite",
      className: `
                                        ${inCall ? 'theme-dark-forced' : ''}
                                    `,
      label: l.copy_chat_link_invite,
      icon: "sprite-fm-mono icon-square-copy",
      onClick: () => {
        delay('chat-event-inv-copy', () => eventlog(99967));
        copyToClipboard(this.getInviteBody(), l.invite_copied);
      }
    })))), canInvite && (link || canToggleLink) && chatRoom.type !== 'group' && react0().createElement("div", {
      className: "content-block invite-panel-divider"
    }, l.invite_dlg_divider), canInvite && react0().createElement("div", {
      className: "content-block add-participant-block"
    }, react0().createElement(_ui_buttons_jsx3__.$, {
      className: "flat-button",
      icon: "sprite-fm-mono icon-user-square-thin-outline",
      label: l.add_participants,
      onClick: () => {
        delay('chat-event-inv-add-participant', () => eventlog(99968));
        onAddParticipants();
      }
    }))));
  }
}

},

818:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
A: () => __WEBPACK_DEFAULT_EXPORT__
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);
const _chat_mixins1__ = REQ_(137);


class ToggleCheckbox extends _chat_mixins1__.w9 {
  constructor(props) {
    super(props);
    this.domRef = react0().createRef();
    this.onToggle = () => {
      const newState = !this.state.value;
      this.setState({
        value: newState
      });
      if (this.props.onToggle) {
        this.props.onToggle(newState);
      }
    };
    this.state = {
      value: this.props.value
    };
  }
  render() {
    return react0().createElement("div", {
      ref: this.domRef,
      className: `
                    mega-switch
                    ${this.props.className}
                    ${this.state.value ? 'toggle-on' : ''}
                `,
      role: "switch",
      "aria-checked": !!this.state.value,
      onClick: this.onToggle
    }, react0().createElement("div", {
      className: `mega-feature-switch sprite-fm-mono-after
                         ${this.state.value ? 'icon-check-after' : 'icon-minimise-after'}`
    }));
  }
}
const __WEBPACK_DEFAULT_EXPORT__ = {
  ToggleCheckbox
};

},

844:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
L: () => DropdownEmojiSelector
});
const _extends0__ = REQ_(168);
const _chat_mixins1__ = REQ_(137);

const React = REQ_(594);

const DropdownsUI = REQ_(911);
const PerfectScrollbar = REQ_(486).O;
class DropdownEmojiSelector extends _chat_mixins1__.w9 {
  constructor(props) {
    super(props);
    this.domRef = React.createRef();
    this.emojiSearchRef = React.createRef();
    this.data_categories = null;
    this.data_emojis = null;
    this.data_emojiByCategory = null;
    this.customCategoriesOrder = ["frequently_used", "people", "nature", "food", "activity", "travel", "objects", "symbols", "flags"];
    this.frequentlyUsedEmojis = ['slight_smile', 'grinning', 'smile', 'rofl', 'wink', 'yum', 'rolling_eyes', 'stuck_out_tongue', 'smiling_face_with_3_hearts', 'heart_eyes', 'kissing_heart', 'sob', 'pleading_face', 'thumbsup', 'pray', 'wave', 'fire', 'sparkles'];
    this.heightDefs = {
      'categoryTitleHeight': 55,
      'emojiRowHeight': 35,
      'containerHeight': 302,
      'totalScrollHeight': 302,
      'numberOfEmojisPerRow': 9
    };
    this.categoryLabels = {
      'frequently_used': l[17737],
      'people': l[8016],
      'objects': l[17735],
      'activity': l[8020],
      'nature': l[8017],
      'travel': l[8021],
      'symbols': l[17736],
      'food': l[8018],
      'flags': l[17703]
    };
    this.state = this.getInitialState();
    this.onSearchChange = this.onSearchChange.bind(this);
    this.onUserScroll = this.onUserScroll.bind(this);
    this._onScrollChanged = this._onScrollChanged.bind(this);
  }
  getInitialState() {
    return clone({
      'previewEmoji': null,
      'searchValue': '',
      'browsingCategory': false,
      'isActive': false,
      'isLoading': true,
      'loadFailed': false,
      'visibleCategories': "0"
    });
  }
  _generateEmoji(meta) {
    const filename = twemoji.convert.toCodePoint(meta.u);
    return React.createElement("img", {
      width: "20",
      height: "20",
      className: "emoji emoji-loading",
      draggable: "false",
      alt: meta.u,
      title: `:${  meta.n  }:`,
      onLoad: e => {
        e.target.classList.remove('emoji-loading');
      },
      onError: e => {
        e.target.classList.remove('emoji-loading');
        e.target.classList.add('emoji-loading-error');
      },
      src: `${staticpath  }images/mega/twemojis/2_v2/72x72/${  filename  }.png`
    });
  }
  _generateEmojiElement(emoji, cat) {
    const self = this;
    const categoryName = self.data_categories[cat];
    return React.createElement("div", {
      "data-emoji": emoji.n,
      className: "button square-button emoji",
      key: `${categoryName  }_${  emoji.n}`,
      onMouseEnter: e => {
        if (self.mouseEnterTimer) {
          clearTimeout(self.mouseEnterTimer);
        }
        e.stopPropagation();
        e.preventDefault();
        self.mouseEnterTimer = setTimeout(() => {
          self.setState({
            'previewEmoji': emoji
          });
        }, 250);
      },
      onMouseLeave: e => {
        if (self.mouseEnterTimer) {
          clearTimeout(self.mouseEnterTimer);
        }
        e.stopPropagation();
        e.preventDefault();
        self.setState({
          'previewEmoji': null
        });
      },
      onClick: e => {
        if (self.props.onClick) {
          self.props.onClick(e, emoji.n, emoji);
          $(document).trigger('closeDropdowns');
        }
      }
    }, self._generateEmoji(emoji));
  }
  UNSAFE_componentWillUpdate(nextProps, nextState) {
    if (nextState.searchValue !== this.state.searchValue || nextState.browsingCategories !== this.state.browsingCategories) {
      this._cachedNodes = {};
      if (this.scrollableArea) {
        this.scrollableArea.scrollToY(0);
      }
      this._onScrollChanged(0, nextState);
    }
    if (nextState.isActive === true) {
      const self = this;
      if (nextState.isLoading === true || !self.loadingPromise && (!self.data_categories || !self.data_emojis)) {
        const p = [megaChat.getEmojiDataSet('categories'), megaChat.getEmojiDataSet('emojis')];
        this.loadingPromise = Promise.all(p).then(([categories, emojis]) => {
          this.data_emojis = emojis;
          this.data_categories = categories;
          self.data_categories.push('frequently_used');
          self.data_categoriesWithCustomOrder = [];
          self.customCategoriesOrder.forEach((catName) => {
            self.data_categoriesWithCustomOrder.push(self.data_categories.indexOf(catName));
          });
          self.data_emojiByCategory = {};
          const frequentlyUsedEmojisMeta = {};
          self.data_emojis.forEach((emoji) => {
            const cat = emoji.c;
            if (!self.data_emojiByCategory[cat]) {
              self.data_emojiByCategory[cat] = [];
            }
            if (self.frequentlyUsedEmojis.indexOf(emoji.n) > -1) {
              frequentlyUsedEmojisMeta[emoji.n] = emoji.u;
            }
            emoji.element = self._generateEmojiElement(emoji, cat);
            self.data_emojiByCategory[cat].push(emoji);
          });
          self.data_emojiByCategory[8] = [];
          self.frequentlyUsedEmojis.forEach((slug) => {
            const emoji = {
              'n': slug,
              'u': frequentlyUsedEmojisMeta[slug]
            };
            emoji.element = self._generateEmojiElement(emoji, 99);
            self.data_emojiByCategory[8].push(emoji);
          });
          self._onScrollChanged(0);
          self.setState({
            'isLoading': false
          });
        }).catch(ex => {
          if (d) {
            console.error("Emoji loading failed.", ex);
          }
          this.setState({
            'loadFailed': true,
            'isLoading': false
          });
        });
      }
    } else if (nextState.isActive === false) {
      if (this.data_emojis) {
        for (let i = this.data_emojis.length; i--;) {
          delete this.data_emojis[i].element;
        }
      }
      this.data_emojis = null;
      this.data_categories = null;
      this.data_emojiByCategory = null;
      this.loadingPromise = null;
    }
  }
  onSearchChange(e) {
    const self = this;
    self.setState({
      searchValue: e.target.value,
      browsingCategory: false
    });
  }
  onUserScroll($ps) {
    if (this.state.browsingCategory) {
      const $cat = $(`.emoji-category-container[data-category-name="${  this.state.browsingCategory  }"]`);
      if (!elementInViewport($cat)) {
        this.setState({
          'browsingCategory': false
        });
      }
    }
    this._onScrollChanged($ps.getScrollPositionY());
  }
  generateEmojiElementsByCategory(categoryId, posTop, stateObj) {
    const self = this;
    if (!self._cachedNodes) {
      self._cachedNodes = {};
    }
    if (!stateObj) {
      stateObj = self.state;
    }
    if (typeof self._cachedNodes[categoryId] !== 'undefined') {
      return self._cachedNodes[categoryId];
    }
    const categoryName = self.data_categories[categoryId];
    const emojis = [];
    const {searchValue} = stateObj;
    let totalEmojis = 0;
    self.data_emojiByCategory[categoryId].forEach((meta) => {
      const slug = meta.n;
      if (searchValue.length > 0) {
        if (`:${  slug  }:`.toLowerCase().indexOf(searchValue.toLowerCase()) < 0) {
          return;
        }
      }
      totalEmojis++;
      emojis.push(meta.element);
    });
    if (emojis.length > 0) {
      const totalHeight = self.heightDefs.categoryTitleHeight + Math.ceil(totalEmojis / self.heightDefs.numberOfEmojisPerRow) * self.heightDefs.emojiRowHeight;
      return self._cachedNodes[categoryId] = [totalHeight, React.createElement("div", {
        key: categoryName,
        "data-category-name": categoryName,
        className: "emoji-category-container",
        style: {
          'position': 'absolute',
          'top': posTop
        }
      }, emojis.length > 0 ? React.createElement("div", {
        className: "clear"
      }) : null, React.createElement("div", {
        className: "emoji-type-txt"
      }, self.categoryLabels[categoryName] ? self.categoryLabels[categoryName] : categoryName), React.createElement("div", {
        className: "clear"
      }), emojis, React.createElement("div", {
        className: "clear"
      }))];
    } else {
      return self._cachedNodes[categoryId] = undefined;
    }
  }
  _isVisible(scrollTop, scrollBottom, elTop, elBottom) {
    const visibleTop = elTop < scrollTop ? scrollTop : elTop;
    const visibleBottom = elBottom > scrollBottom ? scrollBottom : elBottom;
    return visibleBottom - visibleTop > 0;
  }
  _onScrollChanged(scrollPositionY, stateObj) {
    const self = this;
    if (!self.data_categoriesWithCustomOrder) {
      return;
    }
    if (scrollPositionY === false) {
      scrollPositionY = self.scrollableArea.getScrollPositionY();
    }
    if (!stateObj) {
      stateObj = self.state;
    }
    const visibleStart = scrollPositionY;
    const visibleEnd = visibleStart + self.heightDefs.containerHeight;
    let currentPos = 0;
    let visibleCategories = [];
    self._emojiReactElements = [];
    self.data_categoryPositions = {};
    self.data_categoriesWithCustomOrder.forEach((k) => {
      const categoryDivMeta = self.generateEmojiElementsByCategory(k, currentPos, stateObj);
      if (categoryDivMeta) {
        const startPos = currentPos;
        currentPos += categoryDivMeta[0];
        const endPos = currentPos;
        self.data_categoryPositions[k] = startPos;
        if (self._isVisible(visibleStart, visibleEnd, startPos, endPos)) {
          visibleCategories.push(k);
          self._emojiReactElements.push(categoryDivMeta[1]);
        }
      }
    });
    if (self._emojiReactElements.length === 0) {
      const emojisNotFound = React.createElement("span", {
        className: "emojis-not-found",
        key: 'emojis-not-found'
      }, l[20920]);
      self._emojiReactElements.push(emojisNotFound);
    }
    visibleCategories = visibleCategories.join(',');
    self.setState({
      'totalScrollHeight': currentPos,
      visibleCategories
    });
  }
  _renderEmojiPickerPopup() {
    const self = this;
    let preview;
    if (self.state.previewEmoji) {
      const meta = self.state.previewEmoji;
      preview = React.createElement("div", {
        className: "emoji-preview"
      }, self._generateEmoji(meta), React.createElement("div", {
        className: "emoji title"
      }, `:${  meta.n  }:`));
    }
    const categoryIcons = {
      "frequently_used": "icon-emoji-type-frequent",
      "people": "icon-emoji-type-people",
      "nature": "icon-emoji-type-nature",
      "food": "icon-emoji-type-food",
      "activity": "icon-emoji-type-activity",
      "travel": "icon-emoji-type-travel",
      "objects": "icon-emoji-type-objects",
      "symbols": "icon-emoji-type-symbol",
      "flags": "icon-emoji-type-flag"
    };
    const categoryButtons = [];
    let activeCategoryName = false;
    if (!self.state.searchValue) {
      const firstActive = self.state.visibleCategories.split(",")[0];
      if (firstActive) {
        activeCategoryName = self.data_categories[firstActive];
      }
    }
    self.customCategoriesOrder.forEach(categoryName => {
      categoryButtons.push(React.createElement("div", {
        visiblecategories: this.state.visibleCategories,
        className: `
                        button square-button emoji
                        ${activeCategoryName === categoryName ? 'active' : ''}
                    `,
        key: categoryIcons[categoryName],
        onClick: e => {
          e.stopPropagation();
          e.preventDefault();
          this.setState({
            browsingCategory: categoryName,
            searchValue: ''
          });
          this._cachedNodes = {};
          const categoryPosition = this.data_categoryPositions[this.data_categories.indexOf(categoryName)] + 10;
          this.scrollableArea.scrollToY(categoryPosition);
          this._onScrollChanged(categoryPosition);
          const {
            current
          } = this.emojiSearchRef || !1;
          current == null || current.focus();
        }
      }, React.createElement("i", {
        className: `sprite-fm-mono ${categoryIcons[categoryName]}`
      })));
    });
    return React.createElement(React.Fragment, null, React.createElement("div", {
      className: "popup-header emoji"
    }, preview || React.createElement("div", {
      className: "search-block emoji"
    }, React.createElement("i", {
      className: "sprite-fm-mono icon-preview-reveal"
    }), React.createElement("input", {
      ref: this.emojiSearchRef,
      type: "search",
      placeholder: l[102],
      onChange: this.onSearchChange,
      autoFocus: true,
      value: this.state.searchValue
    }))), React.createElement(PerfectScrollbar, {
      className: "popup-scroll-area emoji perfectScrollbarContainer",
      searchValue: this.state.searchValue,
      onUserScroll: this.onUserScroll,
      visibleCategories: this.state.visibleCategories,
      ref: ref => {
        this.scrollableArea = ref;
      }
    }, React.createElement("div", {
      className: "popup-scroll-content emoji"
    }, React.createElement("div", {
      style: {
        height: this.state.totalScrollHeight
      }
    }, this._emojiReactElements))), React.createElement("div", {
      className: "popup-footer emoji"
    }, categoryButtons));
  }
  render() {
    const self = this;
    let popupContents = null;
    if (self.state.isActive === true) {
      if (self.state.loadFailed === true) {
        popupContents = React.createElement("div", {
          className: "loading"
        }, l[1514]);
      } else if (this.state.isLoading || !this.data_emojiByCategory || !this.data_categories) {
        popupContents = React.createElement("div", {
          className: "loading"
        }, l[5533]);
      } else {
        popupContents = self._renderEmojiPickerPopup();
      }
    } else {
      popupContents = null;
    }
    return React.createElement(DropdownsUI.Dropdown, (0,_extends0__.A)({
      className: "popup emoji"
    }, self.props, {
      isLoading: self.state.isLoading,
      loadFailed: self.state.loadFailed,
      visibleCategories: this.state.visibleCategories,
      forceShowWhenEmpty: true,
      onActiveChange: newValue => {
        if (newValue === false) {
          self.setState(self.getInitialState());
          self._cachedNodes = {};
          self._onScrollChanged(0);
        } else {
          self.setState({
            'isActive': true
          });
        }
        if (self.props.onActiveChange) {
          self.props.onActiveChange(newValue);
        }
      },
      searchValue: self.state.searchValue,
      browsingCategory: self.state.browsingCategory,
      previewEmoji: self.state.previewEmoji
    }), React.createElement("div", {
      ref: this.domRef
    }, popupContents));
  }
}
DropdownEmojiSelector.defaultProps = {
  'requiresUpdateOnResize': true,
  'hideable': true
};

},

890:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  A: () => GenericConversationMessage
});

// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
const esm_extends = REQ_(168);
// EXTERNAL MODULE: external "React"
const React_ = REQ_(594);
const REaCt = REQ_.n(React_);
// EXTERNAL MODULE: ./js/chat/ui/messages/mixin.jsx
const mixin = REQ_(446);
// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
const ui_contacts = REQ_(251);
// EXTERNAL MODULE: ./js/ui/utils.jsx
const utils = REQ_(314);
;// ./js/chat/ui/messages/abstractGenericMessage.jsx




class AbstractGenericMessage extends mixin.M {
  constructor(...args) {
    super(...args);
    this.domRef = REaCt().createRef();
  }
  getAvatar() {
    const contact = this.getContact() || Message.getContactForMessage(this.props.message);
    if (this.props.grouped) {
      return null;
    }
    return contact ? REaCt().createElement(ui_contacts.Avatar, {
      contact: this.getContact(),
      className: "message avatar-wrapper small-rounded-avatar",
      chatRoom: this.props.chatRoom
    }) : null;
  }
  getName() {
    const contact = this.getContact() || Message.getContactForMessage(this.props.message);
    if (this.props.grouped) {
      return null;
    }
    return contact ? REaCt().createElement(ui_contacts.ContactButton, {
      contact,
      className: "message",
      label: REaCt().createElement(utils.zT, null, M.getNameByHandle(contact.u)),
      chatRoom: this.props.message.chatRoom,
      dropdownDisabled: !!this.props.dialog
    }) : null;
  }
  renderMessageActionButtons(buttons) {
    if (!buttons) {
      return null;
    }
    const cnt = buttons.length;
    if (cnt === 0) {
      return null;
    }
    return REaCt().createElement("div", {
      className: `right-aligned-msg-buttons ${cnt && cnt > 1 ? `total-${cnt}` : ''}`
    }, buttons);
  }
  render() {
    const {
      message,
      grouped,
      additionalClasses,
      hideActionButtons
    } = this.props;
    if (message.deleted) {
      return null;
    }
    return REaCt().createElement("div", {
      ref: this.domRef,
      "data-id": message.messageId,
      className: `
                    ${this.getClassNames ? this.getClassNames() : grouped ? 'grouped' : ''}
                    ${additionalClasses}
                    ${message.messageId}
                    message
                    body
                `
    }, this.getAvatar && this.getAvatar(), REaCt().createElement("div", {
      className: "message content-area selectable-txt"
    }, this.getName && this.getName(), this.getMessageTimestamp ? this.getMessageTimestamp() : grouped ? null : REaCt().createElement("div", {
      className: "message date-time simpletip",
      "data-simpletip": time2date(this.getTimestamp(), 17),
      "data-simpletipposition": "top",
      "data-simpletipoffset": "4"
    }, this.getTimestampAsString()), !hideActionButtons && this.getMessageActionButtons && this.renderMessageActionButtons(this.getMessageActionButtons()), this.getContents && this.getContents(), hideActionButtons ? null : this.getEmojisImages()));
  }
}
;// ./js/chat/ui/messages/utils.jsx
let getMessageString;
(function () {
  let MESSAGE_STRINGS;
  let MESSAGE_STRINGS_GROUP;
  let MESSAGE_STRINGS_MEETING;
  const _sanitizeStrings = function (arg) {
    if (typeof arg === "undefined") {
      return arg;
    } else if (typeof arg === "string") {
      return escapeHTML(arg);
    } else if (arg.forEach) {
      arg.forEach((v, k) => {
        arg[k] = _sanitizeStrings(v);
      });
    } else if (typeof arg === "object") {
      Object.keys(arg).forEach((k) => {
        arg[k] = _sanitizeStrings(arg[k]);
      });
    }
    return arg;
  };
  getMessageString = function (type, isGroupCall, isMeeting) {
    if (!MESSAGE_STRINGS) {
      MESSAGE_STRINGS = {
        'outgoing-call': l[5891].replace("[X]", "[[[X]]]"),
        'incoming-call': l[19964] || "[[%s]] is calling...",
        'call-timeout': [l[18698].replace("[X]", "[[[X]]]")],
        'call-starting': l[7206].replace("[X]", "[[[X]]]"),
        'call-feedback': l[7998].replace("[X]", "[[[X]]]"),
        'call-initialising': l[7207].replace("[X]", "[[[X]]]"),
        'call-ended': [l[19965] || "Call ended.", l[7208]],
        'remoteCallEnded': [l[19965] || "Call ended.", l[7208]],
        'call-failed-media': l[7204],
        'call-failed': [l[19966] || "Call failed.", l[7208]],
        'call-handled-elsewhere': l[5895].replace("[X]", "[[[X]]]"),
        'call-missed': l[17870],
        'call-rejected': l[19040],
        'call-canceled': l[19041],
        'remoteCallStarted': l[5888],
        'call-started': l[5888].replace("[X]", "[[[X]]]"),
        'alterParticipants': undefined,
        'privilegeChange': undefined,
        'truncated': l[8905]
      };
      _sanitizeStrings(MESSAGE_STRINGS);
    }
    if (isGroupCall && !MESSAGE_STRINGS_GROUP) {
      MESSAGE_STRINGS_GROUP = {
        'call-ended': [l[19967], l[7208]],
        'remoteCallEnded': [l[19967], l[7208]],
        'call-handled-elsewhere': l[19968],
        'call-canceled': l[19969],
        'call-started': l[19970]
      };
      _sanitizeStrings(MESSAGE_STRINGS_GROUP);
    }
    if (isMeeting && !MESSAGE_STRINGS_MEETING) {
      MESSAGE_STRINGS_MEETING = {
        'call-ended': [l.meeting_mgmt_call_ended, l[7208]],
        'remoteCallEnded': [l.meeting_mgmt_call_ended, l[7208]],
        'call-started': l.meeting_mgmt_call_started
      };
    }
    if (isMeeting && MESSAGE_STRINGS_MEETING[type]) {
      return MESSAGE_STRINGS_MEETING[type];
    }
    if (isGroupCall && MESSAGE_STRINGS_GROUP[type]) {
      return MESSAGE_STRINGS_GROUP[type];
    }
    return MESSAGE_STRINGS[type];
  };
})();
mega.ui = mega.ui || {};
mega.ui.chat = mega.ui.chat || {};
mega.ui.chat.getMessageString = getMessageString;

;// ./js/chat/ui/messages/types/local.jsx





const MESSAGE_TYPE = {
  OUTGOING: 'outgoing-call',
  INCOMING: 'incoming-call',
  TIMEOUT: 'call-timeout',
  STARTING: 'call-starting',
  FEEDBACK: 'call-feedback',
  INITIALISING: 'call-initialising',
  ENDED: 'call-ended',
  ENDED_REMOTE: 'remoteCallEnded',
  FAILED: 'call-failed',
  FAILED_MEDIA: 'call-failed-media',
  HANDLED_ELSEWHERE: 'call-handled-elsewhere',
  MISSED: 'call-missed',
  REJECTED: 'call-rejected',
  CANCELLED: 'call-canceled',
  STARTED: 'call-started',
  STARTED_REMOTE: 'remoteCallStarted',
  ALTER_PARTICIPANTS: 'alterParticipants',
  PRIVILEGE_CHANGE: 'privilegeChange',
  TRUNCATED: 'truncated'
};
class Local extends AbstractGenericMessage {
  componentDidMount() {
    super.componentDidMount();
    this._setClassNames();
  }
  _roomIsGroup() {
    return this.props.message.chatRoom.type === 'group' || this.props.message.chatRoom.type === 'public';
  }
  _getParticipantNames(message) {
    return message.meta && message.meta.participants && !!message.meta.participants.length && message.meta.participants.map(handle => `[[${megaChat.html(M.getNameByHandle(handle))}]]`);
  }
  _getExtraInfo(message) {
    const {
      meta,
      type
    } = message;
    const participantNames = this._getParticipantNames(message);
    const HAS_PARTICIPANTS = participantNames && !!participantNames.length && participantNames.length > 1;
    const HAS_DURATION = meta && meta.duration;
    const ENDED = type === MESSAGE_TYPE.ENDED || type === MESSAGE_TYPE.FAILED || type === MESSAGE_TYPE.CANCELLED;
    let messageExtraInfo = [HAS_PARTICIPANTS ? mega.utils.trans.listToString(participantNames, l[20234]) : ''];
    if (ENDED) {
      messageExtraInfo = [...messageExtraInfo, HAS_PARTICIPANTS ? '. ' : '', HAS_DURATION ? l[7208].replace('[X]', `[[${secToDuration(meta.duration)}]]`) : ''];
    }
    return messageExtraInfo && messageExtraInfo.reduce((acc, cur) => (acc + cur).replace(/\[\[/g, '<span class="bold">').replace(/]]/g, '</span>'));
  }
  _setClassNames() {
    let cssClass;
    switch (this.props.message.type) {
      case MESSAGE_TYPE.REJECTED:
        cssClass = 'sprite-fm-theme icon-handset-rejected';
        break;
      case MESSAGE_TYPE.MISSED:
        cssClass = 'sprite-fm-theme icon-handset-missed';
        break;
      case MESSAGE_TYPE.OUTGOING:
      case MESSAGE_TYPE.HANDLED_ELSEWHERE:
        cssClass = 'sprite-fm-theme icon-handset-outgoing';
        break;
      case MESSAGE_TYPE.FAILED:
      case MESSAGE_TYPE.FAILED_MEDIA:
        cssClass = 'sprite-fm-theme icon-handset-failed';
        break;
      case MESSAGE_TYPE.ENDED:
      case MESSAGE_TYPE.TIMEOUT:
        cssClass = 'sprite-fm-theme icon-handset-ended';
        break;
      case MESSAGE_TYPE.CANCELLED:
        cssClass = 'sprite-fm-theme icon-handset-cancelled';
        break;
      case MESSAGE_TYPE.FEEDBACK:
      case MESSAGE_TYPE.STARTING:
      case MESSAGE_TYPE.STARTED:
        cssClass = 'sprite-fm-mono icon-phone';
        break;
      case MESSAGE_TYPE.INCOMING:
        cssClass = 'sprite-fm-theme icon-handset-incoming';
        break;
      default:
        cssClass = `sprite-fm-mono ${  this.props.message.type}`;
        break;
    }
    this.props.message.cssClass = cssClass;
  }
  _getIcon(message) {
    const MESSAGE_ICONS = {
      [MESSAGE_TYPE.STARTED]: `<i class="${"call-info-icon"} sprite-fm-mono icon-phone">&nbsp;</i>`,
      [MESSAGE_TYPE.ENDED]: `<i class="${"call-info-icon"} sprite-fm-theme icon-handset-ended">&nbsp;</i>`,
      DEFAULT: `<i class="${"call-info-icon"} ${message.cssClass}">&nbsp;</i>`
    };
    return MESSAGE_ICONS[message.type] || MESSAGE_ICONS.DEFAULT;
  }
  _getText() {
    const {
      message
    } = this.props;
    const IS_GROUP = this._roomIsGroup();
    let messageText = getMessageString(message.type, IS_GROUP, message.chatRoom.isMeeting);
    if (!messageText) {
      return console.error(`Message with type: ${message.type} -- no text string defined. Message: ${message}`);
    }
    messageText = CallManager2._getMltiStrTxtCntsForMsg(message, messageText.splice ? messageText : [messageText], true);
    messageText = megaChat.html(messageText);
    message.textContents = String(messageText).replace("[[", "<span class=\"bold\">").replace("]]", "</span>");
    if (IS_GROUP) {
      messageText = `
                ${this._getIcon(message)}
                <div class="call-info-content">
                    <span class="call-info-message bold">${messageText}</span>
                    ${this._getExtraInfo(message)}
                </div>
            `;
    }
    return messageText;
  }
  _getAvatarsListing() {
    const {
      message
    } = this.props;
    if (this._roomIsGroup() && message.type === MESSAGE_TYPE.STARTED && message.messageId === `${MESSAGE_TYPE.STARTED}-${message.chatRoom.getActiveCallMessageId()}`) {
      const unique = message.chatRoom.uniqueCallParts ? Object.keys(message.chatRoom.uniqueCallParts) : [];
      return unique.map(handle => REaCt().createElement(ui_contacts.Avatar, {
        key: handle,
        contact: M.u[handle],
        simpletip: true,
        className: "message avatar-wrapper small-rounded-avatar"
      }));
    }
    return null;
  }
  _getButtons() {
    const {
      message
    } = this.props;
    if (message.buttons && Object.keys(message.buttons).length) {
      return REaCt().createElement("div", {
        className: "buttons-block"
      }, Object.keys(message.buttons).map(key => {
        const button = message.buttons[key];
        return REaCt().createElement("button", {
          key,
          className: button.classes,
          onClick: e => button.callback(e.target)
        }, button.icon && REaCt().createElement("div", null, REaCt().createElement("i", {
          className: `small-icon ${button.icon}`
        })), REaCt().createElement("span", null, button.text));
      }), REaCt().createElement("div", {
        className: "clear"
      }));
    }
  }
  getAvatar() {
    const {
      message,
      grouped
    } = this.props;
    if (message.type === MESSAGE_TYPE.FEEDBACK) {
      return null;
    }
    const $$AVATAR = REaCt().createElement(ui_contacts.Avatar, {
      contact: message.authorContact,
      className: "message avatar-wrapper small-rounded-avatar",
      chatRoom: message.chatRoom
    });
    const $$ICON = REaCt().createElement("div", {
      className: "feedback call-status-block"
    }, REaCt().createElement("i", {
      className: `sprite-fm-mono ${message.cssClass}`
    }));
    return message.showInitiatorAvatar ? grouped ? null : $$AVATAR : $$ICON
    ;
  }
  getMessageTimestamp() {
    let _this$props$message;
    const callId = (_this$props$message = this.props.message) == null || (_this$props$message = _this$props$message.meta) == null ? void 0 : _this$props$message.callId;
    let debugMsg = "";
    if (d && callId) {
      debugMsg = `: callId: ${callId}`;
    }
    return REaCt().createElement("div", {
      className: "message date-time simpletip",
      "data-simpletip": time2date(this.getTimestamp(), 17)
    }, this.getTimestampAsString(), debugMsg);
  }
  getClassNames() {
    const {
      message: {
        showInitiatorAvatar,
        type
      },
      grouped
    } = this.props;
    const classNames = [showInitiatorAvatar && grouped && 'grouped', this._roomIsGroup() && type !== MESSAGE_TYPE.OUTGOING && type !== MESSAGE_TYPE.INCOMING && 'with-border'];
    return classNames.filter(className => className).join(' ');
  }
  getName() {
    const {
      message,
      grouped
    } = this.props;
    const contact = this.getContact();
    return message.showInitiatorAvatar && !grouped ? REaCt().createElement(ui_contacts.ContactButton, {
      contact,
      className: "message",
      label: REaCt().createElement(utils.zT, null, message.authorContact ? M.getNameByHandle(message.authorContact.u) : ''),
      chatRoom: message.chatRoom
    }) : M.getNameByHandle(contact.u);
  }
  getContents() {
    const {
      message: {
        getState
      }
    } = this.props;
    return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
      className: "message text-block"
    }, REaCt().createElement("div", {
      className: "message call-inner-block"
    }, REaCt().createElement("div", {
      className: "call-info"
    }, REaCt().createElement("div", {
      className: "call-info-container"
    }, REaCt().createElement(utils.P9, {
      className: "info-wrapper"
    }, this._getText())), REaCt().createElement("div", {
      className: "call-info-avatars"
    }, this._getAvatarsListing(), REaCt().createElement("div", {
      className: "clear"
    }))))), getState && getState() === Message.STATE.NOT_SENT ? null : this._getButtons());
  }
}
// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
const dropdowns = REQ_(911);
// EXTERNAL MODULE: ./js/ui/buttons.jsx
const buttons = REQ_(994);
;// ./js/chat/ui/messages/types/contact.jsx






class Contact extends AbstractGenericMessage {
  constructor(...args) {
    super(...args);
    this.DIALOG = {
      ADDED: addedEmail => msgDialog('info', l[150], l[5898].replace('[X]', addedEmail)),
      DUPLICATE: () => msgDialog('warningb', '', l[17545])
    };
  }
  haveMoreContactListeners() {
    const {
      message
    } = this.props;
    const textContents = message.textContents.substring(2, message.textContents.length);
    const attachmentMeta = JSON.parse(textContents);
    if (!attachmentMeta) {
      return false;
    }
    const contacts = attachmentMeta.map(v => v.u);
    return contacts.length ? contacts : false;
  }
  _doAddContact(contactEmail) {
    return M.inviteContact(M.u[u_handle] ? M.u[u_handle].m : u_attr.email, contactEmail);
  }
  _handleAddContact(contactEmail) {
    let _this$props$chatRoom;
    if ((_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.isAnonymous()) {
      return this._doAddContact(contactEmail).then(addedEmail => this.DIALOG.ADDED(addedEmail)).catch(this.DIALOG.DUPLICATE);
    }
    return Object.values(M.opc).some(opc => opc.m === contactEmail) ? this.DIALOG.DUPLICATE() : this._doAddContact(contactEmail).then(addedEmail => this.DIALOG.ADDED(addedEmail))
    ;
  }
  _getContactAvatar(contact, className) {
    return REaCt().createElement(ui_contacts.Avatar, {
      className: `avatar-wrapper ${className}`,
      contact: M.u[contact.u],
      chatRoom: this.props.chatRoom
    });
  }
  _getContactDeleteButton(message) {
    if (message.isEditable()) {
      return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-dialog-close",
        label: l[83],
        onClick: e => this.props.onDelete(e, message)
      }));
    }
  }
  _getContactCard(message, contact, contactEmail) {
    const HAS_RELATIONSHIP = M.u[contact.u].c === 1;
    let name = REaCt().createElement(ui_contacts.ContactAwareName, {
      emoji: true,
      contact: M.u[contact.u]
    });
    const {
      chatRoom
    } = this.props;
    const isAnonView = chatRoom.isAnonymous();
    if (megaChat.FORCE_EMAIL_LOADING) {
      name += `(${  contact.m  })`;
    }
    return REaCt().createElement(buttons.$, {
      ref: ref => {
        this.buttonRef = ref;
      },
      className: "tiny-button",
      icon: "tiny-icon icons-sprite grey-dots"
    }, REaCt().createElement(dropdowns.Dropdown, {
      className: "white-context-menu shared-contact-dropdown",
      noArrow: true,
      positionMy: "left bottom",
      positionAt: "right bottom",
      horizOffset: 4
    }, REaCt().createElement("div", {
      className: "dropdown-avatar rounded"
    }, this._getContactAvatar(contact, 'context-avatar'), isAnonView ? REaCt().createElement("div", {
      className: "dropdown-user-name"
    }) : REaCt().createElement("div", {
      className: "dropdown-user-name"
    }, REaCt().createElement("div", {
      className: "name"
    }, HAS_RELATIONSHIP && (this.isLoadingContactInfo() ? REaCt().createElement("em", {
      className: "contact-name-loading"
    }) : name), !HAS_RELATIONSHIP && name, REaCt().createElement(ui_contacts.ContactPresence, {
      className: "small",
      contact
    })), REaCt().createElement("div", {
      className: "email"
    }, M.u[contact.u].m))), REaCt().createElement(ui_contacts.ContactFingerprint, {
      contact: M.u[contact.u]
    }), HAS_RELATIONSHIP && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(dropdowns.DropdownItem, {
      icon: "sprite-fm-mono icon-user-filled",
      label: l[5868],
      onClick: () => {
        loadSubPage(`fm/chat/contacts/${  contact.u}`);
        mBroadcaster.sendMessage('contact:open');
      }
    }), REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
      icon: "sprite-fm-mono icon-chat-filled",
      label: l[8632],
      onClick: () => {
        loadSubPage(`fm/chat/p/${  contact.u}`);
        mBroadcaster.sendMessage('chat:open');
      }
    })), u_type && u_type > 2 && contact.u !== u_handle && !HAS_RELATIONSHIP && !is_eplusplus && REaCt().createElement(dropdowns.DropdownItem, {
      icon: "sprite-fm-mono icon-add",
      label: l[71],
      onClick: () => this._handleAddContact(contactEmail)
    }), this._getContactDeleteButton(message)));
  }
  getContents() {
    const {
      message,
      chatRoom
    } = this.props;
    const textContents = message.textContents.substr(2, message.textContents.length);
    const attachmentMeta = JSON.parse(textContents);
    const isAnonView = chatRoom.isAnonymous();
    if (!attachmentMeta) {
      return console.error(`Message w/ type: ${message.type} -- no attachment meta defined. Message: ${message}`);
    }
    let contacts = [];
    attachmentMeta.forEach(v => {
      let _this$buttonRef;
      const contact = M.u && v.u in M.u && M.u[v.u].m ? M.u[v.u] : v;
      const contactEmail = contact.email ? contact.email : contact.m;
      if (!M.u[contact.u]) {
        M.u.set(contact.u, new MegaDataObject(MEGA_USER_STRUCT, {
          'u': contact.u,
          'name': contact.name,
          'm': contact.email ? contact.email : contactEmail,
          'c': undefined
        }));
      } else if (M.u[contact.u] && !M.u[contact.u].m) {
        M.u[contact.u].m = contact.email ? contact.email : contactEmail;
      }
      contacts = [...contacts, REaCt().createElement("div", {
        key: contact.u
      }, isAnonView ? REaCt().createElement("div", {
        className: "message shared-info"
      }) : REaCt().createElement("div", {
        className: "message shared-info"
      }, REaCt().createElement("div", {
        className: "message data-title selectable-txt",
        onClick: (_this$buttonRef = this.buttonRef) == null ? void 0 : _this$buttonRef.onClick
      }, REaCt().createElement(utils.zT, null, M.getNameByHandle(contact.u))), M.u[contact.u] ? REaCt().createElement(ui_contacts.ContactVerified, {
        className: "right-align",
        contact: M.u[contact.u]
      }) : null, REaCt().createElement("div", {
        className: "user-card-email selectable-txt"
      }, contactEmail)), REaCt().createElement("div", {
        className: "message shared-data"
      }, REaCt().createElement("div", {
        className: "data-block-view semi-big"
      }, M.u[contact.u] ? REaCt().createElement(ui_contacts.ContactPresence, {
        className: "small",
        contact: M.u[contact.u]
      }) : null, this._getContactCard(message, contact, contactEmail), this._getContactAvatar(contact, 'medium-avatar')), REaCt().createElement("div", {
        className: "clear"
      })))];
    });
    return REaCt().createElement("div", {
      className: "message shared-block"
    }, contacts);
  }
}
;// ./js/chat/ui/messages/types/attachment.jsx




class Attachment extends AbstractGenericMessage {
  _isRevoked(node) {
    return !M.chd[node.ch] || node.revoked;
  }
  _isUserRegistered() {
    return typeof u_type !== 'undefined' && u_type > 2;
  }
  getContents() {
    const {
      message,
      chatRoom
    } = this.props;
    const contact = this.getContact();
    const NODE_DOESNT_EXISTS_ANYMORE = {};
    const attachmentMeta = message.getAttachmentMeta() || [];
    const files = [];
    for (let i = 0; i < attachmentMeta.length; i++) {
      var _this$buttonRef;
      const v = attachmentMeta[i];
      if (this._isRevoked(v)) {
        continue;
      }
      const {
        icon,
        isImage,
        isVideo,
        isAudio,
        isText,
        showThumbnail,
        isPreviewable
      } = M.getMediaProperties(v);
      let dropdown = null;
      let noThumbPrev = '';
      var previewButton = null;
      if (isPreviewable) {
        if (!showThumbnail) {
          noThumbPrev = 'no-thumb-prev';
        }
        let previewLabel = isAudio ? l[17828] : isVideo ? l[16275] : l[1899];
        let previewIcon = isAudio ? 'icon-play' : isVideo ? 'icon-video-call-filled' : 'icon-preview-reveal';
        if (isText) {
          previewLabel = l[16797];
          previewIcon = "icon-file-edit";
        }
        previewButton = REaCt().createElement("span", {
          key: "previewButton"
        }, REaCt().createElement(dropdowns.DropdownItem, {
          label: previewLabel,
          icon: `sprite-fm-mono ${previewIcon}`,
          disabled: mega.paywall,
          onClick: e => {
            mega.ui.mInfoPanel.hide();
            this.props.onPreviewStart(v, e);
          }
        }));
      }
      dropdown = contact.u === u_handle ? REaCt().createElement(buttons.$, {
        ref: ref => {
          this.buttonRef = ref;
        },
        className: "tiny-button",
        icon: "tiny-icon icons-sprite grey-dots"
      }, REaCt().createElement(dropdowns.Dropdown, {
        className: "white-context-menu attachments-dropdown",
        noArrow: true,
        positionMy: "left top",
        positionAt: "left bottom",
        horizOffset: -4,
        vertOffset: 3,
        onBeforeActiveChange: newState => {
          if (newState === true) {
            this.forceUpdate();
          }
        },
        dropdownItemGenerator: dd => {
          const linkButtons = [];
          const firstGroupOfButtons = [];
          let revokeButton = null;
          let downloadButton = null;
          let addToAlbumButton = null;
          if (message.isEditable && message.isEditable()) {
            revokeButton = REaCt().createElement(dropdowns.DropdownItem, {
              icon: "sprite-fm-mono icon-dialog-close",
              label: l[83],
              onClick: () => {
                chatRoom.megaChat.plugins.chatdIntegration.updateMessage(chatRoom, message.internalId || message.orderValue, "");
              }
            });
          }
          if (!M.d[v.h] && !NODE_DOESNT_EXISTS_ANYMORE[v.h]) {
            dbfetch.acquire(v.h).always(() => {
              if (!M.d[v.h]) {
                NODE_DOESNT_EXISTS_ANYMORE[v.h] = true;
                dd.doRerender();
              } else {
                dd.doRerender();
              }
            });
            return REaCt().createElement("span", {
              className: "loading"
            }, l[5533]);
          } else if (!NODE_DOESNT_EXISTS_ANYMORE[v.h]) {
            downloadButton = REaCt().createElement(dropdowns.DropdownItem, {
              icon: "sprite-fm-mono icon-download-small",
              label: l[1187],
              disabled: mega.paywall,
              onClick: () => this.props.onDownloadStart(v)
            });
            if (M.getNodeRoot(v.h) !== M.RubbishID) {
              this.props.onAddLinkButtons(v.h, linkButtons);
            }
            firstGroupOfButtons.push(REaCt().createElement(dropdowns.DropdownItem, {
              icon: "sprite-fm-mono icon-info",
              label: l[6859],
              key: "infoDialog",
              onClick: () => {
                mega.ui.mInfoPanel.show([v.ch]);
              }
            }));
            this.props.onAddFavouriteButtons(v.h, firstGroupOfButtons);
            linkButtons.push(REaCt().createElement(dropdowns.DropdownItem, {
              icon: "sprite-fm-mono icon-send-to-chat",
              label: l[17764],
              key: "sendToChat",
              disabled: mega.paywall,
              onClick: () => {
                $.selected = [v.h];
                openSendToChatDialog();
              }
            }));
            if (M.isGalleryNode(v)) {
              addToAlbumButton = REaCt().createElement(dropdowns.DropdownItem, {
                icon: "sprite-fm-mono rectangle-stack-plus-small-regular-outline",
                label: l.add_to_album,
                disabled: mega.paywall,
                onClick: () => mega.gallery.albums.addToAlbum([v.h])
              });
            }
          }
          if (!previewButton && firstGroupOfButtons.length === 0 && !downloadButton && !addToAlbumButton && linkButtons.length === 0 && !revokeButton) {
            return null;
          }
          if (previewButton && (firstGroupOfButtons.length > 0 || downloadButton || addToAlbumButton || linkButtons.length > 0 || revokeButton)) {
            previewButton = [previewButton, REaCt().createElement("hr", {
              key: "preview-sep"
            })];
          }
          return REaCt().createElement("div", null, previewButton, firstGroupOfButtons, firstGroupOfButtons && firstGroupOfButtons.length > 0 ? REaCt().createElement("hr", null) : "", addToAlbumButton, addToAlbumButton ? REaCt().createElement("hr", null) : "", downloadButton, linkButtons, revokeButton && downloadButton ? REaCt().createElement("hr", null) : "", revokeButton);
        }
      })) : REaCt().createElement(buttons.$, {
        ref: ref => {
          this.buttonRef = ref;
        },
        className: "tiny-button",
        icon: "tiny-icon icons-sprite grey-dots"
      }, REaCt().createElement(dropdowns.Dropdown, {
        className: "white-context-menu attachments-dropdown",
        noArrow: true,
        positionMy: "left top",
        positionAt: "left bottom",
        horizOffset: -4,
        vertOffset: 3
      }, previewButton, previewButton && REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-download-small",
        label: l[1187],
        disabled: mega.paywall,
        onClick: () => this.props.onDownloadStart(v)
      }), !is_chatlink && this._isUserRegistered() && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-cloud",
        label: l[1988],
        disabled: mega.paywall,
        onClick: () => this.props.onAddToCloudDrive(v, false)
      }), REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-send-to-chat",
        label: l[17764],
        disabled: mega.paywall,
        onClick: () => this.props.onAddToCloudDrive(v, true)
      }))));
      if (M.getNodeShare(v.h).down) {
        dropdown = null;
      }
      const attachmentClasses = "message shared-data";
      let preview = REaCt().createElement("div", {
        className: `data-block-view medium ${  noThumbPrev}`,
        onClick: ({
          target
        }) => {
          if (isPreviewable && !target.classList.contains('tiny-button')) {
            mega.ui.mInfoPanel.hide();
            this.props.onPreviewStart(v);
          }
        }
      }, dropdown, REaCt().createElement("div", {
        className: "data-block-bg"
      }, REaCt().createElement("div", {
        className: `item-type-icon-90 icon-${  icon  }-90`
      })));
      if (showThumbnail) {
        const src = v.src || window.noThumbURI || '';
        let thumbClass = v.src ? '' : " no-thumb";
        let thumbOverlay = null;
        if (isImage) {
          thumbClass += " image";
          thumbOverlay = REaCt().createElement("div", {
            className: "thumb-overlay",
            onClick: () => {
              mega.ui.mInfoPanel.hide();
              this.props.onPreviewStart(v);
            }
          });
        } else {
          thumbClass = `${thumbClass  } video ${  isPreviewable ? " previewable" : "non-previewable"}`;
          thumbOverlay = REaCt().createElement("div", {
            className: "thumb-overlay",
            onClick: () => {
              if (isPreviewable) {
                mega.ui.mInfoPanel.hide();
                this.props.onPreviewStart(v);
              }
            }
          }, isPreviewable && REaCt().createElement("div", {
            className: "thumb-overlay-play"
          }, REaCt().createElement("div", {
            className: "thumb-overlay-circle"
          }, REaCt().createElement("i", {
            className: "sprite-fm-mono icon-play"
          }))), REaCt().createElement("div", {
            className: "video-thumb-details"
          }, v.playtime && REaCt().createElement("i", {
            className: "sprite-fm-mono icon-play"
          }), REaCt().createElement("span", null, secondsToTimeShort(v.playtime || -1))));
        }
        preview = src ? REaCt().createElement("div", {
          id: v.ch,
          className: `shared-link thumb ${thumbClass}`
        }, thumbOverlay, dropdown, REaCt().createElement("img", {
          alt: "",
          className: `thumbnail-placeholder ${  v.h}`,
          src,
          key: `thumb-${  v.ch}`,
          onClick: () => isPreviewable && this.props.onPreviewStart(v)
        })) : preview;
      }
      files.push(REaCt().createElement("div", {
        key: `attachment-${v.ch}`,
        className: attachmentClasses
      }, REaCt().createElement("div", {
        className: "message shared-info",
        onClick: (_this$buttonRef = this.buttonRef) == null ? void 0 : _this$buttonRef.onClick
      }, REaCt().createElement("div", {
        className: "message data-title selectable-txt"
      }, l[17669], REaCt().createElement("span", {
        className: "file-name"
      }, v.name)), REaCt().createElement("div", {
        className: "message file-size"
      }, bytesToSize(v.s))), preview, REaCt().createElement("div", {
        className: "clear"
      })));
    }
    return REaCt().createElement("div", {
      className: "message shared-block"
    }, files);
  }
}
// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
;// ./js/chat/ui/messages/types/partials/audioPlayer.jsx


class AudioPlayer extends mixins.w9 {
  constructor(props) {
    super(props);
    this.domRef = REaCt().createRef();
    this.state = {
      currentTime: null,
      progressWidth: 0,
      isBeingPlayed: false,
      isPaused: false
    };
    this.handleOnTimeUpdate = this.handleOnTimeUpdate.bind(this);
    this.handleOnMouseDown = this.handleOnMouseDown.bind(this);
  }
  play() {
    const audio = this.audioEl;
    if (audio.paused) {
      const result = audio.play();
      if (result instanceof Promise) {
        result.catch(ex => {
          if (ex.name !== 'AbortError') {
            console.error(ex);
          }
        });
      }
      const audios = document.getElementsByClassName('audio-player__player');
      Array.prototype.filter.call(audios, audioElement => audioElement.id !== this.props.audioId).forEach(audioElement => {
        if (!audioElement.paused) {
          audioElement.pause();
        }
      });
      this.setState({
        isPaused: false
      });
    } else {
      audio.pause();
      this.setState({
        isPaused: true
      });
    }
  }
  handleOnTimeUpdate() {
    const {
      currentTime,
      duration
    } = this.audioEl;
    this.setState({
      currentTime: secondsToTimeShort(currentTime),
      progressWidth: currentTime / duration * 100
    });
  }
  handleOnMouseDown(event) {
    event.preventDefault();
    const {
      sliderPin,
      slider
    } = this;
    const shiftX = event.clientX - sliderPin.getBoundingClientRect().left;
    const onMouseMove = event => {
      let newLeft = event.clientX - shiftX - slider.getBoundingClientRect().left;
      if (newLeft < 0) {
        newLeft = 0;
      }
      const rightEdge = slider.offsetWidth - sliderPin.offsetWidth;
      if (newLeft > rightEdge) {
        newLeft = rightEdge;
      }
      sliderPin.style.left = `${newLeft}px`;
      const pinPosition = newLeft / slider.getBoundingClientRect().width;
      const newTime = Math.ceil(this.props.playtime * pinPosition);
      const newCurrentTime = secondsToTimeShort(newTime);
      this.audioEl.currentTime = newTime;
      this.setState({
        currentTime: newCurrentTime,
        progressWidth: pinPosition > 1 ? 100 : pinPosition * 100
      });
    };
    function onMouseUp() {
      document.removeEventListener('mouseup', onMouseUp);
      document.removeEventListener('mousemove', onMouseMove);
    }
    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);
    sliderPin.ondragstart = () => false;
  }
  render() {
    const {
      source,
      audioId,
      loading,
      playtime
    } = this.props;
    const {
      progressWidth,
      isBeingPlayed,
      isPaused,
      currentTime
    } = this.state;
    let playtimeStyles = null;
    if (isBeingPlayed) {
      playtimeStyles = {
        color: 'var(--secondary-red)'
      };
    }
    let btnClass = 'icon-pause';
    if (!isBeingPlayed || isPaused) {
      btnClass = 'icon-play';
    }
    let controls = REaCt().createElement("span", {
      onClick: () => {
        this.play();
        if (this.props.source === null) {
          this.props.getAudioFile();
        }
      }
    }, REaCt().createElement("i", {
      className: `sprite-fm-mono ${btnClass}`
    }));
    if (loading) {
      controls = REaCt().createElement("div", {
        className: "small-blue-spinner audio-player__spinner"
      });
    }
    return REaCt().createElement("div", {
      ref: this.domRef,
      className: "audio-player"
    }, controls, REaCt().createElement("div", {
      className: "slider",
      ref: slider => {
        this.slider = slider;
      }
    }, REaCt().createElement("div", {
      className: "slider__progress",
      style: {
        width: `${progressWidth}%`
      }
    }), REaCt().createElement("div", {
      className: "slider__progress__pin",
      style: {
        left: `${progressWidth}%`
      },
      ref: sliderPin => {
        this.sliderPin = sliderPin;
      },
      onMouseDown: this.handleOnMouseDown
    })), REaCt().createElement("span", {
      className: "audio-player__time",
      style: playtimeStyles
    }, currentTime || secondsToTimeShort(playtime)), REaCt().createElement("audio", {
      src: source,
      className: "audio-player__player",
      id: audioId,
      ref: audio => {
        this.audioEl = audio;
      },
      onPlaying: () => this.setState({
        isBeingPlayed: true
      }),
      onPause: () => this.setState({
        isPaused: true
      }),
      onEnded: () => this.setState({
        progressWidth: 0,
        isBeingPlayed: false,
        currentTime: 0
      }),
      onTimeUpdate: this.handleOnTimeUpdate
    }));
  }
}
;// ./js/chat/ui/messages/types/partials/audioContainer.jsx


class AudioContainer extends REaCt().Component {
  constructor(props) {
    super(props);
    this.state = {
      audioBlobUrl: null,
      loading: false
    };
    this.getAudioFile = this.getAudioFile.bind(this);
  }
  getAudioFile() {
    const {
      mime,
      h
    } = this.props;
    this.setState({
      loading: true
    });
    if (mime !== 'audio/mp4') {
      if (d) {
        console.warn('cannot play this file type (%s)', mime, h, [this]);
      }
      return false;
    }
    M.gfsfetch(h, 0, -1).then(({
      buffer
    }) => {
      this.setState(() => {
        return {
          audioBlobUrl: mObjectURL([buffer], 'audio/mp4'),
          loading: false
        };
      });
    }).catch(ex => {
      console.error(ex);
    });
    return true;
  }
  componentWillUnmount() {
    URL.revokeObjectURL(this.state.audioBlobUrl);
  }
  render() {
    const {
      audioBlobUrl,
      loading
    } = this.state;
    const {
      playtime,
      mime,
      audioId
    } = this.props;
    return REaCt().createElement("div", {
      className: "audio-container"
    }, REaCt().createElement(AudioPlayer, {
      source: audioBlobUrl,
      audioId,
      loading,
      mime,
      getAudioFile: this.getAudioFile,
      playtime
    }));
  }
}
AudioContainer.defaultProps = {
  h: null,
  mime: null
};
;// ./js/chat/ui/messages/types/voiceClip.jsx





class VoiceClip extends AbstractGenericMessage {
  _getActionButtons() {
    const {
      isBeingEdited,
      chatRoom,
      message,
      dialog,
      onDelete
    } = this.props;
    if (message.isEditable() && !isBeingEdited() && !chatRoom.isReadOnly() && !dialog) {
      return REaCt().createElement(buttons.$, {
        className: "tiny-button",
        icon: "tiny-icon icons-sprite grey-dots"
      }, REaCt().createElement(dropdowns.Dropdown, {
        className: "white-context-menu attachments-dropdown",
        noArrow: true,
        positionMy: "left bottom",
        positionAt: "right bottom",
        horizOffset: 4
      }, REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-dialog-close",
        label: l[1730],
        onClick: ev => onDelete(ev, message)
      })));
    }
    return null;
  }
  _getAudioContainer() {
    const {
      message
    } = this.props;
    const attachmentMeta = message.getAttachmentMeta();
    if (attachmentMeta && attachmentMeta.length) {
      return attachmentMeta.map(voiceClip => REaCt().createElement(AudioContainer, {
        key: voiceClip.h,
        h: voiceClip.h,
        mime: voiceClip.mime,
        playtime: voiceClip.playtime,
        audioId: `vm${message.messageId}`
      }));
    }
  }
  getContents() {
    return REaCt().createElement(REaCt().Fragment, null, this.props.message.getState() === Message.STATE.NOT_SENT ? null : this._getActionButtons(), this._getAudioContainer());
  }
}
;// ./js/chat/ui/messages/types/partials/metaRichpreview.jsx
const React = REQ_(594);
const ConversationMessageMixin = REQ_(446).M;
const MetaRichPreviewLoading = REQ_(707).a;
class MetaRichpreview extends ConversationMessageMixin {
  getBase64Url(b64incoming) {
    if (!b64incoming || !b64incoming.split) {
      return;
    }
    let exti = b64incoming.split(":");
    const b64i = exti[1];
    exti = exti[0];
    return `data:image/${  exti  };base64,${  b64i}`;
  }
  render() {
    const self = this;
    const {message} = this.props;
    const output = [];
    const metas = message.meta && message.meta.extra ? message.meta.extra : [];
    const failedToLoad = message.meta.isLoading && unixtime() - message.meta.isLoading > 300;
    const isLoading = !!message.meta.isLoading;
    if (failedToLoad) {
      return null;
    }
    for (let i = 0; i < metas.length; i++) {
      const meta = metas[i];
      if (!meta.d && !meta.t && !message.meta.isLoading) {
        continue;
      }
      const previewCss = {};
      if (meta.i) {
        previewCss.backgroundImage = `url(${  self.getBase64Url(meta.i)  })`;
        previewCss.backgroundRepeat = "no-repeat";
        previewCss.backgroundPosition = "center center";
      }
      var previewContainer;
      if (isLoading) {
        previewContainer = React.createElement(MetaRichPreviewLoading, {
          message,
          isLoading: message.meta.isLoading
        });
      } else {
        let domainName = meta.url;
        domainName = domainName.replace("https://", "").replace("http://", "").split("/")[0];
        previewContainer = React.createElement("div", {
          className: "message richpreview body"
        }, meta.i ? React.createElement("div", {
          className: "message richpreview img-wrapper"
        }, React.createElement("div", {
          className: "message richpreview preview",
          style: previewCss
        })) : undefined, React.createElement("div", {
          className: "message richpreview inner-wrapper"
        }, React.createElement("div", {
          className: "message richpreview data-title selectable-txt"
        }, React.createElement("span", {
          className: "message richpreview title"
        }, meta.t)), React.createElement("div", {
          className: "message richpreview desc"
        }, ellipsis(meta.d, 'end', 82)), React.createElement("div", {
          className: "message richpreview url-container"
        }, meta.ic ? React.createElement("span", {
          className: "message richpreview url-favicon"
        }, React.createElement("img", {
          src: self.getBase64Url(meta.ic),
          width: 16,
          height: 16,
          onError: e => {
            e.target.parentNode.removeChild(e.target);
          },
          alt: ""
        })) : "", React.createElement("span", {
          className: "message richpreview url"
        }, domainName))));
      }
      output.push(React.createElement("div", {
        key: meta.url,
        className: `message richpreview container ${  meta.i ? "have-preview" : "no-preview"  } ${  meta.d ? "have-description" : "no-description"  } ${  isLoading ? "is-loading" : "done-loading"}`,
        onClick: function (url) {
          if (!message.meta.isLoading) {
            window.open(url, "_blank", 'noopener,noreferrer');
          }
        }.bind(this, meta.url)
      }, previewContainer, React.createElement("div", {
        className: "clear"
      })));
    }
    return React.createElement("div", {
      className: "message richpreview previews-container"
    }, output);
  }
}

;// ./js/chat/ui/messages/types/partials/metaRichpreviewConfirmation.jsx
const metaRichpreviewConfirmation_React = REQ_(594);
const metaRichpreviewConfirmation_ConversationMessageMixin = REQ_(446).M;
class MetaRichprevConfirmation extends metaRichpreviewConfirmation_ConversationMessageMixin {
  doAllow() {
    const {message} = this.props;
    const {megaChat} = this.props.message.chatRoom;
    delete message.meta.requiresConfirmation;
    RichpreviewsFilter.confirmationDoConfirm();
    megaChat.plugins.richpreviewsFilter.processMessage({}, message);
    message.trackDataChange();
  }
  doNotNow() {
    const {message} = this.props;
    delete message.meta.requiresConfirmation;
    RichpreviewsFilter.confirmationDoNotNow();
    message.trackDataChange();
  }
  doNever() {
    const {message} = this.props;
    msgDialog('confirmation', l[870], l[18687], '', (e) => {
      if (e) {
        delete message.meta.requiresConfirmation;
        RichpreviewsFilter.confirmationDoNever();
        message.trackDataChange();
      }
    });
  }
  render() {
    const self = this;
    let notNowButton = null;
    let neverButton = null;
    if (RichpreviewsFilter.confirmationCount >= 2) {
      neverButton = metaRichpreviewConfirmation_React.createElement("button", {
        className: "mega-button right negative",
        onClick () {
          self.doNever();
        }
      }, metaRichpreviewConfirmation_React.createElement("span", null, l[1051]));
    }
    notNowButton = metaRichpreviewConfirmation_React.createElement("button", {
      className: "mega-button right",
      onClick () {
        self.doNotNow();
      }
    }, metaRichpreviewConfirmation_React.createElement("span", null, l[18682]));
    return metaRichpreviewConfirmation_React.createElement("div", {
      className: "message richpreview previews-container"
    }, metaRichpreviewConfirmation_React.createElement("div", {
      className: "message richpreview container confirmation"
    }, metaRichpreviewConfirmation_React.createElement("div", {
      className: "message richpreview body"
    }, metaRichpreviewConfirmation_React.createElement("div", {
      className: "message richpreview img-wrapper"
    }, metaRichpreviewConfirmation_React.createElement("div", {
      className: " message richpreview preview-confirmation sprite-fm-illustration img-chat-url-preview "
    })), metaRichpreviewConfirmation_React.createElement("div", {
      className: "message richpreview inner-wrapper"
    }, metaRichpreviewConfirmation_React.createElement("div", {
      className: "message richpreview data-title selectable-txt"
    }, metaRichpreviewConfirmation_React.createElement("span", {
      className: "message richpreview title"
    }, l[18679])), metaRichpreviewConfirmation_React.createElement("div", {
      className: "message richpreview desc"
    }, l[18680])), metaRichpreviewConfirmation_React.createElement("div", {
      className: "buttons-block"
    }, metaRichpreviewConfirmation_React.createElement("button", {
      className: "mega-button right positive",
      onClick: () => {
        self.doAllow();
      }
    }, metaRichpreviewConfirmation_React.createElement("span", null, l[18681])), notNowButton, neverButton)), metaRichpreviewConfirmation_React.createElement("div", {
      className: "clear"
    })));
  }
}

;// ./js/chat/ui/messages/types/partials/geoLocation.jsx

function GeoLocation(props) {
  const {
    latitude,
    lng
  } = props;
  const handleOnclick = (lat, lng) => {
    const openGmaps = () => {
      window.open(`https://www.google.com/maps/search/?api=1&query=${lat},${lng}`, '_blank', 'noopener,noreferrer');
    };
    if (GeoLocationLinks.gmapsConfirmation === -1 || GeoLocationLinks.gmapsConfirmation === false) {
      msgDialog('confirmation', 'geolocation-link', l[20788], l.confirm_ext_link, answer => {
        if (answer) {
          GeoLocationLinks.confirmationDoConfirm();
          closeDialog();
          openGmaps();
        } else {
          GeoLocationLinks.confirmationDoNever();
        }
      });
    } else if (GeoLocationLinks.gmapsConfirmation) {
      openGmaps();
    }
  };
  return REaCt().createElement("div", {
    className: "geolocation-container"
  }, REaCt().createElement("div", {
    className: "geolocation",
    onClick: () => handleOnclick(latitude, lng)
  }, REaCt().createElement("div", {
    className: "geolocation__details"
  }, REaCt().createElement("div", {
    className: "geolocation__icon"
  }, REaCt().createElement("i", {
    className: "sprite-fm-mono icon-location"
  })), REaCt().createElement("ul", {
    className: "geolocation__data-list"
  }, REaCt().createElement("li", null, REaCt().createElement("span", {
    className: "geolocation__title"
  }, l[20789])), REaCt().createElement("li", null, REaCt().createElement("p", null, REaCt().createElement("span", {
    className: "geolocation__coordinates-icon"
  }), REaCt().createElement("span", {
    className: "geolocation__coordinates"
  }, "https://maps.google.com")))))));
}
const geoLocation = GeoLocation;
// EXTERNAL MODULE: ./js/chat/ui/messages/types/partials/metaRichPreviewLoading.jsx
const metaRichPreviewLoading = REQ_(707);
;// ./js/chat/ui/messages/types/partials/metaRichpreviewMegaLinks.jsx





class MetaRichpreviewMegaLinks extends mixin.M {
  render() {
    const {message} = this.props;
    const {chatRoom} = this.props.message;
    let previewContainer;
    const output = [];
    const megaLinks = message.megaLinks ? message.megaLinks : [];
    for (let i = 0; i < megaLinks.length; i++) {
      const megaLinkInfo = megaLinks[i];
      if (megaLinkInfo.failed) {
        continue;
      }
      if (megaLinkInfo.hadLoaded() === false) {
        if (megaLinkInfo.startedLoading() === false) {
          megaLinkInfo.getInfo().then(() => {
            const {
              megaLinks
            } = this.props.message;
            const contactLinkHandles = megaLinks.filter(link => link.is_contactlink).map(link => link.info.h);
            if (contactLinkHandles.length) {
              this.addContactListenerIfMissing(contactLinkHandles);
            }
          }).catch(reportError).finally(() => {
            message.trackDataChange();
            onIdle(() => {
              this.safeForceUpdate();
            });
          });
        }
        previewContainer = REaCt().createElement(metaRichPreviewLoading.a, {
          message,
          isLoading: megaLinkInfo.hadLoaded()
        });
      } else if (megaLinkInfo.is_contactlink) {
        const fakeContact = M.u[megaLinkInfo.info.h] ? M.u[megaLinkInfo.info.h] : {
          'u': megaLinkInfo.info.h,
          'm': megaLinkInfo.info.e,
          'firstName': megaLinkInfo.info.fn,
          'lastName': megaLinkInfo.info.ln,
          'name': `${megaLinkInfo.info.fn  } ${  megaLinkInfo.info.ln}`
        };
        if (!M.u[fakeContact.u]) {
          M.u.set(fakeContact.u, new MegaDataObject(MEGA_USER_STRUCT, {
            'u': fakeContact.u,
            'name': `${fakeContact.firstName  } ${  fakeContact.lastName}`,
            'm': fakeContact.m ? fakeContact.m : "",
            'c': undefined
          }));
        }
        const contact = M.u[megaLinkInfo.info.h];
        previewContainer = REaCt().createElement("div", {
          key: megaLinkInfo.info.h,
          className: "message shared-block contact-link"
        }, REaCt().createElement("div", {
          className: "message shared-info"
        }, REaCt().createElement("div", {
          className: "message data-title selectable-txt"
        }, contact.name), REaCt().createElement(ui_contacts.ContactVerified, {
          className: "right-align",
          contact
        }), REaCt().createElement("div", {
          className: "user-card-email selectable-txt"
        }, contact.m)), REaCt().createElement("div", {
          className: "message shared-data"
        }, REaCt().createElement("div", {
          className: "data-block-view semi-big"
        }, REaCt().createElement(ui_contacts.ContactPresence, {
          className: "small",
          contact
        }), REaCt().createElement(ui_contacts.Avatar, {
          className: "avatar-wrapper medium-avatar",
          contact,
          chatRoom
        })), REaCt().createElement("div", {
          className: "clear"
        })));
      } else {
        var desc;
        const is_icon = megaLinkInfo.is_dir ? true : !(megaLinkInfo.havePreview() && megaLinkInfo.info.preview_url);
        if (megaLinkInfo.is_chatlink) {
          desc = l[8876].replace('%1', megaLinkInfo.info.ncm);
        } else if (!megaLinkInfo.is_dir) {
          desc = bytesToSize(megaLinkInfo.info.size);
        } else {
          const totalNumberOfFiles = megaLinkInfo.info.s[1];
          const numOfVersionedFiles = megaLinkInfo.info.s[4];
          const folderCount = megaLinkInfo.info.s[2];
          const totalFileSize = megaLinkInfo.info.size;
          const versionsSize = megaLinkInfo.info.s[3];
          desc = REaCt().createElement("span", null, fm_contains(totalNumberOfFiles - numOfVersionedFiles, folderCount - 1), REaCt().createElement("br", null), bytesToSize(totalFileSize - versionsSize));
        }
        previewContainer = REaCt().createElement("div", {
          className: `message richpreview body ${  is_icon ? "have-icon" : "no-icon"  } ${  megaLinkInfo.is_chatlink ? "is-chat" : ""}`
        }, megaLinkInfo.havePreview() && megaLinkInfo.info.preview_url ? REaCt().createElement("div", {
          className: "message richpreview img-wrapper"
        }, REaCt().createElement("div", {
          className: "message richpreview preview",
          style: {
            "backgroundImage": `url(${  megaLinkInfo.info.preview_url  })`
          }
        })) : REaCt().createElement("div", {
          className: "message richpreview img-wrapper"
        }, megaLinkInfo.is_chatlink ? REaCt().createElement("i", {
          className: "huge-icon conversations"
        }) : REaCt().createElement("div", {
          className: `message richpreview icon item-type-icon-90 icon-${  megaLinkInfo.is_dir ? "folder" : fileIcon(megaLinkInfo.info)  }-90`
        })), REaCt().createElement("div", {
          className: "message richpreview inner-wrapper"
        }, REaCt().createElement("div", {
          className: "message richpreview data-title selectable-txt"
        }, REaCt().createElement("span", {
          className: "message richpreview title"
        }, REaCt().createElement(utils.zT, null, megaLinkInfo.info.name || megaLinkInfo.info.topic || ""))), REaCt().createElement("div", {
          className: "message richpreview desc"
        }, desc), REaCt().createElement("div", {
          className: "message richpreview url-container"
        }, REaCt().createElement("span", {
          className: "message richpreview url-favicon"
        }, REaCt().createElement("img", {
          src: `https://mega.${mega.tld}/favicon.ico?v=3&c=1`,
          width: 16,
          height: 16,
          onError: e => {
            if (e && e.target && e.target.parentNode) {
              e.target.parentNode.removeChild(e.target);
            }
          },
          alt: ""
        })), REaCt().createElement("span", {
          className: "message richpreview url"
        }, ellipsis(megaLinkInfo.getLink(), 'end', 40)))));
      }
      output.push(REaCt().createElement("div", {
        key: `${megaLinkInfo.node_key  }_${  output.length}`,
        className: `message richpreview container ${  megaLinkInfo.havePreview() ? "have-preview" : "no-preview"  } ${  megaLinkInfo.d ? "have-description" : "no-description"  } ${  !megaLinkInfo.hadLoaded() ? "is-loading" : "done-loading"}`,
        onClick: function (url, megaLinkInfo) {
          if (megaLinkInfo.hadLoaded()) {
            if (window.sfuClient && megaLinkInfo.is_chatlink) {
              const {
                chatRoom: callRoom
              } = megaChat.activeCall;
              const peers = callRoom ? callRoom.getParticipantsExceptMe(callRoom.getCallParticipants()).map(h => M.getNameByHandle(h)) : [];
              const body = peers.length ? mega.utils.trans.listToString(peers, l.cancel_with_to_join) : l.cancel_to_join;
              return msgDialog('confirmation', undefined, l.call_in_progress, body, e => e && window.open(url, '_blank', 'noopener,noreferrer'));
            }
            window.open(url, '_blank', 'noopener,noreferrer');
          }
        }.bind(this, megaLinkInfo.getLink(), megaLinkInfo)
      }, previewContainer, REaCt().createElement("div", {
        className: "clear"
      })));
    }
    return REaCt().createElement("div", {
      className: "message richpreview previews-container"
    }, output);
  }
}

// EXTERNAL MODULE: ./js/chat/ui/typingArea.jsx + 1 modules
const typingArea = REQ_(795);
// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
const perfectScrollbar = REQ_(486);
;// ./js/chat/ui/messages/types/text.jsx












class Text extends AbstractGenericMessage {
  constructor(props) {
    super(props);
    this.state = {
      editText: ''
    };
  }
  isRichPreview(message) {
    return message.metaType === Message.MESSAGE_META_TYPE.RICH_PREVIEW;
  }
  isGeoLocation(message) {
    return message.metaType === Message.MESSAGE_META_TYPE.GEOLOCATION;
  }
  getClassNames() {
    const {
      message,
      isBeingEdited,
      grouped
    } = this.props;
    const REQUIRES_CONFIRMATION = this.isRichPreview(message) && message.meta.requiresConfirmation && !isBeingEdited() && (message.source === Message.SOURCE.SENT || message.confirmed === true);
    return `
            ${REQUIRES_CONFIRMATION ? 'preview-requires-confirmation-container' : ''}
            ${grouped ? 'grouped' : ''}
        `;
  }
  renderMessageIndicators() {
    const {
      message,
      spinnerElement,
      isBeingEdited,
      onRetry,
      onCancelRetry
    } = this.props;
    if (!message || spinnerElement || isBeingEdited()) {
      return null;
    }
    const state = message.getState == null ? void 0 : message.getState();
    if (![Message.STATE.NOT_SENT, Message.STATE.NOT_SENT_EXPIRED].includes(state)) {
      return null;
    }
    const props = {
      'data-simpletipposition': 'top',
      'data-simpletipoffset': 8
    };
    return message.requiresManualRetry ? REaCt().createElement("div", {
      className: "not-sent-indicator clickable"
    }, REaCt().createElement("span", (0,esm_extends.A)({
      className: "simpletip"
    }, props, {
      "data-simpletip": l[8883],
      onClick: ev => onRetry(ev, message)
    }), REaCt().createElement("i", {
      className: "small-icon refresh-circle"
    })), REaCt().createElement("span", (0,esm_extends.A)({
      className: "simpletip"
    }, props, {
      "data-simpletip": l[8884],
      onClick: ev => onCancelRetry(ev, message)
    }), REaCt().createElement("i", {
      className: "sprite-fm-mono icon-dialog-close"
    }))) : REaCt().createElement("div", (0,esm_extends.A)({
      className: "not-sent-indicator simpletip"
    }, props, {
      "data-simpletip": l[8882]
    }), REaCt().createElement("i", {
      className: "small-icon yellow-triangle"
    }));
  }
  getMessageActionButtons() {
    const {
      chatRoom,
      message,
      isBeingEdited
    } = this.props;
    if (isBeingEdited()) {
      return [];
    }
    let extraPreButtons = [];
    let messageActionButtons = null;
    const IS_GEOLOCATION = this.isGeoLocation(message);
    if (!message.deleted && this.isRichPreview(message)) {
      if (!message.meta.requiresConfirmation) {
        if (message.isEditable()) {
          if (message.meta.isLoading) {
            extraPreButtons = [...extraPreButtons, REaCt().createElement(dropdowns.DropdownItem, {
              icon: "sprite-fm-mono icon-eye-hidden",
              key: "stop-link-preview",
              label: l[18684],
              className: "",
              onClick: e => {
                e.stopPropagation();
                e.preventDefault();
                chatRoom.megaChat.plugins.richpreviewsFilter.cancelLoading(chatRoom, message);
              }
            })];
          } else {
            extraPreButtons = [...extraPreButtons, REaCt().createElement(dropdowns.DropdownItem, {
              key: "remove-link-preview",
              icon: "sprite-fm-mono icon-eye-hidden",
              label: l[18684],
              className: "",
              onClick: e => {
                e.stopPropagation();
                e.preventDefault();
                chatRoom.megaChat.plugins.richpreviewsFilter.revertToText(chatRoom, message);
              }
            })];
          }
        }
      } else if (!isBeingEdited() && !(message.source === Message.SOURCE.SENT || message.confirmed === true)) {
        extraPreButtons = [...extraPreButtons, REaCt().createElement(dropdowns.DropdownItem, {
          key: "insert-link-preview",
          icon: "icons-sprite bold-eye",
          label: l[18683],
          className: "",
          onClick: e => {
            e.stopPropagation();
            e.preventDefault();
            chatRoom.megaChat.plugins.richpreviewsFilter.insertPreview(message);
          }
        })];
      }
    }
    if (!message.deleted && message.isEditable() && !isBeingEdited() && !chatRoom.isReadOnly() && !message.requiresManualRetry) {
      const editButton = !IS_GEOLOCATION && REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-rename",
        label: l[1342],
        onClick: () => this.props.onEditToggle(true)
      });
      messageActionButtons = REaCt().createElement(buttons.$, {
        key: "delete-msg",
        className: "tiny-button",
        icon: "sprite-fm-mono icon-options"
      }, REaCt().createElement(dropdowns.Dropdown, {
        className: "white-context-menu attachments-dropdown",
        noArrow: true,
        positionMy: "left bottom",
        positionAt: "right bottom",
        horizOffset: 4
      }, extraPreButtons, editButton, editButton ? REaCt().createElement("hr", null) : null, REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono icon-dialog-close",
        label: l[1730],
        onClick: e => this.props.onDelete(e, message)
      })));
    }
    let parentButtons;
    if (super.getMessageActionButtons) {
      parentButtons = super.getMessageActionButtons();
    }
    const returnedButtons = [];
    if (messageActionButtons) {
      returnedButtons.push(messageActionButtons);
    }
    if (message.messageHtml && message.messageHtml.includes('<pre class="rtf-multi">') && message.messageHtml.includes('</pre>')) {
      returnedButtons.push(REaCt().createElement(buttons.$, {
        key: "copy-msg",
        className: "tiny-button simpletip copy-txt-block",
        icon: "sprite-fm-mono icon-copy",
        attrs: {
          'data-simpletip': l.copy_txt_block_tip,
          'data-simpletipoffset': '3',
          'data-simpletipposition': 'top'
        },
        onClick: () => {
          copyToClipboard(message.textContents.replace(/```/g, ''), l.copy_txt_block_toast);
        }
      }));
    }
    if (parentButtons) {
      returnedButtons.push(parentButtons);
    }
    return returnedButtons;
  }
  getContents() {
    const {
      message,
      chatRoom,
      onUpdate,
      isBeingEdited,
      spinnerElement
    } = this.props;
    let textMessage = message.messageHtml;
    const IS_GEOLOCATION = this.isGeoLocation(message);
    const {
      lng,
      la: latitude
    } = IS_GEOLOCATION && message.meta.extra[0];
    if (message.textContents === '' && !message.dialogType) {
      message.deleted = true;
    }
    let subMessageComponent = [];
    if (!message.deleted) {
      if (this.isRichPreview(message)) {
        if (!message.meta.requiresConfirmation) {
          subMessageComponent = [...subMessageComponent, REaCt().createElement(MetaRichpreview, {
            key: "richprev",
            message,
            chatRoom
          })];
        } else if (!isBeingEdited()) {
          if (message.source === Message.SOURCE.SENT || message.confirmed === true) {
            subMessageComponent = [...subMessageComponent, REaCt().createElement(MetaRichprevConfirmation, {
              key: "confirm",
              message,
              chatRoom
            })];
          }
        }
      }
      if (message.megaLinks) {
        subMessageComponent = [...subMessageComponent, REaCt().createElement(MetaRichpreviewMegaLinks, {
          key: "richprevml",
          message,
          chatRoom
        })];
      }
    }
    let messageDisplayBlock;
    if (isBeingEdited() === true) {
      let msgContents = message.textContents;
      msgContents = megaChat.plugins.emoticonsFilter.fromUtfToShort(msgContents);
      messageDisplayBlock = REaCt().createElement(typingArea.T, {
        iconClass: "small-icon writing-pen textarea-icon",
        initialText: msgContents,
        text: this.state.editText || msgContents,
        chatRoom,
        showButtons: true,
        editing: true,
        className: "edit-typing-area",
        onUpdate: () => onUpdate ? onUpdate : null,
        onConfirm: messageContents => {
          this.props.onEditToggle(false);
          if (this.props.onEditDone) {
            Soon(() => {
              const tmpMessageObj = {
                textContents: messageContents
              };
              megaChat.plugins.emoticonsFilter.processOutgoingMessage({}, tmpMessageObj);
              this.props.onEditDone(tmpMessageObj.textContents);
              if (this.isMounted()) {
                this.forceUpdate();
              }
            });
          }
          return true;
        },
        onResized: this.props.onResized ? this.props.onResized : false,
        onValueChanged: val => {
          this.setState({
            editText: val
          });
        }
      });
    } else {
      if (message.updated > 0 && !message.metaType) {
        textMessage = `${textMessage} <em class="edited simpletip"
                    data-simpletip="${toLocaleTime(this.getTimestamp(true))}"
                    data-simpletipposition="top" data-simpletipoffset="4"> ${l[8887]} </em>`;
      }
      if (this.props.initTextScrolling) {
        messageDisplayBlock = REaCt().createElement(perfectScrollbar.O, {
          className: "message text-block scroll"
        }, REaCt().createElement("div", {
          className: "message text-scroll"
        }, REaCt().createElement(utils.P9, null, textMessage)));
      } else {
        messageDisplayBlock = REaCt().createElement("div", {
          className: "message text-block"
        }, REaCt().createElement(utils.P9, null, textMessage));
      }
    }
    return REaCt().createElement(REaCt().Fragment, null, this.renderMessageIndicators(), IS_GEOLOCATION ? null : messageDisplayBlock, subMessageComponent, spinnerElement, IS_GEOLOCATION && REaCt().createElement(geoLocation, {
      latitude,
      lng
    }));
  }
}
// EXTERNAL MODULE: ./js/chat/ui/gifPanel/gifPanel.jsx + 3 modules
const gifPanel = REQ_(691);
;// ./js/chat/ui/messages/types/giphy.jsx





class Giphy extends AbstractGenericMessage {
  constructor(...args) {
    super(...args);
    this.gifRef = REaCt().createRef();
    this.viewStateListener = `viewstateChange.giphy--${this.getUniqueId()}`;
    this.state = {
      src: undefined
    };
  }
  componentDidMount() {
    super.componentDidMount();
    megaChat.rebind(this.viewStateListener, ({
      data
    }) => {
      const gifRef = this.gifRef && this.gifRef.current;
      if (gifRef) {
        const {
          state
        } = data;
        if (state === 'active' && gifRef.paused || state !== 'active' && !gifRef.paused) {
          this.toggle();
        }
      }
    });
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    megaChat.off(this.viewStateListener);
  }
  onVisibilityChange(isIntersecting) {
    this.setState({
      src: isIntersecting ? gifPanel.nC.convert(this.props.message.meta.src) : undefined
    }, () => {
      let _this$gifRef;
      (_this$gifRef = this.gifRef) == null || (_this$gifRef = _this$gifRef.current) == null || _this$gifRef[isIntersecting ? 'load' : 'pause']();
      this.safeForceUpdate();
    });
  }
  toggle() {
    const video = this.gifRef.current;
    Promise.resolve(video[video.paused ? 'play' : 'pause']()).catch(nop);
  }
  getMessageActionButtons() {
    const {
      onDelete,
      message
    } = this.props;
    const $$BUTTONS = [message.isEditable() && REaCt().createElement(buttons.$, {
      key: "delete-GIPHY-button",
      className: "tiny-button",
      icon: "sprite-fm-mono icon-options"
    }, REaCt().createElement(dropdowns.Dropdown, {
      className: "white-context-menu attachments-dropdown",
      noArrow: true,
      positionMy: "left bottom",
      positionAt: "right bottom",
      horizOffset: 4
    }, REaCt().createElement(dropdowns.DropdownItem, {
      icon: "sprite-fm-mono icon-dialog-close",
      label: l[1730],
      onClick: e => onDelete(e, message)
    }))), super.getMessageActionButtons && super.getMessageActionButtons()];
    return $$BUTTONS.filter(button => button);
  }
  getContents() {
    const {
      message,
      hideActionButtons
    } = this.props;
    const {
      s,
      w,
      h,
      src
    } = message.meta;
    const autoPlay = parseInt(s, 10) < 4e6;
    return REaCt().createElement("video", {
      className: "giphy-block",
      ref: this.gifRef,
      title: message.textContents,
      autoPlay,
      loop: true,
      muted: true,
      controls: false,
      width: w,
      height: h,
      style: {
        cursor: autoPlay ? 'default' : 'pointer',
        height: `${h}px`
      },
      onClick: () => !autoPlay && this.toggle(),
      src: hideActionButtons ? gifPanel.nC.convert(src) : this.state.src
    });
  }
}
;// ./js/chat/ui/messages/generic.jsx










class GenericConversationMessage extends mixin.M {
  constructor(props) {
    super(props);
    this.containerRef = REaCt().createRef();
    this.state = {
      editing: this.props.editing
    };
    this.pid = `__geom_${  String(Math.random()).substr(2)}`;
  }
  isBeingEdited() {
    return this.state.editing === true || this.props.editing === true;
  }
  componentDidUpdate(oldProps, oldState) {
    const isBeingEdited = this.isBeingEdited();
    const isMounted = this.isMounted();
    if (isBeingEdited && isMounted) {
      let _this$containerRef;
      const $generic = $((_this$containerRef = this.containerRef) == null ? void 0 : _this$containerRef.current);
      const $textarea = $('textarea', $generic);
      if ($textarea.length > 0 && !$textarea.is(":focus")) {
        $textarea.trigger("focus");
        moveCursortoToEnd($textarea[0]);
      }
      if (!oldState.editing && this.props.onEditStarted) {
        this.props.onEditStarted($generic);
        moveCursortoToEnd($textarea);
      }
    }
    if (isMounted && !isBeingEdited && oldState.editing === true && this.props.onUpdate) {
      this.props.onUpdate();
    }
  }
  componentDidMount() {
    let _this$containerRef2;
    super.componentDidMount();
    const $node = $((_this$containerRef2 = this.containerRef) == null ? void 0 : _this$containerRef2.current);
    if (this.isBeingEdited() && this.isMounted()) {
      const $textarea = $('textarea', $node);
      if ($textarea.length > 0 && !$textarea.is(':focus')) {
        $textarea.trigger('focus');
        moveCursortoToEnd($textarea[0]);
      }
    }
  }
  haveMoreContactListeners() {
    if (!this.props.message || !this.props.message.meta) {
      return false;
    }
    if (this.props.message.meta && this.props.message.meta.participants) {
      return this.props.message.meta.participants;
    }
    return false;
  }
  doDelete(e, msg) {
    e.preventDefault(e);
    e.stopPropagation(e);
    if (msg.getState() === Message.STATE.NOT_SENT_EXPIRED) {
      this.doCancelRetry(e, msg);
    } else {
      this.props.onDeleteClicked(this.props.message);
    }
  }
  doCancelRetry(e, msg) {
    e.preventDefault(e);
    e.stopPropagation(e);
    const {chatRoom} = this.props.message;
    const {messageId} = msg;
    chatRoom.messagesBuff.messages.removeByKey(messageId);
    chatRoom.megaChat.plugins.chatdIntegration.discardMessage(chatRoom, messageId);
  }
  doRetry(e, msg) {
    e.preventDefault(e);
    e.stopPropagation(e);
    const {chatRoom} = this.props.message;
    this.doCancelRetry(e, msg);
    chatRoom._sendMessageToTransport(msg).then(internalId => {
      msg.internalId = internalId;
      this.safeForceUpdate();
    });
  }
  _favourite(h) {
    if (M.isInvalidUserStatus()) {
      return;
    }
    const newFavState = Number(!M.isFavourite(h));
    M.favourite([h], newFavState);
  }
  _addFavouriteButtons(h, arr) {
    const self = this;
    if (M.getNodeRights(h) > 1) {
      const isFav = M.isFavourite(h);
      arr.push(REaCt().createElement(dropdowns.DropdownItem, {
        icon: `
                        sprite-fm-mono
                        context
                        ${isFav ? 'icon-favourite-removed' : 'icon-favourite'}
                    `,
        label: isFav ? l[5872] : l[5871],
        isFav,
        key: "fav",
        disabled: mega.paywall,
        onClick: e => {
          self._favourite(h);
          e.stopPropagation();
          e.preventDefault();
          return false;
        }
      }));
      return isFav;
    }
    return false;
  }
  _isNodeHavingALink(h) {
    return M.getNodeShare(h) !== false;
  }
  _addLinkButtons(h, arr) {
    const self = this;
    const haveLink = self._isNodeHavingALink(h) === true;
    const getManageLinkText = haveLink ? l[6909] : l[5622];
    arr.push(REaCt().createElement(dropdowns.DropdownItem, {
      icon: "sprite-fm-mono icon-link",
      key: "getLinkButton",
      label: getManageLinkText,
      disabled: mega.paywall,
      onClick: self._getLink.bind(self, h)
    }));
    if (haveLink) {
      arr.push(REaCt().createElement(dropdowns.DropdownItem, {
        icon: "sprite-fm-mono context icon-link-remove",
        key: "removeLinkButton",
        label: l[6821],
        disabled: mega.paywall,
        onClick: self._removeLink.bind(self, h)
      }));
      return true;
    }
    return false;
  }
  _startDownload(v) {
    M.addDownload([v]);
  }
  _addToCloudDrive(v, openSendToChat) {
    $.selected = [v.h];
    $.chatAttachmentShare = true;
    if ($.dialog === 'onboardingDialog') {
      closeDialog();
    }
    if (openSendToChat) {
      openSendToChatDialog();
      return;
    }
    openSaveToDialog(v, (node, target) => {
      target = target || M.RootID;
      M.injectNodes(node, target, res => {
        if (!Array.isArray(res) || !res.length) {
          if (d) {
            console.warn('Unable to inject nodes... no longer existing?', res);
          }
        } else {
          mega.ui.toast.show(mega.icu.format(l.toast_import_file, res.length).replace('%s', M.getNameByHandle(target)), 4, l[16797], {
            actionButtonCallback() {
              M.openFolder(target).then(() => {
                if (window.selectionManager) {
                  let reset = false;
                  for (let i = res.length; i--;) {
                    const n = M.getNodeByHandle(res[i]);
                    if (n.p === target) {
                      if (reset) {
                        selectionManager.add_to_selection(n.h);
                      } else {
                        selectionManager.resetTo(n.h);
                        reset = true;
                      }
                    }
                  }
                }
              }).catch(dump);
            }
          });
        }
      });
    }, false);
  }
  _getLink(h, e) {
    if (u_type === 0) {
      ephemeralDialog(l[1005]);
    } else {
      $.selected = [h];
      mega.Share.initCopyrightsDialog([h]);
    }
    if (e) {
      e.preventDefault();
      e.stopPropagation();
    }
  }
  _removeLink(h, e) {
    if (u_type === 0) {
      ephemeralDialog(l[1005]);
    } else {
      const exportLink = new mega.Share.ExportLink({
        'updateUI': true,
        'nodesToProcess': [h]
      });
      exportLink.removeExportLink();
    }
    if (e) {
      e.preventDefault();
      e.stopPropagation();
    }
  }
  _startPreview(v, e) {
    if ($(e && e.target).is('.tiny-button')) {
      return;
    }
    assert(M.chat, 'Not in chat.');
    if (e) {
      e.preventDefault();
      e.stopPropagation();
    }
    M.viewMediaFile(v);
  }
  render() {
    const {
      message,
      chatRoom
    } = this.props;
    const {megaChat} = this.props.message.chatRoom;
    const {textContents} = message;
    let additionalClasses = "";
    let spinnerElement = null;
    let messageIsNowBeingSent = false;
    if (this.props.className) {
      additionalClasses += this.props.className;
    }
    if (message instanceof Message) {
      if (!message.wasRendered || !message.messageHtml) {
        message.messageHtml = htmlentities(textContents).replace(/\n/gi, "<br/>").replace(/\t/g, '    ');
        message.processedBy = {};
        const evtObj = {
          message,
          room: chatRoom
        };
        megaChat.trigger('onPreBeforeRenderMessage', evtObj);
        const event = new MegaDataEvent('onBeforeRenderMessage');
        megaChat.trigger(event, evtObj);
        megaChat.trigger('onPostBeforeRenderMessage', evtObj);
        if (event.isPropagationStopped()) {
          this.logger.warn(`Event propagation stopped receiving (rendering) of message: ${message}`);
          return false;
        }
        message.wasRendered = 1;
      }
      const state = message.getState();
      const stateText = message.getStateText(state);
      if (state === Message.STATE.NOT_SENT) {
        messageIsNowBeingSent = unixtime() - message.delay < 5;
        if (messageIsNowBeingSent) {
          additionalClasses += ' sending';
          spinnerElement = REaCt().createElement("div", {
            className: "small-blue-spinner"
          });
          if (!message.sending) {
            message.sending = true;
            delay(this.pid + message.messageId, () => {
              if (chatRoom.messagesBuff.messages[message.messageId] && message.sending === true) {
                chatRoom.messagesBuff.trackDataChange();
                if (this.isMounted()) {
                  this.forceUpdate();
                }
              }
            }, (5 - (unixtime() - message.delay)) * 1000);
          }
        } else {
          additionalClasses += ' not-sent';
          if (message.sending === true) {
            message.sending = false;
            message.trigger('onChange', [message, 'sending', true, false]);
          }
          if (message.requiresManualRetry) {
            additionalClasses += ' retrying requires-manual-retry';
          } else {
            additionalClasses += ' retrying';
          }
        }
      } else {
        additionalClasses += ` ${  stateText}`;
      }
    }
    const MESSAGE = {
      TYPE: {
        ATTACHMENT: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.ATTACHMENT,
        CONTACT: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.CONTACT,
        REVOKE_ATTACHMENT: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.REVOKE_ATTACHMENT,
        VOICE_CLIP: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.VOICE_CLIP,
        GIPHY: message.metaType && message.metaType === Message.MESSAGE_META_TYPE.GIPHY,
        TEXT: textContents[0] !== Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT,
        INLINE: !(message instanceof Message) && message.type && !!message.type.length,
        REVOKED: message.revoked
      },
      props: {
        ...this.props,
        additionalClasses
      },
      isBeingEdited: () => this.isBeingEdited(),
      onDelete: (e, message) => this.doDelete(e, message)
    };
    const $$CONTAINER = children => REaCt().createElement("div", {
      ref: this.containerRef
    }, children);
    switch (true) {
      case MESSAGE.TYPE.REVOKED || MESSAGE.TYPE.REVOKE_ATTACHMENT:
        return null;
      case MESSAGE.TYPE.ATTACHMENT:
        return $$CONTAINER(REaCt().createElement(Attachment, (0,esm_extends.A)({}, MESSAGE.props, {
          onPreviewStart: (v, e) => this._startPreview(v, e),
          onDownloadStart: v => this._startDownload(v),
          onAddLinkButtons: (h, arr) => this._addLinkButtons(h, arr),
          onAddToCloudDrive: (v, openSendToChat) => this._addToCloudDrive(v, openSendToChat),
          onAddFavouriteButtons: (h, arr) => this._addFavouriteButtons(h, arr)
        })));
      case MESSAGE.TYPE.CONTACT:
        return $$CONTAINER(REaCt().createElement(Contact, (0,esm_extends.A)({}, MESSAGE.props, {
          onDelete: MESSAGE.onDelete
        })));
      case MESSAGE.TYPE.VOICE_CLIP:
        return $$CONTAINER(REaCt().createElement(VoiceClip, (0,esm_extends.A)({}, MESSAGE.props, {
          isBeingEdited: MESSAGE.isBeingEdited,
          onDelete: MESSAGE.onDelete
        })));
      case MESSAGE.TYPE.INLINE:
        return $$CONTAINER(REaCt().createElement(Local, MESSAGE.props));
      case MESSAGE.TYPE.GIPHY:
        return $$CONTAINER(REaCt().createElement(Giphy, (0,esm_extends.A)({}, MESSAGE.props, {
          onDelete: MESSAGE.onDelete
        })));
      case MESSAGE.TYPE.TEXT:
        return $$CONTAINER(REaCt().createElement(Text, (0,esm_extends.A)({}, MESSAGE.props, {
          onEditToggle: editing => this.setState({
            editing
          }),
          onDelete: MESSAGE.onDelete,
          onRetry: (e, message) => this.doRetry(e, message),
          onCancelRetry: (e, message) => this.doCancelRetry(e, message),
          isBeingEdited: MESSAGE.isBeingEdited,
          spinnerElement
        })));
      default:
        return null;
    }
  }
}

},

911:
(_, EXP_, REQ_) => {

"use strict";
REQ_.r(EXP_);
REQ_.d(EXP_, {
Dropdown: () => Dropdown,
DropdownContactsSelector: () => DropdownContactsSelector,
DropdownItem: () => DropdownItem
});
const _utils_jsx0__ = REQ_(314);
const _chat_mixins1__ = REQ_(137);
const _chat_ui_contacts_jsx2__ = REQ_(251);
const React = REQ_(594);



class Dropdown extends _chat_mixins1__.w9 {
  constructor(props) {
    super(props);
    this.domRef = React.createRef();
    this.onActiveChange = this.onActiveChange.bind(this);
    this.onResized = this.onResized.bind(this);
  }
  UNSAFE_componentWillUpdate(nextProps) {
    if (this.props.active != nextProps.active) {
      this.onActiveChange(nextProps.active);
    }
  }
  specShouldComponentUpdate(nextProps, nextState) {
    if (this.props.active != nextProps.active) {
      if (this.props.onBeforeActiveChange) {
        this.props.onBeforeActiveChange(nextProps.active);
      }
      return true;
    } else if (this.props.focused != nextProps.focused) {
      return true;
    } else if (this.state && this.state.active != nextState.active) {
      return true;
    }
    return undefined;
  }
  onActiveChange(newVal) {
    if (this.props.onActiveChange) {
      this.props.onActiveChange(newVal);
    }
  }
  reposElementUsing(element, obj, info) {
    let $element;
    if (this.popupElement) {
      $element = $(this.popupElement);
    } else {
      return;
    }
    const self = this;
    let vertOffset = 0;
    let horizOffset = 0;
    if (!self.props.noArrow) {
      const $arrow = $('.dropdown-white-arrow', $element);
      let arrowHeight;
      if (self.props.arrowHeight) {
        arrowHeight = self.props.arrowHeight;
        if (info.vertical === "top") {
          arrowHeight = 0;
        } else {
          arrowHeight *= -1;
        }
      } else {
        arrowHeight = $arrow.outerHeight();
      }
      if (info.vertical === "top") {
        $(element).removeClass("down-arrow").addClass("up-arrow");
      } else {
        $(element).removeClass("up-arrow").addClass("down-arrow");
      }
      vertOffset += info.vertical === "top" ? arrowHeight : 0;
    }
    if (self.props.vertOffset) {
      vertOffset += self.props.vertOffset * (info.vertical === "top" ? 1 : -1);
    }
    if (self.props.horizOffset) {
      horizOffset += self.props.horizOffset;
    }
    $(element).css({
      left: `${obj.left + 0 + horizOffset  }px`,
      top: `${obj.top + vertOffset  }px`
    });
    if (this.props.positionLeft) {
      $(element).css({
        left: this.props.positionLeft
      });
    }
  }
  onResized() {
    const self = this;
    if (this.props.active === true && this.popupElement) {
      const $element = $(this.popupElement);
      const $positionToElement = $('.button.active-dropdown:visible');
      if ($positionToElement.length === 0) {
        return;
      }
      let $container = $positionToElement.closest('.messages.scroll-area');
      if ($container.length === 0) {
        $container = $(document.body);
      }
      $element.css('margin-left', '');
      $element.position({
        of: $positionToElement,
        my: self.props.positionMy ? self.props.positionMy : "center top",
        at: self.props.positionAt ? self.props.positionAt : "center bottom",
        collision: this.props.collision || 'flipfit',
        within: self.props.wrapper || $container,
        using (obj, info) {
          self.reposElementUsing(this, obj, info);
        }
      });
    }
  }
  componentDidMount() {
    super.componentDidMount();
    chatGlobalEventManager.addEventListener('resize', `drpdwn${  this.getUniqueId()}`, this.onResized.bind(this));
    this.onResized();
    const self = this;
    $(document.body).rebind(`closeAllDropdownsExcept.drpdwn${  this.getUniqueId()}`, (e, target) => {
      if (self.props.active && target !== self) {
        if (self.props && self.props.closeDropdown) {
          self.props.closeDropdown();
        }
      }
    });
  }
  componentDidUpdate() {
    this.onResized();
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    $(document.body).unbind(`closeAllDropdownsExcept.drpdwn${  this.getUniqueId()}`);
    if (this.props.active) {
      this.onActiveChange(false);
    }
    chatGlobalEventManager.removeEventListener('resize', `drpdwn${  this.getUniqueId()}`);
  }
  doRerender() {
    const self = this;
    setTimeout(() => {
      self.safeForceUpdate();
    }, 100);
    setTimeout(() => {
      self.onResized();
    }, 200);
  }
  renderChildren() {
    const self = this;
    return React.Children.map(this.props.children, (child) => {
      if (child) {
        let activeVal = self.props.active || self.state.active;
        activeVal = String(activeVal);
        return React.cloneElement(child, {
          active: activeVal
        });
      }
      return null;
    });
  }
  render() {
    if (this.props.active !== true) {
      return null;
    }
    const self = this;
    let child = null;
    if (this.props.children) {
      child = React.createElement("div", {
        ref: this.domRef
      }, self.renderChildren());
    } else if (this.props.dropdownItemGenerator) {
      child = this.props.dropdownItemGenerator(this);
    }
    if (!child && !this.props.forceShowWhenEmpty) {
      if (this.props.active !== false) {
        queueMicrotask(() => {
          self.onActiveChange(false);
        });
      }
      return null;
    }
    return React.createElement(_utils_jsx0__.Ay.RenderTo, {
      element: document.body,
      className: `
                    dropdown
                    body
                    ${this.props.noArrow ? '' : 'dropdown-arrow up-arrow'}
                    ${this.props.className || ''}
                `,
      style: this.popupElement && {
        zIndex: 123,
        position: 'absolute',
        width: this.props.styles ? this.props.styles.width : undefined
      },
      popupDidMount: popupElement => {
        this.popupElement = popupElement;
        this.onResized();
      },
      popupWillUnmount: () => {
        delete this.popupElement;
      }
    }, React.createElement("div", {
      ref: this.domRef,
      onClick: () => {
        $(document.body).trigger('closeAllDropdownsExcept', this);
      }
    }, this.props.noArrow ? null : React.createElement("i", {
      className: "dropdown-white-arrow"
    }), child));
  }
}
Dropdown.defaultProps = {
  'requiresUpdateOnResize': true
};
class DropdownContactsSelector extends _chat_mixins1__.w9 {
  constructor(props) {
    super(props);
    this.state = {
      'selected': this.props.selected ? this.props.selected : []
    };
    this.onSelectClicked = this.onSelectClicked.bind(this);
    this.onSelected = this.onSelected.bind(this);
  }
  specShouldComponentUpdate(nextProps, nextState) {
    if (this.props.active != nextProps.active) {
      return true;
    } else if (this.props.focused != nextProps.focused) {
      return true;
    } else if (this.state && this.state.active != nextState.active) {
      return true;
    } else if (this.state && JSON.stringify(this.state.selected) != JSON.stringify(nextState.selected)) {
      return true;
    } else {
      return undefined;
    }
  }
  onSelected(nodes) {
    this.setState({
      'selected': nodes
    });
    if (this.props.onSelected) {
      this.props.onSelected(nodes);
    }
    this.forceUpdate();
  }
  onSelectClicked() {
    this.props.onSelectClicked();
  }
  render() {
    return React.createElement(Dropdown, {
      className: `
                    popup contacts-search
                    ${this.props.className}
                    tooltip-blur
                `,
      active: this.props.active,
      closeDropdown: this.props.closeDropdown,
      ref: ref => {
        this.dropdownRef = ref;
      },
      positionMy: this.props.positionMy,
      positionAt: this.props.positionAt,
      arrowHeight: this.props.arrowHeight,
      horizOffset: this.props.horizOffset,
      vertOffset: this.props.vertOffset,
      noArrow: true
    }, React.createElement(_chat_ui_contacts_jsx2__.ContactPickerWidget, {
      onClose: this.props.closeDropdown,
      onEventuallyUpdated: () => {
        let _this$dropdownRef;
        return (_this$dropdownRef = this.dropdownRef) == null ? void 0 : _this$dropdownRef.doRerender();
      },
      active: this.props.active,
      className: "popup contacts-search tooltip-blur small-footer",
      contacts: M.u,
      selectFooter: this.props.selectFooter,
      megaChat: this.props.megaChat,
      exclude: this.props.exclude,
      allowEmpty: this.props.allowEmpty,
      multiple: this.props.multiple,
      topButtons: this.props.topButtons,
      showAddContact: this.props.showAddContact,
      onAddContact: () => eventlog(500237),
      onSelected: () => eventlog(500238),
      onSelectDone: this.props.onSelectDone,
      multipleSelectedButtonLabel: this.props.multipleSelectedButtonLabel,
      singleSelectedButtonLabel: this.props.singleSelectedButtonLabel,
      nothingSelectedButtonLabel: this.props.nothingSelectedButtonLabel
    }));
  }
}
DropdownContactsSelector.defaultProps = {
  requiresUpdateOnResize: true
};
class DropdownItem extends _chat_mixins1__.w9 {
  constructor(props) {
    super(props);
    this.domRef = React.createRef();
    this.state = {
      'isClicked': false
    };
    this.onClick = this.onClick.bind(this);
    this.onMouseOver = this.onMouseOver.bind(this);
  }
  renderChildren() {
    const self = this;
    return React.Children.map(this.props.children, (child) => {
      const props = {
        active: self.state.isClicked,
        closeDropdown () {
          self.setState({
            'isClicked': false
          });
        }
      };
      return React.cloneElement(child, props);
    });
  }
  onClick(ev) {
    const {
      children,
      persistent,
      onClick
    } = this.props;
    if (children) {
      ev.stopPropagation();
      ev.preventDefault();
      this.setState({
        isClicked: !this.state.isClicked
      });
    }
    if (!persistent) {
      $(document).trigger('closeDropdowns');
    }
    return onClick && onClick(ev);
  }
  onMouseOver(e) {
    if (this.props.submenu) {
      const $contextItem = $(e.target).closest(".contains-submenu");
      const $subMenu = $contextItem.next('.submenu');
      const contextTopPos = $contextItem.position().top;
      let contextleftPos = 0;
      $contextItem.addClass("opened");
      $subMenu.addClass("active");
      contextleftPos = $contextItem.offset().left + $contextItem.outerWidth() + $subMenu.outerWidth() + 10;
      if (contextleftPos > $(document.body).width()) {
        $subMenu.addClass("left-position");
      }
      $subMenu.css({
        "top": contextTopPos
      });
    } else if (!$(e.target).parent('.submenu').length) {
      const $dropdown = $(e.target).closest(".dropdown.body");
      $dropdown.find(".contains-submenu").removeClass("opened");
      $dropdown.find(".submenu").removeClass("active");
    }
  }
  render() {
    const {
      className,
      disabled,
      label,
      icon,
      submenu
    } = this.props;
    return React.createElement("div", {
      ref: this.domRef,
      className: `
                    dropdown-item
                    ${className ? className : ''}
                    ${submenu ? 'contains-submenu' : ''}
                    ${disabled ? 'disabled' : ''}
                `,
      onClick: disabled ? undefined : ev => this.onClick(ev),
      onMouseOver: this.onMouseOver
    }, icon && React.createElement("i", {
      className: icon
    }), label && React.createElement("span", null, label), submenu ? React.createElement("i", {
      className: "sprite-fm-mono icon-arrow-right submenu-icon"
    }) : '', React.createElement("div", null, this.renderChildren()));
  }
}
DropdownItem.defaultProps = {
  requiresUpdateOnResize: true
};

},

959:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
A: () => __WEBPACK_DEFAULT_EXPORT__
});
const react0__ = REQ_(594);
const react0 = REQ_.n(react0__);

class Group extends react0().Component {
  constructor(props) {
    super(props);
    this.containerRef = react0().createRef();
    this.state = {
      expanded: false
    };
    this.doToggle = this.doToggle.bind(this);
  }
  toggleEvents() {
    return this.state.expanded ? $(document).rebind(`mousedown.${Group.NAMESPACE}`, ev => !this.containerRef.current.contains(ev.target) && this.doToggle()).rebind(`keydown.${Group.NAMESPACE}`, ({
      keyCode
    }) => keyCode && keyCode === 27 && this.doToggle()) : $(document).unbind(`.${Group.NAMESPACE}`);
  }
  doToggle() {
    this.setState(state => ({
      expanded: !state.expanded
    }), () => this.toggleEvents());
  }
  render() {
    const {
      active,
      warn,
      onHold,
      screenSharing,
      children
    } = this.props;
    if (children && children.length) {
      return react0().createElement("div", {
        ref: this.containerRef,
        className: Group.BASE_CLASS
      }, react0().createElement("div", {
        className: `
                            ${Group.BASE_CLASS}-menu
                            ${this.state.expanded ? 'expanded' : ''}
                        `,
        onClick: this.doToggle
      }, children.map(item => {
        return item && react0().createElement("div", {
          key: item.key,
          className: `${Group.BASE_CLASS}-item`
        }, item);
      })), react0().createElement("button", {
        className: "mega-button theme-light-forced round large",
        onClick: this.doToggle
      }, active && react0().createElement("div", {
        className: "info-indicator active"
      }), warn && react0().createElement("div", {
        className: "info-indicator warn simpletip",
        "data-simpletip": l.screen_share_crop_tip,
        "data-simpletipposition": "top",
        "data-simpletipoffset": "5",
        "data-simpletip-class": "theme-dark-forced"
      }, react0().createElement("i", {
        className: "sprite-fm-mono icon-exclamation-filled"
      })), react0().createElement("i", {
        className: `
                                sprite-fm-mono
                                ${screenSharing ? 'icon-end-screenshare' : ''}
                                ${!onHold && !screenSharing && 'icon-options'}
                            `
      })));
    }
    return null;
  }
}
Group.NAMESPACE = 'buttonGroup';
Group.BASE_CLASS = 'button-group';
class Button extends react0().Component {
  constructor(...args) {
    super(...args);
    this.buttonRef = react0().createRef();
  }
  componentDidUpdate() {
    if (this.props.simpletip) {
      $(this.buttonRef.current).trigger('simpletipUpdated');
    }
  }
  componentDidMount() {
    if (this.props.didMount) {
      this.props.didMount(this);
    }
  }
  render() {
    const {
      children,
      className,
      style,
      simpletip,
      icon,
      onClick
    } = this.props;
    return react0().createElement("button", {
      ref: this.buttonRef,
      className: `
                    ${className ? className : ''}
                    ${simpletip ? 'simpletip' : ''}
                `,
      style,
      "data-simpletip": simpletip == null ? void 0 : simpletip.label,
      "data-simpletipposition": simpletip == null ? void 0 : simpletip.position,
      "data-simpletipoffset": simpletip == null ? void 0 : simpletip.offset,
      "data-simpletip-class": simpletip == null ? void 0 : simpletip.className,
      onClick
    }, icon && react0().createElement("i", {
      className: `sprite-fm-mono ${icon}`
    }), children);
  }
}
Button.Group = Group;
const __WEBPACK_DEFAULT_EXPORT__ = Button;

},

972:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
C: () => withHostsObserver
});
const _extends0__ = REQ_(168);
const react1__ = REQ_(594);
const react1 = REQ_.n(react1__);
const _mixins_js2__ = REQ_(137);
const _ui_modalDialogs_jsx3__ = REQ_(318);
const _contacts_jsx4__ = REQ_(251);
const _ui_buttons_jsx5__ = REQ_(994);






const withHostsObserver = Component => {
  return class extends _mixins_js2__.w9 {
    constructor(...args) {
      super(...args);
      this.state = {
        dialog: false,
        selected: []
      };
      this.hasHost = participants => participants.some(handle => this.props.chatRoom.members[handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR);
      this.toggleDialog = () => {
        this.setState(state => ({
          dialog: !state.dialog,
          selected: []
        }), () => this.safeForceUpdate());
      };
      this.renderDialog = () => {
        let _this$props$participa;
        const {
          selected
        } = this.state;
        return react1().createElement(_ui_modalDialogs_jsx3__.A.ModalDialog, (0,_extends0__.A)({}, this.state, {
          className: "assign-host contact-picker-widget",
          dialogName: "assign-host-dialog",
          dialogType: "tool",
          onClose: () => this.setState({
            dialog: false
          }, () => this.safeForceUpdate())
        }), react1().createElement("header", null, react1().createElement("h2", null, l.assign_host_title)), react1().createElement("div", {
          className: "content-block"
        }, react1().createElement(_contacts_jsx4__.ContactPickerWidget, {
          className: "popup contacts-search small-footer",
          contacts: (_this$props$participa = this.props.participants) == null ? void 0 : _this$props$participa.filter(h => h !== u_handle),
          multiple: true,
          hideSearch: true,
          disableFrequents: true,
          participantsList: true,
          disableDoubleClick: true,
          emailTooltips: true,
          nothingSelectedButtonLabel: l.add_hosts_placeholder,
          onClose: () => this.setState({
            dialog: false
          }),
          onSelected: selected => this.setState({
            selected
          }, () => this.safeForceUpdate())
        })), react1().createElement("footer", null, react1().createElement("div", {
          className: "footer-container"
        }, react1().createElement(_ui_buttons_jsx5__.$, {
          label: l.msg_dlg_cancel,
          className: "mega-button",
          onClick: this.toggleDialog
        }), react1().createElement(_ui_buttons_jsx5__.$, {
          label: l.assign_and_leave,
          className: `
                                        mega-button
                                        positive
                                        ${selected.length ? '' : 'disabled'}
                                    `,
          onClick: () => selected.length && this.assignAndLeave()
        }))));
      };
      this.assignAndLeave = () => {
        const {
          chatRoom,
          onLeave
        } = this.props;
        const {
          selected
        } = this.state;
        for (let i = selected.length; i--;) {
          chatRoom.trigger('alterUserPrivilege', [selected[i], ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR]);
        }
        this.toggleDialog();
        onLeave == null || onLeave();
        $(document).trigger('closeDropdowns');
      };
      this.confirmLeave = ({
        title,
        body,
        cta,
        altCta
      }) => {
        msgDialog(`confirmationa:!^${cta}!${altCta || l.msg_dlg_cancel}`, null, title, body, cb => {
          if (cb) {
            this.toggleDialog();
          } else if (cb === false) {
            let _this$props$onConfirm, _this$props;
            (_this$props$onConfirm = (_this$props = this.props).onConfirmDenied) == null || _this$props$onConfirm.call(_this$props);
          }
        }, 1);
      };
    }
    render() {
      return react1().createElement(react1().Fragment, null, react1().createElement(Component, (0,_extends0__.A)({}, this.props, {
        confirmLeave: this.confirmLeave,
        hasHost: this.hasHost
      })), this.state.dialog && this.renderDialog());
    }
  };
};

},

984:
(_, EXP_, REQ_) => {

"use strict";

// EXPORTS
REQ_.d(EXP_, {
  B: () => GenericNodePropsComponent
});

// EXTERNAL MODULE: ./js/chat/mixins.js
const mixins = REQ_(137);
;// ./js/ui/jsx/fm/nodes/nodeProperties.jsx
class NodeProperties {
  static get(node, changeListener) {
    assert(node.h, 'missing handle for node');
    if (NodeProperties._globalCleanupTimer) {
      NodeProperties._globalCleanupTimer.abort();
    }
    (NodeProperties._globalCleanupTimer = tSleep(120)).then(() => {
      NodeProperties.cleanup(0);
    });
    let nodeProps;
    if (!NodeProperties._cache.has(node.h)) {
      nodeProps = new NodeProperties(node, changeListener);
      NodeProperties._cache.set(node.h, nodeProps);
    }
    return nodeProps || NodeProperties._cache.get(node.h);
  }
  unuse(changeListener) {
    const {node} = this;
    if (!node) {
      if (d) {
        console.warn("This should not happen.");
      }
      return;
    }
    this.changeListeners.delete(changeListener);
    let usages = NodeProperties._usages.get(this);
    if (usages) {
      NodeProperties._usages.set(this, --usages);
      if (usages === 0 && NodeProperties._cache.size > NodeProperties.MAX_CACHE_SIZE) {
        delay('nodePropCleanup', NodeProperties.cleanup, 1000);
      }
    }
  }
  static cleanup(maxCacheSize) {
    maxCacheSize = typeof maxCacheSize === "undefined" ? NodeProperties.MAX_CACHE_SIZE : maxCacheSize;
    const len = NodeProperties._cache.size;
    let removed = 0;
    for (const entry of NodeProperties._cache) {
      const id = entry[0];
      const node = entry[1];
      const usage = NodeProperties._usages.get(node);
      if (usage === 0) {
        NodeProperties._usages.delete(node);
        node._cleanup();
        NodeProperties._cache.delete(id);
        removed++;
        if (len - removed < maxCacheSize) {
          return;
        }
      }
    }
  }
  constructor(node, changeListener) {
    this.node = node;
    this.changeListeners = new Set();
    if (changeListener) {
      this.changeListeners.add(changeListener);
    }
    const _onChange = () => {
      this.initProps();
      for (const listener of this.changeListeners) {
        listener();
      }
    };
    if (this.node.addChangeListener) {
      this._listener = this.node.addChangeListener(_onChange);
    } else {
      this._mbListener = mBroadcaster.addListener(`nodeUpdated:${  node.h}`, _onChange);
    }
    this.initProps();
  }
  use(changeListener) {
    if (changeListener) {
      this.changeListeners.add(changeListener);
    }
    NodeProperties._usages.set(this, (NodeProperties._usages.get(this) | 0) + 1);
  }
  _cleanup() {
    if (this._listener) {
      this.node.removeChangeListener(this._listener);
    }
    if (this._mbListener) {
      mBroadcaster.removeListener(this._mbListener);
    }
    oDestroy(this);
  }
  initProps() {
    const {node} = this;
    lazy(this, 'title', () => {
      if (missingkeys[node.h]) {
        return node.t ? l[8686] : l[8687];
      }
      return M.getNameByHandle(node.h);
    });
    lazy(this, 'classNames', () => {
      const classNames = [];
      if (node.su) {
        classNames.push('inbound-share');
      }
      if (node.t) {
        classNames.push('folder');
      } else {
        classNames.push('file');
      }
      const share = this.shareData;
      if (missingkeys[node.h] || share.down) {
        if (share.down) {
          classNames.push('taken-down');
        }
        if (missingkeys[node.h]) {
          classNames.push('undecryptable');
        }
      }
      if (share) {
        classNames.push('linked');
      }
      if (node.lbl && !folderlink) {
        const colourLabel = M.getLabelClassFromId(node.lbl);
        classNames.push('colour-label');
        classNames.push(colourLabel);
      }
      return classNames;
    });
    lazy(this, 'icon', () => {
      return fileIcon(node);
    });
    lazy(this, 'isFolder', () => {
      return !!node.t;
    });
    lazy(this, 'shareData', () => {
      return M.getNodeShare(node);
    });
    lazy(this, 'isTakendown', () => {
      return this.shareData && !!this.shareData.down;
    });
    lazy(this, 'fav', () => {
      return !!node.fav;
    });
    lazy(this, 'size', () => {
      return bytesToSize(node.tb || node.s);
    });
    lazy(this, 'timestamp', () => {
      return time2date(node.ts);
    });
    lazy(this, 'root', () => {
      return M.getNodeRoot(node.h);
    });
    lazy(this, 'incomingShareData', () => {
      const result = {};
      if (node.r === 1) {
        result.accessLabel = l[56];
        result.accessIcon = 'icon-permissions-write';
      } else if (node.r === 2) {
        result.accessLabel = l[57];
        result.accessIcon = 'icon-star';
      } else {
        result.accessLabel = l[55];
        result.accessIcon = 'icon-read-only';
      }
      return result;
    });
    lazy(this, 'timestamp', () => {
      return time2date(node.ts);
    });
    lazy(this, 'onlineStatus', () => {
      return M.onlineStatusClass(node.presence ? node.presence : "unavailable");
    });
  }
}
NodeProperties._cache = new Map();
NodeProperties._usages = new WeakMap();
NodeProperties._globalCleanupTimer = void 0;
NodeProperties.MAX_CACHE_SIZE = 100;
if (d) {
  window.NodeProperties = NodeProperties;
}
;// ./js/ui/jsx/fm/nodes/genericNodePropsComponent.jsx


class GenericNodePropsComponent extends mixins.w9 {
  constructor(props) {
    super(props);
    if (this.props.node.h) {
      this.nodeProps = NodeProperties.get(this.props.node);
      this.changeListener = this.changeListener.bind(this);
    }
  }
  changeListener() {
    if (this.isMounted()) {
      this.safeForceUpdate();
    }
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (nextProps.highlighted !== this.props.highlighted) {
      this.safeForceUpdate();
    }
  }
  UNSAFE_componentWillMount() {
    let _this$nodeProps;
    if (super.UNSAFE_componentWillMount) {
      super.UNSAFE_componentWillMount();
    }
    (_this$nodeProps = this.nodeProps) == null || _this$nodeProps.use(this.changeListener);
  }
  componentWillUnmount() {
    let _this$nodeProps2;
    super.componentWillUnmount();
    (_this$nodeProps2 = this.nodeProps) == null || _this$nodeProps2.unuse(this.changeListener);
  }
}

},

994:
(_, EXP_, REQ_) => {

"use strict";
REQ_.d(EXP_, {
$: () => Button
});
const _extends0__ = REQ_(168);
const react1__ = REQ_(594);
const react1 = REQ_.n(react1__);
const _chat_mixins_js2__ = REQ_(137);



const BLURRABLE_CLASSES = '.conversationsApp, .join-meeting, .main-blur-block';
class Button extends _chat_mixins_js2__.w9 {
  constructor(props) {
    super(props);
    this.domRef = react1().createRef();
    this.buttonClass = `.button`;
    this.state = {
      focused: false,
      hovered: false,
      iconHovered: ''
    };
    this.onBlur = e => {
      let _this$domRef;
      if (!this.isMounted()) {
        return;
      }
      if (!e || !$(e.target).closest(this.buttonClass).is((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current)) {
        this.setState({
          focused: false
        }, () => {
          this.unbindEvents();
          this.safeForceUpdate();
        });
      }
    };
    this.onClick = e => {
      let _this$domRef2;
      if (this.props.disabled === true) {
        e.preventDefault();
        e.stopPropagation();
        return;
      }
      if ($(e.target).closest('.popup').closest(this.buttonClass).is((_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current) && this.state.focused === true) {
        e.preventDefault();
        e.stopPropagation();
        return;
      }
      if ($(e.target).is('input, textarea, select')) {
        return;
      }
      if (this.state.focused === false) {
        if (this.props.onClick) {
          this.props.onClick(this, e);
        } else if (react1().Children.count(this.props.children) > 0) {
          this.setState({
            focused: true
          }, () => this.safeForceUpdate());
        }
      } else if (this.state.focused === true) {
        this.setState({
          focused: false
        });
        this.unbindEvents();
      }
    };
    this.state.iconHovered = this.props.iconHovered || '';
  }
  UNSAFE_componentWillUpdate(nextProps, nextState) {
    if (nextProps.disabled === true && nextState.focused === true) {
      nextState.focused = false;
    }
    if (this.state.focused !== nextState.focused && nextState.focused === true) {
      this.bindEvents();
      if (this._pageChangeListener) {
        mBroadcaster.removeListener(this._pageChangeListener);
      }
      this._pageChangeListener = mBroadcaster.addListener('pagechange', () => {
        if (this.state.focused === true) {
          this.onBlur();
        }
      });
    }
  }
  componentWillUnmount() {
    super.componentWillUnmount();
    this.unbindEvents();
  }
  renderChildren() {
    return this.props.children && react1().Children.map(this.props.children, child => child && (typeof child.type === 'string' || child.type === undefined ? child : react1().cloneElement(child, {
      active: this.state.focused,
      closeDropdown: () => this.setState({
        focused: false
      }, () => this.unbindEvents()),
      onActiveChange: active => {
        let _this$domRef3;
        const $element = $(((_this$domRef3 = this.domRef) == null ? void 0 : _this$domRef3.current) || this.domNode);
        const $scrollables = $element.parents('.ps');
        if ($scrollables.length > 0) {
          $scrollables.map((k, element) => Ps[active ? 'disable' : 'enable'](element));
        }
        child.props.onActiveChange == null || child.props.onActiveChange(active);
        return this[active ? 'bindEvents' : 'unbindEvents']();
      }
    })));
  }
  bindEvents() {
    $(BLURRABLE_CLASSES).rebind(`mousedown.button--${this.getUniqueId()}`, this.onBlur);
    $(document).rebind(`keyup.button--${this.getUniqueId()}`, ev => this.state.focused === true && ev.keyCode === 27 && this.onBlur());
    $(document).rebind(`closeDropdowns.${this.getUniqueId()}`, this.onBlur);
  }
  unbindEvents() {
    $(BLURRABLE_CLASSES).unbind(`mousedown.button--${this.getUniqueId()}`);
    $(document).off(`keyup.button--${this.getUniqueId()}`);
    $(document).off(`closeDropdowns.${this.getUniqueId()}`);
    mBroadcaster.removeListener(this._pageChangeListener);
  }
  render() {
    const {
      className,
      disabled,
      style,
      icon,
      iconHovered,
      label,
      attrs,
      toggle,
      secondLabel,
      secondLabelClass
    } = this.props;
    const isMegaButton = className && className.indexOf('mega-button') > -1;
    const TagName = isMegaButton ? 'button' : 'div';
    return react1().createElement(TagName, (0,_extends0__.A)({
      ref: this.domRef,
      className: `
                    button
                    ${className || ''}
                    ${disabled ? 'disabled' : ''}
                    ${this.state.focused ? 'active active-dropdown' : ''}
                `,
      style,
      onClick: this.onClick,
      onMouseEnter: () => iconHovered && this.setState({
        hovered: true
      }),
      onMouseLeave: () => iconHovered && this.setState({
        hovered: false
      })
    }, attrs), icon && !isMegaButton && react1().createElement("div", null, react1().createElement("i", {
      className: this.state.hovered ? this.state.iconHovered : icon
    })), icon && isMegaButton && react1().createElement("div", null, react1().createElement("i", {
      className: this.state.hovered ? this.state.iconHovered : icon
    })), label && react1().createElement("span", null, label), secondLabel && react1().createElement("span", {
      className: secondLabelClass ? secondLabelClass : ''
    }, secondLabel), toggle && react1().createElement("div", {
      className: `
                            mega-switch
                            ${toggle.className ? toggle.className : ''}
                            ${toggle.enabled ? 'toggle-on' : ''}
                        `,
      role: "switch",
      "aria-checked": !!toggle.enabled,
      onClick: ev => {
        ev.stopPropagation();
        if (this.props.toggle.onClick) {
          this.props.toggle.onClick();
        }
      }
    }, react1().createElement("div", {
      className: `mega-feature-switch sprite-fm-mono-after
                                ${toggle.enabled ? 'icon-check-after' : 'icon-minimise-after'}`
    })), this.renderChildren());
  }
}

}

	};

	// The module cache
	const __webpack_module_cache__ =Object.create(null);

	// The require function
	function REQ_(moduleId) {
		// Check if module is in cache
		const cachedModule = __webpack_module_cache__[moduleId];
		if (cachedModule !== undefined) {
			return cachedModule.exports;
		}
		// Create a new module (and put it into the cache)
		const module = __webpack_module_cache__[moduleId] = {
			// no module.id needed
			// no module.loaded needed
			exports:Object.create(null)
		};

		// Execute the module function
		__webpack_modules__[moduleId](module, module.exports, REQ_);

		// Return the exports of the module
		return module.exports;
	}



	(() => {
		// getDefaultExport function for compatibility with non-harmony modules
		REQ_.n = (module) => {
			const getter = module && module.__esModule ?
				() => module.default :
				() => module;
			REQ_.d(getter, { a: getter });
			return getter;
		};
	})();


	(() => {
		// define getter functions for harmony exports
		REQ_.d = (exports, definition) => {
			for(const key in definition) {
				if(REQ_.o(definition, key) && !REQ_.o(exports, key)) {
					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
				}
			}
		};
	})();


	(() => {
		REQ_.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
	})();


	(() => {
		// define __esModule on exports
		REQ_.r = (exports) => {
			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
			}
			Object.defineProperty(exports, '__esModule', { value: true });
		};
	})();



	// startup
	// Load entry module and return exports
	REQ_(326);
	// This entry module is referenced by other modules so it can't be inlined
	const EXP_ = REQ_(732);

})()
;
