<commit_before>/* @flow weak */

/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import {
  Image,
  View,
} from 'react-native';
import dismissKeyboard from 'dismissKeyboard'; // eslint-disable-line import/no-unresolved

import globalStyles, { BACKGROUND_COLOR } from './globalStyles';

import { Navigator } from './navigation';

import { PAGES, FINALISABLE_PAGES } from './pages';

import {
  FinaliseButton,
  FinaliseModal,
  LoginModal,
  SyncState,
} from './widgets';

import { Synchronizer } from './sync';
import { SyncAuthenticator, UserAuthenticator } from './authentication';
import { Database, schema, UIDatabase } from './database';
import { Scheduler } from './Scheduler';
import { Settings } from './settings';

const SYNC_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds
const AUTHENTICATION_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds

export default class mSupplyMobileApp extends React.Component {

  constructor() {
    super();
    const database = new Database(schema);
    this.database = new UIDatabase(database);
    this.settings = new Settings(this.database);
    this.userAuthenticator = new UserAuthenticator(this.database, this.settings);
    const syncAuthenticator = new SyncAuthenticator(this.database, this.settings);
    this.synchronizer = new Synchronizer(database, syncAuthenticator, this.settings);
    this.scheduler = new Scheduler();
    const initialised = this.synchronizer.isInitialised();
    this.state = {
      confirmFinalise: false,
      currentUser: null,
      initialised: initialised,
      isSyncing: false,
      syncError: '',
      lastSync: null, // Date of the last successful sync
      finaliseItem: null,
    };
  }

  componentWillMount() {
    this.logOut = this.logOut.bind(this);
    this.onAuthentication = this.onAuthentication.bind(this);
    this.onInitialised = this.onInitialised.bind(this);
    this.renderFinaliseButton = this.renderFinaliseButton.bind(this);
    this.renderScene = this.renderScene.bind(this);
    this.renderSyncState = this.renderSyncState.bind(this);
    this.synchronize = this.synchronize.bind(this);
    this.scheduler.schedule(this.synchronize,
                            SYNC_INTERVAL);
    this.scheduler.schedule(() => {
      if (this.state.currentUser !== null) { // Only reauthenticate if currently logged in
        this.userAuthenticator.reauthenticate(this.onAuthentication);
      }
    }, AUTHENTICATION_INTERVAL);
  }

  componentWillUnmount() {
    this.scheduler.clearAll();
  }

  onAuthentication(user) {
    this.setState({ currentUser: user });
  }

  onInitialised() {
    this.setState({ initialised: true });
  }

  async synchronize() {
    if (!this.state.initialised || this.state.isSyncing) return; // If already syncing, skip
    try {
      this.setState({ isSyncing: true });
      await this.synchronizer.synchronize();
      this.setState({
        isSyncing: false,
        syncError: '',
      });
    } catch (error) {
      this.setState({
        isSyncing: false,
        syncError: error.message,
      });
    }
  }

  logOut() {
    this.setState({ currentUser: null });
  }

  renderFinaliseButton() {
    return (
      <FinaliseButton
        isFinalised={this.state.finaliseItem.record.status === 'finalised'}
        onPress={() => this.setState({ confirmFinalise: true })}
      />);
  }

  renderLogo() {
    return (
      <Image
        resizeMode="contain"
        source={require('./images/logo.png')}
      />
    );
  }

  renderScene(props) {
    const navigateTo = (key, title, extraProps, navType) => {
      dismissKeyboard();
      if (!navType) navType = 'push';
      const navigationProps = { key, title, ...extraProps };
      // If the page we're going to has a key value pair in FINALISABLE_PAGES, get recordToFinalise
      // and recordType corresponding to that key. Set the new state and render the finalise Button
      if (FINALISABLE_PAGES[key]) {
        const { recordToFinaliseKey, ...finaliseItem } = FINALISABLE_PAGES[key];
        finaliseItem.record = extraProps[recordToFinaliseKey];
        this.setState({ finaliseItem: finaliseItem });
        navigationProps.renderRightComponent = this.renderFinaliseButton;
      }

      // Now navigate to the page, passing on any extra props and the finalise button if required
      props.onNavigate({ type: navType, ...navigationProps });
    };
    const { key, ...extraProps } = props.scene.route;
    const Page = PAGES[key]; // Get the page the navigation key relates to
    // Return the requested page with any extra props passed to navigateTo in pageProps
    return (
      <Page
        navigateTo={navigateTo}
        database={this.database}
        settings={this.settings}
        logOut={this.logOut}
        currentUser={this.state.currentUser}
        {...extraProps}
      />);
  }

  renderSyncState() {
    return (
      <SyncState
        isSyncing={this.state.isSyncing}
        syncError={this.state.syncError}
        settings={this.settings}
      />
    );
  }

  render() {
    if (!this.state.initialised) {
      const FirstUsePage = PAGES.firstUse;
      return (
        <FirstUsePage
          synchronizer={this.synchronizer}
          onInitialised={this.onInitialised}
        />
      );
    }
    return (
      <View style={globalStyles.appBackground}>
        <Navigator
          renderScene={this.renderScene}
          renderCentreComponent={this.renderLogo}
          renderRightComponent={this.renderSyncState}
          navBarStyle={globalStyles.navBarStyle}
          backgroundColor={BACKGROUND_COLOR}
        />
        <FinaliseModal
          database={this.database}
          isOpen={this.state.confirmFinalise}
          onClose={() => this.setState({ confirmFinalise: false })}
          finaliseItem={this.state.finaliseItem}
          user={this.state.currentUser}
        />
        <LoginModal
          authenticator={this.userAuthenticator}
          isAuthenticated={this.state.currentUser !== null}
          onAuthentication={this.onAuthentication}
        />
      </View>
    );
  }
}
<commit_msg>Update comment<commit_after>/* @flow weak */

/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import {
  Image,
  View,
} from 'react-native';
import dismissKeyboard from 'dismissKeyboard'; // eslint-disable-line import/no-unresolved

import globalStyles, { BACKGROUND_COLOR } from './globalStyles';

import { Navigator } from './navigation';

import { PAGES, FINALISABLE_PAGES } from './pages';

import {
  FinaliseButton,
  FinaliseModal,
  LoginModal,
  SyncState,
} from './widgets';

import { Synchronizer } from './sync';
import { SyncAuthenticator, UserAuthenticator } from './authentication';
import { Database, schema, UIDatabase } from './database';
import { Scheduler } from './Scheduler';
import { Settings } from './settings';

const SYNC_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds
const AUTHENTICATION_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds

export default class mSupplyMobileApp extends React.Component {

  constructor() {
    super();
    const database = new Database(schema);
    this.database = new UIDatabase(database);
    this.settings = new Settings(this.database);
    this.userAuthenticator = new UserAuthenticator(this.database, this.settings);
    const syncAuthenticator = new SyncAuthenticator(this.database, this.settings);
    this.synchronizer = new Synchronizer(database, syncAuthenticator, this.settings);
    this.scheduler = new Scheduler();
    const initialised = this.synchronizer.isInitialised();
    this.state = {
      confirmFinalise: false,
      currentUser: null,
      initialised: initialised,
      isSyncing: false,
      syncError: '',
      lastSync: null, // Date of the last successful sync
      finaliseItem: null,
    };
  }

  componentWillMount() {
    this.logOut = this.logOut.bind(this);
    this.onAuthentication = this.onAuthentication.bind(this);
    this.onInitialised = this.onInitialised.bind(this);
    this.renderFinaliseButton = this.renderFinaliseButton.bind(this);
    this.renderScene = this.renderScene.bind(this);
    this.renderSyncState = this.renderSyncState.bind(this);
    this.synchronize = this.synchronize.bind(this);
    this.scheduler.schedule(this.synchronize,
                            SYNC_INTERVAL);
    this.scheduler.schedule(() => {
      if (this.state.currentUser !== null) { // Only reauthenticate if currently logged in
        this.userAuthenticator.reauthenticate(this.onAuthentication);
      }
    }, AUTHENTICATION_INTERVAL);
  }

  componentWillUnmount() {
    this.scheduler.clearAll();
  }

  onAuthentication(user) {
    this.setState({ currentUser: user });
  }

  onInitialised() {
    this.setState({ initialised: true });
  }

  async synchronize() {
    if (!this.state.initialised || this.state.isSyncing) return; // If already syncing, skip
    try {
      this.setState({ isSyncing: true });
      await this.synchronizer.synchronize();
      this.setState({
        isSyncing: false,
        syncError: '',
      });
    } catch (error) {
      this.setState({
        isSyncing: false,
        syncError: error.message,
      });
    }
  }

  logOut() {
    this.setState({ currentUser: null });
  }

  renderFinaliseButton() {
    return (
      <FinaliseButton
        isFinalised={this.state.finaliseItem.record.status === 'finalised'}
        onPress={() => this.setState({ confirmFinalise: true })}
      />);
  }

  renderLogo() {
    return (
      <Image
        resizeMode="contain"
        source={require('./images/logo.png')}
      />
    );
  }

  renderScene(props) {
    const navigateTo = (key, title, extraProps, navType) => {
      dismissKeyboard();
      if (!navType) navType = 'push';
      const navigationProps = { key, title, ...extraProps };
      // If the page we're going to has a key value pair in FINALISABLE_PAGES, get the finaliseItem
      // details corresponding to that key. Set the new state and render the finalise Button
      if (FINALISABLE_PAGES[key]) {
        const { recordToFinaliseKey, ...finaliseItem } = FINALISABLE_PAGES[key];
        finaliseItem.record = extraProps[recordToFinaliseKey];
        this.setState({ finaliseItem: finaliseItem });
        navigationProps.renderRightComponent = this.renderFinaliseButton;
      }

      // Now navigate to the page, passing on any extra props and the finalise button if required
      props.onNavigate({ type: navType, ...navigationProps });
    };
    const { key, ...extraProps } = props.scene.route;
    const Page = PAGES[key]; // Get the page the navigation key relates to
    // Return the requested page with any extra props passed to navigateTo in pageProps
    return (
      <Page
        navigateTo={navigateTo}
        database={this.database}
        settings={this.settings}
        logOut={this.logOut}
        currentUser={this.state.currentUser}
        {...extraProps}
      />);
  }

  renderSyncState() {
    return (
      <SyncState
        isSyncing={this.state.isSyncing}
        syncError={this.state.syncError}
        settings={this.settings}
      />
    );
  }

  render() {
    if (!this.state.initialised) {
      const FirstUsePage = PAGES.firstUse;
      return (
        <FirstUsePage
          synchronizer={this.synchronizer}
          onInitialised={this.onInitialised}
        />
      );
    }
    return (
      <View style={globalStyles.appBackground}>
        <Navigator
          renderScene={this.renderScene}
          renderCentreComponent={this.renderLogo}
          renderRightComponent={this.renderSyncState}
          navBarStyle={globalStyles.navBarStyle}
          backgroundColor={BACKGROUND_COLOR}
        />
        <FinaliseModal
          database={this.database}
          isOpen={this.state.confirmFinalise}
          onClose={() => this.setState({ confirmFinalise: false })}
          finaliseItem={this.state.finaliseItem}
          user={this.state.currentUser}
        />
        <LoginModal
          authenticator={this.userAuthenticator}
          isAuthenticated={this.state.currentUser !== null}
          onAuthentication={this.onAuthentication}
        />
      </View>
    );
  }
}
<|endoftext|>


<commit_before>'use strict';

const uuidV4 = require('uuid/v4');

const config = require('../../config/lib/middleware/metadata-parse');

function getRequestIdFromReq(req) {
  const requestIdFromHeader = req.get(config.metadata.headers.requestId);
  const requestIdFromQuery = req.query[config.metadata.headers.requestId];
  return requestIdFromHeader || requestIdFromQuery || uuidV4();
}

function getRetryCountFromReq(req) {
  const retryCountFromHeader = Number(req.get(config.metadata.headers.retryCount)) || 0;
  const retryCountFromQuery = Number(req.query[config.metadata.headers.retryCount]) || 0;
  return retryCountFromHeader || retryCountFromQuery;
}

function registerIsARetryRequestFunction(req) {
  req.isARetryRequest = () => !!req.metadata.retryCount;
}

function getFailureInjectionTestIdFromReq(req) {
  const failureIdFromHeader = req.get(config.metadata.headers.failureInjectionTestId);
  const failureIdFromQuery = req.query[config.metadata.headers.failureInjectionTestId];
  return failureIdFromHeader || failureIdFromQuery || false;
}

function registerIsAFailureInjectionTestRequestFunction(req) {
  req.isAFailureInjectionTestRequest = () => !!req.metadata.failureInjectionTestId;
}

module.exports = {
  getRequestIdFromReq,
  getRetryCountFromReq,
  getFailureInjectionTestIdFromReq,
  registerIsARetryRequestFunction,
  registerIsAFailureInjectionTestRequestFunction,
};
<commit_msg>fixed inconsistent use of the metadata-parse config in the metadata helper<commit_after>'use strict';

const uuidV4 = require('uuid/v4');

const config = require('../../config/lib/middleware/metadata-parse');

function getRequestIdFromReq(req) {
  const requestIdFromHeader = req.get(config.metadata.headers.requestId);
  const requestIdFromQuery = req.query[config.metadata.headers.requestId];
  return requestIdFromHeader || requestIdFromQuery || uuidV4();
}

function getRetryCountFromReq(req) {
  const retryCountFromHeader = Number(req.get(config.metadata.headers.retryCount)) || 0;
  const retryCountFromQuery = Number(req.query[config.metadata.headers.retryCount]) || 0;
  return retryCountFromHeader || retryCountFromQuery;
}

function registerIsARetryRequestFunction(req) {
  req.isARetryRequest = () => !!req.metadata[config.metadata.keys.retryCount];
}

function getFailureInjectionTestIdFromReq(req) {
  const failureIdFromHeader = req.get(config.metadata.headers.failureInjectionTestId);
  const failureIdFromQuery = req.query[config.metadata.headers.failureInjectionTestId];
  return failureIdFromHeader || failureIdFromQuery || false;
}

function registerIsAFailureInjectionTestRequestFunction(req) {
  req.isAFailureInjectionTestRequest = () =>
    !!req.metadata[config.metadata.keys.failureInjectionTestId];
}

module.exports = {
  getRequestIdFromReq,
  getRetryCountFromReq,
  getFailureInjectionTestIdFromReq,
  registerIsARetryRequestFunction,
  registerIsAFailureInjectionTestRequestFunction,
};
<|endoftext|>


<commit_before>
const { app, BrowserWindow, Menu, Tray, dialog, nativeImage } = require('electron'); // eslint-disable-line
const path = require('path');
const debug = require('debug');
const { createMenu } = require('./main/menu');
const { installDevTools } = require('./main/devTools');
const Ipc = require('./main/ipc');
const { updateHandle } = require('./main/autoUpdate');

const log = debug('electron-react:main');
log('main process begins initialize');

let mainWindow = null;
const isDev = process.env.NODE_ENV === 'development';

if (!isDev) {
  const sourceMapSupport = require('source-map-support'); // eslint-disable-line
  sourceMapSupport.install();
}

if (isDev) {
  const path = require('path'); // eslint-disable-line
  const p = path.join(__dirname, '..', 'src', 'node_modules'); // eslint-disable-line
  require('module').globalPaths.push(p); // eslint-disable-line
}

const createWindow = () => {
  mainWindow = new BrowserWindow({
    show: false,
    width: 1024,
    height: 768,
    webPreferences: {
      // nodeIntegration: true,
      // webSecurity: true,
      preload: path.resolve(path.join(__dirname, '../resources/lib/preload.js'))
    },
  });

  if (isDev) {
    // eslint-disable-next-line no-console
    console.log('** loadURL: ', `file://${__dirname}/public/index.html`);
    mainWindow.loadURL(`file://${__dirname}/public/index.html`);
  } else {
    // eslint-disable-next-line no-console
    console.log('** loadURL: ', `file://${__dirname}/index.html`);
    mainWindow.loadURL(`file://${__dirname}/index.html`);
  }

  mainWindow.webContents.on('did-finish-load', () => {
    mainWindow.show();
    mainWindow.focus();
  });

  // if the render process crashes, reload the window
  win.webContents.on('crashed', () => {
    mainWindow.destroy();
    createWindow();
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  // await installExtensions();
  installDevTools(mainWindow);

  Menu.setApplicationMenu(createMenu(mainWindow));
  Ipc.init(mainWindow);
  updateHandle(mainWindow);
};

app.on('ready', createWindow);

app.on('activate', () => {
  // 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 (mainWindow === null) {
    createWindow();
  }
});

app.on('window-all-closed', () => {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') app.quit();
});
<commit_msg>feat: fix error when reload the window for the render process crashed<commit_after>
const { app, BrowserWindow, Menu, Tray, dialog, nativeImage } = require('electron'); // eslint-disable-line
const path = require('path');
const debug = require('debug');
const { createMenu } = require('./main/menu');
const { installDevTools } = require('./main/devTools');
const Ipc = require('./main/ipc');
const { updateHandle } = require('./main/autoUpdate');

const log = debug('electron-react:main');
log('main process begins initialize');

let mainWindow = null;
const isDev = process.env.NODE_ENV === 'development';

if (!isDev) {
  const sourceMapSupport = require('source-map-support'); // eslint-disable-line
  sourceMapSupport.install();
}

if (isDev) {
  const path = require('path'); // eslint-disable-line
  const p = path.join(__dirname, '..', 'src', 'node_modules'); // eslint-disable-line
  require('module').globalPaths.push(p); // eslint-disable-line
}

const createWindow = () => {
  mainWindow = new BrowserWindow({
    show: false,
    width: 1024,
    height: 768,
    webPreferences: {
      // nodeIntegration: true,
      // webSecurity: true,
      preload: path.resolve(path.join(__dirname, '../resources/lib/preload.js'))
    },
  });

  if (isDev) {
    // eslint-disable-next-line no-console
    console.log('** loadURL: ', `file://${__dirname}/public/index.html`);
    mainWindow.loadURL(`file://${__dirname}/public/index.html`);
  } else {
    // eslint-disable-next-line no-console
    console.log('** loadURL: ', `file://${__dirname}/index.html`);
    mainWindow.loadURL(`file://${__dirname}/index.html`);
  }

  mainWindow.webContents.on('did-finish-load', () => {
    mainWindow.show();
    mainWindow.focus();
  });

  // if the render process crashes, reload the window
  mainWindow.webContents.on('crashed', () => {
    mainWindow.destroy();
    createWindow();
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  // await installExtensions();
  installDevTools(mainWindow);

  Menu.setApplicationMenu(createMenu(mainWindow));
  Ipc.init(mainWindow);
  updateHandle(mainWindow);
};

app.on('ready', createWindow);

app.on('activate', () => {
  // 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 (mainWindow === null) {
    createWindow();
  }
});

app.on('window-all-closed', () => {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') app.quit();
});
<|endoftext|>


<commit_before>'use strict';
require('es6-promise').polyfill();

module.exports = function (fetch, defaults = {}) {
  if (typeof fetch !== 'function') {
    throw new ArgumentError('fetch must be a function');
  }

  if (typeof defaults !== 'object') {
    throw new ArgumentError('defaults must be an object');
  }

  if (defaults.retries !== undefined && !isPositiveInteger(defaults.retries)) {
    throw new ArgumentError('retries must be a positive integer');
  }

  if (defaults.retryDelay !== undefined && !isPositiveInteger(defaults.retryDelay) && typeof defaults.retryDelay !== 'function') {
    throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
  }

  if (defaults.retryOn !== undefined && !Array.isArray(defaults.retryOn) && typeof defaults.retryOn !== 'function') {
    throw new ArgumentError('retryOn property expects an array or function');
  }

  defaults = {...{
    retries: 3,
    retryDelay: 1000,
    retryOn: [],
  }, ...defaults}

  return function fetchRetry(input, init) {
    var retries = defaults.retries;
    var retryDelay = defaults.retryDelay;
    var retryOn = defaults.retryOn;

    if (init && init.retries !== undefined) {
      if (isPositiveInteger(init.retries)) {
        retries = init.retries;
      } else {
        throw new ArgumentError('retries must be a positive integer');
      }
    }

    if (init && init.retryDelay !== undefined) {
      if (isPositiveInteger(init.retryDelay) || (typeof init.retryDelay === 'function')) {
        retryDelay = init.retryDelay;
      } else {
        throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
      }
    }

    if (init && init.retryOn) {
      if (Array.isArray(init.retryOn) || (typeof init.retryOn === 'function')) {
        retryOn = init.retryOn;
      } else {
        throw new ArgumentError('retryOn property expects an array or function');
      }
    }

    return new Promise(function (resolve, reject) {
      var wrappedFetch = function (attempt) {
        fetch(input, init)
          .then(function (response) {
            if (Array.isArray(retryOn) && retryOn.indexOf(response.status) === -1) {
              resolve(response);
            } else if (typeof retryOn === 'function') {
              if (retryOn(attempt, null, response)) {
                retry(attempt, null, response);
              } else {
                resolve(response);
              }
            } else {
              if (attempt < retries) {
                retry(attempt, null, response);
              } else {
                resolve(response);
              }
            }
          })
          .catch(function (error) {
            if (typeof retryOn === 'function') {
              if (retryOn(attempt, error, null)) {
                retry(attempt, error, null);
              } else {
                reject(error);
              }
            } else if (attempt < retries) {
              retry(attempt, error, null);
            } else {
              reject(error);
            }
          });
      };

      function retry(attempt, error, response) {
        var delay = (typeof retryDelay === 'function') ?
          retryDelay(attempt, error, response) : retryDelay;
        setTimeout(function () {
          wrappedFetch(++attempt);
        }, delay);
      }

      wrappedFetch(0);
    });
  };
};

function isPositiveInteger(value) {
  return Number.isInteger(value) && value >= 0;
}

function ArgumentError(message) {
  this.name = 'ArgumentError';
  this.message = message;
}
<commit_msg>Replaces object spread syntax with Object.assign() for better browser support<commit_after>'use strict';
require('es6-promise').polyfill();

module.exports = function (fetch, defaults = {}) {
  if (typeof fetch !== 'function') {
    throw new ArgumentError('fetch must be a function');
  }

  if (typeof defaults !== 'object') {
    throw new ArgumentError('defaults must be an object');
  }

  if (defaults.retries !== undefined && !isPositiveInteger(defaults.retries)) {
    throw new ArgumentError('retries must be a positive integer');
  }

  if (defaults.retryDelay !== undefined && !isPositiveInteger(defaults.retryDelay) && typeof defaults.retryDelay !== 'function') {
    throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
  }

  if (defaults.retryOn !== undefined && !Array.isArray(defaults.retryOn) && typeof defaults.retryOn !== 'function') {
    throw new ArgumentError('retryOn property expects an array or function');
  }

  const baseDefaults = {
    retries: 3,
    retryDelay: 1000,
    retryOn: [],
  };

  defaults = Object.assign(baseDefaults, defaults);

  return function fetchRetry(input, init) {
    var retries = defaults.retries;
    var retryDelay = defaults.retryDelay;
    var retryOn = defaults.retryOn;

    if (init && init.retries !== undefined) {
      if (isPositiveInteger(init.retries)) {
        retries = init.retries;
      } else {
        throw new ArgumentError('retries must be a positive integer');
      }
    }

    if (init && init.retryDelay !== undefined) {
      if (isPositiveInteger(init.retryDelay) || (typeof init.retryDelay === 'function')) {
        retryDelay = init.retryDelay;
      } else {
        throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
      }
    }

    if (init && init.retryOn) {
      if (Array.isArray(init.retryOn) || (typeof init.retryOn === 'function')) {
        retryOn = init.retryOn;
      } else {
        throw new ArgumentError('retryOn property expects an array or function');
      }
    }

    return new Promise(function (resolve, reject) {
      var wrappedFetch = function (attempt) {
        fetch(input, init)
          .then(function (response) {
            if (Array.isArray(retryOn) && retryOn.indexOf(response.status) === -1) {
              resolve(response);
            } else if (typeof retryOn === 'function') {
              if (retryOn(attempt, null, response)) {
                retry(attempt, null, response);
              } else {
                resolve(response);
              }
            } else {
              if (attempt < retries) {
                retry(attempt, null, response);
              } else {
                resolve(response);
              }
            }
          })
          .catch(function (error) {
            if (typeof retryOn === 'function') {
              if (retryOn(attempt, error, null)) {
                retry(attempt, error, null);
              } else {
                reject(error);
              }
            } else if (attempt < retries) {
              retry(attempt, error, null);
            } else {
              reject(error);
            }
          });
      };

      function retry(attempt, error, response) {
        var delay = (typeof retryDelay === 'function') ?
          retryDelay(attempt, error, response) : retryDelay;
        setTimeout(function () {
          wrappedFetch(++attempt);
        }, delay);
      }

      wrappedFetch(0);
    });
  };
};

function isPositiveInteger(value) {
  return Number.isInteger(value) && value >= 0;
}

function ArgumentError(message) {
  this.name = 'ArgumentError';
  this.message = message;
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Base database service provider.
 *
 * @author kyawtun@yathit.com (Kyaw Tun)
 */

goog.provide('ydn.db.tr.Storage');
goog.require('ydn.db.con.Storage');
goog.require('ydn.db.tr.AtomicParallel');
goog.require('ydn.db.tr.AtomicSerial');
goog.require('ydn.db.tr.DbOperator');
goog.require('ydn.db.tr.IStorage');
goog.require('ydn.db.tr.OverflowSerial');
goog.require('ydn.db.tr.Parallel');
goog.require('ydn.db.tr.Serial');
goog.require('ydn.db.tr.StrictOverflowSerial');

/**
 * Create storage providing method to run in transaction.
 *
 * @param {string=} opt_dbname database name.
 * @param {!ydn.db.schema.Database|DatabaseSchema=} opt_schema database schema
 * or its configuration in JSON format. If not provided, default empty schema
 * is used.
 * schema used in chronical order.
 * @param {!StorageOptions=} opt_options options.
 * @implements {ydn.db.tr.IStorage}
 * @extends {ydn.db.con.Storage}
 * @constructor
 */
ydn.db.tr.Storage = function(opt_dbname, opt_schema, opt_options) {
  goog.base(this, opt_dbname, opt_schema, opt_options);

  this.ptx_no = 0;

  var is_serial = true;
  var req_type = ydn.db.tr.IThread.Policy.SINGLE;
  if (opt_options) {
    if (goog.isDef(opt_options.isSerial)) {
      is_serial = !!opt_options.isSerial;
    }
    if (opt_options.policy) {
      req_type = /** @type {ydn.db.tr.IThread.Policy} */
          (opt_options.policy);
    }
  }

  var tx_thread = this.newTxQueue(req_type, is_serial);

  /**
   * here we must define sync thread first, so that it is ready when
   * executing main thread.
   * @final
   */
  this.sync_thread = ydn.db.base.USE_HOOK ?
      this.newTxQueue(ydn.db.tr.IThread.Policy.ATOMIC, false) : null;

  /**
   * main thread.
   * @final
   */
  this.db_operator = this.newOperator(tx_thread, this.sync_thread);

};
goog.inherits(ydn.db.tr.Storage, ydn.db.con.Storage);

/**
 * @type {ydn.db.tr.IThread}
 * @protected
 */
ydn.db.tr.Storage.prototype.sync_thread;

/**
 * @type {ydn.db.tr.DbOperator}
 * @protected
 */
ydn.db.tr.Storage.prototype.db_operator;

/**
 *
 * @type {number}
 * @protected
 */
ydn.db.tr.Storage.prototype.ptx_no = 0;

/**
 * Create a new db operator.
 * @param {ydn.db.tr.IThread.Policy} request_type thread policy.
 * @param {boolean=} opt_is_serial serial request.
 * @param {!Array.<string>=} opt_store_names store names for tx scope.
 * @param {ydn.db.base.StandardTransactionMode=} opt_mode tx mode.
 * @param {number=} opt_max_tx limit number of transaction.
 * @return {ydn.db.tr.DbOperator} db operator.
 * @final
 */
ydn.db.tr.Storage.prototype.branch = function(request_type, opt_is_serial,
    opt_store_names, opt_mode, opt_max_tx) {

  var mode;
  if (opt_mode == ydn.db.base.StandardTransactionMode.READ_ONLY) {
    mode = ydn.db.base.TransactionMode.READ_ONLY;
  } else if (opt_mode == ydn.db.base.StandardTransactionMode.READ_WRITE) {
    mode = ydn.db.base.TransactionMode.READ_WRITE;
  }

  var tx_thread = this.newTxQueue(request_type, opt_is_serial,
      opt_store_names, mode, opt_max_tx);
  return this.newOperator(tx_thread, this.sync_thread);
};

/**
 * @final
 * @return {number} transaction series number.
 */
ydn.db.tr.Storage.prototype.getTxNo = function() {
  return this.db_operator ? this.db_operator.getTxNo() : NaN;
};

/**
 * @param {!ydn.db.tr.IThread} tx_thread transaction thread.
 * @param {ydn.db.tr.IThread} sync_thread thread for synchronization.
 * @return {ydn.db.tr.DbOperator} the db operator.
 * @protected
 */
ydn.db.tr.Storage.prototype.newOperator = function(tx_thread, sync_thread) {
  return new ydn.db.tr.DbOperator(this, this.schema,
      tx_thread, sync_thread);
};

/**
 * Create a new thread queue.
 * @param {ydn.db.tr.IThread.Policy} request_type thread policy.
 * @param {boolean=} opt_is_serial serial request.
 * @param {!Array.<string>=} opt_store_names store names as scope.
 * @param {ydn.db.base.TransactionMode=} opt_mode mode as scope.
 * @param {number=} opt_max_tx limit number of transaction.
 * @return {!ydn.db.tr.IThread} new transactional storage.
*/
ydn.db.tr.Storage.prototype.newTxQueue = function(request_type, opt_is_serial,
    opt_store_names, opt_mode, opt_max_tx) {

  if (opt_is_serial) {
    if (request_type == ydn.db.tr.IThread.Policy.MULTI) {
      return new ydn.db.tr.OverflowSerial(this, this.ptx_no++);
    } else if (request_type == ydn.db.tr.IThread.Policy.REPEAT) {
      return new ydn.db.tr.StrictOverflowSerial(this, this.ptx_no++);
    } else if (request_type == ydn.db.tr.IThread.Policy.ATOMIC) {
      return new ydn.db.tr.AtomicSerial(this, this.ptx_no++);
    } else if (request_type == ydn.db.tr.IThread.Policy.SINGLE) {
      return new ydn.db.tr.Serial(this, this.ptx_no++, opt_max_tx);
    } else {
      throw new ydn.debug.error.ArgumentException('Invalid requestType "' +
          request_type + '"');
    }
  } else {
    if (request_type == ydn.db.tr.IThread.Policy.MULTI ||
        request_type == ydn.db.tr.IThread.Policy.REPEAT ||
        request_type == ydn.db.tr.IThread.Policy.ALL ||
        request_type == ydn.db.tr.IThread.Policy.SINGLE) {
      return new ydn.db.tr.Parallel(this, this.ptx_no++, request_type,
          opt_store_names, opt_mode, opt_max_tx);
    } else if (request_type == ydn.db.tr.IThread.Policy.ATOMIC) {
      return new ydn.db.tr.AtomicParallel(this, this.ptx_no++);
    } else {
      throw new ydn.debug.error.ArgumentException('Invalid requestType "' +
          request_type + '"');
    }
  }
};

/**
 * Abort current request transaction.
 */
ydn.db.tr.Storage.prototype.abort = function() {
  this.db_operator.abort();
};

/**
 * @inheritDoc
 */
ydn.db.tr.Storage.prototype.run = function(trFn, store_names, opt_mode,
                                           oncompleted, opt_args) {

  var me = this;
  this.ptx_no++;

  var mode = ydn.db.base.TransactionMode.READ_ONLY;
  if (opt_mode) {
    if (opt_mode == ydn.db.base.StandardTransactionMode.READ_WRITE) {
      mode = ydn.db.base.TransactionMode.READ_WRITE;
    } else if (opt_mode != ydn.db.base.StandardTransactionMode.READ_ONLY) {
      throw new ydn.debug.error.ArgumentException('Invalid transaction mode "' +
          opt_mode + '"');
    }
  }

  var tx_thread = this.newTxQueue(ydn.db.tr.IThread.Policy.ALL, false,
      store_names, mode, 1);
  var db_operator = this.newOperator(tx_thread, this.sync_thread);

  if (!goog.isDefAndNotNull(store_names)) {
    store_names = this.schema.getStoreNames();
  }
  if (goog.DEBUG) {
    if (!goog.isArrayLike(store_names)) { // could be  DOMStringList or Array
      throw new ydn.debug.error.ArgumentException(
          'store names must be an array');
    } else if (store_names.length == 0) {
      throw new ydn.debug.error.ArgumentException(
          'number of store names must more than 0');
    } else {
      for (var i = 0; i < store_names.length; i++) {
        if (!goog.isString(store_names[i])) {
          throw new ydn.debug.error.ArgumentException('store name at ' + i +
              ' must be string but found ' + typeof store_names[i]);
        }
      }
    }
  }

  var outFn = trFn;
  if (arguments.length > 4) { // handle optional parameters
    var args = Array.prototype.slice.call(arguments, 4);
    outFn = function() {
      var newArgs = Array.prototype.slice.call(arguments);
      newArgs = newArgs.concat(args); // post-apply
      return trFn.apply(this, newArgs);
    };
  }

  this.logger.finest('scheduling run in transaction with ' + tx_thread);
  // outFn(/** @type {!ydn.db.tr.IStorage} */ (db_operator));

  tx_thread.processTx(function(tx) {
    me.logger.finest('executing run in transaction on ' + tx_thread);
    outFn(/** @type {!ydn.db.tr.IStorage} */ (db_operator));
    outFn = null;
  }, store_names, mode, oncompleted);

};

<commit_msg>add deferred with progress<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Base database service provider.
 *
 * @author kyawtun@yathit.com (Kyaw Tun)
 */

goog.provide('ydn.db.tr.Storage');
goog.require('ydn.db.con.Storage');
goog.require('ydn.db.tr.AtomicParallel');
goog.require('ydn.db.tr.AtomicSerial');
goog.require('ydn.db.tr.DbOperator');
goog.require('ydn.db.tr.IStorage');
goog.require('ydn.db.tr.OverflowSerial');
goog.require('ydn.db.tr.Parallel');
goog.require('ydn.db.tr.Serial');
goog.require('ydn.db.tr.StrictOverflowSerial');

/**
 * Create storage providing method to run in transaction.
 *
 * @param {string=} opt_dbname database name.
 * @param {!ydn.db.schema.Database|DatabaseSchema=} opt_schema database schema
 * or its configuration in JSON format. If not provided, default empty schema
 * is used.
 * schema used in chronical order.
 * @param {!StorageOptions=} opt_options options.
 * @implements {ydn.db.tr.IStorage}
 * @extends {ydn.db.con.Storage}
 * @constructor
 */
ydn.db.tr.Storage = function(opt_dbname, opt_schema, opt_options) {
  goog.base(this, opt_dbname, opt_schema, opt_options);

  this.ptx_no = 0;

  var is_serial = true;
  var req_type = ydn.db.tr.IThread.Policy.SINGLE;
  if (opt_options) {
    if (goog.isDef(opt_options.isSerial)) {
      is_serial = !!opt_options.isSerial;
    }
    if (opt_options.policy) {
      req_type = /** @type {ydn.db.tr.IThread.Policy} */
          (opt_options.policy);
    }
  }

  var tx_thread = this.newTxQueue(req_type, is_serial);

  /**
   * here we must define sync thread first, so that it is ready when
   * executing main thread.
   * @final
   */
  this.sync_thread = ydn.db.base.USE_HOOK ?
      this.newTxQueue(ydn.db.tr.IThread.Policy.ATOMIC, false) : null;

  /**
   * main thread.
   * @final
   */
  this.db_operator = this.newOperator(tx_thread, tx_thread);

};
goog.inherits(ydn.db.tr.Storage, ydn.db.con.Storage);

/**
 * @type {ydn.db.tr.IThread}
 * @protected
 */
ydn.db.tr.Storage.prototype.sync_thread;

/**
 * @type {ydn.db.tr.DbOperator}
 * @protected
 */
ydn.db.tr.Storage.prototype.db_operator;

/**
 *
 * @type {number}
 * @protected
 */
ydn.db.tr.Storage.prototype.ptx_no = 0;

/**
 * Create a new db operator.
 * @param {ydn.db.tr.IThread.Policy} request_type thread policy.
 * @param {boolean=} opt_is_serial serial request.
 * @param {!Array.<string>=} opt_store_names store names for tx scope.
 * @param {ydn.db.base.StandardTransactionMode=} opt_mode tx mode.
 * @param {number=} opt_max_tx limit number of transaction.
 * @return {ydn.db.tr.DbOperator} db operator.
 * @final
 */
ydn.db.tr.Storage.prototype.branch = function(request_type, opt_is_serial,
    opt_store_names, opt_mode, opt_max_tx) {

  var mode;
  if (opt_mode == ydn.db.base.StandardTransactionMode.READ_ONLY) {
    mode = ydn.db.base.TransactionMode.READ_ONLY;
  } else if (opt_mode == ydn.db.base.StandardTransactionMode.READ_WRITE) {
    mode = ydn.db.base.TransactionMode.READ_WRITE;
  }

  var tx_thread = this.newTxQueue(request_type, opt_is_serial,
      opt_store_names, mode, opt_max_tx);
  return this.newOperator(tx_thread, this.sync_thread);
};

/**
 * @final
 * @return {number} transaction series number.
 */
ydn.db.tr.Storage.prototype.getTxNo = function() {
  return this.db_operator ? this.db_operator.getTxNo() : NaN;
};

/**
 * @param {!ydn.db.tr.IThread} tx_thread transaction thread.
 * @param {ydn.db.tr.IThread} sync_thread thread for synchronization.
 * @return {ydn.db.tr.DbOperator} the db operator.
 * @protected
 */
ydn.db.tr.Storage.prototype.newOperator = function(tx_thread, sync_thread) {
  return new ydn.db.tr.DbOperator(this, this.schema,
      tx_thread, sync_thread);
};

/**
 * Create a new thread queue.
 * @param {ydn.db.tr.IThread.Policy} request_type thread policy.
 * @param {boolean=} opt_is_serial serial request.
 * @param {!Array.<string>=} opt_store_names store names as scope.
 * @param {ydn.db.base.TransactionMode=} opt_mode mode as scope.
 * @param {number=} opt_max_tx limit number of transaction.
 * @return {!ydn.db.tr.IThread} new transactional storage.
*/
ydn.db.tr.Storage.prototype.newTxQueue = function(request_type, opt_is_serial,
    opt_store_names, opt_mode, opt_max_tx) {

  if (opt_is_serial) {
    if (request_type == ydn.db.tr.IThread.Policy.MULTI) {
      return new ydn.db.tr.OverflowSerial(this, this.ptx_no++);
    } else if (request_type == ydn.db.tr.IThread.Policy.REPEAT) {
      return new ydn.db.tr.StrictOverflowSerial(this, this.ptx_no++);
    } else if (request_type == ydn.db.tr.IThread.Policy.ATOMIC) {
      return new ydn.db.tr.AtomicSerial(this, this.ptx_no++);
    } else if (request_type == ydn.db.tr.IThread.Policy.SINGLE) {
      return new ydn.db.tr.Serial(this, this.ptx_no++, opt_max_tx);
    } else {
      throw new ydn.debug.error.ArgumentException('Invalid requestType "' +
          request_type + '"');
    }
  } else {
    if (request_type == ydn.db.tr.IThread.Policy.MULTI ||
        request_type == ydn.db.tr.IThread.Policy.REPEAT ||
        request_type == ydn.db.tr.IThread.Policy.ALL ||
        request_type == ydn.db.tr.IThread.Policy.SINGLE) {
      return new ydn.db.tr.Parallel(this, this.ptx_no++, request_type,
          opt_store_names, opt_mode, opt_max_tx);
    } else if (request_type == ydn.db.tr.IThread.Policy.ATOMIC) {
      return new ydn.db.tr.AtomicParallel(this, this.ptx_no++);
    } else {
      throw new ydn.debug.error.ArgumentException('Invalid requestType "' +
          request_type + '"');
    }
  }
};

/**
 * Abort current request transaction.
 */
ydn.db.tr.Storage.prototype.abort = function() {
  this.db_operator.abort();
};

/**
 * @inheritDoc
 */
ydn.db.tr.Storage.prototype.run = function(trFn, store_names, opt_mode,
                                           oncompleted, opt_args) {

  var me = this;
  this.ptx_no++;

  var mode = ydn.db.base.TransactionMode.READ_ONLY;
  if (opt_mode) {
    if (opt_mode == ydn.db.base.StandardTransactionMode.READ_WRITE) {
      mode = ydn.db.base.TransactionMode.READ_WRITE;
    } else if (opt_mode != ydn.db.base.StandardTransactionMode.READ_ONLY) {
      throw new ydn.debug.error.ArgumentException('Invalid transaction mode "' +
          opt_mode + '"');
    }
  }

  var tx_thread = this.newTxQueue(ydn.db.tr.IThread.Policy.ALL, false,
      store_names, mode, 1);
  var db_operator = this.newOperator(tx_thread, this.sync_thread);

  if (!goog.isDefAndNotNull(store_names)) {
    store_names = this.schema.getStoreNames();
  }
  if (goog.DEBUG) {
    if (!goog.isArrayLike(store_names)) { // could be  DOMStringList or Array
      throw new ydn.debug.error.ArgumentException(
          'store names must be an array');
    } else if (store_names.length == 0) {
      throw new ydn.debug.error.ArgumentException(
          'number of store names must more than 0');
    } else {
      for (var i = 0; i < store_names.length; i++) {
        if (!goog.isString(store_names[i])) {
          throw new ydn.debug.error.ArgumentException('store name at ' + i +
              ' must be string but found ' + typeof store_names[i]);
        }
      }
    }
  }

  var outFn = trFn;
  if (arguments.length > 4) { // handle optional parameters
    var args = Array.prototype.slice.call(arguments, 4);
    outFn = function() {
      var newArgs = Array.prototype.slice.call(arguments);
      newArgs = newArgs.concat(args); // post-apply
      return trFn.apply(this, newArgs);
    };
  }

  this.logger.finest('scheduling run in transaction with ' + tx_thread);
  // outFn(/** @type {!ydn.db.tr.IStorage} */ (db_operator));

  tx_thread.processTx(function(tx) {
    me.logger.finest('executing run in transaction on ' + tx_thread);
    outFn(/** @type {!ydn.db.tr.IStorage} */ (db_operator));
    outFn = null;
  }, store_names, mode, oncompleted);

};

<|endoftext|>


<commit_before>/*
Copyright [2009-2014] EMBL-European Bioinformatics Institute
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
     http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var xrefLoader = function(upi) {
	this.upi = upi;

	this.config = {
		dom: {
			xref_table_container: '#xrefs-table-div',
			xref_table: '#xrefs-table',
			xref_loading_container: '#xrefs-loading',
			xref_msg: '#xrefs-loading-msg',
			hopscotch_tour: '.tour',
			downloads: '#download-formats'
		},
		templates: {
			delay_msg: '#handlebars-loading-info-tmpl',
			loading_error_msg: '#handlebars-loading-error-tmpl',
		}
	};

	this.enable_genomic_features = false;
};

xrefLoader.prototype.load_xrefs = function() {

	obj = this;
	set_xref_timer();
	get_xrefs();

	function set_xref_timer() {
		// show an info message if xrefs are taking too long to load
		var target = $(obj.config.dom.xref_msg),
				     delay_template = $(obj.config.templates.delay_msg),
		             delay = 5000;

		var timer = setTimeout(function() {
			// do not update the message if there was an error
			if (target.html().indexOf("alert-danger") != -1) {
				return;
			}
			var msg = Handlebars.compile(delay_template.html());
			target.append(msg).slideDown();
		}, delay);
	};

	function get_xrefs() {
		var url = '/rna/' + obj.upi + '/xrefs';
    	$.get(url, function(data){
        	$(obj.config.dom.xref_table_container).html(data);
			obj.enable_genomic_features = data.indexOf('View genomic location') > 0;
      	}).fail(function() {
      		show_error();
      	}).done(function(){
      		display_xrefs();
      	});
    };

	function show_error() {
		var error_template = $(obj.config.templates.loading_error_msg);
		var target = $(obj.config.dom.xref_msg);
		var msg = Handlebars.compile(error_template.html());
		target.hide().html(msg).fadeIn();
	};

	function display_xrefs(upi) {
		var oTable = {};

		launch_dataTables();
		show_dataTables();
  		enable_sorting();
  		enable_url_filering();
  		append_download_links();
  		enable_hopscotch_genomic_tour();

		function launch_dataTables() {
			oTable = $(obj.config.dom.xref_table).dataTable(
				{
					"aoColumns": [null, null, null, {"bVisible": false}, {"bVisible": false}], // hide columns, but keep them sortable
					"bAutoWidth": true, // pre-recalculate column widths
					"sDom": "ftpil", // filter, table, pagination, information, length
					"iDisplayLength": 5, // show 5 entries by default
					"sPaginationType": "bootstrap", // requires dataTables.bootstrap.js
					"bDeferRender": true, // defer rendering until necessary
					"oLanguage": {
					"sSearch": "", // don't display the "Search:" bit
					"sInfo": "_START_-_END_ of _TOTAL_", // change the informational text
					"oPaginate": {
						"sNext": "",
						"sPrevious": "",
					},
				},
				"aLengthMenu": [[5, 10, 20, 50, -1], [5, 10, 20, 50, "All"]],
				"fnInitComplete": function(oSettings, json) {
					adjust_dataTables_controls();
				},
			});

			function adjust_dataTables_controls() {
				$('.dataTables_filter input').attr('placeholder', 'Filter table').
				                              attr("tabindex", 2).
				                              attr('type', 'search').
				                              addClass('form-control input-sm');
				$('#xrefs-table_filter').appendTo('#xrefs-datatables-filter').
				                         addClass('pull-right hidden-xs');
				$('#xrefs-table_info').appendTo('#xrefs-datatables-counter');
				// hide pagination controls for tables with one page
				if ( $('.dataTables_paginate').find('li').length == 3 ) { // 3 elements: <-, 1, ->
					$('.dataTables_paginate').hide();
					$('#xrefs-table_length').hide();
				} else {
					$('.dataTables_paginate').addClass('pull-left').
					                          appendTo('.xref-datatables-controls');
					$('#xrefs-table_length').addClass('pull-right text-muted small').
					                         appendTo('.xref-datatables-controls');
				}
				$('.table th').css('padding-right','1.5em');
			};
		};

		function show_dataTables() {
			$(obj.config.dom.xref_loading_container).slideUp();
			$(obj.config.dom.xref_table).fadeIn();
		}

		function enable_sorting() {
			oTable.fnSortListener( document.getElementById('sort-by-first-seen'), 3);
			oTable.fnSortListener( document.getElementById('sort-by-last-seen'), 4);
		};

		function enable_url_filering() {
			// monitor the xref datatables search field to update the hashtag
			var dataTables_search = $('#xrefs-table_filter input');
			dataTables_search.on('input', function(e) {
				window.location.hash = $(this).val();
				return false;
			});
			// if the url hash does not refer to any of the tabs, update the search field
			var hash = window.location.hash.substring(1);
			if (hash != 'species' && hash != 'overview' && hash != '') {
				dataTables_search.val(decodeURIComponent(hash)).focus();
				oTable.fnFilter(decodeURIComponent(hash));
			}
		};

		function append_download_links() {
          	// append download links if genomic coordinates are found
          	var url = '/api/v1/rna/' + obj.upi;
			if ( obj.enable_genomic_features ) {
		        $(obj.config.dom.downloads).append('
bed
')
		                                   .append('
gff
')
		                                   .append('
gff3
');
        	}
		};

		function enable_hopscotch_genomic_tour() {
			if ( obj.enable_genomic_features ) {
	            // create the tour button
	            $('h1').first().append('<button type="button" class="btn btn-info pull-right tour help animated pulse" title="Take an interactive tour to see genome integration features in action">Tour genome-related features</button>');

	            // Define hopscotch genome location tour
	            var tour = {
	              id: "tour-hopscotch",
	              showPrevButton: true,
	              onStart: function(){
                    $('#tabs a[href="#overview"]').tab('show');
	              },
	              steps: [
	                {
	                  title: "Genome integration",
	                  content: "Some annotations are linked to the human genome and have additional functionality.",
	                  target: "xrefs-table-div",
	                  placement: "top"
	                },
	                {
	                  title: "Links to genome browsers",
	                  content: "View this genomic location in Ensembl or UCSC with the pre-loaded RNAcentral track.",
	                  target: document.querySelector(".ensembl-link"),
	                  placement: "top"
	                },
	                {
	                  title: "Embedded genome browser",
	                  content: "This genomic location can also be visualised right on this page.",
	                  target: document.querySelector(".genoverse-xref"),
	                  placement: "top",
	                  onNext: function(){
	                    $(".genoverse-xref").first().click(); // launch genoverse
	                  }
	                },
	                {
	                  title: "Using the embedded browser",
	                  content: "You can scroll the browser or click on the entries to view the popup menus with links to Ensembl and other RNAcentral entries.",
	                  target: 'genoverse',
	                  placement: "top",
	                }
	              ]
	            };

	            // initialize the tour
	            $(obj.config.dom.hopscotch_tour).click(function(){
	              var firstStep = 0; // always start at the first step
	              hopscotch.startTour(tour, firstStep);
	            });
			};
		};

	};
};
<commit_msg>Update genome functionality tour<commit_after>/*
Copyright [2009-2014] EMBL-European Bioinformatics Institute
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
     http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var xrefLoader = function(upi) {
	this.upi = upi;

	this.config = {
		dom: {
			xref_table_container: '#xrefs-table-div',
			xref_table: '#xrefs-table',
			xref_loading_container: '#xrefs-loading',
			xref_msg: '#xrefs-loading-msg',
			hopscotch_tour: '.tour',
			downloads: '#download-formats'
		},
		templates: {
			delay_msg: '#handlebars-loading-info-tmpl',
			loading_error_msg: '#handlebars-loading-error-tmpl',
		}
	};

	this.enable_genomic_features = false;
};

xrefLoader.prototype.load_xrefs = function() {

	obj = this;
	set_xref_timer();
	get_xrefs();

	function set_xref_timer() {
		// show an info message if xrefs are taking too long to load
		var target = $(obj.config.dom.xref_msg),
				     delay_template = $(obj.config.templates.delay_msg),
		             delay = 5000;

		var timer = setTimeout(function() {
			// do not update the message if there was an error
			if (target.html().indexOf("alert-danger") != -1) {
				return;
			}
			var msg = Handlebars.compile(delay_template.html());
			target.append(msg).slideDown();
		}, delay);
	};

	function get_xrefs() {
		var url = '/rna/' + obj.upi + '/xrefs';
    	$.get(url, function(data){
        	$(obj.config.dom.xref_table_container).html(data);
			obj.enable_genomic_features = data.indexOf('View genomic location') > 0;
      	}).fail(function() {
      		show_error();
      	}).done(function(){
      		display_xrefs();
      	});
    };

	function show_error() {
		var error_template = $(obj.config.templates.loading_error_msg);
		var target = $(obj.config.dom.xref_msg);
		var msg = Handlebars.compile(error_template.html());
		target.hide().html(msg).fadeIn();
	};

	function display_xrefs(upi) {
		var oTable = {};

		launch_dataTables();
		show_dataTables();
  		enable_sorting();
  		enable_url_filering();
  		append_download_links();
  		enable_hopscotch_genomic_tour();

		function launch_dataTables() {
			oTable = $(obj.config.dom.xref_table).dataTable(
				{
					"aoColumns": [null, null, null, {"bVisible": false}, {"bVisible": false}], // hide columns, but keep them sortable
					"bAutoWidth": true, // pre-recalculate column widths
					"sDom": "ftpil", // filter, table, pagination, information, length
					"iDisplayLength": 5, // show 5 entries by default
					"sPaginationType": "bootstrap", // requires dataTables.bootstrap.js
					"bDeferRender": true, // defer rendering until necessary
					"oLanguage": {
					"sSearch": "", // don't display the "Search:" bit
					"sInfo": "_START_-_END_ of _TOTAL_", // change the informational text
					"oPaginate": {
						"sNext": "",
						"sPrevious": "",
					},
				},
				"aLengthMenu": [[5, 10, 20, 50, -1], [5, 10, 20, 50, "All"]],
				"fnInitComplete": function(oSettings, json) {
					adjust_dataTables_controls();
				},
			});

			function adjust_dataTables_controls() {
				$('.dataTables_filter input').attr('placeholder', 'Filter table').
				                              attr("tabindex", 2).
				                              attr('type', 'search').
				                              addClass('form-control input-sm');
				$('#xrefs-table_filter').appendTo('#xrefs-datatables-filter').
				                         addClass('pull-right hidden-xs');
				$('#xrefs-table_info').appendTo('#xrefs-datatables-counter');
				// hide pagination controls for tables with one page
				if ( $('.dataTables_paginate').find('li').length == 3 ) { // 3 elements: <-, 1, ->
					$('.dataTables_paginate').hide();
					$('#xrefs-table_length').hide();
				} else {
					$('.dataTables_paginate').addClass('pull-left').
					                          appendTo('.xref-datatables-controls');
					$('#xrefs-table_length').addClass('pull-right text-muted small').
					                         appendTo('.xref-datatables-controls');
				}
				$('.table th').css('padding-right','1.5em');
			};
		};

		function show_dataTables() {
			$(obj.config.dom.xref_loading_container).slideUp();
			$(obj.config.dom.xref_table).fadeIn();
		}

		function enable_sorting() {
			oTable.fnSortListener( document.getElementById('sort-by-first-seen'), 3);
			oTable.fnSortListener( document.getElementById('sort-by-last-seen'), 4);
		};

		function enable_url_filering() {
			// monitor the xref datatables search field to update the hashtag
			var dataTables_search = $('#xrefs-table_filter input');
			dataTables_search.on('input', function(e) {
				window.location.hash = $(this).val();
				return false;
			});
			// if the url hash does not refer to any of the tabs, update the search field
			var hash = window.location.hash.substring(1);
			if (hash != 'species' && hash != 'overview' && hash != '') {
				dataTables_search.val(decodeURIComponent(hash)).focus();
				oTable.fnFilter(decodeURIComponent(hash));
			}
		};

		function append_download_links() {
          	// append download links if genomic coordinates are found
          	var url = '/api/v1/rna/' + obj.upi;
			if ( obj.enable_genomic_features ) {
		        $(obj.config.dom.downloads).append('
bed
')
		                                   .append('
gff
')
		                                   .append('
gff3
');
        	}
		};

		function enable_hopscotch_genomic_tour() {
			if ( obj.enable_genomic_features ) {
	            // create the tour button
	            $('h1').first().append('<button type="button" class="btn btn-info pull-right tour help animated pulse" title="Take an interactive tour to see genome integration features in action">Tour genome-related features</button>');

	            // Define hopscotch genome location tour
	            var tour = {
	              id: "tour-hopscotch",
	              showPrevButton: true,
	              onStart: function(){
                    $('#tabs a[href="#overview"]').tab('show');
	              },
	              steps: [
	                {
	                  title: "Genome integration",
	                  content: "Some annotations are linked to their genomic location and have additional functionality.",
	                  target: "xrefs-table-div",
	                  placement: "top"
	                },
	                {
	                  title: "Embedded genome browser",
	                  content: "Click View genomic location to open a genome browser on this page.",
	                  target: document.querySelector(".genoverse-xref"),
	                  placement: "top",
	                  onNext: function(){
	                    $(".genoverse-xref").first().click(); // launch genoverse
	                  }
	                },
	                {
	                  title: "Using the embedded browser",
	                  content: "You can scroll along the genome or click on the entries to view popup menus with additional information.",
	                  target: 'genoverse',
	                  placement: "top",
	                }
	              ]
	            };

	            // initialize the tour
	            $(obj.config.dom.hopscotch_tour).click(function(){
	              var firstStep = 0; // always start at the first step
	              hopscotch.startTour(tour, firstStep);
	            });
			};
		};

	};
};
<|endoftext|>


<commit_before>import stringify from 'json-stringify-safe'
import validator from 'validator'

const OBJLENGTH = 10
const ARRLENGTH = 10
const STRINGLIMIT = 10000
const STRINGTRUNCATE = 200

let sanitizeString = function (str) {
    if (!str) {
        return ''
    }

    return String(str)
        .replace(/\./g, '_')
        .replace(/\s/g, '')
        .toLowerCase()
}

/**
 * formats capability object into sanitized string for e.g.filenames
 * @param {Object} caps  Selenium capabilities
 */
let caps = function (caps) {
    let result

    /**
     * mobile caps
     */
    if (caps.deviceName) {
        result = [sanitizeString(caps.deviceName), sanitizeString(caps.platformName), sanitizeString(caps.platformVersion), sanitizeString(caps.app)]
    } else {
        result = [sanitizeString(caps.browserName), sanitizeString(caps.version), sanitizeString(caps.platform)]
    }

    result = result.filter(n => n !== undefined && n !== '')
    return result.join('.')
}

/**
 * formats arguments into string
 * @param  {Array} args arguments object
 */
let args = function (args) {
    return args.map((arg) => {
        if (typeof arg === 'function' || (typeof arg === 'string' && arg.indexOf('return (function') === 0)) {
            return '<Function>'
        } else if (typeof arg === 'string') {
            return '"' + arg + '"'
        } else if (Array.isArray(arg)) {
            return arg.join(', ')
        }

        return arg
    }).join(', ')
}

let css = function (value) {
    if (!value) {
        return value
    }

    return value.trim().replace(/'/g, '').replace(/"/g, '').toLowerCase()
}

/**
 * Limit the length of an arbritrary variable of any type, suitable for being logged or displayed
 * @param  {Any} val Any variable
 * @return {Any}     Limited var of same type
 */
let limit = function (val) {
    switch (Object.prototype.toString.call(val)) {
    case '[object String]':
        if (val.length > 100 && validator.isBase64(val)) {
            return '[base64] ' + val.length + ' bytes'
        }

        if (val.length > STRINGLIMIT) {
            return val.substr(0, STRINGTRUNCATE) + ' ... (' + (val.length - STRINGTRUNCATE) + ' more bytes)'
        }

        return val
    case '[object Array]':
        const length = val.length
        if (length > ARRLENGTH) {
            val = val.slice(0, ARRLENGTH)
            val.push(' ... (' + (length - ARRLENGTH) + ' more items)')
        }
        return val.map(limit)
    case '[object Object]':
        const keys = Object.keys(val)
        const removed = []
        for (let i = 0, l = keys.length; i < l; i++) {
            if (i < OBJLENGTH) {
                val[keys[i]] = limit(val[keys[i]])
            } else {
                delete val[keys[i]]
                removed.push(keys[i])
            }
        }
        if (keys.length > OBJLENGTH) {
            val._ = (keys.length - OBJLENGTH) + ' more keys: ' + stringify(removed)
        }
        return val
    }
}

export default {
    css,
    args,
    caps,
    limit
}
<commit_msg>Ensure we're working with a copy before mutating<commit_after>import stringify from 'json-stringify-safe'
import validator from 'validator'

const OBJLENGTH = 10
const ARRLENGTH = 10
const STRINGLIMIT = 10000
const STRINGTRUNCATE = 200

let sanitizeString = function (str) {
    if (!str) {
        return ''
    }

    return String(str)
        .replace(/\./g, '_')
        .replace(/\s/g, '')
        .toLowerCase()
}

/**
 * formats capability object into sanitized string for e.g.filenames
 * @param {Object} caps  Selenium capabilities
 */
let caps = function (caps) {
    let result

    /**
     * mobile caps
     */
    if (caps.deviceName) {
        result = [sanitizeString(caps.deviceName), sanitizeString(caps.platformName), sanitizeString(caps.platformVersion), sanitizeString(caps.app)]
    } else {
        result = [sanitizeString(caps.browserName), sanitizeString(caps.version), sanitizeString(caps.platform)]
    }

    result = result.filter(n => n !== undefined && n !== '')
    return result.join('.')
}

/**
 * formats arguments into string
 * @param  {Array} args arguments object
 */
let args = function (args) {
    return args.map((arg) => {
        if (typeof arg === 'function' || (typeof arg === 'string' && arg.indexOf('return (function') === 0)) {
            return '<Function>'
        } else if (typeof arg === 'string') {
            return '"' + arg + '"'
        } else if (Array.isArray(arg)) {
            return arg.join(', ')
        }

        return arg
    }).join(', ')
}

let css = function (value) {
    if (!value) {
        return value
    }

    return value.trim().replace(/'/g, '').replace(/"/g, '').toLowerCase()
}

/**
 * Limit the length of an arbritrary variable of any type, suitable for being logged or displayed
 * @param  {Any} val Any variable
 * @return {Any}     Limited var of same type
 */
let limit = function (val) {
    // Ensure we're working with a copy
    val = JSON.parse(stringify(val))

    switch (Object.prototype.toString.call(val)) {
    case '[object String]':
        if (val.length > 100 && validator.isBase64(val)) {
            return '[base64] ' + val.length + ' bytes'
        }

        if (val.length > STRINGLIMIT) {
            return val.substr(0, STRINGTRUNCATE) + ' ... (' + (val.length - STRINGTRUNCATE) + ' more bytes)'
        }

        return val
    case '[object Array]':
        const length = val.length
        if (length > ARRLENGTH) {
            val = val.slice(0, ARRLENGTH)
            val.push(' ... (' + (length - ARRLENGTH) + ' more items)')
        }
        return val.map(limit)
    case '[object Object]':
        const keys = Object.keys(val)
        const removed = []
        for (let i = 0, l = keys.length; i < l; i++) {
            if (i < OBJLENGTH) {
                val[keys[i]] = limit(val[keys[i]])
            } else {
                delete val[keys[i]]
                removed.push(keys[i])
            }
        }
        if (removed.length) {
            val._ = (keys.length - OBJLENGTH) + ' more keys: ' + JSON.stringify(removed)
        }
        return val
    }
}

export default {
    css,
    args,
    caps,
    limit
}
<|endoftext|>


<commit_before>import '../console/console-frame.scss';
import * as consoleFrames from '../console/frames';
import * as scrolls from '../content/scrolls';
import * as navigates from '../content/navigates';
import Follow from '../content/follow';
import operations from '../operations';
import messages from '../messages';

consoleFrames.initialize(window.document);

const startFollows = (newTab) => {
  let follow = new Follow(window.document);
  follow.onActivated((element) => {
    switch (element.tagName.toLowerCase()) {
    case 'a':
      if (newTab) {
        // getAttribute() to avoid to resolve absolute path
        let href = element.getibute('href');

        // eslint-disable-next-line no-script-url
        if (!href || href === '#' || href.startsWith('javascript:')) {
          return;
        }
        return browser.runtime.sendMessage({
          type: messages.OPEN_URL,
          url: element.href,
          newTab
        });
      }
      return element.click();
    case 'input':
      switch (element.type) {
      case 'file':
      case 'checkbox':
      case 'radio':
      case 'submit':
      case 'reset':
      case 'button':
      case 'image':
      case 'color':
        return element.click();
      default:
        return element.focus();
      }
    case 'textarea':
      return element.focus();
    case 'button':
      return element.click();
    }
  });
};

window.addEventListener('keypress', (e) => {
  if (e.target instanceof HTMLInputElement ||
    e.target instanceof HTMLTextAreaElement ||
    e.target instanceof HTMLSelectElement) {
    return;
  }
  browser.runtime.sendMessage({
    type: messages.KEYDOWN,
    code: e.which,
    ctrl: e.ctrlKey
  });
});

const execOperation = (operation) => {
  switch (operation.type) {
  case operations.SCROLL_LINES:
    return scrolls.scrollLines(window, operation.count);
  case operations.SCROLL_PAGES:
    return scrolls.scrollPages(window, operation.count);
  case operations.SCROLL_TOP:
    return scrolls.scrollTop(window);
  case operations.SCROLL_BOTTOM:
    return scrolls.scrollBottom(window);
  case operations.SCROLL_LEFT:
    return scrolls.scrollLeft(window);
  case operations.SCROLL_RIGHT:
    return scrolls.scrollRight(window);
  case operations.FOLLOW_START:
    return startFollows(operation.newTab);
  case operations.NAVIGATE_HISTORY_PREV:
    return navigates.historyPrev(window);
  case operations.NAVIGATE_HISTORY_NEXT:
    return navigates.historyNext(window);
  case operations.NAVIGATE_LINK_PREV:
    return navigates.linkPrev(window);
  case operations.NAVIGATE_LINK_NEXT:
    return navigates.linkNext(window);
  case operations.NAVIGATE_PARENT:
    return navigates.parent(window);
  case operations.NAVIGATE_ROOT:
    return navigates.root(window);
  }
};

const update = (state) => {
  if (!state.console.commandShown) {
    window.focus();
    consoleFrames.blur(window.document);
  }
};

browser.runtime.onMessage.addListener((action) => {
  switch (action.type) {
  case messages.STATE_UPDATE:
    return update(action.state);
  case messages.CONTENT_OPERATION:
    execOperation(action.operation);
    return Promise.resolve();
  default:
    return Promise.resolve();
  }
});
<commit_msg>open cross-origin links by background<commit_after>import '../console/console-frame.scss';
import * as consoleFrames from '../console/frames';
import * as scrolls from '../content/scrolls';
import * as navigates from '../content/navigates';
import Follow from '../content/follow';
import operations from '../operations';
import messages from '../messages';

consoleFrames.initialize(window.document);

const startFollows = (newTab) => {
  let follow = new Follow(window.document);
  follow.onActivated((element) => {
    switch (element.tagName.toLowerCase()) {
    case 'a':
      if (newTab) {
        // getAttribute() to avoid to resolve absolute path
        let href = element.getibute('href');

        // eslint-disable-next-line no-script-url
        if (!href || href === '#' || href.startsWith('javascript:')) {
          return;
        }
        return browser.runtime.sendMessage({
          type: messages.OPEN_URL,
          url: element.href,
          newTab
        });
      }
      if (element.href.startsWith('http://') ||
        element.href.startsWith('https://') ||
        element.href.startsWith('ftp://')) {
        return browser.runtime.sendMessage({
          type: messages.OPEN_URL,
          url: element.href,
          newTab
        });
      }
      return element.click();
    case 'input':
      switch (element.type) {
      case 'file':
      case 'checkbox':
      case 'radio':
      case 'submit':
      case 'reset':
      case 'button':
      case 'image':
      case 'color':
        return element.click();
      default:
        return element.focus();
      }
    case 'textarea':
      return element.focus();
    case 'button':
      return element.click();
    }
  });
};

window.addEventListener('keypress', (e) => {
  if (e.target instanceof HTMLInputElement ||
    e.target instanceof HTMLTextAreaElement ||
    e.target instanceof HTMLSelectElement) {
    return;
  }
  browser.runtime.sendMessage({
    type: messages.KEYDOWN,
    code: e.which,
    ctrl: e.ctrlKey
  });
});

const execOperation = (operation) => {
  switch (operation.type) {
  case operations.SCROLL_LINES:
    return scrolls.scrollLines(window, operation.count);
  case operations.SCROLL_PAGES:
    return scrolls.scrollPages(window, operation.count);
  case operations.SCROLL_TOP:
    return scrolls.scrollTop(window);
  case operations.SCROLL_BOTTOM:
    return scrolls.scrollBottom(window);
  case operations.SCROLL_LEFT:
    return scrolls.scrollLeft(window);
  case operations.SCROLL_RIGHT:
    return scrolls.scrollRight(window);
  case operations.FOLLOW_START:
    return startFollows(operation.newTab);
  case operations.NAVIGATE_HISTORY_PREV:
    return navigates.historyPrev(window);
  case operations.NAVIGATE_HISTORY_NEXT:
    return navigates.historyNext(window);
  case operations.NAVIGATE_LINK_PREV:
    return navigates.linkPrev(window);
  case operations.NAVIGATE_LINK_NEXT:
    return navigates.linkNext(window);
  case operations.NAVIGATE_PARENT:
    return navigates.parent(window);
  case operations.NAVIGATE_ROOT:
    return navigates.root(window);
  }
};

const update = (state) => {
  if (!state.console.commandShown) {
    window.focus();
    consoleFrames.blur(window.document);
  }
};

browser.runtime.onMessage.addListener((action) => {
  switch (action.type) {
  case messages.STATE_UPDATE:
    return update(action.state);
  case messages.CONTENT_OPERATION:
    execOperation(action.operation);
    return Promise.resolve();
  default:
    return Promise.resolve();
  }
});
<|endoftext|>


<commit_before>// Setting up required files the bot will need
//	* Some are required only for specific commands
try {
	var AuthDetails = require('./auth.json');
} catch (e){
	console.log("Please create an auth.json file with account email and password"+e.stack);
	process.exit();
}

try {
	var Discord = require('discord.io');
} catch (e){
	console.log("Please run npm install discord.io"+e.stack);
	process.exit();
}

try {
	var d20 = require('d20');
} catch (e){
	console.log("Please run npm install d20"+e.stack);
}

try {
	var Stats = require("./user_stats.json");
} catch (e){
	console.log("Unable to provide stats: Missing file");
}

// Setting up Roles object for future reference
var roles = {};
roles.admin_id = 0;
roles.mod_id = 0;

// Setting up Games object for future reference
var games = {};
games.rolloff = false;

// Start client
var bot = new Discord.Client({
	token: AuthDetails.token,
	autorun: true
});

// Create commands
//	* usage - To be used by !help
//	* description - To be used by !help
//	* process - what gets run when command is called
var commands = {
	"dam": {
		usage: "",
		description: "returns image/gif",
		process: function(bot, channel) {
			var rand = Math.floor(Math.random() * 2) + 1;
			var result;
			if (rand == 1)
				result = 'https://i.imgur.com/7lZwLKc.jpg';
			else
				result = 'https://i.imgur.com/VQLGJOL.gif';
			bot.sendMessage({to: channel, message: result});
		}
	},
	"happy": {
		usage: "",
		description: "returns image/gif",
		process: function(bot, channel) {
			var rand = Math.floor(Math.random() * 2) + 1;
			var result;
			if (rand == 1)
			  result = 'https://i.imgur.com/gbXzYXp.gif';
			else
			  result = 'https://i.imgur.com/OxwIC0O.gif';
			bot.sendMessage({to: channel, message: result});
		}
	},
	"horse": {
		usage: "",
		description: "returns horse gif",
		process: function(bot, channel) {
			var result = 'https://i.giphy.com/S4mOmgmpBQAXm.gif';
			bot.sendMessage({to: channel, message: result});
		}
	},
	//NEEDS UPDATE
	"zzzimg": {
		usage: "<search term>",
		description: "searches imgur based on keyword",
		process: function(bot, channel, suffix) {
			var key = AuthDetails;
			var Imgur = require('imgur-search');

			var term = suffix;
			if(!term) {
				bot.sendMessage({to: channel, message:"No Search Term"});
				return;
			}
			new Imgur(key.imgur_key).search(term).then(function(result) {
				if (result.length == 0 || result == undefined) {
					bot.sendMessage({to: channel, message:"You suck at searching"});
				} else {
					var img = result[Math.floor(Math.random() * result.length)];
					bot.sendMessage({to: channel, message: img.link});
				}
			});
		}
	},
	"why": {
		usage: "",
		description: "returns gif",
		process: function(bot, channel) {
			var result = 'https://media.giphy.com/media/1M9fmo1WAFVK0/giphy.gif';
			bot.sendMessage({to: channel, message: result});
		}
	},
	"roll": {
		usage: "[#d#]",
		description: "dice roller, with single command giving a d20, otherwise rolling specified combo",
		process: function(bot, channel, suffix) {
			if (games.rolloff){
				var roll_bot;
				var roll_usr;

				roll_bot = d20.roll(20);
				roll_usr = d20.roll(20);
				bot.sendMessage({to: channel, message:"rolled: " + roll_usr});
				setTimeout(function(){
					if (roll_bot > roll_usr)
						bot.sendMessage({to: channel, message:"MUAHAHAHA. My " + roll_bot + " p4wned your " + roll_usr + ". Get rekt."});
					else if (roll_usr > roll_bot)
						bot.sendMessage({to: channel, message:"Lucky roll... My " + roll_bot + " can't beat your " + roll_usr + "."});
					else
						bot.sendMessage({to: channel, message:"Tie? TIE!? Let's call that a win for me..."})
				;},500);

				games.rolloff = false;
			} else {
				if(!suffix) {
					bot.sendMessage({to: channel, message:"rolled: " + d20.roll(20)});
				} else {
					var result;
					try {
						result = d20.roll(suffix);
					} catch (e){
						bot.sendMessage({to: channel, message:"Could not roll " + suffix});
						return;
					}
					if (!isNaN(result) && result != 'NaN')
						bot.sendMessage({to: channel, message:"Rolled: " + d20.verboseRoll(suffix)});
					else
						bot.sendMessage({to: channel, message:"Not a valid number"});
				}
			}
		}
	},
	"rolloff": {
		usage: "",
		description: "Roll off against the bot (D20)",
		process: function(bot, channel) {
			bot.sendMessage({to: channel, message:"A Challenger APPROACHES! Use !roll to compete against me!"});
			games.rolloff = true;
		}
	},
	"blown": {
		usage: "",
		description: "returns gif",
		process: function(bot, channel) {
			var result;
			var rand = Math.floor(Math.random() * 6);
			var gifs = [	'https://i.imgur.com/YGsTG5o.gif',
					'https://i.imgur.com/pBTk7MC.gif',
					'https://i.imgur.com/rfFWukr.gif',
					'https://media.giphy.com/media/OK27wINdQS5YQ/giphy.gif',
					'https://i.imgur.com/l4bJmRE.gif',
					'https://i.imgur.com/3WB3L.gif',
					'https://giphy.com/gifs/cheezburger-robots-screaming-NfEQd1ge1kP04']

			bot.sendMessage({to: channel, message:gifs[rand]});
		}
	},
	"weekend": {
		usage: "",
		description: "returns days until weekend",
		process: function(bot, channel) {
			var date = new Date();
			var day = date.getDay();
			var result = [  "Last day, Enjoy it!",
					"4 Days Left. Got a case of the Mondays?",
					"3 Days Left",
					"2 Days Left.  Hump Day!",
					"1 Day Left",
					"FRIDAY!",
					"Less than 48 hours left..."];

			bot.sendMessage({to: channel, message:result[day]});
		}
	},
	"stats": {
		// members in JSON file need to be lowercase
		usage: "<user>",
		description: "Score for users in chat games",
		process: function(bot, channel, suffix, userID) {
			if (isAdmin(userID)){
				if (suffix){
					var usr = suffix.toLowerCase();
					var score = Stats.members[usr];
					if (score != null)
						bot.sendMessage({to: channel, message: "Score: " + score});
					else
						bot.sendMessage({to: channel, message: "nothing!"});
				} else {
					bot.sendMessage({to: channel, message:"Pong"});
				}
			} else {
				bot.sendMessage({to: channel, message:"For admins only, I'm afraid"});
			}
		}
	}
};

// Load Roles object with needed roles
//	* the propVal checks may need to be updated on role name changes
function loadRoles(){
	for (var r in bot.servers[AuthDetails.server_id].roles){
		var role = bot.servers[AuthDetails.server_id].roles[r];
		var propVal;
		for (var prop in role){
			propVal = role[prop];
			if (prop == 'name' && propVal == 'Admin'){
				roles.admin_id = role['id'];
			}
			if (prop == 'name' && propVal == 'Moderator'){
				roles.mod_id = role['id'];
			}
		}
	}
}

// Compares user's roles and admin_id
function isAdmin(userID){
	var usrRoles = bot.servers[AuthDetails.server_id].members[userID].roles;
	for (var i = 0; i < usrRoles.length; i++){
		if (usrRoles[i] == roles.admin_id)
			return true;
	}
	return false;
}

// Ready trigger
bot.on('ready', function () {
	console.log("Ready to start.");
	loadRoles();
	console.log("Roles loaded");
});

// Disconnect trigger
bot.on('disconnected', function() {
	console.log('Disconnected.');
	process.exit(1);
});

// Message trigger
bot.on('message', function (user, userID, channelID, message, evt) {
	// if message starts with '!', a command has been entered
	if (message.substring(0,1) == '!'){
		var args = message.substring(1).split(' ');
		var cmd = args[0];
		var suffix = args[1];
		var result = commands[cmd];

		if (cmd == 'help'){
			var info = "Available Commands: ";
			for (var cmd in commands){
				info += "!" + cmd;
				var usage = commands[cmd].usage;
				if (usage){
					info += " " + usage + "; ";
				} else {
					info += "; ";
				}
			}
			bot.sendMessage({to: userID, message: info});
		} else if (result){
			try {
				result.process(bot,channelID,suffix,userID);
			} catch (e){
				console.log("Command failed: " + cmd + ". " + e.stack);
			}
		} else {
			bot.sendMessage({to: channelID, message: "Not a command, use !help"});
		}
	}
});<commit_msg>removed bot from command function calls, added check around loading roles<commit_after>// Setting up required files the bot will need
//	* Some are required only for specific commands
try {
	var AuthDetails = require('./auth.json');
} catch (e){
	console.log("Please create an auth.json file with account email and password"+e.stack);
	process.exit();
}

try {
	var Discord = require('discord.io');
} catch (e){
	console.log("Please run npm install discord.io"+e.stack);
	process.exit();
}

try {
	var d20 = require('d20');
} catch (e){
	console.log("Please run npm install d20"+e.stack);
}

try {
	var Stats = require("./user_stats.json");
} catch (e){
	console.log("Unable to provide stats: Missing file");
}

// Setting up Roles object for future reference
var roles = {};
roles.admin_id = 0;
roles.mod_id = 0;

// Setting up Games object for future reference
var games = {};
games.rolloff = false;

// Start client
var bot = new Discord.Client({
	token: AuthDetails.token,
	autorun: true
});

// Create commands
//	* usage - To be used by !help
//	* description - To be used by !help
//	* process - what gets run when command is called
var commands = {
	"dam": {
		usage: "",
		description: "returns image/gif",
		process: function(channel) {
			var rand = Math.floor(Math.random() * 2) + 1;
			var result;
			if (rand == 1)
				result = 'https://i.imgur.com/7lZwLKc.jpg';
			else
				result = 'https://i.imgur.com/VQLGJOL.gif';
			bot.sendMessage({to: channel, message: result});
		}
	},
	"happy": {
		usage: "",
		description: "returns image/gif",
		process: function(channel) {
			var rand = Math.floor(Math.random() * 2) + 1;
			var result;
			if (rand == 1)
			  result = 'https://i.imgur.com/gbXzYXp.gif';
			else
			  result = 'https://i.imgur.com/OxwIC0O.gif';
			bot.sendMessage({to: channel, message: result});
		}
	},
	"horse": {
		usage: "",
		description: "returns horse gif",
		process: function(channel) {
			var result = 'https://i.giphy.com/S4mOmgmpBQAXm.gif';
			bot.sendMessage({to: channel, message: result});
		}
	},
	//NEEDS UPDATE
	"zzzimg": {
		usage: "<search term>",
		description: "searches imgur based on keyword",
		process: function(channel, suffix) {
			var key = AuthDetails;
			var Imgur = require('imgur-search');

			var term = suffix;
			if(!term) {
				bot.sendMessage({to: channel, message:"No Search Term"});
				return;
			}
			new Imgur(key.imgur_key).search(term).then(function(result) {
				if (result.length == 0 || result == undefined) {
					bot.sendMessage({to: channel, message:"You suck at searching"});
				} else {
					var img = result[Math.floor(Math.random() * result.length)];
					bot.sendMessage({to: channel, message: img.link});
				}
			});
		}
	},
	"why": {
		usage: "",
		description: "returns gif",
		process: function(channel) {
			var result = 'https://media.giphy.com/media/1M9fmo1WAFVK0/giphy.gif';
			bot.sendMessage({to: channel, message: result});
		}
	},
	"roll": {
		usage: "[#d#]",
		description: "dice roller, with single command giving a d20, otherwise rolling specified combo",
		process: function(channel, suffix) {
			if (games.rolloff){
				var roll_bot;
				var roll_usr;

				roll_bot = d20.roll(20);
				roll_usr = d20.roll(20);
				bot.sendMessage({to: channel, message:"rolled: " + roll_usr});
				setTimeout(function(){
					if (roll_bot > roll_usr)
						bot.sendMessage({to: channel, message:"MUAHAHAHA. My " + roll_bot + " p4wned your " + roll_usr + ". Get rekt."});
					else if (roll_usr > roll_bot)
						bot.sendMessage({to: channel, message:"Lucky roll... My " + roll_bot + " can't beat your " + roll_usr + "."});
					else
						bot.sendMessage({to: channel, message:"Tie? TIE!? Let's call that a win for me..."})
				;},500);

				games.rolloff = false;
			} else {
				if(!suffix) {
					bot.sendMessage({to: channel, message:"rolled: " + d20.roll(20)});
				} else {
					var result;
					try {
						result = d20.roll(suffix);
					} catch (e){
						bot.sendMessage({to: channel, message:"Could not roll " + suffix});
						return;
					}
					if (!isNaN(result) && result != 'NaN')
						bot.sendMessage({to: channel, message:"Rolled: " + d20.verboseRoll(suffix)});
					else
						bot.sendMessage({to: channel, message:"Not a valid number"});
				}
			}
		}
	},
	"rolloff": {
		usage: "",
		description: "Roll off against the bot (D20)",
		process: function(channel) {
			bot.sendMessage({to: channel, message:"A Challenger APPROACHES! Use !roll to compete against me!"});
			games.rolloff = true;
		}
	},
	"blown": {
		usage: "",
		description: "returns gif",
		process: function(channel) {
			var result;
			var rand = Math.floor(Math.random() * 6);
			var gifs = [	'https://i.imgur.com/YGsTG5o.gif',
					'https://i.imgur.com/pBTk7MC.gif',
					'https://i.imgur.com/rfFWukr.gif',
					'https://media.giphy.com/media/OK27wINdQS5YQ/giphy.gif',
					'https://i.imgur.com/l4bJmRE.gif',
					'https://i.imgur.com/3WB3L.gif',
					'https://giphy.com/gifs/cheezburger-robots-screaming-NfEQd1ge1kP04']

			bot.sendMessage({to: channel, message:gifs[rand]});
		}
	},
	"weekend": {
		usage: "",
		description: "returns days until weekend",
		process: function(channel) {
			var date = new Date();
			var day = date.getDay();
			var result = [  "Last day, Enjoy it!",
					"4 Days Left. Got a case of the Mondays?",
					"3 Days Left",
					"2 Days Left.  Hump Day!",
					"1 Day Left",
					"FRIDAY!",
					"Less than 48 hours left..."];

			bot.sendMessage({to: channel, message:result[day]});
		}
	},
	"stats": {
		// members in JSON file need to be lowercase
		usage: "<user>",
		description: "Score for users in chat games",
		process: function(channel, suffix, userID) {
			if (isAdmin(userID)){
				if (suffix){
					var usr = suffix.toLowerCase();
					var score = Stats.members[usr];
					if (score != null)
						bot.sendMessage({to: channel, message: "Score: " + score});
					else
						bot.sendMessage({to: channel, message: "nothing!"});
				} else {
					bot.sendMessage({to: channel, message:"Pong"});
				}
			} else {
				bot.sendMessage({to: channel, message:"For admins only, I'm afraid"});
			}
		}
	}
};

// Load Roles object with needed roles
//	* the propVal checks may need to be updated on role name changes
function loadRoles(){
	for (var r in bot.servers[AuthDetails.server_id].roles){
		var role = bot.servers[AuthDetails.server_id].roles[r];
		var propVal;
		for (var prop in role){
			propVal = role[prop];
			if (prop == 'name' && propVal == 'Admin'){
				roles.admin_id = role['id'];
			}
			if (prop == 'name' && propVal == 'Moderator'){
				roles.mod_id = role['id'];
			}
		}
	}
}

// Compares user's roles and admin_id
function isAdmin(userID){
	var usrRoles = bot.servers[AuthDetails.server_id].members[userID].roles;
	for (var i = 0; i < usrRoles.length; i++){
		if (usrRoles[i] == roles.admin_id)
			return true;
	}
	return false;
}

// Ready trigger
bot.on('ready', function () {
	console.log("Ready to start.");
	try {
		loadRoles();
	} catch (e){
		console.log('Unable to load role IDs'+e.stack);
	}
});

// Disconnect trigger
bot.on('disconnected', function() {
	console.log('Disconnected.');
	process.exit(1);
});

// Message trigger
bot.on('message', function (user, userID, channelID, message, evt) {
	// if message starts with '!', a command has been entered
	if (message.substring(0,1) == '!'){
		var args = message.substring(1).split(' ');
		var cmd = args[0];
		var suffix = args[1];
		var result = commands[cmd];

		if (cmd == 'help'){
			var info = "Available Commands: ";
			for (var cmd in commands){
				info += "!" + cmd;
				var usage = commands[cmd].usage;
				if (usage){
					info += " " + usage + "; ";
				} else {
					info += "; ";
				}
			}
			bot.sendMessage({to: userID, message: info});
		} else if (result){
			try {
				result.process(channelID,suffix,userID);
			} catch (e){
				console.log("Command failed: " + cmd + ". " + e.stack);
			}
		} else {
			bot.sendMessage({to: channelID, message: "Not a command, use !help"});
		}
	}
});<|endoftext|>


<commit_before>/**
 * unassertify
 *   Browserify transform for unassert
 *     Encourages programming with assertions by providing tools to compile them away.
 *
 * https://github.com/unassert-js/unassertify
 *
 * Copyright (c) 2015-2017 Takuto Wada
 * Licensed under the MIT license.
 *   https://github.com/unassert-js/unassertify/blob/master/LICENSE
 */
'use strict';

var path = require('path');
var through = require('through');
var acorn = require('acorn');
var escodegen = require('escodegen');
var convert = require('convert-source-map');
var transfer = require('multi-stage-sourcemap').transfer;
var unassert = require('unassert');

function mergeSourceMap (incomingSourceMap, outgoingSourceMap) {
    if (typeof outgoingSourceMap === 'string' || outgoingSourceMap instanceof String) {
        outgoingSourceMap = JSON.parse(outgoingSourceMap);
    }
    if (!incomingSourceMap) {
        return outgoingSourceMap;
    }
    return JSON.parse(transfer({fromSourceMap: outgoingSourceMap, toSourceMap: incomingSourceMap}));
}

function overwritePropertyIfExists (name, from, to) {
    if (from.hasOwnProperty(name)) {
        to.setProperty(name, from[name]);
    }
}

function reconnectSourceMap (inMap, outMap) {
    var mergedRawMap = mergeSourceMap(inMap, outMap.toObject());
    var reMap = convert.fromObject(mergedRawMap);
    overwritePropertyIfExists('sources', inMap, reMap);
    overwritePropertyIfExists('sourceRoot', inMap, reMap);
    overwritePropertyIfExists('sourcesContent', inMap, reMap);
    return reMap;
}

function handleIncomingSourceMap (originalCode) {
    var commented = convert.fromSource(originalCode);
    if (commented) {
        return commented.toObject();
    }
    return null;
}

function applyUnassertWithSourceMap (code, filepath) {
    var ast = acorn.parse(code, {
        sourceType: 'module',
        ecmaVersion: 9,
        locations: true,
        allowHashBang: true
    });
    var inMap = handleIncomingSourceMap(code);
    var instrumented = escodegen.generate(unassert(ast), {
        sourceMap: filepath,
        sourceContent: code,
        sourceMapWithCode: true
    });
    var outMap = convert.fromJSON(instrumented.map.toString());
    if (inMap) {
        var reMap = reconnectSourceMap(inMap, outMap);
        return instrumented.code + '\n' + reMap.toComment() + '\n';
    } else {
        return instrumented.code + '\n' + outMap.toComment() + '\n';
    }
}

function applyUnassertWithoutSourceMap (code) {
    var ast = acorn.parse(code, {
        sourceType: 'module',
        ecmaVersion: 9,
        allowHashBang: true
    });
    return escodegen.generate(unassert(ast));
}

function shouldProduceSourceMap (options) {
    return (options && options._flags && options._flags.debug);
}

module.exports = function unassertify (filepath, options) {
    if (path.extname(filepath) === '.json') {
        return through();
    }

    var data = '',
        stream = through(write, end);

    function write(buf) {
        data += buf;
    }

    function end() {
        if (shouldProduceSourceMap(options)) {
            stream.queue(applyUnassertWithSourceMap(data, filepath));
        } else {
            stream.queue(applyUnassertWithoutSourceMap(data));
        }
        stream.queue(null);
    }

    return stream;
};
<commit_msg>ecmaVersion: 9 → 2018<commit_after>/**
 * unassertify
 *   Browserify transform for unassert
 *     Encourages programming with assertions by providing tools to compile them away.
 *
 * https://github.com/unassert-js/unassertify
 *
 * Copyright (c) 2015-2017 Takuto Wada
 * Licensed under the MIT license.
 *   https://github.com/unassert-js/unassertify/blob/master/LICENSE
 */
'use strict';

var path = require('path');
var through = require('through');
var acorn = require('acorn');
var escodegen = require('escodegen');
var convert = require('convert-source-map');
var transfer = require('multi-stage-sourcemap').transfer;
var unassert = require('unassert');

function mergeSourceMap (incomingSourceMap, outgoingSourceMap) {
    if (typeof outgoingSourceMap === 'string' || outgoingSourceMap instanceof String) {
        outgoingSourceMap = JSON.parse(outgoingSourceMap);
    }
    if (!incomingSourceMap) {
        return outgoingSourceMap;
    }
    return JSON.parse(transfer({fromSourceMap: outgoingSourceMap, toSourceMap: incomingSourceMap}));
}

function overwritePropertyIfExists (name, from, to) {
    if (from.hasOwnProperty(name)) {
        to.setProperty(name, from[name]);
    }
}

function reconnectSourceMap (inMap, outMap) {
    var mergedRawMap = mergeSourceMap(inMap, outMap.toObject());
    var reMap = convert.fromObject(mergedRawMap);
    overwritePropertyIfExists('sources', inMap, reMap);
    overwritePropertyIfExists('sourceRoot', inMap, reMap);
    overwritePropertyIfExists('sourcesContent', inMap, reMap);
    return reMap;
}

function handleIncomingSourceMap (originalCode) {
    var commented = convert.fromSource(originalCode);
    if (commented) {
        return commented.toObject();
    }
    return null;
}

function applyUnassertWithSourceMap (code, filepath) {
    var ast = acorn.parse(code, {
        sourceType: 'module',
        ecmaVersion: 2018,
        locations: true,
        allowHashBang: true
    });
    var inMap = handleIncomingSourceMap(code);
    var instrumented = escodegen.generate(unassert(ast), {
        sourceMap: filepath,
        sourceContent: code,
        sourceMapWithCode: true
    });
    var outMap = convert.fromJSON(instrumented.map.toString());
    if (inMap) {
        var reMap = reconnectSourceMap(inMap, outMap);
        return instrumented.code + '\n' + reMap.toComment() + '\n';
    } else {
        return instrumented.code + '\n' + outMap.toComment() + '\n';
    }
}

function applyUnassertWithoutSourceMap (code) {
    var ast = acorn.parse(code, {
        sourceType: 'module',
        ecmaVersion: 2018,
        allowHashBang: true
    });
    return escodegen.generate(unassert(ast));
}

function shouldProduceSourceMap (options) {
    return (options && options._flags && options._flags.debug);
}

module.exports = function unassertify (filepath, options) {
    if (path.extname(filepath) === '.json') {
        return through();
    }

    var data = '',
        stream = through(write, end);

    function write(buf) {
        data += buf;
    }

    function end() {
        if (shouldProduceSourceMap(options)) {
            stream.queue(applyUnassertWithSourceMap(data, filepath));
        } else {
            stream.queue(applyUnassertWithoutSourceMap(data));
        }
        stream.queue(null);
    }

    return stream;
};
<|endoftext|>