<commit_before>(function() {
  'use strict';

  angular.module('civic.sources')
    .directive('sourceGrid', sourceGrid)
    .controller('SourceGridController', SourceGridController);

  // @ngInject
  function sourceGrid() {
    var directive = {
      restrict: 'E',
      replace: true,
      scope: {
        sources: '=',
        rows: '=',
        context:'='
      },
      templateUrl: 'app/views/sources/components/sourceGrid.tpl.html',
      controller: 'SourceGridController'
    };
    return directive;
  }

  // @ngInject
  function SourceGridController($scope,
                                $state,
                                $window,
                                $filter,
                                uiGridExporterConstants,
                                uiGridConstants,
                                _) {
    console.log('SourceGridController Loaded.');

    var ctrl = $scope.ctrl = {};

    ctrl.exportPopover = {
      templateUrl: 'app/views/events/common/gridExportPopover.tpl.html',
      title: 'Save CSV',
      include: 'all',
      type: 'csv'
    };

    ctrl.rowsToShow = $scope.rows ? $scope.rows : 10;
    ctrl.sourceGridOptions = {
      minRowsToShow: ctrl.rowsToShow - 1,
      //enablePaginationControls: true,
      //paginationPageSizes: [8],
      //paginationPageSize: 8,
      enablePaging: false,

      enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
      enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
      enableFiltering: true,
      enableColumnMenus: false,
      enableSorting: true,
      enableRowSelection: true,
      enableRowHeaderSelection: false,
      multiSelect: false,
      modifierKeysToMultiSelect: false,
      noUnselect: true,
      columnDefs: [
        {
          name: 'source_type',
          displayName: 'Type',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          type: 'string',
          width: '8%',
          filter: {
            type: uiGridConstants.filter.SELECT,
            term: null,
            disableCancelFilterButton: false,
            selectOptions: [
              { value: null, label: '--' },
              { value: '0', label: 'PubMed'},
              { value: '1', label: 'ASCO'}
            ]
          }
        },
        {
          name: 'citation_id',
          displayName: 'Citation ID',
          enableFiltering: true,
          allowCellFocus: false,
          type: 'string',
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          width: '8%',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'name',
          displayName: 'Title',
          enableFiltering: true,
          allowCellFocus: false,
          type: 'string',
          width: '20%',
          cellTemplate: 'app/views/sources/components/cellTemplateTooltip.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'author_list_string',
          displayName: 'Authors',
          enableFiltering: true,
          allowCellFocus: false,
          type: 'string',
          width: '20%',
          cellTemplate: 'app/views/sources/components/cellTemplateTooltip.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'publication_date_string',
          displayName: 'Date',
          type: 'string',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          width: '10%'
        },
        {
          name: 'full_journal_title',
          displayName: 'Journal',
          type: 'string',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/sources/components/cellTemplateTooltip.tpl.html',
          width: '15%'
        },
        {
          name: 'abstract',
          displayName: 'Abstract',
          type: 'string',
          allowCellFocus: false,
          enableFiltering: true,
          cellTemplate: 'app/views/sources/components/cellTemplateTooltip.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        }
      ]
    };

    ctrl.sourceGridOptions.onRegisterApi = function (gridApi) {
      var sources = $scope.sources;
      ctrl.gridApi = gridApi;

      ctrl.context = $scope.context;
      ctrl.sourceGridOptions.data = prepSources(sources);

      $scope.$watchCollection('sources', function (sources) {
        ctrl.sourceGridOptions.minRowsToShow = sources.length + 1;
        ctrl.sourceGridOptions.data = prepSources(sources);
      });

      ctrl.exportData = function() {
        ctrl.sourceGridOptions.exporterCsvFilename = getFilename($scope.variant);
        var rows = ctrl.exportPopover.include === 'all' ? uiGridExporterConstants.ALL : uiGridExporterConstants.VISIBLE;
        if(ctrl.exportPopover.type === 'csv') {
          gridApi.exporter.csvExport(rows, uiGridExporterConstants.ALL);
        } else {
          gridApi.exporter.pdfExport(rows, uiGridExporterConstants.ALL);
        }
      };

      function getFilename() {
        var dateTime = $filter('date')(new Date(), 'yyyy-MM-ddTHH:MM:ss');
        return 'CIViC_sources_' + dateTime + '.csv';
      }

      gridApi.selection.on.rowSelectionChanged($scope, function (row, event) {
        var params = {sourceId: row.entity.id};
        if (event.metaKey) {
          // if meta key (alt or command) pressed, generate a state URL and open it in a new tab/window
          // shift would be preferable to meta but ui-grid's selection module appears to be capturing shift-clicks for multi-select feature
          // keep an eye on: https://github.com/angular-ui/ui-grid/issues/4926
          var url = $state.href('sources.summary', params, {absolute: true});
          $window.open(url, '_blank');
        } else {
          $state.go('sources.summary', params);
        }
      });

      function prepSources(sources) {
        return _.map(sources, function(source) {
          // TODO: refactor this into the service, we're doing the same munging in 3 places
          // format publication date
          var pubDate = [source.publication_date.year];
          if(!_.isUndefined(source.publication_date.month)) {
            pubDate.push(source.publication_date.month);
          }

          if(!_.isUndefined(source.publication_date.day)) {
            pubDate.push(source.publication_date.day);
          }

          source.publication_date_string = pubDate.join('-');

          // format author list
          source.author_list_string = _(source.author_list)
            .sortBy('position')
            .map(function(author) {
              return [author.fore_name, author.last_name].join(' ');
            })
            .value()
            .join(', ');
          return source;
        });
      }
    };
  }

})();
<commit_msg>Use API's author_string return value instead of re-constructing it<commit_after>(function() {
  'use strict';

  angular.module('civic.sources')
    .directive('sourceGrid', sourceGrid)
    .controller('SourceGridController', SourceGridController);

  // @ngInject
  function sourceGrid() {
    var directive = {
      restrict: 'E',
      replace: true,
      scope: {
        sources: '=',
        rows: '=',
        context:'='
      },
      templateUrl: 'app/views/sources/components/sourceGrid.tpl.html',
      controller: 'SourceGridController'
    };
    return directive;
  }

  // @ngInject
  function SourceGridController($scope,
                                $state,
                                $window,
                                $filter,
                                uiGridExporterConstants,
                                uiGridConstants,
                                _) {
    console.log('SourceGridController Loaded.');

    var ctrl = $scope.ctrl = {};

    ctrl.exportPopover = {
      templateUrl: 'app/views/events/common/gridExportPopover.tpl.html',
      title: 'Save CSV',
      include: 'all',
      type: 'csv'
    };

    ctrl.rowsToShow = $scope.rows ? $scope.rows : 10;
    ctrl.sourceGridOptions = {
      minRowsToShow: ctrl.rowsToShow - 1,
      //enablePaginationControls: true,
      //paginationPageSizes: [8],
      //paginationPageSize: 8,
      enablePaging: false,

      enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
      enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
      enableFiltering: true,
      enableColumnMenus: false,
      enableSorting: true,
      enableRowSelection: true,
      enableRowHeaderSelection: false,
      multiSelect: false,
      modifierKeysToMultiSelect: false,
      noUnselect: true,
      columnDefs: [
        {
          name: 'source_type',
          displayName: 'Type',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          type: 'string',
          width: '8%',
          filter: {
            type: uiGridConstants.filter.SELECT,
            term: null,
            disableCancelFilterButton: false,
            selectOptions: [
              { value: null, label: '--' },
              { value: '0', label: 'PubMed'},
              { value: '1', label: 'ASCO'}
            ]
          }
        },
        {
          name: 'citation_id',
          displayName: 'Citation ID',
          enableFiltering: true,
          allowCellFocus: false,
          type: 'string',
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          width: '8%',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'name',
          displayName: 'Title',
          enableFiltering: true,
          allowCellFocus: false,
          type: 'string',
          width: '20%',
          cellTemplate: 'app/views/sources/components/cellTemplateTooltip.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'author_string',
          displayName: 'Authors',
          enableFiltering: true,
          allowCellFocus: false,
          type: 'string',
          width: '20%',
          cellTemplate: 'app/views/sources/components/cellTemplateTooltip.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'publication_date_string',
          displayName: 'Date',
          type: 'string',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/events/common/genericHighlightCell.tpl.html',
          width: '10%'
        },
        {
          name: 'full_journal_title',
          displayName: 'Journal',
          type: 'string',
          enableFiltering: true,
          allowCellFocus: false,
          cellTemplate: 'app/views/sources/components/cellTemplateTooltip.tpl.html',
          width: '15%'
        },
        {
          name: 'abstract',
          displayName: 'Abstract',
          type: 'string',
          allowCellFocus: false,
          enableFiltering: true,
          cellTemplate: 'app/views/sources/components/cellTemplateTooltip.tpl.html',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        }
      ]
    };

    ctrl.sourceGridOptions.onRegisterApi = function (gridApi) {
      var sources = $scope.sources;
      ctrl.gridApi = gridApi;

      ctrl.context = $scope.context;
      ctrl.sourceGridOptions.data = prepSources(sources);

      $scope.$watchCollection('sources', function (sources) {
        ctrl.sourceGridOptions.minRowsToShow = sources.length + 1;
        ctrl.sourceGridOptions.data = prepSources(sources);
      });

      ctrl.exportData = function() {
        ctrl.sourceGridOptions.exporterCsvFilename = getFilename($scope.variant);
        var rows = ctrl.exportPopover.include === 'all' ? uiGridExporterConstants.ALL : uiGridExporterConstants.VISIBLE;
        if(ctrl.exportPopover.type === 'csv') {
          gridApi.exporter.csvExport(rows, uiGridExporterConstants.ALL);
        } else {
          gridApi.exporter.pdfExport(rows, uiGridExporterConstants.ALL);
        }
      };

      function getFilename() {
        var dateTime = $filter('date')(new Date(), 'yyyy-MM-ddTHH:MM:ss');
        return 'CIViC_sources_' + dateTime + '.csv';
      }

      gridApi.selection.on.rowSelectionChanged($scope, function (row, event) {
        var params = {sourceId: row.entity.id};
        if (event.metaKey) {
          // if meta key (alt or command) pressed, generate a state URL and open it in a new tab/window
          // shift would be preferable to meta but ui-grid's selection module appears to be capturing shift-clicks for multi-select feature
          // keep an eye on: https://github.com/angular-ui/ui-grid/issues/4926
          var url = $state.href('sources.summary', params, {absolute: true});
          $window.open(url, '_blank');
        } else {
          $state.go('sources.summary', params);
        }
      });

      function prepSources(sources) {
        return _.map(sources, function(source) {
          // TODO: refactor this into the service, we're doing the same munging in 3 places
          // format publication date
          var pubDate = [source.publication_date.year];
          if(!_.isUndefined(source.publication_date.month)) {
            pubDate.push(source.publication_date.month);
          }

          if(!_.isUndefined(source.publication_date.day)) {
            pubDate.push(source.publication_date.day);
          }

          source.publication_date_string = pubDate.join('-');

          return source;
        });
      }
    };
  }

})();
<|endoftext|>


<commit_before>const debug = require('debug')('sekshi:social-media')
const SekshiModule = require('../Module')

export default class Links extends SekshiModule {

  constructor(sekshi, options) {
    super(sekshi, options)

    this.author = 'ReAnna'
    this.description = 'Throws links at people.'

    this.permissions = {
      fb: sekshi.USERROLE.NONE,
      web: sekshi.USERROLE.NONE,
      gh: sekshi.USERROLE.NONE,
      help: sekshi.USERROLE.NONE
    }
  }

  fb() {
    this.sekshi.sendChat('Like us on Facebook for the latest event announcements! https://facebook.com/welovekpop.club')
  }

  web() {
    this.sekshi.sendChat('Check out our website for rules, tutorials, popular videos and more! http://welovekpop.club')
  }

  gh() {
    this.sekshi.sendChat('SekshiBot is on Github! Check out https://github.com/welovekpop for code and goodies :)')
  }

  help(user) {
    this.sekshi.sendChat(`@${user.username} SekshiBot commands can be found on our website. http://welovekpop.club/sekshibot`)
  }

}
<commit_msg>Adding steam link<commit_after>const debug = require('debug')('sekshi:social-media')
const SekshiModule = require('../Module')

export default class Links extends SekshiModule {

  constructor(sekshi, options) {
    super(sekshi, options)

    this.author = 'ReAnna'
    this.description = 'Throws links at people.'

    this.permissions = {
      fb: sekshi.USERROLE.NONE,
      web: sekshi.USERROLE.NONE,
      gh: sekshi.USERROLE.NONE,
      help: sekshi.USERROLE.NONE,
      steam: sekshi.USERROLE.NONE
    }
  }

  fb() {
    this.sekshi.sendChat('Like us on Facebook for the latest event announcements! https://facebook.com/welovekpop.club')
  }

  web() {
    this.sekshi.sendChat('Check out our website for rules, tutorials, popular videos and more! http://welovekpop.club')
  }

  gh() {
    this.sekshi.sendChat('SekshiBot is on Github! Check out https://github.com/welovekpop for code and goodies :)')
  }

  help(user) {
    this.sekshi.sendChat(`@${user.username} SekshiBot commands can be found on our website. http://welovekpop.club/sekshibot`)
  }

  steam() {
    this.sekshi.sendChat('Join us on steam! http://steamcommunity.com/groups/wlk_gaming')
  }

}
<|endoftext|>


<commit_before>import { Promise } from 'es6-promise';

import { getters as authGetters } from '../auth';

let callApi = function callApi(reactor, method, path, parameters = null) {
  const authInfo = reactor.evaluate(authGetters.authInfo);

  const url = `${authInfo.host}/api/${path}`;

  return new Promise(function apiResponse(resolve, reject) {
    const req = new XMLHttpRequest();
    req.open(method, url, true);
    req.setRequestHeader('X-HA-access', authInfo.authToken);

    req.onload = () => {
      if (req.status > 199 && req.status < 300) {
        resolve(JSON.parse(req.responseText));
      } else {
        // see if we got an error back.
        try {
          reject(JSON.parse(req.responseText));
        } catch (err) {
          reject({});
        }
      }
    };

    req.onerror = () => reject({});

    if (parameters) {
      req.send(JSON.stringify(parameters));
    } else {
      req.send();
    }
  });
};

if (__DEMO__) {
  callApi = function demoCallAPI(reactor, method, path) {
    return new Promise(function demoAPIResponse(resolve) {
      if (method !== 'GET') {
        throw new Error(`Method ${method} not allowed in demo mode.`);
      }

      const component = path.split('/', 1)[0];

      switch (component) {
      case 'bootstrap':
        resolve(require('../demo/bootstrap_data.js'));
        break;
      case 'logbook':
        resolve(require('../demo/logbook_data.js'));
        break;
      case 'history':
        resolve(require('../demo/state_history_data.js'));
        break;
      default:
        throw new Error(`URL not implemented in demo mode /api/${path}`);
      }
    });
  };
}

export default callApi;
<commit_msg>Allow handling API calls that do not return JSON<commit_after>import { Promise } from 'es6-promise';

import { getters as authGetters } from '../auth';

let callApi = function callApi(reactor, method, path, parameters = null) {
  const authInfo = reactor.evaluate(authGetters.authInfo);

  const url = `${authInfo.host}/api/${path}`;

  return new Promise(function apiResponse(resolve, reject) {
    const req = new XMLHttpRequest();
    req.open(method, url, true);
    req.setRequestHeader('X-HA-access', authInfo.authToken);

    req.onload = () => {
      let content;

      try {
        if (req.getResponseHeader('content-type') === 'application/json') {
          content = JSON.parse(req.responseText);
        } else {
          content = req.responseText;
        }
      } catch (err) {
        content = req.responseText;
      }

      if (req.status > 199 && req.status < 300) {
        resolve(content);
      } else {
        reject(content);
      }
    };

    req.onerror = () => reject({});

    if (parameters) {
      req.send(JSON.stringify(parameters));
    } else {
      req.send();
    }
  });
};

if (__DEMO__) {
  callApi = function demoCallAPI(reactor, method, path) {
    return new Promise(function demoAPIResponse(resolve) {
      if (method !== 'GET') {
        throw new Error(`Method ${method} not allowed in demo mode.`);
      }

      const component = path.split('/', 1)[0];

      switch (component) {
      case 'bootstrap':
        resolve(require('../demo/bootstrap_data.js'));
        break;
      case 'logbook':
        resolve(require('../demo/logbook_data.js'));
        break;
      case 'history':
        resolve(require('../demo/state_history_data.js'));
        break;
      default:
        throw new Error(`URL not implemented in demo mode /api/${path}`);
      }
    });
  };
}

export default callApi;
<|endoftext|>


<commit_before>const gametree = require('./gametree')
const helper = require('./helper')
const {sgf} = require('./fileformats')
const Board = require('./board')
const {Command} = require('./gtp')

async function enginePlay(controller, sign, vertex, engineBoard) {
    let color = sign > 0 ? 'B' : 'W'
    let coord = engineBoard.vertex2coord(vertex)

    let {response} = await controller.sendCommand(new Command(null, 'play', color, coord))
    if (response.error) return null

    return engineBoard.makeMove(sign, vertex)
}

exports.sync = async function(controller, engineState, treePosition) {
    let {komi: engineKomi, board: engineBoard} = engineState
    let board = gametree.getBoard(...treePosition)

    if (!board.isSquare()) {
        throw new Error('GTP engines don’t support non-square boards.')
    } else if (!board.isValid()) {
        throw new Error('GTP engines don’t support invalid board positions.')
    }

    // Update komi

    let komi = +gametree.getRootProperty(treePosition[0], 'KM', 0)

    if (komi !== engineKomi && !isNaN(komi)) {
        await controller.sendCommand(new Command(null, 'komi', komi))
    }

    // Incremental board update

    let diff = engineBoard.diff(board).filter(v => board.get(v) !== 0)

    if (diff != null) {
        if (diff.length === 0) {
            return
        } else if (diff.length === 1) {
            let vertex = diff[0]
            let sign = board.get(vertex)
            let move = await enginePlay(controller, sign, vertex, engineBoard)

            if (move != null && move.getPositionHash() === board.getPositionHash())
                return
        }
    }

    // Replay

    await controller.sendCommand(new Command(null, 'boardsize', board.width))
    await controller.sendCommand(new Command(null, 'clear_board'))
    engineBoard = new Board(board.width, board.height)

    let tp = [gametree.getRoot(treePosition[0]), 0]

    while (tp != null) {
        let node = tp[0].nodes[tp[1]]
        let error = false

        for (let color of ['B', 'W']) {
            if (!(color in node)) continue

            let sign = color === 'B' ? 1 : -1
            let vertex = sgf.point2vertex(node[color][0])

            engineBoard = await enginePlay(controller, sign, vertex, engineBoard)
            if (engineBoard == null) error = true
        }

        if (error || 'AE' in node && node.AE.length > 0) break

        for (let prop of ['AB', 'AW']) {
            if (!(prop in node)) continue

            let sign = prop === 'AB' ? 1 : -1
            let points = node[prop].map(sgf.compressed2list).reduce((list, x) => [...list, ...x])
            let vertices = points.map(sgf.point2vertex(x))

            for (let vertex of vertices) {
                engineBoard = await enginePlay(controller, sign, vertex, engineBoard)

                if (engineBoard == null) {
                    error = true
                    break
                }
            }

            if (error) break
        }

        if (error || helper.vertexEquals(tp, treePosition)) break

        tp = gametree.navigate(...tp, 1)
    }

    if (engineBoard != null && engineBoard.getPositionHash() === board.getPositionHash())
        return

    // Rearrangement

    await controller.sendCommand(new Command(null, 'boardsize', board.width))
    await controller.sendCommand(new Command(null, 'clear_board'))
    engineBoard = new Board(board.width, board.height)

    for (let x = 0; x < board.width; x++) {
        if (engineBoard == null) break

        for (let y = 0; y < board.height; y++) {
            let vertex = [x, y]
            let sign = board.get(vertex)
            if (sign === 0) continue

            engineBoard = await enginePlay(controller, sign, vertex, engineBoard)
            if (engineBoard == null) break
        }
    }

    if (engineBoard != null && engineBoard.getPositionHash() === board.getPositionHash())
        return

    throw new Error('Current board arrangement can’t be recreated on the GTP engine.')
}
<commit_msg>enginesyncer.sync() returns new engine state<commit_after>const gametree = require('./gametree')
const helper = require('./helper')
const {sgf} = require('./fileformats')
const Board = require('./board')
const {Command} = require('./gtp')

async function enginePlay(controller, sign, vertex, engineBoard) {
    let color = sign > 0 ? 'B' : 'W'
    let coord = engineBoard.vertex2coord(vertex)

    let {response} = await controller.sendCommand(new Command(null, 'play', color, coord))
    if (response.error) return null

    return engineBoard.makeMove(sign, vertex)
}

exports.sync = async function(controller, engineState, treePosition) {
    let board = gametree.getBoard(...treePosition)

    if (!board.isSquare()) {
        throw new Error('GTP engines don’t support non-square boards.')
    } else if (!board.isValid()) {
        throw new Error('GTP engines don’t support invalid board positions.')
    }

    // Update komi

    let komi = +gametree.getRootProperty(treePosition[0], 'KM', 0)

    if (engineState == null || komi !== engineState.komi) {
        await controller.sendCommand(new Command(null, 'komi', komi))
    }

    // Incremental board update

    let newEngineState = {komi, board}

    if (engineState != null) {
        let diff = engineState.board.diff(board).filter(v => board.get(v) !== 0)

        if (diff != null) {
            if (diff.length === 0) {
                return newEngineState
            } else if (diff.length === 1) {
                let vertex = diff[0]
                let sign = board.get(vertex)
                let move = await enginePlay(controller, sign, vertex, engineState.board)

                if (move != null && move.getPositionHash() === board.getPositionHash())
                    return newEngineState
            }
        }
    }

    // Replay

    await controller.sendCommand(new Command(null, 'boardsize', board.width))
    await controller.sendCommand(new Command(null, 'clear_board'))
    let engineBoard = new Board(board.width, board.height)

    let tp = [gametree.getRoot(treePosition[0]), 0]

    while (tp != null) {
        let node = tp[0].nodes[tp[1]]
        let error = false

        for (let color of ['B', 'W']) {
            if (!(color in node)) continue

            let sign = color === 'B' ? 1 : -1
            let vertex = sgf.point2vertex(node[color][0])

            engineBoard = await enginePlay(controller, sign, vertex, engineBoard)
            if (engineBoard == null) error = true
        }

        if (error || 'AE' in node && node.AE.length > 0) break

        for (let prop of ['AB', 'AW']) {
            if (!(prop in node)) continue

            let sign = prop === 'AB' ? 1 : -1
            let points = node[prop].map(sgf.compressed2list).reduce((list, x) => [...list, ...x])
            let vertices = points.map(sgf.point2vertex(x))

            for (let vertex of vertices) {
                engineBoard = await enginePlay(controller, sign, vertex, engineBoard)

                if (engineBoard == null) {
                    error = true
                    break
                }
            }

            if (error) break
        }

        if (error || helper.vertexEquals(tp, treePosition)) break

        tp = gametree.navigate(...tp, 1)
    }

    if (engineBoard != null && engineBoard.getPositionHash() === board.getPositionHash())
        return newEngineState

    // Rearrangement

    await controller.sendCommand(new Command(null, 'boardsize', board.width))
    await controller.sendCommand(new Command(null, 'clear_board'))
    engineBoard = new Board(board.width, board.height)

    for (let x = 0; x < board.width; x++) {
        if (engineBoard == null) break

        for (let y = 0; y < board.height; y++) {
            let vertex = [x, y]
            let sign = board.get(vertex)
            if (sign === 0) continue

            engineBoard = await enginePlay(controller, sign, vertex, engineBoard)
            if (engineBoard == null) break
        }
    }

    if (engineBoard != null && engineBoard.getPositionHash() === board.getPositionHash())
        return newEngineState

    throw new Error('Current board arrangement can’t be recreated on the GTP engine.')
}
<|endoftext|>


<commit_before>/*!
 * mustache.js v0.3.0
 * Logic-less templates in JavaScript
 * http://mustache.github.com
 *
 * Copyright 2009, Chris Wanstrath (Ruby)
 * Copyright 2010, Jan Lehnardt (JavaScript)
 * Licensed under the MIT license.
 * http://github.com/janl/mustache.js/blob/master/LICENSE
 */

var Mustache = function() {
  var Renderer = function() {};

  Renderer.prototype = {
    otag: "{",
    ctag: "}",
    pragmas: {},
    buffer: [],
    pragmas_implemented: {
      "IMPLICIT-ITERATOR": true
    },
    context: {},

    render: function(template, context, partials, in_recursion) {
      // reset buffer & set context
      if(!in_recursion) {
        this.context = context;
        this.buffer = []; // TODO: make this non-lazy
      }

      // fail fast
      if(!this.includes("", template)) {
        if(in_recursion) {
          return template;
        } else {
          this.send(template);
          return;
        }
      }

      template = this.render_pragmas(template);
      var html = this.render_section(template, context, partials);
      if(in_recursion) {
        return this.render_tags(html, context, partials, in_recursion);
      }

      this.render_tags(html, context, partials, in_recursion);
    },

    /*
      Sends parsed lines
    */
    send: function(line) {
      if(line != "") {
        this.buffer.push(line);
      }
    },

    /*
      Looks for %PRAGMAS
    */
    render_pragmas: function(template) {
      // no pragmas
      if(!this.includes("%", template)) {
        return template;
      }

      var that = this;
      var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
            this.ctag);
      return template.replace(regex, function(match, pragma, options) {
        if(!that.pragmas_implemented[pragma]) {
          throw({message:
            "This implementation of mustache doesn't understand the '" +
            pragma + "' pragma"});
        }
        that.pragmas[pragma] = {};
        if(options) {
          var opts = options.split("=");
          that.pragmas[pragma][opts[0]] = opts[1];
        }
        return "";
        // ignore unknown pragmas silently
      });
    },

    /*
      Tries to find a partial in the curent scope and render it
    */
    render_partial: function(name, context, partials) {
      name = this.trim(name);
      if(!partials || partials[name] === undefined) {
        throw({message: "unknown_partial '" + name + "'"});
      }
      if(typeof(context[name]) != "object") {
        return this.render(partials[name], context, partials, true);
      }
      return this.render(partials[name], context[name], partials, true);
    },

    /*
      Renders inverted (^) and normal (#) sections
    */
    render_section: function(template, context, partials) {
      if(!this.includes("#", template) && !this.includes("^", template)) {
        return template;
      }

      var that = this;
      // CSW - Added "+?" so it finds the tighest bound, not the widest
      var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
              "\n*([\\s\\S]*?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
              "\\s*", "mg");

      // for each {#foo}{/foo} section do...
      return template.replace(regex, function(match, type, name, content) {
        var value = that.find(name, context);
        if(type == "^") { // inverted section
          if(!value || that.is_array(value) && value.length === 0) {
            // false or empty list, render it
            return that.render(content, context, partials, true);
          } else {
            return "";
          }
        } else if(type == "#") { // normal section
          if(that.is_array(value)) { // Enumerable, Let's loop!
            return that.map(value, function(row) {
              return that.render(content, that.create_context(row),
                partials, true);
            }).join("");
          } else if(that.is_object(value)) { // Object, Use it as subcontext!
            return that.render(content, that.create_context(value),
              partials, true);
          } else if(typeof value === "function") {
            // higher order section
            return value.call(context, content, function(text) {
              return that.render(text, context, partials, true);
            });
          } else if(value) { // boolean section
            return that.render(content, context, partials, true);
          } else {
            return "";
          }
        }
      });
    },

    /*
      Replace {foo} and friends with values from our view
    */
    render_tags: function(template, context, partials, in_recursion) {
      // tit for tat
      var that = this;

      var new_regex = function() {
        return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
          that.ctag + "+", "g");
      };

      function callOrReturn(value) {
        if (typeof value === 'function') {
          // higher order section
          value = value.call(context, '', function (text) {
            return that.render(text, context, partials, true);
          });
        } else if (that.is_array(value)) {
          value = (value.length) ? value.join(',') : '';
        }
        return (typeof value === 'undefined') ? '' : String(value);
      }

      var regex = new_regex();
      var tag_replace_callback = function(match, operator, name) {
        switch(operator) {
        case "!": // ignore comments
          return "";
        case "=": // set new delimiters, rebuild the replace regexp
          that.set_delimiters(name);
          regex = new_regex();
          return "";
        case ">": // render partial
          return that.render_partial(name, context, partials);
        case "{": // the double mustache is escaped
          return that.escape(callOrReturn(that.find(name, context)));
        default: // standard is unescaped
          return callOrReturn(that.find(name, context));
        }
      };
      var lines = template.split("\n");
      for(var i = 0; i < lines.length; i++) {
        lines[i] = lines[i].replace(regex, tag_replace_callback, this);
        if(!in_recursion) {
          this.send(lines[i]);
        }
      }

      if(in_recursion) {
        return lines.join("\n");
      }
    },

    set_delimiters: function(delimiters) {
      var dels = delimiters.split(" ");
      this.otag = this.escape_regex(dels[0]);
      this.ctag = this.escape_regex(dels[1]);
    },

    escape_regex: function(text) {
      // thank you Simon Willison
      if(!arguments.callee.sRE) {
        var specials = [
          '/', '.', '*', '+', '?', '|',
          '(', ')', '[', ']', '{', '}', '\\'
        ];
        arguments.callee.sRE = new RegExp(
          '(\\' + specials.join('|\\') + ')', 'g'
        );
      }
      return text.replace(arguments.callee.sRE, '\\$1');
    },

    /*
      find `name` in current `context`. That is find me a value
      from the view object
    */
    find: function(name, context) {
      name = this.trim(name).toLowerCase();

      // Checks whether a value is thruthy or false or 0
      function is_kinda_truthy(bool) {
        return bool === false || bool === 0 || bool;
      }

      var value;
      if(is_kinda_truthy(context[name])) {
        value = context[name];
      } else if(is_kinda_truthy(this.context[name])) {
        value = this.context[name];
      }

      if(typeof value === "function") {
        return value.apply(context);
      }
      if(value !== undefined) {
        return value;
      }
      // silently ignore unkown variables
      return "";
    },

    // Utility methods

    /* includes tag */
    includes: function(needle, haystack) {
      return haystack.indexOf(this.otag + needle) != -1;
    },

    /*
      Does away with nasty characters
    */
    escape: function(s) {
      s = String(s === null ? "" : s);
      return s.replace(/&(?!\w+;)|["<>\\]/g, function(s) {
        switch(s) {
        case "&": return "&";
        case "\\": return "\\\\";
        case '"': return '\"';
        case "<": return "<";
        case ">": return ">";
        default: return s;
        }
      });
    },

    // by @langalex, support for arrays of strings
    create_context: function(_context) {
      if(this.is_object(_context)) {
        return _context;
      } else {
        var iterator = ".";
        if(this.pragmas["IMPLICIT-ITERATOR"]) {
          iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
        }
        var ctx = {};
        ctx[iterator] = _context;
        return ctx;
      }
    },

    is_object: function(a) {
      return a && typeof a == "object";
    },

    is_array: function(a) {
      return Object.prototype.toString.call(a) === '[object Array]';
    },

    /*
      Gets rid of leading and trailing whitespace
    */
    trim: function(s) {
      return s.replace(/^\s*|\s*$/g, "");
    },

    /*
      Why, why, why? Because IE. Cry, cry cry.
    */
    map: function(array, fn) {
      if (typeof array.map == "function") {
        return array.map(fn);
      } else {
        var r = [];
        var l = array.length;
        for(var i = 0; i < l; i++) {
          r.push(fn(array[i]));
        }
        return r;
      }
    }
  };

  return({
    name: "mustache.js",
    version: "0.3.0",

    /*
      Turns a template and view into HTML
    */
    to_html: function(template, view, partials, send_fun) {
      var renderer = new Renderer();
      if(send_fun) {
        renderer.send = send_fun;
      }
      renderer.render(template, view, partials);
      if(!send_fun) {
        return renderer.buffer.join("\n");
      }
    }
  });
}();<commit_msg>updated mustache.js to 0.4.0 and added customizations for #65<commit_after>/*!
 * mustache.js v0.4.0
 * Logic-less templates in JavaScript
 *
 * https://github.com/janl/mustache.js
 *
 * Copyright 2009, Chris Wanstrath (Ruby)
 * Copyright 2010, Jan Lehnardt (JavaScript)
 * Licensed under the MIT license.
 * http://github.com/janl/mustache.js/blob/master/LICENSE
 */

var Mustache = function () {
  var _toString = Object.prototype.toString;

  Array.isArray = Array.isArray || function (obj) {
    return _toString.call(obj) == "[object Array]";
  }

  var _trim = String.prototype.trim, trim;

  if (_trim) {
    trim = function (text) {
      return text == null ? "" : _trim.call(text);
    }
  } else {
    var trimLeft, trimRight;

    // IE doesn't match non-breaking spaces with \s.
    if ((/\S/).test("\xA0")) {
      trimLeft = /^[\s\xA0]+/;
      trimRight = /[\s\xA0]+$/;
    } else {
      trimLeft = /^\s+/;
      trimRight = /\s+$/;
    }

    trim = function (text) {
      return text == null ? "" :
        text.toString().replace(trimLeft, "").replace(trimRight, "");
    }
  }

  var escapeMap = {
    "&": "&",
    "<": "<",
    ">": ">",
    '"': '"',
    "'": '''
  };

  function escapeHTML(string) {
    return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) {
      return escapeMap[s] || s;
    });
  }

  var regexCache = {};
  var Renderer = function () {};

  Renderer.prototype = {
    otag: "{",
    ctag: "}",
    pragmas: {},
    buffer: [],
    pragmas_implemented: {
      "IMPLICIT-ITERATOR": true
    },
    context: {},

    render: function (template, context, partials, in_recursion) {
      // reset buffer & set context
      if (!in_recursion) {
        this.context = context;
        this.buffer = []; // TODO: make this non-lazy
      }

      // fail fast
      if (!this.includes("", template)) {
        if (in_recursion) {
          return template;
        } else {
          this.send(template);
          return;
        }
      }

      // get the pragmas together
      template = this.render_pragmas(template);

      // render the template
      var html = this.render_section(template, context, partials);

      // render_section did not find any sections, we still need to render the tags
      if (html === false) {
        html = this.render_tags(template, context, partials, in_recursion);
      }

      if (in_recursion) {
        return html;
      } else {
        this.sendLines(html);
      }
    },

    /*
      Sends parsed lines
    */
    send: function (line) {
      if (line !== "") {
        this.buffer.push(line);
      }
    },

    sendLines: function (text) {
      if (text) {
        var lines = text.split("\n");
        for (var i = 0; i < lines.length; i++) {
          this.send(lines[i]);
        }
      }
    },

    /*
      Looks for %PRAGMAS
    */
    render_pragmas: function (template) {
      // no pragmas
      if (!this.includes("%", template)) {
        return template;
      }

      var that = this;
      var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) {
        return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g");
      });

      return template.replace(regex, function (match, pragma, options) {
        if (!that.pragmas_implemented[pragma]) {
          throw({message:
            "This implementation of mustache doesn't understand the '" +
            pragma + "' pragma"});
        }
        that.pragmas[pragma] = {};
        if (options) {
          var opts = options.split("=");
          that.pragmas[pragma][opts[0]] = opts[1];
        }
        return "";
        // ignore unknown pragmas silently
      });
    },

    /*
      Tries to find a partial in the curent scope and render it
    */
    render_partial: function (name, context, partials) {
      name = trim(name);
      if (!partials || partials[name] === undefined) {
        throw({message: "unknown_partial '" + name + "'"});
      }
      if (!context || typeof context[name] != "object") {
        return this.render(partials[name], context, partials, true);
      }
      return this.render(partials[name], context[name], partials, true);
    },

    /*
      Renders inverted (^) and normal (#) sections
    */
    render_section: function (template, context, partials) {
      if (!this.includes("#", template) && !this.includes("^", template)) {
        // did not render anything, there were no sections
        return false;
      }

      var that = this;

      var regex = this.getCachedRegex("render_section", function (otag, ctag) {
        // This regex matches _the first_ section ({#foo}{/foo}), and captures the remainder
        return new RegExp(
          "^([\\s\\S]*?)" +         // all the crap at the beginning that is not {*} ($1)

          otag +                    // {
          "(\\^|\\#)\\s*(.+)\\s*" + //  #foo (# == $2, foo == $3)
          ctag +                    // }

          "\n*([\\s\\S]*?)" +       // between the tag ($2). leading newlines are dropped

          otag +                    // {
          "\\/\\s*\\3\\s*" +        //  /foo (backreference to the opening tag).
          ctag +                    // }

          "\\s*([\\s\\S]*)$",       // everything else in the string ($4). leading whitespace is dropped.

        "g");
      });

      // for each {#foo}{/foo} section do...
      return template.replace(regex, function (match, before, type, name, content, after) {
        // before contains only tags, no sections
        var renderedBefore = before ? that.render_tags(before, context, partials, true) : "",

        // after may contain both sections and tags, so use full rendering function
            renderedAfter = after ? that.render(after, context, partials, true) : "",

        // will be computed below
            renderedContent,

            value = that.find(name, context);

        if (type === "^") { // inverted section
          if (!value || Array.isArray(value) && value.length === 0) {
            // false or empty list, render it
            renderedContent = that.render(content, context, partials, true);
          } else {
            renderedContent = "";
          }
        } else if (type === "#") { // normal section
          if (Array.isArray(value)) { // Enumerable, Let's loop!
            renderedContent = that.map(value, function (row) {
              return that.render(content, that.create_context(row), partials, true);
            }).join("");
          } else if (that.is_object(value)) { // Object, Use it as subcontext!
            renderedContent = that.render(content, that.create_context(value),
              partials, true);
          } else if (typeof value == "function") {
            // higher order section
            renderedContent = value.call(context, content, function (text) {
              return that.render(text, context, partials, true);
            });
          } else if (value) { // boolean section
            renderedContent = that.render(content, context, partials, true);
          } else {
            renderedContent = "";
          }
        }

        return renderedBefore + renderedContent + renderedAfter;
      });
    },

    /*
      Replace {foo} and friends with values from our view
    */
    render_tags: function (template, context, partials, in_recursion) {
      // tit for tat
      var that = this;

      var new_regex = function () {
        return that.getCachedRegex("render_tags", function (otag, ctag) {
          return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g");
        });
      };

      function handleValue(value) {
        if (typeof value === "function") {
          // higher order section
          value = value.call(context, "", function (text) {
            return that.render(text, context, partials, true);
          });
        } else if (Array.isArray(value)) {
          // output elements of array in csv format
          value = (value.length) ? value.join(",") : "";
        } else if (that.is_object(value) && _toString.call(value) == "[object Object]") {
          // output property values of object in csv format
          value = (function() {
            var values = [];
            for (var property in value) {
              if (value.hasOwnProperty(property)) {
                values.push(String(value[property]));
              }
            }
            return values;
          }()).join(",");
        }
        return (value == null) ? "" : String(value);
      }

      var regex = new_regex();
      var tag_replace_callback = function (match, operator, name) {
        switch(operator) {
        case "!": // ignore comments
          return "";
        case "=": // set new delimiters, rebuild the replace regexp
          that.set_delimiters(name);
          regex = new_regex();
          return "";
        case ">": // render partial
          return that.render_partial(name, context, partials);
        case "{": // the double mustache is escaped
        case "&": // & operator is an alternative escape method
          return escapeHTML(handleValue(that.find(name, context)));
        default: // standard value is unescaped
          return handleValue(that.find(name, context));
        }
      };
      var lines = template.split("\n");
      for(var i = 0; i < lines.length; i++) {
        lines[i] = lines[i].replace(regex, tag_replace_callback, this);
        if (!in_recursion) {
          this.send(lines[i]);
        }
      }

      if (in_recursion) {
        return lines.join("\n");
      }
    },

    set_delimiters: function (delimiters) {
      var dels = delimiters.split(" ");
      this.otag = this.escape_regex(dels[0]);
      this.ctag = this.escape_regex(dels[1]);
    },

    escape_regex: function (text) {
      // thank you Simon Willison
      if (!arguments.callee.sRE) {
        var specials = [
          '/', '.', '*', '+', '?', '|',
          '(', ')', '[', ']', '{', '}', '\\'
        ];
        arguments.callee.sRE = new RegExp(
          '(\\' + specials.join('|\\') + ')', 'g'
        );
      }
      return text.replace(arguments.callee.sRE, '\\$1');
    },

    /*
      find `name` in current `context`. That is find me a value
      from the view object
    */
    find: function (name, context) {
      name = trim(name).toLowerCase();

      // Checks whether a value is thruthy or false or 0
      function is_kinda_truthy(bool) {
        return bool === false || bool === 0 || bool;
      }

      var value;

      // check for dot notation eg. {foo.bar}
      if (name.match(/([a-z_]+)\./ig)) {
        var childValue = this.walk_context(name, context);
        if (is_kinda_truthy(childValue)) {
          value = childValue;
        }
      } else {
        if (is_kinda_truthy(context[name])) {
          value = context[name];
        } else if (is_kinda_truthy(this.context[name])) {
          value = this.context[name];
        }
      }

      if (typeof value == "function") {
        return value.apply(context);
      }
      if (value !== undefined) {
        return value;
      }
      // silently ignore unkown variables
      return "";
    },

    walk_context: function (name, context) {
      var path = name.split('.');
      // if the var doesn't exist in current context, check the top level context
      var value_context = (context[path[0]] != undefined) ? context : this.context;
      var value = value_context[path.shift()];
      while (value != undefined && path.length > 0) {
        value_context = value;
        value = value[path.shift()];
      }
      // if the value is a function, call it, binding the correct context
      if (typeof value == "function") {
        return value.apply(value_context);
      }
      return value;
    },

    // Utility methods

    /* includes tag */
    includes: function (needle, haystack) {
      return haystack.indexOf(this.otag + needle) != -1;
    },

    // by @langalex, support for arrays of strings
    create_context: function (_context) {
      if (this.is_object(_context)) {
        return _context;
      } else {
        var iterator = ".";
        if (this.pragmas["IMPLICIT-ITERATOR"]) {
          iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
        }
        var ctx = {};
        ctx[iterator] = _context;
        return ctx;
      }
    },

    is_object: function (a) {
      return a && typeof a == "object";
    },

    /*
      Why, why, why? Because IE. Cry, cry cry.
    */
    map: function (array, fn) {
      if (typeof array.map == "function") {
        return array.map(fn);
      } else {
        var r = [];
        var l = array.length;
        for(var i = 0; i < l; i++) {
          r.push(fn(array[i]));
        }
        return r;
      }
    },

    getCachedRegex: function (name, generator) {
      var byOtag = regexCache[this.otag];
      if (!byOtag) {
        byOtag = regexCache[this.otag] = {};
      }

      var byCtag = byOtag[this.ctag];
      if (!byCtag) {
        byCtag = byOtag[this.ctag] = {};
      }

      var regex = byCtag[name];
      if (!regex) {
        regex = byCtag[name] = generator(this.otag, this.ctag);
      }

      return regex;
    }
  };

  return({
    name: "mustache.js",
    version: "0.4.0",

    /*
      Turns a template and view into HTML
    */
    to_html: function (template, view, partials, send_fun) {
      var renderer = new Renderer();
      if (send_fun) {
        renderer.send = send_fun;
      }
      renderer.render(template, view || {}, partials);
      if (!send_fun) {
        return renderer.buffer.join("\n");
      }
    }
  });
}();<|endoftext|>


<commit_before>import * as uiActions from '../../common/ui/actions';
import Component from 'react-pure-render/component';
import Header from './Header.react';
import Menu from './Menu.react';
import React, { Navigator, PropTypes, StatusBarIOS, View } from 'react-native';
import SideMenu from 'react-native-side-menu';
import linksMessages from '../../common/app/linksMessages';
import routes from '../routes';
import styles from './styles';
import start from '../../common/app/start';
import { connect } from 'react-redux';
import { injectIntl, intlShape } from 'react-intl';

class App extends Component {

  static propTypes = {
    device: PropTypes.object.isRequired,
    intl: intlShape.isRequired,
    onSideMenuChange: PropTypes.func.isRequired,
    toggleSideMenu: PropTypes.func.isRequired,
    ui: PropTypes.object.isRequired
  };

  static configureScene(route) {
    return route.animationType || Navigator.SceneConfigs.FloatFromRight;
  }

  constructor(props) {
    super(props);
    this.onNavigatorRef = this.onNavigatorRef.bind(this);
    this.onRouteChange = this.onRouteChange.bind(this);
    this.onSideMenuChange = this.onSideMenuChange.bind(this);
    this.renderScene = this.renderScene.bind(this);
  }

  onNavigatorRef(component) {
    this.navigator = component;
  }

  onRouteChange(route) {
    this.navigator.replace(routes[route]);
    this.props.toggleSideMenu();
  }

  onSideMenuChange(isOpen) {
    const { device, onSideMenuChange } = this.props;
    if (device.platform === 'ios') {
      StatusBarIOS.setHidden(isOpen, true);
    }
    onSideMenuChange(isOpen);
  }

  getTitle(route) {
    const { intl } = this.props;
    switch (route) {
      case routes.home: return intl.formatMessage(linksMessages.home);
      case routes.intl: return intl.formatMessage(linksMessages.intl);
      case routes.todos: return intl.formatMessage(linksMessages.todos);
    }
    throw new Error('Route not found.');
  }

  renderScene(route) {
    const { toggleSideMenu } = this.props;
    return (
      <View style={[styles.sceneView, route.style]}>
        <Header
          title={this.getTitle(route)}
          toggleSideMenu={toggleSideMenu}
        />
        <route.Page />
      </View>
    );
  }

  render() {
    const { ui } = this.props;

    return (
      <SideMenu
        disableGestures
        isOpen={ui.isSideMenuOpen}
        menu={
          <Menu onRouteChange={this.onRouteChange} />
        }
        onChange={this.onSideMenuChange}
        style={styles.container}
      >
        <Navigator
          configureScene={App.configureScene}
          initialRoute={routes.home}
          ref={this.onNavigatorRef}
          renderScene={this.renderScene}
          style={styles.container}
        />
      </SideMenu>
    );
  }

}

App = injectIntl(App);

App = connect(state => ({
  device: state.device,
  ui: state.ui
}), uiActions)(App);

export default start(App);
<commit_msg>Change default side menu width to 1/3 of screen<commit_after>import * as uiActions from '../../common/ui/actions';
import Component from 'react-pure-render/component';
import Header from './Header.react';
import Menu from './Menu.react';
import React, { Navigator, PropTypes, StatusBarIOS, View, Dimensions } from 'react-native';
import SideMenu from 'react-native-side-menu';
import linksMessages from '../../common/app/linksMessages';
import routes from '../routes';
import styles from './styles';
import start from '../../common/app/start';
import { connect } from 'react-redux';
import { injectIntl, intlShape } from 'react-intl';

const deviceScreen = Dimensions.get('window');

class App extends Component {

  static propTypes = {
    device: PropTypes.object.isRequired,
    intl: intlShape.isRequired,
    onSideMenuChange: PropTypes.func.isRequired,
    toggleSideMenu: PropTypes.func.isRequired,
    ui: PropTypes.object.isRequired
  };

  static configureScene(route) {
    return route.animationType || Navigator.SceneConfigs.FloatFromRight;
  }

  constructor(props) {
    super(props);
    this.onNavigatorRef = this.onNavigatorRef.bind(this);
    this.onRouteChange = this.onRouteChange.bind(this);
    this.onSideMenuChange = this.onSideMenuChange.bind(this);
    this.renderScene = this.renderScene.bind(this);
  }

  onNavigatorRef(component) {
    this.navigator = component;
  }

  onRouteChange(route) {
    this.navigator.replace(routes[route]);
    this.props.toggleSideMenu();
  }

  onSideMenuChange(isOpen) {
    const { device, onSideMenuChange } = this.props;
    if (device.platform === 'ios') {
      StatusBarIOS.setHidden(isOpen, true);
    }
    onSideMenuChange(isOpen);
  }

  getTitle(route) {
    const { intl } = this.props;
    switch (route) {
      case routes.home: return intl.formatMessage(linksMessages.home);
      case routes.intl: return intl.formatMessage(linksMessages.intl);
      case routes.todos: return intl.formatMessage(linksMessages.todos);
    }
    throw new Error('Route not found.');
  }

  renderScene(route) {
    const { toggleSideMenu } = this.props;
    return (
      <View style={[styles.sceneView, route.style]}>
        <Header
          title={this.getTitle(route)}
          toggleSideMenu={toggleSideMenu}
        />
        <route.Page />
      </View>
    );
  }

  render() {
    const { ui } = this.props;

    return (
      <SideMenu
        disableGestures
        isOpen={ui.isSideMenuOpen}
        menu={
          <Menu onRouteChange={this.onRouteChange} />
        }
        onChange={this.onSideMenuChange}
        style={styles.container}
        openMenuOffset={deviceScreen.width * 1 / 3}
      >
        <Navigator
          configureScene={App.configureScene}
          initialRoute={routes.home}
          ref={this.onNavigatorRef}
          renderScene={this.renderScene}
          style={styles.container}
        />
      </SideMenu>
    );
  }

}

App = injectIntl(App);

App = connect(state => ({
  device: state.device,
  ui: state.ui
}), uiActions)(App);

export default start(App);
<|endoftext|>


<commit_before>'use strict';
const Cards = require('../Cards'),
	mkGame = require('../mkGame'),
	sock = require('../sock'),
	store = require('../store'),
	util = require('../util'),
	etgutil = require('../etgutil'),
	Components = require('../Components'),
	{connect} = require('react-redux'),
	React = require('react');

function RenderInfo(props) {
	const {info, y} = props;
	if (info) {
		const card = y ? etgutil.asUpped(info.card, true) : info.card;
		const adeck = '05' + card.toString(32) + info.deck;
		return <>
			<Components.DeckDisplay
				deck={etgutil.decodedeck(adeck)}
				renderMark
				y={y}
			/>
			<Components.Text
				style={{ position: 'absolute', left: '100px', top: 4 + y + 'px' }}
				text={
					`W-L: ${info.win || 0} - ${info.loss || 0}` +
					`, Rank: ${info.rank == undefined ? 'Inactive' : info.rank + 1}` +
					`, ${(info.win || 0) * 15 + (info.loss || 0) * 5}$`}
			/>
			<input readOnly
				style={{ position: 'absolute', left: '330px', top: 4 + y + 'px', width: '190px' }}
				value={adeck}
			/>

				Age: {info.day}

				HP: {info.curhp} / {info.hp}

				Mark: {info.mark}

				Draw: {info.draw}

			<input type='button'
				value='Modify'
				style={{
					position: 'absolute',
					left: '500px',
					top: 224 + y + 'px',
				}}
				onClick={() => {
					store.store.dispatch(store.doNav(require('./ArenaEditor'), {
						adeck: info.deck,
						acard: Cards.Codes[card],
						ainfo: info,
					}));
				}}
			/>
			<input type='button'
				value='Test'
				style={{
					position: 'absolute',
					left: '600px',
					top: 224 + y + 'px',
				}}
				onClick={() => {
					const deck = sock.getDeck();
					if (etgutil.decklength(deck) < 9 || etgutil.decklength(adeck) < 9) {
						store.store.dispatch(store.chatMsg('Deck too small'));
						return;
					}
					const gameData = mkGame({
						deck: adeck,
						urdeck: deck,
						seed: util.randint(),
						foename: 'Test',
						cardreward: '',
						p2hp: info.curhp,
						p2markpower: info.mark,
						p2drawpower: info.draw,
						ai: true,
					});
					store.store.dispatch(store.doNav(require('./Match'), gameData));
				}}
			/>
		</>;
	} else {
		return null;
	}
}
function ArenaCard(props) {
	const { info, y, code } = props;
	return <>
		<input type='button'
			value='Create'
			style={{
				position: 'absolute',
				left: '734px',
				top: 260 + y + 'px',
			}}
			onClick={() => {
				store.store.dispatch(store.doNav(require('./ArenaEditor'), {
					adeck: '',
					acard: Cards.Codes[code],
					ainfo: { day: info ? info.day : 8 },
					acreate: true,
				}));
			}}
		/>
		<Components.Card x={734} y={y} code={code} />
	</>;
}

module.exports = connect(({user}) => ({ ocard: user.ocard }))(class ArenaInfo extends React.Component {
	constructor(props) {
		super(props);
		this.state = {};
	}

	componentDidMount() {
		sock.userEmit('arenainfo');
		store.store.dispatch(store.setCmds({
			arenainfo: data => this.setState(data),
		}));
	}

	render() {
		return <>
			<Components.Text
				style={{ position: 'absolute', left: '96px', top: '560px' }}
				text="Earn 5$ when your arena deck is faced, & another 10$ when it wins\nEarn 25$ for submitting a new arena deck, or 250$ if it's been a week"
			/>
			<Components.ExitBtn x={8} y={300} />
			<RenderInfo info={this.state.A} y={0} />
			<RenderInfo info={this.state.B} y={300} />
			{!!this.props.ocard && <>
				<ArenaCard info={this.state.A} y={8} code={etgutil.asUpped(this.props.ocard, false)} />
				<ArenaCard info={this.state.B} y={300} code={etgutil.asUpped(this.props.ocard, true)} />
			</>}
		</>;
	}
});
<commit_msg>Fix arena bottom text. JSX why<commit_after>'use strict';
const Cards = require('../Cards'),
	mkGame = require('../mkGame'),
	sock = require('../sock'),
	store = require('../store'),
	util = require('../util'),
	etgutil = require('../etgutil'),
	Components = require('../Components'),
	{connect} = require('react-redux'),
	React = require('react');

function RenderInfo(props) {
	const {info, y} = props;
	if (info) {
		const card = y ? etgutil.asUpped(info.card, true) : info.card;
		const adeck = '05' + card.toString(32) + info.deck;
		return <>
			<Components.DeckDisplay
				deck={etgutil.decodedeck(adeck)}
				renderMark
				y={y}
			/>
			<Components.Text
				style={{ position: 'absolute', left: '100px', top: 4 + y + 'px' }}
				text={
					`W-L: ${info.win || 0} - ${info.loss || 0}` +
					`, Rank: ${info.rank == undefined ? 'Inactive' : info.rank + 1}` +
					`, ${(info.win || 0) * 15 + (info.loss || 0) * 5}$`}
			/>
			<input readOnly
				style={{ position: 'absolute', left: '330px', top: 4 + y + 'px', width: '190px' }}
				value={adeck}
			/>

				Age: {info.day}

				HP: {info.curhp} / {info.hp}

				Mark: {info.mark}

				Draw: {info.draw}

			<input type='button'
				value='Modify'
				style={{
					position: 'absolute',
					left: '500px',
					top: 224 + y + 'px',
				}}
				onClick={() => {
					store.store.dispatch(store.doNav(require('./ArenaEditor'), {
						adeck: info.deck,
						acard: Cards.Codes[card],
						ainfo: info,
					}));
				}}
			/>
			<input type='button'
				value='Test'
				style={{
					position: 'absolute',
					left: '600px',
					top: 224 + y + 'px',
				}}
				onClick={() => {
					const deck = sock.getDeck();
					if (etgutil.decklength(deck) < 9 || etgutil.decklength(adeck) < 9) {
						store.store.dispatch(store.chatMsg('Deck too small'));
						return;
					}
					const gameData = mkGame({
						deck: adeck,
						urdeck: deck,
						seed: util.randint(),
						foename: 'Test',
						cardreward: '',
						p2hp: info.curhp,
						p2markpower: info.mark,
						p2drawpower: info.draw,
						ai: true,
					});
					store.store.dispatch(store.doNav(require('./Match'), gameData));
				}}
			/>
		</>;
	} else {
		return null;
	}
}
function ArenaCard(props) {
	const { info, y, code } = props;
	return <>
		<input type='button'
			value='Create'
			style={{
				position: 'absolute',
				left: '734px',
				top: 260 + y + 'px',
			}}
			onClick={() => {
				store.store.dispatch(store.doNav(require('./ArenaEditor'), {
					adeck: '',
					acard: Cards.Codes[code],
					ainfo: { day: info ? info.day : 8 },
					acreate: true,
				}));
			}}
		/>
		<Components.Card x={734} y={y} code={code} />
	</>;
}

module.exports = connect(({user}) => ({ ocard: user.ocard }))(class ArenaInfo extends React.Component {
	constructor(props) {
		super(props);
		this.state = {};
	}

	componentDidMount() {
		sock.userEmit('arenainfo');
		store.store.dispatch(store.setCmds({
			arenainfo: data => this.setState(data),
		}));
	}

	render() {
		return <>
			<Components.Text
				style={{ position: 'absolute', left: '96px', top: '560px' }}
				text={"Earn 5$ when your arena deck is faced, & another 10$ when it wins\nEarn 25$ for submitting a new arena deck, or 250$ if it's been a week"}
			/>
			<Components.ExitBtn x={8} y={300} />
			<RenderInfo info={this.state.A} y={0} />
			<RenderInfo info={this.state.B} y={300} />
			{!!this.props.ocard && <>
				<ArenaCard info={this.state.A} y={8} code={etgutil.asUpped(this.props.ocard, false)} />
				<ArenaCard info={this.state.B} y={300} code={etgutil.asUpped(this.props.ocard, true)} />
			</>}
		</>;
	}
});
<|endoftext|>


<commit_before>import Big from 'big.js'
import { format } from 'date-fns'

import { func } from 'prop-types'
import React, { Fragment } from 'react'

import { Link } from 'react-router-dom'

import Icon from '../components/Icon'

const Dashboard = ({ onStartPayment, settings, lastPayment }) => (
  <Fragment>

{settings.name || 'Coffee shop'}

        {format(new Date(), 'DD MMMM YYYY')}

        <button className='c-btn c-btn--rounded' onClick={onStartPayment}>
          Request New Payment
        </button>

        Today

            {settings.exchangeRate ? new Big(settings.exchangeRate).toFixed(2) : '--'}
            XMR / {settings.fiatCurrency}

            {lastPayment ? format(lastPayment.createdAt, 'HH:mm') : '--'}
            Last payment

        <Link to='/payments' className='o-flex o-flex--center u-brand-primary u-medium u-margin-bottom'>
          <Icon name='history' className='icon--brand' />
          See history
        </Link>

      <Icon href='/settings' name='settings' className='icon--white' />

  </Fragment>
)

Dashboard.propTypes = {
  onStartPayment: func.isRequired
}

export default Dashboard
<commit_msg>Need better way to handle default settings :(<commit_after>import Big from 'big.js'
import { format } from 'date-fns'

import { func } from 'prop-types'
import React, { Fragment } from 'react'

import { Link } from 'react-router-dom'

import Icon from '../components/Icon'

const Dashboard = ({ onStartPayment, settings, lastPayment }) => (
  <Fragment>

{settings.name || 'Coffee shop'}

        {format(new Date(), 'DD MMMM YYYY')}

        <button className='c-btn c-btn--rounded' onClick={onStartPayment}>
          Request New Payment
        </button>

        Today

            {settings.exchangeRate ? new Big(settings.exchangeRate).toFixed(2) : '--'}
            XMR / {settings.fiatCurrency || 'EUR'}

            {lastPayment ? format(lastPayment.createdAt, 'HH:mm') : '--'}
            Last payment

        <Link to='/payments' className='o-flex o-flex--center u-brand-primary u-medium u-margin-bottom'>
          <Icon name='history' className='icon--brand' />
          See history
        </Link>

      <Icon href='/settings' name='settings' className='icon--white' />

  </Fragment>
)

Dashboard.propTypes = {
  onStartPayment: func.isRequired
}

export default Dashboard
<|endoftext|>


<commit_before>'use strict';

var analytics = require('../lib/analytics');
var analyticsKinds = require('../constants').analyticsKinds;
var BaseView = require('./base-view');
var classlist = require('../lib/classlist');
var sheetViews = require('./payment-sheet-views');
var PaymentMethodsView = require('./payment-methods-view');
var PaymentOptionsView = require('./payment-options-view');
var supportsFlexbox = require('../lib/supports-flexbox');
var transitionHelper = require('../lib/transition-helper');

function MainView() {
  BaseView.apply(this, arguments);

  this.dependenciesInitializing = 0;

  this._initialize();
}

MainView.prototype = Object.create(BaseView.prototype);
MainView.prototype.constructor = MainView;

MainView.prototype._initialize = function () {
  var hasMultiplePaymentOptions = this.model.supportedPaymentOptions.length > 1;
  var paymentOptionsView;
  var paymentMethods = this.model.getPaymentMethods();

  this._views = {};

  this.sheetContainer = this.getElementById('sheet-container');
  this.sheetErrorText = this.getElementById('sheet-error-text');

  this.toggle = this.getElementById('toggle');
  this.lowerContainer = this.getElementById('lower-container');

  this.loadingContainer = this.getElementById('loading-container');
  this.loadingIndicator = this.getElementById('loading-indicator');
  this.dropinContainer = this.element.querySelector('.braintree-dropin');

  this.supportsFlexbox = supportsFlexbox();

  this.model.on('loadEnd', this.hideLoadingIndicator.bind(this));

  this.model.on('errorOccurred', this.showSheetError.bind(this));
  this.model.on('errorCleared', this.hideSheetError.bind(this));

  this.paymentSheetViewIDs = Object.keys(sheetViews).reduce(function (ids, sheetViewKey) {
    var PaymentSheetView, paymentSheetView;

    if (this.model.supportedPaymentOptions.indexOf(sheetViewKey) !== -1) {
      PaymentSheetView = sheetViews[sheetViewKey];

      paymentSheetView = new PaymentSheetView({
        element: this.getElementById(PaymentSheetView.ID),
        mainView: this,
        model: this.model,
        client: this.client,
        strings: this.strings
      });

      this.addView(paymentSheetView);
      ids.push(paymentSheetView.ID);
    }

    return ids;
  }.bind(this), []);

  this.paymentMethodsViews = new PaymentMethodsView({
    element: this.element,
    model: this.model,
    strings: this.strings
  });
  this.addView(this.paymentMethodsViews);

  this.toggle.addEventListener('click', this.toggleAdditionalOptions.bind(this));

  this.model.on('changeActivePaymentMethod', function () {
    this.setPrimaryView(PaymentMethodsView.ID);
  }.bind(this));

  this.model.on('changeActivePaymentView', function (id) {
    if (id === PaymentMethodsView.ID) {
      classlist.add(this.paymentMethodsViews.container, 'braintree-methods--active');
      classlist.remove(this.sheetContainer, 'braintree-sheet--active');
    } else {
      setTimeout(function () {
        classlist.add(this.sheetContainer, 'braintree-sheet--active');
      }.bind(this), 0);
      classlist.remove(this.paymentMethodsViews.container, 'braintree-methods--active');
    }
  }.bind(this));

  if (hasMultiplePaymentOptions) {
    paymentOptionsView = new PaymentOptionsView({
      client: this.client,
      element: this.getElementById(PaymentOptionsView.ID),
      mainView: this,
      model: this.model,
      strings: this.strings
    });

    this.addView(paymentOptionsView);
  }

  if (paymentMethods.length > 0) {
    this.model.changeActivePaymentMethod(paymentMethods[0]);
  } else if (hasMultiplePaymentOptions) {
    this.setPrimaryView(paymentOptionsView.ID);
  } else {
    this.setPrimaryView(this.paymentSheetViewIDs[0]);
  }
};

MainView.prototype.addView = function (view) {
  this._views[view.ID] = view;
};

MainView.prototype.getView = function (id) {
  return this._views[id];
};

MainView.prototype.setPrimaryView = function (id, secondaryViewId) {
  if (this.primaryView && this.primaryView.closeFrame) {
    this.primaryView.closeFrame();
  }

  setTimeout(function () {
    this.element.className = prefixShowClass(id);
    if (secondaryViewId) {
      classlist.add(this.element, prefixShowClass(secondaryViewId));
    }
  }.bind(this), 1);
  this.primaryView = this.getView(id);
  this.model.changeActivePaymentView(id);

  if (this.paymentSheetViewIDs.indexOf(id) !== -1) {
    if (this.model.getPaymentMethods().length > 0 || this.getView(PaymentOptionsView.ID)) {
      this.showToggle();
      this.paymentMethodsViews.hideMethodsLabel();
    } else {
      this.hideToggle();
    }
  } else if (id === PaymentMethodsView.ID) {
    this.showToggle();
    // Move options below the upper-container
    this.getElementById('lower-container').appendChild(this.getElementById('options'));
  } else if (id === PaymentOptionsView.ID) {
    this.hideToggle();

    // Animation doesn't show without setTimeout
    setTimeout(function () {
      classlist.remove(this.getElementById('choose-a-way-to-pay'), 'braintree-heading--inactive');
    }.bind(this), 1);
  }

  if (!this.supportsFlexbox) {
    // TODO update no flex support
    this.element.className += ' braintree-dropin__no-flexbox';
  }

  this.model.clearError();
};

MainView.prototype.requestPaymentMethod = function (callback) {
  var activePaymentView = this.getView(this.model.getActivePaymentView());

  activePaymentView.requestPaymentMethod(function (err, payload) {
    if (err) {
      analytics.sendEvent(this.client, 'request-payment-method.error');
      callback(err);
      return;
    }

    this.setPrimaryView(PaymentMethodsView.ID);

    analytics.sendEvent(this.client, 'request-payment-method.' + analyticsKinds[payload.type]);
    callback(null, payload);
  }.bind(this));
};

MainView.prototype.hideLoadingIndicator = function () {
  classlist.add(this.dropinContainer, 'braintree-loaded');
  transitionHelper.onTransitionEnd(this.loadingIndicator, 'transform', function () {
    this.loadingContainer.parentNode.removeChild(this.loadingContainer);
  }.bind(this));
};

MainView.prototype.toggleAdditionalOptions = function () {
  var sheetViewID;
  var hasMultiplePaymentOptions = this.model.supportedPaymentOptions.length > 1;
  var isPaymentSheetView = this.paymentSheetViewIDs.indexOf(this.primaryView.ID) !== -1;

  this.hideToggle();
  this.paymentMethodsViews.showMethodsLabel();

  if (!hasMultiplePaymentOptions) {
    sheetViewID = this.paymentSheetViewIDs[0];

    this.element.className = prefixShowClass(sheetViewID);
    this.model.changeActivePaymentView(sheetViewID);
  } else if (isPaymentSheetView) {
    if (this.model.getPaymentMethods().length === 0) {
      this.setPrimaryView(PaymentOptionsView.ID);
    } else {
      this.setPrimaryView(PaymentMethodsView.ID, PaymentOptionsView.ID);
      this.hideToggle();
    }
  } else {
    classlist.add(this.element, prefixShowClass(PaymentOptionsView.ID));
  }
};

MainView.prototype.showToggle = function () {
  classlist.remove(this.toggle, 'braintree-hidden');
  classlist.add(this.lowerContainer, 'braintree-hidden');
};

MainView.prototype.hideToggle = function () {
  classlist.add(this.toggle, 'braintree-hidden');
  classlist.remove(this.lowerContainer, 'braintree-hidden');
};

MainView.prototype.showSheetError = function (error) {
  var errorMessage = this.strings.genericError;

  if (error && error.code && this.strings[snakeCaseToCamelCase(error.code) + 'Error']) {
    errorMessage = this.strings[snakeCaseToCamelCase(error.code) + 'Error'];
  } else if (error && error.message) {
    errorMessage = error.message;
  }

  classlist.add(this.sheetContainer, 'braintree-sheet--has-error');
  this.sheetErrorText.textContent = errorMessage;
};

MainView.prototype.hideSheetError = function () {
  classlist.remove(this.sheetContainer, 'braintree-sheet--has-error');
};

MainView.prototype.getOptionsElements = function () {
  return this._views.options.elements;
};

MainView.prototype.teardown = function (callback) {
  var viewNames = Object.keys(this._views);
  var numberOfViews = viewNames.length;
  var viewsTornDown = 0;
  var error;

  viewNames.forEach(function (view) {
    this._views[view].teardown(function (err) {
      if (err) {
        error = err;
      }
      viewsTornDown += 1;

      if (viewsTornDown >= numberOfViews) {
        callback(error);
      }
    });
  }.bind(this));
};

function snakeCaseToCamelCase(s) {
  return s.toLowerCase().replace(/(\_\w)/g, function (m) {
    return m[1].toUpperCase();
  });
}

function prefixShowClass(classname) {
  return 'braintree-show-' + classname;
}

module.exports = MainView;
<commit_msg>Show methods label after tokenization<commit_after>'use strict';

var analytics = require('../lib/analytics');
var analyticsKinds = require('../constants').analyticsKinds;
var BaseView = require('./base-view');
var classlist = require('../lib/classlist');
var sheetViews = require('./payment-sheet-views');
var PaymentMethodsView = require('./payment-methods-view');
var PaymentOptionsView = require('./payment-options-view');
var supportsFlexbox = require('../lib/supports-flexbox');
var transitionHelper = require('../lib/transition-helper');

function MainView() {
  BaseView.apply(this, arguments);

  this.dependenciesInitializing = 0;

  this._initialize();
}

MainView.prototype = Object.create(BaseView.prototype);
MainView.prototype.constructor = MainView;

MainView.prototype._initialize = function () {
  var hasMultiplePaymentOptions = this.model.supportedPaymentOptions.length > 1;
  var paymentOptionsView;
  var paymentMethods = this.model.getPaymentMethods();

  this._views = {};

  this.sheetContainer = this.getElementById('sheet-container');
  this.sheetErrorText = this.getElementById('sheet-error-text');

  this.toggle = this.getElementById('toggle');
  this.lowerContainer = this.getElementById('lower-container');

  this.loadingContainer = this.getElementById('loading-container');
  this.loadingIndicator = this.getElementById('loading-indicator');
  this.dropinContainer = this.element.querySelector('.braintree-dropin');

  this.supportsFlexbox = supportsFlexbox();

  this.model.on('loadEnd', this.hideLoadingIndicator.bind(this));

  this.model.on('errorOccurred', this.showSheetError.bind(this));
  this.model.on('errorCleared', this.hideSheetError.bind(this));

  this.paymentSheetViewIDs = Object.keys(sheetViews).reduce(function (ids, sheetViewKey) {
    var PaymentSheetView, paymentSheetView;

    if (this.model.supportedPaymentOptions.indexOf(sheetViewKey) !== -1) {
      PaymentSheetView = sheetViews[sheetViewKey];

      paymentSheetView = new PaymentSheetView({
        element: this.getElementById(PaymentSheetView.ID),
        mainView: this,
        model: this.model,
        client: this.client,
        strings: this.strings
      });

      this.addView(paymentSheetView);
      ids.push(paymentSheetView.ID);
    }

    return ids;
  }.bind(this), []);

  this.paymentMethodsViews = new PaymentMethodsView({
    element: this.element,
    model: this.model,
    strings: this.strings
  });
  this.addView(this.paymentMethodsViews);

  this.toggle.addEventListener('click', this.toggleAdditionalOptions.bind(this));

  this.model.on('changeActivePaymentMethod', function () {
    this.setPrimaryView(PaymentMethodsView.ID);
  }.bind(this));

  this.model.on('changeActivePaymentView', function (id) {
    if (id === PaymentMethodsView.ID) {
      classlist.add(this.paymentMethodsViews.container, 'braintree-methods--active');
      classlist.remove(this.sheetContainer, 'braintree-sheet--active');
    } else {
      setTimeout(function () {
        classlist.add(this.sheetContainer, 'braintree-sheet--active');
      }.bind(this), 0);
      classlist.remove(this.paymentMethodsViews.container, 'braintree-methods--active');
    }
  }.bind(this));

  if (hasMultiplePaymentOptions) {
    paymentOptionsView = new PaymentOptionsView({
      client: this.client,
      element: this.getElementById(PaymentOptionsView.ID),
      mainView: this,
      model: this.model,
      strings: this.strings
    });

    this.addView(paymentOptionsView);
  }

  if (paymentMethods.length > 0) {
    this.model.changeActivePaymentMethod(paymentMethods[0]);
  } else if (hasMultiplePaymentOptions) {
    this.setPrimaryView(paymentOptionsView.ID);
  } else {
    this.setPrimaryView(this.paymentSheetViewIDs[0]);
  }
};

MainView.prototype.addView = function (view) {
  this._views[view.ID] = view;
};

MainView.prototype.getView = function (id) {
  return this._views[id];
};

MainView.prototype.setPrimaryView = function (id, secondaryViewId) {
  if (this.primaryView && this.primaryView.closeFrame) {
    this.primaryView.closeFrame();
  }

  setTimeout(function () {
    this.element.className = prefixShowClass(id);
    if (id === 'methods') {
      this.paymentMethodsViews.showMethodsLabel();
    }
    if (secondaryViewId) {
      classlist.add(this.element, prefixShowClass(secondaryViewId));
    }
  }.bind(this), 1);
  this.primaryView = this.getView(id);
  this.model.changeActivePaymentView(id);

  if (this.paymentSheetViewIDs.indexOf(id) !== -1) {
    if (this.model.getPaymentMethods().length > 0 || this.getView(PaymentOptionsView.ID)) {
      this.showToggle();
      this.paymentMethodsViews.hideMethodsLabel();
    } else {
      this.hideToggle();
    }
  } else if (id === PaymentMethodsView.ID) {
    this.showToggle();
    // Move options below the upper-container
    this.getElementById('lower-container').appendChild(this.getElementById('options'));
  } else if (id === PaymentOptionsView.ID) {
    this.hideToggle();

    // Animation doesn't show without setTimeout
    setTimeout(function () {
      classlist.remove(this.getElementById('choose-a-way-to-pay'), 'braintree-heading--inactive');
    }.bind(this), 1);
  }

  if (!this.supportsFlexbox) {
    // TODO update no flex support
    this.element.className += ' braintree-dropin__no-flexbox';
  }

  this.model.clearError();
};

MainView.prototype.requestPaymentMethod = function (callback) {
  var activePaymentView = this.getView(this.model.getActivePaymentView());

  activePaymentView.requestPaymentMethod(function (err, payload) {
    if (err) {
      analytics.sendEvent(this.client, 'request-payment-method.error');
      callback(err);
      return;
    }

    this.setPrimaryView(PaymentMethodsView.ID);

    analytics.sendEvent(this.client, 'request-payment-method.' + analyticsKinds[payload.type]);
    callback(null, payload);
  }.bind(this));
};

MainView.prototype.hideLoadingIndicator = function () {
  classlist.add(this.dropinContainer, 'braintree-loaded');
  transitionHelper.onTransitionEnd(this.loadingIndicator, 'transform', function () {
    this.loadingContainer.parentNode.removeChild(this.loadingContainer);
  }.bind(this));
};

MainView.prototype.toggleAdditionalOptions = function () {
  var sheetViewID;
  var hasMultiplePaymentOptions = this.model.supportedPaymentOptions.length > 1;
  var isPaymentSheetView = this.paymentSheetViewIDs.indexOf(this.primaryView.ID) !== -1;

  this.hideToggle();
  this.paymentMethodsViews.showMethodsLabel();

  if (!hasMultiplePaymentOptions) {
    sheetViewID = this.paymentSheetViewIDs[0];

    this.element.className = prefixShowClass(sheetViewID);
    this.model.changeActivePaymentView(sheetViewID);
  } else if (isPaymentSheetView) {
    if (this.model.getPaymentMethods().length === 0) {
      this.setPrimaryView(PaymentOptionsView.ID);
    } else {
      this.setPrimaryView(PaymentMethodsView.ID, PaymentOptionsView.ID);
      this.hideToggle();
    }
  } else {
    classlist.add(this.element, prefixShowClass(PaymentOptionsView.ID));
  }
};

MainView.prototype.showToggle = function () {
  classlist.remove(this.toggle, 'braintree-hidden');
  classlist.add(this.lowerContainer, 'braintree-hidden');
};

MainView.prototype.hideToggle = function () {
  classlist.add(this.toggle, 'braintree-hidden');
  classlist.remove(this.lowerContainer, 'braintree-hidden');
};

MainView.prototype.showSheetError = function (error) {
  var errorMessage = this.strings.genericError;

  if (error && error.code && this.strings[snakeCaseToCamelCase(error.code) + 'Error']) {
    errorMessage = this.strings[snakeCaseToCamelCase(error.code) + 'Error'];
  } else if (error && error.message) {
    errorMessage = error.message;
  }

  classlist.add(this.sheetContainer, 'braintree-sheet--has-error');
  this.sheetErrorText.textContent = errorMessage;
};

MainView.prototype.hideSheetError = function () {
  classlist.remove(this.sheetContainer, 'braintree-sheet--has-error');
};

MainView.prototype.getOptionsElements = function () {
  return this._views.options.elements;
};

MainView.prototype.teardown = function (callback) {
  var viewNames = Object.keys(this._views);
  var numberOfViews = viewNames.length;
  var viewsTornDown = 0;
  var error;

  viewNames.forEach(function (view) {
    this._views[view].teardown(function (err) {
      if (err) {
        error = err;
      }
      viewsTornDown += 1;

      if (viewsTornDown >= numberOfViews) {
        callback(error);
      }
    });
  }.bind(this));
};

function snakeCaseToCamelCase(s) {
  return s.toLowerCase().replace(/(\_\w)/g, function (m) {
    return m[1].toUpperCase();
  });
}

function prefixShowClass(classname) {
  return 'braintree-show-' + classname;
}

module.exports = MainView;
<|endoftext|>


<commit_before>window.cls = window.cls || {};

/**
 * @constructor
 * @extends ViewBase
 */
cls.NetworkLogView = function(id, name, container_class, html, default_handler) {
  this._service = new cls.NetworkLoggerService()
  this._loading = false;
  this._scroll = 0;
  this._selected = null;

  this.createView = function(container)
  {
    this._render_main_view(container);
  };

  this.ondestroy = function()
  {
    if (this._scrollcontainer)
    {
      this._scroll= this._scrollcontainer.scrollTop;
    }
  }

  this._render_main_view = function(container)
  {
    var ctx = this._service.get_request_context();
    if (ctx && ctx.resources.length)
    {
      this._container = container;

      if (this._scrollcontainer)
      {
        this._scroll = this._scrollcontainer.scrollTop;
      }

      if (this._selected !== null)
      {
        var w = container.getBoundingClientRect().width - 320;
        var h = container.getBoundingClientRect().height;
        container.clearAndRender(templates.network_log_details(ctx, this._selected));
        this._scrollcontainer = container.querySelector(".network-details-url-list");
        this._scrollcontainer.scrollTop = this._scroll;

        var content = container.querySelector(".network-details-request");
         content.style.width = "" + w + "px";
      }
      else
      {
        var contheight = container.getBoundingClientRect().height - 2;
        var availwidth = container.getBoundingClientRect().width - 300;
        var duration = ctx.get_duration();
        var graphwidth = availwidth;

        if (duration > 3000)
        {
          graphwidth = Math.ceil(duration);
        }

        // fixme: round up to nearest second when rendering grid

        container.clearAndRender(templates.network_log_main(ctx, graphwidth));
        this._scrollcontainer = container.querySelector("#main-scroll-container");
        this._scrollcontainer.style.height = "" + (contheight-30) + "px";
        this._scrollcontainer.scrollTop = this._scroll;
        container.className = "";

        var scrollable = container.querySelector("#main-scroll-container");
        var scrollercont = container.querySelector("#scrollbar-container");
        var scroller = container.querySelector("#scrollbar");
        scroller.style.width = "" + graphwidth + "px";

        container.querySelector("#right-side-content").style.width = "" + graphwidth + "px";
        var scrollfun = function(evt) {
          var e = document.getElementById("right-side-container");
          e.scrollLeft = evt.target.scrollLeft;
        }
        scrollercont.addEventListener("scroll", scrollfun, false)
      }
    }
    else if (this._loading)
    {
      container.clearAndRender(
        ['div',
         ['p', "Loading page..."],
         'class', 'info-box'
        ]
      );
    }
    else
    {
      container.clearAndRender(
        ['div',
         ['button',
          'class', 'ui-button',
          'handler', 'reload-window'],
         ['p', "Click the reload button above to reload the debugged window and fetch its resources"],
         'class', 'info-box'
        ]
      );
    }
  };

  this._on_clicked_close_bound = function(evt, target)
  {
    this._selected = null;
    this.update();
  }.bind(this);

  this._on_clicked_request_bound = function(evt, target)
  {
    var rid = target.getAttribute("data-resource-id");
    rid = parseInt(rid);
    if (this._selected == rid)
    {
      this._selected = null;
    }
    else
    {
      this._selected = rid;
    }
    this.update();
  }.bind(this);

  this._on_clicked_get_body = function(evt, target)
  {
    var rid = target.getAttribute("data-resource-id");
    rid = parseInt(rid);
    this._service.request_body(rid, this.update.bind(this));
  }.bind(this);

  this._on_scroll_bound = function(evt)
  {
    this._container.querySelector(".resourcelist").scrollTop = evt.target.scrollTop;
  }.bind(this);

  this._on_abouttoloaddocument_bound = function()
  {
    this._loading = true;
    this._table = null;
    this.update();
  }.bind(this);

  this._on_documentloaded_bound = function()
  {
    this._loading = false;
    this.update();
  }.bind(this);

  var eh = window.eventHandlers;
  // fixme: this is in the wrong place! Doesn't belong in UI and even if it
  // did, the event handler doesn't get added until the view is created
  // which means you can't open tabs from elsewhere if you haven't opened
  // the resources view first
  //  eh.click["resources-all-open"] = this._handle_open_resource_bound;

  eh.click["select-network-request"] = this._on_clicked_request_bound;
  eh.click["close-request-detail"] = this._on_clicked_close_bound;
  eh.click["get-response-body"] = this._on_clicked_get_body;

  var doc_service = window.services['document-manager'];
  doc_service.addListener("abouttoloaddocument", this._on_abouttoloaddocument_bound);
  doc_service.addListener("documentloaded", this._on_documentloaded_bound);

  this.init(id, name, container_class, html, default_handler);
};
cls.NetworkLogView.prototype = ViewBase;
<commit_msg>Clear selected request when a page load starts<commit_after>window.cls = window.cls || {};

/**
 * @constructor
 * @extends ViewBase
 */
cls.NetworkLogView = function(id, name, container_class, html, default_handler) {
  this._service = new cls.NetworkLoggerService()
  this._loading = false;
  this._scroll = 0;
  this._selected = null;

  this.createView = function(container)
  {
    this._render_main_view(container);
  };

  this.ondestroy = function()
  {
    if (this._scrollcontainer)
    {
      this._scroll= this._scrollcontainer.scrollTop;
    }
  }

  this._render_main_view = function(container)
  {
    var ctx = this._service.get_request_context();
    if (ctx && ctx.resources.length)
    {
      this._container = container;

      if (this._scrollcontainer)
      {
        this._scroll = this._scrollcontainer.scrollTop;
      }

      if (this._selected !== null)
      {
        var w = container.getBoundingClientRect().width - 320;
        var h = container.getBoundingClientRect().height;
        container.clearAndRender(templates.network_log_details(ctx, this._selected));
        this._scrollcontainer = container.querySelector(".network-details-url-list");
        this._scrollcontainer.scrollTop = this._scroll;

        var content = container.querySelector(".network-details-request");
         content.style.width = "" + w + "px";
      }
      else
      {
        var contheight = container.getBoundingClientRect().height - 2;
        var availwidth = container.getBoundingClientRect().width - 300;
        var duration = ctx.get_duration();
        var graphwidth = availwidth;

        if (duration > 3000)
        {
          graphwidth = Math.ceil(duration);
        }

        // fixme: round up to nearest second when rendering grid

        container.clearAndRender(templates.network_log_main(ctx, graphwidth));
        this._scrollcontainer = container.querySelector("#main-scroll-container");
        this._scrollcontainer.style.height = "" + (contheight-30) + "px";
        this._scrollcontainer.scrollTop = this._scroll;
        container.className = "";

        var scrollable = container.querySelector("#main-scroll-container");
        var scrollercont = container.querySelector("#scrollbar-container");
        var scroller = container.querySelector("#scrollbar");
        scroller.style.width = "" + graphwidth + "px";

        container.querySelector("#right-side-content").style.width = "" + graphwidth + "px";
        var scrollfun = function(evt) {
          var e = document.getElementById("right-side-container");
          e.scrollLeft = evt.target.scrollLeft;
        }
        scrollercont.addEventListener("scroll", scrollfun, false)
      }
    }
    else if (this._loading)
    {
      container.clearAndRender(
        ['div',
         ['p', "Loading page..."],
         'class', 'info-box'
        ]
      );
    }
    else
    {
      container.clearAndRender(
        ['div',
         ['button',
          'class', 'ui-button',
          'handler', 'reload-window'],
         ['p', "Click the reload button above to reload the debugged window and fetch its resources"],
         'class', 'info-box'
        ]
      );
    }
  };

  this._on_clicked_close_bound = function(evt, target)
  {
    this._selected = null;
    this.update();
  }.bind(this);

  this._on_clicked_request_bound = function(evt, target)
  {
    var rid = target.getAttribute("data-resource-id");
    rid = parseInt(rid);
    if (this._selected == rid)
    {
      this._selected = null;
    }
    else
    {
      this._selected = rid;
    }
    this.update();
  }.bind(this);

  this._on_clicked_get_body = function(evt, target)
  {
    var rid = target.getAttribute("data-resource-id");
    rid = parseInt(rid);
    this._service.request_body(rid, this.update.bind(this));
  }.bind(this);

  this._on_scroll_bound = function(evt)
  {
    this._container.querySelector(".resourcelist").scrollTop = evt.target.scrollTop;
  }.bind(this);

  this._on_abouttoloaddocument_bound = function()
  {
    this._loading = true;
    this._table = null;
    this._selected = null;
    this.update();
  }.bind(this);

  this._on_documentloaded_bound = function()
  {
    this._loading = false;
    this.update();
  }.bind(this);

  var eh = window.eventHandlers;
  // fixme: this is in the wrong place! Doesn't belong in UI and even if it
  // did, the event handler doesn't get added until the view is created
  // which means you can't open tabs from elsewhere if you haven't opened
  // the resources view first
  //  eh.click["resources-all-open"] = this._handle_open_resource_bound;

  eh.click["select-network-request"] = this._on_clicked_request_bound;
  eh.click["close-request-detail"] = this._on_clicked_close_bound;
  eh.click["get-response-body"] = this._on_clicked_get_body;

  var doc_service = window.services['document-manager'];
  doc_service.addListener("abouttoloaddocument", this._on_abouttoloaddocument_bound);
  doc_service.addListener("documentloaded", this._on_documentloaded_bound);

  this.init(id, name, container_class, html, default_handler);
};
cls.NetworkLogView.prototype = ViewBase;
<|endoftext|>


<commit_before>const { createCluster } = require('testHelpers')

describe('Cluster', () => {
  let groupId

  beforeEach(() => {
    groupId = 'test-group-id'
  })

  const testWithOffsets = offsets => {
    it(`should return all committed offsets by group ${
      offsets ? '' : '(no offset map provided)'
    }`, async () => {
      const cluster = createCluster({ offsets })
      const topic = 'test-topic'
      const partition = 0

      expect(cluster.committedOffsets({ groupId })).toEqual({})

      cluster.markOffsetAsCommitted({ groupId, topic, partition, offset: '100' })
      cluster.markOffsetAsCommitted({ groupId: 'foobar', topic, partition, offset: '999' })

      expect(cluster.committedOffsets({ groupId })).toEqual({ [topic]: { [partition]: '100' } })
      expect(cluster.committedOffsets({ groupId: 'foobar' })).toEqual({
        [topic]: { [partition]: '999' },
      })
    })

    if (offsets) {
      it('should use the provided offsets map', async () => {
        const cluster = createCluster({ offsets })
        const topic = 'test-topic'
        const partition = 0

        cluster.markOffsetAsCommitted({ groupId, topic, partition, offset: '100' })
        cluster.markOffsetAsCommitted({ groupId: 'foobar', topic, partition, offset: '999' })

        expect(cluster.committedOffsets({ groupId })).toEqual({ [topic]: { [partition]: '100' } })
        expect(offsets.get(groupId)).toEqual({ [topic]: { [partition]: '100' } })
      })
    }
  }

  testWithOffsets(undefined)
  testWithOffsets(new Map())
})
<commit_msg>EoS #207 Split committedOffsets request<commit_after>const { createCluster } = require('testHelpers')

describe('Cluster', () => {
  let groupId

  beforeEach(() => {
    groupId = 'test-group-id'
  })

  describe('if no offset map is provided', () => {
    it('should return all committed offsets by group', async () => {
      const cluster = createCluster({})
      const topic = 'test-topic'
      const partition = 0

      expect(cluster.committedOffsets({ groupId })).toEqual({})

      cluster.markOffsetAsCommitted({ groupId, topic, partition, offset: '100' })
      cluster.markOffsetAsCommitted({ groupId: 'foobar', topic, partition, offset: '999' })

      expect(cluster.committedOffsets({ groupId })).toEqual({ [topic]: { [partition]: '100' } })
      expect(cluster.committedOffsets({ groupId: 'foobar' })).toEqual({
        [topic]: { [partition]: '999' },
      })
    })
  })

  describe('if an offset map is provided', () => {
    let offsets

    beforeEach(() => {
      offsets = new Map()
    })

    it('should return all committed offsets by group', async () => {
      const cluster = createCluster({ offsets })
      const topic = 'test-topic'
      const partition = 0

      expect(cluster.committedOffsets({ groupId })).toEqual({})

      cluster.markOffsetAsCommitted({ groupId, topic, partition, offset: '100' })
      cluster.markOffsetAsCommitted({ groupId: 'foobar', topic, partition, offset: '999' })

      expect(cluster.committedOffsets({ groupId })).toEqual({ [topic]: { [partition]: '100' } })
      expect(cluster.committedOffsets({ groupId: 'foobar' })).toEqual({
        [topic]: { [partition]: '999' },
      })
    })

    it('should use the provided offsets map', async () => {
      const cluster = createCluster({ offsets })
      const topic = 'test-topic'
      const partition = 0

      cluster.markOffsetAsCommitted({ groupId, topic, partition, offset: '100' })
      cluster.markOffsetAsCommitted({ groupId: 'foobar', topic, partition, offset: '999' })

      expect(cluster.committedOffsets({ groupId })).toEqual({ [topic]: { [partition]: '100' } })
      expect(offsets.get(groupId)).toEqual({ [topic]: { [partition]: '100' } })
    })
  })
})
<|endoftext|>