<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/* eslint import/no-unresolved: [2, { ignore: ['electron'] }] */
/* eslint-disable import/no-extraneous-dependencies */
require('source-map-support').install();

const {
  BrowserWindow,
  Menu,
  Tray,
  app,
  clipboard,
  dialog,
  globalShortcut,
  ipcMain,
  nativeImage,
  nativeTheme,
} = require('electron');
const isDev = require('electron-is-dev');
const settings = require('electron-settings');

settings.configure({
  fileName: 'Settings', // backward compatible with electron-settings@3
});

const path = require('path');
const url = require('url');
const { menubar } = require('menubar');
const windowStateKeeper = require('electron-window-state');

const { getPreference, setPreference } = require('./libs/preferences');

// Activate the Sentry Electron SDK as early as possible in every process.
if (!isDev && getPreference('sentry')) {
  // eslint-disable-next-line global-require
  require('./libs/sentry');
}

const { createMenu, showMenu } = require('./libs/menu');
const loadListeners = require('./listeners');
const { initLocales, getLocale } = require('./libs/locales');
const sendToAllWindows = require('./libs/send-to-all-windows');
const setContextMenu = require('./libs/set-context-menu');
const isMacOs11 = require('./libs/is-mac-os-11');

// we only need updater for AppImage
if (process.platform === 'linux' && process.env.SNAP == null) {
  // eslint-disable-next-line global-require
  require('./libs/updater');
}

// see https://github.com/electron/electron/issues/18397
app.allowRendererProcessReuse = true;

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mb;
let mainWindow;

// app.requestSingleInstanceLock doesnt work for signed mas builds (Mac App Store)
// see https://github.com/electron/electron/issues/15958
const gotTheLock = process.mas || app.requestSingleInstanceLock();

app.on('second-instance', () => {
  if (mainWindow != null) {
    if (mainWindow.isMinimized()) mainWindow.restore();
    mainWindow.focus();
  }
});

if (!gotTheLock) {
  app.quit();
} else {
  // make sure "Settings" file exists
  // if not, ignore this chunk of code
  // as using electron-settings before app.on('ready') and "Settings" is created
  // would return error
  // https://github.com/nathanbuchar/electron-settings/issues/111
  const useHardwareAcceleration = getPreference('useHardwareAcceleration');
  if (!useHardwareAcceleration) {
    app.disableHardwareAcceleration();
  }

  // mock app.whenReady
  let trulyReady = false;
  ipcMain.once('truly-ready', () => { trulyReady = true; });
  const whenTrulyReady = () => {
    if (trulyReady) return Promise.resolve();
    return new Promise((resolve) => {
      ipcMain.once('truly-ready', () => {
        trulyReady = true;
        resolve();
      });
    });
  };

  // Register protocol
  // needed for PopClip support
  // incompatible with snap
  // see https://forum.snapcraft.io/t/dbus-error/4969/9
  if (process.platform === 'darwin') {
    app.setAsDefaultProtocolClient('translatium');
  }

  // Load listeners
  loadListeners();

  const REACT_PATH = process.env.NODE_ENV === 'production'
    ? `file://${path.resolve(__dirname, 'index.html')}`
    : 'http://localhost:3000';

  const createWindowAsync = () => new Promise((resolve) => {
    const updaterEnabled = process.env.SNAP == null && !process.mas && !process.windowsStore;
    global.attachToMenubar = getPreference('attachToMenubar');
    if (global.attachToMenubar) {
      // setImage after Tray instance is created to avoid
      // "Segmentation fault (core dumped)" bug on Linux
      // https://github.com/electron/electron/issues/22137#issuecomment-586105622
      // https://github.com/quanglam2807/translatium/issues/164
      const tray = new Tray(nativeImage.createEmpty());
      // icon template is not supported on Windows & Linux
      const iconPath = path.resolve(__dirname, 'images', process.platform === 'darwin' ? 'menubarTemplate.png' : 'menubar.png');
      tray.setImage(iconPath);

      const menubarWindowState = windowStateKeeper({
        file: 'window-state-menubar.json',
        defaultWidth: 400,
        defaultHeight: 500,
      });

      mb = menubar({
        index: REACT_PATH,
        tray,
        preloadWindow: true,
        // https://github.com/webcatalog/translatium-desktop/issues/291
        tooltip: 'Translatium',
        browserWindow: {
          alwaysOnTop: getPreference('alwaysOnTop'),
          width: menubarWindowState.width,
          height: menubarWindowState.height,
          minWidth: 400,
          minHeight: 500,
          webPreferences: {
            enableRemoteModule: true,
            contextIsolation: false,
            nodeIntegration: true,
            preload: process.env.NODE_ENV === 'production'
              ? path.join(__dirname, 'preload-menubar.js')
              : path.join(__dirname, 'preload', 'menubar.js'),
          },
        },
      });

      mb.on('ready', () => {
        mb.tray.on('right-click', () => {
          const contextMenu = Menu.buildFromTemplate([
            {
              label: getLocale('aboutApp').replace('{appName}', app.name),
              click: () => {
                sendToAllWindows('open-dialog-about');
                mb.showWindow();
              },
            },
            {
              type: 'separator',
              visible: updaterEnabled,
            },
            {
              label: getLocale('checkForUpdates'),
              click: () => {
                global.updateSilent = false;
                ipcMain.emit('request-check-for-updates');
              },
              visible: updaterEnabled,
            },
            { type: 'separator' },
            {
              label: getLocale('preferencesMenuItem'),
              click: () => {
                sendToAllWindows('go-to-preferences');
                mb.showWindow();
              },
            },
            { type: 'separator' },
            {
              label: getLocale('quit'),
              click: () => {
                mb.app.quit();
              },
            },
          ]);
          mb.tray.popUpContextMenu(contextMenu);
        });

        resolve();
      });

      ipcMain.on('unset-show-menubar-shortcut', (e, combinator) => {
        if (combinator) {
          try {
            globalShortcut.unregister(combinator);
          } catch (err) {
            console.log(err); // eslint-disable-line no-console
          }
        }
      });

      let isHidden = true;

      mb.on('after-create-window', () => {
        menubarWindowState.manage(mb.window);
      });

      mb.on('show', () => {
        isHidden = false;
      });

      mb.on('hide', () => {
        isHidden = true;
      });

      ipcMain.on('set-show-menubar-shortcut', (e, combinator) => {
        if (!combinator) return;
        globalShortcut.register(combinator, () => {
          if (isHidden) {
            mb.showWindow();
            const translateClipboardOnShortcut = getPreference('translateClipboardOnShortcut');
            if (translateClipboardOnShortcut) {
              const text = clipboard.readText();
              if (text.length > 0) {
                mb.window.send('set-input-text', text);
              }
            }
          } else {
            mb.hideWindow();
          }
        });
      });

      const openOnMenubarShortcut = getPreference('openOnMenubarShortcut');
      ipcMain.emit('set-show-menubar-shortcut', null, openOnMenubarShortcut);
    } else {
      // Create the browser window.
      const mainWindowState = windowStateKeeper({
        defaultWidth: 400,
        defaultHeight: 500,
      });

      const winOpts = {
        x: mainWindowState.x,
        y: mainWindowState.y,
        width: mainWindowState.width,
        height: mainWindowState.height,
        minWidth: 400,
        minHeight: 500,
        titleBarStyle: 'hidden',
        autoHideMenuBar: false,
        show: false,
        frame: process.platform === 'darwin',
        webPreferences: {
          enableRemoteModule: true,
          nodeIntegration: true,
          contextIsolation: false,
          webSecurity: false,
          preload: process.env.NODE_ENV === 'production'
            ? path.join(__dirname, 'preload-default.js')
            : path.join(__dirname, 'preload', 'default.js'),
        },
      };

      // manually set dock icon for AppImage
      // Snap icon is set correct already so no need to intervene
      const icon = process.platform === 'linux' && process.env.SNAP == null ? path.resolve(__dirname, 'images', 'icon-linux.png') : undefined;
      // winOpts.icon cannot be set to undefined
      // as it'd crash Electron on macOS
      // https://github.com/electron/electron/issues/27303#issuecomment-759501184
      if (icon) {
        winOpts.icon = icon;
      }

      mainWindow = new BrowserWindow(winOpts);
      mainWindowState.manage(mainWindow);

      mainWindow.on('enter-full-screen', () => {
        mainWindow.webContents.send('set-is-full-screen', true);
      });
      mainWindow.on('leave-full-screen', () => {
        mainWindow.webContents.send('set-is-full-screen', false);
      });

      mainWindow.on('maximize', () => {
        mainWindow.webContents.send('set-is-maximized', true);
      });
      mainWindow.on('unmaximize', () => {
        mainWindow.webContents.send('set-is-maximized', false);
      });

      // Emitted when the window is closed.
      mainWindow.on('closed', () => {
        // Dereference the window object, usually you would store windows
        // in an array if your app supports multi windows, this is the time
        // when you should delete the corresponding element.
        mainWindow = null;
        createMenu();
      });

      const { wasOpenedAsHidden } = app.getLoginItemSettings();
      if (!wasOpenedAsHidden) {
        mainWindow.once('ready-to-show', () => {
          mainWindow.show();
        });
      }

      // ensure redux is loaded first
      // if not, redux might not be able catch changes sent from ipcMain
      mainWindow.webContents.once('did-stop-loading', () => {
        resolve();
      });

      // and load the index.html of the app.
      mainWindow.loadURL(REACT_PATH);
    }
  }).then(() => {
    // trigger whenTrulyReady;
    ipcMain.emit('truly-ready');
  });

  const showWindow = () => {
    // On OS X it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.

    if (global.attachToMenubar) {
      if (mb == null) {
        createWindowAsync();
      } else {
        mb.on('ready', () => {
          mb.showWindow();
        });
      }
    } else if (mainWindow == null) {
      createWindowAsync();
    } else {
      mainWindow.show();
    }
  };

  // This method will be called when Electron has finished
  // initialization and is ready to create browser windows.
  // Some APIs can only be used after this event occurs.
  app.on('ready', () => {
    global.isMacOs11 = isMacOs11();

    initLocales();

    const themeSource = getPreference('themeSource');
    nativeTheme.themeSource = themeSource;

    // Register an event listener.
    // When ipcRenderer sends mouse click co-ordinates, show menu at that position.
    // https://dev.to/saisandeepvaddi/creating-a-custom-menu-bar-in-electron-1pi3
    ipcMain.on('request-show-app-menu', (e, x, y) => {
      if (mainWindow) {
        showMenu(mainWindow, x, y);
      }
    });

    createWindowAsync()
      .then(() => {
        const privacyConsentAsked = getPreference('privacyConsentAsked');
        if (!privacyConsentAsked) {
          dialog.showMessageBox(mainWindow, {
            type: 'question',
            buttons: [getLocale('allow'), getLocale('dontAllow')],
            message: getLocale('privacyConsentMessage'),
            detail: getLocale('privacyConsentDetail'),
            cancelId: 1,
            defaultId: 0,
          }).then(({ response }) => {
            setPreference('privacyConsentAsked', true);
            if (response === 0) {
              setPreference('sentry', true);
              setPreference('telemetry', true);
            } else {
              setPreference('sentry', false);
              setPreference('telemetry', false);
            }
          }).catch(console.log); // eslint-disable-line
        }
      });
    createMenu();
    setContextMenu();

    nativeTheme.addListener('updated', () => {
      sendToAllWindows('native-theme-updated');
    });

    ipcMain.emit('request-check-for-updates');
  });

  // Quit when all windows are closed.
  app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
      app.quit();
    }
  });

  app.on('activate', () => {
    app.whenReady()
      .then(() => {
        showWindow();
      });
  });

  app.on('open-url', (e, urlStr) => {
    e.preventDefault();

    whenTrulyReady()
      .then(() => {
        if (urlStr.startsWith('translatium://')) {
          const urlObj = url.parse(urlStr, true);
          const text = decodeURIComponent(urlObj.query.text || '');

          if (global.attachToMenubar) {
            if (mb && mb.window) {
              mb.window.send('go-to-home');
              mb.window.send('set-input-lang', 'auto');
              mb.window.send('set-input-text', text);
              mb.showWindow();
            }
          } else if (mainWindow) {
            mainWindow.send('go-to-home');
            mainWindow.send('set-input-lang', 'auto');
            mainWindow.send('set-input-text', text);
            mainWindow.show();
          }
        }
      });
  });

  ipcMain.on('show-window', () => {
    showWindow();
  });
}
<commit_msg>Fix app menu doesn't work when attaching to taskbar (#307)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/* eslint import/no-unresolved: [2, { ignore: ['electron'] }] */
/* eslint-disable import/no-extraneous-dependencies */
require('source-map-support').install();

const {
  BrowserWindow,
  Menu,
  Tray,
  app,
  clipboard,
  dialog,
  globalShortcut,
  ipcMain,
  nativeImage,
  nativeTheme,
} = require('electron');
const isDev = require('electron-is-dev');
const settings = require('electron-settings');

settings.configure({
  fileName: 'Settings', // backward compatible with electron-settings@3
});

const path = require('path');
const url = require('url');
const { menubar } = require('menubar');
const windowStateKeeper = require('electron-window-state');

const { getPreference, setPreference } = require('./libs/preferences');

// Activate the Sentry Electron SDK as early as possible in every process.
if (!isDev && getPreference('sentry')) {
  // eslint-disable-next-line global-require
  require('./libs/sentry');
}

const { createMenu, showMenu } = require('./libs/menu');
const loadListeners = require('./listeners');
const { initLocales, getLocale } = require('./libs/locales');
const sendToAllWindows = require('./libs/send-to-all-windows');
const setContextMenu = require('./libs/set-context-menu');
const isMacOs11 = require('./libs/is-mac-os-11');

// we only need updater for AppImage
if (process.platform === 'linux' && process.env.SNAP == null) {
  // eslint-disable-next-line global-require
  require('./libs/updater');
}

// see https://github.com/electron/electron/issues/18397
app.allowRendererProcessReuse = true;

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mb;
let mainWindow;

// app.requestSingleInstanceLock doesnt work for signed mas builds (Mac App Store)
// see https://github.com/electron/electron/issues/15958
const gotTheLock = process.mas || app.requestSingleInstanceLock();

app.on('second-instance', () => {
  if (mainWindow != null) {
    if (mainWindow.isMinimized()) mainWindow.restore();
    mainWindow.focus();
  }
});

if (!gotTheLock) {
  app.quit();
} else {
  // make sure "Settings" file exists
  // if not, ignore this chunk of code
  // as using electron-settings before app.on('ready') and "Settings" is created
  // would return error
  // https://github.com/nathanbuchar/electron-settings/issues/111
  const useHardwareAcceleration = getPreference('useHardwareAcceleration');
  if (!useHardwareAcceleration) {
    app.disableHardwareAcceleration();
  }

  // mock app.whenReady
  let trulyReady = false;
  ipcMain.once('truly-ready', () => { trulyReady = true; });
  const whenTrulyReady = () => {
    if (trulyReady) return Promise.resolve();
    return new Promise((resolve) => {
      ipcMain.once('truly-ready', () => {
        trulyReady = true;
        resolve();
      });
    });
  };

  // Register protocol
  // needed for PopClip support
  // incompatible with snap
  // see https://forum.snapcraft.io/t/dbus-error/4969/9
  if (process.platform === 'darwin') {
    app.setAsDefaultProtocolClient('translatium');
  }

  // Load listeners
  loadListeners();

  const REACT_PATH = process.env.NODE_ENV === 'production'
    ? `file://${path.resolve(__dirname, 'index.html')}`
    : 'http://localhost:3000';

  const createWindowAsync = () => new Promise((resolve) => {
    const updaterEnabled = process.env.SNAP == null && !process.mas && !process.windowsStore;
    global.attachToMenubar = getPreference('attachToMenubar');
    if (global.attachToMenubar) {
      // setImage after Tray instance is created to avoid
      // "Segmentation fault (core dumped)" bug on Linux
      // https://github.com/electron/electron/issues/22137#issuecomment-586105622
      // https://github.com/quanglam2807/translatium/issues/164
      const tray = new Tray(nativeImage.createEmpty());
      // icon template is not supported on Windows & Linux
      const iconPath = path.resolve(__dirname, 'images', process.platform === 'darwin' ? 'menubarTemplate.png' : 'menubar.png');
      tray.setImage(iconPath);

      const menubarWindowState = windowStateKeeper({
        file: 'window-state-menubar.json',
        defaultWidth: 400,
        defaultHeight: 500,
      });

      mb = menubar({
        index: REACT_PATH,
        tray,
        preloadWindow: true,
        // https://github.com/webcatalog/translatium-desktop/issues/291
        tooltip: 'Translatium',
        browserWindow: {
          alwaysOnTop: getPreference('alwaysOnTop'),
          width: menubarWindowState.width,
          height: menubarWindowState.height,
          minWidth: 400,
          minHeight: 500,
          webPreferences: {
            enableRemoteModule: true,
            contextIsolation: false,
            nodeIntegration: true,
            preload: process.env.NODE_ENV === 'production'
              ? path.join(__dirname, 'preload-menubar.js')
              : path.join(__dirname, 'preload', 'menubar.js'),
          },
        },
      });

      mb.on('ready', () => {
        mb.tray.on('right-click', () => {
          const contextMenu = Menu.buildFromTemplate([
            {
              label: getLocale('aboutApp').replace('{appName}', app.name),
              click: () => {
                sendToAllWindows('open-dialog-about');
                mb.showWindow();
              },
            },
            {
              type: 'separator',
              visible: updaterEnabled,
            },
            {
              label: getLocale('checkForUpdates'),
              click: () => {
                global.updateSilent = false;
                ipcMain.emit('request-check-for-updates');
              },
              visible: updaterEnabled,
            },
            { type: 'separator' },
            {
              label: getLocale('preferencesMenuItem'),
              click: () => {
                sendToAllWindows('go-to-preferences');
                mb.showWindow();
              },
            },
            { type: 'separator' },
            {
              label: getLocale('quit'),
              click: () => {
                mb.app.quit();
              },
            },
          ]);
          mb.tray.popUpContextMenu(contextMenu);
        });

        resolve();
      });

      ipcMain.on('unset-show-menubar-shortcut', (e, combinator) => {
        if (combinator) {
          try {
            globalShortcut.unregister(combinator);
          } catch (err) {
            console.log(err); // eslint-disable-line no-console
          }
        }
      });

      let isHidden = true;

      mb.on('after-create-window', () => {
        menubarWindowState.manage(mb.window);
      });

      mb.on('show', () => {
        isHidden = false;
      });

      mb.on('hide', () => {
        isHidden = true;
      });

      ipcMain.on('set-show-menubar-shortcut', (e, combinator) => {
        if (!combinator) return;
        globalShortcut.register(combinator, () => {
          if (isHidden) {
            mb.showWindow();
            const translateClipboardOnShortcut = getPreference('translateClipboardOnShortcut');
            if (translateClipboardOnShortcut) {
              const text = clipboard.readText();
              if (text.length > 0) {
                mb.window.send('set-input-text', text);
              }
            }
          } else {
            mb.hideWindow();
          }
        });
      });

      const openOnMenubarShortcut = getPreference('openOnMenubarShortcut');
      ipcMain.emit('set-show-menubar-shortcut', null, openOnMenubarShortcut);
    } else {
      // Create the browser window.
      const mainWindowState = windowStateKeeper({
        defaultWidth: 400,
        defaultHeight: 500,
      });

      const winOpts = {
        x: mainWindowState.x,
        y: mainWindowState.y,
        width: mainWindowState.width,
        height: mainWindowState.height,
        minWidth: 400,
        minHeight: 500,
        titleBarStyle: 'hidden',
        autoHideMenuBar: false,
        show: false,
        frame: process.platform === 'darwin',
        webPreferences: {
          enableRemoteModule: true,
          nodeIntegration: true,
          contextIsolation: false,
          webSecurity: false,
          preload: process.env.NODE_ENV === 'production'
            ? path.join(__dirname, 'preload-default.js')
            : path.join(__dirname, 'preload', 'default.js'),
        },
      };

      // manually set dock icon for AppImage
      // Snap icon is set correct already so no need to intervene
      const icon = process.platform === 'linux' && process.env.SNAP == null ? path.resolve(__dirname, 'images', 'icon-linux.png') : undefined;
      // winOpts.icon cannot be set to undefined
      // as it'd crash Electron on macOS
      // https://github.com/electron/electron/issues/27303#issuecomment-759501184
      if (icon) {
        winOpts.icon = icon;
      }

      mainWindow = new BrowserWindow(winOpts);
      mainWindowState.manage(mainWindow);

      mainWindow.on('enter-full-screen', () => {
        mainWindow.webContents.send('set-is-full-screen', true);
      });
      mainWindow.on('leave-full-screen', () => {
        mainWindow.webContents.send('set-is-full-screen', false);
      });

      mainWindow.on('maximize', () => {
        mainWindow.webContents.send('set-is-maximized', true);
      });
      mainWindow.on('unmaximize', () => {
        mainWindow.webContents.send('set-is-maximized', false);
      });

      // Emitted when the window is closed.
      mainWindow.on('closed', () => {
        // Dereference the window object, usually you would store windows
        // in an array if your app supports multi windows, this is the time
        // when you should delete the corresponding element.
        mainWindow = null;
        createMenu();
      });

      const { wasOpenedAsHidden } = app.getLoginItemSettings();
      if (!wasOpenedAsHidden) {
        mainWindow.once('ready-to-show', () => {
          mainWindow.show();
        });
      }

      // ensure redux is loaded first
      // if not, redux might not be able catch changes sent from ipcMain
      mainWindow.webContents.once('did-stop-loading', () => {
        resolve();
      });

      // and load the index.html of the app.
      mainWindow.loadURL(REACT_PATH);
    }
  }).then(() => {
    // trigger whenTrulyReady;
    ipcMain.emit('truly-ready');
  });

  const showWindow = () => {
    // On OS X it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.

    if (global.attachToMenubar) {
      if (mb == null) {
        createWindowAsync();
      } else {
        mb.on('ready', () => {
          mb.showWindow();
        });
      }
    } else if (mainWindow == null) {
      createWindowAsync();
    } else {
      mainWindow.show();
    }
  };

  // This method will be called when Electron has finished
  // initialization and is ready to create browser windows.
  // Some APIs can only be used after this event occurs.
  app.on('ready', () => {
    global.isMacOs11 = isMacOs11();

    initLocales();

    const themeSource = getPreference('themeSource');
    nativeTheme.themeSource = themeSource;

    // Register an event listener.
    // When ipcRenderer sends mouse click co-ordinates, show menu at that position.
    // https://dev.to/saisandeepvaddi/creating-a-custom-menu-bar-in-electron-1pi3
    ipcMain.on('request-show-app-menu', (e, x, y) => {
      if (global.attachToMenubar) {
        if (mb && mb.window) {
          showMenu(mb.window, x, y);
        }
      } else if (mainWindow) {
        showMenu(mainWindow, x, y);
      }
    });

    createWindowAsync()
      .then(() => {
        const privacyConsentAsked = getPreference('privacyConsentAsked');
        if (!privacyConsentAsked) {
          dialog.showMessageBox(mainWindow, {
            type: 'question',
            buttons: [getLocale('allow'), getLocale('dontAllow')],
            message: getLocale('privacyConsentMessage'),
            detail: getLocale('privacyConsentDetail'),
            cancelId: 1,
            defaultId: 0,
          }).then(({ response }) => {
            setPreference('privacyConsentAsked', true);
            if (response === 0) {
              setPreference('sentry', true);
              setPreference('telemetry', true);
            } else {
              setPreference('sentry', false);
              setPreference('telemetry', false);
            }
          }).catch(console.log); // eslint-disable-line
        }
      });
    createMenu();
    setContextMenu();

    nativeTheme.addListener('updated', () => {
      sendToAllWindows('native-theme-updated');
    });

    ipcMain.emit('request-check-for-updates');
  });

  // Quit when all windows are closed.
  app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
      app.quit();
    }
  });

  app.on('activate', () => {
    app.whenReady()
      .then(() => {
        showWindow();
      });
  });

  app.on('open-url', (e, urlStr) => {
    e.preventDefault();

    whenTrulyReady()
      .then(() => {
        if (urlStr.startsWith('translatium://')) {
          const urlObj = url.parse(urlStr, true);
          const text = decodeURIComponent(urlObj.query.text || '');

          if (global.attachToMenubar) {
            if (mb && mb.window) {
              mb.window.send('go-to-home');
              mb.window.send('set-input-lang', 'auto');
              mb.window.send('set-input-text', text);
              mb.showWindow();
            }
          } else if (mainWindow) {
            mainWindow.send('go-to-home');
            mainWindow.send('set-input-lang', 'auto');
            mainWindow.send('set-input-text', text);
            mainWindow.show();
          }
        }
      });
  });

  ipcMain.on('show-window', () => {
    showWindow();
  });
}
<|endoftext|>


<commit_before>/*jslint browser: true, for: true, node: true */
/*global window */

/*!

   hlsjs engine plugin for Flowplayer HTML5

   Copyright (c) 2015-2016, Flowplayer Oy

   Released under the MIT License:
   http://www.opensource.org/licenses/mit-license.php

   Includes hls.js
   Copyright (c) 2015 Dailymotion (http://www.dailymotion.com)
   https://github.com/dailymotion/hls.js/blob/master/LICENSE

   requires:
   - Flowplayer HTML5 version 6.x or greater
   - hls.js https://github.com/dailymotion/hls.js
   revision: $GIT_ID$

*/

(function (flowplayer, Hls) {
    "use strict";
    var engineName = "hlsjs",
        hlsconf,
        common = flowplayer.common,
        extend = flowplayer.extend,
        version = flowplayer.version,

        isHlsType = function (typ) {
            return typ.toLowerCase().indexOf("mpegurl") > -1;
        },

        engineImpl = function hlsjsEngine(player, root) {
            var bean = flowplayer.bean,
                videoTag,
                hls,
                recover,

                bc,
                has_bg,
                posterHack = function () {
                    // abuse timeupdate to re-instate poster
                    var posterClass = "is-poster",
                        etype = "progress." + engineName;

                    player.one(etype, function () {
                        common.addClass(root, posterClass);
                        player.poster = true;
                        player.one(etype, function () {
                            common.removeClass(root, posterClass);
                            player.poster = false;
                        });
                    });
                },

                engine = {
                    engineName: engineName,

                    pick: function (sources) {
                        var i,
                            source;

                        for (i = 0; i < sources.length; i += 1) {
                            source = sources[i];
                            if (isHlsType(source.type)
                                    && (!source.engine || source.engine === engineName)) {
                                if (typeof source.src === 'string') {
                                    source.src = common.createAbsoluteUrl(source.src);
                                }
                                return source;
                            }
                        }
                    },

                    load: function (video) {
                        var init = !hls,
                            conf = player.conf,
                            hlsClientConf = extend({}, hlsconf),
                            hlsParams = ["anamorphic", "autoLevelCapping", "recover", "startLevel", "strict"];

                        if (init) {
                            common.removeNode(common.findDirect("video", root)[0]
                                    || common.find(".fp-player > video", root)[0]);
                            videoTag = common.createElement("video", {
                                className: "fp-engine " + engineName + "-engine",
                                autoplay: conf.autoplay
                                    ? "autoplay"
                                    : false
                            });
                            videoTag.setAttribute("x-webkit-airplay", "allow");

                        } else {
                            hls.destroy();
                        }

                        bean.on(videoTag, "play", function () {
                            player.trigger('resume', [player]);
                        });
                        bean.on(videoTag, "pause", function () {
                            player.trigger('pause', [player]);
                        });
                        bean.on(videoTag, "timeupdate", function () {
                            player.trigger('progress', [player, videoTag.currentTime]);
                        });
                        bean.on(videoTag, "loadeddata", function () {
                            video = extend(video, {
                                duration: videoTag.duration,
                                seekable: videoTag.seekable.end(null),
                                width: videoTag.videoWidth,
                                height: videoTag.videoHeight,
                                url: videoTag.currentSrc
                            });
                            player.trigger('ready', [player, video]);
                        });
                        bean.on(videoTag, "seeked", function () {
                            player.trigger('seek', [player, videoTag.currentTime]);
                        });
                        bean.on(videoTag, "progress", function (e) {
                            var ct = videoTag.currentTime,
                                buffer = 0,
                                buffend,
                                buffered,
                                last,
                                i;

                            try {
                                buffered = videoTag.buffered;
                                last = buffered.length - 1;
                                buffend = 0;
                                // cycle through time ranges to obtain buffer
                                // nearest current time
                                if (ct) {
                                    for (i = last; i > -1; i -= 1) {
                                        buffend = buffered.end(i);

                                        if (buffend >= ct) {
                                            buffer = buffend;
                                        }
                                    }
                                }
                            } catch (ignore) {}

                            video.buffer = buffer;
                            player.trigger('buffer', [player, e]);
                        });
                        bean.on(videoTag, "ended", function () {
                            player.trigger('finish', [player]);
                        });
                        bean.on(videoTag, "volumechange", function () {
                            player.trigger('volume', [player, videoTag.volume]);
                        });

                        hlsParams.forEach(function (key) {
                            delete hlsClientConf[key];
                        });
                        hls = new Hls(hlsClientConf);
                        player.engine[engineName] = hls;

                        hlsParams.forEach(function (key) {
                            var value = hlsconf[key];

                            switch (key) {
                            case "autoLevelCapping":
                                if (value === false) {
                                    value = -1;
                                }
                                break;
                            case "recover":
                                recover = hlsconf.strict
                                    ? 0
                                    : value;
                                break;
                            case "startLevel":
                                switch (value) {
                                case "auto":
                                    value = -1;
                                    break;
                                case "firstLevel":
                                    value = undefined;
                                    break;
                                }
                                break;
                            }

                            if (key !== "strict" && key !== "recover" && value !== undefined) {
                                hls[key] = value;
                            }
                        });

                        hls.on(Hls.Events.ERROR, function (e, data) {
                            var fperr,
                                errobj = {};

                            if (data.fatal || hlsconf.strict > 0) {
                                switch (data.type) {
                                case Hls.ErrorTypes.NETWORK_ERROR:
                                    if (recover) {
                                        hls.startLoad();
                                        if (recover > 0) {
                                            recover -= 1;
                                        }
                                    } else if (data.frag && data.frag.url) {
                                        errobj.url = data.frag.url;
                                        fperr = 2;
                                    } else {
                                        fperr = 4;
                                    }
                                    break;
                                case Hls.ErrorTypes.MEDIA_ERROR:
                                    if (recover) {
                                        hls.recoverMediaError();
                                        if (recover > 0) {
                                            recover -= 1;
                                        }
                                    } else {
                                        fperr = 3;
                                    }
                                    break;
                                default:
                                    fperr = 5;
                                }

                                if (fperr !== undefined) {
                                    errobj.code = fperr;
                                    if (fperr > 2) {
                                        errobj.video = extend(video, {
                                            src: video.src,
                                            url: data.url || video.src
                                        });
                                    }
                                    player.trigger('error', [player, errobj]);
                                }
                            }
                            /* TODO: */
                            // log non fatals
                        });

                        if (init) {
                            common.prepend(common.find(".fp-player", root)[0], videoTag);
                        }

                        hls.loadSource(video.src);
                        hls.attachMedia(videoTag);

                        if (videoTag.paused && (video.autoplay || conf.autoplay)) {
                            videoTag.play();
                        }
                    },

                    resume: function () {
                        videoTag.play();
                    },

                    pause: function () {
                        videoTag.pause();
                    },

                    seek: function (time) {
                        videoTag.currentTime = time;
                    },

                    volume: function (level) {
                        if (videoTag) {
                            videoTag.volume = level;
                        }
                    },

                    speed: function (val) {
                        videoTag.playbackRate = val;
                        player.trigger('speed', [player, val]);
                    },

                    unload: function () {
                        // hls conditional probably not needed once
                        // https://github.com/flowplayer/flowplayer/commit/871ff783a8f23aa603e1120f4319d4a892125b0a
                        // is released
                        if (hls) {
                            hls.destroy();
                            hls = 0;
                            bean.off(videoTag);
                            common.removeNode(videoTag);
                            videoTag = 0;
                        }
                    }
                };

            // pre 6.0.4: no boolean api.conf.poster and no poster with autoplay
            if (/^6\.0\.[0-3]$/.test(version) &&
                    !player.conf.splash && !player.conf.poster && !player.conf.autoplay) {
                bc = common.css(root, 'backgroundColor');
                // spaces in rgba arg mandatory for recognition
                has_bg = common.css(root, 'backgroundImage') !== "none" ||
                        (bc && bc !== "rgba(0, 0, 0, 0)" && bc !== "transparent");
                if (has_bg) {
                    player.conf.poster = true;
                }
            }
            if (player.conf.poster) {
                // when engine is loaded or player stopped
                // the engine is too late to the party:
                // poster is already removed and api.poster is false
                // poster state must be set again
                player.on("ready." + engineName + " stop." + engineName, posterHack);
            }

            return engine;
        };

    if (Hls.isSupported() && version.indexOf("5.") !== 0) {
        // only load engine if it can be used
        engineImpl.engineName = engineName; // must be exposed
        engineImpl.canPlay = function (type, conf) {
            var b = flowplayer.support.browser,
                wn = window.navigator,
                IE11 = wn.userAgent.indexOf("Trident/7") > -1;

            if (conf[engineName] === false || conf.clip[engineName] === false) {
                // engine disabled for player or clip
                return false;
            }

            // merge hlsjs clip config at earliest opportunity
            hlsconf = extend({
                recover: 0
            }, flowplayer.conf[engineName], conf[engineName], conf.clip[engineName]);

            if (isHlsType(type)) {
                // allow all browsers for hlsjs debugging
                if (hlsconf.debug) {
                    return true;
                }
                // https://bugzilla.mozilla.org/show_bug.cgi?id=1244294
                if (hlsconf.anamorphic &&
                        wn.platform.indexOf("Win") === 0 && b.mozilla && b.version.indexOf("44.") === 0) {
                    return false;
                }

                // https://github.com/dailymotion/hls.js/issues/9
                return IE11 || !b.safari;
            }
            return false;
        };

        // put on top of engine stack
        // so hlsjs is tested before html5 video hls and flash hls
        flowplayer.engines.unshift(engineImpl);

    }

}.apply(null, (typeof module === 'object' && module.exports)
    ? [require('flowplayer'), require('hls.js')['default']]
    : [window.flowplayer, window.Hls]));
<commit_msg>Reading from `default`  not needed anymore<commit_after>/*jslint browser: true, for: true, node: true */
/*global window */

/*!

   hlsjs engine plugin for Flowplayer HTML5

   Copyright (c) 2015-2016, Flowplayer Oy

   Released under the MIT License:
   http://www.opensource.org/licenses/mit-license.php

   Includes hls.js
   Copyright (c) 2015 Dailymotion (http://www.dailymotion.com)
   https://github.com/dailymotion/hls.js/blob/master/LICENSE

   requires:
   - Flowplayer HTML5 version 6.x or greater
   - hls.js https://github.com/dailymotion/hls.js
   revision: $GIT_ID$

*/

(function (flowplayer, Hls) {
    "use strict";
    var engineName = "hlsjs",
        hlsconf,
        common = flowplayer.common,
        extend = flowplayer.extend,
        version = flowplayer.version,

        isHlsType = function (typ) {
            return typ.toLowerCase().indexOf("mpegurl") > -1;
        },

        engineImpl = function hlsjsEngine(player, root) {
            var bean = flowplayer.bean,
                videoTag,
                hls,
                recover,

                bc,
                has_bg,
                posterHack = function () {
                    // abuse timeupdate to re-instate poster
                    var posterClass = "is-poster",
                        etype = "progress." + engineName;

                    player.one(etype, function () {
                        common.addClass(root, posterClass);
                        player.poster = true;
                        player.one(etype, function () {
                            common.removeClass(root, posterClass);
                            player.poster = false;
                        });
                    });
                },

                engine = {
                    engineName: engineName,

                    pick: function (sources) {
                        var i,
                            source;

                        for (i = 0; i < sources.length; i += 1) {
                            source = sources[i];
                            if (isHlsType(source.type)
                                    && (!source.engine || source.engine === engineName)) {
                                if (typeof source.src === 'string') {
                                    source.src = common.createAbsoluteUrl(source.src);
                                }
                                return source;
                            }
                        }
                    },

                    load: function (video) {
                        var init = !hls,
                            conf = player.conf,
                            hlsClientConf = extend({}, hlsconf),
                            hlsParams = ["anamorphic", "autoLevelCapping", "recover", "startLevel", "strict"];

                        if (init) {
                            common.removeNode(common.findDirect("video", root)[0]
                                    || common.find(".fp-player > video", root)[0]);
                            videoTag = common.createElement("video", {
                                className: "fp-engine " + engineName + "-engine",
                                autoplay: conf.autoplay
                                    ? "autoplay"
                                    : false
                            });
                            videoTag.setAttribute("x-webkit-airplay", "allow");

                        } else {
                            hls.destroy();
                        }

                        bean.on(videoTag, "play", function () {
                            player.trigger('resume', [player]);
                        });
                        bean.on(videoTag, "pause", function () {
                            player.trigger('pause', [player]);
                        });
                        bean.on(videoTag, "timeupdate", function () {
                            player.trigger('progress', [player, videoTag.currentTime]);
                        });
                        bean.on(videoTag, "loadeddata", function () {
                            video = extend(video, {
                                duration: videoTag.duration,
                                seekable: videoTag.seekable.end(null),
                                width: videoTag.videoWidth,
                                height: videoTag.videoHeight,
                                url: videoTag.currentSrc
                            });
                            player.trigger('ready', [player, video]);
                        });
                        bean.on(videoTag, "seeked", function () {
                            player.trigger('seek', [player, videoTag.currentTime]);
                        });
                        bean.on(videoTag, "progress", function (e) {
                            var ct = videoTag.currentTime,
                                buffer = 0,
                                buffend,
                                buffered,
                                last,
                                i;

                            try {
                                buffered = videoTag.buffered;
                                last = buffered.length - 1;
                                buffend = 0;
                                // cycle through time ranges to obtain buffer
                                // nearest current time
                                if (ct) {
                                    for (i = last; i > -1; i -= 1) {
                                        buffend = buffered.end(i);

                                        if (buffend >= ct) {
                                            buffer = buffend;
                                        }
                                    }
                                }
                            } catch (ignore) {}

                            video.buffer = buffer;
                            player.trigger('buffer', [player, e]);
                        });
                        bean.on(videoTag, "ended", function () {
                            player.trigger('finish', [player]);
                        });
                        bean.on(videoTag, "volumechange", function () {
                            player.trigger('volume', [player, videoTag.volume]);
                        });

                        hlsParams.forEach(function (key) {
                            delete hlsClientConf[key];
                        });
                        hls = new Hls(hlsClientConf);
                        player.engine[engineName] = hls;

                        hlsParams.forEach(function (key) {
                            var value = hlsconf[key];

                            switch (key) {
                            case "autoLevelCapping":
                                if (value === false) {
                                    value = -1;
                                }
                                break;
                            case "recover":
                                recover = hlsconf.strict
                                    ? 0
                                    : value;
                                break;
                            case "startLevel":
                                switch (value) {
                                case "auto":
                                    value = -1;
                                    break;
                                case "firstLevel":
                                    value = undefined;
                                    break;
                                }
                                break;
                            }

                            if (key !== "strict" && key !== "recover" && value !== undefined) {
                                hls[key] = value;
                            }
                        });

                        hls.on(Hls.Events.ERROR, function (e, data) {
                            var fperr,
                                errobj = {};

                            if (data.fatal || hlsconf.strict > 0) {
                                switch (data.type) {
                                case Hls.ErrorTypes.NETWORK_ERROR:
                                    if (recover) {
                                        hls.startLoad();
                                        if (recover > 0) {
                                            recover -= 1;
                                        }
                                    } else if (data.frag && data.frag.url) {
                                        errobj.url = data.frag.url;
                                        fperr = 2;
                                    } else {
                                        fperr = 4;
                                    }
                                    break;
                                case Hls.ErrorTypes.MEDIA_ERROR:
                                    if (recover) {
                                        hls.recoverMediaError();
                                        if (recover > 0) {
                                            recover -= 1;
                                        }
                                    } else {
                                        fperr = 3;
                                    }
                                    break;
                                default:
                                    fperr = 5;
                                }

                                if (fperr !== undefined) {
                                    errobj.code = fperr;
                                    if (fperr > 2) {
                                        errobj.video = extend(video, {
                                            src: video.src,
                                            url: data.url || video.src
                                        });
                                    }
                                    player.trigger('error', [player, errobj]);
                                }
                            }
                            /* TODO: */
                            // log non fatals
                        });

                        if (init) {
                            common.prepend(common.find(".fp-player", root)[0], videoTag);
                        }

                        hls.loadSource(video.src);
                        hls.attachMedia(videoTag);

                        if (videoTag.paused && (video.autoplay || conf.autoplay)) {
                            videoTag.play();
                        }
                    },

                    resume: function () {
                        videoTag.play();
                    },

                    pause: function () {
                        videoTag.pause();
                    },

                    seek: function (time) {
                        videoTag.currentTime = time;
                    },

                    volume: function (level) {
                        if (videoTag) {
                            videoTag.volume = level;
                        }
                    },

                    speed: function (val) {
                        videoTag.playbackRate = val;
                        player.trigger('speed', [player, val]);
                    },

                    unload: function () {
                        // hls conditional probably not needed once
                        // https://github.com/flowplayer/flowplayer/commit/871ff783a8f23aa603e1120f4319d4a892125b0a
                        // is released
                        if (hls) {
                            hls.destroy();
                            hls = 0;
                            bean.off(videoTag);
                            common.removeNode(videoTag);
                            videoTag = 0;
                        }
                    }
                };

            // pre 6.0.4: no boolean api.conf.poster and no poster with autoplay
            if (/^6\.0\.[0-3]$/.test(version) &&
                    !player.conf.splash && !player.conf.poster && !player.conf.autoplay) {
                bc = common.css(root, 'backgroundColor');
                // spaces in rgba arg mandatory for recognition
                has_bg = common.css(root, 'backgroundImage') !== "none" ||
                        (bc && bc !== "rgba(0, 0, 0, 0)" && bc !== "transparent");
                if (has_bg) {
                    player.conf.poster = true;
                }
            }
            if (player.conf.poster) {
                // when engine is loaded or player stopped
                // the engine is too late to the party:
                // poster is already removed and api.poster is false
                // poster state must be set again
                player.on("ready." + engineName + " stop." + engineName, posterHack);
            }

            return engine;
        };

    if (Hls.isSupported() && version.indexOf("5.") !== 0) {
        // only load engine if it can be used
        engineImpl.engineName = engineName; // must be exposed
        engineImpl.canPlay = function (type, conf) {
            var b = flowplayer.support.browser,
                wn = window.navigator,
                IE11 = wn.userAgent.indexOf("Trident/7") > -1;

            if (conf[engineName] === false || conf.clip[engineName] === false) {
                // engine disabled for player or clip
                return false;
            }

            // merge hlsjs clip config at earliest opportunity
            hlsconf = extend({
                recover: 0
            }, flowplayer.conf[engineName], conf[engineName], conf.clip[engineName]);

            if (isHlsType(type)) {
                // allow all browsers for hlsjs debugging
                if (hlsconf.debug) {
                    return true;
                }
                // https://bugzilla.mozilla.org/show_bug.cgi?id=1244294
                if (hlsconf.anamorphic &&
                        wn.platform.indexOf("Win") === 0 && b.mozilla && b.version.indexOf("44.") === 0) {
                    return false;
                }

                // https://github.com/dailymotion/hls.js/issues/9
                return IE11 || !b.safari;
            }
            return false;
        };

        // put on top of engine stack
        // so hlsjs is tested before html5 video hls and flash hls
        flowplayer.engines.unshift(engineImpl);

    }

}.apply(null, (typeof module === 'object' && module.exports)
    ? [require('flowplayer'), require('hls.js')]
    : [window.flowplayer, window.Hls]));
<|endoftext|>


<commit_before>/*jslint browser: true, for: true, node: true */
/*global window */

/*!

   hlsjs engine plugin for Flowplayer HTML5

   Copyright (c) 2015, Flowplayer Oy

   Released under the MIT License:
   http://www.opensource.org/licenses/mit-license.php

   Includes hls.min.js
   Copyright (c) 2015 Dailymotion (http://www.dailymotion.com)
   https://github.com/dailymotion/hls.js/blob/master/LICENSE

   requires:
   - Flowplayer HTML5 version 6.x or greater
   - hls.js https://github.com/dailymotion/hls.js
   revision: $GIT_ID$

*/

(function (flowplayer, Hls) {
    "use strict";
    var engineName = "hlsjs",
        hlsconf,
        common = flowplayer.common,
        extend = flowplayer.extend,
        version = flowplayer.version,

        isHlsType = function (typ) {
            return typ.toLowerCase().indexOf("mpegurl") > -1;
        },

        engineImpl = function hlsjsEngine(player, root) {
            var bean = flowplayer.bean,
                videoTag,
                hls,

                engine = {
                    engineName: engineName,

                    pick: function (sources) {
                        var i,
                            source;

                        for (i = 0; i < sources.length; i += 1) {
                            source = sources[i];
                            if (isHlsType(source.type)
                                    && (!source.engine || source.engine === engineName)) {
                                return source;
                            }
                        }
                    },

                    load: function (video) {
                        var init = !hls,
                            conf = player.conf,
                            hlsClientConf = extend({}, hlsconf),
                            hlsParams = ["autoLevelCapping", "startLevel", "strict"];

                        if (init) {
                            common.removeNode(common.findDirect("video", root)[0]
                                    || common.find(".fp-player > video", root)[0]);
                            videoTag = common.createElement("video", {
                                className: "fp-engine " + engineName + "-engine",
                                autoplay: conf.autoplay
                                    ? "autoplay"
                                    : false
                            });
                            videoTag.setAttribute("x-webkit-airplay", "allow");

                        } else {
                            hls.destroy();
                        }

                        bean.on(videoTag, "play", function () {
                            player.trigger('resume', [player]);
                        });
                        bean.on(videoTag, "pause", function () {
                            player.trigger('pause', [player]);
                        });
                        bean.on(videoTag, "timeupdate", function () {
                            player.trigger('progress', [player, videoTag.currentTime]);
                        });
                        bean.on(videoTag, "loadeddata", function () {
                            video = extend(video, {
                                duration: videoTag.duration,
                                seekable: videoTag.seekable.end(null),
                                width: videoTag.videoWidth,
                                height: videoTag.videoHeight,
                                url: videoTag.currentSrc
                            });
                            player.trigger('ready', [player, video]);
                        });
                        bean.on(videoTag, "seeked", function () {
                            player.trigger('seek', [player, videoTag.currentTime]);
                        });
                        bean.on(videoTag, "progress", function (e) {
                            var ct = videoTag.currentTime,
                                buffer = 0,
                                buffend,
                                buffered,
                                last,
                                i;

                            try {
                                buffered = videoTag.buffered;
                                last = buffered.length - 1;
                                buffend = 0;
                                // cycle through time ranges to obtain buffer
                                // nearest current time
                                if (ct) {
                                    for (i = last; i > -1; i -= 1) {
                                        buffend = buffered.end(i);

                                        if (buffend >= ct) {
                                            buffer = buffend;
                                        }
                                    }
                                }
                            } catch (ignored) {}

                            video.buffer = buffer;
                            player.trigger('buffer', [player, e]);
                        });
                        bean.on(videoTag, "ended", function () {
                            player.trigger('finish', [player]);
                        });
                        bean.on(videoTag, "volumechange", function () {
                            player.trigger('volume', [player, videoTag.volume]);
                        });

                        hlsParams.forEach(function (key) {
                            delete hlsClientConf[key];
                        });
                        hls = new Hls(hlsClientConf);

                        hlsParams.forEach(function (key) {
                            var value = hlsconf[key];

                            switch (key) {
                            case "autoLevelCapping":
                                if (value === false) {
                                    value = -1;
                                }
                                break;
                            case "startLevel":
                                switch (value) {
                                case "auto":
                                    value = -1;
                                    break;
                                case "firstLevel":
                                    value = undefined;
                                    break;
                                }
                                break;
                            }

                            if (value !== undefined) {
                                hls[key] = value;
                            }
                        });

                        hls.on(Hls.Events.ERROR, function (e, data) {
                            var fperr,
                                errobj = {};

                            if (data.fatal || hlsconf.strict) {
                                switch (data.type) {
                                case Hls.ErrorTypes.NETWORK_ERROR:
                                    if (data.frag && data.frag.url) {
                                        errobj.url = data.frag.url;
                                        fperr = 2;
                                    } else {
                                        fperr = 4;
                                    }
                                    break;
                                case Hls.ErrorTypes.MEDIA_ERROR:
                                    fperr = 3;
                                    break;
                                default:
                                    fperr = 5;
                                    break;
                                }
                                errobj.code = fperr;
                                if (fperr > 2) {
                                    errobj.video = extend(video, {
                                        src: video.src,
                                        url: data.url || video.src
                                    });
                                }
                                player.trigger('error', [player, errobj]);
                            }
                            /* TODO: */
                            // log non fatals
                        });

                        if (init) {
                            common.prepend(common.find(".fp-player", root)[0], videoTag);
                        }

                        hls.loadSource(video.src);
                        hls.attachVideo(videoTag);

                        if (videoTag.paused && (video.autoplay || conf.autoplay)) {
                            videoTag.play();
                        }
                    },

                    resume: function () {
                        videoTag.play();
                    },

                    pause: function () {
                        videoTag.pause();
                    },

                    seek: function (time) {
                        videoTag.currentTime = time;
                    },

                    volume: function (level) {
                        if (videoTag) {
                            videoTag.volume = level;
                        }
                    },

                    speed: function (val) {
                        videoTag.playbackRate = val;
                        player.trigger('speed', [player, val]);
                    },

                    unload: function () {
                        // hls conditional probably not needed once
                        // https://github.com/flowplayer/flowplayer/commit/871ff783a8f23aa603e1120f4319d4a892125b0a
                        // is released
                        if (hls) {
                            hls.destroy();
                            hls = 0;
                            bean.off(videoTag);
                            common.removeNode(videoTag);
                            videoTag = 0;
                        }
                    }
                };

            return engine;
        };

    if (Hls.isSupported() && version.indexOf("5.") !== 0) {
        // only load engine if it can be used
        engineImpl.engineName = engineName; // must be exposed
        engineImpl.canPlay = function (type, conf) {
            var IE11 = navigator.userAgent.indexOf("Trident/7") > -1;

            if (conf[engineName] === false || conf.clip[engineName] === false) {
                // engine disabled for player or clip
                return false;
            }

            // merge hlsjs clip config at earliest opportunity
            hlsconf = extend({}, flowplayer.conf[engineName], conf[engineName], conf.clip[engineName]);

            // support Safari only when hlsjs debugging
            // https://github.com/dailymotion/hls.js/issues/9
            return isHlsType(type) &&
                    (IE11 || !flowplayer.support.browser.safari || hlsconf.debug);
        };

        // put on top of engine stack
        // so hlsjs is tested before html5 video hls and flash hls
        flowplayer.engines.unshift(engineImpl);

        // poster hack
        flowplayer(function (api, root) {
            // detect poster condition as in core on boot
            var pre604 = /^6\.0\.[0-3]$/.test(version),
                conf = api.conf,
                bc = common.css(root, 'backgroundColor'),
                has_bg = common.css(root, 'backgroundImage') !== "none" ||
                        (bc && bc !== "rgba(0,0,0,0)" && bc !== "transparent"),
                posterCondition = has_bg && !conf.splash
                        && (!pre604 || (pre604 && !conf.autoplay)),

                posterHack = function (e) {
                    // assert that poster is set regardless of client of
                    // video loading delay
                    setTimeout(function () {
                        var posterClass = "is-poster";

                        if (!pre604) {
                            // must set this ourselves
                            api.poster = true;
                        }
                        if (!conf.autoplay || e.type === "stop") {
                            common.addClass(root, posterClass);
                            api.one("resume." + engineName, function () {
                                api.off("ready." + engineName);
                                common.removeClass(root, posterClass);
                            });
                        }
                    }, 0);
                };

            if (posterCondition) {
                api.on("ready." + engineName + " stop." + engineName, posterHack)
                    .one("seek." + engineName, posterHack);
            }
        });
    }

}.apply(null, (typeof module === 'object' && module.exports)
    ? [require('flowplayer'), require('hls.js')]
    : [window.flowplayer, window.Hls]));
<commit_msg>Video src should be absolute currently for some core evaluations<commit_after>/*jslint browser: true, for: true, node: true */
/*global window */

/*!

   hlsjs engine plugin for Flowplayer HTML5

   Copyright (c) 2015, Flowplayer Oy

   Released under the MIT License:
   http://www.opensource.org/licenses/mit-license.php

   Includes hls.min.js
   Copyright (c) 2015 Dailymotion (http://www.dailymotion.com)
   https://github.com/dailymotion/hls.js/blob/master/LICENSE

   requires:
   - Flowplayer HTML5 version 6.x or greater
   - hls.js https://github.com/dailymotion/hls.js
   revision: $GIT_ID$

*/

(function (flowplayer, Hls) {
    "use strict";
    var engineName = "hlsjs",
        hlsconf,
        common = flowplayer.common,
        extend = flowplayer.extend,
        version = flowplayer.version,

        isHlsType = function (typ) {
            return typ.toLowerCase().indexOf("mpegurl") > -1;
        },

        engineImpl = function hlsjsEngine(player, root) {
            var bean = flowplayer.bean,
                videoTag,
                hls,

                engine = {
                    engineName: engineName,

                    pick: function (sources) {
                        var i,
                            source;

                        for (i = 0; i < sources.length; i += 1) {
                            source = sources[i];
                            if (isHlsType(source.type)
                                    && (!source.engine || source.engine === engineName)) {
                                if (typeof source.src === 'string') {
                                    source.src = common.createAbsoluteUrl(source.src);
                                }
                                return source;
                            }
                        }
                    },

                    load: function (video) {
                        var init = !hls,
                            conf = player.conf,
                            hlsClientConf = extend({}, hlsconf),
                            hlsParams = ["autoLevelCapping", "startLevel", "strict"];

                        if (init) {
                            common.removeNode(common.findDirect("video", root)[0]
                                    || common.find(".fp-player > video", root)[0]);
                            videoTag = common.createElement("video", {
                                className: "fp-engine " + engineName + "-engine",
                                autoplay: conf.autoplay
                                    ? "autoplay"
                                    : false
                            });
                            videoTag.setAttribute("x-webkit-airplay", "allow");

                        } else {
                            hls.destroy();
                        }

                        bean.on(videoTag, "play", function () {
                            player.trigger('resume', [player]);
                        });
                        bean.on(videoTag, "pause", function () {
                            player.trigger('pause', [player]);
                        });
                        bean.on(videoTag, "timeupdate", function () {
                            player.trigger('progress', [player, videoTag.currentTime]);
                        });
                        bean.on(videoTag, "loadeddata", function () {
                            video = extend(video, {
                                duration: videoTag.duration,
                                seekable: videoTag.seekable.end(null),
                                width: videoTag.videoWidth,
                                height: videoTag.videoHeight,
                                url: videoTag.currentSrc
                            });
                            player.trigger('ready', [player, video]);
                        });
                        bean.on(videoTag, "seeked", function () {
                            player.trigger('seek', [player, videoTag.currentTime]);
                        });
                        bean.on(videoTag, "progress", function (e) {
                            var ct = videoTag.currentTime,
                                buffer = 0,
                                buffend,
                                buffered,
                                last,
                                i;

                            try {
                                buffered = videoTag.buffered;
                                last = buffered.length - 1;
                                buffend = 0;
                                // cycle through time ranges to obtain buffer
                                // nearest current time
                                if (ct) {
                                    for (i = last; i > -1; i -= 1) {
                                        buffend = buffered.end(i);

                                        if (buffend >= ct) {
                                            buffer = buffend;
                                        }
                                    }
                                }
                            } catch (ignored) {}

                            video.buffer = buffer;
                            player.trigger('buffer', [player, e]);
                        });
                        bean.on(videoTag, "ended", function () {
                            player.trigger('finish', [player]);
                        });
                        bean.on(videoTag, "volumechange", function () {
                            player.trigger('volume', [player, videoTag.volume]);
                        });

                        hlsParams.forEach(function (key) {
                            delete hlsClientConf[key];
                        });
                        hls = new Hls(hlsClientConf);

                        hlsParams.forEach(function (key) {
                            var value = hlsconf[key];

                            switch (key) {
                            case "autoLevelCapping":
                                if (value === false) {
                                    value = -1;
                                }
                                break;
                            case "startLevel":
                                switch (value) {
                                case "auto":
                                    value = -1;
                                    break;
                                case "firstLevel":
                                    value = undefined;
                                    break;
                                }
                                break;
                            }

                            if (value !== undefined) {
                                hls[key] = value;
                            }
                        });

                        hls.on(Hls.Events.ERROR, function (e, data) {
                            var fperr,
                                errobj = {};

                            if (data.fatal || hlsconf.strict) {
                                switch (data.type) {
                                case Hls.ErrorTypes.NETWORK_ERROR:
                                    if (data.frag && data.frag.url) {
                                        errobj.url = data.frag.url;
                                        fperr = 2;
                                    } else {
                                        fperr = 4;
                                    }
                                    break;
                                case Hls.ErrorTypes.MEDIA_ERROR:
                                    fperr = 3;
                                    break;
                                default:
                                    fperr = 5;
                                    break;
                                }
                                errobj.code = fperr;
                                if (fperr > 2) {
                                    errobj.video = extend(video, {
                                        src: video.src,
                                        url: data.url || video.src
                                    });
                                }
                                player.trigger('error', [player, errobj]);
                            }
                            /* TODO: */
                            // log non fatals
                        });

                        if (init) {
                            common.prepend(common.find(".fp-player", root)[0], videoTag);
                        }

                        hls.loadSource(video.src);
                        hls.attachVideo(videoTag);

                        if (videoTag.paused && (video.autoplay || conf.autoplay)) {
                            videoTag.play();
                        }
                    },

                    resume: function () {
                        videoTag.play();
                    },

                    pause: function () {
                        videoTag.pause();
                    },

                    seek: function (time) {
                        videoTag.currentTime = time;
                    },

                    volume: function (level) {
                        if (videoTag) {
                            videoTag.volume = level;
                        }
                    },

                    speed: function (val) {
                        videoTag.playbackRate = val;
                        player.trigger('speed', [player, val]);
                    },

                    unload: function () {
                        // hls conditional probably not needed once
                        // https://github.com/flowplayer/flowplayer/commit/871ff783a8f23aa603e1120f4319d4a892125b0a
                        // is released
                        if (hls) {
                            hls.destroy();
                            hls = 0;
                            bean.off(videoTag);
                            common.removeNode(videoTag);
                            videoTag = 0;
                        }
                    }
                };

            return engine;
        };

    if (Hls.isSupported() && version.indexOf("5.") !== 0) {
        // only load engine if it can be used
        engineImpl.engineName = engineName; // must be exposed
        engineImpl.canPlay = function (type, conf) {
            var IE11 = navigator.userAgent.indexOf("Trident/7") > -1;

            if (conf[engineName] === false || conf.clip[engineName] === false) {
                // engine disabled for player or clip
                return false;
            }

            // merge hlsjs clip config at earliest opportunity
            hlsconf = extend({}, flowplayer.conf[engineName], conf[engineName], conf.clip[engineName]);

            // support Safari only when hlsjs debugging
            // https://github.com/dailymotion/hls.js/issues/9
            return isHlsType(type) &&
                    (IE11 || !flowplayer.support.browser.safari || hlsconf.debug);
        };

        // put on top of engine stack
        // so hlsjs is tested before html5 video hls and flash hls
        flowplayer.engines.unshift(engineImpl);

        // poster hack
        flowplayer(function (api, root) {
            // detect poster condition as in core on boot
            var pre604 = /^6\.0\.[0-3]$/.test(version),
                conf = api.conf,
                bc = common.css(root, 'backgroundColor'),
                has_bg = common.css(root, 'backgroundImage') !== "none" ||
                        (bc && bc !== "rgba(0,0,0,0)" && bc !== "transparent"),
                posterCondition = has_bg && !conf.splash
                        && (!pre604 || (pre604 && !conf.autoplay)),

                posterHack = function (e) {
                    // assert that poster is set regardless of client of
                    // video loading delay
                    setTimeout(function () {
                        var posterClass = "is-poster";

                        if (!pre604) {
                            // must set this ourselves
                            api.poster = true;
                        }
                        if (!conf.autoplay || e.type === "stop") {
                            common.addClass(root, posterClass);
                            api.one("resume." + engineName, function () {
                                api.off("ready." + engineName);
                                common.removeClass(root, posterClass);
                            });
                        }
                    }, 0);
                };

            if (posterCondition) {
                api.on("ready." + engineName + " stop." + engineName, posterHack)
                    .one("seek." + engineName, posterHack);
            }
        });
    }

}.apply(null, (typeof module === 'object' && module.exports)
    ? [require('flowplayer'), require('hls.js')]
    : [window.flowplayer, window.Hls]));
<|endoftext|>


<commit_before>var siteBaseUrl = 'https://github.com/';
var repoBaseUrl = 'https://api.github.com/repos/';
var userBaseUrl = 'https://api.github.com/users/';

var Fetchable = Vue.extend({
  methods: {
    fetchData: function () {
      if (!this.apiUrl) return false;
      var xhr = new XMLHttpRequest(),
          self = this;
      xhr.open('GET', self.apiUrl);
      xhr.onload = function () {
        self.items = JSON.parse(xhr.responseText);
      };
      xhr.send();
    }
  }
});

Vue.component('github-repo-list', Fetchable.extend({
  computed: {
    apiUrl: function() {
      if (this.user) {
        var url = userBaseUrl + this.user + '/repos';
        return url;
      }
    }
  },
  created: function () {
    var self = this;
    this.$watch('user', function () {
      self.fetchData();
    });
  }
}));

Vue.component('github-branch-list', Fetchable.extend({
  computed: {
    apiUrl: function() {
      if (this.user && this.project) {
        var url = repoBaseUrl + this.user + '/' + this.project + '/branches';
        return url;
      }
    }
  },
  created: function () {
    var self = this;
    this.$watch('user', function () {
      if (this.project) {
        self.fetchData();
      }
    });
    this.$watch('project', function () {
      self.fetchData();
    });
  }
}));

Vue.component('github-commit-list', Fetchable.extend({
  computed: {
    apiUrl: function() {
      if (this.user && this.project) {
        var url = repoBaseUrl + this.user + '/' + this.project + '/commits?per_page=3&sha=' + (this.branch == 'master' ? '' : this.branch);
        return url;
      }
    }
  },
  created: function () {
    var self = this;
    this.$watch('user', function () {
      self.branch = 'master';
      self.fetchData();
    });
    this.$watch('project', function () {
      self.branch = 'master';
      self.fetchData();
    });
    this.$watch('branch', function () {
      self.fetchData();
    });
  }
}));

Vue.component('github-commit', {
  template: '#template-github-commit'
});

Vue.component('github-milestone-list', Fetchable.extend({
  template: '#template-github-milestone-list',
  computed: {
    apiUrl: function() {
      if (this.user && this.project) {
        var url = repoBaseUrl + this.user + '/' + this.project + '/milestones';
        return url;
      }
    },
    htmlUrl: function() {
      if (this.user && this.project) {
        var url = siteBaseUrl + this.user + '/' + this.project + '/issues/milestones';
        return url;
      }
    }
  },
  created: function () {
    var self = this;
    this.$watch('user', function () {
      self.fetchData();
    });
    this.$watch('project', function () {
      self.fetchData();
    });
  },
  methods: {
    toggleMilestone: function(e) {
      if (this.$parent.milestone == e.targetVM.$data) {
        this.$parent.milestone = {};
      } else {
        this.$parent.milestone = e.targetVM.$data;
      }
    }
  }
}));

Vue.component('github-issue-list', Fetchable.extend({
  template: '#template-github-issue-list',
  computed: {
    apiUrl: function() {
      if (this.user && this.project) {
        var url = repoBaseUrl + this.user + '/' + this.project + '/issues';
        if (this.milestone && this.milestone.number) {
          url += '?milestone=' + this.milestone.number;
        }
        return url;
      }
    },
    htmlUrl: function() {
      if (this.user && this.project) {
        var url = siteBaseUrl + this.user + '/' + this.project + '/issues';
        return url;
      }
    }
  },
  created: function () {
    var self = this;
    this.$watch('user', function () {
      self.fetchData();
    });
    this.$watch('project', function () {
      self.fetchData();
    });
    this.$watch('milestone', function () {
      self.fetchData();
    });
  },
  methods: {
    toggleActive: function(e) {
      if (e.targetVM.accordionOpen) {
        e.targetVM.accordionOpen = false;
      } else {
        e.targetVM.accordionOpen = true;
      }
    }
  },
  filters: {
    marked: marked,
    stripComments: function(v) {
      return v.replace(/<![\s\S]*?--[ \t\n\r]*>/g,'');
    }
  }
}));

Vue.component('vue-github', {
  data: {
    user: '',
    project: '',
    branch: '',
    milestone: {}
  },
  filters: {
    truncate: function (v) {
      var newline = v.indexOf('\n');
      return newline > -1 ? v.slice(0, newline) : v;
    },
    formatDate: function (v) {
      return v.replace(/T|Z/g, ' ');
    }
  }
});

var app = new Vue({
  el: '#vue-github'
});
<commit_msg>added checkbox icon output for todo lists<commit_after>var siteBaseUrl = 'https://github.com/';
var repoBaseUrl = 'https://api.github.com/repos/';
var userBaseUrl = 'https://api.github.com/users/';

var renderer = new marked.Renderer();
renderer.listitem = function(text) {
  if (/^\s*\[[x ]\]\s*/.test(text)) {
    text = text
      .replace(/^\s*\[ \]\s*/, ' ')
      .replace(/^\s*\[x\]\s*/, ' ');
    return '
' + text + '
';
  } else {
    return '
' + text + '
';
  }
};

var Fetchable = Vue.extend({
  methods: {
    fetchData: function () {
      if (!this.apiUrl) return false;
      var xhr = new XMLHttpRequest(),
          self = this;
      xhr.open('GET', self.apiUrl);
      xhr.onload = function () {
        self.items = JSON.parse(xhr.responseText);
      };
      xhr.send();
    }
  }
});

Vue.component('github-repo-list', Fetchable.extend({
  computed: {
    apiUrl: function() {
      if (this.user) {
        var url = userBaseUrl + this.user + '/repos';
        return url;
      }
    }
  },
  created: function () {
    var self = this;
    this.$watch('user', function () {
      self.fetchData();
    });
  }
}));

Vue.component('github-branch-list', Fetchable.extend({
  computed: {
    apiUrl: function() {
      if (this.user && this.project) {
        var url = repoBaseUrl + this.user + '/' + this.project + '/branches';
        return url;
      }
    }
  },
  created: function () {
    var self = this;
    this.$watch('user', function () {
      if (this.project) {
        self.fetchData();
      }
    });
    this.$watch('project', function () {
      self.fetchData();
    });
  }
}));

Vue.component('github-commit-list', Fetchable.extend({
  computed: {
    apiUrl: function() {
      if (this.user && this.project) {
        var url = repoBaseUrl + this.user + '/' + this.project + '/commits?per_page=3&sha=' + (this.branch == 'master' ? '' : this.branch);
        return url;
      }
    }
  },
  created: function () {
    var self = this;
    this.$watch('user', function () {
      self.branch = 'master';
      self.fetchData();
    });
    this.$watch('project', function () {
      self.branch = 'master';
      self.fetchData();
    });
    this.$watch('branch', function () {
      self.fetchData();
    });
  }
}));

Vue.component('github-commit', {
  template: '#template-github-commit'
});

Vue.component('github-milestone-list', Fetchable.extend({
  template: '#template-github-milestone-list',
  computed: {
    apiUrl: function() {
      if (this.user && this.project) {
        var url = repoBaseUrl + this.user + '/' + this.project + '/milestones';
        return url;
      }
    },
    htmlUrl: function() {
      if (this.user && this.project) {
        var url = siteBaseUrl + this.user + '/' + this.project + '/issues/milestones';
        return url;
      }
    }
  },
  created: function () {
    var self = this;
    this.$watch('user', function () {
      self.fetchData();
    });
    this.$watch('project', function () {
      self.fetchData();
    });
  },
  methods: {
    toggleMilestone: function(e) {
      if (this.$parent.milestone == e.targetVM.$data) {
        this.$parent.milestone = {};
      } else {
        this.$parent.milestone = e.targetVM.$data;
      }
    }
  }
}));

Vue.component('github-issue-list', Fetchable.extend({
  template: '#template-github-issue-list',
  computed: {
    apiUrl: function() {
      if (this.user && this.project) {
        var url = repoBaseUrl + this.user + '/' + this.project + '/issues';
        if (this.milestone && this.milestone.number) {
          url += '?milestone=' + this.milestone.number;
        }
        return url;
      }
    },
    htmlUrl: function() {
      if (this.user && this.project) {
        var url = siteBaseUrl + this.user + '/' + this.project + '/issues';
        return url;
      }
    }
  },
  created: function () {
    var self = this;
    this.$watch('user', function () {
      self.fetchData();
    });
    this.$watch('project', function () {
      self.fetchData();
    });
    this.$watch('milestone', function () {
      self.fetchData();
    });
  },
  methods: {
    toggleActive: function(e) {
      if (e.targetVM.accordionOpen) {
        e.targetVM.accordionOpen = false;
      } else {
        e.targetVM.accordionOpen = true;
      }
    }
  },
  filters: {
    marked: function(v) {
      return marked(v, {renderer: renderer});
    },
    stripComments: function(v) {
      return v.replace(/<![\s\S]*?--[ \t\n\r]*>/g,'');
    }
  }
}));

Vue.component('vue-github', {
  data: {
    user: '',
    project: '',
    branch: '',
    milestone: {}
  },
  filters: {
    truncate: function (v) {
      var newline = v.indexOf('\n');
      return newline > -1 ? v.slice(0, newline) : v;
    },
    formatDate: function (v) {
      return v.replace(/T|Z/g, ' ');
    }
  }
});

var app = new Vue({
  el: '#vue-github'
});
<|endoftext|>


<commit_before>import { Mongo } from 'meteor/mongo';
import { check } from 'meteor/check';

//Create Mongo collection for the messages
export const Conversations = new Mongo.Collection("conversations");
/*Current structure:
_id: Object ID
users: {
	ids: [user ids involved]
	usernames: [corresponding strings]
}
languages: [agreed conversation languages]
lastMessage: Date object of most recent messsage
name: name of conversation
*/

if (Meteor.isServer) {
  // This code only runs on the server
  // Only publish convos that belong to the current user

  Meteor.publish('convos', function convosPublication() {
    if (!this.userId) {
      return this.ready();
    }

    return Conversations.find({ "users.ids" : this.userId });
  });
}

Meteor.methods({
  'conversations.new'(userId, username) { //Method is being used temporarily
  	check(userId, String);
  	//check(username, String);

    //Make sure the user is logged in before sending
    if (! Meteor.userId()) {
      alert("Please sign in");
      throw new Meteor.Error("not-authorized");
    }

    //Insert into database
    Conversations.insert({
      users: {
      	ids: [Meteor.userId(), userId],
      	usernames: [Meteor.user().username, username]
      },
      languages: "eng",
      lastMessage: new Date(),
      name: ""
    });
  },
  'conversations.matchmake'() { //Method called when pressing the send button on a message
    //Make sure the user is logged in before matchmaking
    if (! Meteor.userId()) {
      alert("Please sign in");
      throw new Meteor.Error("not-authorized");
    }

    matchedUsers = Conversations.find({},{"users.ids" : 1}).map(function(item){ item.users.ids.shift(); return item.users.ids; })
    matchedUsers.push(Meteor.userId())

    const rand =  Math.floor(Math.random() * matchedUsers.length);
    console.error(rand)
    const randUser = Meteor.users.find({ $nin: matchedUsers }, {skip: rand, limit: -1})

    console.error(randUser._id)

    //Insert into database
    // Conversations.insert({
    //   users: {
    //     ids: [Meteor.userId(), userId],
    //     usernames: [Meteor.user().username, username]
    //   },
    //   languages: "eng",
    //   lastMessage: new Date(),
    //   name: ""
    // });
  },
});
<commit_msg>got the matchmaking working<commit_after>import { Mongo } from 'meteor/mongo';
import { check } from 'meteor/check';

//Create Mongo collection for the messages
export const Conversations = new Mongo.Collection("conversations");
/*Current structure:
_id: Object ID
users: {
	ids: [user ids involved]
	usernames: [corresponding strings]
}
languages: [agreed conversation languages]
lastMessage: Date object of most recent messsage
name: name of conversation
*/

if (Meteor.isServer) {
  // This code only runs on the server
  // Only publish convos that belong to the current user

  Meteor.publish('convos', function convosPublication() {
    if (!this.userId) {
      return this.ready();
    }

    return Conversations.find({ "users.ids" : this.userId });
  });
}

Meteor.methods({
  'conversations.new'(userId, username) { //Method is being used temporarily
  	check(userId, String);
  	//check(username, String);

    //Make sure the user is logged in before sending
    if (! Meteor.userId()) {
      alert("Please sign in");
      throw new Meteor.Error("not-authorized");
    }

    //Insert into database
    Conversations.insert({
      users: {
      	ids: [Meteor.userId(), userId],
      	usernames: [Meteor.user().username, username]
      },
      languages: "eng",
      lastMessage: new Date(),
      name: ""
    });
  },
  'conversations.matchmake'() { //Method called when pressing the send button on a message
    //Make sure the user is logged in before matchmaking
    if (! Meteor.userId()) {
      alert("Please sign in");
      throw new Meteor.Error("not-authorized");
    }

    matchedUsers = Conversations.find({},{"users.ids" : 1}).map(function(item){ item.users.ids.shift(); return item.users.ids; })
    matchedUsers.push(Meteor.userId())
    console.error(matchedUsers)

    length_unmactchedUsers = Meteor.users.find().count() - matchedUsers.length
    console.error(length_unmactchedUsers)

    const rand =  Math.floor(Math.random() * length_unmactchedUsers);
    console.error(rand)
    const randUser = Meteor.users.findOne({ "_id": { $nin: matchedUsers }}, {skip: rand})

    console.error(randUser._id)

    //Insert into database
    Conversations.insert({
      users: {
        ids: [Meteor.userId(), randUser._id],
        usernames: [Meteor.user().username, randUser.username]
      },
      languages: "eng",
      lastMessage: new Date(),
      name: ""
    });
  },
});
<|endoftext|>