<commit_before>import m from 'mithril';
import { isEmpty } from 'lodash/lang';
import i18n from '../../i18n';
import treePath from './path';
import cevalView from './ceval/cevalView';
import gameApi from '../../lichess/game';
import control from './control';
import menu from './menu';
import continuePopup from '../shared/continuePopup';
import { autoScroll, empty, defined, renderEval, isSynthetic } from './util';
import gameStatusApi from '../../lichess/status';
import variantApi from '../../lichess/variant';
import helper from '../helper';
import layout from '../layout';
import { view as renderPromotion } from './promotion';
import { header } from '../shared/common';
import { renderBoard } from '../round/view/roundView';
import { partialf, playerName, gameIcon } from '../../utils';

export default function analyseView(ctrl) {

  const isPortrait = helper.isPortrait();

  return layout.board(
    header.bind(undefined, i18n('analysis')),
    () => renderContent(ctrl, isPortrait),
    () => overlay(ctrl, isPortrait)
  );
}

function renderContent(ctrl, isPortrait) {
  if (!ctrl.data) return null;

  return [
    renderBoard(ctrl.data.game.variant.key, ctrl.chessground, isPortrait),
    renderTable(ctrl),
    renderActionsBar(ctrl, isPortrait)
  ];
}

function renderTable(ctrl) {
  const className = [
    isSynthetic(ctrl.data) ? 'synthetic' : '',
    'analyseTable'
  ].join(' ');

  return (

        {renderOpeningBox(ctrl)}
        {renderReplay(ctrl)}

      {renderInfos(ctrl)}

  );
}

function renderInfos(ctrl) {
  const cevalAllowed = ctrl.ceval.allowed();
  const cevalEnabled = ctrl.ceval.enabled();
  const ceval = ctrl.currentAnyEval() || {};

  const hash = ctrl.data.game.id + cevalAllowed + cevalEnabled + defined(ceval.cp) +
  defined(ceval.mate) + ctrl.ceval.percentComplete() + isEmpty(ctrl.vm.step.dests);

  if (ctrl.vm.infosHash === hash) return {
    subtree: 'retain'
  };
  ctrl.vm.infosHash = hash;

  return (

      {cevalView.renderCeval(ctrl)}
      { !isSynthetic(ctrl.data) ?

          {gameInfos(ctrl)}
          {renderOpponents(ctrl)}

 : null
      }

  );
}

function renderOpponents(ctrl) {
  if (isSynthetic(ctrl.data)) return null;

  const player = ctrl.data.player;
  const opponent = ctrl.data.opponent;
  if (!player || !opponent) return null;

  return (

        {playerName(player, true)}

        {playerName(opponent, true)}

  );
}

function overlay(ctrl) {
  return [
    renderPromotion(ctrl),
    menu.view(ctrl.menu),
    continuePopup.view(ctrl.continuePopup)
  ];
}

function renderEvalTag(e) {
  return {
    tag: 'eval',
    children: e
  };
}

const emptyMove = <move className="empty">...</move>;

function renderMove(ctrl, move, path) {
  if (!move) return emptyMove;
  const pathStr = treePath.write(path);
  const evaluation = path[1] ? {} : (move.oEval || move.ceval || {});
  const className = [
    pathStr === ctrl.vm.pathStr ? 'current' : '',
    pathStr === ctrl.vm.initialPathStr ? 'initial' : ''
  ].join(' ');
  const jump = helper.ontouchY(() => ctrl.userJump(path));
  return (
    <move className={className} config={jump} data-path={path[1] ? pathStr : ''}>
      {move.san[0] === 'P' ? move.san.slice(1) : move.san}
      {defined(evaluation.cp) ? renderEvalTag(renderEval(evaluation.cp)) : (
        defined(evaluation.mate) ? renderEvalTag('#' + evaluation.mate) : null
      )}
    </move>
  );
}

function plyToTurn(ply) {
  return Math.floor((ply - 1) / 2) + 1;
}

function renderVariationMenu(ctrl, path) {
  const showing = ctrl.vm.variationMenu && ctrl.vm.variationMenu === treePath.write(path.slice(0, 1));

  if (!showing) return null;

  const promotable = isSynthetic(ctrl.data) ||
    !ctrl.analyse.getStepAtPly(path[0].ply).fixed;

  const content = m('div.variationMenu', [
    m('button', {
      className: 'withIcon',
      'data-icon': 'q',
      config: helper.ontouch(partialf(ctrl.deleteVariation, path))
    }, 'Delete variation'),
    promotable ? m('button', {
      className: 'withIcon',
      'data-icon': 'E',
      config: helper.ontouch(partialf(ctrl.promoteVariation, path))
    }, 'Promote to main line') : null
  ]);

  return (

        {content}

  );
}

function renderVariation(ctrl, variation, path, klass) {
  return (

      {renderVariationContent(ctrl, variation, path)}
      {renderVariationMenu(ctrl, path)}

  );
}

function renderVariationNested(ctrl, variation, path) {
  return (

      {'(' + renderVariationContent(ctrl, variation, path) + ')' }

  );
}

function renderVariationContent(ctrl, variation, path) {
  const turns = [];
  if (variation[0].ply % 2 === 0) {
    variation = variation.slice(0);
    const move = variation.shift();
    turns.push({
      turn: plyToTurn(move.ply),
      black: move
    });
  }
  const visiting = treePath.contains(path, ctrl.vm.path);
  const maxPlies = Math.min(visiting ? 999 : (path[2] ? 2 : 4), variation.length);
  for (var i = 0; i < maxPlies; i += 2) turns.push({
    turn: plyToTurn(variation[i].ply),
    white: variation[i],
    black: variation[i + 1]
  });
  return turns.map(turn => renderVariationTurn(ctrl, turn, path));
}

function renderVariationMeta(ctrl, move, path) {
  if (!move || empty(move.variations)) return null;
  return move.variations.map(function(variation, i) {
    return renderVariationNested(ctrl, variation, treePath.withVariation(path, i + 1));
  });
}

function renderVariationTurn(ctrl, turn, path) {
  const wPath = turn.white ? treePath.withPly(path, turn.white.ply) : null;
  const wMove = wPath ? renderMove(ctrl, turn.white, wPath) : null;
  const wMeta = renderVariationMeta(ctrl, turn.white, wPath);
  const bPath = turn.black ? treePath.withPly(path, turn.black.ply) : null;
  const bMove = bPath ? renderMove(ctrl, turn.black, bPath) : null;
  const bMeta = renderVariationMeta(ctrl, turn.black, bPath);
  if (wMove) {
    if (wMeta) return [
        renderIndex(turn.turn + '.'),
        wMove,
        wMeta,
        bMove ? bMove : null,
        bMove ? bMeta : null
    ];
    return [
        renderIndex(turn.turn + '.'),
        wMove,
        bMeta ? ' ' : null,
        bMove ? bMove : null,
        bMove ? bMeta : null
    ];
  }
  return [
      renderIndex(turn.turn + '...'),
      bMove,
      bMeta
  ];
}

function renderOpeningBox(ctrl) {
  const opening = ctrl.data.game.opening;

  const hash = '' + (opening && opening.eco + opening.name);

  if (ctrl.vm.openingHash === hash) return {
    subtree: 'retain'
  };
  ctrl.vm.openingHash = hash;

  if (opening) {
    return (

        {opening.eco}
        {opening.name}

    );
  }
}

function renderMeta(ctrl, move, path) {
  if (!ctrl.vm.comments) return null;

  if (!move || (empty(move.comments) && empty(move.variations))) return null;

  const children = [];
  const colorClass = move.ply % 2 === 0 ? 'black ' : 'white ';
  var commentClass = '';
  if (!empty(move.comments)) move.comments.forEach(function(comment) {
    if (comment.indexOf('Inaccuracy.') === 0) commentClass = 'inaccuracy';
    else if (comment.indexOf('Mistake.') === 0) commentClass = 'mistake';
    else if (comment.indexOf('Blunder.') === 0) commentClass = 'blunder';
    children.push(
comment
);
  });
  if (!empty(move.variations)) move.variations.forEach(function(variation, i) {
    if (empty(variation)) return null;
    children.push(renderVariation(
      ctrl,
      variation,
      treePath.withVariation(path, i + 1),
      i === 0 ? colorClass + commentClass : null
    ));
  });
  return (

{children}

  );
}

function renderIndex(txt) {
  return {
    tag: 'index',
    children: [txt]
  };
}

function renderTurnEl(children) {
  return {
    tag: 'turn',
    children: children
  };
}

function renderTurn(ctrl, turn, path) {
  var index = renderIndex(turn.turn);
  var wPath = turn.white ? treePath.withPly(path, turn.white.ply) : null;
  var wMove = wPath ? renderMove(ctrl, turn.white, wPath) : null;
  var wMeta = renderMeta(ctrl, turn.white, wPath);
  var bPath = turn.black ? treePath.withPly(path, turn.black.ply) : null;
  var bMove = bPath ? renderMove(ctrl, turn.black, bPath) : null;
  var bMeta = renderMeta(ctrl, turn.black, bPath);
  if (wMove) {
    if (wMeta) return [
      renderTurnEl([index, wMove, emptyMove]),
      wMeta,
      bMove ? [
        renderTurnEl([index, emptyMove, bMove]),
        bMeta
      ] : null
    ];
    return [
      renderTurnEl([index, wMove, bMove]),
      bMeta
    ];
  }
  return [
    renderTurnEl([index, emptyMove, bMove]),
    bMeta
  ];
}

function renderTree(ctrl, tree) {
  var turns = [];
  var initPly = ctrl.analyse.firstPly();
  if (initPly % 2 === 0)
    for (var i = 1, nb = tree.length; i < nb; i += 2) turns.push({
      turn: Math.floor((initPly + i) / 2) + 1,
      white: tree[i],
      black: tree[i + 1]
    });
  else {
    turns.push({
      turn: Math.floor(initPly / 2) + 1,
      white: null,
      black: tree[1]
    });
    for (var j = 2, jnb = tree.length; j < jnb; j += 2) turns.push({
      turn: Math.floor((initPly + j) / 2) + 1,
      white: tree[j],
      black: tree[j + 1]
    });
  }

  var path = treePath.default();
  var tags = [];
  for (var k = 0, len = turns.length; k < len; k++)
    tags.push(renderTurn(ctrl, turns[k], path));

  return tags;
}

function renderReplay(ctrl) {

  const hash = ctrl.vm.variationMenu + JSON.stringify(ctrl.vm.path) +
    (ctrl.vm.step.ceval && renderEval(ctrl.vm.step.ceval.cp));

  if (ctrl.vm.replayHash === hash) return {
    subtree: 'retain'
  };

  ctrl.vm.replayHash = hash;

  var result;
  if (ctrl.data.game.status.id >= 30) switch (ctrl.data.game.winner) {
    case 'white':
      result = '1-0';
      break;
    case 'black':
      result = '0-1';
      break;
    default:
      result = '½-½';
  }
  const tree = renderTree(ctrl, ctrl.analyse.tree);
  if (result) {
    tree.push(
{result}
);
    const winner = gameApi.getPlayer(ctrl.data, ctrl.data.game.winner);
    tree.push(

        {gameStatusApi.toLabel(ctrl.data.game.status.name, ctrl.data.game.winner, ctrl.data.game.variant.key)}

        {winner ? i18n(winner.color === 'white' ? 'whiteIsVictorious' : 'blackIsVictorious') : null}

    );
  }
  const config = (el, isUpdate) => {
    if (!isUpdate) setTimeout(autoScroll.bind(undefined, el), 100);
  };

  return (

      {tree}

  );
}

function gameInfos(ctrl) {
  if (isSynthetic(ctrl.data)) return null;

  const data = ctrl.data;
  const time = gameApi.time(data);
  const mode = data.game.rated ? i18n('rated') : i18n('casual');
  const icon = data.opponent.ai ? ':' : gameIcon(data.game.perf);
  const variant = m('span.variant', {
    config: helper.ontouch(
      () => {
        var link = variantApi(data.game.variant.key).link;
        if (link)
          window.open(link, '_blank');
      },
      () => window.plugins.toast.show(data.game.variant.title, 'short', 'center')
    )
  }, data.game.variant.name);
  const infos = [time + ' • ', variant, m('br'), mode];

  return (

      {infos}

  );
}

function buttons(ctrl) {
  return [
    ['first', 'fast-backward', control.first ],
    ['prev', 'backward', control.prev],
    ['next', 'forward', control.next],
    ['last', 'fast-forward', control.last]
    ].map(function(b) {
      const className = [
        'action_bar_button',
        'fa',
        'fa-' + b[1],
        ctrl.broken ? 'disabled' : '',
        ctrl.vm.late && b[0] === 'last' ? 'glow' : ''
        ].join(' ');
        const action = b[0] === 'prev' || b[0] === 'next' ?
          helper.ontouch(() => b[2](ctrl), null, () => b[2](ctrl)) :
          helper.ontouch(() => b[2](ctrl));
        return (
          <button className={className} key={b[1]} config={action} />
        );
    });
}

function renderActionsBar(ctrl, isPortrait) {

  const hash = ctrl.data.game.id + ctrl.broken + ctrl.vm.late + isPortrait;

  if (ctrl.vm.buttonsHash === hash) return {
    subtree: 'retain'
  };
  ctrl.vm.buttonsHash = hash;

  return (

      <button className="action_bar_button fa fa-ellipsis-h" key="analyseMenu"
        config={helper.ontouch(ctrl.menu.open)}
      />
      {buttons(ctrl)}

  );
}
<commit_msg>Fix result<commit_after>import m from 'mithril';
import { isEmpty } from 'lodash/lang';
import i18n from '../../i18n';
import treePath from './path';
import cevalView from './ceval/cevalView';
import gameApi from '../../lichess/game';
import control from './control';
import menu from './menu';
import continuePopup from '../shared/continuePopup';
import { autoScroll, empty, defined, renderEval, isSynthetic } from './util';
import gameStatusApi from '../../lichess/status';
import variantApi from '../../lichess/variant';
import helper from '../helper';
import layout from '../layout';
import { view as renderPromotion } from './promotion';
import { header } from '../shared/common';
import { renderBoard } from '../round/view/roundView';
import { partialf, playerName, gameIcon } from '../../utils';

export default function analyseView(ctrl) {

  const isPortrait = helper.isPortrait();

  return layout.board(
    header.bind(undefined, i18n('analysis')),
    () => renderContent(ctrl, isPortrait),
    () => overlay(ctrl, isPortrait)
  );
}

function renderContent(ctrl, isPortrait) {
  if (!ctrl.data) return null;

  return [
    renderBoard(ctrl.data.game.variant.key, ctrl.chessground, isPortrait),
    renderTable(ctrl),
    renderActionsBar(ctrl, isPortrait)
  ];
}

function renderTable(ctrl) {
  const className = [
    isSynthetic(ctrl.data) ? 'synthetic' : '',
    'analyseTable'
  ].join(' ');

  return (

        {renderOpeningBox(ctrl)}
        {renderReplay(ctrl)}

      {renderInfos(ctrl)}

  );
}

function renderInfos(ctrl) {
  const cevalAllowed = ctrl.ceval.allowed();
  const cevalEnabled = ctrl.ceval.enabled();
  const ceval = ctrl.currentAnyEval() || {};

  const hash = ctrl.data.game.id + cevalAllowed + cevalEnabled + defined(ceval.cp) +
  defined(ceval.mate) + ctrl.ceval.percentComplete() + isEmpty(ctrl.vm.step.dests);

  if (ctrl.vm.infosHash === hash) return {
    subtree: 'retain'
  };
  ctrl.vm.infosHash = hash;

  return (

      {cevalView.renderCeval(ctrl)}
      { !isSynthetic(ctrl.data) ?

          {gameInfos(ctrl)}
          {renderOpponents(ctrl)}

 : null
      }

  );
}

function renderOpponents(ctrl) {
  if (isSynthetic(ctrl.data)) return null;

  const player = ctrl.data.player;
  const opponent = ctrl.data.opponent;
  if (!player || !opponent) return null;

  return (

        {playerName(player, true)}

        {playerName(opponent, true)}

  );
}

function overlay(ctrl) {
  return [
    renderPromotion(ctrl),
    menu.view(ctrl.menu),
    continuePopup.view(ctrl.continuePopup)
  ];
}

function renderEvalTag(e) {
  return {
    tag: 'eval',
    children: e
  };
}

const emptyMove = <move className="empty">...</move>;

function renderMove(ctrl, move, path) {
  if (!move) return emptyMove;
  const pathStr = treePath.write(path);
  const evaluation = path[1] ? {} : (move.oEval || move.ceval || {});
  const className = [
    pathStr === ctrl.vm.pathStr ? 'current' : '',
    pathStr === ctrl.vm.initialPathStr ? 'initial' : ''
  ].join(' ');
  const jump = helper.ontouchY(() => ctrl.userJump(path));
  return (
    <move className={className} config={jump} data-path={path[1] ? pathStr : ''}>
      {move.san[0] === 'P' ? move.san.slice(1) : move.san}
      {defined(evaluation.cp) ? renderEvalTag(renderEval(evaluation.cp)) : (
        defined(evaluation.mate) ? renderEvalTag('#' + evaluation.mate) : null
      )}
    </move>
  );
}

function plyToTurn(ply) {
  return Math.floor((ply - 1) / 2) + 1;
}

function renderVariationMenu(ctrl, path) {
  const showing = ctrl.vm.variationMenu && ctrl.vm.variationMenu === treePath.write(path.slice(0, 1));

  if (!showing) return null;

  const promotable = isSynthetic(ctrl.data) ||
    !ctrl.analyse.getStepAtPly(path[0].ply).fixed;

  const content = m('div.variationMenu', [
    m('button', {
      className: 'withIcon',
      'data-icon': 'q',
      config: helper.ontouch(partialf(ctrl.deleteVariation, path))
    }, 'Delete variation'),
    promotable ? m('button', {
      className: 'withIcon',
      'data-icon': 'E',
      config: helper.ontouch(partialf(ctrl.promoteVariation, path))
    }, 'Promote to main line') : null
  ]);

  return (

        {content}

  );
}

function renderVariation(ctrl, variation, path, klass) {
  return (

      {renderVariationContent(ctrl, variation, path)}
      {renderVariationMenu(ctrl, path)}

  );
}

function renderVariationNested(ctrl, variation, path) {
  return (

      {'(' + renderVariationContent(ctrl, variation, path) + ')' }

  );
}

function renderVariationContent(ctrl, variation, path) {
  const turns = [];
  if (variation[0].ply % 2 === 0) {
    variation = variation.slice(0);
    const move = variation.shift();
    turns.push({
      turn: plyToTurn(move.ply),
      black: move
    });
  }
  const visiting = treePath.contains(path, ctrl.vm.path);
  const maxPlies = Math.min(visiting ? 999 : (path[2] ? 2 : 4), variation.length);
  for (var i = 0; i < maxPlies; i += 2) turns.push({
    turn: plyToTurn(variation[i].ply),
    white: variation[i],
    black: variation[i + 1]
  });
  return turns.map(turn => renderVariationTurn(ctrl, turn, path));
}

function renderVariationMeta(ctrl, move, path) {
  if (!move || empty(move.variations)) return null;
  return move.variations.map(function(variation, i) {
    return renderVariationNested(ctrl, variation, treePath.withVariation(path, i + 1));
  });
}

function renderVariationTurn(ctrl, turn, path) {
  const wPath = turn.white ? treePath.withPly(path, turn.white.ply) : null;
  const wMove = wPath ? renderMove(ctrl, turn.white, wPath) : null;
  const wMeta = renderVariationMeta(ctrl, turn.white, wPath);
  const bPath = turn.black ? treePath.withPly(path, turn.black.ply) : null;
  const bMove = bPath ? renderMove(ctrl, turn.black, bPath) : null;
  const bMeta = renderVariationMeta(ctrl, turn.black, bPath);
  if (wMove) {
    if (wMeta) return [
        renderIndex(turn.turn + '.'),
        wMove,
        wMeta,
        bMove ? bMove : null,
        bMove ? bMeta : null
    ];
    return [
        renderIndex(turn.turn + '.'),
        wMove,
        bMeta ? ' ' : null,
        bMove ? bMove : null,
        bMove ? bMeta : null
    ];
  }
  return [
      renderIndex(turn.turn + '...'),
      bMove,
      bMeta
  ];
}

function renderOpeningBox(ctrl) {
  const opening = ctrl.data.game.opening;

  const hash = '' + (opening && opening.eco + opening.name);

  if (ctrl.vm.openingHash === hash) return {
    subtree: 'retain'
  };
  ctrl.vm.openingHash = hash;

  if (opening) {
    return (

        {opening.eco}
        {opening.name}

    );
  }
}

function renderMeta(ctrl, move, path) {
  if (!ctrl.vm.comments) return null;

  if (!move || (empty(move.comments) && empty(move.variations))) return null;

  const children = [];
  const colorClass = move.ply % 2 === 0 ? 'black ' : 'white ';
  var commentClass = '';
  if (!empty(move.comments)) move.comments.forEach(function(comment) {
    if (comment.indexOf('Inaccuracy.') === 0) commentClass = 'inaccuracy';
    else if (comment.indexOf('Mistake.') === 0) commentClass = 'mistake';
    else if (comment.indexOf('Blunder.') === 0) commentClass = 'blunder';
    children.push(
comment
);
  });
  if (!empty(move.variations)) move.variations.forEach(function(variation, i) {
    if (empty(variation)) return null;
    children.push(renderVariation(
      ctrl,
      variation,
      treePath.withVariation(path, i + 1),
      i === 0 ? colorClass + commentClass : null
    ));
  });
  return (

{children}

  );
}

function renderIndex(txt) {
  return {
    tag: 'index',
    children: [txt]
  };
}

function renderTurnEl(children) {
  return {
    tag: 'turn',
    children: children
  };
}

function renderTurn(ctrl, turn, path) {
  var index = renderIndex(turn.turn);
  var wPath = turn.white ? treePath.withPly(path, turn.white.ply) : null;
  var wMove = wPath ? renderMove(ctrl, turn.white, wPath) : null;
  var wMeta = renderMeta(ctrl, turn.white, wPath);
  var bPath = turn.black ? treePath.withPly(path, turn.black.ply) : null;
  var bMove = bPath ? renderMove(ctrl, turn.black, bPath) : null;
  var bMeta = renderMeta(ctrl, turn.black, bPath);
  if (wMove) {
    if (wMeta) return [
      renderTurnEl([index, wMove, emptyMove]),
      wMeta,
      bMove ? [
        renderTurnEl([index, emptyMove, bMove]),
        bMeta
      ] : null
    ];
    return [
      renderTurnEl([index, wMove, bMove]),
      bMeta
    ];
  }
  return [
    renderTurnEl([index, emptyMove, bMove]),
    bMeta
  ];
}

function renderTree(ctrl, tree) {
  var turns = [];
  var initPly = ctrl.analyse.firstPly();
  if (initPly % 2 === 0)
    for (var i = 1, nb = tree.length; i < nb; i += 2) turns.push({
      turn: Math.floor((initPly + i) / 2) + 1,
      white: tree[i],
      black: tree[i + 1]
    });
  else {
    turns.push({
      turn: Math.floor(initPly / 2) + 1,
      white: null,
      black: tree[1]
    });
    for (var j = 2, jnb = tree.length; j < jnb; j += 2) turns.push({
      turn: Math.floor((initPly + j) / 2) + 1,
      white: tree[j],
      black: tree[j + 1]
    });
  }

  var path = treePath.default();
  var tags = [];
  for (var k = 0, len = turns.length; k < len; k++)
    tags.push(renderTurn(ctrl, turns[k], path));

  return tags;
}

function renderReplay(ctrl) {

  const hash = ctrl.vm.variationMenu + JSON.stringify(ctrl.vm.path) +
    (ctrl.vm.step.ceval && renderEval(ctrl.vm.step.ceval.cp));

  if (ctrl.vm.replayHash === hash) return {
    subtree: 'retain'
  };

  ctrl.vm.replayHash = hash;

  var result;
  if (ctrl.data.game.status.id >= 30) switch (ctrl.data.game.winner) {
    case 'white':
      result = '1-0';
      break;
    case 'black':
      result = '0-1';
      break;
    default:
      result = '½-½';
  }
  const tree = renderTree(ctrl, ctrl.analyse.tree);
  if (result) {
    tree.push(
{result}
);
    const winner = gameApi.getPlayer(ctrl.data, ctrl.data.game.winner);
    tree.push(

        {gameStatusApi.toLabel(ctrl.data.game.status.name, ctrl.data.game.winner, ctrl.data.game.variant.key)}

        {winner ? '. ' + i18n(winner.color === 'white' ? 'whiteIsVictorious' : 'blackIsVictorious') + '.' : null}

    );
  }
  const config = (el, isUpdate) => {
    if (!isUpdate) setTimeout(autoScroll.bind(undefined, el), 100);
  };

  return (

      {tree}

  );
}

function gameInfos(ctrl) {
  if (isSynthetic(ctrl.data)) return null;

  const data = ctrl.data;
  const time = gameApi.time(data);
  const mode = data.game.rated ? i18n('rated') : i18n('casual');
  const icon = data.opponent.ai ? ':' : gameIcon(data.game.perf);
  const variant = m('span.variant', {
    config: helper.ontouch(
      () => {
        var link = variantApi(data.game.variant.key).link;
        if (link)
          window.open(link, '_blank');
      },
      () => window.plugins.toast.show(data.game.variant.title, 'short', 'center')
    )
  }, data.game.variant.name);
  const infos = [time + ' • ', variant, m('br'), mode];

  return (

      {infos}

  );
}

function buttons(ctrl) {
  return [
    ['first', 'fast-backward', control.first ],
    ['prev', 'backward', control.prev],
    ['next', 'forward', control.next],
    ['last', 'fast-forward', control.last]
    ].map(function(b) {
      const className = [
        'action_bar_button',
        'fa',
        'fa-' + b[1],
        ctrl.broken ? 'disabled' : '',
        ctrl.vm.late && b[0] === 'last' ? 'glow' : ''
        ].join(' ');
        const action = b[0] === 'prev' || b[0] === 'next' ?
          helper.ontouch(() => b[2](ctrl), null, () => b[2](ctrl)) :
          helper.ontouch(() => b[2](ctrl));
        return (
          <button className={className} key={b[1]} config={action} />
        );
    });
}

function renderActionsBar(ctrl, isPortrait) {

  const hash = ctrl.data.game.id + ctrl.broken + ctrl.vm.late + isPortrait;

  if (ctrl.vm.buttonsHash === hash) return {
    subtree: 'retain'
  };
  ctrl.vm.buttonsHash = hash;

  return (

      <button className="action_bar_button fa fa-ellipsis-h" key="analyseMenu"
        config={helper.ontouch(ctrl.menu.open)}
      />
      {buttons(ctrl)}

  );
}
<|endoftext|>


<commit_before>import {NotFoundError, NetworkError, BadRequestError} from "./errors";

let URI = require("URIjs");
let URITemplate = require("URIjs").URITemplate;

let axios = require("axios");
var EventSource = (typeof window === 'undefined') ? require('eventsource') : window.EventSource;
let toBluebird = require("bluebird").resolve;
let _ = require('lodash');

/**
* @class Builder
*/
export class CallBuilder {

  /*
  * @constructor
  */
  constructor(url) {
    this.url = url;
    this.filter = [];
  }

  checkFilter() {
    if (this.filter.length >= 2) {
      throw new BadRequestError("Too many filters specified", this.filter);
    }
    if (this.filter.length === 1) {
      this.url.segment(this.filter[0]);
    }
  }

  /*
  * Triggers a HTTP request using this builder's current configuration.
  * Returns a Promise that resolves to the server's response.
  */
  call() {
    this.checkFilter();
    var promise = this._sendNormalRequest(this.url)
      .then(r => this._parseResponse(r));
    return promise;
  }

  /*
  * Creates an Eventsource that listens for incoming messages from the server.
  * URL based on builder's current configuration.
  */
  stream(options) {
    this.checkFilter();
    var es = new EventSource(this.url.toString());
    es.onmessage = (message) => {
      var result = message.data ? this._parseRecord(JSON.parse(message.data)) : message;
      options.onmessage(result);
    };
    es.onerror = options.onerror;
    return es;
  }

  _requestFnForLink(link) {
    return opts => {
      if (link.template) {
        let template = URITemplate(link.href);
        return self._sendNormalRequest(URI(template.expand(opts))
          .authority(self.url.authority())
          .protocol(self.url.protocol())
          );
      } else {
        return self._sendNormalRequest(URI(link.href)
          .authority(self.url.authority())
          .protocol(self.url.protocol())
          );
      }
    };
  }

  /**
  * Convert each link into a function on the response object.
  */
  _parseRecord(json) {
    if (!json._links) {
      return json;
    }
    _.mapKeys(json._links, (val, key) => {json[key] = this._requestFnForLink(val);});
    return json;
  }

  _sendNormalRequest(url) {
    url.addQuery('c', Math.random());
    var promise = axios.get(url.toString())
      .then(response => response.data)
      .catch(this._handleNetworkError);
    return toBluebird(promise);
  }

  _parseResponse(json) {
    if (json._embedded && json._embedded.records) {
      return this._toCollectionPage(json);
    } else {
      return this._parseRecord(json);
    }
  }

  _toCollectionPage(json) {
    for (var i = 0; i < json._embedded.records.length; i++) {
      json._embedded.records[i] = this._parseRecord(json._embedded.records[i]);
    }
    return {
      records: json._embedded.records,
      next: () => {
        return this._sendNormalRequest(URI(json._links.next.href)
          .authority(this.url.authority())
          .protocol(this.url.protocol())
          )
          .then(r => this._toCollectionPage(r));
      },
      prev: () => {
        return this._sendNormalRequest(URI(json._links.prev.href)
          .authority(this.url.authority())
          .protocol(this.url.protocol())
          )
          .then(r => this._toCollectionPage(r));
      }
    };
  }

  _handleNetworkError(response) {
    if (response instanceof Error) {
      return Promise.reject(response);
    } else {
      switch (response.status) {
        case 404:
          return Promise.reject(new NotFoundError(response.data, response));
        default:
          return Promise.reject(new NetworkError(response.status, response));
      }
    }
  }

  cursor(token) {
    this.url.addQuery("cursor", token);
    return this;
  }

  limit(number) {
    this.url.addQuery("limit", number);
    return this;
  }

  order(direction) {
    this.url.addQuery("order", direction);
    return this;
  }

}<commit_msg>Changed _.mapKeys for _.forEach.<commit_after>import {NotFoundError, NetworkError, BadRequestError} from "./errors";

let URI = require("URIjs");
let URITemplate = require("URIjs").URITemplate;

let axios = require("axios");
var EventSource = (typeof window === 'undefined') ? require('eventsource') : window.EventSource;
let toBluebird = require("bluebird").resolve;
let _ = require('lodash');

/**
* @class Builder
*/
export class CallBuilder {

  /*
  * @constructor
  */
  constructor(url) {
    this.url = url;
    this.filter = [];
  }

  checkFilter() {
    if (this.filter.length >= 2) {
      throw new BadRequestError("Too many filters specified", this.filter);
    }
    if (this.filter.length === 1) {
      this.url.segment(this.filter[0]);
    }
  }

  /*
  * Triggers a HTTP request using this builder's current configuration.
  * Returns a Promise that resolves to the server's response.
  */
  call() {
    this.checkFilter();
    var promise = this._sendNormalRequest(this.url)
      .then(r => this._parseResponse(r));
    return promise;
  }

  /*
  * Creates an Eventsource that listens for incoming messages from the server.
  * URL based on builder's current configuration.
  */
  stream(options) {
    this.checkFilter();
    var es = new EventSource(this.url.toString());
    es.onmessage = (message) => {
      var result = message.data ? this._parseRecord(JSON.parse(message.data)) : message;
      options.onmessage(result);
    };
    es.onerror = options.onerror;
    return es;
  }

  _requestFnForLink(link) {
    return opts => {
      if (link.template) {
        let template = URITemplate(link.href);
        return self._sendNormalRequest(URI(template.expand(opts))
          .authority(self.url.authority())
          .protocol(self.url.protocol())
          );
      } else {
        return self._sendNormalRequest(URI(link.href)
          .authority(self.url.authority())
          .protocol(self.url.protocol())
          );
      }
    };
  }

  /**
  * Convert each link into a function on the response object.
  */
  _parseRecord(json) {
    if (!json._links) {
      return json;
    }
    _.forEach(json._links, (n, key) => {json[key] = this._requestFnForLink(n);});
    return json;
  }

  _sendNormalRequest(url) {
    url.addQuery('c', Math.random());
    var promise = axios.get(url.toString())
      .then(response => response.data)
      .catch(this._handleNetworkError);
    return toBluebird(promise);
  }

  _parseResponse(json) {
    if (json._embedded && json._embedded.records) {
      return this._toCollectionPage(json);
    } else {
      return this._parseRecord(json);
    }
  }

  _toCollectionPage(json) {
    for (var i = 0; i < json._embedded.records.length; i++) {
      json._embedded.records[i] = this._parseRecord(json._embedded.records[i]);
    }
    return {
      records: json._embedded.records,
      next: () => {
        return this._sendNormalRequest(URI(json._links.next.href)
          .authority(this.url.authority())
          .protocol(this.url.protocol())
          )
          .then(r => this._toCollectionPage(r));
      },
      prev: () => {
        return this._sendNormalRequest(URI(json._links.prev.href)
          .authority(this.url.authority())
          .protocol(this.url.protocol())
          )
          .then(r => this._toCollectionPage(r));
      }
    };
  }

  _handleNetworkError(response) {
    if (response instanceof Error) {
      return Promise.reject(response);
    } else {
      switch (response.status) {
        case 404:
          return Promise.reject(new NotFoundError(response.data, response));
        default:
          return Promise.reject(new NetworkError(response.status, response));
      }
    }
  }

  cursor(token) {
    this.url.addQuery("cursor", token);
    return this;
  }

  limit(number) {
    this.url.addQuery("limit", number);
    return this;
  }

  order(direction) {
    this.url.addQuery("order", direction);
    return this;
  }

}<|endoftext|>


<commit_before>const botgram = require("botgram");
const { json } = require("req");
const cron = require('node-cron');
const cowsay = require("cowsay");
const bot = botgram(process.argv[2]);
const rants = require("./rants.json");
const feature = "This feature is either under construction or i'm too retarded to implement it";
const cow = `

         (__)
         (oo)
   /------\\/
  / |    ||
 *  /\\---/\\
    ~~   ~~
...."Have you mooed today?"...
`;

bot.text(function (msg, reply, next) {
    const text = msg.text.toLowerCase();
    if(text.includes("linux") && !text.includes("gnu"))
		    reply.reply(msg).text(rants.linux[Math.floor(Math.random()*rants.linux.length)]);
    if(text.includes("raphy") && !text.includes("faggot"))
		    reply.reply(msg).text(rants.raphy[Math.floor(Math.random()*rants.raphy.length)]);
    if(text.includes("fighting games"))
        reply.reply(msg).text("fuck off with your gay fighting games nigger");
    if(text.includes("😂"))
        reply.reply(msg).text("fuck off faggot");
    if(text == undefined)
        reply.text("unknown error");
});

bot.command("start", function (msg, reply, next) {
    if(msg.args().includes("moo"))
        reply.text(cow, 'HTML');
    reply.text("fuck off");
});

bot.command("price", function (msg, reply, next) {
    if(msg.args().includes("moo"))
        reply.text(cow, 'HTML');
    const coin = msg.args();
    let crap;
    json("https://api.coinmarketcap.com/v1/ticker/")
        .then(data => crap = data)
        .then(()=> {
            let balls = crap.find(obj => obj.symbol === coin.toUpperCase());
            if(balls == undefined)
                reply.text("give me a valid symbol retard");
            reply.text(balls.name + ": " + balls.price_usd + "$");
        });
});

bot.command("weather", function (msg, reply, next) {
    if(msg.args().includes("moo"))
        reply.text(cow, 'HTML');
    const K = 273.15;
    const city = msg.args();
    let link = `http://api.openweathermap.org/data/2.5/weather?q=${city}&APPID=1566ed87c9944f0df94332da29ee817c`;
    let ass;
    let icon;
    json(link)
        .then(data => {
            switch(data.weather[0].icon) {
            case "01d":
                icon = "☀";
                break;
            case "01n":
                icon = "🌕";
                break;
            case "02d":
            case "02n":
                icon = "🌤";
                break;
            case "03d":
            case "03n":
                icon = "⛅";
                break;
            case "04d":
            case "04n":
                icon = "☁";
                break;
            case "09d":
            case "09n":
                icon = "🌧";
                break;
            case "10d":
            case "10n":
                icon = "🌦";
                break;
            case "11d":
            case "11n":
                icon = "🌩";
                break;
            case "13d":
            case "13n":
                icon = "🌨";
                break;
            case "50d":
            case "50n":
                icon = "🌫";
                break;
            }
            reply.text(`Weather in ${data.name}, ${data.sys.country}: ${Math.floor(data.main.temp - K)}°C, ${data.weather[0].description} ` + icon + `
 Humidity: ${Math.floor(data.main.humidity)}%
 Air pressure: ${Math.floor(data.main.pressure)} hPa
`);
        });
});

bot.command("skelet", function (msg, reply, next) {
    if(msg.args().includes("moo"))
        reply.text(cow, 'HTML');
    let skelets = "";
    for (let i = 0; i < Math.floor((Math.random() * 20) + 1 ); i++)
        skelets += Math.random() < 0.5 ? '💀' : '☠';
    reply.text(skelets);
});

bot.command("cowsay", function (msg, reply, next) {
    const moo = msg.args();
    if(moo == undefined || moo == "moo")
        reply.text(cowsay.say({
            text : "Have you mooed today?"
        }));
    else
        reply.text(cowsay.say({
            text : moo
        }));
});

bot.command("papiez", function (msg, reply, next) {
    if(msg.args().includes("moo"))
        reply.text(cow, 'HTML');
    reply.video("https://vignette4.wikia.nocookie.net/nonsensopedia/images/c/cf/Patron.gif/revision/latest?cb=20130929184445");
});

bot.all(function (msg, reply, next) {
    cron.schedule("37 21 * * *", function() {
        reply.video("https://vignette4.wikia.nocookie.net/nonsensopedia/images/c/cf/Patron.gif/revision/latest?cb=20130929184445");
        reply.text("testing cron");
    });
});

bot.command("moo", function (msg, reply, next) {
    reply.text(cow)
});

bot.command(function (msg, reply, next) {
    reply.text("invalid command dumbass");
  });
<commit_msg>switch order for further testing<commit_after>const botgram = require("botgram");
const { json } = require("req");
const cron = require('node-cron');
const cowsay = require("cowsay");
const bot = botgram(process.argv[2]);
const rants = require("./rants.json");
const feature = "This feature is either under construction or i'm too retarded to implement it";
const cow = `

         (__)
         (oo)
   /------\\/
  / |    ||
 *  /\\---/\\
    ~~   ~~
...."Have you mooed today?"...
`;

bot.text(function (msg, reply, next) {
    const text = msg.text.toLowerCase();
    if(text.includes("linux") && !text.includes("gnu"))
		    reply.reply(msg).text(rants.linux[Math.floor(Math.random()*rants.linux.length)]);
    if(text.includes("raphy") && !text.includes("faggot"))
		    reply.reply(msg).text(rants.raphy[Math.floor(Math.random()*rants.raphy.length)]);
    if(text.includes("fighting games"))
        reply.reply(msg).text("fuck off with your gay fighting games nigger");
    if(text.includes("😂"))
        reply.reply(msg).text("fuck off faggot");
    if(text == undefined)
        reply.text("unknown error");
});

bot.command("start", function (msg, reply, next) {
    if(msg.args().includes("moo"))
        reply.text(cow, 'HTML');
    reply.text("fuck off");
});

bot.command("price", function (msg, reply, next) {
    if(msg.args().includes("moo"))
        reply.text(cow, 'HTML');
    const coin = msg.args();
    let crap;
    json("https://api.coinmarketcap.com/v1/ticker/")
        .then(data => crap = data)
        .then(()=> {
            let balls = crap.find(obj => obj.symbol === coin.toUpperCase());
            if(balls == undefined)
                reply.text("give me a valid symbol retard");
            reply.text(balls.name + ": " + balls.price_usd + "$");
        });
});

bot.command("weather", function (msg, reply, next) {
    if(msg.args().includes("moo"))
        reply.text(cow, 'HTML');
    const K = 273.15;
    const city = msg.args();
    let link = `http://api.openweathermap.org/data/2.5/weather?q=${city}&APPID=1566ed87c9944f0df94332da29ee817c`;
    let ass;
    let icon;
    json(link)
        .then(data => {
            switch(data.weather[0].icon) {
            case "01d":
                icon = "☀";
                break;
            case "01n":
                icon = "🌕";
                break;
            case "02d":
            case "02n":
                icon = "🌤";
                break;
            case "03d":
            case "03n":
                icon = "⛅";
                break;
            case "04d":
            case "04n":
                icon = "☁";
                break;
            case "09d":
            case "09n":
                icon = "🌧";
                break;
            case "10d":
            case "10n":
                icon = "🌦";
                break;
            case "11d":
            case "11n":
                icon = "🌩";
                break;
            case "13d":
            case "13n":
                icon = "🌨";
                break;
            case "50d":
            case "50n":
                icon = "🌫";
                break;
            }
            reply.text(`Weather in ${data.name}, ${data.sys.country}: ${Math.floor(data.main.temp - K)}°C, ${data.weather[0].description} ` + icon + `
 Humidity: ${Math.floor(data.main.humidity)}%
 Air pressure: ${Math.floor(data.main.pressure)} hPa
`);
        });
});

bot.command("skelet", function (msg, reply, next) {
    if(msg.args().includes("moo"))
        reply.text(cow, 'HTML');
    let skelets = "";
    for (let i = 0; i < Math.floor((Math.random() * 20) + 1 ); i++)
        skelets += Math.random() < 0.5 ? '💀' : '☠';
    reply.text(skelets);
});

bot.command("cowsay", function (msg, reply, next) {
    const moo = msg.args();
    if(moo == undefined || moo == "moo")
        reply.text(cowsay.say({
            text : "Have you mooed today?"
        }));
    else
        reply.text(cowsay.say({
            text : moo
        }));
});

bot.command("papiez", function (msg, reply, next) {
    if(msg.args().includes("moo"))
        reply.text(cow, 'HTML');
    reply.video("https://vignette4.wikia.nocookie.net/nonsensopedia/images/c/cf/Patron.gif/revision/latest?cb=20130929184445");
});

bot.command("moo", function (msg, reply, next) {
    reply.text(cow)
});

bot.command(function (msg, reply, next) {
    reply.text("invalid command dumbass");
});

bot.all(function (msg, reply, next) {
    cron.schedule("37 21 * * *", function() {
        reply.video("https://vignette4.wikia.nocookie.net/nonsensopedia/images/c/cf/Patron.gif/revision/latest?cb=20130929184445");
        reply.text("testing cron");
    });
});
<|endoftext|>


<commit_before>/**
 * Start the girder backbone app.
 */
$(function () {
    girder.events.trigger('g:appload.before');
    var app = new girder.App({});
    girder.events.trigger('g:appload.after');
});

describe('Test collection actions', function () {

    it('register a user (first is admin)',
        girderTest.createUser('admin',
                              'admin@email.com',
                              'Admin',
                              'Admin',
                              'adminpassword!'));

    it('go to collections page', function () {
        $("a.g-nav-link[g-target='collections']").click();

        waitsFor(function () {
            return $('.g-collection-create-button').length > 0;
        }, 'navigate to collections page');

        expect($('.g-collection-list-entry').length).toBe(0);
    });

    it('create a collection',
        girderTest.createCollection('collName0', 'coll Desc 0'));

    it('go back to collections page', function () {
        $("a.g-nav-link[g-target='collections']").click();

        waitsFor(function () {
            return $('.g-collection-create-button').length > 0;
        }, 'navigate to collections page');

        waitsFor(function () {
            return $('.g-collection-list-entry').text().match('collName0').length > 0;
        }, 'new collection to appear');

    });

    it('create another collection',
        girderTest.createCollection('collName1', 'coll Desc 1'));

    it('make new collection public', function () {
        runs(function () {
            $('.g-collection-actions-button').click();
        });

        waitsFor(function () {
            return $('.g-collection-access-control').length > 0;
        }, 'access control menu item to appear');

        runs(function () {
            $('.g-collection-access-control').click();
        });

        waitsFor(function () {
            return $('#g-access-public').length > 0;
        }, 'pulic access radio button to appear');

        runs(function () {
            $('#g-access-public').click();
        });

        waitsFor(function () {
            return $('.g-save-access-list').length > 0;
        }, 'access save button to appear');

        runs(function () {
            $('.g-save-access-list').click();
        });
    });

    it('go back to collections page again', function () {
        $("a.g-nav-link[g-target='collections']").click();

        waitsFor(function () {
            return $('.g-collection-create-button').length > 0;
        }, 'navigate to collections page');

        waitsFor(function () {
            return $('.g-collection-list-entry').text().match('collName1').length > 0;
        }, 'new collection to appear');

    });

    it('logout to become anonymous', girderTest.logout());

    it('check if public collection is viewable (and ensure private is not)', function () {
        waitsFor(function () {
            return $('.g-collection-list-entry').text().match('collName1').length > 0;
        }, 'new collection to appear');

        expect($('.g-collection-list-entry').text()).not.toContain('collName0');
    });

});
<commit_msg>My phantom and Travis disagree. I _think_ this is better.<commit_after>/**
 * Start the girder backbone app.
 */
$(function () {
    girder.events.trigger('g:appload.before');
    var app = new girder.App({});
    girder.events.trigger('g:appload.after');
});

describe('Test collection actions', function () {

    it('register a user (first is admin)',
        girderTest.createUser('admin',
                              'admin@email.com',
                              'Admin',
                              'Admin',
                              'adminpassword!'));

    it('go to collections page', function () {
        $("a.g-nav-link[g-target='collections']").click();

        waitsFor(function () {
            return $('.g-collection-create-button').length > 0;
        }, 'navigate to collections page');

        expect($('.g-collection-list-entry').length).toBe(0);
    });

    it('create a collection',
        girderTest.createCollection('collName0', 'coll Desc 0'));

    it('go back to collections page', function () {
        $("a.g-nav-link[g-target='collections']").click();

        waitsFor(function () {
            return $('.g-collection-create-button').length > 0;
        }, 'navigate to collections page');

        waitsFor(function () {
            return $('.g-collection-list-entry').text().match('collName0').length > 0;
        }, 'new collection to appear');

    });

    it('create another collection',
        girderTest.createCollection('collName1', 'coll Desc 1'));

    it('make new collection public', function () {
        runs(function () {
            $('.g-collection-actions-button').click();
        });

        waitsFor(function () {
            return $('.g-collection-access-control').length > 0;
        }, 'access control menu item to appear');

        runs(function () {
            $('.g-collection-access-control').click();
        });

        waitsFor(function () {
            return $('#g-access-public').length > 0;
        }, 'pulic access radio button to appear');

        runs(function () {
            $('#g-access-public').click();
        });

        waitsFor(function () {
            return $('.g-save-access-list').length > 0;
        }, 'access save button to appear');

        runs(function () {
            $('.g-save-access-list').click();
        });
    });

    it('go back to collections page again', function () {
        $("a.g-nav-link[g-target='collections']").click();

        waitsFor(function () {
            return $('.g-collection-create-button').length > 0;
        }, 'navigate to collections page');

        waitsFor(function () {
            return $('.g-collection-list-entry').text().match('collName1').length > 0;
        }, 'new collection to appear');

    });

    it('logout to become anonymous', girderTest.logout());

    it('check if public collection is viewable (and ensure private is not)', function () {
        waitsFor(function () {
            return $('.g-collection-list-entry').length > 0;
        }, 'new collection to appear');

        expect($('.g-collection-list-entry').text()).not.toContain('collName0');
        expect($('.g-collection-list-entry').text()).toContain('collName1');
    });

});
<|endoftext|>


<commit_before>/* eslint-disable new-cap */

const express = require('express');
const router = express.Router();

const handlers = require('./handlers');
const able = require('georap-able').middleware;
const commentIdParser = require('./lib/commentIdParser');
const jsonParser = require('body-parser').json();

router.post('/', able('comments-create'), jsonParser, handlers.create);

router.post('/:commentId', able('comments-create'), commentIdParser,
            jsonParser, handlers.change);

// Deletion has internal permission handling
router.delete('/:commentId', commentIdParser,
              jsonParser, handlers.remove);

module.exports = router;
<commit_msg>Simplify commentIdParser usage<commit_after>/* eslint-disable new-cap */

const express = require('express');
const router = express.Router();

const handlers = require('./handlers');
const able = require('georap-able').middleware;
const commentIdParser = require('./lib/commentIdParser');
const jsonParser = require('body-parser').json();

router.post('/', able('comments-create'), jsonParser, handlers.create);

router.use('/:commentId', commentIdParser);

router.post('/:commentId', able('comments-create'),
            jsonParser, handlers.change);
// Deletion has internal permission handling
router.delete('/:commentId', jsonParser, handlers.remove);

module.exports = router;
<|endoftext|>


<commit_before>var Plurb = require('../db/dbconfig').Plurb;
var User = require('../db/dbconfig').User;

module.exports = {
  //currently not being used
  getAllPlurbs: function (req, res) {
    Plurb.findAll({})
    .then(function (plurbs) {
      res.status(200).json(plurbs);
    })
    .catch(function (err) {
      console.error(err);
    });
  },

  createPlurb: function (req, res) {
    var googId = req.session.user;
    var topicId = req.body.topicId;
    //make a db call using the googid and returns user data
    User.find({where:
      {googid: googId}
    })
    .then(function (user) {
      //set the values for first and last names, picture
      //put all data into an objected used to create plurb
      var plurbData = {
        text: req.body.text,
        lat: req.body.lat,
        long: req.body.long,
        firstName: user.dataValues.firstName,
        lastName: user.dataValues.lastName,
        picture: user.dataValues.picture
      };
      Plurb.create(plurbData)
      .then(function (plurb) {
        //sets the foreign key of googId and topicId
        plurb.setUser(googId);
        plurb.setTopic(topicId);
        res.status(201).json(plurb);
      })
      .catch(function (err) {
        console.error(err);
      });
    });
  },

  getPlurb: function (req, res) {
    var plurbId = req.params.plurbId;
    Plurb.findById(plurbId)
    .then(function (plurb) {
      res.status(200).json(plurb);
    })
    .catch(function (err) {
      console.error(err);
    });
  },

  deletePlurb: function (req, res) {
    var plurbId = req.params.plurbId;
    Plurb.destroy({where: {id: plurbId}})
    .then(function () {
      res.status(201);
    })
    .catch(function (err) {
      console.error(err);
    });
  },

  getPlurbsByGoogId: function (req, res) {
    var googId = req.params.googId;
    Plurb.findAll({where: {UserGoogid: googId}})
    .then(function (plurbs) {
      res.status(200).json(plurbs);
    })
    .catch(function (err) {
      console.error(err);
    });
  },

  getPlurbsByLocation: function (req, res) {
    var googId = req.body.googId;
    var topicId = req.body.topicId;
    var minLat = req.body.mapBounds.minLat;
    var maxLat = req.body.mapBounds.maxLat;
    var minLng = req.body.mapBounds.minLng;
    var maxLng = req.body.mapBounds.maxLng;
    var query = {};
  //builds query object based off the presences of googId and/or topicId
    if(!topicId && !googId) {
  //if topic id is 0 and there is no googId, send back all plurbs in that location regardless of topic
      query = {
        where: {
          lat: {$between: [minLat, maxLat]},
          long: {$between: [minLng, maxLng]}
        }
      };
    } else if (!topicId) {
      query = {
        where: {
          lat: {$between: [minLat, maxLat]},
          long: {$between: [minLng, maxLng]},
          UserGoogid: googId
        }
      };
    } else if (!googId) {
      query = {
        where: {
          lat: {$between: [minLat, maxLat]},
          long: {$between: [minLng, maxLng]},
          TopicId: topicId,
        }
      };
    } else {
      query = {
        where: {
          lat: {$between: [minLat, maxLat]},
          long: {$between: [minLng, maxLng]},
          TopicId: topicId,
          UserGoogid: googId
        }
      };
    }

    Plurb.findAll(query)
    .then(function (plurbs) {
      res.status(200).json(plurbs);
    })
    .catch(function (err) {
      console.error (err);
    });
  },

  getAllFriendsAllPlurbs: function (req, res) {
    var googId = req.session.user;
    var friendsGoogIds = [];

    //Create array of all friends googIds
    User.find({where: {googid: googId}})
    .then(function(user) {
      //this built in Sequelize method will pull all friends
      user.getFriends()
       .then(function(friends){
        friends.forEach(function(friend) {
          //push each friend googid to the array
          friendsGoogIds.push(Number(friend.dataValues.googid));
        });
       })
       .then(function(){
        //find all plurbs that have the friend googIds as UserGoogId (meaning they authored the plurb)
          Plurb.findAll({
            where: {
              $or: [
                {UserGoogid: friendsGoogIds}
              ]
            }
          })
            .then(function (plurbs) {
              res.status(200).json(plurbs);
            })
            .catch(function (err) {
              console.error(err);
            });
       });
    })
    .catch(function (err) {
      console.error(err);
    });
  }
};
<commit_msg>(feat) Will eager load Topic on getAllPlurbs method<commit_after>var Plurb = require('../db/dbconfig').Plurb;
var User = require('../db/dbconfig').User;
var Topic = require('../db/dbconfig').Topic;

module.exports = {
  getAllPlurbs: function (req, res) {
    Plurb.findAll({
       include: [Topic]
    })
    .then(function (plurbs) {
      res.status(200).json(plurbs);
    })
    .catch(function (err) {
      console.error(err);
    });
  },

  createPlurb: function (req, res) {
    var googId = req.session.user;
    var topicId = req.body.topicId;
    //make a db call using the googid and returns user data
    User.find({where:
      {googid: googId}
    })
    .then(function (user) {
      //set the values for first and last names, picture
      //put all data into an objected used to create plurb
      var plurbData = {
        text: req.body.text,
        lat: req.body.lat,
        long: req.body.long,
        firstName: user.dataValues.firstName,
        lastName: user.dataValues.lastName,
        picture: user.dataValues.picture
      };
      Plurb.create(plurbData)
      .then(function (plurb) {
        //sets the foreign key of googId and topicId
        plurb.setUser(googId);
        plurb.setTopic(topicId);
        res.status(201).json(plurb);
      })
      .catch(function (err) {
        console.error(err);
      });
    });
  },

  getPlurb: function (req, res) {
    var plurbId = req.params.plurbId;
    Plurb.findById(plurbId)
    .then(function (plurb) {
      res.status(200).json(plurb);
    })
    .catch(function (err) {
      console.error(err);
    });
  },

  deletePlurb: function (req, res) {
    var plurbId = req.params.plurbId;
    Plurb.destroy({where: {id: plurbId}})
    .then(function () {
      res.status(201);
    })
    .catch(function (err) {
      console.error(err);
    });
  },

  getPlurbsByGoogId: function (req, res) {
    var googId = req.params.googId;
    Plurb.findAll({where: {UserGoogid: googId}})
    .then(function (plurbs) {
      res.status(200).json(plurbs);
    })
    .catch(function (err) {
      console.error(err);
    });
  },

  getPlurbsByLocation: function (req, res) {
    var googId = req.body.googId;
    var topicId = req.body.topicId;
    var minLat = req.body.mapBounds.minLat;
    var maxLat = req.body.mapBounds.maxLat;
    var minLng = req.body.mapBounds.minLng;
    var maxLng = req.body.mapBounds.maxLng;
    var query = {};
  //builds query object based off the presences of googId and/or topicId
    if(!topicId && !googId) {
  //if topic id is 0 and there is no googId, send back all plurbs in that location regardless of topic
      query = {
        where: {
          lat: {$between: [minLat, maxLat]},
          long: {$between: [minLng, maxLng]}
        }
      };
    } else if (!topicId) {
      query = {
        where: {
          lat: {$between: [minLat, maxLat]},
          long: {$between: [minLng, maxLng]},
          UserGoogid: googId
        }
      };
    } else if (!googId) {
      query = {
        where: {
          lat: {$between: [minLat, maxLat]},
          long: {$between: [minLng, maxLng]},
          TopicId: topicId,
        }
      };
    } else {
      query = {
        where: {
          lat: {$between: [minLat, maxLat]},
          long: {$between: [minLng, maxLng]},
          TopicId: topicId,
          UserGoogid: googId
        }
      };
    }

    Plurb.findAll(query)
    .then(function (plurbs) {
      res.status(200).json(plurbs);
    })
    .catch(function (err) {
      console.error (err);
    });
  },

  getAllFriendsAllPlurbs: function (req, res) {
    var googId = req.session.user;
    var friendsGoogIds = [];

    //Create array of all friends googIds
    User.find({where: {googid: googId}})
    .then(function(user) {
      //this built in Sequelize method will pull all friends
      user.getFriends()
       .then(function(friends){
        friends.forEach(function(friend) {
          //push each friend googid to the array
          friendsGoogIds.push(Number(friend.dataValues.googid));
        });
       })
       .then(function(){
        //find all plurbs that have the friend googIds as UserGoogId (meaning they authored the plurb)
          Plurb.findAll({
            where: {
              $or: [
                {UserGoogid: friendsGoogIds}
              ]
            }
          })
            .then(function (plurbs) {
              res.status(200).json(plurbs);
            })
            .catch(function (err) {
              console.error(err);
            });
       });
    })
    .catch(function (err) {
      console.error(err);
    });
  }
};
<|endoftext|>


<commit_before>var Lexer = require('../board/functions/lexer');

module.exports = function() {
  var Types = Object.freeze({
    coord: "A coordinate must be two numbers separated by a comma",
    radius: "A radius here must be a positive number",
    pixel:  "A size in pixels is defined by a positive number",
    text:   "",
    axis:   "An axis must be either 'X' or 'Y', case-sensitive",
    figure: "A figure should begin with an uppercase letter and a number",
    value:  "A value an amount in 'x,y', similar to coordinates",
    degrees: "Here a degrees must always be a positive number"
  });
  $(document).on('focusout keyup', '[data-type]', function() {
    var value = $(this).val(),
        type  = $(this).attr('data-type'),
        failed,
        lexer;
    switch(type) {
      case 'coord':
      case 'value':
        if (value.indexOf(',') === -1) {
          failed = Types[type];
        }
        value = value.split(',');
        if (!$.isNumeric(value[0]) || !$.isNumeric(value[1])) {
          failed = Types[type];
        }
        break;
      case 'radius':
      case 'pixel':
      case 'degrees':
        if (parseInt(value) < 0 || ! $.isNumeric(value)) {
          failed = Types[type]
        }
        break;
      case 'axis':
        if (value !== 'X' && value !== 'Y') {
          failed = Types[type];
        }
        break;
      case 'figure':
        lexer = new Lexer(value);
        // expect a label and EOF.
        var tokens = [lexer.getNextToken(), lexer.getNextToken()];
        if (tokens[0] != 10 || tokens[1] != 11) {
          failed = Types[type];
        }
        break;
    }
    if (typeof failed !== 'undefined') {
      $(this).attr('data-error', failed);
      failed = undefined;
    } else {
      $(this).removeAttr('data-error');
    }
  });
};<commit_msg>improve language in validation messages<commit_after>var Lexer = require('../board/functions/lexer');

module.exports = function() {
  var Types = Object.freeze({
    coord: "A coordinate must be an ordered pair separated by a comma",
    radius: "A radius here must be a positive number",
    pixel:  "A size in pixels is defined by a positive number",
    text:   "",
    axis:   "An axis must be either 'X' or 'Y', case-sensitive",
    figure: "A figure should begin with an uppercase letter and an integer",
    value:  "A value is an ordered pair e.g. 'x,y', similar to coordinates",
    degrees: "Here a degrees must always be a positive number"
  });
  $(document).on('focusout keyup', '[data-type]', function() {
    var value = $(this).val(),
        type  = $(this).attr('data-type'),
        failed,
        lexer;
    switch(type) {
      case 'coord':
      case 'value':
        if (value.indexOf(',') === -1) {
          failed = Types[type];
        }
        value = value.split(',');
        if (!$.isNumeric(value[0]) || !$.isNumeric(value[1])) {
          failed = Types[type];
        }
        break;
      case 'radius':
      case 'pixel':
      case 'degrees':
        if (parseInt(value) < 0 || ! $.isNumeric(value)) {
          failed = Types[type]
        }
        break;
      case 'axis':
        if (value !== 'X' && value !== 'Y') {
          failed = Types[type];
        }
        break;
      case 'figure':
        lexer = new Lexer(value);
        // expect a label and EOF.
        var tokens = [lexer.getNextToken(), lexer.getNextToken()];
        if (tokens[0] != 10 || tokens[1] != 11) {
          failed = Types[type];
        }
        break;
    }
    if (typeof failed !== 'undefined') {
      $(this).attr('data-error', failed);
      failed = undefined;
    } else {
      $(this).removeAttr('data-error');
    }
  });
};<|endoftext|>


<commit_before>/*global $, window, Color */
$.fn.commandLineWidget = function (keyBinding, mapModel) {
	'use strict';
	var element = this;
	element.keyup(keyBinding, function () {
		var input,
			valid = function (color, name) {
				name = name.toUpperCase();
				return color &&
						(color.hexString().toUpperCase() === name.toUpperCase() ||
						(color.keyword() && color.keyword().toUpperCase() === name.toUpperCase()));
			},
			hide = function () {
				if (input) {
					input.remove();
				}
				mapModel.setInputEnabled(true);
			},
			commit = function () {
				/*jslint newcap:true*/
				var value = input && input.val(),
					color = value && Color(value.toLowerCase());
				if (valid(color, value)) {
					mapModel.updateStyle('cmdline', 'background', color.hexString());
				}
				hide();
			},
			colors = [
				"aliceblue",
				"antiquewhite",
				"aqua",
				"aquamarine",
				"azure",
				"beige",
				"bisque",
				"black",
				"blanchedalmond",
				"blue",
				"blueviolet",
				"brown",
				"burlywood",
				"cadetblue",
				"chartreuse",
				"chocolate",
				"coral",
				"cornflowerblue",
				"cornsilk",
				"crimson",
				"cyan",
				"darkblue",
				"darkcyan",
				"darkgoldenrod",
				"darkgray",
				"darkgreen",
				"darkkhaki",
				"darkmagenta",
				"darkolivegreen",
				"darkorange",
				"darkorchid",
				"darkred",
				"darksalmon",
				"darkseagreen",
				"darkslateblue",
				"darkslategray",
				"darkturquoise",
				"darkviolet",
				"deeppink",
				"deepskyblue",
				"dimgray",
				"dodgerblue",
				"firebrick",
				"floralwhite",
				"forestgreen",
				"fuchsia",
				"gainsboro",
				"ghostwhite",
				"gold",
				"goldenrod",
				"gray",
				"green",
				"greenyellow",
				"honeydew",
				"hotpink",
				"indianred",
				"indigo",
				"ivory",
				"khaki",
				"lavender",
				"lavenderblush",
				"lawngreen",
				"lemonchiffon",
				"lightblue",
				"lightcoral",
				"lightcyan",
				"lightgoldenrodyellow",
				"lightgray",            // IE6 breaks on this color
				"lightgreen",
				"lightpink",
				"lightsalmon",
				"lightseagreen",
				"lightskyblue",
				"lightslategray",
				"lightsteelblue",
				"lightyellow",
				"lime",
				"limegreen",
				"linen",
				"magenta",
				"maroon",
				"mediumaquamarine",
				"mediumblue",
				"mediumorchid",
				"mediumpurple",
				"mediumseagreen",
				"mediumslateblue",
				"mediumspringgreen",
				"mediumturquoise",
				"mediumvioletred",
				"midnightblue",
				"mintcream",
				"mistyrose",
				"moccasin",
				"navajowhite",
				"navy",
				"oldlace",
				"olive",
				"olivedrab",
				"orange",
				"orangered",
				"orchid",
				"palegoldenrod",
				"palegreen",
				"paleturquoise",
				"palevioletred",
				"papayawhip",
				"peachpuff",
				"peru",
				"pink",
				"plum",
				"powderblue",
				"purple",
				"red",
				"rosybrown",
				"royalblue",
				"saddlebrown",
				"salmon",
				"sandybrown",
				"seagreen",
				"seashell",
				"sienna",
				"silver",
				"skyblue",
				"slateblue",
				"slategray",
				"snow",
				"springgreen",
				"steelblue",
				"tan",
				"teal",
				"thistle",
				"tomato",
				"turquoise",
				"violet",
				"wheat",
				"white",
				"whitesmoke",
				"yellow",
				"yellowgreen"
			];
		mapModel.setInputEnabled(false);
		input  = $('<input type="text" placeholder="Type a color name or hex…">')
			.css('position', 'absolute')
			.css('z-index', '9999')
			.appendTo(element)
			.css('top', '30%')
			.css('left', '40%')
			.css('width', '20%')
			.css('border-width', '5px')
			.focus()
			.blur(hide)
			.keyup("Esc", hide)
			.change(commit)
			.typeahead({
				source: colors
			});
	});
	return element;
}
<commit_msg>workflow fix for the cmdline widget<commit_after>/*global $, window, Color */
$.fn.commandLineWidget = function (keyBinding, mapModel) {
	'use strict';
	var element = this;
	element.keyup(keyBinding, function () {
		var input,
			valid = function (color, name) {
				name = name.toUpperCase();
				return color &&
						(color.hexString().toUpperCase() === name.toUpperCase() ||
						(color.keyword() && color.keyword().toUpperCase() === name.toUpperCase()));
			},
			hide = function () {
				if (input) {
					input.remove();
				}
				mapModel.setInputEnabled(true);
			},
			commit = function () {
				/*jslint newcap:true*/
				var value = input && input.val(),
					color = value && Color(value.toLowerCase());
				hide();
				if (valid(color, value)) {
					mapModel.updateStyle('cmdline', 'background', color.hexString());
				}
			},
			colors = [
				"aliceblue",
				"antiquewhite",
				"aqua",
				"aquamarine",
				"azure",
				"beige",
				"bisque",
				"black",
				"blanchedalmond",
				"blue",
				"blueviolet",
				"brown",
				"burlywood",
				"cadetblue",
				"chartreuse",
				"chocolate",
				"coral",
				"cornflowerblue",
				"cornsilk",
				"crimson",
				"cyan",
				"darkblue",
				"darkcyan",
				"darkgoldenrod",
				"darkgray",
				"darkgreen",
				"darkkhaki",
				"darkmagenta",
				"darkolivegreen",
				"darkorange",
				"darkorchid",
				"darkred",
				"darksalmon",
				"darkseagreen",
				"darkslateblue",
				"darkslategray",
				"darkturquoise",
				"darkviolet",
				"deeppink",
				"deepskyblue",
				"dimgray",
				"dodgerblue",
				"firebrick",
				"floralwhite",
				"forestgreen",
				"fuchsia",
				"gainsboro",
				"ghostwhite",
				"gold",
				"goldenrod",
				"gray",
				"green",
				"greenyellow",
				"honeydew",
				"hotpink",
				"indianred",
				"indigo",
				"ivory",
				"khaki",
				"lavender",
				"lavenderblush",
				"lawngreen",
				"lemonchiffon",
				"lightblue",
				"lightcoral",
				"lightcyan",
				"lightgoldenrodyellow",
				"lightgray",            // IE6 breaks on this color
				"lightgreen",
				"lightpink",
				"lightsalmon",
				"lightseagreen",
				"lightskyblue",
				"lightslategray",
				"lightsteelblue",
				"lightyellow",
				"lime",
				"limegreen",
				"linen",
				"magenta",
				"maroon",
				"mediumaquamarine",
				"mediumblue",
				"mediumorchid",
				"mediumpurple",
				"mediumseagreen",
				"mediumslateblue",
				"mediumspringgreen",
				"mediumturquoise",
				"mediumvioletred",
				"midnightblue",
				"mintcream",
				"mistyrose",
				"moccasin",
				"navajowhite",
				"navy",
				"oldlace",
				"olive",
				"olivedrab",
				"orange",
				"orangered",
				"orchid",
				"palegoldenrod",
				"palegreen",
				"paleturquoise",
				"palevioletred",
				"papayawhip",
				"peachpuff",
				"peru",
				"pink",
				"plum",
				"powderblue",
				"purple",
				"red",
				"rosybrown",
				"royalblue",
				"saddlebrown",
				"salmon",
				"sandybrown",
				"seagreen",
				"seashell",
				"sienna",
				"silver",
				"skyblue",
				"slateblue",
				"slategray",
				"snow",
				"springgreen",
				"steelblue",
				"tan",
				"teal",
				"thistle",
				"tomato",
				"turquoise",
				"violet",
				"wheat",
				"white",
				"whitesmoke",
				"yellow",
				"yellowgreen"
			];
		mapModel.setInputEnabled(false);
		input  = $('<input type="text" placeholder="Type a color name or hex…">')
			.css('position', 'absolute')
			.css('z-index', '9999')
			.appendTo(element)
			.css('top', '30%')
			.css('left', '40%')
			.css('width', '20%')
			.css('border-width', '5px')
			.focus()
			.blur(hide)
			.keyup("Esc", hide)
			.change(commit)
			.typeahead({
				source: colors
			});
	});
	return element;
}
<|endoftext|>


<commit_before>"use strict";

var request = require("request");
var path = require("path");

var HttpError = require("../../lib/http-error");

module.exports = function(config, req, res, next) {
  var oauth = config.oauth;
  var cryptr = config.cryptr;
  var locale = req.session.locale;
  var authURL = `${oauth.authorization_url}/login/oauth/access_token`;

  res.set("Cache-Control", "no-cache");

  if (req.query.logout) {
    req.session = null;
    return res.redirect(307, path.join("/", locale));
  }

  if (!req.query.code) {
    res.status(401);
    return next(
      HttpError.format({
        message: "OAuth code was not set by the authentication server",
        context: req.query
      }, req)
    );
  }

  if (!req.cookies.state || !req.query.state) {
    res.status(401);
    return next(
      HttpError.format({
        message: "No state information was passed back by the authentication server",
        context: req.query
      }, req)
    );
  }

  if (req.cookies.state !== req.query.state) {
    res.status(401);
    return next(
      HttpError.format({
        message: "The initial state during login does not match the state returned by the authentication server.",
        context: req.query
      }, req)
    );
  }

  if (req.query.client_id !== oauth.client_id) {
    res.status(401);
    return next(
      HttpError.format({
        message: "The client id returned by the authentication server does not match Thimble's client id.",
        context: req.query
      }, req)
    );
  }

  // First, fetch the token
  request.post({
    url: authURL,
    form: {
      client_id: oauth.client_id,
      client_secret: oauth.client_secret,
      grant_type: "authorization_code",
      code: req.query.code
    }
  }, function(err, response, body) {
    if (err) {
      res.status(500);
      return next(
        HttpError.format({
          message: `Failed to send request to ${authURL}. Verify that the authentication server is up and running.`,
          context: err
        }, req)
      );
    }

    if (response.statusCode !== 200) {
      res.status(response.statusCode);
      return next(
        HttpError.format({
          message: `Request to ${authURL} returned a status of ${response.statusCode}`,
          context: response.body
        }, req)
      );
    }

    try {
      body = JSON.parse(body);
    } catch(e) {
      res.status(500);
      return next(
        HttpError.format({
          message: "Data (access token) sent by the authentication server was in an invalid format. Failed to run `JSON.parse`",
          context: e.message,
          stack: e.stack
        }, req)
      );
    }

    req.session.token = cryptr.encrypt(body.access_token);

    var userURL = `${oauth.authorization_url}/user`;

    // Next, fetch user data
    request.get({
      url: userURL,
      headers: {
        "Authorization": "token " + body.access_token
      }
    }, function(err, response, body) {
      if (err) {
        res.status(500);
        return next(
          HttpError.format({
            message: `Failed to send request to ${userURL}. Verify that the authentication server is up and running.`,
            context: err
          }, req)
        );
      }

      if (response.statusCode !== 200) {
        res.status(response.statusCode);
        return next(
          HttpError.format({
            message: `Request to ${userURL} returned a status of ${response.statusCode}`,
            context: response.body
          }, req)
        );
      }

      try {
        req.session.user = JSON.parse(body);
      } catch(e) {
        res.status(500);
        return next(
          HttpError.format({
            message: "User data sent by the authentication server was in an invalid format. Failed to run `JSON.parse`",
            context: e.message,
            stack: e.stack
          }, req)
        );
      }

      // Was this sign-in triggered from the home page?
      if (req.session.home) {
        delete req.session.home;
        return res.redirect(301, path.join("/", locale));
      }

      res.redirect(301, path.join("/", locale, "/editor"));
    });
  });
};
<commit_msg>Fixes #1760 (#1809)<commit_after>"use strict";

var request = require("request");
var path = require("path");

var HttpError = require("../../lib/http-error");

module.exports = function(config, req, res, next) {
  var oauth = config.oauth;
  var cryptr = config.cryptr;
  var locale = req.session.locale;
  var authURL = `${oauth.authorization_url}/login/oauth/access_token`;

  res.set("Cache-Control", "no-cache");

  if (req.query.logout) {
    req.session = null;
    return res.redirect(307, path.join("/", locale));
  }

  if (!req.query.code) {
    res.status(401);
    return next(
      HttpError.format({
        message: "OAuth code was not set by the authentication server",
        context: req.query
      }, req)
    );
  }

  if (!req.cookies.state || !req.query.state) {
    res.status(401);
    return next(
      HttpError.format({
        message: "No state information was passed back by the authentication server",
        context: req.query
      }, req)
    );
  }

  if (req.cookies.state !== req.query.state) {
    res.status(401);
    return next(
      HttpError.format({
        message: "The initial state during login does not match the state returned by the authentication server.",
        context: req.query
      }, req)
    );
  }

  if (req.query.client_id !== oauth.client_id) {
    res.status(401);
    return next(
      HttpError.format({
        message: "The client id returned by the authentication server does not match Thimble's client id.",
        context: req.query
      }, req)
    );
  }

  // First, fetch the token
  request.post({
    url: authURL,
    form: {
      client_id: oauth.client_id,
      client_secret: oauth.client_secret,
      grant_type: "authorization_code",
      code: req.query.code
    }
  }, function(err, response, body) {
    if (err) {
      res.status(500);
      return next(
        HttpError.format({
          message: `Failed to send request to ${authURL}. Verify that the authentication server is up and running.`,
          context: err
        }, req)
      );
    }

    if (response.statusCode !== 200) {
      res.status(response.statusCode);
      return next(
        HttpError.format({
          message: `Request to ${authURL} returned a status of ${response.statusCode}`,
          context: response.body
        }, req)
      );
    }

    try {
      body = JSON.parse(body);
    } catch(e) {
      res.status(500);
      return next(
        HttpError.format({
          message: "Data (access token) sent by the authentication server was in an invalid format. Failed to run `JSON.parse`",
          context: e.message,
          stack: e.stack
        }, req)
      );
    }

    req.session.token = cryptr.encrypt(body.access_token);

    var userURL = `${oauth.authorization_url}/user`;

    // Next, fetch user data
    request.get({
      url: userURL,
      headers: {
        "Authorization": "token " + body.access_token
      }
    }, function(err, response, body) {
      if (err) {
        res.status(500);
        return next(
          HttpError.format({
            message: `Failed to send request to ${userURL}. Verify that the authentication server is up and running.`,
            context: err
          }, req)
        );
      }

      if (response.statusCode !== 200) {
        res.status(response.statusCode);
        return next(
          HttpError.format({
            message: `Request to ${userURL} returned a status of ${response.statusCode}`,
            context: response.body
          }, req)
        );
      }

      try {
        req.session.user = JSON.parse(body);
      } catch(e) {
        res.status(500);
        return next(
          HttpError.format({
            message: "User data sent by the authentication server was in an invalid format. Failed to run `JSON.parse`",
            context: e.message,
            stack: e.stack
          }, req)
        );
      }

      res.redirect(301, path.join("/", locale, "/editor"));
    });
  });
};
<|endoftext|>


<commit_before>var timechart;
var timechart2;

var getItemForTagForDay = function(tag, day) {
	$.getJSON('/api/1/me/items/' + tag + '/' + day + '/', function(items) {
		$('#comments').empty();
		$.each(items, function(i, item) {
			var date = moment(parseInt(item.timestamp)).format('MMMM Do YYYY, HH:mm:ss');
			var comment = item.comment;
			$('#comments').append('
' + date + '	' + tag + '	' + comment + '
');
		});
	});
};

var createTimeChart2 = function(tag, data) {

	var seriesOptions = [];
	seriesOptions[0]  = {
			name : tag,
			data : data.counts,
			tooltip: {
				valueDecimals: 0
			}
		};

	seriesOptions[1]  = {
			name : tag + ' failures',
			data : data.failures,
			tooltip: {
				valueDecimals: 0
			}
		};

	timechart2 = new Highcharts.StockChart({
		chart : {
			renderTo : 'container'
		},

		plotOptions: {
	        series: {
	            cursor: 'pointer',
	            events: {
	                click: function(event) {
	                    console.log(event.point);
	                    var time = event.point.x;
	                    getItemForTagForDay(tag, time);
	                }
	            }
	        }
	    },

		rangeSelector : {
			selected : 1
		},

		title : {
			text : ''
		},

		series : seriesOptions
	});
};

var createTimeChart = function() {
	var data = {
		  "xScale": "time",
		  "yScale": "linear",
		  "type": "line",
		  "main": [
		    {
		      "data": null
		    }
		  ]
		};

	var opts = {
	  "dataFormatX": function (x) { return d3.time.format('%Y-%m-%d').parse(x); },
	  "tickFormatX": function (x) { return d3.time.format('%A')(x); }
	};

	timechart = new xChart('line', data, '#procedurebytag', opts);
};

var getItemsForTag = function() {

	var tag = $("#tag").val();
	$('#procedure').text(tag);
	$('#total').text('42');
	//$('#average').text('4');

	$.getJSON('/api/1/me/analyse/items/' + tag, function(responseData) {
		createTimeChart2(tag, responseData);
	});

};

var getItems = function(done) {

	$.getJSON('/api/1/me/analyse/items', function(items) {
		$.each(items, function(i, item) {
			var tag = item.x;
			$('#tag').append('<option value="' + tag + '">' + tag + '</option>');
		});

		done();
	});

};

var documentReady = function() {
	$(document).ready(function() {

		getItems(getItemsForTag);

		$('#tag').change(function() {
			getItemsForTag();
		});
	});
};<commit_msg>set comments for current day on page load<commit_after>var timechart;
var timechart2;

var getItemForTagForDay = function(tag, day) {
	$.getJSON('/api/1/me/items/' + tag + '/' + day + '/', function(items) {
		$('#comments').empty();
		$.each(items, function(i, item) {
			var date = moment(parseInt(item.timestamp)).format('MMMM Do YYYY, HH:mm:ss');
			var comment = item.comment;
			$('#comments').append('
' + date + '	' + tag + '	' + comment + '
');
		});
	});
};

var createTimeChart2 = function(tag, data) {

	var seriesOptions = [];
	seriesOptions[0]  = {
			name : tag,
			data : data.counts,
			tooltip: {
				valueDecimals: 0
			}
		};

	seriesOptions[1]  = {
			name : tag + ' failures',
			data : data.failures,
			tooltip: {
				valueDecimals: 0
			}
		};

	timechart2 = new Highcharts.StockChart({
		chart : {
			renderTo : 'container'
		},

		plotOptions: {
	        series: {
	            cursor: 'pointer',
	            events: {
	                click: function(event) {
	                    console.log(event.point);
	                    var time = event.point.x;
	                    getItemForTagForDay(tag, time);
	                }
	            }
	        }
	    },

		rangeSelector : {
			selected : 1
		},

		title : {
			text : ''
		},

		series : seriesOptions
	});
};

var createTimeChart = function() {
	var data = {
		  "xScale": "time",
		  "yScale": "linear",
		  "type": "line",
		  "main": [
		    {
		      "data": null
		    }
		  ]
		};

	var opts = {
	  "dataFormatX": function (x) { return d3.time.format('%Y-%m-%d').parse(x); },
	  "tickFormatX": function (x) { return d3.time.format('%A')(x); }
	};

	timechart = new xChart('line', data, '#procedurebytag', opts);
};

var getItemsForTag = function() {

	var tag = $("#tag").val();
	$('#procedure').text(tag);
	$('#total').text('42');
	//$('#average').text('4');

	$.getJSON('/api/1/me/analyse/items/' + tag, function(responseData) {
		createTimeChart2(tag, responseData);
	});

};

var getItems = function(done) {

	$.getJSON('/api/1/me/analyse/items', function(items) {
		$.each(items, function(i, item) {
			var tag = item.x;
			$('#tag').append('<option value="' + tag + '">' + tag + '</option>');
		});

		// Set comments for today
		var firsttag = items[0].x;
		getItemForTagForDay(firsttag, new Date().getTime());

		done();
	});

};

var documentReady = function() {
	$(document).ready(function() {

		getItems(getItemsForTag);

		$('#tag').change(function() {
			getItemsForTag();
		});
	});
};<|endoftext|>


<commit_before>var socket = io.connect();

socket.on('notifyComcastQuery', function() {
    $(".loader").show();
    $(".fa-refresh").addClass("fa-spin");
    $("#refresh").prop("disabled",true);
});

socket.on('updateComcastQuery', function(data) {
    $(".loader").hide();
    $(".fa-refresh").removeClass("fa-spin");
    $("#refresh").prop("disabled",false);
    updateStats(data);
});

socket.on('updateComcastQueryStatus', function(data) {
    $('nav .loader').html(data);
});

function daysRemaining() {
    var date = new Date();
    var firstofNextMonth = new Date(date.getFullYear(), date.getMonth() + 1, 1);
    var timeDiff = Math.abs(firstofNextMonth.getTime() - date.getTime());
    return Math.ceil(timeDiff / (1000 * 3600 * 24));
}

function updateStats(data) {
    var alertOptions;
    var percent = 100 * data.totalUsed / dataCap;
    var percentInt = Math.round(percent);
    if (percent >= 100) {
        percent = 100;
        var overageCost = Math.ceil((data.totalUsed - dataCap + 1) / 50) * 10;
        alertOptions = {
            color: '#D71328',
            label: 'over limit',
            charges: overageCost >= 200 ? 200 : overageCost,
            chargesDisplay: 'initial'
        }
    } else {
        alertOptions = {
            color: '#292b2c',
            label: 'remaining',
            charges: 0,
            chargesDisplay: 'none'
        }
    }

    $("#percent").html(percentInt + "%");
    $("#details").css("color", alertOptions.color);
    $("#data_used").html(data.totalUsed);
    $("#data_remainder").html(Math.abs(data.totalUsed - dataCap));
    $("#data_remainder_label").html(alertOptions.label);
    $("#data_overage_charges").html(alertOptions.charges);
    $("#data_overage_charges_row").css("display", alertOptions.chargesDisplay);
    $("#days_remaining").html(daysRemaining());
}

function gimme30() {
    var array = [];
    var m = new Date().getMonth();
	var y = new Date().getYear();
	var daysInMonth = new Date(y, m, 0).getDate();
    for (var i = 1; i <= daysInMonth; i++) {
        array.push(m + '/' + i)
    }
    return array;
}

function setChartSize() {
	var size = [$(".jumbotron-fluid .container").css("width"), $(".jumbotron-fluid").css("height")]
	if ($(window).width() >= 576) size[0] = parseInt(size[0].slice(0, -2)) - 30 + 'px';
	size[1] = parseInt(size[1].slice(0, -2)) + 10 + 'px';
	$(".chart-container").width(size[0]);
	$(".chart-container").height(size[1]);
}

$(document).ready(function() {
	var cumulativeUse = [];
	var recordedDate = j = dailyUsageData[0]._id - 2;
	for (var i = 0; i < recordedDate; i++) {
		cumulativeUse[i] = 0;
		if (dailyUsageData[i]) cumulativeUse[j] = dailyUsageData[i].totalUsed;
		j++;
	}

    var data = {
        labels: gimme30(),
        datasets: [{
            type: 'line',
            fill: true,
            backgroundColor: 'rgb(215, 19, 40)',
            borderColor: 'rgba(0, 0, 0, 0)',
            borderWidth: 0,
            data: cumulativeUse
        }]
    };

    var options = {
        scales: {
            xAxes: [{
                ticks: {
                    display: false
                },
                gridLines: {
                    display: false,
                    drawBorder: false
                }
            }],
            yAxes: [{
                ticks: {
                    display: false,
                    beginAtZero:true,
                    max: 1024
                },
                gridLines: {
                    display: false,
                    drawBorder: false
                }
            }]
        },
        legend: {
            display: false
        },
        elements: {
            point: {
                radius: 0
            }
        },
		maintainAspectRatio: false
    };

	setChartSize();

    var ctx = $("#chart");

    var chart = new Chart(ctx, {
        type: 'line',
        data: data,
        options: options
    });
});

function requestComcastQuery() {
    socket.emit('requestComcastQuery', null, function(data) {
        updateStats(data);
    });
}

$(window).resize(function() {
	setChartSize();
});

$("#refresh").click(function() {
    requestComcastQuery();
});
<commit_msg>Cleanup<commit_after>var socket = io.connect();

$("#refresh").click(function() {
    socket.emit('requestComcastQuery', null, function(data) {
        updateStats(data);
    });
});

socket.on('notifyComcastQuery', function() {
    $(".loader").show();
    $(".fa-refresh").addClass("fa-spin");
    $("#refresh").prop("disabled",true);
});

socket.on('updateComcastQuery', function(data) {
    $(".loader").hide();
    $(".fa-refresh").removeClass("fa-spin");
    $("#refresh").prop("disabled",false);
    updateStats(data);
});

socket.on('updateComcastQueryStatus', function(data) {
    $('nav .loader').html(data);
});

function daysRemaining() {
    var date = new Date();
    var firstofNextMonth = new Date(date.getFullYear(), date.getMonth() + 1, 1);
    var timeDiff = Math.abs(firstofNextMonth.getTime() - date.getTime());
    return Math.ceil(timeDiff / (1000 * 3600 * 24));
}

function updateStats(data) {
    var alertOptions;
    var percent = 100 * data.totalUsed / dataCap;
    var percentInt = Math.round(percent);
    if (percent >= 100) {
        percent = 100;
        var overageCost = Math.ceil((data.totalUsed - dataCap + 1) / 50) * 10;
        alertOptions = {
            color: '#D71328',
            label: 'over limit',
            charges: overageCost >= 200 ? 200 : overageCost,
            chargesDisplay: 'initial'
        }
    } else {
        alertOptions = {
            color: '#292b2c',
            label: 'remaining',
            charges: 0,
            chargesDisplay: 'none'
        }
    }

    $("#percent").html(percentInt + "%");
    $("#details").css("color", alertOptions.color);
    $("#data_used").html(data.totalUsed);
    $("#data_remainder").html(Math.abs(data.totalUsed - dataCap));
    $("#data_remainder_label").html(alertOptions.label);
    $("#data_overage_charges").html(alertOptions.charges);
    $("#data_overage_charges_row").css("display", alertOptions.chargesDisplay);
    $("#days_remaining").html(daysRemaining());
}

function gimme30() {
    var array = [];
    var m = new Date().getMonth();
	var y = new Date().getYear();
	var daysInMonth = new Date(y, m, 0).getDate();
    for (var i = 1; i <= daysInMonth; i++) {
        array.push(m + '/' + i)
    }
    return array;
}

function setChartSize() {
	var size = [$(".jumbotron-fluid .container").css("width"), $(".jumbotron-fluid").css("height")]
	if ($(window).width() >= 576) size[0] = parseInt(size[0].slice(0, -2)) - 30 + 'px';
	size[1] = parseInt(size[1].slice(0, -2)) + 10 + 'px';
	$(".chart-container").width(size[0]);
	$(".chart-container").height(size[1]);
}

$(document).ready(function() {
	var cumulativeUse = [];
	var recordedDate = j = dailyUsageData[0]._id - 2;
	for (var i = 0; i < recordedDate; i++) {
		cumulativeUse[i] = 0;
		if (dailyUsageData[i]) cumulativeUse[j] = dailyUsageData[i].totalUsed;
		j++;
	}

    var data = {
        labels: gimme30(),
        datasets: [{
            type: 'line',
            fill: true,
            backgroundColor: 'rgb(215, 19, 40)',
            borderColor: 'rgba(0, 0, 0, 0)',
            borderWidth: 0,
            data: cumulativeUse
        }]
    };

    var options = {
        scales: {
            xAxes: [{
                ticks: {
                    display: false
                },
                gridLines: {
                    display: false,
                    drawBorder: false
                }
            }],
            yAxes: [{
                ticks: {
                    display: false,
                    beginAtZero:true,
                    max: 1024
                },
                gridLines: {
                    display: false,
                    drawBorder: false
                }
            }]
        },
        legend: {
            display: false
        },
        elements: {
            point: {
                radius: 0
            }
        },
		maintainAspectRatio: false
    };

	setChartSize();

    var ctx = $("#chart");

    var chart = new Chart(ctx, {
        type: 'line',
        data: data,
        options: options
    });
});

$(window).resize(function() {
	setChartSize();
});
<|endoftext|>