<commit_before>describe('mwListHeader', function () {

  beforeEach(module('karmaDirectiveTemplates'));

  beforeEach(module('mwUI.List'));

  window.mockI18nFilter();
  window.mockIconService();
  var activeBreakPoint = 'md';

  beforeEach(function () {
    module(function ($provide) {
      $provide.service('mwBootstrapBreakpoint', function ($q) {
        return {
          getActiveBreakpoint: function(){
            return activeBreakPoint;
          }
        };
      });
    });
    spyOn(_, 'debounce').and.callFake(function(cb) { return function() { cb(); } });
  });

  beforeEach(inject(function ($compile, $timeout, $rootScope, $httpBackend) {

    this.$compile = $compile;
    this.$httpBackend = $httpBackend;
    this.$timeout = $timeout;
    this.$rootScope = $rootScope;
    this.scope = $rootScope.$new();
    this.collection = new (mwUI.Backbone.Collection.extend({
      url: '/test'
    }))();
    this.scope.collection = this.collection;

    this.setHeaderTemplate = function(tableHeaderTemplate){
      this.template = '
 ' + '
 ' + '
 ' + tableHeaderTemplate + '
 ' + '
' + '
';
      this.$el =  $compile(this.template)(this.scope);
      this.scope.$digest();
      this.$headerEl = this.$el.find('.mw-list-header');
    };
    this.setHeaderTemplate(' ' + 'Title ' + '	')
  }));

  afterEach(function () {
    this.$httpBackend.verifyNoOutstandingExpectation();
    this.scope.$destroy();
    activeBreakPoint = 'md';
  });

  it('is not clickable class when no sort attribute is defined', function(){
    var $headerEl = this.$el.find('.mw-list-header');

    expect($headerEl.hasClass('clickable')).toBeFalsy();
  });

  it('is clickable class when a sort attribute is defined', function(){
    this.scope.sortAttr = 'abc';
    this.scope.$digest();

    expect(this.$headerEl.hasClass('clickable')).toBeTruthy();
  });

  it('triggers an request with an ascending (+) sortOrder param when you click on the header for the first time', function(){
    this.scope.sortAttr = 'abc';
    this.scope.$digest();

    this.$httpBackend.expectGET(/\/test.*sortOrder=%2Babc.*/).respond(200);

    this.$headerEl.triggerHandler('click');
    this.scope.$digest();

    this.$httpBackend.flush();
  });

  it('triggers an request with a descending (-) sortOrder param when you click on the header for the second time', function(){
    this.scope.sortAttr = 'abc';
    this.scope.$digest();
    this.$httpBackend.expectGET(/\/test.*sortOrder=%2Babc.*/).respond(200);
    this.$headerEl.triggerHandler('click');
    this.scope.$digest();

    this.$httpBackend.expectGET(/\/test.*sortOrder=-abc.*/).respond(200);
    this.$headerEl.triggerHandler('click');
    this.scope.$digest();

    this.$httpBackend.flush();
  });

  describe('testing visibility', function(){
    it('is visible when no other attributes are set', function(){
      this.tableHeaderTemplate = '	';
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('is hidden when bootstrap class hidden xs is set and the active breakpoint is xs', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is hidden when bootstrap class visible xs is set and the active breakpoint is md', function(){
      activeBreakPoint = 'md';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is visible when bootstrap class hidden xs is set and the active breakpoint is not xs', function(){
      activeBreakPoint = 'md';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('is visible when bootstrap class visible xs is set and the active breakpoint is xs', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('becomes visible when class hidden xs is set and breakpoint becomes inactive', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      activeBreakPoint = 'lg';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('is hidden when class hidden xs is set and breakpoint becomes active', function(){
      activeBreakPoint = 'lg';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      activeBreakPoint = 'xs';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is hidden when hidden attribute is set', function(){
      activeBreakPoint = 'md';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is hidden when hidden attribute is set to true', function(){
      activeBreakPoint = 'md';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is visible when hidden attribute is set to false', function(){
      activeBreakPoint = 'md';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('is hidden when hidden attribute is set to a breakpoint and breakpoint is becoming active', function(){
      activeBreakPoint = 'lg';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      activeBreakPoint = 'xs';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is hidden when hidden attribute is set to a breakpoint and breakpoint is active', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('becomes visible when hidden attribute is set to a breakpoint and breakpoint is becoming inactive', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      activeBreakPoint = 'lg';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('is visible when hidden attribute is set to a breakpoint and breakpoint is not active', function(){
      activeBreakPoint = 'lg';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('it is visible when hidden attribute is set to a breakpoint and breakpoint active but user has set it to visible', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      isolatedScope.showColumn();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('it is hidden when hidden attribute is set to a breakpoint and breakpoint is inactive but user has set it to hidden', function(){
      activeBreakPoint = 'lg';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      isolatedScope.hideColumn();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('it keeps visiblity status when breakpoint is changing', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();
      isolatedScope.showColumn();

      activeBreakPoint = 'md';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('gets oriignially set visiblity status when calling resetColumnVisibility', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();
      isolatedScope.showColumn();
      activeBreakPoint = 'md';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      isolatedScope.resetColumnVisibility();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

  });

});
<commit_msg>fix jshint linting errors<commit_after>describe('mwListHeader', function () {

  beforeEach(module('karmaDirectiveTemplates'));

  beforeEach(module('mwUI.List'));

  window.mockI18nFilter();
  window.mockIconService();
  var activeBreakPoint = 'md';

  beforeEach(function () {
    module(function ($provide) {
      $provide.service('mwBootstrapBreakpoint', function () {
        return {
          getActiveBreakpoint: function(){
            return activeBreakPoint;
          }
        };
      });
    });
    spyOn(_, 'debounce').and.callFake(function(cb) { return function() { cb(); } });
  });

  beforeEach(inject(function ($compile, $timeout, $rootScope, $httpBackend) {

    this.$compile = $compile;
    this.$httpBackend = $httpBackend;
    this.$timeout = $timeout;
    this.$rootScope = $rootScope;
    this.scope = $rootScope.$new();
    this.collection = new (mwUI.Backbone.Collection.extend({
      url: '/test'
    }))();
    this.scope.collection = this.collection;

    this.setHeaderTemplate = function(tableHeaderTemplate){
      this.template = '
 ' + '
 ' + '
 ' + tableHeaderTemplate + '
 ' + '
' + '
';
      this.$el =  $compile(this.template)(this.scope);
      this.scope.$digest();
      this.$headerEl = this.$el.find('.mw-list-header');
    };
    this.setHeaderTemplate(' ' + 'Title ' + '	');
  }));

  afterEach(function () {
    this.$httpBackend.verifyNoOutstandingExpectation();
    this.scope.$destroy();
    activeBreakPoint = 'md';
  });

  it('is not clickable class when no sort attribute is defined', function(){
    var $headerEl = this.$el.find('.mw-list-header');

    expect($headerEl.hasClass('clickable')).toBeFalsy();
  });

  it('is clickable class when a sort attribute is defined', function(){
    this.scope.sortAttr = 'abc';
    this.scope.$digest();

    expect(this.$headerEl.hasClass('clickable')).toBeTruthy();
  });

  it('triggers an request with an ascending (+) sortOrder param when you click on the header for the first time', function(){
    this.scope.sortAttr = 'abc';
    this.scope.$digest();

    this.$httpBackend.expectGET(/\/test.*sortOrder=%2Babc.*/).respond(200);

    this.$headerEl.triggerHandler('click');
    this.scope.$digest();

    this.$httpBackend.flush();
  });

  it('triggers an request with a descending (-) sortOrder param when you click on the header for the second time', function(){
    this.scope.sortAttr = 'abc';
    this.scope.$digest();
    this.$httpBackend.expectGET(/\/test.*sortOrder=%2Babc.*/).respond(200);
    this.$headerEl.triggerHandler('click');
    this.scope.$digest();

    this.$httpBackend.expectGET(/\/test.*sortOrder=-abc.*/).respond(200);
    this.$headerEl.triggerHandler('click');
    this.scope.$digest();

    this.$httpBackend.flush();
  });

  describe('testing visibility', function(){
    it('is visible when no other attributes are set', function(){
      this.tableHeaderTemplate = '	';
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('is hidden when bootstrap class hidden xs is set and the active breakpoint is xs', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is hidden when bootstrap class visible xs is set and the active breakpoint is md', function(){
      activeBreakPoint = 'md';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is visible when bootstrap class hidden xs is set and the active breakpoint is not xs', function(){
      activeBreakPoint = 'md';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('is visible when bootstrap class visible xs is set and the active breakpoint is xs', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('becomes visible when class hidden xs is set and breakpoint becomes inactive', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      activeBreakPoint = 'lg';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('is hidden when class hidden xs is set and breakpoint becomes active', function(){
      activeBreakPoint = 'lg';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      activeBreakPoint = 'xs';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is hidden when hidden attribute is set', function(){
      activeBreakPoint = 'md';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is hidden when hidden attribute is set to true', function(){
      activeBreakPoint = 'md';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is visible when hidden attribute is set to false', function(){
      activeBreakPoint = 'md';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('is hidden when hidden attribute is set to a breakpoint and breakpoint is becoming active', function(){
      activeBreakPoint = 'lg';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      activeBreakPoint = 'xs';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('is hidden when hidden attribute is set to a breakpoint and breakpoint is active', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('becomes visible when hidden attribute is set to a breakpoint and breakpoint is becoming inactive', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      activeBreakPoint = 'lg';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('is visible when hidden attribute is set to a breakpoint and breakpoint is not active', function(){
      activeBreakPoint = 'lg';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('it is visible when hidden attribute is set to a breakpoint and breakpoint active but user has set it to visible', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      isolatedScope.showColumn();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('it is hidden when hidden attribute is set to a breakpoint and breakpoint is inactive but user has set it to hidden', function(){
      activeBreakPoint = 'lg';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();

      isolatedScope.hideColumn();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

    it('it keeps visiblity status when breakpoint is changing', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();
      isolatedScope.showColumn();

      activeBreakPoint = 'md';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      expect(isolatedScope.isVisible()).toBeTruthy();
    });

    it('gets oriignially set visiblity status when calling resetColumnVisibility', function(){
      activeBreakPoint = 'xs';
      this.setHeaderTemplate('	');
      var isolatedScope = this.$headerEl.isolateScope();
      this.$timeout.flush();
      isolatedScope.showColumn();
      activeBreakPoint = 'md';
      this.$rootScope.$broadcast('mwBootstrapBreakpoint:changed', activeBreakPoint);
      isolatedScope.$digest();

      isolatedScope.resetColumnVisibility();

      expect(isolatedScope.isVisible()).toBeFalsy();
    });

  });

});
<|endoftext|>


<commit_before>"use strict";

var assert = require('assert');

describe('reversi', function() {

  describe('game', function() {
    it('should be self-describing', function() {
      var game = new Reversi();

      assert.equal(8, game.width);
      assert.equal(8, game.height);
    });
  });

  describe('acceptance test', function() {

    var sampleInput = '........\n' +
                      '........\n' +
                      '........\n' +
                      '...BW...\n' +
                      '...WB...\n' +
                      '........\n' +
                      '........\n' +
                      '........\n' +
                      'B\n';

    var sampleOutput = '........\n' +
                       '........\n' +
                       '....0...\n' +
                       '...BW0..\n' +
                       '..0WB...\n' +
                       '...0....\n' +
                       '........\n' +
                       '........\n' +
                       'B\n';

    var drive = function(input) {

    };

    it('should produce the expected output', function() {
      assert.equal(sampleOutput, drive(sampleInput));
    });
  });
});
<commit_msg>make the simplest test pass<commit_after>"use strict";

var assert = require('assert');

var Reversi = function() {
  return {
    width: 8,
    height: 8
  };
};

describe('reversi', function() {

  describe('game', function() {
    it('should be self-describing', function() {
      var game = new Reversi();

      assert.equal(8, game.width);
      assert.equal(8, game.height);
    });
  });

  describe('acceptance test', function() {

    var sampleInput = '........\n' +
                      '........\n' +
                      '........\n' +
                      '...BW...\n' +
                      '...WB...\n' +
                      '........\n' +
                      '........\n' +
                      '........\n' +
                      'B\n';

    var sampleOutput = '........\n' +
                       '........\n' +
                       '....0...\n' +
                       '...BW0..\n' +
                       '..0WB...\n' +
                       '...0....\n' +
                       '........\n' +
                       '........\n' +
                       'B\n';

    var drive = function(input) {

    };

    it('should produce the expected output', function() {
      assert.equal(sampleOutput, drive(sampleInput));
    });
  });
});
<|endoftext|>


<commit_before>"use strict";
var assert = require('assert');

var cellFrom = function(c) {
  return new Cell(c);
};

var createCellCollection = function(s) {
  var cells = [];

  for (var i=0;i<s.length;++i) {
    cells.push(cellFrom(s[i]));
  }

  return new CellCollection(cells);
};

var CellCollection = function(cells) {
  return {
    length: cells.length,

    at: function(i) {
      return cells[i];
    },

    validMove: function(idx) {

    }
  };
};

var createBoard = function(s) {
  var lines = s.split('\n');

  var rows = [];

  for (var i=0;i<lines.length;++i) {
    rows.push(createCellCollection(lines[i]));
  }

  return new Board(rows,lines[8][0]);
};

var Board = function(rows,t) {

  var _rowData = rows;

  return {
    rows: 8,
    cols: 8,
    at: function(r,c) {
      return _rowData[r].at(c)
    },
    turn: function() {
      return cellFrom(t);
    }
  };
};

var Cell = function(c) {
  return {
    isBlack: function() { return c === 'B'; },
    isWhite: function() { return c === 'W'; },
    isEmpty: function() { return c === '.'; },

    opposite: function() {
      if (this.isBlack()) { return new Cell('W'); }
      if (this.isWhite()) { return new Cell('B'); }
    }
  };
};

describe('reversi', function() {

  it('basic predicates', function() {

    var bCell = cellFrom('B');
    var wCell = cellFrom('W');
    var eCell = cellFrom('.');

    assert(bCell.isBlack());
    assert(wCell.isWhite());
    assert(eCell.isEmpty());
  });

  it('knows opposites', function() {
    var black = cellFrom('B');
    assert(black.opposite().isWhite());

    var white = cellFrom('W');
    assert(white.opposite().isBlack());
  });

  describe('collections of cells', function() {
    it('can create', function() {
      var cellCollection = createCellCollection('........');
      assert.equal(8, cellCollection.length);
    });

    it('can test for valid moves', function() {
      var cellCollection = createCellCollection('...');
      assert.equal(false, cellCollection.validMove(0));
    });
  });

  it('has a concept of a board', function() {
    var board = createBoard(exampleInput);

    assert.equal(8,board.rows);
    assert.equal(8,board.cols);

    assert(board.at(3,3).isBlack());
    assert(board.at(3,4).isWhite());

    assert(board.turn().isBlack());
  });

  var exampleInput = '........\n' +
                     '........\n' +
                     '........\n' +
                     '...BW...\n' +
                     '...WB...\n' +
                     '........\n' +
                     '........\n' +
                     '........\n' +
                     'B\n';

  var exampleOutput = '........\n' +
                      '........\n' +
                      '....0...\n' +
                      '...BW0..\n' +
                      '..0WB...\n' +
                      '...0....\n' +
                      '........\n' +
                      '........\n' +
                      'B\n';

  var drive = function(input) {
    var board = createBoard(input);
    return 'not done yet';
  };

  describe('acceptance test', function() {
    it('input/output should match expectations', function() {
      assert.equal(exampleOutput, drive(exampleInput));
    });
  });
});
<commit_msg>make the test pass lazily<commit_after>"use strict";
var assert = require('assert');

var cellFrom = function(c) {
  return new Cell(c);
};

var createCellCollection = function(s) {
  var cells = [];

  for (var i=0;i<s.length;++i) {
    cells.push(cellFrom(s[i]));
  }

  return new CellCollection(cells);
};

var CellCollection = function(cells) {
  return {
    length: cells.length,

    at: function(i) {
      return cells[i];
    },

    validMove: function(idx) {
      return false;
    }
  };
};

var createBoard = function(s) {
  var lines = s.split('\n');

  var rows = [];

  for (var i=0;i<lines.length;++i) {
    rows.push(createCellCollection(lines[i]));
  }

  return new Board(rows,lines[8][0]);
};

var Board = function(rows,t) {

  var _rowData = rows;

  return {
    rows: 8,
    cols: 8,
    at: function(r,c) {
      return _rowData[r].at(c)
    },
    turn: function() {
      return cellFrom(t);
    }
  };
};

var Cell = function(c) {
  return {
    isBlack: function() { return c === 'B'; },
    isWhite: function() { return c === 'W'; },
    isEmpty: function() { return c === '.'; },

    opposite: function() {
      if (this.isBlack()) { return new Cell('W'); }
      if (this.isWhite()) { return new Cell('B'); }
    }
  };
};

describe('reversi', function() {

  it('basic predicates', function() {

    var bCell = cellFrom('B');
    var wCell = cellFrom('W');
    var eCell = cellFrom('.');

    assert(bCell.isBlack());
    assert(wCell.isWhite());
    assert(eCell.isEmpty());
  });

  it('knows opposites', function() {
    var black = cellFrom('B');
    assert(black.opposite().isWhite());

    var white = cellFrom('W');
    assert(white.opposite().isBlack());
  });

  describe('collections of cells', function() {
    it('can create', function() {
      var cellCollection = createCellCollection('........');
      assert.equal(8, cellCollection.length);
    });

    it('can test for valid moves', function() {
      var cellCollection = createCellCollection('...');
      assert.equal(false, cellCollection.validMove(0));
    });
  });

  it('has a concept of a board', function() {
    var board = createBoard(exampleInput);

    assert.equal(8,board.rows);
    assert.equal(8,board.cols);

    assert(board.at(3,3).isBlack());
    assert(board.at(3,4).isWhite());

    assert(board.turn().isBlack());
  });

  var exampleInput = '........\n' +
                     '........\n' +
                     '........\n' +
                     '...BW...\n' +
                     '...WB...\n' +
                     '........\n' +
                     '........\n' +
                     '........\n' +
                     'B\n';

  var exampleOutput = '........\n' +
                      '........\n' +
                      '....0...\n' +
                      '...BW0..\n' +
                      '..0WB...\n' +
                      '...0....\n' +
                      '........\n' +
                      '........\n' +
                      'B\n';

  var drive = function(input) {
    var board = createBoard(input);
    return 'not done yet';
  };

  describe('acceptance test', function() {
    it('input/output should match expectations', function() {
      assert.equal(exampleOutput, drive(exampleInput));
    });
  });
});
<|endoftext|>


<commit_before>import macro from 'vtk.js/Sources/macro';
import ImageHelper from 'vtk.js/Sources/Common/Core/ImageHelper';
import vtkTexture from 'vtk.js/Sources/Rendering/Core/Texture';

import JSZip from 'jszip';

// ----------------------------------------------------------------------------
// vtkSkyboxReader methods
// ----------------------------------------------------------------------------

function vtkSkyboxReader(publicAPI, model) {
  // Set our className
  model.classHierarchy.push('vtkSkyboxReader');

  // Internal method to fetch Array
  function fetchData(url, option = {}) {
    const { compression, progressCallback } = model;
    return model.dataAccessHelper.fetchBinary(url, {
      compression,
      progressCallback,
    });
  }

  // Set DataSet url
  publicAPI.setUrl = (url, option = {}) => {
    model.url = url;

    // Fetch metadata
    return publicAPI.loadData(option);
  };

  // Fetch the actual data arrays
  publicAPI.loadData = (option = {}) =>
    fetchData(model.url, option).then(publicAPI.parseAsArrayBuffer);

  publicAPI.parseAsArrayBuffer = (content) => {
    if (!content) {
      return false;
    }
    model.busy = true;
    publicAPI.invokeBusy(model.busy);
    model.dataMapping = {};
    let workCount = 0;

    function workDone() {
      workCount--;

      // Finish data processing
      if (workCount === 0) {
        model.textures = {};
        for (let i = 0; i < model.positions.length; i++) {
          const key = model.positions[i];
          const images = model.dataMapping[key];
          const texture = vtkTexture.newInstance({ interpolate: true });
          for (let idx = 0; idx < 6; idx++) {
            const { fileName, transform } = model.faceMapping[idx];
            texture.setInputData(
              ImageHelper.imageToImageData(images[fileName], transform),
              idx
            );
          }
          model.textures[key] = texture;
        }

        model.busy = false;
        publicAPI.modified();
        publicAPI.invokeBusy(model.busy);
      }
    }

    const zip = new JSZip();
    zip.loadAsync(content).then(() => {
      // Find root index.json
      zip.forEach((relativePath, zipEntry) => {
        if (relativePath.match(/index.json$/)) {
          workCount++;
          zipEntry.async('text').then((txt) => {
            const config = JSON.parse(txt);
            if (config.skybox && config.skybox.faceMapping) {
              model.faceMapping = config.skybox.faceMapping;
            }
            if (
              config.metadata &&
              config.metadata.skybox &&
              config.metadata.skybox.faceMapping
            ) {
              model.faceMapping = config.metadata.skybox.faceMapping;
            }
            workDone();
          });
        }
        if (relativePath.match(/\.jpg$/)) {
          workCount++;
          const pathTokens = relativePath.split('/');
          const fileName = pathTokens.pop();
          const key = pathTokens.pop();
          if (!model.dataMapping[key]) {
            model.dataMapping[key] = {};
          }
          zipEntry.async('base64').then((txt) => {
            const img = new Image();
            model.dataMapping[key][fileName] = img;
            img.onload = workDone;
            img.src = `data:image/jpg;base64,${txt}`;
          });
        }
      });
      model.positions = Object.keys(model.dataMapping);
      model.position = model.positions[0];
    });
    return publicAPI.getReadyPromise();
  };

  publicAPI.requestData = (inData, outData) => {
    outData[0] = model.textures[model.position];
  };

  publicAPI.setPosition = (name) => {
    if (model.positions.indexOf(name) !== -1 && name !== model.position) {
      model.position = name;
      publicAPI.modified();
    }
  };

  publicAPI.getReadyPromise = () => {
    if (!model.busy) {
      return Promise.resolve(publicAPI);
    }
    return new Promise((resolve, reject) => {
      const subscription = publicAPI.onBusy((isBusy) => {
        if (!isBusy) {
          subscription.unsubscribe();
          resolve(publicAPI);
        }
      });
    });
  };

  // return Busy state
  publicAPI.isBusy = () => model.busy;
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
  // url: null,
  busy: false,
  // everything must be flipped in Y due to canvas
  // versus vtk ordering
  faceMapping: [
    { fileName: 'right.jpg', transform: { flipY: true } },
    { fileName: 'left.jpg', transform: { flipY: true } },
    { fileName: 'up.jpg', transform: { flipY: true } },
    { fileName: 'down.jpg', transform: { flipY: true } },
    { fileName: 'back.jpg', transform: { flipY: true } },
    { fileName: 'front.jpg', transform: { flipY: true } },
  ],
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
  Object.assign(model, DEFAULT_VALUES, initialValues);

  // Build VTK API
  macro.obj(publicAPI, model);
  macro.get(publicAPI, model, ['url', 'positions', 'position']);
  macro.setGet(publicAPI, model, ['faceMapping']);
  macro.event(publicAPI, model, 'busy');
  macro.algo(publicAPI, model, 0, 6);

  // Object methods
  vtkSkyboxReader(publicAPI, model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkSkyboxReader');

// ----------------------------------------------------------------------------

export default { newInstance, extend };
<commit_msg>fix(SkyboxReader): Better memory management<commit_after>import macro from 'vtk.js/Sources/macro';
import ImageHelper from 'vtk.js/Sources/Common/Core/ImageHelper';
import vtkTexture from 'vtk.js/Sources/Rendering/Core/Texture';

import JSZip from 'jszip';

// ----------------------------------------------------------------------------
// vtkSkyboxReader methods
// ----------------------------------------------------------------------------

function vtkSkyboxReader(publicAPI, model) {
  // Set our className
  model.classHierarchy.push('vtkSkyboxReader');

  // Internal method to fetch Array
  function fetchData(url, option = {}) {
    const { compression, progressCallback } = model;
    return model.dataAccessHelper.fetchBinary(url, {
      compression,
      progressCallback,
    });
  }

  // Set DataSet url
  publicAPI.setUrl = (url, option = {}) => {
    model.url = url;

    // Fetch metadata
    return publicAPI.loadData(option);
  };

  // Fetch the actual data arrays
  publicAPI.loadData = (option = {}) =>
    fetchData(model.url, option).then(publicAPI.parseAsArrayBuffer);

  publicAPI.parseAsArrayBuffer = (content) => {
    if (!content) {
      return false;
    }
    model.busy = true;
    publicAPI.invokeBusy(model.busy);
    model.dataMapping = {};
    let workCount = 0;

    function workDone() {
      workCount--;

      // Finish data processing
      if (workCount === 0) {
        model.textures = {};
        for (let i = 0; i < model.positions.length; i++) {
          const key = model.positions[i];
          const images = model.dataMapping[key];
          const texture = vtkTexture.newInstance({ interpolate: true });
          for (let idx = 0; idx < 6; idx++) {
            const { fileName, transform } = model.faceMapping[idx];
            texture.setInputData(
              ImageHelper.imageToImageData(images[fileName], transform),
              idx
            );
            // Free image
            URL.revokeObjectURL(images[fileName].src);
            delete images[fileName];
          }
          model.textures[key] = texture;
        }

        model.busy = false;
        publicAPI.modified();
        publicAPI.invokeBusy(model.busy);
      }
    }

    const zip = new JSZip();
    zip.loadAsync(content).then(() => {
      // Find root index.json
      zip.forEach((relativePath, zipEntry) => {
        if (relativePath.match(/index.json$/)) {
          workCount++;
          zipEntry.async('text').then((txt) => {
            const config = JSON.parse(txt);
            if (config.skybox && config.skybox.faceMapping) {
              model.faceMapping = config.skybox.faceMapping;
            }
            if (
              config.metadata &&
              config.metadata.skybox &&
              config.metadata.skybox.faceMapping
            ) {
              model.faceMapping = config.metadata.skybox.faceMapping;
            }
            workDone();
          });
        }
        if (relativePath.match(/\.jpg$/)) {
          workCount++;
          const pathTokens = relativePath.split('/');
          const fileName = pathTokens.pop();
          const key = pathTokens.pop();
          if (!model.dataMapping[key]) {
            model.dataMapping[key] = {};
          }
          zipEntry.async('blob').then((blob) => {
            const img = new Image();
            model.dataMapping[key][fileName] = img;
            img.onload = workDone;
            img.src = URL.createObjectURL(blob);
          });
        }
      });
      model.positions = Object.keys(model.dataMapping);
      model.position = model.positions[0];
    });
    return publicAPI.getReadyPromise();
  };

  publicAPI.requestData = (inData, outData) => {
    outData[0] = model.textures[model.position];
  };

  publicAPI.setPosition = (name) => {
    if (model.positions.indexOf(name) !== -1 && name !== model.position) {
      model.position = name;
      publicAPI.modified();
    }
  };

  publicAPI.getReadyPromise = () => {
    if (!model.busy) {
      return Promise.resolve(publicAPI);
    }
    return new Promise((resolve, reject) => {
      const subscription = publicAPI.onBusy((isBusy) => {
        if (!isBusy) {
          subscription.unsubscribe();
          resolve(publicAPI);
        }
      });
    });
  };

  // return Busy state
  publicAPI.isBusy = () => model.busy;
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
  // url: null,
  busy: false,
  // everything must be flipped in Y due to canvas
  // versus vtk ordering
  faceMapping: [
    { fileName: 'right.jpg', transform: { flipY: true } },
    { fileName: 'left.jpg', transform: { flipY: true } },
    { fileName: 'up.jpg', transform: { flipY: true } },
    { fileName: 'down.jpg', transform: { flipY: true } },
    { fileName: 'back.jpg', transform: { flipY: true } },
    { fileName: 'front.jpg', transform: { flipY: true } },
  ],
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
  Object.assign(model, DEFAULT_VALUES, initialValues);

  // Build VTK API
  macro.obj(publicAPI, model);
  macro.get(publicAPI, model, ['url', 'positions', 'position']);
  macro.setGet(publicAPI, model, ['faceMapping']);
  macro.event(publicAPI, model, 'busy');
  macro.algo(publicAPI, model, 0, 6);

  // Object methods
  vtkSkyboxReader(publicAPI, model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkSkyboxReader');

// ----------------------------------------------------------------------------

export default { newInstance, extend };
<|endoftext|>


<commit_before>var currentRepo;
var defaultRepo;
var endpoint;
var fileHistory = [];
var hfmEnabled = false;
var hfmTimeout;
var nextFile;

$(document).ready(function() {
    var hash = window.location.hash.substring(2);

    ClickEvents();
    RepositorySelectEvent();
    SidebarToggleEvent();

    ResizeTagsBox();

    if(hash === "") {
        SetupSite(true);
    } else {
        SetupSite(false);
    };
});

window.addEventListener('resize', function(event){
    ResizeTagsBox();
});

window.addEventListener("hashchange", function(event) {
    GetFile();
});

function ClickEvents() {
    $("#about-button").click(function(e) {
        e.preventDefault();
        TogglePanel("about");
    });

    $("#about-panel-close").click(function(e) {
        e.preventDefault(0);
        TogglePanel("about");
    });

    $("#backward-button").click(function(e) {
        e.preventDefault();

        ToggleHfm();

        fileHistory.pop();
        var lastItem = fileHistory.pop();

        window.location.hash = "/" + lastItem;
    });

    $("#hfm-button").click(function(e) {
        e.preventDefault();
        TogglePanel("hfm");
    });

    $("#hfm-panel-close").click(function(e) {
        e.preventDefault();
        TogglePanel("hfm");
    });

    $("#random-button").click(function(e) {
        e.preventDefault();
        ToggleHfm();
        GetRandomFile();
    });

    $("#random-mini-button").click(function(e) {
        e.preventDefault();
        ToggleHfm();
        GetRandomFile();
    });

    $("#start-hfm-button").on("click", function() {
        var int = $("#hfm-interval-input").val();
        ToggleHfm(int);
    });

    $("#view").click(function() {
        ToggleHfm();
        GetRandomFile();
    });
}

function GetFile() {
    var currentFile = window.location.hash.substring(2);

    $("#direct-button").attr("href", endpoint + currentFile);
    $("#view").css("background-image", "url('" + endpoint + currentFile + "')");

    StoreHistory(currentFile);
};

function GetRandomFile() {
    $.ajax({
        url: '/api/v1/random/' + currentRepo.toLowerCase(),
        type: 'GET',
        contentType: "application/json; charset=utf-8",
        dataType: 'json',
        success: function (data)
        {
            if(nextFile) {
                window.location.hash = nextFile;
                PreloadFile(false);
            } else {
                window.location.hash = data.file;
                PreloadFile(false);
            }
        },
        failure: function (data)
        {
            // handle error
        }
    });
}

function PreloadFile(keepTrying) {
    $.ajax({
        url: '/api/v1/random/' + currentRepo.toLowerCase(),
        type: 'GET',
        contentType: "application/json; charset=utf-8",
        dataType: 'json',
        success: function (data)
        {
            if(data.file.endsWith(".png") ||
                data.file.endsWith(".jpg") ||
                data.file.endsWith(".gif")) {
                    $("#image-preload").attr("src", data.url);
                    nextFile = data.file;
            } else {
                if(keepTrying) {
                    PreloadFile(true);
                } else {
                    nextFile = "";
                }
            }
        },
        failure: function (data)
        {
            // handle error
        }
    });
}

function RepositorySelectEvent() {
    $("#repository-selector").change(function() {
        currentRepo = $("#repository-selector").val();
        PreloadFile();
        GetRandomFile();
    });
}

function ResizeTagsBox() {
    $("#sidebar-tags-inner").css("height", "0");

    var requiredHeight = $("#sidebar-tags").height() + "px";

    $("#sidebar-tags-inner").css("height", requiredHeight);
};

function SetupSite(loadFile) {
    $.ajax({
        url: '/api/v1/site',
        type: 'GET',
        contentType: "application/json; charset=utf-8",
        dataType: 'json',
        success: function (data)
        {
            if(window.location.pathname === "/") {
                currentRepo = data.default;
            } else {
                currentRepo = window.location.pathname.slice(1);
                if(window.location.hash) {
                    history.pushState(null, null, '/' + window.location.hash);
                } else {
                    history.pushState(null, null, '/');
                }
            }

            defaultRepo = data.default;
            endpoint = data.endpoint;

            var repos = data.repos.split("|");

            $.each(repos, function(index) {
                $("#repository-selector").append(
                    $("<option>", {}).append(
                        repos[index].toLowerCase()
                    )
                );
            });

            $("#repository-selector").val(currentRepo.toLowerCase());

            if(loadFile) {
                GetRandomFile();
            } else {
                GetFile();
                PreloadFile(true);
            }
        }
    });
};

function SidebarToggleEvent() {
    $("#show-sidebar-button").click(function(e) {
        e.preventDefault(0);
        ToggleSidebar();
    })

    $("#hide-sidebar-button").click(function(e) {
        e.preventDefault(0);
        ToggleSidebar();
    });
};

function StoreHistory(file) {
    fileHistory.push(file);

    if(fileHistory.length === 1) {
        $(".backward-button-item").addClass("disabled");
    } else {
        $(".backward-button-item").removeClass("disabled");
    }
};

function ToggleHfm(interval) {
    if(interval) {
        if(hfmEnabled) {
            $("#hfm-button .fa").css("color", "inherit");
            hfmEnabled = false;
            clearInterval(hfmTimeout);
        } else {
            $("#hfm-button .fa").css("color", "red");
            hfmEnabled = true;
            hfmTimeout = setInterval(function() {
                GetRandomFile();
            }, interval*1000);
        }
    } else {
        $("#hfm-button .fa").css("color", "inherit");
        hfmEnabled = false;
        clearInterval(hfmTimeout);
    }
}

function TogglePanel(name) {
    if($("#" + name + "-panel").css("display") === "block") {
        $("#panel-overlay").css("display", "");
        $("#" + name + "-panel").css("display", "");
    } else {
        $("#panel-overlay").css("display", "block");
        $("#" + name + "-panel").css("display", "block");
    }
}

function ToggleSidebar() {
    ResizeTagsBox();

    if(!$("#sidebar").hasClass("visible")) {
        $("#sidebar-mini-reminder").addClass("invisible");
    }

    if($("#sidebar").hasClass("visible")) {
        $("#sidebar-mini").removeClass("hidden");
        $("#sidebar").removeClass("visible");
        $("#view").addClass("full");
    } else {
        $("#sidebar-mini").addClass("hidden");
        $("#sidebar").addClass("visible");
        $("#view").removeClass("full");
    }
};<commit_msg>Add file history limit<commit_after>var currentRepo;
var defaultRepo;
var endpoint;
var fileHistory = [];
var hfmEnabled = false;
var hfmTimeout;
var nextFile;

$(document).ready(function() {
    var hash = window.location.hash.substring(2);

    ClickEvents();
    RepositorySelectEvent();
    SidebarToggleEvent();

    ResizeTagsBox();

    if(hash === "") {
        SetupSite(true);
    } else {
        SetupSite(false);
    };
});

window.addEventListener('resize', function(event){
    ResizeTagsBox();
});

window.addEventListener("hashchange", function(event) {
    GetFile();
});

function ClickEvents() {
    $("#about-button").click(function(e) {
        e.preventDefault();
        TogglePanel("about");
    });

    $("#about-panel-close").click(function(e) {
        e.preventDefault(0);
        TogglePanel("about");
    });

    $("#backward-button").click(function(e) {
        e.preventDefault();

        ToggleHfm();

        fileHistory.pop();
        var lastItem = fileHistory.pop();

        window.location.hash = "/" + lastItem;
    });

    $("#hfm-button").click(function(e) {
        e.preventDefault();
        TogglePanel("hfm");
    });

    $("#hfm-panel-close").click(function(e) {
        e.preventDefault();
        TogglePanel("hfm");
    });

    $("#random-button").click(function(e) {
        e.preventDefault();
        ToggleHfm();
        GetRandomFile();
    });

    $("#random-mini-button").click(function(e) {
        e.preventDefault();
        ToggleHfm();
        GetRandomFile();
    });

    $("#start-hfm-button").on("click", function() {
        var int = $("#hfm-interval-input").val();
        ToggleHfm(int);
    });

    $("#view").click(function() {
        ToggleHfm();
        GetRandomFile();
    });
}

function GetFile() {
    var currentFile = window.location.hash.substring(2);

    $("#direct-button").attr("href", endpoint + currentFile);
    $("#view").css("background-image", "url('" + endpoint + currentFile + "')");

    StoreHistory(currentFile);
};

function GetRandomFile() {
    $.ajax({
        url: '/api/v1/random/' + currentRepo.toLowerCase(),
        type: 'GET',
        contentType: "application/json; charset=utf-8",
        dataType: 'json',
        success: function (data)
        {
            if(nextFile) {
                window.location.hash = nextFile;
                PreloadFile(false);
            } else {
                window.location.hash = data.file;
                PreloadFile(false);
            }
        },
        failure: function (data)
        {
            // handle error
        }
    });
}

function PreloadFile(keepTrying) {
    $.ajax({
        url: '/api/v1/random/' + currentRepo.toLowerCase(),
        type: 'GET',
        contentType: "application/json; charset=utf-8",
        dataType: 'json',
        success: function (data)
        {
            if(data.file.endsWith(".png") ||
                data.file.endsWith(".jpg") ||
                data.file.endsWith(".gif")) {
                    $("#image-preload").attr("src", data.url);
                    nextFile = data.file;
            } else {
                if(keepTrying) {
                    PreloadFile(true);
                } else {
                    nextFile = "";
                }
            }
        },
        failure: function (data)
        {
            // handle error
        }
    });
}

function RepositorySelectEvent() {
    $("#repository-selector").change(function() {
        currentRepo = $("#repository-selector").val();
        PreloadFile();
        GetRandomFile();
    });
}

function ResizeTagsBox() {
    $("#sidebar-tags-inner").css("height", "0");

    var requiredHeight = $("#sidebar-tags").height() + "px";

    $("#sidebar-tags-inner").css("height", requiredHeight);
};

function SetupSite(loadFile) {
    $.ajax({
        url: '/api/v1/site',
        type: 'GET',
        contentType: "application/json; charset=utf-8",
        dataType: 'json',
        success: function (data)
        {
            if(window.location.pathname === "/") {
                currentRepo = data.default;
            } else {
                currentRepo = window.location.pathname.slice(1);
                if(window.location.hash) {
                    history.pushState(null, null, '/' + window.location.hash);
                } else {
                    history.pushState(null, null, '/');
                }
            }

            defaultRepo = data.default;
            endpoint = data.endpoint;

            var repos = data.repos.split("|");

            $.each(repos, function(index) {
                $("#repository-selector").append(
                    $("<option>", {}).append(
                        repos[index].toLowerCase()
                    )
                );
            });

            $("#repository-selector").val(currentRepo.toLowerCase());

            if(loadFile) {
                GetRandomFile();
            } else {
                GetFile();
                PreloadFile(true);
            }
        }
    });
};

function SidebarToggleEvent() {
    $("#show-sidebar-button").click(function(e) {
        e.preventDefault(0);
        ToggleSidebar();
    })

    $("#hide-sidebar-button").click(function(e) {
        e.preventDefault(0);
        ToggleSidebar();
    });
};

function StoreHistory(file) {
    fileHistory.push(file);

    if(fileHistory.length === 1) {
        $(".backward-button-item").addClass("disabled");
    } else {
        $(".backward-button-item").removeClass("disabled");
    }

    // prunce history if there is 100 items, just so
    // we don't clutter up the user's memory
    if(fileHistory.length === 101) {
        fileHistory.shift();
    }

    console.log(fileHistory);
};

function ToggleHfm(interval) {
    if(interval) {
        if(hfmEnabled) {
            $("#hfm-button .fa").css("color", "inherit");
            hfmEnabled = false;
            clearInterval(hfmTimeout);
        } else {
            $("#hfm-button .fa").css("color", "red");
            hfmEnabled = true;
            hfmTimeout = setInterval(function() {
                GetRandomFile();
            }, interval*1000);
        }
    } else {
        $("#hfm-button .fa").css("color", "inherit");
        hfmEnabled = false;
        clearInterval(hfmTimeout);
    }
}

function TogglePanel(name) {
    if($("#" + name + "-panel").css("display") === "block") {
        $("#panel-overlay").css("display", "");
        $("#" + name + "-panel").css("display", "");
    } else {
        $("#panel-overlay").css("display", "block");
        $("#" + name + "-panel").css("display", "block");
    }
}

function ToggleSidebar() {
    ResizeTagsBox();

    if(!$("#sidebar").hasClass("visible")) {
        $("#sidebar-mini-reminder").addClass("invisible");
    }

    if($("#sidebar").hasClass("visible")) {
        $("#sidebar-mini").removeClass("hidden");
        $("#sidebar").removeClass("visible");
        $("#view").addClass("full");
    } else {
        $("#sidebar-mini").addClass("hidden");
        $("#sidebar").addClass("visible");
        $("#view").removeClass("full");
    }
};<|endoftext|>


<commit_before>// @flow
import React from 'react';
import CommonMark from 'commonmark';
import MarkdownRenderer from 'commonmark-react-renderer';

import Editor from './editor';
import LatexRenderer from '../latex';

type Props = {
  cell: any,
  id: string,
  theme: string,
  cursorBlinkRate: number,
  focusAbove: Function,
  focusBelow: Function,
  focusEditor: Function,
  cellFocused: boolean,
  editorFocused: boolean,
};

type State = {
  view: boolean,
  source: string,
};

type MDRender = (input: string) => string

const parser = new CommonMark.Parser();
const renderer = new MarkdownRenderer();

const mdRender: MDRender = input => renderer.render(parser.parse(input));

export default class MarkdownCell extends React.PureComponent {
  state: State;
  openEditor: () => void;
  editorKeyDown: (e: Object) => void;
  renderedKeyDown: (e: Object) => boolean;
  rendered: HTMLElement;

  static contextTypes = {
    store: React.PropTypes.object,
  };

  static defaultProps = {
    cellFocused: false,
  };

  constructor(props: Props): void {
    super(props);
    this.state = {
      view: true,
      // HACK: We'll need to handle props and state change better here
      source: this.props.cell.get('source'),
    };
    this.openEditor = this.openEditor.bind(this);
    this.editorKeyDown = this.editorKeyDown.bind(this);
    this.renderedKeyDown = this.renderedKeyDown.bind(this);
  }

  componentDidMount(): void {
    this.updateFocus();
  }

  componentWillReceiveProps(nextProps: Props): void {
    this.setState({
      source: nextProps.cell.get('source'),
    });
  }

  componentDidUpdate(): void {
    this.updateFocus();
  }

  updateFocus(): void {
    if (this.state && this.state.view && this.props.cellFocused) {
      this.rendered.focus();
    }
  }

  /**
   * Handles when a keydown event occurs on the unrendered MD cell
   */
  editorKeyDown(e: Object): void {
    const shift = e.shiftKey;
    const ctrl = e.ctrlKey;
    if ((shift || ctrl) && e.key === 'Enter') {
      this.setState({ view: true });
    }
  }

  openEditor(): void {
    this.setState({ view: false });
    this.props.focusEditor();
  }

  /**
   * Handles when a keydown event occurs on the rendered MD cell
   */
  renderedKeyDown(e: Object): boolean {
    const shift = e.shiftKey;
    const ctrl = e.ctrlKey;
    if ((shift || ctrl) && e.key === 'Enter') {
      this.setState({ view: true });
      return false;
    }

    switch (e.key) {
      case 'ArrowUp':
        this.props.focusAbove();
        break;
      case 'ArrowDown':
        this.props.focusBelow();
        break;
      case 'Enter':
        this.openEditor();
        e.preventDefault();
        return false;
      default:
    }
    return true;
  }

  render(): ?React.Element<any> {
    return (
       (this.state && this.state.view) ?

 { this.rendered = rendered; }}
           tabIndex="0"
         >
           <LatexRenderer>
             {
              mdRender(
                this.state.source ?
                this.state.source :
                '*Empty markdown cell, double click me to add content.*')
             }
           </LatexRenderer>

 :

             <Editor
               language="markdown"
               id={this.props.id}
               lineWrapping
               input={this.state.source}
               theme={this.props.theme}
               cursorBlinkRate={this.props.cursorBlinkRate}
               focusAbove={this.props.focusAbove}
               focusBelow={this.props.focusBelow}
               cellFocused={this.props.cellFocused}
               editorFocused={this.props.editorFocused}
             />

             <LatexRenderer>
               { mdRender(this.state.source) }
             </LatexRenderer>

    );
  }
}
<commit_msg>feat(markdown-cell):  keep markdown cell in editing mode (#1409)<commit_after>// @flow
import React from 'react';
import CommonMark from 'commonmark';
import MarkdownRenderer from 'commonmark-react-renderer';

import Editor from './editor';
import LatexRenderer from '../latex';

type Props = {
  cell: any,
  id: string,
  theme: string,
  cursorBlinkRate: number,
  focusAbove: Function,
  focusBelow: Function,
  focusEditor: Function,
  cellFocused: boolean,
  editorFocused: boolean,
};

type State = {
  view: boolean,
  source: string,
};

type MDRender = (input: string) => string

const parser = new CommonMark.Parser();
const renderer = new MarkdownRenderer();

const mdRender: MDRender = input => renderer.render(parser.parse(input));

export default class MarkdownCell extends React.PureComponent {
  state: State;
  openEditor: () => void;
  editorKeyDown: (e: Object) => void;
  renderedKeyDown: (e: Object) => boolean;
  rendered: HTMLElement;

  static contextTypes = {
    store: React.PropTypes.object,
  };

  static defaultProps = {
    cellFocused: false,
  };

  constructor(props: Props): void {
    super(props);
    this.state = {
      view: true,
      // HACK: We'll need to handle props and state change better here
      source: this.props.cell.get('source'),
    };
    this.openEditor = this.openEditor.bind(this);
    this.editorKeyDown = this.editorKeyDown.bind(this);
    this.renderedKeyDown = this.renderedKeyDown.bind(this);
  }

  componentDidMount(): void {
    this.updateFocus();
  }

  componentWillReceiveProps(nextProps: Props): void {
    this.setState({
      source: nextProps.cell.get('source'),
    });
  }

  componentDidUpdate(): void {
    this.updateFocus();
  }

  updateFocus(): void {
    if (this.state && this.state.view && this.props.cellFocused) {
      this.rendered.focus();
      if (this.props.editorFocused) {
        this.openEditor();
      }
    }
  }

  /**
   * Handles when a keydown event occurs on the unrendered MD cell
   */
  editorKeyDown(e: Object): void {
    const shift = e.shiftKey;
    const ctrl = e.ctrlKey;
    if ((shift || ctrl) && e.key === 'Enter') {
      this.setState({ view: true });
    }
  }

  openEditor(): void {
    this.setState({ view: false });
    this.props.focusEditor();
  }

  /**
   * Handles when a keydown event occurs on the rendered MD cell
   */
  renderedKeyDown(e: Object): boolean {
    const shift = e.shiftKey;
    const ctrl = e.ctrlKey;
    if ((shift || ctrl) && e.key === 'Enter') {
      this.setState({ view: true });
      return false;
    }

    switch (e.key) {
      case 'ArrowUp':
        this.props.focusAbove();
        break;
      case 'ArrowDown':
        this.props.focusBelow();
        break;
      case 'Enter':
        this.openEditor();
        e.preventDefault();
        return false;
      default:
    }
    return true;
  }

  render(): ?React.Element<any> {
    return (
       (this.state && this.state.view) ?

 { this.rendered = rendered; }}
           tabIndex="0"
         >
           <LatexRenderer>
             {
              mdRender(
                this.state.source ?
                this.state.source :
                '*Empty markdown cell, double click me to add content.*')
             }
           </LatexRenderer>

 :

             <Editor
               language="markdown"
               id={this.props.id}
               lineWrapping
               input={this.state.source}
               theme={this.props.theme}
               cursorBlinkRate={this.props.cursorBlinkRate}
               focusAbove={this.props.focusAbove}
               focusBelow={this.props.focusBelow}
               cellFocused={this.props.cellFocused}
               editorFocused={this.props.editorFocused}
             />

             <LatexRenderer>
               { mdRender(this.state.source) }
             </LatexRenderer>

    );
  }
}
<|endoftext|>


<commit_before>/*
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

'use strict';

const configCommon = require('config');
const config = configCommon.get('services.CoAuthoring');
//process.env.NODE_ENV = config.get('server.mode');
const logger = require('./../../Common/sources/logger');
const co = require('co');
const license = require('./../../Common/sources/license');
const fs = require('fs');

const express = require('express');
const http = require('http');
const urlModule = require('url');
const path = require('path');
const bodyParser = require("body-parser");
const mime = require('mime');
const docsCoServer = require('./DocsCoServer');
const canvasService = require('./canvasservice');
const converterService = require('./converterservice');
const fileUploaderService = require('./fileuploaderservice');
const constants = require('./../../Common/sources/constants');
const utils = require('./../../Common/sources/utils');
const commonDefines = require('./../../Common/sources/commondefines');
const configStorage = configCommon.get('storage');
const app = express();
const server = http.createServer(app);

let licenseInfo, updatePluginsTime, userPlugins, pluginsLoaded;

const updatePlugins = (eventType, filename) => {
	console.log('update Folder: %s ; %s', eventType, filename);
	if (updatePluginsTime && 1000 >= (new Date() - updatePluginsTime)) {
		return;
	}
	console.log('update Folder true: %s ; %s', eventType, filename);
	updatePluginsTime = new Date();
	pluginsLoaded = false;
};
const readLicense = function*() {
	licenseInfo = yield* license.readLicense();
};
const updateLicense = () => {
	return co(function*() {
		try {
			yield* readLicense();
			docsCoServer.setLicenseInfo(licenseInfo);
			console.log('End updateLicense');
		} catch (err) {
			logger.error('updateLicense error:\r\n%s', err.stack);
		}
	});
};

logger.warn('Express server starting...');

updateLicense();

if (config.has('server.static_content')) {
	const staticContent = config.get('server.static_content');
	for (let i in staticContent) {
		app.use(i, express.static(staticContent[i]['path'], staticContent[i]['options']));
	}
}

if (configStorage.has('fs.folderPath')) {
	const cfgBucketName = configStorage.get('bucketName');
	const cfgStorageFolderName = configStorage.get('storageFolderName');
	app.use('/' + cfgBucketName + '/' + cfgStorageFolderName, (req, res, next) => {
		const index = req.url.lastIndexOf('/');
		if ('GET' === req.method && -1 != index) {
			const contentDisposition = req.query['disposition'] || 'attachment';
			let sendFileOptions = {
				root: configStorage.get('fs.folderPath'), dotfiles: 'deny', headers: {
					'Content-Disposition': contentDisposition
				}
			};
			const urlParsed = urlModule.parse(req.url);
			if (urlParsed && urlParsed.pathname) {
				const filename = decodeURIComponent(path.basename(urlParsed.pathname));
				sendFileOptions.headers['Content-Type'] = mime.getType(filename);
			}
			const realUrl = req.url.substring(0, index);
			res.sendFile(realUrl, sendFileOptions, (err) => {
				if (err) {
					logger.error(err);
					res.status(400).end();
				}
			});
		} else {
			res.sendStatus(404)
		}
	});
}

try {
	fs.watch(config.get('plugins.path'), updatePlugins);
} catch (e) {
	logger.warn('Plugins watch exception (https://nodejs.org/docs/latest/api/fs.html#fs_availability).');
}
fs.watchFile(configCommon.get('license').get('license_file'), updateLicense);
setInterval(updateLicense, 86400000);

// Если захочется использовать 'development' и 'production',
// то с помощью app.settings.env (https://github.com/strongloop/express/issues/936)
// Если нужна обработка ошибок, то теперь она такая https://github.com/expressjs/errorhandler
docsCoServer.install(server, () => {
	console.log('Start callbackFunction');

	server.listen(config.get('server.port'), () => {
		logger.warn("Express server listening on port %d in %s mode", config.get('server.port'), app.settings.env);
	});

	app.get('/index.html', (req, res) => {
		res.send('Server is functioning normally. Version: ' + commonDefines.buildVersion + '. Build: ' +
			commonDefines.buildNumber);
	});
	const rawFileParser = bodyParser.raw(
		{inflate: true, limit: config.get('server.limits_tempfile_upload'), type: function() {return true;}});

	app.get('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser, docsCoServer.commandFromServer);
	app.post('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser,
		docsCoServer.commandFromServer);

	app.get('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
	app.post('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
	app.post('/converter', utils.checkClientIp, rawFileParser, converterService.convertJson);

	app.get('/FileUploader.ashx', utils.checkClientIp, rawFileParser, fileUploaderService.uploadTempFile);
	app.post('/FileUploader.ashx', utils.checkClientIp, rawFileParser, fileUploaderService.uploadTempFile);

	const docIdRegExp = new RegExp("^[" + constants.DOC_ID_PATTERN + "]*$", 'i');
	app.param('docid', (req, res, next, val) => {
		if (docIdRegExp.test(val)) {
			next();
		} else {
			res.sendStatus(403);
		}
	});
	app.param('index', (req, res, next, val) => {
		if (!isNaN(parseInt(val))) {
			next();
		} else {
			res.sendStatus(403);
		}
	});
	app.post('/uploadold/:docid/:userid/:index', fileUploaderService.uploadImageFileOld);
	app.post('/upload/:docid/:userid/:index', rawFileParser, fileUploaderService.uploadImageFile);

	app.post('/downloadas/:docid', rawFileParser, canvasService.downloadAs);
	app.post('/savefile/:docid', rawFileParser, canvasService.saveFile);
	app.get('/healthcheck', utils.checkClientIp, docsCoServer.healthCheck);

	app.get('/baseurl', (req, res) => {
		res.send(utils.getBaseUrlByRequest(req));
	});

	app.get('/robots.txt', (req, res) => {
		res.setHeader('Content-Type', 'plain/text');
		res.send("User-agent: *\nDisallow: /");
	});

	app.post('/docbuilder', utils.checkClientIp, rawFileParser, (req, res) => {
		converterService.builder(req, res);
	});
	app.get('/info/info.json', utils.checkClientIp, docsCoServer.licenseInfo);
	app.put('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
	app.delete('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);

	const sendUserPlugins = (res, data) => {
		pluginsLoaded = true;
		res.setHeader('Content-Type', 'application/json');
		res.send(JSON.stringify(data));
	};
	app.get('/plugins.json', (req, res) => {
		if (userPlugins && pluginsLoaded) {
			sendUserPlugins(res, userPlugins);
			return;
		}

		if (!config.has('server.static_content') || !config.has('plugins.uri')) {
			res.sendStatus(404);
			return;
		}

		let staticContent = config.get('server.static_content');
		let pluginsUri = config.get('plugins.uri');
		let pluginsPath = undefined;
		let pluginsAutostart = config.get('plugins.autostart');

		if (staticContent[pluginsUri]) {
			pluginsPath = staticContent[pluginsUri].path;
		}

		let baseUrl = '../../../..';
		utils.listFolders(pluginsPath, true).then((values) => {
			return co(function*() {
				const configFile = 'config.json';
				let stats = null;
				let result = [];
				for (let i = 0; i < values.length; ++i) {
					try {
						stats = yield utils.fsStat(path.join(values[i], configFile));
					} catch (err) {
						stats = null;
					}

					if (stats && stats.isFile) {
						result.push( baseUrl + pluginsUri + '/' + path.basename(values[i]) + '/' + configFile);
					}
				}

				userPlugins = {'url': '', 'pluginsData': result, 'autostart': pluginsAutostart};
				sendUserPlugins(res, userPlugins);
			});
		});
	});
});

process.on('uncaughtException', (err) => {
	logger.error((new Date).toUTCString() + ' uncaughtException:', err.message);
	logger.error(err.stack);
	logger.shutdown(() => {
		process.exit(1);
	});
});
<commit_msg>[plugins] Update<commit_after>/*
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

'use strict';

const configCommon = require('config');
const config = configCommon.get('services.CoAuthoring');
//process.env.NODE_ENV = config.get('server.mode');
const logger = require('./../../Common/sources/logger');
const co = require('co');
const license = require('./../../Common/sources/license');
const fs = require('fs');

const express = require('express');
const http = require('http');
const urlModule = require('url');
const path = require('path');
const bodyParser = require("body-parser");
const mime = require('mime');
const docsCoServer = require('./DocsCoServer');
const canvasService = require('./canvasservice');
const converterService = require('./converterservice');
const fileUploaderService = require('./fileuploaderservice');
const constants = require('./../../Common/sources/constants');
const utils = require('./../../Common/sources/utils');
const commonDefines = require('./../../Common/sources/commondefines');
const configStorage = configCommon.get('storage');
const app = express();
const server = http.createServer(app);

let licenseInfo, updatePluginsTime, userPlugins, pluginsLoaded;

const updatePlugins = (eventType, filename) => {
	console.log('update Folder: %s ; %s', eventType, filename);
	if (updatePluginsTime && 1000 >= (new Date() - updatePluginsTime)) {
		return;
	}
	console.log('update Folder true: %s ; %s', eventType, filename);
	updatePluginsTime = new Date();
	pluginsLoaded = false;
};
const readLicense = function*() {
	licenseInfo = yield* license.readLicense();
};
const updateLicense = () => {
	return co(function*() {
		try {
			yield* readLicense();
			docsCoServer.setLicenseInfo(licenseInfo);
			console.log('End updateLicense');
		} catch (err) {
			logger.error('updateLicense error:\r\n%s', err.stack);
		}
	});
};

logger.warn('Express server starting...');

updateLicense();

if (config.has('server.static_content')) {
	const staticContent = config.get('server.static_content');
	for (let i in staticContent) {
		app.use(i, express.static(staticContent[i]['path'], staticContent[i]['options']));
	}
}

if (configStorage.has('fs.folderPath')) {
	const cfgBucketName = configStorage.get('bucketName');
	const cfgStorageFolderName = configStorage.get('storageFolderName');
	app.use('/' + cfgBucketName + '/' + cfgStorageFolderName, (req, res, next) => {
		const index = req.url.lastIndexOf('/');
		if ('GET' === req.method && -1 != index) {
			const contentDisposition = req.query['disposition'] || 'attachment';
			let sendFileOptions = {
				root: configStorage.get('fs.folderPath'), dotfiles: 'deny', headers: {
					'Content-Disposition': contentDisposition
				}
			};
			const urlParsed = urlModule.parse(req.url);
			if (urlParsed && urlParsed.pathname) {
				const filename = decodeURIComponent(path.basename(urlParsed.pathname));
				sendFileOptions.headers['Content-Type'] = mime.getType(filename);
			}
			const realUrl = req.url.substring(0, index);
			res.sendFile(realUrl, sendFileOptions, (err) => {
				if (err) {
					logger.error(err);
					res.status(400).end();
				}
			});
		} else {
			res.sendStatus(404)
		}
	});
}

try {
	fs.watch(config.get('plugins.path'), updatePlugins);
} catch (e) {
	logger.warn('Failed to subscribe to plugin folder updates. When changing the list of plugins, you must restart the server. https://nodejs.org/docs/latest/api/fs.html#fs_availability');
}
fs.watchFile(configCommon.get('license').get('license_file'), updateLicense);
setInterval(updateLicense, 86400000);

// Если захочется использовать 'development' и 'production',
// то с помощью app.settings.env (https://github.com/strongloop/express/issues/936)
// Если нужна обработка ошибок, то теперь она такая https://github.com/expressjs/errorhandler
docsCoServer.install(server, () => {
	console.log('Start callbackFunction');

	server.listen(config.get('server.port'), () => {
		logger.warn("Express server listening on port %d in %s mode", config.get('server.port'), app.settings.env);
	});

	app.get('/index.html', (req, res) => {
		res.send('Server is functioning normally. Version: ' + commonDefines.buildVersion + '. Build: ' +
			commonDefines.buildNumber);
	});
	const rawFileParser = bodyParser.raw(
		{inflate: true, limit: config.get('server.limits_tempfile_upload'), type: function() {return true;}});

	app.get('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser, docsCoServer.commandFromServer);
	app.post('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser,
		docsCoServer.commandFromServer);

	app.get('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
	app.post('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
	app.post('/converter', utils.checkClientIp, rawFileParser, converterService.convertJson);

	app.get('/FileUploader.ashx', utils.checkClientIp, rawFileParser, fileUploaderService.uploadTempFile);
	app.post('/FileUploader.ashx', utils.checkClientIp, rawFileParser, fileUploaderService.uploadTempFile);

	const docIdRegExp = new RegExp("^[" + constants.DOC_ID_PATTERN + "]*$", 'i');
	app.param('docid', (req, res, next, val) => {
		if (docIdRegExp.test(val)) {
			next();
		} else {
			res.sendStatus(403);
		}
	});
	app.param('index', (req, res, next, val) => {
		if (!isNaN(parseInt(val))) {
			next();
		} else {
			res.sendStatus(403);
		}
	});
	app.post('/uploadold/:docid/:userid/:index', fileUploaderService.uploadImageFileOld);
	app.post('/upload/:docid/:userid/:index', rawFileParser, fileUploaderService.uploadImageFile);

	app.post('/downloadas/:docid', rawFileParser, canvasService.downloadAs);
	app.post('/savefile/:docid', rawFileParser, canvasService.saveFile);
	app.get('/healthcheck', utils.checkClientIp, docsCoServer.healthCheck);

	app.get('/baseurl', (req, res) => {
		res.send(utils.getBaseUrlByRequest(req));
	});

	app.get('/robots.txt', (req, res) => {
		res.setHeader('Content-Type', 'plain/text');
		res.send("User-agent: *\nDisallow: /");
	});

	app.post('/docbuilder', utils.checkClientIp, rawFileParser, (req, res) => {
		converterService.builder(req, res);
	});
	app.get('/info/info.json', utils.checkClientIp, docsCoServer.licenseInfo);
	app.put('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
	app.delete('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);

	const sendUserPlugins = (res, data) => {
		pluginsLoaded = true;
		res.setHeader('Content-Type', 'application/json');
		res.send(JSON.stringify(data));
	};
	app.get('/plugins.json', (req, res) => {
		if (userPlugins && pluginsLoaded) {
			sendUserPlugins(res, userPlugins);
			return;
		}

		if (!config.has('server.static_content') || !config.has('plugins.uri')) {
			res.sendStatus(404);
			return;
		}

		let staticContent = config.get('server.static_content');
		let pluginsUri = config.get('plugins.uri');
		let pluginsPath = undefined;
		let pluginsAutostart = config.get('plugins.autostart');

		if (staticContent[pluginsUri]) {
			pluginsPath = staticContent[pluginsUri].path;
		}

		let baseUrl = '../../../..';
		utils.listFolders(pluginsPath, true).then((values) => {
			return co(function*() {
				const configFile = 'config.json';
				let stats = null;
				let result = [];
				for (let i = 0; i < values.length; ++i) {
					try {
						stats = yield utils.fsStat(path.join(values[i], configFile));
					} catch (err) {
						stats = null;
					}

					if (stats && stats.isFile) {
						result.push( baseUrl + pluginsUri + '/' + path.basename(values[i]) + '/' + configFile);
					}
				}

				userPlugins = {'url': '', 'pluginsData': result, 'autostart': pluginsAutostart};
				sendUserPlugins(res, userPlugins);
			});
		});
	});
});

process.on('uncaughtException', (err) => {
	logger.error((new Date).toUTCString() + ' uncaughtException:', err.message);
	logger.error(err.stack);
	logger.shutdown(() => {
		process.exit(1);
	});
});
<|endoftext|>


<commit_before>import { VS_HUMAN } from "../reducers/Game.js";
import computeMove from "./AI.js";

// Game action types
export const APPLY_MOVE = "PLAYER_MOVE";
export const RESET_GAME = "RESET_GAME";
export const SET_GAME_MODE = "SET_GAME_MODE";
export const START_NEXT_MATCH = "START_NEXT_MATCH";

const MOVE_TIMEOUT = 200;

// GRID_CHANGED action creator
export const applyMoveAction = function ({x, y}) {
  return {
    x: x,
    y: y,
    type: APPLY_MOVE
  };
};

export const computerMoveAction = function (state) {
  return applyMoveAction(computeMove(state));
}

export const applyComputerMoveAfterTimeout = function (state, timeout) {
  return dispatch => setTimeout(
      () => dispatch(computerMoveAction(state)),
      timeout
    );
}

export const resetGameAction = function () {
  return {
    type: RESET_GAME
  };
};

export const setGameModeAction = function (mode) {
  return {
    mode: mode,
    type: SET_GAME_MODE
  };
};

export const startNextMacthAction = function () {
  return {
    type: START_NEXT_MATCH
  }
}

const shouldHumanMove = function (state, {x, y}) {
  return state.gameGrid[x][y] === "" &&
    (state.gameMode === VS_HUMAN ||
     ((state.currentTurn === "x") !== state.AI.playingX)
    );
}

const shouldComputerMove = function (state) {
  return state.gameMode !== VS_HUMAN &&
    (state.currentTurn === "x") === state.AI.playingX;
}

const gameTick = function (move) {
  return (dispatch, getState) => {
    let state = getState().game;
    if(move) {
      if(state.gameOver) {
        dispatch(startNextMacthAction());
        return;
      }
      if(shouldHumanMove(state, move)) {
        dispatch(applyMoveAction(move));
      }
      return;
    }
    if(shouldComputerMove(state) && !state.gameOver) {
      dispatch(applyComputerMoveAfterTimeout(state, MOVE_TIMEOUT));
    }
  }
}

export default gameTick;
<commit_msg>Refactor add missing ‘;’<commit_after>import { VS_HUMAN } from "../reducers/Game.js";
import computeMove from "./AI.js";

// Game action types
export const APPLY_MOVE = "PLAYER_MOVE";
export const RESET_GAME = "RESET_GAME";
export const SET_GAME_MODE = "SET_GAME_MODE";
export const START_NEXT_MATCH = "START_NEXT_MATCH";

const MOVE_TIMEOUT = 200;

// GRID_CHANGED action creator
export const applyMoveAction = function ({x, y}) {
  return {
    x: x,
    y: y,
    type: APPLY_MOVE
  };
};

export const computerMoveAction = function (state) {
  return applyMoveAction(computeMove(state));
};

export const applyComputerMoveAfterTimeout = function (state, timeout) {
  return dispatch => setTimeout(
      () => dispatch(computerMoveAction(state)),
      timeout
    );
};

export const resetGameAction = function () {
  return {
    type: RESET_GAME
  };
};

export const setGameModeAction = function (mode) {
  return {
    mode: mode,
    type: SET_GAME_MODE
  };
};

export const startNextMatchAction = function () {
  return {
    type: START_NEXT_MATCH
  }
};

const shouldHumanMove = function (state, {x, y}) {
  return state.gameGrid[x][y] === "" &&
    (state.gameMode === VS_HUMAN ||
     ((state.currentTurn === "x") !== state.AI.playingX)
    );
};

const shouldComputerMove = function (state) {
  return state.gameMode !== VS_HUMAN &&
    (state.currentTurn === "x") === state.AI.playingX;
};

const gameTick = function (move) {
  return (dispatch, getState) => {
    let state = getState().game;
    if(move) {
      if(state.gameOver) {
        dispatch(startNextMatchAction());
        return;
      }
      if(shouldHumanMove(state, move)) {
        dispatch(applyMoveAction(move));
      }
      return;
    }
    if(shouldComputerMove(state) && !state.gameOver) {
      dispatch(applyComputerMoveAfterTimeout(state, MOVE_TIMEOUT));
    }
  }
};

export default gameTick;
<|endoftext|>


<commit_before>'use strict';
var VERSION = '2.0.1',
    CONSTANTS = require('../constants.json'),
    utils = require('../utils.js'),
    bidfactory = require('../bidfactory.js'),
    bidmanager = require('../bidmanager.js'),
    adloader = require('../adloader'),
    ajax = require('../ajax').ajax;

/**
 * Adapter for requesting bids from Conversant
 */
var ConversantAdapter = function () {
  var w = window,
    n = navigator;

  // production endpoint
  var conversantUrl = '//media.msg.dotomi.com/s2s/header?callback=$$PREBID_GLOBAL$$.conversantResponse';

  // SSAPI returns JSONP with window.pbjs.conversantResponse as the cb
  var appendScript = function (code) {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.className = 'cnvr-response';

    try {
      script.appendChild(document.createTextNode(code));
      document.getElementsByTagName('head')[0].appendChild(script);
    } catch (e) {
      script.text = code;
      document.getElementsByTagName('head')[0].appendChild(script);
    }
  };

  var getDNT = function () {
    return n.doNotTrack === '1' || w.doNotTrack === '1' || n.msDoNotTrack === '1' || n.doNotTrack === 'yes';
  };

  var getDevice = function () {
    const language = n.language ? 'language' : 'userLanguage';
    return {
      h: screen.height,
      w: screen.width,
      dnt: getDNT() ? 1 : 0,
      language: n[language].split('-')[0],
      make: n.vendor ? n.vendor : '',
      ua: n.userAgent
    };
  };

  var callBids = function (params) {
    var conversantBids = params.bids || [];
    requestBids(conversantBids);
  };

  var requestBids = function (bidReqs) {
    // build bid request object
    var page = location.pathname + location.search + location.hash,
      siteId = '',
      conversantImps = [],
      conversantBidReqs,
      secure = 0;

    //build impression array for conversant
    utils._each(bidReqs, function (bid) {
      var bidfloor = utils.getBidIdParamater('bidfloor', bid.params),
        sizeArrayLength = bid.sizes.length,
        adW = 0,
        adH = 0,
        imp;

      secure = utils.getBidIdParamater('secure', bid.params) ? 1 : secure;
      siteId = utils.getBidIdParamater('site_id', bid.params) + '';

      if (sizeArrayLength === 2 && typeof bid.sizes[0] === 'number' && typeof bid.sizes[1] === 'number') {
        adW = bid.sizes[0];
        adH = bid.sizes[1];
      } else {
        adW = bid.sizes[0][0];
        adH = bid.sizes[0][1];
      }

      imp = {
        id: bid.bidId,
        banner: {
          w: adW,
          h: adH
        },
        secure: secure,
        bidfloor: bidfloor ? bidfloor : 0,
        displaymanager: 'Prebid.js',
        displaymanagerver: VERSION
      };

      conversantImps.push(imp);
    });

    conversantBidReqs = {
      'id': utils.getUniqueIdentifierStr(),
      'imp': conversantImps,

      'site': {
        'id': siteId,
        'mobile': document.querySelector('meta[name="viewport"][content*="width=device-width"]') !== null ? 1 : 0,
        'page': page
      },

      'device': getDevice(),
      'at': 1
    };

    var url = secure ? 'https:' + conversantUrl : location.protocol + conversantUrl;
    ajax(url, appendScript, JSON.stringify(conversantBidReqs), {
      withCredentials : true
    });
  };

  var addEmptyBidResponses = function (placementsWithBidsBack) {
    var allConversantBidRequests = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant');

    if (allConversantBidRequests && allConversantBidRequests.bids){
      utils._each(allConversantBidRequests.bids, function (conversantBid) {
        if (!utils.contains(placementsWithBidsBack, conversantBid.placementCode)) {
          // Add a no-bid response for this placement.
          var bid = bidfactory.createBid(2, conversantBid);
          bid.bidderCode = 'conversant';
          bidmanager.addBidResponse(conversantBid.placementCode, bid);
        }
      });
    }
  };

  var parseSeatbid = function (bidResponse) {
    var placementsWithBidsBack = [];
    utils._each(bidResponse.bid, function (conversantBid) {
      var responseCPM,
        placementCode = '',
        id = conversantBid.impid,
        bid = {},
        responseAd,
        responseNurl,
        sizeArrayLength;

      // Bid request we sent Conversant
      var bidRequested = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant').bids.find(bid => bid.bidId === id);

      if (bidRequested) {
        placementCode = bidRequested.placementCode;
        bidRequested.status = CONSTANTS.STATUS.GOOD;
        responseCPM = parseFloat(conversantBid.price);

        if (responseCPM !== 0.0) {
          conversantBid.placementCode = placementCode;
          placementsWithBidsBack.push(placementCode);
          conversantBid.size = bidRequested.sizes;
          responseAd = conversantBid.adm || '';
          responseNurl = conversantBid.nurl || '';

          // Our bid!
          bid = bidfactory.createBid(1, bidRequested);
          bid.creative_id = conversantBid.id || '';
          bid.bidderCode = 'conversant';

          bid.cpm = responseCPM;

          // Track impression image onto returned html
          bid.ad = responseAd + '';

          sizeArrayLength = bidRequested.sizes.length;
          if (sizeArrayLength === 2 && typeof bidRequested.sizes[0] === 'number' && typeof bidRequested.sizes[1] === 'number') {
            bid.width = bidRequested.sizes[0];
            bid.height = bidRequested.sizes[1];
          } else {
            bid.width = bidRequested.sizes[0][0];
            bid.height = bidRequested.sizes[0][1];
          }

          bidmanager.addBidResponse(placementCode, bid);
        }
      }
    });
    addEmptyBidResponses(placementsWithBidsBack);
  };

  // Register our callback to the global object:
  $$PREBID_GLOBAL$$.conversantResponse = function (conversantResponseObj, path) {
    // valid object?
    if (conversantResponseObj && conversantResponseObj.id) {
      if (conversantResponseObj.seatbid && conversantResponseObj.seatbid.length > 0 && conversantResponseObj.seatbid[0].bid && conversantResponseObj.seatbid[0].bid.length > 0) {
        utils._each(conversantResponseObj.seatbid, parseSeatbid);
      } else {
        //no response data for any placements
        addEmptyBidResponses([]);
      }
    } else {
      //no response data for any placements
      addEmptyBidResponses([]);
    }
    // for debugging purposes
    if (path){
      adloader.loadScript(path, function () {
        var allConversantBidRequests = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant');

        if ($$PREBID_GLOBAL$$.conversantDebugResponse){
          $$PREBID_GLOBAL$$.conversantDebugResponse(allConversantBidRequests);
        }
      });
    }
  }; // conversantResponse

  return {
    callBids: callBids
  };
};

module.exports = ConversantAdapter;
<commit_msg>Allow Conversant sizes to be overridden per placement (#816)<commit_after>'use strict';
var VERSION = '2.0.1',
    CONSTANTS = require('../constants.json'),
    utils = require('../utils.js'),
    bidfactory = require('../bidfactory.js'),
    bidmanager = require('../bidmanager.js'),
    adloader = require('../adloader'),
    ajax = require('../ajax').ajax;

/**
 * Adapter for requesting bids from Conversant
 */
var ConversantAdapter = function () {
  var w = window,
    n = navigator;

  // production endpoint
  var conversantUrl = '//media.msg.dotomi.com/s2s/header?callback=$$PREBID_GLOBAL$$.conversantResponse';

  // SSAPI returns JSONP with window.pbjs.conversantResponse as the cb
  var appendScript = function (code) {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.className = 'cnvr-response';

    try {
      script.appendChild(document.createTextNode(code));
      document.getElementsByTagName('head')[0].appendChild(script);
    } catch (e) {
      script.text = code;
      document.getElementsByTagName('head')[0].appendChild(script);
    }
  };

  var getDNT = function () {
    return n.doNotTrack === '1' || w.doNotTrack === '1' || n.msDoNotTrack === '1' || n.doNotTrack === 'yes';
  };

  var getDevice = function () {
    const language = n.language ? 'language' : 'userLanguage';
    return {
      h: screen.height,
      w: screen.width,
      dnt: getDNT() ? 1 : 0,
      language: n[language].split('-')[0],
      make: n.vendor ? n.vendor : '',
      ua: n.userAgent
    };
  };

  var callBids = function (params) {
    var conversantBids = params.bids || [];
    requestBids(conversantBids);
  };

  var requestBids = function (bidReqs) {
    // build bid request object
    var page = location.pathname + location.search + location.hash,
      siteId = '',
      conversantImps = [],
      conversantBidReqs,
      secure = 0;

    //build impression array for conversant
    utils._each(bidReqs, function (bid) {
      var bidfloor = utils.getBidIdParamater('bidfloor', bid.params),
        adW = 0,
        adH = 0,
        imp;

      secure = utils.getBidIdParamater('secure', bid.params) ? 1 : secure;
      siteId = utils.getBidIdParamater('site_id', bid.params) + '';

      // Allow sizes to be overridden per placement
      var bidSizes = Array.isArray(bid.params.sizes) ? bid.params.sizes : bid.sizes;

      if (bidSizes.length === 2 && typeof bidSizes[0] === 'number' && typeof bidSizes[1] === 'number') {
        adW = bidSizes[0];
        adH = bidSizes[1];
      } else {
        adW = bidSizes[0][0];
        adH = bidSizes[0][1];
      }

      imp = {
        id: bid.bidId,
        banner: {
          w: adW,
          h: adH
        },
        secure: secure,
        bidfloor: bidfloor ? bidfloor : 0,
        displaymanager: 'Prebid.js',
        displaymanagerver: VERSION
      };

      conversantImps.push(imp);
    });

    conversantBidReqs = {
      'id': utils.getUniqueIdentifierStr(),
      'imp': conversantImps,

      'site': {
        'id': siteId,
        'mobile': document.querySelector('meta[name="viewport"][content*="width=device-width"]') !== null ? 1 : 0,
        'page': page
      },

      'device': getDevice(),
      'at': 1
    };

    var url = secure ? 'https:' + conversantUrl : location.protocol + conversantUrl;
    ajax(url, appendScript, JSON.stringify(conversantBidReqs), {
      withCredentials : true
    });
  };

  var addEmptyBidResponses = function (placementsWithBidsBack) {
    var allConversantBidRequests = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant');

    if (allConversantBidRequests && allConversantBidRequests.bids){
      utils._each(allConversantBidRequests.bids, function (conversantBid) {
        if (!utils.contains(placementsWithBidsBack, conversantBid.placementCode)) {
          // Add a no-bid response for this placement.
          var bid = bidfactory.createBid(2, conversantBid);
          bid.bidderCode = 'conversant';
          bidmanager.addBidResponse(conversantBid.placementCode, bid);
        }
      });
    }
  };

  var parseSeatbid = function (bidResponse) {
    var placementsWithBidsBack = [];
    utils._each(bidResponse.bid, function (conversantBid) {
      var responseCPM,
        placementCode = '',
        id = conversantBid.impid,
        bid = {},
        responseAd,
        responseNurl,
        sizeArrayLength;

      // Bid request we sent Conversant
      var bidRequested = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant').bids.find(bid => bid.bidId === id);

      if (bidRequested) {
        placementCode = bidRequested.placementCode;
        bidRequested.status = CONSTANTS.STATUS.GOOD;
        responseCPM = parseFloat(conversantBid.price);

        if (responseCPM !== 0.0) {
          conversantBid.placementCode = placementCode;
          placementsWithBidsBack.push(placementCode);
          conversantBid.size = bidRequested.sizes;
          responseAd = conversantBid.adm || '';
          responseNurl = conversantBid.nurl || '';

          // Our bid!
          bid = bidfactory.createBid(1, bidRequested);
          bid.creative_id = conversantBid.id || '';
          bid.bidderCode = 'conversant';

          bid.cpm = responseCPM;

          // Track impression image onto returned html
          bid.ad = responseAd + '';

          sizeArrayLength = bidRequested.sizes.length;
          if (sizeArrayLength === 2 && typeof bidRequested.sizes[0] === 'number' && typeof bidRequested.sizes[1] === 'number') {
            bid.width = bidRequested.sizes[0];
            bid.height = bidRequested.sizes[1];
          } else {
            bid.width = bidRequested.sizes[0][0];
            bid.height = bidRequested.sizes[0][1];
          }

          bidmanager.addBidResponse(placementCode, bid);
        }
      }
    });
    addEmptyBidResponses(placementsWithBidsBack);
  };

  // Register our callback to the global object:
  $$PREBID_GLOBAL$$.conversantResponse = function (conversantResponseObj, path) {
    // valid object?
    if (conversantResponseObj && conversantResponseObj.id) {
      if (conversantResponseObj.seatbid && conversantResponseObj.seatbid.length > 0 && conversantResponseObj.seatbid[0].bid && conversantResponseObj.seatbid[0].bid.length > 0) {
        utils._each(conversantResponseObj.seatbid, parseSeatbid);
      } else {
        //no response data for any placements
        addEmptyBidResponses([]);
      }
    } else {
      //no response data for any placements
      addEmptyBidResponses([]);
    }
    // for debugging purposes
    if (path){
      adloader.loadScript(path, function () {
        var allConversantBidRequests = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant');

        if ($$PREBID_GLOBAL$$.conversantDebugResponse){
          $$PREBID_GLOBAL$$.conversantDebugResponse(allConversantBidRequests);
        }
      });
    }
  }; // conversantResponse

  return {
    callBids: callBids
  };
};

module.exports = ConversantAdapter;
<|endoftext|>